39#include "eris_ifu_dfs.h"
40#include "eris_ifu_utils.h"
41#include "eris_ifu_error.h"
42#include "eris_ifu_extract_spec_static.h"
47#define CONTEXT "eris.eris_ifu_extract_spec"
49static const char eris_ifu_extract_spec_description[] =
"\
50This recipe extract a single spectrum from a masked spatial area of an ERIS/SPIFFIER cube.\n\
52The area mask can be specified in the following ways selected by the \"mask_method\" recipe parameter:\n\
53- mask: a user supplied mask in the SOF (tag is MASK)\n\
54- position: a user specified circle (\"center\" and \"radius\")\n\
55- max: a circle (with \"radius\") around the position of the maximum of the median collapsed cube\n\
56- fit: a two dimensional gaussian fit of the median collapsed cube (NOT YET IMPLEMENTED!)\n\
58-----------------------------------------------------------------------------\n\
60 DO CATG Explanation Required #Frames\n\
61 ------- ----------- -------- -------\n\
62 CUBE ERIS/SPIFFIER cube Y 1 \n\
63 MASK spatial mask file N [0,1]\n\
66 DO CATG Explanation Product Depth \n\
67 ------- ------------------------------------------- --------------\n\
68 SCIENCE.SPECTRUM extracted spectrum (table) PD_SCIENCE (0)\n\
69 SPECTRUM extracted spectrum (vector) PD_AUX (1)\n\
70 MASK generated and used spatial mask PD_ALL (2)\n\
71 COLLAPSED_CUBE generated and used collapsed cube image PD_ALL (2)\n\
81cpl_recipe_define(eris_ifu_extract_spec, ERIS_BINARY_VERSION,
"Erich Wiezorrek",
82 "erw@mpe.mpg.de",
"2022",
83 "This recipe extracts a spectrum for a data cube",
84 eris_ifu_extract_spec_description);
86cpl_error_code eris_ifu_extract_spec_fetch_params(
87 const cpl_parameterlist * parlist,
89 struct esParamStruct *params);
91cpl_error_code eris_ifu_extract_spec_processSof(cpl_frameset* frames,
92 struct esSofStruct *sof);
94cpl_error_code eris_ifu_extract_spec_save_products(
96 const cpl_parameterlist * parlist,
97 struct esSofStruct sof,
98 cpl_bivector *spectrum,
100 cpl_vector *totalFlux,
101 productDepthType productDepth);
115static cpl_error_code eris_ifu_extract_spec_fill_parameterlist(cpl_parameterlist *pl)
117 cpl_error_code err = CPL_ERROR_NONE;
118 cpl_parameter *p = NULL;
120 char *context = NULL;
125 context = cpl_sprintf(
"eris.%s", REC_NAME_EXTRACT_SPEC));
134 pName = cpl_sprintf(
"%s.%s", context,
"mask_method"));
136 p = cpl_parameter_new_value(pName, CPL_TYPE_STRING,
137 "Method to specify extraction mask : mask, position, max, fit or optimal",
138 context,
"optimal"));
139 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"mask_method");
140 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
141 cpl_parameterlist_append(pl, p);
146 pName = cpl_sprintf(
"%s.%s", context,
"center"));
148 p = cpl_parameter_new_value(pName, CPL_TYPE_STRING,
149 "The centre of the circular mask (pixel)",
151 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"center");
152 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
153 cpl_parameterlist_append(pl, p);
158 pName = cpl_sprintf(
"%s.%s", context,
"radius"));
160 p = cpl_parameter_new_value(pName, CPL_TYPE_DOUBLE,
161 "The radius of the circular mask (pixel)",
163 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"radius");
164 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
165 cpl_parameterlist_append(pl, p);
171 pName = cpl_sprintf(
"%s.%s", context,
"product_depth"));
173 p = cpl_parameter_new_value(pName, CPL_TYPE_INT,
174 "Specifies the product output depth "
175 "(>0 for auxiliary products)",
178 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
181 cpl_parameterlist_append(pl, p));
187 err = cpl_error_get_code();
202static int eris_ifu_extract_spec(cpl_frameset *frameset,
203 const cpl_parameterlist * parlist)
205 struct esParamStruct params;
206 struct esSofStruct sof;
207 cpl_propertylist *pl = NULL;
208 cpl_image *mask = NULL,
210 cpl_bivector *spectrum = NULL;
211 cpl_vector *error = NULL,
213 hdrl_image *collapsedCube = NULL;
214 double startLambda = 0.,
217 cpl_propertylist *h = NULL,
222 cpl_msg_info(cpl_func,
"Reading recipe parameters");
224 eris_ifu_extract_spec_fetch_params(parlist, ¶ms));
226 cpl_msg_info(cpl_func,
"Reading SOF");
228 eris_ifu_extract_spec_processSof(frameset, &sof));
230 if (params.mask_method == MASK && sof.mask == NULL) {
232 "missing MASK input in the SOF which is required "
233 "if mask_method is MASK");
235 if (params.mask_method != MASK && sof.mask != NULL) {
236 cpl_msg_warning(cpl_func,
237 "MASK input in the SOF is ignored because mask_method is not MASK");
242 refPixel = cpl_propertylist_get_double(h,
"CRPIX3");
243 if (cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) {
245 cpl_frame *frame = cpl_frameset_find(frameset, ERIS_IFU_UTIL_CUBE);
246 h = cpl_propertylist_load(cpl_frame_get_filename(frame), 1);
247 refPixel = cpl_propertylist_get_double(h,
"CRPIX3");
250 startLambda = cpl_propertylist_get_double(h,
"CRVAL3");
251 if(cpl_propertylist_has(sof.header,
"CDELT3")) {
252 deltaLambda = cpl_propertylist_get_double(h,
"CDELT3");
254 deltaLambda = cpl_propertylist_get_double(h,
"CD3_3");
256 startLambda = startLambda - (refPixel - 1.) * deltaLambda;
265 collapsedCube = eris_ifu_extract_spec_collapse(sof.cube, &contribMap));
274 mask = eris_ifu_extract_spec_create_mask(params, sof,
276 params.productDepth));
278 if (params.productDepth >= PD_ALL) {
280 pl = cpl_propertylist_duplicate(sof.header));
282 cpl_propertylist_update_string(pl, CPL_DFS_PRO_CATG,
"COLLAPSED_IMAGE");
284 "collapsedCube.fits", CPL_TYPE_FLOAT, pl, CPL_IO_CREATE);
286 cpl_propertylist_update_string(pl, CPL_DFS_PRO_CATG,
"MASK");
287 cpl_image_save(mask,
"mask.fits", CPL_TYPE_FLOAT, pl, CPL_IO_CREATE);
291 if (params.mask_method == OPTIMAL) {
293 spectrum = eris_ifu_optimal_extraction(sof.cube,
296 startLambda, deltaLambda,
302 spectrum = eris_ifu_extract_spectrum(sof.cube, mask,
303 startLambda, deltaLambda,
304 &error, &totalFlux));
310 eris_ifu_extract_spec_save_products(frameset, parlist,
312 spectrum, error, totalFlux,
313 params.productDepth));
324 return (
int)cpl_error_get_code();
338cpl_error_code eris_ifu_extract_spec_fetch_params(
339 const cpl_parameterlist * parlist,
340 struct esParamStruct *params)
344 const char* methodString;
345 methodString = cpl_parameter_get_string(
346 cpl_parameterlist_find_const(parlist,
347 CONTEXT
".mask_method"));
348 if (strncasecmp(methodString,
"mask", strlen(
"mask")) == 0) {
349 params->mask_method = MASK;
350 }
else if (strncasecmp(methodString,
"position", strlen(
"position")) == 0) {
351 params->mask_method = POSITION;
352 }
else if (strncasecmp(methodString,
"max", strlen(
"max")) == 0) {
353 params->mask_method = MAX;
354 }
else if (strncasecmp(methodString,
"fit", strlen(
"fit")) == 0) {
355 params->mask_method = FIT;
356 }
else if (strncasecmp(methodString,
"optimal", strlen(
"optimal")) == 0) {
357 params->mask_method = OPTIMAL;
359 cpl_msg_error(cpl_func,
"The mask_method parameter must be one "
360 "of the list: mask, position, max, fit, optimal");
362 "Error reading recipe parameter, unknown mask method %s",
368 center = cpl_parameter_get_string(
369 cpl_parameterlist_find_const(parlist,
373 nFields = sscanf(center,
"%d,%d%n",
374 ¶ms->center_x, ¶ms->center_y, &end);
375 if (nFields != 2 || end != strlen(center)) {
376 cpl_msg_error(cpl_func,
"The center parameter must be "
377 "a list of two integers separated by a comma");
379 "Error reading recipe parameter, cannot properly read center spec %s",
381 printf(
"Error reading center string\n");
384 params->radius = cpl_parameter_get_double(
385 cpl_parameterlist_find_const(parlist, CONTEXT
".radius"));
387 params->productDepth = cpl_parameter_get_int(
388 cpl_parameterlist_find_const(parlist, CONTEXT
".product_depth"));
395 return cpl_error_get_code();
409cpl_error_code eris_ifu_extract_spec_processSof(
410 cpl_frameset* frames,
413 struct esSofStruct *sof)
415 cpl_frame *frame = NULL;
419 if (frames == NULL) {
423 if (cpl_frameset_is_empty(frames)) {
425 "SOF file is empty or missing");
433 frame = cpl_frameset_find(frames, ERIS_IFU_UTIL_CUBE);
438 cpl_frame_get_filename(frame),
439 &sof->header, &sof->qualImagelist, &sof->qualityType));
445 "missing \"%s\" tag in the SOF, input data cube",
452 frame = cpl_frameset_find(frames, ERIS_IFU_UTIL_MASK);
456 sof->mask = cpl_image_load(
457 cpl_frame_get_filename(frame),
458 CPL_TYPE_DOUBLE, 0, 0));
466 return cpl_error_get_code();
487cpl_error_code eris_ifu_extract_spec_save_products(
488 cpl_frameset* frames,
489 const cpl_parameterlist * parlist,
490 struct esSofStruct sof,
491 cpl_bivector *spectrum,
493 cpl_vector *totalFlux,
494 productDepthType productDepth)
496 cpl_table *productTable = NULL;
497 cpl_propertylist *pl;
498 cpl_vector *lambda = NULL;
499 cpl_vector *data = NULL;
500 const cpl_array *waveArray = NULL;
501 const cpl_array *fluxArray = NULL;
502 const cpl_array *errArray = NULL;
503 const cpl_array *totalFluxArray = NULL;
506 cpl_size spectrumSize;
510 spectrumSize = cpl_bivector_get_size(spectrum);
511 BRK_IF_NULL(lambda = cpl_bivector_get_x(spectrum));
513 firstLambda = cpl_vector_get(lambda,0);
514 deltaLambda = cpl_vector_get(lambda,1) - firstLambda;
516 if (productDepth >= PD_AUXILLIARY) {
517 BRK_IF_NULL(pl = cpl_propertylist_duplicate(sof.header));
518 cpl_propertylist_update_string(pl, CPL_DFS_PRO_CATG,
"SPECTRUM");
519 cpl_propertylist_update_string(pl,
"CTYPE1",
"WAVE");
520 cpl_propertylist_update_double(pl,
"CRPIX1", 1.);
521 cpl_propertylist_update_double(pl,
"CRVAL1", firstLambda);
522 cpl_propertylist_update_double(pl,
"CDELT1", deltaLambda);
523 cpl_propertylist_erase(pl,
"CTYPE2");
524 cpl_propertylist_erase(pl,
"CRPIX2");
525 cpl_propertylist_erase(pl,
"CRVAL2");
526 cpl_propertylist_erase(pl,
"CDELT2");
527 cpl_propertylist_erase(pl,
"CTYPE3");
528 cpl_propertylist_erase(pl,
"CRPIX3");
529 cpl_propertylist_erase(pl,
"CRVAL3");
530 cpl_propertylist_erase(pl,
"CDELT3");
531 cpl_propertylist_update_double(pl,
"CD1_1", 0.);
532 cpl_propertylist_update_double(pl,
"CD1_2", deltaLambda);
533 cpl_propertylist_erase(pl,
"CD1_3");
534 cpl_propertylist_erase(pl,
"CD2_1");
535 cpl_propertylist_erase(pl,
"CD2_2");
536 cpl_propertylist_erase(pl,
"CD2_3");
537 cpl_propertylist_erase(pl,
"CD3_1");
538 cpl_propertylist_erase(pl,
"CD3_2");
539 cpl_propertylist_erase(pl,
"CD3_3");
543 cpl_vector_save(data,
"spectrum_vector.fits",
544 CPL_TYPE_DOUBLE, pl, CPL_IO_CREATE));
545 cpl_propertylist_delete(pl);
548 waveArray = cpl_array_wrap_double(cpl_vector_get_data(lambda), spectrumSize);
549 fluxArray = cpl_array_wrap_double(cpl_vector_get_data(data), spectrumSize);
550 errArray = cpl_array_wrap_double(cpl_vector_get_data(error), spectrumSize);
551 if (totalFlux != NULL) {
552 totalFluxArray = cpl_array_wrap_double(cpl_vector_get_data(totalFlux),
555 BRK_IF_NULL(pl = cpl_propertylist_duplicate(sof.header));
556 cpl_propertylist_update_string(pl, CPL_DFS_PRO_CATG,
"SCIENCE.SPECTRUM");
558 cpl_table_new_column_array(productTable,
"WAVE",
559 CPL_TYPE_DOUBLE, spectrumSize);
560 if (totalFlux != NULL) {
561 cpl_table_new_column_array(productTable,
"FLUX",
562 CPL_TYPE_DOUBLE, spectrumSize);
564 cpl_table_new_column_array(productTable,
"TOT_FLUX",
565 CPL_TYPE_DOUBLE, spectrumSize);
567 cpl_table_new_column_array(productTable,
"ERR",
568 CPL_TYPE_DOUBLE, spectrumSize);
569 if (totalFlux != NULL) {
570 cpl_table_new_column_array(productTable,
"TOT_FLUX",
571 CPL_TYPE_DOUBLE, spectrumSize);
573 cpl_table_set_array(productTable,
"WAVE", 0, waveArray);
574 if (totalFlux != NULL) {
575 cpl_table_set_array(productTable,
"FLUX", 0, fluxArray);
577 cpl_table_set_array(productTable,
"TOT_FLUX", 0, fluxArray);
579 cpl_table_set_array(productTable,
"ERR", 0, errArray);
580 if (totalFlux != NULL) {
581 cpl_table_set_array(productTable,
"TOT_FLUX", 0, totalFluxArray);
585 cpl_dfs_save_table(frames, NULL, parlist, frames, NULL,
586 productTable, NULL, REC_NAME_EXTRACT_SPEC, pl,
587 NULL, PACKAGE
"/" PACKAGE_VERSION,
"spectrum.fits");
589 cpl_propertylist_delete(pl);
595 return cpl_error_get_code();
hdrl_imagelist * eris_ifu_load_deq_hdrl_imagelist(const char *filename, cpl_propertylist **primaryHeader, cpl_imagelist **qualImagelist, deqQualityType *qualityType)
Function to load an HDRL imagelist with quality extensions.
cpl_error_code eris_ifu_dfs_set_groups(cpl_frameset *self)
Set the group as RAW or CALIB in a frameset.
#define BRK_IF_ERROR(function)
If function is or returns an error != CPL_ERROR_NONE, then the try-block is exited.
#define RECOVER(void)
Recover the error state which was present during TRY (at the beginning of the try-block).
#define CHECK_ERROR_STATE(void)
Check the CPL error state, and exit the try-block if not CPL_ERROR_NONE.
#define BRK_WITH_ERROR_MSG(code,...)
Set a new CPL error, and exit the try-block.
#define TRY
Beginning of a TRY-block.
#define CATCH
End of a TRY-block, beginning of a CATCH-block.
#define BRK_IF_NULL(function)
If function is or returns a NULL pointer, then the try-block is exited.
#define CATCH_MSGS()
Displays an error message stack.
void eris_ifu_free_propertylist(cpl_propertylist **item)
free memory and set pointer to null
void eris_ifu_free_string(char **item)
free memory and set pointer to null
void eris_ifu_free_vector(cpl_vector **item)
free memory and set pointer to null
void eris_ifu_free_hdrl_image(hdrl_image **item)
free memory and set pointer to null
void eris_ifu_free_image(cpl_image **item)
free memory and set pointer to null
void eris_ifu_free_bivector(cpl_bivector **item)
free memory and set pointer to null
cpl_image * hdrl_image_get_image(hdrl_image *himg)
get data as cpl image
cpl_size hdrl_imagelist_get_size_y(const hdrl_imagelist *himlist)
Get number of rows of images in the imagelist.
cpl_size hdrl_imagelist_get_size(const hdrl_imagelist *himlist)
Get the number of images in the imagelist.
cpl_size hdrl_imagelist_get_size_x(const hdrl_imagelist *himlist)
Get number of colums of images in the imagelist.