IIINSTRUMENT Pipeline Reference Manual 4.4.13
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
61static cpl_error_code naco_img_jitter_reject_objects(cpl_image *, double,
62 double);
63#endif
64
65static cpl_error_code naco_img_jitter_find_strehl(const cpl_imagelist *,
66 const cpl_parameterlist *,
67 const irplib_framelist *);
68
69static cpl_image * naco_img_jitter_saa_center(const cpl_imagelist *,
70 cpl_bivector *);
71
72static cpl_image * naco_img_jitter_saa_lucky(const cpl_imagelist *,
73 const cpl_vector *,
74 const cpl_bivector *, double);
75
76static cpl_image * naco_img_jitter_find_sky_cube(int, int, const cpl_array *,
77 const irplib_framelist *);
78
79static cpl_error_code naco_img_jitter_imagelist_wrap_nocube(cpl_imagelist *,
80 const cpl_array *,
81 cpl_imagelist *);
82
83
84static cpl_image * naco_img_jitter_combine_cube(cpl_table *, const cpl_imagelist *,
85 const cpl_propertylist *,
86 const cpl_parameterlist *, int);
87
88static cpl_error_code naco_img_jitter_check_cube(const cpl_imagelist *,
89 const cpl_image *);
90
91static 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
97static
98cpl_error_code naco_img_jitter_load_objimages(cpl_imagelist *, cpl_array *,
99 const irplib_framelist *,
100 const cpl_parameterlist *);
101
102static 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
112static cpl_image * naco_img_jitter_find_sky(cpl_propertylist *,
113 const cpl_imagelist *,
114 const cpl_imagelist *);
115static cpl_image ** naco_img_jitter_saa(cpl_imagelist *,
116 const irplib_framelist *,
117 const cpl_parameterlist *);
118static cpl_error_code naco_img_jitter_qc(cpl_propertylist *, cpl_propertylist *,
119 const irplib_framelist *,
120 const cpl_image *, cpl_boolean);
121static cpl_error_code naco_img_jitter_qc_apertures(cpl_propertylist *,
122 const irplib_framelist *,
123 const cpl_image *);
124static 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
133NACO_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/*----------------------------------------------------------------------------*/
175static 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/*----------------------------------------------------------------------------*/
294static 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",
329 irplib_framelist_get_size(obj),
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/*----------------------------------------------------------------------------*/
437static 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/*----------------------------------------------------------------------------*/
476static 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_ne(sscanf(sval, "%d %d %d %d", &sx, &sy, &mx, &my), 4,
522 "number(s) in string parameter (%s): \"%s\"",
523 CPL_XSTRINGIFY(NACO_PARAM_XCORR), sval);
524
525 combine_string = naco_parameterlist_get_string(parlist, RECIPE_STRING,
526 NACO_PARAM_COMBINE);
527
528 bug_if (combine_string == NULL);
529
530 if (combine_string[0] == 'u')
531 combine_mode = CPL_GEOM_UNION;
532 else if (combine_string[0] == 'f')
533 combine_mode = CPL_GEOM_FIRST;
534 else if (combine_string[0] == 'i')
535 combine_mode = CPL_GEOM_INTERSECT;
536 else
537 skip_if(1);
538
539 /* Number of rejected values in stacking */
540 sval = naco_parameterlist_get_string(parlist, RECIPE_STRING,
541 NACO_PARAM_REJ_HILO);
542 bug_if (sval == NULL);
543
544 skip_if_ne(sscanf(sval, "%d %d", &rej_low, &rej_high), 2,
545 "number(s) in string parameter (%s): \"%s\"",
546 CPL_XSTRINGIFY(NACO_PARAM_REJ_HILO), sval);
547
548 /* Get the offsets estimation of each input file pair */
549 cpl_msg_info(cpl_func, "Get the offsets estimation");
550 offsets_est = NULL;
551 if (offsets &&
552 offsets[0] != (char)0) {
553 /* A file has been provided on the command line */
554 offsets_est = cpl_bivector_read(offsets);
555 if (offsets_est == NULL ||
556 cpl_bivector_get_size(offsets_est) != nfiles) {
557 cpl_msg_error(cpl_func, "Cannot get offsets from %s",
558 offsets);
559 skip_if(1);
560 }
561 } else {
562 double * offsets_est_x;
563 double * offsets_est_y;
564 double offx0 = DBL_MAX; /* Avoid (false) uninit warning */
565 double offy0 = DBL_MAX; /* Avoid (false) uninit warning */
566 int i;
567
568 /* Get the offsets from the header */
569 offsets_est = cpl_bivector_new(nfiles);
570 offsets_est_x = cpl_bivector_get_x_data(offsets_est);
571 offsets_est_y = cpl_bivector_get_y_data(offsets_est);
572 for (i=0 ; i < nfiles ; i++) {
573 const cpl_propertylist * plist
574 = irplib_framelist_get_propertylist_const(objframes, i);
575
576 /* X and Y offsets */
577 if (i == 0) {
578 offx0 = naco_pfits_get_cumoffsetx(plist);
579 offy0 = naco_pfits_get_cumoffsety(plist);
580 }
581
582 /* Subtract the first offset to all offsets */
583 offsets_est_x[i] = offx0 - naco_pfits_get_cumoffsetx(plist);
584 offsets_est_y[i] = offy0 - naco_pfits_get_cumoffsety(plist);
585
586 bug_if(0);
587 }
588 }
589
590 /* Read the provided objects file if provided */
591 if (objects &&
592 objects[0] != (char)0) {
593 cpl_msg_info(cpl_func, "Get the user provided correlation objects");
594 /* A file has been provided on the command line */
595 objs = cpl_bivector_read(objects);
596 if (objs==NULL) {
597 cpl_msg_error(cpl_func, "Cannot get objects from %s",
598 objects);
599 skip_if (1);
600 }
601 }
602
603 /* Create the vector for the detection thresholds */
604 sigmas = cpl_vector_wrap(nsigmas, psigmas);
605
606 /* Recombine the images */
607 cpl_msg_info(cpl_func, "Recombine the images set");
608 combined = cpl_geom_img_offset_combine(imlist, offsets_est, 1, objs,
609 sigmas, NULL, sx, sy, mx, my,
610 rej_low, rej_high, combine_mode);
611
612 skip_if (combined == NULL);
613
614 end_skip;
615
616 cpl_bivector_delete(offsets_est);
617 cpl_bivector_delete(objs);
618 cpl_vector_unwrap(sigmas);
619
620 return combined;
621}
622
623/*----------------------------------------------------------------------------*/
633/*----------------------------------------------------------------------------*/
634static cpl_error_code naco_img_jitter_qc(cpl_propertylist * qclist,
635 cpl_propertylist * paflist,
636 const irplib_framelist * objframes,
637 const cpl_image * combined,
638 cpl_boolean drop_wcs)
639{
640 cpl_errorstate cleanstate = cpl_errorstate_get();
641 const cpl_propertylist * reflist
642 = irplib_framelist_get_propertylist_const(objframes, 0);
643 const char * sval;
644
645
646 bug_if(combined == NULL);
647
648 bug_if(cpl_propertylist_copy_property_regexp(paflist, reflist, "^("
649 NACO_PFITS_REGEXP_JITTER_PAF
650 ")$", 0));
651
652 if (naco_img_jitter_qc_apertures(qclist, objframes, combined)) {
653 naco_error_reset("Could not compute all QC parameters");
654 }
655
656 sval = naco_pfits_get_filter(reflist);
657 if (cpl_error_get_code()) {
658 naco_error_reset("Could not get FITS key:");
659 } else {
660 cpl_propertylist_append_string(qclist, "ESO QC FILTER OBS", sval);
661 }
662 sval = naco_pfits_get_opti3_name(reflist);
663 if (cpl_error_get_code()) {
664 naco_error_reset("Could not get FITS key:");
665 } else {
666 cpl_propertylist_append_string(qclist, "ESO QC FILTER NDENS", sval);
667 }
668 sval = naco_pfits_get_opti4_name(reflist);
669 if (cpl_error_get_code()) {
670 naco_error_reset("Could not get FITS key:");
671 } else {
672 cpl_propertylist_append_string(qclist, "ESO QC FILTER POL", sval);
673 }
674
675 bug_if(0);
676
677 bug_if (cpl_propertylist_append(paflist, qclist));
678
679 if (drop_wcs) {
680 cpl_propertylist * pcopy = cpl_propertylist_new();
681 const cpl_error_code error
682 = cpl_propertylist_copy_property_regexp(pcopy, reflist, "^("
683 IRPLIB_PFITS_WCS_REGEXP
684 ")$", 0);
685 if (!error && cpl_propertylist_get_size(pcopy) > 0) {
686 cpl_msg_warning(cpl_func, "Combined image will have no WCS "
687 "coordinates");
688 }
689 cpl_propertylist_delete(pcopy);
690
691 bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
692 NACO_PFITS_REGEXP_JITTER_COPY
693 ")$", 0));
694 } else {
695 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
696 IRPLIB_PFITS_WCS_REGEXP "|"
697 NACO_PFITS_REGEXP_JITTER_COPY
698 ")$", 0));
699 }
700
701 if (cpl_propertylist_has(qclist, "AIRMASS"))
702 bug_if (irplib_pfits_set_airmass(qclist, objframes));
703
704 end_skip;
705
706 return cpl_error_get_code();
707}
708
709/*----------------------------------------------------------------------------*/
717/*----------------------------------------------------------------------------*/
718static cpl_error_code naco_img_jitter_qc_apertures(cpl_propertylist * qclist,
719 const irplib_framelist *
720 objframes,
721 const cpl_image * combined)
722{
723 const cpl_propertylist * reflist
724 = irplib_framelist_get_propertylist_const(objframes, 0);
725
726 cpl_apertures * aperts = NULL;
727 cpl_bivector * fwhms = NULL;
728 cpl_vector * fwhms_sum = NULL;
729 cpl_vector * sigmas = NULL;
730 double * fwhms_x;
731 double * fwhms_y;
732 double * fwhms_sum_data;
733 int nb_val, nb_good;
734 double f_min, f_max;
735 double psigmas[] = {5.0, 2.0, 1.0, 0.5}; /* Not modified */
736 const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
737 cpl_size isigma;
738 int i;
739
740 const double pixscale = naco_pfits_get_pixscale(reflist);
741 /* FIXME: Some hard-coded constants */
742 const double seeing_min_arcsec = 0.1;
743 const double seeing_max_arcsec = 5.0;
744 const double seeing_fwhm_var = 0.2;
745
746 double iq, fwhm_pix, fwhm_arcsec;
747
748
749 /* Detect apertures */
750 cpl_msg_info(cpl_func, "Detecting apertures using %d sigma-levels "
751 "ranging from %g down to %g", nsigmas, psigmas[0],
752 psigmas[nsigmas-1]);
753
754 /* pixscale could be mising */
755 skip_if( pixscale <= 0.0 );
756 bug_if( seeing_min_arcsec < 0.0);
757
758 /* Create the vector for the detection thresholds. (Not modified) */
759 sigmas = cpl_vector_wrap(nsigmas, psigmas);
760
761 aperts = cpl_apertures_extract(combined, sigmas, &isigma);
762 if (aperts == NULL) {
763 cpl_msg_warning(cpl_func, "Could not detect any apertures in combined "
764 "image");
765 skip_if(1);
766 }
767 bug_if(0);
768
769 /* Compute the FHWM of the detected apertures */
770 CPL_DIAG_PRAGMA_PUSH_IGN(-Wdeprecated-declarations);
771 fwhms = cpl_apertures_get_fwhm(combined, aperts);
772 CPL_DIAG_PRAGMA_POP;
773
774 if (fwhms == NULL) {
775 cpl_msg_warning(cpl_func, "Could not compute any FWHMs of the "
776 "apertures in the combined image");
777 skip_if(1);
778 }
779 bug_if(0);
780 cpl_apertures_delete(aperts);
781 aperts = NULL;
782
783 /* Access the data */
784 nb_val = cpl_bivector_get_size(fwhms);
785 fwhms_x = cpl_bivector_get_x_data(fwhms);
786 fwhms_y = cpl_bivector_get_y_data(fwhms);
787
788 /* Get the number of good values */
789 nb_good = 0;
790 for (i=0 ; i < nb_val ; i++) {
791 if (fwhms_x[i] <= 0.0 || fwhms_y[i] <= 0.0) continue;
792 fwhms_x[nb_good] = fwhms_x[i];
793 fwhms_y[nb_good] = fwhms_y[i];
794 nb_good++;
795 }
796
797 cpl_msg_info(cpl_func, "Detected %d (%d) apertures at sigma=%g",
798 nb_good, nb_val, psigmas[isigma]);
799
800 skip_if_lt (nb_good, 1, "aperture with a FWHM");
801
802 nb_val = nb_good;
803 /* This resizing is not really needed */
804 bug_if(cpl_vector_set_size(cpl_bivector_get_x(fwhms), nb_val));
805 bug_if(cpl_vector_set_size(cpl_bivector_get_y(fwhms), nb_val));
806 fwhms_x = cpl_bivector_get_x_data(fwhms);
807 fwhms_y = cpl_bivector_get_y_data(fwhms);
808
809 /* Get the good values */
810 fwhms_sum = cpl_vector_new(nb_good);
811 fwhms_sum_data = cpl_vector_get_data(fwhms_sum);
812 for (i=0; i < nb_good; i++) {
813 fwhms_sum_data[i] = fwhms_x[i] + fwhms_y[i];
814 }
815 /* Compute the fwhm as the median of the average of the FHWMs in x and y */
816 fwhm_pix = 0.5 * cpl_vector_get_median(fwhms_sum);
817
818 bug_if(cpl_propertylist_append_double(qclist, "ESO QC FWHM PIX", fwhm_pix));
819
820 fwhm_arcsec = fwhm_pix * pixscale;
821
822 bug_if(cpl_propertylist_append_double(qclist, "ESO QC FWHM ARCSEC",
823 fwhm_arcsec));
824
825 /* iq is the median of the (fwhm_x+fwhm_y)/2 */
826 /* of the good stars */
827
828 /* Compute f_min and f_max */
829 f_min = seeing_min_arcsec / pixscale;
830 f_max = seeing_max_arcsec / pixscale;
831
832 /* Sum the the good values */
833 nb_good = 0;
834 for (i=0 ; i < nb_val ; i++) {
835 const double fx = fwhms_x[i];
836 const double fy = fwhms_y[i];
837
838 if (fx <= f_min || f_max <= fx || fy <= f_min || f_max <= fy) continue;
839 if (fabs(fx-fy) >= 0.5 * (fx + fy) * seeing_fwhm_var) continue;
840
841 fwhms_sum_data[nb_good] = fx + fy;
842 nb_good++;
843 }
844
845 cpl_msg_info(cpl_func, "%d of the apertures have FWHMs within the range "
846 "%g to %g and eccentricity within %g", nb_good, f_min, f_max,
847 seeing_fwhm_var);
848
849 skip_if_lt (nb_good, 1, "aperture with a good FWHM");
850
851 bug_if(cpl_vector_set_size(fwhms_sum, nb_good));
852
853 /* Compute the fwhm */
854 iq = pixscale * 0.5 * cpl_vector_get_median(fwhms_sum);
855
856 bug_if(cpl_propertylist_append_double(qclist, "ESO QC IQ", iq));
857
858 end_skip;
859
860 cpl_vector_delete(fwhms_sum);
861 cpl_bivector_delete(fwhms);
862 cpl_vector_unwrap(sigmas);
863 cpl_apertures_delete(aperts);
864
865 return cpl_error_get_code();
866}
867
868/*----------------------------------------------------------------------------*/
881/*----------------------------------------------------------------------------*/
882static cpl_error_code naco_img_jitter_save(cpl_frameset * set,
883 const cpl_parameterlist * parlist,
884 const cpl_propertylist * qclist,
885 const cpl_propertylist * paflist,
886 const cpl_imagelist * objimages,
887 const cpl_image * combined,
888 const cpl_image * contrib,
889 const cpl_table * cubetable)
890{
891
892 const cpl_boolean is_cube = cpl_table_get_ncol(cubetable) > 0
893 ? CPL_TRUE : CPL_FALSE;
894 const char * procatg = is_cube ? NACO_IMG_JITTER_CUBE
895 : NACO_IMG_JITTER_COMB;
896 cpl_propertylist * xtlist = cpl_propertylist_new();
897 const cpl_boolean save_cube =
898 naco_parameterlist_get_bool(parlist, RECIPE_STRING,
899 NACO_PARAM_SAVECUBE);
900
901 bug_if (0);
902 bug_if (contrib == NULL);
903
904 /* Write the FITS file */
905 skip_if (irplib_dfs_save_image(set, parlist, set, combined,
906 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
907 procatg, qclist, NULL,
908 naco_pipe_id, RECIPE_STRING CPL_DFS_FITS));
909
910 bug_if(cpl_propertylist_append_string(xtlist, "EXTNAME",
911 "Contribution Map"));
912 skip_if (cpl_image_save(contrib, RECIPE_STRING CPL_DFS_FITS,
913 CPL_BPP_16_SIGNED, xtlist, CPL_IO_EXTEND));
914
915 if (is_cube) {
916
917 bug_if(cpl_propertylist_update_string(xtlist, "EXTNAME",
918 "Plane Properties"));
919 skip_if (cpl_table_save(cubetable, NULL, xtlist,
920 RECIPE_STRING CPL_DFS_FITS, CPL_IO_EXTEND));
921 }
922
923 if (save_cube) {
924 bug_if(cpl_propertylist_update_string(xtlist, "EXTNAME",
925 "Corrected object images"));
926 skip_if (cpl_imagelist_save(objimages, RECIPE_STRING CPL_DFS_FITS,
927 CPL_BPP_IEEE_FLOAT, xtlist, CPL_IO_EXTEND));
928 }
929
930#ifdef NACO_SAVE_PAF
931 skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, paflist,
932 RECIPE_STRING CPL_DFS_PAF));
933#else
934 bug_if(paflist == NULL);
935#endif
936
937 end_skip;
938
939 cpl_propertylist_delete(xtlist);
940
941 return cpl_error_get_code();
942
943}
944
945/*----------------------------------------------------------------------------*/
957/*----------------------------------------------------------------------------*/
958static
959cpl_error_code naco_img_jitter_load_objimages(cpl_imagelist * objlist,
960 cpl_array * iscube,
961 const irplib_framelist * self,
962 const cpl_parameterlist * parlist)
963{
964 const int nframes = irplib_framelist_get_size(self);
965 cpl_image * image = NULL;
966 int i;
967
968 bug_if(objlist == NULL);
969 bug_if(self == NULL);
970 bug_if(iscube == NULL);
971 bug_if(parlist == NULL);
972
973 for (i=0; i < nframes; i++, image = NULL) {
974 const char * filename
975 = cpl_frame_get_filename(irplib_framelist_get_const(self, i));
976 const cpl_propertylist * plist
977 = irplib_framelist_get_propertylist_const(self, i);
978 const int naxis3 = cpl_propertylist_has(plist, "NAXIS3") ?
979 cpl_propertylist_get_int(plist, "NAXIS3") : 1;
980
981
982 if (naxis3 > 2) { /* Real cube mode has at least two frames + sum */
983
984 bug_if(cpl_array_set_int(iscube, i, 1));
985
986 /* EPompei 2009-11-13:
987 The last frame in the cube is the sum of all the previous ones.
988 This is not DICB compliant and may change.
989 See also the NACO user manual.
990 */
991
992 image = cpl_image_load(filename, CPL_TYPE_FLOAT, naxis3-1, EXT0);
993
994 any_if("Could not load %d-cube-sum from frame %d/%d, file=%s",
995 naxis3-1, i+1, nframes, filename);
996
997 } else {
998 image = cpl_image_load(filename, CPL_TYPE_FLOAT, 0, EXT0);
999
1000 any_if("Could not load FITS-image from extension %d in frame "
1001 "%d/%d, file=%s", EXT0, i+1, nframes, filename);
1002
1003 }
1004 bug_if(cpl_imagelist_set(objlist, image, i));
1005 }
1006
1007 end_skip;
1008
1009 cpl_image_delete(image);
1010
1011 return cpl_error_get_code();
1012
1013}
1014
1015/*----------------------------------------------------------------------------*/
1023/*----------------------------------------------------------------------------*/
1024static cpl_error_code naco_img_jitter_check_cube(const cpl_imagelist * self,
1025 const cpl_image * sum)
1026{
1027 cpl_image * accu = cpl_imagelist_collapse_create(self);
1028 double err;
1029
1030 cpl_image_subtract(accu, sum);
1031
1032 err = cpl_image_get_absflux(accu);
1033
1034 if (err > 0.0) {
1035 err /= cpl_image_get_size_x(sum) * cpl_image_get_size_y(sum);
1036
1037 cpl_msg_info(cpl_func, "Average per-pixel error in final sum frame "
1038 "in %d-cube: %g", (int)cpl_imagelist_get_size(self), err);
1039 }
1040
1041 cpl_image_delete(accu);
1042
1043 return cpl_error_get_code();
1044}
1045
1046
1047/*----------------------------------------------------------------------------*/
1059/*----------------------------------------------------------------------------*/
1060static cpl_error_code naco_img_jitter_do_cube(cpl_imagelist * self,
1061 cpl_table * cubetable,
1062 cpl_propertylist * qclist,
1063 const cpl_array * iscube,
1064 const irplib_framelist * obj,
1065 const cpl_parameterlist * parlist)
1066{
1067
1068 const int nframes = irplib_framelist_get_size(obj);
1069 cpl_imagelist * onelist = NULL;
1070 cpl_image * sum = NULL;
1071 cpl_image * onesky = NULL;
1072 const int nskyplane = naco_parameterlist_get_int(parlist,
1073 RECIPE_STRING,
1074 NACO_PARAM_SKYPLANE);
1075 cpl_vector * skymedians = cpl_vector_new(nframes);
1076 int nsky = 0;
1077 int i;
1078
1079 bug_if(self == NULL);
1080 bug_if(cubetable == NULL);
1081 bug_if(qclist == NULL);
1082 bug_if(obj == NULL);
1083 bug_if(parlist == NULL);
1084 bug_if(nframes != cpl_array_get_size(iscube));
1085 bug_if(nframes != cpl_imagelist_get_size(self));
1086
1087
1088 for (i=0; i < nframes; i++) {
1089 int is_invalid = 0;
1090
1091 (void)cpl_array_get_int(iscube, i, &is_invalid);
1092
1093 if (!is_invalid) {
1094 const char * filename
1095 = cpl_frame_get_filename(irplib_framelist_get_const(obj, i));
1096 const cpl_propertylist * plist
1097 = irplib_framelist_get_propertylist_const(obj, i);
1098 double skymedian;
1099 int naxis3;
1100
1101 /* Estimate the sky from nearby cube(s) */
1102 cpl_image_delete(onesky);
1103 onesky = naco_img_jitter_find_sky_cube(i, nskyplane, iscube, obj);
1104 any_if("Could not estimate sky for frame %d/%d, file=%s",
1105 i+1, nframes, filename);
1106
1107 skymedian = cpl_image_get_median(onesky);
1108#ifdef NACO_IMG_JITTER_DEVELOPMENT
1109 if (onelist == NULL) {
1110
1111 /* FIXME: Compute from all cube-sky frames ? */
1112 /* Get the background value */
1113 bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD",
1114 skymedian));
1115
1116 cpl_image_save(onesky, "Sky.fits", CPL_BPP_IEEE_FLOAT, NULL,
1117 CPL_IO_CREATE);
1118 } else {
1119 cpl_image_save(onesky, "Sky.fits", CPL_BPP_IEEE_FLOAT, NULL,
1120 CPL_IO_EXTEND);
1121 }
1122#endif
1123 cpl_imagelist_delete(onelist);
1124 onelist = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
1125
1126 any_if("Could not load cube from frame %d/%d, file=%s",
1127 i+1, nframes, filename);
1128
1129 naxis3 = cpl_imagelist_get_size(onelist);
1130
1131 cpl_msg_info(cpl_func, "Processing %d-cube from frame %d/%d, "
1132 "file=%s. Median of sky-estimate: %g",
1133 naxis3-1, i+1, nframes, filename, skymedian);
1134 cpl_vector_set(skymedians, nsky++, skymedian);
1135
1136 bug_if(naxis3 < 3);
1137
1138 sum = cpl_imagelist_unset(onelist, naxis3-1);
1139
1140 bug_if(naco_img_jitter_check_cube(onelist, sum));
1141
1142 skip_if(cpl_imagelist_subtract_image(onelist, onesky));
1143
1144 cpl_image_delete(sum);
1145 sum = naco_img_jitter_combine_cube(cubetable, onelist, plist,
1146 parlist, i);
1147 any_if("Could not combine %d images from frame %d/%d, file=%s",
1148 naxis3-1, i+1, nframes, filename);
1149
1150 bug_if(cpl_imagelist_set(self, sum, i));
1151 sum = NULL;
1152 }
1153 }
1154
1155 if (nsky > 1) {
1156 double skystdev, skymean;
1157
1158 bug_if(cpl_vector_set_size(skymedians, nsky));
1159
1160 skymean = cpl_vector_get_mean(skymedians);
1161 skystdev = cpl_vector_get_stdev(skymedians);
1162
1163 cpl_msg_info(cpl_func, "Mean and stdev of %d medians of sky estimates: "
1164 "%g %g", nsky, skymean, skystdev);
1165
1166 bug_if(cpl_propertylist_append_double(qclist, "ESO QC SKY STDEV",
1167 skystdev));
1168 }
1169
1170 end_skip;
1171
1172 cpl_imagelist_delete(onelist);
1173 cpl_image_delete(sum);
1174 cpl_image_delete(onesky);
1175 cpl_vector_delete(skymedians);
1176
1177 return cpl_error_get_code();
1178}
1179
1180
1181
1182/*----------------------------------------------------------------------------*/
1193/*----------------------------------------------------------------------------*/
1194static
1195cpl_image * naco_img_jitter_combine_cube(cpl_table * cubetable,
1196 const cpl_imagelist * cube,
1197 const cpl_propertylist * plist,
1198 const cpl_parameterlist * parlist,
1199 int idx)
1200{
1201
1202 cpl_errorstate prestate = cpl_errorstate_get();
1203 cpl_image * self = NULL;
1204 const int ncube = cpl_imagelist_get_size(cube);
1205 cpl_image ** combined = NULL;
1206 cpl_apertures * apert = NULL;
1207 cpl_bivector * offs = cpl_bivector_new(ncube);
1208 cpl_vector * offsx = cpl_bivector_get_x(offs);
1209 cpl_vector * offsy = cpl_bivector_get_y(offs);
1210 cpl_vector * sigmas = NULL;
1211 cpl_vector * vstrehl = cpl_vector_new(ncube);
1212 double psigmas[] = {5.0, 2.0, 1.0, 0.5}; /* not modified */
1213 const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
1214 /* Use half of default value to support images windowed to 128 x 130 */
1215 /* FIXME: Adjust according to image size ? */
1216 const double rstar = 0.5 * IRPLIB_STREHL_STAR_RADIUS;
1217 const double rbgint = 0.5 * IRPLIB_STREHL_BACKGROUND_R1;
1218 const double rbgext = 0.5 * IRPLIB_STREHL_BACKGROUND_R2;
1219 const double pixscale = naco_pfits_get_pixscale(plist);
1220 const double lucky = naco_parameterlist_get_double(parlist,
1221 RECIPE_STRING,
1222 NACO_PARAM_LUCK_STR);
1223 const char * filter = naco_pfits_get_filter(plist);
1224 double lam = DBL_MAX; /* Avoid uninit warning */
1225 double dlam = DBL_MAX; /* Avoid uninit warning */
1226 cpl_size isigma = 0;
1227 const int ncubetable = cpl_table_get_nrow(cubetable);
1228 int icubetable; /* 1st table row to write to */
1229 int i;
1230
1231
1232 skip_if(rbgext <= rbgint);
1233 skip_if(pixscale <= 0.0);
1234
1235 irplib_check(naco_get_filter_infos(filter, &lam, &dlam),
1236 "Frame has no info for filter %s", filter);
1237
1238 cpl_msg_debug(cpl_func, "Frame %d has pixelscale [Arcsecond/pixel]=%g, "
1239 "Central wavelength [micron]=%g, Filter bandwidth "
1240 "[micron]=%g", 1+idx, pixscale, lam, dlam);
1241 cpl_msg_debug(cpl_func, "Frame %d assumes Rstar [pixel]=%g, Rint "
1242 "[pixel]=%g, Rext [pixel]=%g", 1+idx, rstar/pixscale,
1243 rbgint/pixscale, rbgext/pixscale);
1244
1245 if (cpl_table_get_ncol(cubetable) == 0) {
1246 cpl_table_new_column(cubetable, "Frame", CPL_TYPE_INT);
1247 cpl_table_new_column(cubetable, "Plane", CPL_TYPE_INT);
1248 cpl_table_new_column(cubetable, "XCentroid", CPL_TYPE_DOUBLE);
1249 cpl_table_new_column(cubetable, "YCentroid", CPL_TYPE_DOUBLE);
1250 cpl_table_set_column_unit(cubetable, "XCentroid", "pixel");
1251 cpl_table_set_column_unit(cubetable, "YCentroid", "pixel");
1252 cpl_table_new_column(cubetable, "Strehl", CPL_TYPE_DOUBLE);
1253 cpl_table_new_column(cubetable, "Strehl_Error", CPL_TYPE_DOUBLE);
1254 cpl_table_new_column(cubetable, "Star_Background", CPL_TYPE_DOUBLE);
1255 cpl_table_new_column(cubetable, "Star_Peak", CPL_TYPE_DOUBLE);
1256 cpl_table_new_column(cubetable, "Star_Flux", CPL_TYPE_DOUBLE);
1257 cpl_table_new_column(cubetable, "PSF_Peak_per_Flux", CPL_TYPE_DOUBLE);
1258 cpl_table_set_column_unit(cubetable, "PSF_Peak_per_Flux", "unitless");
1259 cpl_table_new_column(cubetable, "Background_Noise", CPL_TYPE_DOUBLE);
1260 cpl_table_set_size(cubetable, ncube);
1261 icubetable = 0;
1262 } else {
1263 cpl_table_set_size(cubetable, ncubetable + ncube);
1264 icubetable = ncubetable;
1265 }
1266
1267 /* Create the vector for the detection thresholds */
1268 sigmas = cpl_vector_wrap(nsigmas, psigmas);
1269 for (i = 0; i < ncube; i++) {
1270 const cpl_image * one = cpl_imagelist_get_const(cube, i);
1271 double cent_x, cent_y;
1272 double strehl, strehl_err, star_bg,star_peak, star_flux;
1273 double psf_peak, psf_flux, bg_noise;
1274 int iflux;
1275
1276
1277 cpl_apertures_delete(apert);
1278 apert = cpl_apertures_extract(one, sigmas, &isigma);
1279
1280 any_if("No object found in image %d/%d in frame %d", i+1, ncube, 1+idx);
1281
1282 bug_if(irplib_apertures_find_max_flux(apert, &iflux, 1));
1283
1284 cent_x = cpl_apertures_get_centroid_x(apert, iflux);
1285 cent_y = cpl_apertures_get_centroid_y(apert, iflux);
1286 cpl_vector_set(offsx, i, cent_x);
1287 cpl_vector_set(offsy, i, cent_y);
1288
1289 cpl_msg_debug(cpl_func, "Detected %d/%d sigma=%g-aperture(s) (x,y)"
1290 "=(%g,%g) (%d/%d) in %d/%d-image in frame %d", iflux,
1291 (int)cpl_apertures_get_size(apert), psigmas[isigma],
1292 cent_x, cent_y, 1+(int)isigma, nsigmas, 1+i, ncube,
1293 1+idx);
1294
1295 cpl_table_set_int(cubetable, "Frame", i+icubetable, 1+idx);
1296 cpl_table_set_int(cubetable, "Plane", i+icubetable, 1+i);
1297 cpl_table_set_double(cubetable, "XCentroid", i+icubetable, cent_x);
1298 cpl_table_set_double(cubetable, "YCentroid", i+icubetable, cent_y);
1299
1300
1301 if (naco_strehl_compute(one, parlist, RECIPE_STRING, lam, dlam,
1302 cent_x, cent_y, pixscale,
1303 &strehl, &strehl_err,
1304 &star_bg, &star_peak, &star_flux,
1305 &psf_peak, &psf_flux,
1306 &bg_noise)) {
1307 cpl_msg_info(cpl_func, "Could not compute strehl for "
1308 "image %d in frame %d", 1+i, 1+idx);
1309 cpl_errorstate_dump(prestate, CPL_FALSE,
1310 irplib_errorstate_dump_debug);
1311 cpl_errorstate_set(prestate);
1312
1313 cpl_table_set_invalid(cubetable, "Strehl", i+icubetable);
1314 cpl_table_set_invalid(cubetable, "Strehl_Error", i+icubetable);
1315 cpl_table_set_invalid(cubetable, "Star_Background", i+icubetable);
1316 cpl_table_set_invalid(cubetable, "Star_Peak", i+icubetable);
1317 cpl_table_set_invalid(cubetable, "Star_Flux", i+icubetable);
1318 cpl_table_set_invalid(cubetable, "PSF_Peak_per_Flux", i+icubetable);
1319 cpl_table_set_invalid(cubetable, "Background_Noise", i+icubetable);
1320 cpl_vector_set(vstrehl, i, 0.0);
1321
1322 } else {
1323 cpl_vector_set(vstrehl, i, strehl);
1324 cpl_table_set_double(cubetable, "Strehl", i+icubetable, strehl);
1325 cpl_table_set_double(cubetable, "Strehl_Error", i+icubetable,
1326 strehl_err);
1327 cpl_table_set_double(cubetable, "Star_Background", i+icubetable,
1328 star_bg);
1329 cpl_table_set_double(cubetable, "Star_Peak", i+icubetable,
1330 star_peak);
1331 cpl_table_set_double(cubetable, "Star_Flux", i+icubetable,
1332 star_flux);
1333 cpl_table_set_double(cubetable, "PSF_Peak_per_Flux", i+icubetable,
1334 psf_peak/psf_flux);
1335 cpl_table_set_double(cubetable, "Background_Noise", i+icubetable,
1336 bg_noise);
1337 }
1338 }
1339
1340 self = naco_img_jitter_saa_lucky(cube, vstrehl, offs, lucky);
1341
1342 end_skip;
1343
1344 if (combined != NULL) {
1345 cpl_image_delete(combined[0]);
1346 cpl_free(combined);
1347 }
1348
1349 cpl_bivector_delete(offs);
1350 (void)cpl_vector_unwrap(sigmas);
1351 cpl_apertures_delete(apert);
1352 cpl_vector_delete(vstrehl);
1353
1354 cpl_ensure(self != NULL, cpl_error_get_code(), NULL);
1355
1356 return self;
1357
1358}
1359
1360
1361/*----------------------------------------------------------------------------*/
1371/*----------------------------------------------------------------------------*/
1372static cpl_image * naco_img_jitter_find_sky_cube(int isky, int nskyplane,
1373 const cpl_array * iscube,
1374 const irplib_framelist * obj)
1375{
1376
1377 cpl_image * self = NULL;
1378 const int nframes = irplib_framelist_get_size(obj);
1379 cpl_imagelist * belowcube = NULL;
1380 cpl_imagelist * abovecube = NULL;
1381 cpl_imagelist * skycube = NULL;
1382 cpl_imagelist * mycube = NULL;
1383 cpl_image * mysky = NULL;
1384 cpl_mask * fillbpm = NULL;
1385 int is_invalid = 0;
1386 int ibelow, iabove;
1387 int i;
1388
1389 bug_if(isky < 0);
1390 bug_if(isky >= nframes);
1391 bug_if(nframes != cpl_array_get_size(iscube));
1392 if (nskyplane > 0) skip_if_lt(nskyplane, 3, "sky planes for median");
1393
1394
1395 (void)cpl_array_get_int(iscube, isky, &is_invalid);
1396
1397 bug_if(is_invalid); /* isky must be a cube */
1398
1399 /* Find 1st cube below isky */
1400 for (i = isky - 1; i >= 0; i++) {
1401
1402 (void)cpl_array_get_int(iscube, i, &is_invalid);
1403
1404 if (!is_invalid) break;
1405 }
1406
1407 ibelow = i; /* -1 means no cube below */
1408
1409 /* Find 1st cube above isky */
1410 for (i = isky + 1; i < nframes; i++) {
1411
1412 (void)cpl_array_get_int(iscube, i, &is_invalid);
1413
1414 if (!is_invalid) break;
1415 }
1416
1417 iabove = i; /* nframes means no cube above */
1418
1419 cpl_msg_info(cpl_func, "Estimating sky for cube %d/%d via cubes %d and %d",
1420 1+isky, nframes, 1+ibelow, 1+iabove);
1421
1422
1423 if (ibelow >= 0) {
1424 const char * filename
1425 = cpl_frame_get_filename(irplib_framelist_get_const(obj, ibelow));
1426
1427 if (nskyplane > 0) {
1428 /* Load the last nskyplane frames */
1429 const cpl_propertylist * plist
1430 = irplib_framelist_get_propertylist_const(obj, ibelow);
1431 /* Ignore the last sum plane */
1432 const int istop = irplib_pfits_get_int(plist, "NAXIS3") - 2;
1433 const int istart = NACO_MAX(0, istop - nskyplane + 1);
1434
1435 skip_if_lt(istop - istart, 2, "sky planes for median");
1436
1437 belowcube = cpl_imagelist_new();
1438
1439 for (i = istart; i <= istop; i++) {
1440 self = cpl_image_load(filename, CPL_TYPE_FLOAT, i, EXT0);
1441
1442 any_if("Could not load plane %d from frame %d/%d, file=%s",
1443 1+i, 1+ibelow, nframes, filename);
1444
1445 bug_if(cpl_imagelist_set(belowcube, self, i - istart));
1446 }
1447
1448 } else {
1449 int naxis3;
1450
1451 belowcube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
1452
1453 any_if("Could not load cube from frame %d/%d, file=%s",
1454 1+ibelow, nframes, filename);
1455
1456 naxis3 = cpl_imagelist_get_size(belowcube);
1457
1458 bug_if(naxis3 < 3);
1459
1460 cpl_image_delete(cpl_imagelist_unset(belowcube, naxis3-1));
1461
1462 }
1463
1464 }
1465
1466 if (iabove < nframes) {
1467 const char * filename
1468 = cpl_frame_get_filename(irplib_framelist_get_const(obj, iabove));
1469
1470 if (nskyplane > 0) {
1471 /* Load the first nskyplane frames */
1472 const cpl_propertylist * plist
1473 = irplib_framelist_get_propertylist_const(obj, iabove);
1474 const int istart = 0;
1475 /* Ignore the last sum plane */
1476 const int istop = NACO_MIN(nskyplane-1, irplib_pfits_get_int
1477 (plist, "NAXIS3") - 2);
1478
1479 skip_if_lt(istop - istart, 2, "sky planes for median");
1480
1481 abovecube = cpl_imagelist_new();
1482
1483 for (i = istart; i <= istop; i++) {
1484 self = cpl_image_load(filename, CPL_TYPE_FLOAT, i, EXT0);
1485
1486 any_if("Could not load plane %d from frame %d/%d, file=%s",
1487 1+i, 1+iabove, nframes, filename);
1488
1489 bug_if(cpl_imagelist_set(abovecube, self, i - istart));
1490 }
1491
1492 } else {
1493
1494 int naxis3;
1495
1496 abovecube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
1497
1498 any_if("Could not load cube from frame %d/%d, file=%s",
1499 1+iabove, nframes, filename);
1500
1501 naxis3 = cpl_imagelist_get_size(abovecube);
1502
1503 bug_if(naxis3 < 3);
1504
1505 cpl_image_delete(cpl_imagelist_unset(abovecube, naxis3-1));
1506 }
1507
1508 }
1509
1510 error_if(belowcube == NULL && abovecube == NULL, CPL_ERROR_DATA_NOT_FOUND,
1511 "No cube(s) available for sky estimation among %d object frames",
1512 nframes);
1513
1514 if (belowcube == NULL) {
1515 skycube = abovecube;
1516 } else if (abovecube == NULL) {
1517 skycube = belowcube;
1518 } else {
1519 /* Wrap around the images in the two cubes */
1520
1521 const int nbelow = cpl_imagelist_get_size(belowcube);
1522 const int nabove = cpl_imagelist_get_size(abovecube);
1523 int nwrap = 0;
1524
1525 skycube = cpl_imagelist_new();
1526
1527 for (i = 0; i < nbelow; i++) {
1528 skip_if(cpl_imagelist_set(skycube, cpl_imagelist_get(belowcube, i),
1529 nwrap++));
1530 }
1531 for (i = 0; i < nabove; i++) {
1532 skip_if(cpl_imagelist_set(skycube, cpl_imagelist_get(abovecube, i),
1533 nwrap++));
1534 }
1535 skip_if(cpl_imagelist_get_size(skycube) != nwrap);
1536 skip_if(nbelow + nabove != nwrap);
1537 }
1538
1539 self = cpl_imagelist_collapse_median_create(skycube);
1540
1541#ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
1542 if (belowcube == NULL || abovecube == NULL) {
1543 /* Try to replace object-pixels with sky-pixels from the object image */
1544 const cpl_mask * fill2bpm;
1545 const cpl_mask * selfbpm = NULL;
1546 const double lo_skysigma = 0.2;
1547 const double hi_skysigma = 5.0;
1548
1549 skip_if(naco_img_jitter_reject_objects(self, lo_skysigma, hi_skysigma));
1550
1551 selfbpm = cpl_image_get_bpm_const(self);
1552
1553 if (selfbpm != NULL) {
1554 const cpl_mask * mybpm;
1555
1556 /* Substitute the objects pixels with sky pixels from isky */
1557
1558 const char * filename
1559 = cpl_frame_get_filename(irplib_framelist_get_const(obj, isky));
1560 int naxis3;
1561
1562 mycube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
1563
1564 any_if("Could not load cube from frame %d/%d, file=%s",
1565 1+isky, nframes, filename);
1566
1567 naxis3 = cpl_imagelist_get_size(mycube);
1568
1569 bug_if(naxis3 < 3);
1570
1571 cpl_image_delete(cpl_imagelist_unset(mycube, naxis3-1));
1572
1573 mysky = cpl_imagelist_collapse_median_create(mycube);
1574
1575 skip_if(naco_img_jitter_reject_objects(mysky, lo_skysigma,
1576 hi_skysigma));
1577
1578 /* When a pixel is bad in self and good in mysky: Set to mysky */
1579 /* Other pixels in self are unchanged */
1580
1581 mybpm = cpl_image_get_bpm_const(mysky);
1582
1583 if (mybpm == NULL) {
1584 /* Fill all bad pixels in self with values from mysky */
1585 fill2bpm = selfbpm;
1586 } else {
1587 /* Fill those bad pixels in self with values from mysky
1588 when those pixels are good */
1589 fillbpm = cpl_mask_duplicate(mybpm);
1590 bug_if(cpl_mask_not(fillbpm));
1591 bug_if(cpl_mask_and(fillbpm, selfbpm));
1592
1593 fill2bpm = fillbpm;
1594
1595 }
1596 cpl_msg_info(cpl_func, "Filling %d object-pixels in sky image "
1597 "with %d sky-pixels from object image",
1598 (int)cpl_mask_count(selfbpm),
1599 (int)cpl_mask_count(fill2bpm));
1600 if (fill2bpm != selfbpm) {
1601 /* These rejected pixels will be filled */
1602 bug_if(cpl_image_reject_from_mask(self, fill2bpm));
1603 }
1604
1605 if (fillbpm == NULL) {
1606 fillbpm = cpl_mask_duplicate(fill2bpm);
1607 } else if (fillbpm != fill2bpm) {
1608 bug_if(cpl_mask_copy(fillbpm, fill2bpm, 1, 1));
1609 }
1610
1611 bug_if(cpl_image_fill_rejected(self, 0.0)); /* Use addition to fill */
1612 bug_if(cpl_image_accept_all(self)); /* fill2bpm may be invalid now */
1613
1614 bug_if(cpl_mask_not(fillbpm));
1615 bug_if(cpl_image_reject_from_mask(mysky, fillbpm));
1616 bug_if(cpl_image_fill_rejected(mysky, 0.0)); /* Use addition to fill */
1617 bug_if(cpl_image_accept_all(mysky));
1618 bug_if(cpl_image_add(self, mysky));
1619 }
1620 }
1621#endif
1622
1623 end_skip;
1624
1625 if (cpl_error_get_code()) {
1626 cpl_image_delete(self);
1627 self = NULL;
1628 }
1629
1630
1631 if (skycube != belowcube && skycube != abovecube) {
1632 int nwrap = cpl_imagelist_get_size(skycube);
1633
1634 /* Unwrap the wrapped images */
1635 for (;nwrap > 0;) {
1636 (void)cpl_imagelist_unset(skycube, --nwrap);
1637 }
1638
1639 cpl_imagelist_delete(skycube);
1640 }
1641
1642 cpl_mask_delete(fillbpm);
1643 cpl_image_delete(mysky);
1644 cpl_imagelist_delete(mycube);
1645 cpl_imagelist_delete(belowcube);
1646 cpl_imagelist_delete(abovecube);
1647
1648 return self;
1649}
1650
1651
1652/*----------------------------------------------------------------------------*/
1663/*----------------------------------------------------------------------------*/
1664static
1665cpl_error_code naco_img_jitter_imagelist_wrap_nocube(cpl_imagelist * self,
1666 const cpl_array * iscube,
1667 cpl_imagelist * other)
1668{
1669
1670 const int ncube = cpl_imagelist_get_size(other);
1671 int nwrap = cpl_imagelist_get_size(self);
1672 int i;
1673
1674 bug_if(self == NULL);
1675 bug_if(iscube == NULL);
1676 bug_if(other == NULL);
1677 bug_if(nwrap != 0);
1678 bug_if(cpl_array_get_size(iscube) != ncube);
1679
1680 for (i = 0; i < ncube; i++) {
1681 int is_invalid;
1682
1683 (void)cpl_array_get_int(iscube, i, &is_invalid);
1684
1685 if (is_invalid) {
1686 cpl_imagelist_set(self, cpl_imagelist_get(other, i), nwrap);
1687 nwrap++;
1688 }
1689 }
1690
1691 bug_if(cpl_imagelist_get_size(self) != nwrap);
1692
1693 end_skip;
1694
1695 return cpl_error_get_code();
1696}
1697
1698
1699#ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
1700
1701/*----------------------------------------------------------------------------*/
1712/*----------------------------------------------------------------------------*/
1713static cpl_error_code naco_img_jitter_reject_objects(cpl_image * self,
1714 double lo_sigma,
1715 double hi_sigma)
1716{
1717 double median;
1718 double med_dist = DBL_MAX;
1719 double hi_threshold;
1720 cpl_mask * hi_objects = NULL;
1721 cpl_mask * lo_objects = NULL;
1722 cpl_mask * rejects = NULL;
1723 cpl_image * hi_label = NULL;
1724 cpl_image * lo_label = NULL;
1725 cpl_apertures * hi_apert = NULL;
1726 cpl_mask * kernel = NULL;
1727
1728
1729 bug_if(self == NULL);
1730 bug_if(lo_sigma <= 0.0);
1731 bug_if(hi_sigma < lo_sigma);
1732
1733 /* Compute the threshold */
1734 median = cpl_image_get_median_dev(self, &med_dist);
1735 hi_threshold = median + hi_sigma * med_dist;
1736
1737 /* Binarise the image with the high sigma threshold */
1738 hi_objects = cpl_mask_threshold_image_create(self, hi_threshold, DBL_MAX);
1739 bug_if(hi_objects == NULL);
1740
1741 /* Apply a morphological opening to remove the single pixel detections */
1742 /* Copied from cpl_apertures_extract_sigma() */
1743 kernel = cpl_mask_new(3, 3);
1744 bug_if(cpl_mask_not(kernel));
1745 bug_if(cpl_mask_filter(hi_objects, hi_objects, kernel, CPL_FILTER_OPENING,
1746 CPL_BORDER_ZERO));
1747
1748 if (!cpl_mask_is_empty(hi_objects)) {
1749 /* Any low-sigma aperture overlapping a high-sigma
1750 aperture is assumed to be (all of) an object */
1751
1752 const double lo_threshold = median + lo_sigma * med_dist;
1753 cpl_size hi_ilabel, hi_nlabel, lo_nlabel;
1754
1755 /* Binarise the image with the low sigma threshold */
1756 lo_objects = cpl_mask_threshold_image_create(self, lo_threshold, DBL_MAX);
1757 bug_if(lo_objects == NULL);
1758 bug_if(cpl_mask_filter(lo_objects, lo_objects, kernel,
1759 CPL_FILTER_OPENING, CPL_BORDER_ZERO));
1760
1761 hi_label = cpl_image_labelise_mask_create(hi_objects, &hi_nlabel);
1762 lo_label = cpl_image_labelise_mask_create(lo_objects, &lo_nlabel);
1763
1764 hi_apert = cpl_apertures_new_from_image(self, hi_label);
1765 bug_if(hi_apert == NULL);
1766
1767 for (hi_ilabel = 1; hi_ilabel <= hi_nlabel; hi_ilabel++) {
1768 /* Get one pixel from the high-sigma aperture */
1769 const int pos_x = cpl_apertures_get_top_x(hi_apert, hi_ilabel);
1770 const int pos_y = cpl_apertures_get_top(hi_apert, hi_ilabel);
1771 /* The corresponding low-sigma aperture */
1772 int is_rejected;
1773 const int lo_ilabel = (int)cpl_image_get(lo_label, pos_x, pos_y,
1774 &is_rejected);
1775
1776 /* The mask of pixels with the corresponding low-sigma aperture */
1777 cpl_mask_delete(rejects);
1778 rejects = cpl_mask_threshold_image_create(lo_label,
1779 (double)lo_ilabel - 0.5,
1780 (double)lo_ilabel + 0.5);
1781
1782 /* Add to the rejection mask */
1783 cpl_mask_or(hi_objects, rejects);
1784
1785 }
1786
1787 cpl_msg_info(cpl_func, "Found %d object(s) of %d pixel(s) "
1788 "in sky image using sigmas %g and %g", (int)hi_nlabel,
1789 (int)cpl_mask_count(hi_objects), lo_sigma, hi_sigma);
1790 bug_if(cpl_image_reject_from_mask(self, hi_objects));
1791
1792 }
1793
1794 end_skip;
1795
1796 cpl_apertures_delete(hi_apert);
1797 cpl_image_delete(hi_label);
1798 cpl_image_delete(lo_label);
1799 cpl_mask_delete(kernel);
1800 cpl_mask_delete(hi_objects);
1801 cpl_mask_delete(lo_objects);
1802 cpl_mask_delete(rejects);
1803
1804 return cpl_error_get_code();
1805}
1806#endif
1807
1808
1809
1810/*----------------------------------------------------------------------------*/
1820/*----------------------------------------------------------------------------*/
1821static cpl_image * naco_img_jitter_saa_lucky(const cpl_imagelist * cube,
1822 const cpl_vector * strehl,
1823 const cpl_bivector * offs,
1824 double fraction)
1825{
1826
1827 cpl_image * self = NULL;
1828 const int ncube = cpl_imagelist_get_size(cube);
1829 const int mcube = NACO_MAX(NACO_MIN(ncube, (int)(0.5 + fraction * ncube)),
1830 1);
1831 cpl_imagelist * lcube = NULL;
1832 const cpl_imagelist * ucube;
1833 cpl_vector * lstrehl = NULL;
1834 /* Always need to duplicate due to pesky offset convention in
1835 cpl_geom_img_offset_saa() */
1836 cpl_bivector * loffs = cpl_bivector_duplicate(offs);
1837 cpl_vector * loffsx = cpl_bivector_get_x(loffs);
1838 cpl_vector * loffsy = cpl_bivector_get_y(loffs);
1839 cpl_table * tsort = NULL;
1840 cpl_propertylist * psort = NULL;
1841 int i;
1842
1843
1844 bug_if(cpl_vector_get_size(strehl) != ncube);
1845 bug_if(cpl_bivector_get_size(offs) != ncube);
1846 bug_if(fraction <= 0.0);
1847 bug_if(fraction > 1.0);
1848
1849 if (mcube < ncube) {
1850 double strehlmin; /* Smallest to be used */
1851 int * pindex;
1852
1853 lstrehl = cpl_vector_duplicate(strehl);
1854
1855 tsort = cpl_table_new(ncube);
1856 psort = cpl_propertylist_new();
1857
1858 /* Largest Strehl 1st */
1859 bug_if(cpl_propertylist_append_bool(psort, "LSTREHL", CPL_TRUE));
1860
1861 bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(lstrehl),
1862 "LSTREHL"));
1863 bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(loffsx),
1864 "LOFFSX"));
1865 bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(loffsy),
1866 "LOFFSY"));
1867 bug_if(cpl_table_new_column(tsort, "INDEX", CPL_TYPE_INT));
1868
1869 /* The indices for the imagelist */
1870 pindex = cpl_table_get_data_int(tsort, "INDEX");
1871 for (i = 0; i < ncube; i++) {
1872 pindex[i] = i;
1873 }
1874
1875 bug_if(cpl_table_sort(tsort, psort));
1876 /* Strehl, offsets and the (imagelist) indices have been sorted */
1877
1878 lcube = cpl_imagelist_new();
1879
1880 /* Use the index column to create a sorted list of wrapped images */
1881 for (i = 0; i < mcube; i++) {
1882 const int j = pindex[i];
1883 const cpl_image * image = cpl_imagelist_get_const(cube, j);
1884
1885 cpl_imagelist_set(lcube, (cpl_image*)image, i);
1886 }
1887 /* tsort no longer accessed */
1888
1889 /* loffs and the imagelist must both have length mcube */
1890 bug_if(cpl_vector_set_size(loffsx, mcube));
1891 bug_if(cpl_vector_set_size(loffsy, mcube));
1892
1893 strehlmin = cpl_vector_get(lstrehl, mcube - 1);
1894 cpl_vector_delete(lstrehl);
1895 lstrehl = NULL;
1896
1897 cpl_msg_info(cpl_func, "%g%% (%d/%d) lucky mode at Strehl=%g",
1898 100.0*fraction, mcube, ncube, strehlmin);
1899 }
1900 ucube = lcube ? lcube : cube;
1901
1902 self = naco_img_jitter_saa_center(ucube, loffs);
1903 any_if("Could not center and saa %d-cube", ncube);
1904
1905 end_skip;
1906
1907 if (lcube != NULL) {
1908 /* Unwrap the wrapped images */
1909 for (i = cpl_imagelist_get_size(lcube); i > 0;) {
1910 (void)cpl_imagelist_unset(lcube, --i);
1911 }
1912
1913 cpl_imagelist_delete(lcube);
1914 }
1915
1916 cpl_vector_delete(lstrehl);
1917
1918 cpl_bivector_delete(loffs);
1919
1920 if (tsort != NULL) {
1921 if (cpl_table_has_column(tsort, "LSTREHL"))
1922 (void)cpl_table_unwrap(tsort, "LSTREHL");
1923 if (cpl_table_has_column(tsort, "LOFFSX"))
1924 (void)cpl_table_unwrap(tsort, "LOFFSX");
1925 if (cpl_table_has_column(tsort, "LOFFSY"))
1926 (void)cpl_table_unwrap(tsort, "LOFFSY");
1927 cpl_table_delete(tsort);
1928 }
1929 cpl_propertylist_delete(psort);
1930
1931 return self;
1932}
1933
1934
1935/*----------------------------------------------------------------------------*/
1943/*----------------------------------------------------------------------------*/
1944static
1945cpl_error_code naco_img_jitter_find_strehl(const cpl_imagelist * self,
1946 const cpl_parameterlist * parlist,
1947 const irplib_framelist * objframes)
1948{
1949
1950 const int nobj = irplib_framelist_get_size(objframes);
1951 cpl_apertures * apert = NULL;
1952 cpl_vector * sigmas = NULL;
1953 double psigmas[] = {5.0, 2.0, 1.0, 0.5}; /* not modified */
1954 const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
1955 cpl_size isigma = 0;
1956 int i;
1957
1958
1959 bug_if(cpl_imagelist_get_size(self) != nobj);
1960
1961 /* Create the vector for the detection thresholds */
1962 sigmas = cpl_vector_wrap(nsigmas, psigmas);
1963
1964 for (i = 0; i < nobj; i++) {
1965 const cpl_propertylist * plist
1966 = irplib_framelist_get_propertylist_const(objframes, i);
1967 const cpl_image * oimage = cpl_imagelist_get_const(self, i);
1968
1969 const double pixscale = naco_pfits_get_pixscale(plist);
1970 const char * filter = naco_pfits_get_filter(plist);
1971 double lam = DBL_MAX; /* Avoid uninit warning */
1972 double dlam = DBL_MAX; /* Avoid uninit warning */
1973
1974 double cent_x, cent_y;
1975 double strehl = 0, strehl_err, star_bg,star_peak, star_flux;
1976 double psf_peak, psf_flux, bg_noise;
1977 int iflux;
1978
1979
1980 skip_if(pixscale <= 0.0);
1981
1982 irplib_check(naco_get_filter_infos(filter, &lam, &dlam),
1983 "Frame %d has no info for filter %s", 1+i, filter);
1984
1985 cpl_apertures_delete(apert);
1986 apert = cpl_apertures_extract(oimage, sigmas, &isigma);
1987
1988 any_if("No object found in combined image of frame %d", 1+i);
1989
1990 bug_if(irplib_apertures_find_max_flux(apert, &iflux, 1));
1991
1992 cent_x = cpl_apertures_get_centroid_x(apert, iflux);
1993 cent_y = cpl_apertures_get_centroid_y(apert, iflux);
1994
1995 skip_if (naco_strehl_compute(oimage, parlist, RECIPE_STRING, lam, dlam,
1996 cent_x, cent_y, pixscale,
1997 &strehl, &strehl_err,
1998 &star_bg, &star_peak, &star_flux,
1999 &psf_peak, &psf_flux,
2000 &bg_noise));
2001 cpl_msg_info(cpl_func, "Image of frame %d/%d has strehl=%g at (x,y)"
2002 "=(%g,%g)", 1+i, nobj, strehl, cent_x, cent_y);
2003 }
2004
2005 end_skip;
2006
2007 (void)cpl_vector_unwrap(sigmas);
2008 cpl_apertures_delete(apert);
2009
2010 return cpl_error_get_code();
2011}
2012
2013
2014
2015/*----------------------------------------------------------------------------*/
2023/*----------------------------------------------------------------------------*/
2024static cpl_image * naco_img_jitter_saa_center(const cpl_imagelist * cube,
2025 cpl_bivector * offs)
2026{
2027
2028 const int ncube = cpl_imagelist_get_size(cube);
2029 cpl_image * self = NULL;
2030 cpl_image ** combined = NULL;
2031 cpl_imagelist * ccube = NULL;
2032 const cpl_imagelist * ucube;
2033 cpl_vector * offsx = cpl_bivector_get_x(offs);
2034 cpl_vector * offsy = cpl_bivector_get_y(offs);
2035 double * doffsx = cpl_vector_get_data(offsx);
2036 double * doffsy = cpl_vector_get_data(offsy);
2037 const double med_x = cpl_vector_get_median_const(offsx);
2038 const double med_y = cpl_vector_get_median_const(offsy);
2039 double pos_x, pos_y;
2040 double minsqdist = DBL_MAX;
2041 int imin = -1;
2042 int i;
2043
2044
2045 bug_if(cpl_bivector_get_size(offs) != ncube);
2046
2047 /* Find image with object closest to object median location */
2048 for (i = 0; i < ncube; i++) {
2049 const double x = cpl_vector_get(offsx, i);
2050 const double y = cpl_vector_get(offsy, i);
2051 const double sqdist
2052 = (x - med_x) * (x - med_x) + (y - med_y) * (y - med_y);
2053
2054 if (sqdist < minsqdist) {
2055 minsqdist = sqdist;
2056 imin = i;
2057 }
2058 }
2059
2060 cpl_msg_info(cpl_func, "Plane %d/%d has minimal object distance %g "
2061 "from median (x,y)=(%g,%g)", 1+imin, ncube,
2062 sqrt(minsqdist), med_x, med_y);
2063
2064
2065 if (imin > 0) {
2066 /* Wrap ccube around the images - with image imin first */
2067 /* - the images from cube will _not_ be modified */
2068 const cpl_image * image = cpl_imagelist_get_const(cube, imin);
2069
2070 ccube = cpl_imagelist_new();
2071
2072 bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, 0));
2073
2074 for (i = 0; i < imin; i++) {
2075 image = cpl_imagelist_get_const(cube, i);
2076 bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, 1+i));
2077 }
2078 for (i = 1+imin; i < ncube; i++) {
2079 image = cpl_imagelist_get_const(cube, i);
2080 bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, i));
2081 }
2082
2083 bug_if(cpl_imagelist_get_size(ccube) != ncube);
2084
2085 /* Reorder offs accordingly */
2086 pos_x = cpl_vector_get(offsx, imin);
2087 pos_y = cpl_vector_get(offsy, imin);
2088
2089 /* Move all offsets below imin 1 place up */
2090 (void)memmove(doffsx + 1, doffsx, (size_t)imin * sizeof(*doffsx));
2091 (void)memmove(doffsy + 1, doffsy, (size_t)imin * sizeof(*doffsy));
2092
2093 /* Copy the imin offset to the 1st element */
2094 cpl_vector_set(offsx, 0, pos_x);
2095 cpl_vector_set(offsy, 0, pos_y);
2096 }
2097 ucube = ccube ? ccube : cube;
2098
2099 /* Strange convention for the offsets :-(((((((((((((((( */
2100 cpl_vector_subtract_scalar(offsx, cpl_vector_get(offsx, 0));
2101 cpl_vector_subtract_scalar(offsy, cpl_vector_get(offsy, 0));
2102 cpl_vector_multiply_scalar(offsx, -1.0);
2103 cpl_vector_multiply_scalar(offsy, -1.0);
2104
2105 combined = cpl_geom_img_offset_saa(ucube, offs, CPL_KERNEL_DEFAULT,
2106 0, 0, CPL_GEOM_FIRST, &pos_x, &pos_y);
2107
2108 any_if("Could not shift and add %d-cube", ncube);
2109
2110 cpl_msg_info(cpl_func, "Shift-and-added %d-cube, 1st pos=(%g,%g)",
2111 ncube, pos_x, pos_y);
2112
2113 self = combined[0];
2114 cpl_image_delete(combined[1]);
2115 combined[0] = NULL;
2116 combined[1] = NULL;
2117
2118 end_skip;
2119
2120 if (combined != NULL) {
2121 cpl_image_delete(combined[0]);
2122 cpl_image_delete(combined[1]);
2123 cpl_free(combined);
2124 }
2125
2126 if (ccube != NULL) {
2127 /* Unwrap the wrapped no-cube images */
2128 for (i = cpl_imagelist_get_size(ccube); i > 0;) {
2129 (void)cpl_imagelist_unset(ccube, --i);
2130 }
2131
2132 cpl_imagelist_delete(ccube);
2133 }
2134
2135 return self;
2136}
cpl_error_code irplib_pfits_set_airmass(cpl_propertylist *self, const irplib_framelist *rawframes)
Update/Set the AIRMASS property.
Definition: irplib_pfits.c:373
int naco_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: naco_dfs.c:62
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.
int naco_parameterlist_get_int(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO integer parameter.
const char * naco_parameterlist_get_string(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO string parameter.
cpl_boolean naco_parameterlist_get_bool(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO boolean parameter.
const char * naco_pfits_get_filter(const cpl_propertylist *self)
find out the filter
Definition: naco_pfits.c:167
double naco_pfits_get_pixscale(const cpl_propertylist *self)
find out the pixel scale
Definition: naco_pfits.c:341
const char * naco_pfits_get_opti4_name(const cpl_propertylist *self)
find out the OPTI4.NAME key
Definition: naco_pfits.c:316
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_opti3_name(const cpl_propertylist *self)
find out the OPTI3.NAME key
Definition: naco_pfits.c:304
double naco_pfits_get_cumoffsetx(const cpl_propertylist *self)
find out the cumulative offset in X
Definition: naco_pfits.c:95
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
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