KMOS Pipeline Reference Manual 4.5.10
kmos_sci_red.c
1/*
2 * This file is part of the KMOS 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., 59 Temple Place, Suite 330, 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 <math.h>
30
31#include <cpl.h>
32
33#include "kmclipm_constants.h"
34#include "kmclipm_functions.h"
35
36#include "kmo_debug.h"
37#include "kmo_constants.h"
38#include "kmo_cpl_extensions.h"
39#include "kmo_priv_lcorr.h"
40#include "kmo_utils.h"
41#include "kmo_error.h"
42#include "kmo_dfs.h"
43#include "kmos_pfits.h"
44#include "kmo_functions.h"
45#include "kmo_priv_make_image.h"
46
47#include "kmo_priv_arithmetic.h"
48#include "kmo_priv_combine.h"
49#include "kmo_priv_functions.h"
50#include "kmo_priv_reconstruct.h"
51#include "kmos_priv_sky_tweak.h"
52
53/*-----------------------------------------------------------------------------
54 * Functions prototypes
55 *----------------------------------------------------------------------------*/
56static kmclipm_vector * kmo_tweak_load_telluric(
57 cpl_frameset * frameset,
58 int ifu_nr,
59 int is_noise,
60 int no_subtract,
61 const char * telluric_tag,
62 int * ifu_nr_telluric) ;
63
64static int kmos_sci_red_propagate_qc(
65 const cpl_propertylist * main_input,
66 cpl_propertylist * to_update,
67 const cpl_frame * inframe,
68 int det_nr) ;
69
70static double kmos_sci_red_get_f0(const char *, int, double, double) ;
71static double kmos_sci_red_get_zpoint(cpl_frame *, int) ;
72static int kmos_sci_red_check_inputs(cpl_frameset *,double,int *,const char *);
73
74static int kmos_sci_red_create(cpl_plugin *);
75static int kmos_sci_red_exec(cpl_plugin *);
76static int kmos_sci_red_destroy(cpl_plugin *);
77static int kmos_sci_red(cpl_parameterlist *, cpl_frameset *);
78
79/*-----------------------------------------------------------------------------
80 * Static variables
81 *----------------------------------------------------------------------------*/
82
83static char kmos_sci_red_description[] =
84"Two data frames are expected in order to have a sky IFU for the IFU Objects.\n"
85"If an OH spectrum is given in the SOF file the lambda axis will be corrected\n"
86"using the OH lines as reference.\n"
87"Every IFU containing an object will be reconstructed and divided by telluric\n"
88"and illumination correction. By default these intermediate cubes are saved\n"
89"to disk. The reconstructed objects with the same object name are combined.\n"
90"In order to combine a specific object, the parameters --name or --ifus can\n"
91"be used.\n"
92"For exposures taken with the templates KMOS_spec_obs_mapping8 and\n"
93"KMOS_spec_obs_mapping24, all active IFUs are combined.\n"
94"\n"
95"--------------------------------------------------------------------------\n"
96" Input files:\n"
97"\n"
98" DO KMOS \n"
99" category Type Explanation Required #Frames\n"
100" -------- ----- ----------- -------- -------\n"
101" SCIENCE RAW The science frames Y >=1 \n"
102"or LEVEL_CORRECTED RAW The science frames Y >=1 \n"
103" XCAL F2D x calibration frame Y 1 \n"
104" YCAL F2D y calibration frame Y 1 \n"
105" LCAL F2D Wavelength calib. frame Y 1 \n"
106" WAVE_BAND F2L Table with start-/end-wavelengths Y 1 \n"
107" MASTER_FLAT F2D Master flat Y 0,1 \n"
108" BADPIXEL_DARK B2D Bad pixels frame N 0,1 \n"
109" ILLUM_CORR F2I Illumination correction N 0,1 \n"
110" TELLURIC F1I normalised telluric spectrum N 0,1 \n"
111" TELLURIC_GEN F1I normalised telluric spectrum N 0,1 \n"
112" OH_SPEC F1S Vector holding OH lines N 0,1 \n"
113"\n"
114" Output files:\n"
115"\n"
116" DO KMOS\n"
117" category Type Explanation\n"
118" -------- ----- -----------\n"
119" SCI_COMBINED F3I Combined cubes with noise\n"
120" SCI_RECONSTRUCTED F3I Reconstructed cube with noise\n"
121" EXP_MASK F3I Exposure time mask (not for mapping-templates!)\n"
122" SCI_INTERIM_OBJECT F3I (optional) Intermediate reconstructed object \n"
123" cubes used for sky tweaking, no noise \n"
124" (set --sky_tweak and --save_interims)\n"
125" SCI_INTERIM_SKY F3I (optional) Intermediate reconstructed sky \n"
126" cubes used for sky tweaking, no noise\n"
127" (set --sky_tweak and --save_interims)\n"
128" SCI_COMBINED_COLL (optional) Collapsed combined cube\n"
129" (set --collapse_combined)\n"
130" SCI_RECONSTRUCTED_COLL (optional) Collapsed reconstructed cube\n"
131" (set --collapse_reconstructed)\n"
132"--------------------------------------------------------------------------\n"
133"\n";
134
135/*-----------------------------------------------------------------------------
136 * Functions code
137 *----------------------------------------------------------------------------*/
138
139/*----------------------------------------------------------------------------*/
144/*----------------------------------------------------------------------------*/
145
148/*----------------------------------------------------------------------------*/
157/*----------------------------------------------------------------------------*/
158int cpl_plugin_get_info(cpl_pluginlist *list)
159{
160 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
161 cpl_plugin *plugin = &recipe->interface;
162
163 cpl_plugin_init(plugin,
164 CPL_PLUGIN_API,
165 KMOS_BINARY_VERSION,
166 CPL_PLUGIN_TYPE_RECIPE,
167 "kmos_sci_red",
168 "Reconstruct obj/sky-pairs individually and combine "
169 "them afterwards",
170 kmos_sci_red_description,
171 "Alex Agudo Berbel, Yves Jung",
172 "https://support.eso.org/",
173 kmos_get_license(),
174 kmos_sci_red_create,
175 kmos_sci_red_exec,
176 kmos_sci_red_destroy);
177
178 cpl_pluginlist_append(list, plugin);
179
180 return 0;
181}
182
183/*----------------------------------------------------------------------------*/
191/*----------------------------------------------------------------------------*/
192static int kmos_sci_red_create(cpl_plugin *plugin)
193{
194 cpl_recipe *recipe;
195 cpl_parameter *p;
196
197 /* Check that the plugin is part of a valid recipe */
198 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
199 recipe = (cpl_recipe *)plugin;
200 else
201 return -1;
202
203 /* Create the parameters list in the cpl_recipe object */
204 recipe->parameters = cpl_parameterlist_new();
205
206 /* --lcmethod (level correction method) */
207 p = cpl_parameter_new_value("kmos.kmos_sci_red.lcmethod", CPL_TYPE_STRING,
208 "Method to use for the level correction "
209 "[\"NONE\" (no correction), "
210 "\"OSCAN\" (overscan), "
211 "\"SLICES_MEAN\" (intra slices with average), "
212 "\"SLICES_MEDIAN\" (intra slices with median)]",
213 "kmos.kmos_sci_red", "NONE");
214 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lcmethod");
215 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
216 cpl_parameterlist_append(recipe->parameters, p);
217
218 /* --imethod (interpolation method) */
219 p = cpl_parameter_new_value("kmos.kmos_sci_red.imethod", CPL_TYPE_STRING,
220 "Method to use for interpolation during reconstruction. "
221 "[\"NN\" (nearest neighbour), "
222 "\"lwNN\" (linear weighted nearest neighbor), "
223 "\"swNN\" (square weighted nearest neighbor), "
224 "\"MS\" (Modified Shepard's method)"
225 "\"CS\" (Cubic spline)]",
226 "kmos.kmos_sci_red", "CS");
227 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
228 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
229 cpl_parameterlist_append(recipe->parameters, p);
230
231 /* --smethod (shift interpolation method) */
232 p = cpl_parameter_new_value("kmos.kmos_sci_red.smethod", CPL_TYPE_STRING,
233 "Method to use for interpolation during shifting. "
234 "[\"NN\" (nearest neighbour), "
235 "\"CS\" (Cubic spline)]",
236 "kmos.kmos_sci_red", "CS");
237 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "smethod");
238 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
239 cpl_parameterlist_append(recipe->parameters, p);
240
241 /* --method (shift method) */
242 p = cpl_parameter_new_value("kmos.kmos_sci_red.method", CPL_TYPE_STRING,
243 "The shifting method: "
244 "'none': no shifting, combined directly, "
245 "'header': shift according to WCS (default), "
246 "'center': centering algorithm, "
247 "'user': read shifts from file",
248 "kmos.kmos_sci_red", "header");
249 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "method");
250 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
251 cpl_parameterlist_append(recipe->parameters, p);
252
253 /* --fmethod */
254 p = cpl_parameter_new_value("kmos.kmos_sci_red.fmethod", CPL_TYPE_STRING,
255 "The fitting method (applies only when method='center'): "
256 "'gauss': fit a gauss function to collapsed image (default), "
257 "'moffat': fit a moffat function to collapsed image",
258 "kmos.kmos_sci_red", "gauss");
259 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fmethod");
260 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
261 cpl_parameterlist_append(recipe->parameters, p);
262
263 /* --name */
264 p = cpl_parameter_new_value("kmos.kmos_sci_red.name", CPL_TYPE_STRING,
265 "Name of the object to combine.", "kmos.kmos_sci_red", "");
266 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "name");
267 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
268 cpl_parameterlist_append(recipe->parameters, p);
269
270 /* --ifus */
271 p = cpl_parameter_new_value("kmos.kmos_sci_red.ifus", CPL_TYPE_STRING,
272 "The indices of the IFUs to combine. \"ifu1;ifu2;...\"",
273 "kmos.kmos_sci_red", "");
274 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ifus");
275 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
276 cpl_parameterlist_append(recipe->parameters, p);
277
278 /* --pix_scale */
279 p = cpl_parameter_new_value("kmos.kmos_sci_red.pix_scale", CPL_TYPE_DOUBLE,
280 "Change the pixel scale [arcsec]. "
281 "Default of 0.2\" results into cubes of 14x14pix, "
282 "a scale of 0.1\" results into cubes of 28x28pix, etc.",
283 "kmos.kmos_sci_red", KMOS_PIX_RESOLUTION);
284 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "pix_scale");
285 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
286 cpl_parameterlist_append(recipe->parameters, p);
287
288 /* --suppress_extension */
289 p = cpl_parameter_new_value("kmos.kmos_sci_red.suppress_extension",
290 CPL_TYPE_BOOL,
291 "Suppress arbitrary filename extension."
292 "(TRUE (apply) or FALSE (don't apply)",
293 "kmos.kmos_sci_red", FALSE);
294 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension");
295 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
296 cpl_parameterlist_append(recipe->parameters, p);
297
298 /* --neighborhoodRange */
299 p = cpl_parameter_new_value("kmos.kmos_sci_red.neighborhoodRange",
300 CPL_TYPE_DOUBLE,
301 "Defines the range to search for neighbors in pixels",
302 "kmos.kmos_sci_red", 1.001);
303 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "neighborhoodRange");
304 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
305 cpl_parameterlist_append(recipe->parameters, p);
306
307 /* --filename */
308 p = cpl_parameter_new_value("kmos.kmos_sci_red.filename", CPL_TYPE_STRING,
309 "The path to the file with the shift vectors."
310 "(Applies only to method='user')",
311 "kmos.kmos_sci_red", "");
312 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "filename");
313 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
314 cpl_parameterlist_append(recipe->parameters, p);
315
316 /* --flux */
317 p = cpl_parameter_new_value("kmos.kmos_sci_red.flux", CPL_TYPE_BOOL,
318 "TRUE: Apply flux conservation. FALSE: otherwise",
319 "kmos.kmos_sci_red", FALSE);
320 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
321 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
322 cpl_parameterlist_append(recipe->parameters, p);
323
324 /* --background */
325 p = cpl_parameter_new_value("kmos.kmos_sci_red.background", CPL_TYPE_BOOL,
326 "TRUE: Apply background removal. FALSE: otherwise",
327 "kmos.kmos_sci_red", FALSE);
328 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "background");
329 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
330 cpl_parameterlist_append(recipe->parameters, p);
331
332 /* --fast_mode */
333 p = cpl_parameter_new_value("kmos.kmos_sci_red.fast_mode", CPL_TYPE_BOOL,
334 "FALSE: cubes are shifted and combined,"
335 "TRUE: cubes are collapsed and then shifted and combined",
336 "kmos.kmos_sci_red", FALSE);
337 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fast_mode");
338 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
339 cpl_parameterlist_append(recipe->parameters, p);
340
341 /* --extrapolate */
342 p = cpl_parameter_new_value("kmos.kmos_sci_red.extrapolate", CPL_TYPE_BOOL,
343 "Applies only to 'smethod=CS' when doing sub-pixel shifts: "
344 "FALSE: shifted IFU will be filled with NaN's at the borders,"
345 "TRUE: shifted IFU will be extrapolated at the borders",
346 "kmos.kmos_sci_red", FALSE);
347 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extrapolate");
348 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
349 cpl_parameterlist_append(recipe->parameters, p);
350
351 /* --xcal_interpolation */
352 p = cpl_parameter_new_value("kmos.kmos_sci_red.xcal_interpolation",
353 CPL_TYPE_BOOL,
354 "TRUE: Interpolate xcal between rotator angles. FALSE: otherwise",
355 "kmos.kmos_sci_red", TRUE);
356 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "xcal_interpolation");
357 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
358 cpl_parameterlist_append(recipe->parameters, p);
359
360 /* --edge_nan */
361 p = cpl_parameter_new_value("kmos.kmos_sci_red.edge_nan", CPL_TYPE_BOOL,
362 "Set borders of cubes to NaN before combining them."
363 "(TRUE (apply) or FALSE (don't apply)",
364 "kmos.kmos_sci_red", FALSE);
365 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "edge_nan");
366 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
367 cpl_parameterlist_append(recipe->parameters, p);
368
369 /* --no_combine */
370 p = cpl_parameter_new_value("kmos.kmos_sci_red.no_combine", CPL_TYPE_BOOL,
371 "Don't combine cubes after reconstruction."
372 "(TRUE (apply) or FALSE (don't apply)",
373 "kmos.kmos_sci_red", FALSE);
374 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "no_combine");
375 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
376 cpl_parameterlist_append(recipe->parameters, p);
377
378 /* --no_subtract */
379 p = cpl_parameter_new_value("kmos.kmos_sci_red.no_subtract", CPL_TYPE_BOOL,
380 "Don't sky subtract object and references."
381 "(TRUE (apply) or FALSE (don't apply)",
382 "kmos.kmos_sci_red", FALSE);
383 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "no_subtract");
384 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
385 cpl_parameterlist_append(recipe->parameters, p);
386
387 /* --sky_tweak */
388 p = cpl_parameter_new_value("kmos.kmos_sci_red.sky_tweak", CPL_TYPE_BOOL,
389 "Use modified sky cube for sky subtraction."
390 "(TRUE (apply) or FALSE (don't apply)",
391 "kmos.kmos_sci_red", FALSE);
392 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky_tweak");
393 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
394 cpl_parameterlist_append(recipe->parameters, p);
395
396 /* --skip_sky_oh_align */
397 p = cpl_parameter_new_value("kmos.kmos_sci_red.skip_sky_oh_align",
398 CPL_TYPE_BOOL, "Skip the OH alignment for the SKY",
399 "kmos.kmos_sci_red", FALSE);
400 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skip_sky_oh_align");
401 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
402 cpl_parameterlist_append(recipe->parameters, p);
403
404 /* --discard_subband */
405 p = cpl_parameter_new_value("kmos.kmos_sci_red.discard_subband",
406 CPL_TYPE_BOOL, "Ignore last sub-band in the sky tweaking",
407 "kmos.kmos_sci_red", FALSE);
408 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "discard_subband");
409 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
410 cpl_parameterlist_append(recipe->parameters, p);
411
412 /* --stretch_sky */
413 p = cpl_parameter_new_value("kmos.kmos_sci_red.stretch_sky",
414 CPL_TYPE_BOOL, "Stretch sky in the sky tweaking",
415 "kmos.kmos_sci_red", FALSE);
416 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stretch");
417 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
418 cpl_parameterlist_append(recipe->parameters, p);
419
420 /* --stretch_degree */
421 p = cpl_parameter_new_value("kmos.kmos_sci_red.stretch_degree",
422 CPL_TYPE_INT, "Stretch polynomial degree", "kmos.kmos_sci_red",
423 8);
424 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stretch_degree");
425 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
426 cpl_parameterlist_append(recipe->parameters, p);
427
428 /* --stretch_resampling */
429 p = cpl_parameter_new_value("kmos.kmos_sci_red.stretch_resampling",
430 CPL_TYPE_STRING, "Stretch resampling method (linear/spline)",
431 "kmos.kmos_sci_red", "spline");
432 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stretch_resampling");
433 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
434 cpl_parameterlist_append(recipe->parameters, p);
435
436 /* --tbsub */
437 p = cpl_parameter_new_value("kmos.kmos_sci_red.tbsub", CPL_TYPE_BOOL,
438 "Subtract thermal background from input cube."
439 "(TRUE (apply) or FALSE (don't apply)",
440 "kmos.kmos_sci_red", TRUE);
441 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "tbsub");
442 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
443 cpl_parameterlist_append(recipe->parameters, p);
444
445 // add parameters for band-definition
446 kmos_band_pars_create(recipe->parameters, "kmos.kmos_sci_red");
447
448 /* --obj_sky_table */
449 p = cpl_parameter_new_value("kmos.kmos_sci_red.obj_sky_table",
450 CPL_TYPE_STRING,
451 "The path to the file with the modified obj/sky associations.",
452 "kmos.kmos_sci_red", "");
453 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "obj_sky_table");
454 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
455 cpl_parameterlist_append(recipe->parameters, p);
456
457 /* --velocity_offset */
458 p = cpl_parameter_new_value("kmos.kmos_sci_red.velocity_offset",
459 CPL_TYPE_DOUBLE,
460 "Specify velocity offset correction in km/s for lambda scale",
461 "kmos.kmos_sci_red", 0.0);
462 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "velocity_offset");
463 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
464 cpl_parameterlist_append(recipe->parameters, p);
465
466 /* --save_interims */
467 p=cpl_parameter_new_value("kmos.kmos_sci_red.save_interims", CPL_TYPE_BOOL,
468 "Save interim object and sky cubes. "
469 "Can only be used together with --sky_tweak",
470 "kmos.kmos_sci_red", FALSE);
471 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "save_interims");
472 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
473 cpl_parameterlist_append(recipe->parameters, p);
474
475 /* --collapse_reconstructed */
476 p = cpl_parameter_new_value("kmos.kmos_sci_red.collapse_reconstructed",
477 CPL_TYPE_BOOL, "Flag to collapse the reconstructed images",
478 "kmos.kmos_sci_red", FALSE);
479 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"collapse_reconstructed");
480 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
481 cpl_parameterlist_append(recipe->parameters, p);
482
483 /* --collapse_combined */
484 p = cpl_parameter_new_value("kmos.kmos_sci_red.collapse_combined",
485 CPL_TYPE_BOOL, "Flag to collapse the combined images",
486 "kmos.kmos_sci_red", FALSE);
487 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "collapse_combined");
488 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
489 cpl_parameterlist_append(recipe->parameters, p);
490
491 return kmos_combine_pars_create(recipe->parameters, "kmos.kmos_sci_red",
492 DEF_REJ_METHOD, FALSE);
493}
494
495/*----------------------------------------------------------------------------*/
501/*----------------------------------------------------------------------------*/
502static int kmos_sci_red_exec(cpl_plugin *plugin)
503{
504 cpl_recipe *recipe;
505
506 /* Get the recipe out of the plugin */
507 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
508 recipe = (cpl_recipe *)plugin;
509 else return -1 ;
510
511 return kmos_sci_red(recipe->parameters, recipe->frames);
512}
513
514/*----------------------------------------------------------------------------*/
520/*----------------------------------------------------------------------------*/
521static int kmos_sci_red_destroy(cpl_plugin *plugin)
522{
523 cpl_recipe *recipe;
524
525 /* Get the recipe out of the plugin */
526 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
527 recipe = (cpl_recipe *)plugin;
528 else return -1 ;
529
530 cpl_parameterlist_delete(recipe->parameters);
531 return 0 ;
532}
533
534/*----------------------------------------------------------------------------*/
547/*----------------------------------------------------------------------------*/
548static int kmos_sci_red(cpl_parameterlist * parlist, cpl_frameset * frameset)
549{
550 const cpl_parameter * par ;
551 /*********************/
552 /* Parsed Parameters */
553 int flux, background, extrapolate, fast_mode, edge_nan, no_combine,
554 no_subtract, sky_tweak, tbsub, xcal_interpolation, suppress_extension,
555 save_interims, citer, cmin, cmax, collapse_combined,
556 collapse_reconstructed ;
557 double neighborhoodRange, pix_scale, cpos_rej, cneg_rej,
558 velo_offset, velo_corr ;
559 double * velo_corr_ptr ;
560 const char * imethod, * smethod, * cmethod, * comb_method, * fmethod,
561 * sval, * filename, * ifus_txt, * name, * fn_obj_sky_table,
562 * fn_reconstr, * lcmethod ;
563 /*********************/
564
565 double scaling, conversion, f_0, zpoint, dit, angle;
566 int print_once, cube_counter_data, cube_counter_noise, do_sky_subtraction,
567 suppress_index, mapping_id, nb_science, nb_telluric, nb_illum_corr,
568 telluric_ok, actual_msg_level, nr_data, discard_subband,
569 stretch, stretch_degree, stretch_resampling, skip_sky_oh ;
570 int i, j, jj, sf, ifu_nr, sky_ifu_nr, det_nr, ifu_nr_telluric ;
571 char * suffix ;
572 const char * mapping_mode ;
573 char * extname ;
574 char * keyword ;
575 char ** split ;
576 char * fn_suffix ;
577 const char * tmp_str ;
578 const char * fn_obj ;
579 const char * filter_id ;
580 const char * fn_out ;
581
582 /*****************************/
583 /* TO BE CHECKED AND REMOVED */
584 enum kmo_frame_type ft ;
585 char content[256];
586 main_fits_desc desc_telluric, desc1 ;
587 int tmp_int, idx ;
588 /*****************************/
589
590 enum extrapolationType extrapol_enum ;
591 cpl_propertylist * header_tmp ;
592 cpl_propertylist * main_header ;
593 cpl_propertylist * keys_plist ;
594 char * reflex_suffix ;
595 int * qc_output_unit = NULL;
596 int * bounds ;
597 gridDefinition gd ;
598 armNameStruct * arm_name_struct ;
599
600 cpl_propertylist * plist ;
601 cpl_polynomial * oh_lcorr_coeffs ;
602 cpl_vector * ifus ;
603 cpl_array ** unused_ifus_before ;
604 cpl_array ** unused_ifus_after ;
605 cpl_frame * obj_frame ;
606 cpl_frame * illum_frame ;
607 cpl_frame * sky_frame ;
608 cpl_frame * sky_as_object_frame ;
609 cpl_frame * ref_spectrum_frame ;
610 cpl_frame * bpm_frame ;
611 cpl_frame * xcal_frame ;
612 cpl_frame * ycal_frame ;
613 cpl_frame * lcal_frame ;
614 cpl_frame * flat_frame ;
615 cpl_frame * telluric_frame ;
616 cpl_frame * tmp_frame ;
617
618 cpl_table * band_table ;
619
620 cpl_imagelist * combined_data ;
621 cpl_imagelist * combined_noise ;
622 cpl_imagelist * tmp_cube1 ;
623 cpl_imagelist * tmp_cube2 ;
624 cpl_imagelist * new_sky ;
625
626 cpl_image * tmpImg ;
627 cpl_image * exp_mask ;
628 cpl_image * illum_data ;
629
630 cpl_imagelist ** cube_data ;
631 cpl_imagelist ** cube_noise ;
632 cpl_imagelist ** cube_interim_object = NULL;
633 cpl_imagelist ** cube_interim_sky = NULL;
634
635 cpl_propertylist ** header_data ;
636 cpl_propertylist ** header_noise ;
637 cpl_propertylist ** header_sky = NULL;
638
639 kmclipm_vector * telluric_data ;
640 kmclipm_vector * telluric_noise ;
641
642 const char * telluric_tag ;
643 const char * science_tag ;
644
645 /* Check initial Entries */
646 if (kmos_check_and_set_groups(frameset) != CPL_ERROR_NONE) {
647 return cpl_error_get_code();
648 }
649
650 /* Initialise */
651 telluric_tag = TELLURIC ;
652 print_once = FALSE ;
653 cube_counter_data = cube_counter_noise = 0 ;
654 do_sky_subtraction = FALSE ;
655 suppress_index = 0 ;
656 mapping_id = -1 ;
657 combined_data = combined_noise = NULL ;
658 sky_as_object_frame = NULL ;
659
660 /* Get parameters */
661 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.flux");
662 flux = cpl_parameter_get_bool(par);
663 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.background");
664 background = cpl_parameter_get_bool(par);
665 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.lcmethod");
666 lcmethod = cpl_parameter_get_string(par) ;
667 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.imethod");
668 imethod = cpl_parameter_get_string(par) ;
669 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.smethod");
670 smethod = cpl_parameter_get_string(par) ;
671 par = cpl_parameterlist_find_const(parlist,
672 "kmos.kmos_sci_red.neighborhoodRange");
673 neighborhoodRange = cpl_parameter_get_double(par) ;
674 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.method");
675 comb_method = cpl_parameter_get_string(par) ;
676 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.fmethod");
677 fmethod = cpl_parameter_get_string(par) ;
678 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.filename");
679 filename = cpl_parameter_get_string(par) ;
680 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.ifus");
681 ifus_txt = cpl_parameter_get_string(par) ;
682 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.name");
683 name = cpl_parameter_get_string(par) ;
684 kmos_band_pars_load(parlist, "kmos.kmos_sci_red");
685 par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.extrapolate");
686 extrapolate = cpl_parameter_get_bool(par);
687 par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.fast_mode");
688 fast_mode = cpl_parameter_get_bool(par);
689 par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.edge_nan");
690 edge_nan = cpl_parameter_get_bool(par);
691 par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.no_combine");
692 no_combine = cpl_parameter_get_bool(par);
693 par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.no_subtract");
694 no_subtract = cpl_parameter_get_bool(par);
695 par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.sky_tweak");
696 sky_tweak = cpl_parameter_get_bool(par);
697 par = cpl_parameterlist_find_const(parlist,
698 "kmos.kmos_sci_red.skip_sky_oh_align");
699 skip_sky_oh = cpl_parameter_get_bool(par);
700 par = cpl_parameterlist_find_const(parlist,
701 "kmos.kmos_sci_red.discard_subband");
702 discard_subband = cpl_parameter_get_bool(par);
703 par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.stretch_sky");
704 stretch = cpl_parameter_get_bool(par);
705
706 par=cpl_parameterlist_find_const(parlist,
707 "kmos.kmos_sci_red.stretch_degree");
708 stretch_degree = cpl_parameter_get_int(par);
709 par=cpl_parameterlist_find_const(parlist,
710 "kmos.kmos_sci_red.stretch_resampling");
711 sval = cpl_parameter_get_string(par);
712 if (!strcmp(sval, "linear")) {
713 stretch_resampling = 1 ;
714 } else if (!strcmp(sval, "spline")) {
715 stretch_resampling = 2 ;
716 } else {
717 stretch_resampling = -1 ;
718 }
719 par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.tbsub");
720 tbsub = cpl_parameter_get_bool(par);
721 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.pix_scale");
722 pix_scale = cpl_parameter_get_double(par) ;
723 par = cpl_parameterlist_find_const(parlist,
724 "kmos.kmos_sci_red.xcal_interpolation");
725 xcal_interpolation = cpl_parameter_get_bool(par);
726 par = cpl_parameterlist_find_const(parlist,
727 "kmos.kmos_sci_red.suppress_extension");
728 suppress_extension = cpl_parameter_get_bool(par);
729 par = cpl_parameterlist_find_const(parlist,
730 "kmos.kmos_sci_red.obj_sky_table");
731 fn_obj_sky_table = cpl_parameter_get_string(par) ;
732 kmos_combine_pars_load(parlist, "kmos.kmos_sci_red", &cmethod, &cpos_rej,
733 &cneg_rej, &citer, &cmin, &cmax, FALSE);
734 par = cpl_parameterlist_find_const(parlist,
735 "kmos.kmos_sci_red.velocity_offset");
736 velo_offset = cpl_parameter_get_double(par) ;
737 velo_corr = 1. + velo_offset * 1000. / CPL_PHYS_C;
738 velo_corr_ptr = &velo_corr;
739 par = cpl_parameterlist_find_const(parlist,
740 "kmos.kmos_sci_red.save_interims");
741 save_interims = cpl_parameter_get_bool(par);
742 par = cpl_parameterlist_find_const(parlist,
743 "kmos.kmos_sci_red.collapse_combined");
744 collapse_combined = cpl_parameter_get_bool(par);
745 par = cpl_parameterlist_find_const(parlist,
746 "kmos.kmos_sci_red.collapse_reconstructed");
747 collapse_reconstructed = cpl_parameter_get_bool(par);
748
749 /* Check Parameters */
750 /* Only allow to skip the sky OH alignment if the stretching is on */
751 if (stretch == 0) skip_sky_oh = 0 ;
752 if (strcmp(lcmethod, "OSCAN") && strcmp(lcmethod, "SLICES_MEAN") &&
753 strcmp(lcmethod, "SLICES_MEDIAN") && strcmp(lcmethod, "NONE")) {
754 cpl_msg_error(__func__,
755 "lcmethod can be 'NONE', 'OSCAN','SLICES_MEAN' or 'SLICES_MEDIAN'") ;
756 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
757 return -1 ;
758 }
759 if (strcmp(imethod, "NN") && strcmp(imethod, "lwNN") &&
760 strcmp(imethod, "swNN") && strcmp(imethod, "MS") &&
761 strcmp(imethod, "CS")) {
762 cpl_msg_error(__func__,
763 "imethod must be 'NN','lwNN','swNN','MS' or 'CS'") ;
764 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
765 return -1 ;
766 }
767 if (strcmp(smethod, "NN") && strcmp(smethod, "CS")) {
768 cpl_msg_error(__func__,
769 "smethod must be 'NN' or 'CS'") ;
770 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
771 return -1 ;
772 }
773 if (neighborhoodRange <= 0.0) {
774 cpl_msg_error(__func__,
775 "neighborhoodRange must be greater than 0.0") ;
776 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
777 return -1 ;
778 }
779 if (strcmp(comb_method, "none") && strcmp(comb_method, "header") &&
780 strcmp(comb_method, "center") && strcmp(comb_method, "user")) {
781 cpl_msg_error(__func__,
782 "shift methods must be 'none', 'header', 'center' or 'user'") ;
783 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
784 return -1 ;
785 }
786 if (strcmp(ifus_txt, "") && strcmp(name, "")) {
787 cpl_msg_error(__func__,
788 "name and IFU indices cannot be both provided") ;
789 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
790 return -1 ;
791 }
792 if (strcmp(smethod, "NN") && strcmp(smethod, "CS")) {
793 cpl_msg_error(__func__, "smethod must be 'NN' or 'CS'") ;
794 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
795 return -1 ;
796 }
797 if (!strcmp(smethod, "NN") && extrapolate == TRUE) {
798 cpl_msg_error(__func__,
799 "extrapolation in not compatible with smethod 'NN'");
800 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
801 return -1 ;
802 }
803 if (!strcmp(smethod, "CS")) smethod = "BCS";
804 if (!strcmp(smethod, "BCS") && extrapolate == TRUE)
805 extrapol_enum = BCS_NATURAL;
806 else
807 extrapol_enum = NONE_NANS;
808
809 if (no_subtract && sky_tweak) {
810 cpl_msg_error(__func__,"no_subtract and sky_tweak cannot be both TRUE");
811 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
812 return -1 ;
813 }
814 if (sky_tweak == 0 && stretch == 1) {
815 cpl_msg_warning(__func__,"stretch can only be used with sky_tweak");
816 }
817 if (stretch_resampling < 0) {
818 cpl_msg_warning(__func__,
819 "Invalid resampling method specified - use spline") ;
820 stretch_resampling = 2 ;
821 }
822 if (pix_scale < 0.01 || pix_scale > 0.4) {
823 cpl_msg_error(__func__, "pix_scale must be between 0.01 and 0.4");
824 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
825 return -1 ;
826 }
827
828 /* Science frames are either SCIENCE or LEVEL_CORRECTED */
829 if (cpl_frameset_count_tags(frameset, SCIENCE) > 0)
830 science_tag = SCIENCE ;
831 else if (cpl_frameset_count_tags(frameset, LEVEL_CORRECTED) > 0)
832 science_tag = LEVEL_CORRECTED ;
833 else {
834 cpl_msg_error(__func__, "Missing input RAW frames");
835 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
836 return -1 ;
837 }
838
839 if (no_subtract) {
840 no_combine = TRUE;
841 cpl_msg_info(__func__,"--no_combine set to TRUE because --no_subtract");
842 }
843
844 /* Check the inputs consistency */
845 if (kmos_sci_red_check_inputs(frameset, pix_scale, &mapping_id,
846 science_tag) != 1) {
847 cpl_msg_error(__func__, "Input frameset is not consistent") ;
848 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
849 return -1 ;
850 }
851 if (mapping_id == 0) mapping_mode = NULL ;
852 if (mapping_id == 1) mapping_mode = "mapping8" ;
853 if (mapping_id == 2) mapping_mode = "mapping24" ;
854
855 /* Instrument setup */
856 suffix = kmo_dfs_get_suffix(kmo_dfs_get_frame(frameset,science_tag), TRUE,
857 FALSE);
858 cpl_msg_info(__func__, "Detected instrument setup: %s", suffix+1);
859 cpl_free(suffix);
860
861 /* Load IFUS if specified */
862 if (strcmp(ifus_txt, "")) {
863 nb_science = cpl_frameset_count_tags(frameset, science_tag);
864 ifus = kmo_identify_values(ifus_txt);
865 if (ifus == NULL || cpl_vector_get_size(ifus) != nb_science) {
866 if (ifus != NULL) cpl_vector_delete(ifus);
867 cpl_msg_error(__func__, "ifus size must match the science frames") ;
868 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
869 return -1 ;
870 }
871 } else {
872 ifus = NULL ;
873 }
874
875 /* Mapping mode */
876 if (mapping_id > 0) {
877 if ((ifus != NULL) || (strcmp(name, ""))) {
878 cpl_msg_warning(__func__,"Mapping Mode ٍ+ Specific IFUs requested") ;
879 } else {
880 if (!strcmp(smethod, "BCS")) {
881 extrapol_enum = BCS_NATURAL;
882 cpl_msg_info(__func__, "Mapping Mode : extrapolation set") ;
883 }
884 }
885 }
886
887 /* Check which IFUs are active for all frames */
888 unused_ifus_before = kmo_get_unused_ifus(frameset, 1, 1);
889 unused_ifus_after = kmo_duplicate_unused_ifus(unused_ifus_before);
890 kmo_print_unused_ifus(unused_ifus_before, FALSE);
891 kmo_free_unused_ifus(unused_ifus_before);
892
893 /* Setup grid definition, wavelength start and end are set later */
894 kmclipm_setup_grid(&gd, imethod, neighborhoodRange, pix_scale, 0.);
895
896 /* Get frames */
897 bpm_frame = kmo_dfs_get_frame(frameset, BADPIXEL_DARK) ;
898 xcal_frame = kmo_dfs_get_frame(frameset, XCAL) ;
899 ycal_frame = kmo_dfs_get_frame(frameset, YCAL) ;
900 lcal_frame = kmo_dfs_get_frame(frameset, LCAL) ;
901 flat_frame = kmo_dfs_get_frame(frameset, MASTER_FLAT) ;
902 ref_spectrum_frame = kmo_dfs_get_frame(frameset, OH_SPEC) ;
903 nb_illum_corr = cpl_frameset_count_tags(frameset, ILLUM_CORR);
904
905 /*Getting MASTER_FLAT MJD-OBS*/
906 cpl_propertylist *flat_properties =
907 kmclipm_propertylist_load(
908 cpl_frame_get_filename(flat_frame),0);
909 double flat_mjd = kmos_pfits_get_mjd_obs(flat_properties);
910 cpl_propertylist_delete(flat_properties);
911 double tel_gen_mjd = 0.0;
912
913 /* Get left and right bounds of IFUs from XCAL */
914 header_tmp = kmo_dfs_load_primary_header(frameset, XCAL);
915 bounds = kmclipm_extract_bounds(header_tmp);
916 cpl_propertylist_delete(header_tmp);
917 if (bounds == NULL) {
918 if (ifus != NULL) cpl_vector_delete(ifus);
919 kmo_free_unused_ifus(unused_ifus_after);
920 cpl_msg_error(__func__, "Cannot compute bounds") ;
921 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
922 return -1 ;
923 }
924
925 /* armNameStruct: objects that need to be reconstructed and their
926 associated sky. Valid STD frames with objects and associated sky.
927 Get valid object names, either one object name in several frames,
928 or all object names */
929 if (!strcmp(fn_obj_sky_table, "")) {
930 arm_name_struct = kmo_create_armNameStruct(frameset, science_tag, ifus,
931 name, unused_ifus_after, bounds, mapping_mode, no_subtract);
932 /* TODO : need to save ?? */
933 kmo_save_objSkyStruct(arm_name_struct->obj_sky_struct);
934 } else {
935 // read in obj/sky-table
936 objSkyStruct *obj_sky_struct = NULL;
937 obj_sky_struct = kmo_read_objSkyStruct(fn_obj_sky_table, frameset,
938 science_tag);
939
940 /* Check if any sky-IFUs have been specified not beeing the */
941 /* same IFU# for objects. */
942 // In this case sky_tweak must be activated
943 for (i = 0; i < obj_sky_struct->size; i++) {
944 if (obj_sky_struct->table[i].objFrame != NULL) {
945 for (j = 0; j < KMOS_NR_IFUS; j++) {
946 if ((obj_sky_struct->table[i].skyIfus[j] > 0) &&
947 (sky_tweak == FALSE)) {
948 kmo_print_objSkyStruct(obj_sky_struct);
949 kmo_delete_objSkyStruct(obj_sky_struct);
950 cpl_msg_error(__func__,
951 "--sky_tweak needs to be set when sky are used from other IFUs");
952 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
953 return -1 ;
954 }
955 }
956 }
957 }
958 arm_name_struct = kmo_create_armNameStruct2(obj_sky_struct, frameset,
959 science_tag, ifus, name, unused_ifus_after, bounds,
960 mapping_mode, no_subtract);
961 }
962 if (ifus != NULL) cpl_vector_delete(ifus);
963 if (arm_name_struct == NULL) {
964 kmo_free_unused_ifus(unused_ifus_after);
965 cpl_free(bounds);
966 cpl_msg_error(__func__, "Cannot compute ARM/name structure") ;
967 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
968 return -1 ;
969 }
970 kmo_print_armNameStruct(frameset, arm_name_struct);
971
972 /* Check Telluric availability for each Object */
973 /* in mapping-mode check if for all IFUs there is either no */
974 /* telluric at all or the same number of tellurics than object names */
975 nb_telluric = cpl_frameset_count_tags(frameset, TELLURIC_GEN);
976 if (nb_telluric == 0) {
977 nb_telluric = cpl_frameset_count_tags(frameset, telluric_tag);
978 } else {
979 telluric_tag = TELLURIC_GEN ;
980 }
981 if (nb_telluric > 0 && mapping_id > 0) {
982 for (i = 0; i < arm_name_struct->nrNames; i++) {
983 if (arm_name_struct->telluricCnt[i] != arm_name_struct->namesCnt[i]
984 && (arm_name_struct->telluricCnt[i] != 0)) {
985 cpl_msg_error(__func__, "Mosaics need a telluric per detector");
986 cpl_error_set(__func__, CPL_ERROR_UNSUPPORTED_MODE) ;
987 return -1 ;
988 }
989 }
990 }
991
992 /* Allocate data */
993 cube_data=(cpl_imagelist**)cpl_calloc(KMOS_NR_IFUS, sizeof(cpl_imagelist*));
994 cube_noise=(cpl_imagelist**)cpl_calloc(KMOS_NR_IFUS,sizeof(cpl_imagelist*));
995 header_data = (cpl_propertylist**)cpl_calloc(KMOS_NR_IFUS,
996 sizeof(cpl_propertylist*));
997 header_noise = (cpl_propertylist**)cpl_calloc(KMOS_NR_IFUS,
998 sizeof(cpl_propertylist*));
999 if (save_interims) {
1000 cube_interim_object=(cpl_imagelist**)cpl_calloc(KMOS_NR_IFUS,
1001 sizeof(cpl_imagelist*));
1002 cube_interim_sky =(cpl_imagelist**)cpl_calloc(KMOS_NR_IFUS,
1003 sizeof(cpl_imagelist*));
1004 header_sky = (cpl_propertylist**)cpl_calloc(KMOS_NR_IFUS,
1005 sizeof(cpl_propertylist*));
1006 }
1007
1008 cpl_size pers_nr = 0;
1009 cpl_size sat_nr = 0;
1010
1011 /* Loop all science frames containing at least one object */
1012 cpl_msg_info(__func__, "Reconstructing & saving cubes with objects");
1013 for (sf = 0; sf < arm_name_struct->size; sf++) {
1014 fn_obj = cpl_frame_get_filename(
1015 arm_name_struct->obj_sky_struct->table[sf].objFrame);
1016 if ((main_header = kmclipm_propertylist_load(fn_obj, 0)) == NULL) {
1017 kmo_free_unused_ifus(unused_ifus_after);
1018 cpl_free(bounds);
1019 kmo_delete_armNameStruct(arm_name_struct);
1020
1021 if (qc_output_unit) cpl_free(qc_output_unit) ;
1022
1023 cpl_free(cube_data) ;
1024 cpl_free(cube_noise) ;
1025 cpl_free(header_data) ;
1026 cpl_free(header_noise) ;
1027
1028 if (cube_interim_object) cpl_free(cube_interim_object) ;
1029 if (cube_interim_sky ) cpl_free(cube_interim_sky ) ;
1030 if (header_sky ) cpl_free(header_sky ) ;
1031
1032 cpl_msg_error(__func__, "Cannot Load main header");
1033 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
1034 return -1 ;
1035 }
1036 actual_msg_level = cpl_msg_get_level();
1037
1038 /* Hold the QC parameter */
1039 qc_output_unit = cpl_calloc(KMOS_NR_IFUS, sizeof(int)) ;
1040
1041
1042 /* Reconstruct science frame */
1043 cpl_msg_info(__func__, " > processing frame: %s", fn_obj);
1044 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
1045
1046 /* Initialise */
1047 cube_data[ifu_nr-1] = cube_noise[ifu_nr-1] = NULL ;
1048
1049 sky_ifu_nr = ifu_nr;
1050 det_nr = (ifu_nr - 1)/KMOS_IFUS_PER_DETECTOR + 1;
1051 if (det_nr == 0) {
1052 sat_nr = 0;
1053 pers_nr = 0;
1054 }
1055
1056 /* Get subheader data */
1057 header_data[ifu_nr-1] = kmclipm_propertylist_load(fn_obj, det_nr);
1058 extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_DATA);
1059 kmclipm_update_property_string(header_data[ifu_nr-1],
1060 EXTNAME, extname, "FITS extension name");
1061 cpl_free(extname);
1062
1063 /* Inherit some QCs */
1064 kmos_sci_red_propagate_qc(main_header, header_data[ifu_nr-1],
1065 lcal_frame, det_nr) ;
1066
1067 if (arm_name_struct->name_ids[ifu_nr-1+sf*KMOS_NR_IFUS] >= 1) {
1068 // IFU is valid
1069
1070 cpl_image * sci_image = kmclipm_image_load(fn_obj, CPL_TYPE_FLOAT, 0, det_nr);
1071 cpl_mask * sat_mask = cpl_mask_threshold_image_create(sci_image, QC_SAT_LEVEL_SCI_RED, INFINITY );
1072 cpl_mask * pers_mask = cpl_mask_threshold_image_create(sci_image, QC_PERS_LEVEL_VAL, INFINITY);
1073 sat_nr = (cpl_mask_count(sat_mask) >= sat_nr)? cpl_mask_count(sat_mask): sat_nr;
1074 pers_nr = (cpl_mask_count(pers_mask) >= pers_nr)? cpl_mask_count(pers_mask): pers_nr;
1075
1076 cpl_msg_info(__func__, "Saturated number: %lld, Persistance number : %lld", sat_nr, pers_nr);
1077
1078 cpl_image_delete(sci_image);
1079 cpl_mask_delete(sat_mask);
1080 cpl_mask_delete(pers_mask);
1081
1082
1083 /* Fill sky_as_object_frame, do_sky_subtraction and sky_frame */
1084 sky_as_object_frame = NULL ;
1085 if ((arm_name_struct->obj_sky_struct->table[sf].skyFrames[ifu_nr-1] != NO_CORRESPONDING_SKYFRAME) && !no_subtract) {
1086 do_sky_subtraction = TRUE;
1087 if (no_subtract) sky_frame = NULL;
1088 else sky_frame =
1089 arm_name_struct->obj_sky_struct->table[sf].skyFrames[ifu_nr-1];
1090
1091 if (sky_tweak){
1092 sky_as_object_frame = sky_frame;
1093 sky_frame = NULL;
1094 sky_ifu_nr = arm_name_struct->obj_sky_struct->table[sf].skyIfus[ifu_nr-1];
1095 }
1096 } else {
1097 do_sky_subtraction = FALSE;
1098 sky_frame = NULL;
1099 }
1100
1101 /* Get filter and setup grid definition using WAVE_BAND */
1102 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, det_nr,
1103 IFU_FILTID_POSTFIX);
1104 filter_id = cpl_propertylist_get_string(main_header, keyword);
1105 cpl_free(keyword);
1106
1107 if (print_once) cpl_msg_set_level(CPL_MSG_WARNING);
1108 print_once = TRUE;
1109
1110 band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, 0);
1111 kmclipm_setup_grid_band_lcal(&gd, filter_id, band_table);
1112 cpl_table_delete(band_table);
1113
1114 cpl_msg_set_level(actual_msg_level);
1115
1116 /* calc WCS & update subheader */
1117 kmo_calc_wcs_gd(main_header, header_data[ifu_nr-1], ifu_nr, gd);
1118
1119 /* Update some keywords */
1120 kmclipm_update_property_int(header_data[ifu_nr-1], NAXIS, 3,
1121 "number of data axes");
1122 kmclipm_update_property_int(header_data[ifu_nr-1], NAXIS1,
1123 gd.x.dim, "length of data axis 1");
1124 kmclipm_update_property_int(header_data[ifu_nr-1], NAXIS2,
1125 gd.y.dim, "length of data axis 2");
1126 kmclipm_update_property_int(header_data[ifu_nr-1], NAXIS3,
1127 gd.l.dim, "length of data axis 3");
1128
1129 /* Option save_interim only applies if sky_tweak is used */
1130 if (save_interims && sky_as_object_frame != NULL) {
1131 header_tmp = kmclipm_propertylist_load(
1132 cpl_frame_get_filename(sky_as_object_frame), 0);
1133
1134 header_sky[ifu_nr-1]=kmclipm_propertylist_load(
1135 cpl_frame_get_filename(sky_as_object_frame),det_nr);
1136 extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_DATA);
1137 kmclipm_update_property_string(header_sky[ifu_nr-1],
1138 EXTNAME, extname, "FITS extension name");
1139 cpl_free(extname);
1140
1141 kmo_calc_wcs_gd(header_tmp, header_sky[ifu_nr-1],
1142 ifu_nr, gd);
1143 kmclipm_update_property_int(header_sky[ifu_nr-1], NAXIS, 3,
1144 "number of data axes");
1145 kmclipm_update_property_int(header_sky[ifu_nr-1], NAXIS1,
1146 gd.x.dim, "length of data axis 1");
1147 kmclipm_update_property_int(header_sky[ifu_nr-1], NAXIS2,
1148 gd.y.dim, "length of data axis 2");
1149 kmclipm_update_property_int(header_sky[ifu_nr-1], NAXIS3,
1150 gd.l.dim, "length of data axis 3");
1151 cpl_propertylist_delete(header_tmp);
1152 }
1153
1154 /* OH lines based lambda correction */
1155 oh_lcorr_coeffs = NULL ;
1156 if (ref_spectrum_frame != NULL) {
1157 if (kmo_reconstruct_sci(ifu_nr, bounds[2*(ifu_nr-1)],
1158 bounds[2*(ifu_nr-1)+1],
1159 arm_name_struct->obj_sky_struct->table[sf].objFrame,
1160 science_tag, NULL, NULL, flat_frame, bpm_frame,
1161 xcal_frame, ycal_frame, lcal_frame, NULL, NULL,
1162 &gd, &tmp_cube1, &tmp_cube2, FALSE, FALSE,
1163 xcal_interpolation, lcmethod) == CPL_ERROR_NONE) {
1164 oh_lcorr_coeffs = kmo_lcorr_get(tmp_cube1,
1165 header_data[ifu_nr-1], ref_spectrum_frame, gd,
1166 filter_id, ifu_nr);
1167 cpl_imagelist_delete(tmp_cube1);
1168 cpl_imagelist_delete(tmp_cube2);
1169 }
1170 }
1171
1172 /* Reconstruct object */
1173 kmo_reconstruct_sci(ifu_nr, bounds[2*(ifu_nr-1)],
1174 bounds[2*(ifu_nr-1)+1],
1175 arm_name_struct->obj_sky_struct->table[sf].objFrame,
1176 science_tag, sky_frame, science_tag, flat_frame,
1177 bpm_frame, xcal_frame, ycal_frame, lcal_frame,
1178 oh_lcorr_coeffs, velo_corr_ptr, &gd,
1179 &cube_data[ifu_nr-1], &cube_noise[ifu_nr-1], flux,
1180 background, xcal_interpolation, lcmethod);
1181
1182 if (oh_lcorr_coeffs != NULL)
1183 cpl_polynomial_delete(oh_lcorr_coeffs);
1184
1185 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1186 kmo_free_unused_ifus(unused_ifus_after);
1187 cpl_free(bounds);
1188 kmo_delete_armNameStruct(arm_name_struct);
1189 for (j=0 ; j<ifu_nr-1 ; j++) {
1190 if (cube_data[j] != NULL)
1191 cpl_imagelist_delete(cube_data[j]);
1192 if (cube_noise[j] != NULL)
1193 cpl_imagelist_delete(cube_noise[j]);
1194 cpl_propertylist_delete(header_data[j]);
1195 cpl_propertylist_delete(header_noise[j]);
1196 if (save_interims) {
1197 cpl_imagelist_delete(cube_interim_object[j]);
1198 cpl_imagelist_delete(cube_interim_sky[j]);
1199 cpl_propertylist_delete(header_sky[j]);
1200 }
1201 }
1202 cpl_propertylist_delete(header_data[ifu_nr-1]);
1203 cpl_free(cube_data) ;
1204 cpl_free(cube_noise) ;
1205 cpl_free(header_data) ;
1206 cpl_free(header_noise) ;
1207 if (save_interims) {
1208 cpl_free(cube_interim_object) ;
1209 cpl_free(cube_interim_sky) ;
1210 cpl_free(header_sky) ;
1211 }
1212 cpl_msg_error(__func__, "Cannot reconstruct");
1213 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
1214 return -1 ;
1215 }
1216
1217 /* If sky_tweak is set, reconstruct sky frame as object */
1218 /* use kmos_priv_sky_tweak to subtract a modified sky cube */
1219 if (do_sky_subtraction && sky_tweak) {
1220
1221 /* OH lines based lambda correction */
1222 oh_lcorr_coeffs = NULL ;
1223 if (ref_spectrum_frame != NULL && skip_sky_oh == 0) {
1224 if (kmo_reconstruct_sci(sky_ifu_nr,
1225 bounds[2*(sky_ifu_nr-1)],
1226 bounds[2*(sky_ifu_nr-1)+1],
1227 sky_as_object_frame, science_tag, NULL,
1228 NULL, flat_frame, bpm_frame, xcal_frame,
1229 ycal_frame, lcal_frame, NULL, NULL, &gd,
1230 &tmp_cube1, &tmp_cube2, FALSE, FALSE,
1231 xcal_interpolation,
1232 lcmethod) == CPL_ERROR_NONE) {
1233 oh_lcorr_coeffs = kmo_lcorr_get(tmp_cube1,
1234 header_data[ifu_nr-1], ref_spectrum_frame,
1235 gd, filter_id, ifu_nr);
1236 cpl_imagelist_delete(tmp_cube1);
1237 cpl_imagelist_delete(tmp_cube2);
1238 }
1239 }
1240
1241 /* Reconstruct object */
1242 kmo_reconstruct_sci(sky_ifu_nr,
1243 bounds[2*(sky_ifu_nr-1)],
1244 bounds[2*(sky_ifu_nr-1)+1], sky_as_object_frame,
1245 science_tag, sky_frame, science_tag, flat_frame,
1246 bpm_frame, xcal_frame, ycal_frame, lcal_frame,
1247 oh_lcorr_coeffs, velo_corr_ptr, &gd, &tmp_cube1,
1248 &tmp_cube2, flux, background, xcal_interpolation,
1249 lcmethod);
1250
1251 cpl_imagelist_delete(tmp_cube2);
1252 if (oh_lcorr_coeffs != NULL)
1253 cpl_polynomial_delete(oh_lcorr_coeffs);
1254
1255 if (save_interims && (sky_as_object_frame != NULL)) {
1256 cube_interim_object[ifu_nr-1]=
1257 cpl_imagelist_duplicate(cube_data[ifu_nr-1]);
1258 cube_interim_sky[ifu_nr-1]=
1259 cpl_imagelist_duplicate(tmp_cube1);
1260 }
1261
1262 /* Apply the SKY tweaking */
1263 tmp_cube2 = kmos_priv_sky_tweak(cube_data[ifu_nr-1],
1264 tmp_cube1, header_data[ifu_nr-1], .3, tbsub,
1265 discard_subband, stretch, stretch_degree,
1266 stretch_resampling, 0, &new_sky);
1267 cpl_imagelist_delete(cube_data[ifu_nr-1]);
1268 cpl_imagelist_delete(tmp_cube1);
1269 cpl_imagelist_delete(new_sky);
1270 cube_data[ifu_nr-1] = tmp_cube2 ;
1271 }
1272
1273 if (ifu_nr == 1) {
1274 /* kmos_plot_cube_background(cube_data[ifu_nr-1]) ; */
1275 }
1276
1277 /* Maintain flux constant in case the pixscale is diff */
1278 /* For example, pixscale=0.1 => images 28x28 => scaling=4 */
1279 tmpImg = cpl_imagelist_get(cube_data[ifu_nr-1], 0);
1280 scaling = (cpl_image_get_size_x(tmpImg) *
1281 cpl_image_get_size_y(tmpImg)) /
1282 (KMOS_SLITLET_X*KMOS_SLITLET_Y);
1283 cpl_imagelist_divide_scalar(cube_data[ifu_nr-1], scaling);
1284 if (cube_noise[ifu_nr-1] != NULL) {
1285 cpl_imagelist_divide_scalar(cube_noise[ifu_nr-1], scaling);
1286 }
1287
1288 /* Divide cube by telluric correction */
1289 qc_output_unit[ifu_nr-1] = 0 ;
1290 if (nb_telluric > 0) {
1291 /* Create the mapping string */
1292 if (mapping_id == 0) {
1293 /* Get object name */
1294 keyword = cpl_sprintf("%s%d%s", IFU_NAME_PREFIX,
1295 ifu_nr, IFU_NAME_POSTFIX);
1296 tmp_str = cpl_propertylist_get_string(
1297 header_data[ifu_nr-1], keyword);
1298 cpl_free(keyword);
1299 } else if (mapping_id == 1) {
1300 tmp_str = "mapping8";
1301 } else if (mapping_id == 2) {
1302 tmp_str = "mapping24";
1303 }
1304
1305 /* Check if the nb of occurences of the object name */
1306 /* is the same as the number of found tellurics for */
1307 /* this object (which can be on different arms) */
1308 telluric_ok = FALSE;
1309 for (jj = 0; jj < arm_name_struct->nrNames; jj++) {
1310 if ((!strcmp(arm_name_struct->names[jj], tmp_str) ||
1311 !strcmp(arm_name_struct->names[jj], IFUS_USER_DEFINED)) &&
1312 arm_name_struct->telluricCnt[jj] == arm_name_struct->namesCnt[jj]) {
1313 telluric_ok = TRUE;
1314 break;
1315 }
1316 }
1317
1318 if (telluric_ok) {
1319 telluric_data = kmo_tweak_load_telluric(frameset,
1320 ifu_nr, FALSE, no_subtract,
1321 telluric_tag, &ifu_nr_telluric);
1322 if (telluric_data != NULL) {
1323 telluric_frame =
1324 kmo_dfs_get_frame(frameset, telluric_tag);
1325 kmo_init_fits_desc(&desc_telluric);
1326
1327 /*Get TELLURIC GEN mjd-obs*/
1328
1329 cpl_propertylist *telluric_plist =
1330 kmclipm_propertylist_load(
1331 cpl_frame_get_filename(
1332 telluric_frame),0);
1333 tel_gen_mjd = kmos_pfits_get_mjd_obs(telluric_plist);
1334 cpl_propertylist_delete(telluric_plist);
1335
1336 desc_telluric=kmo_identify_fits_header(
1337 cpl_frame_get_filename(telluric_frame));
1338
1339 /* Get the index of the telluric noise */
1340 idx = kmo_identify_index_desc(desc_telluric,
1341 ifu_nr, TRUE);
1342 if (desc_telluric.sub_desc[idx-1].valid_data) {
1343 /* Load noise if present */
1344 telluric_noise = kmo_tweak_load_telluric(
1345 frameset,ifu_nr, TRUE, no_subtract,
1346 telluric_tag, &ifu_nr_telluric);
1347 } else {
1348 telluric_noise = NULL ;
1349 }
1350 kmo_free_fits_desc(&desc_telluric);
1351
1352 kmo_arithmetic_3D_1D(cube_data[ifu_nr-1],
1353 telluric_data, cube_noise[ifu_nr-1],
1354 telluric_noise, "/");
1355 if (telluric_noise != NULL)
1356 kmclipm_vector_delete(telluric_noise);
1357 kmclipm_vector_delete(telluric_data);
1358
1359 /* Convert to ERG if zpoint available */
1360 zpoint = kmos_sci_red_get_zpoint(telluric_frame,
1361 ifu_nr_telluric) ;
1362 if (zpoint > 0.0) {
1363 f_0 = kmos_sci_red_get_f0(filter_id, gd.l.dim,
1364 gd.l.start, gd.l.delta) ;
1365 if (f_0 > 0.0) {
1366 conversion = f_0*pow(10,-0.4*zpoint)/10.0 ;
1367 cpl_msg_info(__func__,
1368 "Apply Unit conversion factor %g for IFU nb %d",
1369 conversion, ifu_nr) ;
1370 kmo_arithmetic_3D_scalar(
1371 cube_data[ifu_nr-1], conversion,
1372 cube_noise[ifu_nr-1], "*") ;
1373 qc_output_unit[ifu_nr-1] = 1 ;
1374 }
1375 }
1376 }
1377 }
1378 }
1379
1380 /* Divide cube by illumination correction */
1381 /* Illumination noise small versus noise - skipped */
1382 if (nb_illum_corr > 0) {
1383 obj_frame =
1384 arm_name_struct->obj_sky_struct->table[sf].objFrame ;
1385 plist = kmclipm_propertylist_load(
1386 cpl_frame_get_filename(obj_frame), 0) ;
1387 angle = kmo_dfs_get_property_double(plist, ROTANGLE);
1388 cpl_propertylist_delete(plist);
1389
1390 illum_frame = kmo_dfs_get_frame(frameset, ILLUM_CORR);
1391 double dummy1 ;
1392 illum_data = kmos_illum_load(
1393 cpl_frame_get_filename(illum_frame),
1394 CPL_TYPE_FLOAT, ifu_nr, angle, &dummy1) ;
1395 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1396 cpl_msg_warning(__func__,
1397 "No illumination correction for IFU %d available! "
1398 "Proceeding anyway.", ifu_nr);
1399 if (illum_data != NULL) cpl_image_delete(illum_data);
1400 cpl_error_reset();
1401 } else {
1402 kmo_arithmetic_3D_2D(cube_data[ifu_nr-1], illum_data,
1403 cube_noise[ifu_nr-1], NULL, "/");
1404 cpl_image_delete(illum_data);
1405 }
1406 }
1407 }
1408
1409 /* Duplicate subheader data */
1410 header_noise[ifu_nr-1] = cpl_propertylist_duplicate(
1411 header_data[ifu_nr-1]);
1412 extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_NOISE);
1413 kmclipm_update_property_string(header_noise[ifu_nr-1], EXTNAME,
1414 extname, "FITS extension name");
1415 cpl_free(extname);
1416 }
1417
1418 /* Convert from ADU->ADU/sec by dividing by DIT */
1419 plist = cpl_propertylist_load(cpl_frame_get_filename(
1420 arm_name_struct->obj_sky_struct->table[sf].objFrame), 0);
1421 dit = kmos_pfits_get_dit(plist) ;
1422 cpl_propertylist_delete(plist) ;
1423 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
1424 /* Data / DIT */
1425 if (cube_data[ifu_nr-1] != NULL) {
1426 kmo_arithmetic_3D_scalar(cube_data[ifu_nr-1], dit,
1427 cube_noise[ifu_nr-1], "/") ;
1428 }
1429 }
1430
1431 /* Count number of reconstructed data- and noise-cubes */
1432 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
1433 if (cube_data[ifu_nr-1] != NULL) cube_counter_data++;
1434 if (cube_noise[ifu_nr-1] != NULL) cube_counter_noise++;
1435 }
1436
1437 /* Save reconstructed cubes of science frame */
1438 if (cube_counter_data > 0) {
1439 cpl_msg_info(__func__, " > saving...");
1440
1441 if (!suppress_extension) {
1442 fn_out = fn_obj;
1443
1444 int nr_found = 0;
1445 // remove any path-elements from filename and use it as suffix
1446 split = kmo_strsplit(fn_out, "/", &nr_found);
1447 fn_suffix = cpl_sprintf("_%s", split[nr_found-1]);
1448 kmo_strfreev(split);
1449
1450 // remove '.fits' at the end if there is any
1451 char *fff = fn_suffix;
1452 fff += strlen(fn_suffix)-5;
1453 if (strcmp(fff, ".fits") == 0) {
1454 fn_suffix[strlen(fn_suffix)-5] = '\0';
1455 }
1456 } else {
1457 fn_suffix = cpl_sprintf("_%d", suppress_index++);
1458 }
1459
1460 fn_out = RECONSTRUCTED_CUBE;
1461
1462 /* Add REFLEX SUFFIX keyword */
1463 keys_plist = cpl_propertylist_new() ;
1464 reflex_suffix = cpl_strdup(kmos_pfits_get_arcfile(main_header)) ;
1465 if (strlen(reflex_suffix) > 5)
1466 reflex_suffix[strlen(reflex_suffix)-5] = '\0' ;
1467 cpl_propertylist_update_string(keys_plist, "ESO PRO REFLEX SUFFIX",
1468 reflex_suffix) ;
1469 cpl_free(reflex_suffix) ;
1470
1471 /* Add PRO MJD-OBS */
1472 cpl_propertylist_update_double(keys_plist, PRO_MJD_OBS,
1473 kmos_pfits_get_mjd_obs(main_header)) ;
1474
1475 /* Add PRO DATE-OBS */
1476 cpl_propertylist_update_string(keys_plist, PRO_DATE_OBS,
1477 kmos_pfits_get_date_obs(main_header)) ;
1478
1479 /* Add QC Parameters */
1480 cpl_propertylist_update_double(keys_plist, QC_SAT_LEVEL,
1481 QC_SAT_LEVEL_SCI_RED) ;
1482 cpl_propertylist_update_int(keys_plist, QC_SAT_NB,
1483 sat_nr) ;
1484 cpl_propertylist_update_double(keys_plist, QC_PERS_LEVEL,
1485 QC_PERS_LEVEL_VAL) ;
1486 cpl_propertylist_update_int(keys_plist, QC_PERS_NB,
1487 pers_nr) ;
1488
1489 /*QC Parameters to be used in kmos_combine*/
1490 cpl_propertylist_update_double(keys_plist, QC_MASTER_FLAT_MJD_OBS,
1491 flat_mjd ) ;
1492 cpl_propertylist_update_double(keys_plist, QC_TELLURIC_GEN_MJD_OBS,
1493 tel_gen_mjd ) ;
1494
1495
1496 /* Create Primary Header */
1497 kmo_dfs_save_main_header(frameset, fn_out, fn_suffix,
1498 arm_name_struct->obj_sky_struct->table[sf].objFrame,
1499 keys_plist, parlist, cpl_func);
1500 cpl_propertylist_delete(keys_plist) ;
1501
1502 /* save intermediate products (only in sky tweak case) */
1503 if (save_interims && (sky_as_object_frame != NULL)) {
1504 kmo_dfs_save_main_header(frameset, INTERIM_OBJECT_CUBE,
1505 fn_suffix,
1506 arm_name_struct->obj_sky_struct->table[sf].objFrame,
1507 NULL, parlist, cpl_func);
1508 kmo_dfs_save_main_header(frameset, INTERIM_OBJECT_SKY,
1509 fn_suffix,
1510 arm_name_struct->obj_sky_struct->table[sf].objFrame,
1511 NULL, parlist, cpl_func);
1512 }
1513
1514 /* Loop on IFUs */
1515 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
1516
1517 /* Hold the QC */
1518 if (qc_output_unit[ifu_nr-1] == 0) {
1519 kmclipm_update_property_string(header_data[ifu_nr-1],
1520 "ESO QC CUBE_UNIT", "ADU/sec", "Cube Unit");
1521 if (header_noise[ifu_nr-1] != NULL)
1522 kmclipm_update_property_string(header_noise[ifu_nr-1],
1523 "ESO QC CUBE_UNIT", "ADU/sec", "Cube Unit");
1524 } else {
1525 kmclipm_update_property_string(header_data[ifu_nr-1],
1526 "ESO QC CUBE_UNIT",
1527 "erg.s**(-1).cm**(-2).angstrom**(-1)", "Cube Unit");
1528 if (header_noise[ifu_nr-1] != NULL)
1529 kmclipm_update_property_string(header_noise[ifu_nr-1],
1530 "ESO QC CUBE_UNIT",
1531 "erg.s**(-1).cm**(-2).angstrom**(-1)",
1532 "Cube Unit");
1533 }
1534
1535 /* Save data Extension */
1536 if (cube_data[ifu_nr-1] == NULL)
1537 kmos_all_clean_plist(header_data[ifu_nr-1]) ;
1538 kmo_dfs_save_cube(cube_data[ifu_nr-1], fn_out, fn_suffix,
1539 header_data[ifu_nr-1], 0./0.);
1540 cpl_imagelist_delete(cube_data[ifu_nr-1]);
1541 cube_data[ifu_nr-1] = NULL ;
1542
1543 /* Save noise Extension */
1544 if (cube_counter_noise > 0) {
1545 if (cube_noise[ifu_nr-1] == NULL)
1546 kmos_all_clean_plist(header_noise[ifu_nr-1]) ;
1547 kmo_dfs_save_cube(cube_noise[ifu_nr-1], fn_out, fn_suffix,
1548 header_noise[ifu_nr-1], 0./0.);
1549 }
1550 cpl_propertylist_delete(header_noise[ifu_nr-1]);
1551 header_noise[ifu_nr-1] = NULL ;
1552 cpl_imagelist_delete(cube_noise[ifu_nr-1]);
1553 cube_noise[ifu_nr-1] = NULL ;
1554
1555 /* save intermediate products (only in sky tweak case */
1556 if (save_interims && (sky_as_object_frame != NULL)) {
1557 kmo_dfs_save_cube(cube_interim_object[ifu_nr-1],
1558 INTERIM_OBJECT_CUBE, fn_suffix,
1559 header_data[ifu_nr-1], 0./0.);
1560 kmo_dfs_save_cube(cube_interim_sky[ifu_nr-1],
1561 INTERIM_OBJECT_SKY, fn_suffix, header_sky[ifu_nr-1],
1562 0./0.);
1563 }
1564 cpl_propertylist_delete(header_data[ifu_nr-1]);
1565 header_data[ifu_nr-1] = NULL ;
1566 if (save_interims) {
1567 cpl_imagelist_delete(cube_interim_object[ifu_nr-1]);
1568 cube_interim_object[ifu_nr-1] = NULL ;
1569 cpl_imagelist_delete(cube_interim_sky[ifu_nr-1]);
1570 cube_interim_sky[ifu_nr-1] = NULL ;
1571 cpl_propertylist_delete(header_sky[ifu_nr-1]);
1572 header_sky[ifu_nr-1] = NULL ;
1573 }
1574 }
1575 cpl_free(fn_suffix);
1576 } else {
1577 cpl_msg_info(__func__, " > all IFUs invalid, don't save");
1578 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
1579 cpl_propertylist_delete(header_data[ifu_nr-1]);
1580 header_data[ifu_nr-1] = NULL ;
1581 cpl_propertylist_delete(header_noise[ifu_nr-1]);
1582 header_noise[ifu_nr-1] = NULL ;
1583 }
1584 }
1585 cpl_propertylist_delete(main_header) ;
1586 cpl_free(qc_output_unit) ;
1587 }
1588 cpl_free(bounds) ;
1589 cpl_free(cube_data);
1590 cpl_free(cube_noise);
1591 cpl_free(header_data);
1592 cpl_free(header_noise);
1593 if (save_interims) {
1594 cpl_free(cube_interim_object);
1595 cpl_free(cube_interim_sky);
1596 cpl_free(header_sky);
1597 }
1598
1599 kmo_print_unused_ifus(unused_ifus_after, TRUE);
1600 kmo_free_unused_ifus(unused_ifus_after);
1601
1602 /***********/
1603 /* Combine */
1604 /***********/
1605 suppress_index = 0;
1606 if (!no_combine) {
1607 cpl_msg_info(__func__, "Combining reconstructed objects");
1608 if (mapping_id==0 || (mapping_id>0 && (strcmp(ifus_txt, "") ||
1609 strcmp(name,"")))){
1610 /* Loop all available objects */
1611 for (i = 0; i < arm_name_struct->nrNames; i++) {
1612 cpl_msg_info(__func__,
1613 " > object: %s", arm_name_struct->names[i]);
1614 nr_data = arm_name_struct->namesCnt[i];
1615 cube_data=(cpl_imagelist**)cpl_calloc(nr_data,
1616 sizeof(cpl_imagelist*));
1617 cube_noise=(cpl_imagelist**)cpl_calloc(nr_data,
1618 sizeof(cpl_imagelist*));
1619 header_data=(cpl_propertylist**)cpl_calloc(nr_data,
1620 sizeof(cpl_propertylist*));
1621 header_noise=(cpl_propertylist**)cpl_calloc(nr_data,
1622 sizeof(cpl_propertylist*));
1623
1624 /* Initialise */
1625 for (jj = 0; jj < nr_data; jj++) {
1626 cube_data[jj] = NULL ;
1627 cube_noise[jj] = NULL ;
1628 header_data[jj] = NULL ;
1629 header_noise[jj] = NULL ;
1630 }
1631
1632 // setup cube-list and header-list for kmo_priv_combine()
1633 cube_counter_data = 0;
1634 cube_counter_noise = 0;
1635 tmp_frame = kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE);
1636 while (tmp_frame != NULL ) {
1637 fn_reconstr = cpl_frame_get_filename(tmp_frame);
1638 main_header = kmclipm_propertylist_load(fn_reconstr, 0);
1639
1640 kmo_init_fits_desc(&desc1);
1641 desc1 = kmo_identify_fits_header(fn_reconstr);
1642
1643 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
1644 // check if object-name equals the one in our list
1645 keyword = cpl_sprintf("%s%d%s", IFU_NAME_PREFIX, ifu_nr,
1646 IFU_NAME_POSTFIX);
1647 tmp_str=cpl_propertylist_get_string(main_header,
1648 keyword);
1649 cpl_free(keyword);
1650
1651 if (!strcmp(arm_name_struct->names[i],tmp_str) ||
1652 !strcmp(arm_name_struct->names[i], IFUS_USER_DEFINED)) {
1653 /* Found object-IFU with matching name */
1654 /* Load data & subheader */
1655 idx=kmo_identify_index(fn_reconstr,ifu_nr,FALSE);
1656
1657 if (desc1.sub_desc[idx-1].valid_data) {
1658 cube_data[cube_counter_data] =
1659 kmclipm_imagelist_load(fn_reconstr,
1660 CPL_TYPE_FLOAT, idx);
1661 /* Set cubes borders (1 pixel) to Nan to avoid jumps in combined cube */
1662 if (edge_nan) {
1663 kmo_edge_nan(cube_data[cube_counter_data],
1664 ifu_nr);
1665 }
1666
1667 header_data[cube_counter_data] =
1668 kmclipm_propertylist_load(fn_reconstr,
1669 idx);
1670 cpl_propertylist_update_string(
1671 header_data[cube_counter_data],
1672 "ESO PRO FRNAME", fn_reconstr);
1673 cpl_propertylist_update_int(
1674 header_data[cube_counter_data],
1675 "ESO PRO IFUNR", ifu_nr);
1676 cube_counter_data++;
1677 }
1678
1679 /* Load noise & subheader (if existing) */
1680 if (desc1.ex_noise) {
1681 idx = kmo_identify_index(fn_reconstr, ifu_nr,
1682 TRUE);
1683 if (desc1.sub_desc[idx-1].valid_data) {
1684 cube_noise[cube_counter_noise] =
1685 kmclipm_imagelist_load(fn_reconstr,
1686 CPL_TYPE_FLOAT, idx);
1687 if (edge_nan) {
1688 kmo_edge_nan(
1689 cube_noise[cube_counter_noise],
1690 ifu_nr);
1691 }
1692 header_noise[cube_counter_noise] =
1693 kmclipm_propertylist_load(fn_reconstr,
1694 idx);
1695 cube_counter_noise++;
1696 }
1697 }
1698 cpl_error_reset();
1699 }
1700 }
1701 kmo_free_fits_desc(&desc1);
1702 cpl_propertylist_delete(main_header);
1703 tmp_frame = kmo_dfs_get_frame(frameset, NULL);
1704 }
1705
1706 if (cube_counter_noise == 0) {
1707 cpl_free(cube_noise);
1708 cube_noise = NULL ;
1709 }
1710
1711 if (cube_counter_data > 1) {
1712 if (cube_counter_data == cube_counter_noise ||
1713 cube_counter_noise == 0) {
1714 kmo_priv_combine(cube_data, cube_noise, header_data,
1715 header_noise, cube_counter_data,
1716 cube_counter_noise, arm_name_struct->names[i],
1717 "", comb_method, smethod, fmethod, filename,
1718 cmethod, cpos_rej, cneg_rej, citer, cmin, cmax,
1719 extrapol_enum, flux, &combined_data,
1720 &combined_noise, &exp_mask);
1721 } else {
1722 cpl_msg_error(__func__, "Data/Noise cubes nb mismatch");
1723 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
1724 return -1 ;
1725 }
1726 } else if (cube_counter_data == 1) {
1727 cpl_msg_warning(__func__,
1728 "Only one reconstructed cube with this object");
1729 combined_data = cpl_imagelist_duplicate(cube_data[0]);
1730 tmpImg = cpl_imagelist_get(combined_data, 0);
1731 exp_mask = cpl_image_new(cpl_image_get_size_x(tmpImg),
1732 cpl_image_get_size_y(tmpImg), CPL_TYPE_FLOAT);
1733 kmo_image_fill(exp_mask, 1.);
1734
1735 combined_noise = NULL ;
1736 if (cube_counter_noise > 0 && cube_noise[0] != NULL) {
1737 combined_noise = cpl_imagelist_duplicate(cube_noise[0]);
1738 }
1739 } else {
1740 cpl_msg_error(__func__, "No cube found with this obj name");
1741 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
1742 return -1 ;
1743 }
1744 for (jj = 0; jj < nr_data; jj++) {
1745 cpl_imagelist_delete(cube_data[jj]);
1746 if (cube_counter_noise > 0)
1747 cpl_imagelist_delete(cube_noise[jj]);
1748 }
1749 cpl_free(cube_data);
1750 cpl_free(cube_noise);
1751
1752 fn_out = COMBINED_CUBE;
1753 if (!suppress_extension) {
1754 char tmp_suffix[1024];
1755 tmp_suffix[0] = '\0';
1756
1757 if (arm_name_struct->telluricCnt[i] ==
1758 arm_name_struct->namesCnt[i]) {
1759 strcat(tmp_suffix, "_telluric");
1760 }
1761 if (nb_illum_corr > 0) strcat(tmp_suffix, "_illum");
1762 if (sky_tweak) strcat(tmp_suffix, "_skytweak");
1763
1764 if (strlen(tmp_suffix) > 0) {
1765 fn_suffix = cpl_sprintf("_%s_%s",
1766 arm_name_struct->names[i], tmp_suffix);
1767 } else {
1768 fn_suffix = cpl_sprintf("_%s",
1769 arm_name_struct->names[i]);
1770 }
1771 } else {
1772 fn_suffix = cpl_sprintf("_%d", suppress_index++);
1773 }
1774
1775 /* Add REFLEX SUFFIX keyword */
1776 reflex_suffix = kmos_get_reflex_suffix(mapping_id,
1777 ifus_txt, name, arm_name_struct->names[i]) ;
1778 keys_plist = cpl_propertylist_new() ;
1779 cpl_propertylist_update_string(keys_plist,
1780 "ESO PRO REFLEX SUFFIX", reflex_suffix) ;
1781 cpl_free(reflex_suffix);
1782
1783 /* Save Products */
1784 tmp_frame = kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE);
1785 /* Save Combined Cube Main Header */
1786 kmo_dfs_save_main_header(frameset, fn_out, fn_suffix,
1787 tmp_frame, keys_plist, parlist, cpl_func);
1788 /* Save Mask Main Header */
1789 kmo_dfs_save_main_header(frameset, EXP_MASK, fn_suffix,
1790 tmp_frame, keys_plist, parlist, cpl_func);
1791 cpl_propertylist_delete(keys_plist) ;
1792 /* Save Combined Cube Data */
1793 kmo_dfs_save_cube(combined_data, fn_out, fn_suffix,
1794 header_data[0], 0./0.);
1795 /* Save Mask Data */
1796 kmo_dfs_save_image(exp_mask, EXP_MASK, fn_suffix,
1797 header_data[0], 0./0.);
1798 cpl_image_delete(exp_mask);
1799
1800 if (combined_noise) {
1801 /* Save Combined Cube Noise */
1802 cpl_propertylist *final_noise_hdr = NULL;
1803 if (header_noise[0]) {
1804 final_noise_hdr = cpl_propertylist_duplicate(
1805 header_noise[0]);
1806 } else {
1807 final_noise_hdr = cpl_propertylist_duplicate(
1808 header_data[0]);
1809 tmp_str = cpl_propertylist_get_string(header_data[0],
1810 EXTNAME);
1811 kmo_extname_extractor(tmp_str, &ft, &tmp_int, content);
1812 extname = kmo_extname_creator(ifu_frame, tmp_int,
1813 EXT_NOISE);
1814 kmclipm_update_property_string(final_noise_hdr,
1815 EXTNAME, extname, "FITS extension name");
1816 cpl_free(extname);
1817 }
1818 kmo_dfs_save_cube(combined_noise, fn_out, fn_suffix,
1819 final_noise_hdr, 0./0.);
1820 cpl_propertylist_delete(final_noise_hdr);
1821 cpl_imagelist_delete(combined_noise);
1822 }
1823 cpl_free(fn_suffix);
1824
1825 for (jj = 0; jj < nr_data; jj++) {
1826 cpl_propertylist_delete(header_data[jj]);
1827 cpl_propertylist_delete(header_noise[jj]);
1828 }
1829 cpl_free(header_data);
1830 cpl_free(header_noise);
1831 cpl_imagelist_delete(combined_data);
1832 }
1833 } else {
1834 /* Mapping_mode */
1835 nr_data = KMOS_NR_IFUS *
1836 cpl_frameset_count_tags(frameset,RECONSTRUCTED_CUBE);
1837 cube_data = (cpl_imagelist**)cpl_calloc(nr_data,
1838 sizeof(cpl_imagelist*));
1839 cube_noise = (cpl_imagelist**)cpl_calloc(nr_data,
1840 sizeof(cpl_imagelist*));
1841 header_data=(cpl_propertylist**)cpl_calloc(nr_data,
1842 sizeof(cpl_propertylist*));
1843 header_noise=(cpl_propertylist**)cpl_calloc(nr_data,
1844 sizeof(cpl_propertylist*));
1845
1846 /* Initialise */
1847 for (jj = 0; jj < nr_data; jj++) {
1848 cube_data[jj] = NULL ;
1849 cube_noise[jj] = NULL ;
1850 header_data[jj] = NULL ;
1851 header_noise[jj] = NULL ;
1852 }
1853
1854 cube_counter_data = 0;
1855 cube_counter_noise = 0;
1856 tmp_frame = kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE);
1857 while (tmp_frame != NULL ) {
1858 fn_reconstr = cpl_frame_get_filename(tmp_frame);
1859
1860 kmo_init_fits_desc(&desc1);
1861 desc1 = kmo_identify_fits_header(fn_reconstr);
1862 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
1863 idx = kmo_identify_index(fn_reconstr, ifu_nr, FALSE);
1864
1865 if (desc1.sub_desc[idx-1].valid_data) {
1866 cpl_msg_debug(__func__,
1867 "Load in cube_data - Frame: %s IFU: %d",
1868 fn_reconstr, ifu_nr) ;
1869 cube_data[cube_counter_data] = kmclipm_imagelist_load(
1870 fn_reconstr, CPL_TYPE_FLOAT, idx);
1871 if (edge_nan)
1872 kmo_edge_nan(cube_data[cube_counter_data], ifu_nr);
1873
1874 if (fast_mode) {
1875 tmpImg = cpl_imagelist_collapse_median_create(
1876 cube_data[cube_counter_data]);
1877 tmp_cube1 = cpl_imagelist_new();
1878 cpl_imagelist_set(tmp_cube1, tmpImg, 0);
1879 cpl_imagelist_delete(cube_data[cube_counter_data]);
1880 cube_data[cube_counter_data] = tmp_cube1;
1881 }
1882
1883 cpl_msg_debug(__func__,
1884 "Load in header_data - Frame: %s IFU: %d",
1885 fn_reconstr, ifu_nr) ;
1886 header_data[cube_counter_data] =
1887 kmclipm_propertylist_load(fn_reconstr, idx);
1888 cpl_propertylist_update_string(
1889 header_data[cube_counter_data],
1890 "ESO PRO FRNAME", fn_reconstr);
1891 cpl_propertylist_update_int(
1892 header_data[cube_counter_data],
1893 "ESO PRO IFUNR", ifu_nr);
1894 cube_counter_data++;
1895 cpl_msg_debug(__func__, "cube_counter_data: %d\n",
1896 cube_counter_data) ;
1897 }
1898
1899 /* Load noise & subheader (if existing) */
1900 if (desc1.ex_noise) {
1901 idx = kmo_identify_index(fn_reconstr,ifu_nr,TRUE);
1902 if (desc1.sub_desc[idx-1].valid_data) {
1903 cpl_msg_debug(__func__,
1904 "Load in cube_noise - Frame: %s IFU: %d",
1905 fn_reconstr, ifu_nr) ;
1906 cube_noise[cube_counter_noise] =
1907 kmclipm_imagelist_load(fn_reconstr,
1908 CPL_TYPE_FLOAT, idx);
1909
1910 if (edge_nan)
1911 kmo_edge_nan(cube_noise[cube_counter_noise],
1912 ifu_nr);
1913 if (fast_mode) {
1914 tmpImg=cpl_imagelist_collapse_median_create(
1915 cube_noise[cube_counter_noise]);
1916 tmp_cube1 = cpl_imagelist_new();
1917 cpl_imagelist_set(tmp_cube1, tmpImg, 0);
1918 cpl_imagelist_delete(
1919 cube_noise[cube_counter_noise]);
1920 cube_noise[cube_counter_noise] = tmp_cube1;
1921 }
1922 cpl_msg_debug(__func__,
1923 "Load in header_noise - Frame: %s IFU: %d",
1924 fn_reconstr, ifu_nr) ;
1925 header_noise[cube_counter_noise] =
1926 kmclipm_propertylist_load(fn_reconstr, idx);
1927 cube_counter_noise++;
1928 cpl_msg_debug(__func__, "cube_counter_noise: %d\n",
1929 cube_counter_noise) ;
1930 }
1931 }
1932 cpl_error_reset();
1933 }
1934 kmo_free_fits_desc(&desc1);
1935 tmp_frame = kmo_dfs_get_frame(frameset, NULL);
1936 }
1937
1938 if (cube_counter_noise == 0) {
1939 cpl_free(cube_noise);
1940 cube_noise = NULL ;
1941 }
1942
1943 if (cube_counter_data > 1) {
1944 if (cube_counter_data == cube_counter_noise ||
1945 cube_counter_noise == 0) {
1946 kmo_priv_combine(cube_data, cube_noise, header_data,
1947 header_noise, cube_counter_data, cube_counter_noise,
1948 mapping_mode, "", comb_method, smethod, fmethod,
1949 filename, cmethod, cpos_rej, cneg_rej, citer, cmin,
1950 cmax, extrapol_enum, flux, &combined_data,
1951 &combined_noise, NULL);
1952 } else {
1953 cpl_msg_error(__func__, "Data/Noise cubes nb mismatch");
1954 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
1955 return -1 ;
1956 }
1957 } else if (cube_counter_data == 1) {
1958 cpl_msg_warning(__func__,
1959 "There is only one reconstructed cube - Save it");
1960 combined_data = cpl_imagelist_duplicate(cube_data[0]);
1961
1962 if (cube_noise[0] != NULL) {
1963 combined_noise = cpl_imagelist_duplicate(cube_noise[0]);
1964 }
1965 } else {
1966 cpl_msg_error(__func__, "No cube found with this obj name");
1967 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
1968 return -1 ;
1969 }
1970 fn_out = COMBINED_CUBE;
1971 fn_suffix = cpl_sprintf("_%s", mapping_mode);
1972
1973 /* Add REFLEX SUFFIX keyword */
1974 keys_plist = cpl_propertylist_new() ;
1975 cpl_propertylist_update_string(keys_plist,
1976 "ESO PRO REFLEX SUFFIX", "mapping") ;
1977
1978 // save combined cube
1979 tmp_frame = kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE);
1980 kmo_dfs_save_main_header(frameset, fn_out, fn_suffix, tmp_frame,
1981 keys_plist, parlist, cpl_func);
1982 cpl_propertylist_delete(keys_plist) ;
1983
1984 kmo_dfs_save_cube(combined_data, fn_out, fn_suffix, header_data[0],
1985 0./0.);
1986
1987 if (combined_noise) {
1988 cpl_propertylist *final_noise_hdr = NULL;
1989 if (cube_counter_noise > 0) {
1990 final_noise_hdr = cpl_propertylist_duplicate(
1991 header_noise[0]);
1992 } else {
1993 final_noise_hdr = cpl_propertylist_duplicate(
1994 header_data[0]);
1995 tmp_str = cpl_propertylist_get_string(header_data[0],
1996 EXTNAME);
1997 kmo_extname_extractor(tmp_str, &ft, &tmp_int, content);
1998 extname = kmo_extname_creator(ifu_frame, tmp_int,
1999 EXT_NOISE);
2000 kmclipm_update_property_string(final_noise_hdr, EXTNAME,
2001 extname, "FITS extension name");
2002 cpl_free(extname);
2003 }
2004 kmo_dfs_save_cube(combined_noise, fn_out, fn_suffix,
2005 final_noise_hdr, 0./0.);
2006 cpl_propertylist_delete(final_noise_hdr);
2007 cpl_imagelist_delete(combined_noise);
2008 }
2009 cpl_free(fn_suffix);
2010
2011 for (i = 0; i < cube_counter_data ; i++) {
2012 cpl_propertylist_delete(header_data[i]);
2013 cpl_imagelist_delete(cube_data[i]);
2014 }
2015 for (i = 0; i < cube_counter_noise ; i++) {
2016 cpl_propertylist_delete(header_noise[i]);
2017 cpl_imagelist_delete(cube_noise[i]);
2018 }
2019 cpl_free(cube_data);
2020 cpl_free(cube_noise);
2021 cpl_free(header_data);
2022 cpl_free(header_noise);
2023 cpl_imagelist_delete(combined_data);
2024 }
2025 }
2026 kmo_delete_armNameStruct(arm_name_struct);
2027
2028 /* Collapse the reconstructed cubes if requested */
2029 if (collapse_reconstructed) {
2030 kmos_collapse_cubes(RECONSTRUCTED_CUBE, frameset, parlist, 0.1,
2031 "", DEF_REJ_METHOD, DEF_POS_REJ_THRES, DEF_NEG_REJ_THRES,
2032 DEF_ITERATIONS, DEF_NR_MIN_REJ, DEF_NR_MAX_REJ) ;
2033 }
2034
2035 /* Collapse the combined cubes if requested */
2036 if (collapse_combined) {
2037 kmos_collapse_cubes(COMBINED_CUBE, frameset, parlist, 0.1, "",
2038 DEF_REJ_METHOD, DEF_POS_REJ_THRES, DEF_NEG_REJ_THRES,
2039 DEF_ITERATIONS, DEF_NR_MIN_REJ, DEF_NR_MAX_REJ) ;
2040 }
2041 return 0;
2042}
2043
2046/*----------------------------------------------------------------------------*/
2055/*----------------------------------------------------------------------------*/
2056static int kmos_sci_red_check_inputs(
2057 cpl_frameset * frameset,
2058 double pix_scale,
2059 int * mapping_id,
2060 const char * science_tag)
2061{
2062 int nb_science, nb_xcal, nb_ycal, nb_lcal, nb_wave_band,
2063 nb_master_flat, nb_illum_corr, nb_telluric, nb_oh_spec,
2064 nb_telluric_gen ;
2065 cpl_error_code err ;
2066 const cpl_frame * frame1 ;
2067 const cpl_frame * frame2 ;
2068 int next1, next2, mapping_id_loc,
2069 mapping_id_curr, nx, ny ;
2070 cpl_propertylist * mh ;
2071 cpl_propertylist * eh ;
2072 const char * tmp_str ;
2073
2074 /* Check Entries */
2075 if (frameset == NULL || mapping_id == NULL) return -1;
2076
2077 /* Count frames */
2078 nb_science = cpl_frameset_count_tags(frameset, science_tag) ;
2079 nb_xcal = cpl_frameset_count_tags(frameset, XCAL) ;
2080 nb_ycal = cpl_frameset_count_tags(frameset, YCAL) ;
2081 nb_lcal = cpl_frameset_count_tags(frameset, LCAL) ;
2082 nb_wave_band = cpl_frameset_count_tags(frameset, WAVE_BAND) ;
2083 nb_master_flat = cpl_frameset_count_tags(frameset, MASTER_FLAT);
2084 nb_illum_corr = cpl_frameset_count_tags(frameset, ILLUM_CORR);
2085 nb_telluric = cpl_frameset_count_tags(frameset, TELLURIC);
2086 nb_telluric_gen = cpl_frameset_count_tags(frameset, TELLURIC_GEN);
2087 nb_oh_spec = cpl_frameset_count_tags(frameset, OH_SPEC) ;
2088
2089 /* Checks */
2090 if (nb_science < 1) {
2091 cpl_msg_error(__func__, "At least one SCIENCE frame is required") ;
2092 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
2093 return 0 ;
2094 }
2095 if (nb_science == 1) {
2096 cpl_msg_warning(__func__,
2097 "Only 1 SCIENCE: no sky subtraction - reconstruct all IFUs");
2098 }
2099 if (nb_xcal != 1 || nb_ycal != 1 || nb_lcal != 1) {
2100 cpl_msg_error(__func__, "Exactly 1 XCAL/YCAL/LCAL expected") ;
2101 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
2102 return 0 ;
2103 }
2104 if (nb_wave_band != 1) {
2105 cpl_msg_error(__func__, "At most one WAVE_BAND frame expected") ;
2106 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
2107 return 0 ;
2108 }
2109
2110 if (nb_master_flat > 1 || nb_illum_corr > 1 || nb_telluric > 1 ||
2111 nb_oh_spec > 1) {
2112 cpl_msg_error(__func__,
2113 "MASTER_FLAT/ILLUM_CORR/OH_SPEC/TELLURIC: 0 or 1 frame expected") ;
2114 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
2115 return 0 ;
2116 }
2117
2118 /* filter_id, grating_id and rotator offset match all detectors */
2119 err = CPL_ERROR_NONE ;
2120 err += kmo_check_frameset_setup(frameset, science_tag, TRUE, FALSE, TRUE);
2121 err += kmo_check_frame_setup(frameset, science_tag, YCAL, TRUE, FALSE,TRUE);
2122 err += kmo_check_frame_setup(frameset, XCAL, YCAL, TRUE, FALSE, TRUE);
2123 err += kmo_check_frame_setup(frameset, XCAL, LCAL, TRUE, FALSE, TRUE);
2124 if (nb_master_flat > 0) err += kmo_check_frame_setup(frameset, XCAL,
2125 MASTER_FLAT, TRUE, FALSE, TRUE);
2126 if (nb_telluric > 0) err += kmo_check_frame_setup(frameset, XCAL,
2127 TELLURIC, TRUE, FALSE, TRUE);
2128 if (nb_telluric_gen > 0) err += kmo_check_frame_setup(frameset, XCAL,
2129 TELLURIC_GEN, TRUE, FALSE, TRUE);
2130 if (nb_oh_spec > 0) err += kmo_check_oh_spec_setup(frameset, XCAL);
2131
2132 /* Check XCAL */
2133 frame1 = kmo_dfs_get_frame(frameset, XCAL);
2134 next1 = cpl_frame_get_nextensions(frame1);
2135 if (next1 % KMOS_NR_DETECTORS) {
2136 cpl_msg_error(__func__, "XCAL wrong format") ;
2137 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
2138 return 0 ;
2139 }
2140 /* Check YCAL */
2141 frame2 = kmo_dfs_get_frame(frameset, YCAL);
2142 next2 = cpl_frame_get_nextensions(frame2);
2143 if (next1 != next2) {
2144 cpl_msg_error(__func__, "YCAL wrong format") ;
2145 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
2146 return 0 ;
2147 }
2148 /* Check LCAL */
2149 frame2 = kmo_dfs_get_frame(frameset, LCAL);
2150 next2 = cpl_frame_get_nextensions(frame2);
2151 if (next1 != next2) {
2152 cpl_msg_error(__func__, "LCAL wrong format") ;
2153 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
2154 return 0 ;
2155 }
2156 /* Check MASTER_FLAT */
2157 if (nb_master_flat >= 1) {
2158 frame2 = kmo_dfs_get_frame(frameset, MASTER_FLAT);
2159 next2 = cpl_frame_get_nextensions(frame2);
2160 if (next2 % (2*KMOS_NR_DETECTORS)) {
2161 cpl_msg_error(__func__, "MASTER_FLAT wrong format") ;
2162 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
2163 return 0 ;
2164 }
2165 }
2166 /* Check ILLUM_CORR */
2167 if (nb_illum_corr >= 1) {
2168 frame2 = kmo_dfs_get_frame(frameset, ILLUM_CORR);
2169 /* Check Size regarding the pixscale */
2170 eh = cpl_propertylist_load(cpl_frame_get_filename(frame2), 1);
2171 nx = kmos_pfits_get_naxis1(eh) ;
2172 ny = kmos_pfits_get_naxis2(eh) ;
2173 cpl_propertylist_delete(eh) ;
2174 if (fabs(nx*pix_scale-2.8) > 1e-3 || fabs(ny*pix_scale-2.8) > 1e-3) {
2175 cpl_msg_error(__func__,
2176 "ILLUM wrong Size (nx/y*pix_scale= %g/%g <> 2.8)",
2177 nx*pix_scale, ny*pix_scale) ;
2178 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
2179 return 0 ;
2180 }
2181 }
2182 /* Check TELLURIC */
2183 if (nb_telluric >= 1) {
2184 frame2 = kmo_dfs_get_frame(frameset, TELLURIC);
2185 next2 = cpl_frame_get_nextensions(frame2);
2186 if (next2 != 24 && next2 != 48) {
2187 cpl_msg_error(__func__, "TELLURIC wrong format") ;
2188 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
2189 return 0 ;
2190 }
2191 }
2192 /* Check TELLURIC_GEN */
2193 if (nb_telluric_gen >= 1) {
2194 frame2 = kmo_dfs_get_frame(frameset, TELLURIC_GEN);
2195 next2 = cpl_frame_get_nextensions(frame2);
2196 if (next2 != 24 && next2 != 48) {
2197 cpl_msg_error(__func__, "TELLURIC_GEN wrong format") ;
2198 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
2199 return 0 ;
2200 }
2201 }
2202
2203 /* Loop on the SCIENCE frames */
2204 frame2 = kmo_dfs_get_frame(frameset, science_tag);
2205 mapping_id_loc = -1 ;
2206 while (frame2 != NULL ) {
2207 next2 = cpl_frame_get_nextensions(frame2);
2208 if (next2 != 3) {
2209 cpl_msg_error(__func__, "SCIENCE wrong format") ;
2210 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
2211 return 0 ;
2212 }
2213
2214 mh = cpl_propertylist_load(cpl_frame_get_filename(frame2), 0);
2215 tmp_str = cpl_propertylist_get_string(mh, TPL_ID);
2216 if (!strcmp(tmp_str, MAPPING8)) mapping_id_curr = 1 ;
2217 else if (strcmp(tmp_str, MAPPING24) == 0) mapping_id_curr = 2 ;
2218 else mapping_id_curr = 0 ;
2219 cpl_propertylist_delete(mh);
2220
2221 if (mapping_id_loc < 0) mapping_id_loc = mapping_id_curr ;
2222 if (mapping_id_curr != mapping_id_loc) {
2223 cpl_msg_error(__func__, "Inconsistent MAPPING information") ;
2224 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
2225 return 0 ;
2226 }
2227 frame2 = kmo_dfs_get_frame(frameset, NULL);
2228 }
2229
2230 /* Verify that XCAL / YCAL were generated together */
2231 err += kmo_check_frame_setup_md5_xycal(frameset);
2232 /* Verify that XCAL and YCAL / LCAL were generated together */
2233 err += kmo_check_frame_setup_md5(frameset);
2234 /* b_samples used for LCAL and TELLURIC were the same */
2235 err += kmo_check_frame_setup_sampling(frameset);
2236
2237 if (err != CPL_ERROR_NONE) {
2238 cpl_msg_warning(__func__, "Frames are inconsistent") ;
2239 return 0 ;
2240 }
2241
2242 /* Return */
2243 *mapping_id = mapping_id_loc ;
2244 return 1 ;
2245}
2246
2247/*----------------------------------------------------------------------------*/
2254/*----------------------------------------------------------------------------*/
2255static double kmos_sci_red_get_zpoint(
2256 cpl_frame * frame,
2257 int ifu_nr)
2258{
2259 cpl_propertylist * plist ;
2260 double zpoint ;
2261 int nb_ext, ext_nb ;
2262
2263 /* Check entries */
2264 if (frame == NULL) return -1.0 ;
2265 if (cpl_error_get_code() != CPL_ERROR_NONE) return -1.0 ;
2266
2267 /* Get the number of extentions */
2268 nb_ext = cpl_frame_get_nextensions(frame);
2269
2270 /* Compute ext_nb */
2271 if (nb_ext == KMOS_NR_IFUS) ext_nb = ifu_nr ;
2272 else if (nb_ext == 2 * KMOS_NR_IFUS) ext_nb = 2 * ifu_nr - 1 ;
2273 else return -1.0 ;
2274
2275 /* Get QC ZPOINT */
2276 plist = cpl_propertylist_load(cpl_frame_get_filename(frame), ext_nb);
2277 zpoint = cpl_propertylist_get_double(plist, "ESO QC ZPOINT") ;
2278 cpl_propertylist_delete(plist) ;
2279
2280 if (cpl_error_get_code() != CPL_ERROR_NONE) {
2281 cpl_error_reset() ;
2282 zpoint = -1.0 ;
2283 }
2284
2285 return zpoint ;
2286}
2287
2288/*----------------------------------------------------------------------------*/
2294/*----------------------------------------------------------------------------*/
2295static double kmos_sci_red_get_f0(
2296 const char * filter_id,
2297 int lam_dim,
2298 double lam_start,
2299 double lam_delta)
2300{
2301 double f_0 = -1.0 ;
2302 if (!strcmp(filter_id, "H")) f_0 = 1.133e-9 ;
2303 if (!strcmp(filter_id, "HK")) f_0 = 6.954423052992941e-10 ;
2304 if (!strcmp(filter_id, "K")) f_0 = 4.283e-10 ;
2305 if (!strcmp(filter_id, "YJ")) f_0 = 3.129e-9 ;
2306 if (!strcmp(filter_id, "IZ")) f_0 = 7.63e-9 ;
2307 return f_0 ;
2308}
2309
2310
2311
2312/*----------------------------------------------------------------------------*/
2337/*----------------------------------------------------------------------------*/
2338static kmclipm_vector * kmo_tweak_load_telluric(
2339 cpl_frameset * frameset,
2340 int ifu_nr,
2341 int is_noise,
2342 int no_subtract,
2343 const char * telluric_tag,
2344 int * ifu_nr_telluric)
2345{
2346 kmclipm_vector *vec = NULL;
2347 int actual_msg_level = 0 ;
2348
2349
2350 /* Check entries */
2351 if (frameset == NULL || ifu_nr_telluric == NULL) return NULL ;
2352 if (ifu_nr < 1 || ifu_nr > KMOS_NR_IFUS) return NULL ;
2353
2354 *ifu_nr_telluric = kmo_tweak_find_ifu(frameset, ifu_nr);
2355 if (ifu_nr!=*ifu_nr_telluric && *ifu_nr_telluric!=-1 && no_subtract!=-1) {
2356 if (!no_subtract) {
2357 cpl_msg_info(__func__, "Telluric IFU %d selected",
2358 *ifu_nr_telluric);
2359 } else {
2360 cpl_msg_info(__func__, "For IFU %d, telluric in IFU %d selected",
2361 ifu_nr, *ifu_nr_telluric);
2362 }
2363 }
2364
2365 actual_msg_level = cpl_msg_get_level();
2366 cpl_msg_set_level(CPL_MSG_OFF);
2367 vec = kmo_dfs_load_vector(frameset, telluric_tag,*ifu_nr_telluric,is_noise);
2368 cpl_msg_set_level(actual_msg_level);
2369
2370 if (cpl_error_get_code() != CPL_ERROR_NONE) cpl_error_reset();
2371
2372 if ((vec == NULL) && !is_noise && (no_subtract != -1)) {
2373 if (!no_subtract) {
2374 cpl_msg_warning(__func__, "No telluric on this detector");
2375 } else {
2376 cpl_msg_warning(__func__, "No telluric on this detector for IFU %d",
2377 ifu_nr);
2378 }
2379 }
2380
2381 return vec;
2382}
2383
2384static int kmos_sci_red_propagate_qc(
2385 const cpl_propertylist * main_input,
2386 cpl_propertylist * to_update,
2387 const cpl_frame * inframe,
2388 int det_nr)
2389{
2390 cpl_propertylist * plist ;
2391 double rotangle, fwhm_ar, fwhm_ne,
2392 vscale_ar, vscale_ne, pos_ne, pos_ar ;
2393 int xtnum ;
2394
2395 /* Get the Angle from plist */
2396 rotangle = kmo_dfs_get_property_double(main_input, ROTANGLE);
2397
2398 /* Get the extension number */
2399 (void)kmclipm_cal_propertylist_find_angle(
2400 cpl_frame_get_filename(inframe), det_nr, 0, rotangle,
2401 &xtnum, NULL);
2402
2403 /* Get the Header with the QC to propagate */
2404 plist = cpl_propertylist_load(cpl_frame_get_filename(inframe), xtnum) ;
2405 fwhm_ar = kmos_pfits_get_qc_ar_fwhm_mean(plist) ;
2406 vscale_ar = kmos_pfits_get_qc_ar_vscale(plist) ;
2407 fwhm_ne = kmos_pfits_get_qc_ne_fwhm_mean(plist) ;
2408 vscale_ne = kmos_pfits_get_qc_ne_vscale(plist) ;
2409 pos_ar = kmos_pfits_get_qc_ar_pos_stdev(plist) ;
2410 pos_ne = kmos_pfits_get_qc_ne_pos_stdev(plist) ;
2411 cpl_propertylist_delete(plist) ;
2412 if (cpl_error_get_code() != CPL_ERROR_NONE) {
2413 cpl_msg_warning(__func__,
2414 "Cannot propagate the QC ARC xx FWHM MEAN keyword") ;
2415 cpl_error_reset() ;
2416 }
2417
2418 /* Set the QC */
2419 kmclipm_update_property_double(to_update, "ESO QC ARC NE POS STDEV",
2420 pos_ne, "[km/s] mean stdev of pos. of NE");
2421 kmclipm_update_property_double(to_update, "ESO QC ARC AR POS STDEV",
2422 pos_ar, "[km/s] mean stdev of pos. of AR");
2423 kmclipm_update_property_double(to_update, "ESO QC ARC NE FWHM MEAN",
2424 fwhm_ne, "[km/s] mean of fwhm for Ne");
2425 kmclipm_update_property_double(to_update, "ESO QC ARC AR FWHM MEAN",
2426 fwhm_ar, "[km/s] mean of fwhm for Ar");
2427 kmclipm_update_property_double(to_update, "ESO QC ARC NE VSCALE",
2428 vscale_ne, "Velocity scale for Ne");
2429 kmclipm_update_property_double(to_update, "ESO QC ARC AR VSCALE",
2430 vscale_ar, "Velocity scale for Ar");
2431 return 0 ;
2432}
2433
2434
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.
Definition: kmos_sci_red.c:158