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_create_sky_z.h"
00036
00037
00047
00050
00051
00052
00053 static const char *muse_create_sky_help =
00054 "This recipe creates the continuum and the atmospheric transition line spectra of the night sky from the data in a pixel table(s) belonging to one exposure of (mostly) empty sky.";
00055
00056 static const char *muse_create_sky_help_esorex =
00057 "\n\nInput frames for raw frame tag \"PIXTABLE_SKY\":\n"
00058 "\n Frame tag Type Req #Fr Description"
00059 "\n -------------------- ---- --- --- ------------"
00060 "\n PIXTABLE_SKY raw Y Input pixel table. If the pixel table is not already flux calibrated, the corresponding flux calibration frames should be given as well."
00061 "\n EXTINCT_TABLE calib Y 1 Atmospheric extinction table"
00062 "\n STD_RESPONSE calib Y 1 Response curve as derived from standard star(s)"
00063 "\n STD_TELLURIC calib . 1 Telluric absorption as derived from standard star(s)"
00064 "\n SKY_LINES calib Y 1 List of OH transitions and other sky lines"
00065 "\n SKY_CONTINUUM calib . 1 Sky continuum to use"
00066 "\n LSF_PROFILE calib . Slice specific LSF parameters cubes"
00067 "\n SKY_MASK calib . 1 Sky mask to use"
00068 "\n\nProduct frames for raw frame tag \"PIXTABLE_SKY\":\n"
00069 "\n Frame tag Level Description"
00070 "\n -------------------- -------- ------------"
00071 "\n SKY_MASK intermed Created sky mask"
00072 "\n IMAGE_FOV intermed Whitelight image used to create the sky mask"
00073 "\n SKY_SPECTRUM intermed Sky spectrum within the sky mask"
00074 "\n SKY_LINES final Estimated sky line flux table"
00075 "\n SKY_CONTINUUM final Estimated continuum flux spectrum";
00076
00077
00085
00086 static cpl_recipeconfig *
00087 muse_create_sky_new_recipeconfig(void)
00088 {
00089 cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
00090
00091 cpl_recipeconfig_set_tag(recipeconfig, "PIXTABLE_SKY", 1, -1);
00092 cpl_recipeconfig_set_input(recipeconfig, "PIXTABLE_SKY", "EXTINCT_TABLE", 1, 1);
00093 cpl_recipeconfig_set_input(recipeconfig, "PIXTABLE_SKY", "STD_RESPONSE", 1, 1);
00094 cpl_recipeconfig_set_input(recipeconfig, "PIXTABLE_SKY", "STD_TELLURIC", -1, 1);
00095 cpl_recipeconfig_set_input(recipeconfig, "PIXTABLE_SKY", "SKY_LINES", 1, 1);
00096 cpl_recipeconfig_set_input(recipeconfig, "PIXTABLE_SKY", "SKY_CONTINUUM", 0, 1);
00097 cpl_recipeconfig_set_input(recipeconfig, "PIXTABLE_SKY", "LSF_PROFILE", 0, -1);
00098 cpl_recipeconfig_set_input(recipeconfig, "PIXTABLE_SKY", "SKY_MASK", 0, 1);
00099 cpl_recipeconfig_set_output(recipeconfig, "PIXTABLE_SKY", "SKY_MASK");
00100 cpl_recipeconfig_set_output(recipeconfig, "PIXTABLE_SKY", "IMAGE_FOV");
00101 cpl_recipeconfig_set_output(recipeconfig, "PIXTABLE_SKY", "SKY_SPECTRUM");
00102 cpl_recipeconfig_set_output(recipeconfig, "PIXTABLE_SKY", "SKY_LINES");
00103 cpl_recipeconfig_set_output(recipeconfig, "PIXTABLE_SKY", "SKY_CONTINUUM");
00104
00105 return recipeconfig;
00106 }
00107
00108
00118
00119 static cpl_error_code
00120 muse_create_sky_prepare_header(const char *aFrametag, cpl_propertylist *aHeader)
00121 {
00122 cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
00123 cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
00124 if (!strcmp(aFrametag, "SKY_MASK")) {
00125 muse_processing_prepare_property(aHeader, "ESO QC SKY THRESHOLD",
00126 CPL_TYPE_DOUBLE,
00127 "Threshold in the white light considered as sky, used to create this mask");
00128 } else if (!strcmp(aFrametag, "IMAGE_FOV")) {
00129 } else if (!strcmp(aFrametag, "SKY_SPECTRUM")) {
00130 } else if (!strcmp(aFrametag, "SKY_LINES")) {
00131 muse_processing_prepare_property(aHeader, "ESO QC SKY LINE[0-9]+ NAME",
00132 CPL_TYPE_STRING,
00133 "Name of the strongest line in group k");
00134 muse_processing_prepare_property(aHeader, "ESO QC SKY LINE[0-9]+ AWAV",
00135 CPL_TYPE_DOUBLE,
00136 "[Angstrom] Wavelength (air) of the strongest line of group l");
00137 muse_processing_prepare_property(aHeader, "ESO QC SKY LINE[0-9]+ FLUX",
00138 CPL_TYPE_DOUBLE,
00139 "[erg/(s cm2 arcsec2)] Flux of the strongest line of group l");
00140 } else if (!strcmp(aFrametag, "SKY_CONTINUUM")) {
00141 muse_processing_prepare_property(aHeader, "ESO QC SKY CONT FLUX",
00142 CPL_TYPE_DOUBLE,
00143 "[erg/(s cm2 arcsec2)] Total flux of the continuum");
00144 muse_processing_prepare_property(aHeader, "ESO QC SKY CONT MAXDEV",
00145 CPL_TYPE_DOUBLE,
00146 "[erg/(s cm2 arcsec2 Angstrom)] Maximum (absolute value) of the derivative of the continuum spectrum");
00147 } else {
00148 cpl_msg_warning(__func__, "Frame tag %s is not defined", aFrametag);
00149 return CPL_ERROR_ILLEGAL_INPUT;
00150 }
00151 return CPL_ERROR_NONE;
00152 }
00153
00154
00163
00164 static cpl_frame_level
00165 muse_create_sky_get_frame_level(const char *aFrametag)
00166 {
00167 if (!aFrametag) {
00168 return CPL_FRAME_LEVEL_NONE;
00169 }
00170 if (!strcmp(aFrametag, "SKY_MASK")) {
00171 return CPL_FRAME_LEVEL_INTERMEDIATE;
00172 }
00173 if (!strcmp(aFrametag, "IMAGE_FOV")) {
00174 return CPL_FRAME_LEVEL_INTERMEDIATE;
00175 }
00176 if (!strcmp(aFrametag, "SKY_SPECTRUM")) {
00177 return CPL_FRAME_LEVEL_INTERMEDIATE;
00178 }
00179 if (!strcmp(aFrametag, "SKY_LINES")) {
00180 return CPL_FRAME_LEVEL_FINAL;
00181 }
00182 if (!strcmp(aFrametag, "SKY_CONTINUUM")) {
00183 return CPL_FRAME_LEVEL_FINAL;
00184 }
00185 return CPL_FRAME_LEVEL_NONE;
00186 }
00187
00188
00197
00198 static muse_frame_mode
00199 muse_create_sky_get_frame_mode(const char *aFrametag)
00200 {
00201 if (!aFrametag) {
00202 return MUSE_FRAME_MODE_ALL;
00203 }
00204 if (!strcmp(aFrametag, "SKY_MASK")) {
00205 return MUSE_FRAME_MODE_MASTER;
00206 }
00207 if (!strcmp(aFrametag, "IMAGE_FOV")) {
00208 return MUSE_FRAME_MODE_MASTER;
00209 }
00210 if (!strcmp(aFrametag, "SKY_SPECTRUM")) {
00211 return MUSE_FRAME_MODE_MASTER;
00212 }
00213 if (!strcmp(aFrametag, "SKY_LINES")) {
00214 return MUSE_FRAME_MODE_MASTER;
00215 }
00216 if (!strcmp(aFrametag, "SKY_CONTINUUM")) {
00217 return MUSE_FRAME_MODE_MASTER;
00218 }
00219 return MUSE_FRAME_MODE_ALL;
00220 }
00221
00222
00232
00233 static int
00234 muse_create_sky_create(cpl_plugin *aPlugin)
00235 {
00236
00237 cpl_recipe *recipe;
00238 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
00239 recipe = (cpl_recipe *)aPlugin;
00240 } else {
00241 return -1;
00242 }
00243
00244
00245
00246 muse_processinginfo_register(recipe,
00247 muse_create_sky_new_recipeconfig(),
00248 muse_create_sky_prepare_header,
00249 muse_create_sky_get_frame_level,
00250 muse_create_sky_get_frame_mode);
00251
00252
00253
00254 if (muse_cplframework() == MUSE_CPLFRAMEWORK_ESOREX) {
00255 cpl_msg_set_time_on();
00256 }
00257
00258
00259 recipe->parameters = cpl_parameterlist_new();
00260
00261 cpl_parameter *p;
00262
00263
00264 p = cpl_parameter_new_value("muse.muse_create_sky.fraction",
00265 CPL_TYPE_DOUBLE,
00266 "Fraction of the image (without the ignored part) to be considered as sky. If an input sky mask is provided, the fraction is applied to the regions within the mask. If the whole sky mask should be used, set this parameter to 1.",
00267 "muse.muse_create_sky",
00268 (double)0.75);
00269 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "fraction");
00270 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fraction");
00271
00272 cpl_parameterlist_append(recipe->parameters, p);
00273
00274
00275 p = cpl_parameter_new_value("muse.muse_create_sky.ignore",
00276 CPL_TYPE_DOUBLE,
00277 "Fraction of the image to be ignored. If an input sky mask is provided, the fraction is applied to the regions within the mask. If the whole sky mask should be used, set this parameter to 0.",
00278 "muse.muse_create_sky",
00279 (double)0.05);
00280 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "ignore");
00281 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ignore");
00282
00283 cpl_parameterlist_append(recipe->parameters, p);
00284
00285
00286 p = cpl_parameter_new_value("muse.muse_create_sky.sampling",
00287 CPL_TYPE_DOUBLE,
00288 "Spectral sampling of the sky spectrum [Angstrom].",
00289 "muse.muse_create_sky",
00290 (double)0.3125);
00291 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "sampling");
00292 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sampling");
00293 if (!getenv("MUSE_EXPERT_USER")) {
00294 cpl_parameter_disable(p, CPL_PARAMETER_MODE_CLI);
00295 }
00296
00297 cpl_parameterlist_append(recipe->parameters, p);
00298
00299
00300 p = cpl_parameter_new_value("muse.muse_create_sky.csampling",
00301 CPL_TYPE_DOUBLE,
00302 "Spectral sampling of the continuum spectrum [Angstrom].",
00303 "muse.muse_create_sky",
00304 (double)0.3125);
00305 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "csampling");
00306 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "csampling");
00307 if (!getenv("MUSE_EXPERT_USER")) {
00308 cpl_parameter_disable(p, CPL_PARAMETER_MODE_CLI);
00309 }
00310
00311 cpl_parameterlist_append(recipe->parameters, p);
00312
00313
00314 p = cpl_parameter_new_value("muse.muse_create_sky.crsigma",
00315 CPL_TYPE_STRING,
00316 "Sigma level clipping for cube-based and spectrum-based CR rejection. This has to be a string of two comma-separated floating-point numbers. The first value gives the sigma-level rejection for cube-based CR rejection (using \"median\", see muse_scipost), the second value the sigma-level for spectrum-based CR cleaning. Both can be switched off, by passing zero or a negative value; by default, the spectrum-based rejection is switched off.",
00317 "muse.muse_create_sky",
00318 (const char *)"15.,15.");
00319 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "crsigma");
00320 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "crsigma");
00321 if (!getenv("MUSE_EXPERT_USER")) {
00322 cpl_parameter_disable(p, CPL_PARAMETER_MODE_CLI);
00323 }
00324
00325 cpl_parameterlist_append(recipe->parameters, p);
00326
00327
00328 p = cpl_parameter_new_value("muse.muse_create_sky.lambdamin",
00329 CPL_TYPE_DOUBLE,
00330 "Cut off the data below this wavelength after loading the pixel table(s).",
00331 "muse.muse_create_sky",
00332 (double)4000.);
00333 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lambdamin");
00334 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lambdamin");
00335
00336 cpl_parameterlist_append(recipe->parameters, p);
00337
00338
00339 p = cpl_parameter_new_value("muse.muse_create_sky.lambdamax",
00340 CPL_TYPE_DOUBLE,
00341 "Cut off the data above this wavelength after loading the pixel table(s).",
00342 "muse.muse_create_sky",
00343 (double)10000.);
00344 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lambdamax");
00345 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lambdamax");
00346
00347 cpl_parameterlist_append(recipe->parameters, p);
00348
00349
00350 p = cpl_parameter_new_value("muse.muse_create_sky.lambdaref",
00351 CPL_TYPE_DOUBLE,
00352 "Reference wavelength used for correction of differential atmospheric refraction. The R-band (peak wavelength ~7000 Angstrom) that is usually used for guiding, is close to the central wavelength of MUSE, so a value of 7000.0 Angstrom should be used if nothing else is known. A value less than zero switches DAR correction off.",
00353 "muse.muse_create_sky",
00354 (double)7000.);
00355 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG, "lambdaref");
00356 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lambdaref");
00357
00358 cpl_parameterlist_append(recipe->parameters, p);
00359
00360 return 0;
00361 }
00362
00363
00374
00375 static int
00376 muse_create_sky_params_fill(muse_create_sky_params_t *aParams, cpl_parameterlist *aParameters)
00377 {
00378 cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
00379 cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
00380 cpl_parameter *p;
00381
00382 p = cpl_parameterlist_find(aParameters, "muse.muse_create_sky.fraction");
00383 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00384 aParams->fraction = cpl_parameter_get_double(p);
00385
00386 p = cpl_parameterlist_find(aParameters, "muse.muse_create_sky.ignore");
00387 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00388 aParams->ignore = cpl_parameter_get_double(p);
00389
00390 p = cpl_parameterlist_find(aParameters, "muse.muse_create_sky.sampling");
00391 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00392 aParams->sampling = cpl_parameter_get_double(p);
00393
00394 p = cpl_parameterlist_find(aParameters, "muse.muse_create_sky.csampling");
00395 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00396 aParams->csampling = cpl_parameter_get_double(p);
00397
00398 p = cpl_parameterlist_find(aParameters, "muse.muse_create_sky.crsigma");
00399 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00400 aParams->crsigma = cpl_parameter_get_string(p);
00401
00402 p = cpl_parameterlist_find(aParameters, "muse.muse_create_sky.lambdamin");
00403 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00404 aParams->lambdamin = cpl_parameter_get_double(p);
00405
00406 p = cpl_parameterlist_find(aParameters, "muse.muse_create_sky.lambdamax");
00407 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00408 aParams->lambdamax = cpl_parameter_get_double(p);
00409
00410 p = cpl_parameterlist_find(aParameters, "muse.muse_create_sky.lambdaref");
00411 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
00412 aParams->lambdaref = cpl_parameter_get_double(p);
00413
00414 return 0;
00415 }
00416
00417
00424
00425 static int
00426 muse_create_sky_exec(cpl_plugin *aPlugin)
00427 {
00428 if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
00429 return -1;
00430 }
00431 muse_processing_recipeinfo(aPlugin);
00432 cpl_recipe *recipe = (cpl_recipe *)aPlugin;
00433 cpl_msg_set_threadid_on();
00434
00435 cpl_frameset *usedframes = cpl_frameset_new(),
00436 *outframes = cpl_frameset_new();
00437 muse_create_sky_params_t params;
00438 muse_create_sky_params_fill(¶ms, recipe->parameters);
00439
00440 cpl_errorstate prestate = cpl_errorstate_get();
00441
00442 muse_processing *proc = muse_processing_new("muse_create_sky",
00443 recipe);
00444 int rc = muse_create_sky_compute(proc, ¶ms);
00445 cpl_frameset_join(usedframes, proc->usedframes);
00446 cpl_frameset_join(outframes, proc->outframes);
00447 muse_processing_delete(proc);
00448
00449 if (!cpl_errorstate_is_equal(prestate)) {
00450
00451 cpl_errorstate_dump(prestate, CPL_FALSE, muse_cplerrorstate_dump_some);
00452
00453 cpl_msg_set_level(CPL_MSG_INFO);
00454 }
00455
00456 muse_cplframeset_erase_duplicate(usedframes);
00457 muse_cplframeset_erase_duplicate(outframes);
00458
00459
00460
00461
00462
00463 muse_cplframeset_erase_all(recipe->frames);
00464 cpl_frameset_join(recipe->frames, usedframes);
00465 cpl_frameset_join(recipe->frames, outframes);
00466 cpl_frameset_delete(usedframes);
00467 cpl_frameset_delete(outframes);
00468 return rc;
00469 }
00470
00471
00478
00479 static int
00480 muse_create_sky_destroy(cpl_plugin *aPlugin)
00481 {
00482
00483 cpl_recipe *recipe;
00484 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
00485 recipe = (cpl_recipe *)aPlugin;
00486 } else {
00487 return -1;
00488 }
00489
00490
00491 cpl_parameterlist_delete(recipe->parameters);
00492 muse_processinginfo_delete(recipe);
00493 return 0;
00494 }
00495
00496
00506
00507 int
00508 cpl_plugin_get_info(cpl_pluginlist *aList)
00509 {
00510 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00511 cpl_plugin *plugin = &recipe->interface;
00512
00513 char *helptext;
00514 if (muse_cplframework() == MUSE_CPLFRAMEWORK_ESOREX) {
00515 helptext = cpl_sprintf("%s%s", muse_create_sky_help,
00516 muse_create_sky_help_esorex);
00517 } else {
00518 helptext = cpl_sprintf("%s", muse_create_sky_help);
00519 }
00520
00521
00522 cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
00523 CPL_PLUGIN_TYPE_RECIPE,
00524 "muse_create_sky",
00525 "Create night sky model from selected pixels of an exposure of empty sky.",
00526 helptext,
00527 "Ole Streicher",
00528 "usd-help@eso.org",
00529 muse_get_license(),
00530 muse_create_sky_create,
00531 muse_create_sky_exec,
00532 muse_create_sky_destroy);
00533 cpl_pluginlist_append(aList, plugin);
00534 cpl_free(helptext);
00535
00536 return 0;
00537 }
00538