IIINSTRUMENT Pipeline Reference Manual 4.5.1
visir_utils.c
1/* $Id: visir_utils.c,v 1.187 2013-09-24 10:19:57 jtaylor Exp $
2 *
3 * This file is part of the VISIR Pipeline
4 * Copyright (C) 2002,2003,2013,2014 European Southern Observatory
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19 */
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25/*-----------------------------------------------------------------------------
26 Includes
27 -----------------------------------------------------------------------------*/
28
29#include "visir_utils.h"
30
31#include "irplib_utils.h"
32
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"
38#include <cpl.h>
39#include <cxlist.h>
40#include <sys/types.h> /* for waitpid */
41#include <sys/wait.h> /* for waitpid */
42#include <errno.h>
43
44#include <string.h>
45#include <math.h>
46#include <assert.h>
47#include <stdlib.h>
48#include <unistd.h>
49#include <libgen.h>
50#include <stdint.h> /* for intptr_t */
51
52/* for mkdir, open, posix_fadvise */
53#include <sys/stat.h>
54#include <sys/types.h>
55#include <fcntl.h>
56
57#include <signal.h> /* for sigaction, sigemptyset */
58
59#ifdef _OPENMP
60#include <omp.h>
61#endif
62
63/* make sure we have fdopen (posix 1990) */
64IRPLIB_DIAG_PRAGMA_PUSH_ERR(-Wimplicit-function-declaration)
65
66#ifdef __SSE3__
67#include <pmmintrin.h>
68#endif
69#ifdef __SSE2__
70#include <xmmintrin.h>
71#endif
72
73/*-----------------------------------------------------------------------------
74 Define
75 -----------------------------------------------------------------------------*/
76
77#define VISIR_BACKGD_START 76
78#define VISIR_BACKGD_STOP 172
79
80/*----------------------------------------------------------------------------*/
86/*----------------------------------------------------------------------------*/
87
88#define IND(x, y , nx) ((x) + (nx) * (y))
89
90/*-----------------------------------------------------------------------------
91 Private function prototypes
92 -----------------------------------------------------------------------------*/
93
94
95static double visir_great_circle_dist(double, double, double, double);
96static double ra_hms2deg(int, int, double);
97static double dec_hms2deg(int, int, double);
98
99static const char * visir_get_capa(const cpl_propertylist *);
100static double visir_hcycle_background(const irplib_framelist *, int, int);
101
102#ifdef VISIR_MASK_HAS
103static cpl_boolean visir_mask_has(const cpl_mask *, cpl_binary, int);
104#endif
105
109/*----------------------------------------------------------------------------*/
115/*----------------------------------------------------------------------------*/
116size_t visir_get_num_threads(cpl_boolean force)
117{
118 long ret = 1;
119 FILE * f;
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;
124 }
125#ifdef _OPENMP
126 /* respects affinity */
127 ret = omp_get_max_threads();
128#endif
129#if defined HAVE_SYSCONF && defined _SC_NPROCESSORS_ONLN
130 ret = sysconf(_SC_NPROCESSORS_ONLN);
131#endif
132 /* simple linux only check for hyperthreading, not useful for visir */
133 f = fopen("/sys/devices/system/cpu/cpu0/"
134 "topology/thread_siblings_list", "r");
135 if (f) {
136 char buf[80];
137 if (fgets(buf, 80, f) != NULL) {
138 int a, b;
139 buf[79] = 0;
140 if (sscanf(buf, "%d,%d", &a, &b) == 2) {
141 ret /= 2;
142 }
143 }
144 fclose(f);
145 }
146 return ret < 1 ? 1 : ret;
147}
148
149
150/*----------------------------------------------------------------------------*/
157/*----------------------------------------------------------------------------*/
158cpl_boolean visir_get_tempdir(char * tmpdir_)
159{
160 cpl_boolean have_tmpdir = CPL_FALSE;
161 char tmpdir[strlen(tmpdir_) + 1];
162
163 /* create safe tempfile, remove it and reuse name for mkdir,
164 * mkdir is atomic and symlink safe but we need to try multiple times
165 * due to the possible race between unlink and mkdir */
166 for (int i = 0; i < 10 && !have_tmpdir; i++) {
167 strcpy(tmpdir, tmpdir_);
168 int fd = mkstemp(tmpdir);
169 skip_if(fd < 0);
170 close(fd);
171 skip_if(unlink(tmpdir));
172 have_tmpdir = mkdir(tmpdir, O_RDWR | S_IRWXU) == 0;
173 }
174
175 error_if(have_tmpdir != CPL_TRUE, CPL_ERROR_FILE_IO,
176 "Temporary directory creation failed");
177
178 strcpy(tmpdir_, tmpdir);
179
180 end_skip;
181
182 return have_tmpdir;
183}
184
185/* ---------------------------------------------------------------------------*/
190/* ---------------------------------------------------------------------------*/
191char * visir_get_cwd(void)
192{
193 size_t n = 4096;
194 char * buf;
195 errno = 0;
196 /* if only we could use sane GNU functions instead of this posix crap */
197 while (1) {
198 buf = cpl_malloc(n);
199 if (getcwd(buf, n) != 0) {
200 break;
201 }
202 else if (errno == ERANGE) {
203 /* increase buffer, repeat */
204 errno = 0;
205 n *= 2;
206 cpl_free(buf);
207 }
208 else {
209 cpl_free(buf);
210 cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
211 "Could not determine current working "
212 "directory: %s", strerror(errno));
213 return NULL;
214 }
215 }
216
217 return buf;
218}
219
220/* ---------------------------------------------------------------------------*/
227/* ---------------------------------------------------------------------------*/
228void visir_drop_cache(const char * VISIR_ATTR_UNUSED filename,
229 off_t VISIR_ATTR_UNUSED offset,
230 off_t VISIR_ATTR_UNUSED length)
231{
232#if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_DONTNEED
233 int fd = open(filename, O_RDONLY);
234 if (fd != -1) {
235 /* POSIX_FADV_NOREUSE is a nop on linux */
236 posix_fadvise(fd, offset, length, POSIX_FADV_DONTNEED);
237 close(fd);
238 }
239#endif
240}
241
242/* ---------------------------------------------------------------------------*/
254/* ---------------------------------------------------------------------------*/
255void visir_readahead(const char * VISIR_ATTR_UNUSED filename,
256 off_t VISIR_ATTR_UNUSED offset, off_t VISIR_ATTR_UNUSED length)
257{
258#if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_WILLNEED
259 int fd = open(filename, O_RDONLY);
260 if (fd != -1) {
261 /* does the same as readahead(2) on linux */
262 posix_fadvise(fd, offset, length, POSIX_FADV_WILLNEED);
263 close(fd);
264 }
265#endif
266}
267
268/* ---------------------------------------------------------------------------*/
273/* ---------------------------------------------------------------------------*/
274size_t visir_get_nbytes(const cpl_image * img)
275{
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));
279}
280
281/* ---------------------------------------------------------------------------*/
290/* ---------------------------------------------------------------------------*/
291size_t visir_get_nbytes_plist(const cpl_propertylist * self)
292{
293 int naxis = visir_pfits_get_int("NAXIS");
294 int bitpix = abs(visir_pfits_get_int("BITPIX"));
295 int pcount = 0;
296 int gcount = 1;
297 size_t naxis_bytes = 1;
298 size_t nbytes;
299 for (int i = 0; i < naxis; i++) {
300 char buffer[80];
301 sprintf(buffer, "NAXIS%d", i + 1);
302 naxis_bytes *= visir_pfits_get_int(buffer);
303 }
304 if (cpl_propertylist_has(self, "XTENSION")) {
305 pcount = visir_pfits_get_int("PCOUNT");
306 gcount = visir_pfits_get_int("GCOUNT");
307 }
308 if (cpl_error_get_code())
309 return 0;
310
311 nbytes = (bitpix / 8) * gcount * (pcount + naxis_bytes);
312 /* approximation as there may be empty headers */
313 nbytes += cpl_propertylist_get_size(self) * 80;
314 return nbytes;
315}
316
317/*----------------------------------------------------------------------------*/
328/*----------------------------------------------------------------------------*/
329cpl_error_code visir_image_multiply_fast(cpl_image * im1,
330 const cpl_image * im2)
331{
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);
335
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;
344
345 float complex * a = cpl_image_get_data(im1);
346 const float complex * b = cpl_image_get_data_const(im2);
347
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);
351
352 /* if unaligned fall back to cpl, it is vectorized since 6.1 too but
353 * checks for NaN which makes it a bit slower */
354 if (((intptr_t)a % 16) != 0 || ((intptr_t)b % 16) != 0)
355 return cpl_image_multiply(im1, im2);
356
357#if defined __SSE2__ && !defined __SSE3__
358 const __m128 neg = (__m128)_mm_set_epi32(0x0u, 0x80000000u, 0x0u, 0x80000000u);
359#endif
360 for (size_t i = 0; i < n; i += 2) {
361 __m128 ua = _mm_load_ps((float *)&a[i]); /* x w */
362 __m128 ub = _mm_load_ps((const float *)&b[i]); /* y z */
363 /* optimized to SSE3 _mm_move[hl]dup_ps by gcc */
364 __m128 reala = _mm_shuffle_ps(ua, ua, _MM_SHUFFLE(2, 2, 0, 0)); /* x x */
365 __m128 imaga = _mm_shuffle_ps(ua, ua, _MM_SHUFFLE(3, 3, 1, 1)); /* w w */
366 __m128 t1 = _mm_mul_ps(reala, ub); /* x*y x*z */
367 __m128 sb = _mm_shuffle_ps(ub, ub, _MM_SHUFFLE(2, 3, 0, 1)); /* z y */
368 __m128 t2 = _mm_mul_ps(imaga, sb); /* w*z w*y */
369#if defined __SSE2__ && !defined __SSE3__
370 t2 = _mm_xor_ps(t2, neg); /* faster than multipling with 1,-1,1,-1 */
371 __m128 res = _mm_add_ps(t1, t2);
372#else
373 __m128 res = _mm_addsub_ps(t1, t2); /* x*y-w*z x*z+w*y*/
374#endif
375 _mm_store_ps((float *)&a[i], res);
376 }
377
378 if ((Nt) % 2 == 1)
379 a[Nt - 1] = a[Nt - 1] * b[Nt - 1];
380
381 /* Handle bad pixels map */
382 const cpl_mask * bpm1 = cpl_image_get_bpm_const(im1);
383 const cpl_mask * bpm2 = cpl_image_get_bpm_const(im2);
384 if (bpm2 != NULL) {
385 if (bpm1 == NULL)
386 cpl_image_reject_from_mask(im1, bpm2);
387 else {
388 cpl_mask_or(cpl_image_get_bpm(im1), bpm2);
389 }
390 }
391
392 } else
393#endif
394 cpl_image_multiply(im1, im2);
395
396 return CPL_ERROR_NONE;
397}
398
399/* ---------------------------------------------------------------------------*/
410/* ---------------------------------------------------------------------------*/
411double visir_image_get_mean_fast(const cpl_image * im)
412{
413 if (im == NULL || cpl_image_get_type(im) != CPL_TYPE_FLOAT) {
414 return cpl_image_get_mean(im);
415 }
416 else {
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);
421 /* sum into multiple values to break dependency cycle and improve
422 * accuracy slightly (see pairwise summation) */
423 double sum1 = 0;
424 double sum2 = 0;
425 double sum3 = 0;
426 double sum4 = 0;
427 if (nbad == 0) {
428 size_t i;
429 for (i = 0; i < npix - (npix % 4u); i+=4) {
430 sum1 += data[i];
431 sum2 += data[i + 1];
432 sum3 += data[i + 2];
433 sum4 += data[i + 3];
434 }
435 for (; i < npix; i++) {
436 sum1 += data[i];
437 }
438 }
439 else if (nbad == npix) {
440 return 0.;
441 }
442 else {
443 size_t i;
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) {
447 if (!m[i])
448 sum1 += data[i];
449 if (!m[i + 1])
450 sum2 += data[i + 1];
451 if (!m[i + 2])
452 sum3 += data[i + 2];
453 if (!m[i + 3])
454 sum4 += data[i + 3];
455 }
456 for (; i < npix; i++) {
457 if (!m[i])
458 sum1 += data[i];
459 }
460 }
461 return (sum1 + sum2 + sum3 + sum4) / (npix - nbad);
462 }
463}
464
465
466/*----------------------------------------------------------------------------*/
474/*----------------------------------------------------------------------------*/
475int visir_cmp_frm_fn(const cpl_frame * a, const cpl_frame * b)
476{
477 const char * fna = cpl_frame_get_filename(a);
478 const char * fnb = cpl_frame_get_filename(b);
479
480 return strcmp(fna, fnb);
481}
482
483/*----------------------------------------------------------------------------*/
492/*----------------------------------------------------------------------------*/
493cpl_error_code visir_move_products(cpl_frameset *frames,
494 const char * dest_, const char * src_)
495{
496 const char * dest = dest_ ? dest_ : ".";
497 const char * src = src_ ? src_ : ".";
498
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));
503 cpl_free(buf);
504
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);
511 cpl_free(buf);
512 cpl_free(new_fn);
513 skip_if(0);
514 }
515 /* DFS11986: new_fn is an absolute path
516 * esorex cannot deal with paths in the filename */
517 /* cpl_frame_set_filename(frm, new_fn); */
518 cpl_free(buf);
519 cpl_free(new_fn);
520 skip_if(0);
521 }
522 /* remove ../ from adapted relative paths again so esorex finds them */
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) {
526 continue;
527 }
528 char * buf = cpl_strdup(cpl_frame_get_filename(frm));
529 cpl_frame_set_filename(frm, buf + 3);
530 cpl_free(buf);
531 }
532 }
533
534 end_skip;
535
536 return cpl_error_get_code();
537}
538
539
540/*----------------------------------------------------------------------------*/
549/*----------------------------------------------------------------------------*/
550cpl_parameter * visir_parameter_duplicate(const cpl_parameter * p)
551{
552 cpl_parameter * np = NULL;
553
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);
557
558 switch (cpl_parameter_get_type(p)) {
559 case CPL_TYPE_BOOL:
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));
566 break;
567
568 case CPL_TYPE_INT:
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));
575 break;
576
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));
584 break;
585
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));
593 break;
594
595 default:
596 cpl_error_set_message(cpl_func, CPL_ERROR_UNSUPPORTED_MODE,
597 "Parameter has unknown type");
598 break;
599 }
600
601 if (np == NULL)
602 return NULL;
603
604 if (cpl_parameter_get_tag(p))
605 cpl_parameter_set_tag(np, cpl_parameter_get_tag(p));
606
607 {
608 cpl_parameter_mode modes[] = {CPL_PARAMETER_MODE_CLI,
609 CPL_PARAMETER_MODE_CFG, CPL_PARAMETER_MODE_ENV};
610
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]);
616 }
617 }
618
619 return np;
620}
621
622
623/*----------------------------------------------------------------------------*/
634/*----------------------------------------------------------------------------*/
635cpl_error_code visir_copy_parameters(cpl_parameterlist * dest,
636 const cpl_parameterlist * src)
637{
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));
642
643 if (!par)
644 continue;
645
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));
655 else
656 bug_if(1);
657 }
658
659 end_skip;
660
661 return cpl_error_get_code();
662}
663
664
665/*----------------------------------------------------------------------------*/
674/*----------------------------------------------------------------------------*/
675cpl_recipe *
676visir_init_recipe(const char * name, int (*get_info)(cpl_pluginlist *),
677 cpl_pluginlist * plugins)
678{
679 cpl_recipe * recipe = cpl_calloc(1, sizeof(cpl_recipe));
680 get_info(plugins);
681 cpl_plugin * pl = cpl_pluginlist_find (plugins, name);
682 cpl_plugin_copy ((cpl_plugin *) & recipe->interface, pl);
683 return recipe;
684}
685
686
687/*----------------------------------------------------------------------------*/
698/*----------------------------------------------------------------------------*/
699cpl_error_code
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 *))
704{
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);
709
710 skip_if(0);
711
712 recipe->frames = framelist;
713
714 /* write out sof file for easier debugging of recipe chains */
715 if (getenv("VISIR_TEST_MODE")) {
716 char * buf = cpl_sprintf("%s.sof", cpl_plugin_get_name(pl));
717 FILE * f = fopen(buf, "wt");
718 cpl_free(buf);
719 FOR_EACH_FRAMESET(frm, framelist) {
720 fprintf(f, "%s %s\n", cpl_frame_get_filename(frm), cpl_frame_get_tag(frm));
721 }
722 fclose(f);
723 }
724
725 /* clear cache as new recipes usually start from extension 1 */
726 cpl_fits_set_mode(CPL_FITS_RESTART_CACHING);
727
728 plugin_func_init(&recipe->interface);
729 if (set_parlist)
730 set_parlist(recipe->parameters, parlist);
731 plugin_func_exec(&recipe->interface);
732 plugin_func_deinit(&recipe->interface);
733
734 end_skip;
735
736 cpl_fits_set_mode(CPL_FITS_RESTART_CACHING);
737
738 return cpl_error_get_code();
739}
740
741
742/*----------------------------------------------------------------------------*/
758/*----------------------------------------------------------------------------*/
759cpl_frameset *
760visir_prepare_frameset(const cpl_frameset * frameset,
761 const char ** tagmap, size_t ntags,
762 cpl_boolean reverse)
763{
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);
767
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]);
776
777 cx_list_push_back(_nlist, frm);
778 }
779 if (cpl_frame_get_group(frame) == CPL_FRAME_GROUP_CALIB)
780 cx_list_push_back(_nlist, cpl_frame_duplicate(frame));
781 }
782
783 cx_list_sort(_nlist, (cx_compare_func)visir_cmp_frm_fn);
784 if (reverse) {
785 cx_list_reverse(_nlist);
786 }
787
788 FOR_EACH(it, _nlist)
789 cpl_frameset_insert(nlist, cx_list_get(_nlist, it));
790 cx_list_delete(_nlist);
791
792 return nlist;
793}
794
795/* ---------------------------------------------------------------------------*/
804/* ---------------------------------------------------------------------------*/
805cpl_frameset * visir_remove_modified_calib(cpl_frameset * set)
806{
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) {
812 continue;
813 }
814 cpl_frameset_insert(cleanset, cpl_frame_duplicate(frame));
815 }
816 cpl_frameset_delete(set);
817
818 return cleanset;
819}
820
821
822/*----------------------------------------------------------------------------*/
831/*----------------------------------------------------------------------------*/
832static cpl_frameset *
833visir_wait_for_child(pid_t pid, FILE * rpipe)
834{
835 char * rbuffer = NULL;
836 int status;
837 cpl_error_code err;
838 size_t size;
839 cpl_frameset * result = NULL;
840
841 /* we must read before waiting for the child else the writes may block
842 * use stream to save us the EINTR and partial read loops
843 * pipes are all closed on error so fread will fail if child fails */
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);
847
848 skip_if(fread(&size, sizeof(size), 1, rpipe) != 1);
849
850 rbuffer = cpl_malloc(size);
851 skip_if(fread(rbuffer, size, 1, rpipe) != 1);
852
853 result = visir_frameset_deserialize(rbuffer, NULL);
854
855 end_skip;
856
857 /* wait for child to end */
858 if (waitpid(pid, &status, 0) != pid) {
859 cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
860 "%s", strerror(errno));
861 }
862 else if (WIFSIGNALED(status)) {
863 cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
864 "Process killed by signal %d", WTERMSIG(status));
865 }
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));
870 }
871 else
872 assert(1);
873
874 cpl_free(rbuffer);
875
876 return result;
877}
878
879/* ---------------------------------------------------------------------------*/
887/* ---------------------------------------------------------------------------*/
888static void
889remove_tempdir(const cpl_parameterlist * parlist, const char* recipename,
890 const char * tmpdir)
891{
892 const cpl_boolean delete =
893 irplib_parameterlist_get_bool(parlist, PACKAGE,
894 recipename, "delete-temp");
895
896 if (delete) {
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);
902 cpl_free(cmd);
903 }
904 else
905 cpl_msg_info(cpl_func, "Keeping temporary directory: %s", tmpdir);
906}
907
908/*----------------------------------------------------------------------------*/
917/*----------------------------------------------------------------------------*/
918cpl_error_code
919visir_tmpdir_exec(const char * recipename, cpl_plugin * plugin,
920 int (*function)(cpl_frameset *, const cpl_parameterlist *))
921{
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);
927
928 have_tmpdir = visir_get_tempdir(tmpdir);
929 skip_if(have_tmpdir != CPL_TRUE);
930
931 cpl_msg_info(cpl_func, "Working in temporary directory: %s", tmpdir);
932
933 /* go to 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);
937 }
938
939 /* correct relative paths for the change to the 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);
944 cpl_free(buf);
945 }
946 }
947
948 cpl_recipedefine_exec(plugin, function);
949
950 if (chdir("..") != 0) {
951 return cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
952 "Could not change back to base directory");
953 }
954
955 /* move end products from tmp to cwd */
956 skip_if(visir_move_products(recipe->frames, ".", tmpdir));
957
958 end_skip;
959
960 if (have_tmpdir) {
961 remove_tempdir(recipe->parameters, recipename, tmpdir);
962 }
963
964 if (!cpl_errorstate_is_equal(cleanstate))
965 cpl_errorstate_dump(cleanstate, CPL_FALSE, NULL);
966
967 return cpl_error_get_code();
968}
969
970
971/*----------------------------------------------------------------------------*/
980/*----------------------------------------------------------------------------*/
981cpl_error_code
982visir_forking_exec(const char * recipename, cpl_plugin * plugin,
983 int (*function)(cpl_frameset *, const cpl_parameterlist *))
984{
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;
990 int pipe_fd[2];
991 static const int READ = 0, WRITE = 1;
992 sprintf(tmpdir, "%s_XXXXXX", recipename);
993
994 /* ignore sigint in parent to ensure cleanup */
995 struct sigaction sa, sa_orig;
996 sa.sa_handler = SIG_IGN;
997 sigemptyset(&sa.sa_mask);
998 sa.sa_flags = 0;
999 skip_if(sigaction(SIGINT, &sa, &sa_orig) != 0);
1000
1001 have_tmpdir = visir_get_tempdir(tmpdir);
1002 skip_if(have_tmpdir != CPL_TRUE);
1003
1004 cpl_msg_info(cpl_func, "Working in temporary directory: %s", tmpdir);
1005
1006 skip_if(pipe(pipe_fd) != 0);
1007
1008 pid_t pid = fork();
1009 if (pid == -1) {
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));
1014 skip_if(0);
1015 }
1016 else if (pid == 0) {
1017 /* restore default signal handler */
1018 sigaction(SIGINT, &sa_orig, NULL);
1019
1020 /* close unused read and convert write to stream for convinience */
1021 close(pipe_fd[READ]);
1022 pipe_stream = fdopen(pipe_fd[WRITE], "w");
1023
1024 /* go to tmpdir */
1025 if (!pipe_stream || chdir(tmpdir) != 0) {
1026 close(pipe_fd[WRITE]);
1027 _exit(EXIT_FAILURE);
1028 }
1029
1030 /* correct relative paths for the change to the tmpdir */
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);
1035 cpl_free(buf);
1036 }
1037 }
1038
1039 cpl_error_code err = cpl_recipedefine_exec(plugin, function)
1040 ? (int)cpl_error_set_where(cpl_func) : 0;
1041
1042 if (err == CPL_ERROR_NONE) {
1043 assert((void*)recipe == (void*)plugin);
1044 err = visir_send_frameset(pipe_stream, recipe->frames);
1045 }
1046 fclose(pipe_stream);
1047 _exit(err);
1048 }
1049 else {
1050 /* close unused write and convert read to stream for convinience */
1051 close(pipe_fd[WRITE]);
1052 pipe_stream = fdopen(pipe_fd[READ], "r");
1053 skip_if(pipe_stream == NULL);
1054
1055 recipe->frames = visir_wait_for_child(pid, pipe_stream);
1056 fclose(pipe_stream);
1057 skip_if(recipe->frames == NULL);
1058
1059 /* move end products from tmp to cwd */
1060 skip_if(visir_move_products(recipe->frames, ".", tmpdir));
1061 }
1062
1063 end_skip;
1064
1065 if (have_tmpdir) {
1066 remove_tempdir(recipe->parameters, recipename, tmpdir);
1067 }
1068
1069 if (!cpl_errorstate_is_equal(cleanstate))
1070 cpl_errorstate_dump(cleanstate, CPL_FALSE, NULL);
1071
1072 return cpl_error_get_code();
1073}
1074
1075/*----------------------------------------------------------------------------*/
1083/*----------------------------------------------------------------------------*/
1084double visir_utils_get_exptime(const int nnod, const cpl_propertylist * plist)
1085{
1086 /* fits EXPTIME key is equal to DIT * NAVRG with NGC */
1087 /* DIT */
1088 const double dit = visir_pfits_get_dit(plist);
1089 /* NDIT */
1090 const int ndit = visir_pfits_get_ndit(plist);
1091 /* NAVRG */
1092 const int navrg = visir_pfits_get_navrg(plist);
1093 /* Number of chopping cycles */
1094 const int ncycles = visir_pfits_get_chop_ncycles(plist);
1095
1096 /* exptime *= 2 because of chopping */
1097 const double value = 2 * dit * ndit * nnod * ncycles * navrg;
1098
1099 if (value <= 0) {
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);
1103 skip_if(1);
1104 }
1105
1106 end_skip;
1107 return value;
1108}
1109
1110/*----------------------------------------------------------------------------*/
1119/*----------------------------------------------------------------------------*/
1120double * visir_utils_get_wls(const irplib_framelist * self)
1121{
1122 /* Get the number of files */
1123 const int size = irplib_framelist_get_size(self);
1124 double * wls = NULL;
1125 int i;
1126
1127
1128 skip_if (0);
1129
1130 skip_if(irplib_framelist_contains(self, VISIR_PFITS_DOUBLE_MONOC_POS,
1131 CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
1132
1133 /* Allocate the output array */
1134 wls = cpl_malloc(size * sizeof(double));
1135
1136 /* Get the wavelengths */
1137 for (i=0; i < size; i++) {
1138 const cpl_propertylist * plist
1139 = irplib_framelist_get_propertylist_const(self, i);
1140
1141 wls[i] = visir_pfits_get_monoc_pos(plist);
1142
1143 skip_if (0);
1144 }
1145
1146 end_skip;
1147
1148 if (cpl_error_get_code()) {
1149 cpl_free(wls);
1150 wls = NULL;
1151 }
1152
1153 return wls;
1154}
1155
1156/*----------------------------------------------------------------------------*/
1166/*----------------------------------------------------------------------------*/
1167cpl_image * visir_create_disk_intimage(
1168 int nx,
1169 int ny,
1170 int x_pos,
1171 int y_pos,
1172 int radius)
1173{
1174 cpl_image * intima;
1175 int * pintima;
1176 double dist;
1177 int i, j;
1178
1179 /* Create the empty output image */
1180 intima = cpl_image_new(nx, ny, CPL_TYPE_INT);
1181 pintima = cpl_image_get_data_int(intima);
1182
1183 /* Loop on the pixels */
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;
1189 } else {
1190 pintima[i+j*nx] = 0;
1191 }
1192 }
1193 }
1194 return intima;
1195}
1196
1197/*----------------------------------------------------------------------------*/
1208/*----------------------------------------------------------------------------*/
1209cpl_image * visir_create_ring_intimage(
1210 int nx,
1211 int ny,
1212 int x_pos,
1213 int y_pos,
1214 int radius1,
1215 int radius2)
1216{
1217 cpl_image * intima;
1218 int * pintima;
1219 double dist;
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);
1224 return NULL;
1225 }
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);
1232 return NULL;
1233 }
1234
1235 /* Create the empty output image */
1236 intima = cpl_image_new(nx, ny, CPL_TYPE_INT);
1237 pintima = cpl_image_get_data_int(intima);
1238
1239 /* Loop on the pixels */
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;
1245 } else {
1246 pintima[i+j*nx] = 0;
1247 }
1248 }
1249 }
1250 return intima;
1251}
1252
1253/*----------------------------------------------------------------------------*/
1264/*----------------------------------------------------------------------------*/
1265double visir_image_sigma_clip(const cpl_image * self, double * pstdev)
1266{
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);
1270 /* Apply a 3x3 median filter to the input image */
1271 /* FIXME: A wrap (around float/double) would be sufficient */
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;
1279 int i = -1;
1280
1281
1282 bug_if (0);
1283
1284 bug_if(cpl_mask_not(kernel));
1285 bug_if(cpl_image_filter_mask(noise, self, kernel, CPL_FILTER_MEDIAN,
1286 CPL_BORDER_FILTER));
1287
1288 /* (Inverted) Noise image */
1289 bug_if (cpl_image_subtract(noise, self));
1290
1291 for (i=0; i < niterations ; i++) {
1292 /* Compute mean and stdev */
1293 cpl_stats * stats =
1294 cpl_stats_new_from_image(noise, CPL_STATS_MEAN | CPL_STATS_STDEV);
1295
1296 const double mean = cpl_stats_get_mean(stats);
1297 const double stdev = cpl_stats_get_stdev(stats);
1298
1299 /* Set the thresholds */
1300 const double low_thresh = mean - sigma * stdev;
1301 const double high_thresh = mean + sigma * stdev;
1302
1303
1304 cpl_stats_delete(stats); /* :-( */
1305
1306 /* The previous thresholding may have left too few good pixels */
1307 skip_if (0);
1308
1309 /* Identify where mean-sigma*stdev < noise < mean+sigma*stdev */
1310 bpm = cpl_mask_threshold_image_create(noise, low_thresh, high_thresh);
1311
1312 bug_if (0);
1313
1314 bug_if (cpl_mask_not(bpm));
1315
1316 bug_if (cpl_image_reject_from_mask(noise, bpm));
1317
1318 cpl_mask_delete(bpm); /* :-( */
1319 bpm = NULL;
1320
1321 }
1322
1323 if (pstdev != NULL) {
1324 /* Compute the stdev of the noise and the background */
1325
1326 cpl_stats * stats =
1327 cpl_stats_new_from_image(noise, CPL_STATS_MEAN | CPL_STATS_STDEV);
1328
1329 /* Compute mean and stdev */
1330 bgnoise = cpl_stats_get_stdev(stats);
1331 *pstdev = cpl_image_get_median(self) - cpl_stats_get_mean(stats);
1332
1333 cpl_stats_delete(stats);
1334 } else {
1335 /* Compute the stdev */
1336 bgnoise = cpl_image_get_stdev(noise);
1337 }
1338
1339 bug_if(0);
1340
1341 bgnoise /= median_corr;
1342
1343 end_skip;
1344
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);
1348
1349 cpl_mask_delete(kernel);
1350 cpl_mask_delete(bpm);
1351 cpl_image_delete(noise);
1352
1353 return bgnoise;
1354}
1355
1356/*----------------------------------------------------------------------------*/
1366/*----------------------------------------------------------------------------*/
1367double visir_img_phot_sigma_clip(const cpl_image * self)
1368{
1369
1370 const double noise = visir_image_sigma_clip(self, NULL);
1371
1372 cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), noise);
1373
1374 return noise;
1375
1376}
1377
1378/*----------------------------------------------------------------------------*/
1396/*----------------------------------------------------------------------------*/
1397int visir_star_find(const cpl_vector * v_ra, const cpl_vector * v_dec,
1398 double ra, double dec, double maxdist, double * pdist)
1399{
1400 const int nra = cpl_vector_get_size(v_ra);
1401 const int ndec = cpl_vector_get_size(v_dec);
1402 double dmin = 0.0; /* Avoid (false) uninit warning */
1403 int minind = 0;
1404 int i;
1405
1406
1407 /* Catch NULL input */
1408 cpl_ensure(nra > 0, cpl_error_get_code(), -2);
1409 cpl_ensure(ndec > 0, cpl_error_get_code(), -3);
1410
1411 /* It would be natural to use a cpl_bivector for the positions,
1412 but since CPL cannot ensure that a bivector comprises two vectors
1413 of the same length this would be pointless :-( */
1414 cpl_ensure(nra == ndec, CPL_ERROR_INCOMPATIBLE_INPUT, -4);
1415
1416 cpl_ensure(maxdist >= 0, CPL_ERROR_ILLEGAL_INPUT, -5);
1417
1418 /* Find the index of the star closest to the given coordinate */
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);
1423
1424 cpl_msg_debug(cpl_func, "DISTANCE (RAi,DECi)=(%g,%g) <=> "
1425 "(RA,DEC)=(%g,%g): %g", rai, deci, ra, dec, gdist);
1426
1427 if (i == 0 || gdist < dmin) {
1428 minind = i;
1429 dmin = gdist;
1430 }
1431 }
1432
1433 if (pdist != NULL) *pdist = dmin;
1434
1435 /* Check that it is close enough */
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);
1442 }
1443
1444 return minind;
1445}
1446
1447/*----------------------------------------------------------------------------*/
1466/*----------------------------------------------------------------------------*/
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)
1472{
1473
1474 double sign;
1475 int i;
1476
1477 assert( line );
1478 assert( pra );
1479 assert( pdec );
1480 assert( jys );
1481 assert( njys > 0 );
1482
1483
1484 if (isign == '+')
1485 sign = 1.0;
1486 else if (isign == '-')
1487 sign = -1.0;
1488 else {
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);
1492 }
1493
1494 if (ra_hh < 0) {
1495 cpl_msg_error(cpl_func, "Line has negative RA hh (%d): %s",
1496 ra_hh, line);
1497 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1498 }
1499 if (ra_mm < 0) {
1500 cpl_msg_error(cpl_func, "Line has negative RA mm (%d): %s",
1501 ra_hh, line);
1502 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1503 }
1504 if (ra_mm >= 60) {
1505 cpl_msg_error(cpl_func, "Line has too large RA mm (%d): %s ",
1506 ra_mm, line);
1507 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1508 }
1509 if (ra_ss < 0) {
1510 cpl_msg_error(cpl_func, "Line has negative RA ss (%g): %s",
1511 ra_ss, line);
1512 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1513 }
1514 if (ra_ss >= 60) {
1515 cpl_msg_error(cpl_func, "Line has too large RA ss (%g): %s ",
1516 ra_ss, line);
1517 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1518 }
1519
1520 if (dec_hh < 0) {
1521 cpl_msg_error(cpl_func, "Line has negative DEC hh (%d): %s",
1522 dec_hh, line);
1523 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1524 }
1525 if (dec_mm < 0) {
1526 cpl_msg_error(cpl_func, "Line has negative DEC mm (%d): %s",
1527 dec_hh, line);
1528 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1529 }
1530 if (dec_mm >= 60) {
1531 cpl_msg_error(cpl_func, "Line has too large DEC mm (%d): %s ",
1532 dec_mm, line);
1533 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1534 }
1535 if (dec_ss < 0) {
1536 cpl_msg_error(cpl_func, "Line has negative DEC ss (%g): %s",
1537 dec_ss, line);
1538 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1539 }
1540 if (dec_ss >= 60) {
1541 cpl_msg_error(cpl_func, "Line has too large DEC ss (%g): %s ",
1542 dec_ss, line);
1543 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1544 }
1545
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 ",
1549 *pra, line);
1550 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1551 }
1552
1553 *pdec = sign * dec_hms2deg(dec_hh, dec_mm, dec_ss);
1554 if (*pdec > 90.0) {
1555 cpl_msg_error(cpl_func, "Line has too large RA (%g): %s ",
1556 *pdec, line);
1557 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1558 }
1559 if (*pdec < -90.0) {
1560 cpl_msg_error(cpl_func, "Line has too small RA (%g): %s ",
1561 *pdec, line);
1562 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1563 }
1564
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 ",
1567 jys[i], i+1, line);
1568 cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
1569 }
1570
1571 return CPL_ERROR_NONE;
1572
1573}
1574
1575/*----------------------------------------------------------------------------*/
1588/*----------------------------------------------------------------------------*/
1589cpl_table * visir_table_new_xypos(const cpl_imagelist * images,
1590 const char * label)
1591{
1592 cpl_errorstate cleanstate = cpl_errorstate_get();
1593 const int nsize = cpl_imagelist_get_size(images);
1594 double psigmas[] = {5, 2, 1, 0.5}; /* Actually not modified */
1595 cpl_vector * sigmas = NULL;
1596 cpl_table * self = NULL;
1597 const int nsigmas = sizeof(psigmas)/sizeof(double);
1598 int isflux = 0;
1599 int nfail, i;
1600
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);
1605
1606 self = cpl_table_new(nsize);
1607
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));
1610
1611 if (!strcmp(label,"FLUX")) {
1612 isflux = 1;
1613 skip_if (cpl_table_new_column(self, label, CPL_TYPE_DOUBLE));
1614 } else {
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));
1617 }
1618
1619 sigmas = cpl_vector_wrap(4, psigmas);
1620 skip_if (sigmas == NULL);
1621
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]);
1625
1626 /* Object detection */
1627 nfail = 0;
1628 for (i=0 ; i < nsize ; i++) {
1629 const cpl_image * image = cpl_imagelist_get_const(images, i);
1630 cpl_apertures * apert;
1631 cpl_size isigma;
1632
1633
1634 double posx = -1;
1635 double posy = -1;
1636 double fwhmx = -1;
1637 double fwhmy = -1;
1638 double flux = -1;
1639 int iflux;
1640
1641 skip_if (0);
1642
1643 /* Find any apertures in each image */
1644 apert = cpl_apertures_extract(image, sigmas, &isigma);
1645
1646 if (apert != NULL && cpl_error_get_code()) {
1647 /* FIX for DFS 2616 */
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:",
1652 (void*)apert);
1653 if (cpl_msg_get_level() <= CPL_MSG_DEBUG)
1654 cpl_apertures_dump(apert, stdout);
1655 cpl_apertures_delete(apert);
1656 apert = NULL;
1657 }
1658
1659 if (apert != NULL &&
1660 !irplib_apertures_find_max_flux(apert, &iflux, 1) &&
1661 cpl_apertures_get_flux(apert, iflux) > 0) {
1662
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);
1666 if (!isflux)
1667 cpl_image_get_fwhm(image, (int)posx, (int)posy, &fwhmx, &fwhmy);
1668
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);
1672 }
1673
1674 if (apert == NULL || cpl_error_get_code()) {
1675 visir_error_reset("Aperture detection in image %d of %d failed",
1676 i+1, nsize);
1677 nfail++;
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,
1683 flux);
1684 nfail++;
1685 }
1686
1687 cpl_apertures_delete(apert);
1688 apert = NULL;
1689
1690 skip_if (cpl_table_set_double(self, "X_POS", i, posx));
1691 skip_if (cpl_table_set_double(self, "Y_POS", i, posy));
1692
1693 if (isflux)
1694 skip_if (cpl_table_set_double(self, "FLUX", i, flux));
1695 else {
1696 skip_if (cpl_table_set_double(self, "X_FWHM", i, fwhmx));
1697 skip_if (cpl_table_set_double(self, "Y_FWHM", i, fwhmy));
1698 }
1699
1700 }
1701
1702 /* Check if some detections were successful */
1703 if (nfail == nsize) {
1704 cpl_msg_error(cpl_func, "Aperture detection failed in all %d images",
1705 nsize);
1706 visir_error_set(CPL_ERROR_DATA_NOT_FOUND);
1707 skip_if(1);
1708 }
1709
1710 end_skip;
1711
1712 cpl_vector_unwrap(sigmas);
1713
1714 if (self && cpl_error_get_code()) {
1715 cpl_table_delete(self);
1716 self = NULL;
1717 }
1718
1719 return self;
1720}
1721
1722/*----------------------------------------------------------------------------*/
1729/*----------------------------------------------------------------------------*/
1730int visir_vector_minpos(const cpl_vector * v)
1731{
1732 const double * x = cpl_vector_get_data_const(v);
1733 const int n = cpl_vector_get_size(v);
1734 int minpos = 0;
1735 int i;
1736
1737 cpl_ensure(x, CPL_ERROR_NULL_INPUT, -1);
1738
1739 for (i = 1; i < n; i++) if (x[i] < x[minpos]) minpos = i;
1740
1741 return minpos;
1742}
1743
1744/*----------------------------------------------------------------------------*/
1759/*----------------------------------------------------------------------------*/
1760cpl_error_code visir_bivector_load(cpl_bivector * self, FILE * stream)
1761{
1762 cpl_vector * v1;
1763 cpl_vector * v2;
1764 int np = 0;
1765 int xsize, ysize;
1766 char line[1024];
1767
1768 cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
1769 cpl_ensure_code(stream, CPL_ERROR_NULL_INPUT);
1770
1771 /* Create and fill the vectors */
1772 v1 = cpl_bivector_get_x(self);
1773 v2 = cpl_bivector_get_y(self);
1774
1775 xsize = cpl_vector_get_size(v1);
1776 ysize = cpl_vector_get_size(v2);
1777
1778 while (fgets(line, 1024, stream) != NULL) {
1779 double x, y;
1780 if (line[0] != '#' && sscanf(line, "%lg %lg", &x, &y) == 2) {
1781 /* Found new element-pair
1782 - increase vector sizes if necessary,
1783 - insert element at end and
1784 - increment size counter */
1785 if (np == xsize) {
1786 xsize *= 2;
1787 cpl_vector_set_size(v1, xsize);
1788 }
1789 if (np == ysize) {
1790 ysize *= 2;
1791 cpl_vector_set_size(v2, ysize);
1792 }
1793 cpl_vector_set(v1, np, x);
1794 cpl_vector_set(v2, np, y);
1795 np++;
1796 }
1797 }
1798
1799 /* Check that the loop ended due to eof and not an error */
1800 cpl_ensure_code(!ferror(stream), CPL_ERROR_FILE_IO);
1801
1802 /* Check that the file was not empty and set the size to its true value */
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);
1805 }
1806
1807 return CPL_ERROR_NONE;
1808
1809}
1810
1811/*----------------------------------------------------------------------------*/
1824/*----------------------------------------------------------------------------*/
1825double visir_star_dist_min(const double * pras, const double * pdecs, int nloc,
1826 int * piloc1, int * piloc2)
1827{
1828
1829 int i, j;
1830 double dmin = 180;
1831
1832
1833 assert( pras != NULL);
1834 assert( pdecs != NULL);
1835 assert( piloc1 != NULL);
1836 assert( piloc2 != NULL);
1837 assert( nloc > 0 );
1838
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],
1842 pras[j], pdecs[j]);
1843 if (dist < dmin) {
1844 dmin = dist;
1845 *piloc1 = i;
1846 *piloc2 = j;
1847 }
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);
1851 }
1852 }
1853
1854 return dmin;
1855}
1856
1857
1858/*----------------------------------------------------------------------------*/
1872/*----------------------------------------------------------------------------*/
1873const char ** visir_framelist_set_tag(irplib_framelist * self,
1874 char * (*pftag)(const cpl_frame *,
1875 const cpl_propertylist *,
1876 int),
1877 int *pntags)
1878{
1879
1880 /* FIXME: Copied from NACO - move to irplib */
1881
1882 const char ** taglist = NULL; /* Must be initialized due to realloc call */
1883 int iframe, size;
1884
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);
1889
1890 size = irplib_framelist_get_size(self);
1891
1892 cpl_ensure(size > 0, CPL_ERROR_DATA_NOT_FOUND, NULL);
1893
1894 *pntags = 0;
1895
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);
1900 char * tag;
1901 const char * newtag;
1902 int i;
1903
1904
1905 /* This should really be an assert() */
1906 cpl_ensure(frame != NULL, CPL_ERROR_ILLEGAL_INPUT, NULL);
1907 cpl_ensure(plist != NULL, CPL_ERROR_ILLEGAL_INPUT, NULL);
1908
1909 tag = (*pftag)(frame, plist, iframe);
1910
1911 cpl_ensure(tag != NULL, cpl_error_get_code(), NULL);
1912
1913 /* From this point on failures should not really happen */
1914
1915 (void)cpl_frame_set_tag(frame, tag);
1916 cpl_free(tag);
1917
1918 newtag = cpl_frame_get_tag(frame);
1919
1920 cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), NULL);
1921
1922 /* Compare the new tags with those of previous frames */
1923 for (i=0; i < *pntags; i++)
1924 if (strcmp(newtag, taglist[i]) == 0) break;
1925
1926 if (i == *pntags) {
1927 /* The new tag is different from the previous ones
1928 - add it to the list */
1929 (*pntags)++;
1930 taglist = (const char **)cpl_realloc(taglist, *pntags *
1931 sizeof(const char *));
1932 taglist[i] = newtag;
1933 }
1934
1935 }
1936
1937 return taglist;
1938
1939}
1940
1941
1942/*----------------------------------------------------------------------------*/
1948/*----------------------------------------------------------------------------*/
1949int visir_get_ncombine(const irplib_framelist * rawframes)
1950{
1951 int ncombine = 0;
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(
1955 rawframes, i);
1956 if (cpl_propertylist_has(pl, "ESO PRO DATANCOM"))
1957 ncombine += cpl_propertylist_get_int(pl, "ESO PRO DATANCOM");
1958 }
1959 return cpl_error_get_code() ? 0 : (ncombine ? ncombine : 1);
1960}
1961
1962
1963/*----------------------------------------------------------------------------*/
1973/*----------------------------------------------------------------------------*/
1974cpl_error_code visir_qc_append_background(cpl_propertylist * self,
1975 const irplib_framelist * rawframes,
1976 int icol1, int icol2)
1977{
1978
1979 /* Compute the background values of the HCYCLE frames */
1980 const double bg_mean = visir_hcycle_background(rawframes, icol1, icol2);
1981
1982 skip_if (0);
1983
1984 bug_if (cpl_propertylist_append_double(self, "ESO QC BACKGD MEAN",
1985 bg_mean));
1986
1987 end_skip;
1988
1989 return cpl_error_get_code();
1990
1991}
1992
1993
1994/*----------------------------------------------------------------------------*/
2003/*----------------------------------------------------------------------------*/
2004cpl_error_code visir_qc_append_capa(cpl_propertylist * self,
2005 const irplib_framelist * rawframes)
2006{
2007
2008 cpl_errorstate cleanstate = cpl_errorstate_get();
2009 const cpl_propertylist * plist
2010 = irplib_framelist_get_propertylist_const(rawframes, 0);
2011 const char * capa;
2012
2013
2014 bug_if (0);
2015
2016 capa = visir_get_capa(plist);
2017
2018 if (cpl_error_get_code()) {
2019 /* ignore error as keys are not defined for aqu data */
2020 //visir_error_reset("Could not determine capa");
2021 cpl_msg_info(cpl_func, "Could not determine capa");
2022 cpl_errorstate_set(cleanstate);
2023 } else {
2024 bug_if (cpl_propertylist_append_string(self, "ESO QC CAPA", capa));
2025 }
2026
2027 end_skip;
2028
2029 return cpl_error_get_code();
2030
2031}
2032
2033/*----------------------------------------------------------------------------*/
2041/*----------------------------------------------------------------------------*/
2042cpl_error_code visir_qc_append_filter(cpl_propertylist * self,
2043 const irplib_framelist * rawframes)
2044{
2045
2046 const cpl_propertylist * plist
2047 = irplib_framelist_get_propertylist_const(rawframes, 0);
2048 const char * value = visir_pfits_get_filter(plist);
2049
2050
2051 skip_if (0);
2052
2053 bug_if (cpl_propertylist_append_string(self, "ESO QC FILTER", value));
2054
2055 end_skip;
2056
2057 return cpl_error_get_code();
2058
2059}
2060
2061/*----------------------------------------------------------------------------*/
2069/*----------------------------------------------------------------------------*/
2070cpl_error_code visir_qc_append_exptime(cpl_propertylist * self,
2071 const irplib_framelist * rawframes)
2072{
2073 const cpl_propertylist * plist
2074 = irplib_framelist_get_propertylist_const(rawframes, 0);
2075
2076 /* NNOD */
2077 const int nnod = irplib_framelist_get_size(rawframes);
2078 /* Get the total exposure time */
2079 const double value = visir_utils_get_exptime(nnod, plist);
2080
2081 skip_if (0);
2082
2083 bug_if (cpl_propertylist_append_double(self, "ESO QC EXPTIME", value));
2084
2085 end_skip;
2086
2087 return cpl_error_get_code();
2088
2089}
2090
2093/*----------------------------------------------------------------------------*/
2104/*----------------------------------------------------------------------------*/
2105static double visir_great_circle_dist(double ra1, double dec1,
2106 double ra2, double dec2)
2107{
2108
2109 /* Convert all input from degrees to radian - and back for the result */
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 );
2112
2113 dec1 *= CPL_MATH_RAD_DEG;
2114 dec2 *= CPL_MATH_RAD_DEG;
2115
2116 return 2.0 * asin(sqrt( ddec*ddec + cos(dec1)*cos(dec2)*dra*dra))
2117 * CPL_MATH_DEG_RAD;
2118
2119}
2120
2121/*----------------------------------------------------------------------------*/
2134/*----------------------------------------------------------------------------*/
2135static double ra_hms2deg(int hh, int mm, double ss)
2136{
2137 return 15.0 * dec_hms2deg(hh, mm, ss);
2138}
2139
2140/*----------------------------------------------------------------------------*/
2152/*----------------------------------------------------------------------------*/
2153static double dec_hms2deg(int dd, int mm, double ss)
2154{
2155 return ((double)ss/60.0 + (double)mm)/60.0 + dd;
2156}
2157
2158/*----------------------------------------------------------------------------*/
2171/*----------------------------------------------------------------------------*/
2172static double visir_hcycle_background(const irplib_framelist * rawframes,
2173 int icol1, int icol2)
2174{
2175 cpl_imagelist * iset = NULL;
2176 /* Get the number of files */
2177 const int nfiles = irplib_framelist_get_size(rawframes);
2178 double bgsum = 0;
2179 double bgmean = -1;
2180 int nsum = 0;
2181 int i, j;
2182
2183 skip_if (nfiles < 1);
2184
2185 if (icol1 == 0) icol1 = VISIR_BACKGD_START;
2186 if (icol2 == 0) icol2 = VISIR_BACKGD_STOP;
2187
2188 cpl_msg_info(cpl_func, "Computing Half-cycle background level from column %d "
2189 "through %d", icol1, icol2);
2190
2191 /* Loop on the hcycles images */
2192 for (i=0; i < nfiles; i++) {
2193
2194 iset = visir_load_hcycle(rawframes, i);
2195
2196 skip_if (0);
2197
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);
2203
2204 skip_if (0);
2205
2206 if (median != median) {
2207 const cpl_frame * frame = irplib_framelist_get_const(rawframes,
2208 i);
2209 /* Some Comm. I data contains NaNs */
2210 cpl_msg_error(cpl_func, "Image window (%d, %d, %d, %d) "
2211 "(image %d of %d) in %s (frame %d of %d) "
2212 "has NaN median",
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);
2218 skip_if(1);
2219 }
2220 bgsum += median;
2221 }
2222 nsum += j;
2223 cpl_imagelist_delete(iset);
2224 iset = NULL;
2225 }
2226
2227 /* Test if there are some HCYCLE frames */
2228 skip_if (nsum < 1);
2229
2230 bgmean = bgsum / nsum;
2231
2232 end_skip;
2233
2234 cpl_imagelist_delete(iset);
2235
2236 /* The background was requested to not include the offset correction */
2237 return bgmean - VISIR_HCYCLE_OFFSET;
2238}
2239
2240
2241/*----------------------------------------------------------------------------*/
2252/*----------------------------------------------------------------------------*/
2253cpl_error_code
2254visir_get_subpixel_maxpos(const cpl_image * img, cpl_size x, cpl_size y,
2255 double * xsub, double * ysub)
2256{
2257 int bad;
2258 const cpl_size nx = cpl_image_get_size_x(img);
2259 const cpl_size ny = cpl_image_get_size_y(img);
2260
2261 *xsub = 0;
2262 *ysub = 0;
2263 if (x - 1 > 0 && x + 1 <= nx) {
2264 double sub[] = {
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),
2268 };
2269 if (!bad)
2270 *xsub = 0.5 * (sub[0] - sub[2])/(sub[0] - 2*sub[1] + sub[2]);
2271 }
2272 if (y - 1 > 0 && y + 1 <= ny) {
2273 double sub[] = {
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),
2277 };
2278 if (!bad)
2279 *ysub = 0.5 * (sub[0] - sub[2])/(sub[0] - 2*sub[1] + sub[2]);
2280 }
2281
2282 return cpl_error_get_code();
2283}
2284
2285static inline unsigned long get_msb(unsigned long a)
2286{
2287 /* dumb integer msb, (63 - __builtin_clzl(a)) would be faster */
2288 unsigned long msb = 0;
2289 while (a >>= 1) {
2290 msb++;
2291 }
2292 return msb;
2293}
2294
2295/* ---------------------------------------------------------------------------*/
2304/* ---------------------------------------------------------------------------*/
2305size_t visir_get_next_regular(size_t a)
2306{
2307 /* fftw can also deal efficiently with factors of 7 and 13 but it needs
2308 * testing that the speed of these algorithms will not cancel out the gain
2309 * of smaller input sizes */
2310 if (a <= 6)
2311 return a;
2312 /* is already power of 2 */
2313 if ((a & (a - 1)) == 0)
2314 return a;
2315 /* overflow */
2316 if (5 > SIZE_MAX / a)
2317 return a;
2318
2319 size_t match = SIZE_MAX;
2320 size_t p5 = 1;
2321 while(p5 < a) {
2322 size_t p35 = p5;
2323 while (p35 < a) {
2324 /* ceil division */
2325 size_t quotient = a % p35 != 0 ? a / p35 + 1 : a / p35;
2326 /* next power of two of quotient */
2327 size_t p2 = 2 << get_msb(quotient - 1);
2328
2329 size_t n = p2 * p35;
2330 if (n == a)
2331 return n;
2332 else if (n < match)
2333 match = n;
2334
2335 p35 *= 3;
2336 if (p35 == a)
2337 return p35;
2338 }
2339 if (p35 < match)
2340 match = p35;
2341 p5 *= 5;
2342 if (p5 == a)
2343 return p5;
2344 }
2345 if (p5 < match)
2346 match = p5;
2347 return match;
2348}
2349
2350struct _visir_fftx_cache {
2351 int initialized;
2352 cpl_image * template_fft;
2353 double template_stdev;
2354};
2355
2356visir_fftx_cache * visir_new_fftx_cache(void)
2357{
2358 return cpl_calloc(sizeof(visir_fftx_cache), 1);
2359}
2360
2361void visir_delete_fftx_cache(visir_fftx_cache * c)
2362{
2363 irplib_aligned_free(cpl_image_unwrap(c->template_fft));
2364 cpl_free(c);
2365}
2366
2367/*----------------------------------------------------------------------------*/
2383/*----------------------------------------------------------------------------*/
2384cpl_error_code
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)
2388{
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);
2393 /* pad to small prime factors for better performance */
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;
2404 void * buffer;
2405 double template_stdev;
2406 /* measure is nondeterministic in the last ulp */
2407 cpl_fft_mode mode = getenv("VISIR_TEST_MODE") ? 0 : CPL_FFT_FIND_MEASURE;
2408
2409 cpl_ensure_code(atemplate != NULL, CPL_ERROR_NULL_INPUT);
2410 cpl_ensure_code(aimg != NULL, CPL_ERROR_NULL_INPUT);
2411
2412 if (cache == NULL || cache->initialized == 0) {
2413 /* prepare template */
2414 cpl_image * template = NULL;
2415 if (cpl_image_get_type(atemplate) != CPL_TYPE_FLOAT)
2416 template = cpl_image_cast(atemplate, CPL_TYPE_FLOAT);
2417 else
2418 template = cpl_image_duplicate(atemplate);
2419
2420 cpl_image_fill_rejected(template, 0);
2421 if (normalize)
2422 skip_if(cpl_image_subtract_scalar(template,
2423 visir_image_get_mean_fast(template)));
2424 template_stdev = cpl_image_get_stdev(template);
2425
2426 buffer = irplib_aligned_calloc(32, Nxe * Nye, sizeof(float));
2427 ztemp = cpl_image_wrap(Nxe, Nye, CPL_TYPE_FLOAT, buffer);
2428
2429 /* flip we have a fft correlation instead of a convolution
2430 * due to FT(f(x))* = FT(f(-x)) for real values*/
2431 skip_if(cpl_image_flip(template, 1));
2432 skip_if(cpl_image_flip(template, 3));
2433
2434 /* zero pad */
2435 skip_if(cpl_image_copy(ztemp, template, 1, 1));
2436 cpl_image_delete(template);
2437
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,
2441 buffer);
2442 skip_if(cpl_fft_image(fft2, ztemp, CPL_FFT_FORWARD));
2443 if (cache) {
2444 cache->template_fft = fft2;
2445 cache->template_stdev = template_stdev;
2446 cache->initialized = 1;
2447 }
2448 }
2449 else {
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");
2456 }
2457
2458 /* prepare image */
2459
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);
2464 else
2465 img = cpl_image_duplicate(aimg);
2466
2467 skip_if(img == NULL);
2468
2469 cpl_image_fill_rejected(img, 0);
2470
2471 if (normalize)
2472 skip_if(cpl_image_subtract_scalar(img,
2473 visir_image_get_mean_fast(img)));
2474
2475 /* zero pad */
2476 skip_if(cpl_image_copy(zimg, img, 1, 1));
2477
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);
2481
2482 skip_if(cpl_fft_image(fft1, zimg, CPL_FFT_FORWARD | mode));
2483
2484
2485 /* correlate, no conjugation necessary due to flipping */
2486 skip_if(visir_image_multiply_fast(fft1, fft2));
2487
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 |
2491 mode));
2492
2493 skip_if(cpl_image_get_maxpos_window(res, Nxt / 2 , Nyt / 2,
2494 Nxt / 2 + Nxi, Nyt / 2 + Nyi,
2495 &txshift, &tyshift));
2496
2497 if (max_correlation != NULL) {
2498 int rej;
2499 *max_correlation = cpl_image_get(res, txshift, tyshift, &rej);
2500 // remove fftw scaling
2501 *max_correlation /= Nxe * Nye;
2502
2503 if (normalize) {
2504 double tstd = template_stdev;
2505 int mx = txshift - Nxt;
2506 int my = tyshift - Nyt;
2507 double istd= cpl_image_get_stdev_window(zimg,
2508 CX_MAX(1, mx + 1),
2509 CX_MAX(1, my + 1),
2510 CX_MIN(Nxe, mx + Nxt),
2511 CX_MIN(Nye, my + Nyt));
2512
2513 if (tstd * istd == 0)
2514 *max_correlation = 0;
2515 else
2516 *max_correlation /= (tstd * istd * Nxt * Nyt);
2517
2518 skip_if(0);
2519 }
2520 }
2521 skip_if(visir_get_subpixel_maxpos(res, txshift, tyshift, &subx, &suby));
2522 if (xshift != NULL) {
2523 *xshift = txshift - Nxt + subx;
2524 }
2525 if (yshift != NULL) {
2526 *yshift = tyshift - Nyt + suby;
2527 }
2528
2529 end_skip;
2530
2531 cpl_image_delete(img);
2532 if (cache == NULL)
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));
2538
2539 return cpl_error_get_code();
2540}
2541
2542
2543/*----------------------------------------------------------------------------*/
2559/*----------------------------------------------------------------------------*/
2560static cx_list *
2561get_interpolation_points(size_t x, size_t y,
2562 size_t nx_, size_t ny_, cpl_binary *bpm)
2563{
2564 ssize_t l = -1, r = -1 , u = -1, d = -1;
2565 ssize_t xl = x;
2566 ssize_t xh = x;
2567 ssize_t yl = y;
2568 ssize_t yh = y;
2569 ssize_t nx = (ssize_t)nx_;
2570 ssize_t ny = (ssize_t)ny_;
2571 cx_list * p = cx_list_new();
2572
2573 /* FIXME: only uses x and y axes, add diagonal?
2574 * maybe a circle around bp? */
2575 while (1) {
2576 xl--;
2577 xh++;
2578 yl--;
2579 yh++;
2580
2581 if (l < 0 && xl >= 0 && bpm[IND(xl, y, nx)] == CPL_BINARY_0)
2582 l = xl;
2583 if (r < 0 && xh < nx && bpm[IND(xh, y, nx)] == CPL_BINARY_0)
2584 r = xh;
2585 if (d < 0 && yl >= 0 && bpm[IND(x, yl, nx)] == CPL_BINARY_0)
2586 d = yl;
2587 if (u < 0 && yh < ny && bpm[IND(x, yh, nx)] == CPL_BINARY_0)
2588 u = yh;
2589
2590 /* stop on first pair or end of image */
2591 /* FIXME: searches too much for bp on corner */
2592 if ((l != -1 && r != -1) || (d != -1 && u != -1) ||
2593 (xl < 0 && xh >= nx && yl < 0 && yh >= ny))
2594 break;
2595 }
2596
2597 /* save the valid points */
2598 if (r >= 0)
2599 cx_list_push_back(p, (cxcptr)(IND(r, y, nx)));
2600 if (l >= 0)
2601 cx_list_push_back(p, (cxcptr)(IND(l, y, nx)));
2602 if (u >= 0)
2603 cx_list_push_back(p, (cxcptr)(IND(x, u, nx)));
2604 if (d >= 0)
2605 cx_list_push_back(p, (cxcptr)(IND(x, d, nx)));
2606 return p;
2607}
2608
2609
2610/*----------------------------------------------------------------------------*/
2628/*----------------------------------------------------------------------------*/
2629cpl_error_code
2630visir_interpolate_rejected(cpl_image * img, size_t ** ppoints, size_t * n)
2631{
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);
2637
2638 /* FIXME: support more image types */
2639 skip_if(data == NULL);
2640
2641 if (ppoints == NULL || *ppoints == NULL) {
2642 size_t i = 0;
2643 cpl_binary * found = memchr(bpm, CPL_BINARY_1,
2644 sizeof(cpl_binary) * nx * ny);
2645 /* max 4 points per bp + number of points + bp index */
2646 size_t * restrict pbpm = cpl_calloc(cpl_image_count_rejected(img) * 6,
2647 sizeof(size_t));
2648
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);
2656 double sum = 0;
2657
2658 pbpm[i++] = ind;
2659 pbpm[i++] = npix;
2660 assert(pbpm[i - 1] <= 4);
2661
2662 while (it != cx_list_end(p)) {
2663 const size_t lind = (size_t)cx_list_get(p, it);
2664 pbpm[i++] = lind;
2665 sum += data[lind];
2666 it = cx_list_next(p, it);
2667 }
2668 data[ind] = sum / npix;
2669 cx_list_delete(p);
2670
2671 found = memchr(found + 1, CPL_BINARY_1,
2672 sizeof(cpl_binary) * nx * ny - ind - 1);
2673 }
2674 if (ppoints && n) {
2675 *n = i;
2676 *ppoints = pbpm;
2677 }
2678 else
2679 cpl_free(pbpm);
2680 }
2681 else {
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++];
2687 double sum = 0;
2688 for (size_t j = 0; j < m; j++) {
2689 const size_t lind = points[i++];
2690 sum += data[lind];
2691 }
2692 data[ind] = sum / m;
2693 }
2694 }
2695
2696 cpl_image_accept_all(img);
2697
2698 end_skip;
2699
2700 return cpl_error_get_code();
2701}
2702
2703#ifdef _OPENMP
2704static const cpl_image *
2705image_const_row_view_create(const cpl_image * img,
2706 cpl_size ly,
2707 cpl_size uy)
2708{
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);
2716
2717 const cpl_mask * omask = cpl_image_get_bpm_const(img);
2718 if (omask) {
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));
2722 }
2723
2724 return wimg;
2725}
2726
2727static void
2728image_const_row_view_delete(const cpl_image * img)
2729{
2730 cpl_mask_unwrap(cpl_image_unset_bpm((cpl_image*)(img)));
2731 cpl_image_unwrap((cpl_image *)img);
2732}
2733#endif
2734
2735/* ---------------------------------------------------------------------------*/
2742/* ---------------------------------------------------------------------------*/
2743cpl_image *
2744visir_parallel_median_collapse(const cpl_imagelist * l)
2745{
2746#ifndef _OPENMP
2747 return cpl_imagelist_collapse_median_create(l);
2748#else
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);
2752
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));
2759 /* make sure image has bpm to avoid creation races later */
2760 cpl_image_get_bpm(res);
2761
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)
2767 yhigh = ny;
2768 /* create list with images pointing to row views of the original */
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),
2773 ylow, yhigh);
2774IRPLIB_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual);
2775 cpl_imagelist_set(view, (cpl_image *)iview, i);
2776IRPLIB_DIAG_PRAGMA_POP;
2777 }
2778
2779 /* collapse views and copy to full result image */
2780 cpl_image * r = cpl_imagelist_collapse_median_create(view);
2781 cpl_image_copy(res, r, 1, ylow);
2782
2783 /* cleanup */
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));
2787 }
2788 cpl_imagelist_unwrap(view);
2789 }
2790
2791 return res;
2792#endif
2793}
2794
2795
2796/*----------------------------------------------------------------------------*/
2802/*----------------------------------------------------------------------------*/
2803static const char * visir_get_capa(const cpl_propertylist * plist)
2804{
2805 const char * capa = "Pb with Capa";
2806 const char * sval;
2807 double mean;
2808
2809
2810 skip_if (0);
2811
2812
2813 /* Get the instrument mode */
2814 sval = visir_pfits_get_insmode(plist);
2815 skip_if (0);
2816
2817 /* Identify the mode */
2818 if (!strcmp(sval, "IMG")) {
2819 /* Imaging mode */
2820 mean = visir_pfits_get_volt1dcta9(plist);
2821 mean += visir_pfits_get_volt1dctb9(plist);
2822 } else if (!strcmp(sval, "SPC") || !strcmp(sval, "SPCIMG")) {
2823 /* Spectro mode */
2824 mean = visir_pfits_get_volt2dcta9(plist);
2825 mean += visir_pfits_get_volt2dctb9(plist);
2826 } else
2827 skip_if (1);
2828
2829 skip_if (0);
2830
2831 mean *= 0.5;
2832
2833 /* Compute Capa value */
2834 if (mean < 1.0) {
2835 capa = "Large Capa";
2836 } else if (mean > 4.5) {
2837 capa = "Small Capa";
2838 }
2839
2840 end_skip;
2841
2842 return capa;
2843}
2844
2845#ifdef VISIR_MASK_HAS
2846/*----------------------------------------------------------------------------*/
2866/*----------------------------------------------------------------------------*/
2867static cpl_boolean visir_mask_has(const cpl_mask * self, cpl_binary value,
2868 int ngood)
2869{
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);
2873 int i;
2874
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);
2880
2881 for (i = 0; i < ngood; i++) {
2882 /* Assume NULL is returned if size == 0 */
2883 const cpl_binary * ppos = memchr(pself, value, (size_t)size);
2884 if (ppos == NULL) break;
2885
2886 size -= 1 + (int)(ppos - pself);
2887 pself = 1 + ppos;
2888 }
2889
2890 return i == ngood ? CPL_TRUE : CPL_FALSE;
2891}
2892#endif
2893
2894
2895/* ---------------------------------------------------------------------------*/
2901/* ---------------------------------------------------------------------------*/
2902size_t visir_upper_bound(const cpl_vector * vec, double val)
2903{
2904 const double * d = cpl_vector_get_data_const(vec);
2905 long count = cpl_vector_get_size(vec);
2906 long first = 0;
2907 while (count > 0)
2908 {
2909 long step = count / 2;
2910 long it = first + step;
2911 if (!(val < d[it])) {
2912 first = it + 1;
2913 count -= step + 1;
2914 }
2915 else
2916 count = step;
2917 }
2918 return first;
2919}
2920
2921
2922/* ---------------------------------------------------------------------------*/
2928/* ---------------------------------------------------------------------------*/
2929size_t visir_lower_bound(const cpl_vector * vec, double val)
2930{
2931 const double * d = cpl_vector_get_data_const(vec);
2932 long count = cpl_vector_get_size(vec);
2933 long first = 0;
2934 while (count > 0)
2935 {
2936 long step = count / 2;
2937 long it = first + step;
2938 if (d[it] < val) {
2939 first = it + 1;
2940 count -= step + 1;
2941 }
2942 else
2943 count = step;
2944 }
2945 return first;
2946}
2947
2948
2949/* ---------------------------------------------------------------------------*/
2961/* ---------------------------------------------------------------------------*/
2962cpl_image * visir_linintp_values(const cpl_image * inp, const cpl_bivector * ref)
2963{
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);
2973
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);
2978 //double intval, rx1, rx2, ry1, ry2;
2979 //if (ilo == 0) {
2980 // /* extrapolate low */
2981 // ilo += 1;
2982 //}
2983 //else if (ilo == nref) {
2984 // /* extrapolate high */
2985 // ilo -= 1;
2986 //}
2987 //rx1 = cpl_vector_get(rx, ilo - 1);
2988 //rx2 = cpl_vector_get(rx, ilo);
2989 //ry1 = cpl_vector_get(ry, ilo - 1);
2990 //ry2 = cpl_vector_get(ry, ilo);
2991 //double grad = (ry2 - ry1) / (rx2 - rx1);
2992 //double y0 = ry1 - grad * rx1;
2993 //rdata[y * nx + x] = grad * val + y0;
2994
2995 if (ilo == 0) {
2996 rdata[y * nx + x] = cpl_vector_get(ry, 0);
2997 cpl_image_reject(res, x + 1, y + 1);
2998 }
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);
3002 }
3003 else {
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;
3011 }
3012 }
3013 }
3014 return res;
3015}
3016
3017/* ---------------------------------------------------------------------------*/
3036/* ---------------------------------------------------------------------------*/
3037cpl_error_code
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)
3044{
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;
3054
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,
3057 urx, ury));
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);
3063
3064 cpl_image * err = cpl_image_new(cpl_image_get_size_x(img),
3065 cpl_image_get_size_y(img),
3066 CPL_TYPE_DOUBLE);
3067 cpl_image_add_scalar(err, 1.);
3068 cpl_image_divide(err, weights);
3069 cpl_image_power(err, 0.5);
3070
3071 skip_if(cpl_fit_image_gaussian(img, err,
3072 x,
3073 y,
3074 urx - llx + 1,
3075 ury - lly + 1,
3076 dpar,
3077 epar,
3078 NULL, /* fit params */
3079 NULL,
3080 NULL,
3081 &cov,
3082 major,
3083 minor,
3084 angle,
3085 &phys_cov
3086 ));
3087
3088 /* ignores covariance, values become nan for near circular gauss, forumula
3089 * illdefined for e.g. rho < 0 or theta = 45
3090 * nan cannot be in fits header, so set to -1 */
3091 if (peak) {
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]));
3095 if (isnan(*peak)) {
3096 cpl_msg_warning(cpl_func, "2d gaussfit, could not determine peak");
3097 *peak = -1.;
3098 }
3099 }
3100 if (peak_err) {
3101 double * a = cpl_array_get_data_double(dpar);
3102 double * e = cpl_array_get_data_double(epar);
3103 double A = a[1];
3104 double sigx = a[5];
3105 double sigy = a[6];
3106 double rho = a[2];
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]);
3112 double A2 = A * A;
3113 double rho2 = rho * rho;
3114 double xd = CPL_MATH_PI * CPL_MATH_PI * 4 * sigx * sigx * sigy * sigy;
3115 *peak_err =
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)) {
3121 *peak_err = -1.;
3122 }
3123 }
3124 if (major) {
3125 *major *= CPL_MATH_FWHM_SIG;
3126 if (isnan(*major)) {
3127 cpl_msg_warning(cpl_func,
3128 "2d gaussfit, could not determine major axis");
3129 *minor = -1.;
3130 }
3131 }
3132 if (minor) {
3133 *minor *= CPL_MATH_FWHM_SIG;
3134 if (isnan(*minor)) {
3135 cpl_msg_warning(cpl_func,
3136 "2d gaussfit, could not determine minor axis");
3137 *minor = -1.;
3138 }
3139 }
3140 if (major_err) {
3141 *major_err = sqrt(cpl_matrix_get(phys_cov, 1, 1)) * CPL_MATH_FWHM_SIG;
3142 if (isnan(*major_err)) {
3143 *major_err = -1.;
3144 }
3145 }
3146 if (minor_err) {
3147 *minor_err = sqrt(cpl_matrix_get(phys_cov, 2, 2)) * CPL_MATH_FWHM_SIG;
3148 if (isnan(*minor_err)) {
3149 *minor_err = -1.;
3150 }
3151 }
3152 if (angle_err) {
3153 *angle_err = sqrt(cpl_matrix_get(phys_cov, 0, 0));
3154 if (isnan(*angle_err)) {
3155 *angle_err = -1.;
3156 }
3157 }
3158
3159cleanup:
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);
3166
3167 return cpl_error_get_code();
3168}
3169
3170
3171/* ---------------------------------------------------------------------------*/
3185/* ---------------------------------------------------------------------------*/
3186cpl_error_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)
3191{
3192 double sigma, area, offset;
3193 cpl_matrix * cov = NULL;
3194 skip_if(cpl_vector_fit_gaussian(xv, /*sigma_x*/NULL,
3195 yv, dyv,
3196 CPL_FIT_CENTROID | CPL_FIT_STDEV |
3197 CPL_FIT_AREA | CPL_FIT_OFFSET,
3198 x0, &sigma, &area, &offset,
3199 NULL, NULL,
3200 &cov));
3201 if (x0 && isnan(*x0)) {
3202 cpl_msg_warning(cpl_func, "1d gaussfit, could not determine mean");
3203 *x0 = -1.;
3204 }
3205 if (x0_err) {
3206 *x0_err = sqrt(cpl_matrix_get(cov, 0, 0));
3207 if (isnan(*x0_err)) {
3208 *x0_err = -1.;
3209 }
3210 }
3211 if (sigma) {
3212 *sigma_ = sigma;
3213 if (isnan(*sigma_)) {
3214 cpl_msg_warning(cpl_func,
3215 "1d gaussfit, could not determine sigma");
3216 *sigma_ = -1.;
3217 }
3218 }
3219 if (peak) {
3220 *peak = area / sqrt(2 * CPL_MATH_PI * sigma * sigma) + offset;
3221 if (isnan(*peak)) {
3222 cpl_msg_warning(cpl_func, "1d gaussfit, could not determine peak");
3223 *peak = -1.;
3224 }
3225 }
3226 if (peak_err) {
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)) {
3235 *peak_err = -1.;
3236 }
3237 }
3238 if (sigma_err) {
3239 *sigma_err = sqrt(cpl_matrix_get(cov, 1, 1));
3240 if (isnan(*sigma_err)) {
3241 *sigma_err = -1.;
3242 }
3243 }
3244
3245cleanup:
3246 cpl_matrix_delete(cov);
3247
3248 return cpl_error_get_code();
3249}
cpl_imagelist * visir_load_hcycle(const irplib_framelist *rawframes, int pos)
Load the HCYCLE images from a VISIR file.
double visir_pfits_get_monoc_pos(const cpl_propertylist *self)
The INS.MONOC1.POS.
Definition: visir_pfits.c:523
int visir_pfits_get_navrg(const cpl_propertylist *self)
The NAVRG.
Definition: visir_pfits.c:339
double visir_pfits_get_dit(const cpl_propertylist *self)
The DIT.
Definition: visir_pfits.c:325
double visir_pfits_get_volt1dctb9(const cpl_propertylist *self)
The VOLT1.DCTB9.
Definition: visir_pfits.c:859
int visir_pfits_get_chop_ncycles(const cpl_propertylist *self)
The number of chopping cycles.
Definition: visir_pfits.c:237
double visir_pfits_get_volt2dctb9(const cpl_propertylist *self)
The VOLT2.DCTB9.
Definition: visir_pfits.c:883
const char * visir_pfits_get_insmode(const cpl_propertylist *self)
The mode.
Definition: visir_pfits.c:474
const char * visir_pfits_get_filter(const cpl_propertylist *self)
The filter.
Definition: visir_pfits.c:365
double visir_pfits_get_volt2dcta9(const cpl_propertylist *self)
The VOLT2.DCTA9.
Definition: visir_pfits.c:871
int visir_pfits_get_ndit(const cpl_propertylist *self)
The NDIT keyword.
Definition: visir_pfits.c:535
double visir_pfits_get_volt1dcta9(const cpl_propertylist *self)
The VOLT1.DCTA9.
Definition: visir_pfits.c:847