NACO Pipeline Reference Manual  4.4.0
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  -----------------------------------------------------------------------------*/
50 typedef struct {
51  double x;
52  int index;
53 } vector_index;
54 
55 
56 /*-----------------------------------------------------------------------------
57  Private functions
58  -----------------------------------------------------------------------------*/
59 
60 static int naco_vector_get_maxpos_window(const cpl_vector *, int, int);
61 
62 #if 0
63 static int vector_index_compare(const void *, const void *);
64 #endif
65 
66 static 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 /*----------------------------------------------------------------------------*/
96 cpl_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 /*----------------------------------------------------------------------------*/
256 cpl_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 /*----------------------------------------------------------------------------*/
300 cpl_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 /*----------------------------------------------------------------------------*/
340 cpl_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 /*----------------------------------------------------------------------------*/
407 char * 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 /*----------------------------------------------------------------------------*/
482 cpl_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;
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;
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 /*----------------------------------------------------------------------------*/
626 static
627 cpl_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
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 /*----------------------------------------------------------------------------*/
728 static 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 /*----------------------------------------------------------------------------*/
746 static 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
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_add_split(cpl_imagelist *self)
Readd all the pairs, preserving the number of images.
Definition: naco_spc.c:256
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
const cpl_propertylist * irplib_framelist_get_propertylist_const(const irplib_framelist *self, int pos)
Get the propertylist of the specified frame in the framelist.
cpl_error_code naco_imagelist_append_invert(cpl_imagelist *self)
Fo each image append also its inverted.
Definition: naco_spc.c:300
const cpl_frame * irplib_framelist_get_const(const irplib_framelist *self, int pos)
Get the specified frame from the framelist.
cpl_error_code irplib_framelist_contains(const irplib_framelist *self, const char *key, cpl_type type, cpl_boolean is_equal, double fp_tol)
Verify that a property is present for all frames.
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
int irplib_framelist_get_size(const irplib_framelist *self)
Get the size of a framelist.