NACO Pipeline Reference Manual  4.4.0
naco_img_jitter.c
1 /* $Id: naco_img_jitter.c,v 1.123 2011-12-22 11:09:36 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: 2011-12-22 11:09:36 $
24  * $Revision: 1.123 $
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_recipe.h"
37 #include "naco_strehl.h"
38 
39 #include "irplib_strehl.h"
40 #include "irplib_calib.h"
41 
42 /* Needed for memmove() */
43 #include <string.h>
44 
45 /*-----------------------------------------------------------------------------
46  Defines
47  -----------------------------------------------------------------------------*/
48 
49 #define RECIPE_STRING "naco_img_jitter"
50 
51 #define EXT0 0
52 
53 #define NACO_MIN(A,B) ((A) < (B) ? (A) : (B))
54 #define NACO_MAX(A,B) ((A) > (B) ? (A) : (B))
55 
56 /*-----------------------------------------------------------------------------
57  Private Functions prototypes
58  -----------------------------------------------------------------------------*/
59 
60 #ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
61 static cpl_error_code naco_img_jitter_reject_objects(cpl_image *, double,
62  double);
63 #endif
64 
65 static cpl_error_code naco_img_jitter_find_strehl(const cpl_imagelist *,
66  const cpl_parameterlist *,
67  const irplib_framelist *);
68 
69 static cpl_image * naco_img_jitter_saa_center(const cpl_imagelist *,
70  cpl_bivector *);
71 
72 static cpl_image * naco_img_jitter_saa_lucky(const cpl_imagelist *,
73  const cpl_vector *,
74  const cpl_bivector *, double);
75 
76 static cpl_image * naco_img_jitter_find_sky_cube(int, int, const cpl_array *,
77  const irplib_framelist *);
78 
79 static cpl_error_code naco_img_jitter_imagelist_wrap_nocube(cpl_imagelist *,
80  const cpl_array *,
81  cpl_imagelist *);
82 
83 
84 static cpl_image * naco_img_jitter_combine_cube(cpl_table *, const cpl_imagelist *,
85  const cpl_propertylist *,
86  const cpl_parameterlist *, int);
87 
88 static cpl_error_code naco_img_jitter_check_cube(const cpl_imagelist *,
89  const cpl_image *);
90 
91 static cpl_error_code naco_img_jitter_do_cube(cpl_imagelist *, cpl_table *,
92  cpl_propertylist *,
93  const cpl_array *,
94  const irplib_framelist *,
95  const cpl_parameterlist *);
96 
97 static
98 cpl_error_code naco_img_jitter_load_objimages(cpl_imagelist *, cpl_array *,
99  const irplib_framelist *,
100  const cpl_parameterlist *);
101 
102 static cpl_image ** naco_img_jitter_reduce(cpl_imagelist *, cpl_table *,
103  cpl_propertylist *,
104  const irplib_framelist *,
105  const irplib_framelist *,
106  const cpl_parameterlist *,
107  const char *,
108  const char *,
109  const char *,
110  cpl_boolean *);
111 
112 static cpl_image * naco_img_jitter_find_sky(cpl_propertylist *,
113  const cpl_imagelist *,
114  const cpl_imagelist *);
115 static cpl_image ** naco_img_jitter_saa(cpl_imagelist *,
116  const irplib_framelist *,
117  const cpl_parameterlist *);
118 static cpl_error_code naco_img_jitter_qc(cpl_propertylist *, cpl_propertylist *,
119  const irplib_framelist *,
120  const cpl_image *, cpl_boolean);
121 static cpl_error_code naco_img_jitter_qc_apertures(cpl_propertylist *,
122  const irplib_framelist *,
123  const cpl_image *);
124 static cpl_error_code naco_img_jitter_save(cpl_frameset *,
125  const cpl_parameterlist *,
126  const cpl_propertylist *,
127  const cpl_propertylist *,
128  const cpl_imagelist *,
129  const cpl_image *,
130  const cpl_image *,
131  const cpl_table *);
132 
133 NACO_RECIPE_DEFINE(naco_img_jitter,
134  NACO_PARAM_OFFSETS |
135  NACO_PARAM_OBJECTS |
136  NACO_PARAM_ODDEVEN |
137  NACO_PARAM_XCORR |
138  NACO_PARAM_UNION |
139  NACO_PARAM_COMBINE |
140  NACO_PARAM_SKYPLANE|
141  NACO_PARAM_CUBEMODE|
142  NACO_PARAM_LUCK_STR|
143  NACO_PARAM_SAVECUBE|
144  NACO_PARAM_REJ_HILO,
145  "Jitter recipe",
146  RECIPE_STRING " -- NACO imaging jitter recipe.\n"
147  "The files listed in the Set Of Frames (sof-file) "
148  "must be tagged:\n"
149  "NACO-raw-file.fits "NACO_IMG_JITTER_OBJ" or\n"
150  "NACO-raw-file.fits "NACO_IMG_JITTER_SKY" or\n"
151  "NACO-raw-file.fits "NACO_IMG_JITTER_OBJ_POL" or\n"
152  "NACO-raw-file.fits "NACO_IMG_JITTER_SKY_POL" or\n"
153  "NACO-flat-file.fits "NACO_CALIB_FLAT" or\n"
154  "NACO-bpm-file.fits "NACO_CALIB_BPM" or\n"
155  "NACO-dark-file.fits "NACO_CALIB_DARK"\n");
156 
157 /*----------------------------------------------------------------------------*/
161 /*----------------------------------------------------------------------------*/
162 
163 /*-----------------------------------------------------------------------------
164  Functions code
165  -----------------------------------------------------------------------------*/
166 
167 /*----------------------------------------------------------------------------*/
174 /*----------------------------------------------------------------------------*/
175 static int naco_img_jitter(cpl_frameset * framelist,
176  const cpl_parameterlist * parlist)
177 {
178  cpl_errorstate cleanstate = cpl_errorstate_get();
179  irplib_framelist * allframes = NULL;
180  irplib_framelist * objframes = NULL;
181  irplib_framelist * skyframes = NULL;
182  cpl_propertylist * qclist = cpl_propertylist_new();
183  cpl_propertylist * paflist = cpl_propertylist_new();
184  cpl_imagelist * objimages = cpl_imagelist_new();
185  cpl_image ** combined = NULL;
186  cpl_table * cubetable = cpl_table_new(1);
187  const char * badpix;
188  const char * dark;
189  const char * flat;
190  cpl_boolean drop_wcs = CPL_FALSE;
191 
192 
193  /* Identify the RAW and CALIB frames in the input frameset */
194  skip_if (naco_dfs_set_groups(framelist));
195 
196  allframes = irplib_framelist_cast(framelist);
197  skip_if(allframes == NULL);
198 
199  objframes = irplib_framelist_extract_regexp(allframes,
200  "^(" NACO_IMG_JITTER_OBJ "|"
201  NACO_IMG_JITTER_OBJ_POL ")$",
202  CPL_FALSE);
203  skip_if(objframes == NULL);
204 
205  skyframes = irplib_framelist_extract_regexp(allframes,
206  "^(" NACO_IMG_JITTER_SKY "|"
207  NACO_IMG_JITTER_SKY_POL ")$",
208  CPL_FALSE);
209  irplib_framelist_empty(allframes);
210  if (skyframes == NULL) {
211  naco_error_reset("The set of frames has no sky frames:");
212  }
213 
214  flat = irplib_frameset_find_file(framelist, NACO_CALIB_FLAT);
215  bug_if(0);
216 
217  badpix = irplib_frameset_find_file(framelist, NACO_CALIB_BPM);
218  bug_if(0);
219 
220  dark = irplib_frameset_find_file(framelist, NACO_CALIB_DARK);
221  bug_if(0);
222 
223  skip_if(irplib_framelist_load_propertylist(objframes, 0, 0, "^("
224  NACO_PFITS_REGEXP_JITTER_FIRST
225  ")$", CPL_FALSE));
226 
227  skip_if(irplib_framelist_load_propertylist_all(objframes, 0, "^("
228  NACO_PFITS_REGEXP_JITTER_ALL
229  ")$", CPL_FALSE));
230 
231  /* Apply the reduction */
232  cpl_msg_info(cpl_func, "Apply the data recombination");
233  combined = naco_img_jitter_reduce(objimages, cubetable, qclist, objframes,
234  skyframes, parlist, dark, flat, badpix,
235  &drop_wcs);
236 
237  skip_if (combined == NULL);
238 
239  irplib_framelist_empty(skyframes);
240 
241  /* Compute QC parameters from the combined image */
242  cpl_msg_info(cpl_func, "Compute QC parameters from the combined image");
243  skip_if (naco_img_jitter_qc(qclist, paflist, objframes, combined[0], drop_wcs));
244 
245  irplib_framelist_empty(objframes);
246 
247  /* Save the products */
248  cpl_msg_info(cpl_func, "Save the products");
249 
250  /* PRO.CATG */
251  bug_if (cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,
252  cpl_table_get_ncol(cubetable) > 0 ?
253  NACO_IMG_JITTER_CUBE :
254  NACO_IMG_JITTER_COMB));
255 
256  skip_if (naco_img_jitter_save(framelist, parlist, qclist, paflist,
257  objimages,
258  combined[0], combined[1], cubetable));
259 
260  end_skip;
261 
262  if (combined != NULL) {
263  cpl_image_delete(combined[0]);
264  cpl_image_delete(combined[1]);
265  cpl_free(combined);
266  }
267  cpl_imagelist_delete(objimages);
268  irplib_framelist_delete(allframes);
269  irplib_framelist_delete(objframes);
270  irplib_framelist_delete(skyframes);
271  cpl_propertylist_delete(qclist);
272  cpl_propertylist_delete(paflist);
273  cpl_table_delete(cubetable);
274 
275  return cpl_error_get_code();
276 }
277 
278 /*----------------------------------------------------------------------------*/
293 /*----------------------------------------------------------------------------*/
294 static cpl_image ** naco_img_jitter_reduce(cpl_imagelist * objimages,
295  cpl_table * cubetable,
296  cpl_propertylist * qclist,
297  const irplib_framelist * obj,
298  const irplib_framelist * sky,
299  const cpl_parameterlist * parlist,
300  const char * dark,
301  const char * flat,
302  const char * bpm,
303  cpl_boolean * pdid_resize)
304 {
305  cpl_errorstate prestate = cpl_errorstate_get();
306  const int nobj = irplib_framelist_get_size(obj);
307  cpl_imagelist * nocubeimgs = NULL;
308  cpl_imagelist * skyimages = NULL;
309  cpl_image * skyimage = NULL;
310  cpl_image ** combined = NULL;
311  cpl_array * iscube = NULL;
312  cpl_boolean has_cube = CPL_FALSE;
313  const char * scubemode = naco_parameterlist_get_string
314  (parlist, RECIPE_STRING, NACO_PARAM_CUBEMODE);
315  int inocube = 0;
316 
317 
318  bug_if(pdid_resize == NULL);
319  bug_if(scubemode == NULL);
320 
321  skip_if (irplib_framelist_contains(obj, NACO_PFITS_DOUBLE_CUMOFFSETX,
322  CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
323 
324  skip_if (irplib_framelist_contains(obj, NACO_PFITS_DOUBLE_CUMOFFSETY,
325  CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
326 
327  /* Load the input data */
328  cpl_msg_info(cpl_func, "Loading the %d object and %d sky images",
330  sky == NULL ? 0 : irplib_framelist_get_size(sky));
331 
332  iscube = cpl_array_new(nobj, CPL_TYPE_INT);
333 
334  (void)naco_img_jitter_load_objimages(objimages, iscube, obj, parlist);
335 
336  any_if("Could not load the %d object images", nobj);
337 
338  cpl_msg_info(cpl_func, "Loaded %d object images", nobj);
339 
340  skip_if(cpl_imagelist_get_size(objimages) != nobj);
341 
342  skip_if (irplib_flat_dark_bpm_calib(objimages, flat, dark, bpm));
343 
344  cpl_msg_info(cpl_func, "Sky estimation and correction");
345 
346  if (scubemode[0] == 'a') {
347  /* Just add without shifting */
348  const int mcube = nobj - cpl_array_count_invalid(iscube);
349 
350  if (mcube > 0) {
351  cpl_msg_info(cpl_func, "Collapsing %d cube(s) with no shifting",
352  mcube);
353  cpl_array_delete(iscube);
354  iscube = cpl_array_new(nobj, CPL_TYPE_INT);
355  }
356  }
357 
358  if (cpl_array_has_valid(iscube)) {
359  has_cube = CPL_TRUE;
360 
361  skip_if(naco_img_jitter_do_cube(objimages, cubetable, qclist,
362  iscube, obj, parlist));
363 
364 #ifdef NACO_IMG_JITTER_DEVELOPMENT
365  skip_if(cpl_imagelist_save(objimages, "Collapsed.fits", CPL_BPP_IEEE_FLOAT,
366  NULL, CPL_IO_CREATE));
367 #endif
368  }
369 
370  if (cpl_array_has_invalid(iscube)) {
371 
372  nocubeimgs = has_cube ? cpl_imagelist_new() : objimages;
373  if (has_cube) {
374  skip_if(naco_img_jitter_imagelist_wrap_nocube(nocubeimgs, iscube,
375  objimages));
376  inocube = cpl_imagelist_get_size(nocubeimgs);
377  }
378 
379  /* Estimate the sky */
380  if (sky != NULL) {
381  skyimages = irplib_imagelist_load_framelist(sky, CPL_TYPE_FLOAT, 0, 0);
382  any_if("Could not load sky images");
383  skip_if (irplib_flat_dark_bpm_calib(skyimages, flat, dark, bpm));
384  }
385 
386  skyimage = naco_img_jitter_find_sky(qclist, nocubeimgs, skyimages);
387  any_if("Could not estimate sky");
388 
389  cpl_imagelist_delete(skyimages);
390  skyimages = NULL;
391 
392  /* Apply the sky correction */
393  skip_if (cpl_imagelist_subtract_image(nocubeimgs, skyimage));
394  }
395 
396  /* Find the Strehl ratio of all object frames */
397  if(naco_img_jitter_find_strehl(objimages, parlist, obj)) {
398  irplib_error_recover(prestate, "Could not compute Strehl-ratio "
399  "for %d frame(s)", nobj);
400  }
401 
402  /* Apply the shift and add */
403  cpl_msg_info(cpl_func, "Shift and add");
404  combined = naco_img_jitter_saa(objimages, obj, parlist);
405  skip_if (combined == NULL);
406 
407  *pdid_resize = (cpl_boolean)
408  (cpl_image_get_size_x(combined[0])
409  != cpl_image_get_size_x(cpl_imagelist_get_const(objimages, 0)) ||
410  cpl_image_get_size_y(combined[0])
411  != cpl_image_get_size_y(cpl_imagelist_get_const(objimages, 0)));
412 
413  end_skip;
414 
415  /* Unwrap the wrapped no-cube images */
416  for (;inocube > 0;) {
417  (void)cpl_imagelist_unset(nocubeimgs, --inocube);
418  }
419 
420  if (nocubeimgs != objimages) cpl_imagelist_delete(nocubeimgs);
421  cpl_imagelist_delete(skyimages);
422  cpl_image_delete(skyimage);
423  cpl_array_delete(iscube);
424 
425  return combined;
426 }
427 
428 /*----------------------------------------------------------------------------*/
436 /*----------------------------------------------------------------------------*/
437 static cpl_image * naco_img_jitter_find_sky(cpl_propertylist * qclist,
438  const cpl_imagelist * objs,
439  const cpl_imagelist * skys)
440 {
441  cpl_image * self = NULL;
442 
443  if (skys != NULL) {
444  /* Use sky images */
445  self = cpl_imagelist_collapse_median_create(skys);
446  any_if("Could not compute the median of %d sky images",
447  (int)cpl_imagelist_get_size(skys));
448  } else {
449  /* Use objects images */
450  /* FIXME: This will work badly for few (one!) images */
451  self = cpl_imagelist_collapse_median_create(objs);
452  any_if("Could not compute the median of %d object images",
453  (int)cpl_imagelist_get_size(objs));
454  }
455 
456  /* Get the background value */
457  bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD",
458  cpl_image_get_median(self)));
459  bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD STDEV",
460  cpl_image_get_stdev(self)));
461 
462  end_skip;
463 
464  return self;
465 }
466 
467 /*----------------------------------------------------------------------------*/
475 /*----------------------------------------------------------------------------*/
476 static cpl_image ** naco_img_jitter_saa(cpl_imagelist * imlist,
477  const irplib_framelist * objframes,
478  const cpl_parameterlist * parlist)
479 {
480  const char * sval;
481  cpl_bivector * offsets_est = NULL;
482  cpl_bivector * objs = NULL;
483  cpl_image ** combined = NULL;
484  cpl_vector * sigmas = NULL;
485  double psigmas[] = {5.0, 2.0, 1.0, 0.5};
486  const char * offsets;
487  const char * objects;
488 #ifdef NACO_USE_ODDEVEN
489  cpl_boolean oddeven_flag;
490 #endif
491  const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
492  const int nfiles = cpl_imagelist_get_size(imlist);
493  int sx, sy, mx, my;
494  int rej_low, rej_high;
495  const char * combine_string;
496  cpl_geom_combine combine_mode;
497 
498 
499  bug_if(0);
500  bug_if (irplib_framelist_get_size(objframes) != nfiles);
501 
502  /* Retrieve input parameters */
503 
504  /* Offsets */
505  offsets = naco_parameterlist_get_string(parlist, RECIPE_STRING,
506  NACO_PARAM_OFFSETS);
507  /* Objects */
508  objects = naco_parameterlist_get_string(parlist, RECIPE_STRING,
509  NACO_PARAM_OBJECTS);
510 #ifdef NACO_USE_ODDEVEN
511  /* Oddeven flag */
512  oddeven_flag = naco_parameterlist_get_bool(parlist, RECIPE_STRING,
513  NACO_PARAM_ODDEVEN);
514 #endif
515 
516  /* Cross correlation windows parameters */
517  sval = naco_parameterlist_get_string(parlist, RECIPE_STRING,
518  NACO_PARAM_XCORR);
519  bug_if (sval == NULL);
520 
521  skip_if (sscanf(sval, "%d %d %d %d", &sx, &sy, &mx, &my) != 4);
522 
523  combine_string = naco_parameterlist_get_string(parlist, RECIPE_STRING,
524  NACO_PARAM_COMBINE);
525 
526  bug_if (combine_string == NULL);
527 
528  if (combine_string[0] == 'u')
529  combine_mode = CPL_GEOM_UNION;
530  else if (combine_string[0] == 'f')
531  combine_mode = CPL_GEOM_FIRST;
532  else if (combine_string[0] == 'i')
533  combine_mode = CPL_GEOM_INTERSECT;
534  else
535  skip_if(1);
536 
537  /* Number of rejected values in stacking */
538  sval = naco_parameterlist_get_string(parlist, RECIPE_STRING,
539  NACO_PARAM_REJ_HILO);
540  bug_if (sval == NULL);
541 
542  skip_if (sscanf(sval, "%d %d", &rej_low, &rej_high) != 2);
543 
544 
545  /* Get the offsets estimation of each input file pair */
546  cpl_msg_info(cpl_func, "Get the offsets estimation");
547  offsets_est = NULL;
548  if (offsets &&
549  offsets[0] != (char)0) {
550  /* A file has been provided on the command line */
551  offsets_est = cpl_bivector_read(offsets);
552  if (offsets_est == NULL ||
553  cpl_bivector_get_size(offsets_est) != nfiles) {
554  cpl_msg_error(cpl_func, "Cannot get offsets from %s",
555  offsets);
556  skip_if(1);
557  }
558  } else {
559  double * offsets_est_x;
560  double * offsets_est_y;
561  double offx0 = DBL_MAX; /* Avoid (false) uninit warning */
562  double offy0 = DBL_MAX; /* Avoid (false) uninit warning */
563  int i;
564 
565  /* Get the offsets from the header */
566  offsets_est = cpl_bivector_new(nfiles);
567  offsets_est_x = cpl_bivector_get_x_data(offsets_est);
568  offsets_est_y = cpl_bivector_get_y_data(offsets_est);
569  for (i=0 ; i < nfiles ; i++) {
570  const cpl_propertylist * plist
572 
573  /* X and Y offsets */
574  if (i == 0) {
575  offx0 = naco_pfits_get_cumoffsetx(plist);
576  offy0 = naco_pfits_get_cumoffsety(plist);
577  }
578 
579  /* Subtract the first offset to all offsets */
580  offsets_est_x[i] = offx0 - naco_pfits_get_cumoffsetx(plist);
581  offsets_est_y[i] = offy0 - naco_pfits_get_cumoffsety(plist);
582 
583  bug_if(0);
584  }
585  }
586 
587  /* Read the provided objects file if provided */
588  if (objects &&
589  objects[0] != (char)0) {
590  cpl_msg_info(cpl_func, "Get the user provided correlation objects");
591  /* A file has been provided on the command line */
592  objs = cpl_bivector_read(objects);
593  if (objs==NULL) {
594  cpl_msg_error(cpl_func, "Cannot get objects from %s",
595  objects);
596  skip_if (1);
597  }
598  }
599 
600  /* Create the vector for the detection thresholds */
601  sigmas = cpl_vector_wrap(nsigmas, psigmas);
602 
603  /* Recombine the images */
604  cpl_msg_info(cpl_func, "Recombine the images set");
605  combined = cpl_geom_img_offset_combine(imlist, offsets_est, 1, objs,
606  sigmas, NULL, sx, sy, mx, my,
607  rej_low, rej_high, combine_mode);
608 
609  skip_if (combined == NULL);
610 
611  end_skip;
612 
613  cpl_bivector_delete(offsets_est);
614  cpl_bivector_delete(objs);
615  cpl_vector_unwrap(sigmas);
616 
617  return combined;
618 }
619 
620 /*----------------------------------------------------------------------------*/
630 /*----------------------------------------------------------------------------*/
631 static cpl_error_code naco_img_jitter_qc(cpl_propertylist * qclist,
632  cpl_propertylist * paflist,
633  const irplib_framelist * objframes,
634  const cpl_image * combined,
635  cpl_boolean drop_wcs)
636 {
637  cpl_errorstate cleanstate = cpl_errorstate_get();
638  const cpl_propertylist * reflist
640  const char * sval;
641 
642 
643  bug_if(combined == NULL);
644 
645  bug_if(cpl_propertylist_copy_property_regexp(paflist, reflist, "^("
646  NACO_PFITS_REGEXP_JITTER_PAF
647  ")$", 0));
648 
649  if (naco_img_jitter_qc_apertures(qclist, objframes, combined)) {
650  naco_error_reset("Could not compute all QC parameters");
651  }
652 
653  sval = naco_pfits_get_filter(reflist);
654  if (cpl_error_get_code()) {
655  naco_error_reset("Could not get FITS key:");
656  } else {
657  cpl_propertylist_append_string(qclist, "ESO QC FILTER OBS", sval);
658  }
659  sval = naco_pfits_get_opti3_name(reflist);
660  if (cpl_error_get_code()) {
661  naco_error_reset("Could not get FITS key:");
662  } else {
663  cpl_propertylist_append_string(qclist, "ESO QC FILTER NDENS", sval);
664  }
665  sval = naco_pfits_get_opti4_name(reflist);
666  if (cpl_error_get_code()) {
667  naco_error_reset("Could not get FITS key:");
668  } else {
669  cpl_propertylist_append_string(qclist, "ESO QC FILTER POL", sval);
670  }
671 
672  bug_if(0);
673 
674  bug_if (cpl_propertylist_append(paflist, qclist));
675 
676  if (drop_wcs) {
677  cpl_propertylist * pcopy = cpl_propertylist_new();
678  const cpl_error_code error
679  = cpl_propertylist_copy_property_regexp(pcopy, reflist, "^("
680  IRPLIB_PFITS_WCS_REGEXP
681  ")$", 0);
682  if (!error && cpl_propertylist_get_size(pcopy) > 0) {
683  cpl_msg_warning(cpl_func, "Combined image will have no WCS "
684  "coordinates");
685  }
686  cpl_propertylist_delete(pcopy);
687 
688  bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
689  NACO_PFITS_REGEXP_JITTER_COPY
690  ")$", 0));
691  } else {
692  bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
693  IRPLIB_PFITS_WCS_REGEXP "|"
694  NACO_PFITS_REGEXP_JITTER_COPY
695  ")$", 0));
696  }
697 
698  if (cpl_propertylist_has(qclist, "AIRMASS"))
699  bug_if (irplib_pfits_set_airmass(qclist, objframes));
700 
701  end_skip;
702 
703  return cpl_error_get_code();
704 }
705 
706 /*----------------------------------------------------------------------------*/
714 /*----------------------------------------------------------------------------*/
715 static cpl_error_code naco_img_jitter_qc_apertures(cpl_propertylist * qclist,
716  const irplib_framelist *
717  objframes,
718  const cpl_image * combined)
719 {
720  const cpl_propertylist * reflist
722 
723  cpl_apertures * aperts = NULL;
724  cpl_bivector * fwhms = NULL;
725  cpl_vector * fwhms_sum = NULL;
726  cpl_vector * sigmas = NULL;
727  double * fwhms_x;
728  double * fwhms_y;
729  double * fwhms_sum_data;
730  int nb_val, nb_good;
731  double f_min, f_max;
732  double psigmas[] = {5.0, 2.0, 1.0, 0.5}; /* Not modified */
733  const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
734  cpl_size isigma;
735  int i;
736 
737  const double pixscale = naco_pfits_get_pixscale(reflist);
738  /* FIXME: Some hard-coded constants */
739  const double seeing_min_arcsec = 0.1;
740  const double seeing_max_arcsec = 5.0;
741  const double seeing_fwhm_var = 0.2;
742 
743  double iq, fwhm_pix, fwhm_arcsec;
744 
745 
746  /* Detect apertures */
747  cpl_msg_info(cpl_func, "Detecting apertures using %d sigma-levels "
748  "ranging from %g down to %g", nsigmas, psigmas[0],
749  psigmas[nsigmas-1]);
750 
751  /* pixscale could be mising */
752  skip_if( pixscale <= 0.0 );
753  bug_if( seeing_min_arcsec < 0.0);
754 
755  /* Create the vector for the detection thresholds. (Not modified) */
756  sigmas = cpl_vector_wrap(nsigmas, psigmas);
757 
758  aperts = cpl_apertures_extract(combined, sigmas, &isigma);
759  if (aperts == NULL) {
760  cpl_msg_warning(cpl_func, "Could not detect any apertures in combined "
761  "image");
762  skip_if(1);
763  }
764  bug_if(0);
765 
766  /* Compute the FHWM of the detected apertures */
767  fwhms = cpl_apertures_get_fwhm(combined, aperts);
768  if (fwhms == NULL) {
769  cpl_msg_warning(cpl_func, "Could not compute any FWHMs of the "
770  "apertures in the combined image");
771  skip_if(1);
772  }
773  bug_if(0);
774  cpl_apertures_delete(aperts);
775  aperts = NULL;
776 
777  /* Access the data */
778  nb_val = cpl_bivector_get_size(fwhms);
779  fwhms_x = cpl_bivector_get_x_data(fwhms);
780  fwhms_y = cpl_bivector_get_y_data(fwhms);
781 
782  /* Get the number of good values */
783  nb_good = 0;
784  for (i=0 ; i < nb_val ; i++) {
785  if (fwhms_x[i] <= 0.0 || fwhms_y[i] <= 0.0) continue;
786  fwhms_x[nb_good] = fwhms_x[i];
787  fwhms_y[nb_good] = fwhms_y[i];
788  nb_good++;
789  }
790 
791  cpl_msg_info(cpl_func, "Detected %d (%d) apertures at sigma=%g",
792  nb_good, nb_val, psigmas[isigma]);
793 
794  skip_if_lt (nb_good, 1, "aperture with a FWHM");
795 
796  nb_val = nb_good;
797  /* This resizing is not really needed */
798  bug_if(cpl_vector_set_size(cpl_bivector_get_x(fwhms), nb_val));
799  bug_if(cpl_vector_set_size(cpl_bivector_get_y(fwhms), nb_val));
800  fwhms_x = cpl_bivector_get_x_data(fwhms);
801  fwhms_y = cpl_bivector_get_y_data(fwhms);
802 
803  /* Get the good values */
804  fwhms_sum = cpl_vector_new(nb_good);
805  fwhms_sum_data = cpl_vector_get_data(fwhms_sum);
806  for (i=0; i < nb_good; i++) {
807  fwhms_sum_data[i] = fwhms_x[i] + fwhms_y[i];
808  }
809  /* Compute the fwhm as the median of the average of the FHWMs in x and y */
810  fwhm_pix = 0.5 * cpl_vector_get_median(fwhms_sum);
811 
812  bug_if(cpl_propertylist_append_double(qclist, "ESO QC FWHM PIX", fwhm_pix));
813 
814  fwhm_arcsec = fwhm_pix * pixscale;
815 
816  bug_if(cpl_propertylist_append_double(qclist, "ESO QC FWHM ARCSEC",
817  fwhm_arcsec));
818 
819  /* iq is the median of the (fwhm_x+fwhm_y)/2 */
820  /* of the good stars */
821 
822  /* Compute f_min and f_max */
823  f_min = seeing_min_arcsec / pixscale;
824  f_max = seeing_max_arcsec / pixscale;
825 
826  /* Sum the the good values */
827  nb_good = 0;
828  for (i=0 ; i < nb_val ; i++) {
829  const double fx = fwhms_x[i];
830  const double fy = fwhms_y[i];
831 
832  if (fx <= f_min || f_max <= fx || fy <= f_min || f_max <= fy) continue;
833  if (fabs(fx-fy) >= 0.5 * (fx + fy) * seeing_fwhm_var) continue;
834 
835  fwhms_sum_data[nb_good] = fx + fy;
836  nb_good++;
837  }
838 
839  cpl_msg_info(cpl_func, "%d of the apertures have FWHMs within the range "
840  "%g to %g and eccentricity within %g", nb_good, f_min, f_max,
841  seeing_fwhm_var);
842 
843  skip_if_lt (nb_good, 1, "aperture with a good FWHM");
844 
845  bug_if(cpl_vector_set_size(fwhms_sum, nb_good));
846 
847  /* Compute the fwhm */
848  iq = pixscale * 0.5 * cpl_vector_get_median(fwhms_sum);
849 
850  bug_if(cpl_propertylist_append_double(qclist, "ESO QC IQ", iq));
851 
852  end_skip;
853 
854  cpl_vector_delete(fwhms_sum);
855  cpl_bivector_delete(fwhms);
856  cpl_vector_unwrap(sigmas);
857  cpl_apertures_delete(aperts);
858 
859  return cpl_error_get_code();
860 }
861 
862 /*----------------------------------------------------------------------------*/
875 /*----------------------------------------------------------------------------*/
876 static cpl_error_code naco_img_jitter_save(cpl_frameset * set,
877  const cpl_parameterlist * parlist,
878  const cpl_propertylist * qclist,
879  const cpl_propertylist * paflist,
880  const cpl_imagelist * objimages,
881  const cpl_image * combined,
882  const cpl_image * contrib,
883  const cpl_table * cubetable)
884 {
885 
886  const cpl_boolean is_cube = cpl_table_get_ncol(cubetable) > 0
887  ? CPL_TRUE : CPL_FALSE;
888  const char * procatg = is_cube ? NACO_IMG_JITTER_CUBE
889  : NACO_IMG_JITTER_COMB;
890  cpl_propertylist * xtlist = cpl_propertylist_new();
891  const cpl_boolean save_cube =
892  naco_parameterlist_get_bool(parlist, RECIPE_STRING,
893  NACO_PARAM_SAVECUBE);
894 
895  bug_if (0);
896  bug_if (contrib == NULL);
897 
898  /* Write the FITS file */
899  skip_if (irplib_dfs_save_image(set, parlist, set, combined,
900  CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
901  procatg, qclist, NULL,
902  naco_pipe_id, RECIPE_STRING CPL_DFS_FITS));
903 
904  bug_if(cpl_propertylist_append_string(xtlist, "EXTNAME",
905  "Contribution Map"));
906  skip_if (cpl_image_save(contrib, RECIPE_STRING CPL_DFS_FITS,
907  CPL_BPP_16_SIGNED, xtlist, CPL_IO_EXTEND));
908 
909  if (is_cube) {
910 
911  bug_if(cpl_propertylist_update_string(xtlist, "EXTNAME",
912  "Plane Properties"));
913  skip_if (cpl_table_save(cubetable, NULL, xtlist,
914  RECIPE_STRING CPL_DFS_FITS, CPL_IO_EXTEND));
915  }
916 
917  if (save_cube) {
918  bug_if(cpl_propertylist_update_string(xtlist, "EXTNAME",
919  "Corrected object images"));
920  skip_if (cpl_imagelist_save(objimages, RECIPE_STRING CPL_DFS_FITS,
921  CPL_BPP_IEEE_FLOAT, xtlist, CPL_IO_EXTEND));
922  }
923 
924 #ifdef NACO_SAVE_PAF
925  skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, paflist,
926  RECIPE_STRING CPL_DFS_PAF));
927 #else
928  bug_if(paflist == NULL);
929 #endif
930 
931  end_skip;
932 
933  cpl_propertylist_delete(xtlist);
934 
935  return cpl_error_get_code();
936 
937 }
938 
939 /*----------------------------------------------------------------------------*/
951 /*----------------------------------------------------------------------------*/
952 static
953 cpl_error_code naco_img_jitter_load_objimages(cpl_imagelist * objlist,
954  cpl_array * iscube,
955  const irplib_framelist * self,
956  const cpl_parameterlist * parlist)
957 {
958  const int nframes = irplib_framelist_get_size(self);
959  cpl_image * image = NULL;
960  int i;
961 
962  bug_if(objlist == NULL);
963  bug_if(self == NULL);
964  bug_if(iscube == NULL);
965  bug_if(parlist == NULL);
966 
967  for (i=0; i < nframes; i++, image = NULL) {
968  const char * filename
969  = cpl_frame_get_filename(irplib_framelist_get_const(self, i));
970  const cpl_propertylist * plist
972  const int naxis3 = cpl_propertylist_has(plist, "NAXIS3") ?
973  cpl_propertylist_get_int(plist, "NAXIS3") : 1;
974 
975 
976  if (naxis3 > 2) { /* Real cube mode has at least two frames + sum */
977 
978  bug_if(cpl_array_set_int(iscube, i, 1));
979 
980  /* EPompei 2009-11-13:
981  The last frame in the cube is the sum of all the previous ones.
982  This is not DICB compliant and may change.
983  See also the NACO user manual.
984  */
985 
986  image = cpl_image_load(filename, CPL_TYPE_FLOAT, naxis3-1, EXT0);
987 
988  any_if("Could not load %d-cube-sum from frame %d/%d, file=%s",
989  naxis3-1, i+1, nframes, filename);
990 
991  } else {
992  image = cpl_image_load(filename, CPL_TYPE_FLOAT, 0, EXT0);
993 
994  any_if("Could not load FITS-image from extension %d in frame "
995  "%d/%d, file=%s", EXT0, i+1, nframes, filename);
996 
997  }
998  bug_if(cpl_imagelist_set(objlist, image, i));
999  }
1000 
1001  end_skip;
1002 
1003  cpl_image_delete(image);
1004 
1005  return cpl_error_get_code();
1006 
1007 }
1008 
1009 /*----------------------------------------------------------------------------*/
1017 /*----------------------------------------------------------------------------*/
1018 static cpl_error_code naco_img_jitter_check_cube(const cpl_imagelist * self,
1019  const cpl_image * sum)
1020 {
1021  cpl_image * accu = cpl_imagelist_collapse_create(self);
1022  double err;
1023 
1024  cpl_image_subtract(accu, sum);
1025 
1026  err = cpl_image_get_absflux(accu);
1027 
1028  if (err > 0.0) {
1029  err /= cpl_image_get_size_x(sum) * cpl_image_get_size_y(sum);
1030 
1031  cpl_msg_info(cpl_func, "Average per-pixel error in final sum frame "
1032  "in %d-cube: %g", (int)cpl_imagelist_get_size(self), err);
1033  }
1034 
1035  cpl_image_delete(accu);
1036 
1037  return cpl_error_get_code();
1038 }
1039 
1040 
1041 /*----------------------------------------------------------------------------*/
1053 /*----------------------------------------------------------------------------*/
1054 static cpl_error_code naco_img_jitter_do_cube(cpl_imagelist * self,
1055  cpl_table * cubetable,
1056  cpl_propertylist * qclist,
1057  const cpl_array * iscube,
1058  const irplib_framelist * obj,
1059  const cpl_parameterlist * parlist)
1060 {
1061 
1062  const int nframes = irplib_framelist_get_size(obj);
1063  cpl_imagelist * onelist = NULL;
1064  cpl_image * sum = NULL;
1065  cpl_image * onesky = NULL;
1066  const int nskyplane = naco_parameterlist_get_int(parlist,
1067  RECIPE_STRING,
1068  NACO_PARAM_SKYPLANE);
1069  cpl_vector * skymedians = cpl_vector_new(nframes);
1070  int nsky = 0;
1071  int i;
1072 
1073  bug_if(self == NULL);
1074  bug_if(cubetable == NULL);
1075  bug_if(qclist == NULL);
1076  bug_if(obj == NULL);
1077  bug_if(parlist == NULL);
1078  bug_if(nframes != cpl_array_get_size(iscube));
1079  bug_if(nframes != cpl_imagelist_get_size(self));
1080 
1081 
1082  for (i=0; i < nframes; i++) {
1083  int is_invalid = 0;
1084 
1085  (void)cpl_array_get_int(iscube, i, &is_invalid);
1086 
1087  if (!is_invalid) {
1088  const char * filename
1089  = cpl_frame_get_filename(irplib_framelist_get_const(obj, i));
1090  const cpl_propertylist * plist
1092  double skymedian;
1093  int naxis3;
1094 
1095  /* Estimate the sky from nearby cube(s) */
1096  cpl_image_delete(onesky);
1097  onesky = naco_img_jitter_find_sky_cube(i, nskyplane, iscube, obj);
1098  any_if("Could not estimate sky for frame %d/%d, file=%s",
1099  i+1, nframes, filename);
1100 
1101  skymedian = cpl_image_get_median(onesky);
1102 #ifdef NACO_IMG_JITTER_DEVELOPMENT
1103  if (onelist == NULL) {
1104 
1105  /* FIXME: Compute from all cube-sky frames ? */
1106  /* Get the background value */
1107  bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD",
1108  skymedian));
1109 
1110  cpl_image_save(onesky, "Sky.fits", CPL_BPP_IEEE_FLOAT, NULL,
1111  CPL_IO_CREATE);
1112  } else {
1113  cpl_image_save(onesky, "Sky.fits", CPL_BPP_IEEE_FLOAT, NULL,
1114  CPL_IO_EXTEND);
1115  }
1116 #endif
1117  cpl_imagelist_delete(onelist);
1118  onelist = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
1119 
1120  any_if("Could not load cube from frame %d/%d, file=%s",
1121  i+1, nframes, filename);
1122 
1123  naxis3 = cpl_imagelist_get_size(onelist);
1124 
1125  cpl_msg_info(cpl_func, "Processing %d-cube from frame %d/%d, "
1126  "file=%s. Median of sky-estimate: %g",
1127  naxis3-1, i+1, nframes, filename, skymedian);
1128  cpl_vector_set(skymedians, nsky++, skymedian);
1129 
1130  bug_if(naxis3 < 3);
1131 
1132  sum = cpl_imagelist_unset(onelist, naxis3-1);
1133 
1134  bug_if(naco_img_jitter_check_cube(onelist, sum));
1135 
1136  skip_if(cpl_imagelist_subtract_image(onelist, onesky));
1137 
1138  cpl_image_delete(sum);
1139  sum = naco_img_jitter_combine_cube(cubetable, onelist, plist,
1140  parlist, i);
1141  any_if("Could not combine %d images from frame %d/%d, file=%s",
1142  naxis3-1, i+1, nframes, filename);
1143 
1144  bug_if(cpl_imagelist_set(self, sum, i));
1145  sum = NULL;
1146  }
1147  }
1148 
1149  if (nsky > 1) {
1150  double skystdev, skymean;
1151 
1152  bug_if(cpl_vector_set_size(skymedians, nsky));
1153 
1154  skymean = cpl_vector_get_mean(skymedians);
1155  skystdev = cpl_vector_get_stdev(skymedians);
1156 
1157  cpl_msg_info(cpl_func, "Mean and stdev of %d medians of sky estimates: "
1158  "%g %g", nsky, skymean, skystdev);
1159 
1160  bug_if(cpl_propertylist_append_double(qclist, "ESO QC SKY STDEV",
1161  skystdev));
1162  }
1163 
1164  end_skip;
1165 
1166  cpl_imagelist_delete(onelist);
1167  cpl_image_delete(sum);
1168  cpl_image_delete(onesky);
1169  cpl_vector_delete(skymedians);
1170 
1171  return cpl_error_get_code();
1172 }
1173 
1174 
1175 
1176 /*----------------------------------------------------------------------------*/
1187 /*----------------------------------------------------------------------------*/
1188 static
1189 cpl_image * naco_img_jitter_combine_cube(cpl_table * cubetable,
1190  const cpl_imagelist * cube,
1191  const cpl_propertylist * plist,
1192  const cpl_parameterlist * parlist,
1193  int idx)
1194 {
1195 
1196  cpl_errorstate prestate = cpl_errorstate_get();
1197  cpl_image * self = NULL;
1198  const int ncube = cpl_imagelist_get_size(cube);
1199  cpl_image ** combined = NULL;
1200  cpl_apertures * apert = NULL;
1201  cpl_bivector * offs = cpl_bivector_new(ncube);
1202  cpl_vector * offsx = cpl_bivector_get_x(offs);
1203  cpl_vector * offsy = cpl_bivector_get_y(offs);
1204  cpl_vector * sigmas = NULL;
1205  cpl_vector * vstrehl = cpl_vector_new(ncube);
1206  double psigmas[] = {5.0, 2.0, 1.0, 0.5}; /* not modified */
1207  const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
1208  /* Use half of default value to support images windowed to 128 x 130 */
1209  /* FIXME: Adjust according to image size ? */
1210  const double rstar = 0.5 * IRPLIB_STREHL_STAR_RADIUS;
1211  const double rbgint = 0.5 * IRPLIB_STREHL_BACKGROUND_R1;
1212  const double rbgext = 0.5 * IRPLIB_STREHL_BACKGROUND_R2;
1213  const double pixscale = naco_pfits_get_pixscale(plist);
1214  const double lucky = naco_parameterlist_get_double(parlist,
1215  RECIPE_STRING,
1216  NACO_PARAM_LUCK_STR);
1217  const char * filter = naco_pfits_get_filter(plist);
1218  double lam = DBL_MAX; /* Avoid uninit warning */
1219  double dlam = DBL_MAX; /* Avoid uninit warning */
1220  cpl_size isigma = 0;
1221  const int ncubetable = cpl_table_get_nrow(cubetable);
1222  int icubetable; /* 1st table row to write to */
1223  int i;
1224 
1225 
1226  skip_if(rbgext <= rbgint);
1227  skip_if(pixscale <= 0.0);
1228 
1229  irplib_check(naco_get_filter_infos(filter, &lam, &dlam),
1230  "Frame has no info for filter %s", filter);
1231 
1232  cpl_msg_debug(cpl_func, "Frame %d has pixelscale [Arcsecond/pixel]=%g, "
1233  "Central wavelength [micron]=%g, Filter bandwidth "
1234  "[micron]=%g", 1+idx, pixscale, lam, dlam);
1235  cpl_msg_debug(cpl_func, "Frame %d assumes Rstar [pixel]=%g, Rint "
1236  "[pixel]=%g, Rext [pixel]=%g", 1+idx, rstar/pixscale,
1237  rbgint/pixscale, rbgext/pixscale);
1238 
1239  if (cpl_table_get_ncol(cubetable) == 0) {
1240  cpl_table_new_column(cubetable, "Frame", CPL_TYPE_INT);
1241  cpl_table_new_column(cubetable, "Plane", CPL_TYPE_INT);
1242  cpl_table_new_column(cubetable, "XCentroid", CPL_TYPE_DOUBLE);
1243  cpl_table_new_column(cubetable, "YCentroid", CPL_TYPE_DOUBLE);
1244  cpl_table_set_column_unit(cubetable, "XCentroid", "pixel");
1245  cpl_table_set_column_unit(cubetable, "YCentroid", "pixel");
1246  cpl_table_new_column(cubetable, "Strehl", CPL_TYPE_DOUBLE);
1247  cpl_table_new_column(cubetable, "Strehl_Error", CPL_TYPE_DOUBLE);
1248  cpl_table_new_column(cubetable, "Star_Background", CPL_TYPE_DOUBLE);
1249  cpl_table_new_column(cubetable, "Star_Peak", CPL_TYPE_DOUBLE);
1250  cpl_table_new_column(cubetable, "Star_Flux", CPL_TYPE_DOUBLE);
1251  cpl_table_new_column(cubetable, "PSF_Peak_per_Flux", CPL_TYPE_DOUBLE);
1252  cpl_table_set_column_unit(cubetable, "PSF_Peak_per_Flux", "unitless");
1253  cpl_table_new_column(cubetable, "Background_Noise", CPL_TYPE_DOUBLE);
1254  cpl_table_set_size(cubetable, ncube);
1255  icubetable = 0;
1256  } else {
1257  cpl_table_set_size(cubetable, ncubetable + ncube);
1258  icubetable = ncubetable;
1259  }
1260 
1261  /* Create the vector for the detection thresholds */
1262  sigmas = cpl_vector_wrap(nsigmas, psigmas);
1263  for (i = 0; i < ncube; i++) {
1264  const cpl_image * one = cpl_imagelist_get_const(cube, i);
1265  double cent_x, cent_y;
1266  double strehl, strehl_err, star_bg,star_peak, star_flux;
1267  double psf_peak, psf_flux, bg_noise;
1268  int iflux;
1269 
1270 
1271  cpl_apertures_delete(apert);
1272  apert = cpl_apertures_extract(one, sigmas, &isigma);
1273 
1274  any_if("No object found in image %d/%d in frame %d", i+1, ncube, 1+idx);
1275 
1276  bug_if(irplib_apertures_find_max_flux(apert, &iflux, 1));
1277 
1278  cent_x = cpl_apertures_get_centroid_x(apert, iflux);
1279  cent_y = cpl_apertures_get_centroid_y(apert, iflux);
1280  cpl_vector_set(offsx, i, cent_x);
1281  cpl_vector_set(offsy, i, cent_y);
1282 
1283  cpl_msg_debug(cpl_func, "Detected %d/%d sigma=%g-aperture(s) (x,y)"
1284  "=(%g,%g) (%d/%d) in %d/%d-image in frame %d", iflux,
1285  (int)cpl_apertures_get_size(apert), psigmas[isigma],
1286  cent_x, cent_y, 1+(int)isigma, nsigmas, 1+i, ncube,
1287  1+idx);
1288 
1289  cpl_table_set_int(cubetable, "Frame", i+icubetable, 1+idx);
1290  cpl_table_set_int(cubetable, "Plane", i+icubetable, 1+i);
1291  cpl_table_set_double(cubetable, "XCentroid", i+icubetable, cent_x);
1292  cpl_table_set_double(cubetable, "YCentroid", i+icubetable, cent_y);
1293 
1294 
1295  if (naco_strehl_compute(one, parlist, RECIPE_STRING, lam, dlam,
1296  cent_x, cent_y, pixscale,
1297  &strehl, &strehl_err,
1298  &star_bg, &star_peak, &star_flux,
1299  &psf_peak, &psf_flux,
1300  &bg_noise)) {
1301  cpl_msg_info(cpl_func, "Could not compute strehl for "
1302  "image %d in frame %d", 1+i, 1+idx);
1303  cpl_errorstate_dump(prestate, CPL_FALSE,
1305  cpl_errorstate_set(prestate);
1306 
1307  cpl_table_set_invalid(cubetable, "Strehl", i+icubetable);
1308  cpl_table_set_invalid(cubetable, "Strehl_Error", i+icubetable);
1309  cpl_table_set_invalid(cubetable, "Star_Background", i+icubetable);
1310  cpl_table_set_invalid(cubetable, "Star_Peak", i+icubetable);
1311  cpl_table_set_invalid(cubetable, "Star_Flux", i+icubetable);
1312  cpl_table_set_invalid(cubetable, "PSF_Peak_per_Flux", i+icubetable);
1313  cpl_table_set_invalid(cubetable, "Background_Noise", i+icubetable);
1314  cpl_vector_set(vstrehl, i, 0.0);
1315 
1316  } else {
1317  cpl_vector_set(vstrehl, i, strehl);
1318  cpl_table_set_double(cubetable, "Strehl", i+icubetable, strehl);
1319  cpl_table_set_double(cubetable, "Strehl_Error", i+icubetable,
1320  strehl_err);
1321  cpl_table_set_double(cubetable, "Star_Background", i+icubetable,
1322  star_bg);
1323  cpl_table_set_double(cubetable, "Star_Peak", i+icubetable,
1324  star_peak);
1325  cpl_table_set_double(cubetable, "Star_Flux", i+icubetable,
1326  star_flux);
1327  cpl_table_set_double(cubetable, "PSF_Peak_per_Flux", i+icubetable,
1328  psf_peak/psf_flux);
1329  cpl_table_set_double(cubetable, "Background_Noise", i+icubetable,
1330  bg_noise);
1331  }
1332  }
1333 
1334  self = naco_img_jitter_saa_lucky(cube, vstrehl, offs, lucky);
1335 
1336  end_skip;
1337 
1338  if (combined != NULL) {
1339  cpl_image_delete(combined[0]);
1340  cpl_free(combined);
1341  }
1342 
1343  cpl_bivector_delete(offs);
1344  (void)cpl_vector_unwrap(sigmas);
1345  cpl_apertures_delete(apert);
1346  cpl_vector_delete(vstrehl);
1347 
1348  cpl_ensure(self != NULL, cpl_error_get_code(), NULL);
1349 
1350  return self;
1351 
1352 }
1353 
1354 
1355 /*----------------------------------------------------------------------------*/
1365 /*----------------------------------------------------------------------------*/
1366 static cpl_image * naco_img_jitter_find_sky_cube(int isky, int nskyplane,
1367  const cpl_array * iscube,
1368  const irplib_framelist * obj)
1369 {
1370 
1371  cpl_image * self = NULL;
1372  const int nframes = irplib_framelist_get_size(obj);
1373  cpl_imagelist * belowcube = NULL;
1374  cpl_imagelist * abovecube = NULL;
1375  cpl_imagelist * skycube = NULL;
1376  cpl_imagelist * mycube = NULL;
1377  cpl_image * mysky = NULL;
1378  cpl_mask * fillbpm = NULL;
1379  int is_invalid = 0;
1380  int ibelow, iabove;
1381  int i;
1382 
1383  bug_if(isky < 0);
1384  bug_if(isky >= nframes);
1385  bug_if(nframes != cpl_array_get_size(iscube));
1386  if (nskyplane > 0) skip_if_lt(nskyplane, 3, "sky planes for median");
1387 
1388 
1389  (void)cpl_array_get_int(iscube, isky, &is_invalid);
1390 
1391  bug_if(is_invalid); /* isky must be a cube */
1392 
1393  /* Find 1st cube below isky */
1394  for (i = isky - 1; i >= 0; i++) {
1395 
1396  (void)cpl_array_get_int(iscube, i, &is_invalid);
1397 
1398  if (!is_invalid) break;
1399  }
1400 
1401  ibelow = i; /* -1 means no cube below */
1402 
1403  /* Find 1st cube above isky */
1404  for (i = isky + 1; i < nframes; i++) {
1405 
1406  (void)cpl_array_get_int(iscube, i, &is_invalid);
1407 
1408  if (!is_invalid) break;
1409  }
1410 
1411  iabove = i; /* nframes means no cube above */
1412 
1413  cpl_msg_info(cpl_func, "Estimating sky for cube %d/%d via cubes %d and %d",
1414  1+isky, nframes, 1+ibelow, 1+iabove);
1415 
1416 
1417  if (ibelow >= 0) {
1418  const char * filename
1419  = cpl_frame_get_filename(irplib_framelist_get_const(obj, ibelow));
1420 
1421  if (nskyplane > 0) {
1422  /* Load the last nskyplane frames */
1423  const cpl_propertylist * plist
1425  /* Ignore the last sum plane */
1426  const int istop = irplib_pfits_get_int(plist, "NAXIS3") - 2;
1427  const int istart = NACO_MAX(0, istop - nskyplane + 1);
1428 
1429  skip_if_lt(istop - istart, 2, "sky planes for median");
1430 
1431  belowcube = cpl_imagelist_new();
1432 
1433  for (i = istart; i <= istop; i++) {
1434  self = cpl_image_load(filename, CPL_TYPE_FLOAT, i, EXT0);
1435 
1436  any_if("Could not load plane %d from frame %d/%d, file=%s",
1437  1+i, 1+ibelow, nframes, filename);
1438 
1439  bug_if(cpl_imagelist_set(belowcube, self, i - istart));
1440  }
1441 
1442  } else {
1443  int naxis3;
1444 
1445  belowcube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
1446 
1447  any_if("Could not load cube from frame %d/%d, file=%s",
1448  1+ibelow, nframes, filename);
1449 
1450  naxis3 = cpl_imagelist_get_size(belowcube);
1451 
1452  bug_if(naxis3 < 3);
1453 
1454  cpl_image_delete(cpl_imagelist_unset(belowcube, naxis3-1));
1455 
1456  }
1457 
1458  }
1459 
1460  if (iabove < nframes) {
1461  const char * filename
1462  = cpl_frame_get_filename(irplib_framelist_get_const(obj, iabove));
1463 
1464  if (nskyplane > 0) {
1465  /* Load the first nskyplane frames */
1466  const cpl_propertylist * plist
1468  const int istart = 0;
1469  /* Ignore the last sum plane */
1470  const int istop = NACO_MIN(nskyplane-1, irplib_pfits_get_int
1471  (plist, "NAXIS3") - 2);
1472 
1473  skip_if_lt(istop - istart, 2, "sky planes for median");
1474 
1475  abovecube = cpl_imagelist_new();
1476 
1477  for (i = istart; i <= istop; i++) {
1478  self = cpl_image_load(filename, CPL_TYPE_FLOAT, i, EXT0);
1479 
1480  any_if("Could not load plane %d from frame %d/%d, file=%s",
1481  1+i, 1+iabove, nframes, filename);
1482 
1483  bug_if(cpl_imagelist_set(abovecube, self, i - istart));
1484  }
1485 
1486  } else {
1487 
1488  int naxis3;
1489 
1490  abovecube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
1491 
1492  any_if("Could not load cube from frame %d/%d, file=%s",
1493  1+iabove, nframes, filename);
1494 
1495  naxis3 = cpl_imagelist_get_size(abovecube);
1496 
1497  bug_if(naxis3 < 3);
1498 
1499  cpl_image_delete(cpl_imagelist_unset(abovecube, naxis3-1));
1500  }
1501 
1502  }
1503 
1504  error_if(belowcube == NULL && abovecube == NULL, CPL_ERROR_DATA_NOT_FOUND,
1505  "No cube(s) available for sky estimation among %d object frames",
1506  nframes);
1507 
1508  if (belowcube == NULL) {
1509  skycube = abovecube;
1510  } else if (abovecube == NULL) {
1511  skycube = belowcube;
1512  } else {
1513  /* Wrap around the images in the two cubes */
1514 
1515  const int nbelow = cpl_imagelist_get_size(belowcube);
1516  const int nabove = cpl_imagelist_get_size(abovecube);
1517  int nwrap = 0;
1518 
1519  skycube = cpl_imagelist_new();
1520 
1521  for (i = 0; i < nbelow; i++) {
1522  skip_if(cpl_imagelist_set(skycube, cpl_imagelist_get(belowcube, i),
1523  nwrap++));
1524  }
1525  for (i = 0; i < nabove; i++) {
1526  skip_if(cpl_imagelist_set(skycube, cpl_imagelist_get(abovecube, i),
1527  nwrap++));
1528  }
1529  skip_if(cpl_imagelist_get_size(skycube) != nwrap);
1530  skip_if(nbelow + nabove != nwrap);
1531  }
1532 
1533  self = cpl_imagelist_collapse_median_create(skycube);
1534 
1535 #ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
1536  if (belowcube == NULL || abovecube == NULL) {
1537  /* Try to replace object-pixels with sky-pixels from the object image */
1538  const cpl_mask * fill2bpm;
1539  const cpl_mask * selfbpm = NULL;
1540  const double lo_skysigma = 0.2;
1541  const double hi_skysigma = 5.0;
1542 
1543  skip_if(naco_img_jitter_reject_objects(self, lo_skysigma, hi_skysigma));
1544 
1545  selfbpm = cpl_image_get_bpm_const(self);
1546 
1547  if (selfbpm != NULL) {
1548  const cpl_mask * mybpm;
1549 
1550  /* Substitute the objects pixels with sky pixels from isky */
1551 
1552  const char * filename
1553  = cpl_frame_get_filename(irplib_framelist_get_const(obj, isky));
1554  int naxis3;
1555 
1556  mycube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
1557 
1558  any_if("Could not load cube from frame %d/%d, file=%s",
1559  1+isky, nframes, filename);
1560 
1561  naxis3 = cpl_imagelist_get_size(mycube);
1562 
1563  bug_if(naxis3 < 3);
1564 
1565  cpl_image_delete(cpl_imagelist_unset(mycube, naxis3-1));
1566 
1567  mysky = cpl_imagelist_collapse_median_create(mycube);
1568 
1569  skip_if(naco_img_jitter_reject_objects(mysky, lo_skysigma,
1570  hi_skysigma));
1571 
1572  /* When a pixel is bad in self and good in mysky: Set to mysky */
1573  /* Other pixels in self are unchanged */
1574 
1575  mybpm = cpl_image_get_bpm_const(mysky);
1576 
1577  if (mybpm == NULL) {
1578  /* Fill all bad pixels in self with values from mysky */
1579  fill2bpm = selfbpm;
1580  } else {
1581  /* Fill those bad pixels in self with values from mysky
1582  when those pixels are good */
1583  fillbpm = cpl_mask_duplicate(mybpm);
1584  bug_if(cpl_mask_not(fillbpm));
1585  bug_if(cpl_mask_and(fillbpm, selfbpm));
1586 
1587  fill2bpm = fillbpm;
1588 
1589  }
1590  cpl_msg_info(cpl_func, "Filling %d object-pixels in sky image "
1591  "with %d sky-pixels from object image",
1592  (int)cpl_mask_count(selfbpm),
1593  (int)cpl_mask_count(fill2bpm));
1594  if (fill2bpm != selfbpm) {
1595  /* These rejected pixels will be filled */
1596  bug_if(cpl_image_reject_from_mask(self, fill2bpm));
1597  }
1598 
1599  if (fillbpm == NULL) {
1600  fillbpm = cpl_mask_duplicate(fill2bpm);
1601  } else if (fillbpm != fill2bpm) {
1602  bug_if(cpl_mask_copy(fillbpm, fill2bpm, 1, 1));
1603  }
1604 
1605  bug_if(cpl_image_fill_rejected(self, 0.0)); /* Use addition to fill */
1606  bug_if(cpl_image_accept_all(self)); /* fill2bpm may be invalid now */
1607 
1608  bug_if(cpl_mask_not(fillbpm));
1609  bug_if(cpl_image_reject_from_mask(mysky, fillbpm));
1610  bug_if(cpl_image_fill_rejected(mysky, 0.0)); /* Use addition to fill */
1611  bug_if(cpl_image_accept_all(mysky));
1612  bug_if(cpl_image_add(self, mysky));
1613  }
1614  }
1615 #endif
1616 
1617  end_skip;
1618 
1619  if (cpl_error_get_code()) {
1620  cpl_image_delete(self);
1621  self = NULL;
1622  }
1623 
1624 
1625  if (skycube != belowcube && skycube != abovecube) {
1626  int nwrap = cpl_imagelist_get_size(skycube);
1627 
1628  /* Unwrap the wrapped images */
1629  for (;nwrap > 0;) {
1630  (void)cpl_imagelist_unset(skycube, --nwrap);
1631  }
1632 
1633  cpl_imagelist_delete(skycube);
1634  }
1635 
1636  cpl_mask_delete(fillbpm);
1637  cpl_image_delete(mysky);
1638  cpl_imagelist_delete(mycube);
1639  cpl_imagelist_delete(belowcube);
1640  cpl_imagelist_delete(abovecube);
1641 
1642  return self;
1643 }
1644 
1645 
1646 /*----------------------------------------------------------------------------*/
1657 /*----------------------------------------------------------------------------*/
1658 static
1659 cpl_error_code naco_img_jitter_imagelist_wrap_nocube(cpl_imagelist * self,
1660  const cpl_array * iscube,
1661  cpl_imagelist * other)
1662 {
1663 
1664  const int ncube = cpl_imagelist_get_size(other);
1665  int nwrap = cpl_imagelist_get_size(self);
1666  int i;
1667 
1668  bug_if(self == NULL);
1669  bug_if(iscube == NULL);
1670  bug_if(other == NULL);
1671  bug_if(nwrap != 0);
1672  bug_if(cpl_array_get_size(iscube) != ncube);
1673 
1674  for (i = 0; i < ncube; i++) {
1675  int is_invalid;
1676 
1677  (void)cpl_array_get_int(iscube, i, &is_invalid);
1678 
1679  if (is_invalid) {
1680  cpl_imagelist_set(self, cpl_imagelist_get(other, i), nwrap);
1681  nwrap++;
1682  }
1683  }
1684 
1685  bug_if(cpl_imagelist_get_size(self) != nwrap);
1686 
1687  end_skip;
1688 
1689  return cpl_error_get_code();
1690 }
1691 
1692 
1693 #ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
1694 
1695 /*----------------------------------------------------------------------------*/
1706 /*----------------------------------------------------------------------------*/
1707 static cpl_error_code naco_img_jitter_reject_objects(cpl_image * self,
1708  double lo_sigma,
1709  double hi_sigma)
1710 {
1711  double median;
1712  double med_dist = DBL_MAX;
1713  double hi_threshold;
1714  cpl_mask * hi_objects = NULL;
1715  cpl_mask * lo_objects = NULL;
1716  cpl_mask * rejects = NULL;
1717  cpl_image * hi_label = NULL;
1718  cpl_image * lo_label = NULL;
1719  cpl_apertures * hi_apert = NULL;
1720  cpl_mask * kernel = NULL;
1721 
1722 
1723  bug_if(self == NULL);
1724  bug_if(lo_sigma <= 0.0);
1725  bug_if(hi_sigma < lo_sigma);
1726 
1727  /* Compute the threshold */
1728  median = cpl_image_get_median_dev(self, &med_dist);
1729  hi_threshold = median + hi_sigma * med_dist;
1730 
1731  /* Binarise the image with the high sigma threshold */
1732  hi_objects = cpl_mask_threshold_image_create(self, hi_threshold, DBL_MAX);
1733  bug_if(hi_objects == NULL);
1734 
1735  /* Apply a morphological opening to remove the single pixel detections */
1736  /* Copied from cpl_apertures_extract_sigma() */
1737  kernel = cpl_mask_new(3, 3);
1738  bug_if(cpl_mask_not(kernel));
1739  bug_if(cpl_mask_filter(hi_objects, hi_objects, kernel, CPL_FILTER_OPENING,
1740  CPL_BORDER_ZERO));
1741 
1742  if (!cpl_mask_is_empty(hi_objects)) {
1743  /* Any low-sigma aperture overlapping a high-sigma
1744  aperture is assumed to be (all of) an object */
1745 
1746  const double lo_threshold = median + lo_sigma * med_dist;
1747  cpl_size hi_ilabel, hi_nlabel, lo_nlabel;
1748 
1749  /* Binarise the image with the low sigma threshold */
1750  lo_objects = cpl_mask_threshold_image_create(self, lo_threshold, DBL_MAX);
1751  bug_if(lo_objects == NULL);
1752  bug_if(cpl_mask_filter(lo_objects, lo_objects, kernel,
1753  CPL_FILTER_OPENING, CPL_BORDER_ZERO));
1754 
1755  hi_label = cpl_image_labelise_mask_create(hi_objects, &hi_nlabel);
1756  lo_label = cpl_image_labelise_mask_create(lo_objects, &lo_nlabel);
1757 
1758  hi_apert = cpl_apertures_new_from_image(self, hi_label);
1759  bug_if(hi_apert == NULL);
1760 
1761  for (hi_ilabel = 1; hi_ilabel <= hi_nlabel; hi_ilabel++) {
1762  /* Get one pixel from the high-sigma aperture */
1763  const int pos_x = cpl_apertures_get_top_x(hi_apert, hi_ilabel);
1764  const int pos_y = cpl_apertures_get_top(hi_apert, hi_ilabel);
1765  /* The corresponding low-sigma aperture */
1766  int is_rejected;
1767  const int lo_ilabel = (int)cpl_image_get(lo_label, pos_x, pos_y,
1768  &is_rejected);
1769 
1770  /* The mask of pixels with the corresponding low-sigma aperture */
1771  cpl_mask_delete(rejects);
1772  rejects = cpl_mask_threshold_image_create(lo_label,
1773  (double)lo_ilabel - 0.5,
1774  (double)lo_ilabel + 0.5);
1775 
1776  /* Add to the rejection mask */
1777  cpl_mask_or(hi_objects, rejects);
1778 
1779  }
1780 
1781  cpl_msg_info(cpl_func, "Found %d object(s) of %d pixel(s) "
1782  "in sky image using sigmas %g and %g", (int)hi_nlabel,
1783  (int)cpl_mask_count(hi_objects), lo_sigma, hi_sigma);
1784  bug_if(cpl_image_reject_from_mask(self, hi_objects));
1785 
1786  }
1787 
1788  end_skip;
1789 
1790  cpl_apertures_delete(hi_apert);
1791  cpl_image_delete(hi_label);
1792  cpl_image_delete(lo_label);
1793  cpl_mask_delete(kernel);
1794  cpl_mask_delete(hi_objects);
1795  cpl_mask_delete(lo_objects);
1796  cpl_mask_delete(rejects);
1797 
1798  return cpl_error_get_code();
1799 }
1800 #endif
1801 
1802 
1803 
1804 /*----------------------------------------------------------------------------*/
1814 /*----------------------------------------------------------------------------*/
1815 static cpl_image * naco_img_jitter_saa_lucky(const cpl_imagelist * cube,
1816  const cpl_vector * strehl,
1817  const cpl_bivector * offs,
1818  double fraction)
1819 {
1820 
1821  cpl_image * self = NULL;
1822  const int ncube = cpl_imagelist_get_size(cube);
1823  const int mcube = NACO_MAX(NACO_MIN(ncube, (int)(0.5 + fraction * ncube)),
1824  1);
1825  cpl_imagelist * lcube = NULL;
1826  const cpl_imagelist * ucube;
1827  cpl_vector * lstrehl = mcube == ncube ? (cpl_vector*)strehl
1828  : cpl_vector_duplicate(strehl);
1829  /* Always need to duplicate due to pesky offset convention in
1830  cpl_geom_img_offset_saa() */
1831  cpl_bivector * loffs = cpl_bivector_duplicate(offs);
1832  cpl_vector * loffsx = cpl_bivector_get_x(loffs);
1833  cpl_vector * loffsy = cpl_bivector_get_y(loffs);
1834  cpl_table * tsort = NULL;
1835  cpl_propertylist * psort = NULL;
1836  int i;
1837 
1838 
1839  bug_if(cpl_vector_get_size(strehl) != ncube);
1840  bug_if(cpl_bivector_get_size(offs) != ncube);
1841  bug_if(fraction <= 0.0);
1842  bug_if(fraction > 1.0);
1843 
1844  if (mcube < ncube) {
1845  double strehlmin; /* Smallest to be used */
1846  int * pindex;
1847 
1848  tsort = cpl_table_new(ncube);
1849  psort = cpl_propertylist_new();
1850 
1851  /* Largest Strehl 1st */
1852  bug_if(cpl_propertylist_append_bool(psort, "LSTREHL", CPL_TRUE));
1853 
1854  bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(lstrehl),
1855  "LSTREHL"));
1856  bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(loffsx),
1857  "LOFFSX"));
1858  bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(loffsy),
1859  "LOFFSY"));
1860  bug_if(cpl_table_new_column(tsort, "INDEX", CPL_TYPE_INT));
1861 
1862  /* The indices for the imagelist */
1863  pindex = cpl_table_get_data_int(tsort, "INDEX");
1864  for (i = 0; i < ncube; i++) {
1865  pindex[i] = i;
1866  }
1867 
1868  bug_if(cpl_table_sort(tsort, psort));
1869  /* Strehl, offsets and the (imagelist) indices have been sorted */
1870 
1871  lcube = cpl_imagelist_new();
1872 
1873  /* Use the index column to create a sorted list of wrapped images */
1874  for (i = 0; i < mcube; i++) {
1875  const int j = pindex[i];
1876  const cpl_image * image = cpl_imagelist_get_const(cube, j);
1877 
1878  cpl_imagelist_set(lcube, (cpl_image*)image, i);
1879  }
1880  /* tsort no longer accessed */
1881 
1882  /* loffs and the imagelist must both have length mcube */
1883  bug_if(cpl_vector_set_size(loffsx, mcube));
1884  bug_if(cpl_vector_set_size(loffsy, mcube));
1885 
1886  strehlmin = cpl_vector_get(lstrehl, mcube - 1);
1887  cpl_vector_delete(lstrehl);
1888  lstrehl = NULL;
1889 
1890  cpl_msg_info(cpl_func, "%g%% (%d/%d) lucky mode at Strehl=%g",
1891  100.0*fraction, mcube, ncube, strehlmin);
1892  }
1893  ucube = lcube ? lcube : cube;
1894 
1895  self = naco_img_jitter_saa_center(ucube, loffs);
1896  any_if("Could not center and saa %d-cube", ncube);
1897 
1898  end_skip;
1899 
1900  if (lcube != NULL) {
1901  /* Unwrap the wrapped images */
1902  for (i = cpl_imagelist_get_size(lcube); i > 0;) {
1903  (void)cpl_imagelist_unset(lcube, --i);
1904  }
1905 
1906  cpl_imagelist_delete(lcube);
1907  }
1908 
1909  if (lstrehl != strehl)
1910  cpl_vector_delete(lstrehl);
1911 
1912  cpl_bivector_delete(loffs);
1913 
1914  if (tsort != NULL) {
1915  if (cpl_table_has_column(tsort, "LSTREHL"))
1916  (void)cpl_table_unwrap(tsort, "LSTREHL");
1917  if (cpl_table_has_column(tsort, "LOFFSX"))
1918  (void)cpl_table_unwrap(tsort, "LOFFSX");
1919  if (cpl_table_has_column(tsort, "LOFFSY"))
1920  (void)cpl_table_unwrap(tsort, "LOFFSY");
1921  cpl_table_delete(tsort);
1922  }
1923  cpl_propertylist_delete(psort);
1924 
1925  return self;
1926 }
1927 
1928 
1929 /*----------------------------------------------------------------------------*/
1937 /*----------------------------------------------------------------------------*/
1938 static
1939 cpl_error_code naco_img_jitter_find_strehl(const cpl_imagelist * self,
1940  const cpl_parameterlist * parlist,
1941  const irplib_framelist * objframes)
1942 {
1943 
1944  const int nobj = irplib_framelist_get_size(objframes);
1945  cpl_apertures * apert = NULL;
1946  cpl_vector * sigmas = NULL;
1947  double psigmas[] = {5.0, 2.0, 1.0, 0.5}; /* not modified */
1948  const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
1949  /* Use half of default value to support images windowed to 128 x 130 */
1950  /* FIXME: Adjust according to image size ? */
1951  const double rstar = 0.5 * IRPLIB_STREHL_STAR_RADIUS;
1952  const double rbgint = 0.5 * IRPLIB_STREHL_BACKGROUND_R1;
1953  const double rbgext = 0.5 * IRPLIB_STREHL_BACKGROUND_R2;
1954  cpl_size isigma = 0;
1955  int i;
1956 
1957 
1958  skip_if(rbgext <= rbgint);
1959 
1960  bug_if(cpl_imagelist_get_size(self) != nobj);
1961 
1962  /* Create the vector for the detection thresholds */
1963  sigmas = cpl_vector_wrap(nsigmas, psigmas);
1964 
1965  for (i = 0; i < nobj; i++) {
1966  const cpl_propertylist * plist
1968  const cpl_image * oimage = cpl_imagelist_get_const(self, i);
1969 
1970  const double pixscale = naco_pfits_get_pixscale(plist);
1971  const char * filter = naco_pfits_get_filter(plist);
1972  double lam = DBL_MAX; /* Avoid uninit warning */
1973  double dlam = DBL_MAX; /* Avoid uninit warning */
1974 
1975  double cent_x, cent_y;
1976  double strehl = 0, strehl_err, star_bg,star_peak, star_flux;
1977  double psf_peak, psf_flux, bg_noise;
1978  int iflux;
1979 
1980 
1981  skip_if(pixscale <= 0.0);
1982 
1983  irplib_check(naco_get_filter_infos(filter, &lam, &dlam),
1984  "Frame %d has no info for filter %s", 1+i, filter);
1985 
1986  cpl_apertures_delete(apert);
1987  apert = cpl_apertures_extract(oimage, sigmas, &isigma);
1988 
1989  any_if("No object found in combined image of frame %d", 1+i);
1990 
1991  bug_if(irplib_apertures_find_max_flux(apert, &iflux, 1));
1992 
1993  cent_x = cpl_apertures_get_centroid_x(apert, iflux);
1994  cent_y = cpl_apertures_get_centroid_y(apert, iflux);
1995 
1996  skip_if (naco_strehl_compute(oimage, parlist, RECIPE_STRING, lam, dlam,
1997  cent_x, cent_y, pixscale,
1998  &strehl, &strehl_err,
1999  &star_bg, &star_peak, &star_flux,
2000  &psf_peak, &psf_flux,
2001  &bg_noise));
2002  cpl_msg_info(cpl_func, "Image of frame %d/%d has strehl=%g at (x,y)"
2003  "=(%g,%g)", 1+i, nobj, strehl, cent_x, cent_y);
2004  }
2005 
2006  end_skip;
2007 
2008  (void)cpl_vector_unwrap(sigmas);
2009  cpl_apertures_delete(apert);
2010 
2011  return cpl_error_get_code();
2012 }
2013 
2014 
2015 
2016 /*----------------------------------------------------------------------------*/
2024 /*----------------------------------------------------------------------------*/
2025 static cpl_image * naco_img_jitter_saa_center(const cpl_imagelist * cube,
2026  cpl_bivector * offs)
2027 {
2028 
2029  const int ncube = cpl_imagelist_get_size(cube);
2030  cpl_image * self = NULL;
2031  const cpl_image * image;
2032  cpl_image ** combined = NULL;
2033  cpl_imagelist * ccube = NULL;
2034  const cpl_imagelist * ucube;
2035  cpl_vector * offsx = cpl_bivector_get_x(offs);
2036  cpl_vector * offsy = cpl_bivector_get_y(offs);
2037  double * doffsx = cpl_vector_get_data(offsx);
2038  double * doffsy = cpl_vector_get_data(offsy);
2039  const double med_x = cpl_vector_get_median_const(offsx);
2040  const double med_y = cpl_vector_get_median_const(offsy);
2041  double pos_x, pos_y;
2042  double minsqdist = DBL_MAX;
2043  int imin = -1;
2044  int i;
2045 
2046 
2047  bug_if(cpl_bivector_get_size(offs) != ncube);
2048 
2049  /* Find image with object closest to object median location */
2050  for (i = 0; i < ncube; i++) {
2051  const double x = cpl_vector_get(offsx, i);
2052  const double y = cpl_vector_get(offsy, i);
2053  const double sqdist
2054  = (x - med_x) * (x - med_x) + (y - med_y) * (y - med_y);
2055 
2056  if (sqdist < minsqdist) {
2057  minsqdist = sqdist;
2058  imin = i;
2059  }
2060  }
2061 
2062  cpl_msg_info(cpl_func, "Plane %d/%d has minimal object distance %g "
2063  "from median (x,y)=(%g,%g)", 1+imin, ncube,
2064  sqrt(minsqdist), med_x, med_y);
2065 
2066 
2067  if (imin > 0) {
2068  /* Wrap ccube around the images - with image imin first */
2069 
2070  ccube = cpl_imagelist_new();
2071 
2072  image = cpl_imagelist_get_const(cube, imin);
2073  bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, 0));
2074 
2075  for (i = 0; i < imin; i++) {
2076  image = cpl_imagelist_get_const(cube, i);
2077  bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, 1+i));
2078  }
2079  for (i = 1+imin; i < ncube; i++) {
2080  image = cpl_imagelist_get_const(cube, i);
2081  bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, i));
2082  }
2083 
2084  bug_if(cpl_imagelist_get_size(ccube) != ncube);
2085 
2086  /* Reorder offs accordingly */
2087  pos_x = cpl_vector_get(offsx, imin);
2088  pos_y = cpl_vector_get(offsy, imin);
2089 
2090  /* Move all offsets below imin 1 place up */
2091  memmove(doffsx + 1, doffsx, (size_t)imin * sizeof(*doffsx));
2092  memmove(doffsy + 1, doffsy, (size_t)imin * sizeof(*doffsy));
2093 
2094  /* Copy the imin offset to the 1st element */
2095  cpl_vector_set(offsx, 0, pos_x);
2096  cpl_vector_set(offsy, 0, pos_y);
2097  }
2098  ucube = ccube ? ccube : cube;
2099 
2100  /* Strange convention for the offsets :-(((((((((((((((( */
2101  cpl_vector_subtract_scalar(offsx, cpl_vector_get(offsx, 0));
2102  cpl_vector_subtract_scalar(offsy, cpl_vector_get(offsy, 0));
2103  cpl_vector_multiply_scalar(offsx, -1.0);
2104  cpl_vector_multiply_scalar(offsy, -1.0);
2105 
2106  combined = cpl_geom_img_offset_saa(ucube, offs, CPL_KERNEL_DEFAULT,
2107  0, 0, CPL_GEOM_FIRST, &pos_x, &pos_y);
2108 
2109  any_if("Could not shift and add %d-cube", ncube);
2110 
2111  cpl_msg_info(cpl_func, "Shift-and-added %d-cube, 1st pos=(%g,%g)",
2112  ncube, pos_x, pos_y);
2113 
2114  self = combined[0];
2115  cpl_image_delete(combined[1]);
2116  combined[0] = NULL;
2117  combined[1] = NULL;
2118 
2119  end_skip;
2120 
2121  if (combined != NULL) {
2122  cpl_image_delete(combined[0]);
2123  cpl_image_delete(combined[1]);
2124  cpl_free(combined);
2125  }
2126 
2127  if (ccube != NULL) {
2128  /* Unwrap the wrapped no-cube images */
2129  for (i = cpl_imagelist_get_size(ccube); i > 0;) {
2130  (void)cpl_imagelist_unset(ccube, --i);
2131  }
2132 
2133  cpl_imagelist_delete(ccube);
2134  }
2135 
2136  return self;
2137 }
cpl_imagelist * irplib_imagelist_load_framelist(const irplib_framelist *self, cpl_type pixeltype, int planenum, int extnum)
Load an imagelist from a framelist.
cpl_error_code naco_strehl_compute(const cpl_image *self, const cpl_parameterlist *parlist, const char *recipename, double lam, double dlam, double pos_x, double pos_y, double pixscale, double *pstrehl, double *pstrehl_err, double *pstar_bg, double *pstar_peak, double *pstar_flux, double *ppsf_peak, double *ppsf_flux, double *pbg_noise)
Compute the strehl ratio in an image.
Definition: naco_strehl.c:80
double naco_pfits_get_pixscale(const cpl_propertylist *self)
find out the pixel scale
Definition: naco_pfits.c:341
double naco_pfits_get_cumoffsety(const cpl_propertylist *self)
find out the cumulative offset in Y
Definition: naco_pfits.c:107
const char * naco_pfits_get_opti4_name(const cpl_propertylist *self)
find out the OPTI4.NAME key
Definition: naco_pfits.c:316
cpl_error_code naco_get_filter_infos(const char *f, double *lam, double *dlam)
Get the infos of one of the filters.
Definition: naco_utils.c:61
int naco_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: naco_dfs.c:62
cpl_error_code irplib_apertures_find_max_flux(const cpl_apertures *self, int *ind, int nfind)
Find the aperture(s) with the greatest flux.
#define IRPLIB_STREHL_STAR_RADIUS
The radius of the star, [Arcseconds].
Definition: irplib_strehl.h:81
double naco_pfits_get_cumoffsetx(const cpl_propertylist *self)
find out the cumulative offset in X
Definition: naco_pfits.c:95
cpl_error_code irplib_pfits_set_airmass(cpl_propertylist *self, const irplib_framelist *rawframes)
Update/Set the AIRMASS property.
Definition: irplib_pfits.c:373
irplib_framelist * irplib_framelist_extract_regexp(const irplib_framelist *self, const char *regexp, cpl_boolean invert)
Extract the frames with the given tag from a framelist.
void irplib_errorstate_dump_debug(unsigned self, unsigned first, unsigned last)
Dump a single CPL error at the CPL debug level.
Definition: irplib_utils.c:177
int naco_parameterlist_get_int(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO integer parameter.
const cpl_propertylist * irplib_framelist_get_propertylist_const(const irplib_framelist *self, int pos)
Get the propertylist of the specified frame in the framelist.
void irplib_framelist_empty(irplib_framelist *self)
Erase all frames from a framelist.
cpl_error_code irplib_dfs_save_image(cpl_frameset *allframes, const cpl_parameterlist *parlist, const cpl_frameset *usedframes, const cpl_image *image, cpl_type_bpp bpp, const char *recipe, const char *procat, const cpl_propertylist *applist, const char *remregexp, const char *pipe_id, const char *filename)
Save an image as a DFS-compliant pipeline product.
Definition: irplib_utils.c:208
cpl_error_code irplib_framelist_load_propertylist_all(irplib_framelist *self, int ind, const char *regexp, cpl_boolean invert)
Load the propertylists of all frames in the framelist.
double naco_parameterlist_get_double(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO parameter of type double.
cpl_boolean naco_parameterlist_get_bool(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO boolean parameter.
#define IRPLIB_STREHL_BACKGROUND_R2
The outer radius of the noise-estimation region, [Arcseconds].
Definition: irplib_strehl.h:99
const cpl_frame * irplib_framelist_get_const(const irplib_framelist *self, int pos)
Get the specified frame from the framelist.
const char * naco_pfits_get_opti3_name(const cpl_propertylist *self)
find out the OPTI3.NAME key
Definition: naco_pfits.c:304
void irplib_framelist_delete(irplib_framelist *self)
Deallocate an irplib_framelist with its frames and properties.
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.
const char * irplib_frameset_find_file(const cpl_frameset *self, const char *tag)
Find the filename with the given tag in a frame set.
#define IRPLIB_STREHL_BACKGROUND_R1
The inner radius of the noise-estimation region, [Arcseconds].
Definition: irplib_strehl.h:90
cpl_error_code irplib_framelist_load_propertylist(irplib_framelist *self, int pos, int ind, const char *regexp, cpl_boolean invert)
Load the propertylist of the specified frame in the framelist.
irplib_framelist * irplib_framelist_cast(const cpl_frameset *frameset)
Create an irplib_framelist from a cpl_framelist.
const char * naco_parameterlist_get_string(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO string parameter.
int irplib_flat_dark_bpm_calib(cpl_imagelist *ilist, const char *flat, const char *dark, const char *bpm)
Apply the calibration to the frames.
Definition: irplib_calib.c:578
int irplib_framelist_get_size(const irplib_framelist *self)
Get the size of a framelist.
const char * naco_pfits_get_filter(const cpl_propertylist *self)
find out the filter
Definition: naco_pfits.c:167