ERIS Pipeline Reference Manual 1.8.10
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/*----------------------------------------------------------------------------*/
139/*----------------------------------------------------------------------------*/
140
143/*----------------------------------------------------------------------------*/
152/*----------------------------------------------------------------------------*/
153int eris_ifu_plot_cube_background(cpl_imagelist * obj)
154{
155 cpl_image * mask ;
156 cpl_vector * obj_spec ;
157 cpl_vector * sky_spec ;
158
159 /* Check inputs */
160 if (obj == NULL) return -1 ;
161
162 /* mask is a binary image : 0 -> obj / 1 -> background */
163 mask = eris_ifu_lcorr_create_object_mask(obj, .3, NULL, NULL);
164
165 /* Get the background spectrum from obj and sky cubes using mask */
166 if (eris_ifu_sky_tweak_get_spectra_simple(obj, obj, mask, &obj_spec,
167 &sky_spec) != CPL_ERROR_NONE) {
168 cpl_msg_error(cpl_func, "Cannot extract the spectra from cubes") ;
169 cpl_image_delete(mask) ;
170 return -1 ;
171 }
172
173 cpl_plot_vector("set grid;set xlabel 'pix';", "t 'CUBE BGD' w lines", "",
174 obj_spec);
175
176 cpl_vector_delete(obj_spec) ;
177 cpl_vector_delete(sky_spec) ;
178 return 0 ;
179}
180
181/*----------------------------------------------------------------------------*/
200/*----------------------------------------------------------------------------*/
201cpl_imagelist * eris_ifu_sky_tweak(
202 cpl_imagelist * obj,
203 cpl_imagelist * sky,
204 const cpl_propertylist * header,
205 float min_frac,
206 int tbsub,
207 int skip_last,
208 int stretch,
209 int stretch_degree,
210 int stretch_resampling,
211 int plot,
212 cpl_imagelist ** new_sky)
213{
214 cpl_imagelist * new_obj ;
215 cpl_image * mask ;
216 cpl_bivector * obj_spec = NULL;
217 cpl_bivector * sky_spec = NULL;
218 cpl_bivector * thermal_backg ;
219 cpl_bivector * vscales ;
220 cpl_vector * lambda ;
221 int nx, ny, nz, ix, kx, snx, sny, snz, kmax, first_nonan ;
222
223 /* Check Entries */
224 cpl_ensure(obj, CPL_ERROR_NULL_INPUT, NULL);
225 cpl_ensure(sky, CPL_ERROR_NULL_INPUT, NULL);
226 cpl_ensure(header, CPL_ERROR_NULL_INPUT, NULL);
227 cpl_ensure(new_sky, CPL_ERROR_NULL_INPUT, NULL);
228 cpl_ensure(min_frac > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
229 cpl_ensure(stretch_resampling > 0 && stretch_resampling < 3, CPL_ERROR_ILLEGAL_INPUT, NULL);
230
231 nx = cpl_image_get_size_x(cpl_imagelist_get_const(obj, 0));
232 ny = cpl_image_get_size_y(cpl_imagelist_get_const(obj, 0));
233 nz = cpl_imagelist_get_size(obj);
234 snx = cpl_image_get_size_x(cpl_imagelist_get_const(sky, 0));
235 sny = cpl_image_get_size_y(cpl_imagelist_get_const(sky, 0));
236 snz = cpl_imagelist_get_size(sky);
237 if (nx!=snx || ny!=sny || nz!=snz) {
238 cpl_msg_error(__func__, "Illegal inputs") ;
239 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
240 return NULL ;
241 }
242
243 /* Start by applying the sky stretching if wished */
244 if (stretch) {
245 *new_sky = eris_ifu_priv_sky_stretch(obj, sky, .3, stretch_degree,
246 stretch_resampling, plot) ;
247 } else {
248 *new_sky = cpl_imagelist_duplicate(sky) ;
249 }
250
251 /* Create wavelengths vector corresponding to the input cubes */
253 if (nz != cpl_vector_get_size(lambda)) {
254 cpl_msg_error(__func__, "Illegal inputs") ;
255 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
256 return NULL ;
257 }
258
259 /* mask is a binary image : 0 -> obj / 1 -> background */
260 mask = eris_ifu_lcorr_create_object_mask(obj, min_frac, NULL, NULL);
261 if (cpl_msg_get_level() == CPL_MSG_DEBUG)
262 cpl_image_save(mask, "mask.fits", CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
263
264 /* Get the background spectrum (using mask) from obj and sky cubes */
265// eris_ifu_sky_tweak_get_spectra(obj, *new_sky, lambda, mask, 1,
266// &obj_spec, &sky_spec, &first_nonan);
267 eris_ifu_sky_tweak_get_spectra(obj, *new_sky, lambda, mask, 0,
268 &obj_spec, &sky_spec, &first_nonan);
269
270 /* Get the corrections factors for each sub-band */
271 vscales = eris_ifu_sky_tweak_correct_vibrational_trans(obj_spec,
272 sky_spec, skip_last, plot);
273 if (cpl_msg_get_level() == CPL_MSG_DEBUG && plot)
274 cpl_plot_bivector("set title \"SCALES\";", "w lines", "",vscales);
275
276 /* Get the thermal bgd */
277 thermal_backg = eris_ifu_sky_tweak_thermal_bgd(obj_spec, 1.0);
278
279 /* Re-try if the computation failed (PIPE-5528) */
280 if (thermal_backg == NULL) {
281 cpl_error_reset() ;
282 cpl_msg_indent_more() ;
283 cpl_msg_warning(__func__,
284 "Thermal Bgd failed, re-try by clipping highest values") ;
285 thermal_backg = eris_ifu_sky_tweak_thermal_bgd(obj_spec, 0.98);
286 if (thermal_backg == NULL) {
287 cpl_msg_warning(__func__,
288 "Recovery failed - skip the thermal background correction");
289 cpl_error_reset() ;
290 } else {
291 cpl_msg_info(__func__, "Recovery succeeded");
292 }
293 cpl_msg_indent_less() ;
294 }
295
296 if (cpl_msg_get_level() == CPL_MSG_DEBUG && plot)
297 cpl_plot_bivector("set title \"Th. bgd\";","w lines", "",thermal_backg);
298
299 /* Correct using the computed scales */
300 new_obj = cpl_imagelist_duplicate(obj);
301 kmax = cpl_vector_get_size(cpl_bivector_get_x_const(obj_spec));
302 kx = 0;
303 for (ix=0; ix<nz; ix++) {
304 if ((kx < kmax ) && (cpl_vector_get(lambda,ix)==cpl_vector_get(
305 cpl_bivector_get_x_const(obj_spec),kx))) {
306 /* Subtract thermal background from new sky cube */
307 if (thermal_backg != NULL) {
308 cpl_image_subtract_scalar(cpl_imagelist_get(*new_sky ,ix),
309 cpl_vector_get(cpl_bivector_get_y_const(thermal_backg),
310 kx));
311 }
312
313 /* Multiply new sky cube with scaling factors from */
314 /* OH line fitting */
315 cpl_image_multiply_scalar(cpl_imagelist_get(*new_sky, ix),
316 cpl_vector_get(cpl_bivector_get_y_const(vscales), kx));
317 /* Subtract new sky cube from obj cube copy to */
318 /* get new obj cube */
319 cpl_image_subtract(cpl_imagelist_get(new_obj, ix),
320 cpl_imagelist_get(*new_sky, ix));
321
322 /* Subtract thermal background from new obj cube as well */
323 if (tbsub && thermal_backg != NULL) {
324 cpl_image_subtract_scalar(cpl_imagelist_get(new_obj, ix),
325 cpl_vector_get(cpl_bivector_get_y_const(
326 thermal_backg), kx));
327 }
328 kx++;
329 }
330 }
331 cpl_bivector_delete(obj_spec);
332 cpl_bivector_delete(sky_spec);
333 if (thermal_backg != NULL) cpl_bivector_delete(thermal_backg);
334 cpl_bivector_delete(vscales);
335 cpl_vector_delete(lambda);
336
337 cpl_image_delete(mask);
338 eris_check_error_code("eris_ifu_sky_tweak");
339 return new_obj;
340}
341
344/*----------------------------------------------------------------------------*/
353/*----------------------------------------------------------------------------*/
354static void eris_ifu_plot_arrays(
355 double * wl,
356 double * obj,
357 double * sky,
358 int arr_size)
359{
360 cpl_vector ** vectors ;
361
362 /* Checks */
363 if (obj == NULL || sky == NULL) return ;
364
365 /* Create Vectors */
366 vectors = cpl_malloc(3*sizeof(cpl_vector*)) ;
367 vectors[0] = cpl_vector_wrap(arr_size, wl) ;
368 vectors[1] = cpl_vector_wrap(arr_size, obj) ;
369 vectors[2] = cpl_vector_wrap(arr_size, sky) ;
370
371 CPL_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual);
372 cpl_plot_vectors("set grid;set xlabel 'Wavelength (microns)';",
373 "t 'Obj and Sky sub-band' w lines", "",
374 (const cpl_vector **)vectors,
375 3);
376 CPL_DIAG_PRAGMA_POP;
377
378 cpl_vector_unwrap(vectors[0]) ;
379 cpl_vector_unwrap(vectors[1]) ;
380 cpl_vector_unwrap(vectors[2]) ;
381 cpl_free(vectors) ;
382 return ;
383}
384
385/*----------------------------------------------------------------------------*/
392/*----------------------------------------------------------------------------*/
393static cpl_bivector * eris_ifu_sky_tweak_thermal_bgd(
394 cpl_bivector * spectrum,
395 double clip_rate)
396{
397 cpl_bivector * result ;
398 cpl_vector * spectrum_v ;
399 cpl_vector * thermal_v ;
400 cpl_vector * tmp_v ;
401 cpl_vector * sorted_y ;
402 const int ndim = 3;
403 const int nsimplex = ndim + 1;
404 double ** p ;
405 double p_init[ndim+1];
406 double * lspectrum = NULL,
407 * vspectrum = NULL;
408 double * x_amoeba ;
409 double * y_amoeba ;
410 int i, j, ix, loop, niter, new_size, skip, input_size ;
411 double min, max, tmp, diff, limit, clip_limit ;
412
413 /* Check entries */
414 if (spectrum == NULL) {
415 cpl_msg_error(__func__, "NULL inputs") ;
416 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
417 return NULL ;
418 }
419 if ((clip_rate < 0.5) || (clip_rate > 1.0)) {
420 cpl_msg_error(__func__, "Invalid clip rate: %g", clip_rate) ;
421 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
422 return NULL ;
423 }
424
425 /* Initialise */
426 min = +1.e30;
427 max = -1.e30;
428 niter = 0 ;
429 new_size = 0;
430 skip = 11;
431 input_size = cpl_bivector_get_size(spectrum) ;
432
433 lspectrum = cpl_bivector_get_x_data(spectrum);
434 vspectrum = cpl_bivector_get_y_data(spectrum);
435 spectrum_lambda=cpl_malloc(input_size*sizeof(double));
436 spectrum_value=cpl_malloc(input_size* sizeof(double));
437 thermal_background= cpl_malloc(input_size*sizeof(double));
438
439 /* Get rid off spikes - skip highest values in the first iteration */
440 if (clip_rate < 1.0) {
441 sorted_y = cpl_vector_duplicate(cpl_bivector_get_y(spectrum));
442 cpl_vector_sort(sorted_y, CPL_SORT_ASCENDING);
443 clip_limit = cpl_vector_get(sorted_y,
444 cpl_vector_get_size(sorted_y) * clip_rate);
445 cpl_vector_delete(sorted_y) ;
446 } else {
447 clip_limit = +1.e30;
448 }
449
450 /* Move to the first non-zero value */
451 for (ix=0; ix < input_size ; ix++) if (vspectrum[ix] != 0.0) break;
452 /* Store the following non-zero/nan/inf values */
453 /* Also omit the clipped ones - Store the min of the retained values */
454 /* Skip the 11 first values */
455 for (i=ix+skip; i<input_size; i++) {
456 if ((vspectrum[i] != 0.0) && (! eris_ifu_is_nan_or_inf(vspectrum[i]))
457 && (vspectrum[i] <= clip_limit) ) {
458 spectrum_lambda[new_size] = lspectrum[i];
459 spectrum_value[new_size] = vspectrum[i];
460 if (vspectrum[i] < min) { min = vspectrum[i]; }
461 new_size++;
462 }
463 }
464 /* Skip the last 0.0 values if any */
465 for (ix=new_size; ix >= 0; ix--) if (vspectrum[ix] != 0.0) break;
466 /* Skip the 11 last values */
467 spectrum_size = ix-skip;
468
469 y_amoeba=cpl_malloc((nsimplex+1)*sizeof(double));
470 x_amoeba=cpl_malloc((ndim+1)*sizeof(double));
471 p = matrix(nsimplex+1,ndim+1);
472
473 p_init[1] = min;
474 p_init[2] = spectrum_value[spectrum_size-1];
475 p_init[3] = 280.;
476 p[1][1] = p_init[1];
477 p[1][2] = p_init[2];
478 p[1][3] = p_init[3];
479
480 for (loop=0; loop<20; loop++) {
481 /*
482 printf("p initial : %d %g %g %g\n",
483 loop, p[1][1], p[1][2], p[1][3]) ;
484 */
485 for (i=2; i<nsimplex+1; i++) {
486 for (j=1; j<ndim+1; j++) p[i][j] = p[1][j];
487 }
488 for (i=2; i<nsimplex+1; i++) p[i][i-1] = p[i][i-1] * 1.2;
489 for (i=1; i<nsimplex+1; i++) {
490 for (j=1; j<ndim+1; j++) x_amoeba[j] = p[i][j];
491 y_amoeba[i] = fitbkd(x_amoeba);
492 }
493 amoeba(p, y_amoeba, 3, 1.e-5, fitbkd, &niter);
494 if (niter < 0) {
495 cpl_msg_error(__func__, "Function minimization failed") ;
496 free_matrix(p, 5);
497 cpl_free(x_amoeba);
498 cpl_free(y_amoeba);
499 cpl_free(spectrum_lambda);
500 cpl_free(spectrum_value);
501 cpl_free(thermal_background);
502 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
503 return NULL ;
504 }
505 spectrum_v = cpl_vector_wrap(spectrum_size, spectrum_value);
506 thermal_v = cpl_vector_wrap(spectrum_size, thermal_background);
507 tmp_v = cpl_vector_duplicate(spectrum_v);
508 cpl_vector_subtract(tmp_v, thermal_v);
509 limit = cpl_vector_get_median(tmp_v) + 2. * cpl_vector_get_stdev(tmp_v);
510 cpl_vector_delete(tmp_v);
511 cpl_vector_unwrap(spectrum_v);
512 cpl_vector_unwrap(thermal_v);
513
514 min = +1.e30;
515 new_size = 0;
516 for (i=0; i<spectrum_size; i++) {
517 diff = spectrum_value[i] - thermal_background[i];
518 if (diff < limit) {
519 spectrum_lambda[new_size] = spectrum_lambda[i];
520 spectrum_value[new_size] = spectrum_value[i];
521 if (spectrum_value[i] < min) min = spectrum_value[i];
522 new_size++;
523 }
524 }
525 spectrum_size = new_size;
526 }
527
528 for (i=0; i<spectrum_size; i++) {
529 tmp = PLANCK(spectrum_lambda[i], p[1][3]);
530 if (tmp > max) max = tmp;
531 }
532 if (fabs(max) < 1e-90) {
533 cpl_msg_error(__func__, "Cannot determine thermal Background") ;
534 free_matrix(p, 5);
535 cpl_free(x_amoeba);
536 cpl_free(y_amoeba);
537 cpl_free(spectrum_lambda);
538 cpl_free(spectrum_value);
539 cpl_free(thermal_background);
540 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
541 return NULL ;
542 }
543
544 for (i=0; i<input_size; i++) {
545 spectrum_lambda[i] = lspectrum[i];
546 spectrum_value[i] = vspectrum[i];
547 tmp = PLANCK(spectrum_lambda[i], p[1][3]);
548 thermal_background[i] = p[1][1] + tmp / max * p[1][2];
549 }
550 thermal_v = cpl_vector_wrap(input_size, thermal_background);
551 tmp_v = cpl_vector_duplicate(thermal_v);
552 cpl_vector_unwrap(thermal_v);
553
554 result = cpl_bivector_wrap_vectors(
555 cpl_vector_duplicate(cpl_bivector_get_x_const(spectrum)), tmp_v);
556
557 free_matrix(p, 5);
558 cpl_free(x_amoeba);
559 cpl_free(y_amoeba);
560 cpl_free(spectrum_lambda);
561 cpl_free(spectrum_value);
562 cpl_free(thermal_background);
563 return result;
564}
565
566/*----------------------------------------------------------------------------*/
572/*----------------------------------------------------------------------------*/
573static double eris_ifu_sky_tweak_get_mean_wo_outliers(const cpl_vector * vdata)
574{
575 cpl_vector * tmpv1 ;
576 cpl_vector * tmpv2 ;
577 cpl_vector * tmpv3 ;
578 cpl_vector * tmpv4 ;
579 const double * data ;
580 double * tmpv1_data;
581 double avg, median, stdev, clip;
582 int nr_data, i, nr_i;
583
584 nr_data = cpl_vector_get_size(vdata);
585 data = cpl_vector_get_data_const(vdata);
586 tmpv1 = cpl_vector_new(nr_data);
587 tmpv1_data = cpl_vector_get_data(tmpv1);
588
589 median = cpl_vector_get_median_const(vdata);
590 for (i=0; i<nr_data; i++) tmpv1_data[i] = fabs(data[i] - median);
591 cpl_vector_sort(tmpv1, CPL_SORT_ASCENDING);
592 clip = cpl_vector_get(tmpv1, (int) .8*nr_data);
593 tmpv2 = eris_ifu_idl_where(tmpv1, clip*5., le);
594 tmpv3 = eris_ifu_idl_values_at_indices(vdata, tmpv2);
595 median = cpl_vector_get_median_const(tmpv3);
596 stdev = cpl_vector_get_stdev(tmpv3);
597 nr_i = 0;
598 for (i=0; i<nr_data; i++) {
599 if ((data[i] < median + 3. * stdev) && (data[i] > median - 3. * stdev)){
600 tmpv1_data[nr_i] = data[i];
601 nr_i++;
602 }
603 }
604 tmpv4 = cpl_vector_wrap(nr_i, tmpv1_data);
605 avg = cpl_vector_get_mean(tmpv4);
606
607 cpl_vector_delete(tmpv1);
608 cpl_vector_delete(tmpv2);
609 cpl_vector_delete(tmpv3);
610 cpl_vector_unwrap(tmpv4);
611 return avg;
612}
613
614/*----------------------------------------------------------------------------*/
620/*----------------------------------------------------------------------------*/
621static cpl_error_code eris_ifu_sky_tweak_get_spectra_simple(
622 const cpl_imagelist * object,
623 const cpl_imagelist * sky,
624 const cpl_image * mask,
625 cpl_vector ** obj_spec,
626 cpl_vector ** sky_spec)
627{
628 cpl_vector * intobj ;
629 cpl_vector * intsky ;
630 const cpl_image * oimg ;
631 const cpl_image * simg ;
632 double * intobj_data ;
633 double * intsky_data ;
634 double * vo ;
635 double * vs ;
636 cpl_vector * ovec ;
637 cpl_vector * svec ;
638 double mpix, opix, spix;
639 int nx, ny, nz, snx, sny, snz, ix, iy, iz, found,
640 m_is_rejected, o_is_rejected, s_is_rejected;
641
642 /* Initialise */
643 nx = cpl_image_get_size_x(cpl_imagelist_get_const(object, 0));
644 ny = cpl_image_get_size_y(cpl_imagelist_get_const(object, 0));
645 nz = cpl_imagelist_get_size(object);
646 snx = cpl_image_get_size_x(cpl_imagelist_get_const(sky, 0));
647 sny = cpl_image_get_size_y(cpl_imagelist_get_const(sky, 0));
648 snz = cpl_imagelist_get_size(sky);
649
650 /* Check entries */
651 if (nx!=snx || ny!=sny || nz!=snz) {
652 cpl_msg_error(__func__, "Illegal inputs") ;
653 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
654 return CPL_ERROR_ILLEGAL_INPUT ;
655 }
656
657 /* Allocate data */
658 intobj = cpl_vector_new(nz);
659 intsky = cpl_vector_new(snz);
660 intobj_data = cpl_vector_get_data(intobj);
661 intsky_data = cpl_vector_get_data(intsky);
662 vo = cpl_malloc(nx * ny * sizeof(double));
663 vs = cpl_malloc(nx * ny * sizeof(double));
664
665 /* For each image, comput the sky value from both the obj and the sky */
666 for (iz = 0; iz <nz; iz++) {
667 oimg = cpl_imagelist_get_const(object, iz);
668 simg = cpl_imagelist_get_const(sky, iz);
669 found = 0;
670 for (ix = 1; ix<=nx; ix++) {
671 for (iy = 1; iy<=ny; iy++) {
672 mpix = cpl_image_get(mask, ix, iy, &m_is_rejected);
673 opix = cpl_image_get(oimg, ix, iy, &o_is_rejected);
674 spix = cpl_image_get(simg, ix, iy, &s_is_rejected);
675 if ( mpix > .5 && m_is_rejected == 0 && o_is_rejected == 0 &&
676 s_is_rejected == 0 ) {
677 vo[found] = opix;
678 vs[found] = spix;
679 found++;
680 }
681 }
682 }
683 /* Only if enough values, the mean or mediaan is taken, otherwise 0.0 */
684 if (found >= nx*ny/4.) {
685 ovec = cpl_vector_wrap(found, vo);
686 svec = cpl_vector_wrap(found, vs);
687
688 if (found < nx*ny/2. ) {
689 intobj_data[iz] = cpl_vector_get_median(ovec);
690 intsky_data[iz] = cpl_vector_get_median(svec);
691 } else {
692 intobj_data[iz] = eris_ifu_sky_tweak_get_mean_wo_outliers(ovec);
693 intsky_data[iz] = eris_ifu_sky_tweak_get_mean_wo_outliers(svec);
694 }
695 cpl_vector_unwrap(ovec);
696 cpl_vector_unwrap(svec);
697 } else {
698 intobj_data[iz] = 0.;
699 intsky_data[iz] = 0.;
700 }
701 }
702 cpl_free(vo);
703 cpl_free(vs);
704
705 /* Return the spectra */
706 *obj_spec = intobj ;
707 *sky_spec = intsky ;
708 return CPL_ERROR_NONE;
709}
710
711/*----------------------------------------------------------------------------*/
717/*----------------------------------------------------------------------------*/
718static cpl_error_code eris_ifu_sky_tweak_get_spectra(
719 const cpl_imagelist * object,
720 const cpl_imagelist * sky,
721 const cpl_vector * lambda,
722 const cpl_image * mask,
723 const int no_nans,
724 cpl_bivector ** obj_spectrum_ptr,
725 cpl_bivector ** sky_spectrum_ptr,
726 int * first_nonan)
727{
728 cpl_bivector * obj_spectrum ;
729 cpl_bivector * sky_spectrum ;
730 cpl_vector * intobj ;
731 cpl_vector * intsky ;
732 cpl_vector * new_lambda ;
733 cpl_vector * new_intobj ;
734 cpl_vector * new_intsky ;
735 const cpl_image * oimg ;
736 const cpl_image * simg ;
737 double * intobj_data ;
738 double * intsky_data ;
739 double * vo ;
740 double * vs ;
741 double * new_lambda_d ;
742 double * new_intobj_d ;
743 double * new_intsky_d ;
744 const double * lambda_d ;
745 cpl_vector * ovec ;
746 cpl_vector * svec ;
747 double mpix, opix, spix;
748 int nx, ny, nz, snx, sny, snz, ix, iy, iz, ni, found,
749 nr_valid_int, m_is_rejected, o_is_rejected,
750 s_is_rejected;
751
752 /* Check entries */
753
754 if (first_nonan==NULL) {
755 cpl_msg_error(__func__, "Illegal inputs") ;
756 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
757 return CPL_ERROR_ILLEGAL_INPUT ;
758 } else {
759 *first_nonan = -1 ;
760 }
761
762 nx = cpl_image_get_size_x(cpl_imagelist_get_const(object, 0));
763 ny = cpl_image_get_size_y(cpl_imagelist_get_const(object, 0));
764 nz = cpl_imagelist_get_size(object);
765 snx = cpl_image_get_size_x(cpl_imagelist_get_const(sky, 0));
766 sny = cpl_image_get_size_y(cpl_imagelist_get_const(sky, 0));
767 snz = cpl_imagelist_get_size(sky);
768
769 if (nx!=snx || ny!=sny || nz!=snz) {
770 cpl_msg_error(__func__, "Illegal inputs") ;
771 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
772 return CPL_ERROR_ILLEGAL_INPUT ;
773 }
774
775 if (nz != cpl_vector_get_size(lambda)) {
776 cpl_msg_error(__func__, "Illegal inputs") ;
777 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
778 return CPL_ERROR_ILLEGAL_INPUT ;
779 }
780
781 intobj = cpl_vector_new(cpl_vector_get_size(lambda));
782 intsky = cpl_vector_new(cpl_vector_get_size(lambda));
783 intobj_data = cpl_vector_get_data(intobj);
784 intsky_data = cpl_vector_get_data(intsky);
785
786 vo = cpl_malloc(nx * ny * sizeof(double));
787 vs = cpl_malloc(nx * ny * sizeof(double));
788
789 nr_valid_int = 0;
790 for (iz = 0; iz <nz; iz++) {
791 oimg = cpl_imagelist_get_const(object, iz);
792 simg = cpl_imagelist_get_const(sky, iz);
793 found = 0;
794 for (ix = 1; ix<=nx; ix++) {
795 for (iy = 1; iy<=ny; iy++) {
796 mpix = cpl_image_get(mask, ix, iy, &m_is_rejected);
797 opix = cpl_image_get(oimg, ix, iy, &o_is_rejected);
798 spix = cpl_image_get(simg, ix, iy, &s_is_rejected);
799 if ( mpix > .5 && m_is_rejected == 0 && o_is_rejected == 0 &&
800 s_is_rejected == 0 ) {
801 vo[found] = opix;
802 vs[found] = spix;
803 found++;
804 }
805
806 }
807 }
808 if (found >= nx*ny/4.) {
809 if (*first_nonan < 0) *first_nonan = iz ;
810 nr_valid_int++;
811 ovec = cpl_vector_wrap(found, vo);
812 svec = cpl_vector_wrap(found, vs);
813
814 if (found < nx*ny/2. ) {
815 intobj_data[iz] = cpl_vector_get_median(ovec);
816 intsky_data[iz] = cpl_vector_get_median(svec);
817 } else {
818 intobj_data[iz] = eris_ifu_sky_tweak_get_mean_wo_outliers(ovec);
819 intsky_data[iz] = eris_ifu_sky_tweak_get_mean_wo_outliers(svec);
820 }
821 cpl_vector_unwrap(ovec);
822 cpl_vector_unwrap(svec);
823 } else {
824 if (no_nans) {
825 intobj_data[iz] = 0./0.;
826 intsky_data[iz] = 0./0.;
827 } else {
828 nr_valid_int++;
829 intobj_data[iz] = 0.;
830 intsky_data[iz] = 0.;
831 }
832 }
833 }
834
835 if (no_nans) {
836 new_lambda = cpl_vector_new(nr_valid_int);
837 new_intobj = cpl_vector_new(nr_valid_int);
838 new_intsky = cpl_vector_new(nr_valid_int);
839 new_lambda_d=cpl_vector_get_data(new_lambda);
840 new_intobj_d=cpl_vector_get_data(new_intobj);
841 new_intsky_d=cpl_vector_get_data(new_intsky);
842 lambda_d=cpl_vector_get_data_const(lambda);
843
844 ni = 0;
845 for (iz=0 ; iz<nz; iz++) {
846 if ((! isnan(intobj_data[iz])) && ni < nr_valid_int) {
847 new_lambda_d[ni] = lambda_d[iz];
848 new_intobj_d[ni] = intobj_data[iz];
849 new_intsky_d[ni] = intsky_data[iz];
850 ni++;
851 }
852 }
853 obj_spectrum = cpl_bivector_wrap_vectors(new_lambda, new_intobj) ;
854 sky_spectrum = cpl_bivector_wrap_vectors(
855 cpl_vector_duplicate(new_lambda), new_intsky);
856
857 cpl_vector_delete(intobj);
858 cpl_vector_delete(intsky);
859 } else {
860 obj_spectrum = cpl_bivector_wrap_vectors(cpl_vector_duplicate(lambda),
861 intobj);
862 sky_spectrum = cpl_bivector_wrap_vectors(cpl_vector_duplicate(lambda),
863 intsky);
864 }
865
866 cpl_free(vo);
867 cpl_free(vs);
868 *obj_spectrum_ptr = obj_spectrum;
869 *sky_spectrum_ptr = sky_spectrum;
870 return CPL_ERROR_NONE;
871}
872
873/*----------------------------------------------------------------------------*/
879/*----------------------------------------------------------------------------*/
880static cpl_bivector * eris_ifu_sky_tweak_correct_vibrational_trans(
881 cpl_bivector * obj_spectrum,
882 cpl_bivector * sky_spectrum,
883 int skip_last,
884 int plot)
885{
886 cpl_bivector * result ;
887 double * scalings ;
888 double * lambda_boundaries ;
889 const char ** labels ;
890 const double * lambda ;
891 const double * intobj ;
892 const double * intsky ;
893 double * array_wls ;
894 double * array_obj ;
895 double * array_sky ;
896 double * line_interpolate_object ;
897 double * line_interpolate_sky ;
898 double * flineres;
899 cpl_vector * tmp_vec ;
900 cpl_vector * sky_lines_map_vec ;
901 double median, stdev ;
902 int i, ix, il, lx, cx, nr_lambda, nr_samples, nr_boundaries,
903 cont_start, cont_end ;
904 cpl_error_code errCode;
905
906 /* Check Entries */
907 if (obj_spectrum == NULL || sky_spectrum == NULL) {
908 cpl_msg_error(__func__, "NULL inputs") ;
909 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
910 return NULL;
911 }
912 if (cpl_bivector_get_size(obj_spectrum) !=
913 cpl_bivector_get_size(sky_spectrum)) {
914 cpl_msg_error(__func__, "Illegal inputs") ;
915 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
916 return NULL;
917 }
918
919 /* Initialise */
920 nr_lambda = cpl_bivector_get_size(obj_spectrum);
921 lambda = cpl_vector_get_data_const(cpl_bivector_get_x_const(obj_spectrum));
922 intobj = cpl_vector_get_data_const(cpl_bivector_get_y_const(obj_spectrum));
923 intsky = cpl_vector_get_data_const(cpl_bivector_get_y_const(sky_spectrum));
924 median = stdev = 0.0 ;
925
926 /* Wavelengths for sky and obj need to be identical */
927 for (ix=0; ix<nr_lambda; ix++) {
928 if (fabs(lambda[ix] -
929 cpl_vector_get(cpl_bivector_get_x_const(sky_spectrum), ix))
930 >= 1.e-7) {
931 cpl_msg_error(__func__, "Illegal inputs") ;
932 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
933 return NULL;
934 }
935 }
936
937 /* Create lambda boundaries for the sub-bands */
938 if (skip_last) {
939 nr_boundaries = 20 ;
940 lambda_boundaries = cpl_malloc(nr_boundaries * sizeof(double)) ;
941 labels = cpl_malloc((nr_boundaries-1) * sizeof(char*)) ;
942 } else {
943 nr_boundaries = 21 ;
944 lambda_boundaries = cpl_malloc(nr_boundaries * sizeof(double)) ;
945 labels = cpl_malloc((nr_boundaries-1) * sizeof(char*)) ;
946 }
947 lambda_boundaries[0] = 0.780 ; labels[0] = "" ;
948 lambda_boundaries[1] = 0.824 ; labels[1] = "" ;
949 lambda_boundaries[2] = 0.873 ; labels[2] = "" ;
950 lambda_boundaries[3] = 0.926 ; labels[3] = "" ;
951 lambda_boundaries[4] = 0.964 ; labels[4] = "" ;
952 lambda_boundaries[5] = 1.014 ; labels[5] = "4-1 transitions" ;
953 lambda_boundaries[6] = 1.067 ; labels[6] = "5-2 transitions" ;
954 lambda_boundaries[7] = 1.125 ; labels[7] = "6-3 transitions" ;
955 lambda_boundaries[8] = 1.196 ; labels[8] = "7-4 transitions" ;
956 lambda_boundaries[9] = 1.252 ; labels[9] = " 02 transitions" ;
957 lambda_boundaries[10] = 1.289 ; labels[10] = "8-5 transitions" ;
958 lambda_boundaries[11] = 1.400 ; labels[11] = "2-0 transitions" ;
959 lambda_boundaries[12] = 1.472 ; labels[12] = "3-1 transitions" ;
960 lambda_boundaries[13] = 1.5543 ; labels[13] = "4-2 transitions" ;
961 lambda_boundaries[14] = 1.6356 ; labels[14] = "5-3 transitions" ;
962 lambda_boundaries[15] = 1.7253 ; labels[15] = "6-4 transitions" ;
963 lambda_boundaries[16] = 1.840 ; labels[16] = "7-5 transitions" ;
964 lambda_boundaries[17] = 1.9570 ; labels[17] = "8-6 transitions" ;
965 lambda_boundaries[18] = 2.095 ; labels[18] = "9-7 transitions" ;
966 if (skip_last) {
967 lambda_boundaries[19] = 2.460 ;
968 } else {
969 lambda_boundaries[19] = 2.30 ; labels[19] = "final bit" ;
970 lambda_boundaries[20] = 2.460 ;
971 }
972
973 /* Allocate scalings */
974 scalings = cpl_malloc(nr_boundaries * sizeof(double)) ;
975 for (ix=0; ix<nr_boundaries; ix++) scalings[ix] = 0.;
976
977 array_wls = cpl_malloc(nr_lambda * sizeof(double)) ;
978 array_obj = cpl_malloc(nr_lambda * sizeof(double)) ;
979 array_sky = cpl_malloc(nr_lambda * sizeof(double)) ;
980
981 /* Loop on the SUB BANDS */
982 for (ix = 0; ix<nr_boundaries-1; ix++) {
983 cpl_msg_debug(__func__, "Sub-band %2d: %s", ix+1, labels[ix]) ;
984 cpl_msg_indent_more() ;
985
986 /* Stor non-Nan values from the current sub-band in array_* */
987 nr_samples = 0;
988 for (il=0; il<nr_lambda; il++) {
989 if ((lambda[il] >= lambda_boundaries[ix] ) &&
990 (lambda[il] < lambda_boundaries[ix+1]) ) {
991
992 if (eris_ifu_is_nan_or_inf(intsky[il]) ||
993 eris_ifu_is_nan_or_inf(intobj[il]) ||
994 intsky[il] == 0. || intobj[il] == 0. ) {
995 cpl_msg_indent_less() ;
996 continue ;
997 }
998
999 array_wls[nr_samples] = lambda[il];
1000 array_obj[nr_samples] = intobj[il];
1001 array_sky[nr_samples] = intsky[il];
1002 nr_samples++;
1003 }
1004 }
1005 cpl_msg_debug(__func__, "Found %d samples", nr_samples) ;
1006
1007 /* Skip the sub-band if too few samples */
1008 if (nr_samples <= 20) {
1009 cpl_msg_indent_less() ;
1010 continue ;
1011 }
1012 if (plot==ix+1 && cpl_msg_get_level() == CPL_MSG_DEBUG)
1013 eris_ifu_plot_arrays(array_wls, array_obj, array_sky, nr_samples);
1014
1015 /* Sky vector sub-band statistics */
1016 tmp_vec = cpl_vector_wrap(nr_samples, array_sky);
1017 median = cpl_vector_get_median_const(tmp_vec);
1018 stdev = cpl_vector_get_stdev(tmp_vec);
1019 cpl_vector_unwrap(tmp_vec);
1020 cpl_msg_debug(__func__, "Sky Stats - Med: %g Stdev: %g", median, stdev);
1021
1022 /* Create a map of the sky vector lines */
1023 sky_lines_map_vec = cpl_vector_new(nr_samples) ;
1024 cpl_vector_fill(sky_lines_map_vec, 0.0) ;
1025 for (i=0; i<nr_samples; i++) {
1026 if (array_sky[i] > median+stdev)
1027 cpl_vector_set(sky_lines_map_vec, i, 10.0) ;
1028 }
1029 if (plot==ix+1 && cpl_msg_get_level() == CPL_MSG_DEBUG)
1030 cpl_plot_vector("set grid;set xlabel 'Samples';set ylabel 'Map';",
1031 "t 'Sky lines map' w lines", "", sky_lines_map_vec);
1032
1033 /* Smoothe the map to create the sky lines signal */
1034 tmp_vec=cpl_vector_filter_lowpass_create(sky_lines_map_vec,
1035 CPL_LOWPASS_LINEAR,2);
1036 cpl_vector_delete(sky_lines_map_vec);
1037 sky_lines_map_vec = tmp_vec ;
1038
1039 if (plot==ix+1 && cpl_msg_get_level() == CPL_MSG_DEBUG)
1040 cpl_plot_vector("set grid;set xlabel 'Samples';set ylabel 'Map';",
1041 "t 'Smoothed sky lines map' w lines", "",
1042 sky_lines_map_vec);
1043
1044 /* Identify the continuum and lines sizes */
1045 eris_ifu_sky_tweak_identify_lines_cont(sky_lines_map_vec,
1046 &cont_start, &cont_end, &cont_size, &lines_size) ;
1047 if (lines_size == 0) {
1048 cpl_msg_warning(__func__, "No line region found") ;
1049 cpl_vector_delete(sky_lines_map_vec);
1050 cpl_msg_indent_less() ;
1051 continue;
1052 }
1053
1054 /* Allocate arrays to hold concatenated line and */
1055 /* continuum regions */
1056 cont_sky_sig = cpl_malloc(cont_size * sizeof(double));
1057 cont_object_sig = cpl_malloc(cont_size * sizeof(double));
1058 cont_lambda = cpl_malloc(cont_size * sizeof(double));
1059 line_sky_sig = cpl_malloc(lines_size * sizeof(double));
1060 line_object_sig = cpl_malloc(lines_size * sizeof(double));
1061 line_lambda = cpl_malloc(lines_size * sizeof(double));
1062
1063 /* Store separately Lines and Continuum */
1064 cx = lx = 0;
1065 for (i = cont_start; i <= cont_end ; i++) {
1066 if (cpl_vector_get(sky_lines_map_vec, i) > 0.) {
1067 line_sky_sig[lx] = array_sky[i];
1068 line_object_sig[lx] = array_obj[i];
1069 line_lambda[lx] = array_wls[i];
1070 lx++;
1071 } else {
1072 cont_sky_sig[cx] = array_sky[i];
1073 cont_object_sig[cx] = array_obj[i];
1074 cont_lambda[cx] = array_wls[i];
1075 cx++;
1076 }
1077 }
1078
1079 /* Minimize object - sky difference (line regions - */
1080 /* interpolated background) using a single factor */
1081 const int ndim = 1;
1082 const int nsimplex = ndim + 1;
1083 double **p = NULL;
1084 double *x_amoeba = NULL,
1085 *y_amoeba = NULL;
1086 int niter = 0;
1087 int ip,jp;
1088 double scale;
1089 y_amoeba = cpl_malloc((nsimplex+1) * sizeof(double));
1090 x_amoeba = cpl_malloc((ndim+1) * sizeof(double));
1091 p = matrix(nsimplex+1,ndim+1);
1092
1093 p[1][1] = 1.;
1094 p[2][1] = 1.25;
1095 for (ip=1; ip<nsimplex+1; ip++) {
1096 for (jp=1; jp<ndim+1; jp++) {
1097 x_amoeba[jp] = p[ip][jp];
1098 }
1099 y_amoeba[ip] = fitsky(x_amoeba);
1100 }
1101 amoeba(p, y_amoeba, ndim, 1.e-5, fitsky, &niter );
1102 if (niter < 0) {
1103 cpl_msg_error(__func__, "Function minimization failed") ;
1104 free_matrix(p, 5);
1105 cpl_free(x_amoeba);
1106 cpl_free(y_amoeba);
1107 cpl_free(spectrum_lambda);
1108 cpl_free(spectrum_value);
1109 cpl_free(thermal_background);
1110 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
1111 return NULL ;
1112 }
1113 scale = p[1][1];
1114 flineres = cpl_malloc(lines_size * sizeof(double));
1115
1116/* line_interpolate_object = polynomial_irreg_irreg_nonans(
1117 cont_size, cont_lambda, cont_object_sig,
1118 lines_size, line_lambda, 2);
1119 line_interpolate_sky = polynomial_irreg_irreg_nonans(
1120 cont_size, cont_lambda, cont_sky_sig,
1121 lines_size, line_lambda, 2);
1122 */
1123 line_interpolate_object = cpl_calloc(lines_size, sizeof(double));
1124 errCode = eris_ifu_1d_interpolation(
1125 cont_lambda, cont_object_sig, cont_size,
1126 line_lambda, line_interpolate_object, lines_size, 2);
1127 if (errCode != CPL_ERROR_NONE) {
1128 printf("ERROR: The function eris_ifu_1d_interpolation called in eris_ifu_sky_tweak_correct_vibrational_trans returned the error %d\n", errCode);
1129 printf("%s\n", cpl_error_get_message_default(errCode));
1130 }
1131
1132 line_interpolate_sky = cpl_calloc(lines_size, sizeof(double));
1133 errCode = eris_ifu_1d_interpolation(
1134 cont_lambda, cont_sky_sig, cont_size,
1135 line_lambda, line_interpolate_sky, lines_size, 2);
1136 if (errCode != CPL_ERROR_NONE) {
1137 printf("ERROR: The function eris_ifu_1d_interpolation called in eris_ifu_sky_tweak_correct_vibrational_trans returned the error %d\n", errCode);
1138 printf("%s\n", cpl_error_get_message_default(errCode));
1139 }
1140
1141 for (i=0; i<lines_size; i++) {
1142 flineres[i] = (line_object_sig[i] -
1143 line_interpolate_object[i]) -
1144 (line_sky_sig[i] - line_interpolate_sky[i]) * scale;
1145 }
1146
1147 tmp_vec = cpl_vector_wrap(lines_size, flineres);
1148 median = cpl_vector_get_median_const(tmp_vec);
1149 stdev = cpl_vector_get_stdev(tmp_vec);
1150 cpl_vector_unwrap(tmp_vec) ;
1151
1152 int clip_cnt=0;
1153 for (i=0; i<lines_size; i++) {
1154 if ( fabs(flineres[i] - median) <= (3 * stdev) ) {
1155 clip_cnt++;
1156 }
1157 }
1158 cpl_msg_debug(__func__, "Outliers: %d", lines_size-clip_cnt) ;
1159
1160 if ((clip_cnt != lines_size) && (clip_cnt >= 3)) {
1161 lx = 0;
1162 for (i=0; i<lines_size; i++) {
1163 if ( fabs(flineres[i] - median) <= (3 * stdev) ) {
1164 line_sky_sig[lx] = line_sky_sig[i];
1165 line_object_sig[lx] =
1166 line_object_sig[i];
1167 line_lambda[lx] = line_lambda[i];
1168 lx++;
1169 }
1170 }
1171 lines_size = lx;
1172 cpl_msg_debug(__func__, "2. Lines size: %d", lines_size) ;
1173
1174 p[1][1] = 1.;
1175 p[2][1] = 1.5;
1176 for (ip=1; ip<nsimplex+1; ip++) {
1177 for (jp=1; jp<ndim+1; jp++) x_amoeba[jp] = p[ip][jp];
1178 y_amoeba[ip] = fitsky(x_amoeba);
1179 }
1180 amoeba(p, y_amoeba, ndim, 1.e-5, fitsky, &niter);
1181 if (niter < 0) {
1182 cpl_msg_error(__func__, "Function minimization failed") ;
1183 free_matrix(p, 5);
1184 cpl_free(x_amoeba);
1185 cpl_free(y_amoeba);
1186 cpl_free(spectrum_lambda);
1187 cpl_free(spectrum_value);
1188 cpl_free(thermal_background);
1189 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
1190 return NULL ;
1191 }
1192 scale = p[1][1];
1193 }
1194 cpl_msg_debug(__func__, "Scale: %g", scale) ;
1195 scalings[ix] = scale;
1196
1197 cpl_vector_delete(sky_lines_map_vec);
1198 free_matrix(p, nsimplex+1);
1199 cpl_free(x_amoeba);
1200 cpl_free(y_amoeba);
1201 cpl_free(cont_sky_sig);
1202 cpl_free(line_sky_sig);
1203 cpl_free(cont_object_sig);
1204 cpl_free(line_object_sig);
1205 cpl_free(cont_lambda);
1206 cpl_free(line_lambda);
1207 cpl_free(flineres);
1208 cpl_free(line_interpolate_object);
1209 cpl_free(line_interpolate_sky);
1210
1211 cpl_msg_indent_less() ;
1212 } // end for (ix = 0; ix<nr_boundaries-1; ix++)
1213 cpl_free(labels) ;
1214
1215 // check for outliers in the scaling factors
1216 int nr_valid = 0,
1217 v_ix = 0;
1218 double valid_scales[nr_boundaries];
1219 cpl_vector *valid_scales_v = NULL;
1220 for (ix=0; ix<nr_boundaries; ix++) {
1221 if (scalings[ix] != 0.0 ) {
1222 valid_scales[nr_valid] = scalings[ix];
1223 nr_valid++;
1224 }
1225 }
1226 valid_scales_v = cpl_vector_wrap(nr_valid, valid_scales);
1227 median = cpl_vector_get_median_const(valid_scales_v);
1228 stdev = cpl_vector_get_stdev(valid_scales_v);
1229 v_ix = 0;
1230 for (ix=0; ix<nr_boundaries; ix++) {
1231 if (scalings[ix] != 0.0 ) {
1232 if (fabs(valid_scales[v_ix] - median) > 2 * stdev) {
1233 scalings[ix] = 0.;
1234 }
1235 v_ix++;
1236 }
1237 }
1238 if (valid_scales_v != NULL) {
1239 cpl_vector_unwrap(valid_scales_v);
1240 valid_scales_v = NULL;
1241 }
1242
1243 int scale0_size;
1244 double *scale0_lambda = NULL,
1245 *scale0_value = NULL,
1246 *scale = NULL;
1247 cpl_vector *scale_v = NULL;
1248
1249 scale0_lambda = cpl_malloc(nr_lambda * sizeof(double));
1250 scale0_value = cpl_malloc(nr_lambda * sizeof(double));
1251
1252 scale0_size = 0;
1253 for (il=0; il<nr_lambda; il++) {
1254 for (ix = 0; ix<nr_boundaries-1; ix++) {
1255 if (scalings[ix] != 0.) {
1256 if ((lambda[il] >= lambda_boundaries[ix] ) &&
1257 (lambda[il] < lambda_boundaries[ix+1]) ) {
1258 scale0_lambda[scale0_size] = lambda[il];
1259 scale0_value[scale0_size] = scalings[ix];
1260 scale0_size++;
1261 }
1262 }
1263 }
1264 }
1265 cpl_free(scalings) ;
1266 cpl_free(lambda_boundaries) ;
1267
1268/* scale = polynomial_irreg_irreg_nonans(scale0_size, scale0_lambda,
1269 scale0_value, nr_lambda, lambda, 1);
1270*/
1271 scale = cpl_calloc(nr_lambda, sizeof(double));
1272 /* cast to lambda* to prevent compiler problem on mac */
1273 double* lambda_tmp = (double*) lambda;
1274 errCode = eris_ifu_1d_interpolation(
1275 scale0_lambda, scale0_value, scale0_size,
1276 lambda_tmp, scale, nr_lambda, 2);
1277 if (errCode != CPL_ERROR_NONE) {
1278 printf("ERROR: The function eris_ifu_1d_interpolation called in eris_ifu_sky_tweak_correct_vibrational_trans returned the error %d\n", errCode);
1279 printf("%s\n", cpl_error_get_message_default(errCode));
1280 }
1281
1282 scale_v = cpl_vector_wrap(nr_lambda, scale);
1283
1284 if (scale0_lambda != NULL) cpl_free(scale0_lambda);
1285 if (scale0_value != NULL) cpl_free(scale0_value);
1286 result = cpl_bivector_wrap_vectors(
1287 cpl_vector_duplicate(cpl_bivector_get_x_const(obj_spectrum)),
1288 scale_v);
1289
1290 cpl_free(array_wls) ;
1291 cpl_free(array_obj) ;
1292 cpl_free(array_sky) ;
1293
1294 return result;
1295}
1296
1297/*----------------------------------------------------------------------------*/
1303/*----------------------------------------------------------------------------*/
1304static int eris_ifu_sky_tweak_identify_lines_cont(
1305 cpl_vector * sky_lines_map_vec,
1306 int * cont_start,
1307 int * cont_end,
1308 int * local_cont_size,
1309 int * local_lines_size)
1310{
1311 int current_line_size, nr_samples, i ;
1312
1313 /* local_ prefix added to avoid conflict with global variables */
1314
1315 /* Initialise */
1316 current_line_size = 0 ;
1317 nr_samples = cpl_vector_get_size(sky_lines_map_vec) ;
1318
1319 /* Make sure cont/line regions start and end with a contin. reg */
1320 *cont_start = -1;
1321 *cont_end = -1;
1322 *local_cont_size = 0;
1323 *local_lines_size = 0;
1324 for (i=0; i<nr_samples; i++) {
1325 if (cpl_vector_get(sky_lines_map_vec, i) > 0.) {
1326 /*** Line ***/
1327 /* Ignore Lines at the start */
1328 if (*cont_start == -1) continue;
1329 current_line_size++;
1330 } else {
1331 /*** Continuum ***/
1332 if (*cont_start == -1) *cont_start = i;
1333 *cont_end = i;
1334 (*local_cont_size)++;
1335 *local_lines_size += current_line_size;
1336 current_line_size = 0;
1337 }
1338 }
1339 cpl_msg_debug(__func__, "Cont [%d, %d] size: %d / Lines size: %d",
1340 *cont_start, *cont_end, *local_cont_size, *local_lines_size) ;
1341 return 0 ;
1342}
1343
1344static double fitsky(double *p) {
1345 double result = 0.;
1346 double *cont_sky = NULL,
1347 *cont_object = NULL;
1348 double avg = 0.;
1349 int ix;
1350 cpl_error_code errCode;
1351
1352/*
1353 cont_sky = polynomial_irreg_irreg_nonans(cont_size, cont_lambda,
1354 cont_sky_sig, lines_size, line_lambda, 1);
1355 cont_object = polynomial_irreg_irreg_nonans(cont_size, cont_lambda,
1356 cont_object_sig, lines_size, line_lambda, 1);
1357*/
1358
1359 cont_sky = cpl_calloc(lines_size, sizeof(double));
1360 errCode = eris_ifu_1d_interpolation(cont_lambda, cont_sky_sig, cont_size,
1361 line_lambda, cont_sky, lines_size, 2);
1362 if (errCode != CPL_ERROR_NONE) {
1363 printf("ERROR: The function eris_ifu_1d_interpolation called in fitsky returned the error %d\n", errCode);
1364 printf("%s\n", cpl_error_get_message_default(errCode));
1365 }
1366
1367 cont_object = cpl_calloc(lines_size, sizeof(double));
1368 errCode = eris_ifu_1d_interpolation(cont_lambda, cont_object_sig, cont_size,
1369 line_lambda, cont_object, lines_size, 2);
1370 if (errCode != CPL_ERROR_NONE) {
1371 printf("ERROR: The function eris_ifu_1d_interpolation called in fitsky returned the error %d\n", errCode);
1372 printf("%s\n", cpl_error_get_message_default(errCode));
1373 }
1374
1375 for (ix=0; ix<lines_size; ix++) {
1376 double diff = (line_object_sig[ix] - cont_object[ix]) -
1377 (line_sky_sig[ix] - cont_sky[ix]) * p[1];
1378 avg += diff * diff;
1379 }
1380 avg /= lines_size;
1381 result = sqrt(avg);
1382
1383 eris_ifu_free_double_array(&cont_sky);
1384 eris_ifu_free_double_array(&cont_object);
1385
1386 return result;
1387}
1388
1389static double fitbkd(double *p) {
1390 double result = 0.;
1391 double *tmp = NULL;
1392 double max = 0.;
1393 int i = 0;
1394
1395 tmp = cpl_malloc(spectrum_size * sizeof(double));
1396
1397 max = -1.;
1398 for (i=0; i<spectrum_size; i++) {
1399 tmp[i] = PLANCK(spectrum_lambda[i], p[3]);
1400 if (tmp[i] > max) {
1401 max = tmp[i];
1402 }
1403 }
1404 p[2]=fabs(p[2]); // make sure scaling factor is positive
1405 if (max > 0.) {
1406 for (i=0; i<spectrum_size; i++) {
1407 thermal_background[i] = p[1] + tmp[i] / max * fabs(p[2]);
1408 }
1409 } else {
1410 for (i=0; i<spectrum_size; i++) {
1411 thermal_background[i] = tmp[i];
1412 }
1413 }
1414
1415 result = 0.;
1416 for (i=0; i<spectrum_size; i++) {
1417 result += (spectrum_value[i] - thermal_background[i]) *
1418 (spectrum_value[i] - thermal_background[i]);
1419 }
1420
1421 if (tmp != NULL) cpl_free(tmp);
1422 return result;
1423}
1424
1425
1426
1427/* !!!!!!!!! UNDER LICENSE !!!!!!! */
1428#define GET_PSUM \
1429 for (j=1;j<=ndim;j++) {\
1430 for (sum=0.0,i=1;i<=mpts;i++) sum += p[i][j];\
1431 psum[j]=sum;}
1432#define SWAP(a,b) {swap=(a);(a)=(b);(b)=swap;}
1433static void amoeba(
1434 double **p,
1435 double y[],
1436 int ndim,
1437 double ftol,
1438 double (*funk)(double []),
1439 int * nfunk)
1440{
1441 int i,ihi,ilo,inhi,j,mpts=ndim+1;
1442 double rtol, sum, swap, ysave, ytry, *psum = NULL, d;
1443
1444 psum=cpl_calloc(ndim+1, sizeof(double));
1445 *nfunk=0;
1446 GET_PSUM
1447 for (;;) {
1448 ilo=1;
1449 ihi = y[1]>y[2] ? (inhi=2,1) : (inhi=1,2);
1450 for (i=1;i<=mpts;i++) {
1451 if (y[i] <= y[ilo]) {
1452 ilo=i;
1453 }
1454 if (y[i] > y[ihi]) {
1455 inhi=ihi;
1456 ihi=i;
1457 } else if (y[i] > y[inhi] && i != ihi) inhi=i;
1458 }
1459 d = fabs(y[ihi])+fabs(y[ilo]);
1460 if (d == 0.0) {
1461 rtol = ftol / 2. ; //succeeds next if statement -> breaks loop
1462 } else {
1463 rtol=2.0*fabs(y[ihi]-y[ilo])/d;
1464 }
1465 if (rtol < ftol) {
1466 SWAP(y[1],y[ilo])
1467 for (i=1;i<=ndim;i++) SWAP(p[1][i],p[ilo][i])
1468 break;
1469 }
1470 if (*nfunk >= 5000) {
1471 //printf("5000 exceeded\n");
1472 *nfunk = -1;
1473 return;
1474 }
1475 *nfunk += 2;
1476 ytry=amotry(p,y,psum,ndim,funk,ihi,-1.0);
1477 if (ytry <= y[ilo])
1478 ytry=amotry(p,y,psum,ndim,funk,ihi,2.0);
1479 else if (ytry >= y[inhi]) {
1480 ysave=y[ihi];
1481 ytry=amotry(p,y,psum,ndim,funk,ihi,0.5);
1482 if (ytry >= ysave) {
1483 for (i=1;i<=mpts;i++) {
1484 if (i != ilo) {
1485 for (j=1;j<=ndim;j++) {
1486 p[i][j]=psum[j]=0.5*(p[i][j]+p[ilo][j]);
1487 }
1488 y[i]=(*funk)(psum);
1489 }
1490 }
1491 *nfunk += ndim;
1492 GET_PSUM
1493 }
1494 } else {
1495 --(*nfunk);
1496 }
1497 }
1499}
1500#undef SWAP
1501#undef GET_PSUM
1502
1503static double amotry(
1504 double ** p,
1505 double y[],
1506 double psum[],
1507 int ndim,
1508 double (*funk)(double []),
1509 int ihi,
1510 double fac)
1511{
1512 int j;
1513 double fac1,fac2,ytry,*ptry=NULL;
1514
1515 ptry=cpl_calloc(ndim+1, sizeof(double));
1516 fac1=(1.0-fac)/ndim;
1517 fac2=fac1-fac;
1518 for (j=1;j<=ndim;j++) ptry[j]=psum[j]*fac1-p[ihi][j]*fac2;
1519 ytry=(*funk)(ptry);
1520 if (ytry < y[ihi]) {
1521 y[ihi]=ytry;
1522 for (j=1;j<=ndim;j++) {
1523 psum[j] += ptry[j]-p[ihi][j];
1524 p[ihi][j]=ptry[j];
1525 }
1526 }
1528 return ytry;
1529}
1530/* !!!!!!!!! END UNDER LICENSE !!!!!!! */
1531
1532/* ************************************************************************* */
1533/* ****************************** ERIS STRETCH ***************************** */
1534/* ************************************************************************* */
1535
1536/*----------------------------------------------------------------------------*/
1553/*----------------------------------------------------------------------------*/
1554static cpl_imagelist * eris_ifu_priv_sky_stretch(
1555 cpl_imagelist * obj,
1556 cpl_imagelist * sky,
1557 float min_frac,
1558 int poly_degree,
1559 int resampling_method,
1560 int plot)
1561{
1562 cpl_vector * obj_spec ;
1563 cpl_vector * sky_spec ;
1564 cpl_imagelist * new_sky ;
1565 cpl_image * mask ;
1566 cpl_polynomial * transf_poly ;
1567 cpl_polynomial * new_transf_poly ;
1568 cpl_bivector * matching_lines ;
1569 cpl_bivector * new_matching_lines ;
1570
1571 /* Check inputs */
1572 if (obj == NULL || sky == NULL) return NULL ;
1573 if (resampling_method != 1 && resampling_method != 2) return NULL ;
1574
1575 /* mask is a binary image : 0 -> obj / 1 -> background */
1576 mask = eris_ifu_lcorr_create_object_mask(obj, min_frac, NULL, NULL);
1577
1578 /* Get the background spectrum from obj and sky cubes using mask */
1579 if (eris_ifu_sky_tweak_get_spectra_simple(obj, sky, mask, &obj_spec,
1580 &sky_spec) != CPL_ERROR_NONE) {
1581 cpl_msg_error(cpl_func, "Cannot extract the spectra from cubes") ;
1582 cpl_image_delete(mask) ;
1583 return NULL ;
1584 }
1585
1586 /* Create the transformation poynomial */
1587 if ((transf_poly = eris_ifu_stretch_get_poly(obj_spec, sky_spec, 5, poly_degree,
1588 &matching_lines))==NULL) {
1589 cpl_msg_error(cpl_func, "Cannot compute the transformation polynomial");
1590 cpl_vector_delete(obj_spec) ;
1591 cpl_vector_delete(sky_spec) ;
1592 cpl_image_delete(mask) ;
1593 return NULL ;
1594 }
1595 cpl_vector_delete(obj_spec) ;
1596 cpl_vector_delete(sky_spec) ;
1597
1598 /* Apply the sky cube transformation */
1599 if (resampling_method == 1)
1600 new_sky = eris_ifu_stretch_apply_linear(sky, transf_poly) ;
1601 else
1602 new_sky = eris_ifu_stretch_apply_spline(sky, transf_poly) ;
1603 if (new_sky == NULL) {
1604 cpl_msg_error(cpl_func, "Cannot apply the transformation");
1605 cpl_polynomial_delete(transf_poly) ;
1606 cpl_image_delete(mask) ;
1607 return NULL ;
1608 }
1609
1610 /* FOR DEBUG PUPOSE - Check the new sky */
1611 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
1612 if (eris_ifu_sky_tweak_get_spectra_simple(obj, new_sky, mask, &obj_spec,
1613 &sky_spec) != CPL_ERROR_NONE) {
1614 cpl_msg_error(cpl_func, "Cannot extract the spectra from cubes") ;
1615 cpl_image_delete(mask) ;
1616 cpl_bivector_delete(matching_lines) ;
1617 cpl_polynomial_delete(transf_poly) ;
1618 cpl_imagelist_delete(new_sky) ;
1619 return NULL ;
1620 }
1621 if ((new_transf_poly = eris_ifu_stretch_get_poly(obj_spec, sky_spec, 5,
1622 poly_degree, &new_matching_lines))==NULL) {
1623 cpl_msg_error(cpl_func, "Cannot compute the transf. polynomial");
1624 cpl_vector_delete(obj_spec) ;
1625 cpl_vector_delete(sky_spec) ;
1626 cpl_image_delete(mask) ;
1627 cpl_bivector_delete(matching_lines) ;
1628 cpl_polynomial_delete(transf_poly) ;
1629 cpl_imagelist_delete(new_sky) ;
1630 return NULL ;
1631 }
1632 cpl_vector_delete(obj_spec) ;
1633 cpl_vector_delete(sky_spec) ;
1634
1635 cpl_polynomial_dump(transf_poly, stdout) ;
1636 /* cpl_polynomial_dump(new_transf_poly, stdout) ; */
1637
1638 if (plot) {
1639 eris_ifu_stretch_plot_positions_differences(matching_lines,
1640 new_matching_lines) ;
1641 eris_ifu_stretch_check(obj, sky, new_sky, mask) ;
1642 }
1643 cpl_bivector_delete(new_matching_lines) ;
1644 cpl_polynomial_delete(new_transf_poly) ;
1645 }
1646
1647 cpl_bivector_delete(matching_lines) ;
1648 cpl_polynomial_delete(transf_poly) ;
1649 cpl_image_delete(mask) ;
1650
1651 return new_sky ;
1652}
1653
1654static cpl_polynomial * eris_ifu_stretch_get_poly(
1655 const cpl_vector * obj,
1656 const cpl_vector * sky,
1657 double min_gap,
1658 int degree,
1659 cpl_bivector ** matching_lines)
1660{
1661 cpl_size deg_loc ;
1662 cpl_size nb_lines ;
1663 cpl_matrix * matchedx ;
1664 cpl_polynomial * fitted ;
1665
1666 /* Check entries */
1667 if (obj == NULL || sky == NULL || matching_lines == NULL) return NULL ;
1668
1669 /* Initialise */
1670 deg_loc = (cpl_size)degree ;
1671
1672 /* Detect Matching lines */
1673 *matching_lines=eris_ifu_strech_get_matching_lines(obj, sky, min_gap, 1,degree);
1674 nb_lines = cpl_bivector_get_size(*matching_lines) ;
1675
1676 /* Compute the fit */
1677 matchedx = cpl_matrix_wrap(1, nb_lines,
1678 cpl_vector_get_data(cpl_bivector_get_x(*matching_lines)));
1679 fitted = cpl_polynomial_new(1);
1680 if (cpl_polynomial_fit(fitted, matchedx, NULL,
1681 cpl_bivector_get_y(*matching_lines), NULL, CPL_FALSE,
1682 NULL, &deg_loc) != CPL_ERROR_NONE) {
1683 cpl_msg_error(cpl_func, "Cannot fit the polynomial") ;
1684 cpl_polynomial_delete(fitted);
1685 cpl_matrix_unwrap(matchedx);
1686 cpl_bivector_delete(*matching_lines) ;
1687 return NULL ;
1688 }
1689 cpl_matrix_unwrap(matchedx);
1690 return fitted ;
1691}
1692
1693/* TODO */
1694/*----------------------------------------------------------------------------*/
1701/*----------------------------------------------------------------------------*/
1702static cpl_imagelist * eris_ifu_stretch_apply_spline(
1703 cpl_imagelist * in,
1704 cpl_polynomial * stretch)
1705{
1706 cpl_imagelist * out ;
1707 cpl_vector ** zlines ;
1708 cpl_vector ** resampled_zlines ;
1709 double * image_data ;
1710 cpl_vector * pos ;
1711 double * ppos ;
1712 double * resampled_array ;
1713 cpl_vector * new_pos ;
1714 int spec_size, nx, ny, i, j, k ;
1715
1716 /* Initialize */
1717 spec_size = cpl_imagelist_get_size(in) ;
1718 nx = cpl_image_get_size_x(cpl_imagelist_get_const(in, 0)) ;
1719 ny = cpl_image_get_size_x(cpl_imagelist_get_const(in, 0)) ;
1720
1721 /* Create the z vectors */
1722 zlines = cpl_malloc(nx*ny*sizeof(cpl_vector*)) ;
1723 for (i=0 ; i<nx ; i++)
1724 for (j=0 ; j<ny ; j++)
1725 zlines[i+j*nx] = cpl_vector_new(spec_size) ;
1726
1727 /* Fill the z vectors */
1728 for (k=0 ; k<spec_size ; k++) {
1729 image_data = cpl_image_get_data_double(cpl_imagelist_get(in, k)) ;
1730 for (i=0 ; i<nx ; i++)
1731 for (j=0 ; j<ny ; j++)
1732 if (!isnan(image_data[i+j*nx]))
1733 cpl_vector_set(zlines[i+j*nx], k, image_data[i+j*nx]) ;
1734 else
1735 cpl_vector_set(zlines[i+j*nx], k, 0.0) ;
1736 }
1737
1738 /* Create the positions vector */
1739 pos = cpl_vector_new(spec_size) ;
1740 ppos = cpl_vector_get_data(pos);
1741 for (i=0 ; i<spec_size ; i++) ppos[i] = i+1 ;
1742
1743 /* Create the new positions vector */
1744 new_pos = cpl_vector_new(spec_size) ;
1745 cpl_vector_fill_polynomial(new_pos, stretch, 1, 1) ;
1746
1747 /* Extend the lambdas for the border effects */
1748 if (cpl_vector_get(new_pos, 0) < 1.0) cpl_vector_set(new_pos, 0, 1.0) ;
1749 if (cpl_vector_get(new_pos, spec_size-1) > spec_size-1)
1750 cpl_vector_set(new_pos, spec_size-1, spec_size-1) ;
1751
1752 resampled_zlines = cpl_malloc(nx*ny*sizeof(cpl_vector*)) ;
1753 /* Run the interpolations */
1754 cpl_error_code retErr;
1755 for (i=0 ; i<nx ; i++) {
1756 for (j=0 ; j<ny ; j++) {
1757 resampled_array = cpl_malloc(spec_size * sizeof(double));
1759 ppos, cpl_vector_get_data(zlines[i+j*nx]), spec_size,
1760 cpl_vector_get_data(new_pos), resampled_array, spec_size,
1761 -1);
1762 if (retErr != CPL_ERROR_NONE) {
1763 printf("ERROR: The function eris_ifu_1d_interpolation called in eris_ifu_stretch_apply_spline returned the error %d\n", retErr);
1764 printf("%s\n", cpl_error_get_message_default(retErr));
1765 }
1766/*
1767 resampled_array = cubicspline_irreg_irreg(spec_size,
1768 ppos, cpl_vector_get_data(zlines[i+j*nx]),
1769 spec_size, cpl_vector_get_data(new_pos), NATURAL) ;
1770*/
1771
1772 resampled_zlines[i+j*nx] = cpl_vector_wrap(spec_size,
1773 resampled_array) ;
1774 }
1775 }
1776 cpl_vector_delete(new_pos) ;
1777 cpl_vector_delete(pos) ;
1778 //cpl_free(resampled_array);
1779
1780 /* Deallocate specs */
1781 for (i=0 ; i<nx ; i++)
1782 for (j=0 ; j<ny ; j++)
1783 cpl_vector_delete(zlines[i+j*nx]) ;
1784 cpl_free(zlines) ;
1785
1786 /* Fill the output cube */
1787 out = cpl_imagelist_duplicate(in) ;
1788 for (k=0 ; k<spec_size ; k++) {
1789 image_data = cpl_image_get_data_double(cpl_imagelist_get(out, k)) ;
1790 for (i=0 ; i<nx ; i++)
1791 for (j=0 ; j<ny ; j++)
1792 image_data[i+j*nx]= cpl_vector_get(resampled_zlines[i+j*nx],k) ;
1793 }
1794
1795 /* Deallocate resampled_specs */
1796 for (i=0 ; i<nx ; i++)
1797 for (j=0 ; j<ny ; j++)
1798 cpl_free(cpl_vector_unwrap(resampled_zlines[i+j*nx]));
1799// cpl_vector_delete(resampled_zlines[i+j*nx]) ;
1800 cpl_free(resampled_zlines) ;
1801 return out ;
1802}
1803
1804
1805/*----------------------------------------------------------------------------*/
1812/*----------------------------------------------------------------------------*/
1813static cpl_imagelist * eris_ifu_stretch_apply_linear(
1814 cpl_imagelist * in,
1815 cpl_polynomial * stretch)
1816{
1817 cpl_imagelist * out ;
1818 cpl_vector ** zlines ;
1819 cpl_vector ** resampled_zlines ;
1820 double * image_data ;
1821 cpl_vector * pos ;
1822 double * ppos ;
1823 cpl_vector * new_pos ;
1824 cpl_bivector * ref_spec ;
1825 cpl_bivector * resampled_spec ;
1826 int spec_size, nx, ny, i, j, k ;
1827
1828 /* Initialize */
1829 spec_size = cpl_imagelist_get_size(in) ;
1830 nx = cpl_image_get_size_x(cpl_imagelist_get_const(in, 0)) ;
1831 ny = cpl_image_get_size_x(cpl_imagelist_get_const(in, 0)) ;
1832
1833 /* Create the z vectors */
1834 zlines = cpl_malloc(nx*ny*sizeof(cpl_vector*)) ;
1835 for (i=0 ; i<nx ; i++)
1836 for (j=0 ; j<ny ; j++)
1837 zlines[i+j*nx] = cpl_vector_new(spec_size) ;
1838
1839 /* Fill the z vectors */
1840 for (k=0 ; k<spec_size ; k++) {
1841 image_data = cpl_image_get_data_double(cpl_imagelist_get(in, k)) ;
1842 for (i=0 ; i<nx ; i++)
1843 for (j=0 ; j<ny ; j++)
1844 if (!isnan(image_data[i+j*nx]))
1845 cpl_vector_set(zlines[i+j*nx], k, image_data[i+j*nx]) ;
1846 else
1847 cpl_vector_set(zlines[i+j*nx], k, 0.0) ;
1848 }
1849
1850 /* Create the positions vector */
1851 pos = cpl_vector_new(spec_size) ;
1852 ppos = cpl_vector_get_data(pos);
1853 for (i=0 ; i<spec_size ; i++) ppos[i] = i+1 ;
1854
1855 /* Create the new positions vector */
1856 new_pos = cpl_vector_new(spec_size) ;
1857 cpl_vector_fill_polynomial(new_pos, stretch, 1, 1) ;
1858
1859 /* Extend the lambdas for the border effects */
1860 if (cpl_vector_get(new_pos, 0) < 1.0) cpl_vector_set(new_pos, 0, 1.0) ;
1861 if (cpl_vector_get(new_pos, spec_size-1) > spec_size-1)
1862 cpl_vector_set(new_pos, spec_size-1, spec_size-1) ;
1863
1864 resampled_zlines = cpl_malloc(nx*ny*sizeof(cpl_vector*)) ;
1865 /* Run the interpolations */
1866 for (i=0 ; i<nx ; i++) {
1867 for (j=0 ; j<ny ; j++) {
1868 /* Allocate the vector holding the resampled sky */
1869 resampled_zlines[i+j*nx] = cpl_vector_new(spec_size) ;
1870
1871 /* Wrap the bivectors */
1872 ref_spec = cpl_bivector_wrap_vectors(pos, zlines[i+j*nx]);
1873 resampled_spec = cpl_bivector_wrap_vectors(new_pos,
1874 resampled_zlines[i+j*nx]) ;
1875 /* Apply the resampling */
1876 cpl_bivector_interpolate_linear(resampled_spec, ref_spec) ;
1877
1878 /* Unwrap */
1879 cpl_bivector_unwrap_vectors(ref_spec) ;
1880 cpl_bivector_unwrap_vectors(resampled_spec) ;
1881 }
1882 }
1883 cpl_vector_delete(new_pos) ;
1884 cpl_vector_delete(pos) ;
1885
1886 /* Deallocate specs */
1887 for (i=0 ; i<nx ; i++)
1888 for (j=0 ; j<ny ; j++)
1889 cpl_vector_delete(zlines[i+j*nx]) ;
1890 cpl_free(zlines) ;
1891
1892 /* Fill the output cube */
1893 out = cpl_imagelist_duplicate(in) ;
1894 for (k=0 ; k<spec_size ; k++) {
1895 image_data = cpl_image_get_data_double(cpl_imagelist_get(out, k)) ;
1896 for (i=0 ; i<nx ; i++)
1897 for (j=0 ; j<ny ; j++)
1898 image_data[i+j*nx]= cpl_vector_get(resampled_zlines[i+j*nx],k) ;
1899 }
1900
1901 /* Deallocate resampled_specs */
1902 for (i=0 ; i<nx ; i++)
1903 for (j=0 ; j<ny ; j++)
1904 cpl_vector_delete(resampled_zlines[i+j*nx]) ;
1905 cpl_free(resampled_zlines) ;
1906 return out ;
1907}
1908
1909static int eris_ifu_stretch_check(
1910 cpl_imagelist * obj,
1911 cpl_imagelist * sky,
1912 cpl_imagelist * new_sky,
1913 cpl_image * mask)
1914{
1915 cpl_vector * spec1 ;
1916 cpl_vector * spec2 ;
1917
1918 eris_ifu_sky_tweak_get_spectra_simple(obj, sky, mask, &spec1, &spec2);
1919 cpl_plot_vector("set grid;set xlabel 'pix';", "t 'obj' w lines", "",
1920 spec1);
1921 cpl_plot_vector("set grid;set xlabel 'pix';",
1922 "t 'sky before stretching' w lines", "", spec2);
1923 cpl_vector_subtract(spec1, spec2) ;
1924
1925 cpl_plot_vector("set grid;set xlabel 'pix';",
1926 "t 'obj-sky before stretching' w lines", "",
1927 spec1);
1928 cpl_vector_delete(spec1) ;
1929 cpl_vector_delete(spec2) ;
1930
1931 eris_ifu_sky_tweak_get_spectra_simple(obj, new_sky, mask, &spec1, &spec2);
1932 cpl_plot_vector("set grid;set xlabel 'pix';",
1933 "t 'sky after stretching' w lines", "", spec2);
1934 cpl_vector_subtract(spec1, spec2) ;
1935
1936 cpl_plot_vector("set grid;set xlabel 'pix';",
1937 "t 'obj-sky after stretching' w lines", "",
1938 spec1);
1939 cpl_vector_delete(spec1) ;
1940 cpl_vector_delete(spec2) ;
1941
1942 return 0 ;
1943}
1944
1945static int eris_ifu_stretch_plot_positions_differences(
1946 cpl_bivector * matching_lines,
1947 cpl_bivector * new_matching_lines)
1948{
1949 cpl_vector * diff_values ;
1950 cpl_bivector * diff ;
1951
1952 /* BEFORE */
1953 diff_values = cpl_vector_duplicate(cpl_bivector_get_x(matching_lines)) ;
1954 cpl_vector_subtract(diff_values, cpl_bivector_get_y(matching_lines)) ;
1955 diff = cpl_bivector_wrap_vectors(cpl_bivector_get_x(matching_lines),
1956 diff_values) ;
1957 cpl_plot_bivector("set grid;", "t 'Pos. diff. BEFORE STRECHING'", "", diff);
1958 cpl_bivector_unwrap_vectors(diff) ;
1959 cpl_vector_delete(diff_values) ;
1960
1961 /* AFTER */
1962 diff_values = cpl_vector_duplicate(cpl_bivector_get_x(new_matching_lines)) ;
1963 cpl_vector_subtract(diff_values, cpl_bivector_get_y(new_matching_lines)) ;
1964 diff = cpl_bivector_wrap_vectors(cpl_bivector_get_x(new_matching_lines),
1965 diff_values) ;
1966 cpl_plot_bivector("set grid;", "t 'Pos. diff. AFTER STRECHING'", "", diff);
1967 cpl_bivector_unwrap_vectors(diff) ;
1968 cpl_vector_delete(diff_values) ;
1969
1970 return 0 ;
1971}
1972
1973/* TODO */
1974static cpl_bivector * eris_ifu_strech_get_matching_lines(
1975 const cpl_vector * obj,
1976 const cpl_vector * sky,
1977 double min_gap,
1978 int remove_outliers,
1979 int degree)
1980{
1981 cpl_vector * tmp_vec ;
1982 cpl_vector * obj_lines ;
1983 cpl_vector * obj_lines_clean ;
1984 double * pobj_lines ;
1985 cpl_vector * sky_lines ;
1986 cpl_vector * sky_lines_clean ;
1987 double * psky_lines ;
1988 cpl_vector * diff ;
1989 double * obj_lines_arr ;
1990 double * sky_lines_arr ;
1991 double obj_pos, sky_pos ;
1992 cpl_size sky_idx, nb_lines ;
1993 double fwhm, kappa, threshold ;
1994 int i, nb_found ;
1995
1996 /* Check entries */
1997 if (obj == NULL || sky == NULL) return NULL ;
1998
1999 /* Initialise */
2000 fwhm = 5.0 ;
2001 kappa = 3 ;
2002
2003 /* TODO */
2004 /* Replace by keeping the 20 brightest lines dispatched on the detector */
2005
2006 /* Detect lines in obj */
2007 /* Pre-process before detection */
2008 threshold = fabs(cpl_vector_get_mean(obj) + cpl_vector_get_stdev(obj)) ;
2009 tmp_vec = cpl_vector_duplicate(obj) ;
2010 for (i=0 ; i<cpl_vector_get_size(tmp_vec) ; i++) {
2011 if (cpl_vector_get(tmp_vec, i) < threshold)
2012 cpl_vector_set(tmp_vec, i, 0.0);
2013 }
2014 if ((obj_lines = irplib_spectrum_detect_peaks(tmp_vec, fwhm,
2015 kappa, 0, NULL, NULL)) == NULL) {
2016 cpl_msg_error(cpl_func, "Cannot detect peaks from obj") ;
2017 cpl_vector_delete(tmp_vec) ;
2018 return NULL ;
2019 }
2020 cpl_vector_delete(tmp_vec) ;
2021
2022 /* Detect lines in sky */
2023 /* Pre-process before detection */
2024 threshold = fabs(cpl_vector_get_mean(sky) + cpl_vector_get_stdev(sky)) ;
2025 tmp_vec = cpl_vector_duplicate(sky) ;
2026 for (i=0 ; i<cpl_vector_get_size(tmp_vec) ; i++) {
2027 if (cpl_vector_get(tmp_vec, i) < threshold)
2028 cpl_vector_set(tmp_vec, i, 0.0);
2029 }
2030 if ((sky_lines = irplib_spectrum_detect_peaks(tmp_vec, fwhm,
2031 kappa, 0, NULL, NULL)) == NULL) {
2032 cpl_msg_error(cpl_func, "Cannot detect peaks from sky") ;
2033 cpl_vector_delete(obj_lines) ;
2034 cpl_vector_delete(tmp_vec) ;
2035 return NULL ;
2036 }
2037 cpl_vector_delete(tmp_vec) ;
2038
2039 cpl_msg_debug(cpl_func, "Detected %"CPL_SIZE_FORMAT" lines from obj",
2040 cpl_vector_get_size(obj_lines));
2041 cpl_msg_debug(cpl_func, "Detected %"CPL_SIZE_FORMAT" lines from sky",
2042 cpl_vector_get_size(sky_lines));
2043
2044 /* Obj lines need to be separated - Remove double lines */
2045 cpl_vector_sort(obj_lines, CPL_SORT_ASCENDING) ;
2046 nb_lines = cpl_vector_get_size(obj_lines) ;
2047 pobj_lines = cpl_vector_get_data(obj_lines) ;
2048 obj_lines_arr = cpl_malloc(nb_lines * sizeof(double)) ;
2049 /* Always keep the first line */
2050 obj_lines_arr[0] = pobj_lines[0] ;
2051 nb_found = 1 ;
2052 for (i=1 ; i<nb_lines ; i++) {
2053 /* If the lines positions are too close to neighbor, remove them */
2054 if (fabs(pobj_lines[i]-pobj_lines[i-1]) > min_gap) {
2055 obj_lines_arr[nb_found] = pobj_lines[i] ;
2056 nb_found++ ;
2057 }
2058 }
2059 /* Create the new obj_lines */
2060 cpl_vector_delete(obj_lines) ;
2061 obj_lines = cpl_vector_new(nb_found) ;
2062 pobj_lines = cpl_vector_get_data(obj_lines) ;
2063 for (i=0 ; i<nb_found ; i++) pobj_lines[i] = obj_lines_arr[i] ;
2064 cpl_free(obj_lines_arr) ;
2065 nb_lines = cpl_vector_get_size(obj_lines) ;
2066
2067 cpl_msg_debug(cpl_func,
2068 "Detected %"CPL_SIZE_FORMAT" separated lines from obj",
2069 cpl_vector_get_size(obj_lines));
2070
2071 /* Associate obj and sky lines */
2072 obj_lines_arr = cpl_malloc(nb_lines * sizeof(double)) ;
2073 sky_lines_arr = cpl_malloc(nb_lines * sizeof(double)) ;
2074 nb_found = 0 ;
2075 cpl_vector_sort(sky_lines, CPL_SORT_ASCENDING) ;
2076 for (i=0 ; i<nb_lines ; i++) {
2077 obj_pos = cpl_vector_get(obj_lines, i) ;
2078 sky_idx = cpl_vector_find(sky_lines, obj_pos) ;
2079 sky_pos = cpl_vector_get(sky_lines, sky_idx) ;
2080 /* If the lines positions are close enough, keep them */
2081 if (fabs(obj_pos-sky_pos) < min_gap) {
2082 obj_lines_arr[nb_found] = obj_pos ;
2083 sky_lines_arr[nb_found] = sky_pos ;
2084 nb_found++ ;
2085 }
2086 }
2087
2088 /* Create the new lines vectors */
2089 cpl_vector_delete(obj_lines) ;
2090 cpl_vector_delete(sky_lines) ;
2091 obj_lines = cpl_vector_new(nb_found) ;
2092 sky_lines = cpl_vector_new(nb_found) ;
2093 nb_lines = cpl_vector_get_size(obj_lines) ;
2094 pobj_lines = cpl_vector_get_data(obj_lines) ;
2095 psky_lines = cpl_vector_get_data(sky_lines) ;
2096 for (i=0 ; i<nb_found ; i++) {
2097 pobj_lines[i] = obj_lines_arr[i] ;
2098 psky_lines[i] = sky_lines_arr[i] ;
2099 }
2100 cpl_free(obj_lines_arr) ;
2101 cpl_free(sky_lines_arr) ;
2102
2103 /* Remove outliers */
2104 if (remove_outliers) {
2105 diff = cpl_vector_duplicate(obj_lines) ;
2106 cpl_vector_subtract(diff, sky_lines) ;
2107 threshold = fabs(cpl_vector_get_median_const(diff)) +
2108 2 * cpl_vector_get_stdev(diff) ;
2109 nb_found = 0 ;
2110 for (i=0 ; i<cpl_vector_get_size(diff) ; i++)
2111 if (fabs(cpl_vector_get(diff, i)) < threshold) nb_found++ ;
2112 obj_lines_clean = cpl_vector_new(nb_found) ;
2113 sky_lines_clean = cpl_vector_new(nb_found) ;
2114 nb_found = 0 ;
2115 for (i=0 ; i<cpl_vector_get_size(diff) ; i++)
2116 if (fabs(cpl_vector_get(diff, i)) < threshold) {
2117 cpl_vector_set(obj_lines_clean, nb_found,
2118 cpl_vector_get(obj_lines, i)) ;
2119 cpl_vector_set(sky_lines_clean, nb_found,
2120 cpl_vector_get(sky_lines, i)) ;
2121 nb_found++ ;
2122 }
2123 cpl_vector_delete(diff) ;
2124 cpl_vector_delete(obj_lines) ;
2125 cpl_vector_delete(sky_lines) ;
2126 obj_lines = obj_lines_clean ;
2127 sky_lines = sky_lines_clean ;
2128 }
2129
2130 /* Check if there are enough matched lines */
2131 if (nb_found <= degree) {
2132 cpl_msg_error(cpl_func, "Not enough match for the fit") ;
2133 cpl_vector_delete(obj_lines) ;
2134 cpl_vector_delete(sky_lines) ;
2135 return NULL ;
2136 }
2137
2138 cpl_msg_debug(cpl_func, "Matched %"CPL_SIZE_FORMAT" lines",
2139 cpl_vector_get_size(obj_lines));
2140
2141 return cpl_bivector_wrap_vectors(obj_lines, sky_lines);
2142}
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)
Creates a mask of the cube.
cpl_vector * eris_ifu_lcorr_create_lambda_vector(const cpl_propertylist *header)
Creates a wavelength vector from an input cube.
int eris_ifu_plot_cube_background(cpl_imagelist *obj)
Extract backgroung from cube and plot.
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 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 knownm 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