30#include "kmos_molecfit.h"
38#define KMOS_MOLECFIT_CALCULE_COLUMN_NF "NF"
39#define KMOS_MOLECFIT_CALCULE_COLUMN_NTF "NTF"
41#define KMOS_MOLECFIT_RESULTS_ROW_RMS_REL_TO_MEAN "rms_rel_to_mean"
42#define KMOS_MOLECFIT_RESULTS_ROW_RMS_STATUS "status"
43#define KMOS_MOLECFIT_RESULTS_ROW_RMS_H2O_COL_MM "h2o_col_mm"
45#define KMOS_MOLECFIT_QC_PARAM_RMS "ESO QC RMS"
46#define KMOS_MOLECFIT_QC_PARAM_STATUS "ESO QC STATUS"
47#define KMOS_MOLECFIT_QC_PARAM_H2O "ESO QC H2O"
48#define KMOS_MOLECFIT_QC_PARAM_IMPROV "ESO QC IMPROV"
50#define KMOS_MOLECFIT_QC_PARAM_RMS_TXT "Molecfit best_fit parameter rms_rel_to_mean"
51#define KMOS_MOLECFIT_QC_PARAM_STATUS_TXT "Molecfit best_fit parameter status"
52#define KMOS_MOLECFIT_QC_PARAM_H2O_TXT "Molecfit best_fit parameter h2o_col_mm"
53#define KMOS_MOLECFIT_QC_PARAM_IMPROV_TXT "Computed from the Molecfit model columns flux, mscal, mtrans"
99 kmos_molecfit_parameter mf;
100 const char *process_ifus;
106} kmos_molecfit_model_parameter;
116static cpl_error_code kmos_molecfit_model_check_wave_molec_conf(
117 kmos_grating *grating);
120static kmos_molecfit_model_parameter * kmos_molecfit_model_conf(
121 const cpl_parameterlist *list);
124static cpl_table * kmos_molecfit_model_get_gdas_profile(
125 cpl_frameset *frameset);
128static cpl_table * kmos_molecfit_model_get_atm_profile_standard(
129 cpl_frameset *frameset);
132static cpl_error_code kmos_molecfit_model_mf_conf(
133 kmos_molecfit_model_parameter *conf,
135 kmos_grating_type type,
136 mf_parameters_config *config_parameters);
139static void kmos_molecfit_model_clean(
140 kmos_molecfit_model_parameter *conf);
143static cpl_error_code kmos_molecfit_model_headers_fill_qc_parameters(
144 const cpl_table *res_table,
145 const cpl_table *spec_out,
146 cpl_propertylist *pl_BParms,
147 cpl_propertylist *pl_BModel,
151 cpl_vector *qc_improv,
162#define RECIPE_NAME KMOS_MOLECFIT_MODEL
163#define CONTEXT "kmos."RECIPE_NAME
165static char kmos_molecfit_model_description[] =
166 "This recipe runs molecfit on a 1D spectrum and the input data can have category: \n"
167 " - STAR_SPEC (24 DATA plus 24 NOISE extensions)\n"
168 " - EXTRACT_SPEC (24 DATA extensions, additional 24 NOISE extensions are optional)\n"
169 " - SCIENCE (24 DATA extensions, additional 24 NOISE extensions are optional)\n"
170 " - SCI_RECONSTRUCTED (24 DATA extensions, additional 24 NOISE extensions are optional)\n"
171 "It is not mandatory that all the DATA extension contains data.\n"
172 "Molecfit will be run on all the extension that contain data (not noise extensions). \n"
173 "The recipe also accepts as input a kernel library, e.g. the information of the spectral resolution for each IFU and each rotator angle. \n"
174 "When the recipe executes molecfit on the i-th IFU, the kernel in the library that matches the IFU number and rotator angle is used. \n"
175 "If no kernel are provided, each time the recipe runs molecfit, the kernel is considered as a free parameter and it will be determined by molecfit itself and stored into the BEST_FIT_PARM output. \n"
177 "Input files: (It's mandatory to provide 1 file only of type A) \n"
180 " category Type required Explanation \n"
181 " -------- ----- -------- ----------- \n"
182 " STAR_SPEC F1I A The spectrum (1D spectrum, IMAGE format).\n"
183 " EXTRACT_SPEC F1I A The spectrum (1D spectrum, IMAGE format).\n"
184 " SCIENCE F3I A The spectrum (3D cube, IMAGE format).\n"
185 " SCI_RECONSTRUCTED F3I A The spectrum (3D cube, IMAGE format).\n"
186 " KERNEL_LIBRARY F2I N The kernel library; must be the same grating as the other inputs.\n"
187 " GDAS F1L N User define GDAS profile (fits table).\n"
192 " category Type Explanation \n"
193 " -------- ----- ----------- \n"
194 " GDAS F1L Used GDAS profile (fits table).\n"
195 " GDAS_BEFORE F1L If ESO DB GDAS is used, file before the MJD-OBS (fits table).\n"
196 " GDAS_AFTER F1L If ESO DB GDAS is used, file after the MJD-OBS (fits table).\n"
197 " ATM_PROF_STANDARD F1L Atmospheric profile standard. (fits table).\n"
198 " ATM_PROF_COMBINED F1L Atmospheric profile combined with GDAS. (fits table).\n"
199 " ATMOS_PARM F1L Atmospheric parameters (multiextension fits table).\n"
200 " BEST_FIT_PARM F1L Best fitting parameters (multiextension fits table).\n"
201 " BEST_FIT_MODEL F1L Best fit model and intermediate products (multiextension fits table).\n"
202 " MODEL_KERNEL_LIBRARY F2I The kernel library used in Molecfit; if user provide kernel inputs. \n"
206cpl_recipe_define( kmos_molecfit_model,
208 "Jose A. Escartin, Yves Jung",
209 "https://support.eso.org/",
211 "Run molecfit on set of 1D spectra to compute an atmospheric model.",
212 kmos_molecfit_model_description);
241static int kmos_molecfit_model(
242 cpl_frameset *frameset,
const cpl_parameterlist *parlist)
245 if (kmos_check_and_set_groups(frameset) != CPL_ERROR_NONE) {
246 return cpl_error_get_code();
250 cpl_errorstate initial_errorstate = cpl_errorstate_get();
253 cpl_msg_info(cpl_func,
"Configuring initial parameters in the recipe ...");
254 kmos_molecfit_model_parameter *conf = kmos_molecfit_model_conf(parlist);
255 cpl_error_ensure(conf, CPL_ERROR_ILLEGAL_INPUT,
256 return (
int)CPL_ERROR_ILLEGAL_INPUT,
"Problems with the configuration parameters");
257 if (!(conf->mf.fit_wavelenght.fit)) cpl_msg_info(cpl_func,
"Not fit wavelength!");
258 if (!(conf->mf.fit_continuum.fit) ) cpl_msg_info(cpl_func,
"Not fit continuum!" );
262 if(kmos_molecfit_load_spectrums(frameset, &(conf->mf), RECIPE_NAME) != CPL_ERROR_NONE) {
263 kmos_molecfit_model_clean(conf);
264 return (
int)cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
265 "Loading spectrums data in the input frameset failed!");
269 const cpl_frame *frmKernel = cpl_frameset_find(frameset, KERNEL_LIBRARY);
270 cpl_error_code sKernels_e;
271 if (frmKernel && conf->mf.use_input_kernel) {
273 if(kmos_molecfit_load_kernels(frmKernel, &(conf->mf)) != CPL_ERROR_NONE) {
274 kmos_molecfit_model_clean(conf);
275 return (
int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
276 "Loading convolution kernel data in the input frameset failed!");
279 sKernels_e = kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, conf->mf.parms, MODEL_KERNEL_LIBRARY, conf->mf.grating.name, conf->mf.suppress_extension, NULL);
280 if (sKernels_e != CPL_ERROR_NONE){
281 kmos_molecfit_model_clean(conf);
282 return (
int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
283 "Saving generic multi-extension output fits file ('%s') failed!",
284 MODEL_KERNEL_LIBRARY);
290 cpl_msg_warning(cpl_func,
"Kernel is provided, but use_input_kernel = false !");
291 }
else if (conf->mf.use_input_kernel){
292 cpl_msg_warning(cpl_func,
"Kernel isn't provided, but use_input_kernel = true !");
295 cpl_msg_info(cpl_func,
"Using the default molecfit kernels!");
296 cpl_msg_info(cpl_func,
"Fit resolution by Boxcar (--fit_res_box ) = %d", conf->boxcar.fit );
297 cpl_msg_info(cpl_func,
"Fit resolution by Gaussian (--fit_res_gauss ) = %d", conf->gauss.fit );
298 cpl_msg_info(cpl_func,
"Fit resolution by Lorentz (--fit_res_lorentz) = %d", conf->lorentz.fit);
303 cpl_msg_info(cpl_func,
" +++ All input data loaded successfully! +++");
309 cpl_propertylist_update_string(conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_PROCESS_IFUS, conf->process_ifus);
311 cpl_propertylist_update_bool( conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_SUPPRESS_EXTENSION, conf->mf.suppress_extension);
313 cpl_propertylist_update_string(conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_WRANGE, conf->mf.grating.wave_range);
314 cpl_propertylist_update_string(conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_LIST, conf->mf.grating.list_molec);
315 cpl_propertylist_update_string(conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_FIT, conf->mf.grating.fit_molec);
316 cpl_propertylist_update_string(conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_RELATIVE_VALUE, conf->mf.grating.rel_col);
318 cpl_propertylist_update_double(conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_FTOL, conf->ftol);
319 cpl_propertylist_update_double(conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_XTOL, conf->xtol);
321 cpl_propertylist_update_bool( conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_FIT_CONTINUUM, conf->mf.fit_continuum.fit);
322 cpl_propertylist_update_int( conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_CONTINUUM_N, conf->mf.fit_continuum.n);
324 cpl_propertylist_update_bool( conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_FIT_WLC, conf->mf.fit_wavelenght.fit);
325 cpl_propertylist_update_int( conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_WLC_N, conf->mf.fit_wavelenght.n);
326 cpl_propertylist_update_double(conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_WLC_CONST, conf->mf.fit_wavelenght.const_val);
328 cpl_propertylist_update_bool( conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_USE_INPUT_KERNEL, conf->mf.use_input_kernel);
330 cpl_propertylist_update_bool( conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_KERN_MODE, conf->mf.kernmode);
331 cpl_propertylist_update_double(conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_KERN_FAC, conf->mf.kernfac);
332 cpl_propertylist_update_bool( conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_VAR_KERN, conf->mf.varkern);
334 cpl_propertylist_update_bool( conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_FIT_RES_BOX, conf->boxcar.fit);
335 cpl_propertylist_update_double(conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_RES_BOX, conf->boxcar.res);
337 cpl_propertylist_update_bool( conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_FIT_GAUSS, conf->gauss.fit);
338 cpl_propertylist_update_double(conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_RES_GAUSS, conf->gauss.res);
340 cpl_propertylist_update_bool( conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_FIT_LORENTZ, conf->lorentz.fit);
341 cpl_propertylist_update_double(conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_RES_LORENTZ, conf->lorentz.res);
345 cpl_msg_info(cpl_func,
"Saving generic multi-extension output fits file ('%s','%s','%s') ...",
346 ATMOS_PARM, BEST_FIT_PARM, BEST_FIT_MODEL);
347 const char * atmos_file =
"atmos_param_pre.fits";
348 const char * bfp_file =
"best_fit_param_pre.fits";
349 const char * bfm_file =
"best_fit_model_pre.fits";
350 cpl_error_code sAtm_e = cpl_propertylist_save(conf->mf.header_spectrums, atmos_file, CPL_IO_CREATE);
352 cpl_error_code sBParms_e = cpl_propertylist_save(conf->mf.header_spectrums, bfp_file, CPL_IO_CREATE);
354 cpl_error_code sBModel_e = cpl_propertylist_save(conf->mf.header_spectrums, bfm_file, CPL_IO_CREATE);
356 if (sAtm_e != CPL_ERROR_NONE || sBParms_e != CPL_ERROR_NONE || sBModel_e != CPL_ERROR_NONE) {
357 kmos_molecfit_model_clean(conf);
358 return (
int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
359 "Saving generic multi-extension output fits files ('%s','%s','%s') failed!",
360 ATMOS_PARM, BEST_FIT_PARM, BEST_FIT_MODEL);
364 cpl_error_code err = CPL_ERROR_NONE;
367 mf_configuration *mf_config = mf_configuration_create();
372 cpl_msg_info(cpl_func,
"Sorting the chips and ranges flags");
375 cpl_boolean flag= conf->mf.fit_wavelenght.fit;
376 int order = conf->mf.fit_wavelenght.n;
378 cpl_msg_info(cpl_func,
"Fitting wavlength corrections with polynomial of order %d",order);
379 for (
int i=0; i<MF_PARAMETERS_MAXIMUM_NO_OF_CHIPS; i++) {
380 mf_config->parameters->fitting.fit_chips[i]=CPL_TRUE;
385 flag = conf->mf.fit_continuum.fit;
386 order = conf->mf.fit_continuum.n;
388 cpl_msg_info(cpl_func,
"Fitting contiuum model for each range with polynomials of order %d ", order);
389 for (
int i=0; i<MF_PARAMETERS_MAXIMUM_NO_OF_RANGES; i++) {
390 mf_config->parameters->fitting.fit_ranges[i]=CPL_TRUE;
391 mf_config->parameters->fitting.cont_poly_order[i]=order;
400 if (!mf_config) err = CPL_ERROR_NULL_INPUT;
403 err = mf_parameters_config_update_with_header_keywords(mf_config->parameters, conf->mf.header_spectrums);
404 if (err != CPL_ERROR_NONE) {
405 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
406 "Error updating molecfit parameters with the raw primary header configuration");
410 cpl_msg_info(cpl_func,
"Checking if %s user profile provided ...", GDAS);
411 cpl_boolean gdas_write = CPL_FALSE;
412 cpl_table *gdas_user = kmos_molecfit_model_get_gdas_profile(frameset);
415 cpl_msg_info(cpl_func,
"Checking if %s user provided ...", ATM_PROFILE_STANDARD);
416 cpl_boolean atm_profile_standard_write = CPL_FALSE;
417 cpl_table *atm_profile_standard = kmos_molecfit_model_get_atm_profile_standard(frameset);
418 cpl_table *atm_profile_combined = NULL;
420 cpl_vector * qc_zpt = cpl_vector_new(N_IFUS);
421 cpl_vector * qc_h2o = cpl_vector_new(N_IFUS);
422 cpl_vector * qc_rms = cpl_vector_new(N_IFUS);
423 cpl_vector * qc_improv = cpl_vector_new(N_IFUS);
428 cpl_size n_procesed_ifus = 0;
429 kmos_grating *grating = &(conf->mf.grating);
430 char * gdas_avail =
"F";
434 for (cpl_size i = 0; i < N_IFUS; i++) {
436 kmos_spectrum *ifu = &(conf->mf.ifus[i]);
439 mf_model_results *results = NULL;
442 cpl_propertylist *pl_BParms = cpl_propertylist_duplicate(ifu->header_ext_data);
443 cpl_propertylist *pl_BModel = cpl_propertylist_duplicate(ifu->header_ext_data);
446 if (ifu->process && ifu->data) {
454 cpl_msg_info(cpl_func,
"Building molecfict configuration variable in %s ...", ifu->name);
457 if (!err) err = kmos_molecfit_model_mf_conf(conf, ifu, grating->type, mf_config->parameters);
462 cpl_msg_info(cpl_func,
"MNB About to call mf_model, err=%d", err);
466 cpl_table *spec_telluriccorr_lblrtm = mf_spectrum_create(mf_config->parameters, ifu->data);
469 cpl_msg_info(cpl_func,
"Call mf_model(...) in %s ...", ifu->name);
470 results = mf_model( mf_config,
472 ifu->header_ext_data,
473 spec_telluriccorr_lblrtm,
474 grating->incl_wave_ranges,
477 ifu->kernel.header_ext_data,
480 atm_profile_standard,
481 atm_profile_combined);
483 cpl_table_delete(spec_telluriccorr_lblrtm);
485 cpl_msg_info(cpl_func,
"GDAS source for IFU 1= %s", results->gdas_src );
486 if (strcmp(results->gdas_src,
"REPOSITORY")) {
492 err = cpl_error_get_code();
502 err = kmos_molecfit_model_headers_fill_qc_parameters(results->res, results->spec, pl_BParms, pl_BModel,
503 qc_zpt, qc_h2o, qc_rms, qc_improv , n_procesed_ifus);
506 cpl_msg_info(cpl_func,
"Molecfit call mf_model(...) run successfully! in %s ...", ifu->name);
508 cpl_msg_info(cpl_func,
"Dumping BEST FIT MODEL Propertylist");
510 cpl_msg_info(cpl_func,
"Dumping BEST FIT PARAM Propertylist");
517 cpl_msg_warning(cpl_func,
"Molecfit call mf_model(...) run Error! in %s ... %s", ifu->name, cpl_error_get_message());
520 if (!cpl_errorstate_is_equal(initial_errorstate)) cpl_errorstate_set(initial_errorstate);
521 err = CPL_ERROR_NONE;
532 if ( !(ifu->data) ) cpl_msg_info( cpl_func,
"Saving data IFU=%d ...", ifu->num);
533 else if (!(ifu->process)) cpl_msg_info( cpl_func,
"Saving data IFU=%d ... (data spectrum -> But not processed)", ifu->num);
534 else if (!results) cpl_msg_warning(cpl_func,
"Saving data IFU=%d ... (data spectrum -> But failed Molecfit!)", ifu->num);
535 else cpl_msg_info( cpl_func,
"Saving data IFU=%d ... (data spectrum -> Molecfit executed)", ifu->num);
539 if (results && !gdas_write) {
543 if (results->gdas_interpolate) {
545 cpl_msg_info(cpl_func,
"Saving Molecfit output user provide fits files ('%s') ... [only first call to Molecfit!]",
548 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, conf->mf.parms, GDAS, NULL, CPL_TRUE, NULL);
549 cpl_table_save(results->gdas_interpolate, NULL, conf->mf.header_spectrums, GDAS
".fits", CPL_IO_EXTEND);
552 gdas_write = CPL_TRUE;
554 if (cpl_error_get_code() != CPL_ERROR_NONE) {
555 cpl_error_set_message(cpl_func, cpl_error_get_code(),
556 "Saving Molecfit output GDAS user provide fits file ('%s') failed!",
561 }
else if (results->gdas_before && results->gdas_after && results->gdas_interpolate) {
563 cpl_msg_info(cpl_func,
"Saving Molecfit output GDAS automatic fits files ('%s','%s','%s') ... [only first call to Molecfit!]",
564 GDAS_BEFORE, GDAS_AFTER, GDAS);
566 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, conf->mf.parms, GDAS_BEFORE, NULL, CPL_FALSE, NULL);
567 cpl_table_save(results->gdas_before, NULL, conf->mf.header_spectrums, GDAS_BEFORE
".fits", CPL_IO_EXTEND);
569 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, conf->mf.parms, GDAS_AFTER, NULL, CPL_FALSE, NULL);
570 cpl_table_save(results->gdas_after, NULL, conf->mf.header_spectrums, GDAS_AFTER
".fits", CPL_IO_EXTEND);
572 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, conf->mf.parms, GDAS, NULL, CPL_FALSE, NULL);
573 cpl_table_save(results->gdas_interpolate, NULL, conf->mf.header_spectrums, GDAS
".fits", CPL_IO_EXTEND);
576 gdas_user = cpl_table_duplicate(results->gdas_interpolate);
578 gdas_write = CPL_TRUE;
580 if (cpl_error_get_code() != CPL_ERROR_NONE) {
581 cpl_error_set_message(cpl_func, cpl_error_get_code(),
582 "Saving Molecfit output GDAS automatic fits files ('%s','%s','%s') failed!",
583 GDAS_BEFORE, GDAS_AFTER, GDAS);
589 if (results && !atm_profile_standard_write) {
591 if (atm_profile_standard) {
593 if (results->atm_profile_standard) {
595 cpl_msg_info(cpl_func,
"Saving Molecfit output user provide fits files ('%s') ... [only first call to Molecfit!]",
596 ATM_PROFILE_STANDARD);
598 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, conf->mf.parms, ATM_PROFILE_STANDARD, NULL, CPL_FALSE, NULL);
599 cpl_table_save(results->atm_profile_standard, NULL, conf->mf.header_spectrums, ATM_PROFILE_STANDARD
".fits", CPL_IO_EXTEND);
601 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, conf->mf.parms, ATM_PROFILE_COMBINED, NULL, CPL_FALSE, NULL);
602 cpl_table_save(results->atm_profile_combined, NULL, conf->mf.header_spectrums, ATM_PROFILE_COMBINED
".fits", CPL_IO_EXTEND);
604 atm_profile_combined = cpl_table_duplicate(results->atm_profile_combined);
606 atm_profile_standard_write = CPL_TRUE;
608 if (cpl_error_get_code() != CPL_ERROR_NONE) {
609 cpl_error_set_message(cpl_func, cpl_error_get_code(),
610 "Saving Molecfit output user provide fits file ('%s') failed!",
611 ATM_PROFILE_STANDARD);
615 }
else if (results->atm_profile_standard) {
617 cpl_msg_info(cpl_func,
"Saving Molecfit output ATM_PROFILE automatic fits files ('%s','%s') ... [only first call to Molecfit!]",
618 ATM_PROFILE_STANDARD, ATM_PROFILE_COMBINED);
620 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, conf->mf.parms, ATM_PROFILE_STANDARD, NULL, CPL_FALSE, NULL);
621 cpl_table_save(results->atm_profile_standard, NULL, conf->mf.header_spectrums, ATM_PROFILE_STANDARD
".fits", CPL_IO_EXTEND);
623 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, conf->mf.parms, ATM_PROFILE_COMBINED, NULL, CPL_FALSE, NULL);
624 cpl_table_save(results->atm_profile_combined, NULL, conf->mf.header_spectrums, ATM_PROFILE_COMBINED
".fits", CPL_IO_EXTEND);
627 atm_profile_standard = cpl_table_duplicate(results->atm_profile_standard);
628 atm_profile_combined = cpl_table_duplicate(results->atm_profile_combined);
630 atm_profile_standard_write = CPL_TRUE;
632 if (cpl_error_get_code() != CPL_ERROR_NONE) {
633 cpl_error_set_message(cpl_func, cpl_error_get_code(),
634 "Saving Molecfit output GDAS automatic fits files ('%s','%s') failed!",
635 ATM_PROFILE_STANDARD, ATM_PROFILE_COMBINED);
640 cpl_table *atm_profile_fitted = results ? results->atm_profile_fitted : NULL;
641 cpl_table *spec = results ? results->spec : NULL;
642 cpl_table *res = results ? results->res : NULL;
644 sAtm_e = kmos_molecfit_save_mf_results(ifu->header_ext_data, ifu->header_ext_noise, ATMOS_PARM, conf->mf.grating.name, conf->mf.suppress_extension, atmos_file, NULL, atm_profile_fitted, NULL);
646 sBModel_e = kmos_molecfit_save_mf_results(pl_BModel, ifu->header_ext_noise, BEST_FIT_MODEL, conf->mf.grating.name, conf->mf.suppress_extension, bfm_file, NULL, spec, NULL);
648 sBParms_e = kmos_molecfit_save_mf_results(pl_BParms, ifu->header_ext_noise, BEST_FIT_PARM, conf->mf.grating.name, conf->mf.suppress_extension, bfp_file, NULL, res, NULL);
651 if (sAtm_e != CPL_ERROR_NONE || sBModel_e != CPL_ERROR_NONE || sBParms_e != CPL_ERROR_NONE || sKernels_e != CPL_ERROR_NONE) {
652 err = cpl_error_set_message(cpl_func, cpl_error_get_code(),
653 "Saving Molecfit output fits files ('%s','%s','%s') failed!",
654 ATMOS_PARM, BEST_FIT_MODEL, BEST_FIT_PARM);
657 if (frmKernel && conf->mf.use_input_kernel) {
659 cpl_propertylist *header_kernel_data = ifu->kernel.header_ext_data ? ifu->kernel.header_ext_data : ifu->header_ext_data;
660 cpl_propertylist *header_kernel_noise = ifu->kernel.header_ext_noise ? ifu->kernel.header_ext_noise : ifu->header_ext_noise;
662 cpl_matrix *kernel = NULL;
664 if (results->kernel) kernel = results->kernel;
667 sKernels_e = kmos_molecfit_save_mf_results(header_kernel_data, header_kernel_noise,
668 MODEL_KERNEL_LIBRARY, conf->mf.grating.name, conf->mf.suppress_extension, NULL, kernel, NULL, NULL);
670 if (sKernels_e != CPL_ERROR_NONE) {
671 err = cpl_error_set_message(cpl_func, cpl_error_get_code(),
672 "Saving Molecfit output fits file ('%s') failed!",
673 MODEL_KERNEL_LIBRARY);
679 mf_model_results_delete(results);
680 cpl_propertylist_delete(pl_BParms);
681 cpl_propertylist_delete(pl_BModel);
686 cpl_msg_info(cpl_func,
"Calculating QC Parameters");
688 cpl_propertylist* qc_atmos = kmclipm_propertylist_load(atmos_file, 0);
689 cpl_propertylist* qc_bfp = kmclipm_propertylist_load(bfp_file, 0);
690 cpl_propertylist* qc_bfm = kmclipm_propertylist_load(bfm_file, 0);
706 qc_zpt = cpl_vector_extract(qc_zpt, 0, n_procesed_ifus-1,1);
707 qc_h2o = cpl_vector_extract(qc_h2o, 0, n_procesed_ifus-1,1);
708 qc_rms = cpl_vector_extract(qc_rms, 0, n_procesed_ifus-1,1);
709 qc_improv = cpl_vector_extract(qc_improv, 0, n_procesed_ifus-1,1);
711 double zpt_avg = cpl_vector_get_mean(qc_zpt);
712 double zpt_rms = cpl_vector_get_stdev(qc_zpt);
713 double rms_avg = cpl_vector_get_mean(qc_rms);
714 double rms_rms = cpl_vector_get_stdev(qc_rms);
715 double h2o_avg = cpl_vector_get_mean(qc_h2o);
716 double h2o_rms = cpl_vector_get_stdev(qc_h2o);
717 double improv_avg = cpl_vector_get_mean(qc_improv);
718 double improv_rms = cpl_vector_get_stdev(qc_improv);
719 double meas_iwv =0.0, meas_iwv30d = 0.0;
723 double lon = mf_config->parameters->ambient.longitude.value;
724 double lat = mf_config->parameters->ambient.latitude.value;
725 char *global_gdas_path = cpl_sprintf(
"%s/%s", mf_config->parameters->directories.telluriccorr_data_path, MF_PROFILES_GDAS_PATH);
728 char * gdas_tarball_name = cpl_sprintf(
"gdas_profiles_C%+.1f%+.1f.tar.gz", lon, lat);
729 char * global_gdas_tarball = cpl_sprintf(
"%s/%s",global_gdas_path, gdas_tarball_name);
731 if (access(global_gdas_tarball, F_OK) == CPL_ERROR_NONE) {
734 cpl_msg_info(cpl_func,
"The GDAS file name - %s ",global_gdas_tarball );
735 cpl_msg_info(cpl_func,
"The GDAS Profile was found in the REPO ");
741 if (cpl_propertylist_has(qc_bfm,
"ESO TEL AMBI IWV START") &&
742 cpl_propertylist_has(qc_bfm,
"ESO TEL AMBI IWV END")){
743 meas_iwv = (cpl_propertylist_get_double(qc_bfm,
"ESO TEL AMBI IWV END")+
744 cpl_propertylist_get_double(qc_bfm,
"ESO TEL AMBI IWV START"))/2.0;
745 kmclipm_update_property_double(qc_bfm,QC_PARAM_MEAS_IWV,
746 meas_iwv, QC_PARAM_MEAS_IWV_TXT);
749 if (cpl_propertylist_has(qc_bfm,
"ESO TEL AMBI IWV30D START") &&
750 cpl_propertylist_has(qc_bfm,
"ESO TEL AMBI IWV30D END")){
751 meas_iwv30d = (cpl_propertylist_get_double(qc_bfm,
"ESO TEL AMBI IWV30D END")+
752 cpl_propertylist_get_double(qc_bfm,
"ESO TEL AMBI IWV30D START"))/2.0;
753 kmclipm_update_property_double(qc_bfm, QC_PARAM_MEAS_IWV30D,
754 meas_iwv30d, QC_PARAM_MEAS_IWV30D_TXT);
757 if (cpl_propertylist_has(kmo_dfs_load_primary_header(frameset,
"STAR_SPEC"),
760 int nr_std_str= cpl_propertylist_get_int(kmo_dfs_load_primary_header(frameset,
"STAR_SPEC"), QC_NR_STD_STARS);
762 kmclipm_update_property_int(qc_bfm, QC_NR_STD_STARS, nr_std_str, QC_NR_STD_STARS_TXT);
763 kmclipm_update_property_int(qc_bfp, QC_NR_STD_STARS, nr_std_str, QC_NR_STD_STARS_TXT);
764 kmclipm_update_property_int(qc_atmos, QC_NR_STD_STARS, nr_std_str, QC_NR_STD_STARS_TXT);
768 kmclipm_update_property_double(qc_atmos, QC_PARAM_ZPT_AVG,
769 zpt_avg, QC_PARAM_ZPT_AVG_TXT);
770 kmclipm_update_property_double(qc_atmos, QC_PARAM_ZPT_RMS,
771 zpt_rms, QC_PARAM_ZPT_RMS_TXT);
772 cpl_msg_info(cpl_func,
"atmos primary header updated");
774 kmclipm_update_property_double(qc_bfm, QC_PARAM_ZPT_AVG,
775 zpt_avg, QC_PARAM_ZPT_AVG_TXT);
776 kmclipm_update_property_double(qc_bfm, QC_PARAM_ZPT_RMS,
777 zpt_rms, QC_PARAM_ZPT_RMS_TXT);
778 kmclipm_update_property_double(qc_bfm, QC_PARAM_IMPROV_AVG,
779 improv_avg, QC_PARAM_IMPROV_AVG_TXT);
780 kmclipm_update_property_double(qc_bfm, QC_PARAM_IMPROV_RMS,
781 improv_rms, QC_PARAM_IMPROV_RMS_TXT);
782 cpl_msg_info(cpl_func,
"best fit params primary header updated");
785 kmclipm_update_property_string(qc_bfp, QC_PARAM_GDAS,
786 gdas_avail, QC_PARAM_GDAS_TXT);
787 kmclipm_update_property_int(qc_bfp, QC_PARAM_FLAG_GDAS,
788 gdas_flag, QC_PARAM_FLAG_GDAS_TXT);
789 kmclipm_update_property_double(qc_bfp, QC_PARAM_ZPT_AVG,
790 zpt_avg, QC_PARAM_ZPT_AVG_TXT);
791 kmclipm_update_property_double(qc_bfp, QC_PARAM_ZPT_RMS,
792 zpt_rms, QC_PARAM_ZPT_RMS_TXT);
793 kmclipm_update_property_double(qc_bfp, QC_PARAM_H2O_AVG,
794 h2o_avg, QC_PARAM_H2O_AVG_TXT);
795 kmclipm_update_property_double(qc_bfp, QC_PARAM_H2O_RMS,
796 h2o_rms, QC_PARAM_H2O_RMS_TXT);
797 kmclipm_update_property_double(qc_bfp, QC_PARAM_RMS_AVG,
798 rms_avg, QC_PARAM_RMS_AVG_TXT);
799 kmclipm_update_property_double(qc_bfp, QC_PARAM_RMS_RMS,
800 rms_rms, QC_PARAM_RMS_RMS_TXT);
802 kmclipm_update_property_double(qc_bfm, QC_PARAM_H2O_RELRMS,
803 (h2o_rms/h2o_avg), QC_PARAM_H2O_RELRMS_TXT);
804 kmclipm_update_property_double(qc_bfp, QC_PARAM_H2O_RELRMS,
805 (h2o_rms/h2o_avg), QC_PARAM_H2O_RELRMS_TXT);
808 if (cpl_propertylist_has(qc_bfm,
"ESO TEL AMBI IWV START")){
809 kmclipm_update_property_double(qc_bfm, QC_PARAM_H2O_DELTA,
810 (h2o_avg-meas_iwv), QC_PARAM_H2O_DELTA_TXT);
811 kmclipm_update_property_double(qc_bfp, QC_PARAM_H2O_DELTA,
812 (h2o_avg-meas_iwv), QC_PARAM_H2O_DELTA_TXT);
825 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, qc_atmos, ATMOS_PARM, conf->mf.grating.name, conf->mf.suppress_extension, NULL);
827 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, qc_bfp, BEST_FIT_PARM, conf->mf.grating.name, conf->mf.suppress_extension, NULL);
829 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, qc_bfm, BEST_FIT_MODEL, conf->mf.grating.name, conf->mf.suppress_extension, NULL);
831 const char * suffix=
"";
833 if (!conf->mf.suppress_extension) {
835 cpl_msg_info(cpl_func,
"need to find a suffix ! ");
837 suffix = kmo_dfs_get_suffix(kmo_dfs_get_frame(frameset, ATMOS_PARM), TRUE, FALSE);
841 for (cpl_size i = 1; i <= N_IFUS; i++) {
845 cpl_propertylist* sub_header_atmos = kmclipm_propertylist_load(atmos_file,j);
846 cpl_propertylist* sub_header_bfp = kmclipm_propertylist_load(bfp_file,j);
847 cpl_propertylist* sub_header_bfm = kmclipm_propertylist_load(bfm_file,j);
849 cpl_propertylist* sub_header_atmos_noise = kmclipm_propertylist_load(atmos_file,j+1);
850 cpl_propertylist* sub_header_bfp_noise = kmclipm_propertylist_load(bfp_file,j+1);
851 cpl_propertylist* sub_header_bfm_noise = kmclipm_propertylist_load(bfm_file,j+1);
854 cpl_table * atmos_tbl = kmclipm_table_load( atmos_file, j, 0 );
855 if (atmos_tbl == NULL){
856 kmos_all_clean_plist(sub_header_atmos) ;
857 kmos_all_clean_plist(sub_header_atmos_noise) ;
859 cpl_table * bfp_tbl = kmclipm_table_load( bfp_file, j, 0);
860 if (bfp_tbl == NULL){
861 kmos_all_clean_plist(sub_header_bfp) ;
862 kmos_all_clean_plist(sub_header_bfp_noise) ;
864 cpl_table * bfm_tbl = kmclipm_table_load( bfm_file, j, 0);
865 if (bfm_tbl == NULL){
866 kmos_all_clean_plist(sub_header_bfm) ;
867 kmos_all_clean_plist(sub_header_bfm_noise) ;
870 cpl_table * atmos_tbl_noise = kmclipm_table_load( atmos_file, j+1, 0 );
871 cpl_table * bfp_tbl_noise = kmclipm_table_load( bfp_file, j+1, 0);
872 cpl_table * bfm_tbl_noise = kmclipm_table_load( bfm_file, j+1, 0);
876 sAtm_e = kmo_dfs_save_table(atmos_tbl, ATMOS_PARM, suffix ,sub_header_atmos);
877 sBModel_e = kmo_dfs_save_table(bfm_tbl, BEST_FIT_MODEL, suffix ,sub_header_bfm);
878 sBParms_e = kmo_dfs_save_table(bfp_tbl, BEST_FIT_PARM, suffix ,sub_header_bfp);
880 sAtm_e = kmo_dfs_save_table(atmos_tbl_noise, ATMOS_PARM, suffix ,sub_header_atmos_noise);
881 sBModel_e = kmo_dfs_save_table(bfm_tbl_noise, BEST_FIT_MODEL, suffix ,sub_header_bfm_noise);
882 sBParms_e = kmo_dfs_save_table(bfp_tbl_noise, BEST_FIT_PARM, suffix ,sub_header_bfp_noise);
884 cpl_propertylist_delete(sub_header_atmos);
885 cpl_propertylist_delete(sub_header_bfp);
886 cpl_propertylist_delete(sub_header_bfm);
888 cpl_propertylist_delete(sub_header_atmos_noise);
889 cpl_propertylist_delete(sub_header_bfp_noise);
890 cpl_propertylist_delete(sub_header_bfm_noise);
892 cpl_table_delete(atmos_tbl);
893 cpl_table_delete(bfm_tbl);
894 cpl_table_delete(bfp_tbl);
896 cpl_table_delete(atmos_tbl_noise);
897 cpl_table_delete(bfm_tbl_noise);
898 cpl_table_delete(bfp_tbl_noise);
911 if (gdas_user) cpl_table_delete(gdas_user);
912 if (atm_profile_standard) cpl_table_delete(atm_profile_standard);
913 if (atm_profile_combined) cpl_table_delete(atm_profile_combined);
914 if (mf_config) mf_configuration_delete(mf_config);
921 if (err != CPL_ERROR_NONE) {
922 kmos_molecfit_model_clean(conf);
923 return cpl_error_set_message(cpl_func, err,
924 "Call to Molecfit (MF_MODEL) failed, err_str: %s",
925 cpl_error_get_message());
929 cpl_msg_info(cpl_func,
"Cleaning variables ...");
930 kmos_molecfit_model_clean(conf);
933 cpl_msg_info(cpl_func,
"Check errorstate ...");
934 if (cpl_errorstate_is_equal(initial_errorstate) && cpl_error_get_code() == CPL_ERROR_NONE ) {
935 cpl_msg_info(cpl_func,
"Recipe successfully!, Number of IFUs processed (with data): %lld", n_procesed_ifus);
939 cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);
940 cpl_msg_info(cpl_func,
"Recipe failed!, error(%d)=%s", cpl_error_get_code(), cpl_error_get_message());
943 cpl_msg_info(cpl_func,
"Finish recipe. Returning ...");
944 return (
int)cpl_error_get_code();
959static cpl_error_code kmos_molecfit_model_fill_parameterlist(
960 cpl_parameterlist *self)
963 cpl_errorstate prestate = cpl_errorstate_get();
967 cpl_boolean range = CPL_TRUE;
968 const void *dummyMin = NULL;
969 const void *dummyMax = NULL;
973 const char *process_ifus =
"-1";
974 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, KMOS_MOLECFIT_PARAMETER_PROCESS_IFUS,
975 !range, dummyMin, dummyMax, CPL_TYPE_STRING, (
const void *)process_ifus,
976 "A list of IFUs to process. If set to -1, all the IFUs that have data will be process.", CPL_FALSE);
977 if (e != CPL_ERROR_NONE)
return (
int)e;
980 cpl_boolean suppress_extension = CPL_FALSE;
981 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, KMOS_MOLECFIT_PARAMETER_SUPPRESS_EXTENSION,
982 !range, dummyMin, dummyMax, CPL_TYPE_BOOL, &suppress_extension,
983 "Suppress arbitrary filename extension.(TRUE (apply) or FALSE (don't apply).", CPL_FALSE);
984 if (e != CPL_ERROR_NONE)
return (
int)e;
987 const char *wrange_inc =
"-1";
988 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, KMOS_MOLECFIT_PARAMETER_WRANGE,
989 !range, dummyMin, dummyMax, CPL_TYPE_STRING, (
const void *)wrange_inc,
990 "A list of numbers defining the wavelength ranges to fit in the grating. "
991 "If set to -1, grating dependent default values are used (see manual for reference). ", CPL_FALSE);
992 if (e != CPL_ERROR_NONE)
return (
int)e;
995 const char *list_molec =
"-1";
996 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, KMOS_MOLECFIT_PARAMETER_LIST,
997 !range, dummyMin, dummyMax, CPL_TYPE_STRING, (
const void *)list_molec,
998 "A list of molecules to fit in grating IZ. "
999 "If set to -1, grating dependent default values are used (see manual for reference). ", CPL_FALSE);
1000 if (e != CPL_ERROR_NONE)
return (
int)e;
1003 const char *fit_molec =
"-1";
1004 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, KMOS_MOLECFIT_PARAMETER_FIT,
1005 !range, dummyMin, dummyMax, CPL_TYPE_STRING, (
const void *)fit_molec,
1006 "Flags to fit the column density of the corresponding list_molec in grating. "
1007 "If set to -1, grating dependent default values are used (see manual for reference). ", CPL_FALSE);
1008 if (e != CPL_ERROR_NONE)
return (
int)e;
1011 const char *relcol =
"-1";
1012 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, KMOS_MOLECFIT_PARAMETER_RELATIVE_VALUE,
1013 !range, dummyMin, dummyMax, CPL_TYPE_STRING, (
const void *)relcol,
1014 "Column density relative to atmospheric profile of the corresponding list_molec in grating. "
1015 "If set to -1, grating dependent default values are used (see manual for reference). ", CPL_FALSE);
1016 if (e != CPL_ERROR_NONE)
return (
int)e;
1020 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_FTOL,
1021 !range, dummyMin, dummyMax, CPL_TYPE_DOUBLE, &ftol,
1022 "Relative chi-square convergence criterion.", CPL_FALSE);
1023 if (e != CPL_ERROR_NONE)
return (
int)e;
1026 double xtol = 0.001;
1027 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_XTOL,
1028 !range, dummyMin, dummyMax, CPL_TYPE_DOUBLE, &xtol,
1029 "Relative parameter convergence criterion.", CPL_FALSE);
1030 if (e != CPL_ERROR_NONE)
return (
int)e;
1040 char* fit_cont_str_lst = MF_PARAMETERS_FIT_CONTINUUM_INIT;
1041 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_FIT_CONTINUUM,
1042 !range, dummyMin, dummyMax, CPL_TYPE_BOOL, fit_cont_str_lst,
1043 "Flag to enable/disable the polynomial fit of the continuum.", CPL_FALSE);
1045 if (e != CPL_ERROR_NONE)
return (
int)e;
1049 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_CONTINUUM_N,
1050 !range, dummyMin, dummyMax, CPL_TYPE_INT, &cont_n,
1051 "Degree of polynomial continuum fit.", CPL_FALSE);
1052 if (e != CPL_ERROR_NONE)
return (
int)e;
1055 cpl_boolean fit_wlc = CPL_TRUE;
1056 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_FIT_WLC,
1057 !range, dummyMin, dummyMax, CPL_TYPE_BOOL, &fit_wlc,
1058 "Flag to enable/disable the refinement of the wavelength solution.", CPL_FALSE);
1059 if (e != CPL_ERROR_NONE)
return (
int)e;
1063 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_WLC_N,
1064 !range, dummyMin, dummyMax, CPL_TYPE_INT, &wlc_n,
1065 "Polynomial degree of the refined wavelength solution.", CPL_FALSE);
1066 if (e != CPL_ERROR_NONE)
return (
int)e;
1069 double wlc_const = 0.;
1070 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_WLC_CONST,
1071 !range, dummyMin, dummyMax, CPL_TYPE_DOUBLE, &wlc_const,
1072 "Initial constant term for wavelength adjustment (shift relative to half wavelength range).", CPL_FALSE);
1073 if (e != CPL_ERROR_NONE)
return (
int)e;
1076 cpl_boolean use_input_kernel = CPL_TRUE;
1077 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, KMOS_MOLECFIT_PARAMETER_USE_INPUT_KERNEL,
1078 !range, dummyMin, dummyMax, CPL_TYPE_BOOL, &use_input_kernel,
1079 "The parameters below are ignored if use_input_kernel.", CPL_FALSE);
1080 if (e != CPL_ERROR_NONE)
return (
int)e;
1083 cpl_boolean fit_res_box = CPL_FALSE;
1084 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_FIT_RES_BOX,
1085 !range, dummyMin, dummyMax, CPL_TYPE_BOOL, &fit_res_box,
1086 "Fit resolution by Boxcar LSF.", CPL_FALSE);
1087 if (e != CPL_ERROR_NONE)
return (
int)e;
1090 double relres_box_min = MF_PARAMETERS_RES_BOX_MIN;
1091 double relres_box_max = MF_PARAMETERS_RES_BOX_MAX;
1092 double relres_box = 0.;
1093 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_RES_BOX,
1094 range, &relres_box_min, &relres_box_max, CPL_TYPE_DOUBLE, &relres_box,
1095 "Initial value for FWHM of Boxcar rel. to slit width (Range between 0 and 2).", CPL_FALSE);
1096 if (e != CPL_ERROR_NONE)
return (
int)e;
1099 cpl_boolean fit_res_gauss = MF_PARAMETERS_FIT_GAUSS_INIT;
1100 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_FIT_GAUSS,
1101 !range, dummyMin, dummyMax, CPL_TYPE_BOOL, &fit_res_gauss,
1102 "Fit resolution by Gaussian.", CPL_FALSE);
1103 if (e != CPL_ERROR_NONE)
return (
int)e;
1108 double res_gauss = -1.;
1109 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_RES_GAUSS,
1110 !range, dummyMin, dummyMax, CPL_TYPE_DOUBLE, &res_gauss,
1111 "Initial value for FWHM of the Gaussian in pixels (Default = -1: IZ=1.84, YJ=1.82, H=1.76, K=1.73, HK=2.06).", CPL_FALSE);
1112 if (e != CPL_ERROR_NONE)
return (
int)e;
1115 cpl_boolean fit_res_lorentz = CPL_FALSE;
1116 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_FIT_LORENTZ,
1117 !range, dummyMin, dummyMax, CPL_TYPE_BOOL, &fit_res_lorentz,
1118 "Fit resolution by Lorentz.", CPL_FALSE);
1119 if (e != CPL_ERROR_NONE)
return (
int)e;
1124 double res_lorentz = 0.5;
1125 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_RES_LORENTZ,
1126 !range, dummyMin, dummyMax, CPL_TYPE_DOUBLE, &res_lorentz,
1127 "Initial value for FWHM of the Lorentz in pixels.", CPL_FALSE);
1128 if (e != CPL_ERROR_NONE)
return (
int)e;
1131 cpl_boolean kernmode = CPL_FALSE;
1132 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_KERN_MODE,
1133 !range, dummyMin, dummyMax, CPL_TYPE_BOOL, &kernmode,
1134 "Voigt profile approx. or independent Gauss and Lorentz.", CPL_FALSE);
1135 if (e != CPL_ERROR_NONE)
return (
int)e;
1138 double kernfac = 5.;
1139 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_KERN_FAC,
1140 !range, dummyMin, dummyMax, CPL_TYPE_DOUBLE, &kernfac,
1141 "Size of Gaussian/Lorentz/Voigt kernel in FWHM.", CPL_FALSE);
1142 if (e != CPL_ERROR_NONE)
return (
int)e;
1145 cpl_boolean varkern = CPL_FALSE;
1146 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_VAR_KERN,
1147 !range, dummyMin, dummyMax, CPL_TYPE_BOOL, &varkern,
1148 "Does the kernel size increase linearly with wavelength?.", CPL_FALSE);
1149 if (e != CPL_ERROR_NONE)
return (
int)e;
1153 cpl_boolean flag = MF_PARAMETERS_EXPERT_MODE_INIT;
1154 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_EXPERT_MODE,
1155 !range, dummyMin, dummyMax, CPL_TYPE_BOOL, &flag,
1156 MF_PARAMETERS_EXPERT_MODE_DESC, CPL_FALSE);
1157 if (e != CPL_ERROR_NONE)
return (
int)e;
1162 if (!cpl_errorstate_is_equal(prestate)) {
1163 return cpl_error_set_message(cpl_func, cpl_error_get_code(),
1164 "kmos_molecfit_model_fill_parameterlist failed!");
1167 return CPL_ERROR_NONE;
1180static cpl_error_code kmos_molecfit_model_check_wave_molec_conf(
1181 kmos_grating *grating)
1184 cpl_error_ensure(grating, CPL_ERROR_NULL_INPUT,
1185 return CPL_ERROR_NULL_INPUT,
"grating input is NULL!");
1187 cpl_error_ensure(grating->wave_range && grating->list_molec && grating->fit_molec && grating->rel_col, CPL_ERROR_NULL_INPUT,
1188 return CPL_ERROR_NULL_INPUT,
"values of grating input are NULL!");
1196 if (strcmp(grating->wave_range,
"-1") != 0) {
1198 tokens = kmos_molecfit_str_split(grating->wave_range,
",", &n_tokens);
1201 if (!tokens || n_tokens <= 0) {
1202 if (tokens) kmos_molecfit_str_array_delete(tokens);
1203 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
1204 "Unexpected error getting .wave_ranges!");
1208 if (n_tokens % 2 != 0) {
1209 kmos_molecfit_str_array_delete(tokens);
1210 return cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1211 ".wave_range haven't a even number of parameters");
1215 for (cpl_size i = 0; i < n_tokens / 2; i++) {
1217 cpl_size idx = i * 2;
1218 double start = strtod(tokens[idx], NULL);
1219 double end = strtod(tokens[idx + 1], NULL);
1222 if (start < KMOS_WAVELENGTH_START || start > KMOS_WAVELENGTH_END || end < KMOS_WAVELENGTH_START || end > KMOS_WAVELENGTH_END) {
1223 kmos_molecfit_str_array_delete(tokens);
1224 return cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1225 "wavelength in '.wave_range' out of the valid range [%g,%g]", KMOS_WAVELENGTH_START, KMOS_WAVELENGTH_END);
1226 }
else if (start > end) {
1227 kmos_molecfit_str_array_delete(tokens);
1228 return cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1229 "wavelength in '.wave_range' starts before end , valid range [%g,%g]", KMOS_WAVELENGTH_START, KMOS_WAVELENGTH_END);
1232 kmos_molecfit_str_array_delete(tokens);
1236 if (strcmp(grating->list_molec,
"-1") != 0 ){
1238 tokens = kmos_molecfit_str_split(grating->list_molec,
",", &n_tokens);
1241 if (!tokens || n_tokens <= 0) {
1242 kmos_molecfit_str_array_delete(tokens);
1243 return cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1244 "It's necessary at least one molecule in .list_molec");
1248 for (cpl_size i = 0; i < n_tokens; i++) {
1249 if (mf_molecules_str_check(tokens[i]) != CPL_ERROR_NONE) {
1250 kmos_molecfit_str_array_delete(tokens);
1251 return cpl_error_set_message(cpl_func, cpl_error_get_code(),
1252 "Molecule non-valid for Molecfit in .list_molec");
1255 kmos_molecfit_str_array_delete(tokens);
1259 if (strcmp(grating->fit_molec,
"-1") != 0) {
1261 tokens = kmos_molecfit_str_split(grating->fit_molec,
",", &n_tokens);
1264 if (!tokens || n_tokens <= 0) {
1265 kmos_molecfit_str_array_delete(tokens);
1266 return cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1267 "It's necessary the same number of values in .list_molec and .fit_molec");
1271 for (cpl_size i = 0; i < n_tokens; i++) {
1272 int fit_molec = atoi(tokens[i]);
1274 if (fit_molec != 0 && fit_molec != 1) {
1275 kmos_molecfit_str_array_delete(tokens);
1276 return cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1277 "Unexpected value in .fit_molec it'll be boolean, 0 or 1");
1280 kmos_molecfit_str_array_delete(tokens);
1284 if (strcmp(grating->rel_col,
"-1") != 0) {
1286 tokens = kmos_molecfit_str_split(grating->rel_col,
",", &n_tokens);
1289 if (!tokens || n_tokens <= 0) {
1290 kmos_molecfit_str_array_delete(tokens);
1291 return cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1292 "It's necessary the same number of values in .list_molec and .relcol");
1296 for (cpl_size j = 0; j < n_tokens; j++) {
1297 double relcol = strtod(tokens[j], NULL);
1298 if (relcol < 0. || relcol > 1.) {
1299 kmos_molecfit_str_array_delete(tokens);
1300 return cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1301 "Unexpected value in .relcol, it's a fraction. It'll be < 0. or > 1.");
1304 kmos_molecfit_str_array_delete(tokens);
1308 return CPL_ERROR_NONE;
1321static kmos_molecfit_model_parameter * kmos_molecfit_model_conf(
1322 const cpl_parameterlist *list)
1325 cpl_error_ensure(list, CPL_ERROR_NULL_INPUT,
1326 return NULL,
"list input is NULL!");
1329 cpl_errorstate preState = cpl_errorstate_get();
1330 const cpl_parameter *p;
1334 kmos_molecfit_model_parameter *conf = (kmos_molecfit_model_parameter *)cpl_malloc(
sizeof(kmos_molecfit_model_parameter));
1335 kmos_molecfit_nullify(&(conf->mf));
1338 conf->mf.parms = cpl_propertylist_new();
1342 for (cpl_size n_ifu = 0; n_ifu < N_IFUS; n_ifu++) {
1343 conf->mf.ifus[n_ifu].map = n_ifu + 1;
1348 p = cpl_parameterlist_find_const(list, KMOS_MOLECFIT_PARAMETER_PROCESS_IFUS);
1349 conf->process_ifus = cpl_parameter_get_string(p);
1350 if (strcmp(conf->process_ifus,
"-1") == 0) {
1353 cpl_msg_info(cpl_func,
"Processing all IFUs (by default) ... ");
1354 for (cpl_size n_ifu = 0; n_ifu < N_IFUS; n_ifu++) {
1355 conf->mf.ifus[n_ifu].process = CPL_TRUE;
1361 for (cpl_size n_ifu = 0; n_ifu < N_IFUS; n_ifu++) {
1362 conf->mf.ifus[n_ifu].process = CPL_FALSE;
1367 char **tokens = kmos_molecfit_str_split(conf->process_ifus,
",", &n_tokens);
1370 if (!tokens || n_tokens <= 0) {
1371 kmos_molecfit_str_array_delete(tokens);
1372 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1373 "proccess_IFU empty. It's necessary to process some IFU");
1378 for (cpl_size i = 0; i < n_tokens; i++) {
1379 int n_ifu = atoi(tokens[i]);
1382 if (n_ifu < 1 || n_ifu > 24) {
1383 kmos_molecfit_str_array_delete(tokens);
1384 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1385 "Incorrect value in process_ifus. It need to be from 1 to 24");
1390 cpl_msg_info(cpl_func,
"Processing IFU.%02d (assigned by the user) ... ", n_ifu);
1391 conf->mf.ifus[n_ifu - 1].process = CPL_TRUE;
1393 kmos_molecfit_str_array_delete(tokens);
1397 p = cpl_parameterlist_find_const(list, KMOS_MOLECFIT_PARAMETER_SUPPRESS_EXTENSION);
1398 conf->mf.suppress_extension = cpl_parameter_get_bool(p);
1403 p = cpl_parameterlist_find_const(list, KMOS_MOLECFIT_PARAMETER_WRANGE);
1404 conf->mf.grating.wave_range = cpl_parameter_get_string(p);
1407 p = cpl_parameterlist_find_const(list, KMOS_MOLECFIT_PARAMETER_LIST);
1408 conf->mf.grating.list_molec = cpl_parameter_get_string(p);
1411 p = cpl_parameterlist_find_const(list, KMOS_MOLECFIT_PARAMETER_FIT);
1412 conf->mf.grating.fit_molec = cpl_parameter_get_string(p);
1415 p = cpl_parameterlist_find_const(list, KMOS_MOLECFIT_PARAMETER_RELATIVE_VALUE);
1416 conf->mf.grating.rel_col = cpl_parameter_get_string(p);
1419 if (kmos_molecfit_model_check_wave_molec_conf(&(conf->mf.grating)) != CPL_ERROR_NONE) {
1420 kmos_molecfit_model_clean(conf);
1427 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_FTOL);
1428 conf->ftol = cpl_parameter_get_double(p);
1429 if (conf->ftol < 1.e-10) {
1430 kmos_molecfit_model_clean(conf);
1431 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1432 ".ftol out of the valid range");
1436 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_XTOL);
1437 conf->xtol = cpl_parameter_get_double(p);
1438 if (conf->xtol < 1.e-10) {
1439 kmos_molecfit_model_clean(conf);
1440 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1441 ".xtol out of the valid range");
1448 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_FIT_CONTINUUM);
1449 conf->mf.fit_continuum.fit = cpl_parameter_get_bool(p);
1450 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1451 kmos_molecfit_model_clean(conf);
1452 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1453 "Unexpected value in .fit_cont it'll be boolean, 0 or 1");
1457 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_CONTINUUM_N);
1458 conf->mf.fit_continuum.n = cpl_parameter_get_int(p);
1459 if (conf->mf.fit_continuum.n < 0 || conf->mf.fit_continuum.n > MOLECFIT_MAX_POLY_FIT) {
1460 kmos_molecfit_model_clean(conf);
1461 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1462 ".cont_n out of the valid range");
1469 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_FIT_WLC);
1470 conf->mf.fit_wavelenght.fit = cpl_parameter_get_bool(p);
1471 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1472 kmos_molecfit_model_clean(conf);
1473 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1474 "Unexpected value in .fit_wlc it'll be boolean, 0 or 1");
1478 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_WLC_N);
1479 conf->mf.fit_wavelenght.n = cpl_parameter_get_int(p);
1480 if (conf->mf.fit_wavelenght.n < 1 || conf->mf.fit_wavelenght.n > MOLECFIT_MAX_POLY_FIT) {
1481 kmos_molecfit_model_clean(conf);
1482 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1483 ".wlc_n out of the valid range");
1487 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_WLC_CONST);
1488 conf->mf.fit_wavelenght.const_val = cpl_parameter_get_double(p);
1489 if (conf->mf.fit_wavelenght.const_val < 0.) {
1490 kmos_molecfit_model_clean(conf);
1491 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1492 ".wlc_const out of the valid range");
1498 p = cpl_parameterlist_find_const(list, KMOS_MOLECFIT_PARAMETER_USE_INPUT_KERNEL);
1499 conf->mf.use_input_kernel = cpl_parameter_get_bool(p);
1500 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1501 kmos_molecfit_model_clean(conf);
1502 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1503 "Unexpected value in .use_input_kernel it'll be boolean, 0 or 1");
1509 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_FIT_RES_BOX);
1510 conf->boxcar.fit = cpl_parameter_get_bool(p);
1511 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1512 kmos_molecfit_model_clean(conf);
1513 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1514 "Unexpected value in .fit_res_box it'll be boolean, 0 or 1");
1517 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_RES_BOX);
1518 conf->boxcar.res = cpl_parameter_get_double(p);
1519 if (conf->boxcar.res < MF_PARAMETERS_RES_BOX_MIN || conf->boxcar.res > MF_PARAMETERS_RES_BOX_MAX) {
1520 kmos_molecfit_model_clean(conf);
1521 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1522 ".relres_box out of the valid range");
1528 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_FIT_GAUSS);
1529 conf->gauss.fit = cpl_parameter_get_bool(p);
1530 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1531 kmos_molecfit_model_clean(conf);
1532 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1533 "Unexpected value in .fit_res_gauss it'll be boolean, 0 or 1");
1536 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_RES_GAUSS);
1537 conf->gauss.res = cpl_parameter_get_double(p);
1538 if (conf->gauss.res != -1. && conf->gauss.res < 0.01) {
1539 kmos_molecfit_model_clean(conf);
1540 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1541 ".res_gauss out of the valid range");
1546 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_FIT_LORENTZ);
1547 conf->lorentz.fit = cpl_parameter_get_bool(p);
1548 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1549 kmos_molecfit_model_clean(conf);
1550 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1551 "Unexpected value in .fit_res_lorentz it'll be boolean, 0 or 1");
1554 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_RES_LORENTZ);
1555 conf->lorentz.res = cpl_parameter_get_double(p);
1556 if (conf->lorentz.res < 0. || conf->lorentz.res > 100.) {
1557 kmos_molecfit_model_clean(conf);
1558 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1559 ".res_lorentz out of the valid range");
1566 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_KERN_MODE);
1567 conf->mf.kernmode = cpl_parameter_get_bool(p);
1568 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1569 kmos_molecfit_model_clean(conf);
1570 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1571 "Unexpected value in .kernmode it'll be boolean, 0 or 1");
1575 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_KERN_FAC);
1576 conf->mf.kernfac = cpl_parameter_get_double(p);
1577 if (conf->mf.kernfac < 3. || conf->mf.kernfac > 300.) {
1578 kmos_molecfit_model_clean(conf);
1579 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1580 ".kernfac out of the valid range");
1584 p = cpl_parameterlist_find_const(list, MF_PARAMETERS_VAR_KERN);
1585 conf->mf.varkern = cpl_parameter_get_bool(p);
1586 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1587 kmos_molecfit_model_clean(conf);
1588 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
1589 "Unexpected value in .varkern it'll be boolean, 0 or 1");
1596 cpl_propertylist_update_string(conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_PROCESS_IFUS, conf->process_ifus);
1598 cpl_propertylist_update_bool( conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_SUPPRESS_EXTENSION, conf->mf.suppress_extension);
1600 cpl_propertylist_update_string(conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_WRANGE, conf->mf.grating.wave_range);
1601 cpl_propertylist_update_string(conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_LIST, conf->mf.grating.list_molec);
1602 cpl_propertylist_update_string(conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_FIT, conf->mf.grating.fit_molec);
1603 cpl_propertylist_update_string(conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_RELATIVE_VALUE, conf->mf.grating.rel_col);
1605 cpl_propertylist_update_double(conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_FTOL, conf->ftol);
1606 cpl_propertylist_update_double(conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_XTOL, conf->xtol);
1608 cpl_propertylist_update_bool( conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_FIT_CONTINUUM, conf->mf.fit_continuum.fit);
1609 cpl_propertylist_update_int( conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_CONTINUUM_N, conf->mf.fit_continuum.n);
1611 cpl_propertylist_update_bool( conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_FIT_WLC, conf->mf.fit_wavelenght.fit);
1612 cpl_propertylist_update_int( conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_WLC_N, conf->mf.fit_wavelenght.n);
1613 cpl_propertylist_update_double(conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_WLC_CONST, conf->mf.fit_wavelenght.const_val);
1615 cpl_propertylist_update_bool( conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "KMOS_MOLECFIT_KEYWORD_USE_INPUT_KERNEL, conf->mf.use_input_kernel);
1617 cpl_propertylist_update_bool( conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_KERN_MODE, conf->mf.kernmode);
1618 cpl_propertylist_update_double(conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_KERN_FAC, conf->mf.kernfac);
1619 cpl_propertylist_update_bool( conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_VAR_KERN, conf->mf.varkern);
1621 cpl_propertylist_update_bool( conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_FIT_RES_BOX, conf->boxcar.fit);
1622 cpl_propertylist_update_double(conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_RES_BOX, conf->boxcar.res);
1624 cpl_propertylist_update_bool( conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_FIT_GAUSS, conf->gauss.fit);
1625 cpl_propertylist_update_double(conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_RES_GAUSS, conf->gauss.res);
1627 cpl_propertylist_update_bool( conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_FIT_LORENTZ, conf->lorentz.fit);
1628 cpl_propertylist_update_double(conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT
" "MF_PARAMETERS_RES_LORENTZ, conf->lorentz.res);
1632 if (!cpl_errorstate_is_equal(preState)) {
1634 kmos_molecfit_model_clean(conf);
1652static cpl_table * kmos_molecfit_model_get_gdas_profile(
1653 cpl_frameset *frameset)
1656 cpl_error_ensure(frameset, CPL_ERROR_NULL_INPUT,
1657 return NULL,
"kmos_molecfit_model_get_gdas_profile inputs NULL!");
1659 cpl_table *gdas_user = NULL;
1662 const cpl_frame *frmGDAS = cpl_frameset_find(frameset, GDAS);
1665 cpl_msg_info(cpl_func,
"Not %s user profile provided.", GDAS);
1669 const char *fileGDAS = cpl_frame_get_filename(frmGDAS);
1670 cpl_msg_info(cpl_func,
"Loading '%s' %s user profile ...", fileGDAS, GDAS);
1672 gdas_user = cpl_table_load(fileGDAS, 1, 0);
1673 cpl_error_ensure(gdas_user, cpl_error_get_code(),
1674 return NULL,
"Cannot load %s data from the file '%s'!",
1676 cpl_msg_info(cpl_func,
"cpl_table *gdas_user profile loaded :");
1677 cpl_table_dump(gdas_user, 0, cpl_table_get_nrow(gdas_user), NULL);
1693static cpl_table * kmos_molecfit_model_get_atm_profile_standard(
1694 cpl_frameset *frameset)
1697 cpl_error_ensure(frameset, CPL_ERROR_NULL_INPUT,
1698 return NULL,
"kmos_molecfit_model_get_atm_profile_standard inputs NULL!");
1700 cpl_table *atm_profile_standard = NULL;
1703 const cpl_frame *frm_atm_profile_standard = cpl_frameset_find(frameset, ATM_PROFILE_STANDARD);
1704 if (!frm_atm_profile_standard) {
1706 cpl_msg_info(cpl_func,
"Not %s user profile provided.", ATM_PROFILE_STANDARD);
1710 const char *file_atm_profile_standard = cpl_frame_get_filename(frm_atm_profile_standard);
1711 cpl_msg_info(cpl_func,
"Loading '%s' %s user atm_profile_standard ...", file_atm_profile_standard, ATM_PROFILE_STANDARD);
1713 atm_profile_standard = cpl_table_load(file_atm_profile_standard, 1, 0);
1714 cpl_error_ensure(atm_profile_standard, cpl_error_get_code(),
1715 return NULL,
"Cannot load %s data from the file '%s'!",
1716 ATM_PROFILE_STANDARD, file_atm_profile_standard);
1717 cpl_msg_info(cpl_func,
"cpl_table *atm_profile_standard loaded :");
1718 cpl_table_dump(atm_profile_standard, 0, cpl_table_get_nrow(atm_profile_standard), NULL);
1721 return atm_profile_standard;
1736static cpl_error_code kmos_molecfit_model_mf_conf(
1737 kmos_molecfit_model_parameter *conf,
1739 kmos_grating_type type,
1740 mf_parameters_config *config_parameters)
1743 cpl_error_ensure(conf && ifu, CPL_ERROR_NULL_INPUT,
1744 return CPL_ERROR_NULL_INPUT,
"Any input is NULL!");
1747 cpl_error_code err = kmos_molecfit_conf_generic(&(conf->mf), config_parameters);
1748 if (err != CPL_ERROR_NONE)
return err;
1753 config_parameters->fitting.ftol = conf->ftol;
1754 config_parameters->fitting.xtol = conf->xtol;
1756 config_parameters->fitting.fit_continuum.fit = conf->mf.fit_continuum.fit;
1757 config_parameters->fitting.fit_continuum.n = conf->mf.fit_continuum.n;
1758 config_parameters->fitting.fit_continuum.const_val = ifu->median;
1759 cpl_msg_info(cpl_func,
"--.cont_const = %g", config_parameters->fitting.fit_continuum.const_val);
1761 config_parameters->fitting.fit_wavelenght.fit = conf->mf.fit_wavelenght.fit;
1762 config_parameters->fitting.fit_wavelenght.n = conf->mf.fit_wavelenght.n;
1763 config_parameters->fitting.fit_wavelenght.const_val = conf->mf.fit_wavelenght.const_val;
1765 config_parameters->fitting.fit_res_box.fit = conf->boxcar.fit;
1766 config_parameters->fitting.fit_res_box.const_val = conf->boxcar.res;
1768 config_parameters->fitting.fit_gauss.fit = conf->gauss.fit;
1769 config_parameters->fitting.fit_gauss.const_val = conf->gauss.res;
1771 if (config_parameters->fitting.fit_gauss.const_val == -1.) {
1773 case GRATING_IZ: config_parameters->fitting.fit_gauss.const_val = RES_GAUSS_IZ;
break;
1774 case GRATING_YJ: config_parameters->fitting.fit_gauss.const_val = RES_GAUSS_YJ;
break;
1775 case GRATING_H: config_parameters->fitting.fit_gauss.const_val = RES_GAUSS_H;
break;
1776 case GRATING_K: config_parameters->fitting.fit_gauss.const_val = RES_GAUSS_K;
break;
1777 case GRATING_HK: config_parameters->fitting.fit_gauss.const_val = RES_GAUSS_HK;
break;
1779 cpl_msg_info(cpl_func,
"--.res_gauss by default = %g", config_parameters->fitting.fit_gauss.const_val);
1781 cpl_msg_info(cpl_func,
"--.res_gauss by the user = %g", config_parameters->fitting.fit_gauss.const_val);
1784 config_parameters->fitting.fit_lorentz.fit = conf->lorentz.fit;
1785 config_parameters->fitting.fit_lorentz.const_val = conf->lorentz.res;
1790 config_parameters->inputs.transmission = MF_PARAMETERS_TRANSMISSION_TRUE;
1791 config_parameters->inputs.default_error = 0.01;
1792 config_parameters->fitting.flux_unit = MF_PARAMETERS_FLUX_UNIT_NO_CONVERSION;
1794 config_parameters->fitting.fit_telescope_background.fit = CPL_FALSE;
1795 config_parameters->fitting.fit_telescope_background.const_val = 0.1;
1797 if (config_parameters->atmospheric.ref_atm) cpl_free(config_parameters->atmospheric.ref_atm);
1798 config_parameters->atmospheric.ref_atm = cpl_sprintf(
"%s", MF_PARAMETERS_REFERENCE_ATMOSPHERIC_INIT);
1800 if (config_parameters->atmospheric.gdas_prof) cpl_free(config_parameters->atmospheric.gdas_prof);
1801 config_parameters->atmospheric.gdas_prof = cpl_sprintf(
"%s", MF_PARAMETERS_GDAS_PROFILE_AUTO);
1803 config_parameters->atmospheric.layers = CPL_TRUE;
1804 config_parameters->atmospheric.emix = 5.;
1805 config_parameters->atmospheric.pwv = -1.;
1808 return CPL_ERROR_NONE;
1819static void kmos_molecfit_model_clean(
1820 kmos_molecfit_model_parameter *conf)
1824 kmos_molecfit_clean(&(conf->mf));
1843static cpl_error_code kmos_molecfit_model_headers_fill_qc_parameters(
1844 const cpl_table *res_table,
1845 const cpl_table *spec_out,
1846 cpl_propertylist *pl_BParms,
1847 cpl_propertylist *pl_BModel,
1851 cpl_vector *qc_improv,
1859 if ( !cpl_table_has_column(res_table, MF_COL_PARAMETER )
1860 || !cpl_table_has_column(res_table, MF_COL_VALUE )
1861 || !cpl_table_has_column(spec_out, MF_COL_IN_FLUX )
1862 || !cpl_table_has_column(spec_out, MF_COL_OUT_TELLURIC_CORR)
1863 || !cpl_table_has_column(spec_out, MF_COL_MOD_SCALE ) ){
1865 return CPL_ERROR_DATA_NOT_FOUND;
1879 const char **parameter = cpl_table_get_data_string_const(res_table, MF_COL_PARAMETER);
1880 const double *value = cpl_table_get_data_double_const(res_table, MF_COL_VALUE );
1883 cpl_size nrows_res_table = cpl_table_get_nrow(res_table);
1884 for (cpl_size i = 0; i < nrows_res_table; i++) {
1886 cpl_msg_info(cpl_func,
"Parameter: %s, Value = %g", parameter[i], value[i]);
1888 if (!strcmp(parameter[i], KMOS_MOLECFIT_RESULTS_ROW_RMS_REL_TO_MEAN)) {
1889 cpl_propertylist_update_double( pl_BParms, KMOS_MOLECFIT_QC_PARAM_RMS, value[i] );
1890 cpl_propertylist_set_comment( pl_BParms, KMOS_MOLECFIT_QC_PARAM_RMS, KMOS_MOLECFIT_QC_PARAM_RMS_TXT );
1891 cpl_vector_set(qc_rms, k, value[i]);
1895 if (!strcmp(parameter[i], KMOS_MOLECFIT_RESULTS_ROW_RMS_STATUS)) {
1896 cpl_propertylist_update_double( pl_BParms, KMOS_MOLECFIT_QC_PARAM_STATUS, value[i] );
1897 cpl_propertylist_set_comment( pl_BParms, KMOS_MOLECFIT_QC_PARAM_STATUS, KMOS_MOLECFIT_QC_PARAM_STATUS_TXT);
1900 if (!strcmp(parameter[i], KMOS_MOLECFIT_RESULTS_ROW_RMS_H2O_COL_MM)) {
1901 cpl_propertylist_update_double( pl_BParms, KMOS_MOLECFIT_QC_PARAM_H2O, value[i] );
1902 cpl_propertylist_set_comment( pl_BParms, KMOS_MOLECFIT_QC_PARAM_H2O, KMOS_MOLECFIT_QC_PARAM_H2O_TXT );
1903 cpl_vector_set(qc_h2o, k ,value[i]);
1909 if ( !cpl_propertylist_has(pl_BParms, KMOS_MOLECFIT_QC_PARAM_RMS )
1910 || !cpl_propertylist_has(pl_BParms, KMOS_MOLECFIT_QC_PARAM_STATUS)
1911 || !cpl_propertylist_has(pl_BParms, KMOS_MOLECFIT_QC_PARAM_H2O ) ){
1913 return CPL_ERROR_DATA_NOT_FOUND;
1916 if (cpl_propertylist_has(pl_BParms, QC_ZEROPOINT) ){
1917 cpl_vector_set(qc_zpt, k, cpl_propertylist_get_double(pl_BParms,QC_ZEROPOINT));
1921 cpl_size nrows_spec_out = cpl_table_get_nrow(spec_out);
1923 double RMS_NTF = -1.;
1926 cpl_table *copy_spec_out = cpl_table_duplicate(spec_out);
1927 cpl_table_new_column(copy_spec_out, KMOS_MOLECFIT_CALCULE_COLUMN_NF, CPL_TYPE_DOUBLE);
1928 cpl_table_new_column(copy_spec_out, KMOS_MOLECFIT_CALCULE_COLUMN_NTF, CPL_TYPE_DOUBLE);
1929 for (cpl_size i = 0; i < nrows_spec_out; i++) {
1930 cpl_table_set_double(copy_spec_out, KMOS_MOLECFIT_CALCULE_COLUMN_NF, i, 0.);
1931 cpl_table_set_double(copy_spec_out, KMOS_MOLECFIT_CALCULE_COLUMN_NTF, i, 0.);
1935 cpl_table_unselect_all(copy_spec_out);
1936 cpl_table_or_selected_double(copy_spec_out, MF_COL_OUT_TELLURIC_CORR, CPL_GREATER_THAN, 0.05);
1937 cpl_msg_info(cpl_func,
"Number of select columns (%s > 0) = %lld ", MF_COL_OUT_TELLURIC_CORR, cpl_table_count_selected(copy_spec_out));
1938 cpl_table *calculate_spec_out = cpl_table_extract_selected(copy_spec_out);
1943 cpl_table_delete(copy_spec_out);
1946 if (cpl_table_get_nrow(calculate_spec_out) > 0) {
1949 const double *cflux = cpl_table_get_data_double_const(calculate_spec_out, MF_PARAMETERS_COLUMN_FLUX_DEFAULT);
1950 cpl_table_copy_data_double(calculate_spec_out, KMOS_MOLECFIT_CALCULE_COLUMN_NF, cflux);
1951 cpl_table_divide_columns( calculate_spec_out, KMOS_MOLECFIT_CALCULE_COLUMN_NF, MF_COL_MOD_SCALE);
1954 const double *cNF = cpl_table_get_data_double_const(calculate_spec_out, KMOS_MOLECFIT_CALCULE_COLUMN_NF);
1955 cpl_table_copy_data_double(calculate_spec_out, KMOS_MOLECFIT_CALCULE_COLUMN_NTF, cNF);
1956 cpl_table_divide_columns( calculate_spec_out, KMOS_MOLECFIT_CALCULE_COLUMN_NTF, MF_COL_OUT_TELLURIC_CORR);
1959 RMS_NF = cpl_table_get_column_stdev(calculate_spec_out, KMOS_MOLECFIT_CALCULE_COLUMN_NF);
1960 RMS_NTF = cpl_table_get_column_stdev(calculate_spec_out, KMOS_MOLECFIT_CALCULE_COLUMN_NTF);
1962 cpl_msg_info(cpl_func,
"RMS_NF = %g", RMS_NF);
1963 cpl_msg_info(cpl_func,
"RMS_NTF = %g", RMS_NTF);
1967 cpl_msg_warning(cpl_func,
"Any values in the column MSCAL < 0");
1971 cpl_table_delete(calculate_spec_out);
1974 double improv = RMS_NTF / RMS_NF;
1975 cpl_propertylist_update_double( pl_BModel, KMOS_MOLECFIT_QC_PARAM_IMPROV, improv);
1976 cpl_propertylist_set_comment( pl_BModel, KMOS_MOLECFIT_QC_PARAM_IMPROV, KMOS_MOLECFIT_QC_PARAM_IMPROV_TXT);
1977 cpl_msg_info(cpl_func,
"HIERACH ESO QC IMPROV = %g ", improv);
1978 cpl_vector_set(qc_improv,k,improv);
1981 return CPL_ERROR_NONE;