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 <ctype.h>
00035 #include <cpl.h>
00036 #include <moses.h>
00037 #include <fors_stack.h>
00038 #include <fors_dfs.h>
00039 #include <fors_header.h>
00040
00041 #define OFFSET 50
00042 #define TOLERANCE 10
00043
00044 static int fors_pmos_calib_create(cpl_plugin *);
00045 static int fors_pmos_calib_exec(cpl_plugin *);
00046 static int fors_pmos_calib_destroy(cpl_plugin *);
00047 static int fors_pmos_calib(cpl_parameterlist *, cpl_frameset *);
00048
00049 static char fors_pmos_calib_description[] =
00050 "This recipe is used to identify reference lines on PMOS arc lamp\n"
00051 "exposures, and trace the spectral edges on the corresponding flat field\n"
00052 "exposures. This information is used to determine the spectral extraction\n"
00053 "mask to be applied in the scientific data reduction, performed with the\n"
00054 "recipe fors_science.\n"
00055 "This recipe accepts both FORS1 and FORS2 frames. The input arc lamps and\n"
00056 "flat field exposures are assumed to be obtained quasi-simultaneously, so\n"
00057 "that they would be described by exactly the same instrument distortions.\n"
00058 "A line catalog must be specified, containing the wavelengths of the\n"
00059 "reference arc lamp lines used for the wavelength calibration. A grism\n"
00060 "table (typically depending on the instrument mode, and in particular on\n"
00061 "the grism used) may also be specified: this table contains a default\n"
00062 "recipe parameter setting to control the way spectra are extracted for\n"
00063 "a specific instrument mode, as it is used for automatic run of the\n"
00064 "pipeline on Paranal and in Garching. If this table is specified, it\n"
00065 "will modify the default recipe parameter setting, with the exception of\n"
00066 "those parameters which have been explicitly modifyed on the command line.\n"
00067 "If a grism table is not specified, the input recipe parameters values\n"
00068 "will always be read from the command line, or from an esorex configuration\n"
00069 "file if present, or from their generic default values (that are rarely\n"
00070 "meaningful). Finally a master bias frame must be input to this recipe.\n"
00071 "The products SPECTRA_DETECTION_PMOS, SLIT_MAP_PMOS, and DISP_RESIDUALS_PMOS,\n"
00072 "are just created if the --check parameter is set to true.\n"
00073 "The MASTER_DISTORTION_TABLE is marked as required, but it is not so if all\n"
00074 "slits have different offsets, and in the case of FORS1 observations made\n"
00075 "with the old TK2048EB4-1 1604 chip read in windowed mode (2048x400)\n\n"
00076 "Input files:\n\n"
00077 " DO category: Type: Explanation: Required:\n"
00078 " SCREEN_FLAT_PMOS Raw Flat field exposures Y\n"
00079 " LAMP_PMOS Raw Arc lamp exposure Y\n"
00080 " MASTER_BIAS or BIAS Calib Bias frame Y\n"
00081 " MASTER_LINECAT Calib Line catalog Y\n"
00082 " GRISM_TABLE Calib Grism table .\n"
00083 " MASTER_DISTORTION_TABLE Calib Master distortions table Y\n\n"
00084 "Output files:\n\n"
00085 " DO category: Data type: Explanation:\n"
00086 " MASTER_SCREEN_FLAT_PMOS FITS image Combined (sum) flat field\n"
00087 " MASTER_NORM_FLAT_PMOS FITS image Normalised flat field\n"
00088 " MAPPED_SCREEN_FLAT_PMOS FITS image Wavelength calibrated flat field\n"
00089 " MAPPED_NORM_FLAT_PMOS FITS image Wavelength calibrated normalised flat\n"
00090 " REDUCED_LAMP_PMOS FITS image Wavelength calibrated arc spectrum\n"
00091 " DISP_COEFF_PMOS FITS table Inverse dispersion coefficients\n"
00092 " DISP_RESIDUALS_PMOS FITS image Residuals in wavelength calibration\n"
00093 " DISP_RESIDUALS_TABLE_PMOS FITS table Residuals in wavelength calibration\n"
00094 " DELTA_IMAGE_PMOS FITS image Offset vs linear wavelength calib\n"
00095 " WAVELENGTH_MAP_PMOS FITS image Wavelength for each pixel on CCD\n"
00096 " SPECTRA_DETECTION_PMOS FITS image Check for preliminary detection\n"
00097 " SLIT_MAP_PMOS FITS image Map of central wavelength on CCD\n"
00098 " CURV_TRACES_PMOS FITS table Spectral curvature traces\n"
00099 " CURV_COEFF_PMOS FITS table Spectral curvature coefficients\n"
00100 " SPATIAL_MAP_PMOS FITS image Spatial position along slit on CCD\n"
00101 " SPECTRAL_RESOLUTION_PMOS FITS table Resolution at reference arc lines\n"
00102 " SLIT_LOCATION_PMOS FITS table Slits on product frames and CCD\n\n";
00103
00104 #define fors_pmos_calib_exit(message) \
00105 { \
00106 if ((const char *)message != NULL) cpl_msg_error(recipe, message); \
00107 cpl_free(instrume); \
00108 cpl_free(fiterror); \
00109 cpl_free(fitlines); \
00110 cpl_image_delete(bias); \
00111 cpl_image_delete(master_bias); \
00112 cpl_image_delete(coordinate); \
00113 cpl_image_delete(checkwave); \
00114 cpl_image_delete(flat); \
00115 cpl_image_delete(master_flat); \
00116 cpl_image_delete(added_flat); \
00117 cpl_image_delete(norm_flat); \
00118 cpl_image_delete(mapped_flat); \
00119 cpl_image_delete(mapped_nflat); \
00120 cpl_image_delete(rainbow); \
00121 cpl_image_delete(rectified); \
00122 cpl_image_delete(residual); \
00123 cpl_image_delete(smo_flat); \
00124 cpl_image_delete(spatial); \
00125 cpl_image_delete(spectra); \
00126 cpl_image_delete(wavemap); \
00127 cpl_image_delete(delta); \
00128 cpl_image_delete(rect_flat); \
00129 cpl_image_delete(rect_nflat); \
00130 cpl_mask_delete(refmask); \
00131 cpl_propertylist_delete(header); \
00132 cpl_propertylist_delete(save_header); \
00133 cpl_propertylist_delete(qclist); \
00134 cpl_table_delete(grism_table); \
00135 cpl_table_delete(idscoeff); \
00136 cpl_table_delete(idscoeff_all); \
00137 cpl_table_delete(restable); \
00138 cpl_table_delete(maskslits); \
00139 cpl_table_delete(overscans); \
00140 cpl_table_delete(traces); \
00141 cpl_table_delete(polytraces); \
00142 cpl_table_delete(slits); \
00143 cpl_table_delete(restab); \
00144 cpl_table_delete(global); \
00145 cpl_table_delete(wavelengths); \
00146 cpl_vector_delete(lines); \
00147 cpl_msg_indent_less(); \
00148 return -1; \
00149 }
00150
00151 #define fors_pmos_calib_exit_memcheck(message) \
00152 { \
00153 if ((const char *)message != NULL) cpl_msg_info(recipe, message); \
00154 printf("free instrume (%p)\n", instrume); \
00155 cpl_free(instrume); \
00156 printf("free pipefile (%p)\n", pipefile); \
00157 cpl_free(pipefile); \
00158 printf("free fiterror (%p)\n", fiterror); \
00159 cpl_free(fiterror); \
00160 printf("free fitlines (%p)\n", fitlines); \
00161 cpl_free(fitlines); \
00162 printf("free bias (%p)\n", bias); \
00163 cpl_image_delete(bias); \
00164 printf("free master_bias (%p)\n", master_bias); \
00165 cpl_image_delete(master_bias); \
00166 printf("free coordinate (%p)\n", coordinate); \
00167 cpl_image_delete(coordinate); \
00168 printf("free checkwave (%p)\n", checkwave); \
00169 cpl_image_delete(checkwave); \
00170 printf("free flat (%p)\n", flat); \
00171 cpl_image_delete(flat); \
00172 printf("free master_flat (%p)\n", master_flat); \
00173 cpl_image_delete(master_flat); \
00174 printf("free norm_flat (%p)\n", norm_flat); \
00175 cpl_image_delete(norm_flat); \
00176 printf("free mapped_flat (%p)\n", mapped_flat); \
00177 cpl_image_delete(mapped_flat); \
00178 printf("free mapped_nflat (%p)\n", mapped_nflat); \
00179 cpl_image_delete(mapped_nflat); \
00180 printf("free rainbow (%p)\n", rainbow); \
00181 cpl_image_delete(rainbow); \
00182 printf("free rectified (%p)\n", rectified); \
00183 cpl_image_delete(rectified); \
00184 printf("free residual (%p)\n", residual); \
00185 cpl_image_delete(residual); \
00186 printf("free smo_flat (%p)\n", smo_flat); \
00187 cpl_image_delete(smo_flat); \
00188 printf("free spatial (%p)\n", spatial); \
00189 cpl_image_delete(spatial); \
00190 printf("free spectra (%p)\n", spectra); \
00191 cpl_image_delete(spectra); \
00192 printf("free wavemap (%p)\n", wavemap); \
00193 cpl_image_delete(wavemap); \
00194 printf("free delta (%p)\n", delta); \
00195 cpl_image_delete(delta); \
00196 printf("free rect_flat (%p)\n", rect_flat); \
00197 cpl_image_delete(rect_flat); \
00198 printf("free rect_nflat (%p)\n", rect_nflat); \
00199 cpl_image_delete(rect_nflat); \
00200 printf("free refmask (%p)\n", refmask); \
00201 cpl_mask_delete(refmask); \
00202 printf("free header (%p)\n", header); \
00203 cpl_propertylist_delete(header); \
00204 printf("free save_header (%p)\n", save_header); \
00205 cpl_propertylist_delete(save_header); \
00206 printf("free qclist (%p)\n", qclist); \
00207 cpl_propertylist_delete(qclist); \
00208 printf("free grism_table (%p)\n", grism_table); \
00209 cpl_table_delete(grism_table); \
00210 printf("free idscoeff (%p)\n", idscoeff); \
00211 cpl_table_delete(idscoeff); \
00212 printf("free idscoeff_all (%p)\n", idscoeff_all); \
00213 cpl_table_delete(idscoeff_all); \
00214 printf("free restable (%p)\n", restable); \
00215 cpl_table_delete(restable); \
00216 printf("free maskslits (%p)\n", maskslits); \
00217 cpl_table_delete(maskslits); \
00218 printf("free overscans (%p)\n", overscans); \
00219 cpl_table_delete(overscans); \
00220 printf("free traces (%p)\n", traces); \
00221 cpl_table_delete(traces); \
00222 printf("free polytraces (%p)\n", polytraces); \
00223 cpl_table_delete(polytraces); \
00224 printf("free slits (%p)\n", slits); \
00225 cpl_table_delete(slits); \
00226 printf("free restab (%p)\n", restab); \
00227 cpl_table_delete(restab); \
00228 printf("free global (%p)\n", global); \
00229 cpl_table_delete(global); \
00230 printf("free wavelengths (%p)\n", wavelengths); \
00231 cpl_table_delete(wavelengths); \
00232 printf("free lines (%p)\n", lines); \
00233 cpl_vector_delete(lines); \
00234 cpl_msg_indent_less(); \
00235 return 0; \
00236 }
00237
00238
00250 int cpl_plugin_get_info(cpl_pluginlist *list)
00251 {
00252 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
00253 cpl_plugin *plugin = &recipe->interface;
00254
00255 cpl_plugin_init(plugin,
00256 CPL_PLUGIN_API,
00257 FORS_BINARY_VERSION,
00258 CPL_PLUGIN_TYPE_RECIPE,
00259 "fors_pmos_calib",
00260 "Determination of the extraction mask",
00261 fors_pmos_calib_description,
00262 "Carlo Izzo",
00263 PACKAGE_BUGREPORT,
00264 "This file is currently part of the FORS Instrument Pipeline\n"
00265 "Copyright (C) 2002-2010 European Southern Observatory\n\n"
00266 "This program is free software; you can redistribute it and/or modify\n"
00267 "it under the terms of the GNU General Public License as published by\n"
00268 "the Free Software Foundation; either version 2 of the License, or\n"
00269 "(at your option) any later version.\n\n"
00270 "This program is distributed in the hope that it will be useful,\n"
00271 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00272 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
00273 "GNU General Public License for more details.\n\n"
00274 "You should have received a copy of the GNU General Public License\n"
00275 "along with this program; if not, write to the Free Software Foundation,\n"
00276 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n",
00277 fors_pmos_calib_create,
00278 fors_pmos_calib_exec,
00279 fors_pmos_calib_destroy);
00280
00281 cpl_pluginlist_append(list, plugin);
00282
00283 return 0;
00284 }
00285
00286
00297 static int fors_pmos_calib_create(cpl_plugin *plugin)
00298 {
00299 cpl_recipe *recipe;
00300 cpl_parameter *p;
00301
00302
00303
00304
00305
00306
00307 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00308 recipe = (cpl_recipe *)plugin;
00309 else
00310 return -1;
00311
00312
00313
00314
00315
00316 recipe->parameters = cpl_parameterlist_new();
00317
00318
00319
00320
00321
00322
00323 p = cpl_parameter_new_value("fors.fors_pmos_calib.dispersion",
00324 CPL_TYPE_DOUBLE,
00325 "Expected spectral dispersion (Angstrom/pixel)",
00326 "fors.fors_pmos_calib",
00327 0.0);
00328 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
00329 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00330 cpl_parameterlist_append(recipe->parameters, p);
00331
00332
00333
00334
00335
00336 p = cpl_parameter_new_value("fors.fors_pmos_calib.peakdetection",
00337 CPL_TYPE_DOUBLE,
00338 "Initial peak detection threshold (ADU)",
00339 "fors.fors_pmos_calib",
00340 0.0);
00341 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "peakdetection");
00342 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00343 cpl_parameterlist_append(recipe->parameters, p);
00344
00345
00346
00347
00348
00349 p = cpl_parameter_new_value("fors.fors_pmos_calib.wdegree",
00350 CPL_TYPE_INT,
00351 "Degree of wavelength calibration polynomial",
00352 "fors.fors_pmos_calib",
00353 0);
00354 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wdegree");
00355 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00356 cpl_parameterlist_append(recipe->parameters, p);
00357
00358
00359
00360
00361
00362 p = cpl_parameter_new_value("fors.fors_pmos_calib.wradius",
00363 CPL_TYPE_INT,
00364 "Search radius if iterating pattern-matching "
00365 "with first-guess method",
00366 "fors.fors_pmos_calib",
00367 4);
00368 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wradius");
00369 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00370 cpl_parameterlist_append(recipe->parameters, p);
00371
00372
00373
00374
00375
00376 p = cpl_parameter_new_value("fors.fors_pmos_calib.wreject",
00377 CPL_TYPE_DOUBLE,
00378 "Rejection threshold in dispersion "
00379 "relation fit (pixel)",
00380 "fors.fors_pmos_calib",
00381 0.7);
00382 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wreject");
00383 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00384 cpl_parameterlist_append(recipe->parameters, p);
00385
00386
00387
00388
00389
00390 p = cpl_parameter_new_value("fors.fors_pmos_calib.wcolumn",
00391 CPL_TYPE_STRING,
00392 "Name of line catalog table column "
00393 "with wavelengths",
00394 "fors.fors_pmos_calib",
00395 "WLEN");
00396 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
00397 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00398 cpl_parameterlist_append(recipe->parameters, p);
00399
00400
00401
00402
00403
00404 p = cpl_parameter_new_value("fors.fors_pmos_calib.cdegree",
00405 CPL_TYPE_INT,
00406 "Degree of spectral curvature polynomial",
00407 "fors.fors_pmos_calib",
00408 0);
00409 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cdegree");
00410 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00411 cpl_parameterlist_append(recipe->parameters, p);
00412
00413
00414
00415
00416
00417 p = cpl_parameter_new_value("fors.fors_pmos_calib.cmode",
00418 CPL_TYPE_INT,
00419 "Interpolation mode of curvature solution "
00420 "(0 = no "
00421 "interpolation, 1 = fill gaps, 2 = global "
00422 "model)",
00423 "fors.fors_pmos_calib",
00424 1);
00425 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cmode");
00426 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00427 cpl_parameterlist_append(recipe->parameters, p);
00428
00429
00430
00431
00432
00433 p = cpl_parameter_new_value("fors.fors_pmos_calib.startwavelength",
00434 CPL_TYPE_DOUBLE,
00435 "Start wavelength in spectral extraction",
00436 "fors.fors_pmos_calib",
00437 0.0);
00438 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
00439 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00440 cpl_parameterlist_append(recipe->parameters, p);
00441
00442
00443
00444
00445
00446 p = cpl_parameter_new_value("fors.fors_pmos_calib.endwavelength",
00447 CPL_TYPE_DOUBLE,
00448 "End wavelength in spectral extraction",
00449 "fors.fors_pmos_calib",
00450 0.0);
00451 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
00452 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00453 cpl_parameterlist_append(recipe->parameters, p);
00454
00455
00456
00457
00458
00459 fors_stack_define_parameters(recipe->parameters, "fors.fors_pmos_calib",
00460 "average");
00461
00462
00463
00464
00465
00466 p = cpl_parameter_new_value("fors.fors_pmos_calib.ddegree",
00467 CPL_TYPE_INT,
00468 "Degree of flat field fitting polynomial "
00469 "along dispersion direction",
00470 "fors.fors_pmos_calib",
00471 -1);
00472 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ddegree");
00473 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00474 cpl_parameterlist_append(recipe->parameters, p);
00475
00476
00477
00478
00479
00480 p = cpl_parameter_new_value("fors.fors_pmos_calib.dradius",
00481 CPL_TYPE_INT,
00482 "Smooth box radius for flat field along "
00483 "dispersion direction",
00484 "fors.fors_pmos_calib",
00485 10);
00486 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dradius");
00487 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00488 cpl_parameterlist_append(recipe->parameters, p);
00489
00490
00491
00492
00493
00494 p = cpl_parameter_new_value("fors.fors_pmos_calib.qc",
00495 CPL_TYPE_BOOL,
00496 "Compute QC1 parameters",
00497 "fors.fors_pmos_calib",
00498 TRUE);
00499 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "qc");
00500 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00501 cpl_parameterlist_append(recipe->parameters, p);
00502
00503
00504
00505
00506
00507 p = cpl_parameter_new_value("fors.fors_pmos_calib.check",
00508 CPL_TYPE_BOOL,
00509 "Create intermediate products",
00510 "fors.fors_pmos_calib",
00511 FALSE);
00512 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "check");
00513 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00514 cpl_parameterlist_append(recipe->parameters, p);
00515
00516 return 0;
00517 }
00518
00519
00528 static int fors_pmos_calib_exec(cpl_plugin *plugin)
00529 {
00530 cpl_recipe *recipe;
00531
00532 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00533 recipe = (cpl_recipe *)plugin;
00534 else
00535 return -1;
00536
00537 return fors_pmos_calib(recipe->parameters, recipe->frames);
00538 }
00539
00540
00549 static int fors_pmos_calib_destroy(cpl_plugin *plugin)
00550 {
00551 cpl_recipe *recipe;
00552
00553 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00554 recipe = (cpl_recipe *)plugin;
00555 else
00556 return -1;
00557
00558 cpl_parameterlist_delete(recipe->parameters);
00559
00560 return 0;
00561 }
00562
00563
00573 static int fors_pmos_calib(cpl_parameterlist *parlist, cpl_frameset *frameset)
00574 {
00575
00576 const char *recipe = "fors_pmos_calib";
00577
00578
00579
00580
00581
00582
00583 double dispersion;
00584 double peakdetection;
00585 int wdegree;
00586 int wradius;
00587 double wreject;
00588 const char *wcolumn;
00589 int cdegree;
00590 int cmode;
00591 double startwavelength;
00592 double endwavelength;
00593 int ddegree;
00594 int dradius;
00595 int qc;
00596 int check;
00597 const char *stack_method;
00598 int min_reject;
00599 int max_reject;
00600 double klow;
00601 double khigh;
00602 int kiter;
00603
00604
00605
00606
00607
00608
00609 cpl_imagelist *biases = NULL;
00610 cpl_image *bias = NULL;
00611 cpl_image *master_bias = NULL;
00612 cpl_image *multi_bias = NULL;
00613 cpl_image *flat = NULL;
00614 cpl_image *master_flat = NULL;
00615 cpl_image *added_flat = NULL;
00616 cpl_image *trace_flat = NULL;
00617 cpl_image *smo_flat = NULL;
00618 cpl_image *norm_flat = NULL;
00619 cpl_image *spectra = NULL;
00620 cpl_image *wavemap = NULL;
00621 cpl_image *delta = NULL;
00622 cpl_image *residual = NULL;
00623 cpl_image *checkwave = NULL;
00624 cpl_image *rectified = NULL;
00625 cpl_image *dummy = NULL;
00626 cpl_image *add_dummy = NULL;
00627 cpl_image *refimage = NULL;
00628 cpl_image *coordinate = NULL;
00629 cpl_image *rainbow = NULL;
00630 cpl_image *spatial = NULL;
00631 cpl_image *rect_flat = NULL;
00632 cpl_image *rect_nflat = NULL;
00633 cpl_image *mapped_flat = NULL;
00634 cpl_image *mapped_nflat = NULL;
00635
00636 cpl_mask *refmask = NULL;
00637
00638 cpl_table *grism_table = NULL;
00639 cpl_table *overscans = NULL;
00640 cpl_table *wavelengths = NULL;
00641 cpl_table *idscoeff = NULL;
00642 cpl_table *idscoeff_all = NULL;
00643 cpl_table *restable = NULL;
00644 cpl_table *slits = NULL;
00645 cpl_table *positions = NULL;
00646 cpl_table *maskslits = NULL;
00647 cpl_table *traces = NULL;
00648 cpl_table *polytraces = NULL;
00649 cpl_table *restab = NULL;
00650 cpl_table *global = NULL;
00651
00652 cpl_vector *lines = NULL;
00653
00654 cpl_propertylist *header_dist = NULL;
00655 cpl_propertylist *header = NULL;
00656 cpl_propertylist *save_header = NULL;
00657 cpl_propertylist *qclist = NULL;
00658
00659
00660
00661
00662
00663 char version[80];
00664 const char *arc_tag;
00665 const char *flat_tag;
00666 const char *master_screen_flat_tag;
00667 const char *master_norm_flat_tag;
00668 const char *reduced_lamp_tag;
00669 const char *disp_residuals_tag;
00670 const char *disp_coeff_tag;
00671 const char *wavelength_map_tag;
00672 const char *spectra_detection_tag;
00673 const char *spectral_resolution_tag;
00674 const char *slit_map_tag;
00675 const char *curv_traces_tag;
00676 const char *curv_coeff_tag;
00677 const char *spatial_map_tag;
00678 const char *slit_location_tag;
00679 const char *master_distortion_tag = "MASTER_DISTORTION_TABLE";
00680 const char *disp_residuals_table_tag;
00681 const char *delta_image_tag;
00682 const char *mapped_screen_flat_tag;
00683 const char *mapped_norm_flat_tag;
00684 const char *keyname;
00685 int pmos;
00686 int same_offset = 0;
00687 int nslits;
00688 float *data;
00689 double *xpos;
00690 double mxpos;
00691 double mean_rms;
00692 double mean_rms_err;
00693 double alltime;
00694 int nflats;
00695 int nbias;
00696 int nlines;
00697 int rebin, rebin_dist;
00698 double *line;
00699 double *fiterror = NULL;
00700 int *fitlines = NULL;
00701 int nx, ny;
00702 double reference;
00703 double gain;
00704 int ccd_ysize;
00705 int i, j;
00706
00707 char *instrume = NULL;
00708
00709
00710
00711
00712
00713 int bagoo = 0;
00714 int doit = 0;
00715 double blevel = 0.0;
00716 double ron = 0.0;
00717
00718 snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION);
00719
00720 cpl_msg_set_indentation(2);
00721
00722 fors_dfs_set_groups(frameset);
00723
00724
00725
00726
00727
00728 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00729 cpl_msg_indent_more();
00730
00731 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00732 fors_pmos_calib_exit("Too many in input: GRISM_TABLE");
00733
00734 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00735
00736 dispersion = dfs_get_parameter_double(parlist,
00737 "fors.fors_pmos_calib.dispersion", grism_table);
00738
00739 if (dispersion <= 0.0)
00740 fors_pmos_calib_exit("Invalid spectral dispersion value");
00741
00742 peakdetection = dfs_get_parameter_double(parlist,
00743 "fors.fors_pmos_calib.peakdetection", grism_table);
00744 if (peakdetection <= 0.0)
00745 fors_pmos_calib_exit("Invalid peak detection level");
00746
00747 wdegree = dfs_get_parameter_int(parlist,
00748 "fors.fors_pmos_calib.wdegree", grism_table);
00749
00750 if (wdegree < 1)
00751 fors_pmos_calib_exit("Invalid polynomial degree");
00752
00753 if (wdegree > 5)
00754 fors_pmos_calib_exit("Max allowed polynomial degree is 5");
00755
00756 wradius = dfs_get_parameter_int(parlist,
00757 "fors.fors_pmos_calib.wradius", NULL);
00758
00759 if (wradius < 0)
00760 fors_pmos_calib_exit("Invalid search radius");
00761
00762 wreject = dfs_get_parameter_double(parlist,
00763 "fors.fors_pmos_calib.wreject", NULL);
00764
00765 if (wreject <= 0.0)
00766 fors_pmos_calib_exit("Invalid rejection threshold");
00767
00768 wcolumn = dfs_get_parameter_string(parlist,
00769 "fors.fors_pmos_calib.wcolumn", NULL);
00770
00771 cdegree = dfs_get_parameter_int(parlist,
00772 "fors.fors_pmos_calib.cdegree", grism_table);
00773
00774 if (cdegree < 1)
00775 fors_pmos_calib_exit("Invalid polynomial degree");
00776
00777 if (cdegree > 5)
00778 fors_pmos_calib_exit("Max allowed polynomial degree is 5");
00779
00780 cmode = dfs_get_parameter_int(parlist, "fors.fors_pmos_calib.cmode", NULL);
00781
00782 if (cmode < 0 || cmode > 2)
00783 fors_pmos_calib_exit("Invalid curvature solution interpolation mode");
00784
00785 startwavelength = dfs_get_parameter_double(parlist,
00786 "fors.fors_pmos_calib.startwavelength", grism_table);
00787 if (startwavelength > 1.0)
00788 if (startwavelength < 3000.0 || startwavelength > 13000.0)
00789 fors_pmos_calib_exit("Invalid wavelength");
00790
00791 endwavelength = dfs_get_parameter_double(parlist,
00792 "fors.fors_pmos_calib.endwavelength", grism_table);
00793 if (endwavelength > 1.0) {
00794 if (endwavelength < 3000.0 || endwavelength > 13000.0)
00795 fors_pmos_calib_exit("Invalid wavelength");
00796 if (startwavelength < 1.0)
00797 fors_pmos_calib_exit("Invalid wavelength interval");
00798 }
00799
00800 if (startwavelength > 1.0)
00801 if (endwavelength - startwavelength <= 0.0)
00802 fors_pmos_calib_exit("Invalid wavelength interval");
00803
00804 stack_method = dfs_get_parameter_string(parlist,
00805 "fors.fors_pmos_calib.stack_method",
00806 NULL);
00807
00808 if (strcmp(stack_method, "minmax") == 0) {
00809 min_reject = dfs_get_parameter_int(parlist,
00810 "fors.fors_pmos_calib.minrejection", NULL);
00811 if (min_reject < 0)
00812 fors_pmos_calib_exit("Invalid number of lower rejections");
00813
00814 max_reject = dfs_get_parameter_int(parlist,
00815 "fors.fors_pmos_calib.maxrejection", NULL);
00816 if (max_reject < 0)
00817 fors_pmos_calib_exit("Invalid number of upper rejections");
00818 }
00819
00820 if (strcmp(stack_method, "ksigma") == 0) {
00821 klow = dfs_get_parameter_double(parlist,
00822 "fors.fors_pmos_calib.klow", NULL);
00823 if (klow < 0.1)
00824 fors_pmos_calib_exit("Invalid lower K-sigma");
00825
00826 khigh = dfs_get_parameter_double(parlist,
00827 "fors.fors_pmos_calib.khigh", NULL);
00828 if (khigh < 0.1)
00829 fors_pmos_calib_exit("Invalid lower K-sigma");
00830
00831 kiter = dfs_get_parameter_int(parlist,
00832 "fors.fors_pmos_calib.kiter", NULL);
00833 if (kiter < 1)
00834 fors_pmos_calib_exit("Invalid number of iterations");
00835 }
00836
00837 ddegree = dfs_get_parameter_int(parlist,
00838 "fors.fors_pmos_calib.ddegree", NULL);
00839 dradius = dfs_get_parameter_int(parlist,
00840 "fors.fors_pmos_calib.dradius", NULL);
00841
00842 if (dradius < 1)
00843 fors_pmos_calib_exit("Invalid smoothing box radius");
00844
00845 qc = dfs_get_parameter_bool(parlist, "fors.fors_pmos_calib.qc", NULL);
00846
00847 check = dfs_get_parameter_bool(parlist, "fors.fors_pmos_calib.check", NULL);
00848
00849 cpl_table_delete(grism_table); grism_table = NULL;
00850
00851 if (cpl_error_get_code())
00852 fors_pmos_calib_exit("Failure getting the configuration parameters");
00853
00854
00855
00856
00857
00858
00859 cpl_msg_indent_less();
00860 cpl_msg_info(recipe, "Check input set-of-frames:");
00861 cpl_msg_indent_more();
00862
00863 {
00864 cpl_frameset *subframeset = cpl_frameset_duplicate(frameset);
00865 cpl_frameset_erase(subframeset, "BIAS");
00866 cpl_frameset_erase(subframeset, "MASTER_BIAS");
00867
00868 if (!dfs_equal_keyword(subframeset, "ESO INS GRIS1 ID"))
00869 cpl_msg_warning(cpl_func,"Input frames are not from the same grism");
00870
00871 if (!dfs_equal_keyword(subframeset, "ESO INS FILT1 ID"))
00872 cpl_msg_warning(cpl_func,"Input frames are not from the same filter");
00873
00874 if (!dfs_equal_keyword(subframeset, "ESO DET CHIP1 ID"))
00875 cpl_msg_warning(cpl_func,"Input frames are not from the same chip");
00876
00877 cpl_frameset_delete(subframeset);
00878 }
00879
00880 pmos = cpl_frameset_count_tags(frameset, "LAMP_PMOS");
00881
00882 if (pmos == 0)
00883 fors_pmos_calib_exit("Missing input arc lamp frame");
00884
00885 if (pmos) {
00886 cpl_msg_info(recipe, "PMOS data found");
00887 arc_tag = "LAMP_PMOS";
00888 flat_tag = "SCREEN_FLAT_PMOS";
00889 master_screen_flat_tag = "MASTER_SCREEN_FLAT_PMOS";
00890 master_norm_flat_tag = "MASTER_NORM_FLAT_PMOS";
00891 reduced_lamp_tag = "REDUCED_LAMP_PMOS";
00892 disp_residuals_tag = "DISP_RESIDUALS_PMOS";
00893 disp_coeff_tag = "DISP_COEFF_PMOS";
00894 wavelength_map_tag = "WAVELENGTH_MAP_PMOS";
00895 spectra_detection_tag = "SPECTRA_DETECTION_PMOS";
00896 spectral_resolution_tag = "SPECTRAL_RESOLUTION_PMOS";
00897 slit_map_tag = "SLIT_MAP_PMOS";
00898 curv_traces_tag = "CURV_TRACES_PMOS";
00899 curv_coeff_tag = "CURV_COEFF_PMOS";
00900 spatial_map_tag = "SPATIAL_MAP_PMOS";
00901 slit_location_tag = "SLIT_LOCATION_PMOS";
00902 disp_residuals_table_tag = "DISP_RESIDUALS_TABLE_PMOS";
00903 delta_image_tag = "DELTA_IMAGE_PMOS";
00904 mapped_screen_flat_tag = "MAPPED_SCREEN_FLAT_PMOS";
00905 mapped_norm_flat_tag = "MAPPED_NORM_FLAT_PMOS";
00906 }
00907
00908 nbias = 0;
00909 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0) {
00910 if (cpl_frameset_count_tags(frameset, "BIAS") == 0)
00911 fors_pmos_calib_exit("Missing required input: MASTER_BIAS or BIAS");
00912 nbias = cpl_frameset_count_tags(frameset, "BIAS");
00913 }
00914
00915 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1)
00916 fors_pmos_calib_exit("Too many in input: MASTER_BIAS");
00917
00918 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0)
00919 fors_pmos_calib_exit("Missing required input: MASTER_LINECAT");
00920
00921 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1)
00922 fors_pmos_calib_exit("Too many in input: MASTER_LINECAT");
00923
00924 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0)
00925 fors_pmos_calib_exit("Missing required input: MASTER_LINECAT");
00926
00927 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1)
00928 fors_pmos_calib_exit("Too many in input: MASTER_LINECAT");
00929
00930
00931
00932
00933
00934
00935 if (cpl_frameset_count_tags(frameset, master_distortion_tag) > 1)
00936 fors_pmos_calib_exit("Too many in input: MASTER_DISTORTION_TABLE");
00937
00938 nflats = cpl_frameset_count_tags(frameset, flat_tag);
00939
00940 if (nflats < 1) {
00941 cpl_msg_error(recipe, "Missing required input: %s", flat_tag);
00942 fors_pmos_calib_exit(NULL);
00943 }
00944
00945 cpl_msg_indent_less();
00946
00947 if (nflats > 1)
00948 cpl_msg_info(recipe, "Load %d flat field frames and stack them "
00949 "with method \"%s\"", nflats, stack_method);
00950 else
00951 cpl_msg_info(recipe, "Load flat field exposure...");
00952
00953 cpl_msg_indent_more();
00954
00955 header = dfs_load_header(frameset, flat_tag, 0);
00956
00957 if (header == NULL)
00958 fors_pmos_calib_exit("Cannot load flat field frame header");
00959
00960 alltime = cpl_propertylist_get_double(header, "EXPTIME");
00961
00962 if (cpl_error_get_code() != CPL_ERROR_NONE)
00963 fors_pmos_calib_exit("Missing keyword EXPTIME in flat field "
00964 "frame header");
00965
00966 cpl_propertylist_delete(header);
00967
00968 for (i = 1; i < nflats; i++) {
00969
00970 header = dfs_load_header(frameset, NULL, 0);
00971
00972 if (header == NULL)
00973 fors_pmos_calib_exit("Cannot load flat field frame header");
00974
00975 alltime += cpl_propertylist_get_double(header, "EXPTIME");
00976
00977 if (cpl_error_get_code() != CPL_ERROR_NONE)
00978 fors_pmos_calib_exit("Missing keyword EXPTIME in flat field "
00979 "frame header");
00980
00981 cpl_propertylist_delete(header);
00982
00983 }
00984
00985 if (bagoo) {
00986 char *montecarlo = getenv("MONTECARLO");
00987
00988 if (montecarlo)
00989 doit = atoi(montecarlo);
00990
00991 if (doit) {
00992 master_bias = dfs_load_image(frameset, "MASTER_BIAS",
00993 CPL_TYPE_FLOAT, 0, 1);
00994 if (master_bias == NULL)
00995 fors_pmos_calib_exit("Cannot load master bias");
00996
00997 blevel = cpl_image_get_mean(master_bias);
00998
00999 cpl_image_delete(master_bias);
01000 }
01001 }
01002
01003 master_flat = dfs_load_image(frameset, flat_tag, CPL_TYPE_FLOAT, 0, 0);
01004
01005 if (master_flat == NULL)
01006 fors_pmos_calib_exit("Cannot load flat field");
01007
01008 if (doit) {
01009 header = dfs_load_header(frameset, flat_tag, 0);
01010
01011 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
01012
01013 if (cpl_error_get_code() != CPL_ERROR_NONE)
01014 fors_pmos_calib_exit("Missing keyword ESO DET OUT1 CONAD "
01015 "in flat field frame header");
01016
01017 ron = cpl_propertylist_get_double(header, "ESO DET OUT1 RON");
01018
01019 if (cpl_error_get_code() != CPL_ERROR_NONE)
01020 fors_pmos_calib_exit("Missing keyword ESO DET OUT1 RON "
01021 "in flat field frame header");
01022
01023 cpl_propertylist_delete(header);
01024
01025 ron /= gain;
01026
01027 mos_randomise_image(master_flat, ron, gain, blevel);
01028 }
01029
01030 ny = cpl_image_get_size_y(master_flat);
01031
01032 if (nflats > 1) {
01033 if (strcmp(stack_method, "average") == 0) {
01034 for (i = 1; i < nflats; i++) {
01035 flat = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01036 if (flat) {
01037 if (doit) {
01038 mos_randomise_image(flat, ron, gain, blevel);
01039 }
01040 cpl_image_add(master_flat, flat);
01041 cpl_image_delete(flat); flat = NULL;
01042 }
01043 else
01044 fors_pmos_calib_exit("Cannot load flat field");
01045 }
01046
01047
01048
01049
01050
01051
01052 }
01053 else {
01054 cpl_imagelist *flatlist = NULL;
01055 double rflux, flux;
01056
01057 added_flat = cpl_image_duplicate(master_flat);
01058
01059 flatlist = cpl_imagelist_new();
01060 cpl_imagelist_set(flatlist, master_flat,
01061 cpl_imagelist_get_size(flatlist));
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072 rflux = cpl_image_get_mean(master_flat);
01073
01074 for (i = 1; i < nflats; i++) {
01075 flat = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01076 if (flat) {
01077 if (doit) {
01078 mos_randomise_image(flat, ron, gain, blevel);
01079 }
01080 cpl_image_add(added_flat, flat);
01081 flux = cpl_image_get_mean(flat);
01082 cpl_image_multiply_scalar(flat, rflux / flux);
01083 cpl_imagelist_set(flatlist, flat,
01084 cpl_imagelist_get_size(flatlist));
01085 }
01086 else {
01087 fors_pmos_calib_exit("Cannot load flat field");
01088 }
01089 }
01090
01091 if (strcmp(stack_method, "median") == 0) {
01092 master_flat = cpl_imagelist_collapse_median_create(flatlist);
01093 }
01094
01095 if (strcmp(stack_method, "minmax") == 0) {
01096 master_flat = cpl_imagelist_collapse_minmax_create(flatlist,
01097 min_reject,
01098 max_reject);
01099 }
01100
01101 if (strcmp(stack_method, "ksigma") == 0) {
01102 master_flat = mos_ksigma_stack(flatlist,
01103 klow, khigh, kiter, NULL);
01104 }
01105 }
01106 }
01107
01108
01109
01110
01111
01112
01113
01114 header = dfs_load_header(frameset, arc_tag, 0);
01115
01116 if (header == NULL)
01117 fors_pmos_calib_exit("Cannot load arc lamp header");
01118
01119 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
01120 if (instrume == NULL)
01121 fors_pmos_calib_exit("Missing keyword INSTRUME in arc lamp header");
01122
01123 instrume = cpl_strdup(instrume);
01124
01125 if (instrume[4] == '1')
01126 snprintf(version, 80, "%s/%s", "fors1", VERSION);
01127 if (instrume[4] == '2')
01128 snprintf(version, 80, "%s/%s", "fors2", VERSION);
01129
01130 reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
01131
01132 if (cpl_error_get_code() != CPL_ERROR_NONE)
01133 fors_pmos_calib_exit("Missing keyword ESO INS GRIS1 WLEN in arc lamp "
01134 "frame header");
01135
01136 if (reference < 3000.0)
01137 reference *= 10;
01138
01139 if (reference < 3000.0 || reference > 13000.0) {
01140 cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
01141 "keyword ESO INS GRIS1 WLEN in arc lamp frame header",
01142 reference);
01143 fors_pmos_calib_exit(NULL);
01144 }
01145
01146 cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
01147
01148 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
01149
01150 if (cpl_error_get_code() != CPL_ERROR_NONE)
01151 fors_pmos_calib_exit("Missing keyword ESO DET WIN1 BINX in arc lamp "
01152 "frame header");
01153
01154 if (rebin != 1) {
01155 dispersion *= rebin;
01156 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
01157 "working dispersion used is %f A/pixel", rebin,
01158 dispersion);
01159 }
01160
01161 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
01162
01163 if (cpl_error_get_code() != CPL_ERROR_NONE)
01164 fors_pmos_calib_exit("Missing keyword ESO DET OUT1 CONAD in arc lamp "
01165 "frame header");
01166
01167 cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain);
01168
01169 if (pmos) {
01170 int nslits_out_det;
01171 cpl_msg_info(recipe, "Produce mask slit position table...");
01172
01173 maskslits = mos_load_slits_fors_mos(header, &nslits_out_det);
01174
01175
01176
01177
01178
01179
01180 mxpos = cpl_table_get_column_median(maskslits, "xtop");
01181 xpos = cpl_table_get_data_double(maskslits, "xtop");
01182 nslits = cpl_table_get_nrow(maskslits);
01183
01184 same_offset = 1;
01185 for (i = 0; i < nslits; i++) {
01186 if (fabs(mxpos-xpos[i]) > 0.01) {
01187 same_offset = 0;
01188 break;
01189 }
01190 }
01191
01192
01193 if(nslits_out_det != 0)
01194 same_offset = 0;
01195
01196 if (same_offset) {
01197 cpl_msg_info(recipe, "All slits have same offset: %.2f", mxpos);
01198 }
01199 else {
01200 cpl_msg_info(recipe, "All slits have different offsets");
01201 }
01202
01203 if (ny != 400 && ny != 500) {
01204 if (cpl_frameset_count_tags(frameset,
01205 master_distortion_tag) == 0)
01206 fors_pmos_calib_exit(
01207 "Missing required input: MASTER_DISTORTION_TABLE");
01208
01209 header_dist = dfs_load_header(frameset,
01210 master_distortion_tag, 0);
01211 rebin_dist = cpl_propertylist_get_int(header_dist,
01212 "ESO DET WIN1 BINX");
01213 cpl_propertylist_delete(header_dist);
01214 }
01215 }
01216
01217
01218
01219
01220
01221
01222
01223
01224 if (nbias) {
01225
01226
01227
01228
01229
01230 cpl_msg_info(recipe, "Generate the master from input raw biases...");
01231
01232 if (nbias > 1) {
01233
01234 biases = cpl_imagelist_new();
01235
01236 bias = dfs_load_image(frameset, "BIAS", CPL_TYPE_FLOAT, 0, 0);
01237
01238 if (bias == NULL)
01239 fors_pmos_calib_exit("Cannot load bias frame");
01240
01241 cpl_imagelist_set(biases, bias, 0);
01242
01243 for (i = 1; i < nbias; i++) {
01244 bias = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01245 if (bias)
01246 cpl_imagelist_set(biases, bias, i);
01247 else
01248 fors_pmos_calib_exit("Cannot load bias frame");
01249 }
01250
01251 master_bias = cpl_imagelist_collapse_median_create(biases);
01252
01253 cpl_imagelist_delete(biases);
01254 }
01255 else {
01256 master_bias = dfs_load_image(frameset, "BIAS",
01257 CPL_TYPE_FLOAT, 0, 1);
01258 if (master_bias == NULL)
01259 fors_pmos_calib_exit("Cannot load bias");
01260 }
01261
01262 }
01263 else {
01264 master_bias = dfs_load_image(frameset, "MASTER_BIAS",
01265 CPL_TYPE_FLOAT, 0, 1);
01266 if (master_bias == NULL)
01267 fors_pmos_calib_exit("Cannot load master bias");
01268 }
01269
01270 cpl_msg_info(recipe, "Remove the master bias...");
01271
01272 overscans = mos_load_overscans_fors(header);
01273 cpl_propertylist_delete(header); header = NULL;
01274
01275 if (nbias) {
01276 int xlow = cpl_table_get_int(overscans, "xlow", 0, NULL);
01277 int ylow = cpl_table_get_int(overscans, "ylow", 0, NULL);
01278 int xhig = cpl_table_get_int(overscans, "xhig", 0, NULL);
01279 int yhig = cpl_table_get_int(overscans, "yhig", 0, NULL);
01280 dummy = cpl_image_extract(master_bias, xlow+1, ylow+1, xhig, yhig);
01281 cpl_image_delete(master_bias); master_bias = dummy;
01282
01283 if (dfs_save_image(frameset, master_bias, "MASTER_BIAS",
01284 NULL, parlist, recipe, version))
01285 fors_pmos_calib_exit(NULL);
01286 }
01287
01288 if (nflats > 1) {
01289 multi_bias = cpl_image_multiply_scalar_create(master_bias, nflats);
01290 dummy = mos_remove_bias(master_flat, multi_bias, overscans);
01291 if (added_flat)
01292 add_dummy = mos_remove_bias(added_flat, multi_bias, overscans);
01293 cpl_image_delete(multi_bias);
01294 }
01295 else {
01296 dummy = mos_remove_bias(master_flat, master_bias, overscans);
01297 }
01298 cpl_image_delete(master_flat);
01299 master_flat = dummy;
01300
01301 if (master_flat == NULL)
01302 fors_pmos_calib_exit("Cannot remove bias from flat field");
01303
01304 if (added_flat) {
01305 cpl_image_delete(added_flat);
01306 added_flat = add_dummy;
01307
01308 if (added_flat == NULL)
01309 fors_pmos_calib_exit("Cannot remove bias from added flat field");
01310
01311 trace_flat = added_flat;
01312 }
01313 else
01314 trace_flat = master_flat;
01315
01316 wavelengths = dfs_load_table(frameset, "MASTER_LINECAT", 1);
01317
01318 if (wavelengths == NULL)
01319 fors_pmos_calib_exit("Cannot load line catalog");
01320
01321
01322
01323
01324
01325 nlines = cpl_table_get_nrow(wavelengths);
01326
01327 if (nlines == 0)
01328 fors_pmos_calib_exit("Empty input line catalog");
01329
01330 if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
01331 cpl_msg_error(recipe, "Missing column %s in input line catalog table",
01332 wcolumn);
01333 fors_pmos_calib_exit(NULL);
01334 }
01335
01336 line = cpl_malloc(nlines * sizeof(double));
01337
01338 for (i = 0; i < nlines; i++)
01339 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
01340
01341 lines = cpl_vector_wrap(nlines, line);
01342
01343 for (j = 0; j < pmos; j++) {
01344 int k;
01345
01346 cpl_msg_indent_less();
01347 cpl_msg_info(recipe, "Processing arc lamp nb %d out of %d ...",
01348 j + 1, pmos);
01349 cpl_msg_indent_more();
01350
01351 cpl_msg_info(recipe, "Load arc lamp exposure...");
01352 cpl_msg_indent_more();
01353
01354 spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0);
01355
01356
01357
01358
01359
01360
01361 for (k = 0; k < j; k ++) {
01362 cpl_image_delete(spectra);
01363 spectra = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01364 }
01365
01366 if (spectra == NULL)
01367 fors_pmos_calib_exit("Cannot load arc lamp exposure");
01368
01369 if (doit) {
01370 mos_randomise_image(spectra, ron, gain, blevel);
01371 }
01372
01373 cpl_msg_info(recipe, "Remove the master bias...");
01374
01375 dummy = mos_remove_bias(spectra, master_bias, overscans);
01376 cpl_image_delete(spectra); spectra = dummy;
01377
01378 if (spectra == NULL)
01379 fors_pmos_calib_exit("Cannot remove bias from arc lamp exposure");
01380
01381 cpl_msg_indent_less();
01382 cpl_msg_info(recipe, "Load input line catalog...");
01383 cpl_msg_indent_more();
01384
01385
01386
01387
01388
01389 if (mos_saturation_process(spectra))
01390 fors_pmos_calib_exit("Cannot process saturation");
01391
01392 if (mos_subtract_background(spectra))
01393 fors_pmos_calib_exit("Cannot subtract the background");
01394
01395 if (!j) {
01396
01397
01398
01399
01400 cpl_msg_indent_less();
01401 cpl_msg_info(recipe, "Detecting spectra on CCD...");
01402 cpl_msg_indent_more();
01403
01404 nx = cpl_image_get_size_x(spectra);
01405 ccd_ysize = ny = cpl_image_get_size_y(spectra);
01406
01407 refmask = cpl_mask_new(nx, ny);
01408
01409 checkwave =
01410 mos_wavelength_calibration_raw(spectra, lines, dispersion,
01411 peakdetection, wradius,
01412 wdegree, wreject, reference,
01413 &startwavelength, &endwavelength,
01414 NULL, NULL, NULL, NULL, NULL,
01415 NULL, refmask, NULL);
01416
01417 if (checkwave == NULL)
01418 fors_pmos_calib_exit("Wavelength calibration failure.");
01419
01420
01421
01422
01423
01424 header = cpl_propertylist_new();
01425 cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01426 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01427 cpl_propertylist_update_double(header, "CRVAL1",
01428 startwavelength + dispersion/2);
01429 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01430
01431
01432 cpl_propertylist_update_double(header, "CD1_1", dispersion);
01433 cpl_propertylist_update_double(header, "CD1_2", 0.0);
01434 cpl_propertylist_update_double(header, "CD2_1", 0.0);
01435 cpl_propertylist_update_double(header, "CD2_2", 1.0);
01436 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01437 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01438
01439 if (check) {
01440 if (!j) {
01441 if(dfs_save_image_null(frameset, parlist,
01442 spectra_detection_tag,
01443 recipe, version)) {
01444 fors_pmos_calib_exit(NULL);
01445 }
01446 }
01447
01448 if (dfs_save_image_ext(checkwave,
01449 spectra_detection_tag, header)) {
01450 fors_pmos_calib_exit(NULL);
01451 }
01452 }
01453
01454 cpl_image_delete(checkwave); checkwave = NULL;
01455 cpl_propertylist_delete(header); header = NULL;
01456
01457 if (cpl_mask_is_empty(refmask))
01458 fors_pmos_calib_exit("Wavelength calibration failure.");
01459
01460 if (mos_refmask_find_gaps(refmask, trace_flat, -1.0))
01461 fors_pmos_calib_exit("The gaps could not be found");
01462
01463 cpl_msg_info(recipe,
01464 "Locate slits at reference wavelength on CCD...");
01465 slits = mos_locate_spectra(refmask);
01466
01467 if (!slits) {
01468 cpl_msg_error(cpl_error_get_where(), "%s",
01469 cpl_error_get_message());
01470 fors_pmos_calib_exit("No slits could be detected!");
01471 }
01472
01473 if (same_offset) {
01474 if (ny != 400 && ny != 500) {
01475 float rescale = (float) rebin_dist / rebin;
01476 if (mos_check_slits(slits, rescale)) {
01477 fors_pmos_calib_exit("Some slits are missing. "
01478 "Cannot recover!");
01479 }
01480 }
01481 }
01482
01483 refimage = cpl_image_new_from_mask(refmask);
01484 cpl_mask_delete(refmask); refmask = NULL;
01485
01486 if (check) {
01487 if (!j) {
01488 if(dfs_save_image_null(frameset, parlist,
01489 slit_map_tag,
01490 recipe, version)) {
01491 fors_pmos_calib_exit(NULL);
01492 }
01493 }
01494
01495 save_header = dfs_load_header(frameset, arc_tag, 0);
01496
01497 for (k = 0; k < j; k ++) {
01498 cpl_propertylist_delete(save_header);
01499 save_header = dfs_load_header(frameset, NULL, 0);
01500 }
01501
01502 if (dfs_save_image_ext(refimage, slit_map_tag, save_header)) {
01503 fors_pmos_calib_exit(NULL);
01504 }
01505 cpl_propertylist_delete(save_header); save_header = NULL;
01506 }
01507
01508 cpl_image_delete(refimage); refimage = NULL;
01509
01510
01511
01512 same_offset = 1;
01513 if (0) {
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531 cpl_msg_indent_less();
01532 cpl_msg_info(recipe,
01533 "Attempt slit identification (optional)...");
01534 cpl_msg_indent_more();
01535
01536 positions = mos_identify_slits(slits, maskslits, NULL);
01537
01538 if (positions) {
01539 cpl_table_delete(slits);
01540 slits = positions;
01541
01542
01543
01544
01545
01546 cpl_table_and_selected_double(slits,
01547 "ytop", CPL_GREATER_THAN, ny);
01548 cpl_table_or_selected_double(slits,
01549 "ybottom", CPL_LESS_THAN, 0);
01550 cpl_table_erase_selected(slits);
01551
01552 nslits = cpl_table_get_nrow(slits);
01553
01554 if (nslits == 0)
01555 fors_pmos_calib_exit("No slits found on the CCD");
01556
01557 cpl_msg_info(recipe,
01558 "%d slits are entirely contained in CCD",
01559 nslits);
01560 }
01561 else {
01562 same_offset = 1;
01563 cpl_msg_info(recipe,
01564 "Global distortion model cannot be computed");
01565 if (cpl_error_get_code() != CPL_ERROR_NONE) {
01566 fors_pmos_calib_exit(NULL);
01567 }
01568 }
01569 }
01570
01571
01572 if (ny == 400 || ny == 500) {
01573
01574
01575
01576
01577
01578
01579 nslits = cpl_table_get_nrow(slits);
01580
01581 if (nslits > 4) {
01582 cpl_table_unselect_all(slits);
01583 for (k = 0; k < cpl_table_get_nrow(slits); k++) {
01584 double jump = cpl_table_get(slits, "ytop", k, NULL)
01585 - cpl_table_get(slits, "ybottom", k, NULL);
01586 if (jump < 50.) {
01587 cpl_table_select_row(slits, k);
01588 }
01589 }
01590 cpl_table_erase_selected(slits);
01591 nslits = cpl_table_get_nrow(slits);
01592 }
01593
01594 if (nslits == 0)
01595 fors_pmos_calib_exit("No slits found on the CCD");
01596
01597 if (nslits == 4) {
01598 cpl_table_unselect_all(slits);
01599 cpl_table_select_row(slits, 0);
01600 cpl_table_select_row(slits, cpl_table_get_nrow(slits)-1);
01601 cpl_table_erase_selected(slits);
01602 }
01603
01604 cpl_msg_info(recipe,
01605 "%d slits are entirely contained in CCD", nslits);
01606 }
01607 else {
01608 cpl_table_unselect_all(slits);
01609 for (k = 0; k < cpl_table_get_nrow(slits); k++) {
01610 double jump = cpl_table_get(slits, "ytop", k, NULL)
01611 - cpl_table_get(slits, "ybottom", k, NULL);
01612 if (jump < 10.) {
01613 cpl_table_select_row(slits, k);
01614 }
01615 }
01616 cpl_table_erase_selected(slits);
01617 nslits = cpl_table_get_nrow(slits);
01618 }
01619
01620
01621
01622
01623
01624
01625 cpl_msg_indent_less();
01626 cpl_msg_info(recipe, "Determining spectral curvature...");
01627 cpl_msg_indent_more();
01628
01629 cpl_msg_info(recipe, "Tracing master flat field spectra edges...");
01630 traces = mos_trace_flat(trace_flat, slits, reference,
01631 startwavelength, endwavelength, dispersion);
01632
01633 if (!traces)
01634 fors_pmos_calib_exit("Tracing failure");
01635
01636 cpl_image_delete(added_flat); added_flat = NULL;
01637
01638 cpl_msg_info(recipe, "Fitting flat field spectra edges...");
01639 polytraces = mos_poly_trace(slits, traces, cdegree);
01640
01641 if (!polytraces)
01642 fors_pmos_calib_exit("Trace fitting failure");
01643
01644 if (cmode) {
01645 cpl_msg_info(recipe,
01646 "Computing global spectral curvature model...");
01647 mos_global_trace(slits, polytraces, cmode);
01648 }
01649
01650 if (!j) {
01651 if(dfs_save_image_null(frameset, parlist, curv_traces_tag,
01652 recipe, version)) {
01653 fors_pmos_calib_exit(NULL);
01654 }
01655 }
01656
01657 if (dfs_save_table_ext(traces, curv_traces_tag, NULL)) {
01658 fors_pmos_calib_exit(NULL);
01659 }
01660
01661 cpl_table_delete(traces); traces = NULL;
01662
01663 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01664
01665 }
01666
01667 spatial = mos_spatial_calibration(spectra, slits, polytraces,
01668 reference,
01669 startwavelength, endwavelength,
01670 dispersion, 0, j ? NULL: coordinate);
01671
01672 if (!j) {
01673
01674 if (same_offset) {
01675 cpl_image_delete(spectra); spectra = NULL;
01676 }
01677
01678
01679
01680
01681
01682
01683
01684 cpl_msg_indent_less();
01685 cpl_msg_info(recipe, "Perform flat field normalisation...");
01686 cpl_msg_indent_more();
01687
01688 norm_flat = cpl_image_duplicate(master_flat);
01689
01690 smo_flat = mos_normalise_flat(norm_flat, coordinate, slits,
01691 polytraces, reference,
01692 startwavelength, endwavelength,
01693 dispersion, dradius, ddegree);
01694
01695
01696 cpl_image_delete(smo_flat); smo_flat = NULL;
01697
01698
01699 save_header = dfs_load_header(frameset, flat_tag, 0);
01700 cpl_propertylist_update_int(save_header, "ESO PRO DATANCOM",
01701 nflats);
01702
01703 rect_flat = mos_spatial_calibration(master_flat, slits, polytraces,
01704 reference, startwavelength,
01705 endwavelength, dispersion, 0,
01706 NULL);
01707 rect_nflat = mos_spatial_calibration(norm_flat, slits, polytraces,
01708 reference, startwavelength,
01709 endwavelength, dispersion, 0,
01710 NULL);
01711
01712
01713 if (dfs_save_image(frameset, master_flat, master_screen_flat_tag,
01714 save_header, parlist, recipe, version))
01715 fors_pmos_calib_exit(NULL);
01716
01717
01718 if (dfs_save_image(frameset, norm_flat, master_norm_flat_tag,
01719 save_header, parlist, recipe, version))
01720 fors_pmos_calib_exit(NULL);
01721
01722 cpl_image_delete(norm_flat); norm_flat = NULL;
01723 cpl_propertylist_delete(save_header); save_header = NULL;
01724
01725 }
01726
01727
01728
01729
01730
01731
01732
01733 cpl_msg_indent_less();
01734 cpl_msg_info(recipe, "Perform final wavelength calibration...");
01735 cpl_msg_indent_more();
01736
01737 nx = cpl_image_get_size_x(spatial);
01738 ny = cpl_image_get_size_y(spatial);
01739
01740 idscoeff = cpl_table_new(ny);
01741 restable = cpl_table_new(nlines);
01742 rainbow = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01743 if (check)
01744 residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01745 fiterror = cpl_calloc(ny, sizeof(double));
01746 fitlines = cpl_calloc(ny, sizeof(int));
01747
01748 rectified = mos_wavelength_calibration_final(spatial, slits, lines,
01749 dispersion, peakdetection,
01750 wradius, wdegree, wreject,
01751 reference,
01752 &startwavelength,
01753 &endwavelength, fitlines,
01754 fiterror, idscoeff,
01755 rainbow,
01756 residual, restable, NULL);
01757
01758 if (rectified == NULL)
01759 fors_pmos_calib_exit("Wavelength calibration failure.");
01760
01761 if (!j) {
01762 if(dfs_save_image_null(frameset, parlist, disp_residuals_table_tag,
01763 recipe, version)) {
01764 fors_pmos_calib_exit(NULL);
01765 }
01766 }
01767
01768 header = dfs_load_header(frameset, arc_tag, 0);
01769
01770 for (k = 0; k < j; k ++) {
01771 cpl_propertylist_delete(header);
01772 header = dfs_load_header(frameset, NULL, 0);
01773 }
01774
01775 if (dfs_save_table_ext(restable, disp_residuals_table_tag, header)) {
01776 fors_pmos_calib_exit(NULL);
01777 }
01778
01779 cpl_propertylist_delete(header);
01780
01781 cpl_table_delete(restable); restable = NULL;
01782
01783 cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL;
01784 cpl_table_set_column_unit(idscoeff, "error", "pixel");
01785 cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL;
01786
01787 for (i = 0; i < ny; i++)
01788 if (!cpl_table_is_valid(idscoeff, "c0", i))
01789 cpl_table_set_invalid(idscoeff, "error", i);
01790
01791 delta = mos_map_pixel(idscoeff, reference, startwavelength,
01792 endwavelength, dispersion, 2);
01793
01794 header = dfs_load_header(frameset, arc_tag, 0);
01795
01796 for (k = 0; k < j; k ++) {
01797 cpl_propertylist_delete(header);
01798 header = dfs_load_header(frameset, NULL, 0);
01799 }
01800
01801 cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01802 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01803 cpl_propertylist_update_double(header, "CRVAL1",
01804 startwavelength + dispersion/2);
01805 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01806
01807
01808 cpl_propertylist_update_double(header, "CD1_1", dispersion);
01809 cpl_propertylist_update_double(header, "CD1_2", 0.0);
01810 cpl_propertylist_update_double(header, "CD2_1", 0.0);
01811 cpl_propertylist_update_double(header, "CD2_2", 1.0);
01812 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01813 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01814
01815 if (!j) {
01816 if(dfs_save_image_null(frameset, parlist, delta_image_tag,
01817 recipe, version)) {
01818 fors_pmos_calib_exit(NULL);
01819 }
01820 }
01821
01822 if (dfs_save_image_ext(delta, delta_image_tag, header)) {
01823 fors_pmos_calib_exit(NULL);
01824 }
01825
01826 cpl_image_delete(delta); delta = NULL;
01827 cpl_propertylist_delete(header); header = NULL;
01828
01829 mean_rms = mos_distortions_rms(rectified, lines, startwavelength,
01830 dispersion, 6, 0);
01831
01832 cpl_msg_info(recipe, "Mean residual: %f pixel", mean_rms);
01833
01834 mean_rms = cpl_table_get_column_mean(idscoeff, "error");
01835 mean_rms_err = cpl_table_get_column_stdev(idscoeff, "error");
01836
01837 cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)",
01838 mean_rms, mean_rms * dispersion);
01839
01840 restab = mos_resolution_table(rectified, startwavelength, dispersion,
01841 60000, lines);
01842
01843 if (restab) {
01844 cpl_msg_info(recipe, "Mean spectral resolution: %.2f",
01845 cpl_table_get_column_mean(restab, "resolution"));
01846 cpl_msg_info(recipe,
01847 "Mean reference lines FWHM: %.2f +/- %.2f pixel",
01848 cpl_table_get_column_mean(restab, "fwhm") / dispersion,
01849 cpl_table_get_column_mean(restab, "fwhm_rms") / dispersion);
01850
01851 cpl_table_duplicate_column(restab, "dlambda",
01852 restab, "fwhm");
01853 cpl_table_multiply_scalar(restab, "dlambda", dispersion);
01854 cpl_table_duplicate_column(restab, "dlambda_rms",
01855 restab, "fwhm_rms");
01856 cpl_table_multiply_scalar(restab, "dlambda_rms", dispersion);
01857
01858 if (qc) {
01859
01860 qclist = cpl_propertylist_new();
01861
01862
01863
01864
01865 keyname = "QC.DID";
01866
01867 if (fors_header_write_string(qclist,
01868 keyname,
01869 "2.0",
01870 "QC1 dictionary")) {
01871 fors_pmos_calib_exit("Cannot write dictionary version "
01872 "to QC log file");
01873 }
01874
01875
01876 keyname = "QC.PMOS.RESOLUTION";
01877
01878 if (fors_header_write_double(qclist,
01879 cpl_table_get_column_mean(restab,
01880 "resolution"),
01881 keyname,
01882 "Angstrom",
01883 "Mean spectral resolution")) {
01884 fors_pmos_calib_exit("Cannot write mean spectral "
01885 "resolution to QC log file");
01886 }
01887
01888 keyname = "QC.PMOS.RESOLUTION.RMS";
01889
01890 if (fors_header_write_double(qclist,
01891 cpl_table_get_column_stdev(restab,
01892 "resolution"),
01893 keyname,
01894 "Angstrom",
01895 "Scatter of spectral resolution")) {
01896 fors_pmos_calib_exit("Cannot write spectral resolution "
01897 "scatter to QC log file");
01898 }
01899
01900 keyname = "QC.PMOS.RESOLUTION.NWAVE";
01901
01902 if (fors_header_write_int(qclist, cpl_table_get_nrow(restab) -
01903 cpl_table_count_invalid(restab,
01904 "resolution"),
01905 keyname,
01906 NULL,
01907 "Number of examined wavelengths "
01908 "for resolution computation")) {
01909 fors_pmos_calib_exit("Cannot write number of lines used "
01910 "in spectral resolution computation "
01911 "to QC log file");
01912 }
01913
01914 keyname = "QC.PMOS.RESOLUTION.MEANRMS";
01915
01916 if (fors_header_write_double(qclist,
01917 cpl_table_get_column_mean(restab,
01918 "resolution_rms"),
01919 keyname, NULL,
01920 "Mean error on spectral "
01921 "resolution computation")) {
01922 fors_pmos_calib_exit("Cannot write mean error in "
01923 "spectral resolution computation "
01924 "to QC log file");
01925 }
01926
01927 keyname = "QC.PMOS.RESOLUTION.NLINES";
01928
01929 if (fors_header_write_int(qclist,
01930 cpl_table_get_column_mean(restab,
01931 "nlines") *
01932 cpl_table_get_nrow(restab),
01933 keyname, NULL,
01934 "Number of lines for spectral "
01935 "resolution computation")) {
01936 fors_pmos_calib_exit("Cannot write number of examined "
01937 "wavelengths in spectral resolution "
01938 "computation to QC log file");
01939 }
01940
01941 }
01942
01943 if (!j) {
01944 if(dfs_save_image_null(frameset, parlist,
01945 spectral_resolution_tag,
01946 recipe, version)) {
01947 fors_pmos_calib_exit(NULL);
01948 }
01949 }
01950
01951 header = dfs_load_header(frameset, arc_tag, 0);
01952
01953 for (k = 0; k < j; k ++) {
01954 cpl_propertylist_delete(header);
01955 header = dfs_load_header(frameset, NULL, 0);
01956 }
01957
01958 cpl_propertylist_append(header, qclist);
01959
01960 if (dfs_save_table_ext(restab, spectral_resolution_tag, header)) {
01961 fors_pmos_calib_exit(NULL);
01962 }
01963
01964 cpl_table_delete(restab); restab = NULL;
01965 cpl_propertylist_delete(qclist); qclist = NULL;
01966 cpl_propertylist_delete(header); header = NULL;
01967
01968 }
01969 else
01970 fors_pmos_calib_exit("Cannot compute the spectral "
01971 "resolution table");
01972
01973 if (!j) {
01974 if(dfs_save_image_null(frameset, parlist, disp_coeff_tag,
01975 recipe, version)) {
01976 fors_pmos_calib_exit(NULL);
01977 }
01978 }
01979
01980 header = dfs_load_header(frameset, arc_tag, 0);
01981
01982 for (k = 0; k < j; k ++) {
01983 cpl_propertylist_delete(header);
01984 header = dfs_load_header(frameset, NULL, 0);
01985 }
01986
01987 if (dfs_save_table_ext(idscoeff, disp_coeff_tag, header)) {
01988 fors_pmos_calib_exit(NULL);
01989 }
01990
01991 cpl_propertylist_delete(header);
01992
01993 if (!j) {
01994 mapped_flat = mos_wavelength_calibration(rect_flat, reference,
01995 startwavelength,
01996 endwavelength,
01997 dispersion, idscoeff, 0);
01998
01999 mapped_nflat = mos_wavelength_calibration(rect_nflat, reference,
02000 startwavelength,
02001 endwavelength,
02002 dispersion, idscoeff, 0);
02003
02004 cpl_image_delete(rect_flat); rect_flat = NULL;
02005 cpl_image_delete(rect_nflat); rect_nflat = NULL;
02006 }
02007
02008
02009
02010 cpl_table_delete(idscoeff); idscoeff = NULL;
02011
02012 header = dfs_load_header(frameset, arc_tag, 0);
02013
02014 for (k = 0; k < j; k ++) {
02015 cpl_propertylist_delete(header);
02016 header = dfs_load_header(frameset, NULL, 0);
02017 }
02018
02019 cpl_propertylist_update_double(header, "CRPIX1", 1.0);
02020 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
02021 cpl_propertylist_update_double(header, "CRVAL1",
02022 startwavelength + dispersion/2);
02023 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
02024
02025
02026 cpl_propertylist_update_double(header, "CD1_1", dispersion);
02027 cpl_propertylist_update_double(header, "CD1_2", 0.0);
02028 cpl_propertylist_update_double(header, "CD2_1", 0.0);
02029 cpl_propertylist_update_double(header, "CD2_2", 1.0);
02030 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
02031 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
02032 cpl_propertylist_update_int(header, "ESO PRO DATANCOM", 1);
02033
02034 if (!j) {
02035 if(dfs_save_image_null(frameset, parlist, reduced_lamp_tag,
02036 recipe, version)) {
02037 fors_pmos_calib_exit(NULL);
02038 }
02039 }
02040
02041 if (dfs_save_image_ext(rectified, reduced_lamp_tag, header)) {
02042 fors_pmos_calib_exit(NULL);
02043 }
02044
02045 cpl_image_delete(rectified); rectified = NULL;
02046
02047 cpl_propertylist_update_int(header, "ESO PRO DATANCOM", nflats);
02048
02049 if (!j) {
02050 if (dfs_save_image(frameset, mapped_flat, mapped_screen_flat_tag,
02051 header, parlist, recipe, version))
02052 fors_pmos_calib_exit(NULL);
02053 cpl_image_delete(mapped_flat); mapped_flat = NULL;
02054
02055 if (dfs_save_image(frameset, mapped_nflat, mapped_norm_flat_tag,
02056 header, parlist, recipe, version))
02057 fors_pmos_calib_exit(NULL);
02058 cpl_image_delete(mapped_nflat); mapped_nflat = NULL;
02059 }
02060
02061 cpl_propertylist_delete(header); header = NULL;
02062
02063 if (check) {
02064 save_header = dfs_load_header(frameset, arc_tag, 0);
02065 for (k = 0; k < j; k ++) {
02066 cpl_propertylist_delete(save_header);
02067 save_header = dfs_load_header(frameset, NULL, 0);
02068 }
02069
02070 cpl_propertylist_update_double(save_header, "CRPIX2", 1.0);
02071 cpl_propertylist_update_double(save_header, "CRVAL2", 1.0);
02072
02073 cpl_propertylist_update_double(save_header, "CD1_1", 1.0);
02074 cpl_propertylist_update_double(save_header, "CD1_2", 0.0);
02075 cpl_propertylist_update_double(save_header, "CD2_1", 0.0);
02076 cpl_propertylist_update_double(save_header, "CD2_2", 1.0);
02077 cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR");
02078 cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL");
02079
02080 if (!j) {
02081 if(dfs_save_image_null(frameset, parlist, disp_residuals_tag,
02082 recipe, version)) {
02083 fors_pmos_calib_exit(NULL);
02084 }
02085 }
02086
02087 if (dfs_save_image_ext(residual, disp_residuals_tag, save_header)) {
02088 fors_pmos_calib_exit(NULL);
02089 }
02090
02091 cpl_image_delete(residual); residual = NULL;
02092 cpl_propertylist_delete(save_header); save_header = NULL;
02093 }
02094
02095 wavemap = mos_map_wavelengths(coordinate, rainbow, slits, polytraces,
02096 reference, startwavelength, endwavelength,
02097 dispersion);
02098
02099 cpl_image_delete(rainbow); rainbow = NULL;
02100
02101 save_header = dfs_load_header(frameset, arc_tag, 0);
02102
02103 for (k = 0; k < j; k ++) {
02104 cpl_propertylist_delete(save_header);
02105 save_header = dfs_load_header(frameset, NULL, 0);
02106 }
02107
02108 if (qc) {
02109
02110
02111
02112
02113 if (fors_header_write_string(save_header,
02114 "QC.DID",
02115 "2.0",
02116 "QC1 dictionary")) {
02117 fors_pmos_calib_exit("Cannot write dictionary version "
02118 "to QC log file");
02119 }
02120
02121 if (fors_header_write_double(save_header,
02122 mean_rms,
02123 "QC.WAVE.ACCURACY",
02124 "pixel",
02125 "Mean accuracy of wavecalib model")) {
02126 fors_pmos_calib_exit("Cannot write mean wavelength calibration "
02127 "accuracy to QC log file");
02128 }
02129
02130
02131 if (fors_header_write_double(save_header,
02132 mean_rms_err,
02133 "QC.WAVE.ACCURACY.ERROR",
02134 "pixel",
02135 "Error on accuracy of wavecalib model")) {
02136 fors_pmos_calib_exit("Cannot write error on wavelength "
02137 "calibration accuracy to QC log file");
02138 }
02139
02140 if (same_offset && fabs(mxpos) < 0.05) {
02141
02142
02143 data = cpl_image_get_data(wavemap);
02144
02145 if (fors_header_write_double(save_header,
02146 data[nx/2 + ccd_ysize*nx/2],
02147 "QC.PMOS.CENTRAL.WAVELENGTH",
02148 "Angstrom",
02149 "Wavelength at CCD center")) {
02150 fors_pmos_calib_exit("Cannot write central wavelength "
02151 "to QC log file");
02152 }
02153 }
02154
02155 }
02156
02157 if (!j) {
02158 if(dfs_save_image_null(frameset, parlist, wavelength_map_tag,
02159 recipe, version)) {
02160 fors_pmos_calib_exit(NULL);
02161 }
02162 }
02163
02164 if (dfs_save_image_ext(wavemap, wavelength_map_tag, save_header)) {
02165 fors_pmos_calib_exit(NULL);
02166 }
02167
02168 cpl_image_delete(wavemap); wavemap = NULL;
02169
02170 cpl_propertylist_erase_regexp(save_header, "^ESO QC ", 0);
02171
02172 cpl_propertylist_delete(save_header); save_header = NULL;
02173
02174 cpl_msg_indent_less();
02175
02176 }
02177
02178 if (dfs_save_image(frameset, coordinate, spatial_map_tag, save_header,
02179 parlist, recipe, version))
02180 fors_pmos_calib_exit(NULL);
02181
02182 cpl_image_delete(coordinate); coordinate = NULL;
02183 cpl_propertylist_delete(save_header); save_header = NULL;
02184
02185 header = NULL;
02186
02187 if (qc) {
02188
02189 double maxpos, maxneg, maxcurve, maxslope;
02190
02191 header = dfs_load_header(frameset, arc_tag, 0);
02192
02193
02194
02195
02196 if (fors_header_write_string(header,
02197 "QC.DID",
02198 "2.0",
02199 "QC1 dictionary")) {
02200 fors_pmos_calib_exit("Cannot write dictionary version "
02201 "to QC log file");
02202 }
02203
02204 maxpos = fabs(cpl_table_get_column_max(polytraces, "c2"));
02205 maxneg = fabs(cpl_table_get_column_min(polytraces, "c2"));
02206 maxcurve = maxpos > maxneg ? maxpos : maxneg;
02207 if (fors_header_write_double(header,
02208 maxcurve,
02209 "QC.TRACE.MAX.CURVATURE",
02210 "Y pixel / X pixel ^2",
02211 "Max observed curvature "
02212 "in spectral tracing")) {
02213 fors_pmos_calib_exit("Cannot write max observed curvature in "
02214 "spectral tracing to QC log file");
02215 }
02216
02217 maxpos = fabs(cpl_table_get_column_max(polytraces, "c1"));
02218 maxneg = fabs(cpl_table_get_column_min(polytraces, "c1"));
02219 maxslope = maxpos > maxneg ? maxpos : maxneg;
02220
02221 if (fors_header_write_double(header,
02222 maxslope,
02223 "QC.TRACE.MAX.SLOPE",
02224 "Y pixel / X pixel",
02225 "Max observed slope in spectral tracing")) {
02226 fors_pmos_calib_exit("Cannot write max observed slope in spectral "
02227 "tracing to QC log file");
02228 }
02229 }
02230
02231 if (dfs_save_table(frameset, polytraces, curv_coeff_tag, header,
02232 parlist, recipe, version)) {
02233 fors_pmos_calib_exit(NULL);
02234 }
02235
02236 cpl_propertylist_delete(header); header = NULL;
02237 cpl_table_delete(polytraces); polytraces = NULL;
02238
02239
02240
02241
02242 if (same_offset) {
02243 cpl_table *globaltbl;
02244 cpl_table *slitpos;
02245 double *l_ytop;
02246 int *l_id;
02247 int npairs;
02248 double *ytop = cpl_table_get_data_double(slits, "ytop");
02249 double *ybot = cpl_table_get_data_double(slits, "ybottom");
02250 int k;
02251
02252
02253
02254 nslits = cpl_table_get_nrow(slits);
02255
02256 cpl_table_new_column(slits, "pair_id", CPL_TYPE_INT);
02257
02258
02259 if (ccd_ysize == 400 || ccd_ysize == 500) {
02260
02261
02262
02263
02264
02265 l_ytop = cpl_malloc(sizeof(double));
02266 l_ytop[0] = 255.0;
02267 l_id = cpl_malloc(sizeof(double));
02268 l_id[0] = 10;
02269 npairs = 1;
02270 }
02271 else {
02272 globaltbl = dfs_load_table(frameset, master_distortion_tag, 1);
02273 slitpos = mos_build_slit_location(globaltbl, maskslits, ccd_ysize);
02274 l_ytop = cpl_table_get_data_double(slitpos, "ytop");
02275 l_id = cpl_table_get_data_int(slitpos, "slit_id");
02276 npairs = cpl_table_get_nrow(slitpos);
02277 if (rebin_dist != rebin) {
02278 float rescale = (float)rebin_dist / rebin;
02279 for (i = 0; i < npairs; i++) {
02280 l_ytop[i] *= rescale;
02281 }
02282 }
02283 }
02284
02285 for (k = 0; k < npairs; k++) {
02286 int h;
02287
02288 for (h = 0; h < nslits; h++) {
02289
02290 if (l_ytop[k] < ytop[h] && l_ytop[k] > ybot[h]) {
02291 if (h + 1 < nslits) {
02292 cpl_table_set_int(slits, "pair_id", h, l_id[k]);
02293 cpl_table_set_int(slits, "pair_id", h + 1, l_id[k]);
02294 }
02295 }
02296 }
02297 }
02298
02299
02300
02301 cpl_table_fill_invalid_int(slits, "pair_id", -1);
02302
02303 if (ccd_ysize == 400 || ccd_ysize == 500) {
02304 cpl_free(l_ytop);
02305 cpl_free(l_id);
02306 }
02307 else {
02308 cpl_table_delete(slitpos); slitpos = NULL;
02309 cpl_table_delete(globaltbl); globaltbl = NULL;
02310
02311 cpl_table_delete(maskslits); maskslits = NULL;
02312 }
02313 }
02314
02315 if (dfs_save_table(frameset, slits, slit_location_tag, NULL,
02316 parlist, recipe, version)) {
02317 fors_pmos_calib_exit(NULL);
02318 }
02319
02320 cpl_table_delete(slits); slits = NULL;
02321
02322 cpl_image_delete(spatial); spatial = NULL;
02323
02324 cpl_free(instrume); instrume = NULL;
02325
02326 cpl_table_delete(overscans); overscans = NULL;
02327 cpl_image_delete(master_bias); master_bias = NULL;
02328 cpl_image_delete(master_flat); master_flat = NULL;
02329
02330 cpl_table_delete(wavelengths); wavelengths = NULL;
02331 cpl_vector_delete(lines); lines = NULL;
02332
02333 if (cpl_error_get_code()) {
02334 cpl_msg_error(cpl_error_get_where(), "%s", cpl_error_get_message());
02335 fors_pmos_calib_exit(NULL);
02336 }
02337
02338 return 0;
02339 }