|
KMOS Pipeline Reference Manual
1.3.4
|
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 ; 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 00670 if (fabs(mean_noise) < 1e-3) { 00671 cpl_image_save(combined_noise_on, "noise.fits", 00672 CPL_TYPE_FLOAT, NULL, CPL_IO_CREATE); 00673 cpl_msg_error(__func__, "Division by 0.0") ; 00674 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00675 cpl_free(angles_array) ; 00676 return -1 ; 00677 } 00678 stored_qc_flat_sn[sx] = mean_data / mean_noise; 00679 00680 /* Normalize data & noise on the whole detector frame */ 00681 /* The spectral slope on each slitlet has already been */ 00682 /* normalised in kmo_calc_curvature() */ 00683 cpl_image_divide_scalar(combined_data_on, mean_data); 00684 cpl_image_divide_scalar(combined_noise_on, mean_data); 00685 00686 /* Apply the badpixel mask to the produced frames */ 00687 cpl_image_multiply(combined_data_on, bad_pix_mask_flat); 00688 cpl_image_multiply(combined_noise_on, bad_pix_mask_flat); 00689 cpl_image_multiply(xcal, bad_pix_mask_flat) ; 00690 cpl_image_multiply(ycal, bad_pix_mask_flat) ; 00691 00692 /* Store temporarily flat, badpixel and calibration */ 00693 stored_xcal[sx] = xcal; 00694 stored_ycal[sx] = ycal; 00695 00696 /* Save immediate results, free memory */ 00697 kmclipm_image_save(combined_data_on, fn_flat, CPL_TYPE_FLOAT, 00698 NULL, save_mode, 0./0.); 00699 kmclipm_image_save(combined_noise_on, fn_noise, CPL_TYPE_FLOAT, 00700 NULL, save_mode, 0./0.); 00701 kmclipm_image_save(bad_pix_mask_flat, fn_badpix, CPL_TYPE_FLOAT, 00702 NULL, save_mode, 0./0.); 00703 /* Next saves will create extensions */ 00704 save_mode = CPL_IO_EXTEND; 00705 00706 } else if (spec_found[sx] == CPL_ERROR_DATA_NOT_FOUND) { 00707 /* All IFUs seem to be deativated */ 00708 cpl_msg_warning(__func__, "All IFUs deactivated") ; 00709 cpl_error_reset(); 00710 00711 /* Save immediate results, free memory */ 00712 cpl_image_save(NULL, fn_flat, CPL_TYPE_FLOAT, NULL, save_mode); 00713 cpl_image_save(NULL, fn_noise, CPL_TYPE_FLOAT, NULL, save_mode); 00714 cpl_image_save(NULL, fn_badpix, CPL_TYPE_FLOAT, NULL,save_mode); 00715 /* Next saves will create extensions */ 00716 save_mode = CPL_IO_EXTEND; 00717 00718 stored_xcal[sx] = NULL ; 00719 stored_ycal[sx] = NULL ; 00720 } else { 00721 // another error occured 00722 cpl_msg_error(__func__, "Unknown ERROR !") ; 00723 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00724 cpl_image_delete(combined_data_on); 00725 cpl_image_delete(combined_noise_on); 00726 cpl_image_delete(bad_pix_mask_flat); 00727 cpl_free(angles_array) ; 00728 cpl_msg_indent_less() ; 00729 cpl_msg_indent_less() ; 00730 return -1 ; 00731 } 00732 cpl_image_delete(combined_data_on); 00733 cpl_image_delete(combined_noise_on); 00734 cpl_image_delete(bad_pix_mask_flat); 00735 00736 cpl_msg_indent_less() ; 00737 } // for i = 1; i <= ne 00738 cpl_frameset_delete(angle_frameset); 00739 cpl_msg_indent_less() ; 00740 } // for a = 0; a < nb_angles 00741 00742 /* Clean OFF frames */ 00743 for (i = 1; i <= ne; i++) { 00744 /* Compute only one detector */ 00745 if (reduce_det != 0 && i != reduce_det) continue ; 00746 00747 cpl_image_delete(combined_data_off[i-1]) ; 00748 cpl_image_delete(combined_noise_off[i-1]) ; 00749 cpl_image_delete(bad_pix_mask_dark[i-1]); 00750 } 00751 00752 /* ----- QC parameters & saving */ 00753 /* ---- load, update & save primary header */ 00754 main_header = kmo_dfs_load_primary_header(frameset, FLAT_ON); 00755 00756 /* Update which IFUs are not used */ 00757 kmo_print_unused_ifus(unused_ifus_after, TRUE); 00758 kmo_set_unused_ifus(unused_ifus_after, main_header, "kmos_flat"); 00759 kmo_free_unused_ifus(unused_ifus_after); 00760 00761 /* xcal gets additionally the boundaries of the IFUs for reconstruction */ 00762 main_header_xcal=kmos_create_bounds_properties(stored_ycal, ne, nb_angles) ; 00763 00764 /* --------- saving headers */ 00765 if (!suppress_extension) fn_suffix = cpl_sprintf("%s", suffix); 00766 else fn_suffix = cpl_sprintf("%s", ""); 00767 cpl_free(suffix); 00768 00769 cpl_msg_info(__func__, "Saving data..."); 00770 00771 frame = kmo_dfs_get_frame(frameset, FLAT_ON); 00772 kmo_dfs_save_main_header(frameset, MASTER_FLAT, fn_suffix, frame, 00773 main_header, parlist, cpl_func); 00774 kmo_dfs_save_main_header(frameset, XCAL, fn_suffix, frame, 00775 main_header_xcal, parlist, cpl_func); 00776 kmo_dfs_save_main_header(frameset, YCAL, fn_suffix, frame, 00777 main_header, parlist, cpl_func); 00778 kmo_dfs_save_main_header(frameset, BADPIXEL_FLAT, fn_suffix, frame, 00779 main_header, parlist, cpl_func); 00780 kmo_dfs_save_main_header(frameset, FLAT_EDGE, fn_suffix, frame, 00781 main_header, parlist, cpl_func); 00782 00783 cpl_propertylist_delete(main_header); 00784 cpl_propertylist_delete(main_header_xcal); 00785 00786 /* -------- saving sub frames */ 00787 for (a = 0; a < nb_angles; a++) { 00788 for (i = 1; i <= ne; i++) { 00789 sx = a * ne + (i - 1); 00790 00791 // load stored data again 00792 stored_flat[sx]=kmclipm_image_load(fn_flat, CPL_TYPE_FLOAT, 0, sx); 00793 cpl_error_reset() ; 00794 stored_noise[sx]=kmclipm_image_load(fn_noise, CPL_TYPE_FLOAT, 0,sx); 00795 cpl_error_reset() ; 00796 stored_badpix[sx]=kmclipm_image_load(fn_badpix,CPL_TYPE_FLOAT,0,sx); 00797 cpl_error_reset() ; 00798 00799 sub_header = kmo_dfs_load_sub_header(frameset, FLAT_ON, i, FALSE); 00800 kmclipm_update_property_double(sub_header,CAL_ROTANGLE, 00801 ((double) angles_array[a]), 00802 "[deg] Rotator relative to nasmyth"); 00803 00804 if (spec_found[sx] == CPL_ERROR_NONE) { 00805 kmclipm_update_property_int(sub_header, QC_FLAT_SAT, 00806 stored_qc_flat_sat[sx], 00807 "[] nr. saturated pixels of master flat"); 00808 /* Load gain */ 00809 gain = kmo_dfs_get_property_double(sub_header, GAIN); 00810 00811 kmclipm_update_property_double(sub_header, QC_FLAT_EFF, 00812 stored_qc_flat_eff[sx]/gain, 00813 "[e-/s] rel. brightness of flat lamp"); 00814 kmclipm_update_property_double(sub_header, QC_FLAT_SN, 00815 stored_qc_flat_sn[sx], "[] S/N of master flat"); 00816 } 00817 00818 /* Store qc parameters only if any slitlet- and gap-width */ 00819 /* has been detected (should be the case when at least */ 00820 /* one IFU is active) */ 00821 if (stored_xcal[sx] != NULL) { 00822 kmclipm_update_property_double(sub_header, QC_GAP_MEAN, 00823 stored_gapmean[sx], 00824 "[pix] mean gap width between slitlets"); 00825 kmclipm_update_property_double(sub_header, QC_GAP_SDV, 00826 stored_gapsdv[sx], 00827 "[pix] stdev of gap width between slitlets"); 00828 kmclipm_update_property_double(sub_header, QC_GAP_MAXDEV, 00829 stored_gapmaxdev[sx], 00830 "[pix] max gap deviation between slitlets"); 00831 kmclipm_update_property_double(sub_header, QC_SLIT_MEAN, 00832 stored_slitmean[sx], "[pix] mean slitlet width"); 00833 kmclipm_update_property_double(sub_header, QC_SLIT_SDV, 00834 stored_slitsdv[sx], "[pix] stdev of slitlet widths"); 00835 kmclipm_update_property_double(sub_header, QC_SLIT_MAXDEV, 00836 stored_slitmaxdev[sx], 00837 "[pix] max slitlet width deviation"); 00838 } 00839 00840 00841 /* Calculate QC.BADPIX.NCOUNT */ 00842 /* Remove 4pixel-border as bad pixels */ 00843 nr_bad_pix = 0 ; 00844 if (stored_badpix[sx] != NULL) { 00845 nr_bad_pix = cpl_image_count_rejected(stored_badpix[sx]); 00846 nr_bad_pix -= 2*KMOS_BADPIX_BORDER*(nx-2*KMOS_BADPIX_BORDER) + 00847 2*KMOS_BADPIX_BORDER*ny; 00848 } 00849 00850 kmclipm_update_property_int(sub_header, QC_NR_BAD_PIX, nr_bad_pix, 00851 "[] nr. of bad pixels"); 00852 00853 /* Save flat frame */ 00854 extname = kmo_extname_creator(detector_frame, i, EXT_DATA); 00855 kmclipm_update_property_string(sub_header, EXTNAME,extname, 00856 "FITS extension name"); 00857 cpl_free(extname); 00858 00859 kmclipm_update_property_int(sub_header, EXTVER, sx+1, 00860 "FITS extension ver"); 00861 00862 kmo_dfs_save_image(stored_flat[sx], MASTER_FLAT, fn_suffix, 00863 sub_header, 0./0.); 00864 00865 /* Save noise frame when enough input frames were available */ 00866 extname = kmo_extname_creator(detector_frame, i, EXT_NOISE); 00867 kmclipm_update_property_string(sub_header, EXTNAME,extname, 00868 "FITS extension name"); 00869 cpl_free(extname); 00870 00871 kmo_dfs_save_image(stored_noise[sx], MASTER_FLAT, fn_suffix, 00872 sub_header, 0./0.); 00873 00874 /* Save bad_pix frame */ 00875 extname = kmo_extname_creator(detector_frame, i, EXT_BADPIX); 00876 kmclipm_update_property_string(sub_header, EXTNAME,extname, 00877 "FITS extension name"); 00878 cpl_free(extname); 00879 00880 kmo_dfs_save_image(stored_badpix[sx], BADPIXEL_FLAT, fn_suffix, 00881 sub_header, 0.); 00882 00883 // save xcal and ycal-frame 00884 extname = kmo_extname_creator(detector_frame, i, EXT_DATA); 00885 kmclipm_update_property_string(sub_header, EXTNAME, extname, 00886 "FITS extension name"); 00887 cpl_free(extname); 00888 00889 kmo_dfs_save_image(stored_xcal[sx], XCAL, fn_suffix, sub_header, 00890 0./0.); 00891 kmo_dfs_save_image(stored_ycal[sx], YCAL, fn_suffix, sub_header, 00892 0./0.); 00893 00894 /* Save edge_pars-frame */ 00895 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00896 extname = cpl_sprintf("%s_IFU.%d_ANGLE.%d", EXT_LIST, 00897 j+1+(i-1)*KMOS_IFUS_PER_DETECTOR, angles_array[a]); 00898 kmclipm_update_property_string(sub_header, EXTNAME, extname, 00899 "FITS extension name"); 00900 cpl_free(extname); 00901 00902 kmclipm_update_property_int(sub_header, CAL_IFU_NR, 00903 j+1+(i-1)*KMOS_IFUS_PER_DETECTOR, "IFU Number {1..24}"); 00904 00905 /* Save edge-parameters as product */ 00906 if ((spec_found[sx] != CPL_ERROR_DATA_NOT_FOUND) && 00907 (edge_table[sx] != NULL)&&(edge_table[sx][j] != NULL)) { 00908 kmo_dfs_save_table(edge_table[sx][j], FLAT_EDGE, 00909 fn_suffix, sub_header); 00910 } else { 00911 cpl_propertylist_erase(sub_header, CRVAL1); 00912 cpl_propertylist_erase(sub_header, CRVAL2); 00913 cpl_propertylist_erase(sub_header, CD1_1); 00914 cpl_propertylist_erase(sub_header, CD1_2); 00915 cpl_propertylist_erase(sub_header, CD2_1); 00916 cpl_propertylist_erase(sub_header, CD2_2); 00917 cpl_propertylist_erase(sub_header, CRPIX1); 00918 cpl_propertylist_erase(sub_header, CRPIX2); 00919 cpl_propertylist_erase(sub_header, CTYPE1); 00920 cpl_propertylist_erase(sub_header, CTYPE2); 00921 00922 kmo_dfs_save_table(NULL, FLAT_EDGE, fn_suffix, 00923 sub_header); 00924 } 00925 } 00926 cpl_propertylist_delete(sub_header); 00927 00928 cpl_image_delete(stored_flat[sx]); 00929 cpl_image_delete(stored_noise[sx]); 00930 cpl_image_delete(stored_badpix[sx]); 00931 } // for (i = ne) 00932 } // for (a = nb_angles) 00933 00934 // delete temporary files 00935 unlink(fn_flat); 00936 unlink(fn_noise); 00937 unlink(fn_badpix); 00938 00939 cpl_free(stored_qc_flat_sat); 00940 cpl_free(stored_qc_flat_eff); 00941 cpl_free(stored_qc_flat_sn); 00942 cpl_free(stored_gapmean); 00943 cpl_free(stored_gapsdv); 00944 cpl_free(stored_gapmaxdev); 00945 cpl_free(stored_slitmean); 00946 cpl_free(stored_slitsdv); 00947 cpl_free(stored_slitmaxdev); 00948 cpl_free(fn_suffix); 00949 cpl_free(stored_flat); 00950 cpl_free(stored_noise); 00951 cpl_free(stored_badpix); 00952 for (i = 0; i < ne * nb_angles; i++) { 00953 cpl_image_delete(stored_xcal[i]); 00954 cpl_image_delete(stored_ycal[i]); 00955 } 00956 cpl_free(stored_xcal); 00957 cpl_free(stored_ycal); 00958 if (edge_table != NULL) { 00959 for (i = 0; i < ne * nb_angles; i++) { 00960 if (edge_table[i] != NULL) { 00961 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00962 cpl_table_delete(edge_table[i][j]); 00963 } 00964 cpl_free(edge_table[i]); 00965 } 00966 } 00967 cpl_free(edge_table); 00968 } 00969 cpl_free(spec_found); 00970 cpl_free(angles_array) ; 00971 00972 return 0; 00973 } 00974 00977 /*----------------------------------------------------------------------------*/ 00987 /*----------------------------------------------------------------------------*/ 00988 static cpl_propertylist * kmos_create_bounds_properties( 00989 cpl_image ** stored_ycal, 00990 int ne, 00991 int nb_angles) 00992 { 00993 cpl_propertylist * bounds_props ; 00994 int * bounds ; 00995 int ** total_bounds ; 00996 char * tmpstr ; 00997 int a, i, j, sx ; 00998 00999 /* Check Entries */ 01000 if (stored_ycal == NULL) return NULL ; 01001 01002 /* Add here boundaries for reconstruction */ 01003 bounds_props = cpl_propertylist_new(); 01004 01005 /* Initialize total_bounds */ 01006 total_bounds = (int**)cpl_malloc(ne*sizeof(int*)); 01007 for (i = 0; i < ne; i++) { 01008 total_bounds[i]=(int*)cpl_calloc(2*KMOS_IFUS_PER_DETECTOR,sizeof(int)); 01009 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01010 total_bounds[i][2*j] = 2048; 01011 total_bounds[i][2*j+1] = 0; 01012 } 01013 } 01014 01015 /* Store the min left bound and max right bound for all angles */ 01016 for (a = 0; a < nb_angles; a++) { 01017 for (i = 0; i < ne; i++) { 01018 sx = a * ne + i; 01019 if (stored_ycal[sx] != NULL) { 01020 bounds = kmo_split_frame(stored_ycal[sx]); 01021 01022 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01023 if ((total_bounds[i][2*j] == -1)||(bounds[2*j] == -1)) { 01024 total_bounds[i][2*j] = -1; 01025 } else { 01026 if (total_bounds[i][2*j] > bounds[2*j]) { 01027 total_bounds[i][2*j] = bounds[2*j]; 01028 } 01029 } 01030 01031 if ((total_bounds[i][2*j+1] == -1) || 01032 (bounds[2*j+1] == -1)) { 01033 total_bounds[i][2*j+1] = -1; 01034 } else { 01035 if (total_bounds[i][2*j+1] < bounds[2*j+1]) { 01036 total_bounds[i][2*j+1] = bounds[2*j+1]; 01037 } 01038 } 01039 } 01040 cpl_free(bounds); 01041 } else { 01042 // whole detector inactive 01043 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01044 total_bounds[i][2*j] = -1; 01045 total_bounds[i][2*j+1] = -1; 01046 } 01047 } 01048 } // for (ne) 01049 } // for (nb_angles) 01050 01051 /* Write the min left bound and max right bound for all angles */ 01052 /* into the main header */ 01053 for (i = 0; i < ne; i++) { 01054 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 01055 if (total_bounds[i][2*j] > -1) { 01056 tmpstr= cpl_sprintf("%s%d%s", BOUNDS_PREFIX, 01057 i*KMOS_IFUS_PER_DETECTOR + j+1, "_L"); 01058 kmclipm_update_property_int(bounds_props, tmpstr, 01059 total_bounds[i][2*j], 01060 "[pix] left boundary for reconstr."); 01061 cpl_free(tmpstr); 01062 } 01063 01064 if (total_bounds[i][2*j+1] > -1) { 01065 tmpstr= cpl_sprintf("%s%d%s", BOUNDS_PREFIX, 01066 i*KMOS_IFUS_PER_DETECTOR + j+1, "_R"); 01067 kmclipm_update_property_int(bounds_props,tmpstr, 01068 total_bounds[i][2*j+1], 01069 "[pix] right boundary for reconstr."); 01070 cpl_free(tmpstr); 01071 } 01072 } 01073 } // for (ne) 01074 for (i = 0; i < ne; i++) cpl_free(total_bounds[i]); 01075 cpl_free(total_bounds); 01076 01077 return bounds_props ; 01078 } 01079 01080 /*----------------------------------------------------------------------------*/ 01090 /*----------------------------------------------------------------------------*/ 01091 static int kmos_flat_check_inputs( 01092 cpl_frameset * frameset, 01093 int * nx, 01094 int * ny, 01095 int * ne, 01096 double * exptime_on) 01097 { 01098 cpl_frame * frame ; 01099 cpl_propertylist * eh ; 01100 cpl_propertylist * mh1 ; 01101 cpl_propertylist * main_header ; 01102 int ndit ; 01103 double exptime ; 01104 const char * readmode ; 01105 int naxis1, naxis2, next ; 01106 01107 /* TODO Add frames dimensions checks TODO */ 01108 01109 /* Check Entries */ 01110 if (nx == NULL || ny == NULL || frameset == NULL || exptime_on == NULL) 01111 return -1; 01112 01113 /* check BADPIXEL_DARK */ 01114 frame = kmo_dfs_get_frame(frameset, BADPIXEL_DARK); 01115 if (frame == NULL) { 01116 cpl_msg_warning(__func__, "BADPIXEL_DARK frame is missing") ; 01117 return 0 ; 01118 } 01119 next = cpl_frame_get_nextensions(frame); 01120 if (next != KMOS_NR_DETECTORS) { 01121 cpl_msg_warning(__func__, "BADPIXEL_DARK must have 3 extensions") ; 01122 return 0 ; 01123 } 01124 eh = cpl_propertylist_load(cpl_frame_get_filename(frame), 1); 01125 naxis1 = kmos_pfits_get_naxis1(eh) ; 01126 naxis2 = kmos_pfits_get_naxis2(eh) ; 01127 cpl_propertylist_delete(eh) ; 01128 01129 /* check FLAT_OFF */ 01130 frame = kmo_dfs_get_frame(frameset, FLAT_OFF); 01131 mh1 = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 01132 ndit = cpl_propertylist_get_int(mh1, NDIT); 01133 exptime = cpl_propertylist_get_double(mh1, EXPTIME); 01134 readmode = cpl_propertylist_get_string(mh1, READMODE); 01135 01136 /* Loop through FLAT_OFF frames */ 01137 while (frame != NULL) { 01138 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 01139 01140 if (cpl_propertylist_get_int(main_header, NDIT) != ndit) { 01141 cpl_msg_warning(__func__, "NDIT inconsistent") ; 01142 cpl_propertylist_delete(mh1); 01143 cpl_propertylist_delete(main_header); 01144 return 0 ; 01145 } 01146 if (cpl_propertylist_get_double(main_header, EXPTIME) != exptime) { 01147 cpl_msg_warning(__func__, "EXPTIME inconsistent") ; 01148 cpl_propertylist_delete(mh1); 01149 cpl_propertylist_delete(main_header); 01150 return 0 ; 01151 } 01152 if (strcmp(cpl_propertylist_get_string(main_header, READMODE), 01153 readmode) != 0) { 01154 cpl_msg_warning(__func__, "READMODE inconsistent") ; 01155 cpl_propertylist_delete(mh1); 01156 cpl_propertylist_delete(main_header); 01157 return 0 ; 01158 } 01159 01160 /* Assure that arc lamps are off */ 01161 if ((kmo_check_lamp(main_header, INS_LAMP1_ST) != FALSE) 01162 || (kmo_check_lamp(main_header, INS_LAMP2_ST) != FALSE)) { 01163 cpl_msg_warning(__func__, "Arc lamps must be switched off") ; 01164 cpl_propertylist_delete(mh1); 01165 cpl_propertylist_delete(main_header); 01166 return 0 ; 01167 } 01168 cpl_propertylist_delete(main_header); 01169 01170 /* Get next FLAT_OFF frame */ 01171 frame = kmo_dfs_get_frame(frameset, NULL); 01172 } 01173 01174 /* Loop through FLAT_ON frames */ 01175 frame = kmo_dfs_get_frame(frameset, FLAT_ON); 01176 while (frame != NULL) { 01177 main_header = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 01178 01179 if (cpl_propertylist_get_int(main_header, NDIT) != ndit) { 01180 cpl_msg_warning(__func__, "NDIT inconsistent") ; 01181 cpl_propertylist_delete(mh1); 01182 cpl_propertylist_delete(main_header); 01183 return 0 ; 01184 } 01185 if (cpl_propertylist_get_double(main_header, EXPTIME) != exptime) { 01186 cpl_msg_warning(__func__, "EXPTIME inconsistent") ; 01187 cpl_propertylist_delete(mh1); 01188 cpl_propertylist_delete(main_header); 01189 return 0 ; 01190 } 01191 if (strcmp(cpl_propertylist_get_string(main_header, READMODE), 01192 readmode) != 0) { 01193 cpl_msg_warning(__func__, "READMODE inconsistent") ; 01194 cpl_propertylist_delete(mh1); 01195 cpl_propertylist_delete(main_header); 01196 return 0 ; 01197 } 01198 01199 /* Assure that arc lamps are off */ 01200 if ((kmo_check_lamp(main_header, INS_LAMP1_ST) != FALSE) 01201 || (kmo_check_lamp(main_header, INS_LAMP2_ST) != FALSE)) { 01202 cpl_msg_warning(__func__, "Arc lamps must be switched off") ; 01203 cpl_propertylist_delete(mh1); 01204 cpl_propertylist_delete(main_header); 01205 return 0 ; 01206 } 01207 01208 /* Assure that at least one flat lamp is on */ 01209 if ((kmo_check_lamp(main_header, INS_LAMP3_ST) != TRUE) 01210 && (kmo_check_lamp(main_header, INS_LAMP4_ST) != TRUE)) { 01211 cpl_msg_warning(__func__, "At least one flat lamps must be on") ; 01212 cpl_propertylist_delete(mh1); 01213 cpl_propertylist_delete(main_header); 01214 return 0 ; 01215 } 01216 01217 /* Get next FLAT_ON frame */ 01218 frame = kmo_dfs_get_frame(frameset, NULL); 01219 01220 cpl_propertylist_delete(main_header); 01221 } 01222 cpl_msg_info(__func__, "EXPTIME: %g seconds", exptime); 01223 cpl_msg_info(__func__, "NDIT: %d", ndit); 01224 cpl_msg_info(__func__, "Detector readout mode: %s", readmode); 01225 cpl_propertylist_delete(mh1); 01226 01227 /* Check Filters consistency */ 01228 if (kmo_check_frameset_setup(frameset, FLAT_ON, TRUE, FALSE, FALSE) != 01229 CPL_ERROR_NONE) { 01230 cpl_msg_warning(__func__, "Filters are not consistent") ; 01231 return 0 ; 01232 } 01233 01234 /* Return */ 01235 *nx = naxis1 ; 01236 *ny = naxis2 ; 01237 *ne = next ; 01238 *exptime_on = exptime ; 01239 return 1 ; 01240 } 01241
1.7.6.1