GRAVI Pipeline Reference Manual  0.9.6
gravity_viscal.c
1 /* $Id: gravity_viscal.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 <math.h>
40 #include <time.h>
41 
42 #include "gravi_utils.h"
43 #include "gravi_pfits.h"
44 #include "gravi_data.h"
45 #include "gravi_dfs.h"
46 #include "gravi_calib.h"
47 #include "gravi_p2vmred.h"
48 #include "gravi_vis.h"
49 #include "gravi_tf.h"
50 
51 /*-----------------------------------------------------------------------------
52  Private function prototypes
53  -----------------------------------------------------------------------------*/
54 
55 static int gravity_viscal_create(cpl_plugin *);
56 static int gravity_viscal_exec(cpl_plugin *);
57 static int gravity_viscal_destroy(cpl_plugin *);
58 static int gravity_viscal(cpl_frameset *, const cpl_parameterlist *);
59 
60 /*-----------------------------------------------------------------------------
61  Static variables
62  -----------------------------------------------------------------------------*/
63 
64 static char gravity_viscal_short[] = "Calibrate visibilities from the transfer function.";
65 static char gravity_viscal_description[] =
66  "This recipe calibrates the visibilities acquired on science target using visibilities acquired on calibrator target. If the DIAMETER_CAT is not provided, the recipe will use the diameter provided in the header to compute the transfer function QC parameters. The corresponding keywords are INS.SOBJ.DIAMETER and FT.ROBJ.DIAMETER. The OI_FLUX data are not yet calibrated."
67  "\n"
68  "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"
69  GRAVI_RECIPE_INPUT"\n"
70  GRAVI_VIS_SINGLE_SCIENCE" (>=1) : visibilities on sciences\n"
71  GRAVI_VIS_SINGLE_CALIB" (>=1) : visibilities on calibrators\n"
72  GRAVI_DIAMETER_CAT" (opt) : catalog of diameter\n"
73  GRAVI_RECIPE_OUTPUT"\n"
74  GRAVI_VIS_SINGLE_CALIBRATED" : calibrated science visibilities\n"
75  GRAVI_TF_SINGLE_CALIB" : Transfer Function (TF) estimated on calibrators\n"
76  GRAVI_TF_SINGLE_SCIENCE" : TF interpolated at the time of sciences\n"
77  "";
78 
79 /*-----------------------------------------------------------------------------
80  Function code
81  -----------------------------------------------------------------------------*/
82 
83 /*----------------------------------------------------------------------------*/
93 /*----------------------------------------------------------------------------*/
94 int cpl_plugin_get_info(cpl_pluginlist * list)
95 {
96  cpl_recipe * recipe = cpl_calloc(1, sizeof *recipe );
97  cpl_plugin * plugin = &recipe->interface;
98 
99  if (cpl_plugin_init(plugin,
100  CPL_PLUGIN_API,
101  GRAVI_BINARY_VERSION,
102  CPL_PLUGIN_TYPE_RECIPE,
103  "gravity_viscal",
104  gravity_viscal_short,
105  gravity_viscal_description,
106  "Nabih Azouaoui, Vincent Lapeyrere, JB. Le Bouquin",
107  PACKAGE_BUGREPORT,
108  gravi_get_license(),
109  gravity_viscal_create,
110  gravity_viscal_exec,
111  gravity_viscal_destroy)) {
112  cpl_msg_error(cpl_func, "Plugin initialization failed");
113  (void)cpl_error_set_where(cpl_func);
114  return 1;
115  }
116 
117  if (cpl_pluginlist_append(list, plugin)) {
118  cpl_msg_error(cpl_func, "Error adding plugin to list");
119  (void)cpl_error_set_where(cpl_func);
120  return 1;
121  }
122 
123  return 0;
124 }
125 
126 /*----------------------------------------------------------------------------*/
134 /*----------------------------------------------------------------------------*/
135 static int gravity_viscal_create(cpl_plugin * plugin)
136 {
137  cpl_recipe * recipe;
138  cpl_parameter * p;
139 
140  /* Do not create the recipe if an error code is already set */
141  if (cpl_error_get_code() != CPL_ERROR_NONE) {
142  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
143  cpl_func, __LINE__, cpl_error_get_where());
144  return (int)cpl_error_get_code();
145  }
146 
147  if (plugin == NULL) {
148  cpl_msg_error(cpl_func, "Null plugin");
149  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
150  }
151 
152  /* Verify plugin type */
153  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
154  cpl_msg_error(cpl_func, "Plugin is not a recipe");
155  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
156  }
157 
158  /* Get the recipe */
159  recipe = (cpl_recipe *)plugin;
160 
161  /* Create the parameters list in the cpl_recipe object */
162  recipe->parameters = cpl_parameterlist_new();
163  if (recipe->parameters == NULL) {
164  cpl_msg_error(cpl_func, "Parameter list allocation failed");
165  cpl_ensure_code(0, (int)CPL_ERROR_ILLEGAL_OUTPUT);
166  }
167 
168  /* Fill the parameters list */
169  gravi_parameter_add_static_name (recipe->parameters);
170 
171  /* delta-time */
172  p = cpl_parameter_new_value ("gravity.viscal.delta-time-calib", CPL_TYPE_DOUBLE,
173  "Delta time to interpolate the TF [s]",
174  "gravity.viscal", 3600.0);
175  cpl_parameter_set_alias (p, CPL_PARAMETER_MODE_CLI, "delta-time-calib");
176  cpl_parameter_disable (p, CPL_PARAMETER_MODE_ENV);
177  cpl_parameterlist_append (recipe->parameters, p);
178 
179  /* force-calib */
180  p = cpl_parameter_new_value ("gravity.viscal.force-calib", CPL_TYPE_BOOL,
181  "Force the calibration, don't check setup",
182  "gravity.viscal", FALSE);
183  cpl_parameter_set_alias (p, CPL_PARAMETER_MODE_CLI, "force-calib");
184  cpl_parameter_disable (p, CPL_PARAMETER_MODE_ENV);
185  cpl_parameterlist_append (recipe->parameters, p);
186 
187  return 0;
188 }
189 
190 /*----------------------------------------------------------------------------*/
196 /*----------------------------------------------------------------------------*/
197 static int gravity_viscal_exec(cpl_plugin * plugin)
198 {
199 
200  cpl_recipe * recipe;
201  int recipe_status;
202  cpl_errorstate initial_errorstate = cpl_errorstate_get();
203 
204  /* Return immediately if an error code is already set */
205  if (cpl_error_get_code() != CPL_ERROR_NONE) {
206  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
207  cpl_func, __LINE__, cpl_error_get_where());
208  return (int)cpl_error_get_code();
209  }
210 
211  if (plugin == NULL) {
212  cpl_msg_error(cpl_func, "Null plugin");
213  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
214  }
215 
216  /* Verify plugin type */
217  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
218  cpl_msg_error(cpl_func, "Plugin is not a recipe");
219  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
220  }
221 
222  /* Get the recipe */
223  recipe = (cpl_recipe *)plugin;
224 
225  /* Verify parameter and frame lists */
226  if (recipe->parameters == NULL) {
227  cpl_msg_error(cpl_func, "Recipe invoked with NULL parameter list");
228  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
229  }
230  if (recipe->frames == NULL) {
231  cpl_msg_error(cpl_func, "Recipe invoked with NULL frame set");
232  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
233  }
234 
235  /* Invoke the recipe */
236  recipe_status = gravity_viscal(recipe->frames, recipe->parameters);
237 
238  /* Ensure DFS-compliance of the products */
239 
240  if (cpl_dfs_update_product_header(recipe->frames)) {
241  if (!recipe_status){
242  recipe_status = (int)cpl_error_get_code();
243  }
244  }
245 
246  if (!cpl_errorstate_is_equal(initial_errorstate)) {
247  /* Dump the error history since recipe execution start.
248  At this point the recipe cannot recover from the error */
249  cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);
250  }
251 
252  return recipe_status;
253 }
254 
255 /*----------------------------------------------------------------------------*/
261 /*----------------------------------------------------------------------------*/
262 static int gravity_viscal_destroy(cpl_plugin * plugin)
263 {
264  cpl_recipe * recipe;
265 
266  if (plugin == NULL) {
267  cpl_msg_error(cpl_func, "Null plugin");
268  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
269  }
270 
271  /* Verify plugin type */
272  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
273  cpl_msg_error(cpl_func, "Plugin is not a recipe");
274  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
275  }
276 
277  /* Get the recipe */
278  recipe = (cpl_recipe *)plugin;
279 
280  cpl_parameterlist_delete(recipe->parameters);
281 
282  return 0;
283 }
284 
285 
286 /*----------------------------------------------------------------------------*/
294 /*----------------------------------------------------------------------------*/
295 static int gravity_viscal(cpl_frameset * frameset,
296  const cpl_parameterlist * parlist)
297 {
298  cpl_frameset * vis_calib_frameset = NULL, * vis_sci_frameset = NULL, *current_frameset = NULL;
299  cpl_frameset * tf_calib_frameset = NULL, * used_frameset = NULL, * diamcat_frameset = NULL;
300  cpl_frame * frame = NULL;
301 
302  cpl_propertylist * applist = NULL;
303 
304  cpl_errorstate errorstate;
305 
306  gravi_data ** vis_calibs = NULL, *vis_calib = NULL, * zero_data = NULL, * tf_science = NULL;
307  gravi_data * calibrated = NULL, * vis_data = NULL, * diamcat_data = NULL;
308 
309  int data_mode, nb_frame_tf = 0, nb_frame_calib = 0, nb_frame_sci, i, j, nb_calib = 0;
310 
311  /* Message */
312  gravity_print_banner ();
313  cpl_msg_set_time_on();
314  cpl_msg_set_component_on();
315  gravi_msg_function_start(1);
316 
317  /* Identify the RAW and CALIB frames in the input frameset */
318  cpl_ensure_code(gravi_dfs_set_groups(frameset) == CPL_ERROR_NONE,
319  cpl_error_get_code());
320 
321  /* Extract a set of vis_calib and vis_sci data frameset */
322  vis_calib_frameset = gravi_frameset_extract_vis_calib (frameset);
323  vis_sci_frameset = gravi_frameset_extract_vis_science (frameset);
324  tf_calib_frameset = gravi_frameset_extract_tf_calib (frameset);
325  diamcat_frameset = gravi_frameset_extract_diamcat_map (frameset);
326 
327 
328  /* To use this recipe the frameset must contain
329  * at least one VIS_*_CAL frame or TF_*_CAL frame. */
330  if ( cpl_frameset_is_empty (vis_calib_frameset) &&
331  cpl_frameset_is_empty (tf_calib_frameset) ) {
332  cpl_error_set_message (cpl_func, CPL_ERROR_ILLEGAL_INPUT,
333  "No VIS or TF file on the frameset") ;
334  goto cleanup;
335  }
336 
337  /* Get the number of the frames contained in the frameset */
338  nb_frame_tf = cpl_frameset_get_size (tf_calib_frameset);
339  nb_frame_calib = cpl_frameset_get_size (vis_calib_frameset);
340  nb_frame_sci = cpl_frameset_get_size (vis_sci_frameset);
341 
342  /* Init memory */
343  vis_calibs = cpl_malloc ( (nb_frame_calib + nb_frame_tf) * sizeof (gravi_data *));
344  for (j = 0; j < (nb_frame_calib + nb_frame_tf); j++) vis_calibs[j] = NULL;
345 
346  /*
347  * Load or compute of the transfer function
348  */
349 
350  /* Load the DIAMETER_CAT
351  * FIXME: how/when install in the used_frameset ? */
352  if ( !cpl_frameset_is_empty (diamcat_frameset) ) {
353  frame = cpl_frameset_get_position (diamcat_frameset, 0);
354  diamcat_data = gravi_data_load_frame (frame, NULL);
355  }
356 
357  /* Init the frameset for all calibration (TF computed and loaded) */
358  used_frameset = cpl_frameset_new();
359 
360  /* Loop on the TF to compute */
361  for (j = 0; j < nb_frame_calib; j++) {
362  errorstate = cpl_errorstate_get();
363 
364  cpl_msg_info (cpl_func, "*** Compute TF %i over %i ***", j+1, nb_frame_calib);
365 
366  /* Load the VIS data and compute TF */
367  frame = cpl_frameset_get_position (vis_calib_frameset, j);
368  vis_data = gravi_data_load_frame (frame, NULL);
369  vis_calib = gravi_compute_tf (vis_data, diamcat_data);
370 
371  /* Check the TF has been computed */
372  if (vis_calib == NULL) {
373  cpl_msg_error (cpl_func, "Cannot compute this TF... continue");
374  goto cleanup_rawtf;
375  }
376 
377  CPLCHECK_GOTO ("Cannot compute the TF", cleanup_rawtf);
378 
379  /* Save the TF file */
380  data_mode = gravi_data_frame_get_mode (frame);
381 
382  gravi_data_save_new (vis_calib, frameset, NULL, parlist,
383  NULL, frame, "gravity_vis",
384  NULL, GRAVI_TF_CALIB(data_mode));
385 
386  CPLCHECK_GOTO ("Cannot save the TF", cleanup_rawtf);
387 
388  /* Store this successfull TF */
389  vis_calibs[nb_calib] = vis_calib;
390  vis_calib = NULL;
391  nb_calib++;
392 
393  /* Update the used_frameset -- now used as calibration */
394  frame = cpl_frame_duplicate (frame);
395  cpl_frame_set_group (frame, CPL_FRAME_GROUP_CALIB);
396  cpl_frameset_insert (used_frameset, frame);
397 
398  /* Clean memory of the loop */
399  cleanup_rawtf:
400  FREE (gravi_data_delete, vis_data);
401  FREE (gravi_data_delete, vis_calib);
402  cpl_errorstate_set (errorstate);
403  }
404  /* End loop on the TF to compute */
405 
406  cpl_msg_info (cpl_func,"*** Load already computed TF ***");
407 
408  /* Loop on the TF to load */
409  for (j = 0; j < nb_frame_tf; j++) {
410  errorstate = cpl_errorstate_get();
411 
412  cpl_msg_info (cpl_func," %i over %i", j+1, nb_frame_tf);
413 
414  frame = cpl_frameset_get_position (tf_calib_frameset, j);
415  vis_calib = gravi_data_load_frame (frame, used_frameset);
416 
417  CPLCHECK_GOTO("Cannot load the TF", cleanup_caltf);
418 
419  /* Store this successfull TF */
420  vis_calibs[nb_calib] = vis_calib;
421  vis_calib = NULL;
422  nb_calib++;
423 
424  cleanup_caltf:
425  FREE (gravi_data_delete,vis_calib);
426  cpl_errorstate_set (errorstate);
427  }
428  /* End loop on TF to load */
429 
430  cpl_msg_info (cpl_func,"*** All TF computed or loaded ***");
431 
432  cpl_msg_info (cpl_func, "Load or create successfully %i TF over %i input CAL files", nb_calib, nb_frame_calib + nb_frame_tf);
433 
434  /*
435  * Compute the zero of the metrology if several TF are availables
436  */
437 
438  if ( nb_calib > 1 ) {
439  errorstate = cpl_errorstate_get();
440 
441  cpl_msg_info (cpl_func, "*** Compute the zero of the metrology -- FIXME: to be done ***");
442  zero_data = gravi_compute_zp (vis_calibs, nb_calib);
443 
444  CPLCHECK_GOTO("Cannot compute ZP", cleanup_zp);
445 
446  gravi_data_save_new (zero_data, frameset, "output.fits", parlist,
447  used_frameset, NULL, "gravity_vis",
448  NULL, GRAVI_ZP_CAL);
449 
450  CPLCHECK_GOTO("Cannot save ZP", cleanup_zp);
451 
452  cleanup_zp:
453  FREE (gravi_data_delete,zero_data);
454  cpl_errorstate_set (errorstate);
455  }
456 
457  /*
458  * Apply the TF to the SCIENCE files of the frameset
459  */
460 
461  /* Loop on the SCI files to calibrate */
462  for (i = 0; i < nb_frame_sci; i++){
463  errorstate = cpl_errorstate_get();
464  current_frameset = cpl_frameset_duplicate (used_frameset);
465 
466  cpl_msg_info (cpl_func, "*** Calibration of file %i over %i ***", i+1, nb_frame_sci);
467 
468  frame = cpl_frameset_get_position (vis_sci_frameset, i);
469  vis_data = gravi_data_load_frame (frame, current_frameset);
470 
471  tf_science = gravi_data_duplicate (vis_data);
472  calibrated = gravi_calibrate_vis (vis_data, vis_calibs, nb_calib, zero_data, tf_science, parlist);
473 
474  CPLCHECK_GOTO("Cannot calibrate the visibility", cleanup_calib);
475 
476  /* Save calibrated visibilities */
477  data_mode = gravi_data_frame_get_mode (frame);
478 
479  gravi_data_save_new (calibrated, frameset, NULL, parlist,
480  current_frameset, frame, "gravity_vis",
481  NULL, GRAVI_VIS_CALIBRATED(data_mode));
482 
483  CPLCHECK_GOTO("Cannot save the calibrated visibility", cleanup_calib);
484 
485  /* Save TF interpolated at the science visibilities */
486  data_mode = gravi_data_frame_get_mode (frame);
487 
488  gravi_data_save_new (tf_science, frameset, NULL, parlist,
489  current_frameset, frame, "gravity_vis", NULL,
490  GRAVI_TF_SCIENCE(data_mode));
491 
492  CPLCHECK_GOTO("Cannot save the TF interpolated for this visibility", cleanup_calib);
493 
494  cleanup_calib:
495  FREE (gravi_data_delete,vis_data);
496  FREE (gravi_data_delete,tf_science);
497  FREE (gravi_data_delete,calibrated);
498  FREE (cpl_propertylist_delete,applist);
499  FREE (cpl_frameset_delete,current_frameset);
500  cpl_errorstate_set (errorstate);
501  }
502  /* End loop on VIS_*_SCI files to calibrate */
503 
504  /* Terminate the function */
505  goto cleanup;
506 
507 cleanup:
508  /* Deallocation of all variables */
509  cpl_msg_info(cpl_func,"Memory cleanup");
510 
511  FREE (gravi_data_delete,diamcat_data);
512  FREE (gravi_data_delete,zero_data);
513  FREE (cpl_frameset_delete,tf_calib_frameset);
514  FREE (cpl_frameset_delete,vis_calib_frameset);
515  FREE (cpl_frameset_delete,vis_sci_frameset);
516  FREE (cpl_frameset_delete,diamcat_frameset);
517  FREE (cpl_frameset_delete,current_frameset);
518  FREE (cpl_frameset_delete,used_frameset);
519  FREELOOP (gravi_data_delete,vis_calibs,nb_frame_calib+nb_frame_tf);
520 
521  gravi_msg_function_exit(1);
522  return (int)cpl_error_get_code();
523 }
524 
525