29#include "visir_utils.h"
31#include "irplib_utils.h"
33#include "visir_inputs.h"
34#include "visir_pfits.h"
35#define visir_pfits_get_int(KEY) irplib_pfits_get_int(self, KEY)
36#include "visir_spc_distortion.h"
37#include "visir_cpl_compat.h"
64IRPLIB_DIAG_PRAGMA_PUSH_ERR(-Wimplicit-function-declaration)
77#define VISIR_BACKGD_START 76
78#define VISIR_BACKGD_STOP 172
88#define IND(x, y , nx) ((x) + (nx) * (y))
95static double visir_great_circle_dist(
double,
double,
double,
double);
96static double ra_hms2deg(
int,
int,
double);
97static double dec_hms2deg(
int,
int,
double);
99static const char * visir_get_capa(
const cpl_propertylist *);
100static double visir_hcycle_background(
const irplib_framelist *,
int,
int);
103static cpl_boolean visir_mask_has(
const cpl_mask *, cpl_binary,
int);
116size_t visir_get_num_threads(cpl_boolean force)
120 if (force == CPL_FALSE && getenv(
"OMP_NUM_THREADS")) {
121 char * endptr, * str = getenv(
"OMP_NUM_THREADS");
122 int r = (int)strtol(str, &endptr, 10);
123 return (str == endptr || r < 1) ? 1 : r;
127 ret = omp_get_max_threads();
129#if defined HAVE_SYSCONF && defined _SC_NPROCESSORS_ONLN
130 ret = sysconf(_SC_NPROCESSORS_ONLN);
133 f = fopen(
"/sys/devices/system/cpu/cpu0/"
134 "topology/thread_siblings_list",
"r");
137 if (fgets(buf, 80, f) != NULL) {
140 if (sscanf(buf,
"%d,%d", &a, &b) == 2) {
146 return ret < 1 ? 1 : ret;
158cpl_boolean visir_get_tempdir(
char * tmpdir_)
160 cpl_boolean have_tmpdir = CPL_FALSE;
161 char tmpdir[strlen(tmpdir_) + 1];
166 for (
int i = 0; i < 10 && !have_tmpdir; i++) {
167 strcpy(tmpdir, tmpdir_);
168 int fd = mkstemp(tmpdir);
171 skip_if(unlink(tmpdir));
172 have_tmpdir = mkdir(tmpdir, O_RDWR | S_IRWXU) == 0;
175 error_if(have_tmpdir != CPL_TRUE, CPL_ERROR_FILE_IO,
176 "Temporary directory creation failed");
178 strcpy(tmpdir_, tmpdir);
191char * visir_get_cwd(
void)
199 if (getcwd(buf, n) != 0) {
202 else if (errno == ERANGE) {
210 cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
211 "Could not determine current working "
212 "directory: %s", strerror(errno));
228void visir_drop_cache(
const char * VISIR_ATTR_UNUSED filename,
229 off_t VISIR_ATTR_UNUSED offset,
230 off_t VISIR_ATTR_UNUSED length)
232#if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_DONTNEED
233 int fd = open(filename, O_RDONLY);
236 posix_fadvise(fd, offset, length, POSIX_FADV_DONTNEED);
255void visir_readahead(
const char * VISIR_ATTR_UNUSED filename,
256 off_t VISIR_ATTR_UNUSED offset, off_t VISIR_ATTR_UNUSED length)
258#if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_WILLNEED
259 int fd = open(filename, O_RDONLY);
262 posix_fadvise(fd, offset, length, POSIX_FADV_WILLNEED);
274size_t visir_get_nbytes(
const cpl_image * img)
276 return cpl_image_get_size_x(img) *
277 cpl_image_get_size_y(img) *
278 cpl_type_get_sizeof(cpl_image_get_type(img));
291size_t visir_get_nbytes_plist(
const cpl_propertylist * self)
293 int naxis = visir_pfits_get_int(
"NAXIS");
294 int bitpix = abs(visir_pfits_get_int(
"BITPIX"));
297 size_t naxis_bytes = 1;
299 for (
int i = 0; i < naxis; i++) {
301 sprintf(buffer,
"NAXIS%d", i + 1);
302 naxis_bytes *= visir_pfits_get_int(buffer);
304 if (cpl_propertylist_has(self,
"XTENSION")) {
305 pcount = visir_pfits_get_int(
"PCOUNT");
306 gcount = visir_pfits_get_int(
"GCOUNT");
308 if (cpl_error_get_code())
311 nbytes = (bitpix / 8) * gcount * (pcount + naxis_bytes);
313 nbytes += cpl_propertylist_get_size(self) * 80;
329cpl_error_code visir_image_multiply_fast(cpl_image * im1,
330 const cpl_image * im2)
332#if defined __SSE3__ || defined __SSE2__
333 cpl_ensure_code(im1 != NULL, CPL_ERROR_NULL_INPUT);
334 cpl_ensure_code(im2 != NULL, CPL_ERROR_NULL_INPUT);
336 if (cpl_image_get_type(im1) == CPL_TYPE_FLOAT_COMPLEX &&
337 cpl_image_get_type(im2) == CPL_TYPE_FLOAT_COMPLEX) {
338 const cpl_size nx1 = cpl_image_get_size_x(im1);
339 const cpl_size ny1 = cpl_image_get_size_y(im1);
340 const cpl_size nx2 = cpl_image_get_size_x(im2);
341 const cpl_size ny2 = cpl_image_get_size_y(im2);
342 const size_t Nt = nx1 * ny1;
343 const size_t n = (Nt % 2) == 1 ? Nt - 1 : Nt;
345 float complex * a = cpl_image_get_data(im1);
346 const float complex * b = cpl_image_get_data_const(im2);
348 cpl_ensure_code(nx1 == nx2, CPL_ERROR_INCOMPATIBLE_INPUT);
349 cpl_ensure_code(ny1 == ny2, CPL_ERROR_INCOMPATIBLE_INPUT);
350 cpl_ensure_code(n < SIZE_MAX - 1, CPL_ERROR_ACCESS_OUT_OF_RANGE);
354 if (((intptr_t)a % 16) != 0 || ((intptr_t)b % 16) != 0)
355 return cpl_image_multiply(im1, im2);
357#if defined __SSE2__ && !defined __SSE3__
358 const __m128 neg = (__m128)_mm_set_epi32(0x0u, 0x80000000u, 0x0u, 0x80000000u);
360 for (
size_t i = 0; i < n; i += 2) {
361 __m128 ua = _mm_load_ps((
float *)&a[i]);
362 __m128 ub = _mm_load_ps((
const float *)&b[i]);
364 __m128 reala = _mm_shuffle_ps(ua, ua, _MM_SHUFFLE(2, 2, 0, 0));
365 __m128 imaga = _mm_shuffle_ps(ua, ua, _MM_SHUFFLE(3, 3, 1, 1));
366 __m128 t1 = _mm_mul_ps(reala, ub);
367 __m128 sb = _mm_shuffle_ps(ub, ub, _MM_SHUFFLE(2, 3, 0, 1));
368 __m128 t2 = _mm_mul_ps(imaga, sb);
369#if defined __SSE2__ && !defined __SSE3__
370 t2 = _mm_xor_ps(t2, neg);
371 __m128 res = _mm_add_ps(t1, t2);
373 __m128 res = _mm_addsub_ps(t1, t2);
375 _mm_store_ps((
float *)&a[i], res);
379 a[Nt - 1] = a[Nt - 1] * b[Nt - 1];
382 const cpl_mask * bpm1 = cpl_image_get_bpm_const(im1);
383 const cpl_mask * bpm2 = cpl_image_get_bpm_const(im2);
386 cpl_image_reject_from_mask(im1, bpm2);
388 cpl_mask_or(cpl_image_get_bpm(im1), bpm2);
394 cpl_image_multiply(im1, im2);
396 return CPL_ERROR_NONE;
411double visir_image_get_mean_fast(
const cpl_image * im)
413 if (im == NULL || cpl_image_get_type(im) != CPL_TYPE_FLOAT) {
414 return cpl_image_get_mean(im);
417 const size_t npix = cpl_image_get_size_x(im) *
418 cpl_image_get_size_y(im);
419 const float * data = cpl_image_get_data_float_const(im);
420 const size_t nbad = cpl_image_count_rejected(im);
429 for (i = 0; i < npix - (npix % 4u); i+=4) {
435 for (; i < npix; i++) {
439 else if (nbad == npix) {
444 const cpl_binary * m =
445 cpl_mask_get_data_const(cpl_image_get_bpm_const(im));
446 for (i = 0; i < npix - (npix % 4u); i+=4) {
456 for (; i < npix; i++) {
461 return (sum1 + sum2 + sum3 + sum4) / (npix - nbad);
475int visir_cmp_frm_fn(
const cpl_frame * a,
const cpl_frame * b)
477 const char * fna = cpl_frame_get_filename(a);
478 const char * fnb = cpl_frame_get_filename(b);
480 return strcmp(fna, fnb);
493cpl_error_code visir_move_products(cpl_frameset *frames,
494 const char * dest_,
const char * src_)
496 const char * dest = dest_ ? dest_ :
".";
497 const char * src = src_ ? src_ :
".";
499 FOR_EACH_FRAMESET(frm, frames) {
500 if (cpl_frame_get_group(frm) == CPL_FRAME_GROUP_PRODUCT) {
501 char * buf = cpl_strdup(cpl_frame_get_filename(frm));
502 char * new_fn = cpl_sprintf(
"%s/%s", dest, basename(buf));
505 buf = cpl_sprintf(
"mv \"%s/%s\" \"%s\"", src,
506 cpl_frame_get_filename(frm), new_fn);
507 if (WEXITSTATUS(system(buf)) != 0) {
508 cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
509 "Could not move %s/%s to %s", src,
510 cpl_frame_get_filename(frm), new_fn);
523 if (cpl_frame_get_group(frm) == CPL_FRAME_GROUP_RAW ||
524 cpl_frame_get_group(frm) == CPL_FRAME_GROUP_CALIB) {
525 if (strncmp(cpl_frame_get_filename(frm),
"../", 3) != 0) {
528 char * buf = cpl_strdup(cpl_frame_get_filename(frm));
529 cpl_frame_set_filename(frm, buf + 3);
536 return cpl_error_get_code();
550cpl_parameter * visir_parameter_duplicate(
const cpl_parameter * p)
552 cpl_parameter * np = NULL;
554 cpl_ensure(p != NULL, CPL_ERROR_NULL_INPUT, NULL);
555 cpl_ensure(cpl_parameter_get_class(p) == CPL_PARAMETER_CLASS_VALUE,
556 CPL_ERROR_UNSUPPORTED_MODE, NULL);
558 switch (cpl_parameter_get_type(p)) {
560 np = cpl_parameter_new_value(cpl_parameter_get_name(p),
561 cpl_parameter_get_type(p),
562 cpl_parameter_get_help(p),
563 cpl_parameter_get_context(p),
564 cpl_parameter_get_default_bool(p));
565 cpl_parameter_set_bool(np, cpl_parameter_get_bool(p));
569 np = cpl_parameter_new_value(cpl_parameter_get_name(p),
570 cpl_parameter_get_type(p),
571 cpl_parameter_get_help(p),
572 cpl_parameter_get_context(p),
573 cpl_parameter_get_default_int(p));
574 cpl_parameter_set_int(np, cpl_parameter_get_int(p));
577 case CPL_TYPE_DOUBLE:
578 np = cpl_parameter_new_value(cpl_parameter_get_name(p),
579 cpl_parameter_get_type(p),
580 cpl_parameter_get_help(p),
581 cpl_parameter_get_context(p),
582 cpl_parameter_get_default_double(p));
583 cpl_parameter_set_double(np, cpl_parameter_get_double(p));
586 case CPL_TYPE_STRING:
587 np = cpl_parameter_new_value(cpl_parameter_get_name(p),
588 cpl_parameter_get_type(p),
589 cpl_parameter_get_help(p),
590 cpl_parameter_get_context(p),
591 cpl_parameter_get_default_string(p));
592 cpl_parameter_set_string(np, cpl_parameter_get_string(p));
596 cpl_error_set_message(cpl_func, CPL_ERROR_UNSUPPORTED_MODE,
597 "Parameter has unknown type");
604 if (cpl_parameter_get_tag(p))
605 cpl_parameter_set_tag(np, cpl_parameter_get_tag(p));
608 cpl_parameter_mode modes[] = {CPL_PARAMETER_MODE_CLI,
609 CPL_PARAMETER_MODE_CFG, CPL_PARAMETER_MODE_ENV};
611 for (
size_t i = 0; i < ARRAY_LEN(modes); i++) {
612 cpl_parameter_set_alias(np, modes[i],
613 cpl_parameter_get_alias(p, modes[i]));
614 if (!cpl_parameter_is_enabled(p, modes[i]))
615 cpl_parameter_disable(np, modes[i]);
635cpl_error_code visir_copy_parameters(cpl_parameterlist * dest,
636 const cpl_parameterlist * src)
638 for (
const cpl_parameter * p = cpl_parameterlist_get_first_const(src);
639 p != NULL; p = cpl_parameterlist_get_next_const(src)) {
640 cpl_parameter * par =
641 cpl_parameterlist_find(dest, cpl_parameter_get_name(p));
646 cpl_type t = cpl_parameter_get_type(par);
647 if (t == CPL_TYPE_BOOL)
648 cpl_parameter_set_bool(par, cpl_parameter_get_bool(p));
649 else if (t == CPL_TYPE_INT)
650 cpl_parameter_set_int(par, cpl_parameter_get_int(p));
651 else if (t == CPL_TYPE_DOUBLE)
652 cpl_parameter_set_double(par, cpl_parameter_get_double(p));
653 else if (t == CPL_TYPE_STRING)
654 cpl_parameter_set_string(par, cpl_parameter_get_string(p));
661 return cpl_error_get_code();
676visir_init_recipe(
const char * name,
int (*get_info)(cpl_pluginlist *),
677 cpl_pluginlist * plugins)
679 cpl_recipe * recipe = cpl_calloc(1,
sizeof(cpl_recipe));
681 cpl_plugin * pl = cpl_pluginlist_find (plugins, name);
682 cpl_plugin_copy ((cpl_plugin *) & recipe->interface, pl);
700visir_run_recipe(cpl_recipe * recipe,
701 cpl_frameset * framelist,
const cpl_parameterlist * parlist,
702 cpl_error_code (*set_parlist)(cpl_parameterlist *,
703 const cpl_parameterlist *))
705 cpl_plugin * pl = &recipe->interface;
706 cpl_plugin_func plugin_func_init = cpl_plugin_get_init(pl);
707 cpl_plugin_func plugin_func_exec = cpl_plugin_get_exec(pl);
708 cpl_plugin_func plugin_func_deinit = cpl_plugin_get_deinit(pl);
712 recipe->frames = framelist;
715 if (getenv(
"VISIR_TEST_MODE")) {
716 char * buf = cpl_sprintf(
"%s.sof", cpl_plugin_get_name(pl));
717 FILE * f = fopen(buf,
"wt");
719 FOR_EACH_FRAMESET(frm, framelist) {
720 fprintf(f,
"%s %s\n", cpl_frame_get_filename(frm), cpl_frame_get_tag(frm));
726 cpl_fits_set_mode(CPL_FITS_RESTART_CACHING);
728 plugin_func_init(&recipe->interface);
730 set_parlist(recipe->parameters, parlist);
731 plugin_func_exec(&recipe->interface);
732 plugin_func_deinit(&recipe->interface);
736 cpl_fits_set_mode(CPL_FITS_RESTART_CACHING);
738 return cpl_error_get_code();
760visir_prepare_frameset(
const cpl_frameset * frameset,
761 const char ** tagmap,
size_t ntags,
764 cpl_frameset * nlist = cpl_frameset_new();
765 cx_list * _nlist = cx_list_new();
766 cpl_ensure(ntags % 2 == 0, CPL_ERROR_ILLEGAL_INPUT, nlist);
768 FOR_EACH_FRAMESET_C(frame, frameset) {
769 if (cpl_frame_get_group(frame) == CPL_FRAME_GROUP_PRODUCT) {
770 cpl_frame * frm = cpl_frame_duplicate(frame);
771 cpl_frame_set_group(frm, CPL_FRAME_GROUP_RAW);
772 cpl_frame_set_level(frm, CPL_FRAME_LEVEL_NONE);
773 for (
size_t i = 0; i < ntags; i += 2)
774 if (strcmp(tagmap[i], cpl_frame_get_tag(frm)) == 0)
775 cpl_frame_set_tag(frm, tagmap[i + 1]);
777 cx_list_push_back(_nlist, frm);
779 if (cpl_frame_get_group(frame) == CPL_FRAME_GROUP_CALIB)
780 cx_list_push_back(_nlist, cpl_frame_duplicate(frame));
783 cx_list_sort(_nlist, (cx_compare_func)visir_cmp_frm_fn);
785 cx_list_reverse(_nlist);
789 cpl_frameset_insert(nlist, cx_list_get(_nlist, it));
790 cx_list_delete(_nlist);
805cpl_frameset * visir_remove_modified_calib(cpl_frameset * set)
807 cpl_frameset * cleanset = cpl_frameset_new();
808 FOR_EACH_FRAMESET(frame, set) {
809 if (cpl_frame_get_group(frame) == CPL_FRAME_GROUP_CALIB &&
810 strcmp(cpl_frame_get_tag(frame),
811 "STATIC_MASK") == 0) {
814 cpl_frameset_insert(cleanset, cpl_frame_duplicate(frame));
816 cpl_frameset_delete(set);
833visir_wait_for_child(pid_t pid, FILE * rpipe)
835 char * rbuffer = NULL;
839 cpl_frameset * result = NULL;
844 cpl_ensure(rpipe != NULL, CPL_ERROR_NULL_INPUT, NULL);
845 skip_if(fread(&err,
sizeof(err), 1, rpipe) != 1);
846 cpl_error_set(cpl_func, err);
848 skip_if(fread(&size,
sizeof(size), 1, rpipe) != 1);
850 rbuffer = cpl_malloc(size);
851 skip_if(fread(rbuffer, size, 1, rpipe) != 1);
853 result = visir_frameset_deserialize(rbuffer, NULL);
858 if (waitpid(pid, &status, 0) != pid) {
859 cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
860 "%s", strerror(errno));
862 else if (WIFSIGNALED(status)) {
863 cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
864 "Process killed by signal %d", WTERMSIG(status));
866 else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
867 cpl_error_set_message(cpl_func, CPL_ERROR_UNSPECIFIED,
868 "Process failed with code %d",
869 WEXITSTATUS(status));
889remove_tempdir(
const cpl_parameterlist * parlist,
const char* recipename,
892 const cpl_boolean
delete =
893 irplib_parameterlist_get_bool(parlist, PACKAGE,
894 recipename,
"delete-temp");
897 char * cmd = cpl_sprintf(
"rm -rf \"%s\"", tmpdir);
898 cpl_msg_info(cpl_func,
"Removing temporary directory: %s", tmpdir);
899 if (WEXITSTATUS(system(cmd)) != 0)
900 cpl_msg_warning(cpl_func,
"Removing temporary "
901 "directory %s failed", tmpdir);
905 cpl_msg_info(cpl_func,
"Keeping temporary directory: %s", tmpdir);
919visir_tmpdir_exec(
const char * recipename, cpl_plugin * plugin,
920 int (*function)(cpl_frameset *,
const cpl_parameterlist *))
922 char tmpdir[strlen(recipename) + 8];
923 cpl_boolean have_tmpdir = CPL_FALSE;
924 cpl_errorstate cleanstate = cpl_errorstate_get();
925 cpl_recipe * recipe = (cpl_recipe *)plugin;
926 sprintf(tmpdir,
"%s_XXXXXX", recipename);
928 have_tmpdir = visir_get_tempdir(tmpdir);
929 skip_if(have_tmpdir != CPL_TRUE);
931 cpl_msg_info(cpl_func,
"Working in temporary directory: %s", tmpdir);
934 if (chdir(tmpdir) != 0) {
935 return cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
936 "Could not change to temporary directory %s", tmpdir);
940 FOR_EACH_FRAMESET(frm, recipe->frames) {
941 if (cpl_frame_get_filename(frm)[0] !=
'/') {
942 char * buf = cpl_sprintf(
"../%s", cpl_frame_get_filename(frm));
943 cpl_frame_set_filename(frm, buf);
948 cpl_recipedefine_exec(plugin, function);
950 if (chdir(
"..") != 0) {
951 return cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
952 "Could not change back to base directory");
956 skip_if(visir_move_products(recipe->frames,
".", tmpdir));
961 remove_tempdir(recipe->parameters, recipename, tmpdir);
964 if (!cpl_errorstate_is_equal(cleanstate))
965 cpl_errorstate_dump(cleanstate, CPL_FALSE, NULL);
967 return cpl_error_get_code();
982visir_forking_exec(
const char * recipename, cpl_plugin * plugin,
983 int (*function)(cpl_frameset *,
const cpl_parameterlist *))
985 char tmpdir[strlen(recipename) + 8];
986 cpl_boolean have_tmpdir = CPL_FALSE;
987 cpl_errorstate cleanstate = cpl_errorstate_get();
988 cpl_recipe * recipe = (cpl_recipe *)plugin;
989 FILE * pipe_stream = NULL;
991 static const int READ = 0, WRITE = 1;
992 sprintf(tmpdir,
"%s_XXXXXX", recipename);
995 struct sigaction sa, sa_orig;
996 sa.sa_handler = SIG_IGN;
997 sigemptyset(&sa.sa_mask);
999 skip_if(sigaction(SIGINT, &sa, &sa_orig) != 0);
1001 have_tmpdir = visir_get_tempdir(tmpdir);
1002 skip_if(have_tmpdir != CPL_TRUE);
1004 cpl_msg_info(cpl_func,
"Working in temporary directory: %s", tmpdir);
1006 skip_if(pipe(pipe_fd) != 0);
1010 close(pipe_fd[READ]);
1011 close(pipe_fd[WRITE]);
1012 cpl_error_set_message(cpl_func, CPL_ERROR_UNSPECIFIED,
1013 "fork failed: %s", strerror(errno));
1016 else if (pid == 0) {
1018 sigaction(SIGINT, &sa_orig, NULL);
1021 close(pipe_fd[READ]);
1022 pipe_stream = fdopen(pipe_fd[WRITE],
"w");
1025 if (!pipe_stream || chdir(tmpdir) != 0) {
1026 close(pipe_fd[WRITE]);
1027 _exit(EXIT_FAILURE);
1031 FOR_EACH_FRAMESET(frm, recipe->frames) {
1032 if (cpl_frame_get_filename(frm)[0] !=
'/') {
1033 char * buf = cpl_sprintf(
"../%s", cpl_frame_get_filename(frm));
1034 cpl_frame_set_filename(frm, buf);
1039 cpl_error_code err = cpl_recipedefine_exec(plugin, function)
1040 ? (int)cpl_error_set_where(cpl_func) : 0;
1042 if (err == CPL_ERROR_NONE) {
1043 assert((
void*)recipe == (
void*)plugin);
1044 err = visir_send_frameset(pipe_stream, recipe->frames);
1046 fclose(pipe_stream);
1051 close(pipe_fd[WRITE]);
1052 pipe_stream = fdopen(pipe_fd[READ],
"r");
1053 skip_if(pipe_stream == NULL);
1055 recipe->frames = visir_wait_for_child(pid, pipe_stream);
1056 fclose(pipe_stream);
1057 skip_if(recipe->frames == NULL);
1060 skip_if(visir_move_products(recipe->frames,
".", tmpdir));
1066 remove_tempdir(recipe->parameters, recipename, tmpdir);
1069 if (!cpl_errorstate_is_equal(cleanstate))
1070 cpl_errorstate_dump(cleanstate, CPL_FALSE, NULL);
1072 return cpl_error_get_code();
1084double visir_utils_get_exptime(
const int nnod,
const cpl_propertylist * plist)
1097 const double value = 2 * dit * ndit * nnod * ncycles * navrg;
1100 cpl_msg_error(cpl_func,
"Illegal exposure time "
1101 "(dit=%g:ndit=%d:ncycles=%d:nnod=%d): %g",
1102 dit, ndit, ncycles, nnod, value);
1120double * visir_utils_get_wls(
const irplib_framelist * self)
1123 const int size = irplib_framelist_get_size(self);
1124 double * wls = NULL;
1130 skip_if(irplib_framelist_contains(self, VISIR_PFITS_DOUBLE_MONOC_POS,
1131 CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
1134 wls = cpl_malloc(size *
sizeof(
double));
1137 for (i=0; i < size; i++) {
1138 const cpl_propertylist * plist
1139 = irplib_framelist_get_propertylist_const(self, i);
1148 if (cpl_error_get_code()) {
1167cpl_image * visir_create_disk_intimage(
1180 intima = cpl_image_new(nx, ny, CPL_TYPE_INT);
1181 pintima = cpl_image_get_data_int(intima);
1184 for (j=0;j<ny ; j++) {
1185 for (i=0;i<nx ; i++) {
1186 dist = (i+1-x_pos)*(i+1-x_pos)+(j+1-y_pos)*(j+1-y_pos);
1187 if (dist < radius*radius) {
1188 pintima[i+j*nx] = 1;
1190 pintima[i+j*nx] = 0;
1209cpl_image * visir_create_ring_intimage(
1220 if (radius1 >= radius2) {
1221 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
1222 "Small ring radius %d larger than big "
1223 "ring radius %d", radius1, radius2);
1226 if ((nx - x_pos) < radius2 || x_pos < radius2 ||
1227 (ny - y_pos) < radius2 || y_pos < radius2) {
1228 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
1229 "Image of size [%d,%d] with object at "
1230 "[%d,%d] too small to create ring mask of "
1231 "radius %d", nx, ny, x_pos, y_pos, radius2);
1236 intima = cpl_image_new(nx, ny, CPL_TYPE_INT);
1237 pintima = cpl_image_get_data_int(intima);
1240 for (
int j=0;j<ny ; j++) {
1241 for (
int i=0;i<nx ; i++) {
1242 dist = (i+1-x_pos)*(i+1-x_pos)+(j+1-y_pos)*(j+1-y_pos);
1243 if ((dist < radius2*radius2) && (dist > radius1*radius1)) {
1244 pintima[i+j*nx] = 1;
1246 pintima[i+j*nx] = 0;
1265double visir_image_sigma_clip(
const cpl_image * self,
double * pstdev)
1267 const int dimx = cpl_image_get_size_x(self);
1268 const int dimy = cpl_image_get_size_y(self);
1269 const cpl_type type = cpl_image_get_type(self);
1272 cpl_image * noise = cpl_image_new(dimx, dimy, type);
1273 cpl_mask * bpm = NULL;
1274 cpl_mask * kernel = cpl_mask_new(3, 3);
1275 const int niterations = 5;
1276 const double sigma = 3.0;
1277 const double median_corr = 0.94;
1278 double bgnoise = -1;
1284 bug_if(cpl_mask_not(kernel));
1285 bug_if(cpl_image_filter_mask(noise, self, kernel, CPL_FILTER_MEDIAN,
1286 CPL_BORDER_FILTER));
1289 bug_if (cpl_image_subtract(noise, self));
1291 for (i=0; i < niterations ; i++) {
1294 cpl_stats_new_from_image(noise, CPL_STATS_MEAN | CPL_STATS_STDEV);
1296 const double mean = cpl_stats_get_mean(stats);
1297 const double stdev = cpl_stats_get_stdev(stats);
1300 const double low_thresh = mean - sigma * stdev;
1301 const double high_thresh = mean + sigma * stdev;
1304 cpl_stats_delete(stats);
1310 bpm = cpl_mask_threshold_image_create(noise, low_thresh, high_thresh);
1314 bug_if (cpl_mask_not(bpm));
1316 bug_if (cpl_image_reject_from_mask(noise, bpm));
1318 cpl_mask_delete(bpm);
1323 if (pstdev != NULL) {
1327 cpl_stats_new_from_image(noise, CPL_STATS_MEAN | CPL_STATS_STDEV);
1330 bgnoise = cpl_stats_get_stdev(stats);
1331 *pstdev = cpl_image_get_median(self) - cpl_stats_get_mean(stats);
1333 cpl_stats_delete(stats);
1336 bgnoise = cpl_image_get_stdev(noise);
1341 bgnoise /= median_corr;
1345 if (cpl_error_get_code())
1346 cpl_msg_error(cpl_func,
"Computation of background noise using sigma=%g"
1347 " failed in iteration %d of %d", sigma, i+1, niterations);
1349 cpl_mask_delete(kernel);
1350 cpl_mask_delete(bpm);
1351 cpl_image_delete(noise);
1367double visir_img_phot_sigma_clip(
const cpl_image * self)
1370 const double noise = visir_image_sigma_clip(self, NULL);
1372 cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), noise);
1397int visir_star_find(
const cpl_vector * v_ra,
const cpl_vector * v_dec,
1398 double ra,
double dec,
double maxdist,
double * pdist)
1400 const int nra = cpl_vector_get_size(v_ra);
1401 const int ndec = cpl_vector_get_size(v_dec);
1408 cpl_ensure(nra > 0, cpl_error_get_code(), -2);
1409 cpl_ensure(ndec > 0, cpl_error_get_code(), -3);
1414 cpl_ensure(nra == ndec, CPL_ERROR_INCOMPATIBLE_INPUT, -4);
1416 cpl_ensure(maxdist >= 0, CPL_ERROR_ILLEGAL_INPUT, -5);
1419 for (i=0 ; i < nra ; i++) {
1420 const double rai = cpl_vector_get(v_ra, i);
1421 const double deci = cpl_vector_get(v_dec, i);
1422 const double gdist = visir_great_circle_dist(rai, deci, ra, dec);
1424 cpl_msg_debug(cpl_func,
"DISTANCE (RAi,DECi)=(%g,%g) <=> "
1425 "(RA,DEC)=(%g,%g): %g", rai, deci, ra, dec, gdist);
1427 if (i == 0 || gdist < dmin) {
1433 if (pdist != NULL) *pdist = dmin;
1436 if (dmin > maxdist) {
1437 cpl_msg_error(cpl_func,
"Nearest standard star (%d of %d) at (RA,DEC)="
1438 "(%g,%g) is too distant from (RA,DEC)=(%g, %g): %g > %g",
1439 1+minind, nra, cpl_vector_get(v_ra, minind),
1440 cpl_vector_get(v_dec, minind), ra, dec, dmin, maxdist);
1441 cpl_ensure(0, CPL_ERROR_DATA_NOT_FOUND, -1);
1467cpl_error_code visir_star_convert(
const char * line,
int ra_hh,
int ra_mm,
1468 double ra_ss,
char isign,
int dec_hh,
1469 int dec_mm,
double dec_ss,
1470 const double * jys,
int njys,
1471 double * pra,
double * pdec)
1486 else if (isign ==
'-')
1489 cpl_msg_error(cpl_func,
"Line has illegal declination-sign character "
1490 "(%c): %s", isign, line);
1491 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1495 cpl_msg_error(cpl_func,
"Line has negative RA hh (%d): %s",
1497 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1500 cpl_msg_error(cpl_func,
"Line has negative RA mm (%d): %s",
1502 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1505 cpl_msg_error(cpl_func,
"Line has too large RA mm (%d): %s ",
1507 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1510 cpl_msg_error(cpl_func,
"Line has negative RA ss (%g): %s",
1512 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1515 cpl_msg_error(cpl_func,
"Line has too large RA ss (%g): %s ",
1517 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1521 cpl_msg_error(cpl_func,
"Line has negative DEC hh (%d): %s",
1523 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1526 cpl_msg_error(cpl_func,
"Line has negative DEC mm (%d): %s",
1528 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1531 cpl_msg_error(cpl_func,
"Line has too large DEC mm (%d): %s ",
1533 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1536 cpl_msg_error(cpl_func,
"Line has negative DEC ss (%g): %s",
1538 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1541 cpl_msg_error(cpl_func,
"Line has too large DEC ss (%g): %s ",
1543 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1546 *pra = ra_hms2deg(ra_hh, ra_mm, ra_ss);
1547 if (*pra >= 360.0) {
1548 cpl_msg_error(cpl_func,
"Line has too large RA (%g): %s ",
1550 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1553 *pdec = sign * dec_hms2deg(dec_hh, dec_mm, dec_ss);
1555 cpl_msg_error(cpl_func,
"Line has too large RA (%g): %s ",
1557 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1559 if (*pdec < -90.0) {
1560 cpl_msg_error(cpl_func,
"Line has too small RA (%g): %s ",
1562 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1565 for (i=0; i < njys; i++)
if (jys[i] <= 0.0) {
1566 cpl_msg_error(cpl_func,
"Line has non-positive Jy value (%g) at %d: %s ",
1568 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1571 return CPL_ERROR_NONE;
1589cpl_table * visir_table_new_xypos(
const cpl_imagelist * images,
1592 cpl_errorstate cleanstate = cpl_errorstate_get();
1593 const int nsize = cpl_imagelist_get_size(images);
1594 double psigmas[] = {5, 2, 1, 0.5};
1595 cpl_vector * sigmas = NULL;
1596 cpl_table * self = NULL;
1597 const int nsigmas =
sizeof(psigmas)/
sizeof(
double);
1601 cpl_ensure(nsize > 0, cpl_error_get_code(), NULL);
1602 cpl_ensure(label, CPL_ERROR_NULL_INPUT, NULL);
1603 cpl_ensure(!strcmp(label,
"FLUX") || !strcmp(label,
"FWHM"),
1604 CPL_ERROR_UNSUPPORTED_MODE, NULL);
1606 self = cpl_table_new(nsize);
1608 skip_if (cpl_table_new_column(self,
"X_POS", CPL_TYPE_DOUBLE));
1609 skip_if (cpl_table_new_column(self,
"Y_POS", CPL_TYPE_DOUBLE));
1611 if (!strcmp(label,
"FLUX")) {
1613 skip_if (cpl_table_new_column(self, label, CPL_TYPE_DOUBLE));
1615 skip_if (cpl_table_new_column(self,
"X_FWHM", CPL_TYPE_DOUBLE));
1616 skip_if (cpl_table_new_column(self,
"Y_FWHM", CPL_TYPE_DOUBLE));
1619 sigmas = cpl_vector_wrap(4, psigmas);
1620 skip_if (sigmas == NULL);
1622 cpl_msg_info(cpl_func,
"Detecting apertures using %d sigma-levels "
1623 "ranging from %g down to %g", nsigmas, psigmas[0],
1624 psigmas[nsigmas-1]);
1628 for (i=0 ; i < nsize ; i++) {
1629 const cpl_image * image = cpl_imagelist_get_const(images, i);
1630 cpl_apertures * apert;
1644 apert = cpl_apertures_extract(image, sigmas, &isigma);
1646 if (apert != NULL && cpl_error_get_code()) {
1648 cpl_msg_error(cpl_func,
"cpl_apertures_extract() returned non-NULL "
1649 "while setting the CPL error-state to '%s' at '%s'",
1650 cpl_error_get_message(), cpl_error_get_where());
1651 cpl_msg_debug(cpl_func,
"Deleting the spurious aperture list at %p:",
1653 if (cpl_msg_get_level() <= CPL_MSG_DEBUG)
1654 cpl_apertures_dump(apert, stdout);
1655 cpl_apertures_delete(apert);
1659 if (apert != NULL &&
1660 !irplib_apertures_find_max_flux(apert, &iflux, 1) &&
1661 cpl_apertures_get_flux(apert, iflux) > 0) {
1663 posx = cpl_apertures_get_centroid_x(apert, iflux);
1664 posy = cpl_apertures_get_centroid_y(apert, iflux);
1665 flux = cpl_apertures_get_flux(apert, iflux);
1667 cpl_image_get_fwhm(image, (
int)posx, (
int)posy, &fwhmx, &fwhmy);
1669 cpl_msg_info(cpl_func,
"Detected an aperture with flux=%g at "
1670 "sigma=%g, at position: %g %g", flux,
1671 psigmas[isigma], posx, posy);
1674 if (apert == NULL || cpl_error_get_code()) {
1675 visir_error_reset(
"Aperture detection in image %d of %d failed",
1678 }
else if (flux <= 0) {
1679 cpl_msg_warning(cpl_func,
"Ignoring %d-pixel aperture %d (out of "
1680 "%d) in file %d of %d with non-positive flux: %g",
1681 (
int)cpl_apertures_get_npix(apert, iflux), iflux,
1682 (
int)cpl_apertures_get_size(apert), i+1, nsize,
1687 cpl_apertures_delete(apert);
1690 skip_if (cpl_table_set_double(self,
"X_POS", i, posx));
1691 skip_if (cpl_table_set_double(self,
"Y_POS", i, posy));
1694 skip_if (cpl_table_set_double(self,
"FLUX", i, flux));
1696 skip_if (cpl_table_set_double(self,
"X_FWHM", i, fwhmx));
1697 skip_if (cpl_table_set_double(self,
"Y_FWHM", i, fwhmy));
1703 if (nfail == nsize) {
1704 cpl_msg_error(cpl_func,
"Aperture detection failed in all %d images",
1706 visir_error_set(CPL_ERROR_DATA_NOT_FOUND);
1712 cpl_vector_unwrap(sigmas);
1714 if (self && cpl_error_get_code()) {
1715 cpl_table_delete(self);
1730int visir_vector_minpos(
const cpl_vector * v)
1732 const double * x = cpl_vector_get_data_const(v);
1733 const int n = cpl_vector_get_size(v);
1737 cpl_ensure(x, CPL_ERROR_NULL_INPUT, -1);
1739 for (i = 1; i < n; i++)
if (x[i] < x[minpos]) minpos = i;
1760cpl_error_code visir_bivector_load(cpl_bivector * self, FILE * stream)
1768 cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
1769 cpl_ensure_code(stream, CPL_ERROR_NULL_INPUT);
1772 v1 = cpl_bivector_get_x(self);
1773 v2 = cpl_bivector_get_y(self);
1775 xsize = cpl_vector_get_size(v1);
1776 ysize = cpl_vector_get_size(v2);
1778 while (fgets(line, 1024, stream) != NULL) {
1780 if (line[0] !=
'#' && sscanf(line,
"%lg %lg", &x, &y) == 2) {
1787 cpl_vector_set_size(v1, xsize);
1791 cpl_vector_set_size(v2, ysize);
1793 cpl_vector_set(v1, np, x);
1794 cpl_vector_set(v2, np, y);
1800 cpl_ensure_code(!ferror(stream), CPL_ERROR_FILE_IO);
1803 if (np == 0 || cpl_vector_set_size(v1, np) || cpl_vector_set_size(v2, np)) {
1804 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1807 return CPL_ERROR_NONE;
1825double visir_star_dist_min(
const double * pras,
const double * pdecs,
int nloc,
1826 int * piloc1,
int * piloc2)
1833 assert( pras != NULL);
1834 assert( pdecs != NULL);
1835 assert( piloc1 != NULL);
1836 assert( piloc2 != NULL);
1839 for (j = 0; j < nloc; j++) {
1840 for (i = 0; i < j; i++) {
1841 const double dist = visir_great_circle_dist(pras[i], pdecs[i],
1848 if (dist < VISIR_STAR_MAX_RADIUS)
1849 cpl_msg_warning(cpl_func,
"The two stars (%d,%d) have a distance"
1850 ": %g < %g", i, j, dist, VISIR_STAR_MAX_RADIUS);
1873const char ** visir_framelist_set_tag(irplib_framelist * self,
1874 char * (*pftag)(
const cpl_frame *,
1875 const cpl_propertylist *,
1882 const char ** taglist = NULL;
1885 cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), NULL);
1886 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, NULL);
1887 cpl_ensure(pftag != NULL, CPL_ERROR_NULL_INPUT, NULL);
1888 cpl_ensure(pntags != NULL, CPL_ERROR_NULL_INPUT, NULL);
1890 size = irplib_framelist_get_size(self);
1892 cpl_ensure(size > 0, CPL_ERROR_DATA_NOT_FOUND, NULL);
1896 for (iframe = 0; iframe < size ; iframe++) {
1897 cpl_frame * frame = irplib_framelist_get(self, iframe);
1898 const cpl_propertylist * plist
1899 = irplib_framelist_get_propertylist_const(self, iframe);
1901 const char * newtag;
1906 cpl_ensure(frame != NULL, CPL_ERROR_ILLEGAL_INPUT, NULL);
1907 cpl_ensure(plist != NULL, CPL_ERROR_ILLEGAL_INPUT, NULL);
1909 tag = (*pftag)(frame, plist, iframe);
1911 cpl_ensure(tag != NULL, cpl_error_get_code(), NULL);
1915 (void)cpl_frame_set_tag(frame, tag);
1918 newtag = cpl_frame_get_tag(frame);
1920 cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), NULL);
1923 for (i=0; i < *pntags; i++)
1924 if (strcmp(newtag, taglist[i]) == 0)
break;
1930 taglist = (
const char **)cpl_realloc(taglist, *pntags *
1931 sizeof(
const char *));
1932 taglist[i] = newtag;
1949int visir_get_ncombine(
const irplib_framelist * rawframes)
1952 const cpl_size nframes = irplib_framelist_get_size(rawframes);
1953 for (cpl_size i = 0; i < nframes; i++) {
1954 const cpl_propertylist * pl = irplib_framelist_get_propertylist_const(
1956 if (cpl_propertylist_has(pl,
"ESO PRO DATANCOM"))
1957 ncombine += cpl_propertylist_get_int(pl,
"ESO PRO DATANCOM");
1959 return cpl_error_get_code() ? 0 : (ncombine ? ncombine : 1);
1974cpl_error_code visir_qc_append_background(cpl_propertylist * self,
1975 const irplib_framelist * rawframes,
1976 int icol1,
int icol2)
1980 const double bg_mean = visir_hcycle_background(rawframes, icol1, icol2);
1984 bug_if (cpl_propertylist_append_double(self,
"ESO QC BACKGD MEAN",
1989 return cpl_error_get_code();
2004cpl_error_code visir_qc_append_capa(cpl_propertylist * self,
2005 const irplib_framelist * rawframes)
2008 cpl_errorstate cleanstate = cpl_errorstate_get();
2009 const cpl_propertylist * plist
2010 = irplib_framelist_get_propertylist_const(rawframes, 0);
2016 capa = visir_get_capa(plist);
2018 if (cpl_error_get_code()) {
2021 cpl_msg_info(cpl_func,
"Could not determine capa");
2022 cpl_errorstate_set(cleanstate);
2024 bug_if (cpl_propertylist_append_string(self,
"ESO QC CAPA", capa));
2029 return cpl_error_get_code();
2042cpl_error_code visir_qc_append_filter(cpl_propertylist * self,
2043 const irplib_framelist * rawframes)
2046 const cpl_propertylist * plist
2047 = irplib_framelist_get_propertylist_const(rawframes, 0);
2053 bug_if (cpl_propertylist_append_string(self,
"ESO QC FILTER", value));
2057 return cpl_error_get_code();
2070cpl_error_code visir_qc_append_exptime(cpl_propertylist * self,
2071 const irplib_framelist * rawframes)
2073 const cpl_propertylist * plist
2074 = irplib_framelist_get_propertylist_const(rawframes, 0);
2077 const int nnod = irplib_framelist_get_size(rawframes);
2079 const double value = visir_utils_get_exptime(nnod, plist);
2083 bug_if (cpl_propertylist_append_double(self,
"ESO QC EXPTIME", value));
2087 return cpl_error_get_code();
2105static double visir_great_circle_dist(
double ra1,
double dec1,
2106 double ra2,
double dec2)
2110 const double dra = sin( CPL_MATH_RAD_DEG * (ra2 - ra1 )/2.0 );
2111 const double ddec = sin( CPL_MATH_RAD_DEG * (dec2 - dec1)/2.0 );
2113 dec1 *= CPL_MATH_RAD_DEG;
2114 dec2 *= CPL_MATH_RAD_DEG;
2116 return 2.0 * asin(sqrt( ddec*ddec + cos(dec1)*cos(dec2)*dra*dra))
2135static double ra_hms2deg(
int hh,
int mm,
double ss)
2137 return 15.0 * dec_hms2deg(hh, mm, ss);
2153static double dec_hms2deg(
int dd,
int mm,
double ss)
2155 return ((
double)ss/60.0 + (
double)mm)/60.0 + dd;
2172static double visir_hcycle_background(
const irplib_framelist * rawframes,
2173 int icol1,
int icol2)
2175 cpl_imagelist * iset = NULL;
2177 const int nfiles = irplib_framelist_get_size(rawframes);
2183 skip_if (nfiles < 1);
2185 if (icol1 == 0) icol1 = VISIR_BACKGD_START;
2186 if (icol2 == 0) icol2 = VISIR_BACKGD_STOP;
2188 cpl_msg_info(cpl_func,
"Computing Half-cycle background level from column %d "
2189 "through %d", icol1, icol2);
2192 for (i=0; i < nfiles; i++) {
2198 for (j = 0; j < cpl_imagelist_get_size(iset) ; j++) {
2199 const double median =
2200 cpl_image_get_median_window(cpl_imagelist_get(iset, j),
2201 VISIR_BACKGD_START, icol1,
2202 VISIR_BACKGD_STOP, icol2);
2206 if (median != median) {
2207 const cpl_frame * frame = irplib_framelist_get_const(rawframes,
2210 cpl_msg_error(cpl_func,
"Image window (%d, %d, %d, %d) "
2211 "(image %d of %d) in %s (frame %d of %d) "
2213 VISIR_BACKGD_START, icol1,
2214 VISIR_BACKGD_STOP, icol2,
2215 j+1, (
int)cpl_imagelist_get_size(iset),
2216 cpl_frame_get_filename(frame), i+1, nfiles);
2217 visir_error_set(CPL_ERROR_BAD_FILE_FORMAT);
2223 cpl_imagelist_delete(iset);
2230 bgmean = bgsum / nsum;
2234 cpl_imagelist_delete(iset);
2237 return bgmean - VISIR_HCYCLE_OFFSET;
2254visir_get_subpixel_maxpos(
const cpl_image * img, cpl_size x, cpl_size y,
2255 double * xsub,
double * ysub)
2258 const cpl_size nx = cpl_image_get_size_x(img);
2259 const cpl_size ny = cpl_image_get_size_y(img);
2263 if (x - 1 > 0 && x + 1 <= nx) {
2265 cpl_image_get(img, x - 1, y, &bad),
2266 cpl_image_get(img, x - 0, y, &bad),
2267 cpl_image_get(img, x + 1, y, &bad),
2270 *xsub = 0.5 * (sub[0] - sub[2])/(sub[0] - 2*sub[1] + sub[2]);
2272 if (y - 1 > 0 && y + 1 <= ny) {
2274 cpl_image_get(img, x, y - 1, &bad),
2275 cpl_image_get(img, x, y - 0, &bad),
2276 cpl_image_get(img, x, y + 1, &bad),
2279 *ysub = 0.5 * (sub[0] - sub[2])/(sub[0] - 2*sub[1] + sub[2]);
2282 return cpl_error_get_code();
2285static inline unsigned long get_msb(
unsigned long a)
2288 unsigned long msb = 0;
2305size_t visir_get_next_regular(
size_t a)
2313 if ((a & (a - 1)) == 0)
2316 if (5 > SIZE_MAX / a)
2319 size_t match = SIZE_MAX;
2325 size_t quotient = a % p35 != 0 ? a / p35 + 1 : a / p35;
2327 size_t p2 = 2 << get_msb(quotient - 1);
2329 size_t n = p2 * p35;
2350struct _visir_fftx_cache {
2352 cpl_image * template_fft;
2353 double template_stdev;
2356visir_fftx_cache * visir_new_fftx_cache(
void)
2358 return cpl_calloc(
sizeof(visir_fftx_cache), 1);
2361void visir_delete_fftx_cache(visir_fftx_cache * c)
2363 irplib_aligned_free(cpl_image_unwrap(c->template_fft));
2385visir_fftxcorrelate(
const cpl_image * atemplate,
const cpl_image * aimg,
2386 cpl_boolean normalize,
double * xshift,
double * yshift,
2387 double * max_correlation, visir_fftx_cache * cache)
2389 const cpl_size Nxi = cpl_image_get_size_x(aimg);
2390 const cpl_size Nyi = cpl_image_get_size_y(aimg);
2391 const cpl_size Nxt = cpl_image_get_size_x(atemplate);
2392 const cpl_size Nyt = cpl_image_get_size_y(atemplate);
2394 const cpl_size Nxe = visir_get_next_regular(Nxi + Nxt - 1);
2395 const cpl_size Nye = visir_get_next_regular(Nyi + Nyt - 1);
2396 cpl_size txshift, tyshift;
2397 double subx = 0, suby = 0;
2398 cpl_image * img = NULL;
2399 cpl_image * zimg = NULL;
2400 cpl_image * ztemp = NULL;
2401 cpl_image * fft1 = NULL;
2402 cpl_image * fft2 = NULL;
2403 cpl_image * res = NULL;
2405 double template_stdev;
2407 cpl_fft_mode mode = getenv(
"VISIR_TEST_MODE") ? 0 : CPL_FFT_FIND_MEASURE;
2409 cpl_ensure_code(atemplate != NULL, CPL_ERROR_NULL_INPUT);
2410 cpl_ensure_code(aimg != NULL, CPL_ERROR_NULL_INPUT);
2412 if (cache == NULL || cache->initialized == 0) {
2414 cpl_image *
template = NULL;
2415 if (cpl_image_get_type(atemplate) != CPL_TYPE_FLOAT)
2416 template = cpl_image_cast(atemplate, CPL_TYPE_FLOAT);
2418 template = cpl_image_duplicate(atemplate);
2420 cpl_image_fill_rejected(
template, 0);
2422 skip_if(cpl_image_subtract_scalar(
template,
2423 visir_image_get_mean_fast(
template)));
2424 template_stdev = cpl_image_get_stdev(
template);
2426 buffer = irplib_aligned_calloc(32, Nxe * Nye,
sizeof(
float));
2427 ztemp = cpl_image_wrap(Nxe, Nye, CPL_TYPE_FLOAT, buffer);
2431 skip_if(cpl_image_flip(
template, 1));
2432 skip_if(cpl_image_flip(
template, 3));
2435 skip_if(cpl_image_copy(ztemp,
template, 1, 1));
2436 cpl_image_delete(
template);
2438 buffer = irplib_aligned_malloc(32, (Nxe / 2 + 1) * Nye *
2439 sizeof(
float complex));
2440 fft2 = cpl_image_wrap(Nxe / 2 + 1, Nye, CPL_TYPE_FLOAT_COMPLEX,
2442 skip_if(cpl_fft_image(fft2, ztemp, CPL_FFT_FORWARD));
2444 cache->template_fft = fft2;
2445 cache->template_stdev = template_stdev;
2446 cache->initialized = 1;
2450 fft2 = cache->template_fft;
2451 template_stdev = cache->template_stdev;
2452 error_if(cpl_image_get_type(fft2) != CPL_TYPE_FLOAT_COMPLEX ||
2453 cpl_image_get_size_x(fft2) != Nxe / 2 + 1 ||
2454 cpl_image_get_size_y(fft2) != Nye, CPL_ERROR_ILLEGAL_INPUT,
2455 "Invalid fourier transformed template");
2460 buffer = irplib_aligned_calloc(32, Nxe * Nye,
sizeof(
float));
2461 zimg = cpl_image_wrap(Nxe, Nye, CPL_TYPE_FLOAT, buffer);
2462 if (cpl_image_get_type(aimg) != CPL_TYPE_FLOAT)
2463 img = cpl_image_cast(aimg, CPL_TYPE_FLOAT);
2465 img = cpl_image_duplicate(aimg);
2467 skip_if(img == NULL);
2469 cpl_image_fill_rejected(img, 0);
2472 skip_if(cpl_image_subtract_scalar(img,
2473 visir_image_get_mean_fast(img)));
2476 skip_if(cpl_image_copy(zimg, img, 1, 1));
2478 buffer = irplib_aligned_malloc(32, (Nxe / 2 + 1) * Nye *
2479 sizeof(
float complex));
2480 fft1 = cpl_image_wrap(Nxe / 2 + 1, Nye, CPL_TYPE_FLOAT_COMPLEX, buffer);
2482 skip_if(cpl_fft_image(fft1, zimg, CPL_FFT_FORWARD | mode));
2486 skip_if(visir_image_multiply_fast(fft1, fft2));
2488 buffer = irplib_aligned_malloc(32, Nxe * Nye *
sizeof(
float));
2489 res = cpl_image_wrap(Nxe, Nye, CPL_TYPE_FLOAT, buffer);
2490 skip_if(cpl_fft_image(res, fft1, CPL_FFT_BACKWARD | CPL_FFT_NOSCALE |
2493 skip_if(cpl_image_get_maxpos_window(res, Nxt / 2 , Nyt / 2,
2494 Nxt / 2 + Nxi, Nyt / 2 + Nyi,
2495 &txshift, &tyshift));
2497 if (max_correlation != NULL) {
2499 *max_correlation = cpl_image_get(res, txshift, tyshift, &rej);
2501 *max_correlation /= Nxe * Nye;
2504 double tstd = template_stdev;
2505 int mx = txshift - Nxt;
2506 int my = tyshift - Nyt;
2507 double istd= cpl_image_get_stdev_window(zimg,
2510 CX_MIN(Nxe, mx + Nxt),
2511 CX_MIN(Nye, my + Nyt));
2513 if (tstd * istd == 0)
2514 *max_correlation = 0;
2516 *max_correlation /= (tstd * istd * Nxt * Nyt);
2521 skip_if(visir_get_subpixel_maxpos(res, txshift, tyshift, &subx, &suby));
2522 if (xshift != NULL) {
2523 *xshift = txshift - Nxt + subx;
2525 if (yshift != NULL) {
2526 *yshift = tyshift - Nyt + suby;
2531 cpl_image_delete(img);
2533 irplib_aligned_free(cpl_image_unwrap(fft2));
2534 irplib_aligned_free(cpl_image_unwrap(fft1));
2535 irplib_aligned_free(cpl_image_unwrap(zimg));
2536 irplib_aligned_free(cpl_image_unwrap(ztemp));
2537 irplib_aligned_free(cpl_image_unwrap(res));
2539 return cpl_error_get_code();
2561get_interpolation_points(
size_t x,
size_t y,
2562 size_t nx_,
size_t ny_, cpl_binary *bpm)
2564 ssize_t l = -1, r = -1 , u = -1, d = -1;
2569 ssize_t nx = (ssize_t)nx_;
2570 ssize_t ny = (ssize_t)ny_;
2571 cx_list * p = cx_list_new();
2581 if (l < 0 && xl >= 0 && bpm[IND(xl, y, nx)] == CPL_BINARY_0)
2583 if (r < 0 && xh < nx && bpm[IND(xh, y, nx)] == CPL_BINARY_0)
2585 if (d < 0 && yl >= 0 && bpm[IND(x, yl, nx)] == CPL_BINARY_0)
2587 if (u < 0 && yh < ny && bpm[IND(x, yh, nx)] == CPL_BINARY_0)
2592 if ((l != -1 && r != -1) || (d != -1 && u != -1) ||
2593 (xl < 0 && xh >= nx && yl < 0 && yh >= ny))
2599 cx_list_push_back(p, (cxcptr)(IND(r, y, nx)));
2601 cx_list_push_back(p, (cxcptr)(IND(l, y, nx)));
2603 cx_list_push_back(p, (cxcptr)(IND(x, u, nx)));
2605 cx_list_push_back(p, (cxcptr)(IND(x, d, nx)));
2630visir_interpolate_rejected(cpl_image * img,
size_t ** ppoints,
size_t * n)
2632 cpl_mask * mask = cpl_image_get_bpm(img);
2633 float * data = cpl_image_get_data_float(img);
2634 cpl_binary * bpm = cpl_mask_get_data(mask);
2635 const size_t nx = (size_t)cpl_image_get_size_x(img);
2636 const size_t ny = (size_t)cpl_image_get_size_y(img);
2639 skip_if(data == NULL);
2641 if (ppoints == NULL || *ppoints == NULL) {
2643 cpl_binary * found = memchr(bpm, CPL_BINARY_1,
2644 sizeof(cpl_binary) * nx * ny);
2646 size_t * restrict pbpm = cpl_calloc(cpl_image_count_rejected(img) * 6,
2649 while (found != NULL) {
2650 const size_t ind = found - bpm;
2651 const size_t y = ind / nx;
2652 const size_t x = ind - y * nx;
2653 cx_list * p = get_interpolation_points(x, y, nx, ny, bpm);
2654 cx_list_iterator it = cx_list_begin(p);
2655 const size_t npix = cx_list_size(p);
2660 assert(pbpm[i - 1] <= 4);
2662 while (it != cx_list_end(p)) {
2663 const size_t lind = (size_t)cx_list_get(p, it);
2666 it = cx_list_next(p, it);
2668 data[ind] = sum / npix;
2671 found = memchr(found + 1, CPL_BINARY_1,
2672 sizeof(cpl_binary) * nx * ny - ind - 1);
2682 const size_t n_ = *n;
2683 size_t * restrict points = *ppoints;
2684 for (
size_t i = 0; i < n_;) {
2685 const size_t ind = points[i++];
2686 const size_t m = points[i++];
2688 for (
size_t j = 0; j < m; j++) {
2689 const size_t lind = points[i++];
2692 data[ind] = sum / m;
2696 cpl_image_accept_all(img);
2700 return cpl_error_get_code();
2704static const cpl_image *
2705image_const_row_view_create(
const cpl_image * img,
2709 const size_t dsz = cpl_type_get_sizeof(cpl_image_get_type(img));
2710 const cpl_size nx = cpl_image_get_size_x(img);
2711 const char * d = cpl_image_get_data_const(img);
2712 size_t offset = (ly - 1) * nx;
2713 cpl_size nny = uy - ly + 1;
2714 cpl_image * wimg = cpl_image_wrap(nx, nny, cpl_image_get_type(img),
2715 (
char*)d + offset * dsz);
2717 const cpl_mask * omask = cpl_image_get_bpm_const(img);
2719 cpl_mask * mask = cpl_mask_wrap(nx, nny,
2720 (cpl_binary*)cpl_mask_get_data_const(omask) + offset);
2721 cpl_mask_delete(cpl_image_set_bpm(wimg, mask));
2728image_const_row_view_delete(
const cpl_image * img)
2730 cpl_mask_unwrap(cpl_image_unset_bpm((cpl_image*)(img)));
2731 cpl_image_unwrap((cpl_image *)img);
2744visir_parallel_median_collapse(
const cpl_imagelist * l)
2747 return cpl_imagelist_collapse_median_create(l);
2749 cpl_ensure(l != NULL, CPL_ERROR_NULL_INPUT, NULL);
2750 cpl_ensure(cpl_imagelist_get_size(l) > 0,
2751 CPL_ERROR_ILLEGAL_INPUT, NULL);
2753 const size_t n = cpl_imagelist_get_size(l);
2754 const cpl_image * img = cpl_imagelist_get_const(l, 0);
2755 const size_t ny = cpl_image_get_size_y(img);
2756 const size_t nx = cpl_image_get_size_x(img);
2757 const size_t nthreads = CX_MIN(visir_get_num_threads(CPL_FALSE), ny);
2758 cpl_image * res = cpl_image_new(nx, ny, cpl_image_get_type(img));
2760 cpl_image_get_bpm(res);
2762 OMP_PRAGMA(omp parallel
for num_threads(nthreads))
2763 for (
size_t j = 0; j < nthreads; j++) {
2764 size_t ylow = j * (ny / nthreads) + 1;
2765 size_t yhigh = (j + 1) * (ny / nthreads);
2766 if (j == nthreads - 1)
2769 cpl_imagelist * view = cpl_imagelist_new();
2770 for (
size_t i = 0; i < n; i++) {
2771 const cpl_image * iview =
2772 image_const_row_view_create(cpl_imagelist_get_const(l, i),
2774IRPLIB_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual);
2775 cpl_imagelist_set(view, (cpl_image *)iview, i);
2776IRPLIB_DIAG_PRAGMA_POP;
2780 cpl_image * r = cpl_imagelist_collapse_median_create(view);
2781 cpl_image_copy(res, r, 1, ylow);
2784 cpl_image_delete(r);
2785 for (
size_t i = 0; i < n; i++) {
2786 image_const_row_view_delete(cpl_imagelist_get(view, i));
2788 cpl_imagelist_unwrap(view);
2803static const char * visir_get_capa(
const cpl_propertylist * plist)
2805 const char * capa =
"Pb with Capa";
2818 if (!strcmp(sval,
"IMG")) {
2822 }
else if (!strcmp(sval,
"SPC") || !strcmp(sval,
"SPCIMG")) {
2835 capa =
"Large Capa";
2836 }
else if (mean > 4.5) {
2837 capa =
"Small Capa";
2845#ifdef VISIR_MASK_HAS
2867static cpl_boolean visir_mask_has(
const cpl_mask * self, cpl_binary value,
2870 const cpl_binary * pself = cpl_mask_get_data_const(self);
2871 int size = cpl_mask_get_size_x(self)
2872 * cpl_mask_get_size_y(self);
2875 cpl_ensure(self, CPL_ERROR_NULL_INPUT, CPL_FALSE);
2876 cpl_ensure(ngood >= 0, CPL_ERROR_ILLEGAL_INPUT, CPL_FALSE);
2877 cpl_ensure(ngood <= size, CPL_ERROR_ACCESS_OUT_OF_RANGE, CPL_FALSE);
2878 cpl_ensure(value == CPL_BINARY_0 || value == CPL_BINARY_1,
2879 CPL_ERROR_INCOMPATIBLE_INPUT, CPL_FALSE);
2881 for (i = 0; i < ngood; i++) {
2883 const cpl_binary * ppos = memchr(pself, value, (
size_t)size);
2884 if (ppos == NULL)
break;
2886 size -= 1 + (int)(ppos - pself);
2890 return i == ngood ? CPL_TRUE : CPL_FALSE;
2902size_t visir_upper_bound(
const cpl_vector * vec,
double val)
2904 const double * d = cpl_vector_get_data_const(vec);
2905 long count = cpl_vector_get_size(vec);
2909 long step = count / 2;
2910 long it = first + step;
2911 if (!(val < d[it])) {
2929size_t visir_lower_bound(
const cpl_vector * vec,
double val)
2931 const double * d = cpl_vector_get_data_const(vec);
2932 long count = cpl_vector_get_size(vec);
2936 long step = count / 2;
2937 long it = first + step;
2962cpl_image * visir_linintp_values(
const cpl_image * inp,
const cpl_bivector * ref)
2964 const double * data = cpl_image_get_data_double_const(inp);
2965 const cpl_vector * rx = cpl_bivector_get_x_const(ref);
2966 const cpl_vector * ry = cpl_bivector_get_y_const(ref);
2967 size_t nref = cpl_bivector_get_size(ref);
2968 size_t nx = cpl_image_get_size_x(inp);
2969 size_t ny = cpl_image_get_size_y(inp);
2970 cpl_image * res = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
2971 double * rdata = cpl_image_get_data_double(res);
2972 cpl_ensure(nref >= 2, CPL_ERROR_ILLEGAL_INPUT, NULL);
2974 for (
size_t y = 0; y < ny; y++) {
2975 for (
size_t x = 0; x < nx; x++) {
2976 double val = data[y * nx + x];
2977 intptr_t ilo = visir_lower_bound(rx, val);
2996 rdata[y * nx + x] = cpl_vector_get(ry, 0);
2997 cpl_image_reject(res, x + 1, y + 1);
2999 else if (ilo == (intptr_t)nref) {
3000 rdata[y * nx + x] = cpl_vector_get(ry, nref - 1);
3001 cpl_image_reject(res, x + 1, y + 1);
3004 double rx1 = cpl_vector_get(rx, ilo - 1);
3005 double rx2 = cpl_vector_get(rx, ilo);
3006 double ry1 = cpl_vector_get(ry, ilo - 1);
3007 double ry2 = cpl_vector_get(ry, ilo);
3008 double grad = (ry2 - ry1) / (rx2 - rx1);
3009 double y0 = ry1 - grad * rx1;
3010 rdata[y * nx + x] = grad * val + y0;
3038fit_2d_gauss(
const cpl_image * img_,
const cpl_image * weights, cpl_size x, cpl_size y,
3039 double est_fwhmx,
double est_fwhmy,
3040 double * peak,
double * peak_err,
3041 double * major,
double * major_err,
3042 double * minor,
double * minor_err,
3043 double * angle,
double * angle_err)
3045 cpl_image * img = cpl_image_cast(img_, CPL_TYPE_DOUBLE);
3046 cpl_size llx = CX_MAX(x - est_fwhmx * 3, 1);
3047 cpl_size lly = CX_MAX(y - est_fwhmy * 3, 1);
3048 cpl_size urx = CX_MIN(x + est_fwhmx * 3, cpl_image_get_size_x(img));
3049 cpl_size ury = CX_MIN(y + est_fwhmy * 3, cpl_image_get_size_y(img));
3050 cpl_array * dpar = cpl_array_new(7, CPL_TYPE_DOUBLE);
3051 cpl_array * epar = cpl_array_new(7, CPL_TYPE_DOUBLE);
3052 cpl_matrix * cov = NULL;
3053 cpl_matrix * phys_cov = NULL;
3055 cpl_array_set_double(dpar, 0, cpl_image_get_median(img));
3056 cpl_array_set_double(dpar, 1, cpl_image_get_flux_window(img, llx, lly,
3058 cpl_array_set_double(dpar, 2, 0.);
3059 cpl_array_set_double(dpar, 3, x);
3060 cpl_array_set_double(dpar, 4, y);
3061 cpl_array_set_double(dpar, 5, est_fwhmx / 2.355);
3062 cpl_array_set_double(dpar, 6, est_fwhmx / 2.355);
3064 cpl_image * err = cpl_image_new(cpl_image_get_size_x(img),
3065 cpl_image_get_size_y(img),
3067 cpl_image_add_scalar(err, 1.);
3068 cpl_image_divide(err, weights);
3069 cpl_image_power(err, 0.5);
3071 skip_if(cpl_fit_image_gaussian(img, err,
3092 double * a = cpl_array_get_data_double(dpar);
3093 *peak = a[0] + a[1] /
3094 (CPL_MATH_2PI * a[5] * a[6] * sqrt(1.0 - a[2] * a[2]));
3096 cpl_msg_warning(cpl_func,
"2d gaussfit, could not determine peak");
3101 double * a = cpl_array_get_data_double(dpar);
3102 double * e = cpl_array_get_data_double(epar);
3107 double dB = sqrt(e[0]);
3108 double dA = sqrt(e[1]);
3109 double dsigx = sqrt(e[5]);
3110 double dsigy = sqrt(e[6]);
3111 double drho = sqrt(e[2]);
3113 double rho2 = rho * rho;
3114 double xd = CPL_MATH_PI * CPL_MATH_PI * 4 * sigx * sigx * sigy * sigy;
3116 sqrt(A2 * drho * drho * rho2 /(xd * pow(-rho2 + 1.0, 3)) +
3117 A2 * dsigx * dsigx /(xd * sigx * sigx * (-rho2 + 1.0)) +
3118 A2 * dsigy * dsigy /(xd * sigy * sigy * (-rho2 + 1.0)) +
3119 dA * dA/(xd * (-rho2 + 1.0)) + dB * dB);
3120 if (isnan(*peak_err)) {
3125 *major *= CPL_MATH_FWHM_SIG;
3126 if (isnan(*major)) {
3127 cpl_msg_warning(cpl_func,
3128 "2d gaussfit, could not determine major axis");
3133 *minor *= CPL_MATH_FWHM_SIG;
3134 if (isnan(*minor)) {
3135 cpl_msg_warning(cpl_func,
3136 "2d gaussfit, could not determine minor axis");
3141 *major_err = sqrt(cpl_matrix_get(phys_cov, 1, 1)) * CPL_MATH_FWHM_SIG;
3142 if (isnan(*major_err)) {
3147 *minor_err = sqrt(cpl_matrix_get(phys_cov, 2, 2)) * CPL_MATH_FWHM_SIG;
3148 if (isnan(*minor_err)) {
3153 *angle_err = sqrt(cpl_matrix_get(phys_cov, 0, 0));
3154 if (isnan(*angle_err)) {
3160 cpl_array_delete(dpar);
3161 cpl_array_delete(epar);
3162 cpl_image_delete(err);
3163 cpl_image_delete(img);
3164 cpl_matrix_delete(phys_cov);
3165 cpl_matrix_delete(cov);
3167 return cpl_error_get_code();
3187fit_1d_gauss(
const cpl_vector * xv,
const cpl_vector * yv, cpl_vector * dyv,
3188 double * x0,
double * x0_err,
3189 double * peak,
double * peak_err,
3190 double * sigma_,
double * sigma_err)
3192 double sigma, area, offset;
3193 cpl_matrix * cov = NULL;
3194 skip_if(cpl_vector_fit_gaussian(xv, NULL,
3196 CPL_FIT_CENTROID | CPL_FIT_STDEV |
3197 CPL_FIT_AREA | CPL_FIT_OFFSET,
3198 x0, &sigma, &area, &offset,
3201 if (x0 && isnan(*x0)) {
3202 cpl_msg_warning(cpl_func,
"1d gaussfit, could not determine mean");
3206 *x0_err = sqrt(cpl_matrix_get(cov, 0, 0));
3207 if (isnan(*x0_err)) {
3213 if (isnan(*sigma_)) {
3214 cpl_msg_warning(cpl_func,
3215 "1d gaussfit, could not determine sigma");
3220 *peak = area / sqrt(2 * CPL_MATH_PI * sigma * sigma) + offset;
3222 cpl_msg_warning(cpl_func,
"1d gaussfit, could not determine peak");
3227 double dsig = sqrt(cpl_matrix_get(cov, 1, 1));
3228 double dA = sqrt(cpl_matrix_get(cov, 2, 2));
3229 double dB = sqrt(cpl_matrix_get(cov, 3, 3));
3230 double pi2sig2 = 2 * CPL_MATH_PI * sigma * sigma;
3231 *peak_err = sqrt(dsig * dsig * area * area /
3232 (2 * CPL_MATH_PI * pi2sig2 * sigma * sigma) +
3233 dA * dA / pi2sig2 + dB * dB);
3234 if (isnan(*peak_err)) {
3239 *sigma_err = sqrt(cpl_matrix_get(cov, 1, 1));
3240 if (isnan(*sigma_err)) {
3246 cpl_matrix_delete(cov);
3248 return cpl_error_get_code();
double visir_pfits_get_monoc_pos(const cpl_propertylist *self)
The INS.MONOC1.POS.
int visir_pfits_get_navrg(const cpl_propertylist *self)
The NAVRG.
double visir_pfits_get_dit(const cpl_propertylist *self)
The DIT.
double visir_pfits_get_volt1dctb9(const cpl_propertylist *self)
The VOLT1.DCTB9.
int visir_pfits_get_chop_ncycles(const cpl_propertylist *self)
The number of chopping cycles.
double visir_pfits_get_volt2dctb9(const cpl_propertylist *self)
The VOLT2.DCTB9.
const char * visir_pfits_get_insmode(const cpl_propertylist *self)
The mode.
const char * visir_pfits_get_filter(const cpl_propertylist *self)
The filter.
double visir_pfits_get_volt2dcta9(const cpl_propertylist *self)
The VOLT2.DCTA9.
int visir_pfits_get_ndit(const cpl_propertylist *self)
The NDIT keyword.
double visir_pfits_get_volt1dcta9(const cpl_propertylist *self)
The VOLT1.DCTA9.