UVES Pipeline Reference Manual  5.4.6
uves_parameters.c
1 /* *
2  * This file is part of the ESO UVES Pipeline *
3  * Copyright (C) 2004,2005 European Southern Observatory *
4  * *
5  * This library is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the Free Software *
17  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA *
18  * */
19 
20 /*
21  * $Author: amodigli $
22  * $Date: 2010-12-16 16:57:40 $
23  * $Revision: 1.68 $
24  * $Name: not supported by cvs2svn $
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31 
32 /*----------------------------------------------------------------------------*/
40 /*----------------------------------------------------------------------------*/
41 
42 /*-----------------------------------------------------------------------------
43  Includes
44  -----------------------------------------------------------------------------*/
45 
46 #include <uves.h>
47 #include <uves_parameters.h>
48 #include <uves_dump.h>
49 #include <uves_backsub.h>
50 #include <uves_extract.h>
51 #include <uves_rebin.h>
52 #include <uves_mdark_impl.h>
53 #include <uves_corrbadpix.h>
54 #include <uves_reduce.h>
55 #include <uves_utils_wrappers.h>
56 #include <uves_error.h>
57 #include <uves_msg.h>
58 
59 #include <cpl.h>
60 #include <string.h>
61 /*-----------------------------------------------------------------------------
62  Functions prototypes
63  -----------------------------------------------------------------------------*/
64 static int propagate(const char *substep_id, const cpl_parameterlist *sub_parameters,
65  cpl_parameterlist *parent_parameters,
66  const char *parent_id, const char *context);
67 static cpl_parameter *
68 create_parameter_enum_int (const char *name, cpl_type type,
69  const char *description, const char *context,
70  int default_value, int size, int *values);
71 static cpl_parameter *
72 create_parameter_enum_double(const char *name, cpl_type type, const char *description,
73  const char *context, double default_value,
74  int size, double *values);
75 static cpl_parameter *
76 create_parameter_enum_string(const char *name, cpl_type type, const char *description,
77  const char *context, const char *default_value,
78  int size, const char **values);
79 /*-----------------------------------------------------------------------------
80  Defines
81  -----------------------------------------------------------------------------*/
82 #define FAIL(return_code, error_code, ...) do { \
83  cpl_msg_error(__func__, __VA_ARGS__); \
84  if (cpl_error_get_code() == CPL_ERROR_NONE) { \
85  cpl_error_set(__func__, error_code); \
86  } \
87  return return_code; \
88  } while(false)
89 
92 /*-----------------------------------------------------------------------------
93  Implementation
94  -----------------------------------------------------------------------------*/
95 
96 /*---------------------------------------------------------------------------*/
106 /*---------------------------------------------------------------------------*/
107 
108 cpl_error_code
109 uves_corr_traps_define_parameters(cpl_parameterlist * parameters,
110  const char *recipe_id)
111 {
112 
113  //const char *context = "clean";
114  const char *name = "";
115  char full_name[256];
116  cpl_parameter *p;
117 
118 
119  //
120  name = "clean_traps";
121  sprintf(full_name,"%s.%s",recipe_id,name);
122  /* PIPE-5514: decided to always have clean-trap false */
123  if((strcmp(recipe_id,"uves_obs_scired") == 0) ||
124  (strcmp(recipe_id,"uves_obs_spatred") == 0) ||
125  (strcmp(recipe_id,"uves_cal_mbias") == 0) ||
126  (strcmp(recipe_id,"uves_cal_mkmaster") == 0) ||
127  (strcmp(recipe_id,"uves_cal_tflat") == 0) ) {
128 
129  uves_parameter_new_value(p, full_name,
130  CPL_TYPE_BOOL,
131  "Clean detector traps. "
132  "If TRUE detector traps are interpolated."
133  "The bad pixels are replaced by the average of the"
134  "nearest good pixels in the same column, or simply marked "
135  "as bad. The positions of bad pixels are hard-coded "
136  "(as function of UVES chip).",
137  recipe_id,
138  CPL_FALSE);
139 
140 
141  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
142  cpl_parameterlist_append(parameters, p);
143 
144  } else {
145 
146  uves_msg("Creation of trap not supported for recipe: '%s'",
147  recipe_id);
148 
149  }
150 
151  if (cpl_error_get_code() != CPL_ERROR_NONE)
152  {
153 
154  cpl_msg_error(__func__,
155  "Creation of trap column parameters failed: '%s'",
156  cpl_error_get_where());
157  }
158 
159 
160  return cpl_error_get_code();
161 
162 
163 }
164 
165 
166 
167 /*----------------------------------------------------------------------------*/
176 /*----------------------------------------------------------------------------*/
177 
178 cpl_error_code
179 uves_master_stack_define_parameters(cpl_parameterlist *parlist, const char *recipe_id)
180 {
181 
182  const char *name = "";
183  char full_name[256];
184 
185  cpl_parameter *p;
186 
187  {
188  name = "stack_method";
189  sprintf(full_name,"%s.%s",recipe_id,name);
190  uves_parameter_new_enum(p, full_name,
191  CPL_TYPE_STRING,
192  "Method used to build master frame ",
193  recipe_id,
194  "median",2,"median","mean");
195  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
196  cpl_parameterlist_append(parlist, p);
197 
198  }
199 
200  {
201  name = "klow";
202  sprintf(full_name,"%s.%s",recipe_id,name);
203  uves_parameter_new_range(p, full_name,
204  CPL_TYPE_DOUBLE,
205  "Kappa used to clip low level values, when method is set to 'mean' ",
206  recipe_id,
207  5.,0.,100.);
208  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
209  cpl_parameterlist_append(parlist, p);
210 
211  }
212 
213  {
214  name = "khigh";
215  sprintf(full_name,"%s.%s",recipe_id,name);
216  uves_parameter_new_range(p, full_name,
217  CPL_TYPE_DOUBLE,
218  "Kappa used to clip high level values, when method is set to 'mean' ",
219  recipe_id,
220  5.,0.,100.);
221  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
222  cpl_parameterlist_append(parlist, p);
223 
224  }
225 
226 
227 
228  {
229  name = "niter";
230  sprintf(full_name,"%s.%s",recipe_id,name);
231 
232  uves_parameter_new_range(p, full_name,
233  CPL_TYPE_INT,
234  "Number of kappa sigma iterations, when method is set to 'mean' ",
235  recipe_id,
236  5,0,100);
237  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
238  cpl_parameterlist_append(parlist, p);
239 
240  }
241 
242  if (cpl_error_get_code() != CPL_ERROR_NONE)
243  {
244  cpl_msg_error(__func__, "Creation of kappa sigma parameters failed: '%s'",
245  cpl_error_get_where());
246  }
247 
248  return cpl_error_get_code();
249 }
250 
251 
252 
253 /*----------------------------------------------------------------------------*/
262 /*----------------------------------------------------------------------------*/
263 
264 cpl_error_code
265 uves_master_flat_define_parameters(cpl_parameterlist *parlist, const char *recipe_id)
266 {
267 
268  const char *name = "";
269  char full_name[256];
270 
271  cpl_parameter *p;
272 
273  {
274  name = "norm_method";
275  sprintf(full_name,"%s.%s",recipe_id,name);
276  uves_msg("recipe id %s",recipe_id);
277  uves_parameter_new_enum(p, full_name,
278  CPL_TYPE_STRING,
279  "Method used to build master frame ",
280  recipe_id,
281  (strstr(recipe_id,"flames") !=NULL) ? "exptime" : "explevel",
282  2,"exptime","explevel");
283  }
284  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
285  cpl_parameterlist_append(parlist, p);
286 
287 
288 
289  if (cpl_error_get_code() != CPL_ERROR_NONE)
290  {
291  cpl_msg_error(__func__, "Creation of master flat parameters failed: '%s'",
292  cpl_error_get_where());
293  }
294 
295  return cpl_error_get_code();
296 }
297 
298 
299 
300 /*----------------------------------------------------------------------------*/
309 /*----------------------------------------------------------------------------*/
310 cpl_error_code
311 uves_define_global_parameters(cpl_parameterlist *parlist)
312 {
313  const char *context = "uves";
314  const char *name = "";
315  char *full_name = NULL;
316  cpl_parameter *p;
317 
318  {
319  name = "debug";
320  full_name = uves_sprintf("%s.%s", context, name);
321  uves_parameter_new_value(p, full_name,
322  CPL_TYPE_BOOL,
323  "Whether or not to save intermediate "
324  "results to local directory",
325  context,
326  false);
327  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
328  cpl_parameterlist_append(parlist, p);
329  cpl_free(full_name);
330  }
331 
332 
333  {
334  name = "plotter";
335  full_name = uves_sprintf("%s.%s", context, name);
336  uves_parameter_new_value(
337  p, full_name,
338  CPL_TYPE_STRING,
339  "Any plots produced by the recipe "
340  "are redirected to the command specified "
341  "by this parameter. The plotting command "
342  "must contain the substring 'gnuplot' and "
343  "must be able to parse gnuplot syntax on its "
344  "standard input. "
345  "Valid examples of such a command may include "
346  "'gnuplot -persist' and 'cat > mygnuplot$$.gp'. "
347  "A finer control of the plotting options can "
348  "be obtained by writing an "
349  "executable script, e.g. my_gnuplot.pl, that "
350  "executes gnuplot after setting the desired gnuplot "
351  "options (e.g. set terminal pslatex color). "
352  "To turn off plotting, set this parameter to 'no'",
353  context,
354  "no");
355 
356  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
357  cpl_parameterlist_append(parlist, p);
358  cpl_free(full_name);
359  }
360 
361 
362 
363  {
364  name = "process_chip";
365  full_name = uves_sprintf("%s.%s", context, name);
366  uves_parameter_new_enum(p, full_name,
367  CPL_TYPE_STRING,
368  "For RED arm data process the "
369  "redl, redu, or both chip(s)",
370  context,
371  "both",5,"both","redl","redu","REDL","REDU");
372  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
373  cpl_parameterlist_append(parlist, p);
374  cpl_free(full_name);
375  }
376 
377  if (0)
378  /* The meaning of this parameter often escapes the developers,
379  so let's not expose it to the users */
380  {
381  name = "msginfolevel";
382  full_name = uves_sprintf("%s.%s", context, name);
383  uves_parameter_new_range(p, full_name,
384  CPL_TYPE_INT,
385  "This parameter controls the subdivision "
386  "of the 'info' message level (set e.g. with "
387  "esorex' --msg-level). The higher the value "
388  "of this parameter, the more messages are "
389  "printed at the info level. For minimum "
390  "output, set to zero. Increase the level "
391  "(to 1, 2, 3, ...) for more output. The "
392  "value -1 is a special value meaning maximum "
393  "output",
394  context,
395  -1, /* Default */
396  -1, INT_MAX); /* Range */
397  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
398  cpl_parameterlist_append(parlist, p);
399  cpl_free(full_name);
400  }
401 
402  if (cpl_error_get_code() != CPL_ERROR_NONE)
403  {
404  cpl_msg_error(__func__, "Creation of global parameters failed: '%s'",
405  cpl_error_get_where());
406  }
407 
408  return cpl_error_get_code();
409 }
410 /*----------------------------------------------------------------------------*/
419 /*----------------------------------------------------------------------------*/
420 cpl_error_code
421 uves_define_extract_for_response_chain_parameters(cpl_parameterlist *parameters)
422 {
423 
424  const char *name = "";
425  char *full_name = NULL;
426  //char *context = NULL;
427  cpl_parameter *p = NULL;
428 /*
429  context = uves_sprintf("%s.%s.%s", make_str(UVES_REDCHAIN_ID), make_str(UVES_RESPONSE_ID), name);
430 */
431  {
432  name = "uves_cal_response.reduce.extract.method";
433  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
434 
435  uves_parameter_new_enum(p, full_name,
436  CPL_TYPE_STRING,
437  "Extraction method. (2d/optimal not supported by uves_cal_wavecal, weighted supported only by uves_cal_wavecal, 2d not supported by uves_cal_response)",
438  UVES_EXTRACT_ID,
439  "optimal",
440  5,
441  "average",
442  "linear",
443  "2d",
444  "weighted",
445  "optimal");
446 
447  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
448  cpl_parameterlist_append(parameters, p);
449  cpl_free(full_name);
450  }
451 
452  {
453  name = "uves_cal_response.reduce.extract.kappa";
454  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
455 
456  uves_parameter_new_range(p, full_name,
457  CPL_TYPE_DOUBLE,
458  "In optimal extraction mode, this is the "
459  "threshold for bad (i.e. hot/cold) "
460  "pixel rejection. If a pixel deviates more than "
461  "kappa*sigma (where sigma is "
462  "the uncertainty of the pixel flux) from "
463  "the inferred spatial profile, its "
464  "weight is set to zero. Range: [-1,100]. If this parameter "
465  "is negative, no rejection is performed.",
466  UVES_EXTRACT_ID,
467  10.0,-1.,100.);
468 
469  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
470  cpl_parameterlist_append(parameters, p);
471  cpl_free(full_name);
472  }
473 
474  {
475  name = "uves_cal_response.reduce.extract.chunk";
476  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
477 
478  uves_parameter_new_range(p, full_name,
479  CPL_TYPE_INT,
480  "In optimal extraction mode, the chunk size (in pixels) "
481  "used for fitting the analytical profile (a fit of the "
482  "analytical profile to single bins would suffer from "
483  "low statistics).",
484  UVES_EXTRACT_ID,
485  32,
486  1, INT_MAX);
487 
488  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
489  cpl_parameterlist_append(parameters, p);
490  cpl_free(full_name);
491  }
492 
493  {
494  name = "uves_cal_response.reduce.extract.profile";
495  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
496 
497  uves_parameter_new_enum(p, full_name,
498  CPL_TYPE_STRING,
499  "In optimal extraction mode, the kind of profile to use. "
500  "'gauss' gives a Gaussian profile, 'moffat' gives "
501  "a Moffat profile with beta=4 and a possible linear sky "
502  "contribution. 'virtual' uses "
503  "a virtual resampling algorithm (i.e. measures and "
504  "uses the actual object profile). "
505  "'constant' assumes a constant spatial profile and "
506  "allows optimal extraction of wavelength "
507  "calibration frames. 'auto' will automatically "
508  "select the best method based on the estimated S/N of the "
509  "object. For low S/N, 'moffat' or 'gauss' are "
510  "recommended (for robustness). For high S/N, 'virtual' is "
511  "recommended (for accuracy). In the case of virtual resampling, "
512  "a precise determination of the order positions is required; "
513  "therefore the order-definition is repeated "
514  "using the (assumed non-low S/N) science frame",
515  UVES_EXTRACT_ID,
516  "auto",
517  5,
518  "constant",
519  "gauss",
520  "moffat",
521  "virtual",
522  "auto");
523 
524  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
525  cpl_parameterlist_append(parameters, p);
526  cpl_free(full_name);
527  }
528 
529  {
530  name = "uves_cal_response.reduce.extract.skymethod";
531  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
532 
533  uves_parameter_new_enum(p, full_name,
534  CPL_TYPE_STRING,
535  "In optimal extraction mode, the sky subtraction method "
536  "to use. 'median' estimates the sky as the median of pixels "
537  "along the slit (ignoring pixels close to the object), whereas "
538  "'optimal' does a chi square minimization along the slit "
539  "to obtain the best combined object and sky levels. The optimal "
540  "method gives the most accurate sky determination but is also "
541  "a bit slower than the median method",
542  UVES_EXTRACT_ID,
543  "optimal",
544  2,
545  "median",
546  "optimal");
547 
548  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
549  cpl_parameterlist_append(parameters, p);
550  cpl_free(full_name);
551  }
552 
553  {
554  name = "uves_cal_response.reduce.extract.oversample";
555  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
556 
557  uves_parameter_new_range(p, full_name,
558  CPL_TYPE_INT,
559  "The oversampling factor used for the virtual "
560  "resampling algorithm. If negative, the value 5 is "
561  "used for S/N <=200, and the value 10 is used if the estimated "
562  "S/N is > 200",
563  UVES_EXTRACT_ID,
564  -1,
565  -2, INT_MAX);
566 
567  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
568  cpl_parameterlist_append(parameters, p);
569  cpl_free(full_name);
570  }
571 
572  {
573  name = "uves_cal_response.reduce.extract.best";
574  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
575 
576  uves_parameter_new_value(p, full_name,
577  CPL_TYPE_BOOL,
578  "(optimal extraction only) "
579  "If false (fastest), the spectrum is extracted only once. "
580  "If true (best), the spectrum is extracted twice, the "
581  "second time using improved variance estimates "
582  "based on the first iteration. Better variance "
583  "estimates slightly improve the obtained signal to "
584  "noise but at the cost of increased execution time",
585  UVES_EXTRACT_ID,
586  true);
587 
588  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
589  cpl_parameterlist_append(parameters, p);
590  cpl_free(full_name);
591  }
592 
593 
594  if (cpl_error_get_code() != CPL_ERROR_NONE)
595  {
596  cpl_msg_error(__func__, "Creation of extraction parameters failed: '%s'",
597  cpl_error_get_where());
598  }
599  return cpl_error_get_code();
600 
601 }
602 
603 /*----------------------------------------------------------------------------*/
612 /*----------------------------------------------------------------------------*/
613 cpl_error_code
614 uves_define_rebin_for_response_chain_parameters(cpl_parameterlist *parameters)
615 {
616 
617 
618 
619  const char *name = "";
620  char *full_name = NULL;
621  cpl_parameter *p = NULL;
622 
623 
624  {
625  name = "uves_cal_response.reduce.rebin.wavestep";
626  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID),"", name);
627 
628  uves_parameter_new_range(p, full_name,
629  CPL_TYPE_DOUBLE,
630  "The bin size (in w.l.u.) in wavelength space. "
631  "If negative, a step size of "
632  "2/3 * ( average pixel size ) is used.",
633  UVES_REBIN_ID,
634  -1.0,-1.0,DBL_MAX);
635  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
636  cpl_parameterlist_append(parameters, p);
637  cpl_free(full_name);
638 
639  name = "uves_cal_response.reduce.rebin.scale";
640  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID),"", name);
641  uves_parameter_new_value(p, full_name,
642  CPL_TYPE_BOOL,
643  "Whether or not to multiply by the factor "
644  "dx/dlambda (pixels per wavelength) "
645  "during the rebinning. This option is disabled "
646  "as default in concordance with the "
647  "method used in the MIDAS pipeline. This "
648  "option should be set to true "
649  "to convert the observed flux (in pixel-space) "
650  "to a flux per wavelength (in "
651  "wavelength-space).",
652  UVES_REBIN_ID,
653  false);
654  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
655  cpl_parameterlist_append(parameters, p);
656  cpl_free(full_name);
657  }
658 
659  if (cpl_error_get_code() != CPL_ERROR_NONE)
660  {
661  cpl_msg_error(__func__, "Creation of background parameters failed: '%s'",
662  cpl_error_get_where());
663  }
664 
665 
666  return cpl_error_get_code();
667 
668 }
669 
670 
671 /*----------------------------------------------------------------------------*/
680 /*----------------------------------------------------------------------------*/
681 cpl_error_code
682 uves_define_reduce_for_response_chain_parameters(cpl_parameterlist *parameters)
683 {
684 
685  const char *name = NULL;
686  char *full_name = NULL;
687  cpl_parameter *p;
688 
689 
690  /******************
691  * Slit geometry *
692  ******************/
693  if (cpl_error_get_code() == CPL_ERROR_NONE)
694  {
695  name = "uves_cal_response.reduce.slitlength";
696  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID),"", name);
697 
698  uves_parameter_new_range(p, full_name,
699  CPL_TYPE_DOUBLE,
700  "Extraction slit length (in pixels). "
701  "If negative, the value "
702  "inferred from the raw frame header is used",
703  UVES_REDUCE_ID,
704  -1.0,
705  -2.0, DBL_MAX);
706 
707  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
708  cpl_parameterlist_append(parameters, p);
709  cpl_free(full_name);
710  }
711 
712  if (cpl_error_get_code() == CPL_ERROR_NONE)
713  {
714  name = "uves_cal_response.reduce.skysub";
715  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID),"", name);
716 
717  uves_parameter_new_value(p, full_name,
718  CPL_TYPE_BOOL,
719  "Do sky-subtraction (only applicable to linear "
720  "and average extractions)?",
721  UVES_REDUCE_ID,
722  true);
723 
724  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
725  cpl_parameterlist_append(parameters, p);
726  cpl_free(full_name);
727  }
728 
729  if (cpl_error_get_code() == CPL_ERROR_NONE)
730  {
731  name = "uves_cal_response.reduce.objoffset";
732  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID),"", name);
733 
734  uves_parameter_new_value(p, full_name,
735  CPL_TYPE_DOUBLE,
736  "Offset (in pixels) of extraction slit "
737  "with respect to center of order. "
738  "This parameter applies to linear/average/"
739  "optimal extraction. "
740  "For linear/average extraction, if the related "
741  "parameter objslit is negative, the offset is "
742  "automatically determined by measuring the "
743  "actual object position. ",
744  UVES_REDUCE_ID,
745  0.0);
746 
747  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
748  cpl_parameterlist_append(parameters, p);
749  cpl_free(full_name);
750  }
751 
752  if (cpl_error_get_code() == CPL_ERROR_NONE)
753  {
754  name = "uves_cal_response.reduce.objslit";
755  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID),"", name);
756 
757  uves_parameter_new_range(p, full_name,
758  CPL_TYPE_DOUBLE,
759  "Object window size (in pixels). This must "
760  "be less than the total slit length. If "
761  "negative, the default value (half of full "
762  "slit length) is used. The upper and lower "
763  "sky windows are defined as the part of the "
764  "full slit (if any) outside the object "
765  "window. The center of the object window "
766  "is determined by the offset parameter. "
767  "This parameter does not apply to optimal "
768  "extraction.",
769  UVES_REDUCE_ID,
770  -1.0,
771  -2.0, DBL_MAX);
772 
773  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
774  cpl_parameterlist_append(parameters, p);
775  cpl_free(full_name);
776  }
777 
778  if (cpl_error_get_code() == CPL_ERROR_NONE)
779  {
780  name = "uves_cal_response.reduce.tiltcorr";
781  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID),"", name);
782 
783  uves_parameter_new_value(p, full_name,
784  CPL_TYPE_BOOL,
785  "If enabled (recommended), the provided "
786  "dispersion solutions "
787  "obtained at different slit positions are "
788  "interpolated linearly at the actually "
789  "measured position of the object/sky. "
790  "Line tilt correction is currently not supported "
791  "for 2d extraction, in which case the "
792  "dispersion solution obtained at the middle of "
793  "the slit is always used.",
794  UVES_REDUCE_ID,
795  true);
796 
797  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
798  cpl_parameterlist_append(parameters, p);
799  cpl_free(full_name);
800  }
801 
802 
803 
804  /*****************
805  * Flatfielding *
806  *****************/
807 
808  if (cpl_error_get_code() == CPL_ERROR_NONE)
809  {
810  name = "uves_cal_response.reduce.ffmethod";
811  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID),"", name);
812 
813  uves_parameter_new_enum(p, full_name,
814  CPL_TYPE_STRING,
815  "Flat-fielding method. If set to 'pixel', "
816  "flat-fielding is done in pixel-pixel space "
817  "(before extraction); if set to 'extract', "
818  "flat-fielding is performed in pixel-order "
819  "space (i.e. after extraction). If set to "
820  "'no', no flat-field correction is done",
821  UVES_REDUCE_ID,
822  "extract", /* 'Pixel' method is usually preferred,
823  but do like UVES/MIDAS */
824  3,
825  "pixel", "extract", "no");
826 
827  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
828  cpl_parameterlist_append(parameters, p);
829  cpl_free(full_name);
830  }
831 
832  /*****************
833  * Blaze corr. *
834  *****************/
835 
836  if (cpl_error_get_code() == CPL_ERROR_NONE)
837  {
838 
839 /*
840  name = "uves_cal_response.reduce.blazecorr";
841  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID),"", name);
842 
843  uves_parameter_new_value(p, full_name,
844  CPL_TYPE_BOOL,
845  "(highly experimental, recommended=false) "
846  "Apply a correction for the different shapes "
847  "of flat-field and science blaze functions? "
848  "For this to be possible, flat-fielding method "
849  "must be different from 'no'.",
850  UVES_REDUCE_ID,
851  false);
852 
853  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
854  cpl_parameterlist_append(parameters, p);
855  cpl_free(full_name);
856 */
857  }
858 
859 
860 
861  /*****************
862  * Merging *
863  *****************/
864  if (cpl_error_get_code() == CPL_ERROR_NONE)
865  {
866  name = "uves_cal_response.reduce.merge";
867  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID),"", name);
868 
869  uves_parameter_new_enum(p, full_name,
870  CPL_TYPE_STRING,
871  "Order merging method. If 'optimal', the "
872  "flux in the overlapping region is set "
873  "to the (optimally computed, using the "
874  "uncertainties) average of single order "
875  "spectra. If 'sum', the flux in the "
876  "overlapping region is computed as the "
877  "sum of the single order spectra. If 'noappend' "
878  "the spectrum is simply rebinned but not merged."
879  "If flat-fielding is done, method 'optimal' "
880  "is recommended, otherwise 'sum'.",
881  UVES_REDUCE_ID,
882  "optimal",
883  3,
884  "optimal", "sum", "noappend");
885 
886  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
887  cpl_parameterlist_append(parameters, p);
888  cpl_free(full_name);
889 
890 
891  name = "uves_cal_response.reduce.merge_delt1";
892  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID),"", name);
893 
894  uves_parameter_new_range(p, full_name,
895  CPL_TYPE_DOUBLE,
896  "Order merging left hand (short wavelength) "
897  "cut. To reduce the amount of order "
898  "overlapping regions we allow to cut short and "
899  "long wavelength ranges. "
900  "This may reduce the ripple possibly "
901  "introduced by the order merging. "
902  "Suggested values are: "
903  "10 (W<=390), 12 (390<W<=437, 520<W<=564), "
904  "14 (437<W<=520, 564<W) ",
905  UVES_REDUCE_ID,
906  0.,0.,20.);
907 
908  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
909  cpl_parameterlist_append(parameters, p);
910  cpl_free(full_name);
911 
912 
913  name = "uves_cal_response.reduce.merge_delt2";
914  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID),"", name);
915 
916  uves_parameter_new_range(p, full_name,
917  CPL_TYPE_DOUBLE,
918  "Order merging right hand (long wavelength) "
919  "cut. To reduce the amount of order "
920  "overlapping regions we allow to cut short and "
921  "long wavelength ranges. "
922  "This may reduce the ripple possibly "
923  "introduced by the order merging. "
924  "Suggested values is 4",
925  UVES_REDUCE_ID,
926  0.,0.,20.);
927 
928  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
929  cpl_parameterlist_append(parameters, p);
930  cpl_free(full_name);
931 
932 
933 
934  }
935 
936 
937  if (cpl_error_get_code() != CPL_ERROR_NONE)
938  {
939  cpl_msg_error(__func__, "Creation of background parameters failed: '%s'",
940  cpl_error_get_where());
941  }
942 
943 
944  return cpl_error_get_code();
945 
946 }
947 /*----------------------------------------------------------------------------*/
956 /*----------------------------------------------------------------------------*/
957 cpl_error_code
958 uves_define_background_for_response_chain_parameters(cpl_parameterlist *parameters)
959 {
960 
961 
962  //const char *context = "uves";
963  const char *name = NULL;
964  char *full_name = NULL;
965  cpl_parameter *p;
966 
967 
968 
969  /**************************
970  * Inter-order-background *
971  **************************/
972 
973  name = "uves_cal_response.reduce.backsub.mmethod";
974  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID),"", name);
975 
976  uves_parameter_new_enum(p, full_name,
977  CPL_TYPE_STRING,
978  "Background measuring method. If equal to 'median' "
979  "the background is sampled using the median of a subwindow. "
980  "If 'minimum', the subwindow minimum value is used. "
981  "If 'no', no background subtraction is done.",
982  UVES_BACKSUB_ID,
983  "median", /* Default */
984  3, /* Number of options */
985  "median", "minimum", "no"); /* List of options */
986  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
987  cpl_parameterlist_append(parameters, p);
988  cpl_free(full_name);
989 
990  //
991  name = "uves_cal_response.reduce.backsub.npoints";
992  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
993  uves_parameter_new_range(p, full_name,
994  CPL_TYPE_INT,
995  "This is the number of columns in interorder space "
996  "used to sample the background.",
997  UVES_BACKSUB_ID,
998  82, 0, INT_MAX);
999  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1000  cpl_parameterlist_append(parameters, p);
1001  cpl_free(full_name);
1002 
1003  //
1004  name = "uves_cal_response.reduce.backsub.radiusy";
1005  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
1006  uves_parameter_new_range(p, full_name,
1007  CPL_TYPE_INT,
1008  "The height (in pixels) of the background sampling "
1009  "window is (2*radiusy + 1). "
1010  "This parameter is not corrected for binning.",
1011  UVES_BACKSUB_ID,
1012  2, 0, INT_MAX);
1013  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1014  cpl_parameterlist_append(parameters, p);
1015  cpl_free(full_name);
1016 
1017  //
1018  name = "uves_cal_response.reduce.backsub.sdegree";
1019  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
1020  uves_parameter_new_range(p, full_name,
1021  CPL_TYPE_INT,
1022  "Degree of interpolating splines. Currently "
1023  "only degree = 1 is supported",
1024  UVES_BACKSUB_ID,
1025  1, 0, INT_MAX);
1026  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1027  cpl_parameterlist_append(parameters, p);
1028  cpl_free(full_name);
1029 
1030  //
1031  name = "uves_cal_response.reduce.backsub.smoothx";
1032  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
1033  uves_parameter_new_range(p, full_name,
1034  CPL_TYPE_DOUBLE,
1035  "If spline interpolation is used to measure the background, "
1036  "the x-radius of the post-smoothing window is "
1037  "(smoothx * image_width). Here, 'image_width' is the image "
1038  "width after binning. If negative, the default values are used: "
1039  make_str(BACKSUB_FLAT_SMOOTHX_BLUE) " for blue flat-field frames, "
1040  make_str(BACKSUB_FLAT_SMOOTHX_RED) " for red flat-field frames, "
1041  make_str(BACKSUB_SCI_SMOOTHX_BLUE) " for blue science frames and "
1042  make_str(BACKSUB_SCI_SMOOTHX_RED) " for red science frames.",
1043  UVES_BACKSUB_ID,
1044  -1.0, -DBL_MAX, DBL_MAX);
1045  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1046  cpl_parameterlist_append(parameters, p);
1047  cpl_free(full_name);
1048 
1049  //
1050  name = "uves_cal_response.reduce.backsub.smoothy";
1051  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
1052  uves_parameter_new_range(p, full_name,
1053  CPL_TYPE_DOUBLE,
1054  "If spline interpolation is used to measure the "
1055  "background, the y-radius of the post-smoothing "
1056  "window is (smoothy * image_height). Here, "
1057  "'image_height' is the image height after binning. "
1058  "If negative, the default values are used: "
1059  make_str(BACKSUB_FLAT_SMOOTHY_BLUE) " for blue flat-field frames, "
1060  make_str(BACKSUB_FLAT_SMOOTHY_RED) " for red flat-field frames, "
1061  make_str(BACKSUB_SCI_SMOOTHY_BLUE) " for blue science frames and "
1062  make_str(BACKSUB_SCI_SMOOTHY_RED) " for red science frames.",
1063  UVES_BACKSUB_ID,
1064  -1.0, -DBL_MAX, DBL_MAX);
1065  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1066  cpl_parameterlist_append(parameters, p);
1067  cpl_free(full_name);
1068 
1069 
1070  if (cpl_error_get_code() != CPL_ERROR_NONE)
1071  {
1072  cpl_msg_error(__func__, "Creation of background parameters failed: '%s'",
1073  cpl_error_get_where());
1074  }
1075 
1076  return cpl_error_get_code();
1077 
1078 }
1079 
1080 
1081 
1082 /*----------------------------------------------------------------------------*/
1091 /*----------------------------------------------------------------------------*/
1092 cpl_error_code
1093 uves_define_efficiency_for_response_chain_parameters(cpl_parameterlist *parlist)
1094 {
1095 
1096  char *full_name = NULL;
1097  cpl_parameter* p=NULL;
1098  const char* name = NULL;
1099  const char* value = NULL;
1100 
1101 
1102  /**********************
1103  * Extraction-Merge *
1104  **********************/
1105 
1106 
1107  /* For the efficiency step: Set default extraction method to 'linear',
1108  * flatfield_method to 'no', blazecorrection to 'false' and merge to
1109  * 'sum' (because optimal merging doesn't make sense without flatfielding)
1110  */
1111 
1112  {
1113 
1114  name = "uves_cal_response.efficiency.reduce.extract.method";
1115  value = "linear";
1116 
1117  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
1118  uves_parameter_new_value(p, full_name,
1119  CPL_TYPE_STRING,
1120  "Extraction method."
1121  "<average | linear | weighted | optimal>",
1122  UVES_REDUCE_ID,
1123  value);
1124 
1125  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1126  cpl_parameterlist_append(parlist, p);
1127  cpl_free(full_name);
1128 
1129  name = "uves_cal_response.efficiency.reduce.ffmethod";
1130  value = "no";
1131 
1132  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
1133  uves_parameter_new_value(p, full_name,
1134  CPL_TYPE_STRING,
1135  "Flat-fielding method. If set to 'pixel', flat-fielding "
1136  "is done in pixel-pixel space (before extraction); if "
1137  "set to 'extract', flat-fielding is performed in "
1138  "pixel-order space (i.e. after extraction). If set to "
1139  "'no', no flat-field correction is done. <pixel | "
1140  "extract | no>",
1141  UVES_REDUCE_ID,
1142  value);
1143 
1144  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1145  cpl_parameterlist_append(parlist, p);
1146  cpl_free(full_name);
1147 
1148  name = "uves_cal_response.efficiency.reduce.merge";
1149  value = "sum";
1150 
1151  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
1152  uves_parameter_new_value(p, full_name,
1153  CPL_TYPE_STRING,
1154  "Order merging method. If 'optimal', the flux in the "
1155  "overlapping region is set to the (optimally computed, "
1156  "using the uncertainties) average of single order "
1157  "spectra. If 'sum', the flux in the overlapping region "
1158  "is computed as the sum of the single order spectra."
1159  "If 'noappend' the spectrum is simply rebinned but not "
1160  "merged.If flat-fielding is done, method 'optimal' is "
1161  "recommended, otherwise 'sum'. <optimal | sum | "
1162  "noappend>",
1163  UVES_REDUCE_ID,
1164  value);
1165 
1166  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1167  cpl_parameterlist_append(parlist, p);
1168  cpl_free(full_name);
1169 
1170 
1171 
1172  const char *param = "linear";
1173 
1174  if (uves_set_parameter_default(parlist,
1175  make_str(UVES_REDCHAIN_ID), "uves_cal_response.efficiency.reduce.extract.method",
1176  CPL_TYPE_STRING, &param) != CPL_ERROR_NONE)
1177  {
1178  return -1;
1179  }
1180 
1181 
1182  }
1183 
1184 
1185  {
1186 
1187  name = "uves_cal_response.efficiency.reduce.best";
1188  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
1189 
1190  uves_parameter_new_value(p, full_name,
1191  CPL_TYPE_BOOL,
1192  "(optimal extraction only) "
1193  "If false (fastest), the spectrum is extracted only once. "
1194  "If true (best), the spectrum is extracted twice, the "
1195  "second time using improved variance estimates "
1196  "based on the first iteration. Better variance "
1197  "estimates slightly improve the obtained signal to "
1198  "noise but at the cost of increased execution time",
1199  UVES_EXTRACT_ID,
1200  true);
1201 
1202  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1203  cpl_parameterlist_append(parlist, p);
1204  cpl_free(full_name);
1205  }
1206 
1207 
1208 
1209  /****************
1210  * Efficiency *
1211  ****************/
1212 
1213  {
1214 
1215  name = "uves_cal_response.efficiency.paccuracy";
1216  full_name = uves_sprintf("%s.%s%s", make_str(UVES_REDCHAIN_ID), "", name);
1217 
1218  uves_parameter_new_value(p, full_name,
1219  CPL_TYPE_DOUBLE,
1220  "The pointing accuracy (in arcseconds) used to "
1221  "identify the observed star with a "
1222  "catalogue star. If the angular separation is "
1223  "less than this number, the identification is made.",
1224  UVES_REDUCE_ID,
1225  60.0);
1226 
1227  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1228  cpl_parameterlist_append(parlist, p);
1229  cpl_free(full_name);
1230 
1231  }
1232 
1233 
1234 
1235  if (cpl_error_get_code() != CPL_ERROR_NONE)
1236  {
1237  cpl_msg_error(__func__, "Creation of efficiency parameters failed: '%s'",
1238  cpl_error_get_where());
1239  }
1240 
1241  return cpl_error_get_code();
1242 }
1243 
1244 /*----------------------------------------------------------------------------*/
1253 /*----------------------------------------------------------------------------*/
1254 cpl_error_code
1255 uves_define_efficiency_parameters(cpl_parameterlist *parlist)
1256 {
1257 
1258  char *full_name = NULL;
1259  cpl_parameter* p=NULL;
1260  const char* name = NULL;
1261  const char* value = NULL;
1262 
1263 
1264  /**********************
1265  * Extraction-Merge *
1266  **********************/
1267 
1268 
1269  /* For the efficiency step: Set default extraction method to 'linear',
1270  * flatfield_method to 'no', blazecorrection to 'false' and merge to
1271  * 'sum' (because optimal merging doesn't make sense without flatfielding)
1272  */
1273 
1274  {
1275 
1276 
1277  name = "efficiency.reduce.extract.method";
1278  value = "linear";
1279 
1280  full_name = uves_sprintf("%s.%s", make_str(UVES_RESPONSE_ID), name);
1281  uves_parameter_new_value(p, full_name,
1282  CPL_TYPE_STRING,
1283  "Extraction method. "
1284  "<average | linear | weighted | optimal>",
1285  UVES_REDUCE_ID,
1286  value);
1287 
1288  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1289  cpl_parameterlist_append(parlist, p);
1290  cpl_free(full_name);
1291 
1292 
1293  name = "efficiency.reduce.ffmethod";
1294  value = "no";
1295 
1296  full_name = uves_sprintf("%s.%s", make_str(UVES_RESPONSE_ID), name);
1297  uves_parameter_new_value(p, full_name,
1298  CPL_TYPE_STRING,
1299  "Flat-fielding method. If set to 'pixel', flat-fielding "
1300  "is done in pixel-pixel space (before extraction); if "
1301  "set to 'extract', flat-fielding is performed in "
1302  "pixel-order space (i.e. after extraction). If set to "
1303  "'no', no flat-field correction is done. <pixel | "
1304  "extract | no>",
1305  UVES_REDUCE_ID,
1306  value);
1307 
1308  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1309  cpl_parameterlist_append(parlist, p);
1310  cpl_free(full_name);
1311 
1312  name = "efficiency.reduce.merge";
1313  value = "sum";
1314 
1315  full_name = uves_sprintf("%s.%s", make_str(UVES_RESPONSE_ID), name);
1316  uves_parameter_new_value(p, full_name,
1317  CPL_TYPE_STRING,
1318  "Order merging method. If 'optimal', the flux in the "
1319  "overlapping region is set to the (optimally computed, "
1320  "using the uncertainties) average of single order "
1321  "spectra. If 'sum', the flux in the overlapping region "
1322  "is computed as the sum of the single order spectra."
1323  "If 'noappend' the spectrum is simply rebinned but not "
1324  "merged.If flat-fielding is done, method 'optimal' is "
1325  "recommended, otherwise 'sum'. <optimal | sum | "
1326  "noappend>",
1327  UVES_REDUCE_ID,
1328  value);
1329 
1330  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1331  cpl_parameterlist_append(parlist, p);
1332  cpl_free(full_name);
1333 
1334 
1335 
1336 
1337  const char *param = "linear";
1338 
1339  if (uves_set_parameter_default(parlist,
1340  make_str(UVES_RESPONSE_ID), "efficiency.reduce.extract.method",
1341  CPL_TYPE_STRING, &param) != CPL_ERROR_NONE)
1342  {
1343  return -1;
1344  }
1345 
1346 
1347 /*
1348  if (uves_set_parameter_default(parlist,
1349  make_str(UVES_RESPONSE_ID), "efficiency.reduce.extract.best",
1350  CPL_TYPE_BOOL, &bool_param) != CPL_ERROR_NONE)
1351  {
1352  return -1;
1353  }
1354 */
1355 
1356  }
1357 
1358 
1359  {
1360 
1361  name = "efficiency.reduce.best";
1362  full_name = uves_sprintf("%s.%s", make_str(UVES_RESPONSE_ID), name);
1363 
1364  uves_parameter_new_value(p, full_name,
1365  CPL_TYPE_BOOL,
1366  "(optimal extraction only) "
1367  "If false (fastest), the spectrum is extracted only once. "
1368  "If true (best), the spectrum is extracted twice, the "
1369  "second time using improved variance estimates "
1370  "based on the first iteration. Better variance "
1371  "estimates slightly improve the obtained signal to "
1372  "noise but at the cost of increased execution time",
1373  UVES_EXTRACT_ID,
1374  true);
1375 
1376  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1377  cpl_parameterlist_append(parlist, p);
1378  cpl_free(full_name);
1379  }
1380 
1381 
1382 
1383  /****************
1384  * Efficiency *
1385  ****************/
1386 
1387  {
1388  /* const char *recipe_id = make_str(UVES_RESPONSE_ID); */
1389  const char *subcontext = "efficiency";
1390  const char* name="paccuracy";
1391  char *context=uves_sprintf("%s.%s",make_str(UVES_RESPONSE_ID),subcontext);
1392  // paccuracy
1393 
1394 
1395 /*
1396  uves_par_new_value("paccuracy",
1397  CPL_TYPE_DOUBLE,
1398  "The pointing accuracy (in arcseconds) used to "
1399  "identify the observed star with a "
1400  "catalogue star. If the angular separation is "
1401  "less than this number, the identification is made.",
1402  60.0);
1403 */
1404 
1405 
1406  full_name = uves_sprintf("%s.%s", context,name);
1407  uves_parameter_new_value(p, full_name,
1408  CPL_TYPE_DOUBLE,
1409  "The pointing accuracy (in arcseconds) used to "
1410  "identify the observed star with a "
1411  "catalogue star. If the angular separation is "
1412  "less than this number, the identification is made.",
1413  context,
1414  60.0);
1415 
1416  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
1417  cpl_parameterlist_append(parlist, p);
1418  cpl_free(full_name);
1419  cpl_free(context);
1420 
1421 
1422 
1423 
1424  }
1425 
1426 
1427 
1428  if (cpl_error_get_code() != CPL_ERROR_NONE)
1429  {
1430  cpl_msg_error(__func__, "Creation of efficiency parameters failed: '%s'",
1431  cpl_error_get_where());
1432  }
1433 
1434  return cpl_error_get_code();
1435 }
1436 
1437 
1438 
1439 
1440 /*----------------------------------------------------------------------------*/
1455 /*----------------------------------------------------------------------------*/
1456 
1457 int
1458 uves_exec_recipe(int (*get_info)(cpl_pluginlist *),
1459  const char *recipe_domain,
1460  const cpl_parameterlist *parameters,
1461  cpl_frameset *frames,
1462  const char *caller_id, const char *context)
1463 {
1464  cpl_pluginlist *list = NULL;
1465  cpl_plugin *plugin = NULL;
1466  cpl_recipe *recipe = NULL;
1467 
1468  const char *recipe_id = NULL;
1469  cpl_parameter *p = NULL;
1470  char *parent_name = NULL;
1471  char *sub_domain = NULL;
1472  int status = 0;
1473 
1474  bool must_destroy_plugin = false; /* Indicates if recipe_create()
1475  has been called */
1476 
1477  /* Check input */
1478  assure(recipe_domain != NULL, CPL_ERROR_NULL_INPUT, "Null recipe message domain");
1479  assure(parameters != NULL, CPL_ERROR_NULL_INPUT, "Null parameter list");
1480  assure(frames != NULL, CPL_ERROR_NULL_INPUT, "Null frame set");
1481  assure(caller_id != NULL, CPL_ERROR_NULL_INPUT, "Null caller recipe name");
1482  /* 'context' may be NULL */
1483 
1484  /* Get the sub-recipe plugin */
1485  check( list = cpl_pluginlist_new(),
1486  "Error allocating plugin list");
1487 
1488  /* Get info about recipe */
1489  status = get_info(list);
1490 
1491  assure( status == 0, CPL_ERROR_ILLEGAL_INPUT,
1492  "Could not get info about recipe");
1493 
1494  /* Get default parameter list */
1495  check( plugin = cpl_pluginlist_get_first(list), "Error getting plugin");
1496  assure( plugin != NULL, CPL_ERROR_ILLEGAL_INPUT,
1497  "Plugin '%s' returned empty plugin list", recipe_id);
1498  assure( cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE,
1499  CPL_ERROR_TYPE_MISMATCH, "Plugin is not a recipe");
1500  recipe = (cpl_recipe *) plugin;
1501 
1502  recipe_id = cpl_strdup(cpl_plugin_get_name(plugin));
1503 
1504  /* Call initializer function */
1505  must_destroy_plugin = true;
1506  assure( cpl_plugin_get_init(plugin)(plugin) == 0, CPL_ERROR_ILLEGAL_INPUT,
1507  "Error initializing recipe");
1508  assure( recipe->parameters != NULL, CPL_ERROR_ILLEGAL_INPUT,
1509  "Recipe '%s' returned NULL parameter list", recipe_id);
1510 
1511  /* For each recipe parameter x:
1512  Set to value of C.x (from argument parameter list)
1513 
1514  Parameters in 'uves' context are simply overwritten
1515  */
1516  for (p = cpl_parameterlist_get_first(recipe->parameters);
1517  p != NULL;
1518  p = cpl_parameterlist_get_next(recipe->parameters) )
1519  {
1520  const char *name = cpl_parameter_get_name(p);
1521  const char *subcontext = cpl_parameter_get_context(p);
1522  cpl_type type = cpl_parameter_get_type(p);
1523 
1524  const cpl_parameter *parent;
1525 
1526  if (strcmp(subcontext, "uves") == 0)
1527  {
1528  parent_name = uves_sprintf("%s", name);
1529  }
1530  else
1531  {
1532  if (context != NULL)
1533  {
1534  parent_name = uves_sprintf("%s.%s.%s", caller_id, context, name);
1535  }
1536  else
1537  {
1538  parent_name = uves_sprintf("%s.%s", caller_id, name);
1539  }
1540  }
1541 
1542  /* Const cast, we don't change the parameter list, parent is declared const */
1543  check( parent = cpl_parameterlist_find_const(parameters, parent_name),
1544  "Could not get parameter '%s' from provided parameter list", parent_name);
1545  /* PIPPO
1546  assure( parent != NULL, CPL_ERROR_DATA_NOT_FOUND,
1547  "Missing parameter '%s' needed to define '%s' in context '%s'",
1548  parent_name, name, context);
1549 
1550  assure( cpl_parameter_get_type(parent) == type, CPL_ERROR_TYPE_MISMATCH,
1551  "Parameter '%s' type is %s. Type %s needed for recipe parameter '%s'",
1552  parent_name,
1553  uves_tostring_cpl_type(cpl_parameter_get_type(parent)),
1554  uves_tostring_cpl_type(type),
1555  name);
1556  */
1557  switch (type)
1558  {
1559  int value_int;
1560  bool value_bool;
1561  double value_double;
1562  const char *value_string;
1563 
1564  case CPL_TYPE_BOOL:
1565  check( value_bool = cpl_parameter_get_bool(parent),
1566  "Error reading parameter '%s'", parent_name);
1567 
1568  check( cpl_parameter_set_bool(p, value_bool),
1569  "Error setting parameter '%s'", name);
1570 
1571  uves_msg_debug("Setting parameter '%s' <- '%s' = %s",
1572  name, parent_name, (value_bool) ? "true" : "false");
1573  break;
1574 
1575  case CPL_TYPE_INT:
1576  check( value_int = cpl_parameter_get_int(parent),
1577  "Error reading parameter '%s'", parent_name);
1578 
1579  check( cpl_parameter_set_int(p, value_int),
1580  "Error setting parameter '%s'", name);
1581 
1582  uves_msg_debug("Setting parameter '%s' <- '%s' = %d",
1583  name, parent_name, value_int);
1584  break;
1585 
1586  case CPL_TYPE_DOUBLE:
1587  check( value_double = cpl_parameter_get_double(parent),
1588  "Error reading parameter '%s'", parent_name);
1589 
1590  check( cpl_parameter_set_double(p, value_double),
1591  "Error setting parameter '%s'", name);
1592 
1593  uves_msg_debug("Setting parameter '%s' <- '%s' = %e",
1594  name, parent_name, value_double);
1595  break;
1596 
1597  case CPL_TYPE_STRING:
1598  check( value_string = cpl_parameter_get_string(parent),
1599  "Error reading parameter '%s'", parent_name);
1600 
1601  check( cpl_parameter_set_string(p, value_string),
1602  "Error setting parameter '%s'", name);
1603 
1604  uves_msg_debug("Setting parameter '%s' <- '%s' = '%s'",
1605  name, parent_name, value_string);
1606  break;
1607 
1608  default:
1609  assure(false, CPL_ERROR_UNSUPPORTED_MODE,
1610  "Parameter '%s' has type %s",
1611  name, uves_tostring_cpl_type(type));
1612  } /* switch type */
1613 
1614  cpl_free(parent_name); parent_name = NULL;
1615 
1616  } /* Set each recipe parameter */
1617 
1618  /* Pass frame set without touching */
1619  recipe->frames = frames;
1620 
1621  /*
1622  * Invoke recipe
1623  *
1624  * Remember message domain of caller,
1625  * and number of warnings in caller.
1626  */
1627 
1628  {
1629  const char *domain = uves_msg_get_domain();
1630  int warnings_in_caller = uves_msg_get_warnings();
1631 
1632  sub_domain = uves_sprintf("%s.%s", domain, recipe_domain);
1633  uves_msg_set_domain(sub_domain);
1634 
1635  status = cpl_plugin_get_exec(plugin)(plugin);
1636 
1637  /* Reset state (domain+warnings) */
1638 
1639  uves_msg_set_domain(domain);
1640 
1641  /* Total number of warnings in caller is not
1642  * (previous warnings) + (subrecipe warnings)
1643  */
1644  uves_msg_add_warnings(warnings_in_caller);
1645  }
1646 
1647  /* On recipe failure: The recipe is responsible
1648  * for printing any error messages.
1649  * A failing recipe is an unrecoverable error.
1650  */
1651 
1652  if (cpl_error_get_code() != CPL_ERROR_NONE)
1653  {
1654  /* Reset error stack but keep error code */
1655  cpl_error_code ec = cpl_error_get_code();
1656  uves_error_reset();
1657  assure( false, ec, "Recipe '%s' failed", recipe_id);
1658  }
1659 
1660  assure( status == 0, CPL_ERROR_ILLEGAL_OUTPUT,
1661  "Recipe '%s' failed with exit status %d", recipe_id, status);
1662 
1663  /* Call recipe_destroy */
1664  must_destroy_plugin = false;
1665  assure( cpl_plugin_get_deinit(plugin)(plugin) == 0,
1666  CPL_ERROR_ILLEGAL_OUTPUT,
1667  "Error cleaning up recipe");
1668 
1669  uves_msg("Recipe '%s' succeeded", recipe_id);
1670 
1671  cleanup:
1672  uves_free_string_const(&recipe_id);
1673  cpl_free(parent_name); parent_name = NULL;
1674  cpl_free(sub_domain); sub_domain = NULL;
1675  if (must_destroy_plugin)
1676  {
1677  cpl_plugin_get_deinit(plugin)(plugin);
1678  }
1679 
1680  cpl_pluginlist_delete(list);
1681 
1682  return (cpl_error_get_code() != CPL_ERROR_NONE);
1683 }
1684 
1685 /*----------------------------------------------------------------------------*/
1700 /*----------------------------------------------------------------------------*/
1701 
1702 int
1703 uves_invoke_recipe(const char *recipe_id, const cpl_parameterlist *parameters,
1704  cpl_frameset *frames,
1705  const char *caller_id, const char *context)
1706 {
1707  assure(recipe_id != NULL, CPL_ERROR_NULL_INPUT, "Null recipe name");
1708 
1709  if (strcmp(recipe_id, make_str(UVES_PHYSMOD_ID) ) == 0) return uves_exec_recipe(&uves_physmod_get_info, UVES_PHYSMOD_DOM, parameters, frames, caller_id, context);
1710  else if (strcmp(recipe_id, make_str(UVES_ORDERPOS_ID)) == 0) return uves_exec_recipe(&uves_orderpos_get_info, UVES_ORDERPOS_DOM, parameters, frames, caller_id, context);
1711  else if (strcmp(recipe_id, make_str(UVES_MBIAS_ID) ) == 0) return uves_exec_recipe(&uves_mbias_get_info, UVES_MBIAS_DOM, parameters, frames, caller_id, context);
1712  else if (strcmp(recipe_id, make_str(UVES_MDARK_ID) ) == 0) return uves_exec_recipe(&uves_mdark_get_info, UVES_MDARK_DOM, parameters, frames, caller_id, context);
1713  else if (strcmp(recipe_id, make_str(UVES_MFLAT_ID) ) == 0) return uves_exec_recipe(&uves_mflat_get_info, UVES_MFLAT_DOM, parameters, frames, caller_id, context);
1714  else if (strcmp(recipe_id, make_str(UVES_WAVECAL_ID) ) == 0) return uves_exec_recipe(&uves_wavecal_get_info, UVES_WAVECAL_DOM, parameters, frames, caller_id, context);
1715  else if (strcmp(recipe_id, make_str(UVES_RESPONSE_ID)) == 0) return uves_exec_recipe(&uves_response_get_info, UVES_RESPONSE_DOM, parameters, frames, caller_id, context);
1716  else if (strcmp(recipe_id, make_str(UVES_SCIRED_ID) ) == 0) return uves_exec_recipe(&uves_scired_get_info, UVES_SCIRED_DOM, parameters, frames, caller_id, context);
1717  else if (strcmp(recipe_id, make_str(UVES_REDCHAIN_ID)) == 0) return uves_exec_recipe(&uves_redchain_get_info, UVES_REDCHAIN_DOM, parameters, frames, caller_id, context);
1718  else
1719  {
1720  assure( false, CPL_ERROR_ILLEGAL_INPUT, "Unknown recipe: '%s'", recipe_id);
1721  }
1722  cleanup:
1723  return (cpl_error_get_code() != CPL_ERROR_NONE);
1724 }
1725 
1726 
1727 /*----------------------------------------------------------------------------*/
1745 /*----------------------------------------------------------------------------*/
1746 int
1747 uves_prop_par(int (*get_info)(cpl_pluginlist *),
1748  cpl_parameterlist *parameters,
1749  const char *recipe_id, const char *context)
1750 {
1751  cpl_plugin *plugin = NULL;
1752  cpl_pluginlist *list = NULL;
1753  cpl_recipe *subrecipe = NULL;
1754  char name[256];
1755  int status;
1756 
1757  /* Check input */
1758  if (get_info == NULL)
1759  {
1760  FAIL(-1, CPL_ERROR_NULL_INPUT, "Null function pointer");
1761  }
1762  /* context may be NULL */
1763  if (parameters == NULL)
1764  {
1765  FAIL(-1, CPL_ERROR_NULL_INPUT, "Null parameter list");
1766  }
1767 
1768  if (recipe_id == NULL)
1769  {
1770  FAIL(-1, CPL_ERROR_NULL_INPUT, "Null recipe id");
1771  }
1772 
1773  /* Get the sub-recipe plugin */
1774  list = cpl_pluginlist_new();
1775  status = get_info(list);
1776 
1777  if (status != 0)
1778  {
1779  cpl_pluginlist_delete(list);
1780  FAIL(-1, CPL_ERROR_ILLEGAL_INPUT, "Could not get info about recipe");
1781  }
1782 
1783  /* Get first plugin in plugin list, it must be of type recipe */
1784  if ((plugin = cpl_pluginlist_get_first(list)) == NULL)
1785  {
1786  cpl_pluginlist_delete(list);
1787  FAIL(-1, CPL_ERROR_ILLEGAL_INPUT, "Error getting plugin");
1788  }
1789  if (cpl_plugin_get_name(plugin) == NULL) {
1790  cpl_pluginlist_delete(list);
1791  FAIL(-1, CPL_ERROR_ILLEGAL_INPUT, "Plugin name is NULL");
1792  }
1793  sprintf(name, "%s", cpl_plugin_get_name(plugin));
1794 
1795  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE)
1796  {
1797  cpl_pluginlist_delete(list);
1798  FAIL(-1, CPL_ERROR_TYPE_MISMATCH, "Plugin is not a recipe");
1799  }
1800  subrecipe = (cpl_recipe *) plugin;
1801 
1802  /* Create parameter list by calling subrecipe initializer function */
1803  if( cpl_plugin_get_init(plugin)(plugin) != 0)
1804  {
1805  cpl_plugin_get_deinit(plugin)(plugin);
1806  cpl_pluginlist_delete(list);
1807  FAIL(-1, CPL_ERROR_ILLEGAL_INPUT, "Error getting '%s' parameter list",
1808  name);
1809  }
1810 
1811  if (subrecipe->parameters == NULL)
1812  {
1813  cpl_plugin_get_deinit(plugin)(plugin);
1814  cpl_pluginlist_delete(list);
1815  FAIL(-1, CPL_ERROR_NULL_INPUT, "Recipe '%s' returned NULL parameter list",
1816  name);
1817  }
1818 
1819  if (propagate(cpl_plugin_get_name(plugin), subrecipe->parameters, parameters, recipe_id, context) != 0)
1820  {
1821  cpl_plugin_get_deinit(plugin)(plugin);
1822  cpl_pluginlist_delete(list);
1823  FAIL(-1, CPL_ERROR_ILLEGAL_OUTPUT, "Error propagating parameters from recipe '%s'",
1824  name);
1825  }
1826 
1827  cpl_plugin_get_deinit(plugin)(plugin);
1828  cpl_pluginlist_delete(list);
1829 
1830  return 0;
1831 }
1832 
1833 /*----------------------------------------------------------------------------*/
1839 /*----------------------------------------------------------------------------*/
1840 int
1841 uves_propagate_parameters(const char *subrecipe,
1842  cpl_parameterlist *parameters,
1843  const char *recipe_id, const char *context)
1844 {
1845  if (subrecipe == NULL) {
1846  FAIL(-1, CPL_ERROR_NULL_INPUT, "Null subrecipe id");
1847  }
1848 
1849  if (strcmp(subrecipe, make_str(UVES_PHYSMOD_ID) ) == 0) return uves_prop_par(&uves_physmod_get_info, parameters, recipe_id, context);
1850  else if (strcmp(subrecipe, make_str(UVES_ORDERPOS_ID)) == 0) return uves_prop_par(&uves_orderpos_get_info, parameters, recipe_id, context);
1851  else if (strcmp(subrecipe, make_str(UVES_MBIAS_ID) ) == 0) return uves_prop_par(&uves_mbias_get_info, parameters, recipe_id, context);
1852  else if (strcmp(subrecipe, make_str(UVES_MDARK_ID) ) == 0) return uves_prop_par(&uves_mdark_get_info, parameters, recipe_id, context);
1853  else if (strcmp(subrecipe, make_str(UVES_MFLAT_ID) ) == 0) return uves_prop_par(&uves_mflat_get_info, parameters, recipe_id, context);
1854  else if (strcmp(subrecipe, make_str(UVES_WAVECAL_ID) ) == 0) return uves_prop_par(&uves_wavecal_get_info, parameters, recipe_id, context);
1855  else if (strcmp(subrecipe, make_str(UVES_RESPONSE_ID)) == 0) return uves_prop_par(&uves_response_get_info, parameters, recipe_id, context);
1856  else if (strcmp(subrecipe, make_str(UVES_SCIRED_ID) ) == 0) return uves_prop_par(&uves_scired_get_info, parameters, recipe_id, context);
1857  else if (strcmp(subrecipe, make_str(UVES_REDCHAIN_ID)) == 0) return uves_prop_par(&uves_redchain_get_info, parameters, recipe_id, context);
1858  else {
1859  FAIL(-1, CPL_ERROR_DATA_NOT_FOUND, "Unknown recipe: '%s'", subrecipe);
1860  }
1861 }
1862 
1863 /*----------------------------------------------------------------------------*/
1908 /*----------------------------------------------------------------------------*/
1909 
1910 int
1911 uves_propagate_parameters_step(const char *step_id,
1912  cpl_parameterlist *parameters,
1913  const char *recipe_id, const char *context)
1914 {
1915  cpl_parameterlist *subparameters = NULL;
1916  cpl_parameterlist *(*get_parameters)(void) = NULL; /* Pointer to function
1917  returning parameter list */
1918 
1919  /* Check input */
1920  if (step_id == NULL)
1921  {
1922  FAIL(-1, CPL_ERROR_NULL_INPUT, "Null parameter list");
1923  }
1924 
1925  if (parameters == NULL)
1926  {
1927  FAIL(-1, CPL_ERROR_NULL_INPUT, "Null parameter list");
1928  }
1929 
1930  if (recipe_id == NULL)
1931  {
1932  FAIL(-1, CPL_ERROR_NULL_INPUT, "Null recipe id");
1933  }
1934  /* context may be NULL */
1935 
1936  /* Define which function to call */
1937  if (strcmp(step_id, UVES_BACKSUB_ID ) == 0) {
1938  get_parameters = uves_backsub_define_parameters;
1939  } else if (strcmp(step_id, UVES_QCDARK_ID ) == 0) {
1940  get_parameters = uves_qcdark_define_parameters;
1941  } else if (strcmp(step_id, UVES_EXTRACT_ID ) == 0) {
1942  get_parameters = uves_extract_define_parameters;
1943  } else if (strcmp(step_id, UVES_REBIN_ID ) == 0) {
1944  get_parameters = uves_rebin_define_parameters;
1945  } else if (strcmp(step_id, UVES_REDUCE_ID ) == 0) {
1946  get_parameters = uves_reduce_define_parameters;
1947  } else {
1948  FAIL(-1, CPL_ERROR_DATA_NOT_FOUND, "Unknown sub-step: '%s'", step_id);
1949  }
1950 
1951  /* Get sub-step parameters */
1952  if( (subparameters = get_parameters()) == NULL )
1953  {
1954  FAIL(-1, CPL_ERROR_ILLEGAL_INPUT, "Error getting '%s' parameter list", step_id);
1955  }
1956 
1957  if ( propagate(step_id, subparameters, parameters, recipe_id, context) != 0)
1958  {
1959  cpl_parameterlist_delete(subparameters);
1960  FAIL(-1, CPL_ERROR_ILLEGAL_OUTPUT, "Error propagating '%s' parameters", step_id);
1961  }
1962 
1963  cpl_parameterlist_delete(subparameters);
1964  return 0;
1965 }
1966 
1967 
1968 /*
1969  * Create an enumeration parameter.
1970  * One function for each of int, double, string
1971  * size of values array must match 'size', returns NULL iff error.
1972  *
1973  * It would be much nicer to use a cpl_parameter_duplicate(), but that
1974  * doesn't exist
1975  *
1976  * (These three functions could be reduced to one function by use
1977  * of void pointers, but that is also ugly)
1978  */
1979 static cpl_parameter *
1980 create_parameter_enum_int(const char *name, cpl_type type,
1981  const char *description,
1982  const char *context,
1983  int default_value, int size,
1984  int *values)
1985 {
1986  /* This is just ugly */
1987 
1988  cpl_parameter *result = NULL;
1989 
1990  if (! (1 <= size && size <= 10))
1991  {
1992  cpl_msg_error(__func__, "Unsupported enumeration size: %d (max is 10)", size);
1993  return NULL;
1994  }
1995 
1996  switch(size)
1997  {
1998  case 1:
1999  uves_parameter_new_enum(result, name,
2000  type,
2001  description,
2002  context,
2003  default_value, size,
2004  values[0]);
2005  break;
2006  case 2:
2007  uves_parameter_new_enum(result, name,
2008  type,
2009  description,
2010  context,
2011  default_value, size,
2012  values[0],
2013  values[1]);
2014  break;
2015  case 3:
2016  uves_parameter_new_enum(result, name,
2017  type,
2018  description,
2019  context,
2020  default_value, size,
2021  values[0],
2022  values[1],
2023  values[2]);
2024  break;
2025  case 4:
2026  uves_parameter_new_enum(result, name,
2027  type,
2028  description,
2029  context,
2030  default_value, size,
2031  values[0],
2032  values[1],
2033  values[2],
2034  values[3]);
2035  break;
2036  case 5:
2037  uves_parameter_new_enum(result, name,
2038  type,
2039  description,
2040  context,
2041  default_value, size,
2042  values[0],
2043  values[1],
2044  values[2],
2045  values[3],
2046  values[4]);
2047  break;
2048  case 6:
2049  uves_parameter_new_enum(result, name,
2050  type,
2051  description,
2052  context,
2053  default_value, size,
2054  values[0],
2055  values[1],
2056  values[2],
2057  values[3],
2058  values[4],
2059  values[5]);
2060  break;
2061  case 7:
2062  uves_parameter_new_enum(result, name,
2063  type,
2064  description,
2065  context,
2066  default_value, size,
2067  values[0],
2068  values[1],
2069  values[2],
2070  values[3],
2071  values[4],
2072  values[5],
2073  values[6]);
2074  break;
2075  case 8:
2076  uves_parameter_new_enum(result, name,
2077  type,
2078  description,
2079  context,
2080  default_value, size,
2081  values[0],
2082  values[1],
2083  values[2],
2084  values[3],
2085  values[4],
2086  values[5],
2087  values[6],
2088  values[7]);
2089  break;
2090  case 9:
2091  uves_parameter_new_enum(result, name,
2092  type,
2093  description,
2094  context,
2095  default_value, size,
2096  values[0],
2097  values[1],
2098  values[2],
2099  values[3],
2100  values[4],
2101  values[5],
2102  values[6],
2103  values[7],
2104  values[8]);
2105  break;
2106  case 10:
2107  uves_parameter_new_enum(result, name,
2108  type,
2109  description,
2110  context,
2111  default_value, size,
2112  values[0],
2113  values[1],
2114  values[2],
2115  values[3],
2116  values[4],
2117  values[5],
2118  values[6],
2119  values[7],
2120  values[8],
2121  values[9]);
2122  break;
2123  } /* Switch size */
2124  return result;
2125 }
2126 static cpl_parameter *
2127 create_parameter_enum_double(const char *name, cpl_type type,
2128  const char *description,
2129  const char *context, double default_value,
2130  int size, double *values)
2131 {
2132  /* This is very ugly */
2133 
2134  cpl_parameter *result = NULL;
2135 
2136  if (! (1 <= size && size <= 10))
2137  {
2138  cpl_msg_error(__func__, "Unsupported enumeration size: %d (max is 10)", size);
2139  return NULL;
2140  }
2141 
2142  switch(size)
2143  {
2144  case 1:
2145  uves_parameter_new_enum(result, name,
2146  type,
2147  description,
2148  context,
2149  default_value, size,
2150  values[0]);
2151  break;
2152  case 2:
2153  uves_parameter_new_enum(result, name,
2154  type,
2155  description,
2156  context,
2157  default_value, size,
2158  values[0],
2159  values[1]);
2160  break;
2161  case 3:
2162  uves_parameter_new_enum(result, name,
2163  type,
2164  description,
2165  context,
2166  default_value, size,
2167  values[0],
2168  values[1],
2169  values[2]);
2170  break;
2171  case 4:
2172  uves_parameter_new_enum(result, name,
2173  type,
2174  description,
2175  context,
2176  default_value, size,
2177  values[0],
2178  values[1],
2179  values[2],
2180  values[3]);
2181  break;
2182  case 5:
2183  uves_parameter_new_enum(result, name,
2184  type,
2185  description,
2186  context,
2187  default_value, size,
2188  values[0],
2189  values[1],
2190  values[2],
2191  values[3],
2192  values[4]);
2193  break;
2194  case 6:
2195  uves_parameter_new_enum(result, name,
2196  type,
2197  description,
2198  context,
2199  default_value, size,
2200  values[0],
2201  values[1],
2202  values[2],
2203  values[3],
2204  values[4],
2205  values[5]);
2206  break;
2207  case 7:
2208  uves_parameter_new_enum(result, name,
2209  type,
2210  description,
2211  context,
2212  default_value, size,
2213  values[0],
2214  values[1],
2215  values[2],
2216  values[3],
2217  values[4],
2218  values[5],
2219  values[6]);
2220  break;
2221  case 8:
2222  uves_parameter_new_enum(result, name,
2223  type,
2224  description,
2225  context,
2226  default_value, size,
2227  values[0],
2228  values[1],
2229  values[2],
2230  values[3],
2231  values[4],
2232  values[5],
2233  values[6],
2234  values[7]);
2235  break;
2236  case 9:
2237  uves_parameter_new_enum(result, name,
2238  type,
2239  description,
2240  context,
2241  default_value, size,
2242  values[0],
2243  values[1],
2244  values[2],
2245  values[3],
2246  values[4],
2247  values[5],
2248  values[6],
2249  values[7],
2250  values[8]);
2251  break;
2252  case 10:
2253  uves_parameter_new_enum(result, name,
2254  type,
2255  description,
2256  context,
2257  default_value, size,
2258  values[0],
2259  values[1],
2260  values[2],
2261  values[3],
2262  values[4],
2263  values[5],
2264  values[6],
2265  values[7],
2266  values[8],
2267  values[9]);
2268  break;
2269  } /* Switch size */
2270  return result;
2271 }
2272 static cpl_parameter *
2273 create_parameter_enum_string(const char *name, cpl_type type,
2274  const char *description,
2275  const char *context,
2276  const char *default_value,
2277  int size, const char **values)
2278 {
2279  /* This is extremely ugly */
2280 
2281  cpl_parameter *result = NULL;
2282 
2283  if (! (1 <= size && size <= 10))
2284  {
2285  cpl_msg_error(__func__, "Unsupported enumeration size: %d (max is 10)", size);
2286  return NULL;
2287  }
2288 
2289  switch(size)
2290  {
2291  case 1:
2292  uves_parameter_new_enum(result, name,
2293  type,
2294  description,
2295  context,
2296  default_value, size,
2297  values[0]);
2298  break;
2299  case 2:
2300  uves_parameter_new_enum(result, name,
2301  type,
2302  description,
2303  context,
2304  default_value, size,
2305  values[0],
2306  values[1]);
2307  break;
2308  case 3:
2309  uves_parameter_new_enum(result, name,
2310  type,
2311  description,
2312  context,
2313  default_value, size,
2314  values[0],
2315  values[1],
2316  values[2]);
2317  break;
2318  case 4:
2319  uves_parameter_new_enum(result, name,
2320  type,
2321  description,
2322  context,
2323  default_value, size,
2324  values[0],
2325  values[1],
2326  values[2],
2327  values[3]);
2328  break;
2329  case 5:
2330  uves_parameter_new_enum(result, name,
2331  type,
2332  description,
2333  context,
2334  default_value, size,
2335  values[0],
2336  values[1],
2337  values[2],
2338  values[3],
2339  values[4]);
2340  break;
2341  case 6:
2342  uves_parameter_new_enum(result, name,
2343  type,
2344  description,
2345  context,
2346  default_value, size,
2347  values[0],
2348  values[1],
2349  values[2],
2350  values[3],
2351  values[4],
2352  values[5]);
2353  break;
2354  case 7:
2355  uves_parameter_new_enum(result, name,
2356  type,
2357  description,
2358  context,
2359  default_value, size,
2360  values[0],
2361  values[1],
2362  values[2],
2363  values[3],
2364  values[4],
2365  values[5],
2366  values[6]);
2367  break;
2368  case 8:
2369  uves_parameter_new_enum(result, name,
2370  type,
2371  description,
2372  context,
2373  default_value, size,
2374  values[0],
2375  values[1],
2376  values[2],
2377  values[3],
2378  values[4],
2379  values[5],
2380  values[6],
2381  values[7]);
2382  break;
2383  case 9:
2384  uves_parameter_new_enum(result, name,
2385  type,
2386  description,
2387  context,
2388  default_value, size,
2389  values[0],
2390  values[1],
2391  values[2],
2392  values[3],
2393  values[4],
2394  values[5],
2395  values[6],
2396  values[7],
2397  values[8]);
2398  break;
2399  case 10:
2400  uves_parameter_new_enum(result, name,
2401  type,
2402  description,
2403  context,
2404  default_value, size,
2405  values[0],
2406  values[1],
2407  values[2],
2408  values[3],
2409  values[4],
2410  values[5],
2411  values[6],
2412  values[7],
2413  values[8],
2414  values[9]);
2415  break;
2416  } /* Switch size */
2417  return result;
2418 }
2419 
2420 
2421 /*----------------------------------------------------------------------------*/
2457 /*----------------------------------------------------------------------------*/
2458 
2459 static int
2460 propagate(const char *substep_id, const cpl_parameterlist *sub_parameters,
2461  cpl_parameterlist *parent_parameters,
2462  const char *parent_id, const char *context)
2463 {
2464  const cpl_parameter *p = NULL;
2465 
2466  /* For each sub-recipe parameter:
2467  prefix with context and insert in parent parameter list
2468 
2469  Set (overwrite) default value as current value
2470  */
2471  for (p = cpl_parameterlist_get_first_const(sub_parameters);
2472  p != NULL;
2473  p = cpl_parameterlist_get_next_const(sub_parameters) )
2474  {
2475  const char *name = cpl_parameter_get_name(p);
2476  const char *description = cpl_parameter_get_help(p);
2477  const char *subcontext = cpl_parameter_get_context(p);
2478  const char *alias = cpl_parameter_get_alias(p,
2479  CPL_PARAMETER_MODE_CLI);
2480  cpl_parameter_class class = cpl_parameter_get_class(p);
2481  cpl_type type = cpl_parameter_get_type(p);
2482 
2483  /* Check that S <= name
2484  * and S <= c and c <= name,
2485  * where S is either subrecipe id or 'uves', c is the context,
2486  * and "<=" means "is substring of"
2487  */
2488 
2489  {
2490  const char *S;
2491 
2492  if (strstr(name, "uves.") == name)
2493  {
2494  S = "uves";
2495  }
2496  else
2497  {
2498  S = substep_id;
2499 
2500  /* Check S <= name */
2501  if (strstr(name, S) != name)
2502  {
2503  FAIL(-1, CPL_ERROR_ILLEGAL_INPUT,
2504  "Recipe id '%s' is not prefix of parameter name '%s'",
2505  S, name);
2506  }
2507  }
2508 
2509  /* Check S <= c */
2510  if (strstr(subcontext, S) != subcontext)
2511  {
2512  FAIL(-1, CPL_ERROR_ILLEGAL_INPUT,
2513  "Recipe id '%s' is not prefix of parameter context '%s'",
2514  S, subcontext);
2515  }
2516 
2517  /* Check c <= name */
2518  if (strstr(name, subcontext) != name)
2519  {
2520  FAIL(-1, CPL_ERROR_ILLEGAL_INPUT,
2521  "Parameter context '%s' is not prefix of parameter name '%s'",
2522  subcontext, name);
2523  }
2524  }/* End check parameter format */
2525 
2526  if (strcmp(subcontext, "uves") != 0)
2527  {
2528  int enum_size;
2529 
2530  cpl_parameter *new_par = NULL;
2531  char *new_name;
2532  char *new_context;
2533  char *new_alias;
2534 
2535  if (context == NULL)
2536  {
2537  new_name = uves_sprintf("%s.%s", parent_id, name); /* R.S.x */
2538  new_context = uves_sprintf("%s", parent_id); /* R */
2539  if (alias != NULL)
2540  {
2541  new_alias = uves_sprintf("%s.%s", substep_id, alias); /* S.A */
2542  }
2543  else
2544  {
2545  new_alias = NULL;
2546  }
2547  }
2548  else
2549  {
2550  new_name = uves_sprintf("%s.%s.%s", parent_id, context, name);
2551  /* R.c.Sx */
2552  new_context = uves_sprintf("%s.%s", parent_id, context);
2553  /* R.c */
2554  if (alias != NULL)
2555  {
2556  new_alias = uves_sprintf("%s.%s.%s",
2557  context, substep_id, alias);
2558  /* c.S.A */
2559  }
2560  else
2561  {
2562  new_alias = NULL;
2563  }
2564  }
2565 
2566  if (new_name == NULL || new_context == NULL)
2567  {
2568  if (new_name != NULL) cpl_free(new_name);
2569  if (new_context != NULL) cpl_free(new_context);
2570  if (new_alias != NULL) cpl_free(new_alias);
2571  FAIL(-1, CPL_ERROR_ILLEGAL_OUTPUT, "Memory allocation failed");
2572  }
2573 
2574 
2575  /* Check for legal class/type before switch */
2576  if (class != CPL_PARAMETER_CLASS_VALUE &&
2577  class != CPL_PARAMETER_CLASS_RANGE &&
2578  class != CPL_PARAMETER_CLASS_ENUM)
2579  {
2580  cpl_free(new_name);
2581  cpl_free(new_context);
2582  if (new_alias != NULL) cpl_free(new_alias);
2583  FAIL(-1, CPL_ERROR_TYPE_MISMATCH,
2584  "Unrecognized class of parameter '%s'", name);
2585  }
2586 
2587  if (type != CPL_TYPE_BOOL &&
2588  type != CPL_TYPE_INT &&
2589  type != CPL_TYPE_DOUBLE &&
2590  type != CPL_TYPE_STRING)
2591  {
2592  cpl_free(new_name);
2593  cpl_free(new_context);
2594  if (new_alias != NULL) cpl_free(new_alias);
2595  FAIL(-1, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported type: %s",
2596  uves_tostring_cpl_type(type));
2597  }
2598 
2599  /* Create a new parameter from the sub-parameter */
2600  switch (class)
2601  {
2602  case CPL_PARAMETER_CLASS_VALUE:
2603  switch (type)
2604  {
2605  case CPL_TYPE_BOOL:
2606  uves_parameter_new_value(new_par, new_name,
2607  type,
2608  description,
2609  new_context,
2610  cpl_parameter_get_default_bool(p));
2611  break;
2612 
2613  case CPL_TYPE_INT:
2614  uves_parameter_new_value(new_par, new_name,
2615  type,
2616  description,
2617  new_context,
2618  cpl_parameter_get_default_int(p));
2619  break;
2620 
2621  case CPL_TYPE_DOUBLE:
2622  uves_parameter_new_value(new_par, new_name,
2623  type,
2624  description,
2625  new_context,
2626  cpl_parameter_get_default_double(p));
2627  break;
2628  case CPL_TYPE_STRING:
2629  uves_parameter_new_value(new_par, new_name,
2630  type,
2631  description,
2632  new_context,
2633  cpl_parameter_get_default_string(p));
2634  break;
2635  default:
2636  break;
2637  } /* switch type */
2638 
2639  break; /* CLASS_VALUE */
2640 
2641  case CPL_PARAMETER_CLASS_RANGE:
2642  /* Range is either int or double */
2643  switch (type)
2644  {
2645  int min_int, max_int;
2646  double min_double, max_double;
2647 
2648  case CPL_TYPE_INT:
2649  min_int = cpl_parameter_get_range_min_int(p);
2650  max_int = cpl_parameter_get_range_max_int(p);
2651 
2652  uves_parameter_new_range(new_par, new_name,
2653  type,
2654  description,
2655  new_context,
2656  cpl_parameter_get_default_int(p),
2657  min_int, max_int);
2658  break;
2659 
2660  case CPL_TYPE_DOUBLE:
2661  min_double = cpl_parameter_get_range_min_double(p);
2662  max_double = cpl_parameter_get_range_max_double(p);
2663 
2664  uves_parameter_new_range(new_par, new_name,
2665  type,
2666  description,
2667  new_context,
2668  cpl_parameter_get_default_double(p),
2669  min_double, max_double);
2670  break;
2671  default:
2672  break;
2673  }
2674 
2675  break; /* CLASS_RANGE */
2676 
2677  case CPL_PARAMETER_CLASS_ENUM:
2678  enum_size = cpl_parameter_get_enum_size(p);
2679 
2680  /* Enum type is either int, double or string */
2681  switch (type)
2682  {
2683  int *values_int; /* Arrays to hold enum values */
2684  double *values_double;
2685  const char **values_string;
2686  int i;
2687 
2688  case CPL_TYPE_INT:
2689  if ( (values_int = cpl_malloc(sizeof(int) * enum_size))
2690  == NULL)
2691  {
2692  cpl_free(new_name);
2693  cpl_free(new_context);
2694  if (new_alias != NULL) cpl_free(new_alias);
2695  FAIL(-1, CPL_ERROR_ILLEGAL_OUTPUT,
2696  "Memory allocation failed");
2697  }
2698  for (i = 0; i < enum_size; i++)
2699  {
2700  values_int[i] = cpl_parameter_get_enum_int(p, i);
2701  }
2702 
2703  new_par = create_parameter_enum_int(
2704  new_name,
2705  type,
2706  description,
2707  new_context,
2708  cpl_parameter_get_default_int(p),
2709  enum_size,
2710  values_int);
2711  cpl_free(values_int);
2712  break; /* Enum type int */
2713 
2714  case CPL_TYPE_DOUBLE:
2715  if ( (values_double =
2716  cpl_malloc(sizeof(double) * enum_size)) == NULL)
2717  {
2718  cpl_free(new_name);
2719  cpl_free(new_context);
2720  if (new_alias != NULL) cpl_free(new_alias);
2721  FAIL(-1, CPL_ERROR_ILLEGAL_OUTPUT,
2722  "Memory allocation failed");
2723  }
2724  for (i = 0; i < enum_size; i++)
2725  {
2726  values_double[i] = cpl_parameter_get_enum_double(p, i);
2727  }
2728 
2729  new_par = create_parameter_enum_double(
2730  new_name,
2731  type,
2732  description,
2733  new_context,
2734  cpl_parameter_get_default_double(p),
2735  enum_size,
2736  values_double);
2737  cpl_free(values_double);
2738 
2739  break; /* Enum type double */
2740 
2741  case CPL_TYPE_STRING:
2742  if ( (values_string =
2743  cpl_malloc(sizeof(char *) * enum_size)) == NULL)
2744  {
2745  cpl_free(new_name);
2746  cpl_free(new_context);
2747  if (new_alias != NULL) cpl_free(new_alias);
2748  FAIL(-1, CPL_ERROR_ILLEGAL_OUTPUT,
2749  "Memory allocation failed");
2750  }
2751  for (i = 0; i < enum_size; i++)
2752  {
2753  values_string[i] = cpl_parameter_get_enum_string(p, i);
2754  }
2755 
2756  new_par = create_parameter_enum_string(
2757  new_name,
2758  type,
2759  description,
2760  new_context,
2761  cpl_parameter_get_default_string(p),
2762  enum_size,
2763  values_string);
2764  cpl_free(values_string);
2765 
2766  break; /* Enum type string */
2767 
2768  default:
2769  break;
2770 
2771  } /* Switch enum type */
2772 
2773  break; /* CLASS_ENUM */
2774 
2775  default:
2776  break;
2777 
2778  } /* Switch class */
2779 
2780  if (new_par == NULL)
2781  {
2782  cpl_free(new_name);
2783  cpl_free(new_context);
2784  if (new_alias != NULL) cpl_free(new_alias);
2785  FAIL(-1, CPL_ERROR_ILLEGAL_OUTPUT,
2786  "Propagation of parameter '%s' failed",
2787  name);
2788  }
2789 
2790  /* Also propagate alias */
2791  if (alias != NULL)
2792  {
2793  cpl_parameter_set_alias(new_par, CPL_PARAMETER_MODE_CLI, new_alias);
2794  }
2795 
2796  /* Insert parameter in parent parameter list */
2797  cpl_parameterlist_append(parent_parameters, new_par);
2798 
2799  cpl_free(new_name);
2800  cpl_free(new_context);
2801  if (new_alias != NULL) cpl_free(new_alias);
2802 
2803  } /* If parameter context was not 'uves' */
2804 
2805  } /* For each sub-recipe parameter */
2806 
2807  return (cpl_error_get_code() != CPL_ERROR_NONE);
2808 }
2809 
2810 
const char * uves_msg_get_domain(void)
Get current message domain.
Definition: uves_msg.c:368
int uves_msg_get_warnings(void)
Get number of warnings printed so far.
Definition: uves_msg.c:309
void uves_msg_add_warnings(int n)
Accumulate warnings.
Definition: uves_msg.c:324
#define uves_msg(...)
Print a message on 'info' or 'debug' level.
Definition: uves_msg.h:119
cpl_parameterlist * uves_extract_define_parameters(void)
Define recipe parameters used for extraction.
Definition: uves_extract.c:264
cpl_parameterlist * uves_reduce_define_parameters(void)
Define recipe parameters used for reducing a frame.
Definition: uves_reduce.c:188
const char * uves_tostring_cpl_type(cpl_type t)
Convert a CPL type to a string.
Definition: uves_dump.c:378
#define uves_error_reset()
Definition: uves_error.h:215
#define uves_msg_debug(...)
Print a debug message.
Definition: uves_msg.h:97
cpl_parameterlist * uves_rebin_define_parameters(void)
Define recipe parameters used for rebinning.
Definition: uves_rebin.c:245
#define check(CMD,...)
Definition: uves_error.h:198
void uves_msg_set_domain(const char *d)
Set message domain.
Definition: uves_msg.c:379