KMOS Pipeline Reference Manual 4.5.10
kmos_flat.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_priv_flat.h"
35#include "kmo_priv_wave_cal.h"
36#include "kmo_priv_functions.h"
37#include "kmo_dfs.h"
38#include "kmo_priv_combine.h"
39#include "kmos_pfits.h"
40#include "kmo_error.h"
41#include "kmo_constants.h"
42#include "kmo_cpl_extensions.h"
43#include "kmo_debug.h"
44
45/*-----------------------------------------------------------------------------
46 * Functions prototypes
47 *----------------------------------------------------------------------------*/
48
49static int kmos_flat_check_inputs(cpl_frameset *, int *, int *, int *,double *);
50static cpl_propertylist * kmos_create_bounds_properties(cpl_image **,int, int) ;
51
52static int kmos_flat_create(cpl_plugin *);
53static int kmos_flat_exec(cpl_plugin *);
54static int kmos_flat_destroy(cpl_plugin *);
55static int kmos_flat(cpl_parameterlist *, cpl_frameset *);
56
57/*-----------------------------------------------------------------------------
58 * Static variables
59 *----------------------------------------------------------------------------*/
60
61static char kmos_flat_description[] =
62"This recipe creates the master flat field and calibration frames needed for\n"
63"spatial calibration for all three detectors. It must be called after the \n"
64"kmo_dark-recipe, which generates a bad pixel mask (badpixel_dark.fits). The\n"
65"bad pixel mask will be updated in this recipe.\n"
66"As input at least 3 dark frames, 3 frames with the flat lamp on are\n"
67"recommended. Additionally a badpixel mask from kmo_dark is required.\n"
68"\n"
69"The badpixel mask contains 0 for bad pixels and 1 for good ones.\n"
70"\n"
71"The structure of the resulting xcal and ycal frames is quite complex since\n"
72"the arrangement of the IFUs isn't just linear on the detector. Basically the\n"
73"integer part of the calibration data shows the offset of each pixels centre\n"
74"in mas (Milli arcsec) from the field centre. The viewing of an IFU is\n"
75"2800 mas (14pix*0.2arcsec/pix). So the values in these two frames will vary\n"
76"between +/-1500 (One would expect 1400, but since the slitlets aren't\n"
77"expected to be exactly vertical, the values can even go up to around 1500).\n"
78"Additionally in the calibration data in y-direction the decimal part of the\n"
79"data designates the IFU to which the slitlet corresponds to (for each\n"
80"detector from 1 to 8).\n"
81"Because of the irregular arrangement of the IFUs not all x-direction\n"
82"calibration data is found in xcal and similarly not all y-direction\n"
83"calibration data is located in ycal. For certain IFUs they are switched\n"
84" and/or flipped in x- or y-direction:\n"
85"For IFUs 1,2,3,4,13,14,15,16: x- and y- data is switched\n"
86"For IFUs 17,18,19,20: y-data is flipped \n"
87"For IFUs 21,22,23,24: x-data is flipped \n"
88"For IFUs 5,6,7,8,9,10,11,12: x- and y- data is switched and\n"
89" x- and y- data is flipped\n"
90"\n"
91"Furthermore frames can be provided for several rotator angles. In this case\n"
92"the resulting calibration frames for each detector are repeatedly saved as \n"
93"extension for every angle.\n"
94"\n"
95"Advanced features:\n"
96"------------------\n"
97"To create the badpixel mask the edges of all slitlets are fitted to a\n"
98"polynomial. Since it can happen that some of these fits (3 detectors\n"
99"8 IFUs * 14slitlets * 2 edges (left and right edge of slitlet)= 672 edges)\n"
100"fail, the fit parameters are themselves fitted again to detect any outliers.\n"
101"By default, the parameters of all left and all right edges are grouped\n"
102"individually and then fitted using chebyshev polynomials. The advantage of\n"
103"a chebyshev polynomial is, that it consists in fact of a series of\n"
104"orthogonal polynomials. This implies that the parameters of the polynomials\n"
105"are independent. This fact predestines the use of chebyshev polynomials\n"
106"for our case. So each individual parameter can be examined independently.\n"
107"The reason why the left and right edges are fitted individually is that\n"
108"there is a systematic pattern specific to these groups. The reason for\n"
109"this pattern is probably to be found in the optical path the light is\n"
110"traversing.\n"
111"\n"
112"BASIC PARAMETERS:\n"
113"-----------------\n"
114"--badpix_thresh\n"
115"The threshold level to mark pixels as bad on the dark subtracted frames [%]"
116"\n"
117"--surrounding_pixels\n"
118"The amount of bad pixels to surround a specific pixel, to let it be marked\n"
119"bad as well.\n"
120"\n"
121"--cmethod\n"
122"Following methods of frame combination are available:\n"
123" * 'ksigma' (Default)\n"
124" An iterative sigma clipping. For each position all pixels in the\n"
125" spectrum are examined. If they deviate significantly, they will be\n"
126" rejected according to the conditions:\n"
127" val > mean + stdev * cpos_rej\n"
128" and\n"
129" val < mean - stdev * cneg_rej\n"
130" where --cpos_rej, --cneg_rej and --citer are the configuration\n"
131" parameters. In the first iteration median and percentile level are used.\n"
132"\n"
133" * 'median'\n"
134" At each pixel position the median is calculated.\n"
135"\n"
136" * 'average'\n"
137" At each pixel position the average is calculated.\n"
138"\n"
139" * 'sum'\n"
140" At each pixel position the sum is calculated.\n"
141"\n"
142" * 'min_max'\n"
143" The specified number of min and max pixel values will be rejected.\n"
144" --cmax and --cmin apply to this method.\n"
145"\n"
146"ADVANCED PARAMETERS\n"
147"-------------------\n"
148"--cpos_rej\n"
149"--cneg_rej\n"
150"--citer\n"
151"see --cmethod='ksigma'\n"
152"\n"
153"--cmax\n"
154"--cmin\n"
155"see --cmethod='min_max'\n"
156"\n"
157"--suppress_extension\n"
158"If set to TRUE, the arbitrary filename extensions are suppressed. If\n"
159"multiple products with the same category are produced, they will be\n"
160"numbered consecutively starting from 0.\n"
161"\n"
162"-------------------------------------------------------------------------------\n"
163" Input files:\n"
164" DO CATG Type Explanation Required #Frames\n"
165" ------- ----- ----------- -------- -------\n"
166" FLAT_ON RAW Flatlamp-on exposures Y 1-n \n"
167" (at least 3 frames recommended) \n"
168" FLAT_OFF RAW Flatlamp-off exposures Y 1-n \n"
169" (at least 3 frames recommended) \n"
170" BADPIXEL_DARK B2D Bad pixel mask Y 1 \n"
171"\n"
172" Output files:\n"
173" DO CATG Type Explanation\n"
174" ------- ----- -----------\n"
175" MASTER_FLAT F2D Normalised flat field\n"
176" (6 extensions: alternating data & noise\n"
177" BADPIXEL_FLAT B2D Updated bad pixel mask (3 Extensions)\n"
178" XCAL F2D Calibration frame 1 (3 Extensions)\n"
179" YCAL F2D Calibration frame 2 (3 Extensions)\n"
180" FLAT_EDGE F2L Frame containing parameters of fitted \n"
181" slitlets of all IFUs of all detectors\n"
182"---------------------------------------------------------------------------"
183"\n";
184
185/*----------------------------------------------------------------------------*/
189/*----------------------------------------------------------------------------*/
190
193/*-----------------------------------------------------------------------------
194 * Functions code
195 *----------------------------------------------------------------------------*/
196
197/*----------------------------------------------------------------------------*/
206/*----------------------------------------------------------------------------*/
207int cpl_plugin_get_info(cpl_pluginlist *list)
208{
209 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
210 cpl_plugin *plugin = &recipe->interface;
211
212 cpl_plugin_init(plugin,
213 CPL_PLUGIN_API,
214 KMOS_BINARY_VERSION,
215 CPL_PLUGIN_TYPE_RECIPE,
216 "kmos_flat",
217 "Create master flatfield frame and badpixel map",
218 kmos_flat_description,
219 "Alex Agudo Berbel, Yves Jung",
220 "https://support.eso.org/",
221 kmos_get_license(),
222 kmos_flat_create,
223 kmos_flat_exec,
224 kmos_flat_destroy);
225
226 cpl_pluginlist_append(list, plugin);
227
228 return 0;
229}
230
231/*----------------------------------------------------------------------------*/
239/*----------------------------------------------------------------------------*/
240static int kmos_flat_create(cpl_plugin *plugin)
241{
242 cpl_recipe *recipe;
243 cpl_parameter *p;
244
245 /* Check that the plugin is part of a valid recipe */
246 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
247 recipe = (cpl_recipe *)plugin;
248 else
249 return -1;
250
251 /* Create the parameters list in the cpl_recipe object */
252 recipe->parameters = cpl_parameterlist_new();
253
254 /* Fill the parameters list */
255
256 /* --badpix_thresh */
257 p = cpl_parameter_new_value("kmos.kmos_flat.badpix_thresh", CPL_TYPE_INT,
258 "The threshold level to mark bad pixels [%].","kmos.kmos_flat", 35);
259 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "badpix_thresh");
260 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
261 cpl_parameterlist_append(recipe->parameters, p);
262
263 /* --surrounding_pixels */
264 p = cpl_parameter_new_value("kmos.kmos_flat.surrounding_pixels",
265 CPL_TYPE_INT, "The nb of bad surrounding pix to mark a pixel bad",
266 "kmos.kmos_flat", 5);
267 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "surrounding_pixels");
268 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
269 cpl_parameterlist_append(recipe->parameters, p);
270
271 /* --suppress_extension */
272 p = cpl_parameter_new_value("kmos.kmos_flat.suppress_extension",
273 CPL_TYPE_BOOL, "Suppress arbitrary filename extension",
274 "kmos.kmos_flat", FALSE);
275 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension");
276 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
277 cpl_parameterlist_append(recipe->parameters, p);
278
279 /* Add parameters for combination */
280 kmos_combine_pars_create(recipe->parameters, "kmos.kmos_flat",
281 DEF_REJ_METHOD, FALSE);
282
283 /* --detector */
284 p = cpl_parameter_new_value("kmos.kmos_flat.detector",
285 CPL_TYPE_INT, "Only reduce the specified detector",
286 "kmos.kmos_flat", 0);
287 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "det");
288 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
289 cpl_parameterlist_append(recipe->parameters, p);
290
291 /* --angle */
292 p = cpl_parameter_new_value("kmos.kmos_flat.angle",
293 CPL_TYPE_DOUBLE, "Only reduce the specified angle",
294 "kmos.kmos_flat", 370.0);
295 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "angle");
296 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
297 cpl_parameterlist_append(recipe->parameters, p);
298
299 return 0 ;
300}
301
302/*----------------------------------------------------------------------------*/
308/*----------------------------------------------------------------------------*/
309static int kmos_flat_exec(cpl_plugin *plugin)
310{
311 cpl_recipe *recipe;
312
313 /* Get the recipe out of the plugin */
314 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
315 recipe = (cpl_recipe *)plugin;
316 else return -1;
317
318 return kmos_flat(recipe->parameters, recipe->frames);
319}
320
321/*----------------------------------------------------------------------------*/
327/*----------------------------------------------------------------------------*/
328static int kmos_flat_destroy(cpl_plugin *plugin)
329{
330 cpl_recipe *recipe;
331
332 /* Get the recipe out of the plugin */
333 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
334 recipe = (cpl_recipe *)plugin;
335 else return -1 ;
336
337 cpl_parameterlist_delete(recipe->parameters);
338 return 0 ;
339}
340
341/*----------------------------------------------------------------------------*/
355/*----------------------------------------------------------------------------*/
356static int kmos_flat(cpl_parameterlist *parlist, cpl_frameset *frameset)
357{
358 const cpl_parameter * par ;
359 int surrounding_pixels, badpix_thresh,
360 suppress_extension, reduce_det ;
361 double reduce_angle, cpos_rej, cneg_rej, ext_index ;
362 int cmax, cmin, citer ;
363 const char * cmethod ;
364 cpl_frame * frame ;
365 int nx, ny, next ;
366 int * angles_array ;
367 int nb_angles ;
368 cpl_image ** stored_flat ;
369 cpl_image ** stored_noise ;
370 cpl_image ** stored_badpix ;
371 cpl_image ** stored_xcal ;
372 cpl_image ** stored_ycal ;
373 double * stored_gapmean ;
374 double * stored_gapsdv ;
375 double * stored_gapmaxdev ;
376 double * stored_slitmean ;
377 double * stored_slitsdv ;
378 double * stored_slitmaxdev ;
379 double * stored_qc_flat_eff ;
380 double * stored_qc_flat_sn ;
381 int * stored_qc_flat_sat ;
382 int * stored_qc_flat_fail ;
383 //int * stored_qc_ifu_active ;
384 int * stored_qc_slit_edge ;
385 cpl_frameset * angle_frameset ;
386 char * extname ;
387 char * suffix ;
388 char * fn_suffix ;
389 unsigned int save_mode ;
390 const char * fn_flat = "flat_tmp.fits" ;
391 const char * fn_noise = "flat_noise.fits" ;
392 const char * fn_badpix = "badpix_tmp.fits" ;
393 cpl_imagelist * det_lamp_on ;
394 cpl_imagelist * det_lamp_off ;
395 cpl_image * img_in ;
396 cpl_image * combined_data_on ;
397 cpl_image * combined_noise_on ;
398 cpl_image * combined_data_off[KMOS_NR_DETECTORS] ;
399 cpl_image * combined_noise_off[KMOS_NR_DETECTORS] ;
400 cpl_image * bad_pix_mask_flat ;
401 cpl_image * bad_pix_mask_dark[KMOS_NR_DETECTORS] ;
402 cpl_image * xcal ;
403 cpl_image * ycal ;
404 cpl_array ** unused_ifus_before ;
405 cpl_array ** unused_ifus_after ;
406 cpl_propertylist * main_header ;
407 cpl_propertylist * main_header_xcal ;
408 cpl_propertylist * sub_header ;
409 cpl_table *** edge_table ;
410 cpl_error_code * spec_found ;
411 //QC Param New
412 double slit_edge_vec;
413 int y;
414
415 double gain, exptime, mean_data, mean_noise ;
416 int sx, nr_bad_pix, i, j, a, k, nr_cols;
417 int nr_sat = 0;
418 int active_ifus =0;
419 const int * pactive = NULL;
420
421 /* Check initial Entries */
422 if (kmos_check_and_set_groups(frameset) != CPL_ERROR_NONE) {
423 return cpl_error_get_code();
424 }
425
426 /* Get Parameters */
427 par = cpl_parameterlist_find_const(parlist,
428 "kmos.kmos_flat.surrounding_pixels");
429 surrounding_pixels = cpl_parameter_get_int(par);
430 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_flat.badpix_thresh");
431 badpix_thresh = cpl_parameter_get_int(par);
432 par = cpl_parameterlist_find_const(parlist,
433 "kmos.kmos_flat.suppress_extension");
434 suppress_extension = cpl_parameter_get_bool(par);
435 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_flat.angle");
436 reduce_angle = cpl_parameter_get_double(par);
437 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_flat.detector");
438 reduce_det = cpl_parameter_get_int(par);
439
440 kmos_combine_pars_load(parlist, "kmos.kmos_flat", &cmethod, &cpos_rej,
441 &cneg_rej, &citer, &cmin, &cmax, FALSE);
442
443 /* Check Parameters */
444 if (surrounding_pixels < 0 || surrounding_pixels > 8) {
445 cpl_msg_error(__func__, "surrounding_pixels must be in [0,8]") ;
446 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
447 return -1 ;
448 }
449 if (badpix_thresh < 0 || badpix_thresh > 100) {
450 cpl_msg_error(__func__, "badpix_thresh must be in [0,100]") ;
451 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
452 return -1 ;
453 }
454 if (reduce_det < 0 || reduce_det > 3) {
455 cpl_msg_error(__func__, "detector must be in [1,3]") ;
456 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
457 return -1 ;
458 }
459
460 /* Check the inputs consistency */
461 if (kmos_flat_check_inputs(frameset, &nx, &ny, &next, &exptime) != 1) {
462 cpl_msg_error(__func__, "Input frameset is not consistent") ;
463 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
464 return -1 ;
465 }
466
467 /* Instrument setup */
468 suffix = kmo_dfs_get_suffix(kmo_dfs_get_frame(frameset,FLAT_ON),TRUE,FALSE);
469 cpl_msg_info(__func__, "Detected instrument setup: %s", suffix+1);
470
471 /* Get Rotator angles */
472 if ((angles_array = kmos_get_angles(frameset, &nb_angles,FLAT_ON)) == NULL){
473 cpl_msg_error(__func__, "Cannot get Angles informations") ;
474 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
475 return -1 ;
476 }
477
478 /* The frames have to be stored temporarily because the QC parameters */
479 /* for the main header are calculated from each detector. */
480 /* So they can be stored only when all detectors are processed */
481 stored_flat = (cpl_image**)cpl_calloc(next*nb_angles, sizeof(cpl_image*));
482 stored_noise = (cpl_image**)cpl_calloc(next*nb_angles, sizeof(cpl_image*));
483 stored_badpix = (cpl_image**)cpl_calloc(next*nb_angles, sizeof(cpl_image*));
484 stored_xcal = (cpl_image**)cpl_calloc(next*nb_angles, sizeof(cpl_image*));
485 stored_ycal = (cpl_image**)cpl_calloc(next * nb_angles, sizeof(cpl_image*));
486 stored_qc_flat_sat = (int*)cpl_malloc(next * nb_angles * sizeof(int));
487 stored_qc_flat_fail = (int*)cpl_malloc(next* sizeof(int));
488 stored_qc_slit_edge = (int*)cpl_malloc(next * nb_angles * sizeof(int));
489 //stored_qc_ifu_active = (int*)cpl_malloc(next * nb_angles * sizeof(int));
490 stored_qc_flat_eff = (double*)cpl_malloc(next * nb_angles * sizeof(double));
491 stored_qc_flat_sn = (double*)cpl_malloc(next * nb_angles * sizeof(double));
492 stored_gapmean = (double*)cpl_malloc(next * nb_angles * sizeof(double));
493 stored_gapsdv = (double*)cpl_malloc(next * nb_angles * sizeof(double));
494 stored_gapmaxdev = (double*)cpl_malloc(next * nb_angles * sizeof(double));
495 stored_slitmean = (double*)cpl_malloc(next * nb_angles * sizeof(double));
496 stored_slitsdv = (double*)cpl_malloc(next * nb_angles * sizeof(double));
497 stored_slitmaxdev = (double*)cpl_malloc(next * nb_angles * sizeof(double));
498 spec_found = (cpl_error_code*)cpl_malloc(next * nb_angles *
499 sizeof(cpl_error_code));
500
501 //cpl_msg_info(cpl_func, "parameters set. %s", cpl_error_get_message());
502 //QC Params New
503 //cpl_vector * stored_qc_edge_mean = cpl_vector_new(next); //(double*)cpl_malloc( next* sizeof(double));
504 //( nb_angles * KMOS_IFUS_PER_DETECTOR * sizeof(double));
505 //cpl_msg_info(cpl_func, "edge mean array set %s.", cpl_error_get_message());
506
507 /* Initialise */
508 for (i = 0; i < next * nb_angles ; i++) {
509 stored_qc_flat_sat[i] = 0;
510 stored_qc_flat_eff[i] = 0.0;
511 stored_qc_flat_sn[i] = 0.0;
512 stored_gapmean[i] = 0.0;
513 stored_gapsdv[i] = 0.0;
514 stored_gapmaxdev[i] = 0.0;
515 stored_slitmean[i] = 0.0;
516 stored_slitsdv[i] = 0.0;
517 stored_slitmaxdev[i] = 0.0;
518 stored_qc_slit_edge[i] = 0.0;
519 spec_found[i] = CPL_ERROR_NONE;
520 }
521
522 //cpl_msg_info(cpl_func, "arrays almost done . %s", cpl_error_get_message());
523
524 for (i = 0; i < next; i++) {
525 stored_qc_flat_fail[i]= 0;
526
527 }
528
529 //y = (int*)cpl_malloc((int)((KMOS_DETECTOR_SIZE-2*KMOS_BADPIX_BORDER+1)/10) * sizeof(int));
530 // y = (int*)cpl_malloc((int)((KMOS_DETECTOR_SIZE)/10) * sizeof(int));
531 //int y[(int)cpl_image_get_size_y(img_in)/10];
532 //for (i =0; i <= sizeof(y); i++){
533 // y[i] = i*10;//+KMOS_BADPIX_BORDER;
534 //}
535 //cpl_msg_info(cpl_func, "Y values set for dimensions %d and %d. %s", next, nb_angles, cpl_error_get_message());
536
537
538 //cpl_msg_info(cpl_func, "arrays initialised . %s", cpl_error_get_message());
539
540 /* TODO : Improve handling of edge_table !!!! */
541 edge_table = (cpl_table***)cpl_malloc(next*nb_angles * sizeof(cpl_table**));
542 for (i = 0; i < next * nb_angles; i++) edge_table[i] = NULL;
543
544 /* Check which IFUs are active for all FLAT_ON frames */
545 unused_ifus_before = kmo_get_unused_ifus(frameset, 0, 0);
546 unused_ifus_after = kmo_duplicate_unused_ifus(unused_ifus_before);
547 kmo_print_unused_ifus(unused_ifus_before, FALSE);
548 kmo_free_unused_ifus(unused_ifus_before);
549
550 //cpl_msg_info(cpl_func, "checking detectors start." );
551 /* Combine the FLAT_OFF frames for the 3 detectors */
552 for (i = 1; i <= next; i++) {
553 /* Compute only one detector */
554 if (reduce_det != 0 && i != reduce_det) continue ;
555
556 /* Load the badpixel masks */
557 bad_pix_mask_dark[i-1] = kmo_dfs_load_image(frameset, BADPIXEL_DARK,
558 i, 2, FALSE, NULL) ;
559 //cpl_msg_info(cpl_func, "BPM loaded." );
560
561 /* Load lamp-off images */
562 det_lamp_off = cpl_imagelist_new();
563 frame = kmo_dfs_get_frame(frameset, FLAT_OFF);
564 //cpl_msg_info(cpl_func, "FLAT frame loaded." );
565
566 j = 0;
567 while (frame != NULL) {
568 img_in = kmo_dfs_load_image_frame(frame, i, FALSE, FALSE, NULL);
569 kmo_image_reject_from_mask(img_in, bad_pix_mask_dark[i-1]);
570 cpl_imagelist_set(det_lamp_off, img_in, j++);
571 frame = kmo_dfs_get_frame(frameset, NULL);
572 }
573
574 /* Combine FLAT_OFF frames */
575 //cpl_msg_info(__func__, "Combine FLAT_OFF frames for Detector %d", i) ;
576 kmos_combine_frames(det_lamp_off, cmethod, cpos_rej,
577 cneg_rej, citer, cmax, cmin, &(combined_data_off[i-1]),
578 &(combined_noise_off[i-1]), -1.0);
579 /*
580 cpl_image_save(combined_data_off[i-1], "off.fits",
581 CPL_TYPE_FLOAT, NULL, CPL_IO_CREATE) ;
582 */
583 cpl_imagelist_delete(det_lamp_off);
584 cpl_image_power(combined_noise_off[i-1], 2.0);
585 }
586
587 save_mode = CPL_IO_CREATE;
588 /* Loop all Rotator Angles and Detectors */
589 for (a = 0; a < nb_angles; a++) {
590 /* Reduce only one angle */
591 if (reduce_angle <= 360 && angles_array[a] != reduce_angle) continue ;
592
593 //cpl_msg_info(__func__, "Processing rotator angle %d -> %d degree",
594 // a, angles_array[a]);
595 //cpl_msg_indent_more() ;
596
597 /* Get the frameset with this angle */
598 angle_frameset = kmos_get_angle_frameset(frameset, angles_array[a],
599 FLAT_ON);
600 if (angle_frameset == NULL) {
601 cpl_msg_error(__func__, "Cannot get angle frameset") ;
602 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
603 cpl_msg_indent_less() ;
604 cpl_free(angles_array) ;
605 return -1 ;
606 }
607
608 for (i = 1; i <= next; i++) {
609 /* Compute only one detector */
610 if (reduce_det != 0 && i != reduce_det) continue ;
611
612 //cpl_msg_info(__func__, "Processing detector No. %d", i);
613 //cpl_msg_indent_more() ;
614 sx = a * next + (i - 1);
615 /* Load lamp-on images for Angle a */
616 det_lamp_on = cpl_imagelist_new();
617 frame = kmo_dfs_get_frame(angle_frameset, FLAT_ON);
618 j = 0;
619 while (frame != NULL) {
620 img_in=kmo_dfs_load_image_frame(frame, i, FALSE, TRUE, &nr_sat);
621 kmo_image_reject_from_mask(img_in, bad_pix_mask_dark[i-1]);
622 cpl_imagelist_set(det_lamp_on, img_in, j++);
623 frame = kmo_dfs_get_frame(angle_frameset, NULL);
624 }
625
626 /* Count saturated pixels for each detector */
627 //cpl_msg_info(__func__, "Count Saturated pixels on the detector") ;
628 frame = kmo_dfs_get_frame(angle_frameset, FLAT_ON);
629 main_header = kmclipm_propertylist_load(
630 cpl_frame_get_filename(frame), 0);
631 if (strcmp(cpl_propertylist_get_string(main_header, READMODE),
632 "Nondest") == 0) {
633 // NDR: non-destructive readout mode
634 stored_qc_flat_sat[sx] = nr_sat;
635 } else {
636 // normal readout mode
637 stored_qc_flat_sat[sx] = kmo_imagelist_get_saturated(
638 det_lamp_on, KMO_FLAT_SATURATED, KMO_FLAT_SAT_MIN);
639 }
640 cpl_propertylist_delete(main_header);
641
642 /* Combine imagelists and create noise */
643 //cpl_msg_info(__func__, "Combine FLAT_ON frames, %s", cpl_error_get_message() ) ;
644 kmos_combine_frames(det_lamp_on, cmethod, cpos_rej,
645 cneg_rej, citer, cmax, cmin, &combined_data_on,
646 &combined_noise_on, -1.0);
647 cpl_imagelist_delete(det_lamp_on);
648
649 if (kmclipm_omit_warning_one_slice > 10)
650 kmclipm_omit_warning_one_slice = FALSE;
651
652 /* Subtract combined lamp_off from lamp_on */
653 cpl_image_subtract(combined_data_on, combined_data_off[i-1]);
654
655 /* noise: sig_x = sqrt(sig_u^2 + sig_v^2 */
656 //cpl_msg_info(__func__, "Compute the noise") ;
657 cpl_image_power(combined_noise_on, 2.0);
658 cpl_image_add(combined_noise_on, combined_noise_off[i-1]);
659 cpl_image_power(combined_noise_on, 0.5);
660
661 /* Create bad-pixel-mask */
662 bad_pix_mask_flat = kmo_create_bad_pix_flat_thresh(combined_data_on,
663 surrounding_pixels, badpix_thresh);
664
665 /* Calculate spectral curvature here */
666 //cpl_msg_info(__func__, "Compute the spectral curvature") ;
667 cpl_msg_indent_more() ;
668 spec_found[sx] = kmo_calc_curvature(combined_data_on,
669 combined_noise_on, unused_ifus_after[i-1],
670 bad_pix_mask_flat, i, &xcal, &ycal, stored_gapmean+(sx),
671 stored_gapsdv+(sx), stored_gapmaxdev+(sx),
672 stored_slitmean+(sx), stored_slitsdv+(sx),
673 stored_slitmaxdev+(sx), &edge_table[sx]);
674 cpl_msg_indent_less() ;
675
676 if (spec_found[sx] == CPL_ERROR_NONE) {
677 // in kmo_calc_curvature() the spectral slope of each
678 // slitlet has been normalised individually. Now the
679 // normalisation on the whole frame is applied.
680 // (cpl_image_get_mean() ignores bad pixels when
681 // calculating the mean)
682 mean_data = cpl_image_get_mean(combined_data_on);
683 stored_qc_flat_eff[sx] = mean_data / exptime;
684 mean_noise = cpl_image_get_mean(combined_noise_on);
685 if (fabs(mean_noise) < 1e-3) {
686 cpl_msg_error(__func__, "Division by 0.0") ;
687 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
688 cpl_free(angles_array) ;
689 return -1 ;
690 }
691 stored_qc_flat_sn[sx] = mean_data / mean_noise;
692
693 /* Normalize data & noise on the whole detector frame */
694 /* The spectral slope on each slitlet has already been */
695 /* normalised in kmo_calc_curvature() */
696 cpl_image_divide_scalar(combined_data_on, mean_data);
697 cpl_image_divide_scalar(combined_noise_on, mean_data);
698
699 /* Apply the badpixel mask to the produced frames */
700 cpl_image_multiply(combined_data_on, bad_pix_mask_flat);
701 cpl_image_multiply(combined_noise_on, bad_pix_mask_flat);
702 cpl_image_multiply(xcal, bad_pix_mask_flat) ;
703 cpl_image_multiply(ycal, bad_pix_mask_flat) ;
704
705 /* Store temporarily flat, badpixel and calibration */
706 stored_xcal[sx] = xcal;
707 stored_ycal[sx] = ycal;
708
709 //cpl_msg_info(cpl_func, "SPEC FOUND - %d", sx);
710
711 /* Save immediate results, free memory */
712 kmclipm_image_save(combined_data_on, fn_flat, CPL_TYPE_FLOAT,
713 NULL, save_mode, 0./0.);
714 kmclipm_image_save(combined_noise_on, fn_noise, CPL_TYPE_FLOAT,
715 NULL, save_mode, 0./0.);
716 kmclipm_image_save(bad_pix_mask_flat, fn_badpix, CPL_TYPE_FLOAT,
717 NULL, save_mode, 0./0.);
718 /* Next saves will create extensions */
719 save_mode = CPL_IO_EXTEND;
720
721 } else if (spec_found[sx] == CPL_ERROR_DATA_NOT_FOUND) {
722 /* All IFUs seem to be deactivated */
723 cpl_msg_warning(__func__, "All IFUs deactivated - NULL image saved.") ;
724 cpl_error_reset();
725
726 /* Save immediate results, free memory */
727 //cpl_image * nan_image = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
728 //cpl_image_fill_window(nan_image, 1, 1, nx, ny, 0./0.);
729 cpl_image_save(NULL, fn_flat, CPL_TYPE_FLOAT, NULL, save_mode);
730 cpl_image_save(NULL , fn_noise, CPL_TYPE_FLOAT, NULL, save_mode);
731 cpl_image_save(NULL , fn_badpix, CPL_TYPE_FLOAT, NULL,save_mode);
732 /* Next saves will create extensions */
733 save_mode = CPL_IO_EXTEND;
734
735 stored_xcal[sx] = NULL ;
736 stored_ycal[sx] = NULL ;
737 stored_qc_flat_fail[i-1]++;
738 //cpl_image_delete(nan_image);
739 //cpl_msg_info(__func__, "NAN image saved .") ;
740
741
742 } else {
743 // another error occurred
744 cpl_msg_error(__func__, "Unknown ERROR !") ;
745 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
746 cpl_image_delete(combined_data_on);
747 cpl_image_delete(combined_noise_on);
748 cpl_image_delete(bad_pix_mask_flat);
749 cpl_free(angles_array) ;
750 cpl_msg_indent_less() ;
751 cpl_msg_indent_less() ;
752 return -1 ;
753 }
754 cpl_image_delete(combined_data_on);
755 cpl_image_delete(combined_noise_on);
756 cpl_image_delete(bad_pix_mask_flat);
757 //cpl_vector_delete(slit_edge_vec);
758
759 cpl_msg_indent_less() ;
760 } // for i = 1; i <= next
761 cpl_frameset_delete(angle_frameset);
762 cpl_msg_indent_less() ;
763 } // for a = 0; a < nb_angles
764
765 cpl_msg_info(__func__, "image saving done .") ;
766 /*cpl_msg_info(cpl_func, "Edge Table 0,17");
767 cpl_table_dump(&edge_table[0][0], 0, cpl_table_get_nrow(edge_table[0][0]), stdout);
768 cpl_msg_info(cpl_func, "Edge Table 1,0");
769 cpl_table_dump(edge_table[5][3], 0, cpl_table_get_nrow(edge_table[5][3]), stdout);*/
770 //cpl_msg_info(cpl_func, "ERROR Message - %s", cpl_error_get_message());
771
772 /* Clean OFF frames */
773 for (i = 1; i <= next; i++) {
774 /* Compute only one detector */
775 if (reduce_det != 0 && i != reduce_det) continue ;
776
777 cpl_image_delete(combined_data_off[i-1]) ;
778 cpl_image_delete(combined_noise_off[i-1]) ;
779 cpl_image_delete(bad_pix_mask_dark[i-1]);
780 }
781
782 cpl_msg_info(__func__, "frame cleaning done .") ;
783
784 //Calculating QC FLAT FAIL
785
786 /*for (i = 1; i <=next; i++) {
787 stored_qc_flat_fail[i]= 0;
788 if (reduce_det != 0 && i != reduce_det) continue ;
789
790 for (a = 0; a < nb_angles; a++) {
791 sx = a * next + (i - 1);
792 if (stored_flat[sx] == NULL){
793 stored_qc_flat_fail[i]++;
794 }
795 }
796 } */
797
798 cpl_msg_info(__func__, "coming into qc parameters.") ;
799
800 /* ----- QC parameters & saving */
801 /* ---- load, update & save primary header */
802 main_header = kmo_dfs_load_primary_header(frameset, FLAT_ON);
803
804 /* Update which IFUs are not used */
805 kmo_print_unused_ifus(unused_ifus_after, TRUE);
806 kmo_set_unused_ifus(unused_ifus_after, main_header, "kmos_flat");
807 //kmo_free_unused_ifus(unused_ifus_after);
808
809 cpl_msg_info(__func__, " creating bounds starting .") ;
810 /* xcal gets additionally the boundaries of the IFUs for reconstruction */
811 main_header_xcal=kmos_create_bounds_properties(stored_ycal,next,nb_angles) ;
812
813 /* --------- saving headers */
814 if (!suppress_extension) fn_suffix = cpl_sprintf("%s", suffix);
815 else fn_suffix = cpl_sprintf("%s", "");
816 cpl_free(suffix);
817
818 //cpl_msg_info(__func__, "Saving data...");
819
820 frame = kmo_dfs_get_frame(frameset, FLAT_ON);
821 kmo_dfs_save_main_header(frameset, MASTER_FLAT, fn_suffix, frame,
822 main_header, parlist, cpl_func);
823 kmo_dfs_save_main_header(frameset, XCAL, fn_suffix, frame,
824 main_header_xcal, parlist, cpl_func);
825 kmo_dfs_save_main_header(frameset, YCAL, fn_suffix, frame,
826 main_header, parlist, cpl_func);
827 kmo_dfs_save_main_header(frameset, BADPIXEL_FLAT, fn_suffix, frame,
828 main_header, parlist, cpl_func);
829 kmo_dfs_save_main_header(frameset, FLAT_EDGE, fn_suffix, frame,
830 main_header, parlist, cpl_func);
831
832 cpl_propertylist_delete(main_header);
833 cpl_propertylist_delete(main_header_xcal);
834
835 cpl_msg_info(__func__, " main headers read and saved .") ;
836
837
838 /* -------- saving sub frames */
839 ext_index = 0 ;
840 char *name = NULL;
841 double x = 0.;
842
843 for (a = 0; a < nb_angles; a++) {
844
845 /* Reduce only one angle */
846 if (reduce_angle <= 360 && angles_array[a] != reduce_angle) continue ;
847
848 for (i = 1; i <= next; i++) {
849 /* Compute only one detector */
850 if (reduce_det != 0 && i != reduce_det) continue ;
851
852 sx = a * next + (i - 1);
853 // load stored data again
854 stored_flat[sx]=kmclipm_image_load(fn_flat, CPL_TYPE_FLOAT, 0,
855 ext_index);
856
857 cpl_error_reset() ;
858 stored_noise[sx]=kmclipm_image_load(fn_noise, CPL_TYPE_FLOAT, 0,
859 ext_index);
860 cpl_error_reset() ;
861 stored_badpix[sx]=kmclipm_image_load(fn_badpix,CPL_TYPE_FLOAT, 0,
862 ext_index);
863 cpl_error_reset() ;
864 ext_index ++ ;
865
866 sub_header = kmo_dfs_load_sub_header(frameset, FLAT_ON, i, FALSE);
867
868 kmclipm_update_property_double(sub_header,CAL_ROTANGLE,
869 ((double) angles_array[a]),
870 "[deg] Rotator relative to nasmyth");
871
872 if (spec_found[sx] == CPL_ERROR_NONE) {
873 kmclipm_update_property_int(sub_header, QC_FLAT_SAT,
874 stored_qc_flat_sat[sx],
875 "[] nr. saturated pixels of master flat");
876 /* Load gain */
877 gain = kmo_dfs_get_property_double(sub_header, GAIN);
878 kmclipm_update_property_double(sub_header, QC_FLAT_EFF,
879 stored_qc_flat_eff[sx]/gain,
880 "[e-/s] rel. brightness of flat lamp");
881
882 kmclipm_update_property_double(sub_header, QC_FLAT_SN,
883 stored_qc_flat_sn[sx], "[] S/N of master flat");
884 }
885
886 /* Store qc parameters only if any slitlet- and gap-width */
887 /* has been detected (should be the case when at least */
888 /* one IFU is active) */
889 if (stored_xcal[sx] != NULL) {
890 kmclipm_update_property_double(sub_header, QC_GAP_MEAN,
891 stored_gapmean[sx],
892 "[pix] mean gap width between slitlets");
893 kmclipm_update_property_double(sub_header, QC_GAP_SDV,
894 stored_gapsdv[sx],
895 "[pix] stdev of gap width between slitlets");
896 kmclipm_update_property_double(sub_header, QC_GAP_MAXDEV,
897 stored_gapmaxdev[sx],
898 "[pix] max gap deviation between slitlets");
899 kmclipm_update_property_double(sub_header, QC_SLIT_MEAN,
900 stored_slitmean[sx], "[pix] mean slitlet width");
901 kmclipm_update_property_double(sub_header, QC_SLIT_SDV,
902 stored_slitsdv[sx], "[pix] stdev of slitlet widths");
903 kmclipm_update_property_double(sub_header, QC_SLIT_MAXDEV,
904 stored_slitmaxdev[sx],
905 "[pix] max slitlet width deviation");
906 }
907
908 /* Calculate QC.BADPIX.NCOUNT */
909 /* Remove 4pixel-border as bad pixels */
910 nr_bad_pix = 0 ;
911 if (stored_badpix[sx] != NULL) {
912 nr_bad_pix = cpl_image_count_rejected(stored_badpix[sx]);
913 nr_bad_pix -= 2*KMOS_BADPIX_BORDER*(nx-2*KMOS_BADPIX_BORDER) +
914 2*KMOS_BADPIX_BORDER*ny;
915 }
916
917 kmclipm_update_property_int(sub_header, QC_NR_BAD_PIX, nr_bad_pix,
918 "[] nr. of bad pixels");
919
920 active_ifus= 0;
921 pactive = cpl_array_get_data_int(unused_ifus_after[i-1]);
922 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
923 if (pactive[j] ==0)
924 active_ifus++;
925 }
926 kmclipm_update_property_int(sub_header, QC_IFU_ACTIVE, active_ifus,
927 "[] nr. of active ifus");
928
929 kmclipm_update_property_int(sub_header, QC_FLAT_FAIL, stored_qc_flat_fail[i-1],
930 "[] rot. angles with empty extensions ");
931
932 // QC SLIT EDGE START
933
934 cpl_vector * stored_qc_edge_mean = cpl_vector_new(KMOS_IFUS_PER_DETECTOR);
935
936 int ref_sl=-1;
937 for (int ref_sl_i=0; ref_sl_i<KMOS_IFUS_PER_DETECTOR; ref_sl_i++){
938 if (pactive[ref_sl_i] == 0){
939 ref_sl = ref_sl_i;
940 break;
941 }
942 }
943
944 if ((ref_sl != -1)&&(edge_table[sx] != NULL)&&(edge_table[sx][ref_sl] != NULL)){
945 slit_edge_vec = 0.0;
946 y=0;
947 k=0;
948
949 while ( y < (int)KMOS_DETECTOR_SIZE){
950 //for (k=0; k< sizeof(y); k++){
951 // subtract one because the first column contains the slitlet IDs
952 nr_cols = cpl_table_get_ncol(edge_table[sx][ref_sl])-1;
953 x = 0.0;
954 for (j = 0; j < nr_cols; j++) {
955 // construct column name
956 name = cpl_sprintf("A%d", j);
957
958 // x = A0 + A1*y + A2*y*y + A3*y*y*y + ...
959 x += pow(y, j) *
960 cpl_table_get_double(edge_table[sx][ref_sl], name, 0, NULL);
961
962 cpl_free(name); name = NULL;
963 }
964 slit_edge_vec += x;
965 k++;
966 y= k*10;
967
968 }
969
970 cpl_vector_set(stored_qc_edge_mean, (i-1), slit_edge_vec/(k-1));
971
972 }
973 else {
974 cpl_vector_set(stored_qc_edge_mean, (i-1), -1.0);
975 }
976
977 kmclipm_update_property_double(sub_header, QC_SLIT_EDGE,
978 cpl_vector_get(stored_qc_edge_mean,i-1), QC_SLIT_EDGE_DESC);
979 //cpl_msg_info(cpl_func, "sub header updated");
980
981 cpl_vector_delete(stored_qc_edge_mean);
982
983 // QC SLIT EDGE END
984
985 /* Save flat frame */
986 extname = kmo_extname_creator(detector_frame, i, EXT_DATA);
987 kmclipm_update_property_string(sub_header, EXTNAME,extname,
988 "FITS extension name");
989 cpl_free(extname);
990
991 kmclipm_update_property_int(sub_header, EXTVER, sx+1,
992 "FITS extension ver");
993
994 if (stored_flat[sx] != NULL) {
995 kmo_dfs_save_image(stored_flat[sx], MASTER_FLAT, fn_suffix,
996 sub_header, 0./0.);
997 }
998 else {
999 cpl_image * nan_image = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
1000 cpl_image_fill_window(nan_image, 1, 1, nx, ny, 0./0.);
1001 kmo_dfs_save_image(nan_image, MASTER_FLAT, fn_suffix,
1002 sub_header, 0./0.);
1003
1004 cpl_image_delete(nan_image);
1005 }
1006
1007 /* Save noise frame when enough input frames were available */
1008 extname = kmo_extname_creator(detector_frame, i, EXT_NOISE);
1009 kmclipm_update_property_string(sub_header, EXTNAME,extname,
1010 "FITS extension name");
1011 cpl_free(extname);
1012
1013 if (stored_flat[sx] != NULL) {
1014 kmo_dfs_save_image(stored_noise[sx], MASTER_FLAT, fn_suffix,
1015 sub_header, 0./0.);
1016 }
1017 else {
1018 cpl_image * nan_image = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
1019 cpl_image_fill_window(nan_image, 1, 1, nx, ny, 0./0.);
1020 kmo_dfs_save_image(stored_noise[sx], MASTER_FLAT, fn_suffix,
1021 sub_header, 0./0.);
1022
1023 cpl_image_delete(nan_image);
1024 }
1025
1026 cpl_propertylist_erase(sub_header, QC_IFU_ACTIVE);
1027 cpl_propertylist_erase(sub_header, QC_FLAT_FAIL);
1028
1029
1030 /* Save bad_pix frame */
1031 extname = kmo_extname_creator(detector_frame, i, EXT_BADPIX);
1032 kmclipm_update_property_string(sub_header, EXTNAME,extname,
1033 "FITS extension name");
1034 cpl_free(extname);
1035
1036 kmo_dfs_save_image(stored_badpix[sx], BADPIXEL_FLAT, fn_suffix,
1037 sub_header, 0.);
1038
1039 // save xcal and ycal-frame
1040 extname = kmo_extname_creator(detector_frame, i, EXT_DATA);
1041 kmclipm_update_property_string(sub_header, EXTNAME, extname,
1042 "FITS extension name");
1043 cpl_free(extname);
1044
1045 if (stored_flat[sx] != NULL) {
1046 kmo_dfs_save_image(stored_xcal[sx], XCAL, fn_suffix, sub_header,
1047 0./0.);
1048 kmo_dfs_save_image(stored_ycal[sx], YCAL, fn_suffix, sub_header,
1049 0./0.);
1050 }
1051 else {
1052 cpl_image * nan_image = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
1053 cpl_image_fill_window(nan_image, 1, 1, nx, ny, 0./0.);
1054 kmo_dfs_save_image(nan_image, XCAL, fn_suffix, sub_header,
1055 0./0.);
1056 kmo_dfs_save_image(nan_image, YCAL, fn_suffix, sub_header,
1057 0./0.);
1058
1059 cpl_image_delete(nan_image);
1060 }
1061
1062 /* Save edge_pars-frame */
1063 /* Clean the input header */
1064 cpl_propertylist_erase(sub_header, "BUNIT");
1065
1066
1067 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
1068 extname = cpl_sprintf("%s_IFU.%d_ANGLE.%d", EXT_LIST,
1069 j+1+(i-1)*KMOS_IFUS_PER_DETECTOR, angles_array[a]);
1070 kmclipm_update_property_string(sub_header, EXTNAME, extname,
1071 "FITS extension name");
1072 cpl_free(extname);
1073
1074 kmclipm_update_property_int(sub_header, CAL_IFU_NR,
1075 j+1+(i-1)*KMOS_IFUS_PER_DETECTOR, "IFU Number {1..24}");
1076
1077 /* Save edge-parameters as product */
1078 if ((spec_found[sx] != CPL_ERROR_DATA_NOT_FOUND) &&
1079 (edge_table[sx] != NULL)&&(edge_table[sx][j] != NULL)) {
1080 kmo_dfs_save_table(edge_table[sx][j], FLAT_EDGE,
1081 fn_suffix, sub_header);
1082 } else {
1083 cpl_propertylist_erase(sub_header, CRVAL1);
1084 cpl_propertylist_erase(sub_header, CRVAL2);
1085 cpl_propertylist_erase(sub_header, CD1_1);
1086 cpl_propertylist_erase(sub_header, CD1_2);
1087 cpl_propertylist_erase(sub_header, CD2_1);
1088 cpl_propertylist_erase(sub_header, CD2_2);
1089 cpl_propertylist_erase(sub_header, CRPIX1);
1090 cpl_propertylist_erase(sub_header, CRPIX2);
1091 cpl_propertylist_erase(sub_header, CTYPE1);
1092 cpl_propertylist_erase(sub_header, CTYPE2);
1093
1094 kmo_dfs_save_table(NULL, FLAT_EDGE, fn_suffix,
1095 sub_header);
1096 }
1097 }
1098 cpl_propertylist_delete(sub_header);
1099
1100 cpl_image_delete(stored_flat[sx]);
1101 cpl_image_delete(stored_noise[sx]);
1102 cpl_image_delete(stored_badpix[sx]);
1103 } // for (i = next)
1104 } // for (a = nb_angles)
1105
1106 // delete temporary files
1107
1108 kmo_free_unused_ifus(unused_ifus_after);
1109 unlink(fn_flat);
1110 unlink(fn_noise);
1111 unlink(fn_badpix);
1112
1113 cpl_free(stored_qc_flat_fail);
1114 cpl_free(stored_qc_flat_sat);
1115 cpl_free(stored_qc_flat_eff);
1116 cpl_free(stored_qc_flat_sn);
1117 cpl_free(stored_gapmean);
1118 cpl_free(stored_gapsdv);
1119 cpl_free(stored_gapmaxdev);
1120 cpl_free(stored_slitmean);
1121 cpl_free(stored_slitsdv);
1122 cpl_free(stored_slitmaxdev);
1123 cpl_free(fn_suffix);
1124 cpl_free(stored_flat);
1125 cpl_free(stored_noise);
1126 cpl_free(stored_badpix);
1127 for (i = 0; i < next * nb_angles; i++) {
1128 cpl_image_delete(stored_xcal[i]);
1129 cpl_image_delete(stored_ycal[i]);
1130 }
1131 cpl_free(stored_xcal);
1132 cpl_free(stored_ycal);
1133 if (edge_table != NULL) {
1134 for (i = 0; i < next * nb_angles; i++) {
1135 if (edge_table[i] != NULL) {
1136 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
1137 cpl_table_delete(edge_table[i][j]);
1138 }
1139 cpl_free(edge_table[i]);
1140 }
1141 }
1142 cpl_free(edge_table);
1143 }
1144 cpl_free(spec_found);
1145 cpl_free(angles_array) ;
1146
1147 return 0;
1148}
1149
1152/*----------------------------------------------------------------------------*/
1162/*----------------------------------------------------------------------------*/
1163static cpl_propertylist * kmos_create_bounds_properties(
1164 cpl_image ** stored_ycal,
1165 int next,
1166 int nb_angles)
1167{
1168 cpl_propertylist * bounds_props ;
1169 int * bounds ;
1170 int ** total_bounds ;
1171 char * tmpstr ;
1172 int a, i, j, sx ;
1173
1174 /* Check Entries */
1175 if (stored_ycal == NULL) return NULL ;
1176
1177 /* Add here boundaries for reconstruction */
1178 bounds_props = cpl_propertylist_new();
1179
1180 /* Initialize total_bounds */
1181 total_bounds = (int**)cpl_malloc(next*sizeof(int*));
1182 for (i = 0; i < next; i++) {
1183 total_bounds[i]=(int*)cpl_calloc(2*KMOS_IFUS_PER_DETECTOR,sizeof(int));
1184 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
1185 total_bounds[i][2*j] = 2048;
1186 total_bounds[i][2*j+1] = 0;
1187 }
1188 }
1189
1190 /* Store the min left bound and max right bound for all angles */
1191 for (a = 0; a < nb_angles; a++) {
1192 for (i = 0; i < next; i++) {
1193 sx = a * next + i;
1194
1195 if (stored_ycal[sx] != NULL) {
1196 bounds = kmo_split_frame(stored_ycal[sx]);
1197
1198 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
1199 if ((total_bounds[i][2*j] == -1)||(bounds[2*j] == -1)) {
1200 total_bounds[i][2*j] = -1;
1201 } else {
1202 if (total_bounds[i][2*j] > bounds[2*j]) {
1203 total_bounds[i][2*j] = bounds[2*j];
1204 }
1205 }
1206
1207 if ((total_bounds[i][2*j+1] == -1) ||
1208 (bounds[2*j+1] == -1)) {
1209 total_bounds[i][2*j+1] = -1;
1210 } else {
1211 if (total_bounds[i][2*j+1] < bounds[2*j+1]) {
1212 total_bounds[i][2*j+1] = bounds[2*j+1];
1213 }
1214 }
1215 }
1216 cpl_free(bounds);
1217 } else {
1218 // whole detector inactive
1219 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
1220 total_bounds[i][2*j] = -1;
1221 total_bounds[i][2*j+1] = -1;
1222 }
1223 }
1224 } // for (next)
1225 } // for (nb_angles)
1226
1227 /* Write the min left bound and max right bound for all angles */
1228 /* into the main header */
1229 for (i = 0; i < next; i++) {
1230 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
1231 if (total_bounds[i][2*j] > -1) {
1232 tmpstr= cpl_sprintf("%s%d%s", BOUNDS_PREFIX,
1233 i*KMOS_IFUS_PER_DETECTOR + j+1, "_L");
1234 kmclipm_update_property_int(bounds_props, tmpstr,
1235 total_bounds[i][2*j],
1236 "[pix] left boundary for reconstr.");
1237 cpl_free(tmpstr);
1238 }
1239
1240 if (total_bounds[i][2*j+1] > -1) {
1241 tmpstr= cpl_sprintf("%s%d%s", BOUNDS_PREFIX,
1242 i*KMOS_IFUS_PER_DETECTOR + j+1, "_R");
1243 kmclipm_update_property_int(bounds_props,tmpstr,
1244 total_bounds[i][2*j+1],
1245 "[pix] right boundary for reconstr.");
1246 cpl_free(tmpstr);
1247 }
1248 }
1249 } // for (next)
1250 for (i = 0; i < next; i++) cpl_free(total_bounds[i]);
1251 cpl_free(total_bounds);
1252
1253 return bounds_props ;
1254}
1255
1256/*----------------------------------------------------------------------------*/
1266/*----------------------------------------------------------------------------*/
1267static int kmos_flat_check_inputs(
1268 cpl_frameset * frameset,
1269 int * nx,
1270 int * ny,
1271 int * next,
1272 double * exptime_on)
1273{
1274 const cpl_frame * frame ;
1275 cpl_propertylist * eh ;
1276 cpl_propertylist * mh1 ;
1277 cpl_propertylist * main_header ;
1278 int ndit ;
1279 double exptime ;
1280 const char * readmode ;
1281 int naxis1, naxis2, n_ext ;
1282
1283 /* TODO Add frames dimensions checks TODO */
1284
1285 /* Check Entries */
1286 if (nx == NULL || ny == NULL || frameset == NULL || exptime_on == NULL)
1287 return -1;
1288
1289 /* check BADPIXEL_DARK */
1290 frame = kmo_dfs_get_frame(frameset, BADPIXEL_DARK);
1291 if (frame == NULL) {
1292 cpl_msg_warning(__func__, "BADPIXEL_DARK frame is missing") ;
1293 return 0 ;
1294 }
1295 n_ext = cpl_frame_get_nextensions(frame);
1296 if (n_ext != KMOS_NR_DETECTORS) {
1297 cpl_msg_warning(__func__, "BADPIXEL_DARK must have 3 extensions") ;
1298 return 0 ;
1299 }
1300 eh = cpl_propertylist_load(cpl_frame_get_filename(frame), 1);
1301 naxis1 = kmos_pfits_get_naxis1(eh) ;
1302 naxis2 = kmos_pfits_get_naxis2(eh) ;
1303 cpl_propertylist_delete(eh) ;
1304
1305 /* check FLAT_OFF */
1306 frame = kmo_dfs_get_frame(frameset, FLAT_OFF);
1307 mh1 = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
1308 ndit = cpl_propertylist_get_int(mh1, NDIT);
1309 exptime = cpl_propertylist_get_double(mh1, EXPTIME);
1310 readmode = cpl_propertylist_get_string(mh1, READMODE);
1311
1312 /* Loop through FLAT_OFF frames */
1313 while (frame != NULL) {
1314 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
1315
1316 if (cpl_propertylist_get_int(main_header, NDIT) != ndit) {
1317 cpl_msg_warning(__func__, "NDIT inconsistent") ;
1318 cpl_propertylist_delete(mh1);
1319 cpl_propertylist_delete(main_header);
1320 return 0 ;
1321 }
1322 if (cpl_propertylist_get_double(main_header, EXPTIME) != exptime) {
1323 cpl_msg_warning(__func__, "EXPTIME inconsistent") ;
1324 cpl_propertylist_delete(mh1);
1325 cpl_propertylist_delete(main_header);
1326 return 0 ;
1327 }
1328 if (strcmp(cpl_propertylist_get_string(main_header, READMODE),
1329 readmode) != 0) {
1330 cpl_msg_warning(__func__, "READMODE inconsistent") ;
1331 cpl_propertylist_delete(mh1);
1332 cpl_propertylist_delete(main_header);
1333 return 0 ;
1334 }
1335
1336 /* Assure that arc lamps are off */
1337 if ((kmo_check_lamp(main_header, INS_LAMP1_ST) != FALSE)
1338 || (kmo_check_lamp(main_header, INS_LAMP2_ST) != FALSE)) {
1339 cpl_msg_warning(__func__, "Arc lamps must be switched off") ;
1340 cpl_propertylist_delete(mh1);
1341 cpl_propertylist_delete(main_header);
1342 return 0 ;
1343 }
1344 cpl_propertylist_delete(main_header);
1345
1346 /* Get next FLAT_OFF frame */
1347 frame = kmo_dfs_get_frame(frameset, NULL);
1348 }
1349
1350 /* Loop through FLAT_ON frames */
1351 frame = kmo_dfs_get_frame(frameset, FLAT_ON);
1352 while (frame != NULL) {
1353 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
1354
1355 if (cpl_propertylist_get_int(main_header, NDIT) != ndit) {
1356 cpl_msg_warning(__func__, "NDIT inconsistent") ;
1357 cpl_propertylist_delete(mh1);
1358 cpl_propertylist_delete(main_header);
1359 return 0 ;
1360 }
1361 if (cpl_propertylist_get_double(main_header, EXPTIME) != exptime) {
1362 cpl_msg_warning(__func__, "EXPTIME inconsistent") ;
1363 cpl_propertylist_delete(mh1);
1364 cpl_propertylist_delete(main_header);
1365 return 0 ;
1366 }
1367 if (strcmp(cpl_propertylist_get_string(main_header, READMODE),
1368 readmode) != 0) {
1369 cpl_msg_warning(__func__, "READMODE inconsistent") ;
1370 cpl_propertylist_delete(mh1);
1371 cpl_propertylist_delete(main_header);
1372 return 0 ;
1373 }
1374
1375 /* Assure that arc lamps are off */
1376 if ((kmo_check_lamp(main_header, INS_LAMP1_ST) != FALSE)
1377 || (kmo_check_lamp(main_header, INS_LAMP2_ST) != FALSE)) {
1378 cpl_msg_warning(__func__, "Arc lamps must be switched off") ;
1379 cpl_propertylist_delete(mh1);
1380 cpl_propertylist_delete(main_header);
1381 return 0 ;
1382 }
1383
1384 /* Assure that at least one flat lamp is on */
1385 if ((kmo_check_lamp(main_header, INS_LAMP3_ST) != TRUE)
1386 && (kmo_check_lamp(main_header, INS_LAMP4_ST) != TRUE)) {
1387 cpl_msg_warning(__func__, "At least one flat lamps must be on") ;
1388 cpl_propertylist_delete(mh1);
1389 cpl_propertylist_delete(main_header);
1390 return 0 ;
1391 }
1392
1393 /* Get next FLAT_ON frame */
1394 frame = kmo_dfs_get_frame(frameset, NULL);
1395
1396 cpl_propertylist_delete(main_header);
1397 }
1398 cpl_msg_info(__func__, "EXPTIME: %g seconds", exptime);
1399 cpl_msg_info(__func__, "NDIT: %d", ndit);
1400 cpl_msg_info(__func__, "Detector readout mode: %s", readmode);
1401 cpl_propertylist_delete(mh1);
1402
1403 /* Check Filters consistency */
1404 if (kmo_check_frameset_setup(frameset, FLAT_ON, TRUE, FALSE, FALSE) !=
1405 CPL_ERROR_NONE) {
1406 cpl_msg_warning(__func__, "Filters are not consistent") ;
1407 return 0 ;
1408 }
1409
1410 /* Return */
1411 *nx = naxis1 ;
1412 *ny = naxis2 ;
1413 *next = n_ext ;
1414 *exptime_on = exptime ;
1415 return 1 ;
1416}
1417
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.
Definition: kmos_flat.c:207