KMOS Pipeline Reference Manual 4.5.10
kmos_molecfit_correct.c
1/*
2 * This file is part of the KMOS Pipeline
3 * Copyright (C) 2002,2003 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#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24/*----------------------------------------------------------------------------*/
28/*----------------------------------------------------------------------------*/
29
30#include "kmclipm_vector.h"
31#include "kmo_priv_arithmetic.h"
32#include "kmos_molecfit.h"
33#include "kmo_dfs.h"
34
35/*----------------------------------------------------------------------------*/
39/*----------------------------------------------------------------------------*/
40
41#define KMOS_MOLECFIT_CORRECT_REFLEX_SUFFIX "ESO PRO REFLEX SUFFIX"
42
43#define KMOS_MOLECFIT_CORRECT_PARAMETER_SUPPRESS_EXTENSION "suppress_extension"
44#define KMOS_MOLECFIT_CORRECT_PARAMETER_MIN_THRESHOLD "min_threshold"
45
46/*----------------------------------------------------------------------------*/
50/*----------------------------------------------------------------------------*/
51
52typedef struct {
53 cpl_propertylist *header_ext_data; /* Data header */
54 cpl_propertylist *header_ext_noise; /* Noise header */
55 cpl_imagelist *cube_data; /* Data cube (3D) */
56 cpl_imagelist *cube_noise; /* Noise cube (3D) */
57 cpl_vector *vec_data; /* Data (1D) */
58 cpl_vector *vec_noise; /* Noise (1D) */
59 cpl_vector *correction; /* Data correction (1D) TELLURIC_CORR/RESPONSE */
60
61} kmos_molecfit_correct_data;
62
63typedef struct {
64 kmos_molecfit_correct_data ifus[N_IFUS]; /* Input data */
65 cpl_propertylist *parms; /* Input parameters propertylist */
66 cpl_propertylist *pl_data; /* Header of input data fits file */
67 cpl_propertylist *pl_correction; /* Header of input correction fits file */
68 const char *tag_output; /* Tag of the output files */
69 double min_threshold; /* Smaller threshold in the telluric correction */
70} kmos_molecfit_correct_parameter;
71
72
73/*----------------------------------------------------------------------------*/
77/*----------------------------------------------------------------------------*/
78
79/* Use the data input and kmos_molecfit_calctrans output to configure kmos_molecfit_correct */
80static cpl_error_code kmos_molecfit_correct_frame_conf(
81 kmos_molecfit_correct_parameter *conf,
82 cpl_frame *frmCorrection,
83 cpl_frame *frmData);
84
85/* Fill the internal KMOS configuration file */
86static kmos_molecfit_correct_parameter * kmos_molecfit_correct_conf(
87 const cpl_parameterlist *list);
88
89/* Clean variables allocated in the recipe */
90static void kmos_molecfit_correct_clean(
91 kmos_molecfit_correct_parameter *conf);
92
93/*----------------------------------------------------------------------------*/
97/*----------------------------------------------------------------------------*/
98
99#define RECIPE_NAME KMOS_MOLECFIT_CORRECT
100#define CONTEXT "kmos."RECIPE_NAME
101
102static char kmos_molecfit_correct_description[] =
103 "This recipe reads the results from kmos_molecfit_calctrans and apply the telluric correction for scientific input data file.\n"
104 "The input data can have category: \n"
105 " - STAR_SPEC (24 DATA plus 24 NOISE extensions)\n"
106 " - EXTRACT_SPEC (24 DATA extensions, additional 24 NOISE extensions are optional)\n"
107 " - SCIENCE (24 DATA extensions, additional 24 NOISE extensions are optional)\n"
108 " - SCI_RECONSTRUCTED (24 DATA extensions, additional 24 NOISE extensions are optional)\n"
109 "It is not mandatory that all the DATA extension contains data.\n"
110 "The recipe will be run on all the extension that contain data, it include noise extensions.\n"
111 "It is independent from molecfit/calctrans and uses one utility that is available in the KMOS pipeline (kmo_arithmetic).\n"
112 "The result obtained by the proposed molecfit/calctrans recipes must be the same as at the current molecfit and calctrans stand-alone tools.\n"
113 "\n"
114 "Input files: (It's mandatory to provide 1 to N files type A, but only 1 type B that it will apply in all of A's) \n"
115 "\n"
116 " DO KMOS \n"
117 " category Type required Explanation \n"
118 " -------- ----- -------- ----------- \n"
119 " STAR_SPEC F1I A The spectrum (1D spectrum, IMAGE format).\n"
120 " EXTRACT_SPEC F1I A The spectrum (1D spectrum, IMAGE format).\n"
121 " SCIENCE F3I A The spectrum (3D cube, IMAGE format).\n"
122 " SCI_RECONSTRUCTED F3I A The spectrum (3D cube, IMAGE format).\n"
123 " TELLURIC_CORR F1I B Telluric correction for each IFU (24-data extensions, additionaly 24-error are optional, in IMAGE format).\n"
124 " RESPONSE F1S B Response correction for each IFU (24-data extensions, additionaly 24-error are optional, in IMAGE format).\n"
125 "\n"
126 "Output files: (The output is 1 file of type C. The file match with the input dimensions)\n"
127 "\n"
128 " DO KMOS \n"
129 " category Type Explanation \n"
130 " -------- ----- ----------- \n"
131 " SINGLE_SPECTRA F1I C The 1D input data corrected file.\n"
132 " SINGLE_CUBES F3I C The 3D input data corrected file.\n"
133 "\n";
134
135/* Standard CPL recipe definition */
136cpl_recipe_define( kmos_molecfit_correct,
137 KMOS_BINARY_VERSION,
138 "Jose A. Escartin, Yves Jung",
139 "https://support.eso.org/",
140 "2017",
141 "Read the results from kmos_molecfit_calctrans and apply the telluric correction for a scientific input data.",
142 kmos_molecfit_correct_description);
143
144
145/*----------------------------------------------------------------------------*/
149/*----------------------------------------------------------------------------*/
150
153/*----------------------------------------------------------------------------*/
157/*----------------------------------------------------------------------------*/
158
159/*----------------------------------------------------------------------------*/
169/*----------------------------------------------------------------------------*/
170static int kmos_molecfit_correct(
171 cpl_frameset *frameset, const cpl_parameterlist *parlist)
172{
173 /* Check initial Entries */
174 if (kmos_check_and_set_groups(frameset) != CPL_ERROR_NONE) {
175 return cpl_error_get_code();
176 }
177
178 /* Get initial errorstate */
179 cpl_errorstate initial_errorstate = cpl_errorstate_get();
180
181 /* Get --suppress_extension parameter : Flag to activate/suppress the output grating prefix */
182 const cpl_parameter *p = cpl_parameterlist_find_const(parlist, KMOS_MOLECFIT_CORRECT_PARAMETER_SUPPRESS_EXTENSION);
183 cpl_boolean suppress_extension = cpl_parameter_get_bool(p);
184
185 /*** Get frame, header and check: correction TELLURIC_CORR/RESPONSE ***/
186 cpl_errorstate preStateLoadCorrection = cpl_errorstate_get();
187 cpl_msg_info(cpl_func, "Loading header, input spectrum correction ...");
188 cpl_frame *frmCorrection = cpl_frameset_find(frameset, TELLURIC_CORR);
189 if (!frmCorrection) {
190 cpl_errorstate_set(preStateLoadCorrection);
191 frmCorrection = cpl_frameset_find(frameset, RESPONSE);
192 if (!frmCorrection) {
193 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
194 "Frame with input correction data spectrum not found in frameset ('%s','%s') !",
195 TELLURIC_CORR, RESPONSE);
196 }
197 }
198
199 /*** Create the raw frameset ***/
200 cpl_size nframes = cpl_frameset_get_size(frameset);
201 cpl_frameset *fs_raws = cpl_frameset_new();
202 for (cpl_size i = 0; i < nframes; i++) {
203
204 cpl_frame *frame = cpl_frameset_get_position(frameset, i);
205
206 if ( !strcmp(cpl_frame_get_tag(frame), STAR_SPEC )
207 || !strcmp(cpl_frame_get_tag(frame), EXTRACT_SPEC )
208 || !strcmp(cpl_frame_get_tag(frame), SCIENCE )
209 || !strcmp(cpl_frame_get_tag(frame), RECONSTRUCTED_CUBE) ){
210
211 cpl_frameset_insert(fs_raws, cpl_frame_duplicate(frame));
212 }
213 }
214
215 /* Check size of raw frameset*/
216 cpl_size n_raws = cpl_frameset_get_size(fs_raws);
217 if (n_raws < 1) {
218 cpl_frameset_delete(fs_raws);
219 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
220 "Not raw Frames in the input frameset!");
221 }
222
223 /* Loop to compute all the inputs raws files */
224 for (cpl_size i = 0; i < n_raws; i++) {
225
226 /* Get one input data file */
227 cpl_frame *frmData = cpl_frameset_get_position(fs_raws, i);
228
229 /* Create a new independent cpl_frameset for this concrete input DATA frame */
230 cpl_frameset *fs_raw_output = cpl_frameset_new();
231 cpl_frameset_insert(fs_raw_output, cpl_frame_duplicate(frmData));
232
233 /* Extract and verify data in the parameters of the recipe */
234 cpl_msg_info(cpl_func, "Configuring initial parameters in the recipe ...");
235 kmos_molecfit_correct_parameter *conf = kmos_molecfit_correct_conf(parlist);
236 if (!conf) {
237 cpl_frameset_delete(fs_raws);
238 cpl_frameset_delete(fs_raw_output);
239 return (int)cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
240 "Problems with the configuration parameters");
241
242 }
243
244 /* Complete configuration using the data input and kmos_molecfit_calctrans output to configure kmos_molecfit_correct */
245
246 if (kmos_molecfit_correct_frame_conf(conf, frmCorrection, frmData) != CPL_ERROR_NONE) {
247 kmos_molecfit_correct_clean(conf);
248 cpl_frameset_delete(fs_raws);
249 cpl_frameset_delete(fs_raw_output);
250 return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
251 "Configuration with kmos_molecfit_model output failed!");
252 }
253
254 /*Update primary header with QC paramters from telluricc_corr file */
255 /*cpl_errorstate prevstate = cpl_errorstate_get();
256
257 cpl_propertylist_dump(conf->parms,stdout);
258
259 kmclipm_update_property_double(conf->parms, KMOS_MOLECFIT_QC_PARAM_H2O_AVG,
260 cpl_propertylist_get_double(tel_corr_header, KMOS_MOLECFIT_QC_PARAM_H2O_AVG),
261 KMOS_MOLECFIT_QC_PARAM_H2O_AVG_TXT);
262 kmclipm_update_property_double(conf->parms, KMOS_MOLECFIT_QC_PARAM_H2O_RMS,
263 cpl_propertylist_get_double(tel_corr_header, KMOS_MOLECFIT_QC_PARAM_H2O_RMS),
264 KMOS_MOLECFIT_QC_PARAM_H2O_RMS_TXT);
265 kmclipm_update_property_double(conf->parms, KMOS_MOLECFIT_QC_PARAM_AIRM_STD,
266 cpl_propertylist_get_double(tel_corr_header, KMOS_MOLECFIT_QC_PARAM_AIRM_STD),
267 KMOS_MOLECFIT_QC_PARAM_AIRM_STD_TXT);
268 kmclipm_update_property_double(conf->parms, KMOS_MOLECFIT_QC_PARAM_MEAS_IWV,
269 cpl_propertylist_get_double(tel_corr_header, KMOS_MOLECFIT_QC_PARAM_MEAS_IWV),
270 KMOS_MOLECFIT_QC_PARAM_MEAS_IWV_TXT);
271 kmclipm_update_property_double(conf->parms, KMOS_MOLECFIT_QC_PARAM_MEAS_IWV,
272 cpl_propertylist_get_double(tel_corr_header, KMOS_MOLECFIT_QC_PARAM_MEAS_IWV30D),
273 KMOS_MOLECFIT_QC_PARAM_MEAS_IWV30D_TXT);
274 kmclipm_update_property_double(conf->parms, KMOS_MOLECFIT_QC_PARAM_H2O_DELTA,
275 cpl_propertylist_get_double(tel_corr_header, KMOS_MOLECFIT_QC_PARAM_H2O_DELTA),
276 KMOS_MOLECFIT_QC_PARAM_H2O_DELTA_TXT);
277
278 if (!cpl_errorstate_is_equal(prevstate)) {
279 cpl_errorstate_set(prevstate);
280 } */
281
282 /*MOVE ABOVE SECTION TO NEW FUNCTION*/
283
284 const char *fileData = cpl_frame_get_filename(frmData);
285 cpl_msg_info(cpl_func, " +++ All input data loaded successfully from the input file: %s +++", fileData);
286
287 /* Saving generic multi-extension output *.fits file */
288 char *filename;
289 if (suppress_extension) {
290 filename = cpl_sprintf("%s_%lld.fits", conf->tag_output, i);
291 } else {
292 filename = cpl_sprintf("%s_%s", conf->tag_output, cpl_propertylist_get_string(conf->pl_data, "ARCFILE"));
293 }
294
295 cpl_msg_info(cpl_func, "Saving generic multi-extension output fits file ('%s') ...", filename);
296 if (kmos_molecfit_save(frameset, fs_raw_output, parlist, RECIPE_NAME, conf->parms, conf->tag_output, NULL, CPL_FALSE, filename) != CPL_ERROR_NONE) {
297 cpl_free(filename);
298 kmos_molecfit_correct_clean(conf);
299 cpl_frameset_delete(fs_raws);
300 cpl_frameset_delete(fs_raw_output);
301 return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
302 "Saving generic multi-extension output fits files failed!");
303 }
304
305
306 /* Execute correction */
307 for (cpl_size n_ifu = 0; n_ifu < N_IFUS; n_ifu++) {
308 kmos_molecfit_correct_data *ifu = &(conf->ifus[n_ifu]);
309
310 /* Get state */
311 cpl_errorstate preState = cpl_errorstate_get();
312
313 /* Apply the correction and save */
314 cpl_error_code e_sData;
315 cpl_error_code e_sNoise = CPL_ERROR_NONE;
316
317 /*** Get input data ***/
318 if (ifu->vec_data) {
319
320 cpl_msg_info(cpl_func, "Correcting 1D data spectrum , IFU.%02lld ...", n_ifu + 1);
321 cpl_vector_divide(ifu->vec_data, ifu->correction);
322
323 cpl_msg_info(cpl_func, "Saving in '%s' 1D data , IFU.%02lld ...", filename, n_ifu + 1);
324 e_sData = cpl_vector_save(ifu->vec_data, filename, CPL_TYPE_FLOAT, ifu->header_ext_data, CPL_IO_EXTEND);
325
326 if (ifu->vec_noise) {
327
328 cpl_msg_info(cpl_func, "Correcting 1D noise spectrum, IFU.%02lld ...", n_ifu + 1);
329 cpl_vector_divide(ifu->vec_noise, ifu->correction);
330
331 cpl_msg_info(cpl_func, "Saving in '%s' 1D noise , IFU.%02lld ...", filename, n_ifu + 1);
332 e_sNoise = cpl_vector_save(ifu->vec_noise, filename, CPL_TYPE_FLOAT, ifu->header_ext_noise, CPL_IO_EXTEND);
333
334 } else if (ifu->header_ext_noise){
335
336 cpl_msg_info(cpl_func, "Saving in '%s' header noise , IFU.%02lld ...", filename, n_ifu + 1);
337 e_sNoise = cpl_propertylist_save(ifu->header_ext_noise, filename, CPL_IO_EXTEND);
338 }
339
340 } else if (ifu->cube_data) {
341
342 /* Conver ifu->correction for operate with kmo_priv_arithmetic */
343 kmclipm_vector *correction = kmclipm_vector_create(cpl_vector_duplicate(ifu->correction));
344
345 cpl_msg_info(cpl_func, "Correcting 3D data cube , IFU.%02lld ...", n_ifu + 1);
346 if (kmo_arithmetic_3D_1D(ifu->cube_data, correction, NULL, NULL, "/") != CPL_ERROR_NONE) {
347 cpl_free(filename);
348 kmclipm_vector_delete(correction);
349 kmos_molecfit_correct_clean(conf);
350 cpl_frameset_delete(fs_raws);
351 cpl_frameset_delete(fs_raw_output);
352 return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
353 "Correction 3D failed in IFU.%02lld!", n_ifu + 1);
354 }
355
356 cpl_msg_info(cpl_func, "Saving in '%s' 3D data , IFU.%02lld ...", filename, n_ifu + 1);
357 e_sData = cpl_imagelist_save(ifu->cube_data, filename, CPL_TYPE_FLOAT, ifu->header_ext_data, CPL_IO_EXTEND);
358
359 if (ifu->cube_noise) {
360
361 cpl_msg_info(cpl_func, "Correcting 3D noise cube, IFU.%02lld ...", n_ifu + 1);
362 if (kmo_arithmetic_3D_1D(ifu->cube_noise, correction, NULL, NULL, "/") != CPL_ERROR_NONE) {
363 cpl_free(filename);
364 kmclipm_vector_delete(correction);
365 kmos_molecfit_correct_clean(conf);
366 cpl_frameset_delete(fs_raws);
367 cpl_frameset_delete(fs_raw_output);
368 return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
369 "Correction 3D failed in IFU.%02lld!", n_ifu + 1);
370 }
371
372 cpl_msg_info(cpl_func, "Saving in '%s' 3D noise correction cube, IFU.%02lld ...", filename, n_ifu + 1);
373 e_sNoise = cpl_imagelist_save(ifu->cube_noise, filename, CPL_TYPE_FLOAT, ifu->header_ext_noise, CPL_IO_EXTEND);
374
375 } else if (ifu->header_ext_noise) {
376
377 cpl_msg_info(cpl_func, "Saving in '%s' header noise , IFU.%02lld ...", filename, n_ifu + 1);
378 e_sNoise = cpl_propertylist_save(ifu->header_ext_noise, filename, CPL_IO_EXTEND);
379 }
380
381 /* Cleanup correction */
382 kmclipm_vector_delete(correction);
383
384 } else {
385
386 cpl_msg_info(cpl_func, "Saving in '%s' header data , IFU.%02lld ...", filename, n_ifu + 1);
387 e_sData = cpl_propertylist_save(ifu->header_ext_data, filename, CPL_IO_EXTEND);
388 if (ifu->header_ext_noise) {
389 cpl_msg_info(cpl_func, "Saving in '%s' header noise , IFU.%02lld ...", filename, n_ifu + 1);
390 e_sNoise = cpl_propertylist_save(ifu->header_ext_noise, filename, CPL_IO_EXTEND);
391 }
392 }
393
394 /* Check save */
395 if (e_sData != CPL_ERROR_NONE || e_sNoise != CPL_ERROR_NONE) {
396 cpl_free(filename);
397 kmos_molecfit_correct_clean(conf);
398 cpl_frameset_delete(fs_raws);
399 cpl_frameset_delete(fs_raw_output);
400 return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
401 "Saving correction output failed!, ext=%lld", n_ifu + 1);
402 }
403
404 /* Check execution */
405 if (!cpl_errorstate_is_equal(preState)) {
406 cpl_msg_info(cpl_func, "Correction failed! in IFU.%02lld -> error: %s", n_ifu + 1, cpl_error_get_message());
407 cpl_free(filename);
408 kmos_molecfit_correct_clean(conf);
409 cpl_frameset_delete(fs_raws);
410 cpl_frameset_delete(fs_raw_output);
411 return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
412 "Correction failed! in IFU.%02lld ...", n_ifu + 1);
413
414 }
415 }
416
417 /* Cleanup configuration */
418 cpl_msg_info(cpl_func,"Cleaning variables from the input file : %s", fileData);
419 cpl_free(filename);
420 kmos_molecfit_correct_clean(conf);
421 cpl_frameset_delete(fs_raw_output);
422 }
423
424 /* Cleanup */
425 cpl_frameset_delete(fs_raws);
426
427
428 /* Check Recipe status and end */
429 if (cpl_errorstate_is_equal(initial_errorstate) && cpl_error_get_code() == CPL_ERROR_NONE ) {
430 cpl_msg_info(cpl_func,"Recipe successfully!");
431 } else {
432 /* Dump the error history since recipe execution start.
433 * At this point the recipe cannot recover from the error */
434 cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);
435 cpl_msg_info(cpl_func,"Recipe failed!, error(%d)=%s", cpl_error_get_code(), cpl_error_get_message());
436 }
437
438 return (int)cpl_error_get_code();
439}
440
443/*----------------------------------------------------------------------------*/
452/*----------------------------------------------------------------------------*/
453static cpl_error_code kmos_molecfit_correct_fill_parameterlist(
454 cpl_parameterlist *self)
455{
456 cpl_error_ensure(self, CPL_ERROR_NULL_INPUT, return CPL_ERROR_NULL_INPUT, "Null input");
457
458 /* Add the different default parameters to the recipe */
459 cpl_errorstate prestate = cpl_errorstate_get();
460
461 /* Fill the parameters list */
462 cpl_error_code e;
463 cpl_boolean range = CPL_TRUE;
464 const void *dummyMin = NULL;
465 const void *dummyMax = NULL;
466
467
468 /* --suppress_extension */
469 cpl_boolean suppress_extension = CPL_FALSE;
470 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, KMOS_MOLECFIT_CORRECT_PARAMETER_SUPPRESS_EXTENSION,
471 !range, dummyMin, dummyMax, CPL_TYPE_BOOL, &suppress_extension,
472 "Suppress arbitrary filename extension.(TRUE (apply) or FALSE (don't apply).", CPL_FALSE);
473 if (e != CPL_ERROR_NONE) return (int)e;
474
475 /* --min_threshold */
476 double min_threshold = 0.01;
477 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, KMOS_MOLECFIT_CORRECT_PARAMETER_MIN_THRESHOLD,
478 !range, dummyMin, dummyMax, CPL_TYPE_DOUBLE, &min_threshold,
479 "Minimum threshold in the telluric correction. If min_threshold > 0 then elements in the telluric correction that are smaller than the threshold are set to the threshold", CPL_FALSE);
480 if (e != CPL_ERROR_NONE) return (int)e;
481
482
483 /* Check possible errors */
484 if (!cpl_errorstate_is_equal(prestate)) {
485 return cpl_error_set_message(cpl_func, cpl_error_get_code(),
486 "kmos_molecfit_correct_fill_parameterlist failed!");
487 }
488
489 return CPL_ERROR_NONE;
490}
491
492/*----------------------------------------------------------------------------*/
501/*----------------------------------------------------------------------------*/
502static kmos_molecfit_correct_parameter * kmos_molecfit_correct_conf(
503 const cpl_parameterlist *list)
504{
505 /* Check input */
506 cpl_error_ensure(list, CPL_ERROR_NULL_INPUT,
507 return NULL, "kmos_molecfit_correct_fill_conf input list NULL!");
508
509 /* Get preState */
510 cpl_errorstate preState = cpl_errorstate_get();
511
512 /* Create the configuration parameter */
513 kmos_molecfit_correct_parameter *conf = (kmos_molecfit_correct_parameter *)cpl_malloc(sizeof(kmos_molecfit_correct_parameter));
514 conf->parms = cpl_propertylist_new();
515 conf->pl_data = NULL;
516 conf->pl_correction = NULL;
517 for (cpl_size n_ifu = 0; n_ifu < N_IFUS; n_ifu++) {
518 kmos_molecfit_correct_data *ifu = &(conf->ifus[n_ifu]);
519
520 ifu->header_ext_data = NULL;
521 ifu->header_ext_noise = NULL;
522
523 ifu->cube_data = NULL;
524 ifu->cube_noise = NULL;
525
526 ifu->vec_data = NULL;
527 ifu->vec_noise = NULL;
528
529 ifu->correction = NULL;
530 }
531
532 /* Get --min_threshold : Smaller threshold in the telluric correction */
533 const cpl_parameter *p = cpl_parameterlist_find_const(list, KMOS_MOLECFIT_CORRECT_PARAMETER_MIN_THRESHOLD);
534 conf->min_threshold = cpl_parameter_get_double(p);
535
536 /* Check status */
537 if (!cpl_errorstate_is_equal(preState)) {
538 /* Configuration failed */
539 kmos_molecfit_correct_clean(conf);
540 return NULL;
541 }
542
543 /* Configuration successfully */
544 return conf;
545}
546
547/*----------------------------------------------------------------------------*/
557/*----------------------------------------------------------------------------*/
558static cpl_error_code kmos_molecfit_correct_frame_conf(
559 kmos_molecfit_correct_parameter *conf,
560 cpl_frame *frmCorrection,
561 cpl_frame *frmData)
562{
563 /* Check input */
564 cpl_error_ensure(conf && frmCorrection && frmData, CPL_ERROR_NULL_INPUT,
565 return CPL_ERROR_NULL_INPUT, "kmos_molecfit_correct_inputs_conf inputs NULL!");
566
567 /* Get preState */
568 cpl_errorstate initialState = cpl_errorstate_get();
569
570
571 /*** Get frame, header and check input data ***/
572 cpl_msg_info(cpl_func, "Loading header, input data frame ...");
573 const char *fileData = cpl_frame_get_filename(frmData);
574 conf->pl_data = cpl_propertylist_load(fileData, 0);
575 cpl_error_ensure(conf->pl_data, cpl_error_get_code(),
576 return cpl_error_get_code(), "Cannot load input data primary header propertylist from '%s'!", fileData);
577
578 /* Get REFLEX_SUFFIX if exist in the file */
579 if (cpl_propertylist_has(conf->pl_data, KMOS_MOLECFIT_CORRECT_REFLEX_SUFFIX)) {
580 cpl_propertylist_update_string(conf->parms, KMOS_MOLECFIT_CORRECT_REFLEX_SUFFIX, cpl_propertylist_get_string(conf->pl_data, KMOS_MOLECFIT_CORRECT_REFLEX_SUFFIX));
581 }
582
583 /* Propagate the keyword : ESO PRO MJD-OBS */
584 if (cpl_propertylist_has(conf->pl_data, PRO_MJD_OBS)) {
585 cpl_propertylist_update_double(conf->parms, PRO_MJD_OBS,
586 cpl_propertylist_get_double(conf->pl_data, PRO_MJD_OBS));
587 }
588
589 /* Propagate the keyword : ESO PRO DATE-OBS */
590 if (cpl_propertylist_has(conf->pl_data, PRO_DATE_OBS)) {
591 cpl_propertylist_update_string(conf->parms, PRO_DATE_OBS,
592 cpl_propertylist_get_string(conf->pl_data, PRO_DATE_OBS));
593 }
594
595 /* Propagate QC keywords from data file */
596 if (cpl_propertylist_has(conf->pl_data, QC_SAT_LEVEL)) {
597 cpl_propertylist_update_double(conf->parms, QC_SAT_LEVEL,
598 cpl_propertylist_get_double(conf->pl_data, QC_SAT_LEVEL));
599 }
600
601 if (cpl_propertylist_has(conf->pl_data, QC_PERS_LEVEL)) {
602 cpl_propertylist_update_double(conf->parms, QC_PERS_LEVEL,
603 cpl_propertylist_get_double(conf->pl_data, QC_PERS_LEVEL));
604 }
605
606 if (cpl_propertylist_has(conf->pl_data, QC_MASTER_FLAT_MJD_OBS)) {
607 cpl_propertylist_update_double(conf->parms, QC_MASTER_FLAT_MJD_OBS,
608 cpl_propertylist_get_double(conf->pl_data, QC_MASTER_FLAT_MJD_OBS));
609 }
610
611 if (cpl_propertylist_has(conf->pl_data, QC_TELLURIC_GEN_MJD_OBS)) {
612 cpl_propertylist_update_double(conf->parms, QC_TELLURIC_GEN_MJD_OBS,
613 cpl_propertylist_get_double(conf->pl_data, QC_TELLURIC_GEN_MJD_OBS));
614 }
615
616 /* Get input data tag and select ouput tag */
617 const char *tag = cpl_frame_get_tag(frmData);
618 if ( strcmp(tag, STAR_SPEC ) == 0
619 || strcmp(tag, EXTRACT_SPEC ) == 0 ){
620 conf->tag_output = SINGLE_SPECTRA;
621 } else if ( strcmp(tag, SCIENCE ) == 0
622 || strcmp(tag, RECONSTRUCTED_CUBE) == 0 ){
623 conf->tag_output = SINGLE_CUBES;
624 } else {
625 return cpl_error_set_message(cpl_func, CPL_ERROR_TYPE_MISMATCH,
626 "Tag input data unexpected: %s", tag);
627 }
628
629 /* Get if the file raw have 24(1) or 48(2) extensions */
630 cpl_size n_extensions_raw = cpl_fits_count_extensions(fileData);
631 cpl_size ext24_raw = (N_IFUS == n_extensions_raw) ? 1 : 2;
632
633 const char *fileCorrection = cpl_frame_get_filename(frmCorrection);
634 conf->pl_correction = cpl_propertylist_load(fileCorrection, 0);
635 cpl_error_ensure(conf->pl_correction, cpl_error_get_code(),
636 return cpl_error_get_code(), "Cannot load TELLURIC_CORR primary header propertylist from '%s'!", fileCorrection);
637
638 /* Propagate QC keywords from Telluric-corr file */
639
640
641 if (cpl_propertylist_has(conf->pl_correction, QC_SAT_NB)) {
642 cpl_propertylist_update_int(conf->parms, QC_SAT_NB,
643 cpl_propertylist_get_int(conf->pl_correction, QC_SAT_NB));
644 }
645
646 if (cpl_propertylist_has(conf->pl_correction, QC_PERS_NB)) {
647 cpl_propertylist_update_int(conf->parms, QC_PERS_NB,
648 cpl_propertylist_get_int(conf->pl_correction, QC_PERS_NB));
649 }
650
651 if (cpl_propertylist_has(conf->pl_correction, QC_PARAM_H2O_AVG)) {
652 cpl_propertylist_update_double(conf->parms, QC_PARAM_H2O_AVG,
653 cpl_propertylist_get_double(conf->pl_correction, QC_PARAM_H2O_AVG));
654 }
655
656 if (cpl_propertylist_has(conf->pl_correction, QC_PARAM_H2O_RMS)) {
657 cpl_propertylist_update_double(conf->parms, QC_PARAM_H2O_RMS,
658 cpl_propertylist_get_double(conf->pl_correction, QC_PARAM_H2O_RMS));
659 }
660
661 if (cpl_propertylist_has(conf->pl_correction, QC_PARAM_AIRM_STD)) {
662 cpl_propertylist_update_double(conf->parms, QC_PARAM_AIRM_STD,
663 cpl_propertylist_get_double(conf->pl_correction, QC_PARAM_AIRM_STD));
664 }
665
666 if (cpl_propertylist_has(conf->pl_correction, QC_PARAM_MEAS_IWV)) {
667 cpl_propertylist_update_double(conf->parms, QC_PARAM_MEAS_IWV,
668 cpl_propertylist_get_double(conf->pl_correction, QC_PARAM_MEAS_IWV));
669 }
670
671 if (cpl_propertylist_has(conf->pl_correction, QC_PARAM_MEAS_IWV30D)) {
672 cpl_propertylist_update_double(conf->parms, QC_PARAM_MEAS_IWV30D,
673 cpl_propertylist_get_double(conf->pl_correction, QC_PARAM_MEAS_IWV30D));
674 }
675
676 if (cpl_propertylist_has(conf->pl_correction, QC_PARAM_H2O_RATIO)) {
677 cpl_propertylist_update_double(conf->parms, QC_PARAM_H2O_RATIO,
678 cpl_propertylist_get_double(conf->pl_correction, QC_PARAM_H2O_RATIO));
679 }
680
681 if (cpl_propertylist_has(conf->pl_correction, QC_PARAM_H2O_DELTA)) {
682 cpl_propertylist_update_double(conf->parms, QC_PARAM_H2O_DELTA,
683 cpl_propertylist_get_double(conf->pl_correction, QC_PARAM_H2O_DELTA));
684 }
685
686 /* Get input correction tag */
687 const char *tag_correction = cpl_frame_get_tag(frmCorrection);
688
689 /* Get if the file correction have 24(1) or 48(2) extensions */
690 cpl_size n_extensions_correction = cpl_fits_count_extensions(fileCorrection);
691 cpl_size ext24_correction = (N_IFUS == n_extensions_correction) ? 1 : 2;
692
693
694 /*** Loading data form the input fits file ***/
695 cpl_errorstate preState = cpl_errorstate_get();
696 for (cpl_size n_ifu = 0; n_ifu < N_IFUS; n_ifu++) {
697 kmos_molecfit_correct_data *ifu = &(conf->ifus[n_ifu]);
698
699 /* Get number of extensions */
700 cpl_size correction_ext = (n_ifu * ext24_correction) + 1; /* 24/48 extensions (odd ext - data ) */
701 cpl_size data_ext = (n_ifu * ext24_raw ) + 1; /* 24/48 extensions (odd ext - data ) */
702 cpl_size noise_ext = data_ext + 1; /* 24/48 extensions (even ext - noise) */
703
704
705 /*** Get input data header ***/
706 ifu->header_ext_data = cpl_propertylist_load(fileData, data_ext);
707 cpl_error_ensure(ifu->header_ext_data, cpl_error_get_code(),
708 return cpl_error_get_code(), "Cannot load input data extension header propertylist from '%s', ext=%lld!", fileData, n_ifu + 1);
709
710
711 /*** Get input noise header: 48 extensions in the file? ***/
712 if (ext24_raw > 1) {
713
714 /* Load header noise extension */
715 ifu->header_ext_noise = cpl_propertylist_load(fileData, noise_ext);
716 cpl_error_ensure(ifu->header_ext_data, cpl_error_get_code(),
717 return cpl_error_get_code(), "Cannot load input data extension header propertylist from '%s', ext=%lld!", fileData, n_ifu + 1);
718 }
719
720
721 /*** Get input data ***/
722 if (strcmp(conf->tag_output, SINGLE_SPECTRA) == 0){
723
724 ifu->vec_data = cpl_vector_load(fileData, data_ext);
725 if (!(ifu->vec_data)) {
726 /* The extension doesn't have 1D data */
727 cpl_errorstate_set(preState);
728 cpl_msg_info(cpl_func, "Frame: %s --> IFU.%02lld : Loaded 1D input data header (not exist input data).", tag, n_ifu + 1);
729 } else {
730 cpl_msg_info(cpl_func, "Frame: %s --> IFU.%02lld : Loaded 1D input data!", tag, n_ifu + 1);
731
732 /* Get input noise: 48 extensions in the file? */
733 if (ext24_raw > 1) {
734
735 ifu->vec_noise = cpl_vector_load(fileData, noise_ext);
736 if (!(ifu->vec_noise)) {
737 /* The extension doesn't have 1D data */
738 cpl_errorstate_set(preState);
739 cpl_msg_info(cpl_func, "Frame: %s --> IFU.%02lld : Loaded 1D input noise header (not exist input noise).", tag, n_ifu + 1);
740
741 } else {
742 cpl_msg_info(cpl_func, "Frame: %s --> IFU.%02lld : Loaded 1D input noise!", tag, n_ifu + 1);
743 }
744 }
745 }
746
747
748 } else if (strcmp(conf->tag_output, SINGLE_CUBES) == 0){
749
750 ifu->cube_data = cpl_imagelist_load(fileData, CPL_TYPE_FLOAT, data_ext);
751 if (!(ifu->cube_data)) {
752 /* The extension doesn't have 1D data */
753 cpl_errorstate_set(preState);
754 cpl_msg_info(cpl_func, "Frame: %s --> IFU.%02lld : Loaded 3D input data header (not exist input data).", tag, n_ifu + 1);
755 } else {
756 cpl_msg_info(cpl_func, "Frame: %s --> IFU.%02lld : Loaded 3D input data!", tag, n_ifu + 1);
757
758 /* Get input noise: 48 extensions in the file? */
759 if (ext24_raw > 1) {
760
761 ifu->cube_noise = cpl_imagelist_load(fileData, CPL_TYPE_FLOAT, noise_ext);
762 if (!(ifu->cube_noise)) {
763 /* The extension doesn't have 1D data */
764 cpl_errorstate_set(preState);
765 cpl_msg_info(cpl_func, "Frame: %s --> IFU.%02lld : Loaded 3D input noise header (not exist input noise).", tag, n_ifu + 1);
766
767 } else {
768 cpl_msg_info(cpl_func, "Frame: %s --> IFU.%02lld : Loaded 3D input noise!", tag, n_ifu + 1);
769 }
770 }
771 }
772 }
773
774
775 /* Get Telluric correction */
776 ifu->correction = cpl_vector_load(fileCorrection, correction_ext);
777 if (!(ifu->correction)) {
778 /* The extension doesn't have correction (telluric/response) */
779 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
780 "The extension doesn't have correction spectrum in IFU.%02lld", n_ifu + 1);
781 } else {
782
783 cpl_msg_info(cpl_func, "Frame: %s --> IFU.%02lld : Loaded input data spectrum correction (output of kmos_molecfit_calctrans recipe).", tag_correction, n_ifu + 1);
784
785 /* Check minimum threshold */
786 if (conf->min_threshold > 0) {
787
788 cpl_msg_info(cpl_func, "Apply min_threshold in the telluric correction[min_threshold=%g]", conf->min_threshold);
789 cpl_size positions_update = 0;
790
791 cpl_size size = cpl_vector_get_size(ifu->correction);
792 for (cpl_size i = 0; i < size; i++) {
793
794 /* Check position */
795 double value = cpl_vector_get(ifu->correction, i);
796 if (value < conf->min_threshold) {
797 cpl_vector_set(ifu->correction, i, conf->min_threshold);
798 positions_update++;
799 }
800 }
801
802 /* Show info */
803 if (positions_update > 0) {
804 cpl_msg_info(cpl_func, "Telluric correction positions update with min_threshold = %lld]", positions_update);
805 }
806 }
807 }
808 }
809
810
811 /* Check status */
812 if (!cpl_errorstate_is_equal(initialState)) {
813 /* Configuration failed */
814 return cpl_error_get_code();
815 }
816
817 return CPL_ERROR_NONE;
818}
819
820/*----------------------------------------------------------------------------*/
826/*----------------------------------------------------------------------------*/
827static void kmos_molecfit_correct_clean(
828 kmos_molecfit_correct_parameter *conf)
829{
830 if (conf) {
831
832 if (conf->parms) cpl_propertylist_delete(conf->parms);
833 if (conf->pl_data) cpl_propertylist_delete(conf->pl_data);
834 if (conf->pl_correction) cpl_propertylist_delete(conf->pl_correction);
835
836 for (cpl_size n_ifu = 0; n_ifu < N_IFUS; n_ifu ++) {
837 kmos_molecfit_correct_data *ifu = &(conf->ifus[n_ifu]);
838
839 if (ifu->header_ext_data) cpl_propertylist_delete(ifu->header_ext_data);
840 if (ifu->header_ext_noise) cpl_propertylist_delete(ifu->header_ext_noise);
841
842 if (ifu->cube_data) cpl_imagelist_delete( ifu->cube_data);
843 if (ifu->cube_noise) cpl_imagelist_delete( ifu->cube_noise);
844
845 if (ifu->vec_data) cpl_vector_delete( ifu->vec_data);
846 if (ifu->vec_noise) cpl_vector_delete( ifu->vec_noise);
847
848 if (ifu->correction) cpl_vector_delete( ifu->correction);
849 }
850
851 cpl_free(conf);
852 }
853}