GRAVI Pipeline Reference Manual 1.9.6
Loading...
Searching...
No Matches
gravi_idp.c
Go to the documentation of this file.
1/*
2 * This file is part of the GRAVI Pipeline
3 * Copyright (C) 2022 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*-----------------------------------------------------------------------------
21 Includes
22 -----------------------------------------------------------------------------*/
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <math.h>
29#include <string.h>
30#include "gravi_utils.h"
31#include "gravi_idp.h"
32#include "gravi_pfits.h"
33#include "gravi_dfs.h"
34#include "gravi_cpl.h"
35#include "gravi_vis.h"
36
37/*-----------------------------------------------------------------------------*/
46/*-----------------------------------------------------------------------------*/
47cpl_propertylist * gravi_idp_compute (gravi_data * vis_data,
48 cpl_propertylist * header,
49 cpl_frameset * frameset,
50 char * input_data_type)
51{
52 cpl_propertylist * idp_plist = cpl_propertylist_new ();
53
55 char qc_name[100];
56
57 /* Scratch tables to merge polarization tables */
58 cpl_table * oi_vis2_SC_allpol = NULL;
59 cpl_table * oi_T3_SC_allpol = NULL;
60 cpl_table * oi_wave_SC_allpol = NULL;
61
62 /* There are products like the p2vmred that do not have all columns */
64 {
65 double vis2err = 0;
66 double visphierr = 0;
67 double t3phierr = 0;
68 oi_vis2_SC_allpol = cpl_table_duplicate(gravi_data_get_oi_vis2 (vis_data, GRAVI_SC, 0, npol_sc));
69 oi_T3_SC_allpol = cpl_table_duplicate(gravi_data_get_oi_t3 (vis_data, GRAVI_SC, 0, npol_sc));
70 oi_wave_SC_allpol = cpl_table_duplicate(gravi_data_get_oi_wave (vis_data, GRAVI_SC, 0, npol_sc));
71 for (int pol = 1; pol < npol_sc; pol++) {
72 cpl_table_insert(oi_vis2_SC_allpol, gravi_data_get_oi_vis2 (vis_data, GRAVI_SC, pol, npol_sc), cpl_table_get_nrow(oi_vis2_SC_allpol));
73 cpl_table_insert(oi_T3_SC_allpol, gravi_data_get_oi_t3 (vis_data, GRAVI_SC, pol, npol_sc), cpl_table_get_nrow(oi_T3_SC_allpol));
74 cpl_table_insert(oi_wave_SC_allpol, gravi_data_get_oi_wave (vis_data, GRAVI_SC, pol, npol_sc), cpl_table_get_nrow(oi_wave_SC_allpol));
75 }
76
77 for (int pol = 0; pol < npol_sc; pol++) {
78 double this_pol_vis2err = gravi_table_get_column_flagged_mean(gravi_data_get_oi_vis2 (vis_data, GRAVI_SC, pol, npol_sc), "VIS2ERR");
79 vis2err += this_pol_vis2err * this_pol_vis2err;
80 double this_pol_visphierr = gravi_table_get_column_flagged_mean(gravi_data_get_oi_vis (vis_data, GRAVI_SC, pol, npol_sc), "VISPHIERR");
81 visphierr += this_pol_visphierr * this_pol_visphierr;
82 double this_pol_t3phierr = gravi_table_get_column_flagged_mean(gravi_data_get_oi_t3 (vis_data, GRAVI_SC, pol, npol_sc), "T3PHIERR");
83 t3phierr += this_pol_t3phierr * this_pol_t3phierr;
84 }
85
86 /* Compute QC values that aggregate on polarizations */
87 sprintf (qc_name, "VIS2ERR");
88 cpl_propertylist_update_double (idp_plist, qc_name, sqrt(vis2err));
89 cpl_propertylist_set_comment (idp_plist, qc_name, "Representative squared visibility error [%]");
90
91 sprintf (qc_name, "VISPHERR");
92 cpl_propertylist_update_double (idp_plist, qc_name, sqrt(visphierr));
93 cpl_propertylist_set_comment (idp_plist, qc_name, "Representative visibility phase error [%]");
94
95 sprintf (qc_name, "T3PHIERR");
96 cpl_propertylist_update_double (idp_plist, qc_name, sqrt(t3phierr));
97 cpl_propertylist_set_comment (idp_plist, qc_name, "Representative closure phase error [deg]");
98
99 double min_uvcoord, max_uvcoord;
100 gravi_data_get_minmax_uvcoord(oi_vis2_SC_allpol, &min_uvcoord, &max_uvcoord);
101
102 double min_eff_wave = cpl_table_get_column_min(oi_wave_SC_allpol, "EFF_WAVE");
103 double max_eff_wave = cpl_table_get_column_max(oi_wave_SC_allpol, "EFF_WAVE");
104
105 double base_max = max_uvcoord / min_eff_wave;
106 double base_min = min_uvcoord / max_eff_wave;
107 if(isnan(base_max) || isinf(base_max))
108 base_max = 0;
109 if(isnan(base_min) || isinf(base_min))
110 base_min = 0;
111
112 sprintf (qc_name, "BASE_MAX");
113 cpl_propertylist_update_double (idp_plist, qc_name, base_max);
114 cpl_propertylist_set_comment (idp_plist, qc_name, "Maximum baseline / Minimum effective wavelenth");
115
116 sprintf (qc_name, "BASE_MIN");
117 cpl_propertylist_update_double (idp_plist, qc_name, base_min);
118 cpl_propertylist_set_comment (idp_plist, qc_name, "Minimum baseline / Maximum effective wavelenth");
119
120 /* The rows in oi_wave_SC_allpol contain each wavelenght npol_sc times,
121 since it has been aggregated. Therefore dividing by npol_sc times */
122 sprintf (qc_name, "NUM_CHAN");
123 cpl_propertylist_update_int (idp_plist, qc_name, cpl_table_get_nrow(oi_wave_SC_allpol) / npol_sc );
124 cpl_propertylist_set_comment (idp_plist, qc_name, "Number of wavelength channels");
125
126 sprintf (qc_name, "WAVELMAX");
127 double avg_band = cpl_table_get_column_mean(oi_wave_SC_allpol, "EFF_BAND");
128 cpl_propertylist_update_double (idp_plist, qc_name, (max_eff_wave + avg_band / 2.) * 1e9);
129 cpl_propertylist_set_comment (idp_plist, qc_name, "[nm] Maximum wavelength");
130
131 sprintf (qc_name, "WAVELMIN");
132 cpl_propertylist_update_double (idp_plist, qc_name, (min_eff_wave - avg_band / 2.) * 1e9);
133 cpl_propertylist_set_comment (idp_plist, qc_name, "[nm] Minimum wavelength");
134
135 cpl_table_duplicate_column(oi_wave_SC_allpol, "SPEC_RES", oi_wave_SC_allpol, "EFF_WAVE");
136 cpl_table_divide_columns(oi_wave_SC_allpol,"SPEC_RES", "EFF_BAND");
137
138 sprintf (qc_name, "SPEC_RES");
139 cpl_propertylist_update_double (idp_plist, qc_name, cpl_table_get_column_mean(oi_wave_SC_allpol, "SPEC_RES"));
140 cpl_propertylist_set_comment (idp_plist, qc_name, "Spectral resolution");
141
142 /* This is the mean INT_TIME, which includes duplicated entries due to the several polarizations.
143 Since it is a mean, the final value should be the same */
144 sprintf (qc_name, "EXPTIME");
145 double mean_int_time = 0.0;
146 cpl_size valid_elem = 0;
147 cpl_size nrow = cpl_table_get_nrow (oi_vis2_SC_allpol);
148 double * inttime = cpl_table_get_data_double (oi_vis2_SC_allpol, "INT_TIME");
149 for (cpl_size r=0; r<nrow;r++)
150 {
151 if (inttime[r])
152 {
153 mean_int_time += inttime[r];
154 valid_elem++;
155 }
156 }
157
158 if(valid_elem)
159 mean_int_time = mean_int_time / valid_elem;
160 cpl_propertylist_update_double (idp_plist, qc_name, mean_int_time);
161 cpl_propertylist_set_comment (idp_plist, qc_name, "Exposure time");
162 /* This is the sum of all INT_TIME divided by the number of baselines. The mean is multiplied
163 by the number of rows and then divided by the number of polarizations since they have been
164 aggregated. Finally divided by the number of baselines as specified in PIPE-9900 */
165 if(!cpl_propertylist_has(header, "TEXPTIME"))
166 {
167 double texptime = 0;
168 for (int pol = 0; pol < npol_sc; pol++) {
169 cpl_table * this_pol_table = gravi_data_get_oi_vis2 (vis_data, GRAVI_SC, pol, npol_sc);
170 double this_pol_texptime = 0;
171 cpl_size nsets = cpl_table_get_nrow(this_pol_table) / GRAVI_NBASE ;
172 for (cpl_size set = 0 ; set < nsets ; set++)
173 {
174 cpl_table * int_time_this_set = cpl_table_extract(this_pol_table, GRAVI_NBASE * set, GRAVI_NBASE);
175 double max_int_time = gravi_table_get_column_flagged_max(int_time_this_set, "INT_TIME");
176 this_pol_texptime += max_int_time;
177 cpl_table_delete(int_time_this_set);
178 }
179 texptime = fmax(texptime, this_pol_texptime);
180 }
181
182 sprintf (qc_name, "TEXPTIME");
183 cpl_propertylist_update_double (idp_plist, qc_name, texptime);
184 cpl_propertylist_set_comment (idp_plist, qc_name, "Total exposure time");
185 }
186 else
187 {
188 cpl_propertylist_update_double (idp_plist, "TEXPTIME",
189 cpl_propertylist_get_double(header, "TEXPTIME") );
190 cpl_propertylist_set_comment (idp_plist, "TEXPTIME", "Total exposure time");
191 }
192 }
193
194 /* PRODCATG */
195 cpl_propertylist_update_string (idp_plist, "PRODCATG", "SCIENCE.VISIBILITY");
196 cpl_propertylist_set_comment (idp_plist, "PRODCATG", "Data product category");
197
198 /* VISCAL */
199 if(input_data_type != NULL)
200 {
201 if(strcmp(input_data_type, "raw_science") == 0 || strcmp(input_data_type, "raw_calibrator") == 0 )
202 {
203 cpl_propertylist_update_string (idp_plist, "VISCAL", "UNCALIBRATED");
204 cpl_propertylist_set_comment (idp_plist, "VISCAL", "Type of visibilities");
205 }
206 if(strcmp(input_data_type, "vis_science") == 0 || strcmp(input_data_type, "vis_calibrator") == 0 )
207 {
208 cpl_propertylist_update_string (idp_plist, "VISCAL", "CALIBRATED");
209 cpl_propertylist_set_comment (idp_plist, "VISCAL", "Type of visibilities");
210 }
211 }
212
213 /* MJD-OBS */
214 double mjd_obs_first = DBL_MAX;
215 if(frameset != NULL)
216 {
217 const cpl_frame *frame;
218 cpl_frameset * science_frames = gravi_frameset_extract_fringe_data(frameset);
219 cpl_frameset_iterator *it = cpl_frameset_iterator_new(science_frames);
220 while ((frame = cpl_frameset_iterator_get(it)) != NULL) {
221 cpl_propertylist * this_frame_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
222 double mjd_obs = gravi_pfits_get_mjd(this_frame_header);
223 if (mjd_obs < mjd_obs_first)
224 mjd_obs_first = mjd_obs;
225 cpl_frameset_iterator_advance(it, 1);
226 cpl_propertylist_delete(this_frame_header);
227 }
228 cpl_frameset_delete(science_frames);
229 cpl_frameset_iterator_delete(it);
230 }
231 if (mjd_obs_first == DBL_MAX)
232 mjd_obs_first = gravi_pfits_get_mjd(header);
233 cpl_propertylist_update_double (idp_plist, "MJD-OBS", mjd_obs_first);
234 cpl_propertylist_set_comment (idp_plist, "MJD-OBS", "Start of observation");
235
236 /* MJD-END */
237 double mjd_obs_last = 0;
238 double exptime_last = 0;
239 if(frameset != NULL)
240 {
241 const cpl_frame *frame;
242 cpl_frameset * science_frames = gravi_frameset_extract_fringe_data(frameset);
243 cpl_frameset_iterator *it = cpl_frameset_iterator_new(science_frames);
244 while ((frame = cpl_frameset_iterator_get(it)) != NULL) {
245 cpl_propertylist * this_frame_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
246 double mjd_obs = gravi_pfits_get_mjd(this_frame_header);
247 if (mjd_obs > mjd_obs_last)
248 {
249 mjd_obs_last = mjd_obs;
250 exptime_last = cpl_propertylist_get_double(this_frame_header, "EXPTIME");
251 }
252 cpl_frameset_iterator_advance(it, 1);
253 cpl_propertylist_delete(this_frame_header);
254 }
255 cpl_frameset_delete(science_frames);
256 cpl_frameset_iterator_delete(it);
257 }
258 if (mjd_obs_last == 0)
259 mjd_obs_last = gravi_pfits_get_mjd(header);
260 if (exptime_last == 0)
261 {
262 if ( cpl_propertylist_has(header, "EXPTIME") )
263 exptime_last = cpl_propertylist_get_double(header, "EXPTIME");
264 else
265 exptime_last = cpl_propertylist_get_double(idp_plist, "EXPTIME");
266 }
267
268 cpl_propertylist_update_double (idp_plist, "MJD-END",
269 mjd_obs_last + exptime_last / 86400.);
270 cpl_propertylist_set_comment (idp_plist, "MJD-END", "End of observation");
271
272 /* Delete MJD-OBS from the main header, since it will take precedence over what is computed here*/
273 cpl_propertylist_erase (header, "MJD-OBS");
274
275 /* OBID */
276 cpl_propertylist_update_int (idp_plist, "OBID1",
277 cpl_propertylist_get_int(header, "ESO OBS ID"));
278 cpl_propertylist_set_comment (idp_plist, "OBID1", "Obseration Block ID");
279
280 /* NCOMBINE */
281 if(frameset != NULL)
282 {
283 cpl_frameset * science_frames = gravi_frameset_extract_fringe_data(frameset);
284 cpl_size nscience = cpl_frameset_get_size(science_frames);
285 cpl_frameset_delete(science_frames);
286 if(!cpl_propertylist_has(header, "NCOMBINE"))
287 {
288 if (nscience != 0)
289 {
290 cpl_propertylist_update_int (idp_plist, "NCOMBINE", nscience);
291 cpl_propertylist_set_comment (idp_plist, "NCOMBINE", "Number of raw science combined");
292 }
293 }
294 else
295 {
296 cpl_propertylist_update_int (idp_plist, "NCOMBINE",
297 cpl_propertylist_get_int(header, "NCOMBINE") );
298 cpl_propertylist_set_comment (idp_plist, "NCOMBINE", "Number of raw science combined");
299 }
300 }
301 /* OBSTECH */
302 // Only create OBSTECH if it does not exist yet.
303 // This is needed for For gravity_viscal which starts from
304 // products and does not have a ESO DPR TECH anymore
305 if(cpl_propertylist_has(header, "ESO DPR TECH"))
306 {
307 cpl_propertylist_update_string (idp_plist, "OBSTECH",
308 cpl_propertylist_get_string(header, "ESO DPR TECH") );
309 cpl_propertylist_set_comment (idp_plist, "OBSTECH", "Observation technique");
310 }
311 else if(cpl_propertylist_has(header, "OBSTECH"))
312 {
313 cpl_propertylist_update_string (idp_plist, "OBSTECH",
314 cpl_propertylist_get_string(header, "OBSTECH") );
315 cpl_propertylist_set_comment (idp_plist, "OBSTECH", "Observation technique");
316 }
317
318 /* SPECSYS */
319 cpl_propertylist_update_string (idp_plist, "SPECSYS", "TOPOCENT");
320 cpl_propertylist_set_comment (idp_plist, "SPECSYS", "Frame of reference for spectral coordinates");
321
322 /* TIMESYS */
323 cpl_propertylist_update_string (idp_plist, "TIMESYS", "UTC");
324 cpl_propertylist_set_comment (idp_plist, "TIMESYS", "Time system");
325
326 /* SPEC_ERR */
327 /* According to https://jira.eso.org/browse/PIPE-9900 this
328 is hard-coded depending on resolution */
329 double spec_err = 0;
330 const char * resolution = gravi_pfits_get_resolution (header);
331 if ( !strcmp (resolution, "HIGH") )
332 spec_err = 0.28;
333 if ( !strcmp (resolution, "MED") )
334 spec_err = 2.2;
335 if ( !strcmp (resolution, "LOW") )
336 spec_err = 50;
337 cpl_propertylist_update_double (idp_plist, "SPEC_ERR", spec_err);
338 cpl_propertylist_set_comment (idp_plist, "SPEC_ERR", "Statistical error in spectral coordinate");
339
340 /* SPEC_SYE */
341 /* Hard-coded to the values in Sanchez-Bermudez et al. 2017 */
342 cpl_propertylist_update_double (idp_plist, "SPEC_SYE", 0.1);
343 cpl_propertylist_set_comment (idp_plist, "SPEC_SYE", "Systematic error in spectral coordinate");
344
345 /* PROV keywords */
346 if(frameset != NULL)
347 {
348 const cpl_frame *frame;
349 size_t i_prov = 1;
350 char prov_keyword[8];
351 cpl_frameset_iterator *it = cpl_frameset_iterator_new(frameset);
352 while ((frame = cpl_frameset_iterator_get(it)) != NULL) {
353 if (strcmp(cpl_frame_get_tag(frame), GRAVI_SINGLE_SCIENCE_RAW) == 0 ||
354 strcmp(cpl_frame_get_tag(frame), GRAVI_DUAL_SCIENCE_RAW) == 0 ||
355 strcmp(cpl_frame_get_tag(frame), GRAVI_SINGLE_CALIB_RAW) == 0 ||
356 strcmp(cpl_frame_get_tag(frame), GRAVI_DUAL_CALIB_RAW) == 0 ||
357 strcmp(cpl_frame_get_tag(frame), GRAVI_VIS_DUAL_SCIENCE) == 0 ||
358 strcmp(cpl_frame_get_tag(frame), GRAVI_VIS_SINGLE_SCIENCE) == 0)
359 {
360 snprintf(prov_keyword, 7, "PROV%zu",i_prov);
361 const char * filename = cpl_frame_get_filename(frame);
362 const char * filename_no_path = strrchr(filename, '/');
363 if (filename_no_path == NULL)
364 filename_no_path = filename;
365 else
366 filename_no_path += 1;
367 cpl_propertylist_update_string(idp_plist, prov_keyword, filename_no_path);
368 i_prov++;
369 }
370 cpl_frameset_iterator_advance(it, 1);
371 }
372 cpl_frameset_iterator_delete(it);
373 }
374
376 {
377 cpl_table * oi_array = gravi_data_get_table (vis_data, GRAVI_OI_ARRAY_EXT);
378 if(!cpl_table_has_column(oi_array, "FOV"))
379 {
380 cpl_table_new_column(oi_array, "FOV", CPL_TYPE_DOUBLE);
381 cpl_table_new_column(oi_array, "FOVTYPE", CPL_TYPE_STRING);
382 double fov;
383 const char * telname = gravi_conf_get_telname (0, header);
384 if (telname == NULL) {
385 cpl_msg_warning(cpl_func, "Cannot get TELNAME, FOV is not determined");
386 fov = 0.0;
387 } else {
388 if (telname[0] == 'U')
389 fov = 0.0285; // Hard-coded UT FOV
390 else
391 fov = 0.126; // Hard-coded AT FOV
392 }
393
394 cpl_table_fill_column_window_double(oi_array, "FOV", 0, cpl_table_get_nrow(oi_array), fov);
395 cpl_table_fill_column_window_string(oi_array, "FOVTYPE", 0, cpl_table_get_nrow(oi_array),"RADIUS");
396 cpl_table_set_column_unit(oi_array, "FOV", "arcsec");
397 }
398 }
399
400 /* Delete scratch tables */
401 cpl_table_delete(oi_vis2_SC_allpol);
402 cpl_table_delete(oi_T3_SC_allpol);
403 cpl_table_delete(oi_wave_SC_allpol);
404
405 return idp_plist;
406}
407
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_vis2(data, type, pol, npol)
Definition: gravi_data.h:47
#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
#define GRAVI_SINGLE_SCIENCE_RAW
Definition: gravi_dfs.h:52
#define GRAVI_VIS_DUAL_SCIENCE
Definition: gravi_dfs.h:98
#define GRAVI_VIS_SINGLE_SCIENCE
Definition: gravi_dfs.h:96
#define GRAVI_DUAL_CALIB_RAW
Definition: gravi_dfs.h:53
#define GRAVI_SINGLE_CALIB_RAW
Definition: gravi_dfs.h:51
#define GRAVI_DUAL_SCIENCE_RAW
Definition: gravi_dfs.h:54
cpl_propertylist * gravi_idp_compute(gravi_data *vis_data, cpl_propertylist *header, cpl_frameset *frameset, char *input_data_type)
Create IDP keywords to satisfy standard.
Definition: gravi_idp.c:47
cpl_propertylist * header
Definition: gravi_old.c:2004
cpl_propertylist_update_double(header, "ESO QC MINWAVE SC", cpl_propertylist_get_double(plist, "ESO QC MINWAVE SC"))
#define GRAVI_OI_VIS2_EXT
Definition: gravi_pfits.h:95
#define GRAVI_OI_ARRAY_EXT
Definition: gravi_pfits.h:83
#define GRAVI_SC
Definition: gravi_pfits.h:165
#define GRAVI_NBASE
Definition: gravi_utils.h:105
double gravi_table_get_column_flagged_mean(cpl_table *table, const char *name)
Function to compute the mean of a column table with arrays.
Definition: gravi_cpl.c:217
double gravi_table_get_column_flagged_max(cpl_table *table, const char *name)
Function to compute the maximum of a column table with arrays.
Definition: gravi_cpl.c:290
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
cpl_table * gravi_data_get_table(gravi_data *self, const char *extname)
Return a pointer on a table extension by its EXTNAME.
Definition: gravi_data.c:2096
cpl_frameset * gravi_frameset_extract_fringe_data(cpl_frameset *frameset)
Definition: gravi_dfs.c:1320
int gravi_pfits_get_pola_num(const cpl_propertylist *plist, int type_data)
Definition: gravi_pfits.c:263
double gravi_pfits_get_mjd(const cpl_propertylist *plist)
Definition: gravi_pfits.c:526
const char * gravi_pfits_get_resolution(const cpl_propertylist *plist)
Definition: gravi_pfits.c:155
const char * gravi_conf_get_telname(int gravi_beam, cpl_propertylist *header)
Definition: gravi_utils.c:1191
cpl_error_code gravi_data_get_minmax_uvcoord(const cpl_table *oi_vis2, double *min_uvcoord, double *max_uvcoord)
Compute the minimum and maximum values of sqrt(ucoord**2 + vcoord**2)
Definition: gravi_vis.c:2541