ERIS Pipeline Reference Manual 1.8.15
eris_ifu_extract_spec.c
1/* $Id: eris_ifu_recipe.c,v 1.33 2013-03-26 17:00:45 jtaylor Exp $
2 *
3 * This file is part of the ERIS Pipeline
4 * Copyright (C) 2002,2003 European Southern Observatory
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/*
22 * $Author: erw $
23 * $Date: 2013-03-26 17:00:45 $
24 * $Revision: 1.33 $
25 * $Name: not supported by cvs2svn $
26 */
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31
32/*-----------------------------------------------------------------------------
33 Includes
34 -----------------------------------------------------------------------------*/
35#include <cpl.h>
36#include <string.h>
37#include <strings.h>
38#include <stdio.h>
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"
43
44/*-----------------------------------------------------------------------------
45 Static variables
46 -----------------------------------------------------------------------------*/
47#define CONTEXT "eris.eris_ifu_extract_spec"
48
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\
51\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\
57\n\
58-----------------------------------------------------------------------------\n\
59Input files:\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\
64\n\
65Output files:\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\
72\n\
73QC parameters:\n\
74None\n\
75";
76
77/*-----------------------------------------------------------------------------
78 Private function prototypes
79 -----------------------------------------------------------------------------*/
80
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);
85
87 const cpl_parameterlist * parlist,
88// struct stdParamStruct *stdParams,
89 struct esParamStruct *params);
90
91cpl_error_code eris_ifu_extract_spec_processSof(cpl_frameset* frames,
92 struct esSofStruct *sof);
93
94cpl_error_code eris_ifu_extract_spec_save_products(
95 cpl_frameset* frames,
96 const cpl_parameterlist * parlist,
97 struct esSofStruct sof,
98 cpl_bivector *spectrum,
99 cpl_vector *error,
100 cpl_vector *totalFlux,
101 productDepthType productDepth);
102/*-----------------------------------------------------------------------------
103 Function code
104 -----------------------------------------------------------------------------*/
105
106/*----------------------------------------------------------------------------*/
114/*----------------------------------------------------------------------------*/
115static cpl_error_code eris_ifu_extract_spec_fill_parameterlist(cpl_parameterlist *pl)
116{
117 cpl_error_code err = CPL_ERROR_NONE;
118 cpl_parameter *p = NULL;
119 char *pName = NULL;
120 char *context = NULL;
121
122 TRY
123 {
125 context = cpl_sprintf("eris.%s", REC_NAME_EXTRACT_SPEC));
126
127/*
128 BRK_IF_ERROR(
129 eris_ifu_add_std_params(pl, REC_NAME_EXTRACT_SPEC));
130*/
131 /* Fill the parameters list */
132 /* --mask_method */
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);
142 eris_ifu_free_string(&pName);
143
144 /* --centre */
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)",
150 context, "32,32"));
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);
154 eris_ifu_free_string(&pName);
155
156 /* --radius */
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)",
162 context, 4.0));
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);
166 eris_ifu_free_string(&pName);
167
168 // productDepthType pdMin = PD_SCIENCE;
169 // productDepthType pdMax = PD_DEBUG;
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)",
176 context, 0));
178 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
179 "product_depth"));
181 cpl_parameterlist_append(pl, p));
182 eris_ifu_free_string(&pName);
183
184
185
186 } CATCH {
187 err = cpl_error_get_code();
188 }
189 eris_ifu_free_string(&context);
190
191 return err;
192}
193
194/*----------------------------------------------------------------------------*/
201/*----------------------------------------------------------------------------*/
202static int eris_ifu_extract_spec(cpl_frameset *frameset,
203 const cpl_parameterlist * parlist)
204{
205 struct esParamStruct params;
206 struct esSofStruct sof;
207 cpl_propertylist *pl = NULL;
208 cpl_image *mask = NULL,
209 *contribMap = NULL;
210 cpl_bivector *spectrum = NULL;
211 cpl_vector *error = NULL,
212 *qual = NULL,
213 *totalFlux = NULL;
214 hdrl_image *collapsedCube = NULL;
215 double startLambda = 0.,
216 deltaLambda = 0.,
217 refPixel = 0.;
218 cpl_propertylist *h = NULL,
219 *h_orig = NULL;
220
221 TRY
222 {
223 cpl_msg_info(cpl_func, "Reading recipe parameters");
225 eris_ifu_extract_spec_fetch_params(parlist, &params));
226
227 cpl_msg_info(cpl_func, "Reading SOF");
229 eris_ifu_extract_spec_processSof(frameset, &sof));
230
231 if (params.mask_method == MASK && sof.mask == NULL) {
232 BRK_WITH_ERROR_MSG(CPL_ERROR_NULL_INPUT,
233 "missing MASK input in the SOF which is required "
234 "if mask_method is MASK");
235 }
236 if (params.mask_method != MASK && sof.mask != NULL) {
237 cpl_msg_warning(cpl_func,
238 "MASK input in the SOF is ignored because mask_method is not MASK");
239 }
240
241 h = sof.header,
242 h_orig = sof.header;
243 refPixel = cpl_propertylist_get_double(h, "CRPIX3");
244 if (cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) {
245 RECOVER();
246 cpl_frame *frame = cpl_frameset_find(frameset, ERIS_IFU_UTIL_CUBE);
247 h = cpl_propertylist_load(cpl_frame_get_filename(frame), 1);
248 refPixel = cpl_propertylist_get_double(h, "CRPIX3");
250 }
251 startLambda = cpl_propertylist_get_double(h, "CRVAL3");
252 if(cpl_propertylist_has(sof.header,"CDELT3")) {
253 deltaLambda = cpl_propertylist_get_double(h, "CDELT3");
254 } else {
255 deltaLambda = cpl_propertylist_get_double(h, "CD3_3");
256 }
257 startLambda = startLambda - (refPixel - 1.) * deltaLambda;
258
259 if (h_orig != h) {
261 }
263
264
266 collapsedCube = eris_ifu_extract_spec_collapse(sof.cube, &contribMap));
267 eris_ifu_free_image(&contribMap);
268
269// const cpl_parameter *par = cpl_parameterlist_find_const(parlist, "edge-trim");
270// if (par != NULL) {
271// edge_trim = cpl_parameter_get_int(par);
272// }
273// agudo: eventually take edge_trim in respect when creating mask?
275 mask = eris_ifu_extract_spec_create_mask(params, sof,
276 collapsedCube,
277 params.productDepth));
278
279 if (params.productDepth >= PD_ALL) {
281 pl = cpl_propertylist_duplicate(sof.header));
282
283 cpl_propertylist_update_string(pl, CPL_DFS_PRO_CATG, "COLLAPSED_IMAGE");
284 cpl_image_save(hdrl_image_get_image(collapsedCube),
285 "collapsedCube.fits", CPL_TYPE_FLOAT, pl, CPL_IO_CREATE);
286
287 cpl_propertylist_update_string(pl, CPL_DFS_PRO_CATG, "MASK");
288 cpl_image_save(mask, "mask.fits", CPL_TYPE_FLOAT, pl, CPL_IO_CREATE);
290 }
291
292 if (params.mask_method == OPTIMAL) {
294 spectrum = eris_ifu_optimal_extraction(sof.cube,
295 sof.qualImagelist,
296 mask,
297 startLambda, deltaLambda,
298 params.productDepth,
299 &error));
300 } else {
301
303 spectrum = eris_ifu_extract_spectrum(sof.cube, mask,
304 startLambda, deltaLambda,
305 &error, &totalFlux, &qual));
306
307 eris_ifu_free_image(&mask);
308 }
309
311 eris_ifu_extract_spec_save_products(frameset, parlist,
312 sof,
313 spectrum, error, totalFlux,
314 params.productDepth));
315 } CATCH {
316 CATCH_MSGS();
317 }
318
319 eris_ifu_free_vector(&error);
321 eris_ifu_free_vector(&totalFlux);
322 eris_ifu_free_image(&mask);
323 eris_ifu_free_bivector(&spectrum);
324 eris_ifu_free_hdrl_image(&collapsedCube);
325
326 return (int)cpl_error_get_code();
327}
328
329/*----------------------------------------------------------------------------*/
337/*----------------------------------------------------------------------------*/
338
339
341 const cpl_parameterlist * parlist,
342 struct esParamStruct *params)
343{
344 TRY
345 {
346 const char* methodString;
347 methodString = cpl_parameter_get_string(
348 cpl_parameterlist_find_const(parlist,
349 CONTEXT".mask_method"));
350 if (strncasecmp(methodString, "mask", strlen("mask")) == 0) {
351 params->mask_method = MASK;
352 } else if (strncasecmp(methodString, "position", strlen("position")) == 0) {
353 params->mask_method = POSITION;
354 } else if (strncasecmp(methodString, "max", strlen("max")) == 0) {
355 params->mask_method = MAX;
356 } else if (strncasecmp(methodString, "fit", strlen("fit")) == 0) {
357 params->mask_method = FIT;
358 } else if (strncasecmp(methodString, "optimal", strlen("optimal")) == 0) {
359 params->mask_method = OPTIMAL;
360 } else {
361 cpl_msg_error(cpl_func, "The mask_method parameter must be one "
362 "of the list: mask, position, max, fit, optimal");
363 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
364 "Error reading recipe parameter, unknown mask method %s",
365 methodString);
366
367 }
368
369 const char* center;
370 center = cpl_parameter_get_string(
371 cpl_parameterlist_find_const(parlist,
372 CONTEXT".center"));
373 int nFields;
374 unsigned int end;
375 nFields = sscanf(center, "%d,%d%n",
376 &params->center_x, &params->center_y, &end);
377 if (nFields != 2 || end != strlen(center)) {
378 cpl_msg_error(cpl_func, "The center parameter must be "
379 "a list of two integers separated by a comma");
380 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
381 "Error reading recipe parameter, cannot properly read center spec %s",
382 center);
383 printf("Error reading center string\n");
384 }
385
386 params->radius = cpl_parameter_get_double(
387 cpl_parameterlist_find_const(parlist, CONTEXT".radius"));
388
389 params->productDepth = cpl_parameter_get_int(
390 cpl_parameterlist_find_const(parlist, CONTEXT".product_depth"));
391
393 } CATCH
394 {
395 }
396
397 return cpl_error_get_code();
398}
399
400/*----------------------------------------------------------------------------*/
409/*----------------------------------------------------------------------------*/
410
411cpl_error_code eris_ifu_extract_spec_processSof(
412 cpl_frameset* frames,
413// struct stdParamStruct stdParams,
414// struct esParamStruct params,
415 struct esSofStruct *sof)
416{
417 cpl_frame *frame = NULL;
418
419 TRY
420 {
421 if (frames == NULL) {
422 BRK_WITH_ERROR_MSG(CPL_ERROR_NULL_INPUT,
423 "missing frameset");
424 }
425 if (cpl_frameset_is_empty(frames)) {
426 BRK_WITH_ERROR_MSG(CPL_ERROR_NULL_INPUT,
427 "SOF file is empty or missing");
428 }
430
433
434 // get data cube
435 frame = cpl_frameset_find(frames, ERIS_IFU_UTIL_CUBE);
437 if (frame != NULL) {
440 cpl_frame_get_filename(frame),
441 &sof->header, &sof->qualImagelist, &sof->qualityType));
442 sof->nx = hdrl_imagelist_get_size_x(sof->cube);
443 sof->ny = hdrl_imagelist_get_size_y(sof->cube);
444 sof->nz = hdrl_imagelist_get_size(sof->cube);
445 } else {
446 BRK_WITH_ERROR_MSG(CPL_ERROR_NULL_INPUT,
447 "missing \"%s\" tag in the SOF, input data cube",
448 ERIS_IFU_UTIL_CUBE);
449
450 }
451
452 // get mask (optional
453 sof->mask = NULL;
454 frame = cpl_frameset_find(frames, ERIS_IFU_UTIL_MASK);
456 if (frame != NULL) {
458 sof->mask = cpl_image_load(
459 cpl_frame_get_filename(frame),
460 CPL_TYPE_DOUBLE, 0, 0));
461 }
462
463 } CATCH
464 {
465// CATCH_MSGS();
466 }
467
468 return cpl_error_get_code();
469
470}
471
472
473/*----------------------------------------------------------------------------*/
488/*----------------------------------------------------------------------------*/
489cpl_error_code eris_ifu_extract_spec_save_products(
490 cpl_frameset* frames,
491 const cpl_parameterlist * parlist,
492 struct esSofStruct sof,
493 cpl_bivector *spectrum,
494 cpl_vector *error,
495 cpl_vector *totalFlux,
496 productDepthType productDepth)
497{
498 cpl_table *productTable = NULL;
499 cpl_propertylist *pl;
500 cpl_vector *lambda = NULL;
501 cpl_vector *data = NULL;
502 const cpl_array *waveArray = NULL;
503 const cpl_array *fluxArray = NULL;
504 const cpl_array *errArray = NULL;
505 const cpl_array *totalFluxArray = NULL;
506 double firstLambda;
507 double deltaLambda;
508 cpl_size spectrumSize;
509
510 TRY
511 {
512 spectrumSize = cpl_bivector_get_size(spectrum);
513 BRK_IF_NULL(lambda = cpl_bivector_get_x(spectrum));
514 BRK_IF_NULL(data = cpl_bivector_get_y(spectrum));
515 firstLambda = cpl_vector_get(lambda,0);
516 deltaLambda = cpl_vector_get(lambda,1) - firstLambda;
517
518 if (productDepth >= PD_AUXILLIARY) {
519 BRK_IF_NULL(pl = cpl_propertylist_duplicate(sof.header));
520 cpl_propertylist_update_string(pl, CPL_DFS_PRO_CATG, "SPECTRUM");
521 cpl_propertylist_update_string(pl, "CTYPE1", "WAVE");
522 cpl_propertylist_update_double(pl, "CRPIX1", 1.);
523 cpl_propertylist_update_double(pl, "CRVAL1", firstLambda);
524 cpl_propertylist_update_double(pl, "CDELT1", deltaLambda);
525 cpl_propertylist_erase(pl, "CTYPE2");
526 cpl_propertylist_erase(pl, "CRPIX2");
527 cpl_propertylist_erase(pl, "CRVAL2");
528 cpl_propertylist_erase(pl, "CDELT2");
529 cpl_propertylist_erase(pl, "CTYPE3");
530 cpl_propertylist_erase(pl, "CRPIX3");
531 cpl_propertylist_erase(pl, "CRVAL3");
532 cpl_propertylist_erase(pl, "CDELT3");
533 cpl_propertylist_update_double(pl, "CD1_1", 0.);
534 cpl_propertylist_update_double(pl, "CD1_2", deltaLambda);
535 cpl_propertylist_erase(pl, "CD1_3");
536 cpl_propertylist_erase(pl, "CD2_1");
537 cpl_propertylist_erase(pl, "CD2_2");
538 cpl_propertylist_erase(pl, "CD2_3");
539 cpl_propertylist_erase(pl, "CD3_1");
540 cpl_propertylist_erase(pl, "CD3_2");
541 cpl_propertylist_erase(pl, "CD3_3");
542
545 cpl_vector_save(data, "spectrum_vector.fits",
546 CPL_TYPE_DOUBLE, pl, CPL_IO_CREATE));
547 cpl_propertylist_delete(pl);
548 }
549
550 waveArray = cpl_array_wrap_double(cpl_vector_get_data(lambda), spectrumSize);
551 fluxArray = cpl_array_wrap_double(cpl_vector_get_data(data), spectrumSize);
552 errArray = cpl_array_wrap_double(cpl_vector_get_data(error), spectrumSize);
553 if (totalFlux != NULL) {
554 totalFluxArray = cpl_array_wrap_double(cpl_vector_get_data(totalFlux),
555 spectrumSize);
556 }
557 BRK_IF_NULL(pl = cpl_propertylist_duplicate(sof.header));
558 cpl_propertylist_update_string(pl, CPL_DFS_PRO_CATG, "SCIENCE.SPECTRUM");
559 BRK_IF_NULL(productTable = cpl_table_new(1));
560 cpl_table_new_column_array(productTable, "WAVE",
561 CPL_TYPE_DOUBLE, spectrumSize);
562 if (totalFlux != NULL) {
563 cpl_table_new_column_array(productTable, "FLUX",
564 CPL_TYPE_DOUBLE, spectrumSize);
565 } else {
566 cpl_table_new_column_array(productTable, "TOT_FLUX",
567 CPL_TYPE_DOUBLE, spectrumSize);
568 }
569 cpl_table_new_column_array(productTable, "ERR",
570 CPL_TYPE_DOUBLE, spectrumSize);
571 if (totalFlux != NULL) {
572 cpl_table_new_column_array(productTable, "TOT_FLUX",
573 CPL_TYPE_DOUBLE, spectrumSize);
574 }
575 cpl_table_set_array(productTable, "WAVE", 0, waveArray);
576 if (totalFlux != NULL) {
577 cpl_table_set_array(productTable, "FLUX", 0, fluxArray);
578 } else {
579 cpl_table_set_array(productTable, "TOT_FLUX", 0, fluxArray);
580 }
581 cpl_table_set_array(productTable, "ERR", 0, errArray);
582 if (totalFlux != NULL) {
583 cpl_table_set_array(productTable, "TOT_FLUX", 0, totalFluxArray);
584 }
585 //cpl_table_save(productTable, pl, NULL, "spectrum.fits", CPL_IO_CREATE);
586
587 cpl_dfs_save_table(frames, NULL, parlist, frames, NULL,
588 productTable, NULL, REC_NAME_EXTRACT_SPEC, pl,
589 NULL, PACKAGE "/" PACKAGE_VERSION, "spectrum.fits");
590
591 cpl_propertylist_delete(pl);
593
594 } CATCH{
595 }
596
597 return cpl_error_get_code();
598}
599
600
hdrl_imagelist * eris_ifu_load_deq_hdrl_imagelist(const char *filename, cpl_propertylist **primaryHeader, cpl_imagelist **qualImagelist, deqQualityType *qualityType)
Load a DEQ-format cube into an HDRL imagelist structure.
cpl_error_code eris_ifu_dfs_set_groups(cpl_frameset *self)
Set the frame group (RAW, CALIB, or PRODUCT) for all frames in a frameset.
Definition: eris_ifu_dfs.c:89
#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.
cpl_error_code eris_ifu_extract_spec(const cpl_imagelist *data_in, const cpl_imagelist *noise_in, cpl_image *mask, cpl_vector **spec_data_out, cpl_vector **spec_noise_out)
Extract a spectrum from 3D data cube.
cpl_error_code eris_ifu_extract_spec_fetch_params(const cpl_parameterlist *parlist, struct esParamStruct *params, const char *context)
Fetch spectral extraction parameters from parameter list.
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
Definition: hdrl_image.c:105
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.