NACO Pipeline Reference Manual  4.4.0
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 
54 static 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 
60 static cpl_error_code naco_img_checkfocus_qc(cpl_propertylist *,
61  const irplib_framelist *);
62 
63 static cpl_error_code naco_img_checkfocus_save(cpl_frameset *,
64  const cpl_parameterlist *,
65  const cpl_propertylist *);
66 
67 NACO_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 /*----------------------------------------------------------------------------*/
97 static 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 /*----------------------------------------------------------------------------*/
300 static 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 /*----------------------------------------------------------------------------*/
437 static cpl_error_code naco_img_checkfocus_qc(cpl_propertylist * qclist,
438  const irplib_framelist * rawframes)
439 {
440 
441  const cpl_propertylist * reflist
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 /*----------------------------------------------------------------------------*/
466 static
467 cpl_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 }
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
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.
double naco_pfits_get_focus(const cpl_propertylist *self)
find out the focus
Definition: naco_pfits.c:220
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_framelist_load_propertylist_all(irplib_framelist *self, int ind, const char *regexp, cpl_boolean invert)
Load the propertylists of all frames in the framelist.
irplib_framelist * irplib_framelist_extract(const irplib_framelist *self, const char *tag)
Extract the frames with the given tag from a framelist.
const cpl_frame * irplib_framelist_get_const(const irplib_framelist *self, int pos)
Get the specified frame from the framelist.
void irplib_framelist_delete(irplib_framelist *self)
Deallocate an irplib_framelist with its frames and properties.
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.
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