GRAVI Pipeline Reference Manual 1.9.0
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{
51 cpl_propertylist * idp_plist = cpl_propertylist_new ();
52 int nbase = 6;
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 = gravi_table_get_column_flagged_mean(oi_vis2_SC_allpol, "INT_TIME");
146 cpl_propertylist_update_double (idp_plist, qc_name, mean_int_time);
147 cpl_propertylist_set_comment (idp_plist, qc_name, "Exposure time");
148 /* This is the sum of all INT_TIME divided by the number of baselines. The mean is multiplied
149 by the number of rows and then divided by the number of polarizations since they have been
150 aggregated. Finally divided by the number of baselines as specified in PIPE-9900 */
151 if(!cpl_propertylist_has(header, "TEXPTIME"))
152 {
153 cpl_size nsets = cpl_table_get_nrow(oi_vis2_SC_allpol) / GRAVI_NBASE ;
154 double texptime = 0;
155 for (cpl_size set = 0 ; set < nsets ; set++)
156 {
157 cpl_table * int_time_this_set = cpl_table_extract(oi_vis2_SC_allpol, GRAVI_NBASE * set, GRAVI_NBASE);
158 double max_int_time = gravi_table_get_column_flagged_max(int_time_this_set, "INT_TIME");
159 texptime += max_int_time;
160 cpl_table_delete(int_time_this_set);
161 }
162
163 sprintf (qc_name, "TEXPTIME");
164 cpl_propertylist_update_double (idp_plist, qc_name, texptime);
165 cpl_propertylist_set_comment (idp_plist, qc_name, "Total exposure time");
166 }
167 else
168 {
169 cpl_propertylist_update_double (idp_plist, "TEXPTIME",
170 cpl_propertylist_get_double(header, "TEXPTIME") );
171 cpl_propertylist_set_comment (idp_plist, "TEXPTIME", "Total exposure time");
172 }
173 }
174
175 /* PRODCATG */
176 cpl_propertylist_update_string (idp_plist, "PRODCATG", "SCIENCE.VISIBILITY.UNCALIBRATED");
177 cpl_propertylist_set_comment (idp_plist, "PRODCATG", "Data product category");
178
179 /* MJD-OBS */
180 double mjd_obs_first = DBL_MAX;
181 if(frameset != NULL)
182 {
183 const cpl_frame *frame;
184 cpl_frameset * science_frames = gravi_frameset_extract_fringe_data(frameset);
185 cpl_frameset_iterator *it = cpl_frameset_iterator_new(science_frames);
186 while ((frame = cpl_frameset_iterator_get(it)) != NULL) {
187 cpl_propertylist * this_frame_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
188 double mjd_obs = gravi_pfits_get_mjd(this_frame_header);
189 if (mjd_obs < mjd_obs_first)
190 mjd_obs_first = mjd_obs;
191 cpl_frameset_iterator_advance(it, 1);
192 cpl_propertylist_delete(this_frame_header);
193 }
194 cpl_frameset_delete(science_frames);
195 cpl_frameset_iterator_delete(it);
196 }
197 if (mjd_obs_first == DBL_MAX)
198 mjd_obs_first = gravi_pfits_get_mjd(header);
199 cpl_propertylist_update_double (idp_plist, "MJD-OBS", mjd_obs_first);
200 cpl_propertylist_set_comment (idp_plist, "MJD-OBS", "Start of observation");
201
202 /* MJD-END */
203 double mjd_obs_last = 0;
204 double exptime_last = 0;
205 if(frameset != NULL)
206 {
207 const cpl_frame *frame;
208 cpl_frameset * science_frames = gravi_frameset_extract_fringe_data(frameset);
209 cpl_frameset_iterator *it = cpl_frameset_iterator_new(science_frames);
210 while ((frame = cpl_frameset_iterator_get(it)) != NULL) {
211 cpl_propertylist * this_frame_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
212 double mjd_obs = gravi_pfits_get_mjd(this_frame_header);
213 if (mjd_obs > mjd_obs_last)
214 {
215 mjd_obs_last = mjd_obs;
216 exptime_last = cpl_propertylist_get_double(this_frame_header, "EXPTIME");
217 }
218 cpl_frameset_iterator_advance(it, 1);
219 cpl_propertylist_delete(this_frame_header);
220 }
221 cpl_frameset_delete(science_frames);
222 cpl_frameset_iterator_delete(it);
223 }
224 if (mjd_obs_last == 0)
225 mjd_obs_last = gravi_pfits_get_mjd(header);
226 if (exptime_last == 0)
227 {
228 if ( cpl_propertylist_has(header, "EXPTIME") )
229 exptime_last = cpl_propertylist_get_double(header, "EXPTIME");
230 else
231 exptime_last = cpl_propertylist_get_double(idp_plist, "EXPTIME");
232 }
233
234 cpl_propertylist_update_double (idp_plist, "MJD-END",
235 mjd_obs_last + exptime_last / 86400.);
236 cpl_propertylist_set_comment (idp_plist, "MJD-END", "End of observation");
237
238 /* Delete MJD-OBS from the main header, since it will take precedence over what is computed here*/
239 cpl_propertylist_erase (header, "MJD-OBS");
240
241 /* OBID */
242 cpl_propertylist_update_int (idp_plist, "OBID1",
243 cpl_propertylist_get_int(header, "ESO OBS ID"));
244 cpl_propertylist_set_comment (idp_plist, "OBID1", "Obseration Block ID");
245
246 /* NCOMBINE */
247 if(frameset != NULL)
248 {
249 cpl_frameset * science_frames = gravi_frameset_extract_fringe_data(frameset);
250 cpl_size nscience = cpl_frameset_get_size(science_frames);
251 cpl_frameset_delete(science_frames);
252 if(!cpl_propertylist_has(header, "NCOMBINE"))
253 {
254 if (nscience != 0)
255 {
256 cpl_propertylist_update_int (idp_plist, "NCOMBINE", nscience);
257 cpl_propertylist_set_comment (idp_plist, "NCOMBINE", "Number of raw science combined");
258 }
259 }
260 else
261 {
262 cpl_propertylist_update_int (idp_plist, "NCOMBINE",
263 cpl_propertylist_get_int(header, "NCOMBINE") );
264 cpl_propertylist_set_comment (idp_plist, "NCOMBINE", "Number of raw science combined");
265 }
266 }
267 /* OBSTECH */
268 // Only create OBSTECH if it does not exist yet.
269 // This is needed for For gravity_viscal which starts from
270 // products and does not have a ESO DPR TECH anymore
271 if(cpl_propertylist_has(header, "ESO DPR TECH"))
272 {
273 cpl_propertylist_update_string (idp_plist, "OBSTECH",
274 cpl_propertylist_get_string(header, "ESO DPR TECH") );
275 cpl_propertylist_set_comment (idp_plist, "OBSTECH", "Observation technique");
276 }
277 else if(cpl_propertylist_has(header, "OBSTECH"))
278 {
279 cpl_propertylist_update_string (idp_plist, "OBSTECH",
280 cpl_propertylist_get_string(header, "OBSTECH") );
281 cpl_propertylist_set_comment (idp_plist, "OBSTECH", "Observation technique");
282 }
283
284 /* SPECSYS */
285 cpl_propertylist_update_string (idp_plist, "SPECSYS", "TOPOCENT");
286 cpl_propertylist_set_comment (idp_plist, "SPECSYS", "Frame of reference for spectral coordinates");
287
288 /* TIMESYS */
289 cpl_propertylist_update_string (idp_plist, "TIMESYS", "UTC");
290 cpl_propertylist_set_comment (idp_plist, "TIMESYS", "Time system");
291
292 /* SPEC_ERR */
293 /* According to https://jira.eso.org/browse/PIPE-9900 this
294 is hard-coded depending on resolution */
295 double spec_err = 0;
296 const char * resolution = gravi_pfits_get_resolution (header);
297 if ( !strcmp (resolution, "HIGH") )
298 spec_err = 0.28;
299 if ( !strcmp (resolution, "MED") )
300 spec_err = 2.2;
301 if ( !strcmp (resolution, "LOW") )
302 spec_err = 50;
303 cpl_propertylist_update_double (idp_plist, "SPEC_ERR", spec_err);
304 cpl_propertylist_set_comment (idp_plist, "SPEC_ERR", "Statistical error in spectral coordinate");
305
306 /* SPEC_SYE */
307 /* Hard-coded to the values in Sanchez-Bermudez et al. 2017 */
308 cpl_propertylist_update_double (idp_plist, "SPEC_SYE", 0.1);
309 cpl_propertylist_set_comment (idp_plist, "SPEC_SYE", "Systematic error in spectral coordinate");
310
311 /* PROV keywords */
312 if(frameset != NULL)
313 {
314 const cpl_frame *frame;
315 size_t i_prov = 1;
316 char prov_keyword[8];
317 cpl_frameset_iterator *it = cpl_frameset_iterator_new(frameset);
318 while ((frame = cpl_frameset_iterator_get(it)) != NULL) {
319 if (strcmp(cpl_frame_get_tag(frame), GRAVI_SINGLE_SCIENCE_RAW) == 0 ||
320 strcmp(cpl_frame_get_tag(frame), GRAVI_DUAL_SCIENCE_RAW) == 0)
321 {
322 snprintf(prov_keyword, 7, "PROV%zu",i_prov);
323 const char * filename = cpl_frame_get_filename(frame);
324 const char * filename_no_path = strrchr(filename, '/');
325 if (filename_no_path == NULL)
326 filename_no_path = filename;
327 else
328 filename_no_path += 1;
329 cpl_propertylist_update_string(idp_plist, prov_keyword, filename_no_path);
330 i_prov++;
331 }
332 cpl_frameset_iterator_advance(it, 1);
333 }
334 cpl_frameset_iterator_delete(it);
335 }
336
338 {
339 cpl_table * oi_array = gravi_data_get_table (vis_data, GRAVI_OI_ARRAY_EXT);
340 if(!cpl_table_has_column(oi_array, "FOV"))
341 {
342 cpl_table_new_column(oi_array, "FOV", CPL_TYPE_DOUBLE);
343 cpl_table_new_column(oi_array, "FOVTYPE", CPL_TYPE_STRING);
344 double fov;
345 const char * telname = gravi_conf_get_telname (0, header);
346 if (telname == NULL) {
347 cpl_msg_warning(cpl_func, "Cannot get TELNAME, FOV is not determined");
348 fov = 0.0;
349 } else {
350 if (telname[0] == 'U')
351 fov = 0.03; // Hard-coded UT FOV
352 else
353 fov = 0.14; // Hard-coded AT FOV
354 }
355
356 cpl_table_fill_column_window_double(oi_array, "FOV", 0, cpl_table_get_nrow(oi_array), fov);
357 cpl_table_fill_column_window_string(oi_array, "FOVTYPE", 0, cpl_table_get_nrow(oi_array),"RADIUS");
358 }
359 }
360
361 /* Delete scratch tables */
362 cpl_table_delete(oi_vis2_SC_allpol);
363 cpl_table_delete(oi_T3_SC_allpol);
364 cpl_table_delete(oi_wave_SC_allpol);
365
366 return idp_plist;
367}
368
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_DUAL_SCIENCE_RAW
Definition: gravi_dfs.h:54
cpl_propertylist * gravi_idp_compute(gravi_data *vis_data, cpl_propertylist *header, cpl_frameset *frameset)
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:1323
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:2509