ERIS Pipeline Reference Manual 1.8.10
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{
260 cpl_bivector *spectrum = NULL;
261 cpl_imagelist *data_in = NULL;
262 cpl_imagelist *error_in = NULL;
263 const cpl_image *tmpDataImg = NULL;
264 const cpl_image *tmpErrorImg = NULL;
265 const cpl_mask *bpm = NULL;
266 const double *pTmpData = NULL;
267 const double *pTmpError = NULL;
268 const cpl_binary *pBpm = NULL;
269 const double *pMask = NULL;
270 cpl_size nx, ny, nz;
271 cpl_size fill_nz;
272 cpl_vector *lambda = NULL;
273 cpl_vector *spec_data = NULL;
274 cpl_vector *spec_error = NULL;
275 cpl_vector *spec_totFlux = NULL;
276 double *pLambda = NULL;;
277 double *pData = NULL;;
278 double *pError = NULL;;
279 double *pTotFlux = NULL;;
280 double sumData;
281 double sumVariance;
282 double weights;
283 bool valid;
284
285
286 cpl_ensure(cube != NULL,CPL_ERROR_NULL_INPUT, NULL);
287 cpl_ensure(mask != NULL,CPL_ERROR_NULL_INPUT, NULL);
288 cpl_ensure(error != NULL,CPL_ERROR_NULL_INPUT, NULL);
289 cpl_ensure(totalFlux != NULL,CPL_ERROR_NULL_INPUT, NULL);
290
291 TRY{
292 nx = hdrl_imagelist_get_size_x(cube);
293 ny = hdrl_imagelist_get_size_y(cube);
294 nz = hdrl_imagelist_get_size(cube);
295
296 ASSURE((nx == cpl_image_get_size_x(mask)) &&
297 (ny == cpl_image_get_size_y(mask)),
298 CPL_ERROR_ILLEGAL_INPUT,
299 "Data cube and mask don't have same dimensions!");
300
301
302 BRK_IF_NULL(data_in = cpl_imagelist_new());
303 BRK_IF_NULL(error_in = cpl_imagelist_new());
304 for (cpl_size sz = 0; sz < nz; sz++) {
305 hdrl_image *tmpImg = hdrl_imagelist_get(cube, sz);
306 cpl_imagelist_set(data_in, cpl_image_duplicate(hdrl_image_get_image(tmpImg)), sz);
307 cpl_imagelist_set(error_in, cpl_image_duplicate(hdrl_image_get_error(tmpImg)), sz);
308 }
310
311 lambda = cpl_vector_new(nz);
312 spec_data = cpl_vector_new(nz);
313 spec_error = cpl_vector_new(nz);
314 spec_totFlux = cpl_vector_new(nz);
315 pLambda = cpl_vector_get_data(lambda);
316 pData = cpl_vector_get_data(spec_data);
317 pError = cpl_vector_get_data(spec_error);
318 pTotFlux = cpl_vector_get_data(spec_totFlux);
319 pMask = cpl_image_get_data_double_const(mask);
321
322 // loop over all lambda slices
323 fill_nz = 0;
324 for (cpl_size sz = 0; sz < nz; sz++) {
325 tmpDataImg = cpl_imagelist_get(data_in, sz);
326 tmpErrorImg = cpl_imagelist_get(error_in, sz);
327 bpm = cpl_image_get_bpm_const(tmpDataImg);
328 pTmpData = cpl_image_get_data_double_const(tmpDataImg);
329 pTmpError = cpl_image_get_data_double_const(tmpErrorImg);
330 pBpm = cpl_mask_get_data_const(bpm);
332
333 // extract spectrum for data
334 sumData = 0.0;
335 sumVariance = 0.0;
336 weights = 0.0;
337 valid = false;
338 for (cpl_size j = 0; j < ny; j++) {
339 for (cpl_size i = 0; i < nx; i++) {
340 // sumData weighted pixels in spatial plane
341 cpl_size p = i+j*nx;
342 if ((pBpm[p] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[p])) {
343 valid = true;
344 if (mask != NULL) {
345 sumData += pTmpData[p] * pMask[p];
346 sumVariance += pow(pTmpError[p] * pMask[p],2);
347 weights += pMask[p];
348 /* AMo: temporarily added for debug to make some check on problematic data
349 if(startLambda + (double) sz * deltaLambda > 2.254 &&
350 startLambda + (double) sz * deltaLambda < 2.270 ) {
351 cpl_msg_info(cpl_func,"ok1: pMask[p]: %g",pMask[p]);
352 }
353 */
354 } else {
355 sumData += pTmpData[p];
356 sumVariance += pow(pTmpError[p],2);
357 weights += 1.;
358 }
359 }
360 }
361 }
362
363 if ((valid == true) && (fabs(weights) > DBL_ZERO_TOLERANCE)) {
364 pLambda[fill_nz] = startLambda + (double) sz * deltaLambda;
365 pData[fill_nz] = sumData / weights;
366 pError[fill_nz] = sqrt(sumVariance) / weights;
367 pTotFlux[fill_nz] = sumData;
368 fill_nz++;
369 }
371 }
372 BRK_IF_ERROR(cpl_vector_set_size(lambda, fill_nz));
373 BRK_IF_ERROR(cpl_vector_set_size(spec_data, fill_nz));
374 BRK_IF_ERROR(cpl_vector_set_size(spec_error, fill_nz));
375 BRK_IF_ERROR(cpl_vector_set_size(spec_totFlux, fill_nz));
376
377 spectrum = cpl_bivector_wrap_vectors(lambda, spec_data);
378 *error = spec_error;
379 *totalFlux = spec_totFlux;
380 cpl_imagelist_delete(data_in);
381 cpl_imagelist_delete(error_in);
382 } CATCH {
383 spectrum = NULL;
384 }
385 eris_check_error_code("eris_ifu_extract_spectrum");
386 return spectrum;
387}
388
389
390
391
392
393//cpl_bivector * eris_ifu_extract_spectrum2(
394// hdrl_imagelist *cube,
395// cpl_image *mask,
396// double startLambda,
397// double deltaLambda,
398// cpl_vector **error,
399// cpl_vector **totalFlux)
400//{
401// cpl_bivector *spectrum = NULL;
402// cpl_imagelist *data_in = NULL;
403// cpl_imagelist *error_in = NULL;
404// const cpl_image *tmpDataImg = NULL;
405// const cpl_image *tmpErrorImg = NULL;
406// const cpl_mask *bpm = NULL;
407// const double *pTmpData = NULL;
408// const double *pTmpError = NULL;
409// const cpl_binary *pBpm = NULL;
410// const double *pMask = NULL;
411// cpl_size nx, ny, nz;
412// cpl_size fill_nz;
413// cpl_vector *lambda = NULL;
414// cpl_vector *spec_data = NULL;
415// cpl_vector *spec_error = NULL;
416// cpl_vector *spec_totFlux = NULL;
417// double *pLambda = NULL;;
418// double *pData = NULL;;
419// double *pError = NULL;;
420// double *pTotFlux = NULL;;
421// double sumData;
422// double sumVariance;
423// double weights;
424// bool valid;
425
426// hdrl_image* cube_median = NULL;
427// cpl_image* cube_median_data = NULL;
428// cpl_image* cube_median_errs = NULL;
429// cpl_image* scale_factor_data = NULL;
430// cpl_image* scale_factor_errs = NULL;
431// const double *pFactorData = NULL;
433// const double *pModelData = NULL;
434// const double *pModelErrs = NULL;
437// double model_factor_avg = 0;
438
439// cpl_size model_ndata = 0;
440// const cpl_size kernel_sx = 5;
441// const cpl_size kernel_sy = 5;
442// cpl_image* contrib_map;
443
444// cpl_ensure(cube != NULL,CPL_ERROR_NULL_INPUT, NULL);
445// cpl_ensure(mask != NULL,CPL_ERROR_NULL_INPUT, NULL);
446// cpl_ensure(error != NULL,CPL_ERROR_NULL_INPUT, NULL);
447
448// TRY{
449// nx = hdrl_imagelist_get_size_x(cube);
450// ny = hdrl_imagelist_get_size_y(cube);
451// nz = hdrl_imagelist_get_size(cube);
452
453// ASSURE((nx == cpl_image_get_size_x(mask)) &&
454// (ny == cpl_image_get_size_y(mask)),
455// CPL_ERROR_ILLEGAL_INPUT,
456// "Data cube and mask don't have same dimensions!");
457// eris_print_rec_status(0);
458// hdrl_imagelist_collapse_median(cube, &cube_median, &contrib_map);
459// eris_print_rec_status(1);
460// cube_median_data = hdrl_image_get_image(cube_median);
461// cube_median_errs = hdrl_image_get_error(cube_median);
462// cpl_image_save(cube_median_data,"cube_median_data.fits",CPL_TYPE_DOUBLE,NULL,CPL_IO_DEFAULT);
463// eris_print_rec_status(2);
464// data_in = cpl_imagelist_new();
465// error_in = cpl_imagelist_new();
466// for (cpl_size sz = 0; sz < nz; sz++) {
467// hdrl_image *tmpImg = hdrl_imagelist_get(cube, sz);
468// cpl_imagelist_set(data_in, cpl_image_duplicate(hdrl_image_get_image(tmpImg)), sz);
469// cpl_imagelist_set(error_in, cpl_image_duplicate(hdrl_image_get_error(tmpImg)), sz);
470// }
471// CHECK_ERROR_STATE();
472
473// lambda = cpl_vector_new(nz);
474// spec_data = cpl_vector_new(nz);
475// spec_error = cpl_vector_new(nz);
476// spec_totFlux = cpl_vector_new(nz);
477// pLambda = cpl_vector_get_data(lambda);
478// pData = cpl_vector_get_data(spec_data);
479// pError = cpl_vector_get_data(spec_error);
480// pTotFlux = cpl_vector_get_data(spec_totFlux);
481// pMask = cpl_image_get_data_double_const(mask);
482// CHECK_ERROR_STATE();
483
484// // loop over all lambda slices
485// fill_nz = 0;
486// for (cpl_size sz = 0; sz < nz; sz++) {
487// tmpDataImg = cpl_imagelist_get(data_in, sz);
488// tmpErrorImg = cpl_imagelist_get(error_in, sz);
489// bpm = cpl_image_get_bpm_const(tmpDataImg);
490// pTmpData = cpl_image_get_data_double_const(tmpDataImg);
491// pTmpError = cpl_image_get_data_double_const(tmpErrorImg);
492// pBpm = cpl_mask_get_data_const(bpm);
493// eris_print_rec_status(0);
494// scale_factor_data = cpl_image_duplicate(tmpDataImg);
495// scale_factor_errs = cpl_image_duplicate(tmpErrorImg);
496// eris_print_rec_status(1);
497// cpl_image_power(scale_factor_errs, 2);
498// cpl_image_power(scale_factor_errs, 2);
499// eris_print_rec_status(2);
500// cpl_image_divide(scale_factor_data, cube_median_data);
501// cpl_image_divide(scale_factor_errs, cube_median_errs);
502// eris_print_rec_status(3);
503// pFactorData = cpl_image_get_data_double_const(scale_factor_data);
505// eris_print_rec_status(4);
506// pModelData = cpl_image_get_data_double_const(cube_median_data);
507// pModelErrs = cpl_image_get_data_double_const(cube_median_errs);
508// eris_print_rec_status(5);
509// CHECK_ERROR_STATE();
510
511// // extract spectrum for data
512// sumData = 0.0;
513// sumVariance = 0.0;
514// weights = 0.0;
515// valid = false;
516// for (cpl_size j = 0; j < ny; j++) {
517// for (cpl_size i = 0; i < nx; i++) {
518// // sumData weighted pixels in spatial plane
519// cpl_size p = i+j*nx;
522// model_ndata = 0;
523// if ((pBpm[p] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[p])) {
524// valid = true;
525// if (mask != NULL) {
526// sumData += pTmpData[p] * pMask[p];
527// sumVariance += pow(pTmpError[p] * pMask[p],2);
528// weights += pMask[p];
529// } else {
530// sumData += pTmpData[p];
531// sumVariance += pow(pTmpError[p],2);
532// weights += 1.;
533// }
534// } else {
535
536// /* we are on a bad pixel, we need to interpolate flux
537// * using the model */
538// /* Determine average factor: plane_data / model */
539// for (cpl_size jj = -kernel_sy; jj <= kernel_sy; jj++) {
540// for (cpl_size ii = -kernel_sx; ii <= kernel_sx; ii++) {
541// if( (i+ii) >= 0 && (i+ii) < nx &&
542// (j+jj) >= 0 && (j+jj) < ny) {
543
544// cpl_size pp = (i+ii)+(j+jj)*nx;
545// if ((pBpm[pp] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[pp])) {
546// model_factor_avg += pFactorData[pp];
547// model_ndata ++;
548// }
549// }
550// }
551// }
552// if(model_ndata>0) {
553// model_factor_avg /= model_ndata;
554// }
555
556// /* compute contribute from interpolated bad pixels
557// * scaling data from model and add it to flux determined
558// * on good data
559// */
560// if (!eris_ifu_is_nan_or_inf(pModelData[p])) {
561// valid = true;
562// if (mask != NULL) {
563// sumData += model_factor_avg * pModelData[p] * pMask[p];
564// sumVariance += pow(model_factor_avg * pModelErrs[p] * pMask[p],2);
565// weights += pMask[p];
566// if(startLambda + (double) sz * deltaLambda > 1.615 &&
567// startLambda + (double) sz * deltaLambda < 1.647 ) {
568// cpl_msg_info(cpl_func,"lambda: %g model: %g",pLambda[fill_nz], pModelData[p]);
569// }
570// } else {
571// sumData += model_factor_avg * pModelData[p];
572// sumVariance += pow(model_factor_avg * pModelErrs[p],2);
573// weights += 1.;
574// }
575// }
576
577// }
578// }
579// }
580
581// if ((valid == true) && (fabs(weights) > DBL_ZERO_TOLERANCE)) {
582// pLambda[fill_nz] = startLambda + (double) sz * deltaLambda;
583// pData[fill_nz] = sumData / weights;
584// pError[fill_nz] = sqrt(sumVariance) / weights;
585// pTotFlux[fill_nz] = sumData;
586// if(startLambda + (double) sz * deltaLambda > 1.615 &&
587// startLambda + (double) sz * deltaLambda < 1.647 ) {
588// cpl_msg_info(cpl_func,"lambda: %g flux: %g",pLambda[fill_nz], pData[fill_nz]);
589// }
590// fill_nz++;
591
592// }
593// cpl_image_delete(scale_factor_data);
594// cpl_image_delete(scale_factor_errs);
595// CHECK_ERROR_STATE();
596// }
597// BRK_IF_ERROR(cpl_vector_set_size(lambda, fill_nz));
598// BRK_IF_ERROR(cpl_vector_set_size(spec_data, fill_nz));
599// BRK_IF_ERROR(cpl_vector_set_size(spec_error, fill_nz));
600// BRK_IF_ERROR(cpl_vector_set_size(spec_totFlux, fill_nz));
601
602// spectrum = cpl_bivector_wrap_vectors(lambda, spec_data);
603// *error = spec_error;
604// *totalFlux = spec_totFlux;
605// cpl_imagelist_delete(data_in);
606// cpl_imagelist_delete(error_in);
607// hdrl_image_delete(cube_median);
608// cpl_image_delete(contrib_map);
609// } CATCH
610// {
611// spectrum = NULL;
612// }
613// eris_check_error_code("eris_ifu_extract_spectrum2");
614// return spectrum;
615//}
616
617
618
619//cpl_bivector * eris_ifu_extract_spectrum3(
620// hdrl_imagelist *cube,
621// cpl_image *mask,
622// double startLambda,
623// double deltaLambda,
624// cpl_vector **error,
625// cpl_vector **totalFlux)
626//{
627// cpl_bivector *spectrum = NULL;
628// cpl_imagelist *data_in = NULL;
629// cpl_imagelist *error_in = NULL;
630// const cpl_image *tmpDataImg = NULL;
631// const cpl_image *tmpErrorImg = NULL;
632// const cpl_mask *bpm = NULL;
633// const double *pTmpData = NULL;
634// const double *pTmpError = NULL;
635// const cpl_binary *pBpm = NULL;
636// const double *pMask = NULL;
637// cpl_size nx, ny, nz;
638// cpl_size fill_nz;
639// cpl_vector *lambda = NULL;
640// cpl_vector *spec_data = NULL;
641// cpl_vector *spec_error = NULL;
642// cpl_vector *spec_totFlux = NULL;
643// double *pLambda = NULL;;
644// double *pData = NULL;;
645// double *pError = NULL;;
646// double *pTotFlux = NULL;;
647// double sumData;
648// double sumVariance;
649// double weights;
650// bool valid;
651
652// cpl_imagelist* cube_data_tmp = NULL;
653// cpl_imagelist* cube_errs_tmp = NULL;
654// hdrl_image* cube_median = NULL;
655// cpl_image* cube_median_data = NULL;
656// cpl_image* cube_median_errs = NULL;
657// cpl_image* scale_factor_data = NULL;
658// cpl_image* scale_factor_errs = NULL;
659// const double *pFactorData = NULL;
661// const double *pModelData = NULL;
662// const double *pModelErrs = NULL;
665// double model_factor_avg = 0;
666
667// cpl_size model_def_hsize = 100;
668// cpl_size model_ndata = 0;
669// const cpl_size kernel_sx = 5;
670// const cpl_size kernel_sy = 5;
671// cpl_image* contrib_map;
672
673// cpl_ensure(cube != NULL,CPL_ERROR_NULL_INPUT, NULL);
674// cpl_ensure(mask != NULL,CPL_ERROR_NULL_INPUT, NULL);
675// cpl_ensure(error != NULL,CPL_ERROR_NULL_INPUT, NULL);
676
677// TRY {
678// eris_print_rec_status(0);
679// nx = hdrl_imagelist_get_size_x(cube);
680// ny = hdrl_imagelist_get_size_y(cube);
681// nz = hdrl_imagelist_get_size(cube);
682// eris_print_rec_status(1);
683// ASSURE((nx == cpl_image_get_size_x(mask)) &&
684// (ny == cpl_image_get_size_y(mask)),
685// CPL_ERROR_ILLEGAL_INPUT,
686// "Data cube and mask don't have same dimensions!");
687
688// hdrl_imagelist_collapse_median(cube, &cube_median, &contrib_map);
689// eris_print_rec_status(2);
690// cube_median_data = hdrl_image_get_image(cube_median);
691// cube_median_errs = hdrl_image_get_error(cube_median);
692// cpl_image_save(cube_median_data,"cube_median_data.fits",CPL_TYPE_DOUBLE,NULL,CPL_IO_DEFAULT);
693// eris_print_rec_status(3);
694// data_in = cpl_imagelist_new();
695// error_in = cpl_imagelist_new();
696// for (cpl_size sz = 0; sz < nz; sz++) {
697// hdrl_image *tmpImg = hdrl_imagelist_get(cube, sz);
698// cpl_imagelist_set(data_in, cpl_image_duplicate(hdrl_image_get_image(tmpImg)), sz);
699// cpl_imagelist_set(error_in, cpl_image_duplicate(hdrl_image_get_error(tmpImg)), sz);
700// }
701// eris_print_rec_status(4);
702// CHECK_ERROR_STATE();
703
704// lambda = cpl_vector_new(nz);
705// spec_data = cpl_vector_new(nz);
706// spec_error = cpl_vector_new(nz);
707// spec_totFlux = cpl_vector_new(nz);
708// pLambda = cpl_vector_get_data(lambda);
709// pData = cpl_vector_get_data(spec_data);
710// pError = cpl_vector_get_data(spec_error);
711// pTotFlux = cpl_vector_get_data(spec_totFlux);
712// pMask = cpl_image_get_data_double_const(mask);
713// eris_print_rec_status(5);
714// CHECK_ERROR_STATE();
715
716// // loop over all lambda slices
717// fill_nz = 0;
718// for (cpl_size sz = 0; sz < nz; sz++) {
719// eris_print_rec_status(6);
720// tmpDataImg = cpl_imagelist_get(data_in, sz);
721// tmpErrorImg = cpl_imagelist_get(error_in, sz);
722// bpm = cpl_image_get_bpm_const(tmpDataImg);
723// pTmpData = cpl_image_get_data_double_const(tmpDataImg);
724// pTmpError = cpl_image_get_data_double_const(tmpErrorImg);
725// pBpm = cpl_mask_get_data_const(bpm);
726// eris_print_rec_status(7);
727
728// /* determine local model on a slice of half size model_def_hsize */
729// if( sz >= model_def_hsize && sz < (nz-model_def_hsize)) {
730// cube_data_tmp = cpl_imagelist_new();
731// cube_errs_tmp = cpl_imagelist_new();
732// for(cpl_size k = 0; k <= 2*model_def_hsize; k++) {
733// cpl_size kk = sz - model_def_hsize + k;
734// cpl_imagelist_set(cube_data_tmp, cpl_imagelist_get(data_in, kk), k);
735// cpl_imagelist_set(cube_errs_tmp, cpl_imagelist_get(error_in, kk), k);
736// }
737
738// cube_median_data = cpl_imagelist_collapse_median_create(cube_data_tmp);
739// cube_median_errs = cpl_imagelist_collapse_median_create(cube_errs_tmp);
740
741// }
742// eris_print_rec_status(8);
743// scale_factor_data = cpl_image_duplicate(tmpDataImg);
744// scale_factor_errs = cpl_image_duplicate(tmpErrorImg);
745
746// cpl_image_power(scale_factor_errs, 2);
747// cpl_image_power(cube_median_errs, 2);
748// eris_print_rec_status(9);
749// if(cube_median_data != NULL) {
750// cpl_msg_warning(cpl_func,"Median data for sz: %lld", sz);
751// cpl_image_divide(scale_factor_data, cube_median_data);
752// } else {
753// cpl_msg_warning(cpl_func,"Median data for sz: %lld", sz);
754// }
755// if(cube_median_data != NULL) {
756// cpl_image_divide(scale_factor_errs, cube_median_errs);
757// } else {
758// cpl_msg_warning(cpl_func,"Median error for sz: %lld", sz);
759// }
760// eris_print_rec_status(10);
761// pFactorData = cpl_image_get_data_double_const(scale_factor_data);
763
764// pModelData = cpl_image_get_data_double_const(cube_median_data);
765// pModelErrs = cpl_image_get_data_double_const(cube_median_errs);
766// eris_print_rec_status(11);
767// CHECK_ERROR_STATE();
768
769// // extract spectrum for data
770// sumData = 0.0;
771// sumVariance = 0.0;
772// weights = 0.0;
773// valid = false;
774// eris_print_rec_status(12);
775// for (cpl_size j = 0; j < ny; j++) {
776// for (cpl_size i = 0; i < nx; i++) {
777// // sumData weighted pixels in spatial plane
778// cpl_size p = i+j*nx;
781// model_ndata = 0;
782// if ((pBpm[p] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[p])) {
783// valid = true;
784// if (mask != NULL) {
785// sumData += pTmpData[p] * pMask[p];
786// sumVariance += pow(pTmpError[p] * pMask[p],2);
787// weights += pMask[p];
788// } else {
789// sumData += pTmpData[p];
790// sumVariance += pow(pTmpError[p],2);
791// weights += 1.;
792// }
793// } else {
794
795// /* we are on a bad pixel, we need to interpolate flux
796// * using the model */
797// /* Determine average factor: plane_data / model */
798// for (cpl_size jj = -kernel_sy; jj <= kernel_sy; jj++) {
799// for (cpl_size ii = -kernel_sx; ii <= kernel_sx; ii++) {
800// if( (i+ii) >= 0 && (i+ii) < nx &&
801// (j+jj) >= 0 && (j+jj) < ny) {
802
803// cpl_size pp = (i+ii)+(j+jj)*nx;
804// if ((pBpm[pp] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[pp])) {
805// model_factor_avg += pFactorData[pp];
806// model_ndata ++;
807// }
808// }
809// }
810// }
811// if(model_ndata>0) {
812// model_factor_avg /= model_ndata;
813// }
814
815// /* compute contribute from interpolated bad pixels
816// * scaling data from model and add it to flux determined
817// * on good data
818// */
819// if (!eris_ifu_is_nan_or_inf(pModelData[p])) {
820// valid = true;
821// if (mask != NULL) {
822// sumData += model_factor_avg * pModelData[p] * pMask[p];
823// sumVariance += pow(model_factor_avg * pModelErrs[p] * pMask[p],2);
824// weights += pMask[p];
825// /*
826// if(startLambda + (double) sz * deltaLambda > 1.615 &&
827// startLambda + (double) sz * deltaLambda < 1.647 ) {
828// cpl_msg_info(cpl_func,"lambda: %g model: %g",pLambda[fill_nz], pModelData[p]);
829// }
830// */
831// } else {
832// sumData += model_factor_avg * pModelData[p];
833// sumVariance += pow(model_factor_avg * pModelErrs[p],2);
834// weights += 1.;
835// }
836// }
837
838// }
839// }
840// }
841// eris_print_rec_status(13);
842// if ((valid == true) && (fabs(weights) > DBL_ZERO_TOLERANCE)) {
843// pLambda[fill_nz] = startLambda + (double) sz * deltaLambda;
844// pData[fill_nz] = sumData / weights;
845// pError[fill_nz] = sqrt(sumVariance) / weights;
846// pTotFlux[fill_nz] = sumData;
847// /*
848// if(startLambda + (double) sz * deltaLambda > 1.615 &&
849// startLambda + (double) sz * deltaLambda < 1.647 ) {
850// cpl_msg_info(cpl_func,"lambda: %g flux: %g",pLambda[fill_nz], pData[fill_nz]);
851// }
852// */
853// fill_nz++;
854
855// }
856// eris_print_rec_status(14);
857// cpl_image_delete(scale_factor_data);
858// cpl_image_delete(scale_factor_errs);
859// if( sz >= model_def_hsize && sz < (nz-model_def_hsize)) {
860// cpl_image_delete(cube_median_data);
861// cpl_image_delete(cube_median_errs);
862// for(cpl_size k = 2*model_def_hsize; k >= 0; k--) {
863// cpl_imagelist_unset(cube_data_tmp,k);
864// cpl_imagelist_unset(cube_errs_tmp,k);
865// }
866// cpl_imagelist_delete(cube_data_tmp);
867// cpl_imagelist_delete(cube_errs_tmp);
868// }
869// eris_print_rec_status(15);
870// CHECK_ERROR_STATE();
871// }
872// eris_print_rec_status(16);
873// BRK_IF_ERROR(cpl_vector_set_size(lambda, fill_nz));
874// BRK_IF_ERROR(cpl_vector_set_size(spec_data, fill_nz));
875// BRK_IF_ERROR(cpl_vector_set_size(spec_error, fill_nz));
876// BRK_IF_ERROR(cpl_vector_set_size(spec_totFlux, fill_nz));
877
878// spectrum = cpl_bivector_wrap_vectors(lambda, spec_data);
879// *error = spec_error;
880// *totalFlux = spec_totFlux;
881// cpl_imagelist_delete(data_in);
882// cpl_imagelist_delete(error_in);
883// hdrl_image_delete(cube_median);
884// cpl_image_delete(contrib_map);
885// eris_print_rec_status(17);
886// } CATCH
887// {
888// spectrum = NULL;
889// }
890// eris_check_error_code("eris_ifu_extract_spectrum3");
891// return spectrum;
892//}
893
909cpl_bivector * eris_ifu_optimal_extraction(const hdrl_imagelist *cube,
910 const cpl_imagelist *cube_dqi,
911 const cpl_image *img_mask,
912 double startLambda,
913 double deltaLambda,
914 int productDepth,
915 cpl_vector **error_out)
916{
917 cpl_bivector *spectrum = NULL;
918 cpl_mask *mask = NULL;
919 cpl_vector *spec = NULL,
920 *spec_var = NULL;
921 eris_ifu_vector *spec2 = NULL,
922 *spec_var2 = NULL;
923// hdrl_image *img = NULL;
924// cpl_image *contribMap = NULL;
925// cpl_size nx = 0,
926// ny = 0;
927// cpl_size xcen = 0,
928// ycen = 0;
929// double fwhm = 0.;
930
931 cpl_ensure(cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
932 cpl_ensure(cube_dqi != NULL, CPL_ERROR_NULL_INPUT, NULL);
933 cpl_ensure(img_mask != NULL, CPL_ERROR_NULL_INPUT, NULL);
934 cpl_ensure(startLambda > 1.0, CPL_ERROR_NULL_INPUT, NULL);
935 cpl_ensure(deltaLambda > 0, CPL_ERROR_NULL_INPUT, NULL);
936 cpl_ensure(error_out != NULL,CPL_ERROR_NULL_INPUT, NULL);
937
938 TRY {
939// nx = hdrl_imagelist_get_size_x(cube);
940// ny = hdrl_imagelist_get_size_y(cube);
941//
942// // find centre & fwhm from a collapsed image (without fitting)
943// img = eris_ifu_extract_spec_collapse(cube, &contribMap);
944// if (productDepth >= PD_DEBUG) {
945// eris_ifu_save_hdrl_image_dbg(img, "eris_dbg_collapsed_cube", CPL_IO_CREATE, NULL);
946// }
947//
948// BRK_IF_ERROR(
949// eris_ifu_opt_extr_get_center_fwhm(img, edge_trim, &xcen, &ycen, &fwhm));
950// cpl_msg_debug(cpl_func,"Mask center at (%d/%d), FWHM: %g)", (int)xcen, (int)ycen, fwhm);
951//
952// BRK_IF_NULL(
953// mask = eris_ifu_opt_extr_create_mask(nx, ny, xcen, ycen, fwhm));
954// if (productDepth >= PD_DEBUG) {
955// eris_ifu_save_mask_dbg(mask, "eris_dbg_mask.fits", CPL_IO_CREATE, NULL);
956// }
957
958 // convert image to mask
959 // img: 1: good, 0:bad -> mask: 0: good, 1: bad
960 mask = eris_ifu_mask_from_image(img_mask);
961 if (productDepth >= PD_DEBUG) {
962 eris_ifu_save_mask_dbg(mask, "eris_dbg_mask.fits", CPL_IO_CREATE, NULL);
963 }
964
966 eris_ifu_opt_extr_simple_extraction(cube, mask, &spec, &spec_var));
967 if (productDepth >= PD_DEBUG) {
968 eris_ifu_save_vector_dbg(spec, "eris_dbg_spec1.fits", CPL_IO_CREATE, NULL);
969 eris_ifu_save_vector_dbg(spec_var, "eris_dbg_spec1.fits", CPL_IO_EXTEND, NULL);
970 }
971
972 spec2 = eris_ifu_vector_create(spec),
973 spec_var2 = eris_ifu_vector_create(spec_var);
975 spectrum = eris_ifu_opt_extr_doit(cube, cube_dqi, mask,
976 spec2, spec_var2,
977 startLambda, deltaLambda,
978 productDepth,
979 error_out));
981 eris_ifu_free_ifu_vector(&spec_var2);
982
983 if (productDepth >= PD_DEBUG) {
984 // error ist the total error of the masked area
985 eris_ifu_save_bivector_dbg(spectrum, "eris_dbg_spectrum_out.fits", 0, CPL_IO_CREATE);
986 eris_ifu_save_vector_dbg(*error_out, "eris_dbg_spectrum_out.fits", CPL_IO_EXTEND, NULL);
987
988 eris_ifu_save_vector_dbg(cpl_bivector_get_x_const(spectrum), "eris_dbg_spectrum_in.fits", CPL_IO_CREATE, NULL);
989 eris_ifu_save_vector_dbg(spec, "eris_dbg_spectrum_in.fits", CPL_IO_EXTEND, NULL);
990 eris_ifu_opt_extr_vector_sqrt(spec_var);
991 eris_ifu_save_vector_dbg(spec_var, "eris_dbg_spectrum_in.fits", CPL_IO_EXTEND, NULL);
992 }
993 } CATCH
994 {
995 eris_ifu_free_bivector(&spectrum);
996 eris_ifu_free_mask(&mask);
998 eris_ifu_free_ifu_vector(&spec_var2);
999 }
1000// eris_ifu_free_image(&contribMap);
1001 eris_ifu_free_vector(&spec_var);
1002 eris_ifu_free_vector(&spec);
1003 eris_ifu_free_mask(&mask);
1004
1005 return spectrum;
1006}
1007
1016cpl_error_code eris_ifu_opt_extr_get_center_fwhm(const hdrl_image *hdrl_img,
1017 int edge_trim,
1018 cpl_size *xcen,
1019 cpl_size *ycen,
1020 double *fwhm)
1021{
1022 cpl_error_code ret_error = CPL_ERROR_NONE;
1023 double maxval = -9999e10;
1024 const cpl_image *img_data = NULL;
1025 const double *pimg_data = NULL;
1026 const cpl_mask *img_mask = NULL;
1027 const cpl_binary *pimg_mask = NULL;
1028 cpl_size nx = 0;
1029 int npix = 0;
1030
1031 cpl_ensure_code(hdrl_img != NULL, CPL_ERROR_NULL_INPUT);
1032 cpl_ensure_code(edge_trim >= 0, CPL_ERROR_NULL_INPUT);
1033 cpl_ensure_code(xcen, CPL_ERROR_NULL_INPUT);
1034 cpl_ensure_code(ycen, CPL_ERROR_NULL_INPUT);
1035 cpl_ensure_code(fwhm, CPL_ERROR_NULL_INPUT);
1036
1037 TRY {
1039 img_data = hdrl_image_get_image_const(hdrl_img));
1040 nx = cpl_image_get_size_x(img_data);
1042 pimg_data = cpl_image_get_data_double_const(img_data));
1044 img_mask = hdrl_image_get_mask_const(hdrl_img));
1046 pimg_mask = cpl_mask_get_data_const(img_mask));
1047
1048 // find maxval and its position
1049 for (cpl_size x = edge_trim; x < hdrl_image_get_size_x(hdrl_img)-edge_trim; x++) {
1050 for (cpl_size y = edge_trim; y < hdrl_image_get_size_y(hdrl_img)-edge_trim; y++) {
1051 if ((pimg_mask[x+y*nx] == GOOD_PIX) &&
1052 (pimg_data[x+y*nx] > maxval) &&
1053 (!isnan(pimg_data[x+y*nx])))
1054 {
1055 maxval = pimg_data[x+y*nx];
1056 *xcen = x;
1057 *ycen = y;
1058 }
1059 }
1060 }
1061
1062 cpl_msg_debug(cpl_func,"Mask max. value: %g)", maxval);
1063
1064 // find number of pixels where value is bigger than half of maxval
1065 maxval *= 0.5;
1066 for (cpl_size x = edge_trim; x < hdrl_image_get_size_x(hdrl_img)-edge_trim; x++) {
1067 for (cpl_size y = edge_trim; y < hdrl_image_get_size_y(hdrl_img)-edge_trim; y++) {
1068 if ((pimg_mask[x+y*nx] == GOOD_PIX) &&
1069 (pimg_data[x+y*nx] > maxval) &&
1070 (!isnan(pimg_data[x+y*nx])))
1071 {
1072 npix++;
1073 }
1074 }
1075 }
1076
1077 // now define fwhm
1078 *fwhm = sqrt(npix); // a bit larger than the nominal size
1079 //*fwhm = 1.5 * sqrt(npix); // a bit larger than the nominal size
1080 } CATCH {
1081 CATCH_MSG();
1082 ret_error = cpl_error_get_code();
1083 *xcen = -1;
1084 *ycen = -1;
1085 *fwhm = NAN;
1086 }
1087
1088 return ret_error;
1089}
1090
1100cpl_mask* eris_ifu_opt_extr_create_mask(int nx,
1101 int ny,
1102 int xcen,
1103 int ycen,
1104 double fwhm)
1105{
1106 cpl_mask *mask = NULL;
1107 cpl_binary *pmask =NULL;
1108
1109 cpl_ensure(nx > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1110 cpl_ensure(ny > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1111 cpl_ensure(xcen > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1112 cpl_ensure(ycen > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1113 cpl_ensure(fwhm > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1114
1115 TRY {
1117 mask = cpl_mask_new(nx, ny));
1119 pmask = cpl_mask_get_data(mask));
1120
1121 for (int x = 0; x < nx; x++) {
1122 for (int y = 0; y < ny; y++) {
1123 if (fwhm <= sqrt(pow(x-xcen,2)+pow(y-ycen,2))) {
1124 // bad: outside
1125 pmask[x+y*nx] = BAD_PIX;
1126 } else {
1127 // good:inside
1128 pmask[x+y*nx] = GOOD_PIX;
1129 }
1130 }
1131 }
1132 } CATCH {
1133 CATCH_MSG();
1134 eris_ifu_free_mask(&mask);
1135 }
1136
1137 return mask;
1138}
1139
1150cpl_error_code eris_ifu_opt_extr_simple_extraction(const hdrl_imagelist *cube,
1151 const cpl_mask *mask,
1152 cpl_vector **spec,
1153 cpl_vector **spec_var)
1154{
1155 cpl_error_code ret_error = CPL_ERROR_NONE;
1156 const hdrl_image *tmp_img = NULL;
1157 hdrl_image *tmp_img2 = NULL;
1158 double *pspec = NULL,
1159 *pspec_var = NULL;
1160 cpl_size nz = 0;
1161 hdrl_value hv;
1162
1163 cpl_ensure_code(cube != NULL, CPL_ERROR_NULL_INPUT);
1164 cpl_ensure_code(mask != NULL, CPL_ERROR_NULL_INPUT);
1165
1166 TRY {
1167 nz = hdrl_imagelist_get_size(cube);
1168
1170 *spec = cpl_vector_new(nz));
1172 *spec_var = cpl_vector_new(nz));
1174 pspec = cpl_vector_get_data(*spec));
1176 pspec_var = cpl_vector_get_data(*spec_var));
1177
1178 for (int z = 0; z < nz; z++) {
1180 tmp_img = hdrl_imagelist_get_const(cube, z));
1182 tmp_img2 = hdrl_image_duplicate(tmp_img));
1184 hdrl_image_reject_from_mask(tmp_img2, mask));
1185
1186 hv = hdrl_image_get_sum(tmp_img2);
1187 pspec[z] = hv.data;
1188 pspec_var[z] = hv.error*hv.error;
1189 hdrl_image_delete(tmp_img2);
1190 }
1191 } CATCH {
1192 CATCH_MSG();
1193 ret_error = cpl_error_get_code();
1195 eris_ifu_free_vector(spec_var);
1196 }
1197
1198 return ret_error;
1199}
1200
1207cpl_bivector * eris_ifu_opt_extr_helper_usepix(const cpl_mask *mask, int *n_usepix)
1208{
1209 cpl_bivector *usepix = NULL;
1210 int nx = 0,
1211 ny = 0,
1212 index = 0;
1213 double *px = NULL,
1214 *py = NULL;
1215 const cpl_binary *pmask = NULL;
1216
1217 cpl_ensure(mask != NULL, CPL_ERROR_NULL_INPUT, NULL);
1218
1219 TRY {
1220 nx = cpl_mask_get_size_x(mask);
1221 ny = cpl_mask_get_size_y(mask);
1222
1223 // get number of pixels in mask
1224 *n_usepix = (nx * ny) - cpl_mask_count(mask);
1225 cpl_msg_debug(cpl_func,"optimal extraction: n_usepix: %d", *n_usepix);
1226
1227 if (*n_usepix > 0) {
1228 usepix = cpl_bivector_new(*n_usepix);
1229 pmask = cpl_mask_get_data_const(mask);
1230
1231 px = cpl_vector_get_data(cpl_bivector_get_x(usepix));
1232 py = cpl_vector_get_data(cpl_bivector_get_y(usepix));
1233
1234 for (int y = 0; y < ny; y++) {
1235 for (int x = 0; x < nx; x++) {
1236 if (pmask[x+y*nx] == GOOD_PIX) {
1237 px[index] = x;
1238 py[index] = y;
1239 index++;
1240 }
1241 }
1242 }
1243 }
1244 } CATCH {
1245 eris_ifu_free_bivector(&usepix);
1246 }
1247
1248 return usepix;
1249}
1250
1260cpl_error_code eris_ifu_opt_extr_helper_fill_vertical(cpl_image *img, const eris_ifu_vector *vec)
1261{
1262 cpl_ensure_code(vec, CPL_ERROR_NULL_INPUT);
1263
1264 double *pimg = cpl_image_get_data_double(img);
1265 cpl_size nx = cpl_image_get_size_x(img),
1266 ny = cpl_image_get_size_y(img);
1267 double *pkvmask = cpl_vector_get_data(vec->data),
1268 *pkvdata = cpl_vector_get_data(vec->mask);
1269
1270 cpl_ensure_code(eris_ifu_vector_get_size(vec) == ny, CPL_ERROR_ILLEGAL_INPUT);
1271
1272 for (int y = 0; y < ny; y++) {
1273 for (int x = 0; x < nx; x++) {
1274 if (pkvmask[y] > 0.5) {
1275 pimg[x+y*nx] = pkvdata[y];
1276 } else {
1277 cpl_image_reject(img, x+1, y+1);
1278 }
1279 }
1280 }
1281
1282 return CPL_ERROR_NONE;
1283}
1284
1294void eris_ifu_opt_extr_helper_fill_horizontal(cpl_image *img, const cpl_image *slice, const cpl_bivector *usepix, int row, int power) {
1295 double *pimg = cpl_image_get_data_double(img);
1296 const double *pslice_d = NULL;
1297 const int *pslice_i = NULL;
1298 cpl_size nx = cpl_image_get_size_x(slice);
1299 cpl_type type = cpl_image_get_type(slice);
1300 const double *px = cpl_vector_get_data_const(cpl_bivector_get_x_const(usepix)),
1301 *py = cpl_vector_get_data_const(cpl_bivector_get_y_const(usepix));
1302 cpl_size n_usepix = cpl_bivector_get_size(usepix);
1303
1304 if (type == CPL_TYPE_DOUBLE) {
1305 pslice_d = cpl_image_get_data_double_const(slice);
1306 } else if (type == CPL_TYPE_INT) {
1307 pslice_i = cpl_image_get_data_int_const(slice);
1308 } else {
1309 return;
1310 }
1311
1312 if (type == CPL_TYPE_DOUBLE) {
1313 for (int i = 0; i < n_usepix; i++) {
1314 double val = pslice_d[(int)px[i]+(int)py[i]*nx];
1315 if (power) {
1316 pimg[i+row*n_usepix] = pow(val, 2);
1317 } else {
1318 pimg[i+row*n_usepix] = val;
1319 }
1320 }
1321 } else {
1322 for (int i = 0; i < n_usepix; i++) {
1323 int val = pslice_i[(int)px[i]+(int)py[i]*nx];
1324 if (power) {
1325 pimg[i+row*n_usepix] = pow(val, 2);
1326 } else {
1327 pimg[i+row*n_usepix] = val;
1328 }
1329 }
1330 }
1331}
1332
1339void eris_ifu_opt_extr_helper_set_positive(cpl_image *img) {
1340 double *pimg = cpl_image_get_data_double(img);
1341 cpl_size nx = cpl_image_get_size_x(img),
1342 ny = cpl_image_get_size_y(img);
1343 int n_neg = 0;
1344
1345 for (int x = 0; x < nx; x++) {
1346 for (int y = 0; y < ny; y++) {
1347 if ((pimg[x+y*nx] < 0.) || isnan(pimg[x+y*nx])) {
1348 pimg[x+y*nx] = 0.;
1349 n_neg++;
1350 }
1351 }
1352 }
1353 cpl_msg_debug(cpl_func, "optimal extraction: Resetting %d negative values in original PSF", n_neg);
1354}
1355
1362cpl_vector* eris_ifu_opt_extr_get_col(const cpl_image *img, int colnr)
1363{
1364 int nx = 0,
1365 ny = 0;
1366 double *pvec = NULL;
1367 const double *pimg = NULL;
1368 cpl_vector *vec = NULL;
1369
1370 cpl_ensure(img != NULL, CPL_ERROR_NULL_INPUT, NULL);
1371
1372 nx = cpl_image_get_size_x(img);
1373 ny = cpl_image_get_size_y(img);
1374
1375 cpl_ensure(colnr <= nx, CPL_ERROR_ILLEGAL_INPUT, NULL);
1376
1377 vec = cpl_vector_new(ny);
1378 pvec = cpl_vector_get_data(vec);
1379 pimg = cpl_image_get_data_double_const(img);
1380
1381 for (int y = 0; y < ny; y++) {
1382 pvec[y] = pimg[colnr+y*nx];
1383 }
1384
1385 return vec;
1386}
1387
1394cpl_vector* eris_ifu_opt_extr_get_row(const cpl_image *img, int rownr)
1395{
1396 int nx = 0,
1397 ny = 0;
1398 double *pvec = NULL;
1399 const double *pimg = NULL;
1400 cpl_vector *vec = NULL;
1401
1402 cpl_ensure(img != NULL, CPL_ERROR_NULL_INPUT, NULL);
1403
1404 nx = cpl_image_get_size_x(img);
1405 ny = cpl_image_get_size_y(img);
1406
1407 cpl_ensure(rownr <= ny, CPL_ERROR_ILLEGAL_INPUT, NULL);
1408
1409 vec = cpl_vector_new(nx);
1410 pvec = cpl_vector_get_data(vec);
1411 pimg = cpl_image_get_data_double_const(img);
1412
1413 for (int x = 0; x < nx; x++) {
1414 pvec[x] = pimg[x+rownr*nx];
1415 }
1416
1417 return vec;
1418}
1419
1426cpl_error_code eris_ifu_opt_extr_set_row(cpl_image *img,
1427 int rownr,
1428 const cpl_vector *vec)
1429{
1430 int nx = 0,
1431 ny = 0;
1432 const double *pvec = NULL;
1433 double *pimg = NULL;
1434
1435 cpl_ensure_code(img != NULL, CPL_ERROR_NULL_INPUT);
1436 cpl_ensure_code(vec != NULL, CPL_ERROR_NULL_INPUT);
1437
1438 nx = cpl_image_get_size_x(img);
1439 ny = cpl_image_get_size_y(img);
1440
1441 cpl_ensure_code(rownr <= ny, CPL_ERROR_ILLEGAL_INPUT);
1442 cpl_ensure_code(nx == cpl_vector_get_size(vec), CPL_ERROR_ILLEGAL_INPUT);
1443
1444 pvec = cpl_vector_get_data_const(vec);
1445 pimg = cpl_image_get_data_double(img);
1446
1447 for (int x = 0; x < nx; x++) {
1448 pimg[x+rownr*nx] = pvec[x];
1449 }
1450
1451 return cpl_error_get_code();
1452}
1453
1461cpl_error_code eris_ifu_opt_extr_set_col(cpl_image *img,
1462 int colnr,
1463 const cpl_vector *vec)
1464{
1465 int nx = 0,
1466 ny = 0;
1467 double *pimg = NULL;
1468 const double *pvec = NULL;
1469
1470 cpl_ensure_code(img != NULL, CPL_ERROR_NULL_INPUT);
1471 cpl_ensure_code(vec != NULL, CPL_ERROR_NULL_INPUT);
1472
1473 nx = cpl_image_get_size_x(img);
1474 ny = cpl_image_get_size_y(img);
1475
1476 cpl_ensure_code(colnr <= nx, CPL_ERROR_ILLEGAL_INPUT);
1477 cpl_ensure_code(ny == cpl_vector_get_size(vec), CPL_ERROR_ILLEGAL_INPUT);
1478
1479 pvec = cpl_vector_get_data_const(vec);
1480 pimg = cpl_image_get_data_double(img);
1481
1482 for (int y = 0; y < ny; y++) {
1483 pimg[colnr+y*nx] = pvec[y];
1484 }
1485
1486 return cpl_error_get_code();
1487}
1488
1489cpl_vector* eris_ifu_opt_extr_create_lambda(int size, double startLambda, double deltaLambda)
1490{
1491 cpl_vector *lambda = cpl_vector_new(size);
1492 double *pLambda = cpl_vector_get_data(lambda);
1493
1494 for (int i = 0; i < size; i++) {
1495 pLambda[i] = startLambda + (double)i * deltaLambda;
1496 }
1497 return lambda;
1498}
1499
1500cpl_error_code eris_ifu_opt_extr_vector_sqrt(cpl_vector *vec)
1501{
1502 double *pvec = cpl_vector_get_data(vec);
1503 cpl_ensure_code(vec != NULL, CPL_ERROR_NULL_INPUT);
1504
1505 for (int i = 0; i < cpl_vector_get_size(vec); i++) {
1506 pvec[i] = sqrt(pvec[i]);
1507 }
1508 return cpl_error_get_code();
1509}
1510
1511cpl_bivector* eris_ifu_opt_extr_doit(const hdrl_imagelist *cube,
1512 const cpl_imagelist *cube_dqi,
1513 const cpl_mask *mask,
1514 const eris_ifu_vector *spec,
1515 const eris_ifu_vector *spec_var,
1516 double startLambda,
1517 double deltaLambda,
1518 int productDepth,
1519 cpl_vector **error_out)
1520{
1521 cpl_bivector *spectrum = NULL,
1522 *usepix = NULL;
1523 cpl_size nz = 0;
1524 cpl_vector *vec = NULL,
1525 *rejectvec = NULL,
1526 *vec_err = NULL,
1527 *keep0 = NULL,
1528 *new_vec = NULL;
1529 eris_ifu_vector *speco = NULL,
1530 *spec_var_err = NULL,
1531 *sigo = NULL;
1532 cpl_image *spec1 = NULL,
1533 *psfvals = NULL,
1534 *varvals = NULL,
1535 *qualvals = NULL,
1536 *psfmod = NULL,
1537 *psfmodnew = NULL,
1538 *reject = NULL,
1539 *snr2 = NULL,
1540 *residual = NULL;
1541 int n_usepix = 0,
1542 jj = 0,
1543 sm = 49; // smoothing half-length (use, e.g. 15 for spectra with wiggles, up to 49 for ideal spectra).
1544 // Smoothing is done over a length of +/-sm pixels.
1545 double clipfrac = 0.9, // fraction to set for percentile clipping
1546 *pnew_vec = NULL,
1547 *pqualvals = NULL,
1548 *preject = NULL,
1549 *pkeep0 = NULL/*,
1550 *pspeco = NULL,
1551 *psigo = NULL*/;
1552 const double *pvec = NULL,
1553 *prejectvec = NULL;
1554
1555 cpl_ensure(cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
1556 cpl_ensure(cube_dqi != NULL, CPL_ERROR_NULL_INPUT, NULL);
1557 cpl_ensure(mask != NULL, CPL_ERROR_NULL_INPUT, NULL);
1558 cpl_ensure(spec != NULL, CPL_ERROR_NULL_INPUT, NULL);
1559 cpl_ensure(spec_var != NULL, CPL_ERROR_NULL_INPUT, NULL);
1560 cpl_ensure(error_out != NULL, CPL_ERROR_NULL_INPUT, NULL);
1561 cpl_ensure(hdrl_imagelist_get_size(cube) == cpl_imagelist_get_size(cube_dqi),
1562 CPL_ERROR_ILLEGAL_INPUT, NULL);
1563 cpl_ensure(hdrl_imagelist_get_size(cube) == eris_ifu_vector_get_size(spec),
1564 CPL_ERROR_ILLEGAL_INPUT, NULL);
1565 cpl_ensure(hdrl_imagelist_get_size(cube) == eris_ifu_vector_get_size(spec_var),
1566 CPL_ERROR_ILLEGAL_INPUT, NULL);
1567
1568 TRY {
1569 nz = hdrl_imagelist_get_size(cube);
1570
1571 spec_var_err = eris_ifu_vector_duplicate(spec_var);
1572 eris_ifu_vector_sqrt(spec_var_err);
1573 eris_ifu_vector_divide(spec_var_err, spec);
1575
1576 // get coordinates of used pixels in mask
1577 usepix = eris_ifu_opt_extr_helper_usepix(mask, &n_usepix);
1578
1579 // for convenience spectra of all selected pixels are stored in a 2D array
1580 spec1 = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE);
1581 psfvals = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // = (D - S)
1582 //psfmod = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // = P
1583 varvals = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // = V
1584 qualvals = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // for additional clipping regarding DQI
1585 pqualvals = cpl_image_get_data_double(qualvals);
1587
1588 // begin optimal extraction
1589 // 1st time through bigloop use initial spectrum
1590 // 2nd time through bigloop use previous output spectrum
1591 speco = eris_ifu_vector_duplicate(spec); // working spectrum data
1592// pspeco = cpl_vector_get_data(speco);
1593 sigo = eris_ifu_vector_new(nz); // working spectrum error
1594// psigo = cpl_vector_get_data(sigo);
1596
1597 for (int bigloop = 0; bigloop <= 1; bigloop++) {
1598 // spec0 is vector
1599 // spec1 is image (duplicates of speco)
1601 eris_ifu_opt_extr_helper_fill_vertical(spec1, speco));
1602
1603 // fill data/error/dqi values of used (unmasked) pixels to 2D-array
1604 // for varvals store the squared values
1605 for (int z = 0; z < nz; z++) {
1606 const hdrl_image *hdrl_img = hdrl_imagelist_get_const(cube, z);
1607 const cpl_image *slice_d = hdrl_image_get_image_const(hdrl_img);
1608 const cpl_image *slice_e = hdrl_image_get_error_const(hdrl_img);
1609 const cpl_image *slice_q = cpl_imagelist_get_const(cube_dqi, z);
1610
1611 eris_ifu_opt_extr_helper_fill_horizontal(psfvals, slice_d, usepix, z, FALSE);
1612 eris_ifu_opt_extr_helper_fill_horizontal(varvals, slice_e, usepix, z, TRUE);
1613 eris_ifu_opt_extr_helper_fill_horizontal(qualvals, slice_q, usepix, z, FALSE);
1614 }
1615
1616 eris_ifu_opt_extr_helper_set_positive(psfvals);
1617
1618 if (productDepth >= PD_DEBUG) {
1619 eris_ifu_save_image_dbg(psfvals, "ers_psfvals.fits", CPL_IO_CREATE, NULL);
1620 eris_ifu_save_image_dbg(varvals, "ers_varvals.fits", CPL_IO_CREATE, NULL);
1621 eris_ifu_save_image_dbg(qualvals, "ers_qualvals.fits", CPL_IO_CREATE, NULL);
1622 }
1623
1624 // replace fractions with weighted polynomial fits: the PSF model
1625 // Horne86, page 613 bottom right & Fig 1
1626 // two iterations; first with all pixels, second with clipped (from reject)
1627 reject = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // all zeros initially
1628 preject = cpl_image_get_data_double(reject);
1630
1631 new_vec = cpl_vector_new(nz);
1632 pnew_vec = cpl_vector_get_data(new_vec);
1633
1634 for (int iloop = 0; iloop <= 1; iloop++) {
1635 if (psfmod != NULL) {
1636 eris_ifu_free_image(&psfmod);
1637 }
1638 psfmod = cpl_image_divide_create(psfvals, spec1); // Horne86 eq 14, P = (D-S)/f
1639 eris_ifu_opt_extr_helper_set_positive(psfmod);
1641
1642 if (productDepth >= PD_DEBUG) {
1643 eris_ifu_save_image_dbg(psfmod, "ers_psfmod.fits", CPL_IO_CREATE, NULL);
1644 }
1645
1646 // slow loop
1647 for (int n = 0; n < n_usepix; n++) {
1648 vec = eris_ifu_opt_extr_get_col(psfmod, n);
1649 pvec = cpl_vector_get_data_const(vec);
1651
1653 vec_err = eris_ifu_vector_get_data(spec_var_err));
1655 cpl_vector_multiply(vec_err, vec));
1656
1657 rejectvec = eris_ifu_opt_extr_get_col(reject, n);
1658 prejectvec = cpl_vector_get_data_const(rejectvec);
1660
1661 // vector 'keep0' with indices on which values to keep
1662 keep0 = cpl_vector_new(nz);
1663 cpl_vector_fill(keep0, -1.0);
1664 pkeep0 = cpl_vector_get_data(keep0);
1665 jj = 0;
1666
1667 for (cpl_size iz = 0; iz < nz; iz++) {
1668
1669 if ((fabs(prejectvec[iz]) < 1e-5) &&
1670 (pvec[iz] > 0) &&
1671 !eris_ifu_is_nan_or_inf(pvec[iz]))
1672 {
1673
1674 pkeep0[jj++]= iz;
1675
1676 }
1677 } // end: for iz
1678 cpl_vector_delete(rejectvec);
1680 eris_ifu_cut_endings(&keep0, NULL, NULL, TRUE));
1681 if (keep0 != NULL) {
1682 pkeep0 = cpl_vector_get_data(keep0);
1684
1685 if ((productDepth >= PD_DEBUG) && (n==92)) {
1686 eris_ifu_save_vector_dbg(keep0, "ers_keep0.fits", CPL_IO_CREATE, NULL);
1687 }
1688
1689 // replace polynomial fitting by weighted mean smoothing over +/-sm pixels, after rejection
1690 for (int z = 0; z < nz; z++) {
1691 // reject keep0
1692 int s = cpl_vector_get_size(keep0);
1693 cpl_vector* ttt = cpl_vector_new(s);
1694 double *pttt = cpl_vector_get_data(ttt);
1695 cpl_vector_fill(ttt, -1.0);
1696 jj = 0;
1697 for (int iz = 0; iz < s; iz++) {
1698 int v = (int)(pkeep0[iz] +.5);
1699 if ((v > z-sm) && (v < z+sm)) {
1700 pttt[jj++] = iz;
1701 }
1702 }
1703 if (productDepth >= PD_DEBUG) {
1704 eris_ifu_save_vector_dbg(ttt, "ers_ttt.fits", CPL_IO_CREATE, NULL);
1705 }
1707 eris_ifu_cut_endings(&ttt, NULL, NULL, TRUE));
1708 if (ttt != NULL) {
1709 cpl_vector *iiuse = eris_ifu_idl_values_at_indices(keep0, ttt),
1710 *els = eris_ifu_idl_values_at_indices(vec, iiuse),
1711 *els_err = eris_ifu_idl_values_at_indices(vec_err, iiuse),
1712 *ones = cpl_vector_new(cpl_vector_get_size(els));
1714
1715 if ((productDepth >= PD_DEBUG) && (n==92) && (z == 1000)) {
1716 eris_ifu_save_vector_dbg(iiuse, "ers_iiuse.fits", CPL_IO_CREATE, NULL);
1717 eris_ifu_save_vector_dbg(els, "ers_els.fits", CPL_IO_CREATE, NULL);
1718 eris_ifu_save_vector_dbg(els_err, "ers_elserr.fits", CPL_IO_CREATE, NULL);
1719 }
1720
1721 cpl_vector_fill(ones, 1.0);
1722 cpl_vector_divide(els, els_err);
1723 cpl_vector_divide(ones, els_err);
1724 pnew_vec[z] = cpl_vector_get_sum(els) / cpl_vector_get_sum(ones);
1726
1727 eris_ifu_free_vector(&iiuse);
1728 eris_ifu_free_vector(&ones);
1730 eris_ifu_free_vector(&els_err);
1731 } else {
1732 pnew_vec[z] = NAN;
1733 }
1734
1736 } // end: for z
1738
1740 eris_ifu_opt_extr_set_col(psfmod, n, new_vec));
1741
1742 if ((productDepth >= PD_DEBUG) && (n==92)) {
1743 eris_ifu_save_vector_dbg(new_vec, "ers_newvec.fits", CPL_IO_CREATE, NULL);
1744 }
1745 }
1747 eris_ifu_free_vector(&vec_err);
1748 eris_ifu_free_vector(&keep0);
1749 } // end: for n
1751
1752 if (productDepth >= PD_DEBUG) {
1753 if (iloop==0) {
1754 eris_ifu_save_image_dbg(psfmod, "ers_psfmod_0.fits", CPL_IO_CREATE, NULL);
1755 } else {
1756 eris_ifu_save_image_dbg(psfmod, "ers_psfmod_1.fits", CPL_IO_CREATE, NULL);
1757 }
1758 }
1759
1760 // second iteration of polynomial fitting uses Horne86, page 614, top left: ((D-S) - fP)^2/V
1761 // also use qualitfy flag to reject pixels & define clipping value from data, slice by slice
1762 // snr2 = (psfvals-psfmod*spec1)^2/varvals
1763 cpl_image *psfmod_tmp = cpl_image_multiply_create(psfmod, spec1);
1764 snr2 = cpl_image_subtract_create(psfvals, psfmod_tmp);
1765 cpl_image_power(snr2, 2);
1766 cpl_image_divide(snr2, varvals);
1767 eris_ifu_free_image(&psfmod_tmp);
1769 if (productDepth >= PD_DEBUG) {
1770 if (iloop==0) {
1771 eris_ifu_save_image_dbg(snr2, "ers_snr2_0.fits", CPL_IO_CREATE, NULL);
1772 eris_ifu_save_image_dbg(reject, "ers_reject0_0.fits", CPL_IO_CREATE, NULL);
1773 } else {
1774 eris_ifu_save_image_dbg(snr2, "ers_snr2_1.fits", CPL_IO_CREATE, NULL);
1775 eris_ifu_save_image_dbg(reject, "ers_reject0_1.fits", CPL_IO_CREATE, NULL);
1776 }
1777 }
1778 for (int iz = 0; iz < nz; iz++) {
1779 vec = eris_ifu_opt_extr_get_row(snr2, iz);
1780 int n_fin = eris_ifu_opt_extr_get_not_finite(vec);
1781 if (n_fin > n_usepix*0.25) {
1782 //cpl_vector_abs
1783 cpl_vector_power(vec, 2);
1784 eris_ifu_cpl_vector_sqrt(vec);
1785
1786 cpl_vector_sort(vec, CPL_SORT_ASCENDING);
1787 double clip = cpl_vector_get(vec, n_usepix*clipfrac)*5;
1788 cpl_vector *tmp = eris_ifu_idl_where(vec, clip, gt);
1789 if ((tmp != NULL) && (cpl_vector_get_size(tmp) > 0)) {
1790 for (int ii = 0; ii < cpl_vector_get_size(tmp); ii++) {
1791 preject[(int)(cpl_vector_get(tmp, ii)+.5)+iz*n_usepix] = 1;
1792 }
1793 }
1795 } else {
1796 for (int ii = 0; ii < n_usepix; ii++) {
1797 preject[ii+iz*n_usepix] = 1;
1798 }
1799 }
1801 } // end: for iz
1803 if (productDepth >= PD_DEBUG) {
1804 if (iloop==0) {
1805 eris_ifu_save_image_dbg(reject, "ers_reject1_0.fits", CPL_IO_CREATE, NULL);
1806 } else {
1807 eris_ifu_save_image_dbg(reject, "ers_reject1_1.fits", CPL_IO_CREATE, NULL);
1808 }
1809 }
1810 for (int ii = 0; ii < n_usepix * nz; ii++) {
1811 if (pqualvals[ii] > 0) {
1812 preject[ii] = 1;
1813 }
1814 }
1816 if (productDepth >= PD_DEBUG) {
1817 if (iloop==0) {
1818 eris_ifu_save_image_dbg(reject, "ers_reject2_0.fits", CPL_IO_CREATE, NULL);
1819 } else {
1820 eris_ifu_save_image_dbg(reject, "ers_reject2_1.fits", CPL_IO_CREATE, NULL);
1821 }
1822 }
1823 eris_ifu_free_image(&snr2);
1824 } // end: for iloop
1825 eris_ifu_free_vector(&new_vec);
1826
1827 if (productDepth >= PD_DEBUG) {
1828 eris_ifu_save_image_dbg(reject, "ers_reject3.fits", CPL_IO_CREATE, NULL);
1829 }
1830 eris_ifu_free_image(&reject);
1831
1832 //go through PSF model plane by plane
1833 // reject low quality & noisy pixels * re-extract spectrum
1834 // Horne86 page 614, left, & Table 1 step 5c, 7, 8
1835 // steps 6 is skipped;
1836 // step 7 includes the quality flag
1837
1838 eris_ifu_free_image(&psfmodnew);
1840 psfmodnew = cpl_image_duplicate(psfmod));
1841
1842 //residual = (psfvals-psfmod*spec1)^2/varvals
1843 // for step 7; page 614 top right
1844 eris_ifu_free_image(&residual);
1845 residual = cpl_image_multiply_create(psfmod, spec1);
1846 cpl_image_subtract(residual, psfvals);
1847 cpl_image_multiply_scalar(residual, -1.);
1848 cpl_image_power(residual, 2);
1849 cpl_image_divide(residual, varvals);
1850
1851 if (productDepth >= PD_DEBUG) {
1852 eris_ifu_save_image_dbg(psfvals, "ers_psfvalsXXX.fits", CPL_IO_CREATE, NULL);
1853 eris_ifu_save_image_dbg(psfmod, "ers_psfmodXXX.fits", CPL_IO_CREATE, NULL);
1854 eris_ifu_save_image_dbg(spec1, "ers_spec1XXX.fits", CPL_IO_CREATE, NULL);
1855 eris_ifu_save_image_dbg(varvals, "ers_varvalsXXX.fits", CPL_IO_CREATE, NULL);
1856 eris_ifu_save_image_dbg(residual, "ers_residual.fits", CPL_IO_CREATE, NULL);
1857 }
1858
1859 // need to set clip value slice by slice
1860 // fit linear function to first 90% of sorted residual values and clip
1861 for (int iz = 0; iz < nz; iz++) {
1862 cpl_vector *resvec0 = eris_ifu_opt_extr_get_row(residual, iz);
1863 double *presvec0 = cpl_vector_get_data(resvec0);
1864
1865 if (productDepth >= PD_DEBUG) {
1866 eris_ifu_save_vector_dbg(resvec0, "ers_resvec0.fits", CPL_IO_CREATE, NULL);
1867 }
1868
1869 // vector 'keep0' with indices on which values to keep
1870 keep0 = cpl_vector_new(n_usepix);
1871 cpl_vector_fill(keep0, -1.0);
1872 pkeep0 = cpl_vector_get_data(keep0);
1873 jj = 0;
1874 for (int ii = 0; ii < n_usepix; ii++) {
1875 if (!eris_ifu_is_nan_or_inf(presvec0[ii]) &&
1876 presvec0[ii] > 0.)
1877 {
1878 pkeep0[jj++]= ii;
1879 }
1880 }
1882 eris_ifu_cut_endings(&keep0, NULL, NULL, TRUE));
1883
1884 if (productDepth >= PD_DEBUG) {
1885 eris_ifu_save_vector_dbg(keep0, "ers_keep.fits", CPL_IO_CREATE, NULL);
1886 }
1887
1888 cpl_vector *p = eris_ifu_opt_extr_get_row(psfmod, iz);
1889 double *pp = cpl_vector_get_data(p);
1890
1891 if ((keep0 != NULL) && (cpl_vector_get_size(keep0) > n_usepix*0.25)) {
1892 int nkeep = cpl_vector_get_size(keep0);
1893 cpl_vector *resvec = eris_ifu_idl_values_at_indices(resvec0, keep0),
1894 *resvecs = cpl_vector_duplicate(resvec);
1895 cpl_vector_sort(resvecs, CPL_SORT_ASCENDING);
1896
1897 if ((productDepth >= PD_DEBUG) && (iz == 1000)){
1898 eris_ifu_save_vector_dbg(resvecs, "ers_resvecs.fits", CPL_IO_CREATE, NULL);
1899 }
1900
1901 double clip = cpl_vector_get(resvecs, (int)(nkeep*clipfrac+.5)-1) * 5.;
1902 if (clip < 25.) {
1903 clip = 25.;
1904 }
1905
1906 cpl_vector *q = eris_ifu_opt_extr_get_row(qualvals, iz);
1907 double *pq = cpl_vector_get_data(q);
1908 eris_ifu_free_vector(&keep0);
1909 keep0 = cpl_vector_new(n_usepix);
1910 cpl_vector_fill(keep0, -1.0);
1911 pkeep0 = cpl_vector_get_data(keep0);
1912 jj = 0;
1913 for (int ii = 0; ii < n_usepix; ii++) {
1914 if ((presvec0[ii] > clip) || (pq[ii] == 1)) {
1915 pkeep0[jj++]= ii;
1916 }
1917 }
1919 eris_ifu_cut_endings(&keep0, NULL, NULL, TRUE));
1920 if (keep0 != NULL) {
1921 pkeep0 = cpl_vector_get_data(keep0);
1922 for (int ii = 0; ii < cpl_vector_get_size(keep0); ii++) {
1923 pp[(int)(pkeep0[ii])] = 0.;
1924 }
1925 }
1926
1927 double sum = cpl_vector_get_sum(p);
1928 for (int ii = 0; ii < cpl_vector_get_size(p); ii++) {
1929 pp[ii] /= sum;
1930 }
1931
1933 eris_ifu_free_vector(&resvecs);
1934 eris_ifu_free_vector(&resvec);
1935 } else {
1937 cpl_vector_fill(p, 0.));
1938 }
1939
1941 eris_ifu_opt_extr_set_row(psfmodnew, iz, p));
1942
1943 cpl_vector *vals = eris_ifu_opt_extr_get_row(psfvals, iz),
1944 *var = eris_ifu_opt_extr_get_row(varvals, iz);
1946 eris_ifu_opt_extr_convert_0_to_NaN_vec(var);
1947
1948 // pspeco[iz] = total(p*vals/var)/total(p^2./var)
1949 cpl_vector *tt = cpl_vector_duplicate(p);
1950 cpl_vector_multiply(tt, vals);
1951 cpl_vector_divide(tt, var);
1952 cpl_vector_power(p, 2.0);
1953 cpl_vector_divide(p, var);
1954 double sum_data = cpl_vector_get_sum(tt),
1955 sum_weight = cpl_vector_get_sum(p);
1957 eris_ifu_vector_set(speco, iz, sum_data / sum_weight));
1958
1959 //BRK_IF_ERROR(
1960 // eris_ifu_vector_set(sigo, iz, sqrt(1./total(p^2/var)));
1962 eris_ifu_vector_set(sigo, iz, sqrt(1./sum_weight)));
1963
1965 eris_ifu_free_vector(&vals);
1968 eris_ifu_free_vector(&keep0);
1969 eris_ifu_free_vector(&resvec0);
1971 } // end if: iz
1973 } // endfor: bigloop
1975
1976 // median((speco/sigo)/(spec0/sig0))
1977 eris_ifu_vector *tt = eris_ifu_vector_duplicate(speco);
1978 eris_ifu_vector_divide(tt, sigo);
1979 eris_ifu_vector_power(spec_var_err, -1.);
1980 eris_ifu_vector_divide(tt, spec_var_err);
1982
1983 cpl_msg_info(cpl_func, "typical S/N has increased by %g", eris_ifu_vector_get_median(tt, ERIS_IFU_ARITHMETIC));
1985
1986 cpl_vector *lambda = eris_ifu_opt_extr_create_lambda(nz, startLambda, deltaLambda);
1987 cpl_vector *speco2 = eris_ifu_vector_get_data(speco);
1989 spectrum = cpl_bivector_wrap_vectors(lambda, speco2));
1990
1991 cpl_vector *sigo2 = eris_ifu_vector_get_data(sigo);
1992 *error_out = sigo2;
1993
1994 // return sigo as vector (pow? sqrt?)
1995 // return total_flux??
1996 } CATCH {
1997 CATCH_MSG();
1998 eris_ifu_free_bivector(&spectrum);
1999 eris_ifu_free_vector(error_out);
2000 }
2001
2004 eris_ifu_free_ifu_vector(&spec_var_err);
2005 eris_ifu_free_bivector(&usepix);
2006 eris_ifu_free_image(&spec1);
2007 eris_ifu_free_image(&psfvals);
2008 eris_ifu_free_image(&psfmod);
2009 eris_ifu_free_image(&psfmodnew);
2010 eris_ifu_free_image(&varvals);
2011 eris_ifu_free_image(&qualvals);
2012 eris_ifu_free_image(&reject);
2013 eris_ifu_free_image(&residual);
2014
2015 return spectrum;
2016}
2017
2023int eris_ifu_opt_extr_get_not_finite(cpl_vector *vec) {
2024 int n_fin = 0;
2025 double *pvec = NULL;
2026
2027 cpl_ensure_code(vec != NULL, CPL_ERROR_NULL_INPUT);
2028
2029 pvec = cpl_vector_get_data(vec);
2030
2031 for (int i = 0; i < cpl_vector_get_size(vec); i++) {
2032 if (!eris_ifu_is_nan_or_inf(pvec[i])) {
2033 n_fin++;
2034 }
2035 }
2036
2037 return n_fin;
2038}
2039
2044void eris_ifu_opt_extr_convert_0_to_NaN_vec(cpl_vector *vec)
2045{
2046 cpl_size x = 0;
2047 double *pvec = NULL;
2048
2049 if (vec != NULL) {
2050 pvec = cpl_vector_get_data(vec);
2051
2052 x = cpl_vector_get_size(vec);
2053
2054 for (int i = 0 ; i < x; i++) {
2055 if (fabs(pvec[i]) < DBL_ZERO_TOLERANCE) {
2056 pvec[i] = NAN;
2057 }
2058 }
2059 }
2060}
2061
2062cpl_image* eris_ifu_opt_extr_estimate_radius_helper(const cpl_image *img,
2063 cpl_size center_x, cpl_size center_y,
2064 double radius,
2065 cpl_size *llx, cpl_size *lly,
2066 cpl_size *urx, cpl_size *ury)
2067{
2068 double half_maxval = 0.,
2069 *pmask = NULL;
2070 const double *pimg = NULL;
2071 cpl_image *mask = NULL;
2072 cpl_size nx = 0,
2073 ny = 0;
2074
2075 cpl_ensure(img != NULL, CPL_ERROR_NULL_INPUT, NULL);
2076
2077 TRY {
2078 pimg = cpl_image_get_data_double_const(img);
2079 nx = cpl_image_get_size_x(img);
2080 ny = cpl_image_get_size_y(img);
2081 half_maxval = pimg[center_x+nx*center_y] / 2;
2082
2083 mask = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
2084 pmask = cpl_image_get_data_double(mask);
2085
2086 *llx = center_x - radius;
2087 *lly = center_y - radius;
2088 *urx = center_x + radius;
2089 *ury = center_y + radius;
2090 if (*llx < 0) {
2091 *llx = 0;
2092 }
2093 if (*lly < 0) {
2094 *lly = 0;
2095 }
2096 if (*urx >= nx) {
2097 *urx = nx-1;
2098 }
2099 if (*ury >= ny) {
2100 *ury = ny-1;
2101 }
2102
2103 for (cpl_size x = *llx; x < *urx; x++) {
2104 for (cpl_size y = *lly; y < *ury; y++) {
2105 if (pimg[x+nx*y] >= half_maxval) {
2106 pmask[x+nx*y] = 1;
2107 }
2108 }
2109 }
2110
2111 } CATCH {
2112 CATCH_MSG();
2113 eris_ifu_free_image(&mask);
2114 }
2115
2116 return mask;
2117}
2118
2119double eris_ifu_opt_extr_estimate_radius(const cpl_image *img,
2120 cpl_size center_x, cpl_size center_y,
2121 double initial_radius,
2122 int productDepth)
2123{
2124 double radius = 0.,
2125 inc_radius = 2.,
2126 area_rectangle = 1.,
2127 area_mask = 4.;
2128 cpl_image *mask = NULL;
2129 cpl_size llx = 0,
2130 lly = 0,
2131 urx = 0,
2132 ury = 0,
2133 nx = 0,
2134 ny = 0;
2135
2136 cpl_ensure(img != NULL, CPL_ERROR_NULL_INPUT, -1.);
2137
2138 TRY {
2139 nx = cpl_image_get_size_x(img);
2140 ny = cpl_image_get_size_y(img);
2141 // define a max. radius: half size of image
2142 double max_radius = nx/2;
2143 if (ny/2 < max_radius) {
2144 max_radius = ny/2;
2145 }
2146 radius = initial_radius - inc_radius;
2147 // calculate ratio of good pixels, if > pi/4 make radius bigger
2148
2149 while ((area_mask / area_rectangle >= CPL_MATH_PI_4) && (radius < max_radius)) {
2150 radius += inc_radius;
2151 eris_ifu_free_image(&mask);
2152 mask = eris_ifu_opt_extr_estimate_radius_helper(img,
2153 center_x, center_y,
2154 radius,
2155 &llx, &lly, &urx, &ury);
2156 area_rectangle = (urx-llx)*(ury-lly);
2157 area_mask = cpl_image_get_flux(mask);
2158 if (productDepth >= PD_DEBUG) {
2159 eris_ifu_save_image_dbg(mask, "eris_dbg_mask.fits", CPL_IO_CREATE, NULL);
2160 }
2161 cpl_msg_debug(cpl_func, " intermediate mask center at (%d/%d), radius: %g, area mask: %g, area rect: %g)",
2162 (int)center_x, (int)center_y, radius, area_mask, area_rectangle);
2163
2164 }
2165 if (productDepth >= PD_DEBUG) {
2166 eris_ifu_save_image_dbg(mask, "eris_dbg_mask.fits", CPL_IO_CREATE, NULL);
2167 }
2168 cpl_msg_debug(cpl_func, "Final mask center at (%d/%d), radius: %g, area mask: %g, area rect: %g)",
2169 (int)center_x, (int)center_y, radius, area_mask, area_rectangle);
2170 } CATCH {
2171 CATCH_MSG();
2172 radius = 0.;
2173 }
2174
2175 eris_ifu_free_image(&mask);
2176
2177 return radius;
2178}
2179
2181// * @brief eris_ifu_opt_extr_median_without_NaN
2182// * @param vec
2183// */
2184//double eris_ifu_opt_extr_median_without_NaN(cpl_vector *vec)
2185//{
2186// cpl_size x = 0;
2187// double *pvec = NULL,
2188// *ptmp = NULL,
2189// median = -1.;
2190// int cnt = 0;
2191// cpl_vector *tmp = NULL;
2192//
2193// if (vec != NULL) {
2194// pvec = cpl_vector_get_data(vec);
2195//
2196// x = cpl_vector_get_size(vec);
2197// for (int i = 0 ; i < x; i++) {
2198// if (eris_ifu_is_nan_or_inf(pvec[i])) {
2199// cnt++;
2200// }
2201// }
2202//
2203// if ((x-cnt) > 0) {
2204// tmp = cpl_vector_new(x-cnt);
2205// ptmp = cpl_vector_get_data(tmp);
2206// cnt = 0;
2207// for (int i = 0 ; i < x; i++) {
2208// if (!eris_ifu_is_nan_or_inf(pvec[i])) {
2209// ptmp[cnt++] = pvec[i];
2210// }
2211// }
2212//
2213// median = cpl_vector_get_median(tmp);
2214// eris_ifu_free_vector(&tmp);
2215// }
2216// }
2217// return median;
2218//}
2219
2228cpl_error_code eris_ifu_cpl_vector_sqrt(cpl_vector *vec)
2229{
2230 cpl_size n = 0;
2231 double *pvec = NULL;
2232 cpl_error_code err = CPL_ERROR_NONE;
2233
2234 cpl_ensure_code(vec, CPL_ERROR_NULL_INPUT);
2235
2236 TRY
2237 {
2238 n = cpl_vector_get_size(vec);
2240
2242 pvec = cpl_vector_get_data(vec));
2243
2244 /* Compute the sqrt */
2245 for (int i = 0; i < n; i++) {
2246 /* pvec[i] can be NaN, since sqrt() handles NaN correctly:
2247 sqrt(NaN) = NaN */
2248 if (pvec[i] >= 0) {
2249 pvec[i] = sqrt(pvec[i]);
2250 } else {
2251 pvec[i] = NAN;
2252 }
2253 }
2254 } CATCH {
2255 err = cpl_error_get_code();
2256 }
2257
2258 return err;
2259}
#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.