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(const cpl_propertylist *);
00063
00064 NACO_RECIPE_DEFINE(naco_img_checkfocus,
00065 NACO_PARAM_PLOT |
00066 NACO_PARAM_STAR_R |
00067 NACO_PARAM_BG_RINT |
00068 NACO_PARAM_BG_REXT,
00069 "Focus check recipe",
00070 RECIPE_STRING " -- The focus checking recipe\n"
00071 "The Set Of Frames (sof-file) must specify at least four "
00072 "files and they must be tagged\n"
00073 "NACO-raw-file.fits "NACO_IMG_CHECKFOCUS_RAW"\n"
00074 "The first of the files is used as a dark frame.\n");
00075
00076
00080
00081
00082
00083
00084
00085
00086
00093
00094 static int naco_img_checkfocus(cpl_frameset * framelist,
00095 const cpl_parameterlist * parlist)
00096 {
00097 cpl_errorstate cleanstate = cpl_errorstate_get();
00098 irplib_framelist * allframes = NULL;
00099 irplib_framelist * rawframes = NULL;
00100 cpl_propertylist * qclist = cpl_propertylist_new();
00101 cpl_image * dark = NULL;
00102 cpl_vector * strehl_vec = NULL;
00103 cpl_vector * focus_vec = NULL;
00104 cpl_matrix * focus_mat = NULL;
00105 cpl_vector * focus_res = NULL;
00106 cpl_polynomial * fit_poly = NULL;
00107 const char * darkfile;
00108 int nframes;
00109 int nb_good;
00110 const int degree1 = 1;
00111 const int degree2 = 2;
00112 double best_strehl = DBL_MAX;
00113 double c1, c2;
00114 double optimal_focus, optimal_strehl, mse2, mse1;
00115 int i;
00116
00117
00118 skip_if (naco_dfs_set_groups(framelist));
00119
00120 allframes = irplib_framelist_cast(framelist);
00121 skip_if(allframes == NULL);
00122
00123 rawframes = irplib_framelist_extract(allframes, NACO_IMG_CHECKFOCUS_RAW);
00124 skip_if(rawframes == NULL);
00125 irplib_framelist_empty(allframes);
00126
00127 nframes = irplib_framelist_get_size(rawframes);
00128 irplib_ensure(nframes >= 4, CPL_ERROR_DATA_NOT_FOUND,
00129 "Must have at least 4 (not %d) frames to check the focus",
00130 nframes);
00131
00132 skip_if(irplib_framelist_load_propertylist(rawframes, 0, 0, "^("
00133 NACO_PFITS_REGEXP_CHECKFOCUS "|"
00134 NACO_PFITS_REGEXP_CHECKFOCUS_PAF
00135 ")$", CPL_FALSE));
00136
00137 skip_if(irplib_framelist_load_propertylist_all(rawframes, 0, "^("
00138 NACO_PFITS_REGEXP_CHECKFOCUS
00139 ")$", CPL_FALSE));
00140
00141
00142 cpl_msg_info(cpl_func, "The first frame is used as a dark");
00143 darkfile = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, 0));
00144 skip_if (0);
00145
00146 irplib_check(dark = cpl_image_load(darkfile, CPL_TYPE_FLOAT, 0, 0),
00147 "Could not load the dark from %s", darkfile);
00148
00149
00150 strehl_vec = cpl_vector_new(nframes-1);
00151 focus_vec = cpl_vector_new(nframes-1);
00152
00153 skip_if (naco_img_checkfocus_qc(qclist, rawframes));
00154
00155
00156 nb_good = 0;
00157 for (i=1 ; i < nframes ; i++) {
00158 double focus = DBL_MAX;
00159 double energy = DBL_MAX;
00160 double fwhm = DBL_MAX;
00161 double strehl, strehl_err;
00162
00163 cpl_msg_info(cpl_func, "Reducing frame %d of %d\n", i+1, nframes);
00164
00165
00166 if (naco_img_checkfocus_reduce(parlist, rawframes, i, dark,
00167 &fwhm, &strehl, &strehl_err,
00168 &energy, &focus)) {
00169 naco_error_reset("Could not compute focus for this frame:");
00170 continue;
00171 }
00172
00173
00174 if (strehl_err >= 0.1) continue;
00175
00176
00177 bug_if (cpl_vector_set(strehl_vec, nb_good, strehl));
00178 bug_if (cpl_vector_set(focus_vec, nb_good, focus));
00179
00180 nb_good++;
00181
00182 if (nb_good > 1 && strehl <= best_strehl) continue;
00183
00184
00185 best_strehl = strehl;
00186
00187
00188 bug_if(cpl_propertylist_update_double(qclist, "ESO QC STREHL", strehl));
00189 bug_if(cpl_propertylist_update_double(qclist, "ESO QC STREHL ERROR",
00190 strehl_err));
00191 bug_if(cpl_propertylist_update_double(qclist, "ESO QC FWHM PIX", fwhm));
00192 bug_if(cpl_propertylist_update_double(qclist, "ESO QC ENERGY", energy));
00193 bug_if(cpl_propertylist_update_double(qclist, "ESO QC FOCUS", focus));
00194
00195
00196 }
00197 cpl_image_delete(dark);
00198 dark = NULL;
00199 irplib_framelist_empty(rawframes);
00200
00201 skip_if_lt (nb_good, 3, "frames with a Strehl error less than 0.1");
00202
00203 bug_if (cpl_vector_set_size(strehl_vec, nb_good));
00204 bug_if (cpl_vector_set_size(focus_vec, nb_good));
00205
00206
00207 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE < CPL_VERSION(4, 8, 0)
00208 irplib_check(fit_poly = cpl_polynomial_fit_1d_create(focus_vec, strehl_vec,
00209 degree1, &mse1),
00210 "Cannot fit the strehl/focus");
00211
00212
00213 cpl_polynomial_delete(fit_poly);
00214 irplib_check(fit_poly = cpl_polynomial_fit_1d_create(focus_vec, strehl_vec,
00215 degree2, &mse2),
00216 "Cannot fit the strehl/focus");
00217
00218 #else
00219 focus_res = cpl_vector_new(nb_good);
00220 focus_mat = cpl_matrix_wrap(1, nb_good, cpl_vector_get_data(focus_vec));
00221 fit_poly = cpl_polynomial_new(1);
00222 skip_if(cpl_polynomial_fit(fit_poly, focus_mat, NULL, strehl_vec, NULL,
00223 CPL_FALSE, NULL, °ree1));
00224
00225 bug_if(cpl_vector_fill_polynomial_fit_residual(focus_res, strehl_vec, NULL,
00226 fit_poly, focus_mat, NULL));
00227 mse1 = cpl_vector_product(focus_res, focus_res) / nb_good;
00228
00229 skip_if(cpl_polynomial_fit(fit_poly, focus_mat, NULL, strehl_vec, NULL,
00230 CPL_FALSE, NULL, °ree2));
00231
00232 bug_if(cpl_vector_fill_polynomial_fit_residual(focus_res, strehl_vec, NULL,
00233 fit_poly, focus_mat, NULL));
00234 mse2 = cpl_vector_product(focus_res, focus_res) / nb_good;
00235
00236 cpl_vector_delete(focus_res);
00237 focus_res = NULL;
00238 (void)cpl_matrix_unwrap(focus_mat);
00239 focus_mat = NULL;
00240 #endif
00241 cpl_vector_delete(strehl_vec);
00242 strehl_vec = NULL;
00243 cpl_vector_delete(focus_vec);
00244 focus_vec = NULL;
00245
00246 i = 1;
00247 c1 = cpl_polynomial_get_coeff(fit_poly, &i);
00248 i = 2;
00249 c2 = cpl_polynomial_get_coeff(fit_poly, &i);
00250
00251 irplib_ensure(mse2 < mse1, CPL_ERROR_DATA_NOT_FOUND,
00252 "Ill-defined optimal focus, the strehl ratio "
00253 "appears to be a linear function of the focus value: "
00254 "mse(2)=%g >= mse(1)=%g (c1=%g, c2=%g)",
00255 mse2, mse1, c1, c2);
00256
00257 bug_if (c2 == 0.0);
00258
00259 irplib_ensure(c2 < 0.0, CPL_ERROR_DATA_NOT_FOUND,
00260 "Ill-defined optimal focus, the strehl ratio "
00261 "does not have a single optimal value: mse(2)=%g, c1=%g, "
00262 "c2=%g > 0", mse2, c1, c2);
00263
00264 optimal_focus = -c1/(2.0*c2);
00265
00266
00267 optimal_strehl = cpl_polynomial_eval_1d(fit_poly, optimal_focus, NULL);
00268
00269 cpl_polynomial_delete(fit_poly);
00270 fit_poly = NULL;
00271
00272 cpl_msg_info(cpl_func, "Strehl ratio with optimal Focus(%g): %g "
00273 "(mse(2)=%g < mse(1)=%g)", optimal_focus, optimal_strehl,
00274 mse2, mse1);
00275
00276 bug_if(cpl_propertylist_append_double(qclist, "ESO QC FOCUSOPT",
00277 optimal_focus));
00278
00279 skip_if (naco_img_checkfocus_save(qclist));
00280
00281 end_skip;
00282
00283 cpl_propertylist_delete(qclist);
00284 irplib_framelist_delete(allframes);
00285 irplib_framelist_delete(rawframes);
00286 cpl_image_delete(dark);
00287
00288 (void)cpl_matrix_unwrap(focus_mat);
00289 cpl_vector_delete(focus_res);
00290 cpl_vector_delete(strehl_vec);
00291 cpl_vector_delete(focus_vec);
00292
00293 cpl_polynomial_delete(fit_poly);
00294
00295 return cpl_error_get_code();
00296 }
00297
00298
00312
00313 static cpl_error_code naco_img_checkfocus_reduce(const cpl_parameterlist * parlist,
00314 const irplib_framelist * rawframes,
00315 int iframe,
00316 const cpl_image * dark,
00317 double * fwhm,
00318 double * strehl,
00319 double * strehl_err,
00320 double * energy,
00321 double * focus)
00322 {
00323 const cpl_propertylist * plist;
00324 const char * filter;
00325 double pixscale;
00326 cpl_image * ima = NULL;
00327 cpl_vector * sigmas = NULL;
00328 cpl_apertures * apert = NULL;
00329 const char * file;
00330 double psigmas[] = {5, 2, 1, 0.5};
00331 const int nsigmas = (int)(sizeof(psigmas)/sizeof(double));
00332 int isigma;
00333 double lam, dlam;
00334 double pos_x, pos_y;
00335 double star_bg, star_peak, star_flux, psf_peak, psf_flux,
00336 bg_noise;
00337 double fwhm_x, fwhm_y;
00338 int imax_flux;
00339
00340
00341 skip_if (0);
00342
00343 bug_if (parlist == NULL);
00344 bug_if (rawframes == NULL);
00345 bug_if (dark == NULL);
00346 bug_if (fwhm == NULL);
00347 bug_if (strehl == NULL);
00348 bug_if (strehl_err == NULL);
00349 bug_if (energy == NULL);
00350 bug_if (focus == NULL);
00351
00352 file = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, iframe));
00353
00354
00355 plist = irplib_framelist_get_propertylist_const(rawframes, iframe);
00356 bug_if (0);
00357
00358 filter = naco_pfits_get_filter(plist);
00359 pixscale = naco_pfits_get_pixscale(plist);
00360 *focus = naco_pfits_get_focus(plist);
00361
00362 skip_if (0);
00363
00364
00365 irplib_check(naco_get_filter_infos(filter, &lam, &dlam),
00366 "Cannot get filter infos [%s]", filter);
00367
00368
00369 cpl_msg_info(cpl_func, "---> Load input image and subtract the dark");
00370 ima = cpl_image_load(file, CPL_TYPE_FLOAT, 0, 0);
00371 skip_if (0);
00372
00373 bug_if (cpl_image_subtract(ima, dark));
00374
00375
00376 cpl_msg_info(cpl_func, "---> Detecting a bright star using "
00377 "%d sigma-levels ranging from %g down to %g", nsigmas,
00378 psigmas[0], psigmas[nsigmas-1]);
00379 sigmas = cpl_vector_wrap(nsigmas, psigmas);
00380 apert = cpl_apertures_extract_window(ima, sigmas,
00381 (int)(cpl_image_get_size_x(ima)-STREHL_DEF_LOCATE_SX)/2,
00382 (int)(cpl_image_get_size_y(ima)-STREHL_DEF_LOCATE_SY)/2,
00383 (int)(cpl_image_get_size_x(ima)+STREHL_DEF_LOCATE_SX)/2,
00384 (int)(cpl_image_get_size_y(ima)+STREHL_DEF_LOCATE_SY)/2,
00385 &isigma);
00386 if (apert == NULL) {
00387 cpl_msg_error(cpl_func, "Cannot detect any object");
00388 skip_if(1);
00389 }
00390
00391
00392 skip_if (irplib_apertures_find_max_flux(apert, &imax_flux, 1));
00393
00394 pos_x = cpl_apertures_get_centroid_x(apert, imax_flux);
00395 skip_if (0);
00396 pos_y = cpl_apertures_get_centroid_y(apert, imax_flux);
00397 skip_if (0);
00398
00399 cpl_apertures_delete(apert);
00400 apert = NULL;
00401
00402 cpl_msg_info(cpl_func, "Star detected at sigma=%g, at position: %g %g",
00403 psigmas[isigma], pos_x, pos_y);
00404
00405
00406 cpl_msg_info(cpl_func, "---> Compute the strehl");
00407 irplib_check(irplib_strehl_compute(ima,
00408 STREHL_M1, STREHL_M2, lam, dlam,
00409 pixscale, STREHL_BOX_SIZE,
00410 pos_x, pos_y,
00411 naco_parameterlist_get_double(parlist,
00412 RECIPE_STRING,
00413 NACO_PARAM_STAR_R),
00414 naco_parameterlist_get_double(parlist,
00415 RECIPE_STRING,
00416 NACO_PARAM_BG_RINT),
00417 naco_parameterlist_get_double(parlist,
00418 RECIPE_STRING,
00419 NACO_PARAM_BG_REXT),
00420 -1, -1,
00421 strehl, strehl_err, &star_bg, &star_peak,
00422 &star_flux, &psf_peak,
00423 &psf_flux, &bg_noise),
00424 "Cannot compute the strehl");
00425
00426
00427 *energy = irplib_strehl_disk_flux(ima, pos_x, pos_y, ENERGY_RADIUS_PIX,
00428 0.0);
00429
00430 skip_if (0);
00431
00432
00433 skip_if (cpl_image_get_fwhm(ima, (int)pos_x, (int)pos_y, &fwhm_x, &fwhm_y));
00434
00435 *fwhm = (fwhm_x+fwhm_y)/2.0;
00436
00437
00438 cpl_msg_info(cpl_func, "Strehl: %g", *strehl);
00439 cpl_msg_info(cpl_func, "Strehl error: %g", *strehl_err);
00440 cpl_msg_info(cpl_func, "Energy: %g", *energy);
00441 cpl_msg_info(cpl_func, "FWHM: %g", *fwhm);
00442 cpl_msg_info(cpl_func, "Focus: %g", *focus);
00443
00444 end_skip;
00445
00446 cpl_image_delete(ima);
00447 cpl_vector_unwrap(sigmas);
00448 cpl_apertures_delete(apert);
00449
00450 return cpl_error_get_code();
00451 }
00452
00453
00454
00461
00462 static cpl_error_code naco_img_checkfocus_qc(cpl_propertylist * qclist,
00463 const irplib_framelist * rawframes)
00464 {
00465
00466 const cpl_propertylist * reflist
00467 = irplib_framelist_get_propertylist_const(rawframes, 0);
00468
00469
00470 bug_if (0);
00471
00472
00473 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist,
00474 "^(" IRPLIB_PFITS_REGEXP_PAF
00475 ")$", 0));
00476
00477 end_skip;
00478
00479 return cpl_error_get_code();
00480 }
00481
00482
00489
00490 static cpl_error_code naco_img_checkfocus_save(const cpl_propertylist * qclist)
00491 {
00492
00493 skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, qclist,
00494 RECIPE_STRING CPL_DFS_PAF));
00495
00496 end_skip;
00497
00498 return cpl_error_get_code();
00499 }