GRAVI Pipeline Reference Manual 1.8.0
Loading...
Searching...
No Matches
gravi_tf.c
Go to the documentation of this file.
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
65int gravi_array_set_invalid_negative (cpl_array * array);
66cpl_error_code gravi_vis_flag_negative (cpl_table * oi_table,
67 const char * data, const char *flag);
68cpl_error_code gravi_vis_flag_invalid (cpl_table * oi_table,
69 const char * data, const char *flag);
71double gravi_visibility_UD (double uv, double diam, double lbd);
72cpl_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
86int 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
117cpl_error_code gravi_vis_flag_negative (cpl_table * oi_table,
118 const char * data, const char *flag)
119{
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
144 return CPL_ERROR_NONE;
145}
146
147/*-----------------------------------------------------------------------------*/
155/*-----------------------------------------------------------------------------*/
156
157cpl_error_code gravi_vis_flag_invalid (cpl_table * oi_table,
158 const char * data, const char *flag)
159{
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
185 return CPL_ERROR_NONE;
186}
187
188/*-----------------------------------------------------------------------------*/
199/*-----------------------------------------------------------------------------*/
200
202{
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),
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
222 return setupstring;
223}
224
225/*-----------------------------------------------------------------------------*/
246/*-----------------------------------------------------------------------------*/
247
248cpl_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{
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 /* Apply the TF to the error on the science_calibrated data -- FIXME: error on TF not propagated */
340 cpl_array_divide (cpl_table_get_data_array (sci_table, ampErrName)[row_sc], tf_mean);
341
342 /* Free tf_mean */
343 cpl_array_delete (tf_mean);
344 }
345 /* End loop on row of SCIENCE */
346
347 /* Flag invalid data (NULL data, NULL error, negative errors) */
348 if (sci_tf_table) {
349 gravi_vis_flag_invalid (sci_tf_table, ampName, "FLAG");
350 gravi_vis_flag_negative (sci_tf_table, ampErrName, "FLAG");
351 gravi_vis_flag_invalid (sci_tf_table, ampErrName, "FLAG");
352 }
353
354 gravi_vis_flag_invalid (sci_table, ampName, "FLAG");
355 gravi_vis_flag_invalid (sci_table, ampErrName, "FLAG");
356 gravi_vis_flag_negative (sci_table, ampErrName, "FLAG");
357
359 return CPL_ERROR_NONE;
360}
361
362/*-----------------------------------------------------------------------------*/
383/*-----------------------------------------------------------------------------*/
384
385cpl_error_code gravi_apply_tf_phi( gravi_data * science,
386 gravi_data * science_tf,
387 gravi_data ** used_tf_data,
388 int num_tf_data,
389 const char * extName,
390 const char * insName,
391 const char * phiName,
392 const char * phiErrName,
393 int nbase, double delta_t)
394{
396 cpl_ensure_code (science, CPL_ERROR_NULL_INPUT);
397 cpl_ensure_code (insName, CPL_ERROR_NULL_INPUT);
398 cpl_ensure_code (extName, CPL_ERROR_NULL_INPUT);
399 cpl_ensure_code (phiName, CPL_ERROR_NULL_INPUT);
400 cpl_ensure_code (phiErrName, CPL_ERROR_NULL_INPUT);
401 cpl_ensure_code (used_tf_data, CPL_ERROR_NULL_INPUT);
402 cpl_ensure_code (num_tf_data>0, CPL_ERROR_ILLEGAL_INPUT);
403
404 cpl_msg_debug(cpl_func, "%s %s phi=%s phiErr=%s nbase=%i",extName,insName,phiName,phiErrName,nbase);
405
406 int i, row_sc, row_cal, nv=0;
407
408 /* Get correct table */
409 cpl_table * sci_table = gravi_data_get_oi_table (science, extName, insName);
410 cpl_table * sci_tf_table = (science_tf?gravi_data_get_oi_table (science_tf, extName, insName):NULL);
411
412 /* Some generic info */
413 int nrow_sc = cpl_table_get_nrow (sci_table);
414 int nwave = cpl_table_get_column_depth (sci_table, phiName);
415
416 CPLCHECK_MSG("Cannot get data on SCIENCE");
417
418 /* Loop on row of SCIENCE */
419 for (row_sc = 0; row_sc < nrow_sc; row_sc ++){
420 double time_sci = cpl_table_get_double (sci_table, "TIME", row_sc, &nv);
421 int base = row_sc % nbase;
422
423 /* Init the TF */
424 cpl_array * tf_mean = cpl_array_new (nwave, CPL_TYPE_DOUBLE_COMPLEX);
425 cpl_array_fill_window_complex (tf_mean, 0, nwave, 0.0 + 0.0*I);
426
427 /* Loop on all possible TF = loop on TF files and loop
428 * on rows in each of this TF file */
429 for (i = 0; i < num_tf_data; i++){
430
431 cpl_table * tf_table = gravi_data_get_oi_table (used_tf_data[i], extName, insName );
432 int nrow_tf = cpl_table_get_nrow (tf_table);
433 CPLCHECK_MSG("Cannot get the table on TF");
434
435 for (row_cal = base; row_cal < nrow_tf; row_cal += nbase){
436 double time_tf = cpl_table_get_double (tf_table, "TIME", row_cal, &nv);
437
438 /* Get the data of this TF in the form exp( i phase ) */
439 cpl_array * tf_data = gravi_array_cexp ( I*CPL_MATH_PI/180.0, cpl_table_get_array (tf_table, phiName, row_cal) );
440 cpl_array * tf_err = cpl_array_duplicate (cpl_table_get_array (tf_table, phiErrName, row_cal) );
441 CPLCHECK_MSG("Cannot get data on TF");
442
443 /* Compute the mean error. Don't give added advantage
444 for 0.2deg for phase, Idea from John Monnier */
445 double sigma = CPL_MAX (cpl_array_get_median (tf_err), 0.2);
446
447 /* Compute the weighted mean of TF for this baseline */
448 double coeff = exp (-2 * fabs (time_sci - time_tf) / delta_t) / (sigma*sigma);
449 cpl_array_multiply_scalar (tf_data, coeff);
450 cpl_array_add (tf_mean, tf_data);
451
452 cpl_array_delete (tf_data);
453 cpl_array_delete (tf_err);
454 CPLCHECK_MSG("Error while integrating the TF");
455 }
456 /* End loop on row in this TF file */
457 }
458 /* End loop on TF files */
459
460 /* Apply the TF to the science_calibrated data
461 * VISPHI = arg{ exp(i VISPHI/180*pi) / tf_mean } * 180/pi */
462 cpl_array * sci_data = gravi_array_cexp ( I*CPL_MATH_PI/180.0, cpl_table_get_array (sci_table, phiName, row_sc) );
463 cpl_array_divide (sci_data, tf_mean);
464 cpl_array_arg (sci_data);
465 cpl_array_multiply_scalar (sci_data, 180./CPL_MATH_PI);
466 cpl_table_set_array (sci_table, phiName, row_sc, sci_data);
467
468
469 /* Dump the TF mean in the output table of TF_SCI
470 * VIPHI = arg{ tf_mean } * 180 / pi */
471 cpl_array_arg (tf_mean);
472 cpl_array_multiply_scalar (tf_mean, 180./CPL_MATH_PI);
473 if (sci_tf_table) cpl_table_set_array (sci_tf_table, phiName, row_sc, tf_mean );
474
475 /* No need to change error -- FIXME: error on TF not propagated */
476
477 /* Free data */
478 cpl_array_delete (tf_mean);
479 cpl_array_delete (sci_data);
480 }
481 /* End loop on row of SCIENCE */
482
483 /* Flag invalid data (NULL data, NULL error, negative errors) */
484 if (sci_tf_table) {
485 gravi_vis_flag_invalid (sci_tf_table, phiName, "FLAG");
486 gravi_vis_flag_invalid (sci_tf_table, phiErrName, "FLAG");
487 gravi_vis_flag_negative (sci_tf_table, phiErrName, "FLAG");
488 }
489 gravi_vis_flag_invalid (sci_table, phiName, "FLAG");
490 gravi_vis_flag_invalid (sci_table, phiErrName, "FLAG");
491 gravi_vis_flag_negative (sci_table, phiErrName, "FLAG");
492
494 return CPL_ERROR_NONE;
495}
496
497
498/*----------------------------------------------------------------------------*/
519/*----------------------------------------------------------------------------*/
520
521gravi_data * gravi_calibrate_vis(gravi_data * vis_data, gravi_data ** tf_data, int num_tf, gravi_data * phi_tf_data,
522 gravi_data * tf_science,
523 const cpl_parameterlist * parlist)
524{
526 cpl_ensure (vis_data, CPL_ERROR_NULL_INPUT, NULL);
527 cpl_ensure (tf_data, CPL_ERROR_NULL_INPUT, NULL);
528 cpl_ensure (parlist, CPL_ERROR_NULL_INPUT, NULL);
529 cpl_ensure (num_tf>0, CPL_ERROR_NULL_INPUT, NULL);
530
531 int i;
532 gravi_data * vis_calib;
533 char * setup_science, * setup_tf;
534
535 /* Check the inputs */
536 cpl_ensure( (vis_data != NULL) && (tf_data != NULL), CPL_ERROR_NULL_INPUT, NULL );
537
538 if (gravi_param_get_bool (parlist, "gravity.viscal.separate-phase-calib"))
539 cpl_ensure(phi_tf_data != NULL, CPL_ERROR_NULL_INPUT, NULL);
540
541 /*
542 * Find out the TF files who have the same setup keywords
543 * with the input SCIENCE file
544 */
545
546 /* This will store the pointer to usefull TF data */
547 gravi_data ** used_tf_data = cpl_malloc (sizeof( gravi_data *) * num_tf);
548 cpl_msg_info (cpl_func,"Number of possible TF: %i", num_tf);
549
550 /* Verbose the options */
551 double delta_t = gravi_param_get_double (parlist, "gravity.viscal.delta-time-calib");
552 cpl_msg_info (cpl_func, "Delta time to interpolate the TF: %f s (%f h)", delta_t, delta_t/3600.0);
553
554 int force_calib = gravi_param_get_bool (parlist, "gravity.viscal.force-calib");
555 cpl_msg_info (cpl_func,"Force calibration of the SCI by CALs: %s", force_calib?"T":"F");
556
557 /* Get setup keywords of the input SCIENCE file */
558 setup_science = gravi_calib_setupstring (vis_data);
559 cpl_msg_info (cpl_func,"Setup of SCIENCE: %s", setup_science);
560
561 CPLCHECK_NUL("Cannot build the setup string for SCIENCE");
562
563 /* Loop on the TF files */
564 int num_used_tf = 0;
565 for (i = 0; i < num_tf; i++){
566
567 /* Get the setup string of this TF */
568 setup_tf = gravi_calib_setupstring (tf_data[i]);
569
570 /* Check if compatible with SCIENCE */
571 if (!(strcmp (setup_tf, setup_science )) ) {
572 /* case same setup */
573 used_tf_data[num_used_tf] = tf_data[i];
574 num_used_tf ++;
575 cpl_msg_info (cpl_func,"Setup of TF file: %s -> keep", setup_tf);
576 } else if (force_calib) {
577 /* case different setups but forced */
578 used_tf_data[num_used_tf] = tf_data[i];
579 num_used_tf ++;
580 cpl_msg_info (cpl_func,"Setup of TF file: %s -> keep (force_calib)", setup_tf);
581 } else
582 /* case different setups */
583 cpl_msg_info (cpl_func,"Setup of TF file: %s -> discard", setup_tf);
584
585 cpl_free (setup_tf);
586 }
587 /* End loop on TF files */
588
589 if (num_used_tf == 0) {
590 cpl_free (used_tf_data);
591 cpl_error_set_message (cpl_func, CPL_ERROR_NULL_INPUT, "No calib file with the same keywords");
592 return NULL;
593 }
594
595 if (gravi_param_get_bool (parlist, "gravity.viscal.separate-phase-calib")){
596 /* Get the setup string of phical TF */
597 setup_tf = gravi_calib_setupstring (phi_tf_data);
598
599 /* Check if phical compatible with SCIENCE */
600 if (!force_calib && (strcmp (setup_tf, setup_science )) ) {
601 cpl_error_set_message (cpl_func, CPL_ERROR_NULL_INPUT, "Visphi calib file does not have the same keywords");
602 return NULL;
603 }
604
605 cpl_free (setup_tf);
606 }
607
608 /* Duplicate the data to create a calibrated dataset */
609 vis_calib = gravi_data_duplicate (vis_data);
610
611 /* Get the header */
612 cpl_propertylist * hdr_data = gravi_data_get_header (vis_calib);
613
614 /* For each type of data SC / FT */
615 int type_data, ntype_data = 2;
616 for (type_data = 0; type_data < ntype_data ; type_data ++) {
617
618 /* Loop on polarisation */
619 int pol, npol = gravi_pfits_get_pola_num( hdr_data, type_data );
620 for ( pol= 0 ; pol < npol ; pol++ ) {
621
622 /* Calibrate the VIS2 as a real quantity */
623 gravi_apply_tf_amp (vis_calib, tf_science, used_tf_data, num_used_tf,
625 GRAVI_INSNAME(type_data, pol, npol),
626 "VIS2DATA", "VIS2ERR", 6, delta_t);
627
628 CPLCHECK_NUL("Cannot apply tf to VIS2DATA");
629
630 /* Calibrate the VISAMP as a real quantity --> to be discussed */
631 gravi_apply_tf_amp (vis_calib, tf_science, used_tf_data, num_used_tf,
633 GRAVI_INSNAME(type_data, pol, npol),
634 "VISAMP", "VISAMPERR", 6, delta_t);
635
636 CPLCHECK_NUL("Cannot apply tf to VISAMP");
637
638 /* Calibrate the T3AMP as a scalar quantity --> to be discussed */
639 gravi_apply_tf_amp (vis_calib, tf_science, used_tf_data, num_used_tf,
641 GRAVI_INSNAME(type_data, pol, npol),
642 "T3AMP", "T3AMPERR", 4, delta_t);
643
644 CPLCHECK_NUL("Cannot apply tf to T3AMP");
645
646 /* Calibrate the VISPHI --> to be discussed for the astrometry */
647 if (gravi_param_get_bool (parlist, "gravity.viscal.separate-phase-calib")) {
648 gravi_apply_tf_phi (vis_calib, tf_science, &phi_tf_data, 1,
650 GRAVI_INSNAME(type_data, pol, npol),
651 "VISPHI", "VISPHIERR", 6, delta_t);
652 } else {
653 gravi_apply_tf_phi (vis_calib, tf_science, used_tf_data, num_used_tf,
655 GRAVI_INSNAME(type_data, pol, npol),
656 "VISPHI", "VISPHIERR", 6, delta_t);
657 }
658 CPLCHECK_NUL("Cannot apply tf to VISPHI");
659
660 /* Calibrate the T3PHI as a phasor */
661 gravi_apply_tf_phi (vis_calib, tf_science, used_tf_data, num_used_tf,
663 GRAVI_INSNAME(type_data, pol, npol),
664 "T3PHI", "T3PHIERR", 4, delta_t);
665 CPLCHECK_NUL("Cannot apply tf to T3PHI");
666
667 /* Calibrate the FLUX as a real quantity --> not calibrated */
668 if (gravi_param_get_bool (parlist, "gravity.viscal.calib-flux")){
669 gravi_apply_tf_amp (vis_calib, tf_science, used_tf_data, num_used_tf,
671 GRAVI_INSNAME(type_data, pol, npol),
672 "FLUX", "FLUXERR", 4, delta_t);
673
674 CPLCHECK_NUL("Cannot apply tf to FLUX");
675 }
676
677 }
678 /* End loop on polarisation */
679 }
680 /* End loop on data_type */
681
682 /* Free */
683 cpl_free (used_tf_data);
684 cpl_free (setup_science);
685
687 return vis_calib;
688}
689
690
691/*----------------------------------------------------------------------------*/
701/*----------------------------------------------------------------------------*/
702
703double gravi_visibility_UD (double uv, double diam, double lbd)
704{
705 if (lbd <=0) return 0.0;
706 double x = CPL_MATH_PI * uv / lbd * (diam * 1e-3 / 3600 / 180 * CPL_MATH_PI);
707 return ( (x<=0) ? 1.0 : 2.0 * j1 (x) / x );
708}
709
710/*----------------------------------------------------------------------------*/
721/*----------------------------------------------------------------------------*/
722
723cpl_size gravi_get_row_in_cat (cpl_table * diam_table, double ra, double dec, double *separation)
724{
726 cpl_ensure (diam_table, CPL_ERROR_NULL_INPUT, -1);
727
728 /* Assume the data are on the first extension */
729 const char ** p_ra = cpl_table_get_data_string_const (diam_table, "RAJ2000");
730 const char ** p_dec = cpl_table_get_data_string_const (diam_table, "DEJ2000");
731 cpl_size nrow = cpl_table_get_nrow (diam_table);
732
733 cpl_ensure (p_ra, CPL_ERROR_ILLEGAL_INPUT, -1);
734 cpl_ensure (p_dec, CPL_ERROR_ILLEGAL_INPUT, -1);
735 cpl_ensure (nrow>0, CPL_ERROR_ILLEGAL_INPUT, -1);
736
737 /* Init search */
738 cpl_size row0 = -2;
739 double dis0 = 1e20;
740
741 /* Loop on rows */
742 for (cpl_size row = 0; row < nrow ; row ++) {
743
744 /* RA and DEC of this row in [rad] */
745 double c_ra = gravi_ra_to_rad (p_ra[row]);
746 double c_dec = gravi_dec_to_rad (p_dec[row]);
747
748 /* Compute distance in [rad]
749 * FIXME: we assume J2000 everywere */
750 double dist = acos ( sin (c_dec) * sin (dec) + cos (c_dec) * cos (dec) * cos (ra - c_ra) );
751
752 /* Closest so far */
753 if ( dist < dis0 ) {
754 row0 = row;
755 dis0 = dist;
756 }
757 } /* End loop on rows */
758
759 /* Best separation in arcsec */
760 if (separation != NULL) *separation = dis0 / CPL_MATH_PI * 180 * 3600;
761
763 return row0;
764}
765
766/*----------------------------------------------------------------------------*/
776/*----------------------------------------------------------------------------*/
777
778gravi_data * gravi_compute_tf (gravi_data * vis_data, gravi_data * diamcat_data)
779{
781 cpl_ensure (vis_data, CPL_ERROR_NULL_INPUT, NULL);
782
783 gravi_data * tf_data = NULL;
784 cpl_propertylist * plist;
785 cpl_table * tf_vistable;
786 cpl_table * tf_vis2table;
787 cpl_table * oi_wavelength;
788 int nv, type_data;
789 double diameter, diameter_err, lambda, r_vis, r_vis2, tf_v, tf_v2;
790 char qc_name[90];
791
792 /* Get the OIFITS table */
793 tf_data = gravi_data_duplicate (vis_data);
794 plist = gravi_data_get_header (tf_data);
795
796 /* Loop on SC / FT */
797 for (type_data = 0; type_data < 2; type_data ++) {
798 cpl_table * diam_table;
799 double sep = 99.0;
800 cpl_size row_cat = -1;
801
802 /* Search in catalogue. Actually this should only
803 * be for SINGLE since catalogue won't be accurate for dual */
804 if (diamcat_data) {
805 /* Get the matching row */
806 diam_table = gravi_data_get_table_x (diamcat_data, 0);
807 row_cat = gravi_get_row_in_cat (diam_table,
808 gravi_pfits_get_type_raep (plist, type_data),
810 &sep);
811
812 /* Use it only if closest than 5" */
813 if ( (row_cat > -1) && (sep < 5.0) ) {
814 cpl_msg_info (cpl_func, "Find match in DIAMETER_CAT (best sep=%.2f arcsec)", sep);
815 diameter = cpl_table_get (diam_table, "UDDK", row_cat, NULL);
816 diameter_err = cpl_table_get (diam_table, "e_LDD", row_cat, NULL);
817 } else {
818 cpl_msg_warning (cpl_func, "No match in DIAMETER_CAT (best sep=%.2f arcsec), use the HEADER value instead", sep);
819 diameter = gravi_pfits_get_diameter (plist, type_data);
820 diameter_err = 0.15;
821 }
822
823 } else {
824 cpl_msg_info (cpl_func, "No DIAMETER_CAT, use the HEADER value if any");
825 diameter = gravi_pfits_get_diameter (plist, type_data);
826 diameter_err = 0.15;
827 }
828
829 /* Verbose about diameter value with a warning if weird value
830 * Or a return NULL is value is zero */
831 if ( diameter>=4.0 ) {
832 cpl_msg_warning (cpl_func,"Diameter for %s target: %.3f (+-%.3f) mas. Expected ?", GRAVI_TYPE(type_data), diameter, diameter_err);
833 }
834 else if (diameter <= 0.0 && !gravi_data_is_internal(vis_data)) {
835 cpl_msg_warning (cpl_func, "Diameter for %s target: 0.0 mas. Probably wrong, check parameter value", GRAVI_TYPE(type_data));
836 /* FREE (gravi_data_delete, tf_data);
837 return NULL;*/
838 }
839 else {
840 cpl_msg_info(cpl_func,"Diameter for %s target: %.3f (+-%.3f) mas", GRAVI_TYPE(type_data), diameter, diameter_err);
841 }
842
843 /* Loop on polarisations */
844 int pol,npol = gravi_pfits_get_pola_num (plist, type_data);
845 for (pol = 0; pol < npol; pol ++){
846
847 oi_wavelength = gravi_data_get_oi_wave (vis_data, type_data, pol,npol);
848 tf_vistable = gravi_data_get_oi_vis (tf_data, type_data, pol,npol);
849 tf_vis2table = gravi_data_get_oi_vis2 (tf_data, type_data, pol,npol);
850
851 if ((tf_vistable == NULL) || (tf_vis2table == NULL) || (oi_wavelength == NULL)){
852 FREE (gravi_data_delete, tf_data);
853 cpl_error_set_message (cpl_func, CPL_ERROR_NULL_INPUT,
854 "Missing OI_VIS or OI_VIS2 or OI_WAVELENGTH");
855 return NULL;
856 }
857
858 /* Construction of the data */
859
860 /* Loop on row in the table -- warning, we here suppose the OI_VIS and
861 * OI_VIS2 have the same number of rows */
862 int nrow = cpl_table_get_nrow (tf_vistable);
863 int nwave = cpl_table_get_column_depth (tf_vis2table, "VIS2DATA" );
864 for (cpl_size row = 0; row < nrow; row ++){
865
866 /* Compute norm for the baseline in meters */
867 r_vis = sqrt (pow (cpl_table_get_double (tf_vistable, "UCOORD", row, &nv), 2) +
868 pow (cpl_table_get_double (tf_vistable, "VCOORD", row, &nv), 2));
869
870 r_vis2 = sqrt (pow (cpl_table_get_double (tf_vis2table, "UCOORD", row, &nv), 2) +
871 pow (cpl_table_get_double (tf_vis2table, "VCOORD", row, &nv), 2));
872
873 CPLCHECK_NUL ("Cannot extract UVCOORD");
874
875 /* Compute the model visibility from uniform disk */
876 cpl_array * model_vis = cpl_array_new (nwave, CPL_TYPE_DOUBLE);
877 cpl_array * model_vis2 = cpl_array_new (nwave, CPL_TYPE_DOUBLE);
878
879 /* Loop on wave */
880 for (cpl_size wave = 0; wave < nwave ; wave ++){
881 /* This computation is validated */
882 lambda = cpl_table_get (oi_wavelength, "EFF_WAVE", wave, &nv);
883 tf_v = gravi_visibility_UD (r_vis, diameter, lambda);
884 tf_v2 = pow (gravi_visibility_UD (r_vis2, diameter, lambda), 2.0);
885
886 /* Set into the temporary array */
887 cpl_array_set_double (model_vis, wave, tf_v);
888 cpl_array_set_double (model_vis2, wave, tf_v2);
889 }
890 /* End loop on wave */
891
892 /* Divide the observed visibilities by the model for VISAMP */
893 cpl_array * tf_vis = cpl_table_get_data_array (tf_vistable, "VISAMP")[row];
894 cpl_array * tf_visErr = cpl_table_get_data_array (tf_vistable, "VISAMPERR")[row];
895 cpl_array_divide (tf_vis, model_vis);
896 cpl_array_divide (tf_visErr, model_vis);
897
898 /* Divide the observed visibilities by the model for VIS2 */
899 cpl_array * tf_vis2 = cpl_table_get_data_array (tf_vis2table, "VIS2DATA")[row];
900 cpl_array * tf_vis2Err = cpl_table_get_data_array (tf_vis2table, "VIS2ERR")[row];
901 cpl_array_divide (tf_vis2, model_vis2);
902 cpl_array_divide (tf_vis2Err, model_vis2);
903
904 CPLCHECK_NUL("Cannot set the tf array");
905
906 /* Compute the relative error on the TF at 2.2 microns
907 * due to the diameter uncertainty */
908 double errRelTF = fabs (( gravi_visibility_UD (r_vis, (diameter+diameter_err), 2.2e-6) -
909 gravi_visibility_UD (r_vis, (diameter-diameter_err), 2.2e-6) ) /
910 gravi_visibility_UD (r_vis, diameter, 2.2e-6) );
911
912 /* Note that VISPHI, T3PHI, T3AMP, VISDATA are already in
913 * output table since they are duplicated */
914
915 /* Add QC params. FIXME: deal with QC parameter if multiple files
916 * - *mean* over file QC TF VISAMP_SC12_P1 AVG
917 * - *p2p* over file
918 * FIXME: put both polarisation in a single QC */
919
920 /* Get baseline name and id */
921 int base=row%6;
922
923 sprintf (qc_name, "ESO QC TF VISMOD_%s%s RELERR", GRAVI_TYPE(type_data), GRAVI_BASE_NAME[base]);
924 gravi_pfits_update_double (plist, qc_name, errRelTF);
925 cpl_propertylist_set_comment (plist, qc_name, "TF rel.err from diameter at 2.2um");
926 CPLCHECK_NUL ("QC TF VISMOD RELERR");
927
928 sprintf (qc_name, "ESO QC TF VISAMP_%s%s_P%d MED", GRAVI_TYPE(type_data), GRAVI_BASE_NAME[base], pol+1);
929 gravi_pfits_update_double (plist, qc_name, cpl_array_get_median (tf_vis));
930 cpl_propertylist_set_comment (plist, qc_name, "TF. VIS median over lbd.");
931 CPLCHECK_NUL ("QC TF VIS AVG");
932
933 sprintf (qc_name, "ESO QC TF VIS2_%s%s_P%d MED", GRAVI_TYPE(type_data), GRAVI_BASE_NAME[base], pol+1);
934 gravi_pfits_update_double (plist, qc_name, cpl_array_get_median (tf_vis2));
935 cpl_propertylist_set_comment (plist, qc_name, "TF. VIS2 median over lbd.");
936 CPLCHECK_NUL ("QC TF VIS2 AVG");
937
938 /* Free Memory */
939 cpl_array_delete (model_vis2);
940 cpl_array_delete (model_vis);
941 }
942 /* End loop on rows */
943 }
944 /* End loop on pol */
945
946
947 /* Compute the transmission QC only if a
948 * valid match with catalog is found */
949 if ( (row_cat > -1) && (sep < 5.0) ) {
950
951 /* Check if consistent setup (all ATs or all UTs) */
952 cpl_table * oi_array = gravi_data_get_table (vis_data, GRAVI_OI_ARRAY_EXT);
953 const char sta = *cpl_table_get_string (oi_array, "TEL_NAME", 0);
954 if (*cpl_table_get_string (oi_array, "TEL_NAME", 1) != sta ||
955 *cpl_table_get_string (oi_array, "TEL_NAME", 2) != sta ||
956 *cpl_table_get_string (oi_array, "TEL_NAME", 3) != sta)
957 {
958 cpl_error_set_message (cpl_func, CPL_ERROR_ILLEGAL_INPUT, "AT/UT mode is not supported");
959 return NULL;
960 }
961
962 /* Compute in [photons/s/m2] */
963 double diam = 1.0;
964 if (sta=='U') { diam = 8.0; cpl_msg_info (cpl_func, "Use UTs"); }
965 else if (sta=='A') { diam = 1.8; cpl_msg_info (cpl_func, "Use ATs"); }
966 else { diam = 1.0; cpl_msg_warning (cpl_func, "Cannot find the diameter of telescope"); }
967
968 /* Get the expected flux in [photons/s] */
969 double Kmag = cpl_table_get (diam_table, "Kmag", row_cat, NULL);
970 double flux0 = 1.71173e+09 * pow (10.0, -Kmag/2.5) * (CPL_MATH_PI * pow (diam/2, 2));
971 cpl_msg_info (cpl_func, "Use Kmag=%.2f for QC.TRANS", Kmag);
972
973 /* Loop on beam */
974 for (int tel = 0; tel < 4; tel++) {
975 double flux = 0.0;
976
977 /* Get the total observed flux in [e/s] */
978 sprintf (qc_name, "ESO QC FLUXRATE_%s%i_P1 SUM",GRAVI_TYPE(type_data),tel+1);
979 flux += gravi_pfits_get_double_silentdefault (plist, qc_name, 0.);
980 sprintf (qc_name, "ESO QC FLUXRATE_%s%i_P2 SUM",GRAVI_TYPE(type_data),tel+1);
981 flux += gravi_pfits_get_double_silentdefault (plist, qc_name, 0.);
982 CPLCHECK_NUL ("Cannot get fluxrate");
983
984 /* Add the QC parameter */
985 sprintf (qc_name, "ESO QC TF TRANS_%s%i",GRAVI_TYPE(type_data),tel+1);
986 gravi_pfits_update_double (plist, qc_name, flux / flux0 * 100.0);
987 cpl_propertylist_set_comment (plist, qc_name, "[%] Total transmission");
988 cpl_msg_info (cpl_func, "%s = %.2f%%", qc_name, flux / flux0 * 100.0);
989 CPLCHECK_NUL ("QC TRANS");
990 }
991 } /* End computation of TF */
992
993 }
994 /* End loop on type_data */
995
997 return tf_data;
998}
999
1000/*----------------------------------------------------------------------------*/
1012/*----------------------------------------------------------------------------*/
1013
1014cpl_error_code gravi_compute_tf_qc (gravi_data * oi_vis, gravi_data * diamcat_data)
1015{
1017 cpl_ensure_code (oi_vis, CPL_ERROR_NULL_INPUT);
1018
1019 cpl_errorstate prestate = cpl_errorstate_get();
1020
1021 cpl_msg_info (cpl_func, "Compute the QC TF parameters");
1022
1023 /* Compute TF */
1024 gravi_data * oi_tf = gravi_compute_tf (oi_vis, diamcat_data);
1025
1026 /* If an error is catch when computing the QC parameters, dump this error but continue */
1027 if ( cpl_error_get_code() || oi_tf == NULL) {
1028 cpl_msg_warning (cpl_func, "Cannot compute the QC TF parameters for this observation... continue.");
1029 cpl_errorstate_set (prestate);
1030 return CPL_ERROR_NONE;
1031 }
1032
1033 /* Copy to header */
1034 cpl_propertylist_copy_property_regexp (gravi_data_get_header (oi_vis),
1035 gravi_data_get_header (oi_tf),
1036 ".*QC TF.*", 0);
1037 FREE (gravi_data_delete,oi_tf);
1038
1040 return CPL_ERROR_NONE;
1041}
1042
1043/*----------------------------------------------------------------------------*/
1047/*----------------------------------------------------------------------------*/
1048
1049gravi_data * gravi_compute_zp (gravi_data ** vis_calib, int num_calib)
1050{
1052 cpl_ensure (vis_calib, CPL_ERROR_NULL_INPUT, NULL);
1053 cpl_ensure (num_calib>0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1054
1055 gravi_data * zero_met = gravi_data_duplicate (vis_calib[0]);
1056
1058 return zero_met;
1059}
1060
1061
typedefCPL_BEGIN_DECLS struct _gravi_data_ gravi_data
Definition: gravi_data.h:38
#define gravi_data_is_internal(data)
Definition: gravi_data.h:77
#define gravi_data_get_header(data)
Definition: gravi_data.h:74
#define gravi_data_get_oi_vis2(data, type, pol, npol)
Definition: gravi_data.h:46
#define gravi_data_get_oi_wave(data, type, pol, npol)
Definition: gravi_data.h:44
#define gravi_data_get_oi_vis(data, type, pol, npol)
Definition: gravi_data.h:45
cpl_msg_debug(cpl_func, "Spectra has <50 pixels -> don't flat")
cpl_propertylist * plist
Definition: gravi_old.c:2000
cpl_msg_info(cpl_func, "Compute WAVE_SCAN for %s", GRAVI_TYPE(type_data))
#define GRAVI_OI_VIS2_EXT
Definition: gravi_pfits.h:95
#define GRAVI_INSNAME(type, pol, npol)
Definition: gravi_pfits.h:198
#define GRAVI_OI_ARRAY_EXT
Definition: gravi_pfits.h:83
#define GRAVI_SC
Definition: gravi_pfits.h:165
#define GRAVI_OI_VIS_EXT
Definition: gravi_pfits.h:92
#define GRAVI_OI_FLUX_EXT
Definition: gravi_pfits.h:93
#define gravi_pfits_get_type_raep(plist, type)
Definition: gravi_pfits.h:211
#define gravi_pfits_get_type_decep(plist, type)
Definition: gravi_pfits.h:210
#define GRAVI_OI_T3_EXT
Definition: gravi_pfits.h:94
#define GRAVI_TYPE(type)
Definition: gravi_pfits.h:167
#define GRAVI_FT
Definition: gravi_pfits.h:166
#define gravi_msg_function_exit(flag)
Definition: gravi_utils.h:85
#define FREE(function, variable)
Definition: gravi_utils.h:69
#define CPLCHECK_NUL(msg)
Definition: gravi_utils.h:48
#define gravi_msg_function_start(flag)
Definition: gravi_utils.h:84
#define CPLCHECK_MSG(msg)
Definition: gravi_utils.h:45
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:1069
gravi_data * gravi_data_duplicate(const gravi_data *self)
Create a copy of the gravi data.
Definition: gravi_data.c:250
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:2096
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:1952
cpl_table * gravi_data_get_table_x(gravi_data *self, int i)
Get the table of an extension by position.
Definition: gravi_data.c:1901
void gravi_data_delete(gravi_data *self)
Delete a gravi data.
Definition: gravi_data.c:146
int gravi_param_get_bool(const cpl_parameterlist *parlist, const char *name)
Definition: gravi_dfs.c:1537
double gravi_param_get_double(const cpl_parameterlist *parlist, const char *name)
Definition: gravi_dfs.c:1511
int gravi_pfits_get_pola_num(const cpl_propertylist *plist, int type_data)
Definition: gravi_pfits.c:263
cpl_error_code gravi_pfits_update_double(cpl_propertylist *plist, const char *full_name, double value)
Definition: gravi_pfits.c:1518
const char * gravi_pfits_get_pola_mode(const cpl_propertylist *plist, int type_data)
Definition: gravi_pfits.c:169
const char * gravi_pfits_get_spec_res(const cpl_propertylist *plist)
Definition: gravi_pfits.c:162
double gravi_pfits_get_dit_sc(const cpl_propertylist *plist)
Definition: gravi_pfits.c:664
double gravi_dec_to_rad(const char *stri)
Definition: gravi_pfits.c:1255
double gravi_pfits_get_dit_ft(const cpl_propertylist *plist)
Definition: gravi_pfits.c:673
double gravi_pfits_get_double_silentdefault(const cpl_propertylist *plist, const char *name, double def)
Definition: gravi_pfits.c:1612
double gravi_pfits_get_diameter(const cpl_propertylist *plist, int type_data)
Definition: gravi_pfits.c:100
double gravi_ra_to_rad(const char *stri)
Definition: gravi_pfits.c:1236
char * gravi_calib_setupstring(gravi_data *data)
Build a unique setup string per calibratable setup.
Definition: gravi_tf.c:201
gravi_data * gravi_calibrate_vis(gravi_data *vis_data, gravi_data **tf_data, int num_tf, gravi_data *phi_tf_data, 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:521
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
double gravi_visibility_UD(double uv, double diam, double lbd)
Compute the expected visibility from a UD model.
Definition: gravi_tf.c:703
int gravi_array_set_invalid_negative(cpl_array *array)
Set invalid to all negative elements of an array.
Definition: gravi_tf.c:86
gravi_data * gravi_compute_zp(gravi_data **vis_calib, int num_calib)
Compute the ZP data.
Definition: gravi_tf.c:1049
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:723
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_compute_tf_qc(gravi_data *oi_vis, gravi_data *diamcat_data)
Fill QC parameters related to transfer function.
Definition: gravi_tf.c:1014
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:385
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
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:778
char GRAVI_BASE_NAME[6][3]
Definition: gravi_utils.c:57