40#include "irplib_plugin.h"
41#include "irplib_utils.h"
42#include "irplib_spectrum.h"
44#include "sofi_utils.h"
45#include "sofi_wavelength.h"
46#include "sofi_pfits.h"
53#define RECIPE_STRING "sofi_spc_jitter"
55#define SOFI_SPC_JITTER_OFFSET_ERR 10
61static cpl_image ** sofi_spc_jitter_combine(cpl_frameset *,
const char *,
62 const char *,
const char *);
63static cpl_vector * sofi_spc_jitter_get_offsets(cpl_frameset *);
64static int * sofi_spc_jitter_classif(cpl_vector *,
int *);
65static int off_comp(
double,
double,
double);
66static cpl_imagelist * sofi_spc_jitter_saa_groups(cpl_imagelist *,
67 cpl_vector *,
int *,
int, cpl_vector **);
68static int sofi_spc_jitter_wavecal(
const char *,
const char *, cpl_image *,
70static cpl_imagelist * sofi_spc_jitter_nodded(cpl_imagelist *, cpl_vector *,
72static cpl_imagelist * sofi_spc_jitter_distor(cpl_imagelist *,
const char *);
73static double sofi_spc_jitter_refine_offset(cpl_image *, cpl_image *);
74static cpl_table * sofi_spc_jitter_extract(cpl_image *);
75static cpl_error_code sofi_spc_jitter_save(cpl_frameset *,
const cpl_image *,
77 const cpl_parameterlist *);
79cpl_recipe_define(sofi_spc_jitter, SOFI_BINARY_VERSION,
80 "Lars Lundin", PACKAGE_BUGREPORT,
"2002,2003,2009",
81 "SOFI Spectro jitter recipe",
82 RECIPE_STRING
" -- SOFI Spectro jitter recipe"
83 "The files listed in the Set Of Frames (sof-file) "
85 "raw-file.fits "SOFI_SPC_JITTER_NODOBJ_RAW
" or\n"
86 "raw-file.fits "SOFI_SPC_JITTER_NODSKY_RAW
"\n"
87 "Calibration files:\n"
88 "oh-cat.fits "SOFI_CALPRO_OH_CAT
" or\n"
89 "flat-file.fits "SOFI_CALIB_SPFLAT
" or\n"
90 "arc-file.fits "SOFI_CALIB_ARC
"\n");
104 int wavecal_nsamples;
111 int extr_sky_le_width;
112 int extr_sky_ri_width;
113 int extr_sky_le_dist;
114 int extr_sky_ri_dist;
118 cpl_vector * intensities;
127} sofi_spc_jitter_config;
144cpl_error_code sofi_spc_jitter_fill_parameterlist(cpl_parameterlist * self)
146 const char * context = PACKAGE
"." RECIPE_STRING;
149 cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
155 err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
156 "crosstalk", CPL_TRUE, NULL, context,
157 "Enable removal of the crosstalk "
159 cpl_ensure_code(!err, err);
162 err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
163 "wavecal",
"sky", NULL, context,
164 "Wavelength method: "
165 "phy or sky or arc");
166 cpl_ensure_code(!err, err);
169 err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
170 "wavecal_ppm", CPL_FALSE, NULL, context,
171 "Enable Point Pattern Matching in the "
172 "wavelength calibration");
173 cpl_ensure_code(!err, err);
176 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
177 "wavecal_degree", 2, NULL, context,
178 "Degree of the wavelength dispersion "
180 cpl_ensure_code(!err, err);
183 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
184 "wavecal_nsamples", 100, NULL, context,
185 "Number of samples for the wavelength "
187 cpl_ensure_code(!err, err);
190 err = irplib_parameterlist_set_double(self, PACKAGE, RECIPE_STRING,
191 "wavecal_err", 1000.0, NULL, context,
192 "The wavelength error [Angstrom]");
193 cpl_ensure_code(!err, err);
196 err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
197 "saa_refine", CPL_TRUE, NULL, context,
198 "Enable refinement of the offsets");
199 cpl_ensure_code(!err, err);
202 err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
203 "saa_rej",
"0.1,0.1", NULL, context,
204 "Low, high SAA rejection [%,%]");
205 cpl_ensure_code(!err, err);
208 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
209 "spec_pos", -1, NULL, context,
210 "Spectrum position");
211 cpl_ensure_code(!err, err);
214 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
215 "spec_width", 10, NULL, context,
217 cpl_ensure_code(!err, err);
220 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
221 "sky_le_width", 10, NULL, context,
222 "Sky width left of the spectrum");
223 cpl_ensure_code(!err, err);
226 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
227 "sky_ri_width", 10, NULL, context,
228 "Sky width right of the spectrum");
229 cpl_ensure_code(!err, err);
232 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
233 "sky_le_dist", -1, NULL, context,
234 "Sky distance left of the spectrum");
235 cpl_ensure_code(!err, err);
238 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
239 "sky_ri_dist", -1, NULL, context,
240 "Sky distance right of the spectrum");
241 cpl_ensure_code(!err, err);
244 err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
"display",
245 CPL_FALSE, NULL, context,
247 cpl_ensure_code(!err, err);
249 return CPL_ERROR_NONE;
260static int sofi_spc_jitter(cpl_frameset * framelist,
261 const cpl_parameterlist * parlist)
263 cpl_propertylist * plist;
265 cpl_frameset * rawframes = NULL;
266 const cpl_frame * cur_frame;
270 cpl_image ** combined = NULL;
271 cpl_table * extracted = NULL;
274 sofi_spc_jitter_config.wavecal_out = -1;
275 sofi_spc_jitter_config.wavecal_cc = -1.0;
276 sofi_spc_jitter_config.throws = NULL;
277 sofi_spc_jitter_config.intensities = NULL;
278 sofi_spc_jitter_config.filter[0] = (char)0;
283 sofi_spc_jitter_config.crosstalk
284 = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
288 sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
290 bug_if(sval == NULL);
291 if (!strcmp(sval,
"phy")) sofi_spc_jitter_config.wavecal_in = 0;
292 else if (!strcmp(sval,
"sky")) sofi_spc_jitter_config.wavecal_in = 1;
293 else if (!strcmp(sval,
"arc")) sofi_spc_jitter_config.wavecal_in = 2;
295 error_if(1, CPL_ERROR_UNSUPPORTED_MODE,
296 "Invalid value for wavecal option: %s", sval);
300 sofi_spc_jitter_config.wavecal_degree
301 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
305 sofi_spc_jitter_config.wavecal_nsamples
306 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
310 sofi_spc_jitter_config.wavecal_err
311 = irplib_parameterlist_get_double(parlist, PACKAGE, RECIPE_STRING,
315 sofi_spc_jitter_config.wavecal_ppm
316 = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
320 sofi_spc_jitter_config.saa_refine
321 = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
325 sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
327 skip_if (sscanf(sval,
"%lg,%lg",
328 &sofi_spc_jitter_config.saa_rej_low,
329 &sofi_spc_jitter_config.saa_rej_high) != 2);
332 sofi_spc_jitter_config.extr_spec_pos
333 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
337 sofi_spc_jitter_config.extr_spec_width
338 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
342 sofi_spc_jitter_config.extr_sky_le_width
343 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
346 sofi_spc_jitter_config.extr_sky_ri_width
347 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
351 sofi_spc_jitter_config.extr_sky_le_dist
352 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
356 sofi_spc_jitter_config.extr_sky_ri_dist
357 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
360 sofi_spc_jitter_config.display
361 = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
368 cur_frame = cpl_frameset_get_position(framelist, 0);
369 plist = cpl_propertylist_load(cpl_frame_get_filename(cur_frame), 0);
370 skip_if(plist == NULL);
373 strcpy(sofi_spc_jitter_config.filter, sval);
377 cpl_propertylist_delete(plist);
386 error_if (rawframes == NULL, CPL_ERROR_DATA_NOT_FOUND,
387 "Cannot find the raw frames in the input list");
390 error_if (arc == NULL && sofi_spc_jitter_config.wavecal_in == 2,
391 CPL_ERROR_ILLEGAL_INPUT,
392 "You must provide an ARC file for the wl cal");
395 cpl_msg_info(cpl_func,
"Create the combined image");
396 cpl_msg_indent_more();
397 combined = sofi_spc_jitter_combine(rawframes, oh, flat, arc);
398 cpl_msg_indent_less();
400 error_if (combined==NULL, CPL_ERROR_ILLEGAL_INPUT,
401 "Cannot combine the images");
404 cpl_msg_info(cpl_func,
"Extract the spectrum");
405 cpl_msg_indent_more();
406 extracted = sofi_spc_jitter_extract(combined[0]);
407 cpl_msg_indent_less();
409 error_if (extracted == NULL, CPL_ERROR_DATA_NOT_FOUND,
410 "Cannot extract the spectrum");
413 cpl_msg_info(cpl_func,
"Save the products");
414 skip_if(sofi_spc_jitter_save(framelist, combined[0], extracted, parlist));
418 if (combined != NULL) {
419 cpl_image_delete(combined[0]);
420 cpl_image_delete(combined[1]);
424 cpl_vector_delete(sofi_spc_jitter_config.intensities);
425 cpl_vector_delete(sofi_spc_jitter_config.throws);
427 cpl_frameset_delete(rawframes);
429 cpl_table_delete(extracted);
431 return cpl_error_get_code();
444static cpl_image ** sofi_spc_jitter_combine(
445 cpl_frameset * rawframes,
450 cpl_imagelist * ilist;
452 cpl_vector * offsets;
455 cpl_imagelist * abba;
456 cpl_vector * abba_off;
457 cpl_imagelist * nodded;
458 cpl_vector * nodded_off_x;
459 cpl_vector * nodded_off_y;
461 cpl_table * extracted;
463 double * pnodded_off_x;
464 cpl_imagelist * nodded_warped;
465 cpl_bivector * nodded_offsets;
466 cpl_image ** combined;
472 if (rawframes == NULL)
return NULL;
475 cpl_msg_info(cpl_func,
"Load the data");
476 cpl_msg_indent_more();
477 if ((ilist = cpl_imagelist_load_frameset(rawframes, CPL_TYPE_FLOAT, 1,
479 cpl_msg_error(cpl_func,
"cannot load the data");
480 cpl_msg_indent_less();
483 cpl_msg_indent_less();
486 if (sofi_spc_jitter_config.crosstalk) {
487 cpl_msg_info(cpl_func,
"Apply the cross-talk correction");
488 cpl_msg_indent_more();
490 cpl_msg_error(cpl_func,
"Cannot correct for Cross-talk");
491 cpl_imagelist_delete(ilist);
492 cpl_msg_indent_less();
495 cpl_msg_indent_less();
500 cpl_msg_info(cpl_func,
"Apply the flatfield correction");
501 if ((tmp_im = cpl_image_load(flat, CPL_TYPE_FLOAT, 0, 0)) == NULL) {
502 cpl_msg_warning(cpl_func,
"cannot load the flat field");
504 if (cpl_imagelist_divide_image(ilist, tmp_im) != CPL_ERROR_NONE) {
505 cpl_msg_warning(cpl_func,
"cannot apply the flat field");
507 cpl_image_delete(tmp_im);
512 cpl_msg_info(cpl_func,
"Get the offsets");
513 if ((offsets = sofi_spc_jitter_get_offsets(rawframes)) == NULL) {
514 cpl_msg_error(cpl_func,
"cannot get the offsets");
515 cpl_imagelist_delete(ilist);
520 cpl_msg_info(cpl_func,
"Classify in groups");
521 cpl_msg_indent_more();
522 if ((groups = sofi_spc_jitter_classif(offsets, &ngroups)) == NULL) {
523 cpl_msg_error(cpl_func,
"cannot classify the data");
524 cpl_imagelist_delete(ilist);
525 cpl_vector_delete(offsets);
526 cpl_msg_indent_less();
529 cpl_msg_indent_less();
532 cpl_msg_info(cpl_func,
"Shift and add each group to one image");
533 cpl_msg_indent_more();
534 if ((abba = sofi_spc_jitter_saa_groups(ilist, offsets, groups,
535 ngroups, &abba_off)) == NULL) {
536 cpl_msg_error(cpl_func,
"cannot shift and add groups");
537 cpl_imagelist_delete(ilist);
538 cpl_vector_delete(offsets);
540 cpl_msg_indent_less();
543 cpl_imagelist_delete(ilist);
545 cpl_vector_delete(offsets);
546 cpl_msg_indent_less();
549 cpl_msg_info(cpl_func,
"Compute the wavelength calibration");
550 cpl_msg_indent_more();
551 if (sofi_spc_jitter_wavecal(arc, oh, cpl_imagelist_get(abba, 0),
553 cpl_msg_error(cpl_func,
"cannot compute the wavelength");
554 cpl_imagelist_delete(abba);
555 cpl_vector_delete(abba_off);
556 cpl_msg_indent_less();
559 cpl_msg_indent_less();
562 cpl_msg_info(cpl_func,
"Create the nodded images");
563 cpl_msg_indent_more();
564 if ((nodded = sofi_spc_jitter_nodded(abba, abba_off,
565 &nodded_off_x))==NULL) {
566 cpl_msg_error(cpl_func,
"cannot create the nodded images");
567 cpl_imagelist_delete(abba);
568 cpl_vector_delete(abba_off);
569 cpl_msg_indent_less();
572 cpl_imagelist_delete(abba);
573 cpl_msg_indent_less();
576 nima = cpl_imagelist_get_size(nodded);
577 sofi_spc_jitter_config.throws = cpl_vector_new(nima);
578 for (i=0; i<nima/2; i++) {
579 throw = fabs( (cpl_vector_get(abba_off, 2*i))-
580 (cpl_vector_get(abba_off, 2*i+1)));
581 cpl_vector_set(sofi_spc_jitter_config.throws, 2*i,
throw);
582 cpl_vector_set(sofi_spc_jitter_config.throws, 2*i+1,
throw);
584 cpl_vector_delete(abba_off);
587 cpl_msg_info(cpl_func,
"Compute the spectra intensities");
588 cpl_msg_indent_more();
589 nima = cpl_imagelist_get_size(nodded);
590 sofi_spc_jitter_config.intensities = cpl_vector_new(nima);
591 for (i=0; i<nima; i++) {
592 if ((extracted = sofi_spc_jitter_extract(
593 cpl_imagelist_get(nodded, i))) == NULL) {
594 cpl_msg_warning(cpl_func,
"Cannot extract the spectrum from nodded %d",
598 intensity = cpl_table_get_column_mean(extracted,
599 "Extracted_spectrum_value");
600 intensity *= cpl_table_get_nrow(extracted);
601 cpl_table_delete(extracted);
603 cpl_msg_info(cpl_func,
"Spectrum intensity nb %d: %g", i+1,
605 cpl_vector_set(sofi_spc_jitter_config.intensities, i, intensity);
607 cpl_msg_indent_less();
611 cpl_msg_info(cpl_func,
"Correct the distortion on nodded images");
612 cpl_msg_indent_more();
613 if ((nodded_warped = sofi_spc_jitter_distor(nodded, arc)) == NULL) {
614 cpl_msg_error(cpl_func,
"cannot correct the distortion");
615 cpl_imagelist_delete(nodded);
616 cpl_vector_delete(nodded_off_x);
617 cpl_msg_indent_less();
620 cpl_imagelist_delete(nodded);
621 nodded = nodded_warped;
622 cpl_msg_indent_less();
626 if (sofi_spc_jitter_config.saa_refine) {
627 cpl_msg_info(cpl_func,
"Refine the offsets");
628 pnodded_off_x = cpl_vector_get_data(nodded_off_x);
629 for (i=0; i<cpl_imagelist_get_size(nodded); i++) {
630 new_offset = sofi_spc_jitter_refine_offset(
631 cpl_imagelist_get(nodded, 0),
632 cpl_imagelist_get(nodded, i));
633 if (new_offset > 5000) {
634 cpl_msg_debug(cpl_func,
"cannot refine the offset - keep %g",
637 if (fabs(new_offset-pnodded_off_x[i]) <
638 SOFI_SPC_JITTER_OFFSET_ERR) {
639 cpl_msg_debug(cpl_func,
"refined offset : %g (old was %g)",
640 new_offset, pnodded_off_x[i]);
641 pnodded_off_x[i] = new_offset;
643 cpl_msg_debug(cpl_func,
644 "refined offset %g too different - keep %g",
645 new_offset, pnodded_off_x[i]);
653 nodded_off_y = cpl_vector_duplicate(nodded_off_x);
654 cpl_vector_fill(nodded_off_y, 0.0);
655 nodded_offsets = cpl_bivector_wrap_vectors(nodded_off_x, nodded_off_y);
657 cpl_msg_info(cpl_func,
"Apply the shift and add on the nodded frames");
658 nima = cpl_imagelist_get_size(nodded);
659 if ((combined = cpl_geom_img_offset_saa(nodded, nodded_offsets,
661 (
int)(sofi_spc_jitter_config.saa_rej_low * nima),
662 (
int)(sofi_spc_jitter_config.saa_rej_high * nima),
663 CPL_GEOM_FIRST, NULL, NULL)) == NULL) {
664 cpl_msg_error(cpl_func,
"Cannot shift and add group");
665 cpl_imagelist_delete(nodded);
666 cpl_bivector_unwrap_vectors(nodded_offsets);
667 cpl_vector_delete(nodded_off_x);
668 cpl_vector_delete(nodded_off_y);
671 cpl_imagelist_delete(nodded);
672 cpl_bivector_unwrap_vectors(nodded_offsets);
673 cpl_vector_delete(nodded_off_x);
674 cpl_vector_delete(nodded_off_y);
685static cpl_vector * sofi_spc_jitter_get_offsets(cpl_frameset * rawframes)
687 cpl_vector * offsets;
690 cpl_frame * cur_frame;
691 cpl_propertylist * plist;
695 if (rawframes == NULL)
return NULL;
698 nraw = cpl_frameset_get_size(rawframes);
701 offsets = cpl_vector_new(nraw);
702 pvect = cpl_vector_get_data(offsets);
703 for (i=0; i<nraw; i++) {
704 cur_frame = cpl_frameset_get_position(rawframes, i);
705 if ((plist=cpl_propertylist_load(cpl_frame_get_filename(cur_frame),
707 cpl_msg_error(cpl_func,
"cannot get property list");
708 cpl_vector_delete(offsets);
712 if (cpl_error_get_code()) {
713 cpl_msg_error(cpl_func,
"cannot get the offset from the header");
714 cpl_vector_delete(offsets);
715 cpl_propertylist_delete(plist);
718 cpl_propertylist_delete(plist);
763static int * sofi_spc_jitter_classif(
764 cpl_vector * offsets,
769 double offset_thresh;
770 cpl_vector * tmp_vec;
776 if (offsets == NULL)
return NULL;
779 nraw = cpl_vector_get_size(offsets);
782 tmp_vec = cpl_vector_duplicate(offsets);
783 cpl_vector_sort(tmp_vec, 1);
784 pvect = cpl_vector_get_data(tmp_vec);
785 if (pvect[0] == pvect[nraw-1]) {
786 cpl_msg_error(cpl_func,
"Only one offset in the list - abort");
787 cpl_vector_delete(tmp_vec);
790 offset_thresh = (pvect[0] + pvect[nraw-1]) / 2.0;
791 cpl_vector_delete(tmp_vec);
794 pvect = cpl_vector_get_data(offsets);
796 groups = cpl_calloc(nraw,
sizeof(
int));
804 (!off_comp(pvect[i], pvect[i+j], offset_thresh))) j++;
806 if (i+j >= nraw) i = nraw;
810 while ((i+j+k < nraw)
811 && (!off_comp(pvect[i+j], pvect[i+j+k], offset_thresh))
815 for (l=i+j+k; l<nraw; l++) {
816 if (off_comp(pvect[i+j], pvect[l], offset_thresh)) {
822 if (last_group == 0) {
823 for (l=0; l<j; l++) groups[i+l] = *ngroups + 1;
824 for (l=0; l<k; l++) groups[i+j+l] = *ngroups + 2;
828 for (l=0; l<j; l++) groups[i+l] = *ngroups + 1;
829 for (l=0; l<nraw - (i+j); l++) groups[i+j+l] =*ngroups + 2;
838 cpl_msg_error(cpl_func,
"Odd number of groups found");
878static cpl_imagelist * sofi_spc_jitter_saa_groups(
879 cpl_imagelist * ilist,
880 cpl_vector * offsets,
883 cpl_vector ** abba_off)
885 cpl_imagelist * abba;
886 cpl_imagelist * group_list;
888 cpl_image ** combined;
889 cpl_bivector * group_off;
898 if ((ilist == NULL) || (offsets == NULL) || (groups == NULL))
return NULL;
901 nima = cpl_imagelist_get_size(ilist);
902 poffsets = cpl_vector_get_data(offsets);
905 abba = cpl_imagelist_new();
906 *abba_off = cpl_vector_new(ngroups);
907 pabba_off = cpl_vector_get_data(*abba_off);
910 for (i=0; i<ngroups; i++) {
914 group_list = cpl_imagelist_new();
916 for (j=0; j<nima; j++) {
917 if (i+1 == groups[j]) {
919 if (k==0) pabba_off[i] = poffsets[j];
921 if (fabs(pabba_off[i]-poffsets[j]) > 1e-3) saa = 1;
923 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(ilist, j));
924 cpl_imagelist_set(group_list, tmp_ima, k);
932 group_off = cpl_bivector_new(k);
933 cpl_vector_fill(cpl_bivector_get_y(group_off), 0.0);
934 pgroup_off = cpl_bivector_get_x_data(group_off);
936 for (j=0; j<nima; j++) {
937 if (i+1 == groups[j]) {
938 pgroup_off[k] = poffsets[j];
942 cpl_vector_subtract_scalar(cpl_bivector_get_x(group_off),
945 cpl_msg_debug(cpl_func,
"Apply shift-and-add for group %d", i+1);
946 if ((combined = cpl_geom_img_offset_saa(group_list,
947 group_off, CPL_KERNEL_DEFAULT, 0, 0,
948 CPL_GEOM_FIRST, NULL, NULL)) == NULL) {
949 cpl_msg_error(cpl_func,
"Cannot shift and add group nb %d", i+1);
950 cpl_imagelist_delete(group_list);
951 cpl_bivector_delete(group_off);
952 cpl_imagelist_delete(abba);
953 cpl_vector_delete(*abba_off);
956 cpl_bivector_delete(group_off);
957 cpl_image_delete(combined[1]);
958 cpl_imagelist_set(abba, combined[0], i);
962 cpl_msg_debug(cpl_func,
"Apply averaging for group %d", i+1);
963 if ((tmp_ima = cpl_imagelist_collapse_create(group_list)) == NULL) {
964 cpl_msg_error(cpl_func,
"Cannot average group nb %d", i+1);
965 cpl_imagelist_delete(group_list);
966 cpl_imagelist_delete(abba);
967 cpl_vector_delete(*abba_off);
970 cpl_imagelist_set(abba, tmp_ima, i);
972 cpl_imagelist_delete(group_list);
987static int sofi_spc_jitter_wavecal(
994 cpl_polynomial * phdisprel;
995 cpl_frame * cur_frame;
996 const char * cur_fname;
997 cpl_polynomial * disprel;
1000 double xc, a, b, c, d, e;
1004 if (sofi_spc_jitter_config.wavecal_in == 2) {
1006 cpl_msg_error(cpl_func,
"Missing arc for the wavelength calib");
1007 return CPL_ERROR_UNSPECIFIED;
1009 cpl_msg_info(cpl_func,
"Get the wavelength from the ARC file");
1010 if ((arc_tab = cpl_table_load(arc, 1, 0)) == NULL) {
1011 cpl_msg_error(cpl_func,
"Cannot load the arc table");
1012 sofi_spc_jitter_config.wavecal_out = -1;
1013 return CPL_ERROR_UNSPECIFIED;
1015 sofi_spc_jitter_config.wavecal_a0 =
1016 cpl_table_get_double(arc_tab,
"WL_coefficients", 0, NULL);
1017 sofi_spc_jitter_config.wavecal_a1 =
1018 cpl_table_get_double(arc_tab,
"WL_coefficients", 1, NULL);
1019 sofi_spc_jitter_config.wavecal_a2 =
1020 cpl_table_get_double(arc_tab,
"WL_coefficients", 2, NULL);
1021 sofi_spc_jitter_config.wavecal_a3 =
1022 cpl_table_get_double(arc_tab,
"WL_coefficients", 3, NULL);
1023 sofi_spc_jitter_config.wavecal_a4 =
1024 cpl_table_get_double(arc_tab,
"WL_coefficients", 4, NULL);
1025 cpl_table_delete(arc_tab);
1026 sofi_spc_jitter_config.wavecal_out = 2;
1027 sofi_spc_jitter_config.wavecal_cc = -1.0;
1032 cur_frame = cpl_frameset_get_position(raw, 0);
1033 cur_fname = cpl_frame_get_filename(cur_frame);
1036 cpl_msg_info(cpl_func,
"Compute the physical model");
1037 cpl_msg_indent_more();
1039 cpl_msg_error(cpl_func,
"cannot compute the physical model");
1040 sofi_spc_jitter_config.wavecal_out = -1;
1041 cpl_msg_indent_less();
1042 return CPL_ERROR_UNSPECIFIED;
1045 a = cpl_polynomial_get_coeff(phdisprel, p);
1046 b = cpl_polynomial_get_coeff(phdisprel, p + 1);
1047 cpl_msg_info(cpl_func,
"f(x)=%g + %g*x", a, b);
1048 sofi_spc_jitter_config.wavecal_a0 = a;
1049 sofi_spc_jitter_config.wavecal_a1 = b;
1050 sofi_spc_jitter_config.wavecal_a2 = 0.0;
1051 sofi_spc_jitter_config.wavecal_a3 = 0.0;
1052 sofi_spc_jitter_config.wavecal_a4 = 0.0;
1053 sofi_spc_jitter_config.wavecal_cc = -1.0;
1054 sofi_spc_jitter_config.wavecal_out = 0;
1055 cpl_msg_indent_less();
1058 if (sofi_spc_jitter_config.wavecal_in == 1) {
1061 cpl_msg_warning(cpl_func,
"cannot get the slit width");
1062 cpl_polynomial_delete(phdisprel);
1066 cpl_msg_info(cpl_func,
"Compute the wavelength with the sky lines");
1067 cpl_msg_indent_more();
1069 phdisprel, slit_width,
1070 sofi_spc_jitter_config.wavecal_degree,
1071 sofi_spc_jitter_config.wavecal_err,
1072 sofi_spc_jitter_config.wavecal_nsamples,
1073 sofi_spc_jitter_config.wavecal_ppm,
1074 sofi_spc_jitter_config.display, &xc)) == NULL) {
1075 cpl_msg_error(cpl_func,
"cannot compute the dispersion relation");
1076 cpl_polynomial_delete(phdisprel);
1077 cpl_msg_indent_less();
1080 cpl_msg_info(cpl_func,
"Cross correlation factor: %g", xc);
1081 p[0] = 0; p[1] = 1; p[2] = 2; p[3] = 3; p[4] = 4;
1082 a = b = c = d = e = 0.0;
1083 degree = cpl_polynomial_get_degree(disprel);
1084 a = cpl_polynomial_get_coeff(disprel, p);
1085 if (degree > 0) b = cpl_polynomial_get_coeff(disprel, p + 1);
1086 if (degree > 1) c = cpl_polynomial_get_coeff(disprel, p + 2);
1087 if (degree > 2) d = cpl_polynomial_get_coeff(disprel, p + 3);
1088 if (degree > 3) e = cpl_polynomial_get_coeff(disprel, p + 4);
1090 cpl_msg_info(cpl_func,
"f(x)=%g", a);
1092 cpl_msg_info(cpl_func,
"f(x)=%g + %g*x", a, b);
1094 cpl_msg_info(cpl_func,
"f(x)=%g + %g*x + %g*x^2", a, b, c);
1096 cpl_msg_info(cpl_func,
"f(x)=%g + %g*x + %g*x^2 + %g*x^3",
1099 cpl_msg_info(cpl_func,
"f(x)=%g + %g*x + %g*x^2 + %g*x^3 + %g*x^4",
1101 sofi_spc_jitter_config.wavecal_a0 = a;
1102 sofi_spc_jitter_config.wavecal_a1 = b;
1103 sofi_spc_jitter_config.wavecal_a2 = c;
1104 sofi_spc_jitter_config.wavecal_a3 = d;
1105 sofi_spc_jitter_config.wavecal_a4 = e;
1106 sofi_spc_jitter_config.wavecal_cc = xc;
1107 sofi_spc_jitter_config.wavecal_out = 1;
1108 cpl_polynomial_delete(disprel);
1109 cpl_msg_indent_less();
1111 cpl_polynomial_delete(phdisprel);
1137static cpl_imagelist * sofi_spc_jitter_nodded(
1138 cpl_imagelist * abba,
1139 cpl_vector * abba_off,
1140 cpl_vector ** nodded_off)
1142 cpl_imagelist * nodded;
1143 cpl_image * tmp_ima;
1149 if ((abba == NULL) || (abba_off == NULL))
return NULL;
1152 nima = cpl_imagelist_get_size(abba);
1154 cpl_msg_error(cpl_func,
"Number of images should be even");
1159 *nodded_off = cpl_vector_duplicate(abba_off);
1161 nodded = cpl_imagelist_new();
1162 for (i=0; i<(nima/2); i++) {
1164 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i));
1165 cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i+1));
1166 cpl_imagelist_set(nodded, tmp_ima, 2*i);
1168 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i+1));
1169 cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i));
1170 cpl_imagelist_set(nodded, tmp_ima, 2*i+1);
1174 ref_off = cpl_vector_get(*nodded_off, 0);
1175 cpl_vector_subtract_scalar(*nodded_off, ref_off);
1187static cpl_imagelist * sofi_spc_jitter_distor(
1188 cpl_imagelist * ilist,
1191 cpl_polynomial * arc_poly;
1192 cpl_polynomial * id_poly;
1195 cpl_vector * profile;
1196 cpl_imagelist * warped_list;
1201 if (ilist == NULL)
return NULL;
1202 if (arc == NULL)
return NULL;
1205 arc_poly = cpl_polynomial_new(2);
1206 cpl_msg_info(cpl_func,
"Get the arc distortion from the file");
1207 if ((tab = cpl_table_load(arc, 1, 0)) == NULL) {
1208 cpl_msg_error(cpl_func,
"cannot load the arc table");
1209 cpl_polynomial_delete(arc_poly);
1212 for (i=0; i<cpl_table_get_nrow(tab); i++) {
1213 power[0] = cpl_table_get_int(tab,
"Degree_of_x", i, NULL);
1214 power[1] = cpl_table_get_int(tab,
"Degree_of_y", i, NULL);
1215 cpl_polynomial_set_coeff(arc_poly, power,
1216 cpl_table_get_double(tab,
"poly2d_coef", i, NULL));
1218 cpl_table_delete(tab);
1221 id_poly = cpl_polynomial_new(2);
1224 cpl_polynomial_set_coeff(id_poly, power, 1.0);
1227 profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
1228 cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
1229 CPL_KERNEL_DEF_WIDTH);
1232 warped_list = cpl_imagelist_new();
1233 for (i=0; i<cpl_imagelist_get_size(ilist); i++) {
1234 warped = cpl_image_duplicate(cpl_imagelist_get(ilist, i));
1235 if (cpl_image_warp_polynomial(warped, cpl_imagelist_get(ilist, i),
1236 id_poly, arc_poly, profile, CPL_KERNEL_DEF_WIDTH, profile,
1237 CPL_KERNEL_DEF_WIDTH) != CPL_ERROR_NONE) {
1238 cpl_msg_error(cpl_func,
"cannot correct the distortion");
1239 cpl_image_delete(warped);
1240 cpl_polynomial_delete(arc_poly);
1241 cpl_polynomial_delete(id_poly);
1242 cpl_vector_delete(profile);
1245 cpl_imagelist_set(warped_list, warped, i);
1247 cpl_vector_delete(profile);
1248 cpl_polynomial_delete(arc_poly);
1249 cpl_polynomial_delete(id_poly);
1261static double sofi_spc_jitter_refine_offset(
1268 if (ima1 == NULL)
return 10000.0;
1269 if (ima2 == NULL)
return 10000.0;
1272 if (irplib_spectrum_find_brightest(ima1, 0.0, NO_SHADOW, 0.0, 1,
1276 if (irplib_spectrum_find_brightest(ima2, 0.0, NO_SHADOW, 0.0, 1,
1290static cpl_table * sofi_spc_jitter_extract(cpl_image * combined)
1292 cpl_errorstate allstate = cpl_errorstate_get();
1293 int ri_dist, le_dist, ri_width, le_width, spec_pos;
1296 int right_side, left_side;
1305 cpl_bivector * toplot;
1313 if (combined == NULL)
return NULL;
1316 nx = cpl_image_get_size_x(combined);
1317 ny = cpl_image_get_size_y(combined);
1318 ri_dist = sofi_spc_jitter_config.extr_sky_ri_dist;
1319 le_dist = sofi_spc_jitter_config.extr_sky_le_dist;
1320 ri_width = sofi_spc_jitter_config.extr_sky_ri_width;
1321 le_width = sofi_spc_jitter_config.extr_sky_le_width;
1322 spec_pos = sofi_spc_jitter_config.extr_spec_pos;
1327 if (sofi_spc_jitter_config.throws == NULL) {
1328 cpl_msg_error(cpl_func,
1329 "Need a throw value to detect the spectra !!");
1332 for (i=0; i<cpl_vector_get_size(sofi_spc_jitter_config.throws); i++){
1333 throw = (int)cpl_vector_get(sofi_spc_jitter_config.throws, i);
1334 if ((res = irplib_spectrum_find_brightest(combined,
throw,
1335 TWO_SHADOWS, 0.0, 1, &pos)) == 0)
break;
1336 if ((res = irplib_spectrum_find_brightest(combined,
throw,
1337 ONE_SHADOW, 0.0, 1, &pos)) == 0)
break;
1340 cpl_msg_error(cpl_func,
"Cannot detect the spectrum");
1341 (void)cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
1344 spec_pos = (int)pos;
1345 cpl_msg_info(cpl_func,
"Spectrum detected at x = %d", spec_pos);
1351 left_side = spec_pos - (int)(sofi_spc_jitter_config.extr_spec_width/2);
1352 right_side = left_side + sofi_spc_jitter_config.extr_spec_width;
1353 if ((left_side < 1) || (right_side > ny)) {
1354 cpl_msg_error(cpl_func,
"Spectrum zone falls outside the image");
1355 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
1356 "%d < 1 || %d > %d", (
int)left_side,
1357 (
int)right_side, (
int)ny);
1361 if (ri_dist < 0) ri_dist = 2*sofi_spc_jitter_config.extr_spec_width;
1362 if (le_dist < 0) le_dist = 2*sofi_spc_jitter_config.extr_spec_width;
1363 sky_pos[1] = spec_pos - le_dist;
1364 sky_pos[0] = sky_pos[1] - le_width;
1365 sky_pos[2] = spec_pos + ri_dist;
1366 sky_pos[3] = sky_pos[2] + ri_width;
1369 sky = cpl_vector_new(ny);
1370 psky = cpl_vector_get_data(sky);
1371 if (((sky_pos[0] < 1) || (le_width == 0)) &&
1372 ((sky_pos[3] <= nx) && (ri_width > 0))) {
1373 for (i=0; i<ny; i++) {
1374 psky[i] = cpl_image_get_median_window(combined, sky_pos[2],
1375 ny-i, sky_pos[3], ny-i);
1377 }
else if (((sky_pos[3] > nx) || (ri_width == 0))
1378 && ((sky_pos[0] > 0) && (le_width > 0))) {
1379 for (i=0; i<ny; i++) {
1380 psky[i] = cpl_image_get_median_window(combined, sky_pos[0],
1381 ny-i, sky_pos[1], ny-i);
1383 }
else if ((ri_width != 0) && (le_width != 0)
1384 && (sky_pos[0] > 0) && (sky_pos[3] <= nx)) {
1385 for (i=0; i<ny; i++) {
1386 psky[i] = cpl_image_get_median_window(combined, sky_pos[2],
1387 ny-i, sky_pos[3], ny-i);
1388 psky[i] += cpl_image_get_median_window(combined, sky_pos[0],
1389 ny-i, sky_pos[1], ny-i);
1393 for (i=0; i<ny; i++) psky[i] = 0.0;
1397 spec = cpl_vector_new(ny);
1398 pspec = cpl_vector_get_data(spec);
1399 for (i=0; i<ny; i++) {
1400 cpl_errorstate prestate = cpl_errorstate_get();
1401 pspec[i] = cpl_image_get_flux_window(combined, left_side, ny-i,
1403 if (cpl_errorstate_is_equal(prestate)) {
1404 if (nokfirst < 0) nokfirst = i;
1406 pspec[i] -= psky[i] * sofi_spc_jitter_config.extr_spec_width;
1409 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
1410 "%d <= %d. i=%d < %d=ny", (
int)left_side,
1411 (
int)right_side, (
int)i, (
int)ny);
1414 if (nokfirst <= noklast) {
1415 cpl_msg_warning(cpl_func,
"Only %d of %d column(s) processed, from %d "
1416 "to %d", (
int)(1+noklast-nokfirst), (
int)ny,
1417 (
int)(ny-noklast), (
int)(ny-nokfirst));
1418 cpl_errorstate_dump(allstate, CPL_FALSE,
1419 cpl_errorstate_dump_one_warning);
1420 cpl_errorstate_set(allstate);
1422 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
1423 "All %d columns failed", (
int)ny);
1427 wl = cpl_vector_new(ny);
1428 pwl = cpl_vector_get_data(wl);
1429 for (i=0; i<ny; i++) {
1430 pwl[i] = sofi_spc_jitter_config.wavecal_a0 +
1431 sofi_spc_jitter_config.wavecal_a1 * (i+1) +
1432 sofi_spc_jitter_config.wavecal_a2 * (i+1) * (i+1) +
1433 sofi_spc_jitter_config.wavecal_a3 * (i+1) * (i+1) * (i+1) +
1434 sofi_spc_jitter_config.wavecal_a4 * (i+1) * (i+1) * (i+1) + (i+1);
1438 if (sofi_spc_jitter_config.display) {
1439 toplot = cpl_bivector_wrap_vectors(wl, spec);
1440 cpl_plot_bivector(NULL,
"t 'Spectrum' w lines", NULL, toplot);
1441 cpl_bivector_unwrap_vectors(toplot);
1442 toplot = cpl_bivector_wrap_vectors(wl, sky);
1443 cpl_plot_bivector(NULL,
"t 'Sky' w lines", NULL, toplot);
1444 cpl_bivector_unwrap_vectors(toplot);
1448 out = cpl_table_new(nx);
1449 cpl_table_new_column(out,
"Y_coordinate", CPL_TYPE_DOUBLE);
1450 cpl_table_new_column(out,
"Extracted_spectrum_value", CPL_TYPE_DOUBLE);
1451 cpl_table_new_column(out,
"Sky_spectrum", CPL_TYPE_DOUBLE);
1452 for (i=0; i<nx; i++) {
1453 cpl_table_set_double(out,
"Y_coordinate", i, pwl[i]);
1454 cpl_table_set_double(out,
"Extracted_spectrum_value", i, pspec[i]);
1455 cpl_table_set_double(out,
"Sky_spectrum", i, psky[i]);
1457 cpl_vector_delete(wl);
1458 cpl_vector_delete(spec);
1459 cpl_vector_delete(sky);
1473static cpl_error_code sofi_spc_jitter_save(cpl_frameset * set,
1474 const cpl_image * ima,
1475 const cpl_table * tab,
1476 const cpl_parameterlist * parlist)
1478 cpl_propertylist * plist;
1480 cpl_propertylist * qclist = cpl_propertylist_new();
1481 cpl_propertylist * paflist;
1483 const cpl_frame * ref_frame
1484 = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
1490 if (sofi_spc_jitter_config.filter[0] != (
char)0)
1491 cpl_propertylist_append_string(qclist,
"ESO QC FILTER OBS",
1492 sofi_spc_jitter_config.filter);
1493 cpl_propertylist_append_double(qclist,
"ESO QC DISPCO1",
1494 sofi_spc_jitter_config.wavecal_a0);
1495 cpl_propertylist_append_double(qclist,
"ESO QC DISPCO2",
1496 sofi_spc_jitter_config.wavecal_a1);
1497 cpl_propertylist_append_double(qclist,
"ESO QC DISPCO3",
1498 sofi_spc_jitter_config.wavecal_a2);
1499 cpl_propertylist_append_double(qclist,
"ESO QC DISPCO4",
1500 sofi_spc_jitter_config.wavecal_a3);
1501 cpl_propertylist_append_double(qclist,
"ESO QC DISPCO5",
1502 sofi_spc_jitter_config.wavecal_a4);
1503 cpl_propertylist_append_double(qclist,
"ESO QC WLEN",
1504 sofi_spc_jitter_config.wavecal_a0 +
1505 sofi_spc_jitter_config.wavecal_a1 * 512 +
1506 sofi_spc_jitter_config.wavecal_a2 * 512 * 512 +
1507 sofi_spc_jitter_config.wavecal_a3 * 512 * 512 * 512 +
1508 sofi_spc_jitter_config.wavecal_a4 * 512 * 512 * 512 * 512);
1509 cpl_propertylist_append_double(qclist,
"ESO QC DISP XCORR",
1510 sofi_spc_jitter_config.wavecal_cc);
1511 if (sofi_spc_jitter_config.wavecal_out == 0) {
1512 cpl_propertylist_append_string(qclist,
"ESO QC WLMETHOD",
1514 }
else if (sofi_spc_jitter_config.wavecal_out == 1) {
1515 cpl_propertylist_append_string(qclist,
"ESO QC WLMETHOD",
1517 }
else if (sofi_spc_jitter_config.wavecal_out == 2) {
1518 cpl_propertylist_append_string(qclist,
"ESO QC WLMETHOD",
1521 for (i=0; i<cpl_vector_get_size(sofi_spc_jitter_config.intensities);i++) {
1522 sprintf(qc_str,
"ESO QC SPEC INTENS%d", i+1);
1523 cpl_propertylist_append_double(qclist, qc_str,
1524 cpl_vector_get(sofi_spc_jitter_config.intensities, i));
1528 cpl_propertylist_update_double(qclist,
"CRVAL1",
1529 sofi_spc_jitter_config.wavecal_a0);
1530 cpl_propertylist_update_double(qclist,
"CRVAL2", 1.0);
1531 cpl_propertylist_update_double(qclist,
"CRPIX1", 1.0);
1532 cpl_propertylist_update_double(qclist,
"CRPIX2", 1.0);
1533 cpl_propertylist_update_double(qclist,
"CDELT1",
1534 sofi_spc_jitter_config.wavecal_a1);
1535 cpl_propertylist_update_double(qclist,
"CDELT2", 1.0);
1536 cpl_propertylist_update_string(qclist,
"CTYPE1",
"LINEAR");
1537 cpl_propertylist_update_string(qclist,
"CTYPE2",
"LINEAR");
1538 if (cpl_propertylist_has(qclist,
"CD1_1")) {
1539 cpl_propertylist_update_double(qclist,
"CD1_1",
1540 sofi_spc_jitter_config.wavecal_a1);
1542 cpl_propertylist_insert_after_double(qclist,
"CTYPE2",
"CD1_1",
1543 sofi_spc_jitter_config.wavecal_a1);
1545 if (cpl_propertylist_has(qclist,
"CD2_2")) {
1546 cpl_propertylist_update_double(qclist,
"CD2_2", 1.0);
1548 cpl_propertylist_insert_after_double(qclist,
"CD1_1",
"CD2_2", 1.0);
1552 irplib_dfs_save_image(set, parlist, set, ima, CPL_BPP_IEEE_FLOAT,
1553 RECIPE_STRING, SOFI_SPC_JITTER_COMB, qclist,
1554 NULL, PACKAGE
"/" PACKAGE_VERSION,
1555 RECIPE_STRING
"_combined" CPL_DFS_FITS);
1559 irplib_dfs_save_table(set, parlist, set, tab, NULL, RECIPE_STRING,
1560 SOFI_SPC_JITTER_EXTR, qclist, NULL, PACKAGE
"/" PACKAGE_VERSION,
1561 RECIPE_STRING
"_extracted" CPL_DFS_FITS);
1566 plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame), 0);
1567 if (plist == NULL) {
1568 cpl_propertylist_delete(qclist);
1569 return cpl_error_set_message(cpl_func, cpl_error_get_code(),
"Could "
1570 "not read header from reference frame");
1574 paflist = cpl_propertylist_new();
1575 cpl_propertylist_copy_property_regexp(paflist, plist,
1576 "^(ARCFILE|MJD-OBS|INSTRUME|ESO TPL ID|ESO TPL NEXP|ESO DPR CATG|"
1577 "ESO DPR TECH|ESO DPR TYPE|DATE-OBS|ESO INS GRAT NAME|"
1578 "ESO INS GRAT WLEN|ESO INS OPTI1 ID|ESO OBS ID|ESO OBS TARG NAME)$", 0);
1579 cpl_propertylist_delete(plist);
1582 cpl_propertylist_copy_property_regexp(paflist, qclist,
".", 0);
1583 cpl_propertylist_delete(qclist);
1586 cpl_dfs_save_paf(
"SOFI", RECIPE_STRING, paflist,
1587 RECIPE_STRING CPL_DFS_PAF);
1588 cpl_propertylist_delete(paflist);
1590 return cpl_error_get_code();
1602static int off_comp(
double off1,
double off2,
double thresh)
1604 if (((off1>thresh) && (off2<thresh)) || ((off1<thresh) && (off2>thresh)))
int sofi_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
double sofi_pfits_get_cumoffsetx(const cpl_propertylist *plist)
find out the cumulative offset in X
const char * sofi_pfits_get_filter(const cpl_propertylist *plist)
find out which wave band is active in short wavelength
cpl_frameset * sofi_extract_frameset(const cpl_frameset *in, const char *tag)
Extract the frames with the given tag from a frameset.
const char * sofi_extract_filename(const cpl_frameset *in, const char *tag)
Extract the filename ffor the first frame of the given tag.
int sofi_correct_crosstalk_list(cpl_imagelist *ilist)
Remove the Cross-talk effect from an image list.
cpl_polynomial * sofi_get_disprel_estimate(const char *filename, int poly_deg)
Estimate the instrument dispersion relation.
double sofi_get_slitwidth(const char *filename)
Find out the slit width.
cpl_polynomial * sofi_wavelength_engine(const cpl_image *in, const char *table_name, const char *oh, const char *xe, const char *ne, const cpl_polynomial *phdisprel, double slit_width, int degree, double wl_err, int nsamples, int use_ppm, int plot, double *xcorr)
Compute a dispersion relation.