MUSE Pipeline Reference Manual  2.1.1
muse_dark_z.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set sw=2 sts=2 et cin: */
3 /*
4  * This file is part of the MUSE Instrument Pipeline
5  * Copyright (C) 2005-2015 European Southern Observatory
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 /* This file was automatically generated */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 /*----------------------------------------------------------------------------*
29  * Includes *
30  *----------------------------------------------------------------------------*/
31 #include <string.h> /* strcmp(), strstr() */
32 #include <strings.h> /* strcasecmp() */
33 #include <cpl.h>
34 
35 #include "muse_dark_z.h" /* in turn includes muse.h */
36 
37 /*----------------------------------------------------------------------------*/
58 /*----------------------------------------------------------------------------*/
61 /*----------------------------------------------------------------------------*
62  * Static variables *
63  *----------------------------------------------------------------------------*/
64 static const char *muse_dark_help =
65  "This recipe combines several separate dark images into one master dark file. The master dark contains the combined pixel values of the raw dark exposures, with respect to the image combination method used and normalization time specified. Processing trims the raw data and records the overscan statistics, subtracts the bias (taking account of the overscan, if --overscan is not \"none\") from each raw input image, converts them from adu to count, scales them according to their exposure time, and combines them using input parameters. Hot pixels are then identified using image statistics and marked in the data quality extension. The combined image is normalized to 1 hour exposure time. QC statistics are computed on the output master dark.";
66 
67 static const char *muse_dark_help_esorex =
68  "\n\nInput frames for raw frame tag \"DARK\":\n"
69  "\n Frame tag Type Req #Fr Description"
70  "\n -------------------- ---- --- --- ------------"
71  "\n DARK raw Y >=3 Raw dark"
72  "\n MASTER_BIAS calib Y 1 Master bias"
73  "\n BADPIX_TABLE calib . Known bad pixels"
74  "\n\nProduct frames for raw frame tag \"DARK\":\n"
75  "\n Frame tag Level Description"
76  "\n -------------------- -------- ------------"
77  "\n MASTER_DARK final Master dark";
78 
79 /*----------------------------------------------------------------------------*/
87 /*----------------------------------------------------------------------------*/
88 static cpl_recipeconfig *
89 muse_dark_new_recipeconfig(void)
90 {
91  cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
92 
93  cpl_recipeconfig_set_tag(recipeconfig, "DARK", 3, -1);
94  cpl_recipeconfig_set_input(recipeconfig, "DARK", "MASTER_BIAS", 1, 1);
95  cpl_recipeconfig_set_input(recipeconfig, "DARK", "BADPIX_TABLE", -1, -1);
96  cpl_recipeconfig_set_output(recipeconfig, "DARK", "MASTER_DARK");
97 
98  return recipeconfig;
99 } /* muse_dark_new_recipeconfig() */
100 
101 /*----------------------------------------------------------------------------*/
111 /*----------------------------------------------------------------------------*/
112 static cpl_error_code
113 muse_dark_prepare_header(const char *aFrametag, cpl_propertylist *aHeader)
114 {
115  cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
116  cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
117  if (!strcmp(aFrametag, "MASTER_DARK")) {
118  muse_processing_prepare_property(aHeader, "ESO QC DARK INPUT[0-9]+ NSATURATED",
119  CPL_TYPE_INT,
120  "Number of saturated pixels in raw dark i in input list");
121  muse_processing_prepare_property(aHeader, "ESO QC DARK MASTER NBADPIX",
122  CPL_TYPE_INT,
123  "Number of bad pixels determined from master dark");
124  muse_processing_prepare_property(aHeader, "ESO QC DARK MASTER MEDIAN",
125  CPL_TYPE_FLOAT,
126  "Median value of the master dark");
127  muse_processing_prepare_property(aHeader, "ESO QC DARK MASTER MEAN",
128  CPL_TYPE_FLOAT,
129  "Mean value of the master dark");
130  muse_processing_prepare_property(aHeader, "ESO QC DARK MASTER STDEV",
131  CPL_TYPE_FLOAT,
132  "Standard deviation of the master dark");
133  muse_processing_prepare_property(aHeader, "ESO QC DARK MASTER MIN",
134  CPL_TYPE_FLOAT,
135  "Minimum value of the master dark");
136  muse_processing_prepare_property(aHeader, "ESO QC DARK MASTER MAX",
137  CPL_TYPE_FLOAT,
138  "Maximum value of the master dark");
139  muse_processing_prepare_property(aHeader, "ESO QC DARK MASTER DC",
140  CPL_TYPE_FLOAT,
141  "[count/pix/h] Dark current measured on master dark in randomly placed windows");
142  muse_processing_prepare_property(aHeader, "ESO QC DARK MASTER DCERR",
143  CPL_TYPE_FLOAT,
144  "[count/pix/h] Dark current error measured on master dark in randomly placed windows");
145  muse_processing_prepare_property(aHeader, "ESO QC DARK MASTER NSATURATED",
146  CPL_TYPE_INT,
147  "Number of saturated pixels in output data");
148  } else {
149  cpl_msg_warning(__func__, "Frame tag %s is not defined", aFrametag);
150  return CPL_ERROR_ILLEGAL_INPUT;
151  }
152  return CPL_ERROR_NONE;
153 } /* muse_dark_prepare_header() */
154 
155 /*----------------------------------------------------------------------------*/
164 /*----------------------------------------------------------------------------*/
165 static cpl_frame_level
166 muse_dark_get_frame_level(const char *aFrametag)
167 {
168  if (!aFrametag) {
169  return CPL_FRAME_LEVEL_NONE;
170  }
171  if (!strcmp(aFrametag, "MASTER_DARK")) {
172  return CPL_FRAME_LEVEL_FINAL;
173  }
174  return CPL_FRAME_LEVEL_NONE;
175 } /* muse_dark_get_frame_level() */
176 
177 /*----------------------------------------------------------------------------*/
186 /*----------------------------------------------------------------------------*/
187 static muse_frame_mode
188 muse_dark_get_frame_mode(const char *aFrametag)
189 {
190  if (!aFrametag) {
191  return MUSE_FRAME_MODE_ALL;
192  }
193  if (!strcmp(aFrametag, "MASTER_DARK")) {
194  return MUSE_FRAME_MODE_MASTER;
195  }
196  return MUSE_FRAME_MODE_ALL;
197 } /* muse_dark_get_frame_mode() */
198 
199 /*----------------------------------------------------------------------------*/
209 /*----------------------------------------------------------------------------*/
210 static int
211 muse_dark_create(cpl_plugin *aPlugin)
212 {
213  /* Check that the plugin is part of a valid recipe */
214  cpl_recipe *recipe;
215  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
216  recipe = (cpl_recipe *)aPlugin;
217  } else {
218  return -1;
219  }
220 
221  /* register the extended processing information (new FITS header creation, *
222  * getting of the frame level for a certain tag) */
224  muse_dark_new_recipeconfig(),
225  muse_dark_prepare_header,
226  muse_dark_get_frame_level,
227  muse_dark_get_frame_mode);
228 
229  /* XXX initialize timing in messages *
230  * since at least esorex is too stupid to turn it on, we have to do it */
232  cpl_msg_set_time_on();
233  }
234 
235  /* Create the parameter list in the cpl_recipe object */
236  recipe->parameters = cpl_parameterlist_new();
237  /* Fill the parameters list */
238  cpl_parameter *p;
239 
240  /* --nifu: IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel. */
241  p = cpl_parameter_new_range("muse.muse_dark.nifu",
242  CPL_TYPE_INT,
243  "IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel.",
244  "muse.muse_dark",
245  (int)0,
246  (int)-1,
247  (int)24);
248  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nifu");
249  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nifu");
250 
251  cpl_parameterlist_append(recipe->parameters, p);
252 
253  /* --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. */
254  p = cpl_parameter_new_value("muse.muse_dark.overscan",
255  CPL_TYPE_STRING,
256  "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.",
257  "muse.muse_dark",
258  (const char *)"vpoly");
259  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "overscan");
260  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "overscan");
261 
262  cpl_parameterlist_append(recipe->parameters, p);
263 
264  /* --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"). */
265  p = cpl_parameter_new_value("muse.muse_dark.ovscreject",
266  CPL_TYPE_STRING,
267  "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\").",
268  "muse.muse_dark",
269  (const char *)"dcr");
270  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscreject");
271  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscreject");
272 
273  cpl_parameterlist_append(recipe->parameters, p);
274 
275  /* --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". */
276  p = cpl_parameter_new_value("muse.muse_dark.ovscsigma",
277  CPL_TYPE_DOUBLE,
278  "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\".",
279  "muse.muse_dark",
280  (double)30.);
281  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscsigma");
282  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscsigma");
283 
284  cpl_parameterlist_append(recipe->parameters, p);
285 
286  /* --ovscignore: The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when computing statistics or fits. */
287  p = cpl_parameter_new_value("muse.muse_dark.ovscignore",
288  CPL_TYPE_INT,
289  "The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when computing statistics or fits.",
290  "muse.muse_dark",
291  (int)3);
292  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscignore");
293  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscignore");
294 
295  cpl_parameterlist_append(recipe->parameters, p);
296 
297  /* --combine: Type of image combination to use. */
298  p = cpl_parameter_new_enum("muse.muse_dark.combine",
299  CPL_TYPE_STRING,
300  "Type of image combination to use.",
301  "muse.muse_dark",
302  (const char *)"sigclip",
303  4,
304  (const char *)"average",
305  (const char *)"median",
306  (const char *)"minmax",
307  (const char *)"sigclip");
308  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "combine");
309  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "combine");
310 
311  cpl_parameterlist_append(recipe->parameters, p);
312 
313  /* --nlow: Number of minimum pixels to reject with minmax. */
314  p = cpl_parameter_new_value("muse.muse_dark.nlow",
315  CPL_TYPE_INT,
316  "Number of minimum pixels to reject with minmax.",
317  "muse.muse_dark",
318  (int)1);
319  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nlow");
320  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nlow");
321 
322  cpl_parameterlist_append(recipe->parameters, p);
323 
324  /* --nhigh: Number of maximum pixels to reject with minmax. */
325  p = cpl_parameter_new_value("muse.muse_dark.nhigh",
326  CPL_TYPE_INT,
327  "Number of maximum pixels to reject with minmax.",
328  "muse.muse_dark",
329  (int)1);
330  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nhigh");
331  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nhigh");
332 
333  cpl_parameterlist_append(recipe->parameters, p);
334 
335  /* --nkeep: Number of pixels to keep with minmax. */
336  p = cpl_parameter_new_value("muse.muse_dark.nkeep",
337  CPL_TYPE_INT,
338  "Number of pixels to keep with minmax.",
339  "muse.muse_dark",
340  (int)1);
341  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nkeep");
342  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nkeep");
343 
344  cpl_parameterlist_append(recipe->parameters, p);
345 
346  /* --lsigma: Low sigma for pixel rejection with sigclip. */
347  p = cpl_parameter_new_value("muse.muse_dark.lsigma",
348  CPL_TYPE_DOUBLE,
349  "Low sigma for pixel rejection with sigclip.",
350  "muse.muse_dark",
351  (double)3);
352  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lsigma");
353  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lsigma");
354 
355  cpl_parameterlist_append(recipe->parameters, p);
356 
357  /* --hsigma: High sigma for pixel rejection with sigclip. */
358  p = cpl_parameter_new_value("muse.muse_dark.hsigma",
359  CPL_TYPE_DOUBLE,
360  "High sigma for pixel rejection with sigclip.",
361  "muse.muse_dark",
362  (double)3);
363  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "hsigma");
364  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "hsigma");
365 
366  cpl_parameterlist_append(recipe->parameters, p);
367 
368  /* --scale: Scale the individual images to a common exposure time before combining them. */
369  p = cpl_parameter_new_value("muse.muse_dark.scale",
370  CPL_TYPE_BOOL,
371  "Scale the individual images to a common exposure time before combining them.",
372  "muse.muse_dark",
373  (int)TRUE);
374  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "scale");
375  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scale");
376  if (!getenv("MUSE_EXPERT_USER")) {
377  cpl_parameter_disable(p, CPL_PARAMETER_MODE_CLI);
378  }
379 
380  cpl_parameterlist_append(recipe->parameters, p);
381 
382  /* --normalize: Normalize the master dark to this exposure time (in seconds). To disable normalization, set this to a negative value. */
383  p = cpl_parameter_new_value("muse.muse_dark.normalize",
384  CPL_TYPE_DOUBLE,
385  "Normalize the master dark to this exposure time (in seconds). To disable normalization, set this to a negative value.",
386  "muse.muse_dark",
387  (double)3600.);
388  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "normalize");
389  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "normalize");
390  if (!getenv("MUSE_EXPERT_USER")) {
391  cpl_parameter_disable(p, CPL_PARAMETER_MODE_CLI);
392  }
393 
394  cpl_parameterlist_append(recipe->parameters, p);
395 
396  /* --hotsigma: Sigma level, in terms of median deviation above the median dark level, above which a pixel is detected and marked as 'hot'. */
397  p = cpl_parameter_new_value("muse.muse_dark.hotsigma",
398  CPL_TYPE_DOUBLE,
399  "Sigma level, in terms of median deviation above the median dark level, above which a pixel is detected and marked as 'hot'.",
400  "muse.muse_dark",
401  (double)5);
402  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "hotsigma");
403  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "hotsigma");
404 
405  cpl_parameterlist_append(recipe->parameters, p);
406 
407  /* --merge: Merge output products from different IFUs into a common file. */
408  p = cpl_parameter_new_value("muse.muse_dark.merge",
409  CPL_TYPE_BOOL,
410  "Merge output products from different IFUs into a common file.",
411  "muse.muse_dark",
412  (int)FALSE);
413  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "merge");
414  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "merge");
415 
416  cpl_parameterlist_append(recipe->parameters, p);
417 
418  return 0;
419 } /* muse_dark_create() */
420 
421 /*----------------------------------------------------------------------------*/
432 /*----------------------------------------------------------------------------*/
433 static int
434 muse_dark_params_fill(muse_dark_params_t *aParams, cpl_parameterlist *aParameters)
435 {
436  cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
437  cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
438  cpl_parameter *p;
439 
440  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.nifu");
441  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
442  aParams->nifu = cpl_parameter_get_int(p);
443 
444  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.overscan");
445  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
446  aParams->overscan = cpl_parameter_get_string(p);
447 
448  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.ovscreject");
449  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
450  aParams->ovscreject = cpl_parameter_get_string(p);
451 
452  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.ovscsigma");
453  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
454  aParams->ovscsigma = cpl_parameter_get_double(p);
455 
456  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.ovscignore");
457  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
458  aParams->ovscignore = cpl_parameter_get_int(p);
459 
460  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.combine");
461  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
462  aParams->combine_s = cpl_parameter_get_string(p);
463  aParams->combine =
464  (!strcasecmp(aParams->combine_s, "average")) ? MUSE_DARK_PARAM_COMBINE_AVERAGE :
465  (!strcasecmp(aParams->combine_s, "median")) ? MUSE_DARK_PARAM_COMBINE_MEDIAN :
466  (!strcasecmp(aParams->combine_s, "minmax")) ? MUSE_DARK_PARAM_COMBINE_MINMAX :
467  (!strcasecmp(aParams->combine_s, "sigclip")) ? MUSE_DARK_PARAM_COMBINE_SIGCLIP :
468  MUSE_DARK_PARAM_COMBINE_INVALID_VALUE;
469  cpl_ensure_code(aParams->combine != MUSE_DARK_PARAM_COMBINE_INVALID_VALUE,
470  CPL_ERROR_ILLEGAL_INPUT);
471 
472  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.nlow");
473  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
474  aParams->nlow = cpl_parameter_get_int(p);
475 
476  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.nhigh");
477  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
478  aParams->nhigh = cpl_parameter_get_int(p);
479 
480  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.nkeep");
481  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
482  aParams->nkeep = cpl_parameter_get_int(p);
483 
484  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.lsigma");
485  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
486  aParams->lsigma = cpl_parameter_get_double(p);
487 
488  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.hsigma");
489  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
490  aParams->hsigma = cpl_parameter_get_double(p);
491 
492  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.scale");
493  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
494  aParams->scale = cpl_parameter_get_bool(p);
495 
496  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.normalize");
497  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
498  aParams->normalize = cpl_parameter_get_double(p);
499 
500  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.hotsigma");
501  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
502  aParams->hotsigma = cpl_parameter_get_double(p);
503 
504  p = cpl_parameterlist_find(aParameters, "muse.muse_dark.merge");
505  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
506  aParams->merge = cpl_parameter_get_bool(p);
507 
508  return 0;
509 } /* muse_dark_params_fill() */
510 
511 /*----------------------------------------------------------------------------*/
518 /*----------------------------------------------------------------------------*/
519 static int
520 muse_dark_exec(cpl_plugin *aPlugin)
521 {
522  if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
523  return -1;
524  }
526  cpl_recipe *recipe = (cpl_recipe *)aPlugin;
527  cpl_msg_set_threadid_on();
528 
529  cpl_frameset *usedframes = cpl_frameset_new(),
530  *outframes = cpl_frameset_new();
531  muse_dark_params_t params;
532  muse_dark_params_fill(&params, recipe->parameters);
533 
534  cpl_errorstate prestate = cpl_errorstate_get();
535 
536  if (params.nifu < -1 || params.nifu > kMuseNumIFUs) {
537  cpl_msg_error(__func__, "Please specify a valid IFU number (between 1 and "
538  "%d), 0 (to process all IFUs consecutively), or -1 (to "
539  "process all IFUs in parallel) using --nifu.", kMuseNumIFUs);
540  return -1;
541  } /* if invalid params.nifu */
542 
543  cpl_boolean donotmerge = CPL_FALSE; /* depending on nifu we may not merge */
544  int rc = 0;
545  if (params.nifu > 0) {
546  muse_processing *proc = muse_processing_new("muse_dark",
547  recipe);
548  rc = muse_dark_compute(proc, &params);
549  cpl_frameset_join(usedframes, proc->usedframes);
550  cpl_frameset_join(outframes, proc->outframes);
552  donotmerge = CPL_TRUE; /* after processing one IFU, merging cannot work */
553  } else if (params.nifu < 0) { /* parallel processing */
554  int *rcs = cpl_calloc(kMuseNumIFUs, sizeof(int));
555  int nifu;
556  #pragma omp parallel for default(none) \
557  shared(outframes, params, rcs, recipe, usedframes)
558  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
559  muse_processing *proc = muse_processing_new("muse_dark",
560  recipe);
561  muse_dark_params_t *pars = cpl_malloc(sizeof(muse_dark_params_t));
562  memcpy(pars, &params, sizeof(muse_dark_params_t));
563  pars->nifu = nifu;
564  int *rci = rcs + (nifu - 1);
565  *rci = muse_dark_compute(proc, pars);
566  if (rci && (int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
567  *rci = 0;
568  }
569  cpl_free(pars);
570  #pragma omp critical(muse_processing_used_frames)
571  cpl_frameset_join(usedframes, proc->usedframes);
572  #pragma omp critical(muse_processing_output_frames)
573  cpl_frameset_join(outframes, proc->outframes);
575  } /* for nifu */
576  /* non-parallel loop to propagate the "worst" return code; *
577  * since we only ever return -1, any non-zero code is propagated */
578  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
579  if (rcs[nifu-1] != 0) {
580  rc = rcs[nifu-1];
581  } /* if */
582  } /* for nifu */
583  cpl_free(rcs);
584  } else { /* serial processing */
585  for (params.nifu = 1; params.nifu <= kMuseNumIFUs && !rc; params.nifu++) {
586  muse_processing *proc = muse_processing_new("muse_dark",
587  recipe);
588  rc = muse_dark_compute(proc, &params);
589  if (rc && (int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
590  rc = 0;
591  }
592  cpl_frameset_join(usedframes, proc->usedframes);
593  cpl_frameset_join(outframes, proc->outframes);
595  } /* for nifu */
596  } /* else */
597  UNUSED_ARGUMENT(donotmerge); /* maybe this is not going to be used below */
598 
599  if (!cpl_errorstate_is_equal(prestate)) {
600  /* dump all errors from this recipe in chronological order */
601  cpl_errorstate_dump(prestate, CPL_FALSE, muse_cplerrorstate_dump_some);
602  /* reset message level to not get the same errors displayed again by esorex */
603  cpl_msg_set_level(CPL_MSG_INFO);
604  }
605  /* clean up duplicates in framesets of used and output frames */
608 
609  /* merge output products from the up to 24 IFUs */
610  if (params.merge && !donotmerge) {
611  muse_utils_frameset_merge_frames(outframes, CPL_TRUE);
612  }
613 
614  /* to get esorex to see our classification (frame groups etc.), *
615  * replace the original frameset with the list of used frames *
616  * before appending product output frames */
617  /* keep the same pointer, so just erase all frames, not delete the frameset */
618  muse_cplframeset_erase_all(recipe->frames);
619  cpl_frameset_join(recipe->frames, usedframes);
620  cpl_frameset_join(recipe->frames, outframes);
621  cpl_frameset_delete(usedframes);
622  cpl_frameset_delete(outframes);
623  return rc;
624 } /* muse_dark_exec() */
625 
626 /*----------------------------------------------------------------------------*/
633 /*----------------------------------------------------------------------------*/
634 static int
635 muse_dark_destroy(cpl_plugin *aPlugin)
636 {
637  /* Get the recipe from the plugin */
638  cpl_recipe *recipe;
639  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
640  recipe = (cpl_recipe *)aPlugin;
641  } else {
642  return -1;
643  }
644 
645  /* Clean up */
646  cpl_parameterlist_delete(recipe->parameters);
648  return 0;
649 } /* muse_dark_destroy() */
650 
651 /*----------------------------------------------------------------------------*/
661 /*----------------------------------------------------------------------------*/
662 int
663 cpl_plugin_get_info(cpl_pluginlist *aList)
664 {
665  cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
666  cpl_plugin *plugin = &recipe->interface;
667 
668  char *helptext;
670  helptext = cpl_sprintf("%s%s", muse_dark_help,
671  muse_dark_help_esorex);
672  } else {
673  helptext = cpl_sprintf("%s", muse_dark_help);
674  }
675 
676  /* Initialize the CPL plugin stuff for this module */
677  cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
678  CPL_PLUGIN_TYPE_RECIPE,
679  "muse_dark",
680  "Combine several separate dark images into one master dark file and locate hot pixels.",
681  helptext,
682  "Peter Weilbacher",
683  "usd-help@eso.org",
685  muse_dark_create,
686  muse_dark_exec,
687  muse_dark_destroy);
688  cpl_pluginlist_append(aList, plugin);
689  cpl_free(helptext);
690 
691  return 0;
692 } /* cpl_plugin_get_info() */
693 
void muse_processing_delete(muse_processing *aProcessing)
Free the muse_processing structure.
int ovscignore
The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when co...
Definition: muse_dark_z.h:62
const char * combine_s
Type of image combination to use. (as string)
Definition: muse_dark_z.h:67
muse_cplframework_type muse_cplframework(void)
Return the CPL framework the recipe is run under.
int scale
Scale the individual images to a common exposure time before combining them.
Definition: muse_dark_z.h:85
const char * ovscreject
This influences how values are rejected when computing overscan statistics. Either no rejection at al...
Definition: muse_dark_z.h:56
cpl_frameset * usedframes
muse_processing * muse_processing_new(const char *aName, cpl_recipe *aRecipe)
Create a new processing structure.
const char * muse_get_license(void)
Get the pipeline copyright and license.
Definition: muse_utils.c:83
muse_frame_mode
cpl_frameset * outframes
double hotsigma
Sigma level, in terms of median deviation above the median dark level, above which a pixel is detecte...
Definition: muse_dark_z.h:91
int nkeep
Number of pixels to keep with minmax.
Definition: muse_dark_z.h:76
Structure to hold the parameters of the muse_dark recipe.
Definition: muse_dark_z.h:48
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.
double ovscsigma
If the deviation of mean overscan levels between a raw input image and the reference image is higher ...
Definition: muse_dark_z.h:59
int merge
Merge output products from different IFUs into a common file.
Definition: muse_dark_z.h:94
double lsigma
Low sigma for pixel rejection with sigclip.
Definition: muse_dark_z.h:79
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 combine
Type of image combination to use.
Definition: muse_dark_z.h:65
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_dark_z.h:50
double normalize
Normalize the master dark to this exposure time (in seconds). To disable normalization, set this to a negative value.
Definition: muse_dark_z.h:88
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.
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_dark_z.h:53
int nlow
Number of minimum pixels to reject with minmax.
Definition: muse_dark_z.h:70
void muse_processing_recipeinfo(cpl_plugin *)
Output main pipeline configuration, inputs, and parameters.
cpl_error_code muse_utils_frameset_merge_frames(cpl_frameset *aFrames, cpl_boolean aDelete)
Merge IFU-specific files from a frameset to create multi-IFU outputs.
Definition: muse_utils.c:589
int nhigh
Number of maximum pixels to reject with minmax.
Definition: muse_dark_z.h:73
double hsigma
High sigma for pixel rejection with sigclip.
Definition: muse_dark_z.h:82
cpl_error_code muse_processing_prepare_property(cpl_propertylist *, const char *, cpl_type, const char *)
Prepare and check the specified property.