ERIS Pipeline Reference Manual 1.8.15
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 nx_in = cpl_image_get_size_x(imagesDataShifted[0]);
889 ny_in = cpl_image_get_size_y(imagesDataShifted[0]);
890
891 if (
892 (nx_out != cpl_image_get_size_x(mergedImgDIT)) ||
893 (ny_out != cpl_image_get_size_y(mergedImgDIT))
894 )
895 {
896 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
897 return cpl_error_get_code();
898 }
899
900 *imgMergedCubeData = cpl_image_new(nx_out, ny_out, CPL_TYPE_DOUBLE);
901 pimgMergedCubeData = cpl_image_get_data_double(*imgMergedCubeData);
902
903 *imgMergedCubeError = cpl_image_new(nx_out, ny_out, CPL_TYPE_DOUBLE);
904 pimgMergedCubeError = cpl_image_get_data_double(*imgMergedCubeError);
905
906 pmergedImgDIT = cpl_image_get_data_double(mergedImgDIT);
907
908 for (int y = 0; y < ny_out; y++) {
909 for (int x = 0; x < nx_out; x++) {
910 if (!strcmp(compute_mode, "MEDIAN")) {
911 // median
912 val = cpl_vector_new(n_cubes);
913 ovr = 0;
914 }
915
916 data_vec = eris_ifu_vector_new(n_cubes);
917 err_vec = eris_ifu_vector_new(n_cubes);
918
919 for (int i = 0; i < n_cubes; i++) {
920 if ((y >= lly[i]) && (y < lly[i]+ny_in) &&
921 (x >= llx[i]) && (x < llx[i]+nx_in))
922 {
923 pimgCubesDataShifted = cpl_image_get_data_double(imagesDataShifted[i]);
924 pimgCubesErrorShifted = cpl_image_get_data_double(imagesErrorShifted[i]);
925
926 posx = x - llx[i];
927 posy = y - lly[i];
928
929 if (!isnan(pimgCubesDataShifted[posx+posy*nx_in]) &&
930 (fabs(pimgCubesDataShifted[posx+posy*nx_in]) > DBL_ZERO_TOLERANCE) &&
931 (fabs(pmergedImgDIT[x+y*nx_out]) > DBL_ZERO_TOLERANCE))
932 {
933 // valid data value
934 if (!strcmp(compute_mode, "MEDIAN")) {
935 // median
936 cpl_vector_set(val, ovr, pimgCubesDataShifted[posx+posy*nx_in]);
937 ovr++;
938 } else {
939 // mean
940 pimgMergedCubeData[x+y*nx_out] += pimgCubesDataShifted[posx+posy*nx_in] * exptimes[i];
941 }
942 eris_ifu_vector_set(data_vec, i, pimgCubesDataShifted[posx+posy*nx_in]);
943 eris_ifu_vector_set(err_vec, i, pimgCubesErrorShifted[posx+posy*nx_in]);
944 } else {
945 // invalid data value
946 eris_ifu_vector_reject(data_vec, i);
947 eris_ifu_vector_reject(err_vec, i);
948 }
949 } else {
950 // invalid data value
951 eris_ifu_vector_reject(data_vec, i);
952 eris_ifu_vector_reject(err_vec, i);
953 }
954 } // end for(i)
955
956 // calculate error
957 pimgMergedCubeError[x+y*nx_out] = eris_ifu_combine_calc_error(data_vec, err_vec, compute_mode);
958
959 eris_ifu_vector_delete(data_vec); data_vec = NULL;
960 eris_ifu_vector_delete(err_vec); err_vec = NULL;
961
962 if (!strcmp(compute_mode, "MEDIAN")){
963 // median
964 if (ovr > 0) {
965 cpl_vector *tval = cpl_vector_extract(val, 0, ovr-1, 1);
966 pimgMergedCubeData[x+y*nx_out] = cpl_vector_get_median_const(tval);
968 }
970 } else {
971 // mean
972 pimgMergedCubeData[x+y*nx_out] /= pmergedImgDIT[x+y*nx_out];
973 }
974 } // end for x
975 } // end for y
976
977 return cpl_error_get_code();
978}
979
980/*----------------------------------------------------------------------------*/
991/*----------------------------------------------------------------------------*/
992int eris_ifu_combine_calc_contributions(cpl_image **imagesDataShifted,
993 const int n_frames,
994 const int* llx, const int* lly,
995 const int x, const int y)
996{
997 int n_contributes = 0,
998 pos = 0,
999 posx = 0,
1000 posy = 0,
1001 lox = 0,
1002 loy = 0,
1003 upx = 0,
1004 upy = 0;
1005 double *pimg = NULL;
1006 cpl_size nx = 0,
1007 ny = 0;
1008
1009 nx = cpl_image_get_size_x(imagesDataShifted[0]);
1010 ny = cpl_image_get_size_y(imagesDataShifted[0]);
1011
1012 // Count the number of shifted input cubes to be used for
1013 // each overlapping point at x,y
1014 for (int i = 0; i < n_frames; i++) {
1015 pimg = cpl_image_get_data_double(imagesDataShifted[i]);
1016
1017 lox = llx[i];
1018 loy = lly[i];
1019 upx = llx[i] + nx;
1020 upy = lly[i] + ny;
1021
1022 if ((y >= loy) && (y < upy) && (x >= lox) && (x < upx)) {
1023 posx = x - lox;
1024 posy = y - loy;
1025 pos = posx+posy*nx;
1026
1027 if (!isnan(pimg[pos]) && (fabs(pimg[pos]) > DBL_ZERO_TOLERANCE)) {
1028 n_contributes++;
1029 }
1030 }
1031 }
1032
1033 return n_contributes;
1034}
1035
1036/*----------------------------------------------------------------------------*/
1045/*----------------------------------------------------------------------------*/
1046cpl_error_code eris_ifu_combine_subtract_background(cpl_image *img,
1047 bool *warn)
1048{
1049 double local_median = 0.;
1050 cpl_error_code err = CPL_ERROR_NONE;
1051
1052 cpl_ensure_code(img != NULL, CPL_ERROR_NULL_INPUT);
1053
1054 TRY {
1056 cpl_image_reject_value(img, CPL_VALUE_NOTFINITE));
1057
1058 local_median = cpl_image_get_median(img);
1059 if (cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) {
1060 local_median = NAN;
1061 RECOVER();
1062 }
1064
1065 if (!isnan(local_median)) {
1067 cpl_image_subtract_scalar(img, local_median));
1068 *warn = FALSE;
1069 } else {
1070 *warn = TRUE;
1071 }
1072 } CATCH {
1073 CATCH_MSGS();
1074 err = cpl_error_get_code();
1075 }
1076 return err;
1077}
1078
1079/*----------------------------------------------------------------------------*/
1092/*----------------------------------------------------------------------------*/
1093void eris_ifu_combine_get_xy_min_max(const int nframes,
1094 const float *offsetx, const float *offsety,
1095 float *min_offx, float *max_offx,
1096 float *min_offy, float *max_offy)
1097{
1098 float offx = 0.,
1099 offy = 0.;
1100
1101 for (int n = 0; n < nframes; n++) {
1102 offx = offsetx[n];
1103 offy = offsety[n];
1104 if (n == 0) {
1105 *min_offx = offx;
1106 *min_offy = offy;
1107 *max_offx = offx;
1108 *max_offy = offy;
1109 } else {
1110 if(offx > *max_offx)
1111 *max_offx=offx;
1112 if(offy > *max_offy)
1113 *max_offy=offy;
1114 if(offx < *min_offx)
1115 *min_offx=offx;
1116 if(offy < *min_offy)
1117 *min_offy=offy;
1118 }
1119 }
1120}
1121
1122/*----------------------------------------------------------------------------*/
1130/*----------------------------------------------------------------------------*/
1132{
1133 int k = x;
1134
1135 if (x >= 0.) {
1136 if ((x - (double)k) <= 0.5) {
1137 return k;
1138 } else {
1139 return k + 1;
1140 }
1141 } else {
1142 if ((x - (double)k) <= -0.5) {
1143 return k - 1;
1144 } else {
1145 return k;
1146 }
1147 }
1148}
1149
1150/*----------------------------------------------------------------------------*/
1180/*----------------------------------------------------------------------------*/
1181cpl_image* eris_ifu_combine_shift_image(const cpl_image *img_in,
1182 const double shift_x,
1183 const double shift_y,
1184 const double *kernel)
1185{
1186 cpl_image *img_shifted = NULL;
1187 cpl_size nx = 0,
1188 ny = 0;
1189 int samples = KERNEL_SAMPLES,
1190 mid = samples / 2,
1191 px = 0,
1192 py = 0,
1193 pos = 0,
1194 tabx = 0,
1195 taby = 0;
1196 double norm = 0.,
1197 value = 0.,
1198 fx = 0.,
1199 rx = 0.,
1200 fy = 0.,
1201 ry = 0.,
1202 *first_pass = NULL,
1203 *pimg_shifted = NULL;
1204 const double *pimg_in = NULL;
1205
1206 cpl_ensure(img_in != NULL, CPL_ERROR_NULL_INPUT, NULL);
1207 cpl_ensure(kernel != NULL, CPL_ERROR_NULL_INPUT, NULL);
1208
1209 /* Shifting by a zero offset returns a copy of the input image */
1210 if ((fabs(shift_x) < 1e-2) && (fabs(shift_y) < 1e-2))
1211 return cpl_image_duplicate(img_in);
1212
1213 nx = cpl_image_get_size_x(img_in);
1214 ny = cpl_image_get_size_y(img_in);
1215
1216 pimg_in = cpl_image_get_data_double_const(img_in);
1217 if (pimg_in != NULL) {
1218 first_pass = cpl_calloc(nx, ny*sizeof(double));
1219 img_shifted = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
1220 pimg_shifted = cpl_image_get_data_double(img_shifted);
1221 for (int y = 0; y < (int)ny; y++) {
1222 for (int x = 1; x < (int)nx-2; x++) {
1223 fx = (double)x - shift_x;
1224 px = (int)fx;
1225 rx = fx - (double)px;
1226 pos = px + y * (int)nx;
1227
1228 if ((px>1) && (px<(nx-3))) {
1229 tabx = (int)(fabs(mid * rx));
1230
1231 // Sum up over 4 closest pixel values,
1232 // weighted by interpolation kernel values
1233 value = pimg_in[pos-1] * kernel[mid+tabx] +
1234 pimg_in[pos] * kernel[tabx] +
1235 pimg_in[pos+1] * kernel[mid-tabx] +
1236 pimg_in[pos+2] * kernel[samples-tabx-1];
1237
1238 // Also sum up interpolation kernel coefficients
1239 // for further normalization
1240 norm = kernel[mid+tabx] +
1241 kernel[tabx] +
1242 kernel[mid-tabx] +
1243 kernel[samples-tabx-1];
1244
1245 if (fabs(norm) > 1e-4) {
1246 value /= norm;
1247 }
1248 } else {
1249 value = 0.;
1250 }
1251 // There may be a problem of rounding here if pixelvalue
1252 // has not enough bits to sustain the accuracy.
1253 first_pass[x+y*nx] = value;
1254 }
1255 }
1256
1257 for (int x = 0; x < (int)nx; x++) {
1258 for (int y = 1; y < (int)ny-3; y++) {
1259 fy = (double)y - shift_y;
1260 py = (int)fy ;
1261 ry = fy - (double)py ;
1262 pos = x + py * nx ;
1263
1264 if ((py > 1) && (py < ((int)ny-2))) {
1265 taby = (int)(fabs((double)mid * ry));
1266
1267 // Sum up over 4 closest pixel values,
1268 // weighted by interpolation kernel values
1269 value = first_pass[pos-nx] * kernel[mid+taby] +
1270 first_pass[pos] * kernel[taby] +
1271 first_pass[pos+nx] * kernel[mid-taby] +
1272 first_pass[pos+2*nx]*kernel[samples-taby-1];
1273
1274 // Also sum up interpolation kernel coefficients
1275 // for further normalization
1276 norm = kernel[mid+taby] +
1277 kernel[taby] +
1278 kernel[mid-taby] +
1279 kernel[samples-taby-1];
1280
1281 if (fabs(norm) > 1e-4) {
1282 value /= norm;
1283 }
1284 } else {
1285 value = 0.0;
1286 }
1287 pimg_shifted[x+y*nx] = value;
1288 }
1289 }
1290 } else {
1291 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT);
1292 cpl_msg_error(cpl_func, "Cannot get a data from an image");
1293 return NULL;
1294 }
1295
1296 // free memory
1297 cpl_free(first_pass); first_pass = NULL;
1298
1299 return img_shifted;
1300}
1301
1302/*----------------------------------------------------------------------------*/
1307/*----------------------------------------------------------------------------*/
1309{
1310 cpl_size nx = 0,
1311 ny = 0;
1312 double *pimg = NULL;
1313
1314 if (img != NULL) {
1315 pimg = cpl_image_get_data_double(img);
1316
1317 nx = cpl_image_get_size_x(img);
1318 ny = cpl_image_get_size_y(img);
1319
1320 for (int i = 0 ; i < nx*ny; i++) {
1321 if (fabs(pimg[i]) < DBL_ZERO_TOLERANCE) {
1322 pimg[i] = NAN;
1323 }
1324 }
1325 }
1326}
1327
1328/*----------------------------------------------------------------------------*/
1336/*----------------------------------------------------------------------------*/
1337double eris_ifu_combine_calc_error(eris_ifu_vector *data_vec,
1338 eris_ifu_vector *err_vec,
1339 const char *compute_mode)
1340{
1341 double std_err = 0.,
1342 std_dev = 0.;
1343 int vec_size = 0;
1344 cpl_ensure_code(data_vec != NULL, CPL_ERROR_NULL_INPUT);
1345 cpl_ensure_code(err_vec != NULL, CPL_ERROR_NULL_INPUT);
1346
1347 vec_size = eris_ifu_vector_count_non_rejected(data_vec);
1348
1349 if (vec_size > 2) {
1350 // recalculate error from input data (regardless if there is
1351 // input error or not)
1352
1353 if (!strcmp(compute_mode, "MEDIAN")) {
1354 std_dev = eris_ifu_vector_get_stdev_median(data_vec);
1355 } else {
1356 std_dev = eris_ifu_vector_get_stdev(data_vec);
1357 }
1358 std_err = std_dev / sqrt(vec_size);
1359 } else {
1360 vec_size = eris_ifu_vector_count_non_rejected(err_vec);
1361 /* error propagation from input error*/
1362 if (vec_size == 1) {
1363 int i = 0;
1364 while (eris_ifu_vector_is_rejected(err_vec, i)) {
1365 i++;
1366 }
1367 std_err = eris_ifu_vector_get(err_vec, i);
1368 } else if (vec_size == 2) {
1369 double tmp_dbl = 0.;
1370 int i = 0;
1371 while (eris_ifu_vector_is_rejected(err_vec, i)) {
1372 i++;
1373 }
1374
1375 int j = i+1;
1376 while (eris_ifu_vector_is_rejected(err_vec, j)) {
1377 j++;
1378 }
1379
1380 tmp_dbl = sqrt(pow(eris_ifu_vector_get(err_vec, i), 2) +
1381 pow(eris_ifu_vector_get(err_vec, j), 2));
1382
1383 std_dev = tmp_dbl / 2;
1384 std_err = std_dev / sqrt(2);
1385 }
1386 }
1387 return std_err;
1388}
1389
1390/* --- simple shifting from KMOS pipeline --- */
1391
1392enum boundary_mode {
1393 NATURAL,
1394 EXACT,
1395 ESTIMATED1,
1396 ESTIMATED2
1397};
1398
1399double** matrix(int nrow, int ncol) {
1400 double **matrix = (double**)cpl_malloc((size_t)((nrow)*sizeof(double*)));
1401
1402 for(int i = 0; i < nrow; i++) {
1403 matrix[i] = (double *) cpl_malloc((size_t)((ncol)*sizeof(double)));
1404 }
1405
1406 return matrix;
1407}
1408
1409void free_matrix(double **matrix, int nrow) {
1410 for(int i = 0; i < nrow; i++) {
1411 cpl_free(matrix[i]); matrix[i] = NULL;
1412 }
1413 cpl_free(matrix); matrix = NULL;
1414}
1415
1416/*----------------------------------------------------------------------------*/
1429/*----------------------------------------------------------------------------*/
1430cpl_error_code eris_ifu_reject_nan(cpl_image *img)
1431{
1432 cpl_error_code err = CPL_ERROR_NONE;
1433 int nx = 0,
1434 ny = 0,
1435 is_rej = 0;
1436 float tmp = 0.0;
1437
1438 cpl_ensure_code(img != NULL, CPL_ERROR_NULL_INPUT);
1439
1440 TRY {
1441
1442 nx = cpl_image_get_size_x(img);
1443 ny = cpl_image_get_size_y(img);
1445
1446 for (int ix = 1; ix <= nx; ix++) {
1447 for (int iy = 1; iy <= ny; iy++) {
1448 tmp = cpl_image_get(img, ix, iy, &is_rej);
1450
1451 if (!is_rej && isnan(tmp)) {
1453 cpl_image_reject(img, ix, iy));
1454 }
1455 }
1456 }
1457 } CATCH {
1458 err = cpl_error_get_code();
1459 }
1460
1461 return err;
1462}
1463
1464/*----------------------------------------------------------------------------*/
1513/*----------------------------------------------------------------------------*/
1514cpl_image* eris_ifu_combine_shift_image_kmos(const cpl_image *img_in,
1515 double xshift,
1516 double yshift,
1517 const char *method,
1518 const enum extrapolationType extrapolation)
1519{
1520 const double *pimg_in = NULL;
1521 double **array_in = NULL,
1522 **array_out = NULL,
1523 *pimg_out = NULL;
1524 cpl_image *img_out = NULL;
1525 int xdim = 0,
1526 ydim = 0,
1527 xdim_new = 0,
1528 ydim_new = 0;
1529
1530 cpl_ensure(img_in != NULL, CPL_ERROR_NULL_INPUT, NULL);
1531 cpl_ensure((extrapolation == NONE_NANS) ||
1532 (extrapolation == NONE_CLIPPING)/* ||
1533 (extrapolation == BCS_NATURAL) ||
1534 (extrapolation == BCS_ESTIMATED)*/, CPL_ERROR_ILLEGAL_INPUT, NULL);
1535
1536 TRY {
1537 if ((xshift == 0.0) && (yshift == 0.0)) {
1538 // duplicate image
1540 img_out = cpl_image_duplicate(img_in));
1541 } else {
1542 xdim = cpl_image_get_size_x(img_in);
1543 ydim = cpl_image_get_size_y(img_in);
1544
1545 pimg_in = cpl_image_get_data_double_const(img_in);
1546
1547 array_in = matrix(xdim, ydim);
1548 for (int j = 0; j < ydim ; j++) {
1549 for (int i = 0; i < xdim ; i++) {
1550 if (isnan(pimg_in[i + j*xdim]))
1551 /* agudo: fix because of NaN-input */
1552 array_in[i][j] = 0;
1553 else
1554 array_in[i][j] = pimg_in[i + j*xdim];
1555 }
1556 }
1557
1558 /*if (strcmp(method, "BCS") == 0) {
1559 xdim_new = xdim;
1560 ydim_new = ydim;
1561 xstart_new = xshift;
1562 ystart_new = yshift;
1563
1564 enum boundary_mode boundaryMode = NATURAL;
1565 if (extrapolation == BCS_ESTIMATED) {
1566 boundaryMode = ESTIMATED2;
1567 }
1568
1569 array_out = bicubicspline_reg_reg(
1570 xdim, 0.0, 1.0,
1571 ydim, 0.0, 1.0,
1572 array_in,
1573 xdim_new, xstart_new, 1.0,
1574 ydim_new, ystart_new, 1.0,
1575 boundaryMode);
1576 } else */if (strcmp(method, "NN") == 0) {
1577 if (fabs(xshift) > 1.0 || fabs(yshift) > 1.0) {
1578 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
1579 "Neither xshift nor yshift are allowed to "
1580 "be greater than 1 pixel for NN");
1581 }
1582 int xoffset = 0,
1583 yoffset = 0;
1584 if (xshift > 0.5) {
1585 xoffset = 1;
1586 } else if (xshift < -0.5) {
1587 xoffset = -1;
1588 } else {
1589 xoffset = 0;
1590 }
1591 if (yshift > 0.5) {
1592 yoffset = 1;
1593 } else if (yshift < -0.5) {
1594 yoffset = -1;
1595 } else {
1596 yoffset = 0;
1597 }
1598 array_out = matrix(xdim,ydim);
1599 for (int j = 0; j < ydim; j++) {
1600 for (int i = 0; i < xdim; i++) {
1601 int xix = i+xoffset,
1602 yix = j+yoffset;
1603 if (xix < 0 || xix >= xdim || yix < 0 || yix >= ydim) {
1604 array_out[i][j] = NAN;
1605 } else {
1606 array_out[i][j] = array_in[i+xoffset][j+yoffset];
1607 }
1608 }
1609 }
1610 } else {
1611 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
1612 "Unknown value for interpolation method");
1613 }
1614 free_matrix(array_in, xdim);
1615
1616 switch (extrapolation) {
1617// case BCS_NATURAL:
1618// case BCS_ESTIMATED:
1619// BRK_IF_NULL(
1620// image_out = cpl_malloc(xdim_new * ydim_new * sizeof(double)));
1621// for (int j = 0; j < ydim_new; j++) {
1622// for (int i = 0; i < xdim_new; i++) {
1623// image_out[i+j*xdim_new] = array_out[i][j];
1624// }
1625// }
1626// break;
1627 case NONE_CLIPPING:
1628 xdim_new = xdim - lrintf(ceill(fabsl(xshift)));
1629 ydim_new = xdim - lrintf(ceill(fabsl(yshift)));
1631 pimg_out = cpl_malloc(xdim_new * ydim_new * sizeof(double)));
1632 int xmin = - floorl(xshift);
1633 if (xmin < 0)
1634 xmin = 0;
1635 int xmax = xdim - ceill(xshift);
1636 if (xmax > xdim)
1637 xmax = xdim;
1638 int ymin = - floorl(yshift);
1639 if (ymin < 0)
1640 ymin = 0;
1641 int ymax = ydim - ceill(yshift);
1642 if (ymax > ydim)
1643 ymax = ydim;
1644 for (int j = ymin; j < ymax; j++) {
1645 for (int i = xmin; i < xmax; i++) {
1646 pimg_out[(i - xmin) + (j - ymin) * xdim_new] = array_out[i][j];
1647 }
1648 }
1649 break;
1650 case NONE_NANS:
1651 xdim_new = xdim;
1652 ydim_new = ydim;
1654 pimg_out = cpl_malloc(xdim * ydim * sizeof(double)));
1655 float xxmin = 0 - xshift;
1656 float xxmax = xdim - 1 - xshift;
1657 float yymin = 0 - yshift;
1658 float yymax = ydim - 1 - yshift;
1659 for (int j = 0; j < ydim; j++) {
1660 for (int i = 0; i < xdim; i++) {
1661 if ((i < xxmin ) || (i > xxmax) ||
1662 (j < yymin ) || (j > yymax))
1663 {
1664 pimg_out[i+j*xdim] = NAN;
1665 } else {
1666 pimg_out[i+j*xdim] = array_out[i][j];
1667 }
1668 }
1669 }
1670 break;
1671 default:
1672 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
1673 "Unknown value for extrapolation type");
1674 }
1675
1676 free_matrix(array_out, xdim);
1677 img_out = cpl_image_wrap_double(xdim_new, ydim_new, pimg_out);
1678
1679 /* reject NaN values here */
1681 eris_ifu_reject_nan(img_out));
1682 }
1683 }
1684 CATCH
1685 {
1686 CATCH_MSGS();
1687 eris_ifu_free_image(&img_out);
1688 }
1689
1690 return img_out;
1691}
1692
1693/*----------------------------------------------------------------------------*/
1704/*----------------------------------------------------------------------------*/
1705cpl_error_code eris_ifu_combine_read_image_planes(const cpl_frameset *frameset,
1706 cpl_image **imagesData,
1707 cpl_image **imagesError,
1708 int z,
1709 int edge_trim,
1710 bool subtract_background)
1711{
1712 cpl_size nframes = 0,
1713 llx = 0,
1714 lly = 0,
1715 urx = 0,
1716 ury = 0;
1717 cpl_error_code err = CPL_ERROR_NONE;
1718 const cpl_frame *frame = NULL;
1719 cpl_mask *tmp_mask = NULL;
1720 cpl_image *cube_qual_tmp = NULL;
1721 cpl_propertylist *plist = NULL;
1722 const char *name = NULL;
1723 int tmp_size_x = 0,
1724 tmp_size_y = 0;
1725 bool warn = FALSE,
1726 warned = FALSE;
1727
1728 cpl_ensure_code(frameset != NULL, CPL_ERROR_NULL_INPUT);
1729
1730 TRY {
1731 nframes = cpl_frameset_get_size(frameset);
1732
1733 /* Read in cubes */
1734 for (cpl_size n = 0; n < nframes; n++) {
1736 frame = cpl_frameset_get_position_const(frameset, n));
1738 name = cpl_frame_get_filename(frame));
1739 if (edge_trim > 0) {
1741 plist = cpl_propertylist_load(name, 1));
1742 tmp_size_x = eris_pfits_get_naxis1(plist);
1743 tmp_size_y = eris_pfits_get_naxis2(plist);
1745
1747 llx = 1 + edge_trim;
1748 lly = 1 + edge_trim;
1749 urx = tmp_size_x - edge_trim;
1750 ury = tmp_size_y - edge_trim;
1751
1753 imagesData[n] = cpl_image_load_window(name, CPL_TYPE_DOUBLE, z, 1, llx, lly, urx, ury));
1755 imagesError[n] = cpl_image_load_window(name, CPL_TYPE_DOUBLE, z, 2, llx, lly, urx, ury));
1757 cube_qual_tmp = cpl_image_load_window(name, CPL_TYPE_DOUBLE, z, 3, llx, lly, urx, ury));
1758 }
1759 else{
1761 imagesData[n] = cpl_image_load(name, CPL_TYPE_DOUBLE, z, 1));
1763 imagesError[n] = cpl_image_load(name, CPL_TYPE_DOUBLE, z, 2));
1765 cube_qual_tmp = cpl_image_load(name, CPL_TYPE_DOUBLE, z, 3));
1766 }
1767
1768 /* Reject mask */
1770 tmp_mask = cpl_mask_threshold_image_create(cube_qual_tmp, 0, INT_MAX));
1772 cpl_image_reject_from_mask(imagesData[n], tmp_mask));
1774 cpl_image_reject_from_mask(imagesError[n], tmp_mask));
1775 eris_ifu_free_mask(&tmp_mask);
1776 eris_ifu_free_image(&cube_qual_tmp);
1777
1778 if (subtract_background) {
1780 eris_ifu_combine_subtract_background(imagesData[n], &warn));
1781 if (warn && !warned) {
1782 warned = TRUE;
1783 cpl_msg_warning(cpl_func, " local_median is NAN in %dth plane", z);
1784 }
1785 }
1787 } // end for nframes
1788 } CATCH {
1789 CATCH_MSGS();
1790 err = cpl_error_get_code();
1791 }
1792 return err;
1793}
1794
1795/*----------------------------------------------------------------------------*/
1805/*----------------------------------------------------------------------------*/
1806int eris_ifu_combine_min_cube_size(const cpl_frameset *fs) {
1807 int naxis3 = 0,
1808 naxis3_tmp = 0;
1809 double crval3 = 0.,
1810 crpix3 = 0,
1811 cd3_3 = 0.,
1812 crval3_tmp = 0.,
1813 crpix3_tmp = 0.,
1814 cd3_3_tmp = 0.;
1815 const char *name = NULL;
1816 const cpl_frame *fr = NULL;
1817 cpl_propertylist *pl = NULL;
1818
1819 cpl_ensure(fs != NULL, CPL_ERROR_NULL_INPUT, -1);
1820
1821 TRY {
1822 // initialize with 1st frame
1823 cpl_frameset_iterator *iter = NULL;
1825 iter = cpl_frameset_iterator_new(fs));
1826 fr = cpl_frameset_iterator_get(iter);
1829 name = cpl_frame_get_filename(fr));
1830
1831 // load header of data extension
1833 pl = cpl_propertylist_load(name, 1));
1834 naxis3 = cpl_propertylist_get_int( pl, NAXIS3);
1835 crpix3 = cpl_propertylist_get_double(pl, CRPIX3);
1836 crval3 = cpl_propertylist_get_double(pl, CRVAL3);
1837 cd3_3 = cpl_propertylist_get_double(pl, CD3_3);
1840
1842 cpl_frameset_iterator_advance(iter, 1));
1843 fr = cpl_frameset_iterator_get(iter);
1845
1846 while (fr != NULL) {
1848 name = cpl_frame_get_filename(fr));
1849 // load header of data extension
1851 pl = cpl_propertylist_load(name, 1));
1852
1853 naxis3_tmp = cpl_propertylist_get_int( pl, NAXIS3);
1854 crpix3_tmp = cpl_propertylist_get_double(pl, CRPIX3);
1855 crval3_tmp = cpl_propertylist_get_double(pl, CRVAL3);
1856 cd3_3_tmp = cpl_propertylist_get_double(pl, CD3_3);
1859
1860 if ((fabs(crpix3 - crpix3_tmp) > DBL_ZERO_TOLERANCE) ||
1861 (fabs(crval3 - crval3_tmp) > DBL_ZERO_TOLERANCE) ||
1862 (fabs(cd3_3 - cd3_3_tmp) > DBL_ZERO_TOLERANCE))
1863 {
1864 BRK_WITH_ERROR_MSG(CPL_ERROR_ILLEGAL_INPUT,
1865 "WCS not matching for all frames!");
1866 }
1867
1868 if (naxis3_tmp < naxis3) {
1869 naxis3 = naxis3_tmp;
1870 }
1871
1873 cpl_frameset_iterator_advance(iter, 1));
1874 fr = cpl_frameset_iterator_get(iter);
1876 } // end while
1877 } CATCH {
1878 CATCH_MSGS();
1879 naxis3 = -1;
1880 }
1881 return naxis3;
1882}
1883
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