MUSE Pipeline Reference Manual  0.18.5
muse_skyflat_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_skyflat_z.h" /* in turn includes muse.h */
36 
37 /*----------------------------------------------------------------------------*/
63 /*----------------------------------------------------------------------------*/
66 /*----------------------------------------------------------------------------*
67  * Static variables *
68  *----------------------------------------------------------------------------*/
69 static const char *muse_skyflat_help =
70  "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, and combines the exposures using input parameters. Bad pixels are then interpolated from surrounding good ones before computing the integrated flux in all slices by summing the pixel values of all within the boundaries given by the trace table and the --lambdamin and --lambdamax parameters. The integrated flux value is then later used as estimate for the relative throughput of each IFU, to scale values to a common flux level. Since twilight sky flat-fields will have an illumination similar to that of science exposures, they should preferably be used as input to this recipe. Normal lamp flat-fields can be used, if twilight sky flats are not available. The output image is not further used by the pipeline, only the FITS header with the integrated flux is propagated to the science data.";
71 
72 static const char *muse_skyflat_help_esorex =
73  "\n\nInput frames for raw frame tag \"SKYFLAT\":\n"
74  "\n Frame tag Type Req #Fr Description"
75  "\n -------------------- ---- --- --- ------------"
76  "\n SKYFLAT raw Y >=3 Master twilight skyflat"
77  "\n MASTER_BIAS calib Y 1 Master bias"
78  "\n MASTER_DARK calib . 1 Master dark"
79  "\n BADPIX_TABLE calib . 1 Known bad pixels"
80  "\n TRACE_TABLE calib Y 1 Tracing table for all slices"
81  "\n WAVECAL_TABLE calib Y 1 Wavelength calibration table"
82  "\n\nProduct frames for raw frame tag \"SKYFLAT\":\n"
83  "\n Frame tag Level Description"
84  "\n -------------------- -------- ------------"
85  "\n MASTER_SKYFLAT final Master twilight skyflat";
86 
87 /*----------------------------------------------------------------------------*/
95 /*----------------------------------------------------------------------------*/
96 static cpl_recipeconfig *
97 muse_skyflat_new_recipeconfig(void)
98 {
99  cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
100  const char *tag;
101 
102  tag = "SKYFLAT";
103  cpl_recipeconfig_set_tag(recipeconfig, tag, 3, -1);
104  cpl_recipeconfig_set_input(recipeconfig, tag, "MASTER_BIAS", 1, 1);
105  cpl_recipeconfig_set_input(recipeconfig, tag, "MASTER_DARK", -1, 1);
106  cpl_recipeconfig_set_input(recipeconfig, tag, "BADPIX_TABLE", -1, 1);
107  cpl_recipeconfig_set_input(recipeconfig, tag, "TRACE_TABLE", 1, 1);
108  cpl_recipeconfig_set_input(recipeconfig, tag, "WAVECAL_TABLE", 1, 1);
109  cpl_recipeconfig_set_output(recipeconfig, tag, "MASTER_SKYFLAT");
110 
111  return recipeconfig;
112 } /* muse_skyflat_new_recipeconfig() */
113 
114 /*----------------------------------------------------------------------------*/
124 /*----------------------------------------------------------------------------*/
125 static cpl_error_code
126 muse_skyflat_prepare_header(const char *aFrametag, cpl_propertylist *aHeader)
127 {
128  cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
129  cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
130  if (!strcmp(aFrametag, "MASTER_SKYFLAT")) {
131  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT INPUT[0-9]+ MEDIAN",
132  CPL_TYPE_FLOAT,
133  "Median value of raw flat i in input list");
134  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT INPUT[0-9]+ MEAN",
135  CPL_TYPE_FLOAT,
136  "Mean value of raw flat i in input list");
137  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT INPUT[0-9]+ STDEV",
138  CPL_TYPE_FLOAT,
139  "Standard deviation of raw flat i in input list");
140  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT INPUT[0-9]+ MIN",
141  CPL_TYPE_FLOAT,
142  "Minimum value of raw flat i in input list");
143  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT INPUT[0-9]+ MAX",
144  CPL_TYPE_FLOAT,
145  "Maximum value of raw flat i in input list");
146  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT INPUT[0-9]+ NSATURATED",
147  CPL_TYPE_INT,
148  "Number of saturated pixels in raw flat i in input list");
149  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT MASTER MEDIAN",
150  CPL_TYPE_FLOAT,
151  "Median value of the master flat");
152  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT MASTER MEAN",
153  CPL_TYPE_FLOAT,
154  "Mean value of the master flat");
155  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT MASTER STDEV",
156  CPL_TYPE_FLOAT,
157  "Standard deviation of the master flat");
158  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT MASTER MIN",
159  CPL_TYPE_FLOAT,
160  "Minimum value of the master flat");
161  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT MASTER MAX",
162  CPL_TYPE_FLOAT,
163  "Maximum value of the master flat");
164  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT MASTER NSATURATED",
165  CPL_TYPE_INT,
166  "Number of saturated pixels in output data");
167  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT MASTER INTFLUX",
168  CPL_TYPE_FLOAT,
169  "Flux integrated over all slices");
170  muse_processing_prepare_property(aHeader, "ESO QC SKYFLAT MASTER SLICE[0-9]+ INTFLUX",
171  CPL_TYPE_FLOAT,
172  "Flux integrated over slice j");
173  } else {
174  cpl_msg_warning(__func__, "Frame tag %s is not defined", aFrametag);
175  return CPL_ERROR_ILLEGAL_INPUT;
176  }
177  return CPL_ERROR_NONE;
178 } /* muse_skyflat_prepare_header() */
179 
180 /*----------------------------------------------------------------------------*/
189 /*----------------------------------------------------------------------------*/
190 static cpl_frame_level
191 muse_skyflat_get_frame_level(const char *aFrametag)
192 {
193  if (!aFrametag) {
194  return CPL_FRAME_LEVEL_NONE;
195  }
196  if (!strcmp(aFrametag, "MASTER_SKYFLAT")) {
197  return CPL_FRAME_LEVEL_FINAL;
198  }
199  return CPL_FRAME_LEVEL_NONE;
200 } /* muse_skyflat_get_frame_level() */
201 
202 /*----------------------------------------------------------------------------*/
211 /*----------------------------------------------------------------------------*/
212 static muse_frame_mode
213 muse_skyflat_get_frame_mode(const char *aFrametag)
214 {
215  if (!aFrametag) {
216  return MUSE_FRAME_MODE_ALL;
217  }
218  if (!strcmp(aFrametag, "MASTER_SKYFLAT")) {
219  return MUSE_FRAME_MODE_MASTER;
220  }
221  return MUSE_FRAME_MODE_ALL;
222 } /* muse_skyflat_get_frame_mode() */
223 
224 /*----------------------------------------------------------------------------*/
234 /*----------------------------------------------------------------------------*/
235 static int
236 muse_skyflat_create(cpl_plugin *aPlugin)
237 {
238  /* Check that the plugin is part of a valid recipe */
239  cpl_recipe *recipe;
240  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
241  recipe = (cpl_recipe *)aPlugin;
242  } else {
243  return -1;
244  }
245 
246  /* register the extended processing information (new FITS header creation, *
247  * getting of the frame level for a certain tag) */
249  muse_skyflat_new_recipeconfig(),
250  muse_skyflat_prepare_header,
251  muse_skyflat_get_frame_level,
252  muse_skyflat_get_frame_mode);
253 
254  /* XXX initialize timing in messages *
255  * since at least esorex is too stupid to turn it on, we have to do it */
257  cpl_msg_set_time_on();
258  }
259 
260  /* Create the parameter list in the cpl_recipe object */
261  recipe->parameters = cpl_parameterlist_new();
262  /* Fill the parameters list */
263  cpl_parameter *p;
264 
265  /* --nifu: IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel. */
266  p = cpl_parameter_new_range("muse.muse_skyflat.nifu",
267  CPL_TYPE_INT,
268  "IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel.",
269  "muse.muse_skyflat",
270  (int)0,
271  (int)-1,
272  (int)24);
273  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nifu");
274  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nifu");
275 
276  cpl_parameterlist_append(recipe->parameters, p);
277 
278  /* --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. */
279  p = cpl_parameter_new_value("muse.muse_skyflat.overscan",
280  CPL_TYPE_STRING,
281  "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.",
282  "muse.muse_skyflat",
283  (const char *)"vpoly");
284  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "overscan");
285  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "overscan");
286 
287  cpl_parameterlist_append(recipe->parameters, p);
288 
289  /* --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"). */
290  p = cpl_parameter_new_value("muse.muse_skyflat.ovscreject",
291  CPL_TYPE_STRING,
292  "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\").",
293  "muse.muse_skyflat",
294  (const char *)"dcr");
295  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscreject");
296  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscreject");
297 
298  cpl_parameterlist_append(recipe->parameters, p);
299 
300  /* --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". */
301  p = cpl_parameter_new_value("muse.muse_skyflat.ovscsigma",
302  CPL_TYPE_DOUBLE,
303  "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\".",
304  "muse.muse_skyflat",
305  (double)3.);
306  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscsigma");
307  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscsigma");
308 
309  cpl_parameterlist_append(recipe->parameters, p);
310 
311  /* --ovscignore: The number of pixels of the overscan adjacent to the data region of the CCD that are ignored when computing statistics or fits. */
312  p = cpl_parameter_new_value("muse.muse_skyflat.ovscignore",
313  CPL_TYPE_INT,
314  "The number of pixels of the overscan adjacent to the data region of the CCD that are ignored when computing statistics or fits.",
315  "muse.muse_skyflat",
316  (int)3);
317  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscignore");
318  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscignore");
319 
320  cpl_parameterlist_append(recipe->parameters, p);
321 
322  /* --combine: Type of combination to use */
323  p = cpl_parameter_new_enum("muse.muse_skyflat.combine",
324  CPL_TYPE_STRING,
325  "Type of combination to use",
326  "muse.muse_skyflat",
327  (const char *)"sigclip",
328  4,
329  (const char *)"average",
330  (const char *)"median",
331  (const char *)"minmax",
332  (const char *)"sigclip");
333  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "combine");
334  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "combine");
335 
336  cpl_parameterlist_append(recipe->parameters, p);
337 
338  /* --nlow: Number of minimum pixels to reject with minmax */
339  p = cpl_parameter_new_value("muse.muse_skyflat.nlow",
340  CPL_TYPE_INT,
341  "Number of minimum pixels to reject with minmax",
342  "muse.muse_skyflat",
343  (int)1);
344  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nlow");
345  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nlow");
346 
347  cpl_parameterlist_append(recipe->parameters, p);
348 
349  /* --nhigh: Number of maximum pixels to reject with minmax */
350  p = cpl_parameter_new_value("muse.muse_skyflat.nhigh",
351  CPL_TYPE_INT,
352  "Number of maximum pixels to reject with minmax",
353  "muse.muse_skyflat",
354  (int)1);
355  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nhigh");
356  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nhigh");
357 
358  cpl_parameterlist_append(recipe->parameters, p);
359 
360  /* --nkeep: Number of pixels to keep with minmax */
361  p = cpl_parameter_new_value("muse.muse_skyflat.nkeep",
362  CPL_TYPE_INT,
363  "Number of pixels to keep with minmax",
364  "muse.muse_skyflat",
365  (int)1);
366  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nkeep");
367  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nkeep");
368 
369  cpl_parameterlist_append(recipe->parameters, p);
370 
371  /* --lsigma: Low sigma for pixel rejection with sigclip */
372  p = cpl_parameter_new_value("muse.muse_skyflat.lsigma",
373  CPL_TYPE_DOUBLE,
374  "Low sigma for pixel rejection with sigclip",
375  "muse.muse_skyflat",
376  (double)3);
377  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lsigma");
378  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lsigma");
379 
380  cpl_parameterlist_append(recipe->parameters, p);
381 
382  /* --hsigma: High sigma for pixel rejection with sigclip */
383  p = cpl_parameter_new_value("muse.muse_skyflat.hsigma",
384  CPL_TYPE_DOUBLE,
385  "High sigma for pixel rejection with sigclip",
386  "muse.muse_skyflat",
387  (double)3);
388  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "hsigma");
389  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "hsigma");
390 
391  cpl_parameterlist_append(recipe->parameters, p);
392 
393  /* --scale: Scale the individual images to a common exposure time before combining them. */
394  p = cpl_parameter_new_value("muse.muse_skyflat.scale",
395  CPL_TYPE_BOOL,
396  "Scale the individual images to a common exposure time before combining them.",
397  "muse.muse_skyflat",
398  (int)FALSE);
399  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "scale");
400  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scale");
401 
402  cpl_parameterlist_append(recipe->parameters, p);
403 
404  /* --lambdamin: Minimum wavelength to use for flux integration. */
405  p = cpl_parameter_new_value("muse.muse_skyflat.lambdamin",
406  CPL_TYPE_DOUBLE,
407  "Minimum wavelength to use for flux integration.",
408  "muse.muse_skyflat",
409  (double)4800.);
410  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lambdamin");
411  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lambdamin");
412 
413  cpl_parameterlist_append(recipe->parameters, p);
414 
415  /* --lambdamax: Maximum wavelength to use for flux integration. */
416  p = cpl_parameter_new_value("muse.muse_skyflat.lambdamax",
417  CPL_TYPE_DOUBLE,
418  "Maximum wavelength to use for flux integration.",
419  "muse.muse_skyflat",
420  (double)9300.);
421  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lambdamax");
422  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lambdamax");
423 
424  cpl_parameterlist_append(recipe->parameters, p);
425 
426  /* --normalize: Normalize the master skyflat to the flux integrated over the given wavelength range. */
427  p = cpl_parameter_new_value("muse.muse_skyflat.normalize",
428  CPL_TYPE_BOOL,
429  "Normalize the master skyflat to the flux integrated over the given wavelength range.",
430  "muse.muse_skyflat",
431  (int)TRUE);
432  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "normalize");
433  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "normalize");
434 
435  cpl_parameterlist_append(recipe->parameters, p);
436 
437  return 0;
438 } /* muse_skyflat_create() */
439 
440 /*----------------------------------------------------------------------------*/
451 /*----------------------------------------------------------------------------*/
452 static int
453 muse_skyflat_params_fill(muse_skyflat_params_t *aParams, cpl_parameterlist *aParameters)
454 {
455  cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
456  cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
457  cpl_parameter *p;
458 
459  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.nifu");
460  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
461  aParams->nifu = cpl_parameter_get_int(p);
462 
463  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.overscan");
464  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
465  aParams->overscan = cpl_parameter_get_string(p);
466 
467  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.ovscreject");
468  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
469  aParams->ovscreject = cpl_parameter_get_string(p);
470 
471  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.ovscsigma");
472  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
473  aParams->ovscsigma = cpl_parameter_get_double(p);
474 
475  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.ovscignore");
476  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
477  aParams->ovscignore = cpl_parameter_get_int(p);
478 
479  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.combine");
480  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
481  aParams->combine_s = cpl_parameter_get_string(p);
482  aParams->combine =
483  (!strcasecmp(aParams->combine_s, "average")) ? MUSE_SKYFLAT_PARAM_COMBINE_AVERAGE :
484  (!strcasecmp(aParams->combine_s, "median")) ? MUSE_SKYFLAT_PARAM_COMBINE_MEDIAN :
485  (!strcasecmp(aParams->combine_s, "minmax")) ? MUSE_SKYFLAT_PARAM_COMBINE_MINMAX :
486  (!strcasecmp(aParams->combine_s, "sigclip")) ? MUSE_SKYFLAT_PARAM_COMBINE_SIGCLIP :
487  MUSE_SKYFLAT_PARAM_COMBINE_INVALID_VALUE;
488  cpl_ensure_code(aParams->combine != MUSE_SKYFLAT_PARAM_COMBINE_INVALID_VALUE,
489  CPL_ERROR_ILLEGAL_INPUT);
490 
491  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.nlow");
492  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
493  aParams->nlow = cpl_parameter_get_int(p);
494 
495  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.nhigh");
496  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
497  aParams->nhigh = cpl_parameter_get_int(p);
498 
499  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.nkeep");
500  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
501  aParams->nkeep = cpl_parameter_get_int(p);
502 
503  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.lsigma");
504  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
505  aParams->lsigma = cpl_parameter_get_double(p);
506 
507  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.hsigma");
508  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
509  aParams->hsigma = cpl_parameter_get_double(p);
510 
511  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.scale");
512  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
513  aParams->scale = cpl_parameter_get_bool(p);
514 
515  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.lambdamin");
516  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
517  aParams->lambdamin = cpl_parameter_get_double(p);
518 
519  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.lambdamax");
520  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
521  aParams->lambdamax = cpl_parameter_get_double(p);
522 
523  p = cpl_parameterlist_find(aParameters, "muse.muse_skyflat.normalize");
524  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
525  aParams->normalize = cpl_parameter_get_bool(p);
526 
527  return 0;
528 } /* muse_skyflat_params_fill() */
529 
530 /*----------------------------------------------------------------------------*/
537 /*----------------------------------------------------------------------------*/
538 static int
539 muse_skyflat_exec(cpl_plugin *aPlugin)
540 {
541  if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
542  return -1;
543  }
544  cpl_recipe *recipe = (cpl_recipe *)aPlugin;
545  cpl_msg_set_threadid_on();
546 
547  cpl_frameset *usedframes = cpl_frameset_new(),
548  *outframes = cpl_frameset_new();
549  muse_skyflat_params_t params;
550  muse_skyflat_params_fill(&params, recipe->parameters);
551 
552  cpl_errorstate prestate = cpl_errorstate_get();
553 
554  if (params.nifu < -1 || params.nifu > kMuseNumIFUs) {
555  cpl_msg_error(__func__, "Please specify a valid IFU number (between 1 and "
556  "%d), 0 (to process all IFUs consecutively), or -1 (to "
557  "process all IFUs in parallel) using --nifu.", kMuseNumIFUs);
558  return -1;
559  } /* if invalid params.nifu */
560 
561  int rc = 0;
562  if (params.nifu > 0) {
563  muse_processing *proc = muse_processing_new("muse_skyflat",
564  recipe);
565  rc = muse_skyflat_compute(proc, &params);
566  cpl_frameset_join(usedframes, proc->usedFrames);
567  cpl_frameset_join(outframes, proc->outputFrames);
569  } else if (params.nifu < 0) { /* parallel processing */
570  int *rcs = cpl_calloc(kMuseNumIFUs, sizeof(int));
571  int nifu;
572  #pragma omp parallel for default(none) \
573  shared(outframes, params, rcs, recipe, usedframes)
574  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
575  muse_processing *proc = muse_processing_new("muse_skyflat",
576  recipe);
577  muse_skyflat_params_t *pars = cpl_malloc(sizeof(muse_skyflat_params_t));
578  memcpy(pars, &params, sizeof(muse_skyflat_params_t));
579  pars->nifu = nifu;
580  int *rci = rcs + (nifu - 1);
581  *rci = muse_skyflat_compute(proc, pars);
582  if (rci && cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
583  *rci = 0;
584  }
585  cpl_free(pars);
586  #pragma omp critical(muse_processing_used_frames)
587  cpl_frameset_join(usedframes, proc->usedFrames);
588  #pragma omp critical(muse_processing_output_frames)
589  cpl_frameset_join(outframes, proc->outputFrames);
591  } /* for nifu */
592  /* non-parallel loop to propagate the "worst" return code; *
593  * since we only ever return -1, any non-zero code is propagated */
594  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
595  if (rcs[nifu-1] != 0) {
596  rc = rcs[nifu-1];
597  } /* if */
598  } /* for nifu */
599  cpl_free(rcs);
600  } else { /* serial processing */
601  for (params.nifu = 1; params.nifu <= kMuseNumIFUs && !rc; params.nifu++) {
602  muse_processing *proc = muse_processing_new("muse_skyflat",
603  recipe);
604  rc = muse_skyflat_compute(proc, &params);
605  if (rc && cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
606  rc = 0;
607  }
608  cpl_frameset_join(usedframes, proc->usedFrames);
609  cpl_frameset_join(outframes, proc->outputFrames);
611  } /* for nifu */
612  } /* else */
613 
614  if (!cpl_errorstate_is_equal(prestate)) {
615  /* dump all errors from this recipe in chronological order */
616  cpl_errorstate_dump(prestate, CPL_FALSE, muse_cplerrorstate_dump_some);
617  /* reset message level to not get the same errors displayed again by esorex */
618  cpl_msg_set_level(CPL_MSG_INFO);
619  }
620  /* clean up duplicates in framesets of used and output frames */
623  /* to get esorex to see our classification (frame groups etc.), *
624  * replace the original frameset with the list of used frames *
625  * before appending product output frames */
626  /* keep the same pointer, so just erase all frames, not delete the frameset */
627  muse_cplframeset_erase_all(recipe->frames);
628  cpl_frameset_join(recipe->frames, usedframes);
629  cpl_frameset_join(recipe->frames, outframes);
630  cpl_frameset_delete(usedframes);
631  cpl_frameset_delete(outframes);
632  return rc;
633 } /* muse_skyflat_exec() */
634 
635 /*----------------------------------------------------------------------------*/
642 /*----------------------------------------------------------------------------*/
643 static int
644 muse_skyflat_destroy(cpl_plugin *aPlugin)
645 {
646  /* Get the recipe from the plugin */
647  cpl_recipe *recipe;
648  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
649  recipe = (cpl_recipe *)aPlugin;
650  } else {
651  return -1;
652  }
653 
654  /* Clean up */
655  cpl_parameterlist_delete(recipe->parameters);
657  return 0;
658 } /* muse_skyflat_destroy() */
659 
660 /*----------------------------------------------------------------------------*/
670 /*----------------------------------------------------------------------------*/
671 int
672 cpl_plugin_get_info(cpl_pluginlist *aList)
673 {
674  cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
675  cpl_plugin *plugin = &recipe->interface;
676 
677  char *helptext;
679  helptext = cpl_sprintf("%s%s", muse_skyflat_help,
680  muse_skyflat_help_esorex);
681  } else {
682  helptext = cpl_sprintf("%s", muse_skyflat_help);
683  }
684 
685  /* Initialize the CPL plugin stuff for this module */
686  cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
687  CPL_PLUGIN_TYPE_RECIPE,
688  "muse_skyflat",
689  "Combine several separate (twilight) sky flat-fields into one master skyflat, and compute the integrated flux within the given wavelength range of the IFU.",
690  helptext,
691  "Peter Weilbacher",
692  "usd-help@eso.org",
694  muse_skyflat_create,
695  muse_skyflat_exec,
696  muse_skyflat_destroy);
697  cpl_pluginlist_append(aList, plugin);
698  cpl_free(helptext);
699 
700  return 0;
701 } /* cpl_plugin_get_info() */
702 
Structure to hold the parameters of the muse_skyflat recipe.
void muse_processing_delete(muse_processing *aProcessing)
Free the muse_processing structure.
int combine
Type of combination to use.
const char * ovscreject
This influences how values are rejected when computing overscan statistics. Either no rejection at al...
muse_cplframework_type muse_cplframework(void)
Return the CPL framework the recipe is run under.
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.
int nlow
Number of minimum pixels to reject with minmax.
double ovscsigma
If the deviation of mean overscan levels between a raw input image and the reference image is higher ...
double lsigma
Low sigma for pixel rejection with sigclip.
int ovscignore
The number of pixels of the overscan adjacent to the data region of the CCD that are ignored when com...
double hsigma
High sigma for pixel rejection with sigclip.
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
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 nhigh
Number of maximum pixels to reject with minmax.
const char * combine_s
Type of combination to use (as string)
cpl_error_code muse_cplframeset_erase_duplicate(cpl_frameset *aFrames)
Erase all duplicate frames from a frameset.
cpl_error_code muse_cplframeset_erase_all(cpl_frameset *aFrames)
Erase all frames in a frameset.
int nkeep
Number of pixels to keep with minmax.
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 normalize
Normalize the master skyflat to the flux integrated over the given wavelength range.
int scale
Scale the individual images to a common exposure time before combining them.
cpl_frameset * usedFrames
int nifu
IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in ...
double lambdamax
Maximum wavelength to use for flux integration.
double lambdamin
Minimum wavelength to use for flux integration.
cpl_error_code muse_processing_prepare_property(cpl_propertylist *, const char *, cpl_type, const char *)
Prepare and check the specified property.