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