00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027
00028
00029
00030
00031 #include <string.h>
00032 #include <strings.h>
00033 #include <cpl.h>
00034
00035 #include "muse_wavecal_z.h"
00036
00037
00076
00079
00080
00081
00082 static const char *muse_wavecal_help =
00083 "This recipe detects arc emission lines and fits a wavelength solution to each slice of the instrument. The wavelength calibration table contains polynomials defining the wavelength solution of the slices on the CCD. Processing trims the raw data and records the overscan statistics, subtracts the bias (taking account of the overscan, if --overscan is not &none&) and converts them from adu to count. Optionally, the dark can be subtracted and the data can be divided by the flat-field, but this is not recommended. The data is then combined using input parameters, first into separate images for each lamp. If --lampwise is not given or if --resample is given, these lamp-separate exposures are summed to create a single combined master arc. To compute the wavelength solution, arc lines are detected at the center of each slice (using threshold detection on a S/N image) and subsequently assigned wavelengths, using pattern matching to identify lines from the input line catalog. Each line is then traced to the edges of the slice, using Gaussian centering in each CCD column. The Gaussians not only yield center, but also centering error, and line properties (e.g. FWHM). Deviant fits are detected using polynomial fits to each arc line (using the xorder parameter) and rejected. If --lampwise is switched on, these analysis and measuring steps are carried out separately on images exposed by the different arc lamps, reducing the amount of blending, that can otherwise influence line identification and Gaussian centering. The final two-dimensional fit uses all positions (of all lamps), their wavelengths, and the given polynomial orders to compute the final wavelength solution for each slice, iteratively rejecting outliers. This final fit can be either unweighted (fitweighting=&uniform&, for fastest processing) or weighted (other values of fitweighting, for higher accuracy).";
00084
00085 static const char *muse_wavecal_help_esorex =
00086 "\n\nInput frames for raw frame tag \"ARC\":\n"
00087 "\n Frame tag Type Req #Fr Description"
00088 "\n -------------------- ---- --- --- ------------"
00089 "\n ARC raw Y Raw arc lamp exposures"
00090 "\n MASTER_BIAS calib Y 1 Master bias"
00091 "\n MASTER_DARK calib . 1 Master dark"
00092 "\n MASTER_FLAT calib . 1 Master flat"
00093 "\n TRACE_TABLE calib Y 1 Trace table"
00094 "\n LINE_CATALOG calib Y 1 Arc line catalog"
00095 "\n BADPIX_TABLE calib . 1 Bad pixel table"
00096 "\n\nProduct frames for raw frame tag \"ARC\":\n"
00097 "\n Frame tag Level Description"
00098 "\n -------------------- -------- ------------"
00099 "\n WAVECAL_TABLE final Wavelength calibration table"
00100 "\n WAVECAL_RESIDUALS final Fit residuals of all arc lines (if --residuals=true)"
00101 "\n ARC_RED_LAMP final Reduced ARC image, per lamp"
00102 "\n ARC_RED final Reduced, combined master ARC image (if --lampwise=false or --resample=true)"
00103 "\n ARC_RESAMPLED final Resampled arc images (if --resample=true)"
00104 "\n WAVE_MAP final Wavelength map of the input images";
00105
00106
00114
00115 static cpl_recipeconfig *
00116 muse_wavecal_new_recipeconfig(void)
00117 {
00118 cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
00119
00120 cpl_recipeconfig_set_tag(recipeconfig, "ARC", 1, -1);
00121 cpl_recipeconfig_set_input(recipeconfig, "ARC", "MASTER_BIAS", 1, 1);
00122 cpl_recipeconfig_set_input(recipeconfig, "ARC", "MASTER_DARK", -1, 1);
00123 cpl_recipeconfig_set_input(recipeconfig, "ARC", "MASTER_FLAT", -1, 1);
00124 cpl_recipeconfig_set_input(recipeconfig, "ARC", "TRACE_TABLE", 1, 1);
00125 cpl_recipeconfig_set_input(recipeconfig, "ARC", "LINE_CATALOG", 1, 1);
00126 cpl_recipeconfig_set_input(recipeconfig, "ARC", "BADPIX_TABLE", -1, 1);
00127 cpl_recipeconfig_set_output(recipeconfig, "ARC", "WAVECAL_TABLE");
00128 cpl_recipeconfig_set_output(recipeconfig, "ARC", "WAVECAL_RESIDUALS");
00129 cpl_recipeconfig_set_output(recipeconfig, "ARC", "ARC_RED_LAMP");
00130 cpl_recipeconfig_set_output(recipeconfig, "ARC", "ARC_RED");
00131 cpl_recipeconfig_set_output(recipeconfig, "ARC", "ARC_RESAMPLED");
00132 cpl_recipeconfig_set_output(recipeconfig, "ARC", "WAVE_MAP");
00133
00134 return recipeconfig;
00135 }
00136
00137
00147
00148 static cpl_error_code
00149 muse_wavecal_prepare_header(const char *aFrametag, cpl_propertylist *aHeader)
00150 {
00151 cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
00152 cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
00153 if (!strcmp(aFrametag, "WAVECAL_TABLE")) {
00154 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ LINES NDET",
00155 CPL_TYPE_INT,
00156 "Number of detected arc lines in slice j");
00157 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ LINES NID",
00158 CPL_TYPE_INT,
00159 "Number of identified arc lines in slice j");
00160 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ LINES PEAK MEAN",
00161 CPL_TYPE_FLOAT,
00162 "[count] Mean peak count level above background of detected arc lines in slice j");
00163 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ LINES PEAK STDEV",
00164 CPL_TYPE_FLOAT,
00165 "[count] Standard deviation of peak count level above background of detected arc lines in slice j");
00166 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ LINES PEAK MIN",
00167 CPL_TYPE_FLOAT,
00168 "[count] Peak count level above background of the faintest line in slice j");
00169 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ LINES PEAK MAX",
00170 CPL_TYPE_FLOAT,
00171 "[count] Peak count level above background of the brightest line in slice j");
00172 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ LAMP[0-9] LINES PEAK MEAN",
00173 CPL_TYPE_FLOAT,
00174 "[count] Mean peak count level of lines of lamp l above background of detected arc lines in slice j. Not produced with --lampwise=FALSE!");
00175 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ LAMP[0-9] LINES PEAK STDEV",
00176 CPL_TYPE_FLOAT,
00177 "[count] Standard deviation of peak count level of lines of lamp l above background of detected arc lines in slice j. Not produced with --lampwise=FALSE!");
00178 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ LAMP[0-9] LINES PEAK MAX",
00179 CPL_TYPE_FLOAT,
00180 "[count] Peak count level above background of the brightest line of lamp l in slice j. Not produced with --lampwise=FALSE!");
00181 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ LINES FWHM MEAN",
00182 CPL_TYPE_FLOAT,
00183 "Mean FWHM of detected arc lines in slice j");
00184 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ LINES FWHM STDEV",
00185 CPL_TYPE_FLOAT,
00186 "Standard deviation of FWHM of detected arc lines in slice j");
00187 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ LINES FWHM MIN",
00188 CPL_TYPE_FLOAT,
00189 "Minimum FWHM of detected arc lines in slice j");
00190 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ LINES FWHM MAX",
00191 CPL_TYPE_FLOAT,
00192 "Maximum FWHM of detected arc lines in slice j");
00193 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ RESOL",
00194 CPL_TYPE_FLOAT,
00195 "Mean spectral resolution R determined in slice j");
00196 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ FIT NLINES",
00197 CPL_TYPE_INT,
00198 "Number of arc lines used in calibration solution fit in slice j");
00199 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ FIT RMS",
00200 CPL_TYPE_FLOAT,
00201 "[Angstrom] RMS of the wavelength calibration fit in slice j");
00202 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ DWLEN BOTTOM",
00203 CPL_TYPE_FLOAT,
00204 "[Angstrom] Difference in wavelength computed for the bottom left and bottom right corners of the slice on the CCD");
00205 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ DWLEN TOP",
00206 CPL_TYPE_FLOAT,
00207 "[Angstrom] Difference in wavelength computed for the top left and top right corners of the slice on the CCD");
00208 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ WLPOS",
00209 CPL_TYPE_FLOAT,
00210 "[pix] Position of wavelength given in WLEN in slice j");
00211 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL SLICE[0-9]+ WLEN",
00212 CPL_TYPE_FLOAT,
00213 "[Angstrom] Wavelength associated to WLPOS in slice j");
00214 } else if (!strcmp(aFrametag, "WAVECAL_RESIDUALS")) {
00215 } else if (!strcmp(aFrametag, "ARC_RED_LAMP")) {
00216 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL INPUT[0-9]+ NSATURATED",
00217 CPL_TYPE_INT,
00218 "Number of saturated pixels in raw arc i in input list");
00219 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL NSATURATED",
00220 CPL_TYPE_INT,
00221 "Number of saturated pixels in output data");
00222 } else if (!strcmp(aFrametag, "ARC_RED")) {
00223 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL LAMP[0-9]+ INPUT[0-9]+ NSATURATED",
00224 CPL_TYPE_INT,
00225 "Number of saturated pixels in raw arc i of lamp l in input list");
00226 muse_processing_prepare_property(aHeader, "ESO QC WAVECAL NSATURATED",
00227 CPL_TYPE_INT,
00228 "Number of saturated pixels in output data");
00229 } else if (!strcmp(aFrametag, "ARC_RESAMPLED")) {
00230 } else if (!strcmp(aFrametag, "WAVE_MAP")) {
00231 } else {
00232 cpl_msg_warning(__func__, "Frame tag %s is not defined", aFrametag);
00233 return CPL_ERROR_ILLEGAL_INPUT;
00234 }
00235 return CPL_ERROR_NONE;
00236 }
00237
00238
00247
00248 static cpl_frame_level
00249 muse_wavecal_get_frame_level(const char *aFrametag)
00250 {
00251 if (!aFrametag) {
00252 return CPL_FRAME_LEVEL_NONE;
00253 }
00254 if (!strcmp(aFrametag, "WAVECAL_TABLE")) {
00255 return CPL_FRAME_LEVEL_FINAL;
00256 }
00257 if (!strcmp(aFrametag, "WAVECAL_RESIDUALS")) {
00258 return CPL_FRAME_LEVEL_FINAL;
00259 }
00260 if (!strcmp(aFrametag, "ARC_RED_LAMP")) {
00261 return CPL_FRAME_LEVEL_FINAL;
00262 }
00263 if (!strcmp(aFrametag, "ARC_RED")) {
00264 return CPL_FRAME_LEVEL_FINAL;
00265 }
00266 if (!strcmp(aFrametag, "ARC_RESAMPLED")) {
00267 return CPL_FRAME_LEVEL_FINAL;
00268 }
00269 if (!strcmp(aFrametag, "WAVE_MAP")) {
00270 return CPL_FRAME_LEVEL_FINAL;
00271 }
00272 return CPL_FRAME_LEVEL_NONE;
00273 }
00274
00275
00284
00285 static muse_frame_mode
00286 muse_wavecal_get_frame_mode(const char *aFrametag)
00287 {
00288 if (!aFrametag) {
00289 return MUSE_FRAME_MODE_ALL;
00290 }
00291 if (!strcmp(aFrametag, "WAVECAL_TABLE")) {
00292 return MUSE_FRAME_MODE_MASTER;
00293 }
00294 if (!strcmp(aFrametag, "WAVECAL_RESIDUALS")) {
00295 return MUSE_FRAME_MODE_MASTER;
00296 }
00297 if (!strcmp(aFrametag, "ARC_RED_LAMP")) {
00298 return MUSE_FRAME_MODE_SUBSET;
00299 }
00300 if (!strcmp(aFrametag, "ARC_RED")) {
00301 return MUSE_FRAME_MODE_MASTER;
00302 }
00303 if (!strcmp(aFrametag, "ARC_RESAMPLED")) {
00304 return MUSE_FRAME_MODE_MASTER;
00305 }
00306 if (!strcmp(aFrametag, "WAVE_MAP")) {
00307 return MUSE_FRAME_MODE_MASTER;
00308 }
00309 return MUSE_FRAME_MODE_ALL;
00310 }
00311
00312
00322
00323 static int
00324 muse_wavecal_create(cpl_plugin *aPlugin)
00325 {
00326
00327 cpl_recipe *recipe;
00328 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
00329 recipe = (cpl_recipe *)aPlugin;
00330 } else {
00331 return -1;
00332 }
00333
00334
00335
00336 muse_processinginfo_register(recipe,
00337 muse_wavecal_new_recipeconfig(),
00338 muse_wavecal_prepare_header,
00339 muse_wavecal_get_frame_level,
00340 muse_wavecal_get_frame_mode);
00341
00342
00343
00344 if (muse_cplframework() == MUSE_CPLFRAMEWORK_ESOREX) {
00345 cpl_msg_set_time_on();
00346 }
00347
00348
00349 recipe->parameters = cpl_parameterlist_new();
00350
00351 cpl_parameter *p;
00352
00353
00354 p = cpl_parameter_new_range("muse.muse_wavecal.nifu",
00355 CPL_TYPE_INT,
00356 "IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel.",
00357 "muse.muse_wavecal",
00358 (int)0,
00359 (int)-1,
00360 (int)24);
00361 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "nifu");
00362 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nifu");
00363
00364 cpl_parameterlist_append(recipe->parameters, p);
00365
00366
00367 p = cpl_parameter_new_value("muse.muse_wavecal.overscan",
00368 CPL_TYPE_STRING,
00369 "If this is \"none\", stop when detecting discrepant overscan levels (see ovscsigma), for \"offset\" it assumes that the mean overscan level represents the real offset in the bias levels of the exposures involved, and adjusts the data accordingly; for \"vpoly\", a polynomial is fit to the vertical overscan and subtracted from the whole quadrant.",
00370 "muse.muse_wavecal",
00371 (const char *)"vpoly");
00372 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "overscan");
00373 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "overscan");
00374
00375 cpl_parameterlist_append(recipe->parameters, p);
00376
00377
00378 p = cpl_parameter_new_value("muse.muse_wavecal.ovscreject",
00379 CPL_TYPE_STRING,
00380 "This influences how values are rejected when computing overscan statistics. Either no rejection at all (\"none\"), rejection using the DCR algorithm (\"dcr\"), or rejection using an iterative constant fit (\"fit\").",
00381 "muse.muse_wavecal",
00382 (const char *)"dcr");
00383 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscreject");
00384 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscreject");
00385
00386 cpl_parameterlist_append(recipe->parameters, p);
00387
00388
00389 p = cpl_parameter_new_value("muse.muse_wavecal.ovscsigma",
00390 CPL_TYPE_DOUBLE,
00391 "If the deviation of mean overscan levels between a raw input image and the reference image is higher than |ovscsigma x stdev|, stop the processing. If overscan=\"vpoly\", this is used as sigma rejection level for the iterative polynomial fit (the level comparison is then done afterwards with |100 x stdev| to guard against incompatible settings). Has no effect for overscan=\"offset\".",
00392 "muse.muse_wavecal",
00393 (double)30.);
00394 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscsigma");
00395 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscsigma");
00396
00397 cpl_parameterlist_append(recipe->parameters, p);
00398
00399
00400 p = cpl_parameter_new_value("muse.muse_wavecal.ovscignore",
00401 CPL_TYPE_INT,
00402 "The number of pixels of the overscan adjacent to the data region of the CCD that are ignored when computing statistics or fits.",
00403 "muse.muse_wavecal",
00404 (int)3);
00405 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ovscignore");
00406 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ovscignore");
00407
00408 cpl_parameterlist_append(recipe->parameters, p);
00409
00410
00411 p = cpl_parameter_new_enum("muse.muse_wavecal.combine",
00412 CPL_TYPE_STRING,
00413 "Type of lampwise image combination to use.",
00414 "muse.muse_wavecal",
00415 (const char *)"sigclip",
00416 4,
00417 (const char *)"average",
00418 (const char *)"median",
00419 (const char *)"minmax",
00420 (const char *)"sigclip");
00421 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "combine");
00422 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "combine");
00423
00424 cpl_parameterlist_append(recipe->parameters, p);
00425
00426
00427 p = cpl_parameter_new_value("muse.muse_wavecal.lampwise",
00428 CPL_TYPE_BOOL,
00429 "Identify and measure the arc emission lines on images separately for each lamp setup.",
00430 "muse.muse_wavecal",
00431 (int)TRUE);
00432 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lampwise");
00433 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lampwise");
00434
00435 cpl_parameterlist_append(recipe->parameters, p);
00436
00437
00438 p = cpl_parameter_new_value("muse.muse_wavecal.sigma",
00439 CPL_TYPE_DOUBLE,
00440 "Sigma level used to detect arc emission lines above the median background level in the S/N image of the central column of each slice",
00441 "muse.muse_wavecal",
00442 (double)1.0);
00443 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "sigma");
00444 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sigma");
00445
00446 cpl_parameterlist_append(recipe->parameters, p);
00447
00448
00449 p = cpl_parameter_new_value("muse.muse_wavecal.dres",
00450 CPL_TYPE_DOUBLE,
00451 "The allowed range of resolutions for pattern matching (of detected arc lines to line list) in fractions relative to the expected value",
00452 "muse.muse_wavecal",
00453 (double)0.05);
00454 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "dres");
00455 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dres");
00456
00457 cpl_parameterlist_append(recipe->parameters, p);
00458
00459
00460 p = cpl_parameter_new_value("muse.muse_wavecal.tolerance",
00461 CPL_TYPE_DOUBLE,
00462 "Tolerance for pattern matching (of detected arc lines to line list)",
00463 "muse.muse_wavecal",
00464 (double)0.1);
00465 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "tolerance");
00466 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "tolerance");
00467
00468 cpl_parameterlist_append(recipe->parameters, p);
00469
00470
00471 p = cpl_parameter_new_value("muse.muse_wavecal.xorder",
00472 CPL_TYPE_INT,
00473 "Order of the polynomial for the horizontal curvature within each slice",
00474 "muse.muse_wavecal",
00475 (int)2);
00476 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "xorder");
00477 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "xorder");
00478
00479 cpl_parameterlist_append(recipe->parameters, p);
00480
00481
00482 p = cpl_parameter_new_value("muse.muse_wavecal.yorder",
00483 CPL_TYPE_INT,
00484 "Order of the polynomial used to fit the dispersion relation",
00485 "muse.muse_wavecal",
00486 (int)6);
00487 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "yorder");
00488 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "yorder");
00489
00490 cpl_parameterlist_append(recipe->parameters, p);
00491
00492
00493 p = cpl_parameter_new_value("muse.muse_wavecal.linesigma",
00494 CPL_TYPE_DOUBLE,
00495 "Sigma level for iterative rejection of deviant fits for each arc line within each slice, a negative value means to use the default (2.5).",
00496 "muse.muse_wavecal",
00497 (double)-1.0);
00498 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "linesigma");
00499 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "linesigma");
00500
00501 cpl_parameterlist_append(recipe->parameters, p);
00502
00503
00504 p = cpl_parameter_new_value("muse.muse_wavecal.residuals",
00505 CPL_TYPE_BOOL,
00506 "Create a table containing residuals of the fits to the data of all arc lines. This is useful to assess the quality of the wavelength solution in detail.",
00507 "muse.muse_wavecal",
00508 (int)FALSE);
00509 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "residuals");
00510 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "residuals");
00511
00512 cpl_parameterlist_append(recipe->parameters, p);
00513
00514
00515 p = cpl_parameter_new_value("muse.muse_wavecal.fitsigma",
00516 CPL_TYPE_DOUBLE,
00517 "Sigma level for iterative rejection of deviant datapoints during the final polynomial wavelength solution within each slice, a negative value means to use the default (3.0).",
00518 "muse.muse_wavecal",
00519 (double)-1.0);
00520 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "fitsigma");
00521 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fitsigma");
00522
00523 cpl_parameterlist_append(recipe->parameters, p);
00524
00525
00526 p = cpl_parameter_new_enum("muse.muse_wavecal.fitweighting",
00527 CPL_TYPE_STRING,
00528 "Type of weighting to use in the final polynomial wavelength solution fit, using centroiding error estimate and/or scatter of each single line as estimates of its accuracy.",
00529 "muse.muse_wavecal",
00530 (const char *)"cerrscatter",
00531 4,
00532 (const char *)"uniform",
00533 (const char *)"cerr",
00534 (const char *)"scatter",
00535 (const char *)"cerrscatter");
00536 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "fitweighting");
00537 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fitweighting");
00538
00539 cpl_parameterlist_append(recipe->parameters, p);
00540
00541
00542 p = cpl_parameter_new_value("muse.muse_wavecal.resample",
00543 CPL_TYPE_BOOL,
00544 "Resample the input arc images onto 2D images for a visual check using tracing and wavelength calibration solutions. Note that the image produced will show small wiggles even when the calibration was successful!",
00545 "muse.muse_wavecal",
00546 (int)FALSE);
00547 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "resample");
00548 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "resample");
00549
00550 cpl_parameterlist_append(recipe->parameters, p);
00551
00552
00553 p = cpl_parameter_new_value("muse.muse_wavecal.wavemap",
00554 CPL_TYPE_BOOL,
00555 "Create a wavelength map of the input images",
00556 "muse.muse_wavecal",
00557 (int)FALSE);
00558 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "wavemap");
00559 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wavemap");
00560
00561 cpl_parameterlist_append(recipe->parameters, p);
00562
00563
00564 p = cpl_parameter_new_value("muse.muse_wavecal.merge",
00565 CPL_TYPE_BOOL,
00566 "Merge output products from different IFUs into a common file.",
00567 "muse.muse_wavecal",
00568 (int)FALSE);
00569 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "merge");
00570 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "merge");
00571
00572 cpl_parameterlist_append(recipe->parameters, p);
00573
00574 return 0;
00575 }
00576
00577
00588
00589 static int
00590 muse_wavecal_params_fill(muse_wavecal_params_t *aParams, cpl_parameterlist *aParameters)
00591 {
00592 cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
00593 cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
00594 cpl_parameter *p;
00595
00596 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.nifu");
00597 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00598 aParams->nifu = cpl_parameter_get_int(p);
00599
00600 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.overscan");
00601 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00602 aParams->overscan = cpl_parameter_get_string(p);
00603
00604 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.ovscreject");
00605 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00606 aParams->ovscreject = cpl_parameter_get_string(p);
00607
00608 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.ovscsigma");
00609 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00610 aParams->ovscsigma = cpl_parameter_get_double(p);
00611
00612 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.ovscignore");
00613 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00614 aParams->ovscignore = cpl_parameter_get_int(p);
00615
00616 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.combine");
00617 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00618 aParams->combine_s = cpl_parameter_get_string(p);
00619 aParams->combine =
00620 (!strcasecmp(aParams->combine_s, "average")) ? MUSE_WAVECAL_PARAM_COMBINE_AVERAGE :
00621 (!strcasecmp(aParams->combine_s, "median")) ? MUSE_WAVECAL_PARAM_COMBINE_MEDIAN :
00622 (!strcasecmp(aParams->combine_s, "minmax")) ? MUSE_WAVECAL_PARAM_COMBINE_MINMAX :
00623 (!strcasecmp(aParams->combine_s, "sigclip")) ? MUSE_WAVECAL_PARAM_COMBINE_SIGCLIP :
00624 MUSE_WAVECAL_PARAM_COMBINE_INVALID_VALUE;
00625 cpl_ensure_code(aParams->combine != MUSE_WAVECAL_PARAM_COMBINE_INVALID_VALUE,
00626 CPL_ERROR_ILLEGAL_INPUT);
00627
00628 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.lampwise");
00629 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00630 aParams->lampwise = cpl_parameter_get_bool(p);
00631
00632 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.sigma");
00633 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00634 aParams->sigma = cpl_parameter_get_double(p);
00635
00636 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.dres");
00637 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00638 aParams->dres = cpl_parameter_get_double(p);
00639
00640 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.tolerance");
00641 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00642 aParams->tolerance = cpl_parameter_get_double(p);
00643
00644 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.xorder");
00645 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00646 aParams->xorder = cpl_parameter_get_int(p);
00647
00648 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.yorder");
00649 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00650 aParams->yorder = cpl_parameter_get_int(p);
00651
00652 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.linesigma");
00653 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00654 aParams->linesigma = cpl_parameter_get_double(p);
00655
00656 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.residuals");
00657 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00658 aParams->residuals = cpl_parameter_get_bool(p);
00659
00660 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.fitsigma");
00661 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00662 aParams->fitsigma = cpl_parameter_get_double(p);
00663
00664 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.fitweighting");
00665 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00666 aParams->fitweighting_s = cpl_parameter_get_string(p);
00667 aParams->fitweighting =
00668 (!strcasecmp(aParams->fitweighting_s, "uniform")) ? MUSE_WAVECAL_PARAM_FITWEIGHTING_UNIFORM :
00669 (!strcasecmp(aParams->fitweighting_s, "cerr")) ? MUSE_WAVECAL_PARAM_FITWEIGHTING_CERR :
00670 (!strcasecmp(aParams->fitweighting_s, "scatter")) ? MUSE_WAVECAL_PARAM_FITWEIGHTING_SCATTER :
00671 (!strcasecmp(aParams->fitweighting_s, "cerrscatter")) ? MUSE_WAVECAL_PARAM_FITWEIGHTING_CERRSCATTER :
00672 MUSE_WAVECAL_PARAM_FITWEIGHTING_INVALID_VALUE;
00673 cpl_ensure_code(aParams->fitweighting != MUSE_WAVECAL_PARAM_FITWEIGHTING_INVALID_VALUE,
00674 CPL_ERROR_ILLEGAL_INPUT);
00675
00676 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.resample");
00677 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00678 aParams->resample = cpl_parameter_get_bool(p);
00679
00680 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.wavemap");
00681 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00682 aParams->wavemap = cpl_parameter_get_bool(p);
00683
00684 p = cpl_parameterlist_find(aParameters, "muse.muse_wavecal.merge");
00685 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00686 aParams->merge = cpl_parameter_get_bool(p);
00687
00688 return 0;
00689 }
00690
00691
00698
00699 static int
00700 muse_wavecal_exec(cpl_plugin *aPlugin)
00701 {
00702 if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
00703 return -1;
00704 }
00705 muse_processing_recipeinfo(aPlugin);
00706 cpl_recipe *recipe = (cpl_recipe *)aPlugin;
00707 cpl_msg_set_threadid_on();
00708
00709 cpl_frameset *usedframes = cpl_frameset_new(),
00710 *outframes = cpl_frameset_new();
00711 muse_wavecal_params_t params;
00712 muse_wavecal_params_fill(¶ms, recipe->parameters);
00713
00714 cpl_errorstate prestate = cpl_errorstate_get();
00715
00716 if (params.nifu < -1 || params.nifu > kMuseNumIFUs) {
00717 cpl_msg_error(__func__, "Please specify a valid IFU number (between 1 and "
00718 "%d), 0 (to process all IFUs consecutively), or -1 (to "
00719 "process all IFUs in parallel) using --nifu.", kMuseNumIFUs);
00720 return -1;
00721 }
00722
00723 cpl_boolean donotmerge = CPL_FALSE;
00724 int rc = 0;
00725 if (params.nifu > 0) {
00726 muse_processing *proc = muse_processing_new("muse_wavecal",
00727 recipe);
00728 rc = muse_wavecal_compute(proc, ¶ms);
00729 cpl_frameset_join(usedframes, proc->usedframes);
00730 cpl_frameset_join(outframes, proc->outframes);
00731 muse_processing_delete(proc);
00732 donotmerge = CPL_TRUE;
00733 } else if (params.nifu < 0) {
00734 int *rcs = cpl_calloc(kMuseNumIFUs, sizeof(int));
00735 int nifu;
00736 #pragma omp parallel for default(none) \
00737 shared(outframes, params, rcs, recipe, usedframes)
00738 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
00739 muse_processing *proc = muse_processing_new("muse_wavecal",
00740 recipe);
00741 muse_wavecal_params_t *pars = cpl_malloc(sizeof(muse_wavecal_params_t));
00742 memcpy(pars, ¶ms, sizeof(muse_wavecal_params_t));
00743 pars->nifu = nifu;
00744 int *rci = rcs + (nifu - 1);
00745 *rci = muse_wavecal_compute(proc, pars);
00746 if (rci && (int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
00747 *rci = 0;
00748 }
00749 cpl_free(pars);
00750 #pragma omp critical(muse_processing_used_frames)
00751 cpl_frameset_join(usedframes, proc->usedframes);
00752 #pragma omp critical(muse_processing_output_frames)
00753 cpl_frameset_join(outframes, proc->outframes);
00754 muse_processing_delete(proc);
00755 }
00756
00757
00758 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
00759 if (rcs[nifu-1] != 0) {
00760 rc = rcs[nifu-1];
00761 }
00762 }
00763 cpl_free(rcs);
00764 } else {
00765 for (params.nifu = 1; params.nifu <= kMuseNumIFUs && !rc; params.nifu++) {
00766 muse_processing *proc = muse_processing_new("muse_wavecal",
00767 recipe);
00768 rc = muse_wavecal_compute(proc, ¶ms);
00769 if (rc && (int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
00770 rc = 0;
00771 }
00772 cpl_frameset_join(usedframes, proc->usedframes);
00773 cpl_frameset_join(outframes, proc->outframes);
00774 muse_processing_delete(proc);
00775 }
00776 }
00777 UNUSED_ARGUMENT(donotmerge);
00778
00779 if (!cpl_errorstate_is_equal(prestate)) {
00780
00781 cpl_errorstate_dump(prestate, CPL_FALSE, muse_cplerrorstate_dump_some);
00782
00783 cpl_msg_set_level(CPL_MSG_INFO);
00784 }
00785
00786 muse_cplframeset_erase_duplicate(usedframes);
00787 muse_cplframeset_erase_duplicate(outframes);
00788
00789
00790 if (params.merge && !donotmerge) {
00791 muse_utils_frameset_merge_frames(outframes, CPL_TRUE);
00792 }
00793
00794
00795
00796
00797
00798 muse_cplframeset_erase_all(recipe->frames);
00799 cpl_frameset_join(recipe->frames, usedframes);
00800 cpl_frameset_join(recipe->frames, outframes);
00801 cpl_frameset_delete(usedframes);
00802 cpl_frameset_delete(outframes);
00803 return rc;
00804 }
00805
00806
00813
00814 static int
00815 muse_wavecal_destroy(cpl_plugin *aPlugin)
00816 {
00817
00818 cpl_recipe *recipe;
00819 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
00820 recipe = (cpl_recipe *)aPlugin;
00821 } else {
00822 return -1;
00823 }
00824
00825
00826 cpl_parameterlist_delete(recipe->parameters);
00827 muse_processinginfo_delete(recipe);
00828 return 0;
00829 }
00830
00831
00841
00842 int
00843 cpl_plugin_get_info(cpl_pluginlist *aList)
00844 {
00845 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00846 cpl_plugin *plugin = &recipe->interface;
00847
00848 char *helptext;
00849 if (muse_cplframework() == MUSE_CPLFRAMEWORK_ESOREX) {
00850 helptext = cpl_sprintf("%s%s", muse_wavecal_help,
00851 muse_wavecal_help_esorex);
00852 } else {
00853 helptext = cpl_sprintf("%s", muse_wavecal_help);
00854 }
00855
00856
00857 cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
00858 CPL_PLUGIN_TYPE_RECIPE,
00859 "muse_wavecal",
00860 "Detect arc emission lines and determine the wavelength solution for each slice.",
00861 helptext,
00862 "Peter Weilbacher",
00863 "usd-help@eso.org",
00864 muse_get_license(),
00865 muse_wavecal_create,
00866 muse_wavecal_exec,
00867 muse_wavecal_destroy);
00868 cpl_pluginlist_append(aList, plugin);
00869 cpl_free(helptext);
00870
00871 return 0;
00872 }
00873