KMOS Pipeline Reference Manual
1.3.11
|
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 int nx, ny, next ; 00380 int * angles_array ; 00381 int nb_angles ; 00382 cpl_image ** stored_flat ; 00383 cpl_image ** stored_noise ; 00384 cpl_image ** stored_badpix ; 00385 cpl_image ** stored_xcal ; 00386 cpl_image ** stored_ycal ; 00387 double * stored_gapmean ; 00388 double * stored_gapsdv ; 00389 double * stored_gapmaxdev ; 00390 double * stored_slitmean ; 00391 double * stored_slitsdv ; 00392 double * stored_slitmaxdev ; 00393 double * stored_qc_flat_eff ; 00394 double * stored_qc_flat_sn ; 00395 int * stored_qc_flat_sat ; 00396 cpl_frameset * angle_frameset ; 00397 char * extname ; 00398 char * suffix ; 00399 char * fn_suffix ; 00400 unsigned int save_mode ; 00401 char * fn_flat = "flat_tmp.fits" ; 00402 char * fn_noise = "flat_noise.fits" ; 00403 char * fn_badpix = "badpix_tmp.fits" ; 00404 cpl_imagelist * det_lamp_on ; 00405 cpl_imagelist * det_lamp_off ; 00406 cpl_image * img_in ; 00407 cpl_image * combined_data_on ; 00408 cpl_image * combined_noise_on ; 00409 cpl_image * combined_data_off[KMOS_NR_DETECTORS] ; 00410 cpl_image * combined_noise_off[KMOS_NR_DETECTORS] ; 00411 cpl_image * bad_pix_mask_flat ; 00412 cpl_image * bad_pix_mask_dark[KMOS_NR_DETECTORS] ; 00413 cpl_image * xcal ; 00414 cpl_image * ycal ; 00415 cpl_array ** unused_ifus_before ; 00416 cpl_array ** unused_ifus_after ; 00417 cpl_propertylist * main_header ; 00418 cpl_propertylist * main_header_xcal ; 00419 cpl_propertylist * sub_header ; 00420 cpl_table *** edge_table ; 00421 cpl_error_code * spec_found ; 00422 double gain, exptime, mean_data, mean_noise ; 00423 int sx, nr_bad_pix, nr_sat, i, j, a ; 00424 00425 /* Check entries */ 00426 if (parlist == NULL || frameset == NULL) { 00427 cpl_msg_error(__func__, "Null Inputs") ; 00428 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ; 00429 return -1 ; 00430 } 00431 00432 /* Get Parameters */ 00433 par = cpl_parameterlist_find_const(parlist, 00434 "kmos.kmos_flat.surrounding_pixels"); 00435 surrounding_pixels = cpl_parameter_get_int(par); 00436 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_flat.badpix_thresh"); 00437 badpix_thresh = cpl_parameter_get_int(par); 00438 par = cpl_parameterlist_find_const(parlist, 00439 "kmos.kmos_flat.suppress_extension"); 00440 suppress_extension = cpl_parameter_get_bool(par); 00441 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_flat.angle"); 00442 reduce_angle = cpl_parameter_get_double(par); 00443 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_flat.detector"); 00444 reduce_det = cpl_parameter_get_int(par); 00445 00446 kmos_combine_pars_load(parlist, "kmos.kmos_flat", &cmethod, &cpos_rej, 00447 &cneg_rej, &citer, &cmin, &cmax, FALSE); 00448 00449 /* Check Parameters */ 00450 if (surrounding_pixels < 0 || surrounding_pixels > 8) { 00451 cpl_msg_error(__func__, "surrounding_pixels must be in [0,8]") ; 00452 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00453 return -1 ; 00454 } 00455 if (badpix_thresh < 0 || badpix_thresh > 100) { 00456 cpl_msg_error(__func__, "badpix_thresh must be in [0,100]") ; 00457 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00458 return -1 ; 00459 } 00460 if (reduce_det < 0 || reduce_det > 3) { 00461 cpl_msg_error(__func__, "detector must be in [1,3]") ; 00462 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00463 return -1 ; 00464 } 00465 00466 /* Identify the RAW and CALIB frames in the input frameset */ 00467 if (kmo_dfs_set_groups(frameset, "kmos_flat") != 1) { 00468 cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ; 00469 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00470 return -1 ; 00471 } 00472 00473 /* Check the inputs consistency */ 00474 if (kmos_flat_check_inputs(frameset, &nx, &ny, &next, &exptime) != 1) { 00475 cpl_msg_error(__func__, "Input frameset is not consistent") ; 00476 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00477 return -1 ; 00478 } 00479 00480 /* Instrument setup */ 00481 suffix = kmo_dfs_get_suffix(kmo_dfs_get_frame(frameset,FLAT_ON),TRUE,FALSE); 00482 cpl_msg_info(__func__, "Detected instrument setup: %s", suffix+1); 00483 00484 /* Get Rotator angles */ 00485 if ((angles_array = kmos_get_angles(frameset, &nb_angles,FLAT_ON)) == NULL){ 00486 cpl_msg_error(__func__, "Cannot get Angles informations") ; 00487 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00488 return -1 ; 00489 } 00490 00491 /* The frames have to be stored temporarily because the QC parameters */ 00492 /* for the main header are calculated from each detector. */ 00493 /* So they can be stored only when all detectors are processed */ 00494 stored_flat = (cpl_image**)cpl_calloc(next*nb_angles, sizeof(cpl_image*)); 00495 stored_noise = (cpl_image**)cpl_calloc(next*nb_angles, sizeof(cpl_image*)); 00496 stored_badpix = (cpl_image**)cpl_calloc(next*nb_angles, sizeof(cpl_image*)); 00497 stored_xcal = (cpl_image**)cpl_calloc(next*nb_angles, sizeof(cpl_image*)); 00498 stored_ycal = (cpl_image**)cpl_calloc(next * nb_angles, sizeof(cpl_image*)); 00499 stored_qc_flat_sat = (int*)cpl_malloc(next * nb_angles * sizeof(int)); 00500 stored_qc_flat_eff = (double*)cpl_malloc(next * nb_angles * sizeof(double)); 00501 stored_qc_flat_sn = (double*)cpl_malloc(next * nb_angles * sizeof(double)); 00502 stored_gapmean = (double*)cpl_malloc(next * nb_angles * sizeof(double)); 00503 stored_gapsdv = (double*)cpl_malloc(next * nb_angles * sizeof(double)); 00504 stored_gapmaxdev = (double*)cpl_malloc(next * nb_angles * sizeof(double)); 00505 stored_slitmean = (double*)cpl_malloc(next * nb_angles * sizeof(double)); 00506 stored_slitsdv = (double*)cpl_malloc(next * nb_angles * sizeof(double)); 00507 stored_slitmaxdev = (double*)cpl_malloc(next * nb_angles * sizeof(double)); 00508 spec_found = (cpl_error_code*)cpl_malloc(next * nb_angles * 00509 sizeof(cpl_error_code)); 00510 00511 /* Initialise */ 00512 for (i = 0; i < next * nb_angles ; i++) { 00513 stored_qc_flat_sat[i] = 0; 00514 stored_qc_flat_eff[i] = 0.0; 00515 stored_qc_flat_sn[i] = 0.0; 00516 stored_gapmean[i] = 0.0; 00517 stored_gapsdv[i] = 0.0; 00518 stored_gapmaxdev[i] = 0.0; 00519 stored_slitmean[i] = 0.0; 00520 stored_slitsdv[i] = 0.0; 00521 stored_slitmaxdev[i] = 0.0; 00522 spec_found[i] = CPL_ERROR_NONE; 00523 } 00524 00525 /* TODO : Improve handling of edge_table !!!! */ 00526 edge_table = (cpl_table***)cpl_malloc(next*nb_angles * sizeof(cpl_table**)); 00527 for (i = 0; i < next * nb_angles; i++) edge_table[i] = NULL; 00528 00529 /* Check which IFUs are active for all FLAT_ON frames */ 00530 unused_ifus_before = kmo_get_unused_ifus(frameset, 0, 0); 00531 unused_ifus_after = kmo_duplicate_unused_ifus(unused_ifus_before); 00532 kmo_print_unused_ifus(unused_ifus_before, FALSE); 00533 kmo_free_unused_ifus(unused_ifus_before); 00534 00535 /* Combine the FLAT_OFF frames for the 3 detectors */ 00536 for (i = 1; i <= next; i++) { 00537 /* Compute only one detector */ 00538 if (reduce_det != 0 && i != reduce_det) continue ; 00539 00540 /* Load the badpixel masks */ 00541 bad_pix_mask_dark[i-1] = kmo_dfs_load_image(frameset, BADPIXEL_DARK, 00542 i, 2, FALSE, NULL) ; 00543 00544 /* Load lamp-off images */ 00545 det_lamp_off = cpl_imagelist_new(); 00546 frame = kmo_dfs_get_frame(frameset, FLAT_OFF); 00547 j = 0; 00548 while (frame != NULL) { 00549 img_in = kmo_dfs_load_image_frame(frame, i, FALSE, FALSE, NULL); 00550 kmo_image_reject_from_mask(img_in, bad_pix_mask_dark[i-1]); 00551 cpl_imagelist_set(det_lamp_off, img_in, j++); 00552 frame = kmo_dfs_get_frame(frameset, NULL); 00553 } 00554 00555 /* Combine FLAT_OFF frames */ 00556 cpl_msg_info(__func__, "Combine FLAT_OFF frames for Detector %d", i) ; 00557 kmos_combine_frames(det_lamp_off, cmethod, cpos_rej, 00558 cneg_rej, citer, cmax, cmin, &(combined_data_off[i-1]), 00559 &(combined_noise_off[i-1]), -1.0); 00560 /* 00561 cpl_image_save(combined_data_off[i-1], "off.fits", 00562 CPL_TYPE_FLOAT, NULL, CPL_IO_CREATE) ; 00563 */ 00564 cpl_imagelist_delete(det_lamp_off); 00565 cpl_image_power(combined_noise_off[i-1], 2.0); 00566 } 00567 00568 save_mode = CPL_IO_CREATE; 00569 /* Loop all Rotator Angles and Detectors */ 00570 for (a = 0; a < nb_angles; a++) { 00571 /* Reduce only one angle */ 00572 if (reduce_angle <= 360 && angles_array[a] != reduce_angle) continue ; 00573 00574 cpl_msg_info(__func__, "Processing rotator angle %d -> %d degree", 00575 a, angles_array[a]); 00576 cpl_msg_indent_more() ; 00577 00578 /* Get the frameset with this angle */ 00579 angle_frameset = kmos_get_angle_frameset(frameset, angles_array[a], 00580 FLAT_ON); 00581 if (angle_frameset == NULL) { 00582 cpl_msg_error(__func__, "Cannot get angle frameset") ; 00583 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00584 cpl_msg_indent_less() ; 00585 cpl_free(angles_array) ; 00586 return -1 ; 00587 } 00588 00589 for (i = 1; i <= next; i++) { 00590 /* Compute only one detector */ 00591 if (reduce_det != 0 && i != reduce_det) continue ; 00592 00593 cpl_msg_info(__func__, "Processing detector No. %d", i); 00594 cpl_msg_indent_more() ; 00595 00596 sx = a * next + (i - 1); 00597 00598 /* Load lamp-on images for Angle a */ 00599 det_lamp_on = cpl_imagelist_new(); 00600 frame = kmo_dfs_get_frame(angle_frameset, FLAT_ON); 00601 j = 0; 00602 while (frame != NULL) { 00603 img_in=kmo_dfs_load_image_frame(frame, i, FALSE, TRUE, &nr_sat); 00604 kmo_image_reject_from_mask(img_in, bad_pix_mask_dark[i-1]); 00605 cpl_imagelist_set(det_lamp_on, img_in, j++); 00606 frame = kmo_dfs_get_frame(angle_frameset, NULL); 00607 } 00608 00609 /* Count saturated pixels for each detector */ 00610 cpl_msg_info(__func__, "Count Saturated pixels on the detector") ; 00611 frame = kmo_dfs_get_frame(angle_frameset, FLAT_ON); 00612 main_header = kmclipm_propertylist_load( 00613 cpl_frame_get_filename(frame), 0); 00614 if (strcmp(cpl_propertylist_get_string(main_header, READMODE), 00615 "Nondest") == 0) { 00616 // NDR: non-destructive readout mode 00617 stored_qc_flat_sat[sx] = nr_sat; 00618 } else { 00619 // normal readout mode 00620 stored_qc_flat_sat[sx] = kmo_imagelist_get_saturated( 00621 det_lamp_on, KMO_FLAT_SATURATED, KMO_FLAT_SAT_MIN); 00622 } 00623 cpl_propertylist_delete(main_header); 00624 00625 /* Combine imagelists and create noise */ 00626 cpl_msg_info(__func__, "Combine FLAT_ON frames") ; 00627 kmos_combine_frames(det_lamp_on, cmethod, cpos_rej, 00628 cneg_rej, citer, cmax, cmin, &combined_data_on, 00629 &combined_noise_on, -1.0); 00630 cpl_imagelist_delete(det_lamp_on); 00631 00632 if (kmclipm_omit_warning_one_slice > 10) 00633 kmclipm_omit_warning_one_slice = FALSE; 00634 00635 /* Subtract combined lamp_off from lamp_on */ 00636 cpl_image_subtract(combined_data_on, combined_data_off[i-1]); 00637 00638 /* noise: sig_x = sqrt(sig_u^2 + sig_v^2 */ 00639 cpl_msg_info(__func__, "Compute the noise") ; 00640 cpl_image_power(combined_noise_on, 2.0); 00641 cpl_image_add(combined_noise_on, combined_noise_off[i-1]); 00642 cpl_image_power(combined_noise_on, 0.5); 00643 00644 /* Create bad-pixel-mask */ 00645 bad_pix_mask_flat = kmo_create_bad_pix_flat_thresh(combined_data_on, 00646 surrounding_pixels, badpix_thresh); 00647 00648 /* Calculate spectral curvature here */ 00649 cpl_msg_info(__func__, "Compute the spectral curvature") ; 00650 cpl_msg_indent_more() ; 00651 spec_found[sx] = kmo_calc_curvature(combined_data_on, 00652 combined_noise_on, unused_ifus_after[i-1], 00653 bad_pix_mask_flat, i, &xcal, &ycal, stored_gapmean+(sx), 00654 stored_gapsdv+(sx), stored_gapmaxdev+(sx), 00655 stored_slitmean+(sx), stored_slitsdv+(sx), 00656 stored_slitmaxdev+(sx), &edge_table[sx]); 00657 cpl_msg_indent_less() ; 00658 00659 if (spec_found[sx] == CPL_ERROR_NONE) { 00660 // in kmo_calc_curvature() the spectral slope of each 00661 // slitlet has been normalised individually. Now the 00662 // normalisation on the whole frame is applied. 00663 // (cpl_image_get_mean() ignores bad pixels when 00664 // calculating the mean) 00665 mean_data = cpl_image_get_mean(combined_data_on); 00666 stored_qc_flat_eff[sx] = mean_data / exptime; 00667 mean_noise = cpl_image_get_mean(combined_noise_on); 00668 if (fabs(mean_noise) < 1e-3) { 00669 cpl_msg_error(__func__, "Division by 0.0") ; 00670 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00671 cpl_free(angles_array) ; 00672 return -1 ; 00673 } 00674 stored_qc_flat_sn[sx] = mean_data / mean_noise; 00675 00676 /* Normalize data & noise on the whole detector frame */ 00677 /* The spectral slope on each slitlet has already been */ 00678 /* normalised in kmo_calc_curvature() */ 00679 cpl_image_divide_scalar(combined_data_on, mean_data); 00680 cpl_image_divide_scalar(combined_noise_on, mean_data); 00681 00682 /* Apply the badpixel mask to the produced frames */ 00683 cpl_image_multiply(combined_data_on, bad_pix_mask_flat); 00684 cpl_image_multiply(combined_noise_on, bad_pix_mask_flat); 00685 cpl_image_multiply(xcal, bad_pix_mask_flat) ; 00686 cpl_image_multiply(ycal, bad_pix_mask_flat) ; 00687 00688 /* Store temporarily flat, badpixel and calibration */ 00689 stored_xcal[sx] = xcal; 00690 stored_ycal[sx] = ycal; 00691 00692 /* Save immediate results, free memory */ 00693 kmclipm_image_save(combined_data_on, fn_flat, CPL_TYPE_FLOAT, 00694 NULL, save_mode, 0./0.); 00695 kmclipm_image_save(combined_noise_on, fn_noise, CPL_TYPE_FLOAT, 00696 NULL, save_mode, 0./0.); 00697 kmclipm_image_save(bad_pix_mask_flat, fn_badpix, CPL_TYPE_FLOAT, 00698 NULL, save_mode, 0./0.); 00699 /* Next saves will create extensions */ 00700 save_mode = CPL_IO_EXTEND; 00701 00702 } else if (spec_found[sx] == CPL_ERROR_DATA_NOT_FOUND) { 00703 /* All IFUs seem to be deativated */ 00704 cpl_msg_warning(__func__, "All IFUs deactivated") ; 00705 cpl_error_reset(); 00706 00707 /* Save immediate results, free memory */ 00708 cpl_image_save(NULL, fn_flat, CPL_TYPE_FLOAT, NULL, save_mode); 00709 cpl_image_save(NULL, fn_noise, CPL_TYPE_FLOAT, NULL, save_mode); 00710 cpl_image_save(NULL, fn_badpix, CPL_TYPE_FLOAT, NULL,save_mode); 00711 /* Next saves will create extensions */ 00712 save_mode = CPL_IO_EXTEND; 00713 00714 stored_xcal[sx] = NULL ; 00715 stored_ycal[sx] = NULL ; 00716 } else { 00717 // another error occured 00718 cpl_msg_error(__func__, "Unknown ERROR !") ; 00719 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00720 cpl_image_delete(combined_data_on); 00721 cpl_image_delete(combined_noise_on); 00722 cpl_image_delete(bad_pix_mask_flat); 00723 cpl_free(angles_array) ; 00724 cpl_msg_indent_less() ; 00725 cpl_msg_indent_less() ; 00726 return -1 ; 00727 } 00728 cpl_image_delete(combined_data_on); 00729 cpl_image_delete(combined_noise_on); 00730 cpl_image_delete(bad_pix_mask_flat); 00731 00732 cpl_msg_indent_less() ; 00733 } // for i = 1; i <= next 00734 cpl_frameset_delete(angle_frameset); 00735 cpl_msg_indent_less() ; 00736 } // for a = 0; a < nb_angles 00737 00738 /* Clean OFF frames */ 00739 for (i = 1; i <= next; i++) { 00740 /* Compute only one detector */ 00741 if (reduce_det != 0 && i != reduce_det) continue ; 00742 00743 cpl_image_delete(combined_data_off[i-1]) ; 00744 cpl_image_delete(combined_noise_off[i-1]) ; 00745 cpl_image_delete(bad_pix_mask_dark[i-1]); 00746 } 00747 00748 /* ----- QC parameters & saving */ 00749 /* ---- load, update & save primary header */ 00750 main_header = kmo_dfs_load_primary_header(frameset, FLAT_ON); 00751 00752 /* Update which IFUs are not used */ 00753 kmo_print_unused_ifus(unused_ifus_after, TRUE); 00754 kmo_set_unused_ifus(unused_ifus_after, main_header, "kmos_flat"); 00755 kmo_free_unused_ifus(unused_ifus_after); 00756 00757 /* xcal gets additionally the boundaries of the IFUs for reconstruction */ 00758 main_header_xcal=kmos_create_bounds_properties(stored_ycal,next,nb_angles) ; 00759 00760 /* --------- saving headers */ 00761 if (!suppress_extension) fn_suffix = cpl_sprintf("%s", suffix); 00762 else fn_suffix = cpl_sprintf("%s", ""); 00763 cpl_free(suffix); 00764 00765 cpl_msg_info(__func__, "Saving data..."); 00766 00767 frame = kmo_dfs_get_frame(frameset, FLAT_ON); 00768 kmo_dfs_save_main_header(frameset, MASTER_FLAT, fn_suffix, frame, 00769 main_header, parlist, cpl_func); 00770 kmo_dfs_save_main_header(frameset, XCAL, fn_suffix, frame, 00771 main_header_xcal, parlist, cpl_func); 00772 kmo_dfs_save_main_header(frameset, YCAL, fn_suffix, frame, 00773 main_header, parlist, cpl_func); 00774 kmo_dfs_save_main_header(frameset, BADPIXEL_FLAT, fn_suffix, frame, 00775 main_header, parlist, cpl_func); 00776 kmo_dfs_save_main_header(frameset, FLAT_EDGE, fn_suffix, frame, 00777 main_header, parlist, cpl_func); 00778 00779 cpl_propertylist_delete(main_header); 00780 cpl_propertylist_delete(main_header_xcal); 00781 00782 /* -------- saving sub frames */ 00783 ext_index = 0 ; 00784 for (a = 0; a < nb_angles; a++) { 00785 /* Reduce only one angle */ 00786 if (reduce_angle <= 360 && angles_array[a] != reduce_angle) continue ; 00787 00788 for (i = 1; i <= next; i++) { 00789 /* Compute only one detector */ 00790 if (reduce_det != 0 && i != reduce_det) continue ; 00791 00792 sx = a * next + (i - 1); 00793 // load stored data again 00794 stored_flat[sx]=kmclipm_image_load(fn_flat, CPL_TYPE_FLOAT, 0, 00795 ext_index); 00796 cpl_error_reset() ; 00797 stored_noise[sx]=kmclipm_image_load(fn_noise, CPL_TYPE_FLOAT, 0, 00798 ext_index); 00799 cpl_error_reset() ; 00800 stored_badpix[sx]=kmclipm_image_load(fn_badpix,CPL_TYPE_FLOAT, 0, 00801 ext_index); 00802 cpl_error_reset() ; 00803 ext_index ++ ; 00804 00805 sub_header = kmo_dfs_load_sub_header(frameset, FLAT_ON, i, FALSE); 00806 kmclipm_update_property_double(sub_header,CAL_ROTANGLE, 00807 ((double) angles_array[a]), 00808 "[deg] Rotator relative to nasmyth"); 00809 00810 if (spec_found[sx] == CPL_ERROR_NONE) { 00811 kmclipm_update_property_int(sub_header, QC_FLAT_SAT, 00812 stored_qc_flat_sat[sx], 00813 "[] nr. saturated pixels of master flat"); 00814 /* Load gain */ 00815 gain = kmo_dfs_get_property_double(sub_header, GAIN); 00816 kmclipm_update_property_double(sub_header, QC_FLAT_EFF, 00817 stored_qc_flat_eff[sx]/gain, 00818 "[e-/s] rel. brightness of flat lamp"); 00819 00820 kmclipm_update_property_double(sub_header, QC_FLAT_SN, 00821 stored_qc_flat_sn[sx], "[] S/N of master flat"); 00822 } 00823 00824 /* Store qc parameters only if any slitlet- and gap-width */ 00825 /* has been detected (should be the case when at least */ 00826 /* one IFU is active) */ 00827 if (stored_xcal[sx] != NULL) { 00828 kmclipm_update_property_double(sub_header, QC_GAP_MEAN, 00829 stored_gapmean[sx], 00830 "[pix] mean gap width between slitlets"); 00831 kmclipm_update_property_double(sub_header, QC_GAP_SDV, 00832 stored_gapsdv[sx], 00833 "[pix] stdev of gap width between slitlets"); 00834 kmclipm_update_property_double(sub_header, QC_GAP_MAXDEV, 00835 stored_gapmaxdev[sx], 00836 "[pix] max gap deviation between slitlets"); 00837 kmclipm_update_property_double(sub_header, QC_SLIT_MEAN, 00838 stored_slitmean[sx], "[pix] mean slitlet width"); 00839 kmclipm_update_property_double(sub_header, QC_SLIT_SDV, 00840 stored_slitsdv[sx], "[pix] stdev of slitlet widths"); 00841 kmclipm_update_property_double(sub_header, QC_SLIT_MAXDEV, 00842 stored_slitmaxdev[sx], 00843 "[pix] max slitlet width deviation"); 00844 } 00845 00846 /* Calculate QC.BADPIX.NCOUNT */ 00847 /* Remove 4pixel-border as bad pixels */ 00848 nr_bad_pix = 0 ; 00849 if (stored_badpix[sx] != NULL) { 00850 nr_bad_pix = cpl_image_count_rejected(stored_badpix[sx]); 00851 nr_bad_pix -= 2*KMOS_BADPIX_BORDER*(nx-2*KMOS_BADPIX_BORDER) + 00852 2*KMOS_BADPIX_BORDER*ny; 00853 } 00854 00855 kmclipm_update_property_int(sub_header, QC_NR_BAD_PIX, nr_bad_pix, 00856 "[] nr. of bad pixels"); 00857 00858 /* Save flat frame */ 00859 extname = kmo_extname_creator(detector_frame, i, EXT_DATA); 00860 kmclipm_update_property_string(sub_header, EXTNAME,extname, 00861 "FITS extension name"); 00862 cpl_free(extname); 00863 00864 kmclipm_update_property_int(sub_header, EXTVER, sx+1, 00865 "FITS extension ver"); 00866 00867 kmo_dfs_save_image(stored_flat[sx], MASTER_FLAT, fn_suffix, 00868 sub_header, 0./0.); 00869 00870 /* Save noise frame when enough input frames were available */ 00871 extname = kmo_extname_creator(detector_frame, i, EXT_NOISE); 00872 kmclipm_update_property_string(sub_header, EXTNAME,extname, 00873 "FITS extension name"); 00874 cpl_free(extname); 00875 00876 kmo_dfs_save_image(stored_noise[sx], MASTER_FLAT, fn_suffix, 00877 sub_header, 0./0.); 00878 00879 /* Save bad_pix frame */ 00880 extname = kmo_extname_creator(detector_frame, i, EXT_BADPIX); 00881 kmclipm_update_property_string(sub_header, EXTNAME,extname, 00882 "FITS extension name"); 00883 cpl_free(extname); 00884 00885 kmo_dfs_save_image(stored_badpix[sx], BADPIXEL_FLAT, fn_suffix, 00886 sub_header, 0.); 00887 00888 // save xcal and ycal-frame 00889 extname = kmo_extname_creator(detector_frame, i, EXT_DATA); 00890 kmclipm_update_property_string(sub_header, EXTNAME, extname, 00891 "FITS extension name"); 00892 cpl_free(extname); 00893 00894 kmo_dfs_save_image(stored_xcal[sx], XCAL, fn_suffix, sub_header, 00895 0./0.); 00896 kmo_dfs_save_image(stored_ycal[sx], YCAL, fn_suffix, sub_header, 00897 0./0.); 00898 00899 /* Save edge_pars-frame */ 00900 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00901 extname = cpl_sprintf("%s_IFU.%d_ANGLE.%d", EXT_LIST, 00902 j+1+(i-1)*KMOS_IFUS_PER_DETECTOR, angles_array[a]); 00903 kmclipm_update_property_string(sub_header, EXTNAME, extname, 00904 "FITS extension name"); 00905 cpl_free(extname); 00906 00907 kmclipm_update_property_int(sub_header, CAL_IFU_NR, 00908 j+1+(i-1)*KMOS_IFUS_PER_DETECTOR, "IFU Number {1..24}"); 00909 00910 /* Save edge-parameters as product */ 00911 if ((spec_found[sx] != CPL_ERROR_DATA_NOT_FOUND) && 00912 (edge_table[sx] != NULL)&&(edge_table[sx][j] != NULL)) { 00913 kmo_dfs_save_table(edge_table[sx][j], FLAT_EDGE, 00914 fn_suffix, sub_header); 00915 } else { 00916 cpl_propertylist_erase(sub_header, CRVAL1); 00917 cpl_propertylist_erase(sub_header, CRVAL2); 00918 cpl_propertylist_erase(sub_header, CD1_1); 00919 cpl_propertylist_erase(sub_header, CD1_2); 00920 cpl_propertylist_erase(sub_header, CD2_1); 00921 cpl_propertylist_erase(sub_header, CD2_2); 00922 cpl_propertylist_erase(sub_header, CRPIX1); 00923 cpl_propertylist_erase(sub_header, CRPIX2); 00924 cpl_propertylist_erase(sub_header, CTYPE1); 00925 cpl_propertylist_erase(sub_header, CTYPE2); 00926 00927 kmo_dfs_save_table(NULL, FLAT_EDGE, fn_suffix, 00928 sub_header); 00929 } 00930 } 00931 cpl_propertylist_delete(sub_header); 00932 00933 cpl_image_delete(stored_flat[sx]); 00934 cpl_image_delete(stored_noise[sx]); 00935 cpl_image_delete(stored_badpix[sx]); 00936 } // for (i = next) 00937 } // for (a = nb_angles) 00938 00939 // delete temporary files 00940 unlink(fn_flat); 00941 unlink(fn_noise); 00942 unlink(fn_badpix); 00943 00944 cpl_free(stored_qc_flat_sat); 00945 cpl_free(stored_qc_flat_eff); 00946 cpl_free(stored_qc_flat_sn); 00947 cpl_free(stored_gapmean); 00948 cpl_free(stored_gapsdv); 00949 cpl_free(stored_gapmaxdev); 00950 cpl_free(stored_slitmean); 00951 cpl_free(stored_slitsdv); 00952 cpl_free(stored_slitmaxdev); 00953 cpl_free(fn_suffix); 00954 cpl_free(stored_flat); 00955 cpl_free(stored_noise); 00956 cpl_free(stored_badpix); 00957 for (i = 0; i < next * nb_angles; i++) { 00958 cpl_image_delete(stored_xcal[i]); 00959 cpl_image_delete(stored_ycal[i]); 00960 } 00961 cpl_free(stored_xcal); 00962 cpl_free(stored_ycal); 00963 if (edge_table != NULL) { 00964 for (i = 0; i < next * nb_angles; i++) { 00965 if (edge_table[i] != NULL) { 00966 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00967 cpl_table_delete(edge_table[i][j]); 00968 } 00969 cpl_free(edge_table[i]); 00970 } 00971 } 00972 cpl_free(edge_table); 00973 } 00974 cpl_free(spec_found); 00975 cpl_free(angles_array) ; 00976 00977 return 0; 00978 } 00979 00982 /*----------------------------------------------------------------------------*/ 00992 /*----------------------------------------------------------------------------*/ 00993 static cpl_propertylist * kmos_create_bounds_properties( 00994 cpl_image ** stored_ycal, 00995 int next, 00996 int nb_angles) 00997 { 00998 cpl_propertylist * bounds_props ; 00999 int * bounds ; 01000 int ** total_bounds ; 01001 char * tmpstr ; 01002 int a, i, j, sx ; 01003 01004 /* Check Entries */ 01005 if (stored_ycal == NULL) return NULL ; 01006 01007 /* Add here boundaries for reconstruction */ 01008 bounds_props = cpl_propertylist_new(); 01009 01010 /* Initialize total_bounds */ 01011 total_bounds = (int**)cpl_malloc(next*sizeof(int*)); 01012 for (i = 0; i < next; i++) { 01013 total_bounds[i]=(int*)cpl_calloc(2*KMOS_IFUS_PER_DETECTOR,sizeof(int)); 01014 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01015 total_bounds[i][2*j] = 2048; 01016 total_bounds[i][2*j+1] = 0; 01017 } 01018 } 01019 01020 /* Store the min left bound and max right bound for all angles */ 01021 for (a = 0; a < nb_angles; a++) { 01022 for (i = 0; i < next; i++) { 01023 sx = a * next + i; 01024 if (stored_ycal[sx] != NULL) { 01025 bounds = kmo_split_frame(stored_ycal[sx]); 01026 01027 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01028 if ((total_bounds[i][2*j] == -1)||(bounds[2*j] == -1)) { 01029 total_bounds[i][2*j] = -1; 01030 } else { 01031 if (total_bounds[i][2*j] > bounds[2*j]) { 01032 total_bounds[i][2*j] = bounds[2*j]; 01033 } 01034 } 01035 01036 if ((total_bounds[i][2*j+1] == -1) || 01037 (bounds[2*j+1] == -1)) { 01038 total_bounds[i][2*j+1] = -1; 01039 } else { 01040 if (total_bounds[i][2*j+1] < bounds[2*j+1]) { 01041 total_bounds[i][2*j+1] = bounds[2*j+1]; 01042 } 01043 } 01044 } 01045 cpl_free(bounds); 01046 } else { 01047 // whole detector inactive 01048 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01049 total_bounds[i][2*j] = -1; 01050 total_bounds[i][2*j+1] = -1; 01051 } 01052 } 01053 } // for (next) 01054 } // for (nb_angles) 01055 01056 /* Write the min left bound and max right bound for all angles */ 01057 /* into the main header */ 01058 for (i = 0; i < next; i++) { 01059 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01060 if (total_bounds[i][2*j] > -1) { 01061 tmpstr= cpl_sprintf("%s%d%s", BOUNDS_PREFIX, 01062 i*KMOS_IFUS_PER_DETECTOR + j+1, "_L"); 01063 kmclipm_update_property_int(bounds_props, tmpstr, 01064 total_bounds[i][2*j], 01065 "[pix] left boundary for reconstr."); 01066 cpl_free(tmpstr); 01067 } 01068 01069 if (total_bounds[i][2*j+1] > -1) { 01070 tmpstr= cpl_sprintf("%s%d%s", BOUNDS_PREFIX, 01071 i*KMOS_IFUS_PER_DETECTOR + j+1, "_R"); 01072 kmclipm_update_property_int(bounds_props,tmpstr, 01073 total_bounds[i][2*j+1], 01074 "[pix] right boundary for reconstr."); 01075 cpl_free(tmpstr); 01076 } 01077 } 01078 } // for (next) 01079 for (i = 0; i < next; i++) cpl_free(total_bounds[i]); 01080 cpl_free(total_bounds); 01081 01082 return bounds_props ; 01083 } 01084 01085 /*----------------------------------------------------------------------------*/ 01095 /*----------------------------------------------------------------------------*/ 01096 static int kmos_flat_check_inputs( 01097 cpl_frameset * frameset, 01098 int * nx, 01099 int * ny, 01100 int * next, 01101 double * exptime_on) 01102 { 01103 cpl_frame * frame ; 01104 cpl_propertylist * eh ; 01105 cpl_propertylist * mh1 ; 01106 cpl_propertylist * main_header ; 01107 int ndit ; 01108 double exptime ; 01109 const char * readmode ; 01110 int naxis1, naxis2, n_ext ; 01111 01112 /* TODO Add frames dimensions checks TODO */ 01113 01114 /* Check Entries */ 01115 if (nx == NULL || ny == NULL || frameset == NULL || exptime_on == NULL) 01116 return -1; 01117 01118 /* check BADPIXEL_DARK */ 01119 frame = kmo_dfs_get_frame(frameset, BADPIXEL_DARK); 01120 if (frame == NULL) { 01121 cpl_msg_warning(__func__, "BADPIXEL_DARK frame is missing") ; 01122 return 0 ; 01123 } 01124 n_ext = cpl_frame_get_nextensions(frame); 01125 if (n_ext != KMOS_NR_DETECTORS) { 01126 cpl_msg_warning(__func__, "BADPIXEL_DARK must have 3 extensions") ; 01127 return 0 ; 01128 } 01129 eh = cpl_propertylist_load(cpl_frame_get_filename(frame), 1); 01130 naxis1 = kmos_pfits_get_naxis1(eh) ; 01131 naxis2 = kmos_pfits_get_naxis2(eh) ; 01132 cpl_propertylist_delete(eh) ; 01133 01134 /* check FLAT_OFF */ 01135 frame = kmo_dfs_get_frame(frameset, FLAT_OFF); 01136 mh1 = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 01137 ndit = cpl_propertylist_get_int(mh1, NDIT); 01138 exptime = cpl_propertylist_get_double(mh1, EXPTIME); 01139 readmode = cpl_propertylist_get_string(mh1, READMODE); 01140 01141 /* Loop through FLAT_OFF frames */ 01142 while (frame != NULL) { 01143 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 01144 01145 if (cpl_propertylist_get_int(main_header, NDIT) != ndit) { 01146 cpl_msg_warning(__func__, "NDIT inconsistent") ; 01147 cpl_propertylist_delete(mh1); 01148 cpl_propertylist_delete(main_header); 01149 return 0 ; 01150 } 01151 if (cpl_propertylist_get_double(main_header, EXPTIME) != exptime) { 01152 cpl_msg_warning(__func__, "EXPTIME inconsistent") ; 01153 cpl_propertylist_delete(mh1); 01154 cpl_propertylist_delete(main_header); 01155 return 0 ; 01156 } 01157 if (strcmp(cpl_propertylist_get_string(main_header, READMODE), 01158 readmode) != 0) { 01159 cpl_msg_warning(__func__, "READMODE inconsistent") ; 01160 cpl_propertylist_delete(mh1); 01161 cpl_propertylist_delete(main_header); 01162 return 0 ; 01163 } 01164 01165 /* Assure that arc lamps are off */ 01166 if ((kmo_check_lamp(main_header, INS_LAMP1_ST) != FALSE) 01167 || (kmo_check_lamp(main_header, INS_LAMP2_ST) != FALSE)) { 01168 cpl_msg_warning(__func__, "Arc lamps must be switched off") ; 01169 cpl_propertylist_delete(mh1); 01170 cpl_propertylist_delete(main_header); 01171 return 0 ; 01172 } 01173 cpl_propertylist_delete(main_header); 01174 01175 /* Get next FLAT_OFF frame */ 01176 frame = kmo_dfs_get_frame(frameset, NULL); 01177 } 01178 01179 /* Loop through FLAT_ON frames */ 01180 frame = kmo_dfs_get_frame(frameset, FLAT_ON); 01181 while (frame != NULL) { 01182 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 01183 01184 if (cpl_propertylist_get_int(main_header, NDIT) != ndit) { 01185 cpl_msg_warning(__func__, "NDIT inconsistent") ; 01186 cpl_propertylist_delete(mh1); 01187 cpl_propertylist_delete(main_header); 01188 return 0 ; 01189 } 01190 if (cpl_propertylist_get_double(main_header, EXPTIME) != exptime) { 01191 cpl_msg_warning(__func__, "EXPTIME inconsistent") ; 01192 cpl_propertylist_delete(mh1); 01193 cpl_propertylist_delete(main_header); 01194 return 0 ; 01195 } 01196 if (strcmp(cpl_propertylist_get_string(main_header, READMODE), 01197 readmode) != 0) { 01198 cpl_msg_warning(__func__, "READMODE inconsistent") ; 01199 cpl_propertylist_delete(mh1); 01200 cpl_propertylist_delete(main_header); 01201 return 0 ; 01202 } 01203 01204 /* Assure that arc lamps are off */ 01205 if ((kmo_check_lamp(main_header, INS_LAMP1_ST) != FALSE) 01206 || (kmo_check_lamp(main_header, INS_LAMP2_ST) != FALSE)) { 01207 cpl_msg_warning(__func__, "Arc lamps must be switched off") ; 01208 cpl_propertylist_delete(mh1); 01209 cpl_propertylist_delete(main_header); 01210 return 0 ; 01211 } 01212 01213 /* Assure that at least one flat lamp is on */ 01214 if ((kmo_check_lamp(main_header, INS_LAMP3_ST) != TRUE) 01215 && (kmo_check_lamp(main_header, INS_LAMP4_ST) != TRUE)) { 01216 cpl_msg_warning(__func__, "At least one flat lamps must be on") ; 01217 cpl_propertylist_delete(mh1); 01218 cpl_propertylist_delete(main_header); 01219 return 0 ; 01220 } 01221 01222 /* Get next FLAT_ON frame */ 01223 frame = kmo_dfs_get_frame(frameset, NULL); 01224 01225 cpl_propertylist_delete(main_header); 01226 } 01227 cpl_msg_info(__func__, "EXPTIME: %g seconds", exptime); 01228 cpl_msg_info(__func__, "NDIT: %d", ndit); 01229 cpl_msg_info(__func__, "Detector readout mode: %s", readmode); 01230 cpl_propertylist_delete(mh1); 01231 01232 /* Check Filters consistency */ 01233 if (kmo_check_frameset_setup(frameset, FLAT_ON, TRUE, FALSE, FALSE) != 01234 CPL_ERROR_NONE) { 01235 cpl_msg_warning(__func__, "Filters are not consistent") ; 01236 return 0 ; 01237 } 01238 01239 /* Return */ 01240 *nx = naxis1 ; 01241 *ny = naxis2 ; 01242 *next = n_ext ; 01243 *exptime_on = exptime ; 01244 return 1 ; 01245 } 01246