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
61 static cpl_image ** sofi_spc_jitter_combine(cpl_frameset *,
const char *,
62 const char *,
const char *);
63 static cpl_vector * sofi_spc_jitter_get_offsets(cpl_frameset *);
64 static int * sofi_spc_jitter_classif(cpl_vector *,
int *);
65 static int off_comp(
double,
double,
double);
66 static cpl_imagelist * sofi_spc_jitter_saa_groups(cpl_imagelist *,
67 cpl_vector *,
int *,
int, cpl_vector **);
68 static int sofi_spc_jitter_wavecal(
const char *,
const char *, cpl_image *,
70 static cpl_imagelist * sofi_spc_jitter_nodded(cpl_imagelist *, cpl_vector *,
72 static cpl_imagelist * sofi_spc_jitter_distor(cpl_imagelist *,
const char *);
73 static double sofi_spc_jitter_refine_offset(cpl_image *, cpl_image *);
74 static cpl_table * sofi_spc_jitter_extract(cpl_image *);
75 static cpl_error_code sofi_spc_jitter_save(cpl_frameset *,
const cpl_image *,
77 const cpl_parameterlist *);
79 cpl_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;
144 cpl_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;
260 static 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();
444 static 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);
685 static 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);
763 static 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");
878 static 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);
987 static 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);
1137 static 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);
1187 static 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);
1261 static 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,
1290 static cpl_table * sofi_spc_jitter_extract(cpl_image * combined)
1292 int ri_dist, le_dist, ri_width, le_width, spec_pos;
1295 int right_side, left_side;
1304 cpl_bivector * toplot;
1310 if (combined == NULL)
return NULL;
1313 nx = cpl_image_get_size_x(combined);
1314 ny = cpl_image_get_size_y(combined);
1315 ri_dist = sofi_spc_jitter_config.extr_sky_ri_dist;
1316 le_dist = sofi_spc_jitter_config.extr_sky_le_dist;
1317 ri_width = sofi_spc_jitter_config.extr_sky_ri_width;
1318 le_width = sofi_spc_jitter_config.extr_sky_le_width;
1319 spec_pos = sofi_spc_jitter_config.extr_spec_pos;
1324 if (sofi_spc_jitter_config.throws == NULL) {
1325 cpl_msg_error(cpl_func,
1326 "Need a throw value to detect the spectra !!");
1329 for (i=0; i<cpl_vector_get_size(sofi_spc_jitter_config.throws); i++){
1330 throw = (int)cpl_vector_get(sofi_spc_jitter_config.throws, i);
1331 if ((res = irplib_spectrum_find_brightest(combined,
throw,
1332 TWO_SHADOWS, 0.0, 1, &pos)) == 0)
break;
1333 if ((res = irplib_spectrum_find_brightest(combined,
throw,
1334 ONE_SHADOW, 0.0, 1, &pos)) == 0)
break;
1337 cpl_msg_error(cpl_func,
"Cannot detect the spectrum");
1340 spec_pos = (int)pos;
1341 cpl_msg_info(cpl_func,
"Spectrum detected at x = %d", spec_pos);
1347 left_side = spec_pos - (int)(sofi_spc_jitter_config.extr_spec_width/2);
1348 right_side = left_side + sofi_spc_jitter_config.extr_spec_width;
1349 if ((left_side < 1) || (right_side > ny)) {
1350 cpl_msg_error(cpl_func,
"Spectrum zone falls outside the image");
1354 if (ri_dist < 0) ri_dist = 2*sofi_spc_jitter_config.extr_spec_width;
1355 if (le_dist < 0) le_dist = 2*sofi_spc_jitter_config.extr_spec_width;
1356 sky_pos[1] = spec_pos - le_dist;
1357 sky_pos[0] = sky_pos[1] - le_width;
1358 sky_pos[2] = spec_pos + ri_dist;
1359 sky_pos[3] = sky_pos[2] + ri_width;
1362 sky = cpl_vector_new(ny);
1363 psky = cpl_vector_get_data(sky);
1364 if (((sky_pos[0] < 1) || (le_width == 0)) &&
1365 ((sky_pos[3] <= nx) && (ri_width > 0))) {
1366 for (i=0; i<ny; i++) {
1367 psky[i] = cpl_image_get_median_window(combined, sky_pos[2],
1368 ny-i, sky_pos[3], ny-i);
1370 }
else if (((sky_pos[3] > nx) || (ri_width == 0))
1371 && ((sky_pos[0] > 0) && (le_width > 0))) {
1372 for (i=0; i<ny; i++) {
1373 psky[i] = cpl_image_get_median_window(combined, sky_pos[0],
1374 ny-i, sky_pos[1], ny-i);
1376 }
else if ((ri_width != 0) && (le_width != 0)
1377 && (sky_pos[0] > 0) && (sky_pos[3] <= nx)) {
1378 for (i=0; i<ny; i++) {
1379 psky[i] = cpl_image_get_median_window(combined, sky_pos[2],
1380 ny-i, sky_pos[3], ny-i);
1381 psky[i] += cpl_image_get_median_window(combined, sky_pos[0],
1382 ny-i, sky_pos[1], ny-i);
1386 for (i=0; i<ny; i++) psky[i] = 0.0;
1390 spec = cpl_vector_new(ny);
1391 pspec = cpl_vector_get_data(spec);
1392 for (i=0; i<ny; i++) {
1393 pspec[i] = cpl_image_get_flux_window(combined, left_side, ny-i,
1395 pspec[i] -= psky[i] * sofi_spc_jitter_config.extr_spec_width;
1399 wl = cpl_vector_new(ny);
1400 pwl = cpl_vector_get_data(wl);
1401 for (i=0; i<ny; i++) {
1402 pwl[i] = sofi_spc_jitter_config.wavecal_a0 +
1403 sofi_spc_jitter_config.wavecal_a1 * (i+1) +
1404 sofi_spc_jitter_config.wavecal_a2 * (i+1) * (i+1) +
1405 sofi_spc_jitter_config.wavecal_a3 * (i+1) * (i+1) * (i+1) +
1406 sofi_spc_jitter_config.wavecal_a4 * (i+1) * (i+1) * (i+1) + (i+1);
1410 if (sofi_spc_jitter_config.display) {
1411 toplot = cpl_bivector_wrap_vectors(wl, spec);
1412 cpl_plot_bivector(NULL,
"t 'Spectrum' w lines", NULL, toplot);
1413 cpl_bivector_unwrap_vectors(toplot);
1414 toplot = cpl_bivector_wrap_vectors(wl, sky);
1415 cpl_plot_bivector(NULL,
"t 'Sky' w lines", NULL, toplot);
1416 cpl_bivector_unwrap_vectors(toplot);
1420 out = cpl_table_new(nx);
1421 cpl_table_new_column(out,
"Y_coordinate", CPL_TYPE_DOUBLE);
1422 cpl_table_new_column(out,
"Extracted_spectrum_value", CPL_TYPE_DOUBLE);
1423 cpl_table_new_column(out,
"Sky_spectrum", CPL_TYPE_DOUBLE);
1424 for (i=0; i<nx; i++) {
1425 cpl_table_set_double(out,
"Y_coordinate", i, pwl[i]);
1426 cpl_table_set_double(out,
"Extracted_spectrum_value", i, pspec[i]);
1427 cpl_table_set_double(out,
"Sky_spectrum", i, psky[i]);
1429 cpl_vector_delete(wl);
1430 cpl_vector_delete(spec);
1431 cpl_vector_delete(sky);
1445 static cpl_error_code sofi_spc_jitter_save(cpl_frameset * set,
1446 const cpl_image * ima,
1447 const cpl_table * tab,
1448 const cpl_parameterlist * parlist)
1450 cpl_propertylist * plist;
1452 cpl_propertylist * qclist = cpl_propertylist_new();
1453 cpl_propertylist * paflist;
1455 const cpl_frame * ref_frame
1456 = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
1462 if (sofi_spc_jitter_config.filter[0] != (
char)0)
1463 cpl_propertylist_append_string(qclist,
"ESO QC FILTER OBS",
1464 sofi_spc_jitter_config.filter);
1465 cpl_propertylist_append_double(qclist,
"ESO QC DISPCO1",
1466 sofi_spc_jitter_config.wavecal_a0);
1467 cpl_propertylist_append_double(qclist,
"ESO QC DISPCO2",
1468 sofi_spc_jitter_config.wavecal_a1);
1469 cpl_propertylist_append_double(qclist,
"ESO QC DISPCO3",
1470 sofi_spc_jitter_config.wavecal_a2);
1471 cpl_propertylist_append_double(qclist,
"ESO QC DISPCO4",
1472 sofi_spc_jitter_config.wavecal_a3);
1473 cpl_propertylist_append_double(qclist,
"ESO QC DISPCO5",
1474 sofi_spc_jitter_config.wavecal_a4);
1475 cpl_propertylist_append_double(qclist,
"ESO QC WLEN",
1476 sofi_spc_jitter_config.wavecal_a0 +
1477 sofi_spc_jitter_config.wavecal_a1 * 512 +
1478 sofi_spc_jitter_config.wavecal_a2 * 512 * 512 +
1479 sofi_spc_jitter_config.wavecal_a3 * 512 * 512 * 512 +
1480 sofi_spc_jitter_config.wavecal_a4 * 512 * 512 * 512 * 512);
1481 cpl_propertylist_append_double(qclist,
"ESO QC DISP XCORR",
1482 sofi_spc_jitter_config.wavecal_cc);
1483 if (sofi_spc_jitter_config.wavecal_out == 0) {
1484 cpl_propertylist_append_string(qclist,
"ESO QC WLMETHOD",
1486 }
else if (sofi_spc_jitter_config.wavecal_out == 1) {
1487 cpl_propertylist_append_string(qclist,
"ESO QC WLMETHOD",
1489 }
else if (sofi_spc_jitter_config.wavecal_out == 2) {
1490 cpl_propertylist_append_string(qclist,
"ESO QC WLMETHOD",
1493 for (i=0; i<cpl_vector_get_size(sofi_spc_jitter_config.intensities);i++) {
1494 sprintf(qc_str,
"ESO QC SPEC INTENS%d", i+1);
1495 cpl_propertylist_append_double(qclist, qc_str,
1496 cpl_vector_get(sofi_spc_jitter_config.intensities, i));
1500 cpl_propertylist_update_double(qclist,
"CRVAL1",
1501 sofi_spc_jitter_config.wavecal_a0);
1502 cpl_propertylist_update_double(qclist,
"CRVAL2", 1.0);
1503 cpl_propertylist_update_double(qclist,
"CRPIX1", 1.0);
1504 cpl_propertylist_update_double(qclist,
"CRPIX2", 1.0);
1505 cpl_propertylist_update_double(qclist,
"CDELT1",
1506 sofi_spc_jitter_config.wavecal_a1);
1507 cpl_propertylist_update_double(qclist,
"CDELT2", 1.0);
1508 cpl_propertylist_update_string(qclist,
"CTYPE1",
"LINEAR");
1509 cpl_propertylist_update_string(qclist,
"CTYPE2",
"LINEAR");
1510 if (cpl_propertylist_has(qclist,
"CD1_1")) {
1511 cpl_propertylist_update_double(qclist,
"CD1_1",
1512 sofi_spc_jitter_config.wavecal_a1);
1514 cpl_propertylist_insert_after_double(qclist,
"CTYPE2",
"CD1_1",
1515 sofi_spc_jitter_config.wavecal_a1);
1517 if (cpl_propertylist_has(qclist,
"CD2_2")) {
1518 cpl_propertylist_update_double(qclist,
"CD2_2", 1.0);
1520 cpl_propertylist_insert_after_double(qclist,
"CD1_1",
"CD2_2", 1.0);
1524 irplib_dfs_save_image(set, parlist, set, ima, CPL_BPP_IEEE_FLOAT,
1525 RECIPE_STRING, SOFI_SPC_JITTER_COMB, qclist,
1526 NULL, PACKAGE
"/" PACKAGE_VERSION,
1527 RECIPE_STRING
"_combined" CPL_DFS_FITS);
1531 irplib_dfs_save_table(set, parlist, set, tab, NULL, RECIPE_STRING,
1532 SOFI_SPC_JITTER_EXTR, qclist, NULL, PACKAGE
"/" PACKAGE_VERSION,
1533 RECIPE_STRING
"_extracted" CPL_DFS_FITS);
1538 plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame), 0);
1539 if (plist == NULL) {
1540 cpl_propertylist_delete(qclist);
1541 return cpl_error_set_message(cpl_func, cpl_error_get_code(),
"Could "
1542 "not read header from reference frame");
1546 paflist = cpl_propertylist_new();
1547 cpl_propertylist_copy_property_regexp(paflist, plist,
1548 "^(ARCFILE|MJD-OBS|INSTRUME|ESO TPL ID|ESO TPL NEXP|ESO DPR CATG|"
1549 "ESO DPR TECH|ESO DPR TYPE|DATE-OBS|ESO INS GRAT NAME|"
1550 "ESO INS GRAT WLEN|ESO INS OPTI1 ID|ESO OBS ID|ESO OBS TARG NAME)$", 0);
1551 cpl_propertylist_delete(plist);
1554 cpl_propertylist_copy_property_regexp(paflist, qclist,
".", 0);
1555 cpl_propertylist_delete(qclist);
1558 cpl_dfs_save_paf(
"SOFI", RECIPE_STRING, paflist,
1559 RECIPE_STRING CPL_DFS_PAF);
1560 cpl_propertylist_delete(paflist);
1562 return cpl_error_get_code();
1574 static int off_comp(
double off1,
double off2,
double thresh)
1576 if (((off1>thresh) && (off2<thresh)) || ((off1<thresh) && (off2>thresh)))