UVES Pipeline Reference Manual  5.4.6
uves_redchain_impl.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 02110-1301 USA *
18  */
19 
20 /*
21  * $Author: amodigli $
22  * $Date: 2010-09-24 09:32:07 $
23  *
24  */
25 
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29 
30 
31 /*----------------------------------------------------------------------------*/
37 /*----------------------------------------------------------------------------*/
38 
39 /*-----------------------------------------------------------------------------
40  Includes
41  -----------------------------------------------------------------------------*/
42 
43 #include <uves.h>
44 
45 #include <uves_parameters.h>
46 #include <uves_utils.h>
47 #include <uves_utils_wrappers.h>
48 #include <uves_dfs.h>
49 #include <uves_recipe.h>
50 #include <uves_error.h>
51 #include <uves_msg.h>
52 
53 /* Library */
54 #include <cpl.h>
55 #include <string.h>
56 /*-----------------------------------------------------------------------------
57  Local constants
58  -----------------------------------------------------------------------------*/
59 static const bool flames = false; /* This recipe is only for UVES */
60 
61 /*-----------------------------------------------------------------------------
62  Functions prototypes
63  -----------------------------------------------------------------------------*/
64 static bool frame_is_needed(bool blue, const cpl_frame *f);
65 static cpl_error_code execute_recipe(const char *recipe_id,
66  cpl_frameset *frames, const cpl_parameterlist *parameters,
67  const char *products[], int n_products, bool reclassify);
68 static bool is_missing(const cpl_frameset *frames, const char *frame1, const char *frame2);
69 static void remove_input_frame(cpl_frameset *frames, const char *tag);
70 
71 static int uves_redchain_define_parameters(cpl_parameterlist *parameters);
72 
73 /*-----------------------------------------------------------------------------
74  Recipe standard code
75  -----------------------------------------------------------------------------*/
76 #define cpl_plugin_get_info uves_redchain_get_info
77 UVES_RECIPE_DEFINE(
78  UVES_REDCHAIN_ID, UVES_REDCHAIN_DOM, uves_redchain_define_parameters,
79  "Jonas M. Larsen", "cpl@eso.org",
80  "Runs the full UVES reduction chain",
81  "This recipe does a complete science reduction. It runs all necessary\n"
82  "calibration recipes depending on the availability of raw/processed\n"
83  "calibration frames.\n"
84  "Input frames are all UVES raw and reference frames:\n"
85  "formatchecks, ARC_LAMP_FORM_xxxx, xxxx=BLUE or RED,\n"
86  "order definition frames, ORDER_FLAT_xxx,\n"
87  "biases, BIAS_xxx,\n"
88  "darks, DARK_xxx,\n"
89  "flats, FLAT_xxx,\n"
90  "arc lamps, ARC_LAMP_xxx,\n"
91  "standard stars, STANDARD_xxx\n"
92  "a wavelength catalogue table,LINE_REFER_TABLE, \n"
93  "and optionally a wavelength table of bright lines,LINE_INTMON_TABLE, \n"
94  "used only for computing Quality Control parameters.\n"
95  "a reference standard star flux table, FLUX_STD_TABLE, \n"
96  "a table describing the atmospheric extintion,EXTCOEFF_TABLE.\n"
97  "optionally, science frames, SCIENCE_xxx, or UVES_SCI_POINT_xxx, \n"
98  "or UVES_SCI_EXTND_xxx, or UVES_SCI_SLICER_xxx.\n"
99  "For further details on the data reduction and the input frame types\n"
100  "refer to the man page of the individual recipes.\n");
101 
104 /*-----------------------------------------------------------------------------
105  Functions code
106  -----------------------------------------------------------------------------*/
107 /*----------------------------------------------------------------------------*/
113 /*----------------------------------------------------------------------------*/
114 static int
115 uves_redchain_define_parameters(cpl_parameterlist *parameters)
116 {
117  const char *recipe_id = make_str(UVES_REDCHAIN_ID);
118  const char *subcontext = NULL;
119 
120  uves_par_new_value("scired",
121  CPL_TYPE_BOOL,
122  "Whether or not to do science reduction. "
123  "If false, only master calibration frames "
124  "are created. If false, either zero or all "
125  "necessary calibration frames must be provided "
126  "for each arm",
127  true);
128 
129  /*****************
130  * General *
131  *****************/
132  if (uves_define_global_parameters(parameters) != CPL_ERROR_NONE)
133  {
134  return -1;
135  }
136 
137  /******************
138  * Master bias *
139  ******************/
140  if (uves_propagate_parameters(
141  make_str(UVES_MBIAS_ID), parameters, make_str(UVES_REDCHAIN_ID), NULL) != 0)
142  {
143  return -1;
144  }
145 
146 
147  /******************
148  * Master dark *
149  ******************/
150  if (uves_propagate_parameters(
151  make_str(UVES_MDARK_ID), parameters, make_str(UVES_REDCHAIN_ID), NULL) != 0)
152  {
153  return -1;
154  }
155 
156  /******************
157  * Physical model *
158  ******************/
159  if (uves_propagate_parameters(
160  make_str(UVES_PHYSMOD_ID), parameters, make_str(UVES_REDCHAIN_ID), NULL) != 0)
161  {
162  return -1;
163  }
164 
165  /******************
166  * Order position *
167  ******************/
168  if (uves_propagate_parameters(
169  make_str(UVES_ORDERPOS_ID), parameters, make_str(UVES_REDCHAIN_ID), NULL) != 0)
170  {
171  return -1;
172  }
173 
174  /******************
175  * Master flat *
176  ******************/
177  if (uves_propagate_parameters(
178  make_str(UVES_MFLAT_ID), parameters, make_str(UVES_REDCHAIN_ID), NULL) != 0)
179  {
180  return -1;
181  }
182 
183 
184  /******************
185  * Wave.cal. *
186  ******************/
187  if (uves_propagate_parameters(
188  make_str(UVES_WAVECAL_ID), parameters, make_str(UVES_REDCHAIN_ID), NULL) != 0)
189  {
190  return -1;
191  }
192 
193  /******************
194  * Response *
195  ******************/
196 /*
197  if (uves_propagate_parameters(
198  make_str(UVES_RESPONSE_ID), parameters, make_str(UVES_REDCHAIN_ID), NULL) != 0)
199  {
200  return -1;
201  }
202 */
203 
204  uves_define_background_for_response_chain_parameters(parameters);
205  uves_define_extract_for_response_chain_parameters(parameters);
206  uves_define_reduce_for_response_chain_parameters(parameters);
207  uves_define_rebin_for_response_chain_parameters(parameters);
208  uves_define_efficiency_for_response_chain_parameters(parameters);
209 
210 
211 
212  /******************
213  * Scired *
214  ******************/
215  if (uves_propagate_parameters(
216  make_str(UVES_SCIRED_ID), parameters, make_str(UVES_REDCHAIN_ID), NULL) != 0)
217  {
218  return -1;
219  }
220 
221  return (cpl_error_get_code() != CPL_ERROR_NONE);
222 }
223 
224 /*----------------------------------------------------------------------------*/
233 /*----------------------------------------------------------------------------*/
234 static void
235 UVES_CONCAT2X(UVES_REDCHAIN_ID,exe)(cpl_frameset *frames,
236  const cpl_parameterlist *parameters,
237  const char *starttime)
238 {
239  cpl_frameset *blue_frames = NULL;
240  cpl_frameset *red_frames = NULL;
241  cpl_frameset *common_frames = NULL;
242 
243 
244  bool blue;
245  bool do_science;
246 
247  bool run_mbias[2]; /* index 0 (==false): red arm */
248  bool run_mdark[2]; /* index 1 (==true ): blue arm */
249  bool run_mflat[2];
250  bool run_physmod[2];
251  bool run_orderpos[2];
252  bool run_wavecal[2];
253  bool run_response[2];
254  bool run_scired[2];
255  bool nraw_arm[2]; /* Do we have frames used exclusively
256  for this arm? */
257  const char* PROCESS_CHIP=NULL;
258 
259  /* Exceptionally, this parameter is not used because this
260  recipe does not create any products on its own. Suppress
261  warning about unused variable */
262  starttime = starttime;
263 
264  check( uves_get_parameter(parameters, NULL, make_str(UVES_REDCHAIN_ID), "scired",
265  CPL_TYPE_BOOL, &do_science), "Could not read parameter");
266 
267  /* Check for at least one science frame */
268  assure(!do_science ||
269  cpl_frameset_find(frames, UVES_SCIENCE(true )) != NULL ||
270  cpl_frameset_find(frames, UVES_SCIENCE(false)) != NULL ||
271  cpl_frameset_find(frames, UVES_SCI_EXTND(true )) != NULL ||
272  cpl_frameset_find(frames, UVES_SCI_EXTND(false)) != NULL ||
273  cpl_frameset_find(frames, UVES_SCI_POINT(true )) != NULL ||
274  cpl_frameset_find(frames, UVES_SCI_POINT(false)) != NULL ||
275  cpl_frameset_find(frames, UVES_SCI_SLICER(true )) != NULL ||
276  cpl_frameset_find(frames, UVES_SCI_SLICER(false)) != NULL,
277  CPL_ERROR_DATA_NOT_FOUND, "No %s, %s, %s, %s, %s, %s, %s or %s in frame set",
278  UVES_SCIENCE(true),
279  UVES_SCIENCE(false),
280  UVES_SCI_EXTND(true),
281  UVES_SCI_EXTND(false),
282  UVES_SCI_POINT(true),
283  UVES_SCI_POINT(false),
284  UVES_SCI_SLICER(true),
285  UVES_SCI_SLICER(false));
286 
287  blue_frames = cpl_frameset_new();
288  red_frames = cpl_frameset_new();
289  common_frames = cpl_frameset_new();
290 
291  check( uves_get_parameter(parameters, NULL, "uves", "process_chip", CPL_TYPE_STRING, &PROCESS_CHIP),
292  "Could not read parameter");
293  uves_string_toupper((char*)PROCESS_CHIP);
294 
295  /* Split in blue/red frames */
296  {
297  cpl_frame *f = NULL;
298  int i=0;
299  int nfrm=0;
300  nfrm=cpl_frameset_get_size(frames);
301  for (i=0;i<nfrm;i++)
302  {
303 
304  f=cpl_frameset_get_frame(frames,i);
305  if (frame_is_needed(true, f)) /* Used in blue arm? */
306  {
307  uves_msg_debug("Found blue frame: '%s'", cpl_frame_get_tag(f));
308  check( cpl_frameset_insert(blue_frames, cpl_frame_duplicate(f)),
309  "Error extracting frame '%s' from frame set",
310  cpl_frame_get_tag(f));
311  }
312  if (frame_is_needed(false, f)) /* Used in red arm? */
313  {
314  uves_msg_debug("Found red frame: '%s'", cpl_frame_get_tag(f));
315  check( cpl_frameset_insert(red_frames, cpl_frame_duplicate(f)),
316  "Error extracting frame '%s' from frame set",
317  cpl_frame_get_tag(f));
318  }
319 
320  if (frame_is_needed(true, f) &&
321  frame_is_needed(false, f)) /* Used in both arms? */
322  {
323  uves_msg_debug("Found common frame: '%s'", cpl_frame_get_tag(f));
324  check( cpl_frameset_insert(common_frames, cpl_frame_duplicate(f)),
325  "Error extracting frame '%s' from frame set",
326  cpl_frame_get_tag(f));
327  }
328 
329  }
330  /* Remove all frames from input frame set */
331  cpl_frame *frm = NULL;
332  for (i=0;i<nfrm;i++) {
333  check_nomsg(frm=cpl_frameset_get_frame(frames,0));
334  check_nomsg(cpl_frameset_erase_frame(frames, frm));
335  }
336 
337 
338  }
339 
340  /* Algorithm:
341  (with purpose of failing early if we have to fail.)
342 
343  1) Find out which recipes to run
344  2) Check for necessary input frames
345  3) Execute
346  */
347 
348  blue = true;
349  do {
350  enum uves_chip chip1 = (blue) ? UVES_CHIP_BLUE : UVES_CHIP_REDL;
351  enum uves_chip chip2 = (blue) ? UVES_CHIP_BLUE : UVES_CHIP_REDU;
352 
353  cpl_frameset *fms = (blue) ? blue_frames : red_frames;
354 
355  nraw_arm[blue] =
356  cpl_frameset_get_size(fms) >
357  cpl_frameset_get_size(common_frames);
358 
359  uves_msg_debug("nraw_arm=%d (%s arm)", nraw_arm[blue], blue ? "blue" : "red");
360 
361  run_scired[blue] = do_science &&
362  !(is_missing(fms, UVES_SCIENCE(blue), NULL) &&
363  is_missing(fms, UVES_SCI_EXTND(blue), NULL) &&
364  is_missing(fms, UVES_SCI_POINT(blue), NULL) &&
365  is_missing(fms, UVES_SCI_SLICER(blue), NULL));
366 
367  /* If calibrations must be produced for this arm */
368  if (run_scired[blue]
369  ||
370  (!do_science && nraw_arm[blue])) {
371 
372  /* Require master bias */
373  run_mbias[blue] = is_missing(fms,
374  UVES_MASTER_BIAS(chip1),
375  UVES_MASTER_BIAS(chip2)
376  );
377 
378  /* Run master dark, only if raw frames are available */
379  run_mdark[blue] =
380  is_missing(fms,
381  UVES_MASTER_DARK(chip1),
382  UVES_MASTER_DARK(chip2))
383  &&
384  is_missing(fms,
385  UVES_MASTER_PDARK(chip1),
386  UVES_MASTER_PDARK(chip2))
387  &&(
388  !is_missing(fms, UVES_DARK(blue), NULL) ||
389  !is_missing(fms, UVES_PDARK(blue), NULL));
390 
391  /* Run orderpos if either order table is missing,
392  or raw frame available */
393  run_orderpos[blue] = is_missing(fms,
394  UVES_ORDER_TABLE(flames, chip1),
395  UVES_ORDER_TABLE(flames, chip2)
396  ) ||
397  !is_missing(fms, UVES_ORDER_FLAT(flames, blue), NULL);
398 
399  /* Run master flat recipe if master flat frame is missing */
400  run_mflat[blue] =
401  is_missing(fms,
402  UVES_MASTER_FLAT(chip1),
403  UVES_MASTER_FLAT(chip2))
404  &&
405  is_missing(fms,
406  UVES_MASTER_DFLAT(chip1),
407  UVES_MASTER_DFLAT(chip2))
408  &&
409  is_missing(fms,
410  UVES_MASTER_IFLAT(chip1),
411  UVES_MASTER_IFLAT(chip2))
412  &&
413  is_missing(fms,
414  UVES_MASTER_SCREEN_FLAT(chip1),
415  UVES_MASTER_SCREEN_FLAT(chip2))
416  &&
417  is_missing(fms,
418  UVES_REF_TFLAT(chip1),
419  UVES_REF_TFLAT(chip2));
420 
421 
422  /* Line tables are used as both input and output
423  for wavecal recipe. A provided line table is
424  interpreted as an input table if an arc lamp
425  frame is also available, otherwise as output.
426  Line tables produce by the physmod recipe are
427  input tables. The logic is
428 
429  if !linetable
430  physmod=yes
431  wavecal=yes
432  if linetable
433  physmod=no
434  if !arclamp
435  wavecal=no // line table is final
436  if arclamp
437  wavecal=yes // line table is guess
438  */
439 
440  /* Run physical model if there's no
441  line table */
442  run_physmod[blue] = is_missing(fms,
443  UVES_LINE_TABLE(flames, chip1),
444  UVES_LINE_TABLE(flames, chip2))
445  &&
446  is_missing(fms,
447  UVES_GUESS_LINE_TABLE(flames, chip1),
448  UVES_GUESS_LINE_TABLE(flames, chip2))
449  &&
450  (
451  is_missing(fms,
452  UVES_LINE_TABLE_MIDAS(chip1, 1),
453  UVES_LINE_TABLE_MIDAS(chip2, 1)) ||
454  is_missing(fms,
455  UVES_LINE_TABLE_MIDAS(chip1, 2),
456  UVES_LINE_TABLE_MIDAS(chip2, 2)) ||
457  is_missing(fms,
458  UVES_LINE_TABLE_MIDAS(chip1, 3),
459  UVES_LINE_TABLE_MIDAS(chip2, 3))
460  );
461 
462  /* Run wavecal if no line table,
463  or if there's an arc lamp frame
464  */
465  run_wavecal[blue] =
466  run_physmod[blue]
467  ||
468  (
469  is_missing(fms,
470  UVES_LINE_TABLE(flames, chip1),
471  UVES_LINE_TABLE(flames, chip2))
472  &&
473  (
474  is_missing(fms,
475  UVES_LINE_TABLE_MIDAS(chip1, 1),
476  UVES_LINE_TABLE_MIDAS(chip2, 1)) ||
477  is_missing(fms,
478  UVES_LINE_TABLE_MIDAS(chip1, 2),
479  UVES_LINE_TABLE_MIDAS(chip2, 2)) ||
480  is_missing(fms,
481  UVES_LINE_TABLE_MIDAS(chip1, 3),
482  UVES_LINE_TABLE_MIDAS(chip2, 3))
483  )
484  )
485  ||
486  (
487  !is_missing(fms,
488  UVES_ARC_LAMP(flames, blue), NULL) ||
489  !is_missing(fms,
490  UVES_ECH_ARC_LAMP(blue), NULL)
491  );
492 
493  /* Run response only if there's a standard star.
494  Otherwise no response correction is done */
495  run_response[blue] = !is_missing(fms,
496  UVES_STD_STAR(blue), NULL);
497 
498 
499  uves_msg("Reduction strategy for %s arm:", (blue) ? "BLUE" : "RED");
500  uves_msg("Run %-13s: %s", make_str(UVES_MBIAS_ID) , (run_mbias[blue] ) ? "Yes" : "No");
501  uves_msg("Run %-13s: %s", make_str(UVES_MDARK_ID) , (run_mdark[blue] ) ? "Yes" : "No");
502  uves_msg("Run %-13s: %s", make_str(UVES_PHYSMOD_ID) , (run_physmod[blue] ) ? "Yes" : "No");
503  uves_msg("Run %-13s: %s", make_str(UVES_ORDERPOS_ID), (run_orderpos[blue]) ? "Yes" : "No");
504  uves_msg("Run %-13s: %s", make_str(UVES_MFLAT_ID) , (run_mflat[blue] ) ? "Yes" : "No");
505  uves_msg("Run %-13s: %s", make_str(UVES_WAVECAL_ID) , (run_wavecal[blue] ) ? "Yes" : "No");
506  uves_msg("Run %-13s: %s", make_str(UVES_RESPONSE_ID), (run_response[blue]) ? "Yes" : "No");
507  uves_msg("Run %-13s: %s", make_str(UVES_SCIRED_ID) , (run_scired[blue] ) ? "Yes" : "No");
508 
509  } /* if reduce this arm */
510  else {
511  uves_msg("Skipping %s arm",
512  (blue) ? "BLUE" : "RED");
513 
514  run_mbias[blue] = false;
515  run_mdark[blue] = false;
516  run_mflat[blue] = false;
517  run_physmod[blue] = false;
518  run_orderpos[blue] = false;
519  run_wavecal[blue] = false;
520  run_response[blue] = false;
521  }
522 
523  blue = !blue;
524  }
525  while (!blue);
526 
527  /* As a service to the user, assure that required
528  raw frames and catalogue calibration frames
529  exist *before* doing the reduction */
530 
531  blue = true;
532  do
533  {
534  cpl_frameset *fms = (blue) ? blue_frames : red_frames;
535 
536  assure( !run_mbias[blue] || !is_missing(fms, UVES_BIAS(blue), NULL),
537  CPL_ERROR_DATA_NOT_FOUND,
538  "One or more '%s' frames needed for recipe '%s'",
539  UVES_BIAS(blue), make_str(UVES_MBIAS_ID));
540 
541  assure( !run_mdark[blue] ||
542  !is_missing(fms, UVES_DARK(blue), NULL) ||
543  !is_missing(fms, UVES_PDARK(blue), NULL),
544  CPL_ERROR_DATA_NOT_FOUND,
545  "One or more '%s' or '%s' frames needed for recipe '%s'",
546  UVES_DARK(blue), UVES_PDARK(blue), make_str(UVES_MDARK_ID));
547 
548  assure( !run_physmod[blue] || !is_missing(fms, UVES_FORMATCHECK(flames, blue), NULL),
549  CPL_ERROR_DATA_NOT_FOUND, "Frame '%s' needed for recipe '%s'",
550  UVES_FORMATCHECK(flames, blue), make_str(UVES_PHYSMOD_ID));
551 
552  assure( !run_orderpos[blue] || !is_missing(fms, UVES_ORDER_FLAT(flames, blue), NULL),
553  CPL_ERROR_DATA_NOT_FOUND, "Frame '%s' needed for recipe '%s'",
554  UVES_ORDER_FLAT(flames, blue), make_str(UVES_ORDERPOS_ID));
555 
556  assure( !run_mflat[blue] ||
557  !is_missing(fms, UVES_FLAT(blue), NULL) ||
558  !is_missing(fms, UVES_IFLAT(blue), NULL) ||
559  !is_missing(fms, UVES_SCREEN_FLAT(blue), NULL) ||
560  !is_missing(fms, UVES_DFLAT(blue), NULL) ||
561  !is_missing(fms, UVES_TFLAT(blue), NULL),
562  CPL_ERROR_DATA_NOT_FOUND,
563  "One or more '%s', '%s', '%s', '%s' or '%s' frames needed for recipe '%s'",
564  UVES_FLAT(blue),
565  UVES_IFLAT(blue),
566  UVES_SCREEN_FLAT(blue),
567  UVES_DFLAT(blue),
568  UVES_TFLAT(blue),
569  make_str(UVES_MFLAT_ID));
570 
571  assure( !run_wavecal[blue] || (
572  !is_missing(fms, UVES_ARC_LAMP(flames, blue), NULL) ||
573  !is_missing(fms, UVES_ECH_ARC_LAMP(blue), NULL)),
574  CPL_ERROR_DATA_NOT_FOUND, "Frame '%s' or '%s' needed for recipe '%s'",
575  UVES_ARC_LAMP(flames, blue), UVES_ECH_ARC_LAMP(blue), make_str(UVES_WAVECAL_ID));
576  assure( !run_wavecal[blue] || !is_missing(fms, UVES_LINE_REFER_TABLE, NULL),
577  CPL_ERROR_DATA_NOT_FOUND, "Frame '%s' needed for recipe '%s'",
578  UVES_LINE_REFER_TABLE, make_str(UVES_WAVECAL_ID));
579 
580  assure( !run_response[blue] || !is_missing(fms, UVES_STD_STAR(blue), NULL),
581  CPL_ERROR_DATA_NOT_FOUND, "Frame '%s' needed for recipe '%s'",
582  UVES_STD_STAR(blue), make_str(UVES_RESPONSE_ID));
583  assure( !run_response[blue] || !is_missing(fms, UVES_FLUX_STD_TABLE, NULL),
584  CPL_ERROR_DATA_NOT_FOUND, "Frame '%s' needed for recipe '%s'",
585  UVES_FLUX_STD_TABLE, make_str(UVES_RESPONSE_ID));
586  assure( !run_response[blue] || !is_missing(fms, UVES_EXTCOEFF_TABLE, NULL),
587  CPL_ERROR_DATA_NOT_FOUND, "Frame '%s' needed for recipe '%s'",
588  UVES_EXTCOEFF_TABLE, make_str(UVES_RESPONSE_ID));
589 
590  blue = !blue;
591  }
592  while (!blue);
593 
594  /* We now know which recipes to run and
595  * that required input frames exist. Execute
596  * chain; re-classify PRODUCT->CALIB under way
597  */
598 
599  blue = true;
600  do
601  {
602  enum uves_chip chip1 = (blue) ? UVES_CHIP_BLUE : UVES_CHIP_REDL;
603  enum uves_chip chip2 = (blue) ? UVES_CHIP_BLUE : UVES_CHIP_REDU;
604 
605  cpl_frameset *fms = (blue) ? blue_frames : red_frames;
606 
607  if (run_mbias[blue])
608  {
609  const char *products[2];
610 
611  int nprod = sizeof(products) / sizeof (char *);
612 
613  products[0] = UVES_MASTER_BIAS(chip1);
614  products[1] = UVES_MASTER_BIAS(chip2);
615 
616  if (blue) nprod /= 2;
617 
618  check( execute_recipe(make_str(UVES_MBIAS_ID), fms, parameters, products, nprod, true),
619  "Recipe execution failed");
620  }
621 
622  check( remove_input_frame(fms, UVES_BIAS(blue)), "Error removing input frames");
623 
624  if (run_mdark[blue])
625  {
626  const char *products[4];
627 
628  int nprod = sizeof(products) / sizeof (char *);
629 
630  products[0] = UVES_MASTER_DARK(chip1);
631  products[1] = UVES_MASTER_PDARK(chip1);
632  products[2] = UVES_MASTER_DARK(chip2);
633  products[3] = UVES_MASTER_PDARK(chip2);
634 
635  if (blue) nprod /= 2;
636 
637  check( execute_recipe(
638  make_str(UVES_MDARK_ID), fms, parameters, products, nprod, true),
639  "Recipe execution failed");
640  }
641 
642  check( remove_input_frame(fms, UVES_DARK(blue)), "Error removing input frames");
643  check( remove_input_frame(fms, UVES_PDARK(blue)), "Error removing input frames");
644 
645  if (run_physmod[blue])
646  {
647  const char *products[4];
648  int nprod = sizeof(products) / sizeof (char *);
649 
650  products[0] = UVES_GUESS_LINE_TABLE (flames, chip1);
651  products[1] = UVES_GUESS_ORDER_TABLE(flames, chip1);
652  products[2] = UVES_GUESS_LINE_TABLE (flames, chip2);
653  products[3] = UVES_GUESS_ORDER_TABLE(flames, chip2);
654 
655  if (blue) nprod /= 2;
656 
657  check( execute_recipe(
658  make_str(UVES_PHYSMOD_ID),
659  fms, parameters, products, nprod, true),
660  "Recipe execution failed");
661  }
662 
663  check( remove_input_frame(fms, UVES_FORMATCHECK(flames, blue)),
664  "Error removing input frames");
665 
666  if (run_orderpos[blue])
667  {
668  const char *products[2];
669  int nprod = sizeof(products) / sizeof (char *);
670 
671  products[0] = UVES_ORDER_TABLE(flames, chip1);
672  products[1] = UVES_ORDER_TABLE(flames, chip2);
673 
674  if (blue) nprod /= 2;
675 
676  check( execute_recipe(
677  make_str(UVES_ORDERPOS_ID),
678  fms, parameters, products, nprod, true),
679  "Recipe execution failed");
680  }
681 
682  check( remove_input_frame(fms, UVES_ORDER_FLAT(flames, blue)),
683  "Error removing input frames");
684 
685  if (run_mflat[blue])
686  {
687  const char *products[10];
688 
689  int nprod = sizeof(products) / sizeof (char *);
690 
691  products[0] = UVES_MASTER_FLAT(chip1);
692  products[1] = UVES_MASTER_DFLAT(chip1);
693  products[2] = UVES_MASTER_IFLAT(chip1);
694  products[3] = UVES_MASTER_TFLAT(chip1);
695  products[4] = UVES_MASTER_SCREEN_FLAT(chip1);
696  products[5] = UVES_MASTER_FLAT(chip2);
697  products[6] = UVES_MASTER_DFLAT(chip2);
698  products[7] = UVES_MASTER_IFLAT(chip2);
699  products[8] = UVES_MASTER_TFLAT(chip2);
700  products[9] = UVES_MASTER_SCREEN_FLAT(chip2);
701 
702  if (blue) nprod /= 2;
703 
704  check( execute_recipe(make_str(UVES_MFLAT_ID),
705  fms, parameters, products, nprod, true),
706  "Recipe execution failed");
707  }
708 
709  check( remove_input_frame(fms, UVES_FLAT(blue)), "Error removing input frames");
710  check( remove_input_frame(fms, UVES_IFLAT(blue)), "Error removing input frames");
711  check( remove_input_frame(fms, UVES_DFLAT(blue)), "Error removing input frames");
712  check( remove_input_frame(fms, UVES_TFLAT(blue)), "Error removing input frames");
713  check( remove_input_frame(fms, UVES_SCREEN_FLAT(blue)), "Error removing input frames");
714 
715  if (run_wavecal[blue])
716  {
717  const char *products[2];
718 
719  int nprod = sizeof(products) / sizeof (char *);
720 
721  products[0] = UVES_LINE_TABLE(flames, chip1);
722  products[1] = UVES_LINE_TABLE(flames, chip2);
723 
724  if (blue) nprod /= 2;
725 
726  check( execute_recipe(make_str(UVES_WAVECAL_ID),
727  fms, parameters, products, nprod, true),
728  "Recipe execution failed");
729  }
730 
731  check( remove_input_frame(fms, UVES_ARC_LAMP(flames, blue)),
732  "Error removing input frames");
733  check( remove_input_frame(fms, UVES_ECH_ARC_LAMP(blue)),
734  "Error removing input frames");
735  check( remove_input_frame(fms, UVES_LINE_REFER_TABLE),
736  "Error removing input frames");
737 
738  if (run_response[blue])
739  {
740  const char *products[2];
741 
742  int nprod = sizeof(products) / sizeof (char *);
743 
744  products[0] = UVES_INSTR_RESPONSE(chip1);
745  products[1] = UVES_INSTR_RESPONSE(chip2);
746 
747  if (blue) nprod /= 2;
748 
749  check( execute_recipe(make_str(UVES_RESPONSE_ID),
750  fms, parameters, products, nprod, true),
751  "Recipe execution failed");
752  }
753 
754  check( remove_input_frame(fms, UVES_STD_STAR(blue)), "Error removing input frames");
755  check( remove_input_frame(fms, UVES_FLUX_STD_TABLE), "Error removing input frames");
756 
757  if (run_scired[blue])
758  {
759  const char *products[2];
760 
761  int nprod = sizeof(products) / sizeof (char *);
762 
763  products[0] = blue ? "RED_SCIENCE_BLUE" : "RED_SCIENCE_REDL";
764  products[1] = blue ? "RED_SCIENCE_BLUE" : "RED_SCIENCE_REDU";
765 
766  if (blue) nprod /= 2;
767 
768  check( execute_recipe(make_str(UVES_SCIRED_ID),
769  fms, parameters, products, nprod, false),
770  "Recipe execution failed");
771  }
772 
773  check( remove_input_frame(fms, UVES_SCIENCE(blue)) , "Error removing input frames");
774  check( remove_input_frame(fms, UVES_SCI_EXTND(blue)) , "Error removing input frames");
775  check( remove_input_frame(fms, UVES_SCI_POINT(blue)) , "Error removing input frames");
776  check( remove_input_frame(fms, UVES_SCI_SLICER(blue)), "Error removing input frames");
777 
778  /* Insert all product frames into recipe frame set */
779  {
780  cpl_frame *f = NULL;
781  int i=0;
782  int nfrm=0;
783  nfrm=cpl_frameset_get_size(fms);
784  for (i=0;i<nfrm;i++)
785  {
786  f=cpl_frameset_get_frame(fms,i);
787  if (cpl_frame_get_group(f) == CPL_FRAME_GROUP_PRODUCT)
788  {
789  check( cpl_frameset_insert(frames, cpl_frame_duplicate(f)),
790  "Error inserting product '%s' into frame set",
791  cpl_frame_get_tag(f));
792  }
793  }
794  }
795 
796  blue = !blue;
797  }
798  while(!blue); /* For each arm */
799 
800  cleanup:
801  uves_free_frameset(&blue_frames);
802  uves_free_frameset(&red_frames);
803  uves_free_frameset(&common_frames);
804 
805  return;
806 }
807 
808 /* Returns true, iff frame is used for blue/red arm
809  (note that some frames like UVES_FLUX_STD_TABLE are
810  used for both arms) */
811 static bool
812 frame_is_needed(bool blue, const cpl_frame *f)
813 {
814  const char *tag = cpl_frame_get_tag(f);
815 
816  bool result = (strcmp(tag, UVES_ORDER_FLAT (flames, blue)) == 0 ||
817  strcmp(tag, UVES_BIAS (blue)) == 0 ||
818  strcmp(tag, UVES_DARK (blue)) == 0 ||
819  strcmp(tag, UVES_PDARK (blue)) == 0 ||
820  strcmp(tag, UVES_FLAT (blue)) == 0 ||
821  strcmp(tag, UVES_IFLAT (blue)) == 0 ||
822  strcmp(tag, UVES_DFLAT (blue)) == 0 ||
823  strcmp(tag, UVES_TFLAT (blue)) == 0 ||
824  strcmp(tag, UVES_SCREEN_FLAT(blue)) == 0 ||
825  strcmp(tag, UVES_STD_STAR (blue)) == 0 ||
826  strcmp(tag, UVES_FORMATCHECK(flames, blue)) == 0 ||
827  strcmp(tag, UVES_STD_STAR (blue)) == 0 ||
828  strcmp(tag, UVES_SCIENCE (blue)) == 0 ||
829  strcmp(tag, UVES_SCI_EXTND (blue)) == 0 ||
830  strcmp(tag, UVES_SCI_POINT (blue)) == 0 ||
831  strcmp(tag, UVES_SCI_SLICER (blue)) == 0 ||
832  strcmp(tag, UVES_ARC_LAMP (flames, blue)) == 0 ||
833  strcmp(tag, UVES_ECH_ARC_LAMP(blue)) == 0);
834 
835  enum uves_chip chip;
836 
837  /* Loop through all blue or red chips (1 or 2) */
838  for (chip = uves_chip_get_first(blue);
839  chip != UVES_CHIP_INVALID;
840  chip = uves_chip_get_next(chip))
841  {
842  result = result || (strcmp(tag, UVES_DRS_SETUP(flames, chip)) == 0 ||
843  strcmp(tag, UVES_ORDER_TABLE(flames, chip)) == 0 ||
844  strcmp(tag, UVES_GUESS_ORDER_TABLE(flames, chip)) == 0 ||
845  strcmp(tag, UVES_MASTER_BIAS(chip)) == 0 ||
846  strcmp(tag, UVES_MASTER_DARK(chip)) == 0 ||
847  strcmp(tag, UVES_MASTER_PDARK(chip)) == 0 ||
848  strcmp(tag, UVES_MASTER_FLAT(chip)) == 0 ||
849  strcmp(tag, UVES_MASTER_DFLAT(chip)) == 0 ||
850  strcmp(tag, UVES_MASTER_IFLAT(chip)) == 0 ||
851  strcmp(tag, UVES_MASTER_TFLAT(chip)) == 0 ||
852  strcmp(tag, UVES_REF_TFLAT(chip)) == 0 ||
853  strcmp(tag, UVES_MASTER_SCREEN_FLAT(chip)) == 0 ||
854  strcmp(tag, UVES_LINE_TABLE (flames, chip)) == 0 ||
855  strcmp(tag, UVES_GUESS_LINE_TABLE(flames, chip)) == 0 ||
856  strcmp(tag, UVES_LINE_TABLE_MIDAS(chip, 1)) == 0 ||
857  strcmp(tag, UVES_LINE_TABLE_MIDAS(chip, 2)) == 0 ||
858  strcmp(tag, UVES_LINE_TABLE_MIDAS(chip, 3)) == 0 ||
859  strcmp(tag, UVES_LINE_REFER_TABLE ) == 0 ||
860  strcmp(tag, UVES_FLUX_STD_TABLE ) == 0 ||
861  strcmp(tag, UVES_EXTCOEFF_TABLE ) == 0);
862  }
863  return result;
864 }
865 
866 /* Execute a recipe and re-classify its products as calibration frames */
867 static cpl_error_code
868 execute_recipe(const char *recipe_id,
869  cpl_frameset *frames, const cpl_parameterlist *parameters,
870  const char *products[],
871  int n_products,
872  bool reclassify) /* Re-classify products? */
873 {
874  int i;
875  cpl_frame *f = NULL;
876 
877  /* Remove (from frame set) any product
878  frames already present */
879  for (i = 0; i < n_products; i++)
880  {
881  if ((f = cpl_frameset_find(frames, products[i])) != NULL)
882  {
883  if (cpl_frame_get_group(f) == CPL_FRAME_GROUP_PRODUCT)
884  {
885  cpl_msg_warning(__func__, "Ignoring %s frame in '%s'. "
886  "A new %s frame will now be calculated",
887  products[i], cpl_frame_get_filename(f),
888  products[i]);
889 
890  cpl_frameset_erase_frame(frames, f);
891  }
892  }
893  }
894 
895  /* Execute */
896  check( uves_invoke_recipe(recipe_id, parameters, frames, make_str(UVES_REDCHAIN_ID), NULL),
897  "Recipe '%s' failed", recipe_id);
898 
899  check(cpl_dfs_update_product_header(frames),"Error updating pipe products' header");
900  if (reclassify)
901  {
902  /* Now re-classify PRODUCT->CALIB to be used in the remaining
903  reduction chain. Before doing that, we have to remove any
904  calibration frame with same tag as a product (such as line tables),
905  in order not to confuse the re-classified products with the
906  previous calibration frames */
907 
908  for (i = 0; i < n_products; i++)
909  {
910  if ((f = cpl_frameset_find(frames, products[i])) != NULL &&
911  cpl_frame_get_group(f) != CPL_FRAME_GROUP_PRODUCT)
912  {
913  uves_msg("Removing %s frame in '%s' from frameset. "
914  "It is not tagged as a product",
915  products[i], cpl_frame_get_filename(f));
916 
917  cpl_frameset_erase_frame(frames, f);
918  }
919  }
920 
921  /*
922  * Re-classify products
923  */
924  for (i = 0; i < n_products; i++)
925  {
926  cpl_frame *found = NULL;
927  int j=0;
928  int nfrm=cpl_frameset_get_size(frames);
929  for (j=0;j<nfrm;j++)
930  {
931  f=cpl_frameset_get_frame(frames,j);
932  if (cpl_frame_get_group(f) == CPL_FRAME_GROUP_PRODUCT)
933  {
934  if (strcmp(cpl_frame_get_tag(f), products[i]) == 0)
935  {
936  found = f;
937  }
938  }
939  }
940 
941  if (found != NULL)
942  {
943  /* Re-classify the product as calibration frames */
944  uves_msg("Re-classifying %s product in '%s' PRODUCT->CALIB",
945  products[i], cpl_frame_get_filename(found));
946 
947  cpl_frame_set_group(found, CPL_FRAME_GROUP_CALIB);
948  }
949  }
950 
951  /*
952  * Remove other products that
953  * are not used later (e.g. BKG_FLAT_xxxx)
954  */
955 
956  int k=0;
957  int nfrm=cpl_frameset_get_size(frames);
958  int nerased=0;
959  for (k=0;k<nfrm-nerased;k++)
960  {
961  f=cpl_frameset_get_frame(frames,k);
962 
963  if (cpl_frame_get_group(f) == CPL_FRAME_GROUP_PRODUCT)
964  {
965  /* Remove this product */
966  uves_msg("Removing product %s in '%s' from frameset. "
967  "Not needed later",
968  cpl_frame_get_tag(f), cpl_frame_get_filename(f));
969 
970  cpl_frameset_erase_frame(frames, f);
971  nerased++;
972 
973  }
974  }
975 
976  } /* if re-classify... */
977 
978  cleanup:
979  return cpl_error_get_code();
980 }
981 
982 
983 /* Retruns true if either frame 1 or frame 2 is not in the
984  provided frame set
985 
986  fixme: reverse the logic of this function, i.e. rename to 'contains'
987 */
988 static bool
989 is_missing(const cpl_frameset *frames, const char *frame1, const char *frame2)
990 {
991  bool result = false;
992  if (cpl_frameset_find_const(frames, frame1) == NULL)
993  {
994  uves_msg("checking for %s... no", frame1);
995  result = true;
996  }
997  else
998  {
999  uves_msg("checking for %s... yes", frame1);
1000  }
1001 
1002  if (frame2 != NULL && strcmp(frame1, frame2) != 0)
1003  {
1004  if (cpl_frameset_find_const(frames, frame2) == NULL)
1005  {
1006  uves_msg("checking for %s... no", frame2);
1007  result = true;
1008  }
1009  else
1010  {
1011  uves_msg("checking for %s... yes", frame2);
1012  }
1013  }
1014 
1015  return result;
1016 }
1017 
1018 
1019 /* Remove input frames (e.g. bias frames) along the way */
1020 static void
1021 remove_input_frame(cpl_frameset *frames, const char *tag)
1022 {
1023  int removed = cpl_frameset_erase(frames, tag);
1024 
1025  if (removed > 0)
1026  {
1027  uves_msg("Removing %d %s frame(s) from frame set", removed, tag);
1028  }
1029 
1030  return;
1031 }
#define check_nomsg(CMD)
Definition: uves_error.h:204
#define uves_msg(...)
Print a message on 'info' or 'debug' level.
Definition: uves_msg.h:119
enum uves_chip uves_chip_get_first(bool blue)
Get first chip for blue or red arm.
Definition: uves_chip.c:92
enum uves_chip uves_chip_get_next(enum uves_chip chip)
Get next chip.
Definition: uves_chip.c:108
#define uves_msg_debug(...)
Print a debug message.
Definition: uves_msg.h:97
const char * uves_string_toupper(char *s)
Convert all lowercase characters in a string into uppercase characters.
Definition: uves_utils.c:1493
#define check(CMD,...)
Definition: uves_error.h:198