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