GRAVI Pipeline Reference Manual 1.7.2
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 == 0)
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 /* Delete MJD-OBS from the main header, since it will take precedence over what is computed here*/
202 cpl_propertylist_erase (header, "MJD-OBS");
203
204 /* MJD-END */
205 double mjd_obs_last = 0;
206 double exptime_last = 0;
207 if(frameset != NULL)
208 {
209 const cpl_frame *frame;
210 cpl_frameset * science_frames = gravi_frameset_extract_fringe_data(frameset);
211 cpl_frameset_iterator *it = cpl_frameset_iterator_new(science_frames);
212 while ((frame = cpl_frameset_iterator_get(it)) != NULL) {
213 cpl_propertylist * this_frame_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
214 double mjd_obs = gravi_pfits_get_mjd(this_frame_header);
215 if (mjd_obs > mjd_obs_last)
216 {
217 mjd_obs_last = mjd_obs;
218 exptime_last = cpl_propertylist_get_double(this_frame_header, "EXPTIME");
219 }
220 cpl_frameset_iterator_advance(it, 1);
221 cpl_propertylist_delete(this_frame_header);
222 }
223 cpl_frameset_delete(science_frames);
224 cpl_frameset_iterator_delete(it);
225 }
226 if (mjd_obs_last == 0)
227 mjd_obs_last = gravi_pfits_get_mjd(header);
228 if (exptime_last == 0)
229 {
230 if ( cpl_propertylist_has(header, "EXPTIME") )
231 exptime_last = cpl_propertylist_get_double(header, "EXPTIME");
232 else
233 exptime_last = cpl_propertylist_get_double(idp_plist, "EXPTIME");
234 }
235
236 cpl_propertylist_update_double (idp_plist, "MJD-END",
237 mjd_obs_last + exptime_last / 86400.);
238 cpl_propertylist_set_comment (idp_plist, "MJD-END", "End of observation");
239
240 /* OBID */
241 cpl_propertylist_update_int (idp_plist, "OBID1",
242 cpl_propertylist_get_int(header, "ESO OBS ID"));
243 cpl_propertylist_set_comment (idp_plist, "OBID1", "Obseration Block ID");
244
245 /* NCOMBINE */
246 if(frameset != NULL)
247 {
248 cpl_frameset * science_frames = gravi_frameset_extract_fringe_data(frameset);
249 cpl_size nscience = cpl_frameset_get_size(science_frames);
250 cpl_frameset_delete(science_frames);
251 if(!cpl_propertylist_has(header, "NCOMBINE"))
252 {
253 if (nscience != 0)
254 {
255 cpl_propertylist_update_int (idp_plist, "NCOMBINE", nscience);
256 cpl_propertylist_set_comment (idp_plist, "NCOMBINE", "Number of raw science combined");
257 }
258 }
259 else
260 {
261 cpl_propertylist_update_int (idp_plist, "NCOMBINE",
262 cpl_propertylist_get_int(header, "NCOMBINE") );
263 cpl_propertylist_set_comment (idp_plist, "NCOMBINE", "Number of raw science combined");
264 }
265 }
266 /* OBSTECH */
267 // Only create OBSTECH if it does not exist yet.
268 // This is needed for For gravity_viscal which starts from
269 // products and does not have a ESO DPR TECH anymore
270 if(cpl_propertylist_has(header, "ESO DPR TECH"))
271 {
272 cpl_propertylist_update_string (idp_plist, "OBSTECH",
273 cpl_propertylist_get_string(header, "ESO DPR TECH") );
274 cpl_propertylist_set_comment (idp_plist, "OBSTECH", "Observation technique");
275 }
276 else if(cpl_propertylist_has(header, "OBSTECH"))
277 {
278 cpl_propertylist_update_string (idp_plist, "OBSTECH",
279 cpl_propertylist_get_string(header, "OBSTECH") );
280 cpl_propertylist_set_comment (idp_plist, "OBSTECH", "Observation technique");
281 }
282
283 /* SPECSYS */
284 cpl_propertylist_update_string (idp_plist, "SPECSYS", "TOPOCENT");
285 cpl_propertylist_set_comment (idp_plist, "SPECSYS", "Frame of reference for spectral coordinates");
286
287 /* TIMESYS */
288 cpl_propertylist_update_string (idp_plist, "TIMESYS", "UTC");
289 cpl_propertylist_set_comment (idp_plist, "TIMESYS", "Time system");
290
291 /* SPEC_ERR */
292 /* According to https://jira.eso.org/browse/PIPE-9900 this
293 is hard-coded depending on resolution */
294 double spec_err = 0;
295 const char * resolution = gravi_pfits_get_resolution (header);
296 if ( !strcmp (resolution, "HIGH") )
297 spec_err = 0.28;
298 if ( !strcmp (resolution, "MED") )
299 spec_err = 2.2;
300 if ( !strcmp (resolution, "LOW") )
301 spec_err = 50;
302 cpl_propertylist_update_double (idp_plist, "SPEC_ERR", spec_err);
303 cpl_propertylist_set_comment (idp_plist, "SPEC_ERR", "Statistical error in spectral coordinate");
304
305 /* SPEC_SYE */
306 /* Hard-coded to the values in Sanchez-Bermudez et al. 2017 */
307 cpl_propertylist_update_double (idp_plist, "SPEC_SYE", 0.1);
308 cpl_propertylist_set_comment (idp_plist, "SPEC_SYE", "Systematic error in spectral coordinate");
309
310 /* PROV keywords */
311 if(frameset != NULL)
312 {
313 const cpl_frame *frame;
314 size_t i_prov = 1;
315 char prov_keyword[8];
316 cpl_frameset_iterator *it = cpl_frameset_iterator_new(frameset);
317 while ((frame = cpl_frameset_iterator_get(it)) != NULL) {
318 if (strcmp(cpl_frame_get_tag(frame), GRAVI_SINGLE_SCIENCE_RAW) == 0 ||
319 strcmp(cpl_frame_get_tag(frame), GRAVI_DUAL_SCIENCE_RAW) == 0)
320 {
321 snprintf(prov_keyword, 7, "PROV%zu",i_prov);
322 const char * filename = cpl_frame_get_filename(frame);
323 const char * filename_no_path = strrchr(filename, '/');
324 if (filename_no_path == NULL)
325 filename_no_path = filename;
326 else
327 filename_no_path += 1;
328 cpl_propertylist_update_string(idp_plist, prov_keyword, filename_no_path);
329 i_prov++;
330 }
331 cpl_frameset_iterator_advance(it, 1);
332 }
333 cpl_frameset_iterator_delete(it);
334 }
335
337 {
338 cpl_table * oi_array = gravi_data_get_table (vis_data, GRAVI_OI_ARRAY_EXT);
339 cpl_table_new_column(oi_array, "FOV", CPL_TYPE_DOUBLE);
340 cpl_table_new_column(oi_array, "FOVTYPE", CPL_TYPE_STRING);
341 double fov;
342 const char * telname = gravi_conf_get_telname (0, header);
343 if (telname[0] == 'U')
344 fov = 0.03; // Hard-coded UT FOV
345 else
346 fov = 0.14; // Hard-coded AT FOV
347
348 cpl_table_fill_column_window_double(oi_array, "FOV", 0, cpl_table_get_nrow(oi_array), fov);
349 cpl_table_fill_column_window_string(oi_array, "FOVTYPE", 0, cpl_table_get_nrow(oi_array),"RADIUS");
350 }
351
352 /* Delete scratch tables */
353 cpl_table_delete(oi_vis2_SC_allpol);
354 cpl_table_delete(oi_T3_SC_allpol);
355 cpl_table_delete(oi_wave_SC_allpol);
356
357 return idp_plist;
358}
359
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