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 #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, next, 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, &next, &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, next, 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 < next ; 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 < next ; 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 } else { 00469 reflines = NULL ; 00470 } 00471 00472 /* Check which IFUs are active for all FLAT frames */ 00473 unused_ifus_before = kmo_get_unused_ifus(frameset, 0, 0); 00474 unused_ifus_after = kmo_duplicate_unused_ifus(unused_ifus_before); 00475 kmo_print_unused_ifus(unused_ifus_before, FALSE); 00476 if (unused_ifus_before != NULL) kmo_free_unused_ifus(unused_ifus_before); 00477 00478 /* make sure no reconstruction lookup table (LUT) is used */ 00479 if (getenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE") != NULL) { 00480 last_env = getenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE"); 00481 } else { 00482 last_env = NULL ; 00483 } 00484 setenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE","NONE",1); 00485 00486 /* the frames have to be stored temporarily because the QC params */ 00487 /* for the main header are calculated per detector. So they can be */ 00488 /* stored only when all detectors are processed */ 00489 stored_lcal = (cpl_image**)cpl_calloc(next * nb_angles, sizeof(cpl_image*)); 00490 stored_det_img = (cpl_image**)cpl_calloc(next*nb_angles,sizeof(cpl_image*)); 00491 stored_sub_headers_lcal = (cpl_propertylist**)cpl_calloc(next * nb_angles, 00492 sizeof(cpl_propertylist*)); 00493 stored_sub_headers_det_img = (cpl_propertylist**)cpl_calloc(next*nb_angles, 00494 sizeof(cpl_propertylist*)); 00495 stored_qc_arc_sat = (int*)cpl_calloc(next, nb_angles * sizeof(int)); 00496 stored_qc_ar_eff=(double*)cpl_calloc(next, nb_angles * sizeof(double)); 00497 stored_qc_ne_eff=(double*)cpl_calloc(next, nb_angles * sizeof(double)); 00498 00499 /* Loop all Rotator Angles and Detectors */ 00500 for (a = 0; a < nb_angles; a++) { 00501 /* Reduce only one angle */ 00502 if (reduce_angle <= 360 && angles_array[a] != reduce_angle) continue ; 00503 00504 cpl_msg_info(__func__, "Processing rotator angle %d -> %d degree", 00505 a, angles_array[a]); 00506 cpl_msg_indent_more(); 00507 for (i = 1; i <= next ; i++) { 00508 /* Compute only one detetor */ 00509 if (reduce_det != 0 && i != reduce_det) continue ; 00510 00511 cpl_msg_info(__func__,"Processing detector No. %d", i); 00512 cpl_msg_indent_more(); 00513 00514 /* Load edge parameters */ 00515 frame=kmo_dfs_get_frame(frameset, FLAT_EDGE); 00516 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00517 detector_edges[j] = kmclipm_cal_table_load( 00518 cpl_frame_get_filename(frame), 00519 (i-1) * KMOS_IFUS_PER_DETECTOR + j + 1, 00520 angles_array[a], 0, &angle_found); 00521 00522 /* IFU is inactive: proceed */ 00523 if (cpl_error_get_code() == CPL_ERROR_ILLEGAL_INPUT) { 00524 cpl_error_reset(); 00525 } 00526 } 00527 00528 /* Set default fit orders for the different bands */ 00529 if (fit_order_par == 0) { 00530 if ((strcmp(filter_ids[i-1], "H") == 0) || 00531 (strcmp(filter_ids[i-1], "K") == 0) || 00532 (strcmp(filter_ids[i-1], "YJ") == 0)) { 00533 fit_order = 6; 00534 } else if (strcmp(filter_ids[i-1], "IZ") == 0) { 00535 fit_order = 4; 00536 } else if (strcmp(filter_ids[i-1], "HK") == 0) { 00537 fit_order = 5; 00538 } 00539 cpl_msg_info(__func__, 00540 "Order of wavelength spectrum fit for %s-band: %d", 00541 filter_ids[i-1], fit_order); 00542 } else { 00543 fit_order = fit_order_par; 00544 } 00545 00546 /* Get ARC_ON frame and Load it */ 00547 frame = kmos_get_angle_frame(frameset, angles_array[a], ARC_ON); 00548 det_lamp_on = kmo_dfs_load_image_frame(frame,i,FALSE, TRUE,&nr_sat); 00549 int sx = a * next + (i - 1); 00550 00551 /* Count saturated pixels for each detector */ 00552 if (non_dest_rom) 00553 stored_qc_arc_sat[sx] = nr_sat; 00554 else 00555 stored_qc_arc_sat[sx] = kmo_image_get_saturated(det_lamp_on, 00556 KMO_FLAT_SATURATED); 00557 00558 det_lamp_on_copy = cpl_image_duplicate(det_lamp_on); 00559 00560 /* Get ARC_OFF frame and Load it */ 00561 frame = kmo_dfs_get_frame(frameset, ARC_OFF); 00562 det_lamp_off = kmo_dfs_load_image_frame(frame, i, FALSE, FALSE, 00563 NULL); 00564 00565 /* ARC_ON = ARC_ON - ARC_OFF */ 00566 cpl_image_subtract(det_lamp_on, det_lamp_off); 00567 00568 /* Load XCAL,YCAL */ 00569 xcal = kmo_dfs_load_cal_image(frameset, XCAL, i, 0, 00570 (double)angles_array[a], FALSE, NULL, &angle_found, -1,0,0); 00571 ycal = kmo_dfs_load_cal_image(frameset, YCAL, i, 0, 00572 (double)angles_array[a], FALSE, NULL, &angle_found, -1,0,0); 00573 if (xcal == NULL || ycal == NULL) { 00574 /* Missing calibration for this detector */ 00575 cpl_error_reset() ; 00576 stored_det_img[sx] = NULL ; 00577 stored_lcal[sx] = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 00578 kmo_image_fill(stored_lcal[sx], 0.0); 00579 if (xcal != NULL) cpl_image_delete(xcal) ; 00580 if (ycal != NULL) cpl_image_delete(ycal) ; 00581 cpl_image_delete(det_lamp_on_copy) ; 00582 cpl_image_delete(det_lamp_on) ; 00583 cpl_image_delete(det_lamp_off) ; 00584 continue ; 00585 } 00586 00587 /* Derive BPM from XCAL : NaNs to 0, Others to 1 */ 00588 bad_pix_mask = cpl_image_duplicate(xcal); 00589 pbad_pix_mask = cpl_image_get_data_float(bad_pix_mask); 00590 for (x = 0; x < nx; x++) { 00591 for (y = 0; y < ny; y++) { 00592 if (isnan(pbad_pix_mask[x+nx*y])) { 00593 pbad_pix_mask[x+nx*y] = 0.; 00594 } else { 00595 pbad_pix_mask[x+nx*y] = 1.; 00596 } 00597 } 00598 } 00599 00600 /* Compute wavelength calibration */ 00601 err = kmos_calc_wave_calib(det_lamp_on, bad_pix_mask, 00602 filter_ids[i-1], lamp_config, i, unused_ifus_after[i-1], 00603 detector_edges, lines, reflines, &lcal, 00604 &(stored_qc_ar_eff[sx]), &(stored_qc_ne_eff[sx]), fit_order, 00605 lines_estimation); 00606 cpl_image_delete(det_lamp_on); 00607 for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) { 00608 cpl_table_delete(detector_edges[j]); 00609 } 00610 if (err == CPL_ERROR_NONE) { 00611 /* Update QC parameters */ 00612 if (stored_qc_ar_eff[sx] != -1.0) 00613 stored_qc_ar_eff[sx] /= exptime; 00614 if (stored_qc_ne_eff[sx] != -1.0) 00615 stored_qc_ne_eff[sx] /= exptime; 00616 00617 /* Apply the badpixel mask to the produced frame */ 00618 cpl_image_multiply(lcal, bad_pix_mask); 00619 kmo_image_reject_from_mask(lcal, bad_pix_mask); 00620 00621 /* Store Result frame */ 00622 stored_lcal[sx] = lcal; 00623 } else if (err == CPL_ERROR_UNSPECIFIED) { 00624 /* All IFUs seem to be deactivated */ 00625 /* Continue processing - just save empty frame */ 00626 cpl_error_reset(); 00627 stored_lcal[sx] = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 00628 kmo_image_fill(stored_lcal[sx], 0.0); 00629 } else { 00630 cpl_error_reset(); 00631 cpl_msg_warning(__func__, 00632 "Couldn't identify any line - Check the line list"); 00633 cpl_msg_warning(__func__, 00634 "Band defined in header of detector %d: %s", 00635 i, filter_ids[i-1]); 00636 cpl_msg_warning(__func__, "Arc line file defined: %s", 00637 cpl_frame_get_filename(kmo_dfs_get_frame(frameset, 00638 ARC_LIST))); 00639 } 00640 cpl_image_delete(bad_pix_mask); 00641 00642 /* CREATE RECONSTRUCTED AND RESAMPLED ARC FRAME */ 00643 stored_det_img[sx] = kmo_reconstructed_arc_image(frameset, 00644 det_lamp_on_copy, det_lamp_off, xcal, ycal, stored_lcal[sx], 00645 unused_ifus_after[i-1], FALSE, i, suffix, filter_ids[i-1], 00646 lamp_config, &qc_header); 00647 cpl_image_delete(det_lamp_on_copy); 00648 cpl_image_delete(det_lamp_off); 00649 cpl_image_delete(xcal); 00650 cpl_image_delete(ycal); 00651 if (cpl_error_get_code() != CPL_ERROR_NONE) { 00652 cpl_msg_error(__func__,"Cannot reconstruct IFUs on detector %d", 00653 i); 00654 cpl_error_reset(); 00655 } 00656 00657 /* CREATE EXTENSION HEADER FOR THE PRODUCT */ 00658 stored_sub_headers_lcal[sx] = kmo_dfs_load_sub_header(frameset, 00659 ARC_ON, i, FALSE); 00660 /* update EXTNAME */ 00661 extname = kmo_extname_creator(detector_frame, i, EXT_DATA); 00662 kmclipm_update_property_string(stored_sub_headers_lcal[sx], EXTNAME, 00663 extname, "FITS extension name"); 00664 cpl_free(extname); 00665 00666 kmclipm_update_property_int(stored_sub_headers_lcal[sx], EXTVER, 00667 sx+1, "FITS extension ver"); 00668 00669 // add first QC parameters 00670 kmclipm_update_property_int(stored_sub_headers_lcal[sx], 00671 QC_ARC_SAT, stored_qc_arc_sat[sx], 00672 "[] nr. saturated pixels of arc exp."); 00673 00674 gain=kmo_dfs_get_property_double(stored_sub_headers_lcal[sx],GAIN); 00675 00676 if (stored_qc_ar_eff[sx] != -1.0) { 00677 kmclipm_update_property_double(stored_sub_headers_lcal[sx], 00678 QC_ARC_AR_EFF, stored_qc_ar_eff[sx]/gain, 00679 "[e-/s] Argon lamp efficiency"); 00680 } 00681 00682 if (stored_qc_ne_eff[sx] != -1.0) { 00683 kmclipm_update_property_double(stored_sub_headers_lcal[sx], 00684 QC_ARC_NE_EFF, stored_qc_ne_eff[sx]/gain, 00685 "[e-/s] Neon lamp efficiency"); 00686 } 00687 00688 kmclipm_update_property_double(stored_sub_headers_lcal[sx], 00689 CAL_ROTANGLE, ((double) angles_array[a]), 00690 "[deg] Rotator relative to nasmyth"); 00691 00692 /* append QC parameters */ 00693 cpl_propertylist_append(stored_sub_headers_lcal[sx], qc_header); 00694 cpl_propertylist_delete(qc_header); 00695 00696 stored_sub_headers_det_img[sx]=cpl_propertylist_duplicate( 00697 stored_sub_headers_lcal[sx]); 00698 00699 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CRVAL1); 00700 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CRVAL2); 00701 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CTYPE1); 00702 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CTYPE2); 00703 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CDELT1); 00704 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CDELT2); 00705 00706 cpl_msg_indent_less(); 00707 } // for i devices 00708 cpl_msg_indent_less() ; 00709 } // for a angles 00710 00711 /* Free */ 00712 cpl_free(angles_array) ; 00713 for (i = 0; i < next; i++) cpl_free(filter_ids[i]); 00714 cpl_free(filter_ids); 00715 cpl_bivector_delete(lines); 00716 00717 cpl_free(stored_qc_arc_sat); 00718 cpl_free(stored_qc_ar_eff); 00719 cpl_free(stored_qc_ne_eff); 00720 if (lines_estimation == 0) cpl_table_delete(reflines); 00721 00722 /* QC parameters & saving */ 00723 cpl_msg_info(__func__, "Saving data..."); 00724 00725 /* load, update & save primary header */ 00726 if (!suppress_extension) fn_suffix = cpl_sprintf("%s", suffix); 00727 else fn_suffix = cpl_sprintf("%s", ""); 00728 cpl_free(suffix); 00729 00730 /* update which IFUs are not used */ 00731 frame = kmo_dfs_get_frame(frameset, ARC_ON); 00732 mh_on = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0); 00733 kmo_set_unused_ifus(unused_ifus_after, mh_on, "kmos_wave_cal"); 00734 kmo_dfs_save_main_header(frameset, LCAL, fn_suffix, frame, mh_on, parlist, 00735 cpl_func); 00736 kmo_dfs_save_main_header(frameset, DET_IMG_WAVE, fn_suffix, frame, mh_on, 00737 parlist, cpl_func); 00738 cpl_propertylist_delete(mh_on); 00739 00740 /* Save sub-frames */ 00741 for (a = 0; a < nb_angles; a++) { 00742 for (i = 1; i <= next ; i++) { 00743 int sx = a * next + (i - 1); 00744 /* save lcal-frame */ 00745 kmo_dfs_save_image(stored_lcal[sx], LCAL, fn_suffix, 00746 stored_sub_headers_lcal[sx], 0./0.); 00747 00748 /* save detector image */ 00749 kmo_dfs_save_image(stored_det_img[sx], DET_IMG_WAVE, fn_suffix, 00750 stored_sub_headers_det_img[sx], 0./0.); 00751 } // for i = nxte 00752 } // for a angles 00753 00754 /* Free */ 00755 cpl_free(fn_suffix); 00756 for (i = 0; i < next * nb_angles; i++) { 00757 cpl_image_delete(stored_lcal[i]); 00758 cpl_image_delete(stored_det_img[i]); 00759 cpl_propertylist_delete(stored_sub_headers_lcal[i]); 00760 cpl_propertylist_delete(stored_sub_headers_det_img[i]); 00761 } 00762 cpl_free(stored_lcal); 00763 cpl_free(stored_det_img); 00764 cpl_free(stored_sub_headers_lcal); 00765 cpl_free(stored_sub_headers_det_img); 00766 00767 /* print which IFUs are not used */ 00768 kmo_print_unused_ifus(unused_ifus_after, TRUE); 00769 if (unused_ifus_after != NULL) kmo_free_unused_ifus(unused_ifus_after); 00770 00771 if (last_env != NULL) { 00772 setenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE",last_env,1); 00773 } else { 00774 unsetenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE"); 00775 } 00776 return 0; 00777 } 00778 00781 /*----------------------------------------------------------------------------*/ 00793 /*----------------------------------------------------------------------------*/ 00794 static int kmos_wave_cal_check_inputs( 00795 cpl_frameset * frameset, 00796 int * nx, 00797 int * ny, 00798 int * next, 00799 double * exptime, 00800 int * non_dest_rom, 00801 lampConfiguration * lamp_config) 00802 { 00803 const cpl_frame * frame_off ; 00804 const cpl_frame * frame_on ; 00805 cpl_propertylist * mh_off ; 00806 cpl_propertylist * mh_on ; 00807 cpl_propertylist * eh_off ; 00808 cpl_propertylist * eh_on ; 00809 int ext, next_off, next_on, nx_on, ny_on, nx_off,ny_off; 00810 double ndit_off, ndit_on, exptime_off, exptime_on ; 00811 const char * readmode_off ; 00812 const char * readmode_on ; 00813 00814 /* TODO Check Lamps TODO */ 00815 00816 /* Check Entries */ 00817 if (nx == NULL || ny == NULL || next == NULL || frameset == NULL) return -1; 00818 00819 /* Setup lamp config */ 00820 frame_on = kmo_dfs_get_frame(frameset, ARC_ON); 00821 mh_on = cpl_propertylist_load(cpl_frame_get_filename(frame_on), 0); 00822 if ((kmo_check_lamp(mh_on, INS_LAMP1_ST) == TRUE) && 00823 (kmo_check_lamp(mh_on, INS_LAMP2_ST) == FALSE)) { 00824 *lamp_config = ARGON; 00825 cpl_msg_info(__func__, "Arc lamp: Argon"); 00826 } else if ((kmo_check_lamp(mh_on, INS_LAMP1_ST) == FALSE) && 00827 (kmo_check_lamp(mh_on, INS_LAMP2_ST) == TRUE)) { 00828 *lamp_config = NEON; 00829 cpl_msg_info(__func__, "Arc lamp: Neon"); 00830 } else if ((kmo_check_lamp(mh_on, INS_LAMP1_ST) == TRUE) && 00831 (kmo_check_lamp(mh_on, INS_LAMP2_ST) == TRUE)) { 00832 *lamp_config = ARGON_NEON; 00833 cpl_msg_info(__func__, "Arc lamp: Argon + Neon"); 00834 } else { 00835 *lamp_config = -1 ; 00836 cpl_msg_warning(__func__, "Arc lamp: UNDEFINED"); 00837 } 00838 00839 /* Check READ OUT MODE */ 00840 readmode_on = kmos_pfits_get_readmode(mh_on); 00841 if (!strcmp(readmode_on, "Nondest")) { 00842 *non_dest_rom = 1 ; 00843 } else { 00844 *non_dest_rom = 0 ; 00845 } 00846 cpl_propertylist_delete(mh_on); 00847 00848 /* Get ARC_OFF */ 00849 frame_off = kmo_dfs_get_frame(frameset, ARC_OFF); 00850 if (frame_off == NULL) { 00851 cpl_msg_error(__func__, "No ARC_OFF frame found") ; 00852 return -1 ; 00853 } 00854 00855 /* Get ARC_OFF main header infos */ 00856 next_off = cpl_frame_get_nextensions(frame_off); 00857 mh_off = cpl_propertylist_load(cpl_frame_get_filename(frame_off), 0); 00858 ndit_off = kmos_pfits_get_ndit(mh_off) ; 00859 exptime_off = kmos_pfits_get_exptime(mh_off) ; 00860 readmode_off = kmos_pfits_get_readmode(mh_off); 00861 00862 /* Get ARC_ON frames and loop on them */ 00863 frame_on = kmo_dfs_get_frame(frameset, ARC_ON); 00864 if (frame_on == NULL) { 00865 cpl_msg_error(__func__, "No ARC_ON frame found") ; 00866 cpl_propertylist_delete(mh_off); 00867 return -1 ; 00868 } 00869 while (frame_on != NULL) { 00870 /* Get ARC_ON main header infos */ 00871 next_on = cpl_frame_get_nextensions(frame_on); 00872 mh_on = cpl_propertylist_load(cpl_frame_get_filename(frame_on), 0); 00873 ndit_on = kmos_pfits_get_ndit(mh_on) ; 00874 exptime_on = kmos_pfits_get_exptime(mh_on) ; 00875 readmode_on = kmos_pfits_get_readmode(mh_on); 00876 00877 /* Check consistency */ 00878 if (ndit_on != ndit_off || strcmp(readmode_on, readmode_off) || 00879 fabs(exptime_on-exptime_off) > 0.01 || next_off != next_on) { 00880 cpl_msg_warning(__func__, "Inconsistency for frame %s", 00881 cpl_frame_get_filename(frame_on)) ; 00882 cpl_propertylist_delete(mh_off); 00883 cpl_propertylist_delete(mh_on); 00884 return 0 ; 00885 } 00886 cpl_propertylist_delete(mh_on); 00887 00888 /* Get next frame */ 00889 frame_on = kmo_dfs_get_frame(frameset, NULL); 00890 } 00891 cpl_propertylist_delete(mh_off); 00892 00893 /* Check the extensions */ 00894 for (ext = 1; ext <= next_off ; ext++) { 00895 eh_off = cpl_propertylist_load(cpl_frame_get_filename(frame_off), ext); 00896 nx_off = kmos_pfits_get_naxis1(eh_off) ; 00897 ny_off = kmos_pfits_get_naxis2(eh_off) ; 00898 00899 frame_on = kmo_dfs_get_frame(frameset, ARC_ON); 00900 while (frame_on != NULL) { 00901 eh_on = cpl_propertylist_load(cpl_frame_get_filename(frame_on),ext); 00902 nx_on = kmos_pfits_get_naxis1(eh_on) ; 00903 ny_on = kmos_pfits_get_naxis2(eh_on) ; 00904 /* Check consistency */ 00905 if (nx_on != nx_off || ny_off != ny_on) { 00906 cpl_msg_warning(__func__, "Inconsistency for frame %s", 00907 cpl_frame_get_filename(frame_on)) ; 00908 cpl_propertylist_delete(eh_off); 00909 cpl_propertylist_delete(eh_on); 00910 return 0 ; 00911 } 00912 cpl_propertylist_delete(eh_on); 00913 00914 /* Get next frame */ 00915 frame_on = kmo_dfs_get_frame(frameset, NULL); 00916 } 00917 cpl_propertylist_delete(eh_off); 00918 } 00919 00920 /* FLAT_EDGE Checks */ 00921 frame_on = kmo_dfs_get_frame(frameset, FLAT_EDGE); 00922 if (cpl_frame_get_nextensions(frame_on) % 24 != 0) { 00923 cpl_msg_warning(__func__, "FLAT_EDGE frame is not consistent") ; 00924 return 0 ; 00925 } 00926 00927 /* Checks on XCAL YCAL */ 00928 kmo_check_frame_setup(frameset, ARC_ON, XCAL, TRUE, FALSE, FALSE); 00929 kmo_check_frame_setup(frameset, ARC_ON, YCAL, TRUE, FALSE, FALSE); 00930 kmo_check_frame_setup_md5_xycal(frameset); 00931 if (cpl_error_get_code() != CPL_ERROR_NONE) { 00932 cpl_msg_warning(__func__, "XCAL / YCAL checks failed") ; 00933 return 0 ; 00934 } 00935 00936 /* Return */ 00937 *nx = nx_off ; 00938 *ny = ny_off ; 00939 *next = next_off ; 00940 *exptime = exptime_off ; 00941 return 1 ; 00942 } 00943 00944