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_trace_flat_create(cpl_plugin *);
00038 static int fors_trace_flat_exec(cpl_plugin *);
00039 static int fors_trace_flat_destroy(cpl_plugin *);
00040 static int fors_trace_flat(cpl_parameterlist *, cpl_frameset *);
00041
00042 static char fors_trace_flat_description[] =
00043 "This recipe is used to trace the edges of MOS/MXU flat field slit spectra\n"
00044 "and determine the spectral curvature solution. The input master flat field\n"
00045 "image, product of the recipe fors_flat, is expected to be oriented with\n"
00046 "horizontal dispersion direction and red wavelengths on the right side.\n"
00047 "The input slits location table should be the product of the recipe\n"
00048 "fors_detect_spectra.\n"
00049 "\n"
00050 "The input master flat image is shifted one pixel down and is subtracted\n"
00051 "from the original image. The result is a vertical gradient map. Next,\n"
00052 "the negative values are forced positive, to obtain an absolute gradient\n"
00053 "map. The map is passed with a horizontal median filter, and after that\n"
00054 "the gradient peaks are traced starting from the slits positions listed\n"
00055 "in the input slits location table. The number of pixels to the left and\n"
00056 "to the right of the reference pixel is trivially derived from the specified\n"
00057 "spectral range and spectral dispersion.\n"
00058 "\n"
00059 "The output spectral curvature table contains the coefficients of the\n"
00060 "polynomial fitting of the found traces, while the output trace table\n"
00061 "contains the traced spectral edges positions in CCD (Y) coordinates for\n"
00062 "each spectrum, and their comparison with their modeling. A spatial map\n"
00063 "is also created, where to each CCD pixel is assigned the value of the\n"
00064 "spatial coordinate along the slit (in pixel). For more details please\n"
00065 "refer to the FORS Pipeline User's Manual.\n"
00066 "\n"
00067 "Note that specifying an input GRISM_TABLE will set some of the recipe\n"
00068 "configuration parameters to default values valid for a particular grism.\n"
00069 "Again, see the pipeline manual for more details.\n"
00070 "\n"
00071 "In the table below the MXU acronym can be alternatively read as MOS.\n\n"
00072 "Input files:\n\n"
00073 " DO category: Type: Explanation: Required:\n"
00074 " MASTER_SCREEN_FLAT_MXU Calib Master flat frame Y\n"
00075 " SLIT_LOCATION_DETECT_MXU Calib Slits location Y\n"
00076 " GRISM_TABLE Calib Grism table .\n\n"
00077 "Output files:\n\n"
00078 " DO category: Data type: Explanation:\n"
00079 " CURV_TRACES_MXU FITS table Flat field tracings\n"
00080 " CURV_COEFF_MXU FITS table Spectral curvature table\n"
00081 " SPATIAL_MAP_MXU FITS image Map of spatial coordinate\n\n";
00082
00083 #define fors_trace_flat_exit(message) \
00084 { \
00085 if (message) cpl_msg_error(recipe, message); \
00086 cpl_image_delete(master_flat); \
00087 cpl_image_delete(spatial); \
00088 cpl_image_delete(coordinate); \
00089 cpl_table_delete(grism_table); \
00090 cpl_table_delete(maskslits); \
00091 cpl_table_delete(slits); \
00092 cpl_table_delete(traces); \
00093 cpl_table_delete(polytraces); \
00094 cpl_propertylist_delete(header); \
00095 cpl_msg_indent_less(); \
00096 return -1; \
00097 }
00098
00099 #define fors_trace_flat_exit_memcheck(message) \
00100 { \
00101 if (message) cpl_msg_info(recipe, message); \
00102 printf("free master_flat (%p)\n", master_flat); \
00103 cpl_image_delete(master_flat); \
00104 printf("free spatial (%p)\n", spatial); \
00105 cpl_image_delete(spatial); \
00106 printf("free coordinate (%p)\n", coordinate); \
00107 cpl_image_delete(coordinate); \
00108 printf("free grism_table (%p)\n", grism_table); \
00109 cpl_table_delete(grism_table); \
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 traces (%p)\n", traces); \
00115 cpl_table_delete(traces); \
00116 printf("free polytraces (%p)\n", polytraces); \
00117 cpl_table_delete(polytraces); \
00118 printf("free header (%p)\n", header); \
00119 cpl_propertylist_delete(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_trace_flat",
00146 "Determine spectral curvature model",
00147 fors_trace_flat_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_trace_flat_create,
00164 fors_trace_flat_exec,
00165 fors_trace_flat_destroy);
00166
00167 cpl_pluginlist_append(list, plugin);
00168
00169 return 0;
00170 }
00171
00172
00183 static int fors_trace_flat_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_trace_flat.dispersion",
00208 CPL_TYPE_DOUBLE,
00209 "Expected spectral dispersion (Angstrom/pixel)",
00210 "fors.fors_trace_flat",
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_trace_flat.startwavelength",
00221 CPL_TYPE_DOUBLE,
00222 "Start wavelength in spectral extraction",
00223 "fors.fors_trace_flat",
00224 0.0);
00225 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
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_trace_flat.endwavelength",
00234 CPL_TYPE_DOUBLE,
00235 "End wavelength in spectral extraction",
00236 "fors.fors_trace_flat",
00237 0.0);
00238 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
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_trace_flat.cdegree",
00247 CPL_TYPE_INT,
00248 "Degree of spectral curvature polynomial",
00249 "fors.fors_trace_flat",
00250 0);
00251 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cdegree");
00252 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00253 cpl_parameterlist_append(recipe->parameters, p);
00254
00255
00256
00257
00258
00259 p = cpl_parameter_new_value("fors.fors_trace_flat.cmode",
00260 CPL_TYPE_INT,
00261 "Interpolation mode of curvature solution "
00262 "applicable to MOS-like data (0 = no "
00263 "interpolation, 1 = fill gaps, 2 = global "
00264 "model)",
00265 "fors.fors_trace_flat",
00266 1);
00267 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cmode");
00268 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00269 cpl_parameterlist_append(recipe->parameters, p);
00270
00271 return 0;
00272 }
00273
00274
00283 static int fors_trace_flat_exec(cpl_plugin *plugin)
00284 {
00285 cpl_recipe *recipe;
00286
00287 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00288 recipe = (cpl_recipe *)plugin;
00289 else
00290 return -1;
00291
00292 return fors_trace_flat(recipe->parameters, recipe->frames);
00293 }
00294
00295
00304 static int fors_trace_flat_destroy(cpl_plugin *plugin)
00305 {
00306 cpl_recipe *recipe;
00307
00308 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00309 recipe = (cpl_recipe *)plugin;
00310 else
00311 return -1;
00312
00313 cpl_parameterlist_delete(recipe->parameters);
00314
00315 return 0;
00316 }
00317
00318
00328 static int fors_trace_flat(cpl_parameterlist *parlist,
00329 cpl_frameset *frameset)
00330 {
00331
00332 const char *recipe = "fors_trace_flat";
00333
00334
00335
00336
00337
00338
00339 double dispersion;
00340 double startwavelength;
00341 double endwavelength;
00342 int cdegree;
00343 int cmode;
00344
00345
00346
00347
00348
00349 cpl_image *master_flat = NULL;
00350 cpl_image *coordinate = NULL;
00351 cpl_image *spatial = NULL;
00352 cpl_table *grism_table = NULL;
00353 cpl_table *maskslits = NULL;
00354 cpl_table *slits = NULL;
00355 cpl_table *traces = NULL;
00356 cpl_table *polytraces = NULL;
00357 cpl_propertylist *header = NULL;
00358
00359
00360
00361
00362
00363 char version[80];
00364 const char *master_flat_tag;
00365 const char *spatial_map_tag;
00366 const char *slit_detect_tag;
00367 const char *slit_location_tag;
00368 const char *curv_traces_tag;
00369 const char *curv_coeff_tag;
00370 int flat_mxu;
00371 int flat_mos;
00372 int flat_lss;
00373 int mxu, mos;
00374 int nflat;
00375 int nslits;
00376 int rebin;
00377 int nx, ny;
00378 int treat_as_lss;
00379 int i;
00380 double reference;
00381 double *xpos;
00382 double mxpos;
00383
00384 char *instrume = NULL;
00385
00386
00387 cpl_msg_set_indentation(2);
00388
00389 if (dfs_files_dont_exist(frameset))
00390 fors_trace_flat_exit(NULL);
00391
00392
00393
00394
00395
00396
00397 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00398 cpl_msg_indent_more();
00399
00400 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00401 fors_trace_flat_exit("Too many in input: GRISM_TABLE");
00402
00403 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00404
00405 dispersion = dfs_get_parameter_double(parlist,
00406 "fors.fors_trace_flat.dispersion", grism_table);
00407
00408 if (dispersion <= 0.0)
00409 fors_trace_flat_exit("Invalid spectral dispersion value");
00410
00411 startwavelength = dfs_get_parameter_double(parlist,
00412 "fors.fors_trace_flat.startwavelength", grism_table);
00413 if (startwavelength > 1.0)
00414 if (startwavelength < 3000.0 || startwavelength > 13000.0)
00415 fors_trace_flat_exit("Invalid wavelength");
00416
00417 endwavelength = dfs_get_parameter_double(parlist,
00418 "fors.fors_trace_flat.endwavelength", grism_table);
00419 if (endwavelength > 1.0) {
00420 if (endwavelength < 3000.0 || endwavelength > 13000.0)
00421 fors_trace_flat_exit("Invalid wavelength");
00422 if (startwavelength < 1.0)
00423 fors_trace_flat_exit("Invalid wavelength interval");
00424 }
00425
00426 if (startwavelength > 1.0)
00427 if (endwavelength - startwavelength <= 0.0)
00428 fors_trace_flat_exit("Invalid wavelength interval");
00429
00430 cdegree = dfs_get_parameter_int(parlist,
00431 "fors.fors_trace_flat.cdegree", grism_table);
00432
00433 if (cdegree < 1)
00434 fors_trace_flat_exit("Invalid polynomial degree");
00435
00436 if (cdegree > 5)
00437 fors_trace_flat_exit("Max allowed polynomial degree is 5");
00438
00439 cmode = dfs_get_parameter_int(parlist, "fors.fors_trace_flat.cmode", NULL);
00440
00441 if (cmode < 0 || cmode > 2)
00442 fors_trace_flat_exit("Invalid curvature solution interpolation mode");
00443
00444 cpl_table_delete(grism_table); grism_table = NULL;
00445
00446 if (cpl_error_get_code())
00447 fors_trace_flat_exit("Failure reading the configuration parameters");
00448
00449
00450 cpl_msg_indent_less();
00451 cpl_msg_info(recipe, "Check input set-of-frames:");
00452 cpl_msg_indent_more();
00453
00454 nflat = flat_mxu = cpl_frameset_count_tags(frameset,
00455 "MASTER_SCREEN_FLAT_MXU");
00456 nflat += flat_mos = cpl_frameset_count_tags(frameset,
00457 "MASTER_SCREEN_FLAT_MOS");
00458 nflat += flat_lss = cpl_frameset_count_tags(frameset,
00459 "MASTER_SCREEN_FLAT_LSS");
00460
00461 if (nflat == 0) {
00462 fors_trace_flat_exit("Missing input master flat field frame");
00463 }
00464 if (nflat > 1) {
00465 cpl_msg_error(recipe, "Too many input flat frames (%d > 1)", nflat);
00466 fors_trace_flat_exit(NULL);
00467 }
00468
00469 mxu = mos = 0;
00470
00471 if (flat_mxu) {
00472 mxu = 1;
00473 master_flat_tag = "MASTER_SCREEN_FLAT_MXU";
00474 slit_detect_tag = "SLIT_LOCATION_DETECT_MXU";
00475 slit_location_tag = "SLIT_LOCATION_MXU";
00476 curv_traces_tag = "CURV_TRACES_MXU";
00477 curv_coeff_tag = "CURV_COEFF_MXU";
00478 spatial_map_tag = "SPATIAL_MAP_MXU";
00479 }
00480 else if (flat_mos) {
00481 mos = 1;
00482 master_flat_tag = "MASTER_SCREEN_FLAT_MOS";
00483 slit_detect_tag = "SLIT_LOCATION_DETECT_MOS";
00484 slit_location_tag = "SLIT_LOCATION_MOS";
00485 curv_traces_tag = "CURV_TRACES_MOS";
00486 curv_coeff_tag = "CURV_COEFF_MOS";
00487 spatial_map_tag = "SPATIAL_MAP_MOS";
00488 }
00489 else if (flat_lss) {
00490 fors_trace_flat_exit("LSS spectra are not traceable: use this recipe "
00491 "just for MOS/MXU data.");
00492 }
00493
00494 if (cpl_frameset_count_tags(frameset, slit_detect_tag) == 0) {
00495 cpl_msg_error(recipe, "Missing required input: %s", slit_detect_tag);
00496 fors_trace_flat_exit(NULL);
00497 }
00498
00499 if (cpl_frameset_count_tags(frameset, slit_detect_tag) > 1) {
00500 cpl_msg_error(recipe, "Too many in input: %s", slit_detect_tag);
00501 fors_trace_flat_exit(NULL);
00502 }
00503
00504 if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00505 fors_trace_flat_exit("Input frames are not from the same grism");
00506
00507 if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00508 fors_trace_flat_exit("Input frames are not from the same filter");
00509
00510 if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00511 fors_trace_flat_exit("Input frames are not from the same chip");
00512
00513
00514
00515
00516
00517
00518
00519 header = dfs_load_header(frameset, master_flat_tag, 0);
00520
00521 if (header == NULL)
00522 fors_trace_flat_exit("Cannot load master flat frame header");
00523
00524 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00525 if (instrume == NULL)
00526 fors_trace_flat_exit("Missing keyword INSTRUME in master flat header");
00527
00528 if (instrume[4] == '1')
00529 snprintf(version, 80, "%s/%s", "fors1", VERSION);
00530 if (instrume[4] == '2')
00531 snprintf(version, 80, "%s/%s", "fors2", VERSION);
00532
00533 reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
00534
00535 if (cpl_error_get_code() != CPL_ERROR_NONE)
00536 fors_trace_flat_exit("Missing keyword ESO INS GRIS1 WLEN "
00537 "in master flat frame header");
00538
00539 if (reference < 3000.0)
00540 reference *= 10;
00541
00542 if (reference < 3000.0 || reference > 13000.0) {
00543 cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
00544 "keyword ESO INS GRIS1 WLEN in master flat header",
00545 reference);
00546 fors_trace_flat_exit(NULL);
00547 }
00548
00549 cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
00550
00551 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
00552
00553 if (cpl_error_get_code() != CPL_ERROR_NONE)
00554 fors_trace_flat_exit("Missing keyword ESO DET WIN1 BINX "
00555 "in master flat header");
00556
00557 if (rebin != 1) {
00558 dispersion *= rebin;
00559 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
00560 "working dispersion used is %f A/pixel", rebin,
00561 dispersion);
00562 }
00563
00564
00565
00566
00567
00568
00569 if (mos)
00570 maskslits = mos_load_slits_fors_mos(header);
00571 else
00572 maskslits = mos_load_slits_fors_mxu(header);
00573
00574 mxpos = cpl_table_get_column_median(maskslits, "xtop");
00575 xpos = cpl_table_get_data_double(maskslits, "xtop");
00576 nslits = cpl_table_get_nrow(maskslits);
00577
00578 treat_as_lss = 1;
00579 for (i = 0; i < nslits; i++) {
00580 if (fabs(mxpos-xpos[i]) > 0.01) {
00581 treat_as_lss = 0;
00582 break;
00583 }
00584 }
00585
00586 if (treat_as_lss) {
00587 cpl_msg_error(recipe, "All slits have the same offset: %.2f mm\n"
00588 "Spectra are not traceable: the LSS data reduction\n"
00589 "strategy must be applied.", mxpos);
00590 fors_trace_flat_exit(NULL);
00591 }
00592
00593 cpl_table_delete(maskslits); maskslits = NULL;
00594
00595
00596 cpl_msg_indent_less();
00597 cpl_msg_info(recipe, "Load input frames...");
00598 cpl_msg_indent_more();
00599
00600 master_flat = dfs_load_image(frameset, master_flat_tag,
00601 CPL_TYPE_FLOAT, 0, 0);
00602 if (master_flat == NULL)
00603 fors_trace_flat_exit("Cannot load master flat field frame");
00604
00605 slits = dfs_load_table(frameset, slit_detect_tag, 1);
00606 if (slits == NULL)
00607 fors_trace_flat_exit("Cannot load slits location table");
00608
00609
00610 cpl_msg_indent_less();
00611 cpl_msg_info(recipe, "Determining spectral curvature...");
00612 cpl_msg_indent_more();
00613
00614 cpl_msg_info(recipe, "Tracing master flat field spectra edges...");
00615 traces = mos_trace_flat(master_flat, slits, reference,
00616 startwavelength, endwavelength, dispersion);
00617
00618 if (!traces)
00619 fors_trace_flat_exit("Tracing failure");
00620
00621 cpl_msg_info(recipe, "Fitting flat field spectra edges...");
00622 polytraces = mos_poly_trace(slits, traces, cdegree);
00623
00624 if (!polytraces)
00625 fors_trace_flat_exit("Trace fitting failure");
00626
00627 if (cmode) {
00628 cpl_msg_info(recipe, "Computing global spectral curvature model...");
00629 mos_global_trace(slits, polytraces, cmode);
00630 }
00631
00632 if (dfs_save_table(frameset, traces, curv_traces_tag, NULL, parlist,
00633 recipe, version))
00634 fors_trace_flat_exit(NULL);
00635
00636 cpl_table_delete(traces); traces = NULL;
00637
00638 nx = cpl_image_get_size_x(master_flat);
00639 ny = cpl_image_get_size_y(master_flat);
00640 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00641
00642 spatial = mos_spatial_calibration(master_flat, slits, polytraces,
00643 reference,
00644 startwavelength, endwavelength,
00645 dispersion, 0, coordinate);
00646
00647 cpl_image_delete(master_flat); master_flat = NULL;
00648 cpl_image_delete(spatial); spatial = NULL;
00649
00650 if (dfs_save_image(frameset, coordinate, spatial_map_tag, header,
00651 parlist, recipe, version))
00652 fors_trace_flat_exit(NULL);
00653
00654 cpl_image_delete(coordinate); coordinate = NULL;
00655 cpl_propertylist_delete(header); header = NULL;
00656
00657 if (dfs_save_table(frameset, slits, slit_location_tag, NULL,
00658 parlist, recipe, version))
00659 fors_trace_flat_exit(NULL);
00660
00661 cpl_table_delete(slits); slits = NULL;
00662
00663 if (dfs_save_table(frameset, polytraces, curv_coeff_tag, NULL,
00664 parlist, recipe, version))
00665 fors_trace_flat_exit(NULL);
00666
00667 cpl_table_delete(polytraces); polytraces = NULL;
00668
00669 return 0;
00670 }