00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031
00032 #include <math.h>
00033 #include <string.h>
00034 #include <cpl.h>
00035 #include <moses.h>
00036 #include <fors_stack.h>
00037 #include <fors_dfs.h>
00038 #include <fors_qc.h>
00039
00040 static int fors_calib_create(cpl_plugin *);
00041 static int fors_calib_exec(cpl_plugin *);
00042 static int fors_calib_destroy(cpl_plugin *);
00043 static int fors_calib(cpl_parameterlist *, cpl_frameset *);
00044
00045 static char fors_calib_description[] =
00046 "This recipe is used to identify reference lines on LSS, MOS and MXU arc lamp\n"
00047 "exposures, and trace the spectral edges on the corresponding flat field\n"
00048 "exposures. This information is used to determine the spectral extraction\n"
00049 "mask to be applied in the scientific data reduction, performed with the\n"
00050 "recipe fors_science.\n"
00051 "This recipe accepts both FORS1 and FORS2 frames. The input arc lamp and\n"
00052 "flat field exposures are assumed to be obtained quasi-simultaneously, so\n"
00053 "that they would be described by exactly the same instrument distortions.\n"
00054 "A line catalog must be specified, containing the wavelengths of the\n"
00055 "reference arc lamp lines used for the wavelength calibration. A grism\n"
00056 "table (typically depending on the instrument mode, and in particular on\n"
00057 "the grism used) may also be specified: this table contains a default\n"
00058 "recipe parameter setting to control the way spectra are extracted for\n"
00059 "a specific instrument mode, as it is used for automatic run of the\n"
00060 "pipeline on Paranal and in Garching. If this table is specified, it\n"
00061 "will modify the default recipe parameter setting, with the exception of\n"
00062 "those parameters which have been explicitly modifyed on the command line.\n"
00063 "If a grism table is not specified, the input recipe parameters values\n"
00064 "will always be read from the command line, or from an esorex configuration\n"
00065 "file if present, or from their generic default values (that are rarely\n"
00066 "meaningful). Finally a master bias frame must be input to this recipe.\n"
00067 "In the table below the MXU acronym can be read alternatively as MOS\n"
00068 "and LSS, with the exception of CURV_COEFF_LSS, CURV_TRACES_LSS,\n"
00069 "SPATIAL_MAP_LSS, SPECTRA_DETECTION_LSS, and and SLIT_MAP_LSS, which are\n"
00070 "never created. The products SPECTRA_DETECTION_MXU, SLIT_MAP_MXU, and\n"
00071 "DISP_RESIDUALS_MXU, are just created if the --check parameter is set to\n"
00072 "true. The product GLOBAL_DISTORTION_TABLE is just created if more than 12\n"
00073 "separate spectra are found in the CCD.\n\n"
00074 "Input files:\n\n"
00075 " DO category: Type: Explanation: Required:\n"
00076 " SCREEN_FLAT_MXU Raw Flat field exposures Y\n"
00077 " LAMP_MXU Raw Arc lamp exposure Y\n"
00078 " MASTER_BIAS or BIAS Calib Bias frame Y\n"
00079 " MASTER_LINECAT Calib Line catalog Y\n"
00080 " GRISM_TABLE Calib Grism table .\n\n"
00081 "Output files:\n\n"
00082 " DO category: Data type: Explanation:\n"
00083 " MASTER_SCREEN_FLAT_MXU FITS image Combined (sum) flat field\n"
00084 " MASTER_NORM_FLAT_MXU FITS image Normalised flat field\n"
00085 " MAPPED_SCREEN_FLAT_MXU FITS image Wavelength calibrated flat field\n"
00086 " MAPPED_NORM_FLAT_MXU FITS image Wavelength calibrated normalised flat\n"
00087 " REDUCED_LAMP_MXU FITS image Wavelength calibrated arc spectrum\n"
00088 " DISP_COEFF_MXU FITS table Inverse dispersion coefficients\n"
00089 " DISP_RESIDUALS_MXU FITS image Residuals in wavelength calibration\n"
00090 " DISP_RESIDUALS_TABLE_MXU FITS table Residuals in wavelength calibration\n"
00091 " DELTA_IMAGE_MXU FITS image Offset vs linear wavelength calib\n"
00092 " WAVELENGTH_MAP_MXU FITS image Wavelength for each pixel on CCD\n"
00093 " SPECTRA_DETECTION_MXU FITS image Check for preliminary detection\n"
00094 " SLIT_MAP_MXU FITS image Map of central wavelength on CCD\n"
00095 " CURV_TRACES_MXU FITS table Spectral curvature traces\n"
00096 " CURV_COEFF_MXU FITS table Spectral curvature coefficients\n"
00097 " SPATIAL_MAP_MXU FITS image Spatial position along slit on CCD\n"
00098 " SPECTRAL_RESOLUTION_MXU FITS table Resolution at reference arc lines\n"
00099 " SLIT_LOCATION_MXU FITS table Slits on product frames and CCD\n"
00100 " GLOBAL_DISTORTION_TABLE FITS table Global distortions table\n\n";
00101
00102 #define fors_calib_exit(message) \
00103 { \
00104 if (message) cpl_msg_error(recipe, message); \
00105 cpl_free(instrume); \
00106 cpl_free(pipefile); \
00107 cpl_free(fiterror); \
00108 cpl_free(fitlines); \
00109 cpl_image_delete(bias); \
00110 cpl_image_delete(master_bias); \
00111 cpl_image_delete(coordinate); \
00112 cpl_image_delete(checkwave); \
00113 cpl_image_delete(flat); \
00114 cpl_image_delete(master_flat); \
00115 cpl_image_delete(added_flat); \
00116 cpl_image_delete(norm_flat); \
00117 cpl_image_delete(rainbow); \
00118 cpl_image_delete(rectified); \
00119 cpl_image_delete(residual); \
00120 cpl_image_delete(smo_flat); \
00121 cpl_image_delete(spatial); \
00122 cpl_image_delete(spectra); \
00123 cpl_image_delete(wavemap); \
00124 cpl_image_delete(delta); \
00125 cpl_image_delete(rect_flat); \
00126 cpl_image_delete(rect_nflat); \
00127 cpl_image_delete(mapped_flat); \
00128 cpl_image_delete(mapped_nflat); \
00129 cpl_mask_delete(refmask); \
00130 cpl_propertylist_delete(header); \
00131 cpl_propertylist_delete(save_header); \
00132 cpl_propertylist_delete(qclist); \
00133 cpl_table_delete(grism_table); \
00134 cpl_table_delete(idscoeff); \
00135 cpl_table_delete(idscoeff_all); \
00136 cpl_table_delete(restable); \
00137 cpl_table_delete(maskslits); \
00138 cpl_table_delete(overscans); \
00139 cpl_table_delete(traces); \
00140 cpl_table_delete(polytraces); \
00141 cpl_table_delete(slits); \
00142 cpl_table_delete(restab); \
00143 cpl_table_delete(global); \
00144 cpl_table_delete(wavelengths); \
00145 cpl_vector_delete(lines); \
00146 cpl_msg_indent_less(); \
00147 return -1; \
00148 }
00149
00150 #define fors_calib_exit_memcheck(message) \
00151 { \
00152 if (message) cpl_msg_info(recipe, message); \
00153 printf("free instrume (%p)\n", instrume); \
00154 cpl_free(instrume); \
00155 printf("free pipefile (%p)\n", pipefile); \
00156 cpl_free(pipefile); \
00157 printf("free fiterror (%p)\n", fiterror); \
00158 cpl_free(fiterror); \
00159 printf("free fitlines (%p)\n", fitlines); \
00160 cpl_free(fitlines); \
00161 printf("free bias (%p)\n", bias); \
00162 cpl_image_delete(bias); \
00163 printf("free master_bias (%p)\n", master_bias); \
00164 cpl_image_delete(master_bias); \
00165 printf("free coordinate (%p)\n", coordinate); \
00166 cpl_image_delete(coordinate); \
00167 printf("free checkwave (%p)\n", checkwave); \
00168 cpl_image_delete(checkwave); \
00169 printf("free flat (%p)\n", flat); \
00170 cpl_image_delete(flat); \
00171 printf("free master_flat (%p)\n", master_flat); \
00172 cpl_image_delete(master_flat); \
00173 printf("free norm_flat (%p)\n", norm_flat); \
00174 cpl_image_delete(norm_flat); \
00175 printf("free mapped_flat (%p)\n", mapped_flat); \
00176 cpl_image_delete(mapped_flat); \
00177 printf("free mapped_nflat (%p)\n", mapped_nflat); \
00178 cpl_image_delete(mapped_nflat); \
00179 printf("free rainbow (%p)\n", rainbow); \
00180 cpl_image_delete(rainbow); \
00181 printf("free rectified (%p)\n", rectified); \
00182 cpl_image_delete(rectified); \
00183 printf("free residual (%p)\n", residual); \
00184 cpl_image_delete(residual); \
00185 printf("free smo_flat (%p)\n", smo_flat); \
00186 cpl_image_delete(smo_flat); \
00187 printf("free spatial (%p)\n", spatial); \
00188 cpl_image_delete(spatial); \
00189 printf("free spectra (%p)\n", spectra); \
00190 cpl_image_delete(spectra); \
00191 printf("free wavemap (%p)\n", wavemap); \
00192 cpl_image_delete(wavemap); \
00193 printf("free delta (%p)\n", delta); \
00194 cpl_image_delete(delta); \
00195 printf("free rect_flat (%p)\n", rect_flat); \
00196 cpl_image_delete(rect_flat); \
00197 printf("free rect_nflat (%p)\n", rect_nflat); \
00198 cpl_image_delete(rect_nflat); \
00199 printf("free refmask (%p)\n", refmask); \
00200 cpl_mask_delete(refmask); \
00201 printf("free header (%p)\n", header); \
00202 cpl_propertylist_delete(header); \
00203 printf("free save_header (%p)\n", save_header); \
00204 cpl_propertylist_delete(save_header); \
00205 printf("free qclist (%p)\n", qclist); \
00206 cpl_propertylist_delete(qclist); \
00207 printf("free grism_table (%p)\n", grism_table); \
00208 cpl_table_delete(grism_table); \
00209 printf("free idscoeff (%p)\n", idscoeff); \
00210 cpl_table_delete(idscoeff); \
00211 printf("free idscoeff_all (%p)\n", idscoeff_all); \
00212 cpl_table_delete(idscoeff_all); \
00213 printf("free restable (%p)\n", restable); \
00214 cpl_table_delete(restable); \
00215 printf("free maskslits (%p)\n", maskslits); \
00216 cpl_table_delete(maskslits); \
00217 printf("free overscans (%p)\n", overscans); \
00218 cpl_table_delete(overscans); \
00219 printf("free traces (%p)\n", traces); \
00220 cpl_table_delete(traces); \
00221 printf("free polytraces (%p)\n", polytraces); \
00222 cpl_table_delete(polytraces); \
00223 printf("free slits (%p)\n", slits); \
00224 cpl_table_delete(slits); \
00225 printf("free restab (%p)\n", restab); \
00226 cpl_table_delete(restab); \
00227 printf("free global (%p)\n", global); \
00228 cpl_table_delete(global); \
00229 printf("free wavelengths (%p)\n", wavelengths); \
00230 cpl_table_delete(wavelengths); \
00231 printf("free lines (%p)\n", lines); \
00232 cpl_vector_delete(lines); \
00233 cpl_msg_indent_less(); \
00234 return 0; \
00235 }
00236
00237
00249 int cpl_plugin_get_info(cpl_pluginlist *list)
00250 {
00251 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
00252 cpl_plugin *plugin = &recipe->interface;
00253
00254 cpl_plugin_init(plugin,
00255 CPL_PLUGIN_API,
00256 FORS_BINARY_VERSION,
00257 CPL_PLUGIN_TYPE_RECIPE,
00258 "fors_calib",
00259 "Determination of the extraction mask",
00260 fors_calib_description,
00261 "Carlo Izzo",
00262 PACKAGE_BUGREPORT,
00263 "This file is currently part of the FORS Instrument Pipeline\n"
00264 "Copyright (C) 2002-2010 European Southern Observatory\n\n"
00265 "This program is free software; you can redistribute it and/or modify\n"
00266 "it under the terms of the GNU General Public License as published by\n"
00267 "the Free Software Foundation; either version 2 of the License, or\n"
00268 "(at your option) any later version.\n\n"
00269 "This program is distributed in the hope that it will be useful,\n"
00270 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00271 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
00272 "GNU General Public License for more details.\n\n"
00273 "You should have received a copy of the GNU General Public License\n"
00274 "along with this program; if not, write to the Free Software Foundation,\n"
00275 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n",
00276 fors_calib_create,
00277 fors_calib_exec,
00278 fors_calib_destroy);
00279
00280 cpl_pluginlist_append(list, plugin);
00281
00282 return 0;
00283 }
00284
00285
00296 static int fors_calib_create(cpl_plugin *plugin)
00297 {
00298 cpl_recipe *recipe;
00299 cpl_parameter *p;
00300
00301
00302
00303
00304
00305
00306 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00307 recipe = (cpl_recipe *)plugin;
00308 else
00309 return -1;
00310
00311
00312
00313
00314
00315 recipe->parameters = cpl_parameterlist_new();
00316
00317
00318
00319
00320
00321
00322 p = cpl_parameter_new_value("fors.fors_calib.dispersion",
00323 CPL_TYPE_DOUBLE,
00324 "Expected spectral dispersion (Angstrom/pixel)",
00325 "fors.fors_calib",
00326 0.0);
00327 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
00328 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00329 cpl_parameterlist_append(recipe->parameters, p);
00330
00331
00332
00333
00334
00335 p = cpl_parameter_new_value("fors.fors_calib.peakdetection",
00336 CPL_TYPE_DOUBLE,
00337 "Initial peak detection threshold (ADU)",
00338 "fors.fors_calib",
00339 0.0);
00340 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "peakdetection");
00341 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00342 cpl_parameterlist_append(recipe->parameters, p);
00343
00344
00345
00346
00347
00348 p = cpl_parameter_new_value("fors.fors_calib.wdegree",
00349 CPL_TYPE_INT,
00350 "Degree of wavelength calibration polynomial",
00351 "fors.fors_calib",
00352 0);
00353 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wdegree");
00354 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00355 cpl_parameterlist_append(recipe->parameters, p);
00356
00357
00358
00359
00360
00361 p = cpl_parameter_new_value("fors.fors_calib.wradius",
00362 CPL_TYPE_INT,
00363 "Search radius if iterating pattern-matching "
00364 "with first-guess method",
00365 "fors.fors_calib",
00366 4);
00367 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wradius");
00368 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00369 cpl_parameterlist_append(recipe->parameters, p);
00370
00371
00372
00373
00374
00375 p = cpl_parameter_new_value("fors.fors_calib.wreject",
00376 CPL_TYPE_DOUBLE,
00377 "Rejection threshold in dispersion "
00378 "relation fit (pixel)",
00379 "fors.fors_calib",
00380 0.7);
00381 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wreject");
00382 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00383 cpl_parameterlist_append(recipe->parameters, p);
00384
00385
00386
00387
00388
00389 p = cpl_parameter_new_value("fors.fors_calib.wmode",
00390 CPL_TYPE_INT,
00391 "Interpolation mode of wavelength solution "
00392 "applicable to LSS-like data (0 = no "
00393 "interpolation, 1 = fill gaps, 2 = global "
00394 "model)",
00395 "fors.fors_calib",
00396 2);
00397 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wmode");
00398 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00399 cpl_parameterlist_append(recipe->parameters, p);
00400
00401
00402
00403
00404
00405 p = cpl_parameter_new_value("fors.fors_calib.wmosmode",
00406 CPL_TYPE_INT,
00407 "Interpolation mode of wavelength solution "
00408 "(0 = no interpolation, 1 = local (slit) "
00409 "solution, 2 = global model)",
00410 "fors.fors_calib",
00411 0);
00412 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wmosmode");
00413 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00414 cpl_parameterlist_append(recipe->parameters, p);
00415
00416
00417
00418
00419
00420 p = cpl_parameter_new_value("fors.fors_calib.wcolumn",
00421 CPL_TYPE_STRING,
00422 "Name of line catalog table column "
00423 "with wavelengths",
00424 "fors.fors_calib",
00425 "WLEN");
00426 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
00427 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00428 cpl_parameterlist_append(recipe->parameters, p);
00429
00430
00431
00432
00433
00434 p = cpl_parameter_new_value("fors.fors_calib.cdegree",
00435 CPL_TYPE_INT,
00436 "Degree of spectral curvature polynomial",
00437 "fors.fors_calib",
00438 0);
00439 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cdegree");
00440 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00441 cpl_parameterlist_append(recipe->parameters, p);
00442
00443
00444
00445
00446
00447 p = cpl_parameter_new_value("fors.fors_calib.cmode",
00448 CPL_TYPE_INT,
00449 "Interpolation mode of curvature solution "
00450 "applicable to MOS-like data (0 = no "
00451 "interpolation, 1 = fill gaps, 2 = global "
00452 "model)",
00453 "fors.fors_calib",
00454 1);
00455 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cmode");
00456 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00457 cpl_parameterlist_append(recipe->parameters, p);
00458
00459
00460
00461
00462
00463 p = cpl_parameter_new_value("fors.fors_calib.startwavelength",
00464 CPL_TYPE_DOUBLE,
00465 "Start wavelength in spectral extraction",
00466 "fors.fors_calib",
00467 0.0);
00468 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
00469 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00470 cpl_parameterlist_append(recipe->parameters, p);
00471
00472
00473
00474
00475
00476 p = cpl_parameter_new_value("fors.fors_calib.endwavelength",
00477 CPL_TYPE_DOUBLE,
00478 "End wavelength in spectral extraction",
00479 "fors.fors_calib",
00480 0.0);
00481 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
00482 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00483 cpl_parameterlist_append(recipe->parameters, p);
00484
00485
00486
00487
00488
00489 p = cpl_parameter_new_value("fors.fors_calib.slit_ident",
00490 CPL_TYPE_BOOL,
00491 "Attempt slit identification for MOS or MXU",
00492 "fors.fors_calib",
00493 TRUE);
00494 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "slit_ident");
00495 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00496 cpl_parameterlist_append(recipe->parameters, p);
00497
00498
00499
00500
00501
00502 fors_stack_define_parameters(recipe->parameters, "fors.fors_calib",
00503 "average");
00504
00505
00506
00507
00508
00509
00510 p = cpl_parameter_new_value("fors.fors_calib.sdegree",
00511 CPL_TYPE_INT,
00512 "Degree of flat field fitting polynomial "
00513 "along spatial direction (used for LSS "
00514 "data only)",
00515 "fors.fors_calib",
00516 4);
00517 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sdegree");
00518 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00519 cpl_parameterlist_append(recipe->parameters, p);
00520
00521
00522
00523
00524
00525
00526 p = cpl_parameter_new_value("fors.fors_calib.ddegree",
00527 CPL_TYPE_INT,
00528 "Degree of flat field fitting polynomial "
00529 "along dispersion direction (used for MOS "
00530 "and MXU data only)",
00531 "fors.fors_calib",
00532 -1);
00533 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ddegree");
00534 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00535 cpl_parameterlist_append(recipe->parameters, p);
00536
00537
00538
00539
00540
00541 p = cpl_parameter_new_value("fors.fors_calib.dradius",
00542 CPL_TYPE_INT,
00543 "Smooth box radius for flat field along "
00544 "dispersion direction",
00545 "fors.fors_calib",
00546 10);
00547 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dradius");
00548 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00549 cpl_parameterlist_append(recipe->parameters, p);
00550
00551
00552
00553
00554
00555
00556 p = cpl_parameter_new_value("fors.fors_calib.sradius",
00557 CPL_TYPE_INT,
00558 "Smooth box radius for flat field along "
00559 "spatial direction",
00560 "fors.fors_calib",
00561 10);
00562 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sradius");
00563 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00564 cpl_parameterlist_append(recipe->parameters, p);
00565
00566
00567
00568
00569
00570 p = cpl_parameter_new_value("fors.fors_calib.qc",
00571 CPL_TYPE_BOOL,
00572 "Compute QC1 parameters",
00573 "fors.fors_calib",
00574 TRUE);
00575 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "qc");
00576 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00577 cpl_parameterlist_append(recipe->parameters, p);
00578
00579
00580
00581
00582
00583 p = cpl_parameter_new_value("fors.fors_calib.check",
00584 CPL_TYPE_BOOL,
00585 "Create intermediate products",
00586 "fors.fors_calib",
00587 FALSE);
00588 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "check");
00589 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00590 cpl_parameterlist_append(recipe->parameters, p);
00591
00592 return 0;
00593 }
00594
00595
00604 static int fors_calib_exec(cpl_plugin *plugin)
00605 {
00606 cpl_recipe *recipe;
00607
00608 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00609 recipe = (cpl_recipe *)plugin;
00610 else
00611 return -1;
00612
00613 return fors_calib(recipe->parameters, recipe->frames);
00614 }
00615
00616
00625 static int fors_calib_destroy(cpl_plugin *plugin)
00626 {
00627 cpl_recipe *recipe;
00628
00629 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00630 recipe = (cpl_recipe *)plugin;
00631 else
00632 return -1;
00633
00634 cpl_parameterlist_delete(recipe->parameters);
00635
00636 return 0;
00637 }
00638
00639
00649 static int fors_calib(cpl_parameterlist *parlist, cpl_frameset *frameset)
00650 {
00651
00652 const char *recipe = "fors_calib";
00653
00654
00655
00656
00657
00658
00659 double dispersion;
00660 double peakdetection;
00661 int wdegree;
00662 int wradius;
00663 double wreject;
00664 int wmode;
00665 int wmosmode;
00666 const char *wcolumn;
00667 int cdegree;
00668 int cmode;
00669 double startwavelength;
00670 double endwavelength;
00671 int slit_ident;
00672 int sdegree;
00673 int ddegree;
00674 int sradius;
00675 int dradius;
00676 int qc;
00677 int check;
00678 const char *stack_method;
00679 int min_reject;
00680 int max_reject;
00681 double klow;
00682 double khigh;
00683 int kiter;
00684
00685
00686
00687
00688
00689 cpl_imagelist *biases = NULL;
00690 cpl_image *bias = NULL;
00691 cpl_image *master_bias = NULL;
00692 cpl_image *multi_bias = NULL;
00693 cpl_image *flat = NULL;
00694 cpl_image *master_flat = NULL;
00695 cpl_image *added_flat = NULL;
00696 cpl_image *trace_flat = NULL;
00697 cpl_image *smo_flat = NULL;
00698 cpl_image *norm_flat = NULL;
00699 cpl_image *spectra = NULL;
00700 cpl_image *wavemap = NULL;
00701 cpl_image *delta = NULL;
00702 cpl_image *residual = NULL;
00703 cpl_image *checkwave = NULL;
00704 cpl_image *rectified = NULL;
00705 cpl_image *dummy = NULL;
00706 cpl_image *add_dummy = NULL;
00707 cpl_image *refimage = NULL;
00708 cpl_image *coordinate = NULL;
00709 cpl_image *rainbow = NULL;
00710 cpl_image *spatial = NULL;
00711 cpl_image *rect_flat = NULL;
00712 cpl_image *rect_nflat = NULL;
00713 cpl_image *mapped_flat = NULL;
00714 cpl_image *mapped_nflat = NULL;
00715
00716 cpl_mask *refmask = NULL;
00717
00718 cpl_table *grism_table = NULL;
00719 cpl_table *overscans = NULL;
00720 cpl_table *wavelengths = NULL;
00721 cpl_table *idscoeff = NULL;
00722 cpl_table *idscoeff_all = NULL;
00723 cpl_table *restable = NULL;
00724 cpl_table *slits = NULL;
00725 cpl_table *positions = NULL;
00726 cpl_table *maskslits = NULL;
00727 cpl_table *traces = NULL;
00728 cpl_table *polytraces = NULL;
00729 cpl_table *restab = NULL;
00730 cpl_table *global = NULL;
00731
00732 cpl_vector *lines = NULL;
00733
00734 cpl_propertylist *header = NULL;
00735 cpl_propertylist *save_header = NULL;
00736 cpl_propertylist *qclist = NULL;
00737
00738
00739
00740
00741
00742 char version[80];
00743 const char *arc_tag;
00744 const char *flat_tag;
00745 const char *master_screen_flat_tag;
00746 const char *master_norm_flat_tag;
00747 const char *reduced_lamp_tag;
00748 const char *disp_residuals_tag;
00749 const char *disp_coeff_tag;
00750 const char *wavelength_map_tag;
00751 const char *spectra_detection_tag;
00752 const char *spectral_resolution_tag;
00753 const char *slit_map_tag;
00754 const char *curv_traces_tag;
00755 const char *curv_coeff_tag;
00756 const char *spatial_map_tag;
00757 const char *slit_location_tag;
00758 const char *global_distortion_tag = "GLOBAL_DISTORTION_TABLE";
00759 const char *disp_residuals_table_tag;
00760 const char *delta_image_tag;
00761 const char *mapped_screen_flat_tag;
00762 const char *mapped_norm_flat_tag;
00763 const char *keyname;
00764 int mxu, mos, lss;
00765 int treat_as_lss = 0;
00766 int nslits;
00767 float *data;
00768 double *xpos;
00769 double mxpos;
00770 double mean_rms;
00771 double mean_rms_err;
00772 double alltime;
00773 int nflats;
00774 int nbias;
00775 int nlines;
00776 int rebin;
00777 double *line;
00778 double *fiterror = NULL;
00779 int *fitlines = NULL;
00780 int nx, ny;
00781 double reference;
00782 double gain;
00783 int compute_central_wave;
00784 int ccd_xsize, ccd_ysize;
00785 int i;
00786
00787 char *instrume = NULL;
00788 char *pipefile = NULL;
00789 char *wheel4;
00790
00791
00792 snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION);
00793
00794 cpl_msg_set_indentation(2);
00795
00796 if (dfs_files_dont_exist(frameset))
00797 fors_calib_exit(NULL);
00798
00799
00800
00801
00802
00803 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00804 cpl_msg_indent_more();
00805
00806 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00807 fors_calib_exit("Too many in input: GRISM_TABLE");
00808
00809 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00810
00811 dispersion = dfs_get_parameter_double(parlist,
00812 "fors.fors_calib.dispersion", grism_table);
00813
00814 if (dispersion <= 0.0)
00815 fors_calib_exit("Invalid spectral dispersion value");
00816
00817 peakdetection = dfs_get_parameter_double(parlist,
00818 "fors.fors_calib.peakdetection", grism_table);
00819 if (peakdetection <= 0.0)
00820 fors_calib_exit("Invalid peak detection level");
00821
00822 wdegree = dfs_get_parameter_int(parlist,
00823 "fors.fors_calib.wdegree", grism_table);
00824
00825 if (wdegree < 1)
00826 fors_calib_exit("Invalid polynomial degree");
00827
00828 if (wdegree > 5)
00829 fors_calib_exit("Max allowed polynomial degree is 5");
00830
00831 wradius = dfs_get_parameter_int(parlist, "fors.fors_calib.wradius", NULL);
00832
00833 if (wradius < 0)
00834 fors_calib_exit("Invalid search radius");
00835
00836 wreject = dfs_get_parameter_double(parlist,
00837 "fors.fors_calib.wreject", NULL);
00838
00839 if (wreject <= 0.0)
00840 fors_calib_exit("Invalid rejection threshold");
00841
00842 wmode = dfs_get_parameter_int(parlist, "fors.fors_calib.wmode", NULL);
00843
00844 if (wmode < 0 || wmode > 2)
00845 fors_calib_exit("Invalid wavelength solution interpolation mode");
00846
00847 wmosmode = dfs_get_parameter_int(parlist,
00848 "fors.fors_calib.wmosmode", NULL);
00849
00850 if (wmosmode < 0 || wmosmode > 2)
00851 fors_calib_exit("Invalid wavelength solution interpolation mode");
00852
00853 wcolumn = dfs_get_parameter_string(parlist, "fors.fors_calib.wcolumn",
00854 NULL);
00855
00856 cdegree = dfs_get_parameter_int(parlist, "fors.fors_calib.cdegree",
00857 grism_table);
00858
00859 if (cdegree < 1)
00860 fors_calib_exit("Invalid polynomial degree");
00861
00862 if (cdegree > 5)
00863 fors_calib_exit("Max allowed polynomial degree is 5");
00864
00865 cmode = dfs_get_parameter_int(parlist, "fors.fors_calib.cmode", NULL);
00866
00867 if (cmode < 0 || cmode > 2)
00868 fors_calib_exit("Invalid curvature solution interpolation mode");
00869
00870 startwavelength = dfs_get_parameter_double(parlist,
00871 "fors.fors_calib.startwavelength", grism_table);
00872 if (startwavelength > 1.0)
00873 if (startwavelength < 3000.0 || startwavelength > 13000.0)
00874 fors_calib_exit("Invalid wavelength");
00875
00876 endwavelength = dfs_get_parameter_double(parlist,
00877 "fors.fors_calib.endwavelength", grism_table);
00878 if (endwavelength > 1.0) {
00879 if (endwavelength < 3000.0 || endwavelength > 13000.0)
00880 fors_calib_exit("Invalid wavelength");
00881 if (startwavelength < 1.0)
00882 fors_calib_exit("Invalid wavelength interval");
00883 }
00884
00885 if (startwavelength > 1.0)
00886 if (endwavelength - startwavelength <= 0.0)
00887 fors_calib_exit("Invalid wavelength interval");
00888
00889 slit_ident = dfs_get_parameter_bool(parlist,
00890 "fors.fors_calib.slit_ident", NULL);
00891
00892 stack_method = dfs_get_parameter_string(parlist,
00893 "fors.fors_calib.stack_method",
00894 NULL);
00895
00896 if (strcmp(stack_method, "minmax") == 0) {
00897 min_reject = dfs_get_parameter_int(parlist,
00898 "fors.fors_calib.minrejection", NULL);
00899 if (min_reject < 0)
00900 fors_calib_exit("Invalid number of lower rejections");
00901
00902 max_reject = dfs_get_parameter_int(parlist,
00903 "fors.fors_calib.maxrejection", NULL);
00904 if (max_reject < 0)
00905 fors_calib_exit("Invalid number of upper rejections");
00906 }
00907
00908 if (strcmp(stack_method, "ksigma") == 0) {
00909 klow = dfs_get_parameter_double(parlist,
00910 "fors.fors_calib.klow", NULL);
00911 if (klow < 0.1)
00912 fors_calib_exit("Invalid lower K-sigma");
00913
00914 khigh = dfs_get_parameter_double(parlist,
00915 "fors.fors_calib.khigh", NULL);
00916 if (khigh < 0.1)
00917 fors_calib_exit("Invalid lower K-sigma");
00918
00919 kiter = dfs_get_parameter_int(parlist,
00920 "fors.fors_calib.kiter", NULL);
00921 if (kiter < 1)
00922 fors_calib_exit("Invalid number of iterations");
00923 }
00924
00925 sdegree = dfs_get_parameter_int(parlist, "fors.fors_calib.sdegree", NULL);
00926 ddegree = dfs_get_parameter_int(parlist, "fors.fors_calib.ddegree", NULL);
00927 sradius = dfs_get_parameter_int(parlist, "fors.fors_calib.sradius", NULL);
00928 dradius = dfs_get_parameter_int(parlist, "fors.fors_calib.dradius", NULL);
00929
00930 if (sradius < 1 || dradius < 1)
00931 fors_calib_exit("Invalid smoothing box radius");
00932
00933 qc = dfs_get_parameter_bool(parlist, "fors.fors_calib.qc", NULL);
00934
00935 check = dfs_get_parameter_bool(parlist, "fors.fors_calib.check", NULL);
00936
00937 cpl_table_delete(grism_table); grism_table = NULL;
00938
00939 if (cpl_error_get_code())
00940 fors_calib_exit("Failure getting the configuration parameters");
00941
00942
00943
00944
00945
00946
00947 cpl_msg_indent_less();
00948 cpl_msg_info(recipe, "Check input set-of-frames:");
00949 cpl_msg_indent_more();
00950
00951 if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00952 fors_calib_exit("Input frames are not from the same grism");
00953
00954 if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00955 fors_calib_exit("Input frames are not from the same filter");
00956
00957 if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00958 fors_calib_exit("Input frames are not from the same chip");
00959
00960 mxu = cpl_frameset_count_tags(frameset, "LAMP_MXU");
00961 mos = cpl_frameset_count_tags(frameset, "LAMP_MOS");
00962 lss = cpl_frameset_count_tags(frameset, "LAMP_LSS");
00963
00964 if (mxu + mos + lss == 0)
00965 fors_calib_exit("Missing input arc lamp frame");
00966
00967 if (mxu + mos + lss > 1)
00968 fors_calib_exit("Just one input arc lamp frame is allowed");
00969
00970 if (mxu) {
00971 cpl_msg_info(recipe, "MXU data found");
00972 arc_tag = "LAMP_MXU";
00973 flat_tag = "SCREEN_FLAT_MXU";
00974 master_screen_flat_tag = "MASTER_SCREEN_FLAT_MXU";
00975 master_norm_flat_tag = "MASTER_NORM_FLAT_MXU";
00976 reduced_lamp_tag = "REDUCED_LAMP_MXU";
00977 disp_residuals_tag = "DISP_RESIDUALS_MXU";
00978 disp_coeff_tag = "DISP_COEFF_MXU";
00979 wavelength_map_tag = "WAVELENGTH_MAP_MXU";
00980 spectra_detection_tag = "SPECTRA_DETECTION_MXU";
00981 spectral_resolution_tag = "SPECTRAL_RESOLUTION_MXU";
00982 slit_map_tag = "SLIT_MAP_MXU";
00983 curv_traces_tag = "CURV_TRACES_MXU";
00984 curv_coeff_tag = "CURV_COEFF_MXU";
00985 spatial_map_tag = "SPATIAL_MAP_MXU";
00986 slit_location_tag = "SLIT_LOCATION_MXU";
00987 disp_residuals_table_tag = "DISP_RESIDUALS_TABLE_MXU";
00988 delta_image_tag = "DELTA_IMAGE_MXU";
00989 mapped_screen_flat_tag = "MAPPED_SCREEN_FLAT_MXU";
00990 mapped_norm_flat_tag = "MAPPED_NORM_FLAT_MXU";
00991 }
00992
00993 if (lss) {
00994 cpl_msg_info(recipe, "LSS data found");
00995 arc_tag = "LAMP_LSS";
00996 flat_tag = "SCREEN_FLAT_LSS";
00997 master_screen_flat_tag = "MASTER_SCREEN_FLAT_LSS";
00998 master_norm_flat_tag = "MASTER_NORM_FLAT_LSS";
00999 reduced_lamp_tag = "REDUCED_LAMP_LSS";
01000 spectral_resolution_tag = "SPECTRAL_RESOLUTION_LSS";
01001 disp_residuals_tag = "DISP_RESIDUALS_LSS";
01002 disp_coeff_tag = "DISP_COEFF_LSS";
01003 slit_location_tag = "SLIT_LOCATION_LSS";
01004 wavelength_map_tag = "WAVELENGTH_MAP_LSS";
01005 slit_map_tag = "SLIT_MAP_LSS";
01006 disp_residuals_table_tag = "DISP_RESIDUALS_TABLE_LSS";
01007 delta_image_tag = "DELTA_IMAGE_LSS";
01008 mapped_screen_flat_tag = "MAPPED_SCREEN_FLAT_LSS";
01009 mapped_norm_flat_tag = "MAPPED_NORM_FLAT_LSS";
01010 }
01011
01012 if (mos) {
01013 cpl_msg_info(recipe, "MOS data found");
01014 arc_tag = "LAMP_MOS";
01015 flat_tag = "SCREEN_FLAT_MOS";
01016 master_screen_flat_tag = "MASTER_SCREEN_FLAT_MOS";
01017 master_norm_flat_tag = "MASTER_NORM_FLAT_MOS";
01018 reduced_lamp_tag = "REDUCED_LAMP_MOS";
01019 disp_residuals_tag = "DISP_RESIDUALS_MOS";
01020 disp_coeff_tag = "DISP_COEFF_MOS";
01021 wavelength_map_tag = "WAVELENGTH_MAP_MOS";
01022 spectra_detection_tag = "SPECTRA_DETECTION_MOS";
01023 spectral_resolution_tag = "SPECTRAL_RESOLUTION_MOS";
01024 slit_map_tag = "SLIT_MAP_MOS";
01025 curv_traces_tag = "CURV_TRACES_MOS";
01026 curv_coeff_tag = "CURV_COEFF_MOS";
01027 spatial_map_tag = "SPATIAL_MAP_MOS";
01028 slit_location_tag = "SLIT_LOCATION_MOS";
01029 disp_residuals_table_tag = "DISP_RESIDUALS_TABLE_MOS";
01030 delta_image_tag = "DELTA_IMAGE_MOS";
01031 mapped_screen_flat_tag = "MAPPED_SCREEN_FLAT_MOS";
01032 mapped_norm_flat_tag = "MAPPED_NORM_FLAT_MOS";
01033 }
01034
01035 nbias = 0;
01036 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0) {
01037 if (cpl_frameset_count_tags(frameset, "BIAS") == 0)
01038 fors_calib_exit("Missing required input: MASTER_BIAS or BIAS");
01039 nbias = cpl_frameset_count_tags(frameset, "BIAS");
01040 }
01041
01042 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1)
01043 fors_calib_exit("Too many in input: MASTER_BIAS");
01044
01045 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0)
01046 fors_calib_exit("Missing required input: MASTER_LINECAT");
01047
01048 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1)
01049 fors_calib_exit("Too many in input: MASTER_LINECAT");
01050
01051 nflats = cpl_frameset_count_tags(frameset, flat_tag);
01052
01053 if (nflats < 1) {
01054 cpl_msg_error(recipe, "Missing required input: %s", flat_tag);
01055 fors_calib_exit(NULL);
01056 }
01057
01058 cpl_msg_indent_less();
01059
01060 if (nflats > 1)
01061 cpl_msg_info(recipe, "Load %d flat field frames and stack them "
01062 "with method \"%s\"", nflats, stack_method);
01063 else
01064 cpl_msg_info(recipe, "Load flat field exposure...");
01065
01066 cpl_msg_indent_more();
01067
01068 header = dfs_load_header(frameset, flat_tag, 0);
01069
01070 if (header == NULL)
01071 fors_calib_exit("Cannot load flat field frame header");
01072
01073
01074
01075
01076
01077 wheel4 = (char *)cpl_propertylist_get_string(header, "ESO INS OPTI9 TYPE");
01078 if (cpl_error_get_code() != CPL_ERROR_NONE) {
01079 fors_calib_exit("Missing keyword ESO INS OPTI9 TYPE in flat header");
01080 }
01081
01082 if (strcmp("FILT", wheel4) == 0) {
01083 wheel4 = (char *)cpl_propertylist_get_string(header,
01084 "ESO INS OPTI9 NAME");
01085 cpl_msg_error(recipe, "Unsupported filter: %s", wheel4);
01086 fors_calib_exit(NULL);
01087 }
01088
01089 alltime = cpl_propertylist_get_double(header, "EXPTIME");
01090
01091 if (cpl_error_get_code() != CPL_ERROR_NONE)
01092 fors_calib_exit("Missing keyword EXPTIME in flat field frame header");
01093
01094 cpl_propertylist_delete(header);
01095
01096 for (i = 1; i < nflats; i++) {
01097
01098 header = dfs_load_header(frameset, NULL, 0);
01099
01100 if (header == NULL)
01101 fors_calib_exit("Cannot load flat field frame header");
01102
01103 alltime += cpl_propertylist_get_double(header, "EXPTIME");
01104
01105 if (cpl_error_get_code() != CPL_ERROR_NONE)
01106 fors_calib_exit("Missing keyword EXPTIME in flat field "
01107 "frame header");
01108
01109 cpl_propertylist_delete(header);
01110
01111 }
01112
01113 master_flat = dfs_load_image(frameset, flat_tag, CPL_TYPE_FLOAT, 0, 0);
01114
01115 if (master_flat == NULL)
01116 fors_calib_exit("Cannot load flat field");
01117
01118 if (nflats > 1) {
01119 if (strcmp(stack_method, "average") == 0) {
01120 for (i = 1; i < nflats; i++) {
01121 flat = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01122 if (flat) {
01123 cpl_image_add(master_flat, flat);
01124 cpl_image_delete(flat); flat = NULL;
01125 }
01126 else
01127 fors_calib_exit("Cannot load flat field");
01128 }
01129
01130
01131
01132
01133
01134
01135 }
01136 else {
01137 cpl_imagelist *flatlist = NULL;
01138 double rflux, flux;
01139
01140
01141
01142
01143
01144
01145 added_flat = cpl_image_duplicate(master_flat);
01146
01147 flatlist = cpl_imagelist_new();
01148 cpl_imagelist_set(flatlist, master_flat,
01149 cpl_imagelist_get_size(flatlist));
01150 master_flat = NULL;
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161 rflux = cpl_image_get_mean(added_flat);
01162
01163 for (i = 1; i < nflats; i++) {
01164 flat = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01165 if (flat) {
01166 cpl_image_add(added_flat, flat);
01167 flux = cpl_image_get_mean(flat);
01168 cpl_image_multiply_scalar(flat, rflux / flux);
01169 cpl_imagelist_set(flatlist, flat,
01170 cpl_imagelist_get_size(flatlist));
01171 flat = NULL;
01172 }
01173 else {
01174 fors_calib_exit("Cannot load flat field");
01175 }
01176 }
01177
01178 if (strcmp(stack_method, "median") == 0) {
01179 master_flat = cpl_imagelist_collapse_median_create(flatlist);
01180 }
01181
01182 if (strcmp(stack_method, "minmax") == 0) {
01183 master_flat = cpl_imagelist_collapse_minmax_create(flatlist,
01184 min_reject,
01185 max_reject);
01186 }
01187
01188 if (strcmp(stack_method, "ksigma") == 0) {
01189 master_flat = mos_ksigma_stack(flatlist,
01190 klow, khigh, kiter, NULL);
01191 }
01192
01193 cpl_imagelist_delete(flatlist);
01194 }
01195 }
01196
01197
01198
01199
01200
01201
01202 header = dfs_load_header(frameset, arc_tag, 0);
01203
01204 if (header == NULL)
01205 fors_calib_exit("Cannot load arc lamp header");
01206
01207 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
01208 if (instrume == NULL)
01209 fors_calib_exit("Missing keyword INSTRUME in arc lamp header");
01210 instrume = cpl_strdup(instrume);
01211
01212 if (instrume[4] == '1')
01213 snprintf(version, 80, "%s/%s", "fors1", VERSION);
01214 if (instrume[4] == '2')
01215 snprintf(version, 80, "%s/%s", "fors2", VERSION);
01216
01217 reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
01218
01219 if (cpl_error_get_code() != CPL_ERROR_NONE)
01220 fors_calib_exit("Missing keyword ESO INS GRIS1 WLEN in arc lamp "
01221 "frame header");
01222
01223 if (reference < 3000.0)
01224 reference *= 10;
01225
01226 if (reference < 3000.0 || reference > 13000.0) {
01227 cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
01228 "keyword ESO INS GRIS1 WLEN in arc lamp frame header",
01229 reference);
01230 fors_calib_exit(NULL);
01231 }
01232
01233 cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
01234
01235 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
01236
01237 if (cpl_error_get_code() != CPL_ERROR_NONE)
01238 fors_calib_exit("Missing keyword ESO DET WIN1 BINX in arc lamp "
01239 "frame header");
01240
01241 if (rebin != 1) {
01242 dispersion *= rebin;
01243 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
01244 "working dispersion used is %f A/pixel", rebin,
01245 dispersion);
01246 }
01247
01248 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
01249
01250 if (cpl_error_get_code() != CPL_ERROR_NONE)
01251 fors_calib_exit("Missing keyword ESO DET OUT1 CONAD in arc lamp "
01252 "frame header");
01253
01254 cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain);
01255
01256 if (mos || mxu) {
01257
01258 cpl_msg_info(recipe, "Produce mask slit position table...");
01259 if (mos)
01260 maskslits = mos_load_slits_fors_mos(header);
01261 else
01262 maskslits = mos_load_slits_fors_mxu(header);
01263
01264
01265
01266
01267
01268
01269 mxpos = cpl_table_get_column_median(maskslits, "xtop");
01270 xpos = cpl_table_get_data_double(maskslits, "xtop");
01271 nslits = cpl_table_get_nrow(maskslits);
01272
01273 treat_as_lss = 1;
01274 for (i = 0; i < nslits; i++) {
01275 if (fabs(mxpos-xpos[i]) > 0.01) {
01276 treat_as_lss = 0;
01277 break;
01278 }
01279 }
01280
01281 if (treat_as_lss) {
01282 cpl_msg_warning(recipe, "All MOS slits have the same offset: %.2f\n"
01283 "The LSS data reduction strategy is applied!",
01284 mxpos);
01285 cpl_table_delete(maskslits); maskslits = NULL;
01286 if (mos) {
01287 master_screen_flat_tag = "MASTER_SCREEN_FLAT_LONG_MOS";
01288 master_norm_flat_tag = "MASTER_NORM_FLAT_LONG_MOS";
01289 disp_residuals_table_tag = "DISP_RESIDUALS_TABLE_LONG_MOS";
01290 delta_image_tag = "DELTA_IMAGE_LONG_MOS";
01291 spectral_resolution_tag = "SPECTRAL_RESOLUTION_LONG_MOS";
01292 reduced_lamp_tag = "REDUCED_LAMP_LONG_MOS";
01293 disp_coeff_tag = "DISP_COEFF_LONG_MOS";
01294 wavelength_map_tag = "WAVELENGTH_MAP_LONG_MOS";
01295 slit_location_tag = "SLIT_LOCATION_LONG_MOS";
01296 mapped_screen_flat_tag = "MAPPED_SCREEN_FLAT_LONG_MOS";
01297 mapped_norm_flat_tag = "MAPPED_NORM_FLAT_LONG_MOS";
01298 }
01299 else {
01300 master_screen_flat_tag = "MASTER_SCREEN_FLAT_LONG_MXU";
01301 master_norm_flat_tag = "MASTER_NORM_FLAT_LONG_MXU";
01302 disp_residuals_table_tag = "DISP_RESIDUALS_TABLE_LONG_MXU";
01303 delta_image_tag = "DELTA_IMAGE_LONG_MXU";
01304 spectral_resolution_tag = "SPECTRAL_RESOLUTION_LONG_MXU";
01305 reduced_lamp_tag = "REDUCED_LAMP_LONG_MXU";
01306 disp_coeff_tag = "DISP_COEFF_LONG_MXU";
01307 wavelength_map_tag = "WAVELENGTH_MAP_LONG_MXU";
01308 slit_location_tag = "SLIT_LOCATION_LONG_MXU";
01309 mapped_screen_flat_tag = "MAPPED_SCREEN_FLAT_LONG_MXU";
01310 mapped_norm_flat_tag = "MAPPED_NORM_FLAT_LONG_MXU";
01311 }
01312 }
01313 }
01314
01315 if (slit_ident == 0) {
01316 cpl_table_delete(maskslits); maskslits = NULL;
01317 }
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327 if (nbias) {
01328
01329
01330
01331
01332
01333 cpl_msg_info(recipe, "Generate the master from input raw biases...");
01334
01335 if (nbias > 1) {
01336
01337 biases = cpl_imagelist_new();
01338
01339 bias = dfs_load_image(frameset, "BIAS", CPL_TYPE_FLOAT, 0, 0);
01340
01341 if (bias == NULL)
01342 fors_calib_exit("Cannot load bias frame");
01343
01344 cpl_imagelist_set(biases, bias, 0); bias = NULL;
01345
01346 for (i = 1; i < nbias; i++) {
01347 bias = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01348 if (bias) {
01349 cpl_imagelist_set(biases, bias, i); bias = NULL;
01350 }
01351 else
01352 fors_calib_exit("Cannot load bias frame");
01353 }
01354
01355 master_bias = cpl_imagelist_collapse_median_create(biases);
01356
01357 cpl_imagelist_delete(biases);
01358 }
01359 else {
01360 master_bias = dfs_load_image(frameset, "BIAS",
01361 CPL_TYPE_FLOAT, 0, 1);
01362 if (master_bias == NULL)
01363 fors_calib_exit("Cannot load bias");
01364 }
01365
01366 }
01367 else {
01368 master_bias = dfs_load_image(frameset, "MASTER_BIAS",
01369 CPL_TYPE_FLOAT, 0, 1);
01370 if (master_bias == NULL)
01371 fors_calib_exit("Cannot load master bias");
01372 }
01373
01374 cpl_msg_info(recipe, "Remove the master bias...");
01375
01376 overscans = mos_load_overscans_vimos(header, 1);
01377 cpl_propertylist_delete(header); header = NULL;
01378
01379 if (nbias) {
01380 int xlow = cpl_table_get_int(overscans, "xlow", 0, NULL);
01381 int ylow = cpl_table_get_int(overscans, "ylow", 0, NULL);
01382 int xhig = cpl_table_get_int(overscans, "xhig", 0, NULL);
01383 int yhig = cpl_table_get_int(overscans, "yhig", 0, NULL);
01384 dummy = cpl_image_extract(master_bias, xlow+1, ylow+1, xhig, yhig);
01385 cpl_image_delete(master_bias); master_bias = dummy;
01386
01387 if (dfs_save_image(frameset, master_bias, "MASTER_BIAS",
01388 NULL, parlist, recipe, version))
01389 fors_calib_exit(NULL);
01390 }
01391
01392 if (nflats > 1) {
01393 multi_bias = cpl_image_multiply_scalar_create(master_bias, nflats);
01394 dummy = mos_remove_bias(master_flat, multi_bias, overscans);
01395 if (added_flat)
01396 add_dummy = mos_remove_bias(added_flat, multi_bias, overscans);
01397 cpl_image_delete(multi_bias);
01398 }
01399 else {
01400 dummy = mos_remove_bias(master_flat, master_bias, overscans);
01401 }
01402 cpl_image_delete(master_flat);
01403 master_flat = dummy;
01404
01405 if (master_flat == NULL)
01406 fors_calib_exit("Cannot remove bias from flat field");
01407
01408 if (added_flat) {
01409 cpl_image_delete(added_flat);
01410 added_flat = add_dummy;
01411
01412 if (added_flat == NULL)
01413 fors_calib_exit("Cannot remove bias from added flat field");
01414
01415 trace_flat = added_flat;
01416 }
01417 else
01418 trace_flat = master_flat;
01419
01420 cpl_msg_indent_less();
01421 cpl_msg_info(recipe, "Load arc lamp exposure...");
01422 cpl_msg_indent_more();
01423
01424 spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0);
01425
01426 if (spectra == NULL)
01427 fors_calib_exit("Cannot load arc lamp exposure");
01428
01429 cpl_msg_info(recipe, "Remove the master bias...");
01430
01431 dummy = mos_remove_bias(spectra, master_bias, overscans);
01432 cpl_table_delete(overscans); overscans = NULL;
01433 cpl_image_delete(master_bias); master_bias = NULL;
01434 cpl_image_delete(spectra); spectra = dummy;
01435
01436 if (spectra == NULL)
01437 fors_calib_exit("Cannot remove bias from arc lamp exposure");
01438
01439 cpl_msg_indent_less();
01440 cpl_msg_info(recipe, "Load input line catalog...");
01441 cpl_msg_indent_more();
01442
01443 wavelengths = dfs_load_table(frameset, "MASTER_LINECAT", 1);
01444
01445 if (wavelengths == NULL)
01446 fors_calib_exit("Cannot load line catalog");
01447
01448
01449
01450
01451
01452
01453 nlines = cpl_table_get_nrow(wavelengths);
01454
01455 if (nlines == 0)
01456 fors_calib_exit("Empty input line catalog");
01457
01458 if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
01459 cpl_msg_error(recipe, "Missing column %s in input line catalog table",
01460 wcolumn);
01461 fors_calib_exit(NULL);
01462 }
01463
01464 line = cpl_malloc(nlines * sizeof(double));
01465
01466 for (i = 0; i < nlines; i++)
01467 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
01468
01469 cpl_table_delete(wavelengths); wavelengths = NULL;
01470
01471 lines = cpl_vector_wrap(nlines, line);
01472
01473
01474 if (lss || treat_as_lss) {
01475
01476 int first_row, last_row;
01477 int ylow, yhig;
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493 cpl_msg_indent_less();
01494 cpl_msg_info(recipe, "Perform flat field normalisation...");
01495 cpl_msg_indent_more();
01496
01497 norm_flat = cpl_image_duplicate(master_flat);
01498
01499 smo_flat = mos_normalise_longflat(norm_flat, sradius, dradius,
01500 sdegree);
01501
01502 cpl_image_delete(smo_flat); smo_flat = NULL;
01503
01504 if (1) {
01505 save_header = dfs_load_header(frameset, flat_tag, 0);
01506 cpl_propertylist_update_int(save_header,
01507 "ESO PRO DATANCOM", nflats);
01508
01509 if (dfs_save_image(frameset, master_flat, master_screen_flat_tag,
01510 save_header, parlist, recipe, version))
01511 fors_calib_exit(NULL);
01512
01513 }
01514
01515 if (dfs_save_image(frameset, norm_flat, master_norm_flat_tag,
01516 save_header, parlist, recipe, version))
01517 fors_calib_exit(NULL);
01518
01519 cpl_propertylist_delete(save_header); save_header = NULL;
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529 cpl_msg_indent_less();
01530 cpl_msg_info(recipe, "Perform wavelength calibration...");
01531 cpl_msg_indent_more();
01532
01533 nx = cpl_image_get_size_x(spectra);
01534 ny = cpl_image_get_size_y(spectra);
01535
01536 wavemap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01537 idscoeff_all = cpl_table_new(ny);
01538
01539 if (mos_saturation_process(spectra))
01540 fors_calib_exit("Cannot process saturation");
01541
01542 if (mos_subtract_background(spectra))
01543 fors_calib_exit("Cannot subtract the background");
01544
01545 rectified = mos_wavelength_calibration_raw(spectra, lines, dispersion,
01546 peakdetection, wradius,
01547 wdegree, wreject, reference,
01548 &startwavelength,
01549 &endwavelength, NULL,
01550 NULL, idscoeff_all, wavemap,
01551 NULL, NULL, NULL);
01552
01553 if (rectified == NULL)
01554 fors_calib_exit("Wavelength calibration failure.");
01555
01556 if (!cpl_table_has_valid(idscoeff_all, "c0"))
01557 fors_calib_exit("Wavelength calibration failure.");
01558
01559 cpl_image_delete(rectified); rectified = NULL;
01560
01561 first_row = 0;
01562 while (!cpl_table_is_valid(idscoeff_all, "c0", first_row))
01563 first_row++;
01564
01565 last_row = ny - 1;
01566 while (!cpl_table_is_valid(idscoeff_all, "c0", last_row))
01567 last_row--;
01568
01569 ylow = first_row + 1;
01570 yhig = last_row + 1;
01571
01572 if (ylow >= yhig) {
01573 cpl_error_reset();
01574 fors_calib_exit("No spectra could be detected.");
01575 }
01576
01577 cpl_msg_info(recipe,
01578 "Spectral pattern was detected on %d out of %d CCD rows",
01579 yhig - ylow, ny);
01580
01581 dummy = cpl_image_extract(spectra, 1, ylow, nx, yhig);
01582 cpl_image_delete(spectra); spectra = dummy;
01583
01584 ccd_ysize = ny;
01585 ny = cpl_image_get_size_y(spectra);
01586
01587 if (check)
01588 residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01589
01590 fiterror = cpl_calloc(ny, sizeof(double));
01591 fitlines = cpl_calloc(ny, sizeof(int));
01592 idscoeff = cpl_table_new(ny);
01593 restable = cpl_table_new(nlines);
01594
01595 if (mos_saturation_process(spectra))
01596 fors_calib_exit("Cannot process saturation");
01597
01598 if (mos_subtract_background(spectra))
01599 fors_calib_exit("Cannot subtract the background");
01600
01601 rectified = mos_wavelength_calibration_raw(spectra, lines, dispersion,
01602 peakdetection, wradius,
01603 wdegree, wreject, reference,
01604 &startwavelength,
01605 &endwavelength, fitlines,
01606 fiterror, idscoeff, NULL,
01607 residual, restable, NULL);
01608
01609 if (rectified == NULL)
01610 fors_calib_exit("Wavelength calibration failure.");
01611
01612 if (!cpl_table_has_valid(idscoeff, "c0"))
01613 fors_calib_exit("Wavelength calibration failure.");
01614
01615
01616
01617
01618
01619 slits = cpl_table_new(1);
01620 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
01621 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
01622 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
01623 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
01624 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
01625 cpl_table_new_column(slits, "position", CPL_TYPE_INT);
01626 cpl_table_new_column(slits, "length", CPL_TYPE_INT);
01627 cpl_table_set_column_unit(slits, "xtop", "pixel");
01628 cpl_table_set_column_unit(slits, "ytop", "pixel");
01629 cpl_table_set_column_unit(slits, "xbottom", "pixel");
01630 cpl_table_set_column_unit(slits, "ybottom", "pixel");
01631 cpl_table_set_column_unit(slits, "position", "pixel");
01632 cpl_table_set_column_unit(slits, "length", "pixel");
01633 cpl_table_set_int(slits, "slit_id", 0, 0);
01634 cpl_table_set_double(slits, "xtop", 0, 0);
01635 cpl_table_set_double(slits, "ytop", 0, last_row);
01636 cpl_table_set_double(slits, "xbottom", 0, 0);
01637 cpl_table_set_double(slits, "ybottom", 0, first_row);
01638 cpl_table_set_int(slits, "position", 0, 0);
01639 cpl_table_set_int(slits, "length", 0, ny);
01640
01641 if (dfs_save_table(frameset, slits, slit_location_tag, NULL,
01642 parlist, recipe, version))
01643 fors_calib_exit(NULL);
01644
01645 cpl_table_delete(slits); slits = NULL;
01646
01647 if (dfs_save_table(frameset, restable, disp_residuals_table_tag, NULL,
01648 parlist, recipe, version))
01649 fors_calib_exit(NULL);
01650
01651 cpl_table_delete(restable); restable = NULL;
01652
01653 if (wmode) {
01654 cpl_image_delete(rectified); rectified = NULL;
01655 cpl_image_delete(wavemap); wavemap = NULL;
01656 mos_interpolate_wavecalib(idscoeff, wavemap, wmode, 2);
01657 mos_interpolate_wavecalib(idscoeff_all, wavemap, wmode, 2);
01658 wavemap = mos_map_idscoeff(idscoeff_all, nx, reference,
01659 startwavelength, endwavelength);
01660 rectified = mos_wavelength_calibration(spectra, reference,
01661 startwavelength,
01662 endwavelength, dispersion,
01663 idscoeff, 0);
01664 }
01665
01666 cpl_table_delete(idscoeff_all); idscoeff_all = NULL;
01667
01668 cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL;
01669 cpl_table_set_column_unit(idscoeff, "error", "pixel");
01670 cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL;
01671
01672 for (i = 0; i < ny; i++)
01673 if (!cpl_table_is_valid(idscoeff, "c0", i))
01674 cpl_table_set_invalid(idscoeff, "error", i);
01675
01676 delta = mos_map_pixel(idscoeff, reference, startwavelength,
01677 endwavelength, dispersion, 2);
01678
01679
01680 dummy = cpl_image_extract(master_flat, 1, ylow, nx, yhig);
01681 cpl_image_delete(master_flat); master_flat = dummy;
01682
01683 mapped_flat = mos_wavelength_calibration(master_flat, reference,
01684 startwavelength, endwavelength,
01685 dispersion, idscoeff, 0);
01686
01687 cpl_image_delete(master_flat); master_flat = NULL;
01688
01689 dummy = cpl_image_extract(norm_flat, 1, ylow, nx, yhig);
01690 cpl_image_delete(norm_flat); norm_flat = dummy;
01691
01692 mapped_nflat = mos_wavelength_calibration(norm_flat, reference,
01693 startwavelength, endwavelength,
01694 dispersion, idscoeff, 0);
01695
01696 cpl_image_delete(norm_flat); norm_flat = NULL;
01697
01698 header = cpl_propertylist_new();
01699 cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01700 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01701 cpl_propertylist_update_double(header, "CRVAL1",
01702 startwavelength + dispersion/2);
01703 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01704
01705
01706 cpl_propertylist_update_double(header, "CD1_1", dispersion);
01707 cpl_propertylist_update_double(header, "CD1_2", 0.0);
01708 cpl_propertylist_update_double(header, "CD2_1", 0.0);
01709 cpl_propertylist_update_double(header, "CD2_2", 1.0);
01710 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01711 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01712
01713 if (dfs_save_image(frameset, delta, delta_image_tag,
01714 header, parlist, recipe, version))
01715 fors_calib_exit(NULL);
01716
01717 cpl_image_delete(delta); delta = NULL;
01718
01719 if (dfs_save_image(frameset, mapped_flat, mapped_screen_flat_tag,
01720 header, parlist, recipe, version))
01721 fors_calib_exit(NULL);
01722
01723 cpl_image_delete(mapped_flat); mapped_flat = NULL;
01724
01725 if (dfs_save_image(frameset, mapped_nflat, mapped_norm_flat_tag,
01726 header, parlist, recipe, version))
01727 fors_calib_exit(NULL);
01728
01729 cpl_image_delete(mapped_nflat); mapped_nflat = NULL;
01730
01731 cpl_propertylist_delete(header); header = NULL;
01732
01733 cpl_msg_info(recipe, "Valid solutions found: %d out of %d rows",
01734 ny - cpl_table_count_invalid(idscoeff, "c0"), ny);
01735
01736 cpl_image_delete(spectra); spectra = NULL;
01737
01738 mean_rms = mos_distortions_rms(rectified, lines, startwavelength,
01739 dispersion, 6, 0);
01740
01741 cpl_msg_info(recipe, "Mean residual: %f pixel", mean_rms);
01742
01743 mean_rms = cpl_table_get_column_mean(idscoeff, "error");
01744 mean_rms_err = cpl_table_get_column_stdev(idscoeff, "error");
01745
01746 cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)",
01747 mean_rms, mean_rms * dispersion);
01748
01749 restab = mos_resolution_table(rectified, startwavelength, dispersion,
01750 60000, lines);
01751
01752 if (restab) {
01753 cpl_msg_info(recipe, "Mean spectral resolution: %.2f",
01754 cpl_table_get_column_mean(restab, "resolution"));
01755 cpl_msg_info(recipe,
01756 "Mean reference lines FWHM: %.2f +/- %.2f pixel",
01757 cpl_table_get_column_mean(restab, "fwhm") / dispersion,
01758 cpl_table_get_column_mean(restab, "fwhm_rms") / dispersion);
01759
01760 if (qc) {
01761
01762 header = dfs_load_header(frameset, arc_tag, 0);
01763
01764 if (header == NULL)
01765 fors_calib_exit("Cannot reload arc lamp header");
01766
01767 qclist = cpl_propertylist_new();
01768
01769 fors_qc_start_group(qclist, "2.0", instrume);
01770
01771
01772
01773
01774
01775
01776 if (fors_qc_write_string("PRO.CATG", spectral_resolution_tag,
01777 "Product category", instrume))
01778 fors_calib_exit("Cannot write product category to "
01779 "QC log file");
01780
01781 if (fors_qc_keyword_to_paf(header, "ESO DPR TYPE", NULL,
01782 "DPR type", instrume))
01783 fors_calib_exit("Missing keyword DPR TYPE in arc "
01784 "lamp header");
01785
01786 if (fors_qc_keyword_to_paf(header, "ESO TPL ID", NULL,
01787 "Template", instrume))
01788 fors_calib_exit("Missing keyword TPL ID in arc "
01789 "lamp header");
01790
01791 if (fors_qc_keyword_to_paf(header, "ESO INS GRIS1 NAME", NULL,
01792 "Grism name", instrume))
01793 fors_calib_exit("Missing keyword INS GRIS1 NAME in arc "
01794 "lamp header");
01795
01796 if (fors_qc_keyword_to_paf(header, "ESO INS GRIS1 ID", NULL,
01797 "Grism identifier", instrume))
01798 fors_calib_exit("Missing keyword INS GRIS1 ID in arc "
01799 "lamp header");
01800
01801 if (cpl_propertylist_has(header, "ESO INS FILT1 NAME"))
01802 fors_qc_keyword_to_paf(header, "ESO INS FILT1 NAME", NULL,
01803 "Filter name", instrume);
01804
01805 if (fors_qc_keyword_to_paf(header, "ESO INS COLL NAME", NULL,
01806 "Collimator name", instrume))
01807 fors_calib_exit("Missing keyword INS COLL NAME in arc "
01808 "lamp header");
01809
01810 if (fors_qc_keyword_to_paf(header, "ESO DET CHIP1 ID", NULL,
01811 "Chip identifier", instrume))
01812 fors_calib_exit("Missing keyword DET CHIP1 ID in arc "
01813 "lamp header");
01814
01815 if (mos) {
01816 if (fors_qc_keyword_to_paf(header, "ESO INS MOS10 WID",
01817 "arcsec", "Slit width", instrume))
01818 fors_calib_exit("Missing keyword ESO INS MOS1 WID in "
01819 "arc lamp header");
01820 }
01821 else {
01822 if (fors_qc_keyword_to_paf(header, "ESO INS SLIT WID",
01823 "arcsec", "Slit width", instrume))
01824 fors_calib_exit("Missing keyword ESO INS SLIT WID in "
01825 "arc lamp header");
01826 }
01827
01828 if (fors_qc_keyword_to_paf(header, "ESO DET WIN1 BINX", NULL,
01829 "Binning factor along X", instrume))
01830 fors_calib_exit("Missing keyword ESO DET WIN1 BINX "
01831 "in frame header");
01832
01833 if (fors_qc_keyword_to_paf(header, "ESO DET WIN1 BINY", NULL,
01834 "Binning factor along Y", instrume))
01835 fors_calib_exit("Missing keyword ESO DET WIN1 BINY "
01836 "in frame header");
01837
01838 if (fors_qc_keyword_to_paf(header, "ARCFILE", NULL,
01839 "Archive name of input data",
01840 instrume))
01841 fors_calib_exit("Missing keyword ARCFILE in arc "
01842 "lamp header");
01843
01844 cpl_propertylist_delete(header); header = NULL;
01845
01846 pipefile = dfs_generate_filename_tfits(spectral_resolution_tag);
01847 if (fors_qc_write_string("PIPEFILE", pipefile,
01848 "Pipeline product name", instrume))
01849 fors_calib_exit("Cannot write PIPEFILE to QC log file");
01850 cpl_free(pipefile); pipefile = NULL;
01851
01852
01853
01854
01855
01856
01857 if (mos)
01858 keyname = "QC.MOS.RESOLUTION";
01859 else
01860 keyname = "QC.LSS.RESOLUTION";
01861
01862 if (fors_qc_write_qc_double(qclist,
01863 cpl_table_get_column_mean(restab,
01864 "resolution"),
01865 keyname, NULL,
01866 "Mean spectral resolution",
01867 instrume)) {
01868 fors_calib_exit("Cannot write mean spectral resolution to "
01869 "QC log file");
01870 }
01871
01872 if (mos)
01873 keyname = "QC.MOS.RESOLUTION.RMS";
01874 else
01875 keyname = "QC.LSS.RESOLUTION.RMS";
01876
01877 if (fors_qc_write_qc_double(qclist,
01878 cpl_table_get_column_stdev(restab,
01879 "resolution"),
01880 keyname, NULL,
01881 "Scatter of spectral resolution",
01882 instrume)) {
01883 fors_calib_exit("Cannot write spectral resolution scatter "
01884 "to QC log file");
01885 }
01886
01887 if (mos)
01888 keyname = "QC.MOS.RESOLUTION.NWAVE";
01889 else
01890 keyname = "QC.LSS.RESOLUTION.NWAVE";
01891
01892 if (fors_qc_write_qc_int(qclist, cpl_table_get_nrow(restab) -
01893 cpl_table_count_invalid(restab,
01894 "resolution"),
01895 keyname, NULL,
01896 "Number of examined wavelengths "
01897 "for resolution computation",
01898 instrume)) {
01899 fors_calib_exit("Cannot write number of lines used in "
01900 "spectral resolution computation "
01901 "to QC log file");
01902 }
01903
01904 if (mos)
01905 keyname = "QC.MOS.RESOLUTION.MEANRMS";
01906 else
01907 keyname = "QC.LSS.RESOLUTION.MEANRMS";
01908
01909 if (fors_qc_write_qc_double(qclist,
01910 cpl_table_get_column_mean(restab,
01911 "resolution_rms"),
01912 keyname, NULL,
01913 "Mean error on spectral "
01914 "resolution computation",
01915 instrume)) {
01916 fors_calib_exit("Cannot write mean error in "
01917 "spectral resolution computation "
01918 "to QC log file");
01919 }
01920
01921 if (mos)
01922 keyname = "QC.MOS.RESOLUTION.NLINES";
01923 else
01924 keyname = "QC.LSS.RESOLUTION.NLINES";
01925
01926 if (fors_qc_write_qc_int(qclist,
01927 cpl_table_get_column_mean(restab, "nlines") *
01928 cpl_table_get_nrow(restab),
01929 keyname, NULL,
01930 "Number of lines for spectral "
01931 "resolution computation",
01932 instrume)) {
01933 fors_calib_exit("Cannot write number of examined "
01934 "wavelengths in spectral resolution computation "
01935 "to QC log file");
01936 }
01937
01938 fors_qc_end_group();
01939
01940 }
01941
01942 if (dfs_save_table(frameset, restab, spectral_resolution_tag,
01943 qclist, parlist, recipe, version))
01944 fors_calib_exit(NULL);
01945
01946 cpl_table_delete(restab); restab = NULL;
01947 cpl_propertylist_delete(qclist); qclist = NULL;
01948
01949 }
01950 else
01951 fors_calib_exit("Cannot compute the spectral resolution table");
01952
01953 cpl_vector_delete(lines); lines = NULL;
01954
01955
01956
01957
01958
01959
01960 header = cpl_propertylist_new();
01961 cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01962 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01963 cpl_propertylist_update_double(header, "CRVAL1",
01964 startwavelength + dispersion/2);
01965 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01966
01967
01968 cpl_propertylist_update_double(header, "CD1_1", dispersion);
01969 cpl_propertylist_update_double(header, "CD1_2", 0.0);
01970 cpl_propertylist_update_double(header, "CD2_1", 0.0);
01971 cpl_propertylist_update_double(header, "CD2_2", 1.0);
01972 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01973 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01974 cpl_propertylist_update_int(header, "ESO PRO DATANCOM", 1);
01975
01976 if (dfs_save_image(frameset, rectified, reduced_lamp_tag, header,
01977 parlist, recipe, version))
01978 fors_calib_exit(NULL);
01979
01980 cpl_image_delete(rectified); rectified = NULL;
01981 cpl_propertylist_delete(header); header = NULL;
01982
01983 if (dfs_save_table(frameset, idscoeff, disp_coeff_tag, NULL,
01984 parlist, recipe, version))
01985 fors_calib_exit(NULL);
01986
01987 cpl_table_delete(idscoeff); idscoeff = NULL;
01988
01989 header = dfs_load_header(frameset, arc_tag, 0);
01990
01991 if (header == NULL)
01992 fors_calib_exit("Cannot reload arc lamp header");
01993
01994 if (qc) {
01995
01996 compute_central_wave = 0;
01997 if (lss) {
01998
01999
02000
02001
02002 compute_central_wave = 1;
02003 }
02004 else {
02005 if (fabs(mxpos) < 0.05)
02006 compute_central_wave = 1;
02007 }
02008
02009 fors_qc_start_group(header, "2.0", instrume);
02010
02011
02012
02013
02014
02015 if (fors_qc_write_string("PRO.CATG", wavelength_map_tag,
02016 "Product category", instrume))
02017 fors_calib_exit("Cannot write product category to "
02018 "QC log file");
02019
02020 if (fors_qc_keyword_to_paf(header, "ESO DPR TYPE", NULL,
02021 "DPR type", instrume))
02022 fors_calib_exit("Missing keyword DPR TYPE in arc "
02023 "lamp header");
02024
02025 if (fors_qc_keyword_to_paf(header, "ESO TPL ID", NULL,
02026 "Template", instrume))
02027 fors_calib_exit("Missing keyword TPL ID in arc "
02028 "lamp header");
02029
02030 if (fors_qc_keyword_to_paf(header, "ESO INS GRIS1 NAME", NULL,
02031 "Grism name", instrume))
02032 fors_calib_exit("Missing keyword INS GRIS1 NAME in arc "
02033 "lamp header");
02034
02035 if (fors_qc_keyword_to_paf(header, "ESO INS GRIS1 ID", NULL,
02036 "Grism identifier", instrume))
02037 fors_calib_exit("Missing keyword INS GRIS1 ID in arc "
02038 "lamp header");
02039
02040 if (cpl_propertylist_has(header, "ESO INS FILT1 NAME"))
02041 fors_qc_keyword_to_paf(header, "ESO INS FILT1 NAME", NULL,
02042 "Filter name", instrume);
02043
02044 if (fors_qc_keyword_to_paf(header, "ESO INS COLL NAME", NULL,
02045 "Collimator name", instrume))
02046 fors_calib_exit("Missing keyword INS COLL NAME in arc "
02047 "lamp header");
02048
02049 if (fors_qc_keyword_to_paf(header, "ESO DET CHIP1 ID", NULL,
02050 "Chip identifier", instrume))
02051 fors_calib_exit("Missing keyword DET CHIP1 ID in arc "
02052 "lamp header");
02053
02054 if (mos) {
02055 if (fors_qc_keyword_to_paf(header, "ESO INS MOS10 WID",
02056 "arcsec", "Slit width", instrume))
02057 fors_calib_exit("Missing keyword ESO INS MOS1 WID in "
02058 "arc lamp header");
02059 }
02060 else {
02061 if (fors_qc_keyword_to_paf(header, "ESO INS SLIT WID",
02062 "arcsec", "Slit width", instrume))
02063 fors_calib_exit("Missing keyword ESO INS SLIT WID in "
02064 "arc lamp header");
02065 }
02066
02067 if (fors_qc_keyword_to_paf(header, "ESO DET WIN1 BINX", NULL,
02068 "Binning factor along X", instrume))
02069 fors_calib_exit("Missing keyword ESO DET WIN1 BINX "
02070 "in frame header");
02071
02072 if (fors_qc_keyword_to_paf(header, "ESO DET WIN1 BINY", NULL,
02073 "Binning factor along Y", instrume))
02074 fors_calib_exit("Missing keyword ESO DET WIN1 BINY "
02075 "in frame header");
02076
02077 if (fors_qc_keyword_to_paf(header, "ARCFILE", NULL,
02078 "Archive name of input data",
02079 instrume))
02080 fors_calib_exit("Missing keyword ARCFILE in arc "
02081 "lamp header");
02082
02083 pipefile = dfs_generate_filename(wavelength_map_tag);
02084 if (fors_qc_write_string("PIPEFILE", pipefile,
02085 "Pipeline product name", instrume))
02086 fors_calib_exit("Cannot write PIPEFILE to QC log file");
02087 cpl_free(pipefile); pipefile = NULL;
02088
02089
02090
02091
02092
02093
02094 if (fors_qc_write_qc_double(header,
02095 mean_rms,
02096 "QC.WAVE.ACCURACY",
02097 "pixel",
02098 "Mean accuracy of wavecalib model",
02099 instrume)) {
02100 fors_calib_exit("Cannot write mean wavelength calibration "
02101 "accuracy to QC log file");
02102 }
02103
02104 if (fors_qc_write_qc_double(header,
02105 mean_rms_err,
02106 "QC.WAVE.ACCURACY.ERROR",
02107 "pixel",
02108 "Error on accuracy of wavecalib model",
02109 instrume)) {
02110 fors_calib_exit("Cannot write error on wavelength calibration "
02111 "accuracy to QC log file");
02112 }
02113
02114 if (compute_central_wave) {
02115
02116 data = cpl_image_get_data(wavemap);
02117
02118 if (lss) {
02119 if (fors_qc_write_qc_double(header,
02120 data[nx/2 + ccd_ysize*nx/2],
02121 "QC.LSS.CENTRAL.WAVELENGTH",
02122 "Angstrom",
02123 "Wavelength at CCD center",
02124 instrume)) {
02125 fors_calib_exit("Cannot write central wavelength to QC "
02126 "log file");
02127 }
02128 }
02129 else {
02130 if (fors_qc_write_qc_double(header,
02131 data[nx/2 + ccd_ysize*nx/2],
02132 "QC.MOS.CENTRAL.WAVELENGTH",
02133 "Angstrom",
02134 "Wavelength at CCD center",
02135 instrume)) {
02136 fors_calib_exit("Cannot write central wavelength to QC "
02137 "log file");
02138 }
02139 }
02140 }
02141
02142 fors_qc_end_group();
02143
02144 }
02145
02146 if (dfs_save_image(frameset, wavemap, wavelength_map_tag, header,
02147 parlist, recipe, version))
02148 fors_calib_exit(NULL);
02149
02150 cpl_image_delete(wavemap); wavemap = NULL;
02151
02152 cpl_propertylist_erase_regexp(header, "^ESO QC ", 0);
02153
02154 if (check) {
02155 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
02156 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
02157
02158 cpl_propertylist_update_double(header, "CD1_1", 1.0);
02159 cpl_propertylist_update_double(header, "CD1_2", 0.0);
02160 cpl_propertylist_update_double(header, "CD2_1", 0.0);
02161 cpl_propertylist_update_double(header, "CD2_2", 1.0);
02162 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
02163 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
02164
02165 if (dfs_save_image(frameset, residual, disp_residuals_tag, header,
02166 parlist, recipe, version))
02167 fors_calib_exit(NULL);
02168
02169 cpl_image_delete(residual); residual = NULL;
02170 }
02171
02172 cpl_propertylist_delete(header); header = NULL;
02173 cpl_free(instrume); instrume = NULL;
02174
02175 return 0;
02176
02177 }
02178
02179
02180
02181
02182
02183
02184
02185
02186
02187
02188 cpl_msg_indent_less();
02189 cpl_msg_info(recipe, "Detecting spectra on CCD...");
02190 cpl_msg_indent_more();
02191
02192 ccd_xsize = nx = cpl_image_get_size_x(spectra);
02193 ccd_ysize = ny = cpl_image_get_size_y(spectra);
02194
02195 refmask = cpl_mask_new(nx, ny);
02196
02197 if (mos_saturation_process(spectra))
02198 fors_calib_exit("Cannot process saturation");
02199
02200 if (mos_subtract_background(spectra))
02201 fors_calib_exit("Cannot subtract the background");
02202
02203 checkwave = mos_wavelength_calibration_raw(spectra, lines, dispersion,
02204 peakdetection, wradius,
02205 wdegree, wreject, reference,
02206 &startwavelength, &endwavelength,
02207 NULL, NULL, NULL, NULL, NULL,
02208 NULL, refmask);
02209
02210 if (checkwave == NULL)
02211 fors_calib_exit("Wavelength calibration failure.");
02212
02213
02214
02215
02216
02217 header = cpl_propertylist_new();
02218 cpl_propertylist_update_double(header, "CRPIX1", 1.0);
02219 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
02220 cpl_propertylist_update_double(header, "CRVAL1",
02221 startwavelength + dispersion/2);
02222 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
02223
02224
02225 cpl_propertylist_update_double(header, "CD1_1", dispersion);
02226 cpl_propertylist_update_double(header, "CD1_2", 0.0);
02227 cpl_propertylist_update_double(header, "CD2_1", 0.0);
02228 cpl_propertylist_update_double(header, "CD2_2", 1.0);
02229 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
02230 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
02231
02232 if (check) {
02233 if (dfs_save_image(frameset, checkwave, spectra_detection_tag, header,
02234 parlist, recipe, version))
02235 fors_calib_exit(NULL);
02236 }
02237
02238 cpl_image_delete(checkwave); checkwave = NULL;
02239 cpl_propertylist_delete(header); header = NULL;
02240
02241 cpl_msg_info(recipe, "Locate slits at reference wavelength on CCD...");
02242 slits = mos_locate_spectra(refmask);
02243
02244 if (!slits) {
02245 cpl_msg_error(cpl_error_get_where(), cpl_error_get_message());
02246 fors_calib_exit("No slits could be detected!");
02247 }
02248
02249 refimage = cpl_image_new_from_mask(refmask);
02250 cpl_mask_delete(refmask); refmask = NULL;
02251
02252 if (check) {
02253 save_header = dfs_load_header(frameset, arc_tag, 0);
02254 if (dfs_save_image(frameset, refimage, slit_map_tag, save_header,
02255 parlist, recipe, version))
02256 fors_calib_exit(NULL);
02257 cpl_propertylist_delete(save_header); save_header = NULL;
02258 }
02259
02260 cpl_image_delete(refimage); refimage = NULL;
02261
02262 if (slit_ident) {
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278 cpl_msg_indent_less();
02279 cpl_msg_info(recipe, "Attempt slit identification (optional)...");
02280 cpl_msg_indent_more();
02281
02282 positions = mos_identify_slits(slits, maskslits, NULL);
02283
02284 if (positions) {
02285 cpl_table_delete(slits);
02286 slits = positions;
02287
02288
02289
02290
02291
02292 cpl_table_and_selected_double(slits,
02293 "ybottom", CPL_GREATER_THAN, ny-1);
02294 cpl_table_or_selected_double(slits,
02295 "ytop", CPL_LESS_THAN, 0);
02296 cpl_table_erase_selected(slits);
02297
02298 nslits = cpl_table_get_nrow(slits);
02299
02300 if (nslits == 0)
02301 fors_calib_exit("No slits found on the CCD");
02302
02303 cpl_msg_info(recipe, "%d slits are entirely or partially "
02304 "contained in CCD", nslits);
02305
02306 }
02307 else {
02308 slit_ident = 0;
02309 cpl_msg_info(recipe, "Global distortion model cannot be computed");
02310 if (cpl_error_get_code() != CPL_ERROR_NONE) {
02311 fors_calib_exit(NULL);
02312 }
02313 }
02314 }
02315
02316
02317
02318
02319
02320
02321 cpl_msg_indent_less();
02322 cpl_msg_info(recipe, "Determining spectral curvature...");
02323 cpl_msg_indent_more();
02324
02325 cpl_msg_info(recipe, "Tracing master flat field spectra edges...");
02326 traces = mos_trace_flat(trace_flat, slits, reference,
02327 startwavelength, endwavelength, dispersion);
02328
02329 if (!traces)
02330 fors_calib_exit("Tracing failure");
02331
02332 cpl_image_delete(added_flat); added_flat = NULL;
02333
02334 cpl_msg_info(recipe, "Fitting flat field spectra edges...");
02335 polytraces = mos_poly_trace(slits, traces, cdegree);
02336
02337 if (!polytraces)
02338 fors_calib_exit("Trace fitting failure");
02339
02340 if (cmode) {
02341 cpl_msg_info(recipe, "Computing global spectral curvature model...");
02342 mos_global_trace(slits, polytraces, cmode);
02343 }
02344
02345 if (dfs_save_table(frameset, traces, curv_traces_tag, NULL, parlist,
02346 recipe, version))
02347 fors_calib_exit(NULL);
02348
02349 cpl_table_delete(traces); traces = NULL;
02350
02351 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
02352 spatial = mos_spatial_calibration(spectra, slits, polytraces, reference,
02353 startwavelength, endwavelength,
02354 dispersion, 0, coordinate);
02355
02356 if (!slit_ident) {
02357 cpl_image_delete(spectra); spectra = NULL;
02358 }
02359
02360
02361
02362
02363
02364
02365
02366 cpl_msg_indent_less();
02367 cpl_msg_info(recipe, "Perform flat field normalisation...");
02368 cpl_msg_indent_more();
02369
02370 norm_flat = cpl_image_duplicate(master_flat);
02371
02372 smo_flat = mos_normalise_flat(norm_flat, coordinate, slits, polytraces,
02373 reference, startwavelength, endwavelength,
02374 dispersion, dradius, ddegree);
02375
02376 cpl_image_delete(smo_flat); smo_flat = NULL;
02377
02378
02379 save_header = dfs_load_header(frameset, flat_tag, 0);
02380 cpl_propertylist_update_int(save_header, "ESO PRO DATANCOM", nflats);
02381
02382 rect_flat = mos_spatial_calibration(master_flat, slits, polytraces,
02383 reference, startwavelength,
02384 endwavelength, dispersion, 0, NULL);
02385 rect_nflat = mos_spatial_calibration(norm_flat, slits, polytraces,
02386 reference, startwavelength,
02387 endwavelength, dispersion, 0, NULL);
02388
02389
02390 if (dfs_save_image(frameset, master_flat, master_screen_flat_tag,
02391 save_header, parlist, recipe, version))
02392 fors_calib_exit(NULL);
02393
02394 cpl_image_delete(master_flat); master_flat = NULL;
02395
02396 if (dfs_save_image(frameset, norm_flat, master_norm_flat_tag,
02397 save_header, parlist, recipe, version))
02398 fors_calib_exit(NULL);
02399
02400 cpl_image_delete(norm_flat); norm_flat = NULL;
02401 cpl_propertylist_delete(save_header); save_header = NULL;
02402
02403
02404
02405
02406
02407
02408
02409 cpl_msg_indent_less();
02410 cpl_msg_info(recipe, "Perform final wavelength calibration...");
02411 cpl_msg_indent_more();
02412
02413 nx = cpl_image_get_size_x(spatial);
02414 ny = cpl_image_get_size_y(spatial);
02415
02416 idscoeff = cpl_table_new(ny);
02417 restable = cpl_table_new(nlines);
02418 rainbow = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
02419 if (check)
02420 residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
02421 fiterror = cpl_calloc(ny, sizeof(double));
02422 fitlines = cpl_calloc(ny, sizeof(int));
02423
02424 rectified = mos_wavelength_calibration_final(spatial, slits, lines,
02425 dispersion, peakdetection,
02426 wradius, wdegree, wreject,
02427 reference, &startwavelength,
02428 &endwavelength, fitlines,
02429 fiterror, idscoeff, rainbow,
02430 residual, restable);
02431
02432
02433
02434
02435
02436 if (rectified == NULL)
02437 fors_calib_exit("Wavelength calibration failure.");
02438
02439 if (dfs_save_table(frameset, restable, disp_residuals_table_tag, NULL,
02440 parlist, recipe, version))
02441 fors_calib_exit(NULL);
02442
02443 cpl_table_delete(restable); restable = NULL;
02444
02445 cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL;
02446 cpl_table_set_column_unit(idscoeff, "error", "pixel");
02447 cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL;
02448
02449 for (i = 0; i < ny; i++)
02450 if (!cpl_table_is_valid(idscoeff, "c0", i))
02451 cpl_table_set_invalid(idscoeff, "error", i);
02452
02453 if (wmosmode > 0) {
02454 mos_interpolate_wavecalib_slit(idscoeff, slits, 1, wmosmode - 1);
02455
02456 cpl_image_delete(rectified);
02457
02458 rectified = mos_wavelength_calibration(spatial, reference,
02459 startwavelength, endwavelength,
02460 dispersion, idscoeff, 0);
02461 }
02462
02463 cpl_image_delete(spatial); spatial = NULL;
02464
02465 delta = mos_map_pixel(idscoeff, reference, startwavelength,
02466 endwavelength, dispersion, 2);
02467
02468 header = cpl_propertylist_new();
02469 cpl_propertylist_update_double(header, "CRPIX1", 1.0);
02470 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
02471 cpl_propertylist_update_double(header, "CRVAL1",
02472 startwavelength + dispersion/2);
02473 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
02474
02475
02476 cpl_propertylist_update_double(header, "CD1_1", dispersion);
02477 cpl_propertylist_update_double(header, "CD1_2", 0.0);
02478 cpl_propertylist_update_double(header, "CD2_1", 0.0);
02479 cpl_propertylist_update_double(header, "CD2_2", 1.0);
02480 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
02481 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
02482
02483 if (dfs_save_image(frameset, delta, delta_image_tag,
02484 header, parlist, recipe, version))
02485 fors_calib_exit(NULL);
02486
02487 cpl_image_delete(delta); delta = NULL;
02488 cpl_propertylist_delete(header); header = NULL;
02489
02490 mean_rms = mos_distortions_rms(rectified, lines, startwavelength,
02491 dispersion, 6, 0);
02492
02493 cpl_msg_info(recipe, "Mean residual: %f pixel", mean_rms);
02494
02495 mean_rms = cpl_table_get_column_mean(idscoeff, "error");
02496 mean_rms_err = cpl_table_get_column_stdev(idscoeff, "error");
02497
02498 cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)",
02499 mean_rms, mean_rms * dispersion);
02500
02501 restab = mos_resolution_table(rectified, startwavelength, dispersion,
02502 60000, lines);
02503
02504 if (restab) {
02505 cpl_msg_info(recipe, "Mean spectral resolution: %.2f",
02506 cpl_table_get_column_mean(restab, "resolution"));
02507 cpl_msg_info(recipe, "Mean reference lines FWHM: %.2f +/- %.2f pixel",
02508 cpl_table_get_column_mean(restab, "fwhm") / dispersion,
02509 cpl_table_get_column_mean(restab, "fwhm_rms") / dispersion);
02510
02511 if (qc) {
02512
02513 header = dfs_load_header(frameset, arc_tag, 0);
02514
02515 if (header == NULL)
02516 fors_calib_exit("Cannot reload arc lamp header");
02517
02518 qclist = cpl_propertylist_new();
02519
02520 fors_qc_start_group(qclist, "2.0", instrume);
02521
02522
02523
02524
02525
02526
02527 if (fors_qc_write_string("PRO.CATG", spectral_resolution_tag,
02528 "Product category", instrume))
02529 fors_calib_exit("Cannot write product category to "
02530 "QC log file");
02531
02532 if (fors_qc_keyword_to_paf(header, "ESO DPR TYPE", NULL,
02533 "DPR type", instrume))
02534 fors_calib_exit("Missing keyword DPR TYPE in arc "
02535 "lamp header");
02536
02537 if (fors_qc_keyword_to_paf(header, "ESO TPL ID", NULL,
02538 "Template", instrume))
02539 fors_calib_exit("Missing keyword TPL ID in arc "
02540 "lamp header");
02541
02542 if (fors_qc_keyword_to_paf(header, "ESO INS GRIS1 NAME", NULL,
02543 "Grism name", instrume))
02544 fors_calib_exit("Missing keyword INS GRIS1 NAME in arc "
02545 "lamp header");
02546
02547 if (fors_qc_keyword_to_paf(header, "ESO INS GRIS1 ID", NULL,
02548 "Grism identifier", instrume))
02549 fors_calib_exit("Missing keyword INS GRIS1 ID in arc "
02550 "lamp header");
02551
02552 if (cpl_propertylist_has(header, "ESO INS FILT1 NAME"))
02553 fors_qc_keyword_to_paf(header, "ESO INS FILT1 NAME", NULL,
02554 "Filter name", instrume);
02555
02556 if (fors_qc_keyword_to_paf(header, "ESO INS COLL NAME", NULL,
02557 "Collimator name", instrume))
02558 fors_calib_exit("Missing keyword INS COLL NAME in arc "
02559 "lamp header");
02560
02561 if (fors_qc_keyword_to_paf(header, "ESO DET CHIP1 ID", NULL,
02562 "Chip identifier", instrume))
02563 fors_calib_exit("Missing keyword DET CHIP1 ID in arc "
02564 "lamp header");
02565
02566 if (fors_qc_keyword_to_paf(header, "ARCFILE", NULL,
02567 "Archive name of input data",
02568 instrume))
02569 fors_calib_exit("Missing keyword ARCFILE in arc "
02570 "lamp header");
02571
02572 cpl_propertylist_delete(header); header = NULL;
02573
02574 pipefile = dfs_generate_filename_tfits(spectral_resolution_tag);
02575 if (fors_qc_write_string("PIPEFILE", pipefile,
02576 "Pipeline product name", instrume))
02577 fors_calib_exit("Cannot write PIPEFILE to QC log file");
02578 cpl_free(pipefile); pipefile = NULL;
02579
02580
02581
02582
02583
02584
02585 if (mos)
02586 keyname = "QC.MOS.RESOLUTION";
02587 else
02588 keyname = "QC.MXU.RESOLUTION";
02589
02590 if (fors_qc_write_qc_double(qclist,
02591 cpl_table_get_column_mean(restab,
02592 "resolution"),
02593 keyname,
02594 "Angstrom",
02595 "Mean spectral resolution",
02596 instrume)) {
02597 fors_calib_exit("Cannot write mean spectral resolution to QC "
02598 "log file");
02599 }
02600
02601 if (mos)
02602 keyname = "QC.MOS.RESOLUTION.RMS";
02603 else
02604 keyname = "QC.MXU.RESOLUTION.RMS";
02605
02606 if (fors_qc_write_qc_double(qclist,
02607 cpl_table_get_column_stdev(restab,
02608 "resolution"),
02609 keyname,
02610 "Angstrom",
02611 "Scatter of spectral resolution",
02612 instrume)) {
02613 fors_calib_exit("Cannot write spectral resolution scatter "
02614 "to QC log file");
02615 }
02616
02617 if (mos)
02618 keyname = "QC.MOS.RESOLUTION.NWAVE";
02619 else
02620 keyname = "QC.MXU.RESOLUTION.NWAVE";
02621
02622 if (fors_qc_write_qc_int(qclist, cpl_table_get_nrow(restab) -
02623 cpl_table_count_invalid(restab,
02624 "resolution"),
02625 keyname,
02626 NULL,
02627 "Number of examined wavelengths "
02628 "for resolution computation",
02629 instrume)) {
02630 fors_calib_exit("Cannot write number of lines used in "
02631 "spectral resolution computation "
02632 "to QC log file");
02633 }
02634
02635 if (mos)
02636 keyname = "QC.MOS.RESOLUTION.MEANRMS";
02637 else
02638 keyname = "QC.MXU.RESOLUTION.MEANRMS";
02639
02640 if (fors_qc_write_qc_double(qclist,
02641 cpl_table_get_column_mean(restab,
02642 "resolution_rms"),
02643 keyname, NULL,
02644 "Mean error on spectral "
02645 "resolution computation",
02646 instrume)) {
02647 fors_calib_exit("Cannot write mean error in "
02648 "spectral resolution computation "
02649 "to QC log file");
02650 }
02651
02652 if (mos)
02653 keyname = "QC.MOS.RESOLUTION.NLINES";
02654 else
02655 keyname = "QC.MXU.RESOLUTION.NLINES";
02656
02657 if (fors_qc_write_qc_int(qclist,
02658 cpl_table_get_column_mean(restab, "nlines") *
02659 cpl_table_get_nrow(restab),
02660 keyname, NULL,
02661 "Number of lines for spectral "
02662 "resolution computation",
02663 instrume)) {
02664 fors_calib_exit("Cannot write number of examined "
02665 "wavelengths in spectral resolution computation "
02666 "to QC log file");
02667 }
02668
02669 fors_qc_end_group();
02670
02671 }
02672
02673 if (dfs_save_table(frameset, restab, spectral_resolution_tag, qclist,
02674 parlist, recipe, version))
02675 fors_calib_exit(NULL);
02676
02677 cpl_table_delete(restab); restab = NULL;
02678 cpl_propertylist_delete(qclist); qclist = NULL;
02679
02680 }
02681 else
02682 fors_calib_exit("Cannot compute the spectral resolution table");
02683
02684 cpl_vector_delete(lines); lines = NULL;
02685
02686 if (dfs_save_table(frameset, idscoeff, disp_coeff_tag, NULL,
02687 parlist, recipe, version))
02688 fors_calib_exit(NULL);
02689
02690
02691 mapped_flat = mos_wavelength_calibration(rect_flat, reference,
02692 startwavelength, endwavelength,
02693 dispersion, idscoeff, 0);
02694
02695 mapped_nflat = mos_wavelength_calibration(rect_nflat, reference,
02696 startwavelength, endwavelength,
02697 dispersion, idscoeff, 0);
02698
02699 cpl_image_delete(rect_flat); rect_flat = NULL;
02700 cpl_image_delete(rect_nflat); rect_nflat = NULL;
02701
02702
02703
02704
02705
02706
02707 if (slit_ident) {
02708
02709 cpl_msg_info(recipe, "Computing global distortions model");
02710 global = mos_global_distortion(slits, maskslits, idscoeff,
02711 polytraces, reference);
02712
02713 if (global && 0) {
02714 cpl_table *stest;
02715 cpl_table *ctest;
02716 cpl_table *dtest;
02717 cpl_image *itest;
02718
02719 stest = mos_build_slit_location(global, maskslits, ccd_ysize);
02720
02721 ctest = mos_build_curv_coeff(global, maskslits, stest);
02722 if (dfs_save_table(frameset, ctest, "CURVS", NULL,
02723 parlist, recipe, version))
02724 fors_calib_exit(NULL);
02725
02726 itest = mos_spatial_calibration(spectra, stest, ctest,
02727 reference, startwavelength,
02728 endwavelength, dispersion,
02729 0, NULL);
02730 cpl_table_delete(ctest); ctest = NULL;
02731 cpl_image_delete(itest); itest = NULL;
02732 if (dfs_save_table(frameset, stest, "SLITS", NULL,
02733 parlist, recipe, version))
02734 fors_calib_exit(NULL);
02735
02736 dtest = mos_build_disp_coeff(global, stest);
02737 if (dfs_save_table(frameset, dtest, "DISPS", NULL,
02738 parlist, recipe, version))
02739 fors_calib_exit(NULL);
02740
02741 cpl_table_delete(dtest); dtest = NULL;
02742 cpl_table_delete(stest); stest = NULL;
02743 }
02744
02745 if (global) {
02746 if (dfs_save_table(frameset, global, global_distortion_tag, NULL,
02747 parlist, recipe, version))
02748 fors_calib_exit(NULL);
02749 cpl_table_delete(global); global = NULL;
02750 }
02751
02752 cpl_image_delete(spectra); spectra = NULL;
02753 cpl_table_delete(maskslits); maskslits = NULL;
02754 }
02755
02756 cpl_table_delete(idscoeff); idscoeff = NULL;
02757
02758 header = cpl_propertylist_new();
02759 cpl_propertylist_update_double(header, "CRPIX1", 1.0);
02760 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
02761 cpl_propertylist_update_double(header, "CRVAL1",
02762 startwavelength + dispersion/2);
02763 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
02764
02765
02766 cpl_propertylist_update_double(header, "CD1_1", dispersion);
02767 cpl_propertylist_update_double(header, "CD1_2", 0.0);
02768 cpl_propertylist_update_double(header, "CD2_1", 0.0);
02769 cpl_propertylist_update_double(header, "CD2_2", 1.0);
02770 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
02771 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
02772 cpl_propertylist_update_int(header, "ESO PRO DATANCOM", 1);
02773
02774 if (dfs_save_image(frameset, rectified, reduced_lamp_tag, header,
02775 parlist, recipe, version))
02776 fors_calib_exit(NULL);
02777
02778 cpl_image_delete(rectified); rectified = NULL;
02779
02780 cpl_propertylist_update_int(header, "ESO PRO DATANCOM", nflats);
02781
02782 if (dfs_save_image(frameset, mapped_flat, mapped_screen_flat_tag, header,
02783 parlist, recipe, version))
02784 fors_calib_exit(NULL);
02785
02786 cpl_image_delete(mapped_flat); mapped_flat = NULL;
02787
02788 if (dfs_save_image(frameset, mapped_nflat, mapped_norm_flat_tag, header,
02789 parlist, recipe, version))
02790 fors_calib_exit(NULL);
02791
02792 cpl_image_delete(mapped_nflat); mapped_nflat = NULL;
02793
02794 cpl_propertylist_delete(header); header = NULL;
02795
02796 if (check) {
02797 save_header = dfs_load_header(frameset, arc_tag, 0);
02798
02799 cpl_propertylist_update_double(save_header, "CRPIX2", 1.0);
02800 cpl_propertylist_update_double(save_header, "CRVAL2", 1.0);
02801
02802 cpl_propertylist_update_double(save_header, "CD1_1", 1.0);
02803 cpl_propertylist_update_double(save_header, "CD1_2", 0.0);
02804 cpl_propertylist_update_double(save_header, "CD2_1", 0.0);
02805 cpl_propertylist_update_double(save_header, "CD2_2", 1.0);
02806 cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR");
02807 cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL");
02808
02809 if (dfs_save_image(frameset, residual, disp_residuals_tag, save_header,
02810 parlist, recipe, version))
02811 fors_calib_exit(NULL);
02812
02813 cpl_image_delete(residual); residual = NULL;
02814 cpl_propertylist_delete(save_header); save_header = NULL;
02815 }
02816
02817 wavemap = mos_map_wavelengths(coordinate, rainbow, slits, polytraces,
02818 reference, startwavelength, endwavelength,
02819 dispersion);
02820
02821 cpl_image_delete(rainbow); rainbow = NULL;
02822
02823 save_header = dfs_load_header(frameset, arc_tag, 0);
02824
02825 if (qc) {
02826 fors_qc_start_group(save_header, "2.0", instrume);
02827
02828
02829
02830
02831
02832 if (fors_qc_write_string("PRO.CATG", wavelength_map_tag,
02833 "Product category", instrume))
02834 fors_calib_exit("Cannot write product category to "
02835 "QC log file");
02836
02837 if (fors_qc_keyword_to_paf(save_header, "ESO DPR TYPE", NULL,
02838 "DPR type", instrume))
02839 fors_calib_exit("Missing keyword DPR TYPE in arc "
02840 "lamp header");
02841
02842 if (fors_qc_keyword_to_paf(save_header, "ESO TPL ID", NULL,
02843 "Template", instrume))
02844 fors_calib_exit("Missing keyword TPL ID in arc "
02845 "lamp header");
02846
02847 if (fors_qc_keyword_to_paf(save_header, "ESO INS GRIS1 NAME", NULL,
02848 "Grism name", instrume))
02849 fors_calib_exit("Missing keyword INS GRIS1 NAME in arc "
02850 "lamp header");
02851
02852 if (fors_qc_keyword_to_paf(save_header, "ESO INS GRIS1 ID", NULL,
02853 "Grism identifier", instrume))
02854 fors_calib_exit("Missing keyword INS GRIS1 ID in arc "
02855 "lamp header");
02856
02857 if (cpl_propertylist_has(save_header, "ESO INS FILT1 NAME"))
02858 fors_qc_keyword_to_paf(save_header, "ESO INS FILT1 NAME", NULL,
02859 "Filter name", instrume);
02860
02861 if (fors_qc_keyword_to_paf(save_header, "ESO INS COLL NAME", NULL,
02862 "Collimator name", instrume))
02863 fors_calib_exit("Missing keyword INS COLL NAME in arc "
02864 "lamp header");
02865
02866 if (fors_qc_keyword_to_paf(save_header, "ESO DET CHIP1 ID", NULL,
02867 "Chip identifier", instrume))
02868 fors_calib_exit("Missing keyword DET CHIP1 ID in arc "
02869 "lamp header");
02870
02871 if (fors_qc_keyword_to_paf(save_header, "ESO DET WIN1 BINX", NULL,
02872 "Binning factor along X", instrume))
02873 fors_calib_exit("Missing keyword ESO DET WIN1 BINX "
02874 "in frame header");
02875
02876 if (fors_qc_keyword_to_paf(save_header, "ESO DET WIN1 BINY", NULL,
02877 "Binning factor along Y", instrume))
02878 fors_calib_exit("Missing keyword ESO DET WIN1 BINY "
02879 "in frame header");
02880
02881 if (fors_qc_keyword_to_paf(save_header, "ARCFILE", NULL,
02882 "Archive name of input data",
02883 instrume))
02884 fors_calib_exit("Missing keyword ARCFILE in arc "
02885 "lamp header");
02886
02887 pipefile = dfs_generate_filename(wavelength_map_tag);
02888 if (fors_qc_write_string("PIPEFILE", pipefile,
02889 "Pipeline product name", instrume))
02890 fors_calib_exit("Cannot write PIPEFILE to QC log file");
02891 cpl_free(pipefile); pipefile = NULL;
02892
02893
02894
02895
02896
02897
02898 if (fors_qc_write_qc_double(save_header,
02899 mean_rms,
02900 "QC.WAVE.ACCURACY",
02901 "pixel",
02902 "Mean accuracy of wavecalib model",
02903 instrume)) {
02904 fors_calib_exit("Cannot write mean wavelength calibration "
02905 "accuracy to QC log file");
02906 }
02907
02908
02909 if (fors_qc_write_qc_double(save_header,
02910 mean_rms_err,
02911 "QC.WAVE.ACCURACY.ERROR",
02912 "pixel",
02913 "Error on accuracy of wavecalib model",
02914 instrume)) {
02915 fors_calib_exit("Cannot write error on wavelength calibration "
02916 "accuracy to QC log file");
02917 }
02918
02919 fors_qc_end_group();
02920
02921 }
02922
02923 if (dfs_save_image(frameset, wavemap, wavelength_map_tag, save_header,
02924 parlist, recipe, version))
02925 fors_calib_exit(NULL);
02926
02927 cpl_image_delete(wavemap); wavemap = NULL;
02928
02929 cpl_propertylist_erase_regexp(save_header, "^ESO QC ", 0);
02930
02931 if (dfs_save_image(frameset, coordinate, spatial_map_tag, save_header,
02932 parlist, recipe, version))
02933 fors_calib_exit(NULL);
02934
02935 cpl_image_delete(coordinate); coordinate = NULL;
02936 cpl_propertylist_delete(save_header); save_header = NULL;
02937
02938 header = NULL;
02939
02940 if (qc) {
02941
02942 double maxpos, maxneg, maxcurve, maxslope;
02943
02944 header = dfs_load_header(frameset, arc_tag, 0);
02945
02946 fors_qc_start_group(header, "2.0", instrume);
02947
02948
02949
02950
02951
02952 if (fors_qc_write_string("PRO.CATG", curv_coeff_tag,
02953 "Product category", instrume))
02954 fors_calib_exit("Cannot write product category to "
02955 "QC log file");
02956
02957 if (fors_qc_keyword_to_paf(header, "ESO DPR TYPE", NULL,
02958 "DPR type", instrume))
02959 fors_calib_exit("Missing keyword DPR TYPE in arc "
02960 "lamp header");
02961
02962 if (fors_qc_keyword_to_paf(header, "ESO TPL ID", NULL,
02963 "Template", instrume))
02964 fors_calib_exit("Missing keyword TPL ID in arc "
02965 "lamp header");
02966 if (fors_qc_keyword_to_paf(header, "ARCFILE", NULL,
02967 "Archive name of input data",
02968 instrume))
02969 fors_calib_exit("Missing keyword ARCFILE in arc "
02970 "lamp header");
02971
02972 pipefile = dfs_generate_filename(curv_coeff_tag);
02973 if (fors_qc_write_string("PIPEFILE", pipefile,
02974 "Pipeline product name", instrume))
02975 fors_calib_exit("Cannot write PIPEFILE to QC log file");
02976 cpl_free(pipefile); pipefile = NULL;
02977
02978
02979
02980
02981
02982 maxpos = fabs(cpl_table_get_column_max(polytraces, "c2"));
02983 maxneg = fabs(cpl_table_get_column_min(polytraces, "c2"));
02984 maxcurve = maxpos > maxneg ? maxpos : maxneg;
02985 if (fors_qc_write_qc_double(header,
02986 maxcurve,
02987 "QC.TRACE.MAX.CURVATURE",
02988 "Y pixel / X pixel ^2",
02989 "Max observed curvature in spectral tracing",
02990 instrume)) {
02991 fors_calib_exit("Cannot write max observed curvature in spectral "
02992 "tracing to QC log file");
02993 }
02994
02995 maxpos = fabs(cpl_table_get_column_max(polytraces, "c1"));
02996 maxneg = fabs(cpl_table_get_column_min(polytraces, "c1"));
02997 maxslope = maxpos > maxneg ? maxpos : maxneg;
02998 if (fors_qc_write_qc_double(header,
02999 maxslope,
03000 "QC.TRACE.MAX.SLOPE",
03001 "Y pixel / X pixel",
03002 "Max observed slope in spectral tracing",
03003 instrume)) {
03004 fors_calib_exit("Cannot write max observed slope in spectral "
03005 "tracing to QC log file");
03006 }
03007
03008 fors_qc_end_group();
03009 }
03010
03011 cpl_free(instrume); instrume = NULL;
03012
03013 if (dfs_save_table(frameset, polytraces, curv_coeff_tag, header,
03014 parlist, recipe, version))
03015 fors_calib_exit(NULL);
03016
03017 cpl_propertylist_delete(header); header = NULL;
03018 cpl_table_delete(polytraces); polytraces = NULL;
03019
03020 if (dfs_save_table(frameset, slits, slit_location_tag, NULL,
03021 parlist, recipe, version))
03022 fors_calib_exit(NULL);
03023
03024 cpl_table_delete(slits); slits = NULL;
03025
03026 if (cpl_error_get_code()) {
03027 cpl_msg_error(cpl_error_get_where(), cpl_error_get_message());
03028 fors_calib_exit(NULL);
03029 }
03030
03031 return 0;
03032 }