34#include "kmo_priv_flat.h"
35#include "kmo_priv_wave_cal.h"
36#include "kmo_priv_functions.h"
38#include "kmo_priv_combine.h"
39#include "kmos_pfits.h"
41#include "kmo_constants.h"
42#include "kmo_cpl_extensions.h"
49static int kmos_flat_check_inputs(cpl_frameset *,
int *,
int *,
int *,
double *);
50static cpl_propertylist * kmos_create_bounds_properties(cpl_image **,
int,
int) ;
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 *);
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"
69"The badpixel mask contains 0 for bad pixels and 1 for good ones.\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"
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"
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"
115"The threshold level to mark pixels as bad on the dark subtracted frames [%]"
117"--surrounding_pixels\n"
118"The amount of bad pixels to surround a specific pixel, to let it be marked\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"
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"
134" At each pixel position the median is calculated.\n"
137" At each pixel position the average is calculated.\n"
140" At each pixel position the sum is calculated.\n"
143" The specified number of min and max pixel values will be rejected.\n"
144" --cmax and --cmin apply to this method.\n"
146"ADVANCED PARAMETERS\n"
147"-------------------\n"
151"see --cmethod='ksigma'\n"
155"see --cmethod='min_max'\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"
162"-------------------------------------------------------------------------------\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"
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"---------------------------------------------------------------------------"
209 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe);
210 cpl_plugin *plugin = &recipe->interface;
212 cpl_plugin_init(plugin,
215 CPL_PLUGIN_TYPE_RECIPE,
217 "Create master flatfield frame and badpixel map",
218 kmos_flat_description,
219 "Alex Agudo Berbel, Yves Jung",
220 "https://support.eso.org/",
226 cpl_pluginlist_append(list, plugin);
240static int kmos_flat_create(cpl_plugin *plugin)
246 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
247 recipe = (cpl_recipe *)plugin;
252 recipe->parameters = cpl_parameterlist_new();
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);
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);
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);
280 kmos_combine_pars_create(recipe->parameters,
"kmos.kmos_flat",
281 DEF_REJ_METHOD, FALSE);
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);
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);
309static int kmos_flat_exec(cpl_plugin *plugin)
314 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
315 recipe = (cpl_recipe *)plugin;
318 return kmos_flat(recipe->parameters, recipe->frames);
328static int kmos_flat_destroy(cpl_plugin *plugin)
333 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
334 recipe = (cpl_recipe *)plugin;
337 cpl_parameterlist_delete(recipe->parameters);
356static int kmos_flat(cpl_parameterlist *parlist, cpl_frameset *frameset)
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 ;
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 ;
384 int * stored_qc_slit_edge ;
385 cpl_frameset * angle_frameset ;
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 ;
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] ;
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 ;
412 double slit_edge_vec;
415 double gain, exptime, mean_data, mean_noise ;
416 int sx, nr_bad_pix, i, j, a, k, nr_cols;
419 const int * pactive = NULL;
422 if (kmos_check_and_set_groups(frameset) != CPL_ERROR_NONE) {
423 return cpl_error_get_code();
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);
440 kmos_combine_pars_load(parlist,
"kmos.kmos_flat", &cmethod, &cpos_rej,
441 &cneg_rej, &citer, &cmin, &cmax, FALSE);
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) ;
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) ;
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) ;
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) ;
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);
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) ;
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));
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));
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;
524 for (i = 0; i < next; i++) {
525 stored_qc_flat_fail[i]= 0;
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;
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);
552 for (i = 1; i <= next; i++) {
554 if (reduce_det != 0 && i != reduce_det) continue ;
557 bad_pix_mask_dark[i-1] = kmo_dfs_load_image(frameset, BADPIXEL_DARK,
562 det_lamp_off = cpl_imagelist_new();
563 frame = kmo_dfs_get_frame(frameset, FLAT_OFF);
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);
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);
583 cpl_imagelist_delete(det_lamp_off);
584 cpl_image_power(combined_noise_off[i-1], 2.0);
587 save_mode = CPL_IO_CREATE;
589 for (a = 0; a < nb_angles; a++) {
591 if (reduce_angle <= 360 && angles_array[a] != reduce_angle) continue ;
598 angle_frameset = kmos_get_angle_frameset(frameset, angles_array[a],
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) ;
608 for (i = 1; i <= next; i++) {
610 if (reduce_det != 0 && i != reduce_det) continue ;
614 sx = a * next + (i - 1);
616 det_lamp_on = cpl_imagelist_new();
617 frame = kmo_dfs_get_frame(angle_frameset, FLAT_ON);
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);
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),
634 stored_qc_flat_sat[sx] = nr_sat;
637 stored_qc_flat_sat[sx] = kmo_imagelist_get_saturated(
638 det_lamp_on, KMO_FLAT_SATURATED, KMO_FLAT_SAT_MIN);
640 cpl_propertylist_delete(main_header);
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);
649 if (kmclipm_omit_warning_one_slice > 10)
650 kmclipm_omit_warning_one_slice = FALSE;
653 cpl_image_subtract(combined_data_on, combined_data_off[i-1]);
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);
662 bad_pix_mask_flat = kmo_create_bad_pix_flat_thresh(combined_data_on,
663 surrounding_pixels, badpix_thresh);
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() ;
676 if (spec_found[sx] == CPL_ERROR_NONE) {
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) ;
691 stored_qc_flat_sn[sx] = mean_data / mean_noise;
696 cpl_image_divide_scalar(combined_data_on, mean_data);
697 cpl_image_divide_scalar(combined_noise_on, mean_data);
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) ;
706 stored_xcal[sx] = xcal;
707 stored_ycal[sx] = ycal;
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.);
719 save_mode = CPL_IO_EXTEND;
721 }
else if (spec_found[sx] == CPL_ERROR_DATA_NOT_FOUND) {
723 cpl_msg_warning(__func__,
"All IFUs deactivated - NULL image saved.") ;
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);
733 save_mode = CPL_IO_EXTEND;
735 stored_xcal[sx] = NULL ;
736 stored_ycal[sx] = NULL ;
737 stored_qc_flat_fail[i-1]++;
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() ;
754 cpl_image_delete(combined_data_on);
755 cpl_image_delete(combined_noise_on);
756 cpl_image_delete(bad_pix_mask_flat);
759 cpl_msg_indent_less() ;
761 cpl_frameset_delete(angle_frameset);
762 cpl_msg_indent_less() ;
765 cpl_msg_info(__func__,
"image saving done .") ;
773 for (i = 1; i <= next; i++) {
775 if (reduce_det != 0 && i != reduce_det) continue ;
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]);
782 cpl_msg_info(__func__,
"frame cleaning done .") ;
798 cpl_msg_info(__func__,
"coming into qc parameters.") ;
802 main_header = kmo_dfs_load_primary_header(frameset, FLAT_ON);
805 kmo_print_unused_ifus(unused_ifus_after, TRUE);
806 kmo_set_unused_ifus(unused_ifus_after, main_header,
"kmos_flat");
809 cpl_msg_info(__func__,
" creating bounds starting .") ;
811 main_header_xcal=kmos_create_bounds_properties(stored_ycal,next,nb_angles) ;
814 if (!suppress_extension) fn_suffix = cpl_sprintf(
"%s", suffix);
815 else fn_suffix = cpl_sprintf(
"%s",
"");
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);
832 cpl_propertylist_delete(main_header);
833 cpl_propertylist_delete(main_header_xcal);
835 cpl_msg_info(__func__,
" main headers read and saved .") ;
843 for (a = 0; a < nb_angles; a++) {
846 if (reduce_angle <= 360 && angles_array[a] != reduce_angle) continue ;
848 for (i = 1; i <= next; i++) {
850 if (reduce_det != 0 && i != reduce_det) continue ;
852 sx = a * next + (i - 1);
854 stored_flat[sx]=kmclipm_image_load(fn_flat, CPL_TYPE_FLOAT, 0,
858 stored_noise[sx]=kmclipm_image_load(fn_noise, CPL_TYPE_FLOAT, 0,
861 stored_badpix[sx]=kmclipm_image_load(fn_badpix,CPL_TYPE_FLOAT, 0,
866 sub_header = kmo_dfs_load_sub_header(frameset, FLAT_ON, i, FALSE);
868 kmclipm_update_property_double(sub_header,CAL_ROTANGLE,
869 ((
double) angles_array[a]),
870 "[deg] Rotator relative to nasmyth");
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");
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");
882 kmclipm_update_property_double(sub_header, QC_FLAT_SN,
883 stored_qc_flat_sn[sx],
"[] S/N of master flat");
889 if (stored_xcal[sx] != NULL) {
890 kmclipm_update_property_double(sub_header, QC_GAP_MEAN,
892 "[pix] mean gap width between slitlets");
893 kmclipm_update_property_double(sub_header, QC_GAP_SDV,
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");
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;
917 kmclipm_update_property_int(sub_header, QC_NR_BAD_PIX, nr_bad_pix,
918 "[] nr. of bad pixels");
921 pactive = cpl_array_get_data_int(unused_ifus_after[i-1]);
922 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
926 kmclipm_update_property_int(sub_header, QC_IFU_ACTIVE, active_ifus,
927 "[] nr. of active ifus");
929 kmclipm_update_property_int(sub_header, QC_FLAT_FAIL, stored_qc_flat_fail[i-1],
930 "[] rot. angles with empty extensions ");
934 cpl_vector * stored_qc_edge_mean = cpl_vector_new(KMOS_IFUS_PER_DETECTOR);
937 for (
int ref_sl_i=0; ref_sl_i<KMOS_IFUS_PER_DETECTOR; ref_sl_i++){
938 if (pactive[ref_sl_i] == 0){
944 if ((ref_sl != -1)&&(edge_table[sx] != NULL)&&(edge_table[sx][ref_sl] != NULL)){
949 while ( y < (
int)KMOS_DETECTOR_SIZE){
952 nr_cols = cpl_table_get_ncol(edge_table[sx][ref_sl])-1;
954 for (j = 0; j < nr_cols; j++) {
956 name = cpl_sprintf(
"A%d", j);
960 cpl_table_get_double(edge_table[sx][ref_sl], name, 0, NULL);
962 cpl_free(name); name = NULL;
970 cpl_vector_set(stored_qc_edge_mean, (i-1), slit_edge_vec/(k-1));
974 cpl_vector_set(stored_qc_edge_mean, (i-1), -1.0);
977 kmclipm_update_property_double(sub_header, QC_SLIT_EDGE,
978 cpl_vector_get(stored_qc_edge_mean,i-1), QC_SLIT_EDGE_DESC);
981 cpl_vector_delete(stored_qc_edge_mean);
986 extname = kmo_extname_creator(detector_frame, i, EXT_DATA);
987 kmclipm_update_property_string(sub_header, EXTNAME,extname,
988 "FITS extension name");
991 kmclipm_update_property_int(sub_header, EXTVER, sx+1,
992 "FITS extension ver");
994 if (stored_flat[sx] != NULL) {
995 kmo_dfs_save_image(stored_flat[sx], MASTER_FLAT, fn_suffix,
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,
1004 cpl_image_delete(nan_image);
1008 extname = kmo_extname_creator(detector_frame, i, EXT_NOISE);
1009 kmclipm_update_property_string(sub_header, EXTNAME,extname,
1010 "FITS extension name");
1013 if (stored_flat[sx] != NULL) {
1014 kmo_dfs_save_image(stored_noise[sx], MASTER_FLAT, fn_suffix,
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,
1023 cpl_image_delete(nan_image);
1026 cpl_propertylist_erase(sub_header, QC_IFU_ACTIVE);
1027 cpl_propertylist_erase(sub_header, QC_FLAT_FAIL);
1031 extname = kmo_extname_creator(detector_frame, i, EXT_BADPIX);
1032 kmclipm_update_property_string(sub_header, EXTNAME,extname,
1033 "FITS extension name");
1036 kmo_dfs_save_image(stored_badpix[sx], BADPIXEL_FLAT, fn_suffix,
1040 extname = kmo_extname_creator(detector_frame, i, EXT_DATA);
1041 kmclipm_update_property_string(sub_header, EXTNAME, extname,
1042 "FITS extension name");
1045 if (stored_flat[sx] != NULL) {
1046 kmo_dfs_save_image(stored_xcal[sx], XCAL, fn_suffix, sub_header,
1048 kmo_dfs_save_image(stored_ycal[sx], YCAL, fn_suffix, sub_header,
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,
1056 kmo_dfs_save_image(nan_image, YCAL, fn_suffix, sub_header,
1059 cpl_image_delete(nan_image);
1064 cpl_propertylist_erase(sub_header,
"BUNIT");
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");
1074 kmclipm_update_property_int(sub_header, CAL_IFU_NR,
1075 j+1+(i-1)*KMOS_IFUS_PER_DETECTOR,
"IFU Number {1..24}");
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);
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);
1094 kmo_dfs_save_table(NULL, FLAT_EDGE, fn_suffix,
1098 cpl_propertylist_delete(sub_header);
1100 cpl_image_delete(stored_flat[sx]);
1101 cpl_image_delete(stored_noise[sx]);
1102 cpl_image_delete(stored_badpix[sx]);
1108 kmo_free_unused_ifus(unused_ifus_after);
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]);
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]);
1139 cpl_free(edge_table[i]);
1142 cpl_free(edge_table);
1144 cpl_free(spec_found);
1145 cpl_free(angles_array) ;
1163static cpl_propertylist * kmos_create_bounds_properties(
1164 cpl_image ** stored_ycal,
1168 cpl_propertylist * bounds_props ;
1170 int ** total_bounds ;
1175 if (stored_ycal == NULL)
return NULL ;
1178 bounds_props = cpl_propertylist_new();
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;
1191 for (a = 0; a < nb_angles; a++) {
1192 for (i = 0; i < next; i++) {
1195 if (stored_ycal[sx] != NULL) {
1196 bounds = kmo_split_frame(stored_ycal[sx]);
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;
1202 if (total_bounds[i][2*j] > bounds[2*j]) {
1203 total_bounds[i][2*j] = bounds[2*j];
1207 if ((total_bounds[i][2*j+1] == -1) ||
1208 (bounds[2*j+1] == -1)) {
1209 total_bounds[i][2*j+1] = -1;
1211 if (total_bounds[i][2*j+1] < bounds[2*j+1]) {
1212 total_bounds[i][2*j+1] = bounds[2*j+1];
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;
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.");
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.");
1250 for (i = 0; i < next; i++) cpl_free(total_bounds[i]);
1251 cpl_free(total_bounds);
1253 return bounds_props ;
1267static int kmos_flat_check_inputs(
1268 cpl_frameset * frameset,
1272 double * exptime_on)
1274 const cpl_frame * frame ;
1275 cpl_propertylist * eh ;
1276 cpl_propertylist * mh1 ;
1277 cpl_propertylist * main_header ;
1280 const char * readmode ;
1281 int naxis1, naxis2, n_ext ;
1286 if (nx == NULL || ny == NULL || frameset == NULL || exptime_on == NULL)
1290 frame = kmo_dfs_get_frame(frameset, BADPIXEL_DARK);
1291 if (frame == NULL) {
1292 cpl_msg_warning(__func__,
"BADPIXEL_DARK frame is missing") ;
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") ;
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) ;
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);
1313 while (frame != NULL) {
1314 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
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);
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);
1328 if (strcmp(cpl_propertylist_get_string(main_header, READMODE),
1330 cpl_msg_warning(__func__,
"READMODE inconsistent") ;
1331 cpl_propertylist_delete(mh1);
1332 cpl_propertylist_delete(main_header);
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);
1344 cpl_propertylist_delete(main_header);
1347 frame = kmo_dfs_get_frame(frameset, NULL);
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);
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);
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);
1367 if (strcmp(cpl_propertylist_get_string(main_header, READMODE),
1369 cpl_msg_warning(__func__,
"READMODE inconsistent") ;
1370 cpl_propertylist_delete(mh1);
1371 cpl_propertylist_delete(main_header);
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);
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);
1394 frame = kmo_dfs_get_frame(frameset, NULL);
1396 cpl_propertylist_delete(main_header);
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);
1404 if (kmo_check_frameset_setup(frameset, FLAT_ON, TRUE, FALSE, FALSE) !=
1406 cpl_msg_warning(__func__,
"Filters are not consistent") ;
1414 *exptime_on = exptime ;
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.