KMOS Pipeline Reference Manual 4.5.10
kmos_reconstruct.c
1/*
2 * This file is part of the KMOS Pipeline
3 * Copyright (C) 2002,2003 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24/*-----------------------------------------------------------------------------
25 * Includes
26 *----------------------------------------------------------------------------*/
27
28#include <string.h>
29#include <math.h>
30
31#include <cpl.h>
32
33#include "kmo_utils.h"
34#include "kmo_functions.h"
35#include "kmo_priv_reconstruct.h"
36#include "kmo_priv_functions.h"
37#include "kmo_priv_lcorr.h"
38#include "kmo_cpl_extensions.h"
39#include "kmo_dfs.h"
40#include "kmo_error.h"
41#include "kmo_utils.h"
42#include "kmo_constants.h"
43#include "kmo_debug.h"
44
45/*-----------------------------------------------------------------------------
46 * Functions prototypes
47 *----------------------------------------------------------------------------*/
48
49static int kmos_reconstruct_check_inputs(cpl_frameset *, const char *);
50
51static int kmos_reconstruct_create(cpl_plugin *);
52static int kmos_reconstruct_exec(cpl_plugin *);
53static int kmos_reconstruct_destroy(cpl_plugin *);
54static int kmos_reconstruct(cpl_parameterlist *, cpl_frameset *);
55
56/*-----------------------------------------------------------------------------
57 * Static variables
58 *----------------------------------------------------------------------------*/
59
60static char kmos_reconstruct_description[] =
61"Data with or without noise is reconstructed into a cube using X/Y/LCAL, YCAL\n"
62"The input data can contain noise extensions and will be reconstructed into\n"
63"additional extensions.\n"
64"If an OH spectrum is given in the SOF file the lambda axis will be corrected\n"
65"using the OH lines as reference.\n"
66"\n"
67"---------------------------------------------------------------------------\n"
68" Input files:\n"
69"\n"
70" DO KMOS \n"
71" category Type Explanation Required #Frames\n"
72" -------- ----- ----------- -------- -------\n"
73" DARK or RAW/F2D data with Y 1 \n"
74" FLAT_ON or RAW/F2D or without noise \n"
75" ARC_ON or RAW/F2D \n"
76" OBJECT or RAW \n"
77" STD or RAW \n"
78" SCIENCE or RAW \n"
79" ACQUISITION RAW \n"
80" XCAL F2D x-direction calib. frame Y 1 \n"
81" YCAL F2D y-direction calib. frame Y 1 \n"
82" LCAL F2D Wavelength calib. frame Y 1 \n"
83" WAVE_BAND F2L Table with start-/end-wavelengths Y 1 \n"
84" OH_SPEC F1S Vector holding OH lines N 1 \n"
85"\n"
86" Output files:\n"
87"\n"
88" DO KMOS\n"
89" category Type Explanation\n"
90" -------- ----- -----------\n"
91" CUBE_DARK or F3I Reconstructed cube \n"
92" CUBE_FLAT or RAW/F2D with or without noise\n"
93" CUBE_ARC or \n"
94" CUBE_OBJECT or \n"
95" CUBE_STD or \n"
96" CUBE_SCIENCE \n"
97"---------------------------------------------------------------------------\n"
98"\n";
99
100/*-----------------------------------------------------------------------------
101 * Functions code
102 *----------------------------------------------------------------------------*/
103
104/*----------------------------------------------------------------------------*/
108/*----------------------------------------------------------------------------*/
109
112/*----------------------------------------------------------------------------*/
121/*----------------------------------------------------------------------------*/
122int cpl_plugin_get_info(cpl_pluginlist *list)
123{
124 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
125 cpl_plugin *plugin = &recipe->interface;
126
127 cpl_plugin_init(plugin,
128 CPL_PLUGIN_API,
129 KMOS_BINARY_VERSION,
130 CPL_PLUGIN_TYPE_RECIPE,
131 "kmos_reconstruct",
132 "Performs the cube reconstruction",
133 kmos_reconstruct_description,
134 "Alex Agudo Berbel, Y. Jung",
135 "https://support.eso.org/",
136 kmos_get_license(),
137 kmos_reconstruct_create,
138 kmos_reconstruct_exec,
139 kmos_reconstruct_destroy);
140
141 cpl_pluginlist_append(list, plugin);
142
143 return 0;
144}
145
146/*----------------------------------------------------------------------------*/
154/*----------------------------------------------------------------------------*/
155static int kmos_reconstruct_create(cpl_plugin *plugin)
156{
157 cpl_recipe *recipe;
158 cpl_parameter *p;
159
160 /* Check that the plugin is part of a valid recipe */
161 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
162 recipe = (cpl_recipe *)plugin;
163 else
164 return -1;
165
166 /* Create the parameters list in the cpl_recipe object */
167 recipe->parameters = cpl_parameterlist_new();
168
169 /* Fill the parameters list */
170 /* --imethod */
171 p = cpl_parameter_new_value("kmos.kmos_reconstruct.imethod",
172 CPL_TYPE_STRING,
173 "Method to use for interpolation. [\"NN\" (nearest neighbour), "
174 "\"lwNN\" (linear weighted nearest neighbor), "
175 "\"swNN\" (square weighted nearest neighbor), "
176 "\"MS\" (Modified Shepard's method)"
177 "\"CS\" (Cubic spline)]",
178 "kmos.kmos_reconstruct", "CS");
179 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
180 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
181 cpl_parameterlist_append(recipe->parameters, p);
182
183 /* --neighborhoodRange */
184 p = cpl_parameter_new_value("kmos.kmos_reconstruct.neighborhoodRange",
185 CPL_TYPE_DOUBLE,
186 "Defines the range to search for neighbors. in pixels",
187 "kmos.kmos_reconstruct", 1.001);
188 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "neighborhoodRange");
189 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
190 cpl_parameterlist_append(recipe->parameters, p);
191
192 /* --flux */
193 p = cpl_parameter_new_value("kmos.kmos_reconstruct.flux", CPL_TYPE_BOOL,
194 "TRUE: Apply flux conservation. FALSE: otherwise",
195 "kmos.kmos_reconstruct", FALSE);
196 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
197 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
198 cpl_parameterlist_append(recipe->parameters, p);
199
200 /* --detectorimage */
201 p = cpl_parameter_new_value("kmos.kmos_reconstruct.detectorimage",
202 CPL_TYPE_BOOL,
203 "TRUE: if resampled detector frame should be "
204 "created, FALSE: otherwise",
205 "kmos.kmos_reconstruct", FALSE);
206 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "detimg");
207 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
208 cpl_parameterlist_append(recipe->parameters, p);
209
210 /* --file_extension */
211 p = cpl_parameter_new_value("kmos.kmos_reconstruct.file_extension",
212 CPL_TYPE_BOOL,
213 "TRUE: if OBS_ID keyword should be appended to "
214 "output frames, FALSE: otherwise",
215 "kmos.kmos_reconstruct", FALSE);
216 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "file_extension");
217 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
218 cpl_parameterlist_append(recipe->parameters, p);
219
220 /* --pix_scale */
221 p = cpl_parameter_new_value("kmos.kmos_reconstruct.pix_scale",
222 CPL_TYPE_DOUBLE,
223 "Change the pixel scale [arcsec]. "
224 "Default of 0.2\" results into cubes of 14x14pix, "
225 "a scale of 0.1\" results into cubes of 28x28pix, etc.",
226 "kmos.kmos_reconstruct", KMOS_PIX_RESOLUTION);
227 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "pix_scale");
228 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
229 cpl_parameterlist_append(recipe->parameters, p);
230
231 /* --xcal_interpolation */
232 p = cpl_parameter_new_value("kmos.kmos_reconstruct.xcal_interpolation",
233 CPL_TYPE_BOOL,
234 "TRUE: Interpolate xcal between rotator angles. FALSE: otherwise",
235 "kmos.kmos_reconstruct", TRUE);
236 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "xcal_interpolation");
237 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
238 cpl_parameterlist_append(recipe->parameters, p);
239
240 /* --lcmethod (level correction method) */
241 p = cpl_parameter_new_value("kmos.kmos_reconstruct.lcmethod",
242 CPL_TYPE_STRING,
243 "Method to use for the level correction "
244 "[\"NONE\" (no correction), "
245 "\"OSCAN\" (overscan)]",
246 "kmos.kmos_reconstruct", "NONE");
247 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lcmethod");
248 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
249 cpl_parameterlist_append(recipe->parameters, p);
250
251 /* Add parameters for band-definition */
252 kmos_band_pars_create(recipe->parameters, "kmos.kmos_reconstruct");
253 return 0;
254}
255
256/*----------------------------------------------------------------------------*/
262/*----------------------------------------------------------------------------*/
263static int kmos_reconstruct_exec(cpl_plugin *plugin)
264{
265 cpl_recipe *recipe;
266
267 /* Get the recipe out of the plugin */
268 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
269 recipe = (cpl_recipe *)plugin;
270 else return -1;
271
272 return kmos_reconstruct(recipe->parameters, recipe->frames);
273}
274
275/*----------------------------------------------------------------------------*/
281/*----------------------------------------------------------------------------*/
282static int kmos_reconstruct_destroy(cpl_plugin *plugin)
283{
284 cpl_recipe *recipe;
285
286 /* Get the recipe out of the plugin */
287 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
288 recipe = (cpl_recipe *)plugin;
289 else return -1 ;
290
291 cpl_parameterlist_delete(recipe->parameters);
292 return 0 ;
293}
294
295/*----------------------------------------------------------------------------*/
308/*----------------------------------------------------------------------------*/
309static int kmos_reconstruct(cpl_parameterlist *parlist, cpl_frameset *frameset)
310{
311 const cpl_parameter * par ;
312 const char * imethod ;
313 const char * lcmethod ;
314 int flux, detectorimage, xcal_interpolation,
315 file_extension ;
316 double neighborhoodRange, pix_scale, scaling ;
317 cpl_frame * input_frame ;
318 cpl_frame * xcal_frame ;
319 cpl_frame * ycal_frame ;
320 cpl_frame * lcal_frame ;
321 cpl_frame * ref_spectrum_frame ;
322 float * pdet_img_data ;
323 float * pdet_img_noise ;
324 float * slice ;
325 const char * input_frame_name ;
326 const char * output_frame_name ;
327 const char * filter_id ;
328 char * keyword ;
329 char * suffix ;
330 char * obs_suffix ;
331 char * extname ;
332 int * bounds ;
333 cpl_image * det_img_data ;
334 cpl_image * det_img_noise;
335 cpl_image * tmp_img ;
336 cpl_imagelist * cube_data ;
337 cpl_imagelist * cube_noise ;
338 cpl_propertylist * main_header ;
339 cpl_propertylist * sub_header ;
340 cpl_propertylist * tmp_header ;
341 cpl_table * band_table ;
342 gridDefinition gd ;
343 cpl_polynomial * lcorr_coeffs ;
344 main_fits_desc desc1 ;
345 int i, j, index, ifu_nr, detImgCube, l, x, y ;
346
347 /* Initialise */
348 detImgCube = FALSE ;
349
350 /* Check Entries */
351 if (parlist == NULL || frameset == NULL) {
352 cpl_msg_error(__func__, "Null Inputs") ;
353 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
354 return -1 ;
355 }
356
357 /* Get parameters */
358 par = cpl_parameterlist_find_const(parlist,"kmos.kmos_reconstruct.imethod");
359 imethod = cpl_parameter_get_string(par) ;
360 par=cpl_parameterlist_find_const(parlist,"kmos.kmos_reconstruct.lcmethod");
361 lcmethod = cpl_parameter_get_string(par) ;
362 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_reconstruct.flux");
363 flux = cpl_parameter_get_bool(par);
364 par = cpl_parameterlist_find_const(parlist,
365 "kmos.kmos_reconstruct.detectorimage");
366 detectorimage = cpl_parameter_get_bool(par);
367 par = cpl_parameterlist_find_const(parlist,
368 "kmos.kmos_reconstruct.neighborhoodRange");
369 neighborhoodRange = cpl_parameter_get_double(par) ;
370 kmos_band_pars_load(parlist, "kmos.kmos_reconstruct");
371 par = cpl_parameterlist_find_const(parlist,
372 "kmos.kmos_reconstruct.file_extension");
373 file_extension = cpl_parameter_get_bool(par);
374 par = cpl_parameterlist_find_const(parlist,
375 "kmos.kmos_reconstruct.pix_scale");
376 pix_scale = cpl_parameter_get_double(par) ;
377 par = cpl_parameterlist_find_const(parlist,
378 "kmos.kmos_reconstruct.xcal_interpolation");
379 xcal_interpolation = cpl_parameter_get_bool(par);
380
381 /* Check Parameters */
382 if (strcmp(imethod, "NN") && strcmp(imethod, "lwNN") &&
383 strcmp(imethod, "swNN") && strcmp(imethod, "MS") &&
384 strcmp(imethod, "CS")) {
385 cpl_msg_error(__func__,
386 "imethod must be 'NN','lwNN','swNN','MS' or 'CS'") ;
387 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
388 return -1 ;
389 }
390
391 /* Check Parameters */
392 if (strcmp(lcmethod, "OSCAN") && strcmp(lcmethod, "NONE")) {
393 cpl_msg_error(__func__,
394 "lcmethod must be 'OSCAN' or 'NONE'") ;
395 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
396 return -1 ;
397 }
398
399 if (neighborhoodRange <= 0.0) {
400 cpl_msg_error(__func__,
401 "neighborhoodRange must be greater than 0.0") ;
402 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
403 return -1 ;
404 }
405 if (pix_scale < 0.01 || pix_scale > 0.4) {
406 cpl_msg_error(__func__, "pix_scale must be between 0.01 and 0.4");
407 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
408 return -1 ;
409 }
410
411 /* Identify the RAW and CALIB frames in the input frameset */
412 if (kmo_dfs_set_groups(frameset) != 1) {
413 cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
414 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
415 return -1 ;
416 }
417
418 /* IO File names */
419 if (cpl_frameset_count_tags(frameset, DARK) == 1) {
420 input_frame_name = DARK;
421 output_frame_name = CUBE_DARK;
422 } else if (cpl_frameset_count_tags(frameset, FLAT_ON) == 1) {
423 input_frame_name = FLAT_ON;
424 output_frame_name = CUBE_FLAT;
425 } else if (cpl_frameset_count_tags(frameset, ARC_ON) == 1) {
426 input_frame_name = ARC_ON;
427 output_frame_name = CUBE_ARC;
428 } else if (cpl_frameset_count_tags(frameset, OBJECT) == 1) {
429 input_frame_name = OBJECT;
430 output_frame_name = CUBE_OBJECT;
431 } else if (cpl_frameset_count_tags(frameset, ACQUISITION) == 1) {
432 input_frame_name = ACQUISITION;
433 output_frame_name = CUBE_ACQUISITION;
434 } else if (cpl_frameset_count_tags(frameset, STD) == 1) {
435 input_frame_name = STD;
436 output_frame_name = CUBE_STD;
437 } else if (cpl_frameset_count_tags(frameset, SCIENCE) == 1) {
438 input_frame_name = SCIENCE;
439 output_frame_name = CUBE_SCIENCE;
440 } else if (cpl_frameset_count_tags(frameset, ACQUISITION) == 1) {
441 input_frame_name = SCIENCE;
442 output_frame_name = CUBE_SCIENCE;
443 } else {
444 cpl_msg_error(__func__, "Missing Inputs") ;
445 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
446 return -1 ;
447 }
448
449 /* Check the inputs consistency */
450 if (kmos_reconstruct_check_inputs(frameset, input_frame_name) != 1) {
451 cpl_msg_error(__func__, "Input frameset is not consistent") ;
452 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
453 return -1 ;
454 }
455
456 /* Instrument setup */
457 input_frame = kmo_dfs_get_frame(frameset, input_frame_name);
458 suffix = kmo_dfs_get_suffix(input_frame, TRUE, TRUE);
459 cpl_msg_info(__func__, "Detected instrument setup: %s", suffix+1);
460 cpl_free(suffix);
461
462 /* Get frames */
463 xcal_frame = kmo_dfs_get_frame(frameset, XCAL);
464 ycal_frame = kmo_dfs_get_frame(frameset, YCAL) ;
465 lcal_frame = kmo_dfs_get_frame(frameset, LCAL) ;
466 ref_spectrum_frame = kmo_dfs_get_frame(frameset, OH_SPEC) ;
467
468 /* Get input frame primary header */
469 main_header = kmo_dfs_load_primary_header(frameset, input_frame_name);
470
471 /* Use the OBS ID in the file name */
472 if (file_extension) {
473 obs_suffix = cpl_sprintf("_%d",
474 cpl_propertylist_get_int(main_header, OBS_ID));
475 } else {
476 obs_suffix = cpl_sprintf("%s", "");
477 }
478
479 /* Save Product (reconstructed) Main Header */
480 kmo_dfs_save_main_header(frameset, output_frame_name, obs_suffix,
481 input_frame, NULL, parlist, cpl_func);
482
483 /* Save Product (detector image) Main Header */
484 if (detectorimage == TRUE)
485 kmo_dfs_save_main_header(frameset, DET_IMG_REC, obs_suffix,
486 input_frame, NULL, parlist, cpl_func);
487
488 /* Grid definition, wavelength start and end are set later */
489 kmclipm_setup_grid(&gd, imethod, neighborhoodRange, pix_scale, 0.);
490
491 /* READ Wavelength bounds */
492 tmp_header = kmo_dfs_load_primary_header(frameset, XCAL);
493 bounds = kmclipm_extract_bounds(tmp_header);
494 cpl_propertylist_delete(tmp_header);
495
496 kmo_init_fits_desc(&desc1);
497 desc1 = kmo_identify_fits_header(cpl_frame_get_filename(input_frame));
498
499 /* Loop through detectors */
500 for (i = 1; i <= KMOS_NR_DETECTORS; i++) {
501 cpl_msg_info("","Processing detector No. %d", i);
502
503 /* Load LCAL image close to ROTANGLE 0. assuming that the */
504 /* wavelength range doesn't differ with different ROTANGLEs. */
505 print_cal_angle_msg_once = FALSE;
506 print_xcal_angle_msg_once = FALSE;
507 if (i==1) {
508 print_cal_angle_msg_once = TRUE;
509 print_xcal_angle_msg_once = TRUE;
510 }
511
512 /* Read Filter ID */
513 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX,i,IFU_FILTID_POSTFIX);
514 filter_id = cpl_propertylist_get_string(main_header, keyword);
515 cpl_free(keyword);
516
517 /* Load Band Info */
518 band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, FALSE);
519 kmclipm_setup_grid_band_lcal(&gd, filter_id, band_table);
520 cpl_table_delete(band_table);
521
522 /* Create empty detector images */
523 if (detectorimage) {
524 det_img_data = cpl_image_new(
525 gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR, gd.l.dim,
526 CPL_TYPE_FLOAT);
527 pdet_img_data = cpl_image_get_data_float(det_img_data);
528
529 det_img_noise = cpl_image_new(
530 gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR, gd.l.dim,
531 CPL_TYPE_FLOAT);
532 pdet_img_noise = cpl_image_get_data_float(det_img_noise);
533 }
534
535 /* Loop on IFUs */
536 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
537 ifu_nr = (i-1)*KMOS_IFUS_PER_DETECTOR + j + 1;
538
539 /* Load sub-header*/
540 sub_header = kmo_dfs_load_sub_header(frameset, input_frame_name,
541 i, FALSE);
542
543 /* Check if IFU is valid according to main header keywords */
544 if (bounds[2*(ifu_nr-1)] != -1 && bounds[2*(ifu_nr-1)+1] != -1) {
545 /* IFU valid */
546
547 /* calc WCS & update subheader */
548 kmo_calc_wcs_gd(main_header, sub_header, ifu_nr, gd);
549 kmclipm_update_property_int(sub_header, NAXIS, 3,
550 "number of data axes");
551 kmclipm_update_property_int(sub_header, NAXIS1,
552 gd.x.dim, "length of data axis 1");
553 kmclipm_update_property_int(sub_header, NAXIS2,
554 gd.y.dim, "length of data axis 2");
555 kmclipm_update_property_int(sub_header, NAXIS3,
556 gd.l.dim, "length of data axis 3");
557
558 /* Reconstruct data and noise (if available) */
559 kmo_reconstruct_sci(ifu_nr, bounds[2*(ifu_nr-1)],
560 bounds[2*(ifu_nr-1)+1], input_frame, input_frame_name,
561 NULL, NULL, NULL, NULL, xcal_frame, ycal_frame,
562 lcal_frame, NULL, NULL, &gd, &cube_data, &cube_noise,
563 flux, 0, xcal_interpolation, lcmethod);
564
565 /* Reconstruct again using OH_SPEC */
566 if (ref_spectrum_frame != NULL && cube_data != NULL) {
567 lcorr_coeffs = kmo_lcorr_get(cube_data, sub_header,
568 ref_spectrum_frame, gd, filter_id, ifu_nr);
569 cpl_imagelist_delete(cube_data);
570 if (cube_noise != NULL) cpl_imagelist_delete(cube_noise);
571 kmo_reconstruct_sci(ifu_nr, bounds[2*(ifu_nr-1)],
572 bounds[2*(ifu_nr-1)+1], input_frame,
573 input_frame_name, NULL, NULL, NULL, NULL,
574 xcal_frame, ycal_frame, lcal_frame, lcorr_coeffs,
575 NULL, &gd, &cube_data, &cube_noise, flux, 0,
576 xcal_interpolation, lcmethod);
577 cpl_polynomial_delete(lcorr_coeffs);
578 }
579
580 /* Scale flux according to pixel_scale */
581 tmp_img = cpl_imagelist_get(cube_data, 0);
582 scaling = (cpl_image_get_size_x(tmp_img)*
583 cpl_image_get_size_y(tmp_img)) /
584 (KMOS_SLITLET_X*KMOS_SLITLET_Y);
585 cpl_imagelist_divide_scalar(cube_data, scaling);
586 if (cube_noise != NULL)
587 cpl_imagelist_divide_scalar(cube_noise, scaling);
588 } else {
589 /* IFU invalid */
590 cube_data = cube_noise = NULL ;
591 }
592
593 /* Fill detector images */
594 if (detectorimage) {
595 if (cube_data != NULL) {
596 for (l = 0; l < gd.l.dim; l++) {
597 slice = cpl_image_get_data_float(
598 cpl_imagelist_get(cube_data, l));
599 for (y = 0; y < gd.y.dim; y++) {
600 for (x = 0; x < gd.x.dim; x++) {
601 int ix = x +
602 y* gd.x.dim +
603 j* gd.x.dim*gd.y.dim + //IFU offset
604 l* gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
605 pdet_img_data[ix] = slice[x + y*gd.x.dim];
606 }
607 }
608 }
609 }
610 if (cube_noise != NULL) {
611 detImgCube = TRUE;
612 for (l = 0; l < gd.l.dim; l++) {
613 slice = cpl_image_get_data_float(
614 cpl_imagelist_get(cube_noise, l));
615 for (y = 0; y < gd.y.dim; y++) {
616 for (x = 0; x < gd.x.dim; x++) {
617 int ix = x +
618 y* gd.x.dim +
619 j* gd.x.dim*gd.y.dim + //IFU offset
620 l* gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
621 pdet_img_noise[ix] = slice[x + y*gd.x.dim];
622 }
623 }
624 }
625 }
626 }
627
628 /* Save Product (reconstructed) Data Cube */
629 extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_DATA);
630 kmclipm_update_property_string(sub_header, EXTNAME, extname,
631 "FITS extension name");
632 cpl_free(extname);
633 kmo_dfs_save_cube(cube_data, output_frame_name, obs_suffix,
634 sub_header, 0./0.);
635
636 /* Save Product (reconstructed) Noise Cube */
637 if (cube_noise != NULL) {
638 extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_NOISE);
639 kmclipm_update_property_string(sub_header, EXTNAME,
640 extname, "FITS extension name");
641 cpl_free(extname);
642 kmo_dfs_save_cube(cube_noise, output_frame_name, obs_suffix,
643 sub_header, 0./0.);
644 }
645
646 cpl_imagelist_delete(cube_data);
647 if (cube_noise != NULL) cpl_imagelist_delete(cube_noise);
648 cpl_propertylist_delete(sub_header);
649 } // IFUs loop
650
651 if (detectorimage) {
652
653 /* Save Product (detector image) Data Cube */
654 index = kmo_identify_index(cpl_frame_get_filename(input_frame), i,
655 FALSE);
656
657 tmp_header = kmclipm_propertylist_load(
658 cpl_frame_get_filename(input_frame), index);
659 if (det_img_data) {
660 kmo_save_det_img_ext(det_img_data, gd, i, DET_IMG_REC,
661 obs_suffix, tmp_header, FALSE, FALSE);
662 cpl_image_delete(det_img_data);
663 }
664 cpl_propertylist_delete(tmp_header);
665
666 if (detImgCube) {
667
668 /* Save Product (detector image) Noise Cube */
669 /* Index changes (*2) if Noise extensions are there */
670 if (desc1.ex_noise) {
671 index = kmo_identify_index(
672 cpl_frame_get_filename(input_frame), i, TRUE);
673 }
674 tmp_header = kmclipm_propertylist_load(
675 cpl_frame_get_filename(input_frame), index);
676 if (det_img_noise) {
677 kmo_save_det_img_ext(det_img_noise, gd, i, DET_IMG_REC,
678 obs_suffix, tmp_header, FALSE, TRUE);
679 }
680 cpl_propertylist_delete(tmp_header);
681 }
682 if (det_img_noise) cpl_image_delete(det_img_noise);
683 }
684 } // Detectors loop
685 cpl_propertylist_delete(main_header);
686 cpl_free(obs_suffix);
687 kmo_free_fits_desc(&desc1);
688 cpl_free(bounds);
689
690 return 0;
691}
692
695/*----------------------------------------------------------------------------*/
702/*----------------------------------------------------------------------------*/
703static int kmos_reconstruct_check_inputs(
704 cpl_frameset * frameset,
705 const char * input_frame_name)
706{
707 cpl_propertylist * lcal_header ;
708 cpl_propertylist * input_header ;
709 int nb_xcal, nb_ycal, nb_lcal, nb_oh_spec ;
710 char * keyword ;
711 const char * filter_id ;
712 const char * filter_id_tmp ;
713 int i ;
714
715 /* Check entries */
716 if (frameset == NULL || input_frame_name == NULL) return -1;
717
718 /* Count frames */
719 if (cpl_frameset_count_tags(frameset, DARK) != 1 &&
720 cpl_frameset_count_tags(frameset, FLAT_ON) != 1 &&
721 cpl_frameset_count_tags(frameset, ARC_ON) != 1 &&
722 cpl_frameset_count_tags(frameset, OBJECT) != 1 &&
723 cpl_frameset_count_tags(frameset, ACQUISITION) != 1 &&
724 cpl_frameset_count_tags(frameset, STD) != 1 &&
725 cpl_frameset_count_tags(frameset, SCIENCE) != 1) {
726 cpl_msg_error(__func__, "1 data frame must be provided") ;
727 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
728 return 0 ;
729 }
730 nb_xcal = cpl_frameset_count_tags(frameset, XCAL) ;
731 nb_ycal = cpl_frameset_count_tags(frameset, YCAL) ;
732 nb_lcal = cpl_frameset_count_tags(frameset, LCAL) ;
733 if (nb_xcal != 1 || nb_ycal != 1 || nb_lcal != 1) {
734 cpl_msg_error(__func__, "Exactly 1 XCAL/YCAL/LCAL expected") ;
735 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
736 return 0 ;
737 }
738 if (cpl_frameset_count_tags(frameset, WAVE_BAND) != 1) {
739 cpl_msg_error(__func__, "Missing WAVE_BAND") ;
740 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
741 return 0 ;
742 }
743 nb_oh_spec = cpl_frameset_count_tags(frameset, OH_SPEC) ;
744 if (nb_oh_spec != 0 && nb_oh_spec != 1) {
745 cpl_msg_error(__func__, "Only 1 reference spectrum can be provided") ;
746 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
747 return 0 ;
748 }
749
750 /* Check filters, rotation consistencies */
751 kmo_check_frame_setup(frameset, XCAL, YCAL, TRUE, FALSE, TRUE);
752 kmo_check_frame_setup(frameset, XCAL, LCAL, TRUE, FALSE, TRUE);
753 if (nb_oh_spec == 1) kmo_check_oh_spec_setup(frameset, XCAL);
754
755 if (cpl_frameset_count_tags(frameset, DARK) != 1) {
756 kmo_check_frame_setup(frameset, XCAL, input_frame_name, TRUE, FALSE,
757 FALSE);
758 }
759 kmo_check_frame_setup_md5_xycal(frameset);
760 kmo_check_frame_setup_md5(frameset);
761
762 /* Check filters */
763 input_header = kmo_dfs_load_primary_header(frameset, input_frame_name);
764 lcal_header = kmo_dfs_load_primary_header(frameset, LCAL);
765 for (i = 1; i <= KMOS_NR_DETECTORS; i++) {
766 // ESO INS FILTi ID
767 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX,i,IFU_FILTID_POSTFIX);
768 filter_id = cpl_propertylist_get_string(lcal_header, keyword);
769 if (strcmp(filter_id, "IZ") && strcmp(filter_id, "YJ") &&
770 strcmp(filter_id, "H") && strcmp(filter_id, "K") &&
771 strcmp(filter_id, "HK")) {
772 cpl_free(keyword) ;
773 cpl_propertylist_delete(input_header) ;
774 cpl_propertylist_delete(lcal_header) ;
775 cpl_msg_error(__func__,"LCAL Filter ID must be IZ, YJ, H, HK or K");
776 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
777 return 0 ;
778 }
779
780 /* Dark not taken with filter */
781 if (!strcmp(input_frame_name, DARK)) {
782 filter_id_tmp = cpl_propertylist_get_string(input_header, keyword);
783 if (strcmp(filter_id, filter_id_tmp)) {
784 cpl_free(keyword) ;
785 cpl_propertylist_delete(input_header) ;
786 cpl_propertylist_delete(lcal_header) ;
787 cpl_msg_error(__func__,"Filter mismatch");
788 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
789 return 0 ;
790 }
791 }
792 cpl_free(keyword);
793 }
794 cpl_propertylist_delete(input_header) ;
795 cpl_propertylist_delete(lcal_header) ;
796
797 return 1 ;
798}
799
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.