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 (message) 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 (message) 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 mxu, mos;
00429 int treat_as_lss = 0;
00430 int nslits;
00431 double *xpos;
00432 double mxpos;
00433 int narc;
00434 int nlines;
00435 int rebin;
00436 double *line;
00437 int nx, ny;
00438 double reference;
00439 int i;
00440
00441 char *instrume = NULL;
00442
00443
00444 cpl_msg_set_indentation(2);
00445
00446 if (dfs_files_dont_exist(frameset))
00447 fors_detect_spectra_exit(NULL);
00448
00449
00450
00451
00452
00453 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00454 cpl_msg_indent_more();
00455
00456 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00457 fors_detect_spectra_exit("Too many in input: GRISM_TABLE");
00458
00459 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00460
00461 dispersion = dfs_get_parameter_double(parlist,
00462 "fors.fors_detect_spectra.dispersion", grism_table);
00463
00464 if (dispersion <= 0.0)
00465 fors_detect_spectra_exit("Invalid spectral dispersion value");
00466
00467 peakdetection = dfs_get_parameter_double(parlist,
00468 "fors.fors_detect_spectra.peakdetection", grism_table);
00469 if (peakdetection <= 0.0)
00470 fors_detect_spectra_exit("Invalid peak detection level");
00471
00472 wdegree = dfs_get_parameter_int(parlist,
00473 "fors.fors_detect_spectra.wdegree", grism_table);
00474
00475 if (wdegree < 1)
00476 fors_detect_spectra_exit("Invalid polynomial degree");
00477
00478 if (wdegree > 5)
00479 fors_detect_spectra_exit("Max allowed polynomial degree is 5");
00480
00481 wradius = dfs_get_parameter_int(parlist,
00482 "fors.fors_detect_spectra.wradius", NULL);
00483
00484 if (wradius < 0)
00485 fors_detect_spectra_exit("Invalid search radius");
00486
00487 wreject = dfs_get_parameter_double(parlist,
00488 "fors.fors_detect_spectra.wreject", NULL);
00489
00490 if (wreject <= 0.0)
00491 fors_detect_spectra_exit("Invalid rejection threshold");
00492
00493 wcolumn = dfs_get_parameter_string(parlist,
00494 "fors.fors_detect_spectra.wcolumn", NULL);
00495
00496 startwavelength = dfs_get_parameter_double(parlist,
00497 "fors.fors_detect_spectra.startwavelength", grism_table);
00498 if (startwavelength > 1.0)
00499 if (startwavelength < 3000.0 || startwavelength > 13000.0)
00500 fors_detect_spectra_exit("Invalid wavelength");
00501
00502 endwavelength = dfs_get_parameter_double(parlist,
00503 "fors.fors_detect_spectra.endwavelength", grism_table);
00504 if (endwavelength > 1.0) {
00505 if (endwavelength < 3000.0 || endwavelength > 13000.0)
00506 fors_detect_spectra_exit("Invalid wavelength");
00507 if (startwavelength < 1.0)
00508 fors_detect_spectra_exit("Invalid wavelength interval");
00509 }
00510
00511 if (startwavelength > 1.0)
00512 if (endwavelength - startwavelength <= 0.0)
00513 fors_detect_spectra_exit("Invalid wavelength interval");
00514
00515 slit_ident = dfs_get_parameter_bool(parlist,
00516 "fors.fors_detect_spectra.slit_ident", NULL);
00517
00518 cpl_table_delete(grism_table); grism_table = NULL;
00519
00520 if (cpl_error_get_code())
00521 fors_detect_spectra_exit("Failure reading the "
00522 "configuration parameters");
00523
00524
00525 cpl_msg_indent_less();
00526 cpl_msg_info(recipe, "Check input set-of-frames:");
00527 cpl_msg_indent_more();
00528
00529 narc = lamp_mxu = cpl_frameset_count_tags(frameset, "LAMP_UNBIAS_MXU");
00530 narc += lamp_mos = cpl_frameset_count_tags(frameset, "LAMP_UNBIAS_MOS");
00531 narc += lamp_lss = cpl_frameset_count_tags(frameset, "LAMP_UNBIAS_LSS");
00532
00533 if (narc == 0) {
00534 fors_detect_spectra_exit("Missing input arc lamp frame");
00535 }
00536 if (narc > 1) {
00537 cpl_msg_error(recipe, "Too many input arc lamp frames (%d > 1)", narc);
00538 fors_detect_spectra_exit(NULL);
00539 }
00540
00541 mxu = mos = 0;
00542
00543 if (lamp_mxu) {
00544 mxu = 1;
00545 arc_tag = "LAMP_UNBIAS_MXU";
00546 spectra_detection_tag = "SPECTRA_DETECTION_MXU";
00547 slit_map_tag = "SLIT_MAP_MXU";
00548 slit_location_tag = "SLIT_LOCATION_DETECT_MXU";
00549 }
00550 else if (lamp_mos) {
00551 mos = 1;
00552 arc_tag = "LAMP_UNBIAS_MOS";
00553 spectra_detection_tag = "SPECTRA_DETECTION_MOS";
00554 slit_map_tag = "SLIT_MAP_MOS";
00555 slit_location_tag = "SLIT_LOCATION_DETECT_MOS";
00556 }
00557 else if (lamp_lss) {
00558 fors_detect_spectra_exit("Use recipe fors_wave_calib_lss "
00559 "for LSS data reduction");
00560 }
00561
00562
00563 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0)
00564 fors_detect_spectra_exit("Missing required input: MASTER_LINECAT");
00565
00566 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1)
00567 fors_detect_spectra_exit("Too many in input: MASTER_LINECAT");
00568
00569 if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00570 fors_detect_spectra_exit("Input frames are not from the same grism");
00571
00572 if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00573 fors_detect_spectra_exit("Input frames are not from the same filter");
00574
00575 if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00576 fors_detect_spectra_exit("Input frames are not from the same chip");
00577
00578
00579
00580
00581
00582
00583
00584 header = dfs_load_header(frameset, arc_tag, 0);
00585
00586 if (header == NULL)
00587 fors_detect_spectra_exit("Cannot load arc lamp header");
00588
00589 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00590 if (instrume == NULL)
00591 fors_detect_spectra_exit("Missing keyword INSTRUME in arc lamp header");
00592
00593 if (instrume[4] == '1')
00594 snprintf(version, 80, "%s/%s", "fors1", VERSION);
00595 if (instrume[4] == '2')
00596 snprintf(version, 80, "%s/%s", "fors2", VERSION);
00597
00598 reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
00599
00600 if (cpl_error_get_code() != CPL_ERROR_NONE)
00601 fors_detect_spectra_exit("Missing keyword ESO INS GRIS1 WLEN "
00602 "in arc lamp frame header");
00603
00604 if (reference < 3000.0)
00605 reference *= 10;
00606
00607 if (reference < 3000.0 || reference > 13000.0) {
00608 cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
00609 "keyword ESO INS GRIS1 WLEN in arc lamp frame header",
00610 reference);
00611 fors_detect_spectra_exit(NULL);
00612 }
00613
00614 cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
00615
00616 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
00617
00618 if (cpl_error_get_code() != CPL_ERROR_NONE)
00619 fors_detect_spectra_exit("Missing keyword ESO DET WIN1 BINX "
00620 "in arc lamp frame header");
00621
00622 if (rebin != 1) {
00623 dispersion *= rebin;
00624 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
00625 "working dispersion used is %f A/pixel", rebin,
00626 dispersion);
00627 }
00628
00629
00630 cpl_msg_info(recipe, "Produce mask slit position table...");
00631
00632 if (mos)
00633 maskslits = mos_load_slits_fors_mos(header);
00634 else
00635 maskslits = mos_load_slits_fors_mxu(header);
00636
00637 cpl_propertylist_delete(header); header = NULL;
00638
00639
00640
00641
00642
00643
00644
00645 mxpos = cpl_table_get_column_median(maskslits, "xtop");
00646 xpos = cpl_table_get_data_double(maskslits, "xtop");
00647 nslits = cpl_table_get_nrow(maskslits);
00648
00649 treat_as_lss = 1;
00650 for (i = 0; i < nslits; i++) {
00651 if (fabs(mxpos-xpos[i]) > 0.01) {
00652 treat_as_lss = 0;
00653 break;
00654 }
00655 }
00656
00657 if (treat_as_lss) {
00658 cpl_msg_error(recipe, "All slits have the same offset: %.2f mm\n"
00659 "The LSS data reduction strategy must be applied: "
00660 "please use recipe fors_wave_calib_lss", mxpos);
00661 fors_detect_spectra_exit(NULL);
00662 }
00663
00664 if (slit_ident == 0) {
00665 cpl_table_delete(maskslits); maskslits = NULL;
00666 }
00667
00668
00669 cpl_msg_indent_less();
00670 cpl_msg_info(recipe, "Load arc lamp exposure...");
00671 cpl_msg_indent_more();
00672
00673 spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0);
00674
00675 if (spectra == NULL)
00676 fors_detect_spectra_exit("Cannot load arc lamp exposure");
00677
00678
00679 cpl_msg_indent_less();
00680 cpl_msg_info(recipe, "Load input line catalog...");
00681 cpl_msg_indent_more();
00682
00683 wavelengths = dfs_load_table(frameset, "MASTER_LINECAT", 1);
00684
00685 if (wavelengths == NULL)
00686 fors_detect_spectra_exit("Cannot load line catalog");
00687
00688
00689
00690
00691
00692
00693 nlines = cpl_table_get_nrow(wavelengths);
00694
00695 if (nlines == 0)
00696 fors_detect_spectra_exit("Empty input line catalog");
00697
00698 if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
00699 cpl_msg_error(recipe, "Missing column %s in input line catalog table",
00700 wcolumn);
00701 fors_detect_spectra_exit(NULL);
00702 }
00703
00704 line = cpl_malloc(nlines * sizeof(double));
00705
00706 for (i = 0; i < nlines; i++)
00707 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
00708
00709 cpl_table_delete(wavelengths); wavelengths = NULL;
00710
00711 lines = cpl_vector_wrap(nlines, line);
00712
00713
00714 cpl_msg_indent_less();
00715 cpl_msg_info(recipe, "Detecting spectra on CCD...");
00716 cpl_msg_indent_more();
00717
00718 nx = cpl_image_get_size_x(spectra);
00719 ny = cpl_image_get_size_y(spectra);
00720
00721 refmask = cpl_mask_new(nx, ny);
00722
00723 if (mos_saturation_process(spectra))
00724 fors_detect_spectra_exit("Cannot process saturation");
00725
00726 if (mos_subtract_background(spectra))
00727 fors_detect_spectra_exit("Cannot subtract the background");
00728
00729 checkwave = mos_wavelength_calibration_raw(spectra, lines, dispersion,
00730 peakdetection, wradius,
00731 wdegree, wreject, reference,
00732 &startwavelength, &endwavelength,
00733 NULL, NULL, NULL, NULL, NULL,
00734 NULL, refmask);
00735
00736 cpl_image_delete(spectra); spectra = NULL;
00737 cpl_vector_delete(lines); lines = NULL;
00738
00739 if (checkwave == NULL)
00740 fors_detect_spectra_exit("Wavelength calibration failure.");
00741
00742
00743
00744
00745
00746
00747 header = cpl_propertylist_new();
00748 cpl_propertylist_update_double(header, "CRPIX1", 1.0);
00749 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
00750 cpl_propertylist_update_double(header, "CRVAL1",
00751 startwavelength + dispersion/2);
00752 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
00753
00754
00755 cpl_propertylist_update_double(header, "CD1_1", dispersion);
00756 cpl_propertylist_update_double(header, "CD1_2", 0.0);
00757 cpl_propertylist_update_double(header, "CD2_1", 0.0);
00758 cpl_propertylist_update_double(header, "CD2_2", 1.0);
00759 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
00760 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
00761
00762 if (dfs_save_image(frameset, checkwave, spectra_detection_tag, header,
00763 parlist, recipe, version))
00764 fors_detect_spectra_exit(NULL);
00765
00766 cpl_image_delete(checkwave); checkwave = NULL;
00767 cpl_propertylist_delete(header); header = NULL;
00768
00769
00770 cpl_msg_info(recipe, "Locate slits at reference wavelength on CCD...");
00771 slits = mos_locate_spectra(refmask);
00772
00773 if (!slits) {
00774 cpl_msg_error(cpl_error_get_where(), cpl_error_get_message());
00775 fors_detect_spectra_exit("No slits could be detected!");
00776 }
00777
00778 refimage = cpl_image_new_from_mask(refmask);
00779 cpl_mask_delete(refmask); refmask = NULL;
00780
00781 header = dfs_load_header(frameset, arc_tag, 0);
00782 if (dfs_save_image(frameset, refimage, slit_map_tag, header,
00783 parlist, recipe, version))
00784 fors_detect_spectra_exit(NULL);
00785 cpl_propertylist_delete(header); header = NULL;
00786
00787 cpl_image_delete(refimage); refimage = NULL;
00788
00789 if (slit_ident) {
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805 cpl_msg_indent_less();
00806 cpl_msg_info(recipe, "Attempt slit identification (optional)...");
00807 cpl_msg_indent_more();
00808
00809 positions = mos_identify_slits(slits, maskslits, NULL);
00810 cpl_table_delete(maskslits); maskslits = NULL;
00811
00812 if (positions) {
00813 cpl_table_delete(slits);
00814 slits = positions;
00815
00816
00817
00818
00819
00820 cpl_table_and_selected_double(slits,
00821 "ybottom", CPL_GREATER_THAN, ny-1);
00822 cpl_table_or_selected_double(slits,
00823 "ytop", CPL_LESS_THAN, 0);
00824 cpl_table_erase_selected(slits);
00825
00826 nslits = cpl_table_get_nrow(slits);
00827
00828 if (nslits == 0)
00829 fors_detect_spectra_exit("No slits found on the CCD");
00830
00831 cpl_msg_info(recipe, "%d slits are entirely or partially "
00832 "contained in CCD", nslits);
00833
00834 }
00835 else {
00836 slit_ident = 0;
00837 cpl_msg_info(recipe, "Global distortion model cannot be computed");
00838 if (cpl_error_get_code() != CPL_ERROR_NONE) {
00839 fors_detect_spectra_exit(NULL);
00840 }
00841 }
00842 }
00843
00844 if (dfs_save_table(frameset, slits, slit_location_tag, NULL,
00845 parlist, recipe, version))
00846 fors_detect_spectra_exit(NULL);
00847
00848 cpl_table_delete(slits); slits = NULL;
00849
00850 return 0;
00851 }