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