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 int degree1 = 1;
00112 const int 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 i = 1;
00232 c1 = cpl_polynomial_get_coeff(fit_poly, &i);
00233 i = 2;
00234 c2 = cpl_polynomial_get_coeff(fit_poly, &i);
00235
00236 irplib_ensure(mse2 < mse1, CPL_ERROR_DATA_NOT_FOUND,
00237 "Ill-defined optimal focus, the strehl ratio "
00238 "appears to be a linear function of the focus value: "
00239 "mse(2)=%g >= mse(1)=%g (c1=%g, c2=%g)",
00240 mse2, mse1, c1, c2);
00241
00242 bug_if (c2 == 0.0);
00243
00244 irplib_ensure(c2 < 0.0, CPL_ERROR_DATA_NOT_FOUND,
00245 "Ill-defined optimal focus, the strehl ratio "
00246 "does not have a single optimal value: mse(2)=%g, c1=%g, "
00247 "c2=%g > 0", mse2, c1, c2);
00248
00249 optimal_focus = -c1/(2.0*c2);
00250
00251
00252 optimal_strehl = cpl_polynomial_eval_1d(fit_poly, optimal_focus, NULL);
00253
00254 cpl_polynomial_delete(fit_poly);
00255 fit_poly = NULL;
00256
00257 cpl_msg_info(cpl_func, "Strehl ratio with optimal Focus(%g): %g "
00258 "(mse(2)=%g < mse(1)=%g)", optimal_focus, optimal_strehl,
00259 mse2, mse1);
00260
00261 bug_if(cpl_propertylist_append_double(qclist, "ESO QC FOCUSOPT",
00262 optimal_focus));
00263
00264
00265 bug_if(cpl_propertylist_append_string(qclist, CPL_DFS_PRO_CATG,
00266 NACO_IMG_CHECKFOCUS));
00267
00268 skip_if (naco_img_checkfocus_save(framelist, parlist, qclist));
00269
00270 end_skip;
00271
00272 cpl_propertylist_delete(qclist);
00273 irplib_framelist_delete(allframes);
00274 irplib_framelist_delete(rawframes);
00275 cpl_image_delete(dark);
00276
00277 cpl_vector_delete(focus_res);
00278 cpl_vector_delete(strehl_vec);
00279 cpl_matrix_delete(focus_mat);
00280
00281 cpl_polynomial_delete(fit_poly);
00282
00283 return cpl_error_get_code();
00284 }
00285
00286
00300
00301 static cpl_error_code naco_img_checkfocus_reduce(const cpl_parameterlist * parlist,
00302 const irplib_framelist * rawframes,
00303 int iframe,
00304 const cpl_image * dark,
00305 double * fwhm,
00306 double * strehl,
00307 double * strehl_err,
00308 double * energy,
00309 double * focus)
00310 {
00311 const cpl_propertylist * plist;
00312 const char * filter;
00313 double pixscale;
00314 cpl_image * ima = NULL;
00315 cpl_vector * sigmas = NULL;
00316 cpl_apertures * apert = NULL;
00317 const char * file;
00318 double psigmas[] = {5, 2, 1, 0.5};
00319 const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
00320 int isigma;
00321 double lam, dlam;
00322 double pos_x, pos_y;
00323 double star_bg, star_peak, star_flux, psf_peak, psf_flux,
00324 bg_noise;
00325 double fwhm_x, fwhm_y;
00326 int imax_flux;
00327
00328
00329 skip_if (0);
00330
00331 bug_if (parlist == NULL);
00332 bug_if (rawframes == NULL);
00333 bug_if (dark == NULL);
00334 bug_if (fwhm == NULL);
00335 bug_if (strehl == NULL);
00336 bug_if (strehl_err == NULL);
00337 bug_if (energy == NULL);
00338 bug_if (focus == NULL);
00339
00340 file = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, iframe));
00341
00342
00343 plist = irplib_framelist_get_propertylist_const(rawframes, iframe);
00344 bug_if (0);
00345
00346 filter = naco_pfits_get_filter(plist);
00347 pixscale = naco_pfits_get_pixscale(plist);
00348 *focus = naco_pfits_get_focus(plist);
00349
00350 skip_if (0);
00351
00352
00353 irplib_check(naco_get_filter_infos(filter, &lam, &dlam),
00354 "Cannot get filter infos [%s]", filter);
00355
00356
00357 cpl_msg_info(cpl_func, "---> Load input image and subtract the dark");
00358 ima = cpl_image_load(file, CPL_TYPE_FLOAT, 0, 0);
00359 skip_if (0);
00360
00361 bug_if (cpl_image_subtract(ima, dark));
00362
00363
00364 cpl_msg_info(cpl_func, "---> Detecting a bright star using "
00365 "%d sigma-levels ranging from %g down to %g", nsigmas,
00366 psigmas[0], psigmas[nsigmas-1]);
00367 sigmas = cpl_vector_wrap(nsigmas, psigmas);
00368 apert = cpl_apertures_extract_window(ima, sigmas,
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 (int)(cpl_image_get_size_x(ima)+STREHL_DEF_LOCATE_SX)/2,
00372 (int)(cpl_image_get_size_y(ima)+STREHL_DEF_LOCATE_SY)/2,
00373 &isigma);
00374 if (apert == NULL) {
00375 cpl_msg_error(cpl_func, "Cannot detect any object");
00376 skip_if(1);
00377 }
00378
00379
00380 skip_if (irplib_apertures_find_max_flux(apert, &imax_flux, 1));
00381
00382 pos_x = cpl_apertures_get_centroid_x(apert, imax_flux);
00383 skip_if (0);
00384 pos_y = cpl_apertures_get_centroid_y(apert, imax_flux);
00385 skip_if (0);
00386
00387 cpl_apertures_delete(apert);
00388 apert = NULL;
00389
00390 cpl_msg_info(cpl_func, "Star detected at sigma=%g, at position: %g %g",
00391 psigmas[isigma], pos_x, pos_y);
00392
00393
00394 cpl_msg_info(cpl_func, "---> Compute the strehl");
00395 irplib_check(irplib_strehl_compute(ima,
00396 STREHL_M1, STREHL_M2, lam, dlam,
00397 pixscale, STREHL_BOX_SIZE,
00398 pos_x, pos_y,
00399 naco_parameterlist_get_double(parlist,
00400 RECIPE_STRING,
00401 NACO_PARAM_STAR_R),
00402 naco_parameterlist_get_double(parlist,
00403 RECIPE_STRING,
00404 NACO_PARAM_BG_RINT),
00405 naco_parameterlist_get_double(parlist,
00406 RECIPE_STRING,
00407 NACO_PARAM_BG_REXT),
00408 -1, -1,
00409 strehl, strehl_err, &star_bg, &star_peak,
00410 &star_flux, &psf_peak,
00411 &psf_flux, &bg_noise),
00412 "Cannot compute the strehl");
00413
00414
00415 *energy = irplib_strehl_disk_flux(ima, pos_x, pos_y, ENERGY_RADIUS_PIX,
00416 0.0);
00417
00418 skip_if (0);
00419
00420
00421 skip_if (cpl_image_get_fwhm(ima, (int)pos_x, (int)pos_y, &fwhm_x, &fwhm_y));
00422
00423 *fwhm = (fwhm_x+fwhm_y)/2.0;
00424
00425
00426 cpl_msg_info(cpl_func, "Strehl: %g", *strehl);
00427 cpl_msg_info(cpl_func, "Strehl error: %g", *strehl_err);
00428 cpl_msg_info(cpl_func, "Energy: %g", *energy);
00429 cpl_msg_info(cpl_func, "FWHM: %g", *fwhm);
00430 cpl_msg_info(cpl_func, "Focus: %g", *focus);
00431
00432 end_skip;
00433
00434 cpl_image_delete(ima);
00435 cpl_vector_unwrap(sigmas);
00436 cpl_apertures_delete(apert);
00437
00438 return cpl_error_get_code();
00439 }
00440
00441
00442
00449
00450 static cpl_error_code naco_img_checkfocus_qc(cpl_propertylist * qclist,
00451 const irplib_framelist * rawframes)
00452 {
00453
00454 const cpl_propertylist * reflist
00455 = irplib_framelist_get_propertylist_const(rawframes, 0);
00456
00457
00458 bug_if (0);
00459
00460
00461 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist,
00462 "^(" IRPLIB_PFITS_REGEXP_PAF
00463 ")$", 0));
00464
00465 end_skip;
00466
00467 return cpl_error_get_code();
00468 }
00469
00470
00478
00479 static
00480 cpl_error_code naco_img_checkfocus_save(cpl_frameset * self,
00481 const cpl_parameterlist * parlist,
00482 const cpl_propertylist * qclist)
00483 {
00484
00485
00486 skip_if(cpl_dfs_save_propertylist(self, NULL, parlist, self, NULL,
00487 RECIPE_STRING, qclist, NULL, naco_pipe_id,
00488 RECIPE_STRING CPL_DFS_FITS));
00489
00490 #ifdef NACO_SAVE_PAF
00491 skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, qclist,
00492 RECIPE_STRING CPL_DFS_PAF));
00493 #endif
00494
00495 end_skip;
00496
00497 return cpl_error_get_code();
00498 }