|
KMOS Pipeline Reference Manual
1.3.7
|
00001 /* 00002 * This file is part of the KMOS Pipeline 00003 * Copyright (C) 2002,2003 European Southern Observatory 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00018 */ 00019 00020 #ifdef HAVE_CONFIG_H 00021 #include <config.h> 00022 #endif 00023 00024 /*----------------------------------------------------------------------------- 00025 * Includes 00026 *----------------------------------------------------------------------------*/ 00027 00028 #include <string.h> 00029 #include <math.h> 00030 00031 #include <cpl.h> 00032 00033 #include "kmo_utils.h" 00034 #include "kmo_priv_flat.h" 00035 #include "kmo_priv_functions.h" 00036 #include "kmo_dfs.h" 00037 #include "kmo_error.h" 00038 #include "kmo_constants.h" 00039 #include "kmo_cpl_extensions.h" 00040 #include "kmo_debug.h" 00041 00042 /*----------------------------------------------------------------------------- 00043 * Functions prototypes 00044 *----------------------------------------------------------------------------*/ 00045 00046 static int kmos_flat_check_inputs(cpl_frameset *, int *, int *, int *,double *); 00047 static cpl_propertylist * kmos_create_bounds_properties(cpl_image **,int, int) ; 00048 00049 static int kmos_flat_create(cpl_plugin *); 00050 static int kmos_flat_exec(cpl_plugin *); 00051 static int kmos_flat_destroy(cpl_plugin *); 00052 static int kmos_flat(cpl_parameterlist *, cpl_frameset *); 00053 00054 /*----------------------------------------------------------------------------- 00055 * Static variables 00056 *----------------------------------------------------------------------------*/ 00057 00058 static char kmos_flat_description[] = 00059 "This recipe creates the master flat field and calibration frames needed for\n" 00060 "spatial calibration for all three detectors. It must be called after the \n" 00061 "kmo_dark-recipe, which generates a bad pixel mask (badpixel_dark.fits). The\n" 00062 "bad pixel mask will be updated in this recipe.\n" 00063 "As input at least 3 dark frames, 3 frames with the flat lamp on are\n" 00064 "recommended. Additionally a badpixel mask from kmo_dark is required.\n" 00065 "\n" 00066 "The badpixel mask contains 0 for bad pixels and 1 for good ones.\n" 00067 "\n" 00068 "The structure of the resulting xcal and ycal frames is quite complex since\n" 00069 "the arrangement of the IFUs isn't just linear on the detector. Basically the\n" 00070 "integer part of the calibration data shows the offset of each pixels centre\n" 00071 "in mas (Milli arcsec) from the field centre. The viewing of an IFU is\n" 00072 "2800 mas (14pix*0.2arcsec/pix). So the values in these two frames will vary\n" 00073 "between +/-1500 (One would expect 1400, but since the slitlets aren't\n" 00074 "expected to be exactly vertical, the values can even go up to around 1500).\n" 00075 "Additionally in the calibration data in y-direction the decimal part of the\n" 00076 "data designates the IFU to which the slitlet corresponds to (for each\n" 00077 "detector from 1 to 8).\n" 00078 "Because of the irregular arrangement of the IFUs not all x-direction\n" 00079 "calibration data is found in xcal and similarly not all y-direction\n" 00080 "calibration data is located in ycal. For certain IFUs they are switched\n" 00081 " and/or flipped in x- or y-direction:\n" 00082 "For IFUs 1,2,3,4,13,14,15,16: x- and y- data is switched\n" 00083 "For IFUs 17,18,19,20: y-data is flipped \n" 00084 "For IFUs 21,22,23,24: x-data is flipped \n" 00085 "For IFUs 5,6,7,8,9,10,11,12: x- and y- data is switched and\n" 00086 " x- and y- data is flipped\n" 00087 "\n" 00088 "Furthermore frames can be provided for several rotator angles. In this case\n" 00089 "the resulting calibration frames for each detector are repeatedly saved as \n" 00090 "extension for every angle.\n" 00091 "\n" 00092 "Advanced features:\n" 00093 "------------------\n" 00094 "To create the badpixel mask the edges of all slitlets are fitted to a\n" 00095 "polynomial. Since it can happen that some of these fits (3 detectors\n" 00096 "8 IFUs * 14slitlets * 2 edges (left and right edge of slitlet)= 672 edges)\n" 00097 "fail, the fit parameters are themselves fitted again to detect any outliers.\n" 00098 "By default, the parameters of all left and all right edges are grouped\n" 00099 "individually and then fitted using chebyshev polynomials. The advantage of\n" 00100 "a chebyshev polynomial is, that it consists in fact of a series of\n" 00101 "orthogonal polynomials. This implies that the parameters of the polynomials\n" 00102 "are independent. This fact predestines the use of chebyshev polynomials\n" 00103 "for our case. So each individual parameter can be examined independently.\n" 00104 "The reason why the left and right edges are fitted individually is that\n" 00105 "there is a systematic pattern specific to these groups. The reason for\n" 00106 "this pattern is probably to be found in the optical path the light is\n" 00107 "traversing.\n" 00108 "\n" 00109 "The behaviour of this fitting step can be influenced via environment\n" 00110 "parameters:\n" 00111 "* KF_ALLPARS (default: 1)\n" 00112 " When set to 1 all coefficients of the polynomial of an edge are to be\n" 00113 " corrected, also when just one of these coefficients is an outlier. When\n" 00114 " set to 0 only the outlier is to be corrected.\n" 00115 "* KF_CH (default: 1)\n" 00116 " When set to 1 chebyshev polynomials are used to fit the fitted parameters.\n" 00117 " When set to 0 normal polynomials are used.\n" 00118 "* KF_SIDES (default: 2)\n" 00119 " This variable can either be set to 1 or 2. When set to 2 the left and\n" 00120 " right edges are examined individually. When set to 1 all edges are\n" 00121 " examined as one group.\n" 00122 "* KF_FACTOR(default: 4)\n" 00123 " This factor defines the threshold factor. All parameters deviating \n" 00124 " KF_FACTOR*stddev are to be corrected\n" 00125 "\n" 00126 "BASIC PARAMETERS:\n" 00127 "-----------------\n" 00128 "--badpix_thresh\n" 00129 "The threshold level to mark pixels as bad on the dark subtracted frames [%]" 00130 "\n" 00131 "--surrounding_pixels\n" 00132 "The amount of bad pixels to surround a specific pixel, to let it be marked\n" 00133 "bad as well.\n" 00134 "\n" 00135 "--cmethod\n" 00136 "Following methods of frame combination are available:\n" 00137 " * 'ksigma' (Default)\n" 00138 " An iterative sigma clipping. For each position all pixels in the\n" 00139 " spectrum are examined. If they deviate significantly, they will be\n" 00140 " rejected according to the conditions:\n" 00141 " val > mean + stdev * cpos_rej\n" 00142 " and\n" 00143 " val < mean - stdev * cneg_rej\n" 00144 " where --cpos_rej, --cneg_rej and --citer are the configuration\n" 00145 " parameters. In the first iteration median and percentile level are used.\n" 00146 "\n" 00147 " * 'median'\n" 00148 " At each pixel position the median is calculated.\n" 00149 "\n" 00150 " * 'average'\n" 00151 " At each pixel position the average is calculated.\n" 00152 "\n" 00153 " * 'sum'\n" 00154 " At each pixel position the sum is calculated.\n" 00155 "\n" 00156 " * 'min_max'\n" 00157 " The specified number of min and max pixel values will be rejected.\n" 00158 " --cmax and --cmin apply to this method.\n" 00159 "\n" 00160 "ADVANCED PARAMETERS\n" 00161 "-------------------\n" 00162 "--cpos_rej\n" 00163 "--cneg_rej\n" 00164 "--citer\n" 00165 "see --cmethod='ksigma'\n" 00166 "\n" 00167 "--cmax\n" 00168 "--cmin\n" 00169 "see --cmethod='min_max'\n" 00170 "\n" 00171 "--suppress_extension\n" 00172 "If set to TRUE, the arbitrary filename extensions are supressed. If\n" 00173 "multiple products with the same category are produced, they will be\n" 00174 "numered consecutively starting from 0.\n" 00175 "\n" 00176 "-------------------------------------------------------------------------------\n" 00177 " Input files:\n" 00178 " DO CATG Type Explanation Required #Frames\n" 00179 " ------- ----- ----------- -------- -------\n" 00180 " FLAT_ON RAW Flatlamp-on exposures Y 1-n \n" 00181 " (at least 3 frames recommended) \n" 00182 " FLAT_OFF RAW Flatlamp-off exposures Y 1-n \n" 00183 " (at least 3 frames recommended) \n" 00184 " BADPIXEL_DARK B2D Bad pixel mask Y 1 \n" 00185 "\n" 00186 " Output files:\n" 00187 " DO CATG Type Explanation\n" 00188 " ------- ----- -----------\n" 00189 " MASTER_FLAT F2D Normalised flat field\n" 00190 " (6 extensions: alternating data & noise\n" 00191 " BADPIXEL_FLAT B2D Updated bad pixel mask (3 Extensions)\n" 00192 " XCAL F2D Calibration frame 1 (3 Extensions)\n" 00193 " YCAL F2D Calibration frame 2 (3 Extensions)\n" 00194 " FLAT_EDGE F2L Frame containing parameters of fitted \n" 00195 " slitlets of all IFUs of all detectors\n" 00196 "---------------------------------------------------------------------------" 00197 "\n"; 00198 00199 /*----------------------------------------------------------------------------*/ 00203 /*----------------------------------------------------------------------------*/ 00204 00207 /*----------------------------------------------------------------------------- 00208 * Functions code 00209 *----------------------------------------------------------------------------*/ 00210 00211 /*----------------------------------------------------------------------------*/ 00220 /*----------------------------------------------------------------------------*/ 00221 int cpl_plugin_get_info(cpl_pluginlist *list) 00222 { 00223 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe); 00224 cpl_plugin *plugin = &recipe->interface; 00225 00226 cpl_plugin_init(plugin, 00227 CPL_PLUGIN_API, 00228 KMOS_BINARY_VERSION, 00229 CPL_PLUGIN_TYPE_RECIPE, 00230 "kmos_flat", 00231 "Create master flatfield frame and badpixel map", 00232 kmos_flat_description, 00233 "Alex Agudo Berbel, Yves Jung", 00234 "usd-help@eso.org", 00235 kmos_get_license(), 00236 kmos_flat_create, 00237 kmos_flat_exec, 00238 kmos_flat_destroy); 00239 00240 cpl_pluginlist_append(list, plugin); 00241 00242 return 0; 00243 } 00244 00245 /*----------------------------------------------------------------------------*/ 00253 /*----------------------------------------------------------------------------*/ 00254 static int kmos_flat_create(cpl_plugin *plugin) 00255 { 00256 cpl_recipe *recipe; 00257 cpl_parameter *p; 00258 00259 /* Check that the plugin is part of a valid recipe */ 00260 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00261 recipe = (cpl_recipe *)plugin; 00262 else 00263 return -1; 00264 00265 /* Create the parameters list in the cpl_recipe object */ 00266 recipe->parameters = cpl_parameterlist_new(); 00267 00268 /* Fill the parameters list */ 00269 00270 /* --badpix_thresh */ 00271 p = cpl_parameter_new_value("kmos.kmos_flat.badpix_thresh", CPL_TYPE_INT, 00272 "The threshold level to mark bad pixels [%].","kmos.kmos_flat", 35); 00273 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "badpix_thresh"); 00274 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00275 cpl_parameterlist_append(recipe->parameters, p); 00276 00277 /* --surrounding_pixels */ 00278 p = cpl_parameter_new_value("kmos.kmos_flat.surrounding_pixels", 00279 CPL_TYPE_INT, "The nb of bad surrounding pix to mark a pixel bad", 00280 "kmos.kmos_flat", 5); 00281 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "surrounding_pixels"); 00282 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00283 cpl_parameterlist_append(recipe->parameters, p); 00284 00285 /* --suppress_extension */ 00286 p = cpl_parameter_new_value("kmos.kmos_flat.suppress_extension", 00287 CPL_TYPE_BOOL, "Suppress arbitrary filename extension", 00288 "kmos.kmos_flat", FALSE); 00289 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension"); 00290 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00291 cpl_parameterlist_append(recipe->parameters, p); 00292 00293 /* Add parameters for combination */ 00294 kmos_combine_pars_create(recipe->parameters, "kmos.kmos_flat", 00295 DEF_REJ_METHOD, FALSE); 00296 00297 /* --detector */ 00298 p = cpl_parameter_new_value("kmos.kmos_flat.detector", 00299 CPL_TYPE_INT, "Only reduce the specified detector", 00300 "kmos.kmos_flat", 0); 00301 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "det"); 00302 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00303 cpl_parameterlist_append(recipe->parameters, p); 00304 00305 /* --angle */ 00306 p = cpl_parameter_new_value("kmos.kmos_flat.angle", 00307 CPL_TYPE_DOUBLE, "Only reduce the specified angle", 00308 "kmos.kmos_flat", 370.0); 00309 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "angle"); 00310 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00311 cpl_parameterlist_append(recipe->parameters, p); 00312 00313 return 0 ; 00314 } 00315 00316 /*----------------------------------------------------------------------------*/ 00322 /*----------------------------------------------------------------------------*/ 00323 static int kmos_flat_exec(cpl_plugin *plugin) 00324 { 00325 cpl_recipe *recipe; 00326 00327 /* Get the recipe out of the plugin */ 00328 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00329 recipe = (cpl_recipe *)plugin; 00330 else return -1; 00331 00332 return kmos_flat(recipe->parameters, recipe->frames); 00333 } 00334 00335 /*----------------------------------------------------------------------------*/ 00341 /*----------------------------------------------------------------------------*/ 00342 static int kmos_flat_destroy(cpl_plugin *plugin) 00343 { 00344 cpl_recipe *recipe; 00345 00346 /* Get the recipe out of the plugin */ 00347 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00348 recipe = (cpl_recipe *)plugin; 00349 else return -1 ; 00350 00351 cpl_parameterlist_delete(recipe->parameters); 00352 return 0 ; 00353 } 00354 00355 /*----------------------------------------------------------------------------*/ 00369 /*----------------------------------------------------------------------------*/ 00370 static int kmos_flat(cpl_parameterlist *parlist, cpl_frameset *frameset) 00371 { 00372 const cpl_parameter * par ; 00373 int surrounding_pixels, badpix_thresh, 00374 suppress_extension, reduce_det ; 00375 double reduce_angle, cpos_rej, cneg_rej, ext_index ; 00376 int cmax, cmin, citer ; 00377 const char * cmethod ; 00378 cpl_frame * frame ; 00379 cpl_propertylist * plist ; 00380 int nx, ny, ne ; 00381 int * angles_array ; 00382 int nb_angles ; 00383 cpl_image ** stored_flat ; 00384 cpl_image ** stored_noise ; 00385 cpl_image ** stored_badpix ; 00386 cpl_image ** stored_xcal ; 00387 cpl_image ** stored_ycal ; 00388 double * stored_gapmean ; 00389 double * stored_gapsdv ; 00390 double * stored_gapmaxdev ; 00391 double * stored_slitmean ; 00392 double * stored_slitsdv ; 00393 double * stored_slitmaxdev ; 00394 double * stored_qc_flat_eff ; 00395 double * stored_qc_flat_sn ; 00396 int * stored_qc_flat_sat ; 00397 cpl_frameset * angle_frameset ; 00398 char * extname ; 00399 char * suffix ; 00400 char * fn_suffix ; 00401 unsigned int save_mode ; 00402 char * fn_flat = "flat_tmp.fits" ; 00403 char * fn_noise = "flat_noise.fits" ; 00404 char * fn_badpix = "badpix_tmp.fits" ; 00405 cpl_imagelist * det_lamp_on ; 00406 cpl_imagelist * det_lamp_off ; 00407 cpl_image * img_in ; 00408 cpl_image * combined_data_on ; 00409 cpl_image * combined_noise_on ; 00410 cpl_image * combined_data_off[KMOS_NR_DETECTORS] ; 00411 cpl_image * combined_noise_off[KMOS_NR_DETECTORS] ; 00412 cpl_image * bad_pix_mask_flat ; 00413 cpl_image * bad_pix_mask_dark[KMOS_NR_DETECTORS] ; 00414 cpl_image * xcal ; 00415 cpl_image * ycal ; 00416 cpl_array ** unused_ifus_before ; 00417 cpl_array ** unused_ifus_after ; 00418 cpl_propertylist * main_header ; 00419 cpl_propertylist * main_header_xcal ; 00420 cpl_propertylist * sub_header ; 00421 cpl_table *** edge_table ; 00422 cpl_error_code * spec_found ; 00423 double gain, exptime, mean_data, mean_noise ; 00424 int sx, nr_bad_pix, nr_sat, i, j, a ; 00425 00426 /* Check entries */ 00427 if (parlist == NULL || frameset == NULL) { 00428 cpl_msg_error(__func__, "Null Inputs") ; 00429 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ; 00430 return -1 ; 00431 } 00432 00433 /* Get Parameters */ 00434 par = cpl_parameterlist_find_const(parlist, 00435 "kmos.kmos_flat.surrounding_pixels"); 00436 surrounding_pixels = cpl_parameter_get_int(par); 00437 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_flat.badpix_thresh"); 00438 badpix_thresh = cpl_parameter_get_int(par); 00439 par = cpl_parameterlist_find_const(parlist, 00440 "kmos.kmos_flat.suppress_extension"); 00441 suppress_extension = cpl_parameter_get_bool(par); 00442 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_flat.angle"); 00443 reduce_angle = cpl_parameter_get_double(par); 00444 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_flat.detector"); 00445 reduce_det = cpl_parameter_get_int(par); 00446 00447 kmos_combine_pars_load(parlist, "kmos.kmos_flat", &cmethod, &cpos_rej, 00448 &cneg_rej, &citer, &cmin, &cmax, FALSE); 00449 00450 /* Check Parameters */ 00451 if (surrounding_pixels < 0 || surrounding_pixels > 8) { 00452 cpl_msg_error(__func__, "surrounding_pixels must be in [0,8]") ; 00453 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00454 return -1 ; 00455 } 00456 if (badpix_thresh < 0 || badpix_thresh > 100) { 00457 cpl_msg_error(__func__, "badpix_thresh must be in [0,100]") ; 00458 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00459 return -1 ; 00460 } 00461 if (reduce_det < 0 || reduce_det > 3) { 00462 cpl_msg_error(__func__, "detector must be in [1,3]") ; 00463 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00464 return -1 ; 00465 } 00466 00467 /* Identify the RAW and CALIB frames in the input frameset */ 00468 if (kmo_dfs_set_groups(frameset, "kmos_flat") != 1) { 00469 cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ; 00470 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00471 return -1 ; 00472 } 00473 00474 /* Check the inputs consistency */ 00475 if (kmos_flat_check_inputs(frameset, &nx, &ny, &ne, &exptime) != 1) { 00476 cpl_msg_error(__func__, "Input frameset is not consistent") ; 00477 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00478 return -1 ; 00479 } 00480 00481 /* Instrument setup */ 00482 suffix = kmo_dfs_get_suffix(kmo_dfs_get_frame(frameset,FLAT_ON),TRUE,FALSE); 00483 cpl_msg_info(__func__, "Detected instrument setup: %s", suffix+1); 00484 00485 /* Get Rotator angles */ 00486 if ((angles_array = kmos_get_angles(frameset, &nb_angles,FLAT_ON)) == NULL){ 00487 cpl_msg_error(__func__, "Cannot get Angles informations") ; 00488 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00489 return -1 ; 00490 } 00491 00492 /* The frames have to be stored temporarily because the QC parameters */ 00493 /* for the main header are calculated from each detector. */ 00494 /* So they can be stored only when all detectors are processed */ 00495 stored_flat = (cpl_image**)cpl_calloc(ne*nb_angles, sizeof(cpl_image*)); 00496 stored_noise = (cpl_image**)cpl_calloc(ne * nb_angles, sizeof(cpl_image*)); 00497 stored_badpix = (cpl_image**)cpl_calloc(ne * nb_angles, sizeof(cpl_image*)); 00498 stored_xcal = (cpl_image**)cpl_calloc(ne * nb_angles, sizeof(cpl_image*)); 00499 stored_ycal = (cpl_image**)cpl_calloc(ne * nb_angles, sizeof(cpl_image*)); 00500 stored_qc_flat_sat = (int*)cpl_malloc(ne * nb_angles * sizeof(int)); 00501 stored_qc_flat_eff = (double*)cpl_malloc(ne * nb_angles * sizeof(double)); 00502 stored_qc_flat_sn = (double*)cpl_malloc(ne * nb_angles * sizeof(double)); 00503 stored_gapmean = (double*)cpl_malloc(ne * nb_angles * sizeof(double)); 00504 stored_gapsdv = (double*)cpl_malloc(ne * nb_angles * sizeof(double)); 00505 stored_gapmaxdev = (double*)cpl_malloc(ne * nb_angles * sizeof(double)); 00506 stored_slitmean = (double*)cpl_malloc(ne * nb_angles * sizeof(double)); 00507 stored_slitsdv = (double*)cpl_malloc(ne * nb_angles * sizeof(double)); 00508 stored_slitmaxdev = (double*)cpl_malloc(ne * nb_angles * sizeof(double)); 00509 spec_found = (cpl_error_code*)cpl_malloc(ne * nb_angles * 00510 sizeof(cpl_error_code)); 00511 00512 /* Initialise */ 00513 for (i = 0; i < ne * nb_angles ; i++) { 00514 stored_qc_flat_sat[i] = 0; 00515 stored_qc_flat_eff[i] = 0.0; 00516 stored_qc_flat_sn[i] = 0.0; 00517 stored_gapmean[i] = 0.0; 00518 stored_gapsdv[i] = 0.0; 00519 stored_gapmaxdev[i] = 0.0; 00520 stored_slitmean[i] = 0.0; 00521 stored_slitsdv[i] = 0.0; 00522 stored_slitmaxdev[i] = 0.0; 00523 spec_found[i] = CPL_ERROR_NONE; 00524 } 00525 00526 /* TODO : Improve handling of edge_table !!!! */ 00527 edge_table = (cpl_table***)cpl_malloc(ne * nb_angles * sizeof(cpl_table**)); 00528 for (i = 0; i < ne * nb_angles; i++) edge_table[i] = NULL; 00529 00530 /* Check which IFUs are active for all FLAT_ON frames */ 00531 unused_ifus_before = kmo_get_unused_ifus(frameset, 0, 0); 00532 unused_ifus_after = kmo_duplicate_unused_ifus(unused_ifus_before); 00533 kmo_print_unused_ifus(unused_ifus_before, FALSE); 00534 kmo_free_unused_ifus(unused_ifus_before); 00535 00536 /* Combine the FLAT_OFF frames for the 3 detectors */ 00537 for (i = 1; i <= ne; i++) { 00538 /* Compute only one detector */ 00539 if (reduce_det != 0 && i != reduce_det) continue ; 00540 00541 /* Load the badpixel masks */ 00542 bad_pix_mask_dark[i-1] = kmo_dfs_load_image(frameset, BADPIXEL_DARK, 00543 i, 2, FALSE, NULL) ; 00544 00545 /* Load lamp-off images */ 00546 det_lamp_off = cpl_imagelist_new(); 00547 frame = kmo_dfs_get_frame(frameset, FLAT_OFF); 00548 j = 0; 00549 while (frame != NULL) { 00550 img_in = kmo_dfs_load_image_frame(frame, i, FALSE, FALSE, NULL); 00551 kmo_image_reject_from_mask(img_in, bad_pix_mask_dark[i-1]); 00552 cpl_imagelist_set(det_lamp_off, img_in, j++); 00553 frame = kmo_dfs_get_frame(frameset, NULL); 00554 } 00555 00556 /* Combine FLAT_OFF frames */ 00557 cpl_msg_info(__func__, "Combine FLAT_OFF frames for Detector %d", i) ; 00558 kmos_combine_frames(det_lamp_off, cmethod, cpos_rej, 00559 cneg_rej, citer, cmax, cmin, &(combined_data_off[i-1]), 00560 &(combined_noise_off[i-1]), -1.0); 00561 /* 00562 cpl_image_save(combined_data_off[i-1], "off.fits", 00563 CPL_TYPE_FLOAT, NULL, CPL_IO_CREATE) ; 00564 */ 00565 cpl_imagelist_delete(det_lamp_off); 00566 cpl_image_power(combined_noise_off[i-1], 2.0); 00567 } 00568 00569 save_mode = CPL_IO_CREATE; 00570 /* Loop all Rotator Angles and Detectors */ 00571 for (a = 0; a < nb_angles; a++) { 00572 /* Reduce only one angle */ 00573 if (reduce_angle <= 360 && angles_array[a] != reduce_angle) continue ; 00574 00575 cpl_msg_info(__func__, "Processing rotator angle %d -> %d degree", 00576 a, angles_array[a]); 00577 cpl_msg_indent_more() ; 00578 00579 /* Get the frameset with this angle */ 00580 angle_frameset = kmos_get_angle_frameset(frameset, angles_array[a], 00581 FLAT_ON); 00582 if (angle_frameset == NULL) { 00583 cpl_msg_error(__func__, "Cannot get angle frameset") ; 00584 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00585 cpl_msg_indent_less() ; 00586 cpl_free(angles_array) ; 00587 return -1 ; 00588 } 00589 00590 for (i = 1; i <= ne; i++) { 00591 /* Compute only one detector */ 00592 if (reduce_det != 0 && i != reduce_det) continue ; 00593 00594 cpl_msg_info(__func__, "Processing detector No. %d", i); 00595 cpl_msg_indent_more() ; 00596 00597 sx = a * ne + (i - 1); 00598 00599 /* Load lamp-on images for Angle a */ 00600 det_lamp_on = cpl_imagelist_new(); 00601 frame = kmo_dfs_get_frame(angle_frameset, FLAT_ON); 00602 j = 0; 00603 while (frame != NULL) { 00604 img_in=kmo_dfs_load_image_frame(frame, i, FALSE, TRUE, &nr_sat); 00605 kmo_image_reject_from_mask(img_in, bad_pix_mask_dark[i-1]); 00606 cpl_imagelist_set(det_lamp_on, img_in, j++); 00607 frame = kmo_dfs_get_frame(angle_frameset, NULL); 00608 } 00609 00610 /* Count saturated pixels for each detector */ 00611 cpl_msg_info(__func__, "Count Saturated pixels on the detector") ; 00612 frame = kmo_dfs_get_frame(angle_frameset, FLAT_ON); 00613 main_header = kmclipm_propertylist_load( 00614 cpl_frame_get_filename(frame), 0); 00615 if (strcmp(cpl_propertylist_get_string(main_header, READMODE), 00616 "Nondest") == 0) { 00617 // NDR: non-destructive readout mode 00618 stored_qc_flat_sat[sx] = nr_sat; 00619 } else { 00620 // normal readout mode 00621 stored_qc_flat_sat[sx] = kmo_imagelist_get_saturated( 00622 det_lamp_on, KMO_FLAT_SATURATED, KMO_FLAT_SAT_MIN); 00623 } 00624 cpl_propertylist_delete(main_header); 00625 00626 /* Combine imagelists and create noise */ 00627 cpl_msg_info(__func__, "Combine FLAT_ON frames") ; 00628 kmos_combine_frames(det_lamp_on, cmethod, cpos_rej, 00629 cneg_rej, citer, cmax, cmin, &combined_data_on, 00630 &combined_noise_on, -1.0); 00631 cpl_imagelist_delete(det_lamp_on); 00632 00633 if (kmclipm_omit_warning_one_slice > 10) 00634 kmclipm_omit_warning_one_slice = FALSE; 00635 00636 /* Subtract combined lamp_off from lamp_on */ 00637 cpl_image_subtract(combined_data_on, combined_data_off[i-1]); 00638 00639 /* noise: sig_x = sqrt(sig_u^2 + sig_v^2 */ 00640 cpl_msg_info(__func__, "Compute the noise") ; 00641 cpl_image_power(combined_noise_on, 2.0); 00642 cpl_image_add(combined_noise_on, combined_noise_off[i-1]); 00643 cpl_image_power(combined_noise_on, 0.5); 00644 00645 /* Create bad-pixel-mask */ 00646 bad_pix_mask_flat = kmo_create_bad_pix_flat_thresh(combined_data_on, 00647 surrounding_pixels, badpix_thresh); 00648 00649 /* Calculate spectral curvature here */ 00650 cpl_msg_info(__func__, "Compute the spectral curvature") ; 00651 cpl_msg_indent_more() ; 00652 spec_found[sx] = kmo_calc_curvature(combined_data_on, 00653 combined_noise_on, unused_ifus_after[i-1], 00654 bad_pix_mask_flat, i, &xcal, &ycal, stored_gapmean+(sx), 00655 stored_gapsdv+(sx), stored_gapmaxdev+(sx), 00656 stored_slitmean+(sx), stored_slitsdv+(sx), 00657 stored_slitmaxdev+(sx), &edge_table[sx]); 00658 cpl_msg_indent_less() ; 00659 00660 if (spec_found[sx] == CPL_ERROR_NONE) { 00661 // in kmo_calc_curvature() the spectral slope of each 00662 // slitlet has been normalised individually. Now the 00663 // normalisation on the whole frame is applied. 00664 // (cpl_image_get_mean() ignores bad pixels when 00665 // calculating the mean) 00666 mean_data = cpl_image_get_mean(combined_data_on); 00667 stored_qc_flat_eff[sx] = mean_data / exptime; 00668 mean_noise = cpl_image_get_mean(combined_noise_on); 00669 if (fabs(mean_noise) < 1e-3) { 00670 cpl_msg_error(__func__, "Division by 0.0") ; 00671 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00672 cpl_free(angles_array) ; 00673 return -1 ; 00674 } 00675 stored_qc_flat_sn[sx] = mean_data / mean_noise; 00676 00677 /* Normalize data & noise on the whole detector frame */ 00678 /* The spectral slope on each slitlet has already been */ 00679 /* normalised in kmo_calc_curvature() */ 00680 cpl_image_divide_scalar(combined_data_on, mean_data); 00681 cpl_image_divide_scalar(combined_noise_on, mean_data); 00682 00683 /* Apply the badpixel mask to the produced frames */ 00684 cpl_image_multiply(combined_data_on, bad_pix_mask_flat); 00685 cpl_image_multiply(combined_noise_on, bad_pix_mask_flat); 00686 cpl_image_multiply(xcal, bad_pix_mask_flat) ; 00687 cpl_image_multiply(ycal, bad_pix_mask_flat) ; 00688 00689 /* Store temporarily flat, badpixel and calibration */ 00690 stored_xcal[sx] = xcal; 00691 stored_ycal[sx] = ycal; 00692 00693 /* Save immediate results, free memory */ 00694 kmclipm_image_save(combined_data_on, fn_flat, CPL_TYPE_FLOAT, 00695 NULL, save_mode, 0./0.); 00696 kmclipm_image_save(combined_noise_on, fn_noise, CPL_TYPE_FLOAT, 00697 NULL, save_mode, 0./0.); 00698 kmclipm_image_save(bad_pix_mask_flat, fn_badpix, CPL_TYPE_FLOAT, 00699 NULL, save_mode, 0./0.); 00700 /* Next saves will create extensions */ 00701 save_mode = CPL_IO_EXTEND; 00702 00703 } else if (spec_found[sx] == CPL_ERROR_DATA_NOT_FOUND) { 00704 /* All IFUs seem to be deativated */ 00705 cpl_msg_warning(__func__, "All IFUs deactivated") ; 00706 cpl_error_reset(); 00707 00708 /* Save immediate results, free memory */ 00709 cpl_image_save(NULL, fn_flat, CPL_TYPE_FLOAT, NULL, save_mode); 00710 cpl_image_save(NULL, fn_noise, CPL_TYPE_FLOAT, NULL, save_mode); 00711 cpl_image_save(NULL, fn_badpix, CPL_TYPE_FLOAT, NULL,save_mode); 00712 /* Next saves will create extensions */ 00713 save_mode = CPL_IO_EXTEND; 00714 00715 stored_xcal[sx] = NULL ; 00716 stored_ycal[sx] = NULL ; 00717 } else { 00718 // another error occured 00719 cpl_msg_error(__func__, "Unknown ERROR !") ; 00720 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00721 cpl_image_delete(combined_data_on); 00722 cpl_image_delete(combined_noise_on); 00723 cpl_image_delete(bad_pix_mask_flat); 00724 cpl_free(angles_array) ; 00725 cpl_msg_indent_less() ; 00726 cpl_msg_indent_less() ; 00727 return -1 ; 00728 } 00729 cpl_image_delete(combined_data_on); 00730 cpl_image_delete(combined_noise_on); 00731 cpl_image_delete(bad_pix_mask_flat); 00732 00733 cpl_msg_indent_less() ; 00734 } // for i = 1; i <= ne 00735 cpl_frameset_delete(angle_frameset); 00736 cpl_msg_indent_less() ; 00737 } // for a = 0; a < nb_angles 00738 00739 /* Clean OFF frames */ 00740 for (i = 1; i <= ne; i++) { 00741 /* Compute only one detector */ 00742 if (reduce_det != 0 && i != reduce_det) continue ; 00743 00744 cpl_image_delete(combined_data_off[i-1]) ; 00745 cpl_image_delete(combined_noise_off[i-1]) ; 00746 cpl_image_delete(bad_pix_mask_dark[i-1]); 00747 } 00748 00749 /* ----- QC parameters & saving */ 00750 /* ---- load, update & save primary header */ 00751 main_header = kmo_dfs_load_primary_header(frameset, FLAT_ON); 00752 00753 /* Update which IFUs are not used */ 00754 kmo_print_unused_ifus(unused_ifus_after, TRUE); 00755 kmo_set_unused_ifus(unused_ifus_after, main_header, "kmos_flat"); 00756 kmo_free_unused_ifus(unused_ifus_after); 00757 00758 /* xcal gets additionally the boundaries of the IFUs for reconstruction */ 00759 main_header_xcal=kmos_create_bounds_properties(stored_ycal, ne, nb_angles) ; 00760 00761 /* --------- saving headers */ 00762 if (!suppress_extension) fn_suffix = cpl_sprintf("%s", suffix); 00763 else fn_suffix = cpl_sprintf("%s", ""); 00764 cpl_free(suffix); 00765 00766 cpl_msg_info(__func__, "Saving data..."); 00767 00768 frame = kmo_dfs_get_frame(frameset, FLAT_ON); 00769 kmo_dfs_save_main_header(frameset, MASTER_FLAT, fn_suffix, frame, 00770 main_header, parlist, cpl_func); 00771 kmo_dfs_save_main_header(frameset, XCAL, fn_suffix, frame, 00772 main_header_xcal, parlist, cpl_func); 00773 kmo_dfs_save_main_header(frameset, YCAL, fn_suffix, frame, 00774 main_header, parlist, cpl_func); 00775 kmo_dfs_save_main_header(frameset, BADPIXEL_FLAT, fn_suffix, frame, 00776 main_header, parlist, cpl_func); 00777 kmo_dfs_save_main_header(frameset, FLAT_EDGE, fn_suffix, frame, 00778 main_header, parlist, cpl_func); 00779 00780 cpl_propertylist_delete(main_header); 00781 cpl_propertylist_delete(main_header_xcal); 00782 00783 /* -------- saving sub frames */ 00784 ext_index = 0 ; 00785 for (a = 0; a < nb_angles; a++) { 00786 /* Reduce only one angle */ 00787 if (reduce_angle <= 360 && angles_array[a] != reduce_angle) continue ; 00788 00789 for (i = 1; i <= ne; i++) { 00790 /* Compute only one detector */ 00791 if (reduce_det != 0 && i != reduce_det) continue ; 00792 00793 sx = a * ne + (i - 1); 00794 // load stored data again 00795 stored_flat[sx]=kmclipm_image_load(fn_flat, CPL_TYPE_FLOAT, 0, 00796 ext_index); 00797 cpl_error_reset() ; 00798 stored_noise[sx]=kmclipm_image_load(fn_noise, CPL_TYPE_FLOAT, 0, 00799 ext_index); 00800 cpl_error_reset() ; 00801 stored_badpix[sx]=kmclipm_image_load(fn_badpix,CPL_TYPE_FLOAT, 0, 00802 ext_index); 00803 cpl_error_reset() ; 00804 ext_index ++ ; 00805 00806 sub_header = kmo_dfs_load_sub_header(frameset, FLAT_ON, i, FALSE); 00807 kmclipm_update_property_double(sub_header,CAL_ROTANGLE, 00808 ((double) angles_array[a]), 00809 "[deg] Rotator relative to nasmyth"); 00810 00811 if (spec_found[sx] == CPL_ERROR_NONE) { 00812 kmclipm_update_property_int(sub_header, QC_FLAT_SAT, 00813 stored_qc_flat_sat[sx], 00814 "[] nr. saturated pixels of master flat"); 00815 /* Load gain */ 00816 gain = kmo_dfs_get_property_double(sub_header, GAIN); 00817 kmclipm_update_property_double(sub_header, QC_FLAT_EFF, 00818 stored_qc_flat_eff[sx]/gain, 00819 "[e-/s] rel. brightness of flat lamp"); 00820 00821 kmclipm_update_property_double(sub_header, QC_FLAT_SN, 00822 stored_qc_flat_sn[sx], "[] S/N of master flat"); 00823 } 00824 00825 /* Store qc parameters only if any slitlet- and gap-width */ 00826 /* has been detected (should be the case when at least */ 00827 /* one IFU is active) */ 00828 if (stored_xcal[sx] != NULL) { 00829 kmclipm_update_property_double(sub_header, QC_GAP_MEAN, 00830 stored_gapmean[sx], 00831 "[pix] mean gap width between slitlets"); 00832 kmclipm_update_property_double(sub_header, QC_GAP_SDV, 00833 stored_gapsdv[sx], 00834 "[pix] stdev of gap width between slitlets"); 00835 kmclipm_update_property_double(sub_header, QC_GAP_MAXDEV, 00836 stored_gapmaxdev[sx], 00837 "[pix] max gap deviation between slitlets"); 00838 kmclipm_update_property_double(sub_header, QC_SLIT_MEAN, 00839 stored_slitmean[sx], "[pix] mean slitlet width"); 00840 kmclipm_update_property_double(sub_header, QC_SLIT_SDV, 00841 stored_slitsdv[sx], "[pix] stdev of slitlet widths"); 00842 kmclipm_update_property_double(sub_header, QC_SLIT_MAXDEV, 00843 stored_slitmaxdev[sx], 00844 "[pix] max slitlet width deviation"); 00845 } 00846 00847 /* Calculate QC.BADPIX.NCOUNT */ 00848 /* Remove 4pixel-border as bad pixels */ 00849 nr_bad_pix = 0 ; 00850 if (stored_badpix[sx] != NULL) { 00851 nr_bad_pix = cpl_image_count_rejected(stored_badpix[sx]); 00852 nr_bad_pix -= 2*KMOS_BADPIX_BORDER*(nx-2*KMOS_BADPIX_BORDER) + 00853 2*KMOS_BADPIX_BORDER*ny; 00854 } 00855 00856 kmclipm_update_property_int(sub_header, QC_NR_BAD_PIX, nr_bad_pix, 00857 "[] nr. of bad pixels"); 00858 00859 /* Save flat frame */ 00860 extname = kmo_extname_creator(detector_frame, i, EXT_DATA); 00861 kmclipm_update_property_string(sub_header, EXTNAME,extname, 00862 "FITS extension name"); 00863 cpl_free(extname); 00864 00865 kmclipm_update_property_int(sub_header, EXTVER, sx+1, 00866 "FITS extension ver"); 00867 00868 kmo_dfs_save_image(stored_flat[sx], MASTER_FLAT, fn_suffix, 00869 sub_header, 0./0.); 00870 00871 /* Save noise frame when enough input frames were available */ 00872 extname = kmo_extname_creator(detector_frame, i, EXT_NOISE); 00873 kmclipm_update_property_string(sub_header, EXTNAME,extname, 00874 "FITS extension name"); 00875 cpl_free(extname); 00876 00877 kmo_dfs_save_image(stored_noise[sx], MASTER_FLAT, fn_suffix, 00878 sub_header, 0./0.); 00879 00880 /* Save bad_pix frame */ 00881 extname = kmo_extname_creator(detector_frame, i, EXT_BADPIX); 00882 kmclipm_update_property_string(sub_header, EXTNAME,extname, 00883 "FITS extension name"); 00884 cpl_free(extname); 00885 00886 kmo_dfs_save_image(stored_badpix[sx], BADPIXEL_FLAT, fn_suffix, 00887 sub_header, 0.); 00888 00889 // save xcal and ycal-frame 00890 extname = kmo_extname_creator(detector_frame, i, EXT_DATA); 00891 kmclipm_update_property_string(sub_header, EXTNAME, extname, 00892 "FITS extension name"); 00893 cpl_free(extname); 00894 00895 kmo_dfs_save_image(stored_xcal[sx], XCAL, fn_suffix, sub_header, 00896 0./0.); 00897 kmo_dfs_save_image(stored_ycal[sx], YCAL, fn_suffix, sub_header, 00898 0./0.); 00899 00900 /* Save edge_pars-frame */ 00901 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00902 extname = cpl_sprintf("%s_IFU.%d_ANGLE.%d", EXT_LIST, 00903 j+1+(i-1)*KMOS_IFUS_PER_DETECTOR, angles_array[a]); 00904 kmclipm_update_property_string(sub_header, EXTNAME, extname, 00905 "FITS extension name"); 00906 cpl_free(extname); 00907 00908 kmclipm_update_property_int(sub_header, CAL_IFU_NR, 00909 j+1+(i-1)*KMOS_IFUS_PER_DETECTOR, "IFU Number {1..24}"); 00910 00911 /* Save edge-parameters as product */ 00912 if ((spec_found[sx] != CPL_ERROR_DATA_NOT_FOUND) && 00913 (edge_table[sx] != NULL)&&(edge_table[sx][j] != NULL)) { 00914 kmo_dfs_save_table(edge_table[sx][j], FLAT_EDGE, 00915 fn_suffix, sub_header); 00916 } else { 00917 cpl_propertylist_erase(sub_header, CRVAL1); 00918 cpl_propertylist_erase(sub_header, CRVAL2); 00919 cpl_propertylist_erase(sub_header, CD1_1); 00920 cpl_propertylist_erase(sub_header, CD1_2); 00921 cpl_propertylist_erase(sub_header, CD2_1); 00922 cpl_propertylist_erase(sub_header, CD2_2); 00923 cpl_propertylist_erase(sub_header, CRPIX1); 00924 cpl_propertylist_erase(sub_header, CRPIX2); 00925 cpl_propertylist_erase(sub_header, CTYPE1); 00926 cpl_propertylist_erase(sub_header, CTYPE2); 00927 00928 kmo_dfs_save_table(NULL, FLAT_EDGE, fn_suffix, 00929 sub_header); 00930 } 00931 } 00932 cpl_propertylist_delete(sub_header); 00933 00934 cpl_image_delete(stored_flat[sx]); 00935 cpl_image_delete(stored_noise[sx]); 00936 cpl_image_delete(stored_badpix[sx]); 00937 } // for (i = ne) 00938 } // for (a = nb_angles) 00939 00940 // delete temporary files 00941 unlink(fn_flat); 00942 unlink(fn_noise); 00943 unlink(fn_badpix); 00944 00945 cpl_free(stored_qc_flat_sat); 00946 cpl_free(stored_qc_flat_eff); 00947 cpl_free(stored_qc_flat_sn); 00948 cpl_free(stored_gapmean); 00949 cpl_free(stored_gapsdv); 00950 cpl_free(stored_gapmaxdev); 00951 cpl_free(stored_slitmean); 00952 cpl_free(stored_slitsdv); 00953 cpl_free(stored_slitmaxdev); 00954 cpl_free(fn_suffix); 00955 cpl_free(stored_flat); 00956 cpl_free(stored_noise); 00957 cpl_free(stored_badpix); 00958 for (i = 0; i < ne * nb_angles; i++) { 00959 cpl_image_delete(stored_xcal[i]); 00960 cpl_image_delete(stored_ycal[i]); 00961 } 00962 cpl_free(stored_xcal); 00963 cpl_free(stored_ycal); 00964 if (edge_table != NULL) { 00965 for (i = 0; i < ne * nb_angles; i++) { 00966 if (edge_table[i] != NULL) { 00967 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00968 cpl_table_delete(edge_table[i][j]); 00969 } 00970 cpl_free(edge_table[i]); 00971 } 00972 } 00973 cpl_free(edge_table); 00974 } 00975 cpl_free(spec_found); 00976 cpl_free(angles_array) ; 00977 00978 return 0; 00979 } 00980 00983 /*----------------------------------------------------------------------------*/ 00993 /*----------------------------------------------------------------------------*/ 00994 static cpl_propertylist * kmos_create_bounds_properties( 00995 cpl_image ** stored_ycal, 00996 int ne, 00997 int nb_angles) 00998 { 00999 cpl_propertylist * bounds_props ; 01000 int * bounds ; 01001 int ** total_bounds ; 01002 char * tmpstr ; 01003 int a, i, j, sx ; 01004 01005 /* Check Entries */ 01006 if (stored_ycal == NULL) return NULL ; 01007 01008 /* Add here boundaries for reconstruction */ 01009 bounds_props = cpl_propertylist_new(); 01010 01011 /* Initialize total_bounds */ 01012 total_bounds = (int**)cpl_malloc(ne*sizeof(int*)); 01013 for (i = 0; i < ne; i++) { 01014 total_bounds[i]=(int*)cpl_calloc(2*KMOS_IFUS_PER_DETECTOR,sizeof(int)); 01015 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01016 total_bounds[i][2*j] = 2048; 01017 total_bounds[i][2*j+1] = 0; 01018 } 01019 } 01020 01021 /* Store the min left bound and max right bound for all angles */ 01022 for (a = 0; a < nb_angles; a++) { 01023 for (i = 0; i < ne; i++) { 01024 sx = a * ne + i; 01025 if (stored_ycal[sx] != NULL) { 01026 bounds = kmo_split_frame(stored_ycal[sx]); 01027 01028 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01029 if ((total_bounds[i][2*j] == -1)||(bounds[2*j] == -1)) { 01030 total_bounds[i][2*j] = -1; 01031 } else { 01032 if (total_bounds[i][2*j] > bounds[2*j]) { 01033 total_bounds[i][2*j] = bounds[2*j]; 01034 } 01035 } 01036 01037 if ((total_bounds[i][2*j+1] == -1) || 01038 (bounds[2*j+1] == -1)) { 01039 total_bounds[i][2*j+1] = -1; 01040 } else { 01041 if (total_bounds[i][2*j+1] < bounds[2*j+1]) { 01042 total_bounds[i][2*j+1] = bounds[2*j+1]; 01043 } 01044 } 01045 } 01046 cpl_free(bounds); 01047 } else { 01048 // whole detector inactive 01049 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01050 total_bounds[i][2*j] = -1; 01051 total_bounds[i][2*j+1] = -1; 01052 } 01053 } 01054 } // for (ne) 01055 } // for (nb_angles) 01056 01057 /* Write the min left bound and max right bound for all angles */ 01058 /* into the main header */ 01059 for (i = 0; i < ne; i++) { 01060 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01061 if (total_bounds[i][2*j] > -1) { 01062 tmpstr= cpl_sprintf("%s%d%s", BOUNDS_PREFIX, 01063 i*KMOS_IFUS_PER_DETECTOR + j+1, "_L"); 01064 kmclipm_update_property_int(bounds_props, tmpstr, 01065 total_bounds[i][2*j], 01066 "[pix] left boundary for reconstr."); 01067 cpl_free(tmpstr); 01068 } 01069 01070 if (total_bounds[i][2*j+1] > -1) { 01071 tmpstr= cpl_sprintf("%s%d%s", BOUNDS_PREFIX, 01072 i*KMOS_IFUS_PER_DETECTOR + j+1, "_R"); 01073 kmclipm_update_property_int(bounds_props,tmpstr, 01074 total_bounds[i][2*j+1], 01075 "[pix] right boundary for reconstr."); 01076 cpl_free(tmpstr); 01077 } 01078 } 01079 } // for (ne) 01080 for (i = 0; i < ne; i++) cpl_free(total_bounds[i]); 01081 cpl_free(total_bounds); 01082 01083 return bounds_props ; 01084 } 01085 01086 /*----------------------------------------------------------------------------*/ 01096 /*----------------------------------------------------------------------------*/ 01097 static int kmos_flat_check_inputs( 01098 cpl_frameset * frameset, 01099 int * nx, 01100 int * ny, 01101 int * ne, 01102 double * exptime_on) 01103 { 01104 cpl_frame * frame ; 01105 cpl_propertylist * eh ; 01106 cpl_propertylist * mh1 ; 01107 cpl_propertylist * main_header ; 01108 int ndit ; 01109 double exptime ; 01110 const char * readmode ; 01111 int naxis1, naxis2, next ; 01112 01113 /* TODO Add frames dimensions checks TODO */ 01114 01115 /* Check Entries */ 01116 if (nx == NULL || ny == NULL || frameset == NULL || exptime_on == NULL) 01117 return -1; 01118 01119 /* check BADPIXEL_DARK */ 01120 frame = kmo_dfs_get_frame(frameset, BADPIXEL_DARK); 01121 if (frame == NULL) { 01122 cpl_msg_warning(__func__, "BADPIXEL_DARK frame is missing") ; 01123 return 0 ; 01124 } 01125 next = cpl_frame_get_nextensions(frame); 01126 if (next != KMOS_NR_DETECTORS) { 01127 cpl_msg_warning(__func__, "BADPIXEL_DARK must have 3 extensions") ; 01128 return 0 ; 01129 } 01130 eh = cpl_propertylist_load(cpl_frame_get_filename(frame), 1); 01131 naxis1 = kmos_pfits_get_naxis1(eh) ; 01132 naxis2 = kmos_pfits_get_naxis2(eh) ; 01133 cpl_propertylist_delete(eh) ; 01134 01135 /* check FLAT_OFF */ 01136 frame = kmo_dfs_get_frame(frameset, FLAT_OFF); 01137 mh1 = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 01138 ndit = cpl_propertylist_get_int(mh1, NDIT); 01139 exptime = cpl_propertylist_get_double(mh1, EXPTIME); 01140 readmode = cpl_propertylist_get_string(mh1, READMODE); 01141 01142 /* Loop through FLAT_OFF frames */ 01143 while (frame != NULL) { 01144 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 01145 01146 if (cpl_propertylist_get_int(main_header, NDIT) != ndit) { 01147 cpl_msg_warning(__func__, "NDIT inconsistent") ; 01148 cpl_propertylist_delete(mh1); 01149 cpl_propertylist_delete(main_header); 01150 return 0 ; 01151 } 01152 if (cpl_propertylist_get_double(main_header, EXPTIME) != exptime) { 01153 cpl_msg_warning(__func__, "EXPTIME inconsistent") ; 01154 cpl_propertylist_delete(mh1); 01155 cpl_propertylist_delete(main_header); 01156 return 0 ; 01157 } 01158 if (strcmp(cpl_propertylist_get_string(main_header, READMODE), 01159 readmode) != 0) { 01160 cpl_msg_warning(__func__, "READMODE inconsistent") ; 01161 cpl_propertylist_delete(mh1); 01162 cpl_propertylist_delete(main_header); 01163 return 0 ; 01164 } 01165 01166 /* Assure that arc lamps are off */ 01167 if ((kmo_check_lamp(main_header, INS_LAMP1_ST) != FALSE) 01168 || (kmo_check_lamp(main_header, INS_LAMP2_ST) != FALSE)) { 01169 cpl_msg_warning(__func__, "Arc lamps must be switched off") ; 01170 cpl_propertylist_delete(mh1); 01171 cpl_propertylist_delete(main_header); 01172 return 0 ; 01173 } 01174 cpl_propertylist_delete(main_header); 01175 01176 /* Get next FLAT_OFF frame */ 01177 frame = kmo_dfs_get_frame(frameset, NULL); 01178 } 01179 01180 /* Loop through FLAT_ON frames */ 01181 frame = kmo_dfs_get_frame(frameset, FLAT_ON); 01182 while (frame != NULL) { 01183 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 01184 01185 if (cpl_propertylist_get_int(main_header, NDIT) != ndit) { 01186 cpl_msg_warning(__func__, "NDIT inconsistent") ; 01187 cpl_propertylist_delete(mh1); 01188 cpl_propertylist_delete(main_header); 01189 return 0 ; 01190 } 01191 if (cpl_propertylist_get_double(main_header, EXPTIME) != exptime) { 01192 cpl_msg_warning(__func__, "EXPTIME inconsistent") ; 01193 cpl_propertylist_delete(mh1); 01194 cpl_propertylist_delete(main_header); 01195 return 0 ; 01196 } 01197 if (strcmp(cpl_propertylist_get_string(main_header, READMODE), 01198 readmode) != 0) { 01199 cpl_msg_warning(__func__, "READMODE inconsistent") ; 01200 cpl_propertylist_delete(mh1); 01201 cpl_propertylist_delete(main_header); 01202 return 0 ; 01203 } 01204 01205 /* Assure that arc lamps are off */ 01206 if ((kmo_check_lamp(main_header, INS_LAMP1_ST) != FALSE) 01207 || (kmo_check_lamp(main_header, INS_LAMP2_ST) != FALSE)) { 01208 cpl_msg_warning(__func__, "Arc lamps must be switched off") ; 01209 cpl_propertylist_delete(mh1); 01210 cpl_propertylist_delete(main_header); 01211 return 0 ; 01212 } 01213 01214 /* Assure that at least one flat lamp is on */ 01215 if ((kmo_check_lamp(main_header, INS_LAMP3_ST) != TRUE) 01216 && (kmo_check_lamp(main_header, INS_LAMP4_ST) != TRUE)) { 01217 cpl_msg_warning(__func__, "At least one flat lamps must be on") ; 01218 cpl_propertylist_delete(mh1); 01219 cpl_propertylist_delete(main_header); 01220 return 0 ; 01221 } 01222 01223 /* Get next FLAT_ON frame */ 01224 frame = kmo_dfs_get_frame(frameset, NULL); 01225 01226 cpl_propertylist_delete(main_header); 01227 } 01228 cpl_msg_info(__func__, "EXPTIME: %g seconds", exptime); 01229 cpl_msg_info(__func__, "NDIT: %d", ndit); 01230 cpl_msg_info(__func__, "Detector readout mode: %s", readmode); 01231 cpl_propertylist_delete(mh1); 01232 01233 /* Check Filters consistency */ 01234 if (kmo_check_frameset_setup(frameset, FLAT_ON, TRUE, FALSE, FALSE) != 01235 CPL_ERROR_NONE) { 01236 cpl_msg_warning(__func__, "Filters are not consistent") ; 01237 return 0 ; 01238 } 01239 01240 /* Return */ 01241 *nx = naxis1 ; 01242 *ny = naxis2 ; 01243 *ne = next ; 01244 *exptime_on = exptime ; 01245 return 1 ; 01246 } 01247
1.7.6.1