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