31#include "cr2res_utils.h"
32#include "cr2res_idp.h"
33#include "cr2res_nodding.h"
34#include "cr2res_calib.h"
35#include "cr2res_pfits.h"
36#include "cr2res_dfs.h"
37#include "cr2res_bpm.h"
38#include "cr2res_trace.h"
39#include "cr2res_extract.h"
42#include "cr2res_photom.h"
48#define RECIPE_STRING "cr2res_obs_nodding"
54int cpl_plugin_get_info(cpl_pluginlist * list);
60static int cr2res_obs_nodding_astrometry_compare(
61 const cpl_frame * frame1,
62 const cpl_frame * frame2) ;
63static cpl_frameset * cr2res_obs_nodding_find_RAW(
64 const cpl_frameset * in,
66static int cr2res_obs_nodding_check_inputs_validity(
67 const cpl_frameset * rawframes) ;
68static int cr2res_obs_nodding_reduce(
69 const cpl_frameset * rawframes,
70 const cpl_frame * trace_wave_frame,
71 const cpl_frame * detlin_frame,
72 const cpl_frame * master_dark_frame,
73 const cpl_frame * master_flat_frame,
74 const cpl_frame * bpm_frame,
75 const cpl_frame * blaze_frame,
77 int subtract_nolight_rows,
78 int subtract_interorder_column,
81 int extract_oversample,
82 int extract_swath_width,
84 double extract_smooth_slit,
85 double extract_smooth_spec,
92 hdrl_image ** combineda,
93 cpl_table ** extracta,
94 cpl_table ** slitfunca,
97 hdrl_image ** combinedb,
98 cpl_table ** extractb,
99 cpl_table ** slitfuncb,
100 hdrl_image ** modelb,
102 cpl_table ** extractc,
103 cpl_propertylist ** ext_plist) ;
105static int cr2res_obs_nodding_create(cpl_plugin *);
106static int cr2res_obs_nodding_exec(cpl_plugin *);
107static int cr2res_obs_nodding_destroy(cpl_plugin *);
108static int cr2res_obs_nodding(cpl_frameset *,
const cpl_parameterlist *);
114static char cr2res_obs_nodding_description[] =
"\
115Nodding Observation \n\
116 This recipe handles nodding observations. It expects an even number \n\
117 of rawframes in input, and as many A positions as B positions \n\
118 If the input are standard stars, it computes a post processing step \n\
119 to determine the throughput. \n\
120 If the input are spectro astrometric data, it will apply the nodding \n\
121 on each of the sub-groups \n\
124 raw.fits " CR2RES_CAL_NODDING_OTHER_RAW
" [2 to 2n] \n\
125 or " CR2RES_CAL_NODDING_JITTER_RAW
" [2 to 2n] \n\
126 or " CR2RES_OBS_NODDING_OTHER_RAW
" [2 to 2n] \n\
127 or " CR2RES_OBS_NODDING_JITTER_RAW
" [2 to 2n] \n\
128 or " CR2RES_OBS_ASTROMETRY_OTHER_RAW
" [2 to 2n] \n\
129 or " CR2RES_OBS_ASTROMETRY_JITTER_RAW
" [2 to 2n] \n\
130 trace.fits " CR2RES_CAL_FLAT_TW_PROCATG
" [1] \n\
131 or " CR2RES_CAL_FLAT_TW_MERGED_PROCATG
" \n\
132 or " CR2RES_UTIL_TRACE_TW_PROCATG
" \n\
133 or " CR2RES_UTIL_WAVE_TW_PROCATG
" \n\
134 or " CR2RES_CAL_WAVE_TW_PROCATG
" \n\
135 or " CR2RES_UTIL_SLIT_CURV_TW_PROCATG
" \n\
136 detlin.fits " CR2RES_CAL_DETLIN_COEFFS_PROCATG
" [0 to 1] \n\
137 bpm.fits " CR2RES_CAL_DARK_BPM_PROCATG
" [0 to 1] \n\
138 or " CR2RES_CAL_FLAT_BPM_PROCATG
" \n\
139 or " CR2RES_CAL_DETLIN_BPM_PROCATG
" \n\
140 or " CR2RES_UTIL_BPM_MERGE_PROCATG
" \n\
141 or " CR2RES_UTIL_BPM_SPLIT_PROCATG
" \n\
142 master_dark.fits " CR2RES_CAL_DARK_MASTER_PROCATG
" [0 to 1] \n\
143 master_flat.fits " CR2RES_CAL_FLAT_MASTER_PROCATG
" [0 to 1] \n\
144 photo_flux.fits " CR2RES_PHOTO_FLUX_PROCATG
" [0 to 1] \n\
145 blaze.fits " CR2RES_CAL_FLAT_EXTRACT_1D_PROCATG
" [0 to 1] \n\
148 cr2res_obs_nodding_extractedA.fits "
149 CR2RES_OBS_NODDING_EXTRACTA_PROCATG
"\n\
150 cr2res_obs_nodding_extractedB.fits "
151 CR2RES_OBS_NODDING_EXTRACTB_PROCATG
"\n\
152 cr2res_obs_nodding_combinedA.fits "
153 CR2RES_OBS_NODDING_COMBINEDA_PROCATG
"\n\
154 cr2res_obs_nodding_combinedB.fits "
155 CR2RES_OBS_NODDING_COMBINEDB_PROCATG
"\n\
156 cr2res_obs_nodding_trace_wave_A.fits "
157 CR2RES_OBS_NODDING_TWA_PROCATG
"\n\
158 cr2res_obs_nodding_trace_wave_B.fits "
159 CR2RES_OBS_NODDING_TWB_PROCATG
"\n\
160 cr2res_obs_nodding_modelA.fits "
161 CR2RES_OBS_NODDING_SLITMODELA_PROCATG
"\n\
162 cr2res_obs_nodding_modelB.fits "
163 CR2RES_OBS_NODDING_SLITMODELB_PROCATG
"\n\
164 cr2res_obs_nodding_slitfuncA.fits "
165 CR2RES_OBS_NODDING_SLITFUNCA_PROCATG
"\n\
166 cr2res_obs_nodding_slitfuncB.fits "
167 CR2RES_OBS_NODDING_SLITFUNCB_PROCATG
"\n\
168 cr2res_obs_nodding_throughput.fits "
169 CR2RES_OBS_NODDING_THROUGHPUT_PROCATG
"\n\
172 loop on detectors d: \n\
173 call cr2res_obs_nodding_reduce() \n\
174 -> combined[a|b](d) \n\
175 -> extract[a|b|c](d) \n\
176 -> slitfunc[a|b](d) \n\
179 Save combineda and combinedb \n\
180 Save extracta, extractb, extractc \n\
181 Save slitfunca and slitfuncb \n\
182 Save modela and modelb \n\
185 cr2res_obs_nodding_reduce() \n\
186 Load the input raw frames in an image list \n\
187 Apply the calibrations to the image list \n\
188 Split the list in listA and listB image lists \n\
189 Compute diffA=listA-listB and diffB=listB-listA \n\
190 Collapse diffA and diffB \n\
192 Load the input trace wave \n\
193 Compute the slit fractions for A and B by using the nodthrow \n\
194 and the assumption that A and B are at equal distances \n\
195 from the slit center. \n\
196 Compute 2 new trace_wave files with these 2 computed slit fractions\n\
197 Extract the spectra for A and for B \n\
198 -> extracted[a|b] \n\
199 -> slit_func[a|b] \n\
200 -> model_master[a|b] \n\
201 -> trace_wave[a|b] \n\
202 Compute QC parameters \n\
203 If STD star, compute the throughput \n\
206 Library functions used \n\
207 cr2res_io_find_TRACE_WAVE() \n\
208 cr2res_io_find_BPM() \n\
209 cr2res_obs_nodding_reduce() \n\
210 cr2res_nodding_read_positions() \n\
211 cr2res_io_read_dits() \n\
212 cr2res_io_load_image_list_from_set() \n\
213 cr2res_calib_imagelist() \n\
214 cr2res_combine_nodding_split() \n\
215 cr2res_io_load_TRACE_WAVE() \n\
216 cr2res_pfits_get_nodthrow() \n\
217 cr2res_trace_new_slit_fraction() \n\
218 cr2res_extract_traces() \n\
219 cr2res_qc_obs_nodding_signal() \n\
220 cr2res_qc_obs_nodding_transmission() \n\
221 cr2res_qc_obs_slit_psf() \n\
222 cr2res_photom_engine() \n\
223 cr2res_io_save_COMBINED() \n\
224 cr2res_io_save_EXTRACT_1D() \n\
225 cr2res_io_save_SLIT_FUNC() \n\
226 cr2res_io_save_SLIT_MODEL() \n\
227 cr2res_io_save_THROUGHPUT() \n\
246int cpl_plugin_get_info(cpl_pluginlist * list)
248 cpl_recipe * recipe = cpl_calloc(1,
sizeof *recipe );
249 cpl_plugin * plugin = &recipe->interface;
251 if (cpl_plugin_init(plugin,
253 CR2RES_BINARY_VERSION,
254 CPL_PLUGIN_TYPE_RECIPE,
256 "Nodding Observation recipe",
257 cr2res_obs_nodding_description,
258 CR2RES_PIPELINE_AUTHORS,
261 cr2res_obs_nodding_create,
262 cr2res_obs_nodding_exec,
263 cr2res_obs_nodding_destroy)) {
264 cpl_msg_error(cpl_func,
"Plugin initialization failed");
265 (void)cpl_error_set_where(cpl_func);
269 if (cpl_pluginlist_append(list, plugin)) {
270 cpl_msg_error(cpl_func,
"Error adding plugin to list");
271 (void)cpl_error_set_where(cpl_func);
287static int cr2res_obs_nodding_create(cpl_plugin * plugin)
289 cpl_recipe * recipe ;
293 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
294 recipe = (cpl_recipe *)plugin;
299 recipe->parameters = cpl_parameterlist_new();
302 p = cpl_parameter_new_value(
303 "cr2res.cr2res_obs_nodding.subtract_nolight_rows",
305 "Subtract median row from baffled region at detector bottom",
306 "cr2res.cr2res_obs_nodding", FALSE);
307 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"subtract_nolight_rows");
308 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
309 cpl_parameterlist_append(recipe->parameters, p);
311 p = cpl_parameter_new_value(
312 "cr2res.cr2res_obs_nodding.subtract_interorder_column",
314 "Subtract column-by-column fit to the pixel values between orders",
315 "cr2res.cr2res_obs_nodding", TRUE);
316 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
317 "subtract_interorder_column");
318 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
319 cpl_parameterlist_append(recipe->parameters, p);
321 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.cosmics",
322 CPL_TYPE_BOOL,
"Find and mark cosmic rays hits as bad",
323 "cr2res.cr2res_obs_nodding", FALSE);
324 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"cosmics");
325 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
326 cpl_parameterlist_append(recipe->parameters, p);
328 p = cpl_parameter_new_enum(
"cr2res.cr2res_obs_nodding.error_method",
329 CPL_TYPE_STRING,
"The 1d extraction error calculation method",
330 "cr2res.cr2res_obs_nodding",
331 "Poisson", 2,
"Poisson",
"Horne");
332 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"error_method");
333 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
334 cpl_parameterlist_append(recipe->parameters, p);
336 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.nodding_invert",
337 CPL_TYPE_BOOL,
"Flag to use when A is above B",
338 "cr2res.cr2res_obs_nodding", FALSE);
339 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"nodding_invert");
340 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
341 cpl_parameterlist_append(recipe->parameters, p);
343 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.extract_oversample",
344 CPL_TYPE_INT,
"factor by which to oversample the extraction",
345 "cr2res.cr2res_obs_nodding", 7);
346 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"extract_oversample");
347 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
348 cpl_parameterlist_append(recipe->parameters, p);
350 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.extract_swath_width",
351 CPL_TYPE_INT,
"The swath width",
"cr2res.cr2res_obs_nodding", 2048);
352 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"extract_swath_width");
353 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
354 cpl_parameterlist_append(recipe->parameters, p);
356 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.extract_height",
357 CPL_TYPE_INT,
"Extraction height",
"cr2res.cr2res_obs_nodding", -1);
358 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"extract_height");
359 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
360 cpl_parameterlist_append(recipe->parameters, p);
362 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.extract_smooth_slit",
363 CPL_TYPE_DOUBLE,
"Smoothing along the slit",
364 "cr2res.cr2res_obs_nodding", 1.0);
365 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"extract_smooth_slit");
366 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
367 cpl_parameterlist_append(recipe->parameters, p);
369 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.extract_smooth_spec",
370 CPL_TYPE_DOUBLE,
"Smoothing along spectrum",
371 "cr2res.cr2res_obs_nodding", 8e-8);
372 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"extract_smooth_spec");
373 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
374 cpl_parameterlist_append(recipe->parameters, p);
376 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.detector",
377 CPL_TYPE_INT,
"Only reduce the specified detector",
378 "cr2res.cr2res_obs_nodding", 0);
379 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"detector");
380 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
381 cpl_parameterlist_append(recipe->parameters, p);
383 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.create_idp",
384 CPL_TYPE_BOOL,
"Flag to produce IDP files",
385 "cr2res.cr2res_obs_nodding", FALSE);
386 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"idp");
387 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
388 cpl_parameterlist_append(recipe->parameters, p);
390 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.display_detector",
391 CPL_TYPE_INT,
"Apply the display for the specified detector",
392 "cr2res.cr2res_obs_nodding", 0);
393 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"display_detector");
394 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
395 cpl_parameterlist_append(recipe->parameters, p);
397 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.display_order",
398 CPL_TYPE_INT,
"Apply the display for the specified order",
399 "cr2res.cr2res_obs_nodding", 1000);
400 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"display_order");
401 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
402 cpl_parameterlist_append(recipe->parameters, p);
404 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.display_trace",
405 CPL_TYPE_INT,
"Apply the display for the specified trace",
406 "cr2res.cr2res_obs_nodding", 0);
407 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"display_trace");
408 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
409 cpl_parameterlist_append(recipe->parameters, p);
421static int cr2res_obs_nodding_exec(cpl_plugin * plugin)
426 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
427 recipe = (cpl_recipe *)plugin;
430 return cr2res_obs_nodding(recipe->frames, recipe->parameters);
440static int cr2res_obs_nodding_destroy(cpl_plugin * plugin)
445 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
446 recipe = (cpl_recipe *)plugin;
449 cpl_parameterlist_delete(recipe->parameters);
461static int cr2res_obs_nodding(
462 cpl_frameset * frameset,
463 const cpl_parameterlist * parlist)
465 const cpl_parameter * param ;
466 int extract_oversample, extract_swath_width,
467 extract_height, reduce_det,
468 disp_order_idx, disp_trace, disp_det,
469 nodding_invert, create_idp, subtract_nolight_rows,
470 subtract_interorder_column, cosmics,
472 double extract_smooth_slit, extract_smooth_spec;
474 double ra, dec, mjd_obs, mjd_cen, geolon, geolat, geoelev,
476 cpl_frameset * rawframes ;
477 cpl_frameset * raw_flat_frames ;
478 const cpl_frame * trace_wave_frame ;
479 const cpl_frame * detlin_frame ;
480 const cpl_frame * master_dark_frame ;
481 const cpl_frame * photo_flux_frame ;
482 const cpl_frame * blaze_frame ;
483 const cpl_frame * master_flat_frame ;
484 const cpl_frame * bpm_frame ;
486 cpl_size nlabels, l ;
487 char * product_name_addon ;
488 hdrl_image * combineda[CR2RES_NB_DETECTORS] ;
489 cpl_table * extracta[CR2RES_NB_DETECTORS] ;
490 cpl_table * slitfunca[CR2RES_NB_DETECTORS] ;
491 hdrl_image * modela[CR2RES_NB_DETECTORS] ;
492 cpl_table * twa[CR2RES_NB_DETECTORS] ;
493 hdrl_image * combinedb[CR2RES_NB_DETECTORS] ;
494 cpl_table * extractb[CR2RES_NB_DETECTORS] ;
495 cpl_table * slitfuncb[CR2RES_NB_DETECTORS] ;
496 hdrl_image * modelb[CR2RES_NB_DETECTORS] ;
497 cpl_table * twb[CR2RES_NB_DETECTORS] ;
498 cpl_table * extractc[CR2RES_NB_DETECTORS] ;
499 cpl_table * throughput[CR2RES_NB_DETECTORS] ;
500 cpl_propertylist * qc_main ;
501 cpl_propertylist * ext_plist[CR2RES_NB_DETECTORS] ;
502 cpl_propertylist * ext_plist_photom[CR2RES_NB_DETECTORS] ;
505 cpl_table * eop_table ;
513 param = cpl_parameterlist_find_const(parlist,
514 "cr2res.cr2res_obs_nodding.subtract_nolight_rows");
515 subtract_nolight_rows = cpl_parameter_get_bool(param);
516 param = cpl_parameterlist_find_const(parlist,
517 "cr2res.cr2res_obs_nodding.subtract_interorder_column");
518 subtract_interorder_column = cpl_parameter_get_bool(param);
519 param = cpl_parameterlist_find_const(parlist,
520 "cr2res.cr2res_obs_nodding.nodding_invert");
521 nodding_invert = cpl_parameter_get_bool(param);
522 param = cpl_parameterlist_find_const(parlist,
523 "cr2res.cr2res_obs_nodding.extract_oversample");
524 extract_oversample = cpl_parameter_get_int(param);
525 param = cpl_parameterlist_find_const(parlist,
526 "cr2res.cr2res_obs_nodding.extract_swath_width");
527 extract_swath_width = cpl_parameter_get_int(param);
528 param = cpl_parameterlist_find_const(parlist,
529 "cr2res.cr2res_obs_nodding.extract_height");
530 extract_height = cpl_parameter_get_int(param);
531 param = cpl_parameterlist_find_const(parlist,
532 "cr2res.cr2res_obs_nodding.extract_smooth_slit");
533 extract_smooth_slit = cpl_parameter_get_double(param);
534 param = cpl_parameterlist_find_const(parlist,
535 "cr2res.cr2res_obs_nodding.extract_smooth_spec");
536 extract_smooth_spec = cpl_parameter_get_double(param);
537 param = cpl_parameterlist_find_const(parlist,
538 "cr2res.cr2res_obs_nodding.detector");
539 reduce_det = cpl_parameter_get_int(param);
540 param = cpl_parameterlist_find_const(parlist,
541 "cr2res.cr2res_obs_nodding.create_idp");
542 create_idp = cpl_parameter_get_bool(param);
543 param = cpl_parameterlist_find_const(parlist,
544 "cr2res.cr2res_obs_nodding.display_detector");
545 disp_det = cpl_parameter_get_int(param);
546 param = cpl_parameterlist_find_const(parlist,
547 "cr2res.cr2res_obs_nodding.display_order");
548 disp_order_idx = cpl_parameter_get_int(param);
549 param = cpl_parameterlist_find_const(parlist,
550 "cr2res.cr2res_obs_nodding.display_trace");
551 disp_trace = cpl_parameter_get_int(param);
552 param = cpl_parameterlist_find_const(parlist,
553 "cr2res.cr2res_obs_nodding.cosmics");
554 cosmics = cpl_parameter_get_bool(param);
555 param = cpl_parameterlist_find_const(parlist,
556 "cr2res.cr2res_obs_nodding.error_method");
557 if(strcmp(cpl_parameter_get_string(param),
"Horne") == 0)
558 error_method = CR2RES_EXTRACT_ERROR_HORNE;
560 error_method = CR2RES_EXTRACT_ERROR_POISSON;
563 int extract_niter = 30;
564 double extract_kappa = 10;
568 cpl_msg_error(__func__,
"Cannot identify RAW and CALIB frames") ;
569 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
575 if (trace_wave_frame == NULL) {
576 cpl_msg_error(__func__,
"Could not find TRACE_WAVE frame") ;
579 detlin_frame = cpl_frameset_find_const(frameset,
580 CR2RES_CAL_DETLIN_COEFFS_PROCATG);
581 master_dark_frame = cpl_frameset_find_const(frameset,
582 CR2RES_CAL_DARK_MASTER_PROCATG) ;
583 if (master_dark_frame != NULL) {
584 cpl_msg_warning(__func__,
585 "Providing a MASTER DARK is not recommended for this recipe") ;
587 blaze_frame = cpl_frameset_find_const(frameset,
588 CR2RES_CAL_FLAT_EXTRACT_1D_PROCATG) ;
589 photo_flux_frame = cpl_frameset_find_const(frameset,
590 CR2RES_PHOTO_FLUX_PROCATG) ;
591 master_flat_frame = cpl_frameset_find_const(frameset,
592 CR2RES_CAL_FLAT_MASTER_PROCATG) ;
596 rawframes = cr2res_obs_nodding_find_RAW(frameset, &type) ;
597 if (rawframes == NULL) {
598 cpl_msg_error(__func__,
"Could not find RAW frames") ;
606 if ((labels = cpl_frameset_labelise(rawframes,
607 cr2res_obs_nodding_astrometry_compare, &nlabels)) == NULL) {
608 cpl_msg_error(__func__,
"Cannot label input frames") ;
609 cpl_frameset_delete(rawframes) ;
610 if (raw_flat_frames != NULL) cpl_frameset_delete(raw_flat_frames) ;
611 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
616 if (type != 3 && nlabels != 1) {
617 cpl_msg_error(__func__,
"Expect only one DROT POSANG value - abort") ;
618 cpl_frameset_delete(rawframes) ;
619 if (raw_flat_frames != NULL) cpl_frameset_delete(raw_flat_frames) ;
621 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
626 for (l = 0; l < (int)nlabels; l++) {
628 cpl_frameset *raw_one_angle;
629 cpl_propertylist *plist;
631 raw_one_angle = cpl_frameset_extract(rawframes, labels, (cpl_size)l) ;
634 plist = cpl_propertylist_load(cpl_frame_get_filename(
635 cpl_frameset_get_position(raw_one_angle, 0)), 0) ;
637 cpl_propertylist_delete(plist) ;
639 cpl_msg_info(__func__,
"Process Angle %g", drot_posang) ;
640 cpl_msg_indent_more() ;
643 for (det_nr = 1; det_nr <= CR2RES_NB_DETECTORS; det_nr++) {
645 combineda[det_nr - 1] = NULL;
646 extracta[det_nr - 1] = NULL;
647 slitfunca[det_nr - 1] = NULL;
648 modela[det_nr - 1] = NULL;
649 twa[det_nr - 1] = NULL;
650 combinedb[det_nr - 1] = NULL;
651 extractb[det_nr - 1] = NULL;
652 slitfuncb[det_nr - 1] = NULL;
653 modelb[det_nr - 1] = NULL;
654 twb[det_nr - 1] = NULL;
655 extractc[det_nr - 1] = NULL;
656 ext_plist[det_nr - 1] = NULL;
657 ext_plist_photom[det_nr - 1] = NULL;
658 throughput[det_nr - 1] = NULL;
661 if (reduce_det != 0 && det_nr != reduce_det)
664 cpl_msg_info(__func__,
"Process Detector %d", det_nr);
665 cpl_msg_indent_more();
668 if (cr2res_obs_nodding_reduce(
669 raw_one_angle, trace_wave_frame,
670 detlin_frame, master_dark_frame, master_flat_frame,
671 bpm_frame, blaze_frame, nodding_invert,
672 subtract_nolight_rows, subtract_interorder_column, cosmics,
674 extract_oversample, extract_swath_width, extract_height,
675 extract_smooth_slit, extract_smooth_spec, extract_niter,
676 extract_kappa, det_nr, disp_det, disp_order_idx, disp_trace,
677 &(combineda[det_nr - 1]), &(extracta[det_nr - 1]),
678 &(slitfunca[det_nr - 1]), &(modela[det_nr - 1]),
679 &(twa[det_nr - 1]), &(combinedb[det_nr - 1]),
680 &(extractb[det_nr - 1]), &(slitfuncb[det_nr - 1]),
681 &(modelb[det_nr - 1]), &(twb[det_nr - 1]),
682 &(extractc[det_nr - 1]), &(ext_plist[det_nr - 1])) == -1) {
683 cpl_msg_warning(__func__,
"Failed to reduce detector %d",
687 else if (type == 2) {
690 "Sensitivity / Conversion / Throughput computation");
691 cpl_msg_indent_more();
695 gain = CR2RES_GAIN_CHIP1;
697 gain = CR2RES_GAIN_CHIP2;
699 gain = CR2RES_GAIN_CHIP3;
702 plist = cpl_propertylist_load(
703 cpl_frame_get_filename(
704 cpl_frameset_get_position_const(raw_one_angle, 0)),
711 cpl_propertylist_delete(plist);
712 if (cpl_error_get_code()) {
713 cpl_msg_indent_less();
715 cpl_msg_warning(__func__,
"Missing Header Informations");
720 extracta[det_nr - 1],
721 cpl_frame_get_filename(photo_flux_frame),
722 cur_setting, ra, dec, gain, dit, disp_det == det_nr,
723 disp_order_idx, disp_trace,
724 &(throughput[det_nr - 1]),
725 &(ext_plist_photom[det_nr - 1])) == -1) {
726 cpl_msg_warning(__func__,
727 "Failed to reduce detector %d", det_nr);
731 cpl_free(cur_setting);
732 cpl_msg_indent_less();
734 cpl_msg_indent_less();
738 if (nlabels == 1) product_name_addon = cpl_sprintf(
".fits") ;
739 else product_name_addon = cpl_sprintf(
"_%g.fits",
743 for (det_nr=1 ; det_nr<=CR2RES_NB_DETECTORS ; det_nr++) {
744 if (ext_plist_photom[det_nr-1] != NULL &&
745 ext_plist[det_nr-1] != NULL) {
746 cpl_propertylist_append(ext_plist[det_nr-1],
747 ext_plist_photom[det_nr-1]) ;
752 qc_main = cpl_propertylist_new();
753 cpl_propertylist_append_double(qc_main,
754 CR2RES_HEADER_DRS_TMID,
759 if (eop_table != NULL) {
760 plist=cpl_propertylist_load(cpl_frame_get_filename(
761 cpl_frameset_get_position_const(raw_one_angle, 0)), 0) ;
763 ra = cpl_propertylist_get_double(plist,
"RA") ;
764 dec = cpl_propertylist_get_double(plist,
"DEC") ;
765 mjd_obs = cpl_propertylist_get_double(plist,
"MJD-OBS") ;
766 geolon = cpl_propertylist_get_double(plist,
"ESO TEL GEOLON") ;
767 geolat = cpl_propertylist_get_double(plist,
"ESO TEL GEOLAT") ;
768 geoelev = cpl_propertylist_get_double(plist,
"ESO TEL GEOELEV") ;
770 cpl_propertylist_delete(plist) ;
773 if (!cpl_error_get_code()) {
776 (mjd_cen-mjd_obs)*24*3600, geolon, geolat, geoelev,
777 0.0, 0.0, 0.0, 0.0, &barycorr);
779 cpl_msg_info(__func__,
"Barycentric correction: %g m/s",
782 cpl_msg_info(__func__,
"Cannot derive Barycentric correction");
785 cpl_table_delete(eop_table) ;
790 if(error_method == CR2RES_EXTRACT_ERROR_HORNE){
791 cpl_propertylist_append_string(qc_main, CR2RES_HEADER_DRS_ERRMETHOD,
795 cpl_propertylist_append_string(qc_main, CR2RES_HEADER_DRS_ERRMETHOD,
799 cpl_propertylist_append_int(qc_main,
800 CR2RES_HEADER_QC_NUMSAT,
805 if (trace_wave_frame != NULL)
806 cpl_frameset_insert(raw_one_angle,
807 cpl_frame_duplicate(trace_wave_frame)) ;
808 if (detlin_frame != NULL)
809 cpl_frameset_insert(raw_one_angle,
810 cpl_frame_duplicate(detlin_frame)) ;
811 if (master_dark_frame != NULL)
812 cpl_frameset_insert(raw_one_angle,
813 cpl_frame_duplicate(master_dark_frame)) ;
814 if (master_flat_frame!= NULL)
815 cpl_frameset_insert(raw_one_angle,
816 cpl_frame_duplicate(master_flat_frame)) ;
817 if (bpm_frame!= NULL)
818 cpl_frameset_insert(raw_one_angle,
819 cpl_frame_duplicate(bpm_frame)) ;
820 if (blaze_frame!= NULL)
821 cpl_frameset_insert(raw_one_angle,
822 cpl_frame_duplicate(blaze_frame)) ;
823 if (photo_flux_frame!= NULL)
824 cpl_frameset_insert(raw_one_angle,
825 cpl_frame_duplicate(photo_flux_frame)) ;
827 out_file = cpl_sprintf(
"%s_combinedA%s", RECIPE_STRING,
828 product_name_addon) ;
830 combineda, qc_main, ext_plist,
831 CR2RES_OBS_NODDING_COMBINEDA_PROCATG, RECIPE_STRING) ;
834 char *qc_perdet_keywords[] = { CR2RES_HEADER_QC_SIGNAL,
835 CR2RES_HEADER_QC_STANDARD_FLUX,
836 CR2RES_HEADER_QC_SLITFWHM_MED };
838 char *qc_pertrace_keywords[] = { CR2RES_HEADER_QC_SNR_BASE,
839 CR2RES_HEADER_QC_SLITFWHM_ORDER_BASE };
841 int qc_perdet_size =
sizeof(qc_perdet_keywords) /
sizeof(
char *);
842 int qc_pertrace_size =
sizeof(qc_pertrace_keywords) /
sizeof(
char *);
844 int qc_sizes_ext[] = {CR2RES_NB_DETECTORS};
845 cpl_propertylist** qc_plists_ext[] = {ext_plist} ;
846 char * qc_res_avg, * qc_res_rmsd, * qc_ref;
850 for (qc_i=0; qc_i<qc_perdet_size ; qc_i++) {
852 qc_res_avg = cpl_sprintf(
"%s %s",
853 qc_perdet_keywords[qc_i],
"AVG");
854 qc_res_rmsd = cpl_sprintf(
"%s %s",
855 qc_perdet_keywords[qc_i],
"RMS");
857 cr2res_qc_calculate_mean_and_rmsd(qc_plists_ext, 1, qc_sizes_ext,
858 qc_perdet_keywords[qc_i], qc_main,
859 qc_res_avg, qc_res_rmsd);
861 cpl_free(qc_res_avg);
862 cpl_free(qc_res_rmsd);
866 int min_order = INT_MAX;
867 int max_order = INT_MIN;
868 int current_min, current_max;
870 for (qc_i = 0; qc_i < CR2RES_NB_DETECTORS; qc_i++) {
871 if (twa[qc_i] == NULL) {
875 cpl_table_get_column_min(twa[qc_i],
"Order");
876 if (cpl_error_get_code() != CPL_ERROR_NONE) {
879 if (current_min < min_order) {
880 min_order = current_min;
884 cpl_table_get_column_max(twa[qc_i],
"Order");
885 if (cpl_error_get_code() != CPL_ERROR_NONE) {
888 if (current_max > max_order) {
889 max_order = current_max;
893 for (qc_i = 0; qc_i < qc_pertrace_size; qc_i++) {
894 for (
int order_id = min_order; order_id <= max_order; order_id++) {
896 qc_ref = cpl_sprintf(
"%s%d", qc_pertrace_keywords[qc_i],
899 cpl_sprintf(
"%s%d %s", qc_pertrace_keywords[qc_i],
902 cpl_sprintf(
"%s%d %s", qc_pertrace_keywords[qc_i],
905 cr2res_qc_calculate_mean_and_rmsd(qc_plists_ext, 1, qc_sizes_ext,
906 qc_ref, qc_main, qc_res_avg,
910 cpl_free(qc_res_avg);
911 cpl_free(qc_res_rmsd);
915 out_file = cpl_sprintf(
"%s_extractedA%s", RECIPE_STRING,
916 product_name_addon) ;
918 extracta, qc_main, ext_plist,
919 CR2RES_OBS_NODDING_EXTRACTA_PROCATG, RECIPE_STRING);
922 extracta, qc_main, ext_plist,
923 CR2RES_OBS_NODDING_EXTRACTA_IDP_PROCATG,
952 out_file = cpl_sprintf(
"%s_slitfuncA%s", RECIPE_STRING,
953 product_name_addon) ;
955 slitfunca, qc_main, ext_plist,
956 CR2RES_OBS_NODDING_SLITFUNCA_PROCATG, RECIPE_STRING) ;
959 out_file = cpl_sprintf(
"%s_modelA%s", RECIPE_STRING,
960 product_name_addon) ;
962 modela, qc_main, ext_plist,
963 CR2RES_OBS_NODDING_SLITMODELA_PROCATG, RECIPE_STRING) ;
966 out_file = cpl_sprintf(
"%s_trace_wave_A%s", RECIPE_STRING,
967 product_name_addon) ;
969 twa, qc_main, ext_plist, CR2RES_OBS_NODDING_TWA_PROCATG,
973 out_file = cpl_sprintf(
"%s_combinedB%s", RECIPE_STRING,
974 product_name_addon) ;
976 combinedb, qc_main, ext_plist,
977 CR2RES_OBS_NODDING_COMBINEDB_PROCATG, RECIPE_STRING) ;
980 out_file = cpl_sprintf(
"%s_extractedB%s", RECIPE_STRING,
981 product_name_addon) ;
983 extractb, qc_main, ext_plist,
984 CR2RES_OBS_NODDING_EXTRACTB_PROCATG, RECIPE_STRING);
987 extractb, qc_main, ext_plist,
988 CR2RES_OBS_NODDING_EXTRACTB_IDP_PROCATG,
993 out_file = cpl_sprintf(
"%s_slitfuncB%s", RECIPE_STRING,
994 product_name_addon) ;
996 slitfuncb, qc_main, ext_plist,
997 CR2RES_OBS_NODDING_SLITFUNCB_PROCATG, RECIPE_STRING) ;
1000 out_file = cpl_sprintf(
"%s_modelB%s", RECIPE_STRING,
1001 product_name_addon) ;
1003 modelb, qc_main, ext_plist,
1004 CR2RES_OBS_NODDING_SLITMODELB_PROCATG, RECIPE_STRING) ;
1007 out_file = cpl_sprintf(
"%s_trace_wave_B%s", RECIPE_STRING,
1008 product_name_addon) ;
1010 twb, qc_main, ext_plist, CR2RES_OBS_NODDING_TWB_PROCATG,
1014 out_file = cpl_sprintf(
"%s_extracted_combined%s", RECIPE_STRING,
1015 product_name_addon) ;
1017 extractc, qc_main, ext_plist,
1018 CR2RES_OBS_NODDING_EXTRACTC_PROCATG, RECIPE_STRING);
1021 extractc, qc_main, ext_plist,
1022 CR2RES_OBS_NODDING_EXTRACTC_IDP_PROCATG,
1029 qc_res_avg = cpl_sprintf(
"%s %s", CR2RES_HEADER_QC_THROUGHPUT,
"AVG");
1030 qc_res_rmsd = cpl_sprintf(
"%s %s", CR2RES_HEADER_QC_THROUGHPUT,
"RMS");
1032 cr2res_qc_calculate_mean_and_rmsd(qc_plists_ext, 1, qc_sizes_ext,
1033 CR2RES_HEADER_QC_THROUGHPUT, qc_main,
1034 qc_res_avg, qc_res_rmsd);
1036 cpl_free(qc_res_avg);
1037 cpl_free(qc_res_rmsd);
1039 out_file = cpl_sprintf(
"%s_throughput%s", RECIPE_STRING,
1040 product_name_addon) ;
1042 parlist, throughput, qc_main, ext_plist,
1043 CR2RES_OBS_NODDING_THROUGHPUT_PROCATG, RECIPE_STRING) ;
1046 cpl_free(product_name_addon) ;
1049 cpl_propertylist_delete(qc_main) ;
1050 for (det_nr=1 ; det_nr<=CR2RES_NB_DETECTORS ; det_nr++) {
1051 if (combineda[det_nr-1] != NULL)
1053 if (extracta[det_nr-1] != NULL)
1054 cpl_table_delete(extracta[det_nr-1]) ;
1055 if (slitfunca[det_nr-1] != NULL)
1056 cpl_table_delete(slitfunca[det_nr-1]) ;
1057 if (modela[det_nr-1] != NULL)
1059 if (twa[det_nr-1] != NULL)
1060 cpl_table_delete(twa[det_nr-1]) ;
1061 if (combinedb[det_nr-1] != NULL)
1063 if (extractb[det_nr-1] != NULL)
1064 cpl_table_delete(extractb[det_nr-1]) ;
1065 if (slitfuncb[det_nr-1] != NULL)
1066 cpl_table_delete(slitfuncb[det_nr-1]) ;
1067 if (modelb[det_nr-1] != NULL)
1069 if (twb[det_nr-1] != NULL)
1070 cpl_table_delete(twb[det_nr-1]) ;
1071 if (extractc[det_nr-1] != NULL)
1072 cpl_table_delete(extractc[det_nr-1]) ;
1073 if (throughput[det_nr-1] != NULL)
1074 cpl_table_delete(throughput[det_nr-1]) ;
1075 if (ext_plist[det_nr-1] != NULL)
1076 cpl_propertylist_delete(ext_plist[det_nr-1]) ;
1077 if (ext_plist_photom[det_nr-1] != NULL)
1078 cpl_propertylist_delete(ext_plist_photom[det_nr-1]) ;
1080 cpl_frameset_delete(raw_one_angle) ;
1081 cpl_msg_indent_less() ;
1084 cpl_frameset_delete(rawframes) ;
1085 if (raw_flat_frames != NULL) cpl_frameset_delete(raw_flat_frames) ;
1087 return (
int)cpl_error_get_code();
1128static int cr2res_obs_nodding_reduce(
1129 const cpl_frameset * rawframes,
1130 const cpl_frame * trace_wave_frame,
1131 const cpl_frame * detlin_frame,
1132 const cpl_frame * master_dark_frame,
1133 const cpl_frame * master_flat_frame,
1134 const cpl_frame * bpm_frame,
1135 const cpl_frame * blaze_frame,
1137 int subtract_nolight_rows,
1138 int subtract_interorder_column,
1141 int extract_oversample,
1142 int extract_swath_width,
1144 double extract_smooth_slit,
1145 double extract_smooth_spec,
1147 double extract_kappa,
1152 hdrl_image ** combineda,
1153 cpl_table ** extracta,
1154 cpl_table ** slitfunca,
1155 hdrl_image ** modela,
1157 hdrl_image ** combinedb,
1158 cpl_table ** extractb,
1159 cpl_table ** slitfuncb,
1160 hdrl_image ** modelb,
1162 cpl_table ** extractc,
1163 cpl_propertylist ** ext_plist)
1165 hdrl_imagelist * in ;
1166 hdrl_imagelist * in_calib ;
1167 hdrl_imagelist * in_a ;
1168 hdrl_imagelist * in_b ;
1169 hdrl_imagelist * diff_a ;
1170 hdrl_imagelist * diff_b ;
1171 hdrl_image * collapsed_a ;
1172 hdrl_image * collapsed_b ;
1173 cpl_image * contrib_a ;
1174 cpl_image * contrib_b ;
1175 cr2res_nodding_pos * nod_positions ;
1177 cpl_vector * ndits=NULL ;
1178 cpl_table * trace_wave ;
1180 cpl_table * trace_wave_a ;
1181 cpl_table * trace_wave_b ;
1182 cpl_table * blaze_table ;
1183 cpl_array * slit_frac_a ;
1184 cpl_array * slit_frac_b ;
1185 cpl_table * extracted_a ;
1186 cpl_table * extracted_b ;
1187 cpl_table * extracted_combined ;
1188 cpl_table * slit_func_a ;
1189 cpl_table * slit_func_b ;
1190 hdrl_image * model_master_a ;
1191 hdrl_image * model_master_b ;
1192 cpl_propertylist * plist ;
1193 cpl_size nframes, i ;
1195 const char * first_fname ;
1196 double slit_length, extr_width_frac, slit_frac_a_bot,
1197 slit_frac_a_mid, slit_frac_a_top, slit_frac_b_bot,
1198 slit_frac_b_mid, slit_frac_b_top, nod_throw,
1199 gain, error_factor ;
1200 double qc_signal_a, qc_signal_b, qc_fwhm_a,
1201 qc_fwhm_b, qc_standard_flux_a,
1202 qc_standard_flux_b, qc_fwhm_med, blaze_norm ;
1203 cpl_array * fwhm_a_array ;
1204 cpl_array * fwhm_b_array ;
1205 char * cur_setting ;
1206 int * order_idx_values ;
1208 double * qc_der_snrs ;
1209 int nb_order_idx_values,
1210 order_zp, order_idx, order_idxp ;
1213 if (combineda == NULL || combinedb == NULL ||
1214 twa == NULL || twb == NULL ||
1215 slitfunca == NULL || slitfuncb == NULL ||
1216 modela == NULL || modelb == NULL ||
1217 extracta == NULL || extractb == NULL || extractc == NULL ||
1218 ext_plist == NULL || rawframes == NULL || trace_wave_frame == NULL)
1222 if (reduce_det == 1) gain = CR2RES_GAIN_CHIP1 ;
1223 else if (reduce_det == 2) gain = CR2RES_GAIN_CHIP2 ;
1224 else if (reduce_det == 3) gain = CR2RES_GAIN_CHIP3 ;
1226 cpl_msg_error(__func__,
"Failed to get the Gain value") ;
1231 if (cr2res_obs_nodding_check_inputs_validity(rawframes) != 1) {
1232 cpl_msg_error(__func__,
"Invalid Inputs") ;
1237 nframes = cpl_frameset_get_size(rawframes) ;
1238 first_fname = cpl_frame_get_filename(
1239 cpl_frameset_get_position_const(rawframes, 0)) ;
1242 if ((plist = cpl_propertylist_load(cpl_frame_get_filename(trace_wave_frame),
1244 cpl_msg_error(__func__,
"Cannot read the ORDER_ZP from the input TW") ;
1247 order_zp = cr2res_pfits_get_order_zp(plist) ;
1248 cpl_propertylist_delete(plist) ;
1249 if (cpl_error_get_code()) {
1250 cpl_msg_error(__func__,
"Missing ORDER_ZP in the header - Skip") ;
1257 cpl_msg_info(__func__,
"Get the Nodding positions") ;
1258 cpl_msg_indent_more() ;
1260 for (i=0 ; i<nframes ; i++) {
1261 cpl_msg_info(__func__,
"Frame %s - Nodding %c",
1262 cpl_frame_get_filename(
1263 cpl_frameset_get_position_const(rawframes, i)),
1266 cpl_msg_indent_less() ;
1272 if (cpl_msg_get_level() == CPL_MSG_DEBUG && dits != NULL)
1273 cpl_vector_dump(dits, stdout) ;
1277 if (cpl_msg_get_level() == CPL_MSG_DEBUG && ndits != NULL)
1278 cpl_vector_dump(ndits, stdout) ;
1281 cpl_msg_info(__func__,
"Load the image list") ;
1283 reduce_det)) == NULL) {
1284 cpl_msg_error(__func__,
"Cannot load images") ;
1285 cpl_free(nod_positions) ;
1286 if (dits != NULL) cpl_vector_delete(dits) ;
1290 cpl_msg_error(__func__,
"Inconsistent number of loaded images") ;
1291 cpl_free(nod_positions) ;
1292 if (dits != NULL) cpl_vector_delete(dits) ;
1298 cpl_msg_info(__func__,
"Apply the Calibrations") ;
1299 cpl_msg_indent_more() ;
1301 subtract_nolight_rows, subtract_interorder_column, cosmics,
1302 master_flat_frame, master_dark_frame, bpm_frame, detlin_frame, dits,
1304 cpl_msg_error(__func__,
"Failed to apply the calibrations") ;
1305 cpl_msg_indent_less() ;
1306 cpl_free(nod_positions) ;
1307 if (dits != NULL) cpl_vector_delete(dits) ;
1308 if (ndits != NULL) cpl_vector_delete(ndits) ;
1313 if (dits != NULL) cpl_vector_delete(dits) ;
1314 cpl_msg_indent_less() ;
1317 cpl_msg_info(__func__,
"Split the images in A and B lists") ;
1318 cpl_msg_indent_more() ;
1321 cpl_msg_error(__func__,
"Failed to split the nodding positions") ;
1322 cpl_msg_indent_less() ;
1323 cpl_free(nod_positions) ;
1325 cpl_vector_delete(ndits) ;
1330 if (error_method == CR2RES_EXTRACT_ERROR_HORNE) {
1331 error_factor = -1.0;
1334 error_factor = gain * cpl_vector_get(ndits, 0) *
1338 for (i=0; i<cpl_vector_get_size(ndits); i++){
1339 if (cpl_vector_get(ndits,i) != cpl_vector_get(ndits, 0))
1340 cpl_msg_warning(__func__,
"Raw frames have different NDIT! "
1341 "Error spectrum will likely be scaled incorrectly.");
1343 cpl_vector_delete(ndits) ;
1344 cpl_free(nod_positions) ;
1346 cpl_msg_indent_less() ;
1351 cpl_msg_error(__func__,
"Inconsistent A / B number of images") ;
1358 cpl_msg_info(__func__,
"Compute difference image lists A-B and B-A") ;
1367 cpl_msg_info(__func__,
"Collapse image lists A-B and B-A") ;
1368 cpl_msg_indent_more() ;
1371 cpl_msg_error(__func__,
"Failed to Collapse A-B") ;
1374 cpl_msg_indent_less() ;
1377 cpl_image_delete(contrib_a) ;
1381 cpl_msg_error(__func__,
"Failed to Collapse B-A") ;
1384 cpl_msg_indent_less() ;
1387 cpl_image_delete(contrib_b) ;
1389 cpl_msg_indent_less() ;
1392 cpl_msg_info(__func__,
"Load the TRACE WAVE") ;
1394 trace_wave_frame), reduce_det)) == NULL) {
1395 cpl_msg_error(__func__,
"Failed to Load the traces file") ;
1402 cpl_msg_warning(__func__,
"TRACE ADJUST NOT YET IMPLEMENTED") ;
1417 cpl_msg_info(__func__,
"Compute the slit fractions for A and B positions");
1418 cpl_msg_indent_more() ;
1427 if ((plist = cpl_propertylist_load(first_fname, 0)) == NULL) {
1428 cpl_msg_error(__func__,
"Cannot read the NODTHROW in the input files") ;
1429 cpl_msg_indent_less() ;
1432 cpl_table_delete(trace_wave) ;
1436 cpl_propertylist_delete(plist) ;
1437 if (nod_throw < slit_length / 2.0) {
1438 extr_width_frac = nod_throw/slit_length ;
1439 if (nodding_invert == 1) {
1440 slit_frac_a_bot = 0.5 ;
1441 slit_frac_a_mid = slit_frac_a_bot + extr_width_frac/2.0 ;
1442 slit_frac_a_top = slit_frac_a_bot + extr_width_frac ;
1443 slit_frac_b_top = 0.5 ;
1444 slit_frac_b_mid = slit_frac_b_top - extr_width_frac/2.0 ;
1445 slit_frac_b_bot = slit_frac_b_top - extr_width_frac ;
1447 slit_frac_a_top = 0.5 ;
1448 slit_frac_a_mid = slit_frac_a_top - extr_width_frac/2.0 ;
1449 slit_frac_a_bot = slit_frac_a_top - extr_width_frac ;
1450 slit_frac_b_bot = 0.5 ;
1451 slit_frac_b_mid = slit_frac_b_bot + extr_width_frac/2.0 ;
1452 slit_frac_b_top = slit_frac_b_bot + extr_width_frac ;
1454 }
else if (nod_throw <= slit_length) {
1455 extr_width_frac = (slit_length - nod_throw)/slit_length ;
1456 if (nodding_invert == 1) {
1457 slit_frac_a_top = 1.0 ;
1458 slit_frac_a_mid = slit_frac_a_top - extr_width_frac/2.0 ;
1459 slit_frac_a_bot = slit_frac_a_top - extr_width_frac ;
1460 slit_frac_b_bot = 0.0 ;
1461 slit_frac_b_mid = slit_frac_b_bot + extr_width_frac/2.0 ;
1462 slit_frac_b_top = slit_frac_b_bot + extr_width_frac ;
1464 slit_frac_a_bot = 0.0 ;
1465 slit_frac_a_mid = slit_frac_a_bot + extr_width_frac/2.0 ;
1466 slit_frac_a_top = slit_frac_a_bot + extr_width_frac ;
1467 slit_frac_b_top = 1.0 ;
1468 slit_frac_b_mid = slit_frac_b_top - extr_width_frac/2.0 ;
1469 slit_frac_b_bot = slit_frac_b_top - extr_width_frac ;
1472 cpl_msg_error(__func__,
"NODTHROW > slit length (%g>%g)- abort",
1473 nod_throw, slit_length) ;
1474 cpl_msg_indent_less() ;
1477 cpl_table_delete(trace_wave) ;
1480 cpl_msg_info(__func__,
"Nod Throw : %g arcsecs", nod_throw) ;
1481 cpl_msg_info(__func__,
"Nodding A extraction: Slit fraction %g - %g",
1482 slit_frac_a_bot, slit_frac_a_top) ;
1483 cpl_msg_info(__func__,
"Nodding B extraction: Slit fraction %g - %g",
1484 slit_frac_b_bot, slit_frac_b_top) ;
1486 slit_frac_a = cpl_array_new(3, CPL_TYPE_DOUBLE) ;
1487 cpl_array_set(slit_frac_a, 0, slit_frac_a_bot) ;
1488 cpl_array_set(slit_frac_a, 1, slit_frac_a_mid) ;
1489 cpl_array_set(slit_frac_a, 2, slit_frac_a_top) ;
1491 slit_frac_b = cpl_array_new(3, CPL_TYPE_DOUBLE) ;
1492 cpl_array_set(slit_frac_b, 0, slit_frac_b_bot) ;
1493 cpl_array_set(slit_frac_b, 1, slit_frac_b_mid) ;
1494 cpl_array_set(slit_frac_b, 2, slit_frac_b_top) ;
1495 cpl_msg_indent_less() ;
1498 cpl_msg_info(__func__,
"Recompute the traces for the A slit fraction") ;
1500 slit_frac_a)) == NULL) {
1501 cpl_msg_error(__func__,
1502 "Failed to compute the traces for extraction of A") ;
1505 cpl_table_delete(trace_wave) ;
1506 cpl_array_delete(slit_frac_a) ;
1507 cpl_array_delete(slit_frac_b) ;
1510 cpl_array_delete(slit_frac_a) ;
1512 cpl_msg_info(__func__,
"Recompute the traces for the B slit fraction") ;
1514 slit_frac_b)) == NULL) {
1515 cpl_msg_error(__func__,
1516 "Failed to compute the traces for extraction of B") ;
1519 cpl_table_delete(trace_wave) ;
1520 cpl_table_delete(trace_wave_a) ;
1521 cpl_array_delete(slit_frac_b) ;
1524 cpl_array_delete(slit_frac_b) ;
1527 blaze_table = NULL ;
1529 if (blaze_frame != NULL) {
1530 cpl_msg_info(__func__,
"Load the BLAZE") ;
1532 blaze_frame), reduce_det)) == NULL) {
1533 cpl_msg_error(__func__,
"Failed to Load the Blaze file") ;
1536 cpl_table_delete(trace_wave) ;
1537 cpl_table_delete(trace_wave_a) ;
1538 cpl_table_delete(trace_wave_b) ;
1541 cpl_propertylist * blaze_plist ;
1542 blaze_plist = cpl_propertylist_load_regexp(cpl_frame_get_filename(
1543 blaze_frame),0,CR2RES_HEADER_QC_BLAZE_NORM,0);
1544 if(cpl_propertylist_get_size(blaze_plist)>0){
1545 blaze_norm = cpl_propertylist_get_double(blaze_plist, CR2RES_HEADER_QC_BLAZE_NORM);
1549 cpl_msg_warning(__func__,
"QC BLAZE NORM value not found, reverting to per trace normalization") ;
1551 if(blaze_plist!=NULL){
1552 cpl_propertylist_delete(blaze_plist);
1557 cpl_msg_info(__func__,
"A position Spectra Extraction") ;
1558 cpl_msg_indent_more() ;
1560 -1, CR2RES_EXTR_OPT_CURV, extract_height, extract_swath_width,
1561 extract_oversample, extract_smooth_slit, extract_smooth_spec,
1562 extract_niter, extract_kappa, error_factor,
1563 disp_det==reduce_det, disp_order_idx, disp_trace,
1564 &extracted_a, &slit_func_a, &model_master_a) == -1) {
1565 cpl_msg_error(__func__,
"Failed to extract A");
1566 cpl_msg_indent_less() ;
1569 cpl_table_delete(trace_wave_a) ;
1570 cpl_table_delete(trace_wave_b) ;
1571 cpl_table_delete(trace_wave) ;
1574 cpl_msg_indent_less() ;
1576 cpl_msg_info(__func__,
"B position Spectra Extraction") ;
1577 cpl_msg_indent_more() ;
1579 -1, CR2RES_EXTR_OPT_CURV, extract_height, extract_swath_width,
1580 extract_oversample, extract_smooth_slit, extract_smooth_spec,
1581 extract_niter, extract_kappa, error_factor,
1582 disp_det==reduce_det, disp_order_idx, disp_trace,
1583 &extracted_b, &slit_func_b, &model_master_b) == -1) {
1584 cpl_msg_error(__func__,
"Failed to extract B");
1585 cpl_msg_indent_less() ;
1586 cpl_table_delete(extracted_a) ;
1587 cpl_table_delete(slit_func_a) ;
1591 cpl_table_delete(trace_wave_a) ;
1592 cpl_table_delete(trace_wave_b) ;
1593 cpl_table_delete(trace_wave) ;
1596 cpl_msg_indent_less() ;
1598 if (blaze_table != NULL) cpl_table_delete(blaze_table) ;
1601 cpl_msg_info(__func__,
"A and B spectra combination") ;
1602 cpl_msg_indent_more() ;
1604 cpl_msg_indent_less() ;
1607 plist = cpl_propertylist_load(first_fname, 0) ;
1610 cpl_propertylist_delete(plist) ;
1613 plist = cpl_propertylist_load(first_fname,
1617 cpl_msg_info(__func__,
"QC parameters computation") ;
1620 cpl_propertylist_append_double(plist, CR2RES_HEADER_QC_SIGNAL,
1621 (qc_signal_a+qc_signal_b)/2.0) ;
1624 qc_standard_flux_a =
1626 qc_standard_flux_b =
1628 cpl_propertylist_append_double(plist, CR2RES_HEADER_QC_STANDARD_FLUX,
1629 (qc_standard_flux_a+qc_standard_flux_b)/2.0) ;
1630 cpl_free(cur_setting) ;
1633 qc_snrs =
cr2res_qc_snr(trace_wave_a, extracted_a, &order_idx_values,
1634 &nb_order_idx_values) ;
1636 &nb_order_idx_values) ;
1637 for (i=0 ; i<nb_order_idx_values ; i++) {
1638 order_idx = order_idx_values[i] ;
1640 key_name = cpl_sprintf(CR2RES_HEADER_QC_SNR, order_idxp) ;
1641 cpl_propertylist_append_double(plist, key_name, qc_snrs[i]) ;
1642 cpl_free(key_name) ;
1643 key_name = cpl_sprintf(CR2RES_HEADER_QC_DER_SNR, order_idxp) ;
1644 cpl_propertylist_append_double(plist, key_name, qc_der_snrs[i]) ;
1645 cpl_free(key_name) ;
1647 cpl_free(order_idx_values) ;
1652 &nb_order_idx_values);
1655 fwhm_a_array = cpl_array_new(nb_order_idx_values, CPL_TYPE_DOUBLE);
1656 fwhm_b_array = cpl_array_new(nb_order_idx_values, CPL_TYPE_DOUBLE);
1657 for (i=0 ; i<nb_order_idx_values ; i++) {
1658 order_idx = order_idx_values[i] ;
1661 extract_oversample);
1663 extract_oversample);
1665 key_name = cpl_sprintf(CR2RES_HEADER_QC_SLITFWHM_ORDER, order_idxp) ;
1666 cpl_propertylist_append_double(plist, key_name,
1667 (qc_fwhm_a+qc_fwhm_b)/2.0) ;
1668 cpl_free(key_name) ;
1669 cpl_array_set(fwhm_a_array, i, qc_fwhm_a) ;
1670 cpl_array_set(fwhm_b_array, i, qc_fwhm_b) ;
1672 qc_fwhm_a = cpl_array_get_median(fwhm_a_array);
1673 qc_fwhm_b = cpl_array_get_median(fwhm_b_array);
1674 qc_fwhm_med = (qc_fwhm_a+qc_fwhm_b)/2.0 ;
1675 cpl_propertylist_append_double(plist, CR2RES_HEADER_QC_SLITFWHM_MED,
1677 if (qc_fwhm_med < 3.5) {
1678 cpl_msg_warning(__func__,
"Median FWHM of the PSF along the slit "
1679 "is %gpix, i.e. below the slit width. This means the slit "
1680 "is likely not evenly filled with light "
1681 "in the spectral direction. This can result in a "
1682 "wavelength offset between A and B nodding positions, and with "
1683 "respect to calibrations."
1686 cpl_array_delete(fwhm_a_array) ;
1687 cpl_array_delete(fwhm_b_array) ;
1692 for (i = 0; i < nb_order_idx_values; i++) {
1694 order_idx = order_idx_values[i] ;
1698 key_name = cpl_sprintf(CR2RES_HEADER_QC_REAL_ORDER, order_idxp) ;
1699 cpl_propertylist_append_int(plist, key_name, order_real) ;
1700 cpl_free(key_name) ;
1703 cpl_table_delete(trace_wave) ;
1704 cpl_free(order_idx_values) ;
1707 *combineda = collapsed_a ;
1708 *extracta = extracted_a ;
1709 *slitfunca = slit_func_a ;
1710 *modela = model_master_a ;
1711 *twa = trace_wave_a ;
1713 *combinedb = collapsed_b ;
1714 *extractb = extracted_b ;
1715 *slitfuncb = slit_func_b ;
1716 *modelb = model_master_b ;
1717 *twb = trace_wave_b ;
1719 *extractc = extracted_combined ;
1720 *ext_plist = plist ;
1732static int cr2res_obs_nodding_check_inputs_validity(
1733 const cpl_frameset * rawframes)
1735 cpl_propertylist * plist ;
1736 cr2res_nodding_pos * nod_positions ;
1737 cpl_size nframes, i ;
1742 if (rawframes == NULL)
return -1 ;
1745 nframes = cpl_frameset_get_size(rawframes) ;
1747 cpl_msg_error(__func__,
"Require an even number of raw frames") ;
1754 if (nod_positions == NULL)
return -1 ;
1755 for (i=0 ; i<nframes ; i++) {
1756 if (nod_positions[i] == CR2RES_NODDING_A) nb_a++ ;
1757 if (nod_positions[i] == CR2RES_NODDING_B) nb_b++ ;
1759 cpl_free(nod_positions) ;
1761 if (nb_a == 0 || nb_b == 0 || nb_a != nb_b) {
1762 cpl_msg_error(__func__,
"Require as many A and B positions") ;
1767 if ((plist = cpl_propertylist_load(cpl_frame_get_filename(
1768 cpl_frameset_get_position_const(rawframes, 0)),
1773 cpl_propertylist_delete(plist) ;
1774 for (i = 1; i < nframes; i++) {
1775 double nodthrow_cur;
1776 if ((plist = cpl_propertylist_load(cpl_frame_get_filename(
1777 cpl_frameset_get_position_const(rawframes, i)),
1782 cpl_propertylist_delete(plist) ;
1784 if (fabs(nodthrow_cur-nodthrow) > 1e-3) {
1785 cpl_msg_error(__func__,
1786 "Require constant NOD THROW in the raw frames") ;
1810static cpl_frameset * cr2res_obs_nodding_find_RAW(
1811 const cpl_frameset * in,
1814 cpl_frameset * out ;
1817 if (in == NULL)
return NULL ;
1824 if (type != NULL) *type = 1 ;
1831 if (type != NULL) *type = 2 ;
1836 CR2RES_OBS_ASTROMETRY_JITTER_RAW) ;
1839 if (type != NULL) *type = 3 ;
1844 if (type != NULL) *type = 0 ;
1857static int cr2res_obs_nodding_astrometry_compare(
1858 const cpl_frame * frame1,
1859 const cpl_frame * frame2)
1862 cpl_propertylist * plist1 ;
1863 cpl_propertylist * plist2 ;
1864 double dval1, dval2 ;
1867 if (frame1==NULL || frame2==NULL)
return -1 ;
1870 if ((plist1=cpl_propertylist_load(cpl_frame_get_filename(frame1),0))==NULL){
1871 cpl_msg_error(__func__,
"getting header from reference frame");
1874 if ((plist2=cpl_propertylist_load(cpl_frame_get_filename(frame2),0))==NULL){
1875 cpl_msg_error(__func__,
"getting header from reference frame");
1876 cpl_propertylist_delete(plist1) ;
1881 if (cpl_error_get_code()) {
1882 cpl_propertylist_delete(plist1) ;
1883 cpl_propertylist_delete(plist2) ;
1892 if (cpl_error_get_code()) {
1893 cpl_msg_error(__func__,
"Cannot get the angle");
1894 cpl_propertylist_delete(plist1) ;
1895 cpl_propertylist_delete(plist2) ;
1898 if (fabs(dval1-dval2) > 1e-3) comparison = 0 ;
1900 cpl_propertylist_delete(plist1) ;
1901 cpl_propertylist_delete(plist2) ;
hdrl_imagelist * cr2res_calib_imagelist(const hdrl_imagelist *in, int chip, int clean_bad, int subtract_nolight_rows, int subtract_interorder_column, int cosmics_corr, const cpl_frame *flat, const cpl_frame *dark, const cpl_frame *bpm, const cpl_frame *detlin, const cpl_vector *dits, const cpl_vector *ndits)
The images calibration routine for a given chip on a list.
cpl_error_code cr2res_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
int cr2res_idp_save(const char *filename, cpl_frameset *allframes, cpl_frameset *rawframes, const cpl_parameterlist *parlist, cpl_table **tables, cpl_propertylist *main_qc_plist, cpl_propertylist **ext_plist, const char *procatg, const char *recipe)
Save an IDP file.
cpl_table * cr2res_io_load_EXTRACT_1D(const char *filename, int detector)
Load a table from a EXTRACT_1D.
const cpl_frame * cr2res_io_find_BPM(const cpl_frameset *in)
Get the first CR2RES_BPM_DRSTYPE frame from a frameset.
int cr2res_io_save_SLIT_MODEL(const char *filename, cpl_frameset *allframes, cpl_frameset *inframes, const cpl_parameterlist *parlist, hdrl_image **data, const cpl_propertylist *qc_list, cpl_propertylist **ext_plist, const char *procatg, const char *recipe)
Save a SLIT_MODEL.
const cpl_frame * cr2res_io_find_TRACE_WAVE(const cpl_frameset *in)
Get the first CR2RES_TW_DRSTYPE frame from a frameset.
int cr2res_io_convert_order_idx_to_idxp(int order_idx)
Convert the order_idx to the order_idxp.
int cr2res_io_save_TRACE_WAVE(const char *filename, cpl_frameset *allframes, cpl_frameset *inframes, const cpl_parameterlist *parlist, cpl_table **tables, const cpl_propertylist *qc_list, cpl_propertylist **ext_plist, const char *procatg, const char *recipe)
Save a TRACE_WAVE.
cpl_vector * cr2res_io_read_dits(const cpl_frameset *in)
Get the DITS from a frame set.
int cr2res_io_save_EXTRACT_1D(const char *filename, cpl_frameset *allframes, cpl_frameset *inframes, const cpl_parameterlist *parlist, cpl_table **tables, const cpl_propertylist *qc_list, cpl_propertylist **ext_plist, const char *procatg, const char *recipe)
Save a 1D extracted spectrum.
hdrl_imagelist * cr2res_io_load_image_list_from_set(const cpl_frameset *in, int detector)
Load an hdrl image list from an images frameset.
cpl_table * cr2res_io_get_eop_table()
Get the eop_table.
int cr2res_io_save_THROUGHPUT(const char *filename, cpl_frameset *allframes, cpl_frameset *inframes, const cpl_parameterlist *parlist, cpl_table **tables, const cpl_propertylist *qc_list, cpl_propertylist **ext_plist, const char *procatg, const char *recipe)
Save a THROUGHPUT table.
int cr2res_io_get_ext_idx(const char *filename, int detector, int data)
Get the wished extension number for a detector.
int cr2res_io_save_SLIT_FUNC(const char *filename, cpl_frameset *allframes, cpl_frameset *inframes, const cpl_parameterlist *parlist, cpl_table **slit_func, const cpl_propertylist *qc_list, cpl_propertylist **ext_plist, const char *procatg, const char *recipe)
Save a SLIT_FUNC.
int cr2res_io_save_COMBINED(const char *filename, cpl_frameset *allframes, cpl_frameset *inframes, const cpl_parameterlist *parlist, hdrl_image **data, const cpl_propertylist *qc_list, cpl_propertylist **ext_plist, const char *procatg, const char *recipe)
Save a COMBINED.
cpl_table * cr2res_io_load_TRACE_WAVE(const char *filename, int detector)
Load a table from a TRACE_WAVE.
cpl_vector * cr2res_io_read_ndits(const cpl_frameset *in)
Get the NDITs from a frame set.
const char * cr2res_pfits_get_wlen_id(const cpl_propertylist *plist)
find out the Setting
double cr2res_pfits_get_dit(const cpl_propertylist *plist)
find out the DIT value
double cr2res_pfits_get_dec(const cpl_propertylist *plist)
find out the DEC
double cr2res_pfits_get_drot_posang(const cpl_propertylist *plist)
find out the DROT POSANG value
double cr2res_pfits_get_nodthrow(const cpl_propertylist *plist)
find out the NODTHROW value
double cr2res_pfits_get_ra(const cpl_propertylist *plist)
find out the RA
int cr2res_photom_engine(const cpl_table *extr, const char *std_star_file, const char *setting, double ra, double dec, double gain, double exptime, int display, int display_order, int display_trace, cpl_table **throughput, cpl_propertylist **ext_plist)
Compute the conversion/throughput/sensitivity high level.
int cr2res_qc_numsat(const cpl_frameset *frameset)
Calculate the number of saturated pixels.
double * cr2res_qc_der_snr(const cpl_table *tw, const cpl_table *extracted, int **out_order_idx_values, int *out_nb_order_idx_values)
Computes the DER SNR of several spectra.
double cr2res_qc_obs_nodding_signal(const cpl_table *extracted)
Computes the integrated flux over part of the spectrum.
double cr2res_qc_obs_nodding_standard_flux(const cpl_table *extracted, char *setting)
Computes the standard flux over part of the spectrum.
double * cr2res_qc_snr(const cpl_table *tw, const cpl_table *extracted, int **out_order_idx_values, int *out_nb_order_idx_values)
Computes the SNR of several spectra.
double cr2res_qc_obs_slit_psf(const cpl_table *slitfu, int order_idxp, int oversample)
Computes the FWHM of the PSF along the slit for a given order.
cpl_table * cr2res_trace_new_slit_fraction(const cpl_table *traces, const cpl_array *new_slit_fraction)
Recompute the traces at a newly specified slit fraction.
int * cr2res_trace_get_order_idx_values(const cpl_table *trace, int *nb_order_idx_values)
Count and return the different order_idx values from a TW table.
int cr2res_format_setting(char *setting_id)
Format the setting.
int cr2res_order_idx_to_real(int order_idx, int order_zp)
Convert the order_idx into order_real.
char cr2res_nodding_position_char(cr2res_nodding_pos pos)
Get the nodding position character for display.
int cr2res_combine_nodding_split(const hdrl_imagelist *in, const cr2res_nodding_pos *positions, hdrl_imagelist **pos_a, hdrl_imagelist **pos_b)
Split A/B positions in 2 image lists.
double cr2res_utils_get_center_mjd(const cpl_frameset *frameset)
Calculate the middle of the exposures in the frameset.
cr2res_nodding_pos * cr2res_nodding_read_positions(const cpl_frameset *in)
Get the nodding positions from a frame set.
cpl_table * cr2res_combine_extracted(const cpl_table *extracta, const cpl_table *extractb)
Combine two extracted spectra by resampling one to the other's WL.
cpl_frameset * cr2res_extract_frameset(const cpl_frameset *in, const char *tag)
Extract the frames with the given tag from a frameset.
const char * cr2res_get_license(void)
Get the pipeline copyright and license.
cpl_error_code hdrl_barycorr_compute(double ra, double dec, const cpl_table *eop_table, double mjdobs, double time_to_mid_exposure, double longitude, double latitude, double elevation, double pressure, double temperature, double humidity, double wavelength, double *barycorr)
Derives the barycentric correction using the erfa function eraApco13(). The latter For a terrestrial ...
void hdrl_image_delete(hdrl_image *himg)
delete hdrl_image
cpl_error_code hdrl_imagelist_collapse_mean(const hdrl_imagelist *himlist, hdrl_image **out, cpl_image **contrib)
Mean collapsing of image list.
void hdrl_imagelist_delete(hdrl_imagelist *himlist)
Free all memory used by a hdrl_imagelist object including the images.
cpl_size hdrl_imagelist_get_size(const hdrl_imagelist *himlist)
Get the number of images in the imagelist.
cpl_error_code hdrl_imagelist_sub_imagelist(hdrl_imagelist *himlist1, const hdrl_imagelist *himlist2)
Subtract two image lists, the first one is replaced by the result.
hdrl_imagelist * hdrl_imagelist_duplicate(const hdrl_imagelist *himlist)
Duplicate an image list.