CR2RE Pipeline Reference Manual 1.6.2
cr2res_obs_nodding.c
1/*
2 * This file is part of the CR2RES Pipeline
3 * Copyright (C) 2002,2003 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24/*-----------------------------------------------------------------------------
25 Includes
26 -----------------------------------------------------------------------------*/
27
28#include <string.h>
29#include <cpl.h>
30
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"
40#include "cr2res_io.h"
41#include "cr2res_qc.h"
42#include "cr2res_photom.h"
43
44/*-----------------------------------------------------------------------------
45 Define
46 -----------------------------------------------------------------------------*/
47
48#define RECIPE_STRING "cr2res_obs_nodding"
49
50/*-----------------------------------------------------------------------------
51 Plugin registration
52 -----------------------------------------------------------------------------*/
53
54int cpl_plugin_get_info(cpl_pluginlist * list);
55
56/*-----------------------------------------------------------------------------
57 Private function prototypes
58 -----------------------------------------------------------------------------*/
59
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,
65 int * type) ;
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,
76 int nodding_invert,
77 int subtract_nolight_rows,
78 int subtract_interorder_column,
79 int cosmics,
80 int extract_oversample,
81 int extract_swath_width,
82 int extract_height,
83 double extract_smooth_slit,
84 double extract_smooth_spec,
85 int extract_niter,
86 double extract_kappa,
87 int reduce_det,
88 int disp_det,
89 int disp_order_idx,
90 int disp_trace,
91 hdrl_image ** combineda,
92 cpl_table ** extracta,
93 cpl_table ** slitfunca,
94 hdrl_image ** modela,
95 cpl_table ** twa,
96 hdrl_image ** combinedb,
97 cpl_table ** extractb,
98 cpl_table ** slitfuncb,
99 hdrl_image ** modelb,
100 cpl_table ** twb,
101 cpl_table ** extractc,
102 cpl_propertylist ** ext_plist) ;
103
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 *);
108
109/*-----------------------------------------------------------------------------
110 Static variables
111 -----------------------------------------------------------------------------*/
112
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\
121 \n\
122 Inputs \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\
145 \n\
146 Outputs \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\
169 \n\
170 Algorithm \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\
176 -> model[a|b](d) \n\
177 -> tw[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\
182 Save throughput \n\
183 \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\
190 -> combined[a|b] \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\
203 -> throughput \n\
204 \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\
227";
228
229/*-----------------------------------------------------------------------------
230 Function code
231 -----------------------------------------------------------------------------*/
232
233/*----------------------------------------------------------------------------*/
243/*----------------------------------------------------------------------------*/
244int cpl_plugin_get_info(cpl_pluginlist * list)
245{
246 cpl_recipe * recipe = cpl_calloc(1, sizeof *recipe );
247 cpl_plugin * plugin = &recipe->interface;
248
249 if (cpl_plugin_init(plugin,
250 CPL_PLUGIN_API,
251 CR2RES_BINARY_VERSION,
252 CPL_PLUGIN_TYPE_RECIPE,
253 RECIPE_STRING,
254 "Nodding Observation recipe",
255 cr2res_obs_nodding_description,
256 CR2RES_PIPELINE_AUTHORS,
257 PACKAGE_BUGREPORT,
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);
264 return 1;
265 }
266
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);
270 return 1;
271 }
272
273 return 0;
274}
275
276/*----------------------------------------------------------------------------*/
284/*----------------------------------------------------------------------------*/
285static int cr2res_obs_nodding_create(cpl_plugin * plugin)
286{
287 cpl_recipe * recipe ;
288 cpl_parameter * p ;
289
290 /* Check that the plugin is part of a valid recipe */
291 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
292 recipe = (cpl_recipe *)plugin;
293 else
294 return -1;
295
296 /* Create the parameters list in the cpl_recipe object */
297 recipe->parameters = cpl_parameterlist_new();
298
299 /* Fill the parameters list */
300 p = cpl_parameter_new_value(
301 "cr2res.cr2res_obs_nodding.subtract_nolight_rows",
302 CPL_TYPE_BOOL,
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);
308
309 p = cpl_parameter_new_value(
310 "cr2res.cr2res_obs_nodding.subtract_interorder_column",
311 CPL_TYPE_BOOL,
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);
318
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);
325
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);
332
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);
339
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);
345
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);
351
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);
358
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);
365
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);
372
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);
379
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);
386
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);
393
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);
400
401 return 0;
402}
403
404/*----------------------------------------------------------------------------*/
410/*----------------------------------------------------------------------------*/
411static int cr2res_obs_nodding_exec(cpl_plugin * plugin)
412{
413 cpl_recipe *recipe;
414
415 /* Get the recipe out of the plugin */
416 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
417 recipe = (cpl_recipe *)plugin;
418 else return -1;
419
420 return cr2res_obs_nodding(recipe->frames, recipe->parameters);
421}
422
423/*----------------------------------------------------------------------------*/
429/*----------------------------------------------------------------------------*/
430static int cr2res_obs_nodding_destroy(cpl_plugin * plugin)
431{
432 cpl_recipe *recipe;
433
434 /* Get the recipe out of the plugin */
435 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
436 recipe = (cpl_recipe *)plugin;
437 else return -1 ;
438
439 cpl_parameterlist_delete(recipe->parameters);
440 return 0 ;
441}
442
443/*----------------------------------------------------------------------------*/
450/*----------------------------------------------------------------------------*/
451static int cr2res_obs_nodding(
452 cpl_frameset * frameset,
453 const cpl_parameterlist * parlist)
454{
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;
462 double dit, gain;
463 double ra, dec, mjd_obs, mjd_cen, geolon, geolat, geoelev,
464 barycorr;
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 ;
474 cpl_size * labels ;
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] ;
492 char * cur_setting ;
493 char * out_file;
494 cpl_table * eop_table ;
495 int det_nr, type;
496
497 /* Initialise */
498 gain = 0.0 ;
499 barycorr = 0.0;
500
501 /* RETRIEVE INPUT PARAMETERS */
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);
544
545 /* TODO, make parameters, maybe */
546 int extract_niter = 30;
547 double extract_kappa = 10;
548
549 /* Identify the RAW and CALIB frames in the input frameset */
550 if (cr2res_dfs_set_groups(frameset)) {
551 cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
552 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
553 return -1 ;
554 }
555
556 /* Get Calibration frames */
557 trace_wave_frame = cr2res_io_find_TRACE_WAVE(frameset) ;
558 if (trace_wave_frame == NULL) {
559 cpl_msg_error(__func__, "Could not find TRACE_WAVE frame") ;
560 return -1 ;
561 }
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") ;
569 }
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) ;
576 bpm_frame = cr2res_io_find_BPM(frameset) ;
577
578 /* Get the RAW Frames */
579 rawframes = cr2res_obs_nodding_find_RAW(frameset, &type) ;
580 if (rawframes == NULL) {
581 cpl_msg_error(__func__, "Could not find RAW frames") ;
582 return -1 ;
583 }
584
585 /* Get the RAW flat frames */
586 raw_flat_frames = cr2res_extract_frameset(frameset, CR2RES_FLAT_RAW) ;
587
588 /* Label the raw frames with the different angles */
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) ;
595 return -1 ;
596 }
597
598 /* Check the number of angles */
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) ;
603 cpl_free(labels) ;
604 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
605 return -1 ;
606 }
607
608 /* Loop on the settings */
609 for (l = 0; l < (int)nlabels; l++) {
610 double drot_posang;
611 cpl_frameset *raw_one_angle;
612 cpl_propertylist *plist;
613 /* Get the frames for the current angle */
614 raw_one_angle = cpl_frameset_extract(rawframes, labels, (cpl_size)l) ;
615
616 /* Get the current angle */
617 plist = cpl_propertylist_load(cpl_frame_get_filename(
618 cpl_frameset_get_position(raw_one_angle, 0)), 0) ;
619 drot_posang = cr2res_pfits_get_drot_posang(plist) ;
620 cpl_propertylist_delete(plist) ;
621
622 cpl_msg_info(__func__, "Process Angle %g", drot_posang) ;
623 cpl_msg_indent_more() ;
624
625 /* Loop on the detectors */
626 for (det_nr = 1; det_nr <= CR2RES_NB_DETECTORS; det_nr++) {
627 /* Initialise */
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;
642
643 /* Compute only one detector */
644 if (reduce_det != 0 && det_nr != reduce_det)
645 continue;
646
647 cpl_msg_info(__func__, "Process Detector %d", det_nr);
648 cpl_msg_indent_more();
649
650 /* Call the reduction function */
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",
666 det_nr);
667 cpl_error_reset();
668 }
669 else if (type == 2) {
670 cpl_msg_info(
671 __func__,
672 "Sensitivity / Conversion / Throughput computation");
673 cpl_msg_indent_more();
674
675 /* Define the gain */
676 if (det_nr == 1)
677 gain = CR2RES_GAIN_CHIP1;
678 if (det_nr == 2)
679 gain = CR2RES_GAIN_CHIP2;
680 if (det_nr == 3)
681 gain = CR2RES_GAIN_CHIP3;
682
683 /* Get the RA and DEC observed */
684 plist = cpl_propertylist_load(
685 cpl_frame_get_filename(
686 cpl_frameset_get_position_const(raw_one_angle, 0)),
687 0);
688 ra = cr2res_pfits_get_ra(plist);
689 dec = cr2res_pfits_get_dec(plist);
690 dit = cr2res_pfits_get_dit(plist);
691 cur_setting = cpl_strdup(cr2res_pfits_get_wlen_id(plist));
692 cr2res_format_setting(cur_setting);
693 cpl_propertylist_delete(plist);
694 if (cpl_error_get_code()) {
695 cpl_msg_indent_less();
696 cpl_error_reset();
697 cpl_msg_warning(__func__, "Missing Header Informations");
698 }
699 else {
700 /* Compute the photometry */
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);
710 cpl_error_reset();
711 }
712 }
713 cpl_free(cur_setting);
714 cpl_msg_indent_less();
715 }
716 cpl_msg_indent_less();
717 }
718
719 /* Save Products */
720 if (nlabels == 1) product_name_addon = cpl_sprintf(".fits") ;
721 else product_name_addon = cpl_sprintf("_%g.fits",
722 drot_posang);
723
724 /* Add the photom QC to the std ones */
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]) ;
730 }
731 }
732
733 /* Add ESO.DRS.TMID in the Main Header */
734 qc_main = cpl_propertylist_new();
735 cpl_propertylist_append_double(qc_main,
736 CR2RES_HEADER_DRS_TMID,
737 cr2res_utils_get_center_mjd(raw_one_angle)) ;
738
739 /* Add barycentric correction */
740 eop_table = cr2res_io_get_eop_table() ;
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) ;
744
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") ;
751
752 cpl_propertylist_delete(plist) ;
753
754 barycorr = 0.0 ;
755 if (!cpl_error_get_code()) {
756 mjd_cen = cr2res_utils_get_center_mjd(raw_one_angle) ;
757 hdrl_barycorr_compute(ra, dec, eop_table, mjd_obs,
758 (mjd_cen-mjd_obs)*24*3600, geolon, geolat, geoelev,
759 0.0, 0.0, 0.0, 0.0, &barycorr);
760
761 cpl_msg_info(__func__, "Barycentric correction: %g m/s",
762 barycorr);
763 } else {
764 cpl_msg_info(__func__, "Cannot derive Barycentric correction");
765 cpl_error_reset() ;
766 }
767 cpl_table_delete(eop_table) ;
768 cpl_propertylist_append_double(qc_main, CR2RES_HEADER_DRS_BARYCORR,
769 barycorr);
770 }
771
772 /* Add QC NUMSAT */
773 cpl_propertylist_append_int(qc_main,
774 CR2RES_HEADER_QC_NUMSAT,
775 cr2res_qc_numsat(raw_one_angle)) ;
776
777 /* Save only the used RAW - fill raw_one_angle with CALIBS */
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)) ;
799
800 out_file = cpl_sprintf("%s_combinedA%s", RECIPE_STRING,
801 product_name_addon) ;
802 cr2res_io_save_COMBINED(out_file, frameset, raw_one_angle, parlist,
803 combineda, qc_main, ext_plist,
804 CR2RES_OBS_NODDING_COMBINEDA_PROCATG, RECIPE_STRING) ;
805 cpl_free(out_file);
806
807 char *qc_perdet_keywords[] = { CR2RES_HEADER_QC_SIGNAL,
808 CR2RES_HEADER_QC_STANDARD_FLUX,
809 CR2RES_HEADER_QC_SLITFWHM_MED };
810
811 char *qc_pertrace_keywords[] = { CR2RES_HEADER_QC_SNR_BASE,
812 CR2RES_HEADER_QC_SLITFWHM_ORDER_BASE };
813
814 int qc_perdet_size = sizeof(qc_perdet_keywords) / sizeof(char *);
815 int qc_pertrace_size = sizeof(qc_pertrace_keywords) / sizeof(char *);
816
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;
820
821 int qc_i;
822
823 for (qc_i=0; qc_i<qc_perdet_size ; qc_i++) {
824
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");
829
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);
833
834 cpl_free(qc_res_avg);
835 cpl_free(qc_res_rmsd);
836 }
837
838
839 int min_order = INT_MAX;
840 int max_order = INT_MIN;
841 int current_min, current_max;
842
843 for (qc_i = 0; qc_i < CR2RES_NB_DETECTORS; qc_i++) {
844 if (twa[qc_i] == NULL) {
845 continue;
846 }
847 current_min =
848 cpl_table_get_column_min(twa[qc_i], "Order");
849 if (cpl_error_get_code() != CPL_ERROR_NONE) {
850 continue;
851 }
852 if (current_min < min_order) {
853 min_order = current_min;
854 }
855
856 current_max =
857 cpl_table_get_column_max(twa[qc_i], "Order");
858 if (cpl_error_get_code() != CPL_ERROR_NONE) {
859 continue;
860 }
861 if (current_max > max_order) {
862 max_order = current_max;
863 }
864 }
865
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++) {
868
869 qc_ref = cpl_sprintf("%s%d", qc_pertrace_keywords[qc_i],
870 order_id);
871 qc_res_avg =
872 cpl_sprintf("%s%d %s", qc_pertrace_keywords[qc_i],
873 order_id, "AVG");
874 qc_res_rmsd =
875 cpl_sprintf("%s%d %s", qc_pertrace_keywords[qc_i],
876 order_id, "RMS");
877
878 cr2res_qc_calculate_mean_and_rmsd(qc_plists_ext, 1, qc_sizes_ext,
879 qc_ref, qc_main, qc_res_avg,
880 qc_res_rmsd);
881
882 cpl_free(qc_ref);
883 cpl_free(qc_res_avg);
884 cpl_free(qc_res_rmsd);
885 }
886 }
887
888 out_file = cpl_sprintf("%s_extractedA%s", RECIPE_STRING,
889 product_name_addon) ;
890 cr2res_io_save_EXTRACT_1D(out_file, frameset, raw_one_angle, parlist,
891 extracta, qc_main, ext_plist,
892 CR2RES_OBS_NODDING_EXTRACTA_PROCATG, RECIPE_STRING);
893 if (create_idp) {
894 cr2res_idp_save(out_file, frameset, raw_one_angle, parlist,
895 extracta, qc_main, ext_plist,
896 CR2RES_OBS_NODDING_EXTRACTA_IDP_PROCATG,
897 RECIPE_STRING);
898 }
899 cpl_free(out_file);
900
901 /* for (qc_i=0; qc_i<qc_perdet_size ; qc_i++) {
902
903 qc_res_avg = cpl_sprintf("%s %s",
904 qc_perdet_keywords[qc_i], "AVG");
905 qc_res_rmsd = cpl_sprintf("%s %s",
906 qc_perdet_keywords[qc_i], "RMS");
907
908 cpl_propertylist_erase(qc_main, qc_res_avg);
909 if(cpl_error_get_code() != CPL_ERROR_NONE) {
910 cpl_msg_debug(__func__, "Cannot erase %s", qc_perdet_keywords[qc_i]);
911 cpl_error_reset();
912 }
913
914 cpl_propertylist_erase(qc_main, qc_res_rmsd);
915 if(cpl_error_get_code() != CPL_ERROR_NONE) {
916 cpl_msg_debug(__func__, "Cannot erase %s", qc_perdet_keywords[qc_i]);
917 cpl_error_reset();
918 }
919
920
921 cpl_free(qc_res_avg);
922 cpl_free(qc_res_rmsd);
923 }
924 */
925 out_file = cpl_sprintf("%s_slitfuncA%s", RECIPE_STRING,
926 product_name_addon) ;
927 cr2res_io_save_SLIT_FUNC(out_file, frameset, raw_one_angle, parlist,
928 slitfunca, qc_main, ext_plist,
929 CR2RES_OBS_NODDING_SLITFUNCA_PROCATG, RECIPE_STRING) ;
930 cpl_free(out_file);
931
932 out_file = cpl_sprintf("%s_modelA%s", RECIPE_STRING,
933 product_name_addon) ;
934 cr2res_io_save_SLIT_MODEL(out_file, frameset, raw_one_angle, parlist,
935 modela, qc_main, ext_plist,
936 CR2RES_OBS_NODDING_SLITMODELA_PROCATG, RECIPE_STRING) ;
937 cpl_free(out_file);
938
939 out_file = cpl_sprintf("%s_trace_wave_A%s", RECIPE_STRING,
940 product_name_addon) ;
941 cr2res_io_save_TRACE_WAVE(out_file, frameset, raw_one_angle, parlist,
942 twa, qc_main, ext_plist, CR2RES_OBS_NODDING_TWA_PROCATG,
943 RECIPE_STRING) ;
944 cpl_free(out_file);
945
946 out_file = cpl_sprintf("%s_combinedB%s", RECIPE_STRING,
947 product_name_addon) ;
948 cr2res_io_save_COMBINED(out_file, frameset, raw_one_angle, parlist,
949 combinedb, qc_main, ext_plist,
950 CR2RES_OBS_NODDING_COMBINEDB_PROCATG, RECIPE_STRING) ;
951 cpl_free(out_file);
952
953 out_file = cpl_sprintf("%s_extractedB%s", RECIPE_STRING,
954 product_name_addon) ;
955 cr2res_io_save_EXTRACT_1D(out_file, frameset, raw_one_angle, parlist,
956 extractb, qc_main, ext_plist,
957 CR2RES_OBS_NODDING_EXTRACTB_PROCATG, RECIPE_STRING);
958 if (create_idp) {
959 cr2res_idp_save(out_file, frameset, raw_one_angle, parlist,
960 extractb, qc_main, ext_plist,
961 CR2RES_OBS_NODDING_EXTRACTB_IDP_PROCATG,
962 RECIPE_STRING);
963 }
964 cpl_free(out_file);
965
966 out_file = cpl_sprintf("%s_slitfuncB%s", RECIPE_STRING,
967 product_name_addon) ;
968 cr2res_io_save_SLIT_FUNC(out_file, frameset, raw_one_angle, parlist,
969 slitfuncb, qc_main, ext_plist,
970 CR2RES_OBS_NODDING_SLITFUNCB_PROCATG, RECIPE_STRING) ;
971 cpl_free(out_file);
972
973 out_file = cpl_sprintf("%s_modelB%s", RECIPE_STRING,
974 product_name_addon) ;
975 cr2res_io_save_SLIT_MODEL(out_file, frameset, raw_one_angle, parlist,
976 modelb, qc_main, ext_plist,
977 CR2RES_OBS_NODDING_SLITMODELB_PROCATG, RECIPE_STRING) ;
978 cpl_free(out_file);
979
980 out_file = cpl_sprintf("%s_trace_wave_B%s", RECIPE_STRING,
981 product_name_addon) ;
982 cr2res_io_save_TRACE_WAVE(out_file, frameset, raw_one_angle, parlist,
983 twb, qc_main, ext_plist, CR2RES_OBS_NODDING_TWB_PROCATG,
984 RECIPE_STRING) ;
985 cpl_free(out_file);
986
987 out_file = cpl_sprintf("%s_extracted_combined%s", RECIPE_STRING,
988 product_name_addon) ;
989 cr2res_io_save_EXTRACT_1D(out_file, frameset, raw_one_angle, parlist,
990 extractc, qc_main, ext_plist,
991 CR2RES_OBS_NODDING_EXTRACTC_PROCATG, RECIPE_STRING);
992 if (create_idp) {
993 cr2res_idp_save(out_file, frameset, raw_one_angle, parlist,
994 extractc, qc_main, ext_plist,
995 CR2RES_OBS_NODDING_EXTRACTC_IDP_PROCATG,
996 RECIPE_STRING);
997 }
998 cpl_free(out_file);
999
1000 if (type == 2) {
1001
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");
1004
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);
1008
1009 cpl_free(qc_res_avg);
1010 cpl_free(qc_res_rmsd);
1011
1012 out_file = cpl_sprintf("%s_throughput%s", RECIPE_STRING,
1013 product_name_addon) ;
1014 cr2res_io_save_THROUGHPUT(out_file, frameset, raw_one_angle,
1015 parlist, throughput, qc_main, ext_plist,
1016 CR2RES_OBS_NODDING_THROUGHPUT_PROCATG, RECIPE_STRING) ;
1017 cpl_free(out_file);
1018 }
1019 cpl_free(product_name_addon) ;
1020
1021 /* Free */
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)
1025 hdrl_image_delete(combineda[det_nr-1]) ;
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)
1031 hdrl_image_delete(modela[det_nr-1]) ;
1032 if (twa[det_nr-1] != NULL)
1033 cpl_table_delete(twa[det_nr-1]) ;
1034 if (combinedb[det_nr-1] != NULL)
1035 hdrl_image_delete(combinedb[det_nr-1]) ;
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)
1041 hdrl_image_delete(modelb[det_nr-1]) ;
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]) ;
1052 }
1053 cpl_frameset_delete(raw_one_angle) ;
1054 cpl_msg_indent_less() ;
1055 }
1056 cpl_free(labels);
1057 cpl_frameset_delete(rawframes) ;
1058 if (raw_flat_frames != NULL) cpl_frameset_delete(raw_flat_frames) ;
1059
1060 return (int)cpl_error_get_code();
1061}
1062
1063/*----------------------------------------------------------------------------*/
1100/*----------------------------------------------------------------------------*/
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,
1109 int nodding_invert,
1110 int subtract_nolight_rows,
1111 int subtract_interorder_column,
1112 int cosmics,
1113 int extract_oversample,
1114 int extract_swath_width,
1115 int extract_height,
1116 double extract_smooth_slit,
1117 double extract_smooth_spec,
1118 int extract_niter,
1119 double extract_kappa,
1120 int reduce_det,
1121 int disp_det,
1122 int disp_order_idx,
1123 int disp_trace,
1124 hdrl_image ** combineda,
1125 cpl_table ** extracta,
1126 cpl_table ** slitfunca,
1127 hdrl_image ** modela,
1128 cpl_table ** twa,
1129 hdrl_image ** combinedb,
1130 cpl_table ** extractb,
1131 cpl_table ** slitfuncb,
1132 hdrl_image ** modelb,
1133 cpl_table ** twb,
1134 cpl_table ** extractc,
1135 cpl_propertylist ** ext_plist)
1136{
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 ;
1148 cpl_vector * dits ;
1149 cpl_vector * ndits=NULL ;
1150 cpl_table * trace_wave ;
1151 // cpl_table * trace_wave_corrected ;
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 ;
1166 char * key_name ;
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 ;
1179 double * qc_snrs ;
1180 int nb_order_idx_values,
1181 order_zp, order_idx, order_idxp ;
1182
1183 /* Check Inputs */
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)
1190 return -1 ;
1191
1192 /* Get the Gain */
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 ;
1196 else {
1197 cpl_msg_error(__func__, "Failed to get the Gain value") ;
1198 return -1 ;
1199 }
1200
1201 /* Check raw frames consistency */
1202 if (cr2res_obs_nodding_check_inputs_validity(rawframes) != 1) {
1203 cpl_msg_error(__func__, "Invalid Inputs") ;
1204 return -1 ;
1205 }
1206
1207 /* Initialise */
1208 nframes = cpl_frameset_get_size(rawframes) ;
1209 first_fname = cpl_frame_get_filename(
1210 cpl_frameset_get_position_const(rawframes, 0)) ;
1211
1212 /* Get the order zeropoint */
1213 if ((plist = cpl_propertylist_load(cpl_frame_get_filename(trace_wave_frame),
1214 0)) == NULL) {
1215 cpl_msg_error(__func__, "Cannot read the ORDER_ZP from the input TW") ;
1216 return -1 ;
1217 }
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") ;
1222 cpl_error_reset() ;
1223 /* Negative Zerop to log the fact that it is missing */
1224 order_zp = -100 ;
1225 }
1226
1227 /* Get the Nodding positions */
1228 cpl_msg_info(__func__, "Get the Nodding positions") ;
1229 cpl_msg_indent_more() ;
1230 nod_positions = cr2res_nodding_read_positions(rawframes) ;
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)),
1235 cr2res_nodding_position_char(nod_positions[i])) ;
1236 }
1237 cpl_msg_indent_less() ;
1238
1239 /* Load the DITs if necessary */
1240 if (master_dark_frame != NULL) dits = cr2res_io_read_dits(rawframes) ;
1241 else dits = NULL ;
1242 if (cpl_msg_get_level() == CPL_MSG_DEBUG && dits != NULL)
1243 cpl_vector_dump(dits, stdout) ;
1244
1245 /*Load the NDITs */
1246 ndits = cr2res_io_read_ndits(rawframes);
1247 if (cpl_msg_get_level() == CPL_MSG_DEBUG && ndits != NULL)
1248 cpl_vector_dump(ndits, stdout) ;
1249
1250 /* Load image list */
1251 cpl_msg_info(__func__, "Load the image list") ;
1252 if ((in = cr2res_io_load_image_list_from_set(rawframes,
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) ;
1257 return -1 ;
1258 }
1259 if (hdrl_imagelist_get_size(in) != cpl_frameset_get_size(rawframes)) {
1260 cpl_msg_error(__func__, "Inconsistent number of loaded images") ;
1261 cpl_free(nod_positions) ;
1262 if (dits != NULL) cpl_vector_delete(dits) ;
1264 return -1 ;
1265 }
1266
1267 /* Calibrate the images */
1268 cpl_msg_info(__func__, "Apply the Calibrations") ;
1269 cpl_msg_indent_more() ;
1270 if ((in_calib = cr2res_calib_imagelist(in, reduce_det, 0,
1271 subtract_nolight_rows, subtract_interorder_column, cosmics,
1272 master_flat_frame, master_dark_frame, bpm_frame, detlin_frame, dits,
1273 ndits))==NULL) {
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) ;
1280 return -1 ;
1281 }
1283 if (dits != NULL) cpl_vector_delete(dits) ;
1284 cpl_msg_indent_less() ;
1285
1286 /* Split the image lists */
1287 cpl_msg_info(__func__, "Split the images in A and B lists") ;
1288 cpl_msg_indent_more() ;
1289 if (cr2res_combine_nodding_split(in_calib, nod_positions, &in_a,
1290 &in_b)) {
1291 cpl_msg_error(__func__, "Failed to split the nodding positions") ;
1292 cpl_msg_indent_less() ;
1293 cpl_free(nod_positions) ;
1294 hdrl_imagelist_delete(in_calib) ;
1295 cpl_vector_delete(ndits) ;
1296 return -1 ;
1297 }
1298
1299 /* error factor is gain * ndit *nexp */
1300 error_factor = gain * cpl_vector_get(ndits, 0) *
1302
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.");
1307 }
1308 cpl_vector_delete(ndits) ;
1309 cpl_free(nod_positions) ;
1310 hdrl_imagelist_delete(in_calib) ;
1311 cpl_msg_indent_less() ;
1312
1313 /* Check the sizes of A/B image lists */
1315 || hdrl_imagelist_get_size(in_a) == 0) {
1316 cpl_msg_error(__func__, "Inconsistent A / B number of images") ;
1317 hdrl_imagelist_delete(in_a) ;
1318 hdrl_imagelist_delete(in_b) ;
1319 return -1 ;
1320 }
1321
1322 /* Compute diff_a = in_a - in_b and diff_b = in_b - in_a */
1323 cpl_msg_info(__func__, "Compute difference image lists A-B and B-A") ;
1324 diff_a = hdrl_imagelist_duplicate(in_a) ;
1325 hdrl_imagelist_sub_imagelist(diff_a, in_b) ;
1326 diff_b = hdrl_imagelist_duplicate(in_b) ;
1327 hdrl_imagelist_sub_imagelist(diff_b, in_a) ;
1328 hdrl_imagelist_delete(in_a) ;
1329 hdrl_imagelist_delete(in_b) ;
1330
1331 /* Collapse A-B and B-A */
1332 cpl_msg_info(__func__, "Collapse image lists A-B and B-A") ;
1333 cpl_msg_indent_more() ;
1334 if (hdrl_imagelist_collapse_mean(diff_a, &collapsed_a, &contrib_a) !=
1335 CPL_ERROR_NONE) {
1336 cpl_msg_error(__func__, "Failed to Collapse A-B") ;
1337 hdrl_imagelist_delete(diff_a) ;
1338 hdrl_imagelist_delete(diff_b) ;
1339 cpl_msg_indent_less() ;
1340 return -1 ;
1341 }
1342 cpl_image_delete(contrib_a) ;
1343 hdrl_imagelist_delete(diff_a) ;
1344 if (hdrl_imagelist_collapse_mean(diff_b, &collapsed_b, &contrib_b) !=
1345 CPL_ERROR_NONE) {
1346 cpl_msg_error(__func__, "Failed to Collapse B-A") ;
1347 hdrl_imagelist_delete(diff_b) ;
1348 hdrl_image_delete(collapsed_a) ;
1349 cpl_msg_indent_less() ;
1350 return -1 ;
1351 }
1352 cpl_image_delete(contrib_b) ;
1353 hdrl_imagelist_delete(diff_b) ;
1354 cpl_msg_indent_less() ;
1355
1356 /* Load the trace wave */
1357 cpl_msg_info(__func__, "Load the TRACE WAVE") ;
1358 if ((trace_wave = cr2res_io_load_TRACE_WAVE(cpl_frame_get_filename(
1359 trace_wave_frame), reduce_det)) == NULL) {
1360 cpl_msg_error(__func__, "Failed to Load the traces file") ;
1361 hdrl_image_delete(collapsed_a) ;
1362 hdrl_image_delete(collapsed_b) ;
1363 return -1 ;
1364 }
1365
1366 /* Correct trace_wave with some provided raw flats */
1367 cpl_msg_warning(__func__, "TRACE ADJUST NOT YET IMPLEMENTED") ;
1368 /*if (raw_flat_frames != NULL) {
1369 cpl_msg_info(__func__, "Try to correct the reproducibility error") ;
1370 cpl_msg_indent_more() ;
1371 trace_wave_corrected = cr2res_trace_adjust(trace_wave, raw_flat_frames,
1372 reduce_det) ;
1373 if (trace_wave_corrected != NULL) {
1374 cpl_table_delete(trace_wave) ;
1375 trace_wave = trace_wave_corrected ;
1376 trace_wave_corrected = NULL ;
1377 }
1378 cpl_msg_indent_less() ;
1379 }*/
1380
1381 /* Compute the slit fractions for A and B positions extraction */
1382 cpl_msg_info(__func__, "Compute the slit fractions for A and B positions");
1383 cpl_msg_indent_more() ;
1384 /*
1385 The assumption is made here that :
1386 - The slit center is exactly in the middle of A and B positions
1387 - The nodthrow is the distance in arcseconds between A and B
1388 - The slit size is 10 arcseconds
1389 - The B position is above the A position (--nodding-invert=false)
1390 */
1391 slit_length = 10 ;
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() ;
1395 hdrl_image_delete(collapsed_a) ;
1396 hdrl_image_delete(collapsed_b) ;
1397 cpl_table_delete(trace_wave) ;
1398 return -1 ;
1399 }
1400 nod_throw = cr2res_pfits_get_nodthrow(plist) ;
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 ;
1411 } else {
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 ;
1418 }
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 ;
1428 } else {
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 ;
1435 }
1436 } else {
1437 cpl_msg_error(__func__, "NODTHROW > slit length (%g>%g)- abort",
1438 nod_throw, slit_length) ;
1439 cpl_msg_indent_less() ;
1440 hdrl_image_delete(collapsed_a) ;
1441 hdrl_image_delete(collapsed_b) ;
1442 cpl_table_delete(trace_wave) ;
1443 return -1 ;
1444 }
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) ;
1450
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) ;
1455
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() ;
1461
1462 /* Recompute the traces for the new slit fractions */
1463 cpl_msg_info(__func__, "Recompute the traces for the A slit fraction") ;
1464 if ((trace_wave_a = cr2res_trace_new_slit_fraction(trace_wave,
1465 slit_frac_a)) == NULL) {
1466 cpl_msg_error(__func__,
1467 "Failed to compute the traces for extraction of A") ;
1468 hdrl_image_delete(collapsed_a) ;
1469 hdrl_image_delete(collapsed_b) ;
1470 cpl_table_delete(trace_wave) ;
1471 cpl_array_delete(slit_frac_a) ;
1472 cpl_array_delete(slit_frac_b) ;
1473 return -1 ;
1474 }
1475 cpl_array_delete(slit_frac_a) ;
1476
1477 cpl_msg_info(__func__, "Recompute the traces for the B slit fraction") ;
1478 if ((trace_wave_b = cr2res_trace_new_slit_fraction(trace_wave,
1479 slit_frac_b)) == NULL) {
1480 cpl_msg_error(__func__,
1481 "Failed to compute the traces for extraction of B") ;
1482 hdrl_image_delete(collapsed_a) ;
1483 hdrl_image_delete(collapsed_b) ;
1484 cpl_table_delete(trace_wave) ;
1485 cpl_table_delete(trace_wave_a) ;
1486 cpl_array_delete(slit_frac_b) ;
1487 return -1 ;
1488 }
1489 cpl_array_delete(slit_frac_b) ;
1490
1491 /* Load Blaze */
1492 blaze_table = NULL ;
1493 blaze_norm = 0;
1494 if (blaze_frame != NULL) {
1495 cpl_msg_info(__func__, "Load the BLAZE") ;
1496 if ((blaze_table = cr2res_io_load_EXTRACT_1D(cpl_frame_get_filename(
1497 blaze_frame), reduce_det)) == NULL) {
1498 cpl_msg_error(__func__, "Failed to Load the Blaze file") ;
1499 hdrl_image_delete(collapsed_a) ;
1500 hdrl_image_delete(collapsed_b) ;
1501 cpl_table_delete(trace_wave) ;
1502 cpl_table_delete(trace_wave_a) ;
1503 cpl_table_delete(trace_wave_b) ;
1504 return -1 ;
1505 }
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);
1511 }
1512 else {
1513 blaze_norm = -1;
1514 cpl_msg_warning(__func__, "QC BLAZE NORM value not found, reverting to per trace normalization") ;
1515 }
1516 if(blaze_plist!=NULL){
1517 cpl_propertylist_delete(blaze_plist);
1518 }
1519 }
1520
1521 /* Execute the extraction */
1522 cpl_msg_info(__func__, "A position Spectra Extraction") ;
1523 cpl_msg_indent_more() ;
1524 if (cr2res_extract_traces(collapsed_a, trace_wave_a, NULL, blaze_table, blaze_norm, -1,
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() ;
1532 hdrl_image_delete(collapsed_a) ;
1533 hdrl_image_delete(collapsed_b) ;
1534 cpl_table_delete(trace_wave_a) ;
1535 cpl_table_delete(trace_wave_b) ;
1536 cpl_table_delete(trace_wave) ;
1537 return -1 ;
1538 }
1539 cpl_msg_indent_less() ;
1540
1541 cpl_msg_info(__func__, "B position Spectra Extraction") ;
1542 cpl_msg_indent_more() ;
1543 if (cr2res_extract_traces(collapsed_b, trace_wave_b, NULL, blaze_table, blaze_norm, -1,
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) ;
1553 hdrl_image_delete(model_master_a) ;
1554 hdrl_image_delete(collapsed_a) ;
1555 hdrl_image_delete(collapsed_b) ;
1556 cpl_table_delete(trace_wave_a) ;
1557 cpl_table_delete(trace_wave_b) ;
1558 cpl_table_delete(trace_wave) ;
1559 return -1 ;
1560 }
1561 cpl_msg_indent_less() ;
1562
1563 if (blaze_table != NULL) cpl_table_delete(blaze_table) ;
1564
1565 /* Combine both a and b extracted spectra together */
1566 cpl_msg_info(__func__, "A and B spectra combination") ;
1567 cpl_msg_indent_more() ;
1568 extracted_combined = cr2res_combine_extracted(extracted_a, extracted_b) ;
1569 cpl_msg_indent_less() ;
1570
1571 /* Get the Setting */
1572 plist = cpl_propertylist_load(first_fname, 0) ;
1573 cur_setting = cpl_strdup(cr2res_pfits_get_wlen_id(plist)) ;
1574 cr2res_format_setting(cur_setting) ;
1575 cpl_propertylist_delete(plist) ;
1576
1577 /* Store the extension header for product saving */
1578 plist = cpl_propertylist_load(first_fname,
1579 cr2res_io_get_ext_idx(first_fname, reduce_det, 1)) ;
1580
1581 /* QC - Signal and FWHM */
1582 cpl_msg_info(__func__, "QC parameters computation") ;
1583 qc_signal_a = cr2res_qc_obs_nodding_signal(extracted_a) ;
1584 qc_signal_b = cr2res_qc_obs_nodding_signal(extracted_b) ;
1585 cpl_propertylist_append_double(plist, CR2RES_HEADER_QC_SIGNAL,
1586 (qc_signal_a+qc_signal_b)/2.0) ;
1587
1588 /* QC STANDARD FLUX */
1589 qc_standard_flux_a =
1590 cr2res_qc_obs_nodding_standard_flux(extracted_a, cur_setting) ;
1591 qc_standard_flux_b =
1592 cr2res_qc_obs_nodding_standard_flux(extracted_b, cur_setting) ;
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) ;
1596
1597 /* QC - SNR on nodding A position */
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] ;
1602 order_idxp = cr2res_io_convert_order_idx_to_idxp(order_idx) ;
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) ;
1606 }
1607 cpl_free(order_idx_values) ;
1608 cpl_free(qc_snrs) ;
1609
1610 /* Get the order numbers from the TW rows */
1611 order_idx_values = cr2res_trace_get_order_idx_values(trace_wave,
1612 &nb_order_idx_values);
1613
1614 /* QC - SLIT FWHM */
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] ;
1619 order_idxp = cr2res_io_convert_order_idx_to_idxp(order_idx) ;
1620 qc_fwhm_a = cr2res_qc_obs_slit_psf(slit_func_a, order_idxp,
1621 extract_oversample);
1622 qc_fwhm_b = cr2res_qc_obs_slit_psf(slit_func_b, order_idxp,
1623 extract_oversample);
1624
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) ;
1631 }
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,
1636 qc_fwhm_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."
1644 , qc_fwhm_med);
1645 }
1646 cpl_array_delete(fwhm_a_array) ;
1647 cpl_array_delete(fwhm_b_array) ;
1648
1649 /* QC - Real Orders */
1650 if (order_zp > 0) {
1651 /* Compute the Real Order numbers and store them in QCs */
1652 for (i = 0; i < nb_order_idx_values; i++) {
1653 int order_real;
1654 order_idx = order_idx_values[i] ;
1655 order_idxp = cr2res_io_convert_order_idx_to_idxp(order_idx) ;
1656
1657 order_real = cr2res_order_idx_to_real(order_idx, order_zp) ;
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) ;
1661 }
1662 }
1663 cpl_table_delete(trace_wave) ;
1664 cpl_free(order_idx_values) ;
1665
1666 /* Return */
1667 *combineda = collapsed_a ;
1668 *extracta = extracted_a ;
1669 *slitfunca = slit_func_a ;
1670 *modela = model_master_a ;
1671 *twa = trace_wave_a ;
1672
1673 *combinedb = collapsed_b ;
1674 *extractb = extracted_b ;
1675 *slitfuncb = slit_func_b ;
1676 *modelb = model_master_b ;
1677 *twb = trace_wave_b ;
1678
1679 *extractc = extracted_combined ;
1680 *ext_plist = plist ;
1681
1682 return 0 ;
1683}
1684
1685/*----------------------------------------------------------------------------*/
1691/*----------------------------------------------------------------------------*/
1692static int cr2res_obs_nodding_check_inputs_validity(
1693 const cpl_frameset * rawframes)
1694{
1695 cpl_propertylist * plist ;
1696 cr2res_nodding_pos * nod_positions ;
1697 cpl_size nframes, i ;
1698 double nodthrow;
1699 int nb_a, nb_b ;
1700
1701 /* Check Inputs */
1702 if (rawframes == NULL) return -1 ;
1703
1704 /* Need even number of frames */
1705 nframes = cpl_frameset_get_size(rawframes) ;
1706 if (nframes % 2) {
1707 cpl_msg_error(__func__, "Require an even number of raw frames") ;
1708 return 0 ;
1709 }
1710
1711 /* Need same number of A and B positions */
1712 nb_a = nb_b = 0 ;
1713 nod_positions = cr2res_nodding_read_positions(rawframes) ;
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++ ;
1718 }
1719 cpl_free(nod_positions) ;
1720
1721 if (nb_a == 0 || nb_b == 0 || nb_a != nb_b) {
1722 cpl_msg_error(__func__, "Require as many A and B positions") ;
1723 return 0 ;
1724 }
1725
1726 /* Need the same nod throw in all frames */
1727 if ((plist = cpl_propertylist_load(cpl_frame_get_filename(
1728 cpl_frameset_get_position_const(rawframes, 0)),
1729 0)) == NULL) {
1730 return -1;
1731 }
1732 nodthrow = cr2res_pfits_get_nodthrow(plist);
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)),
1738 0)) == NULL) {
1739 return -1;
1740 }
1741 nodthrow_cur = cr2res_pfits_get_nodthrow(plist);
1742 cpl_propertylist_delete(plist) ;
1743
1744 if (fabs(nodthrow_cur-nodthrow) > 1e-3) {
1745 cpl_msg_error(__func__,
1746 "Require constant NOD THROW in the raw frames") ;
1747 return 0 ;
1748 }
1749 }
1750 return 1 ;
1751}
1752
1753/*----------------------------------------------------------------------------*/
1769/*----------------------------------------------------------------------------*/
1770static cpl_frameset * cr2res_obs_nodding_find_RAW(
1771 const cpl_frameset * in,
1772 int * type)
1773{
1774 cpl_frameset * out ;
1775
1776 /* Check entries */
1777 if (in == NULL) return NULL ;
1778
1779 out = cr2res_extract_frameset(in, CR2RES_OBS_NODDING_OTHER_RAW) ;
1780 if (out == NULL) {
1781 out = cr2res_extract_frameset(in, CR2RES_OBS_NODDING_JITTER_RAW) ;
1782 }
1783 if (out != NULL) {
1784 if (type != NULL) *type = 1 ;
1785 } else {
1786 out = cr2res_extract_frameset(in, CR2RES_CAL_NODDING_OTHER_RAW) ;
1787 if (out == NULL) {
1788 out = cr2res_extract_frameset(in, CR2RES_CAL_NODDING_JITTER_RAW) ;
1789 }
1790 if (out != NULL) {
1791 if (type != NULL) *type = 2 ;
1792 } else {
1793 out = cr2res_extract_frameset(in, CR2RES_OBS_ASTROMETRY_OTHER_RAW) ;
1794 if (out == NULL) {
1795 out = cr2res_extract_frameset(in,
1796 CR2RES_OBS_ASTROMETRY_JITTER_RAW) ;
1797 }
1798 if (out != NULL) {
1799 if (type != NULL) *type = 3 ;
1800 }
1801 }
1802 }
1803 if (out == NULL) {
1804 if (type != NULL) *type = 0 ;
1805 }
1806 return out ;
1807}
1808
1809/*----------------------------------------------------------------------------*/
1816/*----------------------------------------------------------------------------*/
1817static int cr2res_obs_nodding_astrometry_compare(
1818 const cpl_frame * frame1,
1819 const cpl_frame * frame2)
1820{
1821 int comparison ;
1822 cpl_propertylist * plist1 ;
1823 cpl_propertylist * plist2 ;
1824 double dval1, dval2 ;
1825
1826 /* Test entries */
1827 if (frame1==NULL || frame2==NULL) return -1 ;
1828
1829 /* Get property lists */
1830 if ((plist1=cpl_propertylist_load(cpl_frame_get_filename(frame1),0))==NULL){
1831 cpl_msg_error(__func__, "getting header from reference frame");
1832 return -1 ;
1833 }
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) ;
1837 return -1 ;
1838 }
1839
1840 /* Test status */
1841 if (cpl_error_get_code()) {
1842 cpl_propertylist_delete(plist1) ;
1843 cpl_propertylist_delete(plist2) ;
1844 return -1 ;
1845 }
1846
1847 comparison = 1 ;
1848
1849 /* Compare the DROT angle used */
1850 dval1 = cr2res_pfits_get_drot_posang(plist1) ;
1851 dval2 = cr2res_pfits_get_drot_posang(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) ;
1856 return -1 ;
1857 }
1858 if (fabs(dval1-dval2) > 1e-3) comparison = 0 ;
1859
1860 cpl_propertylist_delete(plist1) ;
1861 cpl_propertylist_delete(plist2) ;
1862 return comparison ;
1863}
1864
1865
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.
Definition: cr2res_calib.c:71
cpl_error_code cr2res_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: cr2res_dfs.c:53
int cr2res_extract_traces(const hdrl_image *img, const cpl_table *traces, const cpl_table *slit_func_in, const cpl_table *blaze_table_in, float blaze_norm, int reduce_order, int reduce_trace, cr2res_extr_method extr_method, int extr_height, int swath_width, int oversample, double smooth_slit, double smooth_spec, int niter, double kappa, double error_factor, int display, int disp_order_idx, int disp_trace, cpl_table **extracted, cpl_table **slit_func, hdrl_image **model_master)
Extracts all the passed traces at once.
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.
Definition: cr2res_idp.c:82
cpl_table * cr2res_io_load_EXTRACT_1D(const char *filename, int detector)
Load a table from a EXTRACT_1D.
Definition: cr2res_io.c:1296
const cpl_frame * cr2res_io_find_BPM(const cpl_frameset *in)
Get the first CR2RES_BPM_DRSTYPE frame from a frameset.
Definition: cr2res_io.c:369
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.
Definition: cr2res_io.c:1823
const cpl_frame * cr2res_io_find_TRACE_WAVE(const cpl_frameset *in)
Get the first CR2RES_TW_DRSTYPE frame from a frameset.
Definition: cr2res_io.c:231
int cr2res_io_convert_order_idx_to_idxp(int order_idx)
Convert the order_idx to the order_idxp.
Definition: cr2res_io.c:583
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.
Definition: cr2res_io.c:1670
cpl_vector * cr2res_io_read_dits(const cpl_frameset *in)
Get the DITS from a frame set.
Definition: cr2res_io.c:432
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.
Definition: cr2res_io.c:1732
hdrl_imagelist * cr2res_io_load_image_list_from_set(const cpl_frameset *in, int detector)
Load an hdrl image list from an images frameset.
Definition: cr2res_io.c:808
cpl_table * cr2res_io_get_eop_table()
Get the eop_table.
Definition: cr2res_io.c:120
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.
Definition: cr2res_io.c:1762
int cr2res_io_get_ext_idx(const char *filename, int detector, int data)
Get the wished extension number for a detector.
Definition: cr2res_io.c:644
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.
Definition: cr2res_io.c:1792
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.
Definition: cr2res_io.c:1854
cpl_table * cr2res_io_load_TRACE_WAVE(const char *filename, int detector)
Load a table from a TRACE_WAVE.
Definition: cr2res_io.c:1109
cpl_vector * cr2res_io_read_ndits(const cpl_frameset *in)
Get the NDITs from a frame set.
Definition: cr2res_io.c:462
const char * cr2res_pfits_get_wlen_id(const cpl_propertylist *plist)
find out the Setting
Definition: cr2res_pfits.c:137
double cr2res_pfits_get_dit(const cpl_propertylist *plist)
find out the DIT value
Definition: cr2res_pfits.c:199
double cr2res_pfits_get_dec(const cpl_propertylist *plist)
find out the DEC
Definition: cr2res_pfits.c:150
double cr2res_pfits_get_drot_posang(const cpl_propertylist *plist)
find out the DROT POSANG value
Definition: cr2res_pfits.c:174
double cr2res_pfits_get_nodthrow(const cpl_propertylist *plist)
find out the NODTHROW value
Definition: cr2res_pfits.c:186
double cr2res_pfits_get_ra(const cpl_propertylist *plist)
find out the RA
Definition: cr2res_pfits.c:162
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.
Definition: cr2res_qc.c:1183
double cr2res_qc_obs_nodding_signal(const cpl_table *extracted)
Computes the integrated flux over part of the spectrum.
Definition: cr2res_qc.c:845
double cr2res_qc_obs_nodding_standard_flux(const cpl_table *extracted, char *setting)
Computes the standard flux over part of the spectrum.
Definition: cr2res_qc.c:892
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.
Definition: cr2res_qc.c:1010
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.
Definition: cr2res_qc.c:1101
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.
Definition: cr2res_trace.c:431
int cr2res_format_setting(char *setting_id)
Format the setting.
Definition: cr2res_utils.c:152
int cr2res_order_idx_to_real(int order_idx, int order_zp)
Convert the order_idx into order_real.
Definition: cr2res_utils.c:89
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.
Definition: cr2res_utils.c:278
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
Definition: hdrl_image.c:379
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.