ERIS Pipeline Reference Manual 1.8.10
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
86cpl_error_code eris_ifu_extract_spec_fetch_params(
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 *totalFlux = NULL;
213 hdrl_image *collapsedCube = NULL;
214 double startLambda = 0.,
215 deltaLambda = 0.,
216 refPixel = 0.;
217 cpl_propertylist *h = NULL,
218 *h_orig = NULL;
219
220 TRY
221 {
222 cpl_msg_info(cpl_func, "Reading recipe parameters");
224 eris_ifu_extract_spec_fetch_params(parlist, &params));
225
226 cpl_msg_info(cpl_func, "Reading SOF");
228 eris_ifu_extract_spec_processSof(frameset, &sof));
229
230 if (params.mask_method == MASK && sof.mask == NULL) {
231 BRK_WITH_ERROR_MSG(CPL_ERROR_NULL_INPUT,
232 "missing MASK input in the SOF which is required "
233 "if mask_method is MASK");
234 }
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");
238 }
239
240 h = sof.header,
241 h_orig = sof.header;
242 refPixel = cpl_propertylist_get_double(h, "CRPIX3");
243 if (cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) {
244 RECOVER();
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");
249 }
250 startLambda = cpl_propertylist_get_double(h, "CRVAL3");
251 if(cpl_propertylist_has(sof.header,"CDELT3")) {
252 deltaLambda = cpl_propertylist_get_double(h, "CDELT3");
253 } else {
254 deltaLambda = cpl_propertylist_get_double(h, "CD3_3");
255 }
256 startLambda = startLambda - (refPixel - 1.) * deltaLambda;
257
258 if (h_orig != h) {
260 }
262
263
265 collapsedCube = eris_ifu_extract_spec_collapse(sof.cube, &contribMap));
266 eris_ifu_free_image(&contribMap);
267
268// const cpl_parameter *par = cpl_parameterlist_find_const(parlist, "edge-trim");
269// if (par != NULL) {
270// edge_trim = cpl_parameter_get_int(par);
271// }
272// agudo: eventually take edge_trim in respect when creating mask?
274 mask = eris_ifu_extract_spec_create_mask(params, sof,
275 collapsedCube,
276 params.productDepth));
277
278 if (params.productDepth >= PD_ALL) {
280 pl = cpl_propertylist_duplicate(sof.header));
281
282 cpl_propertylist_update_string(pl, CPL_DFS_PRO_CATG, "COLLAPSED_IMAGE");
283 cpl_image_save(hdrl_image_get_image(collapsedCube),
284 "collapsedCube.fits", CPL_TYPE_FLOAT, pl, CPL_IO_CREATE);
285
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);
289 }
290
291 if (params.mask_method == OPTIMAL) {
293 spectrum = eris_ifu_optimal_extraction(sof.cube,
294 sof.qualImagelist,
295 mask,
296 startLambda, deltaLambda,
297 params.productDepth,
298 &error));
299 } else {
300
302 spectrum = eris_ifu_extract_spectrum(sof.cube, mask,
303 startLambda, deltaLambda,
304 &error, &totalFlux));
305
306 eris_ifu_free_image(&mask);
307 }
308
310 eris_ifu_extract_spec_save_products(frameset, parlist,
311 sof,
312 spectrum, error, totalFlux,
313 params.productDepth));
314 } CATCH {
315 CATCH_MSGS();
316 }
317
318 eris_ifu_free_vector(&error);
319 eris_ifu_free_vector(&totalFlux);
320 eris_ifu_free_image(&mask);
321 eris_ifu_free_bivector(&spectrum);
322 eris_ifu_free_hdrl_image(&collapsedCube);
323
324 return (int)cpl_error_get_code();
325}
326
327/*----------------------------------------------------------------------------*/
335/*----------------------------------------------------------------------------*/
336
337
338cpl_error_code eris_ifu_extract_spec_fetch_params(
339 const cpl_parameterlist * parlist,
340 struct esParamStruct *params)
341{
342 TRY
343 {
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;
358 } else {
359 cpl_msg_error(cpl_func, "The mask_method parameter must be one "
360 "of the list: mask, position, max, fit, optimal");
361 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
362 "Error reading recipe parameter, unknown mask method %s",
363 methodString);
364
365 }
366
367 const char* center;
368 center = cpl_parameter_get_string(
369 cpl_parameterlist_find_const(parlist,
370 CONTEXT".center"));
371 int nFields;
372 unsigned int end;
373 nFields = sscanf(center, "%d,%d%n",
374 &params->center_x, &params->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");
378 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
379 "Error reading recipe parameter, cannot properly read center spec %s",
380 center);
381 printf("Error reading center string\n");
382 }
383
384 params->radius = cpl_parameter_get_double(
385 cpl_parameterlist_find_const(parlist, CONTEXT".radius"));
386
387 params->productDepth = cpl_parameter_get_int(
388 cpl_parameterlist_find_const(parlist, CONTEXT".product_depth"));
389
391 } CATCH
392 {
393 }
394
395 return cpl_error_get_code();
396}
397
398/*----------------------------------------------------------------------------*/
407/*----------------------------------------------------------------------------*/
408
409cpl_error_code eris_ifu_extract_spec_processSof(
410 cpl_frameset* frames,
411// struct stdParamStruct stdParams,
412// struct esParamStruct params,
413 struct esSofStruct *sof)
414{
415 cpl_frame *frame = NULL;
416
417 TRY
418 {
419 if (frames == NULL) {
420 BRK_WITH_ERROR_MSG(CPL_ERROR_NULL_INPUT,
421 "missing frameset");
422 }
423 if (cpl_frameset_is_empty(frames)) {
424 BRK_WITH_ERROR_MSG(CPL_ERROR_NULL_INPUT,
425 "SOF file is empty or missing");
426 }
428
431
432 // get data cube
433 frame = cpl_frameset_find(frames, ERIS_IFU_UTIL_CUBE);
435 if (frame != NULL) {
438 cpl_frame_get_filename(frame),
439 &sof->header, &sof->qualImagelist, &sof->qualityType));
440 sof->nx = hdrl_imagelist_get_size_x(sof->cube);
441 sof->ny = hdrl_imagelist_get_size_y(sof->cube);
442 sof->nz = hdrl_imagelist_get_size(sof->cube);
443 } else {
444 BRK_WITH_ERROR_MSG(CPL_ERROR_NULL_INPUT,
445 "missing \"%s\" tag in the SOF, input data cube",
446 ERIS_IFU_UTIL_CUBE);
447
448 }
449
450 // get mask (optional
451 sof->mask = NULL;
452 frame = cpl_frameset_find(frames, ERIS_IFU_UTIL_MASK);
454 if (frame != NULL) {
456 sof->mask = cpl_image_load(
457 cpl_frame_get_filename(frame),
458 CPL_TYPE_DOUBLE, 0, 0));
459 }
460
461 } CATCH
462 {
463// CATCH_MSGS();
464 }
465
466 return cpl_error_get_code();
467
468}
469
470
471/*----------------------------------------------------------------------------*/
486/*----------------------------------------------------------------------------*/
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,
492 cpl_vector *error,
493 cpl_vector *totalFlux,
494 productDepthType productDepth)
495{
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;
504 double firstLambda;
505 double deltaLambda;
506 cpl_size spectrumSize;
507
508 TRY
509 {
510 spectrumSize = cpl_bivector_get_size(spectrum);
511 BRK_IF_NULL(lambda = cpl_bivector_get_x(spectrum));
512 BRK_IF_NULL(data = cpl_bivector_get_y(spectrum));
513 firstLambda = cpl_vector_get(lambda,0);
514 deltaLambda = cpl_vector_get(lambda,1) - firstLambda;
515
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");
540
543 cpl_vector_save(data, "spectrum_vector.fits",
544 CPL_TYPE_DOUBLE, pl, CPL_IO_CREATE));
545 cpl_propertylist_delete(pl);
546 }
547
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),
553 spectrumSize);
554 }
555 BRK_IF_NULL(pl = cpl_propertylist_duplicate(sof.header));
556 cpl_propertylist_update_string(pl, CPL_DFS_PRO_CATG, "SCIENCE.SPECTRUM");
557 BRK_IF_NULL(productTable = cpl_table_new(1));
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);
563 } else {
564 cpl_table_new_column_array(productTable, "TOT_FLUX",
565 CPL_TYPE_DOUBLE, spectrumSize);
566 }
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);
572 }
573 cpl_table_set_array(productTable, "WAVE", 0, waveArray);
574 if (totalFlux != NULL) {
575 cpl_table_set_array(productTable, "FLUX", 0, fluxArray);
576 } else {
577 cpl_table_set_array(productTable, "TOT_FLUX", 0, fluxArray);
578 }
579 cpl_table_set_array(productTable, "ERR", 0, errArray);
580 if (totalFlux != NULL) {
581 cpl_table_set_array(productTable, "TOT_FLUX", 0, totalFluxArray);
582 }
583 //cpl_table_save(productTable, pl, NULL, "spectrum.fits", CPL_IO_CREATE);
584
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");
588
589 cpl_propertylist_delete(pl);
591
592 } CATCH{
593 }
594
595 return cpl_error_get_code();
596}
597
598
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.
Definition: eris_ifu_dfs.c:63
#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
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.