GRAVI Pipeline Reference Manual 1.9.4
Loading...
Searching...
No Matches
gravi_signal.c
Go to the documentation of this file.
1/* $Id: gravi_vis.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
37/*-----------------------------------------------------------------------------
38 Includes
39 -----------------------------------------------------------------------------*/
40
41#ifdef HAVE_CONFIG_H
42#include <config.h>
43#endif
44
45#include <cpl.h>
46#include <string.h>
47#include <stdio.h>
48#include <math.h>
49#include <time.h>
50#include <complex.h>
51
52#include "gravi_data.h"
53#include "gravi_dfs.h"
54#include "gravi_pfits.h"
55#include "gravi_cpl.h"
56
57#include "gravi_utils.h"
58#include "gravi_signal.h"
59
60/*-----------------------------------------------------------------------------
61 Private prototypes
62 -----------------------------------------------------------------------------*/
63
64cpl_error_code gravi_vis_bootstrap_snr_and_delay(cpl_table * oi_vis,
65 const char * name_snr,
66 const char * name_gdl);
67cpl_error_code gravi_vis_correct_phasediff(cpl_table * oi_vis1, const char *name1,
68 cpl_table * oi_vis2, const char *name2,
69 double * phasediff);
70cpl_error_code gravi_vis_compute_mean_phasor(cpl_table * oi_vis,
71 const char * name_vis,
72 const char * name_err,
73 const char * name_pha,
74 const char * name_var,
75 const char * name_flag);
76cpl_error_code gravi_vis_compute_interspectre (cpl_table * oi_vis,
77 const char * name_vis,
78 const char * name_is,
79 const char * name_flag);
80cpl_error_code gravi_vis_compute_snr(cpl_table * oi_vis,
81 const char * name_pha,
82 const char * name_var,
83 const char * name_snr);
84cpl_error_code gravi_vis_compute_isdelay(cpl_table * oi_vis,
85 const char * name_isp,
86 const char * name_gdl,
87 cpl_table * oi_wavelength);
88cpl_error_code gravi_vis_create_pfactor_sc (cpl_table * vis_SC, cpl_table * t3_SC, cpl_table * flux_FT);
89cpl_error_code gravi_vis_create_pfactor_ft (cpl_table * vis_FT, cpl_table * flux_FT, cpl_size window_width);
90cpl_error_code gravi_vis_create_f1f2_sc (cpl_table * vis_SC, cpl_table * flux_SC);
91cpl_error_code gravi_vis_create_f1f2_ft (cpl_table * vis_FT, cpl_table * flux_FT);
92cpl_error_code gravi_vis_create_phaseref_ft (cpl_table * vis_FT);
93cpl_error_code gravi_vis_create_met_sc (cpl_table * vis_SC, cpl_table * vis_MET, cpl_table * wave_table);
94cpl_error_code gravi_create_outlier_flag_sc (cpl_table * flux_SC, cpl_table * vis_SC,
95 double chi2r_threshold, double chi2r_sigma);
96cpl_error_code gravi_create_outlier_flag_ft (cpl_table * flux_SC, cpl_table * vis_SC);
97cpl_error_code gravi_flux_create_fddlpos_sc (cpl_table * flux_SC, cpl_table * fddl_table);
98cpl_error_code gravi_flux_create_totalflux_sc (cpl_table * flux_SC, cpl_table * flux_FT);
99cpl_error_code gravi_flux_create_met_sc (cpl_table * flux_SC, cpl_table * vis_MET);
100cpl_error_code gravi_flux_create_acq_sc (cpl_table * vis_SC,
101 cpl_table * vis_ACQ);
102
103cpl_error_code gravi_vis_create_acq_sc (cpl_table * vis_SC,
104 cpl_table * vis_ACQ);
105
106cpl_error_code gravi_vis_create_vfactor_sc (cpl_table * vis_SC,
107 cpl_table * wave_table_sc,
108 cpl_table * vis_FT,
109 cpl_table * wave_table_ft);
110cpl_error_code gravi_vis_create_lockratio_sc (cpl_table * vis_SC,
111 cpl_table * vis_FT);
112
113cpl_error_code gravi_vis_create_phaseref_sc (cpl_table * vis_SC,
114 cpl_table * wave_table_sc,
115 cpl_table * wave_table_ft,
116 cpl_propertylist * header,
117 const cpl_parameterlist * parlist);
118
119cpl_error_code gravi_vis_create_opddisp_sc (cpl_table * vis_SC,
120 cpl_table * flux_SC,
121 cpl_table * wave_table,
122 cpl_table * disp_table,
123 cpl_propertylist * header,
124 const cpl_parameterlist * parlist);
125
126cpl_error_code gravi_vis_create_imagingref_sc (cpl_table * vis_SC,
127 cpl_table * wave_table,
128 cpl_propertylist * header,
129 const cpl_parameterlist * parlist);
130
131/*-----------------------------------------------------------------------------
132 Function code
133 -----------------------------------------------------------------------------*/
134
135/* -------------------------------------------------------------------------- */
148/* -------------------------------------------------------------------------- */
149
150cpl_error_code gravi_vis_bootstrap_snr_and_delay(cpl_table * oi_vis,
151 const char * name_snr,
152 const char * name_gdl)
153{
155 cpl_ensure_code (oi_vis, CPL_ERROR_NULL_INPUT);
156 cpl_ensure_code (name_snr, CPL_ERROR_NULL_INPUT);
157 cpl_ensure_code (name_gdl, CPL_ERROR_NULL_INPUT);
158
159 /* Get poointer to data */
160 double * snr = cpl_table_get_data_double (oi_vis, name_snr);
161 double * gdl = cpl_table_get_data_double (oi_vis, name_gdl);
162
163 CPLCHECK_MSG("Cannot load data to compute SNR column");
164
165 /* Loop on base */
166 cpl_size nrow = cpl_table_get_nrow (oi_vis) / 6;
167 for (int base=0; base<6; base++ ) {
168
169 /* Loop on the two closing triangles of this baseline */
170 for (int tri=0; tri<2; tri++ ) {
171
172 /* Search a closing triangle */
173 int b1 = GRAVI_TRI_BASE[base][tri][0];
174 int b2 = GRAVI_TRI_BASE[base][tri][1];
175 int sign1 = GRAVI_TRI_SIGN[base][tri][0];
176 int sign2 = GRAVI_TRI_SIGN[base][tri][1];
177
178 cpl_msg_debug(cpl_func, "Found triangle tels %i%i -> bases (%i,%i, %i,%i)",
179 GRAVI_BASE_TEL[base][0],GRAVI_BASE_TEL[base][1],b1,b2,sign1,sign2);
180
181 /* Loop on rows */
182 for (cpl_size row = 0; row < nrow; row++) {
183 /* Get the bootstraped SNR as the min over the closing baseline */
184 double snrN = CPL_MIN( snr[row*6+b1], snr[row*6+b2] );
185 if ( snrN > snr[row*6+base] ) {
186 snr[row*6+base] = snrN;
187 gdl[row*6+base] = sign1 * gdl[row*6+b1] + sign2 * gdl[row*6+b2];
188 }
189 }
190 /* End loop on rows */
191 }
192 /* End loop on closing triangle */
193
194 cpl_msg_debug(cpl_func,"TODO: loop on 3-baseline bootstrap");
195 }
196 /* End loop on base */
197
199 return CPL_ERROR_NONE;
200}
201
202/* -------------------------------------------------------------------------- */
216/* -------------------------------------------------------------------------- */
217
218cpl_error_code gravi_vis_correct_phasediff(cpl_table * oi_vis1, const char *name1,
219 cpl_table * oi_vis2, const char *name2,
220 double * phasediff)
221{
223 cpl_ensure_code (oi_vis1, CPL_ERROR_NULL_INPUT);
224 cpl_ensure_code (oi_vis2, CPL_ERROR_NULL_INPUT);
225 cpl_ensure_code (name1, CPL_ERROR_NULL_INPUT);
226 cpl_ensure_code (name2, CPL_ERROR_NULL_INPUT);
227 cpl_ensure_code (phasediff, CPL_ERROR_ILLEGAL_OUTPUT);
228
229 int nbase = 6;
230
231 cpl_type type1 = cpl_table_get_column_type (oi_vis1, name1 );
232 cpl_type type2 = cpl_table_get_column_type (oi_vis2, name2 );
233 cpl_size nrow1 = cpl_table_get_nrow (oi_vis1) / nbase;
234 cpl_size nrow2 = cpl_table_get_nrow (oi_vis2) / nbase;
235
236 if ( type1 != CPL_TYPE_DOUBLE_COMPLEX ||
237 type2 != CPL_TYPE_DOUBLE_COMPLEX ||
238 nrow1 != nrow2)
239 return cpl_error_set_message (cpl_func,CPL_ERROR_ILLEGAL_INPUT,"input columns not conformables or not DOUBLE COMPLEX");
240
241 double complex * data1 = cpl_table_get_data_double_complex (oi_vis1, name1);
242 double complex * data2 = cpl_table_get_data_double_complex (oi_vis2, name2);
243 CPLCHECK_MSG("Cannot load data");
244
245 /* Loop on base */
246 for (int base = 0; base < nbase; base++) {
247 double complex phasor = 0.0;
248
249 /* Multiply and sum */
250 for (cpl_size row = 0; row < nrow1; row++) {
251 phasor += data1[row*nbase+base] * conj( data2[row*6+base] );
252 }
253
254 phasediff[base] = carg( phasor );
255
256 /* Correct phase from oi_vis1 to be the one of oi_vis2 */
257 for (cpl_size row = 0; row < nrow1; row++) {
258 data1[row*6+base] *= cexp( -I*phasediff[base] );
259 }
260 }
261
263 return CPL_ERROR_NONE;
264}
265
266/* -------------------------------------------------------------------------- */
278/* -------------------------------------------------------------------------- */
279
280cpl_error_code gravi_vis_compute_mean_phasor(cpl_table * oi_vis,
281 const char * name_vis,
282 const char * name_err,
283 const char * name_pha,
284 const char * name_var,
285 const char * name_flag)
286{
288 cpl_ensure_code (oi_vis, CPL_ERROR_NULL_INPUT);
289 cpl_ensure_code (name_vis, CPL_ERROR_NULL_INPUT);
290 cpl_ensure_code (name_err, CPL_ERROR_NULL_INPUT);
291 cpl_ensure_code (name_pha, CPL_ERROR_ILLEGAL_OUTPUT);
292 cpl_ensure_code (name_var, CPL_ERROR_ILLEGAL_OUTPUT);
293 cpl_ensure_code (name_flag,CPL_ERROR_ILLEGAL_OUTPUT);
294
295 cpl_size nrow = cpl_table_get_nrow (oi_vis);
296
297 /* Init memory for the output array. */
298 gravi_table_new_column (oi_vis, name_pha, "e", CPL_TYPE_DOUBLE_COMPLEX);
299 double complex * phasorRaw = cpl_table_get_data_double_complex (oi_vis, name_pha);
300
301 gravi_table_new_column (oi_vis, name_var, "e^2", CPL_TYPE_DOUBLE);
302 double * varRaw = cpl_table_get_data_double (oi_vis, name_var);
303
304 /* Get input pointer to speed up */
305 cpl_array** tVis = cpl_table_get_data_array (oi_vis, name_vis);
306 cpl_array** tErr = cpl_table_get_data_array (oi_vis, name_err);
307 cpl_array** tFlag = cpl_table_get_data_array (oi_vis, name_flag);
308 cpl_ensure_code (tFlag, CPL_ERROR_ILLEGAL_INPUT);
309
310 /* Get nwave */
311 int nwave = cpl_array_get_size (tVis[0]);
312
313 CPLCHECK_MSG ("Cannot get data");
314
315 /* Loop on rows and bases */
316 for (cpl_size row = 0; row < nrow; row++ ) {
317
318 double complex * cpx = cpl_array_get_data_double_complex (tVis[row]);
319 double complex * err = cpl_array_get_data_double_complex (tErr[row]);
320 cpl_ensure_code (cpx, CPL_ERROR_ILLEGAL_INPUT);
321 cpl_ensure_code (err, CPL_ERROR_ILLEGAL_INPUT);
322 phasorRaw[row] = 0.0;
323 varRaw[row] = 0.0;
324
325 int * flag = cpl_array_get_data_int (tFlag[row]);
326
327 /* Compute integrated phasor and variance over the spectral channels,
328 ignore flagged values if a flag is provided */
329 for (cpl_size wave = 0; wave < nwave; wave++)
330 {
331 if (!flag[wave]) {
332 phasorRaw[row] += cpx[wave];
333 varRaw[row] += cabs(err[wave]) * cabs(err[wave]);
334 }
335 }
336 }
337 /* End loop on rows */
338
339 CPLCHECK_MSG("Cannot fill IS and PHASOR column");
340
342 return CPL_ERROR_NONE;
343}
344
345/* -------------------------------------------------------------------------- */
357/* -------------------------------------------------------------------------- */
358
359cpl_error_code gravi_vis_compute_interspectre (cpl_table * oi_vis,
360 const char * name_vis,
361 const char * name_is,
362 const char * name_flag)
363{
365 cpl_ensure_code (oi_vis, CPL_ERROR_NULL_INPUT);
366 cpl_ensure_code (name_vis, CPL_ERROR_NULL_INPUT);
367 cpl_ensure_code (name_is, CPL_ERROR_NULL_INPUT);
368 cpl_ensure_code (name_flag, CPL_ERROR_NULL_INPUT);
369
370 cpl_size nrow = cpl_table_get_nrow (oi_vis);
371
372 /* Get input pointer to speed up */
373 cpl_array** tVis = cpl_table_get_data_array (oi_vis, name_vis);
374 cpl_ensure_code (tVis, CPL_ERROR_ILLEGAL_INPUT);
375
376 cpl_array** tFlag = cpl_table_get_data_array (oi_vis, name_flag);
377 cpl_ensure_code (tFlag, CPL_ERROR_ILLEGAL_INPUT);
378
379 /* Get nwave */
380 int nwave = cpl_array_get_size (tVis[0]);
381
382 CPLCHECK_MSG ("Cannot get data");
383
384 /* Init memory for the output array. */
385 gravi_table_new_column (oi_vis, name_is, "e^2", CPL_TYPE_DOUBLE_COMPLEX);
386 double complex * interSpectreRaw = cpl_table_get_data_double_complex (oi_vis, name_is);
387
388 CPLCHECK_MSG ("Cannot create columns");
389
390 /* Loop on rows and bases */
391 for (cpl_size row = 0; row < nrow; row++) {
392
393 double complex * cpx = cpl_array_get_data_double_complex (tVis[row]);
394 cpl_ensure_code (cpx, CPL_ERROR_ILLEGAL_INPUT);
395
396 int * flag = cpl_array_get_data_int (tFlag[row]);
397 cpl_ensure_code (flag, CPL_ERROR_ILLEGAL_INPUT);
398
399 interSpectreRaw[row] = 0.0;
400
401 /* Compute integrated interspectre over the spectral channels,
402 ignore the flagged values if a flag is provided */
403 for (cpl_size wave = 0; wave < nwave-1; wave++)
404 {
405 if (!flag[wave] && !flag[wave+1]) {
406 interSpectreRaw[row] += cpx[wave] * conj( cpx[wave+1] );
407 }
408 }
409 }
410 /* End loop on rows */
411
412 CPLCHECK_MSG ("Cannot fill IS column");
413
415 return CPL_ERROR_NONE;
416}
417
418
419/* -------------------------------------------------------------------------- */
430/* -------------------------------------------------------------------------- */
431
432cpl_error_code gravi_vis_compute_snr (cpl_table * oi_vis,
433 const char * name_pha,
434 const char * name_var,
435 const char * name_snr)
436{
438 cpl_ensure_code (oi_vis, CPL_ERROR_NULL_INPUT);
439 cpl_ensure_code (name_pha, CPL_ERROR_NULL_INPUT);
440 cpl_ensure_code (name_var, CPL_ERROR_NULL_INPUT);
441 cpl_ensure_code (name_snr, CPL_ERROR_ILLEGAL_OUTPUT);
442
443 cpl_size nrow = cpl_table_get_nrow (oi_vis);
444
445 /* Get input pointer to data */
446 double complex * cpx = cpl_table_get_data_double_complex (oi_vis, name_pha);
447 double * dbl = cpl_table_get_data_double (oi_vis, name_var);
448
449 CPLCHECK_MSG ("Cannot load data to compute SNR column");
450
451 /* Init memory for the output array. */
452 gravi_table_new_column (oi_vis, name_snr, NULL, CPL_TYPE_DOUBLE);
453 double * snr = cpl_table_get_data_double (oi_vis, name_snr);
454
455 CPLCHECK_MSG ("Cannot createl SNR column");
456
457 /* Loop on rows and bases */
458 for (cpl_size row = 0; row < nrow; row++) {
459 snr[row] = cabs( cpx[row] ) / sqrt (fabs(dbl[row]));
460 }
461
462 CPLCHECK_MSG ("Cannot fill SNR column");
463
465 return CPL_ERROR_NONE;
466}
467
468/* -------------------------------------------------------------------------- */
480/* -------------------------------------------------------------------------- */
481
482cpl_error_code gravi_vis_compute_isdelay (cpl_table * oi_vis,
483 const char * name_isp,
484 const char * name_gdl,
485 cpl_table * oi_wavelength)
486{
488 cpl_ensure_code (oi_vis, CPL_ERROR_NULL_INPUT);
489 cpl_ensure_code (name_isp, CPL_ERROR_NULL_INPUT);
490 cpl_ensure_code (name_gdl, CPL_ERROR_NULL_INPUT);
491 cpl_ensure_code (oi_wavelength, CPL_ERROR_NULL_INPUT);
492
493 cpl_size nrow = cpl_table_get_nrow (oi_vis);
494
495 /* Get pointer to data */
496 double complex * cpx1 = cpl_table_get_data_double_complex (oi_vis, name_isp);
497
498 CPLCHECK_MSG("Cannot load data to compute GDELAY column");
499
500 /* Init memory for the output array. */
501 gravi_table_new_column (oi_vis, name_gdl, "m", CPL_TYPE_DOUBLE);
502 double * gdl = cpl_table_get_data_double (oi_vis, name_gdl);
503 CPLCHECK_MSG("Cannot set GDELAY column");
504
505 /* Compute the coherence */
506 cpl_size wave = cpl_table_get_ncol (oi_wavelength)/2;
507 double factor = 1./fabs(1./cpl_table_get (oi_wavelength, "EFF_WAVE", wave, NULL) -
508 1./cpl_table_get (oi_wavelength, "EFF_WAVE", wave+1, NULL));
509
510 cpl_msg_debug (cpl_func, "Compute the coherence length (%e m)", factor);
511
512 CPLCHECK_MSG("Cannot compute coherence length");
513
514 /* Loop on rows and bases */
515 for (cpl_size row = 0; row < nrow; row++ ) {
516 /* Compute the GD */
517 gdl[row] = (double)carg( cpx1[row] ) / (2.0*M_PI) * factor;
518 }
519
520 CPLCHECK_MSG("Cannot fill GDELAY column");
521
523 return CPL_ERROR_NONE;
524}
525
526/*----------------------------------------------------------------------------*/
534/*----------------------------------------------------------------------------*/
535
536cpl_error_code gravi_compute_outliers (gravi_data * p2vmred_data,
537 const cpl_parameterlist * parlist)
538{
540 cpl_ensure_code (p2vmred_data, CPL_ERROR_NULL_INPUT);
541 cpl_ensure_code (parlist, CPL_ERROR_NULL_INPUT);
542
543 char qc_name[100];
544 int ntel = 4;
545
546 cpl_propertylist * p2vmred_header = gravi_data_get_header (p2vmred_data);
547 cpl_ensure_code (p2vmred_header, CPL_ERROR_ILLEGAL_INPUT);
548
549 /* Loop on polarisations and type_data */
550 for (int type_data = 0; type_data < 2; type_data ++) {
551
552 int npol = gravi_pfits_get_pola_num (p2vmred_header, type_data);
553 for (int pol = 0; pol < npol; pol++) {
554
555 cpl_table * oi_vis = gravi_data_get_oi_vis (p2vmred_data, type_data, pol, npol);
556 cpl_table * oi_flux = gravi_data_get_oi_flux (p2vmred_data, type_data, pol, npol);
557 cpl_size nrow = cpl_table_get_nrow (oi_flux) / ntel;
558 cpl_size nwave = cpl_table_get_column_depth (oi_flux, "FLUX");
559 CPLCHECK_MSG ("Cannot get data");
560
561 if (type_data == GRAVI_FT)
562 {
563 gravi_create_outlier_flag_ft (oi_flux, oi_vis);
564 }
565 else
566 {
567 double chi2r_threshold = gravi_param_get_double (parlist, "gravity.signal.chi2r-threshold");
568 double chi2r_sigma = gravi_param_get_double (parlist, "gravity.signal.chi2r-sigma");
569
570 gravi_create_outlier_flag_sc (oi_flux, oi_vis, chi2r_threshold, chi2r_sigma);
571
572 /* Fraction of chi2 outliers per channel */
573 cpl_array * array = gravi_table_get_column_sum_array (oi_flux, "FLAG", 0, ntel);
574
575 int stat[2] = {0,0};
576 for (cpl_size wave = 0; wave < nwave ; wave ++) {
577 double value = (double)cpl_array_get (array, wave, NULL) / nrow;
578 if (value > 0) stat[0]++;
579 if (value > 0.5) stat[1]++;
580 }
581
582 FREE (cpl_array_delete, array);
583 CPLCHECK_MSG ("Cannot compute stat");
584
585 /* QC */
586 sprintf (qc_name, "ESO QC OUTLIER_SC_P%i", pol+1);
587 cpl_propertylist_update_int (p2vmred_header, qc_name, stat[0]);
588 cpl_propertylist_set_comment (p2vmred_header, qc_name, "Channels with at least one outlier");
589 cpl_msg_info (cpl_func,"%s = %i ", qc_name, stat[0]);
590
591 sprintf (qc_name, "ESO QC OUTLIER50_SC_P%i",pol+1);
592 cpl_propertylist_update_int (p2vmred_header, qc_name, stat[1]);
593 cpl_propertylist_set_comment (p2vmred_header, qc_name, "Channels with more than 50% outlier");
594 cpl_msg_info (cpl_func,"%s = %i ", qc_name, stat[1]);
595 }
596
597 CPLCHECK_MSG ("Cannot create outlier flag");
598 }
599 }
600 /* End loop on polarisation and type_data */
601
603 return CPL_ERROR_NONE;
604}
605/*----------------------------------------------------------------------------*/
618/*----------------------------------------------------------------------------*/
619
620cpl_error_code gravi_compute_snr (gravi_data * p2vmred_data,
621 const cpl_parameterlist * parlist)
622{
623 /* Message and timer */
625 cpl_ensure_code (p2vmred_data, CPL_ERROR_NULL_INPUT);
626
627 int nbase = 6;
628 char qc_name[100];
629 double qc_value;
630
631 cpl_propertylist * p2vmred_header = gravi_data_get_header (p2vmred_data);
632 double periode_sc = gravi_pfits_get_period_sc (p2vmred_header); // [s]
633 CPLCHECK_MSG ("Cannot get header");
634
635 /*
636 * Compute the real-time group-delay and SNR
637 * as well as a running average.
638 */
639
640 /* Loop on polarisations and type_data */
641 for (int type_data = 0; type_data < 2; type_data ++) {
642
643 if (gravi_data_has_type (p2vmred_data, GRAVI_TYPE(type_data)) < 2 ) {
644 cpl_msg_info (cpl_func, "Cannot compute real-time snr for %s "
645 "(no data)", GRAVI_TYPE(type_data));
646 continue;
647 }
648
649 int nsmooth;
650 if (type_data == GRAVI_FT) {
651 /* For FT, the DIT is selected to match somehow the atmospheric
652 * coherence time, hence we shall smooth over 'a few' samples */
653 nsmooth = gravi_param_get_int (parlist, "gravity.signal.nsmooth-snr-ft");
654 }
655 else {
656 /* For SC, we select a smoothing of 1s. Note that the SNR of SC is
657 * not used for selecting frame, thus this choice is not critical */
658 nsmooth = 1./ periode_sc;
659 nsmooth = CPL_MIN (CPL_MAX (nsmooth, 0), 20);
660 }
661
662 /* Loop on polarisation */
663 int npol = gravi_pfits_get_pola_num (p2vmred_header, type_data);
664 for (int pol = 0; pol < npol; pol++) {
665
666 cpl_msg_info (cpl_func, "Compute SNR for pol %i of %s (smoothed over %i frames)",
667 pol+1,GRAVI_TYPE(type_data),2*nsmooth+1);
668
669 cpl_table * oi_vis = gravi_data_get_oi_vis (p2vmred_data, type_data, pol, npol);
670 CPLCHECK_MSG ("Cannot get data");
671
672 /* Compute interspectre and phasor */
673 gravi_vis_compute_interspectre (oi_vis, "VISDATA", "IPHASOR", "FLAG");
674 gravi_vis_compute_mean_phasor (oi_vis, "VISDATA", "VISERR", "PHASOR", "PHASOR_VAR", "FLAG");
675
676 /* Compute real-time SNR */
677 gravi_vis_compute_snr (oi_vis, "PHASOR", "PHASOR_VAR", "SNR");
678 CPLCHECK_MSG ("Cannot compute PHASOR and IPHASOR");
679
680 /* Compute a smoothed version of quantities. Note that this is a running SUM,
681 * not a running MEAN. Hence the SNR is enlarged by the smoothing */
682 gravi_table_runint_column (oi_vis, "IPHASOR", "IPHASOR_SMT", nsmooth, nbase);
683 gravi_table_runint_column (oi_vis, "PHASOR", "PHASOR_SMT", nsmooth, nbase);
684 gravi_table_runint_column (oi_vis, "PHASOR_VAR", "PHASOR_VAR_SMT", nsmooth, nbase);
685 CPLCHECK_MSG ("Cannot running integration");
686
687 } /* End loop on pol */
688 } /* End loop on type_data */
689
690 /*
691 * Compute bootstraped GD and SNR for the FT.
692 * Bootstraped meant with all possible information merging
693 * (polar, baseline, time)
694 */
695
696 /* Loop on type_data */
697 for (int type_data = 0; type_data < 2; type_data ++) {
698
699 if (gravi_data_has_type (p2vmred_data, GRAVI_TYPE(type_data)) < 2 ) {
700 cpl_msg_info (cpl_func, "Cannot compute bootstraped snr %s "
701 "(no data)", GRAVI_TYPE(type_data));
702 continue;
703 }
704
705 int npol = gravi_pfits_get_pola_num (p2vmred_header, type_data);
706
707 cpl_msg_info(cpl_func, "Compute bootstraped GDELAY_BOOT and SNR for %s...",(type_data==GRAVI_FT?"FT":"SC"));
708
709 /* Get the FT data */
710 cpl_table * oi_wave = gravi_data_get_oi_wave (p2vmred_data, type_data, 0, npol);
711 cpl_table * oi_vis_p2, * oi_vis_p1;
712 oi_vis_p1 = gravi_data_get_oi_vis (p2vmred_data, type_data, 0, npol);
713
714 CPLCHECK_MSG("Cannot get OI_VIS_P1 table");
715
716 /* Duplicate interspectre to get the bootstraped column */
717 cpl_table_duplicate_column (oi_vis_p1, "IPHASOR_BOOT", oi_vis_p1, "IPHASOR_SMT");
718 CPLCHECK_MSG("Cannot duplicate columns");
719
720 /* Duplicate phasor and variance to get the bootstraped column. */
721 cpl_table_duplicate_column (oi_vis_p1, "PHASOR_BOOT", oi_vis_p1, "PHASOR_SMT");
722 CPLCHECK_MSG("Cannot duplicate columns");
723
724 cpl_table_duplicate_column (oi_vis_p1, "PHASOR_VAR_BOOT", oi_vis_p1, "PHASOR_VAR_SMT");
725 CPLCHECK_MSG("Cannot duplicate columns");
726
727 /* If two polarisations */
728 if ( npol > 1) {
729
730 cpl_msg_info(cpl_func, "Add the signal of both polarisation to enhance SNR and GDELAY accuracy");
731 oi_vis_p2 = gravi_data_get_oi_vis (p2vmred_data, type_data, 1, npol);
732
733 CPLCHECK_MSG("Cannot get OI_VIS_P2 table");
734
735 /* Sum the interspectre of the second polarisation. No need to deal
736 * with polarisation shifts as they probably have the same GD */
737 gravi_table_add_columns (oi_vis_p1, "IPHASOR_BOOT", oi_vis_p2, "IPHASOR_SMT");
738 CPLCHECK_MSG("Cannot add columns");
739
740 /* Removing the mean phase difference from PHASOR of first polarisation
741 * to be able to sum with maximum SNR */
742 double phasediff[6];
743 gravi_vis_correct_phasediff (oi_vis_p1, "PHASOR_BOOT", oi_vis_p2, "PHASOR_SMT", phasediff);
744
745 /* Sum the phasor and the variance of the second polarisation. */
746 gravi_table_add_columns (oi_vis_p1, "PHASOR_BOOT", oi_vis_p2, "PHASOR_SMT");
747 gravi_table_add_columns (oi_vis_p1, "PHASOR_VAR_BOOT", oi_vis_p2, "PHASOR_VAR_SMT");
748
749 /* Dump these phase difference as QC parameters */
750 cpl_msg_info(cpl_func,"Add the phase difference as QC parameters");
751 for (int base = 0; base < nbase; base++) {
752 sprintf (qc_name, "ESO QC PHASE_POLDIFF_%s%d%d",(type_data==GRAVI_FT?"FT":"SC"),
753 GRAVI_BASE_TEL[base][0]+1, GRAVI_BASE_TEL[base][1]+1);
754 cpl_propertylist_update_double (p2vmred_header, qc_name, phasediff[base] * CPL_MATH_DEG_RAD);
755 cpl_propertylist_set_comment (p2vmred_header, qc_name, "[deg] differential phase" );
756 cpl_msg_info (cpl_func,"%s=%f [deg]",qc_name,phasediff[base] * CPL_MATH_DEG_RAD);
757 CPLCHECK_MSG("QC PHASE_POLDIFF");
758 }
759
760 CPLCHECK_MSG("Cannot add columns of second polarisation");
761 }
762 /* End case two polarisations */
763
764 /* Compute the highest possible GDDELAY and SNR per baseline. */
765 gravi_vis_compute_isdelay (oi_vis_p1, "IPHASOR_BOOT", "GDELAY_BOOT",oi_wave);
766 gravi_vis_compute_snr (oi_vis_p1, "PHASOR_BOOT", "PHASOR_VAR_BOOT", "SNR_BOOT_TMP");
767
768 /* Bootstrap over the baselines. Note the aggressive smooth of SNR to avoid
769 * bootstrapoing on noisy SNR (stabilization). */
770 int nstabilize = (type_data == GRAVI_FT ? 50 : 1);
771 gravi_table_smooth_column (oi_vis_p1, "SNR_BOOT_TMP", "SNR_BOOT", nstabilize, nbase);
772 gravi_vis_bootstrap_snr_and_delay (oi_vis_p1, "SNR_BOOT", "GDELAY_BOOT");
773
774 CPLCHECK_MSG("Cannot compute and fill SNR_BOOT or GDELAY_BOOT column");
775
776 /* If two polarisations. Copy this SNR and GDELAY to the second polarisation */
777 if (npol > 1) {
778 cpl_msg_info (cpl_func, "Duplicate columns in polarisation 2");
779 if (cpl_table_has_column (oi_vis_p2, "SNR_BOOT"))
780 cpl_table_erase_column(oi_vis_p2, "SNR_BOOT");
781 cpl_table_duplicate_column (oi_vis_p2, "SNR_BOOT", oi_vis_p1, "SNR_BOOT");
782
783 if (cpl_table_has_column (oi_vis_p2, "GDELAY_BOOT"))
784 cpl_table_erase_column(oi_vis_p2, "GDELAY_BOOT");
785 cpl_table_duplicate_column (oi_vis_p2, "GDELAY_BOOT", oi_vis_p1, "GDELAY_BOOT");
786 CPLCHECK_MSG("Cannot duplicate column for polarisation 2");
787 }
788
789 /* Remove useless column (IPHASOR, PHASOR, PHASOR_VAR) when the
790 * smoothing and bootstraping are done */
791 cpl_msg_info (cpl_func, "Erase useless columns in P2VMREDUCED");
792
793 cpl_table_erase_column (oi_vis_p1, "IPHASOR");
794 cpl_table_erase_column (oi_vis_p1, "IPHASOR_SMT");
795 cpl_table_erase_column (oi_vis_p1, "IPHASOR_BOOT");
796 cpl_table_erase_column (oi_vis_p1, "PHASOR");
797 cpl_table_erase_column (oi_vis_p1, "PHASOR_SMT");
798 cpl_table_erase_column (oi_vis_p1, "PHASOR_BOOT");
799 cpl_table_erase_column (oi_vis_p1, "PHASOR_VAR");
800 cpl_table_erase_column (oi_vis_p1, "PHASOR_VAR_SMT");
801 cpl_table_erase_column (oi_vis_p1, "PHASOR_VAR_BOOT");
802 cpl_table_erase_column (oi_vis_p1, "SNR_BOOT_TMP");
803 CPLCHECK_MSG("Cannot erase column for polarisation 1");
804
805 if ( npol > 1) {
806 cpl_table_erase_column (oi_vis_p2, "IPHASOR");
807 cpl_table_erase_column (oi_vis_p2, "IPHASOR_SMT");
808 cpl_table_erase_column (oi_vis_p2, "PHASOR");
809 cpl_table_erase_column (oi_vis_p2, "PHASOR_SMT");
810 cpl_table_erase_column (oi_vis_p2, "PHASOR_VAR");
811 cpl_table_erase_column (oi_vis_p2, "PHASOR_VAR_SMT");
812 CPLCHECK_MSG("Cannot erase column for polarisation 2");
813 }
814
815 /* Add the QC on SNR */
816 for (cpl_size base = 0; base < nbase; base++) {
817 snprintf (qc_name, 100, "ESO QC SNRB_%s%s AVG", GRAVI_TYPE(type_data), GRAVI_BASE_NAME[base]);
818 qc_value = gravi_table_get_column_mean (oi_vis_p1, "SNR_BOOT", base, nbase);
819 cpl_propertylist_update_double (p2vmred_header, qc_name, qc_value);
820 cpl_propertylist_set_comment (p2vmred_header, qc_name, "mean bootstrapped SNR");
821 }
822
823 } /* End loop on type_data */
824
826 return CPL_ERROR_NONE;
827}
828
829
830/*----------------------------------------------------------------------------*/
847/*----------------------------------------------------------------------------*/
848
849cpl_error_code gravi_signal_create_sync (cpl_table * vis_SC, int nbase_sc, double dit_sc,
850 cpl_table * vis_FT, int nbase_ft,
851 const char * name)
852{
854 cpl_ensure_code (vis_SC, CPL_ERROR_NULL_INPUT);
855 cpl_ensure_code (vis_FT, CPL_ERROR_NULL_INPUT);
856
857 /* Get the number of rows */
858 cpl_size nrow_sc = cpl_table_get_nrow (vis_SC) / nbase_sc;
859 cpl_size nrow_ft = cpl_table_get_nrow (vis_FT) / nbase_ft;
860
861 CPLCHECK_MSG ("Cannot get data");
862
863 /* Create columns in vis_SC */
864 char full_name[90];
865 sprintf (full_name, "FIRST_%s", name);
866 gravi_table_new_column (vis_SC, full_name, NULL, CPL_TYPE_INT);
867 int * first_ft = cpl_table_get_data_int (vis_SC, full_name);
868
869 sprintf (full_name, "LAST_%s", name);
870 gravi_table_new_column (vis_SC, full_name, NULL, CPL_TYPE_INT);
871 int * last_ft = cpl_table_get_data_int (vis_SC, full_name);
872
873 sprintf (full_name, "NFRAME_%s", name);
874 gravi_table_new_column (vis_SC, full_name, NULL, CPL_TYPE_INT);
875 int * nframe_ft = cpl_table_get_data_int (vis_SC, full_name);
876
877 CPLCHECK_MSG ("Cannot create columns");
878
879 /* Loop on base (here assume base may have different timing) */
880 for (cpl_size base_sc = 0; base_sc < nbase_sc; base_sc++) {
881
882 /* Start info on the second table
883 * base_ft is always 0 if nbase_ft is 1 */
884 cpl_size row_ft = 0;
885 cpl_size base_ft = base_sc % nbase_ft;
886
887 /* Loop on SC rows */
888 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc ++) {
889
890 /* Get the first FT sample */
891 while ( cpl_table_get (vis_FT, "TIME", row_ft * nbase_ft + base_ft, NULL) <
892 cpl_table_get (vis_SC, "TIME", row_sc * nbase_sc + base_sc, NULL) - dit_sc/2.) {
893 if (row_ft >= nrow_ft-1) break; // avoid reading outside of the table
894 row_ft ++;
895 }
896 first_ft[row_sc * nbase_sc + base_sc] = row_ft;
897
898 /* Get the last sample */
899 while ( cpl_table_get (vis_FT, "TIME", row_ft * nbase_ft + base_ft, NULL) <
900 cpl_table_get (vis_SC, "TIME", row_sc * nbase_sc + base_sc, NULL) + dit_sc/2.) {
901 if (row_ft >= nrow_ft-1) break; // avoid reading outside of the table
902 row_ft ++;
903 }
904 last_ft[row_sc * nbase_sc + base_sc] = row_ft;
905
906 /* Check if enough data */
907 if ( first_ft[row_sc * nbase_sc + base_sc] < 2 ||
908 last_ft[row_sc * nbase_sc + base_sc] > nrow_ft - 2 ) {
909 if (!strcmp (name, "ACQ"))
910 {
911 cpl_msg_info (cpl_func,"Not enough %s data to synchronise with DIT %lli over %lli", name, row_sc+1, nrow_sc);
912 } else {
913 cpl_msg_warning (cpl_func,"Not enough %s data to synchronise with DIT %lli over %lli", name, row_sc+1, nrow_sc);
914 }
915 first_ft[row_sc * nbase_sc + base_sc] = 0;
916 last_ft[row_sc * nbase_sc + base_sc] = 0;
917 }
918
919 /* Number of frames */
920 nframe_ft[row_sc * nbase_sc + base_sc] = last_ft[row_sc * nbase_sc + base_sc] - first_ft[row_sc * nbase_sc + base_sc];
921 }
922 }
923 /* End loop on SC row and base */
924
926 return CPL_ERROR_NONE;
927}
928
929/* -------------------------------------------------------------------------- */
941/* -------------------------------------------------------------------------- */
942
943cpl_error_code gravi_vis_create_pfactor_sc (cpl_table * vis_SC, cpl_table * t3_SC, cpl_table * flux_FT)
944{
946 cpl_ensure_code (vis_SC, CPL_ERROR_NULL_INPUT);
947 cpl_ensure_code (flux_FT, CPL_ERROR_NULL_INPUT);
948
949 /* Get the number of rows */
950 cpl_size nbase = 6, ntel = 4, nclo = 4;
951 cpl_size nrow_sc = cpl_table_get_nrow (vis_SC) / nbase;
952
953 /* Create the column */
954 gravi_table_new_column (vis_SC, "P_FACTOR", NULL, CPL_TYPE_DOUBLE);
955 double * pFactor = cpl_table_get_data_double (vis_SC, "P_FACTOR");
956
957 /* Get SC data */
958 int * first_ft = cpl_table_get_data_int (vis_SC, "FIRST_FT");
959 int * last_ft = cpl_table_get_data_int (vis_SC, "LAST_FT");
960
961 /* Get FT data (use already computed unsmoothed total-flux) */
962 double * flux = cpl_table_get_data_double (flux_FT, "TOTALFLUX_UNSMOOTHED");
963
964 CPLCHECK_MSG ("Cannot get pointer to data");
965
966 /* Loop on base and SC rows */
967 for (cpl_size base = 0; base < nbase; base++) {
968 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc++) {
969 cpl_size nsc = row_sc * nbase + base;
970
971 /* Loop on the sync FT frames */
972 double sf0f1 = 0.0, f0 = 0.0, f1 = 0.0;
973 for (cpl_size row_ft = first_ft[nsc]; row_ft < last_ft[nsc]; row_ft++) {
974 int t0 = GRAVI_BASE_TEL[base][0] + row_ft * ntel;
975 int t1 = GRAVI_BASE_TEL[base][1] + row_ft * ntel;
976 if (flux[t0] < 0.0 || flux[t1] < 0.0)
977 continue;
978 sf0f1 += sqrt (flux[t0] * flux[t1]);
979 f0 += flux[t0];
980 f1 += flux[t1];
981 }
982
983 /* Discard unused */
984 if (f0==0 || f1==0) continue;
985
986 /* Compute the pFactor */
987 pFactor[nsc] = sf0f1 * sf0f1 / (f0 * f1);
988 }
989 }
990
991 /* Create the column */
992 gravi_table_new_column (t3_SC, "P3_FACTOR", NULL, CPL_TYPE_DOUBLE);
993 double * p3Factor = cpl_table_get_data_double (t3_SC, "P3_FACTOR");
994
995 /* Get T3 data */
996 first_ft = cpl_table_get_data_int (t3_SC, "FIRST_FT");
997 last_ft = cpl_table_get_data_int (t3_SC, "LAST_FT");
998
999 /* Loop on closure triangle and SC rows */
1000 for (cpl_size closure = 0; closure < nclo; closure++) {
1001 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc++) {
1002 cpl_size nt3 = row_sc * nclo + closure;
1003
1004 /* Loop on the sync FT frames */
1005 double sf0f1f2 = 0.0, f0 = 0.0, f1 = 0.0, f2 = 0.0;
1006 for (cpl_size row_ft = first_ft[nt3]; row_ft < last_ft[nt3]; row_ft++) {
1007 int t0 = GRAVI_CLO_TEL[closure][0] + row_ft * ntel;
1008 int t1 = GRAVI_CLO_TEL[closure][1] + row_ft * ntel;
1009 int t2 = GRAVI_CLO_TEL[closure][2] + row_ft * ntel;
1010 if (flux[t0] < 0.0 || flux[t1] < 0.0 || flux[t2] < 0.0)
1011 continue;
1012 sf0f1f2 += pow (flux[t0] * flux[t1] * flux[t2], 1.0 / 3);
1013 f0 += flux[t0];
1014 f1 += flux[t1];
1015 f2 += flux[t2];
1016 }
1017
1018 /* Discard unused */
1019 if (f0==0 || f1==0 || f2==0) continue;
1020
1021 /* Compute the p3Factor */
1022 p3Factor[nt3] = sf0f1f2 * sf0f1f2 * sf0f1f2 / (f0 * f1 * f2);
1023 }
1024 }
1025
1027 return CPL_ERROR_NONE;
1028}
1029
1030/* -------------------------------------------------------------------------- */
1041/* -------------------------------------------------------------------------- */
1042
1043cpl_error_code gravi_vis_create_pfactor_ft (cpl_table * vis_FT, cpl_table * flux_FT, cpl_size window_width)
1044{
1046 cpl_ensure_code (vis_FT, CPL_ERROR_NULL_INPUT);
1047 cpl_ensure_code (flux_FT, CPL_ERROR_NULL_INPUT);
1048
1049 /* Get the number of rows */
1050 cpl_size nbase = 6, ntel = 4;
1051 cpl_size nrow_ft = cpl_table_get_nrow (vis_FT) / nbase;
1052
1053 /* Get FT data (using unsmoothed flux) */
1054 cpl_size nwave_ft = cpl_table_get_column_depth (flux_FT, "FLUX");
1055 cpl_array **p_flux = cpl_table_get_data_array (flux_FT, "FLUX");
1056
1057 /* Create the column */
1058 gravi_table_init_column_array(vis_FT, "P_FACTOR", NULL, CPL_TYPE_DOUBLE, nwave_ft);
1059 cpl_array **p_pFactor = cpl_table_get_data_array (vis_FT, "P_FACTOR");
1060
1061 CPLCHECK_MSG ("Cannot get pointer to data");
1062
1063 double *sf0f1 = cpl_malloc(nwave_ft * sizeof(double));
1064 double *f0 = cpl_malloc(nwave_ft * sizeof(double));
1065 double *f1 = cpl_malloc(nwave_ft * sizeof(double));
1066
1067 /* Loop on base and FT rows */
1068 for (cpl_size base = 0; base < nbase; base++) {
1069 for (cpl_size row_ft = 0; row_ft < nrow_ft; row_ft++) {
1070 cpl_size nft = row_ft * nbase + base;
1071
1072 /* Loop on window */
1073 int window_start = CPL_MAX(0, row_ft - window_width);
1074 int window_end = CPL_MIN(row_ft + window_width + 1, nrow_ft);
1075
1076 double *pFactor = cpl_array_get_data_double(p_pFactor[nft]);
1077
1078 for (cpl_size wave = 0; wave < nwave_ft; wave++)
1079 sf0f1[wave] = f0[wave] = f1[wave] = 0.0;
1080
1081 for (cpl_size row_ft = window_start; row_ft < window_end; row_ft++) {
1082 int t0 = GRAVI_BASE_TEL[base][0] + row_ft * ntel;
1083 int t1 = GRAVI_BASE_TEL[base][1] + row_ft * ntel;
1084
1085 double *pf0 = cpl_array_get_data_double(p_flux[t0]);
1086 double *pf1 = cpl_array_get_data_double(p_flux[t1]);
1087
1088 /* Loop over spectrum */
1089 for (cpl_size wave = 0; wave < nwave_ft; wave++) {
1090 if (pf0[wave] < 0.0 || pf1[wave] < 0.0)
1091 continue;
1092
1093 sf0f1[wave] += sqrt (pf0[wave] * pf1[wave]);
1094 f0[wave] += pf0[wave];
1095 f1[wave] += pf1[wave];
1096 }
1097 }
1098
1099 for (cpl_size wave = 0; wave < nwave_ft; wave++) {
1100 if (f0[wave] == 0 || f1[wave] == 0)
1101 continue;
1102
1103 /* Compute the pFactor */
1104 pFactor[wave] = sf0f1[wave] * sf0f1[wave] / (f0[wave] * f1[wave]);
1105 }
1106 }
1107 }
1108
1109 cpl_free(sf0f1);
1110 cpl_free(f0);
1111 cpl_free(f1);
1112
1114 return CPL_ERROR_NONE;
1115}
1116
1117/* -------------------------------------------------------------------------- */
1128/* -------------------------------------------------------------------------- */
1129
1130cpl_error_code gravi_vis_create_f1f2_sc (cpl_table * vis_SC, cpl_table * flux_SC)
1131{
1133 cpl_ensure_code (vis_SC, CPL_ERROR_NULL_INPUT);
1134 cpl_ensure_code (flux_SC, CPL_ERROR_NULL_INPUT);
1135
1136 cpl_size nbase = 6, ntel = 4;
1137 cpl_size nrow_sc = cpl_table_get_nrow (flux_SC) / ntel;
1138 cpl_size nwave_sc = cpl_table_get_column_depth (flux_SC, "FLUX");
1139
1140 /* Get pointer to data */
1141 cpl_array ** flux_sc = cpl_table_get_data_array (flux_SC, "FLUX");
1142
1143 CPLCHECK_MSG ("Cannot get data");
1144
1145 /* New column */
1146 gravi_table_new_column_array (vis_SC, "F1F2", "e^2", CPL_TYPE_DOUBLE, nwave_sc);
1147 cpl_array ** f1f2_sc = cpl_table_get_data_array (vis_SC, "F1F2");
1148
1149 for (cpl_size base = 0; base < nbase; base++) {
1150 for (cpl_size row = 0; row < nrow_sc; row ++) {
1151
1152 /* Compute the photometric normalisation of SC
1153 * This is simply FLUX1 * FLUX2 */
1154 f1f2_sc[row*nbase+base] = cpl_array_cast (flux_sc[row*ntel+GRAVI_BASE_TEL[base][0]], CPL_TYPE_DOUBLE);
1155 cpl_array_multiply (f1f2_sc[row*nbase+base], flux_sc[row*ntel+GRAVI_BASE_TEL[base][1]]);
1156 }
1157 }
1158
1160 return CPL_ERROR_NONE;
1161}
1162
1163/* -------------------------------------------------------------------------- */
1176/* -------------------------------------------------------------------------- */
1177
1178cpl_error_code gravi_vis_create_f1f2_ft (cpl_table * vis_FT, cpl_table * flux_FT)
1179{
1181 cpl_ensure_code (vis_FT, CPL_ERROR_NULL_INPUT);
1182 cpl_ensure_code (flux_FT, CPL_ERROR_NULL_INPUT);
1183
1184 cpl_size ntel = 4, nbase = 6;
1185 cpl_size nrow_ft = cpl_table_get_nrow (flux_FT) / ntel;
1186 cpl_size nwave_ft = cpl_table_get_column_depth (flux_FT, "FLUX");
1187
1188 /* Get pointer to data */
1189 double * total_flux_ft = cpl_table_get_data_double (flux_FT, "TOTALFLUX");
1190 cpl_array ** flux_ft = cpl_table_get_data_array (flux_FT, "FLUX");
1191
1192 CPLCHECK_MSG ("Cannot get data");
1193
1194 /* Compute the four mean_spectra */
1195 cpl_array ** mean_spectra = cpl_malloc (4 * sizeof (cpl_array*));
1196
1197 for (cpl_size tel = 0; tel < ntel; tel ++) {
1198 mean_spectra[tel] = cpl_array_duplicate (flux_ft[tel]);
1199 for (cpl_size n = 1; n < nrow_ft; n ++) cpl_array_add (mean_spectra[tel], flux_ft[n*ntel+tel]);
1200 cpl_array_divide_scalar (mean_spectra[tel], cpl_array_get_mean (mean_spectra[tel]) * nwave_ft);
1201 CPLCHECK_MSG ("Cannot compute mean spectra");
1202 }
1203
1204 /* Compute the photometric normalisation for the FT:
1205 * F1F2 = Fsmooth1(t) * Fsmooth2(t) * mean_spectra1(lbd) * mean_spectra2(lbd) */
1206 gravi_table_new_column_array (vis_FT, "F1F2", "e^2", CPL_TYPE_DOUBLE, nwave_ft);
1207 cpl_array ** f1f2_ft = cpl_table_get_data_array (vis_FT, "F1F2");
1208
1209 CPLCHECK_MSG ("Cannot create columns");
1210
1211 /* Loop on base */
1212 for (cpl_size base = 0; base < nbase; base++) {
1213 int t0 = GRAVI_BASE_TEL[base][0];
1214 int t1 = GRAVI_BASE_TEL[base][1];
1215 for (cpl_size n = 0; n < nrow_ft; n ++) {
1216 f1f2_ft[n*nbase+base] = cpl_array_duplicate (mean_spectra[t0]);
1217 cpl_array_multiply (f1f2_ft[n*nbase+base], mean_spectra[t1]);
1218 cpl_array_multiply_scalar (f1f2_ft[n*nbase+base], total_flux_ft[n*ntel+t0] * total_flux_ft[n*ntel+t1]);
1219 // f1f2_ft[n*nbase+base] = cpl_array_duplicate (flux_ft[n*ntel+t0]);
1220 // cpl_array_multiply (f1f2_ft[n*nbase+base], flux_ft[n*ntel+t1]);
1221 }
1222 }
1223
1224 FREELOOP (cpl_array_delete, mean_spectra, 4);
1225
1227 return CPL_ERROR_NONE;
1228}
1229
1230/* -------------------------------------------------------------------------- */
1240/* -------------------------------------------------------------------------- */
1241
1242cpl_error_code gravi_vis_create_phaseref_ft (cpl_table * vis_FT)
1243{
1245 cpl_ensure_code (vis_FT, CPL_ERROR_NULL_INPUT);
1246
1247 /* Get the FT data */
1248 cpl_size nbase = 6;
1249 cpl_size nrow_ft = cpl_table_get_nrow (vis_FT) / nbase;
1250 cpl_size nwave_ft = cpl_table_get_column_depth (vis_FT, "VISDATA");
1251 cpl_array ** visData_ft = cpl_table_get_data_array (vis_FT, "VISDATA");
1252
1253 CPLCHECK_MSG ("Cannot get data");
1254
1255 /* Create the column */
1256 gravi_table_new_column_array (vis_FT, "SELF_REF", "rad", CPL_TYPE_DOUBLE, nwave_ft);
1257 cpl_array ** phaseref_ft = cpl_table_get_data_array (vis_FT, "SELF_REF");
1258
1259 CPLCHECK_MSG ("Cannot create columns");
1260
1261 /* Compute the PHASE_REF for the FT as a weighted
1262 * mean of -3..+3 frames */
1263 for (cpl_size base = 0; base < nbase; base ++) {
1264
1265 /* Loop on running frames */
1266 for (cpl_size n = 3; n < nrow_ft - 3; n ++) {
1267 phaseref_ft[n*nbase+base] = cpl_array_cast (visData_ft[(n-1)*nbase+base], CPL_TYPE_DOUBLE_COMPLEX);
1268 cpl_array_add (phaseref_ft[n*nbase+base], visData_ft[(n+1)*nbase+base]);
1269 cpl_array_multiply_scalar (phaseref_ft[n*nbase+base], 2.0);
1270 cpl_array_add (phaseref_ft[n*nbase+base], visData_ft[(n-2)*nbase+base]);
1271 cpl_array_add (phaseref_ft[n*nbase+base], visData_ft[(n+2)*nbase+base]);
1272 cpl_array_multiply_scalar (phaseref_ft[n*nbase+base], 2.0);
1273 cpl_array_add (phaseref_ft[n*nbase+base], visData_ft[(n-3)*nbase+base]);
1274 cpl_array_add (phaseref_ft[n*nbase+base], visData_ft[(n+3)*nbase+base]);
1275 // cpl_array_fill_window_complex (phaseref_ft[n*nbase+base], 0, nwave_ft, cpl_array_get_mean_complex (phaseref_ft[n*nbase+base]));
1276 cpl_array_arg (phaseref_ft[n*nbase+base]);
1277 cpl_array_multiply_scalar (phaseref_ft[n*nbase+base], -1.0);
1278
1279 CPLCHECK_MSG("Cannot compute the PHASE_REF for the FT");
1280 }
1281 phaseref_ft[0*nbase+base] = cpl_array_duplicate (phaseref_ft[3*nbase+base]);
1282 phaseref_ft[1*nbase+base] = cpl_array_duplicate (phaseref_ft[3*nbase+base]);
1283 phaseref_ft[2*nbase+base] = cpl_array_duplicate (phaseref_ft[3*nbase+base]);
1284 phaseref_ft[(nrow_ft-3)*nbase+base] = cpl_array_duplicate (phaseref_ft[(nrow_ft-4)*nbase+base]);
1285 phaseref_ft[(nrow_ft-2)*nbase+base] = cpl_array_duplicate (phaseref_ft[(nrow_ft-4)*nbase+base]);
1286 phaseref_ft[(nrow_ft-1)*nbase+base] = cpl_array_duplicate (phaseref_ft[(nrow_ft-4)*nbase+base]);
1287 }
1288 /* End loop on FT rows and base */
1289
1290 cpl_msg_warning (cpl_func,"Change of PHASE_REF_FT common channel new... to be decided !!");
1291
1293 return CPL_ERROR_NONE;
1294}
1295
1296/* -------------------------------------------------------------------------- */
1307/* -------------------------------------------------------------------------- */
1308
1309cpl_error_code gravi_vis_create_acq_sc (cpl_table * vis_SC,
1310 cpl_table * vis_ACQ)
1311{
1313 cpl_ensure_code (vis_SC, CPL_ERROR_NULL_INPUT);
1314 cpl_ensure_code (vis_ACQ, CPL_ERROR_NULL_INPUT);
1315
1316 cpl_size nbase = 6, ntel = 4;
1317 cpl_size nrow_sc = cpl_table_get_nrow (vis_SC) / nbase;
1318
1319 /* Get SC data */
1320 int * first = cpl_table_get_data_int (vis_SC, "FIRST_ACQ");
1321 int * last = cpl_table_get_data_int (vis_SC, "LAST_ACQ");
1322 CPLCHECK_MSG("Cannot get data");
1323
1324 /* Get ACQ data */
1325 int * pup_n = cpl_table_get_data_int (vis_ACQ, "PUPIL_NSPOT");
1326 double * pup_x = cpl_table_get_data_double (vis_ACQ, "PUPIL_X");
1327 double * pup_y = cpl_table_get_data_double (vis_ACQ, "PUPIL_Y");
1328 double * pup_z = cpl_table_get_data_double (vis_ACQ, "PUPIL_Z");
1329 CPLCHECK_MSG("Cannot get direct pointer to data");
1330
1331 /* New columns */
1332 gravi_table_new_column (vis_SC, "PUPIL_X", NULL, CPL_TYPE_DOUBLE);
1333 double * pup_x_sc = cpl_table_get_data_double (vis_SC, "PUPIL_X");
1334 gravi_table_new_column (vis_SC, "PUPIL_Y", NULL, CPL_TYPE_DOUBLE);
1335 double * pup_y_sc = cpl_table_get_data_double (vis_SC, "PUPIL_Y");
1336 gravi_table_new_column (vis_SC, "PUPIL_Z", NULL, CPL_TYPE_DOUBLE);
1337 double * pup_z_sc = cpl_table_get_data_double (vis_SC, "PUPIL_Z");
1338
1339 /* Loop on base and rows */
1340 for (cpl_size base = 0; base < nbase; base++) {
1341 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc ++) {
1342 cpl_size nsc = row_sc * nbase + base;
1343
1344 /* Sum over synch ACQ frames, only valid frames */
1345 cpl_size nframe = 0;
1346 for (cpl_size row = first[nsc] ; row < last[nsc]; row++) {
1347 cpl_size row0 = row * ntel + GRAVI_BASE_TEL[base][0];
1348 cpl_size row1 = row * ntel + GRAVI_BASE_TEL[base][1];
1349
1350 if (pup_n[row0] != 0 && pup_n[row1] !=0 ) {
1351 pup_x_sc[nsc] += pup_x[row0] - pup_x[row1];
1352 pup_y_sc[nsc] += pup_y[row0] - pup_y[row1];
1353 pup_z_sc[nsc] += pup_z[row0] - pup_z[row1];
1354 nframe ++;
1355 }
1356
1357 CPLCHECK_MSG ("Fail to integrate the ACQ frames");
1358 }
1359
1360 /* Normalize the means (if nframe == 0, values are zero) */
1361 if (nframe != 0 ){
1362 pup_x_sc[nsc] /= (double)nframe;
1363 pup_y_sc[nsc] /= (double)nframe;
1364 pup_z_sc[nsc] /= (double)nframe;
1365 }
1366
1367 } /* End loop on SC frames */
1368 }/* End loop on bases */
1369
1371 return CPL_ERROR_NONE;
1372}
1373
1374/* -------------------------------------------------------------------------- */
1385/* -------------------------------------------------------------------------- */
1386
1387cpl_error_code gravi_flux_create_acq_sc (cpl_table * flux_SC,
1388 cpl_table * vis_ACQ)
1389{
1391 cpl_ensure_code (flux_SC, CPL_ERROR_NULL_INPUT);
1392 cpl_ensure_code (vis_ACQ, CPL_ERROR_NULL_INPUT);
1393
1394 cpl_size ntel = 4;
1395 cpl_size nrow_sc = cpl_table_get_nrow (flux_SC) / ntel;
1396
1397 /* Get SC data */
1398 int * first = cpl_table_get_data_int (flux_SC, "FIRST_ACQ");
1399 int * last = cpl_table_get_data_int (flux_SC, "LAST_ACQ");
1400 CPLCHECK_MSG ("Cannot get data");
1401
1402 /* Get ACQ data */
1403 int * pup_n = cpl_table_get_data_int (vis_ACQ, "PUPIL_NSPOT");
1404 double * pup_x = cpl_table_get_data_double (vis_ACQ, "PUPIL_X");
1405 double * pup_y = cpl_table_get_data_double (vis_ACQ, "PUPIL_Y");
1406 double * pup_z = cpl_table_get_data_double (vis_ACQ, "PUPIL_Z");
1407 CPLCHECK_MSG ("Cannot get direct pointer to data");
1408
1409 /* New columns -- filled with zero */
1410 gravi_table_new_column (flux_SC, "PUPIL_X", NULL, CPL_TYPE_DOUBLE);
1411 double * pup_x_sc = cpl_table_get_data_double (flux_SC, "PUPIL_X");
1412 gravi_table_new_column (flux_SC, "PUPIL_Y", NULL, CPL_TYPE_DOUBLE);
1413 double * pup_y_sc = cpl_table_get_data_double (flux_SC, "PUPIL_Y");
1414 gravi_table_new_column (flux_SC, "PUPIL_Z", NULL, CPL_TYPE_DOUBLE);
1415 double * pup_z_sc = cpl_table_get_data_double (flux_SC, "PUPIL_Z");
1416
1417 /* Loop on base and rows */
1418 for (cpl_size tel = 0; tel < ntel; tel++) {
1419 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc ++) {
1420 cpl_size nsc = row_sc * ntel + tel;
1421
1422 /* Sum over synch ACQ frames, only valid frames */
1423 cpl_size nframe = 0;
1424 for (cpl_size row = first[nsc] ; row < last[nsc]; row++) {
1425 cpl_size row0 = row * ntel + tel;
1426
1427 if (pup_n[row0] != 0) {
1428 pup_x_sc[nsc] += pup_x[row0];
1429 pup_y_sc[nsc] += pup_y[row0];
1430 pup_z_sc[nsc] += pup_z[row0];
1431 nframe ++;
1432 }
1433
1434 CPLCHECK_MSG ("Fail to integrate the ACQ frames");
1435 }
1436
1437 /* Normalize the means (if nframe == 0, values are zero) */
1438 if (nframe != 0 ){
1439 pup_x_sc[nsc] /= (double)nframe;
1440 pup_y_sc[nsc] /= (double)nframe;
1441 pup_z_sc[nsc] /= (double)nframe;
1442 }
1443
1444 } /* End loop on SC frames */
1445 }/* End loop on bases */
1446
1448 return CPL_ERROR_NONE;
1449}
1450
1451/* -------------------------------------------------------------------------- */
1462/* -------------------------------------------------------------------------- */
1463
1464cpl_error_code gravi_vis_create_met_sc (cpl_table * vis_SC, cpl_table * vis_MET,
1465 cpl_table * wave_table)
1466{
1468 cpl_ensure_code (vis_SC, CPL_ERROR_NULL_INPUT);
1469 cpl_ensure_code (vis_MET, CPL_ERROR_NULL_INPUT);
1470 cpl_ensure_code (wave_table, CPL_ERROR_NULL_INPUT);
1471
1472 cpl_size nbase = 6, ndiode = 4, ntel = 4;
1473 cpl_size nrow_sc = cpl_table_get_nrow (vis_SC) / nbase;
1474
1475 /* get wavenummer from wave table */
1476
1477 cpl_size nwave_sc = cpl_table_get_column_depth (vis_SC, "VISDATA");
1478 double * twopi_wavenumber_sc = cpl_malloc (nwave_sc * sizeof(double));
1479 for (cpl_size wave = 0; wave < nwave_sc ; wave ++) {
1480 twopi_wavenumber_sc[wave] = CPL_MATH_2PI / cpl_table_get (wave_table, "EFF_WAVE", wave, NULL);
1481 }
1482
1483 /* Get SC data */
1484 int * first_met = cpl_table_get_data_int (vis_SC, "FIRST_MET");
1485 int * last_met = cpl_table_get_data_int (vis_SC, "LAST_MET");
1486
1487 CPLCHECK_MSG("Cannot get data");
1488
1489 /* Get MET data */
1490 double * opd_met_fc = cpl_table_get_data_double (vis_MET, "OPD_FC");
1491 cpl_array ** opd_met_tel = cpl_table_get_data_array (vis_MET, "OPD_TEL");
1492
1493 double * opd_met_fc_corr = cpl_table_get_data_double (vis_MET, "OPD_FC_CORR");
1494 double * opd_met_telfc_mcorr = cpl_table_get_data_double (vis_MET, "OPD_TELFC_MCORR");
1495 cpl_array ** opd_met_telfc_corr = cpl_table_get_data_array (vis_MET, "OPD_TELFC_CORR");
1496
1497 CPLCHECK_MSG("Cannot get direct pointer to data");
1498
1499 /* New columns */
1500 gravi_table_new_column_array (vis_SC, "PHASE_MET_TELFC", "rad", CPL_TYPE_DOUBLE, nwave_sc);
1501 cpl_array ** phase_metdit_telfc = cpl_table_get_data_array (vis_SC, "PHASE_MET_TELFC");
1502
1503 gravi_table_new_column (vis_SC, "OPD_MET_FC", "m", CPL_TYPE_DOUBLE);
1504 double * opd_metdit_fc = cpl_table_get_data_double (vis_SC, "OPD_MET_FC");
1505
1506 gravi_table_new_column_array (vis_SC, "OPD_MET_TEL", "m", CPL_TYPE_DOUBLE, ndiode);
1507 cpl_array ** opd_metdit_tel = cpl_table_get_data_array (vis_SC, "OPD_MET_TEL");
1508
1509 gravi_table_new_column (vis_SC, "OPD_MET_FC_CORR", "m", CPL_TYPE_DOUBLE);
1510 double * opd_metdit_fc_corr = cpl_table_get_data_double (vis_SC, "OPD_MET_FC_CORR");
1511
1512 gravi_table_new_column (vis_SC, "OPD_MET_TELFC_MCORR", "m", CPL_TYPE_DOUBLE);
1513 double * opd_metdit_telfc_mcorr = cpl_table_get_data_double (vis_SC, "OPD_MET_TELFC_MCORR");
1514
1515 gravi_table_new_column_array (vis_SC, "OPD_MET_TELFC_CORR", "m", CPL_TYPE_DOUBLE, ndiode);
1516 cpl_array ** opd_metdit_telfc_corr = cpl_table_get_data_array (vis_SC, "OPD_MET_TELFC_CORR");
1517
1518 CPLCHECK_MSG("Cannot create columns");
1519
1520 /* Loop on base and rows */
1521 cpl_msg_info (cpl_func, "Compute OPD_MET_TEL, OPD_MET_FC_CORR, OPD_MET_TELFC_MCORR...");
1522
1523 for (cpl_size base = 0; base < nbase; base++) {
1524 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc ++) {
1525 cpl_size nsc = row_sc * nbase + base;
1526
1527 /* init cpl arrays -- may be can be faster */
1528 opd_metdit_tel[nsc] = gravi_array_init_double (ndiode, 0.0);
1529 opd_metdit_telfc_corr[nsc] = gravi_array_init_double (ndiode, 0.0);
1530 cpl_array * phasor_metdit_telfc = gravi_array_init_double_complex (nwave_sc, 0.0+I*0.0);
1531 _Complex double * phasor_metdit_telfc_ptr = cpl_array_get_data_double_complex(phasor_metdit_telfc);
1532
1533 /* Sum over synch MET frames */
1534 for (cpl_size row_met = first_met[nsc] ; row_met < last_met[nsc]; row_met++) {
1535 cpl_size nmet0 = row_met * ntel + GRAVI_BASE_TEL[base][0];
1536 cpl_size nmet1 = row_met * ntel + GRAVI_BASE_TEL[base][1];
1537
1538 /* compute phasor of astrometric quantity */
1539 double opd_astro = opd_met_fc_corr[nmet0] - opd_met_fc_corr[nmet1] + opd_met_telfc_mcorr[nmet0] - opd_met_telfc_mcorr[nmet1];
1540
1541 for (cpl_size wave = 0; wave < nwave_sc ; wave ++) {
1542 phasor_metdit_telfc_ptr[wave] = phasor_metdit_telfc_ptr[wave] + cexp(opd_astro * I * twopi_wavenumber_sc[wave]);
1543 };
1544
1545 /* Mean OPD_FC_CORR and OPD_TELFC_MCORR for each BASELINE */
1546 opd_metdit_fc_corr[nsc] += opd_met_fc_corr[nmet0] - opd_met_fc_corr[nmet1];
1547 opd_metdit_telfc_mcorr[nsc] += opd_met_telfc_mcorr[nmet0] - opd_met_telfc_mcorr[nmet1];
1548
1549 /* Mean OPD_TELFC_CORR for each BASELINE and diode */
1550 cpl_array_add (opd_metdit_telfc_corr[nsc], opd_met_telfc_corr[nmet0]);
1551 cpl_array_subtract (opd_metdit_telfc_corr[nsc], opd_met_telfc_corr[nmet1]);
1552
1553 /* Mean OPD_MET at Telescope (each diode) */
1554 cpl_array_add (opd_metdit_tel[nsc], opd_met_tel[nmet0]);
1555 cpl_array_subtract (opd_metdit_tel[nsc], opd_met_tel[nmet1]);
1556
1557 /* Mean OPD_MET_FC at Beam Combiner */
1558 opd_metdit_fc[nsc] += opd_met_fc[nmet0] - opd_met_fc[nmet1];
1559
1560 CPLCHECK_MSG ("Fail to integrate the metrology");
1561 }
1562
1563 /* Normalize the means (if nframe == 0, values are zero) */
1564 cpl_size nframe = last_met[nsc] - first_met[nsc];
1565 if (nframe != 0) {
1566 opd_metdit_fc_corr[nsc] /= nframe;
1567 opd_metdit_telfc_mcorr[nsc] /= nframe;
1568 cpl_array_divide_scalar (opd_metdit_telfc_corr[nsc], (double)nframe);
1569 cpl_array_divide_scalar (opd_metdit_tel[nsc], (double)nframe);
1570 opd_metdit_fc[nsc] /= nframe;
1571
1572 /* get the astro phase by taking the argument of astro phasor */
1573 cpl_array_arg (phasor_metdit_telfc);
1574 phase_metdit_telfc[nsc] = cpl_array_cast(phasor_metdit_telfc, CPL_TYPE_DOUBLE);
1575 }
1576 cpl_array_delete(phasor_metdit_telfc);
1577 CPLCHECK_MSG ("Fail to compute metrology per base from metrology per tel");
1578 } /* End loop on SC frames */
1579 } /* End loop on bases */
1580
1581 /* Compute the information comming from VIS_ACQ
1582 * camera... through the VIS_MET */
1583 if (cpl_table_has_column (vis_MET,"FIELD_FIBER_DX")) {
1584
1585 cpl_msg_info (cpl_func, "Compute the information coming from VIS_ACQ");
1586
1587 double * fdx_met = cpl_table_get_data_double (vis_MET, "FIELD_FIBER_DX");
1588 double * fdy_met = cpl_table_get_data_double (vis_MET, "FIELD_FIBER_DY");
1589
1590 gravi_table_new_column (vis_SC, "FIELD_FIBER_DX", "pix", CPL_TYPE_DOUBLE);
1591 double * fdx_metdit = cpl_table_get_data_double (vis_SC, "FIELD_FIBER_DX");
1592
1593 gravi_table_new_column (vis_SC, "FIELD_FIBER_DY", "pix", CPL_TYPE_DOUBLE);
1594 double * fdy_metdit = cpl_table_get_data_double (vis_SC, "FIELD_FIBER_DY");
1595
1596 /* Loop on base and rows */
1597 for (cpl_size base = 0; base < nbase; base++) {
1598 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc ++) {
1599 cpl_size nsc = row_sc * nbase + base;
1600
1601 /* Sum over synch MET frames */
1602 for (cpl_size row_met = first_met[nsc] ; row_met < last_met[nsc]; row_met++) {
1603 cpl_size nmet0 = row_met * ntel + GRAVI_BASE_TEL[base][0];
1604 cpl_size nmet1 = row_met * ntel + GRAVI_BASE_TEL[base][1];
1605
1606 /* Mean FIELD_FIBER */
1607 fdx_metdit[nsc] += fdx_met[nmet0] - fdx_met[nmet1];
1608 fdy_metdit[nsc] += fdy_met[nmet0] - fdy_met[nmet1];
1609 }
1610 CPLCHECK_MSG ("Fail to compute metrology per base from metrology per tel");
1611
1612 /* Normalize the means (if nframe == 0, values are zero) */
1613 cpl_size nframe = last_met[nsc] - first_met[nsc];
1614 if (nframe != 0 ){
1615 fdx_metdit[nsc] /= nframe;
1616 fdy_metdit[nsc] /= nframe;
1617 }
1618 } /* End loop on SC frames */
1619 } /* End loop on bases */
1620 }
1621
1622 /* Compute mean OPD_MET_PUPIL, OPD_MET_PUPIL_STDDEV and OPD_MET_TTPUP
1623 only if OPD_PUPIL exists (ACQ option)*/
1624 if (cpl_table_has_column (vis_MET,"OPD_PUPIL") && cpl_table_has_column (vis_MET,"OPD_TTPUP")) {
1625
1626 cpl_msg_info (cpl_func, "Compute mean OPD_MET_PUPIL, OPD_MET_PUPIL_STDDEV and OPD_MET_TTPUP...");
1627
1628 double * opd_met_pupil = cpl_table_get_data_double (vis_MET, "OPD_PUPIL");
1629 double * opd_met_ttpup = cpl_table_get_data_double (vis_MET, "OPD_TTPUP");
1630
1631 gravi_table_new_column (vis_SC, "OPD_MET_PUPIL", "m", CPL_TYPE_DOUBLE);
1632 double * opd_metdit_pupil = cpl_table_get_data_double (vis_SC, "OPD_MET_PUPIL");
1633
1634 gravi_table_new_column (vis_SC, "OPD_MET_PUPIL_STDDEV", "m", CPL_TYPE_DOUBLE);
1635 double * opd_metdit_pupil_stddev = cpl_table_get_data_double (vis_SC, "OPD_MET_PUPIL_STDDEV");
1636
1637 gravi_table_new_column (vis_SC, "OPD_MET_TTPUP", "m", CPL_TYPE_DOUBLE);
1638 double * opd_metdit_ttpup = cpl_table_get_data_double (vis_SC, "OPD_MET_TTPUP");
1639
1640 CPLCHECK_MSG("Cannot create columns");
1641
1642 /* Loop on base and rows */
1643 for (cpl_size base = 0; base < nbase; base++) {
1644 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc ++) {
1645 cpl_size nsc = row_sc * nbase + base;
1646
1647 /* Sum over synch MET frames */
1648 for (cpl_size row_met = first_met[nsc] ; row_met < last_met[nsc]; row_met++) {
1649 cpl_size nmet0 = row_met * ntel + GRAVI_BASE_TEL[base][0];
1650 cpl_size nmet1 = row_met * ntel + GRAVI_BASE_TEL[base][1];
1651
1652 /* Mean OPD_PUPIL */
1653 opd_metdit_pupil[nsc] += opd_met_pupil[nmet0] - opd_met_pupil[nmet1];
1654
1655 /* Mean OPD_TTPUP */
1656 opd_metdit_ttpup[nsc] += opd_met_ttpup[nmet0] - opd_met_ttpup[nmet1];
1657
1658 CPLCHECK_MSG ("Fail to integrate the metrology");
1659 }
1660
1661 /* Normalize the means (if nframe == 0, values are zero) */
1662 cpl_size nframe = last_met[nsc] - first_met[nsc];
1663 if (nframe != 0) {
1664 opd_metdit_pupil[nsc] /= nframe;
1665 opd_metdit_ttpup[nsc] /= nframe;
1666 }
1667
1668 /* Sum over synch MET frames again, to compute STDDEV */
1669 for (cpl_size row_met = first_met[nsc] ; row_met < last_met[nsc]; row_met++) {
1670 cpl_size nmet0 = row_met * ntel + GRAVI_BASE_TEL[base][0];
1671 cpl_size nmet1 = row_met * ntel + GRAVI_BASE_TEL[base][1];
1672
1673 /* Mean OPD_PUPIL_STDDEV (still sum variance here, sqrt below) */
1674 double tmp = opd_met_pupil[nmet0] - opd_met_pupil[nmet1] - opd_metdit_pupil[nsc];
1675 opd_metdit_pupil_stddev[nsc] += tmp * tmp;
1676
1677 CPLCHECK_MSG ("Fail to integrate the metrology");
1678 }
1679
1680 /* Normalize the STDDEV (if nframe <= 1, values are zero) */
1681 if (nframe > 1) {
1682 opd_metdit_pupil_stddev[nsc] = sqrt(opd_metdit_pupil_stddev[nsc] / (nframe-1));
1683 }
1684
1685 CPLCHECK_MSG ("Fail to compute metrology per base from metrology per tel");
1686 } /* End loop on SC frames */
1687 } /* End loop on bases */
1688 }
1689
1690 FREE (cpl_free, twopi_wavenumber_sc);
1692 return CPL_ERROR_NONE;
1693}
1694
1695
1696/* -------------------------------------------------------------------------- */
1715/* -------------------------------------------------------------------------- */
1716
1717cpl_error_code gravi_vis_create_met_ft (cpl_table * vis_FT, cpl_table * vis_MET)
1718{
1720 cpl_ensure_code (vis_FT, CPL_ERROR_NULL_INPUT);
1721 cpl_ensure_code (vis_MET, CPL_ERROR_NULL_INPUT);
1722
1723 cpl_size nbase = 6, ntel = 4;
1724 cpl_size nrow_ft = cpl_table_get_nrow (vis_FT) / nbase;
1725 cpl_size nrow_met = cpl_table_get_nrow (vis_MET) / ntel;
1726
1727 CPLCHECK_MSG("Cannot get data");
1728
1729 /* Get the FT period in table [us] */
1730 double periode_ft = cpl_table_get (vis_FT, "TIME", nbase, NULL) -
1731 cpl_table_get (vis_FT, "TIME", 0, NULL);
1732 cpl_msg_info (cpl_func, "PERIOD FT = %g [us]", periode_ft);
1733
1734 /* Get MET data */
1735 double * phase_met_fc = cpl_table_get_data_double (vis_MET, "PHASE_FC_DRS");
1736
1737 CPLCHECK_MSG("Cannot get direct pointer to data");
1738
1739 /* New columns */
1740 gravi_table_new_column (vis_FT, "PHASE_MET_FC", "rad", CPL_TYPE_DOUBLE);
1741 double * phase_metdit_fc = cpl_table_get_data_double (vis_FT, "PHASE_MET_FC");
1742
1743 CPLCHECK_MSG("Cannot create columns");
1744
1745 /* Loop on base and rows */
1746 for (cpl_size base = 0; base < nbase; base++) {
1747 int tel0 = GRAVI_BASE_TEL[base][0];
1748 int tel1 = GRAVI_BASE_TEL[base][1];
1749
1750 for (cpl_size last_met = 0, first_met = 0, row_ft = 0; row_ft < nrow_ft; row_ft ++) {
1751 cpl_size nft = row_ft * nbase + base;
1752 double time_ft = cpl_table_get (vis_FT, "TIME", row_ft*nbase+base, NULL);
1753
1754 /*
1755 * FIXME: to respect previous implementation in gravi_wave
1756 * while ((time_met < (time_ft + exptime_ft))){
1757 * we use this shiffted window time_ft -> time_ft + periode_ft
1758 */
1759
1760 /* First sample of MET (assume same DIT for all beam in vis_MET) */
1761 first_met = CPL_MAX (CPL_MIN (last_met - 5, nrow_met - 1), 0);
1762 while ((cpl_table_get (vis_MET, "TIME", first_met*ntel, NULL) <= (time_ft + 0.0))) {
1763 first_met++;
1764 if (first_met == nrow_met) break;
1765 }
1766 CPLCHECK_MSG ("Cannot get first");
1767
1768 /* Last sample of MET (assume same DIT for all beam in vis_MET) */
1769 last_met = CPL_MAX (CPL_MIN (first_met - 1, nrow_met - 1), 0);
1770 while ((cpl_table_get (vis_MET, "TIME", last_met*ntel, NULL) < (time_ft + periode_ft))) {
1771 last_met++;
1772 if (last_met == nrow_met) break;
1773 }
1774 CPLCHECK_MSG ("Cannot get last");
1775
1776 /* For first few FT samples, we use the first MET if none found */
1777 if (row_ft < 5 && last_met == 0) last_met = 1;
1778
1779 /* For last few FT samples, we use the last MET if none found
1780 * also avoid going outside the table */
1781 if (row_ft > nrow_ft-5 && first_met == nrow_met) first_met = nrow_met - 1;
1782 if (row_ft > nrow_ft-5 && last_met == nrow_met) last_met = nrow_met;
1783
1784 /* Check if enough data */
1785 if ( last_met == 0 || last_met > nrow_met ) {
1786 return cpl_error_set_message (cpl_func,CPL_ERROR_ILLEGAL_INPUT,
1787 "Not enough MET data to synchronise "
1788 "with FT DIT %lli over %lli", row_ft+1, nrow_ft);
1789 }
1790
1791 if ( last_met - first_met > 0 ) {
1792 /* If at least one MET samples inside, we average
1793 * FIXME: maybe we better always interpolate ?? */
1794
1795 for (cpl_size rin_met = first_met; rin_met < last_met; rin_met ++)
1796 phase_metdit_fc[nft] += phase_met_fc[rin_met*ntel+tel0] - phase_met_fc[rin_met*ntel+tel1];
1797
1798 phase_metdit_fc[nft] /= (last_met - first_met);
1799
1800 } else {
1801 /* If no MET inside sample, we interpolate linear */
1802 cpl_size rowa_met = first_met-1;
1803 cpl_size rowb_met = last_met;
1804
1805 double phia_met = phase_met_fc[rowa_met*ntel+tel0] - phase_met_fc[rowa_met*ntel+tel1];
1806 double phib_met = phase_met_fc[rowb_met*ntel+tel0] - phase_met_fc[rowb_met*ntel+tel1];
1807 double timea_met = cpl_table_get (vis_MET, "TIME",rowa_met*ntel, NULL);
1808 double timeb_met = cpl_table_get (vis_MET, "TIME",rowb_met*ntel, NULL);
1809
1810 phase_metdit_fc[nft] = phia_met +
1811 (phib_met - phia_met) * (time_ft - timea_met) / (timeb_met - timea_met);
1812 CPLCHECK_MSG ("Cannot interpolate");
1813 }
1814
1815 CPLCHECK_MSG ("Fail to compute metrology per FT base from metrology per tel");
1816 } /* End loop on FT frames */
1817
1818 }/* End loop on bases */
1819
1821 return CPL_ERROR_NONE;
1822}
1823
1824
1825/* -------------------------------------------------------------------------- */
1841/* -------------------------------------------------------------------------- */
1842
1843cpl_error_code gravi_vis_create_opdsc_ft (cpl_table * vis_FT,
1844 cpl_table * vis_SC,
1845 double dit_sc)
1846{
1848 cpl_ensure_code (vis_FT, CPL_ERROR_NULL_INPUT);
1849 cpl_ensure_code (vis_SC, CPL_ERROR_NULL_INPUT);
1850
1851 cpl_size nbase = 6;
1852 cpl_size nrow_ft = cpl_table_get_nrow (vis_FT) / nbase;
1853 cpl_size nrow_sc = cpl_table_get_nrow (vis_SC) / nbase;
1854
1855 CPLCHECK_MSG("Cannot get data");
1856
1857 /* Get OPD data */
1858 double * phase_sc = cpl_table_get_data_double (vis_SC, "OPD");
1859
1860 CPLCHECK_MSG("Cannot get direct pointer to data");
1861
1862 /* New columns */
1863 gravi_table_new_column (vis_FT, "OPD_SC", "rad", CPL_TYPE_DOUBLE);
1864 double * phase_scdit = cpl_table_get_data_double (vis_FT, "OPD_SC");
1865
1866 CPLCHECK_MSG("Cannot create columns");
1867
1868 /* Loop on base and rows */
1869 for (cpl_size base = 0; base < nbase; base++) {
1870 cpl_size row_ft = 0;
1871
1872 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc ++) {
1873 cpl_size nsc = row_sc * nbase + base;
1874 double time_sc = cpl_table_get (vis_SC, "TIME", nsc, NULL);
1875
1876 /* First sample of FT in the SC DIT */
1877 while ((cpl_table_get (vis_FT, "TIME", row_ft*nbase+base, NULL) < (time_sc - dit_sc/2))) {
1878 row_ft++;
1879 if (row_ft >= nrow_ft) break;
1880 }
1881
1882 /* While inside the SC DIT -- we fill the OPD_FT column */
1883 while ((cpl_table_get (vis_FT, "TIME", row_ft*nbase+base, NULL) < (time_sc + dit_sc/2))) {
1884
1885 phase_scdit[row_ft*nbase+base] = phase_sc[nsc];
1886
1887 row_ft++;
1888 if (row_ft >= nrow_ft) break;
1889 }
1890
1891 if (row_ft >= nrow_ft) {
1892 return cpl_error_set_message (cpl_func,CPL_ERROR_ILLEGAL_INPUT,
1893 "Not enough FT data to synchronise "
1894 "with SC DIT %lli over %lli", row_sc+1, nrow_sc);
1895 }
1896
1897 } /* End loop on SC frames */
1898
1899 }/* End loop on bases */
1900
1902 return CPL_ERROR_NONE;
1903}
1904
1905
1906/* -------------------------------------------------------------------------- */
1917/* -------------------------------------------------------------------------- */
1918
1919cpl_error_code gravi_flux_create_met_sc (cpl_table * flux_SC, cpl_table * vis_MET)
1920{
1922 cpl_ensure_code (flux_SC, CPL_ERROR_NULL_INPUT);
1923 cpl_ensure_code (vis_MET, CPL_ERROR_NULL_INPUT);
1924
1925 cpl_size ntel = 4, ndiode = 4;
1926 cpl_size nrow_sc = cpl_table_get_nrow (flux_SC) / ntel;
1927
1928 /* Get SC data */
1929 int * first_met = cpl_table_get_data_int (flux_SC, "FIRST_MET");
1930 int * last_met = cpl_table_get_data_int (flux_SC, "LAST_MET");
1931
1932 CPLCHECK_MSG("Cannot get data");
1933
1934 /* Get MET data */
1935 double * opd_met_fc = cpl_table_get_data_double (vis_MET, "OPD_FC");
1936 cpl_array ** opd_met_tel = cpl_table_get_data_array (vis_MET, "OPD_TEL");
1937
1938 double * opd_met_fc_corr = cpl_table_get_data_double (vis_MET, "OPD_FC_CORR");
1939 double * opd_met_telfc_mcorr = cpl_table_get_data_double (vis_MET, "OPD_TELFC_MCORR");
1940 cpl_array ** opd_met_telfc_corr = cpl_table_get_data_array (vis_MET, "OPD_TELFC_CORR");
1941 double * phase_met_fc = cpl_table_get_data_double (vis_MET, "PHASE_FC_DRS");
1942 double * phase_met_fcft = cpl_table_get_data_double (vis_MET, "PHASE_FCFT_DRS");
1943 double * phase_met_fcsc = cpl_table_get_data_double (vis_MET, "PHASE_FCSC_DRS");
1944
1945
1946 CPLCHECK_MSG("Cannot get direct pointer to data");
1947
1948 /* New columns */
1949 gravi_table_new_column (flux_SC, "PHASE_MET_FC", "rad", CPL_TYPE_DOUBLE);
1950 double * phase_metdit_fc = cpl_table_get_data_double (flux_SC, "PHASE_MET_FC");
1951
1952 gravi_table_new_column (flux_SC, "PHASE_MET_FCFT", "rad", CPL_TYPE_DOUBLE);
1953 double * phase_metdit_fcft = cpl_table_get_data_double (flux_SC, "PHASE_MET_FCFT");
1954
1955 gravi_table_new_column (flux_SC, "PHASE_MET_FCSC", "rad", CPL_TYPE_DOUBLE);
1956 double * phase_metdit_fcsc = cpl_table_get_data_double (flux_SC, "PHASE_MET_FCSC");
1957
1958 gravi_table_new_column (flux_SC, "OPD_MET_FC", "m", CPL_TYPE_DOUBLE);
1959 double * opd_metdit_fc = cpl_table_get_data_double (flux_SC, "OPD_MET_FC");
1960
1961 gravi_table_new_column_array (flux_SC, "OPD_MET_TEL", "m", CPL_TYPE_DOUBLE, ndiode);
1962 cpl_array ** opd_metdit_tel = cpl_table_get_data_array (flux_SC, "OPD_MET_TEL");
1963
1964 gravi_table_new_column (flux_SC, "OPD_MET_FC_CORR", "m", CPL_TYPE_DOUBLE);
1965 double * opd_metdit_fc_corr = cpl_table_get_data_double (flux_SC, "OPD_MET_FC_CORR");
1966
1967 gravi_table_new_column (flux_SC, "OPD_MET_TELFC_MCORR", "m", CPL_TYPE_DOUBLE);
1968 double * opd_metdit_telfc_mcorr = cpl_table_get_data_double (flux_SC, "OPD_MET_TELFC_MCORR");
1969
1970 gravi_table_new_column_array (flux_SC, "OPD_MET_TELFC_CORR", "m", CPL_TYPE_DOUBLE, ndiode);
1971 cpl_array ** opd_metdit_telfc_corr = cpl_table_get_data_array (flux_SC, "OPD_MET_TELFC_CORR");
1972
1973 CPLCHECK_MSG("Cannot create columns");
1974
1975 /* Loop on base and rows */
1976 for (cpl_size tel = 0; tel < ntel; tel++) {
1977 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc ++) {
1978 cpl_size nsc = row_sc * ntel + tel;
1979
1980 opd_metdit_tel[nsc] = gravi_array_init_double (ndiode, 0.0);
1981 opd_metdit_telfc_corr[nsc] = gravi_array_init_double (ndiode, 0.0);
1982
1983 /* Sum over synch MET frames */
1984 for (cpl_size row_met = first_met[nsc] ; row_met < last_met[nsc]; row_met++) {
1985 cpl_size nmet = row_met * ntel + tel;
1986
1987 /* Mean OPD_MET_TEL at Telescope (each diode) */
1988 cpl_array_add (opd_metdit_tel[nsc], opd_met_tel[nmet]);
1989
1990 /* Mean OPD_MET_FC at Beam Combiner */
1991 opd_metdit_fc[nsc] += opd_met_fc[nmet];
1992
1993 /* Mean OPD_FC_CORR and OPD_TELFC_MCORR for each BASELINE */
1994 opd_metdit_fc_corr[nsc] += opd_met_fc_corr[nmet];
1995 opd_metdit_telfc_mcorr[nsc] += opd_met_telfc_mcorr[nmet];
1996
1997 /* Mean OPD_TELFC_CORR for each BASELINE and diode */
1998 cpl_array_add (opd_metdit_telfc_corr[nsc], opd_met_telfc_corr[nmet]);
1999
2000 /* Mean PHASE_MET_FC at Beam Combiner */
2001 phase_metdit_fc[nsc] += phase_met_fc[nmet];
2002
2003 /* Mean PHASE_MET_FCFT at Beam Combiner */
2004 phase_metdit_fcft[nsc] += phase_met_fcft[nmet];
2005
2006 /* Mean PHASE_MET_FCSC at Beam Combiner */
2007 phase_metdit_fcsc[nsc] += phase_met_fcsc[nmet];
2008
2009 CPLCHECK_MSG ("Fail to integrate the metrology");
2010 }
2011
2012 /* Normalize the means (if nframe == 0, values are zero) */
2013 cpl_size nframe = last_met[nsc] - first_met[nsc];
2014 if (nframe != 0 ){
2015 opd_metdit_fc_corr[nsc] /= nframe;
2016 opd_metdit_telfc_mcorr[nsc] /= nframe;
2017 phase_metdit_fc[nsc] /= nframe;
2018 phase_metdit_fcft[nsc] /= nframe;
2019 phase_metdit_fcsc[nsc] /= nframe;
2020 cpl_array_divide_scalar (opd_metdit_telfc_corr[nsc], (double)nframe);
2021
2022 cpl_array_divide_scalar (opd_metdit_tel[nsc], (double)nframe);
2023 opd_metdit_fc[nsc] /= nframe;
2024 }
2025 CPLCHECK_MSG ("Fail to integrate the metrology");
2026
2027 } /* End loop on SC frames */
2028 }/* End loop on bases */
2029
2030
2031 /* Compute the information comming from VIS_ACQ
2032 * camera... through the VIS_MET */
2033 if (cpl_table_has_column (vis_MET,"FIELD_FIBER_DX")) {
2034
2035 double * fdx_met = cpl_table_get_data_double (vis_MET, "FIELD_FIBER_DX");
2036 double * fdy_met = cpl_table_get_data_double (vis_MET, "FIELD_FIBER_DY");
2037
2038 gravi_table_new_column (flux_SC, "FIELD_FIBER_DX", "pix", CPL_TYPE_DOUBLE);
2039 double * fdx_metdit = cpl_table_get_data_double (flux_SC, "FIELD_FIBER_DX");
2040
2041 gravi_table_new_column (flux_SC, "FIELD_FIBER_DY", "pix", CPL_TYPE_DOUBLE);
2042 double * fdy_metdit = cpl_table_get_data_double (flux_SC, "FIELD_FIBER_DY");
2043
2044 /* Loop on tel and rows */
2045 for (cpl_size tel = 0; tel < ntel; tel++) {
2046 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc ++) {
2047 cpl_size nsc = row_sc * ntel + tel;
2048
2049 /* Sum over synch MET frames */
2050 for (cpl_size row_met = first_met[nsc] ; row_met < last_met[nsc]; row_met++) {
2051 cpl_size nmet0 = row_met * ntel + tel;
2052
2053 /* Mean FIELD_FIBER */
2054 fdx_metdit[nsc] += fdx_met[nmet0];
2055 fdy_metdit[nsc] += fdy_met[nmet0];
2056 }
2057 CPLCHECK_MSG ("Fail to compute metrology per base from metrology per tel");
2058
2059 /* Normalize the means (if nframe == 0, values are zero) */
2060 cpl_size nframe = last_met[nsc] - first_met[nsc];
2061 if (nframe != 0 ){
2062 fdx_metdit[nsc] /= nframe;
2063 fdy_metdit[nsc] /= nframe;
2064 }
2065
2066 } /* End loop on SC frames */
2067 }/* End loop on tels */
2068 }
2069
2071 return CPL_ERROR_NONE;
2072}
2073
2074/* -------------------------------------------------------------------------- */
2086/* -------------------------------------------------------------------------- */
2087
2088cpl_error_code gravi_flux_create_fddlpos_sc (cpl_table * flux_SC, cpl_table * fddl_table)
2089{
2091 cpl_ensure_code (flux_SC, CPL_ERROR_NULL_INPUT);
2092 cpl_ensure_code (fddl_table, CPL_ERROR_NULL_INPUT);
2093
2094 cpl_size ntel = 4;
2095 cpl_size nrow_sc = cpl_table_get_nrow (flux_SC) / ntel;
2096
2097 /* Get SC data */
2098 int * first_fddl = cpl_table_get_data_int (flux_SC, "FIRST_FDDL");
2099 int * last_fddl = cpl_table_get_data_int (flux_SC, "LAST_FDDL");
2100
2101 cpl_array ** ftpos = cpl_table_get_data_array (fddl_table, "FT_POS");
2102 cpl_array ** scpos = cpl_table_get_data_array (fddl_table, "SC_POS");
2103 cpl_array ** oplair = cpl_table_get_data_array (fddl_table, "OPL_AIR");
2104
2105 CPLCHECK_MSG("Cannot get data");
2106
2107 /* New columns */
2108 gravi_table_new_column (flux_SC, "FT_POS", "V", CPL_TYPE_DOUBLE);
2109 double * ftpos_flux = cpl_table_get_data_double (flux_SC, "FT_POS");
2110
2111 gravi_table_new_column (flux_SC, "SC_POS", "V", CPL_TYPE_DOUBLE);
2112 double * scpos_flux = cpl_table_get_data_double (flux_SC, "SC_POS");
2113
2114 gravi_table_new_column (flux_SC, "OPL_AIR", "m", CPL_TYPE_DOUBLE);
2115 double * oplair_flux = cpl_table_get_data_double (flux_SC, "OPL_AIR");
2116
2117 CPLCHECK_MSG("Cannot create columns");
2118
2119 /* Loop on tel and frames */
2120 for (cpl_size tel = 0; tel < ntel; tel++) {
2121 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc ++) {
2122 cpl_size nsc = row_sc * ntel + tel;
2123
2124 /* Mean FDDL and OPL_AIR during this frame for this tel */
2125 for (cpl_size row_fddl = first_fddl[nsc] ; row_fddl < last_fddl[nsc]; row_fddl++) {
2126 ftpos_flux[nsc] += cpl_array_get (ftpos[row_fddl], tel, NULL);
2127 scpos_flux[nsc] += cpl_array_get (scpos[row_fddl], tel, NULL);
2128 oplair_flux[nsc] += cpl_array_get (oplair[row_fddl], tel, NULL);
2129 }
2130
2131 /* Normalise the means (if nframe == 0, values are zero) */
2132 cpl_size nframe = last_fddl[nsc] - first_fddl[nsc];
2133 if (nframe != 0 ) {
2134 ftpos_flux[nsc] /= nframe;
2135 scpos_flux[nsc] /= nframe;
2136 oplair_flux[nsc] /= nframe;
2137 }
2138
2139 } /* End loop on SC frames */
2140 }/* End loop on tels */
2141
2143 return CPL_ERROR_NONE;
2144}
2145
2146/* -------------------------------------------------------------------------- */
2157/* -------------------------------------------------------------------------- */
2158
2159cpl_error_code gravi_flux_create_totalflux_sc (cpl_table * flux_SC, cpl_table * flux_FT)
2160{
2162 cpl_ensure_code (flux_SC, CPL_ERROR_NULL_INPUT);
2163 cpl_ensure_code (flux_FT, CPL_ERROR_NULL_INPUT);
2164
2165 cpl_size ntel = 4;
2166 cpl_size nrow_sc = cpl_table_get_nrow (flux_SC) / ntel;
2167 cpl_size nwave_sc = cpl_table_get_column_depth (flux_SC, "FLUX");
2168 cpl_size nwave_ft = cpl_table_get_column_depth (flux_FT, "FLUX");
2169
2170 /* Get SC and FT data */
2171 int * first_ft = cpl_table_get_data_int (flux_SC, "FIRST_FT");
2172 int * last_ft = cpl_table_get_data_int (flux_SC, "LAST_FT");
2173
2174 cpl_array ** flag_sc = cpl_table_get_data_array (flux_SC, "FLAG");
2175 cpl_array ** flux_sc = cpl_table_get_data_array (flux_SC, "FLUX");
2176 cpl_array ** flux_ft = cpl_table_get_data_array (flux_FT, "FLUX");
2177
2178 CPLCHECK_MSG("Cannot get data");
2179
2180 /* New columns */
2181 gravi_table_new_column (flux_SC, "TOTALFLUX_SC", "e", CPL_TYPE_DOUBLE);
2182 double * total_flux_scdit = cpl_table_get_data_double (flux_SC, "TOTALFLUX_SC");
2183
2184 gravi_table_new_column (flux_SC, "TOTALFLUX_FT", "e", CPL_TYPE_DOUBLE);
2185 double * total_flux_ftdit = cpl_table_get_data_double (flux_SC, "TOTALFLUX_FT");
2186
2187 CPLCHECK_MSG("Cannot create columns");
2188
2189 for (cpl_size tel = 0; tel < ntel; tel++) {
2190 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc ++) {
2191 cpl_size nsc = row_sc * ntel + tel;
2192
2193 /* Store the total flux of SC over the SC frame [e] */
2194 total_flux_scdit[nsc] = 0.0;
2195 int nvalid = 0;
2196 for (int wave = 0; wave < nwave_sc; wave++) {
2197 if (!cpl_array_get (flag_sc[nsc], wave, NULL)) {
2198 total_flux_scdit[nsc] += cpl_array_get (flux_sc[nsc], wave, NULL);
2199 nvalid++;
2200 }
2201 }
2202
2203 /* Normalise to replace the rejected values by the mean */
2204 if (nvalid > 0) {
2205 total_flux_scdit[nsc] *= (double)nwave_sc / (double)nvalid;
2206 }
2207
2208 /* Store the total flux of FT over the SC frame [e] */
2209 for (cpl_size row_ft = first_ft[nsc] ; row_ft < last_ft[nsc]; row_ft++) {
2210 total_flux_ftdit[nsc] += cpl_array_get_mean (flux_ft[row_ft * ntel + tel]) * nwave_ft;
2211 }
2212
2213 CPLCHECK_MSG("Issue in the loop to average FT and SC flux per frame");
2214
2215 } /* End loop on SC frames */
2216 }/* End loop on tels */
2217
2219 return CPL_ERROR_NONE;
2220}
2221
2222/* -------------------------------------------------------------------------- */
2238/* -------------------------------------------------------------------------- */
2239
2240cpl_error_code gravi_vis_create_vfactor_sc (cpl_table * vis_SC,
2241 cpl_table * wave_table_sc,
2242 cpl_table * vis_FT,
2243 cpl_table * wave_table_ft)
2244{
2246 cpl_ensure_code (vis_SC, CPL_ERROR_NULL_INPUT);
2247 cpl_ensure_code (vis_FT, CPL_ERROR_NULL_INPUT);
2248 cpl_ensure_code (wave_table_sc, CPL_ERROR_NULL_INPUT);
2249 cpl_ensure_code (wave_table_ft, CPL_ERROR_NULL_INPUT);
2250
2251 /* Get variables */
2252 cpl_size nbase = 6;
2253 cpl_size nrow_sc = cpl_table_get_nrow (vis_SC) / nbase;
2254 cpl_size nwave_sc = cpl_table_get_column_depth (vis_SC, "VISDATA");
2255 cpl_size nwave_ft = cpl_table_get_column_depth (vis_FT, "VISDATA");
2256
2257 /* Get SC and FT data */
2258 int * first_ft = cpl_table_get_data_int (vis_SC, "FIRST_FT");
2259 int * last_ft = cpl_table_get_data_int (vis_SC, "LAST_FT");
2260
2261 cpl_array ** visErr_ft = cpl_table_get_data_array (vis_FT, "VISERR");
2262 cpl_array ** visData_ft = cpl_table_get_data_array (vis_FT, "VISDATA");
2263
2264 CPLCHECK_MSG ("Cannot get data");
2265
2266 /* Create wavenumber to be faster */
2267 double meanwave_ft = cpl_table_get_column_mean (wave_table_ft, "EFF_WAVE");
2268 double * wavenumber_sc = cpl_malloc (nwave_sc * sizeof(double));
2269 for (cpl_size wave = 0; wave < nwave_sc ; wave ++) {
2270 wavenumber_sc[wave] = 1. / cpl_table_get (wave_table_sc, "EFF_WAVE", wave, NULL);
2271 }
2272
2273 CPLCHECK_MSG ("Cannot get data");
2274
2275 /* New columns */
2276 gravi_table_new_column_array (vis_SC, "VISDATA_FT", "e", CPL_TYPE_DOUBLE_COMPLEX, nwave_ft);
2277 cpl_array ** visData_ftdit = cpl_table_get_data_array (vis_SC, "VISDATA_FT");
2278
2279 gravi_table_new_column_array (vis_SC, "VISVAR_FT", "e^2", CPL_TYPE_DOUBLE, nwave_ft);
2280 cpl_array ** visVar_ftdit = cpl_table_get_data_array (vis_SC, "VISVAR_FT");
2281
2282 gravi_table_new_column_array (vis_SC, "VISPOWER_FT", "e^2", CPL_TYPE_DOUBLE, nwave_ft);
2283 cpl_array ** visPower_ftdit = cpl_table_get_data_array (vis_SC, "VISPOWER_FT");
2284
2285 gravi_table_new_column_array (vis_SC, "V_FACTOR", NULL, CPL_TYPE_DOUBLE, nwave_sc);
2286 cpl_array ** vFactor = cpl_table_get_data_array (vis_SC, "V_FACTOR");
2287
2288 gravi_table_new_column_array (vis_SC, "V_FACTOR_FT", NULL, CPL_TYPE_DOUBLE, nwave_ft);
2289 cpl_array ** vFactor_ftdit = cpl_table_get_data_array (vis_SC, "V_FACTOR_FT");
2290
2291 gravi_table_new_column (vis_SC, "V_FACTOR_WL", NULL, CPL_TYPE_DOUBLE);
2292 double * vFactor_wl = cpl_table_get_data_double (vis_SC, "V_FACTOR_WL");
2293
2294 CPLCHECK_MSG ("Cannot create columns");
2295
2296 /* Loop on base and row SC */
2297 for (cpl_size base = 0; base < nbase; base++) {
2298 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc++) {
2299 int nsc = row_sc * nbase + base;
2300
2301 /* Init integration of FT quantities during the SC frame */
2302 visData_ftdit[nsc] = gravi_array_init_double_complex (nwave_ft, 0.0 + I * 0.0);
2303 visVar_ftdit[nsc] = gravi_array_init_double (nwave_ft, 0.0);
2304 visPower_ftdit[nsc] = gravi_array_init_double (nwave_ft, 0.0);
2305
2306 double vFactor_incoh = 0.0;
2307 double complex vFactor_coh = 0.0 + I * 0.0;
2308 double vFactor_var = 0.0;
2309
2310 /* Integrate quantities during the SC frame */
2311 cpl_size nframe = last_ft[nsc] - first_ft[nsc];
2312 for (cpl_size row_ft = first_ft[nsc] ; row_ft < last_ft[nsc]; row_ft++) {
2313 cpl_array * tmp_data;
2314
2315 /* Integrate visVar_ftdit = < |visDataErr|^2 > over the current SC frame [e^2] */
2316 tmp_data = visErr_ft[row_ft * nbase + base];
2317 double *visVar_ftdit_ptr = cpl_array_get_data_double(visVar_ftdit[nsc]);
2318 _Complex double *tmp_data_ptr = cpl_array_get_data_double_complex(tmp_data);
2319 for (cpl_size wave = 0; wave < nwave_ft; wave ++){
2320 visVar_ftdit_ptr[wave] = visVar_ftdit_ptr[wave] + gravi_pow2(cabs(tmp_data_ptr[wave]));
2321 }
2322
2323 /* Integrate visData_ftdit[nsc] = < visData > over the current SC frame [e] */
2324 tmp_data = visData_ft[row_ft * nbase + base];
2325 _Complex double *visData_ftdit_ptr = cpl_array_get_data_double_complex(visData_ftdit[nsc]);
2326 tmp_data_ptr = cpl_array_get_data_double_complex(tmp_data);
2327
2328 for (cpl_size wave = 0; wave < nwave_ft; wave ++){
2329 visData_ftdit_ptr[wave] = visData_ftdit_ptr[wave] + tmp_data_ptr[wave];
2330 }
2331
2332 /* Integrate visPower_ftdit = < |visData|^2 > over the current SC frame [e^2] */
2333 double *visPower_ftdit_ptr = cpl_array_get_data_double(visPower_ftdit[nsc]);
2334 for (cpl_size wave = 0; wave < nwave_ft; wave ++){
2335 visPower_ftdit_ptr[wave] = visPower_ftdit_ptr[wave] + gravi_pow2(cabs(tmp_data_ptr[wave]));
2336 }
2337
2338 /* Integrate the same quantities for the white light vFactor
2339 * This is first doing a coherent integration over the wavelengths */
2340 vFactor_incoh += gravi_pow2(cabs (cpl_array_get_mean_complex (visData_ft[row_ft * nbase + base])) * nwave_ft);
2341 vFactor_coh += cpl_array_get_mean_complex (visData_ft[row_ft * 6 + base]) * nwave_ft;
2342 _Complex double *visErr_ft_ptr = cpl_array_get_data_double_complex(visErr_ft[row_ft * nbase + base]);
2343 for (cpl_size wave = 0; wave < nwave_ft; wave ++) {
2344 vFactor_var += gravi_pow2(cabs (visErr_ft_ptr[ wave]));
2345 }
2346
2347 CPLCHECK_MSG("Issue in the loop to build average FT quantities");
2348 } /* End loop on FT frame within this SC frame */
2349
2350 /* Compute the vFactor as the contrast attenuation within the SC DIT
2351 * (|<visData>|^2 - <|visErr|^2>) / (<|visData|^2> - <|visErr|^2>) / nframe */
2352 vFactor_ftdit[nsc] = cpl_array_new (nwave_ft, CPL_TYPE_DOUBLE);
2353 _Complex double *visData_ftdit_ptr = cpl_array_get_data_double_complex(visData_ftdit[nsc]);
2354 if (nframe != 0) {
2355 for (cpl_size wave = 0; wave < nwave_ft; wave ++) {
2356 cpl_array_set (vFactor_ftdit[nsc], wave,
2357 (gravi_pow2(cabs (visData_ftdit_ptr[ wave])) -
2358 cpl_array_get (visVar_ftdit[nsc], wave, NULL)) /
2359 (cpl_array_get (visPower_ftdit[nsc], wave, NULL) -
2360 cpl_array_get (visVar_ftdit[nsc], wave, NULL)) / (double)nframe);
2361 }
2362
2363 /* Compute the white light vFactor, that is fist performing a coherent
2364 * integration of the spectral channels. To lower the bias */
2365 vFactor_wl[nsc] = (cabs(vFactor_coh)*cabs(vFactor_coh) - vFactor_var) /
2366 (vFactor_incoh - vFactor_var) / (double)nframe;
2367 }
2368 /* if nframe == 0 set the vFactor to 0 */
2369 else {
2370 for (cpl_size wave = 0; wave < nwave_ft; wave ++) {
2371 cpl_array_set (vFactor_ftdit[nsc], wave,0);
2372 }
2373 vFactor_wl[nsc] = 0;
2374 }
2375
2376 /* Compute the mean vFactor of the FT, and fit with a function exp(-a2/lbd2) to
2377 * project on the SC wavelength. This has only one free parameter */
2378 vFactor[nsc] = cpl_array_new (nwave_sc, CPL_TYPE_DOUBLE);
2379 double a2 = log (CPL_MAX(CPL_MIN (vFactor_wl[nsc], 1.0),1e-10)) * meanwave_ft*meanwave_ft;
2380 for (cpl_size wave = 0; wave < nwave_sc; wave ++) {
2381 cpl_array_set (vFactor[nsc], wave, exp ( a2 * gravi_pow2(wavenumber_sc[wave])));
2382 }
2383 }
2384 }
2385 /* End loop on SC frames and base */
2386
2387 FREE (cpl_free, wavenumber_sc);
2388
2390 return CPL_ERROR_NONE;
2391}
2392
2393/* -------------------------------------------------------------------------- */
2407/* -------------------------------------------------------------------------- */
2408
2409cpl_error_code gravi_vis_create_lockratio_sc (cpl_table * vis_SC,
2410 cpl_table * vis_FT)
2411{
2413 cpl_ensure_code (vis_SC, CPL_ERROR_NULL_INPUT);
2414 cpl_ensure_code (vis_FT, CPL_ERROR_NULL_INPUT);
2415
2416 /* Get variables */
2417 cpl_size nbase = 6;
2418 cpl_size nrow_sc = cpl_table_get_nrow (vis_SC) / nbase;
2419
2420 /* Get SC and FT data */
2421 int * reject_flag_ft = cpl_table_get_data_int (vis_FT, "REJECTION_FLAG");
2422 int * first_ft = cpl_table_get_data_int (vis_SC, "FIRST_FT");
2423 int * last_ft = cpl_table_get_data_int (vis_SC, "LAST_FT");
2424
2425 CPLCHECK_MSG ("Cannot get data");
2426
2427 /* Create columns */
2428 gravi_table_new_column (vis_SC, "FRINGEDET_RATIO", NULL, CPL_TYPE_DOUBLE);
2429 double * fringedet_ftdit = cpl_table_get_data_double (vis_SC, "FRINGEDET_RATIO");
2430
2431 CPLCHECK_MSG ("Cannot create columns");
2432
2433 /* Loop on base and row SC */
2434 for (cpl_size base = 0; base < nbase; base++) {
2435 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc++) {
2436 int nsc = row_sc * nbase + base;
2437
2438 /* Integrate fraction of the SC frame with detected FT fringes */
2439 for (cpl_size row_ft = first_ft[nsc] ; row_ft < last_ft[nsc]; row_ft++) {
2440 fringedet_ftdit[nsc] += (reject_flag_ft[row_ft * nbase + base] == 0 ? 1 : 0);
2441 }
2442
2443 /* Normalize the mean (if nframe == 0, value is zero) */
2444 cpl_size nframe = last_ft[nsc] - first_ft[nsc];
2445 if (nframe != 0) fringedet_ftdit[nsc] /= (double)nframe;
2446 }
2447 } /* End loop on base and SC frames */
2448
2450 return CPL_ERROR_NONE;
2451}
2452
2453/* -------------------------------------------------------------------------- */
2470/* -------------------------------------------------------------------------- */
2471
2472cpl_error_code gravi_vis_create_phaseref_sc (cpl_table * vis_SC,
2473 cpl_table * wavesc_table,
2474 cpl_table * waveft_table,
2475 cpl_propertylist * header,
2476 const cpl_parameterlist * parlist)
2477{
2479 cpl_ensure_code (vis_SC, CPL_ERROR_NULL_INPUT);
2480 cpl_ensure_code (wavesc_table, CPL_ERROR_NULL_INPUT);
2481
2482 cpl_array ** visData_ftdit;
2483 double * gdelay_ftdit;
2484 const char * output_name = NULL, * coeff_name = NULL;
2485 if (waveft_table != NULL) {
2486 cpl_msg_info (cpl_func, "Compute reference phase of SC from the FT data");
2487 visData_ftdit = cpl_table_get_data_array (vis_SC, "VISDATA_FT");
2488 gdelay_ftdit = cpl_table_get_data_double (vis_SC, "GDELAY_FT");
2489 output_name = "PHASE_REF";
2490 coeff_name = "PHASE_REF_COEFF";
2491 } else {
2492 cpl_msg_info (cpl_func, "Compute reference phase of SC from the SC");
2493 visData_ftdit = cpl_table_get_data_array (vis_SC, "VISDATA");
2494 gdelay_ftdit = cpl_table_get_data_double (vis_SC, "GDELAY");
2495 waveft_table = wavesc_table;
2496 output_name = "SELF_REF";
2497 coeff_name = "SELF_REF_COEFF";
2498 }
2499
2500 /* Get general data */
2501 cpl_size nbase = 6;
2502 cpl_size nrow_sc = cpl_table_get_nrow (vis_SC) / nbase;
2503 cpl_size nwave_sc = cpl_table_get_nrow (wavesc_table);
2504 cpl_size nwave_ft = cpl_table_get_nrow (waveft_table);
2505
2506 CPLCHECK_MSG ("Cannot get data");
2507
2508 /* Variable for fit */
2509
2510 /* Create maxdeg as an option for user */
2511 cpl_size mindeg = 0;
2512 cpl_size maxdeg = gravi_param_get_int (parlist, "gravity.signal.phase-ref-sc-maxdeg");
2513
2514 /* FE 2019-08-01: proper imaging phase requires higher order phase reference */
2515 // cpl_size mindeg = 0, maxdeg = 3;
2516 /* SG 2019-08-07: trying order 2 and phase-calibration=FULL */
2517 /* cpl_size mindeg = 0, maxdeg = 2; */
2518
2519 cpl_msg_info (cpl_func, "phaseref with polynomial mindeg=%lli to maxdeg=%lli", mindeg, maxdeg);
2520 cpl_propertylist_update_int (header, "ESO QC PHASEREF_SC MINDEG", mindeg);
2521 cpl_propertylist_set_comment (header, "ESO QC PHASEREF_SC MINDEG", "fit of FT phase");
2522 cpl_propertylist_update_int (header, "ESO QC PHASEREF_SC MAXDEG", maxdeg);
2523 cpl_propertylist_set_comment (header, "ESO QC PHASEREF_SC MAXDEG", "fit of FT phase");
2524
2525
2526 cpl_polynomial * fit = cpl_polynomial_new (1);
2527
2528 /* Create the vectors and matrix only once to be faster */
2529 cpl_matrix * sigma_ft = cpl_matrix_new (1,nwave_ft);
2530 cpl_vector * wave_sc = cpl_vector_new (nwave_sc);
2531 cpl_array * wavenumber_ft = cpl_array_new (nwave_ft, CPL_TYPE_DOUBLE);
2532
2533 double lbd0 = cpl_table_get_column_mean (wavesc_table, "EFF_WAVE");
2534 double delta0 = cpl_table_get_column_max (wavesc_table, "EFF_WAVE") -
2535 cpl_table_get_column_min (wavesc_table, "EFF_WAVE");
2536 for (cpl_size wave = 0; wave < nwave_ft; wave ++) {
2537 double lbd = cpl_table_get (waveft_table, "EFF_WAVE", wave, NULL);
2538 cpl_matrix_set (sigma_ft, 0, wave, (lbd0/lbd - 1.) * lbd0/delta0 );
2539 cpl_array_set (wavenumber_ft, wave, 1./lbd);
2540 }
2541 for (cpl_size wave = 0; wave < nwave_sc; wave ++) {
2542 cpl_vector_set (wave_sc, wave, cpl_table_get (wavesc_table, "EFF_WAVE", wave, NULL));
2543 }
2544
2545 CPLCHECK_MSG ("Cannot create wave arrays");
2546
2547 /* Create columns */
2548 gravi_table_new_column_array (vis_SC, output_name, "rad", CPL_TYPE_DOUBLE, nwave_sc);
2549 cpl_array ** phaseref = cpl_table_get_data_array (vis_SC, output_name);
2550
2551 /* Create columns */
2552 gravi_table_new_column_array (vis_SC, coeff_name, NULL, CPL_TYPE_DOUBLE, maxdeg+1);
2553 cpl_array ** phase_coeff = cpl_table_get_data_array (vis_SC, coeff_name);
2554
2555 CPLCHECK_MSG ("Cannot create column");
2556
2557 /* Loop on base and SC frames */
2558 for (cpl_size base = 0; base < nbase; base++) {
2559 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc ++) {
2560 int nsc = row_sc * nbase + base;
2561
2562 /* phaseref_ftdit is the FT phase arg{visData_ftdit}
2563 * Need to be unwrapped before interpolation. */
2564 cpl_array * phaseref_ftdit = cpl_array_cast (visData_ftdit[nsc], CPL_TYPE_DOUBLE_COMPLEX);
2565
2566 /* Remove mean group-delay and phase-delay to unwrap */
2567 gravi_array_multiply_phasor (phaseref_ftdit, - 2*I*CPL_MATH_PI * gdelay_ftdit[nsc], wavenumber_ft);
2568 double mean_phase = carg (cpl_array_get_mean_complex (phaseref_ftdit));
2569 cpl_array_multiply_scalar_complex (phaseref_ftdit, cexp(- I * mean_phase));
2570
2571 /* Compute argument and add back the delay and the phase [rad] */
2572 cpl_array_arg (phaseref_ftdit);
2573 gravi_array_add_phase (phaseref_ftdit, 2.*CPL_MATH_PI*gdelay_ftdit[nsc], wavenumber_ft);
2574 cpl_array_add_scalar (phaseref_ftdit, mean_phase);
2575
2576 /* Interpolate the FT phase at the SC wavelengths with a polynomial of order 2
2577 * rewrap the phase, and make it phase_ref = - phase_ft */
2578
2579 /* Polynomial fit */
2580 cpl_vector * input = cpl_vector_wrap (nwave_ft, cpl_array_get_data_double (phaseref_ftdit));
2581 cpl_polynomial_fit (fit, sigma_ft, NULL, input, NULL, CPL_FALSE, &mindeg, &maxdeg);
2582 cpl_vector_unwrap (input);
2583 cpl_array_delete (phaseref_ftdit);
2584
2585 /* Save fit coefficients */
2586 phase_coeff[nsc] = cpl_array_new (maxdeg+1, CPL_TYPE_DOUBLE);
2587 for (cpl_size d = 0; d < maxdeg+1; d++)
2588 cpl_array_set (phase_coeff[nsc], d, cpl_polynomial_get_coeff (fit, &d));
2589
2590 /* Evaluate polynomial at the output sampling */
2591 phaseref[nsc] = cpl_array_new (nwave_sc, CPL_TYPE_DOUBLE);
2592 for (cpl_size w = 0; w < nwave_sc; w++) {
2593 double delta = (lbd0/cpl_vector_get(wave_sc, w) - 1.) * lbd0/delta0 ;
2594 cpl_array_set (phaseref[nsc], w, cpl_polynomial_eval_1d (fit, delta, NULL));
2595 }
2596
2597 gravi_array_phase_wrap (phaseref[nsc]);
2598 cpl_array_multiply_scalar (phaseref[nsc], -1.0);
2599
2600 CPLCHECK_MSG ("Cannot compute the PHASE_REF for SC");
2601 } /* End loop on SC frames */
2602 } /* End loop on base */
2603
2604 FREE (cpl_vector_delete, wave_sc);
2605 FREE (cpl_matrix_delete, sigma_ft);
2606 FREE (cpl_array_delete, wavenumber_ft);
2607 FREE (cpl_polynomial_delete, fit);
2608
2610 return CPL_ERROR_NONE;
2611}
2612
2613/* -------------------------------------------------------------------------- */
2626/* -------------------------------------------------------------------------- */
2627
2628cpl_error_code gravi_create_outlier_flag_sc (cpl_table * flux_SC,
2629 cpl_table * vis_SC,
2630 double chi2r_threshold,
2631 double chi2r_sigma)
2632{
2634 cpl_ensure_code (flux_SC, CPL_ERROR_NULL_INPUT);
2635 cpl_ensure_code (vis_SC, CPL_ERROR_NULL_INPUT);
2636
2637 cpl_msg_info (cpl_func, "chi2_threshold = %f", chi2r_threshold);
2638 cpl_msg_info (cpl_func, "chi2_sigma = %f", chi2r_sigma);
2639
2640 cpl_size ntel = 4;
2641 cpl_size nrow = cpl_table_get_nrow (flux_SC) / ntel;
2642 cpl_size nwave = cpl_table_get_column_depth (flux_SC, "FLUX");
2643
2644 cpl_array ** chi2 = cpl_table_get_data_array (flux_SC, "CHI2");
2645
2646 /* Create column */
2647 cpl_array ** flux_outliers = cpl_table_get_data_array (flux_SC, "FLAG");
2648
2649 CPLCHECK_MSG ("Cannot create column");
2650
2651 /* vector to store data */
2652 cpl_vector * vector = cpl_vector_new (nwave);
2653 cpl_vector * med = NULL;
2654
2655 /* Loop on rows */
2656 for (cpl_size row = 0; row < nrow; row ++) {
2657
2658 /* Chi2 data as vector so that we can apply filtering */
2659 for (cpl_size wave = 0; wave < nwave ; wave ++) {
2660 double value = cpl_array_get (chi2[row*ntel+0], wave, NULL);
2661 cpl_vector_set (vector, wave, value);
2662 }
2663
2664 /* Normalise the chi2 by median in spectral direction */
2665 med = gravi_vector_median (vector, 50);
2666 /* remove risk of divide by zero */
2667 cpl_vector_add_scalar(med, cpl_vector_get_mean(med)*1e-9);
2668 cpl_vector_divide (vector, med);
2669 FREE (cpl_vector_delete, med);
2670
2671 /* Threshold on normalised value */
2672 for (cpl_size wave = 0; wave < nwave ; wave ++) {
2673 double value = cpl_vector_get (vector, wave);
2674 if (value > chi2r_threshold) cpl_array_set (flux_outliers[row*ntel+0], wave, 1);
2675 }
2676
2677 /* Compute the distance to median,
2678 in unit of variance */
2679 cpl_vector_subtract_scalar (vector, 1.0);
2680 gravi_vector_abs (vector);
2681 med = gravi_vector_median (vector, 50);
2682 /* remove risk of divide by zero */
2683 cpl_vector_add_scalar(med, cpl_vector_get_mean(med)*1e-9);
2684 cpl_vector_divide (vector, med);
2685 FREE (cpl_vector_delete, med);
2686
2687 /* Flag on distance in unit of local variance */
2688 for (cpl_size wave = 0; wave < nwave ; wave ++) {
2689 double value = cpl_vector_get (vector, wave);
2690 if (value > chi2r_sigma) cpl_array_set (flux_outliers[row*ntel+0], wave, 1);
2691 }
2692 }
2693
2694 /* Free memory */
2695 FREE (cpl_vector_delete, vector);
2696
2697 CPLCHECK_MSG ("Cannot fill outliers");
2698
2699 /* Duplicate the detection of outliers in flux_SC,
2700 based on the one of the first beam */
2701
2702 /* Loop on row */
2703 for (cpl_size row = 0; row < nrow; row ++) {
2704 for (cpl_size tel = 1; tel < ntel; tel++) {
2705 cpl_array_add (flux_outliers[row*ntel+tel], flux_outliers[row*ntel+0]);
2706 }
2707 }
2708
2709 CPLCHECK_MSG ("Cannot duplicate in OI_FLUX");
2710
2711 /* Duplicate the detection of outliers in vis_SC,
2712 based on the one of the first beam */
2713
2714 /* Create column */
2715 cpl_array ** vis_outliers = cpl_table_get_data_array (vis_SC, "FLAG");
2716
2717 /* Loop on row */
2718 int nbase = 6;
2719 for (cpl_size row = 0; row < nrow; row ++) {
2720 for (cpl_size base = 0; base < nbase; base++) {
2721 cpl_array_add (vis_outliers[row*nbase+base], flux_outliers[row*ntel+0]);
2722 }
2723 }
2724
2725 CPLCHECK_MSG ("Cannot duplicate in OI_VIS");
2726
2728 return CPL_ERROR_NONE;
2729}
2730
2731/* -------------------------------------------------------------------------- */
2739/* -------------------------------------------------------------------------- */
2740
2741cpl_error_code gravi_create_outlier_flag_ft (cpl_table * flux_FT,
2742 cpl_table * vis_FT)
2743{
2745 cpl_ensure_code (flux_FT, CPL_ERROR_NULL_INPUT);
2746 cpl_ensure_code (vis_FT, CPL_ERROR_NULL_INPUT);
2747
2748 /* Nothing is checked for FT */
2749
2751 return CPL_ERROR_NONE;
2752}
2753
2754/* -------------------------------------------------------------------------- */
2763/* -------------------------------------------------------------------------- */
2764
2765cpl_error_code gravi_flux_create_fddllin_sc (cpl_table * flux_SC,
2766 cpl_table * disp_table)
2767{
2769 cpl_ensure_code (flux_SC, CPL_ERROR_NULL_INPUT);
2770
2771 cpl_size ntel = 4;
2772 cpl_size nrow = cpl_table_get_nrow (flux_SC) / ntel;
2773
2774 /* Create the columns */
2775 gravi_table_new_column (flux_SC, "FDDL", "m", CPL_TYPE_DOUBLE);
2776 CPLCHECK_MSG ("Cannot create columns");
2777 gravi_table_new_column (flux_SC, "FDDL_FT", "m", CPL_TYPE_DOUBLE);
2778 CPLCHECK_MSG ("Cannot create columns");
2779 gravi_table_new_column (flux_SC, "FDDL_SC", "m", CPL_TYPE_DOUBLE);
2780 CPLCHECK_MSG ("Cannot create columns");
2781
2782 /* If not DISP_DATA, we just create the columns */
2783 if (disp_table == NULL) {
2785 return CPL_ERROR_NONE;
2786 }
2787
2788 /* Get the list of coeficients for FDDL linearity */
2789 cpl_msg_info (cpl_func, "Load the linearity model coeficients");
2790
2791 double ** lin_fddl_sc = gravi_table_get_data_array_double (disp_table, "LIN_FDDL_SC");
2792 double ** lin_fddl_ft = gravi_table_get_data_array_double (disp_table, "LIN_FDDL_FT");
2793 cpl_size disp_order = cpl_table_get_column_depth (disp_table, "LIN_FDDL_SC");
2794 CPLCHECK_MSG ("Cannot get linearity model data");
2795
2796 /* Get data */
2797 double * ftpos = cpl_table_get_data_double (flux_SC, "FT_POS");
2798 double * scpos = cpl_table_get_data_double (flux_SC, "SC_POS");
2799 double * fddl = cpl_table_get_data_double (flux_SC, "FDDL");
2800 double * fddl_ft = cpl_table_get_data_double (flux_SC, "FDDL_FT");
2801 double * fddl_sc = cpl_table_get_data_double (flux_SC, "FDDL_SC");
2802 CPLCHECK_MSG ("Cannot get POS data");
2803
2804 /* Loop on tel and frames */
2805 for (cpl_size tel = 0; tel < ntel; tel++) {
2806 for (cpl_size row = 0; row < nrow; row ++) {
2807 cpl_size nsc = row * ntel + tel;
2808
2809 /* Apply the non-linearity to the FDDL while
2810 * computing the mean of SC and FT: [V] -> [m] */
2811 fddl_ft[nsc] = 0.0;
2812 fddl_sc[nsc] = 0.0;
2813 for (int o = 0; o < disp_order; o++) {
2814 fddl_sc[nsc] += lin_fddl_sc[tel][o] * pow (scpos[nsc], (double)o) * 1.0e-6;
2815 fddl_ft[nsc] += lin_fddl_ft[tel][o] * pow (ftpos[nsc], (double)o) * 1.0e-6;
2816 }
2817 fddl[nsc]=0.5*(fddl_ft[nsc]+fddl_sc[nsc]);
2818 } /* End loop on rows */
2819 } /* End loop on base */
2820
2821 /* Free the temporary allocations */
2822 FREE (cpl_free, lin_fddl_sc);
2823 FREE (cpl_free, lin_fddl_ft);
2824
2826 return CPL_ERROR_NONE;
2827}
2828
2829/* -------------------------------------------------------------------------- */
2843/* -------------------------------------------------------------------------- */
2844
2845cpl_error_code gravi_vis_create_opddisp_sc (cpl_table * vis_SC,
2846 cpl_table * flux_SC,
2847 cpl_table * wave_table,
2848 cpl_table * disp_table,
2849 cpl_propertylist * header,
2850 const cpl_parameterlist * parlist)
2851{
2853 cpl_ensure_code (vis_SC, CPL_ERROR_NULL_INPUT);
2854 cpl_ensure_code (wave_table, CPL_ERROR_NULL_INPUT);
2855 cpl_ensure_code (header, CPL_ERROR_NULL_INPUT);
2856
2857 cpl_size nwave_sc = cpl_table_get_column_depth (vis_SC, "VISDATA");
2858
2859 /* If not DISP_DATA, we cannot create these columns */
2860 if (disp_table == NULL) {
2861 cpl_msg_info (cpl_func,"Cannot create OPD_DISP, not DISP_MODEL table");
2863 return CPL_ERROR_NONE;
2864 }
2865
2866
2867 /* Compute the N_MEAN(lbd) and N_DIFF(lbd) for each beam from their
2868 * polynomial model: n = Sum[ coef_i x ((lbd-lbd_met)/lbd_met)^i ] */
2869 cpl_msg_info (cpl_func, "Load the dispersion model coeficients");
2870
2871 /* Allocate memory */
2872 double ** n_mean = cpl_malloc (4 * sizeof(double*));
2873 double ** n_diff = cpl_malloc (4 * sizeof(double*));
2874 for (int t = 0; t < 4; t++) {
2875 n_mean[t] = cpl_calloc (nwave_sc, sizeof(double));
2876 n_diff[t] = cpl_calloc (nwave_sc, sizeof(double));
2877 }
2878
2879 if ( cpl_table_has_column (disp_table,"N_MEAN") &&
2880 cpl_table_has_column (disp_table,"WAVE0")) {
2881 /* The N_MEAN and N_DIFF are described as n(lbd) / n(lbdmet)
2882 * with a polynomial versus (wave0/wave-1) */
2883 cpl_msg_info (cpl_func, "Dispersion model as N/Nmet [wave0/wave-1]");
2884 cpl_size disp_order = cpl_table_get_column_depth (disp_table, "N_MEAN");
2885 for (int t = 0; t < 4; t++) {
2886 double lbd0 = cpl_table_get (disp_table, "WAVE0", t, NULL);
2887 for (int w = 0; w < nwave_sc; w++ ) {
2888 double lbd = cpl_table_get (wave_table, "EFF_WAVE", w, NULL);
2889 double xfit = lbd0/lbd - 1.0;
2890 for (int o = 0; o < disp_order; o++) {
2891 n_mean[t][w] += gravi_table_get_value (disp_table, "N_MEAN", t, o) * pow (xfit, o);
2892 n_diff[t][w] += gravi_table_get_value (disp_table, "N_DIFF", t, o) * pow (xfit, o);
2893 }
2894 }
2895 }
2896 } else {
2897 FREELOOP (cpl_free, n_mean, 4);
2898 FREELOOP (cpl_free, n_diff, 4);
2899 cpl_msg_error (cpl_func,"The DISP_MODEL is not recognized... contact the DRS team");
2900 return cpl_error_set_message (cpl_func,CPL_ERROR_ILLEGAL_INPUT,
2901 "The DISP_MODEL is not recognized... contact the DRS team");
2902 }
2903
2904 CPLCHECK_MSG ("Cannot compute N_MEAN or N_DIFF");
2905
2906 cpl_size nbase = 6, ntel = 4;
2907 cpl_size nrow_sc = cpl_table_get_nrow (vis_SC) / nbase;
2908
2909 /* Create the columns */
2910 gravi_table_new_column_array (vis_SC, "OPD_DISP", "m", CPL_TYPE_DOUBLE, nwave_sc);
2911 cpl_array ** opd_disp = cpl_table_get_data_array (vis_SC, "OPD_DISP");
2912
2913 gravi_table_new_column (vis_SC, "GDELAY_DISP", "m", CPL_TYPE_DOUBLE);
2914 double * gd_disp = cpl_table_get_data_double (vis_SC, "GDELAY_DISP");
2915
2916 gravi_table_new_column_array (vis_SC, "PHASE_DISP", "rad", CPL_TYPE_DOUBLE, nwave_sc);
2917 cpl_array ** phase_disp = cpl_table_get_data_array (vis_SC, "PHASE_DISP");
2918
2919 CPLCHECK_MSG ("Cannot create columns");
2920
2921 /* Get data */
2922 double * opd_met = cpl_table_get_data_double (flux_SC, "OPD_MET_FC");
2923 double * fddl = cpl_table_get_data_double (flux_SC, "FDDL");
2924
2925 CPLCHECK_MSG ("Cannot get data");
2926
2927 /* Create wavenumber to be faster */
2928 double * wavenumber_sc = cpl_malloc (nwave_sc * sizeof(double));
2929 for (cpl_size wave = 0; wave < nwave_sc ; wave ++) {
2930 wavenumber_sc[wave] = 1. / cpl_table_get (wave_table, "EFF_WAVE", wave, NULL);
2931 }
2932
2933 /* Determine OPD_MET_ZERO_FC, based on the content of the header */
2934 int t;
2935 char name[100];
2936 double * opl_zero_fc = cpl_malloc (4 * sizeof(double));
2937 // double gd_zero_fc;
2938
2939 /* Initialise opl_zero_fc to zero */
2940 for (t = 0; t < ntel; t++) {
2941 opl_zero_fc[t] = 0.0;
2942 }
2943 if ( gravi_param_get_bool (parlist, "gravity.signal.use-met-zero") ) {
2944 cpl_msg_info (cpl_func, "Metrology zero calculation is enabled!");
2945
2946 /* Replace by OCS MET OPL_ZERO_FC, if available */
2947 for (t = 0; t < ntel; t++) {
2948 sprintf (name, "ESO OCS MET OPL_ZERO_FC%i", t+1);
2949 if (cpl_propertylist_has (header, name)) {
2950 opl_zero_fc[t] = cpl_propertylist_get_double (header, name)*1e-3;
2951 sprintf (name, "ESO FDDL MET OFFSET%i", t+1);
2952 opl_zero_fc[t] += cpl_propertylist_get_double (header, name)*1e-3;
2953 cpl_msg_info (cpl_func, "Updating metrology zero with OCS MET OPL_ZERO_FC%i and FDDL MET OFFSET%i: %f [mm]", t+1, t+1, opl_zero_fc[t]);
2954 }
2955 }
2956
2957 /* Replace by PRO MET GD_ZERO_FC, if available */
2958 for (t = 0; t < ntel; t++) {
2959 if ( gravi_pfits_has_gdzero (header, t+1) ) {
2960 opl_zero_fc[t] =
2961 gravi_pfits_get_gdzero (header, t+1)*1e-3
2962 * (wavenumber_sc[nwave_sc/2-1] - wavenumber_sc[nwave_sc/2+1])
2963 / (n_mean[t][nwave_sc/2-1] * wavenumber_sc[nwave_sc/2-1] - n_mean[t][nwave_sc/2+1] * wavenumber_sc[nwave_sc/2+1]);
2964 cpl_msg_info (cpl_func, "Updating metrology zero with QC/PRO MET GD_ZERO_FC%i: %f [mm]", t+1, opl_zero_fc[t]);
2965 }
2966 }
2967 // Replace by PRO MET OPL_ZERO_FC, if available
2968 for (t = 0; t < ntel; t++) {
2969 if ( gravi_pfits_get_oplzero (header, t+1) ){
2970 opl_zero_fc[t] = gravi_pfits_get_oplzero (header, t+1)*1e-3;
2971 cpl_msg_info (cpl_func, "Updating metrology zero with QC/PRO MET OPL_ZERO_FC%i: %f [mm]", t+1, opl_zero_fc[t]);
2972 }
2973 }
2974 } else {
2975 cpl_msg_info (cpl_func, "Metrology zero calculation is disabled!");
2976 }
2977
2978
2979 /* Loop on tel and frames */
2980 for (cpl_size base = 0; base < nbase; base++) {
2981 for (cpl_size row_sc = 0; row_sc < nrow_sc; row_sc ++) {
2982
2983 cpl_size nsc = row_sc * nbase + base;
2984 cpl_size t0 = GRAVI_BASE_TEL[base][0], t0f = row_sc * ntel + t0;
2985 cpl_size t1 = GRAVI_BASE_TEL[base][1], t1f = row_sc * ntel + t1;
2986
2987 /* Compute the group-delay introduced by FDDL in the middle of the band
2988 * This is obviously to a constant */
2989 cpl_size wave = nwave_sc / 2;
2990 double s1 = wavenumber_sc[wave-1];
2991 double s2 = wavenumber_sc[wave+1];
2992 double o1 =
2993 (n_mean[t0][wave-1] * (opd_met[t0f]-opl_zero_fc[t0]) + n_diff[t0][wave-1] * fddl[t0f]) -
2994 (n_mean[t1][wave-1] * (opd_met[t1f]-opl_zero_fc[t1]) + n_diff[t1][wave-1] * fddl[t1f]);
2995 double o2 =
2996 (n_mean[t0][wave+1] * (opd_met[t0f]-opl_zero_fc[t0]) + n_diff[t0][wave+1] * fddl[t0f]) -
2997 (n_mean[t1][wave+1] * (opd_met[t1f]-opl_zero_fc[t1]) + n_diff[t1][wave+1] * fddl[t1f]);
2998
2999 gd_disp[nsc] = (o1*s1 - o2*s2) / (s1-s2);
3000
3001 /* Compute the phase introduced by FDDL. This is also to a dispersive constant
3002 * since the amount of fiber and vaccum is not known */
3003 phase_disp[nsc] = cpl_array_new (nwave_sc, CPL_TYPE_DOUBLE);
3004
3005 for (int w = 0; w < nwave_sc ; w++) {
3006 cpl_array_set (phase_disp[nsc], w,
3007 ((n_mean[t0][w] * (opd_met[t0f]-opl_zero_fc[t0]) + n_diff[t0][w] * fddl[t0f]) -
3008 (n_mean[t1][w] * (opd_met[t1f]-opl_zero_fc[t1]) + n_diff[t1][w] * fddl[t1f]) -
3009 gd_disp[nsc]) * wavenumber_sc[w] * CPL_MATH_2PI);
3010 }
3011
3012 gravi_array_phase_wrap (phase_disp[nsc]);
3013
3014 /* Compute the OPD_DISP for each wavelength :
3015 * T0 = N_DIFF0 * (FDDL_SC0+FDDL_FT0)/2 + N_MEAN0 * (MET_SC0-MET_FT0)
3016 * T1 = N_DIFF1 * (FDDL_SC1+FDDL_FT1)/2 + N_MEAN1 * (MET_SC1-MET_FT1) */
3017 opd_disp[nsc] = cpl_array_new (nwave_sc, CPL_TYPE_DOUBLE);
3018
3019 for (int w = 0; w < nwave_sc ; w++) {
3020 cpl_array_set (opd_disp[nsc], w,
3021 (n_mean[t0][w] * (opd_met[t0f]-opl_zero_fc[t0]) + n_diff[t0][w] * fddl[t0f]) -
3022 (n_mean[t1][w] * (opd_met[t1f]-opl_zero_fc[t1]) + n_diff[t1][w] * fddl[t1f]) );
3023 }
3024
3025 } /* End loop on rows */
3026 } /* End loop on base */
3027
3028 /* Free the temporary allocations */
3029 FREELOOP (cpl_free, n_mean, 4);
3030 FREELOOP (cpl_free, n_diff, 4);
3031 FREE (cpl_free, wavenumber_sc);
3032 FREE (cpl_free, opl_zero_fc);
3033
3035 return CPL_ERROR_NONE;
3036}
3037
3038/*----------------------------------------------------------------------------*/
3050/*----------------------------------------------------------------------------*/
3051
3052cpl_error_code gravi_vis_create_imagingref_sc (cpl_table * vis_SC,
3053 cpl_table * wave_table,
3054 cpl_propertylist * header,
3055 const cpl_parameterlist * parlist)
3056{
3058 cpl_ensure_code (vis_SC, CPL_ERROR_NULL_INPUT);
3059 cpl_ensure_code (wave_table, CPL_ERROR_NULL_INPUT);
3060 cpl_ensure_code (header, CPL_ERROR_NULL_INPUT);
3061
3062 /* Get from OI_VIS the number of wavelength channels and rows */
3063 cpl_size nwave = cpl_table_get_column_depth (vis_SC, "VISDATA");
3064 cpl_size nrow = cpl_table_get_nrow (vis_SC);
3065
3066 /* Get from OI_VIS the data needed for the calculation */
3067 double * ucoord = cpl_table_get_data_double (vis_SC, "UCOORD");
3068 double * vcoord = cpl_table_get_data_double (vis_SC, "VCOORD");
3069 cpl_array ** phase_ref = cpl_table_get_data_array (vis_SC, "PHASE_REF");
3070 double * opd_met_telfc_mcorr = NULL;
3071 double * opd_met_fc_corr = NULL;
3072
3073 CPLCHECK_MSG ("Cannot get input data");
3074
3075 /* If OPD_DISP is not computed, we cannot compute IMAGING_REF neither */
3076 if ( !cpl_table_has_column (vis_SC, "OPD_DISP") ) {
3077 cpl_msg_info (cpl_func,"Cannot compute IMAGING_REF, not column OPD_DISP");
3079 return CPL_ERROR_NONE;
3080 }
3081
3082 cpl_array ** opd_disp = cpl_table_get_data_array (vis_SC, "OPD_DISP");
3083 CPLCHECK_MSG ("Cannot get OPD_DISP data");
3084
3085 cpl_array ** phase_met_telfc = cpl_table_get_data_array (vis_SC, "PHASE_MET_TELFC");
3086 CPLCHECK_MSG ("Cannot get PHASE_MET_TELFC data");
3087
3088 /* Get from header the separation, converted from mas to radian */
3089 double sep_U = gravi_pfits_get_sobj_x (header)*1e-3/3600.0/CPL_MATH_DEG_RAD;
3090 double sep_V = gravi_pfits_get_sobj_y (header)*1e-3/3600.0/CPL_MATH_DEG_RAD;
3091
3092 /* Create new PHASE_REF_IMG column array */
3093 gravi_table_new_column_array (vis_SC, "IMAGING_REF", "rad", CPL_TYPE_DOUBLE, nwave);
3094 cpl_array ** imaging_ref = cpl_table_get_data_array (vis_SC, "IMAGING_REF");
3095 CPLCHECK_MSG ("Cannot create column");
3096
3097 /* Which megtrology should be used for IMAGING_REF calculation? */
3098 const char * imaging_ref_met = gravi_param_get_string (parlist, "gravity.signal.imaging-ref-met");
3099 cpl_msg_info (cpl_func, "imaging-ref-met = %s", imaging_ref_met);
3100 if (!strcmp (imaging_ref_met,"TEL")) {
3101 cpl_msg_info (cpl_func,"Use telescope metrology for IMAGING_REF computation");
3102 opd_met_telfc_mcorr = cpl_table_get_data_double (vis_SC, "OPD_MET_TELFC_MCORR");
3103 opd_met_fc_corr = cpl_table_get_data_double (vis_SC, "OPD_MET_FC_CORR");
3104 } else if (!strcmp (imaging_ref_met,"FC_CORR")) {
3105 cpl_msg_info (cpl_func,"Use corrected fiber coupler metrology for IMAGING_REF computation");
3106 opd_met_fc_corr = cpl_table_get_data_double (vis_SC, "OPD_MET_FC_CORR");
3107 } else if (!strcmp (imaging_ref_met,"FC")) {
3108 cpl_msg_info (cpl_func,"Use fiber coupler metrology for IMAGING_REF computation");
3109 } else {
3110 cpl_msg_error (cpl_func,"Unknown metrology source for IMAGING_REF calculation!");
3111 cpl_ensure_code (imaging_ref_met, CPL_ERROR_ILLEGAL_INPUT);
3112 }
3113
3114 /* Compute the reference phase for each row */
3115 for (cpl_size row = 0; row < nrow; row ++) {
3116
3117 /* New array */
3118 imaging_ref[row] = cpl_array_new (nwave, CPL_TYPE_DOUBLE);
3119
3120 /* If requested, use fiber coupler correction or telescope metrology */
3121 // TODO : FE 20190509 added opd_met_ttpup (commented)?
3122 double opd_met_corr = (opd_met_telfc_mcorr ? opd_met_telfc_mcorr[row] : 0.0)
3123 + (opd_met_fc_corr ? opd_met_fc_corr[row] : 0.0);
3124 // + (opd_met_ttpup ? opd_met_ttpup[row] : 0.0);
3125
3126 /* Compute VISPHI for each wavelength */
3127 for (int w = 0; w < nwave; w++) {
3128
3129 double wavelength = cpl_table_get (wave_table, "EFF_WAVE", w, NULL);
3130
3131 /* IMAGING_REF = PHASE_REF - OPD_DISP * (2PI/EFF_WAVE) +
3132 (UCOORD*SOBJ_X + VCOORD*SOBJ_Y) * (2PI/EFF_WAVE) */
3133 cpl_array_set (imaging_ref[row], w,
3134 cpl_array_get (phase_ref[row], w, NULL)
3135 - cpl_array_get (opd_disp[row], w, NULL) * CPL_MATH_2PI / wavelength
3136 + (ucoord[row] * sep_U + vcoord[row] * sep_V) * CPL_MATH_2PI / wavelength
3137 - opd_met_corr * CPL_MATH_2PI / wavelength);
3138
3139 /* Here, we are using the new computation of phase_met_telfc (overide previous calculation) */
3140 if (!strcmp (imaging_ref_met,"TEL"))
3141 cpl_array_set (imaging_ref[row], w,
3142 cpl_array_get (phase_ref[row], w, NULL)
3143 - cpl_array_get (opd_disp[row], w, NULL) * CPL_MATH_2PI / wavelength
3144 + (ucoord[row] * sep_U + vcoord[row] * sep_V) * CPL_MATH_2PI / wavelength
3145 - cpl_array_get (phase_met_telfc[row], w, NULL) );
3146
3147 CPLCHECK_MSG ("Cannot compute the imaging phase");
3148 }
3149
3150 /* Wrap this phase in [rad] */
3151 gravi_array_phase_wrap (imaging_ref[row]);
3152 }
3153
3155 return CPL_ERROR_NONE;
3156}
3157
3158/*----------------------------------------------------------------------------*/
3172/*----------------------------------------------------------------------------*/
3173
3174cpl_error_code gravi_compute_signals (gravi_data * p2vmred_data,
3175 gravi_data * disp_data,
3176 const cpl_parameterlist * parlist)
3177{
3179 cpl_ensure_code (p2vmred_data, CPL_ERROR_NULL_INPUT);
3180
3181 int nbase = 6, ntel = 4, nclo = 4;
3182
3183 /* Get header data */
3184 cpl_propertylist * p2vmred_header = gravi_data_get_header (p2vmred_data);
3185 int npol_ft = gravi_pfits_get_pola_num (p2vmred_header, GRAVI_FT);
3186 int npol_sc = gravi_pfits_get_pola_num (p2vmred_header, GRAVI_SC);
3187
3188 CPLCHECK_MSG ("Cannot get header");
3189
3190 /* Get window width to use for FT P_FACTOR */
3191 cpl_size window_width = cpl_parameter_get_int(cpl_parameterlist_find_const(
3192 parlist, "gravity.vis.pfactor-window-length"));
3193
3194 /* FIXME: probably doesn't work with npol_sc != npol_ft */
3195 if ( npol_sc != npol_ft ) {
3196 gravi_msg_warning ("FIXME", "Not sure this function works with npol_sc != npol_ft");
3197 }
3198
3199
3200 /* Get the SC DIT */
3201 double dit_sc = gravi_pfits_get_dit_sc (p2vmred_header) * 1e6;
3202 cpl_msg_info (cpl_func,"dit_sc = %g [us]", dit_sc);
3203
3204
3205 /*
3206 * Loop on polarisations
3207 */
3208 for (int pol = 0; pol < CPL_MAX(npol_sc,npol_ft); pol++) {
3209
3210 /* verbose */
3211 cpl_msg_info (cpl_func, "Start polarisation %d over %d",pol+1, CPL_MAX(npol_sc,npol_ft));
3212 cpl_msg_info(cpl_func, "Insname FT : %s, pol %d npol %d",
3213 GRAVI_INSNAME(GRAVI_FT,pol,npol_ft), pol+1, npol_ft);
3214 cpl_msg_info(cpl_func, "Insname SC : %s, pol %d npol %d",
3215 GRAVI_INSNAME(GRAVI_SC,pol,npol_sc), pol+1, npol_sc);
3216
3217 /* Get the table of reduced data from FT */
3218 cpl_table * vis_FT = gravi_data_get_oi_vis (p2vmred_data, GRAVI_FT, pol, npol_ft);
3219 cpl_table * flux_FT = gravi_data_get_oi_flux (p2vmred_data, GRAVI_FT, pol, npol_ft);
3220 CPLCHECK_MSG ("Cannot get the FT tables");
3221
3222 /* Get the table of reduced data from SC */
3223 cpl_table * vis_SC = gravi_data_get_oi_vis (p2vmred_data, GRAVI_SC, pol, npol_sc);
3224 cpl_table * flux_SC = gravi_data_get_oi_flux (p2vmred_data, GRAVI_SC, pol, npol_sc);
3225 cpl_table * t3_SC = gravi_data_get_oi_t3 (p2vmred_data, GRAVI_SC, pol, npol_sc);
3226 CPLCHECK_MSG ("Cannot get the SC tables");
3227
3228 /* Get the metrology and FDDL */
3229 cpl_table * vis_met = gravi_data_get_table (p2vmred_data, GRAVI_OI_VIS_MET_EXT);
3230 cpl_table * fddl_table = gravi_data_get_table (p2vmred_data, GRAVI_FDDL_EXT);
3231 CPLCHECK_MSG ("Cannot get the VIS_MET and FDDL tables");
3232
3233 /* Get the OIFITS tables that are alredy in the data */
3234 cpl_table * oi_wavelengthft = gravi_data_get_oi_wave (p2vmred_data, GRAVI_FT, pol, npol_ft);
3235 cpl_table * oi_wavelengthsc = gravi_data_get_oi_wave (p2vmred_data, GRAVI_SC, pol, npol_sc);
3236 CPLCHECK_MSG ("Cannot get the OI_WAVELENGTH tables");
3237
3238
3239 /*
3240 * (1) Create synchronisation information
3241 */
3242
3243 /* Create the FIRST and LAST for each vis_SC frame */
3244 gravi_signal_create_sync (vis_SC, 6, dit_sc, vis_FT, 6, "FT");
3245 gravi_signal_create_sync (vis_SC, 6, dit_sc, vis_met, 4, "MET");
3246
3247 CPLCHECK_MSG ("Cannot sync vis_SC");
3248
3249 /* Create the FIRST and LAST for each flux_SC frame */
3250 gravi_signal_create_sync (flux_SC, 4, dit_sc, flux_FT, 4, "FT");
3251 gravi_signal_create_sync (flux_SC, 4, dit_sc, vis_met, 4, "MET");
3252 gravi_signal_create_sync (flux_SC, 4, dit_sc, fddl_table, 1, "FDDL");
3253
3254 CPLCHECK_MSG ("Cannot sync flux_SC");
3255
3256 /* Create the FIRST and LAST for each t3_SC frame */
3257 /* FIXME: is it definitely ok to use flux_FT here? */
3258 gravi_signal_create_sync (t3_SC, 4, dit_sc, flux_FT, 4, "FT");
3259 gravi_signal_create_sync (t3_SC, 4, dit_sc, vis_met, 4, "MET");
3260 gravi_signal_create_sync (t3_SC, 4, dit_sc, fddl_table, 1, "FDDL");
3261
3262 CPLCHECK_MSG ("Cannot sync t3_SC");
3263
3264 /*
3265 * (2) Create the signals for FLUX_FT
3266 */
3267
3268 cpl_array ** flux_ft = cpl_table_get_data_array (flux_FT, "FLUX");
3269 cpl_size nwave_ft = cpl_table_get_column_depth (vis_FT, "VISDATA");
3270 cpl_size nrow_ft = cpl_table_get_nrow (vis_FT) / nbase;
3271
3272 gravi_table_new_column (flux_FT, "TOTALFLUX", "e", CPL_TYPE_DOUBLE);
3273 double * total_flux_ft = cpl_table_get_data_double (flux_FT, "TOTALFLUX");
3274
3275 CPLCHECK_MSG ("Cannot create columns");
3276
3277 /* Total flux in [e] */
3278 for (cpl_size row = 0; row < nrow_ft * ntel; row ++) {
3279 total_flux_ft[row] = cpl_array_get_mean (flux_ft[row]) * nwave_ft;
3280 }
3281
3282 /* Duplicate the TOTALFLUX to have an unsmoothed copy */
3283 cpl_table_duplicate_column (flux_FT, "TOTALFLUX_UNSMOOTHED", flux_FT, "TOTALFLUX");
3284
3285 /* Smooth TOTALFLUX of the FT over few samples. Maybe make sure
3286 * this is a constant frequency, not a constant nb of samples */
3287 gravi_table_smooth_column (flux_FT, "TOTALFLUX", "TOTALFLUX", 10, ntel);
3288
3289 CPLCHECK_MSG("Cannot compute TOTALFLUX for FT");
3290
3291 /*
3292 * (3) Create the signals for VIS_FT
3293 */
3294 gravi_vis_create_pfactor_ft (vis_FT, flux_FT, window_width);
3295 gravi_vis_create_f1f2_ft (vis_FT, flux_FT);
3297
3298 CPLCHECK_MSG ("Cannot create signals for VIS_FT");
3299
3300 /*
3301 * (4) Create the signal for FLUX_SC
3302 */
3303 gravi_flux_create_met_sc (flux_SC, vis_met);
3304 gravi_flux_create_fddlpos_sc (flux_SC, fddl_table);
3305 gravi_flux_create_totalflux_sc (flux_SC, flux_FT);
3306
3307 CPLCHECK_MSG ("Cannot create the signal for FLUX_SC");
3308
3309 /*
3310 * (5) Create the signals for VIS_SC and T3_SC
3311 */
3312 gravi_vis_create_pfactor_sc (vis_SC, t3_SC, flux_FT);
3313 gravi_vis_create_f1f2_sc (vis_SC, flux_SC);
3314 gravi_vis_create_met_sc (vis_SC, vis_met, oi_wavelengthsc);
3315
3316 gravi_vis_create_vfactor_sc (vis_SC, oi_wavelengthsc,
3317 vis_FT, oi_wavelengthft);
3318
3319 CPLCHECK_MSG ("Cannot create signals for VIS_SC");
3320
3321 /*
3322 * Create QC for PFACTOR, VFACTOR and P3FACTOR
3323 */
3324
3325 for (int base = 0; base < nbase; base++) {
3326 char qc_name[100];
3327
3328 sprintf (qc_name, "ESO QC VFACTOR%s_P%d AVG", GRAVI_BASE_NAME[base], pol+1);
3329 double vmean = gravi_table_get_column_mean (vis_SC, "V_FACTOR_WL", base, nbase);
3330 cpl_propertylist_update_double (p2vmred_header, qc_name, vmean);
3331 cpl_propertylist_set_comment (p2vmred_header, qc_name, "mean v-factor");
3332
3333 sprintf (qc_name, "ESO QC PFACTOR%s_P%d AVG", GRAVI_BASE_NAME[base], pol+1);
3334 double pmean = gravi_table_get_column_mean (vis_SC, "P_FACTOR", base, nbase);
3335 cpl_propertylist_update_double (p2vmred_header, qc_name, pmean);
3336 cpl_propertylist_set_comment (p2vmred_header, qc_name, "mean p-factor");
3337 }
3338
3339 for (int closure = 0; closure < nclo; closure++) {
3340 char qc_name[100];
3341
3342 sprintf (qc_name, "ESO QC P3FACTOR%s_P%d AVG", GRAVI_CLO_NAME[closure], pol+1);
3343 double p3mean = gravi_table_get_column_mean (t3_SC, "P3_FACTOR", closure, nclo);
3344 cpl_propertylist_update_double (p2vmred_header, qc_name, p3mean);
3345 cpl_propertylist_set_comment (p2vmred_header, qc_name, "mean p3-factor");
3346 }
3347
3348 /*
3349 * If available, create the signal from ACQ camera
3350 */
3351 if (gravi_data_has_extension (p2vmred_data, GRAVI_OI_VIS_ACQ_EXT)) {
3352
3353 cpl_table * vis_ACQ = gravi_data_get_table (p2vmred_data, GRAVI_OI_VIS_ACQ_EXT);
3354 gravi_signal_create_sync (vis_SC, 6, dit_sc, vis_ACQ, 4, "ACQ");
3355 gravi_signal_create_sync (flux_SC, 4, dit_sc, vis_ACQ, 4, "ACQ");
3356
3357 gravi_vis_create_acq_sc (vis_SC, vis_ACQ);
3358 gravi_flux_create_acq_sc (flux_SC, vis_ACQ);
3359 }
3360
3361 /*
3362 * Compute FDDL = (FDDL_SC + FDDL_FT)/2 in [m]
3363 * from the POS_SC, POS_FT and the linearity coeficients
3364 *
3365 * Compute the OPD_DISP = n(lbd) * ODD_MET
3366 * from the OPD_MET and the dispersion coeficients
3367 */
3368 cpl_table * disp_table = disp_data ? gravi_data_get_table (disp_data, "DISP_MODEL") : NULL;
3369
3370 gravi_flux_create_fddllin_sc (flux_SC, disp_table);
3371 gravi_vis_create_opddisp_sc (vis_SC, flux_SC, oi_wavelengthsc, disp_table, p2vmred_header, parlist);
3372
3373 CPLCHECK_MSG ("Cannot compute the OPD_DISP");
3374
3375 /*
3376 * Compute the GDELAY of the FT and SC with the proper algorithm.
3377 * Critical since these quantities are used for debuging astrometry
3378 */
3379
3380 /* Recompute the GDELAY of the FT (probably useless since one use GDELAY_FT) */
3381 gravi_table_compute_group_delay (vis_FT, "VISDATA", "FLAG",
3382 "GDELAY", oi_wavelengthft);
3383
3384 /* Recompute the GDELAY of the SC (probably usefull) */
3385 gravi_table_compute_group_delay (vis_SC, "VISDATA", "FLAG",
3386 "GDELAY", oi_wavelengthsc);
3387
3388 /* Compute the GDELAY_FT of VISDATA_FT in SC table (critical) */
3389 gravi_table_compute_group_delay (vis_SC, "VISDATA_FT", "FLAG",
3390 "GDELAY_FT", oi_wavelengthft);
3391
3392 CPLCHECK_MSG ("Cannot compute the GDELAYs");
3393
3394 /* Compute the SELF_REF phase reference for SC (first) */
3395 gravi_vis_create_phaseref_sc (vis_SC, oi_wavelengthsc, NULL, p2vmred_header, parlist);
3396
3397 /* Compute the PHASE_REF reference for SC */
3398 gravi_vis_create_phaseref_sc (vis_SC, oi_wavelengthsc, oi_wavelengthft, p2vmred_header, parlist);
3399
3400 /* Create the IMAGING_REF phase ref, need PHASE_REF */
3401 gravi_vis_create_imagingref_sc (vis_SC, oi_wavelengthsc, p2vmred_header, parlist);
3402
3403 CPLCHECK_MSG ("Cannot compute the PHASE_REF");
3404 } /* End loop on pol */
3405
3406
3408 return CPL_ERROR_NONE;
3409}
3410
3411/*----------------------------------------------------------------------------*/
3418/*----------------------------------------------------------------------------*/
3419
3420cpl_error_code gravi_copy_p2vm_qcs(gravi_data *p2vmred_data, cpl_propertylist *plist) {
3421 cpl_ensure_code(p2vmred_data, CPL_ERROR_NULL_INPUT);
3422 cpl_ensure_code(plist, CPL_ERROR_NULL_INPUT);
3423
3424 cpl_propertylist *p2vmred_header = gravi_data_get_header (p2vmred_data);
3425 CPLCHECK_MSG ("Cannot get header");
3426
3427 int nbase = 6, nclo = 4;
3428 int npol_ft = gravi_pfits_get_pola_num (p2vmred_header, GRAVI_FT);
3429 int npol_sc = gravi_pfits_get_pola_num (p2vmred_header, GRAVI_SC);
3430
3431 cpl_table * vis_SC = gravi_data_get_oi_vis (p2vmred_data, GRAVI_SC, 0, npol_sc);
3432 cpl_size nrow = cpl_table_get_nrow (vis_SC) / nbase;
3433
3434 for (int pol = 0; pol < CPL_MAX(npol_sc,npol_ft); pol++) {
3435 for (int base = 0; base < nbase; base++) {
3436 char qc_name[100];
3437
3438 sprintf (qc_name, "ESO QC VFACTOR%s_P%d AVG", GRAVI_BASE_NAME[base], pol+1);
3439 const cpl_property *qc_val = cpl_propertylist_get_property_const(p2vmred_header, qc_name);
3440 cpl_propertylist_append_property(plist, qc_val);
3441
3442 sprintf (qc_name, "ESO QC PFACTOR%s_P%d AVG", GRAVI_BASE_NAME[base], pol+1);
3443 qc_val = cpl_propertylist_get_property_const(p2vmred_header, qc_name);
3444 cpl_propertylist_append_property(plist, qc_val);
3445 }
3446 CPLCHECK_MSG("Could not copy PFACTOR/VFACTOR");
3447
3448 for (int closure = 0; closure < nclo; closure++) {
3449 char qc_name[100];
3450
3451 sprintf (qc_name, "ESO QC P3FACTOR%s_P%d AVG", GRAVI_CLO_NAME[closure], pol+1);
3452 const cpl_property *qc_val = cpl_propertylist_get_property_const(p2vmred_header, qc_name);
3453 cpl_propertylist_append_property(plist, qc_val);
3454 }
3455 CPLCHECK_INT("Could not copy P3FACTOR");
3456 }
3457
3458 cpl_propertylist_append_long_long(plist, "NROW", nrow);
3459 return CPL_ERROR_NONE;
3460}
3461
3462/*----------------------------------------------------------------------------*/
3482/*----------------------------------------------------------------------------*/
3483
3484cpl_error_code gravi_compute_rejection (gravi_data * p2vmred_data,
3485 const cpl_parameterlist * parlist)
3486{
3488 cpl_ensure_code (p2vmred_data, CPL_ERROR_NULL_INPUT);
3489
3490 char qc_name[100];
3491 int nbase = 6;
3492
3493 /* Get header data */
3494 cpl_propertylist * p2vmred_header = gravi_data_get_header (p2vmred_data);
3495 CPLCHECK_MSG ("Cannot get header");
3496
3497 /* create array to store rejection rate */
3498 cpl_array * rejected_array = cpl_array_new(nbase,CPL_TYPE_DOUBLE);
3499 cpl_array_fill_window_double (rejected_array, 0, nbase, 0.0);
3500
3501 /*
3502 * (1) Do the FT rejection flags
3503 */
3504 if (gravi_data_has_type (p2vmred_data, "_FT") < 2 ) {
3505 cpl_msg_info (cpl_func, "Cannot compute rejection flags for FT (no FT data)");
3506 }
3507 else {
3508 cpl_msg_info (cpl_func, "Compute rejection flags for FT");
3509
3510 /* Get the SNR thresholds from parameter */
3511 double threshold_SNR_ft = gravi_param_get_double (parlist, "gravity.signal.snr-min-ft");
3512 double threshold_STATE_ft = gravi_param_get_double (parlist, "gravity.signal.state-min-ft");
3513 double min_GSTATE_ft = gravi_param_get_double (parlist, "gravity.signal.global-state-min-ft");
3514 double max_GSTATE_ft = gravi_param_get_double (parlist, "gravity.signal.global-state-max-ft");
3515
3516 cpl_msg_info (cpl_func,"SNR threshold to define fringe-detection in FT: %g", threshold_SNR_ft);
3517 cpl_msg_info (cpl_func,"STATE threshold for FT: %g", threshold_STATE_ft);
3518 cpl_msg_info (cpl_func,"GLOBAL_STATE threshold for FT: %g - %g", min_GSTATE_ft, max_GSTATE_ft);
3519
3520 /* Loop on polarisations */
3521 int npol_ft = gravi_pfits_get_pola_num (p2vmred_header, GRAVI_FT);
3522 cpl_size nrow_ft = 0;
3523 for (int pol = 0; pol < npol_ft; pol++) {
3524
3525 /* Get the pointer to data */
3526 cpl_table * vis_FT = gravi_data_get_oi_vis (p2vmred_data, GRAVI_FT, pol, npol_ft);
3527 double * snr = cpl_table_get_data_double (vis_FT, "SNR_BOOT");
3528 int * state = cpl_table_get_data_int (vis_FT, "STATE");
3529 int * gstate = cpl_table_get_data_int (vis_FT, "OPDC_STATE");
3530
3531 gravi_table_new_column (vis_FT, "REJECTION_FLAG", NULL, CPL_TYPE_INT);
3532 int * reject_flag_ft = cpl_table_get_data_int (vis_FT, "REJECTION_FLAG");
3533
3534 CPLCHECK_MSG ("Cannot create columns");
3535
3536 /* Loop on base and rows */
3537 nrow_ft = cpl_table_get_nrow (vis_FT) / nbase;
3538 for (cpl_size row = 0; row < nrow_ft * nbase; row ++) {
3539
3540 /* Rejection based on SNR (first bit) */
3541 int snr_bit = 0;
3542 int reject = 0;
3543 if ( snr[row] < threshold_SNR_ft )
3544 {
3545 gravi_bit_set (reject_flag_ft[row], snr_bit);
3546 reject = 1;
3547 }
3548 else
3549 {
3550 gravi_bit_clear (reject_flag_ft[row], snr_bit);
3551 }
3552
3553 /* Rejection based on STATE (2sd bit) */
3554 int state_bit = 1;
3555 if ( state[row] < threshold_STATE_ft ||
3556 gstate[row] < min_GSTATE_ft ||
3557 gstate[row] > max_GSTATE_ft )
3558 {
3559 gravi_bit_set (reject_flag_ft[row], state_bit);
3560 reject = 1;
3561 }
3562 else
3563 {
3564 gravi_bit_clear (reject_flag_ft[row], state_bit);
3565 }
3566
3567 /* add 1 if rejected to array */
3568 cpl_array_set_double(rejected_array,row%nbase,
3569 cpl_array_get_double(rejected_array,row%nbase,NULL)+reject );
3570 }
3571
3572 } /* End loop on polarisation */
3573
3574 /* normalize the rejection ratio as percent */
3575 cpl_array_multiply_scalar (rejected_array,100./(npol_ft*nrow_ft));
3576
3577 /* store rejection ratio in QC */
3578 for (int base = 0; base < nbase; base++) {
3579
3580 sprintf (qc_name, "ESO QC REJECTED RATIO FT%s", GRAVI_BASE_NAME[base]);
3581 double ratio = cpl_array_get_double (rejected_array, base, NULL);
3582 cpl_msg_info (cpl_func, "%s = %f", qc_name, ratio);
3583 cpl_propertylist_update_int (p2vmred_header, qc_name, round(ratio));
3584 cpl_propertylist_set_comment (p2vmred_header, qc_name, "[%] ratio of FT data flagged");
3585 }
3586
3587 sprintf (qc_name, "ESO QC REJECTED RATIO FT");
3588 double ratio = cpl_array_get_mean (rejected_array);
3589 cpl_msg_info (cpl_func, "%s = %f", qc_name, ratio);
3590 cpl_propertylist_update_int (p2vmred_header, qc_name, round(ratio));
3591 cpl_propertylist_set_comment (p2vmred_header, qc_name, "[%] ratio of FT data flagged");
3592 cpl_array_fill_window_double (rejected_array, 0, nbase, 0.0);
3593
3594 } /* End FT */
3595
3596 /*
3597 * (2) Ratio of FT valid inside each SC DIT
3598 */
3599 if (gravi_data_has_type (p2vmred_data, "_FT") < 1 ||
3600 gravi_data_has_type (p2vmred_data, "_SC") < 1) {
3601 cpl_msg_info (cpl_func, "Cannot compute tracking ratio for SC (no FT or SC data)");
3602 }
3603 else {
3604 cpl_msg_info (cpl_func, "Compute tracking ratio for each SC DIT");
3605
3606 /* Loop on polarisations */
3607 int npol_sc = gravi_pfits_get_pola_num (p2vmred_header, GRAVI_SC);
3608 int npol_ft = gravi_pfits_get_pola_num (p2vmred_header, GRAVI_FT);
3609 for (int pol = 0; pol < npol_sc; pol++) {
3610
3611 cpl_table * vis_SC = gravi_data_get_oi_vis (p2vmred_data, GRAVI_SC, pol, npol_sc);
3612 cpl_table * vis_FT = gravi_data_get_oi_vis (p2vmred_data, GRAVI_FT, CPL_MIN(pol,npol_ft), npol_ft);
3613 gravi_vis_create_lockratio_sc (vis_SC, vis_FT);
3614 CPLCHECK_MSG ("Cannot compute lockratio_sc");
3615 }
3616 }
3617
3618 /*
3619 * (3) Do the SC rejection flags
3620 */
3621 if (gravi_data_has_type (p2vmred_data, "_SC") < 2 ) {
3622 cpl_msg_info (cpl_func, "Cannot compute rejection flags for SC (no SC data)");
3623 }
3624 else {
3625 cpl_msg_info (cpl_func, "Compute rejection flags for SC");
3626
3627 /* Get the SC rejection parameters */
3628 double minlockratio_sc = gravi_param_get_double (parlist, "gravity.signal.tracking-min-sc");
3629 double minvfactor_sc = gravi_param_get_double (parlist, "gravity.signal.vfactor-min-sc");
3630
3631 cpl_msg_info (cpl_func,"Fringe-detection ratio to discard frame on SC: %g", minlockratio_sc);
3632 cpl_msg_info (cpl_func,"vFactor threshold to discard frame on SC: %g", minvfactor_sc);
3633
3634 double opd_pupil_max_sc = gravi_param_get_double (parlist, "gravity.signal.opd-pupil-max-sc");
3635 double opd_pupil_stddev_max_sc = gravi_param_get_double (parlist, "gravity.signal.opd-pupil-stddev-max-sc");
3636
3637 cpl_msg_info (cpl_func,"OPD_PUPIL threshold (abs) to discard frame on SC: %g", opd_pupil_max_sc);
3638 cpl_msg_info (cpl_func,"OPD_PUPIL_STDDEV threshold to discard frame on SC: %g", opd_pupil_stddev_max_sc);
3639
3640 /* Loop on polarisations */
3641 int npol_sc = gravi_pfits_get_pola_num (p2vmred_header, GRAVI_SC);
3642 cpl_size nrow_sc = 0;
3643 for (int pol = 0; pol < npol_sc; pol++) {
3644
3645 /* Get the table of reduced data */
3646 cpl_table * vis_SC = gravi_data_get_oi_vis (p2vmred_data, GRAVI_SC, pol, npol_sc);
3647 double * vFactor_wl = cpl_table_get_data_double (vis_SC, "V_FACTOR_WL");
3648 double * fringedet_ftdit = cpl_table_get_data_double (vis_SC, "FRINGEDET_RATIO");
3649
3650 CPLCHECK_MSG("Cannot load data");
3651
3652 double * opd_metdit_pupil = NULL;
3653 if ( cpl_table_has_column (vis_SC, "OPD_MET_PUPIL") )
3654 opd_metdit_pupil = cpl_table_get_data_double (vis_SC, "OPD_MET_PUPIL");
3655
3656 double * opd_metdit_pupil_stddev = NULL;
3657 if ( cpl_table_has_column (vis_SC, "OPD_MET_PUPIL_STDDEV") )
3658 opd_metdit_pupil_stddev = cpl_table_get_data_double (vis_SC, "OPD_MET_PUPIL_STDDEV");
3659
3660 CPLCHECK_MSG("Cannot load data");
3661
3662 gravi_table_new_column (vis_SC, "REJECTION_FLAG", NULL, CPL_TYPE_INT);
3663 int * reject_flag_sc = cpl_table_get_data_int (vis_SC, "REJECTION_FLAG");
3664
3665 CPLCHECK_MSG ("Cannot create columns");
3666
3667 /* Loop on base and row SC */
3668 nrow_sc = cpl_table_get_nrow (vis_SC) / nbase;
3669 for (cpl_size row_sc = 0; row_sc < nrow_sc * nbase; row_sc++) {
3670
3671 /* Rejection based in lockratio (first bit) */
3672 int lock_bit = 0;
3673 int reject = 0;
3674 if ( fringedet_ftdit[row_sc] < minlockratio_sc )
3675 {
3676 gravi_bit_set (reject_flag_sc[row_sc], lock_bit);
3677 reject = 1;
3678 }
3679 else
3680 gravi_bit_clear (reject_flag_sc[row_sc], lock_bit);
3681
3682 /* Rejection based in the white-light vFactor (second bit) */
3683 int vfactor_bit = 1;
3684 if ( vFactor_wl[row_sc] < minvfactor_sc )
3685 {
3686 gravi_bit_set (reject_flag_sc[row_sc], vfactor_bit);
3687 reject = 1;
3688 }
3689 else
3690 {
3691 gravi_bit_clear (reject_flag_sc[row_sc], vfactor_bit);
3692 }
3693
3694 /* Rejection based on OPD_PUPIL (third bit) */
3695 int opd_pupil_bit = 2;
3696 if ( opd_metdit_pupil ) {
3697 if ( fabs(opd_metdit_pupil[row_sc]) > opd_pupil_max_sc )
3698 {
3699 gravi_bit_set (reject_flag_sc[row_sc], opd_pupil_bit);
3700 reject = 1;
3701 }
3702 else
3703 {
3704 gravi_bit_clear (reject_flag_sc[row_sc], opd_pupil_bit);
3705 }
3706 }
3707
3708 /* Rejection based on OPD_PUPIL_STDDEV (fourth bit) */
3709 int opd_pupil_stddev_bit = 3;
3710 if ( opd_metdit_pupil_stddev ) {
3711 if ( opd_metdit_pupil_stddev[row_sc] > opd_pupil_stddev_max_sc )
3712 {
3713 gravi_bit_set (reject_flag_sc[row_sc], opd_pupil_stddev_bit);
3714 reject = 1;
3715 }
3716 else
3717 {
3718 gravi_bit_clear (reject_flag_sc[row_sc], opd_pupil_stddev_bit);
3719 }
3720 }
3721
3722 /* add 1 if rejected to array */
3723 cpl_array_set_double(rejected_array,row_sc%nbase,
3724 cpl_array_get_double(rejected_array,row_sc%nbase,NULL)+reject );
3725 }
3726 } /* End loop on pol */
3727
3728 /* normalize the rejection ratio as percent */
3729 cpl_array_multiply_scalar (rejected_array,100./(npol_sc*nrow_sc));
3730
3731 /* store rejection ratio in QC */
3732 for (int base = 0; base < nbase; base++) {
3733
3734 sprintf (qc_name, "ESO QC REJECTED RATIO SC%s", GRAVI_BASE_NAME[base]);
3735 double ratio = cpl_array_get_double (rejected_array, base, NULL);
3736 cpl_msg_info (cpl_func, "%s = %f", qc_name, ratio);
3737 cpl_propertylist_update_int (p2vmred_header, qc_name, ratio);
3738 cpl_propertylist_set_comment (p2vmred_header, qc_name, "[%] ratio of SC data flagged");
3739 }
3740
3741 sprintf (qc_name, "ESO QC REJECTED RATIO SC");
3742 double ratio = cpl_array_get_mean (rejected_array);
3743 cpl_msg_info (cpl_func, "%s = %f", qc_name, ratio);
3744 cpl_propertylist_update_int (p2vmred_header, qc_name, ratio);
3745 cpl_propertylist_set_comment (p2vmred_header, qc_name, "[%] ratio of SC data flagged");
3746 } /* End SC */
3747
3748 cpl_array_delete(rejected_array);
3750 return CPL_ERROR_NONE;
3751}
3752
#define gravi_table_get_value(table, name, row, value)
Definition: gravi_cpl.h:49
typedefCPL_BEGIN_DECLS struct _gravi_data_ gravi_data
Definition: gravi_data.h:39
#define gravi_data_get_oi_t3(data, type, pol, npol)
Definition: gravi_data.h:48
#define gravi_data_get_oi_flux(data, type, pol, npol)
Definition: gravi_data.h:49
#define gravi_data_get_header(data)
Definition: gravi_data.h:75
#define gravi_data_get_oi_wave(data, type, pol, npol)
Definition: gravi_data.h:45
#define gravi_data_get_oi_vis(data, type, pol, npol)
Definition: gravi_data.h:46
const cpl_size ntel
const cpl_size ndiode
cpl_msg_debug(cpl_func, "Spectra has <50 pixels -> don't flat")
cpl_propertylist * header
Definition: gravi_old.c:2004
cpl_propertylist * plist
Definition: gravi_old.c:2000
cpl_msg_info(cpl_func, "Compute WAVE_SCAN for %s", GRAVI_TYPE(type_data))
cpl_propertylist_update_double(header, "ESO QC MINWAVE SC", cpl_propertylist_get_double(plist, "ESO QC MINWAVE SC"))
#define GRAVI_OI_VIS_ACQ_EXT
Definition: gravi_pfits.h:89
#define GRAVI_INSNAME(type, pol, npol)
Definition: gravi_pfits.h:198
#define GRAVI_OI_VIS_MET_EXT
Definition: gravi_pfits.h:88
#define GRAVI_SC
Definition: gravi_pfits.h:165
#define GRAVI_FDDL_EXT
Definition: gravi_pfits.h:75
#define GRAVI_TYPE(type)
Definition: gravi_pfits.h:167
#define GRAVI_FT
Definition: gravi_pfits.h:166
#define CPLCHECK_INT(msg)
Definition: gravi_utils.h:51
#define gravi_msg_function_exit(flag)
Definition: gravi_utils.h:85
#define gravi_bit_clear(number, pos)
Definition: gravi_utils.h:37
#define FREE(function, variable)
Definition: gravi_utils.h:69
#define gravi_msg_function_start(flag)
Definition: gravi_utils.h:84
#define CPLCHECK_MSG(msg)
Definition: gravi_utils.h:45
#define gravi_bit_set(number, pos)
Definition: gravi_utils.h:36
#define gravi_pow2(data)
Definition: gravi_utils.h:81
#define FREELOOP(function, variable, n)
Definition: gravi_utils.h:72
cpl_error_code gravi_table_smooth_column(cpl_table *oi_vis, const char *input_name, const char *output_name, int nsmooth, int nbase)
Definition: gravi_cpl.c:1004
cpl_error_code gravi_table_add_columns(cpl_table *oi_vis1, const char *name1, cpl_table *oi_vis2, const char *name2)
Definition: gravi_cpl.c:840
cpl_error_code gravi_table_runint_column(cpl_table *oi_vis, const char *input_name, const char *output_name, int nsmooth, int nbase)
Definition: gravi_cpl.c:911
double gravi_table_get_column_mean(cpl_table *table, const char *name, int base, int nbase)
Definition: gravi_cpl.c:343
cpl_error_code gravi_table_new_column(cpl_table *table, const char *name, const char *unit, cpl_type type)
Definition: gravi_cpl.c:1656
cpl_error_code gravi_table_compute_group_delay(cpl_table *table, const char *input, const char *flag, const char *output, cpl_table *oi_wave)
Definition: gravi_cpl.c:1535
cpl_error_code gravi_table_init_column_array(cpl_table *table, const char *name, const char *unit, cpl_type type, cpl_size size)
Definition: gravi_cpl.c:1692
cpl_error_code gravi_array_add_phase(cpl_array *input, double factor, cpl_array *phase)
Add a REAL phase to a REAL phase array, in-place: input = input + factor * phase.
Definition: gravi_cpl.c:1241
cpl_error_code gravi_vector_abs(cpl_vector *vector)
Return the running median of a vector, with special care for the boundaray, that are filled with the ...
Definition: gravi_cpl.c:2588
cpl_array * gravi_array_init_double(long n, double value)
Definition: gravi_cpl.c:597
double ** gravi_table_get_data_array_double(cpl_table *table, const char *name)
Definition: gravi_cpl.c:473
cpl_vector * gravi_vector_median(const cpl_vector *vector, cpl_size hw)
Return the running median of a vector, with special care for the boundaray, that are filled with the ...
Definition: gravi_cpl.c:2547
cpl_array * gravi_table_get_column_sum_array(cpl_table *table, const char *name, int base, int nbase)
Definition: gravi_cpl.c:427
cpl_error_code gravi_array_phase_wrap(cpl_array *input)
Definition: gravi_cpl.c:1119
cpl_array * gravi_array_init_double_complex(long n, double complex value)
Definition: gravi_cpl.c:619
cpl_error_code gravi_array_multiply_phasor(cpl_array *input, double complex factor, cpl_array *phase)
Multiply a REAL phase to a COMPLEX array, in-place: input = input * cexp (factor * phase)
Definition: gravi_cpl.c:1159
cpl_error_code gravi_table_new_column_array(cpl_table *table, const char *name, const char *unit, cpl_type type, cpl_size size)
Definition: gravi_cpl.c:1678
int gravi_data_has_extension(gravi_data *raw_calib, const char *ext_name)
Check if data has extension with given EXTNAME.
Definition: gravi_data.c:1808
int gravi_data_has_type(gravi_data *self, const char *type)
Return the number of ext whose EXTNAME and INSNAME match 'type'.
Definition: gravi_data.c:1833
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
int gravi_param_get_bool(const cpl_parameterlist *parlist, const char *name)
Definition: gravi_dfs.c:1537
const char * gravi_param_get_string(const cpl_parameterlist *parlist, const char *name)
Definition: gravi_dfs.c:1550
int gravi_param_get_int(const cpl_parameterlist *parlist, const char *name)
Definition: gravi_dfs.c:1524
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
double gravi_pfits_get_gdzero(const cpl_propertylist *plist, int tel)
Definition: gravi_pfits.c:562
double gravi_pfits_get_sobj_y(const cpl_propertylist *plist)
Definition: gravi_pfits.c:461
double gravi_pfits_get_oplzero(const cpl_propertylist *plist, int tel)
Definition: gravi_pfits.c:606
double gravi_pfits_get_dit_sc(const cpl_propertylist *plist)
Definition: gravi_pfits.c:664
int gravi_pfits_has_gdzero(const cpl_propertylist *plist, int tel)
Definition: gravi_pfits.c:541
double gravi_pfits_get_period_sc(const cpl_propertylist *plist)
Definition: gravi_pfits.c:682
double gravi_pfits_get_sobj_x(const cpl_propertylist *plist)
Definition: gravi_pfits.c:455
cpl_error_code gravi_vis_create_f1f2_sc(cpl_table *vis_SC, cpl_table *flux_SC)
Compute the photometric normalisation for the SC.
cpl_error_code gravi_vis_create_pfactor_sc(cpl_table *vis_SC, cpl_table *t3_SC, cpl_table *flux_FT)
Compute the PFACTOR for the SC.
Definition: gravi_signal.c:943
cpl_error_code gravi_vis_create_vfactor_sc(cpl_table *vis_SC, cpl_table *wave_table_sc, cpl_table *vis_FT, cpl_table *wave_table_ft)
Compute the VFACTOR for each SC DIT based on real-time FT.
cpl_error_code gravi_flux_create_acq_sc(cpl_table *vis_SC, cpl_table *vis_ACQ)
Compute the averaged ACQ signal for each SC DIT per beam.
cpl_error_code gravi_vis_compute_isdelay(cpl_table *oi_vis, const char *name_isp, const char *name_gdl, cpl_table *oi_wavelength)
Compute the group-delay from interspectra.
Definition: gravi_signal.c:482
cpl_error_code gravi_vis_create_f1f2_ft(cpl_table *vis_FT, cpl_table *flux_FT)
Compute the photometric normalisation for the FT.
cpl_error_code gravi_vis_create_lockratio_sc(cpl_table *vis_SC, cpl_table *vis_FT)
Create the clockratio for each SC DIT and baseline.
cpl_error_code gravi_compute_snr(gravi_data *p2vmred_data, const cpl_parameterlist *parlist)
Compute real-time SNR and Group-Delay of the observation.
Definition: gravi_signal.c:620
cpl_error_code gravi_flux_create_fddlpos_sc(cpl_table *flux_SC, cpl_table *fddl_table)
Compute the averaged FDDL signal for each SC DIT per beam.
cpl_error_code gravi_flux_create_fddllin_sc(cpl_table *flux_SC, cpl_table *disp_table)
Compute the (FDDL_SC + FDDL_FT)/2 position in [m].
cpl_error_code gravi_vis_create_opdsc_ft(cpl_table *vis_FT, cpl_table *vis_SC, double dit_sc)
Compute the resampled SC signal for each FT DIT per base.
cpl_error_code gravi_flux_create_totalflux_sc(cpl_table *flux_SC, cpl_table *flux_FT)
Compute total flux of each DIT for the SC and of the FT.
cpl_error_code gravi_flux_create_met_sc(cpl_table *flux_SC, cpl_table *vis_MET)
Compute the averaged MET signal for each SC DIT per beam.
cpl_error_code gravi_vis_correct_phasediff(cpl_table *oi_vis1, const char *name1, cpl_table *oi_vis2, const char *name2, double *phasediff)
Correct for mean phase-difference between coherent fluxes.
Definition: gravi_signal.c:218
cpl_error_code gravi_vis_create_phaseref_ft(cpl_table *vis_FT)
Compute the self-reference phase for each FT DIT.
cpl_error_code gravi_vis_create_pfactor_ft(cpl_table *vis_FT, cpl_table *flux_FT, cpl_size window_width)
Compute the PFACTOR for the FT.
cpl_error_code gravi_vis_create_acq_sc(cpl_table *vis_SC, cpl_table *vis_ACQ)
Compute the averaged ACQ signal for each SC DIT per base.
cpl_error_code gravi_vis_create_opddisp_sc(cpl_table *vis_SC, cpl_table *flux_SC, cpl_table *wave_table, cpl_table *disp_table, cpl_propertylist *header, const cpl_parameterlist *parlist)
Compute the MET opd including the dispersion from the FDDL.
cpl_error_code gravi_vis_compute_interspectre(cpl_table *oi_vis, const char *name_vis, const char *name_is, const char *name_flag)
Compute the real-time interspectra.
Definition: gravi_signal.c:359
cpl_error_code gravi_vis_create_met_ft(cpl_table *vis_FT, cpl_table *vis_MET)
Compute the resampled MET signal for each FT DIT per base.
cpl_error_code gravi_vis_create_phaseref_sc(cpl_table *vis_SC, cpl_table *wave_table_sc, cpl_table *wave_table_ft, cpl_propertylist *header, const cpl_parameterlist *parlist)
Compute the reference phase for each SC DIT.
cpl_error_code gravi_compute_signals(gravi_data *p2vmred_data, gravi_data *disp_data, const cpl_parameterlist *parlist)
Create intermediate signal in the P2VMREDUCED file.
cpl_error_code gravi_vis_create_imagingref_sc(cpl_table *vis_SC, cpl_table *wave_table, cpl_propertylist *header, const cpl_parameterlist *parlist)
Create phase-referenced imaging data in the P2VMREDUCED file.
cpl_error_code gravi_signal_create_sync(cpl_table *vis_SC, int nbase_sc, double dit_sc, cpl_table *vis_FT, int nbase_ft, const char *name)
Compute synchronisation indices between OIFITS tables.
Definition: gravi_signal.c:849
cpl_error_code gravi_vis_create_met_sc(cpl_table *vis_SC, cpl_table *vis_MET, cpl_table *wave_table)
Compute the averaged MET signal for each SC DIT per base.
cpl_error_code gravi_compute_outliers(gravi_data *p2vmred_data, const cpl_parameterlist *parlist)
Compute the outliers flags.
Definition: gravi_signal.c:536
cpl_error_code gravi_compute_rejection(gravi_data *p2vmred_data, const cpl_parameterlist *parlist)
Create rejection flags P2VMREDUCED file.
cpl_error_code gravi_vis_compute_snr(cpl_table *oi_vis, const char *name_pha, const char *name_var, const char *name_snr)
Compute the real-time SNR.
Definition: gravi_signal.c:432
cpl_error_code gravi_create_outlier_flag_ft(cpl_table *flux_SC, cpl_table *vis_SC)
Create the list of outlier. For the FT, this is filled with 0.
cpl_error_code gravi_copy_p2vm_qcs(gravi_data *p2vmred_data, cpl_propertylist *plist)
Copy PFACTOR and VFACTOR QCs so that they may be aggregated over all frames.
cpl_error_code gravi_vis_bootstrap_snr_and_delay(cpl_table *oi_vis, const char *name_snr, const char *name_gdl)
Boostrap real-time SNR and GDELAY.
Definition: gravi_signal.c:150
cpl_error_code gravi_vis_compute_mean_phasor(cpl_table *oi_vis, const char *name_vis, const char *name_err, const char *name_pha, const char *name_var, const char *name_flag)
Compute real-time mean phasor of a VISDATA by averaging all spectral elements.
Definition: gravi_signal.c:280
cpl_error_code gravi_create_outlier_flag_sc(cpl_table *flux_SC, cpl_table *vis_SC, double chi2r_threshold, double chi2r_sigma)
Create the list of outlier based on the values of the chi2.
int GRAVI_TRI_SIGN[GRAVI_NBASE][2][2]
Definition: gravi_utils.c:61
cpl_error_code gravi_msg_warning(const char *component, const char *msg)
Definition: gravi_utils.c:127
char GRAVI_BASE_NAME[6][3]
Definition: gravi_utils.c:57
int GRAVI_CLO_TEL[4][3]
Definition: gravi_utils.c:64
int GRAVI_BASE_TEL[GRAVI_NBASE][2]
Definition: gravi_utils.c:56
char GRAVI_CLO_NAME[4][4]
Definition: gravi_utils.c:65
int GRAVI_TRI_BASE[GRAVI_NBASE][2][2]
Definition: gravi_utils.c:60