00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031
00032
00033
00034
00035
00036 #include "naco_recipe.h"
00037 #include "irplib_strehl.h"
00038
00039
00040
00041
00042
00043 #define STREHL_DEF_LOCATE_SX 512
00044 #define STREHL_DEF_LOCATE_SY 512
00045 #define ENERGY_RADIUS_PIX 11
00046
00047 #define RECIPE_STRING "naco_img_checkfocus"
00048
00049
00050
00051
00052
00053 static cpl_error_code naco_img_checkfocus_reduce(const cpl_parameterlist *,
00054 const irplib_framelist *, int,
00055 const cpl_image *, double *,
00056 double *, double *, double *,
00057 double *);
00058
00059 static cpl_error_code naco_img_checkfocus_qc(cpl_propertylist *,
00060 const irplib_framelist *);
00061
00062 static cpl_error_code naco_img_checkfocus_save(cpl_frameset *,
00063 const cpl_parameterlist *,
00064 const cpl_propertylist *);
00065
00066 NACO_RECIPE_DEFINE(naco_img_checkfocus,
00067 NACO_PARAM_PLOT |
00068 NACO_PARAM_STAR_R |
00069 NACO_PARAM_BG_RINT |
00070 NACO_PARAM_BG_REXT,
00071 "Focus check recipe",
00072 RECIPE_STRING " -- The focus checking recipe\n"
00073 "The Set Of Frames (sof-file) must specify at least four "
00074 "files and they must be tagged\n"
00075 "NACO-raw-file.fits "NACO_IMG_CHECKFOCUS_RAW"\n"
00076 "The first of the files is used as a dark frame.\n");
00077
00078
00082
00083
00084
00085
00086
00087
00088
00095
00096 static int naco_img_checkfocus(cpl_frameset * framelist,
00097 const cpl_parameterlist * parlist)
00098 {
00099 cpl_errorstate cleanstate = cpl_errorstate_get();
00100 irplib_framelist * allframes = NULL;
00101 irplib_framelist * rawframes = NULL;
00102 cpl_propertylist * qclist = cpl_propertylist_new();
00103 cpl_image * dark = NULL;
00104 cpl_vector * strehl_vec = NULL;
00105 cpl_matrix * focus_mat = NULL;
00106 cpl_vector * focus_res = NULL;
00107 cpl_polynomial * fit_poly = NULL;
00108 const char * darkfile;
00109 int nframes;
00110 int nb_good;
00111 const cpl_size degree1 = 1;
00112 const cpl_size degree2 = 2;
00113 double best_strehl = DBL_MAX;
00114 double c1, c2;
00115 double optimal_focus, optimal_strehl, mse2, mse1;
00116 int i;
00117
00118
00119 skip_if (naco_dfs_set_groups(framelist));
00120
00121 allframes = irplib_framelist_cast(framelist);
00122 skip_if(allframes == NULL);
00123
00124 rawframes = irplib_framelist_extract(allframes, NACO_IMG_CHECKFOCUS_RAW);
00125 skip_if(rawframes == NULL);
00126 irplib_framelist_empty(allframes);
00127
00128 nframes = irplib_framelist_get_size(rawframes);
00129 irplib_ensure(nframes >= 4, CPL_ERROR_DATA_NOT_FOUND,
00130 "Must have at least 4 (not %d) frames to check the focus",
00131 nframes);
00132
00133 skip_if(irplib_framelist_load_propertylist(rawframes, 0, 0, "^("
00134 NACO_PFITS_REGEXP_CHECKFOCUS "|"
00135 NACO_PFITS_REGEXP_CHECKFOCUS_PAF
00136 ")$", CPL_FALSE));
00137
00138 skip_if(irplib_framelist_load_propertylist_all(rawframes, 0, "^("
00139 NACO_PFITS_REGEXP_CHECKFOCUS
00140 ")$", CPL_FALSE));
00141
00142
00143 cpl_msg_info(cpl_func, "The first frame is used as a dark");
00144 darkfile = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, 0));
00145 skip_if (0);
00146
00147 irplib_check(dark = cpl_image_load(darkfile, CPL_TYPE_FLOAT, 0, 0),
00148 "Could not load the dark from %s", darkfile);
00149
00150
00151 strehl_vec = cpl_vector_new(nframes-1);
00152 focus_mat = cpl_matrix_new(1, nframes-1);
00153
00154 skip_if (naco_img_checkfocus_qc(qclist, rawframes));
00155
00156
00157 nb_good = 0;
00158 for (i=1 ; i < nframes ; i++) {
00159 double focus = DBL_MAX;
00160 double energy = DBL_MAX;
00161 double fwhm = DBL_MAX;
00162 double strehl, strehl_err;
00163
00164 cpl_msg_info(cpl_func, "Reducing frame %d of %d\n", i+1, nframes);
00165
00166
00167 if (naco_img_checkfocus_reduce(parlist, rawframes, i, dark,
00168 &fwhm, &strehl, &strehl_err,
00169 &energy, &focus)) {
00170 naco_error_reset("Could not compute focus for this frame:");
00171 continue;
00172 }
00173
00174
00175 if (strehl_err >= 0.1) continue;
00176
00177
00178 bug_if (cpl_vector_set(strehl_vec, nb_good, strehl));
00179 bug_if (cpl_matrix_set(focus_mat, 0, nb_good, focus));
00180
00181 nb_good++;
00182
00183 if (nb_good > 1 && strehl <= best_strehl) continue;
00184
00185
00186 best_strehl = strehl;
00187
00188
00189 bug_if(cpl_propertylist_update_double(qclist, "ESO QC STREHL", strehl));
00190 bug_if(cpl_propertylist_update_double(qclist, "ESO QC STREHL ERROR",
00191 strehl_err));
00192 bug_if(cpl_propertylist_update_double(qclist, "ESO QC FWHM PIX", fwhm));
00193 bug_if(cpl_propertylist_update_double(qclist, "ESO QC ENERGY", energy));
00194 bug_if(cpl_propertylist_update_double(qclist, "ESO QC FOCUS", focus));
00195
00196
00197 }
00198 cpl_image_delete(dark);
00199 dark = NULL;
00200 irplib_framelist_empty(rawframes);
00201
00202 skip_if_lt (nb_good, 3, "frames with a Strehl error less than 0.1");
00203
00204 bug_if (cpl_vector_set_size(strehl_vec, nb_good));
00205 bug_if (cpl_matrix_set_size(focus_mat, 1, nb_good));
00206
00207
00208 focus_res = cpl_vector_new(nb_good);
00209 fit_poly = cpl_polynomial_new(1);
00210 skip_if(cpl_polynomial_fit(fit_poly, focus_mat, NULL, strehl_vec, NULL,
00211 CPL_FALSE, NULL, °ree1));
00212
00213 bug_if(cpl_vector_fill_polynomial_fit_residual(focus_res, strehl_vec, NULL,
00214 fit_poly, focus_mat, NULL));
00215 mse1 = cpl_vector_product(focus_res, focus_res) / nb_good;
00216
00217 skip_if(cpl_polynomial_fit(fit_poly, focus_mat, NULL, strehl_vec, NULL,
00218 CPL_FALSE, NULL, °ree2));
00219
00220 bug_if(cpl_vector_fill_polynomial_fit_residual(focus_res, strehl_vec, NULL,
00221 fit_poly, focus_mat, NULL));
00222 mse2 = cpl_vector_product(focus_res, focus_res) / nb_good;
00223
00224 cpl_vector_delete(focus_res);
00225 focus_res = NULL;
00226 cpl_vector_delete(strehl_vec);
00227 strehl_vec = NULL;
00228 cpl_matrix_delete(focus_mat);
00229 focus_mat = NULL;
00230
00231 c1 = cpl_polynomial_get_coeff(fit_poly, °ree1);
00232 c2 = cpl_polynomial_get_coeff(fit_poly, °ree2);
00233
00234 irplib_ensure(mse2 < mse1, CPL_ERROR_DATA_NOT_FOUND,
00235 "Ill-defined optimal focus, the strehl ratio "
00236 "appears to be a linear function of the focus value: "
00237 "mse(2)=%g >= mse(1)=%g (c1=%g, c2=%g)",
00238 mse2, mse1, c1, c2);
00239
00240 bug_if (c2 == 0.0);
00241
00242 irplib_ensure(c2 < 0.0, CPL_ERROR_DATA_NOT_FOUND,
00243 "Ill-defined optimal focus, the strehl ratio "
00244 "does not have a single optimal value: mse(2)=%g, c1=%g, "
00245 "c2=%g > 0", mse2, c1, c2);
00246
00247 optimal_focus = -c1/(2.0*c2);
00248
00249
00250 optimal_strehl = cpl_polynomial_eval_1d(fit_poly, optimal_focus, NULL);
00251
00252 cpl_polynomial_delete(fit_poly);
00253 fit_poly = NULL;
00254
00255 cpl_msg_info(cpl_func, "Strehl ratio with optimal Focus(%g): %g "
00256 "(mse(2)=%g < mse(1)=%g)", optimal_focus, optimal_strehl,
00257 mse2, mse1);
00258
00259 bug_if(cpl_propertylist_append_double(qclist, "ESO QC FOCUSOPT",
00260 optimal_focus));
00261
00262
00263 bug_if(cpl_propertylist_append_string(qclist, CPL_DFS_PRO_CATG,
00264 NACO_IMG_CHECKFOCUS));
00265
00266 skip_if (naco_img_checkfocus_save(framelist, parlist, qclist));
00267
00268 end_skip;
00269
00270 cpl_propertylist_delete(qclist);
00271 irplib_framelist_delete(allframes);
00272 irplib_framelist_delete(rawframes);
00273 cpl_image_delete(dark);
00274
00275 cpl_vector_delete(focus_res);
00276 cpl_vector_delete(strehl_vec);
00277 cpl_matrix_delete(focus_mat);
00278
00279 cpl_polynomial_delete(fit_poly);
00280
00281 return cpl_error_get_code();
00282 }
00283
00284
00298
00299 static cpl_error_code naco_img_checkfocus_reduce(const cpl_parameterlist * parlist,
00300 const irplib_framelist * rawframes,
00301 int iframe,
00302 const cpl_image * dark,
00303 double * fwhm,
00304 double * strehl,
00305 double * strehl_err,
00306 double * energy,
00307 double * focus)
00308 {
00309 const cpl_propertylist * plist;
00310 const char * filter;
00311 double pixscale;
00312 cpl_image * ima = NULL;
00313 cpl_vector * sigmas = NULL;
00314 cpl_apertures * apert = NULL;
00315 const char * file;
00316 double psigmas[] = {5, 2, 1, 0.5};
00317 const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
00318 cpl_size isigma;
00319 double lam, dlam;
00320 double pos_x, pos_y;
00321 double star_bg, star_peak, star_flux, psf_peak, psf_flux,
00322 bg_noise;
00323 double fwhm_x, fwhm_y;
00324 int imax_flux;
00325
00326
00327 skip_if (0);
00328
00329 bug_if (parlist == NULL);
00330 bug_if (rawframes == NULL);
00331 bug_if (dark == NULL);
00332 bug_if (fwhm == NULL);
00333 bug_if (strehl == NULL);
00334 bug_if (strehl_err == NULL);
00335 bug_if (energy == NULL);
00336 bug_if (focus == NULL);
00337
00338 file = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, iframe));
00339
00340
00341 plist = irplib_framelist_get_propertylist_const(rawframes, iframe);
00342 bug_if (0);
00343
00344 filter = naco_pfits_get_filter(plist);
00345 pixscale = naco_pfits_get_pixscale(plist);
00346 *focus = naco_pfits_get_focus(plist);
00347
00348 skip_if (0);
00349
00350
00351 irplib_check(naco_get_filter_infos(filter, &lam, &dlam),
00352 "Cannot get filter infos [%s]", filter);
00353
00354
00355 cpl_msg_info(cpl_func, "---> Load input image and subtract the dark");
00356 ima = cpl_image_load(file, CPL_TYPE_FLOAT, 0, 0);
00357 skip_if (0);
00358
00359 bug_if (cpl_image_subtract(ima, dark));
00360
00361
00362 cpl_msg_info(cpl_func, "---> Detecting a bright star using "
00363 "%d sigma-levels ranging from %g down to %g", nsigmas,
00364 psigmas[0], psigmas[nsigmas-1]);
00365 sigmas = cpl_vector_wrap(nsigmas, psigmas);
00366 apert = cpl_apertures_extract_window(ima, sigmas,
00367 (int)(cpl_image_get_size_x(ima)-STREHL_DEF_LOCATE_SX)/2,
00368 (int)(cpl_image_get_size_y(ima)-STREHL_DEF_LOCATE_SY)/2,
00369 (int)(cpl_image_get_size_x(ima)+STREHL_DEF_LOCATE_SX)/2,
00370 (int)(cpl_image_get_size_y(ima)+STREHL_DEF_LOCATE_SY)/2,
00371 &isigma);
00372 if (apert == NULL) {
00373 cpl_msg_error(cpl_func, "Cannot detect any object");
00374 skip_if(1);
00375 }
00376
00377
00378 skip_if (irplib_apertures_find_max_flux(apert, &imax_flux, 1));
00379
00380 pos_x = cpl_apertures_get_centroid_x(apert, imax_flux);
00381 skip_if (0);
00382 pos_y = cpl_apertures_get_centroid_y(apert, imax_flux);
00383 skip_if (0);
00384
00385 cpl_apertures_delete(apert);
00386 apert = NULL;
00387
00388 cpl_msg_info(cpl_func, "Star detected at sigma=%g, at position: %g %g",
00389 psigmas[isigma], pos_x, pos_y);
00390
00391
00392 cpl_msg_info(cpl_func, "---> Compute the strehl");
00393 irplib_check(irplib_strehl_compute(ima,
00394 IRPLIB_STREHL_M1, IRPLIB_STREHL_M2, lam, dlam,
00395 pixscale, IRPLIB_STREHL_BOX_SIZE,
00396 pos_x, pos_y,
00397 naco_parameterlist_get_double(parlist,
00398 RECIPE_STRING,
00399 NACO_PARAM_STAR_R),
00400 naco_parameterlist_get_double(parlist,
00401 RECIPE_STRING,
00402 NACO_PARAM_BG_RINT),
00403 naco_parameterlist_get_double(parlist,
00404 RECIPE_STRING,
00405 NACO_PARAM_BG_REXT),
00406 -1, -1,
00407 strehl, strehl_err, &star_bg, &star_peak,
00408 &star_flux, &psf_peak,
00409 &psf_flux, &bg_noise),
00410 "Cannot compute the strehl");
00411
00412
00413 *energy = irplib_strehl_disk_flux(ima, pos_x, pos_y, ENERGY_RADIUS_PIX,
00414 0.0);
00415
00416 skip_if (0);
00417
00418
00419 skip_if (cpl_image_get_fwhm(ima, (int)pos_x, (int)pos_y, &fwhm_x, &fwhm_y));
00420
00421 *fwhm = (fwhm_x+fwhm_y)/2.0;
00422
00423
00424 cpl_msg_info(cpl_func, "Strehl: %g", *strehl);
00425 cpl_msg_info(cpl_func, "Strehl error: %g", *strehl_err);
00426 cpl_msg_info(cpl_func, "Energy: %g", *energy);
00427 cpl_msg_info(cpl_func, "FWHM: %g", *fwhm);
00428 cpl_msg_info(cpl_func, "Focus: %g", *focus);
00429
00430 end_skip;
00431
00432 cpl_image_delete(ima);
00433 cpl_vector_unwrap(sigmas);
00434 cpl_apertures_delete(apert);
00435
00436 return cpl_error_get_code();
00437 }
00438
00439
00440
00447
00448 static cpl_error_code naco_img_checkfocus_qc(cpl_propertylist * qclist,
00449 const irplib_framelist * rawframes)
00450 {
00451
00452 const cpl_propertylist * reflist
00453 = irplib_framelist_get_propertylist_const(rawframes, 0);
00454
00455
00456 bug_if (0);
00457
00458
00459 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist,
00460 "^(" IRPLIB_PFITS_REGEXP_PAF
00461 ")$", 0));
00462
00463 end_skip;
00464
00465 return cpl_error_get_code();
00466 }
00467
00468
00476
00477 static
00478 cpl_error_code naco_img_checkfocus_save(cpl_frameset * self,
00479 const cpl_parameterlist * parlist,
00480 const cpl_propertylist * qclist)
00481 {
00482
00483
00484 skip_if(cpl_dfs_save_propertylist(self, NULL, parlist, self, NULL,
00485 RECIPE_STRING, qclist, NULL, naco_pipe_id,
00486 RECIPE_STRING CPL_DFS_FITS));
00487
00488 #ifdef NACO_SAVE_PAF
00489 skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, qclist,
00490 RECIPE_STRING CPL_DFS_PAF));
00491 #endif
00492
00493 end_skip;
00494
00495 return cpl_error_get_code();
00496 }