MUSE Pipeline Reference Manual  2.1.1
muse_flat_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_flat_z.h" /* in turn includes muse.h */
36 
37 /*----------------------------------------------------------------------------*/
69 /*----------------------------------------------------------------------------*/
72 /*----------------------------------------------------------------------------*
73  * Static variables *
74  *----------------------------------------------------------------------------*/
75 static const char *muse_flat_help =
76  "This recipe combines several separate flat-field images into one master flat-field file and traces the location of the slices on the CCD. The master flat contains the combined pixel values of the raw flat exposures, with respect to the image combination method used, normalized to the mean flux. The trace table contains polynomials defining the location of the slices on the CCD. Processing trims the raw data and records the overscan statistics, subtracts the bias (taking account of the overscan, if --overscan is not \"none\"), and optionally, the dark from each raw input image, converts them from adu to count, scales them according to their exposure time, and combines the exposures using input parameters. To trace the position of the slices on the CCD, their edges are located using a threshold method. The edge detection is repeated at given intervals thereby tracing the central position (the mean of both edges) and width of each slit vertically across the CCD. Deviant positions of detections on CCD rows can be detected and excluded before fitting a polynomial to all positions measured for one slice. The polynomial parameters for each slice are saved in the output trace table. Finally, the area between the now known slice edges is searched for dark (and bright) pixels, using statistics in each row of the master flat.";
77 
78 static const char *muse_flat_help_esorex =
79  "\n\nInput frames for raw frame tag \"FLAT\":\n"
80  "\n Frame tag Type Req #Fr Description"
81  "\n -------------------- ---- --- --- ------------"
82  "\n FLAT raw Y >=3 Raw flat"
83  "\n MASTER_BIAS calib Y 1 Master bias"
84  "\n MASTER_DARK calib . 1 Master dark"
85  "\n BADPIX_TABLE calib . Known bad pixels"
86  "\n\nProduct frames for raw frame tag \"FLAT\":\n"
87  "\n Frame tag Level Description"
88  "\n -------------------- -------- ------------"
89  "\n MASTER_FLAT final Master flat"
90  "\n TRACE_TABLE final Trace table"
91  "\n TRACE_SAMPLES final Table containing all tracing sample points, if --samples=true";
92 
93 /*----------------------------------------------------------------------------*/
101 /*----------------------------------------------------------------------------*/
102 static cpl_recipeconfig *
103 muse_flat_new_recipeconfig(void)
104 {
105  cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
106 
107  cpl_recipeconfig_set_tag(recipeconfig, "FLAT", 3, -1);
108  cpl_recipeconfig_set_input(recipeconfig, "FLAT", "MASTER_BIAS", 1, 1);
109  cpl_recipeconfig_set_input(recipeconfig, "FLAT", "MASTER_DARK", -1, 1);
110  cpl_recipeconfig_set_input(recipeconfig, "FLAT", "BADPIX_TABLE", -1, -1);
111  cpl_recipeconfig_set_output(recipeconfig, "FLAT", "MASTER_FLAT");
112  cpl_recipeconfig_set_output(recipeconfig, "FLAT", "TRACE_TABLE");
113  cpl_recipeconfig_set_output(recipeconfig, "FLAT", "TRACE_SAMPLES");
114 
115  return recipeconfig;
116 } /* muse_flat_new_recipeconfig() */
117 
118 /*----------------------------------------------------------------------------*/
128 /*----------------------------------------------------------------------------*/
129 static cpl_error_code
130 muse_flat_prepare_header(const char *aFrametag, cpl_propertylist *aHeader)
131 {
132  cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
133  cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
134  if (!strcmp(aFrametag, "MASTER_FLAT")) {
135  muse_processing_prepare_property(aHeader, "ESO QC FLAT INPUT[0-9]+ MEDIAN",
136  CPL_TYPE_FLOAT,
137  "Median value of raw flat i in input list");
138  muse_processing_prepare_property(aHeader, "ESO QC FLAT INPUT[0-9]+ MEAN",
139  CPL_TYPE_FLOAT,
140  "Mean value of raw flat i in input list");
141  muse_processing_prepare_property(aHeader, "ESO QC FLAT INPUT[0-9]+ STDEV",
142  CPL_TYPE_FLOAT,
143  "Standard deviation of raw flat i in input list");
144  muse_processing_prepare_property(aHeader, "ESO QC FLAT INPUT[0-9]+ MIN",
145  CPL_TYPE_FLOAT,
146  "Minimum value of raw flat i in input list");
147  muse_processing_prepare_property(aHeader, "ESO QC FLAT INPUT[0-9]+ MAX",
148  CPL_TYPE_FLOAT,
149  "Maximum value of raw flat i in input list");
150  muse_processing_prepare_property(aHeader, "ESO QC FLAT INPUT[0-9]+ NSATURATED",
151  CPL_TYPE_INT,
152  "Number of saturated pixels in raw flat i in input list");
153  muse_processing_prepare_property(aHeader, "ESO QC FLAT MASTER MEDIAN",
154  CPL_TYPE_FLOAT,
155  "Median value of the master flat before normalization");
156  muse_processing_prepare_property(aHeader, "ESO QC FLAT MASTER MEAN",
157  CPL_TYPE_FLOAT,
158  "Mean value of the master flat before normalization");
159  muse_processing_prepare_property(aHeader, "ESO QC FLAT MASTER STDEV",
160  CPL_TYPE_FLOAT,
161  "Standard deviation of the master flat before normalization");
162  muse_processing_prepare_property(aHeader, "ESO QC FLAT MASTER MIN",
163  CPL_TYPE_FLOAT,
164  "Minimum value of the master flat before normalization");
165  muse_processing_prepare_property(aHeader, "ESO QC FLAT MASTER MAX",
166  CPL_TYPE_FLOAT,
167  "Maximum value of the master flat before normalization");
168  muse_processing_prepare_property(aHeader, "ESO QC FLAT MASTER INTFLUX",
169  CPL_TYPE_FLOAT,
170  "Flux value, integrated over the whole master flat field before normalization");
171  muse_processing_prepare_property(aHeader, "ESO QC FLAT MASTER NSATURATED",
172  CPL_TYPE_INT,
173  "Number of saturated pixels in output data");
174  muse_processing_prepare_property(aHeader, "ESO QC FLAT MASTER SLICE[0-9]+ MEAN",
175  CPL_TYPE_FLOAT,
176  "Mean value around the vertical center of slice j before normalization");
177  muse_processing_prepare_property(aHeader, "ESO QC FLAT MASTER SLICE[0-9]+ STDEV",
178  CPL_TYPE_FLOAT,
179  "Standard deviation around the vertical center of slice j before normalization");
180  } else if (!strcmp(aFrametag, "TRACE_TABLE")) {
181  muse_processing_prepare_property(aHeader, "ESO QC TRACE SLICE_L XPOS",
182  CPL_TYPE_FLOAT,
183  "[pix] Location of midpoint of leftmost slice");
184  muse_processing_prepare_property(aHeader, "ESO QC TRACE SLICE_L TILT",
185  CPL_TYPE_FLOAT,
186  "[deg] Tilt of leftmost slice, measured as angle from vertical direction");
187  muse_processing_prepare_property(aHeader, "ESO QC TRACE SLICE_R XPOS",
188  CPL_TYPE_FLOAT,
189  "[pix] Location of midpoint of rightmost slice");
190  muse_processing_prepare_property(aHeader, "ESO QC TRACE SLICE_R TILT",
191  CPL_TYPE_FLOAT,
192  "[deg] Tilt of rightmost slice, measured as angle from vertical direction");
193  muse_processing_prepare_property(aHeader, "ESO QC TRACE SLICE[0-9]+ MAXSLOPE",
194  CPL_TYPE_FLOAT,
195  "The maximum slope of the derived tracing functions of slice j within the CCD.");
196  muse_processing_prepare_property(aHeader, "ESO QC TRACE SLICE10 WIDTH",
197  CPL_TYPE_FLOAT,
198  "[pix] Width of top left slice in the IFU (10 on CCD)");
199  muse_processing_prepare_property(aHeader, "ESO QC TRACE SLICE46 WIDTH",
200  CPL_TYPE_FLOAT,
201  "[pix] Width of top right slice in the IFU (46 on CCD)");
202  muse_processing_prepare_property(aHeader, "ESO QC TRACE SLICE3 WIDTH",
203  CPL_TYPE_FLOAT,
204  "[pix] Width of bottom left slice in the IFU (3 on CCD)");
205  muse_processing_prepare_property(aHeader, "ESO QC TRACE SLICE39 WIDTH",
206  CPL_TYPE_FLOAT,
207  "[pix] Width of bottom right slice in the IFU (39 on CCD)");
208  muse_processing_prepare_property(aHeader, "ESO QC TRACE WIDTHS MEDIAN",
209  CPL_TYPE_FLOAT,
210  "[pix] Median width of slices");
211  muse_processing_prepare_property(aHeader, "ESO QC TRACE WIDTHS MEAN",
212  CPL_TYPE_FLOAT,
213  "[pix] Mean width of slices");
214  muse_processing_prepare_property(aHeader, "ESO QC TRACE WIDTHS STDEV",
215  CPL_TYPE_FLOAT,
216  "[pix] Standard deviation of widths of slices");
217  muse_processing_prepare_property(aHeader, "ESO QC TRACE WIDTHS MIN",
218  CPL_TYPE_FLOAT,
219  "[pix] Minimum width of slices");
220  muse_processing_prepare_property(aHeader, "ESO QC TRACE WIDTHS MAX",
221  CPL_TYPE_FLOAT,
222  "[pix] Maximum width of slices");
223  muse_processing_prepare_property(aHeader, "ESO QC TRACE GAPS MEDIAN",
224  CPL_TYPE_FLOAT,
225  "[pix] Median of gaps between slices");
226  muse_processing_prepare_property(aHeader, "ESO QC TRACE GAPS MEAN",
227  CPL_TYPE_FLOAT,
228  "[pix] Mean of gaps between slices");
229  muse_processing_prepare_property(aHeader, "ESO QC TRACE GAPS STDEV",
230  CPL_TYPE_FLOAT,
231  "[pix] Standard deviation of gaps between slices");
232  muse_processing_prepare_property(aHeader, "ESO QC TRACE GAPS MIN",
233  CPL_TYPE_FLOAT,
234  "[pix] Minimum of gap between slices");
235  muse_processing_prepare_property(aHeader, "ESO QC TRACE GAPS MAX",
236  CPL_TYPE_FLOAT,
237  "[pix] Maximum gap between slices");
238  } else if (!strcmp(aFrametag, "TRACE_SAMPLES")) {
239  } else {
240  cpl_msg_warning(__func__, "Frame tag %s is not defined", aFrametag);
241  return CPL_ERROR_ILLEGAL_INPUT;
242  }
243  return CPL_ERROR_NONE;
244 } /* muse_flat_prepare_header() */
245 
246 /*----------------------------------------------------------------------------*/
255 /*----------------------------------------------------------------------------*/
256 static cpl_frame_level
257 muse_flat_get_frame_level(const char *aFrametag)
258 {
259  if (!aFrametag) {
260  return CPL_FRAME_LEVEL_NONE;
261  }
262  if (!strcmp(aFrametag, "MASTER_FLAT")) {
263  return CPL_FRAME_LEVEL_FINAL;
264  }
265  if (!strcmp(aFrametag, "TRACE_TABLE")) {
266  return CPL_FRAME_LEVEL_FINAL;
267  }
268  if (!strcmp(aFrametag, "TRACE_SAMPLES")) {
269  return CPL_FRAME_LEVEL_FINAL;
270  }
271  return CPL_FRAME_LEVEL_NONE;
272 } /* muse_flat_get_frame_level() */
273 
274 /*----------------------------------------------------------------------------*/
283 /*----------------------------------------------------------------------------*/
284 static muse_frame_mode
285 muse_flat_get_frame_mode(const char *aFrametag)
286 {
287  if (!aFrametag) {
288  return MUSE_FRAME_MODE_ALL;
289  }
290  if (!strcmp(aFrametag, "MASTER_FLAT")) {
291  return MUSE_FRAME_MODE_MASTER;
292  }
293  if (!strcmp(aFrametag, "TRACE_TABLE")) {
294  return MUSE_FRAME_MODE_MASTER;
295  }
296  if (!strcmp(aFrametag, "TRACE_SAMPLES")) {
297  return MUSE_FRAME_MODE_MASTER;
298  }
299  return MUSE_FRAME_MODE_ALL;
300 } /* muse_flat_get_frame_mode() */
301 
302 /*----------------------------------------------------------------------------*/
312 /*----------------------------------------------------------------------------*/
313 static int
314 muse_flat_create(cpl_plugin *aPlugin)
315 {
316  /* Check that the plugin is part of a valid recipe */
317  cpl_recipe *recipe;
318  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
319  recipe = (cpl_recipe *)aPlugin;
320  } else {
321  return -1;
322  }
323 
324  /* register the extended processing information (new FITS header creation, *
325  * getting of the frame level for a certain tag) */
327  muse_flat_new_recipeconfig(),
328  muse_flat_prepare_header,
329  muse_flat_get_frame_level,
330  muse_flat_get_frame_mode);
331 
332  /* XXX initialize timing in messages *
333  * since at least esorex is too stupid to turn it on, we have to do it */
335  cpl_msg_set_time_on();
336  }
337 
338  /* Create the parameter list in the cpl_recipe object */
339  recipe->parameters = cpl_parameterlist_new();
340  /* Fill the parameters list */
341  cpl_parameter *p;
342 
343  /* --nifu: IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel. */
344  p = cpl_parameter_new_range("muse.muse_flat.nifu",
345  CPL_TYPE_INT,
346  "IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel.",
347  "muse.muse_flat",
348  (int)0,
349  (int)-1,
350  (int)24);
351  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nifu");
352  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nifu");
353 
354  cpl_parameterlist_append(recipe->parameters, p);
355 
356  /* --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. */
357  p = cpl_parameter_new_value("muse.muse_flat.overscan",
358  CPL_TYPE_STRING,
359  "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.",
360  "muse.muse_flat",
361  (const char *)"vpoly");
362  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "overscan");
363  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "overscan");
364 
365  cpl_parameterlist_append(recipe->parameters, p);
366 
367  /* --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"). */
368  p = cpl_parameter_new_value("muse.muse_flat.ovscreject",
369  CPL_TYPE_STRING,
370  "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\").",
371  "muse.muse_flat",
372  (const char *)"dcr");
373  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscreject");
374  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscreject");
375 
376  cpl_parameterlist_append(recipe->parameters, p);
377 
378  /* --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". */
379  p = cpl_parameter_new_value("muse.muse_flat.ovscsigma",
380  CPL_TYPE_DOUBLE,
381  "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\".",
382  "muse.muse_flat",
383  (double)30.);
384  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscsigma");
385  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscsigma");
386 
387  cpl_parameterlist_append(recipe->parameters, p);
388 
389  /* --ovscignore: The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when computing statistics or fits. */
390  p = cpl_parameter_new_value("muse.muse_flat.ovscignore",
391  CPL_TYPE_INT,
392  "The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when computing statistics or fits.",
393  "muse.muse_flat",
394  (int)3);
395  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscignore");
396  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscignore");
397 
398  cpl_parameterlist_append(recipe->parameters, p);
399 
400  /* --combine: Type of combination to use */
401  p = cpl_parameter_new_enum("muse.muse_flat.combine",
402  CPL_TYPE_STRING,
403  "Type of combination to use",
404  "muse.muse_flat",
405  (const char *)"sigclip",
406  4,
407  (const char *)"average",
408  (const char *)"median",
409  (const char *)"minmax",
410  (const char *)"sigclip");
411  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "combine");
412  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "combine");
413 
414  cpl_parameterlist_append(recipe->parameters, p);
415 
416  /* --nlow: Number of minimum pixels to reject with minmax */
417  p = cpl_parameter_new_value("muse.muse_flat.nlow",
418  CPL_TYPE_INT,
419  "Number of minimum pixels to reject with minmax",
420  "muse.muse_flat",
421  (int)1);
422  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nlow");
423  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nlow");
424 
425  cpl_parameterlist_append(recipe->parameters, p);
426 
427  /* --nhigh: Number of maximum pixels to reject with minmax */
428  p = cpl_parameter_new_value("muse.muse_flat.nhigh",
429  CPL_TYPE_INT,
430  "Number of maximum pixels to reject with minmax",
431  "muse.muse_flat",
432  (int)1);
433  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nhigh");
434  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nhigh");
435 
436  cpl_parameterlist_append(recipe->parameters, p);
437 
438  /* --nkeep: Number of pixels to keep with minmax */
439  p = cpl_parameter_new_value("muse.muse_flat.nkeep",
440  CPL_TYPE_INT,
441  "Number of pixels to keep with minmax",
442  "muse.muse_flat",
443  (int)1);
444  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nkeep");
445  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nkeep");
446 
447  cpl_parameterlist_append(recipe->parameters, p);
448 
449  /* --lsigma: Low sigma for pixel rejection with sigclip */
450  p = cpl_parameter_new_value("muse.muse_flat.lsigma",
451  CPL_TYPE_DOUBLE,
452  "Low sigma for pixel rejection with sigclip",
453  "muse.muse_flat",
454  (double)3);
455  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lsigma");
456  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lsigma");
457 
458  cpl_parameterlist_append(recipe->parameters, p);
459 
460  /* --hsigma: High sigma for pixel rejection with sigclip */
461  p = cpl_parameter_new_value("muse.muse_flat.hsigma",
462  CPL_TYPE_DOUBLE,
463  "High sigma for pixel rejection with sigclip",
464  "muse.muse_flat",
465  (double)3);
466  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "hsigma");
467  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "hsigma");
468 
469  cpl_parameterlist_append(recipe->parameters, p);
470 
471  /* --scale: Scale the individual images to a common exposure time before combining them. */
472  p = cpl_parameter_new_value("muse.muse_flat.scale",
473  CPL_TYPE_BOOL,
474  "Scale the individual images to a common exposure time before combining them.",
475  "muse.muse_flat",
476  (int)TRUE);
477  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "scale");
478  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scale");
479  if (!getenv("MUSE_EXPERT_USER")) {
480  cpl_parameter_disable(p, CPL_PARAMETER_MODE_CLI);
481  }
482 
483  cpl_parameterlist_append(recipe->parameters, p);
484 
485  /* --normalize: Normalize the master flat to the average flux */
486  p = cpl_parameter_new_value("muse.muse_flat.normalize",
487  CPL_TYPE_BOOL,
488  "Normalize the master flat to the average flux",
489  "muse.muse_flat",
490  (int)TRUE);
491  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "normalize");
492  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "normalize");
493  if (!getenv("MUSE_EXPERT_USER")) {
494  cpl_parameter_disable(p, CPL_PARAMETER_MODE_CLI);
495  }
496 
497  cpl_parameterlist_append(recipe->parameters, p);
498 
499  /* --trace: Trace the position of the slices on the master flat */
500  p = cpl_parameter_new_value("muse.muse_flat.trace",
501  CPL_TYPE_BOOL,
502  "Trace the position of the slices on the master flat",
503  "muse.muse_flat",
504  (int)TRUE);
505  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "trace");
506  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "trace");
507 
508  cpl_parameterlist_append(recipe->parameters, p);
509 
510  /* --nsum: Number of lines over which to average when tracing */
511  p = cpl_parameter_new_value("muse.muse_flat.nsum",
512  CPL_TYPE_INT,
513  "Number of lines over which to average when tracing",
514  "muse.muse_flat",
515  (int)32);
516  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nsum");
517  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nsum");
518 
519  cpl_parameterlist_append(recipe->parameters, p);
520 
521  /* --order: Order of polynomial fit to the trace */
522  p = cpl_parameter_new_value("muse.muse_flat.order",
523  CPL_TYPE_INT,
524  "Order of polynomial fit to the trace",
525  "muse.muse_flat",
526  (int)5);
527  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "order");
528  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "order");
529 
530  cpl_parameterlist_append(recipe->parameters, p);
531 
532  /* --edgefrac: Fractional change required to identify edge when tracing */
533  p = cpl_parameter_new_value("muse.muse_flat.edgefrac",
534  CPL_TYPE_DOUBLE,
535  "Fractional change required to identify edge when tracing",
536  "muse.muse_flat",
537  (double)0.5);
538  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "edgefrac");
539  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "edgefrac");
540 
541  cpl_parameterlist_append(recipe->parameters, p);
542 
543  /* --losigmabadpix: Low sigma to find dark pixels in the master flat */
544  p = cpl_parameter_new_value("muse.muse_flat.losigmabadpix",
545  CPL_TYPE_DOUBLE,
546  "Low sigma to find dark pixels in the master flat",
547  "muse.muse_flat",
548  (double)5.);
549  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "losigmabadpix");
550  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "losigmabadpix");
551 
552  cpl_parameterlist_append(recipe->parameters, p);
553 
554  /* --hisigmabadpix: High sigma to find bright pixels in the master flat */
555  p = cpl_parameter_new_value("muse.muse_flat.hisigmabadpix",
556  CPL_TYPE_DOUBLE,
557  "High sigma to find bright pixels in the master flat",
558  "muse.muse_flat",
559  (double)5.);
560  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "hisigmabadpix");
561  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "hisigmabadpix");
562 
563  cpl_parameterlist_append(recipe->parameters, p);
564 
565  /* --samples: Create a table containing all tracing sample points. */
566  p = cpl_parameter_new_value("muse.muse_flat.samples",
567  CPL_TYPE_BOOL,
568  "Create a table containing all tracing sample points.",
569  "muse.muse_flat",
570  (int)FALSE);
571  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "samples");
572  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "samples");
573 
574  cpl_parameterlist_append(recipe->parameters, p);
575 
576  /* --merge: Merge output products from different IFUs into a common file. */
577  p = cpl_parameter_new_value("muse.muse_flat.merge",
578  CPL_TYPE_BOOL,
579  "Merge output products from different IFUs into a common file.",
580  "muse.muse_flat",
581  (int)FALSE);
582  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "merge");
583  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "merge");
584 
585  cpl_parameterlist_append(recipe->parameters, p);
586 
587  return 0;
588 } /* muse_flat_create() */
589 
590 /*----------------------------------------------------------------------------*/
601 /*----------------------------------------------------------------------------*/
602 static int
603 muse_flat_params_fill(muse_flat_params_t *aParams, cpl_parameterlist *aParameters)
604 {
605  cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
606  cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
607  cpl_parameter *p;
608 
609  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.nifu");
610  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
611  aParams->nifu = cpl_parameter_get_int(p);
612 
613  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.overscan");
614  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
615  aParams->overscan = cpl_parameter_get_string(p);
616 
617  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.ovscreject");
618  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
619  aParams->ovscreject = cpl_parameter_get_string(p);
620 
621  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.ovscsigma");
622  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
623  aParams->ovscsigma = cpl_parameter_get_double(p);
624 
625  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.ovscignore");
626  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
627  aParams->ovscignore = cpl_parameter_get_int(p);
628 
629  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.combine");
630  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
631  aParams->combine_s = cpl_parameter_get_string(p);
632  aParams->combine =
633  (!strcasecmp(aParams->combine_s, "average")) ? MUSE_FLAT_PARAM_COMBINE_AVERAGE :
634  (!strcasecmp(aParams->combine_s, "median")) ? MUSE_FLAT_PARAM_COMBINE_MEDIAN :
635  (!strcasecmp(aParams->combine_s, "minmax")) ? MUSE_FLAT_PARAM_COMBINE_MINMAX :
636  (!strcasecmp(aParams->combine_s, "sigclip")) ? MUSE_FLAT_PARAM_COMBINE_SIGCLIP :
637  MUSE_FLAT_PARAM_COMBINE_INVALID_VALUE;
638  cpl_ensure_code(aParams->combine != MUSE_FLAT_PARAM_COMBINE_INVALID_VALUE,
639  CPL_ERROR_ILLEGAL_INPUT);
640 
641  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.nlow");
642  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
643  aParams->nlow = cpl_parameter_get_int(p);
644 
645  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.nhigh");
646  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
647  aParams->nhigh = cpl_parameter_get_int(p);
648 
649  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.nkeep");
650  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
651  aParams->nkeep = cpl_parameter_get_int(p);
652 
653  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.lsigma");
654  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
655  aParams->lsigma = cpl_parameter_get_double(p);
656 
657  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.hsigma");
658  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
659  aParams->hsigma = cpl_parameter_get_double(p);
660 
661  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.scale");
662  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
663  aParams->scale = cpl_parameter_get_bool(p);
664 
665  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.normalize");
666  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
667  aParams->normalize = cpl_parameter_get_bool(p);
668 
669  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.trace");
670  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
671  aParams->trace = cpl_parameter_get_bool(p);
672 
673  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.nsum");
674  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
675  aParams->nsum = cpl_parameter_get_int(p);
676 
677  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.order");
678  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
679  aParams->order = cpl_parameter_get_int(p);
680 
681  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.edgefrac");
682  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
683  aParams->edgefrac = cpl_parameter_get_double(p);
684 
685  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.losigmabadpix");
686  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
687  aParams->losigmabadpix = cpl_parameter_get_double(p);
688 
689  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.hisigmabadpix");
690  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
691  aParams->hisigmabadpix = cpl_parameter_get_double(p);
692 
693  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.samples");
694  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
695  aParams->samples = cpl_parameter_get_bool(p);
696 
697  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.merge");
698  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
699  aParams->merge = cpl_parameter_get_bool(p);
700 
701  return 0;
702 } /* muse_flat_params_fill() */
703 
704 /*----------------------------------------------------------------------------*/
711 /*----------------------------------------------------------------------------*/
712 static int
713 muse_flat_exec(cpl_plugin *aPlugin)
714 {
715  if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
716  return -1;
717  }
719  cpl_recipe *recipe = (cpl_recipe *)aPlugin;
720  cpl_msg_set_threadid_on();
721 
722  cpl_frameset *usedframes = cpl_frameset_new(),
723  *outframes = cpl_frameset_new();
724  muse_flat_params_t params;
725  muse_flat_params_fill(&params, recipe->parameters);
726 
727  cpl_errorstate prestate = cpl_errorstate_get();
728 
729  if (params.nifu < -1 || params.nifu > kMuseNumIFUs) {
730  cpl_msg_error(__func__, "Please specify a valid IFU number (between 1 and "
731  "%d), 0 (to process all IFUs consecutively), or -1 (to "
732  "process all IFUs in parallel) using --nifu.", kMuseNumIFUs);
733  return -1;
734  } /* if invalid params.nifu */
735 
736  cpl_boolean donotmerge = CPL_FALSE; /* depending on nifu we may not merge */
737  int rc = 0;
738  if (params.nifu > 0) {
739  muse_processing *proc = muse_processing_new("muse_flat",
740  recipe);
741  rc = muse_flat_compute(proc, &params);
742  cpl_frameset_join(usedframes, proc->usedframes);
743  cpl_frameset_join(outframes, proc->outframes);
745  donotmerge = CPL_TRUE; /* after processing one IFU, merging cannot work */
746  } else if (params.nifu < 0) { /* parallel processing */
747  int *rcs = cpl_calloc(kMuseNumIFUs, sizeof(int));
748  int nifu;
749  #pragma omp parallel for default(none) \
750  shared(outframes, params, rcs, recipe, usedframes)
751  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
752  muse_processing *proc = muse_processing_new("muse_flat",
753  recipe);
754  muse_flat_params_t *pars = cpl_malloc(sizeof(muse_flat_params_t));
755  memcpy(pars, &params, sizeof(muse_flat_params_t));
756  pars->nifu = nifu;
757  int *rci = rcs + (nifu - 1);
758  *rci = muse_flat_compute(proc, pars);
759  if (rci && (int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
760  *rci = 0;
761  }
762  cpl_free(pars);
763  #pragma omp critical(muse_processing_used_frames)
764  cpl_frameset_join(usedframes, proc->usedframes);
765  #pragma omp critical(muse_processing_output_frames)
766  cpl_frameset_join(outframes, proc->outframes);
768  } /* for nifu */
769  /* non-parallel loop to propagate the "worst" return code; *
770  * since we only ever return -1, any non-zero code is propagated */
771  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
772  if (rcs[nifu-1] != 0) {
773  rc = rcs[nifu-1];
774  } /* if */
775  } /* for nifu */
776  cpl_free(rcs);
777  } else { /* serial processing */
778  for (params.nifu = 1; params.nifu <= kMuseNumIFUs && !rc; params.nifu++) {
779  muse_processing *proc = muse_processing_new("muse_flat",
780  recipe);
781  rc = muse_flat_compute(proc, &params);
782  if (rc && (int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
783  rc = 0;
784  }
785  cpl_frameset_join(usedframes, proc->usedframes);
786  cpl_frameset_join(outframes, proc->outframes);
788  } /* for nifu */
789  } /* else */
790  UNUSED_ARGUMENT(donotmerge); /* maybe this is not going to be used below */
791 
792  if (!cpl_errorstate_is_equal(prestate)) {
793  /* dump all errors from this recipe in chronological order */
794  cpl_errorstate_dump(prestate, CPL_FALSE, muse_cplerrorstate_dump_some);
795  /* reset message level to not get the same errors displayed again by esorex */
796  cpl_msg_set_level(CPL_MSG_INFO);
797  }
798  /* clean up duplicates in framesets of used and output frames */
801 
802  /* merge output products from the up to 24 IFUs */
803  if (params.merge && !donotmerge) {
804  muse_utils_frameset_merge_frames(outframes, CPL_TRUE);
805  }
806 
807  /* to get esorex to see our classification (frame groups etc.), *
808  * replace the original frameset with the list of used frames *
809  * before appending product output frames */
810  /* keep the same pointer, so just erase all frames, not delete the frameset */
811  muse_cplframeset_erase_all(recipe->frames);
812  cpl_frameset_join(recipe->frames, usedframes);
813  cpl_frameset_join(recipe->frames, outframes);
814  cpl_frameset_delete(usedframes);
815  cpl_frameset_delete(outframes);
816  return rc;
817 } /* muse_flat_exec() */
818 
819 /*----------------------------------------------------------------------------*/
826 /*----------------------------------------------------------------------------*/
827 static int
828 muse_flat_destroy(cpl_plugin *aPlugin)
829 {
830  /* Get the recipe from the plugin */
831  cpl_recipe *recipe;
832  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
833  recipe = (cpl_recipe *)aPlugin;
834  } else {
835  return -1;
836  }
837 
838  /* Clean up */
839  cpl_parameterlist_delete(recipe->parameters);
841  return 0;
842 } /* muse_flat_destroy() */
843 
844 /*----------------------------------------------------------------------------*/
854 /*----------------------------------------------------------------------------*/
855 int
856 cpl_plugin_get_info(cpl_pluginlist *aList)
857 {
858  cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
859  cpl_plugin *plugin = &recipe->interface;
860 
861  char *helptext;
863  helptext = cpl_sprintf("%s%s", muse_flat_help,
864  muse_flat_help_esorex);
865  } else {
866  helptext = cpl_sprintf("%s", muse_flat_help);
867  }
868 
869  /* Initialize the CPL plugin stuff for this module */
870  cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
871  CPL_PLUGIN_TYPE_RECIPE,
872  "muse_flat",
873  "Combine several separate flat images into one master flat file, trace slice locations, and locate dark pixels.",
874  helptext,
875  "Peter Weilbacher (based on Joris Gerssen's draft)",
876  "usd-help@eso.org",
878  muse_flat_create,
879  muse_flat_exec,
880  muse_flat_destroy);
881  cpl_pluginlist_append(aList, plugin);
882  cpl_free(helptext);
883 
884  return 0;
885 } /* cpl_plugin_get_info() */
886 
int nifu
IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in ...
Definition: muse_flat_z.h:50
void muse_processing_delete(muse_processing *aProcessing)
Free the muse_processing structure.
int order
Order of polynomial fit to the trace.
Definition: muse_flat_z.h:97
double lsigma
Low sigma for pixel rejection with sigclip.
Definition: muse_flat_z.h:79
int scale
Scale the individual images to a common exposure time before combining them.
Definition: muse_flat_z.h:85
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 ...
Definition: muse_flat_z.h:59
int normalize
Normalize the master flat to the average flux.
Definition: muse_flat_z.h:88
Structure to hold the parameters of the muse_flat recipe.
Definition: muse_flat_z.h:48
int combine
Type of combination to use.
Definition: muse_flat_z.h:65
cpl_frameset * usedframes
muse_processing * muse_processing_new(const char *aName, cpl_recipe *aRecipe)
Create a new processing structure.
const char * muse_get_license(void)
Get the pipeline copyright and license.
Definition: muse_utils.c:83
int merge
Merge output products from different IFUs into a common file.
Definition: muse_flat_z.h:112
muse_frame_mode
cpl_frameset * outframes
int nsum
Number of lines over which to average when tracing.
Definition: muse_flat_z.h:94
const char * ovscreject
This influences how values are rejected when computing overscan statistics. Either no rejection at al...
Definition: muse_flat_z.h:56
int samples
Create a table containing all tracing sample points.
Definition: muse_flat_z.h:109
int nkeep
Number of pixels to keep with minmax.
Definition: muse_flat_z.h:76
void muse_cplerrorstate_dump_some(unsigned aCurrent, unsigned aFirst, unsigned aLast)
Dump some CPL errors.
void muse_processinginfo_delete(cpl_recipe *)
Clear all information from the processing info and from the recipe config.
int nlow
Number of minimum pixels to reject with minmax.
Definition: muse_flat_z.h:70
int ovscignore
The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when co...
Definition: muse_flat_z.h:62
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.
Definition: muse_flat_z.h:53
cpl_error_code muse_cplframeset_erase_duplicate(cpl_frameset *aFrames)
Erase all duplicate frames from a frameset.
double edgefrac
Fractional change required to identify edge when tracing.
Definition: muse_flat_z.h:100
cpl_error_code muse_cplframeset_erase_all(cpl_frameset *aFrames)
Erase all frames in a frameset.
double losigmabadpix
Low sigma to find dark pixels in the master flat.
Definition: muse_flat_z.h:103
double hsigma
High sigma for pixel rejection with sigclip.
Definition: muse_flat_z.h:82
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 trace
Trace the position of the slices on the master flat.
Definition: muse_flat_z.h:91
const char * combine_s
Type of combination to use (as string)
Definition: muse_flat_z.h:67
void muse_processing_recipeinfo(cpl_plugin *)
Output main pipeline configuration, inputs, and parameters.
cpl_error_code muse_utils_frameset_merge_frames(cpl_frameset *aFrames, cpl_boolean aDelete)
Merge IFU-specific files from a frameset to create multi-IFU outputs.
Definition: muse_utils.c:589
int nhigh
Number of maximum pixels to reject with minmax.
Definition: muse_flat_z.h:73
double hisigmabadpix
High sigma to find bright pixels in the master flat.
Definition: muse_flat_z.h:106
cpl_error_code muse_processing_prepare_property(cpl_propertylist *, const char *, cpl_type, const char *)
Prepare and check the specified property.