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