CR2RE Pipeline Reference Manual 1.6.2
hdrl_response.c
1/*
2 * This file is part of the HDRL
3 * Copyright (C) 2017 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24/*-----------------------------------------------------------------------------
25 Includes
26 -----------------------------------------------------------------------------*/
27
28#include "hdrl_response.h"
29#include "hdrl_spectrum_resample.h"
30#include "hdrl_efficiency.h"
31#include "hdrl_utils.h"
32#include <math.h>
33#include <cpl.h>
34
35
36/*-----------------------------------------------------------------------------
37 Private Functions
38 -----------------------------------------------------------------------------*/
39static inline cpl_array *
40get_uniform_wavs(const hdrl_spectrum1D * s, const hdrl_data_t w_step,
41 const hdrl_data_t lmin, const hdrl_data_t lmax);
42
43static inline hdrl_xcorrelation_result *
44correlate_obs_with_telluric(const hdrl_spectrum1D * obs_s,
45 const hdrl_spectrum1D * telluric_s,
46 const hdrl_data_t w_step,
47 cpl_size half_win,
48 const cpl_boolean normalize,
49 const hdrl_data_t lmin,
50 const hdrl_data_t lmax);
51
52static inline hdrl_spectrum1D *
53shift_and_convolve_telluric_model(const hdrl_spectrum1D * obs,
54 const hdrl_spectrum1D * telluric,
55 const hdrl_data_t w_step,
56 const cpl_size half_win,
57 const cpl_boolean normalize,
58 const hdrl_data_t lmin,
59 const hdrl_data_t lmax,
60 double * telluric_shift);
61
62static inline cpl_size get_lower_odd(const cpl_size sz);
63
64static inline hdrl_spectrum1D *
65convolve_with_kernel_symmetrically(const hdrl_spectrum1D * s,
66 const double sigma,
67 const hdrl_data_t w_step);
68
69static inline cpl_matrix *
70create_symmetrical_gaussian_kernel(const double slitw, const double fwhm,
71 const cpl_size max_sz);
72
73static inline hdrl_spectrum1D *
74convolve_spectrum_with_kernel(const hdrl_spectrum1D * s,
75 const cpl_matrix * kernel);
76
77static inline double
78erf_antideriv(const double x, const double sigma);
79
80
81/*calculate ratio between obs spectrum and convolved and shifted telluric model*/
82static inline hdrl_spectrum1D *
83compute_corrected_obs_spectrum(
84 const hdrl_spectrum1D * obs_s_arg,
85 const hdrl_spectrum1D * telluric_s_arg,
86 const hdrl_data_t w_step,
87 const cpl_size half_win,
88 const cpl_boolean normalize,
89 const cpl_boolean shift_in_log_scale,
90 const hdrl_data_t lmin, const hdrl_data_t lmax,
91 double * telluric_shift);
92
93static inline hdrl_spectrum1D *
94compute_interpolated_spectrum(const hdrl_spectrum1D * wlength_source,
95 const hdrl_spectrum1D * sampled_points,
96 const hdrl_spectrum1D_interpolation_method method);
97
98static inline void
99compute_quality(const hdrl_spectrum1D * s,
100 const cpl_bivector * quality_areas, double * mean_abs_difference_from_1,
101 double * stddev);
102
103static inline void
104free_spectrum_array(hdrl_spectrum1D ** s, const cpl_size sz);
105
106static inline cpl_error_code
107get_first_error_code(const cpl_error_code * codes, const cpl_size sz);
108
109static inline hdrl_spectrum1D *
110select_win(const hdrl_spectrum1D * s, const hdrl_data_t wmin,
111 const hdrl_data_t wmax);
112
113static inline hdrl_spectrum1D *
114select_obs_wlen( const hdrl_spectrum1D * s,
115 const hdrl_spectrum1D * wlens_source);
116
117static inline hdrl_spectrum1D *
118correct_spectrum_for_doppler_shift(const hdrl_spectrum1D * s,
119 const hdrl_data_t offset);
120
121static inline hdrl_spectrum1D *
122filter_spectrum_median(const hdrl_spectrum1D * resp, const cpl_size radius);
123
124static inline hdrl_image *
125compute_median_on_hdrl_image(const hdrl_image * img, const cpl_size radius);
126
127static inline hdrl_spectrum1D *
128resample_on_medians_skip_abs_regions(const hdrl_spectrum1D * s,
129 const cpl_array * fit_points, const cpl_bivector * high_abs_regions,
130 const hdrl_data_t wrange);
131
132static inline cpl_array *
133remove_regions_and_outliers_from_array(const cpl_array * fit_points,
134 const cpl_bivector * high_abs_regions,
135 const hdrl_data_t wmin, const hdrl_data_t wmax);
136
137static inline cpl_boolean
138contained_in_any_region(const hdrl_data_t w, const cpl_bivector * high_abs_regions);
139
140static inline hdrl_spectrum1D *
141get_median_on_fit_points(const hdrl_spectrum1D * s_input,
142 const cpl_array * fit_points, const hdrl_data_t wrange);
143
144static inline hdrl_spectrum1D *
145remove_bad_data(const hdrl_spectrum1D * s);
146
147static inline const hdrl_spectrum1Dlist *
148hdrl_response_telluric_evaluation_parameter_get_telluric_models(
149 const hdrl_parameter * par);
150
151static inline hdrl_data_t
152hdrl_response_telluric_evaluation_parameter_get_w_step(
153 const hdrl_parameter * par);
154
155static inline cpl_size
156hdrl_response_telluric_evaluation_parameter_get_half_win(
157 const hdrl_parameter * par);
158
159static inline cpl_boolean
160hdrl_response_telluric_evaluation_parameter_get_normalize(
161 const hdrl_parameter * par);
162
163static inline cpl_boolean
164hdrl_response_telluric_evaluation_parameter_get_shift_in_log_scale(
165 const hdrl_parameter * par);
166
167static inline const cpl_bivector *
168hdrl_response_telluric_evaluation_parameter_get_quality_areas(
169 const hdrl_parameter * par);
170
171static inline const cpl_bivector *
172hdrl_response_telluric_evaluation_parameter_get_fit_areas(
173 const hdrl_parameter * par);
174
175static inline hdrl_data_t
176hdrl_response_telluric_evaluation_parameter_get_lmin(
177 const hdrl_parameter * par);
178
179static inline hdrl_data_t
180hdrl_response_telluric_evaluation_parameter_get_lmax(
181 const hdrl_parameter * par);
182
183static inline const cpl_array *
184hdrl_response_parameter_get_fit_points(
185 const hdrl_parameter * par);
186
187static inline const cpl_bivector *
188hdrl_response_parameter_get_high_abs_regions(
189 const hdrl_parameter * par);
190
191static inline cpl_size
192hdrl_response_parameter_get_radius(
193 const hdrl_parameter * par);
194
195static inline hdrl_data_t
196hdrl_response_parameter_get_wrange(
197 const hdrl_parameter * par);
198
199static inline hdrl_spectrum1D *
200 hdrl_spectrum1D_extract_fit_regions(const hdrl_spectrum1D * s,
201 const cpl_bivector * areas);
202
203/*Private data structures*/
204
205/*Parameter used for the telluric evaluation*/
206typedef struct {
207 HDRL_PARAMETER_HEAD;
208 hdrl_spectrum1Dlist * telluric_models;
209 hdrl_data_t w_step;
210 cpl_size half_win;
211 cpl_boolean normalize;
212 cpl_boolean shift_in_log_scale;
213 cpl_bivector * quality_areas;
214 cpl_bivector * fit_areas;
215 hdrl_data_t lmin;
216 hdrl_data_t lmax;
217}hdrl_response_telluric_evaluation_parameter;
218
219static inline void
220hdrl_response_telluric_evaluation_parameter_delete(
221 hdrl_parameter * ev){
222
223 if(ev == NULL) return;
224
225 if(hdrl_parameter_get_parameter_enum(ev)
226 != HDRL_PARAMETER_RESPONSE_TELLURIC_EVALUATION)
227 return;
228
229 hdrl_response_telluric_evaluation_parameter * par =
230 (hdrl_response_telluric_evaluation_parameter *)ev;
231
232 hdrl_spectrum1Dlist_delete(par->telluric_models);
233 cpl_bivector_delete(par->quality_areas);
234 cpl_bivector_delete(par->fit_areas);
235 cpl_free(par);
236}
237
238static hdrl_parameter_typeobj
239hdrl_telluric_eval_parameters_type = {
240 HDRL_PARAMETER_RESPONSE_TELLURIC_EVALUATION, /* type */
241 (hdrl_alloc *)&cpl_malloc, /* fp_alloc */
242 (hdrl_free *)&hdrl_response_telluric_evaluation_parameter_delete, /* fp_free */
243 NULL, /* fp_destroy */
244 sizeof(hdrl_response_telluric_evaluation_parameter), /* obj_size */
245};
246
247/*Parameter used for the response*/
248typedef struct {
249 HDRL_PARAMETER_HEAD;
250 cpl_size radius;
251 cpl_array * fit_points;
252 cpl_bivector * high_abs_regions;
253 hdrl_data_t wrange;
254}response_fit_parameter;
255
256static inline void
257hdrl_response_fit_parameter_delete(
258 hdrl_parameter * ev){
259
260 if(ev == NULL) return;
261
262 if(hdrl_parameter_get_parameter_enum(ev)
263 != HDRL_PARAMETER_RESPONSE_FIT)
264 return;
265
266 response_fit_parameter * par =
267 (response_fit_parameter *)ev;
268
269 cpl_bivector_delete(par->high_abs_regions);
270 cpl_array_delete(par->fit_points);
271 cpl_free(par);
272}
273
274static hdrl_parameter_typeobj
275hdrl_response_parameters_type = {
276 HDRL_PARAMETER_RESPONSE_FIT, /* type */
277 (hdrl_alloc *)&cpl_malloc, /* fp_alloc */
278 (hdrl_free *)&hdrl_response_fit_parameter_delete, /* fp_free */
279 NULL, /* fp_destroy */
280 sizeof(response_fit_parameter), /* obj_size */
281};
282
283
284static inline hdrl_spectrum1D *
285hdrl_spectrum1D_create_from_buffers(double * flux, double * wlens, cpl_size sz,
286 hdrl_spectrum1D_wave_scale scale);
287
288static inline hdrl_response_result *
289hdrl_response_result_wrap(hdrl_spectrum1D * final_response,
290 hdrl_spectrum1D * selected_response,
291 hdrl_spectrum1D * raw_response,
292
293 hdrl_spectrum1D * corrected_observed_spectrum,
294 cpl_size best_telluric_model_idx,
295 hdrl_data_t telluric_shift,
296 hdrl_data_t avg_diff_from_1,
297 hdrl_data_t stddev,
298
299 hdrl_data_t doppler_shift);
300
305/*----------------------------------------------------------------------------*/
306
309/*-----------------------------------------------------------------------------
310 Functions
311 -----------------------------------------------------------------------------*/
312
313/* ---------------------------------------------------------------------------*/
344/* ---------------------------------------------------------------------------*/
345
346hdrl_parameter *
348 const hdrl_spectrum1Dlist * telluric_models,
349 hdrl_data_t w_step,
350 cpl_size half_win,
351 cpl_boolean normalize,
352 cpl_boolean shift_in_log_scale,
353 const cpl_bivector * quality_areas,
354 const cpl_bivector * fit_areas,
355 hdrl_data_t lmin,
356 hdrl_data_t lmax){
357
358 cpl_ensure(quality_areas != NULL, CPL_ERROR_NULL_INPUT, NULL);
359 cpl_ensure(telluric_models != NULL, CPL_ERROR_NULL_INPUT, NULL);
360 cpl_ensure(fit_areas != NULL, CPL_ERROR_NULL_INPUT, NULL);
361 cpl_ensure(w_step > 0.0, CPL_ERROR_ILLEGAL_INPUT, NULL);
362 cpl_ensure(half_win > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
363 cpl_ensure(lmin < lmax, CPL_ERROR_ILLEGAL_INPUT, NULL);
364
365 hdrl_response_telluric_evaluation_parameter * ev
366 = (hdrl_response_telluric_evaluation_parameter *)
367 hdrl_parameter_new(&hdrl_telluric_eval_parameters_type);
368
369 ev->telluric_models = hdrl_spectrum1Dlist_duplicate(telluric_models);
370 ev->w_step = w_step;
371 ev->half_win = half_win;
372 ev->normalize = normalize;
373 ev->shift_in_log_scale = shift_in_log_scale;
374 ev->quality_areas = cpl_bivector_duplicate(quality_areas);
375 ev->fit_areas = cpl_bivector_duplicate(fit_areas);
376 ev->lmin = lmin;
377 ev->lmax = lmax;
378
379 return (hdrl_parameter *)ev;
380}
381
382
383/* ---------------------------------------------------------------------------*/
401/* ---------------------------------------------------------------------------*/
402hdrl_parameter *
404 const cpl_size radius, const cpl_array * fit_points,
405 const hdrl_data_t wrange, const cpl_bivector * high_abs_regions){
406
407 cpl_ensure(radius > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
408 cpl_ensure(wrange > 0.0, CPL_ERROR_ILLEGAL_INPUT, NULL);
409 cpl_ensure(fit_points != NULL, CPL_ERROR_NULL_INPUT, NULL);
410
411 response_fit_parameter * p
412 = (response_fit_parameter *)
413 hdrl_parameter_new(&hdrl_response_parameters_type);
414
415 p->fit_points = cpl_array_duplicate(fit_points);
416 p->high_abs_regions = NULL;
417
418 if(high_abs_regions)
419 p->high_abs_regions = cpl_bivector_duplicate(high_abs_regions);
420
421 p->radius = radius;
422 p->wrange = wrange;
423
424 return (hdrl_parameter *) p;
425}
426
427/* ---------------------------------------------------------------------------*/
457/* ---------------------------------------------------------------------------*/
458hdrl_response_result *
460 const hdrl_spectrum1D * obs_s,
461 const hdrl_spectrum1D * ref_s,
462 const hdrl_spectrum1D * E_x,
463 const hdrl_parameter * telluric_par,
464 const hdrl_parameter * velocity_par,
465 const hdrl_parameter * calc_par,
466 const hdrl_parameter * fit_par){
467
468 cpl_ensure(calc_par != NULL, CPL_ERROR_NULL_INPUT, NULL);
469 cpl_ensure(hdrl_parameter_get_parameter_enum(calc_par) ==
470 HDRL_PARAMETER_EFFICIENCY, CPL_ERROR_ILLEGAL_INPUT, NULL);
471
472 if(telluric_par)
473 cpl_ensure(hdrl_parameter_get_parameter_enum(telluric_par) ==
474 HDRL_PARAMETER_RESPONSE_TELLURIC_EVALUATION,
475 CPL_ERROR_ILLEGAL_INPUT, NULL);
476
477 if(velocity_par)
478 cpl_ensure(hdrl_parameter_get_parameter_enum(velocity_par) ==
479 HDRL_PARAMETER_SPECTRUM1D_SHIFT,
480 CPL_ERROR_ILLEGAL_INPUT, NULL);
481
482 cpl_ensure(fit_par != NULL, CPL_ERROR_NULL_INPUT, NULL);
483 cpl_ensure(hdrl_parameter_get_parameter_enum(fit_par) ==
484 HDRL_PARAMETER_RESPONSE_FIT, CPL_ERROR_ILLEGAL_INPUT, NULL);
485
486 cpl_ensure(obs_s != NULL, CPL_ERROR_NULL_INPUT, NULL);
487 cpl_ensure(ref_s != NULL, CPL_ERROR_NULL_INPUT, NULL);
488 cpl_ensure(E_x != NULL, CPL_ERROR_NULL_INPUT, NULL);
489
490 hdrl_data_t best_mean_minus1 = 0, best_stddev = 0;
491 hdrl_data_t best_telluric_shift = 0;
492 cpl_size best_idx = -1;
493
494 hdrl_spectrum1D * corrected_obs =
495 hdrl_response_evaluate_telluric_models(obs_s, telluric_par,
496 &best_telluric_shift, &best_mean_minus1, &best_stddev, &best_idx);
497
498 cpl_ensure(best_idx >= 0, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
499 cpl_ensure(corrected_obs != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
500
501 cpl_ensure(cpl_error_get_code() == CPL_ERROR_NONE,
502 CPL_ERROR_ILLEGAL_OUTPUT, NULL);
503
504 hdrl_data_t velocity_shift = 0.0;
505 if(velocity_par != NULL){
506 velocity_shift =
507 hdrl_spectrum1D_compute_shift_fit(corrected_obs, velocity_par);
508 }
509
510 cpl_ensure(cpl_error_get_code() == CPL_ERROR_NONE,
511 CPL_ERROR_ILLEGAL_OUTPUT, NULL);
512
513 hdrl_spectrum1D * ref_shifted =
514 correct_spectrum_for_doppler_shift(ref_s,
515 velocity_shift);
516
517 cpl_ensure(ref_shifted != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
518 cpl_ensure(cpl_error_get_code() == CPL_ERROR_NONE,
519 CPL_ERROR_ILLEGAL_OUTPUT, NULL);
520
521 hdrl_spectrum1D * resp_raw =
522 hdrl_response_core_compute(corrected_obs, ref_shifted, E_x, calc_par);
523
524 cpl_ensure(resp_raw != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
525 cpl_ensure(cpl_error_get_code() == CPL_ERROR_NONE,
526 CPL_ERROR_ILLEGAL_OUTPUT, NULL);
527
528 const cpl_size radius = hdrl_response_parameter_get_radius(fit_par);
529 const cpl_bivector * high_abs_regions =
530 hdrl_response_parameter_get_high_abs_regions(fit_par);
531 const cpl_array * fit_points =
532 hdrl_response_parameter_get_fit_points(fit_par);
533 const hdrl_data_t wrange =
534 hdrl_response_parameter_get_wrange(fit_par);
535
536 cpl_ensure(cpl_error_get_code() == CPL_ERROR_NONE,
537 CPL_ERROR_ILLEGAL_OUTPUT, NULL);
538
539 hdrl_spectrum1D * resp_smoothed =
540 filter_spectrum_median(resp_raw, radius);
541
542 cpl_ensure(resp_smoothed != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
543 cpl_ensure(cpl_error_get_code() == CPL_ERROR_NONE, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
544
545 hdrl_spectrum1D * resp_on_fit_points =
546 resample_on_medians_skip_abs_regions(resp_smoothed, fit_points,
547 high_abs_regions, wrange);
548
549 cpl_ensure(resp_on_fit_points != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
550 cpl_ensure(cpl_error_get_code() == CPL_ERROR_NONE,
551 CPL_ERROR_ILLEGAL_OUTPUT, NULL);
552
553
554 hdrl_parameter * par =
555 hdrl_spectrum1D_resample_interpolate_parameter_create(hdrl_spectrum1D_interp_akima);
556
557 hdrl_spectrum1D * resp_final =
558 hdrl_spectrum1D_resample_on_array(resp_on_fit_points,
559 hdrl_spectrum1D_get_wavelength(resp_smoothed).wavelength,
560 par);
561
563 hdrl_spectrum1D_delete(&resp_smoothed);
564 hdrl_spectrum1D_delete(&ref_shifted);
565
566
567 return hdrl_response_result_wrap(resp_final, resp_on_fit_points,
568 resp_raw, corrected_obs, best_idx, best_telluric_shift,
569 best_mean_minus1, best_stddev, velocity_shift);
570}
571
572/* ---------------------------------------------------------------------------*/
583/* ---------------------------------------------------------------------------*/
584
585const hdrl_spectrum1D *
586hdrl_response_result_get_final_response(const hdrl_response_result * res){
587 cpl_ensure(res != NULL, CPL_ERROR_NULL_INPUT, NULL);
588 return res->final_response;
589}
590
591/* ---------------------------------------------------------------------------*/
603/* ---------------------------------------------------------------------------*/
604
605const hdrl_spectrum1D *
606hdrl_response_result_get_selected_response(const hdrl_response_result * res){
607 cpl_ensure(res != NULL, CPL_ERROR_NULL_INPUT, NULL);
608 return res->selected_response;
609}
610
611/* ---------------------------------------------------------------------------*/
623/* ---------------------------------------------------------------------------*/
624const hdrl_spectrum1D *
625hdrl_response_result_get_raw_response(const hdrl_response_result * res){
626 cpl_ensure(res != NULL, CPL_ERROR_NULL_INPUT, NULL);
627 return res->raw_response;
628}
629
630/* ---------------------------------------------------------------------------*/
641/* ---------------------------------------------------------------------------*/
642const hdrl_spectrum1D *
643hdrl_response_result_get_corrected_obs_spectrum(const hdrl_response_result * res){
644 cpl_ensure(res != NULL, CPL_ERROR_NULL_INPUT, NULL);
645 return res->corrected_observed_spectrum;
646}
647
648/* ---------------------------------------------------------------------------*/
660/* ---------------------------------------------------------------------------*/
661cpl_size
662hdrl_response_result_get_best_telluric_model_idx(const hdrl_response_result * res){
663 cpl_ensure(res != NULL, CPL_ERROR_NULL_INPUT, -1);
664 return res->best_telluric_model_idx;
665}
666
667/* ---------------------------------------------------------------------------*/
682/* ---------------------------------------------------------------------------*/
683hdrl_data_t
684hdrl_response_result_get_avg_diff_from_1(const hdrl_response_result * res){
685 cpl_ensure(res != NULL, CPL_ERROR_NULL_INPUT, NAN);
686 return res->avg_diff_from_1;
687}
688
689/* ---------------------------------------------------------------------------*/
704/* ---------------------------------------------------------------------------*/
705hdrl_data_t
706hdrl_response_result_get_stddev(const hdrl_response_result * res){
707 cpl_ensure(res != NULL, CPL_ERROR_NULL_INPUT, NAN);
708 return res->stddev;
709}
710
711/* ---------------------------------------------------------------------------*/
724/* ---------------------------------------------------------------------------*/
725hdrl_data_t
726hdrl_response_result_get_telluric_shift(const hdrl_response_result * res){
727 cpl_ensure(res != NULL, CPL_ERROR_NULL_INPUT, NAN);
728 return res->telluric_shift;
729}
730
731/* ---------------------------------------------------------------------------*/
742/* ---------------------------------------------------------------------------*/
743hdrl_data_t
744hdrl_response_result_get_doppler_shift(const hdrl_response_result * res){
745 cpl_ensure(res != NULL, CPL_ERROR_NULL_INPUT, NAN);
746 return res->doppler_shift;
747}
748
749
750/* ---------------------------------------------------------------------------*/
755/* ---------------------------------------------------------------------------*/
756void
757hdrl_response_result_delete(hdrl_response_result * res){
758
759 if(!res) return;
760
761 hdrl_spectrum1D_delete(&(res->final_response));
762 hdrl_spectrum1D_delete(&(res->selected_response));
763 hdrl_spectrum1D_delete(&(res->raw_response));
764
765 hdrl_spectrum1D_delete(&(res->corrected_observed_spectrum));
766
767 cpl_free(res);
768}
769
770/* This function evaluates all the telluric models inside the hdrl_parameter ev,
771 * picks the best model, returns its index (best_model_index), some quality parameter
772 * (mean_minus_1 and stddev) and obs_s corrected with the best model.
773 * If ev == NULL the function returns a copy of obs_s.
774 * ev is created using hdrl_response_telluric_evaluation_parameter_create. */
775hdrl_spectrum1D *
776hdrl_response_evaluate_telluric_models(
777 const hdrl_spectrum1D * obs_s,
778 const hdrl_parameter * ev,
779 hdrl_data_t * telluric_shift,
780 hdrl_data_t * mean_minus_1, hdrl_data_t * stddev,
781 cpl_size * best_model_index){
782
783 cpl_ensure(mean_minus_1 != NULL, CPL_ERROR_NULL_INPUT, NULL);
784 cpl_ensure(stddev != NULL, CPL_ERROR_NULL_INPUT, NULL);
785 cpl_ensure(best_model_index != NULL, CPL_ERROR_NULL_INPUT, NULL);
786 cpl_ensure(obs_s != NULL, CPL_ERROR_NULL_INPUT, NULL);
787
788 *mean_minus_1 = (hdrl_data_t)0.0;
789 *stddev = (hdrl_data_t)0.0;
790 *best_model_index = -1;
791
792 if(ev == NULL){
793 *best_model_index = 0;
794 *mean_minus_1 = NAN;
795 *stddev = NAN;
796 *telluric_shift = NAN;
797 return hdrl_spectrum1D_duplicate(obs_s);
798 }
799
800 cpl_ensure(hdrl_parameter_get_parameter_enum(ev)
801 == HDRL_PARAMETER_RESPONSE_TELLURIC_EVALUATION,
802 CPL_ERROR_ILLEGAL_INPUT, NULL);
803
804 const hdrl_spectrum1Dlist * telluric_models =
805 hdrl_response_telluric_evaluation_parameter_get_telluric_models(ev);
806 const hdrl_data_t w_step =
807 hdrl_response_telluric_evaluation_parameter_get_w_step(ev);
808 const cpl_size half_win =
809 hdrl_response_telluric_evaluation_parameter_get_half_win(ev);
810 const cpl_boolean normalize =
811 hdrl_response_telluric_evaluation_parameter_get_normalize(ev);
812 const cpl_boolean shift_in_log_scale =
813 hdrl_response_telluric_evaluation_parameter_get_shift_in_log_scale(ev);
814 const cpl_bivector * quality_areas =
815 hdrl_response_telluric_evaluation_parameter_get_quality_areas(ev);
816 const cpl_bivector * fit_areas =
817 hdrl_response_telluric_evaluation_parameter_get_fit_areas(ev);
818 const hdrl_data_t lmin =
819 hdrl_response_telluric_evaluation_parameter_get_lmin(ev);
820 const hdrl_data_t lmax =
821 hdrl_response_telluric_evaluation_parameter_get_lmax(ev);
822
823 hdrl_spectrum1D * to_ret = NULL;
824
825 const cpl_size sz = hdrl_spectrum1Dlist_get_size(telluric_models);
826 cpl_ensure(sz > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
827
828 cpl_array * calc_std_devs = cpl_array_new(sz, CPL_TYPE_DOUBLE);
829 cpl_array * calc_means_minus_1 = cpl_array_new(sz, CPL_TYPE_DOUBLE);
830 cpl_array * calc_telluric_shift = cpl_array_new(sz, CPL_TYPE_DOUBLE);
831
832 cpl_array_fill_window(calc_std_devs, 0, sz, 0);
833 cpl_array_fill_window(calc_means_minus_1, 0, sz, 0);
834 cpl_array_fill_window(calc_telluric_shift, 0, sz, 0);
835
836 double * p_stddevs = cpl_array_get_data_double(calc_std_devs);
837 double * p_means = cpl_array_get_data_double(calc_means_minus_1);
838 double * p_telluric_shift = cpl_array_get_data_double(calc_telluric_shift);
839
840 hdrl_spectrum1D ** l = cpl_calloc(sz, sizeof(hdrl_spectrum1D*));
841 cpl_error_code * codes = cpl_calloc(sz, sizeof(cpl_error_code));
842
843 HDRL_OMP(omp parallel for)
844 for(cpl_size i = 0; i < sz; ++i){
845 const hdrl_spectrum1D * this_model =
846 hdrl_spectrum1Dlist_get_const(telluric_models, i);
847
848 l[i] = hdrl_response_evaluate_telluric_model(obs_s, this_model, w_step,
849 half_win, normalize, shift_in_log_scale, quality_areas, fit_areas,
850 lmin, lmax, p_means + i, p_stddevs + i,p_telluric_shift + i);
851 codes[i] = cpl_error_get_code();
852
853 if(l[i] == NULL && codes[i] == CPL_ERROR_NONE)
854 codes[i] = CPL_ERROR_ILLEGAL_OUTPUT;
855 }
856
857 cpl_error_code err = get_first_error_code(codes, sz);
858
859 if(!err){
860 cpl_size best_idx = 0;
861 err = cpl_array_get_minpos(calc_means_minus_1, &best_idx);
862 if(!err){
863 *stddev = cpl_array_get(calc_std_devs, best_idx, NULL);
864 *mean_minus_1 = cpl_array_get(calc_means_minus_1, best_idx, NULL);
865 *telluric_shift = cpl_array_get(calc_telluric_shift, best_idx, NULL);
866 to_ret = l[best_idx];
867 l[best_idx] = NULL;
868 *best_model_index = best_idx;
869 }
870 }
871
872 cpl_array_delete(calc_std_devs);
873 cpl_array_delete(calc_means_minus_1);
874 cpl_array_delete(calc_telluric_shift);
875 cpl_free(codes);
876 free_spectrum_array(l, sz);
877
878 cpl_ensure(err == CPL_ERROR_NONE, err, NULL);
879
880 return to_ret;
881}
882
883
884
885/*This function evaluates how well a telluric model corrects an observed spectrum.
886 * For the parameters see hdrl_response_telluric_evaluation_parameter_create.*/
887hdrl_spectrum1D *
888hdrl_response_evaluate_telluric_model(const hdrl_spectrum1D * obs_s_arg,
889 const hdrl_spectrum1D * telluric_s_arg,
890 const hdrl_data_t w_step,
891 const cpl_size half_win,
892 const cpl_boolean normalize,
893 const cpl_boolean shift_in_log_scale,
894 const cpl_bivector * quality_areas,
895 const cpl_bivector * fit_areas,
896 const hdrl_data_t lmin, const hdrl_data_t lmax,
897 double * mean_minus_1, double * stddev,
898 double * telluric_shift){
899
900 cpl_ensure(obs_s_arg != NULL, CPL_ERROR_NULL_INPUT, NULL);
901 cpl_ensure(telluric_s_arg != NULL, CPL_ERROR_NULL_INPUT, NULL);
902 cpl_ensure(quality_areas != NULL, CPL_ERROR_NULL_INPUT, NULL);
903 cpl_ensure(fit_areas != NULL, CPL_ERROR_NULL_INPUT, NULL);
904 cpl_ensure(mean_minus_1 != NULL, CPL_ERROR_NULL_INPUT, NULL);
905 cpl_ensure(stddev != NULL, CPL_ERROR_NULL_INPUT, NULL);
906 cpl_ensure(w_step > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
907 cpl_ensure(half_win > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
908
909 *mean_minus_1 = 0.0;
910 *stddev = 0.0;
911 *telluric_shift = 0.0;
912
913 hdrl_spectrum1D * corrected_spectrum =
914 compute_corrected_obs_spectrum(obs_s_arg,
915 telluric_s_arg, w_step, half_win, normalize,
916 shift_in_log_scale, lmin, lmax, telluric_shift);
917
918 cpl_ensure(corrected_spectrum != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
919
920 hdrl_spectrum1D * corr_spectrum_extracted =
921 hdrl_spectrum1D_extract_fit_regions(corrected_spectrum, fit_areas);
922
923 if(corr_spectrum_extracted == NULL) {
924 hdrl_spectrum1D_delete(&corrected_spectrum);
925 cpl_ensure(CPL_FALSE, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
926 }
927
928 hdrl_spectrum1D * smoothed_fit =
929 compute_interpolated_spectrum(corrected_spectrum,
930 corr_spectrum_extracted, hdrl_spectrum1D_interp_akima);
931
932 hdrl_spectrum1D * quality_ratio =
933 hdrl_spectrum1D_div_spectrum_create(corrected_spectrum, smoothed_fit);
934
935 compute_quality(quality_ratio, quality_areas, mean_minus_1, stddev);
936
937 hdrl_spectrum1D_delete(&corr_spectrum_extracted);
938 hdrl_spectrum1D_delete(&smoothed_fit);
939 hdrl_spectrum1D_delete(&quality_ratio);
940
941 return corrected_spectrum;
942}
943
944/*-----------------------------------------------------------------------------
945 Private Functions
946 -----------------------------------------------------------------------------*/
947
948/* Given a spectrum the function calculates:
949 * mean_abs_difference_from_1 = |mean - 1| and standard deviation.
950 * The flux defined on wavelengths outside the quality_areas are ignored.*/
951static inline void
952compute_quality(const hdrl_spectrum1D * s,
953 const cpl_bivector * quality_areas, double * mean_abs_difference_from_1,
954 double * stddev){
955
956 hdrl_spectrum1D * s_new =
957 hdrl_spectrum1D_select_wavelengths(s, quality_areas, CPL_TRUE);
958
959 const hdrl_image * flux = hdrl_spectrum1D_get_flux(s_new);
960
961 *mean_abs_difference_from_1 = fabs(hdrl_image_get_mean(flux).data - 1.0);
962 *stddev = hdrl_image_get_stdev(flux);
963
965}
966
967/* Interpolates using a cspline the points in sampled_points to obtain a spectrum
968 * defined on the wavelengths of wlength_source*/
969static inline hdrl_spectrum1D *
970compute_interpolated_spectrum(const hdrl_spectrum1D * wlength_source,
971 const hdrl_spectrum1D * sampled_points,
972 const hdrl_spectrum1D_interpolation_method method){
973
974 hdrl_parameter * par =
976
977 hdrl_spectrum1D_wavelength waves = hdrl_spectrum1D_get_wavelength(wlength_source);
978
979 hdrl_spectrum1D * continuum_fit =
980 hdrl_spectrum1D_resample(sampled_points, &waves, par);
981
983 return continuum_fit;
984}
985
986/* This function correct the observed spectrum by the telluric spectrum. In order
987 * to do so, the function aligns the two spectra, convolves the telluric model by
988 * a gaussian kernel. The observed spectrum is then divided by the shifted and
989 * convolved telluric model.
990 * NOTE: the output spectrum is defined on the wavelengths of obs_s_arg.*/
991static inline hdrl_spectrum1D *
992compute_corrected_obs_spectrum(
993 const hdrl_spectrum1D * obs_s_arg,
994 const hdrl_spectrum1D * telluric_s_arg,
995 const hdrl_data_t w_step, const cpl_size half_win,
996 const cpl_boolean normalize,
997 const cpl_boolean shift_in_log_scale,
998 const hdrl_data_t lmin, const hdrl_data_t lmax,
999 double * telluric_shift){
1000
1001 cpl_ensure(obs_s_arg != NULL, CPL_ERROR_NULL_INPUT, NULL);
1002 cpl_ensure(telluric_s_arg != NULL, CPL_ERROR_NULL_INPUT, NULL);
1003
1004 hdrl_spectrum1D_wavelength obs_wavs = hdrl_spectrum1D_get_wavelength(obs_s_arg);
1005
1006 hdrl_spectrum1D * obs_s = hdrl_spectrum1D_duplicate(obs_s_arg);
1007 hdrl_spectrum1D * telluric_s_cp = hdrl_spectrum1D_duplicate(telluric_s_arg);
1008
1009 if(shift_in_log_scale){
1012 }
1013
1014 hdrl_spectrum1D * telluric_s_shifted_convolved=
1015 shift_and_convolve_telluric_model(obs_s, telluric_s_cp, w_step,
1016 half_win, normalize, lmin, lmax, telluric_shift);
1017
1018
1019 if(telluric_s_shifted_convolved != NULL){
1020 hdrl_spectrum1D_wavelength_convert_to_linear(telluric_s_shifted_convolved);
1021 }
1022
1024 hdrl_spectrum1D * telluric_s_shifted_convolved_downsampled =
1025 hdrl_spectrum1D_resample(telluric_s_shifted_convolved, &obs_wavs, pars);
1026 hdrl_spectrum1D * corrected =
1027 hdrl_spectrum1D_div_spectrum_create(obs_s_arg , telluric_s_shifted_convolved_downsampled);
1028
1029 hdrl_spectrum1D_delete(&obs_s);
1030 hdrl_spectrum1D_delete(&telluric_s_cp);
1031 hdrl_spectrum1D_delete(&telluric_s_shifted_convolved);
1032 hdrl_spectrum1D_delete(&telluric_s_shifted_convolved_downsampled);
1034
1035 return corrected;
1036}
1037
1038/*Trims s so that its minimum and maximum wavelenghts do not exceed wlens_source*/
1039static inline hdrl_spectrum1D *
1040select_obs_wlen( const hdrl_spectrum1D * s,
1041 const hdrl_spectrum1D * wlens_source){
1042
1043 const cpl_array * wlens = hdrl_spectrum1D_get_wavelength(wlens_source).wavelength;
1044
1045 const hdrl_data_t wmin = cpl_array_get_min(wlens);
1046 const hdrl_data_t wmax = cpl_array_get_max(wlens);
1047
1048 return select_win(s, wmin, wmax);
1049}
1050
1051/*The telluric model is correlated with the observed spectrum to compute the
1052 * relative shift between the two. Then the telluric model is shifted to match the
1053 * observed spectrum. Then the shifted model is convolved with a gaussian kernel. */
1054static inline hdrl_spectrum1D *
1055shift_and_convolve_telluric_model(const hdrl_spectrum1D * obs,
1056 const hdrl_spectrum1D * telluric,
1057 const hdrl_data_t w_step,
1058 const cpl_size half_win,
1059 const cpl_boolean normalize,
1060 const hdrl_data_t lmin,
1061 const hdrl_data_t lmax,
1062 double * telluric_shift){
1063
1064 hdrl_spectrum1D * telluric_s = select_win(telluric, lmin, lmax);
1065
1066 cpl_ensure(telluric_s != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
1067
1068 hdrl_xcorrelation_result * res =
1069 correlate_obs_with_telluric(obs, telluric_s,
1070 w_step, half_win, normalize, lmin, lmax);
1071 hdrl_spectrum1D_delete(&telluric_s);
1072
1073 cpl_ensure(res != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
1074
1075 hdrl_data_t shift = (hdrl_data_t)
1078
1079 *telluric_shift = shift;
1080
1081 hdrl_spectrum1D * telluric_selected_obs =
1082 select_obs_wlen(telluric, obs);
1083
1084 hdrl_spectrum1D * telluric_s_shifted =
1085 hdrl_spectrum1D_wavelength_shift_create(telluric_selected_obs, shift);
1086 const double sigma = hdrl_xcorrelation_result_get_sigma(res);
1087
1089
1090 cpl_ensure(telluric_s_shifted != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
1091
1092 hdrl_spectrum1D * telluric_s_shifted_convolved =
1093 convolve_with_kernel_symmetrically(telluric_s_shifted, sigma, w_step);
1094
1095 hdrl_spectrum1D_delete(&telluric_s_shifted);
1096 hdrl_spectrum1D_delete(&telluric_selected_obs);
1097
1098 return telluric_s_shifted_convolved;
1099}
1100
1101/*The function: 1. resamples uniformly obs_s and telluric_s, so they're defined
1102 * on the same wavelengths. 2. correlates the two spectra to find out the relative
1103 * shift of one wrt the other.
1104 *
1105 * w_step, lmin and lmax are used for the resampling, all the other inputs
1106 * are used for the cross correlation.*/
1107static inline hdrl_xcorrelation_result *
1108correlate_obs_with_telluric(const hdrl_spectrum1D * obs_s,
1109 const hdrl_spectrum1D * telluric_s,
1110 const hdrl_data_t w_step,
1111 const cpl_size half_win,
1112 const cpl_boolean normalize,
1113 const hdrl_data_t lmin,
1114 const hdrl_data_t lmax){
1115
1116 cpl_ensure(obs_s != NULL, CPL_ERROR_NULL_INPUT, NULL);
1117 cpl_ensure(telluric_s != NULL, CPL_ERROR_NULL_INPUT, NULL);
1118
1119 hdrl_data_t wmin = cpl_array_get_min(hdrl_spectrum1D_get_wavelength(obs_s).wavelength);
1120 hdrl_data_t wmax = cpl_array_get_max(hdrl_spectrum1D_get_wavelength(obs_s).wavelength);
1121
1122 hdrl_spectrum1D * tell_for_sel = select_win(telluric_s, wmin, wmax);
1123
1124 hdrl_spectrum1D * telluric_s_res = NULL;
1125 hdrl_spectrum1D * obs_s_res = NULL;
1126 {
1127 cpl_array * new_lambdas = get_uniform_wavs(tell_for_sel, w_step, lmin, lmax);
1128
1129 /*
1130 * We need to make sure that telluric_s and obs_s are
1131 * sampled uniformly.
1132 */
1133 hdrl_parameter * par =
1135 (hdrl_spectrum1D_interp_akima);
1136
1137 telluric_s_res =
1138 hdrl_spectrum1D_resample_on_array(telluric_s, new_lambdas, par);
1139
1140 obs_s_res =
1141 hdrl_spectrum1D_resample_on_array(obs_s, new_lambdas, par);
1142
1144 cpl_array_delete(new_lambdas);
1145 }
1146
1147 cpl_ensure(obs_s_res != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
1148 cpl_ensure(telluric_s_res != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
1149
1150 hdrl_xcorrelation_result * gshift =
1151 hdrl_spectrum1D_compute_shift_xcorrelation(telluric_s_res, obs_s_res,
1152 half_win, normalize);
1153
1154 hdrl_spectrum1D_delete(&telluric_s_res);
1155 hdrl_spectrum1D_delete(&obs_s_res);
1156 hdrl_spectrum1D_delete(&tell_for_sel);
1157 return gshift;
1158}
1159
1160
1161/*This function returns a uniformly sampled sequence of wavelengths. The distance
1162 * between 2 elements is w_step, the starting point is max(lmin, min_wavelengths_s)
1163 * the end point is min(lmax, max_wavelegths_s)*/
1164static inline cpl_array *
1165get_uniform_wavs(const hdrl_spectrum1D * s, const hdrl_data_t w_step,
1166 const hdrl_data_t lmin, const hdrl_data_t lmax){
1167
1168 const hdrl_data_t w_min = CPL_MAX(lmin,
1169 cpl_array_get_min(hdrl_spectrum1D_get_wavelength(s).wavelength));
1170 const hdrl_data_t w_max = CPL_MIN(lmax,
1171 cpl_array_get_max(hdrl_spectrum1D_get_wavelength(s).wavelength));
1172
1173 const cpl_size sz_new_spectrum = (w_max - w_min)/w_step;
1174 cpl_array * new_w_lengths = cpl_array_new(sz_new_spectrum, HDRL_TYPE_DATA);
1175
1176 for(cpl_size i = 0; i < sz_new_spectrum; ++i){
1177 cpl_array_set(new_w_lengths, i, i * w_step + w_min);
1178 }
1179
1180 return new_w_lengths;
1181}
1182
1183/*This function convolves a kernel with the flux of a spectrum. The output
1184 * spectrum is without error and it is defined on the same wavelengths of the input
1185 * spectrum. The convolution one the borders is done using a reduced number of samples.*/
1186static inline hdrl_spectrum1D *
1187convolve_spectrum_with_kernel(const hdrl_spectrum1D * s,
1188 const cpl_matrix * kernel){
1189
1190 const cpl_size sz = hdrl_spectrum1D_get_size(s);
1191 const hdrl_image * h_img = hdrl_spectrum1D_get_flux(s);
1192 const cpl_image * img = hdrl_image_get_image_const(h_img);
1193 cpl_image * dest = cpl_image_new(sz, 1, HDRL_TYPE_DATA);
1194
1195 const cpl_error_code cd =
1196 cpl_image_filter(dest, img, kernel, CPL_FILTER_LINEAR, CPL_BORDER_FILTER);
1197
1198
1199 hdrl_spectrum1D * to_ret = NULL;
1200 if(cd == CPL_ERROR_NONE){
1201 hdrl_spectrum1D_wavelength s_wav = hdrl_spectrum1D_get_wavelength(s);
1202
1203 to_ret =
1204 hdrl_spectrum1D_create_error_free(dest, s_wav.wavelength, s_wav.scale);
1205 }
1206
1207 cpl_image_delete(dest);
1208
1209 cpl_ensure(cd == CPL_ERROR_NONE, cd, NULL);
1210
1211 return to_ret;
1212}
1213
1214static inline cpl_size get_lower_odd(const cpl_size sz){
1215
1216 if(sz == 0) return 0;
1217
1218 if(sz % 2 == 1) return sz;
1219 return sz - 1;
1220}
1221
1222/*This function convolves the spectrum s with a symmetrical gaussian kernel having
1223 * std deviation sigma. The wavelength step of the kernel is w_step.*/
1224static inline hdrl_spectrum1D *
1225convolve_with_kernel_symmetrically(const hdrl_spectrum1D * s,
1226 const double sigma,
1227 const hdrl_data_t w_step){
1228
1229 const double fwhm = CPL_MATH_FWHM_SIG * sigma;
1230 int fwhm_pix = (int) (fwhm / w_step + 0.5);
1231
1232 cpl_matrix * kernel =
1233 create_symmetrical_gaussian_kernel(fwhm_pix / CPL_MATH_FWHM_SIG,
1234 fwhm_pix / CPL_MATH_FWHM_SIG,
1235 get_lower_odd(hdrl_spectrum1D_get_size(s)));
1236
1237 hdrl_spectrum1D * convolved =
1238 convolve_spectrum_with_kernel(s, kernel);
1239 cpl_matrix_delete(kernel);
1240
1241 cpl_ensure(convolved != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
1242
1243 return convolved;
1244}
1245
1246/* Creates a gaussian symmetrical kernel for a given slit width (slitw) and a given
1247 * fwhm. The function ALWAYS returns a kernel with a odd number of elements.*/
1248static inline cpl_matrix *
1249create_symmetrical_gaussian_kernel(const double slitw, const double fwhm,
1250 const cpl_size max_sz){
1251
1252 cpl_ensure(slitw > 0.0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1253 cpl_ensure(fwhm > 0.0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1254
1255 const double sigma = fwhm * CPL_MATH_SIG_FWHM;
1256 cpl_size size = 1 + (cpl_size)(5.0 * sigma + 0.5*slitw);
1257
1258 size *= 2;
1259 /* filter need an odd number of elements */
1260 size ++;
1261
1262 size = CPL_MIN(size, max_sz);
1263
1264 cpl_matrix * kernel = cpl_matrix_new(1, size);
1265
1266 /* Special case for i = 0 */
1267 cpl_matrix_set(kernel, 0, size/2,
1268 (erf_antideriv(0.5*slitw + 0.5, sigma) -
1269 erf_antideriv(0.5*slitw - 0.5, sigma)) / slitw);
1270
1271 for (cpl_size i = 1; i < size / 2; i++) {
1272
1273 const double x1p = (double)i + 0.5 * slitw + 0.5;
1274 const double x1n = (double)i - 0.5 * slitw + 0.5;
1275 const double x0p = (double)i + 0.5 * slitw - 0.5;
1276 const double x0n = (double)i - 0.5 * slitw - 0.5;
1277 const double val = 0.5 / slitw *
1278 (erf_antideriv(x1p, sigma) - erf_antideriv(x1n, sigma) -
1279 erf_antideriv(x0p, sigma) + erf_antideriv(x0n, sigma));
1280
1281 cpl_matrix_set(kernel, 0, size/2 + i, val);
1282 cpl_matrix_set(kernel, 0, size/2 - i, val);
1283 }
1284
1285 return kernel;
1286}
1287
1288/* The antiderivative of erx(x/sigma/sqrt(2)) with respect to x */
1289static inline double
1290erf_antideriv(const double x, const double sigma)
1291{
1292 return x * erf( x / (sigma * CPL_MATH_SQRT2))
1293 + 2.0 * sigma/CPL_MATH_SQRT2PI * exp(-0.5 * x * x / (sigma * sigma));
1294}
1295
1296/* Given an array of spectra the function takes care of freeing each spectra
1297 * and the buffer containing the pointers.*/
1298static inline void
1299free_spectrum_array(hdrl_spectrum1D ** s, const cpl_size sz){
1300 hdrl_spectrum1Dlist * l = hdrl_spectrum1Dlist_wrap(s, sz);
1302}
1303
1304/*Get the first element of the array that is not CPL_ERROR_NONE. If all the
1305 * elements are CPL_ERROR_NONE the function returns CPL_ERROR_NONE.*/
1306static inline cpl_error_code
1307get_first_error_code(const cpl_error_code * codes, const cpl_size sz){
1308 for(cpl_size i = 0; i < sz; ++i){
1309 if(codes[i]) return codes[i];
1310 }
1311 return CPL_ERROR_NONE;
1312}
1313
1314/*Selects all the wavelengths between wmin and wmax*/
1315static inline hdrl_spectrum1D *
1316select_win(const hdrl_spectrum1D * s, const hdrl_data_t wmin,
1317 const hdrl_data_t wmax){
1318
1319 cpl_bivector * bv = cpl_bivector_new(1);
1320
1321 cpl_vector_set(cpl_bivector_get_x(bv), 0, wmin);
1322 cpl_vector_set(cpl_bivector_get_y(bv), 0, wmax);
1323
1324 hdrl_spectrum1D * to_ret = hdrl_spectrum1D_select_wavelengths(s, bv, CPL_TRUE);
1325
1326 cpl_bivector_delete(bv);
1327
1328 return to_ret;
1329}
1330/*Corrects the spectrum s by the doppler offset offset.*/
1331static inline hdrl_spectrum1D *
1332correct_spectrum_for_doppler_shift(const hdrl_spectrum1D * s,
1333 const hdrl_data_t offset){
1334
1335 if(offset == 0.0)
1336 return hdrl_spectrum1D_duplicate(s);
1337
1338 const hdrl_image * flux = hdrl_spectrum1D_get_flux(s);
1339 cpl_array * wavs =
1340 cpl_array_duplicate(hdrl_spectrum1D_get_wavelength(s).wavelength);
1341
1342 for(cpl_size i = 0; i < cpl_array_get_size(wavs); ++i){
1343 const double d = cpl_array_get(wavs, i, NULL) * (1. + offset);
1344 cpl_array_set(wavs, i, d);
1345 }
1346
1347 hdrl_spectrum1D * to_ret = hdrl_spectrum1D_create(
1350 wavs,
1352 cpl_array_delete(wavs);
1353 return to_ret;
1354}
1355/*Median filters the flux, with error propagation*/
1356static inline hdrl_spectrum1D *
1357filter_spectrum_median(const hdrl_spectrum1D * resp, const cpl_size radius){
1358 const hdrl_image * flx_total = hdrl_spectrum1D_get_flux(resp);
1359 hdrl_image * flx_smoothed = compute_median_on_hdrl_image(flx_total, radius);
1360
1361 hdrl_spectrum1D * to_ret = hdrl_spectrum1D_create(
1362 hdrl_image_get_image(flx_smoothed),
1363 hdrl_image_get_error(flx_smoothed),
1364 hdrl_spectrum1D_get_wavelength(resp).wavelength,
1366
1367 hdrl_image_delete(flx_smoothed);
1368
1369 return to_ret;
1370}
1371
1372/*Median filters an HDRL image, with error propagation*/
1373static inline hdrl_image *
1374compute_median_on_hdrl_image(const hdrl_image * img, const cpl_size radius){
1375
1376 hdrl_image * to_ret = hdrl_image_duplicate(img);
1377 cpl_size sz = hdrl_image_get_size_x(img);
1378 for(cpl_size i = 1; i <= sz; ++i){
1379 cpl_size start = CPL_MAX(i - radius, 1);
1380 cpl_size stop = CPL_MIN(i + radius, sz);
1381 hdrl_image * ex_img = hdrl_image_extract(img, start, 1, stop, 1);
1382 hdrl_value m = hdrl_image_get_median(ex_img);
1383 hdrl_image_delete(ex_img);
1384 hdrl_image_set_pixel(to_ret, i, 1, m);
1385 }
1386 return to_ret;
1387}
1388
1389/*Remove rejected values or values being NAN or INF*/
1390static inline hdrl_spectrum1D *
1391remove_bad_data(const hdrl_spectrum1D * s){
1392
1393 const cpl_size sz = hdrl_spectrum1D_get_size(s);
1394 double * flx = cpl_calloc(sz, sizeof(double));
1395 double * flx_e = cpl_calloc(sz, sizeof(double));
1396 double * wlen = cpl_calloc(sz, sizeof(double));
1397
1398 cpl_size true_size = 0;
1399 for(cpl_size i = 0; i < sz; ++i){
1400 int rej = 0;
1401 hdrl_value v = hdrl_spectrum1D_get_flux_value(s, i, &rej);
1402 if(rej || isnan(v.data) || isinf(v.data)) continue;
1403
1404 flx[true_size] = v.data;
1405 flx_e[true_size] = v.error;
1406 wlen[true_size] = hdrl_spectrum1D_get_wavelength_value(s, i, &rej);
1407 true_size++;
1408 }
1409
1410 if(true_size == 0){
1411 cpl_free(flx);
1412 cpl_free(flx_e);
1413 cpl_free(wlen);
1414 return NULL;
1415 }
1416
1417 hdrl_spectrum1D_wave_scale scale = hdrl_spectrum1D_get_scale(s);
1418 cpl_image * img_flx = cpl_image_wrap_double(true_size, 1, flx);
1419 cpl_image * img_flx_e = cpl_image_wrap_double(true_size, 1, flx_e);
1420 cpl_array * arr_wlens= cpl_array_wrap_double(wlen, true_size);
1421 hdrl_spectrum1D * good_spectrum = hdrl_spectrum1D_create(img_flx, img_flx_e,
1422 arr_wlens, scale);
1423
1424 cpl_image_delete(img_flx);
1425 cpl_image_delete(img_flx_e);
1426 cpl_array_delete(arr_wlens);
1427 return good_spectrum;
1428}
1429
1430/* For each point p in fit_points generates a new spectrum whose wavelengths are
1431 * fit_points and whose flux are the medians taken in the range
1432 * [p - wrange, p + wrange]. */
1433static inline hdrl_spectrum1D *
1434get_median_on_fit_points(const hdrl_spectrum1D * s_input,
1435 const cpl_array * fit_points, const hdrl_data_t wrange){
1436
1437 cpl_size final_fit_points_size = cpl_array_get_size(fit_points);
1438
1439 cpl_array * wlens_fit = cpl_array_new(final_fit_points_size,
1440 HDRL_TYPE_DATA);
1441 hdrl_image * flux_fit = hdrl_image_new(final_fit_points_size, 1);
1442
1443 for(cpl_size i = 0; i < final_fit_points_size; ++i){
1444 const double w_fit = cpl_array_get(fit_points, i, NULL);
1445 cpl_array_set(wlens_fit, i, w_fit);
1446 hdrl_spectrum1D * f_s =
1447 select_win(s_input, w_fit - wrange, w_fit + wrange);
1448
1449 if(f_s == NULL){
1450 cpl_error_reset();
1451 hdrl_image_reject(flux_fit, i + 1, 1);
1452 continue;
1453 }
1454
1455 const hdrl_value v = hdrl_image_get_median(hdrl_spectrum1D_get_flux(f_s));
1456 hdrl_image_set_pixel(flux_fit, i + 1, 1, v);
1458 }
1459
1460 const hdrl_spectrum1D_wave_scale scale = hdrl_spectrum1D_get_scale(s_input);
1461
1462 hdrl_spectrum1D * to_ret = hdrl_spectrum1D_create(
1463 hdrl_image_get_image(flux_fit),
1464 hdrl_image_get_error(flux_fit),
1465 wlens_fit,
1466 scale
1467 );
1468 cpl_array_delete(wlens_fit);
1469 hdrl_image_delete(flux_fit);
1470 return to_ret;
1471}
1472/*removes high abs regions and values that are NAN or INF or rejected*/
1473static inline hdrl_spectrum1D *
1474select_regions_and_good_value(const hdrl_spectrum1D * s, const cpl_bivector * areas){
1475
1476 hdrl_spectrum1D * filted = NULL;
1477 if(areas != NULL)
1478 filted = hdrl_spectrum1D_select_wavelengths(s, areas, CPL_FALSE);
1479 else
1480 filted = hdrl_spectrum1D_duplicate(s);
1481
1482 hdrl_spectrum1D * to_ret = remove_bad_data(filted);
1483 hdrl_spectrum1D_delete(&filted);
1484 return to_ret;
1485}
1486
1487/*This function:
1488 * 1. Removes all the wavelengths contained inside high_abs_regions, from both s
1489 * and fit_points
1490 * 2. For each surviving point in fit_points take the median flux on the filtered s
1491*/
1492static inline hdrl_spectrum1D *
1493resample_on_medians_skip_abs_regions(const hdrl_spectrum1D * s,
1494 const cpl_array * fit_points, const cpl_bivector * high_abs_regions,
1495 const hdrl_data_t wrange){
1496
1497 cpl_ensure(s != NULL, CPL_ERROR_NULL_INPUT, NULL);
1498 cpl_ensure(fit_points != NULL, CPL_ERROR_NULL_INPUT, NULL);
1499
1500 hdrl_spectrum1D * filter_s =
1501 select_regions_and_good_value(s, high_abs_regions);
1502
1503 cpl_ensure(filter_s != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
1504
1505 const hdrl_data_t wmin=
1506 cpl_array_get_min(hdrl_spectrum1D_get_wavelength(filter_s).wavelength);
1507 const hdrl_data_t wmax=
1508 cpl_array_get_max(hdrl_spectrum1D_get_wavelength(filter_s).wavelength);
1509
1510 cpl_array * filter_fit_points =
1511 remove_regions_and_outliers_from_array(fit_points, high_abs_regions, wmin, wmax);
1512
1513 if(filter_fit_points == NULL || cpl_array_get_size(filter_fit_points) == 0){
1514 hdrl_spectrum1D_delete(&filter_s);
1515 cpl_array_delete(filter_fit_points);
1516 cpl_ensure(CPL_FALSE, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
1517 }
1518
1519 hdrl_spectrum1D * selected_s_median_points =
1520 get_median_on_fit_points(filter_s, filter_fit_points, wrange);
1521
1522 cpl_array_delete(filter_fit_points);
1523 hdrl_spectrum1D_delete(&filter_s);
1524
1525 return selected_s_median_points;
1526}
1527
1528/*Checks if w is contained in any of the windows in high_abs_regions.*/
1529static inline cpl_boolean
1530contained_in_any_region(const hdrl_data_t w, const cpl_bivector * high_abs_regions){
1531
1532 if(!high_abs_regions) return CPL_FALSE;
1533
1534 const cpl_size sz = cpl_bivector_get_size(high_abs_regions);
1535
1536 for(cpl_size i = 0; i < sz; ++i){
1537 const double wmin =
1538 cpl_vector_get(cpl_bivector_get_x_const(high_abs_regions), i);
1539 const double wmax =
1540 cpl_vector_get(cpl_bivector_get_y_const(high_abs_regions), i);
1541 if(w >= wmin && w <= wmax) return CPL_TRUE;
1542 }
1543 return CPL_FALSE;
1544}
1545
1546/*Removes each element in the array that is outside the range [wmin, wmax] or that
1547 * is contained inside the high_abs_regions*/
1548static inline cpl_array *
1549remove_regions_and_outliers_from_array(const cpl_array * fit_points,
1550 const cpl_bivector * high_abs_regions,
1551 const hdrl_data_t wmin, const hdrl_data_t wmax){
1552
1553 const cpl_size sz = cpl_array_get_size(fit_points);
1554 double * filter = cpl_calloc(sz, sizeof(*filter));
1555 cpl_size k = 0;
1556 for(cpl_size i = 0; i < sz; ++i){
1557 const double w = cpl_array_get(fit_points, i, NULL);
1558 if(w > wmax) continue;
1559 if(w < wmin) continue;
1560 if(contained_in_any_region(w, high_abs_regions)) continue;
1561
1562 filter[k] = w;
1563 k++;
1564 }
1565
1566 if(k == 0){
1567 cpl_free(filter);
1568 return NULL;
1569 }
1570
1571 return cpl_array_wrap_double(filter, k);
1572}
1573
1574static inline const hdrl_spectrum1Dlist *
1575hdrl_response_telluric_evaluation_parameter_get_telluric_models(
1576 const hdrl_parameter * par){
1577
1578 cpl_ensure(par != NULL, CPL_ERROR_NULL_INPUT, NULL);
1579 cpl_ensure(hdrl_parameter_get_parameter_enum(par)
1580 == HDRL_PARAMETER_RESPONSE_TELLURIC_EVALUATION,
1581 CPL_ERROR_ILLEGAL_INPUT, NULL);
1582
1583 const hdrl_response_telluric_evaluation_parameter * p =
1584 (const hdrl_response_telluric_evaluation_parameter *)par;
1585 return p->telluric_models;
1586}
1587
1588static inline hdrl_data_t
1589hdrl_response_telluric_evaluation_parameter_get_w_step(
1590 const hdrl_parameter * par){
1591
1592 cpl_ensure(par != NULL, CPL_ERROR_NULL_INPUT, 0.0);
1593 cpl_ensure(hdrl_parameter_get_parameter_enum(par)
1594 == HDRL_PARAMETER_RESPONSE_TELLURIC_EVALUATION,
1595 CPL_ERROR_ILLEGAL_INPUT, 0.0);
1596
1597 const hdrl_response_telluric_evaluation_parameter * p =
1598 (const hdrl_response_telluric_evaluation_parameter *)par;
1599 return p->w_step;
1600}
1601
1602static inline cpl_size
1603hdrl_response_telluric_evaluation_parameter_get_half_win(
1604 const hdrl_parameter * par){
1605
1606 cpl_ensure(par != NULL, CPL_ERROR_NULL_INPUT, 0);
1607 cpl_ensure(hdrl_parameter_get_parameter_enum(par)
1608 == HDRL_PARAMETER_RESPONSE_TELLURIC_EVALUATION,
1609 CPL_ERROR_ILLEGAL_INPUT, 0);
1610
1611 const hdrl_response_telluric_evaluation_parameter * p =
1612 (const hdrl_response_telluric_evaluation_parameter *)par;
1613 return p->half_win;
1614}
1615
1616static inline cpl_boolean
1617hdrl_response_telluric_evaluation_parameter_get_normalize(
1618 const hdrl_parameter * par){
1619
1620 cpl_ensure(par != NULL, CPL_ERROR_NULL_INPUT, CPL_FALSE);
1621 cpl_ensure(hdrl_parameter_get_parameter_enum(par)
1622 == HDRL_PARAMETER_RESPONSE_TELLURIC_EVALUATION,
1623 CPL_ERROR_ILLEGAL_INPUT, CPL_FALSE);
1624
1625 const hdrl_response_telluric_evaluation_parameter * p =
1626 (const hdrl_response_telluric_evaluation_parameter *)par;
1627 return p->normalize;
1628}
1629
1630static inline cpl_boolean
1631hdrl_response_telluric_evaluation_parameter_get_shift_in_log_scale(
1632 const hdrl_parameter * par){
1633
1634 cpl_ensure(par != NULL, CPL_ERROR_NULL_INPUT, CPL_FALSE);
1635 cpl_ensure(hdrl_parameter_get_parameter_enum(par)
1636 == HDRL_PARAMETER_RESPONSE_TELLURIC_EVALUATION,
1637 CPL_ERROR_ILLEGAL_INPUT, CPL_FALSE);
1638
1639 const hdrl_response_telluric_evaluation_parameter * p =
1640 (const hdrl_response_telluric_evaluation_parameter *)par;
1641 return p->shift_in_log_scale;
1642}
1643
1644static inline const cpl_bivector *
1645hdrl_response_telluric_evaluation_parameter_get_quality_areas(
1646 const hdrl_parameter * par){
1647
1648 cpl_ensure(par != NULL, CPL_ERROR_NULL_INPUT, NULL);
1649 cpl_ensure(hdrl_parameter_get_parameter_enum(par)
1650 == HDRL_PARAMETER_RESPONSE_TELLURIC_EVALUATION,
1651 CPL_ERROR_ILLEGAL_INPUT, NULL);
1652
1653 const hdrl_response_telluric_evaluation_parameter * p =
1654 (const hdrl_response_telluric_evaluation_parameter *)par;
1655 return p->quality_areas;
1656}
1657
1658static inline const cpl_bivector *
1659hdrl_response_telluric_evaluation_parameter_get_fit_areas(
1660 const hdrl_parameter * par){
1661
1662 cpl_ensure(par != NULL, CPL_ERROR_NULL_INPUT, NULL);
1663 cpl_ensure(hdrl_parameter_get_parameter_enum(par)
1664 == HDRL_PARAMETER_RESPONSE_TELLURIC_EVALUATION,
1665 CPL_ERROR_ILLEGAL_INPUT, NULL);
1666
1667 const hdrl_response_telluric_evaluation_parameter * p =
1668 (const hdrl_response_telluric_evaluation_parameter *)par;
1669 return p->fit_areas;
1670}
1671
1672static inline hdrl_data_t
1673hdrl_response_telluric_evaluation_parameter_get_lmin(
1674 const hdrl_parameter * par){
1675
1676 cpl_ensure(par != NULL, CPL_ERROR_NULL_INPUT, 0.0);
1677 cpl_ensure(hdrl_parameter_get_parameter_enum(par)
1678 == HDRL_PARAMETER_RESPONSE_TELLURIC_EVALUATION,
1679 CPL_ERROR_ILLEGAL_INPUT, 0.0);
1680
1681 const hdrl_response_telluric_evaluation_parameter * p =
1682 (const hdrl_response_telluric_evaluation_parameter *)par;
1683 return p->lmin;
1684}
1685
1686static inline hdrl_data_t
1687hdrl_response_telluric_evaluation_parameter_get_lmax(
1688 const hdrl_parameter * par){
1689
1690 cpl_ensure(par != NULL, CPL_ERROR_NULL_INPUT, 0.0);
1691 cpl_ensure(hdrl_parameter_get_parameter_enum(par)
1692 == HDRL_PARAMETER_RESPONSE_TELLURIC_EVALUATION,
1693 CPL_ERROR_ILLEGAL_INPUT, 0.0);
1694
1695 const hdrl_response_telluric_evaluation_parameter * p =
1696 (const hdrl_response_telluric_evaluation_parameter *)par;
1697 return p->lmax;
1698}
1699
1700static inline const cpl_array *
1701hdrl_response_parameter_get_fit_points(
1702 const hdrl_parameter * par){
1703
1704 cpl_ensure(par != NULL, CPL_ERROR_NULL_INPUT, NULL);
1705 cpl_ensure(hdrl_parameter_get_parameter_enum(par)
1706 == HDRL_PARAMETER_RESPONSE_FIT,
1707 CPL_ERROR_ILLEGAL_INPUT, NULL);
1708
1709 const response_fit_parameter * p =
1710 (const response_fit_parameter *)par;
1711 return p->fit_points;
1712}
1713
1714static inline const cpl_bivector *
1715hdrl_response_parameter_get_high_abs_regions(
1716 const hdrl_parameter * par){
1717
1718 cpl_ensure(par != NULL, CPL_ERROR_NULL_INPUT, NULL);
1719 cpl_ensure(hdrl_parameter_get_parameter_enum(par)
1720 == HDRL_PARAMETER_RESPONSE_FIT,
1721 CPL_ERROR_ILLEGAL_INPUT, NULL);
1722
1723 const response_fit_parameter * p =
1724 (const response_fit_parameter *)par;
1725 return p->high_abs_regions;
1726}
1727
1728static inline cpl_size
1729hdrl_response_parameter_get_radius(
1730 const hdrl_parameter * par){
1731
1732 cpl_ensure(par != NULL, CPL_ERROR_NULL_INPUT, 0);
1733 cpl_ensure(hdrl_parameter_get_parameter_enum(par)
1734 == HDRL_PARAMETER_RESPONSE_FIT,
1735 CPL_ERROR_ILLEGAL_INPUT, 0);
1736
1737 const response_fit_parameter * p =
1738 (const response_fit_parameter *)par;
1739 return p->radius;
1740}
1741
1742static inline hdrl_data_t
1743hdrl_response_parameter_get_wrange(
1744 const hdrl_parameter * par){
1745
1746 cpl_ensure(par != NULL, CPL_ERROR_NULL_INPUT, 0.0);
1747 cpl_ensure(hdrl_parameter_get_parameter_enum(par)
1748 == HDRL_PARAMETER_RESPONSE_FIT,
1749 CPL_ERROR_ILLEGAL_INPUT, 0.0);
1750
1751 const response_fit_parameter * p =
1752 (const response_fit_parameter *)par;
1753 return p->wrange;
1754}
1755
1756/*wrapper around the hdrl_spectrum1D constructor that accepts double arrays*/
1757static inline hdrl_spectrum1D *
1758hdrl_spectrum1D_create_from_buffers(double * flux, double * wlens, cpl_size sz,
1759 hdrl_spectrum1D_wave_scale scale){
1760
1761 cpl_array * w = cpl_array_wrap_double(wlens, sz);
1762 cpl_image * fl = cpl_image_wrap_double(sz, 1, flux);
1763
1764 hdrl_spectrum1D * to_ret = hdrl_spectrum1D_create_error_free(fl, w, scale);
1765
1766 cpl_array_unwrap(w);
1767 cpl_image_unwrap(fl);
1768 return to_ret;
1769}
1770/* For every window in "areas", extract a flux point having as wavelength the
1771 * middle point of the window and as flux the median of the flux value defined
1772 * on the window.*/
1773static inline hdrl_spectrum1D *
1774 hdrl_spectrum1D_extract_fit_regions(const hdrl_spectrum1D * s,
1775 const cpl_bivector * areas){
1776
1777 const double step = 1.0;
1778
1779 cpl_size sz = cpl_bivector_get_size(areas);
1780 const cpl_vector * l_min = cpl_bivector_get_x_const(areas);
1781 const cpl_vector * l_max = cpl_bivector_get_y_const(areas);
1782
1783 double * flux = cpl_calloc(sz + 2, sizeof(double));
1784 double * wlens = cpl_calloc(sz + 2, sizeof(double));
1785
1786 const hdrl_data_t wmin =
1787 cpl_array_get_min(hdrl_spectrum1D_get_wavelength(s).wavelength);
1788 const hdrl_data_t wmax =
1789 cpl_array_get_max(hdrl_spectrum1D_get_wavelength(s).wavelength);
1790 {
1791 hdrl_spectrum1D * s_sel =
1792 select_win(s, wmin - step, wmin + step);
1793
1794 const hdrl_image * sel_flux = hdrl_spectrum1D_get_flux(s_sel);
1795 flux[0] = hdrl_image_get_median(sel_flux).data;
1796 wlens[0] = wmin;
1797
1798 hdrl_spectrum1D_delete(&s_sel);
1799 }
1800
1801 cpl_size size_sel = 1;
1802 for(cpl_size i = 0; i < sz; ++i){
1803 const double lambda_min = cpl_vector_get(l_min, i);
1804 const double lambda_max = cpl_vector_get(l_max, i);
1805
1806 hdrl_spectrum1D * s_sel =
1807 select_win(s, lambda_min, lambda_max);
1808
1809 if(s_sel == NULL){
1810 cpl_error_reset();
1811 continue;
1812 }
1813 wlens[size_sel] = .5 * (lambda_max + lambda_min);
1814 const hdrl_image * sel_flux = hdrl_spectrum1D_get_flux(s_sel);
1815 flux[size_sel] = hdrl_image_get_median(sel_flux).data;
1816
1817 hdrl_spectrum1D_delete(&s_sel);
1818 size_sel++;
1819 }
1820
1821 {
1822 hdrl_spectrum1D * s_sel =
1823 select_win(s, wmax - step, wmax + step);
1824 const hdrl_image * sel_flux = hdrl_spectrum1D_get_flux(s_sel);
1825 flux[size_sel] = hdrl_image_get_median(sel_flux).data;
1826 wlens[size_sel] = wmax;
1827 hdrl_spectrum1D_delete(&s_sel);
1828 size_sel++;
1829 }
1830
1831 hdrl_spectrum1D * sel_s = NULL;
1832 if(size_sel > 0)
1833 {
1834 const hdrl_spectrum1D_wave_scale scale = hdrl_spectrum1D_get_scale(s);
1835 sel_s = hdrl_spectrum1D_create_from_buffers(flux, wlens, size_sel, scale);
1836 }
1837
1838 cpl_free(flux);
1839 cpl_free(wlens);
1840
1841 return sel_s;
1842}
1843/*ctor for hdrl_response_result.
1844 * NOTE: hdrl_response_result gets ownership of all the pointers provided.
1845 * DO NOT deallocate them, they will be de-allocated by hdrl_response_result dtor.
1846 * */
1847static inline hdrl_response_result *
1848hdrl_response_result_wrap(hdrl_spectrum1D * final_response,
1849 hdrl_spectrum1D * selected_response,
1850 hdrl_spectrum1D * raw_response,
1851
1852 hdrl_spectrum1D * corrected_observed_spectrum,
1853 cpl_size best_telluric_model_idx,
1854 hdrl_data_t telluric_shift,
1855 hdrl_data_t avg_diff_from_1,
1856 hdrl_data_t stddev,
1857
1858 hdrl_data_t doppler_shift){
1859
1860 hdrl_response_result * to_ret = cpl_calloc(1, sizeof(*to_ret));
1861
1862 to_ret->final_response = final_response;
1863 to_ret->raw_response = raw_response;
1864 to_ret->selected_response = selected_response;
1865
1866 to_ret->corrected_observed_spectrum = corrected_observed_spectrum;
1867 to_ret->best_telluric_model_idx = best_telluric_model_idx;
1868 to_ret->telluric_shift = telluric_shift;
1869 to_ret->avg_diff_from_1 = avg_diff_from_1;
1870 to_ret->stddev = stddev;
1871
1872 to_ret->doppler_shift = doppler_shift;
1873
1874 return to_ret;
1875}
1876
1877
void hdrl_xcorrelation_result_delete(hdrl_xcorrelation_result *self)
Destructor for hdrl_xcorrelation_result.
cpl_size hdrl_xcorrelation_result_get_half_window(const hdrl_xcorrelation_result *self)
Get the half_window used to calculate the cross-correlation.
double hdrl_xcorrelation_result_get_peak_subpixel(const hdrl_xcorrelation_result *self)
Get the index where the cross correlation reaches its maximum, with sub-pixel precision.
double hdrl_xcorrelation_result_get_sigma(const hdrl_xcorrelation_result *self)
Get the estimated standard deviation of the correlation.
hdrl_spectrum1D * hdrl_response_core_compute(const hdrl_spectrum1D *I_std_arg, const hdrl_spectrum1D *I_std_ref, const hdrl_spectrum1D *E_x, const hdrl_parameter *pars)
core response calculation
cpl_error_code hdrl_image_set_pixel(hdrl_image *self, cpl_size xpos, cpl_size ypos, hdrl_value value)
set pixel values of hdrl_image
Definition: hdrl_image.c:594
hdrl_value hdrl_image_get_median(const hdrl_image *self)
computes the median and associated error of an image.
hdrl_image * hdrl_image_duplicate(const hdrl_image *himg)
copy hdrl_image
Definition: hdrl_image.c:391
double hdrl_image_get_stdev(const hdrl_image *self)
computes the standard deviation of the data of an image
hdrl_image * hdrl_image_extract(const hdrl_image *self, cpl_size llx, cpl_size lly, cpl_size urx, cpl_size ury)
extract copy of window from image
Definition: hdrl_image.c:625
cpl_image * hdrl_image_get_error(hdrl_image *himg)
get error as cpl image
Definition: hdrl_image.c:131
hdrl_value hdrl_image_get_mean(const hdrl_image *self)
computes mean pixel value and associated error of an image.
cpl_size hdrl_image_get_size_x(const hdrl_image *self)
return size of X dimension of image
Definition: hdrl_image.c:525
const cpl_image * hdrl_image_get_error_const(const hdrl_image *himg)
get error as cpl image
Definition: hdrl_image.c:144
cpl_image * hdrl_image_get_image(hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:105
cpl_error_code hdrl_image_reject(hdrl_image *self, cpl_size xpos, cpl_size ypos)
mark pixel as bad
Definition: hdrl_image.c:427
const cpl_image * hdrl_image_get_image_const(const hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:118
hdrl_image * hdrl_image_new(cpl_size nx, cpl_size ny)
create new zero filled hdrl image
Definition: hdrl_image.c:311
void hdrl_image_delete(hdrl_image *himg)
delete hdrl_image
Definition: hdrl_image.c:379
void hdrl_parameter_delete(hdrl_parameter *obj)
shallow delete of a parameter
hdrl_data_t hdrl_response_result_get_stddev(const hdrl_response_result *res)
Getter of the standard deviation of the ratio between the corrected observed spectrum and its smoothe...
const hdrl_spectrum1D * hdrl_response_result_get_final_response(const hdrl_response_result *res)
Getter for the final response contained inside the hdrl_response_result.
const hdrl_spectrum1D * hdrl_response_result_get_selected_response(const hdrl_response_result *res)
Getter for the selected response contained inside the hdrl_response_result.
hdrl_parameter * hdrl_response_fit_parameter_create(const cpl_size radius, const cpl_array *fit_points, const hdrl_data_t wrange, const cpl_bivector *high_abs_regions)
ctor for the hdrl_parameter for the final interpolation of the response
cpl_size hdrl_response_result_get_best_telluric_model_idx(const hdrl_response_result *res)
Getter of the index of the telluric model used for telluric correction contained in hdrl_response_res...
hdrl_data_t hdrl_response_result_get_doppler_shift(const hdrl_response_result *res)
Getter of the doppler shift used to correct the model.
void hdrl_response_result_delete(hdrl_response_result *res)
Destructor for hdrl_response_result.
hdrl_response_result * hdrl_response_compute(const hdrl_spectrum1D *obs_s, const hdrl_spectrum1D *ref_s, const hdrl_spectrum1D *E_x, const hdrl_parameter *telluric_par, const hdrl_parameter *velocity_par, const hdrl_parameter *calc_par, const hdrl_parameter *fit_par)
Computation of the response.
hdrl_parameter * hdrl_response_telluric_evaluation_parameter_create(const hdrl_spectrum1Dlist *telluric_models, hdrl_data_t w_step, cpl_size half_win, cpl_boolean normalize, cpl_boolean shift_in_log_scale, const cpl_bivector *quality_areas, const cpl_bivector *fit_areas, hdrl_data_t lmin, hdrl_data_t lmax)
ctor for the hdrl_parameter for the telluric evaluation
const hdrl_spectrum1D * hdrl_response_result_get_raw_response(const hdrl_response_result *res)
Getter for the raw response contained inside the hdrl_response_result.
hdrl_data_t hdrl_response_result_get_avg_diff_from_1(const hdrl_response_result *res)
Getter of the value |mean - 1|, where mean is the average of the ratio between the corrected observed...
hdrl_data_t hdrl_response_result_get_telluric_shift(const hdrl_response_result *res)
Getter of the shift applied to the telluric model.
const hdrl_spectrum1D * hdrl_response_result_get_corrected_obs_spectrum(const hdrl_response_result *res)
Getter for the corrected observed spectrum contained in hdrl_response_result.
const hdrl_image * hdrl_spectrum1D_get_flux(const hdrl_spectrum1D *self)
hdrl_spectrum1D getter flux
cpl_error_code hdrl_spectrum1D_wavelength_convert_to_linear(hdrl_spectrum1D *self)
converts the wavelength scale to linear.
hdrl_data_t hdrl_spectrum1D_compute_shift_fit(const hdrl_spectrum1D *obs, const hdrl_parameter *par)
The function compute the shift due to radial velocity. If wguess is the reference line and wfound is ...
cpl_size hdrl_spectrum1Dlist_get_size(const hdrl_spectrum1Dlist *l)
hdrl_spectrum1Dlist getter for size
hdrl_spectrum1D * hdrl_spectrum1D_resample(const hdrl_spectrum1D *self, const hdrl_spectrum1D_wavelength *waves, const hdrl_parameter *par)
resample a hdrl_spectrum1D on the wavelengths contained in waves
hdrl_parameter * hdrl_spectrum1D_resample_interpolate_parameter_create(const hdrl_spectrum1D_interpolation_method method)
constructor for the hdrl_parameter in the case of interpolation
hdrl_spectrum1D * hdrl_spectrum1D_duplicate(const hdrl_spectrum1D *self)
hdrl_spectrum1D copy constructor
cpl_size hdrl_spectrum1D_get_size(const hdrl_spectrum1D *self)
hdrl_spectrum1D getter for size
void hdrl_spectrum1D_delete(hdrl_spectrum1D **p_self)
hdrl_spectrum1D destructor
cpl_error_code hdrl_spectrum1D_wavelength_convert_to_log(hdrl_spectrum1D *self)
converts the wavelength scale to log. If the spectrum is already in log scale nothing is done.
hdrl_spectrum1D * hdrl_spectrum1D_div_spectrum_create(const hdrl_spectrum1D *num, const hdrl_spectrum1D *den)
divide one spectrum by another spectrum
hdrl_xcorrelation_result * hdrl_spectrum1D_compute_shift_xcorrelation(const hdrl_spectrum1D *s1, const hdrl_spectrum1D *s2, cpl_size half_win, const cpl_boolean normalize)
The function computes the shift between the two spectra.
void hdrl_spectrum1Dlist_delete(hdrl_spectrum1Dlist *l)
hdrl_spectrum1Dlist destructor
hdrl_spectrum1D * hdrl_spectrum1D_wavelength_shift_create(const hdrl_spectrum1D *self, hdrl_data_t shift)
computes the elementwise shift of the wavelength by the shift parameter.
const hdrl_spectrum1D * hdrl_spectrum1Dlist_get_const(const hdrl_spectrum1Dlist *self, const cpl_size idx)
hdrl_spectrum1Dlist getter of the i-th element
hdrl_spectrum1D * hdrl_spectrum1D_create(const cpl_image *arg_flux, const cpl_image *arg_flux_e, const cpl_array *wavelength, hdrl_spectrum1D_wave_scale wave_scale)
hdrl_spectrum1D default constructor
hdrl_spectrum1D * hdrl_spectrum1D_resample_on_array(const hdrl_spectrum1D *self, const cpl_array *waves, const hdrl_parameter *par)
resample a hdrl_spectrum1D on the wavelengths contained in waves
hdrl_spectrum1D_wave_scale hdrl_spectrum1D_get_scale(const hdrl_spectrum1D *self)
hdrl_spectrum1D getter for scale
hdrl_spectrum1D_wavelength hdrl_spectrum1D_get_wavelength(const hdrl_spectrum1D *self)
hdrl_spectrum1D getter for wavelengths
hdrl_spectrum1D * hdrl_spectrum1D_create_error_free(const cpl_image *arg_flux, const cpl_array *wavelength, hdrl_spectrum1D_wave_scale scale)
hdrl_spectrum1D constructor in the case of error-free spectrum (i.e. the error on the flux is zero fo...
hdrl_data_t hdrl_spectrum1D_get_wavelength_value(const hdrl_spectrum1D *self, int idx, int *rej)
hdrl_spectrum1D getter for a wavelength value
hdrl_spectrum1Dlist * hdrl_spectrum1Dlist_duplicate(const hdrl_spectrum1Dlist *l)
hdrl_spectrum1Dlist copy-constructor
hdrl_spectrum1Dlist * hdrl_spectrum1Dlist_wrap(hdrl_spectrum1D **self, const cpl_size sz)
hdrl_spectrum1Dlist wrapper
hdrl_spectrum1D * hdrl_spectrum1D_select_wavelengths(const hdrl_spectrum1D *self, const cpl_bivector *windows, const cpl_boolean is_internal)
the function selects or discards flux values according to whether the value of the corresponding wave...
hdrl_parameter * hdrl_spectrum1D_resample_integrate_parameter_create(void)
constructor for the hdrl_parameter in the case of integration
hdrl_value hdrl_spectrum1D_get_flux_value(const hdrl_spectrum1D *self, int idx, int *rej)
hdrl_spectrum1D getter for a flux value