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,
80 int extract_oversample,
81 int extract_swath_width,
83 double extract_smooth_slit,
84 double extract_smooth_spec,
91 hdrl_image ** combineda,
92 cpl_table ** extracta,
93 cpl_table ** slitfunca,
96 hdrl_image ** combinedb,
97 cpl_table ** extractb,
98 cpl_table ** slitfuncb,
101 cpl_table ** extractc,
102 cpl_propertylist ** ext_plist) ;
104static int cr2res_obs_nodding_create(cpl_plugin *);
105static int cr2res_obs_nodding_exec(cpl_plugin *);
106static int cr2res_obs_nodding_destroy(cpl_plugin *);
107static int cr2res_obs_nodding(cpl_frameset *,
const cpl_parameterlist *);
113static char cr2res_obs_nodding_description[] =
"\
114Nodding Observation \n\
115 This recipe handles nodding observations. It expects an even number \n\
116 of rawframes in input, and as many A positions as B positions \n\
117 If the input are standard stars, it computes a post processing step \n\
118 to determine the throughput. \n\
119 If the input are spectro astrometric data, it will apply the nodding \n\
120 on each of the sub-groups \n\
123 raw.fits " CR2RES_CAL_NODDING_OTHER_RAW
" [2 to 2n] \n\
124 or " CR2RES_CAL_NODDING_JITTER_RAW
" [2 to 2n] \n\
125 or " CR2RES_OBS_NODDING_OTHER_RAW
" [2 to 2n] \n\
126 or " CR2RES_OBS_NODDING_JITTER_RAW
" [2 to 2n] \n\
127 or " CR2RES_OBS_ASTROMETRY_OTHER_RAW
" [2 to 2n] \n\
128 or " CR2RES_OBS_ASTROMETRY_JITTER_RAW
" [2 to 2n] \n\
129 trace.fits " CR2RES_CAL_FLAT_TW_PROCATG
" [1] \n\
130 or " CR2RES_CAL_FLAT_TW_MERGED_PROCATG
" \n\
131 or " CR2RES_UTIL_TRACE_TW_PROCATG
" \n\
132 or " CR2RES_UTIL_WAVE_TW_PROCATG
" \n\
133 or " CR2RES_CAL_WAVE_TW_PROCATG
" \n\
134 or " CR2RES_UTIL_SLIT_CURV_TW_PROCATG
" \n\
135 detlin.fits " CR2RES_CAL_DETLIN_COEFFS_PROCATG
" [0 to 1] \n\
136 bpm.fits " CR2RES_CAL_DARK_BPM_PROCATG
" [0 to 1] \n\
137 or " CR2RES_CAL_FLAT_BPM_PROCATG
" \n\
138 or " CR2RES_CAL_DETLIN_BPM_PROCATG
" \n\
139 or " CR2RES_UTIL_BPM_MERGE_PROCATG
" \n\
140 or " CR2RES_UTIL_BPM_SPLIT_PROCATG
" \n\
141 master_dark.fits " CR2RES_CAL_DARK_MASTER_PROCATG
" [0 to 1] \n\
142 master_flat.fits " CR2RES_CAL_FLAT_MASTER_PROCATG
" [0 to 1] \n\
143 photo_flux.fits " CR2RES_PHOTO_FLUX_PROCATG
" [0 to 1] \n\
144 blaze.fits " CR2RES_CAL_FLAT_EXTRACT_1D_PROCATG
" [0 to 1] \n\
147 cr2res_obs_nodding_extractedA.fits "
148 CR2RES_OBS_NODDING_EXTRACTA_PROCATG
"\n\
149 cr2res_obs_nodding_extractedB.fits "
150 CR2RES_OBS_NODDING_EXTRACTB_PROCATG
"\n\
151 cr2res_obs_nodding_combinedA.fits "
152 CR2RES_OBS_NODDING_COMBINEDA_PROCATG
"\n\
153 cr2res_obs_nodding_combinedB.fits "
154 CR2RES_OBS_NODDING_COMBINEDB_PROCATG
"\n\
155 cr2res_obs_nodding_trace_wave_A.fits "
156 CR2RES_OBS_NODDING_TWA_PROCATG
"\n\
157 cr2res_obs_nodding_trace_wave_B.fits "
158 CR2RES_OBS_NODDING_TWB_PROCATG
"\n\
159 cr2res_obs_nodding_modelA.fits "
160 CR2RES_OBS_NODDING_SLITMODELA_PROCATG
"\n\
161 cr2res_obs_nodding_modelB.fits "
162 CR2RES_OBS_NODDING_SLITMODELB_PROCATG
"\n\
163 cr2res_obs_nodding_slitfuncA.fits "
164 CR2RES_OBS_NODDING_SLITFUNCA_PROCATG
"\n\
165 cr2res_obs_nodding_slitfuncB.fits "
166 CR2RES_OBS_NODDING_SLITFUNCB_PROCATG
"\n\
167 cr2res_obs_nodding_throughput.fits "
168 CR2RES_OBS_NODDING_THROUGHPUT_PROCATG
"\n\
171 loop on detectors d: \n\
172 call cr2res_obs_nodding_reduce() \n\
173 -> combined[a|b](d) \n\
174 -> extract[a|b|c](d) \n\
175 -> slitfunc[a|b](d) \n\
178 Save combineda and combinedb \n\
179 Save extracta, extractb, extractc \n\
180 Save slitfunca and slitfuncb \n\
181 Save modela and modelb \n\
184 cr2res_obs_nodding_reduce() \n\
185 Load the input raw frames in an image list \n\
186 Apply the calibrations to the image list \n\
187 Split the list in listA and listB image lists \n\
188 Compute diffA=listA-listB and diffB=listB-listA \n\
189 Collapse diffA and diffB \n\
191 Load the input trace wave \n\
192 Compute the slit fractions for A and B by using the nodthrow \n\
193 and the assumption that A and B are at equal distances \n\
194 from the slit center. \n\
195 Compute 2 new trace_wave files with these 2 computed slit fractions\n\
196 Extract the spectra for A and for B \n\
197 -> extracted[a|b] \n\
198 -> slit_func[a|b] \n\
199 -> model_master[a|b] \n\
200 -> trace_wave[a|b] \n\
201 Compute QC parameters \n\
202 If STD star, compute the throughput \n\
205 Library functions used \n\
206 cr2res_io_find_TRACE_WAVE() \n\
207 cr2res_io_find_BPM() \n\
208 cr2res_obs_nodding_reduce() \n\
209 cr2res_nodding_read_positions() \n\
210 cr2res_io_read_dits() \n\
211 cr2res_io_load_image_list_from_set() \n\
212 cr2res_calib_imagelist() \n\
213 cr2res_combine_nodding_split() \n\
214 cr2res_io_load_TRACE_WAVE() \n\
215 cr2res_pfits_get_nodthrow() \n\
216 cr2res_trace_new_slit_fraction() \n\
217 cr2res_extract_traces() \n\
218 cr2res_qc_obs_nodding_signal() \n\
219 cr2res_qc_obs_nodding_transmission() \n\
220 cr2res_qc_obs_slit_psf() \n\
221 cr2res_photom_engine() \n\
222 cr2res_io_save_COMBINED() \n\
223 cr2res_io_save_EXTRACT_1D() \n\
224 cr2res_io_save_SLIT_FUNC() \n\
225 cr2res_io_save_SLIT_MODEL() \n\
226 cr2res_io_save_THROUGHPUT() \n\
244int cpl_plugin_get_info(cpl_pluginlist * list)
246 cpl_recipe * recipe = cpl_calloc(1,
sizeof *recipe );
247 cpl_plugin * plugin = &recipe->interface;
249 if (cpl_plugin_init(plugin,
251 CR2RES_BINARY_VERSION,
252 CPL_PLUGIN_TYPE_RECIPE,
254 "Nodding Observation recipe",
255 cr2res_obs_nodding_description,
256 CR2RES_PIPELINE_AUTHORS,
259 cr2res_obs_nodding_create,
260 cr2res_obs_nodding_exec,
261 cr2res_obs_nodding_destroy)) {
262 cpl_msg_error(cpl_func,
"Plugin initialization failed");
263 (void)cpl_error_set_where(cpl_func);
267 if (cpl_pluginlist_append(list, plugin)) {
268 cpl_msg_error(cpl_func,
"Error adding plugin to list");
269 (void)cpl_error_set_where(cpl_func);
285static int cr2res_obs_nodding_create(cpl_plugin * plugin)
287 cpl_recipe * recipe ;
291 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
292 recipe = (cpl_recipe *)plugin;
297 recipe->parameters = cpl_parameterlist_new();
300 p = cpl_parameter_new_value(
301 "cr2res.cr2res_obs_nodding.subtract_nolight_rows",
303 "Subtract median row from baffled region at detector bottom",
304 "cr2res.cr2res_obs_nodding", FALSE);
305 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"subtract_nolight_rows");
306 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
307 cpl_parameterlist_append(recipe->parameters, p);
309 p = cpl_parameter_new_value(
310 "cr2res.cr2res_obs_nodding.subtract_interorder_column",
312 "Subtract column-by-column fit to the pixel values between orders",
313 "cr2res.cr2res_obs_nodding", TRUE);
314 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
315 "subtract_interorder_column");
316 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
317 cpl_parameterlist_append(recipe->parameters, p);
319 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.cosmics",
320 CPL_TYPE_BOOL,
"Find and mark cosmic rays hits as bad",
321 "cr2res.cr2res_obs_nodding", FALSE);
322 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"cosmics");
323 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
324 cpl_parameterlist_append(recipe->parameters, p);
326 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.nodding_invert",
327 CPL_TYPE_BOOL,
"Flag to use when A is above B",
328 "cr2res.cr2res_obs_nodding", FALSE);
329 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"nodding_invert");
330 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
331 cpl_parameterlist_append(recipe->parameters, p);
333 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.extract_oversample",
334 CPL_TYPE_INT,
"factor by which to oversample the extraction",
335 "cr2res.cr2res_obs_nodding", 7);
336 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"extract_oversample");
337 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
338 cpl_parameterlist_append(recipe->parameters, p);
340 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.extract_swath_width",
341 CPL_TYPE_INT,
"The swath width",
"cr2res.cr2res_obs_nodding", 800);
342 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"extract_swath_width");
343 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
344 cpl_parameterlist_append(recipe->parameters, p);
346 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.extract_height",
347 CPL_TYPE_INT,
"Extraction height",
"cr2res.cr2res_obs_nodding", -1);
348 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"extract_height");
349 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
350 cpl_parameterlist_append(recipe->parameters, p);
352 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.extract_smooth_slit",
353 CPL_TYPE_DOUBLE,
"Smoothing along the slit",
354 "cr2res.cr2res_obs_nodding", 1.0);
355 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"extract_smooth_slit");
356 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
357 cpl_parameterlist_append(recipe->parameters, p);
359 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.extract_smooth_spec",
360 CPL_TYPE_DOUBLE,
"Smoothing along spectrum",
361 "cr2res.cr2res_obs_nodding", 8e-8);
362 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"extract_smooth_spec");
363 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
364 cpl_parameterlist_append(recipe->parameters, p);
366 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.detector",
367 CPL_TYPE_INT,
"Only reduce the specified detector",
368 "cr2res.cr2res_obs_nodding", 0);
369 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"detector");
370 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
371 cpl_parameterlist_append(recipe->parameters, p);
373 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.create_idp",
374 CPL_TYPE_BOOL,
"Flag to produce IDP files",
375 "cr2res.cr2res_obs_nodding", FALSE);
376 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"idp");
377 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
378 cpl_parameterlist_append(recipe->parameters, p);
380 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.display_detector",
381 CPL_TYPE_INT,
"Apply the display for the specified detector",
382 "cr2res.cr2res_obs_nodding", 0);
383 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"display_detector");
384 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
385 cpl_parameterlist_append(recipe->parameters, p);
387 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.display_order",
388 CPL_TYPE_INT,
"Apply the display for the specified order",
389 "cr2res.cr2res_obs_nodding", 1000);
390 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"display_order");
391 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
392 cpl_parameterlist_append(recipe->parameters, p);
394 p = cpl_parameter_new_value(
"cr2res.cr2res_obs_nodding.display_trace",
395 CPL_TYPE_INT,
"Apply the display for the specified trace",
396 "cr2res.cr2res_obs_nodding", 0);
397 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"display_trace");
398 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
399 cpl_parameterlist_append(recipe->parameters, p);
411static int cr2res_obs_nodding_exec(cpl_plugin * plugin)
416 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
417 recipe = (cpl_recipe *)plugin;
420 return cr2res_obs_nodding(recipe->frames, recipe->parameters);
430static int cr2res_obs_nodding_destroy(cpl_plugin * plugin)
435 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
436 recipe = (cpl_recipe *)plugin;
439 cpl_parameterlist_delete(recipe->parameters);
451static int cr2res_obs_nodding(
452 cpl_frameset * frameset,
453 const cpl_parameterlist * parlist)
455 const cpl_parameter * param ;
456 int extract_oversample, extract_swath_width,
457 extract_height, reduce_det,
458 disp_order_idx, disp_trace, disp_det,
459 nodding_invert, create_idp, subtract_nolight_rows,
460 subtract_interorder_column, cosmics ;
461 double extract_smooth_slit, extract_smooth_spec;
463 double ra, dec, mjd_obs, mjd_cen, geolon, geolat, geoelev,
465 cpl_frameset * rawframes ;
466 cpl_frameset * raw_flat_frames ;
467 const cpl_frame * trace_wave_frame ;
468 const cpl_frame * detlin_frame ;
469 const cpl_frame * master_dark_frame ;
470 const cpl_frame * photo_flux_frame ;
471 const cpl_frame * blaze_frame ;
472 const cpl_frame * master_flat_frame ;
473 const cpl_frame * bpm_frame ;
475 cpl_size nlabels, l ;
476 char * product_name_addon ;
477 hdrl_image * combineda[CR2RES_NB_DETECTORS] ;
478 cpl_table * extracta[CR2RES_NB_DETECTORS] ;
479 cpl_table * slitfunca[CR2RES_NB_DETECTORS] ;
480 hdrl_image * modela[CR2RES_NB_DETECTORS] ;
481 cpl_table * twa[CR2RES_NB_DETECTORS] ;
482 hdrl_image * combinedb[CR2RES_NB_DETECTORS] ;
483 cpl_table * extractb[CR2RES_NB_DETECTORS] ;
484 cpl_table * slitfuncb[CR2RES_NB_DETECTORS] ;
485 hdrl_image * modelb[CR2RES_NB_DETECTORS] ;
486 cpl_table * twb[CR2RES_NB_DETECTORS] ;
487 cpl_table * extractc[CR2RES_NB_DETECTORS] ;
488 cpl_table * throughput[CR2RES_NB_DETECTORS] ;
489 cpl_propertylist * qc_main ;
490 cpl_propertylist * ext_plist[CR2RES_NB_DETECTORS] ;
491 cpl_propertylist * ext_plist_photom[CR2RES_NB_DETECTORS] ;
494 cpl_table * eop_table ;
502 param = cpl_parameterlist_find_const(parlist,
503 "cr2res.cr2res_obs_nodding.subtract_nolight_rows");
504 subtract_nolight_rows = cpl_parameter_get_bool(param);
505 param = cpl_parameterlist_find_const(parlist,
506 "cr2res.cr2res_obs_nodding.subtract_interorder_column");
507 subtract_interorder_column = cpl_parameter_get_bool(param);
508 param = cpl_parameterlist_find_const(parlist,
509 "cr2res.cr2res_obs_nodding.nodding_invert");
510 nodding_invert = cpl_parameter_get_bool(param);
511 param = cpl_parameterlist_find_const(parlist,
512 "cr2res.cr2res_obs_nodding.extract_oversample");
513 extract_oversample = cpl_parameter_get_int(param);
514 param = cpl_parameterlist_find_const(parlist,
515 "cr2res.cr2res_obs_nodding.extract_swath_width");
516 extract_swath_width = cpl_parameter_get_int(param);
517 param = cpl_parameterlist_find_const(parlist,
518 "cr2res.cr2res_obs_nodding.extract_height");
519 extract_height = cpl_parameter_get_int(param);
520 param = cpl_parameterlist_find_const(parlist,
521 "cr2res.cr2res_obs_nodding.extract_smooth_slit");
522 extract_smooth_slit = cpl_parameter_get_double(param);
523 param = cpl_parameterlist_find_const(parlist,
524 "cr2res.cr2res_obs_nodding.extract_smooth_spec");
525 extract_smooth_spec = cpl_parameter_get_double(param);
526 param = cpl_parameterlist_find_const(parlist,
527 "cr2res.cr2res_obs_nodding.detector");
528 reduce_det = cpl_parameter_get_int(param);
529 param = cpl_parameterlist_find_const(parlist,
530 "cr2res.cr2res_obs_nodding.create_idp");
531 create_idp = cpl_parameter_get_bool(param);
532 param = cpl_parameterlist_find_const(parlist,
533 "cr2res.cr2res_obs_nodding.display_detector");
534 disp_det = cpl_parameter_get_int(param);
535 param = cpl_parameterlist_find_const(parlist,
536 "cr2res.cr2res_obs_nodding.display_order");
537 disp_order_idx = cpl_parameter_get_int(param);
538 param = cpl_parameterlist_find_const(parlist,
539 "cr2res.cr2res_obs_nodding.display_trace");
540 disp_trace = cpl_parameter_get_int(param);
541 param = cpl_parameterlist_find_const(parlist,
542 "cr2res.cr2res_obs_nodding.cosmics");
543 cosmics = cpl_parameter_get_bool(param);
546 int extract_niter = 30;
547 double extract_kappa = 10;
551 cpl_msg_error(__func__,
"Cannot identify RAW and CALIB frames") ;
552 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
558 if (trace_wave_frame == NULL) {
559 cpl_msg_error(__func__,
"Could not find TRACE_WAVE frame") ;
562 detlin_frame = cpl_frameset_find_const(frameset,
563 CR2RES_CAL_DETLIN_COEFFS_PROCATG);
564 master_dark_frame = cpl_frameset_find_const(frameset,
565 CR2RES_CAL_DARK_MASTER_PROCATG) ;
566 if (master_dark_frame != NULL) {
567 cpl_msg_warning(__func__,
568 "Providing a MASTER DARK is not recommended for this recipe") ;
570 blaze_frame = cpl_frameset_find_const(frameset,
571 CR2RES_CAL_FLAT_EXTRACT_1D_PROCATG) ;
572 photo_flux_frame = cpl_frameset_find_const(frameset,
573 CR2RES_PHOTO_FLUX_PROCATG) ;
574 master_flat_frame = cpl_frameset_find_const(frameset,
575 CR2RES_CAL_FLAT_MASTER_PROCATG) ;
579 rawframes = cr2res_obs_nodding_find_RAW(frameset, &type) ;
580 if (rawframes == NULL) {
581 cpl_msg_error(__func__,
"Could not find RAW frames") ;
589 if ((labels = cpl_frameset_labelise(rawframes,
590 cr2res_obs_nodding_astrometry_compare, &nlabels)) == NULL) {
591 cpl_msg_error(__func__,
"Cannot label input frames") ;
592 cpl_frameset_delete(rawframes) ;
593 if (raw_flat_frames != NULL) cpl_frameset_delete(raw_flat_frames) ;
594 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
599 if (type != 3 && nlabels != 1) {
600 cpl_msg_error(__func__,
"Expect only one DROT POSANG value - abort") ;
601 cpl_frameset_delete(rawframes) ;
602 if (raw_flat_frames != NULL) cpl_frameset_delete(raw_flat_frames) ;
604 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
609 for (l = 0; l < (int)nlabels; l++) {
611 cpl_frameset *raw_one_angle;
612 cpl_propertylist *plist;
614 raw_one_angle = cpl_frameset_extract(rawframes, labels, (cpl_size)l) ;
617 plist = cpl_propertylist_load(cpl_frame_get_filename(
618 cpl_frameset_get_position(raw_one_angle, 0)), 0) ;
620 cpl_propertylist_delete(plist) ;
622 cpl_msg_info(__func__,
"Process Angle %g", drot_posang) ;
623 cpl_msg_indent_more() ;
626 for (det_nr = 1; det_nr <= CR2RES_NB_DETECTORS; det_nr++) {
628 combineda[det_nr - 1] = NULL;
629 extracta[det_nr - 1] = NULL;
630 slitfunca[det_nr - 1] = NULL;
631 modela[det_nr - 1] = NULL;
632 twa[det_nr - 1] = NULL;
633 combinedb[det_nr - 1] = NULL;
634 extractb[det_nr - 1] = NULL;
635 slitfuncb[det_nr - 1] = NULL;
636 modelb[det_nr - 1] = NULL;
637 twb[det_nr - 1] = NULL;
638 extractc[det_nr - 1] = NULL;
639 ext_plist[det_nr - 1] = NULL;
640 ext_plist_photom[det_nr - 1] = NULL;
641 throughput[det_nr - 1] = NULL;
644 if (reduce_det != 0 && det_nr != reduce_det)
647 cpl_msg_info(__func__,
"Process Detector %d", det_nr);
648 cpl_msg_indent_more();
651 if (cr2res_obs_nodding_reduce(
652 raw_one_angle, trace_wave_frame,
653 detlin_frame, master_dark_frame, master_flat_frame,
654 bpm_frame, blaze_frame, nodding_invert,
655 subtract_nolight_rows, subtract_interorder_column, cosmics,
656 extract_oversample, extract_swath_width, extract_height,
657 extract_smooth_slit, extract_smooth_spec, extract_niter,
658 extract_kappa, det_nr, disp_det, disp_order_idx, disp_trace,
659 &(combineda[det_nr - 1]), &(extracta[det_nr - 1]),
660 &(slitfunca[det_nr - 1]), &(modela[det_nr - 1]),
661 &(twa[det_nr - 1]), &(combinedb[det_nr - 1]),
662 &(extractb[det_nr - 1]), &(slitfuncb[det_nr - 1]),
663 &(modelb[det_nr - 1]), &(twb[det_nr - 1]),
664 &(extractc[det_nr - 1]), &(ext_plist[det_nr - 1])) == -1) {
665 cpl_msg_warning(__func__,
"Failed to reduce detector %d",
669 else if (type == 2) {
672 "Sensitivity / Conversion / Throughput computation");
673 cpl_msg_indent_more();
677 gain = CR2RES_GAIN_CHIP1;
679 gain = CR2RES_GAIN_CHIP2;
681 gain = CR2RES_GAIN_CHIP3;
684 plist = cpl_propertylist_load(
685 cpl_frame_get_filename(
686 cpl_frameset_get_position_const(raw_one_angle, 0)),
693 cpl_propertylist_delete(plist);
694 if (cpl_error_get_code()) {
695 cpl_msg_indent_less();
697 cpl_msg_warning(__func__,
"Missing Header Informations");
702 extracta[det_nr - 1],
703 cpl_frame_get_filename(photo_flux_frame),
704 cur_setting, ra, dec, gain, dit, disp_det == det_nr,
705 disp_order_idx, disp_trace,
706 &(throughput[det_nr - 1]),
707 &(ext_plist_photom[det_nr - 1])) == -1) {
708 cpl_msg_warning(__func__,
709 "Failed to reduce detector %d", det_nr);
713 cpl_free(cur_setting);
714 cpl_msg_indent_less();
716 cpl_msg_indent_less();
720 if (nlabels == 1) product_name_addon = cpl_sprintf(
".fits") ;
721 else product_name_addon = cpl_sprintf(
"_%g.fits",
725 for (det_nr=1 ; det_nr<=CR2RES_NB_DETECTORS ; det_nr++) {
726 if (ext_plist_photom[det_nr-1] != NULL &&
727 ext_plist[det_nr-1] != NULL) {
728 cpl_propertylist_append(ext_plist[det_nr-1],
729 ext_plist_photom[det_nr-1]) ;
734 qc_main = cpl_propertylist_new();
735 cpl_propertylist_append_double(qc_main,
736 CR2RES_HEADER_DRS_TMID,
741 if (eop_table != NULL) {
742 plist=cpl_propertylist_load(cpl_frame_get_filename(
743 cpl_frameset_get_position_const(raw_one_angle, 0)), 0) ;
745 ra = cpl_propertylist_get_double(plist,
"RA") ;
746 dec = cpl_propertylist_get_double(plist,
"DEC") ;
747 mjd_obs = cpl_propertylist_get_double(plist,
"MJD-OBS") ;
748 geolon = cpl_propertylist_get_double(plist,
"ESO TEL GEOLON") ;
749 geolat = cpl_propertylist_get_double(plist,
"ESO TEL GEOLAT") ;
750 geoelev = cpl_propertylist_get_double(plist,
"ESO TEL GEOELEV") ;
752 cpl_propertylist_delete(plist) ;
755 if (!cpl_error_get_code()) {
758 (mjd_cen-mjd_obs)*24*3600, geolon, geolat, geoelev,
759 0.0, 0.0, 0.0, 0.0, &barycorr);
761 cpl_msg_info(__func__,
"Barycentric correction: %g m/s",
764 cpl_msg_info(__func__,
"Cannot derive Barycentric correction");
767 cpl_table_delete(eop_table) ;
768 cpl_propertylist_append_double(qc_main, CR2RES_HEADER_DRS_BARYCORR,
773 cpl_propertylist_append_int(qc_main,
774 CR2RES_HEADER_QC_NUMSAT,
778 if (trace_wave_frame != NULL)
779 cpl_frameset_insert(raw_one_angle,
780 cpl_frame_duplicate(trace_wave_frame)) ;
781 if (detlin_frame != NULL)
782 cpl_frameset_insert(raw_one_angle,
783 cpl_frame_duplicate(detlin_frame)) ;
784 if (master_dark_frame != NULL)
785 cpl_frameset_insert(raw_one_angle,
786 cpl_frame_duplicate(master_dark_frame)) ;
787 if (master_flat_frame!= NULL)
788 cpl_frameset_insert(raw_one_angle,
789 cpl_frame_duplicate(master_flat_frame)) ;
790 if (bpm_frame!= NULL)
791 cpl_frameset_insert(raw_one_angle,
792 cpl_frame_duplicate(bpm_frame)) ;
793 if (blaze_frame!= NULL)
794 cpl_frameset_insert(raw_one_angle,
795 cpl_frame_duplicate(blaze_frame)) ;
796 if (photo_flux_frame!= NULL)
797 cpl_frameset_insert(raw_one_angle,
798 cpl_frame_duplicate(photo_flux_frame)) ;
800 out_file = cpl_sprintf(
"%s_combinedA%s", RECIPE_STRING,
801 product_name_addon) ;
803 combineda, qc_main, ext_plist,
804 CR2RES_OBS_NODDING_COMBINEDA_PROCATG, RECIPE_STRING) ;
807 char *qc_perdet_keywords[] = { CR2RES_HEADER_QC_SIGNAL,
808 CR2RES_HEADER_QC_STANDARD_FLUX,
809 CR2RES_HEADER_QC_SLITFWHM_MED };
811 char *qc_pertrace_keywords[] = { CR2RES_HEADER_QC_SNR_BASE,
812 CR2RES_HEADER_QC_SLITFWHM_ORDER_BASE };
814 int qc_perdet_size =
sizeof(qc_perdet_keywords) /
sizeof(
char *);
815 int qc_pertrace_size =
sizeof(qc_pertrace_keywords) /
sizeof(
char *);
817 int qc_sizes_ext[] = {CR2RES_NB_DETECTORS};
818 cpl_propertylist** qc_plists_ext[] = {ext_plist} ;
819 char * qc_res_avg, * qc_res_rmsd, * qc_ref;
823 for (qc_i=0; qc_i<qc_perdet_size ; qc_i++) {
825 qc_res_avg = cpl_sprintf(
"%s %s",
826 qc_perdet_keywords[qc_i],
"AVG");
827 qc_res_rmsd = cpl_sprintf(
"%s %s",
828 qc_perdet_keywords[qc_i],
"RMS");
830 cr2res_qc_calculate_mean_and_rmsd(qc_plists_ext, 1, qc_sizes_ext,
831 qc_perdet_keywords[qc_i], qc_main,
832 qc_res_avg, qc_res_rmsd);
834 cpl_free(qc_res_avg);
835 cpl_free(qc_res_rmsd);
839 int min_order = INT_MAX;
840 int max_order = INT_MIN;
841 int current_min, current_max;
843 for (qc_i = 0; qc_i < CR2RES_NB_DETECTORS; qc_i++) {
844 if (twa[qc_i] == NULL) {
848 cpl_table_get_column_min(twa[qc_i],
"Order");
849 if (cpl_error_get_code() != CPL_ERROR_NONE) {
852 if (current_min < min_order) {
853 min_order = current_min;
857 cpl_table_get_column_max(twa[qc_i],
"Order");
858 if (cpl_error_get_code() != CPL_ERROR_NONE) {
861 if (current_max > max_order) {
862 max_order = current_max;
866 for (qc_i = 0; qc_i < qc_pertrace_size; qc_i++) {
867 for (
int order_id = min_order; order_id <= max_order; order_id++) {
869 qc_ref = cpl_sprintf(
"%s%d", qc_pertrace_keywords[qc_i],
872 cpl_sprintf(
"%s%d %s", qc_pertrace_keywords[qc_i],
875 cpl_sprintf(
"%s%d %s", qc_pertrace_keywords[qc_i],
878 cr2res_qc_calculate_mean_and_rmsd(qc_plists_ext, 1, qc_sizes_ext,
879 qc_ref, qc_main, qc_res_avg,
883 cpl_free(qc_res_avg);
884 cpl_free(qc_res_rmsd);
888 out_file = cpl_sprintf(
"%s_extractedA%s", RECIPE_STRING,
889 product_name_addon) ;
891 extracta, qc_main, ext_plist,
892 CR2RES_OBS_NODDING_EXTRACTA_PROCATG, RECIPE_STRING);
895 extracta, qc_main, ext_plist,
896 CR2RES_OBS_NODDING_EXTRACTA_IDP_PROCATG,
925 out_file = cpl_sprintf(
"%s_slitfuncA%s", RECIPE_STRING,
926 product_name_addon) ;
928 slitfunca, qc_main, ext_plist,
929 CR2RES_OBS_NODDING_SLITFUNCA_PROCATG, RECIPE_STRING) ;
932 out_file = cpl_sprintf(
"%s_modelA%s", RECIPE_STRING,
933 product_name_addon) ;
935 modela, qc_main, ext_plist,
936 CR2RES_OBS_NODDING_SLITMODELA_PROCATG, RECIPE_STRING) ;
939 out_file = cpl_sprintf(
"%s_trace_wave_A%s", RECIPE_STRING,
940 product_name_addon) ;
942 twa, qc_main, ext_plist, CR2RES_OBS_NODDING_TWA_PROCATG,
946 out_file = cpl_sprintf(
"%s_combinedB%s", RECIPE_STRING,
947 product_name_addon) ;
949 combinedb, qc_main, ext_plist,
950 CR2RES_OBS_NODDING_COMBINEDB_PROCATG, RECIPE_STRING) ;
953 out_file = cpl_sprintf(
"%s_extractedB%s", RECIPE_STRING,
954 product_name_addon) ;
956 extractb, qc_main, ext_plist,
957 CR2RES_OBS_NODDING_EXTRACTB_PROCATG, RECIPE_STRING);
960 extractb, qc_main, ext_plist,
961 CR2RES_OBS_NODDING_EXTRACTB_IDP_PROCATG,
966 out_file = cpl_sprintf(
"%s_slitfuncB%s", RECIPE_STRING,
967 product_name_addon) ;
969 slitfuncb, qc_main, ext_plist,
970 CR2RES_OBS_NODDING_SLITFUNCB_PROCATG, RECIPE_STRING) ;
973 out_file = cpl_sprintf(
"%s_modelB%s", RECIPE_STRING,
974 product_name_addon) ;
976 modelb, qc_main, ext_plist,
977 CR2RES_OBS_NODDING_SLITMODELB_PROCATG, RECIPE_STRING) ;
980 out_file = cpl_sprintf(
"%s_trace_wave_B%s", RECIPE_STRING,
981 product_name_addon) ;
983 twb, qc_main, ext_plist, CR2RES_OBS_NODDING_TWB_PROCATG,
987 out_file = cpl_sprintf(
"%s_extracted_combined%s", RECIPE_STRING,
988 product_name_addon) ;
990 extractc, qc_main, ext_plist,
991 CR2RES_OBS_NODDING_EXTRACTC_PROCATG, RECIPE_STRING);
994 extractc, qc_main, ext_plist,
995 CR2RES_OBS_NODDING_EXTRACTC_IDP_PROCATG,
1002 qc_res_avg = cpl_sprintf(
"%s %s", CR2RES_HEADER_QC_THROUGHPUT,
"AVG");
1003 qc_res_rmsd = cpl_sprintf(
"%s %s", CR2RES_HEADER_QC_THROUGHPUT,
"RMS");
1005 cr2res_qc_calculate_mean_and_rmsd(qc_plists_ext, 1, qc_sizes_ext,
1006 CR2RES_HEADER_QC_THROUGHPUT, qc_main,
1007 qc_res_avg, qc_res_rmsd);
1009 cpl_free(qc_res_avg);
1010 cpl_free(qc_res_rmsd);
1012 out_file = cpl_sprintf(
"%s_throughput%s", RECIPE_STRING,
1013 product_name_addon) ;
1015 parlist, throughput, qc_main, ext_plist,
1016 CR2RES_OBS_NODDING_THROUGHPUT_PROCATG, RECIPE_STRING) ;
1019 cpl_free(product_name_addon) ;
1022 cpl_propertylist_delete(qc_main) ;
1023 for (det_nr=1 ; det_nr<=CR2RES_NB_DETECTORS ; det_nr++) {
1024 if (combineda[det_nr-1] != NULL)
1026 if (extracta[det_nr-1] != NULL)
1027 cpl_table_delete(extracta[det_nr-1]) ;
1028 if (slitfunca[det_nr-1] != NULL)
1029 cpl_table_delete(slitfunca[det_nr-1]) ;
1030 if (modela[det_nr-1] != NULL)
1032 if (twa[det_nr-1] != NULL)
1033 cpl_table_delete(twa[det_nr-1]) ;
1034 if (combinedb[det_nr-1] != NULL)
1036 if (extractb[det_nr-1] != NULL)
1037 cpl_table_delete(extractb[det_nr-1]) ;
1038 if (slitfuncb[det_nr-1] != NULL)
1039 cpl_table_delete(slitfuncb[det_nr-1]) ;
1040 if (modelb[det_nr-1] != NULL)
1042 if (twb[det_nr-1] != NULL)
1043 cpl_table_delete(twb[det_nr-1]) ;
1044 if (extractc[det_nr-1] != NULL)
1045 cpl_table_delete(extractc[det_nr-1]) ;
1046 if (throughput[det_nr-1] != NULL)
1047 cpl_table_delete(throughput[det_nr-1]) ;
1048 if (ext_plist[det_nr-1] != NULL)
1049 cpl_propertylist_delete(ext_plist[det_nr-1]) ;
1050 if (ext_plist_photom[det_nr-1] != NULL)
1051 cpl_propertylist_delete(ext_plist_photom[det_nr-1]) ;
1053 cpl_frameset_delete(raw_one_angle) ;
1054 cpl_msg_indent_less() ;
1057 cpl_frameset_delete(rawframes) ;
1058 if (raw_flat_frames != NULL) cpl_frameset_delete(raw_flat_frames) ;
1060 return (
int)cpl_error_get_code();
1101static int cr2res_obs_nodding_reduce(
1102 const cpl_frameset * rawframes,
1103 const cpl_frame * trace_wave_frame,
1104 const cpl_frame * detlin_frame,
1105 const cpl_frame * master_dark_frame,
1106 const cpl_frame * master_flat_frame,
1107 const cpl_frame * bpm_frame,
1108 const cpl_frame * blaze_frame,
1110 int subtract_nolight_rows,
1111 int subtract_interorder_column,
1113 int extract_oversample,
1114 int extract_swath_width,
1116 double extract_smooth_slit,
1117 double extract_smooth_spec,
1119 double extract_kappa,
1124 hdrl_image ** combineda,
1125 cpl_table ** extracta,
1126 cpl_table ** slitfunca,
1127 hdrl_image ** modela,
1129 hdrl_image ** combinedb,
1130 cpl_table ** extractb,
1131 cpl_table ** slitfuncb,
1132 hdrl_image ** modelb,
1134 cpl_table ** extractc,
1135 cpl_propertylist ** ext_plist)
1137 hdrl_imagelist * in ;
1138 hdrl_imagelist * in_calib ;
1139 hdrl_imagelist * in_a ;
1140 hdrl_imagelist * in_b ;
1141 hdrl_imagelist * diff_a ;
1142 hdrl_imagelist * diff_b ;
1143 hdrl_image * collapsed_a ;
1144 hdrl_image * collapsed_b ;
1145 cpl_image * contrib_a ;
1146 cpl_image * contrib_b ;
1147 cr2res_nodding_pos * nod_positions ;
1149 cpl_vector * ndits=NULL ;
1150 cpl_table * trace_wave ;
1152 cpl_table * trace_wave_a ;
1153 cpl_table * trace_wave_b ;
1154 cpl_table * blaze_table ;
1155 cpl_array * slit_frac_a ;
1156 cpl_array * slit_frac_b ;
1157 cpl_table * extracted_a ;
1158 cpl_table * extracted_b ;
1159 cpl_table * extracted_combined ;
1160 cpl_table * slit_func_a ;
1161 cpl_table * slit_func_b ;
1162 hdrl_image * model_master_a ;
1163 hdrl_image * model_master_b ;
1164 cpl_propertylist * plist ;
1165 cpl_size nframes, i ;
1167 const char * first_fname ;
1168 double slit_length, extr_width_frac, slit_frac_a_bot,
1169 slit_frac_a_mid, slit_frac_a_top, slit_frac_b_bot,
1170 slit_frac_b_mid, slit_frac_b_top, nod_throw,
1171 gain, error_factor ;
1172 double qc_signal_a, qc_signal_b, qc_fwhm_a,
1173 qc_fwhm_b, qc_standard_flux_a,
1174 qc_standard_flux_b, qc_fwhm_med, blaze_norm ;
1175 cpl_array * fwhm_a_array ;
1176 cpl_array * fwhm_b_array ;
1177 char * cur_setting ;
1178 int * order_idx_values ;
1180 int nb_order_idx_values,
1181 order_zp, order_idx, order_idxp ;
1184 if (combineda == NULL || combinedb == NULL ||
1185 twa == NULL || twb == NULL ||
1186 slitfunca == NULL || slitfuncb == NULL ||
1187 modela == NULL || modelb == NULL ||
1188 extracta == NULL || extractb == NULL || extractc == NULL ||
1189 ext_plist == NULL || rawframes == NULL || trace_wave_frame == NULL)
1193 if (reduce_det == 1) gain = CR2RES_GAIN_CHIP1 ;
1194 else if (reduce_det == 2) gain = CR2RES_GAIN_CHIP2 ;
1195 else if (reduce_det == 3) gain = CR2RES_GAIN_CHIP3 ;
1197 cpl_msg_error(__func__,
"Failed to get the Gain value") ;
1202 if (cr2res_obs_nodding_check_inputs_validity(rawframes) != 1) {
1203 cpl_msg_error(__func__,
"Invalid Inputs") ;
1208 nframes = cpl_frameset_get_size(rawframes) ;
1209 first_fname = cpl_frame_get_filename(
1210 cpl_frameset_get_position_const(rawframes, 0)) ;
1213 if ((plist = cpl_propertylist_load(cpl_frame_get_filename(trace_wave_frame),
1215 cpl_msg_error(__func__,
"Cannot read the ORDER_ZP from the input TW") ;
1218 order_zp = cr2res_pfits_get_order_zp(plist) ;
1219 cpl_propertylist_delete(plist) ;
1220 if (cpl_error_get_code()) {
1221 cpl_msg_error(__func__,
"Missing ORDER_ZP in the header - Skip") ;
1228 cpl_msg_info(__func__,
"Get the Nodding positions") ;
1229 cpl_msg_indent_more() ;
1231 for (i=0 ; i<nframes ; i++) {
1232 cpl_msg_info(__func__,
"Frame %s - Nodding %c",
1233 cpl_frame_get_filename(
1234 cpl_frameset_get_position_const(rawframes, i)),
1237 cpl_msg_indent_less() ;
1242 if (cpl_msg_get_level() == CPL_MSG_DEBUG && dits != NULL)
1243 cpl_vector_dump(dits, stdout) ;
1247 if (cpl_msg_get_level() == CPL_MSG_DEBUG && ndits != NULL)
1248 cpl_vector_dump(ndits, stdout) ;
1251 cpl_msg_info(__func__,
"Load the image list") ;
1253 reduce_det)) == NULL) {
1254 cpl_msg_error(__func__,
"Cannot load images") ;
1255 cpl_free(nod_positions) ;
1256 if (dits != NULL) cpl_vector_delete(dits) ;
1260 cpl_msg_error(__func__,
"Inconsistent number of loaded images") ;
1261 cpl_free(nod_positions) ;
1262 if (dits != NULL) cpl_vector_delete(dits) ;
1268 cpl_msg_info(__func__,
"Apply the Calibrations") ;
1269 cpl_msg_indent_more() ;
1271 subtract_nolight_rows, subtract_interorder_column, cosmics,
1272 master_flat_frame, master_dark_frame, bpm_frame, detlin_frame, dits,
1274 cpl_msg_error(__func__,
"Failed to apply the calibrations") ;
1275 cpl_msg_indent_less() ;
1276 cpl_free(nod_positions) ;
1277 if (dits != NULL) cpl_vector_delete(dits) ;
1278 if (ndits != NULL) cpl_vector_delete(ndits) ;
1283 if (dits != NULL) cpl_vector_delete(dits) ;
1284 cpl_msg_indent_less() ;
1287 cpl_msg_info(__func__,
"Split the images in A and B lists") ;
1288 cpl_msg_indent_more() ;
1291 cpl_msg_error(__func__,
"Failed to split the nodding positions") ;
1292 cpl_msg_indent_less() ;
1293 cpl_free(nod_positions) ;
1295 cpl_vector_delete(ndits) ;
1300 error_factor = gain * cpl_vector_get(ndits, 0) *
1303 for (i=0; i<cpl_vector_get_size(ndits); i++){
1304 if (cpl_vector_get(ndits,i) != cpl_vector_get(ndits, 0))
1305 cpl_msg_warning(__func__,
"Raw frames have different NDIT! "
1306 "Error spectrum will likely be scaled incorrectly.");
1308 cpl_vector_delete(ndits) ;
1309 cpl_free(nod_positions) ;
1311 cpl_msg_indent_less() ;
1316 cpl_msg_error(__func__,
"Inconsistent A / B number of images") ;
1323 cpl_msg_info(__func__,
"Compute difference image lists A-B and B-A") ;
1332 cpl_msg_info(__func__,
"Collapse image lists A-B and B-A") ;
1333 cpl_msg_indent_more() ;
1336 cpl_msg_error(__func__,
"Failed to Collapse A-B") ;
1339 cpl_msg_indent_less() ;
1342 cpl_image_delete(contrib_a) ;
1346 cpl_msg_error(__func__,
"Failed to Collapse B-A") ;
1349 cpl_msg_indent_less() ;
1352 cpl_image_delete(contrib_b) ;
1354 cpl_msg_indent_less() ;
1357 cpl_msg_info(__func__,
"Load the TRACE WAVE") ;
1359 trace_wave_frame), reduce_det)) == NULL) {
1360 cpl_msg_error(__func__,
"Failed to Load the traces file") ;
1367 cpl_msg_warning(__func__,
"TRACE ADJUST NOT YET IMPLEMENTED") ;
1382 cpl_msg_info(__func__,
"Compute the slit fractions for A and B positions");
1383 cpl_msg_indent_more() ;
1392 if ((plist = cpl_propertylist_load(first_fname, 0)) == NULL) {
1393 cpl_msg_error(__func__,
"Cannot read the NODTHROW in the input files") ;
1394 cpl_msg_indent_less() ;
1397 cpl_table_delete(trace_wave) ;
1401 cpl_propertylist_delete(plist) ;
1402 if (nod_throw < slit_length / 2.0) {
1403 extr_width_frac = nod_throw/slit_length ;
1404 if (nodding_invert == 1) {
1405 slit_frac_a_bot = 0.5 ;
1406 slit_frac_a_mid = slit_frac_a_bot + extr_width_frac/2.0 ;
1407 slit_frac_a_top = slit_frac_a_bot + extr_width_frac ;
1408 slit_frac_b_top = 0.5 ;
1409 slit_frac_b_mid = slit_frac_b_top - extr_width_frac/2.0 ;
1410 slit_frac_b_bot = slit_frac_b_top - extr_width_frac ;
1412 slit_frac_a_top = 0.5 ;
1413 slit_frac_a_mid = slit_frac_a_top - extr_width_frac/2.0 ;
1414 slit_frac_a_bot = slit_frac_a_top - extr_width_frac ;
1415 slit_frac_b_bot = 0.5 ;
1416 slit_frac_b_mid = slit_frac_b_bot + extr_width_frac/2.0 ;
1417 slit_frac_b_top = slit_frac_b_bot + extr_width_frac ;
1419 }
else if (nod_throw <= slit_length) {
1420 extr_width_frac = (slit_length - nod_throw)/slit_length ;
1421 if (nodding_invert == 1) {
1422 slit_frac_a_top = 1.0 ;
1423 slit_frac_a_mid = slit_frac_a_top - extr_width_frac/2.0 ;
1424 slit_frac_a_bot = slit_frac_a_top - extr_width_frac ;
1425 slit_frac_b_bot = 0.0 ;
1426 slit_frac_b_mid = slit_frac_b_bot + extr_width_frac/2.0 ;
1427 slit_frac_b_top = slit_frac_b_bot + extr_width_frac ;
1429 slit_frac_a_bot = 0.0 ;
1430 slit_frac_a_mid = slit_frac_a_bot + extr_width_frac/2.0 ;
1431 slit_frac_a_top = slit_frac_a_bot + extr_width_frac ;
1432 slit_frac_b_top = 1.0 ;
1433 slit_frac_b_mid = slit_frac_b_top - extr_width_frac/2.0 ;
1434 slit_frac_b_bot = slit_frac_b_top - extr_width_frac ;
1437 cpl_msg_error(__func__,
"NODTHROW > slit length (%g>%g)- abort",
1438 nod_throw, slit_length) ;
1439 cpl_msg_indent_less() ;
1442 cpl_table_delete(trace_wave) ;
1445 cpl_msg_info(__func__,
"Nod Throw : %g arcsecs", nod_throw) ;
1446 cpl_msg_info(__func__,
"Nodding A extraction: Slit fraction %g - %g",
1447 slit_frac_a_bot, slit_frac_a_top) ;
1448 cpl_msg_info(__func__,
"Nodding B extraction: Slit fraction %g - %g",
1449 slit_frac_b_bot, slit_frac_b_top) ;
1451 slit_frac_a = cpl_array_new(3, CPL_TYPE_DOUBLE) ;
1452 cpl_array_set(slit_frac_a, 0, slit_frac_a_bot) ;
1453 cpl_array_set(slit_frac_a, 1, slit_frac_a_mid) ;
1454 cpl_array_set(slit_frac_a, 2, slit_frac_a_top) ;
1456 slit_frac_b = cpl_array_new(3, CPL_TYPE_DOUBLE) ;
1457 cpl_array_set(slit_frac_b, 0, slit_frac_b_bot) ;
1458 cpl_array_set(slit_frac_b, 1, slit_frac_b_mid) ;
1459 cpl_array_set(slit_frac_b, 2, slit_frac_b_top) ;
1460 cpl_msg_indent_less() ;
1463 cpl_msg_info(__func__,
"Recompute the traces for the A slit fraction") ;
1465 slit_frac_a)) == NULL) {
1466 cpl_msg_error(__func__,
1467 "Failed to compute the traces for extraction of A") ;
1470 cpl_table_delete(trace_wave) ;
1471 cpl_array_delete(slit_frac_a) ;
1472 cpl_array_delete(slit_frac_b) ;
1475 cpl_array_delete(slit_frac_a) ;
1477 cpl_msg_info(__func__,
"Recompute the traces for the B slit fraction") ;
1479 slit_frac_b)) == NULL) {
1480 cpl_msg_error(__func__,
1481 "Failed to compute the traces for extraction of B") ;
1484 cpl_table_delete(trace_wave) ;
1485 cpl_table_delete(trace_wave_a) ;
1486 cpl_array_delete(slit_frac_b) ;
1489 cpl_array_delete(slit_frac_b) ;
1492 blaze_table = NULL ;
1494 if (blaze_frame != NULL) {
1495 cpl_msg_info(__func__,
"Load the BLAZE") ;
1497 blaze_frame), reduce_det)) == NULL) {
1498 cpl_msg_error(__func__,
"Failed to Load the Blaze file") ;
1501 cpl_table_delete(trace_wave) ;
1502 cpl_table_delete(trace_wave_a) ;
1503 cpl_table_delete(trace_wave_b) ;
1506 cpl_propertylist * blaze_plist ;
1507 blaze_plist = cpl_propertylist_load_regexp(cpl_frame_get_filename(
1508 blaze_frame),0,CR2RES_HEADER_QC_BLAZE_NORM,0);
1509 if(cpl_propertylist_get_size(blaze_plist)>0){
1510 blaze_norm = cpl_propertylist_get_double(blaze_plist, CR2RES_HEADER_QC_BLAZE_NORM);
1514 cpl_msg_warning(__func__,
"QC BLAZE NORM value not found, reverting to per trace normalization") ;
1516 if(blaze_plist!=NULL){
1517 cpl_propertylist_delete(blaze_plist);
1522 cpl_msg_info(__func__,
"A position Spectra Extraction") ;
1523 cpl_msg_indent_more() ;
1525 -1, CR2RES_EXTR_OPT_CURV, extract_height, extract_swath_width,
1526 extract_oversample, extract_smooth_slit, extract_smooth_spec,
1527 extract_niter, extract_kappa, error_factor,
1528 disp_det==reduce_det, disp_order_idx, disp_trace,
1529 &extracted_a, &slit_func_a, &model_master_a) == -1) {
1530 cpl_msg_error(__func__,
"Failed to extract A");
1531 cpl_msg_indent_less() ;
1534 cpl_table_delete(trace_wave_a) ;
1535 cpl_table_delete(trace_wave_b) ;
1536 cpl_table_delete(trace_wave) ;
1539 cpl_msg_indent_less() ;
1541 cpl_msg_info(__func__,
"B position Spectra Extraction") ;
1542 cpl_msg_indent_more() ;
1544 -1, CR2RES_EXTR_OPT_CURV, extract_height, extract_swath_width,
1545 extract_oversample, extract_smooth_slit, extract_smooth_spec,
1546 extract_niter, extract_kappa, error_factor,
1547 disp_det==reduce_det, disp_order_idx, disp_trace,
1548 &extracted_b, &slit_func_b, &model_master_b) == -1) {
1549 cpl_msg_error(__func__,
"Failed to extract B");
1550 cpl_msg_indent_less() ;
1551 cpl_table_delete(extracted_a) ;
1552 cpl_table_delete(slit_func_a) ;
1556 cpl_table_delete(trace_wave_a) ;
1557 cpl_table_delete(trace_wave_b) ;
1558 cpl_table_delete(trace_wave) ;
1561 cpl_msg_indent_less() ;
1563 if (blaze_table != NULL) cpl_table_delete(blaze_table) ;
1566 cpl_msg_info(__func__,
"A and B spectra combination") ;
1567 cpl_msg_indent_more() ;
1569 cpl_msg_indent_less() ;
1572 plist = cpl_propertylist_load(first_fname, 0) ;
1575 cpl_propertylist_delete(plist) ;
1578 plist = cpl_propertylist_load(first_fname,
1582 cpl_msg_info(__func__,
"QC parameters computation") ;
1585 cpl_propertylist_append_double(plist, CR2RES_HEADER_QC_SIGNAL,
1586 (qc_signal_a+qc_signal_b)/2.0) ;
1589 qc_standard_flux_a =
1591 qc_standard_flux_b =
1593 cpl_propertylist_append_double(plist, CR2RES_HEADER_QC_STANDARD_FLUX,
1594 (qc_standard_flux_a+qc_standard_flux_b)/2.0) ;
1595 cpl_free(cur_setting) ;
1598 qc_snrs =
cr2res_qc_snr(trace_wave_a, extracted_a, &order_idx_values,
1599 &nb_order_idx_values) ;
1600 for (i=0 ; i<nb_order_idx_values ; i++) {
1601 order_idx = order_idx_values[i] ;
1603 key_name = cpl_sprintf(CR2RES_HEADER_QC_SNR, order_idxp) ;
1604 cpl_propertylist_append_double(plist, key_name, qc_snrs[i]) ;
1605 cpl_free(key_name) ;
1607 cpl_free(order_idx_values) ;
1612 &nb_order_idx_values);
1615 fwhm_a_array = cpl_array_new(nb_order_idx_values, CPL_TYPE_DOUBLE);
1616 fwhm_b_array = cpl_array_new(nb_order_idx_values, CPL_TYPE_DOUBLE);
1617 for (i=0 ; i<nb_order_idx_values ; i++) {
1618 order_idx = order_idx_values[i] ;
1621 extract_oversample);
1623 extract_oversample);
1625 key_name = cpl_sprintf(CR2RES_HEADER_QC_SLITFWHM_ORDER, order_idxp) ;
1626 cpl_propertylist_append_double(plist, key_name,
1627 (qc_fwhm_a+qc_fwhm_b)/2.0) ;
1628 cpl_free(key_name) ;
1629 cpl_array_set(fwhm_a_array, i, qc_fwhm_a) ;
1630 cpl_array_set(fwhm_b_array, i, qc_fwhm_b) ;
1632 qc_fwhm_a = cpl_array_get_median(fwhm_a_array);
1633 qc_fwhm_b = cpl_array_get_median(fwhm_b_array);
1634 qc_fwhm_med = (qc_fwhm_a+qc_fwhm_b)/2.0 ;
1635 cpl_propertylist_append_double(plist, CR2RES_HEADER_QC_SLITFWHM_MED,
1637 if (qc_fwhm_med < 3.5) {
1638 cpl_msg_warning(__func__,
"Median FWHM of the PSF along the slit "
1639 "is %gpix, i.e. below the slit width. This means the slit "
1640 "is likely not evenly filled with light "
1641 "in the spectral direction. This can result in a "
1642 "wavelength offset between A and B nodding positions, and with "
1643 "respect to calibrations."
1646 cpl_array_delete(fwhm_a_array) ;
1647 cpl_array_delete(fwhm_b_array) ;
1652 for (i = 0; i < nb_order_idx_values; i++) {
1654 order_idx = order_idx_values[i] ;
1658 key_name = cpl_sprintf(CR2RES_HEADER_QC_REAL_ORDER, order_idxp) ;
1659 cpl_propertylist_append_int(plist, key_name, order_real) ;
1660 cpl_free(key_name) ;
1663 cpl_table_delete(trace_wave) ;
1664 cpl_free(order_idx_values) ;
1667 *combineda = collapsed_a ;
1668 *extracta = extracted_a ;
1669 *slitfunca = slit_func_a ;
1670 *modela = model_master_a ;
1671 *twa = trace_wave_a ;
1673 *combinedb = collapsed_b ;
1674 *extractb = extracted_b ;
1675 *slitfuncb = slit_func_b ;
1676 *modelb = model_master_b ;
1677 *twb = trace_wave_b ;
1679 *extractc = extracted_combined ;
1680 *ext_plist = plist ;
1692static int cr2res_obs_nodding_check_inputs_validity(
1693 const cpl_frameset * rawframes)
1695 cpl_propertylist * plist ;
1696 cr2res_nodding_pos * nod_positions ;
1697 cpl_size nframes, i ;
1702 if (rawframes == NULL)
return -1 ;
1705 nframes = cpl_frameset_get_size(rawframes) ;
1707 cpl_msg_error(__func__,
"Require an even number of raw frames") ;
1714 if (nod_positions == NULL)
return -1 ;
1715 for (i=0 ; i<nframes ; i++) {
1716 if (nod_positions[i] == CR2RES_NODDING_A) nb_a++ ;
1717 if (nod_positions[i] == CR2RES_NODDING_B) nb_b++ ;
1719 cpl_free(nod_positions) ;
1721 if (nb_a == 0 || nb_b == 0 || nb_a != nb_b) {
1722 cpl_msg_error(__func__,
"Require as many A and B positions") ;
1727 if ((plist = cpl_propertylist_load(cpl_frame_get_filename(
1728 cpl_frameset_get_position_const(rawframes, 0)),
1733 cpl_propertylist_delete(plist) ;
1734 for (i = 1; i < nframes; i++) {
1735 double nodthrow_cur;
1736 if ((plist = cpl_propertylist_load(cpl_frame_get_filename(
1737 cpl_frameset_get_position_const(rawframes, i)),
1742 cpl_propertylist_delete(plist) ;
1744 if (fabs(nodthrow_cur-nodthrow) > 1e-3) {
1745 cpl_msg_error(__func__,
1746 "Require constant NOD THROW in the raw frames") ;
1770static cpl_frameset * cr2res_obs_nodding_find_RAW(
1771 const cpl_frameset * in,
1774 cpl_frameset * out ;
1777 if (in == NULL)
return NULL ;
1784 if (type != NULL) *type = 1 ;
1791 if (type != NULL) *type = 2 ;
1796 CR2RES_OBS_ASTROMETRY_JITTER_RAW) ;
1799 if (type != NULL) *type = 3 ;
1804 if (type != NULL) *type = 0 ;
1817static int cr2res_obs_nodding_astrometry_compare(
1818 const cpl_frame * frame1,
1819 const cpl_frame * frame2)
1822 cpl_propertylist * plist1 ;
1823 cpl_propertylist * plist2 ;
1824 double dval1, dval2 ;
1827 if (frame1==NULL || frame2==NULL)
return -1 ;
1830 if ((plist1=cpl_propertylist_load(cpl_frame_get_filename(frame1),0))==NULL){
1831 cpl_msg_error(__func__,
"getting header from reference frame");
1834 if ((plist2=cpl_propertylist_load(cpl_frame_get_filename(frame2),0))==NULL){
1835 cpl_msg_error(__func__,
"getting header from reference frame");
1836 cpl_propertylist_delete(plist1) ;
1841 if (cpl_error_get_code()) {
1842 cpl_propertylist_delete(plist1) ;
1843 cpl_propertylist_delete(plist2) ;
1852 if (cpl_error_get_code()) {
1853 cpl_msg_error(__func__,
"Cannot get the angle");
1854 cpl_propertylist_delete(plist1) ;
1855 cpl_propertylist_delete(plist2) ;
1858 if (fabs(dval1-dval2) > 1e-3) comparison = 0 ;
1860 cpl_propertylist_delete(plist1) ;
1861 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_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.