MUSE Pipeline Reference Manual  2.1.1
muse_lsf_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_lsf_z.h" /* in turn includes muse.h */
36 
37 /*----------------------------------------------------------------------------*/
45 /*----------------------------------------------------------------------------*/
48 /*----------------------------------------------------------------------------*
49  * Static variables *
50  *----------------------------------------------------------------------------*/
51 static const char *muse_lsf_help =
52  "Compute the slice and wavelength dependent LSF from a lines spectrum (ARC lamp).";
53 
54 static const char *muse_lsf_help_esorex =
55  "\n\nInput frames for raw frame tag \"ARC\":\n"
56  "\n Frame tag Type Req #Fr Description"
57  "\n -------------------- ---- --- --- ------------"
58  "\n ARC raw . Raw arc lamp exposures (from a standard arc sequence)"
59  "\n ARC_LSF raw . Raw arc lamp exposures (from a long LSF arc sequence)"
60  "\n MASTER_BIAS calib Y 1 Master bias"
61  "\n MASTER_DARK calib . 1 Master dark"
62  "\n MASTER_FLAT calib . 1 Master flat"
63  "\n TRACE_TABLE calib Y 1 Trace table"
64  "\n WAVECAL_TABLE calib Y 1 Wavelength calibration table"
65  "\n BADPIX_TABLE calib . Known bad pixels"
66  "\n LINE_CATALOG calib Y 1 Arc line catalog"
67  "\n\nProduct frames for raw frame tag \"ARC\":\n"
68  "\n Frame tag Level Description"
69  "\n -------------------- -------- ------------"
70  "\n LSF_PROFILE final Slice specific LSF images, stacked into one data cube per IFU."
71  "\n PIXTABLE_SUBTRACTED final Subtracted combined pixel table, if --save_subtracted=true. This file contains only the subtracted arc lines that contributed to the LSF calculation. There are additional columns line_lambda and line_flux with the reference wavelength and the estimated line flux of the corresponding arc line.";
72 
73 /*----------------------------------------------------------------------------*/
81 /*----------------------------------------------------------------------------*/
82 static cpl_recipeconfig *
83 muse_lsf_new_recipeconfig(void)
84 {
85  cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
86 
87  cpl_recipeconfig_set_tag(recipeconfig, "ARC", -1, -1);
88  cpl_recipeconfig_set_input(recipeconfig, "ARC", "MASTER_BIAS", 1, 1);
89  cpl_recipeconfig_set_input(recipeconfig, "ARC", "MASTER_DARK", -1, 1);
90  cpl_recipeconfig_set_input(recipeconfig, "ARC", "MASTER_FLAT", -1, 1);
91  cpl_recipeconfig_set_input(recipeconfig, "ARC", "TRACE_TABLE", 1, 1);
92  cpl_recipeconfig_set_input(recipeconfig, "ARC", "WAVECAL_TABLE", 1, 1);
93  cpl_recipeconfig_set_input(recipeconfig, "ARC", "BADPIX_TABLE", -1, -1);
94  cpl_recipeconfig_set_input(recipeconfig, "ARC", "LINE_CATALOG", 1, 1);
95  cpl_recipeconfig_set_output(recipeconfig, "ARC", "LSF_PROFILE");
96  cpl_recipeconfig_set_output(recipeconfig, "ARC", "PIXTABLE_SUBTRACTED");
97  cpl_recipeconfig_set_tag(recipeconfig, "ARC_LSF", -1, -1);
98  cpl_recipeconfig_set_input(recipeconfig, "ARC_LSF", "MASTER_BIAS", 1, 1);
99  cpl_recipeconfig_set_input(recipeconfig, "ARC_LSF", "MASTER_DARK", -1, 1);
100  cpl_recipeconfig_set_input(recipeconfig, "ARC_LSF", "MASTER_FLAT", -1, 1);
101  cpl_recipeconfig_set_input(recipeconfig, "ARC_LSF", "TRACE_TABLE", 1, 1);
102  cpl_recipeconfig_set_input(recipeconfig, "ARC_LSF", "WAVECAL_TABLE", 1, 1);
103  cpl_recipeconfig_set_input(recipeconfig, "ARC_LSF", "BADPIX_TABLE", -1, -1);
104  cpl_recipeconfig_set_input(recipeconfig, "ARC_LSF", "LINE_CATALOG", 1, 1);
105  cpl_recipeconfig_set_output(recipeconfig, "ARC_LSF", "LSF_PROFILE");
106  cpl_recipeconfig_set_output(recipeconfig, "ARC_LSF", "PIXTABLE_SUBTRACTED");
107 
108  return recipeconfig;
109 } /* muse_lsf_new_recipeconfig() */
110 
111 /*----------------------------------------------------------------------------*/
121 /*----------------------------------------------------------------------------*/
122 static cpl_error_code
123 muse_lsf_prepare_header(const char *aFrametag, cpl_propertylist *aHeader)
124 {
125  cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
126  cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
127  if (!strcmp(aFrametag, "LSF_PROFILE")) {
128  muse_processing_prepare_property(aHeader, "ESO QC LSF SLICE[0-9]+ FWHM MEAN",
129  CPL_TYPE_FLOAT,
130  "Mean FWHM of the LSF slice j");
131  muse_processing_prepare_property(aHeader, "ESO QC LSF SLICE[0-9]+ FWHM STDEV",
132  CPL_TYPE_FLOAT,
133  "Standard deviation of the LSF in slice j");
134  muse_processing_prepare_property(aHeader, "ESO QC LSF SLICE[0-9]+ FWHM MIN",
135  CPL_TYPE_FLOAT,
136  "Minimum FWHM of the LSF in slice j");
137  muse_processing_prepare_property(aHeader, "ESO QC LSF SLICE[0-9]+ FWHM MAX",
138  CPL_TYPE_FLOAT,
139  "Maximum FWHM of the LSF in slice j");
140  } else if (!strcmp(aFrametag, "PIXTABLE_SUBTRACTED")) {
141  } else {
142  cpl_msg_warning(__func__, "Frame tag %s is not defined", aFrametag);
143  return CPL_ERROR_ILLEGAL_INPUT;
144  }
145  return CPL_ERROR_NONE;
146 } /* muse_lsf_prepare_header() */
147 
148 /*----------------------------------------------------------------------------*/
157 /*----------------------------------------------------------------------------*/
158 static cpl_frame_level
159 muse_lsf_get_frame_level(const char *aFrametag)
160 {
161  if (!aFrametag) {
162  return CPL_FRAME_LEVEL_NONE;
163  }
164  if (!strcmp(aFrametag, "LSF_PROFILE")) {
165  return CPL_FRAME_LEVEL_FINAL;
166  }
167  if (!strcmp(aFrametag, "PIXTABLE_SUBTRACTED")) {
168  return CPL_FRAME_LEVEL_FINAL;
169  }
170  return CPL_FRAME_LEVEL_NONE;
171 } /* muse_lsf_get_frame_level() */
172 
173 /*----------------------------------------------------------------------------*/
182 /*----------------------------------------------------------------------------*/
183 static muse_frame_mode
184 muse_lsf_get_frame_mode(const char *aFrametag)
185 {
186  if (!aFrametag) {
187  return MUSE_FRAME_MODE_ALL;
188  }
189  if (!strcmp(aFrametag, "LSF_PROFILE")) {
190  return MUSE_FRAME_MODE_MASTER;
191  }
192  if (!strcmp(aFrametag, "PIXTABLE_SUBTRACTED")) {
193  return MUSE_FRAME_MODE_MASTER;
194  }
195  return MUSE_FRAME_MODE_ALL;
196 } /* muse_lsf_get_frame_mode() */
197 
198 /*----------------------------------------------------------------------------*/
208 /*----------------------------------------------------------------------------*/
209 static int
210 muse_lsf_create(cpl_plugin *aPlugin)
211 {
212  /* Check that the plugin is part of a valid recipe */
213  cpl_recipe *recipe;
214  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
215  recipe = (cpl_recipe *)aPlugin;
216  } else {
217  return -1;
218  }
219 
220  /* register the extended processing information (new FITS header creation, *
221  * getting of the frame level for a certain tag) */
223  muse_lsf_new_recipeconfig(),
224  muse_lsf_prepare_header,
225  muse_lsf_get_frame_level,
226  muse_lsf_get_frame_mode);
227 
228  /* XXX initialize timing in messages *
229  * since at least esorex is too stupid to turn it on, we have to do it */
231  cpl_msg_set_time_on();
232  }
233 
234  /* Create the parameter list in the cpl_recipe object */
235  recipe->parameters = cpl_parameterlist_new();
236  /* Fill the parameters list */
237  cpl_parameter *p;
238 
239  /* --nifu: IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel. */
240  p = cpl_parameter_new_range("muse.muse_lsf.nifu",
241  CPL_TYPE_INT,
242  "IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel.",
243  "muse.muse_lsf",
244  (int)0,
245  (int)-1,
246  (int)24);
247  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nifu");
248  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nifu");
249 
250  cpl_parameterlist_append(recipe->parameters, p);
251 
252  /* --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. */
253  p = cpl_parameter_new_value("muse.muse_lsf.overscan",
254  CPL_TYPE_STRING,
255  "If this is \"none\", stop when detecting discrepant overscan levels (see ovscsigma), for \"offset\" it assumes that the mean overscan level represents the real offset in the bias levels of the exposures involved, and adjusts the data accordingly; for \"vpoly\", a polynomial is fit to the vertical overscan and subtracted from the whole quadrant.",
256  "muse.muse_lsf",
257  (const char *)"vpoly");
258  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "overscan");
259  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "overscan");
260 
261  cpl_parameterlist_append(recipe->parameters, p);
262 
263  /* --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"). */
264  p = cpl_parameter_new_value("muse.muse_lsf.ovscreject",
265  CPL_TYPE_STRING,
266  "This influences how values are rejected when computing overscan statistics. Either no rejection at all (\"none\"), rejection using the DCR algorithm (\"dcr\"), or rejection using an iterative constant fit (\"fit\").",
267  "muse.muse_lsf",
268  (const char *)"dcr");
269  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscreject");
270  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscreject");
271 
272  cpl_parameterlist_append(recipe->parameters, p);
273 
274  /* --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". */
275  p = cpl_parameter_new_value("muse.muse_lsf.ovscsigma",
276  CPL_TYPE_DOUBLE,
277  "If the deviation of mean overscan levels between a raw input image and the reference image is higher than |ovscsigma x stdev|, stop the processing. If overscan=\"vpoly\", this is used as sigma rejection level for the iterative polynomial fit (the level comparison is then done afterwards with |100 x stdev| to guard against incompatible settings). Has no effect for overscan=\"offset\".",
278  "muse.muse_lsf",
279  (double)30.);
280  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscsigma");
281  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscsigma");
282 
283  cpl_parameterlist_append(recipe->parameters, p);
284 
285  /* --ovscignore: The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when computing statistics or fits. */
286  p = cpl_parameter_new_value("muse.muse_lsf.ovscignore",
287  CPL_TYPE_INT,
288  "The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when computing statistics or fits.",
289  "muse.muse_lsf",
290  (int)3);
291  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscignore");
292  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscignore");
293 
294  cpl_parameterlist_append(recipe->parameters, p);
295 
296  /* --save_subtracted: Save the pixel table after the LSF subtraction. */
297  p = cpl_parameter_new_value("muse.muse_lsf.save_subtracted",
298  CPL_TYPE_BOOL,
299  "Save the pixel table after the LSF subtraction.",
300  "muse.muse_lsf",
301  (int)FALSE);
302  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "save_subtracted");
303  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "save_subtracted");
304 
305  cpl_parameterlist_append(recipe->parameters, p);
306 
307  /* --line_quality: Minimal quality flag in line catalog for selection */
308  p = cpl_parameter_new_value("muse.muse_lsf.line_quality",
309  CPL_TYPE_INT,
310  "Minimal quality flag in line catalog for selection",
311  "muse.muse_lsf",
312  (int)3);
313  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "line_quality");
314  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "line_quality");
315 
316  cpl_parameterlist_append(recipe->parameters, p);
317 
318  /* --lsf_range: Wavelength window (half size) around each line to estimate LSF */
319  p = cpl_parameter_new_value("muse.muse_lsf.lsf_range",
320  CPL_TYPE_DOUBLE,
321  "Wavelength window (half size) around each line to estimate LSF",
322  "muse.muse_lsf",
323  (double)7.5);
324  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lsf_range");
325  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lsf_range");
326 
327  cpl_parameterlist_append(recipe->parameters, p);
328 
329  /* --lsf_size: Image size in LSF direction */
330  p = cpl_parameter_new_value("muse.muse_lsf.lsf_size",
331  CPL_TYPE_INT,
332  "Image size in LSF direction",
333  "muse.muse_lsf",
334  (int)150);
335  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lsf_size");
336  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lsf_size");
337 
338  cpl_parameterlist_append(recipe->parameters, p);
339 
340  /* --lambda_size: Image size in line wavelength direction */
341  p = cpl_parameter_new_value("muse.muse_lsf.lambda_size",
342  CPL_TYPE_INT,
343  "Image size in line wavelength direction",
344  "muse.muse_lsf",
345  (int)30);
346  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lambda_size");
347  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lambda_size");
348 
349  cpl_parameterlist_append(recipe->parameters, p);
350 
351  /* --lsf_regression_window: Size of the regression window in LSF direction */
352  p = cpl_parameter_new_value("muse.muse_lsf.lsf_regression_window",
353  CPL_TYPE_DOUBLE,
354  "Size of the regression window in LSF direction",
355  "muse.muse_lsf",
356  (double)0.7);
357  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lsf_regression_window");
358  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lsf_regression_window");
359 
360  cpl_parameterlist_append(recipe->parameters, p);
361 
362  /* --merge: Merge output products from different IFUs into a common file. */
363  p = cpl_parameter_new_value("muse.muse_lsf.merge",
364  CPL_TYPE_BOOL,
365  "Merge output products from different IFUs into a common file.",
366  "muse.muse_lsf",
367  (int)FALSE);
368  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "merge");
369  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "merge");
370 
371  cpl_parameterlist_append(recipe->parameters, p);
372 
373  /* --combine: Type of lampwise image combination to use. */
374  p = cpl_parameter_new_enum("muse.muse_lsf.combine",
375  CPL_TYPE_STRING,
376  "Type of lampwise image combination to use.",
377  "muse.muse_lsf",
378  (const char *)"sigclip",
379  4,
380  (const char *)"average",
381  (const char *)"median",
382  (const char *)"minmax",
383  (const char *)"sigclip");
384  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "combine");
385  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "combine");
386 
387  cpl_parameterlist_append(recipe->parameters, p);
388 
389  /* --method: LSF generation method. Depending on this value, either an interpolated LSF cube is created, or a table with the parameters of a hermitean gaussian. */
390  p = cpl_parameter_new_enum("muse.muse_lsf.method",
391  CPL_TYPE_STRING,
392  "LSF generation method. Depending on this value, either an interpolated LSF cube is created, or a table with the parameters of a hermitean gaussian.",
393  "muse.muse_lsf",
394  (const char *)"interpolate",
395  2,
396  (const char *)"interpolate",
397  (const char *)"hermit");
398  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "method");
399  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "method");
400 
401  cpl_parameterlist_append(recipe->parameters, p);
402 
403  return 0;
404 } /* muse_lsf_create() */
405 
406 /*----------------------------------------------------------------------------*/
417 /*----------------------------------------------------------------------------*/
418 static int
419 muse_lsf_params_fill(muse_lsf_params_t *aParams, cpl_parameterlist *aParameters)
420 {
421  cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
422  cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
423  cpl_parameter *p;
424 
425  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.nifu");
426  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
427  aParams->nifu = cpl_parameter_get_int(p);
428 
429  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.overscan");
430  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
431  aParams->overscan = cpl_parameter_get_string(p);
432 
433  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.ovscreject");
434  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
435  aParams->ovscreject = cpl_parameter_get_string(p);
436 
437  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.ovscsigma");
438  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
439  aParams->ovscsigma = cpl_parameter_get_double(p);
440 
441  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.ovscignore");
442  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
443  aParams->ovscignore = cpl_parameter_get_int(p);
444 
445  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.save_subtracted");
446  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
447  aParams->save_subtracted = cpl_parameter_get_bool(p);
448 
449  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.line_quality");
450  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
451  aParams->line_quality = cpl_parameter_get_int(p);
452 
453  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.lsf_range");
454  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
455  aParams->lsf_range = cpl_parameter_get_double(p);
456 
457  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.lsf_size");
458  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
459  aParams->lsf_size = cpl_parameter_get_int(p);
460 
461  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.lambda_size");
462  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
463  aParams->lambda_size = cpl_parameter_get_int(p);
464 
465  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.lsf_regression_window");
466  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
467  aParams->lsf_regression_window = cpl_parameter_get_double(p);
468 
469  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.merge");
470  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
471  aParams->merge = cpl_parameter_get_bool(p);
472 
473  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.combine");
474  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
475  aParams->combine_s = cpl_parameter_get_string(p);
476  aParams->combine =
477  (!strcasecmp(aParams->combine_s, "average")) ? MUSE_LSF_PARAM_COMBINE_AVERAGE :
478  (!strcasecmp(aParams->combine_s, "median")) ? MUSE_LSF_PARAM_COMBINE_MEDIAN :
479  (!strcasecmp(aParams->combine_s, "minmax")) ? MUSE_LSF_PARAM_COMBINE_MINMAX :
480  (!strcasecmp(aParams->combine_s, "sigclip")) ? MUSE_LSF_PARAM_COMBINE_SIGCLIP :
481  MUSE_LSF_PARAM_COMBINE_INVALID_VALUE;
482  cpl_ensure_code(aParams->combine != MUSE_LSF_PARAM_COMBINE_INVALID_VALUE,
483  CPL_ERROR_ILLEGAL_INPUT);
484 
485  p = cpl_parameterlist_find(aParameters, "muse.muse_lsf.method");
486  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
487  aParams->method_s = cpl_parameter_get_string(p);
488  aParams->method =
489  (!strcasecmp(aParams->method_s, "interpolate")) ? MUSE_LSF_PARAM_METHOD_INTERPOLATE :
490  (!strcasecmp(aParams->method_s, "hermit")) ? MUSE_LSF_PARAM_METHOD_HERMIT :
491  MUSE_LSF_PARAM_METHOD_INVALID_VALUE;
492  cpl_ensure_code(aParams->method != MUSE_LSF_PARAM_METHOD_INVALID_VALUE,
493  CPL_ERROR_ILLEGAL_INPUT);
494 
495  return 0;
496 } /* muse_lsf_params_fill() */
497 
498 /*----------------------------------------------------------------------------*/
505 /*----------------------------------------------------------------------------*/
506 static int
507 muse_lsf_exec(cpl_plugin *aPlugin)
508 {
509  if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
510  return -1;
511  }
513  cpl_recipe *recipe = (cpl_recipe *)aPlugin;
514  cpl_msg_set_threadid_on();
515 
516  cpl_frameset *usedframes = cpl_frameset_new(),
517  *outframes = cpl_frameset_new();
518  muse_lsf_params_t params;
519  muse_lsf_params_fill(&params, recipe->parameters);
520 
521  cpl_errorstate prestate = cpl_errorstate_get();
522 
523  if (params.nifu < -1 || params.nifu > kMuseNumIFUs) {
524  cpl_msg_error(__func__, "Please specify a valid IFU number (between 1 and "
525  "%d), 0 (to process all IFUs consecutively), or -1 (to "
526  "process all IFUs in parallel) using --nifu.", kMuseNumIFUs);
527  return -1;
528  } /* if invalid params.nifu */
529 
530  cpl_boolean donotmerge = CPL_FALSE; /* depending on nifu we may not merge */
531  int rc = 0;
532  if (params.nifu > 0) {
533  muse_processing *proc = muse_processing_new("muse_lsf",
534  recipe);
535  rc = muse_lsf_compute(proc, &params);
536  cpl_frameset_join(usedframes, proc->usedframes);
537  cpl_frameset_join(outframes, proc->outframes);
539  donotmerge = CPL_TRUE; /* after processing one IFU, merging cannot work */
540  } else if (params.nifu < 0) { /* parallel processing */
541  int *rcs = cpl_calloc(kMuseNumIFUs, sizeof(int));
542  int nifu;
543  #pragma omp parallel for default(none) \
544  shared(outframes, params, rcs, recipe, usedframes)
545  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
546  muse_processing *proc = muse_processing_new("muse_lsf",
547  recipe);
548  muse_lsf_params_t *pars = cpl_malloc(sizeof(muse_lsf_params_t));
549  memcpy(pars, &params, sizeof(muse_lsf_params_t));
550  pars->nifu = nifu;
551  int *rci = rcs + (nifu - 1);
552  *rci = muse_lsf_compute(proc, pars);
553  if (rci && (int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
554  *rci = 0;
555  }
556  cpl_free(pars);
557  #pragma omp critical(muse_processing_used_frames)
558  cpl_frameset_join(usedframes, proc->usedframes);
559  #pragma omp critical(muse_processing_output_frames)
560  cpl_frameset_join(outframes, proc->outframes);
562  } /* for nifu */
563  /* non-parallel loop to propagate the "worst" return code; *
564  * since we only ever return -1, any non-zero code is propagated */
565  for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
566  if (rcs[nifu-1] != 0) {
567  rc = rcs[nifu-1];
568  } /* if */
569  } /* for nifu */
570  cpl_free(rcs);
571  } else { /* serial processing */
572  for (params.nifu = 1; params.nifu <= kMuseNumIFUs && !rc; params.nifu++) {
573  muse_processing *proc = muse_processing_new("muse_lsf",
574  recipe);
575  rc = muse_lsf_compute(proc, &params);
576  if (rc && (int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
577  rc = 0;
578  }
579  cpl_frameset_join(usedframes, proc->usedframes);
580  cpl_frameset_join(outframes, proc->outframes);
582  } /* for nifu */
583  } /* else */
584  UNUSED_ARGUMENT(donotmerge); /* maybe this is not going to be used below */
585 
586  if (!cpl_errorstate_is_equal(prestate)) {
587  /* dump all errors from this recipe in chronological order */
588  cpl_errorstate_dump(prestate, CPL_FALSE, muse_cplerrorstate_dump_some);
589  /* reset message level to not get the same errors displayed again by esorex */
590  cpl_msg_set_level(CPL_MSG_INFO);
591  }
592  /* clean up duplicates in framesets of used and output frames */
595 
596  /* merge output products from the up to 24 IFUs */
597  if (params.merge && !donotmerge) {
598  muse_utils_frameset_merge_frames(outframes, CPL_TRUE);
599  }
600 
601  /* to get esorex to see our classification (frame groups etc.), *
602  * replace the original frameset with the list of used frames *
603  * before appending product output frames */
604  /* keep the same pointer, so just erase all frames, not delete the frameset */
605  muse_cplframeset_erase_all(recipe->frames);
606  cpl_frameset_join(recipe->frames, usedframes);
607  cpl_frameset_join(recipe->frames, outframes);
608  cpl_frameset_delete(usedframes);
609  cpl_frameset_delete(outframes);
610  return rc;
611 } /* muse_lsf_exec() */
612 
613 /*----------------------------------------------------------------------------*/
620 /*----------------------------------------------------------------------------*/
621 static int
622 muse_lsf_destroy(cpl_plugin *aPlugin)
623 {
624  /* Get the recipe from the plugin */
625  cpl_recipe *recipe;
626  if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
627  recipe = (cpl_recipe *)aPlugin;
628  } else {
629  return -1;
630  }
631 
632  /* Clean up */
633  cpl_parameterlist_delete(recipe->parameters);
635  return 0;
636 } /* muse_lsf_destroy() */
637 
638 /*----------------------------------------------------------------------------*/
648 /*----------------------------------------------------------------------------*/
649 int
650 cpl_plugin_get_info(cpl_pluginlist *aList)
651 {
652  cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
653  cpl_plugin *plugin = &recipe->interface;
654 
655  char *helptext;
657  helptext = cpl_sprintf("%s%s", muse_lsf_help,
658  muse_lsf_help_esorex);
659  } else {
660  helptext = cpl_sprintf("%s", muse_lsf_help);
661  }
662 
663  /* Initialize the CPL plugin stuff for this module */
664  cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
665  CPL_PLUGIN_TYPE_RECIPE,
666  "muse_lsf",
667  "Compute the LSF",
668  helptext,
669  "Ole Streicher",
670  "usd-help@eso.org",
672  muse_lsf_create,
673  muse_lsf_exec,
674  muse_lsf_destroy);
675  cpl_pluginlist_append(aList, plugin);
676  cpl_free(helptext);
677 
678  return 0;
679 } /* cpl_plugin_get_info() */
680 
int method
LSF generation method. Depending on this value, either an interpolated LSF cube is created...
Definition: muse_lsf_z.h:91
int lambda_size
Image size in line wavelength direction.
Definition: muse_lsf_z.h:77
void muse_processing_delete(muse_processing *aProcessing)
Free the muse_processing structure.
double ovscsigma
If the deviation of mean overscan levels between a raw input image and the reference image is higher ...
Definition: muse_lsf_z.h:59
muse_cplframework_type muse_cplframework(void)
Return the CPL framework the recipe is run under.
const char * ovscreject
This influences how values are rejected when computing overscan statistics. Either no rejection at al...
Definition: muse_lsf_z.h:56
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_lsf_z.h:50
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_lsf_z.h:53
int save_subtracted
Save the pixel table after the LSF subtraction.
Definition: muse_lsf_z.h:65
int merge
Merge output products from different IFUs into a common file.
Definition: muse_lsf_z.h:83
int ovscignore
The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when co...
Definition: muse_lsf_z.h:62
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
int lsf_size
Image size in LSF direction.
Definition: muse_lsf_z.h:74
const char * combine_s
Type of lampwise image combination to use. (as string)
Definition: muse_lsf_z.h:88
muse_frame_mode
Structure to hold the parameters of the muse_lsf recipe.
Definition: muse_lsf_z.h:48
cpl_frameset * outframes
int line_quality
Minimal quality flag in line catalog for selection.
Definition: muse_lsf_z.h:68
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 combine
Type of lampwise image combination to use.
Definition: muse_lsf_z.h:86
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.
void muse_processinginfo_register(cpl_recipe *, cpl_recipeconfig *, muse_processing_prepare_header_func *, muse_processing_get_frame_level_func *, muse_processing_get_frame_mode_func *)
Register extended functionalities for MUSE recipes.
const char * method_s
LSF generation method. Depending on this value, either an interpolated LSF cube is created...
Definition: muse_lsf_z.h:93
void muse_processing_recipeinfo(cpl_plugin *)
Output main pipeline configuration, inputs, and parameters.
double lsf_range
Wavelength window (half size) around each line to estimate LSF.
Definition: muse_lsf_z.h:71
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.
double lsf_regression_window
Size of the regression window in LSF direction.
Definition: muse_lsf_z.h:80