30#include "kmclipm_vector.h"
31#include "kmo_priv_arithmetic.h"
32#include "kmos_molecfit.h"
41#define KMOS_MOLECFIT_CORRECT_REFLEX_SUFFIX "ESO PRO REFLEX SUFFIX"
43#define KMOS_MOLECFIT_CORRECT_PARAMETER_SUPPRESS_EXTENSION "suppress_extension"
44#define KMOS_MOLECFIT_CORRECT_PARAMETER_MIN_THRESHOLD "min_threshold"
53 cpl_propertylist *header_ext_data;
54 cpl_propertylist *header_ext_noise;
55 cpl_imagelist *cube_data;
56 cpl_imagelist *cube_noise;
58 cpl_vector *vec_noise;
59 cpl_vector *correction;
61} kmos_molecfit_correct_data;
64 kmos_molecfit_correct_data ifus[N_IFUS];
65 cpl_propertylist *parms;
66 cpl_propertylist *pl_data;
67 cpl_propertylist *pl_correction;
68 const char *tag_output;
70} kmos_molecfit_correct_parameter;
80static cpl_error_code kmos_molecfit_correct_frame_conf(
81 kmos_molecfit_correct_parameter *conf,
82 cpl_frame *frmCorrection,
86static kmos_molecfit_correct_parameter * kmos_molecfit_correct_conf(
87 const cpl_parameterlist *list);
90static void kmos_molecfit_correct_clean(
91 kmos_molecfit_correct_parameter *conf);
99#define RECIPE_NAME KMOS_MOLECFIT_CORRECT
100#define CONTEXT "kmos."RECIPE_NAME
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"
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"
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"
126 "Output files: (The output is 1 file of type C. The file match with the input dimensions)\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"
136cpl_recipe_define( kmos_molecfit_correct,
138 "Jose A. Escartin, Yves Jung",
139 "https://support.eso.org/",
141 "Read the results from kmos_molecfit_calctrans and apply the telluric correction for a scientific input data.",
142 kmos_molecfit_correct_description);
170static int kmos_molecfit_correct(
171 cpl_frameset *frameset,
const cpl_parameterlist *parlist)
174 if (kmos_check_and_set_groups(frameset) != CPL_ERROR_NONE) {
175 return cpl_error_get_code();
179 cpl_errorstate initial_errorstate = cpl_errorstate_get();
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);
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);
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++) {
204 cpl_frame *frame = cpl_frameset_get_position(frameset, i);
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) ){
211 cpl_frameset_insert(fs_raws, cpl_frame_duplicate(frame));
216 cpl_size n_raws = cpl_frameset_get_size(fs_raws);
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!");
224 for (cpl_size i = 0; i < n_raws; i++) {
227 cpl_frame *frmData = cpl_frameset_get_position(fs_raws, i);
230 cpl_frameset *fs_raw_output = cpl_frameset_new();
231 cpl_frameset_insert(fs_raw_output, cpl_frame_duplicate(frmData));
234 cpl_msg_info(cpl_func,
"Configuring initial parameters in the recipe ...");
235 kmos_molecfit_correct_parameter *conf = kmos_molecfit_correct_conf(parlist);
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");
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!");
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);
289 if (suppress_extension) {
290 filename = cpl_sprintf(
"%s_%lld.fits", conf->tag_output, i);
292 filename = cpl_sprintf(
"%s_%s", conf->tag_output, cpl_propertylist_get_string(conf->pl_data,
"ARCFILE"));
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) {
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!");
307 for (cpl_size n_ifu = 0; n_ifu < N_IFUS; n_ifu++) {
308 kmos_molecfit_correct_data *ifu = &(conf->ifus[n_ifu]);
311 cpl_errorstate preState = cpl_errorstate_get();
314 cpl_error_code e_sData;
315 cpl_error_code e_sNoise = CPL_ERROR_NONE;
320 cpl_msg_info(cpl_func,
"Correcting 1D data spectrum , IFU.%02lld ...", n_ifu + 1);
321 cpl_vector_divide(ifu->vec_data, ifu->correction);
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);
326 if (ifu->vec_noise) {
328 cpl_msg_info(cpl_func,
"Correcting 1D noise spectrum, IFU.%02lld ...", n_ifu + 1);
329 cpl_vector_divide(ifu->vec_noise, ifu->correction);
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);
334 }
else if (ifu->header_ext_noise){
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);
340 }
else if (ifu->cube_data) {
343 kmclipm_vector *correction = kmclipm_vector_create(cpl_vector_duplicate(ifu->correction));
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) {
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);
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);
359 if (ifu->cube_noise) {
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) {
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);
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);
375 }
else if (ifu->header_ext_noise) {
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);
382 kmclipm_vector_delete(correction);
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);
395 if (e_sData != CPL_ERROR_NONE || e_sNoise != CPL_ERROR_NONE) {
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);
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());
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);
418 cpl_msg_info(cpl_func,
"Cleaning variables from the input file : %s", fileData);
420 kmos_molecfit_correct_clean(conf);
421 cpl_frameset_delete(fs_raw_output);
425 cpl_frameset_delete(fs_raws);
429 if (cpl_errorstate_is_equal(initial_errorstate) && cpl_error_get_code() == CPL_ERROR_NONE ) {
430 cpl_msg_info(cpl_func,
"Recipe successfully!");
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());
438 return (
int)cpl_error_get_code();
453static cpl_error_code kmos_molecfit_correct_fill_parameterlist(
454 cpl_parameterlist *self)
456 cpl_error_ensure(self, CPL_ERROR_NULL_INPUT,
return CPL_ERROR_NULL_INPUT,
"Null input");
459 cpl_errorstate prestate = cpl_errorstate_get();
463 cpl_boolean range = CPL_TRUE;
464 const void *dummyMin = NULL;
465 const void *dummyMax = NULL;
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;
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;
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!");
489 return CPL_ERROR_NONE;
502static kmos_molecfit_correct_parameter * kmos_molecfit_correct_conf(
503 const cpl_parameterlist *list)
506 cpl_error_ensure(list, CPL_ERROR_NULL_INPUT,
507 return NULL,
"kmos_molecfit_correct_fill_conf input list NULL!");
510 cpl_errorstate preState = cpl_errorstate_get();
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]);
520 ifu->header_ext_data = NULL;
521 ifu->header_ext_noise = NULL;
523 ifu->cube_data = NULL;
524 ifu->cube_noise = NULL;
526 ifu->vec_data = NULL;
527 ifu->vec_noise = NULL;
529 ifu->correction = NULL;
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);
537 if (!cpl_errorstate_is_equal(preState)) {
539 kmos_molecfit_correct_clean(conf);
558static cpl_error_code kmos_molecfit_correct_frame_conf(
559 kmos_molecfit_correct_parameter *conf,
560 cpl_frame *frmCorrection,
564 cpl_error_ensure(conf && frmCorrection && frmData, CPL_ERROR_NULL_INPUT,
565 return CPL_ERROR_NULL_INPUT,
"kmos_molecfit_correct_inputs_conf inputs NULL!");
568 cpl_errorstate initialState = cpl_errorstate_get();
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);
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));
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));
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));
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));
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));
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));
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));
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;
625 return cpl_error_set_message(cpl_func, CPL_ERROR_TYPE_MISMATCH,
626 "Tag input data unexpected: %s", tag);
630 cpl_size n_extensions_raw = cpl_fits_count_extensions(fileData);
631 cpl_size ext24_raw = (N_IFUS == n_extensions_raw) ? 1 : 2;
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);
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));
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));
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));
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));
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));
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));
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));
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));
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));
687 const char *tag_correction = cpl_frame_get_tag(frmCorrection);
690 cpl_size n_extensions_correction = cpl_fits_count_extensions(fileCorrection);
691 cpl_size ext24_correction = (N_IFUS == n_extensions_correction) ? 1 : 2;
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]);
700 cpl_size correction_ext = (n_ifu * ext24_correction) + 1;
701 cpl_size data_ext = (n_ifu * ext24_raw ) + 1;
702 cpl_size noise_ext = data_ext + 1;
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);
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);
722 if (strcmp(conf->tag_output, SINGLE_SPECTRA) == 0){
724 ifu->vec_data = cpl_vector_load(fileData, data_ext);
725 if (!(ifu->vec_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);
730 cpl_msg_info(cpl_func,
"Frame: %s --> IFU.%02lld : Loaded 1D input data!", tag, n_ifu + 1);
735 ifu->vec_noise = cpl_vector_load(fileData, noise_ext);
736 if (!(ifu->vec_noise)) {
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);
742 cpl_msg_info(cpl_func,
"Frame: %s --> IFU.%02lld : Loaded 1D input noise!", tag, n_ifu + 1);
748 }
else if (strcmp(conf->tag_output, SINGLE_CUBES) == 0){
750 ifu->cube_data = cpl_imagelist_load(fileData, CPL_TYPE_FLOAT, data_ext);
751 if (!(ifu->cube_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);
756 cpl_msg_info(cpl_func,
"Frame: %s --> IFU.%02lld : Loaded 3D input data!", tag, n_ifu + 1);
761 ifu->cube_noise = cpl_imagelist_load(fileData, CPL_TYPE_FLOAT, noise_ext);
762 if (!(ifu->cube_noise)) {
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);
768 cpl_msg_info(cpl_func,
"Frame: %s --> IFU.%02lld : Loaded 3D input noise!", tag, n_ifu + 1);
776 ifu->correction = cpl_vector_load(fileCorrection, correction_ext);
777 if (!(ifu->correction)) {
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);
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);
786 if (conf->min_threshold > 0) {
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;
791 cpl_size size = cpl_vector_get_size(ifu->correction);
792 for (cpl_size i = 0; i < size; i++) {
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);
803 if (positions_update > 0) {
804 cpl_msg_info(cpl_func,
"Telluric correction positions update with min_threshold = %lld]", positions_update);
812 if (!cpl_errorstate_is_equal(initialState)) {
814 return cpl_error_get_code();
817 return CPL_ERROR_NONE;
827static void kmos_molecfit_correct_clean(
828 kmos_molecfit_correct_parameter *conf)
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);
836 for (cpl_size n_ifu = 0; n_ifu < N_IFUS; n_ifu ++) {
837 kmos_molecfit_correct_data *ifu = &(conf->ifus[n_ifu]);
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);
842 if (ifu->cube_data) cpl_imagelist_delete( ifu->cube_data);
843 if (ifu->cube_noise) cpl_imagelist_delete( ifu->cube_noise);
845 if (ifu->vec_data) cpl_vector_delete( ifu->vec_data);
846 if (ifu->vec_noise) cpl_vector_delete( ifu->vec_noise);
848 if (ifu->correction) cpl_vector_delete( ifu->correction);