ERIS Pipeline Reference Manual 1.9.3
eris_ifu_combine_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 <math.h>
26#include <string.h>
27#include <cpl.h>
28#include "eris_pfits.h"
29#include "eris_ifu_error.h"
30#include "eris_ifu_functions.h"
31#include "eris_ifu_utils.h"
32#include "eris_ifu_combine_static.h"
33
34/*----------------------------------------------------------------------------*/
47/*----------------------------------------------------------------------------*/
48
51/*----------------------------------------------------------------------------*/
82/*----------------------------------------------------------------------------*/
84 cpl_image **imagesData,
85 cpl_image **imagesError,
86 int nx_out,
87 int ny_out,
88 cpl_image **mergedImageData,
89 cpl_image **mergedImageError,
90 cpl_image **mergedImageDIT,
91 int n_cubes,
92 const float *offsetx,
93 const float *offsety,
94 const double *exptimes,
95 const double kappa,
96 const char *compute_mode,
97 const int pclip)
98{
99 int llx0 = 0,
100 lly0 = 0,
101 nx_in = 0,
102 ny_in = 0,
103 min_lx = INT_MAX,
104 min_ly = INT_MAX,
105 *llx = NULL,
106 *lly = NULL;
107 float *sub_offsetx = NULL,
108 *sub_offsety = NULL;
109 cpl_image **imagesDataShifted = NULL,
110 **imagesErrorShifted = NULL;
111 cpl_error_code ret_err = CPL_ERROR_NONE;
112
113 cpl_ensure_code(imagesData != NULL, CPL_ERROR_NULL_INPUT);
114 cpl_ensure_code(imagesError != NULL, CPL_ERROR_NULL_INPUT);
115 cpl_ensure_code(mergedImageData != NULL, CPL_ERROR_NULL_INPUT);
116 cpl_ensure_code(mergedImageError != NULL, CPL_ERROR_NULL_INPUT);
117 cpl_ensure_code(mergedImageDIT != NULL, CPL_ERROR_NULL_INPUT);
118 cpl_ensure_code(offsetx != NULL, CPL_ERROR_NULL_INPUT);
119 cpl_ensure_code(offsety != NULL, CPL_ERROR_NULL_INPUT);
120 cpl_ensure_code(exptimes != NULL, CPL_ERROR_NULL_INPUT);
121 cpl_ensure_code(compute_mode != NULL, CPL_ERROR_NULL_INPUT);
122
123 TRY {
124 nx_in = cpl_image_get_size_x(imagesData[0]);
125 ny_in = cpl_image_get_size_y(imagesData[0]);
126
127 /* Center the cubes within the allocated big cube.
128 * That means to define the (0,0) positions of the cubes in the image planes
129 * to sub-pixel accuracy by using cumoffsetx/y and the reference cube. */
130
131 /* Position of first reference frame, centered in big cube */
132 llx0 = (int)((double)(nx_out - nx_in) / 2.0 + 0.5);
133 lly0 = (int)((double)(ny_out - ny_in) / 2.0 + 0.5);
134
135 /* Go through the frame list and determine the lower left edge position
136 * of the shifted cubes. Additionnally, the sub-pixel offsets are
137 * determined. */
138 llx = cpl_calloc(n_cubes, sizeof(int));
139 lly = cpl_calloc(n_cubes, sizeof(int));
140 sub_offsetx = cpl_calloc(n_cubes, sizeof(float));
141 sub_offsety = cpl_calloc(n_cubes, sizeof(float));
143
144 for (int i = 0; i < n_cubes; i++) {
145 llx[i] = llx0 - eris_ifu_combine_nearest_int(offsetx[i]);
146
147 sub_offsetx[i] = (float)eris_ifu_combine_nearest_int(offsetx[i]) - offsetx[i];
148 lly[i] = lly0 - eris_ifu_combine_nearest_int(offsety[i]);
149 sub_offsety[i] = (float)eris_ifu_combine_nearest_int(offsety[i]) - offsety[i];
150
151 if (llx[i] < min_lx) {
152 min_lx = llx[i];
153 }
154 if (lly[i] < min_ly) {
155 min_ly = lly[i];
156 }
157 }
159
160 /* "Normalize" the shift - minimum should be 0 */
161 if (min_lx != 0) {
162 for (int i = 0 ; i < n_cubes ; i++ ) {
163 llx[i] = llx[i] - min_lx;
164 }
165 }
166 if (min_ly != 0) {
167 for (int i = 0 ; i < n_cubes ; i++ ) {
168 lly[i] = lly[i] - min_ly;
169 }
170 }
171
172 /* Shift the cubes according to the computed sub-pixel offsets
173 * that means shift the single image planes of each cube
174 * first determine an interpolation kernel
175 */
177 imagesDataShifted = (cpl_image**)cpl_calloc(n_cubes, sizeof(cpl_imagelist*)));
179 imagesErrorShifted = (cpl_image**)cpl_calloc(n_cubes, sizeof(cpl_imagelist*)));
180
181 for (int i = 0; i < n_cubes; i++) {
183 imagesDataShifted[i] = eris_ifu_combine_shift_image_kmos(
184 imagesData[i],
185 sub_offsetx[i], sub_offsety[i],
186 "NN", NONE_NANS));
188 imagesErrorShifted[i] = eris_ifu_combine_shift_image_kmos(
189 imagesError[i],
190 sub_offsetx[i], sub_offsety[i],
191 "NN", NONE_NANS));
192 }
193
194 /* Build the DIT cube */
196 eris_ifu_combine_build_mask_cube(imagesDataShifted,
197 mergedImageDIT,
198 llx, lly, exptimes,
199 n_cubes,
200 nx_out, ny_out));
201
202 if ((kappa != -1) && (pclip != -1)) {
203 // ks-clipping
206 n_cubes,
207 kappa, llx, lly, exptimes,
208 mergedImageData, mergedImageError, *mergedImageDIT,
209 imagesDataShifted, imagesErrorShifted,
210 compute_mode, pclip, nx_out, ny_out));
211 } else {
212 /* Calculate a weighted average using the exposure time of the
213 * single frames of the overlapping regions of the cubes */
216 mergedImageData, mergedImageError, *mergedImageDIT,
217 imagesDataShifted, imagesErrorShifted,
218 exptimes,
219 llx, lly, compute_mode, nx_out, ny_out));
220 }
221 } CATCH {
222 CATCH_MSGS();
223 ret_err = cpl_error_get_code();
224 eris_ifu_free_image(mergedImageData);
225 eris_ifu_free_image(mergedImageError);
226 eris_ifu_free_image(mergedImageDIT);
227 }
228
229 // free memory
230 for (int i = 0; i < n_cubes; i++) {
231 eris_ifu_free_image(&imagesDataShifted[i]);
232 eris_ifu_free_image(&imagesErrorShifted[i]);
233 }
234
235 cpl_free(imagesDataShifted); imagesDataShifted = NULL;
236 cpl_free(imagesErrorShifted); imagesErrorShifted = NULL;
237 cpl_free(llx); llx = NULL;
238 cpl_free(lly); lly = NULL;
239 cpl_free(sub_offsetx); sub_offsetx = NULL;
240 cpl_free(sub_offsety); sub_offsety = NULL;
241
242 return ret_err;
243}
244
245/*----------------------------------------------------------------------------*/
255/*----------------------------------------------------------------------------*/
256cpl_error_code eris_ifu_combine_divide_DIT( cpl_imagelist **cubesData,
257 const int n_cubes,
258 const double *exptimes)
259{
260 cpl_ensure_code(cubesData,CPL_ERROR_NULL_INPUT);
261 TRY {
262 for (int i = 0; i < n_cubes; i++) {
264 cpl_imagelist_divide_scalar(cubesData[i], exptimes[i]));
265 }
266 } CATCH {
267
268 }
269
270 return cpl_error_get_code();
271}
272
273/*----------------------------------------------------------------------------*/
290/*----------------------------------------------------------------------------*/
291cpl_error_code eris_ifu_combine_auto_size_cube(const float *offsetx,
292 const float *offsety,
293 const int nframes,
294 float *ref_offx,
295 float *ref_offy,
296 int *size_x,
297 int *size_y)
298{
299 float min_offx = 0,
300 max_offx = 0,
301 min_offy = 0,
302 max_offy = 0;
303
304 cpl_ensure_code(offsetx != NULL, CPL_ERROR_ILLEGAL_INPUT);
305 cpl_ensure_code(offsety != NULL, CPL_ERROR_ILLEGAL_INPUT);
306 cpl_ensure_code(nframes > 0, CPL_ERROR_ILLEGAL_INPUT);
307 cpl_ensure_code(*size_x >= 64, CPL_ERROR_ILLEGAL_INPUT);
308 cpl_ensure_code(*size_y >= 64, CPL_ERROR_ILLEGAL_INPUT);
309
310 cpl_msg_info (cpl_func, "Computation of output cube size") ;
312 offsetx, offsety,
313 &min_offx, &max_offx,
314 &min_offy, &max_offy);
315
316 cpl_msg_info(cpl_func, " max_offx = %f, max_offy = %f", max_offx, max_offy);
317 cpl_msg_info(cpl_func, " min_offx = %f, min_offy = %f", min_offx, min_offy);
318
319 *ref_offx = (min_offx+max_offx)/2;
320 *ref_offy = (min_offy+max_offy)/2;
321
322 /* The following to allow to compute the size of output cube in case the input
323 * has size different than 64x64
324 */
325 *size_x += 2*floor(max_offx-min_offx+0.5);
326 *size_y += 2*floor(max_offy-min_offy+0.5);
327
328 cpl_msg_info(cpl_func, " Output cube size: %d x %d",*size_x,*size_y);
329 cpl_msg_info(cpl_func, " Ref. offset x: %f, y: %f",*ref_offx,*ref_offy);
330 cpl_msg_info(cpl_func, " Max. offset x: %f, y: %f",max_offx,max_offy);
331 cpl_msg_info(cpl_func, " Min. offset x: %f, y: %f",min_offx,min_offy);
332
333 return cpl_error_get_code();
334}
335
336/*----------------------------------------------------------------------------*/
362/*----------------------------------------------------------------------------*/
363cpl_error_code eris_ifu_combine_build_mask(cpl_imagelist **cubesDataShifted,
364 cpl_image *mergedImgDIT,
365 const int n_cubes,
366 const int *llx,
367 const int *lly,
368 const double *exptimes)
369{
370 int nx_in = 0,
371 ny_in = 0;
372 cpl_size nx_out = 0,
373 ny_out = 0;
374 cpl_image *imgCubesDataShifted = NULL;
375 double *pimgMergedCubeDIT = NULL;
376
377 cpl_ensure_code(llx != NULL, CPL_ERROR_NULL_INPUT);
378 cpl_ensure_code(lly != NULL, CPL_ERROR_NULL_INPUT);
379 cpl_ensure_code(exptimes != NULL, CPL_ERROR_NULL_INPUT);
380 cpl_ensure_code(cubesDataShifted != NULL, CPL_ERROR_NULL_INPUT);
381 cpl_ensure_code(mergedImgDIT != NULL, CPL_ERROR_NULL_INPUT);
382
383 nx_out = cpl_image_get_size_x(mergedImgDIT);
384 ny_out = cpl_image_get_size_y(mergedImgDIT);
385
386 pimgMergedCubeDIT = cpl_image_get_data_double(mergedImgDIT);
387
388 for (int i = 0; i < n_cubes; i++) {
389 imgCubesDataShifted = cpl_imagelist_get(cubesDataShifted[i], 0);
390 nx_in = cpl_image_get_size_x(imgCubesDataShifted);
391 ny_in = cpl_image_get_size_y(imgCubesDataShifted);
392
393 //go through the first image plane of the big data cube
394 for (int y = 0; y < ny_out; y++) {
395 for (int x = 0; x < nx_out; x++) {
396 // find the position of the present cube and go
397 // through the single spectra
398 if ((y >= lly[i]) && (y < lly[i]+ny_in) &&
399 (x >= llx[i]) && (x < llx[i]+nx_in))
400 {
401 pimgMergedCubeDIT[x+y*nx_out] += exptimes[i];
402 }
403 } // end for(x)
404 } // end for(y)
405 } // end for(i)
406 return cpl_error_get_code();
407}
408
409/*----------------------------------------------------------------------------*/
428/*----------------------------------------------------------------------------*/
429cpl_error_code eris_ifu_combine_build_mask_cube(cpl_image **imagesDataShifted,
430 cpl_image **mergedImgDIT,
431 const int *llx,
432 const int *lly,
433 const double *exptimes,
434 int n_cubes,
435 cpl_size nx_out,
436 cpl_size ny_out)
437{
438 int nx_in = 0,
439 ny_in = 0,
440 x_in = 0,
441 y_in = 0;
442 double *pimgMergedCubeDIT = NULL,
443 *pimgCubesDataShifted = NULL;
444 cpl_image *imgCubesDataShifted = NULL;
445 cpl_error_code ret_err = CPL_ERROR_NONE;
446
447 cpl_ensure_code(llx != NULL, CPL_ERROR_NULL_INPUT);
448 cpl_ensure_code(lly != NULL, CPL_ERROR_NULL_INPUT);
449 cpl_ensure_code(exptimes != NULL, CPL_ERROR_NULL_INPUT);
450 cpl_ensure_code(imagesDataShifted != NULL, CPL_ERROR_NULL_INPUT);
451 cpl_ensure_code(mergedImgDIT != NULL, CPL_ERROR_NULL_INPUT);
452
453 TRY {
455 *mergedImgDIT = cpl_image_new(nx_out, ny_out, CPL_TYPE_DOUBLE));
457 pimgMergedCubeDIT = cpl_image_get_data_double(*mergedImgDIT));
458
459 for (int i = 0; i < n_cubes; i++) {
460 imgCubesDataShifted = imagesDataShifted[i];
462 pimgCubesDataShifted = cpl_image_get_data_double(imgCubesDataShifted));
463 nx_in = cpl_image_get_size_x(imgCubesDataShifted);
464 ny_in = cpl_image_get_size_y(imgCubesDataShifted);
465 x_in = 0;
466 y_in = 0;
467 for (int y = 0; y < ny_out; y++) {
468 for (int x = 0; x < nx_out; x++) {
469 // find the position of the present cube and go
470 // through the single spectra
471 if ((y >= lly[i]) && (y < lly[i]+ny_in) &&
472 (x >= llx[i]) && (x < llx[i]+nx_in))
473 {
474 if (!eris_ifu_is_nan_or_inf(pimgCubesDataShifted[x_in+nx_in*y_in]) &&
475 !cpl_image_is_rejected(imgCubesDataShifted, x_in+1, y_in+1))
476 {
477 pimgMergedCubeDIT[x+y*nx_out] += exptimes[i];
478 }
479 x_in++;
480 if (x_in >= nx_in) {
481 x_in = 0;
482 y_in++;
483 }
484 }
485 } // end for(x)
486 } // end for(y)
487 } // end for(i)
488 }
489 CATCH
490 {
491 CATCH_MSGS();
492 eris_ifu_free_image(mergedImgDIT);
493 ret_err = cpl_error_get_code();
494 }
495
496 return ret_err;
497}
498
499/*----------------------------------------------------------------------------*/
526/*----------------------------------------------------------------------------*/
527cpl_error_code eris_ifu_combine_coadd_ks_clip(const int n_frames,
528 const double kappa,
529 int *llx,
530 int *lly,
531 const double *exptimes,
532 cpl_image **imgMergedCubeData,
533 cpl_image **imgMergedCubeError,
534 cpl_image *mergedImgDIT,
535 cpl_image **imagesDataShifted,
536 cpl_image **imagesErrorShifted,
537 const char *compute_mode,
538 const int pclip,
539 const int nx_out,
540 const int ny_out)
541{
542 int n_contributes = 0,
543 nx_in = 0,
544 ny_in = 0,
545 posx = 0,
546 posy = 0,
547 ovr = 0; //overlap count
548 double *pimgCubesDataShifted = NULL,
549 *pimgCubesErrorShifted = NULL,
550 *pimgMergedCubeData = NULL,
551 *pimgMergedCubeError = NULL,
552 *pmergedImgDIT = NULL;
553 cpl_vector *msk = NULL,
554 *val = NULL; // vector to compute median of an output pixel
555 eris_ifu_vector *data_vec = NULL,
556 *err_vec = NULL;
557
558 TRY {
559 nx_in = cpl_image_get_size_x(imagesDataShifted[0]);
560 ny_in = cpl_image_get_size_y(imagesDataShifted[0]);
561
562 if (
563 (nx_out != cpl_image_get_size_x(mergedImgDIT)) ||
564 (ny_out != cpl_image_get_size_y(mergedImgDIT))
565 )
566 {
567 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
568 return cpl_error_get_code();
569 }
570
572 *imgMergedCubeData = cpl_image_new(nx_out, ny_out, CPL_TYPE_DOUBLE));
574 pimgMergedCubeData = cpl_image_get_data_double(*imgMergedCubeData));
575
577 *imgMergedCubeError = cpl_image_new(nx_out, ny_out, CPL_TYPE_DOUBLE));
579 pimgMergedCubeError = cpl_image_get_data_double(*imgMergedCubeError));
580
582 pmergedImgDIT = cpl_image_get_data_double(mergedImgDIT));
583
584 for (int y = 0; y < ny_out; y++) {
585 for (int x = 0; x < nx_out; x++) {
586 n_contributes = eris_ifu_combine_calc_contributions(imagesDataShifted,
587 n_frames,
588 llx, lly, x, y);
589 if (n_contributes > 0) {
590 msk = cpl_vector_new(n_frames);
591 for (int i = 0; i < n_frames; i++) {
592 cpl_vector_set(msk, i, 1);
593 }
594
596 eris_ifu_combine_coadd_ks_clip_internal(imagesDataShifted, n_frames,
597 n_contributes, x, y,
598 llx, lly, kappa, &msk,
599 compute_mode, pclip));
600
601 if (!strcmp(compute_mode, "MEDIAN")){
602 // median
603 val = cpl_vector_new(n_frames);
604 ovr = 0;
605 }
606
607 data_vec = eris_ifu_vector_new(n_frames);
608 err_vec = eris_ifu_vector_new(n_frames);
609
610 for (int i = 0; i < n_frames; i++) {
611 if ((y >= lly[i]) && (y < lly[i]+ny_in) &&
612 (x >= llx[i]) && (x < llx[i]+nx_in))
613 {
614 pimgCubesDataShifted = cpl_image_get_data_double(imagesDataShifted[i]);
615 pimgCubesErrorShifted = cpl_image_get_data_double(imagesErrorShifted[i]);
616
617 posx = x - llx[i];
618 posy = y - lly[i];
619
620 if (!isnan(pimgCubesDataShifted[posx+posy*nx_in]) &&
621 (fabs(pimgCubesDataShifted[posx+posy*nx_in]) > DBL_ZERO_TOLERANCE) &&
622 (fabs(pmergedImgDIT[x+y*nx_out]) > DBL_ZERO_TOLERANCE) &&
623 (cpl_vector_get(msk, i) != 0))
624 {
625 if (!strcmp(compute_mode, "MEDIAN")) {
626 // median
627 cpl_vector_set(val, ovr, pimgCubesDataShifted[posx+posy*nx_in]);
628 ovr++;
629 } else {
630 // mean
631 pimgMergedCubeData[x+y*nx_out] += pimgCubesDataShifted[posx+posy*nx_in] * exptimes[i];
632 }
633 eris_ifu_vector_set(data_vec, i, pimgCubesDataShifted[posx+posy*nx_in]);
634 eris_ifu_vector_set(err_vec, i, pimgCubesErrorShifted[posx+posy*nx_in]);
635 } else {
636 // invalid data value
637 eris_ifu_vector_reject(data_vec, i);
638 eris_ifu_vector_reject(err_vec, i);
639 }
640 } else {
641 // invalid data value
642 eris_ifu_vector_reject(data_vec, i);
643 eris_ifu_vector_reject(err_vec, i);
644 }
645 } // end for(i)
646
647 // calculate error
648 pimgMergedCubeError[x+y*nx_out] = eris_ifu_combine_calc_error(data_vec, err_vec, compute_mode);
649 eris_ifu_vector_delete(data_vec); data_vec = NULL;
650 eris_ifu_vector_delete(err_vec); err_vec = NULL;
651
652 if (!strcmp(compute_mode, "MEDIAN")) {
653 // median
654 if (ovr > 0) {
655 cpl_vector *tval = cpl_vector_extract(val, 0, ovr-1, 1);
656 pimgMergedCubeData[x+y*nx_out] = cpl_vector_get_median_const(tval);
658 }
660 } else {
661 // mean
662 pimgMergedCubeData[x+y*nx_out] /= pmergedImgDIT[x+y*nx_out];
663 }
664
666
667 } // end check if overlap nc > 0
668 } // end loop over x
669 } // end loop over y
670 } CATCH {
673 eris_ifu_free_image(imgMergedCubeData);
674 eris_ifu_free_image(imgMergedCubeError);
675 }
676
677 return cpl_error_get_code();
678}
679
680/*----------------------------------------------------------------------------*/
698/*----------------------------------------------------------------------------*/
699cpl_error_code eris_ifu_combine_coadd_ks_clip_internal(cpl_image** imagesDataShifted,
700 const int n_frames,
701 const int n_contributions,
702 const int x,
703 const int y,
704 int *llx,
705 int *lly,
706 const double kappa,
707 cpl_vector **msk,
708 const char *compute_mode,
709 const int pclip)
710{
711 int nclip = 0,
712 lox = 0,
713 loy = 0,
714 upx = 0,
715 upy = 0,
716 posx = 0,
717 posy = 0,
718 pos = 0,
719 ovr = 0,
720 pk = 0;
721 double sig = 0.,
722 med = 0.,
723 *pimg_in = NULL;
724 cpl_size nx = 0,
725 ny = 0;
726 cpl_vector *val = NULL;
727 cpl_error_code ret_err = CPL_ERROR_NONE;
728
729 TRY {
730 nx = cpl_image_get_size_x(imagesDataShifted[0]);
731 ny = cpl_image_get_size_y(imagesDataShifted[0]);
732
733 for (int ks = 0; ks < n_contributions; ks++) { //for large nc: may optimize for efficiency
734 sig = 0;
735 med = 0;
736 ovr = 0;
737
738 if (n_contributions-nclip > 0) {
739 val = cpl_vector_new(n_contributions-nclip);
740 } else {
741 break;
742 }
743
744 // fill val
745 for (int i = 0; i < n_frames; i++) {
746 pimg_in = cpl_image_get_data_double(imagesDataShifted[i]);
747
748 lox = llx[i];
749 loy = lly[i];
750 upx = llx[i]+nx;
751 upy = lly[i]+ny;
752
753 if ((y >= loy) && (y < upy) && (x >= lox) && (x < upx)) {
754 posx = x - lox;
755 posy = y - loy;
756 pos = posx+posy*nx;
757
758 if (!isnan(pimg_in[pos]) &&
759 (fabs(pimg_in[pos]) > DBL_ZERO_TOLERANCE) &&
760 (cpl_vector_get(*msk, i) != 0))
761 {
763 cpl_vector_set(val, ovr, pimg_in[pos]));
764 ovr++;
765 }
766 }
767 }
768
769 // get avg, med, sig
770 if (ovr > 2) {
771 if (!strcmp(compute_mode, "MEDIAN")) {
772 med=cpl_vector_get_median(val);
773 } else {
774 med = cpl_vector_get_mean(val);
775 }
776
777 //Initial percentile cut
778 if ((ks == 0) && (pclip < 100) && (pclip > 0)) {
779 med = cpl_vector_get_median(val);
780 cpl_vector_subtract_scalar(val, med);
781 cpl_vector_power(val, 2);
782 cpl_vector_sqrt(val);
783 cpl_vector_sort(val, CPL_SORT_ASCENDING);
784 pk = round(pclip/100.0*(cpl_vector_get_size(val)-1));
785 sig = cpl_vector_get(val, pk) / kappa;
786 } else {
787 if (!strcmp(compute_mode, "MEDIAN")){ //Median: sigma = 1.4826*MAD
788 cpl_vector_subtract_scalar(val, med);
789 cpl_vector_power(val, 2);
790 cpl_vector_sqrt(val);
791 sig = 1.4826 * cpl_vector_get_median(val);
792 } else {
793 sig=cpl_vector_get_stdev(val);
794 }
795 }
796
797 for (int i = 0 ; i < n_frames; i++) {
798 pimg_in = cpl_image_get_data_double(imagesDataShifted[i]);
799
800 lox = llx[i];
801 loy = lly[i];
802 upx = llx[i]+nx;
803 upy = lly[i]+ny;
804
805 // Do k-s clipping at each pixel
806 if ((y >= loy) && (y < upy) && (x >= lox) && (x < upx)) {
807 posx = x - lox;
808 posy = y - loy;
809 pos = posx+posy*nx;
810
811 if (!isnan(pimg_in[pos]) &&
812 (fabs(pimg_in[pos]) > DBL_ZERO_TOLERANCE) &&
813 (cpl_vector_get(*msk,i) != 0))
814 {
815 if(fabs((pimg_in[pos]-med)) > kappa*sig)
816 {
817 // clipping pixel here
818 pimg_in[pos] = NAN;
819 // agudo: added this in, hopefully with correct coordinates
820 cpl_image_reject(imagesDataShifted[i], posx+1, posy+1);
821 cpl_vector_set(*msk, i, 0);
822 nclip++;
823 }
824 }
825 }
826 }
827 }
829 } // end for(ks)
830 } CATCH {
832 ret_err = cpl_error_get_code();
833 }
834
835 return ret_err;
836}
837
838/*----------------------------------------------------------------------------*/
860/*----------------------------------------------------------------------------*/
861cpl_error_code eris_ifu_combine_coadd( const int n_cubes,
862 cpl_image **imgMergedCubeData,
863 cpl_image **imgMergedCubeError,
864 cpl_image *mergedImgDIT,
865 cpl_image **imagesDataShifted,
866 cpl_image **imagesErrorShifted,
867 const double *exptimes,
868 int *llx,
869 int *lly,
870 const char *compute_mode,
871 const int nx_out,
872 const int ny_out)
873{
874 int nx_in = 0,
875 ny_in = 0,
876 posx = 0,
877 posy = 0,
878 ovr = 0; //overlap count
879 double *pimgCubesDataShifted = NULL,
880 *pimgCubesErrorShifted = NULL,
881 *pimgMergedCubeData = NULL,
882 *pimgMergedCubeError = NULL,
883 *pmergedImgDIT = NULL;
884 cpl_vector *val = NULL; // vector to compute median of an output pixel
885 eris_ifu_vector *data_vec = NULL,
886 *err_vec = NULL;
887
888 cpl_ensure_code(n_cubes > 0, CPL_ERROR_ILLEGAL_INPUT);
889 cpl_ensure_code(mergedImgDIT != NULL, CPL_ERROR_NULL_INPUT);
890 cpl_ensure_code(*imagesDataShifted != NULL, CPL_ERROR_NULL_INPUT);
891 cpl_ensure_code(*imagesErrorShifted != NULL, CPL_ERROR_NULL_INPUT);
892 cpl_ensure_code(exptimes != NULL, CPL_ERROR_NULL_INPUT);
893
894 nx_in = cpl_image_get_size_x(imagesDataShifted[0]);
895 ny_in = cpl_image_get_size_y(imagesDataShifted[0]);
896
897 if (
898 (nx_out != cpl_image_get_size_x(mergedImgDIT)) ||
899 (ny_out != cpl_image_get_size_y(mergedImgDIT))
900 )
901 {
902 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
903 return cpl_error_get_code();
904 }
905
906 *imgMergedCubeData = cpl_image_new(nx_out, ny_out, CPL_TYPE_DOUBLE);
907 pimgMergedCubeData = cpl_image_get_data_double(*imgMergedCubeData);
908
909 *imgMergedCubeError = cpl_image_new(nx_out, ny_out, CPL_TYPE_DOUBLE);
910 pimgMergedCubeError = cpl_image_get_data_double(*imgMergedCubeError);
911
912 pmergedImgDIT = cpl_image_get_data_double(mergedImgDIT);
913
914 for (int y = 0; y < ny_out; y++) {
915 for (int x = 0; x < nx_out; x++) {
916 if (!strcmp(compute_mode, "MEDIAN")) {
917 // median
918 val = cpl_vector_new(n_cubes);
919 ovr = 0;
920 }
921
922 data_vec = eris_ifu_vector_new(n_cubes);
923 err_vec = eris_ifu_vector_new(n_cubes);
924
925 for (int i = 0; i < n_cubes; i++) {
926 if ((y >= lly[i]) && (y < lly[i]+ny_in) &&
927 (x >= llx[i]) && (x < llx[i]+nx_in))
928 {
929 pimgCubesDataShifted = cpl_image_get_data_double(imagesDataShifted[i]);
930 pimgCubesErrorShifted = cpl_image_get_data_double(imagesErrorShifted[i]);
931
932 posx = x - llx[i];
933 posy = y - lly[i];
934
935 if (!isnan(pimgCubesDataShifted[posx+posy*nx_in]) &&
936 (fabs(pimgCubesDataShifted[posx+posy*nx_in]) > DBL_ZERO_TOLERANCE) &&
937 (fabs(pmergedImgDIT[x+y*nx_out]) > DBL_ZERO_TOLERANCE))
938 {
939 // valid data value
940 if (!strcmp(compute_mode, "MEDIAN")) {
941 // median
942 cpl_vector_set(val, ovr, pimgCubesDataShifted[posx+posy*nx_in]);
943 ovr++;
944 } else {
945 // mean
946 pimgMergedCubeData[x+y*nx_out] += pimgCubesDataShifted[posx+posy*nx_in] * exptimes[i];
947 }
948 eris_ifu_vector_set(data_vec, i, pimgCubesDataShifted[posx+posy*nx_in]);
949 eris_ifu_vector_set(err_vec, i, pimgCubesErrorShifted[posx+posy*nx_in]);
950 } else {
951 // invalid data value
952 eris_ifu_vector_reject(data_vec, i);
953 eris_ifu_vector_reject(err_vec, i);
954 }
955 } else {
956 // invalid data value
957 eris_ifu_vector_reject(data_vec, i);
958 eris_ifu_vector_reject(err_vec, i);
959 }
960 } // end for(i)
961
962 // calculate error
963 pimgMergedCubeError[x+y*nx_out] = eris_ifu_combine_calc_error(data_vec, err_vec, compute_mode);
964
965 eris_ifu_vector_delete(data_vec); data_vec = NULL;
966 eris_ifu_vector_delete(err_vec); err_vec = NULL;
967
968 if (!strcmp(compute_mode, "MEDIAN")){
969 // median
970 if (ovr > 0) {
971 cpl_vector *tval = cpl_vector_extract(val, 0, ovr-1, 1);
972 pimgMergedCubeData[x+y*nx_out] = cpl_vector_get_median_const(tval);
974 }
976 } else {
977 // mean
978 pimgMergedCubeData[x+y*nx_out] /= pmergedImgDIT[x+y*nx_out];
979 }
980 } // end for x
981 } // end for y
982
983 return cpl_error_get_code();
984}
985
986/*----------------------------------------------------------------------------*/
997/*----------------------------------------------------------------------------*/
998int eris_ifu_combine_calc_contributions(cpl_image **imagesDataShifted,
999 const int n_frames,
1000 const int* llx, const int* lly,
1001 const int x, const int y)
1002{
1003 int n_contributes = 0,
1004 pos = 0,
1005 posx = 0,
1006 posy = 0,
1007 lox = 0,
1008 loy = 0,
1009 upx = 0,
1010 upy = 0;
1011 double *pimg = NULL;
1012 cpl_size nx = 0,
1013 ny = 0;
1014
1015 nx = cpl_image_get_size_x(imagesDataShifted[0]);
1016 ny = cpl_image_get_size_y(imagesDataShifted[0]);
1017
1018 // Count the number of shifted input cubes to be used for
1019 // each overlapping point at x,y
1020 for (int i = 0; i < n_frames; i++) {
1021 pimg = cpl_image_get_data_double(imagesDataShifted[i]);
1022
1023 lox = llx[i];
1024 loy = lly[i];
1025 upx = llx[i] + nx;
1026 upy = lly[i] + ny;
1027
1028 if ((y >= loy) && (y < upy) && (x >= lox) && (x < upx)) {
1029 posx = x - lox;
1030 posy = y - loy;
1031 pos = posx+posy*nx;
1032
1033 if (!isnan(pimg[pos]) && (fabs(pimg[pos]) > DBL_ZERO_TOLERANCE)) {
1034 n_contributes++;
1035 }
1036 }
1037 }
1038
1039 return n_contributes;
1040}
1041
1042/*----------------------------------------------------------------------------*/
1051/*----------------------------------------------------------------------------*/
1052cpl_error_code eris_ifu_combine_subtract_background(cpl_image *img,
1053 bool *warn)
1054{
1055 double local_median = 0.;
1056 cpl_error_code err = CPL_ERROR_NONE;
1057
1058 cpl_ensure_code(img != NULL, CPL_ERROR_NULL_INPUT);
1059
1060 TRY {
1062 cpl_image_reject_value(img, CPL_VALUE_NOTFINITE));
1063
1064 local_median = cpl_image_get_median(img);
1065 if (cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) {
1066 local_median = NAN;
1067 RECOVER();
1068 }
1070
1071 if (!isnan(local_median)) {
1073 cpl_image_subtract_scalar(img, local_median));
1074 *warn = FALSE;
1075 } else {
1076 *warn = TRUE;
1077 }
1078 } CATCH {
1079 CATCH_MSGS();
1080 err = cpl_error_get_code();
1081 }
1082 return err;
1083}
1084
1085/*----------------------------------------------------------------------------*/
1098/*----------------------------------------------------------------------------*/
1099void eris_ifu_combine_get_xy_min_max(const int nframes,
1100 const float *offsetx, const float *offsety,
1101 float *min_offx, float *max_offx,
1102 float *min_offy, float *max_offy)
1103{
1104 float offx = 0.,
1105 offy = 0.;
1106
1107 for (int n = 0; n < nframes; n++) {
1108 offx = offsetx[n];
1109 offy = offsety[n];
1110 if (n == 0) {
1111 *min_offx = offx;
1112 *min_offy = offy;
1113 *max_offx = offx;
1114 *max_offy = offy;
1115 } else {
1116 if(offx > *max_offx)
1117 *max_offx=offx;
1118 if(offy > *max_offy)
1119 *max_offy=offy;
1120 if(offx < *min_offx)
1121 *min_offx=offx;
1122 if(offy < *min_offy)
1123 *min_offy=offy;
1124 }
1125 }
1126}
1127
1128/*----------------------------------------------------------------------------*/
1136/*----------------------------------------------------------------------------*/
1138{
1139 int k = x;
1140
1141 if (x >= 0.) {
1142 if ((x - (double)k) <= 0.5) {
1143 return k;
1144 } else {
1145 return k + 1;
1146 }
1147 } else {
1148 if ((x - (double)k) <= -0.5) {
1149 return k - 1;
1150 } else {
1151 return k;
1152 }
1153 }
1154}
1155
1156/*----------------------------------------------------------------------------*/
1186/*----------------------------------------------------------------------------*/
1187cpl_image* eris_ifu_combine_shift_image(const cpl_image *img_in,
1188 const double shift_x,
1189 const double shift_y,
1190 const double *kernel)
1191{
1192 cpl_image *img_shifted = NULL;
1193 cpl_size nx = 0,
1194 ny = 0;
1195 int samples = KERNEL_SAMPLES,
1196 mid = samples / 2,
1197 px = 0,
1198 py = 0,
1199 pos = 0,
1200 tabx = 0,
1201 taby = 0;
1202 double norm = 0.,
1203 value = 0.,
1204 fx = 0.,
1205 rx = 0.,
1206 fy = 0.,
1207 ry = 0.,
1208 *first_pass = NULL,
1209 *pimg_shifted = NULL;
1210 const double *pimg_in = NULL;
1211
1212 cpl_ensure(img_in != NULL, CPL_ERROR_NULL_INPUT, NULL);
1213 cpl_ensure(kernel != NULL, CPL_ERROR_NULL_INPUT, NULL);
1214
1215 /* Shifting by a zero offset returns a copy of the input image */
1216 if ((fabs(shift_x) < 1e-2) && (fabs(shift_y) < 1e-2))
1217 return cpl_image_duplicate(img_in);
1218
1219 nx = cpl_image_get_size_x(img_in);
1220 ny = cpl_image_get_size_y(img_in);
1221
1222 pimg_in = cpl_image_get_data_double_const(img_in);
1223 if (pimg_in != NULL) {
1224 first_pass = cpl_calloc(nx, ny*sizeof(double));
1225 img_shifted = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
1226 pimg_shifted = cpl_image_get_data_double(img_shifted);
1227 for (int y = 0; y < (int)ny; y++) {
1228 for (int x = 1; x < (int)nx-2; x++) {
1229 fx = (double)x - shift_x;
1230 px = (int)fx;
1231 rx = fx - (double)px;
1232 pos = px + y * (int)nx;
1233
1234 if ((px>1) && (px<(nx-3))) {
1235 tabx = (int)(fabs(mid * rx));
1236
1237 // Sum up over 4 closest pixel values,
1238 // weighted by interpolation kernel values
1239 value = pimg_in[pos-1] * kernel[mid+tabx] +
1240 pimg_in[pos] * kernel[tabx] +
1241 pimg_in[pos+1] * kernel[mid-tabx] +
1242 pimg_in[pos+2] * kernel[samples-tabx-1];
1243
1244 // Also sum up interpolation kernel coefficients
1245 // for further normalization
1246 norm = kernel[mid+tabx] +
1247 kernel[tabx] +
1248 kernel[mid-tabx] +
1249 kernel[samples-tabx-1];
1250
1251 if (fabs(norm) > 1e-4) {
1252 value /= norm;
1253 }
1254 } else {
1255 value = 0.;
1256 }
1257 // There may be a problem of rounding here if pixelvalue
1258 // has not enough bits to sustain the accuracy.
1259 first_pass[x+y*nx] = value;
1260 }
1261 }
1262
1263 for (int x = 0; x < (int)nx; x++) {
1264 for (int y = 1; y < (int)ny-3; y++) {
1265 fy = (double)y - shift_y;
1266 py = (int)fy ;
1267 ry = fy - (double)py ;
1268 pos = x + py * nx ;
1269
1270 if ((py > 1) && (py < ((int)ny-2))) {
1271 taby = (int)(fabs((double)mid * ry));
1272
1273 // Sum up over 4 closest pixel values,
1274 // weighted by interpolation kernel values
1275 value = first_pass[pos-nx] * kernel[mid+taby] +
1276 first_pass[pos] * kernel[taby] +
1277 first_pass[pos+nx] * kernel[mid-taby] +
1278 first_pass[pos+2*nx]*kernel[samples-taby-1];
1279
1280 // Also sum up interpolation kernel coefficients
1281 // for further normalization
1282 norm = kernel[mid+taby] +
1283 kernel[taby] +
1284 kernel[mid-taby] +
1285 kernel[samples-taby-1];
1286
1287 if (fabs(norm) > 1e-4) {
1288 value /= norm;
1289 }
1290 } else {
1291 value = 0.0;
1292 }
1293 pimg_shifted[x+y*nx] = value;
1294 }
1295 }
1296 } else {
1297 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT);
1298 cpl_msg_error(cpl_func, "Cannot get a data from an image");
1299 return NULL;
1300 }
1301
1302 // free memory
1303 cpl_free(first_pass); first_pass = NULL;
1304
1305 return img_shifted;
1306}
1307
1308/*----------------------------------------------------------------------------*/
1313/*----------------------------------------------------------------------------*/
1315{
1316 cpl_size nx = 0,
1317 ny = 0;
1318 double *pimg = NULL;
1319
1320 if (img != NULL) {
1321 pimg = cpl_image_get_data_double(img);
1322
1323 nx = cpl_image_get_size_x(img);
1324 ny = cpl_image_get_size_y(img);
1325
1326 for (int i = 0 ; i < nx*ny; i++) {
1327 if (fabs(pimg[i]) < DBL_ZERO_TOLERANCE) {
1328 pimg[i] = NAN;
1329 }
1330 }
1331 }
1332}
1333
1334/*----------------------------------------------------------------------------*/
1342/*----------------------------------------------------------------------------*/
1343double eris_ifu_combine_calc_error(eris_ifu_vector *data_vec,
1344 eris_ifu_vector *err_vec,
1345 const char *compute_mode)
1346{
1347 double std_err = 0.,
1348 std_dev = 0.;
1349 int vec_size = 0;
1350 cpl_ensure_code(data_vec != NULL, CPL_ERROR_NULL_INPUT);
1351 cpl_ensure_code(err_vec != NULL, CPL_ERROR_NULL_INPUT);
1352
1353 vec_size = eris_ifu_vector_count_non_rejected(data_vec);
1354
1355 if (vec_size > 2) {
1356 // recalculate error from input data (regardless if there is
1357 // input error or not)
1358
1359 if (!strcmp(compute_mode, "MEDIAN")) {
1360 std_dev = eris_ifu_vector_get_stdev_median(data_vec);
1361 } else {
1362 std_dev = eris_ifu_vector_get_stdev(data_vec);
1363 }
1364 std_err = std_dev / sqrt(vec_size);
1365 } else {
1366 vec_size = eris_ifu_vector_count_non_rejected(err_vec);
1367 /* error propagation from input error*/
1368 if (vec_size == 1) {
1369 int i = 0;
1370 while (eris_ifu_vector_is_rejected(err_vec, i)) {
1371 i++;
1372 }
1373 std_err = eris_ifu_vector_get(err_vec, i);
1374 } else if (vec_size == 2) {
1375 double tmp_dbl = 0.;
1376 int i = 0;
1377 while (eris_ifu_vector_is_rejected(err_vec, i)) {
1378 i++;
1379 }
1380
1381 int j = i+1;
1382 while (eris_ifu_vector_is_rejected(err_vec, j)) {
1383 j++;
1384 }
1385
1386 tmp_dbl = sqrt(pow(eris_ifu_vector_get(err_vec, i), 2) +
1387 pow(eris_ifu_vector_get(err_vec, j), 2));
1388
1389 std_dev = tmp_dbl / 2;
1390 std_err = std_dev / sqrt(2);
1391 }
1392 }
1393 return std_err;
1394}
1395
1396/* --- simple shifting from KMOS pipeline --- */
1397
1398enum boundary_mode {
1399 NATURAL,
1400 EXACT,
1401 ESTIMATED1,
1402 ESTIMATED2
1403};
1404
1405double** matrix(int nrow, int ncol) {
1406 double **matrix = (double**)cpl_malloc((size_t)((nrow)*sizeof(double*)));
1407
1408 for(int i = 0; i < nrow; i++) {
1409 matrix[i] = (double *) cpl_malloc((size_t)((ncol)*sizeof(double)));
1410 }
1411
1412 return matrix;
1413}
1414
1415void free_matrix(double **matrix, int nrow) {
1416 for(int i = 0; i < nrow; i++) {
1417 cpl_free(matrix[i]); matrix[i] = NULL;
1418 }
1419 cpl_free(matrix); matrix = NULL;
1420}
1421
1422/*----------------------------------------------------------------------------*/
1435/*----------------------------------------------------------------------------*/
1436cpl_error_code eris_ifu_reject_nan(cpl_image *img)
1437{
1438 cpl_error_code err = CPL_ERROR_NONE;
1439 int nx = 0,
1440 ny = 0,
1441 is_rej = 0;
1442 float tmp = 0.0;
1443
1444 cpl_ensure_code(img != NULL, CPL_ERROR_NULL_INPUT);
1445
1446 TRY {
1447
1448 nx = cpl_image_get_size_x(img);
1449 ny = cpl_image_get_size_y(img);
1451
1452 for (int ix = 1; ix <= nx; ix++) {
1453 for (int iy = 1; iy <= ny; iy++) {
1454 tmp = cpl_image_get(img, ix, iy, &is_rej);
1456
1457 if (!is_rej && isnan(tmp)) {
1459 cpl_image_reject(img, ix, iy));
1460 }
1461 }
1462 }
1463 } CATCH {
1464 err = cpl_error_get_code();
1465 }
1466
1467 return err;
1468}
1469
1470/*----------------------------------------------------------------------------*/
1519/*----------------------------------------------------------------------------*/
1520cpl_image* eris_ifu_combine_shift_image_kmos(const cpl_image *img_in,
1521 double xshift,
1522 double yshift,
1523 const char *method,
1524 const enum extrapolationType extrapolation)
1525{
1526 const double *pimg_in = NULL;
1527 double **array_in = NULL,
1528 **array_out = NULL,
1529 *pimg_out = NULL;
1530 cpl_image *img_out = NULL;
1531 int xdim = 0,
1532 ydim = 0,
1533 xdim_new = 0,
1534 ydim_new = 0;
1535
1536 cpl_ensure(img_in != NULL, CPL_ERROR_NULL_INPUT, NULL);
1537 cpl_ensure((extrapolation == NONE_NANS) ||
1538 (extrapolation == NONE_CLIPPING)/* ||
1539 (extrapolation == BCS_NATURAL) ||
1540 (extrapolation == BCS_ESTIMATED)*/, CPL_ERROR_ILLEGAL_INPUT, NULL);
1541
1542 TRY {
1543 if ((xshift == 0.0) && (yshift == 0.0)) {
1544 // duplicate image
1546 img_out = cpl_image_duplicate(img_in));
1547 } else {
1548 xdim = cpl_image_get_size_x(img_in);
1549 ydim = cpl_image_get_size_y(img_in);
1550
1551 pimg_in = cpl_image_get_data_double_const(img_in);
1552
1553 array_in = matrix(xdim, ydim);
1554 for (int j = 0; j < ydim ; j++) {
1555 for (int i = 0; i < xdim ; i++) {
1556 if (isnan(pimg_in[i + j*xdim]))
1557 /* agudo: fix because of NaN-input */
1558 array_in[i][j] = 0;
1559 else
1560 array_in[i][j] = pimg_in[i + j*xdim];
1561 }
1562 }
1563
1564 /*if (strcmp(method, "BCS") == 0) {
1565 xdim_new = xdim;
1566 ydim_new = ydim;
1567 xstart_new = xshift;
1568 ystart_new = yshift;
1569
1570 enum boundary_mode boundaryMode = NATURAL;
1571 if (extrapolation == BCS_ESTIMATED) {
1572 boundaryMode = ESTIMATED2;
1573 }
1574
1575 array_out = bicubicspline_reg_reg(
1576 xdim, 0.0, 1.0,
1577 ydim, 0.0, 1.0,
1578 array_in,
1579 xdim_new, xstart_new, 1.0,
1580 ydim_new, ystart_new, 1.0,
1581 boundaryMode);
1582 } else */if (strcmp(method, "NN") == 0) {
1583 if (fabs(xshift) > 1.0 || fabs(yshift) > 1.0) {
1584 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
1585 "Neither xshift nor yshift are allowed to "
1586 "be greater than 1 pixel for NN");
1587 }
1588 int xoffset = 0,
1589 yoffset = 0;
1590 if (xshift > 0.5) {
1591 xoffset = 1;
1592 } else if (xshift < -0.5) {
1593 xoffset = -1;
1594 } else {
1595 xoffset = 0;
1596 }
1597 if (yshift > 0.5) {
1598 yoffset = 1;
1599 } else if (yshift < -0.5) {
1600 yoffset = -1;
1601 } else {
1602 yoffset = 0;
1603 }
1604 array_out = matrix(xdim,ydim);
1605 for (int j = 0; j < ydim; j++) {
1606 for (int i = 0; i < xdim; i++) {
1607 int xix = i+xoffset,
1608 yix = j+yoffset;
1609 if (xix < 0 || xix >= xdim || yix < 0 || yix >= ydim) {
1610 array_out[i][j] = NAN;
1611 } else {
1612 array_out[i][j] = array_in[i+xoffset][j+yoffset];
1613 }
1614 }
1615 }
1616 } else {
1617 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
1618 "Unknown value for interpolation method");
1619 }
1620 free_matrix(array_in, xdim);
1621
1622 switch (extrapolation) {
1623// case BCS_NATURAL:
1624// case BCS_ESTIMATED:
1625// BRK_IF_NULL(
1626// image_out = cpl_malloc(xdim_new * ydim_new * sizeof(double)));
1627// for (int j = 0; j < ydim_new; j++) {
1628// for (int i = 0; i < xdim_new; i++) {
1629// image_out[i+j*xdim_new] = array_out[i][j];
1630// }
1631// }
1632// break;
1633 case NONE_CLIPPING:
1634 xdim_new = xdim - lrintf(ceill(fabsl(xshift)));
1635 ydim_new = xdim - lrintf(ceill(fabsl(yshift)));
1637 pimg_out = cpl_malloc(xdim_new * ydim_new * sizeof(double)));
1638 int xmin = - floorl(xshift);
1639 if (xmin < 0)
1640 xmin = 0;
1641 int xmax = xdim - ceill(xshift);
1642 if (xmax > xdim)
1643 xmax = xdim;
1644 int ymin = - floorl(yshift);
1645 if (ymin < 0)
1646 ymin = 0;
1647 int ymax = ydim - ceill(yshift);
1648 if (ymax > ydim)
1649 ymax = ydim;
1650 for (int j = ymin; j < ymax; j++) {
1651 for (int i = xmin; i < xmax; i++) {
1652 pimg_out[(i - xmin) + (j - ymin) * xdim_new] = array_out[i][j];
1653 }
1654 }
1655 break;
1656 case NONE_NANS:
1657 xdim_new = xdim;
1658 ydim_new = ydim;
1660 pimg_out = cpl_malloc(xdim * ydim * sizeof(double)));
1661 float xxmin = 0 - xshift;
1662 float xxmax = xdim - 1 - xshift;
1663 float yymin = 0 - yshift;
1664 float yymax = ydim - 1 - yshift;
1665 for (int j = 0; j < ydim; j++) {
1666 for (int i = 0; i < xdim; i++) {
1667 if ((i < xxmin ) || (i > xxmax) ||
1668 (j < yymin ) || (j > yymax))
1669 {
1670 pimg_out[i+j*xdim] = NAN;
1671 } else {
1672 pimg_out[i+j*xdim] = array_out[i][j];
1673 }
1674 }
1675 }
1676 break;
1677 default:
1678 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
1679 "Unknown value for extrapolation type");
1680 }
1681
1682 free_matrix(array_out, xdim);
1683 img_out = cpl_image_wrap_double(xdim_new, ydim_new, pimg_out);
1684
1685 /* reject NaN values here */
1687 eris_ifu_reject_nan(img_out));
1688 }
1689 }
1690 CATCH
1691 {
1692 CATCH_MSGS();
1693 eris_ifu_free_image(&img_out);
1694 }
1695
1696 return img_out;
1697}
1698
1699/*----------------------------------------------------------------------------*/
1710/*----------------------------------------------------------------------------*/
1711cpl_error_code eris_ifu_combine_read_image_planes(const cpl_frameset *frameset,
1712 cpl_image **imagesData,
1713 cpl_image **imagesError,
1714 int z,
1715 int edge_trim,
1716 bool subtract_background)
1717{
1718 cpl_size nframes = 0,
1719 llx = 0,
1720 lly = 0,
1721 urx = 0,
1722 ury = 0;
1723 cpl_error_code err = CPL_ERROR_NONE;
1724 const cpl_frame *frame = NULL;
1725 cpl_mask *tmp_mask = NULL;
1726 cpl_image *cube_qual_tmp = NULL;
1727 cpl_propertylist *plist = NULL;
1728 const char *name = NULL;
1729 int tmp_size_x = 0,
1730 tmp_size_y = 0;
1731 bool warn = FALSE,
1732 warned = FALSE;
1733
1734 cpl_ensure_code(frameset != NULL, CPL_ERROR_NULL_INPUT);
1735
1736 TRY {
1737 nframes = cpl_frameset_get_size(frameset);
1738
1739 /* Read in cubes */
1740 for (cpl_size n = 0; n < nframes; n++) {
1742 frame = cpl_frameset_get_position_const(frameset, n));
1744 name = cpl_frame_get_filename(frame));
1745 if (edge_trim > 0) {
1747 plist = cpl_propertylist_load(name, 1));
1748 tmp_size_x = eris_pfits_get_naxis1(plist);
1749 tmp_size_y = eris_pfits_get_naxis2(plist);
1751
1753 llx = 1 + edge_trim;
1754 lly = 1 + edge_trim;
1755 urx = tmp_size_x - edge_trim;
1756 ury = tmp_size_y - edge_trim;
1757
1759 imagesData[n] = cpl_image_load_window(name, CPL_TYPE_DOUBLE, z, 1, llx, lly, urx, ury));
1761 imagesError[n] = cpl_image_load_window(name, CPL_TYPE_DOUBLE, z, 2, llx, lly, urx, ury));
1763 cube_qual_tmp = cpl_image_load_window(name, CPL_TYPE_DOUBLE, z, 3, llx, lly, urx, ury));
1764 }
1765 else{
1767 imagesData[n] = cpl_image_load(name, CPL_TYPE_DOUBLE, z, 1));
1769 imagesError[n] = cpl_image_load(name, CPL_TYPE_DOUBLE, z, 2));
1771 cube_qual_tmp = cpl_image_load(name, CPL_TYPE_DOUBLE, z, 3));
1772 }
1773
1774 /* Reject mask */
1776 tmp_mask = cpl_mask_threshold_image_create(cube_qual_tmp, 0, INT_MAX));
1778 cpl_image_reject_from_mask(imagesData[n], tmp_mask));
1780 cpl_image_reject_from_mask(imagesError[n], tmp_mask));
1781 eris_ifu_free_mask(&tmp_mask);
1782 eris_ifu_free_image(&cube_qual_tmp);
1783
1784 if (subtract_background) {
1786 eris_ifu_combine_subtract_background(imagesData[n], &warn));
1787 if (warn && !warned) {
1788 warned = TRUE;
1789 cpl_msg_warning(cpl_func, " local_median is NAN in %dth plane", z);
1790 }
1791 }
1793 } // end for nframes
1794 } CATCH {
1795 CATCH_MSGS();
1796 err = cpl_error_get_code();
1797 }
1798 return err;
1799}
1800
1801/*----------------------------------------------------------------------------*/
1811/*----------------------------------------------------------------------------*/
1812int eris_ifu_combine_min_cube_size(const cpl_frameset *fs) {
1813 int naxis3 = 0,
1814 naxis3_tmp = 0;
1815 double crval3 = 0.,
1816 crpix3 = 0,
1817 cd3_3 = 0.,
1818 crval3_tmp = 0.,
1819 crpix3_tmp = 0.,
1820 cd3_3_tmp = 0.;
1821 const char *name = NULL;
1822 const cpl_frame *fr = NULL;
1823 cpl_propertylist *pl = NULL;
1824
1825 cpl_ensure(fs != NULL, CPL_ERROR_NULL_INPUT, -1);
1826
1827 TRY {
1828 // initialize with 1st frame
1829 cpl_frameset_iterator *iter = NULL;
1831 iter = cpl_frameset_iterator_new(fs));
1832 fr = cpl_frameset_iterator_get(iter);
1835 name = cpl_frame_get_filename(fr));
1836
1837 // load header of data extension
1839 pl = cpl_propertylist_load(name, 1));
1840 naxis3 = cpl_propertylist_get_int( pl, NAXIS3);
1841 crpix3 = cpl_propertylist_get_double(pl, CRPIX3);
1842 crval3 = cpl_propertylist_get_double(pl, CRVAL3);
1843 cd3_3 = cpl_propertylist_get_double(pl, CD3_3);
1846
1848 cpl_frameset_iterator_advance(iter, 1));
1849 fr = cpl_frameset_iterator_get(iter);
1851
1852 while (fr != NULL) {
1854 name = cpl_frame_get_filename(fr));
1855 // load header of data extension
1857 pl = cpl_propertylist_load(name, 1));
1858
1859 naxis3_tmp = cpl_propertylist_get_int( pl, NAXIS3);
1860 crpix3_tmp = cpl_propertylist_get_double(pl, CRPIX3);
1861 crval3_tmp = cpl_propertylist_get_double(pl, CRVAL3);
1862 cd3_3_tmp = cpl_propertylist_get_double(pl, CD3_3);
1865
1866 if ((fabs(crpix3 - crpix3_tmp) > DBL_ZERO_TOLERANCE) ||
1867 (fabs(crval3 - crval3_tmp) > DBL_ZERO_TOLERANCE) ||
1868 (fabs(cd3_3 - cd3_3_tmp) > DBL_ZERO_TOLERANCE))
1869 {
1870 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
1871 "WCS not matching for all frames!");
1872 }
1873
1874 if (naxis3_tmp < naxis3) {
1875 naxis3 = naxis3_tmp;
1876 }
1877
1879 cpl_frameset_iterator_advance(iter, 1));
1880 fr = cpl_frameset_iterator_get(iter);
1882 } // end while
1883 } CATCH {
1884 CATCH_MSGS();
1885 naxis3 = -1;
1886 }
1887 return naxis3;
1888}
1889
void eris_ifu_combine_get_xy_min_max(const int nframes, const float *offsetx, const float *offsety, float *min_offx, float *max_offx, float *min_offy, float *max_offy)
eris_ifu_combine_get_xy_min_max
void eris_ifu_combine_convert_0_to_NaN_img(cpl_image *img)
eris_ifu_combine_convert_0_to_NaN_img
int eris_ifu_combine_nearest_int(const double x)
Determine the nearest integer to a specified real value.
cpl_error_code eris_ifu_combine_build_mask_cube(cpl_image **imagesDataShifted, cpl_image **mergedImgDIT, const int *llx, const int *lly, const double *exptimes, int n_cubes, cpl_size nx_out, cpl_size ny_out)
Build the mask data cube.
int eris_ifu_combine_min_cube_size(const cpl_frameset *fs)
eris_ifu_combine_min_cube_size
double eris_ifu_combine_calc_error(eris_ifu_vector *data_vec, eris_ifu_vector *err_vec, const char *compute_mode)
Calculate error for coadded pixel.
cpl_error_code eris_ifu_reject_nan(cpl_image *img)
Rejects NaN values in the internal badpixelmask.
cpl_error_code eris_ifu_combine_read_image_planes(const cpl_frameset *frameset, cpl_image **imagesData, cpl_image **imagesError, int z, int edge_trim, bool subtract_background)
Read image planes from a frameset.
cpl_error_code eris_ifu_combine_coadd_ks_clip_internal(cpl_image **imagesDataShifted, const int n_frames, const int n_contributions, const int x, const int y, int *llx, int *lly, const double kappa, cpl_vector **msk, const char *compute_mode, const int pclip)
Internal routine for kappa-sigma clipping at a single pixel.
cpl_image * eris_ifu_combine_shift_image_kmos(const cpl_image *img_in, double xshift, double yshift, const char *method, const enum extrapolationType extrapolation)
Shifts each image of an image cube.
cpl_image * eris_ifu_combine_shift_image(const cpl_image *img_in, const double shift_x, const double shift_y, const double *kernel)
Shift an image by a given (non-integer) 2d offset.
cpl_error_code eris_ifu_combine_divide_DIT(cpl_imagelist **cubesData, const int n_cubes, const double *exptimes)
Divide each cube in a list by its exposure time.
int eris_ifu_combine_calc_contributions(cpl_image **imagesDataShifted, const int n_frames, const int *llx, const int *lly, const int x, const int y)
Calculate the number of frames contributing to a pixel.
cpl_error_code eris_ifu_combine_coadd(const int n_cubes, cpl_image **imgMergedCubeData, cpl_image **imgMergedCubeError, cpl_image *mergedImgDIT, cpl_image **imagesDataShifted, cpl_image **imagesErrorShifted, const double *exptimes, int *llx, int *lly, const char *compute_mode, const int nx_out, const int ny_out)
Compute weighted mean or median of shifted images.
cpl_error_code eris_ifu_combine_coadd_ks_clip(const int n_frames, const double kappa, int *llx, int *lly, const double *exptimes, cpl_image **imgMergedCubeData, cpl_image **imgMergedCubeError, cpl_image *mergedImgDIT, cpl_image **imagesDataShifted, cpl_image **imagesErrorShifted, const char *compute_mode, const int pclip, const int nx_out, const int ny_out)
Coadd images with kappa-sigma clipping.
cpl_error_code eris_ifu_combine_subtract_background(cpl_image *img, bool *warn)
Subtract spatial median from an image.
cpl_error_code eris_ifu_combine_jittered_images(cpl_image **imagesData, cpl_image **imagesError, int nx_out, int ny_out, cpl_image **mergedImageData, cpl_image **mergedImageError, cpl_image **mergedImageDIT, int n_cubes, const float *offsetx, const float *offsety, const double *exptimes, const double kappa, const char *compute_mode, const int pclip)
Combine jittered images into a merged image with optional kappa-sigma clipping.
cpl_error_code eris_ifu_combine_auto_size_cube(const float *offsetx, const float *offsety, const int nframes, float *ref_offx, float *ref_offy, int *size_x, int *size_y)
Computes size of coadded cube.
cpl_error_code eris_ifu_combine_build_mask(cpl_imagelist **cubesDataShifted, cpl_image *mergedImgDIT, const int n_cubes, const int *llx, const int *lly, const double *exptimes)
Build the mask data image.
#define BRK_IF_ERROR(function)
If function is or returns an error != CPL_ERROR_NONE, then the try-block is exited.
#define RECOVER(void)
Recover the error state which was present during TRY (at the beginning of the try-block).
#define CHECK_ERROR_STATE(void)
Check the CPL error state, and exit the try-block if not CPL_ERROR_NONE.
#define BRK_WITH_ERROR_MSG(code,...)
Set a new CPL error, and exit the try-block.
#define TRY
Beginning of a TRY-block.
#define CATCH
End of a TRY-block, beginning of a CATCH-block.
#define BRK_IF_NULL(function)
If function is or returns a NULL pointer, then the try-block is exited.
#define CATCH_MSGS()
Displays an error message stack.
void eris_ifu_free_propertylist(cpl_propertylist **item)
Free memory and set pointer to null.
void eris_ifu_free_vector(cpl_vector **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.
double eris_ifu_vector_get_stdev_median(const eris_ifu_vector *ev)
Compute the bias-corrected standard deviation using median instead of mean.
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_count_non_rejected(const eris_ifu_vector *ev)
Count the number of non-rejected elements in a eris_ifu_vector.
int eris_ifu_vector_is_rejected(const eris_ifu_vector *ev, int n)
Test if a value is good or bad.
cpl_error_code eris_ifu_vector_set(eris_ifu_vector *ev, int pos, double val)
Set an element of the eris_ifu_vector.
double eris_ifu_vector_get_stdev(const eris_ifu_vector *ev)
Compute the bias-corrected standard deviation of a vector's elements.
double eris_ifu_vector_get(const eris_ifu_vector *ev, int pos)
Get an element of the eris_ifu_vector.
cpl_error_code eris_ifu_vector_reject(eris_ifu_vector *ev, int n)
Set a value as rejected in a eris_ifu_vector.
void eris_ifu_vector_delete(eris_ifu_vector *ev)
Delete a eris_ifu_vector.
int eris_pfits_get_naxis2(const cpl_propertylist *plist)
find out the character string associated to the NAXIS2 keyword
Definition: eris_pfits.c:168
int eris_pfits_get_naxis1(const cpl_propertylist *plist)
find out the character string associated to the NAXIS1 keyword
Definition: eris_pfits.c:155