33#include "kmclipm_priv_splines.h"
35#include "kmo_priv_reconstruct.h"
36#include "kmo_priv_functions.h"
37#include "kmo_priv_flat.h"
38#include "kmo_priv_wave_cal.h"
39#include "kmo_priv_combine.h"
40#include "kmo_functions.h"
41#include "kmo_cpl_extensions.h"
43#include "kmos_pfits.h"
45#include "kmo_constants.h"
52static int kmos_illumination_one_angle(
53 cpl_frameset * frameset,
55 const char * do_catg_used,
58 double neighborhoodRange,
67 const char * ranges_txt,
69 const char * fn_suffix,
73static int kmos_illumination_check_inputs(cpl_frameset *,
const char *,
int,
74 int *,
int *,
int *) ;
75static cpl_table ** kmos_illumination_edge_shift_correct(cpl_image *,
76 cpl_image *,
int,
const cpl_image *,
int, cpl_array *,
77 const char *,
double) ;
79static int kmos_illumination_create(cpl_plugin *);
80static int kmos_illumination_exec(cpl_plugin *);
81static int kmos_illumination_destroy(cpl_plugin *);
82static int kmos_illumination(cpl_parameterlist *, cpl_frameset *);
88static char kmos_illumination_description[] =
89"This recipe creates the spatial non-uniformity calibration frame needed for\n"
90"all three detectors. It must be called after the kmo_wave_cal-recipe, which\n"
91"generates the spectral calibration frame needed in this recipe. As input at\n"
92"least a sky or flat, a master dark, a master flat and the spatial and \n"
93"spectral calibration frames are required.\n"
94"The created product, the illumination correction, can be used as input for\n"
95"kmo_std_star and kmo_sci_red.\n"
97"---------------------------------------------------------------------------\n"
100" DO CATG Type Explanation Required #Frames\n"
101" -------- ----- ----------- -------- -------\n"
102" FLAT_SKY F2D Sky exposures Y 1-n \n"
103" (at least 3 frames recommended) \n"
104"or FLAT_ON F2D Flat exposures Y 1-n \n"
105" (at least 3 frames recommended) \n"
106" MASTER_DARK F2D Master dark Y 1 \n"
107" MASTER_FLAT F2D Master flat Y 1 \n"
108" XCAL F2D x calibration frame Y 1 \n"
109" YCAL F2D y calibration frame Y 1 \n"
110" LCAL F2D Wavelength calib. frame Y 1 \n"
111" WAVE_BAND F2L Table with start-/end-wavelengths Y 1 \n"
112" FLAT_EDGE F2L Table with fitted slitlet edges N 0,1 \n"
116" DO CATG Type Explanation\n"
117" -------- ----- -----------\n"
118" ILLUM_CORR F2I Illumination calibration frame \n"
119" If FLAT_EDGE is provided: \n"
120" SKYFLAT_EDGE F2L Frame containing parameters of fitted \n"
121" slitlets of all IFUs of all detectors\n"
122"---------------------------------------------------------------------------\n"
150 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe);
151 cpl_plugin *plugin = &recipe->interface;
153 cpl_plugin_init(plugin,
156 CPL_PLUGIN_TYPE_RECIPE,
158 "Create a frame to correct spatial non-uniformity of flatfield",
159 kmos_illumination_description,
160 "Alex Agudo Berbel, Yves Jung",
161 "https://support.eso.org/",
163 kmos_illumination_create,
164 kmos_illumination_exec,
165 kmos_illumination_destroy);
166 cpl_pluginlist_append(list, plugin);
180static int kmos_illumination_create(cpl_plugin *plugin)
186 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
187 recipe = (cpl_recipe *)plugin;
192 recipe->parameters = cpl_parameterlist_new();
196 p = cpl_parameter_new_value(
"kmos.kmos_illumination.used_flat_type",
198 "Type (sky/lamp) of input to use: (only if 2 types in input)",
199 "kmos.kmos_illumination",
"sky");
200 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"used_flat_type");
201 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
202 cpl_parameterlist_append(recipe->parameters, p);
205 p = cpl_parameter_new_value(
"kmos.kmos_illumination.imethod",
207 "Method to use for interpolation: "
208 "[\"NN\" (nearest neighbour), "
209 "\"lwNN\" (linear weighted nearest neighbor), "
210 "\"swNN\" (square weighted nearest neighbor), "
211 "\"MS\" (Modified Shepard's method), "
212 "\"CS\" (Cubic spline)]",
213 "kmos.kmos_illumination",
"CS");
214 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"imethod");
215 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
216 cpl_parameterlist_append(recipe->parameters, p);
219 p = cpl_parameter_new_value(
"kmos.kmos_illumination.neighborhoodRange",
220 CPL_TYPE_DOUBLE,
"Range (pixels) to search for neighbors",
221 "kmos.kmos_illumination", 1.001);
222 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"neighborhoodRange");
223 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
224 cpl_parameterlist_append(recipe->parameters, p);
227 p = cpl_parameter_new_value(
"kmos.kmos_illumination.range",
229 "The spectral ranges to combine when collapsing the reconstructed cubes. e.g. " "\"x1_start,x1_end;x2_start,x2_end\" (microns)",
230 "kmos.kmos_illumination",
"");
231 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"range");
232 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
233 cpl_parameterlist_append(recipe->parameters, p);
236 p = cpl_parameter_new_value(
"kmos.kmos_illumination.flux",
237 CPL_TYPE_BOOL,
"TRUE: Apply flux conservation. FALSE: otherwise",
238 "kmos.kmos_illumination", FALSE);
239 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"flux");
240 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
241 cpl_parameterlist_append(recipe->parameters, p);
244 p = cpl_parameter_new_value(
"kmos.kmos_illumination.add-all", CPL_TYPE_BOOL,
245 "FALSE: omit 1st FLAT_SKY frame (acquisition), "
246 "TRUE: don't perform any checks, add them all",
247 "kmos.kmos_illumination", FALSE);
248 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"add-all");
249 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
250 cpl_parameterlist_append(recipe->parameters, p);
253 p = cpl_parameter_new_value(
"kmos.kmos_illumination.pix_scale",
255 "Change the pixel scale [arcsec]. "
256 "Default of 0.2\" results into cubes of 14x14pix, "
257 "a scale of 0.1\" results into cubes of 28x28pix, etc.",
258 "kmos.kmos_illumination", KMOS_PIX_RESOLUTION);
259 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"pix_scale");
260 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
261 cpl_parameterlist_append(recipe->parameters, p);
264 p = cpl_parameter_new_value(
"kmos.kmos_illumination.suppress_extension",
266 "Suppress filename extension. (TRUE (apply) or FALSE (don't apply)",
267 "kmos.kmos_illumination", FALSE);
268 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"suppress_extension");
269 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
270 cpl_parameterlist_append(recipe->parameters, p);
273 kmos_band_pars_create(recipe->parameters,
"kmos.kmos_illumination");
276 kmos_combine_pars_create(recipe->parameters,
"kmos.kmos_illumination",
277 DEF_REJ_METHOD, FALSE);
280 p = cpl_parameter_new_value(
"kmos.kmos_illumination.detector",
281 CPL_TYPE_INT,
"Only reduce the specified detector",
282 "kmos.kmos_illumination", 0);
283 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"det");
284 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
285 cpl_parameterlist_append(recipe->parameters, p);
288 p = cpl_parameter_new_value(
"kmos.kmos_illumination.angle",
289 CPL_TYPE_DOUBLE,
"Only reduce the specified angle",
290 "kmos.kmos_illumination", 370.0);
291 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"angle");
292 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
293 cpl_parameterlist_append(recipe->parameters, p);
305static int kmos_illumination_exec(cpl_plugin *plugin)
310 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
311 recipe = (cpl_recipe *)plugin;
314 return kmos_illumination(recipe->parameters, recipe->frames);
324static int kmos_illumination_destroy(cpl_plugin *plugin)
329 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
330 recipe = (cpl_recipe *)plugin;
333 cpl_parameterlist_delete(recipe->parameters);
351static int kmos_illumination(
352 cpl_parameterlist * parlist,
353 cpl_frameset * frameset)
355 const cpl_parameter * par ;
356 const char * method ;
357 const char * used_flat_type ;
358 const char * cmethod ;
359 const char * cmethod_loc ;
360 const char * ranges_txt ;
361 int flux, add_all_sky, cmax, cmin, citer,
362 suppress_extension, reduce_det,
364 double neighborhoodRange, pix_scale, cpos_rej, cneg_rej,
366 int nb_raw_sky, nb_raw_lamp ;
367 const char * do_catg_used ;
370 cpl_frameset * angle_frameset ;
374 cpl_propertylist * main_header ;
377 if (kmos_check_and_set_groups(frameset) != CPL_ERROR_NONE) {
378 return cpl_error_get_code();
382 par = cpl_parameterlist_find_const(parlist,
383 "kmos.kmos_illumination.used_flat_type") ;
384 used_flat_type = cpl_parameter_get_string(par);
385 par = cpl_parameterlist_find_const(parlist,
386 "kmos.kmos_illumination.imethod") ;
387 method = cpl_parameter_get_string(par);
388 par = cpl_parameterlist_find_const(parlist,
389 "kmos.kmos_illumination.neighborhoodRange");
390 neighborhoodRange = cpl_parameter_get_double(par) ;
391 par = cpl_parameterlist_find_const(parlist,
"kmos.kmos_illumination.range");
392 ranges_txt = cpl_parameter_get_string(par) ;
393 par = cpl_parameterlist_find_const(parlist,
"kmos.kmos_illumination.flux");
394 flux = cpl_parameter_get_bool(par);
395 par = cpl_parameterlist_find_const(parlist,
396 "kmos.kmos_illumination.add-all");
397 add_all_sky = cpl_parameter_get_bool(par) ;
398 par = cpl_parameterlist_find_const(parlist,
399 "kmos.kmos_illumination.pix_scale");
400 pix_scale = cpl_parameter_get_double(par) ;
401 par = cpl_parameterlist_find_const(parlist,
402 "kmos.kmos_illumination.suppress_extension");
403 suppress_extension = cpl_parameter_get_bool(par) ;
404 par = cpl_parameterlist_find_const(parlist,
405 "kmos.kmos_illumination.detector");
406 reduce_det = cpl_parameter_get_int(par);
407 par = cpl_parameterlist_find_const(parlist,
"kmos.kmos_illumination.angle");
408 reduce_angle = cpl_parameter_get_double(par);
410 kmos_band_pars_load(parlist,
"kmos.kmos_illumination");
411 kmos_combine_pars_load(parlist,
"kmos.kmos_illumination", &cmethod,
412 &cpos_rej, &cneg_rej, &citer, &cmin, &cmax, FALSE);
415 if (strcmp(used_flat_type,
"sky") && strcmp(used_flat_type,
"lamp")) {
416 cpl_msg_error(__func__,
"used_flat_type must be \"lamp\" or \"sky\"") ;
417 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
420 if (strcmp(method,
"NN") && strcmp(method,
"lwNN") && strcmp(method,
"swNN")
421 && strcmp(method,
"MS") && strcmp(method,
"CS")) {
422 cpl_msg_error(__func__,
423 "method must be \"NN\", \"lwNN\", \"swNN\", \"MS\" or \"CS\"") ;
424 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
427 if (neighborhoodRange <= 0.0) {
428 cpl_msg_error(__func__,
"neighborhoodRange must be > 0") ;
429 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
432 if (pix_scale < 0.01 || pix_scale > 0.4) {
433 cpl_msg_error(__func__,
434 "pix_scale must be in [0.01,0.4] -> 7x7 to 280x280 pixels") ;
435 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
438 if (reduce_det < 0 || reduce_det > 3) {
439 cpl_msg_error(__func__,
"detector must be in [1,3]") ;
440 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
444 has_flat_edge = cpl_frameset_count_tags(frameset, FLAT_EDGE);
447 nb_raw_sky = cpl_frameset_count_tags(frameset, FLAT_SKY);
448 nb_raw_lamp = cpl_frameset_count_tags(frameset, FLAT_ON);
449 if (nb_raw_sky == 0 && nb_raw_lamp == 0) {
450 cpl_msg_error(__func__,
"Input frameset has no RAW frame") ;
451 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
454 if (nb_raw_sky == 0 && nb_raw_lamp > 0) {
455 do_catg_used = FLAT_ON ;
457 if (nb_raw_sky > 0 && nb_raw_lamp == 0) {
458 do_catg_used = FLAT_SKY ;
460 if (nb_raw_sky > 0 && nb_raw_lamp > 0) {
461 if (!strcmp(used_flat_type,
"sky")) {
462 do_catg_used = FLAT_SKY ;
464 do_catg_used = FLAT_ON ;
467 cpl_msg_info(__func__,
"Use %s RAW frames", do_catg_used) ;
470 if ((angles_array = kmos_get_angles(frameset, &nb_angles,
471 do_catg_used)) == NULL) {
472 cpl_msg_error(__func__,
"Cannot get Angles informations") ;
473 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
478 suffix = kmo_dfs_get_suffix(kmo_dfs_get_frame(frameset, XCAL), TRUE, FALSE);
479 cpl_msg_info(__func__,
"Detected instrument setup: %s", suffix+1);
482 main_header = kmo_dfs_load_primary_header(frameset, do_catg_used);
483 frame = kmo_dfs_get_frame(frameset, do_catg_used);
486 if (!suppress_extension) fn_suffix = cpl_sprintf(
"%s", suffix);
487 else fn_suffix = cpl_sprintf(
"%s",
"");
490 kmo_dfs_save_main_header(frameset, ILLUM_CORR, fn_suffix, frame,
491 main_header, parlist, cpl_func);
493 kmo_dfs_save_main_header(frameset, SKYFLAT_EDGE, fn_suffix, frame,
494 main_header, parlist, cpl_func);
496 cpl_propertylist_delete(main_header) ;
499 for (a = 0; a < nb_angles; a++) {
501 if (reduce_angle <= 360 && angles_array[a] != reduce_angle) continue ;
503 cpl_msg_info(__func__,
"Processing rotator angle %d -> %d degree",
505 cpl_msg_indent_more() ;
508 angle_frameset = kmos_purge_wrong_angles_frameset(frameset,
509 angles_array[a], do_catg_used);
510 if (angle_frameset == NULL) {
511 cpl_msg_error(__func__,
"Cannot get angle frameset") ;
512 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
513 cpl_free(angles_array) ;
514 cpl_free(fn_suffix) ;
516 cpl_msg_indent_less() ;
521 if (cpl_frameset_count_tags(angle_frameset, do_catg_used) == 1) {
522 cpl_msg_warning(cpl_func,
523 "1 input FLAT -> cmethod changed to average");
524 cmethod_loc =
"average";
526 cmethod_loc = cmethod ;
530 if (kmos_illumination_one_angle(angle_frameset, angles_array[a],
531 do_catg_used, reduce_det, pix_scale, neighborhoodRange, method,
532 cmethod_loc, cpos_rej, cneg_rej, citer, cmin, cmax,
533 flux, ranges_txt, suffix, fn_suffix, has_flat_edge,
535 cpl_msg_error(__func__,
"Failed Computation") ;
536 cpl_frameset_delete(angle_frameset) ;
538 cpl_free(fn_suffix) ;
539 cpl_free(angles_array) ;
540 cpl_msg_indent_less() ;
543 cpl_frameset_delete(angle_frameset) ;
544 cpl_msg_indent_less() ;
546 cpl_free(angles_array);
547 cpl_free(fn_suffix) ;
554static int kmos_illumination_one_angle(
555 cpl_frameset * frameset,
557 const char * do_catg_used,
560 double neighborhoodRange,
562 const char * cmethod,
569 const char * ranges_txt,
571 const char * fn_suffix,
575 cpl_array ** unused_ifus ;
576 const int * punused_ifus ;
577 cpl_frameset * frameset_raw ;
579 cpl_propertylist * main_header ;
584 cpl_propertylist * tmp_header ;
586 cpl_array * calTimestamp ;
587 cpl_imagelist ** stored_data_cubes ;
588 cpl_imagelist ** stored_noise_cubes ;
589 cpl_image ** stored_data_images ;
590 cpl_image ** stored_noise_images ;
591 cpl_propertylist ** stored_sub_data_headers ;
592 cpl_propertylist ** stored_sub_noise_headers ;
593 cpl_table *** edge_table_sky = NULL;
594 cpl_vector * calAngles ;
595 cpl_imagelist * detector_in ;
597 cpl_image * combined_data ;
598 cpl_image * combined_noise ;
602 cpl_image * bad_pix_mask ;
603 float * pbad_pix_mask ;
604 cpl_image * img_dark ;
605 cpl_image * img_dark_noise ;
606 cpl_image * img_flat ;
607 cpl_image * img_flat_noise ;
608 cpl_table * band_table ;
609 cpl_propertylist * sub_header ;
611 cpl_vector * identified_slices = NULL;
612 cpl_image * tmp_img ;
614 float * pnoise = NULL;
615 cpl_vector * ranges ;
616 cpl_imagelist * cube_data ;
617 cpl_imagelist * cube_noise ;
618 double ifu_crpix, ifu_crval, ifu_cdelt, mean_data,
619 qc_spat_unif, qc_max_dev, qc_max_nonunif,
620 tmp_stdev, tmp_mean, rotangle_found,
622 int next, nx, ny, process_noise, det_nr, cnt,
623 x, y, i, j, ifu_nr, qc_max_dev_id,
624 qc_max_nonunif_id, ix, iy, xmin, xmax, ymin,
625 ymax, nbdarks, nbflats ;
628 if (kmos_illumination_check_inputs(frameset, do_catg_used, add_all_sky,
629 &next, &nx, &ny) != 1) {
630 cpl_msg_error(__func__,
"Input frameset is not consistent") ;
631 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
636 unused_ifus = kmo_get_unused_ifus(frameset, 0, 0);
637 kmo_print_unused_ifus(unused_ifus, FALSE);
640 if (cpl_frameset_count_tags(frameset, do_catg_used) >= 2 &&
641 !strcmp(do_catg_used, FLAT_SKY)) process_noise = 1 ;
642 else process_noise = 0 ;
645 frameset_raw = cpl_frameset_new();
646 frame = kmo_dfs_get_frame(frameset, do_catg_used);
647 if (!add_all_sky && !strcmp(do_catg_used, FLAT_SKY)) {
649 cpl_msg_info(__func__,
"Use all FLAT_SKY frames but the first");
650 frame = kmo_dfs_get_frame(frameset, NULL);
652 while (frame != NULL) {
653 cpl_frameset_insert(frameset_raw, cpl_frame_duplicate(frame));
654 frame = kmo_dfs_get_frame(frameset, NULL);
658 frame = kmo_dfs_get_frame(frameset_raw, do_catg_used);
660 kmo_free_unused_ifus(unused_ifus);
661 cpl_frameset_delete(frameset_raw) ;
662 cpl_msg_error(__func__,
"Missing RAW in input") ;
663 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
667 main_header = kmo_dfs_load_primary_header(frameset_raw, do_catg_used);
670 if (!strcmp(ranges_txt,
"")) {
671 keyword = cpl_sprintf(
"%s%d%s", IFU_GRATID_PREFIX,1,IFU_GRATID_POSTFIX);
672 filter = cpl_sprintf(
"%s",
673 cpl_propertylist_get_string(main_header,keyword));
675 if (!strcmp(filter,
"IZ")) ranges_txt =
"0.81,1.05";
676 else if (!strcmp(filter,
"YJ")) ranges_txt =
"1.025,1.3";
677 else if (!strcmp(filter,
"H")) ranges_txt =
"1.5,1.7";
678 else if (!strcmp(filter,
"K")) ranges_txt =
"2.1,2.35";
679 else if (!strcmp(filter,
"HK")) ranges_txt =
"1.5,1.7;2.1,2.35";
681 cpl_msg_error(__func__,
"Filter %s not supported", filter) ;
682 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
683 kmo_free_unused_ifus(unused_ifus);
684 cpl_frameset_delete(frameset_raw) ;
685 cpl_propertylist_delete(main_header);
691 cpl_msg_info(__func__,
"Spectral range to collapse: %s um", ranges_txt);
694 kmclipm_setup_grid(&gd, method, neighborhoodRange, pix_scale, 0.);
697 fn_lut = cpl_sprintf(
"%s%s",
"lut", suffix);
700 tmp_header = kmo_dfs_load_primary_header(frameset, XCAL);
701 bounds = kmclipm_extract_bounds(tmp_header);
702 cpl_propertylist_delete(tmp_header);
705 calTimestamp = kmo_get_timestamps(
706 kmo_dfs_get_frame(frameset, XCAL),
707 kmo_dfs_get_frame(frameset, YCAL),
708 kmo_dfs_get_frame(frameset, LCAL)) ;
711 stored_data_cubes=(cpl_imagelist**)cpl_calloc(next*KMOS_IFUS_PER_DETECTOR,
712 sizeof(cpl_imagelist*));
713 stored_noise_cubes=(cpl_imagelist**)cpl_calloc(next*KMOS_IFUS_PER_DETECTOR,
714 sizeof(cpl_imagelist*));
715 stored_data_images = (cpl_image**)cpl_calloc(next*KMOS_IFUS_PER_DETECTOR,
717 stored_noise_images = (cpl_image**)cpl_calloc(next*KMOS_IFUS_PER_DETECTOR,
719 stored_sub_data_headers = (cpl_propertylist**)cpl_calloc(
720 next*KMOS_IFUS_PER_DETECTOR,
sizeof(cpl_propertylist*));
721 stored_sub_noise_headers = (cpl_propertylist**)cpl_calloc(
722 next*KMOS_IFUS_PER_DETECTOR,
sizeof(cpl_propertylist*));
723 if (has_flat_edge) edge_table_sky = (cpl_table***)cpl_calloc(
724 KMOS_NR_DETECTORS,
sizeof(cpl_table**));
725 calAngles = cpl_vector_new(3);
727 for (det_nr = 1; det_nr <= next; det_nr++) {
729 edge_table_sky[det_nr-1] = NULL;
730 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
731 ifu_nr = (det_nr-1)*KMOS_IFUS_PER_DETECTOR + j ;
732 stored_data_cubes[ifu_nr] = NULL ;
733 stored_noise_cubes[ifu_nr] = NULL ;
734 stored_data_images[ifu_nr] = NULL ;
735 stored_noise_images[ifu_nr] = NULL ;
736 stored_sub_data_headers[ifu_nr] = NULL ;
737 stored_sub_noise_headers[ifu_nr] = NULL ;
741 cpl_bivector * skystats = cpl_bivector_new(next * cpl_frameset_count_tags(frameset_raw, do_catg_used));
742 cpl_vector * skymed = cpl_bivector_get_x(skystats);
743 cpl_vector * skystd = cpl_bivector_get_y(skystats);
746 for (det_nr = 1; det_nr <= next; det_nr++) {
749 if (reduce_det != 0 && det_nr != reduce_det) continue ;
751 cpl_msg_info(__func__,
"Processing detector No. %d", det_nr);
752 cpl_msg_indent_more() ;
754 detector_in = cpl_imagelist_new();
756 img_in = kmo_dfs_load_image(frameset_raw, do_catg_used, det_nr, FALSE,
759 while (img_in != NULL) {
761 cpl_imagelist_set(detector_in, img_in, cnt);
762 if (!strcmp(do_catg_used, FLAT_SKY))
764 skystatstemp = cpl_image_get_median(img_in);
765 cpl_vector_set(skymed, cnt + (det_nr - 1) * cnt_max, skystatstemp);
766 skystatstemp = cpl_image_get_stdev(img_in);
767 cpl_vector_set(skystd, cnt + (det_nr - 1) * cnt_max, skystatstemp);
771 img_in = kmo_dfs_load_image(frameset_raw, NULL, det_nr, FALSE,
774 if (cnt > cnt_max) cnt_max = cnt;
778 cpl_msg_info(__func__,
"Combining frames");
779 combined_data = combined_noise = NULL ;
781 kmos_combine_frames(detector_in, cmethod, cpos_rej, cneg_rej,
782 citer, cmax, cmin, &combined_data, &combined_noise, -1.0);
784 kmos_combine_frames(detector_in, cmethod, cpos_rej, cneg_rej,
785 citer, cmax, cmin, &combined_data, NULL, -1.0);
787 cpl_imagelist_delete(detector_in);
790 if (cpl_error_get_code() != CPL_ERROR_NONE) {
791 kmo_free_unused_ifus(unused_ifus);
792 cpl_frameset_delete(frameset_raw) ;
793 cpl_propertylist_delete(main_header);
796 cpl_array_delete(calTimestamp);
797 cpl_free(stored_data_cubes);
798 cpl_free(stored_noise_cubes);
799 cpl_free(stored_data_images);
800 cpl_free(stored_noise_images);
801 cpl_free(stored_sub_data_headers);
802 cpl_free(stored_sub_noise_headers);
803 if (edge_table_sky) cpl_free(edge_table_sky) ;
804 cpl_vector_delete(calAngles) ;
805 cpl_msg_error(__func__,
"Combination failed") ;
806 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
807 cpl_msg_indent_less() ;
811 if (kmclipm_omit_warning_one_slice > 10)
812 kmclipm_omit_warning_one_slice = FALSE;
815 xcal = kmo_dfs_load_cal_image(frameset, XCAL, det_nr, FALSE, rotangle,
816 FALSE, NULL, &rotangle_found, -1, 0, 0);
817 cpl_vector_set(calAngles, 0, rotangle_found);
818 ycal = kmo_dfs_load_cal_image(frameset, YCAL, det_nr, FALSE, rotangle,
819 FALSE, NULL, &rotangle_found, -1, 0, 0);
820 cpl_vector_set(calAngles, 1, rotangle_found);
821 lcal = kmo_dfs_load_cal_image(frameset, LCAL, det_nr, FALSE, rotangle,
822 FALSE, NULL, &rotangle_found, -1, 0, 0);
823 cpl_vector_set(calAngles, 2, rotangle_found);
826 bad_pix_mask = cpl_image_duplicate(xcal);
827 pbad_pix_mask = cpl_image_get_data_float(bad_pix_mask);
828 for (x = 0; x < nx; x++) {
829 for (y = 0; y < ny; y++) {
830 if (isnan(pbad_pix_mask[x+nx*y])) {
831 pbad_pix_mask[x+nx*y] = 0.;
833 pbad_pix_mask[x+nx*y] = 1.;
840 edge_table_sky[det_nr-1] = kmos_illumination_edge_shift_correct(
841 combined_data, combined_noise, process_noise, bad_pix_mask,
842 det_nr, unused_ifus[det_nr-1],
843 cpl_frame_get_filename(kmo_dfs_get_frame(frameset,
844 FLAT_EDGE)), rotangle);
845 if (edge_table_sky[det_nr-1] == NULL) {
846 kmo_free_unused_ifus(unused_ifus);
847 cpl_frameset_delete(frameset_raw) ;
848 cpl_propertylist_delete(main_header);
851 cpl_array_delete(calTimestamp);
852 cpl_free(stored_data_cubes);
853 cpl_free(stored_noise_cubes);
854 cpl_free(stored_data_images);
855 cpl_free(stored_noise_images);
856 cpl_free(stored_sub_data_headers);
857 cpl_free(stored_sub_noise_headers);
858 if (has_flat_edge) cpl_free(edge_table_sky) ;
859 cpl_vector_delete(calAngles) ;
860 cpl_image_delete(xcal);
861 cpl_image_delete(ycal);
862 cpl_image_delete(lcal);
863 cpl_image_delete(bad_pix_mask);
864 cpl_image_delete(combined_data);
865 if (process_noise) cpl_image_delete(combined_noise);
866 cpl_msg_error(__func__,
"Edge Shift Correction failed") ;
867 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
868 cpl_msg_indent_less() ;
876 nbdarks = cpl_frameset_count_tags(frameset, MASTER_DARK) ;
878 img_dark = kmo_dfs_load_image(frameset, MASTER_DARK, det_nr, FALSE,
881 img_dark_noise = kmo_dfs_load_image(frameset, MASTER_DARK,
882 det_nr, TRUE, FALSE, NULL);
884 img_dark_noise = NULL ;
887 img_dark = cpl_image_duplicate(combined_data);
888 cpl_image_multiply_scalar(img_dark, 0);
889 img_dark_noise = NULL ;
893 nbflats = cpl_frameset_count_tags(frameset, MASTER_FLAT) ;
895 img_flat = kmo_dfs_load_cal_image(frameset, MASTER_FLAT, det_nr,
896 FALSE, rotangle, FALSE, NULL, &rotangle_found, -1, 0, 0);
898 img_flat_noise = kmo_dfs_load_cal_image(frameset, MASTER_FLAT,
899 det_nr, TRUE, rotangle, FALSE, NULL, &rotangle_found,
902 img_flat_noise = NULL ;
905 img_flat = cpl_image_duplicate(combined_data);
906 cpl_image_multiply_scalar(img_flat, 0);
907 cpl_image_add_scalar(img_flat, 1);
908 img_flat_noise = NULL ;
912 keyword = cpl_sprintf(
"%s%d%s", IFU_FILTID_PREFIX, det_nr,
914 band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, 0);
915 kmclipm_setup_grid_band_lcal(&gd,
916 cpl_propertylist_get_string(main_header, keyword), band_table);
918 cpl_table_delete(band_table);
920 cpl_msg_info(__func__,
"Reconstructing cubes");
921 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
923 ifu_nr = (det_nr-1)*KMOS_IFUS_PER_DETECTOR + j + 1;
926 sub_header = kmo_dfs_load_sub_header(frameset_raw, do_catg_used,
929 punused_ifus = cpl_array_get_data_int_const(unused_ifus[det_nr-1]);
932 keyword = cpl_sprintf(
"%s%d%s", IFU_VALID_PREFIX, ifu_nr,
934 cpl_propertylist_get_string(main_header, keyword);
936 if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) &&
937 (bounds[2*(ifu_nr-1)] != -1) &&
938 (bounds[2*(ifu_nr-1)+1] != -1) && (punused_ifus[j] == 0)) {
943 kmo_calc_wcs_gd(main_header, sub_header, ifu_nr, gd);
947 kmo_reconstruct_sci_image(ifu_nr, bounds[2*(ifu_nr-1)],
948 bounds[2*(ifu_nr-1)+1], combined_data, combined_noise,
949 img_dark, img_dark_noise, img_flat, img_flat_noise,
950 xcal, ycal, lcal, &gd, calTimestamp, calAngles,
951 fn_lut, &cube_data, &cube_noise, flux, 0,
959 extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_DATA);
961 kmclipm_update_property_string(sub_header, EXTNAME, extname,
962 "FITS extension name");
966 stored_data_cubes[ifu_nr - 1] = cube_data;
967 stored_sub_data_headers[ifu_nr - 1] = sub_header;
970 sub_header=cpl_propertylist_duplicate(
971 stored_sub_data_headers[ifu_nr - 1]);
972 extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_NOISE);
973 kmclipm_update_property_string(sub_header, EXTNAME, extname,
974 "FITS extension name");
977 stored_noise_cubes[ifu_nr - 1] = cube_noise;
978 stored_sub_noise_headers[ifu_nr - 1] = sub_header;
985 cpl_image_delete(xcal);
986 cpl_image_delete(ycal);
987 cpl_image_delete(lcal);
988 cpl_image_delete(combined_data);
989 cpl_image_delete(bad_pix_mask);
990 cpl_image_delete(img_dark);
991 cpl_image_delete(img_flat);
993 cpl_image_delete(combined_noise);
994 cpl_image_delete(img_dark_noise);
995 cpl_image_delete(img_flat_noise);
997 cpl_msg_indent_less() ;
999 cpl_vector_delete(calAngles) ;
1002 cpl_array_delete(calTimestamp);
1004 ranges = kmo_identify_ranges(ranges_txt);
1007 cpl_msg_info(__func__,
"Collapse cubes");
1008 for (det_nr = 1; det_nr <= next; det_nr++) {
1011 if (reduce_det != 0 && det_nr != reduce_det) continue ;
1013 cpl_msg_info(__func__,
"Processing detector No. %d", det_nr);
1014 cpl_msg_indent_more() ;
1016 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
1017 ifu_nr = (det_nr-1)*KMOS_IFUS_PER_DETECTOR + j + 1;
1019 punused_ifus=cpl_array_get_data_int_const(unused_ifus[det_nr-1]);
1020 if (punused_ifus[j] == 0) {
1021 if (stored_sub_data_headers[ifu_nr-1] != NULL) {
1023 ifu_crpix = cpl_propertylist_get_double(
1024 stored_sub_data_headers[ifu_nr-1], CRPIX3);
1025 ifu_crval = cpl_propertylist_get_double(
1026 stored_sub_data_headers[ifu_nr-1], CRVAL3);
1027 ifu_cdelt = cpl_propertylist_get_double(
1028 stored_sub_data_headers[ifu_nr-1], CDELT3);
1029 identified_slices = kmo_identify_slices(ranges, ifu_crpix,
1030 ifu_crval, ifu_cdelt, gd.l.dim);
1033 if (stored_data_cubes[ifu_nr-1] != NULL) {
1034 kmclipm_make_image(stored_data_cubes[ifu_nr-1],
1035 stored_noise_cubes[ifu_nr-1],
1036 &stored_data_images[ifu_nr-1],
1037 &stored_noise_images[ifu_nr-1], identified_slices,
1038 cmethod, cpos_rej, cneg_rej, citer, cmax, cmin);
1043 if (ifu_nr == 1 && cpl_msg_get_level() == CPL_MSG_DEBUG) {
1044 cpl_msg_debug(__func__,
"Save IFU 1 collapsed image") ;
1045 cpl_image_save(stored_data_images[ifu_nr-1],
1046 "debug_collapsed_ifu1.fits", CPL_TYPE_DOUBLE, NULL,
1053 if (!strcmp(do_catg_used, FLAT_ON)) {
1054 nx = cpl_image_get_size_x(stored_data_images[ifu_nr-1]) ;
1055 ny = cpl_image_get_size_x(stored_data_images[ifu_nr-1]) ;
1056 int firstx = 0, lastx = 0, firsty = 0, lasty = 0 ;
1057 if (ifu_nr <= 2*KMOS_IFUS_PER_DETECTOR) {
1069 tmp_img = cpl_image_duplicate(stored_data_images[ifu_nr-1]);
1070 pdata = cpl_image_get_data_float(tmp_img);
1072 cpl_image_get_data_float(stored_noise_images[ifu_nr-1]);
1076 for (ix = 0; ix < nx; ix++) {
1077 for (iy = 0; iy < ny; iy++) {
1078 if (ix-mhalf > firstx) xmin = ix-mhalf;
1080 if (ix+mhalf < lastx) xmax = ix+mhalf;
1082 if (iy-mhalf > firsty) ymin = iy-mhalf;
1084 if (iy+mhalf < lasty) ymax = iy+mhalf;
1086 pdata[ix+nx*iy] = cpl_image_get_median_window(
1087 stored_data_images[ifu_nr-1],xmin+1,ymin+1,
1089 if (stored_noise_images[ifu_nr-1] != NULL) {
1090 pnoise[ix+nx*iy]/=(xmax-xmin+1)*(ymax-ymin+1);
1096 cpl_image_delete(stored_data_images[ifu_nr-1]);
1097 stored_data_images[ifu_nr-1] = tmp_img;
1099 if(identified_slices) cpl_vector_delete(identified_slices);
1104 cpl_msg_indent_less() ;
1107 cpl_vector_delete(ranges);
1108 for (i = 0; i < next * KMOS_IFUS_PER_DETECTOR; i++) {
1109 if (stored_data_cubes != NULL) {
1110 cpl_imagelist_delete(stored_data_cubes[i]);
1112 if (stored_noise_cubes != NULL) {
1113 cpl_imagelist_delete(stored_noise_cubes[i]);
1116 cpl_free(stored_data_cubes);
1117 cpl_free(stored_noise_cubes);
1123 for (j = 0; j < next; j++) {
1125 if (reduce_det != 0 && j+1 != reduce_det) continue ;
1128 for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++) {
1129 ifu_nr = j*KMOS_IFUS_PER_DETECTOR + i;
1130 if (stored_data_images[ifu_nr] != NULL) {
1131 if (cpl_image_count_rejected(stored_data_images[ifu_nr]) >=
1132 cpl_image_get_size_x(stored_data_images[ifu_nr])*
1133 cpl_image_get_size_y(stored_data_images[ifu_nr])) {
1135 cpl_msg_error(__func__,
1136 "The collapsed, dark-subtracted image contains "
1137 "only invalid values! Probably the provided "
1138 "RAW frames are exactly the same as the "
1139 "frames used for MASTER_DARK calculation.");
1140 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
1142 if (stored_sub_data_headers) {
1143 for (
int k = 0; k < next * KMOS_IFUS_PER_DETECTOR; k++) {
1144 if (stored_sub_data_headers[k]) {
1145 cpl_propertylist_delete(stored_sub_data_headers[k]);
1148 cpl_free(stored_sub_data_headers);
1151 if (stored_sub_noise_headers) {
1152 for (
int k = 0; k < next * KMOS_IFUS_PER_DETECTOR; k++) {
1153 if (stored_sub_noise_headers[k]) {
1154 cpl_propertylist_delete(stored_sub_noise_headers[k]);
1157 cpl_free(stored_sub_noise_headers);
1162 mean_data += cpl_image_get_mean(stored_data_images[ifu_nr]);
1168 if (mean_data != 0.0) {
1169 for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++) {
1170 ifu_nr = j*KMOS_IFUS_PER_DETECTOR + i;
1171 if (stored_data_images[ifu_nr] != NULL) {
1172 cpl_image_divide_scalar(stored_data_images[ifu_nr],
1177 cpl_msg_warning(__func__,
"Data cannot be normalised (mean=0.0)");
1180 if (process_noise) {
1181 if (mean_data != 0.0) {
1182 for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++) {
1183 ifu_nr = j*KMOS_IFUS_PER_DETECTOR + i;
1184 if (stored_noise_images[ifu_nr] != NULL) {
1185 cpl_image_divide_scalar(stored_noise_images[ifu_nr],
1190 cpl_msg_warning(__func__,
"Noise cant be normalised (mean=0)");
1196 if (!strcmp(do_catg_used, FLAT_ON)) {
1197 for (j = 0; j < next; j++) {
1199 if (reduce_det != 0 && j+1 != reduce_det) continue ;
1200 for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++) {
1201 ifu_nr = j*KMOS_IFUS_PER_DETECTOR + i;
1202 if (stored_data_images[ifu_nr] != NULL) {
1204 pdata=cpl_image_get_data_float(stored_data_images[ifu_nr]);
1205 if (stored_noise_images[ifu_nr] != NULL) {
1206 pnoise=cpl_image_get_data_float(
1207 stored_noise_images[ifu_nr]);
1209 for (ix = 0; ix < nx; ix++) {
1210 for (iy = 0; iy < ny; iy++) {
1211 old_val = pdata[ix+nx*iy];
1212 pdata[ix+nx*iy] = 1. / pdata[ix+nx*iy];
1213 if (stored_noise_images[ifu_nr] != NULL) {
1214 new_val = pdata[ix+nx*iy];
1216 pnoise[ix+nx*iy] = sqrt(pow(new_val, 2) *
1217 pow(pnoise[ix+nx*iy],2)/pow(old_val,2));
1228 qc_spat_unif = qc_max_nonunif = qc_max_dev = 0.0;
1229 qc_max_nonunif_id = qc_max_dev_id = 0 ;
1232 for (i = 0; i < next * KMOS_IFUS_PER_DETECTOR; i++) {
1233 if (stored_data_images[i] != NULL) {
1234 tmp_mean = cpl_image_get_mean(stored_data_images[i]);
1235 tmp_stdev = cpl_image_get_stdev (stored_data_images[i]);
1237 qc_spat_unif += pow(tmp_mean-1, 2);
1238 if (fabs(tmp_mean) > qc_max_dev) {
1239 qc_max_dev = tmp_mean-1;
1240 qc_max_dev_id = i+1;
1242 if (fabs(tmp_stdev) > qc_max_nonunif) {
1243 qc_max_nonunif = tmp_stdev;
1244 qc_max_nonunif_id = i+1;
1249 qc_spat_unif = sqrt(qc_spat_unif / cnt);
1252 kmo_print_unused_ifus(unused_ifus, TRUE);
1253 kmo_set_unused_ifus(unused_ifus, main_header,
"kmos_illumination");
1254 kmo_free_unused_ifus(unused_ifus);
1255 cpl_propertylist_delete(main_header);
1257 cpl_msg_info(__func__,
"Save data");
1258 for (i = 0; i < next * KMOS_IFUS_PER_DETECTOR; i++) {
1259 if (stored_sub_data_headers[i] != NULL) {
1261 kmclipm_update_property_double(stored_sub_data_headers[i],
1262 CAL_ROTANGLE, ((
double)rotangle),
1263 "[deg] Rotator relative to nasmyth");
1266 kmclipm_update_property_double(stored_sub_data_headers[i],
1267 QC_SPAT_UNIF, qc_spat_unif,
1268 "[adu] uniformity of illumination correction");
1269 kmclipm_update_property_double(stored_sub_data_headers[i],
1270 QC_SPAT_MAX_DEV, qc_max_dev,
1271 "[adu] max. deviation from unity");
1272 kmclipm_update_property_int(stored_sub_data_headers[i],
1273 QC_SPAT_MAX_DEV_ID, qc_max_dev_id,
1274 "[] IFU ID with max. dev. from unity");
1275 kmclipm_update_property_double(stored_sub_data_headers[i],
1276 QC_SPAT_MAX_NONUNIF, qc_max_nonunif,
1277 "[adu] max. stdev of illumination corr.");
1278 kmclipm_update_property_int(stored_sub_data_headers[i],
1279 QC_SPAT_MAX_NONUNIF_ID, qc_max_nonunif_id,
1280 "[] IFU ID with max. stdev in illum. corr.");
1281 if (!strcmp(do_catg_used, FLAT_SKY))
1283 cpl_size nsky = cpl_bivector_get_size(skystats) / next;
1284 for (cpl_size sky_nr = 0; sky_nr < nsky; sky_nr++)
1286 keyword = cpl_sprintf(
"%s%lld %s%s", QC_SKYFLAT_PREFIX, sky_nr + 1,
1287 QC_SKYFLAT_INFIX, QC_MED_SUFFIX);
1288 kmclipm_update_property_double(
1289 stored_sub_data_headers[i],
1290 keyword, cpl_vector_get(skymed, sky_nr + (i / KMOS_IFUS_PER_DETECTOR) * nsky),
1293 keyword = cpl_sprintf(
"%s%lld %s%s", QC_SKYFLAT_PREFIX, sky_nr + 1,
1294 QC_SKYFLAT_INFIX, QC_RMS_SUFFIX);
1295 kmclipm_update_property_double(
1296 stored_sub_data_headers[i],
1297 keyword, cpl_vector_get(skystd, sky_nr + (i / KMOS_IFUS_PER_DETECTOR) * nsky),
1305 kmclipm_update_property_int(stored_sub_data_headers[i], EXTVER, 2*(i+1),
1306 "FITS extension ver");
1308 cpl_propertylist_erase(stored_sub_data_headers[i], CDELT1);
1309 cpl_propertylist_erase(stored_sub_data_headers[i], CDELT2);
1310 cpl_propertylist_erase(stored_sub_data_headers[i], CDELT3);
1311 cpl_propertylist_erase(stored_sub_data_headers[i], CRVAL3);
1312 cpl_propertylist_erase(stored_sub_data_headers[i], CRPIX3);
1313 cpl_propertylist_erase(stored_sub_data_headers[i], CTYPE3);
1315 if (stored_data_images[i]==NULL) {
1316 cpl_propertylist_erase(stored_sub_data_headers[i], CTYPE1);
1317 cpl_propertylist_erase(stored_sub_data_headers[i], CTYPE2);
1318 cpl_propertylist_erase(stored_sub_data_headers[i], CRPIX1);
1319 cpl_propertylist_erase(stored_sub_data_headers[i], CRPIX2);
1320 cpl_propertylist_erase(stored_sub_data_headers[i], CRVAL1);
1321 cpl_propertylist_erase(stored_sub_data_headers[i], CRVAL2);
1322 cpl_propertylist_erase(stored_sub_data_headers[i], CD1_1);
1323 cpl_propertylist_erase(stored_sub_data_headers[i], CD2_1);
1324 cpl_propertylist_erase(stored_sub_data_headers[i], CD1_2);
1325 cpl_propertylist_erase(stored_sub_data_headers[i], CD2_2);
1328 kmo_dfs_save_image(stored_data_images[i], ILLUM_CORR, fn_suffix,
1329 stored_sub_data_headers[i], 0./0.);
1330 if (process_noise) {
1331 if (stored_sub_noise_headers[i] != NULL) {
1333 kmclipm_update_property_int(stored_sub_noise_headers[i], EXTVER,
1334 2*(i+1)+2,
"FITS extension ver");
1336 cpl_propertylist_erase(stored_sub_noise_headers[i], CDELT1);
1337 cpl_propertylist_erase(stored_sub_noise_headers[i], CDELT2);
1338 cpl_propertylist_erase(stored_sub_noise_headers[i], CDELT3);
1339 cpl_propertylist_erase(stored_sub_noise_headers[i], CRVAL3);
1340 cpl_propertylist_erase(stored_sub_noise_headers[i], CRPIX3);
1341 cpl_propertylist_erase(stored_sub_noise_headers[i], CTYPE3);
1343 if (stored_data_images[i]==NULL) {
1344 cpl_propertylist_erase(stored_sub_noise_headers[i], CTYPE1);
1345 cpl_propertylist_erase(stored_sub_noise_headers[i], CTYPE2);
1346 cpl_propertylist_erase(stored_sub_noise_headers[i], CRPIX1);
1347 cpl_propertylist_erase(stored_sub_noise_headers[i], CRPIX2);
1348 cpl_propertylist_erase(stored_sub_noise_headers[i], CRVAL1);
1349 cpl_propertylist_erase(stored_sub_noise_headers[i], CRVAL2);
1350 cpl_propertylist_erase(stored_sub_noise_headers[i], CD1_1);
1351 cpl_propertylist_erase(stored_sub_noise_headers[i], CD2_1);
1352 cpl_propertylist_erase(stored_sub_noise_headers[i], CD1_2);
1353 cpl_propertylist_erase(stored_sub_noise_headers[i], CD2_2);
1356 kmo_dfs_save_image(stored_noise_images[i], ILLUM_CORR, fn_suffix,
1357 stored_sub_noise_headers[i], 0./0.);
1363 cpl_bivector_delete(skystats);
1365 for (i = 0; i < next * KMOS_IFUS_PER_DETECTOR; i++) {
1366 if (stored_data_images != NULL) {
1367 cpl_image_delete(stored_data_images[i]);
1369 if (stored_noise_images != NULL) {
1370 cpl_image_delete(stored_noise_images[i]);
1373 cpl_free(stored_data_images);
1374 cpl_free(stored_noise_images);
1376 for (det_nr = 1; det_nr <= next; det_nr++) {
1378 if (reduce_det != 0 && det_nr != reduce_det) continue ;
1380 for (ifu_nr = 0; ifu_nr < KMOS_IFUS_PER_DETECTOR; ifu_nr++) {
1381 kmclipm_update_property_int(
1382 stored_sub_data_headers[(det_nr-1)*KMOS_IFUS_PER_DETECTOR+ifu_nr],
1383 CAL_IFU_NR, ifu_nr+1+(det_nr-1)*KMOS_IFUS_PER_DETECTOR,
1384 "IFU Number {1..24}");
1385 kmclipm_update_property_double(
1386 stored_sub_data_headers[(det_nr-1)*KMOS_IFUS_PER_DETECTOR+ifu_nr],
1387 CAL_ROTANGLE, rotangle_found,
1388 "[deg] Rotator relative to nasmyth");
1389 if (has_flat_edge) {
1391 kmo_dfs_save_table(edge_table_sky[det_nr-1][ifu_nr],
1392 SKYFLAT_EDGE, fn_suffix,
1393 stored_sub_data_headers[(det_nr-1)*KMOS_IFUS_PER_DETECTOR+ifu_nr]);
1399 cpl_frameset_delete(frameset_raw) ;
1400 for (i = 0; i < next * KMOS_IFUS_PER_DETECTOR; i++) {
1401 if (stored_sub_data_headers != NULL)
1402 cpl_propertylist_delete(stored_sub_data_headers[i]);
1403 if (stored_sub_noise_headers != NULL)
1404 cpl_propertylist_delete(stored_sub_noise_headers[i]);
1406 cpl_free(stored_sub_data_headers);
1407 cpl_free(stored_sub_noise_headers);
1408 if (edge_table_sky) {
1409 for (i = 0; i < KMOS_NR_DETECTORS; i++) {
1410 if (edge_table_sky[i]) {
1411 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++)
1412 cpl_table_delete(edge_table_sky[i][j]);
1413 cpl_free(edge_table_sky[i]);
1416 cpl_free(edge_table_sky);
1432static int kmos_illumination_check_inputs(
1433 cpl_frameset * frameset,
1434 const char * do_catg_used,
1441 cpl_propertylist * main_header ;
1442 cpl_propertylist * tmp_header ;
1443 cpl_propertylist * eh ;
1445 const char * filter_id ;
1446 const char * filter_id_l ;
1447 double exptime, exptime_cur ;
1448 cpl_error_code err ;
1449 int naxis1, naxis2, naxis1_cur, naxis2_cur,
1450 n_ext, n_ext_cur, i, nbdarks, nbflats ;
1453 if (nx == NULL || ny == NULL || frameset == NULL || next == NULL)
1457 frame = kmo_dfs_get_frame(frameset, do_catg_used);
1459 if (!add_all_sky && !strcmp(do_catg_used, FLAT_SKY))
1460 frame = kmo_dfs_get_frame(frameset, NULL);
1462 if (frame == NULL) {
1463 cpl_msg_warning(__func__,
"The only RAW frame is skipped - abort") ;
1468 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
1469 exptime = kmos_pfits_get_exptime(main_header);
1470 cpl_propertylist_delete(main_header);
1473 frame = kmo_dfs_get_frame(frameset, NULL);
1474 while (frame != NULL) {
1476 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
1477 exptime_cur = kmos_pfits_get_exptime(main_header);
1478 cpl_propertylist_delete(main_header);
1479 if (fabs(exptime-exptime_cur) > 0.01) {
1480 cpl_msg_warning(__func__,
"EXPTIME is not consistent") ;
1483 frame = kmo_dfs_get_frame(frameset, NULL);
1487 if (cpl_frameset_count_tags(frameset, do_catg_used) < 3) {
1488 cpl_msg_warning(cpl_func,
"3 or more RAW frames is wished");
1490 nbdarks = cpl_frameset_count_tags(frameset, MASTER_DARK) ;
1491 nbflats = cpl_frameset_count_tags(frameset, MASTER_FLAT) ;
1492 if (cpl_frameset_count_tags(frameset, XCAL) != 1) {
1493 cpl_msg_warning(__func__,
"Need 1 XCAL") ;
1496 if (cpl_frameset_count_tags(frameset, YCAL) != 1) {
1497 cpl_msg_warning(__func__,
"Need 1 YCAL") ;
1500 if (cpl_frameset_count_tags(frameset, LCAL) != 1) {
1501 cpl_msg_warning(__func__,
"Need 1 LCAL") ;
1504 if (cpl_frameset_count_tags(frameset, WAVE_BAND) != 1) {
1505 cpl_msg_warning(__func__,
"Need 1 WAVE_BAND") ;
1510 err = CPL_ERROR_NONE ;
1511 err += kmo_check_frameset_setup(frameset, do_catg_used, TRUE, FALSE, TRUE);
1512 err += kmo_check_frame_setup(frameset, do_catg_used, XCAL, TRUE, FALSE,
1514 err += kmo_check_frame_setup(frameset, XCAL, YCAL, TRUE, FALSE, TRUE);
1515 err += kmo_check_frame_setup(frameset, XCAL, LCAL, TRUE, FALSE, TRUE);
1517 err += kmo_check_frame_setup(frameset, XCAL, MASTER_FLAT, TRUE, FALSE,
1520 err += kmo_check_frame_setup_md5_xycal(frameset);
1521 err += kmo_check_frame_setup_md5(frameset);
1522 if (err != CPL_ERROR_NONE) {
1523 cpl_msg_warning(__func__,
"Frames are inconsistent") ;
1528 frame = kmo_dfs_get_frame(frameset, XCAL) ;
1529 n_ext = cpl_frame_get_nextensions(frame);
1530 if (n_ext % KMOS_NR_DETECTORS != 0) {
1531 cpl_msg_warning(__func__,
"XCAL must have 3*n extensions") ;
1534 eh = cpl_propertylist_load(cpl_frame_get_filename(frame), 1);
1535 naxis1 = kmos_pfits_get_naxis1(eh) ;
1536 naxis2 = kmos_pfits_get_naxis2(eh) ;
1537 cpl_propertylist_delete(eh) ;
1540 frame = kmo_dfs_get_frame(frameset, YCAL);
1541 n_ext_cur = cpl_frame_get_nextensions(frame);
1542 if (n_ext_cur != n_ext) {
1543 cpl_msg_warning(__func__,
"XCAL and YCAL nb of extensions differ") ;
1546 eh = cpl_propertylist_load(cpl_frame_get_filename(frame), 1);
1547 naxis1_cur = kmos_pfits_get_naxis1(eh) ;
1548 naxis2_cur = kmos_pfits_get_naxis2(eh) ;
1549 cpl_propertylist_delete(eh) ;
1550 if (naxis1_cur != naxis1 || naxis2_cur != naxis2) {
1551 cpl_msg_warning(__func__,
"XCAL and YCAL sizes differ") ;
1556 frame = kmo_dfs_get_frame(frameset, LCAL);
1557 n_ext_cur = cpl_frame_get_nextensions(frame);
1558 if (n_ext_cur != n_ext) {
1559 cpl_msg_warning(__func__,
"XCAL and LCAL nb of extensions differ") ;
1562 eh = cpl_propertylist_load(cpl_frame_get_filename(frame), 1);
1563 naxis1_cur = kmos_pfits_get_naxis1(eh) ;
1564 naxis2_cur = kmos_pfits_get_naxis2(eh) ;
1565 cpl_propertylist_delete(eh) ;
1566 if (naxis1_cur != naxis1 || naxis2_cur != naxis2) {
1567 cpl_msg_warning(__func__,
"XCAL and LCAL sizes differ") ;
1573 frame = kmo_dfs_get_frame(frameset, MASTER_DARK);
1574 n_ext_cur = cpl_frame_get_nextensions(frame);
1575 if (n_ext_cur != 2*KMOS_NR_DETECTORS) {
1576 cpl_msg_warning(__func__,
"MASTER_DARK must have 6 extensions") ;
1583 frame = kmo_dfs_get_frame(frameset, MASTER_FLAT);
1584 n_ext_cur = cpl_frame_get_nextensions(frame);
1585 if (n_ext_cur % (2*KMOS_NR_DETECTORS) != 0) {
1586 cpl_msg_warning(__func__,
"MASTER_FLAT must have 6*n extensions") ;
1592 frame = kmo_dfs_get_frame(frameset, do_catg_used);
1593 tmp_header = kmo_dfs_load_primary_header(frameset, LCAL);
1595 while (frame != NULL) {
1596 n_ext = cpl_frame_get_nextensions(frame);
1597 if (n_ext != KMOS_NR_DETECTORS) {
1598 cpl_msg_warning(__func__,
"Raw file has wrong nb of extensions") ;
1601 eh = cpl_propertylist_load(cpl_frame_get_filename(frame), 1);
1602 naxis1_cur = kmos_pfits_get_naxis1(eh) ;
1603 naxis2_cur = kmos_pfits_get_naxis2(eh) ;
1604 cpl_propertylist_delete(eh) ;
1605 if (naxis1_cur != naxis1 || naxis2_cur != naxis2) {
1606 cpl_msg_warning(__func__,
"RAW file and XCAL sizes differ") ;
1611 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
1612 if (!strcmp(do_catg_used, FLAT_SKY)) {
1613 if (kmo_check_lamp(main_header, INS_LAMP1_ST) != FALSE ||
1614 kmo_check_lamp(main_header, INS_LAMP2_ST) != FALSE ||
1615 kmo_check_lamp(main_header, INS_LAMP3_ST) != FALSE ||
1616 kmo_check_lamp(main_header, INS_LAMP4_ST) != FALSE) {
1617 cpl_msg_warning(__func__,
"Some FLAT_SKY lamps are ON") ;
1618 cpl_propertylist_delete(main_header) ;
1624 for (i = 1; i <= KMOS_NR_DETECTORS; i++) {
1626 keyword = cpl_sprintf(
"%s%d%s", IFU_FILTID_PREFIX, i,
1627 IFU_FILTID_POSTFIX);
1628 filter_id = cpl_propertylist_get_string(main_header, keyword);
1629 filter_id_l = cpl_propertylist_get_string(tmp_header, keyword);
1632 if (strcmp(filter_id,
"IZ") && strcmp(filter_id,
"YJ") &&
1633 strcmp(filter_id,
"H") && strcmp(filter_id,
"K") &&
1634 strcmp(filter_id,
"HK")) {
1635 cpl_msg_warning(__func__,
1636 "Filter ID must be 'IZ', 'YJ', 'H', 'K' or 'HK' ") ;
1637 cpl_propertylist_delete(main_header) ;
1638 cpl_propertylist_delete(tmp_header) ;
1642 if (strcmp(filter_id, filter_id_l)) {
1643 cpl_msg_warning(__func__,
1644 "Filter IDs in RAW and LCAL don't match") ;
1645 cpl_propertylist_delete(main_header) ;
1646 cpl_propertylist_delete(tmp_header) ;
1651 keyword = cpl_sprintf(
"%s%d%s", IFU_GRATID_PREFIX, i,
1652 IFU_GRATID_POSTFIX);
1653 filter_id = cpl_propertylist_get_string(main_header, keyword);
1654 filter_id_l = cpl_propertylist_get_string(tmp_header, keyword);
1657 if (strcmp(filter_id,
"IZ") && strcmp(filter_id,
"YJ") &&
1658 strcmp(filter_id,
"H") && strcmp(filter_id,
"K") &&
1659 strcmp(filter_id,
"HK")) {
1660 cpl_msg_warning(__func__,
1661 "Grating ID must be 'IZ', 'YJ', 'H', 'K' or 'HK' ") ;
1662 cpl_propertylist_delete(main_header) ;
1663 cpl_propertylist_delete(tmp_header) ;
1666 if (strcmp(filter_id, filter_id_l)) {
1667 cpl_msg_warning(__func__,
1668 "Grating IDs in RAW and LCAL don't match") ;
1669 cpl_propertylist_delete(main_header) ;
1670 cpl_propertylist_delete(tmp_header) ;
1674 cpl_propertylist_delete(main_header);
1677 frame = kmo_dfs_get_frame(frameset, NULL);
1679 cpl_propertylist_delete(tmp_header);
1695static cpl_table ** kmos_illumination_edge_shift_correct(
1696 cpl_image * combined_data,
1697 cpl_image * combined_noise,
1699 const cpl_image * bad_pix_mask,
1701 cpl_array * unused_ifus,
1702 const char * flat_edge_filename,
1706 cpl_vector ** slitlet_ids = NULL ;
1707 cpl_matrix ** edgepars = NULL ;
1708 cpl_table ** edges ;
1709 cpl_vector * shift_vec ;
1710 const int * punused_ifus ;
1711 cpl_table * edge_table_flat ;
1712 cpl_vector * edge_vec ;
1713 kmclipm_vector * kv ;
1714 float * pcombined_data ;
1715 float * pcombined_noise ;
1717 double * array_out ;
1718 double tmp_rotangle, flatval, skyval, shift_val ;
1719 int ifu_nr, i, nx, ny, ix, iy, edgeNr ;
1727 kmos_calc_edgepars(combined_data, unused_ifus, bad_pix_mask, det_nr,
1728 &slitlet_ids, &edgepars);
1729 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1730 cpl_msg_error(__func__,
"Cannot compute edges parameters") ;
1735 edges = kmo_edgepars_to_table(slitlet_ids, edgepars);
1736 if (edgepars != NULL) {
1737 for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++)
1738 cpl_matrix_delete(edgepars[i]);
1741 if (slitlet_ids != NULL) {
1742 for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++)
1743 cpl_vector_delete(slitlet_ids[i]);
1744 cpl_free(slitlet_ids);
1748 shift_vec = cpl_vector_new(KMOS_IFUS_PER_DETECTOR);
1749 for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++) {
1750 ifu_nr = (det_nr-1)*KMOS_IFUS_PER_DETECTOR + i + 1;
1751 punused_ifus = cpl_array_get_data_int_const(unused_ifus);
1752 if (punused_ifus[i] == 0) {
1753 edge_table_flat = kmclipm_cal_table_load(flat_edge_filename,
1754 ifu_nr, rotangle, 0, &tmp_rotangle);
1756 if (edge_table_flat != NULL) {
1757 edge_vec = cpl_vector_new(2*KMOS_SLITLET_X);
1758 for (edgeNr = 0; edgeNr < 2*KMOS_SLITLET_X; edgeNr++) {
1759 flatval = kmo_calc_fitted_slitlet_edge(edge_table_flat,
1760 edgeNr, middle_row);
1761 skyval = kmo_calc_fitted_slitlet_edge(edges[i], edgeNr,
1763 cpl_vector_set(edge_vec, edgeNr, flatval-skyval);
1765 cpl_table_delete(edge_table_flat);
1768 kv = kmclipm_vector_create(edge_vec);
1769 kmclipm_reject_deviant(kv, 3, 3, NULL, NULL);
1772 cpl_vector_set(shift_vec, i,
1773 kmclipm_vector_get_median(kv, KMCLIPM_ARITHMETIC));
1774 kmclipm_vector_delete(kv);
1776 cpl_vector_set(shift_vec, i, 0.0) ;
1779 cpl_vector_set(shift_vec, i, 0.0) ;
1784 shift_val = -cpl_vector_get_median(shift_vec);
1785 cpl_vector_delete(shift_vec);
1787 cpl_msg_info(__func__,
"Shift detector %d by %g pixels", det_nr, shift_val);
1788 nx = cpl_image_get_size_x(combined_data),
1789 ny = cpl_image_get_size_x(combined_data),
1790 pcombined_data = cpl_image_get_data_float(combined_data) ;
1791 if (process_noise) {
1792 pcombined_noise = cpl_image_get_data_float(combined_noise);
1795 array_in = cpl_calloc(nx,
sizeof(
double)) ;
1797 for (iy = 0; iy < ny; iy++) {
1798 for (ix = 0; ix < nx; ix++) array_in[ix] = pcombined_data[ix+iy*nx];
1799 array_out = cubicspline_reg_reg(nx, 0., 1., array_in, nx, shift_val,
1801 for (ix = 0; ix < nx; ix++) pcombined_data[ix+iy*nx] = array_out[ix];
1802 cpl_free(array_out);
1804 if (process_noise) {
1805 for (ix = 0; ix < nx; ix++) array_in[ix]=pcombined_noise[ix+iy*nx];
1806 array_out = cubicspline_reg_reg(nx, 0., 1., array_in, nx, shift_val,
1808 for (ix = 0; ix < nx; ix++) pcombined_noise[ix+iy*nx]=array_out[ix];
1809 cpl_free(array_out);
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.