ERIS Pipeline Reference Manual 1.8.14
eris_ifu_extract_spec_static.c
1/* $Id$
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#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include "eris_ifu_extract_spec_static.h"
26#include "eris_ifu_vector.h"
27#include "eris_ifu_error.h"
28#include "eris_ifu_utils.h"
29#include "eris_utils.h"
30
36hdrl_image* eris_ifu_extract_spec_collapse(hdrl_imagelist *cube,
37 cpl_image **contribute)
38{
39 hdrl_image *hImage = NULL;
40
41 cpl_ensure(cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
42 cpl_ensure(contribute != NULL, CPL_ERROR_NULL_INPUT, NULL);
43
44 TRY{
46 hdrl_imagelist_collapse(cube, HDRL_COLLAPSE_MEDIAN,
47 &hImage, contribute));
48 } CATCH
49 {
51 eris_ifu_free_image(contribute);
52 }
53
54 return hImage;
55}
56
57void
58eris_ifu_extract_free_esSofStruct(struct esSofStruct* self){
59 if (self != NULL) {
60 eris_ifu_free_image(&self->mask);
61 eris_ifu_free_propertylist(&self->header);
62 eris_ifu_free_imagelist(&self->qualImagelist);
64 }
65
66}
67cpl_image * eris_ifu_extract_spec_create_fit_mask(const hdrl_image* img)
68{
69 cpl_image *mask = NULL;
70 const cpl_image *image = NULL;
71 cpl_array *gauss_params = NULL;
72 cpl_size nx, ny;
73 cpl_size xposcen, yposcen;
74 cpl_size xwinsize, ywinsize;
75
76 cpl_ensure(img, CPL_ERROR_NULL_INPUT, NULL);
77
78 TRY{
80
81 nx = cpl_image_get_size_x(image);
82 ny = cpl_image_get_size_y(image);
83 xposcen = nx / 2;
84 yposcen = ny / 2;
85 xwinsize = nx;
86 ywinsize = ny;
87
88 BRK_IF_NULL(gauss_params = cpl_array_new(7, CPL_TYPE_DOUBLE));
89 BRK_IF_ERROR(cpl_fit_image_gaussian(image, NULL, xposcen, yposcen,
90 xwinsize, ywinsize, gauss_params,
91 NULL, NULL, NULL,
92 NULL, NULL, NULL,
93 NULL, NULL, NULL));
94
95 mask = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
96
97 for (cpl_size iy=1; iy <= ny ; iy++) {
98 for (cpl_size ix=1; ix <= nx ; ix++) {
99 cpl_image_set(mask, ix, iy,
100 cpl_gaussian_eval_2d(gauss_params, (double) ix, (double) iy));
101 }
102 }
104
105
106 /* Normalise mask */
107 cpl_image_subtract_scalar(mask, cpl_image_get_min(mask));
108 cpl_image_divide_scalar(mask, cpl_image_get_max(mask));
109 cpl_array_delete(gauss_params);
111
112 } CATCH
113 {
114 mask = NULL;
115 }
116 return mask;
117}
118
119cpl_image * eris_ifu_extract_spec_create_circle_mask(
120 cpl_size center_x,
121 cpl_size center_y,
122 double radius,
123 cpl_size nx,
124 cpl_size ny)
125{
126 cpl_image *mask = NULL;
127 double cen_x, cen_y, x_lo, y_lo, x_hi, y_hi, r;
128 double *pmask;
129
130 cpl_ensure(center_x > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
131 cpl_ensure(center_y > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
132 cpl_ensure(radius > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
133 cpl_ensure(nx > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
134 cpl_ensure(ny > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
135
136 TRY{
137 mask = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
138 pmask = cpl_image_get_data_double(mask);
139
140 cen_x = (double) center_x - 1.0;
141 cen_y = (double) center_y - 1.0;
142 // draw circle
143 x_lo = floor(cen_x - radius);
144 if (x_lo < 0) x_lo = 0;
145 y_lo = floor(cen_y - radius);
146 if (y_lo < 0) y_lo = 0;
147 x_hi = ceil(cen_x + radius);
148 if (x_hi > nx) x_hi = (int) nx;
149 y_hi = ceil(cen_y + radius);
150 if (y_hi > ny) y_hi = (int) ny;
151 for (int x = (int) x_lo; x < x_hi; x++) {
152 for (int y = (int) y_lo; y < y_hi; y++) {
153 r = sqrt(pow(x - cen_x,2) + pow(y - cen_y,2));
154 if (r <= radius) pmask[x + y * nx] = 1.0;
155 }
156 }
157
158 } CATCH
159 {
160 mask = NULL;
161 }
162 return mask;
163}
164
178cpl_image * eris_ifu_extract_spec_create_mask(
179 struct esParamStruct params,
180 struct esSofStruct sof,
181 const hdrl_image *collapsedCube,
182 int productDepth)
183{
184 cpl_image *mask = NULL;
185 cpl_size nx;
186 cpl_size ny;
187 cpl_size center_x;
188 cpl_size center_y;
189 const cpl_image *img;
190
191 TRY{
192 switch (params.mask_method) {
193 case MASK:
194 mask = sof.mask;
195 break;
196 case MAX:
197 cpl_image_get_maxpos(
198 hdrl_image_get_image_const(collapsedCube), &center_x, &center_y);
201 mask = eris_ifu_extract_spec_create_circle_mask(center_x, center_y,
202 params.radius,
203 sof.nx, sof.ny));
204 break;
205 case POSITION:
207 mask = eris_ifu_extract_spec_create_circle_mask(params.center_x,
208 params.center_y,
209 params.radius,
210 sof.nx, sof.ny));
211 break;
212 case OPTIMAL:
213 // get maxpos
214 img = hdrl_image_get_image_const(collapsedCube);
215 cpl_image_get_maxpos(img, &center_x, &center_y);
217
218 // estimate radius by FWHM
219 double radius = eris_ifu_opt_extr_estimate_radius(img,
220 center_x, center_y,
221 params.radius,
222 productDepth);
223
224 // create mask
226 mask = eris_ifu_extract_spec_create_circle_mask(center_x, center_y,
227 radius,
228 sof.nx, sof.ny));
229 break;
230 case FIT:
232 mask = eris_ifu_extract_spec_create_fit_mask(collapsedCube));
233 break;
234 default:
235 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
236 "Internal error: unknown mask method %d",
237 params.mask_method);
238 }
239
240 nx = cpl_image_get_size_x(mask);
241 ny = cpl_image_get_size_y(mask);
242 if (nx != sof.nx || ny != sof.ny) {
243 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
244 "Dimensions of mask don't match with the cube");
245 }
246 } CATCH
247 {
248 mask = NULL;
249 }
250 return mask;
251}
252
253cpl_bivector * eris_ifu_extract_spectrum(hdrl_imagelist *cube,
254 cpl_image *mask,
255 double startLambda,
256 double deltaLambda,
257 cpl_vector **error,
258 cpl_vector **totalFlux,
259 cpl_vector **quality)
260{
261 cpl_bivector *spectrum = NULL;
262 cpl_imagelist *data_in = NULL;
263 cpl_imagelist *error_in = NULL;
264 const cpl_image *tmpDataImg = NULL;
265 const cpl_image *tmpErrorImg = NULL;
266 const cpl_mask *bpm = NULL;
267 const double *pTmpData = NULL;
268 const double *pTmpError = NULL;
269 const cpl_binary *pBpm = NULL;
270 const double *pMask = NULL;
271 cpl_size nx, ny, nz;
272 cpl_size fill_nz;
273 cpl_vector *lambda = NULL;
274 cpl_vector *spec_data = NULL;
275 cpl_vector *spec_error = NULL;
276 cpl_vector *spec_totFlux = NULL;
277 cpl_vector *spec_qual = NULL;
278 double *pLambda = NULL;
279 double *pData = NULL;
280 double *pError = NULL;
281 double *pTotFlux = NULL;
282 double *pqual = NULL;
283 double sumData;
284 double sumVariance;
285 double weights;
286 bool valid;
287
288
289 cpl_ensure(cube != NULL,CPL_ERROR_NULL_INPUT, NULL);
290 cpl_ensure(mask != NULL,CPL_ERROR_NULL_INPUT, NULL);
291 cpl_ensure(error != NULL,CPL_ERROR_NULL_INPUT, NULL);
292 cpl_ensure(totalFlux != NULL,CPL_ERROR_NULL_INPUT, NULL);
293
294 TRY{
295 nx = hdrl_imagelist_get_size_x(cube);
296 ny = hdrl_imagelist_get_size_y(cube);
297 nz = hdrl_imagelist_get_size(cube);
298
299 ASSURE((nx == cpl_image_get_size_x(mask)) &&
300 (ny == cpl_image_get_size_y(mask)),
301 CPL_ERROR_ILLEGAL_INPUT,
302 "Data cube and mask don't have same dimensions!");
303
304
305 BRK_IF_NULL(data_in = cpl_imagelist_new());
306 BRK_IF_NULL(error_in = cpl_imagelist_new());
307 for (cpl_size sz = 0; sz < nz; sz++) {
308 hdrl_image *tmpImg = hdrl_imagelist_get(cube, sz);
309 cpl_imagelist_set(data_in, cpl_image_duplicate(hdrl_image_get_image(tmpImg)), sz);
310 cpl_imagelist_set(error_in, cpl_image_duplicate(hdrl_image_get_error(tmpImg)), sz);
311 }
313
314 lambda = cpl_vector_new(nz);
315 spec_data = cpl_vector_new(nz);
316 spec_error = cpl_vector_new(nz);
317 spec_totFlux = cpl_vector_new(nz);
318 spec_qual = cpl_vector_new(nz);
319 pLambda = cpl_vector_get_data(lambda);
320 pData = cpl_vector_get_data(spec_data);
321 pError = cpl_vector_get_data(spec_error);
322 pTotFlux = cpl_vector_get_data(spec_totFlux);
323 pqual = cpl_vector_get_data(spec_qual);
324 pMask = cpl_image_get_data_double_const(mask);
326
327 // loop over all lambda slices
328 fill_nz = 0;
329 for (cpl_size sz = 0; sz < nz; sz++) {
330 tmpDataImg = cpl_imagelist_get(data_in, sz);
331 tmpErrorImg = cpl_imagelist_get(error_in, sz);
332 bpm = cpl_image_get_bpm_const(tmpDataImg);
333 pTmpData = cpl_image_get_data_double_const(tmpDataImg);
334 pTmpError = cpl_image_get_data_double_const(tmpErrorImg);
335 pBpm = cpl_mask_get_data_const(bpm);
337
338 // extract spectrum for data
339 sumData = 0.0;
340 sumVariance = 0.0;
341 weights = 0.0;
342 valid = false;
343 for (cpl_size j = 0; j < ny; j++) {
344 for (cpl_size i = 0; i < nx; i++) {
345 // sumData weighted pixels in spatial plane
346 cpl_size p = i+j*nx;
347 if ((pBpm[p] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[p])) {
348 valid = true;
349 if (mask != NULL) {
350 sumData += pTmpData[p] * pMask[p];
351 sumVariance += pow(pTmpError[p] * pMask[p],2);
352 weights += pMask[p];
353 /* AMo: temporarily added for debug to make some check on problematic data
354 if(startLambda + (double) sz * deltaLambda > 2.254 &&
355 startLambda + (double) sz * deltaLambda < 2.270 ) {
356 cpl_msg_info(cpl_func,"ok1: pMask[p]: %g",pMask[p]);
357 }
358 */
359 } else {
360 sumData += pTmpData[p];
361 sumVariance += pow(pTmpError[p],2);
362 weights += 1.;
363 }
364 }
365 }
366 }
367
368 if ((valid == true) && (fabs(weights) > DBL_ZERO_TOLERANCE)) {
369 pLambda[fill_nz] = startLambda + (double) sz * deltaLambda;
370 pData[fill_nz] = sumData / weights;
371 pError[fill_nz] = sqrt(sumVariance) / weights;
372 pTotFlux[fill_nz] = sumData;
373 pqual[fill_nz] = 0;
374 fill_nz++;
375 }
377 }
378 BRK_IF_ERROR(cpl_vector_set_size(lambda, fill_nz));
379 BRK_IF_ERROR(cpl_vector_set_size(spec_data, fill_nz));
380 BRK_IF_ERROR(cpl_vector_set_size(spec_error, fill_nz));
381 BRK_IF_ERROR(cpl_vector_set_size(spec_totFlux, fill_nz));
382 BRK_IF_ERROR(cpl_vector_set_size(spec_qual, fill_nz));
383
384 spectrum = cpl_bivector_wrap_vectors(lambda, spec_data);
385 *error = spec_error;
386 *totalFlux = spec_totFlux;
387 *quality = spec_qual;
388 cpl_imagelist_delete(data_in);
389 cpl_imagelist_delete(error_in);
390 } CATCH {
391 spectrum = NULL;
392 }
393 eris_check_error_code("eris_ifu_extract_spectrum");
394 return spectrum;
395}
396
397
398
399
400
401//cpl_bivector * eris_ifu_extract_spectrum2(
402// hdrl_imagelist *cube,
403// cpl_image *mask,
404// double startLambda,
405// double deltaLambda,
406// cpl_vector **error,
407// cpl_vector **totalFlux)
408//{
409// cpl_bivector *spectrum = NULL;
410// cpl_imagelist *data_in = NULL;
411// cpl_imagelist *error_in = NULL;
412// const cpl_image *tmpDataImg = NULL;
413// const cpl_image *tmpErrorImg = NULL;
414// const cpl_mask *bpm = NULL;
415// const double *pTmpData = NULL;
416// const double *pTmpError = NULL;
417// const cpl_binary *pBpm = NULL;
418// const double *pMask = NULL;
419// cpl_size nx, ny, nz;
420// cpl_size fill_nz;
421// cpl_vector *lambda = NULL;
422// cpl_vector *spec_data = NULL;
423// cpl_vector *spec_error = NULL;
424// cpl_vector *spec_totFlux = NULL;
425// double *pLambda = NULL;;
426// double *pData = NULL;;
427// double *pError = NULL;;
428// double *pTotFlux = NULL;;
429// double sumData;
430// double sumVariance;
431// double weights;
432// bool valid;
433
434// hdrl_image* cube_median = NULL;
435// cpl_image* cube_median_data = NULL;
436// cpl_image* cube_median_errs = NULL;
437// cpl_image* scale_factor_data = NULL;
438// cpl_image* scale_factor_errs = NULL;
439// const double *pFactorData = NULL;
441// const double *pModelData = NULL;
442// const double *pModelErrs = NULL;
445// double model_factor_avg = 0;
446
447// cpl_size model_ndata = 0;
448// const cpl_size kernel_sx = 5;
449// const cpl_size kernel_sy = 5;
450// cpl_image* contrib_map;
451
452// cpl_ensure(cube != NULL,CPL_ERROR_NULL_INPUT, NULL);
453// cpl_ensure(mask != NULL,CPL_ERROR_NULL_INPUT, NULL);
454// cpl_ensure(error != NULL,CPL_ERROR_NULL_INPUT, NULL);
455
456// TRY{
457// nx = hdrl_imagelist_get_size_x(cube);
458// ny = hdrl_imagelist_get_size_y(cube);
459// nz = hdrl_imagelist_get_size(cube);
460
461// ASSURE((nx == cpl_image_get_size_x(mask)) &&
462// (ny == cpl_image_get_size_y(mask)),
463// CPL_ERROR_ILLEGAL_INPUT,
464// "Data cube and mask don't have same dimensions!");
465// eris_print_rec_status(0);
466// hdrl_imagelist_collapse_median(cube, &cube_median, &contrib_map);
467// eris_print_rec_status(1);
468// cube_median_data = hdrl_image_get_image(cube_median);
469// cube_median_errs = hdrl_image_get_error(cube_median);
470// cpl_image_save(cube_median_data,"cube_median_data.fits",CPL_TYPE_DOUBLE,NULL,CPL_IO_DEFAULT);
471// eris_print_rec_status(2);
472// data_in = cpl_imagelist_new();
473// error_in = cpl_imagelist_new();
474// for (cpl_size sz = 0; sz < nz; sz++) {
475// hdrl_image *tmpImg = hdrl_imagelist_get(cube, sz);
476// cpl_imagelist_set(data_in, cpl_image_duplicate(hdrl_image_get_image(tmpImg)), sz);
477// cpl_imagelist_set(error_in, cpl_image_duplicate(hdrl_image_get_error(tmpImg)), sz);
478// }
479// CHECK_ERROR_STATE();
480
481// lambda = cpl_vector_new(nz);
482// spec_data = cpl_vector_new(nz);
483// spec_error = cpl_vector_new(nz);
484// spec_totFlux = cpl_vector_new(nz);
485// pLambda = cpl_vector_get_data(lambda);
486// pData = cpl_vector_get_data(spec_data);
487// pError = cpl_vector_get_data(spec_error);
488// pTotFlux = cpl_vector_get_data(spec_totFlux);
489// pMask = cpl_image_get_data_double_const(mask);
490// CHECK_ERROR_STATE();
491
492// // loop over all lambda slices
493// fill_nz = 0;
494// for (cpl_size sz = 0; sz < nz; sz++) {
495// tmpDataImg = cpl_imagelist_get(data_in, sz);
496// tmpErrorImg = cpl_imagelist_get(error_in, sz);
497// bpm = cpl_image_get_bpm_const(tmpDataImg);
498// pTmpData = cpl_image_get_data_double_const(tmpDataImg);
499// pTmpError = cpl_image_get_data_double_const(tmpErrorImg);
500// pBpm = cpl_mask_get_data_const(bpm);
501// eris_print_rec_status(0);
502// scale_factor_data = cpl_image_duplicate(tmpDataImg);
503// scale_factor_errs = cpl_image_duplicate(tmpErrorImg);
504// eris_print_rec_status(1);
505// cpl_image_power(scale_factor_errs, 2);
506// cpl_image_power(scale_factor_errs, 2);
507// eris_print_rec_status(2);
508// cpl_image_divide(scale_factor_data, cube_median_data);
509// cpl_image_divide(scale_factor_errs, cube_median_errs);
510// eris_print_rec_status(3);
511// pFactorData = cpl_image_get_data_double_const(scale_factor_data);
513// eris_print_rec_status(4);
514// pModelData = cpl_image_get_data_double_const(cube_median_data);
515// pModelErrs = cpl_image_get_data_double_const(cube_median_errs);
516// eris_print_rec_status(5);
517// CHECK_ERROR_STATE();
518
519// // extract spectrum for data
520// sumData = 0.0;
521// sumVariance = 0.0;
522// weights = 0.0;
523// valid = false;
524// for (cpl_size j = 0; j < ny; j++) {
525// for (cpl_size i = 0; i < nx; i++) {
526// // sumData weighted pixels in spatial plane
527// cpl_size p = i+j*nx;
530// model_ndata = 0;
531// if ((pBpm[p] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[p])) {
532// valid = true;
533// if (mask != NULL) {
534// sumData += pTmpData[p] * pMask[p];
535// sumVariance += pow(pTmpError[p] * pMask[p],2);
536// weights += pMask[p];
537// } else {
538// sumData += pTmpData[p];
539// sumVariance += pow(pTmpError[p],2);
540// weights += 1.;
541// }
542// } else {
543
544// /* we are on a bad pixel, we need to interpolate flux
545// * using the model */
546// /* Determine average factor: plane_data / model */
547// for (cpl_size jj = -kernel_sy; jj <= kernel_sy; jj++) {
548// for (cpl_size ii = -kernel_sx; ii <= kernel_sx; ii++) {
549// if( (i+ii) >= 0 && (i+ii) < nx &&
550// (j+jj) >= 0 && (j+jj) < ny) {
551
552// cpl_size pp = (i+ii)+(j+jj)*nx;
553// if ((pBpm[pp] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[pp])) {
554// model_factor_avg += pFactorData[pp];
555// model_ndata ++;
556// }
557// }
558// }
559// }
560// if(model_ndata>0) {
561// model_factor_avg /= model_ndata;
562// }
563
564// /* compute contribute from interpolated bad pixels
565// * scaling data from model and add it to flux determined
566// * on good data
567// */
568// if (!eris_ifu_is_nan_or_inf(pModelData[p])) {
569// valid = true;
570// if (mask != NULL) {
571// sumData += model_factor_avg * pModelData[p] * pMask[p];
572// sumVariance += pow(model_factor_avg * pModelErrs[p] * pMask[p],2);
573// weights += pMask[p];
574// if(startLambda + (double) sz * deltaLambda > 1.615 &&
575// startLambda + (double) sz * deltaLambda < 1.647 ) {
576// cpl_msg_info(cpl_func,"lambda: %g model: %g",pLambda[fill_nz], pModelData[p]);
577// }
578// } else {
579// sumData += model_factor_avg * pModelData[p];
580// sumVariance += pow(model_factor_avg * pModelErrs[p],2);
581// weights += 1.;
582// }
583// }
584
585// }
586// }
587// }
588
589// if ((valid == true) && (fabs(weights) > DBL_ZERO_TOLERANCE)) {
590// pLambda[fill_nz] = startLambda + (double) sz * deltaLambda;
591// pData[fill_nz] = sumData / weights;
592// pError[fill_nz] = sqrt(sumVariance) / weights;
593// pTotFlux[fill_nz] = sumData;
594// if(startLambda + (double) sz * deltaLambda > 1.615 &&
595// startLambda + (double) sz * deltaLambda < 1.647 ) {
596// cpl_msg_info(cpl_func,"lambda: %g flux: %g",pLambda[fill_nz], pData[fill_nz]);
597// }
598// fill_nz++;
599
600// }
601// cpl_image_delete(scale_factor_data);
602// cpl_image_delete(scale_factor_errs);
603// CHECK_ERROR_STATE();
604// }
605// BRK_IF_ERROR(cpl_vector_set_size(lambda, fill_nz));
606// BRK_IF_ERROR(cpl_vector_set_size(spec_data, fill_nz));
607// BRK_IF_ERROR(cpl_vector_set_size(spec_error, fill_nz));
608// BRK_IF_ERROR(cpl_vector_set_size(spec_totFlux, fill_nz));
609
610// spectrum = cpl_bivector_wrap_vectors(lambda, spec_data);
611// *error = spec_error;
612// *totalFlux = spec_totFlux;
613// cpl_imagelist_delete(data_in);
614// cpl_imagelist_delete(error_in);
615// hdrl_image_delete(cube_median);
616// cpl_image_delete(contrib_map);
617// } CATCH
618// {
619// spectrum = NULL;
620// }
621// eris_check_error_code("eris_ifu_extract_spectrum2");
622// return spectrum;
623//}
624
625
626
627//cpl_bivector * eris_ifu_extract_spectrum3(
628// hdrl_imagelist *cube,
629// cpl_image *mask,
630// double startLambda,
631// double deltaLambda,
632// cpl_vector **error,
633// cpl_vector **totalFlux)
634//{
635// cpl_bivector *spectrum = NULL;
636// cpl_imagelist *data_in = NULL;
637// cpl_imagelist *error_in = NULL;
638// const cpl_image *tmpDataImg = NULL;
639// const cpl_image *tmpErrorImg = NULL;
640// const cpl_mask *bpm = NULL;
641// const double *pTmpData = NULL;
642// const double *pTmpError = NULL;
643// const cpl_binary *pBpm = NULL;
644// const double *pMask = NULL;
645// cpl_size nx, ny, nz;
646// cpl_size fill_nz;
647// cpl_vector *lambda = NULL;
648// cpl_vector *spec_data = NULL;
649// cpl_vector *spec_error = NULL;
650// cpl_vector *spec_totFlux = NULL;
651// double *pLambda = NULL;;
652// double *pData = NULL;;
653// double *pError = NULL;;
654// double *pTotFlux = NULL;;
655// double sumData;
656// double sumVariance;
657// double weights;
658// bool valid;
659
660// cpl_imagelist* cube_data_tmp = NULL;
661// cpl_imagelist* cube_errs_tmp = NULL;
662// hdrl_image* cube_median = NULL;
663// cpl_image* cube_median_data = NULL;
664// cpl_image* cube_median_errs = NULL;
665// cpl_image* scale_factor_data = NULL;
666// cpl_image* scale_factor_errs = NULL;
667// const double *pFactorData = NULL;
669// const double *pModelData = NULL;
670// const double *pModelErrs = NULL;
673// double model_factor_avg = 0;
674
675// cpl_size model_def_hsize = 100;
676// cpl_size model_ndata = 0;
677// const cpl_size kernel_sx = 5;
678// const cpl_size kernel_sy = 5;
679// cpl_image* contrib_map;
680
681// cpl_ensure(cube != NULL,CPL_ERROR_NULL_INPUT, NULL);
682// cpl_ensure(mask != NULL,CPL_ERROR_NULL_INPUT, NULL);
683// cpl_ensure(error != NULL,CPL_ERROR_NULL_INPUT, NULL);
684
685// TRY {
686// eris_print_rec_status(0);
687// nx = hdrl_imagelist_get_size_x(cube);
688// ny = hdrl_imagelist_get_size_y(cube);
689// nz = hdrl_imagelist_get_size(cube);
690// eris_print_rec_status(1);
691// ASSURE((nx == cpl_image_get_size_x(mask)) &&
692// (ny == cpl_image_get_size_y(mask)),
693// CPL_ERROR_ILLEGAL_INPUT,
694// "Data cube and mask don't have same dimensions!");
695
696// hdrl_imagelist_collapse_median(cube, &cube_median, &contrib_map);
697// eris_print_rec_status(2);
698// cube_median_data = hdrl_image_get_image(cube_median);
699// cube_median_errs = hdrl_image_get_error(cube_median);
700// cpl_image_save(cube_median_data,"cube_median_data.fits",CPL_TYPE_DOUBLE,NULL,CPL_IO_DEFAULT);
701// eris_print_rec_status(3);
702// data_in = cpl_imagelist_new();
703// error_in = cpl_imagelist_new();
704// for (cpl_size sz = 0; sz < nz; sz++) {
705// hdrl_image *tmpImg = hdrl_imagelist_get(cube, sz);
706// cpl_imagelist_set(data_in, cpl_image_duplicate(hdrl_image_get_image(tmpImg)), sz);
707// cpl_imagelist_set(error_in, cpl_image_duplicate(hdrl_image_get_error(tmpImg)), sz);
708// }
709// eris_print_rec_status(4);
710// CHECK_ERROR_STATE();
711
712// lambda = cpl_vector_new(nz);
713// spec_data = cpl_vector_new(nz);
714// spec_error = cpl_vector_new(nz);
715// spec_totFlux = cpl_vector_new(nz);
716// pLambda = cpl_vector_get_data(lambda);
717// pData = cpl_vector_get_data(spec_data);
718// pError = cpl_vector_get_data(spec_error);
719// pTotFlux = cpl_vector_get_data(spec_totFlux);
720// pMask = cpl_image_get_data_double_const(mask);
721// eris_print_rec_status(5);
722// CHECK_ERROR_STATE();
723
724// // loop over all lambda slices
725// fill_nz = 0;
726// for (cpl_size sz = 0; sz < nz; sz++) {
727// eris_print_rec_status(6);
728// tmpDataImg = cpl_imagelist_get(data_in, sz);
729// tmpErrorImg = cpl_imagelist_get(error_in, sz);
730// bpm = cpl_image_get_bpm_const(tmpDataImg);
731// pTmpData = cpl_image_get_data_double_const(tmpDataImg);
732// pTmpError = cpl_image_get_data_double_const(tmpErrorImg);
733// pBpm = cpl_mask_get_data_const(bpm);
734// eris_print_rec_status(7);
735
736// /* determine local model on a slice of half size model_def_hsize */
737// if( sz >= model_def_hsize && sz < (nz-model_def_hsize)) {
738// cube_data_tmp = cpl_imagelist_new();
739// cube_errs_tmp = cpl_imagelist_new();
740// for(cpl_size k = 0; k <= 2*model_def_hsize; k++) {
741// cpl_size kk = sz - model_def_hsize + k;
742// cpl_imagelist_set(cube_data_tmp, cpl_imagelist_get(data_in, kk), k);
743// cpl_imagelist_set(cube_errs_tmp, cpl_imagelist_get(error_in, kk), k);
744// }
745
746// cube_median_data = cpl_imagelist_collapse_median_create(cube_data_tmp);
747// cube_median_errs = cpl_imagelist_collapse_median_create(cube_errs_tmp);
748
749// }
750// eris_print_rec_status(8);
751// scale_factor_data = cpl_image_duplicate(tmpDataImg);
752// scale_factor_errs = cpl_image_duplicate(tmpErrorImg);
753
754// cpl_image_power(scale_factor_errs, 2);
755// cpl_image_power(cube_median_errs, 2);
756// eris_print_rec_status(9);
757// if(cube_median_data != NULL) {
758// cpl_msg_warning(cpl_func,"Median data for sz: %lld", sz);
759// cpl_image_divide(scale_factor_data, cube_median_data);
760// } else {
761// cpl_msg_warning(cpl_func,"Median data for sz: %lld", sz);
762// }
763// if(cube_median_data != NULL) {
764// cpl_image_divide(scale_factor_errs, cube_median_errs);
765// } else {
766// cpl_msg_warning(cpl_func,"Median error for sz: %lld", sz);
767// }
768// eris_print_rec_status(10);
769// pFactorData = cpl_image_get_data_double_const(scale_factor_data);
771
772// pModelData = cpl_image_get_data_double_const(cube_median_data);
773// pModelErrs = cpl_image_get_data_double_const(cube_median_errs);
774// eris_print_rec_status(11);
775// CHECK_ERROR_STATE();
776
777// // extract spectrum for data
778// sumData = 0.0;
779// sumVariance = 0.0;
780// weights = 0.0;
781// valid = false;
782// eris_print_rec_status(12);
783// for (cpl_size j = 0; j < ny; j++) {
784// for (cpl_size i = 0; i < nx; i++) {
785// // sumData weighted pixels in spatial plane
786// cpl_size p = i+j*nx;
789// model_ndata = 0;
790// if ((pBpm[p] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[p])) {
791// valid = true;
792// if (mask != NULL) {
793// sumData += pTmpData[p] * pMask[p];
794// sumVariance += pow(pTmpError[p] * pMask[p],2);
795// weights += pMask[p];
796// } else {
797// sumData += pTmpData[p];
798// sumVariance += pow(pTmpError[p],2);
799// weights += 1.;
800// }
801// } else {
802
803// /* we are on a bad pixel, we need to interpolate flux
804// * using the model */
805// /* Determine average factor: plane_data / model */
806// for (cpl_size jj = -kernel_sy; jj <= kernel_sy; jj++) {
807// for (cpl_size ii = -kernel_sx; ii <= kernel_sx; ii++) {
808// if( (i+ii) >= 0 && (i+ii) < nx &&
809// (j+jj) >= 0 && (j+jj) < ny) {
810
811// cpl_size pp = (i+ii)+(j+jj)*nx;
812// if ((pBpm[pp] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[pp])) {
813// model_factor_avg += pFactorData[pp];
814// model_ndata ++;
815// }
816// }
817// }
818// }
819// if(model_ndata>0) {
820// model_factor_avg /= model_ndata;
821// }
822
823// /* compute contribute from interpolated bad pixels
824// * scaling data from model and add it to flux determined
825// * on good data
826// */
827// if (!eris_ifu_is_nan_or_inf(pModelData[p])) {
828// valid = true;
829// if (mask != NULL) {
830// sumData += model_factor_avg * pModelData[p] * pMask[p];
831// sumVariance += pow(model_factor_avg * pModelErrs[p] * pMask[p],2);
832// weights += pMask[p];
833// /*
834// if(startLambda + (double) sz * deltaLambda > 1.615 &&
835// startLambda + (double) sz * deltaLambda < 1.647 ) {
836// cpl_msg_info(cpl_func,"lambda: %g model: %g",pLambda[fill_nz], pModelData[p]);
837// }
838// */
839// } else {
840// sumData += model_factor_avg * pModelData[p];
841// sumVariance += pow(model_factor_avg * pModelErrs[p],2);
842// weights += 1.;
843// }
844// }
845
846// }
847// }
848// }
849// eris_print_rec_status(13);
850// if ((valid == true) && (fabs(weights) > DBL_ZERO_TOLERANCE)) {
851// pLambda[fill_nz] = startLambda + (double) sz * deltaLambda;
852// pData[fill_nz] = sumData / weights;
853// pError[fill_nz] = sqrt(sumVariance) / weights;
854// pTotFlux[fill_nz] = sumData;
855// /*
856// if(startLambda + (double) sz * deltaLambda > 1.615 &&
857// startLambda + (double) sz * deltaLambda < 1.647 ) {
858// cpl_msg_info(cpl_func,"lambda: %g flux: %g",pLambda[fill_nz], pData[fill_nz]);
859// }
860// */
861// fill_nz++;
862
863// }
864// eris_print_rec_status(14);
865// cpl_image_delete(scale_factor_data);
866// cpl_image_delete(scale_factor_errs);
867// if( sz >= model_def_hsize && sz < (nz-model_def_hsize)) {
868// cpl_image_delete(cube_median_data);
869// cpl_image_delete(cube_median_errs);
870// for(cpl_size k = 2*model_def_hsize; k >= 0; k--) {
871// cpl_imagelist_unset(cube_data_tmp,k);
872// cpl_imagelist_unset(cube_errs_tmp,k);
873// }
874// cpl_imagelist_delete(cube_data_tmp);
875// cpl_imagelist_delete(cube_errs_tmp);
876// }
877// eris_print_rec_status(15);
878// CHECK_ERROR_STATE();
879// }
880// eris_print_rec_status(16);
881// BRK_IF_ERROR(cpl_vector_set_size(lambda, fill_nz));
882// BRK_IF_ERROR(cpl_vector_set_size(spec_data, fill_nz));
883// BRK_IF_ERROR(cpl_vector_set_size(spec_error, fill_nz));
884// BRK_IF_ERROR(cpl_vector_set_size(spec_totFlux, fill_nz));
885
886// spectrum = cpl_bivector_wrap_vectors(lambda, spec_data);
887// *error = spec_error;
888// *totalFlux = spec_totFlux;
889// cpl_imagelist_delete(data_in);
890// cpl_imagelist_delete(error_in);
891// hdrl_image_delete(cube_median);
892// cpl_image_delete(contrib_map);
893// eris_print_rec_status(17);
894// } CATCH
895// {
896// spectrum = NULL;
897// }
898// eris_check_error_code("eris_ifu_extract_spectrum3");
899// return spectrum;
900//}
901
917cpl_bivector * eris_ifu_optimal_extraction(const hdrl_imagelist *cube,
918 const cpl_imagelist *cube_dqi,
919 const cpl_image *img_mask,
920 double startLambda,
921 double deltaLambda,
922 int productDepth,
923 cpl_vector **error_out)
924{
925 cpl_bivector *spectrum = NULL;
926 cpl_mask *mask = NULL;
927 cpl_vector *spec = NULL,
928 *spec_var = NULL;
929 eris_ifu_vector *spec2 = NULL,
930 *spec_var2 = NULL;
931// hdrl_image *img = NULL;
932// cpl_image *contribMap = NULL;
933// cpl_size nx = 0,
934// ny = 0;
935// cpl_size xcen = 0,
936// ycen = 0;
937// double fwhm = 0.;
938
939 cpl_ensure(cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
940 cpl_ensure(cube_dqi != NULL, CPL_ERROR_NULL_INPUT, NULL);
941 cpl_ensure(img_mask != NULL, CPL_ERROR_NULL_INPUT, NULL);
942 cpl_ensure(startLambda > 1.0, CPL_ERROR_NULL_INPUT, NULL);
943 cpl_ensure(deltaLambda > 0, CPL_ERROR_NULL_INPUT, NULL);
944 cpl_ensure(error_out != NULL,CPL_ERROR_NULL_INPUT, NULL);
945
946 TRY {
947// nx = hdrl_imagelist_get_size_x(cube);
948// ny = hdrl_imagelist_get_size_y(cube);
949//
950// // find centre & fwhm from a collapsed image (without fitting)
951// img = eris_ifu_extract_spec_collapse(cube, &contribMap);
952// if (productDepth >= PD_DEBUG) {
953// eris_ifu_save_hdrl_image_dbg(img, "eris_dbg_collapsed_cube", CPL_IO_CREATE, NULL);
954// }
955//
956// BRK_IF_ERROR(
957// eris_ifu_opt_extr_get_center_fwhm(img, edge_trim, &xcen, &ycen, &fwhm));
958// cpl_msg_debug(cpl_func,"Mask center at (%d/%d), FWHM: %g)", (int)xcen, (int)ycen, fwhm);
959//
960// BRK_IF_NULL(
961// mask = eris_ifu_opt_extr_create_mask(nx, ny, xcen, ycen, fwhm));
962// if (productDepth >= PD_DEBUG) {
963// eris_ifu_save_mask_dbg(mask, "eris_dbg_mask.fits", CPL_IO_CREATE, NULL);
964// }
965
966 // convert image to mask
967 // img: 1: good, 0:bad -> mask: 0: good, 1: bad
968 mask = eris_ifu_mask_from_image(img_mask);
969 if (productDepth >= PD_DEBUG) {
970 eris_ifu_save_mask_dbg(mask, "eris_dbg_mask.fits", CPL_IO_CREATE, NULL);
971 }
972
974 eris_ifu_opt_extr_simple_extraction(cube, mask, &spec, &spec_var));
975 if (productDepth >= PD_DEBUG) {
976 eris_ifu_save_vector_dbg(spec, "eris_dbg_spec1.fits", CPL_IO_CREATE, NULL);
977 eris_ifu_save_vector_dbg(spec_var, "eris_dbg_spec1.fits", CPL_IO_EXTEND, NULL);
978 }
979
980 spec2 = eris_ifu_vector_create(spec),
981 spec_var2 = eris_ifu_vector_create(spec_var);
983 spectrum = eris_ifu_opt_extr_doit(cube, cube_dqi, mask,
984 spec2, spec_var2,
985 startLambda, deltaLambda,
986 productDepth,
987 error_out));
989 eris_ifu_free_ifu_vector(&spec_var2);
990
991 if (productDepth >= PD_DEBUG) {
992 // error ist the total error of the masked area
993 eris_ifu_save_bivector_dbg(spectrum, "eris_dbg_spectrum_out.fits", 0, CPL_IO_CREATE);
994 eris_ifu_save_vector_dbg(*error_out, "eris_dbg_spectrum_out.fits", CPL_IO_EXTEND, NULL);
995
996 eris_ifu_save_vector_dbg(cpl_bivector_get_x_const(spectrum), "eris_dbg_spectrum_in.fits", CPL_IO_CREATE, NULL);
997 eris_ifu_save_vector_dbg(spec, "eris_dbg_spectrum_in.fits", CPL_IO_EXTEND, NULL);
998 eris_ifu_opt_extr_vector_sqrt(spec_var);
999 eris_ifu_save_vector_dbg(spec_var, "eris_dbg_spectrum_in.fits", CPL_IO_EXTEND, NULL);
1000 }
1001 } CATCH
1002 {
1003 eris_ifu_free_bivector(&spectrum);
1004 eris_ifu_free_mask(&mask);
1006 eris_ifu_free_ifu_vector(&spec_var2);
1007 }
1008// eris_ifu_free_image(&contribMap);
1009 eris_ifu_free_vector(&spec_var);
1010 eris_ifu_free_vector(&spec);
1011 eris_ifu_free_mask(&mask);
1012
1013 return spectrum;
1014}
1015
1024cpl_error_code eris_ifu_opt_extr_get_center_fwhm(const hdrl_image *hdrl_img,
1025 int edge_trim,
1026 cpl_size *xcen,
1027 cpl_size *ycen,
1028 double *fwhm)
1029{
1030 cpl_error_code ret_error = CPL_ERROR_NONE;
1031 double maxval = -9999e10;
1032 const cpl_image *img_data = NULL;
1033 const double *pimg_data = NULL;
1034 const cpl_mask *img_mask = NULL;
1035 const cpl_binary *pimg_mask = NULL;
1036 cpl_size nx = 0;
1037 int npix = 0;
1038
1039 cpl_ensure_code(hdrl_img != NULL, CPL_ERROR_NULL_INPUT);
1040 cpl_ensure_code(edge_trim >= 0, CPL_ERROR_NULL_INPUT);
1041
1042 TRY {
1044 img_data = hdrl_image_get_image_const(hdrl_img));
1045 nx = cpl_image_get_size_x(img_data);
1047 pimg_data = cpl_image_get_data_double_const(img_data));
1049 img_mask = hdrl_image_get_mask_const(hdrl_img));
1051 pimg_mask = cpl_mask_get_data_const(img_mask));
1052
1053 // find maxval and its position
1054 for (cpl_size x = edge_trim; x < hdrl_image_get_size_x(hdrl_img)-edge_trim; x++) {
1055 for (cpl_size y = edge_trim; y < hdrl_image_get_size_y(hdrl_img)-edge_trim; y++) {
1056 if ((pimg_mask[x+y*nx] == GOOD_PIX) &&
1057 (pimg_data[x+y*nx] > maxval) &&
1058 (!isnan(pimg_data[x+y*nx])))
1059 {
1060 maxval = pimg_data[x+y*nx];
1061 *xcen = x;
1062 *ycen = y;
1063 }
1064 }
1065 }
1066
1067 cpl_msg_debug(cpl_func,"Mask max. value: %g)", maxval);
1068
1069 // find number of pixels where value is bigger than half of maxval
1070 maxval *= 0.5;
1071 for (cpl_size x = edge_trim; x < hdrl_image_get_size_x(hdrl_img)-edge_trim; x++) {
1072 for (cpl_size y = edge_trim; y < hdrl_image_get_size_y(hdrl_img)-edge_trim; y++) {
1073 if ((pimg_mask[x+y*nx] == GOOD_PIX) &&
1074 (pimg_data[x+y*nx] > maxval) &&
1075 (!isnan(pimg_data[x+y*nx])))
1076 {
1077 npix++;
1078 }
1079 }
1080 }
1081
1082 // now define fwhm
1083 *fwhm = sqrt(npix); // a bit larger than the nominal size
1084 //*fwhm = 1.5 * sqrt(npix); // a bit larger than the nominal size
1085 } CATCH {
1086 CATCH_MSG();
1087 ret_error = cpl_error_get_code();
1088 *xcen = -1;
1089 *ycen = -1;
1090 *fwhm = NAN;
1091 }
1092
1093 return ret_error;
1094}
1095
1105cpl_mask* eris_ifu_opt_extr_create_mask(int nx,
1106 int ny,
1107 int xcen,
1108 int ycen,
1109 double fwhm)
1110{
1111 cpl_mask *mask = NULL;
1112 cpl_binary *pmask =NULL;
1113
1114 cpl_ensure(nx > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1115 cpl_ensure(ny > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1116 cpl_ensure(xcen > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1117 cpl_ensure(ycen > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1118 cpl_ensure(fwhm > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1119
1120 TRY {
1122 mask = cpl_mask_new(nx, ny));
1124 pmask = cpl_mask_get_data(mask));
1125
1126 for (int x = 0; x < nx; x++) {
1127 for (int y = 0; y < ny; y++) {
1128 if (fwhm <= sqrt(pow(x-xcen,2)+pow(y-ycen,2))) {
1129 // bad: outside
1130 pmask[x+y*nx] = BAD_PIX;
1131 } else {
1132 // good:inside
1133 pmask[x+y*nx] = GOOD_PIX;
1134 }
1135 }
1136 }
1137 } CATCH {
1138 CATCH_MSG();
1139 eris_ifu_free_mask(&mask);
1140 }
1141
1142 return mask;
1143}
1144
1155cpl_error_code eris_ifu_opt_extr_simple_extraction(const hdrl_imagelist *cube,
1156 const cpl_mask *mask,
1157 cpl_vector **spec,
1158 cpl_vector **spec_var)
1159{
1160 cpl_error_code ret_error = CPL_ERROR_NONE;
1161 const hdrl_image *tmp_img = NULL;
1162 hdrl_image *tmp_img2 = NULL;
1163 double *pspec = NULL,
1164 *pspec_var = NULL;
1165 cpl_size nz = 0;
1166 hdrl_value hv;
1167
1168 cpl_ensure_code(cube != NULL, CPL_ERROR_NULL_INPUT);
1169 cpl_ensure_code(mask != NULL, CPL_ERROR_NULL_INPUT);
1170
1171 TRY {
1172 nz = hdrl_imagelist_get_size(cube);
1173
1175 *spec = cpl_vector_new(nz));
1177 *spec_var = cpl_vector_new(nz));
1179 pspec = cpl_vector_get_data(*spec));
1181 pspec_var = cpl_vector_get_data(*spec_var));
1182
1183 for (int z = 0; z < nz; z++) {
1185 tmp_img = hdrl_imagelist_get_const(cube, z));
1187 tmp_img2 = hdrl_image_duplicate(tmp_img));
1189 hdrl_image_reject_from_mask(tmp_img2, mask));
1190
1191 hv = hdrl_image_get_sum(tmp_img2);
1192 pspec[z] = hv.data;
1193 pspec_var[z] = hv.error*hv.error;
1194 hdrl_image_delete(tmp_img2);
1195 }
1196 } CATCH {
1197 CATCH_MSG();
1198 ret_error = cpl_error_get_code();
1200 eris_ifu_free_vector(spec_var);
1201 }
1202
1203 return ret_error;
1204}
1205
1212cpl_bivector * eris_ifu_opt_extr_helper_usepix(const cpl_mask *mask, int *n_usepix)
1213{
1214 cpl_bivector *usepix = NULL;
1215 int nx = 0,
1216 ny = 0,
1217 index = 0;
1218 double *px = NULL,
1219 *py = NULL;
1220 const cpl_binary *pmask = NULL;
1221
1222 cpl_ensure(mask != NULL, CPL_ERROR_NULL_INPUT, NULL);
1223
1224 TRY {
1225 nx = cpl_mask_get_size_x(mask);
1226 ny = cpl_mask_get_size_y(mask);
1227
1228 // get number of pixels in mask
1229 *n_usepix = (nx * ny) - cpl_mask_count(mask);
1230 cpl_msg_debug(cpl_func,"optimal extraction: n_usepix: %d", *n_usepix);
1231
1232 if (*n_usepix > 0) {
1233 usepix = cpl_bivector_new(*n_usepix);
1234 pmask = cpl_mask_get_data_const(mask);
1235
1236 px = cpl_vector_get_data(cpl_bivector_get_x(usepix));
1237 py = cpl_vector_get_data(cpl_bivector_get_y(usepix));
1238
1239 for (int y = 0; y < ny; y++) {
1240 for (int x = 0; x < nx; x++) {
1241 if (pmask[x+y*nx] == GOOD_PIX) {
1242 px[index] = x;
1243 py[index] = y;
1244 index++;
1245 }
1246 }
1247 }
1248 }
1249 } CATCH {
1250 eris_ifu_free_bivector(&usepix);
1251 }
1252
1253 return usepix;
1254}
1255
1265cpl_error_code eris_ifu_opt_extr_helper_fill_vertical(cpl_image *img, const eris_ifu_vector *vec)
1266{
1267 cpl_ensure_code(vec, CPL_ERROR_NULL_INPUT);
1268
1269 double *pimg = cpl_image_get_data_double(img);
1270 cpl_size nx = cpl_image_get_size_x(img),
1271 ny = cpl_image_get_size_y(img);
1272 double *pkvmask = cpl_vector_get_data(vec->data),
1273 *pkvdata = cpl_vector_get_data(vec->mask);
1274
1275 cpl_ensure_code(eris_ifu_vector_get_size(vec) == ny, CPL_ERROR_ILLEGAL_INPUT);
1276
1277 for (int y = 0; y < ny; y++) {
1278 for (int x = 0; x < nx; x++) {
1279 if (pkvmask[y] > 0.5) {
1280 pimg[x+y*nx] = pkvdata[y];
1281 } else {
1282 cpl_image_reject(img, x+1, y+1);
1283 }
1284 }
1285 }
1286
1287 return CPL_ERROR_NONE;
1288}
1289
1299void eris_ifu_opt_extr_helper_fill_horizontal(cpl_image *img, const cpl_image *slice, const cpl_bivector *usepix, int row, int power) {
1300 double *pimg = cpl_image_get_data_double(img);
1301 const double *pslice_d = NULL;
1302 const int *pslice_i = NULL;
1303 cpl_size nx = cpl_image_get_size_x(slice);
1304 cpl_type type = cpl_image_get_type(slice);
1305 const double *px = cpl_vector_get_data_const(cpl_bivector_get_x_const(usepix)),
1306 *py = cpl_vector_get_data_const(cpl_bivector_get_y_const(usepix));
1307 cpl_size n_usepix = cpl_bivector_get_size(usepix);
1308
1309 if (type == CPL_TYPE_DOUBLE) {
1310 pslice_d = cpl_image_get_data_double_const(slice);
1311 } else if (type == CPL_TYPE_INT) {
1312 pslice_i = cpl_image_get_data_int_const(slice);
1313 } else {
1314 return;
1315 }
1316
1317 if (type == CPL_TYPE_DOUBLE) {
1318 for (int i = 0; i < n_usepix; i++) {
1319 double val = pslice_d[(int)px[i]+(int)py[i]*nx];
1320 if (power) {
1321 pimg[i+row*n_usepix] = pow(val, 2);
1322 } else {
1323 pimg[i+row*n_usepix] = val;
1324 }
1325 }
1326 } else {
1327 for (int i = 0; i < n_usepix; i++) {
1328 int val = pslice_i[(int)px[i]+(int)py[i]*nx];
1329 if (power) {
1330 pimg[i+row*n_usepix] = pow(val, 2);
1331 } else {
1332 pimg[i+row*n_usepix] = val;
1333 }
1334 }
1335 }
1336}
1337
1344void eris_ifu_opt_extr_helper_set_positive(cpl_image *img) {
1345 double *pimg = cpl_image_get_data_double(img);
1346 cpl_size nx = cpl_image_get_size_x(img),
1347 ny = cpl_image_get_size_y(img);
1348 int n_neg = 0;
1349
1350 for (int x = 0; x < nx; x++) {
1351 for (int y = 0; y < ny; y++) {
1352 if ((pimg[x+y*nx] < 0.) || isnan(pimg[x+y*nx])) {
1353 pimg[x+y*nx] = 0.;
1354 n_neg++;
1355 }
1356 }
1357 }
1358 cpl_msg_debug(cpl_func, "optimal extraction: Resetting %d negative values in original PSF", n_neg);
1359}
1360
1367cpl_vector* eris_ifu_opt_extr_get_col(const cpl_image *img, int colnr)
1368{
1369 int nx = 0,
1370 ny = 0;
1371 double *pvec = NULL;
1372 const double *pimg = NULL;
1373 cpl_vector *vec = NULL;
1374
1375 cpl_ensure(img != NULL, CPL_ERROR_NULL_INPUT, NULL);
1376
1377 nx = cpl_image_get_size_x(img);
1378 ny = cpl_image_get_size_y(img);
1379
1380 cpl_ensure(colnr <= nx, CPL_ERROR_ILLEGAL_INPUT, NULL);
1381
1382 vec = cpl_vector_new(ny);
1383 pvec = cpl_vector_get_data(vec);
1384 pimg = cpl_image_get_data_double_const(img);
1385
1386 for (int y = 0; y < ny; y++) {
1387 pvec[y] = pimg[colnr+y*nx];
1388 }
1389
1390 return vec;
1391}
1392
1399cpl_vector* eris_ifu_opt_extr_get_row(const cpl_image *img, int rownr)
1400{
1401 int nx = 0,
1402 ny = 0;
1403 double *pvec = NULL;
1404 const double *pimg = NULL;
1405 cpl_vector *vec = NULL;
1406
1407 cpl_ensure(img != NULL, CPL_ERROR_NULL_INPUT, NULL);
1408
1409 nx = cpl_image_get_size_x(img);
1410 ny = cpl_image_get_size_y(img);
1411
1412 cpl_ensure(rownr <= ny, CPL_ERROR_ILLEGAL_INPUT, NULL);
1413
1414 vec = cpl_vector_new(nx);
1415 pvec = cpl_vector_get_data(vec);
1416 pimg = cpl_image_get_data_double_const(img);
1417
1418 for (int x = 0; x < nx; x++) {
1419 pvec[x] = pimg[x+rownr*nx];
1420 }
1421
1422 return vec;
1423}
1424
1431cpl_error_code eris_ifu_opt_extr_set_row(cpl_image *img,
1432 int rownr,
1433 const cpl_vector *vec)
1434{
1435 int nx = 0,
1436 ny = 0;
1437 const double *pvec = NULL;
1438 double *pimg = NULL;
1439
1440 cpl_ensure_code(img != NULL, CPL_ERROR_NULL_INPUT);
1441 cpl_ensure_code(vec != NULL, CPL_ERROR_NULL_INPUT);
1442
1443 nx = cpl_image_get_size_x(img);
1444 ny = cpl_image_get_size_y(img);
1445
1446 cpl_ensure_code(rownr <= ny, CPL_ERROR_ILLEGAL_INPUT);
1447 cpl_ensure_code(nx == cpl_vector_get_size(vec), CPL_ERROR_ILLEGAL_INPUT);
1448
1449 pvec = cpl_vector_get_data_const(vec);
1450 pimg = cpl_image_get_data_double(img);
1451
1452 for (int x = 0; x < nx; x++) {
1453 pimg[x+rownr*nx] = pvec[x];
1454 }
1455
1456 return cpl_error_get_code();
1457}
1458
1466cpl_error_code eris_ifu_opt_extr_set_col(cpl_image *img,
1467 int colnr,
1468 const cpl_vector *vec)
1469{
1470 int nx = 0,
1471 ny = 0;
1472 double *pimg = NULL;
1473 const double *pvec = NULL;
1474
1475 cpl_ensure_code(img != NULL, CPL_ERROR_NULL_INPUT);
1476 cpl_ensure_code(vec != NULL, CPL_ERROR_NULL_INPUT);
1477
1478 nx = cpl_image_get_size_x(img);
1479 ny = cpl_image_get_size_y(img);
1480
1481 cpl_ensure_code(colnr <= nx, CPL_ERROR_ILLEGAL_INPUT);
1482 cpl_ensure_code(ny == cpl_vector_get_size(vec), CPL_ERROR_ILLEGAL_INPUT);
1483
1484 pvec = cpl_vector_get_data_const(vec);
1485 pimg = cpl_image_get_data_double(img);
1486
1487 for (int y = 0; y < ny; y++) {
1488 pimg[colnr+y*nx] = pvec[y];
1489 }
1490
1491 return cpl_error_get_code();
1492}
1493
1494cpl_vector* eris_ifu_opt_extr_create_lambda(int size, double startLambda, double deltaLambda)
1495{
1496 cpl_vector *lambda = cpl_vector_new(size);
1497 double *pLambda = cpl_vector_get_data(lambda);
1498
1499 for (int i = 0; i < size; i++) {
1500 pLambda[i] = startLambda + (double)i * deltaLambda;
1501 }
1502 return lambda;
1503}
1504
1505cpl_error_code eris_ifu_opt_extr_vector_sqrt(cpl_vector *vec)
1506{
1507 double *pvec = cpl_vector_get_data(vec);
1508 cpl_ensure_code(vec != NULL, CPL_ERROR_NULL_INPUT);
1509
1510 for (int i = 0; i < cpl_vector_get_size(vec); i++) {
1511 pvec[i] = sqrt(pvec[i]);
1512 }
1513 return cpl_error_get_code();
1514}
1515
1516cpl_bivector* eris_ifu_opt_extr_doit(const hdrl_imagelist *cube,
1517 const cpl_imagelist *cube_dqi,
1518 const cpl_mask *mask,
1519 const eris_ifu_vector *spec,
1520 const eris_ifu_vector *spec_var,
1521 double startLambda,
1522 double deltaLambda,
1523 int productDepth,
1524 cpl_vector **error_out)
1525{
1526 cpl_bivector *spectrum = NULL,
1527 *usepix = NULL;
1528 cpl_size nz = 0;
1529 cpl_vector *vec = NULL,
1530 *rejectvec = NULL,
1531 *vec_err = NULL,
1532 *keep0 = NULL,
1533 *new_vec = NULL;
1534 eris_ifu_vector *speco = NULL,
1535 *spec_var_err = NULL,
1536 *sigo = NULL;
1537 cpl_image *spec1 = NULL,
1538 *psfvals = NULL,
1539 *varvals = NULL,
1540 *qualvals = NULL,
1541 *psfmod = NULL,
1542 *psfmodnew = NULL,
1543 *reject = NULL,
1544 *snr2 = NULL,
1545 *residual = NULL;
1546 int n_usepix = 0,
1547 jj = 0,
1548 sm = 49; // smoothing half-length (use, e.g. 15 for spectra with wiggles, up to 49 for ideal spectra).
1549 // Smoothing is done over a length of +/-sm pixels.
1550 double clipfrac = 0.9, // fraction to set for percentile clipping
1551 *pnew_vec = NULL,
1552 *pqualvals = NULL,
1553 *preject = NULL,
1554 *pkeep0 = NULL/*,
1555 *pspeco = NULL,
1556 *psigo = NULL*/;
1557 const double *pvec = NULL,
1558 *prejectvec = NULL;
1559
1560 cpl_ensure(cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
1561 cpl_ensure(cube_dqi != NULL, CPL_ERROR_NULL_INPUT, NULL);
1562 cpl_ensure(mask != NULL, CPL_ERROR_NULL_INPUT, NULL);
1563 cpl_ensure(spec != NULL, CPL_ERROR_NULL_INPUT, NULL);
1564 cpl_ensure(spec_var != NULL, CPL_ERROR_NULL_INPUT, NULL);
1565 cpl_ensure(error_out != NULL, CPL_ERROR_NULL_INPUT, NULL);
1566 cpl_ensure(hdrl_imagelist_get_size(cube) == cpl_imagelist_get_size(cube_dqi),
1567 CPL_ERROR_ILLEGAL_INPUT, NULL);
1568 cpl_ensure(hdrl_imagelist_get_size(cube) == eris_ifu_vector_get_size(spec),
1569 CPL_ERROR_ILLEGAL_INPUT, NULL);
1570 cpl_ensure(hdrl_imagelist_get_size(cube) == eris_ifu_vector_get_size(spec_var),
1571 CPL_ERROR_ILLEGAL_INPUT, NULL);
1572
1573 TRY {
1574 nz = hdrl_imagelist_get_size(cube);
1575
1576 spec_var_err = eris_ifu_vector_duplicate(spec_var);
1577 eris_ifu_vector_sqrt(spec_var_err);
1578 eris_ifu_vector_divide(spec_var_err, spec);
1580
1581 // get coordinates of used pixels in mask
1582 usepix = eris_ifu_opt_extr_helper_usepix(mask, &n_usepix);
1583
1584 // for convenience spectra of all selected pixels are stored in a 2D array
1585 spec1 = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE);
1586 psfvals = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // = (D - S)
1587 //psfmod = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // = P
1588 varvals = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // = V
1589 qualvals = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // for additional clipping regarding DQI
1590 pqualvals = cpl_image_get_data_double(qualvals);
1592
1593 // begin optimal extraction
1594 // 1st time through bigloop use initial spectrum
1595 // 2nd time through bigloop use previous output spectrum
1596 speco = eris_ifu_vector_duplicate(spec); // working spectrum data
1597// pspeco = cpl_vector_get_data(speco);
1598 sigo = eris_ifu_vector_new(nz); // working spectrum error
1599// psigo = cpl_vector_get_data(sigo);
1601
1602 for (int bigloop = 0; bigloop <= 1; bigloop++) {
1603 // spec0 is vector
1604 // spec1 is image (duplicates of speco)
1606 eris_ifu_opt_extr_helper_fill_vertical(spec1, speco));
1607
1608 // fill data/error/dqi values of used (unmasked) pixels to 2D-array
1609 // for varvals store the squared values
1610 for (int z = 0; z < nz; z++) {
1611 const hdrl_image *hdrl_img = hdrl_imagelist_get_const(cube, z);
1612 const cpl_image *slice_d = hdrl_image_get_image_const(hdrl_img);
1613 const cpl_image *slice_e = hdrl_image_get_error_const(hdrl_img);
1614 const cpl_image *slice_q = cpl_imagelist_get_const(cube_dqi, z);
1615
1616 eris_ifu_opt_extr_helper_fill_horizontal(psfvals, slice_d, usepix, z, FALSE);
1617 eris_ifu_opt_extr_helper_fill_horizontal(varvals, slice_e, usepix, z, TRUE);
1618 eris_ifu_opt_extr_helper_fill_horizontal(qualvals, slice_q, usepix, z, FALSE);
1619 }
1620
1621 eris_ifu_opt_extr_helper_set_positive(psfvals);
1622
1623 if (productDepth >= PD_DEBUG) {
1624 eris_ifu_save_image_dbg(psfvals, "ers_psfvals.fits", CPL_IO_CREATE, NULL);
1625 eris_ifu_save_image_dbg(varvals, "ers_varvals.fits", CPL_IO_CREATE, NULL);
1626 eris_ifu_save_image_dbg(qualvals, "ers_qualvals.fits", CPL_IO_CREATE, NULL);
1627 }
1628
1629 // replace fractions with weighted polynomial fits: the PSF model
1630 // Horne86, page 613 bottom right & Fig 1
1631 // two iterations; first with all pixels, second with clipped (from reject)
1632 reject = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // all zeros initially
1633 preject = cpl_image_get_data_double(reject);
1635
1636 new_vec = cpl_vector_new(nz);
1637 pnew_vec = cpl_vector_get_data(new_vec);
1638
1639 for (int iloop = 0; iloop <= 1; iloop++) {
1640 if (psfmod != NULL) {
1641 eris_ifu_free_image(&psfmod);
1642 }
1643 psfmod = cpl_image_divide_create(psfvals, spec1); // Horne86 eq 14, P = (D-S)/f
1644 eris_ifu_opt_extr_helper_set_positive(psfmod);
1646
1647 if (productDepth >= PD_DEBUG) {
1648 eris_ifu_save_image_dbg(psfmod, "ers_psfmod.fits", CPL_IO_CREATE, NULL);
1649 }
1650
1651 // slow loop
1652 for (int n = 0; n < n_usepix; n++) {
1653 vec = eris_ifu_opt_extr_get_col(psfmod, n);
1654 pvec = cpl_vector_get_data_const(vec);
1656
1658 vec_err = eris_ifu_vector_get_data(spec_var_err));
1660 cpl_vector_multiply(vec_err, vec));
1661
1662 rejectvec = eris_ifu_opt_extr_get_col(reject, n);
1663 prejectvec = cpl_vector_get_data_const(rejectvec);
1665
1666 // vector 'keep0' with indices on which values to keep
1667 keep0 = cpl_vector_new(nz);
1668 cpl_vector_fill(keep0, -1.0);
1669 pkeep0 = cpl_vector_get_data(keep0);
1670 jj = 0;
1671
1672 for (cpl_size iz = 0; iz < nz; iz++) {
1673
1674 if ((fabs(prejectvec[iz]) < 1e-5) &&
1675 (pvec[iz] > 0) &&
1676 !eris_ifu_is_nan_or_inf(pvec[iz]))
1677 {
1678
1679 pkeep0[jj++]= iz;
1680
1681 }
1682 } // end: for iz
1683 cpl_vector_delete(rejectvec);
1685 eris_ifu_cut_endings(&keep0, NULL, NULL, TRUE));
1686 if (keep0 != NULL) {
1687 pkeep0 = cpl_vector_get_data(keep0);
1689
1690 if ((productDepth >= PD_DEBUG) && (n==92)) {
1691 eris_ifu_save_vector_dbg(keep0, "ers_keep0.fits", CPL_IO_CREATE, NULL);
1692 }
1693
1694 // replace polynomial fitting by weighted mean smoothing over +/-sm pixels, after rejection
1695 for (int z = 0; z < nz; z++) {
1696 // reject keep0
1697 int s = cpl_vector_get_size(keep0);
1698 cpl_vector* ttt = cpl_vector_new(s);
1699 double *pttt = cpl_vector_get_data(ttt);
1700 cpl_vector_fill(ttt, -1.0);
1701 jj = 0;
1702 for (int iz = 0; iz < s; iz++) {
1703 int v = (int)(pkeep0[iz] +.5);
1704 if ((v > z-sm) && (v < z+sm)) {
1705 pttt[jj++] = iz;
1706 }
1707 }
1708 if (productDepth >= PD_DEBUG) {
1709 eris_ifu_save_vector_dbg(ttt, "ers_ttt.fits", CPL_IO_CREATE, NULL);
1710 }
1712 eris_ifu_cut_endings(&ttt, NULL, NULL, TRUE));
1713 if (ttt != NULL) {
1714 cpl_vector *iiuse = eris_ifu_idl_values_at_indices(keep0, ttt),
1715 *els = eris_ifu_idl_values_at_indices(vec, iiuse),
1716 *els_err = eris_ifu_idl_values_at_indices(vec_err, iiuse),
1717 *ones = cpl_vector_new(cpl_vector_get_size(els));
1719
1720 if ((productDepth >= PD_DEBUG) && (n==92) && (z == 1000)) {
1721 eris_ifu_save_vector_dbg(iiuse, "ers_iiuse.fits", CPL_IO_CREATE, NULL);
1722 eris_ifu_save_vector_dbg(els, "ers_els.fits", CPL_IO_CREATE, NULL);
1723 eris_ifu_save_vector_dbg(els_err, "ers_elserr.fits", CPL_IO_CREATE, NULL);
1724 }
1725
1726 cpl_vector_fill(ones, 1.0);
1727 cpl_vector_divide(els, els_err);
1728 cpl_vector_divide(ones, els_err);
1729 pnew_vec[z] = cpl_vector_get_sum(els) / cpl_vector_get_sum(ones);
1731
1732 eris_ifu_free_vector(&iiuse);
1733 eris_ifu_free_vector(&ones);
1735 eris_ifu_free_vector(&els_err);
1736 } else {
1737 pnew_vec[z] = NAN;
1738 }
1739
1741 } // end: for z
1743
1745 eris_ifu_opt_extr_set_col(psfmod, n, new_vec));
1746
1747 if ((productDepth >= PD_DEBUG) && (n==92)) {
1748 eris_ifu_save_vector_dbg(new_vec, "ers_newvec.fits", CPL_IO_CREATE, NULL);
1749 }
1750 }
1752 eris_ifu_free_vector(&vec_err);
1753 eris_ifu_free_vector(&keep0);
1754 } // end: for n
1756
1757 if (productDepth >= PD_DEBUG) {
1758 if (iloop==0) {
1759 eris_ifu_save_image_dbg(psfmod, "ers_psfmod_0.fits", CPL_IO_CREATE, NULL);
1760 } else {
1761 eris_ifu_save_image_dbg(psfmod, "ers_psfmod_1.fits", CPL_IO_CREATE, NULL);
1762 }
1763 }
1764
1765 // second iteration of polynomial fitting uses Horne86, page 614, top left: ((D-S) - fP)^2/V
1766 // also use qualitfy flag to reject pixels & define clipping value from data, slice by slice
1767 // snr2 = (psfvals-psfmod*spec1)^2/varvals
1768 cpl_image *psfmod_tmp = cpl_image_multiply_create(psfmod, spec1);
1769 snr2 = cpl_image_subtract_create(psfvals, psfmod_tmp);
1770 cpl_image_power(snr2, 2);
1771 cpl_image_divide(snr2, varvals);
1772 eris_ifu_free_image(&psfmod_tmp);
1774 if (productDepth >= PD_DEBUG) {
1775 if (iloop==0) {
1776 eris_ifu_save_image_dbg(snr2, "ers_snr2_0.fits", CPL_IO_CREATE, NULL);
1777 eris_ifu_save_image_dbg(reject, "ers_reject0_0.fits", CPL_IO_CREATE, NULL);
1778 } else {
1779 eris_ifu_save_image_dbg(snr2, "ers_snr2_1.fits", CPL_IO_CREATE, NULL);
1780 eris_ifu_save_image_dbg(reject, "ers_reject0_1.fits", CPL_IO_CREATE, NULL);
1781 }
1782 }
1783 for (int iz = 0; iz < nz; iz++) {
1784 vec = eris_ifu_opt_extr_get_row(snr2, iz);
1785 int n_fin = eris_ifu_opt_extr_get_not_finite(vec);
1786 if (n_fin > n_usepix*0.25) {
1787 //cpl_vector_abs
1788 cpl_vector_power(vec, 2);
1789 eris_ifu_cpl_vector_sqrt(vec);
1790
1791 cpl_vector_sort(vec, CPL_SORT_ASCENDING);
1792 double clip = cpl_vector_get(vec, n_usepix*clipfrac)*5;
1793 cpl_vector *tmp = eris_ifu_idl_where(vec, clip, gt);
1794 if ((tmp != NULL) && (cpl_vector_get_size(tmp) > 0)) {
1795 for (int ii = 0; ii < cpl_vector_get_size(tmp); ii++) {
1796 preject[(int)(cpl_vector_get(tmp, ii)+.5)+iz*n_usepix] = 1;
1797 }
1798 }
1800 } else {
1801 for (int ii = 0; ii < n_usepix; ii++) {
1802 preject[ii+iz*n_usepix] = 1;
1803 }
1804 }
1806 } // end: for iz
1808 if (productDepth >= PD_DEBUG) {
1809 if (iloop==0) {
1810 eris_ifu_save_image_dbg(reject, "ers_reject1_0.fits", CPL_IO_CREATE, NULL);
1811 } else {
1812 eris_ifu_save_image_dbg(reject, "ers_reject1_1.fits", CPL_IO_CREATE, NULL);
1813 }
1814 }
1815 for (int ii = 0; ii < n_usepix * nz; ii++) {
1816 if (pqualvals[ii] > 0) {
1817 preject[ii] = 1;
1818 }
1819 }
1821 if (productDepth >= PD_DEBUG) {
1822 if (iloop==0) {
1823 eris_ifu_save_image_dbg(reject, "ers_reject2_0.fits", CPL_IO_CREATE, NULL);
1824 } else {
1825 eris_ifu_save_image_dbg(reject, "ers_reject2_1.fits", CPL_IO_CREATE, NULL);
1826 }
1827 }
1828 eris_ifu_free_image(&snr2);
1829 } // end: for iloop
1830 eris_ifu_free_vector(&new_vec);
1831
1832 if (productDepth >= PD_DEBUG) {
1833 eris_ifu_save_image_dbg(reject, "ers_reject3.fits", CPL_IO_CREATE, NULL);
1834 }
1835 eris_ifu_free_image(&reject);
1836
1837 //go through PSF model plane by plane
1838 // reject low quality & noisy pixels * re-extract spectrum
1839 // Horne86 page 614, left, & Table 1 step 5c, 7, 8
1840 // steps 6 is skipped;
1841 // step 7 includes the quality flag
1842
1843 eris_ifu_free_image(&psfmodnew);
1845 psfmodnew = cpl_image_duplicate(psfmod));
1846
1847 //residual = (psfvals-psfmod*spec1)^2/varvals
1848 // for step 7; page 614 top right
1849 eris_ifu_free_image(&residual);
1850 residual = cpl_image_multiply_create(psfmod, spec1);
1851 cpl_image_subtract(residual, psfvals);
1852 cpl_image_multiply_scalar(residual, -1.);
1853 cpl_image_power(residual, 2);
1854 cpl_image_divide(residual, varvals);
1855
1856 if (productDepth >= PD_DEBUG) {
1857 eris_ifu_save_image_dbg(psfvals, "ers_psfvalsXXX.fits", CPL_IO_CREATE, NULL);
1858 eris_ifu_save_image_dbg(psfmod, "ers_psfmodXXX.fits", CPL_IO_CREATE, NULL);
1859 eris_ifu_save_image_dbg(spec1, "ers_spec1XXX.fits", CPL_IO_CREATE, NULL);
1860 eris_ifu_save_image_dbg(varvals, "ers_varvalsXXX.fits", CPL_IO_CREATE, NULL);
1861 eris_ifu_save_image_dbg(residual, "ers_residual.fits", CPL_IO_CREATE, NULL);
1862 }
1863
1864 // need to set clip value slice by slice
1865 // fit linear function to first 90% of sorted residual values and clip
1866 for (int iz = 0; iz < nz; iz++) {
1867 cpl_vector *resvec0 = eris_ifu_opt_extr_get_row(residual, iz);
1868 double *presvec0 = cpl_vector_get_data(resvec0);
1869
1870 if (productDepth >= PD_DEBUG) {
1871 eris_ifu_save_vector_dbg(resvec0, "ers_resvec0.fits", CPL_IO_CREATE, NULL);
1872 }
1873
1874 // vector 'keep0' with indices on which values to keep
1875 keep0 = cpl_vector_new(n_usepix);
1876 cpl_vector_fill(keep0, -1.0);
1877 pkeep0 = cpl_vector_get_data(keep0);
1878 jj = 0;
1879 for (int ii = 0; ii < n_usepix; ii++) {
1880 if (!eris_ifu_is_nan_or_inf(presvec0[ii]) &&
1881 presvec0[ii] > 0.)
1882 {
1883 pkeep0[jj++]= ii;
1884 }
1885 }
1887 eris_ifu_cut_endings(&keep0, NULL, NULL, TRUE));
1888
1889 if (productDepth >= PD_DEBUG) {
1890 eris_ifu_save_vector_dbg(keep0, "ers_keep.fits", CPL_IO_CREATE, NULL);
1891 }
1892
1893 cpl_vector *p = eris_ifu_opt_extr_get_row(psfmod, iz);
1894 double *pp = cpl_vector_get_data(p);
1895
1896 if ((keep0 != NULL) && (cpl_vector_get_size(keep0) > n_usepix*0.25)) {
1897 int nkeep = cpl_vector_get_size(keep0);
1898 cpl_vector *resvec = eris_ifu_idl_values_at_indices(resvec0, keep0),
1899 *resvecs = cpl_vector_duplicate(resvec);
1900 cpl_vector_sort(resvecs, CPL_SORT_ASCENDING);
1901
1902 if ((productDepth >= PD_DEBUG) && (iz == 1000)){
1903 eris_ifu_save_vector_dbg(resvecs, "ers_resvecs.fits", CPL_IO_CREATE, NULL);
1904 }
1905
1906 double clip = cpl_vector_get(resvecs, (int)(nkeep*clipfrac+.5)-1) * 5.;
1907 if (clip < 25.) {
1908 clip = 25.;
1909 }
1910
1911 cpl_vector *q = eris_ifu_opt_extr_get_row(qualvals, iz);
1912 double *pq = cpl_vector_get_data(q);
1913 eris_ifu_free_vector(&keep0);
1914 keep0 = cpl_vector_new(n_usepix);
1915 cpl_vector_fill(keep0, -1.0);
1916 pkeep0 = cpl_vector_get_data(keep0);
1917 jj = 0;
1918 for (int ii = 0; ii < n_usepix; ii++) {
1919 if ((presvec0[ii] > clip) || (pq[ii] == 1)) {
1920 pkeep0[jj++]= ii;
1921 }
1922 }
1924 eris_ifu_cut_endings(&keep0, NULL, NULL, TRUE));
1925 if (keep0 != NULL) {
1926 pkeep0 = cpl_vector_get_data(keep0);
1927 for (int ii = 0; ii < cpl_vector_get_size(keep0); ii++) {
1928 pp[(int)(pkeep0[ii])] = 0.;
1929 }
1930 }
1931
1932 double sum = cpl_vector_get_sum(p);
1933 for (int ii = 0; ii < cpl_vector_get_size(p); ii++) {
1934 pp[ii] /= sum;
1935 }
1936
1938 eris_ifu_free_vector(&resvecs);
1939 eris_ifu_free_vector(&resvec);
1940 } else {
1942 cpl_vector_fill(p, 0.));
1943 }
1944
1946 eris_ifu_opt_extr_set_row(psfmodnew, iz, p));
1947
1948 cpl_vector *vals = eris_ifu_opt_extr_get_row(psfvals, iz),
1949 *var = eris_ifu_opt_extr_get_row(varvals, iz);
1951 eris_ifu_opt_extr_convert_0_to_NaN_vec(var);
1952
1953 // pspeco[iz] = total(p*vals/var)/total(p^2./var)
1954 cpl_vector *tt = cpl_vector_duplicate(p);
1955 cpl_vector_multiply(tt, vals);
1956 cpl_vector_divide(tt, var);
1957 cpl_vector_power(p, 2.0);
1958 cpl_vector_divide(p, var);
1959 double sum_data = cpl_vector_get_sum(tt),
1960 sum_weight = cpl_vector_get_sum(p);
1962 eris_ifu_vector_set(speco, iz, sum_data / sum_weight));
1963
1964 //BRK_IF_ERROR(
1965 // eris_ifu_vector_set(sigo, iz, sqrt(1./total(p^2/var)));
1967 eris_ifu_vector_set(sigo, iz, sqrt(1./sum_weight)));
1968
1970 eris_ifu_free_vector(&vals);
1973 eris_ifu_free_vector(&keep0);
1974 eris_ifu_free_vector(&resvec0);
1976 } // end if: iz
1978 } // endfor: bigloop
1980
1981 // median((speco/sigo)/(spec0/sig0))
1982 eris_ifu_vector *tt = eris_ifu_vector_duplicate(speco);
1983 eris_ifu_vector_divide(tt, sigo);
1984 eris_ifu_vector_power(spec_var_err, -1.);
1985 eris_ifu_vector_divide(tt, spec_var_err);
1987
1988 cpl_msg_info(cpl_func, "typical S/N has increased by %g", eris_ifu_vector_get_median(tt, ERIS_IFU_ARITHMETIC));
1990
1991 cpl_vector *lambda = eris_ifu_opt_extr_create_lambda(nz, startLambda, deltaLambda);
1992 cpl_vector *speco2 = eris_ifu_vector_get_data(speco);
1994 spectrum = cpl_bivector_wrap_vectors(lambda, speco2));
1995
1996 cpl_vector *sigo2 = eris_ifu_vector_get_data(sigo);
1997 *error_out = sigo2;
1998
1999 // return sigo as vector (pow? sqrt?)
2000 // return total_flux??
2001 } CATCH {
2002 CATCH_MSG();
2003 eris_ifu_free_bivector(&spectrum);
2004 eris_ifu_free_vector(error_out);
2005 }
2006
2009 eris_ifu_free_ifu_vector(&spec_var_err);
2010 eris_ifu_free_bivector(&usepix);
2011 eris_ifu_free_image(&spec1);
2012 eris_ifu_free_image(&psfvals);
2013 eris_ifu_free_image(&psfmod);
2014 eris_ifu_free_image(&psfmodnew);
2015 eris_ifu_free_image(&varvals);
2016 eris_ifu_free_image(&qualvals);
2017 eris_ifu_free_image(&reject);
2018 eris_ifu_free_image(&residual);
2019
2020 return spectrum;
2021}
2022
2028int eris_ifu_opt_extr_get_not_finite(cpl_vector *vec) {
2029 int n_fin = 0;
2030 double *pvec = NULL;
2031
2032 cpl_ensure_code(vec != NULL, CPL_ERROR_NULL_INPUT);
2033
2034 pvec = cpl_vector_get_data(vec);
2035
2036 for (int i = 0; i < cpl_vector_get_size(vec); i++) {
2037 if (!eris_ifu_is_nan_or_inf(pvec[i])) {
2038 n_fin++;
2039 }
2040 }
2041
2042 return n_fin;
2043}
2044
2049void eris_ifu_opt_extr_convert_0_to_NaN_vec(cpl_vector *vec)
2050{
2051 cpl_size x = 0;
2052 double *pvec = NULL;
2053
2054 if (vec != NULL) {
2055 pvec = cpl_vector_get_data(vec);
2056
2057 x = cpl_vector_get_size(vec);
2058
2059 for (int i = 0 ; i < x; i++) {
2060 if (fabs(pvec[i]) < DBL_ZERO_TOLERANCE) {
2061 pvec[i] = NAN;
2062 }
2063 }
2064 }
2065}
2066
2067cpl_image* eris_ifu_opt_extr_estimate_radius_helper(const cpl_image *img,
2068 cpl_size center_x, cpl_size center_y,
2069 double radius,
2070 cpl_size *llx, cpl_size *lly,
2071 cpl_size *urx, cpl_size *ury)
2072{
2073 double half_maxval = 0.,
2074 *pmask = NULL;
2075 const double *pimg = NULL;
2076 cpl_image *mask = NULL;
2077 cpl_size nx = 0,
2078 ny = 0;
2079
2080 cpl_ensure(img != NULL, CPL_ERROR_NULL_INPUT, NULL);
2081
2082 TRY {
2083 pimg = cpl_image_get_data_double_const(img);
2084 nx = cpl_image_get_size_x(img);
2085 ny = cpl_image_get_size_y(img);
2086 half_maxval = pimg[center_x+nx*center_y] / 2;
2087
2088 mask = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
2089 pmask = cpl_image_get_data_double(mask);
2090
2091 *llx = center_x - radius;
2092 *lly = center_y - radius;
2093 *urx = center_x + radius;
2094 *ury = center_y + radius;
2095 if (*llx < 0) {
2096 *llx = 0;
2097 }
2098 if (*lly < 0) {
2099 *lly = 0;
2100 }
2101 if (*urx >= nx) {
2102 *urx = nx-1;
2103 }
2104 if (*ury >= ny) {
2105 *ury = ny-1;
2106 }
2107
2108 for (cpl_size x = *llx; x < *urx; x++) {
2109 for (cpl_size y = *lly; y < *ury; y++) {
2110 if (pimg[x+nx*y] >= half_maxval) {
2111 pmask[x+nx*y] = 1;
2112 }
2113 }
2114 }
2115
2116 } CATCH {
2117 CATCH_MSG();
2118 eris_ifu_free_image(&mask);
2119 }
2120
2121 return mask;
2122}
2123
2124double eris_ifu_opt_extr_estimate_radius(const cpl_image *img,
2125 cpl_size center_x, cpl_size center_y,
2126 double initial_radius,
2127 int productDepth)
2128{
2129 double radius = 0.,
2130 inc_radius = 2.,
2131 area_rectangle = 1.,
2132 area_mask = 4.;
2133 cpl_image *mask = NULL;
2134 cpl_size llx = 0,
2135 lly = 0,
2136 urx = 0,
2137 ury = 0,
2138 nx = 0,
2139 ny = 0;
2140
2141 cpl_ensure(img != NULL, CPL_ERROR_NULL_INPUT, -1.);
2142
2143 TRY {
2144 nx = cpl_image_get_size_x(img);
2145 ny = cpl_image_get_size_y(img);
2146 // define a max. radius: half size of image
2147 double max_radius = nx/2;
2148 if (ny/2 < max_radius) {
2149 max_radius = ny/2;
2150 }
2151 radius = initial_radius - inc_radius;
2152 // calculate ratio of good pixels, if > pi/4 make radius bigger
2153
2154 while ((area_mask / area_rectangle >= CPL_MATH_PI_4) && (radius < max_radius)) {
2155 radius += inc_radius;
2156 eris_ifu_free_image(&mask);
2157 mask = eris_ifu_opt_extr_estimate_radius_helper(img,
2158 center_x, center_y,
2159 radius,
2160 &llx, &lly, &urx, &ury);
2161 area_rectangle = (urx-llx)*(ury-lly);
2162 area_mask = cpl_image_get_flux(mask);
2163 if (productDepth >= PD_DEBUG) {
2164 eris_ifu_save_image_dbg(mask, "eris_dbg_mask.fits", CPL_IO_CREATE, NULL);
2165 }
2166 cpl_msg_debug(cpl_func, " intermediate mask center at (%d/%d), radius: %g, area mask: %g, area rect: %g)",
2167 (int)center_x, (int)center_y, radius, area_mask, area_rectangle);
2168
2169 }
2170 if (productDepth >= PD_DEBUG) {
2171 eris_ifu_save_image_dbg(mask, "eris_dbg_mask.fits", CPL_IO_CREATE, NULL);
2172 }
2173 cpl_msg_debug(cpl_func, "Final mask center at (%d/%d), radius: %g, area mask: %g, area rect: %g)",
2174 (int)center_x, (int)center_y, radius, area_mask, area_rectangle);
2175 } CATCH {
2176 CATCH_MSG();
2177 radius = 0.;
2178 }
2179
2180 eris_ifu_free_image(&mask);
2181
2182 return radius;
2183}
2184
2186// * @brief eris_ifu_opt_extr_median_without_NaN
2187// * @param vec
2188// */
2189//double eris_ifu_opt_extr_median_without_NaN(cpl_vector *vec)
2190//{
2191// cpl_size x = 0;
2192// double *pvec = NULL,
2193// *ptmp = NULL,
2194// median = -1.;
2195// int cnt = 0;
2196// cpl_vector *tmp = NULL;
2197//
2198// if (vec != NULL) {
2199// pvec = cpl_vector_get_data(vec);
2200//
2201// x = cpl_vector_get_size(vec);
2202// for (int i = 0 ; i < x; i++) {
2203// if (eris_ifu_is_nan_or_inf(pvec[i])) {
2204// cnt++;
2205// }
2206// }
2207//
2208// if ((x-cnt) > 0) {
2209// tmp = cpl_vector_new(x-cnt);
2210// ptmp = cpl_vector_get_data(tmp);
2211// cnt = 0;
2212// for (int i = 0 ; i < x; i++) {
2213// if (!eris_ifu_is_nan_or_inf(pvec[i])) {
2214// ptmp[cnt++] = pvec[i];
2215// }
2216// }
2217//
2218// median = cpl_vector_get_median(tmp);
2219// eris_ifu_free_vector(&tmp);
2220// }
2221// }
2222// return median;
2223//}
2224
2233cpl_error_code eris_ifu_cpl_vector_sqrt(cpl_vector *vec)
2234{
2235 cpl_size n = 0;
2236 double *pvec = NULL;
2237 cpl_error_code err = CPL_ERROR_NONE;
2238
2239 cpl_ensure_code(vec, CPL_ERROR_NULL_INPUT);
2240
2241 TRY
2242 {
2243 n = cpl_vector_get_size(vec);
2245
2247 pvec = cpl_vector_get_data(vec));
2248
2249 /* Compute the sqrt */
2250 for (int i = 0; i < n; i++) {
2251 /* pvec[i] can be NaN, since sqrt() handles NaN correctly:
2252 sqrt(NaN) = NaN */
2253 if (pvec[i] >= 0) {
2254 pvec[i] = sqrt(pvec[i]);
2255 } else {
2256 pvec[i] = NAN;
2257 }
2258 }
2259 } CATCH {
2260 err = cpl_error_get_code();
2261 }
2262
2263 return err;
2264}
#define ASSURE(condition, error,...)
error handling macro (from fors-pipeline)
#define BRK_IF_ERROR(function)
If function is or returns an error != CPL_ERROR_NONE, then the try-block is exited.
#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 CATCH_MSG()
Displays an error message.
#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.
void eris_ifu_free_propertylist(cpl_propertylist **item)
free memory and set pointer to null
cpl_vector * eris_ifu_idl_values_at_indices(const cpl_vector *data, const cpl_vector *indices)
Returns a vector of given indices.
void eris_ifu_free_vector(cpl_vector **item)
free memory and set pointer to null
cpl_error_code eris_ifu_save_vector_dbg(const cpl_vector *vec, const char *filename, int create, const cpl_propertylist *pl)
save vector
cpl_error_code eris_ifu_save_image_dbg(const cpl_image *img, const char *filename, int create, const cpl_propertylist *pl)
eris_ifu_save_image_dbg
cpl_error_code eris_ifu_cut_endings(cpl_vector **vec, int *begin, int *end, int cut)
Cut leading and trailing -1 of a vector.
void eris_ifu_free_ifu_vector(eris_ifu_vector **item)
free memory and set pointer to null
cpl_error_code eris_ifu_save_bivector_dbg(const cpl_bivector *bivec, const char *filename, int col, int create)
save bivector as a vector (col=1 or col=2) or as a table
cpl_error_code eris_ifu_save_mask_dbg(const cpl_mask *mask, const char *filename, int create, const cpl_propertylist *pl)
eris_ifu_save_mask_dbg
void eris_ifu_free_imagelist(cpl_imagelist **item)
free memory and set pointer to null
cpl_vector * eris_ifu_idl_where(const cpl_vector *data, double val, int op)
Implements the where-function knownm from IDL.
void eris_ifu_free_hdrl_imagelist(hdrl_imagelist **item)
free memory and set pointer to null
cpl_mask * eris_ifu_mask_from_image(const cpl_image *img_mask)
eris_ifu_mask_from_image
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_mask(cpl_mask **item)
free memory and set pointer to null
void eris_ifu_free_bivector(cpl_bivector **item)
free memory and set pointer to null
int eris_ifu_vector_get_size(const eris_ifu_vector *ev)
Get the size of the eris_ifu_vector.
int eris_ifu_is_nan_or_inf(double A)
Checks if a value is nan, inf or -inf.
eris_ifu_vector * eris_ifu_vector_new(int n)
Create a new eris_ifu_vector.
cpl_vector * eris_ifu_vector_get_data(const eris_ifu_vector *ev)
Get a copy of the data, rejected values are set to NaN.
cpl_error_code eris_ifu_vector_sqrt(eris_ifu_vector *ev)
eris_ifu_vector_sqrt
eris_ifu_vector * eris_ifu_vector_duplicate(const eris_ifu_vector *ev)
This function duplicates an existing eris_ifu_vector and allocates memory.
cpl_error_code eris_ifu_vector_set(eris_ifu_vector *ev, int pos, double val)
Set an element of the eris_ifu_vector.
cpl_error_code eris_ifu_vector_power(eris_ifu_vector *ev, double exponent)
Compute the elementwise power of the vector.
eris_ifu_vector * eris_ifu_vector_create(const cpl_vector *data)
Create a new eris_ifu_vector out of a data cpl_vector.
cpl_error_code eris_ifu_vector_divide(eris_ifu_vector *kv1, const eris_ifu_vector *kv2)
Divide two eris_ifu_vectors element-wise.
double eris_ifu_vector_get_median(const eris_ifu_vector *ev, const enum medianType type)
Compute the median of the elements of a vector.
cpl_error_code eris_check_error_code(const char *func_id)
handle CPL errors
Definition: eris_utils.c:56
cpl_error_code hdrl_image_reject_from_mask(hdrl_image *self, const cpl_mask *map)
set bpm of hdrl_image
Definition: hdrl_image.c:407
hdrl_image * hdrl_image_duplicate(const hdrl_image *himg)
copy hdrl_image
Definition: hdrl_image.c:391
hdrl_value hdrl_image_get_sum(const hdrl_image *self)
computes the sum of all pixel values and the associated error of an image.
cpl_image * hdrl_image_get_error(hdrl_image *himg)
get error as cpl image
Definition: hdrl_image.c:131
cpl_size hdrl_image_get_size_y(const hdrl_image *self)
return size of Y dimension of image
Definition: hdrl_image.c:540
const cpl_mask * hdrl_image_get_mask_const(const hdrl_image *himg)
get cpl bad pixel mask from image
Definition: hdrl_image.c:175
cpl_size hdrl_image_get_size_x(const hdrl_image *self)
return size of X dimension of image
Definition: hdrl_image.c:525
const cpl_image * hdrl_image_get_error_const(const hdrl_image *himg)
get error as cpl image
Definition: hdrl_image.c:144
cpl_image * hdrl_image_get_image(hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:105
const cpl_image * hdrl_image_get_image_const(const hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:118
void hdrl_image_delete(hdrl_image *himg)
delete hdrl_image
Definition: hdrl_image.c:379
cpl_size hdrl_imagelist_get_size_y(const hdrl_imagelist *himlist)
Get number of rows of images in the imagelist.
const hdrl_image * hdrl_imagelist_get_const(const hdrl_imagelist *himlist, cpl_size inum)
Get an image from a list of images.
cpl_size hdrl_imagelist_get_size(const hdrl_imagelist *himlist)
Get the number of images in the imagelist.
cpl_error_code hdrl_imagelist_collapse(const hdrl_imagelist *himlist, const hdrl_parameter *param, hdrl_image **out, cpl_image **contrib)
collapsing of image list
cpl_size hdrl_imagelist_get_size_x(const hdrl_imagelist *himlist)
Get number of colums of images in the imagelist.
hdrl_image * hdrl_imagelist_get(const hdrl_imagelist *himlist, cpl_size inum)
Get an image from a list of images.