30 #include "visir_utils.h"
31 #include "visir_pfits.h"
32 #include "visir_parameter.h"
33 #include "visir_pfits.h"
34 #include "visir_spc_distortion.h"
35 #include "visir_inputs.h"
36 #include "irplib_framelist.h"
37 #include "irplib_wcs.h"
49 #define VISIR_SECS_PER_DAY (24 * 3600)
51 #define FIND_BEAM_MAX_APERTURES_SQR (40 * 40)
58 #include "visir_destripe.h"
60 static cpl_image * visir_load_average(
const char *,
61 const cpl_propertylist *);
62 static cpl_imagelist * visir_load_intermint(
const irplib_framelist *,
int);
63 static cpl_error_code visir_imagelist_unpack_interm(cpl_imagelist *);
64 static cpl_error_code visir_rem_glitch(cpl_image *);
65 static cpl_error_code visir_rem_bad_images(cpl_imagelist *);
66 static cpl_error_code visir_offset_hcycle(cpl_image *);
68 static cpl_image ** visir_img_collapse_beam_four(cpl_propertylist *,
71 double,
double,
double,
72 const cpl_propertylist *);
74 static cpl_image ** visir_img_collapse_beam_three(cpl_propertylist *,
78 const cpl_propertylist *);
81 static cpl_error_code visir_img_find_beam_three(cpl_propertylist *,
84 double,
double,
double,
88 static cpl_error_code visir_img_find_beam_four(cpl_propertylist *,
91 double,
double,
double,
121 cpl_error_code visir_load_cube2_split_(cpl_imagelist * alist, cpl_imagelist * blist,
122 cpl_imagelist * packed, cpl_image * prevd)
125 int naxis3 = cpl_imagelist_get_size(packed);
126 int prevd_insert_pos = cpl_imagelist_get_size(blist);
128 bug_if(alist == NULL);
129 bug_if(blist == NULL);
133 cpl_imagelist_set(blist, prevd, prevd_insert_pos);
136 for (
int i = 0; i < naxis3/2; i++) {
137 cpl_image * aimage = cpl_imagelist_unset(packed, 0);
138 cpl_image * dimage = cpl_imagelist_unset(packed, 0);
140 cpl_imagelist_set(alist, aimage, cpl_imagelist_get_size(alist));
141 cpl_imagelist_set(blist, dimage, cpl_imagelist_get_size(blist));
145 skip_if_lt(0, cpl_imagelist_get_size(packed),
"Too many packed frames");
148 bug_if(visir_imagelist_unpack_interm(blist));
152 cpl_imagelist_unset(blist, prevd_insert_pos);
154 for (
int i = 0; i < naxis3/2; i++) {
155 cpl_image * aimage = cpl_imagelist_get(alist, i);
156 cpl_image * dimage = cpl_imagelist_get(blist, i);
158 cpl_image * bimage = cpl_image_subtract_create(aimage, dimage);
160 visir_offset_hcycle(aimage);
161 visir_offset_hcycle(bimage);
163 bug_if(cpl_imagelist_set(blist, bimage, i));
167 skip_if_lt(0, cpl_imagelist_get_size(packed),
"Too many packed frames");
171 return cpl_error_get_code();
189 static cpl_imagelist * load_range(
const char * filename,
196 cpl_imagelist *
self = cpl_imagelist_new();
198 for (
int iplane = pstart; iplane < pend; iplane++) {
199 cpl_image * image = cpl_image_load(filename, im_type, iplane, iext);
201 if (image == NULL)
break;
203 if (cpl_imagelist_set(
self, image, selfsize)) {
204 cpl_image_delete(image);
239 const irplib_framelist * rawframes,
int pos,
240 const int planestart,
const int planeend)
243 cpl_imagelist * packed = NULL;
245 const char * file = cpl_frame_get_filename(frame);
247 visir_data_type data_type;
249 cpl_image * prevd = NULL;
250 const cpl_propertylist * plist =
252 const int iext = cpl_propertylist_has(plist,
"ZNAXIS3") ? 1 : 0;
257 skip_if(visir_get_data_type(frame, plist, &data_type, NULL));
259 cpl_ensure_code(data_type == VISIR_DATA_CUBE2, CPL_ERROR_ILLEGAL_INPUT);
265 error_if(planestart % 2 == 1, CPL_ERROR_ILLEGAL_INPUT,
266 "Plane start %d wrong. It must be even.", planestart);
267 error_if(planeend < naxis3 && planeend % 2 == 1, CPL_ERROR_ILLEGAL_INPUT,
268 "Plane end %d wrong. It must be even if not larger naxis3=%d",
271 any_if(
"Cannot split non-CUBE2 frame %d/%d in %s", 1+pos,
273 bug_if(alist == NULL);
274 bug_if(blist == NULL);
276 error_if(data_type != VISIR_DATA_CUBE2, CPL_ERROR_INCOMPATIBLE_INPUT,
277 "Cannot split non-CUBE2 frame %d/%d w. NAXIS3=%d, "
278 "NCYCLES=%d in %s", 1+pos,
281 if (planeend >= naxis3 || planeend < 0)
286 if (planestart != 0) {
287 packed = load_range(file, CPL_TYPE_UNSPECIFIED,
288 iext, planestart - 1, pend);
289 prevd = cpl_imagelist_unset(packed, 0);
292 packed = load_range(file, CPL_TYPE_UNSPECIFIED, iext, planestart, pend);
294 skip_if(visir_load_cube2_split_(alist, blist, packed, prevd));
298 cpl_image_delete(prevd);
299 cpl_imagelist_delete(packed);
301 return cpl_error_get_code();
324 cpl_error_code visir_load_burst_(cpl_imagelist * alist, cpl_imagelist * blist,
325 cpl_imagelist * packed,
326 const int ichopchange,
const int ihalfcycle,
327 const int trimlow,
int const trimhigh)
329 cpl_boolean bon = CPL_TRUE;
330 const int offset = 0;
331 const int pend = cpl_imagelist_get_size(packed);
332 int lorej = ihalfcycle - trimlow;
333 int hirej = trimhigh + 1;
337 int chpmv = ichopchange - ihalfcycle * 2;
339 cpl_ensure_code(trimhigh >= -1, CPL_ERROR_ILLEGAL_INPUT);
340 cpl_ensure_code(trimlow >= 0, CPL_ERROR_ILLEGAL_INPUT);
341 cpl_ensure_code(ichopchange < ihalfcycle * 2, CPL_ERROR_ILLEGAL_INPUT);
342 cpl_ensure_code(alist != NULL, CPL_ERROR_NULL_INPUT);
343 cpl_ensure_code(blist != NULL, CPL_ERROR_NULL_INPUT);
350 for (
int i = chpmv; i < pend; i++) {
351 if ((i + ihalfcycle * 2) % ihalfcycle == ichopchange % ihalfcycle) {
353 hirej = trimhigh + 1;
354 lorej = ihalfcycle - trimlow;
356 if (hirej <= 0 && lorej > 0 && i >= 0) {
358 cpl_image * image= cpl_imagelist_unset(packed, offset);
359 cpl_imagelist_set(alist, image, cpl_imagelist_get_size(alist));
362 cpl_image * image= cpl_imagelist_unset(packed, offset);
363 cpl_imagelist_set(blist, image, cpl_imagelist_get_size(blist));
367 cpl_image_delete(cpl_imagelist_unset(packed, offset));
373 cpl_msg_info(cpl_func,
"On: %d, Off %d, Skipped %d",
374 (
int)cpl_imagelist_get_size(alist),
375 (
int)cpl_imagelist_get_size(blist),
376 (
int)(pend - cpl_imagelist_get_size(alist)
377 - cpl_imagelist_get_size(blist)));
379 skip_if_lt(0, cpl_imagelist_get_size(packed),
"Too many packed frames");
383 return cpl_error_get_code();
397 static int get_to_off_plane(
int chopchange,
const int offset,
398 const int ihalfcycle)
400 const int ifullcycle = ihalfcycle * 2;
403 (offset / ifullcycle) * ifullcycle > chopchange)
404 chopchange += ifullcycle - (offset % ifullcycle);
406 chopchange -= (offset % ifullcycle);
433 cpl_error_code visir_load_burst(cpl_imagelist * alist, cpl_imagelist * blist,
434 const cpl_frame * frame,
const cpl_propertylist * plist,
435 const int ichopchange,
const int ihalfcycle,
436 const int planestart,
const int planeend,
437 const int trimlow,
const int trimhigh)
439 const char * file = cpl_frame_get_filename(frame);
441 const int pend = planeend <= 0 || planeend > naxis3 ? naxis3 : planeend;
442 cpl_imagelist * packed;
444 int to_off = chop_on ? get_to_off_plane(ichopchange, planestart, ihalfcycle) : 0;
446 cpl_msg_info(cpl_func,
"Loading planes %d to %d, to off %d",
447 planestart, pend, planestart + to_off);
449 packed = load_range(file, CPL_TYPE_UNSPECIFIED,
450 cpl_propertylist_has(plist,
"ZNAXIS3") ? 1 : 0,
453 skip_if(packed == NULL);
455 if (cpl_imagelist_get_size(packed) > 0) {
456 cpl_image * timg = cpl_imagelist_get(packed, 0);
457 size_t nbytes = visir_get_nbytes(timg);
458 visir_drop_cache(file, 0, nbytes * pend);
461 if (chop_on == CPL_FALSE) {
462 for (cpl_size i = 0; i < cpl_imagelist_get_size(packed); i++)
463 cpl_imagelist_set(alist, cpl_imagelist_get(packed, i), i);
465 for (cpl_size i = cpl_imagelist_get_size(packed); i-- > 0;)
466 cpl_imagelist_unset(packed, i);
470 skip_if(visir_load_burst_(alist, blist, packed, to_off, ihalfcycle,
475 cpl_imagelist_delete(packed);
477 return cpl_error_get_code();
505 const cpl_image *
self,
506 const cpl_parameterlist * parlist,
507 const char * recipename,
508 visir_chopnod_mode mode,
509 const cpl_propertylist * plist)
512 cpl_image ** combined = NULL;
514 cpl_image * inverse = cpl_image_multiply_scalar_create(
self, -1.0);
521 const double pthrow = pscale > 0.0
525 skip_if(
self == NULL);
526 skip_if(parlist == NULL);
527 skip_if(qclist == NULL);
528 skip_if(plist == NULL);
530 if (mode == VISIR_CHOPNOD_PERPENDICULAR) {
532 combined = visir_img_collapse_beam_four(qclist,
self, inverse, eccmax,
533 pthrow, angle, plist);
534 }
else if (mode == VISIR_CHOPNOD_PARALLEL) {
536 combined = visir_img_collapse_beam_three(qclist,
self, inverse, eccmax,
538 }
else if (mode == VISIR_CHOPNOD_AUTO) {
539 cpl_errorstate cleanstate = cpl_errorstate_get();
543 if (sdir != NULL && !strcmp(sdir,
"PERPENDICULAR")) {
545 combined = visir_img_collapse_beam_four(qclist,
self, inverse,
546 eccmax, pthrow, angle, plist);
547 }
else if (sdir != NULL && !strcmp(sdir,
"PARALLEL")) {
549 combined = visir_img_collapse_beam_three(qclist,
self, inverse,
550 eccmax, pthrow, plist);
553 visir_error_reset(
"Could not get FITS key");
555 cpl_msg_warning(cpl_func,
"Unknown chopping direction: %s",
558 cpl_msg_warning(cpl_func,
"Proceeding as if FITS card "
559 VISIR_PFITS_STRING_CHOPNOD_DIR
" had value: %s",
561 combined = visir_img_collapse_beam_four(qclist,
self, inverse,
562 eccmax, pthrow, angle, plist);
563 if (combined == NULL) {
564 visir_error_reset(
"Proceeding as if FITS card "
565 VISIR_PFITS_STRING_CHOPNOD_DIR
566 " had value: %s",
"PARALLEL");
567 combined = visir_img_collapse_beam_three(qclist,
self, inverse,
568 eccmax, pthrow, plist);
575 skip_if(combined == NULL);
577 bug_if (cpl_propertylist_append_double(qclist,
"ESO QC ONEBEAM THROW",
579 bug_if (cpl_propertylist_set_comment(qclist,
"ESO QC ONEBEAM THROW",
580 "The throw in pixels (TEL CHOP THROW "
581 "divided by INS PFOV)"));
583 bug_if (cpl_propertylist_set_comment(qclist,
"ESO QC ONEBEAM XPOS",
584 "The X pixel position (centroid) "
585 "of the one-beam object"));
587 bug_if (cpl_propertylist_set_comment(qclist,
"ESO QC ONEBEAM YPOS",
588 "The Y pixel position (centroid) "
589 "of the one-beam object"));
590 bug_if (cpl_propertylist_set_comment(qclist,
"ESO QC ONEBEAM ECCENTRICITY",
591 "Eccentricity: 0 for perfect, throw-"
592 "sized square/line"));
596 cpl_image_delete(inverse);
687 const cpl_parameterlist * parlist,
688 const irplib_framelist * rawframes,
692 cpl_boolean do_spc_fix,
694 visir_spc_resol resol)
696 const char * fnodpos;
698 cpl_imagelist * in = NULL;
699 cpl_image * collapsed = NULL;
700 cpl_image * prev = NULL;
701 cpl_vector * nods_vec = NULL;
703 int * nod_pos = NULL;
704 cpl_image ** images = NULL;
705 cpl_imagelist * nodded = NULL;
707 cpl_image * flat_image = NULL;
708 cpl_image * bpm_im_int = NULL;
709 cpl_mask * bpm_im_bin = NULL;
710 cpl_imagelist * hcycle = NULL;
712 cpl_boolean is_nodding = CPL_FALSE;
714 cpl_boolean auto_bpm, rem_glitch, rem_bad;
717 cpl_boolean morpho_destripe;
718 double tstart, tstop;
719 const cpl_propertylist * plist1;
721 cpl_errorstate cleanstate = cpl_errorstate_get();
723 cpl_error_code didfail = CPL_ERROR_NONE;
727 skip_if(recipename == NULL);
728 skip_if(parlist == NULL);
729 skip_if(rawframes == NULL);
736 cpl_msg_warning(cpl_func,
"Expecting even number of files, "
737 "ignoring the last of %d file(s)", nfiles);
738 error_if (nfiles == 1, CPL_ERROR_DATA_NOT_FOUND,
739 "At least two files are required");
748 CPL_TYPE_STRING, CPL_FALSE, 0.0));
750 CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
753 CPL_TYPE_INT, CPL_TRUE, 0.0));
755 CPL_TYPE_INT, CPL_TRUE, 0.0));
757 CPL_TYPE_INT, CPL_FALSE, 0.0));
759 CPL_TYPE_INT, CPL_FALSE, 0.0));
762 naxis1 = irplib_pfits_get_int(plist1,
"NAXIS1");
763 naxis2 = irplib_pfits_get_int(plist1,
"NAXIS2");
772 VISIR_PARAM_AUTOBPM);
784 VISIR_PARAM_STRIPITE);
787 morpho_destripe = ndestripe <= 0 ? CPL_FALSE :
789 VISIR_PARAM_STRIPMOR);
792 no_rem = !rem_glitch && !rem_bad;
796 nod_pos = nodding_p ? nodding_p : cpl_malloc(nfiles *
sizeof(
int));
798 if (!visir_str_par_is_empty(fnodpos)) {
800 nods_vec = cpl_vector_read(fnodpos);
801 skip_if (cpl_vector_get_size(nods_vec) != nfiles);
802 nods_data = cpl_vector_get_data(nods_vec);
804 for (i=0 ; i<nfiles ; i++) {
805 if ((
int)nods_data[i] == 0) {
808 }
else if ((
int)nods_data[i] == 1) {
810 is_nodding = CPL_TRUE;
812 error_if(1, CPL_ERROR_BAD_FILE_FORMAT,
813 "Wrong values in line %d in %s", i+1, fnodpos);
818 CPL_TYPE_STRING, CPL_FALSE, 0.0));
821 if (no_rem) cpl_msg_info(cpl_func,
"No glitch removal and no purge of bad "
822 "frames requested: Using fast I/O method");
825 if (badpix != NULL) {
827 cpl_msg_info(cpl_func,
"Loading bad pixel map from %s", badpix);
829 bpm_im_int = cpl_image_load(badpix, CPL_TYPE_INT, 0, 0);
833 bpm_im_bin = cpl_mask_threshold_image_create(bpm_im_int, -0.5, 0.5);
834 cpl_image_delete(bpm_im_int);
836 skip_if (cpl_mask_not(bpm_im_bin));
837 }
else if (auto_bpm) {
845 cpl_mask_threshold_image_create(cpl_imagelist_get(hcycle,0),
846 VISIR_HCYCLE_BPM_THRESHOLD,
848 cpl_imagelist_delete(hcycle);
855 cpl_msg_info(cpl_func,
"Divide the nodded images by the flatfield");
857 flat_image = cpl_image_load(flat, CPL_TYPE_FLOAT, 0, 0);
858 any_if (
"Cannot load the flat field %s", flat ? flat :
"<NULL>");
862 nodded = cpl_imagelist_new();
864 tstart = cpl_test_get_walltime();
868 for (i=0; i < nfiles/2 ; i++) {
869 cpl_image * empty = cpl_image_new(naxis1, naxis2, CPL_TYPE_FLOAT);
874 bug_if (cpl_imagelist_set(nodded, empty, i));
878 #pragma omp parallel for private(i) firstprivate(prev, collapsed) \
881 for (i = 0; i < nfiles ; i++) {
882 cpl_error_code errori = cpl_error_get_code();
890 if (didfail)
continue;
896 const cpl_propertylist * plist;
904 errori = cpl_error_set_where(cpl_func);
908 if (nods_vec == NULL) {
911 errori = cpl_error_set_message(cpl_func,
912 CPL_ERROR_DATA_NOT_FOUND,
913 "Cannot get nodding position "
914 "for file %d/%d", i+1, nfiles);
917 if (!strcmp(sval,
"A")) {
925 is_nodding = CPL_TRUE;
930 cpl_msg_info(cpl_func,
"File %02d: %s (%c)", i+1, file,
931 nod_pos[i]==1 ?
'+' :
'-');
934 if (is_nodding && (i & 1) == 1 && nod_pos[i] == nod_pos[i-1]) {
935 cpl_msg_error(cpl_func,
"Nodding pair (%d,%d) does not comprise an "
936 "on-object (A) and an off-object (B) image: %s", i-1,
937 i, nod_pos[i] == 1 ?
"A" :
"B");
942 if (cpl_error_get_code()) {
943 errori = cpl_error_set_where(cpl_func);
948 errori = cpl_error_set_message(cpl_func,
949 CPL_ERROR_ILLEGAL_INPUT,
950 "DIT in file %d/%d is too small: "
951 "%g", i+1, nfiles, dit);
955 factor = dit * nod_pos[i] * 2.0;
958 collapsed = visir_load_average(file, plist);
960 in = visir_load_intermint(rawframes, i);
962 errori = cpl_error_set_message(cpl_func,
963 CPL_ERROR_ILLEGAL_INPUT,
964 "Could not load image set %d",
970 if (visir_imagelist_unpack_interm(in)) {
971 errori = cpl_error_set_message(cpl_func,
972 cpl_error_get_code(),
973 "Failure for file %d/%d",
982 for (jj=0 ; jj < cpl_imagelist_get_size(in); jj++) {
983 if (visir_rem_glitch(cpl_imagelist_get(in, jj))) {
984 errori = cpl_error_set_message(cpl_func,
985 cpl_error_get_code(),
987 "glitch in image %d in "
988 "set %d", jj+1, i+1);
996 cpl_msg_info(cpl_func,
"Remove the bad A-B input images");
997 if (visir_rem_bad_images(in)) {
998 errori = cpl_error_set_message(cpl_func,
999 cpl_error_get_code(),
1000 "Could not remove bad "
1001 "images in list %d", i+1);
1006 collapsed = cpl_imagelist_collapse_create(in);
1008 cpl_imagelist_delete(in);
1013 if (cpl_error_get_code()) {
1014 errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
1015 "Failure for file %d/%d",
1021 if (cpl_image_divide_scalar(collapsed, 2*factor)) {
1022 errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
1023 "Failure for file %d/%d",
1030 if (cpl_image_add(prev, collapsed)) {
1031 errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
1032 "Failure for file %d/%d",
1036 cpl_image_delete(collapsed);
1042 if (bpm_im_bin != NULL) {
1044 if (cpl_image_reject_from_mask(prev, bpm_im_bin)) {
1045 errori = cpl_error_set_message(cpl_func,
1046 cpl_error_get_code(),
1047 "Failure for file %d/%d",
1051 if (cpl_detector_interpolate_rejected(prev)) {
1052 errori = cpl_error_set_message(cpl_func,
1053 cpl_error_get_code(),
1054 "Failure for file %d/%d",
1062 VISIR_DESTRIPE_DETECT,
1063 VISIR_DESTRIPE_DETECT_THRESHOLD,
1065 errori = cpl_error_set_message(cpl_func,
1066 cpl_error_get_code(),
1067 "Failure for file %d/%d",
1072 if (flat_image != NULL) {
1074 if (cpl_image_divide(prev, flat_image)) {
1075 errori = cpl_error_set_message(cpl_func,
1076 cpl_error_get_code(),
1077 "Failure for file %d/%d",
1083 if (cpl_imagelist_set(nodded, prev, i/2)) {
1084 errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
1085 "Failure for file %d/%d",
1100 cpl_errorstate_dump(cleanstate, CPL_FALSE, NULL);
1101 cpl_errorstate_set(cleanstate);
1104 cpl_image_delete(prev); prev = NULL;
1105 cpl_image_delete(collapsed); collapsed = NULL;
1107 #pragma omp critical(visir_inputs_combine)
1113 error_if(didfail, didfail,
"Failed to create %d nodded images from %d "
1114 "files", nnod, nfiles);
1116 tstop = cpl_test_get_walltime();
1117 cpl_msg_info(cpl_func,
"Time to create %d nodded images [s]: %g", nnod,
1120 cpl_vector_delete(nods_vec);
1123 cpl_image_delete(flat_image);
1126 cpl_mask_delete(bpm_im_bin);
1129 if (nod_pos != nodding_p) cpl_free(nod_pos);
1132 error_if(is_nodding && j != nnod, CPL_ERROR_INCOMPATIBLE_INPUT,
1133 "With nodding exactly half of the images "
1134 "must be on-object, not %d of %d", j, 2*nnod);
1138 VISIR_PARAM_SPECSKEW);
1140 VISIR_PARAM_VERTARC);
1142 VISIR_PARAM_HORIARC);
1144 VISIR_PARAM_SLITSKEW);
1151 images = cpl_malloc(nnod *
sizeof(cpl_image*));
1153 for (j = 0; j < nnod; j++) images[j] = cpl_imagelist_get(nodded, j);
1155 skip_if (visir_spc_det_fix(images, nnod, CPL_TRUE, wlen, resol,
1156 phi, ksi, eps, delta, doplot));
1161 cpl_msg_set_time_off();
1164 cpl_imagelist_delete(in);
1166 if (nod_pos != nodding_p) cpl_free(nod_pos);
1167 cpl_vector_delete(nods_vec);
1168 cpl_image_delete(bpm_im_int);
1169 cpl_mask_delete(bpm_im_bin);
1170 cpl_image_delete(collapsed);
1171 cpl_image_delete(prev);
1172 if (cpl_error_get_code() && nodded != NULL) {
1173 cpl_imagelist_delete(nodded);
1191 get_cumoffsets(
const cpl_propertylist * plist,
double * x,
double * y)
1193 cpl_errorstate cleanstate = cpl_errorstate_get();
1195 *x = irplib_pfits_get_double(plist,
"ESO DRS CUMOFFSETX");
1196 *y = irplib_pfits_get_double(plist,
"ESO DRS CUMOFFSETY");
1198 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1199 cpl_errorstate_set(cleanstate);
1200 cpl_msg_info(cpl_func,
"DRS CUMOFFSET[XY] not found, falling back"
1201 " to SEQ CUMOFFSET[XY]");
1205 return cpl_error_get_code();
1225 const cpl_parameterlist * parlist,
1226 cpl_imagelist * nodded,
1227 const cpl_propertylist ** plists,
1228 cpl_geom_combine combine_mode,
1229 cpl_boolean * pdid_resize)
1232 cpl_bivector * offsets_est = NULL;
1233 cpl_bivector * objs = NULL;
1234 cpl_image ** combined = NULL;
1235 cpl_vector * sigmas = NULL;
1236 cpl_propertylist * qclist = cpl_propertylist_new();
1241 bug_if (recipename == NULL);
1242 bug_if (parlist == NULL);
1243 bug_if (pdid_resize == NULL);
1244 bug_if (nodded == NULL);
1246 nnod = cpl_imagelist_get_size(nodded);
1251 combined = cpl_malloc(2*
sizeof(cpl_image*));
1254 combined[0] = cpl_imagelist_unset(nodded, 0);
1255 bug_if (combined[0] == NULL);
1257 combined[1] = cpl_image_new(cpl_image_get_size_x(combined[0]),
1258 cpl_image_get_size_y(combined[0]),
1260 bug_if (combined[1] == NULL);
1263 bug_if(cpl_image_threshold(combined[1], 1.0, 1.0, 1.0, 1.0));
1265 *pdid_resize = CPL_FALSE;
1268 const double psigmas[] = {5, 2, 1, 0.5};
1270 const char * offsets;
1271 const char * objects;
1273 int rej_low, rej_high;
1278 VISIR_PARAM_REFINE);
1282 VISIR_PARAM_OFFSETS);
1286 VISIR_PARAM_OBJECTS);
1293 if (sscanf(sval,
"%d-%d-%d-%d", &sx, &sy, &mx, &my) != 4)
1294 skip_if (sscanf(sval,
"%d %d %d %d", &sx, &sy, &mx, &my) != 4);
1298 VISIR_PARAM_REJECT);
1301 if (sscanf(sval,
"%d-%d", &rej_low, &rej_high) !=2 )
1302 skip_if (sscanf(sval,
"%d %d", &rej_low, &rej_high) !=2 );
1305 cpl_msg_info(cpl_func,
"Get the offsets estimation");
1306 if (!visir_str_par_is_empty(offsets)) {
1308 offsets_est = cpl_bivector_read(offsets);
1309 skip_if (offsets_est==NULL);
1311 error_if (cpl_bivector_get_size(offsets_est) != nnod,
1312 CPL_ERROR_BAD_FILE_FORMAT,
"The offsets file %s must "
1313 "have %d entries, not %d", offsets, (
int)nnod,
1314 (
int)cpl_bivector_get_size(offsets_est));
1316 double * offsets_est_x;
1317 double * offsets_est_y;
1318 double xoff0, yoff0;
1321 offsets_est = cpl_bivector_new(nnod);
1322 offsets_est_x = cpl_bivector_get_x_data(offsets_est);
1323 offsets_est_y = cpl_bivector_get_y_data(offsets_est);
1327 offsets_est_x[0] = 0.0;
1328 offsets_est_y[0] = 0.0;
1329 get_cumoffsets(plists[0], &xoff0, &yoff0);
1331 for (cpl_size i = 1; i < nnod ; i++) {
1334 skip_if(get_cumoffsets(plists[i], &xoff, &yoff));
1337 offsets_est_x[i] = xoff0 - xoff;
1338 offsets_est_y[i] = yoff0 - yoff;
1344 if (!visir_str_par_is_empty(objects)) {
1345 objs = cpl_bivector_read(objects);
1346 any_if (
"Could not read objects from %s", objects);
1349 cpl_msg_info(cpl_func,
"Recombining the list of nodded images using "
1350 "mode: %d (I=%d:U=%d:F=%d), rej-lo=%d, rej-hi=%d",
1351 combine_mode, CPL_GEOM_INTERSECT, CPL_GEOM_UNION,
1352 CPL_GEOM_FIRST, rej_low, rej_high);
1354 if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
1355 cpl_msg_debug(cpl_func,
"The offsets for the recombination:");
1356 cpl_bivector_dump(offsets_est, stdout);
1359 IRPLIB_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual);
1360 sigmas = cpl_vector_wrap(4, (
double*)psigmas);
1361 IRPLIB_DIAG_PRAGMA_POP;
1362 combined = cpl_geom_img_offset_combine(nodded, offsets_est, refine,
1363 objs, sigmas, NULL, sx, sy,
1364 mx, my, rej_low, rej_high,
1366 any_if(
"Could not recombine the images");
1368 *pdid_resize = (cpl_boolean)(cpl_image_get_size_x(combined[0])
1369 != cpl_image_get_size_x(cpl_imagelist_get_const(nodded, 0)) ||
1370 cpl_image_get_size_y(combined[0])
1371 != cpl_image_get_size_y(cpl_imagelist_get_const(nodded, 0)));
1375 visir_image_plot(
"",
"t 'The combined image'",
"", combined[0]);
1379 cpl_propertylist_delete(qclist);
1380 cpl_bivector_delete(offsets_est);
1381 cpl_bivector_delete(objs);
1382 cpl_vector_unwrap(sigmas);
1436 const cpl_parameterlist * parlist,
1437 const irplib_framelist * rawframes,
1438 const char * badpix,
1440 cpl_geom_combine combine_mode,
1441 cpl_boolean * pdid_resize,
1442 cpl_boolean do_spc_fix,
1444 visir_spc_resol resol)
1447 int * nod_pos = NULL;
1448 cpl_imagelist * nodded = NULL;
1450 cpl_bivector * objs = NULL;
1451 cpl_propertylist * qclist = cpl_propertylist_new();
1452 const cpl_propertylist ** plists = NULL;
1453 cpl_image ** rec = NULL;
1458 bug_if (recipename == NULL);
1459 bug_if (parlist == NULL);
1460 bug_if (rawframes == NULL);
1461 bug_if (pdid_resize == NULL);
1468 cpl_msg_warning(cpl_func,
"Expecting even number of files, "
1469 "ignoring the last of %d file(s)", nfiles);
1470 error_if (nfiles == 1, CPL_ERROR_DATA_NOT_FOUND,
1471 "At least two files are required");
1475 skip_if ( nfiles <= 0);
1478 nod_pos = cpl_malloc(nfiles *
sizeof(
int));
1481 cpl_msg_info(cpl_func,
"Combining the input frames into the nodded images");
1483 nod_pos, do_spc_fix, wlen, resol);
1484 skip_if(nodded == NULL);
1486 nnod = cpl_imagelist_get_size(nodded);
1487 plists = cpl_malloc(nnod *
sizeof(cpl_propertylist *));
1488 for (cpl_size i=0; i < nnod ; i++) {
1489 const cpl_size iframe = nod_pos[2*i] == 1 ? 2*i : 2*i+1;
1496 plists, combine_mode, pdid_resize);
1500 cpl_propertylist_delete(qclist);
1503 cpl_imagelist_delete(nodded);
1504 cpl_bivector_delete(objs);
1553 cpl_image * im_bpm = NULL;
1554 cpl_mask * bpm = NULL;
1555 const int upper = VISIR_HCYCLE_BPM_THRESHOLD;
1560 skip_if (
self == NULL);
1562 if (bpmfile == NULL) {
1563 bpm = cpl_mask_threshold_image_create(
self, upper, DBL_MAX);
1568 cpl_msg_info(cpl_func,
"Clean user specified bad pixels");
1570 im_bpm = cpl_image_load(bpmfile, CPL_TYPE_INT, 0, 0);
1571 any_if (
"Could not load the bad pixel map %s",
1572 bpmfile ? bpmfile :
"<NULL>");
1574 bpm = cpl_mask_threshold_image_create(im_bpm, -0.5, 0.5);
1576 cpl_image_delete(im_bpm);
1579 skip_if (cpl_mask_not(bpm));
1582 skip_if (cpl_image_reject_from_mask(
self, bpm));
1586 cpl_image_delete(im_bpm);
1587 cpl_mask_delete(bpm);
1589 return cpl_error_get_code();
1604 cpl_imagelist *
self = NULL;
1609 CPL_TYPE_INT, CPL_TRUE, 0.0));
1619 skip_if (
self == NULL);
1640 int pos, cpl_boolean is_interm)
1642 cpl_imagelist *
self = NULL;
1643 cpl_image * image = NULL;
1645 const cpl_propertylist * plist =
1647 const char * file = cpl_frame_get_filename(frame);
1650 visir_data_type data_type;
1656 skip_if (plist == NULL);
1658 skip_if(visir_get_data_type(frame, plist, &data_type, NULL));
1660 switch (data_type) {
1661 case VISIR_DATA_AQU_HCYCLE:
1662 case VISIR_DATA_AQU_BURST:
1663 case VISIR_DATA_AQU_BURST_EXT:
1664 error_if(1, CPL_ERROR_UNSUPPORTED_MODE,
1665 "Aquarius data not supported");
1671 bug_if (file == NULL);
1673 if (data_type == VISIR_DATA_CUBE1) {
1675 iplane = is_interm ? 0 : nchop;
1677 nsize = is_interm ? nchop : 1;
1679 }
else if (naxis3 == 1) {
1685 iplane = is_interm ? 1 : 0;
1690 self = cpl_imagelist_new();
1692 for (i=0 ; i < nsize; i++, iplane += plane_step) {
1694 image = cpl_image_load(file, CPL_TYPE_FLOAT, iplane, 0);
1695 skip_if (image == NULL);
1697 skip_if (!is_interm && visir_offset_hcycle(image));
1699 skip_if (cpl_imagelist_set(
self, image, i));
1704 skip_if (i < nsize);
1708 if (cpl_error_get_code()) {
1709 if (file != NULL) cpl_msg_warning(cpl_func,
"Could not load the %s "
1710 "frame(s) from: %s",
1711 is_interm ?
"INTERM" :
"Half-Cycle",
1713 cpl_image_delete(image);
1714 cpl_imagelist_delete(
self);
1749 static cpl_imagelist * visir_load_intermint(
const irplib_framelist * rawframes,
1766 static cpl_image * visir_load_average(
const char * file,
1767 const cpl_propertylist * plist)
1769 cpl_errorstate cleanstate = cpl_errorstate_get();
1770 cpl_image *
self = NULL;
1775 skip_if (file == NULL);
1776 skip_if (plist == NULL);
1783 if (nchop == 0 && naxis3 == 1) {
1784 self = cpl_image_load(file, CPL_TYPE_FLOAT, 0, 0);
1789 const int plane_offset = (naxis3 == 2 * nchop + 1) ? 2 : 3;
1792 error_if (nchop <= 0, CPL_ERROR_BAD_FILE_FORMAT,
"CHOP NCYCLES in %s "
1793 "is non-positive (and NAXIS3=%d): %d", file, naxis3, nchop);
1795 error_if (plane_offset == 3 && naxis3 != nchop+2,
1796 CPL_ERROR_BAD_FILE_FORMAT,
"NAXIS3=%d and CHOP NCYCLES=%d "
1797 "in %s is not a valid VISIR INTERM+Half-Cycle format", naxis3,
1800 if (plane_offset == 3 && nchop > 1)
1801 cpl_msg_debug(cpl_func,
"%s has %d INTERM-frames and one Half-"
1802 "Cycle frame (old CUBE1-format)", file, nchop);
1808 visir_error_reset(
"Could not get FITS key");
1810 }
else if (strlen(sval) == 0) {
1812 }
else if (plane_offset == 3) {
1813 if (strcmp(sval,
"CUBE2")==0)
1814 cpl_msg_error(cpl_func,
"%s has FRAM TYPE = CUBE2, but NAXIS3="
1815 "%d and CHOP NCYCLES=%d imply a CUBE1. Assuming"
1816 " the frame type is really CUBE1", file,
1818 }
else if (nchop > 1) {
1820 if (strcmp(sval,
"CUBE1")==0)
1821 cpl_msg_error(cpl_func,
"%s has FRAM TYPE = CUBE1, but NAXIS3="
1822 "%d and CHOP NCYCLES=%d imply a CUBE2. Assuming"
1823 "the frame type is really CUBE2", file,
1828 self = cpl_image_load(file, CPL_TYPE_FLOAT, naxis3-plane_offset, 0);
1836 if (cpl_error_get_code()) {
1837 cpl_msg_warning(cpl_func,
"Could not load the last INTERM frame from: "
1838 "%s", file ? file :
"<NULL>");
1839 cpl_image_delete(
self);
1870 static cpl_error_code visir_imagelist_unpack_interm(cpl_imagelist *
self)
1874 const int n = cpl_imagelist_get_size(
self);
1880 if (n == 1)
return CPL_ERROR_NONE;
1882 iprev = cpl_imagelist_get(
self, n - 1);
1886 skip_if (cpl_image_multiply_scalar(iprev, n));
1889 for (i = n-1 ; i > 1 ; i--, iprev = image) {
1890 image = cpl_imagelist_get(
self, i-1);
1894 skip_if (cpl_image_multiply_scalar(image, i));
1896 skip_if (cpl_image_subtract(iprev, image));
1900 image = cpl_imagelist_get(
self, 0);
1904 skip_if (cpl_image_subtract(iprev, image));
1908 return cpl_error_get_code();
1925 static cpl_error_code visir_rem_glitch(cpl_image * glitchy)
1927 cpl_image * med_filt = NULL;
1928 cpl_mask * bpm = NULL;
1929 cpl_mask * kernel = cpl_mask_new(3, 3);
1931 double low_thresh, high_thresh;
1932 const int nx = cpl_image_get_size_x(glitchy);
1933 const int ny = cpl_image_get_size_y(glitchy);
1937 double factor1 = 3.0;
1938 double factor2 = 10.0;
1939 const int niterations = 5;
1940 const double median_corr = 1.5;
1945 bug_if(cpl_mask_not(kernel));
1948 med_filt = cpl_image_new(cpl_image_get_size_x(glitchy),
1949 cpl_image_get_size_y(glitchy),
1950 cpl_image_get_type(glitchy));
1951 bug_if(med_filt == NULL);
1952 bug_if(cpl_image_filter_mask(med_filt, glitchy, kernel, CPL_FILTER_MEDIAN,
1953 CPL_BORDER_FILTER));
1954 cpl_mask_delete(kernel);
1958 skip_if (cpl_image_subtract(glitchy, med_filt));
1961 for (i=0 ; i < niterations ; i++) {
1963 mean = cpl_image_get_mean(glitchy);
1964 stdev = cpl_image_get_stdev(glitchy);
1969 low_thresh = mean - factor1 * stdev;
1970 high_thresh = mean + factor1 * stdev;
1973 bpm = cpl_mask_threshold_image_create(glitchy,low_thresh,high_thresh);
1974 skip_if (cpl_mask_not(bpm));
1975 skip_if (cpl_image_reject_from_mask(glitchy, bpm));
1976 cpl_mask_delete(bpm);
1980 skip_if (cpl_image_count_rejected(glitchy) == nx*ny);
1985 mean = cpl_image_get_mean(glitchy);
1986 stdev = cpl_image_get_stdev(glitchy) * median_corr;
1990 low_thresh = mean - factor2 * stdev;
1991 high_thresh = mean + factor2 * stdev;
1993 bpm = cpl_mask_threshold_image_create(glitchy, low_thresh, high_thresh);
1994 skip_if (cpl_mask_not(bpm));
1995 skip_if (cpl_image_reject_from_mask(glitchy, bpm));
1996 cpl_mask_delete(bpm);
2000 skip_if (cpl_image_count_rejected(glitchy) == nx*ny);
2003 skip_if (cpl_image_fill_rejected(glitchy, 0.0));
2004 skip_if (cpl_image_accept_all(glitchy));
2007 skip_if (cpl_image_add(glitchy, med_filt));
2011 cpl_image_delete(med_filt);
2012 cpl_mask_delete(bpm);
2013 cpl_mask_delete(kernel);
2015 return cpl_error_get_code();
2030 static cpl_error_code visir_rem_bad_images(cpl_imagelist * in)
2032 cpl_vector * medians = NULL;
2033 cpl_vector * stdevs = NULL;
2034 cpl_vector * selection = NULL;
2035 double mean_medians, mean_stdevs, stdev_medians, stdev_stdevs;
2036 const double threshold = 3;
2037 const int nima = cpl_imagelist_get_size(in);
2044 if (nima <= 3)
return CPL_ERROR_NONE;
2047 medians = cpl_vector_new(nima);
2048 stdevs = cpl_vector_new(nima);
2051 for (i=0 ; i < nima ; i++) {
2052 cpl_stats * stats = cpl_stats_new_from_image(cpl_imagelist_get(in, i),
2053 CPL_STATS_STDEV | CPL_STATS_MEDIAN);
2055 cpl_vector_set(medians, i, cpl_stats_get_median(stats));
2056 cpl_vector_set(stdevs, i, cpl_stats_get_stdev(stats));
2057 cpl_stats_delete(stats);
2063 mean_medians = cpl_vector_get_mean(medians);
2064 stdev_medians = cpl_vector_get_stdev(medians);
2065 mean_stdevs = cpl_vector_get_mean(stdevs);
2066 stdev_stdevs = cpl_vector_get_stdev(stdevs);
2068 skip_if (cpl_vector_subtract_scalar(medians, mean_medians));
2069 skip_if (cpl_vector_subtract_scalar(stdevs, mean_stdevs));
2071 stdev_medians *= threshold;
2072 stdev_stdevs *= threshold;
2075 selection = cpl_vector_new(nima);
2076 skip_if( cpl_vector_fill(selection, 0));
2077 for (i=0 ; i < nima ; i++) {
2078 if (fabs(cpl_vector_get(medians, i)) <= stdev_medians &&
2079 fabs(cpl_vector_get(stdevs, i)) <= stdev_stdevs)
continue;
2081 cpl_vector_set(selection, i, -1);
2082 cpl_msg_info(cpl_func,
"Image %d of %d rejected: median=%g, stdev=%g",
2083 i+1, nima, stdev_medians, stdev_stdevs);
2087 cpl_imagelist_erase(in, selection);
2091 cpl_vector_delete(medians);
2092 cpl_vector_delete(stdevs);
2094 cpl_vector_delete(selection);
2096 return CPL_ERROR_NONE;
2110 static cpl_error_code visir_offset_hcycle(cpl_image * hcycle)
2117 skip_if (cpl_image_add_scalar(hcycle, VISIR_HCYCLE_OFFSET));
2119 minval = cpl_image_get_min(hcycle);
2122 if (minval < 1) cpl_msg_warning(cpl_func,
"HCycle pixel minval: %g", minval);
2126 return CPL_ERROR_NONE;
2143 cpl_image ** visir_img_collapse_beam_four(cpl_propertylist * qclist,
2144 const cpl_image *
self,
2145 const cpl_image * inverse,
2149 const cpl_propertylist * plist)
2152 cpl_image ** combined = NULL;
2153 const int nx = cpl_image_get_size_x(
self);
2154 const int ny = cpl_image_get_size_y(
self);
2155 const cpl_type type = cpl_image_get_type(
self);
2156 cpl_imagelist * list4 = cpl_imagelist_new();
2157 IRPLIB_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual);
2158 cpl_image * swrap = type == CPL_TYPE_DOUBLE
2159 ? cpl_image_wrap_double(nx, ny, cpl_image_get_data((cpl_image*)
self))
2160 : cpl_image_wrap_float(nx, ny, cpl_image_get_data((cpl_image*)self));
2161 cpl_image * iwrap = type == CPL_TYPE_DOUBLE
2162 ? cpl_image_wrap_double(nx, ny, cpl_image_get_data((cpl_image*)inverse))
2163 : cpl_image_wrap_float(nx, ny, cpl_image_get_data((cpl_image*)inverse));
2164 IRPLIB_DIAG_PRAGMA_POP;
2165 cpl_bivector * offs = cpl_bivector_new(4);
2166 double * x4 = cpl_bivector_get_x_data(offs);
2167 double * y4 = cpl_bivector_get_y_data(offs);
2168 double pos_x, pos_y;
2172 skip_if(plist == NULL);
2174 skip_if(visir_img_find_beam_four(qclist,
self, inverse, eccmax, pthrow,
2178 for (
int i = 1; i < 4; i++) {
2179 x4[i] = x4[0] - x4[i];
2180 y4[i] = y4[0] - y4[i];
2183 bug_if (cpl_propertylist_append_double(qclist,
"ESO QC ONEBEAM XPOS",
2185 bug_if (cpl_propertylist_append_double(qclist,
"ESO QC ONEBEAM YPOS",
2187 x4[0] = y4[0] = 0.0;
2189 IRPLIB_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual);
2190 bug_if(cpl_imagelist_set(list4, (cpl_image*)
self, 0));
2191 bug_if(cpl_imagelist_set(list4, swrap, 1));
2192 bug_if(cpl_imagelist_set(list4, (cpl_image*)inverse, 2));
2193 bug_if(cpl_imagelist_set(list4, iwrap, 3));
2194 IRPLIB_DIAG_PRAGMA_POP;
2196 combined = cpl_geom_img_offset_saa(list4, offs, CPL_KERNEL_DEFAULT, 0, 0,
2197 CPL_GEOM_FIRST, &pos_x, &pos_y);
2199 skip_if(combined == NULL);
2203 cpl_bivector_delete(offs);
2204 visir_imagelist_unwrap(list4);
2205 (void)cpl_image_unwrap(swrap);
2206 (void)cpl_image_unwrap(iwrap);
2207 if (cpl_error_get_code() && combined != NULL) {
2208 cpl_image_delete(combined[0]);
2209 cpl_image_delete(combined[1]);
2231 visir_chopnod_mode visir_img_find_beam(cpl_propertylist * qclist,
2232 const cpl_image *
self,
2233 const cpl_image * inverse,
2234 const cpl_propertylist * plist,
2235 const cpl_parameterlist * parlist,
2236 const char * recipename,
2241 cpl_errorstate cleanstate = cpl_errorstate_get();
2242 visir_chopnod_mode mode = VISIR_CHOPNOD_AUTO;
2245 VISIR_PARAM_ECCMAX);
2251 const double pthrow = pscale > 0.0
2253 const cpl_boolean chop_on =
2254 cpl_propertylist_get_bool(plist, VISIR_PFITS_BOOL_CHOP_STATUS);
2257 skip_if(x4 == NULL);
2258 skip_if(y4 == NULL);
2259 skip_if(
self == NULL);
2260 skip_if(inverse == NULL);
2261 skip_if(parlist == NULL);
2262 skip_if(recipename == NULL);
2263 skip_if(qclist == NULL);
2267 if (sdir != NULL && !strcmp(sdir,
"PERPENDICULAR")) {
2270 mode = VISIR_CHOPNOD_PERPENDICULAR;
2273 skip_if (visir_img_find_beam_four(qclist,
self, inverse, eccmax,
2274 pthrow, angle, x4, y4));
2276 skip_if (visir_img_find_beam_two(qclist,
self, inverse, eccmax,
2277 pthrow, angle, x4, y4, CPL_TRUE));
2279 }
else if (sdir != NULL && !strcmp(sdir,
"PARALLEL")) {
2282 mode = VISIR_CHOPNOD_PARALLEL;
2285 skip_if (visir_img_find_beam_three(qclist,
self, inverse, eccmax,
2286 pthrow, angle, x4, y4));
2288 skip_if (visir_img_find_beam_two(qclist,
self, inverse, eccmax,
2289 pthrow, angle, x4, y4, CPL_FALSE));
2293 visir_error_reset(
"Could not get FITS key");
2295 cpl_msg_warning(cpl_func,
"Unknown chopping direction: %s",
2298 cpl_msg_warning(cpl_func,
"Proceeding as if FITS card "
2299 VISIR_PFITS_STRING_CHOPNOD_DIR
" had value: %s",
2302 if (visir_img_find_beam_four(qclist,
self, inverse, eccmax,
2303 pthrow, angle, x4, y4)) {
2305 visir_error_reset(
"Proceeding as if FITS card "
2306 VISIR_PFITS_STRING_CHOPNOD_DIR
2307 " had value: %s",
"PARALLEL");
2309 skip_if (visir_img_find_beam_three(qclist,
self, inverse,
2310 eccmax, pthrow, angle,
2314 mode = VISIR_CHOPNOD_PARALLEL;
2318 mode = VISIR_CHOPNOD_PERPENDICULAR;
2322 bug_if (cpl_propertylist_append_double(qclist,
"ESO QC ONEBEAM THROW",
2324 bug_if (cpl_propertylist_set_comment(qclist,
"ESO QC ONEBEAM THROW",
2325 "The throw in pixels (TEL CHOP THROW "
2326 "divided by INS PFOV)"));
2348 cpl_error_code visir_img_find_beam_four(cpl_propertylist * qclist,
2349 const cpl_image *
self,
2350 const cpl_image * inverse,
2358 cpl_errorstate cleanstate = cpl_errorstate_get();
2359 cpl_apertures * appos = NULL;
2360 cpl_apertures * apneg = NULL;
2361 const double psigmas[] = {2.0, 1.0, 0.5};
2362 const int nsigmas =
sizeof(psigmas)/
sizeof(
double);
2364 int iappos2[] = {1, 2};
2365 int iapneg2[] = {1, 2};
2368 skip_if(
self == NULL);
2369 skip_if(qclist == NULL);
2370 skip_if(pthrow <= 0.0);
2371 skip_if(x4 == NULL);
2372 skip_if(y4 == NULL);
2374 cpl_msg_info(cpl_func,
"Detecting the 4-beam object with %g pixel throw "
2375 "using %d sigma-levels ranging from %g down to %g", pthrow,
2376 nsigmas, psigmas[0], psigmas[nsigmas-1]);
2379 for (isigma = 0; isigma < nsigmas; isigma++) {
2384 cpl_apertures_delete(appos);
2385 appos = cpl_apertures_extract_sigma(
self, psigmas[isigma]);
2387 if (appos != NULL) {
2388 npos = cpl_apertures_get_size(appos);
2393 cpl_apertures_delete(apneg);
2394 apneg = cpl_apertures_extract_sigma(inverse, psigmas[isigma]);
2395 if (apneg != NULL) {
2396 nneg = cpl_apertures_get_size(apneg);
2399 cpl_msg_info(cpl_func,
"Found %d positive (need 2) and %d negative "
2400 "(need 2) object(s) at sigma=%g (%d of %d)", npos, nneg,
2401 psigmas[isigma], 1+isigma, nsigmas);
2404 error_if(npos * nneg > FIND_BEAM_MAX_APERTURES_SQR,
2405 CPL_ERROR_DATA_NOT_FOUND,
"Too many objects found, aborting");
2409 double eccbest = eccmax;
2410 double eccmin = DBL_MAX;
2411 double fluxbest = 0.0;
2412 double fluxecc = DBL_MAX;
2413 cpl_boolean is_first = CPL_TRUE;
2416 #pragma omp parallel for private(ipos1)
2418 for (ipos1 = 2; ipos1 < 1 + npos; ipos1++) {
2419 int ipos2, ineg1, ineg2;
2420 for (ipos2 = 1; ipos2 < ipos1; ipos2++) {
2421 for (ineg1 = 2; ineg1 < 1 + nneg; ineg1++) {
2422 for (ineg2 = 1; ineg2 < ineg1; ineg2++) {
2423 cpl_boolean swappos, swapneg;
2425 = visir_img_check_box(appos, ipos1, ipos2,
2426 apneg, ineg1, ineg2,
2427 pthrow, angle, &swappos,
2431 = cpl_apertures_get_flux(appos, ipos1)
2432 + cpl_apertures_get_flux(appos, ipos2)
2433 + cpl_apertures_get_flux(apneg, ineg1)
2434 + cpl_apertures_get_flux(apneg, ineg2);
2437 if (ecc < 0.0 || flux <= 0.0 ||
2438 !cpl_errorstate_is_equal(cleanstate)) {
2439 irplib_error_recover(cleanstate,
"Invalid 4-"
2440 "object (%d & %d of %d, "
2443 ineg2, ineg1, nneg);
2448 #pragma omp critical(visir_img_find_beam_four_min)
2456 if (eccmax <= ecc)
continue;
2459 #pragma omp critical(visir_img_find_beam_four_ok)
2461 if (is_first || ecc * fluxbest < eccbest * flux)
2464 is_first = CPL_FALSE;
2465 cpl_msg_info(cpl_func,
"Found 4 object "
2466 "positions with throw-"
2467 "scaled eccentricity %g "
2468 "and flux %g", ecc, flux);
2470 cpl_msg_info(cpl_func,
"Found 4 object "
2471 "positions with throw-"
2472 "scaled eccentricity %g "
2473 "< %g and/or flux %g > %g",
2474 ecc, eccbest, flux, fluxbest);
2478 iappos2[0] = swappos ? ipos2 : ipos1;
2479 iappos2[1] = swappos ? ipos1 : ipos2;
2480 iapneg2[0] = swapneg ? ineg2 : ineg1;
2481 iapneg2[1] = swapneg ? ineg1 : ineg2;
2487 if (eccbest < eccmax) {
2488 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC ONEBEAM "
2489 "ECCENTRICITY", eccbest));
2493 if (eccmin < DBL_MAX) {
2494 cpl_msg_info(cpl_func,
"Found 4 sigma-%g object positions with "
2495 "too large throw-scaled eccentricity %g >= %g and "
2496 "flux %g", psigmas[isigma], eccmin, eccmax,
2499 }
else if (npos >= 2 && nneg >= 2) {
2500 cpl_apertures_sort_by_flux(appos);
2501 cpl_apertures_sort_by_flux(apneg);
2505 if (isigma + 1 < nsigmas) {
2506 irplib_error_recover(cleanstate,
"4-Beam positions not found among "
2507 "%d postive and %d negative object(s) at "
2508 "sigma=%g, (%d of %d)", npos, nneg,
2509 psigmas[isigma], 1+isigma, nsigmas);
2513 error_if (isigma == nsigmas, CPL_ERROR_DATA_NOT_FOUND,
2514 "4-Beam positions not found w. %d sigma(s) down to %g",
2515 nsigmas, psigmas[nsigmas - 1]);
2517 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
2518 cpl_apertures_dump(appos, stdout);
2519 cpl_apertures_dump(apneg, stdout);
2522 x4[0] = cpl_apertures_get_centroid_x(appos, iappos2[0]);
2523 y4[0] = cpl_apertures_get_centroid_y(appos, iappos2[0]);
2524 x4[1] = cpl_apertures_get_centroid_x(appos, iappos2[1]);
2525 y4[1] = cpl_apertures_get_centroid_y(appos, iappos2[1]);
2527 x4[2] = cpl_apertures_get_centroid_x(apneg, iapneg2[0]);
2528 y4[2] = cpl_apertures_get_centroid_y(apneg, iapneg2[0]);
2529 x4[3] = cpl_apertures_get_centroid_x(apneg, iapneg2[1]);
2530 y4[3] = cpl_apertures_get_centroid_y(apneg, iapneg2[1]);
2532 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC ONEBEAM FLUX",
2533 cpl_apertures_get_flux(appos,
2536 cpl_msg_info(cpl_func,
"Centroid of positive object 1 [pixel]: %g %g",
2538 cpl_msg_info(cpl_func,
"Centroid of positive object 2 [pixel]: %g %g",
2541 cpl_msg_info(cpl_func,
"Centroid of negative object 1 [pixel]: %g %g",
2543 cpl_msg_info(cpl_func,
"Centroid of negative object 2 [pixel]: %g %g",
2546 cpl_msg_info(cpl_func,
"Expected object distance (chop throw) [pixel]: %g",
2548 cpl_msg_info(cpl_func,
"Object Pos -> Pos x/y-distance [pixel]: %g %g",
2549 x4[1] - x4[0], y4[1] - y4[0]);
2550 cpl_msg_info(cpl_func,
"Object Neg -> Neg x/y-distance [pixel]: %g %g",
2551 x4[3] - x4[2], y4[3] - y4[2]);
2552 cpl_msg_info(cpl_func,
"Object Pos -> Pos angle [degrees]: %g",
2553 atan2(y4[1] - y4[0], x4[1] - x4[0]) * CPL_MATH_DEG_RAD);
2554 cpl_msg_info(cpl_func,
"Object Neg -> Neg angle [degrees]: %g",
2555 atan2(y4[3] - y4[2], x4[3] - x4[2]) * CPL_MATH_DEG_RAD);
2559 cpl_apertures_delete(appos);
2560 cpl_apertures_delete(apneg);
2562 return cpl_error_get_code();
2579 cpl_image ** visir_img_collapse_beam_three(cpl_propertylist * qclist,
2580 const cpl_image *
self,
2581 const cpl_image * inverse,
2584 const cpl_propertylist * plist)
2587 cpl_image ** combined = NULL;
2588 const int nx = cpl_image_get_size_x(
self);
2589 const int ny = cpl_image_get_size_y(
self);
2590 const cpl_type type = cpl_image_get_type(
self);
2591 cpl_imagelist * list3 = cpl_imagelist_new();
2592 IRPLIB_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual);
2593 cpl_image * iwrap = type == CPL_TYPE_DOUBLE
2594 ? cpl_image_wrap_double(nx, ny, cpl_image_get_data((cpl_image*)inverse))
2595 : cpl_image_wrap_float(nx, ny, cpl_image_get_data((cpl_image*)inverse));
2596 IRPLIB_DIAG_PRAGMA_POP;
2597 cpl_bivector * offs = cpl_bivector_new(3);
2598 double * x3 = cpl_bivector_get_x_data(offs);
2599 double * y3 = cpl_bivector_get_y_data(offs);
2600 double pos_x, pos_y;
2605 skip_if(plist == NULL);
2607 skip_if(visir_img_find_beam_three(qclist,
self, inverse, eccmax, pthrow,
2611 for (
int i = 1; i < 3; i++) {
2612 x3[i] = x3[0] - x3[i];
2613 y3[i] = y3[0] - y3[i];
2615 bug_if (cpl_propertylist_append_double(qclist,
"ESO QC ONEBEAM XPOS",
2617 bug_if (cpl_propertylist_append_double(qclist,
"ESO QC ONEBEAM YPOS",
2620 x3[0] = y3[0] = 0.0;
2622 IRPLIB_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual);
2623 bug_if(cpl_imagelist_set(list3, (cpl_image*)
self, 0));
2624 bug_if(cpl_imagelist_set(list3, (cpl_image*)inverse, 1));
2625 bug_if(cpl_imagelist_set(list3, iwrap, 2));
2626 IRPLIB_DIAG_PRAGMA_POP;
2628 combined = cpl_geom_img_offset_saa(list3, offs, CPL_KERNEL_DEFAULT, 0, 0,
2629 CPL_GEOM_FIRST, &pos_x, &pos_y);
2631 skip_if(combined == NULL);
2635 cpl_bivector_delete(offs);
2636 visir_imagelist_unwrap(list3);
2637 (void)cpl_image_unwrap(iwrap);
2638 if (cpl_error_get_code() && combined != NULL) {
2639 cpl_image_delete(combined[0]);
2640 cpl_image_delete(combined[1]);
2664 cpl_error_code visir_img_find_beam_three(cpl_propertylist * qclist,
2665 const cpl_image *
self,
2666 const cpl_image * inverse,
2674 cpl_errorstate cleanstate = cpl_errorstate_get();
2675 cpl_apertures * appos = NULL;
2676 cpl_apertures * apneg = NULL;
2677 const double psigmas[] = {2.0, 1.0, 0.5};
2678 const int nsigmas =
sizeof(psigmas)/
sizeof(
double);
2680 int iappos [] = {1};
2681 int iapneg2[] = {1, 2};
2684 skip_if(
self == NULL);
2685 skip_if(qclist == NULL);
2686 skip_if(pthrow <= 0.0);
2687 skip_if(eccmax < 0.0);
2688 skip_if(x3 == NULL);
2689 skip_if(y3 == NULL);
2692 cpl_msg_info(cpl_func,
"Detecting the 3-beam object with %g pixel throw "
2693 "using %d sigma-levels ranging from %g down to %g", pthrow,
2694 nsigmas, psigmas[0], psigmas[nsigmas-1]);
2697 for (isigma = 0; isigma < nsigmas; isigma++) {
2702 cpl_apertures_delete(appos);
2703 appos = cpl_apertures_extract_sigma(
self, psigmas[isigma]);
2705 if (appos != NULL) {
2706 npos = cpl_apertures_get_size(appos);
2711 cpl_apertures_delete(apneg);
2712 apneg = cpl_apertures_extract_sigma(inverse, psigmas[isigma]);
2713 if (apneg != NULL) {
2714 nneg = cpl_apertures_get_size(apneg);
2717 cpl_msg_info(cpl_func,
"Found %d positive (need 1) and %d negative "
2718 "(need 2) object(s) at sigma=%g (%d of %d)", npos, nneg,
2719 psigmas[isigma], 1+isigma, nsigmas);
2723 double eccbest = eccmax;
2724 double eccmin = DBL_MAX;
2725 double fluxbest = 0.0;
2726 double fluxecc = DBL_MAX;
2727 cpl_boolean is_first = CPL_TRUE;
2730 #pragma omp parallel for private(ipos)
2732 for (ipos = 1; ipos < 1 + npos; ipos++) {
2734 for (ineg1 = 2; ineg1 < 1 + nneg; ineg1++) {
2735 for (ineg2 = 1; ineg2 < ineg1; ineg2++) {
2736 cpl_boolean swapneg;
2739 = visir_img_check_align(appos, ipos, apneg, ineg1,
2740 ineg2, pthrow, angle,
2744 = cpl_apertures_get_flux(appos, ipos)
2745 + cpl_apertures_get_flux(apneg, ineg1)
2746 + cpl_apertures_get_flux(apneg, ineg2);
2749 if (ecc < 0.0 || flux <= 0.0 ||
2750 !cpl_errorstate_is_equal(cleanstate)) {
2751 irplib_error_recover(cleanstate,
"Invalid 3-"
2752 "object (%d of %d, "
2755 ineg2, ineg1, nneg);
2760 #pragma omp critical(visir_img_collapse_beam_three_min)
2768 if (eccmax <= ecc)
continue;
2771 #pragma omp critical(visir_img_collapse_beam_three_ok)
2773 if (is_first || ecc * fluxbest < eccbest * flux)
2776 is_first = CPL_FALSE;
2777 cpl_msg_info(cpl_func,
"Found 3 object posi"
2778 "tions with throw-scaled "
2779 "eccentricity %g and flux %g",
2782 cpl_msg_info(cpl_func,
"Found 3 object posi"
2783 "tions with throw-scaled "
2784 "eccentricity %g < %g and/or "
2785 "flux %g > %g", ecc, eccbest,
2791 iapneg2[0] = swapneg ? ineg2 : ineg1;
2792 iapneg2[1] = swapneg ? ineg1 : ineg2;
2797 if (eccbest < eccmax) {
2798 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC ONEBEAM "
2799 "ECCENTRICITY", eccbest));
2802 if (eccmin < DBL_MAX) {
2803 cpl_msg_info(cpl_func,
"Found 3 sigma-%g object positions with "
2804 "too large throw-scaled eccentricity %g >= %g and "
2805 "flux %g", psigmas[isigma], eccmin, eccmax,
2808 }
else if (npos >= 1 && nneg >= 2) {
2809 cpl_apertures_sort_by_flux(appos);
2810 cpl_apertures_sort_by_flux(apneg);
2814 if (isigma + 1 < nsigmas) {
2815 irplib_error_recover(cleanstate,
"3-Beam positions not found among "
2816 "%d postive and %d negative object(s) at "
2817 "sigma=%g, (%d of %d)", npos, nneg,
2818 psigmas[isigma], 1+isigma, nsigmas);
2822 error_if (isigma == nsigmas, CPL_ERROR_DATA_NOT_FOUND,
2823 "3-Beam positions not found w. %d sigma(s) down to %g",
2824 nsigmas, psigmas[nsigmas - 1]);
2826 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
2827 cpl_apertures_dump(appos, stdout);
2828 cpl_apertures_dump(apneg, stdout);
2831 x3[0] = cpl_apertures_get_centroid_x(appos, iappos[0]);
2832 y3[0] = cpl_apertures_get_centroid_y(appos, iappos[0]);
2834 x3[1] = cpl_apertures_get_centroid_x(apneg, iapneg2[0]);
2835 y3[1] = cpl_apertures_get_centroid_y(apneg, iapneg2[0]);
2836 x3[2] = cpl_apertures_get_centroid_x(apneg, iapneg2[1]);
2837 y3[2] = cpl_apertures_get_centroid_y(apneg, iapneg2[1]);
2839 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC ONEBEAM FLUX",
2840 cpl_apertures_get_flux(appos,
2843 cpl_msg_info(cpl_func,
"Centroid of positive object [pixel]: %g %g",
2846 cpl_msg_info(cpl_func,
"Centroid of negative object 1 [pixel]: %g %g",
2848 cpl_msg_info(cpl_func,
"Centroid of negative object 2 [pixel]: %g %g",
2851 cpl_msg_info(cpl_func,
"Expected object distance (chop throw) [pixel]: %g",
2853 cpl_msg_info(cpl_func,
"Object Neg1 -> Pos x/y-distance [pixel]: %g %g",
2854 x3[2] - x3[0], y3[2] - y3[0]);
2855 cpl_msg_info(cpl_func,
"Object Pos -> Neg2 x/y-distance [pixel]: %g %g",
2856 x3[0] - x3[1], y3[0] - y3[1]);
2860 cpl_apertures_delete(appos);
2861 cpl_apertures_delete(apneg);
2863 return cpl_error_get_code();
2884 cpl_error_code visir_img_find_beam_two(cpl_propertylist * qclist,
2885 const cpl_image *
self,
2886 const cpl_image * inverse,
2895 cpl_errorstate cleanstate = cpl_errorstate_get();
2896 cpl_apertures * appos = NULL;
2897 cpl_apertures * apneg = NULL;
2898 const double psigmas[] = {2.0, 1.0, 0.5};
2899 const int nsigmas =
sizeof(psigmas)/
sizeof(
double);
2905 skip_if(
self == NULL);
2906 skip_if(qclist == NULL);
2907 skip_if(eccmax < 0.0);
2908 skip_if(x2 == NULL);
2909 skip_if(y2 == NULL);
2912 cpl_msg_info(cpl_func,
"Detecting the 2-beam object (Pos -> Neg) with "
2913 "%g pixel throw using %d sigma-levels ranging from %g down"
2914 " to %g", pthrow, nsigmas, psigmas[0], psigmas[nsigmas-1]);
2915 }
else if (pthrow < 0.0) {
2916 cpl_msg_info(cpl_func,
"Detecting the 2-beam object (Neg -> Pos) with "
2917 "%g pixel throw using %d sigma-levels ranging from %g down"
2918 " to %g", pthrow, nsigmas, psigmas[0], psigmas[nsigmas-1]);
2924 for (isigma = 0; isigma < nsigmas; isigma++) {
2929 cpl_apertures_delete(appos);
2930 appos = cpl_apertures_extract_sigma(
self, psigmas[isigma]);
2932 if (appos != NULL) {
2933 npos = cpl_apertures_get_size(appos);
2938 cpl_apertures_delete(apneg);
2939 apneg = cpl_apertures_extract_sigma(inverse, psigmas[isigma]);
2940 if (apneg != NULL) {
2941 nneg = cpl_apertures_get_size(apneg);
2944 cpl_msg_info(cpl_func,
"Found %d positive (need 1) and %d negative "
2945 "(need 1) object(s) at sigma=%g (%d of %d)", npos, nneg,
2946 psigmas[isigma], 1+isigma, nsigmas);
2950 double eccbest = eccmax;
2951 double eccmin = DBL_MAX;
2952 double fluxbest = 0.0;
2953 double fluxecc = DBL_MAX;
2954 cpl_boolean is_first = CPL_TRUE;
2957 #pragma omp parallel for private(ipos)
2959 for (ipos = 1; ipos < 1 + npos; ipos++) {
2961 for (ineg = 1; ineg < 1 + nneg; ineg++) {
2963 visir_img_check_line(appos, ipos, apneg, ineg,
2967 = cpl_apertures_get_flux(appos, ipos)
2968 + cpl_apertures_get_flux(apneg, ineg);
2971 if (ecc < 0.0 || flux <= 0.0 ||
2972 !cpl_errorstate_is_equal(cleanstate)) {
2973 irplib_error_recover(cleanstate,
"Invalid 2-"
2974 "object (%d of %d, "
2982 #pragma omp critical(visir_img_collapse_beam_two_min)
2990 if (eccmax <= ecc)
continue;
2993 #pragma omp critical(visir_img_collapse_beam_two_ok)
2995 if (is_first || ecc * fluxbest < eccbest * flux)
2998 is_first = CPL_FALSE;
2999 cpl_msg_info(cpl_func,
"Found 2 object posi"
3000 "tions with throw-scaled eccen"
3001 "tricity %g and flux %g", ecc,
3004 cpl_msg_info(cpl_func,
"Found 2 object posi"
3005 "tions with throw-scaled eccen"
3006 "tricity %g < %g and/or flux %g "
3007 "> %g", ecc, eccbest, flux,
3017 if (eccbest < eccmax) {
3018 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC ONEBEAM "
3019 "ECCENTRICITY", eccbest));
3022 if (eccmin < DBL_MAX) {
3023 cpl_msg_info(cpl_func,
"Found 2 sigma-%g object positions with "
3024 "too large throw-scaled eccentricity %g >= %g and "
3025 "flux %g", psigmas[isigma], eccmin, eccmax,
3028 }
else if (npos >= 1 && nneg >= 2) {
3029 cpl_apertures_sort_by_flux(appos);
3030 cpl_apertures_sort_by_flux(apneg);
3034 if (isigma + 1 < nsigmas) {
3035 irplib_error_recover(cleanstate,
"2-Beam positions not found among "
3036 "%d postive and %d negative object(s) at "
3037 "sigma=%g, (%d of %d)", npos, nneg,
3038 psigmas[isigma], 1+isigma, nsigmas);
3042 error_if (isigma == nsigmas, CPL_ERROR_DATA_NOT_FOUND,
3043 "2-Beam positions not found w. %d sigma(s) down to %g",
3044 nsigmas, psigmas[nsigmas - 1]);
3046 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
3047 cpl_apertures_dump(appos, stdout);
3048 cpl_apertures_dump(apneg, stdout);
3051 x2[0] = cpl_apertures_get_centroid_x(appos, iappos[0]);
3052 y2[0] = cpl_apertures_get_centroid_y(appos, iappos[0]);
3054 x2[1] = cpl_apertures_get_centroid_x(apneg, iapneg[0]);
3055 y2[1] = cpl_apertures_get_centroid_y(apneg, iapneg[0]);
3057 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC ONEBEAM FLUX",
3058 cpl_apertures_get_flux(appos,
3061 cpl_msg_info(cpl_func,
"Centroid of positive object [pixel]: %g %g",
3064 cpl_msg_info(cpl_func,
"Centroid of negative object [pixel]: %g %g",
3068 cpl_msg_info(cpl_func,
"Expected object distance (chop throw) "
3069 "[pixel]: %g", pthrow);
3071 cpl_msg_info(cpl_func,
"Object Pos -> Neg x/y-distance [pixel]: %g %g",
3072 x2[1] - x2[0], y2[1] - y2[0]);
3074 cpl_msg_info(cpl_func,
"Expected object distance (chop throw) "
3075 "[pixel]: %g", -pthrow);
3077 cpl_msg_info(cpl_func,
"Object Neg -> x/y-distance [pixel]: %g %g",
3078 x2[0] - x2[1], y2[0] - y2[1]);
3083 cpl_apertures_delete(appos);
3084 cpl_apertures_delete(apneg);
3086 return cpl_error_get_code();
3112 double visir_img_check_box(
const cpl_apertures * appos,
3113 int ipos1,
int ipos2,
3114 const cpl_apertures * apneg,
3115 int ineg1,
int ineg2,
double ssize,
double angle,
3116 cpl_boolean * pswapp, cpl_boolean * pswapn)
3122 double xp1 = cpl_apertures_get_centroid_x(appos, ipos1) * cos(angle) -
3123 cpl_apertures_get_centroid_y(appos, ipos1) * sin(angle);
3124 double yp1 = cpl_apertures_get_centroid_x(appos, ipos1) * sin(angle) +
3125 cpl_apertures_get_centroid_y(appos, ipos1) * cos(angle);
3126 double xp2 = cpl_apertures_get_centroid_x(appos, ipos2) * cos(angle) -
3127 cpl_apertures_get_centroid_y(appos, ipos2) * sin(angle);
3128 double yp2 = cpl_apertures_get_centroid_x(appos, ipos2) * sin(angle) +
3129 cpl_apertures_get_centroid_y(appos, ipos2) * cos(angle);
3132 const double xpl = xp1 < xp2 ? xp1 : xp2;
3133 const double ypl = xp1 < xp2 ? yp1 : yp2;
3136 const double xpr = xp1 < xp2 ? xp2 : xp1;
3137 const double ypr = xp1 < xp2 ? yp2 : yp1;
3140 double xn1 = cpl_apertures_get_centroid_x(apneg, ineg1) * cos(angle) -
3141 cpl_apertures_get_centroid_y(apneg, ineg1) * sin(angle);
3142 double yn1 = cpl_apertures_get_centroid_x(apneg, ineg1) * sin(angle) +
3143 cpl_apertures_get_centroid_y(apneg, ineg1) * cos(angle);
3144 double xn2 = cpl_apertures_get_centroid_x(apneg, ineg2) * cos(angle) -
3145 cpl_apertures_get_centroid_y(apneg, ineg2) * sin(angle);
3146 double yn2 = cpl_apertures_get_centroid_x(apneg, ineg2) * sin(angle) +
3147 cpl_apertures_get_centroid_y(apneg, ineg2) * cos(angle);
3150 const double x_nl = xn1 < xn2 ? xn1 : xn2;
3151 const double y_nl = xn1 < xn2 ? yn1 : yn2;
3154 const double xnr = xn1 < xn2 ? xn2 : xn1;
3155 const double ynr = xn1 < xn2 ? yn2 : yn1;
3157 const double lx1 = xnr - xpl;
3158 const double lx2 = xpr - x_nl;
3159 const double ly1 = ypl - y_nl;
3160 const double ly2 = ynr - ypr;
3162 const double dx1 = lx1 - ssize;
3163 const double dx2 = lx2 - ssize;
3164 const double dy1 = ly1 - ssize;
3165 const double dy2 = ly2 - ssize;
3167 const double ey1 = ynr - ypl;
3168 const double ey2 = ypr - y_nl;
3169 const double ex1 = xpl - x_nl;
3170 const double ex2 = xpr - xnr;
3172 const double ok = sqrt(dx1 * dx1 + dx2 * dx2 + dy1 * dy1 + dy2 * dy2 +
3173 ex1 * ex1 + ex2 * ex2 + ey1 * ey1 + ey2 * ey2);
3175 double result = -1.0;
3179 skip_if(pswapp == NULL);
3180 skip_if(pswapn == NULL);
3181 skip_if(appos == apneg);
3182 skip_if(ipos1 == ipos2);
3183 skip_if(ineg1 == ineg2);
3185 skip_if(ssize <= 0.0);
3187 *pswapp = xp1 < xp2 ? CPL_FALSE : CPL_TRUE;
3188 *pswapn = xn1 < xn2 ? CPL_FALSE : CPL_TRUE;
3219 double visir_img_check_align(
const cpl_apertures * appos,
int ipos,
3220 const cpl_apertures * apneg,
int ineg1,
int ineg2,
3221 double ssize,
double angle,
3222 cpl_boolean * pswapn)
3228 double xp = cpl_apertures_get_centroid_x(appos, ipos) * cos(angle) -
3229 cpl_apertures_get_centroid_y(appos, ipos) * sin(angle);
3230 double yp = cpl_apertures_get_centroid_x(appos, ipos) * sin(angle) +
3231 cpl_apertures_get_centroid_y(appos, ipos) * cos(angle);
3234 double xn1 = cpl_apertures_get_centroid_x(apneg, ineg1) * cos(angle) -
3235 cpl_apertures_get_centroid_y(apneg, ineg1) * sin(angle);
3236 double yn1 = cpl_apertures_get_centroid_x(apneg, ineg1) * sin(angle) +
3237 cpl_apertures_get_centroid_y(apneg, ineg1) * cos(angle);
3238 double xn2 = cpl_apertures_get_centroid_x(apneg, ineg2) * cos(angle) -
3239 cpl_apertures_get_centroid_y(apneg, ineg2) * sin(angle);
3240 double yn2 = cpl_apertures_get_centroid_x(apneg, ineg2) * sin(angle) +
3241 cpl_apertures_get_centroid_y(apneg, ineg2) * cos(angle);
3243 double result = -1.0;
3250 const double x_nl = yn1 < yn2 ? xn1 : xn2;
3251 const double y_nl = yn1 < yn2 ? yn1 : yn2;
3254 const double xnr = yn1 < yn2 ? xn2 : xn1;
3255 const double ynr = yn1 < yn2 ? yn2 : yn1;
3257 const double d1 = ynr - yp - ssize;
3258 const double d2 = yp - y_nl - ssize;
3260 const double e1 = xnr - xp;
3261 const double e2 = xp - x_nl;
3263 swapn = yn1 < yn2 ? CPL_FALSE : CPL_TRUE;
3265 ok = sqrt(d1 * d1 + d2 * d2 + e1 * e1 + e2 * e2);
3269 skip_if(pswapn == NULL);
3270 skip_if(appos == apneg);
3271 skip_if(ineg1 == ineg2);
3273 skip_if(ssize <= 0.0);
3304 double visir_img_check_line(
const cpl_apertures * apnear,
int inear,
3305 const cpl_apertures * apfar,
int ifar,
3306 double ssize,
double angle)
3312 double x_n = cpl_apertures_get_centroid_x(apnear, inear) * cos(angle) -
3313 cpl_apertures_get_centroid_y(apnear, inear) * sin(angle);
3314 double y_n = cpl_apertures_get_centroid_x(apnear, inear) * sin(angle) +
3315 cpl_apertures_get_centroid_y(apnear, inear) * cos(angle);
3318 double xf = cpl_apertures_get_centroid_x(apfar, ifar) * cos(angle) -
3319 cpl_apertures_get_centroid_y(apfar, ifar) * sin(angle);
3320 double yf = cpl_apertures_get_centroid_x(apfar, ifar) * sin(angle) +
3321 cpl_apertures_get_centroid_y(apfar, ifar) * cos(angle);
3323 double result = -1.0;
3327 const double d = yf - y_n - ssize;
3329 const double e = xf - x_n;
3331 ok = sqrt(d * d + e * e);
3335 skip_if(apnear == apfar);
3337 skip_if(ssize <= 0.0);
3360 static cpl_error_code
3361 get_aqu_data_type(
const cpl_frame * frame,
const cpl_propertylist * plist,
3362 const cpl_size next, visir_data_type * ptype)
3365 const char * format = NULL;
3366 if (cpl_propertylist_has(plist, VISIR_PFITS_INT_NAXIS3))
3369 if (cpl_propertylist_has(plist,
"ESO DET FRAM FORMAT"))
3370 format = cpl_propertylist_get_string(plist,
"ESO DET FRAM FORMAT");
3373 if (next >= 2 || (format && !strcmp(format,
"extension"))) {
3376 *ptype = VISIR_DATA_AQU_INT;
3379 *ptype = VISIR_DATA_AQU_HCYCLE;
3382 else if (next == 1 && (naxis3 == -1 || naxis3 == 0)) {
3383 *ptype = VISIR_DATA_AQU_BURST_EXT;
3385 else if (next == 0 && naxis3 > 0) {
3386 *ptype = VISIR_DATA_AQU_BURST;
3389 cpl_error_set_message(cpl_func, CPL_ERROR_BAD_FILE_FORMAT,
3390 "Could not determine format of aquarius file %s",
3391 cpl_frame_get_filename(frame));
3394 return cpl_error_get_code();
3410 static cpl_error_code
3411 get_drs_data_type(
const cpl_frame * frame,
const cpl_propertylist * plist,
3412 visir_data_type * ptype)
3414 cpl_errorstate cleanstate = cpl_errorstate_get();
3419 const char * file = cpl_frame_get_filename(frame);
3420 cpl_boolean known_frametype = CPL_TRUE;
3424 cpl_ensure_code(ptype != NULL, CPL_ERROR_NULL_INPUT);
3428 visir_error_reset(
"Could not get FITS key");
3430 known_frametype = CPL_FALSE;
3431 }
else if (strcmp(sval,
"CUBE1")==0) {
3432 *ptype = VISIR_DATA_CUBE1;
3433 }
else if (strcmp(sval,
"CUBE2")==0) {
3434 *ptype = VISIR_DATA_CUBE2;
3437 known_frametype = CPL_FALSE;
3440 if (known_frametype && *ptype == VISIR_DATA_CUBE2) {
3441 if (naxis3 == 2 * nchop + 1) {
3443 }
else if (naxis3 == nchop + 2) {
3444 cpl_msg_warning(cpl_func,
"%s has FRAM TYPE = '%s', but NAXIS3=%d "
3445 "and CHOP NCYCLES=%d imply a CUBE1. Assuming "
3446 "the frame type is really CUBE1", file, sval,
3448 *ptype = VISIR_DATA_CUBE1;
3450 cpl_msg_warning(cpl_func,
"%s has FRAM TYPE = '%s', but NAXIS3=%d "
3451 "and CHOP NCYCLES=%d is not a valid VISIR INTERM+"
3452 "Half-Cycle format", file, sval, naxis3, nchop);
3455 }
else if (known_frametype && *ptype == VISIR_DATA_CUBE1) {
3456 if (naxis3 == nchop + 2) {
3459 cpl_msg_debug(cpl_func,
"%s has %d INTERM-frames and one Half-"
3460 "Cycle frame (old CUBE1-format)", file, nchop);
3462 }
else if (naxis3 == 2 * nchop + 1) {
3463 cpl_msg_warning(cpl_func,
"%s has FRAM TYPE = '%s', but NAXIS3=%d "
3464 "and CHOP NCYCLES=%d imply a CUBE2. Assuming "
3465 "the frame type is really CUBE2", file, sval,
3467 *ptype = VISIR_DATA_CUBE2;
3469 cpl_msg_warning(cpl_func,
"%s has FRAM TYPE = '%s', but NAXIS3=%d "
3470 "and CHOP NCYCLES=%d is not a valid VISIR INTERM+"
3471 "Half-Cycle format", file, sval, naxis3, nchop);
3474 }
else if (naxis3 == 2 * nchop + 1) {
3475 cpl_msg_warning(cpl_func,
"%s has FRAM TYPE='%s', but NAXIS3=%d and "
3476 "CHOP NCYCLES=%d imply a CUBE2. Assuming the frame "
3477 "type is CUBE2", file, sval ? sval :
"<NULL>", naxis3,
3479 *ptype = VISIR_DATA_CUBE2;
3480 }
else if (naxis3 == nchop + 2) {
3481 cpl_msg_warning(cpl_func,
"%s has FRAM TYPE='%s', but NAXIS3=%d and "
3482 "CHOP NCYCLES=%d imply a CUBE1. Assuming the frame "
3483 "type is CUBE1", file, sval ? sval :
"<NULL>", naxis3,
3485 *ptype = VISIR_DATA_CUBE1;
3487 else if (!known_frametype && nchop * ndit * 2 >= naxis3) {
3488 cpl_msg_info(cpl_func,
"%s has FRAM TYPE='%s', NAXIS3=%d and "
3489 "CHOP NCYCLES=%d imply BURST data.",
3490 file, sval ? sval :
"<NULL>", naxis3, nchop);
3491 *ptype = VISIR_DATA_BURST;
3493 return cpl_error_set_message(cpl_func, CPL_ERROR_BAD_FILE_FORMAT,
3494 "%s has FRAM TYPE='%s', NAXIS3 = %d and "
3495 "CHOP NCYCLES = %d", file,
3496 sval ? sval :
"<NULL>", naxis3, nchop);
3501 return cpl_error_get_code();
3516 cpl_error_code visir_get_data_type(
const cpl_frame * frame,
3517 const cpl_propertylist * plist,
3518 visir_data_type * ptype, cpl_size * pnext)
3520 const cpl_size next = cpl_frame_get_nextensions(frame);
3522 cpl_ensure_code(ptype != NULL, CPL_ERROR_NULL_INPUT);
3529 if (cpl_propertylist_has(plist,
"ESO DRS DTYPE"))
3530 *ptype = cpl_propertylist_get_int(plist,
"ESO DRS DTYPE");
3532 if (cpl_propertylist_has(plist, VISIR_PFITS_INT_NAVRG))
3533 skip_if(get_aqu_data_type(frame, plist, next, ptype));
3535 skip_if(get_drs_data_type(frame, plist, ptype));
3540 return cpl_error_get_code();
3553 cpl_error_code visir_img_burst_find_delta_chop(
const cpl_propertylist *
self,
3554 int * ichopchange,
int * ihalfcycle)
3557 const char * sdateobs =
3558 cpl_propertylist_get_string(
self, VISIR_PFITS_STRING_OBS_START);
3559 const char * schopstart =
3560 cpl_propertylist_get_string(
self, VISIR_PFITS_STRING_CHOP_START);
3562 const int nditskip =
3563 cpl_propertylist_get_int(
self, VISIR_PFITS_INT_NDITSKIP);
3565 double ddateobs, dchopstart;
3570 bug_if(irplib_wcs_mjd_from_string(&ddateobs, sdateobs));
3571 bug_if(irplib_wcs_mjd_from_string(&dchopstart, schopstart));
3573 skip_if(chop_freq <= 0.0);
3574 skip_if(dit <= 0.0);
3577 ddateobs += dit * nditskip / (double)VISIR_SECS_PER_DAY;
3579 period = 1.0/(chop_freq * dit);
3582 error_if((
int)(period + 0.5) % 2 != 0, CPL_ERROR_UNSUPPORTED_MODE,
3583 "Period %g not not an even number, chop frequency %g, dit %g",
3584 period, chop_freq, dit);
3586 error_if((
int)(period + 0.5) <= 1, CPL_ERROR_ILLEGAL_INPUT,
3587 "Period %d < 1", (
int)(period + 0.5));
3589 *ihalfcycle = (int)(period + 0.5)/2;
3591 cpl_msg_info(cpl_func,
"Number of A+B frames in one full chopping cycle: %g",
3594 if (dchopstart < ddateobs) {
3595 double tchop = (ddateobs - dchopstart) * (
double)VISIR_SECS_PER_DAY;
3597 double dprecycle = tchop * chop_freq;
3600 const double phase = ceil(dprecycle) - dprecycle;
3603 *ichopchange = (int)ceil(phase * period) - 1;
3605 cpl_msg_info(cpl_func,
"Chopping started %gs (%f cycles) before OBS start: "
3606 "%f < %f", tchop, dprecycle, dchopstart, ddateobs);
3608 }
else if (ddateobs < dchopstart) {
3611 double tchop = (dchopstart - ddateobs) * (
double)VISIR_SECS_PER_DAY;
3612 *ichopchange = (int)ceil(tchop / dit) - 1;
3613 cpl_msg_info(cpl_func,
"Chopping started %gs (wasted %g cycles) after OBS "
3614 "start: %f > %f", tchop, tchop * chop_freq, dchopstart,
3621 cpl_msg_info(cpl_func,
"Chopping started with OBS start: %f == %f",
3622 dchopstart, ddateobs);
3626 *ichopchange = *ichopchange % (*ihalfcycle * 2);
3628 cpl_msg_info(cpl_func,
"Frame of chop change: %d", *ichopchange);
3632 return cpl_error_get_code();
3635 #include "visir_destripe.c"
double visir_parameterlist_get_double(const cpl_parameterlist *self, const char *recipe, visir_parameter bitmask)
Retrieve the value of a VISIR parameter of type double.
cpl_imagelist * irplib_imagelist_load_framelist(const irplib_framelist *self, cpl_type pixeltype, int planenum, int extnum)
Load an imagelist from a framelist.
double visir_pfits_get_cumoffsetx(const cpl_propertylist *self)
The cumulative offset in X.
int visir_pfits_get_naxis3(const cpl_propertylist *self)
The NAXIS3 key.
cpl_error_code visir_destripe_image(cpl_image *self, int niter, double threshold, double thres_detect, cpl_boolean morpho)
Remove the stripes frome an image using iterations.
int visir_parameterlist_get_int(const cpl_parameterlist *self, const char *recipe, visir_parameter bitmask)
Retrieve the value of a VISIR integer parameter.
const char * visir_pfits_get_frame_type(const cpl_propertylist *self)
The frame type.
cpl_boolean visir_parameterlist_get_bool(const cpl_parameterlist *self, const char *recipe, visir_parameter bitmask)
Retrieve the value of a VISIR boolean parameter.
const cpl_propertylist * irplib_framelist_get_propertylist_const(const irplib_framelist *self, int pos)
Get the propertylist of the specified frame in the framelist.
int visir_pfits_get_chop_ncycles(const cpl_propertylist *self)
The number of chopping cycles.
double visir_pfits_get_chop_posang(const cpl_propertylist *self)
The chopping position angle in rad.
const char * visir_parameterlist_get_string(const cpl_parameterlist *self, const char *recipe, visir_parameter bitmask)
Retrieve the value of a VISIR string parameter.
int visir_pfits_get_ndit(const cpl_propertylist *self)
The NDIT keyword.
double visir_pfits_get_cumoffsety(const cpl_propertylist *self)
The cumulative offset in Y.
double visir_pfits_get_chop_freq(const cpl_propertylist *self)
The chopping frequency.
double visir_pfits_get_chop_throw(const cpl_propertylist *self)
The chopping throw.
const char * visir_pfits_get_nodpos(const cpl_propertylist *self)
The nodding position.
double visir_pfits_get_dit(const cpl_propertylist *self)
The DIT.
const cpl_frame * irplib_framelist_get_const(const irplib_framelist *self, int pos)
Get the specified frame from the framelist.
double visir_pfits_get_pixscale(const cpl_propertylist *self)
The pixel scale.
double visir_pfits_get_chop_stat(const cpl_propertylist *self)
The chopping status.
const char * visir_pfits_get_chopnod_dir(const cpl_propertylist *self)
The chopping direction.
cpl_error_code irplib_framelist_contains(const irplib_framelist *self, const char *key, cpl_type type, cpl_boolean is_equal, double fp_tol)
Verify that a property is present for all frames.
int irplib_framelist_get_size(const irplib_framelist *self)
Get the size of a framelist.