36 #include "naco_recipe.h"
38 #include "irplib_distortion.h"
41 #include "irplib_wlxcorr.h"
45 #include "irplib_polynomial.h"
46 #include "irplib_wavecal.h"
47 #include "irplib_distortion.h"
56 #define RECIPE_STRING "naco_spc_wavecal"
62 static cpl_error_code naco_spc_wavecal_reduce(cpl_imagelist *,
66 const irplib_framelist *,
69 const cpl_parameterlist *);
71 static cpl_error_code naco_spc_wavecal_get_slitw(
const cpl_propertylist *,
75 static cpl_error_code naco_spc_wavecal_1d(cpl_imagelist *
self,
76 cpl_propertylist * qclist,
77 const cpl_image * spec2d,
78 const cpl_propertylist * plist,
80 const cpl_polynomial * phdisp,
81 const cpl_bivector * argonlines,
82 const cpl_parameterlist* parlist);
85 cpl_error_code naco_image_fill_column_from_dispersion(cpl_image *,
int, cpl_boolean,
86 const cpl_polynomial *);
88 static cpl_error_code naco_spc_wavecal_distortion(cpl_image *,
90 const cpl_parameterlist *);
92 static cpl_error_code naco_spc_physdisp_fill(cpl_polynomial *,
const char *,
95 static cpl_error_code naco_spc_physdisp_transform(cpl_polynomial *,
double,
96 double,
int,
double,
double,
99 static cpl_error_code naco_spc_wavecal_qc(cpl_propertylist *,
101 const irplib_framelist *);
103 static cpl_error_code naco_spc_wavecal_save(cpl_frameset *,
104 const cpl_parameterlist *,
105 const cpl_propertylist *,
106 const cpl_propertylist *,
107 const cpl_imagelist *,
108 const cpl_polynomial *,
109 int,
const irplib_framelist *);
111 static cpl_error_code naco_spc_wavecal_fill_table(cpl_table *,
112 const cpl_polynomial *);
114 static cpl_error_code naco_spc_wavecal_count_lines(cpl_propertylist *,
115 const cpl_bivector *,
118 cpl_error_code naco_spc_wavecal_interpolate_rejected(cpl_image *,
119 const cpl_polynomial *);
121 static cpl_error_code naco_spc_wavecal_qc_lines(cpl_propertylist *,
123 const cpl_apertures *);
125 NACO_RECIPE_DEFINE(naco_spc_wavecal,
126 NACO_PARAM_PLOT | NACO_PARAM_FORCE,
127 "Wavelength calibration using arc lamps",
129 " -- NACO spectrocopy wavelength calibration from "
131 "The files listed in the Set Of Frames (sof-file) "
133 "NACO-raw-file.fits " NACO_SPC_LAMPWAVE_RAW
"\n"
134 "NACO-spectrum-model.fits " NACO_SPC_MODEL
"\n"
135 "NACO-arc-lines.fits " NACO_SPC_ARGON
"\n"
137 NACO_SPC_MAN_MODESPLIT
"\n\n"
138 "Furthermore, each input frame must have a value of "
139 NACO_PFITS_BOOL_LAMP1
" that is false for off-frames and "
140 "true for on-frames.\n"
143 NACO_CALIB_ARC_MAP
": Primary HDU with the wavelength map, "
144 "i.e. the pixel values are wavelengths. The first extension "
145 "is a single-row table with the polynomial coefficients of "
146 "the 2D dispersion relation, lambda = P(x, y).\n"
147 NACO_CALIB_ARC_DIFF
": Primary HDU with the difference image "
148 "of the lamp-on and -off image. The first extension is the "
149 "distortion corrected image, were all the arc-lines are "
150 "straight. The dispersion in the distortion corrected image "
151 "is given by the central dispersion, lambda = P(512.5, y).");
172 static int naco_spc_wavecal(cpl_frameset * framelist,
173 const cpl_parameterlist * parlist)
175 cpl_errorstate cleanstate = cpl_errorstate_get();
176 irplib_framelist * allframes = NULL;
177 irplib_framelist * rawframes = NULL;
178 irplib_framelist * f_one = NULL;
179 const char ** taglist = NULL;
180 cpl_imagelist * lamp_wave = cpl_imagelist_new();
181 cpl_polynomial * disp2d = cpl_polynomial_new(2);
182 cpl_propertylist * qclist = cpl_propertylist_new();
183 cpl_propertylist * paflist = cpl_propertylist_new();
184 const cpl_frame * modelframe;
185 const char * modelfile;
186 cpl_table * modeltab = NULL;
187 const cpl_frame * argonframe;
188 const char * argonfile;
189 cpl_table * argontab = NULL;
190 cpl_bivector * argonlines= NULL;
191 cpl_vector * argonlinex= NULL;
192 cpl_vector * argonliney= NULL;
202 allframes = irplib_framelist_cast(framelist);
203 skip_if(allframes == NULL);
205 rawframes = irplib_framelist_extract(allframes, NACO_SPC_LAMPWAVE_RAW);
206 skip_if(rawframes == NULL);
208 irplib_framelist_empty(allframes);
211 modelframe = cpl_frameset_find_const(framelist, NACO_SPC_MODEL);
212 error_if (modelframe == NULL, CPL_ERROR_DATA_NOT_FOUND,
"No input frame "
213 "is tagged %s", NACO_SPC_MODEL);
215 modelfile = cpl_frame_get_filename(modelframe);
216 skip_if (modelfile == NULL);
218 modeltab = cpl_table_load(modelfile, 1, 0);
219 error_if (modeltab == NULL, cpl_error_get_code(),
"Could not "
220 "load the table with the model parameters");
223 argonframe = cpl_frameset_find_const(framelist, NACO_SPC_ARGON);
224 error_if (argonframe == NULL, CPL_ERROR_DATA_NOT_FOUND,
"No input frame "
225 "is tagged %s", NACO_SPC_ARGON);
227 argonfile = cpl_frame_get_filename(argonframe);
228 skip_if (argonfile == NULL);
230 argontab = cpl_table_load(argonfile, 1, 0);
231 error_if (argontab == NULL, cpl_error_get_code(),
"Could not "
232 "load the table with the argon lines");
235 nargonlines = cpl_table_get_nrow(argontab);
237 argonlinex = cpl_vector_wrap(nargonlines,
238 cpl_table_get_data_double(argontab,
240 skip_if(argonlinex == NULL);
242 argonliney = cpl_vector_wrap(nargonlines,
243 cpl_table_get_data_double(argontab,
244 NACO_SPC_LAB_INTENS));
245 skip_if(argonliney == NULL);
247 #ifdef NACO_SPC_WAVECAL_LOG
248 bug_if(cpl_vector_add_scalar(argonliney, 1.0));
249 skip_if(cpl_vector_logarithm(argonliney, exp(1.0)));
252 argonlines = cpl_bivector_wrap_vectors(argonlinex, argonliney);
253 bug_if(argonlines == NULL);
255 skip_if(irplib_framelist_load_propertylist_all(rawframes, 0,
"^("
256 NACO_PFITS_REGEXP_SPCWAVE
"|"
257 NACO_PFITS_REGEXP_SPCWAVE_PAF
261 skip_if(taglist == NULL);
263 cpl_msg_info(cpl_func,
"Identified %d setting(s) in %d frames",
264 nsets, irplib_framelist_get_size(rawframes));
267 for (i=0 ; i < nsets ; i++) {
269 cpl_error_code error;
272 cpl_msg_info(cpl_func,
"Reducing data set %d of %d", i+1, nsets);
275 f_one = irplib_framelist_extract(rawframes, taglist[i]);
277 bug_if (f_one == NULL);
279 n_one = irplib_framelist_get_size(f_one);
282 bug_if(irplib_framelist_set_tag_all(f_one, NACO_SPC_LAMPWAVE_RAW));
284 cpl_msg_info(cpl_func,
"Reducing frame set %d of %d (size=%d) with "
285 "setting: %s", i+1, nsets, n_one, taglist[i]);
287 error = naco_spc_wavecal_reduce(lamp_wave, disp2d, qclist, taglist[i],
288 f_one, modeltab, argonlines, parlist);
293 irplib_error_recover(cleanstate,
"Could not do the wavelength "
294 "calibration for this setting");
296 cpl_errorstate prestate = cpl_errorstate_get();
298 skip_if(naco_spc_wavecal_qc(qclist, paflist, f_one));
301 bug_if (cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,
302 NACO_CALIB_ARC_MAP));
306 (void)irplib_framelist_set(f_one, (cpl_frame*)modelframe, n_one);
307 (void)irplib_framelist_set(f_one, (cpl_frame*)argonframe, n_one+1);
308 (void)naco_spc_wavecal_save(framelist, parlist, qclist, paflist,
309 lamp_wave, disp2d, i+1, f_one);
310 (void)irplib_framelist_unset(f_one, n_one+1, NULL);
311 (void)irplib_framelist_unset(f_one, n_one, NULL);
312 skip_if(!cpl_errorstate_is_equal(prestate));
315 cpl_image_delete(cpl_imagelist_unset(lamp_wave, 0));
316 }
while (cpl_imagelist_get_size(lamp_wave) > 0);
320 cpl_propertylist_empty(qclist);
321 cpl_propertylist_empty(paflist);
322 irplib_framelist_delete(f_one);
326 irplib_ensure(nb_good > 0, CPL_ERROR_DATA_NOT_FOUND,
327 "None of the %d sets could be reduced", nsets);
332 cpl_imagelist_delete(lamp_wave);
333 cpl_table_delete(modeltab);
334 cpl_bivector_unwrap_vectors(argonlines);
335 (void)cpl_vector_unwrap(argonlinex);
336 (void)cpl_vector_unwrap(argonliney);
337 cpl_table_delete(argontab);
338 irplib_framelist_delete(f_one);
339 irplib_framelist_delete(allframes);
340 irplib_framelist_delete(rawframes);
341 cpl_propertylist_delete(qclist);
342 cpl_propertylist_delete(paflist);
343 cpl_polynomial_delete(disp2d);
345 return cpl_error_get_code();
362 static cpl_error_code naco_spc_wavecal_reduce(cpl_imagelist * imglist,
363 cpl_polynomial * disp2d,
364 cpl_propertylist * qclist,
366 const irplib_framelist * framelist,
367 const cpl_table * modeltab,
368 const cpl_bivector * argonlines,
369 const cpl_parameterlist * parlist)
371 cpl_image *
self = NULL;
372 cpl_image * corrected = NULL;
373 cpl_imagelist * difflist = cpl_imagelist_new();
374 cpl_polynomial * disp1d = NULL;
375 cpl_polynomial * collapse = cpl_polynomial_new(1);
378 const cpl_size deg0 = 0;
379 cpl_polynomial * phdisp = cpl_polynomial_new(1);
380 const cpl_propertylist * plist
381 = irplib_framelist_get_propertylist_const(framelist, 0);
382 const char * specmode
383 = irplib_pfits_get_string(plist, NACO_PFITS_STRING_SPECMODE);
385 = irplib_pfits_get_double(plist, NACO_PFITS_DOUBLE_CWLEN);
386 cpl_propertylist * lampkeys = cpl_propertylist_new();
387 cpl_stats * stats = NULL;
388 double adumin, adumax;
390 cpl_vector * center = cpl_vector_new(2);
394 bug_if (imglist == NULL);
395 bug_if (qclist == NULL);
396 bug_if (framelist == NULL);
397 bug_if (modeltab == NULL);
398 bug_if (argonlines == NULL);
399 bug_if (parlist == NULL);
400 bug_if (cpl_imagelist_get_size(imglist));
403 bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_BOOL_LAMP1, 1));
404 bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_INT_LAMP2, 0));
410 if (cpl_imagelist_get_size(difflist) > 1) {
411 cpl_msg_warning(cpl_func,
"Averaging %d difference images "
412 "into one image for setting %s",
413 (
int)cpl_imagelist_get_size(difflist), tag);
414 self = cpl_imagelist_collapse_create(difflist);
416 self = cpl_imagelist_unset(difflist, 0);
419 stats = cpl_stats_new_from_image(
self, CPL_STATS_MIN | CPL_STATS_MAX);
420 adumin = cpl_stats_get_min(stats);
421 adumax = cpl_stats_get_max(stats);
423 cpl_msg_info(cpl_func,
"Difference image for '%s' has ADUs in range: "
424 "%g -> %g", tag, adumin, adumax);
426 cpl_msg_info(cpl_func,
"Setting negative ADUs to zero");
427 bug_if(cpl_image_threshold(
self, 0.0, FLT_MAX, 0.0, FLT_MAX));
431 cpl_errorstate prestate = cpl_errorstate_get();
432 cpl_plot_image(
"",
"t 'Difference image'",
"",
self);
433 if (!cpl_errorstate_is_equal(prestate)) {
434 cpl_errorstate_set(prestate);
438 corrected = cpl_image_duplicate(
self);
439 skip_if(naco_spc_wavecal_distortion(corrected, qclist, parlist));
441 ny = cpl_image_get_size_y(
self);
445 skip_if(naco_spc_physdisp_fill(phdisp, specmode, modeltab));
447 cpl_msg_info(cpl_func,
"Wavelength range using physical model [micron]: "
449 cpl_polynomial_eval_1d(phdisp, 0.5, NULL),
450 cpl_polynomial_eval_1d(phdisp, 0.5 + ny, NULL));
454 const cpl_size idegree = 0;
456 = cpl_polynomial_eval_1d(phdisp, 0.5*(1+ny), NULL) - wlen;
458 = cpl_polynomial_get_coeff(phdisp, &idegree) - dwlen;
460 bug_if(cpl_polynomial_set_coeff(phdisp, &idegree, newval));
463 cpl_msg_info(cpl_func,
"Central Wavelength (model <=> CWLEN) [micron]: "
464 "%g <=> %g", cpl_polynomial_eval_1d(phdisp, 0.5*(1+ny), NULL),
468 skip_if(naco_spc_wavecal_1d(imglist, qclist,
self, plist, tag, phdisp,
469 argonlines, parlist));
471 skip_if(irplib_polynomial_fit_2d_dispersion(disp2d,
472 cpl_imagelist_get(imglist, 0),
475 cpl_msg_info(cpl_func,
"2D-dispersion with MSE=%g for setting %s", mse, tag);
476 skip_if(cpl_polynomial_dump(disp2d, stdout));
478 skip_if(naco_spc_wavecal_interpolate_rejected(cpl_imagelist_get(imglist, 0),
481 bug_if(cpl_vector_set(center, 0, 0.5*(1+cpl_image_get_size_x(
self))));
482 bug_if(cpl_vector_set(center, 1, 0.5*(1+cpl_image_get_size_y(
self))));
484 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC WLEN",
485 cpl_polynomial_eval(disp2d, center)));
488 bug_if(cpl_polynomial_set_coeff(collapse, °0,
489 0.5 * (1+cpl_image_get_size_x(
self))));
491 disp1d = cpl_polynomial_extract(disp2d, 0, collapse);
492 cpl_msg_info(cpl_func,
"Central 1D-dispersion (at x=%g)",
493 0.5*(1+cpl_image_get_size_x(
self)));
494 skip_if(cpl_polynomial_dump(disp1d, stdout));
498 if (cpl_error_get_code()) {
499 cpl_image_delete(
self);
500 cpl_image_delete(corrected);
502 cpl_imagelist_set(imglist,
self, 1);
503 cpl_imagelist_set(imglist, corrected, 2);
506 cpl_vector_delete(center);
507 cpl_propertylist_delete(lampkeys);
508 cpl_imagelist_delete(difflist);
509 cpl_stats_delete(stats);
510 cpl_polynomial_delete(phdisp);
511 cpl_polynomial_delete(disp1d);
512 cpl_polynomial_delete(collapse);
514 return cpl_error_get_code();
532 static cpl_error_code naco_spc_wavecal_1d(cpl_imagelist *
self,
533 cpl_propertylist * qclist,
534 const cpl_image * spec2d,
535 const cpl_propertylist * plist,
537 const cpl_polynomial * phdisp,
538 const cpl_bivector * argonlines,
539 const cpl_parameterlist* parlist)
542 cpl_errorstate prestate = cpl_errorstate_get();
543 const int nx = cpl_image_get_size_x(spec2d);
544 const int ny = cpl_image_get_size_y(spec2d);
545 cpl_vector * vspec1d = NULL;
546 cpl_polynomial * disp = NULL;
547 cpl_polynomial * dispcen = NULL;
548 cpl_polynomial * phshift = cpl_polynomial_duplicate(phdisp);
549 cpl_polynomial * dispdif = cpl_polynomial_new(1);
552 = cpl_vector_wrap(cpl_bivector_get_size(argonlines),
553 cpl_calloc(cpl_bivector_get_size(argonlines),
556 const double wfwhm = 4.0;
558 double xc, xcmean, xcstdev;
561 const int plotstep = nplot > 0 ? nx / (1<<nplot) : nx + 1;
562 const int degree = cpl_polynomial_get_degree(phdisp);
563 const int fitdeg = degree > 4 ? degree : 4;
564 cpl_image * imgdisp = cpl_image_new(nx, ny, cpl_image_get_type(spec2d));
565 cpl_vector * vxcall = cpl_vector_new(nx);
568 const int hshiftmax = ny/4;
569 irplib_line_spectrum_model model;
570 const double pixstep = 0.25;
571 const double pixtol = 1e-5;
572 const int istart = nx/2;
573 const int maxite = fitdeg * 100;
575 double wl2dmin = FLT_MAX;
576 double wl2dmax = 0.0;
577 cpl_boolean isfirst = CPL_TRUE;
580 bug_if(qclist == NULL);
581 bug_if(spec2d == NULL);
582 bug_if(plist == NULL);
583 bug_if(phdisp == NULL);
584 bug_if(argonlines == NULL);
587 skip_if(naco_spc_wavecal_get_slitw(plist, &slitw));
589 cpl_msg_info(cpl_func,
"Slitwidth [pixel]: %g", slitw);
591 xtrunc = 0.5 * slitw + 5.0 * wfwhm * CPL_MATH_SIG_FWHM;
593 memset(&model, 0,
sizeof(model));
596 model.xtrunc = xtrunc;
597 model.lines = argonlines;
598 model.linepix = linepix;
601 vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
602 #ifdef NACO_SPC_WAVECAL_LOG
603 bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
604 skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
608 char * title = cpl_sprintf(
"t 'Uncalibrated 1D-spectrum "
609 "using %s' w linespoints", tag);
610 cpl_vector * vphys = cpl_vector_new(ny);
611 cpl_bivector * bspec1d = cpl_bivector_wrap_vectors(vphys, vspec1d);
613 (void)cpl_vector_fill_polynomial(vphys, phdisp, 1.0, 1.0);
616 cpl_plot_bivector(
"set grid;set xlabel 'Wavelength [micron]';"
617 "set ylabel 'Intensity [ADU]';", title,
"",
620 cpl_vector_delete(vphys);
621 cpl_bivector_unwrap_vectors(bspec1d);
622 if (!cpl_errorstate_is_equal(prestate)) {
623 cpl_errorstate_set(prestate);
627 skip_if(irplib_polynomial_shift_1d_from_correlation(phshift, vspec1d,
629 irplib_vector_fill_line_spectrum,
630 hshiftmax, nplot > 0,
634 bug_if(irplib_plot_spectrum_and_model(vspec1d, phshift, (
void*)&model,
635 irplib_vector_fill_line_spectrum));
638 bug_if(cpl_polynomial_subtract(dispdif, phshift, phdisp));
640 cpl_msg_info(cpl_func,
"Changes to model polynomial by XC is of degree %d",
641 (
int)cpl_polynomial_get_degree(dispdif));
642 skip_if(cpl_polynomial_dump(dispdif, stdout));
644 disp = cpl_polynomial_duplicate(phshift);
646 dispcen = cpl_polynomial_duplicate(disp);
649 for (; ispec <= nx; ispec++) {
650 const cpl_size prevcost = model.cost;
653 cpl_vector_delete(vspec1d);
654 vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
655 #ifdef NACO_SPC_WAVECAL_LOG
656 bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
657 skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
662 if (irplib_polynomial_find_1d_from_correlation
663 (disp, fitdeg, vspec1d, (
void *)&model,
664 irplib_vector_fill_line_spectrum, pixtol, pixstep, 2, maxite,
666 irplib_error_recover(prestate,
"Could not calibrate column %d of "
668 cpl_polynomial_copy(disp, dispcen);
671 double wl2d = cpl_polynomial_eval_1d(disp, 0.5, NULL);
673 if (wl2d < wl2dmin) wl2dmin = wl2d;
675 wl2d = cpl_polynomial_eval_1d(disp, ny + 0.5, NULL);
676 if (wl2d > wl2dmax) wl2dmax = wl2d;
678 if (ispec % plotstep == 0) {
679 bug_if(irplib_plot_spectrum_and_model
682 irplib_vector_fill_line_spectrum));
684 #ifdef IRPLIB_SPC_DUMP
686 if (ispec == istart) {
687 irplib_polynomial_tabulate(disp, vspec1d, (
void *)&model,
688 irplib_vector_fill_line_spectrum,
694 bug_if(cpl_vector_set(vxcall, ispec-1, xc));
696 cpl_msg_info(cpl_func,
"XC(%d): %g (cost=%u of %u)", ispec, xc,
697 (
unsigned)(model.cost-prevcost), (
unsigned)model.cost);
699 bug_if(naco_image_fill_column_from_dispersion(imgdisp, ispec, xc <= 0.0,
704 const double cwl = cpl_polynomial_eval_1d(disp, 0.5*ny + 0.5,
708 cpl_msg_info(cpl_func,
"Center of setting %s has range %g -> %g "
709 "-> %g [um], center dispersion %g [nm/pixel] and "
710 "dispersion (of degree %d):", tag,
711 cpl_polynomial_eval_1d(disp, 0.5, NULL),
713 cpl_polynomial_eval_1d(disp, ny + 0.5, NULL),
715 (
int)cpl_polynomial_get_degree(disp));
716 skip_if(cpl_polynomial_dump(disp, stdout));
718 cpl_polynomial_copy(dispcen, disp);
720 bug_if(cpl_polynomial_subtract(dispdif, disp, phshift));
722 cpl_msg_info(cpl_func,
"Changes to model polynomial by search is of"
723 " degree %d", (
int)cpl_polynomial_get_degree(dispdif));
724 skip_if(cpl_polynomial_dump(dispdif, stdout));
726 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC DISP XCORR",
732 cpl_polynomial_copy(disp, dispcen);
734 for (ispec = istart-1; ispec > 0; ispec--) {
735 const cpl_size prevcost = model.cost;
737 cpl_vector_delete(vspec1d);
738 vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
739 #ifdef NACO_SPC_WAVECAL_LOG
740 bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
741 skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
745 if (irplib_polynomial_find_1d_from_correlation
746 (disp, fitdeg, vspec1d, (
void *)&model,
747 irplib_vector_fill_line_spectrum, pixtol, pixstep, 2, maxite, &xc)) {
748 if (ispec == 1 && wl2dmin >= wl2dmax) {
749 error_if (0, cpl_error_get_code(),
750 "None of the columns could be calibrated");
753 irplib_error_recover(prestate,
"Could not calibrate column %d of "
755 cpl_polynomial_copy(disp, dispcen);
757 double wl2d = cpl_polynomial_eval_1d(disp, 0.5, NULL);
759 if (wl2d < wl2dmin) wl2dmin = wl2d;
761 wl2d = cpl_polynomial_eval_1d(disp, ny + 0.5, NULL);
762 if (wl2d > wl2dmax) wl2dmax = wl2d;
764 if (ispec % plotstep == 0) {
765 bug_if(irplib_plot_spectrum_and_model
768 irplib_vector_fill_line_spectrum));
772 bug_if(cpl_vector_set(vxcall, ispec-1, xc));
774 cpl_msg_info(cpl_func,
"XC(%d): %g (cost=%u of %u)", ispec, xc,
775 (
unsigned)(model.cost-prevcost), (
unsigned)model.cost);
777 bug_if(naco_image_fill_column_from_dispersion(imgdisp, ispec, xc <= 0.0,
782 cpl_plot_vector(
"set grid;",
"t 'XC over spatial range' w linespoints",
786 xcmean = cpl_vector_get_mean(vxcall);
787 xcstdev = cpl_vector_get_stdev(vxcall);
789 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC DISP XCORR MEAN",
791 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC DISP XCORR STDEV",
794 cpl_msg_info(cpl_func,
"Cross-correlation mean and stdev for setting %s: %g "
795 "%g", tag, xcmean, xcstdev);
796 cpl_msg_info(cpl_func,
"Total fitting cost: %u", (
unsigned)model.cost);
798 skip_if(naco_spc_wavecal_count_lines(qclist, argonlines, wl2dmin, wl2dmax));
802 if (cpl_error_get_code()) {
803 cpl_image_delete(imgdisp);
805 cpl_imagelist_set(
self, imgdisp, 0);
808 cpl_vector_delete(linepix);
809 cpl_vector_delete(vxcall);
810 cpl_polynomial_delete(dispdif);
811 cpl_polynomial_delete(disp);
812 cpl_polynomial_delete(dispcen);
813 cpl_polynomial_delete(phshift);
814 cpl_vector_delete(vspec1d);
816 return cpl_error_get_code();
830 static cpl_error_code naco_spc_physdisp_fill(cpl_polynomial *
self,
832 const cpl_table * modeltab)
836 const int nrows = cpl_table_get_nrow(modeltab);
837 const char ** smode = cpl_table_get_data_string_const(modeltab,
840 bug_if(
self == NULL);
841 bug_if(mode == NULL);
842 bug_if(modeltab == NULL);
843 bug_if(cpl_polynomial_get_dimension(
self) != 1);
845 skip_if (smode == NULL);
847 for (imode = 0; imode < nrows; imode++) {
849 skip_if(smode[imode] == NULL);
851 if (!strcmp(mode, smode[imode]))
break;
854 error_if (imode == nrows, CPL_ERROR_UNSUPPORTED_MODE,
"Unsupported value "
855 "'%s' for " NACO_PFITS_STRING_SPECMODE, mode);
857 cpl_msg_info(cpl_func,
"Finding dispersion relation for spectrum mode "
858 "%d/%d: %s ", imode, nrows, mode);
860 skip_if(naco_spc_physdisp_transform
862 cpl_table_get_double(modeltab, NACO_SPC_LAB_XMIN, imode, NULL),
863 cpl_table_get_double(modeltab, NACO_SPC_LAB_XMAX, imode, NULL),
864 cpl_table_get_int (modeltab, NACO_SPC_LAB_ORDER, imode, NULL),
865 cpl_table_get_double(modeltab, NACO_SPC_LAB_C1, imode, NULL),
866 cpl_table_get_double(modeltab, NACO_SPC_LAB_C2, imode, NULL),
867 cpl_table_get_double(modeltab, NACO_SPC_LAB_C3, imode, NULL),
868 cpl_table_get_double(modeltab, NACO_SPC_LAB_C4, imode, NULL)));
870 #ifdef NACO_SPC_WAVECAL_S54_3_SH
871 if (!strcmp(
"S54_3_SH", mode)) {
873 double p1 = 0.000165591;
874 double p2 = 2.86676e-07;
877 bug_if(cpl_polynomial_set_coeff(
self, °ree, p0));
879 bug_if(cpl_polynomial_set_coeff(
self, °ree, p1));
881 bug_if(cpl_polynomial_set_coeff(
self, °ree, p2));
883 bug_if(cpl_polynomial_set_coeff(
self, °ree, 0.0));
885 bug_if(cpl_polynomial_set_coeff(
self, °ree, 0.0));
887 cpl_msg_warning(cpl_func,
"Changing phdisp to simple fit:");
888 skip_if(cpl_polynomial_dump(
self, stdout));
894 return cpl_error_get_code();
914 static cpl_error_code naco_spc_physdisp_transform(cpl_polynomial *
self,
915 double xmin,
double xmax,
917 double c1,
double c2,
918 double c3,
double c4)
921 const double alpha = 2.0/(xmax - xmin);
922 const double beta = -(xmax + xmin) / (xmax - xmin);
924 double lambdamin1, lambdamax1;
925 double lambdamin2, lambdamax2;
928 bug_if(
self == NULL);
929 bug_if(cpl_polynomial_get_dimension(
self) != 1);
932 skip_if(xmin >= xmax);
934 value = 1e-4 * (c1 - 0.5 * c3);
936 bug_if(cpl_polynomial_set_coeff(
self, °ree, value));
938 value = 1e-4 * (c2 - 1.5 * c4);
940 bug_if(cpl_polynomial_set_coeff(
self, °ree, value));
943 value = 1e-4 * 1.5 * c3;
945 bug_if(cpl_polynomial_set_coeff(
self, °ree, value));
948 value = 1e-4 * 2.5 * c4;
950 bug_if(cpl_polynomial_set_coeff(
self, °ree, value));
952 skip_if(fit_order > 4);
955 skip_if(fit_order < 2);
959 lambdamin1 = cpl_polynomial_eval_1d(
self, -1.0, NULL);
960 lambdamax1 = cpl_polynomial_eval_1d(
self, 1.0, NULL);
967 bug_if(cpl_polynomial_shift_1d(
self, 0, beta));
970 value = cpl_polynomial_get_coeff(
self, °ree) * alpha;
971 bug_if(cpl_polynomial_set_coeff(
self, °ree, value));
975 value = cpl_polynomial_get_coeff(
self, °ree) * alpha * alpha;
976 bug_if(cpl_polynomial_set_coeff(
self, °ree, value));
980 value = cpl_polynomial_get_coeff(
self, °ree) * alpha * alpha
982 bug_if(cpl_polynomial_set_coeff(
self, °ree, value));
986 lambdamin2 = cpl_polynomial_eval_1d(
self, xmin, NULL);
987 lambdamax2 = cpl_polynomial_eval_1d(
self, xmax, NULL);
989 skip_if(cpl_polynomial_get_degree(
self) != fit_order - 1);
991 skip_if(cpl_polynomial_dump(
self, stdout));
993 cpl_msg_debug(cpl_func,
"Interpolation minimum=%g: %g (%g)", xmin,
994 lambdamin1, lambdamin2-lambdamin1);
995 cpl_msg_debug(cpl_func,
"Interpolation maximum=%g: %g (%g)", xmax,
996 lambdamax1, lambdamax2-lambdamax1);
1000 return cpl_error_get_code();
1015 static cpl_error_code naco_spc_wavecal_get_slitw(
const cpl_propertylist *
self,
1018 const char * sslitw;
1024 bug_if(
self == NULL);
1025 bug_if(pslitw == NULL);
1027 sslitw = irplib_pfits_get_string(
self, NACO_PFITS_STRING_SLITNAME);
1028 skip_if(sslitw == NULL);
1030 nvals = sscanf(sslitw,
"Slit_%u", &uslitw);
1032 error_if(nvals != 1, CPL_ERROR_UNSUPPORTED_MODE,
"Unsupported value of '"
1033 NACO_PFITS_STRING_SLITNAME
": %s", sslitw);
1035 pixscale = irplib_pfits_get_double(
self, NACO_PFITS_DOUBLE_PIXSCALE);
1037 error_if(pixscale <= 0.0, CPL_ERROR_ILLEGAL_INPUT,
"Non-positive value of '"
1038 NACO_PFITS_DOUBLE_PIXSCALE
": %g", pixscale);
1040 *pslitw = (double)uslitw/(1000.0*pixscale);
1044 return cpl_error_get_code();
1059 static cpl_error_code
1060 naco_image_fill_column_from_dispersion(cpl_image *
self,
1061 int ispec, cpl_boolean is_bad,
1062 const cpl_polynomial * disp)
1065 const int ny = cpl_image_get_size_y(
self);
1068 bug_if(
self == NULL);
1069 bug_if(disp == NULL);
1070 bug_if(cpl_polynomial_get_dimension(disp) != 1);
1071 bug_if(cpl_polynomial_get_degree(disp) < 1);
1073 for (i = 1; i <= ny; i++) {
1074 const double value = cpl_polynomial_eval_1d(disp, (
double)i, NULL);
1075 cpl_image_set(
self, ispec, i, value);
1076 if (is_bad) cpl_image_reject(
self, ispec, i);
1081 return cpl_error_get_code();
1096 cpl_error_code naco_spc_wavecal_distortion(cpl_image *
self,
1097 cpl_propertylist * qclist,
1098 const cpl_parameterlist * parlist)
1101 const int fitdeg = 2;
1102 cpl_image * copy = NULL;
1103 const int nx = cpl_image_get_size_x(
self);
1104 const int ny = cpl_image_get_size_y(
self);
1105 cpl_apertures * lines = NULL;
1106 cpl_polynomial* distortion = NULL;
1107 cpl_polynomial* yid2d = cpl_polynomial_new(2);
1108 cpl_vector * profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
1109 cpl_size power[] = {0, 1};
1112 cpl_polynomial* center = cpl_polynomial_new(1);
1113 cpl_polynomial* dist1d = NULL;
1114 cpl_vector * dist1dfix = NULL;
1115 const cpl_size i0 = 0;
1116 const cpl_size i1 = 1;
1117 const double xcent = 0.5*(nx + 1);
1118 const double ycent = 0.5*(ny + 1);
1121 bug_if(
self == NULL);
1122 bug_if(qclist == NULL);
1123 bug_if(parlist == NULL);
1127 bug_if(cpl_image_turn(
self, 1));
1129 distortion = irplib_distortion_estimate(
self, 1, 1, nx, ny,
1132 0.33, fitdeg, &lines);
1134 error_if(distortion == NULL, cpl_error_get_code(),
"Curvature estimation "
1137 if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
1138 skip_if(cpl_polynomial_dump(distortion, stdout));
1139 cpl_apertures_dump(lines, stdout);
1142 skip_if(naco_spc_wavecal_qc_lines(qclist,
self, lines));
1145 bug_if(cpl_polynomial_set_coeff(yid2d, power, 1.0));
1148 bug_if(cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
1149 CPL_KERNEL_DEF_WIDTH));
1152 copy = cpl_image_duplicate(
self);
1153 error_if (cpl_image_warp_polynomial(
self, copy, distortion, yid2d, profile,
1154 CPL_KERNEL_DEF_WIDTH, profile,
1155 CPL_KERNEL_DEF_WIDTH),
1156 cpl_error_get_code(),
"Distortion correction failed");
1159 bug_if(cpl_image_turn(
self, -1));
1162 cpl_errorstate prestate = cpl_errorstate_get();
1163 cpl_plot_image(
"",
"t 'Distortion corrected image'",
"",
self);
1164 if (!cpl_errorstate_is_equal(prestate)) {
1165 cpl_errorstate_set(prestate);
1169 (void)cpl_image_turn(copy, -1);
1171 (void)cpl_image_subtract(copy,
self);
1173 cpl_plot_image(
"",
"t 'Distortion correction'",
"", copy);
1174 if (!cpl_errorstate_is_equal(prestate)) {
1175 cpl_errorstate_set(prestate);
1180 skip_if(cpl_polynomial_dump(distortion, stdout));
1183 bug_if(cpl_polynomial_set_coeff(center, &i0, xcent));
1185 dist1d = cpl_polynomial_extract(distortion, 1, center);
1188 bug_if(cpl_polynomial_set_coeff(center, &i1, 1.0));
1189 bug_if(cpl_polynomial_set_coeff(center, &i0, 0.0));
1192 bug_if(cpl_polynomial_subtract(center, dist1d, center));
1194 if (cpl_polynomial_get_degree(center) > 0) {
1195 const cpl_size ndist1d = cpl_polynomial_get_degree(dist1d);
1196 cpl_size dist1dnreal;
1198 cpl_msg_info(cpl_func,
"On the center column (x=%g) the distortion poly"
1199 "nomial should be P(y)=y, its deviation from that has deg"
1200 "ree %d:", xcent, (
int)cpl_polynomial_get_degree(center));
1201 skip_if(cpl_polynomial_dump(center, stdout));
1204 cpl_errorstate prestate = cpl_errorstate_get();
1205 dist1dfix = cpl_vector_new(ndist1d);
1206 if (irplib_polynomial_solve_1d_all(dist1d, dist1dfix,
1209 irplib_error_recover(prestate,
"Could not compute fix-points for "
1210 "%d-degree polynomial", (
int)ndist1d);
1216 if (dist1dnreal > 0) {
1217 cpl_vector * dist1dfixreal = dist1dnreal == ndist1d ? dist1dfix
1218 : cpl_vector_wrap(dist1dnreal, cpl_vector_get_data(dist1dfix));
1219 cpl_msg_info(cpl_func,
"The distortion correction has %d fix-"
1220 "point(s) on the center column:", (
int)dist1dnreal);
1221 cpl_vector_dump(dist1dfixreal, stdout);
1222 if (dist1dfixreal != dist1dfix)
1223 (void)cpl_vector_unwrap(dist1dfixreal);
1224 }
else if (cpl_polynomial_get_coeff(dist1d, &i0) != 0.0) {
1226 cpl_msg_info(cpl_func,
"The distortion correction has "
1227 "no fix-points on the center column");
1230 cpl_msg_info(cpl_func,
"The distortion correction has "
1231 "no fix-points on the center column");
1234 cpl_msg_info(cpl_func,
"The distortion correction moves the detector "
1235 "center at (%g,%g) by (%g,%g)", xcent, ycent, 0.0,
1236 cpl_polynomial_eval_1d(dist1d, ycent, NULL)-ycent);
1237 }
else if (cpl_polynomial_get_coeff(center, &i0) != 0.0) {
1238 cpl_msg_info(cpl_func,
"The distortion correction has no fix-points "
1239 "on the center column, their Y-offset are [pixel]: %g",
1240 cpl_polynomial_get_coeff(center, &i0));
1242 cpl_msg_info(cpl_func,
"The distortion correction has all points "
1243 "on the center column (at x=%g) as fix-points", xcent);
1247 power[0] = power[1] = 0;
1248 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC DIST1",
1249 cpl_polynomial_get_coeff(distortion,
1252 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC DISTY",
1253 cpl_polynomial_get_coeff(distortion,
1256 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC DISTYY",
1257 cpl_polynomial_get_coeff(distortion,
1260 power[0] = power[1] = 1;
1261 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC DISTXY",
1262 cpl_polynomial_get_coeff(distortion,
1265 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC DISTX",
1266 cpl_polynomial_get_coeff(distortion,
1269 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC DISTXX",
1270 cpl_polynomial_get_coeff(distortion,
1277 cpl_image_delete(copy);
1278 cpl_apertures_delete(lines);
1279 cpl_vector_delete(profile);
1280 cpl_vector_delete(dist1dfix);
1281 cpl_polynomial_delete(distortion);
1282 cpl_polynomial_delete(yid2d);
1283 cpl_polynomial_delete(center);
1284 cpl_polynomial_delete(dist1d);
1286 return cpl_error_get_code();
1298 static cpl_error_code naco_spc_wavecal_qc(cpl_propertylist * qclist,
1299 cpl_propertylist * paflist,
1300 const irplib_framelist * rawframes)
1303 const cpl_propertylist * reflist
1304 = irplib_framelist_get_propertylist_const(rawframes, 0);
1305 const char pafcopy[] =
"^(" NACO_PFITS_REGEXP_SPCWAVE_PAF
")$";
1312 skip_if (cpl_propertylist_copy_property_regexp(paflist, reflist, pafcopy,
1314 skip_if (cpl_propertylist_append(paflist, qclist));
1316 bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist,
"^("
1317 IRPLIB_PFITS_REGEXP_RECAL_LAMP
1321 return cpl_error_get_code();
1337 static cpl_error_code naco_spc_wavecal_fill_table(cpl_table *
self,
1338 const cpl_polynomial * disp2d)
1341 const int degree = cpl_polynomial_get_degree(disp2d);
1342 const char * lunit =
"micron";
1345 bug_if (
self == NULL);
1346 bug_if (cpl_polynomial_get_dimension(disp2d) != 2);
1347 bug_if (degree < 1);
1349 bug_if(cpl_table_set_size(
self, 1));
1351 for (i=0; i <= degree; i++) {
1352 for (j = 0; j <= i; j++) {
1353 const cpl_size powers[2] = {i-j, j};
1354 const double value = cpl_polynomial_get_coeff(disp2d, powers);
1355 char * label = cpl_sprintf(
"DISP2D_%d_%d", i-j, j);
1356 char * unit = i > 1 ? cpl_sprintf(
"%s/pixel^%d", lunit, i)
1357 : cpl_sprintf(i ?
"%s/pixel" :
"%s", lunit);
1359 cpl_table_new_column(
self, label, CPL_TYPE_DOUBLE);
1360 cpl_table_set_column_unit(
self, label, unit);
1361 cpl_table_set_double(
self, label, 0, value);
1371 return cpl_error_get_code();
1388 static cpl_error_code naco_spc_wavecal_save(cpl_frameset * set_tot,
1389 const cpl_parameterlist * parlist,
1390 const cpl_propertylist * qclist,
1391 const cpl_propertylist * paflist,
1392 const cpl_imagelist * lamp_wave,
1393 const cpl_polynomial * disp2d,
1395 const irplib_framelist * rawframes)
1397 cpl_frameset * proframes = irplib_frameset_cast(rawframes);
1398 cpl_table * table2d = cpl_table_new(1);
1399 char * filename = NULL;
1400 cpl_propertylist * xtlist = cpl_propertylist_new();
1402 bug_if(cpl_propertylist_append_string(xtlist,
"EXTNAME",
1403 "Wavelength calibration"));
1406 filename = cpl_sprintf(RECIPE_STRING
"_set%02d" CPL_DFS_FITS, set_nb);
1407 skip_if (irplib_dfs_save_image(set_tot, parlist, proframes,
1408 cpl_imagelist_get_const(lamp_wave, 0),
1409 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
1410 NACO_CALIB_ARC_MAP, qclist, NULL,
1411 naco_pipe_id, filename));
1413 bug_if(naco_spc_wavecal_fill_table(table2d, disp2d));
1415 skip_if(cpl_table_save(table2d, NULL, xtlist, filename, CPL_IO_EXTEND));
1419 filename = cpl_sprintf(RECIPE_STRING
"_set%02d_diff" CPL_DFS_FITS, set_nb);
1420 skip_if (irplib_dfs_save_image(set_tot, parlist, proframes,
1421 cpl_imagelist_get_const(lamp_wave, 1),
1422 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
1423 NACO_CALIB_ARC_DIFF, qclist, NULL,
1424 naco_pipe_id, filename));
1426 bug_if(cpl_propertylist_set_string(xtlist,
"EXTNAME",
1427 "Difference Image"));
1428 skip_if (cpl_image_save(cpl_imagelist_get_const(lamp_wave, 2), filename,
1429 CPL_BPP_IEEE_FLOAT, xtlist, CPL_IO_EXTEND));
1431 #ifdef NACO_SAVE_PAF
1433 filename = cpl_sprintf(RECIPE_STRING
"_set%02d" CPL_DFS_PAF, set_nb);
1434 skip_if (cpl_dfs_save_paf(
"NACO", RECIPE_STRING, paflist, filename));
1436 bug_if(paflist == NULL);
1441 cpl_table_delete(table2d);
1443 cpl_frameset_delete(proframes);
1444 cpl_propertylist_delete(xtlist);
1446 return cpl_error_get_code();
1461 static cpl_error_code naco_spc_wavecal_count_lines(cpl_propertylist *
self,
1462 const cpl_bivector * lines,
1467 const cpl_vector * xlines = cpl_bivector_get_x_const(lines);
1468 const double * dxlines = cpl_vector_get_data_const(xlines);
1469 int minline, maxline;
1473 bug_if (
self == NULL);
1474 bug_if (lines == NULL);
1476 bug_if (wlmin < 0.0);
1477 bug_if (wlmax < wlmin);
1480 minline = cpl_vector_find(xlines, wlmin);
1483 if (dxlines[minline] < wlmin) minline++;
1486 maxline = cpl_vector_find(xlines, wlmax);
1489 if (dxlines[maxline] > wlmax) maxline--;
1491 clines = maxline >= minline ? maxline - minline : 0;
1493 bug_if(cpl_propertylist_append_int(
self,
"ESO QC DISP NUMCAT", clines));
1497 return cpl_error_get_code();
1509 static cpl_error_code
1510 naco_spc_wavecal_interpolate_rejected(cpl_image *
self,
1511 const cpl_polynomial * disp2d)
1514 const int nz = cpl_image_count_rejected(
self);
1515 const int nx = cpl_image_get_size_x(
self);
1516 const int ny = cpl_image_get_size_y(
self);
1518 cpl_vector * vpower = cpl_vector_wrap(2, power);
1522 bug_if(
self == NULL);
1523 bug_if(disp2d == NULL);
1525 if (nz > 0) cpl_msg_info(cpl_func,
"Interpolating %d poorly calibrated "
1526 "pixels in the wavelength map", nz);
1528 for (i = 1; i <= nx && k > 0; i++) {
1529 for (j = 1; j <= ny && k > 0; j++) {
1530 if (cpl_image_is_rejected(
self, i, j)) {
1531 power[0] = (double)i;
1532 power[1] = (double)j;
1533 cpl_image_set(
self, i, j, cpl_polynomial_eval(disp2d, vpower));
1534 cpl_image_reject(
self, i, j);
1542 cpl_vector_unwrap(vpower);
1544 return cpl_error_get_code();
1558 static cpl_error_code naco_spc_wavecal_qc_lines(cpl_propertylist *
self,
1559 const cpl_image * spec2d,
1560 const cpl_apertures * lines)
1563 const int nlines = cpl_apertures_get_size(lines);
1564 const int ny = cpl_image_get_size_y(spec2d);
1565 const double ycen = 0.5 * (ny + 1);
1567 char * label = NULL;
1568 cpl_vector * vmedian = cpl_vector_new(nlines);
1571 bug_if(
self == NULL);
1572 bug_if(spec2d == NULL);
1573 bug_if(lines == NULL);
1575 bug_if(cpl_propertylist_append_int(
self,
"ESO QC ARCS NUM", nlines));
1578 for(i = 1; i <= nlines; i++) {
1579 cpl_errorstate prestate = cpl_errorstate_get();
1580 const double flux = cpl_apertures_get_flux(lines, i);
1581 const double xcen = cpl_apertures_get_centroid_x(lines, i);
1582 double fwhm_x, fwhm_y;
1584 if (cpl_image_get_fwhm(spec2d, xcen, ycen, &fwhm_x, &fwhm_y)) {
1585 irplib_error_recover(prestate,
"Could not compute the FWHM for "
1586 "aperture %d of %d (with xcentroid=%g, flux=%g",
1587 i, nlines, xcen, flux);
1592 cpl_vector_set(vmedian, igood++, fwhm_x);
1596 label = cpl_sprintf(
"ESO QC ARCS%d XPOS", i);
1597 cpl_propertylist_append_double(
self, label, xcen);
1600 label = cpl_sprintf(
"ESO QC ARCS%d FWHM", i);
1602 cpl_propertylist_append_double(
self, label, fwhm_x);
1605 label = cpl_sprintf(
"ESO QC ARCS%d FLUX", i);
1607 cpl_propertylist_append_double(
self, label, flux);
1611 bug_if(cpl_propertylist_append_int(
self,
"ESO QC ARCS NUMGOOD", igood));
1614 bug_if(cpl_vector_set_size(vmedian, igood));
1615 median = cpl_vector_get_median(vmedian);
1620 bug_if(cpl_propertylist_append_double(
self,
"ESO QC FWHM MED", median));
1624 cpl_vector_delete(vmedian);
1627 return cpl_error_get_code();
int naco_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
int naco_parameterlist_get_int(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO integer parameter.
cpl_boolean naco_parameterlist_get_bool(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO boolean parameter.
char * naco_spc_make_tag(const cpl_frame *self, const cpl_propertylist *plist, int dummy)
Create a string suitable for frame comparison in spectroscopy.
cpl_error_code naco_imagelist_load_diff(cpl_imagelist *self, const irplib_framelist *onofflist, const cpl_propertylist *onoffkeys)
Fill the list of difference images from on/off frames.
const char ** naco_framelist_set_tag(irplib_framelist *self, char *(*pftag)(const cpl_frame *, const cpl_propertylist *, int), int *pntags)
Retag a framelist according to the given tagging function.