GRAVI Pipeline Reference Manual  1.2.3
gravi_tf.c
1 /* $Id: gravi_tf.c,v 1.10 2014/11/12 15:10:40 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 
36 /*-----------------------------------------------------------------------------
37  Includes
38  -----------------------------------------------------------------------------*/
39 
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43 
44 #include <cpl.h>
45 #include <string.h>
46 #include <stdio.h>
47 #include <math.h>
48 #include <time.h>
49 #include <complex.h>
50 
51 #include "gravi_data.h"
52 #include "gravi_dfs.h"
53 #include "gravi_pfits.h"
54 #include "gravi_cpl.h"
55 
56 #include "gravi_utils.h"
57 
58 #include "gravi_vis.h"
59 #include "gravi_tf.h"
60 
61 /*-----------------------------------------------------------------------------
62  Private prototypes
63  -----------------------------------------------------------------------------*/
64 
65 int gravi_array_set_invalid_negative (cpl_array * array);
66 cpl_error_code gravi_vis_flag_negative (cpl_table * oi_table,
67  const char * data, const char *flag);
68 cpl_error_code gravi_vis_flag_invalid (cpl_table * oi_table,
69  const char * data, const char *flag);
70 char * gravi_calib_setupstring (gravi_data * data);
71 double gravi_visibility_UD (double uv, double diam, double lbd);
72 cpl_size gravi_get_row_in_cat (cpl_table * diam_table, double ra, double dec, double *separation);
73 
74 /*-----------------------------------------------------------------------------
75  Function code
76  -----------------------------------------------------------------------------*/
77 
78 /*-----------------------------------------------------------------------------*/
84 /*-----------------------------------------------------------------------------*/
85 
86 int gravi_array_set_invalid_negative (cpl_array * array)
87 {
88  cpl_ensure (array, CPL_ERROR_NULL_INPUT, -1);
89 
90  /* Check the TF is positive */
91  if ( cpl_array_get_min ( array ) > 0.0 ) return 0;
92 
93  cpl_size indx, size = cpl_array_get_size (array);
94  int nv = 0, num = 0;
95 
96  /* Loop on array */
97  for ( indx = 0 ; indx < size ; indx ++ ) {
98  if ( cpl_array_get (array, indx, &nv) < 0.0 ) {
99  cpl_array_set_invalid (array, indx);
100  num++;
101  }
102  }
103 
104  return num;
105 }
106 
107 /*-----------------------------------------------------------------------------*/
115 /*-----------------------------------------------------------------------------*/
116 
117 cpl_error_code gravi_vis_flag_negative (cpl_table * oi_table,
118  const char * data, const char *flag)
119 {
120  gravi_msg_function_start(0);
121  cpl_ensure_code (oi_table, CPL_ERROR_NULL_INPUT);
122  cpl_ensure_code (data, CPL_ERROR_NULL_INPUT);
123  cpl_ensure_code (flag, CPL_ERROR_ILLEGAL_OUTPUT);
124 
125  /* Get pointer to speed up */
126  int nv = 0;
127  cpl_size row, nrow = cpl_table_get_nrow (oi_table);
128  cpl_array ** pdata = cpl_table_get_data_array (oi_table, data);
129  cpl_array ** pflag = cpl_table_get_data_array (oi_table, flag);
130  cpl_size indx, size = cpl_array_get_size (pdata[0]);
131 
132  CPLCHECK_MSG ("Cannot get data");
133 
134  /* Loop on row and index. Add to FLAG if data is NULL */
135  for ( row = 0 ; row < nrow ; row ++ ) {
136  for ( indx = 0 ; indx < size ; indx ++ ) {
137  if ( cpl_array_get (pdata[row], indx, &nv) < 0.0) {
138  cpl_array_set (pflag[row], indx, cpl_array_get (pflag[row], indx, &nv) + 1 );
139  }
140  }
141  }
142 
143  gravi_msg_function_exit(0);
144  return CPL_ERROR_NONE;
145 }
146 
147 /*-----------------------------------------------------------------------------*/
155 /*-----------------------------------------------------------------------------*/
156 
157 cpl_error_code gravi_vis_flag_invalid (cpl_table * oi_table,
158  const char * data, const char *flag)
159 {
160  gravi_msg_function_start(0);
161  cpl_ensure_code (oi_table, CPL_ERROR_NULL_INPUT);
162  cpl_ensure_code (data, CPL_ERROR_NULL_INPUT);
163  cpl_ensure_code (flag, CPL_ERROR_ILLEGAL_OUTPUT);
164 
165  /* Get pointer to speed up */
166  int nv = 0;
167  cpl_size row, nrow = cpl_table_get_nrow (oi_table);
168  cpl_array ** pdata = cpl_table_get_data_array(oi_table, data);
169  cpl_array ** pflag = cpl_table_get_data_array(oi_table, flag);
170  cpl_size indx, size = cpl_array_get_size (pdata[0]);
171 
172  CPLCHECK_MSG ("Cannot get data");
173 
174  /* Loop on row and index. Add to FLAG if data is NULL */
175  for ( row = 0 ; row < nrow ; row ++ ) {
176  if (pdata[row]==NULL) continue;
177  for ( indx = 0 ; indx < size ; indx ++ ) {
178  if ( !cpl_array_is_valid (pdata[row], indx) ) {
179  cpl_array_set (pflag[row], indx, cpl_array_get (pflag[row], indx, &nv) + 1 );
180  }
181  }
182  }
183 
184  gravi_msg_function_exit(0);
185  return CPL_ERROR_NONE;
186 }
187 
188 /*-----------------------------------------------------------------------------*/
199 /*-----------------------------------------------------------------------------*/
200 
201 char * gravi_calib_setupstring (gravi_data * data)
202 {
203  gravi_msg_function_start(0);
204  cpl_ensure (data, CPL_ERROR_NULL_INPUT, NULL);
205 
206  /* Main HEADER */
207  cpl_propertylist * hdr_data = gravi_data_get_header (data);
208 
209  /* Build the string */
210  char* setupstring = cpl_sprintf( "%10s %s %s %.2fms %.2fs",
211  gravi_pfits_get_spec_res (hdr_data),
212  gravi_pfits_get_pola_mode (hdr_data, GRAVI_SC),
213  gravi_pfits_get_pola_mode (hdr_data, GRAVI_FT),
214  gravi_pfits_get_dit_ft (hdr_data) * 1e3,
215  gravi_pfits_get_dit_sc (hdr_data) );
216 
217  cpl_msg_debug (cpl_func, "Get setup string: %s", setupstring);
218 
219  CPLCHECK_NUL ("Cannot compute the setupstring");
220 
221  gravi_msg_function_exit(0);
222  return setupstring;
223 }
224 
225 /*-----------------------------------------------------------------------------*/
246 /*-----------------------------------------------------------------------------*/
247 
248 cpl_error_code gravi_apply_tf_amp( gravi_data * science,
249  gravi_data * science_tf,
250  gravi_data ** used_tf_data,
251  int num_tf_data,
252  const char * extName,
253  const char * insName,
254  const char * ampName,
255  const char * ampErrName,
256  int nbase, double delta_t)
257 {
258  gravi_msg_function_start(0);
259  cpl_ensure_code (science, CPL_ERROR_NULL_INPUT);
260  cpl_ensure_code (insName, CPL_ERROR_NULL_INPUT);
261  cpl_ensure_code (extName, CPL_ERROR_NULL_INPUT);
262  cpl_ensure_code (ampName, CPL_ERROR_NULL_INPUT);
263  cpl_ensure_code (ampErrName, CPL_ERROR_NULL_INPUT);
264  cpl_ensure_code (used_tf_data, CPL_ERROR_NULL_INPUT);
265  cpl_ensure_code (num_tf_data>0, CPL_ERROR_ILLEGAL_INPUT);
266 
267  cpl_msg_debug (cpl_func, "%s %s amp=%s ampErr=%s nbase=%i",extName,insName,ampName,ampErrName,nbase);
268 
269  int i, row_sc, row_cal, nv=0;
270 
271  /* Get correct table */
272  cpl_table * sci_table = gravi_data_get_oi_table (science, extName, insName);
273  cpl_table * sci_tf_table = (science_tf?gravi_data_get_oi_table (science_tf, extName, insName):NULL);
274 
275  /* Some generic info */
276  int nrow_sc = cpl_table_get_nrow (sci_table);
277  int nwave = cpl_table_get_column_depth (sci_table, ampName);
278 
279  CPLCHECK_MSG ("Cannot get data on SCIENCE");
280 
281  /* Loop on row of SCIENCE */
282  for (row_sc = 0; row_sc < nrow_sc; row_sc ++){
283  double time_sci = cpl_table_get_double (sci_table, "TIME", row_sc, &nv);
284  int base = row_sc % nbase;
285 
286  /* Init the TF */
287  cpl_array * tf_mean = cpl_array_new (nwave, CPL_TYPE_DOUBLE);
288  cpl_array_fill_window (tf_mean, 0, nwave, 0.0);
289 
290  /* Loop on all possible TF = loop on TF files and loop
291  * on rows in each of this TF file */
292  double norm = 0.0;
293  for (i = 0; i < num_tf_data; i++){
294 
295  cpl_table * tf_table = gravi_data_get_oi_table (used_tf_data[i], extName, insName);
296  int nrow_tf = cpl_table_get_nrow (tf_table);
297  CPLCHECK_MSG("Cannot get the table on TF");
298 
299  for (row_cal = base; row_cal < nrow_tf; row_cal += nbase){
300  double time_tf = cpl_table_get_double (tf_table, "TIME", row_cal, &nv);
301 
302  /* Get the data of this TF */
303  cpl_array * tf_data = cpl_array_duplicate ( cpl_table_get_array (tf_table, ampName, row_cal) );
304  cpl_array * tf_err = cpl_array_duplicate ( cpl_table_get_array (tf_table, ampErrName, row_cal) );
305  CPLCHECK_MSG("Cannot get data on TF");
306 
307  /* Compute the mean error. Don't give added advantage
308  for 2% error, Idea from John Monnier */
309  double sigma = cpl_array_get_median (tf_err);
310  sigma = CPL_MAX (sigma, 0.02*fabs(cpl_array_get_median (tf_data)));
311  sigma = CPL_MAX (sigma, 1e-10);
312 
313  /* Compute the weighted mean of TF for this baseline */
314  double coeff = exp (-2 * fabs (time_sci - time_tf) / delta_t) / (sigma*sigma);
315  cpl_array_multiply_scalar (tf_data, coeff);
316  cpl_array_add (tf_mean, tf_data);
317  norm += coeff;
318 
319  cpl_array_delete (tf_data);
320  cpl_array_delete (tf_err);
321  CPLCHECK_MSG( "Error while integrating the TF" );
322  }
323  /* End loop on row in this TF file */
324  }
325  /* End loop on TF files */
326 
327  /* Divide by the sum of the weights of used CAL */
328  cpl_array_divide_scalar (tf_mean, norm);
329 
330  /* Check the TF is positive */
331  // ninv = gravi_array_set_invalid_negative (tf_mean);
332  // if ( ninv ) cpl_msg_info (cpl_func, "Invalidate %i negative channels over %i", ninv, nwave);
333 
334  /* Dump the TF mean in the output table of TF_SCI*/
335  if (sci_tf_table) cpl_table_set_array (sci_tf_table, ampName, row_sc, tf_mean);
336 
337  /* Apply the TF to the science_calibrated data */
338  cpl_array_divide (cpl_table_get_data_array (sci_table, ampName)[row_sc], tf_mean);
339 
340  /* Apply the TF to the error on the science_calibrated data -- FIXME: error on TF not propagated */
341  cpl_array_divide (cpl_table_get_data_array (sci_table, ampErrName)[row_sc], tf_mean);
342 
343  /* Free tf_mean */
344  cpl_array_delete (tf_mean);
345  }
346  /* End loop on row of SCIENCE */
347 
348  /* Flag invalid data (NULL data, NULL error, negative errors) */
349  if (sci_tf_table) {
350  gravi_vis_flag_invalid (sci_tf_table, ampName, "FLAG");
351  gravi_vis_flag_negative (sci_tf_table, ampErrName, "FLAG");
352  gravi_vis_flag_invalid (sci_tf_table, ampErrName, "FLAG");
353  }
354 
355  gravi_vis_flag_invalid (sci_table, ampName, "FLAG");
356  gravi_vis_flag_invalid (sci_table, ampErrName, "FLAG");
357  gravi_vis_flag_negative (sci_table, ampErrName, "FLAG");
358 
359  gravi_msg_function_exit(0);
360  return CPL_ERROR_NONE;
361 }
362 
363 /*-----------------------------------------------------------------------------*/
384 /*-----------------------------------------------------------------------------*/
385 
386 cpl_error_code gravi_apply_tf_phi( gravi_data * science,
387  gravi_data * science_tf,
388  gravi_data ** used_tf_data,
389  int num_tf_data,
390  const char * extName,
391  const char * insName,
392  const char * phiName,
393  const char * phiErrName,
394  int nbase, double delta_t)
395 {
396  gravi_msg_function_start(0);
397  cpl_ensure_code (science, CPL_ERROR_NULL_INPUT);
398  cpl_ensure_code (insName, CPL_ERROR_NULL_INPUT);
399  cpl_ensure_code (extName, CPL_ERROR_NULL_INPUT);
400  cpl_ensure_code (phiName, CPL_ERROR_NULL_INPUT);
401  cpl_ensure_code (phiErrName, CPL_ERROR_NULL_INPUT);
402  cpl_ensure_code (used_tf_data, CPL_ERROR_NULL_INPUT);
403  cpl_ensure_code (num_tf_data>0, CPL_ERROR_ILLEGAL_INPUT);
404 
405  cpl_msg_debug(cpl_func, "%s %s phi=%s phiErr=%s nbase=%i",extName,insName,phiName,phiErrName,nbase);
406 
407  int i, row_sc, row_cal, nv=0;
408 
409  /* Get correct table */
410  cpl_table * sci_table = gravi_data_get_oi_table (science, extName, insName);
411  cpl_table * sci_tf_table = (science_tf?gravi_data_get_oi_table (science_tf, extName, insName):NULL);
412 
413  /* Some generic info */
414  int nrow_sc = cpl_table_get_nrow (sci_table);
415  int nwave = cpl_table_get_column_depth (sci_table, phiName);
416 
417  CPLCHECK_MSG("Cannot get data on SCIENCE");
418 
419  /* Loop on row of SCIENCE */
420  for (row_sc = 0; row_sc < nrow_sc; row_sc ++){
421  double time_sci = cpl_table_get_double (sci_table, "TIME", row_sc, &nv);
422  int base = row_sc % nbase;
423 
424  /* Init the TF */
425  cpl_array * tf_mean = cpl_array_new (nwave, CPL_TYPE_DOUBLE_COMPLEX);
426  cpl_array_fill_window_complex (tf_mean, 0, nwave, 0.0 + 0.0*I);
427 
428  /* Loop on all possible TF = loop on TF files and loop
429  * on rows in each of this TF file */
430  for (i = 0; i < num_tf_data; i++){
431 
432  cpl_table * tf_table = gravi_data_get_oi_table (used_tf_data[i], extName, insName );
433  int nrow_tf = cpl_table_get_nrow (tf_table);
434  CPLCHECK_MSG("Cannot get the table on TF");
435 
436  for (row_cal = base; row_cal < nrow_tf; row_cal += nbase){
437  double time_tf = cpl_table_get_double (tf_table, "TIME", row_cal, &nv);
438 
439  /* Get the data of this TF in the form exp( i phase ) */
440  cpl_array * tf_data = gravi_array_cexp ( I*CPL_MATH_PI/180.0, cpl_table_get_array (tf_table, phiName, row_cal) );
441  cpl_array * tf_err = cpl_array_duplicate (cpl_table_get_array (tf_table, phiErrName, row_cal) );
442  CPLCHECK_MSG("Cannot get data on TF");
443 
444  /* Compute the mean error. Don't give added advantage
445  for 0.2deg for phase, Idea from John Monnier */
446  double sigma = CPL_MAX (cpl_array_get_median (tf_err), 0.2);
447 
448  /* Compute the weighted mean of TF for this baseline */
449  double coeff = exp (-2 * fabs (time_sci - time_tf) / delta_t) / (sigma*sigma);
450  cpl_array_multiply_scalar (tf_data, coeff);
451  cpl_array_add (tf_mean, tf_data);
452 
453  cpl_array_delete (tf_data);
454  cpl_array_delete (tf_err);
455  CPLCHECK_MSG("Error while integrating the TF");
456  }
457  /* End loop on row in this TF file */
458  }
459  /* End loop on TF files */
460 
461  /* Apply the TF to the science_calibrated data
462  * VISPHI = arg{ exp(i VISPHI/180*pi) / tf_mean } * 180/pi */
463  cpl_array * sci_data = gravi_array_cexp ( I*CPL_MATH_PI/180.0, cpl_table_get_array (sci_table, phiName, row_sc) );
464  cpl_array_divide (sci_data, tf_mean);
465  cpl_array_arg (sci_data);
466  cpl_array_multiply_scalar (sci_data, 180./CPL_MATH_PI);
467  cpl_table_set_array (sci_table, phiName, row_sc, sci_data);
468 
469 
470  /* Dump the TF mean in the output table of TF_SCI
471  * VIPHI = arg{ tf_mean } * 180 / pi */
472  cpl_array_arg (tf_mean);
473  cpl_array_multiply_scalar (tf_mean, 180./CPL_MATH_PI);
474  if (sci_tf_table) cpl_table_set_array (sci_tf_table, phiName, row_sc, tf_mean );
475 
476  /* No need to change error -- FIXME: error on TF not propagated */
477 
478  /* Free data */
479  cpl_array_delete (tf_mean);
480  cpl_array_delete (sci_data);
481  }
482  /* End loop on row of SCIENCE */
483 
484  /* Flag invalid data (NULL data, NULL error, negative errors) */
485  if (sci_tf_table) {
486  gravi_vis_flag_invalid (sci_tf_table, phiName, "FLAG");
487  gravi_vis_flag_invalid (sci_tf_table, phiErrName, "FLAG");
488  gravi_vis_flag_negative (sci_tf_table, phiErrName, "FLAG");
489  }
490  gravi_vis_flag_invalid (sci_table, phiName, "FLAG");
491  gravi_vis_flag_invalid (sci_table, phiErrName, "FLAG");
492  gravi_vis_flag_negative (sci_table, phiErrName, "FLAG");
493 
494  gravi_msg_function_exit(0);
495  return CPL_ERROR_NONE;
496 }
497 
498 
499 /*----------------------------------------------------------------------------*/
518 /*----------------------------------------------------------------------------*/
519 
520 gravi_data * gravi_calibrate_vis(gravi_data * vis_data, gravi_data ** tf_data, int num_tf,
521  gravi_data * zero, gravi_data * tf_science,
522  const cpl_parameterlist * parlist)
523 {
524  gravi_msg_function_start(1);
525  cpl_ensure (vis_data, CPL_ERROR_NULL_INPUT, NULL);
526  cpl_ensure (tf_data, CPL_ERROR_NULL_INPUT, NULL);
527  cpl_ensure (parlist, CPL_ERROR_NULL_INPUT, NULL);
528  cpl_ensure (num_tf>0, CPL_ERROR_NULL_INPUT, NULL);
529 
530  int i;
531  gravi_data * vis_calib;
532  char * setup_science, * setup_tf;
533 
534  /* Check the inputs */
535  cpl_ensure( (vis_data != NULL) && (tf_data != NULL), CPL_ERROR_NULL_INPUT, NULL );
536 
537  /*
538  * Find out the TF files who have the same setup keywords
539  * with the input SCIENCE file
540  */
541 
542  /* This will store the pointer to usefull TF data */
543  gravi_data ** used_tf_data = cpl_malloc (sizeof( gravi_data *) * num_tf);
544  cpl_msg_info (cpl_func,"Number of possible TF: %i", num_tf);
545 
546  /* Verbose the options */
547  double delta_t = gravi_param_get_double (parlist, "gravity.viscal.delta-time-calib");
548  cpl_msg_info (cpl_func, "Delta time to interpolate the TF: %f s (%f h)", delta_t, delta_t/3600.0);
549 
550  int force_calib = gravi_param_get_bool (parlist, "gravity.viscal.force-calib");
551  cpl_msg_info (cpl_func,"Force calibration of the SCI by CALs: %s", force_calib?"T":"F");
552 
553  /* Get setup keywords of the input SCIENCE file */
554  setup_science = gravi_calib_setupstring (vis_data);
555  cpl_msg_info (cpl_func,"Setup of SCIENCE: %s", setup_science);
556 
557  CPLCHECK_NUL("Cannot build the setup string for SCIENCE");
558 
559  /* Loop on the TF files */
560  int num_used_tf = 0;
561  for (i = 0; i < num_tf; i++){
562 
563  /* Get the setup string of this TF */
564  setup_tf = gravi_calib_setupstring (tf_data[i]);
565 
566  /* Check if compatible with SCIENCE */
567  if (!(strcmp (setup_tf, setup_science )) ) {
568  /* case same setup */
569  used_tf_data[num_used_tf] = tf_data[i];
570  num_used_tf ++;
571  cpl_msg_info (cpl_func,"Setup of TF file: %s -> keep", setup_tf);
572  } else if (force_calib) {
573  /* case different setups but forced */
574  used_tf_data[num_used_tf] = tf_data[i];
575  num_used_tf ++;
576  cpl_msg_info (cpl_func,"Setup of TF file: %s -> keep (force_calib)", setup_tf);
577  } else
578  /* case different setups */
579  cpl_msg_info (cpl_func,"Setup of TF file: %s -> discard", setup_tf);
580 
581  cpl_free (setup_tf);
582  }
583  /* End loop on TF files */
584 
585  if (num_used_tf == 0) {
586  cpl_free (used_tf_data);
587  cpl_error_set_message (cpl_func, CPL_ERROR_NULL_INPUT, "No calib file with the same keywords");
588  return NULL;
589  }
590 
591  /* Duplicate the data to create a calibrated dataset */
592  vis_calib = gravi_data_duplicate (vis_data);
593 
594  /* Get the header */
595  cpl_propertylist * hdr_data = gravi_data_get_header (vis_calib);
596 
597  /* For each type of data SC / FT */
598  int type_data, ntype_data = 2;
599  for (type_data = 0; type_data < ntype_data ; type_data ++) {
600 
601  /* Loop on polarisation */
602  int pol, npol = gravi_pfits_get_pola_num( hdr_data, type_data );
603  for ( pol= 0 ; pol < npol ; pol++ ) {
604 
605  /* Calibrate the VIS2 as a real quantity */
606  gravi_apply_tf_amp (vis_calib, tf_science, used_tf_data, num_used_tf,
607  GRAVI_OI_VIS2_EXT,
608  GRAVI_INSNAME(type_data, pol, npol),
609  "VIS2DATA", "VIS2ERR", 6, delta_t);
610 
611  CPLCHECK_NUL("Cannot apply tf to VIS2DATA");
612 
613  /* Calibrate the VISAMP as a real quantity --> to be discussed */
614  gravi_apply_tf_amp (vis_calib, tf_science, used_tf_data, num_used_tf,
615  GRAVI_OI_VIS_EXT,
616  GRAVI_INSNAME(type_data, pol, npol),
617  "VISAMP", "VISAMPERR", 6, delta_t);
618 
619  CPLCHECK_NUL("Cannot apply tf to VISAMP");
620 
621  /* Calibrate the VISPHI --> to be discussed for the astrometry */
622  gravi_apply_tf_phi (vis_calib, tf_science, used_tf_data, num_used_tf,
623  GRAVI_OI_VIS_EXT,
624  GRAVI_INSNAME(type_data, pol, npol),
625  "VISPHI", "VISPHIERR", 6, delta_t);
626 
627  CPLCHECK_NUL("Cannot apply tf to VISPHI");
628 
629  /* Calibrate the T3AMP as a scalar quantity --> to be discussed */
630  gravi_apply_tf_amp (vis_calib, tf_science, used_tf_data, num_used_tf,
631  GRAVI_OI_T3_EXT,
632  GRAVI_INSNAME(type_data, pol, npol),
633  "T3AMP", "T3AMPERR", 4, delta_t);
634 
635  CPLCHECK_NUL("Cannot apply tf to VISAMP");
636 
637  /* Calibrate the T3PHI as a phasor */
638  gravi_apply_tf_phi (vis_calib, tf_science, used_tf_data, num_used_tf,
639  GRAVI_OI_T3_EXT,
640  GRAVI_INSNAME(type_data, pol, npol),
641  "T3PHI", "T3PHIERR", 4, delta_t);
642 
643  CPLCHECK_NUL("Cannot apply tf to T3PHI");
644 
645  /* Calibrate the FLUX as a real quantity --> not calibrated */
646  if (gravi_param_get_bool (parlist, "gravity.viscal.calib-flux")){
647  gravi_apply_tf_amp (vis_calib, tf_science, used_tf_data, num_used_tf,
648  GRAVI_OI_FLUX_EXT,
649  GRAVI_INSNAME(type_data, pol, npol),
650  "FLUX", "FLUXERR", 4, delta_t);
651 
652  CPLCHECK_NUL("Cannot apply tf to FLUX");
653  }
654 
655  }
656  /* End loop on polarisation */
657  }
658  /* End loop on data_type */
659 
660  /* Free */
661  cpl_free (used_tf_data);
662  cpl_free (setup_science);
663 
664  gravi_msg_function_exit(1);
665  return vis_calib;
666 }
667 
668 
669 /*----------------------------------------------------------------------------*/
679 /*----------------------------------------------------------------------------*/
680 
681 double gravi_visibility_UD (double uv, double diam, double lbd)
682 {
683  if (lbd <=0) return 0.0;
684  double x = CPL_MATH_PI * uv / lbd * (diam * 1e-3 / 3600 / 180 * CPL_MATH_PI);
685  return ( (x<=0) ? 1.0 : 2.0 * j1 (x) / x );
686 }
687 
688 /*----------------------------------------------------------------------------*/
699 /*----------------------------------------------------------------------------*/
700 
701 cpl_size gravi_get_row_in_cat (cpl_table * diam_table, double ra, double dec, double *separation)
702 {
703  gravi_msg_function_start(0);
704  cpl_ensure (diam_table, CPL_ERROR_NULL_INPUT, -1);
705 
706  /* Assume the data are on the first extension */
707  const char ** p_ra = cpl_table_get_data_string_const (diam_table, "RAJ2000");
708  const char ** p_dec = cpl_table_get_data_string_const (diam_table, "DEJ2000");
709  cpl_size nrow = cpl_table_get_nrow (diam_table);
710 
711  cpl_ensure (p_ra, CPL_ERROR_ILLEGAL_INPUT, -1);
712  cpl_ensure (p_dec, CPL_ERROR_ILLEGAL_INPUT, -1);
713  cpl_ensure (nrow>0, CPL_ERROR_ILLEGAL_INPUT, -1);
714 
715  /* Init search */
716  cpl_size row0 = -2;
717  double dis0 = 1e20;
718 
719  /* Loop on rows */
720  for (cpl_size row = 0; row < nrow ; row ++) {
721 
722  /* RA and DEC of this row in [rad] */
723  double c_ra = gravi_ra_to_rad (p_ra[row]);
724  double c_dec = gravi_dec_to_rad (p_dec[row]);
725 
726  /* Compute distance in [rad]
727  * FIXME: we assume J2000 everywere */
728  double dist = acos ( sin (c_dec) * sin (dec) + cos (c_dec) * cos (dec) * cos (ra - c_ra) );
729 
730  /* Closest so far */
731  if ( dist < dis0 ) {
732  row0 = row;
733  dis0 = dist;
734  }
735  } /* End loop on rows */
736 
737  /* Best separation in arcsec */
738  if (separation != NULL) *separation = dis0 / CPL_MATH_PI * 180 * 3600;
739 
740  gravi_msg_function_exit(0);
741  return row0;
742 }
743 
744 /*----------------------------------------------------------------------------*/
754 /*----------------------------------------------------------------------------*/
755 
756 gravi_data * gravi_compute_tf (gravi_data * vis_data, gravi_data * diamcat_data)
757 {
758  gravi_msg_function_start(1);
759  cpl_ensure (vis_data, CPL_ERROR_NULL_INPUT, NULL);
760 
761  gravi_data * tf_data = NULL;
762  cpl_propertylist * plist;
763  cpl_table * tf_vistable;
764  cpl_table * tf_vis2table;
765  cpl_table * oi_wavelength;
766  int nv, type_data;
767  double diameter, diameter_err, lambda, r_vis, r_vis2, tf_v, tf_v2;
768  char qc_name[90];
769 
770  /* Get the OIFITS table */
771  tf_data = gravi_data_duplicate (vis_data);
772  plist = gravi_data_get_header (tf_data);
773 
774  /* Loop on SC / FT */
775  for (type_data = 0; type_data < 2; type_data ++) {
776  cpl_table * diam_table;
777  double sep = 99.0;
778  cpl_size row_cat = -1;
779 
780  /* Search in catalogue. Actually this should only
781  * be for SINGLE since catalogue won't be accurate for dual */
782  if (diamcat_data) {
783  /* Get the matching row */
784  diam_table = gravi_data_get_table_x (diamcat_data, 0);
785  row_cat = gravi_get_row_in_cat (diam_table,
786  gravi_pfits_get_type_raep (plist, type_data),
787  gravi_pfits_get_type_decep (plist, type_data),
788  &sep);
789 
790  /* Use it only if closest than 5" */
791  if ( (row_cat > -1) && (sep < 5.0) ) {
792  cpl_msg_info (cpl_func, "Find match in DIAMETER_CAT (best sep=%.2f arcsec)", sep);
793  diameter = cpl_table_get (diam_table, "UDDK", row_cat, NULL);
794  diameter_err = cpl_table_get (diam_table, "e_LDD", row_cat, NULL);
795  } else {
796  cpl_msg_warning (cpl_func, "No match in DIAMETER_CAT (best sep=%.2f arcsec), use the HEADER value instead", sep);
797  diameter = gravi_pfits_get_diameter (plist, type_data);
798  diameter_err = 0.15;
799  }
800 
801  } else {
802  cpl_msg_info (cpl_func, "No DIAMETER_CAT, use the HEADER value if any");
803  diameter = gravi_pfits_get_diameter (plist, type_data);
804  diameter_err = 0.15;
805  }
806 
807  /* Verbose about diameter value with a warning if weird value
808  * Or a return NULL is value is zero */
809  if ( diameter>=4.0 ) {
810  cpl_msg_warning (cpl_func,"Diameter for %s target: %.3f (+-%.3f) mas. Expected ?", GRAVI_TYPE(type_data), diameter, diameter_err);
811  }
812  else if (diameter <= 0.0 && !gravi_data_is_internal(vis_data)) {
813  cpl_msg_warning (cpl_func, "Diameter for %s target: 0.0 mas. Probably wrong, check parameter value", GRAVI_TYPE(type_data));
814  /* FREE (gravi_data_delete, tf_data);
815  return NULL;*/
816  }
817  else {
818  cpl_msg_info(cpl_func,"Diameter for %s target: %.3f (+-%.3f) mas", GRAVI_TYPE(type_data), diameter, diameter_err);
819  }
820 
821  /* Loop on polarisations */
822  int pol,npol = gravi_pfits_get_pola_num (plist, type_data);
823  for (pol = 0; pol < npol; pol ++){
824 
825  oi_wavelength = gravi_data_get_oi_wave (vis_data, type_data, pol,npol);
826  tf_vistable = gravi_data_get_oi_vis (tf_data, type_data, pol,npol);
827  tf_vis2table = gravi_data_get_oi_vis2 (tf_data, type_data, pol,npol);
828 
829  if ((tf_vistable == NULL) || (tf_vis2table == NULL) || (oi_wavelength == NULL)){
830  FREE (gravi_data_delete, tf_data);
831  cpl_error_set_message (cpl_func, CPL_ERROR_NULL_INPUT,
832  "Missing OI_VIS or OI_VIS2 or OI_WAVELENGTH");
833  return NULL;
834  }
835 
836  /* Construction of the data */
837 
838  /* Loop on row in the table -- warning, we here suppose the OI_VIS and
839  * OI_VIS2 have the same number of rows */
840  int nrow = cpl_table_get_nrow (tf_vistable);
841  int nwave = cpl_table_get_column_depth (tf_vis2table, "VIS2DATA" );
842  for (cpl_size row = 0; row < nrow; row ++){
843 
844  /* Compute norm for the baseline in meters */
845  r_vis = sqrt (pow (cpl_table_get_double (tf_vistable, "UCOORD", row, &nv), 2) +
846  pow (cpl_table_get_double (tf_vistable, "VCOORD", row, &nv), 2));
847 
848  r_vis2 = sqrt (pow (cpl_table_get_double (tf_vis2table, "UCOORD", row, &nv), 2) +
849  pow (cpl_table_get_double (tf_vis2table, "VCOORD", row, &nv), 2));
850 
851  CPLCHECK_NUL ("Cannot extract UVCOORD");
852 
853  /* Compute the model visibility from uniform disk */
854  cpl_array * model_vis = cpl_array_new (nwave, CPL_TYPE_DOUBLE);
855  cpl_array * model_vis2 = cpl_array_new (nwave, CPL_TYPE_DOUBLE);
856 
857  /* Loop on wave */
858  for (cpl_size wave = 0; wave < nwave ; wave ++){
859  /* This computation is validated */
860  lambda = cpl_table_get (oi_wavelength, "EFF_WAVE", wave, &nv);
861  tf_v = gravi_visibility_UD (r_vis, diameter, lambda);
862  tf_v2 = pow (gravi_visibility_UD (r_vis2, diameter, lambda), 2.0);
863 
864  /* Set into the temporary array */
865  cpl_array_set_double (model_vis, wave, tf_v);
866  cpl_array_set_double (model_vis2, wave, tf_v2);
867  }
868  /* End loop on wave */
869 
870  /* Divide the observed visibilities by the model for VISAMP */
871  cpl_array * tf_vis = cpl_table_get_data_array (tf_vistable, "VISAMP")[row];
872  cpl_array * tf_visErr = cpl_table_get_data_array (tf_vistable, "VISAMPERR")[row];
873  cpl_array_divide (tf_vis, model_vis);
874  cpl_array_divide (tf_visErr, model_vis);
875 
876  /* Divide the observed visibilities by the model for VIS2 */
877  cpl_array * tf_vis2 = cpl_table_get_data_array (tf_vis2table, "VIS2DATA")[row];
878  cpl_array * tf_vis2Err = cpl_table_get_data_array (tf_vis2table, "VIS2ERR")[row];
879  cpl_array_divide (tf_vis2, model_vis2);
880  cpl_array_divide (tf_vis2Err, model_vis2);
881 
882  CPLCHECK_NUL("Cannot set the tf array");
883 
884  /* Compute the relative error on the TF at 2.2 microns
885  * due to the diameter uncertainty */
886  double errRelTF = fabs (( gravi_visibility_UD (r_vis, (diameter+diameter_err), 2.2e-6) -
887  gravi_visibility_UD (r_vis, (diameter-diameter_err), 2.2e-6) ) /
888  gravi_visibility_UD (r_vis, diameter, 2.2e-6) );
889 
890  /* Note that VISPHI, T3PHI, T3AMP, VISDATA are already in
891  * output table since they are duplicated */
892 
893  /* Add QC params. FIXME: deal with QC parameter if multiple files
894  * - *mean* over file QC TF VISAMP_SC12_P1 AVG
895  * - *p2p* over file
896  * FIXME: put both polarisation in a single QC */
897 
898  /* Get baseline name and id */
899  int base=row%6;
900 
901  sprintf (qc_name, "ESO QC TF VISMOD_%s%s RELERR", GRAVI_TYPE(type_data), GRAVI_BASE_NAME[base]);
902  gravi_pfits_update_double (plist, qc_name, errRelTF);
903  cpl_propertylist_set_comment (plist, qc_name, "TF rel.err from diameter at 2.2um");
904  CPLCHECK_NUL ("QC TF VISMOD RELERR");
905 
906  sprintf (qc_name, "ESO QC TF VISAMP_%s%s_P%d MED", GRAVI_TYPE(type_data), GRAVI_BASE_NAME[base], pol+1);
907  gravi_pfits_update_double (plist, qc_name, cpl_array_get_median (tf_vis));
908  cpl_propertylist_set_comment (plist, qc_name, "TF. VIS median over lbd.");
909  CPLCHECK_NUL ("QC TF VIS AVG");
910 
911  sprintf (qc_name, "ESO QC TF VIS2_%s%s_P%d MED", GRAVI_TYPE(type_data), GRAVI_BASE_NAME[base], pol+1);
912  gravi_pfits_update_double (plist, qc_name, cpl_array_get_median (tf_vis2));
913  cpl_propertylist_set_comment (plist, qc_name, "TF. VIS2 median over lbd.");
914  CPLCHECK_NUL ("QC TF VIS2 AVG");
915 
916  /* Free Memory */
917  cpl_array_delete (model_vis2);
918  cpl_array_delete (model_vis);
919  }
920  /* End loop on rows */
921  }
922  /* End loop on pol */
923 
924 
925  /* Compute the transmission QC only if a
926  * valid match with catalog is found */
927  if ( (row_cat > -1) && (sep < 5.0) ) {
928 
929  /* Check if consistent setup (all ATs or all UTs) */
930  cpl_table * oi_array = gravi_data_get_table (vis_data, GRAVI_OI_ARRAY_EXT);
931  const char sta = *cpl_table_get_string (oi_array, "TEL_NAME", 0);
932  if (*cpl_table_get_string (oi_array, "TEL_NAME", 1) != sta ||
933  *cpl_table_get_string (oi_array, "TEL_NAME", 2) != sta ||
934  *cpl_table_get_string (oi_array, "TEL_NAME", 3) != sta)
935  {
936  cpl_error_set_message (cpl_func, CPL_ERROR_ILLEGAL_INPUT, "AT/UT mode is not supported");
937  return NULL;
938  }
939 
940  /* Compute in [photons/s/m2] */
941  double diam = 1.0;
942  if (sta=='U') { diam = 8.0; cpl_msg_info (cpl_func, "Use UTs"); }
943  else if (sta=='A') { diam = 1.8; cpl_msg_info (cpl_func, "Use ATs"); }
944  else { diam = 1.0; cpl_msg_warning (cpl_func, "Cannot find the diameter of telescope"); }
945 
946  /* Get the expected flux in [photons/s] */
947  double Kmag = cpl_table_get (diam_table, "Kmag", row_cat, NULL);
948  double flux0 = 1.71173e+09 * pow (10.0, -Kmag/2.5) * (CPL_MATH_PI * pow (diam/2, 2));
949  cpl_msg_info (cpl_func, "Use Kmag=%.2f for QC.TRANS", Kmag);
950 
951  /* Loop on beam */
952  for (int tel = 0; tel < 4; tel++) {
953  double flux = 0.0;
954 
955  /* Get the total observed flux in [e/s] */
956  sprintf (qc_name, "ESO QC FLUXRATE_%s%i_P1 SUM",GRAVI_TYPE(type_data),tel+1);
957  flux += gravi_pfits_get_double_silentdefault (plist, qc_name, 0.);
958  sprintf (qc_name, "ESO QC FLUXRATE_%s%i_P2 SUM",GRAVI_TYPE(type_data),tel+1);
959  flux += gravi_pfits_get_double_silentdefault (plist, qc_name, 0.);
960  CPLCHECK_NUL ("Cannot get fluxrate");
961 
962  /* Add the QC parameter */
963  sprintf (qc_name, "ESO QC TF TRANS_%s%i",GRAVI_TYPE(type_data),tel+1);
964  gravi_pfits_update_double (plist, qc_name, flux / flux0 * 100.0);
965  cpl_propertylist_set_comment (plist, qc_name, "[%] Total transmission");
966  cpl_msg_info (cpl_func, "%s = %.2f%%", qc_name, flux / flux0 * 100.0);
967  CPLCHECK_NUL ("QC TRANS");
968  }
969  } /* End computation of TF */
970 
971  }
972  /* End loop on type_data */
973 
974  gravi_msg_function_exit(1);
975  return tf_data;
976 }
977 
978 /*----------------------------------------------------------------------------*/
990 /*----------------------------------------------------------------------------*/
991 
992 cpl_error_code gravi_compute_tf_qc (gravi_data * oi_vis, gravi_data * diamcat_data)
993 {
994  gravi_msg_function_start(0);
995  cpl_ensure_code (oi_vis, CPL_ERROR_NULL_INPUT);
996 
997  cpl_errorstate prestate = cpl_errorstate_get();
998 
999  cpl_msg_info (cpl_func, "Compute the QC TF parameters");
1000 
1001  /* Compute TF */
1002  gravi_data * oi_tf = gravi_compute_tf (oi_vis, diamcat_data);
1003 
1004  /* If an error is catch when computing the QC parameters, dump this error but continue */
1005  if ( cpl_error_get_code() || oi_tf == NULL) {
1006  cpl_msg_warning (cpl_func, "Cannot compute the QC TF parameters for this observation... continue.");
1007  cpl_errorstate_set (prestate);
1008  return CPL_ERROR_NONE;
1009  }
1010 
1011  /* Copy to header */
1012  cpl_propertylist_copy_property_regexp (gravi_data_get_header (oi_vis),
1013  gravi_data_get_header (oi_tf),
1014  ".*QC TF.*", 0);
1015  FREE (gravi_data_delete,oi_tf);
1016 
1017  gravi_msg_function_exit(0);
1018  return CPL_ERROR_NONE;
1019 }
1020 
1021 /*----------------------------------------------------------------------------*/
1025 /*----------------------------------------------------------------------------*/
1026 
1027 gravi_data * gravi_compute_zp (gravi_data ** vis_calib, int num_calib)
1028 {
1029  gravi_msg_function_start(1);
1030  cpl_ensure (vis_calib, CPL_ERROR_NULL_INPUT, NULL);
1031  cpl_ensure (num_calib>0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1032 
1033  gravi_data * zero_met = gravi_data_duplicate (vis_calib[0]);
1034 
1035  gravi_msg_function_exit(1);
1036  return zero_met;
1037 }
1038 
1039 
gravi_data * gravi_calibrate_vis(gravi_data *vis_data, gravi_data **tf_data, int num_tf, gravi_data *zero, gravi_data *tf_science, const cpl_parameterlist *parlist)
Computes the calibrated visibility from science a single data and several previously evaluated instru...
Definition: gravi_tf.c:520
char * gravi_calib_setupstring(gravi_data *data)
Build a unique setup string per calibratable setup.
Definition: gravi_tf.c:201
cpl_error_code gravi_compute_tf_qc(gravi_data *oi_vis, gravi_data *diamcat_data)
Fill QC parameters related to transfer function.
Definition: gravi_tf.c:992
gravi_data * gravi_compute_zp(gravi_data **vis_calib, int num_calib)
Compute the ZP data.
Definition: gravi_tf.c:1027
cpl_array * gravi_array_cexp(double complex factor, const cpl_array *input)
Compute the complex exponention of an array: cexp (factor * input)
Definition: gravi_cpl.c:973
int gravi_array_set_invalid_negative(cpl_array *array)
Set invalid to all negative elements of an array.
Definition: gravi_tf.c:86
cpl_table * gravi_data_get_table(gravi_data *self, const char *extname)
Return a pointer on a table extension by its EXTNAME.
Definition: gravi_data.c:1716
gravi_data * gravi_compute_tf(gravi_data *vis_data, gravi_data *diamcat_data)
This function evaluates the transfer function from the observation of a reference star whose diameter...
Definition: gravi_tf.c:756
double gravi_visibility_UD(double uv, double diam, double lbd)
Compute the expected visibility from a UD model.
Definition: gravi_tf.c:681
cpl_error_code gravi_vis_flag_negative(cpl_table *oi_table, const char *data, const char *flag)
Flag negative element of an OIFITS table.
Definition: gravi_tf.c:117
cpl_size gravi_get_row_in_cat(cpl_table *diam_table, double ra, double dec, double *separation)
Get the row in a cpl_table matching closest RAJ2000 and DEJ2000.
Definition: gravi_tf.c:701
cpl_table * gravi_data_get_table_x(gravi_data *self, int i)
Get the table of an extension by position.
Definition: gravi_data.c:1536
void gravi_data_delete(gravi_data *self)
Delete a gravi data.
Definition: gravi_data.c:137
gravi_data * gravi_data_duplicate(const gravi_data *self)
Create a copy of the gravi data.
Definition: gravi_data.c:236
cpl_error_code gravi_apply_tf_amp(gravi_data *science, gravi_data *science_tf, gravi_data **used_tf_data, int num_tf_data, const char *extName, const char *insName, const char *ampName, const char *ampErrName, int nbase, double delta_t)
Interpolate the TF at the time of the science observation for an amplitude quantity.
Definition: gravi_tf.c:248
cpl_error_code gravi_apply_tf_phi(gravi_data *science, gravi_data *science_tf, gravi_data **used_tf_data, int num_tf_data, const char *extName, const char *insName, const char *phiName, const char *phiErrName, int nbase, double delta_t)
Interpolate the TF at the time of the science observation for a phase quantity (in deg)...
Definition: gravi_tf.c:386
cpl_error_code gravi_vis_flag_invalid(cpl_table *oi_table, const char *data, const char *flag)
Flag invalid element of an OIFITS table.
Definition: gravi_tf.c:157
cpl_table * gravi_data_get_oi_table(gravi_data *self, const char *extname, const char *insname)
Get an OI_FITS table from EXTNAME and INSNAME.
Definition: gravi_data.c:1587