IIINSTRUMENT Pipeline Reference Manual 4.4.13
naco_img_checkfocus.c
1/* $Id: naco_img_checkfocus.c,v 1.59 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.59 $
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#include "irplib_strehl.h"
39
40/*-----------------------------------------------------------------------------
41 Define
42 -----------------------------------------------------------------------------*/
43
44#define STREHL_DEF_LOCATE_SX 512
45#define STREHL_DEF_LOCATE_SY 512
46#define ENERGY_RADIUS_PIX 11
47
48#define RECIPE_STRING "naco_img_checkfocus"
49
50/*-----------------------------------------------------------------------------
51 Private Functions prototypes
52 -----------------------------------------------------------------------------*/
53
54static cpl_error_code naco_img_checkfocus_reduce(const cpl_parameterlist *,
55 const irplib_framelist *, int,
56 const cpl_image *, double *,
57 double *, double *, double *,
58 double *);
59
60static cpl_error_code naco_img_checkfocus_qc(cpl_propertylist *,
61 const irplib_framelist *);
62
63static cpl_error_code naco_img_checkfocus_save(cpl_frameset *,
64 const cpl_parameterlist *,
65 const cpl_propertylist *);
66
67NACO_RECIPE_DEFINE(naco_img_checkfocus,
68 NACO_PARAM_PLOT |
69 NACO_PARAM_STAR_R |
70 NACO_PARAM_BG_RINT |
71 NACO_PARAM_BG_REXT,
72 "Focus check recipe",
73 RECIPE_STRING " -- The focus checking recipe\n"
74 "The Set Of Frames (sof-file) must specify at least four "
75 "files and they must be tagged\n"
76 "NACO-raw-file.fits "NACO_IMG_CHECKFOCUS_RAW"\n"
77 "The first of the files is used as a dark frame.\n");
78
79/*----------------------------------------------------------------------------*/
83/*----------------------------------------------------------------------------*/
84
85/*-----------------------------------------------------------------------------
86 Functions code
87 -----------------------------------------------------------------------------*/
88
89/*----------------------------------------------------------------------------*/
96/*----------------------------------------------------------------------------*/
97static int naco_img_checkfocus(cpl_frameset * framelist,
98 const cpl_parameterlist * parlist)
99{
100 cpl_errorstate cleanstate = cpl_errorstate_get();
101 irplib_framelist * allframes = NULL;
102 irplib_framelist * rawframes = NULL;
103 cpl_propertylist * qclist = cpl_propertylist_new();
104 cpl_image * dark = NULL;
105 cpl_vector * strehl_vec = NULL;
106 cpl_matrix * focus_mat = NULL;
107 cpl_vector * focus_res = NULL;
108 cpl_polynomial * fit_poly = NULL;
109 const char * darkfile;
110 int nframes;
111 int nb_good;
112 const cpl_size degree1 = 1;
113 const cpl_size degree2 = 2;
114 double best_strehl = DBL_MAX; /* Avoid (false) uninit warning */
115 double c1, c2;
116 double optimal_focus, optimal_strehl, mse2, mse1;
117 int i;
118
119 /* Identify the RAW and CALIB frames in the input frameset */
120 skip_if (naco_dfs_set_groups(framelist));
121
122 allframes = irplib_framelist_cast(framelist);
123 skip_if(allframes == NULL);
124
125 rawframes = irplib_framelist_extract(allframes, NACO_IMG_CHECKFOCUS_RAW);
126 skip_if(rawframes == NULL);
127 irplib_framelist_empty(allframes);
128
129 nframes = irplib_framelist_get_size(rawframes);
130 irplib_ensure(nframes >= 4, CPL_ERROR_DATA_NOT_FOUND,
131 "Must have at least 4 (not %d) frames to check the focus",
132 nframes);
133
134 skip_if(irplib_framelist_load_propertylist(rawframes, 0, 0, "^("
135 NACO_PFITS_REGEXP_CHECKFOCUS "|"
136 NACO_PFITS_REGEXP_CHECKFOCUS_PAF
137 ")$", CPL_FALSE));
138
139 skip_if(irplib_framelist_load_propertylist_all(rawframes, 0, "^("
140 NACO_PFITS_REGEXP_CHECKFOCUS
141 ")$", CPL_FALSE));
142
143 /* The dark is the first frame */
144 cpl_msg_info(cpl_func, "The first frame is used as a dark");
145 darkfile = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, 0));
146 skip_if (0);
147
148 irplib_check(dark = cpl_image_load(darkfile, CPL_TYPE_FLOAT, 0, 0),
149 "Could not load the dark from %s", darkfile);
150
151 /* Allocate vectors to store results */
152 strehl_vec = cpl_vector_new(nframes-1);
153 focus_mat = cpl_matrix_new(1, nframes-1);
154
155 skip_if (naco_img_checkfocus_qc(qclist, rawframes));
156
157 /* Reduce each frame */
158 nb_good = 0;
159 for (i=1 ; i < nframes ; i++) {
160 double focus = DBL_MAX; /* Avoid (false) uninit warning */
161 double energy = DBL_MAX; /* Avoid (false) uninit warning */
162 double fwhm = DBL_MAX; /* Avoid (false) uninit warning */
163 double strehl, strehl_err;
164
165 cpl_msg_info(cpl_func, "Reducing frame %d of %d\n", i+1, nframes);
166
167 /* Reduce frame nb i */
168 if (naco_img_checkfocus_reduce(parlist, rawframes, i, dark,
169 &fwhm, &strehl, &strehl_err,
170 &energy, &focus)) {
171 naco_error_reset("Could not compute focus for this frame:");
172 continue;
173 }
174
175 /* Keep only the values where strehl_err < 10% */
176 if (strehl_err >= 0.1) continue;
177
178 /* Assign the results in the vectors */
179 bug_if (cpl_vector_set(strehl_vec, nb_good, strehl));
180 bug_if (cpl_matrix_set(focus_mat, 0, nb_good, focus));
181
182 nb_good++;
183
184 if (nb_good > 1 && strehl <= best_strehl) continue;
185
186 /* Found the best FOCUS */
187 best_strehl = strehl;
188
189 /* Add/Update QC parameters */
190 bug_if(cpl_propertylist_update_double(qclist, "ESO QC STREHL", strehl));
191 bug_if(cpl_propertylist_update_double(qclist, "ESO QC STREHL ERROR",
192 strehl_err));
193 bug_if(cpl_propertylist_update_double(qclist, "ESO QC FWHM PIX", fwhm));
194 bug_if(cpl_propertylist_update_double(qclist, "ESO QC ENERGY", energy));
195 bug_if(cpl_propertylist_update_double(qclist, "ESO QC FOCUS", focus));
196
197
198 }
199 cpl_image_delete(dark);
200 dark = NULL;
201 irplib_framelist_empty(rawframes);
202
203 skip_if_lt (nb_good, 3, "frames with a Strehl error less than 0.1");
204
205 bug_if (cpl_vector_set_size(strehl_vec, nb_good));
206 bug_if (cpl_matrix_set_size(focus_mat, 1, nb_good));
207
208 /* Fit the optimal focus - and make sure it is well-defined */
209 focus_res = cpl_vector_new(nb_good);
210 fit_poly = cpl_polynomial_new(1);
211 skip_if(cpl_polynomial_fit(fit_poly, focus_mat, NULL, strehl_vec, NULL,
212 CPL_FALSE, NULL, &degree1));
213
214 bug_if(cpl_vector_fill_polynomial_fit_residual(focus_res, strehl_vec, NULL,
215 fit_poly, focus_mat, NULL));
216 mse1 = cpl_vector_product(focus_res, focus_res) / nb_good;
217
218 skip_if(cpl_polynomial_fit(fit_poly, focus_mat, NULL, strehl_vec, NULL,
219 CPL_FALSE, NULL, &degree2));
220
221 bug_if(cpl_vector_fill_polynomial_fit_residual(focus_res, strehl_vec, NULL,
222 fit_poly, focus_mat, NULL));
223 mse2 = cpl_vector_product(focus_res, focus_res) / nb_good;
224
225 cpl_vector_delete(focus_res);
226 focus_res = NULL;
227 cpl_vector_delete(strehl_vec);
228 strehl_vec = NULL;
229 cpl_matrix_delete(focus_mat);
230 focus_mat = NULL;
231
232 c1 = cpl_polynomial_get_coeff(fit_poly, &degree1);
233 c2 = cpl_polynomial_get_coeff(fit_poly, &degree2);
234
235 irplib_ensure(mse2 < mse1, CPL_ERROR_DATA_NOT_FOUND,
236 "Ill-defined optimal focus, the strehl ratio "
237 "appears to be a linear function of the focus value: "
238 "mse(2)=%g >= mse(1)=%g (c1=%g, c2=%g)",
239 mse2, mse1, c1, c2);
240
241 bug_if (c2 == 0.0);
242
243 irplib_ensure(c2 < 0.0, CPL_ERROR_DATA_NOT_FOUND,
244 "Ill-defined optimal focus, the strehl ratio "
245 "does not have a single optimal value: mse(2)=%g, c1=%g, "
246 "c2=%g > 0", mse2, c1, c2);
247
248 optimal_focus = -c1/(2.0*c2);
249
250 /* Could compute derivate as well, to check that it is close to zero */
251 optimal_strehl = cpl_polynomial_eval_1d(fit_poly, optimal_focus, NULL);
252
253 cpl_polynomial_delete(fit_poly);
254 fit_poly = NULL;
255
256 cpl_msg_info(cpl_func, "Strehl ratio with optimal Focus(%g): %g "
257 "(mse(2)=%g < mse(1)=%g)", optimal_focus, optimal_strehl,
258 mse2, mse1);
259
260 bug_if(cpl_propertylist_append_double(qclist, "ESO QC FOCUSOPT",
261 optimal_focus));
262
263 /* PRO.CATG */
264 bug_if(cpl_propertylist_append_string(qclist, CPL_DFS_PRO_CATG,
265 NACO_IMG_CHECKFOCUS));
266
267 skip_if (naco_img_checkfocus_save(framelist, parlist, qclist));
268
269 end_skip;
270
271 cpl_propertylist_delete(qclist);
272 irplib_framelist_delete(allframes);
273 irplib_framelist_delete(rawframes);
274 cpl_image_delete(dark);
275
276 cpl_vector_delete(focus_res);
277 cpl_vector_delete(strehl_vec);
278 cpl_matrix_delete(focus_mat);
279
280 cpl_polynomial_delete(fit_poly);
281
282 return cpl_error_get_code();
283}
284
285/*----------------------------------------------------------------------------*/
299/*----------------------------------------------------------------------------*/
300static cpl_error_code naco_img_checkfocus_reduce(const cpl_parameterlist * parlist,
301 const irplib_framelist * rawframes,
302 int iframe,
303 const cpl_image * dark,
304 double * fwhm,
305 double * strehl,
306 double * strehl_err,
307 double * energy,
308 double * focus)
309{
310 const cpl_propertylist * plist;
311 const char * filter;
312 double pixscale;
313 cpl_image * ima = NULL;
314 cpl_vector * sigmas = NULL;
315 cpl_apertures * apert = NULL;
316 const char * file;
317 double psigmas[] = {5, 2, 1, 0.5};
318 const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
319 cpl_size isigma;
320 double lam, dlam;
321 double pos_x, pos_y;
322 double star_bg, star_peak, star_flux, psf_peak, psf_flux,
323 bg_noise;
324 double fwhm_x, fwhm_y;
325 int imax_flux;
326
327
328 skip_if (0);
329
330 bug_if (parlist == NULL);
331 bug_if (rawframes == NULL);
332 bug_if (dark == NULL);
333 bug_if (fwhm == NULL);
334 bug_if (strehl == NULL);
335 bug_if (strehl_err == NULL);
336 bug_if (energy == NULL);
337 bug_if (focus == NULL);
338
339 file = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, iframe));
340
341 /* Print out the filter and the pixel scale */
342 plist = irplib_framelist_get_propertylist_const(rawframes, iframe);
343 bug_if (0);
344
345 filter = naco_pfits_get_filter(plist);
346 pixscale = naco_pfits_get_pixscale(plist);
347 *focus = naco_pfits_get_focus(plist);
348
349 skip_if (0);
350
351 /* Get lam and dlam from the filter name for the Strehl computation */
352 irplib_check(naco_get_filter_infos(filter, &lam, &dlam),
353 "Cannot get filter infos [%s]", filter);
354
355 /* Load input images */
356 cpl_msg_info(cpl_func, "---> Load input image and subtract the dark");
357 ima = cpl_image_load(file, CPL_TYPE_FLOAT, 0, 0);
358 skip_if (0);
359
360 bug_if (cpl_image_subtract(ima, dark));
361
362 /* Detect a bright star around the center */
363 cpl_msg_info(cpl_func, "---> Detecting a bright star using "
364 "%d sigma-levels ranging from %g down to %g", nsigmas,
365 psigmas[0], psigmas[nsigmas-1]);
366 sigmas = cpl_vector_wrap(nsigmas, psigmas);
367 apert = cpl_apertures_extract_window(ima, sigmas,
368 (int)(cpl_image_get_size_x(ima)-STREHL_DEF_LOCATE_SX)/2,
369 (int)(cpl_image_get_size_y(ima)-STREHL_DEF_LOCATE_SY)/2,
370 (int)(cpl_image_get_size_x(ima)+STREHL_DEF_LOCATE_SX)/2,
371 (int)(cpl_image_get_size_y(ima)+STREHL_DEF_LOCATE_SY)/2,
372 &isigma);
373 if (apert == NULL) {
374 cpl_msg_error(cpl_func, "Cannot detect any object");
375 skip_if(1);
376 }
377
378 /* Find position of aperture with largest flux */
379 skip_if (irplib_apertures_find_max_flux(apert, &imax_flux, 1));
380
381 pos_x = cpl_apertures_get_centroid_x(apert, imax_flux);
382 skip_if (0);
383 pos_y = cpl_apertures_get_centroid_y(apert, imax_flux);
384 skip_if (0);
385
386 cpl_apertures_delete(apert);
387 apert = NULL;
388
389 cpl_msg_info(cpl_func, "Star detected at sigma=%g, at position: %g %g",
390 psigmas[isigma], pos_x, pos_y);
391
392 /* Compute the strehl */
393 cpl_msg_info(cpl_func, "---> Compute the strehl");
394 irplib_check(naco_strehl_compute(ima, parlist, RECIPE_STRING, lam, dlam,
395 pos_x, pos_y, pixscale,
396 strehl, strehl_err, &star_bg, &star_peak,
397 &star_flux, &psf_peak,
398 &psf_flux, &bg_noise),
399 "Cannot compute the strehl");
400
401 /* Compute the energy */
402 *energy = irplib_strehl_disk_flux(ima, pos_x, pos_y, ENERGY_RADIUS_PIX,
403 0.0);
404
405 skip_if (0);
406
407 /* Compute the FHWM */
408 skip_if (cpl_image_get_fwhm(ima, (int)pos_x, (int)pos_y, &fwhm_x, &fwhm_y));
409
410 *fwhm = (fwhm_x+fwhm_y)/2.0;
411
412 /* Display results */
413 cpl_msg_info(cpl_func, "Strehl: %g", *strehl);
414 cpl_msg_info(cpl_func, "Strehl error: %g", *strehl_err);
415 cpl_msg_info(cpl_func, "Energy: %g", *energy);
416 cpl_msg_info(cpl_func, "FWHM: %g", *fwhm);
417 cpl_msg_info(cpl_func, "Focus: %g", *focus);
418
419 end_skip;
420
421 cpl_image_delete(ima);
422 cpl_vector_unwrap(sigmas);
423 cpl_apertures_delete(apert);
424
425 return cpl_error_get_code();
426}
427
428
429/*----------------------------------------------------------------------------*/
436/*----------------------------------------------------------------------------*/
437static cpl_error_code naco_img_checkfocus_qc(cpl_propertylist * qclist,
438 const irplib_framelist * rawframes)
439{
440
441 const cpl_propertylist * reflist
442 = irplib_framelist_get_propertylist_const(rawframes, 0);
443
444
445 bug_if (0);
446
447 /* Get the keywords for the paf file */
448 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist,
449 "^(" IRPLIB_PFITS_REGEXP_PAF
450 ")$", 0));
451
452 end_skip;
453
454 return cpl_error_get_code();
455}
456
457/*----------------------------------------------------------------------------*/
465/*----------------------------------------------------------------------------*/
466static
467cpl_error_code naco_img_checkfocus_save(cpl_frameset * self,
468 const cpl_parameterlist * parlist,
469 const cpl_propertylist * qclist)
470{
471
472
473 skip_if(cpl_dfs_save_propertylist(self, NULL, parlist, self, NULL,
474 RECIPE_STRING, qclist, NULL, naco_pipe_id,
475 RECIPE_STRING CPL_DFS_FITS));
476
477#ifdef NACO_SAVE_PAF
478 skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, qclist,
479 RECIPE_STRING CPL_DFS_PAF));
480#endif
481
482 end_skip;
483
484 return cpl_error_get_code();
485}
int naco_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: naco_dfs.c:62
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
double naco_pfits_get_focus(const cpl_propertylist *self)
find out the focus
Definition: naco_pfits.c:220
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