IIINSTRUMENT Pipeline Reference Manual 4.4.13
naco_spc.c
1/* $Id: naco_spc.c,v 1.42 2009-05-12 12:43:43 llundin Exp $
2 *
3 * This file is part of the NACO Pipeline
4 * Copyright (C) 2002,2003 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/*
22 * $Author: llundin $
23 * $Date: 2009-05-12 12:43:43 $
24 * $Revision: 1.42 $
25 * $Name: not supported by cvs2svn $
26 */
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31
32/*-----------------------------------------------------------------------------
33 Includes
34 -----------------------------------------------------------------------------*/
35
36#include "naco_spc.h"
37#include "naco_pfits.h"
38
39#include <string.h>
40#include <math.h>
41
42#ifdef HAVE_GSL
43#include <gsl/gsl_multimin.h>
44#endif
45
46
47/*-----------------------------------------------------------------------------
48 Private types
49 -----------------------------------------------------------------------------*/
50typedef struct {
51 double x;
52 int index;
53} vector_index;
54
55
56/*-----------------------------------------------------------------------------
57 Private functions
58 -----------------------------------------------------------------------------*/
59
60static int naco_vector_get_maxpos_window(const cpl_vector *, int, int);
61
62#if 0
63static int vector_index_compare(const void *, const void *);
64#endif
65
66static cpl_error_code naco_framelist_get_state(const irplib_framelist *,
67 int, cpl_boolean,
68 cpl_boolean *,
69 const cpl_propertylist *);
70
71/*----------------------------------------------------------------------------*/
75/*----------------------------------------------------------------------------*/
76
79/*----------------------------------------------------------------------------*/
95/*----------------------------------------------------------------------------*/
96cpl_error_code naco_vector_correlate_imagelist_1d(cpl_vector * offset,
97 const cpl_vector * goffset,
98 cpl_boolean do_wave,
99 const cpl_imagelist * self)
100{
101
102 cpl_image * d2d = NULL;
103 cpl_image * dspat1d = NULL;
104 cpl_vector * vspat1dp = NULL;
105 cpl_vector * vspat1di = NULL;
106 cpl_vector * vxc = NULL;
107 const int nsize = cpl_imagelist_get_size(self);
108 const int maxerr = 20;
109 int gleni, glenprev = 0; /* Avoid (false) uninit warning */
110
111 /* Wavelenth/Spatial resolution */
112 const int nz = (do_wave ? cpl_image_get_size_y : cpl_image_get_size_x)
113 (cpl_imagelist_get_const(self, 0));
114 const char dirch = do_wave ? 'Y' : 'X';
115 const int direc = do_wave ? 1 : 0;
116 int ii, i, iprev = 0; /* Avoid (false) uninit warning */
117 double xcmin = 1.0;
118
119
120 bug_if(self == NULL);
121
122 bug_if(offset == NULL);
123 bug_if(goffset == NULL);
124 bug_if(cpl_vector_get_size(offset) != nsize);
125 bug_if(cpl_vector_get_size(goffset) != nsize);
126
127 /* Process frames in order of offset */
128 for (ii = 0; ii < nsize; ii++) {
129 i = ii;
130
131 cpl_msg_info(cpl_func, "%c-offset(%d:%d): %g", dirch, ii, i,
132 cpl_vector_get(goffset, i));
133
134 }
135
136 vxc = cpl_vector_new(maxerr);
137
138 /* Process frames in order of offset */
139 for (ii = 0; ii < nsize; ii++) {
140
141 int maxoff, halfoff;
142 int ixc, ixc0;
143 int irealfirst, ireallast;
144 int ioff;
145 double xci;
146 double doff, dnewoff;
147
148 i = ii;
149
150 gleni = (int)round(cpl_vector_get(goffset, i));
151
152 /* Need double for the cpl_vector */
153 d2d = cpl_image_cast(cpl_imagelist_get_const(self, i), CPL_TYPE_DOUBLE);
154
155 /* Sum over the spatial dimension */
156 dspat1d = cpl_image_collapse_create(d2d, direc);
157 /* A skip before vspat1di has wrapped will leak the pixel buffer */
158 cpl_image_delete(d2d);
159 d2d = NULL;
160
161 cpl_vector_delete(vspat1di);
162 vspat1di = cpl_vector_wrap(nz, cpl_image_get_data_double(dspat1d));
163 (void)cpl_image_unwrap(dspat1d);
164 dspat1d = NULL;
165 bug_if(0);
166
167#if 0
168 cpl_plot_vector("set grid;", "t '1D-Profile i' w linespoints", "",
169 vspat1di);
170#endif
171 if (ii == 0) {
172 vspat1dp = vspat1di;
173 vspat1di = NULL;
174 glenprev = gleni;
175 iprev = i;
176 continue;
177 }
178
179 halfoff = maxerr + abs(gleni - glenprev);
180 if (halfoff > nz-1) halfoff = nz - 1;
181 maxoff = 2 * halfoff + 1;
182
183 bug_if(cpl_vector_set_size(vxc, maxoff));
184
185 ixc0 = cpl_vector_correlate(vxc, vspat1di, vspat1dp);
186 bug_if(0);
187
188 /* Limit the search range to 1+2*maxerr to reduce risk of false max */
189 irealfirst = halfoff - (glenprev - gleni) - maxerr;
190 ireallast = halfoff - (glenprev - gleni) + maxerr;
191
192 ixc = naco_vector_get_maxpos_window(vxc, irealfirst, ireallast);
193 bug_if(0);
194
195 if (ixc != ixc0) {
196 cpl_msg_warning(cpl_func, "%c-False maximum(%d:%d): %d <+. %d. "
197 "0 <= %d => %d < %d", dirch, ii, i, ixc0, ixc,
198 irealfirst, ireallast, maxoff);
199 }
200
201 ioff = ixc - halfoff;
202 doff = cpl_vector_get(goffset, i) - cpl_vector_get(goffset, iprev);
203
204 xci = cpl_vector_get(vxc, ixc);
205
206 if (xci < xcmin) xcmin = xci;
207
208 if (ioff != (int)round(doff)) {
209 cpl_msg_warning(cpl_func, "%c-XC(%d)=%g changes offset: %g - %g = "
210 "%g => %d = %d - %d", dirch, i, xci,
211 cpl_vector_get(goffset, i),
212 cpl_vector_get(goffset, iprev), doff, ioff,
213 gleni, glenprev);
214 dnewoff = (double)-ioff;
215 } else {
216 cpl_msg_info(cpl_func, "%c-XC(%d)=%g confirms offset: %g - %g = %g "
217 "<=> %d = %d - %d", dirch, i, xci,
218 cpl_vector_get(goffset, i),
219 cpl_vector_get(goffset, iprev), doff, ioff,
220 gleni, glenprev);
221 dnewoff = -doff;
222 }
223 bug_if(0);
224 bug_if(cpl_vector_set(offset, i, dnewoff));
225
226#if 0
227 cpl_plot_vector("set grid;", "t 'Cross-correlation' w linespoints",
228 "", vxc);
229
230#endif
231 }
232
233 cpl_msg_info(cpl_func, "Minimum 1D-spatial XC for %d sets: %g",
234 nsize, xcmin);
235
236 end_skip;
237
238 cpl_image_delete(d2d);
239 (void)cpl_image_unwrap(dspat1d);
240 cpl_vector_delete(vspat1dp);
241 cpl_vector_delete(vspat1di);
242 cpl_vector_delete(vxc);
243
244 return cpl_error_get_code();
245}
246
247/*----------------------------------------------------------------------------*/
255/*----------------------------------------------------------------------------*/
256cpl_error_code naco_imagelist_add_split(cpl_imagelist * self)
257{
258
259 cpl_image * copy = NULL;
260 int n = cpl_imagelist_get_size(self);
261 int i;
262
263 bug_if(self == NULL);
264
265 bug_if(n&1);
266
267
268 for (i=0; i < n; i += 2) {
269 cpl_image * first = cpl_imagelist_get(self, i);
270 cpl_image * second = cpl_imagelist_get(self, i+1);
271
272 bug_if(cpl_image_subtract(first, second));
273
274 copy = cpl_image_multiply_scalar_create(first, -1.0);
275
276 bug_if(cpl_imagelist_set(self, copy, i+1));
277 copy = NULL;
278
279 }
280
281 end_skip;
282
283 cpl_image_delete(copy);
284
285 return cpl_error_get_code();
286
287}
288
289
290
291/*----------------------------------------------------------------------------*/
299/*----------------------------------------------------------------------------*/
300cpl_error_code naco_imagelist_append_invert(cpl_imagelist * self)
301{
302
303 cpl_image * BA = NULL;
304 const int n = cpl_imagelist_get_size(self);
305 int i;
306
307
308 bug_if(self == NULL);
309
310 for (i=0; i < n; i++) {
311 const cpl_image * AB = cpl_imagelist_get(self, i);
312
313 BA = cpl_image_multiply_scalar_create(AB, -1.0);
314
315 bug_if(cpl_imagelist_set(self, BA, n+i));
316 BA = NULL;
317
318 }
319
320 end_skip;
321
322 cpl_image_delete(BA);
323
324 return cpl_error_get_code();
325
326}
327
328
329/*----------------------------------------------------------------------------*/
339/*----------------------------------------------------------------------------*/
340cpl_error_code naco_imagelist_split(cpl_imagelist * self)
341{
342
343 cpl_imagelist * copy = cpl_imagelist_new();
344 cpl_image * image = NULL;
345 cpl_image * im_neg = NULL;
346 int j = cpl_imagelist_get_size(self);
347 int i = 0;
348
349
350 skip_if(self == NULL);
351
352 /* Move all images to the copy - and revert their order */
353 j--;
354 for (; j >= 0; j--, i++) {
355 bug_if(cpl_imagelist_set(copy, cpl_imagelist_unset(self, j), i));
356 }
357
358 j++;
359 i--;
360
361 bug_if(j != 0);
362
363 /* Move all images back to self, revert their order again while splitting */
364 for (; i >= 0; i--, j += 2) {
365 image = cpl_imagelist_unset(copy, i);
366
367 /* The negative flux */
368 im_neg = cpl_image_duplicate(image);
369 bug_if(cpl_image_threshold(im_neg, -FLT_MAX, 0.0, 0.0, 0.0));
370 bug_if(cpl_image_multiply_scalar(im_neg, -1.0));
371
372
373 /* The positive flux */
374 bug_if(cpl_image_threshold(image, 0.0, FLT_MAX, 0.0, 0.0));
375
376 bug_if(cpl_imagelist_set(self, image, j));
377 image = NULL;
378
379 bug_if(cpl_imagelist_set(self, im_neg, j+1));
380 im_neg = NULL;
381
382 }
383
384 end_skip;
385
386 cpl_image_delete(image);
387 cpl_image_delete(im_neg);
388 cpl_imagelist_delete(copy);
389
390 return CPL_ERROR_NONE;
391
392}
393
394/*----------------------------------------------------------------------------*/
406/*----------------------------------------------------------------------------*/
407char * naco_spc_make_tag(const cpl_frame* self, const cpl_propertylist * plist,
408 int dummy)
409{
410
411 char * tag = NULL;
412 double wlen, dit;
413 const char * specmode;
414 const char * slitname;
415
416
417 bug_if (0);
418
419 bug_if(self == NULL);
420 bug_if(plist == NULL);
421 bug_if(dummy < 0); /* Avoid warning of unused variable */
422
423 specmode = irplib_pfits_get_string(plist, NACO_PFITS_STRING_SPECMODE);
424 skip_if(cpl_error_get_code());
425
426 slitname = irplib_pfits_get_string(plist, NACO_PFITS_STRING_SLITNAME);
427 skip_if(cpl_error_get_code());
428
429 dit = irplib_pfits_get_double(plist, NACO_PFITS_DOUBLE_DIT);
430 skip_if(cpl_error_get_code());
431
432 wlen = irplib_pfits_get_double(plist, NACO_PFITS_DOUBLE_CWLEN);
433 skip_if(cpl_error_get_code());
434
435 tag = cpl_sprintf("%s:%s:%.5f:%.5f", specmode, slitname, wlen, dit);
436 bug_if(tag == NULL);
437
438 end_skip;
439
440 if (cpl_error_get_code()) {
441 cpl_free(tag);
442 tag = NULL;
443 }
444
445 return tag;
446
447}
448
449
450/*----------------------------------------------------------------------------*/
481/*----------------------------------------------------------------------------*/
482cpl_error_code naco_imagelist_load_diff(cpl_imagelist * self,
483 const irplib_framelist * onofflist,
484 const cpl_propertylist * onoffkeys)
485{
486 cpl_image * img_off = NULL;
487 cpl_image * diff = NULL;
488 int nfiles, ndiff;
489 int ion, ioff;
490
491 skip_if (0);
492 skip_if (self == NULL);
493 skip_if (onofflist == NULL);
494
495 skip_if(cpl_imagelist_get_size(self) != 0);
496
497 skip_if (irplib_framelist_contains(onofflist, "NAXIS1", CPL_TYPE_INT,
498 CPL_TRUE, 0.0));
499 skip_if (irplib_framelist_contains(onofflist, "NAXIS2", CPL_TYPE_INT,
500 CPL_TRUE, 0.0));
501
502 skip_if (irplib_framelist_contains(onofflist, NACO_PFITS_DOUBLE_DIT,
503 CPL_TYPE_DOUBLE, CPL_TRUE, 1e-5));
504
505 nfiles = irplib_framelist_get_size(onofflist);
506
507 for (ioff = 0, ion = 0, ndiff = 0; ioff < nfiles && ion < nfiles;
508 ioff++, ion++) {
509 /* Each completed iteration produces one on-off image */
510 cpl_boolean need_on = CPL_TRUE;
511
512 const cpl_frame * frame;
513 const char * name;
514
515
516 /* Find next off-frame - and perhaps also the next on-frame */
517 for (; ioff < nfiles; ioff++) {
518 cpl_boolean is_off = CPL_FALSE; /* Init to avoid gcc-warning */
519
520 skip_if(naco_framelist_get_state(onofflist, ioff, CPL_FALSE,
521 &is_off, onoffkeys));
522
523 if (is_off) {
524 break;
525 } else if (need_on && ioff >= ion) {
526 ion = ioff;
527 need_on = CPL_FALSE;
528 }
529 }
530
531 bug_if(0);
532
533 if (ioff == nfiles) break;
534
535 if (need_on) {
536 /* Find next on-frame */
537 if (ion == ioff) ion++; /* No need to check an off-frame */
538 for (; ion < nfiles; ion++) {
539
540 cpl_boolean is_on = CPL_FALSE; /* Init to avoid gcc-warning */
541
542 skip_if(naco_framelist_get_state(onofflist, ion, CPL_TRUE,
543 &is_on, onoffkeys));
544
545 if (is_on) break;
546
547 }
548
549 bug_if(0);
550
551 if (ion == nfiles) break;
552 }
553
554 frame = irplib_framelist_get_const(onofflist, ion);
555 name = cpl_frame_get_filename(frame);
556
557 bug_if(0);
558
559 diff = cpl_image_load(name, CPL_TYPE_FLOAT, 0, 0);
560 error_if(diff == NULL, cpl_error_get_code(),
561 "Could not load on-image from %s", name);
562
563 frame = irplib_framelist_get_const(onofflist, ioff);
564 name = cpl_frame_get_filename(frame);
565
566 bug_if(0);
567
568 img_off = cpl_image_load(name, CPL_TYPE_FLOAT, 0, 0);
569 error_if(img_off == NULL, cpl_error_get_code(),
570 "Could not load off-image from %s", name);
571
572 error_if(cpl_image_subtract(diff, img_off), cpl_error_get_code(),
573 "Could not subtract frame %d from %d", ioff, ion);
574
575 cpl_image_delete(img_off);
576 img_off = NULL;
577
578 bug_if(cpl_imagelist_set(self, diff, ndiff));
579 diff = NULL;
580
581 ndiff++;
582 }
583
584 bug_if(cpl_imagelist_get_size(self) != ndiff);
585
586 error_if(ndiff == 0 && ion == nfiles, CPL_ERROR_DATA_NOT_FOUND,
587 "The %d frame(s) contain(s) no on-frames", nfiles);
588 error_if(ndiff == 0 && ioff == nfiles, CPL_ERROR_DATA_NOT_FOUND,
589 "The %d frame(s) contain(s) no off-frames", nfiles);
590
591 if (2 * ndiff < nfiles) {
592 cpl_msg_warning(cpl_func, "The %d frames contains only %d pairs of "
593 "on/off-frames, ignoring the rest", nfiles, ndiff);
594 }
595
596 bug_if(cpl_imagelist_get_size(self) < 1);
597
598 end_skip;
599
600 cpl_image_delete(img_off);
601 cpl_image_delete(diff);
602
603 return cpl_error_get_code();
604}
605
606
611/*----------------------------------------------------------------------------*/
625/*----------------------------------------------------------------------------*/
626static
627cpl_error_code naco_framelist_get_state(const irplib_framelist * self,
628 int iframe,
629 cpl_boolean is_on,
630 cpl_boolean * pis_ok,
631 const cpl_propertylist * onoffkeys)
632{
633
634 cpl_boolean state = CPL_FALSE;
635 const cpl_propertylist * plist
636 = irplib_framelist_get_propertylist_const(self, iframe);
637 const int nonoffkeys = cpl_propertylist_get_size(onoffkeys);
638 int i;
639 cpl_boolean onoffkeys_has_one_on = CPL_FALSE;
640
641 bug_if (0);
642 bug_if (self == NULL);
643 bug_if (iframe < 0);
644 bug_if (iframe >= irplib_framelist_get_size(self));
645 bug_if (pis_ok == NULL);
646 bug_if (onoffkeys == NULL);
647 bug_if (plist == NULL);
648
649 for (i=0; i < nonoffkeys; i++) {
650 const cpl_property * prop = cpl_propertylist_get_const(onoffkeys, i);
651 const char * name = cpl_property_get_name(prop);
652 const int ireq = cpl_property_get_int(prop);
653 const cpl_type statetype = cpl_propertylist_get_type(plist, name);
654 cpl_boolean state_is_on;
655
656 error_if(0, cpl_error_get_code(), "On/off property number %d, %s",
657 1+i, name ? name : "<NULL>");
658
659 switch (statetype) {
660 case CPL_TYPE_CHAR:
661 state_is_on = cpl_propertylist_get_char(plist, name) > 0
662 ? CPL_TRUE : CPL_FALSE;
663 break;
664 case CPL_TYPE_BOOL:
665 state_is_on = cpl_propertylist_get_bool(plist, name);
666 break;
667 case CPL_TYPE_INT:
668 state_is_on = cpl_propertylist_get_int(plist, name) > 0
669 ? CPL_TRUE : CPL_FALSE;
670 break;
671 case CPL_TYPE_LONG:
672 state_is_on = cpl_propertylist_get_long(plist, name) > 0
673 ? CPL_TRUE : CPL_FALSE;
674 break;
675 case CPL_TYPE_FLOAT:
676 state_is_on = cpl_propertylist_get_float(plist, name) > 0.0
677 ? CPL_TRUE : CPL_FALSE;
678 break;
679 case CPL_TYPE_DOUBLE:
680 state_is_on = cpl_propertylist_get_double(plist, name) > 0.0
681 ? CPL_TRUE : CPL_FALSE;
682 break;
683 default:
684 cpl_ensure_code(0, CPL_ERROR_UNSUPPORTED_MODE);
685 }
686
687 if (is_on) {
688 if (state_is_on) {
689 if (ireq == 0) break; /* This state is on, but shouldn't be */
690 onoffkeys_has_one_on = CPL_TRUE; /* A state is corrrectly on */
691 } else if (ireq > 0) {
692 break; /* This state is off, but shouldn't be */
693 }
694 } else if (state_is_on) {
695 break; /* This state is on, but all states should be off */
696 }
697 }
698
699 if (i == nonoffkeys) {
700 if (is_on) {
701 /* All states were on or off, as specified by onoffkeys */
702 state = onoffkeys_has_one_on; /* At least one state must be on */
703 } else {
704 /* All states were off, as they should be */
705 state = CPL_TRUE;
706 }
707 }
708
709 *pis_ok = state;
710
711 end_skip;
712
713 return cpl_error_get_code();
714}
715
716#if 0
717/*----------------------------------------------------------------------------*/
727/*----------------------------------------------------------------------------*/
728static int vector_index_compare(const void * a, const void * b)
729{
730 return
731 ( (const vector_index*)a)->x < ((const vector_index*)b)->x ? -1 :
732 (((const vector_index*)a)->x > ((const vector_index*)b)->x ? 1 : 0);
733}
734
735#endif
736/*----------------------------------------------------------------------------*/
745/*----------------------------------------------------------------------------*/
746static int naco_vector_get_maxpos_window(const cpl_vector * v, int i0, int i1)
747{
748 int i = i0;
749 int imax = i0;
750 double vmax = cpl_vector_get(v, imax);
751
752 cpl_ensure(v != NULL, CPL_ERROR_NULL_INPUT, -1);
753 cpl_ensure(0 <= i0, CPL_ERROR_ILLEGAL_INPUT, -2);
754 cpl_ensure(i0 <= i1, CPL_ERROR_ILLEGAL_INPUT, -3);
755 cpl_ensure(i1 < cpl_vector_get_size(v), CPL_ERROR_ILLEGAL_INPUT, -4);
756
757 for (i = i0; i <= i1; i++) if (cpl_vector_get(v, i) > vmax) {
758 imax = i;
759 vmax = cpl_vector_get(v, imax);
760 }
761
762 return imax;
763}
764
cpl_error_code naco_vector_correlate_imagelist_1d(cpl_vector *offset, const cpl_vector *goffset, cpl_boolean do_wave, const cpl_imagelist *self)
Use 1D cross-correlation to recompute the offsets in one direction.
Definition: naco_spc.c:96
cpl_error_code naco_imagelist_split(cpl_imagelist *self)
Split the images in an imagelist into positive and negative images.
Definition: naco_spc.c:340
char * naco_spc_make_tag(const cpl_frame *self, const cpl_propertylist *plist, int dummy)
Create a string suitable for frame comparison in spectroscopy.
Definition: naco_spc.c:407
cpl_error_code naco_imagelist_append_invert(cpl_imagelist *self)
Fo each image append also its inverted.
Definition: naco_spc.c:300
cpl_error_code naco_imagelist_load_diff(cpl_imagelist *self, const irplib_framelist *onofflist, const cpl_propertylist *onoffkeys)
Fill the list of difference images from on/off frames.
Definition: naco_spc.c:482
cpl_error_code naco_imagelist_add_split(cpl_imagelist *self)
Readd all the pairs, preserving the number of images.
Definition: naco_spc.c:256