MUSE Pipeline Reference Manual  0.18.5
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-2013 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 Tracing table for all slices"
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 WIDTHS MEDIAN",
199  CPL_TYPE_FLOAT,
200  "[pix] Median width of slices");
201  muse_processing_prepare_property(aHeader, "ESO QC TRACE WIDTHS MEAN",
202  CPL_TYPE_FLOAT,
203  "[pix] Mean width of slices");
204  muse_processing_prepare_property(aHeader, "ESO QC TRACE WIDTHS STDEV",
205  CPL_TYPE_FLOAT,
206  "[pix] Standard deviation of widths of slices");
207  muse_processing_prepare_property(aHeader, "ESO QC TRACE WIDTHS MIN",
208  CPL_TYPE_FLOAT,
209  "[pix] Minimum width of slices");
210  muse_processing_prepare_property(aHeader, "ESO QC TRACE WIDTHS MAX",
211  CPL_TYPE_FLOAT,
212  "[pix] Maximum width of slices");
213  muse_processing_prepare_property(aHeader, "ESO QC TRACE GAPS MEDIAN",
214  CPL_TYPE_FLOAT,
215  "[pix] Median of gaps between slices");
216  muse_processing_prepare_property(aHeader, "ESO QC TRACE GAPS MEAN",
217  CPL_TYPE_FLOAT,
218  "[pix] Mean of gaps between slices");
219  muse_processing_prepare_property(aHeader, "ESO QC TRACE GAPS STDEV",
220  CPL_TYPE_FLOAT,
221  "[pix] Standard deviation of gaps between slices");
222  muse_processing_prepare_property(aHeader, "ESO QC TRACE GAPS MIN",
223  CPL_TYPE_FLOAT,
224  "[pix] Minimum of gap between slices");
225  muse_processing_prepare_property(aHeader, "ESO QC TRACE GAPS MAX",
226  CPL_TYPE_FLOAT,
227  "[pix] Maximum gap between slices");
228  } else if (!strcmp(aFrametag, "TRACE_SAMPLES")) {
229  } else {
230  cpl_msg_warning(__func__, "Frame tag %s is not defined", aFrametag);
231  return CPL_ERROR_ILLEGAL_INPUT;
232  }
233  return CPL_ERROR_NONE;
234 } /* muse_flat_prepare_header() */
235 
236 /*----------------------------------------------------------------------------*/
245 /*----------------------------------------------------------------------------*/
246 static cpl_frame_level
247 muse_flat_get_frame_level(const char *aFrametag)
248 {
249  if (!aFrametag) {
250  return CPL_FRAME_LEVEL_NONE;
251  }
252  if (!strcmp(aFrametag, "MASTER_FLAT")) {
253  return CPL_FRAME_LEVEL_FINAL;
254  }
255  if (!strcmp(aFrametag, "TRACE_TABLE")) {
256  return CPL_FRAME_LEVEL_FINAL;
257  }
258  if (!strcmp(aFrametag, "TRACE_SAMPLES")) {
259  return CPL_FRAME_LEVEL_FINAL;
260  }
261  return CPL_FRAME_LEVEL_NONE;
262 } /* muse_flat_get_frame_level() */
263 
264 /*----------------------------------------------------------------------------*/
273 /*----------------------------------------------------------------------------*/
274 static muse_frame_mode
275 muse_flat_get_frame_mode(const char *aFrametag)
276 {
277  if (!aFrametag) {
278  return MUSE_FRAME_MODE_ALL;
279  }
280  if (!strcmp(aFrametag, "MASTER_FLAT")) {
281  return MUSE_FRAME_MODE_MASTER;
282  }
283  if (!strcmp(aFrametag, "TRACE_TABLE")) {
284  return MUSE_FRAME_MODE_MASTER;
285  }
286  if (!strcmp(aFrametag, "TRACE_SAMPLES")) {
287  return MUSE_FRAME_MODE_MASTER;
288  }
289  return MUSE_FRAME_MODE_ALL;
290 } /* muse_flat_get_frame_mode() */
291 
292 /*----------------------------------------------------------------------------*/
302 /*----------------------------------------------------------------------------*/
303 static int
304 muse_flat_create(cpl_plugin *aPlugin)
305 {
306  /* Check that the plugin is part of a valid recipe */
307  cpl_recipe *recipe;
308  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
309  recipe = (cpl_recipe *)aPlugin;
310  } else {
311  return -1;
312  }
313 
314  /* register the extended processing information (new FITS header creation, *
315  * getting of the frame level for a certain tag) */
317  muse_flat_new_recipeconfig(),
318  muse_flat_prepare_header,
319  muse_flat_get_frame_level,
320  muse_flat_get_frame_mode);
321 
322  /* XXX initialize timing in messages *
323  * since at least esorex is too stupid to turn it on, we have to do it */
325  cpl_msg_set_time_on();
326  }
327 
328  /* Create the parameter list in the cpl_recipe object */
329  recipe->parameters = cpl_parameterlist_new();
330  /* Fill the parameters list */
331  cpl_parameter *p;
332 
333  /* --nifu: IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel. */
334  p = cpl_parameter_new_range("muse.muse_flat.nifu",
335  CPL_TYPE_INT,
336  "IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel.",
337  "muse.muse_flat",
338  (int)0,
339  (int)-1,
340  (int)24);
341  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nifu");
342  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nifu");
343 
344  cpl_parameterlist_append(recipe->parameters, p);
345 
346  /* --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. */
347  p = cpl_parameter_new_value("muse.muse_flat.overscan",
348  CPL_TYPE_STRING,
349  "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.",
350  "muse.muse_flat",
351  (const char *)"vpoly");
352  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "overscan");
353  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "overscan");
354 
355  cpl_parameterlist_append(recipe->parameters, p);
356 
357  /* --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"). */
358  p = cpl_parameter_new_value("muse.muse_flat.ovscreject",
359  CPL_TYPE_STRING,
360  "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\").",
361  "muse.muse_flat",
362  (const char *)"dcr");
363  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscreject");
364  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscreject");
365 
366  cpl_parameterlist_append(recipe->parameters, p);
367 
368  /* --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. Has no effect for overscan="offset". */
369  p = cpl_parameter_new_value("muse.muse_flat.ovscsigma",
370  CPL_TYPE_DOUBLE,
371  "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. Has no effect for overscan=\"offset\".",
372  "muse.muse_flat",
373  (double)3.);
374  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscsigma");
375  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscsigma");
376 
377  cpl_parameterlist_append(recipe->parameters, p);
378 
379  /* --ovscignore: The number of pixels of the overscan adjacent to the data region of the CCD that are ignored when computing statistics or fits. */
380  p = cpl_parameter_new_value("muse.muse_flat.ovscignore",
381  CPL_TYPE_INT,
382  "The number of pixels of the overscan adjacent to the data region of the CCD that are ignored when computing statistics or fits.",
383  "muse.muse_flat",
384  (int)3);
385  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscignore");
386  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscignore");
387 
388  cpl_parameterlist_append(recipe->parameters, p);
389 
390  /* --combine: Type of combination to use */
391  p = cpl_parameter_new_enum("muse.muse_flat.combine",
392  CPL_TYPE_STRING,
393  "Type of combination to use",
394  "muse.muse_flat",
395  (const char *)"sigclip",
396  4,
397  (const char *)"average",
398  (const char *)"median",
399  (const char *)"minmax",
400  (const char *)"sigclip");
401  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "combine");
402  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "combine");
403 
404  cpl_parameterlist_append(recipe->parameters, p);
405 
406  /* --nlow: Number of minimum pixels to reject with minmax */
407  p = cpl_parameter_new_value("muse.muse_flat.nlow",
408  CPL_TYPE_INT,
409  "Number of minimum pixels to reject with minmax",
410  "muse.muse_flat",
411  (int)1);
412  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nlow");
413  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nlow");
414 
415  cpl_parameterlist_append(recipe->parameters, p);
416 
417  /* --nhigh: Number of maximum pixels to reject with minmax */
418  p = cpl_parameter_new_value("muse.muse_flat.nhigh",
419  CPL_TYPE_INT,
420  "Number of maximum pixels to reject with minmax",
421  "muse.muse_flat",
422  (int)1);
423  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nhigh");
424  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nhigh");
425 
426  cpl_parameterlist_append(recipe->parameters, p);
427 
428  /* --nkeep: Number of pixels to keep with minmax */
429  p = cpl_parameter_new_value("muse.muse_flat.nkeep",
430  CPL_TYPE_INT,
431  "Number of pixels to keep with minmax",
432  "muse.muse_flat",
433  (int)1);
434  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nkeep");
435  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nkeep");
436 
437  cpl_parameterlist_append(recipe->parameters, p);
438 
439  /* --lsigma: Low sigma for pixel rejection with sigclip */
440  p = cpl_parameter_new_value("muse.muse_flat.lsigma",
441  CPL_TYPE_DOUBLE,
442  "Low sigma for pixel rejection with sigclip",
443  "muse.muse_flat",
444  (double)3);
445  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lsigma");
446  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lsigma");
447 
448  cpl_parameterlist_append(recipe->parameters, p);
449 
450  /* --hsigma: High sigma for pixel rejection with sigclip */
451  p = cpl_parameter_new_value("muse.muse_flat.hsigma",
452  CPL_TYPE_DOUBLE,
453  "High sigma for pixel rejection with sigclip",
454  "muse.muse_flat",
455  (double)3);
456  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "hsigma");
457  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "hsigma");
458 
459  cpl_parameterlist_append(recipe->parameters, p);
460 
461  /* --scale: Scale the individual images to a common exposure time before combining them. */
462  p = cpl_parameter_new_value("muse.muse_flat.scale",
463  CPL_TYPE_BOOL,
464  "Scale the individual images to a common exposure time before combining them.",
465  "muse.muse_flat",
466  (int)TRUE);
467  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "scale");
468  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scale");
469 
470  cpl_parameterlist_append(recipe->parameters, p);
471 
472  /* --normalize: Normalize the master flat to the average flux */
473  p = cpl_parameter_new_value("muse.muse_flat.normalize",
474  CPL_TYPE_BOOL,
475  "Normalize the master flat to the average flux",
476  "muse.muse_flat",
477  (int)TRUE);
478  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "normalize");
479  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "normalize");
480 
481  cpl_parameterlist_append(recipe->parameters, p);
482 
483  /* --trace: Trace the position of the slices on the master flat */
484  p = cpl_parameter_new_value("muse.muse_flat.trace",
485  CPL_TYPE_BOOL,
486  "Trace the position of the slices on the master flat",
487  "muse.muse_flat",
488  (int)TRUE);
489  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "trace");
490  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "trace");
491 
492  cpl_parameterlist_append(recipe->parameters, p);
493 
494  /* --nsum: Number of lines over which to average when tracing */
495  p = cpl_parameter_new_value("muse.muse_flat.nsum",
496  CPL_TYPE_INT,
497  "Number of lines over which to average when tracing",
498  "muse.muse_flat",
499  (int)32);
500  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nsum");
501  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nsum");
502 
503  cpl_parameterlist_append(recipe->parameters, p);
504 
505  /* --order: Order of polynomial fit to the trace */
506  p = cpl_parameter_new_value("muse.muse_flat.order",
507  CPL_TYPE_INT,
508  "Order of polynomial fit to the trace",
509  "muse.muse_flat",
510  (int)5);
511  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "order");
512  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "order");
513 
514  cpl_parameterlist_append(recipe->parameters, p);
515 
516  /* --edgefrac: Fractional change required to identify edge when tracing */
517  p = cpl_parameter_new_value("muse.muse_flat.edgefrac",
518  CPL_TYPE_DOUBLE,
519  "Fractional change required to identify edge when tracing",
520  "muse.muse_flat",
521  (double)0.5);
522  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "edgefrac");
523  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "edgefrac");
524 
525  cpl_parameterlist_append(recipe->parameters, p);
526 
527  /* --losigmabadpix: Low sigma to find dark pixels in the master flat */
528  p = cpl_parameter_new_value("muse.muse_flat.losigmabadpix",
529  CPL_TYPE_DOUBLE,
530  "Low sigma to find dark pixels in the master flat",
531  "muse.muse_flat",
532  (double)5.);
533  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "losigmabadpix");
534  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "losigmabadpix");
535 
536  cpl_parameterlist_append(recipe->parameters, p);
537 
538  /* --hisigmabadpix: High sigma to find bright pixels in the master flat */
539  p = cpl_parameter_new_value("muse.muse_flat.hisigmabadpix",
540  CPL_TYPE_DOUBLE,
541  "High sigma to find bright pixels in the master flat",
542  "muse.muse_flat",
543  (double)5.);
544  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "hisigmabadpix");
545  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "hisigmabadpix");
546 
547  cpl_parameterlist_append(recipe->parameters, p);
548 
549  /* --samples: Create a table containing all tracing sample points. */
550  p = cpl_parameter_new_value("muse.muse_flat.samples",
551  CPL_TYPE_BOOL,
552  "Create a table containing all tracing sample points.",
553  "muse.muse_flat",
554  (int)FALSE);
555  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "samples");
556  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "samples");
557 
558  cpl_parameterlist_append(recipe->parameters, p);
559 
560  return 0;
561 } /* muse_flat_create() */
562 
563 /*----------------------------------------------------------------------------*/
574 /*----------------------------------------------------------------------------*/
575 static int
576 muse_flat_params_fill(muse_flat_params_t *aParams, cpl_parameterlist *aParameters)
577 {
578  cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
579  cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
580  cpl_parameter *p;
581 
582  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.nifu");
583  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
584  aParams->nifu = cpl_parameter_get_int(p);
585 
586  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.overscan");
587  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
588  aParams->overscan = cpl_parameter_get_string(p);
589 
590  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.ovscreject");
591  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
592  aParams->ovscreject = cpl_parameter_get_string(p);
593 
594  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.ovscsigma");
595  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
596  aParams->ovscsigma = cpl_parameter_get_double(p);
597 
598  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.ovscignore");
599  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
600  aParams->ovscignore = cpl_parameter_get_int(p);
601 
602  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.combine");
603  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
604  aParams->combine_s = cpl_parameter_get_string(p);
605  aParams->combine =
606  (!strcasecmp(aParams->combine_s, "average")) ? MUSE_FLAT_PARAM_COMBINE_AVERAGE :
607  (!strcasecmp(aParams->combine_s, "median")) ? MUSE_FLAT_PARAM_COMBINE_MEDIAN :
608  (!strcasecmp(aParams->combine_s, "minmax")) ? MUSE_FLAT_PARAM_COMBINE_MINMAX :
609  (!strcasecmp(aParams->combine_s, "sigclip")) ? MUSE_FLAT_PARAM_COMBINE_SIGCLIP :
610  MUSE_FLAT_PARAM_COMBINE_INVALID_VALUE;
611  cpl_ensure_code(aParams->combine != MUSE_FLAT_PARAM_COMBINE_INVALID_VALUE,
612  CPL_ERROR_ILLEGAL_INPUT);
613 
614  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.nlow");
615  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
616  aParams->nlow = cpl_parameter_get_int(p);
617 
618  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.nhigh");
619  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
620  aParams->nhigh = cpl_parameter_get_int(p);
621 
622  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.nkeep");
623  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
624  aParams->nkeep = cpl_parameter_get_int(p);
625 
626  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.lsigma");
627  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
628  aParams->lsigma = cpl_parameter_get_double(p);
629 
630  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.hsigma");
631  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
632  aParams->hsigma = cpl_parameter_get_double(p);
633 
634  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.scale");
635  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
636  aParams->scale = cpl_parameter_get_bool(p);
637 
638  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.normalize");
639  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
640  aParams->normalize = cpl_parameter_get_bool(p);
641 
642  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.trace");
643  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
644  aParams->trace = cpl_parameter_get_bool(p);
645 
646  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.nsum");
647  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
648  aParams->nsum = cpl_parameter_get_int(p);
649 
650  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.order");
651  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
652  aParams->order = cpl_parameter_get_int(p);
653 
654  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.edgefrac");
655  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
656  aParams->edgefrac = cpl_parameter_get_double(p);
657 
658  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.losigmabadpix");
659  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
660  aParams->losigmabadpix = cpl_parameter_get_double(p);
661 
662  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.hisigmabadpix");
663  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
664  aParams->hisigmabadpix = cpl_parameter_get_double(p);
665 
666  p = cpl_parameterlist_find(aParameters, "muse.muse_flat.samples");
667  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
668  aParams->samples = cpl_parameter_get_bool(p);
669 
670  return 0;
671 } /* muse_flat_params_fill() */
672 
673 /*----------------------------------------------------------------------------*/
680 /*----------------------------------------------------------------------------*/
681 static int
682 muse_flat_exec(cpl_plugin *aPlugin)
683 {
684  if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
685  return -1;
686  }
687  cpl_recipe *recipe = (cpl_recipe *)aPlugin;
688  cpl_msg_set_threadid_on();
689 
690  cpl_frameset *usedframes = cpl_frameset_new(),
691  *outframes = cpl_frameset_new();
692  muse_flat_params_t params;
693  muse_flat_params_fill(&params, recipe->parameters);
694 
695  cpl_errorstate prestate = cpl_errorstate_get();
696 
697  if (params.nifu < -1 || params.nifu > kMuseNumIFUs) {
698  cpl_msg_error(__func__, "Please specify a valid IFU number (between 1 and "
699  "%d), 0 (to process all IFUs consecutively), or -1 (to "
700  "process all IFUs in parallel) using --nifu.", kMuseNumIFUs);
701  return -1;
702  } /* if invalid params.nifu */
703 
704  int rc = 0;
705  if (params.nifu > 0) {
706  muse_processing *proc = muse_processing_new("muse_flat",
707  recipe);
708  rc = muse_flat_compute(proc, &params);
709  cpl_frameset_join(usedframes, proc->usedFrames);
710  cpl_frameset_join(outframes, proc->outputFrames);
712  } else if (params.nifu < 0) { /* parallel processing */
713  int *rcs = cpl_calloc(kMuseNumIFUs, sizeof(int));
714  int nifu;
715  #pragma omp parallel for default(none) \
716  shared(outframes, params, rcs, recipe, usedframes)
717  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
718  muse_processing *proc = muse_processing_new("muse_flat",
719  recipe);
720  muse_flat_params_t *pars = cpl_malloc(sizeof(muse_flat_params_t));
721  memcpy(pars, &params, sizeof(muse_flat_params_t));
722  pars->nifu = nifu;
723  int *rci = rcs + (nifu - 1);
724  *rci = muse_flat_compute(proc, pars);
725  if (rci && cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
726  *rci = 0;
727  }
728  cpl_free(pars);
729  #pragma omp critical(muse_processing_used_frames)
730  cpl_frameset_join(usedframes, proc->usedFrames);
731  #pragma omp critical(muse_processing_output_frames)
732  cpl_frameset_join(outframes, proc->outputFrames);
734  } /* for nifu */
735  /* non-parallel loop to propagate the "worst" return code; *
736  * since we only ever return -1, any non-zero code is propagated */
737  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
738  if (rcs[nifu-1] != 0) {
739  rc = rcs[nifu-1];
740  } /* if */
741  } /* for nifu */
742  cpl_free(rcs);
743  } else { /* serial processing */
744  for (params.nifu = 1; params.nifu <= kMuseNumIFUs && !rc; params.nifu++) {
745  muse_processing *proc = muse_processing_new("muse_flat",
746  recipe);
747  rc = muse_flat_compute(proc, &params);
748  if (rc && cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
749  rc = 0;
750  }
751  cpl_frameset_join(usedframes, proc->usedFrames);
752  cpl_frameset_join(outframes, proc->outputFrames);
754  } /* for nifu */
755  } /* else */
756 
757  if (!cpl_errorstate_is_equal(prestate)) {
758  /* dump all errors from this recipe in chronological order */
759  cpl_errorstate_dump(prestate, CPL_FALSE, muse_cplerrorstate_dump_some);
760  /* reset message level to not get the same errors displayed again by esorex */
761  cpl_msg_set_level(CPL_MSG_INFO);
762  }
763  /* clean up duplicates in framesets of used and output frames */
766  /* to get esorex to see our classification (frame groups etc.), *
767  * replace the original frameset with the list of used frames *
768  * before appending product output frames */
769  /* keep the same pointer, so just erase all frames, not delete the frameset */
770  muse_cplframeset_erase_all(recipe->frames);
771  cpl_frameset_join(recipe->frames, usedframes);
772  cpl_frameset_join(recipe->frames, outframes);
773  cpl_frameset_delete(usedframes);
774  cpl_frameset_delete(outframes);
775  return rc;
776 } /* muse_flat_exec() */
777 
778 /*----------------------------------------------------------------------------*/
785 /*----------------------------------------------------------------------------*/
786 static int
787 muse_flat_destroy(cpl_plugin *aPlugin)
788 {
789  /* Get the recipe from the plugin */
790  cpl_recipe *recipe;
791  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
792  recipe = (cpl_recipe *)aPlugin;
793  } else {
794  return -1;
795  }
796 
797  /* Clean up */
798  cpl_parameterlist_delete(recipe->parameters);
800  return 0;
801 } /* muse_flat_destroy() */
802 
803 /*----------------------------------------------------------------------------*/
813 /*----------------------------------------------------------------------------*/
814 int
815 cpl_plugin_get_info(cpl_pluginlist *aList)
816 {
817  cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
818  cpl_plugin *plugin = &recipe->interface;
819 
820  char *helptext;
822  helptext = cpl_sprintf("%s%s", muse_flat_help,
823  muse_flat_help_esorex);
824  } else {
825  helptext = cpl_sprintf("%s", muse_flat_help);
826  }
827 
828  /* Initialize the CPL plugin stuff for this module */
829  cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
830  CPL_PLUGIN_TYPE_RECIPE,
831  "muse_flat",
832  "Combine several separate flat images into one master flat file, trace slice locations, and locate dark pixels.",
833  helptext,
834  "Peter Weilbacher (based on Joris Gerssen's draft)",
835  "usd-help@eso.org",
837  muse_flat_create,
838  muse_flat_exec,
839  muse_flat_destroy);
840  cpl_pluginlist_append(aList, plugin);
841  cpl_free(helptext);
842 
843  return 0;
844 } /* cpl_plugin_get_info() */
845 
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
const char * muse_get_license(void)
Get the pipeline copyright and license.
Definition: muse_utils.c:80
muse_processing * muse_processing_new(const char *aRecipeName, cpl_recipe *aRecipe)
Create a new processing structure.
muse_frame_mode
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
cpl_frameset * outputFrames
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
cpl_frameset * usedFrames
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.