ERIS Pipeline Reference Manual 1.9.3
eris_ifu_sky_tweak.c
1/*
2 * This file is part of the ERIS Pipeline
3 * Copyright (C) 2002,2003 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24/*-----------------------------------------------------------------------------
25 Functions Hierarchy (o : public / x : static)
26
27 eris_ifu_priv_sky_tweak() (o)
28 - eris_ifu_sky_tweak_get_spectra() (x)
29 - eris_ifu_sky_tweak_correct_vibrational_trans() (x)
30 - amoeba
31 - fitsky
32 - eris_ifu_sky_tweak_thermal_bgd() (x)
33 - amoeba
34 - fitbkd
35 *----------------------------------------------------------------------------*/
36
37/*-----------------------------------------------------------------------------
38 * Includes
39 *----------------------------------------------------------------------------*/
40
41#include <math.h>
42#include <string.h>
43#include <stdio.h>
44
45#include <cpl.h>
46
47#include "irplib_wlxcorr.h"
48#include "irplib_spectrum.h"
49
50#include "eris_ifu_error.h"
51#include "eris_ifu_sky_tweak.h"
52#include "eris_ifu_lambda_corr.h"
53#include "eris_ifu_functions.h"
54#include "eris_utils.h"
55/*-----------------------------------------------------------------------------
56 * Global vars
57 *----------------------------------------------------------------------------*/
58
59#define HC_K 14387.7512979 // h*c/k in [micrometer*K]
60#define PLANCK(lambda,t) (pow((lambda),-5.0) / (exp(HC_K/((lambda) * fabs(t))) - 1.))
61
62int cont_size,
63 lines_size;
64double * cont_sky_sig=NULL,
65 * line_sky_sig=NULL,
66 * cont_object_sig=NULL,
67 * line_object_sig=NULL,
68 * cont_lambda=NULL,
69 * line_lambda=NULL;
70
71int spectrum_size;
72double *spectrum_lambda=NULL;
73double *spectrum_value=NULL;
74double *thermal_background=NULL;
75
76/*-----------------------------------------------------------------------------
77 Functions prototypes
78 -----------------------------------------------------------------------------*/
79static cpl_imagelist * eris_ifu_priv_sky_stretch(
80 cpl_imagelist * obj,
81 cpl_imagelist * sky,
82 float min_frac,
83 int poly_degree,
84 int resampling_method,
85 int plot) ;
86static cpl_polynomial * eris_ifu_stretch_get_poly(
87 const cpl_vector * obj,
88 const cpl_vector * sky,
89 double min_gap,
90 int degree,
91 cpl_bivector ** matching_lines) ;
92static cpl_imagelist * eris_ifu_stretch_apply_linear(
93 cpl_imagelist * sky,
94 cpl_polynomial * stretch) ;
95static cpl_imagelist * eris_ifu_stretch_apply_spline(
96 cpl_imagelist * sky,
97 cpl_polynomial * stretch) ;
98static int eris_ifu_stretch_check(
99 cpl_imagelist * obj,
100 cpl_imagelist * sky,
101 cpl_imagelist * new_sky,
102 cpl_image * mask) ;
103static int eris_ifu_stretch_plot_positions_differences(
104 cpl_bivector * matching_lines,
105 cpl_bivector * new_matching_lines) ;
106static cpl_bivector * eris_ifu_strech_get_matching_lines(
107 const cpl_vector * obj,
108 const cpl_vector * sky,
109 double min_gap,
110 int remove_outliers,
111 int degree) ;
112
113static void amoeba(double**, double y[], int, double,
114 double (*funk)(double []), int *) ;
115static double amotry(double **, double y[], double psum[], int,
116 double (*funk)(double []), int, double);
117
118static double fitsky(double *) ;
119static double fitbkd(double *) ;
120
121static int eris_ifu_sky_tweak_identify_lines_cont(cpl_vector *, int *, int *,
122 int *, int *) ;
123static void eris_ifu_plot_arrays(double *, double *, double *, int) ;
124static cpl_bivector * eris_ifu_sky_tweak_thermal_bgd(cpl_bivector *, double) ;
125static double eris_ifu_sky_tweak_get_mean_wo_outliers(const cpl_vector *) ;
126static cpl_error_code eris_ifu_sky_tweak_get_spectra(const cpl_imagelist *,
127 const cpl_imagelist *, const cpl_vector *, const cpl_image *,
128 const int, cpl_bivector **, cpl_bivector **, int *) ;
129static cpl_error_code eris_ifu_sky_tweak_get_spectra_simple(const cpl_imagelist *,
130 const cpl_imagelist *, const cpl_image *, cpl_vector **, cpl_vector **);
131static cpl_bivector * eris_ifu_sky_tweak_correct_vibrational_trans(
132 cpl_bivector *, cpl_bivector *, int, int) ;
133double **matrix(int nrow, int ncol);
134void free_matrix(double ** matrix, int nrow);
135
136/*----------------------------------------------------------------------------*/
153/*----------------------------------------------------------------------------*/
154
157/*----------------------------------------------------------------------------*/
172/*----------------------------------------------------------------------------*/
173int eris_ifu_plot_cube_background(cpl_imagelist * obj)
174{
175 cpl_image * mask ;
176 cpl_vector * obj_spec ;
177 cpl_vector * sky_spec ;
178
179 /* Check inputs */
180 if (obj == NULL) return -1 ;
181
182 /* mask is a binary image : 0 -> obj / 1 -> background */
183 mask = eris_ifu_lcorr_create_object_mask(obj, .3, NULL, NULL);
184
185 /* Get the background spectrum from obj and sky cubes using mask */
186 if (eris_ifu_sky_tweak_get_spectra_simple(obj, obj, mask, &obj_spec,
187 &sky_spec) != CPL_ERROR_NONE) {
188 cpl_msg_error(cpl_func, "Cannot extract the spectra from cubes") ;
189 cpl_image_delete(mask) ;
190 return -1 ;
191 }
192
193 cpl_plot_vector("set grid;set xlabel 'pix';", "t 'CUBE BGD' w lines", "",
194 obj_spec);
195
196 cpl_vector_delete(obj_spec) ;
197 cpl_vector_delete(sky_spec) ;
198 return 0 ;
199}
200
201/*----------------------------------------------------------------------------*/
234/*----------------------------------------------------------------------------*/
235cpl_imagelist * eris_ifu_sky_tweak(
236 cpl_imagelist * obj,
237 cpl_imagelist * sky,
238 const cpl_propertylist * header,
239 float min_frac,
240 int tbsub,
241 int skip_last,
242 int stretch,
243 int stretch_degree,
244 int stretch_resampling,
245 int plot,
246 cpl_imagelist ** new_sky)
247{
248 cpl_imagelist * new_obj ;
249 cpl_image * mask ;
250 cpl_bivector * obj_spec = NULL;
251 cpl_bivector * sky_spec = NULL;
252 cpl_bivector * thermal_backg ;
253 cpl_bivector * vscales ;
254 cpl_vector * lambda ;
255 int nx, ny, nz, ix, kx, snx, sny, snz, kmax, first_nonan ;
256
257 /* Check Entries */
258 cpl_ensure(obj, CPL_ERROR_NULL_INPUT, NULL);
259 cpl_ensure(sky, CPL_ERROR_NULL_INPUT, NULL);
260 cpl_ensure(header, CPL_ERROR_NULL_INPUT, NULL);
261 cpl_ensure(new_sky, CPL_ERROR_NULL_INPUT, NULL);
262 cpl_ensure(min_frac > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
263 cpl_ensure(stretch_resampling > 0 && stretch_resampling < 3, CPL_ERROR_ILLEGAL_INPUT, NULL);
264
265 nx = cpl_image_get_size_x(cpl_imagelist_get_const(obj, 0));
266 ny = cpl_image_get_size_y(cpl_imagelist_get_const(obj, 0));
267 nz = cpl_imagelist_get_size(obj);
268 snx = cpl_image_get_size_x(cpl_imagelist_get_const(sky, 0));
269 sny = cpl_image_get_size_y(cpl_imagelist_get_const(sky, 0));
270 snz = cpl_imagelist_get_size(sky);
271 if (nx!=snx || ny!=sny || nz!=snz) {
272 cpl_msg_error(__func__, "Illegal inputs") ;
273 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
274 return NULL ;
275 }
276
277 /* Start by applying the sky stretching if wished */
278 if (stretch) {
279 *new_sky = eris_ifu_priv_sky_stretch(obj, sky, .3, stretch_degree,
280 stretch_resampling, plot) ;
281 } else {
282 *new_sky = cpl_imagelist_duplicate(sky) ;
283 }
284
285 /* Create wavelengths vector corresponding to the input cubes */
287 if (nz != cpl_vector_get_size(lambda)) {
288 cpl_msg_error(__func__, "Illegal inputs") ;
289 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
290 cpl_vector_delete(lambda);
291 cpl_imagelist_delete(*new_sky);
292 return NULL ;
293 }
294
295 /* mask is a binary image : 0 -> obj / 1 -> background */
296 mask = eris_ifu_lcorr_create_object_mask(obj, min_frac, NULL, NULL);
297 if (cpl_msg_get_level() == CPL_MSG_DEBUG)
298 cpl_image_save(mask, "mask.fits", CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
299
300 /* Get the background spectrum (using mask) from obj and sky cubes */
301// eris_ifu_sky_tweak_get_spectra(obj, *new_sky, lambda, mask, 1,
302// &obj_spec, &sky_spec, &first_nonan);
303 eris_ifu_sky_tweak_get_spectra(obj, *new_sky, lambda, mask, 0,
304 &obj_spec, &sky_spec, &first_nonan);
305
306 /* Get the corrections factors for each sub-band */
307 vscales = eris_ifu_sky_tweak_correct_vibrational_trans(obj_spec,
308 sky_spec, skip_last, plot);
309 if (cpl_msg_get_level() == CPL_MSG_DEBUG && plot)
310 cpl_plot_bivector("set title \"SCALES\";", "w lines", "",vscales);
311
312 /* Get the thermal bgd */
313 thermal_backg = eris_ifu_sky_tweak_thermal_bgd(obj_spec, 1.0);
314
315 /* Re-try if the computation failed (PIPE-5528) */
316 if (thermal_backg == NULL) {
317 cpl_error_reset() ;
318 cpl_msg_indent_more() ;
319 cpl_msg_warning(__func__,
320 "Thermal Bgd failed, re-try by clipping highest values") ;
321 thermal_backg = eris_ifu_sky_tweak_thermal_bgd(obj_spec, 0.98);
322 if (thermal_backg == NULL) {
323 cpl_msg_warning(__func__,
324 "Recovery failed - skip the thermal background correction");
325 cpl_error_reset() ;
326 } else {
327 cpl_msg_info(__func__, "Recovery succeeded");
328 }
329 cpl_msg_indent_less() ;
330 }
331
332 if (cpl_msg_get_level() == CPL_MSG_DEBUG && plot)
333 cpl_plot_bivector("set title \"Th. bgd\";","w lines", "",thermal_backg);
334
335 /* Correct using the computed scales */
336 new_obj = cpl_imagelist_duplicate(obj);
337 kmax = cpl_vector_get_size(cpl_bivector_get_x_const(obj_spec));
338 kx = 0;
339 for (ix=0; ix<nz; ix++) {
340 if ((kx < kmax ) && (cpl_vector_get(lambda,ix)==cpl_vector_get(
341 cpl_bivector_get_x_const(obj_spec),kx))) {
342 /* Subtract thermal background from new sky cube */
343 if (thermal_backg != NULL) {
344 cpl_image_subtract_scalar(cpl_imagelist_get(*new_sky ,ix),
345 cpl_vector_get(cpl_bivector_get_y_const(thermal_backg),
346 kx));
347 }
348
349 /* Multiply new sky cube with scaling factors from */
350 /* OH line fitting */
351 cpl_image_multiply_scalar(cpl_imagelist_get(*new_sky, ix),
352 cpl_vector_get(cpl_bivector_get_y_const(vscales), kx));
353 /* Subtract new sky cube from obj cube copy to */
354 /* get new obj cube */
355 cpl_image_subtract(cpl_imagelist_get(new_obj, ix),
356 cpl_imagelist_get(*new_sky, ix));
357
358 /* Subtract thermal background from new obj cube as well */
359 if (tbsub && thermal_backg != NULL) {
360 cpl_image_subtract_scalar(cpl_imagelist_get(new_obj, ix),
361 cpl_vector_get(cpl_bivector_get_y_const(
362 thermal_backg), kx));
363 }
364 kx++;
365 }
366 }
367 cpl_bivector_delete(obj_spec);
368 cpl_bivector_delete(sky_spec);
369 if (thermal_backg != NULL) cpl_bivector_delete(thermal_backg);
370 cpl_bivector_delete(vscales);
371 cpl_vector_delete(lambda);
372
373 cpl_image_delete(mask);
374 eris_check_error_code("eris_ifu_sky_tweak");
375 return new_obj;
376}
377
380/*----------------------------------------------------------------------------*/
392/*----------------------------------------------------------------------------*/
393static void eris_ifu_plot_arrays(
394 double * wl,
395 double * obj,
396 double * sky,
397 int arr_size)
398{
399 cpl_vector ** vectors ;
400
401 /* Checks */
402 if (obj == NULL || sky == NULL) return ;
403
404 /* Create Vectors */
405 vectors = cpl_malloc(3*sizeof(cpl_vector*)) ;
406 vectors[0] = cpl_vector_wrap(arr_size, wl) ;
407 vectors[1] = cpl_vector_wrap(arr_size, obj) ;
408 vectors[2] = cpl_vector_wrap(arr_size, sky) ;
409
410 CPL_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual);
411 cpl_plot_vectors("set grid;set xlabel 'Wavelength (microns)';",
412 "t 'Obj and Sky sub-band' w lines", "",
413 (const cpl_vector **)vectors,
414 3);
415 CPL_DIAG_PRAGMA_POP;
416
417 cpl_vector_unwrap(vectors[0]) ;
418 cpl_vector_unwrap(vectors[1]) ;
419 cpl_vector_unwrap(vectors[2]) ;
420 cpl_free(vectors) ;
421 return ;
422}
423
424/*----------------------------------------------------------------------------*/
452/*----------------------------------------------------------------------------*/
453static cpl_bivector * eris_ifu_sky_tweak_thermal_bgd(
454 cpl_bivector * spectrum,
455 double clip_rate)
456{
457 cpl_bivector * result ;
458 cpl_vector * spectrum_v ;
459 cpl_vector * thermal_v ;
460 cpl_vector * tmp_v ;
461 cpl_vector * sorted_y ;
462 const int ndim = 3;
463 const int nsimplex = ndim + 1;
464 double ** p ;
465 double p_init[ndim+1];
466 double * lspectrum = NULL,
467 * vspectrum = NULL;
468 double * x_amoeba ;
469 double * y_amoeba ;
470 int i, j, ix, loop, niter, new_size, skip, input_size ;
471 double min, max, tmp, diff, limit, clip_limit ;
472
473 /* Check entries */
474 if (spectrum == NULL) {
475 cpl_msg_error(__func__, "NULL inputs") ;
476 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
477 return NULL ;
478 }
479 if ((clip_rate < 0.5) || (clip_rate > 1.0)) {
480 cpl_msg_error(__func__, "Invalid clip rate: %g", clip_rate) ;
481 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
482 return NULL ;
483 }
484
485 /* Initialise */
486 min = +1.e30;
487 max = -1.e30;
488 niter = 0 ;
489 new_size = 0;
490 skip = 11;
491 input_size = cpl_bivector_get_size(spectrum) ;
492
493 lspectrum = cpl_bivector_get_x_data(spectrum);
494 vspectrum = cpl_bivector_get_y_data(spectrum);
495 spectrum_lambda=cpl_malloc(input_size*sizeof(double));
496 spectrum_value=cpl_malloc(input_size* sizeof(double));
497 thermal_background= cpl_malloc(input_size*sizeof(double));
498
499 /* Get rid off spikes - skip highest values in the first iteration */
500 if (clip_rate < 1.0) {
501 sorted_y = cpl_vector_duplicate(cpl_bivector_get_y(spectrum));
502 cpl_vector_sort(sorted_y, CPL_SORT_ASCENDING);
503 clip_limit = cpl_vector_get(sorted_y,
504 cpl_vector_get_size(sorted_y) * clip_rate);
505 cpl_vector_delete(sorted_y) ;
506 } else {
507 clip_limit = +1.e30;
508 }
509
510 /* Move to the first non-zero value */
511 for (ix=0; ix < input_size ; ix++) if (vspectrum[ix] != 0.0) break;
512 /* Store the following non-zero/nan/inf values */
513 /* Also omit the clipped ones - Store the min of the retained values */
514 /* Skip the 11 first values */
515 for (i=ix+skip; i<input_size; i++) {
516 if ((vspectrum[i] != 0.0) && (! eris_ifu_is_nan_or_inf(vspectrum[i]))
517 && (vspectrum[i] <= clip_limit) ) {
518 spectrum_lambda[new_size] = lspectrum[i];
519 spectrum_value[new_size] = vspectrum[i];
520 if (vspectrum[i] < min) { min = vspectrum[i]; }
521 new_size++;
522 }
523 }
524 /* Skip the last 0.0 values if any */
525 for (ix=new_size; ix >= 0; ix--) if (vspectrum[ix] != 0.0) break;
526 /* Skip the 11 last values */
527 spectrum_size = ix-skip;
528
529 y_amoeba=cpl_malloc((nsimplex+1)*sizeof(double));
530 x_amoeba=cpl_malloc((ndim+1)*sizeof(double));
531 p = matrix(nsimplex+1,ndim+1);
532
533 p_init[1] = min;
534 p_init[2] = spectrum_value[spectrum_size-1];
535 p_init[3] = 280.;
536 p[1][1] = p_init[1];
537 p[1][2] = p_init[2];
538 p[1][3] = p_init[3];
539
540 for (loop=0; loop<20; loop++) {
541 /*
542 printf("p initial : %d %g %g %g\n",
543 loop, p[1][1], p[1][2], p[1][3]) ;
544 */
545 for (i=2; i<nsimplex+1; i++) {
546 for (j=1; j<ndim+1; j++) p[i][j] = p[1][j];
547 }
548 for (i=2; i<nsimplex+1; i++) p[i][i-1] = p[i][i-1] * 1.2;
549 for (i=1; i<nsimplex+1; i++) {
550 for (j=1; j<ndim+1; j++) x_amoeba[j] = p[i][j];
551 y_amoeba[i] = fitbkd(x_amoeba);
552 }
553 amoeba(p, y_amoeba, 3, 1.e-5, fitbkd, &niter);
554 if (niter < 0) {
555 cpl_msg_error(__func__, "Function minimization failed") ;
556 free_matrix(p, 5);
557 cpl_free(x_amoeba);
558 cpl_free(y_amoeba);
559 cpl_free(spectrum_lambda);
560 cpl_free(spectrum_value);
561 cpl_free(thermal_background);
562 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
563 return NULL ;
564 }
565 spectrum_v = cpl_vector_wrap(spectrum_size, spectrum_value);
566 thermal_v = cpl_vector_wrap(spectrum_size, thermal_background);
567 tmp_v = cpl_vector_duplicate(spectrum_v);
568 cpl_vector_subtract(tmp_v, thermal_v);
569 limit = cpl_vector_get_median(tmp_v) + 2. * cpl_vector_get_stdev(tmp_v);
570 cpl_vector_delete(tmp_v);
571 cpl_vector_unwrap(spectrum_v);
572 cpl_vector_unwrap(thermal_v);
573
574 min = +1.e30;
575 new_size = 0;
576 for (i=0; i<spectrum_size; i++) {
577 diff = spectrum_value[i] - thermal_background[i];
578 if (diff < limit) {
579 spectrum_lambda[new_size] = spectrum_lambda[i];
580 spectrum_value[new_size] = spectrum_value[i];
581 if (spectrum_value[i] < min) min = spectrum_value[i];
582 new_size++;
583 }
584 }
585 spectrum_size = new_size;
586 }
587
588 for (i=0; i<spectrum_size; i++) {
589 tmp = PLANCK(spectrum_lambda[i], p[1][3]);
590 if (tmp > max) max = tmp;
591 }
592 if (fabs(max) < 1e-90) {
593 cpl_msg_error(__func__, "Cannot determine thermal Background") ;
594 free_matrix(p, 5);
595 cpl_free(x_amoeba);
596 cpl_free(y_amoeba);
597 cpl_free(spectrum_lambda);
598 cpl_free(spectrum_value);
599 cpl_free(thermal_background);
600 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
601 return NULL ;
602 }
603
604 for (i=0; i<input_size; i++) {
605 spectrum_lambda[i] = lspectrum[i];
606 spectrum_value[i] = vspectrum[i];
607 tmp = PLANCK(spectrum_lambda[i], p[1][3]);
608 thermal_background[i] = p[1][1] + tmp / max * p[1][2];
609 }
610 thermal_v = cpl_vector_wrap(input_size, thermal_background);
611 tmp_v = cpl_vector_duplicate(thermal_v);
612 cpl_vector_unwrap(thermal_v);
613
614 result = cpl_bivector_wrap_vectors(
615 cpl_vector_duplicate(cpl_bivector_get_x_const(spectrum)), tmp_v);
616
617 free_matrix(p, 5);
618 cpl_free(x_amoeba);
619 cpl_free(y_amoeba);
620 cpl_free(spectrum_lambda);
621 cpl_free(spectrum_value);
622 cpl_free(thermal_background);
623 return result;
624}
625
626/*----------------------------------------------------------------------------*/
641/*----------------------------------------------------------------------------*/
642static double eris_ifu_sky_tweak_get_mean_wo_outliers(const cpl_vector * vdata)
643{
644 cpl_vector * tmpv1 ;
645 cpl_vector * tmpv2 ;
646 cpl_vector * tmpv3 ;
647 cpl_vector * tmpv4 ;
648 const double * data ;
649 double * tmpv1_data;
650 double avg, median, stdev, clip;
651 int nr_data, i, nr_i;
652
653 nr_data = cpl_vector_get_size(vdata);
654 data = cpl_vector_get_data_const(vdata);
655 tmpv1 = cpl_vector_new(nr_data);
656 tmpv1_data = cpl_vector_get_data(tmpv1);
657
658 median = cpl_vector_get_median_const(vdata);
659 for (i=0; i<nr_data; i++) tmpv1_data[i] = fabs(data[i] - median);
660 cpl_vector_sort(tmpv1, CPL_SORT_ASCENDING);
661 clip = cpl_vector_get(tmpv1, (int) .8*nr_data);
662 tmpv2 = eris_ifu_idl_where(tmpv1, clip*5., le);
663 tmpv3 = eris_ifu_idl_values_at_indices(vdata, tmpv2);
664 median = cpl_vector_get_median_const(tmpv3);
665 stdev = cpl_vector_get_stdev(tmpv3);
666 nr_i = 0;
667 for (i=0; i<nr_data; i++) {
668 if ((data[i] < median + 3. * stdev) && (data[i] > median - 3. * stdev)){
669 tmpv1_data[nr_i] = data[i];
670 nr_i++;
671 }
672 }
673 tmpv4 = cpl_vector_wrap(nr_i, tmpv1_data);
674 avg = cpl_vector_get_mean(tmpv4);
675
676 cpl_vector_delete(tmpv1);
677 cpl_vector_delete(tmpv2);
678 cpl_vector_delete(tmpv3);
679 cpl_vector_unwrap(tmpv4);
680 return avg;
681}
682
683/*----------------------------------------------------------------------------*/
707/*----------------------------------------------------------------------------*/
708static cpl_error_code eris_ifu_sky_tweak_get_spectra_simple(
709 const cpl_imagelist * object,
710 const cpl_imagelist * sky,
711 const cpl_image * mask,
712 cpl_vector ** obj_spec,
713 cpl_vector ** sky_spec)
714{
715 cpl_vector * intobj ;
716 cpl_vector * intsky ;
717 const cpl_image * oimg ;
718 const cpl_image * simg ;
719 double * intobj_data ;
720 double * intsky_data ;
721 double * vo ;
722 double * vs ;
723 cpl_vector * ovec ;
724 cpl_vector * svec ;
725 double mpix, opix, spix;
726 int nx, ny, nz, snx, sny, snz, ix, iy, iz, found,
727 m_is_rejected, o_is_rejected, s_is_rejected;
728
729 /* Initialise */
730 nx = cpl_image_get_size_x(cpl_imagelist_get_const(object, 0));
731 ny = cpl_image_get_size_y(cpl_imagelist_get_const(object, 0));
732 nz = cpl_imagelist_get_size(object);
733 snx = cpl_image_get_size_x(cpl_imagelist_get_const(sky, 0));
734 sny = cpl_image_get_size_y(cpl_imagelist_get_const(sky, 0));
735 snz = cpl_imagelist_get_size(sky);
736
737 /* Check entries */
738 if (nx!=snx || ny!=sny || nz!=snz) {
739 cpl_msg_error(__func__, "Illegal inputs") ;
740 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
741 return CPL_ERROR_ILLEGAL_INPUT ;
742 }
743
744 /* Allocate data */
745 intobj = cpl_vector_new(nz);
746 intsky = cpl_vector_new(snz);
747 intobj_data = cpl_vector_get_data(intobj);
748 intsky_data = cpl_vector_get_data(intsky);
749 vo = cpl_malloc(nx * ny * sizeof(double));
750 vs = cpl_malloc(nx * ny * sizeof(double));
751
752 /* For each image, comput the sky value from both the obj and the sky */
753 for (iz = 0; iz <nz; iz++) {
754 oimg = cpl_imagelist_get_const(object, iz);
755 simg = cpl_imagelist_get_const(sky, iz);
756 found = 0;
757 for (ix = 1; ix<=nx; ix++) {
758 for (iy = 1; iy<=ny; iy++) {
759 mpix = cpl_image_get(mask, ix, iy, &m_is_rejected);
760 opix = cpl_image_get(oimg, ix, iy, &o_is_rejected);
761 spix = cpl_image_get(simg, ix, iy, &s_is_rejected);
762 if ( mpix > .5 && m_is_rejected == 0 && o_is_rejected == 0 &&
763 s_is_rejected == 0 ) {
764 vo[found] = opix;
765 vs[found] = spix;
766 found++;
767 }
768 }
769 }
770 /* Only if enough values, the mean or mediaan is taken, otherwise 0.0 */
771 if (found >= nx*ny/4.) {
772 ovec = cpl_vector_wrap(found, vo);
773 svec = cpl_vector_wrap(found, vs);
774
775 if (found < nx*ny/2. ) {
776 intobj_data[iz] = cpl_vector_get_median(ovec);
777 intsky_data[iz] = cpl_vector_get_median(svec);
778 } else {
779 intobj_data[iz] = eris_ifu_sky_tweak_get_mean_wo_outliers(ovec);
780 intsky_data[iz] = eris_ifu_sky_tweak_get_mean_wo_outliers(svec);
781 }
782 cpl_vector_unwrap(ovec);
783 cpl_vector_unwrap(svec);
784 } else {
785 intobj_data[iz] = 0.;
786 intsky_data[iz] = 0.;
787 }
788 }
789 cpl_free(vo);
790 cpl_free(vs);
791
792 /* Return the spectra */
793 *obj_spec = intobj ;
794 *sky_spec = intsky ;
795 return CPL_ERROR_NONE;
796}
797
798/*----------------------------------------------------------------------------*/
825/*----------------------------------------------------------------------------*/
826static cpl_error_code eris_ifu_sky_tweak_get_spectra(
827 const cpl_imagelist * object,
828 const cpl_imagelist * sky,
829 const cpl_vector * lambda,
830 const cpl_image * mask,
831 const int no_nans,
832 cpl_bivector ** obj_spectrum_ptr,
833 cpl_bivector ** sky_spectrum_ptr,
834 int * first_nonan)
835{
836 cpl_bivector * obj_spectrum ;
837 cpl_bivector * sky_spectrum ;
838 cpl_vector * intobj ;
839 cpl_vector * intsky ;
840 cpl_vector * new_lambda ;
841 cpl_vector * new_intobj ;
842 cpl_vector * new_intsky ;
843 const cpl_image * oimg ;
844 const cpl_image * simg ;
845 double * intobj_data ;
846 double * intsky_data ;
847 double * vo ;
848 double * vs ;
849 double * new_lambda_d ;
850 double * new_intobj_d ;
851 double * new_intsky_d ;
852 const double * lambda_d ;
853 cpl_vector * ovec ;
854 cpl_vector * svec ;
855 double mpix, opix, spix;
856 int nx, ny, nz, snx, sny, snz, ix, iy, iz, ni, found,
857 nr_valid_int, m_is_rejected, o_is_rejected,
858 s_is_rejected;
859
860 /* Check entries */
861
862 if (first_nonan==NULL) {
863 cpl_msg_error(__func__, "Illegal inputs") ;
864 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
865 return CPL_ERROR_ILLEGAL_INPUT ;
866 } else {
867 *first_nonan = -1 ;
868 }
869
870 nx = cpl_image_get_size_x(cpl_imagelist_get_const(object, 0));
871 ny = cpl_image_get_size_y(cpl_imagelist_get_const(object, 0));
872 nz = cpl_imagelist_get_size(object);
873 snx = cpl_image_get_size_x(cpl_imagelist_get_const(sky, 0));
874 sny = cpl_image_get_size_y(cpl_imagelist_get_const(sky, 0));
875 snz = cpl_imagelist_get_size(sky);
876
877 if (nx!=snx || ny!=sny || nz!=snz) {
878 cpl_msg_error(__func__, "Illegal inputs") ;
879 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
880 return CPL_ERROR_ILLEGAL_INPUT ;
881 }
882
883 if (nz != cpl_vector_get_size(lambda)) {
884 cpl_msg_error(__func__, "Illegal inputs") ;
885 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
886 return CPL_ERROR_ILLEGAL_INPUT ;
887 }
888
889 intobj = cpl_vector_new(cpl_vector_get_size(lambda));
890 intsky = cpl_vector_new(cpl_vector_get_size(lambda));
891 intobj_data = cpl_vector_get_data(intobj);
892 intsky_data = cpl_vector_get_data(intsky);
893
894 vo = cpl_malloc(nx * ny * sizeof(double));
895 vs = cpl_malloc(nx * ny * sizeof(double));
896
897 nr_valid_int = 0;
898 for (iz = 0; iz <nz; iz++) {
899 oimg = cpl_imagelist_get_const(object, iz);
900 simg = cpl_imagelist_get_const(sky, iz);
901 found = 0;
902 for (ix = 1; ix<=nx; ix++) {
903 for (iy = 1; iy<=ny; iy++) {
904 mpix = cpl_image_get(mask, ix, iy, &m_is_rejected);
905 opix = cpl_image_get(oimg, ix, iy, &o_is_rejected);
906 spix = cpl_image_get(simg, ix, iy, &s_is_rejected);
907 if ( mpix > .5 && m_is_rejected == 0 && o_is_rejected == 0 &&
908 s_is_rejected == 0 ) {
909 vo[found] = opix;
910 vs[found] = spix;
911 found++;
912 }
913
914 }
915 }
916 if (found >= nx*ny/4.) {
917 if (*first_nonan < 0) *first_nonan = iz ;
918 nr_valid_int++;
919 ovec = cpl_vector_wrap(found, vo);
920 svec = cpl_vector_wrap(found, vs);
921
922 if (found < nx*ny/2. ) {
923 intobj_data[iz] = cpl_vector_get_median(ovec);
924 intsky_data[iz] = cpl_vector_get_median(svec);
925 } else {
926 intobj_data[iz] = eris_ifu_sky_tweak_get_mean_wo_outliers(ovec);
927 intsky_data[iz] = eris_ifu_sky_tweak_get_mean_wo_outliers(svec);
928 }
929 cpl_vector_unwrap(ovec);
930 cpl_vector_unwrap(svec);
931 } else {
932 if (no_nans) {
933 intobj_data[iz] = 0./0.;
934 intsky_data[iz] = 0./0.;
935 } else {
936 nr_valid_int++;
937 intobj_data[iz] = 0.;
938 intsky_data[iz] = 0.;
939 }
940 }
941 }
942
943 if (no_nans) {
944 new_lambda = cpl_vector_new(nr_valid_int);
945 new_intobj = cpl_vector_new(nr_valid_int);
946 new_intsky = cpl_vector_new(nr_valid_int);
947 new_lambda_d=cpl_vector_get_data(new_lambda);
948 new_intobj_d=cpl_vector_get_data(new_intobj);
949 new_intsky_d=cpl_vector_get_data(new_intsky);
950 lambda_d=cpl_vector_get_data_const(lambda);
951
952 ni = 0;
953 for (iz=0 ; iz<nz; iz++) {
954 if ((! isnan(intobj_data[iz])) && ni < nr_valid_int) {
955 new_lambda_d[ni] = lambda_d[iz];
956 new_intobj_d[ni] = intobj_data[iz];
957 new_intsky_d[ni] = intsky_data[iz];
958 ni++;
959 }
960 }
961 obj_spectrum = cpl_bivector_wrap_vectors(new_lambda, new_intobj) ;
962 sky_spectrum = cpl_bivector_wrap_vectors(
963 cpl_vector_duplicate(new_lambda), new_intsky);
964
965 cpl_vector_delete(intobj);
966 cpl_vector_delete(intsky);
967 } else {
968 obj_spectrum = cpl_bivector_wrap_vectors(cpl_vector_duplicate(lambda),
969 intobj);
970 sky_spectrum = cpl_bivector_wrap_vectors(cpl_vector_duplicate(lambda),
971 intsky);
972 }
973
974 cpl_free(vo);
975 cpl_free(vs);
976 *obj_spectrum_ptr = obj_spectrum;
977 *sky_spectrum_ptr = sky_spectrum;
978 return CPL_ERROR_NONE;
979}
980
981/*----------------------------------------------------------------------------*/
1016/*----------------------------------------------------------------------------*/
1017static cpl_bivector * eris_ifu_sky_tweak_correct_vibrational_trans(
1018 cpl_bivector * obj_spectrum,
1019 cpl_bivector * sky_spectrum,
1020 int skip_last,
1021 int plot)
1022{
1023 cpl_bivector * result ;
1024 double * scalings ;
1025 double * lambda_boundaries ;
1026 const char ** labels ;
1027 const double * lambda ;
1028 const double * intobj ;
1029 const double * intsky ;
1030 double * array_wls ;
1031 double * array_obj ;
1032 double * array_sky ;
1033 double * line_interpolate_object ;
1034 double * line_interpolate_sky ;
1035 double * flineres;
1036 cpl_vector * tmp_vec ;
1037 cpl_vector * sky_lines_map_vec ;
1038 double median, stdev ;
1039 int i, ix, il, lx, cx, nr_lambda, nr_samples, nr_boundaries,
1040 cont_start, cont_end ;
1041 cpl_error_code errCode;
1042
1043 /* Check Entries */
1044 if (obj_spectrum == NULL || sky_spectrum == NULL) {
1045 cpl_msg_error(__func__, "NULL inputs") ;
1046 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
1047 return NULL;
1048 }
1049 if (cpl_bivector_get_size(obj_spectrum) !=
1050 cpl_bivector_get_size(sky_spectrum)) {
1051 cpl_msg_error(__func__, "Illegal inputs") ;
1052 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
1053 return NULL;
1054 }
1055
1056 /* Initialise */
1057 nr_lambda = cpl_bivector_get_size(obj_spectrum);
1058 lambda = cpl_vector_get_data_const(cpl_bivector_get_x_const(obj_spectrum));
1059 intobj = cpl_vector_get_data_const(cpl_bivector_get_y_const(obj_spectrum));
1060 intsky = cpl_vector_get_data_const(cpl_bivector_get_y_const(sky_spectrum));
1061 median = stdev = 0.0 ;
1062
1063 /* Wavelengths for sky and obj need to be identical */
1064 for (ix=0; ix<nr_lambda; ix++) {
1065 if (fabs(lambda[ix] -
1066 cpl_vector_get(cpl_bivector_get_x_const(sky_spectrum), ix))
1067 >= 1.e-7) {
1068 cpl_msg_error(__func__, "Illegal inputs") ;
1069 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
1070 return NULL;
1071 }
1072 }
1073
1074 /* Create lambda boundaries for the sub-bands */
1075 if (skip_last) {
1076 nr_boundaries = 20 ;
1077 lambda_boundaries = cpl_malloc(nr_boundaries * sizeof(double)) ;
1078 labels = cpl_malloc((nr_boundaries-1) * sizeof(char*)) ;
1079 } else {
1080 nr_boundaries = 21 ;
1081 lambda_boundaries = cpl_malloc(nr_boundaries * sizeof(double)) ;
1082 labels = cpl_malloc((nr_boundaries-1) * sizeof(char*)) ;
1083 }
1084 lambda_boundaries[0] = 0.780 ; labels[0] = "" ;
1085 lambda_boundaries[1] = 0.824 ; labels[1] = "" ;
1086 lambda_boundaries[2] = 0.873 ; labels[2] = "" ;
1087 lambda_boundaries[3] = 0.926 ; labels[3] = "" ;
1088 lambda_boundaries[4] = 0.964 ; labels[4] = "" ;
1089 lambda_boundaries[5] = 1.014 ; labels[5] = "4-1 transitions" ;
1090 lambda_boundaries[6] = 1.067 ; labels[6] = "5-2 transitions" ;
1091 lambda_boundaries[7] = 1.125 ; labels[7] = "6-3 transitions" ;
1092 lambda_boundaries[8] = 1.196 ; labels[8] = "7-4 transitions" ;
1093 lambda_boundaries[9] = 1.252 ; labels[9] = " 02 transitions" ;
1094 lambda_boundaries[10] = 1.289 ; labels[10] = "8-5 transitions" ;
1095 lambda_boundaries[11] = 1.400 ; labels[11] = "2-0 transitions" ;
1096 lambda_boundaries[12] = 1.472 ; labels[12] = "3-1 transitions" ;
1097 lambda_boundaries[13] = 1.5543 ; labels[13] = "4-2 transitions" ;
1098 lambda_boundaries[14] = 1.6356 ; labels[14] = "5-3 transitions" ;
1099 lambda_boundaries[15] = 1.7253 ; labels[15] = "6-4 transitions" ;
1100 lambda_boundaries[16] = 1.840 ; labels[16] = "7-5 transitions" ;
1101 lambda_boundaries[17] = 1.9570 ; labels[17] = "8-6 transitions" ;
1102 lambda_boundaries[18] = 2.095 ; labels[18] = "9-7 transitions" ;
1103 if (skip_last) {
1104 lambda_boundaries[19] = 2.460 ;
1105 } else {
1106 lambda_boundaries[19] = 2.30 ; labels[19] = "final bit" ;
1107 lambda_boundaries[20] = 2.460 ;
1108 }
1109
1110 /* Allocate scalings */
1111 scalings = cpl_malloc(nr_boundaries * sizeof(double)) ;
1112 for (ix=0; ix<nr_boundaries; ix++) scalings[ix] = 0.;
1113
1114 array_wls = cpl_malloc(nr_lambda * sizeof(double)) ;
1115 array_obj = cpl_malloc(nr_lambda * sizeof(double)) ;
1116 array_sky = cpl_malloc(nr_lambda * sizeof(double)) ;
1117
1118 /* Loop on the SUB BANDS */
1119 for (ix = 0; ix<nr_boundaries-1; ix++) {
1120 cpl_msg_debug(__func__, "Sub-band %2d: %s", ix+1, labels[ix]) ;
1121 cpl_msg_indent_more() ;
1122
1123 /* Stor non-Nan values from the current sub-band in array_* */
1124 nr_samples = 0;
1125 for (il=0; il<nr_lambda; il++) {
1126 if ((lambda[il] >= lambda_boundaries[ix] ) &&
1127 (lambda[il] < lambda_boundaries[ix+1]) ) {
1128
1129 if (eris_ifu_is_nan_or_inf(intsky[il]) ||
1130 eris_ifu_is_nan_or_inf(intobj[il]) ||
1131 intsky[il] == 0. || intobj[il] == 0. ) {
1132 cpl_msg_indent_less() ;
1133 continue ;
1134 }
1135
1136 array_wls[nr_samples] = lambda[il];
1137 array_obj[nr_samples] = intobj[il];
1138 array_sky[nr_samples] = intsky[il];
1139 nr_samples++;
1140 }
1141 }
1142 cpl_msg_debug(__func__, "Found %d samples", nr_samples) ;
1143
1144 /* Skip the sub-band if too few samples */
1145 if (nr_samples <= 20) {
1146 cpl_msg_indent_less() ;
1147 continue ;
1148 }
1149 if (plot==ix+1 && cpl_msg_get_level() == CPL_MSG_DEBUG)
1150 eris_ifu_plot_arrays(array_wls, array_obj, array_sky, nr_samples);
1151
1152 /* Sky vector sub-band statistics */
1153 tmp_vec = cpl_vector_wrap(nr_samples, array_sky);
1154 median = cpl_vector_get_median_const(tmp_vec);
1155 stdev = cpl_vector_get_stdev(tmp_vec);
1156 cpl_vector_unwrap(tmp_vec);
1157 cpl_msg_debug(__func__, "Sky Stats - Med: %g Stdev: %g", median, stdev);
1158
1159 /* Create a map of the sky vector lines */
1160 sky_lines_map_vec = cpl_vector_new(nr_samples) ;
1161 cpl_vector_fill(sky_lines_map_vec, 0.0) ;
1162 for (i=0; i<nr_samples; i++) {
1163 if (array_sky[i] > median+stdev)
1164 cpl_vector_set(sky_lines_map_vec, i, 10.0) ;
1165 }
1166 if (plot==ix+1 && cpl_msg_get_level() == CPL_MSG_DEBUG)
1167 cpl_plot_vector("set grid;set xlabel 'Samples';set ylabel 'Map';",
1168 "t 'Sky lines map' w lines", "", sky_lines_map_vec);
1169
1170 /* Smoothe the map to create the sky lines signal */
1171 tmp_vec=cpl_vector_filter_lowpass_create(sky_lines_map_vec,
1172 CPL_LOWPASS_LINEAR,2);
1173 cpl_vector_delete(sky_lines_map_vec);
1174 sky_lines_map_vec = tmp_vec ;
1175
1176 if (plot==ix+1 && cpl_msg_get_level() == CPL_MSG_DEBUG)
1177 cpl_plot_vector("set grid;set xlabel 'Samples';set ylabel 'Map';",
1178 "t 'Smoothed sky lines map' w lines", "",
1179 sky_lines_map_vec);
1180
1181 /* Identify the continuum and lines sizes */
1182 eris_ifu_sky_tweak_identify_lines_cont(sky_lines_map_vec,
1183 &cont_start, &cont_end, &cont_size, &lines_size) ;
1184 if (lines_size == 0) {
1185 cpl_msg_warning(__func__, "No line region found") ;
1186 cpl_vector_delete(sky_lines_map_vec);
1187 cpl_msg_indent_less() ;
1188 continue;
1189 }
1190
1191 /* Allocate arrays to hold concatenated line and */
1192 /* continuum regions */
1193 cont_sky_sig = cpl_malloc(cont_size * sizeof(double));
1194 cont_object_sig = cpl_malloc(cont_size * sizeof(double));
1195 cont_lambda = cpl_malloc(cont_size * sizeof(double));
1196 line_sky_sig = cpl_malloc(lines_size * sizeof(double));
1197 line_object_sig = cpl_malloc(lines_size * sizeof(double));
1198 line_lambda = cpl_malloc(lines_size * sizeof(double));
1199
1200 /* Store separately Lines and Continuum */
1201 cx = lx = 0;
1202 for (i = cont_start; i <= cont_end ; i++) {
1203 if (cpl_vector_get(sky_lines_map_vec, i) > 0.) {
1204 line_sky_sig[lx] = array_sky[i];
1205 line_object_sig[lx] = array_obj[i];
1206 line_lambda[lx] = array_wls[i];
1207 lx++;
1208 } else {
1209 cont_sky_sig[cx] = array_sky[i];
1210 cont_object_sig[cx] = array_obj[i];
1211 cont_lambda[cx] = array_wls[i];
1212 cx++;
1213 }
1214 }
1215
1216 /* Minimize object - sky difference (line regions - */
1217 /* interpolated background) using a single factor */
1218 const int ndim = 1;
1219 const int nsimplex = ndim + 1;
1220 double **p = NULL;
1221 double *x_amoeba = NULL,
1222 *y_amoeba = NULL;
1223 int niter = 0;
1224 int ip,jp;
1225 double scale;
1226 y_amoeba = cpl_malloc((nsimplex+1) * sizeof(double));
1227 x_amoeba = cpl_malloc((ndim+1) * sizeof(double));
1228 p = matrix(nsimplex+1,ndim+1);
1229
1230 p[1][1] = 1.;
1231 p[2][1] = 1.25;
1232 for (ip=1; ip<nsimplex+1; ip++) {
1233 for (jp=1; jp<ndim+1; jp++) {
1234 x_amoeba[jp] = p[ip][jp];
1235 }
1236 y_amoeba[ip] = fitsky(x_amoeba);
1237 }
1238 amoeba(p, y_amoeba, ndim, 1.e-5, fitsky, &niter );
1239 if (niter < 0) {
1240 cpl_msg_error(__func__, "Function minimization failed") ;
1241 free_matrix(p, 5);
1242 cpl_free(x_amoeba);
1243 cpl_free(y_amoeba);
1244 cpl_free(spectrum_lambda);
1245 cpl_free(spectrum_value);
1246 cpl_free(thermal_background);
1247 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
1248 return NULL ;
1249 }
1250 scale = p[1][1];
1251 flineres = cpl_malloc(lines_size * sizeof(double));
1252
1253/* line_interpolate_object = polynomial_irreg_irreg_nonans(
1254 cont_size, cont_lambda, cont_object_sig,
1255 lines_size, line_lambda, 2);
1256 line_interpolate_sky = polynomial_irreg_irreg_nonans(
1257 cont_size, cont_lambda, cont_sky_sig,
1258 lines_size, line_lambda, 2);
1259 */
1260 line_interpolate_object = cpl_calloc(lines_size, sizeof(double));
1261 errCode = eris_ifu_1d_interpolation(
1262 cont_lambda, cont_object_sig, cont_size,
1263 line_lambda, line_interpolate_object, lines_size, 2);
1264 if (errCode != CPL_ERROR_NONE) {
1265 printf("ERROR: The function eris_ifu_1d_interpolation called in eris_ifu_sky_tweak_correct_vibrational_trans returned the error %d\n", errCode);
1266 printf("%s\n", cpl_error_get_message_default(errCode));
1267 }
1268
1269 line_interpolate_sky = cpl_calloc(lines_size, sizeof(double));
1270 errCode = eris_ifu_1d_interpolation(
1271 cont_lambda, cont_sky_sig, cont_size,
1272 line_lambda, line_interpolate_sky, lines_size, 2);
1273 if (errCode != CPL_ERROR_NONE) {
1274 printf("ERROR: The function eris_ifu_1d_interpolation called in eris_ifu_sky_tweak_correct_vibrational_trans returned the error %d\n", errCode);
1275 printf("%s\n", cpl_error_get_message_default(errCode));
1276 }
1277
1278 for (i=0; i<lines_size; i++) {
1279 flineres[i] = (line_object_sig[i] -
1280 line_interpolate_object[i]) -
1281 (line_sky_sig[i] - line_interpolate_sky[i]) * scale;
1282 }
1283
1284 tmp_vec = cpl_vector_wrap(lines_size, flineres);
1285 median = cpl_vector_get_median_const(tmp_vec);
1286 stdev = cpl_vector_get_stdev(tmp_vec);
1287 cpl_vector_unwrap(tmp_vec) ;
1288
1289 int clip_cnt=0;
1290 for (i=0; i<lines_size; i++) {
1291 if ( fabs(flineres[i] - median) <= (3 * stdev) ) {
1292 clip_cnt++;
1293 }
1294 }
1295 cpl_msg_debug(__func__, "Outliers: %d", lines_size-clip_cnt) ;
1296
1297 if ((clip_cnt != lines_size) && (clip_cnt >= 3)) {
1298 lx = 0;
1299 for (i=0; i<lines_size; i++) {
1300 if ( fabs(flineres[i] - median) <= (3 * stdev) ) {
1301 line_sky_sig[lx] = line_sky_sig[i];
1302 line_object_sig[lx] =
1303 line_object_sig[i];
1304 line_lambda[lx] = line_lambda[i];
1305 lx++;
1306 }
1307 }
1308 lines_size = lx;
1309 cpl_msg_debug(__func__, "2. Lines size: %d", lines_size) ;
1310
1311 p[1][1] = 1.;
1312 p[2][1] = 1.5;
1313 for (ip=1; ip<nsimplex+1; ip++) {
1314 for (jp=1; jp<ndim+1; jp++) x_amoeba[jp] = p[ip][jp];
1315 y_amoeba[ip] = fitsky(x_amoeba);
1316 }
1317 amoeba(p, y_amoeba, ndim, 1.e-5, fitsky, &niter);
1318 if (niter < 0) {
1319 cpl_msg_error(__func__, "Function minimization failed") ;
1320 free_matrix(p, 5);
1321 cpl_free(x_amoeba);
1322 cpl_free(y_amoeba);
1323 cpl_free(spectrum_lambda);
1324 cpl_free(spectrum_value);
1325 cpl_free(thermal_background);
1326 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
1327 return NULL ;
1328 }
1329 scale = p[1][1];
1330 }
1331 cpl_msg_debug(__func__, "Scale: %g", scale) ;
1332 scalings[ix] = scale;
1333
1334 cpl_vector_delete(sky_lines_map_vec);
1335 free_matrix(p, nsimplex+1);
1336 cpl_free(x_amoeba);
1337 cpl_free(y_amoeba);
1338 cpl_free(cont_sky_sig);
1339 cpl_free(line_sky_sig);
1340 cpl_free(cont_object_sig);
1341 cpl_free(line_object_sig);
1342 cpl_free(cont_lambda);
1343 cpl_free(line_lambda);
1344 cpl_free(flineres);
1345 cpl_free(line_interpolate_object);
1346 cpl_free(line_interpolate_sky);
1347
1348 cpl_msg_indent_less() ;
1349 } // end for (ix = 0; ix<nr_boundaries-1; ix++)
1350 cpl_free(labels) ;
1351
1352 // check for outliers in the scaling factors
1353 int nr_valid = 0,
1354 v_ix = 0;
1355 double valid_scales[nr_boundaries];
1356 cpl_vector *valid_scales_v = NULL;
1357 for (ix=0; ix<nr_boundaries; ix++) {
1358 if (scalings[ix] != 0.0 ) {
1359 valid_scales[nr_valid] = scalings[ix];
1360 nr_valid++;
1361 }
1362 }
1363 valid_scales_v = cpl_vector_wrap(nr_valid, valid_scales);
1364 median = cpl_vector_get_median_const(valid_scales_v);
1365 stdev = cpl_vector_get_stdev(valid_scales_v);
1366 v_ix = 0;
1367 for (ix=0; ix<nr_boundaries; ix++) {
1368 if (scalings[ix] != 0.0 ) {
1369 if (fabs(valid_scales[v_ix] - median) > 2 * stdev) {
1370 scalings[ix] = 0.;
1371 }
1372 v_ix++;
1373 }
1374 }
1375 if (valid_scales_v != NULL) {
1376 cpl_vector_unwrap(valid_scales_v);
1377 valid_scales_v = NULL;
1378 }
1379
1380 int scale0_size;
1381 double *scale0_lambda = NULL,
1382 *scale0_value = NULL,
1383 *scale = NULL;
1384 cpl_vector *scale_v = NULL;
1385
1386 scale0_lambda = cpl_malloc(nr_lambda * sizeof(double));
1387 scale0_value = cpl_malloc(nr_lambda * sizeof(double));
1388
1389 scale0_size = 0;
1390 for (il=0; il<nr_lambda; il++) {
1391 for (ix = 0; ix<nr_boundaries-1; ix++) {
1392 if (scalings[ix] != 0.) {
1393 if ((lambda[il] >= lambda_boundaries[ix] ) &&
1394 (lambda[il] < lambda_boundaries[ix+1]) ) {
1395 scale0_lambda[scale0_size] = lambda[il];
1396 scale0_value[scale0_size] = scalings[ix];
1397 scale0_size++;
1398 }
1399 }
1400 }
1401 }
1402 cpl_free(scalings) ;
1403 cpl_free(lambda_boundaries) ;
1404
1405/* scale = polynomial_irreg_irreg_nonans(scale0_size, scale0_lambda,
1406 scale0_value, nr_lambda, lambda, 1);
1407*/
1408 scale = cpl_calloc(nr_lambda, sizeof(double));
1409 /* cast to lambda* to prevent compiler problem on mac */
1410 double* lambda_tmp = (double*) lambda;
1411 errCode = eris_ifu_1d_interpolation(
1412 scale0_lambda, scale0_value, scale0_size,
1413 lambda_tmp, scale, nr_lambda, 2);
1414 if (errCode != CPL_ERROR_NONE) {
1415 printf("ERROR: The function eris_ifu_1d_interpolation called in eris_ifu_sky_tweak_correct_vibrational_trans returned the error %d\n", errCode);
1416 printf("%s\n", cpl_error_get_message_default(errCode));
1417 }
1418
1419 scale_v = cpl_vector_wrap(nr_lambda, scale);
1420
1421 if (scale0_lambda != NULL) cpl_free(scale0_lambda);
1422 if (scale0_value != NULL) cpl_free(scale0_value);
1423 result = cpl_bivector_wrap_vectors(
1424 cpl_vector_duplicate(cpl_bivector_get_x_const(obj_spectrum)),
1425 scale_v);
1426
1427 cpl_free(array_wls) ;
1428 cpl_free(array_obj) ;
1429 cpl_free(array_sky) ;
1430
1431 return result;
1432}
1433
1434/*----------------------------------------------------------------------------*/
1451/*----------------------------------------------------------------------------*/
1452static int eris_ifu_sky_tweak_identify_lines_cont(
1453 cpl_vector * sky_lines_map_vec,
1454 int * cont_start,
1455 int * cont_end,
1456 int * local_cont_size,
1457 int * local_lines_size)
1458{
1459 int current_line_size, nr_samples, i ;
1460
1461 /* local_ prefix added to avoid conflict with global variables */
1462
1463 /* Initialise */
1464 current_line_size = 0 ;
1465 nr_samples = cpl_vector_get_size(sky_lines_map_vec) ;
1466
1467 /* Make sure cont/line regions start and end with a contin. reg */
1468 *cont_start = -1;
1469 *cont_end = -1;
1470 *local_cont_size = 0;
1471 *local_lines_size = 0;
1472 for (i=0; i<nr_samples; i++) {
1473 if (cpl_vector_get(sky_lines_map_vec, i) > 0.) {
1474 /*** Line ***/
1475 /* Ignore Lines at the start */
1476 if (*cont_start == -1) continue;
1477 current_line_size++;
1478 } else {
1479 /*** Continuum ***/
1480 if (*cont_start == -1) *cont_start = i;
1481 *cont_end = i;
1482 (*local_cont_size)++;
1483 *local_lines_size += current_line_size;
1484 current_line_size = 0;
1485 }
1486 }
1487 cpl_msg_debug(__func__, "Cont [%d, %d] size: %d / Lines size: %d",
1488 *cont_start, *cont_end, *local_cont_size, *local_lines_size) ;
1489 return 0 ;
1490}
1491
1492/*----------------------------------------------------------------------------*/
1509/*----------------------------------------------------------------------------*/
1510static double fitsky(double *p) {
1511 double result = 0.;
1512 double *cont_sky = NULL,
1513 *cont_object = NULL;
1514 double avg = 0.;
1515 int ix;
1516 cpl_error_code errCode;
1517
1518/*
1519 cont_sky = polynomial_irreg_irreg_nonans(cont_size, cont_lambda,
1520 cont_sky_sig, lines_size, line_lambda, 1);
1521 cont_object = polynomial_irreg_irreg_nonans(cont_size, cont_lambda,
1522 cont_object_sig, lines_size, line_lambda, 1);
1523*/
1524
1525 cont_sky = cpl_calloc(lines_size, sizeof(double));
1526 errCode = eris_ifu_1d_interpolation(cont_lambda, cont_sky_sig, cont_size,
1527 line_lambda, cont_sky, lines_size, 2);
1528 if (errCode != CPL_ERROR_NONE) {
1529 printf("ERROR: The function eris_ifu_1d_interpolation called in fitsky returned the error %d\n", errCode);
1530 printf("%s\n", cpl_error_get_message_default(errCode));
1531 }
1532
1533 cont_object = cpl_calloc(lines_size, sizeof(double));
1534 errCode = eris_ifu_1d_interpolation(cont_lambda, cont_object_sig, cont_size,
1535 line_lambda, cont_object, lines_size, 2);
1536 if (errCode != CPL_ERROR_NONE) {
1537 printf("ERROR: The function eris_ifu_1d_interpolation called in fitsky returned the error %d\n", errCode);
1538 printf("%s\n", cpl_error_get_message_default(errCode));
1539 }
1540
1541 for (ix=0; ix<lines_size; ix++) {
1542 double diff = (line_object_sig[ix] - cont_object[ix]) -
1543 (line_sky_sig[ix] - cont_sky[ix]) * p[1];
1544 avg += diff * diff;
1545 }
1546 avg /= lines_size;
1547 result = sqrt(avg);
1548
1549 eris_ifu_free_double_array(&cont_sky);
1550 eris_ifu_free_double_array(&cont_object);
1551
1552 return result;
1553}
1554
1555/*----------------------------------------------------------------------------*/
1577/*----------------------------------------------------------------------------*/
1578static double fitbkd(double *p) {
1579 double result = 0.;
1580 double *tmp = NULL;
1581 double max = 0.;
1582 int i = 0;
1583
1584 tmp = cpl_malloc(spectrum_size * sizeof(double));
1585
1586 max = -1.;
1587 for (i=0; i<spectrum_size; i++) {
1588 tmp[i] = PLANCK(spectrum_lambda[i], p[3]);
1589 if (tmp[i] > max) {
1590 max = tmp[i];
1591 }
1592 }
1593 p[2]=fabs(p[2]); // make sure scaling factor is positive
1594 if (max > 0.) {
1595 for (i=0; i<spectrum_size; i++) {
1596 thermal_background[i] = p[1] + tmp[i] / max * fabs(p[2]);
1597 }
1598 } else {
1599 for (i=0; i<spectrum_size; i++) {
1600 thermal_background[i] = tmp[i];
1601 }
1602 }
1603
1604 result = 0.;
1605 for (i=0; i<spectrum_size; i++) {
1606 result += (spectrum_value[i] - thermal_background[i]) *
1607 (spectrum_value[i] - thermal_background[i]);
1608 }
1609
1610 if (tmp != NULL) cpl_free(tmp);
1611 return result;
1612}
1613
1614
1615
1616/* !!!!!!!!! UNDER LICENSE !!!!!!! */
1617/*----------------------------------------------------------------------------*/
1640/*----------------------------------------------------------------------------*/
1641#define GET_PSUM \
1642 for (j=1;j<=ndim;j++) {\
1643 for (sum=0.0,i=1;i<=mpts;i++) sum += p[i][j];\
1644 psum[j]=sum;}
1645#define SWAP(a,b) {swap=(a);(a)=(b);(b)=swap;}
1646static void amoeba(
1647 double **p,
1648 double y[],
1649 int ndim,
1650 double ftol,
1651 double (*funk)(double []),
1652 int * nfunk)
1653{
1654 int i,ihi,ilo,inhi,j,mpts=ndim+1;
1655 double rtol, sum, swap, ysave, ytry, *psum = NULL, d;
1656
1657 psum=cpl_calloc(ndim+1, sizeof(double));
1658 *nfunk=0;
1659 GET_PSUM
1660 for (;;) {
1661 ilo=1;
1662 ihi = y[1]>y[2] ? (inhi=2,1) : (inhi=1,2);
1663 for (i=1;i<=mpts;i++) {
1664 if (y[i] <= y[ilo]) {
1665 ilo=i;
1666 }
1667 if (y[i] > y[ihi]) {
1668 inhi=ihi;
1669 ihi=i;
1670 } else if (y[i] > y[inhi] && i != ihi) inhi=i;
1671 }
1672 d = fabs(y[ihi])+fabs(y[ilo]);
1673 if (d == 0.0) {
1674 rtol = ftol / 2. ; //succeeds next if statement -> breaks loop
1675 } else {
1676 rtol=2.0*fabs(y[ihi]-y[ilo])/d;
1677 }
1678 if (rtol < ftol) {
1679 SWAP(y[1],y[ilo])
1680 for (i=1;i<=ndim;i++) SWAP(p[1][i],p[ilo][i])
1681 break;
1682 }
1683 if (*nfunk >= 5000) {
1684 //printf("5000 exceeded\n");
1685 *nfunk = -1;
1686 return;
1687 }
1688 *nfunk += 2;
1689 ytry=amotry(p,y,psum,ndim,funk,ihi,-1.0);
1690 if (ytry <= y[ilo])
1691 ytry=amotry(p,y,psum,ndim,funk,ihi,2.0);
1692 else if (ytry >= y[inhi]) {
1693 ysave=y[ihi];
1694 ytry=amotry(p,y,psum,ndim,funk,ihi,0.5);
1695 if (ytry >= ysave) {
1696 for (i=1;i<=mpts;i++) {
1697 if (i != ilo) {
1698 for (j=1;j<=ndim;j++) {
1699 p[i][j]=psum[j]=0.5*(p[i][j]+p[ilo][j]);
1700 }
1701 y[i]=(*funk)(psum);
1702 }
1703 }
1704 *nfunk += ndim;
1705 GET_PSUM
1706 }
1707 } else {
1708 --(*nfunk);
1709 }
1710 }
1712}
1713#undef SWAP
1714#undef GET_PSUM
1715
1716/*----------------------------------------------------------------------------*/
1734/*----------------------------------------------------------------------------*/
1735static double amotry(
1736 double ** p,
1737 double y[],
1738 double psum[],
1739 int ndim,
1740 double (*funk)(double []),
1741 int ihi,
1742 double fac)
1743{
1744 int j;
1745 double fac1,fac2,ytry,*ptry=NULL;
1746
1747 ptry=cpl_calloc(ndim+1, sizeof(double));
1748 fac1=(1.0-fac)/ndim;
1749 fac2=fac1-fac;
1750 for (j=1;j<=ndim;j++) ptry[j]=psum[j]*fac1-p[ihi][j]*fac2;
1751 ytry=(*funk)(ptry);
1752 if (ytry < y[ihi]) {
1753 y[ihi]=ytry;
1754 for (j=1;j<=ndim;j++) {
1755 psum[j] += ptry[j]-p[ihi][j];
1756 p[ihi][j]=ptry[j];
1757 }
1758 }
1760 return ytry;
1761}
1762/* !!!!!!!!! END UNDER LICENSE !!!!!!! */
1763
1764/* ************************************************************************* */
1765/* ****************************** ERIS STRETCH ***************************** */
1766/* ************************************************************************* */
1767
1768/*----------------------------------------------------------------------------*/
1798/*----------------------------------------------------------------------------*/
1799static cpl_imagelist * eris_ifu_priv_sky_stretch(
1800 cpl_imagelist * obj,
1801 cpl_imagelist * sky,
1802 float min_frac,
1803 int poly_degree,
1804 int resampling_method,
1805 int plot)
1806{
1807 cpl_vector * obj_spec ;
1808 cpl_vector * sky_spec ;
1809 cpl_imagelist * new_sky ;
1810 cpl_image * mask ;
1811 cpl_polynomial * transf_poly ;
1812 cpl_polynomial * new_transf_poly ;
1813 cpl_bivector * matching_lines ;
1814 cpl_bivector * new_matching_lines ;
1815
1816 /* Check inputs */
1817 if (obj == NULL || sky == NULL) return NULL ;
1818 if (resampling_method != 1 && resampling_method != 2) return NULL ;
1819
1820 /* mask is a binary image : 0 -> obj / 1 -> background */
1821 mask = eris_ifu_lcorr_create_object_mask(obj, min_frac, NULL, NULL);
1822
1823 /* Get the background spectrum from obj and sky cubes using mask */
1824 if (eris_ifu_sky_tweak_get_spectra_simple(obj, sky, mask, &obj_spec,
1825 &sky_spec) != CPL_ERROR_NONE) {
1826 cpl_msg_error(cpl_func, "Cannot extract the spectra from cubes") ;
1827 cpl_image_delete(mask) ;
1828 return NULL ;
1829 }
1830
1831 /* Create the transformation poynomial */
1832 if ((transf_poly = eris_ifu_stretch_get_poly(obj_spec, sky_spec, 5, poly_degree,
1833 &matching_lines))==NULL) {
1834 cpl_msg_error(cpl_func, "Cannot compute the transformation polynomial");
1835 cpl_vector_delete(obj_spec) ;
1836 cpl_vector_delete(sky_spec) ;
1837 cpl_image_delete(mask) ;
1838 return NULL ;
1839 }
1840 cpl_vector_delete(obj_spec) ;
1841 cpl_vector_delete(sky_spec) ;
1842
1843 /* Apply the sky cube transformation */
1844 if (resampling_method == 1)
1845 new_sky = eris_ifu_stretch_apply_linear(sky, transf_poly) ;
1846 else
1847 new_sky = eris_ifu_stretch_apply_spline(sky, transf_poly) ;
1848 if (new_sky == NULL) {
1849 cpl_msg_error(cpl_func, "Cannot apply the transformation");
1850 cpl_polynomial_delete(transf_poly) ;
1851 cpl_image_delete(mask) ;
1852 return NULL ;
1853 }
1854
1855 /* FOR DEBUG PUPOSE - Check the new sky */
1856 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
1857 if (eris_ifu_sky_tweak_get_spectra_simple(obj, new_sky, mask, &obj_spec,
1858 &sky_spec) != CPL_ERROR_NONE) {
1859 cpl_msg_error(cpl_func, "Cannot extract the spectra from cubes") ;
1860 cpl_image_delete(mask) ;
1861 cpl_bivector_delete(matching_lines) ;
1862 cpl_polynomial_delete(transf_poly) ;
1863 cpl_imagelist_delete(new_sky) ;
1864 return NULL ;
1865 }
1866 if ((new_transf_poly = eris_ifu_stretch_get_poly(obj_spec, sky_spec, 5,
1867 poly_degree, &new_matching_lines))==NULL) {
1868 cpl_msg_error(cpl_func, "Cannot compute the transf. polynomial");
1869 cpl_vector_delete(obj_spec) ;
1870 cpl_vector_delete(sky_spec) ;
1871 cpl_image_delete(mask) ;
1872 cpl_bivector_delete(matching_lines) ;
1873 cpl_polynomial_delete(transf_poly) ;
1874 cpl_imagelist_delete(new_sky) ;
1875 return NULL ;
1876 }
1877 cpl_vector_delete(obj_spec) ;
1878 cpl_vector_delete(sky_spec) ;
1879
1880 cpl_polynomial_dump(transf_poly, stdout) ;
1881 /* cpl_polynomial_dump(new_transf_poly, stdout) ; */
1882
1883 if (plot) {
1884 eris_ifu_stretch_plot_positions_differences(matching_lines,
1885 new_matching_lines) ;
1886 eris_ifu_stretch_check(obj, sky, new_sky, mask) ;
1887 }
1888 cpl_bivector_delete(new_matching_lines) ;
1889 cpl_polynomial_delete(new_transf_poly) ;
1890 }
1891
1892 cpl_bivector_delete(matching_lines) ;
1893 cpl_polynomial_delete(transf_poly) ;
1894 cpl_image_delete(mask) ;
1895
1896 return new_sky ;
1897}
1898
1899static cpl_polynomial * eris_ifu_stretch_get_poly(
1900 const cpl_vector * obj,
1901 const cpl_vector * sky,
1902 double min_gap,
1903 int degree,
1904 cpl_bivector ** matching_lines)
1905{
1906 cpl_size deg_loc ;
1907 cpl_size nb_lines ;
1908 cpl_matrix * matchedx ;
1909 cpl_polynomial * fitted ;
1910
1911 /* Check entries */
1912 if (obj == NULL || sky == NULL || matching_lines == NULL) return NULL ;
1913
1914 /* Initialise */
1915 deg_loc = (cpl_size)degree ;
1916
1917 /* Detect Matching lines */
1918 *matching_lines=eris_ifu_strech_get_matching_lines(obj, sky, min_gap, 1,degree);
1919 nb_lines = cpl_bivector_get_size(*matching_lines) ;
1920
1921 /* Compute the fit */
1922 matchedx = cpl_matrix_wrap(1, nb_lines,
1923 cpl_vector_get_data(cpl_bivector_get_x(*matching_lines)));
1924 fitted = cpl_polynomial_new(1);
1925 if (cpl_polynomial_fit(fitted, matchedx, NULL,
1926 cpl_bivector_get_y(*matching_lines), NULL, CPL_FALSE,
1927 NULL, &deg_loc) != CPL_ERROR_NONE) {
1928 cpl_msg_error(cpl_func, "Cannot fit the polynomial") ;
1929 cpl_polynomial_delete(fitted);
1930 cpl_matrix_unwrap(matchedx);
1931 cpl_bivector_delete(*matching_lines) ;
1932 return NULL ;
1933 }
1934 cpl_matrix_unwrap(matchedx);
1935 return fitted ;
1936}
1937
1938/* TODO */
1939/*----------------------------------------------------------------------------*/
1946/*----------------------------------------------------------------------------*/
1947static cpl_imagelist * eris_ifu_stretch_apply_spline(
1948 cpl_imagelist * in,
1949 cpl_polynomial * stretch)
1950{
1951 cpl_imagelist * out ;
1952 cpl_vector ** zlines ;
1953 cpl_vector ** resampled_zlines ;
1954 double * image_data ;
1955 cpl_vector * pos ;
1956 double * ppos ;
1957 double * resampled_array ;
1958 cpl_vector * new_pos ;
1959 int spec_size, nx, ny, i, j, k ;
1960
1961 /* Initialize */
1962 spec_size = cpl_imagelist_get_size(in) ;
1963 nx = cpl_image_get_size_x(cpl_imagelist_get_const(in, 0)) ;
1964 ny = cpl_image_get_size_x(cpl_imagelist_get_const(in, 0)) ;
1965
1966 /* Create the z vectors */
1967 zlines = cpl_malloc(nx*ny*sizeof(cpl_vector*)) ;
1968 for (i=0 ; i<nx ; i++)
1969 for (j=0 ; j<ny ; j++)
1970 zlines[i+j*nx] = cpl_vector_new(spec_size) ;
1971
1972 /* Fill the z vectors */
1973 for (k=0 ; k<spec_size ; k++) {
1974 image_data = cpl_image_get_data_double(cpl_imagelist_get(in, k)) ;
1975 for (i=0 ; i<nx ; i++)
1976 for (j=0 ; j<ny ; j++)
1977 if (!isnan(image_data[i+j*nx]))
1978 cpl_vector_set(zlines[i+j*nx], k, image_data[i+j*nx]) ;
1979 else
1980 cpl_vector_set(zlines[i+j*nx], k, 0.0) ;
1981 }
1982
1983 /* Create the positions vector */
1984 pos = cpl_vector_new(spec_size) ;
1985 ppos = cpl_vector_get_data(pos);
1986 for (i=0 ; i<spec_size ; i++) ppos[i] = i+1 ;
1987
1988 /* Create the new positions vector */
1989 new_pos = cpl_vector_new(spec_size) ;
1990 cpl_vector_fill_polynomial(new_pos, stretch, 1, 1) ;
1991
1992 /* Extend the lambdas for the border effects */
1993 if (cpl_vector_get(new_pos, 0) < 1.0) cpl_vector_set(new_pos, 0, 1.0) ;
1994 if (cpl_vector_get(new_pos, spec_size-1) > spec_size-1)
1995 cpl_vector_set(new_pos, spec_size-1, spec_size-1) ;
1996
1997 resampled_zlines = cpl_malloc(nx*ny*sizeof(cpl_vector*)) ;
1998 /* Run the interpolations */
1999 cpl_error_code retErr;
2000 for (i=0 ; i<nx ; i++) {
2001 for (j=0 ; j<ny ; j++) {
2002 resampled_array = cpl_malloc(spec_size * sizeof(double));
2004 ppos, cpl_vector_get_data(zlines[i+j*nx]), spec_size,
2005 cpl_vector_get_data(new_pos), resampled_array, spec_size,
2006 -1);
2007 if (retErr != CPL_ERROR_NONE) {
2008 printf("ERROR: The function eris_ifu_1d_interpolation called in eris_ifu_stretch_apply_spline returned the error %d\n", retErr);
2009 printf("%s\n", cpl_error_get_message_default(retErr));
2010 }
2011/*
2012 resampled_array = cubicspline_irreg_irreg(spec_size,
2013 ppos, cpl_vector_get_data(zlines[i+j*nx]),
2014 spec_size, cpl_vector_get_data(new_pos), NATURAL) ;
2015*/
2016
2017 resampled_zlines[i+j*nx] = cpl_vector_wrap(spec_size,
2018 resampled_array) ;
2019 }
2020 }
2021 cpl_vector_delete(new_pos) ;
2022 cpl_vector_delete(pos) ;
2023 //cpl_free(resampled_array);
2024
2025 /* Deallocate specs */
2026 for (i=0 ; i<nx ; i++)
2027 for (j=0 ; j<ny ; j++)
2028 cpl_vector_delete(zlines[i+j*nx]) ;
2029 cpl_free(zlines) ;
2030
2031 /* Fill the output cube */
2032 out = cpl_imagelist_duplicate(in) ;
2033 for (k=0 ; k<spec_size ; k++) {
2034 image_data = cpl_image_get_data_double(cpl_imagelist_get(out, k)) ;
2035 for (i=0 ; i<nx ; i++)
2036 for (j=0 ; j<ny ; j++)
2037 image_data[i+j*nx]= cpl_vector_get(resampled_zlines[i+j*nx],k) ;
2038 }
2039
2040 /* Deallocate resampled_specs */
2041 for (i=0 ; i<nx ; i++)
2042 for (j=0 ; j<ny ; j++)
2043 cpl_free(cpl_vector_unwrap(resampled_zlines[i+j*nx]));
2044// cpl_vector_delete(resampled_zlines[i+j*nx]) ;
2045 cpl_free(resampled_zlines) ;
2046 return out ;
2047}
2048
2049
2050/*----------------------------------------------------------------------------*/
2057/*----------------------------------------------------------------------------*/
2058static cpl_imagelist * eris_ifu_stretch_apply_linear(
2059 cpl_imagelist * in,
2060 cpl_polynomial * stretch)
2061{
2062 cpl_imagelist * out ;
2063 cpl_vector ** zlines ;
2064 cpl_vector ** resampled_zlines ;
2065 double * image_data ;
2066 cpl_vector * pos ;
2067 double * ppos ;
2068 cpl_vector * new_pos ;
2069 cpl_bivector * ref_spec ;
2070 cpl_bivector * resampled_spec ;
2071 int spec_size, nx, ny, i, j, k ;
2072
2073 /* Initialize */
2074 spec_size = cpl_imagelist_get_size(in) ;
2075 nx = cpl_image_get_size_x(cpl_imagelist_get_const(in, 0)) ;
2076 ny = cpl_image_get_size_x(cpl_imagelist_get_const(in, 0)) ;
2077
2078 /* Create the z vectors */
2079 zlines = cpl_malloc(nx*ny*sizeof(cpl_vector*)) ;
2080 for (i=0 ; i<nx ; i++)
2081 for (j=0 ; j<ny ; j++)
2082 zlines[i+j*nx] = cpl_vector_new(spec_size) ;
2083
2084 /* Fill the z vectors */
2085 for (k=0 ; k<spec_size ; k++) {
2086 image_data = cpl_image_get_data_double(cpl_imagelist_get(in, k)) ;
2087 for (i=0 ; i<nx ; i++)
2088 for (j=0 ; j<ny ; j++)
2089 if (!isnan(image_data[i+j*nx]))
2090 cpl_vector_set(zlines[i+j*nx], k, image_data[i+j*nx]) ;
2091 else
2092 cpl_vector_set(zlines[i+j*nx], k, 0.0) ;
2093 }
2094
2095 /* Create the positions vector */
2096 pos = cpl_vector_new(spec_size) ;
2097 ppos = cpl_vector_get_data(pos);
2098 for (i=0 ; i<spec_size ; i++) ppos[i] = i+1 ;
2099
2100 /* Create the new positions vector */
2101 new_pos = cpl_vector_new(spec_size) ;
2102 cpl_vector_fill_polynomial(new_pos, stretch, 1, 1) ;
2103
2104 /* Extend the lambdas for the border effects */
2105 if (cpl_vector_get(new_pos, 0) < 1.0) cpl_vector_set(new_pos, 0, 1.0) ;
2106 if (cpl_vector_get(new_pos, spec_size-1) > spec_size-1)
2107 cpl_vector_set(new_pos, spec_size-1, spec_size-1) ;
2108
2109 resampled_zlines = cpl_malloc(nx*ny*sizeof(cpl_vector*)) ;
2110 /* Run the interpolations */
2111 for (i=0 ; i<nx ; i++) {
2112 for (j=0 ; j<ny ; j++) {
2113 /* Allocate the vector holding the resampled sky */
2114 resampled_zlines[i+j*nx] = cpl_vector_new(spec_size) ;
2115
2116 /* Wrap the bivectors */
2117 ref_spec = cpl_bivector_wrap_vectors(pos, zlines[i+j*nx]);
2118 resampled_spec = cpl_bivector_wrap_vectors(new_pos,
2119 resampled_zlines[i+j*nx]) ;
2120 /* Apply the resampling */
2121 cpl_bivector_interpolate_linear(resampled_spec, ref_spec) ;
2122
2123 /* Unwrap */
2124 cpl_bivector_unwrap_vectors(ref_spec) ;
2125 cpl_bivector_unwrap_vectors(resampled_spec) ;
2126 }
2127 }
2128 cpl_vector_delete(new_pos) ;
2129 cpl_vector_delete(pos) ;
2130
2131 /* Deallocate specs */
2132 for (i=0 ; i<nx ; i++)
2133 for (j=0 ; j<ny ; j++)
2134 cpl_vector_delete(zlines[i+j*nx]) ;
2135 cpl_free(zlines) ;
2136
2137 /* Fill the output cube */
2138 out = cpl_imagelist_duplicate(in) ;
2139 for (k=0 ; k<spec_size ; k++) {
2140 image_data = cpl_image_get_data_double(cpl_imagelist_get(out, k)) ;
2141 for (i=0 ; i<nx ; i++)
2142 for (j=0 ; j<ny ; j++)
2143 image_data[i+j*nx]= cpl_vector_get(resampled_zlines[i+j*nx],k) ;
2144 }
2145
2146 /* Deallocate resampled_specs */
2147 for (i=0 ; i<nx ; i++)
2148 for (j=0 ; j<ny ; j++)
2149 cpl_vector_delete(resampled_zlines[i+j*nx]) ;
2150 cpl_free(resampled_zlines) ;
2151 return out ;
2152}
2153
2154static int eris_ifu_stretch_check(
2155 cpl_imagelist * obj,
2156 cpl_imagelist * sky,
2157 cpl_imagelist * new_sky,
2158 cpl_image * mask)
2159{
2160 cpl_vector * spec1 ;
2161 cpl_vector * spec2 ;
2162
2163 eris_ifu_sky_tweak_get_spectra_simple(obj, sky, mask, &spec1, &spec2);
2164 cpl_plot_vector("set grid;set xlabel 'pix';", "t 'obj' w lines", "",
2165 spec1);
2166 cpl_plot_vector("set grid;set xlabel 'pix';",
2167 "t 'sky before stretching' w lines", "", spec2);
2168 cpl_vector_subtract(spec1, spec2) ;
2169
2170 cpl_plot_vector("set grid;set xlabel 'pix';",
2171 "t 'obj-sky before stretching' w lines", "",
2172 spec1);
2173 cpl_vector_delete(spec1) ;
2174 cpl_vector_delete(spec2) ;
2175
2176 eris_ifu_sky_tweak_get_spectra_simple(obj, new_sky, mask, &spec1, &spec2);
2177 cpl_plot_vector("set grid;set xlabel 'pix';",
2178 "t 'sky after stretching' w lines", "", spec2);
2179 cpl_vector_subtract(spec1, spec2) ;
2180
2181 cpl_plot_vector("set grid;set xlabel 'pix';",
2182 "t 'obj-sky after stretching' w lines", "",
2183 spec1);
2184 cpl_vector_delete(spec1) ;
2185 cpl_vector_delete(spec2) ;
2186
2187 return 0 ;
2188}
2189
2190static int eris_ifu_stretch_plot_positions_differences(
2191 cpl_bivector * matching_lines,
2192 cpl_bivector * new_matching_lines)
2193{
2194 cpl_vector * diff_values ;
2195 cpl_bivector * diff ;
2196
2197 /* BEFORE */
2198 diff_values = cpl_vector_duplicate(cpl_bivector_get_x(matching_lines)) ;
2199 cpl_vector_subtract(diff_values, cpl_bivector_get_y(matching_lines)) ;
2200 diff = cpl_bivector_wrap_vectors(cpl_bivector_get_x(matching_lines),
2201 diff_values) ;
2202 cpl_plot_bivector("set grid;", "t 'Pos. diff. BEFORE STRECHING'", "", diff);
2203 cpl_bivector_unwrap_vectors(diff) ;
2204 cpl_vector_delete(diff_values) ;
2205
2206 /* AFTER */
2207 diff_values = cpl_vector_duplicate(cpl_bivector_get_x(new_matching_lines)) ;
2208 cpl_vector_subtract(diff_values, cpl_bivector_get_y(new_matching_lines)) ;
2209 diff = cpl_bivector_wrap_vectors(cpl_bivector_get_x(new_matching_lines),
2210 diff_values) ;
2211 cpl_plot_bivector("set grid;", "t 'Pos. diff. AFTER STRECHING'", "", diff);
2212 cpl_bivector_unwrap_vectors(diff) ;
2213 cpl_vector_delete(diff_values) ;
2214
2215 return 0 ;
2216}
2217
2218/* TODO */
2219static cpl_bivector * eris_ifu_strech_get_matching_lines(
2220 const cpl_vector * obj,
2221 const cpl_vector * sky,
2222 double min_gap,
2223 int remove_outliers,
2224 int degree)
2225{
2226 cpl_vector * tmp_vec ;
2227 cpl_vector * obj_lines ;
2228 cpl_vector * obj_lines_clean ;
2229 double * pobj_lines ;
2230 cpl_vector * sky_lines ;
2231 cpl_vector * sky_lines_clean ;
2232 double * psky_lines ;
2233 cpl_vector * diff ;
2234 double * obj_lines_arr ;
2235 double * sky_lines_arr ;
2236 double obj_pos, sky_pos ;
2237 cpl_size sky_idx, nb_lines ;
2238 double fwhm, kappa, threshold ;
2239 int i, nb_found ;
2240
2241 /* Check entries */
2242 if (obj == NULL || sky == NULL) return NULL ;
2243
2244 /* Initialise */
2245 fwhm = 5.0 ;
2246 kappa = 3 ;
2247
2248 /* TODO */
2249 /* Replace by keeping the 20 brightest lines dispatched on the detector */
2250
2251 /* Detect lines in obj */
2252 /* Pre-process before detection */
2253 threshold = fabs(cpl_vector_get_mean(obj) + cpl_vector_get_stdev(obj)) ;
2254 tmp_vec = cpl_vector_duplicate(obj) ;
2255 for (i=0 ; i<cpl_vector_get_size(tmp_vec) ; i++) {
2256 if (cpl_vector_get(tmp_vec, i) < threshold)
2257 cpl_vector_set(tmp_vec, i, 0.0);
2258 }
2259 if ((obj_lines = irplib_spectrum_detect_peaks(tmp_vec, fwhm,
2260 kappa, 0, NULL, NULL)) == NULL) {
2261 cpl_msg_error(cpl_func, "Cannot detect peaks from obj") ;
2262 cpl_vector_delete(tmp_vec) ;
2263 return NULL ;
2264 }
2265 cpl_vector_delete(tmp_vec) ;
2266
2267 /* Detect lines in sky */
2268 /* Pre-process before detection */
2269 threshold = fabs(cpl_vector_get_mean(sky) + cpl_vector_get_stdev(sky)) ;
2270 tmp_vec = cpl_vector_duplicate(sky) ;
2271 for (i=0 ; i<cpl_vector_get_size(tmp_vec) ; i++) {
2272 if (cpl_vector_get(tmp_vec, i) < threshold)
2273 cpl_vector_set(tmp_vec, i, 0.0);
2274 }
2275 if ((sky_lines = irplib_spectrum_detect_peaks(tmp_vec, fwhm,
2276 kappa, 0, NULL, NULL)) == NULL) {
2277 cpl_msg_error(cpl_func, "Cannot detect peaks from sky") ;
2278 cpl_vector_delete(obj_lines) ;
2279 cpl_vector_delete(tmp_vec) ;
2280 return NULL ;
2281 }
2282 cpl_vector_delete(tmp_vec) ;
2283
2284 cpl_msg_debug(cpl_func, "Detected %"CPL_SIZE_FORMAT" lines from obj",
2285 cpl_vector_get_size(obj_lines));
2286 cpl_msg_debug(cpl_func, "Detected %"CPL_SIZE_FORMAT" lines from sky",
2287 cpl_vector_get_size(sky_lines));
2288
2289 /* Obj lines need to be separated - Remove double lines */
2290 cpl_vector_sort(obj_lines, CPL_SORT_ASCENDING) ;
2291 nb_lines = cpl_vector_get_size(obj_lines) ;
2292 pobj_lines = cpl_vector_get_data(obj_lines) ;
2293 obj_lines_arr = cpl_malloc(nb_lines * sizeof(double)) ;
2294 /* Always keep the first line */
2295 obj_lines_arr[0] = pobj_lines[0] ;
2296 nb_found = 1 ;
2297 for (i=1 ; i<nb_lines ; i++) {
2298 /* If the lines positions are too close to neighbor, remove them */
2299 if (fabs(pobj_lines[i]-pobj_lines[i-1]) > min_gap) {
2300 obj_lines_arr[nb_found] = pobj_lines[i] ;
2301 nb_found++ ;
2302 }
2303 }
2304 /* Create the new obj_lines */
2305 cpl_vector_delete(obj_lines) ;
2306 obj_lines = cpl_vector_new(nb_found) ;
2307 pobj_lines = cpl_vector_get_data(obj_lines) ;
2308 for (i=0 ; i<nb_found ; i++) pobj_lines[i] = obj_lines_arr[i] ;
2309 cpl_free(obj_lines_arr) ;
2310 nb_lines = cpl_vector_get_size(obj_lines) ;
2311
2312 cpl_msg_debug(cpl_func,
2313 "Detected %"CPL_SIZE_FORMAT" separated lines from obj",
2314 cpl_vector_get_size(obj_lines));
2315
2316 /* Associate obj and sky lines */
2317 obj_lines_arr = cpl_malloc(nb_lines * sizeof(double)) ;
2318 sky_lines_arr = cpl_malloc(nb_lines * sizeof(double)) ;
2319 nb_found = 0 ;
2320 cpl_vector_sort(sky_lines, CPL_SORT_ASCENDING) ;
2321 for (i=0 ; i<nb_lines ; i++) {
2322 obj_pos = cpl_vector_get(obj_lines, i) ;
2323 sky_idx = cpl_vector_find(sky_lines, obj_pos) ;
2324 sky_pos = cpl_vector_get(sky_lines, sky_idx) ;
2325 /* If the lines positions are close enough, keep them */
2326 if (fabs(obj_pos-sky_pos) < min_gap) {
2327 obj_lines_arr[nb_found] = obj_pos ;
2328 sky_lines_arr[nb_found] = sky_pos ;
2329 nb_found++ ;
2330 }
2331 }
2332
2333 /* Create the new lines vectors */
2334 cpl_vector_delete(obj_lines) ;
2335 cpl_vector_delete(sky_lines) ;
2336 obj_lines = cpl_vector_new(nb_found) ;
2337 sky_lines = cpl_vector_new(nb_found) ;
2338 nb_lines = cpl_vector_get_size(obj_lines) ;
2339 pobj_lines = cpl_vector_get_data(obj_lines) ;
2340 psky_lines = cpl_vector_get_data(sky_lines) ;
2341 for (i=0 ; i<nb_found ; i++) {
2342 pobj_lines[i] = obj_lines_arr[i] ;
2343 psky_lines[i] = sky_lines_arr[i] ;
2344 }
2345 cpl_free(obj_lines_arr) ;
2346 cpl_free(sky_lines_arr) ;
2347
2348 /* Remove outliers */
2349 if (remove_outliers) {
2350 diff = cpl_vector_duplicate(obj_lines) ;
2351 cpl_vector_subtract(diff, sky_lines) ;
2352 threshold = fabs(cpl_vector_get_median_const(diff)) +
2353 2 * cpl_vector_get_stdev(diff) ;
2354 nb_found = 0 ;
2355 for (i=0 ; i<cpl_vector_get_size(diff) ; i++)
2356 if (fabs(cpl_vector_get(diff, i)) < threshold) nb_found++ ;
2357 obj_lines_clean = cpl_vector_new(nb_found) ;
2358 sky_lines_clean = cpl_vector_new(nb_found) ;
2359 nb_found = 0 ;
2360 for (i=0 ; i<cpl_vector_get_size(diff) ; i++)
2361 if (fabs(cpl_vector_get(diff, i)) < threshold) {
2362 cpl_vector_set(obj_lines_clean, nb_found,
2363 cpl_vector_get(obj_lines, i)) ;
2364 cpl_vector_set(sky_lines_clean, nb_found,
2365 cpl_vector_get(sky_lines, i)) ;
2366 nb_found++ ;
2367 }
2368 cpl_vector_delete(diff) ;
2369 cpl_vector_delete(obj_lines) ;
2370 cpl_vector_delete(sky_lines) ;
2371 obj_lines = obj_lines_clean ;
2372 sky_lines = sky_lines_clean ;
2373 }
2374
2375 /* Check if there are enough matched lines */
2376 if (nb_found <= degree) {
2377 cpl_msg_error(cpl_func, "Not enough match for the fit") ;
2378 cpl_vector_delete(obj_lines) ;
2379 cpl_vector_delete(sky_lines) ;
2380 return NULL ;
2381 }
2382
2383 cpl_msg_debug(cpl_func, "Matched %"CPL_SIZE_FORMAT" lines",
2384 cpl_vector_get_size(obj_lines));
2385
2386 return cpl_bivector_wrap_vectors(obj_lines, sky_lines);
2387}
cpl_error_code eris_ifu_1d_interpolation(double *xIn, double *yIn, int nIn, double *xOut, double *yOut, int nOut, const int interType)
Perform 1D interpolation using GSL routines.
cpl_image * eris_ifu_lcorr_create_object_mask(const cpl_imagelist *cube, double min_frac, const cpl_vector *lambda, const cpl_vector *range)
Create spaxel selection mask for spectrum extraction.
cpl_vector * eris_ifu_lcorr_create_lambda_vector(const cpl_propertylist *header)
Create wavelength vector from FITS header WCS keywords.
int eris_ifu_plot_cube_background(cpl_imagelist *obj)
Extract background spectrum from cube and plot it.
cpl_imagelist * eris_ifu_sky_tweak(cpl_imagelist *obj, cpl_imagelist *sky, const cpl_propertylist *header, float min_frac, int tbsub, int skip_last, int stretch, int stretch_degree, int stretch_resampling, int plot, cpl_imagelist **new_sky)
Main sky tweaking and subtraction function.
cpl_vector * eris_ifu_idl_values_at_indices(const cpl_vector *data, const cpl_vector *indices)
Returns a vector of given indices.
void eris_ifu_free_double_array(double **item)
Free memory and set pointer to null.
cpl_vector * eris_ifu_idl_where(const cpl_vector *data, double val, int op)
Implements the where-function known from IDL.
int eris_ifu_is_nan_or_inf(double A)
Checks if a value is nan, inf or -inf.
cpl_error_code eris_check_error_code(const char *func_id)
handle CPL errors
Definition: eris_utils.c:56