FORS Pipeline Reference Manual 4.9.20
|
00001 /* $Id: vimos_calib_impl.c,v 1.3 2013/01/21 09:23:34 cgarcia Exp $ 00002 * 00003 * This file is part of the FORS Data Reduction Pipeline 00004 * Copyright (C) 2002-2010 European Southern Observatory 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 /* 00022 * $Author: cgarcia $ 00023 * $Date: 2013/01/21 09:23:34 $ 00024 * $Revision: 1.3 $ 00025 * $Name: fors-4_9_20 $ 00026 */ 00027 00028 #ifdef HAVE_CONFIG_H 00029 #include <config.h> 00030 #endif 00031 00032 #include <vimos_calib_impl.h> 00033 00034 #include <math.h> 00035 #include <cpl.h> 00036 #include <moses.h> 00037 #include <fors_dfs.h> 00038 #include <fors_qc.h> 00039 00040 #define vimos_calib_exit(message) \ 00041 { \ 00042 if (message !=NULL ) cpl_msg_error(recipe, message); \ 00043 cpl_free(instrume); \ 00044 cpl_free(pipefile); \ 00045 cpl_free(fiterror); \ 00046 cpl_free(fitlines); \ 00047 cpl_image_delete(bias); \ 00048 cpl_image_delete(master_bias); \ 00049 cpl_image_delete(coordinate); \ 00050 cpl_image_delete(checkwave); \ 00051 cpl_image_delete(flat); \ 00052 cpl_image_delete(master_flat); \ 00053 cpl_image_delete(norm_flat); \ 00054 cpl_image_delete(rainbow); \ 00055 cpl_image_delete(rectified); \ 00056 cpl_image_delete(residual); \ 00057 cpl_image_delete(smo_flat); \ 00058 cpl_image_delete(spatial); \ 00059 cpl_image_delete(spectra); \ 00060 cpl_image_delete(wavemap); \ 00061 cpl_image_delete(delta); \ 00062 cpl_mask_delete(refmask); \ 00063 cpl_propertylist_delete(header); \ 00064 cpl_propertylist_delete(save_header); \ 00065 cpl_propertylist_delete(qclist); \ 00066 cpl_table_delete(grism_table); \ 00067 cpl_table_delete(idscoeff); \ 00068 cpl_table_delete(restable); \ 00069 cpl_table_delete(maskslits); \ 00070 cpl_table_delete(overscans); \ 00071 cpl_table_delete(traces); \ 00072 cpl_table_delete(polytraces); \ 00073 cpl_table_delete(slits); \ 00074 cpl_table_delete(restab); \ 00075 cpl_table_delete(global); \ 00076 cpl_table_delete(wavelengths); \ 00077 cpl_vector_delete(lines); \ 00078 cpl_msg_indent_less(); \ 00079 return -1; \ 00080 } 00081 00082 #define vimos_calib_exit_memcheck(message) \ 00083 { \ 00084 if (message !=NULL ) cpl_msg_info(recipe, message); \ 00085 printf("free instrume (%p)\n", instrume); \ 00086 cpl_free(instrume); \ 00087 printf("free pipefile (%p)\n", pipefile); \ 00088 cpl_free(pipefile); \ 00089 printf("free fiterror (%p)\n", fiterror); \ 00090 cpl_free(fiterror); \ 00091 printf("free fitlines (%p)\n", fitlines); \ 00092 cpl_free(fitlines); \ 00093 printf("free bias (%p)\n", bias); \ 00094 cpl_image_delete(bias); \ 00095 printf("free master_bias (%p)\n", master_bias); \ 00096 cpl_image_delete(master_bias); \ 00097 printf("free coordinate (%p)\n", coordinate); \ 00098 cpl_image_delete(coordinate); \ 00099 printf("free checkwave (%p)\n", checkwave); \ 00100 cpl_image_delete(checkwave); \ 00101 printf("free flat (%p)\n", flat); \ 00102 cpl_image_delete(flat); \ 00103 printf("free master_flat (%p)\n", master_flat); \ 00104 cpl_image_delete(master_flat); \ 00105 printf("free norm_flat (%p)\n", norm_flat); \ 00106 cpl_image_delete(norm_flat); \ 00107 printf("free rainbow (%p)\n", rainbow); \ 00108 cpl_image_delete(rainbow); \ 00109 printf("free rectified (%p)\n", rectified); \ 00110 cpl_image_delete(rectified); \ 00111 printf("free residual (%p)\n", residual); \ 00112 cpl_image_delete(residual); \ 00113 printf("free smo_flat (%p)\n", smo_flat); \ 00114 cpl_image_delete(smo_flat); \ 00115 printf("free spatial (%p)\n", spatial); \ 00116 cpl_image_delete(spatial); \ 00117 printf("free spectra (%p)\n", spectra); \ 00118 cpl_image_delete(spectra); \ 00119 printf("free wavemap (%p)\n", wavemap); \ 00120 cpl_image_delete(wavemap); \ 00121 printf("free delta (%p)\n", delta); \ 00122 cpl_image_delete(delta); \ 00123 printf("free refmask (%p)\n", refmask); \ 00124 cpl_mask_delete(refmask); \ 00125 printf("free header (%p)\n", header); \ 00126 cpl_propertylist_delete(header); \ 00127 printf("free save_header (%p)\n", save_header); \ 00128 cpl_propertylist_delete(save_header); \ 00129 printf("free qclist (%p)\n", qclist); \ 00130 cpl_propertylist_delete(qclist); \ 00131 printf("free grism_table (%p)\n", grism_table); \ 00132 cpl_table_delete(grism_table); \ 00133 printf("free idscoeff (%p)\n", idscoeff); \ 00134 cpl_table_delete(idscoeff); \ 00135 printf("free restable (%p)\n", restable); \ 00136 cpl_table_delete(restable); \ 00137 printf("free maskslits (%p)\n", maskslits); \ 00138 cpl_table_delete(maskslits); \ 00139 printf("free overscans (%p)\n", overscans); \ 00140 cpl_table_delete(overscans); \ 00141 printf("free traces (%p)\n", traces); \ 00142 cpl_table_delete(traces); \ 00143 printf("free polytraces (%p)\n", polytraces); \ 00144 cpl_table_delete(polytraces); \ 00145 printf("free slits (%p)\n", slits); \ 00146 cpl_table_delete(slits); \ 00147 printf("free restab (%p)\n", restab); \ 00148 cpl_table_delete(restab); \ 00149 printf("free global (%p)\n", global); \ 00150 cpl_table_delete(global); \ 00151 printf("free wavelengths (%p)\n", wavelengths); \ 00152 cpl_table_delete(wavelengths); \ 00153 printf("free lines (%p)\n", lines); \ 00154 cpl_vector_delete(lines); \ 00155 cpl_msg_indent_less(); \ 00156 return 0; \ 00157 } 00158 00174 int vimos_calib_impl(cpl_frameset *frameset, cpl_parameterlist *parlist) 00175 { 00176 00177 const char *recipe = "vimos_calib"; 00178 00179 /* 00180 * Input parameters 00181 */ 00182 00183 double dispersion; 00184 double peakdetection; 00185 int wdegree; 00186 int wradius; 00187 double wreject; 00188 int wmode; 00189 const char *wcolumn; 00190 int cdegree; 00191 int cmode; 00192 double startwavelength; 00193 double endwavelength; 00194 double reference; 00195 int slit_ident; 00196 int sdegree; 00197 int ddegree; 00198 int sradius; 00199 int dradius; 00200 int qc; 00201 int check; 00202 00203 /* 00204 * CPL objects 00205 */ 00206 00207 cpl_imagelist *biases = NULL; 00208 cpl_image *bias = NULL; 00209 cpl_image *master_bias = NULL; 00210 cpl_image *multi_bias = NULL; 00211 cpl_image *flat = NULL; 00212 cpl_image *master_flat = NULL; 00213 cpl_image *smo_flat = NULL; 00214 cpl_image *norm_flat = NULL; 00215 cpl_image *spectra = NULL; 00216 cpl_image *wavemap = NULL; 00217 cpl_image *delta = NULL; 00218 cpl_image *residual = NULL; 00219 cpl_image *checkwave = NULL; 00220 cpl_image *rectified = NULL; 00221 cpl_image *dummy = NULL; 00222 cpl_image *refimage = NULL; 00223 cpl_image *coordinate = NULL; 00224 cpl_image *rainbow = NULL; 00225 cpl_image *spatial = NULL; 00226 00227 cpl_mask *refmask = NULL; 00228 00229 cpl_table *grism_table = NULL; 00230 cpl_table *overscans = NULL; 00231 cpl_table *wavelengths = NULL; 00232 cpl_table *idscoeff = NULL; 00233 cpl_table *restable = NULL; 00234 cpl_table *slits = NULL; 00235 cpl_table *positions = NULL; 00236 cpl_table *maskslits = NULL; 00237 cpl_table *traces = NULL; 00238 cpl_table *polytraces = NULL; 00239 cpl_table *restab = NULL; 00240 cpl_table *global = NULL; 00241 00242 cpl_vector *lines = NULL; 00243 00244 cpl_propertylist *header = NULL; 00245 cpl_propertylist *save_header = NULL; 00246 cpl_propertylist *qclist = NULL; 00247 00248 /* 00249 * Auxiliary variables 00250 */ 00251 00252 cpl_table *idscoeff_lss = NULL; 00253 char version[80]; 00254 const char *arc_tag; 00255 const char *flat_tag; 00256 const char *master_screen_flat_tag; 00257 const char *master_norm_flat_tag; 00258 const char *reduced_lamp_tag; 00259 const char *disp_residuals_tag; 00260 const char *disp_coeff_tag; 00261 const char *wavelength_map_tag; 00262 const char *spectra_detection_tag; 00263 const char *spectral_resolution_tag; 00264 const char *slit_map_tag; 00265 const char *curv_traces_tag; 00266 const char *curv_coeff_tag; 00267 const char *spatial_map_tag; 00268 const char *slit_location_tag; 00269 const char *global_distortion_tag = "GLOBAL_DISTORTION_TABLE"; 00270 const char *disp_residuals_table_tag; 00271 const char *delta_image_tag; 00272 const char *key_gris_name; 00273 const char *key_gris_id; 00274 const char *key_filt_name; 00275 const char *key_filt_id; 00276 const char *key_mask_id; 00277 char *keyname; 00278 int quadrant; 00279 int mos; 00280 int treat_as_lss = 0; 00281 int nslits; 00282 double *xpos; 00283 double mxpos; 00284 double mean_rms; 00285 double alltime, arctime; 00286 int nflats; 00287 int nbias; 00288 int nlines; 00289 double *line; 00290 double *fiterror = NULL; 00291 int *fitlines = NULL; 00292 int nx, ny; 00293 double gain; 00294 int ccd_xsize, ccd_ysize; 00295 int rotate = 1; 00296 int rotate_back = -1; 00297 int i; 00298 00299 char *instrume = NULL; 00300 char *pipefile = NULL; 00301 char *grism; 00302 00303 00304 snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION); 00305 00306 cpl_msg_set_indentation(2); 00307 00308 if (dfs_files_dont_exist(frameset)) 00309 vimos_calib_exit(NULL); 00310 00311 00312 /* 00313 * Get configuration parameters 00314 */ 00315 00316 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe); 00317 cpl_msg_indent_more(); 00318 00319 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1) 00320 vimos_calib_exit("Too many in input: GRISM_TABLE"); 00321 00322 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1); 00323 00324 dispersion = dfs_get_parameter_double(parlist, 00325 "fors.vimos_calib.dispersion", grism_table); 00326 00327 if (dispersion <= 0.0) 00328 vimos_calib_exit("Invalid spectral dispersion value"); 00329 00330 peakdetection = dfs_get_parameter_double(parlist, 00331 "fors.vimos_calib.peakdetection", grism_table); 00332 if (peakdetection <= 0.0) 00333 vimos_calib_exit("Invalid peak detection level"); 00334 00335 wdegree = dfs_get_parameter_int(parlist, 00336 "fors.vimos_calib.wdegree", grism_table); 00337 00338 if (wdegree < 1) 00339 vimos_calib_exit("Invalid polynomial degree"); 00340 00341 if (wdegree > 5) 00342 vimos_calib_exit("Max allowed polynomial degree is 5"); 00343 00344 wradius = dfs_get_parameter_int(parlist, "fors.vimos_calib.wradius", NULL); 00345 00346 if (wradius < 0) 00347 vimos_calib_exit("Invalid search radius"); 00348 00349 wreject = dfs_get_parameter_double(parlist, 00350 "fors.vimos_calib.wreject", NULL); 00351 00352 if (wreject <= 0.0) 00353 vimos_calib_exit("Invalid rejection threshold"); 00354 00355 wmode = dfs_get_parameter_int(parlist, "fors.vimos_calib.wmode", NULL); 00356 00357 if (wmode < 0 || wmode > 2) 00358 vimos_calib_exit("Invalid wavelength solution interpolation mode"); 00359 00360 wcolumn = dfs_get_parameter_string(parlist, 00361 "fors.vimos_calib.wcolumn", NULL); 00362 00363 cdegree = dfs_get_parameter_int(parlist, 00364 "fors.vimos_calib.cdegree", grism_table); 00365 00366 if (cdegree < 1) 00367 vimos_calib_exit("Invalid polynomial degree"); 00368 00369 if (cdegree > 5) 00370 vimos_calib_exit("Max allowed polynomial degree is 5"); 00371 00372 cmode = dfs_get_parameter_int(parlist, "fors.vimos_calib.cmode", NULL); 00373 00374 if (cmode < 0 || cmode > 2) 00375 vimos_calib_exit("Invalid curvature solution interpolation mode"); 00376 00377 startwavelength = dfs_get_parameter_double(parlist, 00378 "fors.vimos_calib.startwavelength", grism_table); 00379 if (startwavelength > 1.0) 00380 if (startwavelength < 3000.0 || startwavelength > 13000.0) 00381 vimos_calib_exit("Invalid wavelength"); 00382 00383 endwavelength = dfs_get_parameter_double(parlist, 00384 "fors.vimos_calib.endwavelength", grism_table); 00385 if (endwavelength > 1.0) { 00386 if (endwavelength < 3000.0 || endwavelength > 13000.0) 00387 vimos_calib_exit("Invalid wavelength"); 00388 if (startwavelength < 1.0) 00389 vimos_calib_exit("Invalid wavelength interval"); 00390 } 00391 00392 if (startwavelength > 1.0) 00393 if (endwavelength - startwavelength <= 0.0) 00394 vimos_calib_exit("Invalid wavelength interval"); 00395 00396 reference = dfs_get_parameter_double(parlist, 00397 "fors.vimos_calib.reference", grism_table); 00398 00399 if (reference < startwavelength || reference > endwavelength) 00400 vimos_calib_exit("Invalid reference wavelength"); 00401 00402 slit_ident = dfs_get_parameter_bool(parlist, 00403 "fors.vimos_calib.slit_ident", NULL); 00404 00405 sdegree = dfs_get_parameter_int(parlist, "fors.vimos_calib.sdegree", NULL); 00406 ddegree = dfs_get_parameter_int(parlist, "fors.vimos_calib.ddegree", NULL); 00407 sradius = dfs_get_parameter_int(parlist, "fors.vimos_calib.sradius", NULL); 00408 dradius = dfs_get_parameter_int(parlist, "fors.vimos_calib.dradius", NULL); 00409 00410 if (sradius < 1 || dradius < 1) 00411 vimos_calib_exit("Invalid smoothing box radius"); 00412 00413 qc = dfs_get_parameter_bool(parlist, "fors.vimos_calib.qc", NULL); 00414 00415 check = dfs_get_parameter_bool(parlist, "fors.vimos_calib.check", NULL); 00416 00417 cpl_table_delete(grism_table); grism_table = NULL; 00418 00419 if (cpl_error_get_code()) 00420 vimos_calib_exit("Failure getting the configuration parameters"); 00421 00422 00423 /* 00424 * Check input set-of-frames 00425 */ 00426 00427 cpl_msg_indent_less(); 00428 cpl_msg_info(recipe, "Check input set-of-frames:"); 00429 cpl_msg_indent_more(); 00430 00431 if (!dfs_equal_keyword(frameset, "ESO OCS CON QUAD")) 00432 vimos_calib_exit("Input frames are not from the same quadrant"); 00433 00434 mos = cpl_frameset_count_tags(frameset, "MOS_ARC_SPECTRUM"); 00435 00436 if (mos == 0) 00437 vimos_calib_exit("Missing input arc lamp frame"); 00438 00439 if (mos > 1) 00440 vimos_calib_exit("Just one input arc lamp frame is allowed"); 00441 00442 arc_tag = "MOS_ARC_SPECTRUM"; 00443 flat_tag = "MOS_SCREEN_FLAT"; 00444 master_screen_flat_tag = "MOS_COMBINED_SCREEN_FLAT"; 00445 master_norm_flat_tag = "MOS_MASTER_SCREEN_FLAT"; 00446 reduced_lamp_tag = "MOS_ARC_SPECTRUM_EXTRACTED"; 00447 disp_residuals_tag = "MOS_DISP_RESIDUALS"; 00448 disp_coeff_tag = "MOS_DISP_COEFF"; 00449 wavelength_map_tag = "MOS_WAVELENGTH_MAP"; 00450 spectra_detection_tag = "MOS_SPECTRA_DETECTION"; 00451 spectral_resolution_tag = "MOS_SPECTRAL_RESOLUTION"; 00452 slit_map_tag = "MOS_SLIT_MAP"; 00453 curv_traces_tag = "MOS_CURV_TRACES"; 00454 curv_coeff_tag = "MOS_CURV_COEFF"; 00455 spatial_map_tag = "MOS_SPATIAL_MAP"; 00456 slit_location_tag = "MOS_SLIT_LOCATION"; 00457 disp_residuals_table_tag = "MOS_DISP_RESIDUALS_TABLE"; 00458 delta_image_tag = "MOS_DELTA_IMAGE"; 00459 00460 nbias = 0; 00461 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0) { 00462 if (cpl_frameset_count_tags(frameset, "BIAS") == 0) 00463 vimos_calib_exit("Missing required input: MASTER_BIAS or BIAS"); 00464 nbias = cpl_frameset_count_tags(frameset, "BIAS"); 00465 } 00466 00467 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1) 00468 vimos_calib_exit("Too many in input: MASTER_BIAS"); 00469 00470 if (cpl_frameset_count_tags(frameset, "LINE_CATALOG") == 0) 00471 vimos_calib_exit("Missing required input: LINE_CATALOG"); 00472 00473 if (cpl_frameset_count_tags(frameset, "LINE_CATALOG") > 1) 00474 vimos_calib_exit("Too many in input: LINE_CATALOG"); 00475 00476 nflats = cpl_frameset_count_tags(frameset, flat_tag); 00477 00478 if (nflats < 1) { 00479 cpl_msg_error(recipe, "Missing required input: %s", flat_tag); 00480 vimos_calib_exit(NULL); 00481 } 00482 00483 cpl_msg_indent_less(); 00484 00485 if (nflats > 1) 00486 cpl_msg_info(recipe, "Load %d flat field frames and sum them...", 00487 nflats); 00488 else 00489 cpl_msg_info(recipe, "Load flat field exposure..."); 00490 00491 cpl_msg_indent_more(); 00492 00493 header = dfs_load_header(frameset, flat_tag, 0); 00494 00495 if (header == NULL) 00496 vimos_calib_exit("Cannot load flat field frame header"); 00497 00498 alltime = cpl_propertylist_get_double(header, "EXPTIME"); 00499 00500 if (cpl_error_get_code() != CPL_ERROR_NONE) 00501 vimos_calib_exit("Missing keyword EXPTIME in flat field frame header"); 00502 00503 cpl_propertylist_delete(header); 00504 00505 for (i = 1; i < nflats; i++) { 00506 00507 header = dfs_load_header(frameset, NULL, 0); 00508 00509 if (header == NULL) 00510 vimos_calib_exit("Cannot load flat field frame header"); 00511 00512 alltime += cpl_propertylist_get_double(header, "EXPTIME"); 00513 00514 if (cpl_error_get_code() != CPL_ERROR_NONE) 00515 vimos_calib_exit("Missing keyword EXPTIME in flat field " 00516 "frame header"); 00517 00518 cpl_propertylist_delete(header); 00519 00520 } 00521 00522 master_flat = dfs_load_image(frameset, flat_tag, CPL_TYPE_FLOAT, 0, 0); 00523 00524 if (master_flat == NULL) 00525 vimos_calib_exit("Cannot load flat field"); 00526 00527 for (i = 1; i < nflats; i++) { 00528 flat = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0); 00529 if (flat) { 00530 cpl_image_add(master_flat, flat); 00531 cpl_image_delete(flat); flat = NULL; 00532 } 00533 else 00534 vimos_calib_exit("Cannot load flat field"); 00535 } 00536 00537 00538 /* 00539 * Get some info from arc lamp header 00540 */ 00541 00542 header = dfs_load_header(frameset, arc_tag, 0); 00543 00544 if (header == NULL) 00545 vimos_calib_exit("Cannot load arc lamp header"); 00546 00547 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME"); 00548 if (instrume == NULL) 00549 vimos_calib_exit("Missing keyword INSTRUME in arc lamp header"); 00550 instrume = cpl_strdup(instrume); 00551 00552 arctime = cpl_propertylist_get_double(header, "EXPTIME"); 00553 00554 quadrant = cpl_propertylist_get_int(header, "ESO OCS CON QUAD"); 00555 00556 switch (quadrant) { 00557 case 1: 00558 key_gris_name = "ESO INS GRIS1 NAME"; 00559 key_gris_id = "ESO INS GRIS1 ID"; 00560 key_filt_name = "ESO INS FILT1 NAME"; 00561 key_filt_id = "ESO INS FILT1 ID"; 00562 key_mask_id = "ESO INS MASK1 ID"; 00563 break; 00564 case 2: 00565 key_gris_name = "ESO INS GRIS2 NAME"; 00566 key_gris_id = "ESO INS GRIS2 ID"; 00567 key_filt_name = "ESO INS FILT2 NAME"; 00568 key_filt_id = "ESO INS FILT2 ID"; 00569 key_mask_id = "ESO INS MASK2 ID"; 00570 break; 00571 case 3: 00572 key_gris_name = "ESO INS GRIS3 NAME"; 00573 key_gris_id = "ESO INS GRIS3 ID"; 00574 key_filt_name = "ESO INS FILT3 NAME"; 00575 key_filt_id = "ESO INS FILT3 ID"; 00576 key_mask_id = "ESO INS MASK3 ID"; 00577 break; 00578 case 4: 00579 key_gris_name = "ESO INS GRIS4 NAME"; 00580 key_gris_id = "ESO INS GRIS4 ID"; 00581 key_filt_name = "ESO INS FILT4 NAME"; 00582 key_filt_id = "ESO INS FILT4 ID"; 00583 key_mask_id = "ESO INS MASK4 ID"; 00584 break; 00585 } 00586 00587 grism = cpl_strdup(cpl_propertylist_get_string(header, key_gris_name)); 00588 00589 if (cpl_error_get_code() != CPL_ERROR_NONE) 00590 vimos_calib_exit("Missing keyword ESO INS GRISn NAME in arc lamp " 00591 "frame header"); 00592 00593 cpl_msg_info(recipe, "The grism is: %s", grism); 00594 00595 /* 00596 if (!dfs_equal_keyword(frameset, key_gris_id)) 00597 vimos_calib_exit("Input frames are not from the same grism"); 00598 00599 if (!dfs_equal_keyword(frameset, key_filt_id)) 00600 vimos_calib_exit("Input frames are not from the same filter"); 00601 */ 00602 00603 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD"); 00604 00605 if (cpl_error_get_code() != CPL_ERROR_NONE) 00606 vimos_calib_exit("Missing keyword ESO DET OUT1 CONAD in arc lamp " 00607 "frame header"); 00608 00609 cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain); 00610 00611 cpl_msg_info(recipe, "Produce mask slit position table..."); 00612 00613 maskslits = mos_load_slits_vimos(header); 00614 00615 /* 00616 * Check if all slits have the same X offset: in such case, 00617 * treat the observation as a long-slit one! 00618 */ 00619 00620 mxpos = cpl_table_get_column_median(maskslits, "ytop"); 00621 xpos = cpl_table_get_data_double(maskslits, "ytop"); 00622 nslits = cpl_table_get_nrow(maskslits); 00623 00624 treat_as_lss = 1; 00625 for (i = 0; i < nslits; i++) { 00626 if (fabs(mxpos-xpos[i]) > 0.01) { 00627 treat_as_lss = 0; 00628 break; 00629 } 00630 } 00631 00632 if (treat_as_lss) { 00633 cpl_msg_warning(recipe, "All MOS slits have the same offset: %.2f\n" 00634 "The long-slit data reduction strategy is applied!", 00635 mxpos); 00636 cpl_table_delete(maskslits); maskslits = NULL; 00637 } 00638 00639 if (slit_ident == 0) { 00640 cpl_table_delete(maskslits); maskslits = NULL; 00641 } 00642 00643 00644 /* Leave the header on for the next step... */ 00645 00646 00647 /* 00648 * Remove the master bias 00649 */ 00650 00651 if (nbias) { 00652 00653 /* 00654 * Set of raw BIASes in input, need to create master bias! 00655 */ 00656 00657 cpl_msg_info(recipe, "Generate the master from input raw biases..."); 00658 00659 if (nbias > 1) { 00660 00661 biases = cpl_imagelist_new(); 00662 00663 bias = dfs_load_image(frameset, "BIAS", CPL_TYPE_FLOAT, 0, 0); 00664 00665 if (bias == NULL) 00666 vimos_calib_exit("Cannot load bias frame"); 00667 00668 cpl_imagelist_set(biases, bias, 0); bias = NULL; 00669 00670 for (i = 1; i < nbias; i++) { 00671 bias = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0); 00672 if (bias) { 00673 cpl_imagelist_set(biases, bias, i); bias = NULL; 00674 } 00675 else 00676 vimos_calib_exit("Cannot load bias frame"); 00677 } 00678 00679 master_bias = cpl_imagelist_collapse_median_create(biases); 00680 00681 cpl_imagelist_delete(biases); 00682 } 00683 else 00684 master_bias = dfs_load_image(frameset, "BIAS", 00685 CPL_TYPE_FLOAT, 0, 1); 00686 00687 } 00688 else { 00689 master_bias = dfs_load_image(frameset, "MASTER_BIAS", 00690 CPL_TYPE_FLOAT, 0, 1); 00691 if (master_bias == NULL) 00692 vimos_calib_exit("Cannot load master bias"); 00693 } 00694 00695 cpl_msg_info(recipe, "Remove the master bias..."); 00696 00697 overscans = mos_load_overscans_vimos(header, 1); 00698 cpl_propertylist_delete(header); header = NULL; 00699 00700 if (nbias) { 00701 int xlow = cpl_table_get_int(overscans, "xlow", 0, NULL); 00702 int ylow = cpl_table_get_int(overscans, "ylow", 0, NULL); 00703 int xhig = cpl_table_get_int(overscans, "xhig", 0, NULL); 00704 int yhig = cpl_table_get_int(overscans, "yhig", 0, NULL); 00705 dummy = cpl_image_extract(master_bias, xlow+1, ylow+1, xhig, yhig); 00706 cpl_image_delete(master_bias); master_bias = dummy; 00707 00708 if (dfs_save_image(frameset, master_bias, "MASTER_BIAS", 00709 NULL, parlist, recipe, version)) 00710 vimos_calib_exit(NULL); 00711 } 00712 00713 if (nflats > 1) { 00714 multi_bias = cpl_image_multiply_scalar_create(master_bias, nflats); 00715 dummy = mos_remove_bias(master_flat, multi_bias, overscans); 00716 cpl_image_delete(multi_bias); 00717 } 00718 else { 00719 dummy = mos_remove_bias(master_flat, master_bias, overscans); 00720 } 00721 cpl_image_delete(master_flat); 00722 master_flat = dummy; 00723 00724 if (master_flat == NULL) 00725 vimos_calib_exit("Cannot remove bias from flat field"); 00726 00727 cpl_msg_indent_less(); 00728 cpl_msg_info(recipe, "Load arc lamp exposure..."); 00729 cpl_msg_indent_more(); 00730 00731 spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0); 00732 00733 if (spectra == NULL) 00734 vimos_calib_exit("Cannot load arc lamp exposure"); 00735 00736 cpl_msg_info(recipe, "Remove the master bias..."); 00737 00738 dummy = mos_remove_bias(spectra, master_bias, overscans); 00739 cpl_table_delete(overscans); overscans = NULL; 00740 cpl_image_delete(master_bias); master_bias = NULL; 00741 cpl_image_delete(spectra); spectra = dummy; 00742 00743 if (spectra == NULL) 00744 vimos_calib_exit("Cannot remove bias from arc lamp exposure"); 00745 00746 cpl_msg_indent_less(); 00747 cpl_msg_info(recipe, "Load input line catalog..."); 00748 cpl_msg_indent_more(); 00749 00750 wavelengths = dfs_load_table(frameset, "LINE_CATALOG", 1); 00751 00752 if (wavelengths == NULL) 00753 vimos_calib_exit("Cannot load line catalog"); 00754 00755 00756 /* 00757 * Cast the wavelengths into a (double precision) CPL vector 00758 */ 00759 00760 nlines = cpl_table_get_nrow(wavelengths); 00761 00762 if (nlines == 0) 00763 vimos_calib_exit("Empty input line catalog"); 00764 00765 if (cpl_table_has_column(wavelengths, wcolumn) != 1) { 00766 cpl_msg_error(recipe, "Missing column %s in input line catalog table", 00767 wcolumn); 00768 vimos_calib_exit(NULL); 00769 } 00770 00771 line = cpl_malloc(nlines * sizeof(double)); 00772 00773 for (i = 0; i < nlines; i++) 00774 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL); 00775 00776 cpl_table_delete(wavelengths); wavelengths = NULL; 00777 00778 lines = cpl_vector_wrap(nlines, line); 00779 00780 00781 /* 00782 * Rotate frames horizontally with red to the right 00783 */ 00784 00785 cpl_image_turn(spectra, rotate); 00786 cpl_image_turn(master_flat, rotate); 00787 00788 ccd_xsize = nx = cpl_image_get_size_x(spectra); // added... 00789 ccd_ysize = ny = cpl_image_get_size_y(spectra); 00790 00791 if (treat_as_lss) { 00792 00793 /* 00794 * In the case of LSS data, find first a "one slit" 00795 * solution. This will be later on split into many-slits 00796 * solutions. This is done for greater accuracy. 00797 */ 00798 00799 cpl_msg_indent_less(); 00800 cpl_msg_info(recipe, "Perform wavelength calibration..."); 00801 cpl_msg_indent_more(); 00802 00803 wavemap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 00804 if (check) 00805 residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 00806 00807 fiterror = cpl_calloc(ny, sizeof(double)); 00808 fitlines = cpl_calloc(ny, sizeof(int)); 00809 idscoeff = cpl_table_new(ny); 00810 refmask = cpl_mask_new(nx, ny); 00811 00812 if (mos_saturation_process(spectra)) 00813 vimos_calib_exit("Cannot process saturation"); 00814 00815 if (mos_subtract_background(spectra)) 00816 vimos_calib_exit("Cannot subtract the background"); 00817 00818 rectified = mos_wavelength_calibration_raw(spectra, lines, dispersion, 00819 peakdetection, wradius, 00820 wdegree, wreject, reference, 00821 &startwavelength, 00822 &endwavelength, fitlines, 00823 fiterror, idscoeff, wavemap, 00824 residual, NULL, refmask); 00825 00826 if (rectified == NULL) 00827 vimos_calib_exit("Wavelength calibration failure."); 00828 00829 if (!cpl_table_has_valid(idscoeff, "c0")) 00830 vimos_calib_exit("Wavelength calibration failure."); 00831 00832 /* 00833 * This is necessary to move on to a many-slits solution 00834 */ 00835 00836 mos_refmask_find_gaps(refmask, master_flat, 1000.); 00837 00838 if (wmode) { 00839 cpl_image_delete(rectified); rectified = NULL; 00840 cpl_image_delete(wavemap); wavemap = NULL; 00841 mos_interpolate_wavecalib(idscoeff, wavemap, wmode); 00842 wavemap = mos_map_idscoeff(idscoeff, nx, reference, 00843 startwavelength, endwavelength); 00844 rectified = mos_wavelength_calibration(spectra, reference, 00845 startwavelength, 00846 endwavelength, dispersion, 00847 idscoeff, 0); 00848 } 00849 00850 cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL; 00851 cpl_table_set_column_unit(idscoeff, "error", "pixel"); 00852 cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL; 00853 00854 for (i = 0; i < ny; i++) 00855 if (!cpl_table_is_valid(idscoeff, "c0", i)) 00856 cpl_table_set_invalid(idscoeff, "error", i); 00857 00858 slit_ident = 0; 00859 idscoeff_lss = idscoeff; 00860 00861 } 00862 else { 00863 00864 /* 00865 * Here the generic MOS calibration is carried out. 00866 */ 00867 00868 /* 00869 * Detecting spectra on the CCD 00870 */ 00871 00872 cpl_msg_indent_less(); 00873 cpl_msg_info(recipe, "Detecting spectra on CCD..."); 00874 cpl_msg_indent_more(); 00875 00876 ccd_xsize = nx = cpl_image_get_size_x(spectra); 00877 ccd_ysize = ny = cpl_image_get_size_y(spectra); 00878 00879 refmask = cpl_mask_new(nx, ny); 00880 00881 if (mos_saturation_process(spectra)) 00882 vimos_calib_exit("Cannot process saturation"); 00883 00884 if (mos_subtract_background(spectra)) 00885 vimos_calib_exit("Cannot subtract the background"); 00886 00887 checkwave = mos_wavelength_calibration_raw(spectra, lines, dispersion, 00888 peakdetection, wradius, 00889 wdegree, wreject, reference, 00890 &startwavelength, 00891 &endwavelength, 00892 NULL, NULL, NULL, NULL, 00893 NULL, NULL, refmask); 00894 00895 if (checkwave == NULL) 00896 vimos_calib_exit("Wavelength calibration failure."); 00897 00898 /* 00899 * Save check image to disk 00900 */ 00901 00902 header = cpl_propertylist_new(); 00903 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 00904 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 00905 cpl_propertylist_update_double(header, "CRVAL1", 00906 startwavelength + dispersion/2); 00907 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 00908 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 00909 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 00910 cpl_propertylist_update_double(header, "CD1_1", dispersion); 00911 cpl_propertylist_update_double(header, "CD1_2", 0.0); 00912 cpl_propertylist_update_double(header, "CD2_1", 0.0); 00913 cpl_propertylist_update_double(header, "CD2_2", 1.0); 00914 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 00915 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 00916 00917 if (check) { 00918 if (dfs_save_image(frameset, checkwave, spectra_detection_tag, 00919 header, parlist, recipe, version)) 00920 vimos_calib_exit(NULL); 00921 } 00922 00923 cpl_image_delete(checkwave); checkwave = NULL; 00924 cpl_propertylist_delete(header); header = NULL; 00925 00926 } 00927 00928 cpl_msg_info(recipe, "Locate slits at reference wavelength on CCD..."); 00929 slits = mos_locate_spectra(refmask); 00930 00931 if (!slits) { 00932 cpl_msg_error(cpl_error_get_where(), cpl_error_get_message()); 00933 vimos_calib_exit("No slits could be detected!"); 00934 } 00935 00936 refimage = cpl_image_new_from_mask(refmask); 00937 cpl_mask_delete(refmask); refmask = NULL; 00938 00939 if (check) { 00940 save_header = dfs_load_header(frameset, arc_tag, 0); 00941 cpl_image_turn(refimage, rotate_back); 00942 if (dfs_save_image(frameset, refimage, slit_map_tag, NULL, 00943 parlist, recipe, version)) 00944 vimos_calib_exit(NULL); 00945 cpl_propertylist_delete(save_header); save_header = NULL; 00946 } 00947 00948 cpl_image_delete(refimage); refimage = NULL; 00949 00950 if (slit_ident) { 00951 00952 /* 00953 * Attempt slit identification: this recipe may continue even 00954 * in case of failed identification (i.e., the position table is 00955 * not produced, but an error is not set). In case of failure, 00956 * the spectra would be still extracted, even if they would not 00957 * be associated to slits on the mask. 00958 * 00959 * The reason for making the slit identification an user option 00960 * (via the parameter slit_ident) is to offer the possibility 00961 * to avoid identifications that are only apparently successful, 00962 * as it would happen in the case of an incorrect slit description 00963 * in the data header. 00964 */ 00965 00966 cpl_msg_indent_less(); 00967 cpl_msg_info(recipe, "Attempt slit identification (optional)..."); 00968 cpl_msg_indent_more(); 00969 00970 mos_rotate_slits(maskslits, -rotate, 0, 0); 00971 positions = mos_identify_slits(slits, maskslits, NULL); 00972 00973 if (positions) { 00974 cpl_table_delete(slits); 00975 slits = positions; 00976 00977 /* 00978 * Eliminate slits which are _entirely_ outside the CCD 00979 */ 00980 00981 cpl_table_and_selected_double(slits, 00982 "ybottom", CPL_GREATER_THAN, ny-1); 00983 cpl_table_or_selected_double(slits, 00984 "ytop", CPL_LESS_THAN, 0); 00985 cpl_table_erase_selected(slits); 00986 00987 nslits = cpl_table_get_nrow(slits); 00988 00989 if (nslits == 0) 00990 vimos_calib_exit("No slits found on the CCD"); 00991 00992 cpl_msg_info(recipe, "%d slits are entirely or partially " 00993 "contained in CCD", nslits); 00994 00995 } 00996 else { 00997 slit_ident = 0; 00998 cpl_msg_info(recipe, "Global distortion model cannot be computed"); 00999 if (cpl_error_get_code() != CPL_ERROR_NONE) { 01000 vimos_calib_exit(NULL); 01001 } 01002 } 01003 } 01004 01005 01006 /* 01007 * Determination of spectral curvature 01008 */ 01009 01010 cpl_msg_indent_less(); 01011 cpl_msg_info(recipe, "Determining spectral curvature..."); 01012 cpl_msg_indent_more(); 01013 01014 cpl_msg_info(recipe, "Tracing master flat field spectra edges..."); 01015 traces = mos_trace_flat(master_flat, slits, reference, 01016 startwavelength, endwavelength, dispersion); 01017 01018 if (!traces) 01019 vimos_calib_exit("Tracing failure"); 01020 01021 cpl_msg_info(recipe, "Fitting flat field spectra edges..."); 01022 polytraces = mos_poly_trace(slits, traces, cdegree); 01023 01024 if (!polytraces) 01025 vimos_calib_exit("Trace fitting failure"); 01026 01027 if (cmode) { 01028 cpl_msg_info(recipe, "Computing global spectral curvature model..."); 01029 mos_global_trace(slits, polytraces, cmode); 01030 } 01031 01032 if (dfs_save_table(frameset, traces, curv_traces_tag, NULL, parlist, 01033 recipe, version)) 01034 vimos_calib_exit(NULL); 01035 01036 cpl_table_delete(traces); traces = NULL; 01037 01038 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01039 spatial = mos_spatial_calibration(spectra, slits, polytraces, reference, 01040 startwavelength, endwavelength, 01041 dispersion, 0, coordinate); 01042 01043 // if (!slit_ident) { 01044 // cpl_image_delete(spectra); spectra = NULL; 01045 // } 01046 01047 /* 01048 * Flat field normalisation is done directly on the master flat 01049 * field (without spatial rectification first). The spectral 01050 * curvature model may be provided in input, in future releases. 01051 */ 01052 01053 cpl_msg_indent_less(); 01054 cpl_msg_info(recipe, "Perform flat field normalisation..."); 01055 cpl_msg_indent_more(); 01056 01057 norm_flat = cpl_image_duplicate(master_flat); 01058 01059 smo_flat = mos_normalise_flat(norm_flat, coordinate, slits, polytraces, 01060 reference, startwavelength, endwavelength, 01061 dispersion, dradius, ddegree); 01062 01063 cpl_image_delete(smo_flat); smo_flat = NULL; /* It may be a product */ 01064 01065 save_header = dfs_load_header(frameset, flat_tag, 0); 01066 cpl_propertylist_update_int(save_header, "ESO PRO DATANCOM", nflats); 01067 01068 cpl_image_turn(norm_flat, rotate_back); 01069 01070 if (dfs_save_image(frameset, norm_flat, master_norm_flat_tag, 01071 save_header, parlist, recipe, version)) 01072 vimos_calib_exit(NULL); 01073 01074 cpl_image_delete(norm_flat); norm_flat = NULL; 01075 01076 01077 /* 01078 * QC parameters for flat 01079 */ 01080 01081 if (qc) { 01082 double scale; 01083 double slit_width; 01084 double flux, flux_err; 01085 int cslit = mos_slit_closest_to_center(slits, nx, ny); 01086 01087 01088 /* 01089 * Refresh base property list, because previous saving 01090 * modified it - e.g., the keyword ARCFILE is missing 01091 */ 01092 01093 cpl_propertylist_delete(save_header); 01094 save_header = dfs_load_header(frameset, flat_tag, 0); 01095 cpl_propertylist_update_int(save_header, "ESO PRO DATANCOM", nflats); 01096 01097 01098 /* 01099 * QC1 group header 01100 */ 01101 01102 fors_qc_start_group(save_header, "1.1", instrume); 01103 01104 if (fors_qc_write_string("PRO.CATG", master_norm_flat_tag, 01105 "Product category", instrume)) 01106 vimos_calib_exit("Cannot write product category to QC log file"); 01107 01108 if (fors_qc_keyword_to_paf(save_header, "ARCFILE", NULL, 01109 "Archive File Name", instrume)) 01110 vimos_calib_exit("Missing keyword ARCFILE in flatfield frame"); 01111 01112 if (fors_qc_keyword_to_paf(save_header, "ESO TPL ID", NULL, 01113 "Template signature ID", instrume)) 01114 vimos_calib_exit("Missing keyword TPL ID in flatfield frame"); 01115 01116 if (fors_qc_keyword_to_paf(save_header, "ESO OCS CON QUAD", NULL, 01117 "Quadrant", instrume)) 01118 vimos_calib_exit("Missing keyword OCS CON QUAD in flatfield frame"); 01119 01120 if (fors_qc_keyword_to_paf(save_header, key_filt_name, NULL, 01121 "Filter", instrume)) { 01122 cpl_msg_error(recipe, "Missing keyword %s in flatfield frame", 01123 key_filt_name); 01124 vimos_calib_exit(NULL); 01125 } 01126 01127 if (fors_qc_keyword_to_paf(save_header, key_gris_name, NULL, 01128 "Grism", instrume)) { 01129 cpl_msg_error(recipe, "Missing keyword %s in flatfield frame", 01130 key_gris_name); 01131 vimos_calib_exit(NULL); 01132 } 01133 01134 if (fors_qc_keyword_to_paf(save_header, key_mask_id, NULL, 01135 "Mask", instrume)) { 01136 cpl_msg_error(recipe, "Missing keyword %s in flatfield frame", 01137 key_mask_id); 01138 vimos_calib_exit(NULL); 01139 } 01140 01141 cpl_propertylist_update_double(save_header, 01142 "ESO PRO WLEN CEN", reference); 01143 01144 if (fors_qc_keyword_to_paf(save_header, "ESO PRO WLEN CEN", "Angstrom", 01145 "Reference wavelength", instrume)) 01146 vimos_calib_exit("Missing keyword PRO WLEN CEN in flatfield frame"); 01147 01148 /* Unused in the old VIMOS pipeline: 01149 01150 if (fors_qc_keyword_to_paf(save_header, "ESO DPR TYPE", NULL, 01151 "DPR type", instrume)) 01152 vimos_calib_exit("Missing keyword DPR TYPE in flat field frame"); 01153 01154 if (fors_qc_keyword_to_paf(save_header, key_gris_id, NULL, 01155 "Grism identifier", instrume)) { 01156 cpl_msg_error(recipe, "Missing keyword %s in arc " 01157 "lamp header", key_gris_id); 01158 vimos_calib_exit(NULL); 01159 } 01160 01161 if (cpl_propertylist_has(save_header, key_filt_name)) 01162 fors_qc_keyword_to_paf(save_header, key_filt_name, NULL, 01163 "Filter name", instrume); 01164 01165 if (fors_qc_keyword_to_paf(save_header, "ESO DET CHIP1 ID", NULL, 01166 "Chip identifier", instrume)) 01167 vimos_calib_exit("Missing keyword DET CHIP1 ID in arc " 01168 "lamp header"); 01169 */ 01170 01171 pipefile = dfs_generate_filename_tfits(master_norm_flat_tag); 01172 if (fors_qc_write_string("PIPEFILE", pipefile, 01173 "Pipeline product name", instrume)) 01174 vimos_calib_exit("Cannot write PIPEFILE to QC log file"); 01175 cpl_free(pipefile); pipefile = NULL; 01176 01177 scale = cpl_propertylist_get_double(save_header, "ESO TEL FOCU SCALE"); 01178 01179 if (cpl_error_get_code()) { 01180 cpl_error_reset(); 01181 scale = 1.718; 01182 cpl_msg_warning(recipe, "Cannot read keyword TEL FOCU SCALE " 01183 "(defaulted to %f arcsec/mm)", scale); 01184 } 01185 01186 /* 01187 * QC1 parameters 01188 */ 01189 01190 keyname = "QC.MOS.SLIT.WIDTH"; 01191 01192 slit_width = scale * cpl_table_get(slits, "ywidth", cslit, NULL); 01193 01194 if (fors_qc_write_qc_double(save_header, slit_width, keyname, "arcsec", 01195 "Width of slit closest to center", 01196 instrume)) { 01197 vimos_calib_exit("Cannot write slit width to QC log file"); 01198 } 01199 01200 mos_extract_flux(master_flat, slits, 2, gain, &flux, &flux_err); 01201 01202 flux_err /= alltime; // The master is simply the sum of all flats 01203 flux /= alltime; 01204 01205 cpl_msg_info(recipe, 01206 "Flux at wavelength %.2f: %.2f +/- %.2f ADU/mm^2/s\n", 01207 reference, flux, flux_err); 01208 01209 keyname = "QC.MOS.FLAT.FLUX"; 01210 01211 if (fors_qc_write_qc_double(save_header, flux, keyname, "ADU/mm^2/s", 01212 "Flux at reference wavelength", 01213 instrume)) { 01214 vimos_calib_exit("Cannot write QC.MOS.FLAT.FLUX to QC log file"); 01215 } 01216 01217 keyname = "QC.MOS.FLAT.FLUXERR"; 01218 01219 if (fors_qc_write_qc_double(save_header, flux_err, keyname, 01220 "ADU/mm^2/s", 01221 "Error on flux at reference wavelength", 01222 instrume)) { 01223 vimos_calib_exit("Cannot write QC.MOS.FLAT.FLUXERR to QC log file"); 01224 } 01225 01226 fors_qc_end_group(); 01227 01228 } 01229 01230 cpl_image_turn(master_flat, rotate_back); 01231 if (dfs_save_image(frameset, master_flat, master_screen_flat_tag, 01232 save_header, parlist, recipe, version)) 01233 vimos_calib_exit(NULL); 01234 01235 cpl_image_delete(master_flat); master_flat = NULL; 01236 01237 cpl_propertylist_delete(save_header); save_header = NULL; 01238 01239 01240 /* 01241 * Final wavelength calibration of spectra having their curvature 01242 * removed 01243 */ 01244 01245 cpl_msg_indent_less(); 01246 cpl_msg_info(recipe, "Perform final wavelength calibration..."); 01247 cpl_msg_indent_more(); 01248 01249 nx = cpl_image_get_size_x(spatial); 01250 ny = cpl_image_get_size_y(spatial); 01251 01252 idscoeff = cpl_table_new(ny); 01253 restable = cpl_table_new(nlines); 01254 rainbow = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01255 if (check) 01256 residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01257 fiterror = cpl_calloc(ny, sizeof(double)); 01258 fitlines = cpl_calloc(ny, sizeof(int)); 01259 01260 rectified = mos_wavelength_calibration_final(spatial, slits, lines, 01261 dispersion, peakdetection, 01262 wradius, wdegree, wreject, 01263 reference, &startwavelength, 01264 &endwavelength, fitlines, 01265 fiterror, idscoeff, rainbow, 01266 residual, restable); 01267 01268 if (rectified == NULL) 01269 vimos_calib_exit("Wavelength calibration failure."); 01270 01271 if (dfs_save_table(frameset, restable, disp_residuals_table_tag, NULL, 01272 parlist, recipe, version)) 01273 vimos_calib_exit(NULL); 01274 01275 cpl_table_delete(restable); restable = NULL; 01276 01277 cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL; 01278 cpl_table_set_column_unit(idscoeff, "error", "pixel"); 01279 cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL; 01280 01281 if (treat_as_lss) { 01282 01283 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"}; 01284 01285 int *position = cpl_table_get_data_int (slits, "position"); 01286 int *length = cpl_table_get_data_int (slits, "length"); 01287 double *ytop = cpl_table_get_data_double(slits, "ytop"); 01288 double *ybottom = cpl_table_get_data_double(slits, "ybottom"); 01289 01290 int j, k, dr, irow; 01291 01292 /* 01293 * Replace the LSS solutions to the poorer MOS solutions 01294 */ 01295 01296 for (j = 0, i = ny - 1; i >= 0; i--) { 01297 if (i < position[j]) { 01298 ++j; 01299 } 01300 dr = position[j] + length[j] - i - 1; 01301 irow = floor(ytop[j] - dr*(ytop[j] - ybottom[j])/length[j] + 0.5); 01302 for (k = 0; k <= wdegree; k++) { 01303 cpl_table_set_double(idscoeff, clab[k], i, 01304 cpl_table_get_double(idscoeff_lss, clab[k], irow, NULL)); 01305 } 01306 cpl_table_set_double(idscoeff, "error", i, 01307 cpl_table_get_double(idscoeff_lss, "error", irow, NULL)); 01308 cpl_table_set_int(idscoeff, "nlines", i, 01309 cpl_table_get_int(idscoeff_lss, "nlines", irow, NULL)); 01310 } 01311 01312 cpl_table_delete(idscoeff_lss); 01313 01314 cpl_image_delete(rectified); 01315 01316 rectified = mos_wavelength_calibration(spatial, reference, 01317 startwavelength, endwavelength, 01318 dispersion, idscoeff, 0); 01319 } 01320 else { 01321 for (i = 0; i < ny; i++) 01322 if (!cpl_table_is_valid(idscoeff, "c0", i)) 01323 cpl_table_set_invalid(idscoeff, "error", i); 01324 } 01325 01326 cpl_image_delete(spatial); spatial = NULL; 01327 01328 delta = mos_map_pixel(idscoeff, reference, startwavelength, 01329 endwavelength, dispersion, 2); 01330 01331 header = cpl_propertylist_new(); 01332 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 01333 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 01334 cpl_propertylist_update_double(header, "CRVAL1", 01335 startwavelength + dispersion/2); 01336 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 01337 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 01338 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 01339 cpl_propertylist_update_double(header, "CD1_1", dispersion); 01340 cpl_propertylist_update_double(header, "CD1_2", 0.0); 01341 cpl_propertylist_update_double(header, "CD2_1", 0.0); 01342 cpl_propertylist_update_double(header, "CD2_2", 1.0); 01343 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 01344 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 01345 01346 if (dfs_save_image(frameset, delta, delta_image_tag, 01347 header, parlist, recipe, version)) 01348 vimos_calib_exit(NULL); 01349 01350 cpl_image_delete(delta); delta = NULL; 01351 cpl_propertylist_delete(header); header = NULL; 01352 01353 mean_rms = mos_distortions_rms(rectified, lines, startwavelength, 01354 dispersion, 6, 0); 01355 01356 cpl_msg_info(recipe, "Mean residual: %f pixel", mean_rms); 01357 01358 mean_rms = cpl_table_get_column_mean(idscoeff, "error"); 01359 01360 cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)", 01361 mean_rms, mean_rms * dispersion); 01362 01363 restab = mos_resolution_table(rectified, startwavelength, dispersion, 01364 60000, lines); 01365 01366 if (restab) { 01367 cpl_msg_info(recipe, "Mean spectral resolution: %.2f", 01368 cpl_table_get_column_mean(restab, "resolution")); 01369 cpl_msg_info(recipe, "Mean reference lines FWHM: %.2f +/- %.2f pixel", 01370 cpl_table_get_column_mean(restab, "fwhm") / dispersion, 01371 cpl_table_get_column_mean(restab, "fwhm_rms") / dispersion); 01372 01373 if (qc) { 01374 01375 header = dfs_load_header(frameset, arc_tag, 0); 01376 01377 if (header == NULL) 01378 vimos_calib_exit("Cannot reload arc lamp header"); 01379 01380 qclist = cpl_propertylist_new(); 01381 01382 fors_qc_start_group(qclist, "1.1", instrume); 01383 01384 01385 /* 01386 * QC1 group header 01387 */ 01388 01389 if (fors_qc_write_string("PRO.CATG", spectral_resolution_tag, 01390 "Product category", instrume)) 01391 vimos_calib_exit("Cannot write product category to " 01392 "QC log file"); 01393 01394 if (fors_qc_keyword_to_paf(header, "ESO DPR TYPE", NULL, 01395 "DPR type", instrume)) 01396 vimos_calib_exit("Missing keyword DPR TYPE in arc " 01397 "lamp header"); 01398 01399 if (fors_qc_keyword_to_paf(header, "ESO TPL ID", NULL, 01400 "Template", instrume)) 01401 vimos_calib_exit("Missing keyword TPL ID in arc " 01402 "lamp header"); 01403 01404 if (fors_qc_keyword_to_paf(header, key_gris_name, NULL, 01405 "Grism name", instrume)) { 01406 cpl_msg_error(recipe, "Missing keyword %s in arc " 01407 "lamp header", key_gris_name); 01408 vimos_calib_exit(NULL); 01409 } 01410 01411 if (fors_qc_keyword_to_paf(header, key_gris_id, NULL, 01412 "Grism identifier", instrume)) { 01413 cpl_msg_error(recipe, "Missing keyword %s in arc " 01414 "lamp header", key_gris_id); 01415 vimos_calib_exit(NULL); 01416 } 01417 01418 if (cpl_propertylist_has(header, key_filt_name)) 01419 fors_qc_keyword_to_paf(header, key_filt_name, NULL, 01420 "Filter name", instrume); 01421 01422 if (fors_qc_keyword_to_paf(header, "ESO DET CHIP1 ID", NULL, 01423 "Chip identifier", instrume)) 01424 vimos_calib_exit("Missing keyword DET CHIP1 ID in arc " 01425 "lamp header"); 01426 01427 if (fors_qc_keyword_to_paf(header, "ARCFILE", NULL, 01428 "Archive name of input data", 01429 instrume)) 01430 vimos_calib_exit("Missing keyword ARCFILE in arc " 01431 "lamp header"); 01432 01433 cpl_propertylist_delete(header); header = NULL; 01434 01435 pipefile = dfs_generate_filename_tfits(spectral_resolution_tag); 01436 if (fors_qc_write_string("PIPEFILE", pipefile, 01437 "Pipeline product name", instrume)) 01438 vimos_calib_exit("Cannot write PIPEFILE to QC log file"); 01439 cpl_free(pipefile); pipefile = NULL; 01440 01441 01442 /* 01443 * QC1 parameters 01444 */ 01445 01446 keyname = "QC.MOS.RESOLUTION"; 01447 01448 if (fors_qc_write_qc_double(qclist, 01449 cpl_table_get_column_mean(restab, 01450 "resolution"), 01451 keyname, 01452 "Angstrom", 01453 "Mean spectral resolution", 01454 instrume)) { 01455 vimos_calib_exit("Cannot write mean spectral resolution to QC " 01456 "log file"); 01457 } 01458 01459 keyname = "QC.MOS.RESOLUTION.RMS"; 01460 01461 if (fors_qc_write_qc_double(qclist, 01462 cpl_table_get_column_stdev(restab, 01463 "resolution"), 01464 "QC.MOS.RESOLUTION.RMS", 01465 "Angstrom", 01466 "Scatter of spectral resolution", 01467 instrume)) { 01468 vimos_calib_exit("Cannot write spectral resolution scatter " 01469 "to QC log file"); 01470 } 01471 01472 keyname = "QC.MOS.RESOLUTION.NLINES"; 01473 01474 if (fors_qc_write_qc_int(qclist, cpl_table_get_nrow(restab) - 01475 cpl_table_count_invalid(restab, 01476 "resolution"), 01477 "QC.MOS.RESOLUTION.NLINES", 01478 NULL, 01479 "Number of lines for spectral resolution " 01480 "computation", 01481 instrume)) { 01482 vimos_calib_exit("Cannot write number of lines used in " 01483 "spectral resolution computation " 01484 "to QC log file"); 01485 } 01486 01487 fors_qc_end_group(); 01488 01489 } 01490 01491 if (dfs_save_table(frameset, restab, spectral_resolution_tag, qclist, 01492 parlist, recipe, version)) 01493 vimos_calib_exit(NULL); 01494 01495 cpl_propertylist_delete(qclist); qclist = NULL; 01496 01497 } 01498 else 01499 vimos_calib_exit("Cannot compute the spectral resolution table"); 01500 01501 cpl_vector_delete(lines); lines = NULL; 01502 01503 if (dfs_save_table(frameset, idscoeff, disp_coeff_tag, NULL, 01504 parlist, recipe, version)) 01505 vimos_calib_exit(NULL); 01506 01507 /* 01508 * Global distortion models 01509 */ 01510 01511 if (slit_ident) { 01512 01513 cpl_msg_info(recipe, "Computing global distortions model"); 01514 global = mos_global_distortion(slits, maskslits, idscoeff, 01515 polytraces, reference); 01516 01517 if (global && 0) { 01518 cpl_table *stest; 01519 cpl_table *ctest; 01520 cpl_table *dtest; 01521 cpl_image *itest; 01522 01523 stest = mos_build_slit_location(global, maskslits, ccd_ysize); 01524 01525 ctest = mos_build_curv_coeff(global, maskslits, stest); 01526 if (dfs_save_table(frameset, ctest, "CURVS", NULL, 01527 parlist, recipe, version)) 01528 vimos_calib_exit(NULL); 01529 01530 itest = mos_spatial_calibration(spectra, stest, ctest, 01531 reference, startwavelength, 01532 endwavelength, dispersion, 01533 0, NULL); 01534 cpl_table_delete(ctest); ctest = NULL; 01535 cpl_image_delete(itest); itest = NULL; 01536 if (dfs_save_table(frameset, stest, "SLITS", NULL, 01537 parlist, recipe, version)) 01538 vimos_calib_exit(NULL); 01539 01540 dtest = mos_build_disp_coeff(global, stest); 01541 if (dfs_save_table(frameset, dtest, "DISPS", NULL, 01542 parlist, recipe, version)) 01543 vimos_calib_exit(NULL); 01544 01545 cpl_table_delete(dtest); dtest = NULL; 01546 cpl_table_delete(stest); stest = NULL; 01547 } 01548 01549 if (global) { 01550 if (dfs_save_table(frameset, global, global_distortion_tag, NULL, 01551 parlist, recipe, version)) 01552 vimos_calib_exit(NULL); 01553 cpl_table_delete(global); global = NULL; 01554 } 01555 01556 // cpl_image_delete(spectra); spectra = NULL; 01557 cpl_table_delete(maskslits); maskslits = NULL; 01558 } 01559 01560 header = dfs_load_header(frameset, arc_tag, 0); 01561 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 01562 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 01563 cpl_propertylist_update_double(header, "CRVAL1", 01564 startwavelength + dispersion/2); 01565 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 01566 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 01567 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 01568 cpl_propertylist_update_double(header, "CD1_1", dispersion); 01569 cpl_propertylist_update_double(header, "CD1_2", 0.0); 01570 cpl_propertylist_update_double(header, "CD2_1", 0.0); 01571 cpl_propertylist_update_double(header, "CD2_2", 1.0); 01572 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 01573 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 01574 cpl_propertylist_update_int(header, "ESO PRO DATANCOM", 1); 01575 01576 if (qc) { 01577 01578 double scale; 01579 double slit_width; 01580 float lambdaHe; 01581 float lambdaNe; 01582 float lambdaAr; 01583 float lambdaRed; 01584 float lambdaYel; 01585 float lambdaBlu; 01586 double flux, flux_err, resol, resol_err; 01587 int selected; 01588 int cslit = mos_slit_closest_to_center(slits, nx, ny); 01589 01590 01591 /* 01592 * QC1 group header 01593 */ 01594 01595 fors_qc_start_group(header, "1.1", instrume); 01596 01597 if (fors_qc_write_string("PRO.CATG", master_norm_flat_tag, 01598 "Product category", instrume)) 01599 vimos_calib_exit("Cannot write product category to QC log file"); 01600 01601 if (fors_qc_keyword_to_paf(header, "ARCFILE", NULL, 01602 "Archive File Name", instrume)) 01603 vimos_calib_exit("Missing keyword ARCFILE in arc lamp frame"); 01604 01605 if (fors_qc_keyword_to_paf(header, "ESO TPL ID", NULL, 01606 "Template signature ID", instrume)) 01607 vimos_calib_exit("Missing keyword TPL ID in arc lamp frame"); 01608 01609 if (fors_qc_keyword_to_paf(header, "ESO OCS CON QUAD", NULL, 01610 "Quadrant", instrume)) 01611 vimos_calib_exit("Missing keyword OCS CON QUAD in arc lamp frame"); 01612 01613 if (fors_qc_keyword_to_paf(header, key_filt_name, NULL, 01614 "Filter", instrume)) { 01615 cpl_msg_error(recipe, "Missing keyword %s in arc lamp frame", 01616 key_filt_name); 01617 vimos_calib_exit(NULL); 01618 } 01619 01620 if (fors_qc_keyword_to_paf(header, key_gris_name, NULL, 01621 "Grism", instrume)) { 01622 cpl_msg_error(recipe, "Missing keyword %s in arc lamp frame", 01623 key_gris_name); 01624 vimos_calib_exit(NULL); 01625 } 01626 01627 if (fors_qc_keyword_to_paf(header, key_mask_id, NULL, 01628 "Mask", instrume)) { 01629 cpl_msg_error(recipe, "Missing keyword %s in arc lamp frame", 01630 key_mask_id); 01631 vimos_calib_exit(NULL); 01632 } 01633 01634 cpl_propertylist_update_double(header, 01635 "ESO PRO WLEN CEN", reference); 01636 01637 if (fors_qc_keyword_to_paf(header, "ESO PRO WLEN CEN", "Angstrom", 01638 "Reference wavelength", instrume)) 01639 vimos_calib_exit("Missing keyword PRO WLEN CEN in arc lamp frame"); 01640 01641 pipefile = dfs_generate_filename_tfits(master_norm_flat_tag); 01642 if (fors_qc_write_string("PIPEFILE", pipefile, 01643 "Pipeline product name", instrume)) 01644 vimos_calib_exit("Cannot write PIPEFILE to QC log file"); 01645 cpl_free(pipefile); pipefile = NULL; 01646 01647 scale = cpl_propertylist_get_double(header, "ESO TEL FOCU SCALE"); 01648 01649 if (cpl_error_get_code()) { 01650 cpl_error_reset(); 01651 scale = 1.718; 01652 cpl_msg_warning(recipe, "Cannot read keyword TEL FOCU SCALE " 01653 "(defaulted to %f arcsec/mm)", scale); 01654 } 01655 01656 /* 01657 * QC1 parameters 01658 */ 01659 01660 keyname = "QC.MOS.SLIT.WIDTH"; 01661 01662 slit_width = scale * cpl_table_get(slits, "ywidth", cslit, NULL); 01663 01664 if (fors_qc_write_qc_double(header, slit_width, keyname, "arcsec", 01665 "Width of slit closest to center", 01666 instrume)) { 01667 vimos_calib_exit("Cannot write slit width to QC log file"); 01668 } 01669 01670 if (grism[0] == 'L') { 01671 if (grism[3] == 'r') { /* LR_red */ 01672 lambdaHe = 7065.19; 01673 lambdaNe = 0.0; 01674 lambdaAr = 7723.80; 01675 lambdaRed = 9122.97; 01676 lambdaYel = 7635.11; 01677 lambdaBlu = 5875.62; 01678 } 01679 if (grism[3] == 'b') { /* LR_blue */ 01680 lambdaHe = 5015.68; 01681 lambdaNe = 6598.96; 01682 lambdaAr = 0.0; 01683 lambdaRed = 6598.95; 01684 lambdaYel = 5015.68; 01685 lambdaBlu = 3888.65; 01686 } 01687 } 01688 01689 if (grism[0] == 'M') { /* MR */ 01690 lambdaHe = 7065.19; 01691 lambdaNe = 7032.41; 01692 lambdaAr = 7723.80; 01693 lambdaRed = 8264.521; 01694 lambdaYel = 6678.200; 01695 lambdaBlu = 5015.675; 01696 } 01697 01698 if (grism[0] == 'H') { 01699 if (grism[3] == 'r') { /* HR_red */ 01700 lambdaHe = 7065.19; 01701 lambdaNe = 7032.41; 01702 lambdaAr = 7723.80; 01703 lambdaRed = 9122.966; 01704 lambdaYel = 7948.175; 01705 lambdaBlu = 6929.468; 01706 } 01707 if (grism[3] == 'o') { /* HR_orange */ 01708 lambdaHe = 7065.19; 01709 lambdaNe = 7032.41; 01710 lambdaAr = 7723.80; 01711 lambdaRed = 7948.175; 01712 lambdaYel = 6929.468; 01713 lambdaBlu = 5875.618; 01714 } 01715 if (grism[3] == 'b') { /* HR_blue */ 01716 lambdaHe = 5015.68; 01717 lambdaNe = 5944.83; 01718 lambdaAr = 0.0; 01719 lambdaRed = 6598.953; 01720 lambdaYel = 5875.618; 01721 lambdaBlu = 5015.675; 01722 } 01723 } 01724 01725 if (lambdaHe > 1.) { 01726 mos_extract_flux_mapped(rectified, slits, lambdaHe, 01727 startwavelength, dispersion, 01728 4, gain, &flux, &flux_err); 01729 01730 flux /= arctime; 01731 flux_err /= arctime; 01732 01733 cpl_msg_info(recipe, "Flux of He %.2f: %.2f +/- %.2f ADU/mm^2/s", 01734 lambdaHe, flux, flux_err); 01735 01736 keyname = "QC.MOS.HE.LAMBDA"; 01737 01738 if (fors_qc_write_qc_double(header, lambdaHe, keyname, "Angstrom", 01739 "He arc lamp line for flux determination", instrume)) { 01740 vimos_calib_exit("Cannot write He arc line to QC log file"); 01741 } 01742 01743 keyname = "QC.MOS.HE.FLUX"; 01744 01745 if (fors_qc_write_qc_double(header, flux, keyname, "ADU/mm^2/s", 01746 "Flux at chosen He wavelength", instrume)) { 01747 vimos_calib_exit("Cannot write He flux to QC log file"); 01748 } 01749 01750 keyname = "QC.MOS.HE.FLUXERR"; 01751 01752 if (fors_qc_write_qc_double(header, flux_err, keyname, "ADU/mm^2/s", 01753 "Error on flux at chosen He wavelength", instrume)) { 01754 vimos_calib_exit("Cannot write He flux error to QC log file"); 01755 } 01756 } 01757 else 01758 cpl_msg_warning(recipe, 01759 "No He lines in %s spectral range: corresponding " 01760 "QC1 parameters are not computed.", grism); 01761 01762 if (lambdaNe > 1.) { 01763 mos_extract_flux_mapped(rectified, slits, lambdaNe, 01764 startwavelength, dispersion, 01765 4, gain, &flux, &flux_err); 01766 01767 flux /= arctime; 01768 flux_err /= arctime; 01769 01770 cpl_msg_info(recipe, "Flux of Ne %.2f: %.2f +/- %.2f ADU/mm^2/s", 01771 lambdaNe, flux, flux_err); 01772 01773 keyname = "QC.MOS.NE.LAMBDA"; 01774 01775 if (fors_qc_write_qc_double(header, lambdaNe, keyname, "Angstrom", 01776 "Ne arc lamp line for flux determination", instrume)) { 01777 vimos_calib_exit("Cannot write Ne arc line to QC log file"); 01778 } 01779 01780 keyname = "QC.MOS.NE.FLUX"; 01781 01782 if (fors_qc_write_qc_double(header, flux, keyname, "ADU/mm^2/s", 01783 "Flux at chosen Ne wavelength", instrume)) { 01784 vimos_calib_exit("Cannot write Ne flux to QC log file"); 01785 } 01786 01787 keyname = "QC.MOS.NE.FLUXERR"; 01788 01789 if (fors_qc_write_qc_double(header, flux_err, keyname, "ADU/mm^2/s", 01790 "Error on flux at chosen Ne wavelength", instrume)) { 01791 vimos_calib_exit("Cannot write Ne flux error to QC log file"); 01792 } 01793 } 01794 else 01795 cpl_msg_warning(recipe, 01796 "No Ne lines in %s spectral range: corresponding " 01797 "QC1 parameters are not computed.", grism); 01798 01799 if (lambdaAr > 1.) { 01800 mos_extract_flux_mapped(rectified, slits, lambdaAr, 01801 startwavelength, dispersion, 01802 4, gain, &flux, &flux_err); 01803 // mos_extract_flux(spectra, slits, 3, gain, &flux, &flux_err); 01804 01805 flux /= arctime; 01806 flux_err /= arctime; 01807 01808 cpl_msg_info(recipe, "Flux of Ar %.2f: %.2f +/- %.2f ADU/mm^2/s", 01809 lambdaAr, flux, flux_err); 01810 01811 keyname = "QC.MOS.AR.LAMBDA"; 01812 01813 if (fors_qc_write_qc_double(header, lambdaAr, keyname, "Angstrom", 01814 "Ar arc lamp line for flux determination", instrume)) { 01815 vimos_calib_exit("Cannot write Ar arc line to QC log file"); 01816 } 01817 01818 keyname = "QC.MOS.AR.FLUX"; 01819 01820 if (fors_qc_write_qc_double(header, flux, keyname, "ADU/mm^2/s", 01821 "Flux at chosen Ar wavelength", instrume)) { 01822 vimos_calib_exit("Cannot write Ar flux to QC log file"); 01823 } 01824 01825 keyname = "QC.MOS.AR.FLUXERR"; 01826 01827 if (fors_qc_write_qc_double(header, flux_err, keyname, "ADU/mm^2/s", 01828 "Error on flux at chosen Ar wavelength", instrume)) { 01829 vimos_calib_exit("Cannot write Ar flux error to QC log file"); 01830 } 01831 } 01832 else 01833 cpl_msg_warning(recipe, 01834 "No Ar lines in %s spectral range: corresponding " 01835 "QC1 parameters are not computed.", grism); 01836 01837 /* 01838 * IDS coefficients 01839 */ 01840 01841 for (i = 0; i <= wdegree; i++) { 01842 char *label = cpl_sprintf("c%d", i); 01843 char *unit; 01844 char *comment; 01845 double mcoeff; 01846 01847 01848 mcoeff = 0.0; // Zero by definition when i == 0 01849 if (i) { 01850 if (mos_median_in_slit(idscoeff, slits, 01851 cslit, label, &mcoeff)) { 01852 cpl_free(label); 01853 break; 01854 } 01855 } 01856 01857 keyname = cpl_sprintf("QC.MOS.WAVECAL.COEFF%d", i); 01858 01859 switch (i) { 01860 case 0: 01861 unit = cpl_strdup("pixel"); 01862 break; 01863 case 1: 01864 unit = cpl_strdup("pixel/Angstrom"); 01865 break; 01866 default: 01867 unit = cpl_sprintf("pixel/Angstrom^%d", i); 01868 break; 01869 } 01870 01871 comment = cpl_sprintf("Median coefficient %d of IDS", i); 01872 01873 if (fors_qc_write_qc_double(header, mcoeff, keyname, 01874 unit, comment, instrume)) { 01875 vimos_calib_exit("Cannot write IDS coefficient to QC logfile"); 01876 } 01877 01878 cpl_free(keyname); 01879 cpl_free(comment); 01880 cpl_free(unit); 01881 cpl_free(label); 01882 } 01883 01884 /* 01885 * These parameters are now useless, I set them to zero. 01886 */ 01887 01888 keyname = "QC.MOS.REFWAVE.MEAN"; 01889 01890 if (fors_qc_write_qc_double(header, 0.0, keyname, "pixel", 01891 "MEAN of CCD positions of reference wavelength", instrume)) { 01892 vimos_calib_exit("Cannot write QC.MOS.REFWAVE.MEAN to QC logfile"); 01893 } 01894 01895 keyname = "QC.MOS.REFWAVE.RMS"; 01896 01897 if (fors_qc_write_qc_double(header, 0.0, keyname, "pixel", 01898 "RMS of CCD positions of reference wavelength", instrume)) { 01899 vimos_calib_exit("Cannot write QC.MOS.REFWAVE.RMS to QC logfile"); 01900 } 01901 01902 if (restab) { 01903 01904 /* 01905 * About spectral resolution: 01906 */ 01907 01908 keyname = "QC.MOS.RESOLUTION1.LAMBDA"; 01909 01910 if (fors_qc_write_qc_double(header, lambdaRed, keyname, "Angstrom", 01911 "Line used in spectral resolution determination", instrume)) { 01912 vimos_calib_exit("Cannot write arc line to QC log file"); 01913 } 01914 01915 keyname = "QC.MOS.RESOLUTION1"; 01916 01917 cpl_table_and_selected_double(restab, "wavelength", 01918 CPL_GREATER_THAN, lambdaRed - 1.0); 01919 selected = 01920 cpl_table_and_selected_double(restab, "wavelength", 01921 CPL_LESS_THAN, lambdaRed + 1.0); 01922 01923 if (selected == 1) { 01924 cpl_table *one_line = cpl_table_extract_selected(restab); 01925 01926 resol = cpl_table_get_double(one_line, 01927 "resolution", 0, NULL); 01928 resol_err = cpl_table_get_double(one_line, 01929 "resolution_rms", 0, NULL); 01930 01931 cpl_table_delete(one_line); 01932 } 01933 else { 01934 resol = 0.0; 01935 resol_err = 0.0; 01936 } 01937 01938 cpl_table_select_all(restab); 01939 01940 cpl_msg_info(recipe, "Spectral resolution at %.2f: %.2f +/- %.2f", 01941 lambdaRed, resol, resol_err); 01942 01943 if (fors_qc_write_qc_double(header, resol, keyname, NULL, 01944 "Mean spectral resolution at red end of spectrum", instrume)) { 01945 vimos_calib_exit("Cannot write spectral resolution " 01946 "to QC log file"); 01947 } 01948 01949 keyname = "QC.MOS.RESOLUTION1.RMS"; 01950 01951 if (fors_qc_write_qc_double(header, resol_err, keyname, NULL, 01952 "Error on mean spectral resolution", instrume)) { 01953 vimos_calib_exit("Cannot write error on resolution " 01954 "to QC log file"); 01955 } 01956 01957 keyname = "QC.MOS.RESOLUTION2.LAMBDA"; 01958 01959 if (fors_qc_write_qc_double(header, lambdaYel, keyname, "Angstrom", 01960 "Line used in spectral resolution determination", instrume)) { 01961 vimos_calib_exit("Cannot write arc line to QC log file"); 01962 } 01963 01964 keyname = "QC.MOS.RESOLUTION2"; 01965 01966 cpl_table_and_selected_double(restab, "wavelength", 01967 CPL_GREATER_THAN, lambdaYel - 1.0); 01968 selected = 01969 cpl_table_and_selected_double(restab, "wavelength", 01970 CPL_LESS_THAN, lambdaYel + 1.0); 01971 01972 if (selected == 1) { 01973 cpl_table *one_line = cpl_table_extract_selected(restab); 01974 01975 resol = cpl_table_get_double(one_line, 01976 "resolution", 0, NULL); 01977 resol_err = cpl_table_get_double(one_line, 01978 "resolution_rms", 0, NULL); 01979 01980 cpl_table_delete(one_line); 01981 } 01982 else { 01983 resol = 0.0; 01984 resol_err = 0.0; 01985 } 01986 01987 cpl_table_select_all(restab); 01988 01989 cpl_msg_info(recipe, "Spectral resolution at %.2f: %.2f +/- %.2f", 01990 lambdaYel, resol, resol_err); 01991 01992 if (fors_qc_write_qc_double(header, resol, keyname, NULL, 01993 "Mean spectral resolution at center of spectrum", instrume)) { 01994 vimos_calib_exit("Cannot write spectral resolution " 01995 "to QC log file"); 01996 } 01997 01998 keyname = "QC.MOS.RESOLUTION2.RMS"; 01999 02000 if (fors_qc_write_qc_double(header, resol_err, keyname, NULL, 02001 "Error on mean spectral resolution", instrume)) { 02002 vimos_calib_exit("Cannot write error on resolution " 02003 "to QC log file"); 02004 } 02005 02006 keyname = "QC.MOS.RESOLUTION3.LAMBDA"; 02007 02008 if (fors_qc_write_qc_double(header, lambdaBlu, keyname, "Angstrom", 02009 "Line used in spectral resolution determination", instrume)) { 02010 vimos_calib_exit("Cannot write arc line to QC log file"); 02011 } 02012 02013 keyname = "QC.MOS.RESOLUTION3"; 02014 02015 cpl_table_and_selected_double(restab, "wavelength", 02016 CPL_GREATER_THAN, lambdaBlu - 1.0); 02017 selected = 02018 cpl_table_and_selected_double(restab, "wavelength", 02019 CPL_LESS_THAN, lambdaBlu + 1.0); 02020 02021 if (selected == 1) { 02022 cpl_table *one_line = cpl_table_extract_selected(restab); 02023 02024 resol = cpl_table_get_double(one_line, 02025 "resolution", 0, NULL); 02026 resol_err = cpl_table_get_double(one_line, 02027 "resolution_rms", 0, NULL); 02028 02029 cpl_table_delete(one_line); 02030 } 02031 else { 02032 resol = 0.0; 02033 resol_err = 0.0; 02034 } 02035 02036 cpl_table_select_all(restab); 02037 02038 cpl_msg_info(recipe, "Spectral resolution at %.2f: %.2f +/- %.2f", 02039 lambdaBlu, resol, resol_err); 02040 02041 if (fors_qc_write_qc_double(header, resol, keyname, NULL, 02042 "Mean spectral resolution at blue end of spectrum", instrume)) { 02043 vimos_calib_exit("Cannot write spectral resolution " 02044 "to QC log file"); 02045 } 02046 02047 keyname = "QC.MOS.RESOLUTION3.RMS"; 02048 02049 if (fors_qc_write_qc_double(header, resol_err, keyname, NULL, 02050 "Error on mean spectral resolution", instrume)) { 02051 vimos_calib_exit("Cannot write error on resolution " 02052 "to QC log file"); 02053 } 02054 02055 keyname = "QC.MOS.IDS.RMS"; 02056 02057 if (fors_qc_write_qc_double(header, mean_rms, keyname, "pixel", 02058 "Mean accuracy of dispersion solution", instrume)) { 02059 vimos_calib_exit("Cannot write mean accuracy of " 02060 "dispersion solution to QC log file"); 02061 } 02062 } 02063 02064 fors_qc_end_group(); 02065 02066 } 02067 02068 cpl_free(grism); grism = NULL; 02069 cpl_free(instrume); instrume = NULL; 02070 cpl_table_delete(restab); restab = NULL; 02071 cpl_table_delete(idscoeff); idscoeff = NULL; 02072 cpl_image_delete(spectra); spectra = NULL; 02073 02074 if (dfs_save_image(frameset, rectified, reduced_lamp_tag, header, 02075 parlist, recipe, version)) 02076 vimos_calib_exit(NULL); 02077 02078 cpl_image_delete(rectified); rectified = NULL; 02079 cpl_propertylist_delete(header); header = NULL; 02080 02081 if (check) { 02082 save_header = dfs_load_header(frameset, arc_tag, 0); 02083 02084 cpl_propertylist_update_double(save_header, "CRPIX2", 1.0); 02085 cpl_propertylist_update_double(save_header, "CRVAL2", 1.0); 02086 /* cpl_propertylist_update_double(save_header, "CDELT2", 1.0); */ 02087 cpl_propertylist_update_double(save_header, "CD1_1", 1.0); 02088 cpl_propertylist_update_double(save_header, "CD1_2", 0.0); 02089 cpl_propertylist_update_double(save_header, "CD2_1", 0.0); 02090 cpl_propertylist_update_double(save_header, "CD2_2", 1.0); 02091 cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR"); 02092 cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL"); 02093 02094 if (dfs_save_image(frameset, residual, disp_residuals_tag, save_header, 02095 parlist, recipe, version)) 02096 vimos_calib_exit(NULL); 02097 02098 cpl_image_delete(residual); residual = NULL; 02099 cpl_propertylist_delete(save_header); save_header = NULL; 02100 } 02101 02102 if (!treat_as_lss) { 02103 02104 /* 02105 * Wavemap was already produced if treat_as_lss = true 02106 */ 02107 02108 wavemap = mos_map_wavelengths(coordinate, rainbow, slits, 02109 polytraces, reference, 02110 startwavelength, endwavelength, 02111 dispersion); 02112 02113 cpl_image_delete(rainbow); rainbow = NULL; 02114 } 02115 02116 save_header = dfs_load_header(frameset, arc_tag, 0); 02117 02118 cpl_image_turn(wavemap, rotate_back); 02119 if (dfs_save_image(frameset, wavemap, wavelength_map_tag, save_header, 02120 parlist, recipe, version)) 02121 vimos_calib_exit(NULL); 02122 02123 cpl_image_delete(wavemap); wavemap = NULL; 02124 02125 cpl_image_turn(coordinate, rotate_back); 02126 if (dfs_save_image(frameset, coordinate, spatial_map_tag, save_header, 02127 parlist, recipe, version)) 02128 vimos_calib_exit(NULL); 02129 02130 cpl_image_delete(coordinate); coordinate = NULL; 02131 cpl_propertylist_delete(save_header); save_header = NULL; 02132 02133 if (dfs_save_table(frameset, polytraces, curv_coeff_tag, NULL, 02134 parlist, recipe, version)) 02135 vimos_calib_exit(NULL); 02136 02137 cpl_table_delete(polytraces); polytraces = NULL; 02138 02139 mos_rotate_slits(slits, rotate, ccd_ysize, ccd_xsize); 02140 if (dfs_save_table(frameset, slits, slit_location_tag, NULL, 02141 parlist, recipe, version)) 02142 vimos_calib_exit(NULL); 02143 02144 cpl_table_delete(slits); slits = NULL; 02145 02146 if (cpl_error_get_code()) { 02147 cpl_msg_error(cpl_error_get_where(), cpl_error_get_message()); 02148 vimos_calib_exit(NULL); 02149 } 02150 02151 return 0; 02152 }