KMOS Pipeline Reference Manual 4.5.10
kmos_combine.c
1/* * This file is part of the KMOS Pipeline
2 * Copyright (C) 2002,2003 European Southern Observatory
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19#ifdef HAVE_CONFIG_H
20 #include <config.h>
21#endif
22
23#define _DEFAULT_SOURCE
24#define _BSD_SOURCE
25
26/*-----------------------------------------------------------------------------
27 * Includes
28 *----------------------------------------------------------------------------*/
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <math.h>
34
35#include <cpl.h>
36#include <cpl_wcs.h>
37
38#include "kmo_debug.h"
39#include "kmo_utils.h"
40#include "kmo_dfs.h"
41#include "kmos_pfits.h"
42#include "kmo_error.h"
43#include "kmo_priv_functions.h"
44#include "kmo_cpl_extensions.h"
45#include "kmo_constants.h"
46#include "kmo_priv_combine.h"
47
48/*-----------------------------------------------------------------------------
49 * Define
50 *----------------------------------------------------------------------------*/
51
52#define CPL_DFS_PRO_DID "PRO-1.16"
53
54/*-----------------------------------------------------------------------------
55 * Functions prototypes
56 *----------------------------------------------------------------------------*/
57
58static double kmos_get_median_from_positives(
59 cpl_image * exp_mask) ;
60static double kmos_get_mode(
61 cpl_imagelist * error) ;
62static int kmos_idp_set_nans(
63 cpl_imagelist * data,
64 cpl_imagelist * error) ;
65static int kmos_combine_collect_data(
66 const cpl_propertylist * recons_prim_header,
67 const cpl_propertylist * recons_ext_header,
68 double * lambda,
69 double * seeing,
70 double * airmass) ;
71static char * kmos_combine_create_ifus_string(const int *,const int *,int);
72static cpl_bivector * kmos_combine_parse_skipped(const char *) ;
73static int kmos_combine_is_skipped(const cpl_bivector *, int, int) ;
74
75static int kmos_combine_create(cpl_plugin *);
76static int kmos_combine_exec(cpl_plugin *);
77static int kmos_combine_destroy(cpl_plugin *);
78static int kmos_combine(cpl_parameterlist *, cpl_frameset *);
79
80/*-----------------------------------------------------------------------------
81 * Static variables
82 *----------------------------------------------------------------------------*/
83
84static char kmos_combine_description[] =
85"This recipe shifts several exposures of an object and combines them. Diffe-\n"
86"rent methods to match the exposures are described here (--method parameter).\n"
87"The output cube is larger than the input cubes, according to the shifts to\n"
88"be applied. Additionally a border of NaN values is added. The WCS is the\n"
89"same as for the first exposure.\n"
90"For each spatial/spectral pixel a new value is calculated (according the\n"
91"--cmethod parameter) and written into the output cube.\n"
92"Only exposures with the same WCS orientation can be combined (except\n"
93"-–method=”none”), north must point to the same direction. It is recommended\n"
94"to apply any rotation possibly after combining.\n"
95"\n"
96"The behavior of the selection of IFUs to combine differs for some templates\n"
97"and can be controlled with the parameters --name and --ifus.\n"
98"If the input data cubes stem from templates KMOS_spec_obs_mapping8 or\n"
99"KMOS_spec_obs_mapping24 all extensions from all input frames are combined\n"
100"into a single map by default (like in recipe kmo_sci_red). If just the area\n"
101"of a specific IFU should be combined, the parameter --ifus can be specified,\n"
102"or more easily --name.\n"
103"If the input data cubes stem from other templates like e.g.\n"
104"KMOS_spec_obs_freedither all extensions of all input frames are combined\n"
105"into several output frames by default. The input IFUs are grouped according\n"
106"to their targeted object name stored in the keywords ESO OCS ARMx NAME. If \n"
107"just a specific object should be combined, its name can be specified with \n"
108"--name. If arbitrary IFUs shoukd be comined, one can specify these with the\n"
109"parameter --ifus.\n"
110"\n"
111"The default mapping mode is done via the --name parameter, where the name of\n"
112"the object has to be provided. The recipe searches in input data cubes IFUs\n"
113"pointing to that object.\n"
114"\n"
115"---------------------------------------------------------------------------\n"
116" Input files:\n"
117"\n"
118" DO KMOS \n"
119" category Type Explanation Required #Frames\n"
120" -------- ----- ----------- -------- -------\n"
121" CUBE_OBJECT F3I data frame Y 2-n \n"
122"\n"
123" Output files:\n"
124"\n"
125" DO KMOS\n"
126" category Type Explanation\n"
127" -------- ----- -----------\n"
128" COMBINE_ F3I Combined data cube\n"
129" EXP_MASK F3I Exposure time mask\n"
130" SCI_COMBINED_COLL (optional) Collapsed combined cube\n"
131" (set --collapse_combined)\n"
132"---------------------------------------------------------------------------\n"
133"\n";
134
135/*-----------------------------------------------------------------------------
136 * Functions code
137 *----------------------------------------------------------------------------*/
138
139/*----------------------------------------------------------------------------*/
143/*----------------------------------------------------------------------------*/
144
147/*----------------------------------------------------------------------------*/
156/*----------------------------------------------------------------------------*/
157int cpl_plugin_get_info(cpl_pluginlist *list)
158{
159 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
160 cpl_plugin *plugin = &recipe->interface;
161
162 cpl_plugin_init(plugin,
163 CPL_PLUGIN_API,
164 KMOS_BINARY_VERSION,
165 CPL_PLUGIN_TYPE_RECIPE,
166 "kmos_combine",
167 "Combine reconstructed cubes",
168 kmos_combine_description,
169 "Alex Agudo Berbel, Y. Jung",
170 "https://support.eso.org/",
171 kmos_get_license(),
172 kmos_combine_create,
173 kmos_combine_exec,
174 kmos_combine_destroy);
175 cpl_pluginlist_append(list, plugin);
176
177 return 0;
178}
179
180/*----------------------------------------------------------------------------*/
188/*----------------------------------------------------------------------------*/
189static int kmos_combine_create(cpl_plugin *plugin)
190{
191 cpl_recipe *recipe;
192 cpl_parameter *p;
193
194 /* Check that the plugin is part of a valid recipe */
195 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
196 recipe = (cpl_recipe *)plugin;
197 else
198 return -1;
199
200 /* Create the parameters list in the cpl_recipe object */
201 recipe->parameters = cpl_parameterlist_new();
202
203 /* Fill the parameters list */
204 /* --name */
205 p = cpl_parameter_new_value("kmos.kmos_combine.name", CPL_TYPE_STRING,
206 "Name of the object to combine.", "kmos.kmos_combine", "");
207 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "name");
208 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
209 cpl_parameterlist_append(recipe->parameters, p);
210
211 /* --ifus */
212 p = cpl_parameter_new_value("kmos.kmos_combine.ifus", CPL_TYPE_STRING,
213 "The indices of the IFUs to combine. " "\"ifu1;ifu2;...\"",
214 "kmos.kmos_combine", "");
215 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ifus");
216 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
217 cpl_parameterlist_append(recipe->parameters, p);
218
219 /* --method */
220 p = cpl_parameter_new_value("kmos.kmos_combine.method", CPL_TYPE_STRING,
221 "The shifting method: "
222 "'none': no shifting, combined directly (default), "
223 "'header': shift according to WCS, "
224 "'center': centering algorithm, "
225 "'user': read shifts from file",
226 "kmos.kmos_combine", "none");
227 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "method");
228 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
229 cpl_parameterlist_append(recipe->parameters, p);
230
231 /* --fmethod */
232 p = cpl_parameter_new_value("kmos.kmos_combine.fmethod", CPL_TYPE_STRING,
233 "The fitting method (applies only when method='center'): "
234 "'gauss': fit a gauss function to collapsed image (default), "
235 "'moffat': fit a moffat function to collapsed image",
236 "kmos.kmos_combine", "gauss");
237 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fmethod");
238 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
239 cpl_parameterlist_append(recipe->parameters, p);
240
241 /* --filename */
242 p = cpl_parameter_new_value("kmos.kmos_combine.filename", CPL_TYPE_STRING,
243 "The path to the file with the shift vectors (method='user')",
244 "kmos.kmos_combine", "");
245 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "filename");
246 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
247 cpl_parameterlist_append(recipe->parameters, p);
248
249 /* --flux */
250 p = cpl_parameter_new_value("kmos.kmos_combine.flux", CPL_TYPE_BOOL,
251 "Apply flux conservation: (TRUE (apply) or FALSE (don't apply)",
252 "kmos.kmos_combine", FALSE);
253 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
254 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
255 cpl_parameterlist_append(recipe->parameters, p);
256
257 /* --edge_nan */
258 p = cpl_parameter_new_value("kmos.kmos_combine.edge_nan", CPL_TYPE_BOOL,
259 "Set borders of cubes to NaN before combining them."
260 "(TRUE (apply) or FALSE (don't apply)", "kmos.kmos_combine", FALSE);
261 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "edge_nan");
262 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
263 cpl_parameterlist_append(recipe->parameters, p);
264
265 /* --skipped_frames */
266 p = cpl_parameter_new_value("kmos.kmos_combine.skipped_frames",
267 CPL_TYPE_STRING,
268 "Comma separated List of IFUs to skip for the combination. "
269 "An IFU is specified with R:I."
270 "R is the index (start 1) of the recons. frame, I the IFU nb",
271 "kmos.kmos_combine", "");
272 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skipped_frames");
273 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
274 cpl_parameterlist_append(recipe->parameters, p);
275
276 /* --suppress_extension */
277 p = cpl_parameter_new_value("kmos.kmos_combine.suppress_extension",
278 CPL_TYPE_BOOL, "Suppress arbitrary filename extension.",
279 "kmos.kmos_combine", FALSE);
280 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension");
281 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
282 cpl_parameterlist_append(recipe->parameters, p);
283
284 /* --collapse_combined */
285 p = cpl_parameter_new_value("kmos.kmos_combine.collapse_combined",
286 CPL_TYPE_BOOL, "Flag to collapse the combined images",
287 "kmos.kmos_combine", FALSE);
288 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "collapse_combined");
289 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
290 cpl_parameterlist_append(recipe->parameters, p);
291
292 return kmos_combine_pars_create(recipe->parameters, "kmos.kmos_combine",
293 DEF_REJ_METHOD, FALSE);
294}
295
296/*----------------------------------------------------------------------------*/
302/*----------------------------------------------------------------------------*/
303static int kmos_combine_exec(cpl_plugin *plugin)
304{
305 cpl_recipe *recipe;
306
307 /* Get the recipe out of the plugin */
308 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
309 recipe = (cpl_recipe *)plugin;
310 else return -1 ;
311
312 return kmos_combine(recipe->parameters, recipe->frames);
313}
314
315/*----------------------------------------------------------------------------*/
321/*----------------------------------------------------------------------------*/
322static int kmos_combine_destroy(cpl_plugin *plugin)
323{
324 cpl_recipe *recipe;
325
326 /* Get the recipe out of the plugin */
327 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
328 recipe = (cpl_recipe *)plugin;
329 else return -1 ;
330
331 cpl_parameterlist_delete(recipe->parameters);
332 return 0 ;
333}
334
335/*----------------------------------------------------------------------------*/
348/*----------------------------------------------------------------------------*/
349static int kmos_combine(cpl_parameterlist *parlist, cpl_frameset *frameset)
350{
351 const cpl_parameter * par ;
352 cpl_frameset * rawframes ;
353 const char * raw_tag,
354 * filename,
355 * fmethod,
356 * method,
357 * ifus_txt,
358 * cmethod,
359 * skipped_frames;
360 double cpos_rej, cneg_rej, fwhm_ar_med, fwhm_ne_med,
361 spec_res, fwhm_ar_val, fwhm_ne_val, pos_ar_val,
362 pos_ne_val, airmass, lambda, seeing, sky_res,
363 sky_rerr, abmaglim, outer_scale,
364 crval1, crval2, pos_ar_med, pos_ne_med,
365 crder3 ;
366 cpl_vector * ifus ;
367 int citer, cmin, cmax, nr_frames, index,
368 data_cube_counter, skip_cube_counter,
369 noise_cube_counter, flux, edge_nan, name_vec_size,
370 found, suppress_extension, ifu_nr,
371 nv, collapse_combined, mapping_id, fwhm_count,
372 data_count;
373 int suppress_index = 0;
374 char * tmp_str,
375 * fn_combine,
376 * fn_mask,
377 * mapping_mode,
378 ** name_vec,
379 * obj_name ;
380 const char * name;
381 const char * frame_filename,
382 * tmp_strc ;
383 cpl_image * exp_mask ;
384 cpl_imagelist ** data_cube_list,
385 ** noise_cube_list,
386 * cube_combined_data,
387 * cube_combined_noise ;
388 cpl_propertylist * main_header,
389 ** data_header_list,
390 ** noise_header_list,
391 * tmp_header,
392 * plist ;
393 cpl_vector * pos_ar ;
394 cpl_vector * pos_ne ;
395 cpl_vector * fwhm_ar ;
396 cpl_vector * fwhm_ne ;
397 cpl_vector * sky_res_vec ;
398 cpl_vector * airmass_vec ;
399 cpl_vector * seeing_vec ;
400 cpl_vector * lambda_vec ;
401 cpl_vector * tmp_vec ;
402 char * reflex_suffix ;
403 cpl_bivector * skipped_bivector ;
404 cpl_frame * frame ;
405 cpl_size ci ;
406 main_fits_desc desc;
407 int * used_frame_idx ;
408 int * used_ifus ;
409 char * used_ifus_str ;
410 int * skip_frame_idx ;
411 int * skip_ifus ;
412 char * skip_ifus_str ;
413 enum extrapolationType extrapol_enum = NONE_CLIPPING;
414 double light_speed, mjd_start, mjd_end ;
415 char * date_obs ;
416 char * object_key ;
417 char * object_data_key ;
418 char * object_stat_key ;
419 int i, j ;
420
421 /* Check initial Entries */
422 if (kmos_check_and_set_groups(frameset) != CPL_ERROR_NONE) {
423 return cpl_error_get_code();
424 }
425
426 /* Initialise */
427 light_speed = 299792.48 ;
428
429 /* Get parameters */
430 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.method");
431 method = cpl_parameter_get_string(par) ;
432 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.fmethod");
433 fmethod = cpl_parameter_get_string(par) ;
434 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.filename");
435 filename = cpl_parameter_get_string(par) ;
436 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.ifus");
437 ifus_txt = cpl_parameter_get_string(par) ;
438 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.name");
439 name = cpl_parameter_get_string(par) ;
440 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.flux");
441 flux = cpl_parameter_get_bool(par) ;
442 par = cpl_parameterlist_find_const(parlist,
443 "kmos.kmos_combine.skipped_frames");
444 skipped_frames = cpl_parameter_get_string(par) ;
445 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.edge_nan");
446 edge_nan = cpl_parameter_get_bool(par) ;
447 par = cpl_parameterlist_find_const(parlist,
448 "kmos.kmos_combine.suppress_extension");
449 suppress_extension = cpl_parameter_get_bool(par) ;
450 kmos_combine_pars_load(parlist, "kmos.kmos_combine", &cmethod, &cpos_rej,
451 &cneg_rej, &citer, &cmin, &cmax, FALSE);
452 par = cpl_parameterlist_find_const(parlist,
453 "kmos.kmos_combine.collapse_combined");
454 collapse_combined = cpl_parameter_get_bool(par);
455
456 /* Check Parameters */
457 if (strcmp(method, "none") && strcmp(method, "header") &&
458 strcmp(method, "center") && strcmp(method, "user")) {
459 cpl_msg_error(__func__,
460 "shift methods must be 'none', 'header', 'center' or 'user'") ;
461 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
462 return -1 ;
463 }
464 if (strcmp(ifus_txt, "") && strcmp(name, "")) {
465 cpl_msg_error(__func__,
466 "name and IFU indices cannot be both provided") ;
467 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
468 return -1 ;
469 }
470 if (!strcmp(method, "user") && !strcmp(filename, "")) {
471 cpl_msg_error(__func__,
472 "path of file with shift information must be provided") ;
473 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
474 return -1 ;
475 }
476
477 /* Parse the skipped frames option */
478 skipped_bivector = NULL ;
479 if (strcmp(skipped_frames, "")) {
480 skipped_bivector = kmos_combine_parse_skipped(skipped_frames) ;
481 if (skipped_bivector != NULL)
482 cpl_msg_info(__func__, "Skip the following IFU: %s",
483 skipped_frames);
484 }
485
486 /* Get the frames to combine - Filter out OH_SPEC */
487 rawframes = cpl_frameset_duplicate(frameset) ;
488 cpl_frameset_erase(rawframes, "OH_SPEC") ;
489
490 /* Check Nb of frames */
491 nr_frames = cpl_frameset_get_size(rawframes);
492 if (nr_frames < 1) {
493 if (skipped_bivector!=NULL) cpl_bivector_delete(skipped_bivector) ;
494 cpl_frameset_delete(rawframes) ;
495 cpl_msg_error(__func__, "At least one frames must be provided") ;
496 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
497 return -1 ;
498 }
499
500 /* Get the rawframes tag used */
501 frame = cpl_frameset_get_position(rawframes, 0);
502 raw_tag = cpl_frame_get_tag(frame) ;
503
504 /* Load IFUS if specified */
505 if (strcmp(ifus_txt, "")) {
506 ifus = kmo_identify_values(ifus_txt);
507 if (ifus == NULL || cpl_vector_get_size(ifus) != nr_frames) {
508 if (ifus != NULL) cpl_vector_delete(ifus);
509 if (skipped_bivector!=NULL) cpl_bivector_delete(skipped_bivector) ;
510 cpl_frameset_delete(rawframes) ;
511 cpl_msg_error(__func__, "ifus size must match the science frames") ;
512 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
513 return -1 ;
514 }
515 } else {
516 ifus = NULL ;
517 }
518
519 /* Check for mapping mode */
520 mapping_mode = NULL ;
521 cpl_size fs_size = cpl_frameset_get_size(rawframes);
522 for (ci = 0; ci < fs_size; ci++) {
523 frame = cpl_frameset_get_position(rawframes, ci);
524 tmp_header = kmclipm_propertylist_load(cpl_frame_get_filename(frame),0);
525 if (cpl_propertylist_has(tmp_header, TPL_ID)) {
526 tmp_strc = cpl_propertylist_get_string(tmp_header, TPL_ID);
527 if (mapping_mode == NULL) {
528 if (!strcmp(tmp_strc, MAPPING8))
529 mapping_mode = cpl_sprintf("%s", tmp_strc);
530 if (!strcmp(tmp_strc, MAPPING24))
531 mapping_mode = cpl_sprintf("%s", tmp_strc);
532 } else {
533 if (strcmp(tmp_strc, mapping_mode)) {
534 cpl_msg_warning(__func__,
535 "There are different TPL IDs in input: %s and %s",
536 tmp_strc, mapping_mode);
537 }
538 }
539 }
540 cpl_propertylist_delete(tmp_header);
541 }
542
543 /* Switch off mapping mode if specific ifus or object are requested */
544 if (mapping_mode != NULL) {
545 if (!strcmp(ifus_txt, "") && !strcmp(name, "")) {
546 cpl_msg_info(__func__,"A map with all IFUs will be generated");
547 extrapol_enum = BCS_NATURAL;
548 } else {
549 if (strcmp(ifus_txt, "")) {
550 cpl_msg_info(__func__,
551 "IFUs %s are requested - switch off mapping mode",
552 ifus_txt);
553 }
554 if (strcmp(name, "")) {
555 cpl_msg_info(__func__,
556 "Object name %s is requested - switch off mapping mode",
557 name);
558 }
559 cpl_free(mapping_mode);
560 mapping_mode = NULL ;
561 }
562 }
563
564 /* Mapping Id : 0->no mapping, 1->mapping8, 2-> mapping24 */
565 mapping_id = -1 ;
566 if (mapping_mode == NULL) {
567 mapping_id = 0 ;
568 cpl_msg_info(__func__, "Mode : Non-Mapping") ;
569 } else {
570 if (!strcmp(mapping_mode, MAPPING8)) {
571 mapping_id = 1 ;
572 cpl_msg_info(__func__, "Mode : Mapping 8") ;
573 }
574 if (!strcmp(mapping_mode, MAPPING24)) {
575 mapping_id = 2 ;
576 cpl_msg_info(__func__, "Mode : Mapping 24") ;
577 }
578 }
579
580 /* Create name/ifu map... */
581 name_vec = cpl_calloc(nr_frames*KMOS_NR_IFUS, sizeof(char*));
582
583 /* No name and no IFU specified and Non mapping mode */
584 if (!strcmp(ifus_txt, "") && !strcmp(name, "") && mapping_mode==NULL) {
585 /* All available names should be combined in one go */
586 name_vec_size = 0;
587 for (i = 0; i < nr_frames; i++) {
588 tmp_str = cpl_sprintf("%d", i);
589 frame = kmo_dfs_get_frame(rawframes, tmp_str);
590 cpl_free(tmp_str);
591 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
592 found = 0;
593 tmp_str = kmo_get_name_from_ocs_ifu(frame, ifu_nr);
594 if (tmp_str != NULL) {
595 for (j = 0; j < name_vec_size; j++) {
596 if (!strcmp(name_vec[j], tmp_str)) {
597 found = TRUE;
598 break;
599 }
600 }
601 if (!found) name_vec[name_vec_size++] = tmp_str;
602 else cpl_free(tmp_str);
603 }
604 }
605 }
606 } else {
607 /* Standard behavior: either ifu_nr- or name- or mapping-case */
608 name_vec_size = 1;
609 if (mapping_mode != NULL) {
610 name_vec[0] = cpl_sprintf("mapping");
611 } else {
612 if (ifus != NULL) {
613 char *tmptmp = NULL;
614
615 // replace all ; with _
616 char *found_char = NULL;
617 found_char = strstr(ifus_txt, ";");
618 while (found_char != NULL) {
619 *found_char = '_';
620 found_char = strstr(ifus_txt, ";");
621 }
622
623 if (strlen(ifus_txt) > 10) {
624 tmptmp = kmo_shorten_ifu_string(ifus_txt);
625 cpl_msg_info(__func__, "Truncate to ..ifu%s..", tmptmp);
626 } else {
627 tmptmp = cpl_sprintf("%s", ifus_txt);
628 }
629 name_vec[0] = cpl_sprintf("IFU%s", tmptmp);
630 ifus_txt = "";
631 cpl_free(tmptmp);
632 } else {
633 name_vec[0] = cpl_sprintf("%s", name);
634 }
635 }
636 }
637
638 /* Display the list of Objects to combine */
639 cpl_msg_info(__func__, "List of Objects to combine:") ;
640 cpl_msg_indent_more() ;
641 for (i = 0; i < name_vec_size ; i++) {
642 cpl_msg_info(__func__, "* %s", name_vec[i]) ;
643 }
644 cpl_msg_indent_less() ;
645
646 /* Load data and noise */
647 data_cube_list = cpl_calloc(nr_frames*KMOS_NR_IFUS,
648 sizeof(cpl_imagelist*));
649 data_header_list = cpl_calloc(nr_frames*KMOS_NR_IFUS,
650 sizeof(cpl_propertylist*));
651 noise_cube_list = cpl_calloc(nr_frames*KMOS_NR_IFUS,
652 sizeof(cpl_imagelist*));
653 noise_header_list = cpl_calloc(nr_frames*KMOS_NR_IFUS,
654 sizeof(cpl_propertylist*));
655
656 /* Load all data (and noise if existent) cubes and store them */
657 for (nv = 0; nv < name_vec_size; nv++) {
658 obj_name = name_vec[nv];
659
660 fwhm_ar = cpl_vector_new(nr_frames*KMOS_NR_IFUS) ;
661 fwhm_ne = cpl_vector_new(nr_frames*KMOS_NR_IFUS) ;
662 pos_ar = cpl_vector_new(nr_frames*KMOS_NR_IFUS) ;
663 pos_ne = cpl_vector_new(nr_frames*KMOS_NR_IFUS) ;
664 airmass_vec = cpl_vector_new(nr_frames*KMOS_NR_IFUS) ;
665 seeing_vec = cpl_vector_new(nr_frames*KMOS_NR_IFUS) ;
666 lambda_vec = cpl_vector_new(nr_frames*KMOS_NR_IFUS) ;
667 used_frame_idx = cpl_calloc(nr_frames*KMOS_NR_IFUS, sizeof(int)) ;
668 used_ifus = cpl_calloc(nr_frames*KMOS_NR_IFUS, sizeof(int)) ;
669 skip_frame_idx = cpl_calloc(nr_frames*KMOS_NR_IFUS, sizeof(int)) ;
670 skip_ifus = cpl_calloc(nr_frames*KMOS_NR_IFUS, sizeof(int)) ;
671
672 data_cube_counter = 0;
673 skip_cube_counter = 0;
674 noise_cube_counter = 0;
675 fwhm_count = 0 ;
676 data_count = 0 ;
677 for (i = 0; i < nr_frames; i++) {
678 tmp_str = cpl_sprintf("%d", i);
679 frame = kmo_dfs_get_frame(rawframes, tmp_str);
680 frame_filename = cpl_frame_get_filename(frame);
681 kmo_init_fits_desc(&desc);
682 desc = kmo_identify_fits_header(frame_filename);
683 main_header = cpl_propertylist_load(frame_filename, 0) ;
684
685 if (mapping_mode != NULL) {
686 /* Mapping mode */
687 for (j = 1; j <= KMOS_NR_IFUS; j++) {
688 /* Loop over all IFUs */
689 if (desc.sub_desc[j-1].valid_data == TRUE &&
690 !kmos_combine_is_skipped(skipped_bivector,i+1,j)) {
691 /* Load data frames */
692 override_err_msg = TRUE;
693 data_cube_list[data_cube_counter] =
694 kmo_dfs_load_cube(rawframes, tmp_str, j,FALSE);
695 override_err_msg = FALSE;
696 if (data_cube_list[data_cube_counter] == NULL) {
697 cpl_error_reset();
698 } else {
699 if (edge_nan) kmo_edge_nan(
700 data_cube_list[data_cube_counter], j);
701 data_header_list[data_cube_counter] =
702 kmo_dfs_load_sub_header(rawframes,
703 tmp_str, j, FALSE);
704
705 /* Store some other quantities */
706 if (kmos_combine_collect_data(main_header,
707 data_header_list[data_cube_counter],
708 &lambda, &seeing, &airmass) == -1) {
709 cpl_error_reset() ;
710 } else {
711 cpl_vector_set(lambda_vec, data_count, lambda) ;
712 cpl_vector_set(seeing_vec, data_count, seeing) ;
713 cpl_vector_set(airmass_vec,data_count,airmass) ;
714 data_count ++ ;
715 }
716
717 /* Store the Resolution */
718 fwhm_ar_val = kmos_pfits_get_qc_ar_fwhm_mean(
719 data_header_list[data_cube_counter]) ;
720 fwhm_ne_val = kmos_pfits_get_qc_ne_fwhm_mean(
721 data_header_list[data_cube_counter]) ;
722 pos_ar_val = kmos_pfits_get_qc_ar_pos_stdev(
723 data_header_list[data_cube_counter]) ;
724 pos_ne_val = kmos_pfits_get_qc_ne_pos_stdev(
725 data_header_list[data_cube_counter]) ;
726 if (cpl_error_get_code() != CPL_ERROR_NONE) {
727 cpl_error_reset() ;
728 } else {
729 cpl_vector_set(fwhm_ar,fwhm_count,
730 light_speed/fwhm_ar_val) ;
731 cpl_vector_set(fwhm_ne,fwhm_count,
732 light_speed/fwhm_ne_val) ;
733 cpl_vector_set(pos_ar,fwhm_count,
734 pos_ar_val*lambda/light_speed) ;
735 cpl_vector_set(pos_ne,fwhm_count,
736 pos_ne_val*lambda/light_speed) ;
737 fwhm_count++ ;
738 }
739
740 cpl_propertylist_update_string(
741 data_header_list[data_cube_counter],
742 "ESO PRO FRNAME", frame_filename);
743 cpl_propertylist_update_int(
744 data_header_list[data_cube_counter],
745 "ESO PRO IFUNR", j);
746 used_frame_idx[data_cube_counter] = i+1 ;
747 used_ifus[data_cube_counter] = j ;
748 data_cube_counter++;
749 }
750
751 /* Load noise frames */
752 override_err_msg = TRUE;
753 noise_cube_list[noise_cube_counter] =
754 kmo_dfs_load_cube(rawframes, tmp_str, j, TRUE);
755
756 override_err_msg = FALSE;
757 if (noise_cube_list[noise_cube_counter] == NULL) {
758 cpl_error_reset();
759 } else {
760 if (edge_nan) kmo_edge_nan(
761 noise_cube_list[noise_cube_counter], j);
762 noise_header_list[noise_cube_counter] =
763 kmo_dfs_load_sub_header(rawframes, tmp_str,
764 j, TRUE);
765 noise_cube_counter++;
766 }
767
768 /* Check if number of data and noise frames match */
769 if (noise_cube_counter > 0) {
770 if (data_cube_counter != noise_cube_counter) {
771 cpl_msg_error(__func__, "Noise missing") ;
772 cpl_error_set(__func__,CPL_ERROR_ILLEGAL_INPUT);
773 /* TODO - deallocate */
774 return -1 ;
775 }
776 }
777 } else if (kmos_combine_is_skipped(skipped_bivector,
778 i+1, j)) {
779 skip_frame_idx[skip_cube_counter] = i+1 ;
780 skip_ifus[skip_cube_counter] = j ;
781 skip_cube_counter++;
782 }
783 }
784 } else {
785 /* Non-Mapping Mode */
786 if (ifus != NULL) ifu_nr = cpl_vector_get(ifus, i);
787 else ifu_nr = kmo_get_index_from_ocs_name(frame, obj_name);
788 if (ifu_nr > 0) {
789 index = kmo_identify_index(frame_filename, ifu_nr , FALSE);
790 if (desc.sub_desc[index-1].valid_data == TRUE &&
791 !kmos_combine_is_skipped(skipped_bivector,i+1,
792 ifu_nr)) {
793 /* Load data frames */
794 override_err_msg = TRUE;
795 data_cube_list[data_cube_counter] =
796 kmo_dfs_load_cube(rawframes, tmp_str, ifu_nr,
797 FALSE);
798 override_err_msg = FALSE;
799 if (data_cube_list[data_cube_counter] == NULL) {
800 /* No data found for this IFU */
801 cpl_error_reset();
802 if (ifus != NULL)
803 cpl_msg_warning(cpl_func,
804 "IFU %d miѕsing in frame %s",
805 ifu_nr, frame_filename);
806 else
807 cpl_msg_warning(cpl_func,
808 "Object %s missing in Frame %d (%s)",
809 obj_name, i+1, frame_filename) ;
810 } else {
811 if (edge_nan) kmo_edge_nan(
812 data_cube_list[data_cube_counter], ifu_nr);
813 data_header_list[data_cube_counter] =
814 kmo_dfs_load_sub_header(rawframes, tmp_str,
815 ifu_nr, FALSE);
816
817 /* Store some other quantities */
818 if (kmos_combine_collect_data(main_header,
819 data_header_list[data_cube_counter],
820 &lambda, &seeing, &airmass) == -1) {
821 cpl_error_reset() ;
822 } else {
823 cpl_vector_set(lambda_vec, data_count, lambda) ;
824 cpl_vector_set(seeing_vec, data_count, seeing) ;
825 cpl_vector_set(airmass_vec,data_count,airmass) ;
826 data_count ++ ;
827 }
828
829 /* Store the Resolution and crder3 */
830 fwhm_ar_val = kmos_pfits_get_qc_ar_fwhm_mean(
831 data_header_list[data_cube_counter]) ;
832 fwhm_ne_val = kmos_pfits_get_qc_ne_fwhm_mean(
833 data_header_list[data_cube_counter]) ;
834 pos_ar_val = kmos_pfits_get_qc_ar_pos_stdev(
835 data_header_list[data_cube_counter]) ;
836 pos_ne_val = kmos_pfits_get_qc_ne_pos_stdev(
837 data_header_list[data_cube_counter]) ;
838 if (cpl_error_get_code() != CPL_ERROR_NONE) {
839 cpl_error_reset() ;
840 } else {
841 cpl_vector_set(fwhm_ar,fwhm_count,
842 light_speed/fwhm_ar_val) ;
843 cpl_vector_set(fwhm_ne,fwhm_count,
844 light_speed/fwhm_ne_val) ;
845 cpl_vector_set(pos_ar,fwhm_count,
846 pos_ar_val*lambda/light_speed) ;
847 cpl_vector_set(pos_ne,fwhm_count,
848 pos_ne_val*lambda/light_speed) ;
849 fwhm_count++ ;
850 }
851
852 cpl_propertylist_update_string(
853 data_header_list[data_cube_counter],
854 "ESO PRO FRNAME", frame_filename);
855 cpl_propertylist_update_int(
856 data_header_list[data_cube_counter],
857 "ESO PRO IFUNR", ifu_nr);
858 used_frame_idx[data_cube_counter] = i+1 ;
859 used_ifus[data_cube_counter] = ifu_nr ;
860 data_cube_counter++;
861 }
862
863 /* Load noise frames */
864 override_err_msg = TRUE;
865 noise_cube_list[noise_cube_counter] =
866 kmo_dfs_load_cube(rawframes, tmp_str, ifu_nr,
867 TRUE);
868 override_err_msg = FALSE;
869 if (noise_cube_list[noise_cube_counter] == NULL) {
870 /* No noise found for this IFU */
871 cpl_error_reset();
872 } else {
873 if (edge_nan) kmo_edge_nan(
874 noise_cube_list[noise_cube_counter],ifu_nr);
875 noise_header_list[noise_cube_counter] =
876 kmo_dfs_load_sub_header(rawframes,
877 tmp_str, ifu_nr, TRUE);
878 noise_cube_counter++;
879 }
880
881 /* Check if number of data and noise frames match */
882 if (noise_cube_counter > 0) {
883 if (data_cube_counter != noise_cube_counter) {
884 /* TODO - deallocate */
885 cpl_msg_error(__func__, "Noise missing") ;
886 cpl_error_set(__func__,CPL_ERROR_ILLEGAL_INPUT);
887 return -1 ;
888 }
889 }
890 } else if (kmos_combine_is_skipped(skipped_bivector,
891 i+1, ifu_nr)) {
892 skip_frame_idx[skip_cube_counter] = i+1 ;
893 skip_ifus[skip_cube_counter] = ifu_nr ;
894 skip_cube_counter++;
895 }
896 }
897 }
898 cpl_propertylist_delete(main_header) ;
899 kmo_free_fits_desc(&desc);
900 cpl_free(tmp_str);
901 }
902
903 /* Compute the Resolution */
904 if (fwhm_count > 2) {
905 tmp_vec = cpl_vector_extract(fwhm_ar, 0, fwhm_count-1, 1) ;
906 fwhm_ar_med = cpl_vector_get_median(tmp_vec) ;
907 cpl_vector_delete(tmp_vec) ;
908 tmp_vec = cpl_vector_extract(fwhm_ne, 0, fwhm_count-1, 1) ;
909 fwhm_ne_med = cpl_vector_get_median(tmp_vec) ;
910 cpl_vector_delete(tmp_vec) ;
911 tmp_vec = cpl_vector_extract(pos_ar, 0, fwhm_count-1, 1) ;
912 pos_ar_med = cpl_vector_get_median(tmp_vec) ;
913 cpl_vector_delete(tmp_vec) ;
914 tmp_vec = cpl_vector_extract(pos_ne, 0, fwhm_count-1, 1) ;
915 pos_ne_med = cpl_vector_get_median(tmp_vec) ;
916 cpl_vector_delete(tmp_vec) ;
917 spec_res = (fwhm_ar_med + fwhm_ne_med) / 2.0 ;
918 crder3 = (pos_ar_med + pos_ne_med) / 2.0 ;
919 } else if (fwhm_count > 0) {
920 tmp_vec = cpl_vector_extract(fwhm_ar, 0, fwhm_count-1, 1) ;
921 fwhm_ar_med = cpl_vector_get_mean(tmp_vec) ;
922 cpl_vector_delete(tmp_vec) ;
923 tmp_vec = cpl_vector_extract(fwhm_ne, 0, fwhm_count-1, 1) ;
924 fwhm_ne_med = cpl_vector_get_mean(tmp_vec) ;
925 cpl_vector_delete(tmp_vec) ;
926 tmp_vec = cpl_vector_extract(pos_ar, 0, fwhm_count-1, 1) ;
927 pos_ar_med = cpl_vector_get_mean(tmp_vec) ;
928 cpl_vector_delete(tmp_vec) ;
929 tmp_vec = cpl_vector_extract(pos_ne, 0, fwhm_count-1, 1) ;
930 pos_ne_med = cpl_vector_get_mean(tmp_vec) ;
931 cpl_vector_delete(tmp_vec) ;
932 spec_res = (fwhm_ar_med + fwhm_ne_med) / 2.0 ;
933 crder3 = (pos_ar_med + pos_ne_med) / 2.0 ;
934 } else {
935 cpl_msg_debug(__func__, "Cound not retrieve QC ARC - FWHM MEAN") ;
936 spec_res = -1.0 ;
937 crder3 = -1.0 ;
938 }
939 cpl_vector_delete(fwhm_ar) ;
940 cpl_vector_delete(fwhm_ne) ;
941 cpl_vector_delete(pos_ar) ;
942 cpl_vector_delete(pos_ne) ;
943
944 /* Compute SKY_RES / SKY_RERR */
945 sky_res_vec = cpl_vector_new(data_count) ;
946 for (i=0 ; i<data_count ; i++) {
947 lambda = cpl_vector_get(lambda_vec, i) ;
948 seeing = cpl_vector_get(seeing_vec, i) ;
949 airmass = cpl_vector_get(airmass_vec, i) ;
950 outer_scale=sqrt(1-78.08*((pow(lambda*1e-6,0.4)*pow(airmass,-0.2))/
951 (pow(seeing,1./3.)))) ;
952 sky_res = seeing * pow(0.5/lambda, 0.2) * pow(airmass, 3./5.) *
953 outer_scale ;
954 cpl_vector_set(sky_res_vec, i, sky_res) ;
955 }
956 cpl_vector_delete(airmass_vec) ;
957 cpl_vector_delete(seeing_vec) ;
958 cpl_vector_delete(lambda_vec) ;
959
960 if (data_count > 2) {
961 sky_res = cpl_vector_get_median_const(sky_res_vec) ;
962 sky_rerr = sqrt((0.2*0.2)+pow(cpl_vector_get_stdev(sky_res_vec),2));
963 } else {
964 sky_res = cpl_vector_get_mean(sky_res_vec) ;
965 sky_rerr = 0.2;
966 }
967 cpl_vector_delete(sky_res_vec) ;
968
969 /* Make sure sky_rerr is within limits */
970 if (sky_rerr > 1.0) sky_rerr = 0.3;
971 if (sky_rerr < 0.0) sky_rerr = 0.3;
972
973 /* Create String for the output header - IFUs usage */
974 used_ifus_str = kmos_combine_create_ifus_string(used_frame_idx,
975 used_ifus, data_cube_counter);
976 cpl_free(used_ifus) ;
977 skip_ifus_str = kmos_combine_create_ifus_string(skip_frame_idx,
978 skip_ifus, skip_cube_counter);
979 cpl_free(skip_frame_idx) ;
980 cpl_free(skip_ifus) ;
981
982 /* Setup output category COMBINE + ESO PRO CATG */
983 main_header = kmo_dfs_load_primary_header(rawframes, "0");
984 const char *tag = cpl_propertylist_get_string(main_header,
985 CPL_DFS_PRO_CATG);
986
987 /* Combine data */
988 exp_mask = NULL ;
989 cube_combined_noise = NULL ;
990 cube_combined_data = NULL ;
991 cpl_error_code err;
992 if (!suppress_extension || strcmp(obj_name, "mapping") == 0) {
993 err = kmo_priv_combine(data_cube_list, noise_cube_list,
994 data_header_list, noise_header_list,
995 data_cube_counter, noise_cube_counter,
996 obj_name, ifus_txt, method, "BCS",
997 fmethod, filename, cmethod,
998 cpos_rej, cneg_rej, citer, cmin, cmax,
999 extrapol_enum, flux, &cube_combined_data,
1000 &cube_combined_noise, &exp_mask);
1001 } else {
1002 char *name_suppress = cpl_sprintf("%d", suppress_index);
1003 err = kmo_priv_combine(data_cube_list, noise_cube_list,
1004 data_header_list, noise_header_list,
1005 data_cube_counter, noise_cube_counter,
1006 name_suppress, ifus_txt, method, "BCS",
1007 fmethod, filename, cmethod,
1008 cpos_rej, cneg_rej, citer, cmin, cmax,
1009 extrapol_enum, flux, &cube_combined_data,
1010 &cube_combined_noise, &exp_mask);
1011 cpl_free(name_suppress);
1012 }
1013 if (err != CPL_ERROR_NONE) {
1014 for (i = 0; i < data_cube_counter ; i++)
1015 cpl_imagelist_delete(data_cube_list[i]);
1016 for (i = 0; i < noise_cube_counter ; i++)
1017 cpl_imagelist_delete(noise_cube_list[i]);
1018 for (i = 0; i < data_cube_counter ; i++)
1019 cpl_propertylist_delete(data_header_list[i]);
1020 for (i = 0; i < noise_cube_counter ; i++)
1021 cpl_propertylist_delete(noise_header_list[i]);
1022 if (ifus != NULL) cpl_vector_delete(ifus);
1023 cpl_free(data_cube_list);
1024 cpl_free(noise_cube_list);
1025 cpl_free(data_header_list);
1026 cpl_free(noise_header_list);
1027 for (i = 0; i < name_vec_size ; i++) cpl_free(name_vec[i]);
1028 cpl_free(name_vec);
1029 cpl_free(used_ifus_str) ;
1030 cpl_free(skip_ifus_str) ;
1031 cpl_frameset_delete(rawframes) ;
1032 cpl_free(used_frame_idx) ;
1033 if (mapping_mode != NULL) cpl_free(mapping_mode) ;
1034 cpl_msg_error(__func__, "Failed Combination") ;
1035 cpl_error_set(__func__,CPL_ERROR_ILLEGAL_INPUT);
1036 return -1 ;
1037 }
1038
1039 for (i = 0; i < data_cube_counter ; i++)
1040 cpl_imagelist_delete(data_cube_list[i]);
1041 for (i = 0; i < noise_cube_counter ; i++)
1042 cpl_imagelist_delete(noise_cube_list[i]);
1043
1044 /* Replace 0s by NANs at the beginning and at the end of the cube */
1045 kmos_idp_set_nans(cube_combined_data, cube_combined_noise) ;
1046
1047 /* Compute ABMAGLIM */
1048 abmaglim = kmos_idp_compute_abmaglim(cube_combined_data,
1049 sky_res, data_header_list[0]) ;
1050 if (cpl_error_get_code()) {
1051 cpl_msg_warning(
1052 __func__, "kmos_idp_compute_abmaglim raised CPL error: \"%s\"; "
1053 "setting abmaglim to 1.0", cpl_error_get_message());
1054 abmaglim = 1.0;
1055 cpl_error_reset();
1056 }
1057
1058 /* Save data */
1059 if (!suppress_extension) {
1060 fn_combine = cpl_sprintf("%s_%s_%s", COMBINE, tag, name_vec[nv] );
1061 fn_mask = cpl_sprintf("%s_%s_%s", EXP_MASK, tag, name_vec[nv] );
1062 } else {
1063 fn_combine = cpl_sprintf("%s_%s_%d", COMBINE, tag, suppress_index);
1064 fn_mask = cpl_sprintf("%s_%s_%d", EXP_MASK, tag, suppress_index);
1065 suppress_index++;
1066 }
1067 /* PIPE-8812 DEBUG - copy convolved data to individual files */
1068 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
1069 char *cft_fn;
1070 cft_fn = cpl_sprintf("%s_%s.fits", "convolved_fov_trimmed", name_vec[nv]);
1071 cpl_image *cft = cpl_image_load("convolved_fov_trimmed.fits", CPL_TYPE_DOUBLE, 0, 0);
1072 cpl_image_save(cft, cft_fn, CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1073 cpl_image_delete(cft);
1074
1075 cft_fn = cpl_sprintf("%s_%s.fits", "convolved_fov", name_vec[nv]);
1076 cft = cpl_image_load("convolved_fov.fits", CPL_TYPE_DOUBLE, 0, 0);
1077 cpl_image_save(cft, cft_fn, CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1078 cpl_image_delete(cft);
1079
1080 cft_fn = cpl_sprintf("%s_%s.fits", "mirrored", name_vec[nv]);
1081 cft = cpl_image_load("mirrored.fits", CPL_TYPE_DOUBLE, 0, 0);
1082 cpl_image_save(cft, cft_fn, CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1083 cpl_image_delete(cft);
1084
1085 cft_fn = cpl_sprintf("%s_%s.fits", "cropped", name_vec[nv]);
1086 cft = cpl_image_load("cropped.fits", CPL_TYPE_DOUBLE, 0, 0);
1087 cpl_image_save(cft, cft_fn, CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1088 cpl_image_delete(cft);
1089
1090 cft_fn = cpl_sprintf("%s_%s.fits", "collapse", name_vec[nv]);
1091 cft = cpl_image_load("collapse.fits", CPL_TYPE_DOUBLE, 0, 0);
1092 cpl_image_save(cft, cft_fn, CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1093 cpl_image_delete(cft);
1094
1095 cft_fn = cpl_sprintf("%s_%s.fits", "mode_limited", name_vec[nv]);
1096 cft = cpl_image_load("mode_limited.fits", CPL_TYPE_DOUBLE, 0, 0);
1097 cpl_image_save(cft, cft_fn, CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1098 cpl_image_delete(cft);
1099 }
1100
1101
1102
1103 /* Create PRO keys plist */
1104 plist = cpl_propertylist_new() ;
1105 if (used_ifus_str != NULL)
1106 cpl_propertylist_update_string(plist, "ESO PRO USEDIFUS",
1107 used_ifus_str) ;
1108 if (skip_ifus_str != NULL)
1109 cpl_propertylist_update_string(plist, "ESO PRO SKIPPEDIFUS",
1110 skip_ifus_str) ;
1111
1112 /* QC EXPMASK AVG */
1113 cpl_propertylist_update_double(plist, "ESO QC EXPMASK AVG",
1114 kmos_get_median_from_positives(exp_mask)) ;
1115
1116 /* Store SPEC_REC in the header */
1117 cpl_propertylist_update_double(plist, KEY_SPEC_RES, spec_res) ;
1118 cpl_propertylist_set_comment(plist, KEY_SPEC_RES, KEY_SPEC_RES_COMMENT);
1119
1120 /* Store data_cube_counter */
1121 cpl_propertylist_update_int(plist, "ESO QC COMBINED_CUBES NB",
1122 data_cube_counter) ;
1123
1124 /* EXPMASK NAME */
1125 tmp_str = cpl_sprintf("%s.fits", fn_mask) ;
1126 cpl_propertylist_update_string(plist, "ESO QC EXPMASK NAME", tmp_str) ;
1127 cpl_free(tmp_str) ;
1128
1129 /* Add the Collapsed File Name */
1130 if (collapse_combined) {
1131 tmp_str = cpl_sprintf("make_image_%s.fits", fn_combine) ;
1132 cpl_propertylist_update_string(plist, "ESO QC COLLAPSE NAME",
1133 tmp_str) ;
1134 cpl_free(tmp_str) ;
1135 }
1136
1137 /* ABMAGLIM */
1138 if (abmaglim > 5.0 && abmaglim < 30.0)
1139 {
1140 cpl_propertylist_update_double(plist, KEY_ABMAGLIM, abmaglim) ;
1141 cpl_propertylist_set_comment(plist, KEY_ABMAGLIM, KEY_ABMAGLIM_COMMENT);
1142 }
1143
1144 /* SKY_RES / SKY_RERR */
1145
1146 if (sky_res > 0.15 && sky_res < 5.0)
1147 {
1148 cpl_propertylist_update_double(plist, KEY_SKY_RES, sky_res) ;
1149 cpl_propertylist_set_comment(plist, KEY_SKY_RES, KEY_SKY_RES_COMMENT) ;
1150 cpl_propertylist_update_double(plist, KEY_SKY_RERR, sky_rerr) ;
1151 cpl_propertylist_set_comment(plist, KEY_SKY_RERR,KEY_SKY_RERR_COMMENT) ;
1152 }
1153
1154 /* Add REFLEX SUFFIX keyword */
1155 reflex_suffix = kmos_get_reflex_suffix(mapping_id, ifus_txt, name,
1156 obj_name) ;
1157 cpl_propertylist_update_string(plist, "ESO PRO REFLEX SUFFIX",
1158 reflex_suffix) ;
1159 cpl_free(reflex_suffix) ;
1160
1161 /* MJD Keys */
1162 kmos_idp_compute_mjd(frameset, raw_tag, used_frame_idx,
1163 data_cube_counter, &mjd_start, &mjd_end, &date_obs) ;
1164
1165 /* Save Headers first */
1166 frame = cpl_frameset_find(rawframes, NULL);
1167
1168 /* Build the Object keywords */
1169 object_key =
1170 cpl_sprintf("%s/%s",
1171 kmos_pfits_get_reflex_suffix(plist),
1172 kmos_pfits_get_obs_targ_name(main_header));
1173 object_data_key =
1174 cpl_sprintf("%s/%s (DATA)",
1175 kmos_pfits_get_reflex_suffix(plist),
1176 kmos_pfits_get_obs_targ_name(main_header));
1177 object_stat_key =
1178 cpl_sprintf("%s/%s (STAT)",
1179 kmos_pfits_get_reflex_suffix(plist),
1180 kmos_pfits_get_obs_targ_name(main_header));
1181
1182 /* Truncate */
1183 if (strlen(object_key) > 68) object_key[68] = 0;
1184 if (strlen(object_data_key) > 68) object_data_key[68] = 0;
1185 if (strlen(object_stat_key) > 68) object_stat_key[68] = 0;
1186
1187 /* Cleanup */
1188 /*cpl_propertylist_delete(main_header); */
1189
1190 /************/
1191 /* EXP_MASK */
1192 /************/
1193 cpl_propertylist * plist2 = cpl_propertylist_duplicate(plist) ;
1194
1195 char * fname_expmap = cpl_sprintf("%s%s", fn_mask, ".fits") ;
1196 char * my_procatg_expmap = NULL ;
1197 char * my_prodcatg_expmap = NULL ;
1198
1199 /* NOTE: Modified to accept SINGLE_CUBES in kmos_combine (PIPE-7566) */
1200 if (!strncmp(fn_mask, EXP_MASK_RECONS,
1201 strlen(EXP_MASK_RECONS))||
1202 !strncmp(fn_mask, EXP_MASK_SINGLE_CUBES,
1203 strlen(EXP_MASK_SINGLE_CUBES)) ){
1204 /* DFS-6276 */
1205 /* TRICK to fix the PROCATG=EXP_MASK_RECONS"_030" */
1206 /* -------------> PROCATG=EXP_MASK_RECONS */
1207 my_procatg_expmap = cpl_sprintf(EXP_MASK) ;
1208 /* my_prodcatg_expmap = cpl_sprintf("ANCILLARY.EXPMAP") ; */
1209 my_prodcatg_expmap = cpl_sprintf("ANCILLARY.PIXELCOUNTMAP") ;
1210 } else {
1211 my_procatg_expmap = cpl_strdup(fn_mask) ;
1212 }
1213 cpl_propertylist_update_string(plist2, CPL_DFS_PRO_CATG,
1214 my_procatg_expmap);
1215 if (my_prodcatg_expmap != NULL) {
1216 cpl_propertylist_update_string(plist2, KEY_PRODCATG,
1217 my_prodcatg_expmap);
1218 cpl_free(my_prodcatg_expmap) ;
1219 cpl_propertylist_set_comment(plist2, KEY_PRODCATG,
1220 KEY_PRODCATG_COMMENT);
1221 }
1222 cpl_propertylist_update_string(plist2, INSTRUMENT, "KMOS") ;
1223
1224 cpl_msg_info(cpl_func, "Writing FITS propertylist product(%s): %s",
1225 my_procatg_expmap, fname_expmap);
1226
1227 cpl_frame * product_frame_expmap = cpl_frame_new();
1228 cpl_frame_set_filename(product_frame_expmap, fname_expmap);
1229 cpl_frame_set_tag(product_frame_expmap, my_procatg_expmap);
1230 cpl_frame_set_type(product_frame_expmap, CPL_FRAME_TYPE_ANY);
1231 cpl_frame_set_group(product_frame_expmap, CPL_FRAME_GROUP_PRODUCT);
1232 cpl_frame_set_level(product_frame_expmap, CPL_FRAME_LEVEL_FINAL);
1233 cpl_free(my_procatg_expmap) ;
1234
1235 /* Add DataFlow keywords */
1236 cpl_dfs_setup_product_header(plist2, product_frame_expmap, frameset,
1237 parlist, cpl_func, PACKAGE "/" PACKAGE_VERSION, CPL_DFS_PRO_DID, frame);
1238
1239 /* Set RA/DEC */
1240
1241 /* Fix RA / DEC <- Set to CRVAL1 / CRVAL2 */
1242 /* plist2(RA / DEC) from plist3(CRVAL1 / CRVAL2) */
1243 crval1 = cpl_propertylist_get_double(data_header_list[0], CRVAL1);
1244 crval2 = cpl_propertylist_get_double(data_header_list[0], CRVAL2);
1245 kmclipm_update_property_double(plist2, "RA", crval1, "") ;
1246 kmclipm_update_property_double(plist2, "DEC", crval2, "") ;
1247
1248 /* Update OBJECT */
1249 cpl_propertylist_update_string(plist2, "OBJECT", object_key) ;
1250
1251 /* Save and register */
1252 cpl_propertylist_save(plist2, fname_expmap, CPL_IO_CREATE);
1253 cpl_free(fname_expmap) ;
1254 cpl_frameset_insert(frameset, product_frame_expmap);
1255 /* cpl_frame_delete(product_frame_expmap); */
1256
1257 cpl_propertylist_delete(plist2) ;
1258
1259 /* ASSON PROV */
1260 kmos_idp_add_files_infos(plist, frameset, raw_tag, used_frame_idx,
1261 data_cube_counter) ;
1262 cpl_free(used_frame_idx) ;
1263
1264 /************/
1265 /* COMBINED */
1266 /************/
1267 char * fname = cpl_sprintf("%s%s", fn_combine, ".fits") ;
1268 char * my_procatg = NULL ;
1269 char * my_prodcatg = NULL ;
1270
1271 /* NOTE: Modified to accept SINGLE_CUBES in kmos_combine (PIPE-7566) */
1272 if (!strncmp(fn_combine, COMBINED_RECONS, strlen(COMBINED_RECONS)) ||
1273 !strncmp(fn_combine, COMBINED_SINGLE_CUBES,
1274 strlen(COMBINED_SINGLE_CUBES))){
1275 /* DFS-6227 */
1276 /* TRICK to fix the PROCATG=COMBINED_RECONS"_030" */
1277 /* -------------> PROCATG=COMBINED_RECONS */
1278 my_procatg = cpl_sprintf(COMBINED_CUBE);
1279 } else {
1280 my_procatg = cpl_strdup(fn_combine) ;
1281 }
1282 cpl_propertylist_update_string(plist, CPL_DFS_PRO_CATG, my_procatg);
1283 if (my_prodcatg != NULL) {
1284 cpl_propertylist_update_string(plist, KEY_PRODCATG, my_prodcatg);
1285 cpl_free(my_prodcatg) ;
1286 cpl_propertylist_set_comment(plist, KEY_PRODCATG,
1287 KEY_PRODCATG_COMMENT);
1288 }
1289 cpl_propertylist_update_string(plist, INSTRUMENT, "KMOS") ;
1290
1291 cpl_msg_info(cpl_func, "Writing FITS propertylist product(%s): %s",
1292 my_procatg, fname);
1293 cpl_msg_info(cpl_func, " WRITING FITS FOR 2");
1294
1295 cpl_frame * product_frame = cpl_frame_new();
1296 cpl_frame_set_filename(product_frame, fname);
1297 cpl_frame_set_tag(product_frame, my_procatg);
1298 cpl_frame_set_type(product_frame, CPL_FRAME_TYPE_ANY);
1299 cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_PRODUCT);
1300 cpl_frame_set_level(product_frame, CPL_FRAME_LEVEL_FINAL);
1301 cpl_free(my_procatg) ;
1302
1303 /* Add DataFlow keywords */
1304 cpl_dfs_setup_product_header(plist, product_frame, frameset, parlist,
1305 cpl_func, PACKAGE "/" PACKAGE_VERSION, CPL_DFS_PRO_DID, frame);
1306
1307 /* Set DATE-OBS / MJD-OBS / MJD-END */
1308 if (mjd_start > 0.0) {
1309 if (date_obs != NULL) {
1310 cpl_propertylist_update_string(plist, KEY_DATEOBS, date_obs) ;
1311 cpl_free(date_obs) ;
1312 } else {
1313 cpl_propertylist_update_string(plist, KEY_DATEOBS, "") ;
1314 }
1315 cpl_propertylist_set_comment(plist, KEY_DATEOBS,
1316 KEY_DATEOBS_COMMENT);
1317
1318 cpl_propertylist_update_double(plist, KEY_MJDOBS, mjd_start) ;
1319 cpl_propertylist_set_comment(plist, KEY_MJDOBS, KEY_MJDOBS_COMMENT);
1320 }
1321 if (mjd_end > 0.0) {
1322 cpl_propertylist_update_double(plist, KEY_MJDEND, mjd_end) ;
1323 cpl_propertylist_set_comment(plist, KEY_MJDEND, KEY_MJDEND_COMMENT);
1324 }
1325
1326 /* Update OBJECT */
1327 cpl_propertylist_update_string(plist, "OBJECT", object_key) ;
1328
1329 // ADD QC PARAMETERS HERE -
1330
1331 cpl_msg_info(cpl_func, " GETTING TO QC PARAMS LEVEL ");
1332 /* PROC SCHEME */
1333
1334 if (cpl_propertylist_has(main_header, QC_SAT_LEVEL)) {
1335 cpl_propertylist_update_double(plist, QC_SAT_LEVEL,
1336 cpl_propertylist_get_double(main_header, QC_SAT_LEVEL));
1337 }
1338
1339 if (cpl_propertylist_has(main_header, QC_SAT_NB)) {
1340 cpl_propertylist_update_int(plist, QC_SAT_NB,
1341 cpl_propertylist_get_int(main_header, QC_SAT_NB));
1342 }
1343
1344 if (cpl_propertylist_has(main_header, QC_PERS_LEVEL)) {
1345 cpl_propertylist_update_double(plist, QC_PERS_LEVEL,
1346 cpl_propertylist_get_double(main_header, QC_PERS_LEVEL));
1347 }
1348
1349 if (cpl_propertylist_has(main_header, QC_PERS_NB)) {
1350 cpl_propertylist_update_int(plist, QC_PERS_NB,
1351 cpl_propertylist_get_int(main_header, QC_PERS_NB));
1352 }
1353
1354 if (cpl_propertylist_has(main_header, QC_MASTER_FLAT_MJD_OBS)) {
1355
1356 cpl_propertylist_update_double(plist, QC_DELTA_TIME_FLAT,
1357 (cpl_propertylist_get_double(main_header,
1358 QC_MASTER_FLAT_MJD_OBS)-mjd_start));
1359 }
1360
1361 if (cpl_propertylist_has(main_header, QC_TELLURIC_GEN_MJD_OBS)) {
1362 cpl_propertylist_update_double(plist, QC_DELTA_TIME_TELL,
1363 (cpl_propertylist_get_double(main_header,
1364 QC_TELLURIC_GEN_MJD_OBS)-mjd_start));
1365 }
1366
1367 cpl_propertylist_update_string(plist, QC_PROC_SCHEME,
1368 QC_PROC_SCHEME_VAL) ;
1369 cpl_propertylist_set_comment(plist, QC_PROC_SCHEME, QC_PROC_SCHEME_TXT);
1370
1371
1372 if (cpl_propertylist_has(main_header, QC_PARAM_H2O_AVG)) {
1373 cpl_propertylist_update_double(plist, QC_PARAM_H2O_AVG,
1374 cpl_propertylist_get_double(main_header, QC_PARAM_H2O_AVG));
1375 }
1376
1377 if (cpl_propertylist_has(main_header, QC_PARAM_H2O_RMS)) {
1378 cpl_propertylist_update_double(plist, QC_PARAM_H2O_RMS,
1379 cpl_propertylist_get_double(main_header, QC_PARAM_H2O_RMS));
1380 }
1381
1382 if (cpl_propertylist_has(main_header, QC_PARAM_AIRM_STD)) {
1383
1384 cpl_msg_info(cpl_func, " QC_PARAM_AIRM_STD exists ");
1385 cpl_propertylist_update_double(plist, "ESO QC AIRM DIFF",
1386 fabs(cpl_propertylist_get_double(main_header, QC_PARAM_AIRM_STD)-
1387// cpl_msg_info(cpl_func, " QC_PARAM_AIRM_STD value %f ", cpl_propertylist_get_double(main_header, QC_PARAM_AIRM_STD));
1388 (cpl_propertylist_get_double(main_header, "ESO TEL AIRM START")+
1389 cpl_propertylist_get_double(main_header, "ESO TEL AIRM END"))/2));
1390 }
1391
1392 if (cpl_propertylist_has(main_header, QC_PARAM_MEAS_IWV)) {
1393 cpl_propertylist_update_double(plist, QC_PARAM_MEAS_IWV,
1394 cpl_propertylist_get_double(main_header, QC_PARAM_MEAS_IWV));
1395 }
1396 else{
1397 if (cpl_propertylist_has(main_header, "ESO TEL AMBI IWV START")){
1398 cpl_propertylist_update_double(plist, QC_PARAM_MEAS_IWV,
1399 (cpl_propertylist_get_double(main_header, "ESO TEL AMBI IWV START")+
1400 cpl_propertylist_get_double(main_header, "ESO TEL AMBI IWV END"))/2);
1401 }
1402 }
1403
1404 if (cpl_propertylist_has(main_header, QC_PARAM_MEAS_IWV30D)) {
1405 cpl_propertylist_update_double(plist, QC_PARAM_MEAS_IWV30D,
1406 cpl_propertylist_get_double(main_header, QC_PARAM_MEAS_IWV30D));
1407 }
1408 else{
1409 if (cpl_propertylist_has(main_header, "ESO TEL AMBI IWV30D START")){
1410 cpl_propertylist_update_double(plist, QC_PARAM_MEAS_IWV30D,
1411 (cpl_propertylist_get_double(main_header, "ESO TEL AMBI IWV30D START")+
1412 cpl_propertylist_get_double(main_header, "ESO TEL AMBI IWV30D END"))/2);
1413 }
1414
1415 }
1416
1417 if (cpl_propertylist_has(main_header, QC_PARAM_H2O_RATIO)) {
1418 cpl_propertylist_update_double(plist, QC_PARAM_H2O_RATIO,
1419 cpl_propertylist_get_double(main_header, QC_PARAM_H2O_RATIO));
1420 }
1421 else {
1422 if (cpl_propertylist_has(main_header, QC_PARAM_H2O_AVG ) &&
1423 cpl_propertylist_has(plist, "ESO TEL AMBI IWV START" ) ){
1424 cpl_propertylist_update_double(plist, QC_PARAM_H2O_RATIO,
1425 (cpl_propertylist_get_double(plist, QC_PARAM_H2O_AVG )/
1426 ((cpl_propertylist_get_double(main_header, "ESO TEL AMBI IWV START")+
1427 cpl_propertylist_get_double(main_header, "ESO TEL AMBI IWV END"))/2)));
1428 }
1429 }
1430 /* This block was copying the existing erroneous QC_PARAM_H2O_DELTA from the input files */
1431 /*if (cpl_propertylist_has(main_header, QC_PARAM_H2O_DELTA)) {
1432 cpl_propertylist_update_double(plist, QC_PARAM_H2O_DELTA,
1433 cpl_propertylist_get_double(main_header, QC_PARAM_H2O_DELTA));
1434 }
1435 else {*/
1436 /* Have to redo the calculation here properly */
1437 if (cpl_propertylist_has(main_header, QC_PARAM_H2O_AVG ) &&
1438 cpl_propertylist_has(plist, QC_PARAM_MEAS_IWV )){
1439 cpl_propertylist_update_double(plist, QC_PARAM_H2O_DELTA,
1440 (cpl_propertylist_get_double(plist, QC_PARAM_H2O_AVG )-
1441 cpl_propertylist_get_double(plist, QC_PARAM_MEAS_IWV)));
1442 }
1443 /*if (cpl_propertylist_has(main_header, QC_PARAM_H2O_AVG ) &&
1444 cpl_propertylist_has(main_header, "ESO TEL AMBI IWV START" )) {
1445 cpl_propertylist_update_double(plist, QC_PARAM_H2O_DELTA,
1446 (cpl_propertylist_get_double(plist, QC_PARAM_H2O_AVG )-
1447 ((cpl_propertylist_get_double(main_header, "ESO TEL AMBI IWV START")+
1448 cpl_propertylist_get_double(main_header, "ESO TEL AMBI IWV END"))/2)));
1449 }*/
1450
1451 /* Cleanup */
1452 cpl_propertylist_delete(main_header);
1453
1454 /* Save and register */
1455 cpl_propertylist_save(plist, fname, CPL_IO_CREATE);
1456 cpl_free(fname) ;
1457 cpl_frameset_insert(frameset, product_frame);
1458
1459 cpl_propertylist_delete(plist) ;
1460 cpl_free(used_ifus_str) ;
1461 cpl_free(skip_ifus_str) ;
1462
1463 /* Clean */
1464 if (data_header_list[0] != NULL) {
1465 if (cpl_propertylist_has(data_header_list[0], "ESO PRO FRNAME")) {
1466 cpl_propertylist_erase(data_header_list[0], "ESO PRO FRNAME");
1467 }
1468 if (cpl_propertylist_has(data_header_list[0], "ESO PRO IFUNR")) {
1469 cpl_propertylist_erase(data_header_list[0], "ESO PRO IFUNR");
1470 }
1471 }
1472 if (noise_header_list[0] != NULL) {
1473 if (cpl_propertylist_has(noise_header_list[0], "ESO PRO FRNAME")) {
1474 cpl_propertylist_erase(noise_header_list[0], "ESO PRO FRNAME");
1475 }
1476 if (cpl_propertylist_has(noise_header_list[0], "ESO PRO IFUNR")) {
1477 cpl_propertylist_erase(noise_header_list[0], "ESO PRO IFUNR");
1478 }
1479 }
1480
1481 /* BUNIT <- HIERARCH ESO QC CUBE_UNIT */
1482 cpl_propertylist_update_string(data_header_list[0], "BUNIT",
1483 kmos_pfits_get_qc_cube_unit(data_header_list[0])) ;
1484 if (noise_header_list[0] != NULL)
1485 cpl_propertylist_update_string(noise_header_list[0], "BUNIT",
1486 kmos_pfits_get_qc_cube_unit(noise_header_list[0])) ;
1487
1488 /* Save DATA extension */
1489 plist = cpl_propertylist_duplicate(data_header_list[0]) ;
1490
1491 /* Store CRDER3 in the header */
1492 cpl_propertylist_update_double(plist, KEY_CRDER3, crder3) ;
1493 cpl_propertylist_set_comment(plist, KEY_CRDER3, KEY_CRDER3_COMMENT);
1494
1495 /* Remove EXPTIME */
1496 cpl_propertylist_erase(plist, "EXPTIME") ;
1497
1498 /* Update OBJECT (DATA) */
1499 cpl_propertylist_update_string(plist, "OBJECT", object_data_key) ;
1500
1501 kmo_dfs_save_cube(cube_combined_data, fn_combine, "", plist, 0./0.);
1502 cpl_propertylist_delete(plist) ;
1503 cpl_imagelist_delete(cube_combined_data);
1504
1505 /* Save NOISE extension */
1506 plist = cpl_propertylist_duplicate(noise_header_list[0]) ;
1507
1508 /* Remove EXPTIME */
1509 cpl_propertylist_erase(plist, "EXPTIME") ;
1510
1511 /* Update OBJECT (STAT) */
1512 cpl_propertylist_update_string(plist, "OBJECT", object_stat_key) ;
1513
1514 kmo_dfs_save_cube(cube_combined_noise, fn_combine, "", plist, 0./0.);
1515 cpl_imagelist_delete(cube_combined_noise);
1516 cpl_propertylist_delete(plist) ;
1517 cpl_free(fn_combine);
1518
1519 /* Clean 3rd dimension keys */
1520 plist = cpl_propertylist_duplicate(data_header_list[0]) ;
1521 kmos_3dim_clean_plist(plist) ;
1522
1523 /* Set BUNIT to '' */
1524 cpl_propertylist_update_string(plist, "BUNIT", "") ;
1525
1526 /* Update OBJECT (DATA) */
1527 cpl_propertylist_update_string(plist, "OBJECT", object_data_key) ;
1528
1529 kmo_dfs_save_image(exp_mask, fn_mask, "", plist, 0./0.);
1530 cpl_propertylist_delete(plist) ;
1531 cpl_free(fn_mask);
1532 cpl_image_delete(exp_mask);
1533
1534 for (i = 0; i < data_cube_counter ; i++)
1535 cpl_propertylist_delete(data_header_list[i]);
1536 for (i = 0; i < noise_cube_counter ; i++)
1537 cpl_propertylist_delete(noise_header_list[i]);
1538 if (noise_header_list!=NULL && noise_cube_counter==0)
1539 cpl_propertylist_delete(noise_header_list[0]) ;
1540 cpl_free(object_key) ;
1541 cpl_free(object_data_key) ;
1542 cpl_free(object_stat_key) ;
1543 }
1544 if (skipped_bivector!=NULL) cpl_bivector_delete(skipped_bivector) ;
1545 if (ifus != NULL) cpl_vector_delete(ifus);
1546 cpl_free(data_cube_list);
1547 cpl_free(noise_cube_list);
1548 cpl_free(data_header_list);
1549 cpl_free(noise_header_list);
1550 for (i = 0; i < name_vec_size ; i++) cpl_free(name_vec[i]);
1551 cpl_free(name_vec);
1552 cpl_free(mapping_mode) ;
1553
1554 /********************************************/
1555 /* Collapse the combined cubes if requested */
1556 /********************************************/
1557 if (collapse_combined) {
1558 kmos_collapse_cubes(COMBINED_CUBE, frameset, parlist, 0.1, "",
1559 DEF_REJ_METHOD, DEF_POS_REJ_THRES, DEF_NEG_REJ_THRES,
1560 DEF_ITERATIONS, DEF_NR_MIN_REJ, DEF_NR_MAX_REJ);
1561 }
1562
1563 /***************************/
1564 /* Create the IDP Products */
1565 /***************************/
1566 cpl_frame * combined_frame ;
1567 const char * combined_fname ;
1568 char * idp_combined_fname ;
1569 cpl_imagelist * cube_combined_error ;
1570 const char * const_data_extname ;
1571 char * data_extname ;
1572 char * error_extname ;
1573 cpl_frameset * combined_frames ;
1574 double pixnoise ;
1575
1576 /* Loop on the Combined Frames */
1577 combined_frames = kmos_extract_frameset(frameset, COMBINED_CUBE) ;
1578 combined_frame = kmo_dfs_get_frame(combined_frames, COMBINED_CUBE);
1579 while (combined_frame != NULL ) {
1580 combined_fname = cpl_frame_get_filename(combined_frame);
1581
1582 /* Load combined data cube */
1583 cube_combined_data=cpl_imagelist_load(combined_fname, CPL_TYPE_FLOAT,1);
1584
1585 /* Compute the IDP error */
1586 cube_combined_error = kmos_idp_compute_error(cube_combined_data);
1587
1588 /* Compute the PIXNOISE from ERROR -> Primary Header */
1589 pixnoise = kmos_get_mode(cube_combined_error) ;
1590
1591 /************* IDP PRIMARY **********/
1592 main_header = cpl_propertylist_load(combined_fname, 0) ;
1593 plist = cpl_propertylist_load(combined_fname, 1) ;
1594 kmos_idp_prepare_main_keys(main_header, frameset, plist,
1595 raw_tag, cube_combined_error) ;
1596 cpl_propertylist_delete(plist) ;
1597 frame = cpl_frameset_find(rawframes, NULL);
1598
1599 /* Save Primary */
1600 idp_combined_fname = cpl_sprintf("IDP_%s", combined_fname) ;
1601
1602 const char * procat = cpl_propertylist_get_string(main_header,
1603 CPL_DFS_PRO_CATG);
1604 cpl_msg_info(cpl_func, "Writing FITS propertylist product(%s): %s",
1605 procat, idp_combined_fname);
1606 cpl_msg_info(cpl_func, " WRITING FITS FOR 3");
1607
1608 cpl_frame * product_frame = cpl_frame_new();
1609 cpl_frame_set_filename(product_frame, idp_combined_fname);
1610 cpl_frame_set_tag(product_frame, procat);
1611 cpl_frame_set_type(product_frame, CPL_FRAME_TYPE_ANY);
1612 cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_PRODUCT);
1613 cpl_frame_set_level(product_frame, CPL_FRAME_LEVEL_FINAL);
1614
1615 plist = cpl_propertylist_duplicate(main_header);
1616
1617 /* Keep the MJD values before the get updated */
1618 mjd_start = cpl_propertylist_get_double(plist, KEY_MJDOBS);
1619 date_obs = cpl_strdup(cpl_propertylist_get_string(plist, KEY_DATEOBS));
1620 mjd_end = cpl_propertylist_get_double(plist, KEY_MJDEND);
1621 /* MJD-END might be missing */
1622 if (cpl_error_get_code()) cpl_error_reset() ;
1623
1624 /* Keep OBJECT value */
1625 object_key = cpl_strdup(kmos_pfits_get_object(plist)) ;
1626
1627 /* Add DataFlow keywords */
1628 cpl_dfs_setup_product_header(plist, product_frame, frameset, parlist,
1629 cpl_func, PACKAGE "/" PACKAGE_VERSION, CPL_DFS_PRO_DID, frame);
1630
1631 /* Restore OBJECT */
1632 cpl_propertylist_update_string(plist, "OBJECT", object_key) ;
1633 cpl_free(object_key) ;
1634
1635 /* Fix RA / DEC <- Set to CRVAL1 / CRVAL2 */
1636 /* plist(RA / DEC) from plist2(CRVAL1 / CRVAL2) */
1637 cpl_propertylist * plist2 = cpl_propertylist_load(combined_fname, 1) ;
1638 crval1 = cpl_propertylist_get_double(plist2, CRVAL1);
1639 crval2 = cpl_propertylist_get_double(plist2, CRVAL2);
1640 cpl_propertylist_delete(plist2) ;
1641 kmclipm_update_property_double(plist, "RA", crval1, "") ;
1642 kmclipm_update_property_double(plist, "DEC", crval2, "") ;
1643
1644 /* Add SPECSYS keyword */
1645
1646 kmclipm_update_property_string(plist, "SPECSYS", "TOPOCENT", "") ;
1647
1648 /* Set DATE-OBS / MJD-OBS / MJD-END */
1649 if (mjd_start > 0.0) {
1650 if (date_obs != NULL) {
1651 cpl_propertylist_update_string(plist, KEY_DATEOBS, date_obs) ;
1652 cpl_propertylist_set_comment(plist, KEY_DATEOBS,
1653 KEY_DATEOBS_COMMENT);
1654 }
1655 cpl_propertylist_update_double(plist, KEY_MJDOBS, mjd_start) ;
1656 cpl_propertylist_set_comment(plist, KEY_MJDOBS, KEY_MJDOBS_COMMENT);
1657 }
1658 if (date_obs != NULL) cpl_free(date_obs) ;
1659 if (mjd_end > 0.0) {
1660 cpl_propertylist_update_double(plist, KEY_MJDEND, mjd_end) ;
1661 cpl_propertylist_set_comment(plist, KEY_MJDEND, KEY_MJDEND_COMMENT);
1662 }
1663
1664 /* Add PIXNOISE */
1665 cpl_propertylist_update_double(plist, KEY_PIXNOISE, pixnoise) ;
1666 cpl_propertylist_set_comment(plist, KEY_PIXNOISE, KEY_PIXNOISE_COMMENT);
1667
1668 /* Save and register */
1669 cpl_propertylist_save(plist, idp_combined_fname, CPL_IO_CREATE);
1670 cpl_propertylist_delete(plist) ;
1671 cpl_frameset_insert(frameset, product_frame);
1672
1673 /************* IDP DATA extension **********/
1674 /* Handle extname values */
1675 plist = cpl_propertylist_load(combined_fname, 1) ;
1676 const_data_extname = kmos_pfits_get_extname(plist) ;
1677 error_extname = kmos_idp_compute_error_extname(const_data_extname) ;
1678
1679 /* IDP Add DATA Keywords */
1680 kmos_idp_prepare_data_keys(plist, error_extname) ;
1681 kmos_idp_prepare_data_hduclas(plist);
1682 cpl_free(error_extname) ;
1683
1684 /* Ѕave Data */
1685 cpl_imagelist_save(cube_combined_data, idp_combined_fname,
1686 CPL_BPP_IEEE_FLOAT,
1687 plist, CPL_IO_EXTEND) ;
1688 cpl_propertylist_delete(plist) ;
1689 cpl_imagelist_delete(cube_combined_data);
1690
1691 /************* IDP ERROR extension **********/
1692 /* IDP Add ERROR Keywords */
1693 plist = cpl_propertylist_load(combined_fname, 1) ;
1694 kmclipm_update_property_string(plist, EXTNAME, "DATA", "");
1695 data_extname = cpl_strdup(kmos_pfits_get_extname(plist)) ;
1696 error_extname = kmos_idp_compute_error_extname(data_extname) ;
1697 kmos_idp_prepare_error_keys(plist, error_extname, data_extname);
1698 kmos_idp_prepare_error_hduclas(plist);
1699 cpl_free(error_extname) ;
1700 cpl_free(data_extname) ;
1701
1702 /* Recreate the OBJECT key here */
1703 object_stat_key =
1704 cpl_sprintf("%s/%s (STAT)",
1705 kmos_pfits_get_reflex_suffix(main_header),
1706 kmos_pfits_get_obs_targ_name(main_header));
1707
1708 /* Truncate */
1709 if (strlen(object_stat_key) > 68) object_stat_key[68] = 0;
1710
1711 /* Update header */
1712 cpl_propertylist_update_string(plist, "OBJECT", object_stat_key) ;
1713
1714 /* Save ERROR extension */
1715 cpl_imagelist_save(cube_combined_error, idp_combined_fname,
1716 CPL_BPP_IEEE_FLOAT,
1717 plist, CPL_IO_EXTEND) ;
1718 cpl_imagelist_delete(cube_combined_error);
1719 cpl_propertylist_delete(plist) ;
1720 cpl_free(idp_combined_fname) ;
1721 cpl_propertylist_delete(main_header) ;
1722
1723 cpl_free(object_stat_key);
1724
1725 /* Next candidate */
1726 combined_frame = kmo_dfs_get_frame(combined_frames, NULL);
1727 }
1728 cpl_frameset_delete(rawframes) ;
1729 cpl_frameset_delete(combined_frames) ;
1730
1731 return 0;
1732}
1733
1736/*----------------------------------------------------------------------------*/
1742/*----------------------------------------------------------------------------*/
1743static char * kmos_combine_create_ifus_string(
1744 const int * frame_idx,
1745 const int * ifus,
1746 int nb)
1747{
1748 char out[8192] ;
1749 char tmp[12] ;
1750 int i ;
1751
1752 if (nb > 1000) return NULL ;
1753 if (nb == 0) return NULL ;
1754 for (i=0 ; i<nb ; i++) {
1755 /* Build the current string */
1756 if (frame_idx[i] < 10 && ifus[i] < 10)
1757 if (i==0) sprintf(tmp, "%1d:%1d", frame_idx[i], ifus[i]);
1758 else sprintf(tmp, ",%1d:%1d", frame_idx[i], ifus[i]);
1759 else if (frame_idx[i] < 10 && ifus[i] >= 10)
1760 if (i==0) sprintf(tmp, "%1d:%2d", frame_idx[i], ifus[i]);
1761 else sprintf(tmp, ",%1d:%2d", frame_idx[i], ifus[i]);
1762 else if (frame_idx[i] >= 10 && ifus[i] < 10)
1763 if (i==0) sprintf(tmp, "%2d:%1d", frame_idx[i], ifus[i]);
1764 else sprintf(tmp, ",%2d:%1d", frame_idx[i], ifus[i]);
1765 else if (frame_idx[i] >= 10 && ifus[i] >= 10)
1766 if (i==0) sprintf(tmp, "%2d:%2d", frame_idx[i], ifus[i]);
1767 else sprintf(tmp, ",%2d:%2d", frame_idx[i], ifus[i]);
1768 else return NULL ;
1769
1770 if (i==0) strcpy(out, tmp) ;
1771 else strcat(out, tmp);
1772 }
1773
1774 /* Warning : If larger than 51 char, it does not fit in the header card */
1775 if (strlen(out) > 51) return NULL ;
1776
1777 return cpl_strdup(out) ;
1778}
1779
1780/*----------------------------------------------------------------------------*/
1786/*----------------------------------------------------------------------------*/
1787static int kmos_combine_collect_data(
1788 const cpl_propertylist * recons_prim_header,
1789 const cpl_propertylist * recons_ext_header,
1790 double * lambda,
1791 double * seeing,
1792 double * airmass)
1793{
1794
1795 double crval3, cd3_3, crpix3, airm_start, airm_end, fwhmlin ;
1796 int naxis3 ;
1797
1798 /* Check Entries */
1799 if (recons_prim_header == NULL || recons_ext_header == NULL) return -1;
1800 if (lambda == NULL || seeing == NULL || airmass == NULL) return -1;
1801
1802 /* Get Values from header */
1803 crval3 = kmos_pfits_get_crval3(recons_ext_header) ;
1804 cd3_3 = kmos_pfits_get_cd3_3(recons_ext_header) ;
1805 crpix3 = kmos_pfits_get_crpix3(recons_ext_header) ;
1806 naxis3 = kmos_pfits_get_naxis3(recons_ext_header) ;
1807 airm_start = kmos_pfits_get_airmass_start(recons_prim_header) ;
1808 airm_end = kmos_pfits_get_airmass_end(recons_prim_header) ;
1809 fwhmlin = kmos_pfits_get_ia_fwhmlin(recons_prim_header) ;
1810 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1811 cpl_error_reset() ;
1812 cpl_msg_error(__func__, "Cannot collect data from header") ;
1813 return -1 ;
1814 }
1815
1816 /* Lambda */
1817 *lambda = (crval3 + (crval3 + cd3_3 * naxis3 - (crpix3-1) * cd3_3)) / 2.0;
1818
1819 /* Airmass */
1820 *airmass = (airm_start + airm_end) / 2.0 ;
1821
1822 /* Seeing */
1823 *seeing = fwhmlin ;
1824
1825 return 0 ;
1826}
1827
1828/*----------------------------------------------------------------------------*/
1834/*----------------------------------------------------------------------------*/
1835static cpl_bivector * kmos_combine_parse_skipped(const char * str)
1836{
1837 cpl_bivector * out ;
1838 cpl_vector * out_x ;
1839 cpl_vector * out_y ;
1840 char * my_str ;
1841 int nb_values ;
1842 char * s1 ;
1843 char * s2 ;
1844 int val1, val2;
1845
1846 /* Check Entries */
1847 if (str == NULL) return NULL ;
1848
1849 /* Initialise */
1850 nb_values = 0 ;
1851 my_str = cpl_strdup(str) ;
1852
1853 /* Count the values */
1854 for (s2 = my_str; s2; ) {
1855 while (*s2 == ' ' || *s2 == '\t') s2++;
1856 s1 = strsep(&s2, ",") ;
1857 if (*s1) {
1858 if (sscanf(s1," %i:%i", &val1, &val2) == 2) {
1859 nb_values ++ ;
1860 }
1861 }
1862 }
1863 cpl_free(my_str) ;
1864 if (nb_values == 0) return NULL ;
1865
1866 /* Create the vector */
1867 out = cpl_bivector_new(nb_values) ;
1868 out_x = cpl_bivector_get_x(out) ;
1869 out_y = cpl_bivector_get_y(out) ;
1870
1871 /* Fill the vector */
1872 nb_values = 0 ;
1873 my_str = cpl_strdup(str) ;
1874 for (s2 = my_str; s2; ) {
1875 while (*s2 == ' ' || *s2 == '\t') s2++;
1876 s1 = strsep(&s2, ",") ;
1877 if (*s1) {
1878 if (sscanf(s1," %i:%i", &val1, &val2) == 2) {
1879 cpl_vector_set(out_x, nb_values, val1) ;
1880 cpl_vector_set(out_y, nb_values, val2) ;
1881 nb_values ++ ;
1882 }
1883 }
1884 }
1885 cpl_free(my_str) ;
1886 return out;
1887}
1888
1889/*----------------------------------------------------------------------------*/
1897/*----------------------------------------------------------------------------*/
1898static int kmos_combine_is_skipped(
1899 const cpl_bivector * skipped,
1900 int frame_idx,
1901 int ifu_nr)
1902{
1903 const cpl_vector * vec_x ;
1904 const cpl_vector * vec_y ;
1905 double val1, val2 ;
1906 int i ;
1907
1908 /* Check entries */
1909 if (skipped == NULL) return 0;
1910
1911 /* Initialise */
1912 vec_x = cpl_bivector_get_x_const(skipped) ;
1913 vec_y = cpl_bivector_get_y_const(skipped) ;
1914
1915 /* Loop */
1916 for (i=0 ; i<cpl_bivector_get_size(skipped) ; i++) {
1917 val1 = cpl_vector_get(vec_x, i) ;
1918 val2 = cpl_vector_get(vec_y, i) ;
1919 if (fabs(val1-frame_idx)<1e-3 && fabs(val2-ifu_nr)<1e-3) return 1 ;
1920 }
1921 return 0 ;
1922}
1923
1924/*----------------------------------------------------------------------------*/
1931/*----------------------------------------------------------------------------*/
1932static int kmos_idp_set_nans(
1933 cpl_imagelist * data,
1934 cpl_imagelist * error)
1935{
1936 cpl_image * data_curr ;
1937 float * pdata_curr ;
1938 int set_to_nan ;
1939 cpl_size i, j, k, nx, ny, ni ;
1940
1941 /* Check entries */
1942 if (data == NULL || error == NULL) return -1 ;
1943
1944 /* Initialise */
1945 data_curr = cpl_imagelist_get(data, 0) ;
1946 nx = cpl_image_get_size_x(data_curr) ;
1947 ny = cpl_image_get_size_y(data_curr) ;
1948 ni = cpl_imagelist_get_size(data) ;
1949
1950 /* Loop on the pixels and set the beginning of the cube to NAN */
1951 for (j=0 ; j<ny ; j++) {
1952 for (i=0 ; i<nx ; i++) {
1953 set_to_nan = 1 ;
1954 for (k=0 ; k<ni && set_to_nan ; k++) {
1955 data_curr = cpl_imagelist_get(data, k) ;
1956 pdata_curr = cpl_image_get_data_float(data_curr) ;
1957 /* Set to nan */
1958 if (fabs(pdata_curr[i+j*nx])<1e-50) {
1959 pdata_curr[i+j*nx] = 0./0. ;
1960 } else {
1961 set_to_nan = 0 ;
1962 }
1963 }
1964 }
1965 }
1966
1967 /* Loop on the pixels and set the end of the cube to NAN */
1968 for (j=0 ; j<ny ; j++) {
1969 for (i=0 ; i<nx ; i++) {
1970 set_to_nan = 1 ;
1971 for (k=ni-1 ; k>=0 && set_to_nan ; k--) {
1972 data_curr = cpl_imagelist_get(data, k) ;
1973 pdata_curr = cpl_image_get_data_float(data_curr) ;
1974 /* Set to nan */
1975 if (fabs(pdata_curr[i+j*nx])<1e-50) {
1976 pdata_curr[i+j*nx] = 0./0. ;
1977 } else {
1978 set_to_nan = 0 ;
1979 }
1980 }
1981 }
1982 }
1983 return 0 ;
1984}
1985
1986/*----------------------------------------------------------------------------*/
1992/*----------------------------------------------------------------------------*/
1993static double kmos_get_mode(
1994 cpl_imagelist * cube)
1995{
1996 cpl_image * data_curr ;
1997 float * pdata_curr ;
1998 cpl_vector * values ;
1999 double * pvalues ;
2000 double min, max, modevalue ;
2001 cpl_size i, j, k, nx, ny, ni, nval ;
2002 int * bins ;
2003 int nbins, ind ;
2004
2005 /* Check entries */
2006 if (cube == NULL) return -1 ;
2007
2008 /* Initialise */
2009 data_curr = cpl_imagelist_get(cube, 0) ;
2010 nx = cpl_image_get_size_x(data_curr) ;
2011 ny = cpl_image_get_size_y(data_curr) ;
2012 ni = cpl_imagelist_get_size(cube) ;
2013 nbins = 100000 ;
2014 nval = 0 ;
2015
2016 /* Count values */
2017 for (k=0 ; k<ni ; k++) {
2018 data_curr = cpl_imagelist_get(cube, k) ;
2019 pdata_curr = cpl_image_get_data_float(data_curr) ;
2020 for (j=0 ; j<ny ; j++) {
2021 for (i=0 ; i<nx ; i++) {
2022 if ((!isnan(pdata_curr[i+j*nx])) &&
2023 fabs(pdata_curr[i+j*nx])>1e-30) {
2024 nval++ ;
2025 }
2026 }
2027 }
2028 }
2029 if (nval < 3) return 0.0 ;
2030
2031 /* Store Values */
2032 values = cpl_vector_new(nval) ;
2033 pvalues = cpl_vector_get_data(values) ;
2034 nval = 0 ;
2035 for (k=0 ; k<ni ; k++) {
2036 data_curr = cpl_imagelist_get(cube, k) ;
2037 pdata_curr = cpl_image_get_data_float(data_curr) ;
2038 for (j=0 ; j<ny ; j++) {
2039 for (i=0 ; i<nx ; i++) {
2040 if ((!isnan(pdata_curr[i+j*nx])) &&
2041 fabs(pdata_curr[i+j*nx])>1e-30) {
2042 pvalues[nval] = pdata_curr[i+j*nx] ;
2043 nval++ ;
2044 }
2045 }
2046 }
2047 }
2048
2049 /* Sort values */
2050 cpl_vector_sort(values, CPL_SORT_ASCENDING) ;
2051 pvalues = cpl_vector_get_data(values) ;
2052
2053 /* Count the bins */
2054 min = pvalues[0] ;
2055 max = pvalues[nval-1] ;
2056 bins = cpl_calloc(nbins, sizeof(int)) ;
2057 for (k=0 ; k<nval ; k++) {
2058 if (fabs(max-min) > 1e-12)
2059 ind = (int)(nbins * (pvalues[k] - min) / (max - min)) ;
2060 else
2061 ind = 0 ;
2062 /* printf("%g -> %d\n", pvalues[k], ind) ; */
2063 bins[ind]++ ;
2064 }
2065 cpl_vector_delete(values) ;
2066
2067 /* Get the Maximum bin */
2068 ind = 0 ;
2069 for (k=0 ; k<nbins ; k++) {
2070 if (bins[k] > bins[ind]) ind = k ;
2071 /* printf("%d %d\n", k, bins[k]) ; */
2072 }
2073 /* printf("%g %g ind : %d %d\n", min, max, ind, bins[ind]) ; */
2074
2075 cpl_free(bins) ;
2076 modevalue = min + (ind * (max-min) / nbins) ;
2077 if (modevalue < (max-min) / nbins) modevalue = (max-min) / nbins ;
2078 return modevalue ;
2079}
2080
2081/*----------------------------------------------------------------------------*/
2087/*----------------------------------------------------------------------------*/
2088static double kmos_get_median_from_positives(
2089 cpl_image * exp_mask)
2090{
2091 double med ;
2092 float * pexp_mask ;
2093 cpl_size nx, ny, i, j, npos ;
2094 cpl_vector * pos_values ;
2095 double * ppos_values ;
2096
2097 /* Check entries */
2098 if (exp_mask == NULL) return -1.0 ;
2099
2100 /* Initialise */
2101 npos = 0 ;
2102 pexp_mask = cpl_image_get_data_float(exp_mask) ;
2103 nx = cpl_image_get_size_x(exp_mask) ;
2104 ny = cpl_image_get_size_y(exp_mask) ;
2105
2106 /* Count pos values */
2107 for (j=0 ; j<ny ; j++) {
2108 for (i=0 ; i<nx ; i++) {
2109 if (pexp_mask[i+j*nx] > 1e-3) npos++ ;
2110 }
2111 }
2112
2113
2114 /* Store the positive values */
2115 pos_values = cpl_vector_new(npos) ;
2116 ppos_values = cpl_vector_get_data(pos_values) ;
2117 npos = 0 ;
2118 for (j=0 ; j<ny ; j++) {
2119 for (i=0 ; i<nx ; i++) {
2120 if (pexp_mask[i+j*nx] > 1e-3) {
2121 ppos_values[npos] = pexp_mask[i+j*nx] ;
2122 npos++ ;
2123 }
2124 }
2125 }
2126
2127 /* Compute the median */
2128 med = cpl_vector_get_median(pos_values);
2129 cpl_vector_delete(pos_values) ;
2130
2131 return med ;
2132}
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.
Definition: kmos_combine.c:157