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