|
KMOS Pipeline Reference Manual
1.3.4
|
00001 /* 00002 * This file is part of the KMOS Pipeline 00003 * Copyright (C) 2002,2003 European Southern Observatory 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00018 */ 00019 00020 #ifdef HAVE_CONFIG_H 00021 #include <config.h> 00022 #endif 00023 00024 /*----------------------------------------------------------------------------- 00025 * Includes 00026 *----------------------------------------------------------------------------*/ 00027 00028 #include <math.h> 00029 #include <string.h> 00030 00031 #include <cpl.h> 00032 00033 #include "kmclipm_priv_splines.h" 00034 00035 #include "kmo_priv_reconstruct.h" 00036 #include "kmo_priv_functions.h" 00037 #include "kmo_priv_flat.h" 00038 #include "kmo_priv_wave_cal.h" 00039 #include "kmo_priv_combine.h" 00040 #include "kmo_functions.h" 00041 #include "kmo_cpl_extensions.h" 00042 #include "kmo_dfs.h" 00043 #include "kmos_pfits.h" 00044 #include "kmo_error.h" 00045 #include "kmo_constants.h" 00046 #include "kmo_debug.h" 00047 00048 /*----------------------------------------------------------------------------- 00049 * Functions prototypes 00050 *----------------------------------------------------------------------------*/ 00051 00052 static int kmos_illumination_check_inputs(cpl_frameset *, int, int *, int *, 00053 int *, int *, int *, double *) ; 00054 static cpl_table ** kmos_illumination_edge_shift_correct(cpl_image *, 00055 cpl_image *, int, const cpl_image *, int, cpl_array *, 00056 const char *, double) ; 00057 00058 static int kmos_illumination_create(cpl_plugin *); 00059 static int kmos_illumination_exec(cpl_plugin *); 00060 static int kmos_illumination_destroy(cpl_plugin *); 00061 static int kmos_illumination(cpl_parameterlist *, cpl_frameset *); 00062 00063 /*----------------------------------------------------------------------------- 00064 * Static variables 00065 *----------------------------------------------------------------------------*/ 00066 00067 static char kmos_illumination_description[] = 00068 "This recipe creates the spatial non-uniformity calibration frame needed for\n" 00069 "all three detectors. It must be called after the kmo_wave_cal-recipe, which\n" 00070 "generates the spectral calibration frame needed in this recipe. As input at\n" 00071 "least a sky, a master dark, a master flat and the spatial and spectral cali-\n" 00072 "bration frames are required.\n" 00073 "The created product, the illumination correction, can be used as input for\n" 00074 "kmo_std_star and kmo_sci_red.\n" 00075 "\n" 00076 "BASIC PARAMETERS:\n" 00077 "-----------------\n" 00078 "--imethod\n" 00079 "The interpolation method used for reconstruction.\n" 00080 "\n" 00081 "--range\n" 00082 "The spectral ranges to combine when collapsing the reconstructed cubes. e.g.\n" 00083 "\"x1_start,x1_end;x2_start,x2_end\" (microns)\n" 00084 "\n" 00085 "ADVANCED PARAMETERS\n" 00086 "-------------------\n" 00087 "--flux\n" 00088 "Specify if flux conservation should be applied.\n" 00089 "\n" 00090 "--add-all\n" 00091 "By default the first FLAT_SKY frame is omitted, since in the\n" 00092 "KMOS_spec_cal_skyflat template this is an acquisition frame to estimate the\n" 00093 "needed exposure time for the subsequent FLAT_SKY frames. If anyway all\n" 00094 "frames should be considered, set this parameter to TRUE.\n" 00095 "\n" 00096 "--neighborhoodRange\n" 00097 "Defines the range to search for neighbors during reconstruction\n" 00098 "\n" 00099 "--b_samples\n" 00100 "The number of samples in spectral direction for the reconstructed cube.\n" 00101 "Ideally this number should be greater than 2048, the detector size.\n" 00102 "\n" 00103 "--b_start\n" 00104 "--b_end\n" 00105 "Used to define manually the start and end wavelength for the reconstructed\n" 00106 "cube. By default the internally defined values are used.\n" 00107 "\n" 00108 "--cmethod\n" 00109 "Following methods of frame combination are available:\n" 00110 " * 'ksigma' (Default)\n" 00111 " An iterative sigma clipping. For each position all pixels in the spectrum\n" 00112 " are examined. If they deviate significantly, they will be rejected\n" 00113 " according to the conditions:\n" 00114 " val > mean + stdev * cpos_rej\n" 00115 " and\n" 00116 " val < mean - stdev * cneg_rej\n" 00117 " where --cpos_rej, --cneg_rej and --citer are the corresponding\n" 00118 " configuration parameters. In the first iteration median and percentile\n" 00119 " level are used.\n" 00120 "\n" 00121 " * 'median'\n" 00122 " At each pixel position the median is calculated.\n" 00123 "\n" 00124 " * 'average'\n" 00125 " At each pixel position the average is calculated.\n" 00126 "\n" 00127 " * 'sum'\n" 00128 " At each pixel position the sum is calculated.\n" 00129 "\n" 00130 " * 'min_max'\n" 00131 " The specified nb of minimum and maximum pixel values will be rejected.\n" 00132 " --cmax and --cmin apply to this method.\n" 00133 "\n" 00134 "--cpos_rej\n" 00135 "--cneg_rej\n" 00136 "--citer\n" 00137 "see --cmethod='ksigma'\n" 00138 "\n" 00139 "--cmax\n" 00140 "--cmin\n" 00141 "see --cmethod='min_max'\n" 00142 "\n" 00143 "--pix_scale\n" 00144 "Change the pixel scale [arcsec]. Default of 0.2\" results into cubes of\n" 00145 "14x14pix, a scale of 0.1\" results into cubes of 28x28pix, etc.\n" 00146 "\n" 00147 "--suppress_extension\n" 00148 "If set to TRUE, the arbitrary filename extensions are supressed. If multiple\n" 00149 "products with the same category are produced, they will be numbered\n" 00150 "consecutively starting from 0.\n" 00151 "\n" 00152 "---------------------------------------------------------------------------\n" 00153 " Input files:\n" 00154 "\n" 00155 " DO CATG Type Explanation Required #Frames\n" 00156 " -------- ----- ----------- -------- -------\n" 00157 " FLAT_SKY F2D Sky exposures Y 1-n \n" 00158 " (at least 3 frames recommended) \n" 00159 " MASTER_DARK F2D Master dark Y 1 \n" 00160 " MASTER_FLAT F2D Master flat Y 1 \n" 00161 " XCAL F2D x calibration frame Y 1 \n" 00162 " YCAL F2D y calibration frame Y 1 \n" 00163 " LCAL F2D Wavelength calib. frame Y 1 \n" 00164 " WAVE_BAND F2L Table with start-/end-wavelengths Y 1 \n" 00165 " FLAT_EDGE F2L Table with fitted slitlet edges N 0,1 \n" 00166 "\n" 00167 " Output files:\n" 00168 "\n" 00169 " DO CATG Type Explanation\n" 00170 " -------- ----- -----------\n" 00171 " ILLUM_CORR F2I Illumination calibration frame \n" 00172 " If FLAT_EDGE is provided: \n" 00173 " SKYFLAT_EDGE F2L Frame containing parameters of fitted \n" 00174 " slitlets of all IFUs of all detectors\n" 00175 "---------------------------------------------------------------------------\n" 00176 "\n"; 00177 00178 /*----------------------------------------------------------------------------- 00179 * Functions code 00180 *----------------------------------------------------------------------------*/ 00181 00182 /*----------------------------------------------------------------------------*/ 00187 /*----------------------------------------------------------------------------*/ 00188 00191 /*----------------------------------------------------------------------------*/ 00200 /*----------------------------------------------------------------------------*/ 00201 int cpl_plugin_get_info(cpl_pluginlist *list) 00202 { 00203 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe); 00204 cpl_plugin *plugin = &recipe->interface; 00205 00206 cpl_plugin_init(plugin, 00207 CPL_PLUGIN_API, 00208 KMOS_BINARY_VERSION, 00209 CPL_PLUGIN_TYPE_RECIPE, 00210 "kmos_illumination", 00211 "Create a frame to correct spatial non-uniformity of flatfield", 00212 kmos_illumination_description, 00213 "Alex Agudo Berbel, Yves Jung", 00214 "usd-help@eso.org", 00215 kmos_get_license(), 00216 kmos_illumination_create, 00217 kmos_illumination_exec, 00218 kmos_illumination_destroy); 00219 cpl_pluginlist_append(list, plugin); 00220 00221 return 0; 00222 } 00223 00224 /*----------------------------------------------------------------------------*/ 00232 /*----------------------------------------------------------------------------*/ 00233 static int kmos_illumination_create(cpl_plugin *plugin) 00234 { 00235 cpl_recipe *recipe; 00236 cpl_parameter *p; 00237 00238 /* Check that the plugin is part of a valid recipe */ 00239 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00240 recipe = (cpl_recipe *)plugin; 00241 else 00242 return -1; 00243 00244 /* Create the parameters list in the cpl_recipe object */ 00245 recipe->parameters = cpl_parameterlist_new(); 00246 00247 /* Fill the parameters list */ 00248 /* --imethod */ 00249 p = cpl_parameter_new_value("kmos.kmos_illumination.imethod", 00250 CPL_TYPE_STRING, 00251 "Method to use for interpolation: " 00252 "[\"NN\" (nearest neighbour), " 00253 "\"lwNN\" (linear weighted nearest neighbor), " 00254 "\"swNN\" (square weighted nearest neighbor), " 00255 "\"MS\" (Modified Shepard's method), " 00256 "\"CS\" (Cubic spline)]", 00257 "kmos.kmos_illumination", "CS"); 00258 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod"); 00259 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00260 cpl_parameterlist_append(recipe->parameters, p); 00261 00262 /* --neighborhoodRange */ 00263 p = cpl_parameter_new_value("kmos.kmos_illumination.neighborhoodRange", 00264 CPL_TYPE_DOUBLE, "Range (pixels) to search for neighbors", 00265 "kmos.kmos_illumination", 1.001); 00266 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "neighborhoodRange"); 00267 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00268 cpl_parameterlist_append(recipe->parameters, p); 00269 00270 /* --range */ 00271 p = cpl_parameter_new_value("kmos.kmos_illumination.range", 00272 CPL_TYPE_STRING, 00273 "The spectral ranges to combine when collapsing the reconstructed cubes. e.g. " "\"x1_start,x1_end;x2_start,x2_end\" (microns)", 00274 "kmos.kmos_illumination", ""); 00275 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "range"); 00276 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00277 cpl_parameterlist_append(recipe->parameters, p); 00278 00279 /* --flux */ 00280 p = cpl_parameter_new_value("kmos.kmos_illumination.flux", 00281 CPL_TYPE_BOOL, "TRUE: Apply flux conservation. FALSE: otherwise", 00282 "kmos.kmos_illumination", FALSE); 00283 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux"); 00284 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00285 cpl_parameterlist_append(recipe->parameters, p); 00286 00287 /* --add-all */ 00288 p = cpl_parameter_new_value("kmos.kmos_illumination.add-all", CPL_TYPE_BOOL, 00289 "FALSE: omit 1st FLAT_SKY frame (acquisition), " 00290 "TRUE: don't perform any checks, add them all", 00291 "kmos.kmos_illumination", FALSE); 00292 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "add-all"); 00293 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00294 cpl_parameterlist_append(recipe->parameters, p); 00295 00296 /* --pix_scale */ 00297 p = cpl_parameter_new_value("kmos.kmos_illumination.pix_scale", 00298 CPL_TYPE_DOUBLE, 00299 "Change the pixel scale [arcsec]. " 00300 "Default of 0.2\" results into cubes of 14x14pix, " 00301 "a scale of 0.1\" results into cubes of 28x28pix, etc.", 00302 "kmos.kmos_illumination", KMOS_PIX_RESOLUTION); 00303 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "pix_scale"); 00304 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00305 cpl_parameterlist_append(recipe->parameters, p); 00306 00307 /* --suppress_extension */ 00308 p = cpl_parameter_new_value("kmos.kmos_illumination.suppress_extension", 00309 CPL_TYPE_BOOL, 00310 "Suppress filename extension. (TRUE (apply) or FALSE (don't apply)", 00311 "kmos.kmos_illumination", FALSE); 00312 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension"); 00313 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00314 cpl_parameterlist_append(recipe->parameters, p); 00315 00316 /* Add parameters for band-definition */ 00317 kmos_band_pars_create(recipe->parameters, "kmos.kmos_illumination"); 00318 00319 /* Add parameters for combining */ 00320 kmos_combine_pars_create(recipe->parameters, "kmos.kmos_illumination", 00321 DEF_REJ_METHOD, FALSE); 00322 00323 /* --detector */ 00324 p = cpl_parameter_new_value("kmos.kmos_illumination.detector", 00325 CPL_TYPE_INT, "Only reduce the specified detector", 00326 "kmos.kmos_illumination", 0); 00327 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "det"); 00328 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00329 cpl_parameterlist_append(recipe->parameters, p); 00330 00331 return 0 ; 00332 } 00333 00334 /*----------------------------------------------------------------------------*/ 00340 /*----------------------------------------------------------------------------*/ 00341 static int kmos_illumination_exec(cpl_plugin *plugin) 00342 { 00343 cpl_recipe *recipe; 00344 00345 /* Get the recipe out of the plugin */ 00346 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00347 recipe = (cpl_recipe *)plugin; 00348 else return -1; 00349 00350 return kmos_illumination(recipe->parameters, recipe->frames); 00351 } 00352 00353 /*----------------------------------------------------------------------------*/ 00359 /*----------------------------------------------------------------------------*/ 00360 static int kmos_illumination_destroy(cpl_plugin *plugin) 00361 { 00362 cpl_recipe *recipe; 00363 00364 /* Get the recipe out of the plugin */ 00365 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00366 recipe = (cpl_recipe *)plugin; 00367 else return -1 ; 00368 00369 cpl_parameterlist_delete(recipe->parameters); 00370 return 0 ; 00371 } 00372 00373 /*----------------------------------------------------------------------------*/ 00386 /*----------------------------------------------------------------------------*/ 00387 static int kmos_illumination( 00388 cpl_parameterlist * parlist, 00389 cpl_frameset * frameset) 00390 { 00391 const cpl_parameter * par ; 00392 const char * method ; 00393 const char * cmethod ; 00394 const char * ranges_txt ; 00395 const char * sval ; 00396 int ne, nx, ny, flux, add_all_sky, cmax, cmin, citer, 00397 suppress_extension, reduce_det, dark_has_noise, 00398 flat_has_noise, 00399 process_noise, cnt, has_flat_edge ; 00400 double neighborhoodRange, pix_scale, cpos_rej, cneg_rej, 00401 rotangle, rotangle_found ; 00402 char * suffix ; 00403 char * fn_lut ; 00404 char * fn_suffix ; 00405 char * extname ; 00406 cpl_array ** unused_ifus ; 00407 const int * punused_ifus ; 00408 cpl_frame * frame ; 00409 cpl_frameset * frameset_sky ; 00410 char * filter ; 00411 char * keyword ; 00412 cpl_vector * ranges ; 00413 gridDefinition gd; 00414 cpl_propertylist * main_header ; 00415 cpl_propertylist * tmp_header ; 00416 int * bounds ; 00417 cpl_array * calTimestamp ; 00418 cpl_imagelist ** stored_data_cubes ; 00419 cpl_imagelist ** stored_noise_cubes ; 00420 cpl_image ** stored_data_images ; 00421 cpl_image ** stored_noise_images ; 00422 cpl_propertylist ** stored_sub_data_headers ; 00423 cpl_propertylist ** stored_sub_noise_headers ; 00424 cpl_table *** edge_table_sky ; 00425 cpl_vector * calAngles ; 00426 cpl_imagelist * detector_in ; 00427 cpl_image * img_in ; 00428 cpl_image * combined_data ; 00429 cpl_image * combined_noise ; 00430 cpl_image * xcal ; 00431 cpl_image * ycal ; 00432 cpl_image * lcal ; 00433 cpl_image * bad_pix_mask ; 00434 float * pbad_pix_mask ; 00435 cpl_image * img_dark ; 00436 cpl_image * img_dark_noise ; 00437 cpl_image * img_flat ; 00438 cpl_image * img_flat_noise ; 00439 cpl_table * band_table ; 00440 cpl_propertylist * sub_header ; 00441 cpl_imagelist * cube_data ; 00442 cpl_imagelist * cube_noise ; 00443 cpl_image * data_ifu ; 00444 cpl_image * noise_ifu ; 00445 cpl_vector * identified_slices ; 00446 double ifu_crpix, ifu_crval, ifu_cdelt, mean_data, 00447 qc_spat_unif, qc_max_dev, qc_max_nonunif, 00448 tmp_stdev, tmp_mean ; 00449 int x, y, det_nr, i, j, ifu_nr, qc_max_dev_id, 00450 qc_max_nonunif_id ; 00451 00452 /* Check entries */ 00453 if (parlist == NULL || frameset == NULL) { 00454 cpl_msg_error(__func__, "Null Inputs") ; 00455 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ; 00456 return -1 ; 00457 } 00458 00459 /* Get parameters */ 00460 par = cpl_parameterlist_find_const(parlist, 00461 "kmos.kmos_illumination.imethod") ; 00462 method = cpl_parameter_get_string(par); 00463 par = cpl_parameterlist_find_const(parlist, 00464 "kmos.kmos_illumination.neighborhoodRange"); 00465 neighborhoodRange = cpl_parameter_get_double(par) ; 00466 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_illumination.range"); 00467 ranges_txt = cpl_parameter_get_string(par) ; 00468 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_illumination.flux"); 00469 flux = cpl_parameter_get_bool(par); 00470 par = cpl_parameterlist_find_const(parlist, 00471 "kmos.kmos_illumination.add-all"); 00472 add_all_sky = cpl_parameter_get_bool(par) ; 00473 par = cpl_parameterlist_find_const(parlist, 00474 "kmos.kmos_illumination.pix_scale"); 00475 pix_scale = cpl_parameter_get_double(par) ; 00476 par = cpl_parameterlist_find_const(parlist, 00477 "kmos.kmos_illumination.suppress_extension"); 00478 suppress_extension = cpl_parameter_get_bool(par) ; 00479 par = cpl_parameterlist_find_const(parlist, 00480 "kmos.kmos_illumination.detector"); 00481 reduce_det = cpl_parameter_get_int(par); 00482 00483 kmos_band_pars_load(parlist, "kmos.kmos_illumination"); 00484 kmos_combine_pars_load(parlist, "kmos.kmos_illumination", &cmethod, 00485 &cpos_rej, &cneg_rej, &citer, &cmin, &cmax, FALSE); 00486 00487 /* Check Parameters */ 00488 if (strcmp(method, "NN") && strcmp(method, "lwNN") && strcmp(method, "swNN") 00489 && strcmp(method, "MS") && strcmp(method, "CS")) { 00490 cpl_msg_error(__func__, 00491 "method must be \"NN\", \"lwNN\", \"swNN\", \"MS\" or \"CS\"") ; 00492 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00493 return -1 ; 00494 } 00495 if (neighborhoodRange <= 0.0) { 00496 cpl_msg_error(__func__, "neighborhoodRange must be > 0") ; 00497 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00498 return -1 ; 00499 } 00500 if (pix_scale < 0.01 || pix_scale > 0.4) { 00501 cpl_msg_error(__func__, 00502 "pix_scale must be in [0.01,0.4] -> 7x7 to 280x280 pixels") ; 00503 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00504 return -1 ; 00505 } 00506 if (reduce_det < 0 || reduce_det > 3) { 00507 cpl_msg_error(__func__, "detector must be in [1,3]") ; 00508 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00509 return -1 ; 00510 } 00511 if (cpl_frameset_count_tags(frameset, FLAT_SKY) == 1) { 00512 cpl_msg_warning(cpl_func, "1 input FLAT -> cmethod changed to average"); 00513 cmethod = "average"; 00514 } 00515 00516 /* Identify the RAW and CALIB frames in the input frameset */ 00517 if (kmo_dfs_set_groups(frameset, "kmos_illumination") != 1) { 00518 cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ; 00519 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00520 return -1 ; 00521 } 00522 00523 /* Check the inputs consistency */ 00524 if (kmos_illumination_check_inputs(frameset, add_all_sky, &dark_has_noise, 00525 &flat_has_noise, &ne, &nx, &ny, &rotangle) != 1) { 00526 cpl_msg_error(__func__, "Input frameset is not consistent") ; 00527 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00528 return -1 ; 00529 } 00530 00531 /* Instrument setup */ 00532 suffix = kmo_dfs_get_suffix(kmo_dfs_get_frame(frameset, XCAL), TRUE, FALSE); 00533 cpl_msg_info(__func__, "Detected instrument setup: %s", suffix+1); 00534 00535 /* Check which IFUs are active for all frames */ 00536 unused_ifus = kmo_get_unused_ifus(frameset, 0, 0); 00537 kmo_print_unused_ifus(unused_ifus, FALSE); 00538 00539 has_flat_edge = cpl_frameset_count_tags(frameset, FLAT_EDGE); 00540 00541 /* Decide here if noise is propagated */ 00542 if (cpl_frameset_count_tags(frameset, FLAT_SKY) >= 2 && 00543 dark_has_noise && flat_has_noise) process_noise = 1 ; 00544 else process_noise = 0 ; 00545 00546 /* Load the FLAT_SKY frames in a frameset */ 00547 frameset_sky = cpl_frameset_new(); 00548 frame = kmo_dfs_get_frame(frameset, FLAT_SKY); 00549 if (add_all_sky) { 00550 cpl_msg_info(__func__, "Use all FLAT_SKY frames"); 00551 } else { 00552 /* Omit the first frame */ 00553 cpl_msg_info(__func__, "Use all FLAT_SKY frames but the first"); 00554 frame = kmo_dfs_get_frame(frameset, NULL); 00555 } 00556 while (frame != NULL) { 00557 cpl_frameset_insert(frameset_sky, cpl_frame_duplicate(frame)); 00558 frame = kmo_dfs_get_frame(frameset, NULL); 00559 } 00560 00561 /* Load first file primary header */ 00562 frame = kmo_dfs_get_frame(frameset_sky, FLAT_SKY); 00563 if (frame == NULL) { 00564 cpl_free(suffix) ; 00565 kmo_free_unused_ifus(unused_ifus); 00566 cpl_frameset_delete(frameset_sky) ; 00567 cpl_msg_error(__func__, "Missing FLAT_SKY in input") ; 00568 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00569 return -1 ; 00570 } 00571 00572 main_header = kmo_dfs_load_primary_header(frameset_sky, FLAT_SKY); 00573 00574 /* Set default band-specific ranges for collapsing */ 00575 if (!strcmp(ranges_txt, "")) { 00576 keyword = cpl_sprintf("%s%d%s", IFU_GRATID_PREFIX,1,IFU_GRATID_POSTFIX); 00577 filter = cpl_sprintf("%s", 00578 cpl_propertylist_get_string(main_header,keyword)); 00579 cpl_free(keyword); 00580 if (strcmp(filter, "IZ") == 0) ranges_txt = "0.81,1.05"; 00581 else if (strcmp(filter, "YJ") == 0) ranges_txt = "1.025,1.3"; 00582 else if (strcmp(filter, "H") == 0) ranges_txt = "1.5,1.7"; 00583 else if (strcmp(filter, "K") == 0) ranges_txt = "2.1,2.35"; 00584 else if (strcmp(filter, "HK") == 0) ranges_txt = "1.5,1.7;2.1,2.35"; 00585 else { 00586 cpl_msg_error(__func__, "Filter %s not supported", filter) ; 00587 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00588 cpl_free(suffix) ; 00589 kmo_free_unused_ifus(unused_ifus); 00590 cpl_frameset_delete(frameset_sky) ; 00591 cpl_propertylist_delete(main_header); 00592 cpl_free(filter) ; 00593 return -1 ; 00594 } 00595 cpl_free(filter) ; 00596 } 00597 cpl_msg_info(__func__, "Spectral range to collapse: %s um", ranges_txt); 00598 00599 /* Set grid definition, wl start/end points will be set in the loop */ 00600 kmclipm_setup_grid(&gd, method, neighborhoodRange, pix_scale, 0.); 00601 00602 // create filename for LUT 00603 fn_lut = cpl_sprintf("%s%s", "lut", suffix); 00604 00605 // extract bounds 00606 tmp_header = kmo_dfs_load_primary_header(frameset, XCAL); 00607 bounds = kmclipm_extract_bounds(tmp_header); 00608 cpl_propertylist_delete(tmp_header); 00609 00610 /* Get timestamps of xcal, ycal & lcal */ 00611 calTimestamp = kmo_get_timestamps( 00612 kmo_dfs_get_frame(frameset, XCAL), 00613 kmo_dfs_get_frame(frameset, YCAL), 00614 kmo_dfs_get_frame(frameset, LCAL)) ; 00615 00616 /* Create holders for reconstructed data, noise cubes and headers */ 00617 stored_data_cubes = (cpl_imagelist**)cpl_calloc(ne*KMOS_IFUS_PER_DETECTOR, 00618 sizeof(cpl_imagelist*)); 00619 stored_noise_cubes = (cpl_imagelist**)cpl_calloc(ne*KMOS_IFUS_PER_DETECTOR, 00620 sizeof(cpl_imagelist*)); 00621 stored_data_images = (cpl_image**)cpl_calloc(ne*KMOS_IFUS_PER_DETECTOR, 00622 sizeof(cpl_image*)); 00623 stored_noise_images = (cpl_image**)cpl_calloc(ne*KMOS_IFUS_PER_DETECTOR, 00624 sizeof(cpl_image*)); 00625 stored_sub_data_headers = (cpl_propertylist**)cpl_calloc( 00626 ne*KMOS_IFUS_PER_DETECTOR, sizeof(cpl_propertylist*)); 00627 stored_sub_noise_headers = (cpl_propertylist**)cpl_calloc( 00628 ne*KMOS_IFUS_PER_DETECTOR, sizeof(cpl_propertylist*)); 00629 if (has_flat_edge) edge_table_sky = (cpl_table***)cpl_calloc( 00630 KMOS_NR_DETECTORS, sizeof(cpl_table**)); 00631 calAngles = cpl_vector_new(3); 00632 00633 /* Loop through all detectors */ 00634 for (det_nr = 1; det_nr <= ne; det_nr++) { 00635 00636 /* Compute only one detector */ 00637 if (reduce_det != 0 && det_nr != reduce_det) continue ; 00638 00639 cpl_msg_info(__func__, "Processing detector No. %d", det_nr); 00640 cpl_msg_indent_more() ; 00641 00642 detector_in = cpl_imagelist_new(); 00643 00644 /* Load all images of this detector */ 00645 img_in = kmo_dfs_load_image(frameset_sky, FLAT_SKY, det_nr, FALSE, 00646 TRUE,NULL); 00647 cnt = 0; 00648 while (img_in != NULL) { 00649 cpl_imagelist_set(detector_in, img_in, cnt); 00650 00651 /* load same extension of next FLAT_SKY frame*/ 00652 img_in = kmo_dfs_load_image(frameset_sky, NULL, det_nr, FALSE, 00653 TRUE, NULL); 00654 cnt++; 00655 } 00656 00657 /* Combine images (data only) and create noise (stdev of data) */ 00658 cpl_msg_info(__func__, "Combining frames"); 00659 if (process_noise) { 00660 kmos_combine_frames(detector_in, cmethod, cpos_rej, cneg_rej, 00661 citer, cmax, cmin, &combined_data, &combined_noise, -1.0); 00662 } else { 00663 kmos_combine_frames(detector_in, cmethod, cpos_rej, cneg_rej, 00664 citer, cmax, cmin, &combined_data, NULL, -1.0); 00665 } 00666 cpl_imagelist_delete(detector_in); 00667 00668 /* Check if combination succesfull */ 00669 if (cpl_error_get_code() != CPL_ERROR_NONE) { 00670 cpl_free(suffix) ; 00671 kmo_free_unused_ifus(unused_ifus); 00672 cpl_frameset_delete(frameset_sky) ; 00673 cpl_propertylist_delete(main_header); 00674 cpl_free(fn_lut) ; 00675 cpl_free(bounds) ; 00676 cpl_array_delete(calTimestamp); 00677 cpl_free(stored_data_cubes); 00678 cpl_free(stored_noise_cubes); 00679 cpl_free(stored_data_images); 00680 cpl_free(stored_noise_images); 00681 cpl_free(stored_sub_data_headers); 00682 cpl_free(stored_sub_noise_headers); 00683 if (has_flat_edge) cpl_free(edge_table_sky) ; 00684 cpl_vector_delete(calAngles) ; 00685 cpl_msg_error(__func__, "Combination failed") ; 00686 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00687 cpl_msg_indent_less() ; 00688 return -1 ; 00689 } 00690 00691 /* 00692 cpl_image_save(combined_data, "combined_image.fits", 00693 CPL_TYPE_FLOAT, NULL, CPL_IO_CREATE) ; 00694 */ 00695 00696 if (kmclipm_omit_warning_one_slice > 10) 00697 kmclipm_omit_warning_one_slice = FALSE; 00698 00699 /* Load calibration files */ 00700 xcal = kmo_dfs_load_cal_image(frameset, XCAL, det_nr, FALSE, rotangle, 00701 FALSE, NULL, &rotangle_found, -1, 0, 0); 00702 cpl_vector_set(calAngles, 0, rotangle_found); 00703 ycal = kmo_dfs_load_cal_image(frameset, YCAL, det_nr, FALSE, rotangle, 00704 FALSE, NULL, &rotangle_found, -1, 0, 0); 00705 cpl_vector_set(calAngles, 1, rotangle_found); 00706 lcal = kmo_dfs_load_cal_image(frameset, LCAL, det_nr, FALSE, rotangle, 00707 FALSE, NULL, &rotangle_found, -1, 0, 0); 00708 cpl_vector_set(calAngles, 2, rotangle_found); 00709 00710 /* Load bad pixel mask from XCAL and set NaNs to 0 other values to 1 */ 00711 bad_pix_mask = cpl_image_duplicate(xcal); 00712 pbad_pix_mask = cpl_image_get_data_float(bad_pix_mask); 00713 for (x = 0; x < nx; x++) { 00714 for (y = 0; y < ny; y++) { 00715 if (isnan(pbad_pix_mask[x+nx*y])) { 00716 pbad_pix_mask[x+nx*y] = 0.; 00717 } else { 00718 pbad_pix_mask[x+nx*y] = 1.; 00719 } 00720 } 00721 } 00722 00723 /* Compute SKYFLAT_EDGE */ 00724 if (has_flat_edge) { 00725 edge_table_sky[det_nr-1] = kmos_illumination_edge_shift_correct( 00726 combined_data, combined_noise, process_noise, bad_pix_mask, 00727 det_nr, unused_ifus[det_nr-1], 00728 cpl_frame_get_filename(kmo_dfs_get_frame(frameset, 00729 FLAT_EDGE)), rotangle); 00730 if (edge_table_sky[det_nr-1] == NULL) { 00731 cpl_free(suffix) ; 00732 kmo_free_unused_ifus(unused_ifus); 00733 cpl_frameset_delete(frameset_sky) ; 00734 cpl_propertylist_delete(main_header); 00735 cpl_free(fn_lut) ; 00736 cpl_free(bounds) ; 00737 cpl_array_delete(calTimestamp); 00738 cpl_free(stored_data_cubes); 00739 cpl_free(stored_noise_cubes); 00740 cpl_free(stored_data_images); 00741 cpl_free(stored_noise_images); 00742 cpl_free(stored_sub_data_headers); 00743 cpl_free(stored_sub_noise_headers); 00744 if (has_flat_edge) cpl_free(edge_table_sky) ; 00745 cpl_image_delete(bad_pix_mask); 00746 cpl_image_delete(combined_data); 00747 if (process_noise) { 00748 cpl_image_delete(combined_noise); 00749 } 00750 cpl_image_delete(xcal); 00751 cpl_image_delete(ycal); 00752 cpl_image_delete(lcal); 00753 cpl_vector_delete(calAngles) ; 00754 cpl_msg_error(__func__, "Edge Shift Correction failed") ; 00755 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00756 cpl_msg_indent_less() ; 00757 return -1 ; 00758 } 00759 } 00760 00761 /* Reconstruct */ 00762 /* Load MASTER_DARK and MASTER_FLAT */ 00763 img_dark = kmo_dfs_load_image(frameset, MASTER_DARK, det_nr, FALSE, 00764 FALSE, NULL); 00765 if (process_noise) { 00766 img_dark_noise = kmo_dfs_load_image(frameset, MASTER_DARK, det_nr, 00767 TRUE, FALSE, NULL); 00768 } 00769 img_flat = kmo_dfs_load_cal_image(frameset, MASTER_FLAT, det_nr, FALSE, 00770 rotangle, FALSE, NULL, &rotangle_found, -1, 0, 0); 00771 if (process_noise) { 00772 img_flat_noise = kmo_dfs_load_cal_image(frameset, MASTER_FLAT, 00773 det_nr, TRUE, rotangle, FALSE, NULL, &rotangle_found, -1, 00774 0, 0); 00775 } 00776 00777 /* ESO INS FILTi ID */ 00778 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, det_nr, 00779 IFU_FILTID_POSTFIX); 00780 band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, 0); 00781 kmclipm_setup_grid_band_lcal(&gd, 00782 cpl_propertylist_get_string(main_header, keyword), band_table); 00783 cpl_free(keyword); 00784 cpl_table_delete(band_table); 00785 00786 cpl_msg_info(__func__, "Reconstructing cubes"); 00787 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00788 // update sub-header 00789 ifu_nr = (det_nr-1)*KMOS_IFUS_PER_DETECTOR + j + 1; 00790 00791 // load raw image and sub-header 00792 sub_header = kmo_dfs_load_sub_header(frameset_sky, FLAT_SKY, 00793 det_nr, FALSE); 00794 00795 punused_ifus = cpl_array_get_data_int_const(unused_ifus[det_nr-1]); 00796 00797 /* Check if IFU is valid */ 00798 keyword = cpl_sprintf("%s%d%s", IFU_VALID_PREFIX, ifu_nr, 00799 IFU_VALID_POSTFIX); 00800 sval = cpl_propertylist_get_string(main_header, keyword); 00801 cpl_free(keyword); 00802 00803 if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) && 00804 (bounds[2*(ifu_nr-1)] != -1) && 00805 (bounds[2*(ifu_nr-1)+1] != -1) && (punused_ifus[j] == 0)) { 00806 // IFU is valid 00807 cpl_error_reset(); 00808 00809 // calculate WCS 00810 kmo_calc_wcs_gd(main_header, sub_header, ifu_nr, gd); 00811 00812 // reconstruct data 00813 kmo_reconstruct_sci_image(ifu_nr, bounds[2*(ifu_nr-1)], 00814 bounds[2*(ifu_nr-1)+1], combined_data, combined_noise, 00815 img_dark, img_dark_noise, img_flat, img_flat_noise, 00816 xcal, ycal, lcal, &gd, calTimestamp, calAngles, 00817 fn_lut, &cube_data, &cube_noise, flux, 0, 00818 NULL, NULL, NULL); 00819 } else { 00820 // IFU is invalid 00821 cpl_error_reset(); 00822 } 00823 00824 /* Save output */ 00825 extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_DATA); 00826 00827 kmclipm_update_property_string(sub_header, EXTNAME, extname, 00828 "FITS extension name"); 00829 cpl_free(extname); 00830 00831 // store cube and sub header into array for later 00832 stored_data_cubes[ifu_nr - 1] = cube_data; 00833 stored_sub_data_headers[ifu_nr - 1] = sub_header; 00834 00835 if (process_noise) { 00836 sub_header=cpl_propertylist_duplicate( 00837 stored_sub_data_headers[ifu_nr - 1]); 00838 extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_NOISE); 00839 kmclipm_update_property_string(sub_header, EXTNAME, extname, 00840 "FITS extension name"); 00841 cpl_free(extname); 00842 00843 stored_noise_cubes[ifu_nr - 1] = cube_noise; 00844 stored_sub_noise_headers[ifu_nr - 1] = sub_header; 00845 } 00846 cpl_image_delete(data_ifu); data_ifu = NULL; 00847 cpl_image_delete(noise_ifu); noise_ifu = NULL; 00848 cube_data = NULL; 00849 cube_noise = NULL; 00850 } 00851 00852 /* Free memory */ 00853 cpl_image_delete(combined_data); 00854 cpl_image_delete(xcal); 00855 cpl_image_delete(ycal); 00856 cpl_image_delete(lcal); 00857 cpl_image_delete(img_dark); 00858 cpl_image_delete(img_flat); 00859 cpl_image_delete(bad_pix_mask); 00860 if (process_noise) { 00861 cpl_image_delete(combined_noise); 00862 cpl_image_delete(img_dark_noise); 00863 cpl_image_delete(img_flat_noise); 00864 } 00865 cpl_msg_indent_less() ; 00866 } 00867 cpl_vector_delete(calAngles) ; 00868 cpl_free(fn_lut) ; 00869 cpl_free(bounds); 00870 cpl_array_delete(calTimestamp); 00871 00872 /* 00873 cpl_frameset_delete(frameset_sky) ; 00874 cpl_free(suffix) ; 00875 kmo_free_unused_ifus(unused_ifus); 00876 cpl_propertylist_delete(main_header); 00877 cpl_free(stored_data_cubes); 00878 cpl_free(stored_noise_cubes); 00879 cpl_free(stored_data_images); 00880 cpl_free(stored_noise_images); 00881 cpl_free(stored_sub_data_headers); 00882 cpl_free(stored_sub_noise_headers); 00883 if (has_flat_edge) cpl_free(edge_table_sky) ; 00884 */ 00885 00886 ranges = kmo_identify_ranges(ranges_txt); 00887 00888 /* Collapse cubes using rejection */ 00889 cpl_msg_info(__func__, "Collapse cubes"); 00890 for (det_nr = 1; det_nr <= ne; det_nr++) { 00891 00892 /* Compute only one detector */ 00893 if (reduce_det != 0 && det_nr != reduce_det) continue ; 00894 00895 cpl_msg_info(__func__, "Processing detector No. %d", det_nr); 00896 cpl_msg_indent_more() ; 00897 00898 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00899 ifu_nr = (det_nr-1)*KMOS_IFUS_PER_DETECTOR + j + 1; 00900 00901 punused_ifus=cpl_array_get_data_int_const( 00902 unused_ifus[det_nr-1]); 00903 if (punused_ifus[j] == 0) { 00904 if (stored_sub_data_headers[ifu_nr-1] != NULL) { 00905 // IFU is valid 00906 ifu_crpix = cpl_propertylist_get_double( 00907 stored_sub_data_headers[ifu_nr-1], CRPIX3); 00908 ifu_crval = cpl_propertylist_get_double( 00909 stored_sub_data_headers[ifu_nr-1], CRVAL3); 00910 ifu_cdelt = cpl_propertylist_get_double( 00911 stored_sub_data_headers[ifu_nr-1], CDELT3); 00912 identified_slices = kmo_identify_slices(ranges, ifu_crpix, 00913 ifu_crval, ifu_cdelt, gd.l.dim); 00914 } 00915 00916 if (stored_data_cubes[ifu_nr-1] != NULL) { 00917 kmclipm_make_image(stored_data_cubes[ifu_nr-1], 00918 stored_noise_cubes[ifu_nr-1], 00919 &stored_data_images[ifu_nr-1], 00920 &stored_noise_images[ifu_nr-1], identified_slices, 00921 cmethod, cpos_rej, cneg_rej, citer, cmax, cmin); 00922 } 00923 cpl_vector_delete(identified_slices); 00924 } else { 00925 // IFU is invalid 00926 } 00927 } 00928 cpl_msg_indent_less() ; 00929 } 00930 cpl_vector_delete(ranges); 00931 for (i = 0; i < ne * KMOS_IFUS_PER_DETECTOR; i++) { 00932 if (stored_data_cubes != NULL) { 00933 cpl_imagelist_delete(stored_data_cubes[i]); 00934 } 00935 if (stored_noise_cubes != NULL) { 00936 cpl_imagelist_delete(stored_noise_cubes[i]); 00937 } 00938 } 00939 cpl_free(stored_data_cubes); 00940 cpl_free(stored_noise_cubes); 00941 00942 // normalise all IFUs of a detector as a group. 00943 // Calculate mean of each IFU, add up and divide by number of successful 00944 // averaged IFUs. 00945 // Then divide all valid IFUs with mean value 00946 for (j = 0; j < ne; j++) { 00947 00948 /* Compute only one detector */ 00949 if (reduce_det != 0 && j+1 != reduce_det) continue ; 00950 00951 cnt = 0; 00952 mean_data = 0; 00953 for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++) { 00954 ifu_nr = j*KMOS_IFUS_PER_DETECTOR + i; 00955 if (stored_data_images[ifu_nr] != NULL) { 00956 if (cpl_image_count_rejected(stored_data_images[ifu_nr]) >= 00957 cpl_image_get_size_x(stored_data_images[ifu_nr])* 00958 cpl_image_get_size_y(stored_data_images[ifu_nr])) { 00959 /* TODO - Deallocate */ 00960 cpl_msg_error(__func__, 00961 "The collapsed, dark-subtracted image contains " 00962 "only invalid values! Probably the provided " 00963 "FLAT_SKY frames are exactly the same as the " 00964 "frames used for MASTER_DARK calculation."); 00965 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00966 return -1 ; 00967 } 00968 mean_data += cpl_image_get_mean(stored_data_images[ifu_nr]); 00969 cnt++; 00970 } 00971 } 00972 mean_data /= cnt; 00973 00974 if (mean_data != 0.0) { 00975 for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++) { 00976 ifu_nr = j*KMOS_IFUS_PER_DETECTOR + i; 00977 if (stored_data_images[ifu_nr] != NULL) { 00978 cpl_image_divide_scalar(stored_data_images[ifu_nr], 00979 mean_data); 00980 } 00981 } 00982 } else { 00983 cpl_msg_warning(__func__, 00984 "Data cannot be normalised (mean=0.0)"); 00985 } 00986 00987 if (process_noise) { 00988 if (mean_data != 0.0) { 00989 for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++) { 00990 ifu_nr = j*KMOS_IFUS_PER_DETECTOR + i; 00991 if (stored_noise_images[ifu_nr] != NULL) { 00992 cpl_image_divide_scalar(stored_noise_images[ifu_nr], 00993 mean_data); 00994 } 00995 } 00996 } else { 00997 cpl_msg_warning(__func__, 00998 "Noise cannot be normalised (mean=0.0)"); 00999 } 01000 } 01001 } 01002 01003 /* Compute qc parameters on normalised data */ 01004 qc_spat_unif = 0.0; 01005 qc_max_nonunif_id = 0 ; 01006 qc_max_dev_id = 0 ; 01007 cnt = 0; 01008 for (i = 0; i < ne * KMOS_IFUS_PER_DETECTOR; i++) { 01009 if (stored_data_images[i] != NULL) { 01010 tmp_mean = cpl_image_get_mean(stored_data_images[i]); 01011 tmp_stdev = cpl_image_get_stdev (stored_data_images[i]); 01012 01013 qc_spat_unif += pow(tmp_mean-1, 2); 01014 if (fabs(tmp_mean) > qc_max_dev) { 01015 qc_max_dev = tmp_mean-1; 01016 qc_max_dev_id = i+1; 01017 } 01018 if (fabs(tmp_stdev) > qc_max_nonunif) { 01019 qc_max_nonunif = tmp_stdev; 01020 qc_max_nonunif_id = i+1; 01021 } 01022 cnt++; 01023 } 01024 } 01025 qc_spat_unif = sqrt(qc_spat_unif / cnt); 01026 01027 /* Udate which IFUs are not used */ 01028 kmo_print_unused_ifus(unused_ifus, TRUE); 01029 kmo_set_unused_ifus(unused_ifus, main_header, "kmos_illumination"); 01030 kmo_free_unused_ifus(unused_ifus); 01031 01032 cpl_msg_info(__func__, "Save data"); 01033 kmclipm_update_property_double(main_header, QC_SPAT_UNIF, qc_spat_unif, 01034 "[adu] uniformity of illumination correction"); 01035 kmclipm_update_property_double(main_header, QC_SPAT_MAX_DEV, qc_max_dev, 01036 "[adu] max. deviation from unity"); 01037 kmclipm_update_property_int(main_header, QC_SPAT_MAX_DEV_ID, qc_max_dev_id, 01038 "[] IFU ID with max. dev. from unity"); 01039 kmclipm_update_property_double(main_header, QC_SPAT_MAX_NONUNIF, 01040 qc_max_nonunif, "[adu] max. stdev of illumination corr."); 01041 kmclipm_update_property_int(main_header, QC_SPAT_MAX_NONUNIF_ID, 01042 qc_max_nonunif_id, "[] IFU ID with max. stdev in illum. corr."); 01043 01044 if (!suppress_extension) fn_suffix = cpl_sprintf("%s", suffix); 01045 else fn_suffix = cpl_sprintf("%s", ""); 01046 cpl_free(suffix) ; 01047 01048 kmo_dfs_save_main_header(frameset, ILLUM_CORR, fn_suffix, frame, 01049 main_header, parlist, cpl_func); 01050 if (has_flat_edge) { 01051 kmo_dfs_save_main_header(frameset, SKYFLAT_EDGE, fn_suffix, frame, 01052 main_header, parlist, cpl_func); 01053 } 01054 cpl_propertylist_delete(main_header); 01055 01056 for (i = 0; i < ne * KMOS_IFUS_PER_DETECTOR; i++) { 01057 kmo_dfs_save_image(stored_data_images[i], ILLUM_CORR, fn_suffix, 01058 stored_sub_data_headers[i], 0./0.); 01059 if (process_noise) { 01060 kmo_dfs_save_image(stored_noise_images[i], ILLUM_CORR, fn_suffix, 01061 stored_sub_noise_headers[i], 0./0.); 01062 } 01063 } 01064 for (i = 0; i < ne * KMOS_IFUS_PER_DETECTOR; i++) { 01065 if (stored_data_images != NULL) { 01066 cpl_image_delete(stored_data_images[i]); 01067 } 01068 if (stored_noise_images != NULL) { 01069 cpl_image_delete(stored_noise_images[i]); 01070 } 01071 } 01072 cpl_free(stored_data_images); 01073 cpl_free(stored_noise_images); 01074 01075 for (det_nr = 1; det_nr <= ne; det_nr++) { 01076 01077 /* Compute only one detector */ 01078 if (reduce_det != 0 && det_nr != reduce_det) continue ; 01079 01080 for (ifu_nr = 0; ifu_nr < KMOS_IFUS_PER_DETECTOR; ifu_nr++) { 01081 kmclipm_update_property_int( 01082 stored_sub_data_headers[(det_nr-1)*KMOS_IFUS_PER_DETECTOR+ifu_nr], 01083 CAL_IFU_NR, ifu_nr+1+(det_nr-1)*KMOS_IFUS_PER_DETECTOR, 01084 "IFU Number {1..24}"); 01085 kmclipm_update_property_double( 01086 stored_sub_data_headers[(det_nr-1)*KMOS_IFUS_PER_DETECTOR+ifu_nr], 01087 CAL_ROTANGLE, rotangle_found, 01088 "[deg] Rotator relative to nasmyth"); 01089 if (has_flat_edge) { 01090 // save edge-parameters as product 01091 kmo_dfs_save_table(edge_table_sky[det_nr-1][ifu_nr], 01092 SKYFLAT_EDGE, fn_suffix, 01093 stored_sub_data_headers[(det_nr-1)*KMOS_IFUS_PER_DETECTOR+ifu_nr]); 01094 } 01095 } 01096 } 01097 cpl_frameset_delete(frameset_sky) ; 01098 cpl_free(fn_suffix); 01099 01100 for (i = 0; i < ne * KMOS_IFUS_PER_DETECTOR; i++) { 01101 if (stored_sub_data_headers != NULL) { 01102 cpl_propertylist_delete(stored_sub_data_headers[i]); 01103 } 01104 if (stored_sub_noise_headers != NULL) { 01105 cpl_propertylist_delete(stored_sub_noise_headers[i]); 01106 } 01107 } 01108 cpl_free(stored_sub_data_headers); 01109 cpl_free(stored_sub_noise_headers); 01110 if (edge_table_sky != NULL) { 01111 for (i = 0; i < KMOS_NR_DETECTORS; i++) { 01112 if (edge_table_sky[i] != NULL) { 01113 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01114 cpl_table_delete(edge_table_sky[i][j]); 01115 } 01116 cpl_free(edge_table_sky[i]); 01117 } 01118 } 01119 cpl_free(edge_table_sky); 01120 } 01121 return 0 ; 01122 } 01123 01126 /*----------------------------------------------------------------------------*/ 01139 /*----------------------------------------------------------------------------*/ 01140 static int kmos_illumination_check_inputs( 01141 cpl_frameset * frameset, 01142 int add_all_sky, 01143 int * dark_has_noise, 01144 int * flat_has_noise, 01145 int * ne, 01146 int * nx, 01147 int * ny, 01148 double * rotangle) 01149 { 01150 cpl_frame * frame ; 01151 cpl_propertylist * main_header ; 01152 cpl_propertylist * tmp_header ; 01153 cpl_propertylist * eh ; 01154 char * keyword ; 01155 const char * filter_id ; 01156 const char * filter_id_l ; 01157 double exptime, exptime_cur, rotangle_loc, tmp_rotangle ; 01158 cpl_error_code err ; 01159 int naxis1, naxis2, naxis1_cur, naxis2_cur, 01160 next, next_cur, i ; 01161 01162 /* Check Entries */ 01163 if (nx == NULL || ny == NULL || frameset == NULL || dark_has_noise == NULL 01164 || flat_has_noise == NULL || ne == NULL || rotangle == NULL) 01165 return -1; 01166 01167 /* Check Exptime consistency */ 01168 frame = kmo_dfs_get_frame(frameset, FLAT_SKY); 01169 /* Skip first file */ 01170 if (!add_all_sky) frame = kmo_dfs_get_frame(frameset, NULL); 01171 01172 /* Get first exptime */ 01173 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 01174 exptime = kmos_pfits_get_exptime(main_header); 01175 cpl_propertylist_delete(main_header); 01176 01177 /* Get second frame and the next */ 01178 frame = kmo_dfs_get_frame(frameset, NULL); 01179 while (frame != NULL) { 01180 /* Get exptime */ 01181 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 01182 exptime_cur = kmos_pfits_get_exptime(main_header); 01183 cpl_propertylist_delete(main_header); 01184 01185 if (fabs(exptime-exptime_cur) > 0.01) { 01186 cpl_msg_warning(__func__, "EXPTIME is not consistent") ; 01187 return 0 ; 01188 } 01189 frame = kmo_dfs_get_frame(frameset, NULL); 01190 } 01191 01192 /* Check frames numbers */ 01193 if (cpl_frameset_count_tags(frameset, FLAT_SKY) < 3) { 01194 cpl_msg_warning(cpl_func, "3 or more FLAT_SKY frames is wished"); 01195 } 01196 if (cpl_frameset_count_tags(frameset, MASTER_DARK) != 1) { 01197 cpl_msg_warning(__func__, "Need 1 MASTER_DARK") ; 01198 return 0 ; 01199 } 01200 if (cpl_frameset_count_tags(frameset, MASTER_FLAT) != 1) { 01201 cpl_msg_warning(__func__, "Need 1 MASTER_FLAT") ; 01202 return 0 ; 01203 } 01204 if (cpl_frameset_count_tags(frameset, XCAL) != 1) { 01205 cpl_msg_warning(__func__, "Need 1 XCAL") ; 01206 return 0 ; 01207 } 01208 if (cpl_frameset_count_tags(frameset, YCAL) != 1) { 01209 cpl_msg_warning(__func__, "Need 1 YCAL") ; 01210 return 0 ; 01211 } 01212 if (cpl_frameset_count_tags(frameset, LCAL) != 1) { 01213 cpl_msg_warning(__func__, "Need 1 LCAL") ; 01214 return 0 ; 01215 } 01216 if (cpl_frameset_count_tags(frameset, WAVE_BAND) != 1) { 01217 cpl_msg_warning(__func__, "Need 1 WAVE_BAND") ; 01218 return 0 ; 01219 } 01220 01221 /* filter_id, grating_id and rotator offset match all detectors */ 01222 err = CPL_ERROR_NONE ; 01223 err += kmo_check_frameset_setup(frameset, FLAT_SKY, TRUE, FALSE, TRUE); 01224 err += kmo_check_frame_setup(frameset, FLAT_SKY, XCAL, TRUE, FALSE, TRUE); 01225 err += kmo_check_frame_setup(frameset, XCAL, YCAL, TRUE, FALSE, TRUE); 01226 err += kmo_check_frame_setup(frameset, XCAL, LCAL, TRUE, FALSE, TRUE); 01227 err += kmo_check_frame_setup(frameset, XCAL, MASTER_FLAT, TRUE, FALSE,TRUE); 01228 err += kmo_check_frame_setup_md5_xycal(frameset); 01229 err += kmo_check_frame_setup_md5(frameset); 01230 if (err != CPL_ERROR_NONE) { 01231 cpl_msg_warning(__func__, "Frames are inconsistent") ; 01232 return 0 ; 01233 } 01234 01235 /* Check MASTER_DARK */ 01236 frame = kmo_dfs_get_frame(frameset, MASTER_DARK); 01237 next = cpl_frame_get_nextensions(frame); 01238 if (next != 2*KMOS_NR_DETECTORS) { 01239 cpl_msg_warning(__func__, "MASTER_DARK must have 6 extensions") ; 01240 return 0 ; 01241 } 01242 eh = cpl_propertylist_load(cpl_frame_get_filename(frame), 1); 01243 naxis1 = kmos_pfits_get_naxis1(eh) ; 01244 naxis2 = kmos_pfits_get_naxis2(eh) ; 01245 cpl_propertylist_delete(eh) ; 01246 01247 /* Check MASTER_FLAT */ 01248 frame = kmo_dfs_get_frame(frameset, MASTER_FLAT); 01249 next = cpl_frame_get_nextensions(frame); 01250 if (next % (2*KMOS_NR_DETECTORS) != 0) { 01251 cpl_msg_warning(__func__, "MASTER_FLAT must have 6*n extensions") ; 01252 return 0 ; 01253 } 01254 01255 /* Check XCAL */ 01256 frame = kmo_dfs_get_frame(frameset, XCAL) ; 01257 next = cpl_frame_get_nextensions(frame); 01258 if (next % KMOS_NR_DETECTORS != 0) { 01259 cpl_msg_warning(__func__, "XCAL must have 3*n extensions") ; 01260 return 0 ; 01261 } 01262 eh = cpl_propertylist_load(cpl_frame_get_filename(frame), 1); 01263 naxis1_cur = kmos_pfits_get_naxis1(eh) ; 01264 naxis2_cur = kmos_pfits_get_naxis2(eh) ; 01265 cpl_propertylist_delete(eh) ; 01266 if (naxis1_cur != naxis1 || naxis2_cur != naxis2) { 01267 cpl_msg_warning(__func__, "XCAL and MASTER_DARK sizes differ") ; 01268 return 0 ; 01269 } 01270 01271 /* Check YCAL */ 01272 frame = kmo_dfs_get_frame(frameset, YCAL); 01273 next_cur = cpl_frame_get_nextensions(frame); 01274 if (next_cur != next) { 01275 cpl_msg_warning(__func__, "XCAL and YCAL nb of extensions differ") ; 01276 return 0 ; 01277 } 01278 eh = cpl_propertylist_load(cpl_frame_get_filename(frame), 1); 01279 naxis1_cur = kmos_pfits_get_naxis1(eh) ; 01280 naxis2_cur = kmos_pfits_get_naxis2(eh) ; 01281 cpl_propertylist_delete(eh) ; 01282 if (naxis1_cur != naxis1 || naxis2_cur != naxis2) { 01283 cpl_msg_warning(__func__, "YCAL and MASTER_DARK sizes differ") ; 01284 return 0 ; 01285 } 01286 01287 /* Check LCAL */ 01288 frame = kmo_dfs_get_frame(frameset, LCAL); 01289 next_cur = cpl_frame_get_nextensions(frame); 01290 if (next_cur != next) { 01291 cpl_msg_warning(__func__, "XCAL and LCAL nb of extensions differ") ; 01292 return 0 ; 01293 } 01294 eh = cpl_propertylist_load(cpl_frame_get_filename(frame), 1); 01295 naxis1_cur = kmos_pfits_get_naxis1(eh) ; 01296 naxis2_cur = kmos_pfits_get_naxis2(eh) ; 01297 cpl_propertylist_delete(eh) ; 01298 if (naxis1_cur != naxis1 || naxis2_cur != naxis2) { 01299 cpl_msg_warning(__func__, "LCAL and MASTER_DARK sizes differ") ; 01300 return 0 ; 01301 } 01302 01303 tmp_header = kmo_dfs_load_primary_header(frameset, LCAL); 01304 01305 /* Check FLAT_SKY */ 01306 frame = kmo_dfs_get_frame(frameset, FLAT_SKY); 01307 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 01308 rotangle_loc = kmos_pfits_get_rotangle(main_header) ; 01309 cpl_propertylist_delete(main_header); 01310 kmclipm_strip_angle(&rotangle_loc); 01311 01312 while (frame != NULL) { 01313 next = cpl_frame_get_nextensions(frame); 01314 if (next != KMOS_NR_DETECTORS) { 01315 cpl_msg_warning(__func__, "FLAT_SKY has wrong nb of estensions") ; 01316 return 0 ; 01317 } 01318 eh = cpl_propertylist_load(cpl_frame_get_filename(frame), 1); 01319 naxis1_cur = kmos_pfits_get_naxis1(eh) ; 01320 naxis2_cur = kmos_pfits_get_naxis2(eh) ; 01321 cpl_propertylist_delete(eh) ; 01322 if (naxis1_cur != naxis1 || naxis2_cur != naxis2) { 01323 cpl_msg_warning(__func__, "FLAT_SKY and MASTER_DARK sizes differ") ; 01324 return 0 ; 01325 } 01326 01327 /* Check Lamps */ 01328 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 01329 if (kmo_check_lamp(main_header, INS_LAMP1_ST) != FALSE || 01330 kmo_check_lamp(main_header, INS_LAMP2_ST) != FALSE || 01331 kmo_check_lamp(main_header, INS_LAMP3_ST) != FALSE || 01332 kmo_check_lamp(main_header, INS_LAMP4_ST) != FALSE) { 01333 cpl_msg_warning(__func__, "Some FLAT_SKY lamps are ON") ; 01334 cpl_propertylist_delete(main_header) ; 01335 return 0 ; 01336 } 01337 01338 /* Check filters */ 01339 for (i = 1; i <= KMOS_NR_DETECTORS; i++) { 01340 /* ESO INS FILTi ID */ 01341 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, i, 01342 IFU_FILTID_POSTFIX); 01343 filter_id = cpl_propertylist_get_string(main_header, keyword); 01344 filter_id_l = cpl_propertylist_get_string(tmp_header, keyword); 01345 cpl_free(keyword); 01346 01347 if (strcmp(filter_id, "IZ") && strcmp(filter_id, "YJ") && 01348 strcmp(filter_id, "H") && strcmp(filter_id, "K") && 01349 strcmp(filter_id, "HK")) { 01350 cpl_msg_warning(__func__, 01351 "Filter ID must be 'IZ', 'YJ', 'H', 'K' or 'HK' ") ; 01352 cpl_propertylist_delete(main_header) ; 01353 cpl_propertylist_delete(tmp_header) ; 01354 return 0 ; 01355 } 01356 01357 if (strcmp(filter_id, filter_id_l)) { 01358 cpl_msg_warning(__func__, 01359 "Filter IDs in FLAT_SKY and LCAL don't match") ; 01360 cpl_propertylist_delete(main_header) ; 01361 cpl_propertylist_delete(tmp_header) ; 01362 return 0 ; 01363 } 01364 01365 /* ESO INS GRATi ID */ 01366 keyword = cpl_sprintf("%s%d%s", IFU_GRATID_PREFIX, i, 01367 IFU_GRATID_POSTFIX); 01368 filter_id = cpl_propertylist_get_string(main_header, keyword); 01369 filter_id_l = cpl_propertylist_get_string(tmp_header, keyword); 01370 cpl_free(keyword); 01371 01372 if (strcmp(filter_id, "IZ") && strcmp(filter_id, "YJ") && 01373 strcmp(filter_id, "H") && strcmp(filter_id, "K") && 01374 strcmp(filter_id, "HK")) { 01375 cpl_msg_warning(__func__, 01376 "Grating ID must be 'IZ', 'YJ', 'H', 'K' or 'HK' ") ; 01377 cpl_propertylist_delete(main_header) ; 01378 cpl_propertylist_delete(tmp_header) ; 01379 return 0 ; 01380 } 01381 if (strcmp(filter_id, filter_id_l)) { 01382 cpl_msg_warning(__func__, 01383 "Grating IDs in FLAT_SKY and LCAL don't match") ; 01384 cpl_propertylist_delete(main_header) ; 01385 cpl_propertylist_delete(tmp_header) ; 01386 return 0 ; 01387 } 01388 01389 tmp_rotangle = kmos_pfits_get_rotangle(main_header) ; 01390 kmclipm_strip_angle(&tmp_rotangle); 01391 01392 if (fabs(rotangle_loc - tmp_rotangle) > 10.0 && 01393 fabs(rotangle_loc - tmp_rotangle) < 360.-10.) { 01394 cpl_msg_warning(__func__, 01395 "OCS ROT NAANGLE of sky flats differ too much: %f %f", 01396 rotangle_loc, tmp_rotangle); 01397 cpl_propertylist_delete(main_header) ; 01398 cpl_propertylist_delete(tmp_header) ; 01399 return 0 ; 01400 } 01401 } 01402 cpl_propertylist_delete(main_header); 01403 01404 // get next FLAT_SKY frame 01405 frame = kmo_dfs_get_frame(frameset, NULL); 01406 } 01407 cpl_propertylist_delete(tmp_header); 01408 01409 /* Return */ 01410 *nx = naxis1 ; 01411 *ny = naxis2 ; 01412 *ne = next ; 01413 *rotangle = rotangle_loc ; 01414 /* TODO */ 01415 *dark_has_noise = 1 ; 01416 *flat_has_noise = 1 ; 01417 return 1 ; 01418 } 01419 01420 /*----------------------------------------------------------------------------*/ 01426 /*----------------------------------------------------------------------------*/ 01427 static cpl_table ** kmos_illumination_edge_shift_correct( 01428 cpl_image * combined_data, 01429 cpl_image * combined_noise, 01430 int process_noise, 01431 const cpl_image * bad_pix_mask, 01432 int det_nr, 01433 cpl_array * unused_ifus, 01434 const char * flat_edge_filename, 01435 double rotangle) 01436 { 01437 int middle_row ; 01438 cpl_vector ** slitlet_ids = NULL ; 01439 cpl_matrix ** edgepars = NULL ; 01440 cpl_table ** edges ; 01441 cpl_vector * shift_vec ; 01442 const int * punused_ifus ; 01443 cpl_table * edge_table_flat ; 01444 cpl_vector * edge_vec ; 01445 kmclipm_vector * kv ; 01446 float * pcombined_data ; 01447 float * pcombined_noise ; 01448 double * array_in ; 01449 double * array_out ; 01450 double tmp_rotangle, flatval, skyval, shift_val ; 01451 int ifu_nr, i, nx, ny, ix, iy, edgeNr ; 01452 01453 /* Check Entries */ 01454 01455 /* Initialise */ 01456 middle_row = 1024 ; 01457 01458 /* Get edge-edgepars from FLAT_SKY */ 01459 kmos_calc_edgepars(combined_data, unused_ifus, bad_pix_mask, det_nr, 01460 &slitlet_ids, &edgepars); 01461 if (cpl_error_get_code() != CPL_ERROR_NONE) { 01462 cpl_msg_error(__func__, "Cannot compute edges parameters") ; 01463 return NULL ; 01464 } 01465 01466 /* Copy edgepars to table for saving later on */ 01467 edges = kmo_edgepars_to_table(slitlet_ids, edgepars); 01468 if (edgepars != NULL) { 01469 for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++) 01470 cpl_matrix_delete(edgepars[i]); 01471 cpl_free(edgepars); 01472 } 01473 if (slitlet_ids != NULL) { 01474 for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++) 01475 cpl_vector_delete(slitlet_ids[i]); 01476 cpl_free(slitlet_ids); 01477 } 01478 01479 /* Correlate FLAT_EDGE and SKYFLAT_EDGE */ 01480 shift_vec = cpl_vector_new(KMOS_IFUS_PER_DETECTOR); 01481 for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++) { 01482 ifu_nr = (det_nr-1)*KMOS_IFUS_PER_DETECTOR + i + 1; 01483 punused_ifus = cpl_array_get_data_int_const(unused_ifus); 01484 if (punused_ifus[i] == 0) { 01485 edge_table_flat = kmclipm_cal_table_load(flat_edge_filename, 01486 ifu_nr, rotangle, 0, &tmp_rotangle); 01487 /* Shift values for each IFU by comparing edge parameters */ 01488 if (edge_table_flat != NULL) { 01489 edge_vec = cpl_vector_new(2*KMOS_SLITLET_X); 01490 for (edgeNr = 0; edgeNr < 2*KMOS_SLITLET_X; edgeNr++) { 01491 flatval = kmo_calc_fitted_slitlet_edge(edge_table_flat, 01492 edgeNr, middle_row); 01493 skyval = kmo_calc_fitted_slitlet_edge(edges[i], edgeNr, 01494 middle_row); 01495 cpl_vector_set(edge_vec, edgeNr, flatval-skyval); 01496 } 01497 cpl_table_delete(edge_table_flat); 01498 01499 /* Reject deviating edge-differences */ 01500 kv = kmclipm_vector_create(edge_vec); 01501 kmclipm_reject_deviant(kv, 3, 3, NULL, NULL); 01502 01503 /* Set shift value for each IFU */ 01504 cpl_vector_set(shift_vec, i, 01505 kmclipm_vector_get_median(kv, KMCLIPM_ARITHMETIC)); 01506 kmclipm_vector_delete(kv); 01507 } else { 01508 cpl_vector_set(shift_vec, i, 0.0) ; 01509 } 01510 } else { 01511 cpl_vector_set(shift_vec, i, 0.0) ; 01512 } 01513 } 01514 01515 /* Take median of all IFU-shift-values */ 01516 shift_val = -cpl_vector_get_median(shift_vec); 01517 cpl_vector_delete(shift_vec); 01518 01519 cpl_msg_info(__func__, "Shift detector %d by %g pixels", det_nr, shift_val); 01520 nx = cpl_image_get_size_x(combined_data), 01521 ny = cpl_image_get_size_x(combined_data), 01522 pcombined_data = cpl_image_get_data_float(combined_data) ; 01523 if (process_noise) { 01524 pcombined_noise = cpl_image_get_data_float(combined_noise); 01525 } 01526 01527 array_in = cpl_calloc(nx, sizeof(double)) ; 01528 /* Apply shift - Cubic spline */ 01529 for (iy = 0; iy < ny; iy++) { 01530 for (ix = 0; ix < nx; ix++) array_in[ix] = pcombined_data[ix+iy*nx]; 01531 array_out = cubicspline_reg_reg(nx, 0., 1., array_in, nx, shift_val, 01532 1.0, NATURAL); 01533 for (ix = 0; ix < nx; ix++) pcombined_data[ix+iy*nx] = array_out[ix]; 01534 cpl_free(array_out); 01535 01536 if (process_noise) { 01537 for (ix = 0; ix < nx; ix++) array_in[ix]=pcombined_noise[ix+iy*nx]; 01538 array_out = cubicspline_reg_reg(nx, 0., 1., array_in, nx, shift_val, 01539 1.0, NATURAL); 01540 for (ix = 0; ix < nx; ix++) pcombined_noise[ix+iy*nx]=array_out[ix]; 01541 cpl_free(array_out); 01542 } 01543 } 01544 cpl_free(array_in); 01545 return edges ; 01546 } 01547 01548
1.7.6.1