GRAVI Pipeline Reference Manual  0.9.7
gravity_vis.c
1 /* $Id: gravity_vis.c,v 1.29 2011/12/3 09:16:12 nazouaoui Exp $
2  *
3  * This file is part of the GRAVI Pipeline
4  * Copyright (C) 2002,2003 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: nazouaoui $
23  * $Date: 2011/12/3 09:16:12 $
24  * $Revision: 1.29 $
25  * $Name: $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include <cpl.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <time.h>
40 
41 #include "gravi_data.h"
42 #include "gravi_pfits.h"
43 #include "gravi_dfs.h"
44 
45 #include "gravi_utils.h"
46 
47 #include "gravi_calib.h"
48 #include "gravi_p2vmred.h"
49 #include "gravi_eop.h"
50 #include "gravi_metrology.h"
51 
52 #include "gravi_signal.h"
53 #include "gravi_vis.h"
54 #include "gravi_tf.h"
55 
56 #include "gravi_preproc.h"
57 
58 /*-----------------------------------------------------------------------------
59  Private function prototypes
60  -----------------------------------------------------------------------------*/
61 
62 static int gravity_vis_create(cpl_plugin *);
63 static int gravity_vis_exec(cpl_plugin *);
64 static int gravity_vis_destroy(cpl_plugin *);
65 static int gravity_vis(cpl_frameset *, const cpl_parameterlist *);
66 
67 /*-----------------------------------------------------------------------------
68  Static variables
69  -----------------------------------------------------------------------------*/
70 static char gravity_vis_short[] = "Compute the visibilities from raw observation of OBJECT.";
71 static char gravity_vis_description[] =
72  "This recipe is associated to the observing template. Its reduces the raw data acquired on calibrator or science targets and computes the uncalibrated visibilities, saved in an OIFITS file. If several OBJECT are provided, the recipe will reduce all of them and merge the resulting data into a single OIFITS. If several SKY_RAW are provided, the recipe reduces the first OBJECT with the first SKY. Then each new OBJECT with the next SKY. When the number of sky is reached, the recipe loops back to first sky (so if the number of SKYs is larger than the number of OBJECTs, the last SKY won't be used). The recipe will reduce the data even if no SKY or no DARK is provided. However this will lead to wrong estimate of the visibility and square visibility of the object. If the DIAMETER_CAT is not provided, the recipe will use the diameter provided in the header to compute the transfer function QC parameters."
73  "\n"
74  "The tag in the DO category can be SINGLE/DUAL and CAL/SCI. They should reflect the mode (SINGLE or DUAL) and the DPR.CATG of the observation (SCIENCE or CALIB). The tag in the PRO.CATG category will be SINGLE/DUAL and CAL/SCI depending on the input tag.\n"
75  GRAVI_RECIPE_INPUT"\n"
76  GRAVI_FLAT_MAP" : flat calibration (PRO.CATG="GRAVI_FLAT_MAP")\n"
77  GRAVI_BAD_MAP" : badpixel calibration (PRO.CATG="GRAVI_BAD_MAP") \n"
78  GRAVI_WAVE_MAP" : wave calibration (PRO.CATG="GRAVI_WAVE_MAP")\n"
79  GRAVI_P2VM_MAP" : p2vm calibration (PRO.CATG="GRAVI_P2VM_MAP")\n"
80  GRAVI_DARK_MAP" : dark calibration (PRO.CATG="GRAVI_DARK_MAP")\n"
81  GRAVI_SINGLE_SCIENCE_RAW" : raw object (DPR.TYPE=OBJECT,SINGLE)\n"
82  GRAVI_SINGLE_SKY_RAW" : raw sky (DPR.TYPE=SKY,SINGLE)\n"
83  GRAVI_DISP_MODEL" (opt) : fiber dispersion model (PRO.CATG="GRAVI_DISP_MODEL")\n"
84  GRAVI_DIAMETER_CAT" (opt) : catalog of diameter (PRO.CATG="GRAVI_DIAMETER_CAT")\n"
85  GRAVI_RECIPE_OUTPUT"\n"
86  GRAVI_VIS_SINGLE_SCIENCE" : OIFITS with uncalibrated visibilities\n"
87  GRAVI_SINGLE_SKY_MAP" (opt) : sky map\n"
88  GRAVI_P2VMRED_SINGLE_SCIENCE" (opt) : intermediate product\n"
89  GRAVI_SPECTRUM" (opt) : intermediate product\n"
90  GRAVI_PREPROC" (opt) : intermediate product\n"
91  "";
92 
93 /*-----------------------------------------------------------------------------
94  Function code
95  -----------------------------------------------------------------------------*/
96 
97 /*----------------------------------------------------------------------------*/
107 /*----------------------------------------------------------------------------*/
108 int cpl_plugin_get_info(cpl_pluginlist * list)
109 {
110  cpl_recipe * recipe = cpl_calloc(1, sizeof *recipe );
111  cpl_plugin * plugin = &recipe->interface;
112 
113  if (cpl_plugin_init(plugin,
114  CPL_PLUGIN_API,
115  GRAVI_BINARY_VERSION,
116  CPL_PLUGIN_TYPE_RECIPE,
117  "gravity_vis",
118  gravity_vis_short,
119  gravity_vis_description,
120  "Nabih Azouaoui, Vincent Lapeyrere, JB. Le Bouquin",
121  PACKAGE_BUGREPORT,
122  gravi_get_license(),
123  gravity_vis_create,
124  gravity_vis_exec,
125  gravity_vis_destroy)) {
126  cpl_msg_error(cpl_func, "Plugin initialization failed");
127  (void)cpl_error_set_where(cpl_func);
128  return 1;
129  }
130 
131  if (cpl_pluginlist_append(list, plugin)) {
132  cpl_msg_error(cpl_func, "Error adding plugin to list");
133  (void)cpl_error_set_where(cpl_func);
134  return 1;
135  }
136 
137  return 0;
138 }
139 
140 /*----------------------------------------------------------------------------*/
148 /*----------------------------------------------------------------------------*/
149 static int gravity_vis_create(cpl_plugin * plugin)
150 {
151  cpl_recipe * recipe;
152  cpl_parameter * p;
153 
154  /* Do not create the recipe if an error code is already set */
155  if (cpl_error_get_code() != CPL_ERROR_NONE) {
156  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
157  cpl_func, __LINE__, cpl_error_get_where());
158  return (int)cpl_error_get_code();
159  }
160 
161  if (plugin == NULL) {
162  cpl_msg_error(cpl_func, "Null plugin");
163  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
164  }
165 
166  /* Verify plugin type */
167  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
168  cpl_msg_error(cpl_func, "Plugin is not a recipe");
169  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
170  }
171 
172  /* Get the recipe */
173  recipe = (cpl_recipe *)plugin;
174 
175  /* Create the parameters list in the cpl_recipe object */
176  recipe->parameters = cpl_parameterlist_new();
177  if (recipe->parameters == NULL) {
178  cpl_msg_error(cpl_func, "Parameter list allocation failed");
179  cpl_ensure_code(0, (int)CPL_ERROR_ILLEGAL_OUTPUT);
180  }
181 
182  /* Fill the parameters list */
183  int isCalib = 0;
184 
185  /* Use static names (output_procatg.fits) */
186  gravi_parameter_add_static_name (recipe->parameters);
187 
188  /* Intermediate files */
189  gravi_parameter_add_biassub_file (recipe->parameters);
190  gravi_parameter_add_spectrum_file (recipe->parameters);
191  gravi_parameter_add_preproc_file (recipe->parameters);
192  gravi_parameter_add_p2vmred_file (recipe->parameters);
193  gravi_parameter_add_astro_file (recipe->parameters);
194 
195  /* Averaging */
196  gravi_parameter_add_average_vis (recipe->parameters);
197 
198  /* Bias-method */
199  gravi_parameter_add_biasmethod (recipe->parameters);
200 
201  /* Extraction */
202  gravi_parameter_add_extract (recipe->parameters);
203 
204  /* Snr */
205  gravi_parameter_add_compute_snr (recipe->parameters, isCalib);
206 
207  /* Rejection */
208  gravi_parameter_add_rejection (recipe->parameters, isCalib);
209 
210  /* Parameters for gravi_compute_vis */
211  gravi_parameter_add_compute_vis (recipe->parameters, isCalib);
212 
213  /* Correct from internal transmission */
214  p = cpl_parameter_new_value ("gravity.vis.flat-flux", CPL_TYPE_BOOL,
215  "Flat the OI_FLUX with instrument transmission recorded in the\n"
216  " input P2VM calibration map. Thus flux is the spectrum recorded\n"
217  " at the detector (FALSE); or the spectrum at the instrument entrance (TRUE).",
218  "gravity.vis", FALSE);
219  cpl_parameter_set_alias (p, CPL_PARAMETER_MODE_CLI, "flat-flux");
220  cpl_parameter_disable (p, CPL_PARAMETER_MODE_ENV);
221  cpl_parameterlist_append (recipe->parameters, p);
222 
223  /* Average sky */
224  p = cpl_parameter_new_value ("gravity.preproc.average-sky", CPL_TYPE_BOOL,
225  "Average the SKYs into a master SKY. If FALSE, the recipe loops\n "
226  "over the SKY to reduce each OBJECT with a different SKY",
227  "gravity.preproc", FALSE);
228  cpl_parameter_set_alias (p, CPL_PARAMETER_MODE_CLI, "average-sky");
229  cpl_parameter_disable (p, CPL_PARAMETER_MODE_ENV);
230  cpl_parameterlist_append (recipe->parameters, p);
231 
232  return 0;
233 }
234 
235 /*----------------------------------------------------------------------------*/
241 /*----------------------------------------------------------------------------*/
242 static int gravity_vis_exec(cpl_plugin * plugin)
243 {
244 
245  cpl_recipe * recipe;
246  int recipe_status;
247  cpl_errorstate initial_errorstate = cpl_errorstate_get();
248 
249 
250  /* Return immediately if an error code is already set */
251  if (cpl_error_get_code() != CPL_ERROR_NONE) {
252  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
253  cpl_func, __LINE__, cpl_error_get_where());
254  return (int)cpl_error_get_code();
255  }
256 
257  if (plugin == NULL) {
258  cpl_msg_error(cpl_func, "Null plugin");
259  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
260  }
261 
262  /* Verify plugin type */
263  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
264  cpl_msg_error(cpl_func, "Plugin is not a recipe");
265  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
266  }
267 
268  /* Get the recipe */
269  recipe = (cpl_recipe *)plugin;
270 
271  /* Verify parameter and frame lists */
272  if (recipe->parameters == NULL) {
273  cpl_msg_error(cpl_func, "Recipe invoked with NULL parameter list");
274  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
275  }
276  if (recipe->frames == NULL) {
277  cpl_msg_error(cpl_func, "Recipe invoked with NULL frame set");
278  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
279  }
280 
281  /* Invoke the recipe */
282  recipe_status = gravity_vis(recipe->frames, recipe->parameters);
283 
284  /* Ensure DFS-compliance of the products */
285  if (cpl_dfs_update_product_header(recipe->frames)) {
286  if (!recipe_status){
287  recipe_status = (int)cpl_error_get_code();
288  }
289  }
290 
291  if (!cpl_errorstate_is_equal(initial_errorstate)) {
292  /* Dump the error history since recipe execution start.
293  At this point the recipe cannot recover from the error */
294  cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);
295  }
296 
297  return recipe_status;
298 }
299 
300 /*----------------------------------------------------------------------------*/
306 /*----------------------------------------------------------------------------*/
307 static int gravity_vis_destroy(cpl_plugin * plugin)
308 {
309  cpl_recipe * recipe;
310 
311  if (plugin == NULL) {
312  cpl_msg_error(cpl_func, "Null plugin");
313  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
314  }
315 
316  /* Verify plugin type */
317  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
318  cpl_msg_error(cpl_func, "Plugin is not a recipe");
319  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
320  }
321 
322  /* Get the recipe */
323  recipe = (cpl_recipe *)plugin;
324 
325  cpl_parameterlist_delete(recipe->parameters);
326 
327  return 0;
328 }
329 
330 
331 /*----------------------------------------------------------------------------*/
339 /*----------------------------------------------------------------------------*/
340 static int gravity_vis(cpl_frameset * frameset,
341  const cpl_parameterlist * parlist)
342 {
343  cpl_frameset * recipe_frameset=NULL, * wavecalib_frameset=NULL, * dark_frameset=NULL,
344  * darkcalib_frameset=NULL, * sky_frameset=NULL, * flatcalib_frameset=NULL, * p2vmcalib_frameset=NULL,
345  * badcalib_frameset=NULL, *used_frameset=NULL, * current_frameset=NULL, * dispcalib_frameset=NULL,
346  * diamcat_frameset = NULL, *eop_frameset = NULL;
347 
348  cpl_frame * frame=NULL;
349 
350  const char * frame_tag=NULL;
351  char * proCatg = NULL, * mode=NULL, * redCatg = NULL, * skyCatg = NULL;
352 
353  gravi_data * p2vm_map=NULL, * data=NULL, * wave_map=NULL, * dark_map=NULL,
354  * profile_map=NULL, * badpix_map=NULL, * preproc_data=NULL, * p2vmred_data=NULL, * tmpvis_data=NULL,
355  * vis_data=NULL, * disp_map=NULL, * diamcat_data=NULL, *eop_map=NULL;
356  gravi_data ** sky_maps = NULL;
357 
358  int nb_frame, nb_sky, isky;
359 
360  /* Message */
361  gravity_print_banner ();
362  cpl_msg_set_time_on();
363  cpl_msg_set_component_on();
364  gravi_msg_function_start(1);
365 
366  cpl_ensure_code(gravi_dfs_set_groups(frameset) == CPL_ERROR_NONE,
367  cpl_error_get_code()) ;
368 
369  /* Dispatch the frameset */
370  p2vmcalib_frameset = gravi_frameset_extract_p2vm_map (frameset);
371  darkcalib_frameset = gravi_frameset_extract_dark_map (frameset);
372  wavecalib_frameset = gravi_frameset_extract_wave_map (frameset);
373  dark_frameset = gravi_frameset_extract_dark_data (frameset);
374  flatcalib_frameset = gravi_frameset_extract_flat_map (frameset);
375  badcalib_frameset = gravi_frameset_extract_bad_map (frameset);
376  dispcalib_frameset = gravi_frameset_extract_disp_map (frameset);
377  diamcat_frameset = gravi_frameset_extract_diamcat_map (frameset);
378  eop_frameset = gravi_frameset_extract_eop_map (frameset);
379 
380  recipe_frameset = gravi_frameset_extract_fringe_data (frameset);
381  sky_frameset = gravi_frameset_extract_sky_data (frameset);
382 
383  /* To use this recipe the frameset must contain the p2vm, wave and
384  * gain calibration file. */
385  if ( cpl_frameset_get_size (p2vmcalib_frameset) !=1 ||
386  cpl_frameset_get_size (wavecalib_frameset) !=1 ||
387  cpl_frameset_get_size (flatcalib_frameset) !=1 ||
388  cpl_frameset_get_size (badcalib_frameset) != 1 ||
389  cpl_frameset_get_size (recipe_frameset) < 1 ||
390  (cpl_frameset_is_empty (dark_frameset) &&
391  cpl_frameset_is_empty (darkcalib_frameset) &&
392  cpl_frameset_is_empty (sky_frameset)) ) {
393  cpl_error_set_message (cpl_func, CPL_ERROR_ILLEGAL_INPUT,
394  "Illegal number of P2VM, FLAT, WAVE, BAD, DARK or SKY, OBJECT file on the frameset");
395  goto cleanup;
396  }
397 
398  /* Insert calibration frame into the used frameset */
399  used_frameset = cpl_frameset_new();
400 
401  /*
402  * Identify the DARK in the input frameset
403  */
404 
405  if (!cpl_frameset_is_empty (dark_frameset)) {
406 
407  frame = cpl_frameset_get_position (dark_frameset, 0);
408  data = gravi_data_load_rawframe (frame, used_frameset);
409  gravi_data_detector_cleanup (data, parlist);
410 
411  /* Compute dark */
412  dark_map = gravi_compute_dark (data);
413  FREE (gravi_data_delete, data);
414 
415  CPLCHECK_CLEAN ("Could not compute the DARK map");
416 
417  /* Save the dark map */
418  gravi_data_save_new (dark_map, frameset, NULL, parlist,
419  NULL, frame, "gravity_vis",
420  NULL, GRAVI_DARK_MAP);
421 
422  CPLCHECK_CLEAN ("Could not save the DARK map");
423  }
424  else if (!cpl_frameset_is_empty (darkcalib_frameset)) {
425 
426  frame = cpl_frameset_get_position (darkcalib_frameset, 0);
427  dark_map = gravi_data_load_frame (frame, used_frameset);
428 
429  CPLCHECK_CLEAN ("Could not load the DARK map");
430  }
431  else
432  cpl_msg_info (cpl_func, "There is no DARK in the frame set");
433 
434  /* Identify the BAD in the input frameset */
435  frame = cpl_frameset_get_position (badcalib_frameset, 0);
436  badpix_map = gravi_data_load_frame (frame, used_frameset);
437 
438  /* Identify the FLAT in the input frameset */
439  frame = cpl_frameset_get_position (flatcalib_frameset, 0);
440  profile_map = gravi_data_load_frame (frame, used_frameset);
441 
442  /* Identify the WAVE in the input frameset */
443  frame = cpl_frameset_get_position (wavecalib_frameset, 0);
444  wave_map = gravi_data_load_frame (frame, used_frameset);
445 
446  /* Identify the P2VM in the input frameset */
447  frame = cpl_frameset_get_position (p2vmcalib_frameset, 0);
448  p2vm_map = gravi_data_load_frame (frame, used_frameset);
449 
450  /* Load the DISP_MODEL in the input frameset */
451  if (!cpl_frameset_is_empty (dispcalib_frameset)) {
452  frame = cpl_frameset_get_position (dispcalib_frameset, 0);
453  disp_map = gravi_data_load_frame (frame, used_frameset);
454  }
455  else
456  cpl_msg_info (cpl_func, "There is no DISP_MODEL in the frameset");
457 
458  /* Load the EOP_PARAM */
459  if ( !cpl_frameset_is_empty (eop_frameset) ) {
460  frame = cpl_frameset_get_position (eop_frameset, 0);
461  eop_map = gravi_data_load_frame (frame, used_frameset);
462  }
463  else
464  cpl_msg_info (cpl_func, "There is no EOP_PARAM in the frameset");
465 
466  /* Load the DIAMETER_CAT */
467  if ( !cpl_frameset_is_empty (diamcat_frameset) ) {
468  frame = cpl_frameset_get_position (diamcat_frameset, 0);
469  diamcat_data = gravi_data_load_frame (frame, used_frameset);
470  }
471  else
472  cpl_msg_info (cpl_func, "There is no DIAMETER_CAT in the frameset");
473 
474 
475  CPLCHECK_CLEAN ("Error while loading the calibration maps");
476 
477  /*
478  * Select the PRO CATG (based on first frame)
479  */
480 
481  frame_tag = cpl_frame_get_tag (cpl_frameset_get_position (recipe_frameset, 0));
482 
483  if ((strcmp(frame_tag, GRAVI_DUAL_CALIB_RAW) == 0)) {
484  redCatg = cpl_sprintf (GRAVI_P2VMRED_DUAL_CALIB);
485  proCatg = cpl_sprintf (GRAVI_VIS_DUAL_CALIB);
486  skyCatg = cpl_sprintf (GRAVI_DUAL_SKY_MAP);
487  mode = cpl_sprintf ("gravi_dual");
488  }
489  else if ((strcmp(frame_tag, GRAVI_DUAL_SCIENCE_RAW) == 0)) {
490  redCatg = cpl_sprintf (GRAVI_P2VMRED_DUAL_SCIENCE);
491  proCatg = cpl_sprintf (GRAVI_VIS_DUAL_SCIENCE);
492  skyCatg = cpl_sprintf (GRAVI_DUAL_SKY_MAP);
493  mode = cpl_sprintf ("gravi_dual");
494  }
495  else if ((strcmp(frame_tag, GRAVI_SINGLE_CALIB_RAW) == 0)) {
496  redCatg = cpl_sprintf (GRAVI_P2VMRED_SINGLE_CALIB);
497  proCatg = cpl_sprintf (GRAVI_VIS_SINGLE_CALIB);
498  skyCatg = cpl_sprintf (GRAVI_SINGLE_SKY_MAP);
499  mode = cpl_sprintf ("gravi_single");
500  }
501  else if ((strcmp(frame_tag, GRAVI_SINGLE_SCIENCE_RAW) == 0)) {
502  redCatg = cpl_sprintf (GRAVI_P2VMRED_SINGLE_SCIENCE);
503  proCatg = cpl_sprintf (GRAVI_VIS_SINGLE_SCIENCE);
504  skyCatg = cpl_sprintf (GRAVI_SINGLE_SKY_MAP);
505  mode = cpl_sprintf ("gravi_single");
506  }
507  else {
508  cpl_error_set_message (cpl_func, CPL_ERROR_ILLEGAL_INPUT,
509  "Cannot recognize the input DO.CATG");
510  goto cleanup;
511  }
512 
513  cpl_msg_info (cpl_func,"Mode of the first frame is: %s (will be used for all frames)", mode);
514 
515  /*
516  * Mode for the SKY
517  */
518  int averageSky = gravi_param_get_bool (parlist,"gravity.preproc.average-sky");
519 
520  /*
521  * Loop on input SKY frames to be reduced
522  */
523  nb_sky = cpl_frameset_get_size (sky_frameset);
524  sky_maps = cpl_calloc (CPL_MAX(nb_sky,1), sizeof(gravi_data*));
525 
526  for (int isky = 0; isky < nb_sky; isky++){
527 
528  /* Load the raw SKY */
529  cpl_msg_info (cpl_func, " ***** SKY %d over %d ***** ", isky+1, nb_sky);
530  frame = cpl_frameset_get_position (sky_frameset, isky);
531  data = gravi_data_load_rawframe (frame, used_frameset);
532  gravi_data_detector_cleanup (data, parlist);
533 
534  /* Compute the SKY map */
535  sky_maps[isky] = gravi_compute_dark (data);
536  FREE (gravi_data_delete, data);
537 
538  CPLCHECK_CLEAN ("Error while computing the sky_map");
539 
540  /* Save the SKY map */
541  if (averageSky == 0) {
542  gravi_data_save_new (sky_maps[isky], frameset, NULL, parlist,
543  NULL, frame, "gravity_vis",
544  NULL, skyCatg);
545  CPLCHECK_CLEAN ("Could not save the sky");
546  }
547  }
548 
549  /*
550  * Average the sky if requested
551  */
552 
553  if (averageSky == 1) {
554  cpl_msg_info (cpl_func, "Do a MASTER SKY from the %d skys", nb_sky);
555 
556  gravi_data * msky_map;
557  msky_map = gravi_average_dark (sky_maps, nb_sky);
558  CPLCHECK_CLEAN ("Cannot do master sky");
559 
560  gravi_data_save_new (msky_map, frameset, NULL, parlist, sky_frameset,
561  cpl_frameset_get_position (sky_frameset, 0),
562  "gravity_vis", NULL, skyCatg);
563  CPLCHECK_CLEAN ("Cannot save master sky");
564 
565  /* Add all sky to used_frameset, and move pointers */
566  cpl_frameset_join (used_frameset, sky_frameset);
567  for (int isky = 0; isky < nb_sky; isky++)
568  FREE (gravi_data_delete, sky_maps[isky]);
569  sky_maps[0] = msky_map;
570  nb_sky = 1;
571  }
572 
573  /*
574  * Loop on input RAW frames to be reduced
575  */
576 
577  nb_frame = cpl_frameset_get_size (recipe_frameset);
578 
579  for (int ivis = 0; ivis < nb_frame; ivis++){
580  current_frameset = cpl_frameset_duplicate (used_frameset);
581 
582  cpl_msg_info (cpl_func, " ***** OBJECT %d over %d ***** ", ivis+1, nb_frame);
583 
584  /*
585  * Identify the SKY for this OBJECT
586  */
587  isky = nb_sky>0 ? ivis % nb_sky : 0;
588 
589  if (nb_sky == 0) {
590  /* No SKY */
591  cpl_msg_info (cpl_func, "There is no SKY in the frameset");
592  }
593  else if (averageSky) {
594  /* Use master SKY already computed, already in frameset */
595  cpl_msg_info (cpl_func, "Use MASTER SKY (already reduced)");
596  }
597  else {
598  /* SKY already computed, add in the used_frameset */
599  cpl_msg_info (cpl_func, "Use SKY %i over %i (already reduced)", isky+1, nb_sky);
600  frame = cpl_frameset_get_position (sky_frameset, isky);
601 
602  /* Add this frame to the current_frameset as well */
603  cpl_frameset_insert (current_frameset, cpl_frame_duplicate (frame));
604  }
605 
606  /*
607  * Reduce the OBJECT
608  */
609 
610  frame = cpl_frameset_get_position (recipe_frameset, ivis);
611  data = gravi_data_load_rawframe (frame, current_frameset);
612  gravi_data_detector_cleanup (data, parlist);
613 
614  /* Option save the preproc file */
615  if (gravi_param_get_bool (parlist,"gravity.dfs.bias-subtracted-file")) {
616 
617  gravi_data_save_new (data, frameset, NULL, parlist,
618  current_frameset, frame, "gravity_vis",
619  NULL, "BIAS_SUBTRACTED");
620 
621  CPLCHECK_CLEAN ("Cannot save the BIAS_SUBTRACTED product");
622  }
623 
624 
625  /* Check the shutters */
626  if ( !gravi_data_check_shutter_open (data) ) {
627  cpl_msg_warning (cpl_func, "Shutter problem in the OBJECT");
628  }
629 
630  /* Extract spectrum */
631  preproc_data = gravi_extract_spectrum (data, profile_map, dark_map, badpix_map,
632  sky_maps[isky], parlist);
633  CPLCHECK_CLEAN ("Cannot extract spectrum");
634 
635  /* Option save the spectrum file */
636  if (gravi_param_get_bool (parlist,"gravity.dfs.spectrum-file")) {
637  gravi_data_save_new (preproc_data, frameset, NULL, parlist,
638  current_frameset, frame, "gravity_vis",
639  NULL, GRAVI_SPECTRUM);
640  CPLCHECK_CLEAN ("Cannot save the SPECTRUM product");
641  }
642 
643  /* Rescale to common wavelength */
644  gravi_align_spectrum (preproc_data, wave_map, p2vm_map);
645  CPLCHECK_CLEAN ("Cannot re-interpolate spectrum");
646 
647  /* Option save the preproc file */
648  if (gravi_param_get_bool (parlist,"gravity.dfs.preproc-file")) {
649  gravi_data_save_new (preproc_data, frameset, NULL, parlist,
650  current_frameset, frame, "gravity_vis",
651  NULL, GRAVI_PREPROC);
652  CPLCHECK_CLEAN ("Cannot save the PREPROC product");
653  }
654 
655  /* Move extensions from raw_data and delete it */
656  gravi_data_move_ext (preproc_data, data, GRAVI_ARRAY_GEOMETRY_EXT);
657  gravi_data_move_ext (preproc_data, data, GRAVI_OPTICAL_TRAIN_EXT);
658  gravi_data_move_ext (preproc_data, data, GRAVI_OPDC_EXT);
659  gravi_data_move_ext (preproc_data, data, GRAVI_FDDL_EXT);
660  gravi_data_move_ext (preproc_data, data, GRAVI_METROLOGY_EXT);
661  FREE (gravi_data_delete, data);
662  CPLCHECK_CLEAN ("Cannot move ext");
663 
664  /* Compute the flux and visibilities for each telescope and
665  * per acquisition with the P2VM applied to preproc_data */
666  p2vmred_data = gravi_compute_p2vmred (preproc_data, p2vm_map, mode, parlist);
667  CPLCHECK_CLEAN ("Cannot apply p2vm to the preproc data");
668 
669  /* Move extensions and delete preproc */
670  gravi_data_move_ext (p2vmred_data, preproc_data, GRAVI_METROLOGY_EXT);
671  gravi_data_move_ext (p2vmred_data, preproc_data, GRAVI_FDDL_EXT);
672  gravi_data_move_ext (p2vmred_data, preproc_data, GRAVI_OPDC_EXT);
673  FREE (gravi_data_delete, preproc_data);
674  CPLCHECK_CLEAN ("Cannot delete preproc");
675 
676  /* Reduce the OPDC table */
677  gravi_compute_opdc_state (p2vmred_data);
678  CPLCHECK_CLEAN ("Cannot reduce OPDC");
679 
680  /* Reduce the metrology into OI_VIS_MET */
681  gravi_metrology_reduce (p2vmred_data);
682  CPLCHECK_CLEAN ("Cannot reduce metrology");
683 
684  /* Compute the uv and pointing directions with ERFA */
685  gravi_compute_uv (p2vmred_data, eop_map);
686  CPLCHECK_CLEAN ("Cannot compute uv");
687 
688  gravi_compute_pointing (p2vmred_data, eop_map);
689  CPLCHECK_CLEAN ("Cannot compute pointing");
690 
691  /* Compute the QC0 about tau0 from piezo signals */
692  gravi_compute_tau0 (p2vmred_data);
693 
694  /* Compute the SNR_BOOT and GDELAY_BOOT */
695  gravi_compute_snr (p2vmred_data, parlist);
696  CPLCHECK_MSG ("Cannot compute SNR");
697 
698  /* Compute the signals for averaging */
699  gravi_compute_signals (p2vmred_data, disp_map, parlist);
700  CPLCHECK_MSG ("Cannot compute signals");
701 
702  /* Compute rejection flags for averaging */
703  gravi_compute_rejection (p2vmred_data, parlist);
704  CPLCHECK_MSG ("Cannot compute rejection flags signals");
705 
706  /* Visibility and flux are averaged and the followings
707  * are saved in Visibility data in tables VIS, VIS2 and T3 */
708  tmpvis_data = gravi_compute_vis (p2vmred_data, parlist);
709  CPLCHECK_CLEAN ("Cannot average the P2VMRED frames into VIS");
710 
711  /* Merge with already existing */
712  if (ivis == 0) {
713  vis_data = tmpvis_data; tmpvis_data = NULL;
714  }
715  else {
716  cpl_msg_info (cpl_func,"Merge with previous OI_VIS");
717  gravi_data_append (vis_data, tmpvis_data, 1);
718  FREE (gravi_data_delete, tmpvis_data);
719  }
720 
721  /* Save the p2vmreduced file */
722  if (gravi_param_get_bool (parlist,"gravity.dfs.p2vmred-file")) {
723 
724  gravi_data_save_new (p2vmred_data, frameset, NULL, parlist,
725  current_frameset, frame, "gravity_vis", NULL, redCatg);
726 
727  CPLCHECK_CLEAN ("Cannot save the P2VMREDUCED product");
728  }
729 
730  /* Save the astro file, which is a lighter version of the p2vmreduced */
731  if (gravi_param_get_bool (parlist,"gravity.dfs.astro-file")) {
732 
733  gravi_data_clean_for_astro (p2vmred_data);
734  gravi_data_save_new (p2vmred_data, frameset, NULL, parlist,
735  current_frameset, frame, "gravity_vis",
736  NULL, GRAVI_ASTROREDUCED);
737 
738  CPLCHECK_CLEAN ("Cannot save the ASTROREDUCED product");
739  }
740 
741  cpl_msg_info (cpl_func,"Free the p2vmreduced");
742  FREE (cpl_frameset_delete, current_frameset);
743  FREE (gravi_data_delete, p2vmred_data);
744 
745  }
746  /* End loop on the input files to reduce */
747 
748  /* Compute the QC parameters of the TF
749  * FIXME: compute QC TF only for CALIB star */
750  gravi_compute_tf_qc (vis_data, diamcat_data);
751 
752  /* Compute the pointing directions with ERFA in the averaged data */
753  gravi_compute_pointing (vis_data, eop_map);
754 
755  /* Eventually flatten the OI_FLUX */
756  if (gravi_param_get_bool (parlist, "gravity.vis.flat-flux")) {
757 
758  cpl_msg_info (cpl_func, "Flatten the FLUX with the internal P2VM spectrum");
759  gravi_flat_flux (vis_data, p2vm_map);
760  CPLCHECK_CLEAN ("Cannot flat the OI_FLUX");
761 
762  } else {
763  cpl_msg_info (cpl_func, "Don't flatten the FLUX with the internal P2VM spectrum");
764  }
765 
766  /* Perform the normalisation of the SC vis2 and visamp
767  * to match those of the FT */
768  if (!strcmp (gravi_param_get_string (parlist, "gravity.vis.vis-correction"), "FORCE")) {
769 
770  cpl_msg_info (cpl_func, "Align the SC visibilities on the FT");
771  gravi_normalize_sc_to_ft (vis_data);
772 
773  } else {
774  cpl_msg_info (cpl_func, "Don't align the SC visibilities on the FT");
775  }
776 
777  /* Co-add the observations if requested */
778  if (gravi_param_get_bool (parlist, "gravity.postprocess.average-vis")) {
779  gravi_average_vis (vis_data);
780 
781  } else {
782  cpl_msg_info (cpl_func, "Don't average the different observation (if any)");
783  }
784 
785  /* Recompute the TIME column from the MJD column
786  * in all OIFITS tables to follow standard */
787  gravi_vis_mjd_to_time (vis_data);
788 
789  /* Save the output data file based on the first frame of the frameset */
790  cpl_frameset_join (used_frameset, recipe_frameset);
791  frame = cpl_frameset_get_position (recipe_frameset, 0);
792 
793  gravi_data_save_new (vis_data, frameset, NULL, parlist,
794  used_frameset, frame, "gravity_vis", NULL, proCatg);
795 
796  CPLCHECK_CLEAN ("Cannot save the VIS product");
797 
798  /* Terminate the function */
799  goto cleanup;
800 
801 cleanup:
802  /* Deallocation of all variables */
803  cpl_msg_info(cpl_func,"Memory cleanup");
804 
805  FREELOOP (gravi_data_delete,sky_maps,nb_sky);
806  FREE (gravi_data_delete,dark_map);
807  FREE (gravi_data_delete,data);
808  FREE (gravi_data_delete,preproc_data);
809  FREE (gravi_data_delete,profile_map);
810  FREE (gravi_data_delete,disp_map);
811  FREE (gravi_data_delete,wave_map);
812  FREE (gravi_data_delete,badpix_map);
813  FREE (gravi_data_delete,p2vm_map);
814  FREE (gravi_data_delete,p2vmred_data);
815  FREE (gravi_data_delete,vis_data);
816  FREE (gravi_data_delete,tmpvis_data);
817  FREE (gravi_data_delete,diamcat_data);
818  FREE (gravi_data_delete,eop_map);
819  FREE (cpl_frameset_delete,darkcalib_frameset);
820  FREE (cpl_frameset_delete,wavecalib_frameset);
821  FREE (cpl_frameset_delete,flatcalib_frameset);
822  FREE (cpl_frameset_delete,badcalib_frameset);
823  FREE (cpl_frameset_delete,p2vmcalib_frameset);
824  FREE (cpl_frameset_delete,dark_frameset);
825  FREE (cpl_frameset_delete,diamcat_frameset);
826  FREE (cpl_frameset_delete,sky_frameset);
827  FREE (cpl_frameset_delete,dispcalib_frameset);
828  FREE (cpl_frameset_delete,eop_frameset);
829  FREE (cpl_frameset_delete,recipe_frameset);
830  FREE (cpl_frameset_delete,current_frameset);
831  FREE (cpl_frameset_delete,used_frameset);
832  FREE (cpl_free,proCatg);
833  FREE (cpl_free,redCatg);
834  FREE (cpl_free,skyCatg);
835  FREE (cpl_free,mode);
836 
837  gravi_msg_function_exit(1);
838  return (int)cpl_error_get_code();
839 }