46static int gravity_pcacal(cpl_frameset *,
const cpl_parameterlist *);
51static char gravity_pcacal_short[] =
"Generate static calibration files for flattening phase visibility data using the PCA method.";
53"This recipe produces a PCA calibration file from a set of calibration frames to be used for flattening phase visibility data.\n"
55 "* Select good input frames using tracking ratio criterion.\n"
56 "* Compute PCA decomposition for each baseline and polarisation channel\n"
57 "* Fit component model and write calibration product\n"
92 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe);
93 cpl_plugin *plugin = &recipe->interface;
95 if (cpl_plugin_init(plugin,
98 CPL_PLUGIN_TYPE_RECIPE,
102 "Calvin Sykes, Shangguan Jinyi, Sebastian Hoenig",
109 cpl_msg_error(cpl_func,
"Plugin initialization failed");
110 (void)cpl_error_set_where(cpl_func);
114 if (cpl_pluginlist_append(list, plugin)) {
115 cpl_msg_error(cpl_func,
"Error adding plugin to list");
116 (void)cpl_error_set_where(cpl_func);
137 if (cpl_error_get_code() != CPL_ERROR_NONE) {
138 cpl_msg_error(cpl_func,
"%s():%d: An error is already set: %s",
139 cpl_func, __LINE__, cpl_error_get_where());
140 return (
int)cpl_error_get_code();
143 if (plugin == NULL) {
144 cpl_msg_error(cpl_func,
"Null plugin");
145 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
149 if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
150 cpl_msg_error(cpl_func,
"Plugin is not a recipe");
151 cpl_ensure_code(0, (
int)CPL_ERROR_TYPE_MISMATCH);
155 recipe = (cpl_recipe *)plugin;
158 recipe->parameters = cpl_parameterlist_new();
159 if (recipe->parameters == NULL) {
160 cpl_msg_error(cpl_func,
"Parameter list allocation failed");
161 cpl_ensure_code(0, (
int)CPL_ERROR_ILLEGAL_OUTPUT);
187 cpl_errorstate initial_errorstate = cpl_errorstate_get();
190 if (cpl_error_get_code() != CPL_ERROR_NONE) {
191 cpl_msg_error(cpl_func,
"%s():%d: An error is already set: %s",
192 cpl_func, __LINE__, cpl_error_get_where());
193 return (
int)cpl_error_get_code();
196 if (plugin == NULL) {
197 cpl_msg_error(cpl_func,
"Null plugin");
198 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
202 if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
203 cpl_msg_error(cpl_func,
"Plugin is not a recipe");
204 cpl_ensure_code(0, (
int)CPL_ERROR_TYPE_MISMATCH);
208 recipe = (cpl_recipe *)plugin;
211 if (recipe->parameters == NULL) {
212 cpl_msg_error(cpl_func,
"Recipe invoked with NULL parameter list");
213 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
215 if (recipe->frames == NULL) {
216 cpl_msg_error(cpl_func,
"Recipe invoked with NULL frame set");
217 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
221 recipe_status =
gravity_pcacal(recipe->frames, recipe->parameters);
224 if (cpl_dfs_update_product_header(recipe->frames)) {
225 if (!recipe_status) recipe_status = (int)cpl_error_get_code();
228 if (!cpl_errorstate_is_equal(initial_errorstate)) {
231 cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);
234 return recipe_status;
248 if (plugin == NULL) {
249 cpl_msg_error(cpl_func,
"Null plugin");
250 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
254 if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
255 cpl_msg_error(cpl_func,
"Plugin is not a recipe");
256 cpl_ensure_code(0, (
int)CPL_ERROR_TYPE_MISMATCH);
260 recipe = (cpl_recipe *)plugin;
262 cpl_parameterlist_delete(recipe->parameters);
280 char tr_param_name[100];
282 for (
int i = 0; i < nbase; i++) {
283 sprintf(tr_param_name,
"ESO QC TRACKING_RATIO_FT%s",
GRAVI_BASE_NAME[i]);
284 const cpl_property *tr_prop = cpl_propertylist_get_property_const(hdr, tr_param_name);
286 int tracking_ratio = 0;
287 if (cpl_property_get_type(tr_prop) == CPL_TYPE_INT)
288 tracking_ratio = cpl_property_get_int(tr_prop);
289 else if (cpl_property_get_type(tr_prop) == CPL_TYPE_DOUBLE)
290 tracking_ratio = (int) cpl_property_get_double(tr_prop);
292 cpl_msg_error(cpl_func,
"Could not get tracking ratio");
294 if (tracking_ratio < min_ratio)
309 const cpl_parameterlist * parlist)
311 cpl_frameset *vis_cal_frameset = NULL;
312 cpl_frameset *used_frameset = cpl_frameset_new();
313 cpl_frame *frame = NULL;
315 gravi_data *data_tmp = NULL, **data_accepted = NULL, *pca_data = NULL;
316 cpl_propertylist *hdr = NULL, *header_first = NULL, *wave_plist = NULL, *wv_plisti = NULL;
317 const char *telescope = NULL, *pola_mode = NULL, *spec_res = NULL;
318 int nframes, nwave, nwavei, npol, naccept;
320 char product_filename[100];
326 int min_tracking_ratio = cpl_parameter_get_int(
327 cpl_parameterlist_find_const(parlist,
"gravity.calib.pca-tracking-ratio"));
331 cpl_error_get_code());
334 if (cpl_frameset_is_empty(vis_cal_frameset)) {
335 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
336 "No VIS_CAL on the frameset");
341 frame = cpl_frameset_get_position(vis_cal_frameset, 0);
345 telescope = cpl_propertylist_get_string(header_first,
"TELESCOP");
351 double time_mjd_obs = cpl_propertylist_get_double(header_first,
"MJD-OBS");
354 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
355 "First frame is too old\n");
357 for (
int i = 0; i <
N_EPOCH; i++) {
365 nwave = cpl_propertylist_get_int(wave_plist,
"NWAVE");
369 cpl_msg_info(cpl_func,
"INS.NAME=%s POLA.MODE=%s SPEC.RES=%s NPOL=%d NWAVE=%d",
370 telescope, pola_mode, spec_res, npol, nwave);
374 nframes = cpl_frameset_get_size(vis_cal_frameset);
375 data_accepted = cpl_malloc(nframes *
sizeof(
gravi_data *));
376 for (
int n = 0; n < nframes; n++) {
377 frame = cpl_frameset_get_position(vis_cal_frameset, n);
384 nwavei = cpl_propertylist_get_int(wv_plisti,
"NWAVE");
386 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
387 "Input files have inconsistent wavelength axes");
390 if (strcmp(telescope, cpl_propertylist_get_string(hdr,
"TELESCOP"))) {
391 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
392 "Input files have multiple TELESCOP");
397 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
398 "Input files have multiple INS.POLA.MODE");
403 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
404 "Input files have multiple INS.SPEC.RES");
408 time_mjd_obs = cpl_propertylist_get_double(hdr,
"MJD-OBS");
411 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
412 "Input files span multiple epochs");
416 cpl_boolean skip = CPL_FALSE;
418 for (
int i = 0; i < nbase; i++) {
419 const cpl_array *vis_arr = cpl_table_get_array(vis_tmp,
"VISPHI", i);
420 if ((cpl_array_get_max(vis_arr) < 1e-2) || (cpl_array_get_min(vis_arr) > -1e-2)) {
421 cpl_msg_warning(cpl_func,
"Input file %s has invalid data and will be skipped [range=%f--%f].",
422 cpl_frame_get_filename(frame), cpl_array_get_max(vis_arr), cpl_array_get_min(vis_arr));
430 data_accepted[naccept] = data_tmp;
431 cpl_frameset_insert(used_frameset, frame);
438 cpl_msg_info(cpl_func,
"Accepting %d of %d frames", naccept, nframes);
439 data_accepted = cpl_realloc(data_accepted, naccept *
sizeof(
gravi_data *));
442 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
443 "None of the input files satisfy the minimum tracking ratio criterion");
446 cpl_msg_warning(cpl_func,
"Fewer than %lld valid frames provided, calibration may be inaccurate",
MIN_CALIB_FRAMES);
448 if (cpl_error_get_code())
459 cpl_errorstate e_state = cpl_errorstate_get();
462 cpl_table_new_column(table,
"FILES", CPL_TYPE_STRING);
463 for (
int i = 0; i < naccept; i++) {
464 const cpl_frame *frame = cpl_frameset_get_position_const(used_frameset, i);
465 cpl_table_set_string(table,
"FILES", i, cpl_frame_get_filename(frame));
469 cpl_errorstate_set(e_state);
473 sprintf(product_filename,
"GRAVI.%s.%s_%s_%s.", mjd_str, spec_res, pola_mode, telescope);
475 used_frameset, NULL,
"gravity_phase_pca",
483 FREE(cpl_propertylist_delete, header_first);
484 FREE(cpl_frameset_delete, vis_cal_frameset);
489 return (
int)cpl_error_get_code();
typedefCPL_BEGIN_DECLS struct _gravi_data_ gravi_data
#define gravi_data_get_header(data)
#define gravi_data_get_oi_vis(data, type, pol, npol)
#define gravi_data_get_oi_wave_plist(data, type, pol, npol)
#define GRAVI_RECIPE_OUTPUT
#define GRAVI_RECIPE_FLOW
#define GRAVI_RECIPE_INPUT
#define GRAVI_VIS_SINGLE_CALIB
cpl_msg_info(cpl_func, "Compute WAVE_SCAN for %s", GRAVI_TYPE(type_data))
#define GRAVI_PCA_RESID_EXT
#define CPLCHECK_CLEAN(msg)
#define gravi_msg_function_exit(flag)
#define FREE(function, variable)
#define gravi_msg_function_start(flag)
#define FREELOOP(function, variable, n)
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.
static int gravity_pcacal_create(cpl_plugin *)
Setup the recipe options.
static cpl_boolean gravi_test_tracking_ratio(const cpl_propertylist *hdr, int min_ratio)
Test whether tracking ratio for all baselines exceeds a limit.
static char gravity_pcacal_short[]
static int gravity_pcacal_exec(cpl_plugin *)
Execute the plugin instance given by the interface.
static char gravity_pcacal_description[]
static cpl_size MIN_CALIB_FRAMES
static int gravity_pcacal_destroy(cpl_plugin *)
Destroy what has been created by the 'create' function.
static int gravity_pcacal(cpl_frameset *, const cpl_parameterlist *)
Compute the PCA model from the provided calibration data.
static double TIME_MJD_EPOCH_START[N_EPOCH]
gravi_data * gravi_compute_pca(gravi_data **data, int naccept, const cpl_parameterlist *params)
Fit model for visphi flattening using PCA.
cpl_propertylist * gravi_data_get_plist(gravi_data *self, const char *extname)
Get the propertylist from EXTNAME.
gravi_data * gravi_data_load_frame(cpl_frame *frame, cpl_frameset *used_frameset)
Load a FITS file and create a gravi_data.
cpl_table * gravi_data_get_table(gravi_data *self, const char *extname)
Return a pointer on a table extension by its EXTNAME.
cpl_error_code gravi_data_save_new(gravi_data *self, cpl_frameset *allframes, const char *filename, const char *suffix, const cpl_parameterlist *parlist, cpl_frameset *usedframes, cpl_frame *frame, const char *recipe, cpl_propertylist *applist, const char *proCatg)
Save a gravi data in a CPL-complian FITS file.
void gravi_data_delete(gravi_data *self)
Delete a gravi data.
cpl_frameset * gravi_frameset_extract_vis_calib(cpl_frameset *frameset)
cpl_parameter * gravi_parameter_add_static_name(cpl_parameterlist *self)
cpl_parameter * gravi_parameter_add_pcacalib(cpl_parameterlist *self)
Add pca calibration parameters to the input parameter list.
cpl_error_code gravi_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
void gravity_print_banner(void)
int gravi_pfits_get_pola_num(const cpl_propertylist *plist, int type_data)
const char * gravi_pfits_get_pola_mode(const cpl_propertylist *plist, int type_data)
const char * gravi_pfits_get_spec_res(const cpl_propertylist *plist)
char * gravi_convert_to_timestamp(double mjd)
char GRAVI_BASE_NAME[6][3]
const char * gravi_get_license(void)
Get the pipeline copyright and license.