35 #include "muse_geometry_z.h" 77 static const char *muse_geometry_help =
78 "Processing first works separately on each IFU of the raw input data (in parallel): it trims the raw data and records the overscan statistics, subtracts the bias and converts them from adu to count. Optionally, the dark can be subtracted and the data can be divided by the flat-field. The data of all input mask exposures is then averaged. The averaged image together with the trace table and wavelength calibration as well as the line catalog are used to detect spots. The detection windows are used to measure the spots on all images of the sequence, the result is saved, with information on the measured PSF, in the spots tables. Then properties of all slices are computed, first separately on each IFU to determine the peak position of the mask for each slice and its angle, subsequently the width and horizontal position. Then, the result of all IFUs is analyzed together to produce a refined horizontal position, applying global shifts to each IFU as needed. The vertical position is then determined using the known slice ordering on the sky; the relative peak positions are put into sequence, taking into account the vertical offsets of the pinholes in the mask. The table is then cleaned up from intermediate debug data. If the --smooth parameter is set to a positive value, it is used to do a sigma-clipped smoothing within each slicer stack, for a more regular appearance of the output table. The table is then saved. As a last optional step, additional raw input data is reduced using the newly geometry to produce an image of the field of view. If these exposures contain smooth features, they can be used as a visual check of the quality of the geometrical calibration.";
80 static const char *muse_geometry_help_esorex =
81 "\n\nInput frames for raw frame tag \"MASK\":\n" 82 "\n Frame tag Type Req #Fr Description" 83 "\n -------------------- ---- --- --- ------------" 84 "\n MASK raw Y >=50 The full exposure sequence of raw multi-pinhole mask images" 85 "\n MASTER_BIAS calib Y 1 Master bias" 86 "\n MASTER_DARK calib . 1 Master dark" 87 "\n MASTER_FLAT calib . 1 Master flat" 88 "\n TRACE_TABLE calib Y 1 Trace table" 89 "\n WAVECAL_TABLE calib Y 1 Wavelength calibration table" 90 "\n LINE_CATALOG calib Y 1 List of arc lines" 91 "\n BADPIX_TABLE calib . Known bad pixels" 92 "\n MASK_CHECK calib . Some other optional raw frame, ideally a trace mask exposure or something else with smooth features." 93 "\n\nProduct frames for raw frame tag \"MASK\":\n" 94 "\n Frame tag Level Description" 95 "\n -------------------- -------- ------------" 96 "\n MASK_REDUCED final Reduced pinhole mask images" 97 "\n MASK_COMBINED final Combined pinhole mask image" 98 "\n SPOTS_TABLE final Measurements of all detected spots on all input images." 99 "\n GEOMETRY_UNSMOOTHED final Relative positions of the slices in the field of view (unsmoothed)" 100 "\n GEOMETRY_TABLE final Relative positions of the slices in the field of view" 101 "\n GEOMETRY_CUBE final Cube of the field of view to check the geometry calibration. It is restricted to the wavelength range given in the parameters and contains an integrated image (\"white\") over this range." 102 "\n GEOMETRY_CHECK final Optional field of view image to check the geometry calibration, integrated over the wavelength range given in the parameters.";
113 static cpl_recipeconfig *
114 muse_geometry_new_recipeconfig(
void)
116 cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
118 cpl_recipeconfig_set_tag(recipeconfig,
"MASK", 50, -1);
119 cpl_recipeconfig_set_input(recipeconfig,
"MASK",
"MASTER_BIAS", 1, 1);
120 cpl_recipeconfig_set_input(recipeconfig,
"MASK",
"MASTER_DARK", -1, 1);
121 cpl_recipeconfig_set_input(recipeconfig,
"MASK",
"MASTER_FLAT", -1, 1);
122 cpl_recipeconfig_set_input(recipeconfig,
"MASK",
"TRACE_TABLE", 1, 1);
123 cpl_recipeconfig_set_input(recipeconfig,
"MASK",
"WAVECAL_TABLE", 1, 1);
124 cpl_recipeconfig_set_input(recipeconfig,
"MASK",
"LINE_CATALOG", 1, 1);
125 cpl_recipeconfig_set_input(recipeconfig,
"MASK",
"BADPIX_TABLE", -1, -1);
126 cpl_recipeconfig_set_input(recipeconfig,
"MASK",
"MASK_CHECK", -1, -1);
127 cpl_recipeconfig_set_output(recipeconfig,
"MASK",
"MASK_REDUCED");
128 cpl_recipeconfig_set_output(recipeconfig,
"MASK",
"MASK_COMBINED");
129 cpl_recipeconfig_set_output(recipeconfig,
"MASK",
"SPOTS_TABLE");
130 cpl_recipeconfig_set_output(recipeconfig,
"MASK",
"GEOMETRY_UNSMOOTHED");
131 cpl_recipeconfig_set_output(recipeconfig,
"MASK",
"GEOMETRY_TABLE");
132 cpl_recipeconfig_set_output(recipeconfig,
"MASK",
"GEOMETRY_CUBE");
148 static cpl_error_code
149 muse_geometry_prepare_header(
const char *aFrametag, cpl_propertylist *aHeader)
151 cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
152 cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
153 if (!strcmp(aFrametag,
"MASK_REDUCED")) {
154 }
else if (!strcmp(aFrametag,
"MASK_COMBINED")) {
155 }
else if (!strcmp(aFrametag,
"SPOTS_TABLE")) {
158 "[pix] Average FWHM of all bright spots in exposure k.");
161 "[pix] Median FWHM of all bright spots in exposure k.");
164 "[pix] Standard deviation of FWHM of all bright spots in exposure k.");
167 "[pix] Average of the average FWHM of all bright spots in all exposures.");
170 "[pix] Standard deviation of the average FWHM of all bright spots in all exposures.");
171 }
else if (!strcmp(aFrametag,
"GEOMETRY_UNSMOOTHED")) {
172 }
else if (!strcmp(aFrametag,
"GEOMETRY_TABLE")) {
175 "[deg] Angle of the mask with respect to the slicer system, computed as median angle of all slices of this IFU for which the measurement could be made.");
178 "[Angstrom] Nominal wavelength of arc line l.");
181 "Average integrated flux in all spots at reference wavelength l.");
184 "Median integrated flux in all spots at reference wavelength l.");
187 "Standard deviation of integrated flux in all spots at reference wavelength l.");
190 "[pix] Average position of the central gap between the 12 slices of IFU m.");
193 "[deg] Angle of the mask with respect to the slicer system, computed as median angle of all slices of all IFUs for which the measurement could be made.");
196 "[pix] Average of all mean central gap positions of all IFUs for which the measurement could be made.");
199 "[pix] Standard deviation of all mean central gap positions of all IFUs for which the measurement could be made.");
202 "Number of slices that were changed with respect to x position by smoothing. Gets set to -1 if smoothing is inactive.");
205 "Number of slices that were changed with respect to y position by smoothing. Gets set to -1 if smoothing is inactive.");
208 "Number of slices that were changed with respect to angle by smoothing. Gets set to -1 if smoothing is inactive.");
211 "Number of slices that were changed with respect to width by smoothing. Gets set to -1 if smoothing is inactive.");
212 }
else if (!strcmp(aFrametag,
"GEOMETRY_CUBE")) {
213 }
else if (!strcmp(aFrametag,
"GEOMETRY_CHECK")) {
215 cpl_msg_warning(__func__,
"Frame tag %s is not defined", aFrametag);
216 return CPL_ERROR_ILLEGAL_INPUT;
218 return CPL_ERROR_NONE;
231 static cpl_frame_level
232 muse_geometry_get_frame_level(
const char *aFrametag)
235 return CPL_FRAME_LEVEL_NONE;
237 if (!strcmp(aFrametag,
"MASK_REDUCED")) {
238 return CPL_FRAME_LEVEL_FINAL;
240 if (!strcmp(aFrametag,
"MASK_COMBINED")) {
241 return CPL_FRAME_LEVEL_FINAL;
243 if (!strcmp(aFrametag,
"SPOTS_TABLE")) {
244 return CPL_FRAME_LEVEL_FINAL;
246 if (!strcmp(aFrametag,
"GEOMETRY_UNSMOOTHED")) {
247 return CPL_FRAME_LEVEL_FINAL;
249 if (!strcmp(aFrametag,
"GEOMETRY_TABLE")) {
250 return CPL_FRAME_LEVEL_FINAL;
252 if (!strcmp(aFrametag,
"GEOMETRY_CUBE")) {
253 return CPL_FRAME_LEVEL_FINAL;
255 if (!strcmp(aFrametag,
"GEOMETRY_CHECK")) {
256 return CPL_FRAME_LEVEL_FINAL;
258 return CPL_FRAME_LEVEL_NONE;
272 muse_geometry_get_frame_mode(
const char *aFrametag)
277 if (!strcmp(aFrametag,
"MASK_REDUCED")) {
280 if (!strcmp(aFrametag,
"MASK_COMBINED")) {
283 if (!strcmp(aFrametag,
"SPOTS_TABLE")) {
286 if (!strcmp(aFrametag,
"GEOMETRY_UNSMOOTHED")) {
289 if (!strcmp(aFrametag,
"GEOMETRY_TABLE")) {
292 if (!strcmp(aFrametag,
"GEOMETRY_CUBE")) {
295 if (!strcmp(aFrametag,
"GEOMETRY_CHECK")) {
313 muse_geometry_create(cpl_plugin *aPlugin)
317 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
318 recipe = (cpl_recipe *)aPlugin;
326 muse_geometry_new_recipeconfig(),
327 muse_geometry_prepare_header,
328 muse_geometry_get_frame_level,
329 muse_geometry_get_frame_mode);
334 cpl_msg_set_time_on();
338 recipe->parameters = cpl_parameterlist_new();
343 p = cpl_parameter_new_range(
"muse.muse_geometry.ifu1",
345 "First IFU to analyze.",
346 "muse.muse_geometry",
350 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ifu1");
351 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ifu1");
352 if (!getenv(
"MUSE_EXPERT_USER")) {
353 cpl_parameter_disable(p, CPL_PARAMETER_MODE_CLI);
356 cpl_parameterlist_append(recipe->parameters, p);
359 p = cpl_parameter_new_range(
"muse.muse_geometry.ifu2",
361 "Last IFU to analyze.",
362 "muse.muse_geometry",
366 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ifu2");
367 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ifu2");
368 if (!getenv(
"MUSE_EXPERT_USER")) {
369 cpl_parameter_disable(p, CPL_PARAMETER_MODE_CLI);
372 cpl_parameterlist_append(recipe->parameters, p);
375 p = cpl_parameter_new_value(
"muse.muse_geometry.sigma",
377 "Sigma detection level for spot detection, in terms of median deviation above the median.",
378 "muse.muse_geometry",
380 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"sigma");
381 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sigma");
383 cpl_parameterlist_append(recipe->parameters, p);
386 p = cpl_parameter_new_enum(
"muse.muse_geometry.centroid",
388 "Type of centroiding and FWHM determination to use for all spot measurements: simple barycenter method or using a Gaussian fit.",
389 "muse.muse_geometry",
390 (
const char *)
"gaussian",
392 (
const char *)
"barycenter",
393 (
const char *)
"gaussian");
394 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"centroid");
395 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"centroid");
397 cpl_parameterlist_append(recipe->parameters, p);
400 p = cpl_parameter_new_value(
"muse.muse_geometry.smooth",
402 "Use this sigma-level cut for smoothing of the output table within each slicer stack. Set to non-positive value to deactivate smoothing.",
403 "muse.muse_geometry",
405 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"smooth");
406 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"smooth");
408 cpl_parameterlist_append(recipe->parameters, p);
411 p = cpl_parameter_new_value(
"muse.muse_geometry.lambdamin",
413 "When passing any MASK_CHECK frames in the input, use this lower wavelength cut before reconstructing the image.",
414 "muse.muse_geometry",
416 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"lambdamin");
417 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"lambdamin");
418 if (!getenv(
"MUSE_EXPERT_USER")) {
419 cpl_parameter_disable(p, CPL_PARAMETER_MODE_CLI);
422 cpl_parameterlist_append(recipe->parameters, p);
425 p = cpl_parameter_new_value(
"muse.muse_geometry.lambdamax",
427 "When passing any MASK_CHECK frames in the input, use this upper wavelength cut before reconstructing the image.",
428 "muse.muse_geometry",
430 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"lambdamax");
431 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"lambdamax");
432 if (!getenv(
"MUSE_EXPERT_USER")) {
433 cpl_parameter_disable(p, CPL_PARAMETER_MODE_CLI);
436 cpl_parameterlist_append(recipe->parameters, p);
456 cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
457 cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
460 p = cpl_parameterlist_find(aParameters,
"muse.muse_geometry.ifu1");
461 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
462 aParams->
ifu1 = cpl_parameter_get_int(p);
464 p = cpl_parameterlist_find(aParameters,
"muse.muse_geometry.ifu2");
465 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
466 aParams->
ifu2 = cpl_parameter_get_int(p);
468 p = cpl_parameterlist_find(aParameters,
"muse.muse_geometry.sigma");
469 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
470 aParams->
sigma = cpl_parameter_get_double(p);
472 p = cpl_parameterlist_find(aParameters,
"muse.muse_geometry.centroid");
473 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
474 aParams->
centroid_s = cpl_parameter_get_string(p);
476 (!strcasecmp(aParams->
centroid_s,
"barycenter")) ? MUSE_GEOMETRY_PARAM_CENTROID_BARYCENTER :
477 (!strcasecmp(aParams->
centroid_s,
"gaussian")) ? MUSE_GEOMETRY_PARAM_CENTROID_GAUSSIAN :
478 MUSE_GEOMETRY_PARAM_CENTROID_INVALID_VALUE;
479 cpl_ensure_code(aParams->
centroid != MUSE_GEOMETRY_PARAM_CENTROID_INVALID_VALUE,
480 CPL_ERROR_ILLEGAL_INPUT);
482 p = cpl_parameterlist_find(aParameters,
"muse.muse_geometry.smooth");
483 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
484 aParams->
smooth = cpl_parameter_get_double(p);
486 p = cpl_parameterlist_find(aParameters,
"muse.muse_geometry.lambdamin");
487 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
488 aParams->
lambdamin = cpl_parameter_get_double(p);
490 p = cpl_parameterlist_find(aParameters,
"muse.muse_geometry.lambdamax");
491 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
492 aParams->
lambdamax = cpl_parameter_get_double(p);
506 muse_geometry_exec(cpl_plugin *aPlugin)
508 if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
512 cpl_recipe *recipe = (cpl_recipe *)aPlugin;
513 cpl_msg_set_threadid_on();
515 cpl_frameset *usedframes = cpl_frameset_new(),
516 *outframes = cpl_frameset_new();
518 muse_geometry_params_fill(¶ms, recipe->parameters);
520 cpl_errorstate prestate = cpl_errorstate_get();
524 int rc = muse_geometry_compute(proc, ¶ms);
525 cpl_frameset_join(usedframes, proc->
usedframes);
526 cpl_frameset_join(outframes, proc->
outframes);
529 if (!cpl_errorstate_is_equal(prestate)) {
533 cpl_msg_set_level(CPL_MSG_INFO);
544 cpl_frameset_join(recipe->frames, usedframes);
545 cpl_frameset_join(recipe->frames, outframes);
546 cpl_frameset_delete(usedframes);
547 cpl_frameset_delete(outframes);
560 muse_geometry_destroy(cpl_plugin *aPlugin)
564 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
565 recipe = (cpl_recipe *)aPlugin;
571 cpl_parameterlist_delete(recipe->parameters);
588 cpl_plugin_get_info(cpl_pluginlist *aList)
590 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe);
591 cpl_plugin *plugin = &recipe->interface;
595 helptext = cpl_sprintf(
"%s%s", muse_geometry_help,
596 muse_geometry_help_esorex);
598 helptext = cpl_sprintf(
"%s", muse_geometry_help);
602 cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
603 CPL_PLUGIN_TYPE_RECIPE,
605 "Compute relative location of the slices within the field of view and measure the instrumental PSF on the detectors.",
610 muse_geometry_create,
612 muse_geometry_destroy);
613 cpl_pluginlist_append(aList, plugin);
void muse_processing_delete(muse_processing *aProcessing)
Free the muse_processing structure.
const char * centroid_s
Type of centroiding and FWHM determination to use for all spot measurements: simple barycenter method...
double sigma
Sigma detection level for spot detection, in terms of median deviation above the median.
double lambdamax
When passing any MASK_CHECK frames in the input, use this upper wavelength cut before reconstructing ...
muse_cplframework_type muse_cplframework(void)
Return the CPL framework the recipe is run under.
cpl_frameset * usedframes
muse_processing * muse_processing_new(const char *aName, cpl_recipe *aRecipe)
Create a new processing structure.
const char * muse_get_license(void)
Get the pipeline copyright and license.
void muse_cplerrorstate_dump_some(unsigned aCurrent, unsigned aFirst, unsigned aLast)
Dump some CPL errors.
void muse_processinginfo_delete(cpl_recipe *)
Clear all information from the processing info and from the recipe config.
int centroid
Type of centroiding and FWHM determination to use for all spot measurements: simple barycenter method...
double smooth
Use this sigma-level cut for smoothing of the output table within each slicer stack. Set to non-positive value to deactivate smoothing.
cpl_error_code muse_cplframeset_erase_duplicate(cpl_frameset *aFrames)
Erase all duplicate frames from a frameset.
int ifu2
Last IFU to analyze.
cpl_error_code muse_cplframeset_erase_all(cpl_frameset *aFrames)
Erase all frames in a frameset.
int ifu1
First IFU to analyze.
double lambdamin
When passing any MASK_CHECK frames in the input, use this lower wavelength cut before reconstructing ...
void muse_processinginfo_register(cpl_recipe *, cpl_recipeconfig *, muse_processing_prepare_header_func *, muse_processing_get_frame_level_func *, muse_processing_get_frame_mode_func *)
Register extended functionalities for MUSE recipes.
void muse_processing_recipeinfo(cpl_plugin *)
Output main pipeline configuration, inputs, and parameters.
cpl_error_code muse_processing_prepare_property(cpl_propertylist *, const char *, cpl_type, const char *)
Prepare and check the specified property.
Structure to hold the parameters of the muse_geometry recipe.