MUSE Pipeline Reference Manual  2.1.1
muse_lingain_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_lingain_z.h" /* in turn includes muse.h */
36 
37 /*----------------------------------------------------------------------------*/
70 /*----------------------------------------------------------------------------*/
73 /*----------------------------------------------------------------------------*
74  * Static variables *
75  *----------------------------------------------------------------------------*/
76 static const char *muse_lingain_help =
77  "The recipe uses the bias and flat field images of a detector monitoring exposure sequence to determine the detector gain in counts/ADU and to model the residual non-linearity for each of the four detector quadrants of all IFUs. All measurements done by the recipe are done on the illuminated parts of the detector, i.e. on the slices. The location of the slices is taken from the given trace table, which is a mandatory input. Using the traces of the slices on the detector a set of measurement windows is placed along these traces. The data used for the determination of the gain and the residual non-linearity is the taken from these windows. Bad pixels indicated by an, optionally, provided bad pixel table, or flagged during the preprocessing (bias subtraction) of the input data are excluded from the measurements. Local measurements of the read-out-noise, the signal and the gain are calculated for each of the measurement windows. Using these measurements the gain for each detector quadrant is computed as the zero-order coefficient of a 1st order polynomial fitted to the binned gain measurements as a function of the signal level. The residual non-linearity is modelled by a (high) order polynomial which is fitted to the fractional percentage deviation of the count rate from an expected constant count rate (the linear case) as function of the signal level.";
78 
79 static const char *muse_lingain_help_esorex =
80  "\n\nInput frames for raw frame tag \"DETMON_LAMP_OFF\":\n"
81  "\n Frame tag Type Req #Fr Description"
82  "\n -------------------- ---- --- --- ------------"
83  "\n DETMON_LAMP_OFF raw Y >=2 Detector monitoring bias images"
84  "\n DETMON_LAMP_ON raw Y >=2 Detector monitoring flat field images"
85  "\n MASTER_BIAS calib Y 1 Master bias"
86  "\n TRACE_TABLE calib Y 1 Trace table"
87  "\n BADPIX_TABLE calib . Known bad pixels"
88  "\n\nProduct frames for raw frame tag \"DETMON_LAMP_OFF\":\n"
89  "\n Frame tag Level Description"
90  "\n -------------------- -------- ------------"
91  "\n NONLINEARITY_GAIN final List of non-linearity and gain parameters for each detector readout port.";
92 
93 /*----------------------------------------------------------------------------*/
101 /*----------------------------------------------------------------------------*/
102 static cpl_recipeconfig *
103 muse_lingain_new_recipeconfig(void)
104 {
105  cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
106 
107  cpl_recipeconfig_set_tag(recipeconfig, "DETMON_LAMP_OFF", 2, -1);
108  cpl_recipeconfig_set_input(recipeconfig, "DETMON_LAMP_OFF", "MASTER_BIAS", 1, 1);
109  cpl_recipeconfig_set_input(recipeconfig, "DETMON_LAMP_OFF", "TRACE_TABLE", 1, 1);
110  cpl_recipeconfig_set_input(recipeconfig, "DETMON_LAMP_OFF", "BADPIX_TABLE", -1, -1);
111  cpl_recipeconfig_set_output(recipeconfig, "DETMON_LAMP_OFF", "NONLINEARITY_GAIN");
112  cpl_recipeconfig_set_tag(recipeconfig, "DETMON_LAMP_ON", 2, -1);
113  cpl_recipeconfig_set_input(recipeconfig, "DETMON_LAMP_ON", "MASTER_BIAS", 1, 1);
114  cpl_recipeconfig_set_input(recipeconfig, "DETMON_LAMP_ON", "TRACE_TABLE", 1, 1);
115  cpl_recipeconfig_set_input(recipeconfig, "DETMON_LAMP_ON", "BADPIX_TABLE", -1, -1);
116  cpl_recipeconfig_set_output(recipeconfig, "DETMON_LAMP_ON", "NONLINEARITY_GAIN");
117 
118  return recipeconfig;
119 } /* muse_lingain_new_recipeconfig() */
120 
121 /*----------------------------------------------------------------------------*/
131 /*----------------------------------------------------------------------------*/
132 static cpl_error_code
133 muse_lingain_prepare_header(const char *aFrametag, cpl_propertylist *aHeader)
134 {
135  cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
136  cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
137  if (!strcmp(aFrametag, "NONLINEARITY_GAIN")) {
138  muse_processing_prepare_property(aHeader, "ESO QC LINGAIN GFIT[1234] RMS",
139  CPL_TYPE_DOUBLE,
140  "RMS of the first order polynomial fit used to determine the gain.");
141  muse_processing_prepare_property(aHeader, "ESO QC LINGAIN NLFIT[1234] RMS",
142  CPL_TYPE_DOUBLE,
143  "RMS of the residual non-linearity fit.");
144  } else {
145  cpl_msg_warning(__func__, "Frame tag %s is not defined", aFrametag);
146  return CPL_ERROR_ILLEGAL_INPUT;
147  }
148  return CPL_ERROR_NONE;
149 } /* muse_lingain_prepare_header() */
150 
151 /*----------------------------------------------------------------------------*/
160 /*----------------------------------------------------------------------------*/
161 static cpl_frame_level
162 muse_lingain_get_frame_level(const char *aFrametag)
163 {
164  if (!aFrametag) {
165  return CPL_FRAME_LEVEL_NONE;
166  }
167  if (!strcmp(aFrametag, "NONLINEARITY_GAIN")) {
168  return CPL_FRAME_LEVEL_FINAL;
169  }
170  return CPL_FRAME_LEVEL_NONE;
171 } /* muse_lingain_get_frame_level() */
172 
173 /*----------------------------------------------------------------------------*/
182 /*----------------------------------------------------------------------------*/
183 static muse_frame_mode
184 muse_lingain_get_frame_mode(const char *aFrametag)
185 {
186  if (!aFrametag) {
187  return MUSE_FRAME_MODE_ALL;
188  }
189  if (!strcmp(aFrametag, "NONLINEARITY_GAIN")) {
190  return MUSE_FRAME_MODE_MASTER;
191  }
192  return MUSE_FRAME_MODE_ALL;
193 } /* muse_lingain_get_frame_mode() */
194 
195 /*----------------------------------------------------------------------------*/
205 /*----------------------------------------------------------------------------*/
206 static int
207 muse_lingain_create(cpl_plugin *aPlugin)
208 {
209  /* Check that the plugin is part of a valid recipe */
210  cpl_recipe *recipe;
211  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
212  recipe = (cpl_recipe *)aPlugin;
213  } else {
214  return -1;
215  }
216 
217  /* register the extended processing information (new FITS header creation, *
218  * getting of the frame level for a certain tag) */
220  muse_lingain_new_recipeconfig(),
221  muse_lingain_prepare_header,
222  muse_lingain_get_frame_level,
223  muse_lingain_get_frame_mode);
224 
225  /* XXX initialize timing in messages *
226  * since at least esorex is too stupid to turn it on, we have to do it */
228  cpl_msg_set_time_on();
229  }
230 
231  /* Create the parameter list in the cpl_recipe object */
232  recipe->parameters = cpl_parameterlist_new();
233  /* Fill the parameters list */
234  cpl_parameter *p;
235 
236  /* --nifu: IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel. */
237  p = cpl_parameter_new_range("muse.muse_lingain.nifu",
238  CPL_TYPE_INT,
239  "IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel.",
240  "muse.muse_lingain",
241  (int)0,
242  (int)-1,
243  (int)24);
244  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nifu");
245  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nifu");
246 
247  cpl_parameterlist_append(recipe->parameters, p);
248 
249  /* --ybox:
250  Size of windows along the traces of the slices.
251  */
252  p = cpl_parameter_new_value("muse.muse_lingain.ybox",
253  CPL_TYPE_INT,
254  "Size of windows along the traces of the slices.",
255  "muse.muse_lingain",
256  (int)50);
257  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ybox");
258  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ybox");
259 
260  cpl_parameterlist_append(recipe->parameters, p);
261 
262  /* --xgap:
263  Extra offset from tracing edge.
264  */
265  p = cpl_parameter_new_value("muse.muse_lingain.xgap",
266  CPL_TYPE_INT,
267  "Extra offset from tracing edge.",
268  "muse.muse_lingain",
269  (int)3);
270  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "xgap");
271  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "xgap");
272 
273  cpl_parameterlist_append(recipe->parameters, p);
274 
275  /* --xborder:
276  Extra offset from the detector edge used for the selection of slices.
277  */
278  p = cpl_parameter_new_value("muse.muse_lingain.xborder",
279  CPL_TYPE_INT,
280  "Extra offset from the detector edge used for the selection of slices.",
281  "muse.muse_lingain",
282  (int)10);
283  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "xborder");
284  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "xborder");
285 
286  cpl_parameterlist_append(recipe->parameters, p);
287 
288  /* --order:
289  Order of the polynomial used to fit the non-linearity residuals.
290  */
291  p = cpl_parameter_new_value("muse.muse_lingain.order",
292  CPL_TYPE_INT,
293  "Order of the polynomial used to fit the non-linearity residuals.",
294  "muse.muse_lingain",
295  (int)12);
296  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "order");
297  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "order");
298 
299  cpl_parameterlist_append(recipe->parameters, p);
300 
301  /* --toffset:
302  Exposure time offset in seconds to apply to linearity flat fields.
303  */
304  p = cpl_parameter_new_value("muse.muse_lingain.toffset",
305  CPL_TYPE_DOUBLE,
306  "Exposure time offset in seconds to apply to linearity flat fields.",
307  "muse.muse_lingain",
308  (double)0.018);
309  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "toffset");
310  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "toffset");
311 
312  cpl_parameterlist_append(recipe->parameters, p);
313 
314  /* --fluxtol:
315  Tolerance value for the overall flux consistency check of a pair of flat fields. The value is the maximum relative offset.
316  */
317  p = cpl_parameter_new_value("muse.muse_lingain.fluxtol",
318  CPL_TYPE_DOUBLE,
319  "Tolerance value for the overall flux consistency check of a pair of flat fields. The value is the maximum relative offset.",
320  "muse.muse_lingain",
321  (double)0.01);
322  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "fluxtol");
323  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fluxtol");
324 
325  cpl_parameterlist_append(recipe->parameters, p);
326 
327  /* --sigma: Sigma value used for signal value clipping. */
328  p = cpl_parameter_new_value("muse.muse_lingain.sigma",
329  CPL_TYPE_DOUBLE,
330  "Sigma value used for signal value clipping.",
331  "muse.muse_lingain",
332  (double)3.);
333  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "sigma");
334  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sigma");
335 
336  cpl_parameterlist_append(recipe->parameters, p);
337 
338  /* --signalmin: Minimum signal value in log(ADU) used for the gain analysis and the non-linearity polynomial model. */
339  p = cpl_parameter_new_value("muse.muse_lingain.signalmin",
340  CPL_TYPE_DOUBLE,
341  "Minimum signal value in log(ADU) used for the gain analysis and the non-linearity polynomial model.",
342  "muse.muse_lingain",
343  (double)0.);
344  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "signalmin");
345  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "signalmin");
346 
347  cpl_parameterlist_append(recipe->parameters, p);
348 
349  /* --signalmax: Maximum signal value in log(ADU) used for the gain analysis and the non-linearity polynomial model. */
350  p = cpl_parameter_new_value("muse.muse_lingain.signalmax",
351  CPL_TYPE_DOUBLE,
352  "Maximum signal value in log(ADU) used for the gain analysis and the non-linearity polynomial model.",
353  "muse.muse_lingain",
354  (double)4.9);
355  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "signalmax");
356  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "signalmax");
357 
358  cpl_parameterlist_append(recipe->parameters, p);
359 
360  /* --signalbin: Size of a signal bin in log10(ADU) used for the gain analysis and the non-linearity polynomial model. */
361  p = cpl_parameter_new_value("muse.muse_lingain.signalbin",
362  CPL_TYPE_DOUBLE,
363  "Size of a signal bin in log10(ADU) used for the gain analysis and the non-linearity polynomial model.",
364  "muse.muse_lingain",
365  (double)0.1);
366  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "signalbin");
367  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "signalbin");
368 
369  cpl_parameterlist_append(recipe->parameters, p);
370 
371  /* --gainlimit: Minimum signal value [ADU] used for fitting the gain relation. */
372  p = cpl_parameter_new_value("muse.muse_lingain.gainlimit",
373  CPL_TYPE_DOUBLE,
374  "Minimum signal value [ADU] used for fitting the gain relation.",
375  "muse.muse_lingain",
376  (double)100.);
377  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "gainlimit");
378  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "gainlimit");
379 
380  cpl_parameterlist_append(recipe->parameters, p);
381 
382  /* --gainsigma: Sigma value for gain value clipping. */
383  p = cpl_parameter_new_value("muse.muse_lingain.gainsigma",
384  CPL_TYPE_DOUBLE,
385  "Sigma value for gain value clipping.",
386  "muse.muse_lingain",
387  (double)3.);
388  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "gainsigma");
389  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "gainsigma");
390 
391  cpl_parameterlist_append(recipe->parameters, p);
392 
393  /* --ctsmin: Minimum signal value in log(counts) to consider for the non-linearity analysis. */
394  p = cpl_parameter_new_value("muse.muse_lingain.ctsmin",
395  CPL_TYPE_DOUBLE,
396  "Minimum signal value in log(counts) to consider for the non-linearity analysis.",
397  "muse.muse_lingain",
398  (double)3.);
399  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ctsmin");
400  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ctsmin");
401 
402  cpl_parameterlist_append(recipe->parameters, p);
403 
404  /* --ctsmax: Maximum signal value in log(counts) to consider for the non-linearity analysis. */
405  p = cpl_parameter_new_value("muse.muse_lingain.ctsmax",
406  CPL_TYPE_DOUBLE,
407  "Maximum signal value in log(counts) to consider for the non-linearity analysis.",
408  "muse.muse_lingain",
409  (double)4.9);
410  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ctsmax");
411  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ctsmax");
412 
413  cpl_parameterlist_append(recipe->parameters, p);
414 
415  /* --ctsbin: Size of a signal bin in log10(counts) used for the non-linearity analysis. */
416  p = cpl_parameter_new_value("muse.muse_lingain.ctsbin",
417  CPL_TYPE_DOUBLE,
418  "Size of a signal bin in log10(counts) used for the non-linearity analysis.",
419  "muse.muse_lingain",
420  (double)0.1);
421  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ctsbin");
422  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ctsbin");
423 
424  cpl_parameterlist_append(recipe->parameters, p);
425 
426  /* --linearmin: Lower limit of desired linear range in log10(counts). */
427  p = cpl_parameter_new_value("muse.muse_lingain.linearmin",
428  CPL_TYPE_DOUBLE,
429  "Lower limit of desired linear range in log10(counts).",
430  "muse.muse_lingain",
431  (double)2.5);
432  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "linearmin");
433  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "linearmin");
434 
435  cpl_parameterlist_append(recipe->parameters, p);
436 
437  /* --linearmax: Upper limit of desired linear range in log10(counts). */
438  p = cpl_parameter_new_value("muse.muse_lingain.linearmax",
439  CPL_TYPE_DOUBLE,
440  "Upper limit of desired linear range in log10(counts).",
441  "muse.muse_lingain",
442  (double)3.);
443  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "linearmax");
444  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "linearmax");
445 
446  cpl_parameterlist_append(recipe->parameters, p);
447 
448  /* --merge: Merge output products from different IFUs into a common file. */
449  p = cpl_parameter_new_value("muse.muse_lingain.merge",
450  CPL_TYPE_BOOL,
451  "Merge output products from different IFUs into a common file.",
452  "muse.muse_lingain",
453  (int)FALSE);
454  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "merge");
455  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "merge");
456 
457  cpl_parameterlist_append(recipe->parameters, p);
458 
459  return 0;
460 } /* muse_lingain_create() */
461 
462 /*----------------------------------------------------------------------------*/
473 /*----------------------------------------------------------------------------*/
474 static int
475 muse_lingain_params_fill(muse_lingain_params_t *aParams, cpl_parameterlist *aParameters)
476 {
477  cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
478  cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
479  cpl_parameter *p;
480 
481  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.nifu");
482  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
483  aParams->nifu = cpl_parameter_get_int(p);
484 
485  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.ybox");
486  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
487  aParams->ybox = cpl_parameter_get_int(p);
488 
489  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.xgap");
490  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
491  aParams->xgap = cpl_parameter_get_int(p);
492 
493  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.xborder");
494  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
495  aParams->xborder = cpl_parameter_get_int(p);
496 
497  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.order");
498  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
499  aParams->order = cpl_parameter_get_int(p);
500 
501  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.toffset");
502  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
503  aParams->toffset = cpl_parameter_get_double(p);
504 
505  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.fluxtol");
506  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
507  aParams->fluxtol = cpl_parameter_get_double(p);
508 
509  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.sigma");
510  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
511  aParams->sigma = cpl_parameter_get_double(p);
512 
513  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.signalmin");
514  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
515  aParams->signalmin = cpl_parameter_get_double(p);
516 
517  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.signalmax");
518  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
519  aParams->signalmax = cpl_parameter_get_double(p);
520 
521  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.signalbin");
522  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
523  aParams->signalbin = cpl_parameter_get_double(p);
524 
525  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.gainlimit");
526  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
527  aParams->gainlimit = cpl_parameter_get_double(p);
528 
529  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.gainsigma");
530  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
531  aParams->gainsigma = cpl_parameter_get_double(p);
532 
533  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.ctsmin");
534  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
535  aParams->ctsmin = cpl_parameter_get_double(p);
536 
537  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.ctsmax");
538  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
539  aParams->ctsmax = cpl_parameter_get_double(p);
540 
541  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.ctsbin");
542  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
543  aParams->ctsbin = cpl_parameter_get_double(p);
544 
545  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.linearmin");
546  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
547  aParams->linearmin = cpl_parameter_get_double(p);
548 
549  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.linearmax");
550  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
551  aParams->linearmax = cpl_parameter_get_double(p);
552 
553  p = cpl_parameterlist_find(aParameters, "muse.muse_lingain.merge");
554  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
555  aParams->merge = cpl_parameter_get_bool(p);
556 
557  return 0;
558 } /* muse_lingain_params_fill() */
559 
560 /*----------------------------------------------------------------------------*/
567 /*----------------------------------------------------------------------------*/
568 static int
569 muse_lingain_exec(cpl_plugin *aPlugin)
570 {
571  if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
572  return -1;
573  }
575  cpl_recipe *recipe = (cpl_recipe *)aPlugin;
576  cpl_msg_set_threadid_on();
577 
578  cpl_frameset *usedframes = cpl_frameset_new(),
579  *outframes = cpl_frameset_new();
580  muse_lingain_params_t params;
581  muse_lingain_params_fill(&params, recipe->parameters);
582 
583  cpl_errorstate prestate = cpl_errorstate_get();
584 
585  if (params.nifu < -1 || params.nifu > kMuseNumIFUs) {
586  cpl_msg_error(__func__, "Please specify a valid IFU number (between 1 and "
587  "%d), 0 (to process all IFUs consecutively), or -1 (to "
588  "process all IFUs in parallel) using --nifu.", kMuseNumIFUs);
589  return -1;
590  } /* if invalid params.nifu */
591 
592  cpl_boolean donotmerge = CPL_FALSE; /* depending on nifu we may not merge */
593  int rc = 0;
594  if (params.nifu > 0) {
595  muse_processing *proc = muse_processing_new("muse_lingain",
596  recipe);
597  rc = muse_lingain_compute(proc, &params);
598  cpl_frameset_join(usedframes, proc->usedframes);
599  cpl_frameset_join(outframes, proc->outframes);
601  donotmerge = CPL_TRUE; /* after processing one IFU, merging cannot work */
602  } else if (params.nifu < 0) { /* parallel processing */
603  int *rcs = cpl_calloc(kMuseNumIFUs, sizeof(int));
604  int nifu;
605  #pragma omp parallel for default(none) \
606  shared(outframes, params, rcs, recipe, usedframes)
607  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
608  muse_processing *proc = muse_processing_new("muse_lingain",
609  recipe);
610  muse_lingain_params_t *pars = cpl_malloc(sizeof(muse_lingain_params_t));
611  memcpy(pars, &params, sizeof(muse_lingain_params_t));
612  pars->nifu = nifu;
613  int *rci = rcs + (nifu - 1);
614  *rci = muse_lingain_compute(proc, pars);
615  if (rci && (int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
616  *rci = 0;
617  }
618  cpl_free(pars);
619  #pragma omp critical(muse_processing_used_frames)
620  cpl_frameset_join(usedframes, proc->usedframes);
621  #pragma omp critical(muse_processing_output_frames)
622  cpl_frameset_join(outframes, proc->outframes);
624  } /* for nifu */
625  /* non-parallel loop to propagate the "worst" return code; *
626  * since we only ever return -1, any non-zero code is propagated */
627  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
628  if (rcs[nifu-1] != 0) {
629  rc = rcs[nifu-1];
630  } /* if */
631  } /* for nifu */
632  cpl_free(rcs);
633  } else { /* serial processing */
634  for (params.nifu = 1; params.nifu <= kMuseNumIFUs && !rc; params.nifu++) {
635  muse_processing *proc = muse_processing_new("muse_lingain",
636  recipe);
637  rc = muse_lingain_compute(proc, &params);
638  if (rc && (int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
639  rc = 0;
640  }
641  cpl_frameset_join(usedframes, proc->usedframes);
642  cpl_frameset_join(outframes, proc->outframes);
644  } /* for nifu */
645  } /* else */
646  UNUSED_ARGUMENT(donotmerge); /* maybe this is not going to be used below */
647 
648  if (!cpl_errorstate_is_equal(prestate)) {
649  /* dump all errors from this recipe in chronological order */
650  cpl_errorstate_dump(prestate, CPL_FALSE, muse_cplerrorstate_dump_some);
651  /* reset message level to not get the same errors displayed again by esorex */
652  cpl_msg_set_level(CPL_MSG_INFO);
653  }
654  /* clean up duplicates in framesets of used and output frames */
657 
658  /* merge output products from the up to 24 IFUs */
659  if (params.merge && !donotmerge) {
660  muse_utils_frameset_merge_frames(outframes, CPL_TRUE);
661  }
662 
663  /* to get esorex to see our classification (frame groups etc.), *
664  * replace the original frameset with the list of used frames *
665  * before appending product output frames */
666  /* keep the same pointer, so just erase all frames, not delete the frameset */
667  muse_cplframeset_erase_all(recipe->frames);
668  cpl_frameset_join(recipe->frames, usedframes);
669  cpl_frameset_join(recipe->frames, outframes);
670  cpl_frameset_delete(usedframes);
671  cpl_frameset_delete(outframes);
672  return rc;
673 } /* muse_lingain_exec() */
674 
675 /*----------------------------------------------------------------------------*/
682 /*----------------------------------------------------------------------------*/
683 static int
684 muse_lingain_destroy(cpl_plugin *aPlugin)
685 {
686  /* Get the recipe from the plugin */
687  cpl_recipe *recipe;
688  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
689  recipe = (cpl_recipe *)aPlugin;
690  } else {
691  return -1;
692  }
693 
694  /* Clean up */
695  cpl_parameterlist_delete(recipe->parameters);
697  return 0;
698 } /* muse_lingain_destroy() */
699 
700 /*----------------------------------------------------------------------------*/
710 /*----------------------------------------------------------------------------*/
711 int
712 cpl_plugin_get_info(cpl_pluginlist *aList)
713 {
714  cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
715  cpl_plugin *plugin = &recipe->interface;
716 
717  char *helptext;
719  helptext = cpl_sprintf("%s%s", muse_lingain_help,
720  muse_lingain_help_esorex);
721  } else {
722  helptext = cpl_sprintf("%s", muse_lingain_help);
723  }
724 
725  /* Initialize the CPL plugin stuff for this module */
726  cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
727  CPL_PLUGIN_TYPE_RECIPE,
728  "muse_lingain",
729  "Compute the gain and a model of the residual non-linearity for each detector quadrant",
730  helptext,
731  "Ralf Palsa",
732  "usd-help@eso.org",
734  muse_lingain_create,
735  muse_lingain_exec,
736  muse_lingain_destroy);
737  cpl_pluginlist_append(aList, plugin);
738  cpl_free(helptext);
739 
740  return 0;
741 } /* cpl_plugin_get_info() */
742 
void muse_processing_delete(muse_processing *aProcessing)
Free the muse_processing structure.
int merge
Merge output products from different IFUs into a common file.
muse_cplframework_type muse_cplframework(void)
Return the CPL framework the recipe is run under.
Structure to hold the parameters of the muse_lingain recipe.
double signalmin
Minimum signal value in log(ADU) used for the gain analysis and the non-linearity polynomial model...
double linearmin
Lower limit of desired linear range in log10(counts).
double sigma
Sigma value used for signal value clipping.
int nifu
IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in ...
double signalbin
Size of a signal bin in log10(ADU) used for the gain analysis and the non-linearity polynomial model...
cpl_frameset * usedframes
muse_processing * muse_processing_new(const char *aName, cpl_recipe *aRecipe)
Create a new processing structure.
const char * muse_get_license(void)
Get the pipeline copyright and license.
Definition: muse_utils.c:83
muse_frame_mode
cpl_frameset * outframes
double signalmax
Maximum signal value in log(ADU) used for the gain analysis and the non-linearity polynomial model...
double fluxtol
Tolerance value for the overall flux consistency check of a pair of flat fields. The value is the max...
void muse_cplerrorstate_dump_some(unsigned aCurrent, unsigned aFirst, unsigned aLast)
Dump some CPL errors.
void muse_processinginfo_delete(cpl_recipe *)
Clear all information from the processing info and from the recipe config.
int order
Order of the polynomial used to fit the non-linearity residuals.
double toffset
Exposure time offset in seconds to apply to linearity flat fields.
double gainsigma
Sigma value for gain value clipping.
double linearmax
Upper limit of desired linear range in log10(counts).
double ctsmin
Minimum signal value in log(counts) to consider for the non-linearity analysis.
cpl_error_code muse_cplframeset_erase_duplicate(cpl_frameset *aFrames)
Erase all duplicate frames from a frameset.
double ctsbin
Size of a signal bin in log10(counts) used for the non-linearity analysis.
cpl_error_code muse_cplframeset_erase_all(cpl_frameset *aFrames)
Erase all frames in a frameset.
int xborder
Extra offset from the detector edge used for the selection of slices.
double ctsmax
Maximum signal value in log(counts) to consider for the non-linearity analysis.
int xgap
Extra offset from tracing edge.
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 gainlimit
Minimum signal value [ADU] used for fitting the gain relation.
int ybox
Size of windows along the traces of the slices.
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.