|
KMOS Pipeline Reference Manual
1.3.10
|
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 #ifdef __USE_XOPEN2K 00032 #include <stdlib.h> 00033 #define GGG 00034 #else 00035 #define __USE_XOPEN2K /* to get the definition for setenv in stdlib.h */ 00036 #include <stdlib.h> 00037 #undef __USE_XOPEN2K 00038 #endif 00039 00040 #include <cpl.h> 00041 00042 #include "kmo_utils.h" 00043 #include "kmos_pfits.h" 00044 #include "kmo_functions.h" 00045 #include "kmo_priv_wave_cal.h" 00046 #include "kmo_priv_functions.h" 00047 #include "kmo_cpl_extensions.h" 00048 #include "kmo_dfs.h" 00049 #include "kmo_error.h" 00050 #include "kmo_constants.h" 00051 #include "kmo_debug.h" 00052 00053 /*----------------------------------------------------------------------------- 00054 * Functions prototypes 00055 *----------------------------------------------------------------------------*/ 00056 00057 static int kmos_wave_cal_check_inputs(cpl_frameset *, int *, int *, int *, 00058 double *, int *, lampConfiguration *); 00059 00060 static int kmos_wave_cal_create(cpl_plugin *); 00061 static int kmos_wave_cal_exec(cpl_plugin *); 00062 static int kmos_wave_cal_destroy(cpl_plugin *); 00063 static int kmos_wave_cal(cpl_parameterlist *, cpl_frameset *); 00064 00065 /*----------------------------------------------------------------------------- 00066 * Static variables 00067 *----------------------------------------------------------------------------*/ 00068 00069 static char kmos_wave_cal_description[] = 00070 "This recipe creates the wavelength calibration frame needed for all three\n" 00071 "detectors. It must be called after the kmo_flat recipe, which generates the\n" 00072 "two spatial calibration frames needed in this recipe. As input a lamp-on \n" 00073 "frame, a lamp-off frame, the spatial calibration frames and the list with \n" 00074 "the reference arclines are required.\n" 00075 "An additional output frame is the resampled image of the reconstructed arc\n" 00076 "frame. All slitlets of all IFUs are aligned one next to the other. This \n" 00077 "frame serves for quality control. One can immediately see if the \n" 00078 "calibration was successful.\n" 00079 "The lists of reference arclines are supposed to contain the lines for both\n" 00080 "available calibration arc-lamps, i.e. Argon and Neon. The list is supposed\n" 00081 "to be a F2L KMOS FITS file with three columns:\n" 00082 "\t1. Reference wavelength\n" 00083 "\t2. Relative strength\n" 00084 "\t3. String either containing “Ar” or “Ne”\n" 00085 "The recipe extracts, based on the header keywords, either the applying\n" 00086 "argon and/or neon emission lines. Below are the plots of the emission lines\n" 00087 "for both argon and neon. The marked lines are the ones used for wavelength \n" 00088 "calibration.\n" 00089 "\n" 00090 "Furthermore frames can be provided for several rotator angles. In this case\n" 00091 "the resulting calibration frames for each detector are repeatedly saved as \n" 00092 "extension for every angle.\n" 00093 "\n" 00094 "BASIC PARAMETERS:\n" 00095 "-----------------\n" 00096 "--order\n" 00097 "The polynomial order to use for the fit of the wavelength solution.\n" 00098 "0: (default) The appropriate order is choosen automatically depending on\n" 00099 "the waveband (4 for IZ band, 5 for HK, 6 for the others)\n" 00100 "\n" 00101 "ADVANCED PARAMETERS\n" 00102 "-------------------\n" 00103 "--b_samples\n" 00104 "The number of samples in spectral direction for the reconstructed cube.\n" 00105 "Ideally this number should be greater than 2048, the detector size.\n" 00106 "\n" 00107 "--b_start\n" 00108 "--b_end\n" 00109 "Used to define manually the start and end wavelength for the reconstructed\n" 00110 "cube. By default the internally defined values are used.\n" 00111 "\n" 00112 "--suppress_extension\n" 00113 "If set to TRUE, the arbitrary filename extensions are supressed. If\n" 00114 "multiple products with the same category are produced, they will be numered\n" 00115 "consecutively starting from 0.\n" 00116 "\n" 00117 "--lines_estimation\n" 00118 "If set to TRUE, the lines estimation method is used\n" 00119 "\n" 00120 "----------------------------------------------------------------------------\n" 00121 "Input files:\n" 00122 "\n" 00123 " DO category Type Explanation Required #Frames\n" 00124 " ----------- ----- ----------- -------- -------\n" 00125 " ARC_ON RAW Arclamp-on exposure Y >=1\n" 00126 " ARC_OFF RAW Arclamp-off exposure Y 1\n" 00127 " XCAL F2D x calibration frame Y 1\n" 00128 " YCAL F2D y calibration frame Y 1\n" 00129 " ARC_LIST F2L List of arclines Y 1\n" 00130 " FLAT_EDGE F2L Fitted edge parameters Y 1\n" 00131 " REF_LINES F2L Reference line table Y 1\n" 00132 " WAVE_BAND F2L Table with start-/end-wavelengths Y 1\n" 00133 "\n" 00134 "Output files:\n" 00135 "\n" 00136 " DO category Type Explanation\n" 00137 " ----------- ----- -----------\n" 00138 " LCAL F2D Wavelength calibration frame\n" 00139 " (3 Extensions)\n" 00140 " DET_IMG_WAVE F2D reconstructed arclamp-on exposure\n" 00141 " (4 extensions: 3 detector images + \n" 00142 " the arclines list table)\n" 00143 "----------------------------------------------------------------------------\n" 00144 "\n"; 00145 00146 /*----------------------------------------------------------------------------- 00147 * Functions code 00148 *----------------------------------------------------------------------------*/ 00149 00156 /*----------------------------------------------------------------------------*/ 00165 /*----------------------------------------------------------------------------*/ 00166 int cpl_plugin_get_info(cpl_pluginlist *list) 00167 { 00168 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe); 00169 cpl_plugin *plugin = &recipe->interface; 00170 00171 cpl_plugin_init(plugin, 00172 CPL_PLUGIN_API, 00173 KMOS_BINARY_VERSION, 00174 CPL_PLUGIN_TYPE_RECIPE, 00175 "kmos_wave_cal", 00176 "Create a wavelength calibration frame", 00177 kmos_wave_cal_description, 00178 "Alex Agudo Berbel, Yves Jung", 00179 "usd-help@eso.org", 00180 kmos_get_license(), 00181 kmos_wave_cal_create, 00182 kmos_wave_cal_exec, 00183 kmos_wave_cal_destroy); 00184 cpl_pluginlist_append(list, plugin); 00185 00186 return 0; 00187 } 00188 00189 /*----------------------------------------------------------------------------*/ 00197 /*----------------------------------------------------------------------------*/ 00198 static int kmos_wave_cal_create(cpl_plugin *plugin) 00199 { 00200 cpl_recipe *recipe; 00201 cpl_parameter *p; 00202 00203 // Check that the plugin is part of a valid recipe 00204 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00205 recipe = (cpl_recipe *)plugin; 00206 else 00207 return -1; 00208 00209 // Create the parameters list in the cpl_recipe object 00210 recipe->parameters = cpl_parameterlist_new(); 00211 00212 // Fill the parameters list 00213 p = cpl_parameter_new_value("kmos.kmos_wave_cal.order", CPL_TYPE_INT, 00214 "The fitting polynomial order used for the wavelength solution. " 00215 "By default, 4 for IZ band, 5 for HK, 6 for the others", 00216 "kmos.kmos_wave_cal", 0); 00217 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "order"); 00218 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00219 cpl_parameterlist_append(recipe->parameters, p); 00220 00221 /* --suppress_extension */ 00222 p = cpl_parameter_new_value("kmos.kmos_wave_cal.suppress_extension", 00223 CPL_TYPE_BOOL, "Suppress arbitrary filename extension", 00224 "kmos.kmos_wave_cal", FALSE); 00225 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension"); 00226 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00227 cpl_parameterlist_append(recipe->parameters, p); 00228 00229 /* --lines_estimation */ 00230 p = cpl_parameter_new_value("kmos.kmos_wave_cal.lines_estimation", 00231 CPL_TYPE_BOOL, "Trigger lines estimation method", 00232 "kmos.kmos_wave_cal", FALSE); 00233 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lines_estimation"); 00234 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00235 cpl_parameterlist_append(recipe->parameters, p); 00236 00237 /* Add parameters for band-definition */ 00238 kmos_band_pars_create(recipe->parameters, "kmos.kmos_wave_cal"); 00239 00240 /* --detector */ 00241 p = cpl_parameter_new_value("kmos.kmos_wave_cal.detector", 00242 CPL_TYPE_INT, "Only reduce the specified detector", 00243 "kmos.kmos_wave_cal", 0); 00244 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "det"); 00245 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00246 cpl_parameterlist_append(recipe->parameters, p); 00247 00248 /* --angle */ 00249 p = cpl_parameter_new_value("kmos.kmos_wave_cal.angle", 00250 CPL_TYPE_DOUBLE, "Only reduce the specified angle", 00251 "kmos.kmos_wave_cal", 370.0); 00252 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "angle"); 00253 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00254 cpl_parameterlist_append(recipe->parameters, p); 00255 00256 return 0; 00257 } 00258 00259 /*----------------------------------------------------------------------------*/ 00265 /*----------------------------------------------------------------------------*/ 00266 static int kmos_wave_cal_exec(cpl_plugin *plugin) 00267 { 00268 cpl_recipe *recipe; 00269 00270 // Get the recipe out of the plugin 00271 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00272 recipe = (cpl_recipe *)plugin; 00273 else return -1; 00274 00275 return kmos_wave_cal(recipe->parameters, recipe->frames); 00276 } 00277 00278 /*----------------------------------------------------------------------------*/ 00284 /*----------------------------------------------------------------------------*/ 00285 static int kmos_wave_cal_destroy(cpl_plugin *plugin) 00286 { 00287 cpl_recipe *recipe; 00288 00289 // Get the recipe out of the plugin 00290 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00291 recipe = (cpl_recipe *)plugin; 00292 else return -1 ; 00293 00294 cpl_parameterlist_delete(recipe->parameters); 00295 return 0 ; 00296 } 00297 00298 /*----------------------------------------------------------------------------*/ 00312 /*----------------------------------------------------------------------------*/ 00313 static int kmos_wave_cal(cpl_parameterlist *parlist, cpl_frameset *frameset) 00314 { 00315 const cpl_parameter * par ; 00316 int suppress_extension, fit_order_par, fit_order ; 00317 int nx, ny, ne, reduce_det, lines_estimation ; 00318 double exptime, gain, angle_found, reduce_angle ; 00319 cpl_frame * frame ; 00320 cpl_propertylist * mh_on ; 00321 cpl_propertylist * plist ; 00322 char * suffix ; 00323 lampConfiguration lamp_config; 00324 char ** filter_ids ; 00325 int * angles_array ; 00326 int nb_angles ; 00327 int non_dest_rom ; 00328 00329 cpl_propertylist ** stored_sub_headers_lcal ; 00330 cpl_propertylist ** stored_sub_headers_det_img ; 00331 cpl_image ** stored_lcal ; 00332 cpl_image ** stored_det_img ; 00333 int * stored_qc_arc_sat ; 00334 double * stored_qc_ar_eff ; 00335 double * stored_qc_ne_eff ; 00336 cpl_table * detector_edges[KMOS_IFUS_PER_DETECTOR] ; 00337 00338 int a, i, j, x, y ; 00339 00340 cpl_image * det_lamp_on ; 00341 cpl_image * det_lamp_off ; 00342 cpl_image * det_lamp_on_copy ; 00343 00344 cpl_table * arclines ; 00345 cpl_table * reflines ; 00346 cpl_bivector * lines ; 00347 00348 cpl_image * bad_pix_mask ; 00349 float * pbad_pix_mask ; 00350 cpl_image * xcal ; 00351 cpl_image * ycal ; 00352 cpl_image * lcal ; 00353 00354 int nr_sat ; 00355 00356 cpl_propertylist * qc_header ; 00357 00358 cpl_array ** unused_ifus_before ; 00359 cpl_array ** unused_ifus_after ; 00360 char * extname ; 00361 char * fn_suffix ; 00362 char * last_env ; 00363 const char * tmp_str ; 00364 cpl_error_code err ; 00365 00366 /* Check entries */ 00367 if (parlist == NULL || frameset == NULL) { 00368 cpl_msg_error(__func__, "Null Inputs") ; 00369 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ; 00370 return -1 ; 00371 } 00372 00373 /* Get Parameters */ 00374 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_wave_cal.order"); 00375 fit_order_par = cpl_parameter_get_int(par); 00376 par=cpl_parameterlist_find_const(parlist, 00377 "kmos.kmos_wave_cal.lines_estimation"); 00378 lines_estimation = cpl_parameter_get_bool(par); 00379 par=cpl_parameterlist_find_const(parlist, 00380 "kmos.kmos_wave_cal.suppress_extension"); 00381 suppress_extension = cpl_parameter_get_bool(par); 00382 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_wave_cal.angle"); 00383 reduce_angle = cpl_parameter_get_double(par); 00384 par = cpl_parameterlist_find_const(parlist, "kmos.kmos_wave_cal.detector"); 00385 reduce_det = cpl_parameter_get_int(par); 00386 00387 kmos_band_pars_load(parlist, "kmos.kmos_wave_cal"); 00388 00389 /* Check Parameters */ 00390 if (fit_order_par < 0 || fit_order_par > 7) { 00391 cpl_msg_error(__func__, "Fitting Order must be in [0,7]") ; 00392 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00393 return -1 ; 00394 } 00395 if (reduce_det < 0 || reduce_det > 3) { 00396 cpl_msg_error(__func__, "detector must be in [1,3]") ; 00397 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00398 return -1 ; 00399 } 00400 00401 /* Identify the RAW and CALIB frames in the input frameset */ 00402 if (kmo_dfs_set_groups(frameset, "kmos_wave_cal") != 1) { 00403 cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ; 00404 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00405 return -1 ; 00406 } 00407 00408 /* Check the inputs consistency */ 00409 if (kmos_wave_cal_check_inputs(frameset, &nx, &ny, &ne, &exptime, 00410 &non_dest_rom, &lamp_config) != 1) { 00411 cpl_msg_error(__func__, "Input frameset is not consistent") ; 00412 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00413 return -1 ; 00414 } 00415 00416 /* Instrument setup */ 00417 suffix = kmo_dfs_get_suffix(kmo_dfs_get_frame(frameset, XCAL), TRUE, FALSE); 00418 cpl_msg_info(__func__, "Detected instrument setup: %s", suffix+1); 00419 00420 /* Check that filter and grating match for each detector */ 00421 /* filter/grating can be different for each detector */ 00422 frame = kmo_dfs_get_frame(frameset, ARC_ON); 00423 mh_on = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 00424 filter_ids = kmo_get_filter_setup(mh_on, ne, TRUE) ; 00425 cpl_propertylist_delete(mh_on); 00426 if (filter_ids == NULL) { 00427 cpl_free(suffix); 00428 cpl_msg_error(__func__, "Cannot get Filter informations") ; 00429 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00430 return -1 ; 00431 } 00432 00433 /* Get Rotator angles */ 00434 if ((angles_array = kmos_get_angles(frameset, &nb_angles, ARC_ON)) == NULL){ 00435 cpl_msg_error(__func__, "Cannot get Angles informations") ; 00436 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00437 for (i = 0; i < ne ; i++) cpl_free(filter_ids[i]); 00438 cpl_free(filter_ids); 00439 cpl_free(suffix); 00440 return -1 ; 00441 } 00442 00443 /* Check the ARC_LIST filter */ 00444 frame = kmo_dfs_get_frame(frameset, ARC_LIST); 00445 plist = cpl_propertylist_load(cpl_frame_get_filename(frame), 0); 00446 tmp_str = cpl_propertylist_get_string(plist, FILT_ID); 00447 if (strcmp(filter_ids[0], tmp_str) != 0) { 00448 cpl_msg_error(__func__, "Wrong ARC_LIST filter") ; 00449 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ; 00450 for (i = 0; i < ne ; i++) cpl_free(filter_ids[i]); 00451 cpl_free(filter_ids); 00452 cpl_free(angles_array); 00453 cpl_propertylist_delete(plist); 00454 return -1 ; 00455 } 00456 cpl_propertylist_delete(plist); 00457 00458 /* Load the lines as a CPL table */ 00459 arclines = kmo_dfs_load_table(frameset, ARC_LIST, 1, 0); 00460 lines = kmos_get_lines(arclines, lamp_config); 00461 cpl_table_delete(arclines); 00462 /* TODO : check not null */ 00463 cpl_msg_info(__func__, "Arc lines: %lld", cpl_bivector_get_size(lines)); 00464 00465 /* Load REFLINES */ 00466 if (lines_estimation == 0) { 00467 reflines = kmo_dfs_load_table(frameset, REF_LINES, 1, 0); 00468 } 00469 00470 /* Check which IFUs are active for all FLAT frames */ 00471 unused_ifus_before = kmo_get_unused_ifus(frameset, 0, 0); 00472 unused_ifus_after = kmo_duplicate_unused_ifus(unused_ifus_before); 00473 kmo_print_unused_ifus(unused_ifus_before, FALSE); 00474 if (unused_ifus_before != NULL) kmo_free_unused_ifus(unused_ifus_before); 00475 00476 /* make sure no reconstruction lookup table (LUT) is used */ 00477 if (getenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE") != NULL) { 00478 last_env = getenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE"); 00479 } else { 00480 last_env = NULL ; 00481 } 00482 setenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE","NONE",1); 00483 00484 /* the frames have to be stored temporarily because the QC params */ 00485 /* for the main header are calculated per detector. So they can be */ 00486 /* stored only when all detectors are processed */ 00487 stored_lcal = (cpl_image**)cpl_calloc(ne * nb_angles, sizeof(cpl_image*)); 00488 stored_det_img = (cpl_image**)cpl_calloc(ne * nb_angles,sizeof(cpl_image*)); 00489 stored_sub_headers_lcal = (cpl_propertylist**)cpl_calloc(ne * nb_angles, 00490 sizeof(cpl_propertylist*)); 00491 stored_sub_headers_det_img = (cpl_propertylist**)cpl_calloc(ne * nb_angles, 00492 sizeof(cpl_propertylist*)); 00493 stored_qc_arc_sat = (int*)cpl_calloc(ne, nb_angles * sizeof(int)); 00494 stored_qc_ar_eff=(double*)cpl_calloc(ne, nb_angles * sizeof(double)); 00495 stored_qc_ne_eff=(double*)cpl_calloc(ne, nb_angles * sizeof(double)); 00496 00497 /* Loop all Rotator Angles and Detectors */ 00498 for (a = 0; a < nb_angles; a++) { 00499 /* Reduce only one angle */ 00500 if (reduce_angle <= 360 && angles_array[a] != reduce_angle) continue ; 00501 00502 cpl_msg_info(__func__, "Processing rotator angle %d -> %d degree", 00503 a, angles_array[a]); 00504 cpl_msg_indent_more(); 00505 for (i = 1; i <= ne ; i++) { 00506 /* Compute only one detetor */ 00507 if (reduce_det != 0 && i != reduce_det) continue ; 00508 00509 cpl_msg_info(__func__,"Processing detector No. %d", i); 00510 cpl_msg_indent_more(); 00511 00512 /* Load edge parameters */ 00513 frame=kmo_dfs_get_frame(frameset, FLAT_EDGE); 00514 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00515 detector_edges[j] = kmclipm_cal_table_load( 00516 cpl_frame_get_filename(frame), 00517 (i-1) * KMOS_IFUS_PER_DETECTOR + j + 1, 00518 angles_array[a], 0, &angle_found); 00519 00520 /* IFU is inactive: proceed */ 00521 if (cpl_error_get_code() == CPL_ERROR_ILLEGAL_INPUT) { 00522 cpl_error_reset(); 00523 } 00524 } 00525 00526 /* Set default fit orders for the different bands */ 00527 if (fit_order_par == 0) { 00528 if ((strcmp(filter_ids[i-1], "H") == 0) || 00529 (strcmp(filter_ids[i-1], "K") == 0) || 00530 (strcmp(filter_ids[i-1], "YJ") == 0)) { 00531 fit_order = 6; 00532 } else if (strcmp(filter_ids[i-1], "IZ") == 0) { 00533 fit_order = 4; 00534 } else if (strcmp(filter_ids[i-1], "HK") == 0) { 00535 fit_order = 5; 00536 } 00537 cpl_msg_info(__func__, 00538 "Order of wavelength spectrum fit for %s-band: %d", 00539 filter_ids[i-1], fit_order); 00540 } else { 00541 fit_order = fit_order_par; 00542 } 00543 00544 /* Get ARC_ON frame and Load it */ 00545 frame = kmos_get_angle_frame(frameset, angles_array[a], ARC_ON); 00546 det_lamp_on = kmo_dfs_load_image_frame(frame,i,FALSE, TRUE,&nr_sat); 00547 int sx = a * ne + (i - 1); 00548 00549 /* Count saturated pixels for each detector */ 00550 if (non_dest_rom) 00551 stored_qc_arc_sat[sx] = nr_sat; 00552 else 00553 stored_qc_arc_sat[sx] = kmo_image_get_saturated(det_lamp_on, 00554 KMO_FLAT_SATURATED); 00555 00556 det_lamp_on_copy = cpl_image_duplicate(det_lamp_on); 00557 00558 /* Get ARC_OFF frame and Load it */ 00559 frame = kmo_dfs_get_frame(frameset, ARC_OFF); 00560 det_lamp_off = kmo_dfs_load_image_frame(frame, i, FALSE, FALSE, 00561 NULL); 00562 00563 /* ARC_ON = ARC_ON - ARC_OFF */ 00564 cpl_image_subtract(det_lamp_on, det_lamp_off); 00565 00566 /* Load XCAL,YCAL */ 00567 xcal = kmo_dfs_load_cal_image(frameset, XCAL, i, 0, 00568 (double)angles_array[a], FALSE, NULL, &angle_found, -1,0,0); 00569 ycal = kmo_dfs_load_cal_image(frameset, YCAL, i, 0, 00570 (double)angles_array[a], FALSE, NULL, &angle_found, -1,0,0); 00571 if (xcal == NULL || ycal == NULL) { 00572 /* Missing calibration for this detector */ 00573 cpl_error_reset() ; 00574 stored_det_img[sx] = NULL ; 00575 stored_lcal[sx] = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 00576 kmo_image_fill(stored_lcal[sx], 0.0); 00577 if (xcal != NULL) cpl_image_delete(xcal) ; 00578 if (ycal != NULL) cpl_image_delete(ycal) ; 00579 cpl_image_delete(det_lamp_on_copy) ; 00580 cpl_image_delete(det_lamp_on) ; 00581 cpl_image_delete(det_lamp_off) ; 00582 continue ; 00583 } 00584 00585 /* Derive BPM from XCAL : NaNs to 0, Others to 1 */ 00586 bad_pix_mask = cpl_image_duplicate(xcal); 00587 pbad_pix_mask = cpl_image_get_data_float(bad_pix_mask); 00588 for (x = 0; x < nx; x++) { 00589 for (y = 0; y < ny; y++) { 00590 if (isnan(pbad_pix_mask[x+nx*y])) { 00591 pbad_pix_mask[x+nx*y] = 0.; 00592 } else { 00593 pbad_pix_mask[x+nx*y] = 1.; 00594 } 00595 } 00596 } 00597 00598 /* Compute wavelength calibration */ 00599 err = kmos_calc_wave_calib(det_lamp_on, bad_pix_mask, 00600 filter_ids[i-1], lamp_config, i, unused_ifus_after[i-1], 00601 detector_edges, lines, reflines, &lcal, 00602 &(stored_qc_ar_eff[sx]), &(stored_qc_ne_eff[sx]), fit_order, 00603 lines_estimation); 00604 cpl_image_delete(det_lamp_on); 00605 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00606 cpl_table_delete(detector_edges[j]); 00607 } 00608 if (err == CPL_ERROR_NONE) { 00609 /* Update QC parameters */ 00610 if (stored_qc_ar_eff[sx] != -1.0) 00611 stored_qc_ar_eff[sx] /= exptime; 00612 if (stored_qc_ne_eff[sx] != -1.0) 00613 stored_qc_ne_eff[sx] /= exptime; 00614 00615 /* Apply the badpixel mask to the produced frame */ 00616 cpl_image_multiply(lcal, bad_pix_mask); 00617 kmo_image_reject_from_mask(lcal, bad_pix_mask); 00618 00619 /* Store Result frame */ 00620 stored_lcal[sx] = lcal; 00621 } else if (err == CPL_ERROR_UNSPECIFIED) { 00622 /* All IFUs seem to be deactivated */ 00623 /* Continue processing - just save empty frame */ 00624 cpl_error_reset(); 00625 stored_lcal[sx] = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 00626 kmo_image_fill(stored_lcal[sx], 0.0); 00627 } else { 00628 cpl_error_reset(); 00629 cpl_msg_warning(__func__, 00630 "Couldn't identify any line - Check the line list"); 00631 cpl_msg_warning(__func__, 00632 "Band defined in header of detector %d: %s", 00633 i, filter_ids[i-1]); 00634 cpl_msg_warning(__func__, "Arc line file defined: %s", 00635 cpl_frame_get_filename(kmo_dfs_get_frame(frameset, 00636 ARC_LIST))); 00637 } 00638 cpl_image_delete(bad_pix_mask); 00639 00640 /* CREATE RECONSTRUCTED AND RESAMPLED ARC FRAME */ 00641 stored_det_img[sx] = kmo_reconstructed_arc_image(frameset, 00642 det_lamp_on_copy, det_lamp_off, xcal, ycal, stored_lcal[sx], 00643 unused_ifus_after[i-1], FALSE, i, suffix, filter_ids[i-1], 00644 lamp_config, &qc_header); 00645 cpl_image_delete(det_lamp_on_copy); 00646 cpl_image_delete(det_lamp_off); 00647 cpl_image_delete(xcal); 00648 cpl_image_delete(ycal); 00649 if (cpl_error_get_code() != CPL_ERROR_NONE) { 00650 cpl_msg_error(__func__,"Cannot reconstruct IFUs on detector %d", 00651 i); 00652 cpl_error_reset(); 00653 } 00654 00655 /* CREATE EXTENSION HEADER FOR THE PRODUCT */ 00656 stored_sub_headers_lcal[sx] = kmo_dfs_load_sub_header(frameset, 00657 ARC_ON, i, FALSE); 00658 /* update EXTNAME */ 00659 extname = kmo_extname_creator(detector_frame, i, EXT_DATA); 00660 kmclipm_update_property_string(stored_sub_headers_lcal[sx], EXTNAME, 00661 extname, "FITS extension name"); 00662 cpl_free(extname); 00663 00664 kmclipm_update_property_int(stored_sub_headers_lcal[sx], EXTVER, 00665 sx+1, "FITS extension ver"); 00666 00667 // add first QC parameters 00668 kmclipm_update_property_int(stored_sub_headers_lcal[sx], 00669 QC_ARC_SAT, stored_qc_arc_sat[sx], 00670 "[] nr. saturated pixels of arc exp."); 00671 00672 gain=kmo_dfs_get_property_double(stored_sub_headers_lcal[sx],GAIN); 00673 00674 if (stored_qc_ar_eff[sx] != -1.0) { 00675 kmclipm_update_property_double(stored_sub_headers_lcal[sx], 00676 QC_ARC_AR_EFF, stored_qc_ar_eff[sx]/gain, 00677 "[e-/s] Argon lamp efficiency"); 00678 } 00679 00680 if (stored_qc_ne_eff[sx] != -1.0) { 00681 kmclipm_update_property_double(stored_sub_headers_lcal[sx], 00682 QC_ARC_NE_EFF, stored_qc_ne_eff[sx]/gain, 00683 "[e-/s] Neon lamp efficiency"); 00684 } 00685 00686 kmclipm_update_property_double(stored_sub_headers_lcal[sx], 00687 CAL_ROTANGLE, ((double) angles_array[a]), 00688 "[deg] Rotator relative to nasmyth"); 00689 00690 /* append QC parameters */ 00691 cpl_propertylist_append(stored_sub_headers_lcal[sx], qc_header); 00692 cpl_propertylist_delete(qc_header); 00693 00694 stored_sub_headers_det_img[sx]=cpl_propertylist_duplicate( 00695 stored_sub_headers_lcal[sx]); 00696 00697 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CRVAL1); 00698 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CRVAL2); 00699 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CTYPE1); 00700 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CTYPE2); 00701 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CDELT1); 00702 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CDELT2); 00703 00704 cpl_msg_indent_less(); 00705 } // for i devices 00706 cpl_msg_indent_less() ; 00707 } // for a angles 00708 00709 /* Free */ 00710 cpl_free(angles_array) ; 00711 for (i = 0; i < ne; i++) cpl_free(filter_ids[i]); 00712 cpl_free(filter_ids); 00713 cpl_bivector_delete(lines); 00714 00715 cpl_free(stored_qc_arc_sat); 00716 cpl_free(stored_qc_ar_eff); 00717 cpl_free(stored_qc_ne_eff); 00718 if (lines_estimation == 0) cpl_table_delete(reflines); 00719 00720 /* QC parameters & saving */ 00721 cpl_msg_info(__func__, "Saving data..."); 00722 00723 /* load, update & save primary header */ 00724 if (!suppress_extension) fn_suffix = cpl_sprintf("%s", suffix); 00725 else fn_suffix = cpl_sprintf("%s", ""); 00726 cpl_free(suffix); 00727 00728 /* update which IFUs are not used */ 00729 frame = kmo_dfs_get_frame(frameset, ARC_ON); 00730 mh_on = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0); 00731 kmo_set_unused_ifus(unused_ifus_after, mh_on, "kmos_wave_cal"); 00732 kmo_dfs_save_main_header(frameset, LCAL, fn_suffix, frame, mh_on, parlist, 00733 cpl_func); 00734 kmo_dfs_save_main_header(frameset, DET_IMG_WAVE, fn_suffix, frame, mh_on, 00735 parlist, cpl_func); 00736 cpl_propertylist_delete(mh_on); 00737 00738 /* Save sub-frames */ 00739 for (a = 0; a < nb_angles; a++) { 00740 for (i = 1; i <= ne ; i++) { 00741 int sx = a * ne + (i - 1); 00742 /* save lcal-frame */ 00743 kmo_dfs_save_image(stored_lcal[sx], LCAL, fn_suffix, 00744 stored_sub_headers_lcal[sx], 0./0.); 00745 00746 /* save detector image */ 00747 kmo_dfs_save_image(stored_det_img[sx], DET_IMG_WAVE, fn_suffix, 00748 stored_sub_headers_det_img[sx], 0./0.); 00749 } // for i = ne 00750 } // for a angles 00751 00752 /* Free */ 00753 cpl_free(fn_suffix); 00754 for (i = 0; i < ne * nb_angles; i++) { 00755 cpl_image_delete(stored_lcal[i]); 00756 cpl_image_delete(stored_det_img[i]); 00757 cpl_propertylist_delete(stored_sub_headers_lcal[i]); 00758 cpl_propertylist_delete(stored_sub_headers_det_img[i]); 00759 } 00760 cpl_free(stored_lcal); 00761 cpl_free(stored_det_img); 00762 cpl_free(stored_sub_headers_lcal); 00763 cpl_free(stored_sub_headers_det_img); 00764 00765 /* print which IFUs are not used */ 00766 kmo_print_unused_ifus(unused_ifus_after, TRUE); 00767 if (unused_ifus_after != NULL) kmo_free_unused_ifus(unused_ifus_after); 00768 00769 if (last_env != NULL) { 00770 setenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE",last_env,1); 00771 } else { 00772 unsetenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE"); 00773 } 00774 return 0; 00775 } 00776 00779 /*----------------------------------------------------------------------------*/ 00791 /*----------------------------------------------------------------------------*/ 00792 static int kmos_wave_cal_check_inputs( 00793 cpl_frameset * frameset, 00794 int * nx, 00795 int * ny, 00796 int * ne, 00797 double * exptime, 00798 int * non_dest_rom, 00799 lampConfiguration * lamp_config) 00800 { 00801 const cpl_frame * frame_off ; 00802 const cpl_frame * frame_on ; 00803 cpl_propertylist * mh_off ; 00804 cpl_propertylist * mh_on ; 00805 cpl_propertylist * eh_off ; 00806 cpl_propertylist * eh_on ; 00807 int ext, next_off, next_on, nx_on, ny_on, nx_off,ny_off; 00808 double ndit_off, ndit_on, exptime_off, exptime_on ; 00809 const char * readmode_off ; 00810 const char * readmode_on ; 00811 00812 /* TODO Check Lamps TODO */ 00813 00814 /* Check Entries */ 00815 if (nx == NULL || ny == NULL || ne == NULL || frameset == NULL) return -1; 00816 00817 /* Setup lamp config */ 00818 frame_on = kmo_dfs_get_frame(frameset, ARC_ON); 00819 mh_on = cpl_propertylist_load(cpl_frame_get_filename(frame_on), 0); 00820 if ((kmo_check_lamp(mh_on, INS_LAMP1_ST) == TRUE) && 00821 (kmo_check_lamp(mh_on, INS_LAMP2_ST) == FALSE)) { 00822 *lamp_config = ARGON; 00823 cpl_msg_info(__func__, "Arc lamp: Argon"); 00824 } else if ((kmo_check_lamp(mh_on, INS_LAMP1_ST) == FALSE) && 00825 (kmo_check_lamp(mh_on, INS_LAMP2_ST) == TRUE)) { 00826 *lamp_config = NEON; 00827 cpl_msg_info(__func__, "Arc lamp: Neon"); 00828 } else if ((kmo_check_lamp(mh_on, INS_LAMP1_ST) == TRUE) && 00829 (kmo_check_lamp(mh_on, INS_LAMP2_ST) == TRUE)) { 00830 *lamp_config = ARGON_NEON; 00831 cpl_msg_info(__func__, "Arc lamp: Argon + Neon"); 00832 } else { 00833 *lamp_config = -1 ; 00834 cpl_warning_info(__func__, "Arc lamp: UNDEFINED"); 00835 } 00836 00837 /* Check READ OUT MODE */ 00838 readmode_on = kmos_pfits_get_readmode(mh_on); 00839 if (!strcmp(readmode_on, "Nondest")) { 00840 *non_dest_rom = 1 ; 00841 } else { 00842 *non_dest_rom = 0 ; 00843 } 00844 cpl_propertylist_delete(mh_on); 00845 00846 /* Get ARC_OFF */ 00847 frame_off = kmo_dfs_get_frame(frameset, ARC_OFF); 00848 if (frame_off == NULL) { 00849 cpl_msg_error(__func__, "No ARC_OFF frame found") ; 00850 return -1 ; 00851 } 00852 00853 /* Get ARC_OFF main header infos */ 00854 next_off = cpl_frame_get_nextensions(frame_off); 00855 mh_off = cpl_propertylist_load(cpl_frame_get_filename(frame_off), 0); 00856 ndit_off = kmos_pfits_get_ndit(mh_off) ; 00857 exptime_off = kmos_pfits_get_exptime(mh_off) ; 00858 readmode_off = kmos_pfits_get_readmode(mh_off); 00859 00860 /* Get ARC_ON frames and loop on them */ 00861 frame_on = kmo_dfs_get_frame(frameset, ARC_ON); 00862 if (frame_on == NULL) { 00863 cpl_msg_error(__func__, "No ARC_ON frame found") ; 00864 cpl_propertylist_delete(mh_off); 00865 return -1 ; 00866 } 00867 while (frame_on != NULL) { 00868 /* Get ARC_ON main header infos */ 00869 next_on = cpl_frame_get_nextensions(frame_on); 00870 mh_on = cpl_propertylist_load(cpl_frame_get_filename(frame_on), 0); 00871 ndit_on = kmos_pfits_get_ndit(mh_on) ; 00872 exptime_on = kmos_pfits_get_exptime(mh_on) ; 00873 readmode_on = kmos_pfits_get_readmode(mh_on); 00874 00875 /* Check consistency */ 00876 if (ndit_on != ndit_off || strcmp(readmode_on, readmode_off) || 00877 fabs(exptime_on-exptime_off) > 0.01 || next_off != next_on) { 00878 cpl_msg_warning(__func__, "Inconsistency for frame %s", 00879 cpl_frame_get_filename(frame_on)) ; 00880 cpl_propertylist_delete(mh_off); 00881 cpl_propertylist_delete(mh_on); 00882 return 0 ; 00883 } 00884 cpl_propertylist_delete(mh_on); 00885 00886 /* Get next frame */ 00887 frame_on = kmo_dfs_get_frame(frameset, NULL); 00888 } 00889 cpl_propertylist_delete(mh_off); 00890 00891 /* Check the extensions */ 00892 for (ext = 1; ext <= next_off ; ext++) { 00893 eh_off = cpl_propertylist_load(cpl_frame_get_filename(frame_off), ext); 00894 nx_off = kmos_pfits_get_naxis1(eh_off) ; 00895 ny_off = kmos_pfits_get_naxis2(eh_off) ; 00896 00897 frame_on = kmo_dfs_get_frame(frameset, ARC_ON); 00898 while (frame_on != NULL) { 00899 eh_on = cpl_propertylist_load(cpl_frame_get_filename(frame_on),ext); 00900 nx_on = kmos_pfits_get_naxis1(eh_on) ; 00901 ny_on = kmos_pfits_get_naxis2(eh_on) ; 00902 /* Check consistency */ 00903 if (nx_on != nx_off || ny_off != ny_on) { 00904 cpl_msg_warning(__func__, "Inconsistency for frame %s", 00905 cpl_frame_get_filename(frame_on)) ; 00906 cpl_propertylist_delete(eh_off); 00907 cpl_propertylist_delete(eh_on); 00908 return 0 ; 00909 } 00910 cpl_propertylist_delete(eh_on); 00911 00912 /* Get next frame */ 00913 frame_on = kmo_dfs_get_frame(frameset, NULL); 00914 } 00915 cpl_propertylist_delete(eh_off); 00916 } 00917 00918 /* FLAT_EDGE Checks */ 00919 frame_on = kmo_dfs_get_frame(frameset, FLAT_EDGE); 00920 if (cpl_frame_get_nextensions(frame_on) % 24 != 0) { 00921 cpl_msg_warning(__func__, "FLAT_EDGE frame is not consistent") ; 00922 return 0 ; 00923 } 00924 00925 /* Checks on XCAL YCAL */ 00926 kmo_check_frame_setup(frameset, ARC_ON, XCAL, TRUE, FALSE, FALSE); 00927 kmo_check_frame_setup(frameset, ARC_ON, YCAL, TRUE, FALSE, FALSE); 00928 kmo_check_frame_setup_md5_xycal(frameset); 00929 if (cpl_error_get_code() != CPL_ERROR_NONE) { 00930 cpl_msg_warning(__func__, "XCAL / YCAL checks failed") ; 00931 return 0 ; 00932 } 00933 00934 /* Return */ 00935 *nx = nx_off ; 00936 *ny = ny_off ; 00937 *ne = next_off ; 00938 *exptime = exptime_off ; 00939 return 1 ; 00940 } 00941 00942
1.7.6.1