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