MUSE Pipeline Reference Manual  2.1.1
muse_twilight_z.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set sw=2 sts=2 et cin: */
3 /*
4  * This file is part of the MUSE Instrument Pipeline
5  * Copyright (C) 2005-2015 European Southern Observatory
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 /* This file was automatically generated */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 /*----------------------------------------------------------------------------*
29  * Includes *
30  *----------------------------------------------------------------------------*/
31 #include <string.h> /* strcmp(), strstr() */
32 #include <strings.h> /* strcasecmp() */
33 #include <cpl.h>
34 
35 #include "muse_twilight_z.h" /* in turn includes muse.h */
36 
37 /*----------------------------------------------------------------------------*/
87 /*----------------------------------------------------------------------------*/
90 /*----------------------------------------------------------------------------*
91  * Static variables *
92  *----------------------------------------------------------------------------*/
93 static const char *muse_twilight_help =
94  "Processing first handles each raw input image separately: it trims the raw data and records the overscan statistics, subtracts the bias (taking account of the overscan, if --overscan is not \"none\"), converts the images from adu to count, subtracts the dark, divides by the flat-field and combines all the exposures using input parameters. The input calibrations geometry table, trace table, and wavelength calibration table are used to assign 3D coordinates to each CCD-based pixel, thereby creating a pixel table from the master sky-flat. These pixel tables are then cut in wavelength using the --lambdamin and --lambdamax parameters. The integrated flux in each IFU is computed as the sum of the data in the pixel table, and saved in the header, to be used later as estimate for the relative throughput of each IFU. If an ILLUM exposure was given as input, it is then used to correct the relative illumination between all slices of one IFU. For this, the data of each slice within the pixel table of each IFU is multiplied by the normalized median flux of that slice in the ILLUM exposure. The pixel tables of all IFUs are then merged, using the integrated fluxes as inverse scaling factors, and a cube is reconstructed from the merged dataset, using given parameters. A white-light image is created from the cube. This skyflat cube is then saved to disk, with the white-light image as one extension. To construct a smooth 3D illumination correction, the cube is post-processed in the following way: the white-light image is used to create a mask of the illuminated area. From this area, the optional vignetting mask is removed. The smoothing is then computed for each plane of the cube: the illuminated area is smoothed (by a 5x7 median filter), normalized, fit with a 2D polynomial (of given polynomial orders), and normalized again. A smooth white image is then created by collapsing the smooth cube. If a vignetting mask was given, the corner area given by the mask is used to compute a 2D correction for the vignetted area: the original unsmoothed white-light image is corrected for large scale gradients by dividing it with the smooth white image. The residuals in the corner area then smoothed using input parameters. This smoothed vignetting correction is the multiplied onto each plane of the smooth cube, normalizing each plane again. This twilight cube is then saved to disk.";
95 
96 static const char *muse_twilight_help_esorex =
97  "\n\nInput frames for raw frame tag \"SKYFLAT\":\n"
98  "\n Frame tag Type Req #Fr Description"
99  "\n -------------------- ---- --- --- ------------"
100  "\n SKYFLAT raw Y >=3 Raw twilight skyflat"
101  "\n ILLUM raw . 1 Single optional raw (attached/illumination) flat-field exposure"
102  "\n MASTER_BIAS calib Y 1 Master bias"
103  "\n MASTER_DARK calib . 1 Master dark"
104  "\n MASTER_FLAT calib Y 1 Master flat"
105  "\n BADPIX_TABLE calib . Known bad pixels"
106  "\n TRACE_TABLE calib Y 1 Tracing table for all slices"
107  "\n WAVECAL_TABLE calib Y 1 Wavelength calibration table"
108  "\n GEOMETRY_TABLE calib Y 1 Relative positions of the slices in the field of view"
109  "\n VIGNETTING_MASK calib . 1 Mask to mark vignetted regions in the MUSE field of view"
110  "\n\nProduct frames for raw frame tag \"SKYFLAT\":\n"
111  "\n Frame tag Level Description"
112  "\n -------------------- -------- ------------"
113  "\n DATACUBE_SKYFLAT final Cube of combined twilight skyflat exposures"
114  "\n TWILIGHT_CUBE final Smoothed cube of twilight sky";
115 
116 /*----------------------------------------------------------------------------*/
124 /*----------------------------------------------------------------------------*/
125 static cpl_recipeconfig *
126 muse_twilight_new_recipeconfig(void)
127 {
128  cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
129 
130  cpl_recipeconfig_set_tag(recipeconfig, "SKYFLAT", 3, -1);
131  cpl_recipeconfig_set_input(recipeconfig, "SKYFLAT", "MASTER_BIAS", 1, 1);
132  cpl_recipeconfig_set_input(recipeconfig, "SKYFLAT", "MASTER_DARK", -1, 1);
133  cpl_recipeconfig_set_input(recipeconfig, "SKYFLAT", "MASTER_FLAT", 1, 1);
134  cpl_recipeconfig_set_input(recipeconfig, "SKYFLAT", "BADPIX_TABLE", -1, -1);
135  cpl_recipeconfig_set_input(recipeconfig, "SKYFLAT", "TRACE_TABLE", 1, 1);
136  cpl_recipeconfig_set_input(recipeconfig, "SKYFLAT", "WAVECAL_TABLE", 1, 1);
137  cpl_recipeconfig_set_input(recipeconfig, "SKYFLAT", "GEOMETRY_TABLE", 1, 1);
138  cpl_recipeconfig_set_input(recipeconfig, "SKYFLAT", "VIGNETTING_MASK", -1, 1);
139  cpl_recipeconfig_set_output(recipeconfig, "SKYFLAT", "DATACUBE_SKYFLAT");
140  cpl_recipeconfig_set_output(recipeconfig, "SKYFLAT", "TWILIGHT_CUBE");
141  cpl_recipeconfig_set_tag(recipeconfig, "ILLUM", -1, 1);
142  cpl_recipeconfig_set_input(recipeconfig, "ILLUM", "MASTER_BIAS", 1, 1);
143  cpl_recipeconfig_set_input(recipeconfig, "ILLUM", "MASTER_DARK", -1, 1);
144  cpl_recipeconfig_set_input(recipeconfig, "ILLUM", "MASTER_FLAT", 1, 1);
145  cpl_recipeconfig_set_input(recipeconfig, "ILLUM", "BADPIX_TABLE", -1, -1);
146  cpl_recipeconfig_set_input(recipeconfig, "ILLUM", "TRACE_TABLE", 1, 1);
147  cpl_recipeconfig_set_input(recipeconfig, "ILLUM", "WAVECAL_TABLE", 1, 1);
148  cpl_recipeconfig_set_input(recipeconfig, "ILLUM", "GEOMETRY_TABLE", 1, 1);
149  cpl_recipeconfig_set_input(recipeconfig, "ILLUM", "VIGNETTING_MASK", -1, 1);
150 
151  return recipeconfig;
152 } /* muse_twilight_new_recipeconfig() */
153 
154 /*----------------------------------------------------------------------------*/
164 /*----------------------------------------------------------------------------*/
165 static cpl_error_code
166 muse_twilight_prepare_header(const char *aFrametag, cpl_propertylist *aHeader)
167 {
168  cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
169  cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
170  if (!strcmp(aFrametag, "DATACUBE_SKYFLAT")) {
171  muse_processing_prepare_property(aHeader, "ESO QC TWILIGHT[0-9]+ INPUT[0-9]+ MEDIAN",
172  CPL_TYPE_FLOAT,
173  "Median value of raw exposure i of IFU m in input list");
174  muse_processing_prepare_property(aHeader, "ESO QC TWILIGHT[0-9]+ INPUT[0-9]+ MEAN",
175  CPL_TYPE_FLOAT,
176  "Mean value of raw exposure i of IFU m in input list");
177  muse_processing_prepare_property(aHeader, "ESO QC TWILIGHT[0-9]+ INPUT[0-9]+ STDEV",
178  CPL_TYPE_FLOAT,
179  "Standard deviation of raw exposure i of IFU m in input list");
180  muse_processing_prepare_property(aHeader, "ESO QC TWILIGHT[0-9]+ INPUT[0-9]+ MIN",
181  CPL_TYPE_FLOAT,
182  "Minimum value of raw exposure i of IFU m in input list");
183  muse_processing_prepare_property(aHeader, "ESO QC TWILIGHT[0-9]+ INPUT[0-9]+ MAX",
184  CPL_TYPE_FLOAT,
185  "Maximum value of raw exposure i of IFU m in input list");
186  muse_processing_prepare_property(aHeader, "ESO QC TWILIGHT[0-9]+ INPUT[0-9]+ NSATURATED",
187  CPL_TYPE_INT,
188  "Number of saturated pixels in raw exposure i of IFU m in input list");
189  muse_processing_prepare_property(aHeader, "ESO QC TWILIGHT[0-9]+ MASTER MEDIAN",
190  CPL_TYPE_FLOAT,
191  "Median value of the combined exposures in IFU m");
192  muse_processing_prepare_property(aHeader, "ESO QC TWILIGHT[0-9]+ MASTER MEAN",
193  CPL_TYPE_FLOAT,
194  "Mean value of the combined exposures in IFU m");
195  muse_processing_prepare_property(aHeader, "ESO QC TWILIGHT[0-9]+ MASTER STDEV",
196  CPL_TYPE_FLOAT,
197  "Standard deviation of the combined exposures in IFU m");
198  muse_processing_prepare_property(aHeader, "ESO QC TWILIGHT[0-9]+ MASTER MIN",
199  CPL_TYPE_FLOAT,
200  "Minimum value of the combined exposures in IFU m");
201  muse_processing_prepare_property(aHeader, "ESO QC TWILIGHT[0-9]+ MASTER MAX",
202  CPL_TYPE_FLOAT,
203  "Maximum value of the combined exposures in IFU m");
204  muse_processing_prepare_property(aHeader, "ESO QC TWILIGHT[0-9]+ MASTER INTFLUX",
205  CPL_TYPE_FLOAT,
206  "Flux integrated over the whole CCD of the combined exposures of IFU m");
207  muse_processing_prepare_property(aHeader, "ESO QC TWILIGHT[0-9]+ INTFLUX",
208  CPL_TYPE_FLOAT,
209  "Flux integrated over all slices of IFU m. Computed using the pixel table of the exposure.");
210  } else if (!strcmp(aFrametag, "TWILIGHT_CUBE")) {
211  } else {
212  cpl_msg_warning(__func__, "Frame tag %s is not defined", aFrametag);
213  return CPL_ERROR_ILLEGAL_INPUT;
214  }
215  return CPL_ERROR_NONE;
216 } /* muse_twilight_prepare_header() */
217 
218 /*----------------------------------------------------------------------------*/
227 /*----------------------------------------------------------------------------*/
228 static cpl_frame_level
229 muse_twilight_get_frame_level(const char *aFrametag)
230 {
231  if (!aFrametag) {
232  return CPL_FRAME_LEVEL_NONE;
233  }
234  if (!strcmp(aFrametag, "DATACUBE_SKYFLAT")) {
235  return CPL_FRAME_LEVEL_FINAL;
236  }
237  if (!strcmp(aFrametag, "TWILIGHT_CUBE")) {
238  return CPL_FRAME_LEVEL_FINAL;
239  }
240  return CPL_FRAME_LEVEL_NONE;
241 } /* muse_twilight_get_frame_level() */
242 
243 /*----------------------------------------------------------------------------*/
252 /*----------------------------------------------------------------------------*/
253 static muse_frame_mode
254 muse_twilight_get_frame_mode(const char *aFrametag)
255 {
256  if (!aFrametag) {
257  return MUSE_FRAME_MODE_ALL;
258  }
259  if (!strcmp(aFrametag, "DATACUBE_SKYFLAT")) {
260  return MUSE_FRAME_MODE_MASTER;
261  }
262  if (!strcmp(aFrametag, "TWILIGHT_CUBE")) {
263  return MUSE_FRAME_MODE_MASTER;
264  }
265  return MUSE_FRAME_MODE_ALL;
266 } /* muse_twilight_get_frame_mode() */
267 
268 /*----------------------------------------------------------------------------*/
278 /*----------------------------------------------------------------------------*/
279 static int
280 muse_twilight_create(cpl_plugin *aPlugin)
281 {
282  /* Check that the plugin is part of a valid recipe */
283  cpl_recipe *recipe;
284  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
285  recipe = (cpl_recipe *)aPlugin;
286  } else {
287  return -1;
288  }
289 
290  /* register the extended processing information (new FITS header creation, *
291  * getting of the frame level for a certain tag) */
293  muse_twilight_new_recipeconfig(),
294  muse_twilight_prepare_header,
295  muse_twilight_get_frame_level,
296  muse_twilight_get_frame_mode);
297 
298  /* XXX initialize timing in messages *
299  * since at least esorex is too stupid to turn it on, we have to do it */
301  cpl_msg_set_time_on();
302  }
303 
304  /* Create the parameter list in the cpl_recipe object */
305  recipe->parameters = cpl_parameterlist_new();
306  /* Fill the parameters list */
307  cpl_parameter *p;
308 
309  /* --overscan: If this is "none", stop when detecting discrepant overscan levels (see ovscsigma), for "offset" it assumes that the mean overscan level represents the real offset in the bias levels of the exposures involved, and adjusts the data accordingly; for "vpoly", a polynomial is fit to the vertical overscan and subtracted from the whole quadrant. */
310  p = cpl_parameter_new_value("muse.muse_twilight.overscan",
311  CPL_TYPE_STRING,
312  "If this is \"none\", stop when detecting discrepant overscan levels (see ovscsigma), for \"offset\" it assumes that the mean overscan level represents the real offset in the bias levels of the exposures involved, and adjusts the data accordingly; for \"vpoly\", a polynomial is fit to the vertical overscan and subtracted from the whole quadrant.",
313  "muse.muse_twilight",
314  (const char *)"vpoly");
315  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "overscan");
316  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "overscan");
317 
318  cpl_parameterlist_append(recipe->parameters, p);
319 
320  /* --ovscreject: This influences how values are rejected when computing overscan statistics. Either no rejection at all ("none"), rejection using the DCR algorithm ("dcr"), or rejection using an iterative constant fit ("fit"). */
321  p = cpl_parameter_new_value("muse.muse_twilight.ovscreject",
322  CPL_TYPE_STRING,
323  "This influences how values are rejected when computing overscan statistics. Either no rejection at all (\"none\"), rejection using the DCR algorithm (\"dcr\"), or rejection using an iterative constant fit (\"fit\").",
324  "muse.muse_twilight",
325  (const char *)"dcr");
326  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscreject");
327  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscreject");
328 
329  cpl_parameterlist_append(recipe->parameters, p);
330 
331  /* --ovscsigma: If the deviation of mean overscan levels between a raw input image and the reference image is higher than |ovscsigma x stdev|, stop the processing. If overscan="vpoly", this is used as sigma rejection level for the iterative polynomial fit (the level comparison is then done afterwards with |100 x stdev| to guard against incompatible settings). Has no effect for overscan="offset". */
332  p = cpl_parameter_new_value("muse.muse_twilight.ovscsigma",
333  CPL_TYPE_DOUBLE,
334  "If the deviation of mean overscan levels between a raw input image and the reference image is higher than |ovscsigma x stdev|, stop the processing. If overscan=\"vpoly\", this is used as sigma rejection level for the iterative polynomial fit (the level comparison is then done afterwards with |100 x stdev| to guard against incompatible settings). Has no effect for overscan=\"offset\".",
335  "muse.muse_twilight",
336  (double)30.);
337  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscsigma");
338  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscsigma");
339 
340  cpl_parameterlist_append(recipe->parameters, p);
341 
342  /* --ovscignore: The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when computing statistics or fits. */
343  p = cpl_parameter_new_value("muse.muse_twilight.ovscignore",
344  CPL_TYPE_INT,
345  "The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when computing statistics or fits.",
346  "muse.muse_twilight",
347  (int)3);
348  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscignore");
349  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscignore");
350 
351  cpl_parameterlist_append(recipe->parameters, p);
352 
353  /* --combine: Type of combination to use */
354  p = cpl_parameter_new_enum("muse.muse_twilight.combine",
355  CPL_TYPE_STRING,
356  "Type of combination to use",
357  "muse.muse_twilight",
358  (const char *)"sigclip",
359  4,
360  (const char *)"average",
361  (const char *)"median",
362  (const char *)"minmax",
363  (const char *)"sigclip");
364  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "combine");
365  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "combine");
366 
367  cpl_parameterlist_append(recipe->parameters, p);
368 
369  /* --nlow: Number of minimum pixels to reject with minmax */
370  p = cpl_parameter_new_value("muse.muse_twilight.nlow",
371  CPL_TYPE_INT,
372  "Number of minimum pixels to reject with minmax",
373  "muse.muse_twilight",
374  (int)1);
375  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nlow");
376  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nlow");
377 
378  cpl_parameterlist_append(recipe->parameters, p);
379 
380  /* --nhigh: Number of maximum pixels to reject with minmax */
381  p = cpl_parameter_new_value("muse.muse_twilight.nhigh",
382  CPL_TYPE_INT,
383  "Number of maximum pixels to reject with minmax",
384  "muse.muse_twilight",
385  (int)1);
386  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nhigh");
387  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nhigh");
388 
389  cpl_parameterlist_append(recipe->parameters, p);
390 
391  /* --nkeep: Number of pixels to keep with minmax */
392  p = cpl_parameter_new_value("muse.muse_twilight.nkeep",
393  CPL_TYPE_INT,
394  "Number of pixels to keep with minmax",
395  "muse.muse_twilight",
396  (int)1);
397  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nkeep");
398  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nkeep");
399 
400  cpl_parameterlist_append(recipe->parameters, p);
401 
402  /* --lsigma: Low sigma for pixel rejection with sigclip */
403  p = cpl_parameter_new_value("muse.muse_twilight.lsigma",
404  CPL_TYPE_DOUBLE,
405  "Low sigma for pixel rejection with sigclip",
406  "muse.muse_twilight",
407  (double)3);
408  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lsigma");
409  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lsigma");
410 
411  cpl_parameterlist_append(recipe->parameters, p);
412 
413  /* --hsigma: High sigma for pixel rejection with sigclip */
414  p = cpl_parameter_new_value("muse.muse_twilight.hsigma",
415  CPL_TYPE_DOUBLE,
416  "High sigma for pixel rejection with sigclip",
417  "muse.muse_twilight",
418  (double)3);
419  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "hsigma");
420  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "hsigma");
421 
422  cpl_parameterlist_append(recipe->parameters, p);
423 
424  /* --scale: Scale the individual images to a common exposure time before combining them. */
425  p = cpl_parameter_new_value("muse.muse_twilight.scale",
426  CPL_TYPE_BOOL,
427  "Scale the individual images to a common exposure time before combining them.",
428  "muse.muse_twilight",
429  (int)FALSE);
430  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "scale");
431  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scale");
432 
433  cpl_parameterlist_append(recipe->parameters, p);
434 
435  /* --resample: The resampling technique to use for the final output cube. */
436  p = cpl_parameter_new_enum("muse.muse_twilight.resample",
437  CPL_TYPE_STRING,
438  "The resampling technique to use for the final output cube.",
439  "muse.muse_twilight",
440  (const char *)"drizzle",
441  6,
442  (const char *)"nearest",
443  (const char *)"linear",
444  (const char *)"quadratic",
445  (const char *)"renka",
446  (const char *)"drizzle",
447  (const char *)"lanczos");
448  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "resample");
449  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "resample");
450 
451  cpl_parameterlist_append(recipe->parameters, p);
452 
453  /* --crtype: Type of statistics used for detection of cosmic rays during final resampling. "iraf" uses the variance information, "mean" uses standard (mean/stdev) statistics, "median" uses median and the median median of the absolute median deviation. */
454  p = cpl_parameter_new_enum("muse.muse_twilight.crtype",
455  CPL_TYPE_STRING,
456  "Type of statistics used for detection of cosmic rays during final resampling. \"iraf\" uses the variance information, \"mean\" uses standard (mean/stdev) statistics, \"median\" uses median and the median median of the absolute median deviation.",
457  "muse.muse_twilight",
458  (const char *)"median",
459  3,
460  (const char *)"iraf",
461  (const char *)"mean",
462  (const char *)"median");
463  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "crtype");
464  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "crtype");
465 
466  cpl_parameterlist_append(recipe->parameters, p);
467 
468  /* --crsigma: Sigma rejection factor to use for cosmic ray rejection during final resampling. A zero or negative value switches cosmic ray rejection off. */
469  p = cpl_parameter_new_value("muse.muse_twilight.crsigma",
470  CPL_TYPE_DOUBLE,
471  "Sigma rejection factor to use for cosmic ray rejection during final resampling. A zero or negative value switches cosmic ray rejection off.",
472  "muse.muse_twilight",
473  (double)50.);
474  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "crsigma");
475  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "crsigma");
476 
477  cpl_parameterlist_append(recipe->parameters, p);
478 
479  /* --lambdamin: Minimum wavelength for twilight reconstruction. */
480  p = cpl_parameter_new_value("muse.muse_twilight.lambdamin",
481  CPL_TYPE_DOUBLE,
482  "Minimum wavelength for twilight reconstruction.",
483  "muse.muse_twilight",
484  (double)5000.);
485  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lambdamin");
486  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lambdamin");
487 
488  cpl_parameterlist_append(recipe->parameters, p);
489 
490  /* --lambdamax: Maximum wavelength for twilight reconstruction. */
491  p = cpl_parameter_new_value("muse.muse_twilight.lambdamax",
492  CPL_TYPE_DOUBLE,
493  "Maximum wavelength for twilight reconstruction.",
494  "muse.muse_twilight",
495  (double)9000.);
496  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lambdamax");
497  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lambdamax");
498 
499  cpl_parameterlist_append(recipe->parameters, p);
500 
501  /* --dlambda: Sampling for twilight reconstruction, this should result in planes of equal wavelength coverage. */
502  p = cpl_parameter_new_value("muse.muse_twilight.dlambda",
503  CPL_TYPE_DOUBLE,
504  "Sampling for twilight reconstruction, this should result in planes of equal wavelength coverage.",
505  "muse.muse_twilight",
506  (double)250.);
507  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "dlambda");
508  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dlambda");
509 
510  cpl_parameterlist_append(recipe->parameters, p);
511 
512  /* --xorder: Polynomial order to use in x direction to fit the full field of view. */
513  p = cpl_parameter_new_value("muse.muse_twilight.xorder",
514  CPL_TYPE_INT,
515  "Polynomial order to use in x direction to fit the full field of view.",
516  "muse.muse_twilight",
517  (int)2);
518  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "xorder");
519  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "xorder");
520 
521  cpl_parameterlist_append(recipe->parameters, p);
522 
523  /* --yorder: Polynomial order to use in y direction to fit the full field of view. */
524  p = cpl_parameter_new_value("muse.muse_twilight.yorder",
525  CPL_TYPE_INT,
526  "Polynomial order to use in y direction to fit the full field of view.",
527  "muse.muse_twilight",
528  (int)2);
529  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "yorder");
530  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "yorder");
531 
532  cpl_parameterlist_append(recipe->parameters, p);
533 
534  /* --vignmaskedges: Pixels on edges stronger than this fraction in the normalized image are excluded from the fit to the vignetted area. Set to non-positive number to include them in the fit. */
535  p = cpl_parameter_new_value("muse.muse_twilight.vignmaskedges",
536  CPL_TYPE_DOUBLE,
537  "Pixels on edges stronger than this fraction in the normalized image are excluded from the fit to the vignetted area. Set to non-positive number to include them in the fit.",
538  "muse.muse_twilight",
539  (double)0.02);
540  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "vignmaskedges");
541  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "vignmaskedges");
542 
543  cpl_parameterlist_append(recipe->parameters, p);
544 
545  /* --vignsmooth: Type of smoothing to use for the vignetted region given by the VIGNETTING_MASK; gaussian uses (vignxpar + vignypar)/2 as FWHM. */
546  p = cpl_parameter_new_enum("muse.muse_twilight.vignsmooth",
547  CPL_TYPE_STRING,
548  "Type of smoothing to use for the vignetted region given by the VIGNETTING_MASK; gaussian uses (vignxpar + vignypar)/2 as FWHM.",
549  "muse.muse_twilight",
550  (const char *)"polyfit",
551  3,
552  (const char *)"polyfit",
553  (const char *)"gaussian",
554  (const char *)"median");
555  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "vignsmooth");
556  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "vignsmooth");
557 
558  cpl_parameterlist_append(recipe->parameters, p);
559 
560  /* --vignxpar: Parameter used by the vignetting smoothing: x order for polyfit (default, recommended 4), parameter that influences the FWHM for the gaussian (recommended: 10), or x dimension of median filter (recommended 5). */
561  p = cpl_parameter_new_value("muse.muse_twilight.vignxpar",
562  CPL_TYPE_INT,
563  "Parameter used by the vignetting smoothing: x order for polyfit (default, recommended 4), parameter that influences the FWHM for the gaussian (recommended: 10), or x dimension of median filter (recommended 5).",
564  "muse.muse_twilight",
565  (int)4);
566  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "vignxpar");
567  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "vignxpar");
568 
569  cpl_parameterlist_append(recipe->parameters, p);
570 
571  /* --vignypar: Parameter used by the vignetting smoothing: y order for polyfit (default, recommended 4), parameter that influences the FWHM for the gaussian (recommended: 10), or y dimension of median filter (recommended 5). */
572  p = cpl_parameter_new_value("muse.muse_twilight.vignypar",
573  CPL_TYPE_INT,
574  "Parameter used by the vignetting smoothing: y order for polyfit (default, recommended 4), parameter that influences the FWHM for the gaussian (recommended: 10), or y dimension of median filter (recommended 5).",
575  "muse.muse_twilight",
576  (int)4);
577  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "vignypar");
578  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "vignypar");
579 
580  cpl_parameterlist_append(recipe->parameters, p);
581 
582  return 0;
583 } /* muse_twilight_create() */
584 
585 /*----------------------------------------------------------------------------*/
596 /*----------------------------------------------------------------------------*/
597 static int
598 muse_twilight_params_fill(muse_twilight_params_t *aParams, cpl_parameterlist *aParameters)
599 {
600  cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
601  cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
602  cpl_parameter *p;
603 
604  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.overscan");
605  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
606  aParams->overscan = cpl_parameter_get_string(p);
607 
608  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.ovscreject");
609  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
610  aParams->ovscreject = cpl_parameter_get_string(p);
611 
612  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.ovscsigma");
613  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
614  aParams->ovscsigma = cpl_parameter_get_double(p);
615 
616  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.ovscignore");
617  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
618  aParams->ovscignore = cpl_parameter_get_int(p);
619 
620  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.combine");
621  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
622  aParams->combine_s = cpl_parameter_get_string(p);
623  aParams->combine =
624  (!strcasecmp(aParams->combine_s, "average")) ? MUSE_TWILIGHT_PARAM_COMBINE_AVERAGE :
625  (!strcasecmp(aParams->combine_s, "median")) ? MUSE_TWILIGHT_PARAM_COMBINE_MEDIAN :
626  (!strcasecmp(aParams->combine_s, "minmax")) ? MUSE_TWILIGHT_PARAM_COMBINE_MINMAX :
627  (!strcasecmp(aParams->combine_s, "sigclip")) ? MUSE_TWILIGHT_PARAM_COMBINE_SIGCLIP :
628  MUSE_TWILIGHT_PARAM_COMBINE_INVALID_VALUE;
629  cpl_ensure_code(aParams->combine != MUSE_TWILIGHT_PARAM_COMBINE_INVALID_VALUE,
630  CPL_ERROR_ILLEGAL_INPUT);
631 
632  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.nlow");
633  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
634  aParams->nlow = cpl_parameter_get_int(p);
635 
636  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.nhigh");
637  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
638  aParams->nhigh = cpl_parameter_get_int(p);
639 
640  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.nkeep");
641  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
642  aParams->nkeep = cpl_parameter_get_int(p);
643 
644  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.lsigma");
645  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
646  aParams->lsigma = cpl_parameter_get_double(p);
647 
648  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.hsigma");
649  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
650  aParams->hsigma = cpl_parameter_get_double(p);
651 
652  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.scale");
653  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
654  aParams->scale = cpl_parameter_get_bool(p);
655 
656  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.resample");
657  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
658  aParams->resample_s = cpl_parameter_get_string(p);
659  aParams->resample =
660  (!strcasecmp(aParams->resample_s, "nearest")) ? MUSE_TWILIGHT_PARAM_RESAMPLE_NEAREST :
661  (!strcasecmp(aParams->resample_s, "linear")) ? MUSE_TWILIGHT_PARAM_RESAMPLE_LINEAR :
662  (!strcasecmp(aParams->resample_s, "quadratic")) ? MUSE_TWILIGHT_PARAM_RESAMPLE_QUADRATIC :
663  (!strcasecmp(aParams->resample_s, "renka")) ? MUSE_TWILIGHT_PARAM_RESAMPLE_RENKA :
664  (!strcasecmp(aParams->resample_s, "drizzle")) ? MUSE_TWILIGHT_PARAM_RESAMPLE_DRIZZLE :
665  (!strcasecmp(aParams->resample_s, "lanczos")) ? MUSE_TWILIGHT_PARAM_RESAMPLE_LANCZOS :
666  MUSE_TWILIGHT_PARAM_RESAMPLE_INVALID_VALUE;
667  cpl_ensure_code(aParams->resample != MUSE_TWILIGHT_PARAM_RESAMPLE_INVALID_VALUE,
668  CPL_ERROR_ILLEGAL_INPUT);
669 
670  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.crtype");
671  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
672  aParams->crtype_s = cpl_parameter_get_string(p);
673  aParams->crtype =
674  (!strcasecmp(aParams->crtype_s, "iraf")) ? MUSE_TWILIGHT_PARAM_CRTYPE_IRAF :
675  (!strcasecmp(aParams->crtype_s, "mean")) ? MUSE_TWILIGHT_PARAM_CRTYPE_MEAN :
676  (!strcasecmp(aParams->crtype_s, "median")) ? MUSE_TWILIGHT_PARAM_CRTYPE_MEDIAN :
677  MUSE_TWILIGHT_PARAM_CRTYPE_INVALID_VALUE;
678  cpl_ensure_code(aParams->crtype != MUSE_TWILIGHT_PARAM_CRTYPE_INVALID_VALUE,
679  CPL_ERROR_ILLEGAL_INPUT);
680 
681  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.crsigma");
682  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
683  aParams->crsigma = cpl_parameter_get_double(p);
684 
685  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.lambdamin");
686  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
687  aParams->lambdamin = cpl_parameter_get_double(p);
688 
689  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.lambdamax");
690  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
691  aParams->lambdamax = cpl_parameter_get_double(p);
692 
693  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.dlambda");
694  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
695  aParams->dlambda = cpl_parameter_get_double(p);
696 
697  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.xorder");
698  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
699  aParams->xorder = cpl_parameter_get_int(p);
700 
701  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.yorder");
702  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
703  aParams->yorder = cpl_parameter_get_int(p);
704 
705  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.vignmaskedges");
706  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
707  aParams->vignmaskedges = cpl_parameter_get_double(p);
708 
709  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.vignsmooth");
710  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
711  aParams->vignsmooth_s = cpl_parameter_get_string(p);
712  aParams->vignsmooth =
713  (!strcasecmp(aParams->vignsmooth_s, "polyfit")) ? MUSE_TWILIGHT_PARAM_VIGNSMOOTH_POLYFIT :
714  (!strcasecmp(aParams->vignsmooth_s, "gaussian")) ? MUSE_TWILIGHT_PARAM_VIGNSMOOTH_GAUSSIAN :
715  (!strcasecmp(aParams->vignsmooth_s, "median")) ? MUSE_TWILIGHT_PARAM_VIGNSMOOTH_MEDIAN :
716  MUSE_TWILIGHT_PARAM_VIGNSMOOTH_INVALID_VALUE;
717  cpl_ensure_code(aParams->vignsmooth != MUSE_TWILIGHT_PARAM_VIGNSMOOTH_INVALID_VALUE,
718  CPL_ERROR_ILLEGAL_INPUT);
719 
720  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.vignxpar");
721  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
722  aParams->vignxpar = cpl_parameter_get_int(p);
723 
724  p = cpl_parameterlist_find(aParameters, "muse.muse_twilight.vignypar");
725  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
726  aParams->vignypar = cpl_parameter_get_int(p);
727 
728  return 0;
729 } /* muse_twilight_params_fill() */
730 
731 /*----------------------------------------------------------------------------*/
738 /*----------------------------------------------------------------------------*/
739 static int
740 muse_twilight_exec(cpl_plugin *aPlugin)
741 {
742  if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
743  return -1;
744  }
746  cpl_recipe *recipe = (cpl_recipe *)aPlugin;
747  cpl_msg_set_threadid_on();
748 
749  cpl_frameset *usedframes = cpl_frameset_new(),
750  *outframes = cpl_frameset_new();
751  muse_twilight_params_t params;
752  muse_twilight_params_fill(&params, recipe->parameters);
753 
754  cpl_errorstate prestate = cpl_errorstate_get();
755 
756  muse_processing *proc = muse_processing_new("muse_twilight",
757  recipe);
758  int rc = muse_twilight_compute(proc, &params);
759  cpl_frameset_join(usedframes, proc->usedframes);
760  cpl_frameset_join(outframes, proc->outframes);
762 
763  if (!cpl_errorstate_is_equal(prestate)) {
764  /* dump all errors from this recipe in chronological order */
765  cpl_errorstate_dump(prestate, CPL_FALSE, muse_cplerrorstate_dump_some);
766  /* reset message level to not get the same errors displayed again by esorex */
767  cpl_msg_set_level(CPL_MSG_INFO);
768  }
769  /* clean up duplicates in framesets of used and output frames */
772 
773  /* to get esorex to see our classification (frame groups etc.), *
774  * replace the original frameset with the list of used frames *
775  * before appending product output frames */
776  /* keep the same pointer, so just erase all frames, not delete the frameset */
777  muse_cplframeset_erase_all(recipe->frames);
778  cpl_frameset_join(recipe->frames, usedframes);
779  cpl_frameset_join(recipe->frames, outframes);
780  cpl_frameset_delete(usedframes);
781  cpl_frameset_delete(outframes);
782  return rc;
783 } /* muse_twilight_exec() */
784 
785 /*----------------------------------------------------------------------------*/
792 /*----------------------------------------------------------------------------*/
793 static int
794 muse_twilight_destroy(cpl_plugin *aPlugin)
795 {
796  /* Get the recipe from the plugin */
797  cpl_recipe *recipe;
798  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
799  recipe = (cpl_recipe *)aPlugin;
800  } else {
801  return -1;
802  }
803 
804  /* Clean up */
805  cpl_parameterlist_delete(recipe->parameters);
807  return 0;
808 } /* muse_twilight_destroy() */
809 
810 /*----------------------------------------------------------------------------*/
820 /*----------------------------------------------------------------------------*/
821 int
822 cpl_plugin_get_info(cpl_pluginlist *aList)
823 {
824  cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
825  cpl_plugin *plugin = &recipe->interface;
826 
827  char *helptext;
829  helptext = cpl_sprintf("%s%s", muse_twilight_help,
830  muse_twilight_help_esorex);
831  } else {
832  helptext = cpl_sprintf("%s", muse_twilight_help);
833  }
834 
835  /* Initialize the CPL plugin stuff for this module */
836  cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
837  CPL_PLUGIN_TYPE_RECIPE,
838  "muse_twilight",
839  "Combine several twilight skyflats into one cube, compute correction factors for each IFU, and create a smooth 3D illumination correction.",
840  helptext,
841  "Peter Weilbacher",
842  "usd-help@eso.org",
844  muse_twilight_create,
845  muse_twilight_exec,
846  muse_twilight_destroy);
847  cpl_pluginlist_append(aList, plugin);
848  cpl_free(helptext);
849 
850  return 0;
851 } /* cpl_plugin_get_info() */
852 
double crsigma
Sigma rejection factor to use for cosmic ray rejection during final resampling. A zero or negative va...
void muse_processing_delete(muse_processing *aProcessing)
Free the muse_processing structure.
const char * vignsmooth_s
Type of smoothing to use for the vignetted region given by the VIGNETTING_MASK; gaussian uses (vignxp...
int scale
Scale the individual images to a common exposure time before combining them.
double lsigma
Low sigma for pixel rejection with sigclip.
int nkeep
Number of pixels to keep with minmax.
muse_cplframework_type muse_cplframework(void)
Return the CPL framework the recipe is run under.
double ovscsigma
If the deviation of mean overscan levels between a raw input image and the reference image is higher ...
const char * crtype_s
Type of statistics used for detection of cosmic rays during final resampling. "iraf" uses the varianc...
const char * overscan
If this is "none", stop when detecting discrepant overscan levels (see ovscsigma), for "offset" it assumes that the mean overscan level represents the real offset in the bias levels of the exposures involved, and adjusts the data accordingly; for "vpoly", a polynomial is fit to the vertical overscan and subtracted from the whole quadrant.
cpl_frameset * usedframes
muse_processing * muse_processing_new(const char *aName, cpl_recipe *aRecipe)
Create a new processing structure.
int nhigh
Number of maximum pixels to reject with minmax.
const char * muse_get_license(void)
Get the pipeline copyright and license.
Definition: muse_utils.c:83
int vignxpar
Parameter used by the vignetting smoothing: x order for polyfit (default, recommended 4)...
double vignmaskedges
Pixels on edges stronger than this fraction in the normalized image are excluded from the fit to the ...
muse_frame_mode
int vignypar
Parameter used by the vignetting smoothing: y order for polyfit (default, recommended 4)...
cpl_frameset * outframes
const char * combine_s
Type of combination to use (as string)
Structure to hold the parameters of the muse_twilight recipe.
double dlambda
Sampling for twilight reconstruction, this should result in planes of equal wavelength coverage...
int vignsmooth
Type of smoothing to use for the vignetted region given by the VIGNETTING_MASK; gaussian uses (vignxp...
int resample
The resampling technique to use for the final output cube.
void muse_cplerrorstate_dump_some(unsigned aCurrent, unsigned aFirst, unsigned aLast)
Dump some CPL errors.
double lambdamin
Minimum wavelength for twilight reconstruction.
void muse_processinginfo_delete(cpl_recipe *)
Clear all information from the processing info and from the recipe config.
int combine
Type of combination to use.
double hsigma
High sigma for pixel rejection with sigclip.
int yorder
Polynomial order to use in y direction to fit the full field of view.
int xorder
Polynomial order to use in x direction to fit the full field of view.
const char * ovscreject
This influences how values are rejected when computing overscan statistics. Either no rejection at al...
cpl_error_code muse_cplframeset_erase_duplicate(cpl_frameset *aFrames)
Erase all duplicate frames from a frameset.
cpl_error_code muse_cplframeset_erase_all(cpl_frameset *aFrames)
Erase all frames in a frameset.
void muse_processinginfo_register(cpl_recipe *, cpl_recipeconfig *, muse_processing_prepare_header_func *, muse_processing_get_frame_level_func *, muse_processing_get_frame_mode_func *)
Register extended functionalities for MUSE recipes.
int ovscignore
The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when co...
double lambdamax
Maximum wavelength for twilight reconstruction.
void muse_processing_recipeinfo(cpl_plugin *)
Output main pipeline configuration, inputs, and parameters.
int nlow
Number of minimum pixels to reject with minmax.
int crtype
Type of statistics used for detection of cosmic rays during final resampling. "iraf" uses the varianc...
cpl_error_code muse_processing_prepare_property(cpl_propertylist *, const char *, cpl_type, const char *)
Prepare and check the specified property.
const char * resample_s
The resampling technique to use for the final output cube. (as string)