MUSE Pipeline Reference Manual  1.0.2
muse_ampl_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_ampl_z.h" /* in turn includes muse.h */
36 
37 /*----------------------------------------------------------------------------*/
63 /*----------------------------------------------------------------------------*/
66 /*----------------------------------------------------------------------------*
67  * Static variables *
68  *----------------------------------------------------------------------------*/
69 static const char *muse_ampl_help =
70  "This recipe combines several separate amplifier images (flat-fields with special FITS headers containing pico amplifier measurements) into one master image file and computes the instrumental throughput per IFU (and slice). 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 them using input parameters. To compute the throughput the image is converted into a pixel table, the flux is then integrated over the given filter band, and the ratio of the expected flux (FITS header INS.AMPL2.CURR) to measured flux is taken, in the same units. If a geometry table was given as input, the relative area of the IFUs is taken into account when computing the flux per unit area. The resulting ratio is the instrument efficiency (throughput) and saved as QC parameters for the whole input image and per slice in the output pixel table.";
71 
72 static const char *muse_ampl_help_esorex =
73  "\n\nInput frames for raw frame tag \"AMPL\":\n"
74  "\n Frame tag Type Req #Fr Description"
75  "\n -------------------- ---- --- --- ------------"
76  "\n AMPL raw Y >=3 Special raw flat-field taken with pico-amplifier readings in the FITS header"
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 GEOMETRY_TABLE calib . 1 Relative positions of the slices in the field of view"
81  "\n FILTER_LIST calib Y 1 Filter definitions; here, it has to contain the filter curve for the filter given in INS.AMPL2.FILTER"
82  "\n TRACE_TABLE calib Y 1 Trace table"
83  "\n WAVECAL_TABLE calib Y 1 Wavelength calibration table"
84  "\n\nProduct frames for raw frame tag \"AMPL\":\n"
85  "\n Frame tag Level Description"
86  "\n -------------------- -------- ------------"
87  "\n MASTER_AMPL final Combined master AMPL image, written if --savemaster=true"
88  "\n TABLE_AMPL final Output table with computations for each CCD pixel, written if --savetable=true."
89  "\n AMPL_CONVOLVED final Combined and convolved master AMPL image";
90 
91 /*----------------------------------------------------------------------------*/
99 /*----------------------------------------------------------------------------*/
100 static cpl_recipeconfig *
101 muse_ampl_new_recipeconfig(void)
102 {
103  cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
104  const char *tag;
105 
106  tag = "AMPL";
107  cpl_recipeconfig_set_tag(recipeconfig, tag, 3, -1);
108  cpl_recipeconfig_set_input(recipeconfig, tag, "MASTER_BIAS", 1, 1);
109  cpl_recipeconfig_set_input(recipeconfig, tag, "MASTER_DARK", -1, 1);
110  cpl_recipeconfig_set_input(recipeconfig, tag, "BADPIX_TABLE", -1, 1);
111  cpl_recipeconfig_set_input(recipeconfig, tag, "GEOMETRY_TABLE", -1, 1);
112  cpl_recipeconfig_set_input(recipeconfig, tag, "FILTER_LIST", 1, 1);
113  cpl_recipeconfig_set_input(recipeconfig, tag, "TRACE_TABLE", 1, 1);
114  cpl_recipeconfig_set_input(recipeconfig, tag, "WAVECAL_TABLE", 1, 1);
115  cpl_recipeconfig_set_output(recipeconfig, tag, "MASTER_AMPL");
116  cpl_recipeconfig_set_output(recipeconfig, tag, "TABLE_AMPL");
117  cpl_recipeconfig_set_output(recipeconfig, tag, "AMPL_CONVOLVED");
118 
119  return recipeconfig;
120 } /* muse_ampl_new_recipeconfig() */
121 
122 /*----------------------------------------------------------------------------*/
132 /*----------------------------------------------------------------------------*/
133 static cpl_error_code
134 muse_ampl_prepare_header(const char *aFrametag, cpl_propertylist *aHeader)
135 {
136  cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
137  cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
138  if (!strcmp(aFrametag, "MASTER_AMPL")) {
139  muse_processing_prepare_property(aHeader, "ESO QC AMPL INPUT[0-9]+ NSATURATED",
140  CPL_TYPE_INT,
141  "Number of saturated pixels in raw image i in input list");
142  muse_processing_prepare_property(aHeader, "ESO QC AMPL MASTER NSATURATED",
143  CPL_TYPE_INT,
144  "Number of saturated pixels in output master image");
145  } else if (!strcmp(aFrametag, "TABLE_AMPL")) {
146  muse_processing_prepare_property(aHeader, "ESO QC AMPL PHOTONS",
147  CPL_TYPE_FLOAT,
148  "[ph] Integrated number of photons detected on the CCD");
149  muse_processing_prepare_property(aHeader, "ESO QC AMPL POWER",
150  CPL_TYPE_FLOAT,
151  "[W] Integrated power detected on the CCD");
152  muse_processing_prepare_property(aHeader, "ESO QC AMPL THRU[0-9]+",
153  CPL_TYPE_FLOAT,
154  "[%] Channel throughput compared to photodiode a");
155  muse_processing_prepare_property(aHeader, "ESO QC AMPL THRU2ERR",
156  CPL_TYPE_FLOAT,
157  "[%] Estimated error of throughput compared to photodiode 2");
158  muse_processing_prepare_property(aHeader, "ESO QC AMPL SLICE[0-9]+ THRU2",
159  CPL_TYPE_FLOAT,
160  "[%] Slice j throughput compared to photodiode 2");
161  } else if (!strcmp(aFrametag, "AMPL_CONVOLVED")) {
162  muse_processing_prepare_property(aHeader, "ESO QC AMPL INPUT[0-9]+ NSATURATED",
163  CPL_TYPE_INT,
164  "Number of saturated pixels in raw image i in input list");
165  muse_processing_prepare_property(aHeader, "ESO QC AMPL MASTER NSATURATED",
166  CPL_TYPE_INT,
167  "Number of saturated pixels in output master image");
168  muse_processing_prepare_property(aHeader, "ESO QC AMPL PHOTONS",
169  CPL_TYPE_FLOAT,
170  "[ph] Integrated number of photons detected on the CCD");
171  muse_processing_prepare_property(aHeader, "ESO QC AMPL POWER",
172  CPL_TYPE_FLOAT,
173  "[W] Integrated power detected on the CCD");
174  muse_processing_prepare_property(aHeader, "ESO QC AMPL THRU[0-9]+",
175  CPL_TYPE_FLOAT,
176  "[%] Channel throughput compared to photodiode a");
177  muse_processing_prepare_property(aHeader, "ESO QC AMPL THRU2ERR",
178  CPL_TYPE_FLOAT,
179  "[%] Estimated error of throughput compared to photodiode 2");
180  muse_processing_prepare_property(aHeader, "ESO QC AMPL SLICE[0-9]+ THRU2",
181  CPL_TYPE_FLOAT,
182  "[%] Slice j throughput compared to photodiode 2");
183  } else {
184  cpl_msg_warning(__func__, "Frame tag %s is not defined", aFrametag);
185  return CPL_ERROR_ILLEGAL_INPUT;
186  }
187  return CPL_ERROR_NONE;
188 } /* muse_ampl_prepare_header() */
189 
190 /*----------------------------------------------------------------------------*/
199 /*----------------------------------------------------------------------------*/
200 static cpl_frame_level
201 muse_ampl_get_frame_level(const char *aFrametag)
202 {
203  if (!aFrametag) {
204  return CPL_FRAME_LEVEL_NONE;
205  }
206  if (!strcmp(aFrametag, "MASTER_AMPL")) {
207  return CPL_FRAME_LEVEL_FINAL;
208  }
209  if (!strcmp(aFrametag, "TABLE_AMPL")) {
210  return CPL_FRAME_LEVEL_FINAL;
211  }
212  if (!strcmp(aFrametag, "AMPL_CONVOLVED")) {
213  return CPL_FRAME_LEVEL_FINAL;
214  }
215  return CPL_FRAME_LEVEL_NONE;
216 } /* muse_ampl_get_frame_level() */
217 
218 /*----------------------------------------------------------------------------*/
227 /*----------------------------------------------------------------------------*/
228 static muse_frame_mode
229 muse_ampl_get_frame_mode(const char *aFrametag)
230 {
231  if (!aFrametag) {
232  return MUSE_FRAME_MODE_ALL;
233  }
234  if (!strcmp(aFrametag, "MASTER_AMPL")) {
235  return MUSE_FRAME_MODE_MASTER;
236  }
237  if (!strcmp(aFrametag, "TABLE_AMPL")) {
238  return MUSE_FRAME_MODE_MASTER;
239  }
240  if (!strcmp(aFrametag, "AMPL_CONVOLVED")) {
241  return MUSE_FRAME_MODE_MASTER;
242  }
243  return MUSE_FRAME_MODE_ALL;
244 } /* muse_ampl_get_frame_mode() */
245 
246 /*----------------------------------------------------------------------------*/
256 /*----------------------------------------------------------------------------*/
257 static int
258 muse_ampl_create(cpl_plugin *aPlugin)
259 {
260  /* Check that the plugin is part of a valid recipe */
261  cpl_recipe *recipe;
262  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
263  recipe = (cpl_recipe *)aPlugin;
264  } else {
265  return -1;
266  }
267 
268  /* register the extended processing information (new FITS header creation, *
269  * getting of the frame level for a certain tag) */
271  muse_ampl_new_recipeconfig(),
272  muse_ampl_prepare_header,
273  muse_ampl_get_frame_level,
274  muse_ampl_get_frame_mode);
275 
276  /* XXX initialize timing in messages *
277  * since at least esorex is too stupid to turn it on, we have to do it */
279  cpl_msg_set_time_on();
280  }
281 
282  /* Create the parameter list in the cpl_recipe object */
283  recipe->parameters = cpl_parameterlist_new();
284  /* Fill the parameters list */
285  cpl_parameter *p;
286 
287  /* --nifu: IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel. */
288  p = cpl_parameter_new_range("muse.muse_ampl.nifu",
289  CPL_TYPE_INT,
290  "IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel.",
291  "muse.muse_ampl",
292  (int)0,
293  (int)-1,
294  (int)24);
295  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nifu");
296  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nifu");
297 
298  cpl_parameterlist_append(recipe->parameters, p);
299 
300  /* --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. */
301  p = cpl_parameter_new_value("muse.muse_ampl.overscan",
302  CPL_TYPE_STRING,
303  "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.",
304  "muse.muse_ampl",
305  (const char *)"vpoly");
306  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "overscan");
307  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "overscan");
308 
309  cpl_parameterlist_append(recipe->parameters, p);
310 
311  /* --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"). */
312  p = cpl_parameter_new_value("muse.muse_ampl.ovscreject",
313  CPL_TYPE_STRING,
314  "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\").",
315  "muse.muse_ampl",
316  (const char *)"dcr");
317  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscreject");
318  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscreject");
319 
320  cpl_parameterlist_append(recipe->parameters, p);
321 
322  /* --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". */
323  p = cpl_parameter_new_value("muse.muse_ampl.ovscsigma",
324  CPL_TYPE_DOUBLE,
325  "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\".",
326  "muse.muse_ampl",
327  (double)30.);
328  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscsigma");
329  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscsigma");
330 
331  cpl_parameterlist_append(recipe->parameters, p);
332 
333  /* --ovscignore: The number of pixels of the overscan adjacent to the data region of the CCD that are ignored when computing statistics or fits. */
334  p = cpl_parameter_new_value("muse.muse_ampl.ovscignore",
335  CPL_TYPE_INT,
336  "The number of pixels of the overscan adjacent to the data region of the CCD that are ignored when computing statistics or fits.",
337  "muse.muse_ampl",
338  (int)3);
339  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscignore");
340  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscignore");
341 
342  cpl_parameterlist_append(recipe->parameters, p);
343 
344  /* --combine: Type of combination to use */
345  p = cpl_parameter_new_enum("muse.muse_ampl.combine",
346  CPL_TYPE_STRING,
347  "Type of combination to use",
348  "muse.muse_ampl",
349  (const char *)"sigclip",
350  4,
351  (const char *)"average",
352  (const char *)"median",
353  (const char *)"minmax",
354  (const char *)"sigclip");
355  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "combine");
356  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "combine");
357 
358  cpl_parameterlist_append(recipe->parameters, p);
359 
360  /* --nlow: Number of minimum pixels to reject with minmax */
361  p = cpl_parameter_new_value("muse.muse_ampl.nlow",
362  CPL_TYPE_INT,
363  "Number of minimum pixels to reject with minmax",
364  "muse.muse_ampl",
365  (int)1);
366  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nlow");
367  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nlow");
368 
369  cpl_parameterlist_append(recipe->parameters, p);
370 
371  /* --nhigh: Number of maximum pixels to reject with minmax */
372  p = cpl_parameter_new_value("muse.muse_ampl.nhigh",
373  CPL_TYPE_INT,
374  "Number of maximum pixels to reject with minmax",
375  "muse.muse_ampl",
376  (int)1);
377  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nhigh");
378  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nhigh");
379 
380  cpl_parameterlist_append(recipe->parameters, p);
381 
382  /* --nkeep: Number of pixels to keep with minmax */
383  p = cpl_parameter_new_value("muse.muse_ampl.nkeep",
384  CPL_TYPE_INT,
385  "Number of pixels to keep with minmax",
386  "muse.muse_ampl",
387  (int)1);
388  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nkeep");
389  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nkeep");
390 
391  cpl_parameterlist_append(recipe->parameters, p);
392 
393  /* --lsigma: Low sigma for pixel rejection with sigclip */
394  p = cpl_parameter_new_value("muse.muse_ampl.lsigma",
395  CPL_TYPE_DOUBLE,
396  "Low sigma for pixel rejection with sigclip",
397  "muse.muse_ampl",
398  (double)3);
399  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lsigma");
400  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lsigma");
401 
402  cpl_parameterlist_append(recipe->parameters, p);
403 
404  /* --hsigma: High sigma for pixel rejection with sigclip */
405  p = cpl_parameter_new_value("muse.muse_ampl.hsigma",
406  CPL_TYPE_DOUBLE,
407  "High sigma for pixel rejection with sigclip",
408  "muse.muse_ampl",
409  (double)3);
410  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "hsigma");
411  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "hsigma");
412 
413  cpl_parameterlist_append(recipe->parameters, p);
414 
415  /* --fbeam: Factor to describe the widening of the beam from the focal plane to photo diode 2. */
416  p = cpl_parameter_new_value("muse.muse_ampl.fbeam",
417  CPL_TYPE_DOUBLE,
418  "Factor to describe the widening of the beam from the focal plane to photo diode 2.",
419  "muse.muse_ampl",
420  (double)1.10);
421  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "fbeam");
422  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fbeam");
423 
424  cpl_parameterlist_append(recipe->parameters, p);
425 
426  /* --temp: Lamp temperature [K] used to create the black body function. */
427  p = cpl_parameter_new_value("muse.muse_ampl.temp",
428  CPL_TYPE_DOUBLE,
429  "Lamp temperature [K] used to create the black body function.",
430  "muse.muse_ampl",
431  (double)3200.);
432  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "temp");
433  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "temp");
434 
435  cpl_parameterlist_append(recipe->parameters, p);
436 
437  /* --savemaster: Save the processed and combined master image before any concolution is done. */
438  p = cpl_parameter_new_value("muse.muse_ampl.savemaster",
439  CPL_TYPE_BOOL,
440  "Save the processed and combined master image before any concolution is done.",
441  "muse.muse_ampl",
442  (int)FALSE);
443  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "savemaster");
444  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "savemaster");
445 
446  cpl_parameterlist_append(recipe->parameters, p);
447 
448  /* --savetable: Save the table with all the processed pixel values. */
449  p = cpl_parameter_new_value("muse.muse_ampl.savetable",
450  CPL_TYPE_BOOL,
451  "Save the table with all the processed pixel values.",
452  "muse.muse_ampl",
453  (int)FALSE);
454  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "savetable");
455  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "savetable");
456 
457  cpl_parameterlist_append(recipe->parameters, p);
458 
459  /* --merge: Merge output products from different IFUs into a common file. */
460  p = cpl_parameter_new_value("muse.muse_ampl.merge",
461  CPL_TYPE_BOOL,
462  "Merge output products from different IFUs into a common file.",
463  "muse.muse_ampl",
464  (int)FALSE);
465  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "merge");
466  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "merge");
467 
468  cpl_parameterlist_append(recipe->parameters, p);
469 
470  return 0;
471 } /* muse_ampl_create() */
472 
473 /*----------------------------------------------------------------------------*/
484 /*----------------------------------------------------------------------------*/
485 static int
486 muse_ampl_params_fill(muse_ampl_params_t *aParams, cpl_parameterlist *aParameters)
487 {
488  cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
489  cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
490  cpl_parameter *p;
491 
492  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.nifu");
493  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
494  aParams->nifu = cpl_parameter_get_int(p);
495 
496  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.overscan");
497  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
498  aParams->overscan = cpl_parameter_get_string(p);
499 
500  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.ovscreject");
501  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
502  aParams->ovscreject = cpl_parameter_get_string(p);
503 
504  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.ovscsigma");
505  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
506  aParams->ovscsigma = cpl_parameter_get_double(p);
507 
508  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.ovscignore");
509  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
510  aParams->ovscignore = cpl_parameter_get_int(p);
511 
512  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.combine");
513  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
514  aParams->combine_s = cpl_parameter_get_string(p);
515  aParams->combine =
516  (!strcasecmp(aParams->combine_s, "average")) ? MUSE_AMPL_PARAM_COMBINE_AVERAGE :
517  (!strcasecmp(aParams->combine_s, "median")) ? MUSE_AMPL_PARAM_COMBINE_MEDIAN :
518  (!strcasecmp(aParams->combine_s, "minmax")) ? MUSE_AMPL_PARAM_COMBINE_MINMAX :
519  (!strcasecmp(aParams->combine_s, "sigclip")) ? MUSE_AMPL_PARAM_COMBINE_SIGCLIP :
520  MUSE_AMPL_PARAM_COMBINE_INVALID_VALUE;
521  cpl_ensure_code(aParams->combine != MUSE_AMPL_PARAM_COMBINE_INVALID_VALUE,
522  CPL_ERROR_ILLEGAL_INPUT);
523 
524  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.nlow");
525  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
526  aParams->nlow = cpl_parameter_get_int(p);
527 
528  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.nhigh");
529  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
530  aParams->nhigh = cpl_parameter_get_int(p);
531 
532  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.nkeep");
533  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
534  aParams->nkeep = cpl_parameter_get_int(p);
535 
536  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.lsigma");
537  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
538  aParams->lsigma = cpl_parameter_get_double(p);
539 
540  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.hsigma");
541  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
542  aParams->hsigma = cpl_parameter_get_double(p);
543 
544  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.fbeam");
545  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
546  aParams->fbeam = cpl_parameter_get_double(p);
547 
548  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.temp");
549  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
550  aParams->temp = cpl_parameter_get_double(p);
551 
552  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.savemaster");
553  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
554  aParams->savemaster = cpl_parameter_get_bool(p);
555 
556  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.savetable");
557  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
558  aParams->savetable = cpl_parameter_get_bool(p);
559 
560  p = cpl_parameterlist_find(aParameters, "muse.muse_ampl.merge");
561  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
562  aParams->merge = cpl_parameter_get_bool(p);
563 
564  return 0;
565 } /* muse_ampl_params_fill() */
566 
567 /*----------------------------------------------------------------------------*/
574 /*----------------------------------------------------------------------------*/
575 static int
576 muse_ampl_exec(cpl_plugin *aPlugin)
577 {
578  if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
579  return -1;
580  }
581  cpl_recipe *recipe = (cpl_recipe *)aPlugin;
582  cpl_msg_set_threadid_on();
583 
584  cpl_frameset *usedframes = cpl_frameset_new(),
585  *outframes = cpl_frameset_new();
586  muse_ampl_params_t params;
587  muse_ampl_params_fill(&params, recipe->parameters);
588 
589  cpl_errorstate prestate = cpl_errorstate_get();
590 
591  if (params.nifu < -1 || params.nifu > kMuseNumIFUs) {
592  cpl_msg_error(__func__, "Please specify a valid IFU number (between 1 and "
593  "%d), 0 (to process all IFUs consecutively), or -1 (to "
594  "process all IFUs in parallel) using --nifu.", kMuseNumIFUs);
595  return -1;
596  } /* if invalid params.nifu */
597 
598  cpl_boolean donotmerge = CPL_FALSE; /* depending on nifu we may not merge */
599  int rc = 0;
600  if (params.nifu > 0) {
601  muse_processing *proc = muse_processing_new("muse_ampl",
602  recipe);
603  rc = muse_ampl_compute(proc, &params);
604  cpl_frameset_join(usedframes, proc->usedframes);
605  cpl_frameset_join(outframes, proc->outframes);
607  donotmerge = CPL_TRUE; /* after processing one IFU, merging cannot work */
608  } else if (params.nifu < 0) { /* parallel processing */
609  int *rcs = cpl_calloc(kMuseNumIFUs, sizeof(int));
610  int nifu;
611  #pragma omp parallel for default(none) \
612  shared(outframes, params, rcs, recipe, usedframes)
613  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
614  muse_processing *proc = muse_processing_new("muse_ampl",
615  recipe);
616  muse_ampl_params_t *pars = cpl_malloc(sizeof(muse_ampl_params_t));
617  memcpy(pars, &params, sizeof(muse_ampl_params_t));
618  pars->nifu = nifu;
619  int *rci = rcs + (nifu - 1);
620  *rci = muse_ampl_compute(proc, pars);
621  if (rci && cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
622  *rci = 0;
623  }
624  cpl_free(pars);
625  #pragma omp critical(muse_processing_used_frames)
626  cpl_frameset_join(usedframes, proc->usedframes);
627  #pragma omp critical(muse_processing_output_frames)
628  cpl_frameset_join(outframes, proc->outframes);
630  } /* for nifu */
631  /* non-parallel loop to propagate the "worst" return code; *
632  * since we only ever return -1, any non-zero code is propagated */
633  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
634  if (rcs[nifu-1] != 0) {
635  rc = rcs[nifu-1];
636  } /* if */
637  } /* for nifu */
638  cpl_free(rcs);
639  } else { /* serial processing */
640  for (params.nifu = 1; params.nifu <= kMuseNumIFUs && !rc; params.nifu++) {
641  muse_processing *proc = muse_processing_new("muse_ampl",
642  recipe);
643  rc = muse_ampl_compute(proc, &params);
644  if (rc && cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
645  rc = 0;
646  }
647  cpl_frameset_join(usedframes, proc->usedframes);
648  cpl_frameset_join(outframes, proc->outframes);
650  } /* for nifu */
651  } /* else */
652  UNUSED_ARGUMENT(donotmerge); /* maybe this is not going to be used below */
653 
654  if (!cpl_errorstate_is_equal(prestate)) {
655  /* dump all errors from this recipe in chronological order */
656  cpl_errorstate_dump(prestate, CPL_FALSE, muse_cplerrorstate_dump_some);
657  /* reset message level to not get the same errors displayed again by esorex */
658  cpl_msg_set_level(CPL_MSG_INFO);
659  }
660  /* clean up duplicates in framesets of used and output frames */
663 
664  /* merge output products from the up to 24 IFUs */
665  if (params.merge && !donotmerge) {
666  muse_utils_frameset_merge_frames(outframes);
667  }
668 
669  /* to get esorex to see our classification (frame groups etc.), *
670  * replace the original frameset with the list of used frames *
671  * before appending product output frames */
672  /* keep the same pointer, so just erase all frames, not delete the frameset */
673  muse_cplframeset_erase_all(recipe->frames);
674  cpl_frameset_join(recipe->frames, usedframes);
675  cpl_frameset_join(recipe->frames, outframes);
676  cpl_frameset_delete(usedframes);
677  cpl_frameset_delete(outframes);
678  return rc;
679 } /* muse_ampl_exec() */
680 
681 /*----------------------------------------------------------------------------*/
688 /*----------------------------------------------------------------------------*/
689 static int
690 muse_ampl_destroy(cpl_plugin *aPlugin)
691 {
692  /* Get the recipe from the plugin */
693  cpl_recipe *recipe;
694  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
695  recipe = (cpl_recipe *)aPlugin;
696  } else {
697  return -1;
698  }
699 
700  /* Clean up */
701  cpl_parameterlist_delete(recipe->parameters);
703  return 0;
704 } /* muse_ampl_destroy() */
705 
706 /*----------------------------------------------------------------------------*/
716 /*----------------------------------------------------------------------------*/
717 int
718 cpl_plugin_get_info(cpl_pluginlist *aList)
719 {
720  cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
721  cpl_plugin *plugin = &recipe->interface;
722 
723  char *helptext;
725  helptext = cpl_sprintf("%s%s", muse_ampl_help,
726  muse_ampl_help_esorex);
727  } else {
728  helptext = cpl_sprintf("%s", muse_ampl_help);
729  }
730 
731  /* Initialize the CPL plugin stuff for this module */
732  cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
733  CPL_PLUGIN_TYPE_RECIPE,
734  "muse_ampl",
735  "Determine the instrumental throughput from exposures taken with the pico-amplifier / photo diode readings.",
736  helptext,
737  "Peter Weilbacher",
738  "usd-help@eso.org",
740  muse_ampl_create,
741  muse_ampl_exec,
742  muse_ampl_destroy);
743  cpl_pluginlist_append(aList, plugin);
744  cpl_free(helptext);
745 
746  return 0;
747 } /* cpl_plugin_get_info() */
748 
void muse_processing_delete(muse_processing *aProcessing)
Free the muse_processing structure.
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_ampl_z.h:50
Structure to hold the parameters of the muse_ampl recipe.
Definition: muse_ampl_z.h:48
muse_cplframework_type muse_cplframework(void)
Return the CPL framework the recipe is run under.
int nhigh
Number of maximum pixels to reject with minmax.
Definition: muse_ampl_z.h:73
double ovscsigma
If the deviation of mean overscan levels between a raw input image and the reference image is higher ...
Definition: muse_ampl_z.h:59
double temp
Lamp temperature [K] used to create the black body function.
Definition: muse_ampl_z.h:88
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
int nlow
Number of minimum pixels to reject with minmax.
Definition: muse_ampl_z.h:70
int combine
Type of combination to use.
Definition: muse_ampl_z.h:65
int ovscignore
The number of pixels of the overscan adjacent to the data region of the CCD that are ignored when com...
Definition: muse_ampl_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_ampl_z.h:53
cpl_frameset * outframes
int merge
Merge output products from different IFUs into a common file.
Definition: muse_ampl_z.h:97
int savetable
Save the table with all the processed pixel values.
Definition: muse_ampl_z.h:94
int nkeep
Number of pixels to keep with minmax.
Definition: muse_ampl_z.h:76
void muse_cplerrorstate_dump_some(unsigned aCurrent, unsigned aFirst, unsigned aLast)
Dump some CPL errors.
void muse_processinginfo_delete(cpl_recipe *)
Clear all information from the processing info and from the recipe config.
double hsigma
High sigma for pixel rejection with sigclip.
Definition: muse_ampl_z.h:82
const char * ovscreject
This influences how values are rejected when computing overscan statistics. Either no rejection at al...
Definition: muse_ampl_z.h:56
double fbeam
Factor to describe the widening of the beam from the focal plane to photo diode 2.
Definition: muse_ampl_z.h:85
const char * combine_s
Type of combination to use (as string)
Definition: muse_ampl_z.h:67
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 savemaster
Save the processed and combined master image before any concolution is done.
Definition: muse_ampl_z.h:91
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.
double lsigma
Low sigma for pixel rejection with sigclip.
Definition: muse_ampl_z.h:79
cpl_error_code muse_processing_prepare_property(cpl_propertylist *, const char *, cpl_type, const char *)
Prepare and check the specified property.