35 #include "muse_geometry_z.h"
53 static const char *muse_geometry_help =
54 "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 mask 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. Finally, the geometry table is cleaned up from intermediate debug data and 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.";
56 static const char *muse_geometry_help_esorex =
57 "\n\nInput frames for raw frame tag \"MASK\":\n"
58 "\n Frame tag Type Req #Fr Description"
59 "\n -------------------- ---- --- --- ------------"
60 "\n MASK raw Y >=50 The full exposure sequence of raw multi-pinhole mask images"
61 "\n MASTER_BIAS calib Y 1 Master bias"
62 "\n MASTER_DARK calib . 1 Master dark"
63 "\n MASTER_FLAT calib . 1 Master flat"
64 "\n TRACE_TABLE calib Y 1 Trace table"
65 "\n WAVECAL_TABLE calib Y 1 Wavelength calibration table"
66 "\n LINE_CATALOG calib Y 1 List of arc lines"
67 "\n BADPIX_TABLE calib . 1 Known bad pixels"
68 "\n MASK_CHECK calib . Some other optional raw frame, ideally a trace mask exposure or something else with smooth features."
69 "\n\nProduct frames for raw frame tag \"MASK\":\n"
70 "\n Frame tag Level Description"
71 "\n -------------------- -------- ------------"
72 "\n MASK_REDUCED final Reduced pinhole mask images"
73 "\n MASK_COMBINED final Combined pinhole mask image"
74 "\n SPOTS_TABLE final Measurements of all detected spots on all input images."
75 "\n GEOMETRY_TABLE final Relative positions of the slices in the field of view"
76 "\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."
77 "\n GEOMETRY_CHECK final Optional field of view image to check the geometry calibration, integrated over the wavelength range given in the parameters.";
88 static cpl_recipeconfig *
89 muse_geometry_new_recipeconfig(
void)
91 cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
95 cpl_recipeconfig_set_tag(recipeconfig, tag, 50, -1);
96 cpl_recipeconfig_set_input(recipeconfig, tag,
"MASTER_BIAS", 1, 1);
97 cpl_recipeconfig_set_input(recipeconfig, tag,
"MASTER_DARK", -1, 1);
98 cpl_recipeconfig_set_input(recipeconfig, tag,
"MASTER_FLAT", -1, 1);
99 cpl_recipeconfig_set_input(recipeconfig, tag,
"TRACE_TABLE", 1, 1);
100 cpl_recipeconfig_set_input(recipeconfig, tag,
"WAVECAL_TABLE", 1, 1);
101 cpl_recipeconfig_set_input(recipeconfig, tag,
"LINE_CATALOG", 1, 1);
102 cpl_recipeconfig_set_input(recipeconfig, tag,
"BADPIX_TABLE", -1, 1);
103 cpl_recipeconfig_set_input(recipeconfig, tag,
"MASK_CHECK", -1, -1);
104 cpl_recipeconfig_set_output(recipeconfig, tag,
"MASK_REDUCED");
105 cpl_recipeconfig_set_output(recipeconfig, tag,
"MASK_COMBINED");
106 cpl_recipeconfig_set_output(recipeconfig, tag,
"SPOTS_TABLE");
107 cpl_recipeconfig_set_output(recipeconfig, tag,
"GEOMETRY_TABLE");
108 cpl_recipeconfig_set_output(recipeconfig, tag,
"GEOMETRY_CUBE");
109 cpl_recipeconfig_set_output(recipeconfig, tag,
"GEOMETRY_CHECK");
125 static cpl_error_code
126 muse_geometry_prepare_header(
const char *aFrametag, cpl_propertylist *aHeader)
128 cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
129 cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
130 if (!strcmp(aFrametag,
"MASK_REDUCED")) {
131 }
else if (!strcmp(aFrametag,
"MASK_COMBINED")) {
132 }
else if (!strcmp(aFrametag,
"SPOTS_TABLE")) {
135 "[pix] Average FWHM of all bright spots in exposure k.");
138 "[pix] Median FWHM of all bright spots in exposure k.");
141 "[pix] Standard deviation of FWHM of all bright spots in exposure k.");
142 }
else if (!strcmp(aFrametag,
"GEOMETRY_TABLE")) {
145 "[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.");
148 "[Angstrom] Nominal wavelength of arc line l.");
151 "Average integrated flux in all spots at reference wavelength l.");
154 "Median integrated flux in all spots at reference wavelength l.");
157 "Standard deviation of integrated flux in all spots at reference wavelength l.");
160 "[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.");
161 }
else if (!strcmp(aFrametag,
"GEOMETRY_CUBE")) {
162 }
else if (!strcmp(aFrametag,
"GEOMETRY_CHECK")) {
164 cpl_msg_warning(__func__,
"Frame tag %s is not defined", aFrametag);
165 return CPL_ERROR_ILLEGAL_INPUT;
167 return CPL_ERROR_NONE;
180 static cpl_frame_level
181 muse_geometry_get_frame_level(
const char *aFrametag)
184 return CPL_FRAME_LEVEL_NONE;
186 if (!strcmp(aFrametag,
"MASK_REDUCED")) {
187 return CPL_FRAME_LEVEL_FINAL;
189 if (!strcmp(aFrametag,
"MASK_COMBINED")) {
190 return CPL_FRAME_LEVEL_FINAL;
192 if (!strcmp(aFrametag,
"SPOTS_TABLE")) {
193 return CPL_FRAME_LEVEL_FINAL;
195 if (!strcmp(aFrametag,
"GEOMETRY_TABLE")) {
196 return CPL_FRAME_LEVEL_FINAL;
198 if (!strcmp(aFrametag,
"GEOMETRY_CUBE")) {
199 return CPL_FRAME_LEVEL_FINAL;
201 if (!strcmp(aFrametag,
"GEOMETRY_CHECK")) {
202 return CPL_FRAME_LEVEL_FINAL;
204 return CPL_FRAME_LEVEL_NONE;
218 muse_geometry_get_frame_mode(
const char *aFrametag)
223 if (!strcmp(aFrametag,
"MASK_REDUCED")) {
226 if (!strcmp(aFrametag,
"MASK_COMBINED")) {
229 if (!strcmp(aFrametag,
"SPOTS_TABLE")) {
232 if (!strcmp(aFrametag,
"GEOMETRY_TABLE")) {
235 if (!strcmp(aFrametag,
"GEOMETRY_CUBE")) {
238 if (!strcmp(aFrametag,
"GEOMETRY_CHECK")) {
256 muse_geometry_create(cpl_plugin *aPlugin)
260 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
261 recipe = (cpl_recipe *)aPlugin;
269 muse_geometry_new_recipeconfig(),
270 muse_geometry_prepare_header,
271 muse_geometry_get_frame_level,
272 muse_geometry_get_frame_mode);
277 cpl_msg_set_time_on();
281 recipe->parameters = cpl_parameterlist_new();
286 p = cpl_parameter_new_range(
"muse.muse_geometry.ifu1",
288 "First IFU to analyze.",
289 "muse.muse_geometry",
293 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ifu1");
294 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ifu1");
296 cpl_parameterlist_append(recipe->parameters, p);
299 p = cpl_parameter_new_range(
"muse.muse_geometry.ifu2",
301 "Last IFU to analyze.",
302 "muse.muse_geometry",
306 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ifu2");
307 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ifu2");
309 cpl_parameterlist_append(recipe->parameters, p);
312 p = cpl_parameter_new_value(
"muse.muse_geometry.sigma",
314 "Sigma detection level for spot detection, in terms of median deviation above the median.",
315 "muse.muse_geometry",
317 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"sigma");
318 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sigma");
320 cpl_parameterlist_append(recipe->parameters, p);
323 p = cpl_parameter_new_enum(
"muse.muse_geometry.centroid",
325 "Type of centroiding and FWHM determination to use for all spot measurements: simple barycenter method or using a Gaussian fit.",
326 "muse.muse_geometry",
327 (
const char *)
"gaussian",
329 (
const char *)
"barycenter",
330 (
const char *)
"gaussian");
331 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"centroid");
332 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"centroid");
334 cpl_parameterlist_append(recipe->parameters, p);
337 p = cpl_parameter_new_value(
"muse.muse_geometry.lambdamin",
339 "When passing any MASK_CHECK frames in the input, use this lower wavelength cut before reconstructing the image.",
340 "muse.muse_geometry",
342 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"lambdamin");
343 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"lambdamin");
345 cpl_parameterlist_append(recipe->parameters, p);
348 p = cpl_parameter_new_value(
"muse.muse_geometry.lambdamax",
350 "When passing any MASK_CHECK frames in the input, use this upper wavelength cut before reconstructing the image.",
351 "muse.muse_geometry",
353 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"lambdamax");
354 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"lambdamax");
356 cpl_parameterlist_append(recipe->parameters, p);
376 cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
377 cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
380 p = cpl_parameterlist_find(aParameters,
"muse.muse_geometry.ifu1");
381 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
382 aParams->
ifu1 = cpl_parameter_get_int(p);
384 p = cpl_parameterlist_find(aParameters,
"muse.muse_geometry.ifu2");
385 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
386 aParams->
ifu2 = cpl_parameter_get_int(p);
388 p = cpl_parameterlist_find(aParameters,
"muse.muse_geometry.sigma");
389 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
390 aParams->
sigma = cpl_parameter_get_double(p);
392 p = cpl_parameterlist_find(aParameters,
"muse.muse_geometry.centroid");
393 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
394 aParams->
centroid_s = cpl_parameter_get_string(p);
396 (!strcasecmp(aParams->
centroid_s,
"barycenter")) ? MUSE_GEOMETRY_PARAM_CENTROID_BARYCENTER :
397 (!strcasecmp(aParams->
centroid_s,
"gaussian")) ? MUSE_GEOMETRY_PARAM_CENTROID_GAUSSIAN :
398 MUSE_GEOMETRY_PARAM_CENTROID_INVALID_VALUE;
399 cpl_ensure_code(aParams->
centroid != MUSE_GEOMETRY_PARAM_CENTROID_INVALID_VALUE,
400 CPL_ERROR_ILLEGAL_INPUT);
402 p = cpl_parameterlist_find(aParameters,
"muse.muse_geometry.lambdamin");
403 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
404 aParams->
lambdamin = cpl_parameter_get_double(p);
406 p = cpl_parameterlist_find(aParameters,
"muse.muse_geometry.lambdamax");
407 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
408 aParams->
lambdamax = cpl_parameter_get_double(p);
422 muse_geometry_exec(cpl_plugin *aPlugin)
424 if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
427 cpl_recipe *recipe = (cpl_recipe *)aPlugin;
428 cpl_msg_set_threadid_on();
430 cpl_frameset *usedframes = cpl_frameset_new(),
431 *outframes = cpl_frameset_new();
433 muse_geometry_params_fill(¶ms, recipe->parameters);
435 cpl_errorstate prestate = cpl_errorstate_get();
439 int rc = muse_geometry_compute(proc, ¶ms);
440 cpl_frameset_join(usedframes, proc->
usedframes);
441 cpl_frameset_join(outframes, proc->
outframes);
444 if (!cpl_errorstate_is_equal(prestate)) {
448 cpl_msg_set_level(CPL_MSG_INFO);
459 cpl_frameset_join(recipe->frames, usedframes);
460 cpl_frameset_join(recipe->frames, outframes);
461 cpl_frameset_delete(usedframes);
462 cpl_frameset_delete(outframes);
475 muse_geometry_destroy(cpl_plugin *aPlugin)
479 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
480 recipe = (cpl_recipe *)aPlugin;
486 cpl_parameterlist_delete(recipe->parameters);
503 cpl_plugin_get_info(cpl_pluginlist *aList)
505 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe);
506 cpl_plugin *plugin = &recipe->interface;
510 helptext = cpl_sprintf(
"%s%s", muse_geometry_help,
511 muse_geometry_help_esorex);
513 helptext = cpl_sprintf(
"%s", muse_geometry_help);
517 cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
518 CPL_PLUGIN_TYPE_RECIPE,
520 "Compute relative location of the slices within the field of view and measure the instrumental PSF on the detectors.",
525 muse_geometry_create,
527 muse_geometry_destroy);
528 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...
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.
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.