KMOS Pipeline Reference Manual 4.5.10
kmos_wave_cal.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#ifdef __USE_XOPEN2K
32#include <stdlib.h>
33#define GGG
34#else
35#define __USE_XOPEN2K /* to get the definition for setenv in stdlib.h */
36#include <stdlib.h>
37#undef __USE_XOPEN2K
38#endif
39
40#include <cpl.h>
41
42#include "kmo_utils.h"
43#include "kmos_pfits.h"
44#include "kmo_functions.h"
45#include "kmo_priv_wave_cal.h"
46#include "kmo_priv_functions.h"
47#include "kmo_cpl_extensions.h"
48#include "kmo_dfs.h"
49#include "kmo_error.h"
50#include "kmo_constants.h"
51#include "kmo_debug.h"
52
53/*-----------------------------------------------------------------------------
54 * Functions prototypes
55 *----------------------------------------------------------------------------*/
56
57static int kmos_wave_cal_check_inputs(cpl_frameset *, int *, int *, int *,
58 double *, int *, lampConfiguration *);
59
60static int kmos_wave_cal_create(cpl_plugin *);
61static int kmos_wave_cal_exec(cpl_plugin *);
62static int kmos_wave_cal_destroy(cpl_plugin *);
63static int kmos_wave_cal(cpl_parameterlist *, cpl_frameset *);
64
65/*-----------------------------------------------------------------------------
66 * Static variables
67 *----------------------------------------------------------------------------*/
68
69static char kmos_wave_cal_description[] =
70"This recipe creates the wavelength calibration frame needed for all three\n"
71"detectors. It must be called after the kmo_flat recipe, which generates the\n"
72"two spatial calibration frames needed in this recipe. As input a lamp-on \n"
73"frame, a lamp-off frame, the spatial calibration frames and the list with \n"
74"the reference arclines are required.\n"
75"An additional output frame is the resampled image of the reconstructed arc\n"
76"frame. All slitlets of all IFUs are aligned one next to the other. This \n"
77"frame serves for quality control. One can immediately see if the \n"
78"calibration was successful.\n"
79"The lists of reference arclines are supposed to contain the lines for both\n"
80"available calibration arc-lamps, i.e. Argon and Neon. The list is supposed\n"
81"to be a F2L KMOS FITS file with three columns:\n"
82"\t1. Reference wavelength\n"
83"\t2. Relative strength\n"
84"\t3. String either containing “Ar” or “Ne”\n"
85"The recipe extracts, based on the header keywords, either the applying\n"
86"argon and/or neon emission lines. Below are the plots of the emission lines\n"
87"for both argon and neon. The marked lines are the ones used for wavelength \n"
88"calibration.\n"
89"\n"
90"Furthermore frames can be provided for several rotator angles. In this case\n"
91"the resulting calibration frames for each detector are repeatedly saved as \n"
92"extension for every angle.\n"
93"\n"
94"BASIC PARAMETERS:\n"
95"-----------------\n"
96"--order\n"
97"The polynomial order to use for the fit of the wavelength solution.\n"
98"0: (default) The appropriate order is choosen automatically depending on\n"
99"the waveband (4 for IZ band, 5 for HK, 6 for the others)\n"
100"\n"
101"ADVANCED PARAMETERS\n"
102"-------------------\n"
103"--b_samples\n"
104"The number of samples in spectral direction for the reconstructed cube.\n"
105"Ideally this number should be greater than 2048, the detector size.\n"
106"\n"
107"--suppress_extension\n"
108"If set to TRUE, the arbitrary filename extensions are supressed. If\n"
109"multiple products with the same category are produced, they will be numered\n"
110"consecutively starting from 0.\n"
111"\n"
112"--lines_estimation\n"
113"If set to TRUE, the lines estimation method is used\n"
114"\n"
115"----------------------------------------------------------------------------\n"
116"Input files:\n"
117"\n"
118" DO category Type Explanation Required #Frames\n"
119" ----------- ----- ----------- -------- -------\n"
120" ARC_ON RAW Arclamp-on exposure Y >=1\n"
121" ARC_OFF RAW Arclamp-off exposure Y 1\n"
122" XCAL F2D x calibration frame Y 1\n"
123" YCAL F2D y calibration frame Y 1\n"
124" ARC_LIST F2L List of arclines Y 1\n"
125" FLAT_EDGE F2L Fitted edge parameters Y 1\n"
126" REF_LINES F2L Reference line table Y 1\n"
127" WAVE_BAND F2L Table with start-/end-wavelengths Y 1\n"
128"\n"
129"Output files:\n"
130"\n"
131" DO category Type Explanation\n"
132" ----------- ----- -----------\n"
133" LCAL F2D Wavelength calibration frame\n"
134" (3 Extensions)\n"
135" DET_IMG_WAVE F2D reconstructed arclamp-on exposure\n"
136" (4 extensions: 3 detector images + \n"
137" the arclines list table)\n"
138"----------------------------------------------------------------------------\n"
139"\n";
140
141/*-----------------------------------------------------------------------------
142 * Functions code
143 *----------------------------------------------------------------------------*/
144
151/*----------------------------------------------------------------------------*/
160/*----------------------------------------------------------------------------*/
161int cpl_plugin_get_info(cpl_pluginlist *list)
162{
163 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
164 cpl_plugin *plugin = &recipe->interface;
165
166 cpl_plugin_init(plugin,
167 CPL_PLUGIN_API,
168 KMOS_BINARY_VERSION,
169 CPL_PLUGIN_TYPE_RECIPE,
170 "kmos_wave_cal",
171 "Create a wavelength calibration frame",
172 kmos_wave_cal_description,
173 "Alex Agudo Berbel, Yves Jung",
174 "https://support.eso.org/",
175 kmos_get_license(),
176 kmos_wave_cal_create,
177 kmos_wave_cal_exec,
178 kmos_wave_cal_destroy);
179 cpl_pluginlist_append(list, plugin);
180
181 return 0;
182}
183
184/*----------------------------------------------------------------------------*/
192/*----------------------------------------------------------------------------*/
193static int kmos_wave_cal_create(cpl_plugin *plugin)
194{
195 cpl_recipe *recipe;
196 cpl_parameter *p;
197
198 // Check that the plugin is part of a valid recipe
199 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
200 recipe = (cpl_recipe *)plugin;
201 else
202 return -1;
203
204 // Create the parameters list in the cpl_recipe object
205 recipe->parameters = cpl_parameterlist_new();
206
207 // Fill the parameters list
208 p = cpl_parameter_new_range("kmos.kmos_wave_cal.order", CPL_TYPE_INT,
209 "The fitting polynomial order used for the wavelength solution. "
210 "By default, 4 for IZ band, 5 for HK, 6 for the others",
211 "kmos.kmos_wave_cal", 0, 0, 7);
212 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "order");
213 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
214 cpl_parameterlist_append(recipe->parameters, p);
215
216 /* --suppress_extension */
217 p = cpl_parameter_new_value("kmos.kmos_wave_cal.suppress_extension",
218 CPL_TYPE_BOOL, "Suppress arbitrary filename extension",
219 "kmos.kmos_wave_cal", FALSE);
220 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension");
221 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
222 cpl_parameterlist_append(recipe->parameters, p);
223
224 /* --lines_estimation */
225 p = cpl_parameter_new_value("kmos.kmos_wave_cal.lines_estimation",
226 CPL_TYPE_BOOL, "Trigger lines estimation method",
227 "kmos.kmos_wave_cal", FALSE);
228 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lines_estimation");
229 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
230 cpl_parameterlist_append(recipe->parameters, p);
231
232 /* Add parameters for band-definition */
233 kmos_band_pars_create(recipe->parameters, "kmos.kmos_wave_cal");
234
235 /* --detector */
236 p = cpl_parameter_new_value("kmos.kmos_wave_cal.detector",
237 CPL_TYPE_INT, "Only reduce the specified detector",
238 "kmos.kmos_wave_cal", 0);
239 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "det");
240 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
241 cpl_parameterlist_append(recipe->parameters, p);
242
243 /* --angle */
244 p = cpl_parameter_new_value("kmos.kmos_wave_cal.angle",
245 CPL_TYPE_DOUBLE, "Only reduce the specified angle",
246 "kmos.kmos_wave_cal", 370.0);
247 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "angle");
248 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
249 cpl_parameterlist_append(recipe->parameters, p);
250
251 return 0;
252}
253
254/*----------------------------------------------------------------------------*/
260/*----------------------------------------------------------------------------*/
261static int kmos_wave_cal_exec(cpl_plugin *plugin)
262{
263 cpl_recipe *recipe;
264
265 // Get the recipe out of the plugin
266 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
267 recipe = (cpl_recipe *)plugin;
268 else return -1;
269
270 return kmos_wave_cal(recipe->parameters, recipe->frames);
271}
272
273/*----------------------------------------------------------------------------*/
279/*----------------------------------------------------------------------------*/
280static int kmos_wave_cal_destroy(cpl_plugin *plugin)
281{
282 cpl_recipe *recipe;
283
284 // Get the recipe out of the plugin
285 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
286 recipe = (cpl_recipe *)plugin;
287 else return -1 ;
288
289 cpl_parameterlist_delete(recipe->parameters);
290 return 0 ;
291}
292
293/*----------------------------------------------------------------------------*/
307/*----------------------------------------------------------------------------*/
308static int kmos_wave_cal(cpl_parameterlist *parlist, cpl_frameset *frameset)
309{
310 const cpl_parameter * par ;
311 int suppress_extension, fit_order_par, fit_order ;
312 int nx, ny, next, reduce_det, lines_estimation ;
313 double exptime, gain, angle_found, reduce_angle ;
314 cpl_frame * frame ;
315 cpl_propertylist * mh_on ;
316 cpl_propertylist * plist ;
317 char * suffix ;
318 lampConfiguration lamp_config;
319 char ** filter_ids ;
320 int * angles_array ;
321 int nb_angles ;
322 int non_dest_rom ;
323
324 cpl_propertylist ** stored_sub_headers_lcal ;
325 cpl_propertylist ** stored_sub_headers_det_img ;
326 cpl_image ** stored_lcal ;
327 cpl_image ** stored_det_img ;
328 int * stored_qc_arc_sat ;
329 double * stored_qc_ar_eff ;
330 double * stored_qc_ne_eff ;
331 int * stored_qc_wave_fail ;
332 cpl_table * detector_edges[KMOS_IFUS_PER_DETECTOR] ;
333
334 int a, i, j, x, y ;
335
336 cpl_image * det_lamp_on ;
337 cpl_image * det_lamp_off ;
338 cpl_image * det_lamp_on_copy ;
339
340 cpl_table * arclines ;
341 cpl_table * reflines ;
342 cpl_bivector * lines ;
343
344 cpl_image * bad_pix_mask ;
345 float * pbad_pix_mask ;
346 cpl_image * xcal ;
347 cpl_image * ycal ;
348 cpl_image * lcal ;
349
350 int nr_sat ;
351
352 cpl_propertylist * qc_header ;
353
354 cpl_array ** unused_ifus_before ;
355 cpl_array ** unused_ifus_after ;
356 char * extname ;
357 char * fn_suffix ;
358 char * last_env ;
359 const char * tmp_str ;
360 cpl_error_code err ;
361
362 /* Check initial Entries */
363 if (kmos_check_and_set_groups(frameset) != CPL_ERROR_NONE) {
364 return cpl_error_get_code();
365 }
366
367 /* Get Parameters */
368 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_wave_cal.order");
369 fit_order_par = cpl_parameter_get_int(par);
370 par=cpl_parameterlist_find_const(parlist,
371 "kmos.kmos_wave_cal.lines_estimation");
372 lines_estimation = cpl_parameter_get_bool(par);
373 par=cpl_parameterlist_find_const(parlist,
374 "kmos.kmos_wave_cal.suppress_extension");
375 suppress_extension = cpl_parameter_get_bool(par);
376 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_wave_cal.angle");
377 reduce_angle = cpl_parameter_get_double(par);
378 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_wave_cal.detector");
379 reduce_det = cpl_parameter_get_int(par);
380
381 kmos_band_pars_load(parlist, "kmos.kmos_wave_cal");
382
383 /* Check Parameters */
384 if (fit_order_par < 0 || fit_order_par > 7) {
385 cpl_msg_error(__func__, "Fitting Order must be in [0,7]") ;
386 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
387 return -1 ;
388 }
389 if (reduce_det < 0 || reduce_det > 3) {
390 cpl_msg_error(__func__, "detector must be in [1,3]") ;
391 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
392 return -1 ;
393 }
394
395 /* Check the inputs consistency */
396 if (kmos_wave_cal_check_inputs(frameset, &nx, &ny, &next, &exptime,
397 &non_dest_rom, &lamp_config) != 1) {
398 cpl_msg_error(__func__, "Input frameset is not consistent") ;
399 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
400 return -1 ;
401 }
402
403 /* Instrument setup */
404 suffix = kmo_dfs_get_suffix(kmo_dfs_get_frame(frameset, XCAL), TRUE, FALSE);
405 cpl_msg_info(__func__, "Detected instrument setup: %s", suffix+1);
406
407 /* Check that filter and grating match for each detector */
408 /* filter/grating can be different for each detector */
409 frame = kmo_dfs_get_frame(frameset, ARC_ON);
410 mh_on = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
411 filter_ids = kmo_get_filter_setup(mh_on, next, TRUE) ;
412 cpl_propertylist_delete(mh_on);
413 if (filter_ids == NULL) {
414 cpl_free(suffix);
415 cpl_msg_error(__func__, "Cannot get Filter informations") ;
416 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
417 return -1 ;
418 }
419
420 /* Get Rotator angles */
421 if ((angles_array = kmos_get_angles(frameset, &nb_angles, ARC_ON)) == NULL){
422 cpl_msg_error(__func__, "Cannot get Angles informations") ;
423 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
424 for (i = 0; i < next ; i++) cpl_free(filter_ids[i]);
425 cpl_free(filter_ids);
426 cpl_free(suffix);
427 return -1 ;
428 }
429
430 /* Check the ARC_LIST filter */
431 frame = kmo_dfs_get_frame(frameset, ARC_LIST);
432 plist = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
433 tmp_str = cpl_propertylist_get_string(plist, FILT_ID);
434 if (strcmp(filter_ids[0], tmp_str) != 0) {
435 cpl_msg_error(__func__, "Wrong ARC_LIST filter") ;
436 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
437 for (i = 0; i < next ; i++) cpl_free(filter_ids[i]);
438 cpl_free(filter_ids);
439 cpl_free(angles_array);
440 cpl_propertylist_delete(plist);
441 return -1 ;
442 }
443 cpl_propertylist_delete(plist);
444
445 /* Load the lines as a CPL table */
446 arclines = kmo_dfs_load_table(frameset, ARC_LIST, 1, 0);
447 lines = kmos_get_lines(arclines, lamp_config);
448 cpl_table_delete(arclines);
449 /* TODO : check not null */
450 cpl_msg_info(__func__, "Arc lines: %lld", cpl_bivector_get_size(lines));
451
452 /* Load REFLINES */
453 if ((reflines = kmo_dfs_load_table(frameset, REF_LINES, 1, 0)) == NULL) {
454 cpl_msg_error(__func__, "Missing REF_LINES calibration file") ;
455 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
456 for (i = 0; i < next ; i++) cpl_free(filter_ids[i]);
457 cpl_free(filter_ids);
458 cpl_free(angles_array);
459 cpl_bivector_delete(lines) ;
460 return -1 ;
461 }
462
463 /* Check which IFUs are active for all FLAT frames */
464 unused_ifus_before = kmo_get_unused_ifus(frameset, 0, 0);
465 unused_ifus_after = kmo_duplicate_unused_ifus(unused_ifus_before);
466 kmo_print_unused_ifus(unused_ifus_before, FALSE);
467 if (unused_ifus_before != NULL) kmo_free_unused_ifus(unused_ifus_before);
468
469 /* make sure no reconstruction lookup table (LUT) is used */
470 if (getenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE") != NULL) {
471 last_env = getenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE");
472 } else {
473 last_env = NULL ;
474 }
475 setenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE","NONE",1);
476
477 /* the frames have to be stored temporarily because the QC params */
478 /* for the main header are calculated per detector. So they can be */
479 /* stored only when all detectors are processed */
480 stored_lcal = (cpl_image**)cpl_calloc(next * nb_angles, sizeof(cpl_image*));
481 stored_det_img = (cpl_image**)cpl_calloc(next*nb_angles,sizeof(cpl_image*));
482 stored_sub_headers_lcal = (cpl_propertylist**)cpl_calloc(next * nb_angles,
483 sizeof(cpl_propertylist*));
484 stored_sub_headers_det_img = (cpl_propertylist**)cpl_calloc(next*nb_angles,
485 sizeof(cpl_propertylist*));
486 stored_qc_arc_sat = (int*)cpl_calloc(next, nb_angles * sizeof(int));
487 stored_qc_ar_eff=(double*)cpl_calloc(next, nb_angles * sizeof(double));
488 stored_qc_ne_eff=(double*)cpl_calloc(next, nb_angles * sizeof(double));
489 stored_qc_wave_fail =(int*)cpl_malloc(next* sizeof(int));
490
491 /* Loop all Rotator Angles and Detectors */
492 for (a = 0; a < nb_angles; a++) {
493 /* Reduce only one angle */
494 if (reduce_angle <= 360 && angles_array[a] != reduce_angle) continue ;
495
496 cpl_msg_info(__func__, "Processing rotator angle %d -> %d degree",
497 a, angles_array[a]);
498 cpl_msg_indent_more();
499 for (i = 1; i <= next ; i++) {
500 stored_qc_wave_fail[i-1] = 0;
501 /* Compute only one detetor */
502 if (reduce_det != 0 && i != reduce_det) continue ;
503
504 cpl_msg_info(__func__,"Processing detector No. %d", i);
505 cpl_msg_indent_more();
506
507 /* Load edge parameters */
508 frame=kmo_dfs_get_frame(frameset, FLAT_EDGE);
509 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
510 detector_edges[j] = kmclipm_cal_table_load(
511 cpl_frame_get_filename(frame),
512 (i-1) * KMOS_IFUS_PER_DETECTOR + j + 1,
513 angles_array[a], 0, &angle_found);
514
515 /* IFU is inactive: proceed */
516 if (cpl_error_get_code() == CPL_ERROR_ILLEGAL_INPUT) {
517 cpl_error_reset();
518 }
519 }
520
521 /* Set default fit orders for the different bands */
522 if (fit_order_par == 0) {
523
524 if ((strcmp(filter_ids[i-1], "H") == 0) ||
525 (strcmp(filter_ids[i-1], "K") == 0) ||
526 (strcmp(filter_ids[i-1], "YJ") == 0)) {
527 fit_order = 6;
528 } else if (strcmp(filter_ids[i-1], "IZ") == 0) {
529 fit_order = 4;
530 } else { //if (strcmp(filter_ids[i-1], "HK") == 0) {
531 fit_order = 5;
532 }
533 cpl_msg_info(__func__,
534 "Order of wavelength spectrum fit for %s-band: %d",
535 filter_ids[i-1], fit_order);
536 } else {
537 fit_order = fit_order_par;
538 }
539
540 /* Get ARC_ON frame and Load it */
541 frame = kmos_get_angle_frame(frameset, angles_array[a], ARC_ON);
542 det_lamp_on = kmo_dfs_load_image_frame(frame,i,FALSE, TRUE,&nr_sat);
543 int sx = a * next + (i - 1);
544
545 /* Count saturated pixels for each detector */
546 if (non_dest_rom)
547 stored_qc_arc_sat[sx] = nr_sat;
548 else
549 stored_qc_arc_sat[sx] = kmo_image_get_saturated(det_lamp_on,
550 KMO_FLAT_SATURATED);
551
552 det_lamp_on_copy = cpl_image_duplicate(det_lamp_on);
553
554 /* Get ARC_OFF frame and Load it */
555 frame = kmo_dfs_get_frame(frameset, ARC_OFF);
556 det_lamp_off = kmo_dfs_load_image_frame(frame, i, FALSE, FALSE,
557 NULL);
558
559 /* ARC_ON = ARC_ON - ARC_OFF */
560 cpl_image_subtract(det_lamp_on, det_lamp_off);
561
562 /* Load XCAL,YCAL */
563 xcal = kmo_dfs_load_cal_image(frameset, XCAL, i, 0,
564 (double)angles_array[a], FALSE, NULL, &angle_found, -1,0,0);
565 ycal = kmo_dfs_load_cal_image(frameset, YCAL, i, 0,
566 (double)angles_array[a], FALSE, NULL, &angle_found, -1,0,0);
567 if (xcal == NULL || ycal == NULL) {
568 /* Missing calibration for this detector */
569 cpl_error_reset() ;
570 stored_det_img[sx] = NULL ;
571 stored_lcal[sx] = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
572 kmo_image_fill(stored_lcal[sx], 0.0);
573 if (xcal != NULL) cpl_image_delete(xcal) ;
574 if (ycal != NULL) cpl_image_delete(ycal) ;
575 cpl_image_delete(det_lamp_on_copy) ;
576 cpl_image_delete(det_lamp_on) ;
577 cpl_image_delete(det_lamp_off) ;
578 continue ;
579 }
580
581 /* Derive BPM from XCAL : NaNs to 0, Others to 1 */
582 bad_pix_mask = cpl_image_duplicate(xcal);
583 pbad_pix_mask = cpl_image_get_data_float(bad_pix_mask);
584 for (x = 0; x < nx; x++) {
585 for (y = 0; y < ny; y++) {
586 if (isnan(pbad_pix_mask[x+nx*y])) {
587 pbad_pix_mask[x+nx*y] = 0.;
588 } else {
589 pbad_pix_mask[x+nx*y] = 1.;
590 }
591 }
592 }
593
594 /* Compute wavelength calibration */
595 err = kmos_calc_wave_calib(det_lamp_on, bad_pix_mask,
596 filter_ids[i-1], lamp_config, i, unused_ifus_after[i-1],
597 detector_edges, lines, reflines, &lcal,
598 &(stored_qc_ar_eff[sx]), &(stored_qc_ne_eff[sx]), fit_order,
599 lines_estimation);
600 cpl_image_delete(det_lamp_on);
601 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
602 cpl_table_delete(detector_edges[j]);
603 }
604 if (err == CPL_ERROR_NONE) {
605 /* Update QC parameters */
606 if (stored_qc_ar_eff[sx] != -1.0)
607 stored_qc_ar_eff[sx] /= exptime;
608 if (stored_qc_ne_eff[sx] != -1.0)
609 stored_qc_ne_eff[sx] /= exptime;
610
611 /* Apply the badpixel mask to the produced frame */
612 cpl_image_multiply(lcal, bad_pix_mask);
613 kmo_image_reject_from_mask(lcal, bad_pix_mask);
614
615 /* Store Result frame */
616 stored_lcal[sx] = lcal;
617 } else if (err == CPL_ERROR_UNSPECIFIED) {
618 /* All IFUs seem to be deactivated */
619 /* Continue processing - just save empty frame */
620 cpl_error_reset();
621 stored_lcal[sx] = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
622 kmo_image_fill(stored_lcal[sx], 0.0);
623 stored_qc_wave_fail[i-1]++;
624 } else {
625 cpl_error_reset();
626 cpl_msg_warning(__func__,
627 "Couldn't identify any line - Check the line list");
628 cpl_msg_warning(__func__,
629 "Band defined in header of detector %d: %s",
630 i, filter_ids[i-1]);
631 cpl_msg_warning(__func__, "Arc line file defined: %s",
632 cpl_frame_get_filename(kmo_dfs_get_frame(frameset,
633 ARC_LIST)));
634 }
635 cpl_image_delete(bad_pix_mask);
636
637 /* CREATE RECONSTRUCTED AND RESAMPLED ARC FRAME */
638 stored_det_img[sx] = kmo_reconstructed_arc_image(frameset,
639 det_lamp_on_copy, det_lamp_off, xcal, ycal, stored_lcal[sx],
640 unused_ifus_after[i-1], FALSE, i, suffix, filter_ids[i-1],
641 lamp_config, &qc_header);
642 cpl_image_delete(det_lamp_on_copy);
643 cpl_image_delete(det_lamp_off);
644 cpl_image_delete(xcal);
645 cpl_image_delete(ycal);
646 if (cpl_error_get_code() != CPL_ERROR_NONE) {
647 cpl_msg_error(__func__,"Cannot reconstruct IFUs on detector %d",
648 i);
649 cpl_error_reset();
650 }
651
652 /* CREATE EXTENSION HEADER FOR THE PRODUCT */
653 stored_sub_headers_lcal[sx] = kmo_dfs_load_sub_header(frameset,
654 ARC_ON, i, FALSE);
655 /* update EXTNAME */
656 extname = kmo_extname_creator(detector_frame, i, EXT_DATA);
657 kmclipm_update_property_string(stored_sub_headers_lcal[sx], EXTNAME,
658 extname, "FITS extension name");
659 cpl_free(extname);
660
661 kmclipm_update_property_int(stored_sub_headers_lcal[sx], EXTVER,
662 sx+1, "FITS extension ver");
663
664 // add first QC parameters
665 kmclipm_update_property_int(stored_sub_headers_lcal[sx],
666 QC_ARC_SAT, stored_qc_arc_sat[sx],
667 "[] nr. saturated pixels of arc exp.");
668
669 gain=kmo_dfs_get_property_double(stored_sub_headers_lcal[sx],GAIN);
670
671 if (stored_qc_ar_eff[sx] != -1.0) {
672 kmclipm_update_property_double(stored_sub_headers_lcal[sx],
673 QC_ARC_AR_EFF, stored_qc_ar_eff[sx]/gain,
674 "[e-/s] Argon lamp efficiency");
675 }
676
677 if (stored_qc_ne_eff[sx] != -1.0) {
678 kmclipm_update_property_double(stored_sub_headers_lcal[sx],
679 QC_ARC_NE_EFF, stored_qc_ne_eff[sx]/gain,
680 "[e-/s] Neon lamp efficiency");
681 }
682
683 kmclipm_update_property_double(stored_sub_headers_lcal[sx],
684 CAL_ROTANGLE, ((double) angles_array[a]),
685 "[deg] Rotator relative to nasmyth");
686
687 if (a ==0 ){
688
689 kmclipm_update_property_int(stored_sub_headers_lcal[sx], QC_WAVE_FAIL, stored_qc_wave_fail[i-1],
690 "[] rot. angles with empty extensions ");
691 }
692
693 /* append QC parameters */
694 cpl_propertylist_append(stored_sub_headers_lcal[sx], qc_header);
695 cpl_propertylist_delete(qc_header);
696
697 /* Prepare DET_IMG_WAVE est header */
698 stored_sub_headers_det_img[sx]=cpl_propertylist_duplicate(
699 stored_sub_headers_lcal[sx]);
700 cpl_propertylist_erase(stored_sub_headers_det_img[sx], CD1_1);
701 cpl_propertylist_erase(stored_sub_headers_det_img[sx], CD1_2);
702 cpl_propertylist_erase(stored_sub_headers_det_img[sx], CD2_1);
703 cpl_propertylist_erase(stored_sub_headers_det_img[sx], CD2_2);
704 cpl_propertylist_erase(stored_sub_headers_det_img[sx], CTYPE2) ;
705 cpl_propertylist_update_string(stored_sub_headers_det_img[sx],
706 CTYPE2, "WAVE") ;
707 cpl_propertylist_update_string(stored_sub_headers_det_img[sx],
708 CUNIT1, "PIXEL") ;
709 cpl_propertylist_update_string(stored_sub_headers_det_img[sx],
710 CUNIT2, "um") ;
711
712 /* Prepare LCAL ext header */
713 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CRVAL1);
714 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CRVAL2);
715 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CTYPE1);
716 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CTYPE2);
717 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CDELT1);
718 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CDELT2);
719
720 cpl_msg_indent_less();
721 } // for i devices
722 cpl_msg_indent_less() ;
723 } // for a angles
724
725 /* Free */
726 cpl_free(angles_array) ;
727 for (i = 0; i < next; i++) cpl_free(filter_ids[i]);
728 cpl_free(filter_ids);
729 cpl_bivector_delete(lines);
730
731 cpl_free(stored_qc_arc_sat);
732 cpl_free(stored_qc_ar_eff);
733 cpl_free(stored_qc_ne_eff);
734 cpl_table_delete(reflines);
735
736 /* QC parameters & saving */
737 cpl_msg_info(__func__, "Saving data...");
738
739 /* load, update & save primary header */
740 if (!suppress_extension) fn_suffix = cpl_sprintf("%s", suffix);
741 else fn_suffix = cpl_sprintf("%s", "");
742 cpl_free(suffix);
743
744 /* update which IFUs are not used */
745 frame = kmo_dfs_get_frame(frameset, ARC_ON);
746 mh_on = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0);
747 kmo_set_unused_ifus(unused_ifus_after, mh_on, "kmos_wave_cal");
748 kmo_dfs_save_main_header(frameset, LCAL, fn_suffix, frame, mh_on, parlist,
749 cpl_func);
750 kmo_dfs_save_main_header(frameset, DET_IMG_WAVE, fn_suffix, frame, mh_on,
751 parlist, cpl_func);
752 cpl_propertylist_delete(mh_on);
753
754 /* Save sub-frames */
755 for (a = 0; a < nb_angles; a++) {
756 for (i = 1; i <= next ; i++) {
757 int sx = a * next + (i - 1);
758 /* save lcal-frame */
759 kmo_dfs_save_image(stored_lcal[sx], LCAL, fn_suffix,
760 stored_sub_headers_lcal[sx], 0./0.);
761
762 /* save detector image */
763 kmo_dfs_save_image(stored_det_img[sx], DET_IMG_WAVE, fn_suffix,
764 stored_sub_headers_det_img[sx], 0./0.);
765 } // for i = nxte
766 } // for a angles
767
768 /* Free */
769 cpl_free(fn_suffix);
770 for (i = 0; i < next * nb_angles; i++) {
771 cpl_image_delete(stored_lcal[i]);
772 cpl_image_delete(stored_det_img[i]);
773 cpl_propertylist_delete(stored_sub_headers_lcal[i]);
774 cpl_propertylist_delete(stored_sub_headers_det_img[i]);
775 }
776 cpl_free(stored_lcal);
777 cpl_free(stored_det_img);
778 cpl_free(stored_sub_headers_lcal);
779 cpl_free(stored_sub_headers_det_img);
780
781 /* print which IFUs are not used */
782 kmo_print_unused_ifus(unused_ifus_after, TRUE);
783 if (unused_ifus_after != NULL) kmo_free_unused_ifus(unused_ifus_after);
784
785 if (last_env != NULL) {
786 setenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE",last_env,1);
787 } else {
788 unsetenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE");
789 }
790 return 0;
791}
792
795/*----------------------------------------------------------------------------*/
807/*----------------------------------------------------------------------------*/
808static int kmos_wave_cal_check_inputs(
809 cpl_frameset * frameset,
810 int * nx,
811 int * ny,
812 int * next,
813 double * exptime,
814 int * non_dest_rom,
815 lampConfiguration * lamp_config)
816{
817 const cpl_frame * frame_off ;
818 const cpl_frame * frame_on ;
819 cpl_propertylist * mh_off ;
820 cpl_propertylist * mh_on ;
821 cpl_propertylist * eh_off ;
822 cpl_propertylist * eh_on ;
823 int ext;
824 int next_off;
825 int next_on;
826 double ndit_off, ndit_on, exptime_off, exptime_on ;
827 const char * readmode_off ;
828 const char * readmode_on ;
829
830 /* TODO Check Lamps TODO */
831
832 /* Check Entries */
833 if (nx == NULL || ny == NULL || next == NULL || frameset == NULL) return -1;
834
835 /* Setup lamp config */
836 frame_on = kmo_dfs_get_frame(frameset, ARC_ON);
837 mh_on = cpl_propertylist_load(cpl_frame_get_filename(frame_on), 0);
838 if ((kmo_check_lamp(mh_on, INS_LAMP1_ST) == TRUE) &&
839 (kmo_check_lamp(mh_on, INS_LAMP2_ST) == FALSE)) {
840 *lamp_config = ARGON;
841 cpl_msg_info(__func__, "Arc lamp: Argon");
842 } else if ((kmo_check_lamp(mh_on, INS_LAMP1_ST) == FALSE) &&
843 (kmo_check_lamp(mh_on, INS_LAMP2_ST) == TRUE)) {
844 *lamp_config = NEON;
845 cpl_msg_info(__func__, "Arc lamp: Neon");
846 } else if ((kmo_check_lamp(mh_on, INS_LAMP1_ST) == TRUE) &&
847 (kmo_check_lamp(mh_on, INS_LAMP2_ST) == TRUE)) {
848 *lamp_config = ARGON_NEON;
849 cpl_msg_info(__func__, "Arc lamp: Argon + Neon");
850 } else {
851 *lamp_config = -1 ;
852 cpl_msg_warning(__func__, "Arc lamp: UNDEFINED");
853 }
854
855 /* Check READ OUT MODE */
856 readmode_on = kmos_pfits_get_readmode(mh_on);
857 if (!readmode_on) return -1;
858
859 if (!strcmp(readmode_on, "Nondest")) {
860 *non_dest_rom = 1 ;
861 } else {
862 *non_dest_rom = 0 ;
863 }
864 cpl_propertylist_delete(mh_on);
865
866 /* Get ARC_OFF */
867 frame_off = kmo_dfs_get_frame(frameset, ARC_OFF);
868 if (frame_off == NULL) {
869 cpl_msg_error(__func__, "No ARC_OFF frame found") ;
870 return -1 ;
871 }
872
873 /* Get ARC_OFF main header infos */
874 next_off = cpl_frame_get_nextensions(frame_off);
875 mh_off = cpl_propertylist_load(cpl_frame_get_filename(frame_off), 0);
876 ndit_off = kmos_pfits_get_ndit(mh_off) ;
877 exptime_off = kmos_pfits_get_exptime(mh_off) ;
878 readmode_off = kmos_pfits_get_readmode(mh_off);
879
880 /* Get ARC_ON frames and loop on them */
881 frame_on = kmo_dfs_get_frame(frameset, ARC_ON);
882 if (frame_on == NULL) {
883 cpl_msg_error(__func__, "No ARC_ON frame found") ;
884 cpl_propertylist_delete(mh_off);
885 return -1 ;
886 }
887 while (frame_on != NULL) {
888 /* Get ARC_ON main header infos */
889 next_on = cpl_frame_get_nextensions(frame_on);
890 mh_on = cpl_propertylist_load(cpl_frame_get_filename(frame_on), 0);
891 ndit_on = kmos_pfits_get_ndit(mh_on) ;
892 exptime_on = kmos_pfits_get_exptime(mh_on) ;
893 readmode_on = kmos_pfits_get_readmode(mh_on);
894
895 /* Check consistency */
896 if (ndit_on != ndit_off || strcmp(readmode_on, readmode_off) ||
897 fabs(exptime_on-exptime_off) > 0.01 || next_off != next_on) {
898 cpl_msg_warning(__func__, "Inconsistency for frame %s",
899 cpl_frame_get_filename(frame_on)) ;
900 cpl_propertylist_delete(mh_off);
901 cpl_propertylist_delete(mh_on);
902 return 0 ;
903 }
904 cpl_propertylist_delete(mh_on);
905
906 /* Get next frame */
907 frame_on = kmo_dfs_get_frame(frameset, NULL);
908 }
909 cpl_propertylist_delete(mh_off);
910
911 /* Check the extensions */
912 int nx_on = -1;
913 int nx_off = -1;
914 int ny_on = -1;
915 int ny_off = -1;
916 for (ext = 1; ext <= next_off ; ext++) {
917 eh_off = cpl_propertylist_load(cpl_frame_get_filename(frame_off), ext);
918 nx_off = kmos_pfits_get_naxis1(eh_off) ;
919 ny_off = kmos_pfits_get_naxis2(eh_off) ;
920
921 frame_on = kmo_dfs_get_frame(frameset, ARC_ON);
922 while (frame_on != NULL) {
923 eh_on = cpl_propertylist_load(cpl_frame_get_filename(frame_on),ext);
924 nx_on = kmos_pfits_get_naxis1(eh_on) ;
925 ny_on = kmos_pfits_get_naxis2(eh_on) ;
926 /* Check consistency */
927 if (nx_on != nx_off || ny_off != ny_on) {
928 cpl_msg_warning(__func__, "Inconsistency for frame %s",
929 cpl_frame_get_filename(frame_on)) ;
930 cpl_propertylist_delete(eh_off);
931 cpl_propertylist_delete(eh_on);
932 return 0 ;
933 }
934 cpl_propertylist_delete(eh_on);
935
936 /* Get next frame */
937 frame_on = kmo_dfs_get_frame(frameset, NULL);
938 }
939 cpl_propertylist_delete(eh_off);
940 }
941
942 /* FLAT_EDGE Checks */
943 frame_on = kmo_dfs_get_frame(frameset, FLAT_EDGE);
944 if (cpl_frame_get_nextensions(frame_on) % 24 != 0) {
945 cpl_msg_warning(__func__, "FLAT_EDGE frame is not consistent") ;
946 return 0 ;
947 }
948
949 /* Checks on XCAL YCAL */
950 kmo_check_frame_setup(frameset, ARC_ON, XCAL, TRUE, FALSE, FALSE);
951 kmo_check_frame_setup(frameset, ARC_ON, YCAL, TRUE, FALSE, FALSE);
952 kmo_check_frame_setup_md5_xycal(frameset);
953 if (cpl_error_get_code() != CPL_ERROR_NONE) {
954 cpl_msg_warning(__func__, "XCAL / YCAL checks failed") ;
955 return 0 ;
956 }
957
958 /* Return */
959 *nx = nx_off ;
960 *ny = ny_off ;
961 *next = next_off ;
962 *exptime = exptime_off ;
963 return 1 ;
964}
965
966
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.