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_detect_spectra_create(cpl_plugin *);
00038 static int fors_detect_spectra_exec(cpl_plugin *);
00039 static int fors_detect_spectra_destroy(cpl_plugin *);
00040 static int fors_detect_spectra(cpl_parameterlist *, cpl_frameset *);
00041
00042 static char fors_detect_spectra_description[] =
00043 "This recipe is used to detect and locate MOS/MXU slit spectra on the CCD,\n"
00044 "applying a pattern-matching algorithm. The input spectral exposure must\n"
00045 "contain spectra with the dispersion direction approximately horizontal,\n"
00046 "with blue on the left and red on the right. Use recipe fors_wave_calib_lss\n"
00047 "for LSS data, or for MOS/MXU data where all slits have the same offset.\n"
00048 "\n"
00049 "The rows of the input spectral exposure are processed separately, one\n"
00050 "by one. First, the background continuum is removed. Second, a list of\n"
00051 "positions of reference lines candidates is created. Only peaks above a\n"
00052 "given threshold (specified by the parameter --peakdetection) are selected.\n"
00053 "Third, the pattern-matching task selects from the found peaks the ones\n"
00054 "corresponding to the reference lines, listed in the input line catalog,\n"
00055 "associating them to the appropriate wavelengths. The ensuing polynomial\n"
00056 "fit is used to locate the central wavelength of the applied grism along\n"
00057 "each image row. The contributions from all rows form an image of the\n"
00058 "location of all spectra, that can be used as a starting point for the\n"
00059 "proper modeling of the optical and spectral distortions. For more details\n"
00060 "on this reduction strategy please refer to the FORS Pipeline User's Manual.\n"
00061 "\n"
00062 "Note that specifying an input GRISM_TABLE will set some of the recipe\n"
00063 "configuration parameters to default values valid for a particular grism.\n"
00064 "Again, see the pipeline manual for more details.\n"
00065 "\n"
00066 "In the table below the MXU acronym can be alternatively read as MOS.\n\n"
00067 "Input files:\n\n"
00068 " DO category: Type: Explanation: Required:\n"
00069 " LAMP_UNBIAS_MXU Calib Bias subtracted arc Y\n"
00070 " MASTER_LINECAT Calib Line catalog Y\n"
00071 " GRISM_TABLE Calib Grism table .\n\n"
00072 "Output files:\n\n"
00073 " DO category: Data type: Explanation:\n"
00074 " SLIT_MAP_MXU FITS image Map of central wavelength on CCD\n"
00075 " SLIT_LOCATION_DETECT_MXU FITS table Slits positions on CCD\n"
00076 " SPECTRA_DETECTION_MXU FITS image Check of preliminary detection\n\n";
00077
00078 #define fors_detect_spectra_exit(message) \
00079 { \
00080 if ((const char *)message != NULL) cpl_msg_error(recipe, message); \
00081 cpl_image_delete(spectra); \
00082 cpl_image_delete(checkwave); \
00083 cpl_image_delete(refimage); \
00084 cpl_mask_delete(refmask); \
00085 cpl_table_delete(grism_table); \
00086 cpl_table_delete(wavelengths); \
00087 cpl_table_delete(maskslits); \
00088 cpl_table_delete(slits); \
00089 cpl_vector_delete(lines); \
00090 cpl_propertylist_delete(header); \
00091 cpl_msg_indent_less(); \
00092 return -1; \
00093 }
00094
00095 #define fors_detect_spectra_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 checkwave (%p)\n", checkwave); \
00101 cpl_image_delete(checkwave); \
00102 printf("free refimage (%p)\n", refimage); \
00103 cpl_image_delete(refimage); \
00104 printf("free refmask (%p)\n", refmask); \
00105 cpl_mask_delete(refmask); \
00106 printf("free grism_table (%p)\n", grism_table); \
00107 cpl_table_delete(grism_table); \
00108 printf("free wavelengths (%p)\n", wavelengths); \
00109 cpl_table_delete(wavelengths); \
00110 printf("free maskslits (%p)\n", maskslits); \
00111 cpl_table_delete(maskslits); \
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 cpl_msg_indent_less(); \
00119 return 0; \
00120 }
00121
00122
00134 int cpl_plugin_get_info(cpl_pluginlist *list)
00135 {
00136 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
00137 cpl_plugin *plugin = &recipe->interface;
00138
00139 cpl_plugin_init(plugin,
00140 CPL_PLUGIN_API,
00141 FORS_BINARY_VERSION,
00142 CPL_PLUGIN_TYPE_RECIPE,
00143 "fors_detect_spectra",
00144 "Detect MOS/MXU spectra on CCD",
00145 fors_detect_spectra_description,
00146 "Carlo Izzo",
00147 PACKAGE_BUGREPORT,
00148 "This file is currently part of the FORS Instrument Pipeline\n"
00149 "Copyright (C) 2002-2010 European Southern Observatory\n\n"
00150 "This program is free software; you can redistribute it and/or modify\n"
00151 "it under the terms of the GNU General Public License as published by\n"
00152 "the Free Software Foundation; either version 2 of the License, or\n"
00153 "(at your option) any later version.\n\n"
00154 "This program is distributed in the hope that it will be useful,\n"
00155 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00156 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
00157 "GNU General Public License for more details.\n\n"
00158 "You should have received a copy of the GNU General Public License\n"
00159 "along with this program; if not, write to the Free Software Foundation,\n"
00160 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n",
00161 fors_detect_spectra_create,
00162 fors_detect_spectra_exec,
00163 fors_detect_spectra_destroy);
00164
00165 cpl_pluginlist_append(list, plugin);
00166
00167 return 0;
00168 }
00169
00170
00181 static int fors_detect_spectra_create(cpl_plugin *plugin)
00182 {
00183 cpl_recipe *recipe;
00184 cpl_parameter *p;
00185
00186
00187
00188
00189
00190 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00191 recipe = (cpl_recipe *)plugin;
00192 else
00193 return -1;
00194
00195
00196
00197
00198
00199 recipe->parameters = cpl_parameterlist_new();
00200
00201
00202
00203
00204
00205 p = cpl_parameter_new_value("fors.fors_detect_spectra.dispersion",
00206 CPL_TYPE_DOUBLE,
00207 "Expected spectral dispersion (Angstrom/pixel)",
00208 "fors.fors_detect_spectra",
00209 0.0);
00210 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
00211 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00212 cpl_parameterlist_append(recipe->parameters, p);
00213
00214
00215
00216
00217
00218 p = cpl_parameter_new_value("fors.fors_detect_spectra.peakdetection",
00219 CPL_TYPE_DOUBLE,
00220 "Initial peak detection threshold (ADU)",
00221 "fors.fors_detect_spectra",
00222 0.0);
00223 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "peakdetection");
00224 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00225 cpl_parameterlist_append(recipe->parameters, p);
00226
00227
00228
00229
00230
00231 p = cpl_parameter_new_value("fors.fors_detect_spectra.wdegree",
00232 CPL_TYPE_INT,
00233 "Degree of wavelength calibration polynomial",
00234 "fors.fors_detect_spectra",
00235 0);
00236 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wdegree");
00237 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00238 cpl_parameterlist_append(recipe->parameters, p);
00239
00240
00241
00242
00243
00244 p = cpl_parameter_new_value("fors.fors_detect_spectra.wradius",
00245 CPL_TYPE_INT,
00246 "Search radius if iterating pattern-matching "
00247 "with first-guess method",
00248 "fors.fors_detect_spectra",
00249 4);
00250 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wradius");
00251 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00252 cpl_parameterlist_append(recipe->parameters, p);
00253
00254
00255
00256
00257
00258 p = cpl_parameter_new_value("fors.fors_detect_spectra.wreject",
00259 CPL_TYPE_DOUBLE,
00260 "Rejection threshold in dispersion "
00261 "relation fit (pixel)",
00262 "fors.fors_detect_spectra",
00263 0.7);
00264 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wreject");
00265 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00266 cpl_parameterlist_append(recipe->parameters, p);
00267
00268
00269
00270
00271
00272 p = cpl_parameter_new_value("fors.fors_detect_spectra.wcolumn",
00273 CPL_TYPE_STRING,
00274 "Name of line catalog table column "
00275 "with wavelengths",
00276 "fors.fors_detect_spectra",
00277 "WLEN");
00278 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
00279 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00280 cpl_parameterlist_append(recipe->parameters, p);
00281
00282
00283
00284
00285
00286 p = cpl_parameter_new_value("fors.fors_detect_spectra.startwavelength",
00287 CPL_TYPE_DOUBLE,
00288 "Start wavelength in spectral extraction",
00289 "fors.fors_detect_spectra",
00290 0.0);
00291 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
00292 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00293 cpl_parameterlist_append(recipe->parameters, p);
00294
00295
00296
00297
00298
00299 p = cpl_parameter_new_value("fors.fors_detect_spectra.endwavelength",
00300 CPL_TYPE_DOUBLE,
00301 "End wavelength in spectral extraction",
00302 "fors.fors_detect_spectra",
00303 0.0);
00304 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
00305 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00306 cpl_parameterlist_append(recipe->parameters, p);
00307
00308
00309
00310
00311
00312 p = cpl_parameter_new_value("fors.fors_detect_spectra.slit_ident",
00313 CPL_TYPE_BOOL,
00314 "Attempt slit identification for MOS or MXU",
00315 "fors.fors_detect_spectra",
00316 TRUE);
00317 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "slit_ident");
00318 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00319 cpl_parameterlist_append(recipe->parameters, p);
00320
00321
00322 return 0;
00323 }
00324
00325
00334 static int fors_detect_spectra_exec(cpl_plugin *plugin)
00335 {
00336 cpl_recipe *recipe;
00337
00338 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00339 recipe = (cpl_recipe *)plugin;
00340 else
00341 return -1;
00342
00343 return fors_detect_spectra(recipe->parameters, recipe->frames);
00344 }
00345
00346
00355 static int fors_detect_spectra_destroy(cpl_plugin *plugin)
00356 {
00357 cpl_recipe *recipe;
00358
00359 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00360 recipe = (cpl_recipe *)plugin;
00361 else
00362 return -1;
00363
00364 cpl_parameterlist_delete(recipe->parameters);
00365
00366 return 0;
00367 }
00368
00369
00379 static int fors_detect_spectra(cpl_parameterlist *parlist,
00380 cpl_frameset *frameset)
00381 {
00382
00383 const char *recipe = "fors_detect_spectra";
00384
00385
00386
00387
00388
00389
00390 double dispersion;
00391 double peakdetection;
00392 int wdegree;
00393 int wradius;
00394 double wreject;
00395 const char *wcolumn;
00396 double startwavelength;
00397 double endwavelength;
00398 int slit_ident;
00399
00400
00401
00402
00403
00404 cpl_image *spectra = NULL;
00405 cpl_image *checkwave = NULL;
00406 cpl_image *refimage = NULL;
00407 cpl_mask *refmask = NULL;
00408 cpl_table *grism_table = NULL;
00409 cpl_table *wavelengths = NULL;
00410 cpl_table *slits = NULL;
00411 cpl_table *positions = NULL;
00412 cpl_table *maskslits = NULL;
00413 cpl_vector *lines = NULL;
00414 cpl_propertylist *header = NULL;
00415
00416
00417
00418
00419
00420 char version[80];
00421 const char *arc_tag;
00422 const char *spectra_detection_tag;
00423 const char *slit_map_tag;
00424 const char *slit_location_tag;
00425 int lamp_mxu;
00426 int lamp_mos;
00427 int lamp_lss;
00428 int mos;
00429 int treat_as_lss = 0;
00430 int nslits;
00431 double mxpos;
00432 int narc;
00433 int nlines;
00434 int rebin;
00435 double *line;
00436 int nx, ny;
00437 double reference;
00438 int i;
00439 int nslits_out_det = 0;
00440
00441 char *instrume = NULL;
00442
00443
00444 cpl_msg_set_indentation(2);
00445
00446
00447
00448
00449
00450 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00451 cpl_msg_indent_more();
00452
00453 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00454 fors_detect_spectra_exit("Too many in input: GRISM_TABLE");
00455
00456 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00457
00458 dispersion = dfs_get_parameter_double(parlist,
00459 "fors.fors_detect_spectra.dispersion", grism_table);
00460
00461 if (dispersion <= 0.0)
00462 fors_detect_spectra_exit("Invalid spectral dispersion value");
00463
00464 peakdetection = dfs_get_parameter_double(parlist,
00465 "fors.fors_detect_spectra.peakdetection", grism_table);
00466 if (peakdetection <= 0.0)
00467 fors_detect_spectra_exit("Invalid peak detection level");
00468
00469 wdegree = dfs_get_parameter_int(parlist,
00470 "fors.fors_detect_spectra.wdegree", grism_table);
00471
00472 if (wdegree < 1)
00473 fors_detect_spectra_exit("Invalid polynomial degree");
00474
00475 if (wdegree > 5)
00476 fors_detect_spectra_exit("Max allowed polynomial degree is 5");
00477
00478 wradius = dfs_get_parameter_int(parlist,
00479 "fors.fors_detect_spectra.wradius", NULL);
00480
00481 if (wradius < 0)
00482 fors_detect_spectra_exit("Invalid search radius");
00483
00484 wreject = dfs_get_parameter_double(parlist,
00485 "fors.fors_detect_spectra.wreject", NULL);
00486
00487 if (wreject <= 0.0)
00488 fors_detect_spectra_exit("Invalid rejection threshold");
00489
00490 wcolumn = dfs_get_parameter_string(parlist,
00491 "fors.fors_detect_spectra.wcolumn", NULL);
00492
00493 startwavelength = dfs_get_parameter_double(parlist,
00494 "fors.fors_detect_spectra.startwavelength", grism_table);
00495 if (startwavelength > 1.0)
00496 if (startwavelength < 3000.0 || startwavelength > 13000.0)
00497 fors_detect_spectra_exit("Invalid wavelength");
00498
00499 endwavelength = dfs_get_parameter_double(parlist,
00500 "fors.fors_detect_spectra.endwavelength", grism_table);
00501 if (endwavelength > 1.0) {
00502 if (endwavelength < 3000.0 || endwavelength > 13000.0)
00503 fors_detect_spectra_exit("Invalid wavelength");
00504 if (startwavelength < 1.0)
00505 fors_detect_spectra_exit("Invalid wavelength interval");
00506 }
00507
00508 if (startwavelength > 1.0)
00509 if (endwavelength - startwavelength <= 0.0)
00510 fors_detect_spectra_exit("Invalid wavelength interval");
00511
00512 slit_ident = dfs_get_parameter_bool(parlist,
00513 "fors.fors_detect_spectra.slit_ident", NULL);
00514
00515 cpl_table_delete(grism_table); grism_table = NULL;
00516
00517 if (cpl_error_get_code())
00518 fors_detect_spectra_exit("Failure reading the "
00519 "configuration parameters");
00520
00521
00522 cpl_msg_indent_less();
00523 cpl_msg_info(recipe, "Check input set-of-frames:");
00524 cpl_msg_indent_more();
00525
00526 narc = lamp_mxu = cpl_frameset_count_tags(frameset, "LAMP_UNBIAS_MXU");
00527 narc += lamp_mos = cpl_frameset_count_tags(frameset, "LAMP_UNBIAS_MOS");
00528 narc += lamp_lss = cpl_frameset_count_tags(frameset, "LAMP_UNBIAS_LSS");
00529
00530 if (narc == 0) {
00531 fors_detect_spectra_exit("Missing input arc lamp frame");
00532 }
00533 if (narc > 1) {
00534 cpl_msg_error(recipe, "Too many input arc lamp frames (%d > 1)", narc);
00535 fors_detect_spectra_exit(NULL);
00536 }
00537
00538 mos = 0;
00539
00540 if (lamp_mxu) {
00541 arc_tag = "LAMP_UNBIAS_MXU";
00542 spectra_detection_tag = "SPECTRA_DETECTION_MXU";
00543 slit_map_tag = "SLIT_MAP_MXU";
00544 slit_location_tag = "SLIT_LOCATION_DETECT_MXU";
00545 }
00546 else if (lamp_mos) {
00547 mos = 1;
00548 arc_tag = "LAMP_UNBIAS_MOS";
00549 spectra_detection_tag = "SPECTRA_DETECTION_MOS";
00550 slit_map_tag = "SLIT_MAP_MOS";
00551 slit_location_tag = "SLIT_LOCATION_DETECT_MOS";
00552 }
00553 else if (lamp_lss) {
00554 fors_detect_spectra_exit("Use recipe fors_wave_calib_lss "
00555 "for LSS data reduction");
00556 }
00557
00558
00559 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0)
00560 fors_detect_spectra_exit("Missing required input: MASTER_LINECAT");
00561
00562 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1)
00563 fors_detect_spectra_exit("Too many in input: MASTER_LINECAT");
00564
00565 if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00566 cpl_msg_warning(cpl_func,"Input frames are not from the same grism");
00567
00568 if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00569 cpl_msg_warning(cpl_func,"Input frames are not from the same filter");
00570
00571 if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00572 cpl_msg_warning(cpl_func,"Input frames are not from the same chip");
00573
00574
00575
00576
00577
00578
00579
00580 header = dfs_load_header(frameset, arc_tag, 0);
00581
00582 if (header == NULL)
00583 fors_detect_spectra_exit("Cannot load arc lamp header");
00584
00585 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00586 if (instrume == NULL)
00587 fors_detect_spectra_exit("Missing keyword INSTRUME in arc lamp header");
00588
00589 if (instrume[4] == '1')
00590 snprintf(version, 80, "%s/%s", "fors1", VERSION);
00591 if (instrume[4] == '2')
00592 snprintf(version, 80, "%s/%s", "fors2", VERSION);
00593
00594 reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
00595
00596 if (cpl_error_get_code() != CPL_ERROR_NONE)
00597 fors_detect_spectra_exit("Missing keyword ESO INS GRIS1 WLEN "
00598 "in arc lamp frame header");
00599
00600 if (reference < 3000.0)
00601 reference *= 10;
00602
00603 if (reference < 3000.0 || reference > 13000.0) {
00604 cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
00605 "keyword ESO INS GRIS1 WLEN in arc lamp frame header",
00606 reference);
00607 fors_detect_spectra_exit(NULL);
00608 }
00609
00610 cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
00611
00612 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
00613
00614 if (cpl_error_get_code() != CPL_ERROR_NONE)
00615 fors_detect_spectra_exit("Missing keyword ESO DET WIN1 BINX "
00616 "in arc lamp frame header");
00617
00618 if (rebin != 1) {
00619 dispersion *= rebin;
00620 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
00621 "working dispersion used is %f A/pixel", rebin,
00622 dispersion);
00623 }
00624
00625
00626 cpl_msg_info(recipe, "Produce mask slit position table...");
00627
00628 if (mos)
00629 maskslits = mos_load_slits_fors_mos(header, &nslits_out_det);
00630 else
00631 maskslits = mos_load_slits_fors_mxu(header);
00632
00633 cpl_propertylist_delete(header); header = NULL;
00634
00635
00636
00637
00638
00639
00640
00641 treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det);
00642
00643 if (treat_as_lss) {
00644 cpl_msg_error(recipe, "All slits have the same offset: %.2f mm\n"
00645 "The LSS data reduction strategy must be applied: "
00646 "please use recipe fors_wave_calib_lss", mxpos);
00647 fors_detect_spectra_exit(NULL);
00648 }
00649
00650 if (slit_ident == 0) {
00651 cpl_table_delete(maskslits); maskslits = NULL;
00652 }
00653
00654
00655 cpl_msg_indent_less();
00656 cpl_msg_info(recipe, "Load arc lamp exposure...");
00657 cpl_msg_indent_more();
00658
00659 spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0);
00660
00661 if (spectra == NULL)
00662 fors_detect_spectra_exit("Cannot load arc lamp exposure");
00663
00664
00665 cpl_msg_indent_less();
00666 cpl_msg_info(recipe, "Load input line catalog...");
00667 cpl_msg_indent_more();
00668
00669 wavelengths = dfs_load_table(frameset, "MASTER_LINECAT", 1);
00670
00671 if (wavelengths == NULL)
00672 fors_detect_spectra_exit("Cannot load line catalog");
00673
00674
00675
00676
00677
00678
00679 nlines = cpl_table_get_nrow(wavelengths);
00680
00681 if (nlines == 0)
00682 fors_detect_spectra_exit("Empty input line catalog");
00683
00684 if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
00685 cpl_msg_error(recipe, "Missing column %s in input line catalog table",
00686 wcolumn);
00687 fors_detect_spectra_exit(NULL);
00688 }
00689
00690 line = cpl_malloc(nlines * sizeof(double));
00691
00692 for (i = 0; i < nlines; i++)
00693 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
00694
00695 cpl_table_delete(wavelengths); wavelengths = NULL;
00696
00697 lines = cpl_vector_wrap(nlines, line);
00698
00699
00700 cpl_msg_indent_less();
00701 cpl_msg_info(recipe, "Detecting spectra on CCD...");
00702 cpl_msg_indent_more();
00703
00704 nx = cpl_image_get_size_x(spectra);
00705 ny = cpl_image_get_size_y(spectra);
00706
00707 refmask = cpl_mask_new(nx, ny);
00708
00709 if (mos_saturation_process(spectra))
00710 fors_detect_spectra_exit("Cannot process saturation");
00711
00712 if (mos_subtract_background(spectra))
00713 fors_detect_spectra_exit("Cannot subtract the background");
00714
00715 checkwave = mos_wavelength_calibration_raw(spectra, lines, dispersion,
00716 peakdetection, wradius,
00717 wdegree, wreject, reference,
00718 &startwavelength, &endwavelength,
00719 NULL, NULL, NULL, NULL, NULL,
00720 NULL, refmask, NULL);
00721
00722 cpl_image_delete(spectra); spectra = NULL;
00723 cpl_vector_delete(lines); lines = NULL;
00724
00725 if (checkwave == NULL)
00726 fors_detect_spectra_exit("Wavelength calibration failure.");
00727
00728
00729
00730
00731
00732
00733 header = cpl_propertylist_new();
00734 cpl_propertylist_update_double(header, "CRPIX1", 1.0);
00735 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
00736 cpl_propertylist_update_double(header, "CRVAL1",
00737 startwavelength + dispersion/2);
00738 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
00739
00740
00741 cpl_propertylist_update_double(header, "CD1_1", dispersion);
00742 cpl_propertylist_update_double(header, "CD1_2", 0.0);
00743 cpl_propertylist_update_double(header, "CD2_1", 0.0);
00744 cpl_propertylist_update_double(header, "CD2_2", 1.0);
00745 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
00746 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
00747
00748 if (dfs_save_image(frameset, checkwave, spectra_detection_tag, header,
00749 parlist, recipe, version))
00750 fors_detect_spectra_exit(NULL);
00751
00752 cpl_image_delete(checkwave); checkwave = NULL;
00753 cpl_propertylist_delete(header); header = NULL;
00754
00755
00756 cpl_msg_info(recipe, "Locate slits at reference wavelength on CCD...");
00757 slits = mos_locate_spectra(refmask);
00758
00759 if (!slits) {
00760 cpl_msg_error(cpl_error_get_where(), "%s", cpl_error_get_message());
00761 fors_detect_spectra_exit("No slits could be detected!");
00762 }
00763
00764 refimage = cpl_image_new_from_mask(refmask);
00765 cpl_mask_delete(refmask); refmask = NULL;
00766
00767 header = dfs_load_header(frameset, arc_tag, 0);
00768 if (dfs_save_image(frameset, refimage, slit_map_tag, header,
00769 parlist, recipe, version))
00770 fors_detect_spectra_exit(NULL);
00771 cpl_propertylist_delete(header); header = NULL;
00772
00773 cpl_image_delete(refimage); refimage = NULL;
00774
00775 if (slit_ident) {
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791 cpl_msg_indent_less();
00792 cpl_msg_info(recipe, "Attempt slit identification (optional)...");
00793 cpl_msg_indent_more();
00794
00795 positions = mos_identify_slits(slits, maskslits, NULL);
00796 cpl_table_delete(maskslits); maskslits = NULL;
00797
00798 if (positions) {
00799 cpl_table_delete(slits);
00800 slits = positions;
00801
00802
00803
00804
00805
00806 cpl_table_and_selected_double(slits,
00807 "ybottom", CPL_GREATER_THAN, ny-1);
00808 cpl_table_or_selected_double(slits,
00809 "ytop", CPL_LESS_THAN, 0);
00810 cpl_table_erase_selected(slits);
00811
00812 nslits = cpl_table_get_nrow(slits);
00813
00814 if (nslits == 0)
00815 fors_detect_spectra_exit("No slits found on the CCD");
00816
00817 cpl_msg_info(recipe, "%d slits are entirely or partially "
00818 "contained in CCD", nslits);
00819
00820 }
00821 else {
00822 slit_ident = 0;
00823 cpl_msg_info(recipe, "Global distortion model cannot be computed");
00824 if (cpl_error_get_code() != CPL_ERROR_NONE) {
00825 fors_detect_spectra_exit(NULL);
00826 }
00827 }
00828 }
00829
00830 if (dfs_save_table(frameset, slits, slit_location_tag, NULL,
00831 parlist, recipe, version))
00832 fors_detect_spectra_exit(NULL);
00833
00834 cpl_table_delete(slits); slits = NULL;
00835
00836 return 0;
00837 }