36#include "hdrl_spectrum_resample.h"
37#include "irplib_wavecal.h"
38#include "irplib_framelist.h"
40#include "visir_spectro.h"
41#include "visir_utils.h"
42#include "visir_pfits.h"
43#include "visir_inputs.h"
44#include "visir_parameter.h"
45#include "visir_spc_distortion.h"
55#include <gsl/gsl_fit.h>
61#define skip_if_error_present() skip_if(0)
63#define MSG_WARN(...) cpl_msg_warning(cpl_func, __VA_ARGS__)
64#define MSG_INFO(...) cpl_msg_info(cpl_func, __VA_ARGS__)
65#define MSG_ERR(...) cpl_msg_error(cpl_func, __VA_ARGS__)
66#define MSG_DBG(...) cpl_msg_debug(cpl_func, __VA_ARGS__)
86 const cpl_vector * vsymm;
90 const cpl_bivector * lines;
92 const cpl_bivector * tqeff;
94} visir_spectrum_model;
96typedef cpl_bivector * (extract_func)(cpl_image *,
int,
int, cpl_propertylist *,
97 cpl_image **,
const visir_spc_config *,
98 const visir_apdefs *,
const bool,
106visir_polynomial_shift_1d_from_correlation(cpl_polynomial *,
108 irplib_base_spectrum_model *,
111 const cpl_polynomial *,
112 irplib_base_spectrum_model *),
113 int,
int, cpl_boolean,
116static cpl_error_code visir_spectro_refine(cpl_polynomial *,
118 visir_spectrum_model *,
119 const cpl_polynomial *,
120 int, cpl_boolean, visir_spc_resol,
121 double *, cpl_boolean *,
double *);
123static cpl_error_code visir_spectro_fill(cpl_vector *,
const cpl_polynomial *,
124 irplib_base_spectrum_model *);
126static extract_func visir_spc_oldex;
127static extract_func visir_spc_newex;
128static extract_func visir_spc_extract;
130static cpl_error_code visir_spc_emission(cpl_bivector *,
const cpl_vector *,
131 const cpl_bivector *,
132 const cpl_bivector *,
133 const cpl_vector *,
double);
135static cpl_polynomial * visir_spc_phys_disp(
int,
double, visir_spc_resol,
int,
137static cpl_polynomial * visir_spc_phys_lrp(
void);
138static double visir_spc_get_dispersion(
const cpl_polynomial *,
double);
139static cpl_error_code visir_vector_convolve_symm(cpl_vector *,
141static cpl_vector * cpl_spc_convolve_init(
int,
double,
double,
int);
143static cpl_error_code visir_spectro_qclist_wcal(cpl_propertylist *,
146 const cpl_polynomial *,
147 const cpl_polynomial *);
149static void * visir_spectro_qclist_obs(cpl_propertylist *,
double,
double);
151static const double N_upper = 13.4e-6;
152static const double whechelle = 35.8/2;
155#define VISIR_XC_LEN 50
157#ifndef VISIR_XC_SUBSEARCH
158#define VISIR_XC_SUBSEARCH 100
161#ifndef VISIR_SPECTRO_SIGMA
162#define VISIR_SPECTRO_SIGMA 3.0
179static const char * pn(
const int oo)
182 const char * sign = oo ? (oo > 0 ?
"+" :
"-") :
"";
183 snprintf(buf,
sizeof(buf),
"%s%d", sign, abs(oo));
187cpl_error_code visir_spc_extract_order(cpl_image ** order,
188 cpl_image ** comorder,
189 int * lcol,
int * rcol,
190 const cpl_image * combined,
191 const cpl_image * imhcycle,
193 const visir_spc_config * cfg,
194 const cpl_boolean do_ech,
201 VISIR_PARAM_REJLEFT);
203 VISIR_PARAM_REJRIGHT);
206 cpl_msg_debug(cpl_func,
"extracting order, wlen=%f, do_ech=%d, jcol1=%d, "
207 "jcol2=%d", wlen, do_ech, jcol1, jcol2);
210 skip_if (visir_spc_echelle_limit(&icol1, &icol2, wlen, cfg, 1,
211 cpl_image_get_size_y(combined),
215 icol2 = cpl_image_get_size_x(imhcycle);
220 cpl_msg_info(cpl_func,
"Ignoring %d leftmost columns from %d to %d",
221 jcol1, icol1, icol1 + jcol1);
225 cpl_msg_info(cpl_func,
"Ignoring %d rightmost columns from %d to %d",
226 jcol2, icol2 - jcol2, icol2);
231 cpl_msg_info(cpl_func,
"Ignoring %d leftmost columns", jcol1);
235 cpl_msg_info(cpl_func,
"Ignoring %d rightmost columns", jcol2);
240 if (icol1 != 1 || icol2 != cpl_image_get_size_x(imhcycle)) {
241 *order = visir_spc_column_extract(imhcycle, icol1, icol2, cfg->plot);
242 skip_if_error_present();
244 *comorder = visir_spc_column_extract(combined, icol1, icol2, cfg->plot);
245 skip_if_error_present();
248 *order = cpl_image_duplicate(imhcycle);
249 *comorder = cpl_image_duplicate(combined);
257 return cpl_error_get_code();
277visir_spc_resol visir_spc_get_res_wl(
const irplib_framelist * rawframes,
278 double * pwlen,
double * pslitw,
279 double * ptemp,
double * pfwhm,
282 cpl_errorstate cleanstate = cpl_errorstate_get();
284 visir_spc_resol resol = VISIR_SPC_R_ERR;
285 char ptmp[IRPLIB_FITS_STRLEN+1];
286 double wl, spx, pfov = 0.127;
288 cpl_boolean need_temp = ptemp != NULL;
292 cpl_ensure(rawframes != NULL, CPL_ERROR_NULL_INPUT, VISIR_SPC_R_ERR);
293 cpl_ensure(pwlen != NULL, CPL_ERROR_NULL_INPUT, VISIR_SPC_R_ERR);
294 cpl_ensure(pslitw != NULL, CPL_ERROR_NULL_INPUT, VISIR_SPC_R_ERR);
295 cpl_ensure(pfwhm != NULL, CPL_ERROR_NULL_INPUT, VISIR_SPC_R_ERR);
297 n = irplib_framelist_get_size(rawframes);
299 cpl_ensure(n > 0, CPL_ERROR_DATA_NOT_FOUND, VISIR_SPC_R_ERR);
302 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_DOUBLE_PIXSPACE,
303 CPL_TYPE_DOUBLE, CPL_TRUE, 1e-6));
306 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_DOUBLE_SLITWIDTH,
307 CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
309 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_RESOL,
310 CPL_TYPE_STRING, CPL_TRUE, 0.0));
312 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_SLITNAME,
313 CPL_TYPE_STRING, CPL_TRUE, 0.0));
315 for (
int i = 0; i < n; i++) {
316 const cpl_propertylist * plist;
317 const char * filename =
318 cpl_frame_get_filename(irplib_framelist_get_const(rawframes, i));
320 double wl_tmp, sl_tmp, spx_tmp, pfov_tmp;
323 cpl_ensure(!cpl_error_get_code(), CPL_ERROR_DATA_NOT_FOUND,
326 cpl_ensure(filename != NULL, CPL_ERROR_DATA_NOT_FOUND,
329 plist = irplib_framelist_get_propertylist_const(rawframes, i);
331 cpl_ensure(plist != NULL, CPL_ERROR_DATA_NOT_FOUND, VISIR_SPC_R_ERR);
334 if (wl_tmp <= 0.0 || !cpl_errorstate_is_equal(cleanstate)) {
335 irplib_error_recover(cleanstate,
"Missing or invalid FITS card");
336 wl_tmp = VISIR_SPC_LRP_CWLEN;
339 if (pfits == NULL || !cpl_errorstate_is_equal(cleanstate)) {
340 irplib_error_recover(cleanstate,
"Missing or invalid FITS card");
341 pfits = VISIR_SPC_LRP_NAME;
349 if (pfov_tmp <= 0.) {
350 cpl_errorstate_set(cleanstate);
351 cpl_msg_warning(cpl_func, VISIR_PFITS_STRING_PIXSCALE
352 " not set, falling back to 0.127");
357 cpl_ensure(!cpl_error_get_code(), CPL_ERROR_DATA_NOT_FOUND,
362 visir_optmod ins_settings;
375 strncpy(ptmp, pfits, IRPLIB_FITS_STRLEN);
376 ptmp[IRPLIB_FITS_STRLEN] =
'\0';
378 cpl_msg_info(cpl_func,
"RESOL [" VISIR_SPC_LRP_NAME
"|LR|MR|HRS|HRG]"
379 " and WLEN [m] (%d frames): %s %g", n, ptmp, *pwlen);
382 cpl_msg_error(cpl_func,
"Pixel Spacing (%g) in %s is non-"
383 "positive", spx, filename);
384 cpl_ensure(0, CPL_ERROR_ILLEGAL_INPUT, VISIR_SPC_R_ERR);
388 cpl_msg_error(cpl_func,
"Slit Width (%g) in %s is non-positive",
390 cpl_ensure(0, CPL_ERROR_ILLEGAL_INPUT, VISIR_SPC_R_ERR);
393 cpl_msg_info(cpl_func,
"Slit Width [pixel] and Pixel Spacing [m]: "
394 "%g %g", *pslitw, spx);
396 if (!strcmp(VISIR_SPC_LRP_NAME, ptmp)) {
397 resol = VISIR_SPC_R_LRP;
398 }
else if (!strcmp(
"LR", ptmp)) {
399 resol = VISIR_SPC_R_LR;
400 }
else if (!strcmp(
"MR", ptmp)) {
401 resol = VISIR_SPC_R_MR;
402 }
else if (!strcmp(
"HRS", ptmp)) {
403 resol = VISIR_SPC_R_HR;
404 }
else if (!strcmp(
"HRG", ptmp)) {
405 resol = VISIR_SPC_R_GHR;
407 cpl_msg_error(cpl_func,
"Unsupported resolution (%s) in %s",
409 cpl_ensure(0, CPL_ERROR_UNSUPPORTED_MODE, VISIR_SPC_R_ERR);
412 if (resol != VISIR_SPC_R_LRP) {
414 skip_if(irplib_framelist_contains(rawframes,
415 VISIR_PFITS_DOUBLE_WLEN,
416 CPL_TYPE_DOUBLE, CPL_TRUE,
420 if (visir_spc_optmod_init(resol, *pwlen, &ins_settings, is_aqu)) {
421 cpl_msg_error(cpl_func,
"Resolution %s does not support "
422 "Central Wavelength [m]: %g", ptmp, *pwlen);
423 cpl_ensure(0, CPL_ERROR_INCOMPATIBLE_INPUT, VISIR_SPC_R_ERR);
426 cpl_msg_info(cpl_func,
"The %s-Spectral Resolution at %gm: %g",
428 visir_spc_optmod_resolution(&ins_settings));
429 cpl_msg_info(cpl_func,
"The %s-Linear Dispersion at %gm [pixel/m]: "
431 visir_spc_optmod_dispersion(&ins_settings));
433 *pfwhm = *pwlen * visir_spc_optmod_dispersion(&ins_settings)
434 / visir_spc_optmod_resolution(&ins_settings);
436 cpl_msg_info(cpl_func,
"The %s-FWHM at %gm [pixel]: %g",
437 ptmp, *pwlen, *pfwhm);
439 if (fabs(sl-sl_tmp) > 1e-3) {
440 cpl_msg_error(cpl_func,
"Inconsistent slit width (%g <=>"
441 " %g) in %s (%d of %d)",
442 sl, sl_tmp, filename, i+1, n);
443 cpl_ensure(0, CPL_ERROR_INCOMPATIBLE_INPUT, VISIR_SPC_R_ERR);
445 if (fabs(pfov-pfov_tmp) > 1e-4) {
446 cpl_msg_error(cpl_func,
"Inconsistent pfov (%g <=>"
447 " %g) in %s (%d of %d)",
448 pfov, pfov_tmp, filename, i+1, n);
449 cpl_ensure(0, CPL_ERROR_INCOMPATIBLE_INPUT, VISIR_SPC_R_ERR);
455 if (cpl_error_get_code()) {
456 visir_error_reset(
"Could not get FITS key");
457 }
else if ((-20 < temp) && (temp < 60)) {
459 need_temp = CPL_FALSE;
467 cpl_msg_warning(cpl_func,
"No FITS-files specify the M1 temperature, "
475 cpl_msg_info(cpl_func,
"The M1 temperature [Kelvin]: %g", *ptemp);
506cpl_error_code visir_vector_resample(cpl_vector * self,
507 const cpl_vector * xbounds,
508 const cpl_bivector * source)
511 const cpl_vector * xsource = cpl_bivector_get_x_const(source);
512 const cpl_vector * ysource = cpl_bivector_get_y_const(source);
514 const double * pxsource = cpl_vector_get_data_const(xsource);
515 const double * pysource = cpl_vector_get_data_const(ysource);
516 const double * pxbounds = cpl_vector_get_data_const(xbounds);
519 cpl_vector * ybounds = cpl_vector_new(cpl_vector_get_size(xbounds));
520 IRPLIB_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual)
521 cpl_bivector * boundary = cpl_bivector_wrap_vectors((cpl_vector*)xbounds,
523 IRPLIB_DIAG_PRAGMA_POP
524 double * pybounds = cpl_vector_get_data(ybounds);
526 double * pself = cpl_vector_get_data(self);
527 const int npix = cpl_vector_get_size(self);
532 cpl_ensure_code(cpl_bivector_get_size(boundary) == npix + 1,
533 CPL_ERROR_ILLEGAL_INPUT);
535 skip_if_error_present();
537 itt = cpl_vector_find(xsource, pxbounds[0]);
539 skip_if_error_present();
541 skip_if (cpl_bivector_interpolate_linear(boundary, source));
545 while (pxsource[itt] < pxbounds[0]) itt++;
547 for (i=0; i < npix; i++) {
552 double xlow = pxbounds[i];
553 double x = pxsource[itt];
555 if (x > pxbounds[i+1]) x = pxbounds[i+1];
557 pself[i] = pybounds[i] * (x - xlow);
560 while (pxsource[itt] < pxbounds[i+1]) {
561 const double xprev = x;
563 if (x > pxbounds[i+1]) x = pxbounds[i+1];
564 pself[i] += pysource[itt] * (x - xlow);
570 pself[i] += pybounds[i+1] * (pxbounds[i+1] - xlow);
574 pself[i] /= 2 * (pxbounds[i+1] - pxbounds[i]);
581 cpl_vector_delete(ybounds);
582 cpl_bivector_unwrap_vectors(boundary);
584 return cpl_error_get_code();
616void * visir_spc_extract_wcal(
const cpl_image * combined,
617 const cpl_image * hcycle,
618 const int lcol,
const int rcol,
619 const double wlen,
const double slitw,
620 const double temp,
const double fwhm,
621 const visir_spc_resol resol,
622 const visir_spc_config * cfg,
623 const char * spc_cal_lines,
624 const char * spc_cal_qeff,
626 const visir_apdefs * aps,
627 const cpl_size ncomb,
const bool rev,
628 cpl_table ** pspc_table,
629 cpl_image ** pweight2d,
630 cpl_propertylist * qclist)
632 cpl_image* flipped = NULL;
633 cpl_bivector* spc_n_err = NULL;
634 cpl_table* calib = NULL;
635 double * pwlen = NULL;
636 double * pflux = NULL;
637 double * perr = NULL;
638 cpl_array* warr = NULL;
639 cpl_image* flux = NULL;
640 cpl_image* err = NULL;
641 hdrl_spectrum1D* response = NULL;
642 hdrl_spectrum1D* spectrum = NULL;
644 const int npix = cpl_image_get_size_y(combined);
647 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
650 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
658 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
659 }
else if (npix != cpl_image_get_size_y(hcycle)) {
660 cpl_msg_error(cpl_func,
661 "Sky frame does not have same size as the "
662 "object frame. %d vs %d pixels",
663 (
int)cpl_image_get_size_y(hcycle), npix);
664 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
670 visir_spc_wavecal(hcycle, qclist, wlen, slitw, temp, fwhm, resol,
671 cfg, spc_cal_lines, spc_cal_qeff, pspc_table,
677 flipped = cpl_image_cast(combined, CPL_TYPE_DOUBLE);
683 spc_n_err = visir_spc_extract(
684 flipped, lcol, rcol, qclist, pweight2d, cfg, aps, rev, ncomb);
685 cpl_image_delete(flipped); flipped = NULL;
690 if (visir_str_par_is_empty(cfg->respcal)) {
691 cpl_table_new_column(*pspc_table,
"SPC_EXTRACTED", CPL_TYPE_DOUBLE);
692 cpl_table_new_column(*pspc_table,
"SPC_ERROR", CPL_TYPE_DOUBLE);
694 cpl_table_copy_data_double(*pspc_table,
"SPC_EXTRACTED",
695 cpl_bivector_get_x_data(spc_n_err));
696 cpl_table_copy_data_double(*pspc_table,
"SPC_ERROR",
697 cpl_bivector_get_y_data(spc_n_err));
699 MSG_INFO(
"Applying response calibration...");
702 calib = cpl_table_load(cfg->respcal, 1, 0);
703 cpl_size nrows = cpl_table_get_nrow(calib);
704 pwlen = cpl_table_get_data_double(calib,
"WLEN");
705 pflux = cpl_table_get_data_double(calib,
"FLUX");
709 perr = cpl_table_get_data_double(calib,
"ERR");
710 if (cpl_error_get_code()) {
711 cpl_msg_warning(cpl_func,
"ERR column missing from %s, "
712 "continuing with zero error", cfg->respcal);
717 warr = cpl_array_wrap_double(pwlen, nrows);
718 cpl_array_multiply_scalar(warr, 1e-6);
719 cpl_image* flux = cpl_image_wrap_double(nrows, 1, pflux);
720 cpl_image* err = (!perr ? NULL : cpl_image_wrap_double(
725 hdrl_spectrum1D* response = hdrl_spectrum1D_create(
726 flux, err, warr, hdrl_spectrum1D_wave_scale_linear);
728 cpl_array_unwrap(warr); warr = NULL;
733 nrows = cpl_table_get_nrow(*pspc_table);
734 pwlen = cpl_table_get_data_double(*pspc_table,
"WLEN");
735 pflux = cpl_bivector_get_x_data(spc_n_err);
736 perr = cpl_bivector_get_y_data(spc_n_err);
737 warr = cpl_array_wrap_double(pwlen, nrows);
738 flux = cpl_image_wrap_double(nrows, 1, pflux);
739 err = cpl_image_wrap_double(nrows, 1, perr);
743 hdrl_spectrum1D* spectrum = hdrl_spectrum1D_create(
744 flux, err, warr, hdrl_spectrum1D_wave_scale_linear);
749 const hdrl_spectrum1D_wavelength spec_wav =
750 hdrl_spectrum1D_get_wavelength(spectrum);
751 hdrl_parameter* params =
752 hdrl_spectrum1D_resample_interpolate_parameter_create(
753 hdrl_spectrum1D_interp_linear);
754 hdrl_spectrum1D* result = hdrl_spectrum1D_resample(
755 response, &spec_wav, params);
760 hdrl_spectrum1D_div_spectrum(spectrum, result);
761 hdrl_spectrum1D_append_to_table(
762 spectrum, *pspc_table,
"SPC_EXTRACTED", NULL,
"SPC_ERROR", NULL);
767 cpl_table_set_column_unit(*pspc_table,
"SPC_EXTRACTED",
"ADU/s");
768 cpl_table_set_column_unit(*pspc_table,
"SPC_ERROR",
"ADU/s");
773 visir_table_plot(
"set grid;set xlabel 'Wavelength [m]';",
774 "t 'Extracted Spectrum' w linespoints",
775 "", *pspc_table,
"WLEN",
"SPC_EXTRACTED");
776 visir_table_plot(
"set grid;set xlabel 'Wavelength [m]';",
777 "t 'Error on Extracted Spectrum' w linespoints",
778 "", *pspc_table,
"WLEN",
"SPC_ERROR");
783 if (cpl_error_get_code()) {
784 cpl_msg_error(cpl_error_get_where(),
"%s", cpl_error_get_message());
787 cpl_image_delete(flipped);
788 cpl_bivector_delete(spc_n_err);
789 cpl_table_delete(calib);
790 cpl_array_unwrap(warr);
791 cpl_image_unwrap(flux);
792 cpl_image_unwrap(err);
793 hdrl_spectrum1D_delete(&response);
794 hdrl_spectrum1D_delete(&spectrum);
826cpl_error_code visir_spc_wavecal(
const cpl_image * hcycle,
827 cpl_propertylist * qclist,
828 double wlen,
double slitw,
829 double temp,
double fwhm,
830 visir_spc_resol resol,
831 const visir_spc_config * cfg,
832 const char * linefile,
833 const char * qefffile,
834 cpl_table ** pspc_table,
839 cpl_polynomial * phdisp = NULL;
841 cpl_polynomial * xcdisp = NULL;
843 visir_spectrum_model mymodel;
844 cpl_vector * wlvals = NULL;
845 cpl_vector * spmodel = NULL;
847 cpl_bivector * emission = NULL;
848 cpl_vector * boundary = NULL;
850 cpl_bivector * temiss = NULL;
851 cpl_bivector * tqeff = NULL;
853 cpl_image * corrected = NULL;
855 cpl_image * xc_image = NULL;
856 cpl_vector * xc_vector = NULL;
858 cpl_vector * vsymm = NULL;
859 cpl_vector * vxc = NULL;
861 const int npix = cpl_image_get_size_y(hcycle);
865 double qcxc = -1.0, qcsubdelta = 0.;
867 const cpl_size i0 = 0;
868 const cpl_size i1 = 1;
869 cpl_boolean didshift = CPL_FALSE;
872 cpl_ensure_code(!cpl_error_get_code(), cpl_error_get_code());
873 cpl_ensure_code(pspc_table, CPL_ERROR_NULL_INPUT);
874 cpl_ensure_code(npix > 0, CPL_ERROR_ILLEGAL_INPUT);
878 corrected = cpl_image_cast(hcycle, CPL_TYPE_DOUBLE);
879 skip_if_error_present();
881 hc_min = cpl_image_get_min(corrected);
882 skip_if_error_present();
883 cpl_msg_info(cpl_func,
"Half-cycle image [%d X %d] has minimum intensity: %g",
884 (
int)cpl_image_get_size_x(hcycle), npix, hc_min);
886 cpl_msg_warning(cpl_func,
"Thresholding negative intensities in half-"
887 "cycle image: %g", hc_min);
888 skip_if (cpl_image_threshold(corrected, 0.0, DBL_MAX, 0.0, DBL_MAX));
889 }
else if (hc_min > 0) {
890 skip_if (cpl_image_subtract_scalar(corrected, hc_min));
893 xc_image = cpl_image_duplicate(corrected);
896 cpl_image_delete(corrected);
897 corrected = cpl_image_collapse_create(xc_image, 1);
898 cpl_image_delete(xc_image);
899 xc_image = corrected;
902 skip_if(cpl_image_divide_scalar(xc_image, npix));
904 xc_vector = cpl_vector_wrap(npix, cpl_image_get_data(xc_image));
906 skip_if_error_present();
909 phdisp = visir_spc_phys_lrp();
910 cpl_msg_info(cpl_func,
"Central Dispersion (physical model) [pixel/m]: %g",
911 1.0/visir_spc_get_dispersion(phdisp, npix/2.0 + 0.5));
912 cpl_msg_info(cpl_func,
"Central Wavelength (physical model) [m]: %g",
913 cpl_polynomial_eval_1d(phdisp, npix/2.0 + 0.5, NULL));
914 cpl_msg_info(cpl_func,
"First Wavelength (physical model) [m]: %g",
915 cpl_polynomial_eval_1d(phdisp, 1.0, NULL));
916 cpl_msg_info(cpl_func,
"Last Wavelength (physical model) [m]: %g",
917 cpl_polynomial_eval_1d(phdisp, 1024, NULL));
918 cpl_polynomial_dump(phdisp, stdout);
919 cpl_polynomial_delete(phdisp);
922 phdisp = visir_spc_phys_disp(npix, wlen, resol, cfg->orderoffset, is_aqu);
923 skip_if_error_present();
925 if (cpl_polynomial_get_degree(phdisp) == 2) {
926 const cpl_size i2 = 2;
927 cpl_msg_info(cpl_func,
"Dispersion polynomial of physical model:"
928 " %gmum + ipix * %gmum/pixel + ipix^2 * (%g)mum/pixel^2 "
929 "[ipix = 1, 2, ..., %d]",
930 cpl_polynomial_get_coeff(phdisp, &i0) * 1e6,
931 cpl_polynomial_get_coeff(phdisp, &i1) * 1e6,
932 cpl_polynomial_get_coeff(phdisp, &i2) * 1e6,
936 cpl_msg_info(cpl_func,
"Dispersion polynomial of physical model:"
937 " %gmum + ipix * %gmum/pixel [ipix = 1, 2, ..., %d]",
938 cpl_polynomial_get_coeff(phdisp, &i0) * 1e6,
939 cpl_polynomial_get_coeff(phdisp, &i1) * 1e6, npix);
942 temiss = visir_bivector_load_fits(linefile,
"Wavelength",
"Emission", 1);
943 any_if (
"Could not load file with Emission Lines");
945 tqeff = visir_bivector_load_fits(qefffile,
"Wavelength",
"Efficiency",
947 any_if(
"Could not load file with Quantum-Efficiencies");
950 visir_bivector_plot(
"set grid;set xlabel 'Wavelength [m]';",
"t '"
951 "Quantum Efficiency' w linespoints",
"", tqeff);
954 vsymm = cpl_spc_convolve_init(npix, slitw, fwhm, cfg->plot);
956 skip_if (vsymm == NULL);
958 vxc = cpl_vector_new(1);
959 xcdisp = cpl_polynomial_new(1);
961 mymodel.lines = temiss;
962 mymodel.tqeff = tqeff;
963 mymodel.vsymm = vsymm;
969 skip_if(visir_spectro_refine(xcdisp, xc_vector, &mymodel, phdisp,
970 VISIR_XC_LEN, cfg->plot, resol,
971 &qcxc, &didshift, &qcsubdelta));
974 if (fabs(qcsubdelta) >= VISIR_XC_LEN) {
975 cpl_msg_warning(cpl_func,
"Cross-correlation (%g pixel shift): %g",
978 cpl_msg_info(cpl_func,
"Cross-correlation (%g pixel shift): %g",
983 cpl_msg_info(cpl_func,
"Dispersion polynomial from cross-correlation: "
984 "%gm + ipix * %gm/pixel [ipix = 1, 2, ..., %d]",
985 cpl_polynomial_get_coeff(xcdisp, &i0),
986 cpl_polynomial_get_coeff(xcdisp, &i1), npix);
988 cpl_msg_info(cpl_func,
"New Central Wavelength [m]: %g",
989 cpl_polynomial_eval_1d(xcdisp, 0.5*npix+0.5, NULL));
991 *pspc_table = cpl_table_new(npix);
992 skip_if_error_present();
995 wlvals = cpl_vector_new(npix);
996 bug_if (cpl_table_wrap_double(*pspc_table, cpl_vector_get_data(wlvals),
999 skip_if (cpl_vector_fill_polynomial(wlvals, xcdisp, 1.0, 1.0));
1002 spmodel = cpl_vector_new(npix);
1003 bug_if (cpl_table_wrap_double(*pspc_table, cpl_vector_get_data(spmodel),
1005 skip_if (visir_spectro_fill(spmodel, phdisp,
1006 (irplib_base_spectrum_model*)&mymodel));
1009 (void)cpl_vector_unwrap(spmodel);
1010 spmodel = cpl_vector_new(npix);
1011 bug_if (cpl_table_wrap_double(*pspc_table, cpl_vector_get_data(spmodel),
1014 skip_if (visir_spectro_fill(spmodel, xcdisp,
1015 (irplib_base_spectrum_model*)&mymodel));
1017 bug_if (cpl_table_wrap_double(*pspc_table,
1018 cpl_image_get_data_double(xc_image),
1020 (void)cpl_image_unwrap(xc_image);
1024 (void)cpl_vector_unwrap(spmodel);
1025 spmodel = cpl_vector_new(npix);
1026 bug_if (cpl_table_wrap_double(*pspc_table, cpl_vector_get_data(spmodel),
1029 boundary = cpl_vector_new(npix + 1);
1030 skip_if (cpl_vector_fill_polynomial(boundary, xcdisp, 0.5, 1.0));
1031 skip_if (visir_vector_resample(spmodel, boundary, temiss));
1033 bug_if (cpl_table_set_column_unit(*pspc_table,
"WLEN",
"m"));
1034 bug_if (cpl_table_set_column_unit(*pspc_table,
"SPC_MODEL_PH",
1036 bug_if (cpl_table_set_column_unit(*pspc_table,
"SPC_MODEL_XC",
1038 bug_if (cpl_table_set_column_unit(*pspc_table,
"SPC_SKY",
"ADU/s"));
1044 if (resol != VISIR_SPC_R_LRP && cpl_vector_get(wlvals, 0) < N_upper &&
1045 N_upper < cpl_vector_get(wlvals, npix-1))
1046 cpl_msg_warning(cpl_func,
"Spectrum goes above N-band (%gm). Wavelength"
1047 " Calibration may be entirely inaccurate", N_upper);
1049 bug_if(visir_spectro_qclist_wcal(qclist, npix, qcxc, didshift, qcsubdelta,
1053 cpl_bivector * plot = cpl_bivector_wrap_vectors(wlvals, xc_vector);
1055 visir_bivector_plot(
"set grid;set xlabel 'Wavelength [m]';",
"t 'Spec"
1056 "trum from Half-cycle' w linespoints",
"", plot);
1057 cpl_bivector_unwrap_vectors(plot);
1059 visir_table_plot(
"set grid;set xlabel 'Wavelength [m]';",
1060 "t 'Calibrated Model Spectrum' w linespoints",
1061 "", *pspc_table,
"WLEN",
"SPC_MODEL_XC");
1064 visir_table_plot(
"set grid;set xlabel 'Wavelength [m]';",
1065 "t 'Physical Model Spectrum' w linespoints",
1066 "", *pspc_table,
"WLEN",
"SPC_MODEL_PH");
1068 if (resol != VISIR_SPC_R_LRP) {
1071 emission = cpl_bivector_new(2 * npix);
1073 cpl_vector_delete(boundary);
1074 boundary = cpl_vector_new(2 * npix + 1);
1076 cpl_vector_fill_polynomial(cpl_bivector_get_x(emission),
1077 phdisp, -0.5*npix, 1);
1078 cpl_vector_fill_polynomial(boundary, phdisp, -0.5*(npix+1), 1);
1081 visir_spc_emission(emission, boundary, temiss, tqeff, vsymm, temp);
1082 cpl_vector_delete(boundary);
1085 visir_bivector_plot(
"set grid;set xlabel 'Wavelength [m]';",
1086 "t 'Extended Model Spectrum' w linespoints",
1093 (void)cpl_vector_unwrap(wlvals);
1094 (void)cpl_vector_unwrap(spmodel);
1095 cpl_polynomial_delete(phdisp);
1096 cpl_polynomial_delete(xcdisp);
1097 cpl_image_delete(xc_image);
1098 cpl_vector_delete(vsymm);
1099 cpl_image_delete(corrected);
1100 cpl_bivector_delete(temiss);
1101 cpl_bivector_delete(tqeff);
1102 cpl_vector_delete(boundary);
1103 cpl_bivector_delete(emission);
1104 (void)cpl_vector_unwrap(xc_vector);
1105 cpl_vector_delete(vxc);
1107 return cpl_error_get_code();
1129cpl_error_code visir_spc_echelle_limit(
int * pcol1,
int * pcol2,
double wlen,
1130 const visir_spc_config * cfg,
1131 int icolmin,
int icolmax,
1135 visir_optmod ins_settings;
1142 cpl_ensure_code(wlen > 0, CPL_ERROR_ILLEGAL_INPUT);
1143 cpl_ensure_code(pcol1, CPL_ERROR_NULL_INPUT);
1144 cpl_ensure_code(pcol2, CPL_ERROR_NULL_INPUT);
1145 cpl_ensure_code(icolmin > 0, CPL_ERROR_ILLEGAL_INPUT);
1146 cpl_ensure_code(icolmax >= icolmin, CPL_ERROR_ILLEGAL_INPUT);
1148 cpl_ensure_code(cfg->orderoffset >= -4, CPL_ERROR_ILLEGAL_INPUT);
1149 cpl_ensure_code(cfg->orderoffset <= 4, CPL_ERROR_ILLEGAL_INPUT);
1151 error = visir_spc_optmod_init(VISIR_SPC_R_GHR, wlen, &ins_settings, is_aqu);
1153 MSG_ERR(
"HRG Optical model initialization (%p) failed: %d (%g)",
1154 (
void*)&ins_settings, error, wlen);
1155 cpl_ensure_code(0, CPL_ERROR_ILLEGAL_INPUT);
1157 order = cfg->orderoffset + visir_spc_optmod_get_echelle_order(&ins_settings);
1160 cpl_ensure_code(order > 0, CPL_ERROR_ILLEGAL_INPUT);
1161 cpl_ensure_code(order <= 18, CPL_ERROR_ILLEGAL_INPUT);
1163 wleni = visir_spc_optmod_echelle(&ins_settings, wlen, cfg->orderoffset );
1165 echpos = visir_spc_optmod_cross_dispersion(&ins_settings, wleni);
1166 if (echpos <= 0 || echpos >= icolmax) {
1167 MSG_ERR(
"Echelle order %2d: offset %s: location out of range [%d;%d]: "
1168 "%g", order, pn(cfg->orderoffset), icolmin, icolmax, echpos);
1169 cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
1172 *pcol1 = ceil(echpos - whechelle);
1173 *pcol2 = echpos + whechelle;
1175 if (*pcol1 < icolmin) *pcol1 = icolmin;
1176 if (*pcol2 > icolmax) *pcol2 = icolmax;
1178 MSG_INFO(
"Echelle order %2d: offset %s: at col %g [%d; %d]", order,
1179 pn(cfg->orderoffset), echpos, *pcol1, *pcol2);
1182 char * label = cpl_sprintf(
"ESO DRS APGUI OFFS%d", order);
1183 cpl_propertylist_update_int(cfg->phu, label, cfg->orderoffset);
1185 label = cpl_sprintf(
"ESO DRS APGUI WLEN%d", order);
1186 cpl_propertylist_update_double(cfg->phu, label, wleni);
1188 label = cpl_sprintf(
"ESO DRS APGUI CPIX%d", order);
1189 cpl_propertylist_update_double(cfg->phu, label, echpos);
1191 label = cpl_sprintf(
"ESO DRS APGUI LPIX%d", order);
1192 cpl_propertylist_update_int(cfg->phu, label, *pcol1);
1194 label = cpl_sprintf(
"ESO DRS APGUI RPIX%d", order);
1195 cpl_propertylist_update_int(cfg->phu, label, *pcol2);
1199 return cpl_error_get_code();
1217cpl_image * visir_spc_column_extract(
const cpl_image * self,
int icol1,
1218 int icol2,
int doplot)
1221 cpl_image * band = NULL;
1222 cpl_image * spatial = NULL;
1223 const int nrow = cpl_image_get_size_y(self);
1224 const int ncol = cpl_image_get_size_x(self);
1226 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, NULL);
1227 cpl_ensure(icol1 > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1228 cpl_ensure(icol2 >= icol1, CPL_ERROR_ILLEGAL_INPUT, NULL);
1230 cpl_ensure(ncol >= icol2, CPL_ERROR_ILLEGAL_INPUT, NULL);
1232 band = cpl_image_extract(self, icol1, 1, icol2, nrow);
1233 skip_if_error_present();
1236 visir_image_plot(
"",
"t 'The full-width image'",
"", self);
1240 spatial = cpl_image_collapse_create(self, 0);
1241 skip_if_error_present();
1242 skip_if (cpl_image_divide_scalar(spatial, nrow));
1244 visir_image_row_plot(
"set grid;",
"t 'Spectral direction "
1245 "collapsed' w linespoints",
"",
1252 cpl_image_delete(spatial);
1253 if (cpl_error_get_code() && band != NULL) {
1254 cpl_image_delete(band);
1277cpl_error_code visir_spectro_qc(cpl_propertylist * qclist,
1278 cpl_propertylist * paflist,
1279 cpl_boolean drop_wcs,
1280 const irplib_framelist * rawframes,
1281 const char * regcopy,
1282 const char * regcopypaf)
1285 const cpl_propertylist * reflist
1286 = irplib_framelist_get_propertylist_const(rawframes, 0);
1290 bug_if (visir_qc_append_capa(qclist, rawframes));
1292 if (regcopy != NULL)
1293 bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist,
1296 if (regcopypaf != NULL)
1297 bug_if (cpl_propertylist_copy_property_regexp(paflist, reflist,
1300 bug_if (cpl_propertylist_append(paflist, qclist));
1303 cpl_propertylist * pcopy = cpl_propertylist_new();
1304 const cpl_error_code error
1305 = cpl_propertylist_copy_property_regexp(pcopy, reflist,
"^("
1306 IRPLIB_PFITS_WCS_REGEXP
1308 if (!error && cpl_propertylist_get_size(pcopy) > 0) {
1309 cpl_msg_warning(cpl_func,
"Combined image will have no WCS "
1312 cpl_propertylist_delete(pcopy);
1315 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist,
"^("
1316 IRPLIB_PFITS_WCS_REGEXP
1322 return cpl_error_get_code();
1344static cpl_error_code visir_spectro_qclist_wcal(cpl_propertylist * self,
1345 int npix,
double xc,
1346 cpl_boolean didshift,
1348 const cpl_polynomial * phdisp,
1349 const cpl_polynomial * xcdisp)
1352 const cpl_size phdegree = cpl_polynomial_get_degree(phdisp);
1353 const cpl_size xcdegree = cpl_polynomial_get_degree(xcdisp);
1355 const double phdisp0 = cpl_polynomial_eval_1d(phdisp, 1.0, NULL);
1356 const double xcdisp0 = cpl_polynomial_eval_1d(xcdisp, 1.0, NULL);
1358 const double xcwlen = cpl_polynomial_eval_1d(xcdisp, 0.5*(
double)npix+0.5,
1360 const double phcdisp = visir_spc_get_dispersion(phdisp, npix/2.0 + 0.5);
1361 const double xccdisp = visir_spc_get_dispersion(xcdisp, npix/2.0 + 0.5);
1366 skip_if (phdegree < 1);
1367 skip_if (xcdegree < 1);
1369 cpl_msg_info(cpl_func,
"Central Dispersion (physical model) [m/pixel]: %g",
1371 cpl_msg_info(cpl_func,
"Central Dispersion (calibrated) [m/pixel]: %g",
1374 bug_if (cpl_propertylist_append_double(self,
"ESO QC XC", xc));
1377 bug_if (cpl_propertylist_append_double(self,
"ESO QC XCSHIFT",
1380 bug_if (cpl_propertylist_append_int(self,
"ESO QC PHDEGREE", phdegree));
1381 bug_if (cpl_propertylist_append_double(self,
"ESO QC PHDISPX0", phdisp0));
1382 for (i = 1; i <= phdegree; i++) {
1383 const double coeff = cpl_polynomial_get_coeff(phdisp, &i);
1384 char * label = cpl_sprintf(
"ESO QC PHDISPX%d", (
int)i);
1386 bug_if (cpl_propertylist_append_double(self, label, coeff));
1390 bug_if (cpl_propertylist_append_double(self,
"ESO QC XCWLEN", xcwlen));
1392 bug_if (cpl_propertylist_append_int(self,
"ESO QC XCDEGREE", xcdegree));
1393 bug_if (cpl_propertylist_append_double(self,
"ESO QC XCDISPX0", xcdisp0));
1395 for (i = 1; i <= xcdegree; i++) {
1396 const double coeff = cpl_polynomial_get_coeff(xcdisp, &i);
1397 char * label = cpl_sprintf(
"ESO QC XCDISPX%d", (
int)i);
1399 bug_if (cpl_propertylist_append_double(self, label, coeff));
1405 return cpl_error_get_code();
1424static void * visir_spectro_qclist_obs(cpl_propertylist * self,
double xfwhm,
1427 cpl_propertylist_append_double(self,
"ESO QC XFWHM", xfwhm);
1428 cpl_propertylist_append_double(self,
"ESO QC XCENTROI", xcentro);
1430 if (cpl_error_get_code()) {
1431 cpl_msg_error(cpl_func,
"Could not append QC params");
1451static cpl_error_code visir_vector_convolve_symm(cpl_vector * self,
1452 const cpl_vector * vsymm)
1455 const int npix = cpl_vector_get_size(self);
1456 const int ihwidth = cpl_vector_get_size(vsymm) - 1;
1457 cpl_vector * raw = cpl_vector_duplicate(self);
1458 double * pself= cpl_vector_get_data(self);
1459 double * praw = cpl_vector_get_data(raw);
1460 const double * psymm = cpl_vector_get_data_const(vsymm);
1465 skip_if_error_present();
1468 skip_if (ihwidth >= npix);
1471 for (i = 0; i < ihwidth; i++) {
1472 pself[i] = praw[i] * psymm[0];
1473 for (j = 1; j <= ihwidth; j++) {
1474 const int k = i-j < 0 ? 0 : i-j;
1475 pself[i] += (praw[k]+praw[i+j]) * psymm[j];
1480 for (i = ihwidth; i < npix-ihwidth; i++) {
1481 pself[i] = praw[i] * psymm[0];
1482 for (j = 1; j <= ihwidth; j++)
1483 pself[i] += (praw[i-j]+praw[i+j]) * psymm[j];
1486 for (i = npix-ihwidth; i < npix; i++) {
1487 pself[i] = praw[i] * psymm[0];
1488 for (j = 1; j <= ihwidth; j++) {
1489 const int k = i+j > npix-1 ? npix - 1 : i+j;
1490 pself[i] += (praw[k]+praw[i-j]) * psymm[j];
1497 cpl_vector_delete(raw);
1499 return cpl_error_get_code();
1524cpl_image * visir_spc_flip(
const cpl_image * image,
double wlen,
1525 visir_spc_resol resol, visir_data_type dtype,
1528 cpl_image * flipped = cpl_image_cast(image, CPL_TYPE_DOUBLE);
1529 visir_optmod ins_settings;
1530 if (is_flipped) *is_flipped =
false;
1532 skip_if_error_present();
1534 if ((resol == VISIR_SPC_R_HR || resol == VISIR_SPC_R_GHR) &&
1535 visir_spc_optmod_init(resol, wlen, &ins_settings,
1536 visir_data_is_aqu(dtype))) {
1537 visir_error_set(CPL_ERROR_ILLEGAL_INPUT);
1544 if (visir_data_is_aqu(dtype)) {
1545 skip_if (cpl_image_turn(flipped, 1));
1546 if ((resol == VISIR_SPC_R_HR || resol == VISIR_SPC_R_GHR) &&
1547 visir_spc_optmod_side_is_A(&ins_settings) == 0) {
1548 cpl_msg_info(cpl_func,
"Flipping image");
1549 skip_if (cpl_image_flip(flipped, 0));
1550 if (is_flipped) *is_flipped =
true;
1554 else if ((resol != VISIR_SPC_R_HR && resol != VISIR_SPC_R_GHR) ||
1555 visir_spc_optmod_side_is_A(&ins_settings) > 0) {
1557 cpl_msg_info(cpl_func,
"Flipping image");
1559 skip_if (cpl_image_flip(flipped, 0));
1560 if (is_flipped) *is_flipped =
true;
1565 if (cpl_error_get_code() && flipped) {
1566 cpl_image_delete(flipped);
1591static cpl_polynomial * visir_spc_phys_disp(
int npix,
double wlen,
1592 visir_spc_resol resol,
int ioffset,
1596 cpl_polynomial * phdisp = NULL;
1597 visir_optmod ins_settings;
1603 const cpl_size i1 = 1;
1604 const cpl_size i0 = 0;
1607 cpl_ensure(resol, CPL_ERROR_ILLEGAL_INPUT, NULL);
1608 cpl_ensure(wlen > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1609 cpl_ensure(npix > 1, CPL_ERROR_ILLEGAL_INPUT, NULL);
1616 cpl_ensure(!visir_spc_optmod_init(resol, wlen, &ins_settings, is_aqu),
1617 CPL_ERROR_ILLEGAL_INPUT, NULL);
1622 dwl = visir_spc_optmod_wlen(&ins_settings, &wlen0, &wlen1);
1624 cpl_ensure(dwl >= 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1629 if (fabs(dwl) > 2*wlen*DBL_EPSILON) cpl_msg_warning(cpl_func,
"Too large res"
1630 "idual in Scan-Angle determination [meps]: %g", dwl/DBL_EPSILON/wlen);
1632 if ((resol == VISIR_SPC_R_HR || resol == VISIR_SPC_R_GHR) &&
1633 !visir_spc_optmod_side_is_A(&ins_settings)) {
1634 const double swap = wlen1;
1638 cpl_ensure(wlen1 > wlen0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1640 if (resol == VISIR_SPC_R_LRP) {
1641 phdisp = visir_spc_phys_lrp();
1645 phdisp = cpl_polynomial_new(1);
1648 disp = (wlen1-wlen0)/(npix-1);
1650 skip_if_error_present();
1652 skip_if (cpl_polynomial_set_coeff(phdisp, &i1, disp));
1654 skip_if (cpl_polynomial_set_coeff(phdisp, &i0, wlen0-disp));
1657 if ((resol == VISIR_SPC_R_HR || resol == VISIR_SPC_R_GHR) &&
1658 !visir_spc_optmod_side_is_A(&ins_settings)) {
1659 cpl_msg_info(cpl_func,
"HR B-side WLMin, WLMax, Disp: %g %g %g", wlen0,
1660 wlen1, cpl_polynomial_get_coeff(phdisp, &i1));
1662 cpl_msg_info(cpl_func,
"WLMin, WLMax, Disp: %g %g %g", wlen0, wlen1,
1663 cpl_polynomial_get_coeff(phdisp, &i1));
1666 if (resol == VISIR_SPC_R_GHR && ioffset != 0) {
1669 const double dispi = visir_spc_optmod_echelle(&ins_settings,
1670 cpl_polynomial_get_coeff(phdisp, &i1), ioffset);
1671 const double wlen0i= visir_spc_optmod_echelle(&ins_settings,
1672 cpl_polynomial_get_coeff(phdisp, &i0), ioffset);
1674 skip_if (cpl_polynomial_set_coeff(phdisp, &i1, dispi));
1676 skip_if (cpl_polynomial_set_coeff(phdisp, &i0, wlen0i));
1678 cpl_msg_info(cpl_func,
"WLc relative error(%d): %g", ioffset,
1679 (wlen0i - cpl_polynomial_eval_1d(phdisp, 1, NULL))/wlen0i);
1685 if (cpl_error_get_code() && phdisp != NULL) {
1686 cpl_polynomial_delete(phdisp);
1711cpl_bivector * visir_bivector_load_fits(
const char * file,
1712 const char * labelx,
1713 const char * labely,
1717 cpl_bivector * result = NULL;
1718 cpl_table * table = NULL;
1719 cpl_propertylist * extlist = NULL;
1720 cpl_vector * xwrapper;
1721 cpl_vector * ywrapper;
1729 bug_if (extnum < 1);
1731 next = cpl_fits_count_extensions(file);
1732 any_if(
"Could not load FITS table from (extension %d in) file: %s",
1733 extnum, file ? file :
"<NULL>");
1735 skip_if_lt(next, extnum,
"extensions in file: %s", file);
1737 table = cpl_table_load(file, extnum, 0);
1738 any_if (
"Could not load FITS table from extension %d of %d in file: %s",
1739 extnum, next, file ? file :
"<NULL>");
1741 extlist = cpl_propertylist_load_regexp(file, extnum,
"EXTNAME", 0);
1742 if (cpl_propertylist_has(extlist,
"EXTNAME")) {
1743 const char * extname = cpl_propertylist_get_string(extlist,
"EXTNAME");
1744 sext = cpl_sprintf(
" (EXTNAME=%s)", extname);
1747 nlines = cpl_table_get_nrow(table);
1748 skip_if_lt(nlines, 2,
"rows in table from extension %d%s of %d "
1749 "in %s", extnum, sext, next, file);
1751 prowx = cpl_table_get_data_double(table, labelx);
1752 any_if(
"Table from extension %d%s of %d in %s has no column %s",
1753 extnum, sext, next, file, labelx);
1755 prowy = cpl_table_get_data_double(table, labely);
1756 any_if(
"Table from extension %d%s of %d in %s has no column %s",
1757 extnum, sext, next, file, labely);
1759 xwrapper = cpl_vector_wrap(nlines, prowx);
1760 ywrapper = cpl_vector_wrap(nlines, prowy);
1762 result = cpl_bivector_wrap_vectors(xwrapper, ywrapper);
1763 cpl_table_unwrap(table, labelx);
1764 cpl_table_unwrap(table, labely);
1766 cpl_msg_info(cpl_func,
"Read %d rows from extension %d%s of %d "
1767 "in %s [%g;%g]", nlines, extnum, sext, next, file,
1768 cpl_vector_get(xwrapper, 0),
1769 cpl_vector_get(ywrapper, nlines-1));
1774 cpl_table_delete(table);
1775 cpl_propertylist_delete(extlist);
1777 if (result && cpl_error_get_code()) {
1778 cpl_bivector_delete(result);
1815static cpl_error_code visir_spc_emission(cpl_bivector * emission,
1816 const cpl_vector * boundary,
1817 const cpl_bivector * temiss,
1818 const cpl_bivector * tqeff,
1819 const cpl_vector * vsymm,
1822 cpl_bivector * tqeffi = NULL;
1823 cpl_vector * planck = NULL;
1824 const int npix = cpl_bivector_get_size(emission);
1827 bug_if(emission == NULL);
1828 bug_if(boundary == NULL);
1829 bug_if(temiss == NULL);
1830 bug_if(tqeff == NULL);
1835 skip_if(cpl_vector_get_size(boundary) != npix + 1);
1837 planck = cpl_vector_new(npix);
1838 skip_if_error_present();
1842 cpl_photom_fill_blackbody(planck, CPL_UNIT_ENERGYRADIANCE,
1843 cpl_bivector_get_x(emission),
1844 CPL_UNIT_LENGTH, 253);
1846 skip_if (visir_vector_resample(cpl_bivector_get_y(emission),
1850 skip_if (visir_vector_convolve_symm(cpl_bivector_get_y(emission),
1853 skip_if (cpl_vector_multiply(cpl_bivector_get_y(emission), planck));
1857 cpl_photom_fill_blackbody(planck, CPL_UNIT_ENERGYRADIANCE,
1858 cpl_bivector_get_x(emission),
1859 CPL_UNIT_LENGTH, temp);
1862 skip_if (cpl_vector_multiply_scalar(planck, 0.12));
1865 skip_if (cpl_vector_add(cpl_bivector_get_y(emission), planck));
1868 tqeffi = cpl_bivector_duplicate(emission);
1869 skip_if (cpl_bivector_interpolate_linear(tqeffi, tqeff));
1871 skip_if (cpl_vector_multiply(cpl_bivector_get_y(emission),
1872 cpl_bivector_get_y(tqeffi)));
1876 cpl_bivector_delete(tqeffi);
1877 cpl_vector_delete(planck);
1879 return cpl_error_get_code();
1907static cpl_vector * cpl_spc_convolve_init(
int maxlen,
double slitw,
1908 double fwhm,
int doplot)
1911 const double sigma = fwhm * CPL_MATH_SIG_FWHM;
1912 const int ihtophat = (int)slitw/2;
1913 const int gausshlen = 1 + 5 * sigma + ihtophat < maxlen/2
1914 ? 1 + 5 * sigma + ihtophat : maxlen/2 - 1;
1916 const int convolen = 1 + 10 * sigma + 8*ihtophat;
1917 cpl_vector * self = cpl_vector_new(gausshlen);
1918 cpl_vector * tophat = cpl_vector_new(convolen);
1922 cpl_image * iself = cpl_image_wrap_double(gausshlen, 1,
1923 cpl_vector_get_data(self));
1926 skip_if_error_present();
1928 skip_if( slitw <= 0.0);
1929 skip_if( fwhm <= 0.0);
1930 skip_if( convolen < 2 * gausshlen);
1933 skip_if (cpl_image_fill_gaussian(iself, 1.0, 1.0, CPL_MATH_SQRT2PI,
1936 if (doplot > 2) visir_vector_plot(
"set grid;",
"t 'Right Half of Gaussian' "
1937 "w linespoints",
"", self);
1940 skip_if( cpl_vector_fill(tophat, 0.0));
1942 for (i = convolen/2-ihtophat; i < 1+convolen/2+ihtophat; i++)
1943 skip_if (cpl_vector_set(tophat, i, 1.0/(1.0+2.0*ihtophat)));
1946 skip_if (visir_vector_convolve_symm(tophat, self));
1948 if (doplot > 2) visir_vector_plot(
"set grid;",
"t 'Full Width Convolution' "
1949 "w linespoints",
"", tophat);
1954 memcpy(cpl_vector_get_data(self),
1955 cpl_vector_get_data(tophat) + convolen/2,
1956 sizeof(
double)*gausshlen);
1959 for (i = 0 ; i < gausshlen; i++)
1960 skip_if (cpl_vector_set(self, i, cpl_vector_get(tophat,
1964 skip_if_error_present();
1966 cpl_msg_info(cpl_func,
"Convolving Model Spectrum, Gauss-sigma=%g, "
1967 "Tophat-width=%d, Truncation-Error=%g with width=%d", sigma,
1969 cpl_vector_get(self,gausshlen-1)/cpl_vector_get(self,0),
1972 if (doplot > 1) visir_vector_plot(
"set grid;",
"t 'Right Half of Convolution"
1973 "' w linespoints",
"", self);
1977 cpl_vector_delete(tophat);
1978 cpl_image_unwrap(iself);
1980 if (cpl_error_get_code()) {
1981 cpl_vector_delete(self);
1990static cpl_error_code
1991fit_gaussians(
const cpl_image * flipped,
const cpl_vector * error,
1992 cpl_size icollo, cpl_size icolhi,
1993 cpl_propertylist * qclist)
1995 cpl_size nrow = cpl_image_get_size_y(flipped);
1996 cpl_size ncol = cpl_image_get_size_x(flipped);
1997 icollo = CX_MAX(1, icollo);
1998 icolhi = CX_MIN(ncol, icolhi);
1999 cpl_errorstate cleanstate = cpl_errorstate_get();
2001 double sigs_err = 0.;
2003 double peaks_err = 0.;
2005 for (cpl_size row = 0; row < nrow; row++) {
2006 const cpl_binary * dmask = cpl_image_get_bpm_const(flipped) ?
2007 cpl_mask_get_data_const(cpl_image_get_bpm_const(flipped)) : NULL;
2008 const double *dflipped = cpl_image_get_data_double_const(flipped);
2009 double * dx = cpl_malloc(ncol *
sizeof(*dx));
2010 double * dy = cpl_malloc(ncol *
sizeof(*dy));
2011 double * dye = cpl_malloc(ncol *
sizeof(*dye));
2016 for (cpl_size i = icollo; i <= icolhi; i++) {
2017 if (dmask == NULL || !dmask[row * ncol + i]) {
2019 dy[n] = dflipped[row * ncol + (i - 1)];
2020 dye[n] = cpl_vector_get(error, (i - 1));
2025 x = cpl_vector_wrap(n, dx);
2026 y = cpl_vector_wrap(n, dy);
2027 ye = cpl_vector_wrap(n, dye);
2028 double x0, sigma, sigma_err, peak, peak_err;
2029 fit_1d_gauss(x, y, ye, &x0, NULL, &peak, &peak_err, &sigma, &sigma_err);
2030 if (cpl_error_get_code() != CPL_ERROR_NONE) {
2031 cpl_msg_debug(cpl_func,
"FIT row %lld failed", row);
2032 cpl_errorstate_set(cleanstate);
2035 sigs[nmeas] = sigma;
2036 peaks[nmeas] = peak;
2037 sigs_err += sigma * sigma;
2038 peaks_err += peak * peak;
2040 cpl_msg_debug(cpl_func,
"FIT row %lld x %g sig %g +- %g "
2042 row, x0, sigma, sigma_err, peak, peak_err);
2044 cpl_vector_delete(x);
2045 cpl_vector_delete(y);
2046 cpl_vector_delete(ye);
2054 cpl_vector * sigv = cpl_vector_wrap(nmeas, sigs);
2055 cpl_vector * peakv = cpl_vector_wrap(nmeas, peaks);
2056 double medsigma = cpl_vector_get_median(sigv);
2057 double medsigma_err = sqrt(sigs_err) * sqrt(CPL_MATH_PI_2) / nmeas;
2058 double medpeak = cpl_vector_get_median(peakv);
2059 double medpeak_err = sqrt(peaks_err) * sqrt(CPL_MATH_PI_2) / nmeas;
2060 cpl_msg_info(cpl_func,
"Median FWHM of spectrum: %g +- %g, Peak %g +- %g",
2061 medsigma, medsigma_err, medpeak, medpeak_err);
2062 cpl_propertylist_append_double(qclist,
"ESO QC GAUSSFIT FWHM",
2064 cpl_propertylist_set_comment(qclist,
"ESO QC GAUSSFIT FWHM",
"[pix]");
2065 cpl_propertylist_append_double(qclist,
"ESO QC GAUSSFIT FWHM_ERR",
2066 medsigma_err * 2.355);
2067 cpl_propertylist_append_double(qclist,
"ESO QC GAUSSFIT PEAK", medpeak);
2068 cpl_propertylist_set_comment(qclist,
"ESO QC GAUSSFIT PEAK",
"[adu/s]");
2069 cpl_propertylist_append_double(qclist,
"ESO QC GAUSSFIT PEAK_ERR",
2071 cpl_vector_unwrap(sigv);
2072 cpl_vector_unwrap(peakv);
2074 return cpl_error_get_code();
2085static cpl_error_code
2086add_qc_background_sigma(
const cpl_image * flipped, cpl_propertylist * qclist)
2090 if (cpl_image_get_size_y(flipped) > VISIR_AQU_APPROX_WLEN13) {
2091 lly = VISIR_AQU_APPROX_WLEN8;
2092 ury = VISIR_AQU_APPROX_WLEN13;
2096 ury = cpl_image_get_size_y(flipped);
2099 cpl_image * cutimg =
2100 cpl_image_extract(flipped, 1, lly, cpl_image_get_size_x(flipped), ury);
2103 double bkgmad, bkgmed;
2104 bkgmed = cpl_image_get_mad(cutimg, &bkgmad);
2105 for (
size_t i = 0; i < 3; i++) {
2107 cpl_mask_threshold_image_create(cutimg,
2108 bkgmed - bkgmad * CPL_MATH_STD_MAD * 3,
2109 bkgmed + bkgmad * CPL_MATH_STD_MAD * 3);
2111 cpl_image_reject_from_mask(cutimg, rej);
2112 cpl_mask_delete(rej);
2113 bkgmed = cpl_image_get_mad(cutimg, &bkgmad);
2116 cpl_propertylist_append_double(qclist,
"ESO QC BACKGD SIGMA",
2117 bkgmad * CPL_MATH_STD_MAD);
2118 cpl_propertylist_set_comment(qclist,
"ESO QC BACKGD SIGMA",
2119 "[adu/s] background corrected");
2120 cpl_image_delete(cutimg);
2122 return cpl_error_get_code();
2132static double * visir_bkg_linfit(
const cpl_image * row)
2138 const int n = cpl_image_get_size_x(row);
2139 const int ngood = n - cpl_image_count_rejected(row);
2144 x = cpl_malloc(ngood *
sizeof(
double));
2145 y = cpl_malloc(ngood *
sizeof(
double));
2149 for (
int bad, i = 0, j = 0; i < n; ++i) {
2150 const double cand = cpl_image_get(row, i+1, 1, &bad);
2159 double c0, c1, cov00, cov01, cov11;
2160 gsl_fit_linear(x, 1, y, 1, ngood, &c0, &c1, &cov00, &cov01, &cov11, NULL);
2163 rv = cpl_malloc(n *
sizeof(
double));
2164 for (
int i = 0; i < n; ++i) {
2165 gsl_fit_linear_est(i, c0, c1, cov00, cov01, cov11, rv + i, NULL);
2196int visir_norm_coord(
const bool rev,
const float coord,
const int lcol,
2197 const int rcol,
const visir_apdefs * aps)
2199 const int x = coord < 0 ? -coord : coord;
2200 if (copysign(1.0, coord) > 0.0)
return
2201 rev ? rcol - aps->limits[x].l + 1 : aps->limits[x].r - lcol + 1;
2203 rev ? rcol - aps->limits[x].r + 1 : aps->limits[x].l - lcol + 1;
2215static cpl_image * visir_image_filter_median(
const cpl_image * image,
2216 const int nx,
const int ny)
2218 cpl_image* filtered = NULL;
2219 cpl_mask* kernel = NULL;
2222 return cpl_image_duplicate(image);
2226 cpl_msg_error(cpl_func,
"kernel size must be odd");
2227 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
2232 const cpl_size xsz = cpl_image_get_size_x(image);
2233 const cpl_size ysz = cpl_image_get_size_y(image);
2234 const cpl_type type = cpl_image_get_type(image);
2238 filtered = cpl_image_new(xsz, ysz, type);
2242 kernel = cpl_mask_new(nx, ny);
2243 cpl_mask_not(kernel);
2244 cpl_image_filter_mask(filtered, image, kernel, CPL_FILTER_MEDIAN,
2249 if (cpl_error_get_code()) {
2250 cpl_msg_error(cpl_error_get_where(),
"%s", cpl_error_get_message());
2251 cpl_image_delete(filtered); filtered = NULL;
2253 cpl_mask_delete(kernel);
2275static void * visir_extraction(
const cpl_image * insci,
const cpl_image * invar,
2276 const cpl_image * insky, cpl_vector * outext,
2277 cpl_vector * outsky, cpl_vector * outerr,
2278 cpl_image * outwgt,
const visir_spc_config * cfg,
2279 const int method,
const int ncomb,
const int beg,
2282 cpl_image* smoothed = NULL;
2285 if (!insci || !invar || !insky || !cfg ||
2286 !outext || !outsky || !outerr || !outwgt) {
2287 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
2292 const int specLen = cpl_image_get_size_x(insci);
2293 const int numRows = cpl_image_get_size_y(insci);
2294 if (beg < 0 || beg >= numRows || end < 0 || end >= numRows || beg > end) {
2295 cpl_error_set(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT);
2300 double * oext_d = cpl_vector_get_data(outext);
2301 double * osky_d = cpl_vector_get_data(outsky);
2302 double * oerr_d = cpl_vector_get_data(outerr);
2303 double * owgt_d = cpl_image_get_data(outwgt);
2307 const double *
const isci_d = cpl_image_get_data_const(insci);
2308 const double *
const isky_d = cpl_image_get_data_const(insky);
2309 const double *
const ivar_d = invar ? cpl_image_get_data_const(invar) : NULL;
2316 if (method && abs(end-beg) > cfg->ox_kernel + 2 ) {
2317 cpl_image* smoothed = visir_image_filter_median(
2318 insci, cfg->ox_kernel, cfg->ox_kernel);
2319 double * smoo_d = cpl_image_get_data(smoothed);
2320 for (
int i = 0; i < specLen; i++) {
2322 for (
int j = beg; j <= end; j++)
2323 oext_d[i] += smoo_d[i + j * specLen];
2326 for (
int i = 0; i < specLen; i++) {
2328 for (
int j = beg; j <= end; j++)
2329 oext_d[i] += isci_d[i + j * specLen];
2337 buf = cpl_calloc(specLen,
sizeof(
double));
2338 for (
int iter = 0; iter < cfg->ox_niters; iter++) {
2341 for (
int i = 0; i < specLen; i++) {
2342 for (
int j = beg; j <= end; j++) {
2343 const int index = i + j * specLen;
2345 owgt_d[index] = fabs(oext_d[i]) > 0.00001
2346 ? isci_d[index] / oext_d[i] : 0.0;
2350 cpl_vector* wrap = NULL;
2351 for (
int j = beg; j <= end; j++) {
2355 for (
int i = 0; i < specLen - cfg->ox_smooth; i++) {
2356 wrap = cpl_vector_wrap(cfg->ox_smooth, owgt_d +
2358 double value = cpl_vector_get_median_const(wrap);
2359 if (value < 0) value = 0.0;
2360 buf[i + cfg->ox_smooth / 2] = value;
2361 cpl_vector_unwrap(wrap);
2367 wrap = cpl_vector_wrap(cfg->ox_smooth / 2, owgt_d +
2369 double value = cpl_vector_get_mean(wrap);
2370 cpl_vector_unwrap(wrap);
2371 if (value < 0) value = 0.0;
2372 for (
int i = 0; i < cfg->ox_smooth / 2; i++) {
2379 wrap = cpl_vector_wrap(cfg->ox_smooth / 2, owgt_d +
2380 specLen - cfg->ox_smooth / 2 + j * specLen);
2381 value = cpl_vector_get_mean(wrap);
2382 cpl_vector_unwrap(wrap);
2383 if (value < 0) value = 0.0;
2384 for (
int i = 0; i < cfg->ox_smooth / 2; i++)
2385 buf[i + specLen - cfg->ox_smooth / 2] = value;
2386 for (
int i = 0; i < specLen; i++)
2387 owgt_d[i + j * specLen] = buf[i];
2393 for (
int i = 0; i < specLen; i++) {
2395 for (
int j = beg; j <= end; j++)
2396 value += owgt_d[i + j * specLen];
2397 if (value > 0.00001)
2398 for (
int j = beg; j <= end; j++)
2399 owgt_d[i + j * specLen] /= value;
2401 for (
int j = beg; j <= end; j++)
2402 owgt_d[i + j * specLen] = 0.0;
2407 for (
int i = 0; i < specLen; i++) {
2408 double sumSci, sumSky, sumWgt, sumProf, sumVar;
2409 sumSci = sumSky = sumWgt = sumProf = sumVar = 0.0;
2410 for (
int j = beg; j <= end; j++) {
2411 const int index = i + j * specLen;
2418 double var = cfg->ron * cfg->ron + fabs(oext_d[i] *
2419 owgt_d[index] + isky_d[index]) / cfg->gain;
2424 double value = isci_d[index] - oext_d[i] * owgt_d[index];
2425 if (fabs(value) / sqrt(var) < cfg->ox_sigma) {
2426 const double weight = 1000000 * owgt_d[index] / var;
2427 sumSci += weight * isci_d[index];
2428 sumSky += weight * isky_d[index];
2429 sumWgt += weight * owgt_d[index];
2430 sumProf += owgt_d[index];
2435 if (ivar_d) sumVar += weight * weight * ivar_d[index];
2439 if (sumWgt > 0.00001) {
2440 oext_d[i] = sumSci / sumWgt;
2441 osky_d[i] = sumSky / sumWgt;
2444 oerr_d[i] = sqrt(sumVar / sumWgt / sumWgt);
2448 oerr_d[i] = 1000 * sqrt(sumProf / sumWgt);
2463 for (
int i = 0; i < specLen; i++) {
2465 for (
int j = beg; j <= end; j++)
2466 osky_d[i] += isky_d[i + j * specLen];
2470 for (
int i = 0; i < specLen; i++) {
2474 for (
int j = beg; j <= end; j++)
2475 oerr_d[i] += ivar_d[i + j * specLen];
2476 oerr_d[i] = sqrt(oerr_d[i]);
2479 oerr_d[i] = sqrt(cfg->ron * cfg->ron + fabs(oext_d[i] +
2480 osky_d[i]) / cfg->gain);
2486 cpl_image_delete(smoothed);
2489 if (cpl_error_get_code()) {
2490 cpl_msg_error(cpl_error_get_where(),
"%s", cpl_error_get_message());
2496static cpl_bivector * visir_spc_extract(cpl_image * flipped,
2498 cpl_propertylist * qclist,
2499 cpl_image ** pweight2d,
2500 const visir_spc_config * cfg,
2501 const visir_apdefs * aps,
2502 const bool rev,
const cpl_size ncomb)
2504 extract_func * meth = aps->ident < 0 ? visir_spc_oldex : visir_spc_newex;
2505 return meth(flipped, lcol, rcol, qclist, pweight2d, cfg, aps, rev, ncomb);
2521static cpl_bivector * visir_spc_newex(cpl_image * flipped,
2523 cpl_propertylist * qclist,
2524 cpl_image ** pweight2d,
2525 const visir_spc_config * cfg,
2526 const visir_apdefs * aps,
2527 const bool rev,
const cpl_size ncomb)
2529 cpl_bivector* rv = NULL;
2530 cpl_image* bkg = NULL;
2531 cpl_image* diff = NULL;
2532 cpl_image* var = NULL;
2533 cpl_vector* spc = NULL;
2534 cpl_vector* sky = NULL;
2535 cpl_vector* err = NULL;
2536 cpl_image* wgt = NULL;
2540 if (!flipped || !qclist || !cfg || !aps) {
2541 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
2546 const int ncol = cpl_image_get_size_x(flipped);
2547 const int specLen = cpl_image_get_size_y(flipped);
2548 const int oo = cfg->orderoffset;
2549 const size_t xn = cfg->extract;
2551 if (aps->nlimits < 1) {
2552 cpl_error_set(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT);
2554 if (!pweight2d || *pweight2d) {
2555 cpl_error_set(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT);
2557 if (ncol != rcol-lcol+1) {
2558 cpl_error_set(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT);
2563 MSG_DBG(
":%s:%ld: > [%d;%d] ([%d;%d]) <", pn(oo), xn, 1, ncol, rcol, lcol);
2567 key = cpl_sprintf(
"ESO DRS APDEF%d", aps->ident);
2569 cpl_propertylist_append_string(cfg->phu, key, line);
2575 add_qc_background_sigma(flipped, qclist);
2579 const bool apex = aps->extract_method == VISIR_EXTRACT_METHOD_APERTURE;
2581 diff = cpl_image_duplicate(flipped);
2585 if (!cfg->bkgcorrect) {
2586 const cpl_type type = cpl_image_get_type(flipped);
2587 bkg = cpl_image_new(ncol, specLen, type);
2588 MSG_WARN(
"Sky subtraction is not enabled: extraction results may be "
2592 bkg = cpl_image_duplicate(flipped);
2596 int beg = rev ? aps->nlimits - 1 : 1;
2597 int end = rev ? 0 : aps->nlimits;
2598 const int inc = rev ? -1 : 1;
2601 for (
int a = beg; a != end; a += inc) {
2602 int l = visir_norm_coord(rev, -a, lcol, rcol, aps);
2603 int r = visir_norm_coord(rev, +a, lcol, rcol, aps);
2604 MSG_DBG(
":%s:%ld: [%d;%d] ([%d;%d])", pn(oo), xn, l, r,
2605 aps->limits[a].r, aps->limits[a].l);
2608 if ((1 <= lp && lp <= ncol) || (1 <= l && l <= ncol)) {
2609 const int trunc_lp = lp < 1 ? 1 : lp;
2610 const int trunc_l = l > ncol ? ncol : l;
2611 if (trunc_lp <= trunc_l) {
2612 cpl_image_fill_window(bkg, trunc_lp, 1, trunc_l,
2613 specLen, -INFINITY);
2614 MSG_DBG(
":%s:%ld: [%d;%d] rejected", pn(oo), xn, trunc_lp,
2623 if (1 <= lp && lp <= ncol) {
2624 cpl_image_fill_window(bkg, lp, 1, ncol, specLen, -INFINITY);
2625 MSG_DBG(
":%s:%ld: [%d;%d] rejected", pn(oo), xn, lp, ncol);
2627 cpl_image_reject_value(bkg, CPL_VALUE_MINUSINF);
2632 double (*method)(
const cpl_image *) = cpl_image_get_median;
2633 if (apex && aps->sky_method == VISIR_SKY_METHOD_AVERAGE)
2634 method = cpl_image_get_mean;
2635 const bool linear = apex && aps->sky_method == VISIR_SKY_METHOD_LINFIT;
2638 for (
int r = 0; r < specLen; ++r) {
2639 cpl_image* row = cpl_image_extract(bkg, 1, r+1, ncol, r+1);
2641 double* levels = visir_bkg_linfit(row);
2642 for (cpl_size c = 0; c < ncol; ++c) {
2643 cpl_image_set(bkg, c+1, r+1, levels[c]);
2648 double level = method(row);
2649 cpl_image_fill_window(bkg, 1, r+1, ncol, r+1, level);
2651 cpl_image_delete(row);
2661 cpl_image_subtract(diff, bkg);
2667 var = cpl_image_duplicate(flipped);
2669 cpl_image_divide_scalar(var, cfg->gain);
2670 cpl_image_add_scalar(var, cfg->ron * cfg->ron);
2675 cpl_image_turn(diff, 1);
2676 cpl_image_turn(var, 1);
2677 cpl_image_turn(bkg, 1);
2682 spc = cpl_vector_new(specLen);
2683 sky = cpl_vector_new(specLen);
2684 err = cpl_vector_new(specLen);
2685 wgt = cpl_image_new(specLen, ncol, CPL_TYPE_DOUBLE);
2686 const int beg = ncol - visir_norm_coord(rev, +0.0, lcol, rcol, aps);
2687 const int end = ncol - visir_norm_coord(rev, -0.0, lcol, rcol, aps);
2691 visir_extraction(diff, var, bkg, spc, sky, err, wgt,
2692 cfg, apex ? 0 : 1, ncomb, beg, end);
2696 cpl_image_turn(wgt, -1);
2697 rv = cpl_bivector_wrap_vectors(spc, err);
2704 cpl_image_delete(bkg);
2705 cpl_image_delete(diff);
2706 cpl_image_delete(var);
2707 cpl_vector_delete(sky);
2711 cpl_vector_delete(spc);
2712 cpl_vector_delete(err);
2740static cpl_bivector * visir_spc_oldex(cpl_image * flipped,
2742 cpl_propertylist * qclist,
2743 cpl_image ** pweight2d,
2744 const visir_spc_config * cfg,
2745 const visir_apdefs * aps,
2746 const bool rev,
const cpl_size ncomb)
2748 cpl_bivector* rv = NULL;
2751 cpl_image* orig = NULL;
2752 cpl_image* spatial = NULL;
2753 cpl_image* iweight = NULL;
2754 cpl_mask* binary = NULL;
2755 cpl_image* locnoise = NULL;
2756 cpl_vector* error = NULL;
2757 cpl_vector* ntor = NULL;
2758 cpl_vector* dtor = NULL;
2759 cpl_vector* spectrum = NULL;
2760 cpl_vector* divisor = NULL;
2762 if (!flipped || !qclist || !cfg || !aps) {
2763 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
2768 const int ncol = cpl_image_get_size_x(flipped);
2769 const int nrow = cpl_image_get_size_y(flipped);
2770 const int oo = cfg->orderoffset;
2771 const size_t xn = cfg->extract;
2776 const double sigma = VISIR_SPECTRO_SIGMA;
2779 cpl_error_set(cpl_func, CPL_ERROR_UNSUPPORTED_MODE);
2781 if (aps->nlimits < 1) {
2782 cpl_error_set(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT);
2784 if (!pweight2d || *pweight2d) {
2785 cpl_error_set(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT);
2787 if (ncol != rcol-lcol+1) {
2788 cpl_error_set(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT);
2793 MSG_DBG(
":%s:%ld: > [%d;%d] ([%d;%d]) <", pn(oo), xn, 1, ncol, rcol, lcol);
2797 key = cpl_sprintf(
"ESO DRS APDEF%d", aps->ident);
2799 cpl_propertylist_append_string(cfg->phu, key, line);
2803 add_qc_background_sigma(flipped, qclist);
2806 orig = cpl_image_duplicate(flipped);
2812 if (cfg->bkgcorrect) {
2815 cpl_image* work = cpl_image_duplicate(flipped);
2817 for (
int r = 0; r < nrow; ++r) {
2818 cpl_image* row = cpl_image_extract(work, 1, r+1, ncol, r+1);
2819 double level = cpl_image_get_median(row);
2820 cpl_image_fill_window(work, 1, r+1, ncol, r+1, level);
2821 cpl_image_delete(row);
2825 cpl_image_subtract(flipped, work);
2826 cpl_image_delete(work);
2831 const int is_echelle = ncol <= 2 * (whechelle + 1);
2836 double mean = cpl_image_get_mean(flipped);
2837 MSG_INFO(
"Combined image has mean: %g", mean);
2839 cpl_vector* col = cpl_vector_new(nrow);
2842 double * pweight = cpl_image_get_data_double(flipped);
2843 for (
int r=0; r < nrow; r++, pweight += ncol) {
2846 cpl_image* imrow = cpl_image_wrap_double(ncol, 1, pweight);
2849 mean = cpl_image_get_mean(imrow);
2850 cpl_vector_set(col, r, mean);
2853 cpl_image_subtract_scalar(imrow, mean);
2855 cpl_image_unwrap(imrow);
2860 if (cfg->plot > 1) {
2862 "set grid;",
"t 'Estimated Background' w linespoints",
"", col);
2865 cpl_vector_delete(col);
2871 spatial = cpl_image_collapse_create(flipped, 0);
2872 cpl_image_divide_scalar(spatial, nrow);
2877 iweight = cpl_image_duplicate(spatial);
2878 cpl_image_normalise(iweight, CPL_NORM_ABSFLUX);
2879 const double sqflux = cpl_image_get_sqflux(iweight);
2880 const double weight_2norm = sqrt(sqflux);
2881 MSG_INFO(
"2-norm of weights: %g", weight_2norm);
2885 if (cfg->plot > 1) {
2886 visir_image_row_plot(
2887 "set grid;",
"t 'Cleaned, normalized combined image with spectral "
2888 "direction averaged' w linespoints",
"", iweight, 1, 1, 1);
2894 const double sp_median = cpl_image_get_median(spatial);
2895 double stdev2d = visir_img_phot_sigma_clip(flipped);
2896 stdev2d /= sqrt(nrow);
2897 MSG_INFO(
"spatial median %g and stdev %g", sp_median, stdev2d);
2903 binary = cpl_mask_threshold_image_create(spatial,
2904 sp_median - sigma * stdev2d, sp_median + sigma * stdev2d);
2905 int mspix = cpl_mask_count(binary);
2906 if (mspix == ncol) {
2907 cpl_msg_error(cpl_func,
"%d spatial "
2908 "weights too noisy. sigma=%g. stdev2d=%g. Spatial median=%g", ncol,
2909 sigma, stdev2d, sp_median);
2910 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
2915 MSG_INFO(
"Pixels of noise (%g +/- %g*%g): %d", sp_median, stdev2d, sigma,
2917 cpl_image_reject_from_mask(spatial, binary);
2922 cpl_size ifwhmx, ifwhmy;
2925 cpl_image_get_maxpos(spatial, &ifwhmx, &ifwhmy);
2927 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT);
2932 const double max = cpl_image_get(spatial, ifwhmx, 1, &rejected);
2934 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT);
2935 }
else if (max <= 0.0) {
2936 cpl_msg_error(cpl_func,
"Cannot compute "
2937 "FWHM on a collapsed spectrum with a non-positive maximum: %g (at "
2938 "i=%lld)", max, ifwhmx);
2939 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
2944 if (cfg->plot > 1) {
2945 visir_image_col_plot(
"",
"t 'Most intense column' w linespoints",
2946 "", flipped, ifwhmx, ifwhmx, 1);
2947 visir_image_row_plot(
"set grid;",
"t 'Combined image with spectral "
2948 "direction collapsed' w linespoints",
2949 "", spatial, 1, 1, 1);
2955 int ilnoise, ihnoise;
2957 for (ilnoise = ifwhmx; ilnoise > 0 &&
2958 !cpl_image_is_rejected(spatial, ilnoise, 1); ilnoise--);
2960 for (ihnoise = ifwhmx; ihnoise <= ncol &&
2961 !cpl_image_is_rejected(spatial, ihnoise, 1); ihnoise++);
2963 if (!ilnoise) ilnoise = 1;
2964 if (ihnoise > ncol) ihnoise = ncol;
2967 const double xcentro = cpl_image_get_centroid_x_window(spatial,
2968 ilnoise, 1, ihnoise, 1);
2969 double xfwhm, yfwhm;
2970 cpl_image_get_fwhm(spatial, ifwhmx, 1, &xfwhm, &yfwhm);
2971 visir_spectro_qclist_obs(qclist, xfwhm, xcentro);
2972 MSG_INFO(
"Spatial FWHM(%d:%lld:%d:%g): %g", ilnoise, ifwhmx, ihnoise,
2974 cpl_image_delete(spatial); spatial = NULL;
2981 int iright = ncol - 5;
2983 if (ileft > xcentro - xfwhm * 2) ileft = xcentro - xfwhm * 2;
2984 if (iright < xcentro + xfwhm * 2) iright = xcentro + xfwhm * 2;
2985 MSG_INFO(
"HRG pixels of noise: [1 %d] [%d %d]", ileft, iright, ncol);
2989 cpl_mask_xor(binary, binary);
2993 cpl_binary * pbin = cpl_mask_get_data(binary);
2994 for (
int i = 0; i < ncol; i++) pbin[i] = CPL_BINARY_0;
2995 for (
int i = 0; i < ileft; i++) pbin[i] = CPL_BINARY_1;
2996 for (
int i = iright; i < ncol; i++) pbin[i] = CPL_BINARY_1;
2998 mspix = cpl_mask_count(binary);
2999 MSG_INFO(
"Pixels of noise (post-echelle refinement): %d", mspix);
3005 cpl_msg_error(cpl_func,
"Cannot estimate "
3006 "spectrum noise with just %d pixels of noise", mspix);
3007 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
3013 locnoise = cpl_image_new_from_mask(binary);
3016 cpl_mask_delete(binary); binary = NULL;
3019 error = cpl_vector_new(nrow);
3020 for (
int r = 0; r < nrow; r++) {
3024 cpl_image* imrow = cpl_image_extract(flipped, 1, r+1, ncol, r+1);
3028 cpl_apertures* objs = cpl_apertures_new_from_image(imrow, locnoise);
3032 double stdev1d = cpl_apertures_get_stdev(objs, 1);
3037 double npp = weight_2norm * stdev1d;
3041 cpl_vector_set(error, r, npp);
3043 cpl_apertures_delete(objs);
3044 cpl_image_delete(imrow);
3050 fit_gaussians(flipped, error, ifwhmx - 20, ifwhmx + 20, qclist);
3057 for (
int c = 1; c <= ncol; c++) {
3059 ntor = cpl_vector_new_from_image_column(flipped, c);
3063 const double weight = cpl_image_get(iweight, c, 1, &rejected);
3065 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
3070 cpl_vector_delete(ntor); ntor = NULL;
3073 cpl_vector_multiply_scalar(ntor, weight);
3077 cpl_vector_add(spectrum, ntor);
3078 cpl_vector_delete(ntor); ntor = NULL;
3084 cpl_vector_add(divisor, dtor);
3085 cpl_vector_delete(dtor); dtor = NULL;
3094 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT);
3100 cpl_vector_divide(spectrum, divisor);
3102 double min = cpl_vector_get_min(spectrum);
3103 if (min < 0) MSG_WARN(
"Extracted spectrum has negative intensity: %g", min);
3106 *pweight2d = cpl_image_new(ncol, nrow, CPL_TYPE_DOUBLE);
3107 for (
int r=1; r <= nrow; r++) {
3108 cpl_image_copy(*pweight2d, iweight, 1, r);
3110 if (cfg->plot > 0) {
3111 visir_image_plot(
"",
"t 'The weight map'",
"", *pweight2d);
3114 rv = cpl_bivector_wrap_vectors(spectrum, error);
3116 if (cfg->plot > 2) {
3117 visir_bivector_plot(
"",
"t 'error versus spectrum'",
"", rv);
3124 cpl_image_delete(orig);
3125 cpl_image_delete(spatial);
3126 cpl_image_delete(iweight);
3127 cpl_mask_delete(binary);
3128 cpl_image_delete(locnoise);
3133 cpl_vector_delete(spectrum);
3134 cpl_vector_delete(error);
3137 if (cpl_error_get_code()) {
3138 cpl_msg_error(cpl_error_get_where(),
"%s", cpl_error_get_message());
3167static cpl_error_code visir_spectro_fill(cpl_vector * self,
3168 const cpl_polynomial * disp,
3169 irplib_base_spectrum_model * model)
3172 visir_spectrum_model * mymodel = (visir_spectrum_model*)model;
3173 const cpl_size npix = cpl_vector_get_size(self);
3175 cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
3176 cpl_ensure_code(model, CPL_ERROR_NULL_INPUT);
3177 cpl_ensure_code(disp, CPL_ERROR_NULL_INPUT);
3179 cpl_vector * wavelength = cpl_vector_new(npix);
3180 cpl_bivector * emission = cpl_bivector_wrap_vectors(wavelength, self);
3181 cpl_vector * boundary = cpl_vector_new(npix + 1);
3185 skip_if (cpl_vector_fill_polynomial(cpl_bivector_get_x(emission),
3187 skip_if (cpl_vector_fill_polynomial(boundary, disp, 0.5, 1));
3190 skip_if (visir_spc_emission(emission, boundary, mymodel->lines,
3191 mymodel->tqeff, mymodel->vsymm,
3195 cpl_bivector_unwrap_vectors(emission);
3196 cpl_vector_delete(wavelength);
3197 cpl_vector_delete(boundary);
3199 return cpl_error_get_code();
3220static cpl_error_code visir_spectro_refine(cpl_polynomial * self,
3221 const cpl_vector * xc_vector,
3222 visir_spectrum_model * pmymodel,
3223 const cpl_polynomial * phdisp,
3224 int hsize, cpl_boolean doplot,
3225 visir_spc_resol resol,
3227 cpl_boolean * pdidshift,
3230 const int subres = VISIR_XC_SUBSEARCH;
3231 cpl_polynomial * shifted = NULL;
3232#ifdef VISIR_SPC_CAL_HIGH
3233 const int fitdeg = 2;
3234 double pixstep = 0.5;
3235 double pixtol = 1e-5;
3236 const int maxite = fitdeg * 200;
3239 const int clines = (int)(cpl_bivector_get_size(pmymodel->lines) *
3240 cpl_vector_get_size(xc_vector));
3241 cpl_errorstate prestate = cpl_errorstate_get();
3244 cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
3245 cpl_ensure_code(xc_vector, CPL_ERROR_NULL_INPUT);
3246 cpl_ensure_code(pmymodel, CPL_ERROR_NULL_INPUT);
3247 cpl_ensure_code(phdisp, CPL_ERROR_NULL_INPUT);
3248 cpl_ensure_code(pxc, CPL_ERROR_NULL_INPUT);
3249 cpl_ensure_code(pdidshift, CPL_ERROR_NULL_INPUT);
3250 cpl_ensure_code(pdelta, CPL_ERROR_NULL_INPUT);
3252 skip_if(cpl_polynomial_copy(self, phdisp));
3254#ifdef VISIR_SPC_CAL_HIGH
3255 if (irplib_polynomial_find_1d_from_correlation_all
3256 (self, fitdeg, xc_vector, 1, clines,
3257 (irplib_base_spectrum_model*)pmymodel,
3258 visir_spectro_fill, pixtol, pixstep,
3259 hsize, maxite, maxfail, maxcont, doplot, pxc) || *pxc <= 0.0) {
3261 irplib_error_recover(prestate,
"Could not optimize %d "
3262 "coefficients, trying shifting", fitdeg);
3263 skip_if(cpl_polynomial_copy(self, phdisp));
3265 skip_if(visir_polynomial_shift_1d_from_correlation
3266 (self, xc_vector, (irplib_base_spectrum_model*) pmymodel,
3267 visir_spectro_fill, hsize, subres, doplot, pxc, pdelta));
3268 *pdidshift = CPL_TRUE;
3271 shifted = cpl_polynomial_duplicate(self);
3273 if (irplib_polynomial_find_1d_from_correlation_all
3274 (self, fitdeg, xc_vector, 1, clines,
3275 (irplib_base_spectrum_model*)pmymodel,
3276 visir_spectro_fill, pixtol, pixstep,
3277 hsize, maxite, maxfail, maxcont, doplot, pxc) || *pxc <= 0.0) {
3279 irplib_error_recover(prestate,
"Could not re-optimize %d "
3280 "coefficients, keeping shifted", fitdeg);
3281 skip_if(cpl_polynomial_copy(self, shifted));
3286 cpl_size clow = 0, chigh = 0;
3288 if (resol == VISIR_SPC_R_LRP) {
3292 cpl_vector * xc_vector_cut = cpl_vector_extract(xc_vector, clow,
3293 cpl_vector_get_size(xc_vector)
3295 cpl_polynomial_shift_1d(self, 0, clow);
3296 skip_if(visir_polynomial_shift_1d_from_correlation
3297 (self, xc_vector_cut, (irplib_base_spectrum_model*) pmymodel,
3298 visir_spectro_fill, hsize, subres, doplot, pxc, pdelta));
3299 cpl_polynomial_shift_1d(self, 0, -clow);
3300 cpl_vector_delete(xc_vector_cut);
3301 *pdidshift = CPL_TRUE;
3304 error_if (*pxc <= 0.0, CPL_ERROR_DATA_NOT_FOUND,
"Atmospheric and Model "
3305 "Spectra have non-positive cross-correlation (%g pixel shift): "
3306 "%g", *pdelta, *pxc);
3310 cpl_polynomial_delete(shifted);
3312 return cpl_error_get_code();
3340static cpl_error_code
3341visir_polynomial_shift_1d_from_correlation(cpl_polynomial * self,
3342 const cpl_vector * obs,
3343 irplib_base_spectrum_model * model,
3344 cpl_error_code (*filler)
3346 const cpl_polynomial *,
3347 irplib_base_spectrum_model *),
3351 double * pxc,
double *pshift)
3353 const int nobs = cpl_vector_get_size(obs);
3354 cpl_polynomial * cand = NULL;
3355 cpl_bivector * xcplot = NULL;
3356 double * xcplotx = NULL;
3357 double * xcploty = NULL;
3358 cpl_vector * mspec1d = NULL;
3360 double bestxc = -1.0;
3361 double bestdelta = -1.0;
3365 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
3366 cpl_ensure_code(obs != NULL, CPL_ERROR_NULL_INPUT);
3367 cpl_ensure_code(model != NULL, CPL_ERROR_NULL_INPUT);
3368 cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
3369 cpl_ensure_code(subres > 0, CPL_ERROR_ILLEGAL_INPUT);
3370 cpl_ensure_code(hsize > 0, CPL_ERROR_ILLEGAL_INPUT);
3372 cand = cpl_polynomial_new(1);
3373 mspec1d = cpl_vector_new(2 * hsize + nobs);
3374 vxc = cpl_vector_new(2 * hsize + 1);
3376 xcplot = cpl_bivector_new(subres * (2 * hsize + 1));
3377 xcplotx = cpl_bivector_get_x_data(xcplot);
3378 xcploty = cpl_bivector_get_y_data(xcplot);
3382 for (i = 0; i < subres; i++) {
3383 const double delta = i / (double)subres;
3387 bug_if (cpl_polynomial_copy(cand, self));
3388 bug_if (cpl_polynomial_shift_1d(cand, 0, delta - hsize));
3390 skip_if (filler(mspec1d, cand, model));
3392 ixc = cpl_vector_correlate(vxc, mspec1d, obs);
3393 xc = cpl_vector_get(vxc, ixc);
3397 bestxxc = ixc - hsize;
3398 bestdelta = delta + bestxxc;
3399 cpl_msg_debug(cpl_func,
"Shifting %g = %d + %g pixels (XC=%g)",
3400 bestdelta, bestxxc, delta, bestxc);
3404 for (j = 0; j <= 2 * hsize; j++) {
3405 const double xcj = cpl_vector_get(vxc, j);
3406 xcplotx[i + j * subres] = (double)(j - hsize) + delta;
3407 xcploty[i + j * subres] = xcj;
3412#ifdef IRPLIB_SPC_DUMP
3414 irplib_polynomial_dump_corr_step(self, vxc,
"Shift");
3417 skip_if(cpl_polynomial_shift_1d(self, 0, bestdelta));
3420 cpl_vector_set_size(vxc, 1);
3421 cpl_vector_set_size(mspec1d, nobs);
3422 skip_if (filler(mspec1d, self, model));
3423 bug_if(cpl_vector_correlate(vxc, mspec1d, obs));
3426 char * title = cpl_sprintf(
"t 'Cross-correlation of %d-pixel spectrum "
3427 "(max=%.4g at %g pixel)' w points", nobs,
3428 cpl_vector_get(vxc, 0), bestdelta);
3430 cpl_plot_bivector(
"set grid;set xlabel 'Offset [pixel]';set ylabel "
3431 "'Cross-correlation';", title,
"", xcplot);
3434 irplib_plot_spectrum_and_model(obs, self, model, filler);
3437 cpl_msg_info(cpl_func,
"Shifting %g = %d + %g pixels (XC: %g <=> %g)",
3438 bestdelta, bestxxc, bestdelta - (
double)bestxxc,
3439 cpl_vector_get(vxc, 0), bestxc);
3441 if (pxc != NULL) *pxc = cpl_vector_get(vxc, 0);
3442 if (pshift != NULL) *pshift = bestdelta;
3446 cpl_vector_delete(mspec1d);
3447 cpl_polynomial_delete(cand);
3448 cpl_vector_delete(vxc);
3449 cpl_bivector_delete(xcplot);
3451 return cpl_error_get_code();
3461static cpl_polynomial * visir_spc_phys_lrp(
void)
3463 const double xval[] = {161, 307, 336, 449, 491, 518, 623, 760, 795, 839};
3464 const double yval[] = {8.22e-6, 9.50e-06, 9.660e-06, 10.5e-06, 10.82e-6,
3465 11.e-06, 11.7e-06, 12.54e-06, 12.76e-06,
3468 const cpl_size maxdeg1d = 2;
3470 cpl_polynomial * self = cpl_polynomial_new(1);
3471 const cpl_boolean sampsym = CPL_FALSE;
3472 const size_t nvals =
sizeof(xval)/
sizeof(*xval);
3474 IRPLIB_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual)
3475 cpl_matrix * xmatrix = cpl_matrix_wrap(1, nvals, (
double*)xval);
3476 cpl_vector * yvector = cpl_vector_wrap(nvals, (
double*)yval);
3477 IRPLIB_DIAG_PRAGMA_POP;
3478 cpl_vector * fitres = cpl_vector_new(nvals);
3480 const cpl_error_code error = cpl_polynomial_fit(self, xmatrix, &sampsym,
3482 CPL_FALSE, NULL, &maxdeg1d)
3483 || cpl_vector_fill_polynomial_fit_residual(fitres, yvector, NULL, self,
3486 const double mse = cpl_vector_product(fitres, fitres) / (double)nvals;
3488 (void)cpl_matrix_unwrap(xmatrix);
3489 (void)cpl_vector_unwrap(yvector);
3490 cpl_vector_delete(fitres);
3493 cpl_error_set_where(cpl_func);
3494 cpl_polynomial_delete(self);
3497 cpl_msg_info(cpl_func,
"Fitted %d degree 1D-polynomial to %u "
3498 "wavelengths with a root mean square error [m]: %g",
3499 (
int)maxdeg1d, (
unsigned)nvals, sqrt(mse));
3513static double visir_spc_get_dispersion(
const cpl_polynomial * self,
double xval)
3516 cpl_errorstate prestate = cpl_errorstate_get();
3519 (void)cpl_polynomial_eval_1d(self, xval, &disp);
3521 if (!cpl_errorstate_is_equal(prestate)) {
3522 (void)cpl_error_set_where(cpl_func);
int visir_parameterlist_get_int(const cpl_parameterlist *self, const char *recipe, visir_parameter bitmask)
Retrieve the value of a VISIR integer parameter.
double visir_pfits_get_temp(const cpl_propertylist *self)
The telescope (M1) temperature [Celcius].
double visir_pfits_get_slitwidth(const cpl_propertylist *self)
The slit width in Arcseconds.
double visir_pfits_get_pixscale(const cpl_propertylist *self)
The pixel scale.
double visir_pfits_get_pixspace(const cpl_propertylist *self)
The pixel spacing.
double visir_pfits_get_wlen(const cpl_propertylist *self)
The central wavelength.
const char * visir_pfits_get_resol(const cpl_propertylist *self)
The spectral resolution.