|
KMOS Pipeline Reference Manual
1.0.7
|
00001 /* $Id: yves_kmo_flat.c,v 1.4 2013/01/27 03:07:33 yjung 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: yjung $ 00023 * $Date: 2013/01/27 03:07:33 $ 00024 * $Revision: 1.4 $ 00025 * $Name: HEAD $ 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 * Define 00051 *----------------------------------------------------------------------------*/ 00052 00053 #define FLAT_NAME "MASTER_FLAT" 00054 #define BAD_NAME "BADPIXEL_FLAT" 00055 #define XCAL_NAME "XCAL" 00056 #define YCAL_NAME "YCAL" 00057 #define LCAL_NAME "LCAL" 00058 #define FLAT_EDGE_NAME "FLAT_EDGE" 00059 #define ANGLE_DIM 360 00060 00061 /*----------------------------------------------------------------------------- 00062 * Functions prototypes 00063 *----------------------------------------------------------------------------*/ 00064 00065 static int kmo_flat_create(cpl_plugin *); 00066 static int kmo_flat_exec(cpl_plugin *); 00067 static int kmo_flat_destroy(cpl_plugin *); 00068 static int kmo_flat(cpl_parameterlist *, cpl_frameset *); 00069 00070 /*----------------------------------------------------------------------------- 00071 * Static variables 00072 *----------------------------------------------------------------------------*/ 00073 00074 static char kmo_flat_description[15000] = 00075 "This recipe creates the master flat field and calibration frames needed for \n" 00076 "spatial calibration for all three detectors. It must be called after the \n" 00077 "kmo_dark-recipe, which generates a bad pixel mask (badpixel_dark.fits). The \n" 00078 "bad pixel mask will be updated in this recipe (goes into badpixel_flat.fits).\n" 00079 "As input at least 3 dark frames, 3 frames with the flat lamp on are recommen-\n" 00080 "ded. Additionally a badpixel mask from kmo_dark is required.\n" 00081 "\n" 00082 "The badpixel mask contains 0 for bad pixels and 1 for good ones.\n" 00083 "\n" 00084 "The structure of the resulting xcal and ycal frames is quite complex since the\n" 00085 "arrangement of the IFUs isn't just linear on the detector. Basically the inte-\n" 00086 "ger part of the calibration data shows the offset of each pixels centre in mas\n" 00087 "(Milli arcsec) from the field centre. The viewing of an IFU is 2800mas \n" 00088 "(14pix*0.2arcsec/pix). So the values in these two frames will vary between \n" 00089 "+/-1500 (One would expect 1400, but since the slitlets aren't expected to be \n" 00090 "exactly vertical, the values can even go up to around 1500). Additionally in \n" 00091 "the calibration data in y-direction the decimal part of the data designates \n" 00092 "the IFU to which the slitlet corresponds to (for each detector from 1 to 8).\n" 00093 "Because of the irregular arrangement of the IFUs not all x-direction calibra-\n" 00094 "tion data is found in xcal and similarly not all y-direction calibration data\n" 00095 "is located in ycal. For certain IFUs they are switched and/or flipped in x- or\n" 00096 "y-direction:\n" 00097 "For IFUs 1,2,3,4,13,14,15,16: x- and y- data is switched\n" 00098 "For IFUs 17,18,19,20: y-data is flipped \n" 00099 "For IFUs 21,22,23,24: x-data is flipped \n" 00100 "For IFUs 5,6,7,8,9,10,11,12: x- and y- data is switched and x- and \n" 00101 " y- data is flipped\n" 00102 "\n" 00103 "Advanced features:\n" 00104 "------------------\n" 00105 "To create the badpixel mask the edges of all slitlets are fitted to a polyno-\n" 00106 "mial. Since it can happen that some of these fits (3 detectors * 8 IFUs * \n" 00107 "14slitlets * 2 edges (left and right edge of slitlet)= 672 edges) fail, the\n" 00108 "fit parameters are themselves fitted again to detect any outliers. By default\n" 00109 "the parameters of all left and all right edges are grouped individually and \n" 00110 "then fitted using chebyshev polynomials. The advantage of a chebyshev polyno-\n" 00111 "mial is, that it consists in fact of a series of orthogonal polynomials. This\n" 00112 "implies that the parameters of the polynomials are independent. This fact pre-\n" 00113 "destines the use of chebyshev polynomials for our case. So each individual pa-\n" 00114 "rameter can be examined independently. The reason why the left and right edges\n" 00115 "are fitted individually is that there is a systematic pattern specific to \n" 00116 "these groups. The reason for this pattern is probably to be found in the opti-\n" 00117 "cal path the light is traversing.\n" 00118 "\n" 00119 "The behaviour of this fitting step can be influenced via environment parameters:\n" 00120 "* KF_ALLPARS (default: 1)\n" 00121 " When set to 1 all coefficients of the polynomial of an edge are to be cor-\n" 00122 " rected, also when just one of these coefficients is an outlier. When set to\n" 00123 " 0 only the outlier is to be corrected.\n" 00124 "* KF_CH (default: 1)\n" 00125 " When set to 1 chebyshev polynomials are used to fit the fitted parameters.\n" 00126 " When set to 0 normal polynomials are used.\n" 00127 "* KF_SIDES (default: 2)\n" 00128 " This variable can either be set to 1 or 2. When set to 2 the left and right\n" 00129 " edges are examined individually. When set to 1 all edges are examined as one\n" 00130 " group.\n" 00131 "* KF_FACTOR(default: 4)\n" 00132 " This factor defines the threshold factor. All parameters deviating \n" 00133 " KF_FACTOR*stddev are to be corrected\n" 00134 "\n" 00135 "BASIC PARAMETERS:\n" 00136 "-----------------\n" 00137 "--surrounding_pixels\n" 00138 "The amount of bad pixels to surround a specific pixel, to let it be marked\n" 00139 "bad as well.\n" 00140 "\n" 00141 "--cmethod\n" 00142 "Following methods of frame combination are available:\n" 00143 " * 'ksigma' (Default)\n" 00144 " An iterative sigma clipping. For each position all pixels in the spectrum\n" 00145 " are examined. If they deviate significantly, they will be rejected according\n" 00146 " to the conditions:\n" 00147 " val > mean + stdev * cpos_rej\n" 00148 " and\n" 00149 " val < mean - stdev * cneg_rej\n" 00150 " where --cpos_rej, --cneg_rej and --citer are the corresponding configuration\n" 00151 " parameters. In the first iteration median and percentile level are used.\n" 00152 "\n" 00153 " * 'median'\n" 00154 " At each pixel position the median is calculated.\n" 00155 "\n" 00156 " * 'average'\n" 00157 " At each pixel position the average is calculated.\n" 00158 "\n" 00159 " * 'sum'\n" 00160 " At each pixel position the sum is calculated.\n" 00161 "\n" 00162 " * 'min_max'\n" 00163 " The specified number of minimum and maximum pixel values will be rejected.\n" 00164 " --cmax and --cmin apply to this method.\n" 00165 "\n" 00166 "ADVANCED PARAMETERS\n" 00167 "-------------------\n" 00168 "--cpos_rej\n" 00169 "--cneg_rej\n" 00170 "--citer\n" 00171 "see --cmethod='ksigma'\n" 00172 "\n" 00173 "--cmax\n" 00174 "--cmin\n" 00175 "see --cmethod='min_max'\n" 00176 "\n" 00177 "-------------------------------------------------------------------------------\n" 00178 " Input files:\n" 00179 "\n" 00180 " DO KMOS \n" 00181 " category Type Explanation Required #Frames\n" 00182 " -------- ----- ----------- -------- -------\n" 00183 " FLAT_ON RAW Flatlamp-on exposures Y 1-n \n" 00184 " (at least 3 frames recommended) \n" 00185 " FLAT_OFF RAW Flatlamp-off exposures Y 1-n \n" 00186 " (at least 3 frames recommended) \n" 00187 " BADPIXEL_DARK B2D Bad pixel mask Y 1 \n" 00188 "\n" 00189 " Output files:\n" 00190 "\n" 00191 " DO KMOS\n" 00192 " category Type Explanation\n" 00193 " -------- ----- -----------\n" 00194 " MASTER_FLAT F2D Normalised flat field\n" 00195 " (6 extensions: alternating data & noise\n" 00196 " BADPIXEL_FLAT B2D Updated bad pixel mask (3 Extensions)\n" 00197 " XCAL F2D Calibration frame 1 (3 Extensions)\n" 00198 " YCAL F2D Calibration frame 2 (3 Extensions)\n" 00199 " FLAT_EDGE F2L Frame containing parameters of fitted \n" 00200 " slitlets of all IFUs of all detectors\n" 00201 "-------------------------------------------------------------------------------" 00202 "\n"; 00203 00204 /*----------------------------------------------------------------------------- 00205 * Functions code 00206 *----------------------------------------------------------------------------*/ 00224 int cpl_plugin_get_info(cpl_pluginlist *list) 00225 { 00226 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe); 00227 cpl_plugin *plugin = &recipe->interface; 00228 00229 cpl_plugin_init(plugin, 00230 CPL_PLUGIN_API, 00231 KMOS_BINARY_VERSION, 00232 CPL_PLUGIN_TYPE_RECIPE, 00233 "kmo_flat", 00234 "Create master flatfield frame and badpixel map to be " 00235 "used during science reduction", 00236 kmo_flat_description, 00237 "Alex Agudo Berbel", 00238 "agudo@mpe.mpg.de", 00239 kmos_get_license(), 00240 kmo_flat_create, 00241 kmo_flat_exec, 00242 kmo_flat_destroy); 00243 00244 cpl_pluginlist_append(list, plugin); 00245 00246 return 0; 00247 } 00248 00256 static int kmo_flat_create(cpl_plugin *plugin) 00257 { 00258 cpl_recipe *recipe; 00259 cpl_parameter *p; 00260 00261 // Check that the plugin is part of a valid recipe 00262 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00263 recipe = (cpl_recipe *)plugin; 00264 else 00265 return -1; 00266 00267 // Create the parameters list in the cpl_recipe object 00268 recipe->parameters = cpl_parameterlist_new(); 00269 00270 // Fill the parameters list 00271 // --badpix_thresh 00272 p = cpl_parameter_new_value("kmos.kmo_flat.badpix_thresh", 00273 CPL_TYPE_INT, 00274 "The threshold level to mark pixels as bad on " 00275 "the dark subtracted frames [%].", 00276 "kmos.kmo_flat", 00277 35); 00278 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "badpix_thresh"); 00279 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00280 cpl_parameterlist_append(recipe->parameters, p); 00281 00282 // --surrounding_pixels 00283 p = cpl_parameter_new_value("kmos.kmo_flat.surrounding_pixels", 00284 CPL_TYPE_INT, 00285 "The amount of bad pixels to surround a specific " 00286 "pixel, to let it be marked bad as well.", 00287 "kmos.kmo_flat", 00288 5); 00289 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "surrounding_pixels"); 00290 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00291 cpl_parameterlist_append(recipe->parameters, p); 00292 00293 return kmo_combine_pars_create(recipe->parameters, 00294 "kmos.kmo_flat", 00295 DEF_REJ_METHOD, 00296 FALSE); 00297 } 00298 00304 static int kmo_flat_exec(cpl_plugin *plugin) 00305 { 00306 cpl_recipe *recipe; 00307 00308 // Get the recipe out of the plugin 00309 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00310 recipe = (cpl_recipe *)plugin; 00311 else return -1; 00312 00313 return kmo_flat(recipe->parameters, recipe->frames); 00314 } 00315 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 00348 static int kmo_flat(cpl_parameterlist *parlist, cpl_frameset *frameset) 00349 { 00350 cpl_imagelist *det_lamp_on = NULL, 00351 *det_lamp_off = NULL; 00352 00353 cpl_image *img_in = NULL, 00354 *combined_data_on = NULL, 00355 *combined_noise_on = NULL, 00356 *combined_data_off = NULL, 00357 *combined_noise_off = NULL, 00358 *bad_pix_mask_flat = NULL, 00359 *bad_pix_mask_dark = NULL, 00360 *xcal = NULL, 00361 *ycal = NULL; 00362 00363 cpl_image **stored_flat = NULL, 00364 **stored_noise = NULL, 00365 **stored_badpix = NULL, 00366 **stored_xcal = NULL, 00367 **stored_ycal = NULL; 00368 00369 cpl_frame *frame = NULL; 00370 cpl_frameset ** angle_frameset = NULL; 00371 00372 int ret_val = 0, 00373 nr_devices = 0, 00374 i = 0, 00375 ii = 0, 00376 a = 0, 00377 sx = 0, 00378 j = 0, 00379 cmax = 0, 00380 cmin = 0, 00381 citer = 0, 00382 surrounding_pixels = 0, 00383 badpix_thresh = 0, 00384 nx = 0, 00385 ny = 0, 00386 nz = 0, 00387 *stored_qc_flat_sat = NULL, 00388 *bounds = NULL, 00389 **total_bounds = NULL, 00390 ***all_bounds = NULL, 00391 nr_bad_pix = 0, 00392 ndit = 0, 00393 nr_sat = 0, 00394 nr_angles = 0; 00395 00396 double cpos_rej = 0.0, 00397 cneg_rej = 0.0, 00398 gain = 0.0, 00399 exptime = 0.0, 00400 *stored_qc_flat_eff = NULL, 00401 *stored_qc_flat_sn = NULL, 00402 mean_data = 0.0, 00403 mean_noise = 0.0, 00404 *stored_gapmean = NULL, 00405 *stored_gapsdv = NULL, 00406 *stored_gapmaxdev = NULL, 00407 *stored_slitmean = NULL, 00408 *stored_slitsdv = NULL, 00409 *stored_slitmaxdev = NULL; 00410 00411 const char *cmethod = NULL; 00412 00413 char *extname = NULL, 00414 *suffix = NULL, 00415 *tmpstr = NULL, 00416 *readmode = NULL; 00417 00418 cpl_propertylist *main_header = NULL, 00419 *main_header_xcal = NULL, 00420 *sub_header = NULL; 00421 00422 cpl_table ***edge_table = NULL; 00423 00424 main_fits_desc desc1, desc2; 00425 00426 cpl_array **unused_ifus_before = NULL, 00427 **unused_ifus_after = NULL; 00428 00429 cpl_error_code *spec_found = NULL; 00430 00431 KMO_TRY 00432 { 00433 kmo_init_fits_desc(&desc1); 00434 kmo_init_fits_desc(&desc2); 00435 00436 KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, BADPIXEL_DARK) == 1, 00437 CPL_ERROR_NULL_INPUT, 00438 "A BADPIXEL_DARK frame must be provided!"); 00439 00440 KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_flat") == 1, 00441 CPL_ERROR_ILLEGAL_INPUT, 00442 "Cannot identify RAW and CALIB frames!"); 00443 00444 // ------------ get parameters ------------ 00445 surrounding_pixels = kmo_dfs_get_parameter_int(parlist, 00446 "kmos.kmo_flat.surrounding_pixels"); 00447 kmo_dfs_print_parameter_help(parlist, 00448 "kmos.kmo_flat.surrounding_pixels"); 00449 badpix_thresh = kmo_dfs_get_parameter_int(parlist, 00450 "kmos.kmo_flat.badpix_thresh"); 00451 kmo_dfs_print_parameter_help(parlist, 00452 "kmos.kmo_flat.badpix_thresh"); 00453 kmo_combine_pars_load(parlist, "kmos.kmo_flat", &cmethod, &cpos_rej, 00454 &cneg_rej, &citer, &cmin, &cmax, FALSE); 00455 00456 // check BADPIXEL_DARK 00457 frame = kmo_dfs_get_frame(frameset, BADPIXEL_DARK); 00458 00459 desc2 = kmo_identify_fits_header(cpl_frame_get_filename(frame)); 00460 00461 KMO_TRY_ASSURE((desc2.nr_ext == 3) && 00462 (desc2.ex_badpix == TRUE) && 00463 (desc2.fits_type == b2d_fits) && 00464 (desc2.frame_type == detector_frame), 00465 CPL_ERROR_ILLEGAL_INPUT, 00466 "BADPIXEL_DARK isn't in the correct format!!!"); 00467 00468 nx = desc2.naxis1; 00469 ny = desc2.naxis2; 00470 nz = desc2.naxis3; 00471 00472 KMO_TRY_ASSURE((surrounding_pixels >= 0) && (surrounding_pixels <= 8), 00473 CPL_ERROR_ILLEGAL_INPUT, 00474 "surrounding_pixels must be between 0 and 8!"); 00475 00476 KMO_TRY_ASSURE((badpix_thresh >= 0) && (badpix_thresh <= 100), 00477 CPL_ERROR_ILLEGAL_INPUT, 00478 "badpix_thresh must be between 0 and 100%%!"); 00479 00480 // Get the first OFF frame 00481 frame = kmo_dfs_get_frame(frameset, FLAT_OFF); 00482 00483 // Get EXPTIME, NDIT, READMODE 00484 main_header = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0); 00485 ndit = cpl_propertylist_get_int(main_header, NDIT); 00486 exptime = cpl_propertylist_get_double(main_header, EXPTIME); 00487 readmode = cpl_strdup(cpl_propertylist_get_string(main_header, READMODE)); 00488 cpl_propertylist_delete(main_header); main_header = NULL; 00489 00490 // Loop on the other OFF frames 00491 while (frame != NULL) { 00492 // Get the Header of the current frame (again ?) 00493 main_header = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0); 00494 00495 KMO_TRY_ASSURE(cpl_propertylist_get_int(main_header, NDIT) == ndit, 00496 CPL_ERROR_ILLEGAL_INPUT, 00497 "NDIT isn't the same for all frames: (is %d and %d).", 00498 cpl_propertylist_get_int(main_header, NDIT), ndit); 00499 KMO_TRY_ASSURE(cpl_propertylist_get_double(main_header, EXPTIME) == exptime, 00500 CPL_ERROR_ILLEGAL_INPUT, 00501 "EXPTIME isn't the same for all frames: (is %g and %g).", 00502 cpl_propertylist_get_double(main_header, EXPTIME), exptime); 00503 KMO_TRY_ASSURE(strcmp(cpl_propertylist_get_string(main_header, READMODE), readmode) == 0, 00504 CPL_ERROR_ILLEGAL_INPUT, 00505 "ESO DET READ CURNAME isn't the same for all frames: (is %s and %s).", 00506 cpl_propertylist_get_string(main_header, READMODE), readmode); 00507 00508 desc1 = kmo_identify_fits_header(cpl_frame_get_filename(frame)); 00509 00510 // Verifications 00511 KMO_TRY_ASSURE((desc1.naxis1 == nx) && 00512 (desc1.naxis2 == ny) && 00513 (desc1.naxis3 == nz), 00514 CPL_ERROR_ILLEGAL_INPUT, 00515 "File (%s) hasn't correct dimensions! (x,y): " 00516 "(%d,%d) vs (%d,%d)", 00517 cpl_frame_get_filename(frame), 00518 desc1.naxis1, desc1.naxis2, nx, ny); 00519 KMO_TRY_ASSURE((kmo_check_lamp(main_header, INS_LAMP1_ST) == FALSE) && 00520 (kmo_check_lamp(main_header, INS_LAMP2_ST) == FALSE), 00521 CPL_ERROR_ILLEGAL_INPUT, 00522 "Arc lamps must be switched off (%s)!", 00523 cpl_frame_get_filename(frame)); 00524 cpl_propertylist_delete(main_header); main_header = NULL; 00525 kmo_free_fits_desc(&desc1); 00526 00527 // get next FLAT_OFF frame 00528 frame = kmo_dfs_get_frame(frameset, NULL); 00529 } 00530 cpl_free(readmode) ; 00531 00532 // Get the first ON frame 00533 frame = kmo_dfs_get_frame(frameset, FLAT_ON); 00534 00535 // Get EXPTIME, NDIT, READMODE 00536 main_header = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0); 00537 ndit = cpl_propertylist_get_int(main_header, NDIT); 00538 exptime = cpl_propertylist_get_double(main_header, EXPTIME); 00539 readmode = cpl_strdup(cpl_propertylist_get_string(main_header, READMODE)); 00540 cpl_propertylist_delete(main_header); main_header = NULL; 00541 00542 // Loop on the other ON frames 00543 while (frame != NULL) { 00544 main_header = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0); 00545 00546 KMO_TRY_ASSURE(cpl_propertylist_get_int(main_header, NDIT) == ndit, 00547 CPL_ERROR_ILLEGAL_INPUT, 00548 "NDIT isn't the same for all frames: (is %d and %d).", 00549 cpl_propertylist_get_int(main_header, NDIT), ndit); 00550 KMO_TRY_ASSURE(cpl_propertylist_get_double(main_header, EXPTIME) == exptime, 00551 CPL_ERROR_ILLEGAL_INPUT, 00552 "EXPTIME isn't the same for all frames: (is %g and %g).", 00553 cpl_propertylist_get_double(main_header, EXPTIME), exptime); 00554 KMO_TRY_ASSURE(strcmp(cpl_propertylist_get_string(main_header, READMODE), readmode) == 0, 00555 CPL_ERROR_ILLEGAL_INPUT, 00556 "ESO DET READ CURNAME isn't the same for all frames: (is %s and %s).", 00557 cpl_propertylist_get_string(main_header, READMODE), readmode); 00558 00559 desc1 = kmo_identify_fits_header(cpl_frame_get_filename(frame)); 00560 00561 // Verifications 00562 KMO_TRY_ASSURE((desc1.naxis1 == nx) && 00563 (desc1.naxis2 == ny) && 00564 (desc1.naxis3 == nz), 00565 CPL_ERROR_ILLEGAL_INPUT, 00566 "File (%s) hasn't correct dimensions! (x,y): " 00567 "(%d,%d) vs (%d,%d)", 00568 cpl_frame_get_filename(frame), 00569 desc1.naxis1, desc1.naxis2, nx, ny); 00570 KMO_TRY_ASSURE((kmo_check_lamp(main_header, INS_LAMP1_ST) == FALSE) && 00571 (kmo_check_lamp(main_header, INS_LAMP2_ST) == FALSE), 00572 CPL_ERROR_ILLEGAL_INPUT, 00573 "Arc lamps must be switched off (%s)!", 00574 cpl_frame_get_filename(frame)); 00575 KMO_TRY_ASSURE((kmo_check_lamp(main_header, INS_LAMP3_ST) == TRUE) || 00576 (kmo_check_lamp(main_header, INS_LAMP4_ST) == TRUE), 00577 CPL_ERROR_ILLEGAL_INPUT, 00578 "At least one flat lamps must be switched on (%s)!", 00579 cpl_frame_get_filename(frame)); 00580 00581 cpl_propertylist_delete(main_header); main_header = NULL; 00582 kmo_free_fits_desc(&desc1); 00583 00584 // get next FLAT_ON frame 00585 frame = kmo_dfs_get_frame(frameset, NULL); 00586 } 00587 00588 // ------------ check filter_id, grating_id and rotator offset --------- 00589 // must match for all detectors 00590 kmo_check_frameset_setup(frameset, FLAT_ON, TRUE, FALSE, FALSE); 00591 00592 // Get the first ON frame 00593 frame = kmo_dfs_get_frame(frameset, FLAT_ON); 00594 suffix = kmo_dfs_get_suffix(frame, TRUE, FALSE); 00595 00596 cpl_msg_info("", "Detected instrument setup: %s", suffix+1); 00597 00598 /*********************************************************/ 00599 /* Comment - This should be done in an external Function */ 00600 int rotang_found[ANGLE_DIM]; 00601 int rotang_cnt[ANGLE_DIM]; 00602 for (int i=0; i<ANGLE_DIM; i++) { 00603 rotang_found[i] = 0; 00604 rotang_cnt[i] = 0; 00605 } 00606 // Get the first ON frame 00607 frame = kmo_dfs_get_frame(frameset, FLAT_ON); 00608 while (frame != NULL) { 00609 main_header = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0); 00610 if (cpl_propertylist_has(main_header, ROTANGLE)) { 00611 int rot_angle = (int) rint(cpl_propertylist_get_double(main_header, ROTANGLE)); 00612 if (rot_angle < 0) { 00613 rot_angle += 360; 00614 } 00615 if (rot_angle < 360 && rot_angle >= 0) 00616 rotang_cnt[rot_angle]++; 00617 } else { 00618 cpl_msg_warning("","File %s has no keyword \"ROTANGLE\"", 00619 cpl_frame_get_filename(frame)); 00620 } 00621 00622 cpl_propertylist_delete(main_header); main_header = NULL; 00623 frame = kmo_dfs_get_frame(frameset, NULL); 00624 } 00625 nr_angles = 0; 00626 for (int ax=0; ax<ANGLE_DIM; ax++) { 00627 if (rotang_cnt[ax] != 0) { 00628 rotang_found[nr_angles] = ax; 00629 nr_angles++; 00630 } 00631 } 00632 00633 /* Create one frameset per angle */ 00634 angle_frameset = (cpl_frameset **) cpl_malloc(nr_angles * sizeof(cpl_frameset*)); 00635 for (int i =0; i<nr_angles; i++) { 00636 angle_frameset[i] = cpl_frameset_new(); 00637 } 00638 00639 // Get the first ON frame 00640 frame = kmo_dfs_get_frame(frameset, FLAT_ON); 00641 while (frame != NULL) { 00642 main_header = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0); 00643 if (cpl_propertylist_has(main_header, ROTANGLE)) { 00644 int rot_angle = (int) rint(cpl_propertylist_get_double(main_header, ROTANGLE)); 00645 if (rot_angle < 0) { 00646 rot_angle += 360; 00647 } 00648 int ix = -1; 00649 for (ix = 0; ix<nr_angles; ix++) { 00650 if (rotang_found[ix] == rot_angle) { 00651 break; 00652 } 00653 } 00654 if (ix<nr_angles) { 00655 KMO_TRY_EXIT_IF_ERROR( 00656 cpl_frameset_insert(angle_frameset[ix], cpl_frame_duplicate(frame))); 00657 } 00658 } 00659 00660 cpl_propertylist_delete(main_header); main_header = NULL; 00661 frame = kmo_dfs_get_frame(frameset, NULL); 00662 KMO_TRY_CHECK_ERROR_STATE(); 00663 } 00664 /* End Comment */ 00665 /********************************************************/ 00666 00667 // check which IFUs are active for all FLAT_ON frames 00668 unused_ifus_before = kmo_get_unused_ifus(frameset, 0, 0); 00669 unused_ifus_after = kmo_duplicate_unused_ifus(unused_ifus_before); 00670 kmo_print_unused_ifus(unused_ifus_before, FALSE); 00671 cpl_msg_info("", "EXPTIME: %g seconds", exptime); 00672 cpl_msg_info("", "NDIT: %d", ndit); 00673 cpl_msg_info("", "Detector readout mode: %s", readmode); 00674 00675 // ######################################################### 00676 // ### allocate temporary memory 00677 // ######################################################### 00678 // Get the first ON frame 00679 frame = kmo_dfs_get_frame(frameset, FLAT_ON); 00680 00681 desc1 = kmo_identify_fits_header(cpl_frame_get_filename(frame)); 00682 00683 nr_devices = desc1.nr_ext; 00684 00685 // the frames have to be stored temporarily because the QC parameters 00686 // for the main header are calculated from each detector. So they can be 00687 // stored only when all detectors are processed 00688 stored_flat = (cpl_image**)cpl_calloc(nr_devices * nr_angles, sizeof(cpl_image*)); 00689 stored_noise = (cpl_image**)cpl_calloc(nr_devices * nr_angles, sizeof(cpl_image*)); 00690 stored_badpix = (cpl_image**)cpl_calloc(nr_devices * nr_angles, sizeof(cpl_image*)); 00691 stored_xcal = (cpl_image**)cpl_calloc(nr_devices * nr_angles, sizeof(cpl_image*)); 00692 stored_ycal = (cpl_image**)cpl_calloc(nr_devices * nr_angles, sizeof(cpl_image*)); 00693 stored_qc_flat_sat = (int*)cpl_malloc(nr_devices * nr_angles * sizeof(int)); 00694 stored_qc_flat_eff = (double*)cpl_malloc(nr_devices * nr_angles * sizeof(double)); 00695 stored_qc_flat_sn = (double*)cpl_malloc(nr_devices * nr_angles * sizeof(double)); 00696 stored_gapmean = (double*)cpl_malloc(nr_devices * nr_angles * sizeof(double)); 00697 stored_gapsdv = (double*)cpl_malloc(nr_devices * nr_angles * sizeof(double)); 00698 stored_gapmaxdev = (double*)cpl_malloc(nr_devices * nr_angles * sizeof(double)); 00699 stored_slitmean = (double*)cpl_malloc(nr_devices * nr_angles * sizeof(double)); 00700 stored_slitsdv = (double*)cpl_malloc(nr_devices * nr_angles * sizeof(double)); 00701 stored_slitmaxdev = (double*)cpl_malloc(nr_devices * nr_angles * sizeof(double)); 00702 spec_found = (cpl_error_code*)cpl_malloc(nr_devices * nr_angles * sizeof(cpl_error_code)); 00703 edge_table = (cpl_table***)cpl_malloc(KMOS_NR_DETECTORS * nr_angles * sizeof(cpl_table**)); 00704 00705 // initialize to NULL 00706 for (i = 0; i < nr_devices * nr_angles ; i++) { 00707 stored_qc_flat_sat[i] = 0.0; 00708 stored_qc_flat_eff[i] = 0.0; 00709 stored_qc_flat_sn[i] = 0.0; 00710 stored_gapmean[i] = 0.0; 00711 stored_gapsdv[i] = 0.0; 00712 stored_gapmaxdev[i] = 0.0; 00713 stored_slitmean[i] = 0.0; 00714 stored_slitsdv[i] = 0.0; 00715 stored_slitmaxdev[i] = 0.0; 00716 spec_found[i] = CPL_ERROR_NONE; 00717 } 00718 for (int i = 0; i < KMOS_NR_DETECTORS * nr_angles; i++) edge_table[i] = NULL; 00719 00720 // ############################################################################# 00721 // ### process data 00722 // ############################################################################# 00723 00724 /* ------------ loop all rotator angles and detectors ------------ */ 00725 for (a = 0; a<nr_angles; a++) { 00726 cpl_msg_info("","Processing rotator angle %d -> %d degree", a,rotang_found[a]); 00727 for (i = 1; i <= nr_devices; i++) { 00728 cpl_msg_info(""," Processing detector No. %d", i); 00729 00730 sx = a * nr_devices + (i - 1); 00731 00732 bad_pix_mask_dark = kmo_dfs_load_image(frameset, BADPIXEL_DARK, 00733 i, 2, FALSE, NULL); 00734 00735 /* ------------ load all lamp_on and lamp_off images ------------ */ 00736 det_lamp_on = cpl_imagelist_new(); 00737 det_lamp_off = cpl_imagelist_new(); 00738 00739 /* load lamp-on images */ 00740 frame = kmo_dfs_get_frame(angle_frameset[a], FLAT_ON); 00741 j = 0; 00742 while (frame != NULL) { 00743 img_in = kmo_dfs_load_image_frame(frame, i, FALSE, TRUE, &nr_sat); 00744 kmo_image_reject_from_mask(img_in, bad_pix_mask_dark); 00745 cpl_imagelist_set(det_lamp_on, img_in, j++); 00746 frame = kmo_dfs_get_frame(angle_frameset[a], NULL); 00747 } 00748 00749 /* load lamp-off images */ 00750 frame = kmo_dfs_get_frame(frameset, FLAT_OFF); 00751 j = 0; 00752 while (frame != NULL) { 00753 img_in = kmo_dfs_load_image_frame(frame, i, FALSE, FALSE, NULL); 00754 kmo_image_reject_from_mask(img_in, bad_pix_mask_dark); 00755 cpl_imagelist_set(det_lamp_off, img_in, j++); 00756 frame = kmo_dfs_get_frame(frameset, NULL); 00757 } 00758 00759 /* ------------ process imagelist ------------ */ 00760 00761 /* count saturated pixels for each detector */ 00762 frame = kmo_dfs_get_frame(angle_frameset[a], FLAT_ON); 00763 main_header = kmclipm_propertylist_load( 00764 cpl_frame_get_filename(frame), 0); 00765 if (strcmp(cpl_propertylist_get_string(main_header, READMODE), "Nondest") == 0) { 00766 // NDR: non-destructive readout mode 00767 stored_qc_flat_sat[sx] = nr_sat; 00768 } else { 00769 // normal readout mode 00770 stored_qc_flat_sat[sx] = kmo_imagelist_get_saturated(det_lamp_on, 00771 KMO_FLAT_SATURATED, KMO_FLAT_SAT_MIN); 00772 } 00773 cpl_propertylist_delete(main_header); main_header = NULL; 00774 00775 // combine imagelists and create noise 00776 kmclipm_combine_frames(det_lamp_on, NULL, 00777 NULL, 00778 cmethod, cpos_rej, cneg_rej, citer, 00779 cmax, cmin, 00780 &combined_data_on, 00781 &combined_noise_on, 00782 -1.0); 00783 00784 kmclipm_combine_frames(det_lamp_off, NULL, 00785 NULL, 00786 cmethod, cpos_rej, cneg_rej, citer, 00787 cmax, cmin, 00788 &combined_data_off, 00789 &combined_noise_off, 00790 -1.0); 00791 00792 if (kmclipm_omit_warning_one_slice > 10) { 00793 cpl_msg_warning(cpl_func, "Previous warning (number of " 00794 "identified slices) occured %d times.", 00795 kmclipm_omit_warning_one_slice); 00796 kmclipm_omit_warning_one_slice = FALSE; 00797 } 00798 00799 // subtract combined lamp_off from lamp_on 00800 // (for noise: sig_x = sqrt(sig_u^2 + sig_v^2) 00801 cpl_image_subtract(combined_data_on, combined_data_off); 00802 00803 cpl_image_power(combined_noise_on, 2.0); 00804 cpl_image_power(combined_noise_off, 2.0); 00805 cpl_image_add(combined_noise_on, combined_noise_off); 00806 cpl_image_power(combined_noise_on, 0.5); 00807 00808 // create bad-pixel-mask 00809 bad_pix_mask_flat = kmo_create_bad_pix_flat_thresh( 00810 combined_data_on, surrounding_pixels, badpix_thresh); 00811 00812 // calculate spectral curvature here 00813 spec_found[sx] = kmo_calc_curvature(combined_data_on, 00814 combined_noise_on, unused_ifus_after[i-1], bad_pix_mask_flat, 00815 i, &xcal, &ycal, stored_gapmean+(sx), stored_gapsdv+(sx), 00816 stored_gapmaxdev+(sx), stored_slitmean+(sx), stored_slitsdv+(sx), 00817 stored_slitmaxdev+(sx), &edge_table[sx]); 00818 00819 if (spec_found[sx] == CPL_ERROR_NONE) { 00820 // in kmo_calc_curvature() the spectral slope of each slitlet 00821 // has been normalised individually. Now the normalisation on 00822 // the whole frame is applied. (cpl_image_get_mean() 00823 // ignores bad pixels when calculating the mean) 00824 mean_data = cpl_image_get_mean(combined_data_on); 00825 00826 stored_qc_flat_eff[sx] = mean_data / exptime; 00827 00828 mean_noise = cpl_image_get_mean(combined_noise_on); 00829 00830 if ((cpl_frameset_count_tags(frameset, FLAT_OFF) > 1) || 00831 (cpl_frameset_count_tags(frameset, FLAT_ON) > 1)) { 00832 KMO_TRY_ASSURE(mean_noise != 0.0, 00833 CPL_ERROR_ILLEGAL_INPUT, 00834 "All frames of detector %i are exactly " 00835 "the same!", i); 00836 stored_qc_flat_sn[sx] = mean_data / mean_noise; 00837 } 00838 00839 // normalize data & noise on the whole detector frame (the 00840 // spectral slope on each slitlet has already been normalised in 00841 // kmo_calc_curvature()) 00842 cpl_image_divide_scalar(combined_data_on, mean_data); 00843 cpl_image_divide_scalar(combined_noise_on, mean_data); 00844 00845 // apply the badpixel mask to the produced frames 00846 cpl_image_multiply(combined_data_on, bad_pix_mask_flat); 00847 cpl_image_multiply(combined_noise_on, bad_pix_mask_flat); 00848 cpl_image_multiply(xcal, bad_pix_mask_flat); 00849 cpl_image_multiply(ycal, bad_pix_mask_flat); 00850 00851 /* ------ store temporarily flat, badpixel and calibration ----- */ 00852 stored_flat[sx] = combined_data_on; 00853 stored_noise[sx] = combined_noise_on; 00854 stored_badpix[sx] = bad_pix_mask_flat; 00855 stored_xcal[sx] = xcal; 00856 stored_ycal[sx] = ycal; 00857 } else if (spec_found[sx] == CPL_ERROR_DATA_NOT_FOUND) { 00858 // all IFUs seem to be deativated, continue processing 00859 // just save empty frames 00860 cpl_error_reset(); 00861 cpl_image_delete(combined_data_on); combined_data_on = NULL; 00862 cpl_image_delete(combined_noise_on); combined_noise_on = NULL; 00863 cpl_image_delete(bad_pix_mask_flat); bad_pix_mask_flat = NULL; 00864 } else { 00865 // another error occured 00866 KMO_TRY_CHECK_ERROR_STATE(); 00867 } 00868 // free memory 00869 cpl_imagelist_delete(det_lamp_on); det_lamp_on = NULL; 00870 cpl_imagelist_delete(det_lamp_off); det_lamp_off = NULL; 00871 cpl_image_delete(combined_data_off); combined_data_off = NULL; 00872 cpl_image_delete(combined_noise_off); combined_noise_off = NULL; 00873 cpl_image_delete(bad_pix_mask_dark); bad_pix_mask_dark = NULL; 00874 } // for i = 1; i <= nr_devices 00875 } // for a = 0; a < nr_angles 00876 00877 00878 // ############################################################################# 00879 // ### QC parameters & saving 00880 // ############################################################################# 00881 /* ------------ load, update & save primary header ------------ */ 00882 main_header = kmo_dfs_load_primary_header(frameset, FLAT_ON); 00883 00884 // update which IFUs are not used 00885 kmo_print_unused_ifus(unused_ifus_after, TRUE); 00886 00887 kmo_set_unused_ifus(unused_ifus_after, main_header, "kmo_flat"); 00888 00889 // write main_header for data-, noise-, ycal- and badpix-frame 00890 // xcal gets additionally the boundaries of the IFUs for reconstruction 00891 00892 // add here boundaries for reconstruction 00893 main_header_xcal = cpl_propertylist_new(); 00894 00895 total_bounds = (int**)cpl_malloc(nr_devices*sizeof(int*)); 00896 for (i = 0; i<nr_devices; i++) { 00897 total_bounds[i] = (int*) cpl_calloc(2*KMOS_IFUS_PER_DETECTOR,sizeof(int)); 00898 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00899 total_bounds[i][2*j] = 2048; 00900 total_bounds[i][2*j+1] = 0; 00901 } 00902 } 00903 00904 all_bounds = (int***) cpl_malloc(nr_angles*sizeof(int**)); 00905 for (a = 0; a<nr_angles; a++) { 00906 all_bounds[a] = (int**) cpl_malloc(nr_devices*sizeof(int*)); 00907 for (i = 0; i<nr_devices; i++) { 00908 all_bounds[a][i] = (int*) cpl_calloc(2*KMOS_IFUS_PER_DETECTOR,sizeof(int)); 00909 } 00910 } 00911 00912 for (a = 0; a<nr_angles; a++) { 00913 for (i = 0; i < nr_devices; i++) { 00914 sx = a * nr_devices + i; 00915 bounds = kmo_split_frame(stored_ycal[sx]); 00916 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00917 all_bounds[a][i][2*j] = bounds[2*j]; 00918 all_bounds[a][i][2*j+1] = bounds[2*j+1]; 00919 00920 if (total_bounds[i][2*j] >= 0 ) { 00921 if (bounds[2*j] < 0) { 00922 total_bounds[i][2*j] = bounds[2*j]; 00923 } else { 00924 if (total_bounds[i][2*j] > bounds[2*j]) { 00925 total_bounds[i][2*j] = bounds[2*j]; 00926 } 00927 } 00928 } 00929 if (total_bounds[i][2*j+1] >= 0 ) { 00930 if (bounds[2*j+1] < 0) { 00931 total_bounds[i][2*j+1] = bounds[2*j+1]; 00932 } else { 00933 if (total_bounds[i][2*j+1] < bounds[2*j+1]) { 00934 total_bounds[i][2*j+1] = bounds[2*j+1]; 00935 } 00936 } 00937 } 00938 } 00939 if (bounds != NULL) { 00940 cpl_free(bounds); bounds = NULL; 00941 } 00942 00943 } 00944 } 00945 for (i = 0; i < nr_devices; i++) { 00946 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00947 if (total_bounds[i][2*j] > -1) { 00948 tmpstr= cpl_sprintf("%s%d%s", BOUNDS_PREFIX, 00949 i*KMOS_IFUS_PER_DETECTOR + j+1, "_L"); 00950 kmclipm_update_property_int(main_header_xcal, tmpstr, 00951 total_bounds[i][2*j], "[pix] left boundary for reconstr."); 00952 cpl_free(tmpstr); tmpstr = NULL; 00953 } 00954 00955 if (total_bounds[i][2*j+1] > -1) { 00956 tmpstr= cpl_sprintf("%s%d%s", BOUNDS_PREFIX, 00957 i*KMOS_IFUS_PER_DETECTOR + j+1, "_R"); 00958 kmclipm_update_property_int(main_header_xcal, tmpstr, 00959 total_bounds[i][2*j+1], "[pix] right boundary for reconstr."); 00960 cpl_free(tmpstr); tmpstr = NULL; 00961 } 00962 } 00963 } // for (nr_devices) 00964 00965 // ------------ saving headers ------------ 00966 cpl_msg_info("","Saving data..."); 00967 00968 frame = kmo_dfs_get_frame(frameset, FLAT_ON); 00969 00970 kmo_dfs_save_main_header(frameset, FLAT_NAME, suffix, frame, main_header, parlist, cpl_func); 00971 kmo_dfs_save_main_header(frameset, XCAL_NAME, suffix, frame, main_header_xcal, parlist, cpl_func); 00972 kmo_dfs_save_main_header(frameset, YCAL, suffix, frame, main_header, parlist, cpl_func); 00973 kmo_dfs_save_main_header(frameset, BAD_NAME, suffix, frame, main_header, parlist, cpl_func); 00974 kmo_dfs_save_main_header(frameset, FLAT_EDGE_NAME, suffix, frame, main_header, parlist, cpl_func); 00975 00976 cpl_propertylist_delete(main_header); main_header = NULL; 00977 cpl_propertylist_delete(main_header_xcal); main_header_xcal = NULL; 00978 00979 // ------------ saving sub frames ------------ 00980 for (a = 0; a<nr_angles; a++) { 00981 for (i = 1; i <= nr_devices; i++) { 00982 sx = a * nr_devices + (i - 1); 00983 00984 sub_header = kmo_dfs_load_sub_header(frameset, FLAT_ON, i, FALSE); 00985 cpl_propertylist_erase(sub_header, CRPIX1); 00986 cpl_propertylist_erase(sub_header, CRPIX2); 00987 00988 kmclipm_update_property_double(sub_header,CAL_ROTANGLE, ((double) rotang_found[a]), 00989 "[deg] Rotator relative to nasmyth"); 00990 if (i == 1) { 00991 for (ii = 0; ii < nr_devices; ii++) { 00992 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00993 if (all_bounds[a][ii][2*j] > -1) { 00994 tmpstr= cpl_sprintf("%s%d%s", BOUNDS_PREFIX, 00995 ii*KMOS_IFUS_PER_DETECTOR + j+1, "_L"); 00996 kmclipm_update_property_int(sub_header, tmpstr, 00997 all_bounds[a][ii][2*j], "[pix] left boundary for reconstr."); 00998 cpl_free(tmpstr); tmpstr = NULL; 00999 } 01000 if (all_bounds[a][ii][2*j+1] > -1) { 01001 tmpstr= cpl_sprintf("%s%d%s", BOUNDS_PREFIX, 01002 ii-1*KMOS_IFUS_PER_DETECTOR + j+1, "_R"); 01003 kmclipm_update_property_int(sub_header, tmpstr, 01004 all_bounds[a][ii][2*j+1], "[pix] right boundary for reconstr."); 01005 cpl_free(tmpstr); tmpstr = NULL; 01006 } 01007 } 01008 } // for (nr_devices) 01009 } 01010 01011 if (spec_found[sx] == CPL_ERROR_NONE) { 01012 kmclipm_update_property_int(sub_header, QC_FLAT_SAT, 01013 stored_qc_flat_sat[sx], "[] nr. saturated pixels of master flat"); 01014 // load gain 01015 gain = kmo_dfs_get_property_double(sub_header, GAIN); 01016 KMO_TRY_CHECK_ERROR_STATE_MSG("GAIN-keyword in fits-header is missing!"); 01017 01018 kmclipm_update_property_double(sub_header, QC_FLAT_EFF, 01019 stored_qc_flat_eff[sx]/gain, "[e-/s] rel. brightness of flat lamp"); 01020 kmclipm_update_property_double(sub_header, QC_FLAT_SN, stored_qc_flat_sn[sx], 01021 "[] S/N of master flat"); 01022 } 01023 01024 // store qc parameters only if any slitlet- and gap-width has been 01025 // detected (should be the case when at least one IFU is active) 01026 if (stored_xcal[sx] != NULL) { 01027 kmclipm_update_property_double(sub_header, QC_GAP_MEAN, 01028 stored_gapmean[sx], "[pix] mean gap width between slitlets"); 01029 kmclipm_update_property_double(sub_header, QC_GAP_SDV, 01030 stored_gapsdv[sx], "[pix] stdev of gap width between slitlets"); 01031 kmclipm_update_property_double(sub_header, QC_GAP_MAXDEV, 01032 stored_gapmaxdev[sx], "[pix] max gap deviation between slitlets"); 01033 kmclipm_update_property_double(sub_header, QC_SLIT_MEAN, 01034 stored_slitmean[sx], "[pix] mean slitlet width"); 01035 kmclipm_update_property_double(sub_header, QC_SLIT_SDV, 01036 stored_slitsdv[sx], "[pix] stdev of slitlet widths"); 01037 kmclipm_update_property_double(sub_header, QC_SLIT_MAXDEV, 01038 stored_slitmaxdev[sx], "[pix] max slitlet width deviation"); 01039 } 01040 01041 if (spec_found[sx] == CPL_ERROR_DATA_NOT_FOUND) { 01042 stored_flat[sx] = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01043 stored_noise[sx] = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01044 stored_badpix[sx] = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01045 stored_xcal[sx] = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01046 stored_ycal[sx] = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01047 } 01048 01049 // calculate QC.BADPIX.NCOUNT 01050 nr_bad_pix = cpl_image_count_rejected(stored_badpix[sx]); 01051 01052 // remove 4pixel-border as bad pixels 01053 nr_bad_pix -= 2*KMOS_BADPIX_BORDER*(nx-2*KMOS_BADPIX_BORDER) + 01054 2*KMOS_BADPIX_BORDER*ny; 01055 01056 kmclipm_update_property_int(sub_header, QC_NR_BAD_PIX, nr_bad_pix, 01057 "[] nr. of bad pixels"); 01058 01059 // save flat frame 01060 extname = kmo_extname_creator(detector_frame, i, EXT_DATA); 01061 kmclipm_update_property_string(sub_header, EXTNAME, extname, "FITS extension name"); 01062 cpl_free(extname); extname = NULL; 01063 01064 kmo_dfs_save_image(stored_flat[sx], FLAT_NAME, suffix, sub_header, 0./0.); 01065 01066 // save noise frame only when enough input frames were available 01067 extname = kmo_extname_creator(detector_frame, i, EXT_NOISE); 01068 kmclipm_update_property_string(sub_header, EXTNAME, extname, "FITS extension name"); 01069 cpl_free(extname); extname = NULL; 01070 01071 kmo_dfs_save_image(stored_noise[sx], FLAT_NAME, suffix, sub_header, 0./0.); 01072 01073 // save bad_pix frame 01074 extname = kmo_extname_creator(detector_frame, i, EXT_BADPIX); 01075 kmclipm_update_property_string(sub_header, EXTNAME, extname, "FITS extension name"); 01076 cpl_free(extname); extname = NULL; 01077 01078 kmo_dfs_save_image(stored_badpix[sx], BAD_NAME, suffix, sub_header, 0.); 01079 01080 // save xcal and ycal-frame 01081 extname = kmo_extname_creator(detector_frame, i, EXT_DATA); 01082 kmclipm_update_property_string(sub_header, EXTNAME, extname, "FITS extension name"); 01083 cpl_free(extname); extname = NULL; 01084 01085 kmo_dfs_save_image(stored_xcal[sx], XCAL_NAME, suffix, sub_header, 0./0.); 01086 kmo_dfs_save_image(stored_ycal[sx], YCAL_NAME, suffix, sub_header, 0./0.); 01087 01088 // save edge_pars-frame 01089 extname = kmo_extname_creator(list_frame, i, EXT_DATA); 01090 kmclipm_update_property_string(sub_header, EXTNAME, extname, "FITS extension name"); 01091 cpl_free(extname); extname = NULL; 01092 01093 for (int j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01094 kmclipm_update_property_int(sub_header, CAL_IFU_NR, 01095 j+1+(i-1)*KMOS_IFUS_PER_DETECTOR, "IFU Number {1..24}"); 01096 01097 // save edge-parameters as product 01098 kmo_dfs_save_table(edge_table[sx][j], FLAT_EDGE_NAME, suffix, sub_header); 01099 } 01100 cpl_propertylist_delete(sub_header); sub_header = NULL; 01101 } 01102 } 01103 } 01104 KMO_CATCH 01105 { 01106 KMO_CATCH_MSG(); 01107 ret_val = -1; 01108 } 01109 01110 kmo_free_fits_desc(&desc1); 01111 kmo_free_fits_desc(&desc2); 01112 kmo_free_unused_ifus(unused_ifus_before); unused_ifus_before = NULL; 01113 kmo_free_unused_ifus(unused_ifus_after); unused_ifus_after = NULL; 01114 cpl_propertylist_delete(main_header); main_header = NULL; 01115 cpl_propertylist_delete(main_header_xcal); main_header_xcal = NULL; 01116 cpl_propertylist_delete(sub_header); sub_header = NULL; 01117 cpl_imagelist_delete(det_lamp_on); det_lamp_on = NULL; 01118 cpl_imagelist_delete(det_lamp_off); det_lamp_off = NULL; 01119 cpl_image_delete(combined_data_off); combined_data_off = NULL; 01120 cpl_image_delete(combined_noise_off); combined_noise_off = NULL; 01121 cpl_image_delete(bad_pix_mask_dark); bad_pix_mask_dark = NULL; 01122 cpl_free(stored_qc_flat_sat); stored_qc_flat_sat = NULL; 01123 cpl_free(stored_qc_flat_eff); stored_qc_flat_eff = NULL; 01124 cpl_free(stored_qc_flat_sn); stored_qc_flat_sn = NULL; 01125 cpl_free(stored_gapmean); stored_gapmean = NULL; 01126 cpl_free(stored_gapsdv); stored_gapsdv = NULL; 01127 cpl_free(stored_gapmaxdev); stored_gapmaxdev = NULL; 01128 cpl_free(stored_slitmean); stored_slitmean = NULL; 01129 cpl_free(stored_slitsdv); stored_slitsdv = NULL; 01130 cpl_free(stored_slitmaxdev); stored_slitmaxdev = NULL; 01131 cpl_free(readmode); readmode = NULL; 01132 cpl_free(suffix); suffix = NULL; 01133 01134 for (int i = 0; i < nr_devices; i++) { 01135 cpl_free(total_bounds[i]); total_bounds[i] = NULL; 01136 } 01137 cpl_free(total_bounds); total_bounds = NULL; 01138 01139 for (int i = 0; i < nr_devices * nr_angles; i++) { 01140 cpl_image_delete(stored_flat[i]); stored_flat[i] = NULL; 01141 cpl_image_delete(stored_noise[i]); stored_noise[i] = NULL; 01142 cpl_image_delete(stored_badpix[i]); stored_badpix[i] = NULL; 01143 cpl_image_delete(stored_xcal[i]); stored_xcal[i] = NULL; 01144 cpl_image_delete(stored_ycal[i]); stored_ycal[i] = NULL; 01145 } 01146 cpl_free(stored_flat); stored_flat = NULL; 01147 cpl_free(stored_noise); stored_noise = NULL; 01148 cpl_free(stored_badpix); stored_badpix = NULL; 01149 cpl_free(stored_xcal); stored_xcal = NULL; 01150 cpl_free(stored_ycal); stored_ycal = NULL; 01151 for (int i = 0; i < nr_angles; i++) { 01152 cpl_frameset_delete(angle_frameset[i]); angle_frameset[i] = NULL; 01153 } 01154 cpl_free(angle_frameset); angle_frameset = NULL; 01155 if (edge_table != NULL) { 01156 for (int i = 0; i < KMOS_NR_DETECTORS * nr_angles; i++) { 01157 if (edge_table[i] != NULL) { 01158 for (int j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01159 cpl_table_delete(edge_table[i][j]); 01160 edge_table[i][j] = NULL; 01161 } 01162 cpl_free(edge_table[i]); edge_table[i] = NULL; 01163 } 01164 } 01165 cpl_free(edge_table); edge_table = NULL; 01166 } 01167 if (bounds != NULL) { 01168 cpl_free(bounds); bounds = NULL; 01169 } 01170 if (spec_found != NULL) { 01171 cpl_free(spec_found); spec_found = NULL; 01172 } 01173 01174 return ret_val; 01175 } 01176
1.7.6.1