KMOS Pipeline Reference Manual
1.3.0
|
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 #include <string.h> 00028 #include <math.h> 00029 00030 #include <cpl.h> 00031 00032 #include "kmo_utils.h" 00033 #include "kmo_priv_flat.h" 00034 #include "kmo_priv_functions.h" 00035 #include "kmo_dfs.h" 00036 #include "kmo_error.h" 00037 #include "kmo_constants.h" 00038 #include "kmo_cpl_extensions.h" 00039 #include "kmo_debug.h" 00040 00041 /*----------------------------------------------------------------------------- 00042 * Functions prototypes 00043 *----------------------------------------------------------------------------*/ 00044 00045 static int kmo_flat_create(cpl_plugin *); 00046 static int kmo_flat_exec(cpl_plugin *); 00047 static int kmo_flat_destroy(cpl_plugin *); 00048 static int kmo_flat(cpl_parameterlist *, cpl_frameset *); 00049 00050 /*----------------------------------------------------------------------------- 00051 * Static variables 00052 *----------------------------------------------------------------------------*/ 00053 00054 static char kmo_flat_description[] = 00055 "This recipe creates the master flat field and calibration frames needed for\n" 00056 "spatial calibration for all three detectors. It must be called after the \n" 00057 "kmo_dark-recipe, which generates a bad pixel mask (badpixel_dark.fits). The\n" 00058 "bad pixel mask will be updated in this recipe.\n" 00059 "As input at least 3 dark frames, 3 frames with the flat lamp on are\n" 00060 "recommended. Additionally a badpixel mask from kmo_dark is required.\n" 00061 "\n" 00062 "The badpixel mask contains 0 for bad pixels and 1 for good ones.\n" 00063 "\n" 00064 "The structure of the resulting xcal and ycal frames is quite complex since\n" 00065 "the arrangement of the IFUs isn't just linear on the detector. Basically the\n" 00066 "integer part of the calibration data shows the offset of each pixels centre\n" 00067 "in mas (Milli arcsec) from the field centre. The viewing of an IFU is\n" 00068 "2800 mas (14pix*0.2arcsec/pix). So the values in these two frames will vary\n" 00069 "between +/-1500 (One would expect 1400, but since the slitlets aren't\n" 00070 "expected to be exactly vertical, the values can even go up to around 1500).\n" 00071 "Additionally in the calibration data in y-direction the decimal part of the\n" 00072 "data designates the IFU to which the slitlet corresponds to (for each\n" 00073 "detector from 1 to 8).\n" 00074 "Because of the irregular arrangement of the IFUs not all x-direction\n" 00075 "calibration data is found in xcal and similarly not all y-direction\n" 00076 "calibration data is located in ycal. For certain IFUs they are switched\n" 00077 " and/or flipped in x- or y-direction:\n" 00078 "For IFUs 1,2,3,4,13,14,15,16: x- and y- data is switched\n" 00079 "For IFUs 17,18,19,20: y-data is flipped \n" 00080 "For IFUs 21,22,23,24: x-data is flipped \n" 00081 "For IFUs 5,6,7,8,9,10,11,12: x- and y- data is switched and\n" 00082 " x- and y- data is flipped\n" 00083 "\n" 00084 "Furthermore frames can be provided for several rotator angles. In this case\n" 00085 "the resulting calibration frames for each detector are repeatedly saved as \n" 00086 "extension for every angle.\n" 00087 "\n" 00088 "Advanced features:\n" 00089 "------------------\n" 00090 "To create the badpixel mask the edges of all slitlets are fitted to a\n" 00091 "polynomial. Since it can happen that some of these fits (3 detectors\n" 00092 "8 IFUs * 14slitlets * 2 edges (left and right edge of slitlet)= 672 edges)\n" 00093 "fail, the fit parameters are themselves fitted again to detect any outliers.\n" 00094 "By default, the parameters of all left and all right edges are grouped\n" 00095 "individually and then fitted using chebyshev polynomials. The advantage of\n" 00096 "a chebyshev polynomial is, that it consists in fact of a series of\n" 00097 "orthogonal polynomials. This implies that the parameters of the polynomials\n" 00098 "are independent. This fact predestines the use of chebyshev polynomials\n" 00099 "for our case. So each individual parameter can be examined independently.\n" 00100 "The reason why the left and right edges are fitted individually is that\n" 00101 "there is a systematic pattern specific to these groups. The reason for\n" 00102 "this pattern is probably to be found in the optical path the light is\n" 00103 "traversing.\n" 00104 "\n" 00105 "The behaviour of this fitting step can be influenced via environment\n" 00106 "parameters:\n" 00107 "* KF_ALLPARS (default: 1)\n" 00108 " When set to 1 all coefficients of the polynomial of an edge are to be\n" 00109 " corrected, also when just one of these coefficients is an outlier. When\n" 00110 " set to 0 only the outlier is to be corrected.\n" 00111 "* KF_CH (default: 1)\n" 00112 " When set to 1 chebyshev polynomials are used to fit the fitted parameters.\n" 00113 " When set to 0 normal polynomials are used.\n" 00114 "* KF_SIDES (default: 2)\n" 00115 " This variable can either be set to 1 or 2. When set to 2 the left and\n" 00116 " right edges are examined individually. When set to 1 all edges are\n" 00117 " examined as one group.\n" 00118 "* KF_FACTOR(default: 4)\n" 00119 " This factor defines the threshold factor. All parameters deviating \n" 00120 " KF_FACTOR*stddev are to be corrected\n" 00121 "\n" 00122 "BASIC PARAMETERS:\n" 00123 "-----------------\n" 00124 "--badpix_thresh\n" 00125 "The threshold level to mark pixels as bad on the dark subtracted frames [%]" 00126 "\n" 00127 "--surrounding_pixels\n" 00128 "The amount of bad pixels to surround a specific pixel, to let it be marked\n" 00129 "bad as well.\n" 00130 "\n" 00131 "--cmethod\n" 00132 "Following methods of frame combination are available:\n" 00133 " * 'ksigma' (Default)\n" 00134 " An iterative sigma clipping. For each position all pixels in the\n" 00135 " spectrum are examined. If they deviate significantly, they will be\n" 00136 " rejected according to the conditions:\n" 00137 " val > mean + stdev * cpos_rej\n" 00138 " and\n" 00139 " val < mean - stdev * cneg_rej\n" 00140 " where --cpos_rej, --cneg_rej and --citer are the configuration\n" 00141 " parameters. In the first iteration median and percentile level are used.\n" 00142 "\n" 00143 " * 'median'\n" 00144 " At each pixel position the median is calculated.\n" 00145 "\n" 00146 " * 'average'\n" 00147 " At each pixel position the average is calculated.\n" 00148 "\n" 00149 " * 'sum'\n" 00150 " At each pixel position the sum is calculated.\n" 00151 "\n" 00152 " * 'min_max'\n" 00153 " The specified number of min and max pixel values will be rejected.\n" 00154 " --cmax and --cmin apply to this method.\n" 00155 "\n" 00156 "ADVANCED PARAMETERS\n" 00157 "-------------------\n" 00158 "--cpos_rej\n" 00159 "--cneg_rej\n" 00160 "--citer\n" 00161 "see --cmethod='ksigma'\n" 00162 "\n" 00163 "--cmax\n" 00164 "--cmin\n" 00165 "see --cmethod='min_max'\n" 00166 "\n" 00167 "--suppress_extension\n" 00168 "If set to TRUE, the arbitrary filename extensions are supressed. If\n" 00169 "multiple products with the same category are produced, they will be\n" 00170 "numered consecutively starting from 0.\n" 00171 "\n" 00172 "-------------------------------------------------------------------------------\n" 00173 " Input files:\n" 00174 " DO CATG Type Explanation Required #Frames\n" 00175 " ------- ----- ----------- -------- -------\n" 00176 " FLAT_ON RAW Flatlamp-on exposures Y 1-n \n" 00177 " (at least 3 frames recommended) \n" 00178 " FLAT_OFF RAW Flatlamp-off exposures Y 1-n \n" 00179 " (at least 3 frames recommended) \n" 00180 " BADPIXEL_DARK B2D Bad pixel mask Y 1 \n" 00181 "\n" 00182 " Output files:\n" 00183 " DO CATG Type Explanation\n" 00184 " ------- ----- -----------\n" 00185 " MASTER_FLAT F2D Normalised flat field\n" 00186 " (6 extensions: alternating data & noise\n" 00187 " BADPIXEL_FLAT B2D Updated bad pixel mask (3 Extensions)\n" 00188 " XCAL F2D Calibration frame 1 (3 Extensions)\n" 00189 " YCAL F2D Calibration frame 2 (3 Extensions)\n" 00190 " FLAT_EDGE F2L Frame containing parameters of fitted \n" 00191 " slitlets of all IFUs of all detectors\n" 00192 "---------------------------------------------------------------------------" 00193 "\n"; 00194 00195 /*----------------------------------------------------------------------------- 00196 * Functions code 00197 *----------------------------------------------------------------------------*/ 00198 00205 /*----------------------------------------------------------------------------*/ 00214 /*----------------------------------------------------------------------------*/ 00215 int cpl_plugin_get_info(cpl_pluginlist *list) 00216 { 00217 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe); 00218 cpl_plugin *plugin = &recipe->interface; 00219 00220 cpl_plugin_init(plugin, 00221 CPL_PLUGIN_API, 00222 KMOS_BINARY_VERSION, 00223 CPL_PLUGIN_TYPE_RECIPE, 00224 "kmo_flat", 00225 "Create master flatfield frame and badpixel map", 00226 kmo_flat_description, 00227 "Alex Agudo Berbel", 00228 "usd-help@eso.org", 00229 kmos_get_license(), 00230 kmo_flat_create, 00231 kmo_flat_exec, 00232 kmo_flat_destroy); 00233 00234 cpl_pluginlist_append(list, plugin); 00235 00236 return 0; 00237 } 00238 00239 /*----------------------------------------------------------------------------*/ 00247 /*----------------------------------------------------------------------------*/ 00248 static int kmo_flat_create(cpl_plugin *plugin) 00249 { 00250 cpl_recipe *recipe; 00251 cpl_parameter *p; 00252 00253 /* Check that the plugin is part of a valid recipe */ 00254 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00255 recipe = (cpl_recipe *)plugin; 00256 else 00257 return -1; 00258 00259 /* Create the parameters list in the cpl_recipe object */ 00260 recipe->parameters = cpl_parameterlist_new(); 00261 00262 /* Fill the parameters list */ 00263 00264 /* --badpix_thresh */ 00265 p = cpl_parameter_new_value("kmos.kmo_flat.badpix_thresh", 00266 CPL_TYPE_INT, 00267 "The threshold level to mark pixels as bad on the dark subtracted frames [%].", 00268 "kmos.kmo_flat", 35); 00269 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "badpix_thresh"); 00270 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00271 cpl_parameterlist_append(recipe->parameters, p); 00272 00273 /* --surrounding_pixels */ 00274 p = cpl_parameter_new_value("kmos.kmo_flat.surrounding_pixels", 00275 CPL_TYPE_INT, 00276 "The amount of bad pixels to surround a specific pixel, to let it be marked bad as well.", 00277 "kmos.kmo_flat", 5); 00278 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "surrounding_pixels"); 00279 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00280 cpl_parameterlist_append(recipe->parameters, p); 00281 00282 /* --suppress_extension */ 00283 p = cpl_parameter_new_value("kmos.kmo_flat.suppress_extension", 00284 CPL_TYPE_BOOL, 00285 "Suppress arbitrary filename extension. (TRUE (apply) or FALSE (don't apply)", 00286 "kmos.kmo_flat", FALSE); 00287 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension"); 00288 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00289 cpl_parameterlist_append(recipe->parameters, p); 00290 00291 return kmo_combine_pars_create(recipe->parameters, "kmos.kmo_flat", 00292 DEF_REJ_METHOD, FALSE); 00293 } 00294 00295 /*----------------------------------------------------------------------------*/ 00301 /*----------------------------------------------------------------------------*/ 00302 static int kmo_flat_exec(cpl_plugin *plugin) 00303 { 00304 cpl_recipe *recipe; 00305 00306 /* Get the recipe out of the plugin */ 00307 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00308 recipe = (cpl_recipe *)plugin; 00309 else return -1; 00310 00311 return kmo_flat(recipe->parameters, recipe->frames); 00312 } 00313 00314 /*----------------------------------------------------------------------------*/ 00320 /*----------------------------------------------------------------------------*/ 00321 static int kmo_flat_destroy(cpl_plugin *plugin) 00322 { 00323 cpl_recipe *recipe; 00324 00325 /* Get the recipe out of the plugin */ 00326 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00327 recipe = (cpl_recipe *)plugin; 00328 else return -1 ; 00329 00330 cpl_parameterlist_delete(recipe->parameters); 00331 return 0 ; 00332 } 00333 00334 /*----------------------------------------------------------------------------*/ 00348 /*----------------------------------------------------------------------------*/ 00349 static int kmo_flat(cpl_parameterlist *parlist, cpl_frameset *frameset) 00350 { 00351 cpl_imagelist *det_lamp_on = NULL, 00352 *det_lamp_off = NULL; 00353 00354 cpl_image *img_in = NULL, 00355 *combined_data_on = NULL, 00356 *combined_noise_on = NULL, 00357 *combined_data_off = NULL, 00358 *combined_noise_off = NULL, 00359 *bad_pix_mask_flat = NULL, 00360 *bad_pix_mask_dark = NULL, 00361 *xcal = NULL, 00362 *ycal = NULL; 00363 00364 cpl_image **stored_flat = NULL, 00365 **stored_noise = NULL, 00366 **stored_badpix = NULL, 00367 **stored_xcal = NULL, 00368 **stored_ycal = NULL; 00369 00370 cpl_frame *frame = NULL; 00371 cpl_frameset ** angle_frameset = NULL; 00372 00373 int ret_val = 0, 00374 nr_devices = 0, 00375 sx = 0, 00376 cmax = 0, 00377 cmin = 0, 00378 citer = 0, 00379 surrounding_pixels = 0, 00380 badpix_thresh = 0, 00381 nx = 0, 00382 ny = 0, 00383 nz = 0, 00384 *stored_qc_flat_sat = NULL, 00385 *bounds = NULL, 00386 **total_bounds = NULL, 00387 nr_bad_pix = 0, 00388 ndit = 0, 00389 suppress_extension = FALSE, 00390 nr_sat = 0, 00391 nr_angles = 0, 00392 i = 0, j = 0, ax = 0, a = 0; 00393 cpl_size ix = 0, iy = 0; 00394 00395 double cpos_rej = 0.0, 00396 cneg_rej = 0.0, 00397 gain = 0.0, 00398 exptime = 0.0, 00399 *stored_qc_flat_eff = NULL, 00400 *stored_qc_flat_sn = NULL, 00401 mean_data = 0.0, 00402 mean_noise = 0.0, 00403 *stored_gapmean = NULL, 00404 *stored_gapsdv = NULL, 00405 *stored_gapmaxdev = NULL, 00406 *stored_slitmean = NULL, 00407 *stored_slitsdv = NULL, 00408 *stored_slitmaxdev = NULL; 00409 00410 const char *cmethod = NULL; 00411 00412 char *extname = NULL, 00413 filename_flat[256], 00414 filename_xcal[256], 00415 filename_ycal[256], 00416 filename_bad[256], 00417 filename_edge[256], 00418 *suffix = NULL, 00419 *fn_suffix = NULL, 00420 *tmpstr = NULL, 00421 *readmode = NULL; 00422 00423 cpl_propertylist *main_header = NULL, 00424 *main_header_xcal = NULL, 00425 *sub_header = NULL; 00426 00427 cpl_table ***edge_table = NULL; 00428 00429 main_fits_desc desc1, desc2; 00430 00431 cpl_array **unused_ifus_before = NULL, 00432 **unused_ifus_after = NULL; 00433 00434 cpl_error_code *spec_found = NULL; 00435 00436 char *fn_flat = "flat_tmp.fits", 00437 *fn_noise = "flat_noise_tmp.fits", 00438 *fn_badpix = "badpix_tmp.fits"; 00439 unsigned int save_mode = CPL_IO_CREATE; // at first files must be created 00440 00441 KMO_TRY 00442 { 00443 00444 kmo_init_fits_desc(&desc1); 00445 kmo_init_fits_desc(&desc2); 00446 00447 KMO_TRY_ASSURE((parlist != NULL) && (frameset != NULL), 00448 CPL_ERROR_NULL_INPUT, "Not all input data is provided!"); 00449 00450 KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, FLAT_OFF) >= 1, 00451 CPL_ERROR_NULL_INPUT, 00452 "At least 1 FLAT_OFF frame is needed (3 or more recommended)"); 00453 00454 KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, FLAT_ON) >= 1, 00455 CPL_ERROR_NULL_INPUT, 00456 "At least 1 FLAT_ON frame is needed (3 or more recommended)"); 00457 00458 if (cpl_frameset_count_tags(frameset, FLAT_OFF) < 3) { 00459 cpl_msg_warning(cpl_func, 00460 "It is recommended to provide at least 3 FLAT_OFF frames"); 00461 } 00462 00463 if (cpl_frameset_count_tags(frameset, FLAT_ON) < 3) { 00464 cpl_msg_warning(cpl_func, 00465 "It is recommended to provide at least 3 FLAT_ON frames") ; 00466 } 00467 00468 KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, BADPIXEL_DARK) == 1, 00469 CPL_ERROR_NULL_INPUT, "BADPIXEL_DARK frame must be provided"); 00470 00471 KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_flat") == 1, 00472 CPL_ERROR_ILLEGAL_INPUT,"Cannot identify RAW and CALIB frames"); 00473 00474 /* ------------ get parameters ------------ */ 00475 cpl_msg_info("", "--- Parameter setup for kmo_flat ----------"); 00476 00477 surrounding_pixels = kmo_dfs_get_parameter_int(parlist, 00478 "kmos.kmo_flat.surrounding_pixels"); 00479 KMO_TRY_CHECK_ERROR_STATE(); 00480 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_print_parameter_help(parlist, 00481 "kmos.kmo_flat.surrounding_pixels")); 00482 00483 badpix_thresh = kmo_dfs_get_parameter_int(parlist, 00484 "kmos.kmo_flat.badpix_thresh"); 00485 KMO_TRY_CHECK_ERROR_STATE(); 00486 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_print_parameter_help(parlist, 00487 "kmos.kmo_flat.badpix_thresh")); 00488 00489 suppress_extension = kmo_dfs_get_parameter_bool(parlist, 00490 "kmos.kmo_flat.suppress_extension"); 00491 KMO_TRY_CHECK_ERROR_STATE(); 00492 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_print_parameter_help(parlist, 00493 "kmos.kmo_flat.suppress_extension")); 00494 00495 KMO_TRY_ASSURE((suppress_extension == TRUE) || 00496 (suppress_extension == FALSE), 00497 CPL_ERROR_ILLEGAL_INPUT, 00498 "suppress_extension must be TRUE or FALSE!"); 00499 00500 KMO_TRY_EXIT_IF_ERROR( 00501 kmo_combine_pars_load(parlist, "kmos.kmo_flat", &cmethod, &cpos_rej, 00502 &cneg_rej, &citer, &cmin, &cmax, FALSE)); 00503 00504 cpl_msg_info("", "-------------------------------------------"); 00505 00506 /* check BADPIXEL_DARK */ 00507 KMO_TRY_EXIT_IF_NULL(frame = kmo_dfs_get_frame(frameset,BADPIXEL_DARK)); 00508 desc2 = kmo_identify_fits_header(cpl_frame_get_filename(frame)); 00509 KMO_TRY_CHECK_ERROR_STATE(); 00510 00511 KMO_TRY_ASSURE((desc2.nr_ext == 3) && (desc2.ex_badpix == TRUE) && 00512 (desc2.fits_type == b2d_fits) && 00513 (desc2.frame_type == detector_frame), CPL_ERROR_ILLEGAL_INPUT, 00514 "BADPIXEL_DARK isn't in the correct format"); 00515 00516 nx = desc2.naxis1; 00517 ny = desc2.naxis2; 00518 nz = desc2.naxis3; 00519 00520 KMO_TRY_ASSURE((surrounding_pixels >= 0) && (surrounding_pixels <= 8), 00521 CPL_ERROR_ILLEGAL_INPUT, 00522 "surrounding_pixels must be between 0 and 8!"); 00523 00524 KMO_TRY_ASSURE((badpix_thresh >= 0) && (badpix_thresh <= 100), 00525 CPL_ERROR_ILLEGAL_INPUT, 00526 "badpix_thresh must be between 0 and 100%%!"); 00527 00528 // ------------ check EXPTIME, NDIT, READMODE and lamps ------------ 00529 // EXPTIME, NDIT, READMODE: the same for all frames 00530 // lamps: at least 3 lamp on and 3 lamp off frames 00531 KMO_TRY_EXIT_IF_NULL(frame = kmo_dfs_get_frame(frameset, FLAT_OFF)); 00532 00533 KMO_TRY_EXIT_IF_NULL(main_header = kmclipm_propertylist_load( 00534 cpl_frame_get_filename(frame), 0)); 00535 ndit = cpl_propertylist_get_int(main_header, NDIT); 00536 KMO_TRY_CHECK_ERROR_STATE("NDIT keyword in main header missing"); 00537 exptime = cpl_propertylist_get_double(main_header, EXPTIME); 00538 KMO_TRY_CHECK_ERROR_STATE("EXPTIME keyword in main header missing"); 00539 readmode =cpl_strdup(cpl_propertylist_get_string(main_header,READMODE)); 00540 KMO_TRY_CHECK_ERROR_STATE("ESO DET READ CURNAME keyword is missing"); 00541 cpl_propertylist_delete(main_header); main_header = NULL; 00542 00543 /* Loop through FLAT_OFF frames */ 00544 while (frame != NULL) { 00545 KMO_TRY_EXIT_IF_NULL( 00546 main_header = kmclipm_propertylist_load( 00547 cpl_frame_get_filename(frame), 0)); 00548 00549 KMO_TRY_ASSURE(cpl_propertylist_get_int(main_header, NDIT) == ndit, 00550 CPL_ERROR_ILLEGAL_INPUT, 00551 "NDIT isn't the same for all frames: (is %d and %d).", 00552 cpl_propertylist_get_int(main_header, NDIT), ndit); 00553 00554 KMO_TRY_ASSURE( 00555 cpl_propertylist_get_double(main_header, EXPTIME)==exptime, 00556 CPL_ERROR_ILLEGAL_INPUT, 00557 "EXPTIME isn't the same for all frames: (is %g and %g).", 00558 cpl_propertylist_get_double(main_header, EXPTIME), exptime); 00559 00560 KMO_TRY_ASSURE(strcmp(cpl_propertylist_get_string(main_header, 00561 READMODE), readmode) == 0, 00562 CPL_ERROR_ILLEGAL_INPUT, 00563 "ESO DET READ CURNAME isn't constant: (is %s and %s).", 00564 cpl_propertylist_get_string(main_header, READMODE), 00565 readmode); 00566 00567 desc1 = kmo_identify_fits_header(cpl_frame_get_filename(frame)); 00568 KMO_TRY_CHECK_ERROR_STATE_MSG( 00569 cpl_sprintf("File (%s) doesn't seem to be in KMOS-format", 00570 cpl_frame_get_filename(frame))); 00571 00572 KMO_TRY_ASSURE(desc1.fits_type == raw_fits, 00573 CPL_ERROR_ILLEGAL_INPUT, 00574 "File hasn't correct data type (%s must be a raw)", 00575 cpl_frame_get_filename(frame)); 00576 00577 KMO_TRY_ASSURE((desc1.naxis1 == nx) && (desc1.naxis2 == ny) && 00578 (desc1.naxis3 == nz), CPL_ERROR_ILLEGAL_INPUT, 00579 "File (%s) has wrong dimensions! (x,y): (%d,%d) vs (%d,%d)", 00580 cpl_frame_get_filename(frame), desc1.naxis1, desc1.naxis2, 00581 nx, ny); 00582 00583 /* Assure that arc lamps are off */ 00584 KMO_TRY_ASSURE((kmo_check_lamp(main_header, INS_LAMP1_ST) == FALSE) 00585 && (kmo_check_lamp(main_header, INS_LAMP2_ST) == FALSE), 00586 CPL_ERROR_ILLEGAL_INPUT, 00587 "Arc lamps must be switched off (%s)!", 00588 cpl_frame_get_filename(frame)); 00589 00590 /* Check if flat lamps are off */ 00591 if ((kmo_check_lamp(main_header, INS_LAMP3_ST) == TRUE) || 00592 (kmo_check_lamp(main_header, INS_LAMP4_ST) == TRUE)) { 00593 if (!(strcmp(cpl_propertylist_get_string(main_header, 00594 "ESO INS FILT1 ID"), "Block") == 0) || 00595 !(strcmp(cpl_propertylist_get_string(main_header, 00596 "ESO INS FILT2 ID"), "Block") == 0) || 00597 !(strcmp(cpl_propertylist_get_string(main_header, 00598 "ESO INS FILT3 ID"), "Block") == 0)) { 00599 cpl_msg_warning(__func__, "At least one flat lamp is on"); 00600 } 00601 } 00602 kmo_free_fits_desc(&desc1); 00603 00604 /* Get next FLAT_OFF frame */ 00605 frame = kmo_dfs_get_frame(frameset, NULL); 00606 KMO_TRY_CHECK_ERROR_STATE(); 00607 00608 cpl_propertylist_delete(main_header); main_header = NULL; 00609 } 00610 00611 /* Loop through FLAT_ON frames */ 00612 KMO_TRY_EXIT_IF_NULL(frame = kmo_dfs_get_frame(frameset, FLAT_ON)); 00613 while (frame != NULL) { 00614 KMO_TRY_EXIT_IF_NULL(main_header = kmclipm_propertylist_load( 00615 cpl_frame_get_filename(frame), 0)); 00616 00617 KMO_TRY_ASSURE(cpl_propertylist_get_int(main_header, NDIT) == ndit, 00618 CPL_ERROR_ILLEGAL_INPUT, 00619 "NDIT isn't the same for all frames: (is %d and %d).", 00620 cpl_propertylist_get_int(main_header, NDIT), ndit); 00621 00622 KMO_TRY_ASSURE( 00623 cpl_propertylist_get_double(main_header, EXPTIME)==exptime, 00624 CPL_ERROR_ILLEGAL_INPUT, 00625 "EXPTIME isn't the same for all frames: (is %g and %g).", 00626 cpl_propertylist_get_double(main_header, EXPTIME), exptime); 00627 00628 KMO_TRY_ASSURE(strcmp(cpl_propertylist_get_string(main_header, 00629 READMODE), readmode) == 0, 00630 CPL_ERROR_ILLEGAL_INPUT, 00631 "ESO DET READ CURNAME isn't constant: (is %s and %s).", 00632 cpl_propertylist_get_string(main_header,READMODE),readmode); 00633 00634 desc1 = kmo_identify_fits_header(cpl_frame_get_filename(frame)); 00635 KMO_TRY_CHECK_ERROR_STATE_MSG( 00636 cpl_sprintf("File (%s) doesn't seem to be in KMOS-format", 00637 cpl_frame_get_filename(frame))); 00638 00639 KMO_TRY_ASSURE(desc1.fits_type == raw_fits, CPL_ERROR_ILLEGAL_INPUT, 00640 "File hasn't correct data type (%s must be a raw)", 00641 cpl_frame_get_filename(frame)); 00642 00643 KMO_TRY_ASSURE((desc1.naxis1 == nx) && (desc1.naxis2 == ny) && 00644 (desc1.naxis3 == nz), CPL_ERROR_ILLEGAL_INPUT, 00645 "File (%s) has wrong dimensions (x,y): (%d,%d) vs (%d,%d)", 00646 cpl_frame_get_filename(frame), 00647 desc1.naxis1, desc1.naxis2, nx, ny); 00648 00649 /* Assure that arc lamps are off */ 00650 KMO_TRY_ASSURE((kmo_check_lamp(main_header, INS_LAMP1_ST) == FALSE) 00651 && (kmo_check_lamp(main_header, INS_LAMP2_ST) == FALSE), 00652 CPL_ERROR_ILLEGAL_INPUT, 00653 "Arc lamps must be switched off (%s)", 00654 cpl_frame_get_filename(frame)); 00655 00656 /* Assure that at least one flat lamp is on */ 00657 KMO_TRY_ASSURE((kmo_check_lamp(main_header, INS_LAMP3_ST) == TRUE) 00658 || (kmo_check_lamp(main_header, INS_LAMP4_ST) == TRUE), 00659 CPL_ERROR_ILLEGAL_INPUT, 00660 "At least one flat lamps must be switched on (%s)", 00661 cpl_frame_get_filename(frame)); 00662 kmo_free_fits_desc(&desc1); 00663 00664 /* Get next FLAT_ON frame */ 00665 frame = kmo_dfs_get_frame(frameset, NULL); 00666 KMO_TRY_CHECK_ERROR_STATE(); 00667 00668 cpl_propertylist_delete(main_header); main_header = NULL; 00669 } 00670 00671 /* -------- check filter_id, grating_id and rotator offset -------- */ 00672 /* must match for all detectors */ 00673 KMO_TRY_EXIT_IF_ERROR(kmo_check_frameset_setup(frameset, FLAT_ON, 00674 TRUE, FALSE, FALSE)); 00675 strcpy(filename_flat, MASTER_FLAT); 00676 strcpy(filename_bad, BADPIXEL_FLAT); 00677 strcpy(filename_xcal, XCAL); 00678 strcpy(filename_ycal, YCAL); 00679 strcpy(filename_edge, FLAT_EDGE); 00680 00681 KMO_TRY_EXIT_IF_NULL(frame = kmo_dfs_get_frame(frameset, FLAT_ON)); 00682 KMO_TRY_EXIT_IF_NULL(suffix = kmo_dfs_get_suffix(frame, TRUE, FALSE)); 00683 00684 cpl_msg_info("", "Detected instrument setup: %s", suffix+1); 00685 cpl_msg_info("", "(grating 1, 2 & 3)"); 00686 00687 /* ---- scan for rotator angles */ 00688 #define ANGLE_DIM 360 00689 int rotang_found[ANGLE_DIM]; 00690 int rotang_cnt[ANGLE_DIM]; 00691 for (i = 0; i < ANGLE_DIM; i++) { 00692 rotang_found[i] = 0; 00693 rotang_cnt[i] = 0; 00694 } 00695 KMO_TRY_EXIT_IF_NULL(frame = kmo_dfs_get_frame(frameset, FLAT_ON)); 00696 while (frame != NULL) { 00697 main_header = kmclipm_propertylist_load( 00698 cpl_frame_get_filename(frame), 0); 00699 if (cpl_propertylist_has(main_header, ROTANGLE)) { 00700 int rot_angle = (int) rint(cpl_propertylist_get_double( 00701 main_header, ROTANGLE)); 00702 if (rot_angle < 0) rot_angle += 360; 00703 if (rot_angle < 360 && rot_angle >= 0) rotang_cnt[rot_angle]++; 00704 } else { 00705 cpl_msg_warning(__func__, "File %s has no keyword \"ROTANGLE\"", 00706 cpl_frame_get_filename(frame)); 00707 } 00708 00709 cpl_propertylist_delete(main_header); main_header = NULL; 00710 frame = kmo_dfs_get_frame(frameset, NULL); 00711 KMO_TRY_CHECK_ERROR_STATE(); 00712 } 00713 nr_angles = 0; 00714 for (ax = 0; ax < ANGLE_DIM; ax++) { 00715 if (rotang_cnt[ax] != 0) { 00716 cpl_msg_info(__func__, "Found %d frames with rotator angle %d", 00717 rotang_cnt[ax],ax); 00718 rotang_found[nr_angles] = ax; 00719 nr_angles++; 00720 } 00721 } 00722 00723 /* Create a Frameset per different Angle */ 00724 KMO_TRY_EXIT_IF_NULL(angle_frameset = 00725 (cpl_frameset **)cpl_malloc(nr_angles * sizeof(cpl_frameset*))); 00726 for (i = 0; i < nr_angles; i++) { 00727 angle_frameset[i] = cpl_frameset_new(); 00728 } 00729 KMO_TRY_EXIT_IF_NULL(frame = kmo_dfs_get_frame(frameset, FLAT_ON)); 00730 while (frame != NULL) { 00731 main_header = kmclipm_propertylist_load(cpl_frame_get_filename( 00732 frame), 0); 00733 if (cpl_propertylist_has(main_header, ROTANGLE)) { 00734 int rot_angle = (int)rint(cpl_propertylist_get_double( 00735 main_header, ROTANGLE)); 00736 if (rot_angle < 0) rot_angle += 360; 00737 int ix = -1; 00738 for (ix = 0; ix<nr_angles; ix++) { 00739 if (rotang_found[ix] == rot_angle) { 00740 break; 00741 } 00742 } 00743 if (ix<nr_angles) { 00744 KMO_TRY_EXIT_IF_ERROR(cpl_frameset_insert( 00745 angle_frameset[ix],cpl_frame_duplicate(frame))); 00746 } 00747 } 00748 00749 cpl_propertylist_delete(main_header); main_header = NULL; 00750 frame = kmo_dfs_get_frame(frameset, NULL); 00751 KMO_TRY_CHECK_ERROR_STATE(); 00752 } 00753 00754 00755 /* -------- Allocate temporary memory */ 00756 /* Load descriptor and header of first operand */ 00757 KMO_TRY_EXIT_IF_NULL(frame = kmo_dfs_get_frame(frameset, FLAT_ON)); 00758 desc1 = kmo_identify_fits_header(cpl_frame_get_filename(frame)); 00759 KMO_TRY_CHECK_ERROR_STATE(); 00760 00761 nr_devices = desc1.nr_ext; 00762 00763 /* The frames have to be stored temporarily because the QC parameters */ 00764 /* for the main header are calculated from each detector. */ 00765 /* So they can be stored only when all detectors are processed */ 00766 KMO_TRY_EXIT_IF_NULL(stored_flat = (cpl_image**)cpl_calloc( 00767 nr_devices * nr_angles, sizeof(cpl_image*))); 00768 KMO_TRY_EXIT_IF_NULL(stored_noise = (cpl_image**)cpl_calloc( 00769 nr_devices * nr_angles, sizeof(cpl_image*))); 00770 KMO_TRY_EXIT_IF_NULL(stored_badpix = (cpl_image**)cpl_calloc( 00771 nr_devices * nr_angles, sizeof(cpl_image*))); 00772 KMO_TRY_EXIT_IF_NULL(stored_xcal = (cpl_image**)cpl_calloc( 00773 nr_devices * nr_angles, sizeof(cpl_image*))); 00774 KMO_TRY_EXIT_IF_NULL(stored_ycal = (cpl_image**)cpl_calloc( 00775 nr_devices * nr_angles, sizeof(cpl_image*))); 00776 KMO_TRY_EXIT_IF_NULL(stored_qc_flat_sat = (int*)cpl_malloc( 00777 nr_devices * nr_angles * sizeof(int))); 00778 KMO_TRY_EXIT_IF_NULL(stored_qc_flat_eff = (double*)cpl_malloc( 00779 nr_devices * nr_angles * sizeof(double))); 00780 KMO_TRY_EXIT_IF_NULL(stored_qc_flat_sn = (double*)cpl_malloc( 00781 nr_devices * nr_angles * sizeof(double))); 00782 KMO_TRY_EXIT_IF_NULL(stored_gapmean = (double*)cpl_malloc( 00783 nr_devices * nr_angles * sizeof(double))); 00784 KMO_TRY_EXIT_IF_NULL(stored_gapsdv = (double*)cpl_malloc( 00785 nr_devices * nr_angles * sizeof(double))); 00786 KMO_TRY_EXIT_IF_NULL(stored_gapmaxdev = (double*)cpl_malloc( 00787 nr_devices * nr_angles * sizeof(double))); 00788 KMO_TRY_EXIT_IF_NULL(stored_slitmean = (double*)cpl_malloc( 00789 nr_devices * nr_angles * sizeof(double))); 00790 KMO_TRY_EXIT_IF_NULL(stored_slitsdv = (double*)cpl_malloc( 00791 nr_devices * nr_angles * sizeof(double))); 00792 KMO_TRY_EXIT_IF_NULL(stored_slitmaxdev = (double*)cpl_malloc( 00793 nr_devices * nr_angles * sizeof(double))); 00794 KMO_TRY_EXIT_IF_NULL(spec_found = (cpl_error_code*)cpl_malloc( 00795 nr_devices * nr_angles * sizeof(cpl_error_code))); 00796 KMO_TRY_EXIT_IF_NULL(edge_table = (cpl_table***)cpl_malloc( 00797 KMOS_NR_DETECTORS * nr_angles * sizeof(cpl_table**))); 00798 00799 // initialize to NULL 00800 for (i = 0; i < nr_devices * nr_angles ; i++) { 00801 stored_qc_flat_sat[i] = 0.0; 00802 stored_qc_flat_eff[i] = 0.0; 00803 stored_qc_flat_sn[i] = 0.0; 00804 stored_gapmean[i] = 0.0; 00805 stored_gapsdv[i] = 0.0; 00806 stored_gapmaxdev[i] = 0.0; 00807 stored_slitmean[i] = 0.0; 00808 stored_slitsdv[i] = 0.0; 00809 stored_slitmaxdev[i] = 0.0; 00810 spec_found[i] = CPL_ERROR_NONE; 00811 } 00812 00813 for (i = 0; i < KMOS_NR_DETECTORS * nr_angles; i++) { 00814 edge_table[i] = NULL; 00815 } 00816 00817 /* ------------------- Process data */ 00818 00819 /* Check which IFUs are active for all FLAT_ON frames */ 00820 KMO_TRY_EXIT_IF_NULL(unused_ifus_before = 00821 kmo_get_unused_ifus(frameset, 0, 0)); 00822 KMO_TRY_EXIT_IF_NULL(unused_ifus_after = 00823 kmo_duplicate_unused_ifus(unused_ifus_before)); 00824 kmo_print_unused_ifus(unused_ifus_before, FALSE); 00825 00826 cpl_msg_info(__func__, "EXPTIME: %g seconds", exptime); 00827 cpl_msg_info(__func__, "NDIT: %d", ndit); 00828 cpl_msg_info(__func__, "Detector readout mode: %s", readmode); 00829 cpl_msg_info(__func__, "-------------------------------------------"); 00830 00831 /* ------------ loop all rotator angles and detectors-------- */ 00832 for (a = 0; a < nr_angles; a++) { 00833 cpl_msg_info(__func__, "Processing rotator angle %d -> %d degree", 00834 a, rotang_found[a]); 00835 for (i = 1; i <= nr_devices; i++) { 00836 cpl_msg_info(__func__, "Processing detector No. %d", i); 00837 sx = a * nr_devices + (i - 1); 00838 KMO_TRY_EXIT_IF_NULL(bad_pix_mask_dark = 00839 kmo_dfs_load_image(frameset, BADPIXEL_DARK, i, 2, 00840 FALSE, NULL)); 00841 00842 /* -------- load all lamp_on and lamp_off images */ 00843 KMO_TRY_EXIT_IF_NULL(det_lamp_on = cpl_imagelist_new()); 00844 KMO_TRY_EXIT_IF_NULL(det_lamp_off = cpl_imagelist_new()); 00845 00846 /* Load lamp-on images for Angle a */ 00847 KMO_TRY_EXIT_IF_NULL(frame = kmo_dfs_get_frame( 00848 angle_frameset[a], FLAT_ON)); 00849 j = 0; 00850 while (frame != NULL) { 00851 KMO_TRY_EXIT_IF_NULL(img_in = kmo_dfs_load_image_frame( 00852 frame, i, FALSE, TRUE, &nr_sat)); 00853 KMO_TRY_EXIT_IF_ERROR(kmo_image_reject_from_mask( 00854 img_in, bad_pix_mask_dark)); 00855 00856 cpl_imagelist_set(det_lamp_on, img_in, j++); 00857 KMO_TRY_CHECK_ERROR_STATE(); 00858 00859 frame = kmo_dfs_get_frame(angle_frameset[a], NULL); 00860 KMO_TRY_CHECK_ERROR_STATE(); 00861 } 00862 00863 /* Load lamp-off images */ 00864 KMO_TRY_EXIT_IF_NULL(frame = kmo_dfs_get_frame(frameset, 00865 FLAT_OFF)); 00866 j = 0; 00867 while (frame != NULL) { 00868 KMO_TRY_EXIT_IF_NULL(img_in = kmo_dfs_load_image_frame( 00869 frame, i, FALSE, FALSE, NULL)); 00870 00871 KMO_TRY_EXIT_IF_ERROR(kmo_image_reject_from_mask( 00872 img_in, bad_pix_mask_dark)); 00873 00874 cpl_imagelist_set(det_lamp_off, img_in, j++); 00875 KMO_TRY_CHECK_ERROR_STATE(); 00876 00877 /* Get next frame */ 00878 frame = kmo_dfs_get_frame(frameset, NULL); 00879 KMO_TRY_CHECK_ERROR_STATE(); 00880 } 00881 00882 /* ------------ Process imagelist */ 00883 00884 /* Count saturated pixels for each detector */ 00885 KMO_TRY_EXIT_IF_NULL(frame = kmo_dfs_get_frame( 00886 angle_frameset[a], FLAT_ON)); 00887 KMO_TRY_EXIT_IF_NULL(main_header = kmclipm_propertylist_load( 00888 cpl_frame_get_filename(frame), 0)); 00889 if (strcmp(cpl_propertylist_get_string(main_header, READMODE), 00890 "Nondest") == 0) { 00891 // NDR: non-destructive readout mode 00892 stored_qc_flat_sat[sx] = nr_sat; 00893 } else { 00894 // normal readout mode 00895 stored_qc_flat_sat[sx] = kmo_imagelist_get_saturated( 00896 det_lamp_on, KMO_FLAT_SATURATED, KMO_FLAT_SAT_MIN); 00897 } 00898 cpl_propertylist_delete(main_header); main_header = NULL; 00899 KMO_TRY_CHECK_ERROR_STATE(); 00900 00901 /* Combine imagelists and create noise */ 00902 KMO_TRY_EXIT_IF_ERROR( 00903 kmclipm_combine_frames(det_lamp_on, NULL, NULL, cmethod, 00904 cpos_rej, cneg_rej, citer, cmax, cmin, 00905 &combined_data_on, &combined_noise_on, -1.0)); 00906 00907 KMO_TRY_EXIT_IF_ERROR( 00908 kmclipm_combine_frames(det_lamp_off, NULL, NULL, cmethod, 00909 cpos_rej, cneg_rej, citer, cmax, cmin, 00910 &combined_data_off, &combined_noise_off, -1.0)); 00911 00912 if (kmclipm_omit_warning_one_slice > 10) { 00913 kmclipm_omit_warning_one_slice = FALSE; 00914 } 00915 00916 /* Subtract combined lamp_off from lamp_on */ 00917 // (for noise: sig_x = sqrt(sig_u^2 + sig_v^2) 00918 KMO_TRY_EXIT_IF_ERROR( 00919 cpl_image_subtract(combined_data_on, combined_data_off)); 00920 00921 KMO_TRY_EXIT_IF_ERROR(cpl_image_power(combined_noise_on, 2.0)); 00922 KMO_TRY_EXIT_IF_ERROR(cpl_image_power(combined_noise_off, 2.0)); 00923 KMO_TRY_EXIT_IF_ERROR(cpl_image_add(combined_noise_on, 00924 combined_noise_off)); 00925 KMO_TRY_EXIT_IF_ERROR(cpl_image_power(combined_noise_on, 0.5)); 00926 00927 /* Create bad-pixel-mask */ 00928 KMO_TRY_EXIT_IF_NULL(bad_pix_mask_flat = 00929 kmo_create_bad_pix_flat_thresh(combined_data_on, 00930 surrounding_pixels, badpix_thresh)); 00931 00932 /* Calculate spectral curvature here */ 00933 spec_found[sx] = kmo_calc_curvature( 00934 combined_data_on, 00935 combined_noise_on, 00936 unused_ifus_after[i-1], 00937 bad_pix_mask_flat, 00938 i, 00939 &xcal, 00940 &ycal, 00941 stored_gapmean+(sx), 00942 stored_gapsdv+(sx), 00943 stored_gapmaxdev+(sx), 00944 stored_slitmean+(sx), 00945 stored_slitsdv+(sx), 00946 stored_slitmaxdev+(sx), 00947 &edge_table[sx]); 00948 00949 if (spec_found[sx] == CPL_ERROR_NONE) { 00950 // in kmo_calc_curvature() the spectral slope of each 00951 // slitlet has been normalised individually. Now the 00952 // normalisation on the whole frame is applied. 00953 // (cpl_image_get_mean() ignores bad pixels when 00954 // calculating the mean) 00955 mean_data = cpl_image_get_mean(combined_data_on); 00956 KMO_TRY_CHECK_ERROR_STATE(); 00957 00958 stored_qc_flat_eff[sx] = mean_data / exptime; 00959 00960 mean_noise = cpl_image_get_mean(combined_noise_on); 00961 KMO_TRY_CHECK_ERROR_STATE(); 00962 00963 if ((cpl_frameset_count_tags(frameset, FLAT_OFF) > 1) || 00964 (cpl_frameset_count_tags(frameset, FLAT_ON) > 1)) { 00965 KMO_TRY_ASSURE(mean_noise != 0.0, 00966 CPL_ERROR_ILLEGAL_INPUT, 00967 "All frames of detector %i are the same", i); 00968 stored_qc_flat_sn[sx] = mean_data / mean_noise; 00969 } 00970 00971 /* Normalize data & noise on the whole detector frame */ 00972 /* The spectral slope on each slitlet has already been */ 00973 /* normalised in kmo_calc_curvature() */ 00974 KMO_TRY_EXIT_IF_ERROR( 00975 cpl_image_divide_scalar(combined_data_on, mean_data)); 00976 00977 KMO_TRY_EXIT_IF_ERROR( 00978 cpl_image_divide_scalar(combined_noise_on, mean_data)); 00979 00980 /* Apply the badpixel mask to the produced frames */ 00981 KMO_TRY_EXIT_IF_ERROR(cpl_image_multiply(combined_data_on, 00982 bad_pix_mask_flat)); 00983 00984 KMO_TRY_EXIT_IF_ERROR(cpl_image_multiply(combined_noise_on, 00985 bad_pix_mask_flat)); 00986 00987 KMO_TRY_EXIT_IF_ERROR(cpl_image_multiply(xcal, 00988 bad_pix_mask_flat)); 00989 00990 KMO_TRY_EXIT_IF_ERROR(cpl_image_multiply(ycal, 00991 bad_pix_mask_flat)); 00992 00993 /* Store temporarily flat, badpixel and calibration */ 00994 stored_flat[sx] = combined_data_on; 00995 stored_noise[sx] = combined_noise_on; 00996 stored_badpix[sx] = bad_pix_mask_flat; 00997 stored_xcal[sx] = xcal; 00998 stored_ycal[sx] = ycal; 00999 } else if (spec_found[sx] == CPL_ERROR_DATA_NOT_FOUND) { 01000 // all IFUs seem to be deativated, continue processing 01001 // just save empty frames 01002 cpl_error_reset(); 01003 01004 cpl_image_delete(combined_data_on); 01005 combined_data_on = NULL; 01006 cpl_image_delete(combined_noise_on); 01007 combined_noise_on = NULL; 01008 cpl_image_delete(bad_pix_mask_flat); 01009 bad_pix_mask_flat = NULL; 01010 01011 KMO_TRY_EXIT_IF_NULL( 01012 stored_flat[sx]=cpl_image_new(nx, ny, CPL_TYPE_FLOAT)); 01013 for(ix = 1; ix <= nx; ix++) { 01014 for(iy = 1; iy <= ny; iy++) { 01015 cpl_image_reject(stored_flat[sx], ix, iy); 01016 } 01017 } 01018 KMO_TRY_CHECK_ERROR_STATE(); 01019 01020 KMO_TRY_EXIT_IF_NULL( 01021 stored_noise[sx]=cpl_image_duplicate(stored_flat[sx])); 01022 KMO_TRY_EXIT_IF_NULL( 01023 stored_xcal[sx]=cpl_image_duplicate(stored_flat[sx])); 01024 KMO_TRY_EXIT_IF_NULL( 01025 stored_ycal[sx]=cpl_image_duplicate(stored_flat[sx])); 01026 KMO_TRY_EXIT_IF_NULL( 01027 stored_badpix[sx]=cpl_image_new(nx, ny,CPL_TYPE_FLOAT)); 01028 } else { 01029 // another error occured 01030 KMO_TRY_CHECK_ERROR_STATE(); 01031 } 01032 01033 // store immediate results, free memory 01034 KMO_TRY_EXIT_IF_ERROR(kmclipm_image_save(stored_flat[sx], 01035 fn_flat, CPL_TYPE_FLOAT, NULL, save_mode, 0./0.)); 01036 KMO_TRY_EXIT_IF_ERROR(kmclipm_image_save(stored_noise[sx], 01037 fn_noise, CPL_TYPE_FLOAT, NULL, save_mode, 0./0.)); 01038 KMO_TRY_EXIT_IF_ERROR(kmclipm_image_save(stored_badpix[sx], 01039 fn_badpix, CPL_TYPE_FLOAT, NULL, save_mode, 0./0.)); 01040 01041 /* All other saves will create extensions */ 01042 save_mode = CPL_IO_EXTEND; 01043 cpl_image_delete(stored_flat[sx]); stored_flat[sx] = NULL; 01044 cpl_image_delete(stored_noise[sx]); stored_noise[sx] = NULL; 01045 cpl_image_delete(stored_badpix[sx]); stored_badpix[sx] = NULL; 01046 01047 // free memory 01048 cpl_imagelist_delete(det_lamp_on); det_lamp_on = NULL; 01049 cpl_imagelist_delete(det_lamp_off); det_lamp_off = NULL; 01050 cpl_image_delete(combined_data_off); combined_data_off = NULL; 01051 cpl_image_delete(combined_noise_off); combined_noise_off = NULL; 01052 cpl_image_delete(bad_pix_mask_dark); bad_pix_mask_dark = NULL; 01053 } // for i = 1; i <= nr_devices 01054 } // for a = 0; a < nr_angles 01055 KMO_TRY_CHECK_ERROR_STATE(); 01056 01057 /* ----- QC parameters & saving */ 01058 /* ---- load, update & save primary header */ 01059 KMO_TRY_EXIT_IF_NULL(main_header = kmo_dfs_load_primary_header( 01060 frameset, FLAT_ON)); 01061 01062 /* Update which IFUs are not used */ 01063 kmo_print_unused_ifus(unused_ifus_after, TRUE); 01064 01065 KMO_TRY_EXIT_IF_ERROR( 01066 kmo_set_unused_ifus(unused_ifus_after, main_header, "kmo_flat")); 01067 01068 // write main_header for data-, noise-, ycal- and badpix-frame 01069 // xcal gets additionally the boundaries of the IFUs for reconstruction 01070 01071 // add here boundaries for reconstruction 01072 KMO_TRY_EXIT_IF_NULL(main_header_xcal = cpl_propertylist_new()); 01073 01074 KMO_TRY_EXIT_IF_NULL( 01075 total_bounds = (int**)cpl_malloc(nr_devices*sizeof(int*))); 01076 for (i = 0; i < nr_devices; i++) { 01077 KMO_TRY_EXIT_IF_NULL( 01078 total_bounds[i] = 01079 (int*) cpl_calloc(2*KMOS_IFUS_PER_DETECTOR,sizeof(int))); 01080 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01081 total_bounds[i][2*j] = 2048; 01082 total_bounds[i][2*j+1] = 0; 01083 } 01084 } 01085 KMO_TRY_CHECK_ERROR_STATE(); 01086 01087 /* Store the min left bound and max right bound for all angles */ 01088 for (a = 0; a < nr_angles; a++) { 01089 for (i = 0; i < nr_devices; i++) { 01090 sx = a * nr_devices + i; 01091 if (stored_ycal[sx] != NULL) { 01092 KMO_TRY_EXIT_IF_NULL( 01093 bounds = kmo_split_frame(stored_ycal[sx])); 01094 01095 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01096 if ((total_bounds[i][2*j] == -1)||(bounds[2*j] == -1)) { 01097 total_bounds[i][2*j] = -1; 01098 } else { 01099 if (total_bounds[i][2*j] > bounds[2*j]) { 01100 total_bounds[i][2*j] = bounds[2*j]; 01101 } 01102 } 01103 01104 if ((total_bounds[i][2*j+1] == -1) || 01105 (bounds[2*j+1] == -1)) { 01106 total_bounds[i][2*j+1] = -1; 01107 } else { 01108 if (total_bounds[i][2*j+1] < bounds[2*j+1]) { 01109 total_bounds[i][2*j+1] = bounds[2*j+1]; 01110 } 01111 } 01112 } 01113 } else { 01114 // whole detector inactive 01115 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01116 total_bounds[i][2*j] = -1; 01117 total_bounds[i][2*j+1] = -1; 01118 } 01119 } 01120 if (bounds != NULL) { 01121 cpl_free(bounds); bounds = NULL; 01122 } 01123 } // for (nr_devices) 01124 } // for (nr_angles) 01125 01126 /* Write the min left bound and max right bound for all angles */ 01127 /* into the main header */ 01128 for (i = 0; i < nr_devices; i++) { 01129 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01130 if (total_bounds[i][2*j] > -1) { 01131 KMO_TRY_EXIT_IF_NULL(tmpstr= cpl_sprintf("%s%d%s", 01132 BOUNDS_PREFIX, i*KMOS_IFUS_PER_DETECTOR + j+1, "_L")); 01133 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int( 01134 main_header_xcal, tmpstr, total_bounds[i][2*j], 01135 "[pix] left boundary for reconstr.")); 01136 cpl_free(tmpstr); tmpstr = NULL; 01137 } 01138 01139 if (total_bounds[i][2*j+1] > -1) { 01140 KMO_TRY_EXIT_IF_NULL(tmpstr= cpl_sprintf("%s%d%s", 01141 BOUNDS_PREFIX, i*KMOS_IFUS_PER_DETECTOR + j+1, "_R")); 01142 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int( 01143 main_header_xcal,tmpstr, total_bounds[i][2*j+1], 01144 "[pix] right boundary for reconstr.")); 01145 cpl_free(tmpstr); tmpstr = NULL; 01146 } 01147 } 01148 } // for (nr_devices) 01149 KMO_TRY_CHECK_ERROR_STATE(); 01150 01151 /* --------- saving headers */ 01152 if (!suppress_extension) { 01153 KMO_TRY_EXIT_IF_NULL(fn_suffix = cpl_sprintf("%s", suffix)); 01154 } else { 01155 KMO_TRY_EXIT_IF_NULL(fn_suffix = cpl_sprintf("%s", "")); 01156 } 01157 01158 cpl_msg_info(__func__, "Saving data..."); 01159 01160 KMO_TRY_EXIT_IF_NULL(frame = kmo_dfs_get_frame(frameset, FLAT_ON)); 01161 01162 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, filename_flat, 01163 fn_suffix, frame, main_header, parlist, cpl_func)); 01164 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, filename_xcal, 01165 fn_suffix, frame, main_header_xcal, parlist, cpl_func)); 01166 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, filename_ycal, 01167 fn_suffix, frame, main_header, parlist, cpl_func)); 01168 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, filename_bad, 01169 fn_suffix, frame, main_header, parlist, cpl_func)); 01170 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, filename_edge, 01171 fn_suffix, frame, main_header, parlist, cpl_func)); 01172 01173 cpl_propertylist_delete(main_header); main_header = NULL; 01174 cpl_propertylist_delete(main_header_xcal); main_header_xcal = NULL; 01175 01176 /* -------- saving sub frames */ 01177 for (a = 0; a < nr_angles; a++) { 01178 for (i = 1; i <= nr_devices; i++) { 01179 sx = a * nr_devices + (i - 1); 01180 01181 // load stored data again 01182 KMO_TRY_EXIT_IF_NULL(stored_flat[sx] = kmclipm_image_load( 01183 fn_flat, CPL_TYPE_FLOAT, 0, sx)); 01184 KMO_TRY_EXIT_IF_NULL(stored_noise[sx] = kmclipm_image_load( 01185 fn_noise, CPL_TYPE_FLOAT, 0, sx)); 01186 KMO_TRY_EXIT_IF_NULL(stored_badpix[sx] = kmclipm_image_load( 01187 fn_badpix, CPL_TYPE_FLOAT, 0, sx)); 01188 01189 KMO_TRY_EXIT_IF_NULL(sub_header = kmo_dfs_load_sub_header( 01190 frameset, FLAT_ON, i, FALSE)); 01191 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_double( 01192 sub_header,CAL_ROTANGLE, ((double) rotang_found[a]), 01193 "[deg] Rotator relative to nasmyth")); 01194 01195 if (spec_found[sx] == CPL_ERROR_NONE) { 01196 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int( 01197 sub_header, QC_FLAT_SAT, stored_qc_flat_sat[sx], 01198 "[] nr. saturated pixels of master flat")); 01199 /* Load gain */ 01200 gain = kmo_dfs_get_property_double(sub_header, GAIN); 01201 KMO_TRY_CHECK_ERROR_STATE_MSG( 01202 "GAIN-keyword in fits-header is missing!"); 01203 01204 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_double( 01205 sub_header, QC_FLAT_EFF, 01206 stored_qc_flat_eff[sx]/gain, 01207 "[e-/s] rel. brightness of flat lamp")); 01208 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_double( 01209 sub_header, QC_FLAT_SN, stored_qc_flat_sn[sx], 01210 "[] S/N of master flat")); 01211 } 01212 01213 /* Store qc parameters only if any slitlet- and gap-width */ 01214 /* has been detected (should be the case when at least */ 01215 /* one IFU is active) */ 01216 if (stored_xcal[sx] != NULL) { 01217 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_double( 01218 sub_header, QC_GAP_MEAN, stored_gapmean[sx], 01219 "[pix] mean gap width between slitlets")); 01220 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_double( 01221 sub_header, QC_GAP_SDV, stored_gapsdv[sx], 01222 "[pix] stdev of gap width between slitlets")); 01223 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_double( 01224 sub_header, QC_GAP_MAXDEV, stored_gapmaxdev[sx], 01225 "[pix] max gap deviation between slitlets")); 01226 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_double( 01227 sub_header, QC_SLIT_MEAN, stored_slitmean[sx], 01228 "[pix] mean slitlet width")); 01229 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_double( 01230 sub_header, QC_SLIT_SDV, stored_slitsdv[sx], 01231 "[pix] stdev of slitlet widths")); 01232 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_double( 01233 sub_header, QC_SLIT_MAXDEV, 01234 stored_slitmaxdev[sx], 01235 "[pix] max slitlet width deviation")); 01236 } 01237 01238 /* Calculate QC.BADPIX.NCOUNT */ 01239 nr_bad_pix = cpl_image_count_rejected(stored_badpix[sx]); 01240 KMO_TRY_CHECK_ERROR_STATE(); 01241 01242 /* Remove 4pixel-border as bad pixels */ 01243 nr_bad_pix -= 2*KMOS_BADPIX_BORDER*(nx-2*KMOS_BADPIX_BORDER) + 01244 2*KMOS_BADPIX_BORDER*ny; 01245 01246 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int(sub_header, 01247 QC_NR_BAD_PIX, nr_bad_pix, "[] nr. of bad pixels")); 01248 01249 /* Save flat frame */ 01250 KMO_TRY_EXIT_IF_NULL(extname = kmo_extname_creator( 01251 detector_frame, i, EXT_DATA)); 01252 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_string( 01253 sub_header, EXTNAME,extname,"FITS extension name")); 01254 cpl_free(extname); extname = NULL; 01255 01256 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int( 01257 sub_header, EXTVER, sx+1, "FITS extension ver")); 01258 01259 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_image(stored_flat[sx], 01260 filename_flat, fn_suffix, sub_header, 0./0.)); 01261 01262 /* Save noise frame when enough input frames were available */ 01263 KMO_TRY_EXIT_IF_NULL(extname = kmo_extname_creator( 01264 detector_frame, i, EXT_NOISE)); 01265 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_string( 01266 sub_header, EXTNAME,extname,"FITS extension name")); 01267 cpl_free(extname); extname = NULL; 01268 01269 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_image(stored_noise[sx], 01270 filename_flat, fn_suffix, sub_header, 0./0.)); 01271 01272 /* Save bad_pix frame */ 01273 KMO_TRY_EXIT_IF_NULL(extname = kmo_extname_creator( 01274 detector_frame, i, EXT_BADPIX)); 01275 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_string( 01276 sub_header, EXTNAME,extname,"FITS extension name")); 01277 cpl_free(extname); extname = NULL; 01278 01279 KMO_TRY_EXIT_IF_ERROR( 01280 kmo_dfs_save_image(stored_badpix[sx], filename_bad, 01281 fn_suffix, sub_header, 0.)); 01282 01283 // save xcal and ycal-frame 01284 KMO_TRY_EXIT_IF_NULL( 01285 extname = kmo_extname_creator(detector_frame, i, EXT_DATA)); 01286 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_string( 01287 sub_header, EXTNAME,extname,"FITS extension name")); 01288 cpl_free(extname); extname = NULL; 01289 01290 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_image(stored_xcal[sx], 01291 filename_xcal, fn_suffix, sub_header, 0./0.)); 01292 01293 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_image(stored_ycal[sx], 01294 filename_ycal, fn_suffix, sub_header, 0./0.)); 01295 01296 cpl_free(extname); extname = NULL; 01297 01298 /* Save edge_pars-frame */ 01299 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01300 KMO_TRY_EXIT_IF_NULL( 01301 extname = cpl_sprintf("%s_IFU.%d_ANGLE.%d", 01302 EXT_LIST, j+1+(i-1)*KMOS_IFUS_PER_DETECTOR, 01303 rotang_found[a])); 01304 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_string( 01305 sub_header, EXTNAME, extname, 01306 "FITS extension name")); 01307 cpl_free(extname); extname = NULL; 01308 01309 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int( 01310 sub_header, CAL_IFU_NR, 01311 j+1+(i-1)*KMOS_IFUS_PER_DETECTOR, 01312 "IFU Number {1..24}")); 01313 01314 /* Save edge-parameters as product */ 01315 if ((spec_found[sx] != CPL_ERROR_DATA_NOT_FOUND) && 01316 (edge_table[sx][j] != NULL)) { 01317 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_table( 01318 edge_table[sx][j], filename_edge, 01319 fn_suffix, sub_header)); 01320 } else { 01321 cpl_propertylist_erase(sub_header, CRVAL1); 01322 cpl_propertylist_erase(sub_header, CRVAL2); 01323 cpl_propertylist_erase(sub_header, CD1_1); 01324 cpl_propertylist_erase(sub_header, CD1_2); 01325 cpl_propertylist_erase(sub_header, CD2_1); 01326 cpl_propertylist_erase(sub_header, CD2_2); 01327 cpl_propertylist_erase(sub_header, CRPIX1); 01328 cpl_propertylist_erase(sub_header, CRPIX2); 01329 cpl_propertylist_erase(sub_header, CTYPE1); 01330 cpl_propertylist_erase(sub_header, CTYPE2); 01331 KMO_TRY_CHECK_ERROR_STATE(); 01332 01333 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_table(NULL, 01334 filename_edge, fn_suffix, sub_header)); 01335 } 01336 } 01337 01338 cpl_propertylist_delete(sub_header); sub_header = NULL; 01339 01340 cpl_image_delete(stored_flat[sx]); stored_flat[sx] = NULL; 01341 cpl_image_delete(stored_noise[sx]); stored_noise[sx] = NULL; 01342 cpl_image_delete(stored_badpix[sx]); stored_badpix[sx] = NULL; 01343 } // for (i = nr_devices) 01344 } // for (a = nr_angles) 01345 } 01346 KMO_CATCH 01347 { 01348 KMO_CATCH_MSG(); 01349 ret_val = -1; 01350 } 01351 // delete temporary files 01352 unlink(fn_flat); 01353 unlink(fn_noise); 01354 unlink(fn_badpix); 01355 01356 kmo_free_fits_desc(&desc1); 01357 kmo_free_fits_desc(&desc2); 01358 kmo_free_unused_ifus(unused_ifus_before); unused_ifus_before = NULL; 01359 kmo_free_unused_ifus(unused_ifus_after); unused_ifus_after = NULL; 01360 cpl_propertylist_delete(main_header); main_header = NULL; 01361 cpl_propertylist_delete(main_header_xcal); main_header_xcal = NULL; 01362 cpl_propertylist_delete(sub_header); sub_header = NULL; 01363 cpl_imagelist_delete(det_lamp_on); det_lamp_on = NULL; 01364 cpl_imagelist_delete(det_lamp_off); det_lamp_off = NULL; 01365 cpl_image_delete(combined_data_off); combined_data_off = NULL; 01366 cpl_image_delete(combined_noise_off); combined_noise_off = NULL; 01367 cpl_image_delete(bad_pix_mask_dark); bad_pix_mask_dark = NULL; 01368 cpl_free(stored_qc_flat_sat); stored_qc_flat_sat = NULL; 01369 cpl_free(stored_qc_flat_eff); stored_qc_flat_eff = NULL; 01370 cpl_free(stored_qc_flat_sn); stored_qc_flat_sn = NULL; 01371 cpl_free(stored_gapmean); stored_gapmean = NULL; 01372 cpl_free(stored_gapsdv); stored_gapsdv = NULL; 01373 cpl_free(stored_gapmaxdev); stored_gapmaxdev = NULL; 01374 cpl_free(stored_slitmean); stored_slitmean = NULL; 01375 cpl_free(stored_slitsdv); stored_slitsdv = NULL; 01376 cpl_free(stored_slitmaxdev); stored_slitmaxdev = NULL; 01377 cpl_free(readmode); readmode = NULL; 01378 cpl_free(suffix); suffix = NULL; 01379 cpl_free(fn_suffix); fn_suffix = NULL; 01380 if (total_bounds != NULL) { 01381 for (i = 0; i < nr_devices; i++) { 01382 cpl_free(total_bounds[i]); total_bounds[i] = NULL; 01383 } 01384 } 01385 cpl_free(total_bounds); total_bounds = NULL; 01386 for (i = 0; i < nr_devices * nr_angles; i++) { 01387 cpl_image_delete(stored_flat[i]); stored_flat[i] = NULL; 01388 cpl_image_delete(stored_noise[i]); stored_noise[i] = NULL; 01389 cpl_image_delete(stored_badpix[i]); stored_badpix[i] = NULL; 01390 cpl_image_delete(stored_xcal[i]); stored_xcal[i] = NULL; 01391 cpl_image_delete(stored_ycal[i]); stored_ycal[i] = NULL; 01392 } 01393 cpl_free(stored_flat); stored_flat = NULL; 01394 cpl_free(stored_noise); stored_noise = NULL; 01395 cpl_free(stored_badpix); stored_badpix = NULL; 01396 cpl_free(stored_xcal); stored_xcal = NULL; 01397 cpl_free(stored_ycal); stored_ycal = NULL; 01398 for (a = 0; a < nr_angles; a++) { 01399 cpl_frameset_delete(angle_frameset[a]); angle_frameset[a] = NULL; 01400 } 01401 cpl_free(angle_frameset); angle_frameset = NULL; 01402 if (edge_table != NULL) { 01403 for (i = 0; i < KMOS_NR_DETECTORS * nr_angles; i++) { 01404 if (edge_table[i] != NULL) { 01405 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01406 cpl_table_delete(edge_table[i][j]); 01407 edge_table[i][j] = NULL; 01408 } 01409 cpl_free(edge_table[i]); edge_table[i] = NULL; 01410 } 01411 } 01412 cpl_free(edge_table); edge_table = NULL; 01413 } 01414 if (bounds != NULL) { 01415 cpl_free(bounds); bounds = NULL; 01416 } 01417 if (spec_found != NULL) { 01418 cpl_free(spec_found); spec_found = NULL; 01419 } 01420 01421 return ret_val; 01422 } 01423