36 #include "naco_recipe.h"
37 #include "naco_strehl.h"
38 #include "irplib_strehl.h"
44 #define STREHL_DEF_LOCATE_SX 512
45 #define STREHL_DEF_LOCATE_SY 512
46 #define ENERGY_RADIUS_PIX 11
48 #define RECIPE_STRING "naco_img_checkfocus"
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 *,
60 static cpl_error_code naco_img_checkfocus_qc(cpl_propertylist *,
61 const irplib_framelist *);
63 static cpl_error_code naco_img_checkfocus_save(cpl_frameset *,
64 const cpl_parameterlist *,
65 const cpl_propertylist *);
67 NACO_RECIPE_DEFINE(naco_img_checkfocus,
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");
97 static int naco_img_checkfocus(cpl_frameset * framelist,
98 const cpl_parameterlist * parlist)
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;
112 const cpl_size degree1 = 1;
113 const cpl_size degree2 = 2;
114 double best_strehl = DBL_MAX;
116 double optimal_focus, optimal_strehl, mse2, mse1;
123 skip_if(allframes == NULL);
126 skip_if(rawframes == NULL);
130 irplib_ensure(nframes >= 4, CPL_ERROR_DATA_NOT_FOUND,
131 "Must have at least 4 (not %d) frames to check the focus",
135 NACO_PFITS_REGEXP_CHECKFOCUS
"|"
136 NACO_PFITS_REGEXP_CHECKFOCUS_PAF
140 NACO_PFITS_REGEXP_CHECKFOCUS
144 cpl_msg_info(cpl_func,
"The first frame is used as a dark");
148 irplib_check(dark = cpl_image_load(darkfile, CPL_TYPE_FLOAT, 0, 0),
149 "Could not load the dark from %s", darkfile);
152 strehl_vec = cpl_vector_new(nframes-1);
153 focus_mat = cpl_matrix_new(1, nframes-1);
155 skip_if (naco_img_checkfocus_qc(qclist, rawframes));
159 for (i=1 ; i < nframes ; i++) {
160 double focus = DBL_MAX;
161 double energy = DBL_MAX;
162 double fwhm = DBL_MAX;
163 double strehl, strehl_err;
165 cpl_msg_info(cpl_func,
"Reducing frame %d of %d\n", i+1, nframes);
168 if (naco_img_checkfocus_reduce(parlist, rawframes, i, dark,
169 &fwhm, &strehl, &strehl_err,
171 naco_error_reset(
"Could not compute focus for this frame:");
176 if (strehl_err >= 0.1)
continue;
179 bug_if (cpl_vector_set(strehl_vec, nb_good, strehl));
180 bug_if (cpl_matrix_set(focus_mat, 0, nb_good, focus));
184 if (nb_good > 1 && strehl <= best_strehl)
continue;
187 best_strehl = strehl;
190 bug_if(cpl_propertylist_update_double(qclist,
"ESO QC STREHL", strehl));
191 bug_if(cpl_propertylist_update_double(qclist,
"ESO QC STREHL ERROR",
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));
199 cpl_image_delete(dark);
203 skip_if_lt (nb_good, 3,
"frames with a Strehl error less than 0.1");
205 bug_if (cpl_vector_set_size(strehl_vec, nb_good));
206 bug_if (cpl_matrix_set_size(focus_mat, 1, nb_good));
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, °ree1));
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;
218 skip_if(cpl_polynomial_fit(fit_poly, focus_mat, NULL, strehl_vec, NULL,
219 CPL_FALSE, NULL, °ree2));
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;
225 cpl_vector_delete(focus_res);
227 cpl_vector_delete(strehl_vec);
229 cpl_matrix_delete(focus_mat);
232 c1 = cpl_polynomial_get_coeff(fit_poly, °ree1);
233 c2 = cpl_polynomial_get_coeff(fit_poly, °ree2);
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)",
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);
248 optimal_focus = -c1/(2.0*c2);
251 optimal_strehl = cpl_polynomial_eval_1d(fit_poly, optimal_focus, NULL);
253 cpl_polynomial_delete(fit_poly);
256 cpl_msg_info(cpl_func,
"Strehl ratio with optimal Focus(%g): %g "
257 "(mse(2)=%g < mse(1)=%g)", optimal_focus, optimal_strehl,
260 bug_if(cpl_propertylist_append_double(qclist,
"ESO QC FOCUSOPT",
264 bug_if(cpl_propertylist_append_string(qclist, CPL_DFS_PRO_CATG,
265 NACO_IMG_CHECKFOCUS));
267 skip_if (naco_img_checkfocus_save(framelist, parlist, qclist));
271 cpl_propertylist_delete(qclist);
274 cpl_image_delete(dark);
276 cpl_vector_delete(focus_res);
277 cpl_vector_delete(strehl_vec);
278 cpl_matrix_delete(focus_mat);
280 cpl_polynomial_delete(fit_poly);
282 return cpl_error_get_code();
300 static cpl_error_code naco_img_checkfocus_reduce(
const cpl_parameterlist * parlist,
301 const irplib_framelist * rawframes,
303 const cpl_image * dark,
310 const cpl_propertylist * plist;
313 cpl_image * ima = NULL;
314 cpl_vector * sigmas = NULL;
315 cpl_apertures * apert = NULL;
317 double psigmas[] = {5, 2, 1, 0.5};
318 const int nsigmas = (int)(
sizeof(psigmas)/
sizeof(double));
322 double star_bg, star_peak, star_flux, psf_peak, psf_flux,
324 double fwhm_x, fwhm_y;
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);
353 "Cannot get filter infos [%s]", filter);
356 cpl_msg_info(cpl_func,
"---> Load input image and subtract the dark");
357 ima = cpl_image_load(file, CPL_TYPE_FLOAT, 0, 0);
360 bug_if (cpl_image_subtract(ima, dark));
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,
374 cpl_msg_error(cpl_func,
"Cannot detect any object");
381 pos_x = cpl_apertures_get_centroid_x(apert, imax_flux);
383 pos_y = cpl_apertures_get_centroid_y(apert, imax_flux);
386 cpl_apertures_delete(apert);
389 cpl_msg_info(cpl_func,
"Star detected at sigma=%g, at position: %g %g",
390 psigmas[isigma], pos_x, pos_y);
393 cpl_msg_info(cpl_func,
"---> Compute the strehl");
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");
402 *energy = irplib_strehl_disk_flux(ima, pos_x, pos_y, ENERGY_RADIUS_PIX,
408 skip_if (cpl_image_get_fwhm(ima, (
int)pos_x, (
int)pos_y, &fwhm_x, &fwhm_y));
410 *fwhm = (fwhm_x+fwhm_y)/2.0;
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);
421 cpl_image_delete(ima);
422 cpl_vector_unwrap(sigmas);
423 cpl_apertures_delete(apert);
425 return cpl_error_get_code();
437 static cpl_error_code naco_img_checkfocus_qc(cpl_propertylist * qclist,
438 const irplib_framelist * rawframes)
441 const cpl_propertylist * reflist
448 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist,
449 "^(" IRPLIB_PFITS_REGEXP_PAF
454 return cpl_error_get_code();
467 cpl_error_code naco_img_checkfocus_save(cpl_frameset *
self,
468 const cpl_parameterlist * parlist,
469 const cpl_propertylist * qclist)
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));
478 skip_if (cpl_dfs_save_paf(
"NACO", RECIPE_STRING, qclist,
479 RECIPE_STRING CPL_DFS_PAF));
484 return cpl_error_get_code();
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.
double naco_pfits_get_pixscale(const cpl_propertylist *self)
find out the pixel scale
cpl_error_code naco_get_filter_infos(const char *f, double *lam, double *dlam)
Get the infos of one of the filters.
int naco_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
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
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