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