39#include "eris_ifu_error.h"
40#include <eris_ifu_jitter_interface.h>
41#include <eris_ifu_jitter_static.h>
42#include <eris_ifu_lambda_corr.h>
43#include <eris_ifu_resample.h>
44#include <eris_ifu_extract_spec_static.h>
45#include <eris_ifu_efficiency_response.h>
46#include <eris_utils.h>
51#define CONTEXT "eris.eris_ifu_jitter"
53static const char eris_ifu_jitter_description[] =
"\
54This recipe performs ERIS/SPIFFIER science data reduction.\n\
56When an OH_SPEC file is provided in the SOF the recipe will use the OH lines\n\
57to correct the lambda calibration.\n\
59-----------------------------------------------------------------------------\n\
61 DO CATG Explanation Required #Frames\n\
62 ------- ----------- -------- -------\n\
63 science exposures with corresponding sky exposures: \n\
64 OBJ Science object exposure Y ? \n\
65 SKY_OBJ Sky exposure Y ? \n\
67 STD Standard star exposure Y ? \n\
68 SKY_STD Standard star sky exposure Y ? \n\
70 PSF_CALIBRATOR PSF calibration source Y ? \n\
71 SKY_PSF_CALIBRATOR PSF calibration sky exposure Y ? \n\
73 and calibration frames: \n\
74 DISTORTION Table with distortion correction pars. Y 1 \n\
75 WAVE_MAP Wavelength calibration map Y 1 \n\
76 OH_SPEC Vector holding OH lines (note 4) Y 1 \n\
77 MASTER_DARK Optional master dark image N [0,1]\n\
78 MASTER_FLAT Optional master flat image N [0,1]\n\
79 BPM_DARK Optional bad pixel mask (note 1 & 3) N [0,1]\n\
80 BPM_FLAT Optional bad pixel mask (note 2 & 3) N [0,1]\n\
81 BPM_LINEARITY Optional bad pixel mask (note 3) N [0,1]\n\
82 EXTCOEFF_TABLE Table with atmospheric extinction N [0,1]\n\
83 FLUX_STD_CATALOG Table with ref flux std star spectra N [0,1]\n\
84 EFFICIENCY_WINDOWS Table with ranges to compute efficiency N [0,1]\n\
85 FIT_AREAS Table with ranges to perform fit N [0,1]\n\
86 HIGH_ABS_REGIONS Table with listed High Abs. Regions N [0,1]\n\
87 QUALITY_AREAS Table with quality regions area N [0,1]\n\
88 RESP_FIT_POINTS_CATALOG Table with points where to fit resp N [0,1]\n\
89 RESPONSE_WINDOWS Table with regions for response computation N [0,1]\n\
90 TELL_MOD_CATALOG Catalog with tellurics models N [0,1]\n\
92 and only in case of old SINFONIE way of distortion correction:\n\
93 DISTANCES Table with slitlet distances \n\
94 with cube.slitlet-detection=\"DIST\" Y 1 \n\
95 SLITLET_POS Table with slitlet edge positions \n\
96 with cube.slitlet-detection=\"EDGE\" Y 1 \n\
99 DO CATG Explanation Product Depth\n\
100 ------- ------------------------------------------- -------------\n\
101 OBJECT_CUBE reconstructed object expoure (note 5) PD_AUX\n\
102 SKY_CUBE reconstructed sky exposure (note 6) PD_AUX\n\
104Note 1) When BPM_DARK is provided this will be used as hot bad pixel mask.\n\
105 Otherwise the qualiiy extension of MASTER_DARK will be used.\n\
106Note 2 When BPM_FLAT is provided this will be used as cold bad pixel mask.\n\
107 Otherwise the qualiiy extension of MASTER_FLAT will be used.\n\
108Note 3) All BPMs will be ORed.\n\
109Note 4) OH_SPEC can be a FITS file holding a single OH spectrum in the primary\n\
110 HDU or a FITS file with several extensions each of them holding an OH spectrum\n\
111 for one of the bands J,H,K,HK.\n\
112 The pipeline package provides the file eris_oh_spec.fits holding OH spectra\n\
114Note 5) If SKY_TWEAK is selected no image will be subtracted, else if there is\n\
115 a matching sky exposure this exposure will be subtracted. Else if a masterDark\n\
116 image is available this image will be subtracted\n\
117Note 6) If SKY_TWEAK is selected no image will be subtracted. Else if a masterDark\n\
118 image is available this image will be subtracted\n\
120Information on relevant parameters may be found with\n\
121 esorex --params "REC_NAME_JITTER
"\n\
122 esorex --help "REC_NAME_JITTER
"\n\
125ESO QC LAMBDA SHIFT UM OH based shift of the central wavelength in [um]\n\
126ESO QC LAMBDA SHIFT PIXEL OH based shift of the central wavelength in [pixel]\n\
133cpl_recipe_define(eris_ifu_jitter, ERIS_BINARY_VERSION,
"Erich Wiezorrek",
134 PACKAGE_BUGREPORT,
"2019",
135 "This recipe reconstruct data cubes from object exposures",
136 eris_ifu_jitter_description);
138#define RECIPE_NAME "eris_ifu_jitter"
154static cpl_error_code eris_ifu_jitter_fill_parameterlist(cpl_parameterlist *pl)
156 cpl_error_code err = CPL_ERROR_NONE;
161 REC_NAME_JITTER, M_SCIENCE, pl);
163 err = cpl_error_get_code();
177eris_crea_dummy_sky_frame(cpl_frameset* obj_set,
const int method)
180 cpl_imagelist* obj_list=NULL;
181 cpl_image* fake_sky=NULL;
182 cpl_frame* frame=NULL;
183 cpl_frame* sky_frame=NULL;
185 cpl_propertylist* plist=NULL;
186 const char* filename;
188 obj_list = cpl_imagelist_load_frameset(obj_set,CPL_TYPE_DOUBLE,0,0);
190 fake_sky = cpl_imagelist_collapse_median_create(obj_list);
191 }
else if(method == 3) {
192 fake_sky = cpl_imagelist_collapse_create(obj_list);
194 frame = cpl_frameset_get_position(obj_set,0);
195 filename = cpl_frame_get_filename(frame);
197 plist = cpl_propertylist_load(filename, 0);
199 if (cpl_propertylist_has(plist, FHDR_DPR_TYPE)) {
200 cpl_propertylist_set_string(plist, FHDR_DPR_TYPE,
"SKY");
202 cpl_propertylist_append_string(plist, FHDR_DPR_TYPE,
"SKY") ;
205 cpl_image_save(fake_sky,
"out_fake_sky.fits", CPL_BPP_IEEE_FLOAT,
206 plist,CPL_IO_DEFAULT);
208 cpl_propertylist_delete(plist);
210 sky_frame = cpl_frame_new();
211 cpl_frame_set_filename(sky_frame,
"out_fake_sky.fits") ;
212 cpl_frame_set_tag(sky_frame,
"SKY") ;
213 cpl_frame_set_type(sky_frame, CPL_FRAME_TYPE_IMAGE);
214 cpl_frame_set_group(sky_frame, CPL_FRAME_GROUP_RAW);
216 cpl_frame_set_level(sky_frame, CPL_FRAME_LEVEL_FINAL);
217 cpl_image_delete(fake_sky);
218 cpl_imagelist_delete(obj_list);
237eris_get_sky_frame(cpl_frameset* raws,
const cpl_size i,
const double mjd_obj,
238 const double obj_cumx,
const double obj_cumy)
242 cpl_frame* sky_frm_inf = NULL;
243 cpl_frame* sky_frm_sup = NULL;
244 cpl_frame* sky_frm = NULL;
245 double mjd_sky_inf = 0;
246 double mjd_sky_sup = 0;
247 double sky_inf_cumx = 0;
248 double sky_inf_cumy = 0;
249 double sky_sup_cumx = 0;
250 double sky_sup_cumy = 0;
252 double cum_thres = 0.001;
256 cpl_propertylist* plist;
258 cpl_size nobj = cpl_frameset_get_size(raws);
261 sky_frm_inf = cpl_frameset_get_position(raws, i-1);
268 sky_frm_sup = cpl_frameset_get_position(raws, i+1);
275 sky_frm = sky_frm_sup;
277 else if(i == (nobj-1)) {
278 sky_frm = sky_frm_inf;
280 if( fabs( mjd_sky_inf - mjd_obj ) <
281 fabs( mjd_sky_sup - mjd_obj ) ) {
282 if((fabs(sky_inf_cumx - obj_cumx) > cum_thres) ||
283 (fabs(sky_inf_cumy - obj_cumy) > cum_thres)) {
284 sky_frm = sky_frm_inf;
286 sky_frm = sky_frm_sup;
289 if((fabs(sky_sup_cumx - obj_cumx) > cum_thres) ||
290 (fabs(sky_sup_cumy - obj_cumy) > cum_thres)) {
291 sky_frm = sky_frm_sup;
293 sky_frm = sky_frm_inf;
298 sky_name = cpl_sprintf(
"%s", cpl_frame_get_filename(sky_frm));
303 if (strstr(sky_name,
"." ) != NULL ) {
304 fake_sky_name = cpl_sprintf(
"%s%lld%s",
"out_fake_sky", i,
".fits");
306 fake_sky_name = cpl_sprintf(
"%s", sky_name) ;
309 sky_ima = cpl_image_load(sky_name, CPL_TYPE_DOUBLE,0,0);
310 plist = cpl_propertylist_load(sky_name, 0);
312 cpl_msg_error(cpl_func,
313 "getting header from reference ima frame %s",sky_name);
317 if (cpl_propertylist_has(plist, FHDR_DPR_TYPE)) {
318 cpl_propertylist_set_string(plist, FHDR_DPR_TYPE,
"SKY");
320 cpl_propertylist_append_string(plist, FHDR_DPR_TYPE,
"SKY") ;
322 double mjd_obs_eps = 0.0001;
323 if (cpl_propertylist_has(plist, FHDR_MJD_OBS)) {
324 cpl_propertylist_set_double(plist, FHDR_MJD_OBS, (mjd_obj+mjd_obs_eps));
326 cpl_propertylist_append_double(plist, FHDR_MJD_OBS, (mjd_obj+mjd_obs_eps)) ;
329 cpl_image_save(sky_ima, fake_sky_name, CPL_BPP_IEEE_FLOAT, plist,
332 cpl_propertylist_delete(plist);
333 cpl_image_delete(sky_ima);
335 cpl_frame_set_filename(sky_frm, fake_sky_name);
336 cpl_frame_set_tag(sky_frm, ERIS_IFU_RAW_SKY) ;
337 cpl_frame_set_type(sky_frm, CPL_FRAME_TYPE_IMAGE);
338 cpl_frame_set_group(sky_frm, CPL_FRAME_GROUP_RAW);
339 cpl_frame_set_level(sky_frm, CPL_FRAME_LEVEL_FINAL);
341 cpl_free(fake_sky_name);
357eris_create_obj_sky_pairs(cpl_frameset* frameset,
const int method,
358 cpl_boolean * crea_fake_sky){
362 cpl_frame* obj_frm = NULL;
364 cpl_frame* sky_frm = NULL;
371 cpl_frameset* raws = cpl_frameset_new();
373 cpl_size nobj = cpl_frameset_get_size(raws);
377 cpl_frameset* sky_set = cpl_frameset_new();
378 for( cpl_size i = 0; i < nobj; i++) {
380 obj_frm = cpl_frameset_get_position(raws, i);
385 sky_frm = eris_get_sky_frame(raws, i, mjd_obj, obj_cumx, obj_cumy);
387 cpl_msg_info(cpl_func,
"obj: %s %s", cpl_frame_get_filename(obj_frm), cpl_frame_get_tag(obj_frm));
388 cpl_msg_info(cpl_func,
"sky: %s %s", cpl_frame_get_filename(sky_frm), cpl_frame_get_tag(sky_frm));
390 dup_frm = cpl_frame_duplicate(sky_frm);
391 cpl_frameset_insert(sky_set, dup_frm);
396 cpl_size nsky = cpl_frameset_get_size(sky_set);
397 for(cpl_size i = 0; i < nsky; i++) {
398 sky_frm = cpl_frameset_get_position(sky_set, i);
399 cpl_frameset_insert(frameset, cpl_frame_duplicate(sky_frm));
401 cpl_frameset_delete(sky_set);
402 *crea_fake_sky = CPL_TRUE;
403 }
else if(method > 1 && method < 4) {
405 sky_frm = eris_crea_dummy_sky_frame(raws, method);
406 cpl_frameset_insert (frameset, cpl_frame_duplicate(sky_frm));
407 *crea_fake_sky = CPL_TRUE;
408 }
else if(method == 4) {
410 }
else if(method == 5) {
412 }
else if(method == 6) {
414 }
else if(method == 7) {
417 }
else if(method == 8) {
422 cpl_msg_error(cpl_func,
"aj-method: %d not supported. Supported are: [0,3]", method);
427 cpl_frameset_delete(raws);
429 return cpl_error_get_code();
441static int eris_ifu_jitter(cpl_frameset *frameset,
442 const cpl_parameterlist * parlist)
444 struct stdParamStruct stdParams = stdParamStructInit;
445 struct paramStruct params;
446 struct sofStruct sof;
447 (void)memset(&sof, 0,
sizeof(sof));
448 cpl_boolean crea_fake_sky = CPL_FALSE;
452 const char* required_tags[1] = {
453 ERIS_IFU_CALIB_OH_SPEC
456 cpl_ensure_code(CPL_ERROR_NONE ==
457 eris_dfs_check_input_tags(frameset, required_tags, ntags, 1),
458 CPL_ERROR_ILLEGAL_INPUT);
462 cpl_msg_info(cpl_func,
"Reading recipe parameters");
464 &stdParams, ¶ms);
466 cpl_msg_info(cpl_func,
467 "Instrument is %d, requested product level is %d",
468 stdParams.instrument, stdParams.productDepth);
470 char* param_name = cpl_sprintf(
"%s.aj-method", CONTEXT);
471 const int aj_method = cpl_parameter_get_int(
472 cpl_parameterlist_find_const(parlist, param_name));
473 cpl_free(param_name);
476 (NULL == cpl_frameset_find(frameset, ERIS_IFU_RAW_SKY)) &&
477 (NULL == cpl_frameset_find(frameset, ERIS_IFU_RAW_OBJ_SKY))
481 eris_create_obj_sky_pairs(frameset, aj_method, &crea_fake_sky);
488 cpl_msg_info(cpl_func,
"Instrument %s, band %s, scale %s",
493 if (sof.mode != SCIENCE) {
495 "Please use the eris_ifu_stdstar recipe for PSF, STD STAR ...");
500 frameset, parlist, RECIPE_NAME, CONTEXT));
502 cubeType obj_type = OBJECT_CUBE;
503 cubeType resampled_obj_type = OBJECT_CUBE_COADD;
505 cpl_boolean is_pupil_tracking = CPL_FALSE;
508 parlist, RECIPE_NAME, &obj_type));
512 if (cpl_frameset_count_tags(frameset, ERIS_IFU_PRO_JITTER_DAR_CUBE)
515 resampled_obj_type = DAR_CUBE_COADD;
516 proCatg = ERIS_IFU_PRO_JITTER_DAR_CUBE;
517 }
else if (cpl_frameset_count_tags(frameset, ERIS_IFU_PRO_JITTER_TWK_CUBE)
519 obj_type = TWEAKED_CUBE;
520 resampled_obj_type = TWEAKED_CUBE_COADD;
521 proCatg = ERIS_IFU_PRO_JITTER_TWK_CUBE;
523 obj_type = OBJECT_CUBE;
524 resampled_obj_type = OBJECT_CUBE_COADD;
525 proCatg = ERIS_IFU_PRO_JITTER_OBJ_CUBE;
529 cpl_frame* frm_obj = cpl_frameset_find(frameset,ERIS_IFU_RAW_OBJ);
530 const char* fname = cpl_frame_get_filename(frm_obj);
531 cpl_propertylist* plist = cpl_propertylist_load(fname,0);
532 const char* dpr_tech = cpl_propertylist_get_string(plist,FHDR_DPR_TECH);
533 if(strstr(dpr_tech,
"IFU,NODDING,PT") != NULL) {
534 is_pupil_tracking = CPL_TRUE;
536 cpl_propertylist_delete(plist);
539 char *combDoCatg = NULL;
540 char *filenameSpec = NULL;
544 if (params.combine && sof.objectCnt > 1) {
545 if(!is_pupil_tracking){
546 cpl_msg_warning(cpl_func,
"Combines individual cubes with proCatg: %s",proCatg);
548 combDoCatg, filenameSpec,
550 RECIPE_NAME, RECIPE_NAME)) {
553 if (params.extractSource && eris_can_extract(frameset)) {
555 proCatg, stdParams, RECIPE_NAME, CONTEXT);
558 cpl_error_set(cpl_func, CPL_ERROR_NONE);
561 cpl_msg_warning(cpl_func,
"pupil tracking: no cube combination (no extraction)");
564 cpl_msg_warning(cpl_func,
"Duplicate cube with proCatg: %s",proCatg);
568 RECIPE_NAME, CPL_TRUE, CPL_FALSE);
570 if (params.extractSource && eris_can_extract(frameset)) {
572 proCatg, stdParams, RECIPE_NAME, CONTEXT);
578 param_name = cpl_sprintf(
"%s.flux-calibrate", CONTEXT);
579 cpl_boolean flux_calibrate = cpl_parameter_get_bool(
580 cpl_parameterlist_find_const(parlist, param_name));
581 cpl_free(param_name);
583 param_name = cpl_sprintf(
"%s.extract-source", CONTEXT);
584 cpl_boolean extract_source = cpl_parameter_get_bool(
585 cpl_parameterlist_find_const(parlist, param_name));
586 cpl_free(param_name);
589 if(flux_calibrate && eris_can_flux_calibrate(frameset)) {
592 cpl_msg_info(cpl_func,
"Flux calibrate extracted spectrum");
593 eris_flux_calibrate_spectra(RECIPE_NAME, RECIPE_NAME, parlist,
596 char* cube_pro_catg = NULL;
597 if(obj_type == DAR_CUBE) {
598 cube_pro_catg = cpl_sprintf(
"%s",ERIS_IFU_PRO_JITTER_OBJ_DAR_CUBE_COADD);
599 }
else if(obj_type == TWEAKED_CUBE) {
600 cube_pro_catg = cpl_sprintf(
"%s",ERIS_IFU_PRO_JITTER_TWK_CUBE_COADD);
602 cube_pro_catg = cpl_sprintf(
"%s",ERIS_IFU_PRO_JITTER_OBJ_CUBE_COADD);
606 cpl_msg_info(cpl_func,
"proCatg: %s",cube_pro_catg);
608 cpl_msg_info(cpl_func,
"Flux calibrate combined data cube");
609 eris_flux_calibrate_cube2(cube_pro_catg, RECIPE_NAME, RECIPE_NAME, parlist,
611 cpl_free(cube_pro_catg);
622 if(crea_fake_sky == CPL_TRUE) {
624 cmd = cpl_sprintf(
"rm out_fake_sky*.fits");
625 int status = system(cmd);
627 cpl_msg_warning(cpl_func,
"call to system() failed");
633 return (
int)cpl_error_get_code();
double eris_get_mjd_obs(cpl_frame *frame)
find out the Julian Date of the observation
double eris_get_cumoffs_ra(cpl_frame *frame)
find out the ESO OCS CUMOFFS RA of the observation
cpl_error_code eris_ifu_dfs_set_groups(cpl_frameset *self)
Set the frame group (RAW, CALIB, or PRODUCT) for all frames in a frameset.
double eris_get_cumoffs_dec(cpl_frame *frame)
find out the ESO OCS CUMOFFS DEC of the observation
#define BRK_IF_ERROR(function)
If function is or returns an error != CPL_ERROR_NONE, then the try-block is exited.
#define BRK_WITH_ERROR_MSG(code,...)
Set a new CPL error, and exit the try-block.
#define TRY
Beginning of a TRY-block.
#define CATCH
End of a TRY-block, beginning of a CATCH-block.
#define CATCH_MSGS()
Displays an error message stack.
void eris_ifu_free_std_param(struct stdParamStruct *stdParams)
Free memory allocated for stdParamStruct.
cpl_error_code eris_ifu_jitter_processSof(cpl_frameset *frames, struct stdParamStruct stdParams, struct paramStruct params, struct sofStruct *sof)
Process SOF (Set of Frames) file and load all calibration data.
cpl_error_code eris_ifu_jitter_fetch_params(const char *context, const char *recipe_name, const cpl_parameterlist *parlist, struct stdParamStruct *stdParams, struct paramStruct *params)
Fetch and parse jitter recipe parameters from parameter list.
cpl_error_code eris_ifu_jitter_fill_common_parameterlist(const char *recipeName, jitterModes jitterMode, cpl_parameterlist *pl)
Fill parameter list with common jitter recipe parameters.
cpl_error_code eris_ifu_jitter_process_cubes(struct sofStruct *sof, struct stdParamStruct stdParams, struct paramStruct params, cpl_frameset *frameset, const cpl_parameterlist *parlist, const char *recipe_name, cubeType *obj_type)
Process and combine data cubes with sky tweaking and DAR correction.
void eris_ifu_jitter_free_sofStruct(struct sofStruct *sof_struct)
Free and clean up SOF structure and all contained data.
cpl_error_code eris_ifu_jitter_extract(cpl_frameset *frameset, const cpl_parameterlist *parlist, cubeType obj_type, const char *pcatg, struct stdParamStruct stdParams, const char *pipefile_prefix, const char *context)
Main spectral extraction function.
cpl_error_code eris_frameset_duplicate_cube_tag(cpl_frameset *frameset, const char *pcatg, cpl_boolean apply_flat)
Duplicate a cube file with different PRODCATG for coadded version.
cpl_error_code eris_ifu_jitter_get_procatg_and_filename(cubeType type, char **proCatg, char **filenamePrefix)
Get the value of the PRO.CATG and the filename as function of the type of cube.
cpl_error_code eris_ifu_jitter_process_exposures(struct sofStruct *sof, struct stdParamStruct stdParams, struct paramStruct params, cpl_frameset *frameset, const cpl_parameterlist *parlist, const char *recipe_name, const char *context)
Process all raw exposures into calibrated 3D data cubes.
cpl_error_code eris_ifu_combine_pbp(cpl_frameset *frameset, const cpl_parameterlist *parlist, const char *input_cube_pro_catg, const char *filenameSpec, float *offsetx, float *offsety, const char *offunit, const char *recipe_name, const char *pipefile_prefix)
Resample and combine cubes plane-by-plane (2D spatial resampling per wavelength)
cpl_error_code eris_ifu_cube_collapse_mean_and_save(const char *pro_catg, cpl_frameset *frameset, const cpl_parameterlist *parlist, const char *recipe_name, cpl_boolean apply_flat, cpl_boolean is_pupil)
-------------------------------------------------------------------------—/
void eris_ifu_free_string(char **item)
Free memory and set pointer to null.
const char * eris_ifu_get_bandString(ifsBand band)
Convert band enum to string.
const char * eris_ifu_get_instrumentString(ifsInstrument instrument)
Convert instrument enum to string.
const char * eris_ifu_get_preopticsScaleString(ifsPreopticsScale scale)
Convert pre-optics scale enum to string.
cpl_error_code eris_check_error_code(const char *func_id)
handle CPL errors
cpl_error_code eris_dfs_extract_raw_frames(cpl_frameset *input, cpl_frameset *raws)
split input sof in groups: raw and calib