KMOS Pipeline Reference Manual 4.5.10
kmos_molecfit_model.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 "kmos_molecfit.h"
31
32/*----------------------------------------------------------------------------*/
36/*----------------------------------------------------------------------------*/
37
38#define KMOS_MOLECFIT_CALCULE_COLUMN_NF "NF"
39#define KMOS_MOLECFIT_CALCULE_COLUMN_NTF "NTF"
40
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"
44
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"
49
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"
54
55/*#define KMOS_MOLECFIT_QC_PARAM_STD_STARS "ESO QC NR STD STARS"
56#define KMOS_MOLECFIT_QC_PARAM_GDAS "ESO QC GDAS"
57#define KMOS_MOLECFIT_QC_PARAM_FLAG_GDAS "ESO QC FLAG GDAS"
58#define KMOS_MOLECFIT_QC_PARAM_ZPT_AVG "ESO QC ZPOINT AVG"
59#define KMOS_MOLECFIT_QC_PARAM_ZPT_RMS "ESO QC ZPOINT RMS"
60#define KMOS_MOLECFIT_QC_PARAM_RMS_AVG "ESO QC RMS AVG"
61#define KMOS_MOLECFIT_QC_PARAM_RMS_RMS "ESO QC RMS RMS"
62#define KMOS_MOLECFIT_QC_PARAM_H2O_AVG "ESO QC H2O AVG"
63#define KMOS_MOLECFIT_QC_PARAM_H2O_RMS "ESO QC H2O RMS"
64#define KMOS_MOLECFIT_QC_PARAM_H2O_RELRMS "ESO QC H2O RELRMS"
65#define KMOS_MOLECFIT_QC_PARAM_IMPROV_AVG "ESO QC IMPROV AVG"
66#define KMOS_MOLECFIT_QC_PARAM_IMPROV_RMS "ESO QC IMPROV RMS"
67#define KMOS_MOLECFIT_QC_PARAM_MEAS_IWV "ESO QC MEAS IWV"
68#define KMOS_MOLECFIT_QC_PARAM_MEAS_IWV30D "ESO QC MEAS IWV30D"
69#define KMOS_MOLECFIT_QC_PARAM_H2O_DELTA "ESO QC H2O DELTA"
70
71#define KMOS_MOLECFIT_QC_PARAM_STD_STARS_TXT "Nr. of standard stars"
72#define KMOS_MOLECFIT_QC_PARAM_GDAS_TXT "GDAS profile of available"
73#define KMOS_MOLECFIT_QC_PARAM_FLAG_GDAS_TXT "GDAS flag "
74#define KMOS_MOLECFIT_QC_PARAM_ZPT_AVG_TXT "Zeropoint average"
75#define KMOS_MOLECFIT_QC_PARAM_ZPT_RMS_TXT "Zeropoint rms "
76#define KMOS_MOLECFIT_QC_PARAM_RMS_AVG_TXT "RMS average"
77#define KMOS_MOLECFIT_QC_PARAM_RMS_RMS_TXT "RMS rms"
78#define KMOS_MOLECFIT_QC_PARAM_H2O_AVG_TXT "H2O value average"
79#define KMOS_MOLECFIT_QC_PARAM_H2O_RMS_TXT "H2O value rms"
80#define KMOS_MOLECFIT_QC_PARAM_H2O_RELRMS_TXT "H2O RMS / H2O AVG "
81#define KMOS_MOLECFIT_QC_PARAM_IMPROV_AVG_TXT "IMPROV average"
82#define KMOS_MOLECFIT_QC_PARAM_IMPROV_RMS_TXT "IMPROV rms"
83#define KMOS_MOLECFIT_QC_PARAM_MEAS_IWV_TXT "Avg of TEL.AMBI.IWV.START and TEL.AMBI.IWV.END"
84#define KMOS_MOLECFIT_QC_PARAM_MEAS_IWV30D_TXT "Avg of TEL.AMBI.IWV30D.START and TEL.AMBI.IWV30D.END"
85#define KMOS_MOLECFIT_QC_PARAM_H2O_DELTA_TXT "H2O AVG - MEAS IWV" */
86
87/*----------------------------------------------------------------------------*/
91/*----------------------------------------------------------------------------*/
92
93typedef struct {
94 cpl_boolean fit; /* Flag: Fit resolution */
95 double res; /* Initial value for FWHM */
96} mf_kernel;
97
98typedef struct {
99 kmos_molecfit_parameter mf; /* Generic molecfit parameter */
100 const char *process_ifus; /* IFUs to process. If -1 (default), process all IFUs with data */
101 double ftol; /* Relative chi-square convergence criterion */
102 double xtol; /* Relative parameter convergence criterion */
103 mf_kernel boxcar; /* Fit resolution by boxcar LSF */
104 mf_kernel gauss; /* Fit resolution by Gaussian */
105 mf_kernel lorentz; /* Fit resolution by Lorentz */
106} kmos_molecfit_model_parameter;
107
108
109/*----------------------------------------------------------------------------*/
113/*----------------------------------------------------------------------------*/
114
115/* Check the string variables defined by the user (wave_range and molecules definition) */
116static cpl_error_code kmos_molecfit_model_check_wave_molec_conf(
117 kmos_grating *grating);
118
119/* Fill the internal KMOS configuration file */
120static kmos_molecfit_model_parameter * kmos_molecfit_model_conf(
121 const cpl_parameterlist *list);
122
123/* Get the input GDAS profile if the user provide */
124static cpl_table * kmos_molecfit_model_get_gdas_profile(
125 cpl_frameset *frameset);
126
127/* Get the input ATM_PROFILE_STANDARD if the user provide */
128static cpl_table * kmos_molecfit_model_get_atm_profile_standard(
129 cpl_frameset *frameset);
130
131/* Fill the molecfit specific recipe configuration file */
132static cpl_error_code kmos_molecfit_model_mf_conf(
133 kmos_molecfit_model_parameter *conf,
134 kmos_spectrum *ifu,
135 kmos_grating_type type,
136 mf_parameters_config *config_parameters);
137
138/* Clean variables allocated in the recipe */
139static void kmos_molecfit_model_clean(
140 kmos_molecfit_model_parameter *conf);
141
142/* Insert QC parameters in the headers of the IFUs with valid data */
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,
148 cpl_vector *qc_zpt,
149 cpl_vector *qc_h2o,
150 cpl_vector *qc_rms,
151 cpl_vector *qc_improv,
152 /*cpl_vector *qc_meas_iwv,
153 cpl_vector *qc_meas_iwv30d, */
154 int k);
155
156/*----------------------------------------------------------------------------*/
160/*----------------------------------------------------------------------------*/
161
162#define RECIPE_NAME KMOS_MOLECFIT_MODEL
163#define CONTEXT "kmos."RECIPE_NAME
164
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"
176 "\n"
177 "Input files: (It's mandatory to provide 1 file only of type A) \n"
178 "\n"
179 " DO KMOS \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"
188 "\n"
189 "Output files: \n"
190 "\n"
191 " DO KMOS \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"
203 "\n";
204
205/* Standard CPL recipe definition */
206cpl_recipe_define( kmos_molecfit_model,
207 KMOS_BINARY_VERSION,
208 "Jose A. Escartin, Yves Jung",
209 "https://support.eso.org/",
210 "2017",
211 "Run molecfit on set of 1D spectra to compute an atmospheric model.",
212 kmos_molecfit_model_description);
213
214
215/*----------------------------------------------------------------------------*/
220/*----------------------------------------------------------------------------*/
221
224/*----------------------------------------------------------------------------*/
228/*----------------------------------------------------------------------------*/
229
230/*----------------------------------------------------------------------------*/
240/*----------------------------------------------------------------------------*/
241static int kmos_molecfit_model(
242 cpl_frameset *frameset, const cpl_parameterlist *parlist)
243{
244 /* Check initial Entries */
245 if (kmos_check_and_set_groups(frameset) != CPL_ERROR_NONE) {
246 return cpl_error_get_code();
247 }
248
249 /* Get initial errorstate */
250 cpl_errorstate initial_errorstate = cpl_errorstate_get();
251
252 /* Extract and verify data in the parameters of the recipe */
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!" );
259
260
261 /* Loading data spectrums */
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!");
266 }
267
268 /* Loading kernels */
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) {
272
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!");
277 }
278
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);
285 }
286
287 } else {
288
289 if (frmKernel) {
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 !");
293 }
294
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);
299 }
300
301
302
303 cpl_msg_info(cpl_func, " +++ All input data loaded successfully! +++");
304
305 /*
306 * Updating KMOS header with parameter values
307 */
308
309 cpl_propertylist_update_string(conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT" "KMOS_MOLECFIT_KEYWORD_PROCESS_IFUS, conf->process_ifus);
310
311 cpl_propertylist_update_bool( conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT" "KMOS_MOLECFIT_KEYWORD_SUPPRESS_EXTENSION, conf->mf.suppress_extension);
312
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);
317
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);
320
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);
323
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);
327
328 cpl_propertylist_update_bool( conf->mf.header_spectrums, MF_PARAMETERS_CONTEX_DEFAULT" "KMOS_MOLECFIT_KEYWORD_USE_INPUT_KERNEL, conf->mf.use_input_kernel);
329
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);
333
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);
336
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);
339
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);
342
343
344 /* Saving generic multi-extension output *.fits files */
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);
351 //kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, conf->mf.parms, ATMOS_PARM, conf->mf.grating.name, conf->mf.suppress_extension, atmos_file);
352 cpl_error_code sBParms_e = cpl_propertylist_save(conf->mf.header_spectrums, bfp_file, CPL_IO_CREATE);
353 //kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, conf->mf.parms, BEST_FIT_PARM, conf->mf.grating.name, conf->mf.suppress_extension, bfp_file);
354 cpl_error_code sBModel_e = cpl_propertylist_save(conf->mf.header_spectrums, bfm_file, CPL_IO_CREATE);
355 //kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, conf->mf.parms, BEST_FIT_MODEL, conf->mf.grating.name, conf->mf.suppress_extension, bfm_file);
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);
361 }
362
363 /*** General configuration of Molecfit for LBLRTM and LNFL calls ***/
364 cpl_error_code err = CPL_ERROR_NONE;
365
366 /* Initialize mf_configuration structure */
367 mf_configuration *mf_config = mf_configuration_create();
368
369 /* ---------------------------------------------------------------*/
370 /* Temporaray solution to fit chips and fit ranges flag mechanism */
371 /* ---------------------------------------------------------------*/
372 cpl_msg_info(cpl_func,"Sorting the chips and ranges flags");
373
374 /* FIX FOR CHIPS */
375 cpl_boolean flag= conf->mf.fit_wavelenght.fit;
376 int order = conf->mf.fit_wavelenght.n;
377 if ( flag) {
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;
381 }
382 }
383
384 /* FIX FOR RANGES */
385 flag = conf->mf.fit_continuum.fit;
386 order = conf->mf.fit_continuum.n;
387 if ( flag) {
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;
392 }
393 }
394
395 /* ---------------------------------------------------------------*/
396 /* END OF Temporary fix of chips and ranges flag mechanism */
397 /* ---------------------------------------------------------------*/
398
399
400 if (!mf_config) err = CPL_ERROR_NULL_INPUT;
401
402 /* Update the molecfit configuration with the data primary header */
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");
407 }
408
409 /*** GDAS user provided ***/
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);
413
414 /*** ATM_PROFILE_STANDARD user provided ***/
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;
419
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);
424 /*cpl_vector * qc_meas_iwv = cpl_vector_new(N_IFUS);
425 cpl_vector * qc_meas_iwv30d = cpl_vector_new(N_IFUS); */
426
427 /* Number of IFUs processed with molecfit */
428 cpl_size n_procesed_ifus = 0;
429 kmos_grating *grating = &(conf->mf.grating);
430 char * gdas_avail = "F";
431 int gdas_flag = 0;
432
433 /* Execute molecfit for each data spectrum (odd extensions) in STAR_SPEC */
434 for (cpl_size i = 0; i < N_IFUS; i++) {
435
436 kmos_spectrum *ifu = &(conf->mf.ifus[i]);
437
438 /* Initialize variables for molecfit execution */
439 mf_model_results *results = NULL;
440
441 /* Create local headers to fill QC parameters, if they are need */
442 cpl_propertylist *pl_BParms = cpl_propertylist_duplicate(ifu->header_ext_data);
443 cpl_propertylist *pl_BModel = cpl_propertylist_duplicate(ifu->header_ext_data);
444
445 /* Check if the IFU contains data */
446 if (ifu->process && ifu->data) {
447
448 /*cpl_msg_info(cpl_func, "Dumping Propertylist BEST FIT PARAM ");
449 cpl_propertylist_dump(pl_BParms, stdout);
450 cpl_msg_info(cpl_func, "Dumping Propertylist BEST FIT MODEL ");
451 cpl_propertylist_dump(pl_BModel, stdout); */
452
453 /* Configuration variables */
454 cpl_msg_info(cpl_func, "Building molecfict configuration variable in %s ...", ifu->name);
455
456 /* Building molecfic configuration file */
457 if (!err) err = kmos_molecfit_model_mf_conf(conf, ifu, grating->type, mf_config->parameters);
458
459 //mf_config->parameters->inputs.silent_external_bins = CPL_FALSE;
460
461 /* Running molecfit */
462 cpl_msg_info(cpl_func,"MNB About to call mf_model, err=%d", err);
463 if (!err) {
464
465 /* Create input molecfit spec format */
466 cpl_table *spec_telluriccorr_lblrtm = mf_spectrum_create(mf_config->parameters, ifu->data);
467
468 /* CALL MOLECFIT */
469 cpl_msg_info(cpl_func, "Call mf_model(...) in %s ...", ifu->name);
470 results = mf_model( mf_config, /* mf_configuration *config */
471 grating->molecules, /* cpl_table *molecules */
472 ifu->header_ext_data, /* const cpl_propertylist *header_spec */
473 spec_telluriccorr_lblrtm, /* const cpl_table *spec_telluriccorr */
474 grating->incl_wave_ranges, /* cpl_table *inc_wranges */
475 NULL, /* cpl_table *exc_wranges */
476 NULL, /* cpl_table *exc_pranges */
477 ifu->kernel.header_ext_data, /* const cpl_propertylist *header_kernel */
478 ifu->kernel.data, /* const cpl_matrix *kernel */
479 gdas_user, /* const cpl_table *gdas_user */
480 atm_profile_standard, /* const cpl_table *atm_profile_standard */
481 atm_profile_combined); /* const cpl_table *atm_profile_combined */
482
483 cpl_table_delete(spec_telluriccorr_lblrtm);
484
485 cpl_msg_info(cpl_func, "GDAS source for IFU 1= %s", results->gdas_src );
486 if (strcmp(results->gdas_src,"REPOSITORY")) {
487 gdas_avail= "T";
488 gdas_flag = 0;
489 }
490
491 /* Check possible errors */
492 err = cpl_error_get_code();
493
494 /*cpl_msg_info(cpl_func, "Dumping Propertylist BEST FIT PARAMS ");
495 cpl_propertylist_dump(pl_BParms, stdout);
496 cpl_msg_info(cpl_func, "Dumping Propertylist BEST FIT MODEL ");
497 cpl_propertylist_dump(pl_BModel, stdout); */
498
499 /* Add QC parameters to assess the quality of the telluric correction */
500 if (!err) {
501
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);
504 //qc_zpoint = cpl_propertylist_get_double(pl_BParams, );
505
506 cpl_msg_info(cpl_func, "Molecfit call mf_model(...) run successfully! in %s ...", ifu->name);
507
508 cpl_msg_info(cpl_func,"Dumping BEST FIT MODEL Propertylist");
509 //cpl_propertylist_dump(pl_BModel,stdout);
510 cpl_msg_info(cpl_func,"Dumping BEST FIT PARAM Propertylist");
511 //cpl_propertylist_dump(pl_BParms,stdout);
512 /*cpl_msg_info(cpl_func,"Dumping ATMOS PARAM Propertylist");
513 cpl_propertylist_dump(ifu->header_ext_data,stdout); */
514
515 } else {
516
517 cpl_msg_warning(cpl_func, "Molecfit call mf_model(...) run Error! in %s ... %s", ifu->name, cpl_error_get_message());
518
519 /* Reset error */
520 if (!cpl_errorstate_is_equal(initial_errorstate)) cpl_errorstate_set(initial_errorstate);
521 err = CPL_ERROR_NONE;
522 }
523
524 /* Increase process ifu counter */
525 n_procesed_ifus++;
526 }
527 }
528
529 if (!err) {
530
531 /* Saving data */
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);
536
537
538 /* Write GDAS files on disk */
539 if (results && !gdas_write) {
540
541 if (gdas_user) {
542
543 if (results->gdas_interpolate) {
544
545 cpl_msg_info(cpl_func, "Saving Molecfit output user provide fits files ('%s') ... [only first call to Molecfit!]",
546 GDAS);
547
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);
550
551
552 gdas_write = CPL_TRUE;
553
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!",
557 GDAS);
558 }
559 }
560
561 } else if (results->gdas_before && results->gdas_after && results->gdas_interpolate) {
562
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);
565
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);
568
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);
571
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);
574
575 /* Keep time, no access to ESO GDAS DB : Same gdas_interpolate for all the IFUs because all the arms have the same 'date' -> MDJ_OBS in the header */
576 gdas_user = cpl_table_duplicate(results->gdas_interpolate);
577
578 gdas_write = CPL_TRUE;
579
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);
584 }
585 }
586 }
587
588 /* Write ATM_PROFILE_STANDARD files on disk */
589 if (results && !atm_profile_standard_write) {
590
591 if (atm_profile_standard) {
592
593 if (results->atm_profile_standard) {
594
595 cpl_msg_info(cpl_func, "Saving Molecfit output user provide fits files ('%s') ... [only first call to Molecfit!]",
596 ATM_PROFILE_STANDARD);
597
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);
600
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);
603
604 atm_profile_combined = cpl_table_duplicate(results->atm_profile_combined);
605
606 atm_profile_standard_write = CPL_TRUE;
607
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);
612 }
613 }
614
615 } else if (results->atm_profile_standard) {
616
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);
619
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);
622
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);
625
626 /* Keep time, no access to disk : Same atm_profile_standard for all the IFUs because all the arms have the same 'date' -> MDJ_OBS in the header */
627 atm_profile_standard = cpl_table_duplicate(results->atm_profile_standard);
628 atm_profile_combined = cpl_table_duplicate(results->atm_profile_combined);
629
630 atm_profile_standard_write = CPL_TRUE;
631
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);
636 }
637 }
638 }
639
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;
643
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);
645 //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);
647 //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);
649 //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);
650
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);
655 }
656
657 if (frmKernel && conf->mf.use_input_kernel) {
658
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;
661
662 cpl_matrix *kernel = NULL;
663 if (results) {
664 if (results->kernel) kernel = results->kernel;
665 }
666
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);
669
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);
674 }
675 }
676 }
677
678 /* Cleanup MF_MODEL auxiliar variables */
679 mf_model_results_delete(results);
680 cpl_propertylist_delete(pl_BParms);
681 cpl_propertylist_delete(pl_BModel);
682 }
683
684 /* ---------------------------- QC PARAM CALCULATION -------------------------------------*/
685
686 cpl_msg_info(cpl_func,"Calculating QC Parameters");
687
688 cpl_propertylist* qc_atmos = kmclipm_propertylist_load(atmos_file, 0); //kmo_dfs_load_primary_header(frameset, ATMOS_PARM);
689 cpl_propertylist* qc_bfp = kmclipm_propertylist_load(bfp_file, 0); //kmo_dfs_load_primary_header(frameset, BEST_FIT_PARM);
690 cpl_propertylist* qc_bfm = kmclipm_propertylist_load(bfm_file, 0); //kmo_dfs_load_primary_header(frameset, BEST_FIT_MODEL);
691
692 //cpl_propertylist_dump(qc_atmos,stdout);
693
694 /*if (sAtm_e != CPL_ERROR_NONE || sBParms_e != CPL_ERROR_NONE || sBModel_e != CPL_ERROR_NONE) {
695 kmos_molecfit_model_clean(conf);
696 return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
697 "Saving generic multi-extension output fits files ('%s','%s','%s') failed!",
698 ATMOS_PARM_TMP, BEST_FIT_PARM_TMP, BEST_FIT_MODEL_TMP);
699 }
700 else {
701 cpl_msg_info(cpl_func, "last error %s" ,cpl_error_get_message());
702 } */
703
704 cpl_size j= 0;
705
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);
710
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;
720
721 /*GDAS Check for QC parameters */
722 //mf_parameters *params = mf_parameters_create(mf_config->parameters, grating->molecules, NULL);
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);
726
727 /* Name of tarball and paths that contain all of GDAS files and the file to search (i.e. Paranal: gdas_profiles_C-70.4-24.6.tar.gz) */
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);
730
731 if (access(global_gdas_tarball, F_OK) == CPL_ERROR_NONE) {
732 gdas_avail= "T";
733 gdas_flag = 0;
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 ");
736 }
737 /*END - put the above section in to kmo_utils.c as a new function*/
738
739 /*qc_meas_iwv = cpl_vector_extract(qc_meas_iwv, 0, n_procesed_ifus-1,1);
740 qc_meas_iwv30d = cpl_vector_extract(qc_meas_iwv30d, 0, n_procesed_ifus-1,1); */
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);
747 }
748
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);
755 }
756
757 if (cpl_propertylist_has(kmo_dfs_load_primary_header(frameset, "STAR_SPEC"),
758 QC_NR_STD_STARS)){
759
760 int nr_std_str= cpl_propertylist_get_int(kmo_dfs_load_primary_header(frameset, "STAR_SPEC"), QC_NR_STD_STARS);
761
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);
765
766 }
767
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");
773
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");
783
784
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);
801
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);
806
807
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);
813 }
814
815 /*cpl_frame *frame_atmos = kmo_dfs_get_frame(frameset, ATMOS_PARM);
816 cpl_frame *frame_bfp = kmo_dfs_get_frame(frameset, BEST_FIT_PARM);
817 cpl_frame *frame_bfm = kmo_dfs_get_frame(frameset, BEST_FIT_MODEL);
818 cpl_msg_info(cpl_func,"Got atmos frame."); */
819
820 // CHANGE FOR SUPPRESS-EXTENSION
821
822 //cpl_sprintf("_%s%s%s", conf->mf.grating.name, conf->mf.grating.name, conf->mf.grating.name);
823
824 //kmo_dfs_save_main_header(frameset, ATMOS_PARM , suffix, NULL, qc_atmos, parlist, cpl_func);
825 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, qc_atmos, ATMOS_PARM, conf->mf.grating.name, conf->mf.suppress_extension, NULL);
826 //kmo_dfs_save_main_header(frameset, BEST_FIT_PARM ,suffix, NULL, qc_bfp, parlist, cpl_func);
827 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, qc_bfp, BEST_FIT_PARM, conf->mf.grating.name, conf->mf.suppress_extension, NULL);
828 //kmo_dfs_save_main_header(frameset, BEST_FIT_MODEL , suffix, NULL, qc_bfm, parlist, cpl_func);
829 kmos_molecfit_save(frameset, frameset, parlist, RECIPE_NAME, qc_bfm, BEST_FIT_MODEL, conf->mf.grating.name, conf->mf.suppress_extension, NULL);
830
831 const char * suffix= "";
832
833 if (!conf->mf.suppress_extension) {
834
835 cpl_msg_info(cpl_func, "need to find a suffix ! ");
836
837 suffix = kmo_dfs_get_suffix(kmo_dfs_get_frame(frameset, ATMOS_PARM), TRUE, FALSE);
838 }
839
840
841 for (cpl_size i = 1; i <= N_IFUS; i++) {
842
843 j = 2*i-1;
844
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);
848
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);
852
853
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) ;
858 }
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) ;
863 }
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) ;
868 }
869
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);
873 //kmos_all_clean_plist(sub_header_atmos_noise) ;
874 //kmos_all_clean_plist(sub_header_bfp_noise) ;
875
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);
879
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);
883
884 cpl_propertylist_delete(sub_header_atmos);
885 cpl_propertylist_delete(sub_header_bfp);
886 cpl_propertylist_delete(sub_header_bfm);
887
888 cpl_propertylist_delete(sub_header_atmos_noise);
889 cpl_propertylist_delete(sub_header_bfp_noise);
890 cpl_propertylist_delete(sub_header_bfm_noise);
891
892 cpl_table_delete(atmos_tbl);
893 cpl_table_delete(bfm_tbl);
894 cpl_table_delete(bfp_tbl);
895
896 cpl_table_delete(atmos_tbl_noise);
897 cpl_table_delete(bfm_tbl_noise);
898 cpl_table_delete(bfp_tbl_noise);
899
900 }
901
902 /*cpl_frame_delete(frame_atmos);
903 cpl_frame_delete(frame_bfp);
904 cpl_frame_delete(frame_bfm); */
905
906 unlink(atmos_file);
907 unlink(bfp_file);
908 unlink(bfm_file);
909
910 /* Cleanup: General configuration of Molecfit */
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);
915
916 /*mf_io_rm(atmos_file);
917 mf_io_rm(bfm_file);
918 mf_io_rm(bfp_file);*/
919
920 /* Check errors in Molecfit calls */
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());
926 }
927
928 /* Cleanup configuration */
929 cpl_msg_info(cpl_func,"Cleaning variables ...");
930 kmos_molecfit_model_clean(conf);
931
932 /* Check Recipe status and end */
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);
936 } else {
937 /* Dump the error history since recipe execution start.
938 * At this point the recipe cannot recover from the error */
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());
941 }
942
943 cpl_msg_info(cpl_func,"Finish recipe. Returning ...");
944 return (int)cpl_error_get_code();
945}
946
949/*----------------------------------------------------------------------------*/
958/*----------------------------------------------------------------------------*/
959static cpl_error_code kmos_molecfit_model_fill_parameterlist(
960 cpl_parameterlist *self)
961{
962 /* Add the different default parameters to the recipe */
963 cpl_errorstate prestate = cpl_errorstate_get();
964
965 /* Fill the parameters list */
966 cpl_error_code e;
967 cpl_boolean range = CPL_TRUE;
968 const void *dummyMin = NULL;
969 const void *dummyMax = NULL;
970
971
972 /* --KMOS_MOLECFIT_PARAMETER_PROCESS_IFUS */
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;
978
979 /* --KMOS_MOLECFIT_PARAMETER_SUPPRESS_EXTENSION */
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;
985
986 /* --KMOS_MOLECFIT_PARAMETER_WRANGE */
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;
993
994 /* --KMOS_MOLECFIT_PARAMETER_LIST */
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;
1001
1002 /* --KMOS_MOLECFIT_PARAMETER_FIT */
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;
1009
1010 /* --KMOS_MOLECFIT_PARAMETER_RELATIVE_VALUE */
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;
1017
1018 /* --MF_PARAMETERS_FTOL */
1019 double ftol = 0.01; /* Molecfit default: 1e-10 */
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;
1024
1025 /* --MF_PARAMETERS_XTOL */
1026 double xtol = 0.001; /* Molecfit default: 1e-10 */
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;
1031
1032 /* --MF_PARAMETERS_FIT_CONT */
1033/*
1034 cpl_boolean fit_cont = MF_PARAMETERS_FIT_CONTINUUM_INIT;
1035 e = kmos_molecfit_fill_parameter(RECIPE_NAME, self, MF_PARAMETERS_FIT_CONTINUUM,
1036 !range, dummyMin, dummyMax, CPL_TYPE_BOOL, &fit_cont,
1037 "Flag to enable/disable the polynomial fit of the continuum.", CPL_FALSE);
1038*/
1039
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);
1044
1045 if (e != CPL_ERROR_NONE) return (int)e;
1046
1047 /* --MF_PARAMETERS_CONT_N */
1048 int cont_n = 1; /* Molecfit default: 0 */
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;
1053
1054 /* --MF_PARAMETERS_FIT_WLC */
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;
1060
1061 /* --MF_PARAMETERS_FIT_WLC */
1062 int wlc_n = 2; /* Molecfit default: 1 */
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;
1067
1068 /* --MF_PARAMETERS_WLC_CONST */
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;
1074
1075 /* --KMOS_MOLECFIT_PARAMETER_USE_INPUT_KERNEL */
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;
1081
1082 /* --MF_PARAMETERS_FIT_RES_BOX */
1083 cpl_boolean fit_res_box = CPL_FALSE; /* Molecfit default: CPL_TRUE */
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;
1088
1089 /* --MF_PARAMETERS_REL_RES_BOX */
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.; /* Molecfit default: 1. */
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;
1097
1098 /* --MF_PARAMETERS_FIT_GAUSS */
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;
1104
1105 /* --MF_PARAMETERS_RES_GAUSS */
1106 //double res_gauss_min = MF_PARAMETERS_RES_GAUSS_MIN;
1107 //double res_gauss_max = MF_PARAMETERS_RES_GAUSS_MAX;
1108 double res_gauss = -1.; /* Molecfit default: 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;
1113
1114 /* --MF_PARAMETERS_RES_LORENTZ */
1115 cpl_boolean fit_res_lorentz = CPL_FALSE; /* Molecfit default: CPL_TRUE */
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;
1120
1121 /* --MF_PARAMETERS_FIT_LORENTZ */
1122 //double res_lorentz_min = MF_PARAMETERS_RES_LORENTZ_MIN;
1123 //double res_lorentz_max = MF_PARAMETERS_RES_LORENTZ_MAX;
1124 double res_lorentz = 0.5; /* Molecfit default: 1. */
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;
1129
1130 /* --MF_PARAMETERS_KERN_MODE */
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;
1136
1137 /* --MF_PARAMETERS_KERN_FAC */
1138 double kernfac = 5.; /* Molecfit default: 3. */
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;
1143
1144 /* --MF_PARAMETERS_VAR_KERN */
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;
1150
1151
1152 /* --MF_PARAMETERS_EXPERT_MODE */
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;
1158
1159
1160
1161 /* Check possible errors */
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!");
1165 }
1166
1167 return CPL_ERROR_NONE;
1168}
1169
1170/*----------------------------------------------------------------------------*/
1179/*----------------------------------------------------------------------------*/
1180static cpl_error_code kmos_molecfit_model_check_wave_molec_conf(
1181 kmos_grating *grating)
1182{
1183 /* Check input */
1184 cpl_error_ensure(grating, CPL_ERROR_NULL_INPUT,
1185 return CPL_ERROR_NULL_INPUT, "grating input is NULL!");
1186
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!");
1189
1190 /* Init variables */
1191 char **tokens;
1192 cpl_size n_tokens;
1193
1194
1195 /*** Check wave_range variable ***/
1196 if (strcmp(grating->wave_range, "-1") != 0) {
1197
1198 tokens = kmos_molecfit_str_split(grating->wave_range, ",", &n_tokens);
1199
1200 /* Any token? */
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!");
1205 }
1206
1207 /* At least 2 parameters, Check even number of parameters */
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");
1212 }
1213
1214 /* Range of wavelenghts and direction */
1215 for (cpl_size i = 0; i < n_tokens / 2; i++) {
1216
1217 cpl_size idx = i * 2;
1218 double start = strtod(tokens[idx], NULL);
1219 double end = strtod(tokens[idx + 1], NULL);
1220
1221 /* Check the wavelength range - range of KMOS between 0.8 to 2.5 (um) */
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);
1230 }
1231 }
1232 kmos_molecfit_str_array_delete(tokens);
1233 }
1234
1235 /*** Check molec_list variable ***/
1236 if (strcmp(grating->list_molec, "-1") != 0 ){
1237
1238 tokens = kmos_molecfit_str_split(grating->list_molec, ",", &n_tokens);
1239
1240 /* Any token? */
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");
1245 }
1246
1247 /* Check if the molecs are valid for Molecfit */
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");
1253 }
1254 }
1255 kmos_molecfit_str_array_delete(tokens);
1256 }
1257
1258 /*** Check fit_molec variable ***/
1259 if (strcmp(grating->fit_molec, "-1") != 0) {
1260
1261 tokens = kmos_molecfit_str_split(grating->fit_molec, ",", &n_tokens);
1262
1263 /* Any token? */
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");
1268 }
1269
1270 /* Boolean value? */
1271 for (cpl_size i = 0; i < n_tokens; i++) {
1272 int fit_molec = atoi(tokens[i]);
1273
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");
1278 }
1279 }
1280 kmos_molecfit_str_array_delete(tokens);
1281 }
1282
1283 /*** Check relcol variable ***/
1284 if (strcmp(grating->rel_col, "-1") != 0) {
1285
1286 tokens = kmos_molecfit_str_split(grating->rel_col, ",", &n_tokens);
1287
1288 /* Any token? */
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");
1293 }
1294
1295 /* Range between 0. to 1. ? */
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.");
1302 }
1303 }
1304 kmos_molecfit_str_array_delete(tokens);
1305 }
1306
1307
1308 return CPL_ERROR_NONE;
1309}
1310
1311/*----------------------------------------------------------------------------*/
1320/*----------------------------------------------------------------------------*/
1321static kmos_molecfit_model_parameter * kmos_molecfit_model_conf(
1322 const cpl_parameterlist *list)
1323{
1324 /* Check input */
1325 cpl_error_ensure(list, CPL_ERROR_NULL_INPUT,
1326 return NULL, "list input is NULL!");
1327
1328 /* Get preState */
1329 cpl_errorstate preState = cpl_errorstate_get();
1330 const cpl_parameter *p;
1331
1332
1333 /* Create the configuration parameter */
1334 kmos_molecfit_model_parameter *conf = (kmos_molecfit_model_parameter *)cpl_malloc(sizeof(kmos_molecfit_model_parameter));
1335 kmos_molecfit_nullify(&(conf->mf));
1336
1337 /* Initialize input parameters propertylist */
1338 conf->mf.parms = cpl_propertylist_new();
1339
1340
1341 /*** Mapping IFUs in kmos_molecfit_model recipe, correspondence 1 to 1 ***/
1342 for (cpl_size n_ifu = 0; n_ifu < N_IFUS; n_ifu++) {
1343 conf->mf.ifus[n_ifu].map = n_ifu + 1;
1344 }
1345
1346
1347 /*** What IFUs Do I need to process? ***/
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) {
1351
1352 /* Process all IFUs by default */
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;
1356 }
1357
1358 } else {
1359
1360 /* Initialize process IFUs to CPL_FALSE */
1361 for (cpl_size n_ifu = 0; n_ifu < N_IFUS; n_ifu++) {
1362 conf->mf.ifus[n_ifu].process = CPL_FALSE;
1363 }
1364
1365 /* Init variables */
1366 cpl_size n_tokens;
1367 char **tokens = kmos_molecfit_str_split(conf->process_ifus, ",", &n_tokens);
1368
1369 /* Any token? */
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");
1374 return NULL;
1375 }
1376
1377 /* Set process IFUs */
1378 for (cpl_size i = 0; i < n_tokens; i++) {
1379 int n_ifu = atoi(tokens[i]);
1380
1381 /* Number of IFU correct */
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");
1386 return NULL;
1387 }
1388
1389 /* Process this IFU */
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;
1392 }
1393 kmos_molecfit_str_array_delete(tokens);
1394 }
1395
1396 /*** Suppress prefix ***/
1397 p = cpl_parameterlist_find_const(list, KMOS_MOLECFIT_PARAMETER_SUPPRESS_EXTENSION);
1398 conf->mf.suppress_extension = cpl_parameter_get_bool(p);
1399
1400 /*** Wavelenght ranges & molecules: Defined by the user ****/
1401
1402 /* Get string iwht the list of wavelenght for the grating defined by the user */
1403 p = cpl_parameterlist_find_const(list, KMOS_MOLECFIT_PARAMETER_WRANGE);
1404 conf->mf.grating.wave_range = cpl_parameter_get_string(p);
1405
1406 /* Get string with the list of molecules for the grating defined by the user */
1407 p = cpl_parameterlist_find_const(list, KMOS_MOLECFIT_PARAMETER_LIST);
1408 conf->mf.grating.list_molec = cpl_parameter_get_string(p);
1409
1410 /* Get string with the fit list of molecules for this grating */
1411 p = cpl_parameterlist_find_const(list, KMOS_MOLECFIT_PARAMETER_FIT);
1412 conf->mf.grating.fit_molec = cpl_parameter_get_string(p);
1413
1414 /* Get string with the relcol list of molecules for this grating */
1415 p = cpl_parameterlist_find_const(list, KMOS_MOLECFIT_PARAMETER_RELATIVE_VALUE);
1416 conf->mf.grating.rel_col = cpl_parameter_get_string(p);
1417
1418 /* Check values defined by the user */
1419 if (kmos_molecfit_model_check_wave_molec_conf(&(conf->mf.grating)) != CPL_ERROR_NONE) {
1420 kmos_molecfit_model_clean(conf);
1421 return NULL;
1422 }
1423
1424
1425 /*** Convergence criterion ***/
1426
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");
1433 return NULL;
1434 }
1435
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");
1442 return NULL;
1443 }
1444
1445
1446 /*** Continuum ***/
1447
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");
1454 return NULL;
1455 }
1456
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");
1463 return NULL;
1464 }
1465
1466
1467 /*** Wavelength solution fit/adjustment ***/
1468
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");
1475 return NULL;
1476 }
1477
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");
1484 return NULL;
1485 }
1486
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");
1493 return NULL;
1494 }
1495
1496
1497 /*** User input kernel ? ***/
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");
1504 return NULL;
1505 }
1506
1507
1508 /*** Default kernel: Boxcar kernel ***/
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");
1515 return NULL;
1516 }
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");
1523 return NULL;
1524 }
1525
1526
1527 /*** Default kernel: Gaussian kernel ***/
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");
1534 return NULL;
1535 }
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");
1542 return NULL;
1543 }
1544
1545 /*** Default kernel: Lorentz kernel ***/
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");
1552 return NULL;
1553 }
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");
1560 return NULL;
1561 }
1562
1563
1564 /*** Default kernels: Generic parameters ***/
1565
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");
1572 return NULL;
1573 }
1574
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");
1581 return NULL;
1582 }
1583
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");
1590 return NULL;
1591 }
1592
1593
1594 /* Save parameter in the output propertylist */
1595
1596 cpl_propertylist_update_string(conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT" "KMOS_MOLECFIT_KEYWORD_PROCESS_IFUS, conf->process_ifus);
1597
1598 cpl_propertylist_update_bool( conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT" "KMOS_MOLECFIT_KEYWORD_SUPPRESS_EXTENSION, conf->mf.suppress_extension);
1599
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);
1604
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);
1607
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);
1610
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);
1614
1615 cpl_propertylist_update_bool( conf->mf.parms, MF_PARAMETERS_CONTEX_DEFAULT" "KMOS_MOLECFIT_KEYWORD_USE_INPUT_KERNEL, conf->mf.use_input_kernel);
1616
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);
1620
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);
1623
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);
1626
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);
1629
1630
1631 /* Check status */
1632 if (!cpl_errorstate_is_equal(preState)) {
1633 /* Configuration failed */
1634 kmos_molecfit_model_clean(conf);
1635 return NULL;
1636 } else {
1637 /* Configuration successfully */
1638 return conf;
1639 }
1640}
1641
1642/*----------------------------------------------------------------------------*/
1651/*----------------------------------------------------------------------------*/
1652static cpl_table * kmos_molecfit_model_get_gdas_profile(
1653 cpl_frameset *frameset)
1654{
1655 /* Check input */
1656 cpl_error_ensure(frameset, CPL_ERROR_NULL_INPUT,
1657 return NULL, "kmos_molecfit_model_get_gdas_profile inputs NULL!");
1658
1659 cpl_table *gdas_user = NULL;
1660
1661 /* Check if exist cpl_frame GDAS */
1662 const cpl_frame *frmGDAS = cpl_frameset_find(frameset, GDAS);
1663 if (!frmGDAS) {
1664
1665 cpl_msg_info(cpl_func, "Not %s user profile provided.", GDAS);
1666
1667 } else {
1668
1669 const char *fileGDAS = cpl_frame_get_filename(frmGDAS);
1670 cpl_msg_info(cpl_func, "Loading '%s' %s user profile ...", fileGDAS, GDAS);
1671
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'!",
1675 GDAS, fileGDAS);
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);
1678 }
1679
1680 return gdas_user;
1681}
1682
1683/*----------------------------------------------------------------------------*/
1692/*----------------------------------------------------------------------------*/
1693static cpl_table * kmos_molecfit_model_get_atm_profile_standard(
1694 cpl_frameset *frameset)
1695{
1696 /* Check input */
1697 cpl_error_ensure(frameset, CPL_ERROR_NULL_INPUT,
1698 return NULL, "kmos_molecfit_model_get_atm_profile_standard inputs NULL!");
1699
1700 cpl_table *atm_profile_standard = NULL;
1701
1702 /* Check if exist cpl_frame ATM_PROFILE_STANDARD */
1703 const cpl_frame *frm_atm_profile_standard = cpl_frameset_find(frameset, ATM_PROFILE_STANDARD);
1704 if (!frm_atm_profile_standard) {
1705
1706 cpl_msg_info(cpl_func, "Not %s user profile provided.", ATM_PROFILE_STANDARD);
1707
1708 } else {
1709
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);
1712
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);
1719 }
1720
1721 return atm_profile_standard;
1722}
1723
1724/*----------------------------------------------------------------------------*/
1735/*----------------------------------------------------------------------------*/
1736static cpl_error_code kmos_molecfit_model_mf_conf(
1737 kmos_molecfit_model_parameter *conf,
1738 kmos_spectrum *ifu,
1739 kmos_grating_type type,
1740 mf_parameters_config *config_parameters)
1741{
1742 /* Check inputs */
1743 cpl_error_ensure(conf && ifu, CPL_ERROR_NULL_INPUT,
1744 return CPL_ERROR_NULL_INPUT, "Any input is NULL!");
1745
1746 /*** Building generic configuration molecfic file ***/
1747 cpl_error_code err = kmos_molecfit_conf_generic(&(conf->mf), config_parameters);
1748 if (err != CPL_ERROR_NONE) return err;
1749
1750
1751 /*** Set molecfit configuration with recipe parameters ***/
1752
1753 config_parameters->fitting.ftol = conf->ftol;
1754 config_parameters->fitting.xtol = conf->xtol;
1755
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);
1760
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;
1764
1765 config_parameters->fitting.fit_res_box.fit = conf->boxcar.fit;
1766 config_parameters->fitting.fit_res_box.const_val = conf->boxcar.res;
1767
1768 config_parameters->fitting.fit_gauss.fit = conf->gauss.fit;
1769 config_parameters->fitting.fit_gauss.const_val = conf->gauss.res;
1770
1771 if (config_parameters->fitting.fit_gauss.const_val == -1.) {
1772 switch(type) {
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;
1778 }
1779 cpl_msg_info(cpl_func,"--.res_gauss by default = %g", config_parameters->fitting.fit_gauss.const_val);
1780 } else {
1781 cpl_msg_info(cpl_func,"--.res_gauss by the user = %g", config_parameters->fitting.fit_gauss.const_val);
1782 }
1783
1784 config_parameters->fitting.fit_lorentz.fit = conf->lorentz.fit;
1785 config_parameters->fitting.fit_lorentz.const_val = conf->lorentz.res;
1786
1787
1788 /*** PARAMETERS NOT INCLUDED IN THE RECIPE: HARD-CODED ***/
1789
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;
1793
1794 config_parameters->fitting.fit_telescope_background.fit = CPL_FALSE; /* Molecfit default: CPL_TRUE */
1795 config_parameters->fitting.fit_telescope_background.const_val = 0.1;
1796
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);
1799
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);
1802
1803 config_parameters->atmospheric.layers = CPL_TRUE;
1804 config_parameters->atmospheric.emix = 5.;
1805 config_parameters->atmospheric.pwv = -1.;
1806
1807
1808 return CPL_ERROR_NONE;
1809}
1810
1811/*-------------------------------------------------------------
1812 * ---------------*/
1818/*----------------------------------------------------------------------------*/
1819static void kmos_molecfit_model_clean(
1820 kmos_molecfit_model_parameter *conf)
1821{
1822 if (conf) {
1823
1824 kmos_molecfit_clean(&(conf->mf));
1825
1826 cpl_free(conf);
1827 }
1828}
1829
1830/*----------------------------------------------------------------------------*/
1842/*----------------------------------------------------------------------------*/
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,
1848 cpl_vector *qc_zpt,
1849 cpl_vector *qc_h2o,
1850 cpl_vector *qc_rms,
1851 cpl_vector *qc_improv,
1852 /*cpl_vector *qc_meas_iwv,
1853 cpl_vector *qc_meas_iwv30d,*/
1854 int k)
1855{
1856
1857
1858 /* Check column inputs */
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 ) ){
1864
1865 return CPL_ERROR_DATA_NOT_FOUND;
1866 }
1867
1868
1869 /*cpl_msg_info(cpl_func, "Result Table structure .");
1870 cpl_propertylist_dump(pl_BParms,stdout);
1871
1872 cpl_msg_info(cpl_func, "Best Fitting Table data");
1873 cpl_propertylist_dump(pl_BModel, stdout); */
1874
1875 /*** Fill the BEST_FIT_PARM FITS header file with the QC parameters ***/
1876 /* cpl_table_dump(res_table, 0, cpl_table_get_nrow(res_table), NULL); */
1877
1878 /* Get parameters and values of the best fit model results table */
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 );
1881
1882 /* Write the QC BEST_FIT_PARM parameters */
1883 cpl_size nrows_res_table = cpl_table_get_nrow(res_table);
1884 for (cpl_size i = 0; i < nrows_res_table; i++) {
1885 if (parameter[i]) {
1886 cpl_msg_info(cpl_func, "Parameter: %s, Value = %g", parameter[i], value[i]);
1887
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]);
1892
1893 }
1894
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);
1898 }
1899
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]);
1904 }
1905 }
1906 }
1907
1908 /* Check QC BEST_FIT_PARM parameters */
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 ) ){
1912
1913 return CPL_ERROR_DATA_NOT_FOUND;
1914 }
1915
1916 if (cpl_propertylist_has(pl_BParms, QC_ZEROPOINT) ){
1917 cpl_vector_set(qc_zpt, k, cpl_propertylist_get_double(pl_BParms,QC_ZEROPOINT));
1918 }
1919
1920 /*** Fill the BEST_FIT_MODEL FITS header file with the QC parameters ***/
1921 cpl_size nrows_spec_out = cpl_table_get_nrow(spec_out);
1922 double RMS_NF = 1.;
1923 double RMS_NTF = -1.;
1924
1925 /* Create new columns to the calculate table and select to zero for convert in valid */
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.);
1932 }
1933
1934 /* Apply the selection: mtrans > 0.05 and extract columns (Avoiding problems with values very close zero) */
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);
1939
1940 /* cpl_table_dump(calculate_spec_out, 0, cpl_table_get_nrow(calculate_spec_out), NULL); */
1941
1942 /* Remove the temporary copy of spec_out table */
1943 cpl_table_delete(copy_spec_out);
1944
1945 /* Calculate RMS_NF and RMS_NTF */
1946 if (cpl_table_get_nrow(calculate_spec_out) > 0) {
1947
1948 /* Calculate NF column and RMS_NF */
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);
1952
1953 /* Calculate NTF column and RMS_NTF */
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);
1957
1958 /* Calculate the standard deviation */
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);
1961
1962 cpl_msg_info(cpl_func, "RMS_NF = %g", RMS_NF);
1963 cpl_msg_info(cpl_func, "RMS_NTF = %g", RMS_NTF);
1964
1965 } else {
1966
1967 cpl_msg_warning(cpl_func, "Any values in the column MSCAL < 0");
1968 }
1969
1970 /* Remove the temporary calculate of spec_out table */
1971 cpl_table_delete(calculate_spec_out);
1972
1973 /* Write the QC BEST_FIT_MODEL parameters */
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);
1979
1980
1981 return CPL_ERROR_NONE;
1982}