CR2RE Pipeline Reference Manual 1.6.7
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 error_method,
81 int extract_oversample,
82 int extract_swath_width,
83 int extract_height,
84 double extract_smooth_slit,
85 double extract_smooth_spec,
86 int extract_niter,
87 double extract_kappa,
88 int reduce_det,
89 int disp_det,
90 int disp_order_idx,
91 int disp_trace,
92 hdrl_image ** combineda,
93 cpl_table ** extracta,
94 cpl_table ** slitfunca,
95 hdrl_image ** modela,
96 cpl_table ** twa,
97 hdrl_image ** combinedb,
98 cpl_table ** extractb,
99 cpl_table ** slitfuncb,
100 hdrl_image ** modelb,
101 cpl_table ** twb,
102 cpl_table ** extractc,
103 cpl_propertylist ** ext_plist) ;
104
105static int cr2res_obs_nodding_create(cpl_plugin *);
106static int cr2res_obs_nodding_exec(cpl_plugin *);
107static int cr2res_obs_nodding_destroy(cpl_plugin *);
108static int cr2res_obs_nodding(cpl_frameset *, const cpl_parameterlist *);
109
110/*-----------------------------------------------------------------------------
111 Static variables
112 -----------------------------------------------------------------------------*/
113
114static char cr2res_obs_nodding_description[] = "\
115Nodding Observation \n\
116 This recipe handles nodding observations. It expects an even number \n\
117 of rawframes in input, and as many A positions as B positions \n\
118 If the input are standard stars, it computes a post processing step \n\
119 to determine the throughput. \n\
120 If the input are spectro astrometric data, it will apply the nodding \n\
121 on each of the sub-groups \n\
122 \n\
123 Inputs \n\
124 raw.fits " CR2RES_CAL_NODDING_OTHER_RAW" [2 to 2n] \n\
125 or " CR2RES_CAL_NODDING_JITTER_RAW" [2 to 2n] \n\
126 or " CR2RES_OBS_NODDING_OTHER_RAW" [2 to 2n] \n\
127 or " CR2RES_OBS_NODDING_JITTER_RAW" [2 to 2n] \n\
128 or " CR2RES_OBS_ASTROMETRY_OTHER_RAW" [2 to 2n] \n\
129 or " CR2RES_OBS_ASTROMETRY_JITTER_RAW" [2 to 2n] \n\
130 trace.fits " CR2RES_CAL_FLAT_TW_PROCATG " [1] \n\
131 or " CR2RES_CAL_FLAT_TW_MERGED_PROCATG " \n\
132 or " CR2RES_UTIL_TRACE_TW_PROCATG " \n\
133 or " CR2RES_UTIL_WAVE_TW_PROCATG " \n\
134 or " CR2RES_CAL_WAVE_TW_PROCATG " \n\
135 or " CR2RES_UTIL_SLIT_CURV_TW_PROCATG " \n\
136 detlin.fits " CR2RES_CAL_DETLIN_COEFFS_PROCATG " [0 to 1] \n\
137 bpm.fits " CR2RES_CAL_DARK_BPM_PROCATG " [0 to 1] \n\
138 or " CR2RES_CAL_FLAT_BPM_PROCATG " \n\
139 or " CR2RES_CAL_DETLIN_BPM_PROCATG " \n\
140 or " CR2RES_UTIL_BPM_MERGE_PROCATG " \n\
141 or " CR2RES_UTIL_BPM_SPLIT_PROCATG " \n\
142 master_dark.fits " CR2RES_CAL_DARK_MASTER_PROCATG " [0 to 1] \n\
143 master_flat.fits " CR2RES_CAL_FLAT_MASTER_PROCATG " [0 to 1] \n\
144 photo_flux.fits " CR2RES_PHOTO_FLUX_PROCATG " [0 to 1] \n\
145 blaze.fits " CR2RES_CAL_FLAT_EXTRACT_1D_PROCATG " [0 to 1] \n\
146 \n\
147 Outputs \n\
148 cr2res_obs_nodding_extractedA.fits "
149 CR2RES_OBS_NODDING_EXTRACTA_PROCATG "\n\
150 cr2res_obs_nodding_extractedB.fits "
151 CR2RES_OBS_NODDING_EXTRACTB_PROCATG "\n\
152 cr2res_obs_nodding_combinedA.fits "
153 CR2RES_OBS_NODDING_COMBINEDA_PROCATG "\n\
154 cr2res_obs_nodding_combinedB.fits "
155 CR2RES_OBS_NODDING_COMBINEDB_PROCATG "\n\
156 cr2res_obs_nodding_trace_wave_A.fits "
157 CR2RES_OBS_NODDING_TWA_PROCATG "\n\
158 cr2res_obs_nodding_trace_wave_B.fits "
159 CR2RES_OBS_NODDING_TWB_PROCATG "\n\
160 cr2res_obs_nodding_modelA.fits "
161 CR2RES_OBS_NODDING_SLITMODELA_PROCATG "\n\
162 cr2res_obs_nodding_modelB.fits "
163 CR2RES_OBS_NODDING_SLITMODELB_PROCATG "\n\
164 cr2res_obs_nodding_slitfuncA.fits "
165 CR2RES_OBS_NODDING_SLITFUNCA_PROCATG "\n\
166 cr2res_obs_nodding_slitfuncB.fits "
167 CR2RES_OBS_NODDING_SLITFUNCB_PROCATG "\n\
168 cr2res_obs_nodding_throughput.fits "
169 CR2RES_OBS_NODDING_THROUGHPUT_PROCATG "\n\
170 \n\
171 Algorithm \n\
172 loop on detectors d: \n\
173 call cr2res_obs_nodding_reduce() \n\
174 -> combined[a|b](d) \n\
175 -> extract[a|b|c](d) \n\
176 -> slitfunc[a|b](d) \n\
177 -> model[a|b](d) \n\
178 -> tw[a|b](d) \n\
179 Save combineda and combinedb \n\
180 Save extracta, extractb, extractc \n\
181 Save slitfunca and slitfuncb \n\
182 Save modela and modelb \n\
183 Save throughput \n\
184 \n\
185 cr2res_obs_nodding_reduce() \n\
186 Load the input raw frames in an image list \n\
187 Apply the calibrations to the image list \n\
188 Split the list in listA and listB image lists \n\
189 Compute diffA=listA-listB and diffB=listB-listA \n\
190 Collapse diffA and diffB \n\
191 -> combined[a|b] \n\
192 Load the input trace wave \n\
193 Compute the slit fractions for A and B by using the nodthrow \n\
194 and the assumption that A and B are at equal distances \n\
195 from the slit center. \n\
196 Compute 2 new trace_wave files with these 2 computed slit fractions\n\
197 Extract the spectra for A and for B \n\
198 -> extracted[a|b] \n\
199 -> slit_func[a|b] \n\
200 -> model_master[a|b] \n\
201 -> trace_wave[a|b] \n\
202 Compute QC parameters \n\
203 If STD star, compute the throughput \n\
204 -> throughput \n\
205 \n\
206 Library functions used \n\
207 cr2res_io_find_TRACE_WAVE() \n\
208 cr2res_io_find_BPM() \n\
209 cr2res_obs_nodding_reduce() \n\
210 cr2res_nodding_read_positions() \n\
211 cr2res_io_read_dits() \n\
212 cr2res_io_load_image_list_from_set() \n\
213 cr2res_calib_imagelist() \n\
214 cr2res_combine_nodding_split() \n\
215 cr2res_io_load_TRACE_WAVE() \n\
216 cr2res_pfits_get_nodthrow() \n\
217 cr2res_trace_new_slit_fraction() \n\
218 cr2res_extract_traces() \n\
219 cr2res_qc_obs_nodding_signal() \n\
220 cr2res_qc_obs_nodding_transmission() \n\
221 cr2res_qc_obs_slit_psf() \n\
222 cr2res_photom_engine() \n\
223 cr2res_io_save_COMBINED() \n\
224 cr2res_io_save_EXTRACT_1D() \n\
225 cr2res_io_save_SLIT_FUNC() \n\
226 cr2res_io_save_SLIT_MODEL() \n\
227 cr2res_io_save_THROUGHPUT() \n\
228";
229
230
231/*-----------------------------------------------------------------------------
232 Function code
233 -----------------------------------------------------------------------------*/
234
235/*----------------------------------------------------------------------------*/
245/*----------------------------------------------------------------------------*/
246int cpl_plugin_get_info(cpl_pluginlist * list)
247{
248 cpl_recipe * recipe = cpl_calloc(1, sizeof *recipe );
249 cpl_plugin * plugin = &recipe->interface;
250
251 if (cpl_plugin_init(plugin,
252 CPL_PLUGIN_API,
253 CR2RES_BINARY_VERSION,
254 CPL_PLUGIN_TYPE_RECIPE,
255 RECIPE_STRING,
256 "Nodding Observation recipe",
257 cr2res_obs_nodding_description,
258 CR2RES_PIPELINE_AUTHORS,
259 PACKAGE_BUGREPORT,
261 cr2res_obs_nodding_create,
262 cr2res_obs_nodding_exec,
263 cr2res_obs_nodding_destroy)) {
264 cpl_msg_error(cpl_func, "Plugin initialization failed");
265 (void)cpl_error_set_where(cpl_func);
266 return 1;
267 }
268
269 if (cpl_pluginlist_append(list, plugin)) {
270 cpl_msg_error(cpl_func, "Error adding plugin to list");
271 (void)cpl_error_set_where(cpl_func);
272 return 1;
273 }
274
275 return 0;
276}
277
278/*----------------------------------------------------------------------------*/
286/*----------------------------------------------------------------------------*/
287static int cr2res_obs_nodding_create(cpl_plugin * plugin)
288{
289 cpl_recipe * recipe ;
290 cpl_parameter * p ;
291
292 /* Check that the plugin is part of a valid recipe */
293 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
294 recipe = (cpl_recipe *)plugin;
295 else
296 return -1;
297
298 /* Create the parameters list in the cpl_recipe object */
299 recipe->parameters = cpl_parameterlist_new();
300
301 /* Fill the parameters list */
302 p = cpl_parameter_new_value(
303 "cr2res.cr2res_obs_nodding.subtract_nolight_rows",
304 CPL_TYPE_BOOL,
305 "Subtract median row from baffled region at detector bottom",
306 "cr2res.cr2res_obs_nodding", FALSE);
307 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "subtract_nolight_rows");
308 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
309 cpl_parameterlist_append(recipe->parameters, p);
310
311 p = cpl_parameter_new_value(
312 "cr2res.cr2res_obs_nodding.subtract_interorder_column",
313 CPL_TYPE_BOOL,
314 "Subtract column-by-column fit to the pixel values between orders",
315 "cr2res.cr2res_obs_nodding", TRUE);
316 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
317 "subtract_interorder_column");
318 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
319 cpl_parameterlist_append(recipe->parameters, p);
320
321 p = cpl_parameter_new_value("cr2res.cr2res_obs_nodding.cosmics",
322 CPL_TYPE_BOOL, "Find and mark cosmic rays hits as bad",
323 "cr2res.cr2res_obs_nodding", FALSE);
324 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cosmics");
325 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
326 cpl_parameterlist_append(recipe->parameters, p);
327
328 p = cpl_parameter_new_enum("cr2res.cr2res_obs_nodding.error_method",
329 CPL_TYPE_STRING, "The 1d extraction error calculation method",
330 "cr2res.cr2res_obs_nodding",
331 "Poisson", 2, "Poisson", "Horne");
332 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "error_method");
333 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
334 cpl_parameterlist_append(recipe->parameters, p);
335
336 p = cpl_parameter_new_value("cr2res.cr2res_obs_nodding.nodding_invert",
337 CPL_TYPE_BOOL, "Flag to use when A is above B",
338 "cr2res.cr2res_obs_nodding", FALSE);
339 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nodding_invert");
340 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
341 cpl_parameterlist_append(recipe->parameters, p);
342
343 p = cpl_parameter_new_value("cr2res.cr2res_obs_nodding.extract_oversample",
344 CPL_TYPE_INT, "factor by which to oversample the extraction",
345 "cr2res.cr2res_obs_nodding", 7);
346 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extract_oversample");
347 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
348 cpl_parameterlist_append(recipe->parameters, p);
349
350 p = cpl_parameter_new_value("cr2res.cr2res_obs_nodding.extract_swath_width",
351 CPL_TYPE_INT, "The swath width", "cr2res.cr2res_obs_nodding", 2048);
352 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extract_swath_width");
353 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
354 cpl_parameterlist_append(recipe->parameters, p);
355
356 p = cpl_parameter_new_value("cr2res.cr2res_obs_nodding.extract_height",
357 CPL_TYPE_INT, "Extraction height", "cr2res.cr2res_obs_nodding", -1);
358 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extract_height");
359 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
360 cpl_parameterlist_append(recipe->parameters, p);
361
362 p = cpl_parameter_new_value("cr2res.cr2res_obs_nodding.extract_smooth_slit",
363 CPL_TYPE_DOUBLE, "Smoothing along the slit",
364 "cr2res.cr2res_obs_nodding", 1.0);
365 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extract_smooth_slit");
366 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
367 cpl_parameterlist_append(recipe->parameters, p);
368
369 p = cpl_parameter_new_value("cr2res.cr2res_obs_nodding.extract_smooth_spec",
370 CPL_TYPE_DOUBLE, "Smoothing along spectrum",
371 "cr2res.cr2res_obs_nodding", 8e-8);
372 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extract_smooth_spec");
373 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
374 cpl_parameterlist_append(recipe->parameters, p);
375
376 p = cpl_parameter_new_value("cr2res.cr2res_obs_nodding.detector",
377 CPL_TYPE_INT, "Only reduce the specified detector",
378 "cr2res.cr2res_obs_nodding", 0);
379 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "detector");
380 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
381 cpl_parameterlist_append(recipe->parameters, p);
382
383 p = cpl_parameter_new_value("cr2res.cr2res_obs_nodding.create_idp",
384 CPL_TYPE_BOOL, "Flag to produce IDP files",
385 "cr2res.cr2res_obs_nodding", FALSE);
386 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "idp");
387 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
388 cpl_parameterlist_append(recipe->parameters, p);
389
390 p = cpl_parameter_new_value("cr2res.cr2res_obs_nodding.display_detector",
391 CPL_TYPE_INT, "Apply the display for the specified detector",
392 "cr2res.cr2res_obs_nodding", 0);
393 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "display_detector");
394 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
395 cpl_parameterlist_append(recipe->parameters, p);
396
397 p = cpl_parameter_new_value("cr2res.cr2res_obs_nodding.display_order",
398 CPL_TYPE_INT, "Apply the display for the specified order",
399 "cr2res.cr2res_obs_nodding", 1000);
400 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "display_order");
401 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
402 cpl_parameterlist_append(recipe->parameters, p);
403
404 p = cpl_parameter_new_value("cr2res.cr2res_obs_nodding.display_trace",
405 CPL_TYPE_INT, "Apply the display for the specified trace",
406 "cr2res.cr2res_obs_nodding", 0);
407 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "display_trace");
408 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
409 cpl_parameterlist_append(recipe->parameters, p);
410
411 return 0;
412}
413
414/*----------------------------------------------------------------------------*/
420/*----------------------------------------------------------------------------*/
421static int cr2res_obs_nodding_exec(cpl_plugin * plugin)
422{
423 cpl_recipe *recipe;
424
425 /* Get the recipe out of the plugin */
426 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
427 recipe = (cpl_recipe *)plugin;
428 else return -1;
429
430 return cr2res_obs_nodding(recipe->frames, recipe->parameters);
431}
432
433/*----------------------------------------------------------------------------*/
439/*----------------------------------------------------------------------------*/
440static int cr2res_obs_nodding_destroy(cpl_plugin * plugin)
441{
442 cpl_recipe *recipe;
443
444 /* Get the recipe out of the plugin */
445 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
446 recipe = (cpl_recipe *)plugin;
447 else return -1 ;
448
449 cpl_parameterlist_delete(recipe->parameters);
450 return 0 ;
451}
452
453/*----------------------------------------------------------------------------*/
460/*----------------------------------------------------------------------------*/
461static int cr2res_obs_nodding(
462 cpl_frameset * frameset,
463 const cpl_parameterlist * parlist)
464{
465 const cpl_parameter * param ;
466 int extract_oversample, extract_swath_width,
467 extract_height, reduce_det,
468 disp_order_idx, disp_trace, disp_det,
469 nodding_invert, create_idp, subtract_nolight_rows,
470 subtract_interorder_column, cosmics,
471 error_method;
472 double extract_smooth_slit, extract_smooth_spec;
473 double dit, gain;
474 double ra, dec, mjd_obs, mjd_cen, geolon, geolat, geoelev,
475 barycorr;
476 cpl_frameset * rawframes ;
477 cpl_frameset * raw_flat_frames ;
478 const cpl_frame * trace_wave_frame ;
479 const cpl_frame * detlin_frame ;
480 const cpl_frame * master_dark_frame ;
481 const cpl_frame * photo_flux_frame ;
482 const cpl_frame * blaze_frame ;
483 const cpl_frame * master_flat_frame ;
484 const cpl_frame * bpm_frame ;
485 cpl_size * labels ;
486 cpl_size nlabels, l ;
487 char * product_name_addon ;
488 hdrl_image * combineda[CR2RES_NB_DETECTORS] ;
489 cpl_table * extracta[CR2RES_NB_DETECTORS] ;
490 cpl_table * slitfunca[CR2RES_NB_DETECTORS] ;
491 hdrl_image * modela[CR2RES_NB_DETECTORS] ;
492 cpl_table * twa[CR2RES_NB_DETECTORS] ;
493 hdrl_image * combinedb[CR2RES_NB_DETECTORS] ;
494 cpl_table * extractb[CR2RES_NB_DETECTORS] ;
495 cpl_table * slitfuncb[CR2RES_NB_DETECTORS] ;
496 hdrl_image * modelb[CR2RES_NB_DETECTORS] ;
497 cpl_table * twb[CR2RES_NB_DETECTORS] ;
498 cpl_table * extractc[CR2RES_NB_DETECTORS] ;
499 cpl_table * throughput[CR2RES_NB_DETECTORS] ;
500 cpl_propertylist * qc_main ;
501 cpl_propertylist * ext_plist[CR2RES_NB_DETECTORS] ;
502 cpl_propertylist * ext_plist_photom[CR2RES_NB_DETECTORS] ;
503 char * cur_setting ;
504 char * out_file;
505 cpl_table * eop_table ;
506 int det_nr, type;
507
508 /* Initialise */
509 gain = 0.0 ;
510 barycorr = 0.0;
511
512 /* RETRIEVE INPUT PARAMETERS */
513 param = cpl_parameterlist_find_const(parlist,
514 "cr2res.cr2res_obs_nodding.subtract_nolight_rows");
515 subtract_nolight_rows = cpl_parameter_get_bool(param);
516 param = cpl_parameterlist_find_const(parlist,
517 "cr2res.cr2res_obs_nodding.subtract_interorder_column");
518 subtract_interorder_column = cpl_parameter_get_bool(param);
519 param = cpl_parameterlist_find_const(parlist,
520 "cr2res.cr2res_obs_nodding.nodding_invert");
521 nodding_invert = cpl_parameter_get_bool(param);
522 param = cpl_parameterlist_find_const(parlist,
523 "cr2res.cr2res_obs_nodding.extract_oversample");
524 extract_oversample = cpl_parameter_get_int(param);
525 param = cpl_parameterlist_find_const(parlist,
526 "cr2res.cr2res_obs_nodding.extract_swath_width");
527 extract_swath_width = cpl_parameter_get_int(param);
528 param = cpl_parameterlist_find_const(parlist,
529 "cr2res.cr2res_obs_nodding.extract_height");
530 extract_height = cpl_parameter_get_int(param);
531 param = cpl_parameterlist_find_const(parlist,
532 "cr2res.cr2res_obs_nodding.extract_smooth_slit");
533 extract_smooth_slit = cpl_parameter_get_double(param);
534 param = cpl_parameterlist_find_const(parlist,
535 "cr2res.cr2res_obs_nodding.extract_smooth_spec");
536 extract_smooth_spec = cpl_parameter_get_double(param);
537 param = cpl_parameterlist_find_const(parlist,
538 "cr2res.cr2res_obs_nodding.detector");
539 reduce_det = cpl_parameter_get_int(param);
540 param = cpl_parameterlist_find_const(parlist,
541 "cr2res.cr2res_obs_nodding.create_idp");
542 create_idp = cpl_parameter_get_bool(param);
543 param = cpl_parameterlist_find_const(parlist,
544 "cr2res.cr2res_obs_nodding.display_detector");
545 disp_det = cpl_parameter_get_int(param);
546 param = cpl_parameterlist_find_const(parlist,
547 "cr2res.cr2res_obs_nodding.display_order");
548 disp_order_idx = cpl_parameter_get_int(param);
549 param = cpl_parameterlist_find_const(parlist,
550 "cr2res.cr2res_obs_nodding.display_trace");
551 disp_trace = cpl_parameter_get_int(param);
552 param = cpl_parameterlist_find_const(parlist,
553 "cr2res.cr2res_obs_nodding.cosmics");
554 cosmics = cpl_parameter_get_bool(param);
555 param = cpl_parameterlist_find_const(parlist,
556 "cr2res.cr2res_obs_nodding.error_method");
557 if(strcmp(cpl_parameter_get_string(param),"Horne") == 0)
558 error_method = CR2RES_EXTRACT_ERROR_HORNE;
559 else
560 error_method = CR2RES_EXTRACT_ERROR_POISSON;
561
562 /* TODO, make parameters, maybe */
563 int extract_niter = 30;
564 double extract_kappa = 10;
565
566 /* Identify the RAW and CALIB frames in the input frameset */
567 if (cr2res_dfs_set_groups(frameset)) {
568 cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
569 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
570 return -1 ;
571 }
572
573 /* Get Calibration frames */
574 trace_wave_frame = cr2res_io_find_TRACE_WAVE(frameset) ;
575 if (trace_wave_frame == NULL) {
576 cpl_msg_error(__func__, "Could not find TRACE_WAVE frame") ;
577 return -1 ;
578 }
579 detlin_frame = cpl_frameset_find_const(frameset,
580 CR2RES_CAL_DETLIN_COEFFS_PROCATG);
581 master_dark_frame = cpl_frameset_find_const(frameset,
582 CR2RES_CAL_DARK_MASTER_PROCATG) ;
583 if (master_dark_frame != NULL) {
584 cpl_msg_warning(__func__,
585 "Providing a MASTER DARK is not recommended for this recipe") ;
586 }
587 blaze_frame = cpl_frameset_find_const(frameset,
588 CR2RES_CAL_FLAT_EXTRACT_1D_PROCATG) ;
589 photo_flux_frame = cpl_frameset_find_const(frameset,
590 CR2RES_PHOTO_FLUX_PROCATG) ;
591 master_flat_frame = cpl_frameset_find_const(frameset,
592 CR2RES_CAL_FLAT_MASTER_PROCATG) ;
593 bpm_frame = cr2res_io_find_BPM(frameset) ;
594
595 /* Get the RAW Frames */
596 rawframes = cr2res_obs_nodding_find_RAW(frameset, &type) ;
597 if (rawframes == NULL) {
598 cpl_msg_error(__func__, "Could not find RAW frames") ;
599 return -1 ;
600 }
601
602 /* Get the RAW flat frames */
603 raw_flat_frames = cr2res_extract_frameset(frameset, CR2RES_FLAT_RAW) ;
604
605 /* Label the raw frames with the different angles */
606 if ((labels = cpl_frameset_labelise(rawframes,
607 cr2res_obs_nodding_astrometry_compare, &nlabels)) == NULL) {
608 cpl_msg_error(__func__, "Cannot label input frames") ;
609 cpl_frameset_delete(rawframes) ;
610 if (raw_flat_frames != NULL) cpl_frameset_delete(raw_flat_frames) ;
611 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
612 return -1 ;
613 }
614
615 /* Check the number of angles */
616 if (type != 3 && nlabels != 1) {
617 cpl_msg_error(__func__, "Expect only one DROT POSANG value - abort") ;
618 cpl_frameset_delete(rawframes) ;
619 if (raw_flat_frames != NULL) cpl_frameset_delete(raw_flat_frames) ;
620 cpl_free(labels) ;
621 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
622 return -1 ;
623 }
624
625 /* Loop on the settings */
626 for (l = 0; l < (int)nlabels; l++) {
627 double drot_posang;
628 cpl_frameset *raw_one_angle;
629 cpl_propertylist *plist;
630 /* Get the frames for the current angle */
631 raw_one_angle = cpl_frameset_extract(rawframes, labels, (cpl_size)l) ;
632
633 /* Get the current angle */
634 plist = cpl_propertylist_load(cpl_frame_get_filename(
635 cpl_frameset_get_position(raw_one_angle, 0)), 0) ;
636 drot_posang = cr2res_pfits_get_drot_posang(plist) ;
637 cpl_propertylist_delete(plist) ;
638
639 cpl_msg_info(__func__, "Process Angle %g", drot_posang) ;
640 cpl_msg_indent_more() ;
641
642 /* Loop on the detectors */
643 for (det_nr = 1; det_nr <= CR2RES_NB_DETECTORS; det_nr++) {
644 /* Initialise */
645 combineda[det_nr - 1] = NULL;
646 extracta[det_nr - 1] = NULL;
647 slitfunca[det_nr - 1] = NULL;
648 modela[det_nr - 1] = NULL;
649 twa[det_nr - 1] = NULL;
650 combinedb[det_nr - 1] = NULL;
651 extractb[det_nr - 1] = NULL;
652 slitfuncb[det_nr - 1] = NULL;
653 modelb[det_nr - 1] = NULL;
654 twb[det_nr - 1] = NULL;
655 extractc[det_nr - 1] = NULL;
656 ext_plist[det_nr - 1] = NULL;
657 ext_plist_photom[det_nr - 1] = NULL;
658 throughput[det_nr - 1] = NULL;
659
660 /* Compute only one detector */
661 if (reduce_det != 0 && det_nr != reduce_det)
662 continue;
663
664 cpl_msg_info(__func__, "Process Detector %d", det_nr);
665 cpl_msg_indent_more();
666
667 /* Call the reduction function */
668 if (cr2res_obs_nodding_reduce(
669 raw_one_angle, trace_wave_frame,
670 detlin_frame, master_dark_frame, master_flat_frame,
671 bpm_frame, blaze_frame, nodding_invert,
672 subtract_nolight_rows, subtract_interorder_column, cosmics,
673 error_method,
674 extract_oversample, extract_swath_width, extract_height,
675 extract_smooth_slit, extract_smooth_spec, extract_niter,
676 extract_kappa, det_nr, disp_det, disp_order_idx, disp_trace,
677 &(combineda[det_nr - 1]), &(extracta[det_nr - 1]),
678 &(slitfunca[det_nr - 1]), &(modela[det_nr - 1]),
679 &(twa[det_nr - 1]), &(combinedb[det_nr - 1]),
680 &(extractb[det_nr - 1]), &(slitfuncb[det_nr - 1]),
681 &(modelb[det_nr - 1]), &(twb[det_nr - 1]),
682 &(extractc[det_nr - 1]), &(ext_plist[det_nr - 1])) == -1) {
683 cpl_msg_warning(__func__, "Failed to reduce detector %d",
684 det_nr);
685 cpl_error_reset();
686 }
687 else if (type == 2) {
688 cpl_msg_info(
689 __func__,
690 "Sensitivity / Conversion / Throughput computation");
691 cpl_msg_indent_more();
692
693 /* Define the gain */
694 if (det_nr == 1)
695 gain = CR2RES_GAIN_CHIP1;
696 if (det_nr == 2)
697 gain = CR2RES_GAIN_CHIP2;
698 if (det_nr == 3)
699 gain = CR2RES_GAIN_CHIP3;
700
701 /* Get the RA and DEC observed */
702 plist = cpl_propertylist_load(
703 cpl_frame_get_filename(
704 cpl_frameset_get_position_const(raw_one_angle, 0)),
705 0);
706 ra = cr2res_pfits_get_ra(plist);
707 dec = cr2res_pfits_get_dec(plist);
708 dit = cr2res_pfits_get_dit(plist);
709 cur_setting = cpl_strdup(cr2res_pfits_get_wlen_id(plist));
710 cr2res_format_setting(cur_setting);
711 cpl_propertylist_delete(plist);
712 if (cpl_error_get_code()) {
713 cpl_msg_indent_less();
714 cpl_error_reset();
715 cpl_msg_warning(__func__, "Missing Header Informations");
716 }
717 else {
718 /* Compute the photometry */
720 extracta[det_nr - 1],
721 cpl_frame_get_filename(photo_flux_frame),
722 cur_setting, ra, dec, gain, dit, disp_det == det_nr,
723 disp_order_idx, disp_trace,
724 &(throughput[det_nr - 1]),
725 &(ext_plist_photom[det_nr - 1])) == -1) {
726 cpl_msg_warning(__func__,
727 "Failed to reduce detector %d", det_nr);
728 cpl_error_reset();
729 }
730 }
731 cpl_free(cur_setting);
732 cpl_msg_indent_less();
733 }
734 cpl_msg_indent_less();
735 }
736
737 /* Save Products */
738 if (nlabels == 1) product_name_addon = cpl_sprintf(".fits") ;
739 else product_name_addon = cpl_sprintf("_%g.fits",
740 drot_posang);
741
742 /* Add the photom QC to the std ones */
743 for (det_nr=1 ; det_nr<=CR2RES_NB_DETECTORS ; det_nr++) {
744 if (ext_plist_photom[det_nr-1] != NULL &&
745 ext_plist[det_nr-1] != NULL) {
746 cpl_propertylist_append(ext_plist[det_nr-1],
747 ext_plist_photom[det_nr-1]) ;
748 }
749 }
750
751 /* Add ESO.DRS.TMID in the Main Header */
752 qc_main = cpl_propertylist_new();
753 cpl_propertylist_append_double(qc_main,
754 CR2RES_HEADER_DRS_TMID,
755 cr2res_utils_get_center_mjd(raw_one_angle)) ;
756
757 /* Add barycentric correction */
758 eop_table = cr2res_io_get_eop_table() ;
759 if (eop_table != NULL) {
760 plist=cpl_propertylist_load(cpl_frame_get_filename(
761 cpl_frameset_get_position_const(raw_one_angle, 0)), 0) ;
762
763 ra = cpl_propertylist_get_double(plist, "RA") ;
764 dec = cpl_propertylist_get_double(plist, "DEC") ;
765 mjd_obs = cpl_propertylist_get_double(plist, "MJD-OBS") ;
766 geolon = cpl_propertylist_get_double(plist, "ESO TEL GEOLON") ;
767 geolat = cpl_propertylist_get_double(plist, "ESO TEL GEOLAT") ;
768 geoelev = cpl_propertylist_get_double(plist, "ESO TEL GEOELEV") ;
769
770 cpl_propertylist_delete(plist) ;
771
772 barycorr = 0.0 ;
773 if (!cpl_error_get_code()) {
774 mjd_cen = cr2res_utils_get_center_mjd(raw_one_angle) ;
775 hdrl_barycorr_compute(ra, dec, eop_table, mjd_obs,
776 (mjd_cen-mjd_obs)*24*3600, geolon, geolat, geoelev,
777 0.0, 0.0, 0.0, 0.0, &barycorr);
778
779 cpl_msg_info(__func__, "Barycentric correction: %g m/s",
780 barycorr);
781 } else {
782 cpl_msg_info(__func__, "Cannot derive Barycentric correction");
783 cpl_error_reset() ;
784 }
785 cpl_table_delete(eop_table) ;
786
787 }
788
789
790 if(error_method == CR2RES_EXTRACT_ERROR_HORNE){
791 cpl_propertylist_append_string(qc_main, CR2RES_HEADER_DRS_ERRMETHOD,
792 "Horne") ;
793 }
794 else {
795 cpl_propertylist_append_string(qc_main, CR2RES_HEADER_DRS_ERRMETHOD,
796 "Poisson") ;
797 }
798 /* Add QC NUMSAT */
799 cpl_propertylist_append_int(qc_main,
800 CR2RES_HEADER_QC_NUMSAT,
801 cr2res_qc_numsat(raw_one_angle)) ;
802
803
804 /* Save only the used RAW - fill raw_one_angle with CALIBS */
805 if (trace_wave_frame != NULL)
806 cpl_frameset_insert(raw_one_angle,
807 cpl_frame_duplicate(trace_wave_frame)) ;
808 if (detlin_frame != NULL)
809 cpl_frameset_insert(raw_one_angle,
810 cpl_frame_duplicate(detlin_frame)) ;
811 if (master_dark_frame != NULL)
812 cpl_frameset_insert(raw_one_angle,
813 cpl_frame_duplicate(master_dark_frame)) ;
814 if (master_flat_frame!= NULL)
815 cpl_frameset_insert(raw_one_angle,
816 cpl_frame_duplicate(master_flat_frame)) ;
817 if (bpm_frame!= NULL)
818 cpl_frameset_insert(raw_one_angle,
819 cpl_frame_duplicate(bpm_frame)) ;
820 if (blaze_frame!= NULL)
821 cpl_frameset_insert(raw_one_angle,
822 cpl_frame_duplicate(blaze_frame)) ;
823 if (photo_flux_frame!= NULL)
824 cpl_frameset_insert(raw_one_angle,
825 cpl_frame_duplicate(photo_flux_frame)) ;
826
827 out_file = cpl_sprintf("%s_combinedA%s", RECIPE_STRING,
828 product_name_addon) ;
829 cr2res_io_save_COMBINED(out_file, frameset, raw_one_angle, parlist,
830 combineda, qc_main, ext_plist,
831 CR2RES_OBS_NODDING_COMBINEDA_PROCATG, RECIPE_STRING) ;
832 cpl_free(out_file);
833
834 char *qc_perdet_keywords[] = { CR2RES_HEADER_QC_SIGNAL,
835 CR2RES_HEADER_QC_STANDARD_FLUX,
836 CR2RES_HEADER_QC_SLITFWHM_MED };
837
838 char *qc_pertrace_keywords[] = { CR2RES_HEADER_QC_SNR_BASE,
839 CR2RES_HEADER_QC_SLITFWHM_ORDER_BASE };
840
841 int qc_perdet_size = sizeof(qc_perdet_keywords) / sizeof(char *);
842 int qc_pertrace_size = sizeof(qc_pertrace_keywords) / sizeof(char *);
843
844 int qc_sizes_ext[] = {CR2RES_NB_DETECTORS};
845 cpl_propertylist** qc_plists_ext[] = {ext_plist} ;
846 char * qc_res_avg, * qc_res_rmsd, * qc_ref;
847
848 int qc_i;
849
850 for (qc_i=0; qc_i<qc_perdet_size ; qc_i++) {
851
852 qc_res_avg = cpl_sprintf("%s %s",
853 qc_perdet_keywords[qc_i], "AVG");
854 qc_res_rmsd = cpl_sprintf("%s %s",
855 qc_perdet_keywords[qc_i], "RMS");
856
857 cr2res_qc_calculate_mean_and_rmsd(qc_plists_ext, 1, qc_sizes_ext,
858 qc_perdet_keywords[qc_i], qc_main,
859 qc_res_avg, qc_res_rmsd);
860
861 cpl_free(qc_res_avg);
862 cpl_free(qc_res_rmsd);
863 }
864
865
866 int min_order = INT_MAX;
867 int max_order = INT_MIN;
868 int current_min, current_max;
869
870 for (qc_i = 0; qc_i < CR2RES_NB_DETECTORS; qc_i++) {
871 if (twa[qc_i] == NULL) {
872 continue;
873 }
874 current_min =
875 cpl_table_get_column_min(twa[qc_i], "Order");
876 if (cpl_error_get_code() != CPL_ERROR_NONE) {
877 continue;
878 }
879 if (current_min < min_order) {
880 min_order = current_min;
881 }
882
883 current_max =
884 cpl_table_get_column_max(twa[qc_i], "Order");
885 if (cpl_error_get_code() != CPL_ERROR_NONE) {
886 continue;
887 }
888 if (current_max > max_order) {
889 max_order = current_max;
890 }
891 }
892
893 for (qc_i = 0; qc_i < qc_pertrace_size; qc_i++) {
894 for (int order_id = min_order; order_id <= max_order; order_id++) {
895
896 qc_ref = cpl_sprintf("%s%d", qc_pertrace_keywords[qc_i],
897 order_id);
898 qc_res_avg =
899 cpl_sprintf("%s%d %s", qc_pertrace_keywords[qc_i],
900 order_id, "AVG");
901 qc_res_rmsd =
902 cpl_sprintf("%s%d %s", qc_pertrace_keywords[qc_i],
903 order_id, "RMS");
904
905 cr2res_qc_calculate_mean_and_rmsd(qc_plists_ext, 1, qc_sizes_ext,
906 qc_ref, qc_main, qc_res_avg,
907 qc_res_rmsd);
908
909 cpl_free(qc_ref);
910 cpl_free(qc_res_avg);
911 cpl_free(qc_res_rmsd);
912 }
913 }
914
915 out_file = cpl_sprintf("%s_extractedA%s", RECIPE_STRING,
916 product_name_addon) ;
917 cr2res_io_save_EXTRACT_1D(out_file, frameset, raw_one_angle, parlist,
918 extracta, qc_main, ext_plist,
919 CR2RES_OBS_NODDING_EXTRACTA_PROCATG, RECIPE_STRING);
920 if (create_idp) {
921 cr2res_idp_save(out_file, frameset, raw_one_angle, parlist,
922 extracta, qc_main, ext_plist,
923 CR2RES_OBS_NODDING_EXTRACTA_IDP_PROCATG,
924 RECIPE_STRING);
925 }
926 cpl_free(out_file);
927
928 /* for (qc_i=0; qc_i<qc_perdet_size ; qc_i++) {
929
930 qc_res_avg = cpl_sprintf("%s %s",
931 qc_perdet_keywords[qc_i], "AVG");
932 qc_res_rmsd = cpl_sprintf("%s %s",
933 qc_perdet_keywords[qc_i], "RMS");
934
935 cpl_propertylist_erase(qc_main, qc_res_avg);
936 if(cpl_error_get_code() != CPL_ERROR_NONE) {
937 cpl_msg_debug(__func__, "Cannot erase %s", qc_perdet_keywords[qc_i]);
938 cpl_error_reset();
939 }
940
941 cpl_propertylist_erase(qc_main, qc_res_rmsd);
942 if(cpl_error_get_code() != CPL_ERROR_NONE) {
943 cpl_msg_debug(__func__, "Cannot erase %s", qc_perdet_keywords[qc_i]);
944 cpl_error_reset();
945 }
946
947
948 cpl_free(qc_res_avg);
949 cpl_free(qc_res_rmsd);
950 }
951 */
952 out_file = cpl_sprintf("%s_slitfuncA%s", RECIPE_STRING,
953 product_name_addon) ;
954 cr2res_io_save_SLIT_FUNC(out_file, frameset, raw_one_angle, parlist,
955 slitfunca, qc_main, ext_plist,
956 CR2RES_OBS_NODDING_SLITFUNCA_PROCATG, RECIPE_STRING) ;
957 cpl_free(out_file);
958
959 out_file = cpl_sprintf("%s_modelA%s", RECIPE_STRING,
960 product_name_addon) ;
961 cr2res_io_save_SLIT_MODEL(out_file, frameset, raw_one_angle, parlist,
962 modela, qc_main, ext_plist,
963 CR2RES_OBS_NODDING_SLITMODELA_PROCATG, RECIPE_STRING) ;
964 cpl_free(out_file);
965
966 out_file = cpl_sprintf("%s_trace_wave_A%s", RECIPE_STRING,
967 product_name_addon) ;
968 cr2res_io_save_TRACE_WAVE(out_file, frameset, raw_one_angle, parlist,
969 twa, qc_main, ext_plist, CR2RES_OBS_NODDING_TWA_PROCATG,
970 RECIPE_STRING) ;
971 cpl_free(out_file);
972
973 out_file = cpl_sprintf("%s_combinedB%s", RECIPE_STRING,
974 product_name_addon) ;
975 cr2res_io_save_COMBINED(out_file, frameset, raw_one_angle, parlist,
976 combinedb, qc_main, ext_plist,
977 CR2RES_OBS_NODDING_COMBINEDB_PROCATG, RECIPE_STRING) ;
978 cpl_free(out_file);
979
980 out_file = cpl_sprintf("%s_extractedB%s", RECIPE_STRING,
981 product_name_addon) ;
982 cr2res_io_save_EXTRACT_1D(out_file, frameset, raw_one_angle, parlist,
983 extractb, qc_main, ext_plist,
984 CR2RES_OBS_NODDING_EXTRACTB_PROCATG, RECIPE_STRING);
985 if (create_idp) {
986 cr2res_idp_save(out_file, frameset, raw_one_angle, parlist,
987 extractb, qc_main, ext_plist,
988 CR2RES_OBS_NODDING_EXTRACTB_IDP_PROCATG,
989 RECIPE_STRING);
990 }
991 cpl_free(out_file);
992
993 out_file = cpl_sprintf("%s_slitfuncB%s", RECIPE_STRING,
994 product_name_addon) ;
995 cr2res_io_save_SLIT_FUNC(out_file, frameset, raw_one_angle, parlist,
996 slitfuncb, qc_main, ext_plist,
997 CR2RES_OBS_NODDING_SLITFUNCB_PROCATG, RECIPE_STRING) ;
998 cpl_free(out_file);
999
1000 out_file = cpl_sprintf("%s_modelB%s", RECIPE_STRING,
1001 product_name_addon) ;
1002 cr2res_io_save_SLIT_MODEL(out_file, frameset, raw_one_angle, parlist,
1003 modelb, qc_main, ext_plist,
1004 CR2RES_OBS_NODDING_SLITMODELB_PROCATG, RECIPE_STRING) ;
1005 cpl_free(out_file);
1006
1007 out_file = cpl_sprintf("%s_trace_wave_B%s", RECIPE_STRING,
1008 product_name_addon) ;
1009 cr2res_io_save_TRACE_WAVE(out_file, frameset, raw_one_angle, parlist,
1010 twb, qc_main, ext_plist, CR2RES_OBS_NODDING_TWB_PROCATG,
1011 RECIPE_STRING) ;
1012 cpl_free(out_file);
1013
1014 out_file = cpl_sprintf("%s_extracted_combined%s", RECIPE_STRING,
1015 product_name_addon) ;
1016 cr2res_io_save_EXTRACT_1D(out_file, frameset, raw_one_angle, parlist,
1017 extractc, qc_main, ext_plist,
1018 CR2RES_OBS_NODDING_EXTRACTC_PROCATG, RECIPE_STRING);
1019 if (create_idp) {
1020 cr2res_idp_save(out_file, frameset, raw_one_angle, parlist,
1021 extractc, qc_main, ext_plist,
1022 CR2RES_OBS_NODDING_EXTRACTC_IDP_PROCATG,
1023 RECIPE_STRING);
1024 }
1025 cpl_free(out_file);
1026
1027 if (type == 2) {
1028
1029 qc_res_avg = cpl_sprintf("%s %s", CR2RES_HEADER_QC_THROUGHPUT, "AVG");
1030 qc_res_rmsd = cpl_sprintf("%s %s", CR2RES_HEADER_QC_THROUGHPUT, "RMS");
1031
1032 cr2res_qc_calculate_mean_and_rmsd(qc_plists_ext, 1, qc_sizes_ext,
1033 CR2RES_HEADER_QC_THROUGHPUT, qc_main,
1034 qc_res_avg, qc_res_rmsd);
1035
1036 cpl_free(qc_res_avg);
1037 cpl_free(qc_res_rmsd);
1038
1039 out_file = cpl_sprintf("%s_throughput%s", RECIPE_STRING,
1040 product_name_addon) ;
1041 cr2res_io_save_THROUGHPUT(out_file, frameset, raw_one_angle,
1042 parlist, throughput, qc_main, ext_plist,
1043 CR2RES_OBS_NODDING_THROUGHPUT_PROCATG, RECIPE_STRING) ;
1044 cpl_free(out_file);
1045 }
1046 cpl_free(product_name_addon) ;
1047
1048 /* Free */
1049 cpl_propertylist_delete(qc_main) ;
1050 for (det_nr=1 ; det_nr<=CR2RES_NB_DETECTORS ; det_nr++) {
1051 if (combineda[det_nr-1] != NULL)
1052 hdrl_image_delete(combineda[det_nr-1]) ;
1053 if (extracta[det_nr-1] != NULL)
1054 cpl_table_delete(extracta[det_nr-1]) ;
1055 if (slitfunca[det_nr-1] != NULL)
1056 cpl_table_delete(slitfunca[det_nr-1]) ;
1057 if (modela[det_nr-1] != NULL)
1058 hdrl_image_delete(modela[det_nr-1]) ;
1059 if (twa[det_nr-1] != NULL)
1060 cpl_table_delete(twa[det_nr-1]) ;
1061 if (combinedb[det_nr-1] != NULL)
1062 hdrl_image_delete(combinedb[det_nr-1]) ;
1063 if (extractb[det_nr-1] != NULL)
1064 cpl_table_delete(extractb[det_nr-1]) ;
1065 if (slitfuncb[det_nr-1] != NULL)
1066 cpl_table_delete(slitfuncb[det_nr-1]) ;
1067 if (modelb[det_nr-1] != NULL)
1068 hdrl_image_delete(modelb[det_nr-1]) ;
1069 if (twb[det_nr-1] != NULL)
1070 cpl_table_delete(twb[det_nr-1]) ;
1071 if (extractc[det_nr-1] != NULL)
1072 cpl_table_delete(extractc[det_nr-1]) ;
1073 if (throughput[det_nr-1] != NULL)
1074 cpl_table_delete(throughput[det_nr-1]) ;
1075 if (ext_plist[det_nr-1] != NULL)
1076 cpl_propertylist_delete(ext_plist[det_nr-1]) ;
1077 if (ext_plist_photom[det_nr-1] != NULL)
1078 cpl_propertylist_delete(ext_plist_photom[det_nr-1]) ;
1079 }
1080 cpl_frameset_delete(raw_one_angle) ;
1081 cpl_msg_indent_less() ;
1082 }
1083 cpl_free(labels);
1084 cpl_frameset_delete(rawframes) ;
1085 if (raw_flat_frames != NULL) cpl_frameset_delete(raw_flat_frames) ;
1086
1087 return (int)cpl_error_get_code();
1088}
1089
1090/*----------------------------------------------------------------------------*/
1127/*----------------------------------------------------------------------------*/
1128static int cr2res_obs_nodding_reduce(
1129 const cpl_frameset * rawframes,
1130 const cpl_frame * trace_wave_frame,
1131 const cpl_frame * detlin_frame,
1132 const cpl_frame * master_dark_frame,
1133 const cpl_frame * master_flat_frame,
1134 const cpl_frame * bpm_frame,
1135 const cpl_frame * blaze_frame,
1136 int nodding_invert,
1137 int subtract_nolight_rows,
1138 int subtract_interorder_column,
1139 int cosmics,
1140 int error_method,
1141 int extract_oversample,
1142 int extract_swath_width,
1143 int extract_height,
1144 double extract_smooth_slit,
1145 double extract_smooth_spec,
1146 int extract_niter,
1147 double extract_kappa,
1148 int reduce_det,
1149 int disp_det,
1150 int disp_order_idx,
1151 int disp_trace,
1152 hdrl_image ** combineda,
1153 cpl_table ** extracta,
1154 cpl_table ** slitfunca,
1155 hdrl_image ** modela,
1156 cpl_table ** twa,
1157 hdrl_image ** combinedb,
1158 cpl_table ** extractb,
1159 cpl_table ** slitfuncb,
1160 hdrl_image ** modelb,
1161 cpl_table ** twb,
1162 cpl_table ** extractc,
1163 cpl_propertylist ** ext_plist)
1164{
1165 hdrl_imagelist * in ;
1166 hdrl_imagelist * in_calib ;
1167 hdrl_imagelist * in_a ;
1168 hdrl_imagelist * in_b ;
1169 hdrl_imagelist * diff_a ;
1170 hdrl_imagelist * diff_b ;
1171 hdrl_image * collapsed_a ;
1172 hdrl_image * collapsed_b ;
1173 cpl_image * contrib_a ;
1174 cpl_image * contrib_b ;
1175 cr2res_nodding_pos * nod_positions ;
1176 cpl_vector * dits ;
1177 cpl_vector * ndits=NULL ;
1178 cpl_table * trace_wave ;
1179 // cpl_table * trace_wave_corrected ;
1180 cpl_table * trace_wave_a ;
1181 cpl_table * trace_wave_b ;
1182 cpl_table * blaze_table ;
1183 cpl_array * slit_frac_a ;
1184 cpl_array * slit_frac_b ;
1185 cpl_table * extracted_a ;
1186 cpl_table * extracted_b ;
1187 cpl_table * extracted_combined ;
1188 cpl_table * slit_func_a ;
1189 cpl_table * slit_func_b ;
1190 hdrl_image * model_master_a ;
1191 hdrl_image * model_master_b ;
1192 cpl_propertylist * plist ;
1193 cpl_size nframes, i ;
1194 char * key_name ;
1195 const char * first_fname ;
1196 double slit_length, extr_width_frac, slit_frac_a_bot,
1197 slit_frac_a_mid, slit_frac_a_top, slit_frac_b_bot,
1198 slit_frac_b_mid, slit_frac_b_top, nod_throw,
1199 gain, error_factor ;
1200 double qc_signal_a, qc_signal_b, qc_fwhm_a,
1201 qc_fwhm_b, qc_standard_flux_a,
1202 qc_standard_flux_b, qc_fwhm_med, blaze_norm ;
1203 cpl_array * fwhm_a_array ;
1204 cpl_array * fwhm_b_array ;
1205 char * cur_setting ;
1206 int * order_idx_values ;
1207 double * qc_snrs ;
1208 double * qc_der_snrs ;
1209 int nb_order_idx_values,
1210 order_zp, order_idx, order_idxp ;
1211
1212 /* Check Inputs */
1213 if (combineda == NULL || combinedb == NULL ||
1214 twa == NULL || twb == NULL ||
1215 slitfunca == NULL || slitfuncb == NULL ||
1216 modela == NULL || modelb == NULL ||
1217 extracta == NULL || extractb == NULL || extractc == NULL ||
1218 ext_plist == NULL || rawframes == NULL || trace_wave_frame == NULL)
1219 return -1 ;
1220
1221 /* Get the Gain */
1222 if (reduce_det == 1) gain = CR2RES_GAIN_CHIP1 ;
1223 else if (reduce_det == 2) gain = CR2RES_GAIN_CHIP2 ;
1224 else if (reduce_det == 3) gain = CR2RES_GAIN_CHIP3 ;
1225 else {
1226 cpl_msg_error(__func__, "Failed to get the Gain value") ;
1227 return -1 ;
1228 }
1229
1230 /* Check raw frames consistency */
1231 if (cr2res_obs_nodding_check_inputs_validity(rawframes) != 1) {
1232 cpl_msg_error(__func__, "Invalid Inputs") ;
1233 return -1 ;
1234 }
1235
1236 /* Initialise */
1237 nframes = cpl_frameset_get_size(rawframes) ;
1238 first_fname = cpl_frame_get_filename(
1239 cpl_frameset_get_position_const(rawframes, 0)) ;
1240
1241 /* Get the order zeropoint */
1242 if ((plist = cpl_propertylist_load(cpl_frame_get_filename(trace_wave_frame),
1243 0)) == NULL) {
1244 cpl_msg_error(__func__, "Cannot read the ORDER_ZP from the input TW") ;
1245 return -1 ;
1246 }
1247 order_zp = cr2res_pfits_get_order_zp(plist) ;
1248 cpl_propertylist_delete(plist) ;
1249 if (cpl_error_get_code()) {
1250 cpl_msg_error(__func__, "Missing ORDER_ZP in the header - Skip") ;
1251 cpl_error_reset() ;
1252 /* Negative Zerop to log the fact that it is missing */
1253 order_zp = -100 ;
1254 }
1255
1256 /* Get the Nodding positions */
1257 cpl_msg_info(__func__, "Get the Nodding positions") ;
1258 cpl_msg_indent_more() ;
1259 nod_positions = cr2res_nodding_read_positions(rawframes) ;
1260 for (i=0 ; i<nframes ; i++) {
1261 cpl_msg_info(__func__, "Frame %s - Nodding %c",
1262 cpl_frame_get_filename(
1263 cpl_frameset_get_position_const(rawframes, i)),
1264 cr2res_nodding_position_char(nod_positions[i])) ;
1265 }
1266 cpl_msg_indent_less() ;
1267
1268 /* Load the DITs if necessary */
1269 dits = cr2res_io_read_dits(rawframes) ;
1270 //if (master_dark_frame != NULL) dits = cr2res_io_read_dits(rawframes) ;
1271 //else dits = NULL ;
1272 if (cpl_msg_get_level() == CPL_MSG_DEBUG && dits != NULL)
1273 cpl_vector_dump(dits, stdout) ;
1274
1275 /*Load the NDITs */
1276 ndits = cr2res_io_read_ndits(rawframes);
1277 if (cpl_msg_get_level() == CPL_MSG_DEBUG && ndits != NULL)
1278 cpl_vector_dump(ndits, stdout) ;
1279
1280 /* Load image list */
1281 cpl_msg_info(__func__, "Load the image list") ;
1282 if ((in = cr2res_io_load_image_list_from_set(rawframes,
1283 reduce_det)) == NULL) {
1284 cpl_msg_error(__func__, "Cannot load images") ;
1285 cpl_free(nod_positions) ;
1286 if (dits != NULL) cpl_vector_delete(dits) ;
1287 return -1 ;
1288 }
1289 if (hdrl_imagelist_get_size(in) != cpl_frameset_get_size(rawframes)) {
1290 cpl_msg_error(__func__, "Inconsistent number of loaded images") ;
1291 cpl_free(nod_positions) ;
1292 if (dits != NULL) cpl_vector_delete(dits) ;
1294 return -1 ;
1295 }
1296
1297 /* Calibrate the images */
1298 cpl_msg_info(__func__, "Apply the Calibrations") ;
1299 cpl_msg_indent_more() ;
1300 if ((in_calib = cr2res_calib_imagelist(in, reduce_det, 0,
1301 subtract_nolight_rows, subtract_interorder_column, cosmics,
1302 master_flat_frame, master_dark_frame, bpm_frame, detlin_frame, dits,
1303 ndits))==NULL) {
1304 cpl_msg_error(__func__, "Failed to apply the calibrations") ;
1305 cpl_msg_indent_less() ;
1306 cpl_free(nod_positions) ;
1307 if (dits != NULL) cpl_vector_delete(dits) ;
1308 if (ndits != NULL) cpl_vector_delete(ndits) ;
1310 return -1 ;
1311 }
1313 if (dits != NULL) cpl_vector_delete(dits) ;
1314 cpl_msg_indent_less() ;
1315
1316 /* Split the image lists */
1317 cpl_msg_info(__func__, "Split the images in A and B lists") ;
1318 cpl_msg_indent_more() ;
1319 if (cr2res_combine_nodding_split(in_calib, nod_positions, &in_a,
1320 &in_b)) {
1321 cpl_msg_error(__func__, "Failed to split the nodding positions") ;
1322 cpl_msg_indent_less() ;
1323 cpl_free(nod_positions) ;
1324 hdrl_imagelist_delete(in_calib) ;
1325 cpl_vector_delete(ndits) ;
1326 return -1 ;
1327 }
1328
1329 /* error factor is gain * ndit *nexp */
1330 if (error_method == CR2RES_EXTRACT_ERROR_HORNE) {
1331 error_factor = -1.0;
1332 }
1333 else {
1334 error_factor = gain * cpl_vector_get(ndits, 0) *
1336 }
1337
1338 for (i=0; i<cpl_vector_get_size(ndits); i++){
1339 if (cpl_vector_get(ndits,i) != cpl_vector_get(ndits, 0))
1340 cpl_msg_warning(__func__, "Raw frames have different NDIT! "
1341 "Error spectrum will likely be scaled incorrectly.");
1342 }
1343 cpl_vector_delete(ndits) ;
1344 cpl_free(nod_positions) ;
1345 hdrl_imagelist_delete(in_calib) ;
1346 cpl_msg_indent_less() ;
1347
1348 /* Check the sizes of A/B image lists */
1350 || hdrl_imagelist_get_size(in_a) == 0) {
1351 cpl_msg_error(__func__, "Inconsistent A / B number of images") ;
1352 hdrl_imagelist_delete(in_a) ;
1353 hdrl_imagelist_delete(in_b) ;
1354 return -1 ;
1355 }
1356
1357 /* Compute diff_a = in_a - in_b and diff_b = in_b - in_a */
1358 cpl_msg_info(__func__, "Compute difference image lists A-B and B-A") ;
1359 diff_a = hdrl_imagelist_duplicate(in_a) ;
1360 hdrl_imagelist_sub_imagelist(diff_a, in_b) ;
1361 diff_b = hdrl_imagelist_duplicate(in_b) ;
1362 hdrl_imagelist_sub_imagelist(diff_b, in_a) ;
1363 hdrl_imagelist_delete(in_a) ;
1364 hdrl_imagelist_delete(in_b) ;
1365
1366 /* Collapse A-B and B-A */
1367 cpl_msg_info(__func__, "Collapse image lists A-B and B-A") ;
1368 cpl_msg_indent_more() ;
1369 if (hdrl_imagelist_collapse_mean(diff_a, &collapsed_a, &contrib_a) !=
1370 CPL_ERROR_NONE) {
1371 cpl_msg_error(__func__, "Failed to Collapse A-B") ;
1372 hdrl_imagelist_delete(diff_a) ;
1373 hdrl_imagelist_delete(diff_b) ;
1374 cpl_msg_indent_less() ;
1375 return -1 ;
1376 }
1377 cpl_image_delete(contrib_a) ;
1378 hdrl_imagelist_delete(diff_a) ;
1379 if (hdrl_imagelist_collapse_mean(diff_b, &collapsed_b, &contrib_b) !=
1380 CPL_ERROR_NONE) {
1381 cpl_msg_error(__func__, "Failed to Collapse B-A") ;
1382 hdrl_imagelist_delete(diff_b) ;
1383 hdrl_image_delete(collapsed_a) ;
1384 cpl_msg_indent_less() ;
1385 return -1 ;
1386 }
1387 cpl_image_delete(contrib_b) ;
1388 hdrl_imagelist_delete(diff_b) ;
1389 cpl_msg_indent_less() ;
1390
1391 /* Load the trace wave */
1392 cpl_msg_info(__func__, "Load the TRACE WAVE") ;
1393 if ((trace_wave = cr2res_io_load_TRACE_WAVE(cpl_frame_get_filename(
1394 trace_wave_frame), reduce_det)) == NULL) {
1395 cpl_msg_error(__func__, "Failed to Load the traces file") ;
1396 hdrl_image_delete(collapsed_a) ;
1397 hdrl_image_delete(collapsed_b) ;
1398 return -1 ;
1399 }
1400
1401 /* Correct trace_wave with some provided raw flats */
1402 cpl_msg_warning(__func__, "TRACE ADJUST NOT YET IMPLEMENTED") ;
1403 /*if (raw_flat_frames != NULL) {
1404 cpl_msg_info(__func__, "Try to correct the reproducibility error") ;
1405 cpl_msg_indent_more() ;
1406 trace_wave_corrected = cr2res_trace_adjust(trace_wave, raw_flat_frames,
1407 reduce_det) ;
1408 if (trace_wave_corrected != NULL) {
1409 cpl_table_delete(trace_wave) ;
1410 trace_wave = trace_wave_corrected ;
1411 trace_wave_corrected = NULL ;
1412 }
1413 cpl_msg_indent_less() ;
1414 }*/
1415
1416 /* Compute the slit fractions for A and B positions extraction */
1417 cpl_msg_info(__func__, "Compute the slit fractions for A and B positions");
1418 cpl_msg_indent_more() ;
1419 /*
1420 The assumption is made here that :
1421 - The slit center is exactly in the middle of A and B positions
1422 - The nodthrow is the distance in arcseconds between A and B
1423 - The slit size is 10 arcseconds
1424 - The B position is above the A position (--nodding-invert=false)
1425 */
1426 slit_length = 10 ;
1427 if ((plist = cpl_propertylist_load(first_fname, 0)) == NULL) {
1428 cpl_msg_error(__func__, "Cannot read the NODTHROW in the input files") ;
1429 cpl_msg_indent_less() ;
1430 hdrl_image_delete(collapsed_a) ;
1431 hdrl_image_delete(collapsed_b) ;
1432 cpl_table_delete(trace_wave) ;
1433 return -1 ;
1434 }
1435 nod_throw = cr2res_pfits_get_nodthrow(plist) ;
1436 cpl_propertylist_delete(plist) ;
1437 if (nod_throw < slit_length / 2.0) {
1438 extr_width_frac = nod_throw/slit_length ;
1439 if (nodding_invert == 1) {
1440 slit_frac_a_bot = 0.5 ;
1441 slit_frac_a_mid = slit_frac_a_bot + extr_width_frac/2.0 ;
1442 slit_frac_a_top = slit_frac_a_bot + extr_width_frac ;
1443 slit_frac_b_top = 0.5 ;
1444 slit_frac_b_mid = slit_frac_b_top - extr_width_frac/2.0 ;
1445 slit_frac_b_bot = slit_frac_b_top - extr_width_frac ;
1446 } else {
1447 slit_frac_a_top = 0.5 ;
1448 slit_frac_a_mid = slit_frac_a_top - extr_width_frac/2.0 ;
1449 slit_frac_a_bot = slit_frac_a_top - extr_width_frac ;
1450 slit_frac_b_bot = 0.5 ;
1451 slit_frac_b_mid = slit_frac_b_bot + extr_width_frac/2.0 ;
1452 slit_frac_b_top = slit_frac_b_bot + extr_width_frac ;
1453 }
1454 } else if (nod_throw <= slit_length) {
1455 extr_width_frac = (slit_length - nod_throw)/slit_length ;
1456 if (nodding_invert == 1) {
1457 slit_frac_a_top = 1.0 ;
1458 slit_frac_a_mid = slit_frac_a_top - extr_width_frac/2.0 ;
1459 slit_frac_a_bot = slit_frac_a_top - extr_width_frac ;
1460 slit_frac_b_bot = 0.0 ;
1461 slit_frac_b_mid = slit_frac_b_bot + extr_width_frac/2.0 ;
1462 slit_frac_b_top = slit_frac_b_bot + extr_width_frac ;
1463 } else {
1464 slit_frac_a_bot = 0.0 ;
1465 slit_frac_a_mid = slit_frac_a_bot + extr_width_frac/2.0 ;
1466 slit_frac_a_top = slit_frac_a_bot + extr_width_frac ;
1467 slit_frac_b_top = 1.0 ;
1468 slit_frac_b_mid = slit_frac_b_top - extr_width_frac/2.0 ;
1469 slit_frac_b_bot = slit_frac_b_top - extr_width_frac ;
1470 }
1471 } else {
1472 cpl_msg_error(__func__, "NODTHROW > slit length (%g>%g)- abort",
1473 nod_throw, slit_length) ;
1474 cpl_msg_indent_less() ;
1475 hdrl_image_delete(collapsed_a) ;
1476 hdrl_image_delete(collapsed_b) ;
1477 cpl_table_delete(trace_wave) ;
1478 return -1 ;
1479 }
1480 cpl_msg_info(__func__, "Nod Throw : %g arcsecs", nod_throw) ;
1481 cpl_msg_info(__func__, "Nodding A extraction: Slit fraction %g - %g",
1482 slit_frac_a_bot, slit_frac_a_top) ;
1483 cpl_msg_info(__func__, "Nodding B extraction: Slit fraction %g - %g",
1484 slit_frac_b_bot, slit_frac_b_top) ;
1485
1486 slit_frac_a = cpl_array_new(3, CPL_TYPE_DOUBLE) ;
1487 cpl_array_set(slit_frac_a, 0, slit_frac_a_bot) ;
1488 cpl_array_set(slit_frac_a, 1, slit_frac_a_mid) ;
1489 cpl_array_set(slit_frac_a, 2, slit_frac_a_top) ;
1490
1491 slit_frac_b = cpl_array_new(3, CPL_TYPE_DOUBLE) ;
1492 cpl_array_set(slit_frac_b, 0, slit_frac_b_bot) ;
1493 cpl_array_set(slit_frac_b, 1, slit_frac_b_mid) ;
1494 cpl_array_set(slit_frac_b, 2, slit_frac_b_top) ;
1495 cpl_msg_indent_less() ;
1496
1497 /* Recompute the traces for the new slit fractions */
1498 cpl_msg_info(__func__, "Recompute the traces for the A slit fraction") ;
1499 if ((trace_wave_a = cr2res_trace_new_slit_fraction(trace_wave,
1500 slit_frac_a)) == NULL) {
1501 cpl_msg_error(__func__,
1502 "Failed to compute the traces for extraction of A") ;
1503 hdrl_image_delete(collapsed_a) ;
1504 hdrl_image_delete(collapsed_b) ;
1505 cpl_table_delete(trace_wave) ;
1506 cpl_array_delete(slit_frac_a) ;
1507 cpl_array_delete(slit_frac_b) ;
1508 return -1 ;
1509 }
1510 cpl_array_delete(slit_frac_a) ;
1511
1512 cpl_msg_info(__func__, "Recompute the traces for the B slit fraction") ;
1513 if ((trace_wave_b = cr2res_trace_new_slit_fraction(trace_wave,
1514 slit_frac_b)) == NULL) {
1515 cpl_msg_error(__func__,
1516 "Failed to compute the traces for extraction of B") ;
1517 hdrl_image_delete(collapsed_a) ;
1518 hdrl_image_delete(collapsed_b) ;
1519 cpl_table_delete(trace_wave) ;
1520 cpl_table_delete(trace_wave_a) ;
1521 cpl_array_delete(slit_frac_b) ;
1522 return -1 ;
1523 }
1524 cpl_array_delete(slit_frac_b) ;
1525
1526 /* Load Blaze */
1527 blaze_table = NULL ;
1528 blaze_norm = 0;
1529 if (blaze_frame != NULL) {
1530 cpl_msg_info(__func__, "Load the BLAZE") ;
1531 if ((blaze_table = cr2res_io_load_EXTRACT_1D(cpl_frame_get_filename(
1532 blaze_frame), reduce_det)) == NULL) {
1533 cpl_msg_error(__func__, "Failed to Load the Blaze file") ;
1534 hdrl_image_delete(collapsed_a) ;
1535 hdrl_image_delete(collapsed_b) ;
1536 cpl_table_delete(trace_wave) ;
1537 cpl_table_delete(trace_wave_a) ;
1538 cpl_table_delete(trace_wave_b) ;
1539 return -1 ;
1540 }
1541 cpl_propertylist * blaze_plist ;
1542 blaze_plist = cpl_propertylist_load_regexp(cpl_frame_get_filename(
1543 blaze_frame),0,CR2RES_HEADER_QC_BLAZE_NORM,0);
1544 if(cpl_propertylist_get_size(blaze_plist)>0){
1545 blaze_norm = cpl_propertylist_get_double(blaze_plist, CR2RES_HEADER_QC_BLAZE_NORM);
1546 }
1547 else {
1548 blaze_norm = -1;
1549 cpl_msg_warning(__func__, "QC BLAZE NORM value not found, reverting to per trace normalization") ;
1550 }
1551 if(blaze_plist!=NULL){
1552 cpl_propertylist_delete(blaze_plist);
1553 }
1554 }
1555
1556 /* Execute the extraction */
1557 cpl_msg_info(__func__, "A position Spectra Extraction") ;
1558 cpl_msg_indent_more() ;
1559 if (cr2res_extract_traces(collapsed_a, trace_wave_a, NULL, blaze_table, blaze_norm, -1,
1560 -1, CR2RES_EXTR_OPT_CURV, extract_height, extract_swath_width,
1561 extract_oversample, extract_smooth_slit, extract_smooth_spec,
1562 extract_niter, extract_kappa, error_factor,
1563 disp_det==reduce_det, disp_order_idx, disp_trace,
1564 &extracted_a, &slit_func_a, &model_master_a) == -1) {
1565 cpl_msg_error(__func__, "Failed to extract A");
1566 cpl_msg_indent_less() ;
1567 hdrl_image_delete(collapsed_a) ;
1568 hdrl_image_delete(collapsed_b) ;
1569 cpl_table_delete(trace_wave_a) ;
1570 cpl_table_delete(trace_wave_b) ;
1571 cpl_table_delete(trace_wave) ;
1572 return -1 ;
1573 }
1574 cpl_msg_indent_less() ;
1575
1576 cpl_msg_info(__func__, "B position Spectra Extraction") ;
1577 cpl_msg_indent_more() ;
1578 if (cr2res_extract_traces(collapsed_b, trace_wave_b, NULL, blaze_table, blaze_norm, -1,
1579 -1, CR2RES_EXTR_OPT_CURV, extract_height, extract_swath_width,
1580 extract_oversample, extract_smooth_slit, extract_smooth_spec,
1581 extract_niter, extract_kappa, error_factor,
1582 disp_det==reduce_det, disp_order_idx, disp_trace,
1583 &extracted_b, &slit_func_b, &model_master_b) == -1) {
1584 cpl_msg_error(__func__, "Failed to extract B");
1585 cpl_msg_indent_less() ;
1586 cpl_table_delete(extracted_a) ;
1587 cpl_table_delete(slit_func_a) ;
1588 hdrl_image_delete(model_master_a) ;
1589 hdrl_image_delete(collapsed_a) ;
1590 hdrl_image_delete(collapsed_b) ;
1591 cpl_table_delete(trace_wave_a) ;
1592 cpl_table_delete(trace_wave_b) ;
1593 cpl_table_delete(trace_wave) ;
1594 return -1 ;
1595 }
1596 cpl_msg_indent_less() ;
1597
1598 if (blaze_table != NULL) cpl_table_delete(blaze_table) ;
1599
1600 /* Combine both a and b extracted spectra together */
1601 cpl_msg_info(__func__, "A and B spectra combination") ;
1602 cpl_msg_indent_more() ;
1603 extracted_combined = cr2res_combine_extracted(extracted_a, extracted_b) ;
1604 cpl_msg_indent_less() ;
1605
1606 /* Get the Setting */
1607 plist = cpl_propertylist_load(first_fname, 0) ;
1608 cur_setting = cpl_strdup(cr2res_pfits_get_wlen_id(plist)) ;
1609 cr2res_format_setting(cur_setting) ;
1610 cpl_propertylist_delete(plist) ;
1611
1612 /* Store the extension header for product saving */
1613 plist = cpl_propertylist_load(first_fname,
1614 cr2res_io_get_ext_idx(first_fname, reduce_det, 1)) ;
1615
1616 /* QC - Signal and FWHM */
1617 cpl_msg_info(__func__, "QC parameters computation") ;
1618 qc_signal_a = cr2res_qc_obs_nodding_signal(extracted_a) ;
1619 qc_signal_b = cr2res_qc_obs_nodding_signal(extracted_b) ;
1620 cpl_propertylist_append_double(plist, CR2RES_HEADER_QC_SIGNAL,
1621 (qc_signal_a+qc_signal_b)/2.0) ;
1622
1623 /* QC STANDARD FLUX */
1624 qc_standard_flux_a =
1625 cr2res_qc_obs_nodding_standard_flux(extracted_a, cur_setting) ;
1626 qc_standard_flux_b =
1627 cr2res_qc_obs_nodding_standard_flux(extracted_b, cur_setting) ;
1628 cpl_propertylist_append_double(plist, CR2RES_HEADER_QC_STANDARD_FLUX,
1629 (qc_standard_flux_a+qc_standard_flux_b)/2.0) ;
1630 cpl_free(cur_setting) ;
1631
1632 /* QC - SNR on nodding A position */
1633 qc_snrs = cr2res_qc_snr(trace_wave_a, extracted_a, &order_idx_values,
1634 &nb_order_idx_values) ;
1635 qc_der_snrs = cr2res_qc_der_snr(trace_wave_a, extracted_a, &order_idx_values,
1636 &nb_order_idx_values) ;
1637 for (i=0 ; i<nb_order_idx_values ; i++) {
1638 order_idx = order_idx_values[i] ;
1639 order_idxp = cr2res_io_convert_order_idx_to_idxp(order_idx) ;
1640 key_name = cpl_sprintf(CR2RES_HEADER_QC_SNR, order_idxp) ;
1641 cpl_propertylist_append_double(plist, key_name, qc_snrs[i]) ;
1642 cpl_free(key_name) ;
1643 key_name = cpl_sprintf(CR2RES_HEADER_QC_DER_SNR, order_idxp) ;
1644 cpl_propertylist_append_double(plist, key_name, qc_der_snrs[i]) ;
1645 cpl_free(key_name) ;
1646 }
1647 cpl_free(order_idx_values) ;
1648 cpl_free(qc_snrs) ;
1649
1650 /* Get the order numbers from the TW rows */
1651 order_idx_values = cr2res_trace_get_order_idx_values(trace_wave,
1652 &nb_order_idx_values);
1653
1654 /* QC - SLIT FWHM */
1655 fwhm_a_array = cpl_array_new(nb_order_idx_values, CPL_TYPE_DOUBLE);
1656 fwhm_b_array = cpl_array_new(nb_order_idx_values, CPL_TYPE_DOUBLE);
1657 for (i=0 ; i<nb_order_idx_values ; i++) {
1658 order_idx = order_idx_values[i] ;
1659 order_idxp = cr2res_io_convert_order_idx_to_idxp(order_idx) ;
1660 qc_fwhm_a = cr2res_qc_obs_slit_psf(slit_func_a, order_idxp,
1661 extract_oversample);
1662 qc_fwhm_b = cr2res_qc_obs_slit_psf(slit_func_b, order_idxp,
1663 extract_oversample);
1664
1665 key_name = cpl_sprintf(CR2RES_HEADER_QC_SLITFWHM_ORDER, order_idxp) ;
1666 cpl_propertylist_append_double(plist, key_name,
1667 (qc_fwhm_a+qc_fwhm_b)/2.0) ;
1668 cpl_free(key_name) ;
1669 cpl_array_set(fwhm_a_array, i, qc_fwhm_a) ;
1670 cpl_array_set(fwhm_b_array, i, qc_fwhm_b) ;
1671 }
1672 qc_fwhm_a = cpl_array_get_median(fwhm_a_array);
1673 qc_fwhm_b = cpl_array_get_median(fwhm_b_array);
1674 qc_fwhm_med = (qc_fwhm_a+qc_fwhm_b)/2.0 ;
1675 cpl_propertylist_append_double(plist, CR2RES_HEADER_QC_SLITFWHM_MED,
1676 qc_fwhm_med) ;
1677 if (qc_fwhm_med < 3.5) {
1678 cpl_msg_warning(__func__, "Median FWHM of the PSF along the slit "
1679 "is %gpix, i.e. below the slit width. This means the slit "
1680 "is likely not evenly filled with light "
1681 "in the spectral direction. This can result in a "
1682 "wavelength offset between A and B nodding positions, and with "
1683 "respect to calibrations."
1684 , qc_fwhm_med);
1685 }
1686 cpl_array_delete(fwhm_a_array) ;
1687 cpl_array_delete(fwhm_b_array) ;
1688
1689 /* QC - Real Orders */
1690 if (order_zp > 0) {
1691 /* Compute the Real Order numbers and store them in QCs */
1692 for (i = 0; i < nb_order_idx_values; i++) {
1693 int order_real;
1694 order_idx = order_idx_values[i] ;
1695 order_idxp = cr2res_io_convert_order_idx_to_idxp(order_idx) ;
1696
1697 order_real = cr2res_order_idx_to_real(order_idx, order_zp) ;
1698 key_name = cpl_sprintf(CR2RES_HEADER_QC_REAL_ORDER, order_idxp) ;
1699 cpl_propertylist_append_int(plist, key_name, order_real) ;
1700 cpl_free(key_name) ;
1701 }
1702 }
1703 cpl_table_delete(trace_wave) ;
1704 cpl_free(order_idx_values) ;
1705
1706 /* Return */
1707 *combineda = collapsed_a ;
1708 *extracta = extracted_a ;
1709 *slitfunca = slit_func_a ;
1710 *modela = model_master_a ;
1711 *twa = trace_wave_a ;
1712
1713 *combinedb = collapsed_b ;
1714 *extractb = extracted_b ;
1715 *slitfuncb = slit_func_b ;
1716 *modelb = model_master_b ;
1717 *twb = trace_wave_b ;
1718
1719 *extractc = extracted_combined ;
1720 *ext_plist = plist ;
1721
1722 return 0 ;
1723}
1724
1725/*----------------------------------------------------------------------------*/
1731/*----------------------------------------------------------------------------*/
1732static int cr2res_obs_nodding_check_inputs_validity(
1733 const cpl_frameset * rawframes)
1734{
1735 cpl_propertylist * plist ;
1736 cr2res_nodding_pos * nod_positions ;
1737 cpl_size nframes, i ;
1738 double nodthrow;
1739 int nb_a, nb_b ;
1740
1741 /* Check Inputs */
1742 if (rawframes == NULL) return -1 ;
1743
1744 /* Need even number of frames */
1745 nframes = cpl_frameset_get_size(rawframes) ;
1746 if (nframes % 2) {
1747 cpl_msg_error(__func__, "Require an even number of raw frames") ;
1748 return 0 ;
1749 }
1750
1751 /* Need same number of A and B positions */
1752 nb_a = nb_b = 0 ;
1753 nod_positions = cr2res_nodding_read_positions(rawframes) ;
1754 if (nod_positions == NULL) return -1 ;
1755 for (i=0 ; i<nframes ; i++) {
1756 if (nod_positions[i] == CR2RES_NODDING_A) nb_a++ ;
1757 if (nod_positions[i] == CR2RES_NODDING_B) nb_b++ ;
1758 }
1759 cpl_free(nod_positions) ;
1760
1761 if (nb_a == 0 || nb_b == 0 || nb_a != nb_b) {
1762 cpl_msg_error(__func__, "Require as many A and B positions") ;
1763 return 0 ;
1764 }
1765
1766 /* Need the same nod throw in all frames */
1767 if ((plist = cpl_propertylist_load(cpl_frame_get_filename(
1768 cpl_frameset_get_position_const(rawframes, 0)),
1769 0)) == NULL) {
1770 return -1;
1771 }
1772 nodthrow = cr2res_pfits_get_nodthrow(plist);
1773 cpl_propertylist_delete(plist) ;
1774 for (i = 1; i < nframes; i++) {
1775 double nodthrow_cur;
1776 if ((plist = cpl_propertylist_load(cpl_frame_get_filename(
1777 cpl_frameset_get_position_const(rawframes, i)),
1778 0)) == NULL) {
1779 return -1;
1780 }
1781 nodthrow_cur = cr2res_pfits_get_nodthrow(plist);
1782 cpl_propertylist_delete(plist) ;
1783
1784 if (fabs(nodthrow_cur-nodthrow) > 1e-3) {
1785 cpl_msg_error(__func__,
1786 "Require constant NOD THROW in the raw frames") ;
1787 return 0 ;
1788 }
1789 }
1790 return 1 ;
1791}
1792
1793/*----------------------------------------------------------------------------*/
1809/*----------------------------------------------------------------------------*/
1810static cpl_frameset * cr2res_obs_nodding_find_RAW(
1811 const cpl_frameset * in,
1812 int * type)
1813{
1814 cpl_frameset * out ;
1815
1816 /* Check entries */
1817 if (in == NULL) return NULL ;
1818
1819 out = cr2res_extract_frameset(in, CR2RES_OBS_NODDING_OTHER_RAW) ;
1820 if (out == NULL) {
1821 out = cr2res_extract_frameset(in, CR2RES_OBS_NODDING_JITTER_RAW) ;
1822 }
1823 if (out != NULL) {
1824 if (type != NULL) *type = 1 ;
1825 } else {
1826 out = cr2res_extract_frameset(in, CR2RES_CAL_NODDING_OTHER_RAW) ;
1827 if (out == NULL) {
1828 out = cr2res_extract_frameset(in, CR2RES_CAL_NODDING_JITTER_RAW) ;
1829 }
1830 if (out != NULL) {
1831 if (type != NULL) *type = 2 ;
1832 } else {
1833 out = cr2res_extract_frameset(in, CR2RES_OBS_ASTROMETRY_OTHER_RAW) ;
1834 if (out == NULL) {
1835 out = cr2res_extract_frameset(in,
1836 CR2RES_OBS_ASTROMETRY_JITTER_RAW) ;
1837 }
1838 if (out != NULL) {
1839 if (type != NULL) *type = 3 ;
1840 }
1841 }
1842 }
1843 if (out == NULL) {
1844 if (type != NULL) *type = 0 ;
1845 }
1846 return out ;
1847}
1848
1849/*----------------------------------------------------------------------------*/
1856/*----------------------------------------------------------------------------*/
1857static int cr2res_obs_nodding_astrometry_compare(
1858 const cpl_frame * frame1,
1859 const cpl_frame * frame2)
1860{
1861 int comparison ;
1862 cpl_propertylist * plist1 ;
1863 cpl_propertylist * plist2 ;
1864 double dval1, dval2 ;
1865
1866 /* Test entries */
1867 if (frame1==NULL || frame2==NULL) return -1 ;
1868
1869 /* Get property lists */
1870 if ((plist1=cpl_propertylist_load(cpl_frame_get_filename(frame1),0))==NULL){
1871 cpl_msg_error(__func__, "getting header from reference frame");
1872 return -1 ;
1873 }
1874 if ((plist2=cpl_propertylist_load(cpl_frame_get_filename(frame2),0))==NULL){
1875 cpl_msg_error(__func__, "getting header from reference frame");
1876 cpl_propertylist_delete(plist1) ;
1877 return -1 ;
1878 }
1879
1880 /* Test status */
1881 if (cpl_error_get_code()) {
1882 cpl_propertylist_delete(plist1) ;
1883 cpl_propertylist_delete(plist2) ;
1884 return -1 ;
1885 }
1886
1887 comparison = 1 ;
1888
1889 /* Compare the DROT angle used */
1890 dval1 = cr2res_pfits_get_drot_posang(plist1) ;
1891 dval2 = cr2res_pfits_get_drot_posang(plist2) ;
1892 if (cpl_error_get_code()) {
1893 cpl_msg_error(__func__, "Cannot get the angle");
1894 cpl_propertylist_delete(plist1) ;
1895 cpl_propertylist_delete(plist2) ;
1896 return -1 ;
1897 }
1898 if (fabs(dval1-dval2) > 1e-3) comparison = 0 ;
1899
1900 cpl_propertylist_delete(plist1) ;
1901 cpl_propertylist_delete(plist2) ;
1902 return comparison ;
1903}
1904
1905
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:84
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:1290
double * cr2res_qc_der_snr(const cpl_table *tw, const cpl_table *extracted, int **out_order_idx_values, int *out_nb_order_idx_values)
Computes the DER SNR of several spectra.
Definition: cr2res_qc.c:1103
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:1208
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.