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 <cpl.h>
00034 #include <moses.h>
00035 #include <fors_dfs.h>
00036
00037 static int fors_wave_calib_create(cpl_plugin *);
00038 static int fors_wave_calib_exec(cpl_plugin *);
00039 static int fors_wave_calib_destroy(cpl_plugin *);
00040 static int fors_wave_calib(cpl_parameterlist *, cpl_frameset *);
00041
00042 static char fors_wave_calib_description[] =
00043 "This recipe is used to wavelength calibrate MOS/MXU slit spectra contained\n"
00044 "in the rectified arc lamp exposure produced with recipe fors_extract_slits.\n"
00045 "A pattern-matching algorithm is applied as in recipe fors_detect_spectra.\n"
00046 "The input spatial map is used in the production of the wavelength map.\n"
00047 "\n"
00048 "Use recipe fors_wave_calib_lss for LSS data, or for MOS/MXU data where all\n"
00049 "slits have the same offset. For more details on this data reduction strategy\n"
00050 "please refer to the FORS Pipeline User's Manual.\n"
00051 "\n"
00052 "Note that specifying an input GRISM_TABLE will set some of the recipe\n"
00053 "configuration parameters to default values valid for a particular grism.\n"
00054 "\n"
00055 "In the table below the MXU acronym can be alternatively read as MOS.\n\n"
00056 "Input files:\n\n"
00057 " DO category: Type: Explanation: Required:\n"
00058 " SPATIAL_MAP_MXU Calib Spatial map Y\n"
00059 " RECTIFIED_LAMP_MXU Calib Rectified arc exposure Y\n"
00060 " SLIT_LOCATION_MXU Calib Slit location table Y\n"
00061 " CURV_COEFF_MXU Calib Spectral curvature Y\n"
00062 " MASTER_LINECAT Calib Line catalog Y\n"
00063 " GRISM_TABLE Calib Grism table .\n\n"
00064 "Output files:\n\n"
00065 " DO category: Data type: Explanation:\n"
00066 " REDUCED_LAMP_MXU FITS image Calibrated arc lamp exposure\n"
00067 " DISP_COEFF_MXU FITS table Inverse dispersion coefficients\n"
00068 " DISP_RESIDUALS_MXU FITS image Image of modeling residuals\n"
00069 " WAVELENGTH_MAP_MXU FITS image Wavelengths mapped on CCD\n"
00070 " SPECTRAL_RESOLUTION_MXU FITS table Spectral resolution table\n\n";
00071
00072 #define fors_wave_calib_exit(message) \
00073 { \
00074 if ((const char *)message != NULL) cpl_msg_error(recipe, message); \
00075 cpl_image_delete(spectra); \
00076 cpl_image_delete(spatial); \
00077 cpl_image_delete(rainbow); \
00078 cpl_image_delete(residual); \
00079 cpl_image_delete(rectified); \
00080 cpl_image_delete(wavemap); \
00081 cpl_table_delete(grism_table); \
00082 cpl_table_delete(wavelengths); \
00083 cpl_table_delete(maskslits); \
00084 cpl_table_delete(idscoeff); \
00085 cpl_table_delete(restab); \
00086 cpl_table_delete(slits); \
00087 cpl_table_delete(polytraces); \
00088 cpl_vector_delete(lines); \
00089 cpl_propertylist_delete(header); \
00090 cpl_propertylist_delete(save_header); \
00091 cpl_msg_indent_less(); \
00092 return -1; \
00093 }
00094
00095 #define fors_wave_calib_exit_memcheck(message) \
00096 { \
00097 if ((const char *)message != NULL) cpl_msg_info(recipe, message); \
00098 printf("free spectra (%p)\n", spectra); \
00099 cpl_image_delete(spectra); \
00100 printf("free spatial (%p)\n", spatial); \
00101 cpl_image_delete(spatial); \
00102 printf("free rainbow (%p)\n", rainbow); \
00103 cpl_image_delete(rainbow); \
00104 printf("free residual (%p)\n", residual); \
00105 cpl_image_delete(residual); \
00106 printf("free rectified (%p)\n", rectified); \
00107 cpl_image_delete(rectified); \
00108 printf("free wavemap (%p)\n", wavemap); \
00109 cpl_image_delete(wavemap); \
00110 printf("free grism_table (%p)\n", grism_table); \
00111 cpl_table_delete(grism_table); \
00112 printf("free wavelengths (%p)\n", wavelengths); \
00113 cpl_table_delete(wavelengths); \
00114 printf("free maskslits (%p)\n", maskslits); \
00115 cpl_table_delete(maskslits); \
00116 printf("free idscoeff (%p)\n", idscoeff); \
00117 cpl_table_delete(idscoeff); \
00118 printf("free restab (%p)\n", restab); \
00119 cpl_table_delete(restab); \
00120 printf("free slits (%p)\n", slits); \
00121 cpl_table_delete(slits); \
00122 printf("free polytraces (%p)\n", polytraces); \
00123 cpl_table_delete(polytraces); \
00124 printf("free lines (%p)\n", lines); \
00125 cpl_vector_delete(lines); \
00126 printf("free header (%p)\n", header); \
00127 cpl_propertylist_delete(header); \
00128 printf("free save_header (%p)\n", save_header); \
00129 cpl_propertylist_delete(save_header); \
00130 cpl_msg_indent_less(); \
00131 return 0; \
00132 }
00133
00134
00146 int cpl_plugin_get_info(cpl_pluginlist *list)
00147 {
00148 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
00149 cpl_plugin *plugin = &recipe->interface;
00150
00151 cpl_plugin_init(plugin,
00152 CPL_PLUGIN_API,
00153 FORS_BINARY_VERSION,
00154 CPL_PLUGIN_TYPE_RECIPE,
00155 "fors_wave_calib",
00156 "Derive dispersion relation from rectified arc lamp frame",
00157 fors_wave_calib_description,
00158 "Carlo Izzo",
00159 PACKAGE_BUGREPORT,
00160 "This file is currently part of the FORS Instrument Pipeline\n"
00161 "Copyright (C) 2002-2010 European Southern Observatory\n\n"
00162 "This program is free software; you can redistribute it and/or modify\n"
00163 "it under the terms of the GNU General Public License as published by\n"
00164 "the Free Software Foundation; either version 2 of the License, or\n"
00165 "(at your option) any later version.\n\n"
00166 "This program is distributed in the hope that it will be useful,\n"
00167 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00168 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
00169 "GNU General Public License for more details.\n\n"
00170 "You should have received a copy of the GNU General Public License\n"
00171 "along with this program; if not, write to the Free Software Foundation,\n"
00172 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n",
00173 fors_wave_calib_create,
00174 fors_wave_calib_exec,
00175 fors_wave_calib_destroy);
00176
00177 cpl_pluginlist_append(list, plugin);
00178
00179 return 0;
00180 }
00181
00182
00193 static int fors_wave_calib_create(cpl_plugin *plugin)
00194 {
00195 cpl_recipe *recipe;
00196 cpl_parameter *p;
00197
00198
00199
00200
00201
00202 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00203 recipe = (cpl_recipe *)plugin;
00204 else
00205 return -1;
00206
00207
00208
00209
00210
00211 recipe->parameters = cpl_parameterlist_new();
00212
00213
00214
00215
00216
00217 p = cpl_parameter_new_value("fors.fors_wave_calib.dispersion",
00218 CPL_TYPE_DOUBLE,
00219 "Expected spectral dispersion (Angstrom/pixel)",
00220 "fors.fors_wave_calib",
00221 0.0);
00222 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
00223 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00224 cpl_parameterlist_append(recipe->parameters, p);
00225
00226
00227
00228
00229
00230 p = cpl_parameter_new_value("fors.fors_wave_calib.peakdetection",
00231 CPL_TYPE_DOUBLE,
00232 "Initial peak detection threshold (ADU)",
00233 "fors.fors_wave_calib",
00234 0.0);
00235 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "peakdetection");
00236 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00237 cpl_parameterlist_append(recipe->parameters, p);
00238
00239
00240
00241
00242
00243 p = cpl_parameter_new_value("fors.fors_wave_calib.wdegree",
00244 CPL_TYPE_INT,
00245 "Degree of wavelength calibration polynomial",
00246 "fors.fors_wave_calib",
00247 0);
00248 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wdegree");
00249 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00250 cpl_parameterlist_append(recipe->parameters, p);
00251
00252
00253
00254
00255
00256 p = cpl_parameter_new_value("fors.fors_wave_calib.wradius",
00257 CPL_TYPE_INT,
00258 "Search radius if iterating pattern-matching "
00259 "with first-guess method",
00260 "fors.fors_wave_calib",
00261 4);
00262 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wradius");
00263 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00264 cpl_parameterlist_append(recipe->parameters, p);
00265
00266
00267
00268
00269
00270 p = cpl_parameter_new_value("fors.fors_wave_calib.wreject",
00271 CPL_TYPE_DOUBLE,
00272 "Rejection threshold in dispersion "
00273 "relation fit (pixel)",
00274 "fors.fors_wave_calib",
00275 0.7);
00276 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wreject");
00277 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00278 cpl_parameterlist_append(recipe->parameters, p);
00279
00280
00281
00282
00283
00284 p = cpl_parameter_new_value("fors.fors_wave_calib.wcolumn",
00285 CPL_TYPE_STRING,
00286 "Name of line catalog table column "
00287 "with wavelengths",
00288 "fors.fors_wave_calib",
00289 "WLEN");
00290 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
00291 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00292 cpl_parameterlist_append(recipe->parameters, p);
00293
00294
00295
00296
00297
00298 p = cpl_parameter_new_value("fors.fors_wave_calib.startwavelength",
00299 CPL_TYPE_DOUBLE,
00300 "Start wavelength in spectral extraction",
00301 "fors.fors_wave_calib",
00302 0.0);
00303 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
00304 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00305 cpl_parameterlist_append(recipe->parameters, p);
00306
00307
00308
00309
00310
00311 p = cpl_parameter_new_value("fors.fors_wave_calib.endwavelength",
00312 CPL_TYPE_DOUBLE,
00313 "End wavelength in spectral extraction",
00314 "fors.fors_wave_calib",
00315 0.0);
00316 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
00317 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00318 cpl_parameterlist_append(recipe->parameters, p);
00319
00320 return 0;
00321 }
00322
00323
00332 static int fors_wave_calib_exec(cpl_plugin *plugin)
00333 {
00334 cpl_recipe *recipe;
00335
00336 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00337 recipe = (cpl_recipe *)plugin;
00338 else
00339 return -1;
00340
00341 return fors_wave_calib(recipe->parameters, recipe->frames);
00342 }
00343
00344
00353 static int fors_wave_calib_destroy(cpl_plugin *plugin)
00354 {
00355 cpl_recipe *recipe;
00356
00357 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00358 recipe = (cpl_recipe *)plugin;
00359 else
00360 return -1;
00361
00362 cpl_parameterlist_delete(recipe->parameters);
00363
00364 return 0;
00365 }
00366
00367
00377 static int fors_wave_calib(cpl_parameterlist *parlist,
00378 cpl_frameset *frameset)
00379 {
00380
00381 const char *recipe = "fors_wave_calib";
00382
00383
00384
00385
00386
00387
00388 double dispersion;
00389 double peakdetection;
00390 int wdegree;
00391 int wradius;
00392 double wreject;
00393 const char *wcolumn;
00394 double startwavelength;
00395 double endwavelength;
00396
00397
00398
00399
00400
00401 cpl_image *spectra = NULL;
00402 cpl_image *spatial = NULL;
00403 cpl_image *rectified = NULL;
00404 cpl_image *wavemap = NULL;
00405 cpl_image *rainbow = NULL;
00406 cpl_image *residual = NULL;
00407 cpl_image *bimage = NULL;
00408 cpl_table *grism_table = NULL;
00409 cpl_table *wavelengths = NULL;
00410 cpl_table *slits = NULL;
00411 cpl_table *polytraces = NULL;
00412 cpl_table *idscoeff = NULL;
00413 cpl_table *maskslits = NULL;
00414 cpl_table *restab = NULL;
00415 cpl_vector *lines = NULL;
00416 cpl_propertylist *header = NULL;
00417 cpl_propertylist *save_header = NULL;
00418
00419
00420
00421
00422
00423 char version[80];
00424 const char *arc_tag;
00425 const char *reduced_lamp_tag;
00426 const char *wavelength_map_tag;
00427 const char *spatial_map_tag;
00428 const char *disp_residuals_tag;
00429 const char *disp_coeff_tag;
00430 const char *curv_coeff_tag;
00431 const char *slit_location_tag;
00432 const char *spectral_resolution_tag;
00433 int lamp_mxu;
00434 int lamp_mos;
00435 int mos;
00436 int treat_as_lss = 0;
00437 double mean_rms;
00438 double mxpos;
00439 int narc, nref;
00440 int nlines;
00441 int rebin;
00442 double *line;
00443 double *fiterror = NULL;
00444 int *fitlines = NULL;
00445 int nx, ny;
00446 double reference;
00447 int i;
00448 int nslits_out_det = 0;
00449
00450
00451 char *instrume = NULL;
00452
00453
00454 cpl_msg_set_indentation(2);
00455
00456
00457
00458
00459
00460 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00461 cpl_msg_indent_more();
00462
00463 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00464 fors_wave_calib_exit("Too many in input: GRISM_TABLE");
00465
00466 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00467
00468 dispersion = dfs_get_parameter_double(parlist,
00469 "fors.fors_wave_calib.dispersion", grism_table);
00470
00471 if (dispersion <= 0.0)
00472 fors_wave_calib_exit("Invalid spectral dispersion value");
00473
00474 peakdetection = dfs_get_parameter_double(parlist,
00475 "fors.fors_wave_calib.peakdetection", grism_table);
00476 if (peakdetection <= 0.0)
00477 fors_wave_calib_exit("Invalid peak detection level");
00478
00479 wdegree = dfs_get_parameter_int(parlist,
00480 "fors.fors_wave_calib.wdegree", grism_table);
00481
00482 if (wdegree < 1)
00483 fors_wave_calib_exit("Invalid polynomial degree");
00484
00485 if (wdegree > 5)
00486 fors_wave_calib_exit("Max allowed polynomial degree is 5");
00487
00488 wradius = dfs_get_parameter_int(parlist,
00489 "fors.fors_wave_calib.wradius", NULL);
00490
00491 if (wradius < 0)
00492 fors_wave_calib_exit("Invalid search radius");
00493
00494 wreject = dfs_get_parameter_double(parlist,
00495 "fors.fors_wave_calib.wreject", NULL);
00496
00497 if (wreject <= 0.0)
00498 fors_wave_calib_exit("Invalid rejection threshold");
00499
00500 wcolumn = dfs_get_parameter_string(parlist,
00501 "fors.fors_wave_calib.wcolumn", NULL);
00502
00503 startwavelength = dfs_get_parameter_double(parlist,
00504 "fors.fors_wave_calib.startwavelength", grism_table);
00505 if (startwavelength > 1.0)
00506 if (startwavelength < 3000.0 || startwavelength > 13000.0)
00507 fors_wave_calib_exit("Invalid wavelength");
00508
00509 endwavelength = dfs_get_parameter_double(parlist,
00510 "fors.fors_wave_calib.endwavelength", grism_table);
00511 if (endwavelength > 1.0) {
00512 if (endwavelength < 3000.0 || endwavelength > 13000.0)
00513 fors_wave_calib_exit("Invalid wavelength");
00514 if (startwavelength < 1.0)
00515 fors_wave_calib_exit("Invalid wavelength interval");
00516 }
00517
00518 if (startwavelength > 1.0)
00519 if (endwavelength - startwavelength <= 0.0)
00520 fors_wave_calib_exit("Invalid wavelength interval");
00521
00522 cpl_table_delete(grism_table); grism_table = NULL;
00523
00524 if (cpl_error_get_code())
00525 fors_wave_calib_exit("Failure reading the configuration parameters");
00526
00527
00528 cpl_msg_indent_less();
00529 cpl_msg_info(recipe, "Check input set-of-frames:");
00530 cpl_msg_indent_more();
00531
00532 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0)
00533 fors_wave_calib_exit("Missing required input: MASTER_LINECAT");
00534
00535 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1)
00536 fors_wave_calib_exit("Too many in input: MASTER_LINECAT");
00537
00538 lamp_mxu = cpl_frameset_count_tags(frameset, "RECTIFIED_LAMP_MXU");
00539 lamp_mos = cpl_frameset_count_tags(frameset, "RECTIFIED_LAMP_MOS");
00540
00541 narc = lamp_mxu + lamp_mos;
00542
00543 if (narc == 0) {
00544 fors_wave_calib_exit("Missing input rectified arc lamp frame");
00545 }
00546 if (narc > 1) {
00547 cpl_msg_error(recipe, "Too many input rectified arc lamp frames "
00548 "(%d > 1)", narc);
00549 fors_wave_calib_exit(NULL);
00550 }
00551
00552 mos = 0;
00553
00554 if (lamp_mxu) {
00555 arc_tag = "RECTIFIED_LAMP_MXU";
00556 slit_location_tag = "SLIT_LOCATION_MXU";
00557 spatial_map_tag = "SPATIAL_MAP_MXU";
00558 reduced_lamp_tag = "REDUCED_LAMP_MXU";
00559 disp_residuals_tag = "DISP_RESIDUALS_MXU";
00560 disp_coeff_tag = "DISP_COEFF_MXU";
00561 curv_coeff_tag = "CURV_COEFF_MXU";
00562 wavelength_map_tag = "WAVELENGTH_MAP_MXU";
00563 spectral_resolution_tag = "SPECTRAL_RESOLUTION_MXU";
00564 }
00565 else if (lamp_mos) {
00566 mos = 1;
00567 arc_tag = "RECTIFIED_LAMP_MOS";
00568 slit_location_tag = "SLIT_LOCATION_MOS";
00569 spatial_map_tag = "SPATIAL_MAP_MOS";
00570 reduced_lamp_tag = "REDUCED_LAMP_MOS";
00571 disp_residuals_tag = "DISP_RESIDUALS_MOS";
00572 disp_coeff_tag = "DISP_COEFF_MOS";
00573 curv_coeff_tag = "CURV_COEFF_MXU";
00574 wavelength_map_tag = "WAVELENGTH_MAP_MOS";
00575 spectral_resolution_tag = "SPECTRAL_RESOLUTION_MOS";
00576 }
00577
00578
00579 nref = cpl_frameset_count_tags(frameset, spatial_map_tag);
00580
00581 if (nref == 0) {
00582 fors_wave_calib_exit("Missing input spatial map");
00583 }
00584 if (nref > 1) {
00585 cpl_msg_error(recipe, "Too many input spatial maps (%d > 1)", nref);
00586 fors_wave_calib_exit(NULL);
00587 }
00588
00589 nref = cpl_frameset_count_tags(frameset, slit_location_tag);
00590
00591 if (nref == 0) {
00592 fors_wave_calib_exit("Missing input slit location table");
00593 }
00594 if (nref > 1) {
00595 cpl_msg_error(recipe, "Too many input slit location tables (%d > 1)",
00596 nref);
00597 fors_wave_calib_exit(NULL);
00598 }
00599
00600 nref = cpl_frameset_count_tags(frameset, curv_coeff_tag);
00601
00602 if (nref == 0) {
00603 fors_wave_calib_exit("Missing input spectral curvature table");
00604 }
00605 if (nref > 1) {
00606 cpl_msg_error(recipe, "Too many input spectral curvature tables "
00607 "(%d > 1)", nref);
00608 fors_wave_calib_exit(NULL);
00609 }
00610
00611
00612 if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00613 cpl_msg_warning(cpl_func,"Input frames are not from the same grism");
00614
00615 if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00616 cpl_msg_warning(cpl_func,"Input frames are not from the same filter");
00617
00618 if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00619 cpl_msg_warning(cpl_func,"Input frames are not from the same chip");
00620
00621
00622
00623
00624
00625
00626
00627 header = dfs_load_header(frameset, spatial_map_tag, 0);
00628
00629 if (header == NULL)
00630 fors_wave_calib_exit("Cannot load arc lamp header");
00631
00632 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00633 if (instrume == NULL)
00634 fors_wave_calib_exit("Missing keyword INSTRUME in arc lamp header");
00635
00636 if (instrume[4] == '1')
00637 snprintf(version, 80, "%s/%s", "fors1", VERSION);
00638 if (instrume[4] == '2')
00639 snprintf(version, 80, "%s/%s", "fors2", VERSION);
00640
00641 reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
00642
00643 if (cpl_error_get_code() != CPL_ERROR_NONE)
00644 fors_wave_calib_exit("Missing keyword ESO INS GRIS1 WLEN "
00645 "in arc lamp frame header");
00646
00647 if (reference < 3000.0)
00648 reference *= 10;
00649
00650 if (reference < 3000.0 || reference > 13000.0) {
00651 cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
00652 "keyword ESO INS GRIS1 WLEN in arc lamp frame header",
00653 reference);
00654 fors_wave_calib_exit(NULL);
00655 }
00656
00657 cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
00658
00659 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
00660
00661 if (cpl_error_get_code() != CPL_ERROR_NONE)
00662 fors_wave_calib_exit("Missing keyword ESO DET WIN1 BINX "
00663 "in arc lamp frame header");
00664
00665 if (rebin != 1) {
00666 dispersion *= rebin;
00667 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
00668 "working dispersion used is %f A/pixel", rebin,
00669 dispersion);
00670 }
00671
00672
00673 cpl_msg_info(recipe, "Produce mask slit position table...");
00674
00675 if (mos)
00676 maskslits = mos_load_slits_fors_mos(header, &nslits_out_det);
00677 else
00678 maskslits = mos_load_slits_fors_mxu(header);
00679
00680
00681
00682
00683
00684
00685
00686 treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det);
00687
00688 cpl_table_delete(maskslits); maskslits = NULL;
00689
00690 if (treat_as_lss) {
00691 cpl_msg_error(recipe, "All slits have the same offset: %.2f mm\n"
00692 "The LSS data reduction strategy must be applied: "
00693 "please use recipe fors_wave_calib_lss", mxpos);
00694 fors_wave_calib_exit(NULL);
00695 }
00696
00697
00698 cpl_msg_indent_less();
00699 cpl_msg_info(recipe, "Load arc lamp exposure...");
00700 cpl_msg_indent_more();
00701
00702 spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0);
00703
00704 if (spectra == NULL)
00705 fors_wave_calib_exit("Cannot load arc lamp exposure");
00706
00707
00708 cpl_msg_indent_less();
00709 cpl_msg_info(recipe, "Load input line catalog...");
00710 cpl_msg_indent_more();
00711
00712 wavelengths = dfs_load_table(frameset, "MASTER_LINECAT", 1);
00713
00714 if (wavelengths == NULL)
00715 fors_wave_calib_exit("Cannot load line catalog");
00716
00717
00718
00719
00720
00721
00722 nlines = cpl_table_get_nrow(wavelengths);
00723
00724 if (nlines == 0)
00725 fors_wave_calib_exit("Empty input line catalog");
00726
00727 if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
00728 cpl_msg_error(recipe, "Missing column %s in input line catalog table",
00729 wcolumn);
00730 fors_wave_calib_exit(NULL);
00731 }
00732
00733 line = cpl_malloc(nlines * sizeof(double));
00734
00735 for (i = 0; i < nlines; i++)
00736 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
00737
00738 cpl_table_delete(wavelengths); wavelengths = NULL;
00739
00740 lines = cpl_vector_wrap(nlines, line);
00741
00742
00743 cpl_msg_indent_less();
00744 cpl_msg_info(recipe, "Load slit location table...");
00745 cpl_msg_indent_more();
00746
00747 slits = dfs_load_table(frameset, slit_location_tag, 1);
00748
00749 if (slits == NULL)
00750 fors_wave_calib_exit("Cannot load slit location table");
00751
00752
00753 cpl_msg_indent_less();
00754 cpl_msg_info(recipe, "Subtract background from input arc exposure...");
00755 cpl_msg_indent_more();
00756
00757 bimage = mos_arc_background(spectra, 15, 15);
00758 cpl_image_subtract(spectra, bimage);
00759 cpl_image_delete(bimage);
00760
00761
00762 cpl_msg_indent_less();
00763 cpl_msg_info(recipe, "Perform wavelength calibration...");
00764 cpl_msg_indent_more();
00765
00766 nx = cpl_image_get_size_x(spectra);
00767 ny = cpl_image_get_size_y(spectra);
00768
00769 idscoeff = cpl_table_new(ny);
00770 rainbow = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00771 residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00772 fiterror = cpl_calloc(ny, sizeof(double));
00773 fitlines = cpl_calloc(ny, sizeof(int));
00774
00775 rectified = mos_wavelength_calibration_final(spectra, slits, lines,
00776 dispersion, peakdetection,
00777 wradius, wdegree, wreject,
00778 reference, &startwavelength,
00779 &endwavelength, fitlines,
00780 fiterror, idscoeff, rainbow,
00781 residual, NULL, NULL);
00782
00783 cpl_image_delete(spectra); spectra = NULL;
00784
00785 if (rectified == NULL)
00786 fors_wave_calib_exit("Wavelength calibration failure");
00787
00788 save_header = cpl_propertylist_new();
00789 cpl_propertylist_update_double(save_header, "CRPIX1", 1.0);
00790 cpl_propertylist_update_double(save_header, "CRPIX2", 1.0);
00791 cpl_propertylist_update_double(save_header, "CRVAL1",
00792 startwavelength + dispersion/2);
00793 cpl_propertylist_update_double(save_header, "CRVAL2", 1.0);
00794
00795
00796 cpl_propertylist_update_double(save_header, "CD1_1", dispersion);
00797 cpl_propertylist_update_double(save_header, "CD1_2", 0.0);
00798 cpl_propertylist_update_double(save_header, "CD2_1", 0.0);
00799 cpl_propertylist_update_double(save_header, "CD2_2", 1.0);
00800 cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR");
00801 cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL");
00802 cpl_propertylist_update_int(save_header, "ESO PRO DATANCOM", 1);
00803
00804 if (dfs_save_image(frameset, rectified, reduced_lamp_tag, save_header,
00805 parlist, recipe, version))
00806 fors_wave_calib_exit(NULL);
00807
00808 cpl_propertylist_delete(save_header); save_header = NULL;
00809 save_header = cpl_propertylist_new();
00810
00811 cpl_propertylist_update_double(save_header, "CRPIX2", 1.0);
00812 cpl_propertylist_update_double(save_header, "CRVAL2", 1.0);
00813
00814 cpl_propertylist_update_double(save_header, "CD1_1", 1.0);
00815 cpl_propertylist_update_double(save_header, "CD1_2", 0.0);
00816 cpl_propertylist_update_double(save_header, "CD2_1", 0.0);
00817 cpl_propertylist_update_double(save_header, "CD2_2", 1.0);
00818 cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR");
00819 cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL");
00820
00821 if (dfs_save_image(frameset, residual, disp_residuals_tag, save_header,
00822 parlist, recipe, version))
00823 fors_wave_calib_exit(NULL);
00824
00825 cpl_propertylist_delete(save_header); save_header = NULL;
00826 cpl_image_delete(residual); residual = NULL;
00827
00828 cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL;
00829 cpl_table_set_column_unit(idscoeff, "error", "pixel");
00830 cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL;
00831
00832 for (i = 0; i < ny; i++)
00833 if (!cpl_table_is_valid(idscoeff, "c0", i))
00834 cpl_table_set_invalid(idscoeff, "error", i);
00835
00836 if (dfs_save_table(frameset, idscoeff, disp_coeff_tag, NULL,
00837 parlist, recipe, version))
00838 fors_wave_calib_exit(NULL);
00839
00840 mean_rms = mos_distortions_rms(rectified, lines, startwavelength,
00841 dispersion, 6, 0);
00842
00843 cpl_msg_info(recipe, "Mean residual: %f pixel", mean_rms);
00844
00845 mean_rms = cpl_table_get_column_mean(idscoeff, "error");
00846
00847 cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)",
00848 mean_rms, mean_rms * dispersion);
00849
00850 cpl_table_delete(idscoeff); idscoeff = NULL;
00851
00852
00853
00854
00855
00856 restab = mos_resolution_table(rectified, startwavelength, dispersion,
00857 60000, lines);
00858
00859 cpl_vector_delete(lines); lines = NULL;
00860 cpl_image_delete(rectified); rectified = NULL;
00861
00862 if (restab) {
00863 cpl_msg_info(recipe, "Mean spectral resolution: %.2f",
00864 cpl_table_get_column_mean(restab, "resolution"));
00865 cpl_msg_info(recipe, "Mean reference lines FWHM: %.2f +/- %.2f pixel",
00866 cpl_table_get_column_mean(restab, "fwhm") / dispersion,
00867 cpl_table_get_column_mean(restab, "fwhm_rms") / dispersion);
00868
00869 if (dfs_save_table(frameset, restab, spectral_resolution_tag, NULL,
00870 parlist, recipe, version))
00871 fors_wave_calib_exit(NULL);
00872
00873 cpl_table_delete(restab); restab = NULL;
00874 }
00875 else
00876 fors_wave_calib_exit("Cannot compute the spectral resolution table");
00877
00878
00879 cpl_msg_indent_less();
00880 cpl_msg_info(recipe, "Load spatial map image...");
00881 cpl_msg_indent_more();
00882
00883 spatial = dfs_load_image(frameset, spatial_map_tag, CPL_TYPE_FLOAT, 0, 0);
00884
00885 if (spatial == NULL)
00886 fors_wave_calib_exit("Cannot load spatial map");
00887
00888 cpl_msg_indent_less();
00889 cpl_msg_info(recipe, "Load spectral curvature table...");
00890 cpl_msg_indent_more();
00891
00892 polytraces = dfs_load_table(frameset, curv_coeff_tag, 1);
00893
00894 if (polytraces == NULL)
00895 fors_wave_calib_exit("Cannot load spectral curvature table");
00896
00897 wavemap = mos_map_wavelengths(spatial, rainbow, slits, polytraces,
00898 reference, startwavelength, endwavelength,
00899 dispersion);
00900
00901 cpl_image_delete(rainbow); rainbow = NULL;
00902 cpl_image_delete(spatial); spatial = NULL;
00903 cpl_table_delete(slits); slits = NULL;
00904 cpl_table_delete(polytraces); polytraces = NULL;
00905
00906 if (dfs_save_image(frameset, wavemap, wavelength_map_tag, header,
00907 parlist, recipe, version))
00908 fors_wave_calib_exit(NULL);
00909
00910 cpl_image_delete(wavemap); wavemap = NULL;
00911 cpl_propertylist_delete(header); header = NULL;
00912
00913 return 0;
00914 }