ERIS Pipeline Reference Manual 1.8.15
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
65/*---------------------------------------------------------------------------*/
79/*---------------------------------------------------------------------------*/
80hdrl_image* eris_ifu_extract_spec_collapse(hdrl_imagelist *cube,
81 cpl_image **contribute)
82{
83 hdrl_image *hImage = NULL;
84
85 cpl_ensure(cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
86 cpl_ensure(contribute != NULL, CPL_ERROR_NULL_INPUT, NULL);
87
88 TRY{
90 hdrl_imagelist_collapse(cube, HDRL_COLLAPSE_MEDIAN,
91 &hImage, contribute));
92 } CATCH
93 {
95 eris_ifu_free_image(contribute);
96 }
97
98 return hImage;
99}
100
101/*---------------------------------------------------------------------------*/
111/*---------------------------------------------------------------------------*/
112void
113eris_ifu_extract_free_esSofStruct(struct esSofStruct* self){
114 if (self != NULL) {
115 eris_ifu_free_image(&self->mask);
116 eris_ifu_free_propertylist(&self->header);
117 eris_ifu_free_imagelist(&self->qualImagelist);
118 eris_ifu_free_hdrl_imagelist(&self->cube);
119 }
120
121}
122
123/*---------------------------------------------------------------------------*/
143/*---------------------------------------------------------------------------*/
144cpl_image * eris_ifu_extract_spec_create_fit_mask(const hdrl_image* img)
145{
146 cpl_image *mask = NULL;
147 const cpl_image *image = NULL;
148 cpl_array *gauss_params = NULL;
149 cpl_size nx, ny;
150 cpl_size xposcen, yposcen;
151 cpl_size xwinsize, ywinsize;
152
153 cpl_ensure(img, CPL_ERROR_NULL_INPUT, NULL);
154
155 TRY{
157
158 nx = cpl_image_get_size_x(image);
159 ny = cpl_image_get_size_y(image);
160 xposcen = nx / 2;
161 yposcen = ny / 2;
162 xwinsize = nx;
163 ywinsize = ny;
164
165 BRK_IF_NULL(gauss_params = cpl_array_new(7, CPL_TYPE_DOUBLE));
166 BRK_IF_ERROR(cpl_fit_image_gaussian(image, NULL, xposcen, yposcen,
167 xwinsize, ywinsize, gauss_params,
168 NULL, NULL, NULL,
169 NULL, NULL, NULL,
170 NULL, NULL, NULL));
171
172 mask = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
173
174 for (cpl_size iy=1; iy <= ny ; iy++) {
175 for (cpl_size ix=1; ix <= nx ; ix++) {
176 cpl_image_set(mask, ix, iy,
177 cpl_gaussian_eval_2d(gauss_params, (double) ix, (double) iy));
178 }
179 }
181
182
183 /* Normalise mask */
184 cpl_image_subtract_scalar(mask, cpl_image_get_min(mask));
185 cpl_image_divide_scalar(mask, cpl_image_get_max(mask));
186 cpl_array_delete(gauss_params);
188
189 } CATCH
190 {
191 mask = NULL;
192 }
193 return mask;
194}
195
196/*---------------------------------------------------------------------------*/
213/*---------------------------------------------------------------------------*/
214cpl_image * eris_ifu_extract_spec_create_circle_mask(
215 cpl_size center_x,
216 cpl_size center_y,
217 double radius,
218 cpl_size nx,
219 cpl_size ny)
220{
221 cpl_image *mask = NULL;
222 double cen_x, cen_y, x_lo, y_lo, x_hi, y_hi, r;
223 double *pmask;
224
225 cpl_ensure(center_x > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
226 cpl_ensure(center_y > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
227 cpl_ensure(radius > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
228 cpl_ensure(nx > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
229 cpl_ensure(ny > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
230
231 TRY{
232 mask = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
233 pmask = cpl_image_get_data_double(mask);
234
235 cen_x = (double) center_x - 1.0;
236 cen_y = (double) center_y - 1.0;
237 // draw circle
238 x_lo = floor(cen_x - radius);
239 if (x_lo < 0) x_lo = 0;
240 y_lo = floor(cen_y - radius);
241 if (y_lo < 0) y_lo = 0;
242 x_hi = ceil(cen_x + radius);
243 if (x_hi > nx) x_hi = (int) nx;
244 y_hi = ceil(cen_y + radius);
245 if (y_hi > ny) y_hi = (int) ny;
246 for (int x = (int) x_lo; x < x_hi; x++) {
247 for (int y = (int) y_lo; y < y_hi; y++) {
248 r = sqrt(pow(x - cen_x,2) + pow(y - cen_y,2));
249 if (r <= radius) pmask[x + y * nx] = 1.0;
250 }
251 }
252
253 } CATCH
254 {
255 mask = NULL;
256 }
257 return mask;
258}
259
260/*---------------------------------------------------------------------------*/
282/*---------------------------------------------------------------------------*/
283cpl_image * eris_ifu_extract_spec_create_mask(
284 struct esParamStruct params,
285 struct esSofStruct sof,
286 const hdrl_image *collapsedCube,
287 int productDepth)
288{
289 cpl_image *mask = NULL;
290 cpl_size nx;
291 cpl_size ny;
292 cpl_size center_x;
293 cpl_size center_y;
294 const cpl_image *img;
295
296 TRY{
297 switch (params.mask_method) {
298 case MASK:
299 mask = sof.mask;
300 break;
301 case MAX:
302 cpl_image_get_maxpos(
303 hdrl_image_get_image_const(collapsedCube), &center_x, &center_y);
306 mask = eris_ifu_extract_spec_create_circle_mask(center_x, center_y,
307 params.radius,
308 sof.nx, sof.ny));
309 break;
310 case POSITION:
312 mask = eris_ifu_extract_spec_create_circle_mask(params.center_x,
313 params.center_y,
314 params.radius,
315 sof.nx, sof.ny));
316 break;
317 case OPTIMAL:
318 // get maxpos
319 img = hdrl_image_get_image_const(collapsedCube);
320 cpl_image_get_maxpos(img, &center_x, &center_y);
322
323 // estimate radius by FWHM
324 double radius = eris_ifu_opt_extr_estimate_radius(img,
325 center_x, center_y,
326 params.radius,
327 productDepth);
328
329 // create mask
331 mask = eris_ifu_extract_spec_create_circle_mask(center_x, center_y,
332 radius,
333 sof.nx, sof.ny));
334 break;
335 case FIT:
337 mask = eris_ifu_extract_spec_create_fit_mask(collapsedCube));
338 break;
339 default:
340 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
341 "Internal error: unknown mask method %d",
342 params.mask_method);
343 }
344
345 nx = cpl_image_get_size_x(mask);
346 ny = cpl_image_get_size_y(mask);
347 if (nx != sof.nx || ny != sof.ny) {
348 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
349 "Dimensions of mask don't match with the cube");
350 }
351 } CATCH
352 {
353 mask = NULL;
354 }
355 return mask;
356}
357
358/*---------------------------------------------------------------------------*/
387/*---------------------------------------------------------------------------*/
388cpl_bivector * eris_ifu_extract_spectrum(hdrl_imagelist *cube,
389 cpl_image *mask,
390 double startLambda,
391 double deltaLambda,
392 cpl_vector **error,
393 cpl_vector **totalFlux,
394 cpl_vector **quality)
395{
396 cpl_bivector *spectrum = NULL;
397 cpl_imagelist *data_in = NULL;
398 cpl_imagelist *error_in = NULL;
399 const cpl_image *tmpDataImg = NULL;
400 const cpl_image *tmpErrorImg = NULL;
401 const cpl_mask *bpm = NULL;
402 const double *pTmpData = NULL;
403 const double *pTmpError = NULL;
404 const cpl_binary *pBpm = NULL;
405 const double *pMask = NULL;
406 cpl_size nx, ny, nz;
407 cpl_size fill_nz;
408 cpl_vector *lambda = NULL;
409 cpl_vector *spec_data = NULL;
410 cpl_vector *spec_error = NULL;
411 cpl_vector *spec_totFlux = NULL;
412 cpl_vector *spec_qual = NULL;
413 double *pLambda = NULL;
414 double *pData = NULL;
415 double *pError = NULL;
416 double *pTotFlux = NULL;
417 double *pqual = NULL;
418 double sumData;
419 double sumVariance;
420 double weights;
421 bool valid;
422
423
424 cpl_ensure(cube != NULL,CPL_ERROR_NULL_INPUT, NULL);
425 cpl_ensure(mask != NULL,CPL_ERROR_NULL_INPUT, NULL);
426 cpl_ensure(error != NULL,CPL_ERROR_NULL_INPUT, NULL);
427 cpl_ensure(totalFlux != NULL,CPL_ERROR_NULL_INPUT, NULL);
428
429 TRY{
430 nx = hdrl_imagelist_get_size_x(cube);
431 ny = hdrl_imagelist_get_size_y(cube);
432 nz = hdrl_imagelist_get_size(cube);
433
434 ASSURE((nx == cpl_image_get_size_x(mask)) &&
435 (ny == cpl_image_get_size_y(mask)),
436 CPL_ERROR_ILLEGAL_INPUT,
437 "Data cube and mask don't have same dimensions!");
438
439
440 BRK_IF_NULL(data_in = cpl_imagelist_new());
441 BRK_IF_NULL(error_in = cpl_imagelist_new());
442 for (cpl_size sz = 0; sz < nz; sz++) {
443 hdrl_image *tmpImg = hdrl_imagelist_get(cube, sz);
444 cpl_imagelist_set(data_in, cpl_image_duplicate(hdrl_image_get_image(tmpImg)), sz);
445 cpl_imagelist_set(error_in, cpl_image_duplicate(hdrl_image_get_error(tmpImg)), sz);
446 }
448
449 lambda = cpl_vector_new(nz);
450 spec_data = cpl_vector_new(nz);
451 spec_error = cpl_vector_new(nz);
452 spec_totFlux = cpl_vector_new(nz);
453 spec_qual = cpl_vector_new(nz);
454 pLambda = cpl_vector_get_data(lambda);
455 pData = cpl_vector_get_data(spec_data);
456 pError = cpl_vector_get_data(spec_error);
457 pTotFlux = cpl_vector_get_data(spec_totFlux);
458 pqual = cpl_vector_get_data(spec_qual);
459 pMask = cpl_image_get_data_double_const(mask);
461
462 // loop over all lambda slices
463 fill_nz = 0;
464 for (cpl_size sz = 0; sz < nz; sz++) {
465 tmpDataImg = cpl_imagelist_get(data_in, sz);
466 tmpErrorImg = cpl_imagelist_get(error_in, sz);
467 bpm = cpl_image_get_bpm_const(tmpDataImg);
468 pTmpData = cpl_image_get_data_double_const(tmpDataImg);
469 pTmpError = cpl_image_get_data_double_const(tmpErrorImg);
470 pBpm = cpl_mask_get_data_const(bpm);
472
473 // extract spectrum for data
474 sumData = 0.0;
475 sumVariance = 0.0;
476 weights = 0.0;
477 valid = false;
478 for (cpl_size j = 0; j < ny; j++) {
479 for (cpl_size i = 0; i < nx; i++) {
480 // sumData weighted pixels in spatial plane
481 cpl_size p = i+j*nx;
482 if ((pBpm[p] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[p])) {
483 valid = true;
484 if (mask != NULL) {
485 sumData += pTmpData[p] * pMask[p];
486 sumVariance += pow(pTmpError[p] * pMask[p],2);
487 weights += pMask[p];
488 /* AMo: temporarily added for debug to make some check on problematic data
489 if(startLambda + (double) sz * deltaLambda > 2.254 &&
490 startLambda + (double) sz * deltaLambda < 2.270 ) {
491 cpl_msg_info(cpl_func,"ok1: pMask[p]: %g",pMask[p]);
492 }
493 */
494 } else {
495 sumData += pTmpData[p];
496 sumVariance += pow(pTmpError[p],2);
497 weights += 1.;
498 }
499 }
500 }
501 }
502
503 if ((valid == true) && (fabs(weights) > DBL_ZERO_TOLERANCE)) {
504 pLambda[fill_nz] = startLambda + (double) sz * deltaLambda;
505 pData[fill_nz] = sumData / weights;
506 pError[fill_nz] = sqrt(sumVariance) / weights;
507 pTotFlux[fill_nz] = sumData;
508 pqual[fill_nz] = 0;
509 fill_nz++;
510 }
512 }
513 BRK_IF_ERROR(cpl_vector_set_size(lambda, fill_nz));
514 BRK_IF_ERROR(cpl_vector_set_size(spec_data, fill_nz));
515 BRK_IF_ERROR(cpl_vector_set_size(spec_error, fill_nz));
516 BRK_IF_ERROR(cpl_vector_set_size(spec_totFlux, fill_nz));
517 BRK_IF_ERROR(cpl_vector_set_size(spec_qual, fill_nz));
518
519 spectrum = cpl_bivector_wrap_vectors(lambda, spec_data);
520 *error = spec_error;
521 *totalFlux = spec_totFlux;
522 *quality = spec_qual;
523 cpl_imagelist_delete(data_in);
524 cpl_imagelist_delete(error_in);
525 } CATCH {
526 spectrum = NULL;
527 }
528 eris_check_error_code("eris_ifu_extract_spectrum");
529 return spectrum;
530}
531
532
533
534
535
536//cpl_bivector * eris_ifu_extract_spectrum2(
537// hdrl_imagelist *cube,
538// cpl_image *mask,
539// double startLambda,
540// double deltaLambda,
541// cpl_vector **error,
542// cpl_vector **totalFlux)
543//{
544// cpl_bivector *spectrum = NULL;
545// cpl_imagelist *data_in = NULL;
546// cpl_imagelist *error_in = NULL;
547// const cpl_image *tmpDataImg = NULL;
548// const cpl_image *tmpErrorImg = NULL;
549// const cpl_mask *bpm = NULL;
550// const double *pTmpData = NULL;
551// const double *pTmpError = NULL;
552// const cpl_binary *pBpm = NULL;
553// const double *pMask = NULL;
554// cpl_size nx, ny, nz;
555// cpl_size fill_nz;
556// cpl_vector *lambda = NULL;
557// cpl_vector *spec_data = NULL;
558// cpl_vector *spec_error = NULL;
559// cpl_vector *spec_totFlux = NULL;
560// double *pLambda = NULL;;
561// double *pData = NULL;;
562// double *pError = NULL;;
563// double *pTotFlux = NULL;;
564// double sumData;
565// double sumVariance;
566// double weights;
567// bool valid;
568
569// hdrl_image* cube_median = NULL;
570// cpl_image* cube_median_data = NULL;
571// cpl_image* cube_median_errs = NULL;
572// cpl_image* scale_factor_data = NULL;
573// cpl_image* scale_factor_errs = NULL;
574// const double *pFactorData = NULL;
576// const double *pModelData = NULL;
577// const double *pModelErrs = NULL;
580// double model_factor_avg = 0;
581
582// cpl_size model_ndata = 0;
583// const cpl_size kernel_sx = 5;
584// const cpl_size kernel_sy = 5;
585// cpl_image* contrib_map;
586
587// cpl_ensure(cube != NULL,CPL_ERROR_NULL_INPUT, NULL);
588// cpl_ensure(mask != NULL,CPL_ERROR_NULL_INPUT, NULL);
589// cpl_ensure(error != NULL,CPL_ERROR_NULL_INPUT, NULL);
590
591// TRY{
592// nx = hdrl_imagelist_get_size_x(cube);
593// ny = hdrl_imagelist_get_size_y(cube);
594// nz = hdrl_imagelist_get_size(cube);
595
596// ASSURE((nx == cpl_image_get_size_x(mask)) &&
597// (ny == cpl_image_get_size_y(mask)),
598// CPL_ERROR_ILLEGAL_INPUT,
599// "Data cube and mask don't have same dimensions!");
600// eris_print_rec_status(0);
601// hdrl_imagelist_collapse_median(cube, &cube_median, &contrib_map);
602// eris_print_rec_status(1);
603// cube_median_data = hdrl_image_get_image(cube_median);
604// cube_median_errs = hdrl_image_get_error(cube_median);
605// cpl_image_save(cube_median_data,"cube_median_data.fits",CPL_TYPE_DOUBLE,NULL,CPL_IO_DEFAULT);
606// eris_print_rec_status(2);
607// data_in = cpl_imagelist_new();
608// error_in = cpl_imagelist_new();
609// for (cpl_size sz = 0; sz < nz; sz++) {
610// hdrl_image *tmpImg = hdrl_imagelist_get(cube, sz);
611// cpl_imagelist_set(data_in, cpl_image_duplicate(hdrl_image_get_image(tmpImg)), sz);
612// cpl_imagelist_set(error_in, cpl_image_duplicate(hdrl_image_get_error(tmpImg)), sz);
613// }
614// CHECK_ERROR_STATE();
615
616// lambda = cpl_vector_new(nz);
617// spec_data = cpl_vector_new(nz);
618// spec_error = cpl_vector_new(nz);
619// spec_totFlux = cpl_vector_new(nz);
620// pLambda = cpl_vector_get_data(lambda);
621// pData = cpl_vector_get_data(spec_data);
622// pError = cpl_vector_get_data(spec_error);
623// pTotFlux = cpl_vector_get_data(spec_totFlux);
624// pMask = cpl_image_get_data_double_const(mask);
625// CHECK_ERROR_STATE();
626
627// // loop over all lambda slices
628// fill_nz = 0;
629// for (cpl_size sz = 0; sz < nz; sz++) {
630// tmpDataImg = cpl_imagelist_get(data_in, sz);
631// tmpErrorImg = cpl_imagelist_get(error_in, sz);
632// bpm = cpl_image_get_bpm_const(tmpDataImg);
633// pTmpData = cpl_image_get_data_double_const(tmpDataImg);
634// pTmpError = cpl_image_get_data_double_const(tmpErrorImg);
635// pBpm = cpl_mask_get_data_const(bpm);
636// eris_print_rec_status(0);
637// scale_factor_data = cpl_image_duplicate(tmpDataImg);
638// scale_factor_errs = cpl_image_duplicate(tmpErrorImg);
639// eris_print_rec_status(1);
640// cpl_image_power(scale_factor_errs, 2);
641// cpl_image_power(scale_factor_errs, 2);
642// eris_print_rec_status(2);
643// cpl_image_divide(scale_factor_data, cube_median_data);
644// cpl_image_divide(scale_factor_errs, cube_median_errs);
645// eris_print_rec_status(3);
646// pFactorData = cpl_image_get_data_double_const(scale_factor_data);
648// eris_print_rec_status(4);
649// pModelData = cpl_image_get_data_double_const(cube_median_data);
650// pModelErrs = cpl_image_get_data_double_const(cube_median_errs);
651// eris_print_rec_status(5);
652// CHECK_ERROR_STATE();
653
654// // extract spectrum for data
655// sumData = 0.0;
656// sumVariance = 0.0;
657// weights = 0.0;
658// valid = false;
659// for (cpl_size j = 0; j < ny; j++) {
660// for (cpl_size i = 0; i < nx; i++) {
661// // sumData weighted pixels in spatial plane
662// cpl_size p = i+j*nx;
665// model_ndata = 0;
666// if ((pBpm[p] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[p])) {
667// valid = true;
668// if (mask != NULL) {
669// sumData += pTmpData[p] * pMask[p];
670// sumVariance += pow(pTmpError[p] * pMask[p],2);
671// weights += pMask[p];
672// } else {
673// sumData += pTmpData[p];
674// sumVariance += pow(pTmpError[p],2);
675// weights += 1.;
676// }
677// } else {
678
679// /* we are on a bad pixel, we need to interpolate flux
680// * using the model */
681// /* Determine average factor: plane_data / model */
682// for (cpl_size jj = -kernel_sy; jj <= kernel_sy; jj++) {
683// for (cpl_size ii = -kernel_sx; ii <= kernel_sx; ii++) {
684// if( (i+ii) >= 0 && (i+ii) < nx &&
685// (j+jj) >= 0 && (j+jj) < ny) {
686
687// cpl_size pp = (i+ii)+(j+jj)*nx;
688// if ((pBpm[pp] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[pp])) {
689// model_factor_avg += pFactorData[pp];
690// model_ndata ++;
691// }
692// }
693// }
694// }
695// if(model_ndata>0) {
696// model_factor_avg /= model_ndata;
697// }
698
699// /* compute contribute from interpolated bad pixels
700// * scaling data from model and add it to flux determined
701// * on good data
702// */
703// if (!eris_ifu_is_nan_or_inf(pModelData[p])) {
704// valid = true;
705// if (mask != NULL) {
706// sumData += model_factor_avg * pModelData[p] * pMask[p];
707// sumVariance += pow(model_factor_avg * pModelErrs[p] * pMask[p],2);
708// weights += pMask[p];
709// if(startLambda + (double) sz * deltaLambda > 1.615 &&
710// startLambda + (double) sz * deltaLambda < 1.647 ) {
711// cpl_msg_info(cpl_func,"lambda: %g model: %g",pLambda[fill_nz], pModelData[p]);
712// }
713// } else {
714// sumData += model_factor_avg * pModelData[p];
715// sumVariance += pow(model_factor_avg * pModelErrs[p],2);
716// weights += 1.;
717// }
718// }
719
720// }
721// }
722// }
723
724// if ((valid == true) && (fabs(weights) > DBL_ZERO_TOLERANCE)) {
725// pLambda[fill_nz] = startLambda + (double) sz * deltaLambda;
726// pData[fill_nz] = sumData / weights;
727// pError[fill_nz] = sqrt(sumVariance) / weights;
728// pTotFlux[fill_nz] = sumData;
729// if(startLambda + (double) sz * deltaLambda > 1.615 &&
730// startLambda + (double) sz * deltaLambda < 1.647 ) {
731// cpl_msg_info(cpl_func,"lambda: %g flux: %g",pLambda[fill_nz], pData[fill_nz]);
732// }
733// fill_nz++;
734
735// }
736// cpl_image_delete(scale_factor_data);
737// cpl_image_delete(scale_factor_errs);
738// CHECK_ERROR_STATE();
739// }
740// BRK_IF_ERROR(cpl_vector_set_size(lambda, fill_nz));
741// BRK_IF_ERROR(cpl_vector_set_size(spec_data, fill_nz));
742// BRK_IF_ERROR(cpl_vector_set_size(spec_error, fill_nz));
743// BRK_IF_ERROR(cpl_vector_set_size(spec_totFlux, fill_nz));
744
745// spectrum = cpl_bivector_wrap_vectors(lambda, spec_data);
746// *error = spec_error;
747// *totalFlux = spec_totFlux;
748// cpl_imagelist_delete(data_in);
749// cpl_imagelist_delete(error_in);
750// hdrl_image_delete(cube_median);
751// cpl_image_delete(contrib_map);
752// } CATCH
753// {
754// spectrum = NULL;
755// }
756// eris_check_error_code("eris_ifu_extract_spectrum2");
757// return spectrum;
758//}
759
760
761
762//cpl_bivector * eris_ifu_extract_spectrum3(
763// hdrl_imagelist *cube,
764// cpl_image *mask,
765// double startLambda,
766// double deltaLambda,
767// cpl_vector **error,
768// cpl_vector **totalFlux)
769//{
770// cpl_bivector *spectrum = NULL;
771// cpl_imagelist *data_in = NULL;
772// cpl_imagelist *error_in = NULL;
773// const cpl_image *tmpDataImg = NULL;
774// const cpl_image *tmpErrorImg = NULL;
775// const cpl_mask *bpm = NULL;
776// const double *pTmpData = NULL;
777// const double *pTmpError = NULL;
778// const cpl_binary *pBpm = NULL;
779// const double *pMask = NULL;
780// cpl_size nx, ny, nz;
781// cpl_size fill_nz;
782// cpl_vector *lambda = NULL;
783// cpl_vector *spec_data = NULL;
784// cpl_vector *spec_error = NULL;
785// cpl_vector *spec_totFlux = NULL;
786// double *pLambda = NULL;;
787// double *pData = NULL;;
788// double *pError = NULL;;
789// double *pTotFlux = NULL;;
790// double sumData;
791// double sumVariance;
792// double weights;
793// bool valid;
794
795// cpl_imagelist* cube_data_tmp = NULL;
796// cpl_imagelist* cube_errs_tmp = NULL;
797// hdrl_image* cube_median = NULL;
798// cpl_image* cube_median_data = NULL;
799// cpl_image* cube_median_errs = NULL;
800// cpl_image* scale_factor_data = NULL;
801// cpl_image* scale_factor_errs = NULL;
802// const double *pFactorData = NULL;
804// const double *pModelData = NULL;
805// const double *pModelErrs = NULL;
808// double model_factor_avg = 0;
809
810// cpl_size model_def_hsize = 100;
811// cpl_size model_ndata = 0;
812// const cpl_size kernel_sx = 5;
813// const cpl_size kernel_sy = 5;
814// cpl_image* contrib_map;
815
816// cpl_ensure(cube != NULL,CPL_ERROR_NULL_INPUT, NULL);
817// cpl_ensure(mask != NULL,CPL_ERROR_NULL_INPUT, NULL);
818// cpl_ensure(error != NULL,CPL_ERROR_NULL_INPUT, NULL);
819
820// TRY {
821// eris_print_rec_status(0);
822// nx = hdrl_imagelist_get_size_x(cube);
823// ny = hdrl_imagelist_get_size_y(cube);
824// nz = hdrl_imagelist_get_size(cube);
825// eris_print_rec_status(1);
826// ASSURE((nx == cpl_image_get_size_x(mask)) &&
827// (ny == cpl_image_get_size_y(mask)),
828// CPL_ERROR_ILLEGAL_INPUT,
829// "Data cube and mask don't have same dimensions!");
830
831// hdrl_imagelist_collapse_median(cube, &cube_median, &contrib_map);
832// eris_print_rec_status(2);
833// cube_median_data = hdrl_image_get_image(cube_median);
834// cube_median_errs = hdrl_image_get_error(cube_median);
835// cpl_image_save(cube_median_data,"cube_median_data.fits",CPL_TYPE_DOUBLE,NULL,CPL_IO_DEFAULT);
836// eris_print_rec_status(3);
837// data_in = cpl_imagelist_new();
838// error_in = cpl_imagelist_new();
839// for (cpl_size sz = 0; sz < nz; sz++) {
840// hdrl_image *tmpImg = hdrl_imagelist_get(cube, sz);
841// cpl_imagelist_set(data_in, cpl_image_duplicate(hdrl_image_get_image(tmpImg)), sz);
842// cpl_imagelist_set(error_in, cpl_image_duplicate(hdrl_image_get_error(tmpImg)), sz);
843// }
844// eris_print_rec_status(4);
845// CHECK_ERROR_STATE();
846
847// lambda = cpl_vector_new(nz);
848// spec_data = cpl_vector_new(nz);
849// spec_error = cpl_vector_new(nz);
850// spec_totFlux = cpl_vector_new(nz);
851// pLambda = cpl_vector_get_data(lambda);
852// pData = cpl_vector_get_data(spec_data);
853// pError = cpl_vector_get_data(spec_error);
854// pTotFlux = cpl_vector_get_data(spec_totFlux);
855// pMask = cpl_image_get_data_double_const(mask);
856// eris_print_rec_status(5);
857// CHECK_ERROR_STATE();
858
859// // loop over all lambda slices
860// fill_nz = 0;
861// for (cpl_size sz = 0; sz < nz; sz++) {
862// eris_print_rec_status(6);
863// tmpDataImg = cpl_imagelist_get(data_in, sz);
864// tmpErrorImg = cpl_imagelist_get(error_in, sz);
865// bpm = cpl_image_get_bpm_const(tmpDataImg);
866// pTmpData = cpl_image_get_data_double_const(tmpDataImg);
867// pTmpError = cpl_image_get_data_double_const(tmpErrorImg);
868// pBpm = cpl_mask_get_data_const(bpm);
869// eris_print_rec_status(7);
870
871// /* determine local model on a slice of half size model_def_hsize */
872// if( sz >= model_def_hsize && sz < (nz-model_def_hsize)) {
873// cube_data_tmp = cpl_imagelist_new();
874// cube_errs_tmp = cpl_imagelist_new();
875// for(cpl_size k = 0; k <= 2*model_def_hsize; k++) {
876// cpl_size kk = sz - model_def_hsize + k;
877// cpl_imagelist_set(cube_data_tmp, cpl_imagelist_get(data_in, kk), k);
878// cpl_imagelist_set(cube_errs_tmp, cpl_imagelist_get(error_in, kk), k);
879// }
880
881// cube_median_data = cpl_imagelist_collapse_median_create(cube_data_tmp);
882// cube_median_errs = cpl_imagelist_collapse_median_create(cube_errs_tmp);
883
884// }
885// eris_print_rec_status(8);
886// scale_factor_data = cpl_image_duplicate(tmpDataImg);
887// scale_factor_errs = cpl_image_duplicate(tmpErrorImg);
888
889// cpl_image_power(scale_factor_errs, 2);
890// cpl_image_power(cube_median_errs, 2);
891// eris_print_rec_status(9);
892// if(cube_median_data != NULL) {
893// cpl_msg_warning(cpl_func,"Median data for sz: %lld", sz);
894// cpl_image_divide(scale_factor_data, cube_median_data);
895// } else {
896// cpl_msg_warning(cpl_func,"Median data for sz: %lld", sz);
897// }
898// if(cube_median_data != NULL) {
899// cpl_image_divide(scale_factor_errs, cube_median_errs);
900// } else {
901// cpl_msg_warning(cpl_func,"Median error for sz: %lld", sz);
902// }
903// eris_print_rec_status(10);
904// pFactorData = cpl_image_get_data_double_const(scale_factor_data);
906
907// pModelData = cpl_image_get_data_double_const(cube_median_data);
908// pModelErrs = cpl_image_get_data_double_const(cube_median_errs);
909// eris_print_rec_status(11);
910// CHECK_ERROR_STATE();
911
912// // extract spectrum for data
913// sumData = 0.0;
914// sumVariance = 0.0;
915// weights = 0.0;
916// valid = false;
917// eris_print_rec_status(12);
918// for (cpl_size j = 0; j < ny; j++) {
919// for (cpl_size i = 0; i < nx; i++) {
920// // sumData weighted pixels in spatial plane
921// cpl_size p = i+j*nx;
924// model_ndata = 0;
925// if ((pBpm[p] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[p])) {
926// valid = true;
927// if (mask != NULL) {
928// sumData += pTmpData[p] * pMask[p];
929// sumVariance += pow(pTmpError[p] * pMask[p],2);
930// weights += pMask[p];
931// } else {
932// sumData += pTmpData[p];
933// sumVariance += pow(pTmpError[p],2);
934// weights += 1.;
935// }
936// } else {
937
938// /* we are on a bad pixel, we need to interpolate flux
939// * using the model */
940// /* Determine average factor: plane_data / model */
941// for (cpl_size jj = -kernel_sy; jj <= kernel_sy; jj++) {
942// for (cpl_size ii = -kernel_sx; ii <= kernel_sx; ii++) {
943// if( (i+ii) >= 0 && (i+ii) < nx &&
944// (j+jj) >= 0 && (j+jj) < ny) {
945
946// cpl_size pp = (i+ii)+(j+jj)*nx;
947// if ((pBpm[pp] == GOOD_PIX) && !eris_ifu_is_nan_or_inf(pTmpData[pp])) {
948// model_factor_avg += pFactorData[pp];
949// model_ndata ++;
950// }
951// }
952// }
953// }
954// if(model_ndata>0) {
955// model_factor_avg /= model_ndata;
956// }
957
958// /* compute contribute from interpolated bad pixels
959// * scaling data from model and add it to flux determined
960// * on good data
961// */
962// if (!eris_ifu_is_nan_or_inf(pModelData[p])) {
963// valid = true;
964// if (mask != NULL) {
965// sumData += model_factor_avg * pModelData[p] * pMask[p];
966// sumVariance += pow(model_factor_avg * pModelErrs[p] * pMask[p],2);
967// weights += pMask[p];
968// /*
969// if(startLambda + (double) sz * deltaLambda > 1.615 &&
970// startLambda + (double) sz * deltaLambda < 1.647 ) {
971// cpl_msg_info(cpl_func,"lambda: %g model: %g",pLambda[fill_nz], pModelData[p]);
972// }
973// */
974// } else {
975// sumData += model_factor_avg * pModelData[p];
976// sumVariance += pow(model_factor_avg * pModelErrs[p],2);
977// weights += 1.;
978// }
979// }
980
981// }
982// }
983// }
984// eris_print_rec_status(13);
985// if ((valid == true) && (fabs(weights) > DBL_ZERO_TOLERANCE)) {
986// pLambda[fill_nz] = startLambda + (double) sz * deltaLambda;
987// pData[fill_nz] = sumData / weights;
988// pError[fill_nz] = sqrt(sumVariance) / weights;
989// pTotFlux[fill_nz] = sumData;
990// /*
991// if(startLambda + (double) sz * deltaLambda > 1.615 &&
992// startLambda + (double) sz * deltaLambda < 1.647 ) {
993// cpl_msg_info(cpl_func,"lambda: %g flux: %g",pLambda[fill_nz], pData[fill_nz]);
994// }
995// */
996// fill_nz++;
997
998// }
999// eris_print_rec_status(14);
1000// cpl_image_delete(scale_factor_data);
1001// cpl_image_delete(scale_factor_errs);
1002// if( sz >= model_def_hsize && sz < (nz-model_def_hsize)) {
1003// cpl_image_delete(cube_median_data);
1004// cpl_image_delete(cube_median_errs);
1005// for(cpl_size k = 2*model_def_hsize; k >= 0; k--) {
1006// cpl_imagelist_unset(cube_data_tmp,k);
1007// cpl_imagelist_unset(cube_errs_tmp,k);
1008// }
1009// cpl_imagelist_delete(cube_data_tmp);
1010// cpl_imagelist_delete(cube_errs_tmp);
1011// }
1012// eris_print_rec_status(15);
1013// CHECK_ERROR_STATE();
1014// }
1015// eris_print_rec_status(16);
1016// BRK_IF_ERROR(cpl_vector_set_size(lambda, fill_nz));
1017// BRK_IF_ERROR(cpl_vector_set_size(spec_data, fill_nz));
1018// BRK_IF_ERROR(cpl_vector_set_size(spec_error, fill_nz));
1019// BRK_IF_ERROR(cpl_vector_set_size(spec_totFlux, fill_nz));
1020
1021// spectrum = cpl_bivector_wrap_vectors(lambda, spec_data);
1022// *error = spec_error;
1023// *totalFlux = spec_totFlux;
1024// cpl_imagelist_delete(data_in);
1025// cpl_imagelist_delete(error_in);
1026// hdrl_image_delete(cube_median);
1027// cpl_image_delete(contrib_map);
1028// eris_print_rec_status(17);
1029// } CATCH
1030// {
1031// spectrum = NULL;
1032// }
1033// eris_check_error_code("eris_ifu_extract_spectrum3");
1034// return spectrum;
1035//}
1036
1074/*---------------------------------------------------------------------------*/
1075cpl_bivector * eris_ifu_optimal_extraction(const hdrl_imagelist *cube,
1076 const cpl_imagelist *cube_dqi,
1077 const cpl_image *img_mask,
1078 double startLambda,
1079 double deltaLambda,
1080 int productDepth,
1081 cpl_vector **error_out)
1082{
1083 cpl_bivector *spectrum = NULL;
1084 cpl_mask *mask = NULL;
1085 cpl_vector *spec = NULL,
1086 *spec_var = NULL;
1087 eris_ifu_vector *spec2 = NULL,
1088 *spec_var2 = NULL;
1089// hdrl_image *img = NULL;
1090// cpl_image *contribMap = NULL;
1091// cpl_size nx = 0,
1092// ny = 0;
1093// cpl_size xcen = 0,
1094// ycen = 0;
1095// double fwhm = 0.;
1096
1097 cpl_ensure(cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
1098 cpl_ensure(cube_dqi != NULL, CPL_ERROR_NULL_INPUT, NULL);
1099 cpl_ensure(img_mask != NULL, CPL_ERROR_NULL_INPUT, NULL);
1100 cpl_ensure(startLambda > 1.0, CPL_ERROR_NULL_INPUT, NULL);
1101 cpl_ensure(deltaLambda > 0, CPL_ERROR_NULL_INPUT, NULL);
1102 cpl_ensure(error_out != NULL,CPL_ERROR_NULL_INPUT, NULL);
1103
1104 TRY {
1105// nx = hdrl_imagelist_get_size_x(cube);
1106// ny = hdrl_imagelist_get_size_y(cube);
1107//
1108// // find centre & fwhm from a collapsed image (without fitting)
1109// img = eris_ifu_extract_spec_collapse(cube, &contribMap);
1110// if (productDepth >= PD_DEBUG) {
1111// eris_ifu_save_hdrl_image_dbg(img, "eris_dbg_collapsed_cube", CPL_IO_CREATE, NULL);
1112// }
1113//
1114// BRK_IF_ERROR(
1115// eris_ifu_opt_extr_get_center_fwhm(img, edge_trim, &xcen, &ycen, &fwhm));
1116// cpl_msg_debug(cpl_func,"Mask center at (%d/%d), FWHM: %g)", (int)xcen, (int)ycen, fwhm);
1117//
1118// BRK_IF_NULL(
1119// mask = eris_ifu_opt_extr_create_mask(nx, ny, xcen, ycen, fwhm));
1120// if (productDepth >= PD_DEBUG) {
1121// eris_ifu_save_mask_dbg(mask, "eris_dbg_mask.fits", CPL_IO_CREATE, NULL);
1122// }
1123
1124 // convert image to mask
1125 // img: 1: good, 0:bad -> mask: 0: good, 1: bad
1126 mask = eris_ifu_mask_from_image(img_mask);
1127 if (productDepth >= PD_DEBUG) {
1128 eris_ifu_save_mask_dbg(mask, "eris_dbg_mask.fits", CPL_IO_CREATE, NULL);
1129 }
1130
1132 eris_ifu_opt_extr_simple_extraction(cube, mask, &spec, &spec_var));
1133 if (productDepth >= PD_DEBUG) {
1134 eris_ifu_save_vector_dbg(spec, "eris_dbg_spec1.fits", CPL_IO_CREATE, NULL);
1135 eris_ifu_save_vector_dbg(spec_var, "eris_dbg_spec1.fits", CPL_IO_EXTEND, NULL);
1136 }
1137
1138 spec2 = eris_ifu_vector_create(spec),
1139 spec_var2 = eris_ifu_vector_create(spec_var);
1141 spectrum = eris_ifu_opt_extr_doit(cube, cube_dqi, mask,
1142 spec2, spec_var2,
1143 startLambda, deltaLambda,
1144 productDepth,
1145 error_out));
1147 eris_ifu_free_ifu_vector(&spec_var2);
1148
1149 if (productDepth >= PD_DEBUG) {
1150 // error ist the total error of the masked area
1151 eris_ifu_save_bivector_dbg(spectrum, "eris_dbg_spectrum_out.fits", 0, CPL_IO_CREATE);
1152 eris_ifu_save_vector_dbg(*error_out, "eris_dbg_spectrum_out.fits", CPL_IO_EXTEND, NULL);
1153
1154 eris_ifu_save_vector_dbg(cpl_bivector_get_x_const(spectrum), "eris_dbg_spectrum_in.fits", CPL_IO_CREATE, NULL);
1155 eris_ifu_save_vector_dbg(spec, "eris_dbg_spectrum_in.fits", CPL_IO_EXTEND, NULL);
1156 eris_ifu_opt_extr_vector_sqrt(spec_var);
1157 eris_ifu_save_vector_dbg(spec_var, "eris_dbg_spectrum_in.fits", CPL_IO_EXTEND, NULL);
1158 }
1159 } CATCH
1160 {
1161 eris_ifu_free_bivector(&spectrum);
1162 eris_ifu_free_mask(&mask);
1164 eris_ifu_free_ifu_vector(&spec_var2);
1165 }
1166// eris_ifu_free_image(&contribMap);
1167 eris_ifu_free_vector(&spec_var);
1168 eris_ifu_free_vector(&spec);
1169 eris_ifu_free_mask(&mask);
1170
1171 return spectrum;
1172}
1173
1174/*---------------------------------------------------------------------------*/
1197/*---------------------------------------------------------------------------*/
1198cpl_error_code eris_ifu_opt_extr_get_center_fwhm(const hdrl_image *hdrl_img,
1199 int edge_trim,
1200 cpl_size *xcen,
1201 cpl_size *ycen,
1202 double *fwhm)
1203{
1204 cpl_error_code ret_error = CPL_ERROR_NONE;
1205 double maxval = -9999e10;
1206 const cpl_image *img_data = NULL;
1207 const double *pimg_data = NULL;
1208 const cpl_mask *img_mask = NULL;
1209 const cpl_binary *pimg_mask = NULL;
1210 cpl_size nx = 0;
1211 int npix = 0;
1212
1213 cpl_ensure_code(hdrl_img != NULL, CPL_ERROR_NULL_INPUT);
1214 cpl_ensure_code(edge_trim >= 0, CPL_ERROR_NULL_INPUT);
1215
1216 TRY {
1218 img_data = hdrl_image_get_image_const(hdrl_img));
1219 nx = cpl_image_get_size_x(img_data);
1221 pimg_data = cpl_image_get_data_double_const(img_data));
1223 img_mask = hdrl_image_get_mask_const(hdrl_img));
1225 pimg_mask = cpl_mask_get_data_const(img_mask));
1226
1227 // find maxval and its position
1228 for (cpl_size x = edge_trim; x < hdrl_image_get_size_x(hdrl_img)-edge_trim; x++) {
1229 for (cpl_size y = edge_trim; y < hdrl_image_get_size_y(hdrl_img)-edge_trim; y++) {
1230 if ((pimg_mask[x+y*nx] == GOOD_PIX) &&
1231 (pimg_data[x+y*nx] > maxval) &&
1232 (!isnan(pimg_data[x+y*nx])))
1233 {
1234 maxval = pimg_data[x+y*nx];
1235 *xcen = x;
1236 *ycen = y;
1237 }
1238 }
1239 }
1240
1241 cpl_msg_debug(cpl_func,"Mask max. value: %g)", maxval);
1242
1243 // find number of pixels where value is bigger than half of maxval
1244 maxval *= 0.5;
1245 for (cpl_size x = edge_trim; x < hdrl_image_get_size_x(hdrl_img)-edge_trim; x++) {
1246 for (cpl_size y = edge_trim; y < hdrl_image_get_size_y(hdrl_img)-edge_trim; y++) {
1247 if ((pimg_mask[x+y*nx] == GOOD_PIX) &&
1248 (pimg_data[x+y*nx] > maxval) &&
1249 (!isnan(pimg_data[x+y*nx])))
1250 {
1251 npix++;
1252 }
1253 }
1254 }
1255
1256 // now define fwhm
1257 *fwhm = sqrt(npix); // a bit larger than the nominal size
1258 //*fwhm = 1.5 * sqrt(npix); // a bit larger than the nominal size
1259 } CATCH {
1260 CATCH_MSG();
1261 ret_error = cpl_error_get_code();
1262 *xcen = -1;
1263 *ycen = -1;
1264 *fwhm = NAN;
1265 }
1266
1267 return ret_error;
1268}
1269
1270/*---------------------------------------------------------------------------*/
1288/*---------------------------------------------------------------------------*/
1289cpl_mask* eris_ifu_opt_extr_create_mask(int nx,
1290 int ny,
1291 int xcen,
1292 int ycen,
1293 double fwhm)
1294{
1295 cpl_mask *mask = NULL;
1296 cpl_binary *pmask =NULL;
1297
1298 cpl_ensure(nx > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1299 cpl_ensure(ny > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1300 cpl_ensure(xcen > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1301 cpl_ensure(ycen > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1302 cpl_ensure(fwhm > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1303
1304 TRY {
1306 mask = cpl_mask_new(nx, ny));
1308 pmask = cpl_mask_get_data(mask));
1309
1310 for (int x = 0; x < nx; x++) {
1311 for (int y = 0; y < ny; y++) {
1312 if (fwhm <= sqrt(pow(x-xcen,2)+pow(y-ycen,2))) {
1313 // bad: outside
1314 pmask[x+y*nx] = BAD_PIX;
1315 } else {
1316 // good:inside
1317 pmask[x+y*nx] = GOOD_PIX;
1318 }
1319 }
1320 }
1321 } CATCH {
1322 CATCH_MSG();
1323 eris_ifu_free_mask(&mask);
1324 }
1325
1326 return mask;
1327}
1328
1329/*---------------------------------------------------------------------------*/
1346/*---------------------------------------------------------------------------*/
1347cpl_error_code eris_ifu_opt_extr_simple_extraction(const hdrl_imagelist *cube,
1348 const cpl_mask *mask,
1349 cpl_vector **spec,
1350 cpl_vector **spec_var)
1351{
1352 cpl_error_code ret_error = CPL_ERROR_NONE;
1353 const hdrl_image *tmp_img = NULL;
1354 hdrl_image *tmp_img2 = NULL;
1355 double *pspec = NULL,
1356 *pspec_var = NULL;
1357 cpl_size nz = 0;
1358 hdrl_value hv;
1359
1360 cpl_ensure_code(cube != NULL, CPL_ERROR_NULL_INPUT);
1361 cpl_ensure_code(mask != NULL, CPL_ERROR_NULL_INPUT);
1362
1363 TRY {
1364 nz = hdrl_imagelist_get_size(cube);
1365
1367 *spec = cpl_vector_new(nz));
1369 *spec_var = cpl_vector_new(nz));
1371 pspec = cpl_vector_get_data(*spec));
1373 pspec_var = cpl_vector_get_data(*spec_var));
1374
1375 for (int z = 0; z < nz; z++) {
1377 tmp_img = hdrl_imagelist_get_const(cube, z));
1379 tmp_img2 = hdrl_image_duplicate(tmp_img));
1381 hdrl_image_reject_from_mask(tmp_img2, mask));
1382
1383 hv = hdrl_image_get_sum(tmp_img2);
1384 pspec[z] = hv.data;
1385 pspec_var[z] = hv.error*hv.error;
1386 hdrl_image_delete(tmp_img2);
1387 }
1388 } CATCH {
1389 CATCH_MSG();
1390 ret_error = cpl_error_get_code();
1392 eris_ifu_free_vector(spec_var);
1393 }
1394
1395 return ret_error;
1396}
1397
1398/*---------------------------------------------------------------------------*/
1412/*---------------------------------------------------------------------------*/
1413cpl_bivector * eris_ifu_opt_extr_helper_usepix(const cpl_mask *mask, int *n_usepix)
1414{
1415 cpl_bivector *usepix = NULL;
1416 int nx = 0,
1417 ny = 0,
1418 index = 0;
1419 double *px = NULL,
1420 *py = NULL;
1421 const cpl_binary *pmask = NULL;
1422
1423 cpl_ensure(mask != NULL, CPL_ERROR_NULL_INPUT, NULL);
1424
1425 TRY {
1426 nx = cpl_mask_get_size_x(mask);
1427 ny = cpl_mask_get_size_y(mask);
1428
1429 // get number of pixels in mask
1430 *n_usepix = (nx * ny) - cpl_mask_count(mask);
1431 cpl_msg_debug(cpl_func,"optimal extraction: n_usepix: %d", *n_usepix);
1432
1433 if (*n_usepix > 0) {
1434 usepix = cpl_bivector_new(*n_usepix);
1435 pmask = cpl_mask_get_data_const(mask);
1436
1437 px = cpl_vector_get_data(cpl_bivector_get_x(usepix));
1438 py = cpl_vector_get_data(cpl_bivector_get_y(usepix));
1439
1440 for (int y = 0; y < ny; y++) {
1441 for (int x = 0; x < nx; x++) {
1442 if (pmask[x+y*nx] == GOOD_PIX) {
1443 px[index] = x;
1444 py[index] = y;
1445 index++;
1446 }
1447 }
1448 }
1449 }
1450 } CATCH {
1451 eris_ifu_free_bivector(&usepix);
1452 }
1453
1454 return usepix;
1455}
1456
1457/*---------------------------------------------------------------------------*/
1471/*---------------------------------------------------------------------------*/
1472cpl_error_code eris_ifu_opt_extr_helper_fill_vertical(cpl_image *img, const eris_ifu_vector *vec)
1473{
1474 cpl_ensure_code(vec, CPL_ERROR_NULL_INPUT);
1475
1476 double *pimg = cpl_image_get_data_double(img);
1477 cpl_size nx = cpl_image_get_size_x(img),
1478 ny = cpl_image_get_size_y(img);
1479 double *pkvmask = cpl_vector_get_data(vec->data),
1480 *pkvdata = cpl_vector_get_data(vec->mask);
1481
1482 cpl_ensure_code(eris_ifu_vector_get_size(vec) == ny, CPL_ERROR_ILLEGAL_INPUT);
1483
1484 for (int y = 0; y < ny; y++) {
1485 for (int x = 0; x < nx; x++) {
1486 if (pkvmask[y] > 0.5) {
1487 pimg[x+y*nx] = pkvdata[y];
1488 } else {
1489 cpl_image_reject(img, x+1, y+1);
1490 }
1491 }
1492 }
1493
1494 return CPL_ERROR_NONE;
1495}
1496
1497/*---------------------------------------------------------------------------*/
1513/*---------------------------------------------------------------------------*/
1514void eris_ifu_opt_extr_helper_fill_horizontal(cpl_image *img, const cpl_image *slice, const cpl_bivector *usepix, int row, int power) {
1515 double *pimg = cpl_image_get_data_double(img);
1516 const double *pslice_d = NULL;
1517 const int *pslice_i = NULL;
1518 cpl_size nx = cpl_image_get_size_x(slice);
1519 cpl_type type = cpl_image_get_type(slice);
1520 const double *px = cpl_vector_get_data_const(cpl_bivector_get_x_const(usepix)),
1521 *py = cpl_vector_get_data_const(cpl_bivector_get_y_const(usepix));
1522 cpl_size n_usepix = cpl_bivector_get_size(usepix);
1523
1524 if (type == CPL_TYPE_DOUBLE) {
1525 pslice_d = cpl_image_get_data_double_const(slice);
1526 } else if (type == CPL_TYPE_INT) {
1527 pslice_i = cpl_image_get_data_int_const(slice);
1528 } else {
1529 return;
1530 }
1531
1532 if (type == CPL_TYPE_DOUBLE) {
1533 for (int i = 0; i < n_usepix; i++) {
1534 double val = pslice_d[(int)px[i]+(int)py[i]*nx];
1535 if (power) {
1536 pimg[i+row*n_usepix] = pow(val, 2);
1537 } else {
1538 pimg[i+row*n_usepix] = val;
1539 }
1540 }
1541 } else {
1542 for (int i = 0; i < n_usepix; i++) {
1543 int val = pslice_i[(int)px[i]+(int)py[i]*nx];
1544 if (power) {
1545 pimg[i+row*n_usepix] = pow(val, 2);
1546 } else {
1547 pimg[i+row*n_usepix] = val;
1548 }
1549 }
1550 }
1551}
1552
1553/*---------------------------------------------------------------------------*/
1564/*---------------------------------------------------------------------------*/
1565void eris_ifu_opt_extr_helper_set_positive(cpl_image *img) {
1566 double *pimg = cpl_image_get_data_double(img);
1567 cpl_size nx = cpl_image_get_size_x(img),
1568 ny = cpl_image_get_size_y(img);
1569 int n_neg = 0;
1570
1571 for (int x = 0; x < nx; x++) {
1572 for (int y = 0; y < ny; y++) {
1573 if ((pimg[x+y*nx] < 0.) || isnan(pimg[x+y*nx])) {
1574 pimg[x+y*nx] = 0.;
1575 n_neg++;
1576 }
1577 }
1578 }
1579 cpl_msg_debug(cpl_func, "optimal extraction: Resetting %d negative values in original PSF", n_neg);
1580}
1581
1582/*---------------------------------------------------------------------------*/
1591/*---------------------------------------------------------------------------*/
1592cpl_vector* eris_ifu_opt_extr_get_col(const cpl_image *img, int colnr)
1593{
1594 int nx = 0,
1595 ny = 0;
1596 double *pvec = NULL;
1597 const double *pimg = NULL;
1598 cpl_vector *vec = NULL;
1599
1600 cpl_ensure(img != NULL, CPL_ERROR_NULL_INPUT, NULL);
1601
1602 nx = cpl_image_get_size_x(img);
1603 ny = cpl_image_get_size_y(img);
1604
1605 cpl_ensure(colnr <= nx, CPL_ERROR_ILLEGAL_INPUT, NULL);
1606
1607 vec = cpl_vector_new(ny);
1608 pvec = cpl_vector_get_data(vec);
1609 pimg = cpl_image_get_data_double_const(img);
1610
1611 for (int y = 0; y < ny; y++) {
1612 pvec[y] = pimg[colnr+y*nx];
1613 }
1614
1615 return vec;
1616}
1617
1618/*---------------------------------------------------------------------------*/
1627/*---------------------------------------------------------------------------*/
1628cpl_vector* eris_ifu_opt_extr_get_row(const cpl_image *img, int rownr)
1629{
1630 int nx = 0,
1631 ny = 0;
1632 double *pvec = NULL;
1633 const double *pimg = NULL;
1634 cpl_vector *vec = NULL;
1635
1636 cpl_ensure(img != NULL, CPL_ERROR_NULL_INPUT, NULL);
1637
1638 nx = cpl_image_get_size_x(img);
1639 ny = cpl_image_get_size_y(img);
1640
1641 cpl_ensure(rownr <= ny, CPL_ERROR_ILLEGAL_INPUT, NULL);
1642
1643 vec = cpl_vector_new(nx);
1644 pvec = cpl_vector_get_data(vec);
1645 pimg = cpl_image_get_data_double_const(img);
1646
1647 for (int x = 0; x < nx; x++) {
1648 pvec[x] = pimg[x+rownr*nx];
1649 }
1650
1651 return vec;
1652}
1653
1654/*---------------------------------------------------------------------------*/
1664/*---------------------------------------------------------------------------*/
1665cpl_error_code eris_ifu_opt_extr_set_row(cpl_image *img,
1666 int rownr,
1667 const cpl_vector *vec)
1668{
1669 int nx = 0,
1670 ny = 0;
1671 const double *pvec = NULL;
1672 double *pimg = NULL;
1673
1674 cpl_ensure_code(img != NULL, CPL_ERROR_NULL_INPUT);
1675 cpl_ensure_code(vec != NULL, CPL_ERROR_NULL_INPUT);
1676
1677 nx = cpl_image_get_size_x(img);
1678 ny = cpl_image_get_size_y(img);
1679
1680 cpl_ensure_code(rownr <= ny, CPL_ERROR_ILLEGAL_INPUT);
1681 cpl_ensure_code(nx == cpl_vector_get_size(vec), CPL_ERROR_ILLEGAL_INPUT);
1682
1683 pvec = cpl_vector_get_data_const(vec);
1684 pimg = cpl_image_get_data_double(img);
1685
1686 for (int x = 0; x < nx; x++) {
1687 pimg[x+rownr*nx] = pvec[x];
1688 }
1689
1690 return cpl_error_get_code();
1691}
1692
1693/*---------------------------------------------------------------------------*/
1703/*---------------------------------------------------------------------------*/
1704cpl_error_code eris_ifu_opt_extr_set_col(cpl_image *img,
1705 int colnr,
1706 const cpl_vector *vec)
1707{
1708 int nx = 0,
1709 ny = 0;
1710 double *pimg = NULL;
1711 const double *pvec = NULL;
1712
1713 cpl_ensure_code(img != NULL, CPL_ERROR_NULL_INPUT);
1714 cpl_ensure_code(vec != NULL, CPL_ERROR_NULL_INPUT);
1715
1716 nx = cpl_image_get_size_x(img);
1717 ny = cpl_image_get_size_y(img);
1718
1719 cpl_ensure_code(colnr <= nx, CPL_ERROR_ILLEGAL_INPUT);
1720 cpl_ensure_code(ny == cpl_vector_get_size(vec), CPL_ERROR_ILLEGAL_INPUT);
1721
1722 pvec = cpl_vector_get_data_const(vec);
1723 pimg = cpl_image_get_data_double(img);
1724
1725 for (int y = 0; y < ny; y++) {
1726 pimg[colnr+y*nx] = pvec[y];
1727 }
1728
1729 return cpl_error_get_code();
1730}
1731
1732/*---------------------------------------------------------------------------*/
1744/*---------------------------------------------------------------------------*/
1745cpl_vector* eris_ifu_opt_extr_create_lambda(int size, double startLambda, double deltaLambda)
1746{
1747 cpl_vector *lambda = cpl_vector_new(size);
1748 double *pLambda = cpl_vector_get_data(lambda);
1749
1750 for (int i = 0; i < size; i++) {
1751 pLambda[i] = startLambda + (double)i * deltaLambda;
1752 }
1753 return lambda;
1754}
1755
1756/*---------------------------------------------------------------------------*/
1765/*---------------------------------------------------------------------------*/
1766cpl_error_code eris_ifu_opt_extr_vector_sqrt(cpl_vector *vec)
1767{
1768 double *pvec = cpl_vector_get_data(vec);
1769 cpl_ensure_code(vec != NULL, CPL_ERROR_NULL_INPUT);
1770
1771 for (int i = 0; i < cpl_vector_get_size(vec); i++) {
1772 pvec[i] = sqrt(pvec[i]);
1773 }
1774 return cpl_error_get_code();
1775}
1776
1777/*---------------------------------------------------------------------------*/
1804/*---------------------------------------------------------------------------*/
1805cpl_bivector* eris_ifu_opt_extr_doit(const hdrl_imagelist *cube,
1806 const cpl_imagelist *cube_dqi,
1807 const cpl_mask *mask,
1808 const eris_ifu_vector *spec,
1809 const eris_ifu_vector *spec_var,
1810 double startLambda,
1811 double deltaLambda,
1812 int productDepth,
1813 cpl_vector **error_out)
1814{
1815 cpl_bivector *spectrum = NULL,
1816 *usepix = NULL;
1817 cpl_size nz = 0;
1818 cpl_vector *vec = NULL,
1819 *rejectvec = NULL,
1820 *vec_err = NULL,
1821 *keep0 = NULL,
1822 *new_vec = NULL;
1823 eris_ifu_vector *speco = NULL,
1824 *spec_var_err = NULL,
1825 *sigo = NULL;
1826 cpl_image *spec1 = NULL,
1827 *psfvals = NULL,
1828 *varvals = NULL,
1829 *qualvals = NULL,
1830 *psfmod = NULL,
1831 *psfmodnew = NULL,
1832 *reject = NULL,
1833 *snr2 = NULL,
1834 *residual = NULL;
1835 int n_usepix = 0,
1836 jj = 0,
1837 sm = 49; // smoothing half-length (use, e.g. 15 for spectra with wiggles, up to 49 for ideal spectra).
1838 // Smoothing is done over a length of +/-sm pixels.
1839 double clipfrac = 0.9, // fraction to set for percentile clipping
1840 *pnew_vec = NULL,
1841 *pqualvals = NULL,
1842 *preject = NULL,
1843 *pkeep0 = NULL/*,
1844 *pspeco = NULL,
1845 *psigo = NULL*/;
1846 const double *pvec = NULL,
1847 *prejectvec = NULL;
1848
1849 cpl_ensure(cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
1850 cpl_ensure(cube_dqi != NULL, CPL_ERROR_NULL_INPUT, NULL);
1851 cpl_ensure(mask != NULL, CPL_ERROR_NULL_INPUT, NULL);
1852 cpl_ensure(spec != NULL, CPL_ERROR_NULL_INPUT, NULL);
1853 cpl_ensure(spec_var != NULL, CPL_ERROR_NULL_INPUT, NULL);
1854 cpl_ensure(error_out != NULL, CPL_ERROR_NULL_INPUT, NULL);
1855 cpl_ensure(hdrl_imagelist_get_size(cube) == cpl_imagelist_get_size(cube_dqi),
1856 CPL_ERROR_ILLEGAL_INPUT, NULL);
1857 cpl_ensure(hdrl_imagelist_get_size(cube) == eris_ifu_vector_get_size(spec),
1858 CPL_ERROR_ILLEGAL_INPUT, NULL);
1859 cpl_ensure(hdrl_imagelist_get_size(cube) == eris_ifu_vector_get_size(spec_var),
1860 CPL_ERROR_ILLEGAL_INPUT, NULL);
1861
1862 TRY {
1863 nz = hdrl_imagelist_get_size(cube);
1864
1865 spec_var_err = eris_ifu_vector_duplicate(spec_var);
1866 eris_ifu_vector_sqrt(spec_var_err);
1867 eris_ifu_vector_divide(spec_var_err, spec);
1869
1870 // get coordinates of used pixels in mask
1871 usepix = eris_ifu_opt_extr_helper_usepix(mask, &n_usepix);
1872
1873 // for convenience spectra of all selected pixels are stored in a 2D array
1874 spec1 = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE);
1875 psfvals = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // = (D - S)
1876 //psfmod = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // = P
1877 varvals = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // = V
1878 qualvals = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // for additional clipping regarding DQI
1879 pqualvals = cpl_image_get_data_double(qualvals);
1881
1882 // begin optimal extraction
1883 // 1st time through bigloop use initial spectrum
1884 // 2nd time through bigloop use previous output spectrum
1885 speco = eris_ifu_vector_duplicate(spec); // working spectrum data
1886// pspeco = cpl_vector_get_data(speco);
1887 sigo = eris_ifu_vector_new(nz); // working spectrum error
1888// psigo = cpl_vector_get_data(sigo);
1890
1891 for (int bigloop = 0; bigloop <= 1; bigloop++) {
1892 // spec0 is vector
1893 // spec1 is image (duplicates of speco)
1895 eris_ifu_opt_extr_helper_fill_vertical(spec1, speco));
1896
1897 // fill data/error/dqi values of used (unmasked) pixels to 2D-array
1898 // for varvals store the squared values
1899 for (int z = 0; z < nz; z++) {
1900 const hdrl_image *hdrl_img = hdrl_imagelist_get_const(cube, z);
1901 const cpl_image *slice_d = hdrl_image_get_image_const(hdrl_img);
1902 const cpl_image *slice_e = hdrl_image_get_error_const(hdrl_img);
1903 const cpl_image *slice_q = cpl_imagelist_get_const(cube_dqi, z);
1904
1905 eris_ifu_opt_extr_helper_fill_horizontal(psfvals, slice_d, usepix, z, FALSE);
1906 eris_ifu_opt_extr_helper_fill_horizontal(varvals, slice_e, usepix, z, TRUE);
1907 eris_ifu_opt_extr_helper_fill_horizontal(qualvals, slice_q, usepix, z, FALSE);
1908 }
1909
1910 eris_ifu_opt_extr_helper_set_positive(psfvals);
1911
1912 if (productDepth >= PD_DEBUG) {
1913 eris_ifu_save_image_dbg(psfvals, "ers_psfvals.fits", CPL_IO_CREATE, NULL);
1914 eris_ifu_save_image_dbg(varvals, "ers_varvals.fits", CPL_IO_CREATE, NULL);
1915 eris_ifu_save_image_dbg(qualvals, "ers_qualvals.fits", CPL_IO_CREATE, NULL);
1916 }
1917
1918 // replace fractions with weighted polynomial fits: the PSF model
1919 // Horne86, page 613 bottom right & Fig 1
1920 // two iterations; first with all pixels, second with clipped (from reject)
1921 reject = cpl_image_new(n_usepix, nz, CPL_TYPE_DOUBLE); // all zeros initially
1922 preject = cpl_image_get_data_double(reject);
1924
1925 new_vec = cpl_vector_new(nz);
1926 pnew_vec = cpl_vector_get_data(new_vec);
1927
1928 for (int iloop = 0; iloop <= 1; iloop++) {
1929 if (psfmod != NULL) {
1930 eris_ifu_free_image(&psfmod);
1931 }
1932 psfmod = cpl_image_divide_create(psfvals, spec1); // Horne86 eq 14, P = (D-S)/f
1933 eris_ifu_opt_extr_helper_set_positive(psfmod);
1935
1936 if (productDepth >= PD_DEBUG) {
1937 eris_ifu_save_image_dbg(psfmod, "ers_psfmod.fits", CPL_IO_CREATE, NULL);
1938 }
1939
1940 // slow loop
1941 for (int n = 0; n < n_usepix; n++) {
1942 vec = eris_ifu_opt_extr_get_col(psfmod, n);
1943 pvec = cpl_vector_get_data_const(vec);
1945
1947 vec_err = eris_ifu_vector_get_data(spec_var_err));
1949 cpl_vector_multiply(vec_err, vec));
1950
1951 rejectvec = eris_ifu_opt_extr_get_col(reject, n);
1952 prejectvec = cpl_vector_get_data_const(rejectvec);
1954
1955 // vector 'keep0' with indices on which values to keep
1956 keep0 = cpl_vector_new(nz);
1957 cpl_vector_fill(keep0, -1.0);
1958 pkeep0 = cpl_vector_get_data(keep0);
1959 jj = 0;
1960
1961 for (cpl_size iz = 0; iz < nz; iz++) {
1962
1963 if ((fabs(prejectvec[iz]) < 1e-5) &&
1964 (pvec[iz] > 0) &&
1965 !eris_ifu_is_nan_or_inf(pvec[iz]))
1966 {
1967
1968 pkeep0[jj++]= iz;
1969
1970 }
1971 } // end: for iz
1972 cpl_vector_delete(rejectvec);
1974 eris_ifu_cut_endings(&keep0, NULL, NULL, TRUE));
1975 if (keep0 != NULL) {
1976 pkeep0 = cpl_vector_get_data(keep0);
1978
1979 if ((productDepth >= PD_DEBUG) && (n==92)) {
1980 eris_ifu_save_vector_dbg(keep0, "ers_keep0.fits", CPL_IO_CREATE, NULL);
1981 }
1982
1983 // replace polynomial fitting by weighted mean smoothing over +/-sm pixels, after rejection
1984 for (int z = 0; z < nz; z++) {
1985 // reject keep0
1986 int s = cpl_vector_get_size(keep0);
1987 cpl_vector* ttt = cpl_vector_new(s);
1988 double *pttt = cpl_vector_get_data(ttt);
1989 cpl_vector_fill(ttt, -1.0);
1990 jj = 0;
1991 for (int iz = 0; iz < s; iz++) {
1992 int v = (int)(pkeep0[iz] +.5);
1993 if ((v > z-sm) && (v < z+sm)) {
1994 pttt[jj++] = iz;
1995 }
1996 }
1997 if (productDepth >= PD_DEBUG) {
1998 eris_ifu_save_vector_dbg(ttt, "ers_ttt.fits", CPL_IO_CREATE, NULL);
1999 }
2001 eris_ifu_cut_endings(&ttt, NULL, NULL, TRUE));
2002 if (ttt != NULL) {
2003 cpl_vector *iiuse = eris_ifu_idl_values_at_indices(keep0, ttt),
2004 *els = eris_ifu_idl_values_at_indices(vec, iiuse),
2005 *els_err = eris_ifu_idl_values_at_indices(vec_err, iiuse),
2006 *ones = cpl_vector_new(cpl_vector_get_size(els));
2008
2009 if ((productDepth >= PD_DEBUG) && (n==92) && (z == 1000)) {
2010 eris_ifu_save_vector_dbg(iiuse, "ers_iiuse.fits", CPL_IO_CREATE, NULL);
2011 eris_ifu_save_vector_dbg(els, "ers_els.fits", CPL_IO_CREATE, NULL);
2012 eris_ifu_save_vector_dbg(els_err, "ers_elserr.fits", CPL_IO_CREATE, NULL);
2013 }
2014
2015 cpl_vector_fill(ones, 1.0);
2016 cpl_vector_divide(els, els_err);
2017 cpl_vector_divide(ones, els_err);
2018 pnew_vec[z] = cpl_vector_get_sum(els) / cpl_vector_get_sum(ones);
2020
2021 eris_ifu_free_vector(&iiuse);
2022 eris_ifu_free_vector(&ones);
2024 eris_ifu_free_vector(&els_err);
2025 } else {
2026 pnew_vec[z] = NAN;
2027 }
2028
2030 } // end: for z
2032
2034 eris_ifu_opt_extr_set_col(psfmod, n, new_vec));
2035
2036 if ((productDepth >= PD_DEBUG) && (n==92)) {
2037 eris_ifu_save_vector_dbg(new_vec, "ers_newvec.fits", CPL_IO_CREATE, NULL);
2038 }
2039 }
2041 eris_ifu_free_vector(&vec_err);
2042 eris_ifu_free_vector(&keep0);
2043 } // end: for n
2045
2046 if (productDepth >= PD_DEBUG) {
2047 if (iloop==0) {
2048 eris_ifu_save_image_dbg(psfmod, "ers_psfmod_0.fits", CPL_IO_CREATE, NULL);
2049 } else {
2050 eris_ifu_save_image_dbg(psfmod, "ers_psfmod_1.fits", CPL_IO_CREATE, NULL);
2051 }
2052 }
2053
2054 // second iteration of polynomial fitting uses Horne86, page 614, top left: ((D-S) - fP)^2/V
2055 // also use qualitfy flag to reject pixels & define clipping value from data, slice by slice
2056 // snr2 = (psfvals-psfmod*spec1)^2/varvals
2057 cpl_image *psfmod_tmp = cpl_image_multiply_create(psfmod, spec1);
2058 snr2 = cpl_image_subtract_create(psfvals, psfmod_tmp);
2059 cpl_image_power(snr2, 2);
2060 cpl_image_divide(snr2, varvals);
2061 eris_ifu_free_image(&psfmod_tmp);
2063 if (productDepth >= PD_DEBUG) {
2064 if (iloop==0) {
2065 eris_ifu_save_image_dbg(snr2, "ers_snr2_0.fits", CPL_IO_CREATE, NULL);
2066 eris_ifu_save_image_dbg(reject, "ers_reject0_0.fits", CPL_IO_CREATE, NULL);
2067 } else {
2068 eris_ifu_save_image_dbg(snr2, "ers_snr2_1.fits", CPL_IO_CREATE, NULL);
2069 eris_ifu_save_image_dbg(reject, "ers_reject0_1.fits", CPL_IO_CREATE, NULL);
2070 }
2071 }
2072 for (int iz = 0; iz < nz; iz++) {
2073 vec = eris_ifu_opt_extr_get_row(snr2, iz);
2074 int n_fin = eris_ifu_opt_extr_get_not_finite(vec);
2075 if (n_fin > n_usepix*0.25) {
2076 //cpl_vector_abs
2077 cpl_vector_power(vec, 2);
2078 eris_ifu_cpl_vector_sqrt(vec);
2079
2080 cpl_vector_sort(vec, CPL_SORT_ASCENDING);
2081 double clip = cpl_vector_get(vec, n_usepix*clipfrac)*5;
2082 cpl_vector *tmp = eris_ifu_idl_where(vec, clip, gt);
2083 if ((tmp != NULL) && (cpl_vector_get_size(tmp) > 0)) {
2084 for (int ii = 0; ii < cpl_vector_get_size(tmp); ii++) {
2085 preject[(int)(cpl_vector_get(tmp, ii)+.5)+iz*n_usepix] = 1;
2086 }
2087 }
2089 } else {
2090 for (int ii = 0; ii < n_usepix; ii++) {
2091 preject[ii+iz*n_usepix] = 1;
2092 }
2093 }
2095 } // end: for iz
2097 if (productDepth >= PD_DEBUG) {
2098 if (iloop==0) {
2099 eris_ifu_save_image_dbg(reject, "ers_reject1_0.fits", CPL_IO_CREATE, NULL);
2100 } else {
2101 eris_ifu_save_image_dbg(reject, "ers_reject1_1.fits", CPL_IO_CREATE, NULL);
2102 }
2103 }
2104 for (int ii = 0; ii < n_usepix * nz; ii++) {
2105 if (pqualvals[ii] > 0) {
2106 preject[ii] = 1;
2107 }
2108 }
2110 if (productDepth >= PD_DEBUG) {
2111 if (iloop==0) {
2112 eris_ifu_save_image_dbg(reject, "ers_reject2_0.fits", CPL_IO_CREATE, NULL);
2113 } else {
2114 eris_ifu_save_image_dbg(reject, "ers_reject2_1.fits", CPL_IO_CREATE, NULL);
2115 }
2116 }
2117 eris_ifu_free_image(&snr2);
2118 } // end: for iloop
2119 eris_ifu_free_vector(&new_vec);
2120
2121 if (productDepth >= PD_DEBUG) {
2122 eris_ifu_save_image_dbg(reject, "ers_reject3.fits", CPL_IO_CREATE, NULL);
2123 }
2124 eris_ifu_free_image(&reject);
2125
2126 //go through PSF model plane by plane
2127 // reject low quality & noisy pixels * re-extract spectrum
2128 // Horne86 page 614, left, & Table 1 step 5c, 7, 8
2129 // steps 6 is skipped;
2130 // step 7 includes the quality flag
2131
2132 eris_ifu_free_image(&psfmodnew);
2134 psfmodnew = cpl_image_duplicate(psfmod));
2135
2136 //residual = (psfvals-psfmod*spec1)^2/varvals
2137 // for step 7; page 614 top right
2138 eris_ifu_free_image(&residual);
2139 residual = cpl_image_multiply_create(psfmod, spec1);
2140 cpl_image_subtract(residual, psfvals);
2141 cpl_image_multiply_scalar(residual, -1.);
2142 cpl_image_power(residual, 2);
2143 cpl_image_divide(residual, varvals);
2144
2145 if (productDepth >= PD_DEBUG) {
2146 eris_ifu_save_image_dbg(psfvals, "ers_psfvalsXXX.fits", CPL_IO_CREATE, NULL);
2147 eris_ifu_save_image_dbg(psfmod, "ers_psfmodXXX.fits", CPL_IO_CREATE, NULL);
2148 eris_ifu_save_image_dbg(spec1, "ers_spec1XXX.fits", CPL_IO_CREATE, NULL);
2149 eris_ifu_save_image_dbg(varvals, "ers_varvalsXXX.fits", CPL_IO_CREATE, NULL);
2150 eris_ifu_save_image_dbg(residual, "ers_residual.fits", CPL_IO_CREATE, NULL);
2151 }
2152
2153 // need to set clip value slice by slice
2154 // fit linear function to first 90% of sorted residual values and clip
2155 for (int iz = 0; iz < nz; iz++) {
2156 cpl_vector *resvec0 = eris_ifu_opt_extr_get_row(residual, iz);
2157 double *presvec0 = cpl_vector_get_data(resvec0);
2158
2159 if (productDepth >= PD_DEBUG) {
2160 eris_ifu_save_vector_dbg(resvec0, "ers_resvec0.fits", CPL_IO_CREATE, NULL);
2161 }
2162
2163 // vector 'keep0' with indices on which values to keep
2164 keep0 = cpl_vector_new(n_usepix);
2165 cpl_vector_fill(keep0, -1.0);
2166 pkeep0 = cpl_vector_get_data(keep0);
2167 jj = 0;
2168 for (int ii = 0; ii < n_usepix; ii++) {
2169 if (!eris_ifu_is_nan_or_inf(presvec0[ii]) &&
2170 presvec0[ii] > 0.)
2171 {
2172 pkeep0[jj++]= ii;
2173 }
2174 }
2176 eris_ifu_cut_endings(&keep0, NULL, NULL, TRUE));
2177
2178 if (productDepth >= PD_DEBUG) {
2179 eris_ifu_save_vector_dbg(keep0, "ers_keep.fits", CPL_IO_CREATE, NULL);
2180 }
2181
2182 cpl_vector *p = eris_ifu_opt_extr_get_row(psfmod, iz);
2183 double *pp = cpl_vector_get_data(p);
2184
2185 if ((keep0 != NULL) && (cpl_vector_get_size(keep0) > n_usepix*0.25)) {
2186 int nkeep = cpl_vector_get_size(keep0);
2187 cpl_vector *resvec = eris_ifu_idl_values_at_indices(resvec0, keep0),
2188 *resvecs = cpl_vector_duplicate(resvec);
2189 cpl_vector_sort(resvecs, CPL_SORT_ASCENDING);
2190
2191 if ((productDepth >= PD_DEBUG) && (iz == 1000)){
2192 eris_ifu_save_vector_dbg(resvecs, "ers_resvecs.fits", CPL_IO_CREATE, NULL);
2193 }
2194
2195 double clip = cpl_vector_get(resvecs, (int)(nkeep*clipfrac+.5)-1) * 5.;
2196 if (clip < 25.) {
2197 clip = 25.;
2198 }
2199
2200 cpl_vector *q = eris_ifu_opt_extr_get_row(qualvals, iz);
2201 double *pq = cpl_vector_get_data(q);
2202 eris_ifu_free_vector(&keep0);
2203 keep0 = cpl_vector_new(n_usepix);
2204 cpl_vector_fill(keep0, -1.0);
2205 pkeep0 = cpl_vector_get_data(keep0);
2206 jj = 0;
2207 for (int ii = 0; ii < n_usepix; ii++) {
2208 if ((presvec0[ii] > clip) || (pq[ii] == 1)) {
2209 pkeep0[jj++]= ii;
2210 }
2211 }
2213 eris_ifu_cut_endings(&keep0, NULL, NULL, TRUE));
2214 if (keep0 != NULL) {
2215 pkeep0 = cpl_vector_get_data(keep0);
2216 for (int ii = 0; ii < cpl_vector_get_size(keep0); ii++) {
2217 pp[(int)(pkeep0[ii])] = 0.;
2218 }
2219 }
2220
2221 double sum = cpl_vector_get_sum(p);
2222 for (int ii = 0; ii < cpl_vector_get_size(p); ii++) {
2223 pp[ii] /= sum;
2224 }
2225
2227 eris_ifu_free_vector(&resvecs);
2228 eris_ifu_free_vector(&resvec);
2229 } else {
2231 cpl_vector_fill(p, 0.));
2232 }
2233
2235 eris_ifu_opt_extr_set_row(psfmodnew, iz, p));
2236
2237 cpl_vector *vals = eris_ifu_opt_extr_get_row(psfvals, iz),
2238 *var = eris_ifu_opt_extr_get_row(varvals, iz);
2240 eris_ifu_opt_extr_convert_0_to_NaN_vec(var);
2241
2242 // pspeco[iz] = total(p*vals/var)/total(p^2./var)
2243 cpl_vector *tt = cpl_vector_duplicate(p);
2244 cpl_vector_multiply(tt, vals);
2245 cpl_vector_divide(tt, var);
2246 cpl_vector_power(p, 2.0);
2247 cpl_vector_divide(p, var);
2248 double sum_data = cpl_vector_get_sum(tt),
2249 sum_weight = cpl_vector_get_sum(p);
2251 eris_ifu_vector_set(speco, iz, sum_data / sum_weight));
2252
2253 //BRK_IF_ERROR(
2254 // eris_ifu_vector_set(sigo, iz, sqrt(1./total(p^2/var)));
2256 eris_ifu_vector_set(sigo, iz, sqrt(1./sum_weight)));
2257
2259 eris_ifu_free_vector(&vals);
2262 eris_ifu_free_vector(&keep0);
2263 eris_ifu_free_vector(&resvec0);
2265 } // end if: iz
2267 } // endfor: bigloop
2269
2270 // median((speco/sigo)/(spec0/sig0))
2271 eris_ifu_vector *tt = eris_ifu_vector_duplicate(speco);
2272 eris_ifu_vector_divide(tt, sigo);
2273 eris_ifu_vector_power(spec_var_err, -1.);
2274 eris_ifu_vector_divide(tt, spec_var_err);
2276
2277 cpl_msg_info(cpl_func, "typical S/N has increased by %g", eris_ifu_vector_get_median(tt, ERIS_IFU_ARITHMETIC));
2279
2280 cpl_vector *lambda = eris_ifu_opt_extr_create_lambda(nz, startLambda, deltaLambda);
2281 cpl_vector *speco2 = eris_ifu_vector_get_data(speco);
2283 spectrum = cpl_bivector_wrap_vectors(lambda, speco2));
2284
2285 cpl_vector *sigo2 = eris_ifu_vector_get_data(sigo);
2286 *error_out = sigo2;
2287
2288 // return sigo as vector (pow? sqrt?)
2289 // return total_flux??
2290 } CATCH {
2291 CATCH_MSG();
2292 eris_ifu_free_bivector(&spectrum);
2293 eris_ifu_free_vector(error_out);
2294 }
2295
2298 eris_ifu_free_ifu_vector(&spec_var_err);
2299 eris_ifu_free_bivector(&usepix);
2300 eris_ifu_free_image(&spec1);
2301 eris_ifu_free_image(&psfvals);
2302 eris_ifu_free_image(&psfmod);
2303 eris_ifu_free_image(&psfmodnew);
2304 eris_ifu_free_image(&varvals);
2305 eris_ifu_free_image(&qualvals);
2306 eris_ifu_free_image(&reject);
2307 eris_ifu_free_image(&residual);
2308
2309 return spectrum;
2310}
2311
2312/*---------------------------------------------------------------------------*/
2318/*---------------------------------------------------------------------------*/
2319int eris_ifu_opt_extr_get_not_finite(cpl_vector *vec) {
2320 int n_fin = 0;
2321 double *pvec = NULL;
2322
2323 cpl_ensure_code(vec != NULL, CPL_ERROR_NULL_INPUT);
2324
2325 pvec = cpl_vector_get_data(vec);
2326
2327 for (int i = 0; i < cpl_vector_get_size(vec); i++) {
2328 if (!eris_ifu_is_nan_or_inf(pvec[i])) {
2329 n_fin++;
2330 }
2331 }
2332
2333 return n_fin;
2334}
2335
2336/*---------------------------------------------------------------------------*/
2347/*---------------------------------------------------------------------------*/
2348void eris_ifu_opt_extr_convert_0_to_NaN_vec(cpl_vector *vec)
2349{
2350 cpl_size x = 0;
2351 double *pvec = NULL;
2352
2353 if (vec != NULL) {
2354 pvec = cpl_vector_get_data(vec);
2355
2356 x = cpl_vector_get_size(vec);
2357
2358 for (int i = 0 ; i < x; i++) {
2359 if (fabs(pvec[i]) < DBL_ZERO_TOLERANCE) {
2360 pvec[i] = NAN;
2361 }
2362 }
2363 }
2364}
2365
2366cpl_image* eris_ifu_opt_extr_estimate_radius_helper(const cpl_image *img,
2367 cpl_size center_x, cpl_size center_y,
2368 double radius,
2369 cpl_size *llx, cpl_size *lly,
2370 cpl_size *urx, cpl_size *ury)
2371{
2372 double half_maxval = 0.,
2373 *pmask = NULL;
2374 const double *pimg = NULL;
2375 cpl_image *mask = NULL;
2376 cpl_size nx = 0,
2377 ny = 0;
2378
2379 cpl_ensure(img != NULL, CPL_ERROR_NULL_INPUT, NULL);
2380
2381 TRY {
2382 pimg = cpl_image_get_data_double_const(img);
2383 nx = cpl_image_get_size_x(img);
2384 ny = cpl_image_get_size_y(img);
2385 half_maxval = pimg[center_x+nx*center_y] / 2;
2386
2387 mask = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
2388 pmask = cpl_image_get_data_double(mask);
2389
2390 *llx = center_x - radius;
2391 *lly = center_y - radius;
2392 *urx = center_x + radius;
2393 *ury = center_y + radius;
2394 if (*llx < 0) {
2395 *llx = 0;
2396 }
2397 if (*lly < 0) {
2398 *lly = 0;
2399 }
2400 if (*urx >= nx) {
2401 *urx = nx-1;
2402 }
2403 if (*ury >= ny) {
2404 *ury = ny-1;
2405 }
2406
2407 for (cpl_size x = *llx; x < *urx; x++) {
2408 for (cpl_size y = *lly; y < *ury; y++) {
2409 if (pimg[x+nx*y] >= half_maxval) {
2410 pmask[x+nx*y] = 1;
2411 }
2412 }
2413 }
2414
2415 } CATCH {
2416 CATCH_MSG();
2417 eris_ifu_free_image(&mask);
2418 }
2419
2420 return mask;
2421}
2422
2423double eris_ifu_opt_extr_estimate_radius(const cpl_image *img,
2424 cpl_size center_x, cpl_size center_y,
2425 double initial_radius,
2426 int productDepth)
2427{
2428 double radius = 0.,
2429 inc_radius = 2.,
2430 area_rectangle = 1.,
2431 area_mask = 4.;
2432 cpl_image *mask = NULL;
2433 cpl_size llx = 0,
2434 lly = 0,
2435 urx = 0,
2436 ury = 0,
2437 nx = 0,
2438 ny = 0;
2439
2440 cpl_ensure(img != NULL, CPL_ERROR_NULL_INPUT, -1.);
2441
2442 TRY {
2443 nx = cpl_image_get_size_x(img);
2444 ny = cpl_image_get_size_y(img);
2445 // define a max. radius: half size of image
2446 double max_radius = nx/2;
2447 if (ny/2 < max_radius) {
2448 max_radius = ny/2;
2449 }
2450 radius = initial_radius - inc_radius;
2451 // calculate ratio of good pixels, if > pi/4 make radius bigger
2452
2453 while ((area_mask / area_rectangle >= CPL_MATH_PI_4) && (radius < max_radius)) {
2454 radius += inc_radius;
2455 eris_ifu_free_image(&mask);
2456 mask = eris_ifu_opt_extr_estimate_radius_helper(img,
2457 center_x, center_y,
2458 radius,
2459 &llx, &lly, &urx, &ury);
2460 area_rectangle = (urx-llx)*(ury-lly);
2461 area_mask = cpl_image_get_flux(mask);
2462 if (productDepth >= PD_DEBUG) {
2463 eris_ifu_save_image_dbg(mask, "eris_dbg_mask.fits", CPL_IO_CREATE, NULL);
2464 }
2465 cpl_msg_debug(cpl_func, " intermediate mask center at (%d/%d), radius: %g, area mask: %g, area rect: %g)",
2466 (int)center_x, (int)center_y, radius, area_mask, area_rectangle);
2467
2468 }
2469 if (productDepth >= PD_DEBUG) {
2470 eris_ifu_save_image_dbg(mask, "eris_dbg_mask.fits", CPL_IO_CREATE, NULL);
2471 }
2472 cpl_msg_debug(cpl_func, "Final mask center at (%d/%d), radius: %g, area mask: %g, area rect: %g)",
2473 (int)center_x, (int)center_y, radius, area_mask, area_rectangle);
2474 } CATCH {
2475 CATCH_MSG();
2476 radius = 0.;
2477 }
2478
2479 eris_ifu_free_image(&mask);
2480
2481 return radius;
2482}
2483
2485// * @brief eris_ifu_opt_extr_median_without_NaN
2486// * @param vec
2487// */
2488//double eris_ifu_opt_extr_median_without_NaN(cpl_vector *vec)
2489//{
2490// cpl_size x = 0;
2491// double *pvec = NULL,
2492// *ptmp = NULL,
2493// median = -1.;
2494// int cnt = 0;
2495// cpl_vector *tmp = NULL;
2496//
2497// if (vec != NULL) {
2498// pvec = cpl_vector_get_data(vec);
2499//
2500// x = cpl_vector_get_size(vec);
2501// for (int i = 0 ; i < x; i++) {
2502// if (eris_ifu_is_nan_or_inf(pvec[i])) {
2503// cnt++;
2504// }
2505// }
2506//
2507// if ((x-cnt) > 0) {
2508// tmp = cpl_vector_new(x-cnt);
2509// ptmp = cpl_vector_get_data(tmp);
2510// cnt = 0;
2511// for (int i = 0 ; i < x; i++) {
2512// if (!eris_ifu_is_nan_or_inf(pvec[i])) {
2513// ptmp[cnt++] = pvec[i];
2514// }
2515// }
2516//
2517// median = cpl_vector_get_median(tmp);
2518// eris_ifu_free_vector(&tmp);
2519// }
2520// }
2521// return median;
2522//}
2523
2532cpl_error_code eris_ifu_cpl_vector_sqrt(cpl_vector *vec)
2533{
2534 cpl_size n = 0;
2535 double *pvec = NULL;
2536 cpl_error_code err = CPL_ERROR_NONE;
2537
2538 cpl_ensure_code(vec, CPL_ERROR_NULL_INPUT);
2539
2540 TRY
2541 {
2542 n = cpl_vector_get_size(vec);
2544
2546 pvec = cpl_vector_get_data(vec));
2547
2548 /* Compute the sqrt */
2549 for (int i = 0; i < n; i++) {
2550 /* pvec[i] can be NaN, since sqrt() handles NaN correctly:
2551 sqrt(NaN) = NaN */
2552 if (pvec[i] >= 0) {
2553 pvec[i] = sqrt(pvec[i]);
2554 } else {
2555 pvec[i] = NAN;
2556 }
2557 }
2558 } CATCH {
2559 err = cpl_error_get_code();
2560 }
2561
2562 return err;
2563}
#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 for debugging (quick, no DFS overhead)
cpl_error_code eris_ifu_save_image_dbg(const cpl_image *img, const char *filename, int create, const cpl_propertylist *pl)
Save image for debugging (quick, no DFS overhead)
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 for debugging (as vector or table)
cpl_error_code eris_ifu_save_mask_dbg(const cpl_mask *mask, const char *filename, int create, const cpl_propertylist *pl)
Save mask for debugging (quick, no DFS overhead)
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 known 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_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.
int eris_ifu_vector_get_size(const eris_ifu_vector *ev)
Get the size of the eris_ifu_vector.
cpl_error_code eris_ifu_vector_set(eris_ifu_vector *ev, int pos, double val)
Set an element of the eris_ifu_vector.
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_sqrt(eris_ifu_vector *ev)
eris_ifu_vector_sqrt
cpl_error_code eris_ifu_vector_power(eris_ifu_vector *ev, double exponent)
Compute the elementwise power of the 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.
double eris_ifu_vector_get_median(const eris_ifu_vector *ev, const enum medianType type)
Compute the median of the elements of a 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.
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.