GRAVI Pipeline Reference Manual  1.2.3
gravi_disp.c
1 /* $Id: gravi_disp.c,v 1.10 2012/03/23 15:10:40 nazouaoui Exp $
2  *
3  * This file is part of the GRAVI Pipeline
4  * Copyright (C) 2002,2003 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
36 /*
37  * History
38  * 07/12/208 add wave_param to gravi_compute_argon_pos
39  */
40 /*----------------------------------------------------------------------------
41  DEBUG
42  -----------------------------------------------------------------------------*/
43 
44 #define INFO_DEBUG 0
45 #define GRAVI_ACOEFF_RANGE 0.02
46 
47 /*-----------------------------------------------------------------------------
48  Includes
49  -----------------------------------------------------------------------------*/
50 
51 #ifdef HAVE_CONFIG_H
52 #include <config.h>
53 #endif
54 
55 #include <cpl.h>
56 #include <string.h>
57 #include <stdio.h>
58 #include <time.h>
59 #include <math.h>
60 #include <complex.h>
61 
62 #include "gravi_data.h"
63 #include "gravi_dfs.h"
64 #include "gravi_pfits.h"
65 #include "gravi_cpl.h"
66 
67 #include "gravi_utils.h"
68 #include "gravi_signal.h"
69 
70 #include "gravi_vis.h"
71 #include "gravi_disp.h"
72 
73 /*-----------------------------------------------------------------------------
74  Private prototypes
75  -----------------------------------------------------------------------------*/
76 
77 cpl_table * gravi_fit_fddl_lin (cpl_table * oiflux_table);
78 
79 cpl_table * gravi_fit_dispersion (cpl_table * oiflux_table,
80  cpl_table * oivis_table,
81  cpl_table * oiwave_table,
82  double * GDrms,
83  double * Amin,
84  double * Amax);
85 
86 /*-----------------------------------------------------------------------------
87  Functions code
88  -----------------------------------------------------------------------------*/
89 
90 /*----------------------------------------------------------------------------*/
111 /*----------------------------------------------------------------------------*/
112 
113 gravi_data * gravi_compute_disp (gravi_data * vis_data)
114 {
115  gravi_msg_function_start(1);
116  cpl_ensure (vis_data, CPL_ERROR_NULL_INPUT, NULL);
117 
118  /* Get data */
119  cpl_size ntel = 4;
120  cpl_propertylist * vis_header = gravi_data_get_header (vis_data);
121  cpl_size npol = gravi_pfits_get_pola_num (vis_header, GRAVI_SC);
122  cpl_table * oiflux_table = gravi_data_get_oi_flux (vis_data, GRAVI_SC, 0, npol);
123  CPLCHECK_NUL ("Cannot get data");
124 
125  /* Get the number of observations */
126  cpl_size nrow = cpl_table_get_nrow (oiflux_table) / ntel;
127  cpl_msg_info (cpl_func,"Input vis_data has %lld observation",nrow);
128 
129  /* Check the number of observation */
130  if (nrow < 10) {
131  cpl_error_set_message (cpl_func, CPL_ERROR_ILLEGAL_INPUT,
132  "Not enough observations to compute"
133  "a dispersion model. Check input SOF");
134  return NULL;
135  }
136 
137  /*
138  * Create output data
139  */
140  gravi_data * disp_map = gravi_data_new (0);
141 
142  /* Set the input header */
143  cpl_propertylist * disp_header = gravi_data_get_header (disp_map);
144  cpl_propertylist_append (disp_header, vis_header);
145 
146  /* Set a QC parameter with the number of observations */
147  const char * qc_name = "ESO QC DISP NEXP";
148  cpl_propertylist_update_int (disp_header, qc_name, nrow);
149  cpl_propertylist_set_comment (disp_header, qc_name, "Number of exposures used");
150 
151 
152  /*
153  * Compute the coefficient of FDDL linearity
154  */
155 
156  cpl_table * linearity_table;
157  linearity_table = gravi_fit_fddl_lin (oiflux_table);
158  CPLCHECK_NUL ("Cannot compute the FDDL linearity");
159 
160 
161  /*
162  * Compute the coefficients for FDDL index dispersion
163  */
164 
165  cpl_table * dispwave_table;
166  double GDrms = 0.0, Amin = 1e4, Amax = -1e4;
167 
168  /* Loop on polarisations */
169  for (int pol = 0; pol < npol; pol++) {
170 
171  /* Get table for this polarisation */
172  cpl_table * oiflux_table = gravi_data_get_oi_flux (vis_data, GRAVI_SC, pol, npol);
173  cpl_table * oivis_table = gravi_data_get_oi_vis (vis_data, GRAVI_SC, pol, npol);
174  cpl_table * oiwave_table = gravi_data_get_oi_wave (vis_data, GRAVI_SC, pol, npol);
175 
176  /* (Re) create the column FDDLi = (FDDL_FTi + FDDL_SCi)/2 */
177  gravi_flux_create_fddllin_sc (oiflux_table, linearity_table);
178 
179  /* Compute the BETA and GAMMA for each wavelength */
180  cpl_table * dispwave_table0;
181  dispwave_table0 = gravi_fit_dispersion (oiflux_table, oivis_table,
182  oiwave_table, &GDrms,
183  &Amin, &Amax);
184  CPLCHECK_NUL ("Cannot compute dispersion");
185 
186  /* Co-add the two polarisation. So here we assume the wavelength
187  * table are the same for the two polarisation */
188  if (pol == 0) {
189  dispwave_table = dispwave_table0;
190  } else {
191  gravi_msg_warning ("FIXME", "Assumes same OI_WAVE for both polar of SC");
192  gravi_table_add_columns (dispwave_table, "BETA", dispwave_table0, "BETA");
193  gravi_table_multiply_scalar (dispwave_table, "BETA", 0, 1, 0.5);
194  gravi_table_add_columns (dispwave_table, "GAMMA", dispwave_table0, "GAMMA");
195  gravi_table_multiply_scalar (dispwave_table, "GAMMA", 0, 1, 0.5);
196  cpl_table_delete (dispwave_table0);
197  }
198  } /* End loop on polarisations */
199 
200 
201  /* Set a QC parameters */
202  qc_name = "ESO QC DISP GDELAY_RMS";
203  cpl_propertylist_update_double (disp_header, qc_name, GDrms);
204  cpl_propertylist_set_comment (disp_header, qc_name, "[m] GDELAY rms over files");
205 
206  qc_name = "ESO QC DISP BETA_CORRECTION MIN";
207  cpl_propertylist_update_double (disp_header, qc_name, Amin);
208  cpl_propertylist_set_comment (disp_header, qc_name, "Fine correction");
209 
210  qc_name = "ESO QC DISP BETA_CORRECTION MAX";
211  cpl_propertylist_update_double (disp_header, qc_name, Amax);
212  cpl_propertylist_set_comment (disp_header, qc_name, "Fine correction");
213 
214  qc_name = "ESO QC DISP BETA_CORRECTION RANGE";
215  cpl_propertylist_update_double (disp_header, qc_name, GRAVI_ACOEFF_RANGE);
216  cpl_propertylist_set_comment (disp_header, qc_name, "Fine correction");
217 
218 
219  /*
220  * Interpolate BETA and GAMMA at known Argon wavelength
221  * WAVE is the position of the argon line on the current OI_WAVE
222  * WAVE_TH is the true, vaccum line wavelength
223  */
224 
225  cpl_table * pos_table = gravi_data_get_table (vis_data, "POS_ARGON");
226  cpl_table * dispth_table = cpl_table_duplicate (pos_table);
227  cpl_size nline = cpl_table_get_nrow (dispth_table);
228 
229  gravi_table_interpolate_column (dispth_table, "WAVE", "BETA",
230  dispwave_table, "EFF_WAVE", "BETA");
231 
232  gravi_table_interpolate_column (dispth_table, "WAVE", "GAMMA",
233  dispwave_table, "EFF_WAVE", "GAMMA");
234 
235  CPLCHECK_NUL ("Cannot interpolate into argon lines");
236 
237  /*
238  * Compute the optical index N_MEAN and N_DIFF from BETA and GAMMA
239  * N_MEAN = BETA * WAVE_TH / LAMBDA_MET
240  * N_DIFF = GAMMA * WAVE_TH / LAMBDA_MET
241  */
242 
243  cpl_table_duplicate_column (dispth_table, "N_MEAN", dispth_table, "BETA");
244  cpl_table_duplicate_column (dispth_table, "N_DIFF", dispth_table, "GAMMA");
245 
246  for (cpl_size line = 0; line < nline; line++) {
247  double value = cpl_table_get (dispth_table, "WAVE_TH", line, NULL) / LAMBDA_MET;
248  cpl_array_multiply_scalar (cpl_table_get_data_array (dispth_table, "N_MEAN")[line], value);
249  cpl_array_multiply_scalar (cpl_table_get_data_array (dispth_table, "N_DIFF")[line], value);
250  }
251 
252 
253  /*
254  * Create the output table from the linearity table
255  */
256  cpl_table * disp_table = linearity_table;
257 
258 
259  /*
260  * Fit dispersion by a polynomial of order 2 and fill
261  * the output table
262  */
263 
264  cpl_size mindeg = 0, maxdeg = 2;
265  gravi_table_new_column_array (disp_table, "N_MEAN", NULL, CPL_TYPE_DOUBLE, maxdeg+1);
266  gravi_table_new_column_array (disp_table, "N_DIFF", NULL, CPL_TYPE_DOUBLE, maxdeg+1);
267  gravi_table_new_column (disp_table, "WAVE0", "m", CPL_TYPE_DOUBLE);
268  gravi_table_new_column_array (disp_table, "BETA", NULL, CPL_TYPE_DOUBLE, maxdeg+1);
269  gravi_table_new_column_array (disp_table, "GAMMA", NULL, CPL_TYPE_DOUBLE, maxdeg+1);
270 
271  /* Allocation of the fit */
272  cpl_matrix * matrix = cpl_matrix_new (1, nline);
273  cpl_vector * vector = cpl_vector_new (nline);
274  cpl_polynomial * poly = cpl_polynomial_new (1);
275  cpl_array * coeff = cpl_array_new (maxdeg+1, CPL_TYPE_DOUBLE);
276 
277  /* The axis for the 2.2e-6/wave_th - 1 */
278  double wave0 = 2.2e-6;
279  for (cpl_size line = 0; line < nline; line++) {
280  double wave_th = cpl_table_get (dispth_table, "WAVE_TH", line, NULL);
281  cpl_matrix_set (matrix, 0, line, wave0/wave_th - 1.);
282  }
283 
284  for (cpl_size tel = 0; tel < ntel; tel++) {
285  cpl_table_set (disp_table, "WAVE0", tel, wave0);
286 
287  /* Fit the BETA */
288  for (cpl_size line = 0; line < nline; line++)
289  cpl_vector_set (vector, line, gravi_table_get_value (dispth_table, "BETA", line, tel));
290  cpl_polynomial_fit (poly, matrix, NULL, vector, NULL, CPL_FALSE, &mindeg, &maxdeg);
291  for (cpl_size order = 0; order <= maxdeg; order ++)
292  cpl_array_set (coeff, order, cpl_polynomial_get_coeff (poly, &order));
293  cpl_table_set_array (disp_table, "BETA", tel, coeff);
294 
295  /* Fit the GAMMA */
296  for (cpl_size line = 0; line < nline; line++)
297  cpl_vector_set (vector, line, gravi_table_get_value (dispth_table, "GAMMA", line, tel));
298  cpl_polynomial_fit (poly, matrix, NULL, vector, NULL, CPL_FALSE, &mindeg, &maxdeg);
299  for (cpl_size order = 0; order <= maxdeg; order ++)
300  cpl_array_set (coeff, order, cpl_polynomial_get_coeff (poly, &order));
301  cpl_table_set_array (disp_table, "GAMMA", tel, coeff);
302 
303  /* Fit the N_MEAN */
304  for (cpl_size line = 0; line < nline; line++)
305  cpl_vector_set (vector, line, gravi_table_get_value (dispth_table, "N_MEAN", line, tel));
306  cpl_polynomial_fit (poly, matrix, NULL, vector, NULL, CPL_FALSE, &mindeg, &maxdeg);
307  for (cpl_size order = 0; order <= maxdeg; order ++)
308  cpl_array_set (coeff, order, cpl_polynomial_get_coeff (poly, &order));
309  cpl_table_set_array (disp_table, "N_MEAN", tel, coeff);
310 
311  /* Fit the N_DIFF */
312  for (cpl_size line = 0; line < nline; line++)
313  cpl_vector_set (vector, line, gravi_table_get_value (dispth_table, "N_DIFF", line, tel));
314  cpl_polynomial_fit (poly, matrix, NULL, vector, NULL, CPL_FALSE, &mindeg, &maxdeg);
315  for (cpl_size order = 0; order <= maxdeg; order ++)
316  cpl_array_set (coeff, order, cpl_polynomial_get_coeff (poly, &order));
317  cpl_table_set_array (disp_table, "N_DIFF", tel, coeff);
318  }
319  CPLCHECK_NUL ("Cannot fit the dispersion coefficients");
320 
321  FREE (cpl_vector_delete, vector);
322  FREE (cpl_matrix_delete, matrix);
323  FREE (cpl_polynomial_delete, poly);
324  FREE (cpl_array_delete, coeff);
325 
326 
327  /*
328  * Output data
329  */
330 
331  /* Add the DISP_MODEL in the output gravi_data */
332  gravi_data_add_table (disp_map, NULL, "DISP_MODEL", disp_table);
333 
334  /* Add the DISP_WAVE in the output gravi_data */
335  gravi_data_add_table (disp_map, NULL, "DISP_WAVE", dispwave_table);
336 
337  /* Add the DISP_WAVETH in the output gravi_data */
338  gravi_data_add_table (disp_map, NULL, "DISP_WAVETH", dispth_table);
339 
340 
341  gravi_msg_function_exit(1);
342  return disp_map;
343 }
344 
345 /*----------------------------------------------------------------------------*/
357 /*----------------------------------------------------------------------------*/
358 
359 cpl_error_code gravi_disp_cleanup (gravi_data * vis_data)
360 {
361  gravi_msg_function_start(1);
362  cpl_ensure_code (vis_data, CPL_ERROR_NULL_INPUT);
363 
364  cpl_size nbase = 6, ntel = 4, nclo = 4;
365 
366  cpl_propertylist * header = gravi_data_get_header (vis_data);
367  cpl_size npol_sc = gravi_pfits_get_pola_num (header, GRAVI_SC);
368  cpl_size npol_ft = gravi_pfits_get_pola_num (header, GRAVI_FT);
369 
370  /* Get one FT OI_VIS table */
371  cpl_table * oivis_table = gravi_data_get_oi_vis (vis_data, GRAVI_FT, 0, npol_ft);
372  cpl_table * oiflux_table = gravi_data_get_oi_flux (vis_data, GRAVI_SC, 0, npol_sc);
373  cpl_size nrow = cpl_table_get_nrow (oivis_table) / nbase;
374 
375  /* Rejection flag (1 = rejected) */
376  cpl_array * flag_array = cpl_array_new (nrow, CPL_TYPE_INT);
377  cpl_array_fill_window (flag_array, 0, nrow, 0);
378 
379  /*
380  * Verify the visibility amplitude
381  */
382 
383  for (cpl_size row = 0; row < nrow; row++) {
384  for (cpl_size base = 0; base < nbase; base++) {
385  cpl_size id = row * nbase + base;
386  double vis = cpl_array_get_median (cpl_table_get_array (oivis_table, "VISAMP", id));
387  cpl_msg_debug ("TEST", "vis = %g", vis);
388  if ( vis < 0.35) cpl_array_set (flag_array, row, 1);
389  }
390  }
391  CPLCHECK_MSG ("Cannot compute flag_array");
392 
393  /*
394  * Flag on lockdate LKDT
395  */
396 
397  /* Get longuest sequence */
398  cpl_size first = 0, nobs = 0;
399  gravi_lkdt_get_sequence (oiflux_table, 4, &first, &nobs);
400 
401  /* Flag all observations outside this sequence */
402  for (cpl_size row = 0; row < nrow; row++) {
403  if (row < first || row >= first+nobs)
404  cpl_array_set (flag_array, row, 1);
405  }
406 
407  if (nobs != nrow) {
408  cpl_msg_warning (cpl_func, "LKDT not stable over all files "
409  "(keep %lld over %lld)", nobs, nrow);
410  } else {
411  cpl_msg_info (cpl_func, "LKDT stable over all files");
412  }
413 
414  /*
415  * Cleanup all tables with this flag_array (rejection flag)
416  */
417 
418  for (int type_data = 0; type_data < 2; type_data ++) {
419  cpl_size npol = gravi_pfits_get_pola_num (header, type_data);
420  for (int pol = 0; pol < npol; pol ++) {
421  gravi_vis_erase_obs (gravi_data_get_oi_flux (vis_data, type_data, pol, npol), flag_array, ntel);
422  gravi_vis_erase_obs (gravi_data_get_oi_vis (vis_data, type_data, pol, npol), flag_array, nbase);
423  gravi_vis_erase_obs (gravi_data_get_oi_vis2 (vis_data, type_data, pol, npol), flag_array, nbase);
424  gravi_vis_erase_obs (gravi_data_get_oi_t3 (vis_data, type_data, pol, npol), flag_array, nclo);
425  CPLCHECK_MSG ("Cannot erase flagged observations");
426  }
427  }
428  FREE (cpl_array_delete, flag_array);
429 
430  /* Verbose */
431  cpl_size nrow_new = cpl_table_get_nrow (oivis_table) / nbase;
432  cpl_msg_info (cpl_func, "Initial data had %lld obs, now %lld", nrow, nrow_new);
433 
434  gravi_msg_function_exit(1);
435  return CPL_ERROR_NONE;
436 }
437 
438 /*----------------------------------------------------------------------------*/
461 /*----------------------------------------------------------------------------*/
462 
463 cpl_table * gravi_fit_fddl_lin (cpl_table * oiflux_table)
464 {
465  gravi_msg_function_start(1);
466  cpl_ensure (oiflux_table, CPL_ERROR_NULL_INPUT, NULL);
467 
468  cpl_size ntel = 4, nbase = 6;
469  cpl_size nrow = cpl_table_get_nrow (oiflux_table) / ntel;
470 
471  /* Model and right-hand-side for the lineary system */
472  cpl_matrix * rhs_matrix = cpl_matrix_new (nrow * nbase, 1);
473  cpl_matrix * model_matrix = cpl_matrix_new (nrow * nbase, nbase + 4 * ntel);
474 
475  for (int base = 0; base < nbase; base++) {
476  int i = GRAVI_BASE_TEL[base][0];
477  int j = GRAVI_BASE_TEL[base][1];
478 
479  for (cpl_size row=0; row<nrow; row++) {
480  int id = row * nbase + base;
481  int idi = row * ntel + i;
482  int idj = row * ntel + j;
483 
484  /* Fill the MET [um] */
485  double meti = cpl_table_get (oiflux_table, "OPD_MET_FC", idi, NULL);
486  double metj = cpl_table_get (oiflux_table, "OPD_MET_FC", idj, NULL);
487  cpl_matrix_set (rhs_matrix, id, 0, (meti - metj)*1e6);
488 
489  /* Fill the model Aij (unfilled matrix are 0.0) */
490  cpl_matrix_set (model_matrix, id, base, 1.0);
491 
492  /* Fill the model Bi, Bj, Ci, Cj */
493  double ft_posi = cpl_table_get (oiflux_table, "FT_POS", idi, NULL);
494  double ft_posj = cpl_table_get (oiflux_table, "FT_POS", idj, NULL);
495  cpl_matrix_set (model_matrix, id, 6 +i, ft_posi);
496  cpl_matrix_set (model_matrix, id, 6 +j, -1*ft_posj);
497  cpl_matrix_set (model_matrix, id, 10+i, ft_posi*ft_posi);
498  cpl_matrix_set (model_matrix, id, 10+j, -1*ft_posj*ft_posj);
499 
500  /* Fill the model Di, Dj, Ei, Ej */
501  double sc_posi = cpl_table_get (oiflux_table, "SC_POS", idi, NULL);
502  double sc_posj = cpl_table_get (oiflux_table, "SC_POS", idj, NULL);
503  cpl_matrix_set (model_matrix, id, 14+i, -1*sc_posi);
504  cpl_matrix_set (model_matrix, id, 14+j, sc_posj);
505  cpl_matrix_set (model_matrix, id, 18+i, -1*sc_posi*sc_posi);
506  cpl_matrix_set (model_matrix, id, 18+j, sc_posj*sc_posj);
507  } /* End loop on rows */
508  } /* End loop on bases */
509 
510  /* Solve the system */
511  cpl_matrix * res_matrix = cpl_matrix_solve_normal (model_matrix, rhs_matrix);
512  FREE (cpl_matrix_delete, model_matrix);
513  FREE (cpl_matrix_delete, rhs_matrix);
514 
515 
516  /*
517  * Fill the linearity coefficients in the output table
518  */
519  cpl_table * lin_table = cpl_table_new (ntel);
520  gravi_table_new_column_array (lin_table, "LIN_FDDL_SC", "um/V^i", CPL_TYPE_DOUBLE, 3);
521  gravi_table_new_column_array (lin_table, "LIN_FDDL_FT", "um/V^i", CPL_TYPE_DOUBLE, 3);
522 
523  cpl_array * coeff = cpl_array_new (3, CPL_TYPE_DOUBLE);
524  for (cpl_size tel = 0; tel < ntel; tel++) {
525  cpl_array_set (coeff, 0, 0);
526  cpl_array_set (coeff, 1, cpl_matrix_get (res_matrix, 6 +tel, 0));
527  cpl_array_set (coeff, 2, cpl_matrix_get (res_matrix, 10+tel, 0));
528  cpl_table_set_array (lin_table, "LIN_FDDL_FT", tel, coeff);
529  cpl_array_set (coeff, 0, 0);
530  cpl_array_set (coeff, 1, cpl_matrix_get (res_matrix, 14+tel, 0));
531  cpl_array_set (coeff, 2, cpl_matrix_get (res_matrix, 18+tel, 0));
532  cpl_table_set_array (lin_table, "LIN_FDDL_SC", tel, coeff);
533  CPLCHECK_NUL ("Cannot set dispersion coeff");
534  }
535 
536  /* Free results */
537  FREE (cpl_matrix_delete, res_matrix);
538  FREE (cpl_array_delete, coeff);
539 
540  gravi_msg_function_exit(1);
541  return lin_table;
542 }
543 
544 /*----------------------------------------------------------------------------*/
582 /*----------------------------------------------------------------------------*/
583 
584 cpl_table * gravi_fit_dispersion (cpl_table * oiflux_table,
585  cpl_table * oivis_table,
586  cpl_table * oiwave_table,
587  double * GDrms,
588  double * Amin,
589  double * Amax)
590 {
591  gravi_msg_function_start(1);
592  cpl_ensure (oiflux_table, CPL_ERROR_NULL_INPUT, NULL);
593  cpl_ensure (oivis_table, CPL_ERROR_NULL_INPUT, NULL);
594  cpl_ensure (oiwave_table, CPL_ERROR_NULL_INPUT, NULL);
595 
596  cpl_size nbase = 6, ntel = 4;
597  cpl_size nrow = cpl_table_get_nrow (oiflux_table) / 4;
598  cpl_size nwave = cpl_table_get_column_depth (oiflux_table, "FLUX");
599  CPLCHECK_NUL ("Cannot get data");
600 
601  /*
602  * Compute a guess of the BETA dispersion coefficient
603  */
604  double beta0 = 0.8651, beta1 = 0.8814;
605 
606  cpl_table_new_column (oiwave_table, "BETA", CPL_TYPE_DOUBLE);
607  for (cpl_size wave = 0; wave < nwave; wave ++) {
608  double lbd = cpl_table_get (oiwave_table, "EFF_WAVE", wave, NULL);
609  double beta = beta0 + beta1 * (2.2e-6/lbd - 1.0);
610  cpl_table_set (oiwave_table, "BETA", wave, beta);
611  }
612  CPLCHECK_NUL ("Cannot create BETA column");
613 
614  /* Get direct pointer to data */
615  double * metdata = cpl_table_get_data_double (oivis_table, "OPD_MET_FC");
616  double complex ** visdata = gravi_table_get_data_array_double_complex (oivis_table, "VISDATA");
617  double * beta = cpl_table_get_data_double (oiwave_table, "BETA");
618  float * effwave = cpl_table_get_data_float (oiwave_table, "EFF_WAVE");
619  CPLCHECK_NUL ("Cannot get data");
620 
621 
622  /*
623  * Correction par la metrologie (Correction # 1)
624  * VIS_ijlt *= exp (-2ipi * BETA_l * METC_ijt / LAMBDA_MET)
625  */
626  cpl_msg_info (cpl_func, "Correction #1");
627 
628  /* Loop on base, rows and wave */
629  for (cpl_size base = 0; base < nbase ; base ++) {
630  for (cpl_size row = 0; row < nrow ; row ++) {
631  int id = row * nbase + base;
632  for (cpl_size wave = 0; wave < nwave; wave ++) {
633  visdata[id][wave] *= cexp (- 2*I*CPL_MATH_PI * beta[wave] * metdata[id] / LAMBDA_MET);
634  }
635  }
636  }
637 
638 
639  /*
640  * Correction par le groupe delay (Correction # 2)
641  * VIS_ijlt *= exp (-2ipi * GD_ij / LBD_l)
642  * with GD_ij = <GD_ijt>
643  */
644  cpl_msg_info (cpl_func, "Correction #2");
645 
646  /* Compute the GD of all base and rows (with wavelength in glass) */
647  gravi_table_compute_group_delay (oivis_table, "VISDATA", "GDELAY", oiwave_table);
648 
649  /* Allocate memory for result */
650  cpl_vector * GDb = cpl_vector_new (nbase);
651 
652  for (cpl_size base = 0; base < nbase ; base ++) {
653  double mean = gravi_table_get_column_mean (oivis_table, "GDELAY", base, nbase);
654  double std = gravi_table_get_column_std (oivis_table, "GDELAY", base, nbase);
655  cpl_vector_set (GDb, base, mean);
656 
657  /* Correct from the mean group-delay */
658  for (cpl_size row = 0; row < nrow ; row ++) {
659  int id = row * nbase + base;
660  for (cpl_size wave = 0; wave < nwave; wave ++) {
661  visdata[id][wave] *= cexp (-2*I*CPL_MATH_PI * mean / effwave[wave]);
662  }
663  }
664 
665  cpl_msg_info (cpl_func, "GD mean = %g [um]", mean*1e6);
666  cpl_msg_info (cpl_func, "GD std = %g [um]", std*1e6);
667 
668  /* Save the overall worst value of GD rms */
669  *GDrms = CPL_MAX (std, *GDrms);
670  }
671 
672 
673  /*
674  * Correction from the residual slope versus met (Correction # 3)
675  * VIS_ijlt *= exp (-2ipi * A_bl * METC_ijt / LAMBDA_MET)
676  *
677  * Where A_bl is computed such that the following is maximum:
678  * | Sum_t[ VIS_ijlt * exp (-2ipi * A_bl * METC_ijt / LAMBDA_MET) ] |
679  *
680  * Hence the A value is a BETA coefficient fine correction.
681  */
682  cpl_msg_info (cpl_func, "Correction #3");
683 
684  /* Allocate memory for force-brut exploration of A values */
685  cpl_size nA = 1000;
686  double complex * phasor = cpl_calloc (nrow * nA, sizeof (double complex));
687  // cpl_vector * plot_vector = cpl_vector_new (nA);
688 
689  /* Allocate memory for results */
690  cpl_matrix * Abl = cpl_matrix_new (nbase, nwave);
691 
692  /* Loop on base and wave */
693  for (cpl_size base = 0; base < nbase ; base ++) {
694  for (cpl_size wave = 0; wave < nwave ; wave ++) {
695 
696  /* Test various possible A value */
697  cpl_size iAmax;
698  double maxV = 0.0;
699  for (cpl_size iA = 0; iA < nA; iA++) {
700  double A = GRAVI_ACOEFF_RANGE * (2.* iA / nA - 1.0);
701 
702  /* Accumulate the re-phased complex Note that we
703  * compute the exp(i.a.METbm) only if needed */
704  double complex currentV = 0.0;
705  for (cpl_size row = 0; row < nrow; row++) {
706  if (wave==0) phasor[row*nA+iA] = cexp (-2.* CPL_MATH_PI * I * A *
707  metdata[row*nbase+base] /
708  LAMBDA_MET);
709  currentV += phasor[row*nA+iA] * visdata[row*nbase+base][wave];
710  }
711 
712  // if (base == 0 && wave == 1700) cpl_vector_set (plot_vector, iA, cabs (currentV));
713 
714  /* Check if better fit */
715  if (cabs (currentV) > maxV) {
716  cpl_matrix_set (Abl, base, wave, A);
717  iAmax = iA;
718  maxV = cabs (currentV);
719  }
720  }/* End exploration in A values */
721 
722  /* Correct the visdata of this base and wave
723  * from the best-fit A value */
724  for (cpl_size row = 0; row < nrow; row++) {
725  visdata[row*nbase+base][wave] *= phasor[row*nA+iAmax];
726  }
727 
728  }
729  } /* End loop on base and wave */
730  FREE (cpl_free, phasor);
731 
732  /* Some verbose */
733  cpl_msg_info (cpl_func, "Abl range = %g (beta correction)",
734  GRAVI_ACOEFF_RANGE);
735  cpl_msg_info (cpl_func, "Abl mean = %g (beta correction)",
736  cpl_matrix_get_mean (Abl));
737  cpl_msg_info (cpl_func, "Abl std = %g (beta correction)",
738  cpl_matrix_get_stdev (Abl));
739 
740  *Amax = CPL_MAX (*Amax, cpl_matrix_get_max (Abl));
741  *Amin = CPL_MIN (*Amin, cpl_matrix_get_min (Abl));
742 
743 
744  // cpl_plot_vector (NULL, NULL, NULL, plot_vector);
745  // FREE (cpl_vector_delete, plot_vector);
746 
747 
748  /*
749  * Remove the mean phase over the rows (Correction # 4)
750  * VIS_ijlt *= exp (-i*O_ijl)
751  * with O_ijl = arg (<VIS_ijlt>)
752  */
753  cpl_msg_info (cpl_func, "Correction #4");
754 
755  /* Allocate memory for results */
756  cpl_matrix * Obl = cpl_matrix_new (nbase, nwave);
757 
758  /* Loop on base and wave */
759  for (cpl_size base = 0; base < nbase ; base ++) {
760  for (cpl_size wave = 0; wave < nwave ; wave ++) {
761 
762  /* Compute the mean phase */
763  double complex currentV = 0.0;
764  for (cpl_size row = 0; row < nrow; row++) {
765  currentV += visdata[row*nbase+base][wave];
766  }
767  cpl_matrix_set (Obl, base, wave, carg (currentV));
768 
769  /* Correct the visdata of this base and wave
770  * from this mean phase */
771  for (cpl_size row = 0; row < nrow; row++) {
772  visdata[row*nbase+base][wave] *= conj (currentV);
773  }
774  }
775  } /* End loop on base and wave */
776 
777 
778 
779  /*
780  * Search for 6Aij + 4Bi + 4Ci solving the linear system:
781  * PHASEijt * LAMBDA_MET / 2pi = Aij + Ci (FDDL_FTit + FDDL_SCit)/2
782  * - Cj (FDDL_FTjt + FDDL_SCjt)/2
783  * + Bi METit - Bj METjt
784  * for all wavelength and both polaristions
785  */
786  cpl_msg_info (cpl_func, "Fit dispersion model");
787 
788  /* Output of all wavelenths */
789  cpl_matrix * disp_fits = cpl_matrix_new (nbase + ntel * 2, nwave);
790 
791  /* Model and right-hand-side for the lineary system (unfilled matrix are 0.0) */
792  cpl_matrix * rhs_matrix = cpl_matrix_new (nrow * nbase, 1);
793  cpl_matrix * model_matrix = cpl_matrix_new (nrow * nbase, nbase + ntel * 2);
794 
795  for (cpl_size wave = 0; wave < nwave; wave ++) {
796 
797  for (int base = 0; base < nbase; base++) {
798  int i = GRAVI_BASE_TEL[base][0];
799  int j = GRAVI_BASE_TEL[base][1];
800 
801  for (cpl_size row=0; row<nrow; row++) {
802  int id = row * nbase + base;
803  int idi = row * ntel + i;
804  int idj = row * ntel + j;
805 
806  /* Fill with unwrap phases from all the corrections
807  * PHIblt = angle(visdata) + Obl + 2pi*Abl*METbt*Abl/LBD_l
808  * 2pi*GDb/LBD_l + 2pi*beta_l*METbt/LAMBDA_MET */
809  double phi = carg (visdata[id][wave]);
810  phi += cpl_matrix_get (Obl, base, wave);
811  phi += CPL_MATH_2PI * cpl_matrix_get (Abl, base, wave) * metdata[id] / LAMBDA_MET;
812  phi += CPL_MATH_2PI * cpl_vector_get (GDb, base) / effwave[wave];
813  phi += CPL_MATH_2PI * beta[wave] * metdata[id] / LAMBDA_MET;
814  cpl_matrix_set (rhs_matrix, id, 0, phi * LAMBDA_MET / CPL_MATH_2PI);
815 
816  /* Fill the model Aij (unfilled matrix are 0.0) */
817  cpl_matrix_set (model_matrix, id, base, 1);
818 
819  /* Fill the model GAMMAi, GAMMAj */
820  double fddli = cpl_table_get (oiflux_table, "FDDL", idi, NULL);
821  double fddlj = cpl_table_get (oiflux_table, "FDDL", idj, NULL);
822  cpl_matrix_set (model_matrix, id, 6+i, fddli);
823  cpl_matrix_set (model_matrix, id, 6+j, -1*fddlj);
824 
825  /* Fill the model BETAi, BETAj */
826  double meti = cpl_table_get (oiflux_table, "OPD_MET_FC", idi, NULL);
827  double metj = cpl_table_get (oiflux_table, "OPD_MET_FC", idj, NULL);
828  cpl_matrix_set (model_matrix, id, 10+i, meti);
829  cpl_matrix_set (model_matrix, id, 10+j, -1*metj);
830  } /* End loop on rows */
831  } /* End loop on bases */
832 
833  /* Solve the system */
834  cpl_matrix * res_matrix = cpl_matrix_solve_normal (model_matrix, rhs_matrix);
835 
836  /* Save result in disp_fits */
837  for (cpl_size param = 0; param < nbase + ntel * 2; param++)
838  cpl_matrix_set (disp_fits, param, wave, cpl_matrix_get (res_matrix,param,0));
839  FREE (cpl_matrix_delete, res_matrix);
840 
841  } /* End loop on waves */
842  FREE (cpl_matrix_delete, model_matrix);
843  FREE (cpl_matrix_delete, rhs_matrix);
844 
845  /* Delete pointer to data */
846  FREE (cpl_free, visdata);
847  // FREE (cpl_table_delete, oiwavefb_table);
848 
849  /* Delete corrections */
850  FREE (cpl_vector_delete, GDb);
851  FREE (cpl_matrix_delete, Abl);
852  FREE (cpl_matrix_delete, Obl);
853 
854 
855  /* Convert the result into DISP_WAVE table,
856  * inspired from OI_WAVE */
857  cpl_table * dispwave_table = cpl_table_duplicate (oiwave_table);
858 
859  /* Add the BETA and GAMMA columns */
860  gravi_table_init_column_array (dispwave_table, "BETA", NULL, CPL_TYPE_DOUBLE, ntel);
861  gravi_table_init_column_array (dispwave_table, "GAMMA", NULL, CPL_TYPE_DOUBLE, ntel);
862 
863  /* Fill the BETA and GAMMA columns */
864  for (cpl_size tel = 0; tel < ntel; tel++) {
865  for (cpl_size wave = 0; wave < nwave; wave ++) {
866  gravi_table_set_value (dispwave_table,"BETA",wave,tel,
867  cpl_matrix_get (disp_fits, 10+tel, wave));
868  gravi_table_set_value (dispwave_table,"GAMMA",wave,tel,
869  cpl_matrix_get (disp_fits, 6+tel, wave));
870  CPLCHECK_NUL ("Cannot fill the dispwave_table");
871  }
872  }
873 
874  /* Delete the matrix */
875  FREE (cpl_matrix_delete, disp_fits);
876 
877  gravi_msg_function_exit (1);
878  return dispwave_table;
879 }
880 
881 /*----------------------------------------------------------------------------*/
896 /*----------------------------------------------------------------------------*/
897 
898 cpl_error_code gravi_compute_argon_pos (gravi_data * preproc_data, gravi_data *wave_param)
899 {
900  gravi_msg_function_start(1);
901  cpl_ensure_code (preproc_data, CPL_ERROR_NULL_INPUT);
902 
903  /* Get data */
904  cpl_table * spectrum_table = gravi_data_get_spectrum_data (preproc_data, GRAVI_SC);
905  cpl_size n_region = gravi_spectrum_get_nregion (spectrum_table);
906  cpl_size npol = gravi_spectrum_get_npol (spectrum_table);
907  cpl_size nwave = gravi_spectrum_get_nwave (spectrum_table);
908  CPLCHECK_MSG ("Cannot get data");
909 
910  /* Get the OI_WAVE */
911  gravi_msg_warning ("FIXME", "Assumes same OI_WAVE for both polar of SC");
912  cpl_table * oi_wave = gravi_data_get_oi_wave (preproc_data, GRAVI_SC, 0, npol);
913 
914  /* Ensure */
915  cpl_ensure_code (spectrum_table, CPL_ERROR_ILLEGAL_INPUT);
916  cpl_ensure_code (oi_wave, CPL_ERROR_ILLEGAL_INPUT);
917 
918  /*
919  * Compute the mean of all the spectra of the argon
920  */
921 
922  const cpl_array * array_data;
923  cpl_array * argon = cpl_array_new (nwave, CPL_TYPE_DOUBLE);
924  cpl_array_fill_window (argon, 0, nwave, 0.0);
925 
926  /* Loop region */
927  for (cpl_size region = 0; region < n_region; region ++) {
928  array_data = cpl_table_get_array (spectrum_table, GRAVI_DATA[region], 0);
929  cpl_array_add (argon, array_data);
930  }
931 
932  cpl_array_divide_scalar (argon, n_region);
933 
934  /* EKW START 07/12/2018 */
935  /*
936  * Wavelengths of the argon emission lines [m]
937  */
938 #if(0)
939  int nlines = 10;
940  double line_wave[] = {/*1.982291e-6,*/
941  1.997118e-6,
942  2.032256e-6,
943  2.062186e-6,
944  /*2.065277e-6,*/
945  /*2.073922e-6,*/
946  /*2.081672e-6,*/
947  2.099184e-6,
948  2.133871e-6,
949  2.154009e-6,
950  2.208321e-6,
951  2.313952e-6,
952  2.385154e-6,
953  2.397306e-6};
954 #endif
955 
956  double *line_wave;
957  int nlines;
958  cpl_msg_info(cpl_func,"Vor line_wave2" );
959 
960  cpl_table * line_wave_table = gravi_data_get_table (wave_param, "ARGON_TAB");
961  if ( cpl_table_has_column(line_wave_table , "ARGON_LINES") ) {
962  line_wave = cpl_table_get_data_double (line_wave_table, "ARGON_LINES");
963  nlines = cpl_table_get_nrow (line_wave_table);
964 
965  cpl_msg_info(cpl_func,"line_wave [0] : %e", line_wave[0] );
966  cpl_msg_info(cpl_func,"line_wave [1] : %e", line_wave[1] );
967  cpl_msg_info(cpl_func,"line_wave [2] : %e", line_wave[2] );
968  cpl_msg_info(cpl_func,"line_wave [3] : %e", line_wave[3] );
969  cpl_msg_info(cpl_func,"line_wave [4] : %e", line_wave[4] );
970  cpl_msg_info(cpl_func,"line_wave [5] : %e", line_wave[5] );
971  cpl_msg_info(cpl_func,"line_wave [6] : %e", line_wave[6] );
972  cpl_msg_info(cpl_func,"line_wave [7] : %e", line_wave[7] );
973  cpl_msg_info(cpl_func,"line_wave [8] : %e", line_wave[8] );
974  cpl_msg_info(cpl_func,"line_wave [9] : %e", line_wave[9] );
975  cpl_msg_info(cpl_func,"nlines : %d", nlines );
976  }
977  else {
978  cpl_msg_error(cpl_func,"Cannot get the default values for Argon line_wave");
979  }
980 
981  /* EKW END 07/12/2018 */
982  /*
983  * Fit the position of each emission line
984  */
985 
986  /* Number of pixels to fit around the line */
987  int fitwidth = nwave > 500 ? 10 : 3;
988  int nfitwidth = fitwidth * 2;
989 
990  /* Create output tables */
991  cpl_table * outTable = cpl_table_new (nlines);
992  gravi_table_new_column (outTable, "WAVE_TH", "m", CPL_TYPE_DOUBLE);
993  gravi_table_new_column (outTable, "WAVE", "m", CPL_TYPE_DOUBLE);
994  gravi_table_new_column (outTable, "SIGMA", "m", CPL_TYPE_DOUBLE);
995  gravi_table_new_column (outTable, "DIFF", "m", CPL_TYPE_DOUBLE);
996  gravi_table_new_column (outTable, "DIFF_PIX", "pix", CPL_TYPE_DOUBLE);
997  gravi_table_new_column_array (outTable, "DATA_MEAN", "adu", CPL_TYPE_DOUBLE, nfitwidth);
998 
999  /* Allocate vector to extract only sub-part of spectrum */
1000  cpl_vector * vector_x = cpl_vector_new (nfitwidth);
1001  cpl_vector * vector_y = cpl_vector_new (nfitwidth);
1002 
1003  for (cpl_size list = 0; list < nlines; list ++) {
1004 
1005  /* Expected position */
1006  double waveI = line_wave[list];
1007 
1008  /* Expected position in integer [pix] */
1009  cpl_size pixI = 0;
1010  while ( cpl_table_get (oi_wave, "EFF_WAVE", pixI, NULL) < waveI) {
1011  CPLCHECK_MSG ("Cannot get the expected position");
1012  pixI++;
1013  }
1014 
1015  /* Fill the extracted sub-vector */
1016  for (cpl_size i = 0; i < nfitwidth; i++) {
1017  cpl_size w = pixI - fitwidth + i;
1018  cpl_vector_set (vector_x, i, cpl_table_get (oi_wave, "EFF_WAVE", w, NULL));
1019  cpl_vector_set (vector_y, i, cpl_array_get (argon, w, NULL));
1020  }
1021 
1022  /* Fit Gaussian */
1023  cpl_errorstate prestate = cpl_errorstate_get();
1024  double w0 = waveI, sigma, area, offset, mse;
1025  cpl_vector_fit_gaussian (vector_x, NULL, vector_y, NULL,
1026  CPL_FIT_ALL, &w0, &sigma, &area,
1027  &offset, &mse, NULL, NULL);
1028 
1029  if (cpl_error_get_code() == CPL_ERROR_CONTINUE){
1030  cpl_errorstate_set (prestate);
1031  cpl_msg_warning(cpl_func, "The gaussian fit did not converge");
1032  cpl_vector_multiply (vector_x, vector_y);
1033  w0 = cpl_vector_get_mean (vector_x) /
1034  cpl_vector_get_mean (vector_y);
1035  sigma = 100.0;
1036  }
1037 
1038  /* compute difference in [m] and [pix] */
1039  double diff = w0 - waveI;
1040  double scale = (cpl_vector_get_max (vector_x) - cpl_vector_get_min (vector_x)) / (nfitwidth - 1);
1041  double diff_pix = diff / scale;
1042 
1043  /* Print results */
1044  cpl_msg_info (cpl_func,"Argon line %lld: %.3g [nm] %.3g [pix] (over %i)",
1045  list, 1e9*diff, diff_pix, fitwidth);
1046 
1047  /* Set the result */
1048  cpl_table_set (outTable, "WAVE_TH", list, waveI);
1049  cpl_table_set (outTable, "WAVE", list, w0);
1050  cpl_table_set (outTable, "SIGMA", list, sigma);
1051  cpl_table_set (outTable, "DIFF", list, diff);
1052  cpl_table_set (outTable, "DIFF_PIX", list, diff_pix);
1053 
1054  /* Set the extracted part of spectrum for this line */
1055  cpl_array * tmp_array = cpl_array_wrap_double (cpl_vector_get_data (vector_y), nfitwidth);
1056  cpl_table_set_array (outTable, "DATA_MEAN", list, tmp_array);
1057  FREE (cpl_array_unwrap, tmp_array);
1058 
1059  CPLCHECK_MSG ("Error during the computation");
1060  } /* End loop on list of lines */
1061 
1062  /* Delete vector extraction */
1063  FREE (cpl_vector_delete, vector_y);
1064  FREE (cpl_vector_delete, vector_x);
1065  FREE (cpl_array_delete, argon);
1066 
1067  /*
1068  * Compute RMS of difference
1069  */
1070  cpl_msg_info (cpl_func, "MIN=%e MAX=%e RMS=%e [nm]",
1071  cpl_table_get_column_min (outTable, "DIFF") * 1e9,
1072  cpl_table_get_column_max (outTable, "DIFF") * 1e9,
1073  cpl_table_get_column_stdev (outTable, "DIFF") * 1e9);
1074 
1075  /* Set the table in gravi_data */
1076  gravi_data_add_table (preproc_data, NULL, "POS_ARGON", outTable);
1077  cpl_msg_error(cpl_func,"Ekki und raus hier");
1078  gravi_msg_function_exit(1);
1079  return CPL_ERROR_NONE;
1080 }
1081 
1082 
1083 /*----------------------------------------------------------------------------*/
1084 
1085 
gravi_data * gravi_data_new(int nb_ext)
Create an empty gravi_data.
Definition: gravi_data.c:102
gravi_data * gravi_compute_disp(gravi_data *vis_data)
Compute the DISP_MODEL calibration map.
Definition: gravi_disp.c:113
cpl_error_code gravi_lkdt_get_sequence(cpl_table *oi_table, cpl_size ntel, cpl_size *first, cpl_size *nobs)
Return the longuest sequence with constant LKDT.
Definition: gravi_utils.c:1145
cpl_error_code gravi_compute_argon_pos(gravi_data *preproc_data, gravi_data *wave_param)
Compute position of argon lines in SC spectrum.
Definition: gravi_disp.c:898
cpl_table * gravi_fit_fddl_lin(cpl_table *oiflux_table)
Compute the linearity coefficient of FDDLs.
Definition: gravi_disp.c:463
cpl_error_code gravi_table_multiply_scalar(cpl_table *table, const char *name, int base, int nbase, double value)
Multiply scalar or array column by scalar.
Definition: gravi_cpl.c:2331
cpl_table * gravi_data_get_table(gravi_data *self, const char *extname)
Return a pointer on a table extension by its EXTNAME.
Definition: gravi_data.c:1716
cpl_error_code gravi_vis_erase_obs(cpl_table *oi_table, cpl_array *flag_array, cpl_size ntel)
Erase observation from an OIFITS table.
Definition: gravi_vis.c:3593
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_disp_cleanup(gravi_data *vis_data)
Cleanup a VIS gravi_data before calibrating the dispersion.
Definition: gravi_disp.c:359
cpl_table * gravi_fit_dispersion(cpl_table *oiflux_table, cpl_table *oivis_table, cpl_table *oiwave_table, double *GDrms, double *Amin, double *Amax)
Compute the dispersion coefficient of FDDLs.
Definition: gravi_disp.c:584
cpl_error_code gravi_data_add_table(gravi_data *self, cpl_propertylist *plist, const char *extname, cpl_table *table)
Add a BINTABLE extension in gravi_data.
Definition: gravi_data.c:1909