36 #include "irplib_wavecal.h"
37 #include "irplib_utils.h"
38 #include "irplib_polynomial.h"
39 #include "isaac_wavelength.h"
40 #include "isaac_pfits.h"
41 #include "isaac_utils.h"
42 #include "isaac_dfs.h"
52 #define ISAAC_MAX(A,B) ((A) > (B) ? (A) : (B))
53 #define ISAAC_MIN(A,B) ((A) < (B) ? (A) : (B))
57 #define ISAAC_WFWHM 4.0
60 #define SLITWIDTH_TO_SIGMA 0.25
65 #define WAVELEN(poly,ipix) (poly[0] + (ipix) * \
73 #define WAVEDIF(poly,ipix) (poly[1] + (ipix) * \
74 (poly[2]*2 + (ipix) * \
80 #define WAVEDLT(poly,ipix) (0.25*poly[3] + WAVEDIF(poly, ipix))
86 #define THERMAL_START 20000.0
90 #define CALIB_COEFFS 4
102 static int isaac_wavelength_count_lines(
const cpl_bivector *,
double,
double);
103 static int isaac_wavelength_count_linez(
const cpl_bivector *,
double,
double);
104 static cpl_bivector * isaac_wavelength_load_catalog(
const char *,
const char *,
105 const char *,
const char *);
106 static isaac_band isaac_get_band(
const char *);
107 static const char * isaac_get_filtername(isaac_band);
108 static double get_line_offset(
const cpl_bivector *,
const cpl_vector *,
109 int,
int,
double,
int,
int,
int,
double,
const double *,
111 static double isaac_wavelength_centroid(
const cpl_vector *,
int,
int);
112 static computed_disprel * spectro_refine_solution(
const cpl_bivector *,
113 const cpl_vector *,
int,
int,
int,
double,
const double *);
195 computed_disprel * spectro_compute_disprel(
196 const cpl_image * in,
203 const char * table_name,
210 const double * phdisprel)
212 cpl_bivector * spec_cat;
213 computed_disprel * solution;
215 cpl_image * collapsed;
216 cpl_image * thresholded;
217 cpl_vector * spec_init;
218 cpl_vector * spec_bg;
219 cpl_vector * spec_bgclean;
220 double * pspec_bgclean;
221 cpl_vector * spec_bgclean_log;
222 double * pspec_bgclean_log;
224 const int npix = cpl_image_get_size_x(in);
225 double wl_min, wl_max;
229 cpl_ensure(in != NULL, CPL_ERROR_NULL_INPUT, NULL);
230 cpl_ensure(table_name != NULL, CPL_ERROR_NULL_INPUT, NULL);
231 cpl_ensure(phdisprel != NULL, CPL_ERROR_NULL_INPUT, NULL);
235 wl_min = WAVELEN(phdisprel, 0.5);
236 wl_max = WAVELEN(phdisprel, npix+0.5);
239 if ((wl_min > wl_max) || (wl_min < MIN_WAVELENGTH) ||
240 (wl_max > MAX_WAVELENGTH)) {
241 cpl_msg_error(cpl_func,
242 "in provided wavelength range: [%g %g] ([min max] is [%g %g])",
243 wl_min, wl_max, MIN_WAVELENGTH, MAX_WAVELENGTH);
248 cpl_msg_info(cpl_func,
"Load the catalog");
250 if ((spec_cat=isaac_wavelength_load_catalog(table_name, oh,ar,xe))==NULL) {
251 cpl_msg_error(cpl_func,
"Cannot load the catalog");
256 cpl_vector_multiply_scalar(cpl_bivector_get_x(spec_cat), order);
259 cpl_msg_info(cpl_func,
"Cross correlation");
261 emil = isaac_wavelength_count_lines(spec_cat, wl_min, wl_max);
263 cpl_msg_debug(cpl_func,
"Spectral order: %d", order);
264 cpl_msg_debug(cpl_func,
"First guess poly. wl = f(pix) (pix in 1-%d):",
266 cpl_msg_debug(cpl_func,
"f(x) = %g + %g * x + %g * x^2 + %g * x^3\n",
267 phdisprel[0], phdisprel[1], phdisprel[2], phdisprel[3]);
268 cpl_msg_debug(cpl_func,
"Spectral range [%g %g] with %02d out of %d lines",
269 wl_min, wl_max, emil, (
int)cpl_bivector_get_size(spec_cat));
273 cpl_msg_error(cpl_func,
274 "No line found in catalog in the specified range - abort");
275 cpl_bivector_delete(spec_cat);
280 thresholded = cpl_image_duplicate(in);
281 if (cpl_image_threshold(thresholded, 0.0, DBL_MAX, 0.0, 0.0)!=CPL_ERROR_NONE) {
282 cpl_msg_error(cpl_func,
283 "thresholding input image: aborting wavelength calibration");
284 cpl_bivector_delete(spec_cat);
285 cpl_image_delete(thresholded);
292 if ((collapsed = cpl_image_collapse_median_create(thresholded, 0,
293 discard_lo, discard_hi)) == NULL) {
294 cpl_msg_error(cpl_func,
295 "collapsing input image: aborting wavelength calibration");
296 cpl_bivector_delete(spec_cat);
297 cpl_image_delete(thresholded);
300 cpl_image_delete(thresholded);
303 spec_init = cpl_vector_new_from_image_row(collapsed, 1);
304 cpl_image_delete(collapsed);
307 spec_bgclean = cpl_vector_duplicate(spec_init);
308 if ((remove_thermal!=0&&wl_max>THERMAL_START) || !strcmp(table_name,
"oh")){
309 cpl_msg_debug(cpl_func,
"Removing low-frequency background");
311 if ((spec_bg = cpl_vector_filter_median_create(spec_init,
312 (
int)((0.5+8*slit_width)/2))) == NULL) {
313 cpl_msg_error(cpl_func,
"sub_lowpass failed");
314 cpl_bivector_delete(spec_cat);
315 cpl_vector_delete(spec_init);
316 cpl_vector_delete(spec_bgclean);
319 cpl_vector_subtract(spec_bgclean, spec_bg);
320 cpl_vector_delete(spec_bg);
322 pspec_bgclean = cpl_vector_get_data(spec_bgclean);
323 for (i=0; i<cpl_vector_get_size(spec_bgclean); i++)
324 if (pspec_bgclean[i] < 0) pspec_bgclean[i] = 0.0;
328 if (discard_le < 0 || discard_le >= npix) discard_le = ZEROPIX_LE;
329 if (discard_ri < 0 || discard_le + discard_ri >= npix) {
330 if (!strcmp(table_name,
"oh") && wl_max > THERMAL_START) {
336 discard_ri = ZEROPIX_RI;
342 spec_bgclean_log = cpl_vector_duplicate(spec_bgclean);
343 pspec_bgclean = cpl_vector_get_data(spec_bgclean);
344 pspec_bgclean_log = cpl_vector_get_data(spec_bgclean_log);
345 for (i=0; i<cpl_vector_get_size(spec_bgclean_log); i++)
346 pspec_bgclean_log[i] = pspec_bgclean[i] > 0.0 ?
347 log1p(pspec_bgclean[i]) : 0.0;
349 disprel = cpl_malloc(CALIB_COEFFS *
sizeof(
double));
352 irplib_line_spectrum_model model;
354 const double wfwhm = ISAAC_WFWHM;
355 const double slitw = slit_width;
356 const double xtrunc = 0.5 * slitw + 5.0 * wfwhm * CPL_MATH_SIG_FWHM;
359 cpl_vector * spec_short = cpl_vector_extract(spec_bgclean_log,
361 npix-discard_ri-1, 1);
363 const int short_size = cpl_vector_get_size(spec_short);
367 const int hshiftmax = ISAAC_MIN(short_size/4, max_offset);
371 = cpl_vector_wrap(cpl_bivector_get_size(spec_cat),
372 cpl_calloc(cpl_bivector_get_size(spec_cat),
375 = cpl_vector_wrap(1, cpl_calloc(1,
sizeof(
double)));
376 cpl_polynomial * phshift = cpl_polynomial_new(1);
377 cpl_error_code error = CPL_ERROR_NONE;
378 const int fitdeg = emil >= CALIB_COEFFS
379 ? CALIB_COEFFS-1 : emil-1;
380 double pixstep = 0.5;
381 double pixtol = 1e-5;
382 const int maxite = fitdeg * 200;
385 const unsigned clines
386 = (unsigned)(xtrunc*(short_size + 2 * hshiftmax));
387 const cpl_boolean doplot
388 = getenv(
"ISAAC_DOPLOT") ? CPL_TRUE : CPL_FALSE;
390 memset(&model, 0,
sizeof(model));
393 model.xtrunc = xtrunc;
394 model.lines = spec_cat;
395 model.linepix = linepix;
396 model.erftmp = erftmp;
400 for (i = 0; i < CALIB_COEFFS; i++) {
401 error |= cpl_polynomial_set_coeff(phshift, &i, phdisprel[i]);
403 error |= cpl_polynomial_shift_1d(phshift, 0, discard_le);
405 error |= irplib_polynomial_find_1d_from_correlation_all
406 (phshift, fitdeg, spec_short, 0, clines,
407 (irplib_base_spectrum_model*)&model,
408 irplib_vector_fill_logline_spectrum_fast, pixtol, pixstep,
409 hshiftmax, maxite, maxfail, maxcont, doplot, &xc);
411 error |= irplib_polynomial_find_1d_from_correlation_all
412 (phshift, fitdeg, spec_short, 1, clines,
413 (irplib_base_spectrum_model*)&model,
414 irplib_vector_fill_logline_spectrum, pixtol, pixstep,
415 hshiftmax, maxite, maxfail, maxcont, doplot, &xc);
417 cpl_vector_delete(spec_short);
418 cpl_vector_delete(linepix);
419 cpl_vector_delete(erftmp);
421 error |= cpl_polynomial_shift_1d(phshift, 0, -discard_le);
424 cpl_msg_info(cpl_func,
"XC: %g (cost=%u:%u. lines=%u)", xc,
425 (
unsigned)model.cost, (
unsigned)model.xcost,
426 (
unsigned)model.ulines);
428 for (i = 0; i < CALIB_COEFFS; i++) {
429 disprel[i] = cpl_polynomial_get_coeff(phshift, &i);
432 cpl_error_set_where(cpl_func);
433 for (i = 0; i < CALIB_COEFFS; i++) {
434 disprel[i] = phdisprel[i];
438 cpl_polynomial_delete(phshift);
442 if ((discard_le>0) || (discard_ri>0)) {
443 double wl_min_z = wl_min;
444 double wl_max_z = wl_max;
446 if (discard_le>0) wl_min_z = WAVELEN(phdisprel, discard_le+0.5);
447 if (discard_ri>0) wl_max_z = WAVELEN(phdisprel, npix-discard_ri+0.5);
449 emil_z = isaac_wavelength_count_lines(spec_cat, wl_min_z, wl_max_z);
451 cpl_msg_debug(cpl_func,
452 "Zeroed calibration signal [%g %g] has %d lines, dropped %d",
453 wl_min_z, wl_max_z, emil_z, emil-emil_z);
456 for (i=0; i<CALIB_COEFFS; i++)
457 cpl_msg_debug(cpl_func,
"Coef nb. %d correction rate: %g / %g = %g",
458 (
int)i+1, disprel[i], phdisprel[i], phdisprel[i] != 0 ?
459 disprel[i]/ phdisprel[i] : disprel[i]);
462 solution = spectro_refine_solution(spec_cat, spec_bgclean, discard_le+5,
463 discard_ri-5, npix, slit_width, disprel);
464 if (solution == NULL) {
466 cpl_bivector_delete(spec_cat);
467 cpl_vector_delete(spec_init);
468 cpl_vector_delete(spec_bgclean);
469 cpl_vector_delete(spec_bgclean_log);
477 out_file = fopen(
"collapsed_physical.txt",
"w");
478 for (i=0; i<npix; i++)
479 fprintf(out_file,
"%g\t%g\n", WAVELEN(phdisprel, i+1),
480 cpl_vector_get(spec_init, i));
484 out_file = fopen(
"collapsed_calibrated.txt",
"w");
485 for (i=0; i<npix; i++)
486 fprintf(out_file,
"%g\t%g\n", WAVELEN(disprel, i+1),
487 cpl_vector_get(spec_init, i));
491 out_file = fopen(
"collapsed_calibrated_filtered.txt",
"w");
492 for (i=0; i<npix; i++)
493 fprintf(out_file,
"%g\t%g\n", WAVELEN(disprel, i+1),
494 cpl_vector_get(spec_bgclean, i));
499 cpl_vector_delete(spec_init);
500 cpl_vector_delete(spec_bgclean);
501 cpl_vector_delete(spec_bgclean_log);
502 cpl_bivector_delete(spec_cat);
505 cpl_msg_debug(cpl_func,
"Computed poly. wave = f(pix) (pix in 1-%d):",npix);
506 cpl_msg_debug(cpl_func,
"f(x) = %g + %g * x + %g * x^2 + %g * x^3",
507 disprel[0], disprel[1], disprel[2], disprel[3]);
508 cpl_msg_debug(cpl_func,
"Spectral range [%g %g]",
509 WAVELEN(disprel,1), WAVELEN(disprel,npix));
512 solution->poly = disprel;
513 solution->degree = CALIB_COEFFS-1;
515 solution->offset = (disprel[0] - phdisprel[0]) /
516 WAVEDLT(disprel, 0.5 * (1 + npix));
517 solution->scal1 = disprel[1] / phdisprel[1];
518 solution->scal2 = disprel[2];
519 if (phdisprel[2] != 0) solution->scal2 /= phdisprel[2];
520 solution->scal3 = disprel[3];
521 if (phdisprel[3] != 0) solution->scal3 /= phdisprel[3];
535 int isaac_find_order(
const char * image_name)
539 cpl_propertylist * plist;
546 plist=cpl_propertylist_load(image_name, 0);
550 cpl_msg_error(cpl_func,
"cannot get resolution from [%s]", image_name);
551 cpl_propertylist_delete(plist);
554 strcpy(grat_name, sval);
557 if (cpl_error_get_code()) {
558 cpl_msg_error(cpl_func,
"cannot get central wlen from [%s]", image_name);
559 cpl_propertylist_delete(plist);
565 cpl_msg_error(cpl_func,
"cannot get filter from [%s]", image_name);
566 cpl_propertylist_delete(plist);
569 band = isaac_get_band(sval);
570 cpl_propertylist_delete(plist);
573 if (grat_name[0] ==
'M' && band == ISAAC_BAND_SH &&
574 27000 < wl_c && wl_c < 42000) order = 2;
576 if (grat_name[0] ==
'M' && band == ISAAC_BAND_JBLOCK &&
577 35500 < wl_c && wl_c < 42000) order = 3;
580 if (grat_name[0] ==
'M' && band == ISAAC_BAND_SK &&
581 44000 < wl_c && wl_c < 51000) order = 2;
583 if (grat_name[0] ==
'M' && band == ISAAC_BAND_SH &&
584 44000 < wl_c && wl_c < 51000) order = 3;
587 if (grat_name[0] ==
'M' && band == ISAAC_BAND_JBLOCK &&
588 44000 < wl_c && wl_c < 51000) order = 4;
594 if (grat_name[0] ==
'L' && band == ISAAC_BAND_SK &&
595 35500 < wl_c && wl_c < 42000) order = 2;
598 if (grat_name[0] ==
'L' && band == ISAAC_BAND_SH &&
599 35500 < wl_c && wl_c < 42000) order = 2;
602 if (grat_name[0] ==
'L' && band == ISAAC_BAND_JBLOCK &&
603 35500 < wl_c && wl_c < 42000) order = 3;
606 if (grat_name[0] ==
'L' && band == ISAAC_BAND_SH &&
607 44000 < wl_c && wl_c < 51000) order = 3;
609 cpl_msg_debug(cpl_func,
610 "Find order: %d. Resol: %c. Lambda_c: %g. Filter: %s",
611 order, grat_name[0], wl_c, isaac_get_filtername(band));
622 int isaac_has_thermal(
const char * im_name)
625 cpl_propertylist * plist;
632 plist=cpl_propertylist_load(im_name, 0);
636 cpl_msg_error(cpl_func,
"cannot get resolution from [%s]", im_name);
637 cpl_propertylist_delete(plist);
640 strcpy(grat_name, sval);
643 if (cpl_error_get_code()) {
644 cpl_msg_error(cpl_func,
"cannot get central wlen from [%s]", im_name);
645 cpl_propertylist_delete(plist);
651 cpl_msg_error(cpl_func,
"cannot get filter from [%s]", im_name);
652 cpl_propertylist_delete(plist);
655 band = isaac_get_band(sval);
656 cpl_propertylist_delete(plist);
660 if (grat_name[0] ==
'L' && band == ISAAC_BAND_SK &&
661 21900 <= wl_c) has_thermal = 1;
665 if (grat_name[0] ==
'L' && band == ISAAC_BAND_SL &&
666 34000 <= wl_c) has_thermal = 1;
671 if (grat_name[0] ==
'L' && band == ISAAC_BAND_SH &&
672 34000 <= wl_c && wl_c < 37000) has_thermal = 1;
676 if (grat_name[0] ==
'M' && band == ISAAC_BAND_SK &&
677 22500 <= wl_c) has_thermal = 1;
681 if (grat_name[0] ==
'M' && band == ISAAC_BAND_SL &&
682 30000 <= wl_c) has_thermal = 1;
685 if (grat_name[0] ==
'M' && band == ISAAC_BAND_SH &&
686 32000 <= wl_c) has_thermal = 1;
689 if (grat_name[0] ==
'M' && band == ISAAC_BAND_JBLOCK &&
690 34000 <= wl_c) has_thermal = 1;
692 cpl_msg_debug(cpl_func,
693 "Has thermal: %d. Resol: %c. Lambda_c: %g. Filter: %s",
694 has_thermal, grat_name[0], wl_c, isaac_get_filtername(band));
706 double isaac_get_slitwidth(
const char * filename)
711 cpl_propertylist * plist;
714 plist=cpl_propertylist_load(filename, 0);
718 cpl_msg_error(cpl_func,
"cannot get slit used");
719 cpl_propertylist_delete(plist);
724 if (!strcmp(sval,
"slit_1")) slit_width = 1;
725 else if (!strcmp(sval,
"slit_2")) slit_width = 2;
726 else if (!strcmp(sval,
"slit_0.3_tilted")) slit_width = 0.3;
727 else if (!strcmp(sval,
"slit_0.8")) slit_width = 0.8;
728 else if (!strcmp(sval,
"slit_1.5")) slit_width = 1.5;
729 else if (!strcmp(sval,
"slit_0.6_tilted")) slit_width = 0.6;
731 cpl_msg_error(cpl_func,
"unrecognized slit");
732 cpl_propertylist_delete(plist);
738 if (cpl_error_get_code()) {
739 cpl_msg_error(cpl_func,
"cannot get pixscale");
740 cpl_propertylist_delete(plist);
743 cpl_propertylist_delete(plist);
745 cpl_msg_debug(cpl_func,
"Slit width = %g arcsec (%-.2f pixels)\n",
746 slit_width, slit_width / pscale);
748 slit_width /= pscale;
766 static int isaac_wavelength_count_lines(
const cpl_bivector * lines,
770 const int cat_nlines = cpl_bivector_get_size(lines);
771 const double * px = cpl_bivector_get_x_data_const(lines);
772 const double * py = cpl_bivector_get_y_data_const(lines);
776 cpl_ensure(lines != NULL, CPL_ERROR_NULL_INPUT, -1);
778 while (i < cat_nlines && px[i] < wave_min) i++;
779 while (i < cat_nlines && px[i] < wave_max)
780 if (py[i++] > 0) nb_lines++;
794 static int isaac_wavelength_count_linez(
const cpl_bivector * lines,
798 const int cat_nlines = cpl_bivector_get_size(lines);
799 const double * px = cpl_bivector_get_x_data_const(lines);
803 cpl_ensure(lines != NULL, CPL_ERROR_NULL_INPUT, -1);
805 while (i < cat_nlines && px[i] < wave_min) i++;
806 while (i < cat_nlines && px[i++] < wave_max) nb_lines++;
821 static cpl_bivector * isaac_wavelength_load_catalog(
830 double * pcat_tab1_wave;
831 double * pcat_tab1_emiss;
833 cpl_table * cat_tab1;
834 cpl_table * cat_tab2;
835 cpl_propertylist * reflist;
839 if (name == NULL)
return NULL;
842 if (!strcmp(name,
"oh")) {
845 cpl_msg_error(cpl_func,
"Please provide the OH lines catalog");
849 if ((cat_tab1 = cpl_table_load(oh, 1, 0)) == NULL) {
850 cpl_msg_error(cpl_func,
"Cannot load the catalog");
853 }
else if (!strcmp(name,
"Xe")) {
856 cpl_msg_error(cpl_func,
"Please provide the XE lines catalog");
860 if ((cat_tab1 = cpl_table_load(xe, 1, 0)) == NULL) {
861 cpl_msg_error(cpl_func,
"Cannot load the XE catalog");
864 }
else if (!strcmp(name,
"Ar")) {
867 cpl_msg_error(cpl_func,
"Please provide the AR lines catalog");
871 if ((cat_tab1 = cpl_table_load(ar, 1, 0)) == NULL) {
872 cpl_msg_error(cpl_func,
"Cannot load the AR catalog");
875 }
else if (!strcmp(name,
"Xe+Ar")) {
878 cpl_msg_error(cpl_func,
"Please provide the XE lines catalog");
882 if ((cat_tab1 = cpl_table_load(xe, 1, 0)) == NULL) {
883 cpl_msg_error(cpl_func,
"Cannot load the XE catalog");
888 cpl_msg_error(cpl_func,
"Please provide the AR lines catalog");
892 if ((cat_tab2 = cpl_table_load(ar, 1, 0)) == NULL) {
893 cpl_msg_error(cpl_func,
"Cannot load the AR catalog");
894 cpl_table_delete(cat_tab1);
898 if (cpl_table_insert(cat_tab1, cat_tab2,
899 cpl_table_get_nrow(cat_tab1)) != CPL_ERROR_NONE) {
900 cpl_msg_error(cpl_func,
"Cannot merge tables");
901 cpl_table_delete(cat_tab1);
902 cpl_table_delete(cat_tab2);
905 cpl_table_delete(cat_tab2);
909 reflist = cpl_propertylist_new();
910 cpl_propertylist_append_bool(reflist, ISAAC_COL_WAVELENGTH, 0);
911 cpl_table_sort(cat_tab1, reflist);
912 cpl_propertylist_delete(reflist);
915 nlines = cpl_table_get_nrow(cat_tab1);
916 sig = cpl_bivector_new(nlines);
917 psigx = cpl_bivector_get_x_data(sig);
918 psigy = cpl_bivector_get_y_data(sig);
919 pcat_tab1_wave = cpl_table_get_data_double(cat_tab1, ISAAC_COL_WAVELENGTH);
920 pcat_tab1_emiss = cpl_table_get_data_double(cat_tab1, ISAAC_COL_EMISSION);
921 for (i=0; i<nlines; i++) {
922 psigx[i] = pcat_tab1_wave[i];
923 psigy[i] = pcat_tab1_emiss[i];
925 cpl_table_delete(cat_tab1);
936 static isaac_band isaac_get_band(
const char * filter)
938 if (filter == NULL)
return ISAAC_BAND_UNKNOWN;
939 if (!strcmp(filter,
"Z"))
return ISAAC_BAND_Z;
940 if (!strcmp(filter,
"SZ"))
return ISAAC_BAND_SZ;
941 if (!strcmp(filter,
"Js"))
return ISAAC_BAND_JS;
942 if (!strcmp(filter,
"J"))
return ISAAC_BAND_J;
943 if (!strcmp(filter,
"J+Block"))
return ISAAC_BAND_JBLOCK;
944 if (!strcmp(filter,
"SH"))
return ISAAC_BAND_SH;
945 if (!strcmp(filter,
"H"))
return ISAAC_BAND_H;
946 if (!strcmp(filter,
"Ks"))
return ISAAC_BAND_KS;
947 if (!strcmp(filter,
"SK"))
return ISAAC_BAND_SK;
948 if (!strcmp(filter,
"K"))
return ISAAC_BAND_K;
949 if (!strcmp(filter,
"SL"))
return ISAAC_BAND_SL;
950 if (!strcmp(filter,
"L"))
return ISAAC_BAND_L;
951 if (!strcmp(filter,
"M"))
return ISAAC_BAND_M;
952 return ISAAC_BAND_UNKNOWN;
962 static const char * isaac_get_filtername(isaac_band band)
964 if (band == ISAAC_BAND_UNKNOWN)
return NULL;
965 if (band == ISAAC_BAND_Z)
return "Z";
966 if (band == ISAAC_BAND_SZ)
return "SZ";
967 if (band == ISAAC_BAND_JS)
return "Js";
968 if (band == ISAAC_BAND_J)
return "J";
969 if (band == ISAAC_BAND_JBLOCK)
return "J+Block";
970 if (band == ISAAC_BAND_SH)
return "SH";
971 if (band == ISAAC_BAND_H)
return "H";
972 if (band == ISAAC_BAND_KS)
return "Ks";
973 if (band == ISAAC_BAND_SK)
return "SK";
974 if (band == ISAAC_BAND_K)
return "K";
975 if (band == ISAAC_BAND_SL)
return "SL";
976 if (band == ISAAC_BAND_L)
return "L";
977 if (band == ISAAC_BAND_M)
return "M";
1000 static double get_line_offset(
1001 const cpl_bivector * cat,
1002 const cpl_vector * spec,
1010 const double * disprel,
1015 const double * px = cpl_bivector_get_x_data_const(cat);
1016 const double * py = cpl_bivector_get_y_data_const(cat);
1017 const double wl = px[iline];
1019 const double spix = 1+ipix + isub;
1022 const double sigma = slit_width * SLITWIDTH_TO_SIGMA;
1024 const double centernoise = 1.25;
1025 const int mpix = pix_high-pix_low+1;
1026 const int maxdist = slit_width;
1027 const double * pspec = cpl_vector_get_data_const(spec);
1033 cpl_ensure(pmaxval != NULL, CPL_ERROR_NULL_INPUT, -1);
1036 if (sigma <= 0)
return -1;
1037 if (mpix <= 2)
return -1;
1039 if (ipix >= cpl_vector_get_size(spec)) {
1040 cpl_msg_error(cpl_func,
"IPIX(mpix=%d): %d <= ipix=%d <= %d <= %d",
1041 mpix, pix_low, ipix, pix_high,
1042 (
int)cpl_vector_get_size(spec));
1046 maxval = pspec[ipix];
1048 for (i=pix_low; i<=pix_high; i++)
1049 if (pspec[i] > maxval) maxval = pspec[maxpos = i];
1053 cpl_msg_debug(cpl_func,
"0LINE %d (%g) at pixel: %d <= %g <= %d",
1054 nline, wl, 1+pix_low, spix, 1+pix_high);
1059 while (imax+1 <= pix_high && (pspec[imax+1] < lastval || pspec[imax+1] ==0
1060 || (imax-maxpos < maxdist && pspec[imax+1] < centernoise * lastval)))
1061 lastval = pspec[++imax];
1066 while (imin-1 >= pix_low && (pspec[imin-1] < lastval || pspec[imin-1] == 0
1067 || (maxpos-imin < maxdist && pspec[imin-1] < centernoise * lastval)))
1068 lastval = pspec[--imin];
1070 offset = isaac_wavelength_centroid(spec, imin, imax);
1072 if (abs(maxpos - ipix) > maxdist ) {
1075 const int plow = maxpos > ipix ? pix_low : (maxpos + ipix)/2;
1076 const int phigh = maxpos < ipix ? pix_high : (maxpos + ipix)/2;
1078 cpl_msg_debug(cpl_func,
"LINE %d (%g) at pixel: %d <= %g/%d <= %d",
1079 nline, WAVELEN(disprel,1+maxpos), 1+pix_low, spix,
1080 1+maxpos, 1+pix_high);
1083 cpl_msg_debug(cpl_func,
"LIne %d (%g) at pixel: %d <= %g/%d/%g <= %d",
1084 nline, WAVELEN(disprel,1+offset+imin), 1+pix_low,
1085 spix, 1+maxpos, 1+offset+imin, 1+pix_high);
1088 return get_line_offset(cat, spec, plow, ipix, isub, phigh, iline,
1089 nline, slit_width, disprel, poffset, pmaxval);
1092 relint = 100*py[iline]/(sigma*sqrt(2*4*atan(1))*maxval);
1096 cpl_msg_debug(cpl_func,
"LINe %d (%g) at pixel: %d/%d <= %g/%d <= %d/%d "
1097 "(%4.2f%%)\n", nline, wl, 1+pix_low, 1+imin, spix, 1+maxpos,
1098 1+imax, 1+pix_high, relint);
1102 *poffset = offset + imin - ipix;
1104 cpl_msg_debug(cpl_func,
1105 "Line %d (%g) at pixel: %d/%d <= %g/%d/%g <= %d/%d (%4.2f%%) %g",
1106 nline, wl, 1+pix_low, 1+imin, spix, 1+maxpos, 1+offset + imin,
1107 1+imax, 1+pix_high, relint, *poffset);
1109 return fabs(*poffset);
1125 static double isaac_wavelength_centroid(
1126 const cpl_vector * vec,
1130 const double * pvec;
1131 int half_centroid_domain = 5;
1138 if (vec==NULL)
return -1.0;
1139 pvec = cpl_vector_get_data_const(vec);
1144 for (i=start; i<=stop; i++) {
1151 if (maxpos < start + half_centroid_domain ||
1152 maxpos >= stop + 1 - half_centroid_domain)
return -1.0;
1157 for (i=maxpos-half_centroid_domain; i<=maxpos+half_centroid_domain; i++)
1158 if (pvec[i] < min) min = pvec[i];
1164 for (i=maxpos-half_centroid_domain;i<=maxpos+half_centroid_domain;i++) {
1165 centroid += (double)(pvec[i]-min) * (double)i;
1166 weights += (double)(pvec[i]-min);
1169 for (i=maxpos-half_centroid_domain;i<=maxpos+half_centroid_domain;i++) {
1170 centroid += (double)(pvec[i]) * (double)i;
1171 weights += (double)(pvec[i]);
1175 if (fabs(weights)<fabs(centroid)*1e-5 ) centroid = -1.0;
1176 else centroid /= weights;
1178 return centroid - start;
1194 static computed_disprel * spectro_refine_solution(
1195 const cpl_bivector * cat,
1196 const cpl_vector * spec,
1201 const double * disprel)
1203 computed_disprel * solution;
1204 const int istart = discard_le > 0 ? discard_le : 0;
1205 const int istop = discard_ri > 0 ? npix-discard_ri : npix;
1207 const double wl_min = WAVELEN(disprel, 0 + 0.5);
1208 const double wl_max = WAVELEN(disprel, npix + 1.5);
1210 const int nlines = cpl_bivector_get_size(cat);
1211 const double * px = cpl_bivector_get_x_data_const(cat);
1212 const double * py = cpl_bivector_get_y_data_const(cat);
1215 double sum_offset = 0;
1216 double sum_aboffs = 0;
1217 double sum_sqoffs = 0;
1227 const int emil = isaac_wavelength_count_lines(cat, wl_min, wl_max);
1228 const int emilz = isaac_wavelength_count_linez(cat, wl_min, wl_max);
1234 if (emil < 1)
return NULL;
1236 solution = cpl_malloc(
sizeof(*solution));
1239 while (iline < nlines && px[iline] < wl_min) iline++;
1242 if (emilz * (11 + slit_width) > npix) {
1246 for (i=iline; i<nlines; i++) {
1247 if (px[i] > wl_max)
break;
1248 if (py[i] > maxint) maxint = py[i];
1252 cpl_msg_debug(cpl_func,
1253 "No detection of faint lines (I < %g) in crowded spectrum: %g",
1254 maxint * faint, npix/(emilz * slit_width));
1257 while (pix_high < npix - 1) {
1259 const double isub_prev = isub;
1260 const int icalprev = ical;
1261 const int pix_low = pix_high;
1266 while (iline<nlines && 0 < py[iline] &&
1267 (py[iline] < maxint * faint ||
1268 (py[iline] == py[iline-1] &&
1269 (px[iline] - px[iline-1])
1270 < 0.5*WAVEDLT(disprel, 1+icalprev)*slit_width))) {
1271 cpl_msg_debug(cpl_func,
"Skipping line(%d): %g %g", iline,
1272 px[iline], py[iline]);
1276 if (iline < nlines &&
1278 (wl = px[iline]) < wl_max) {
1279 double wl_low, wl_high;
1290 while (++ical < npix-1 && WAVELEN(disprel, ical+1 + 0.5) < wl);
1291 wl_low = WAVELEN(disprel, ical+1 - 0.5);
1292 wl_high = WAVELEN(disprel, ical+1 + 0.5);
1295 isub = (wl - wl_low) / (wl_high - wl_low) - 0.5;
1299 delta = (WAVELEN(disprel, ical+1+isub)-wl)
1300 / WAVEDIF(disprel, ical+1+isub);
1302 }
while (--i && fabs(delta) > DBL_EPSILON);
1304 pix_high = (ical + icalprev)/2;
1306 pix_high = npix - 1;
1310 if (get_line_offset(cat, spec, pix_low, icalprev, isub_prev,
1311 pix_high, iline-1, nline, slit_width,
1312 disprel, &offset, &maxval) >=0) {
1313 if (istart <= icalprev && icalprev <= istop) {
1315 sum_offset += offset;
1316 sum_aboffs += fabs(offset);
1317 sum_sqoffs += offset * offset;
1321 if (maxval == 0) nzero++;
1326 solution->dlines = nfound;
1327 solution->clines = emilz;
1329 solution->mean = -1;
1332 double stdev = nfound ==1 ? 0 :
1333 (sum_sqoffs-sum_offset*sum_offset/nfound)/(nfound-1);
1334 stdev = stdev > 0 ? sqrt(stdev) : 0;
1336 cpl_msg_debug(cpl_func,
1337 "Mean & RMS pixel-offset on calibration (%d:%d:%d:%d): %g %g",
1338 emilz, emilz-emil,nzero, nfound, sum_aboffs/nfound, stdev);
1341 solution->rms = stdev;
1343 solution->mean = sum_aboffs/nfound;
const char * isaac_pfits_get_opti1_id(const cpl_propertylist *plist)
find out the OPTI1.ID key
double isaac_pfits_get_pixscale(const cpl_propertylist *plist)
find out the pixel scale
double isaac_pfits_get_wlen(const cpl_propertylist *plist)
find out the central wavelength
const char * isaac_pfits_get_resolution(const cpl_propertylist *plist)
find out the resolution
const char * isaac_pfits_get_filter(const cpl_propertylist *plist)
find out the filter