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 #if 0
00038 #include "irplib_distortion.h"
00039 #endif
00040
00041 #include "irplib_wlxcorr.h"
00042
00043 #include "naco_spc.h"
00044
00045 #include "irplib_polynomial.h"
00046 #include "irplib_wavecal.h"
00047 #include "irplib_distortion.h"
00048
00049
00050 #include <string.h>
00051
00052
00053
00054
00055
00056 #define RECIPE_STRING "naco_spc_wavecal"
00057
00058
00059
00060
00061
00062 static cpl_error_code naco_spc_wavecal_reduce(cpl_imagelist *,
00063 cpl_polynomial *,
00064 cpl_propertylist *,
00065 const char *,
00066 const irplib_framelist *,
00067 const cpl_table *,
00068 const cpl_bivector *,
00069 const cpl_parameterlist *);
00070
00071 static cpl_error_code naco_spc_wavecal_get_slitw(const cpl_propertylist *,
00072 double *);
00073
00074
00075 static cpl_error_code naco_spc_wavecal_1d(cpl_imagelist * self,
00076 cpl_propertylist * qclist,
00077 const cpl_image * spec2d,
00078 const cpl_propertylist * plist,
00079 const char * tag,
00080 const cpl_polynomial * phdisp,
00081 const cpl_bivector * argonlines,
00082 const cpl_parameterlist* parlist);
00083
00084 static
00085 cpl_error_code naco_image_fill_column_from_dispersion(cpl_image *, int, cpl_boolean,
00086 const cpl_polynomial *);
00087
00088 static cpl_error_code naco_spc_wavecal_distortion(cpl_image *,
00089 cpl_propertylist *,
00090 const cpl_parameterlist *);
00091
00092 static cpl_error_code naco_spc_physdisp_fill(cpl_polynomial *, const char *,
00093 const cpl_table *);
00094
00095 static cpl_error_code naco_spc_physdisp_transform(cpl_polynomial *, double,
00096 double, int, double, double,
00097 double, double);
00098
00099 static cpl_error_code naco_spc_wavecal_qc(cpl_propertylist *,
00100 cpl_propertylist *,
00101 const irplib_framelist *);
00102
00103 static cpl_error_code naco_spc_wavecal_save(cpl_frameset *,
00104 const cpl_parameterlist *,
00105 const cpl_propertylist *,
00106 const cpl_propertylist *,
00107 const cpl_imagelist *,
00108 const cpl_polynomial *,
00109 int, const irplib_framelist *);
00110
00111 static cpl_error_code naco_spc_wavecal_fill_table(cpl_table *,
00112 const cpl_polynomial *);
00113
00114 static cpl_error_code naco_spc_wavecal_count_lines(cpl_propertylist *,
00115 const cpl_bivector *,
00116 double, double);
00117 static
00118 cpl_error_code naco_spc_wavecal_interpolate_rejected(cpl_image *,
00119 const cpl_polynomial *);
00120
00121 static cpl_error_code naco_spc_wavecal_qc_lines(cpl_propertylist *,
00122 const cpl_image *,
00123 const cpl_apertures *);
00124
00125 NACO_RECIPE_DEFINE(naco_spc_wavecal,
00126 NACO_PARAM_PLOT | NACO_PARAM_FORCE,
00127 "Wavelength calibration using arc lamps",
00128 RECIPE_STRING
00129 " -- NACO spectrocopy wavelength calibration from "
00130 "lamp images.\n"
00131 "The files listed in the Set Of Frames (sof-file) "
00132 "must be tagged:\n"
00133 "NACO-raw-file.fits " NACO_SPC_LAMPWAVE_RAW "\n"
00134 "NACO-spectrum-model.fits " NACO_SPC_MODEL " .\n"
00135 "\n"
00136 NACO_SPC_MAN_MODESPLIT "\n\n"
00137 "Furthermore, each input frame must have a value of "
00138 NACO_PFITS_BOOL_LAMP1 " that is false for off-frames and "
00139 "true for on-frames.\n"
00140 "\n"
00141 "Products:\n"
00142 NACO_CALIB_ARC_MAP ": Primary HDU with the wavelength map, "
00143 "i.e. the pixel values are wavelengths. The first extension "
00144 "is a single-row table with the polynomial coefficients of "
00145 "the 2D dispersion relation, lambda = P(x, y).\n"
00146 NACO_CALIB_ARC_DIFF ": Primary HDU with the difference image "
00147 "of the lamp-on and -off image. The first extension is the "
00148 "distortion corrected image, were all the arc-lines are "
00149 "straight. The dispersion in the distortion corrected image "
00150 "is given by the central dispersion, lambda = P(512.5, y).");
00151
00152
00153
00157
00158
00159
00160
00161
00162
00163
00170
00171 static int naco_spc_wavecal(cpl_frameset * framelist,
00172 const cpl_parameterlist * parlist)
00173 {
00174 cpl_errorstate cleanstate = cpl_errorstate_get();
00175 irplib_framelist * allframes = NULL;
00176 irplib_framelist * rawframes = NULL;
00177 irplib_framelist * f_one = NULL;
00178 const char ** taglist = NULL;
00179 cpl_imagelist * lamp_wave = cpl_imagelist_new();
00180 cpl_polynomial * disp2d = cpl_polynomial_new(2);
00181 cpl_propertylist * qclist = cpl_propertylist_new();
00182 cpl_propertylist * paflist = cpl_propertylist_new();
00183 const cpl_frame * modelframe;
00184 const char * modelfile;
00185 cpl_table * modeltab = NULL;
00186 const cpl_frame * argonframe;
00187 const char * argonfile;
00188 cpl_table * argontab = NULL;
00189 cpl_bivector * argonlines= NULL;
00190 cpl_vector * argonlinex= NULL;
00191 cpl_vector * argonliney= NULL;
00192 int nargonlines;
00193 int nb_good = 0;
00194 int nsets;
00195 int i;
00196
00197
00198
00199 skip_if (naco_dfs_set_groups(framelist));
00200
00201 allframes = irplib_framelist_cast(framelist);
00202 skip_if(allframes == NULL);
00203
00204 rawframes = irplib_framelist_extract(allframes, NACO_SPC_LAMPWAVE_RAW);
00205 skip_if(rawframes == NULL);
00206
00207 irplib_framelist_empty(allframes);
00208
00209
00210 modelframe = cpl_frameset_find_const(framelist, NACO_SPC_MODEL);
00211 error_if (modelframe == NULL, CPL_ERROR_DATA_NOT_FOUND, "No input frame "
00212 "is tagged %s", NACO_SPC_MODEL);
00213
00214 modelfile = cpl_frame_get_filename(modelframe);
00215 skip_if (modelfile == NULL);
00216
00217 modeltab = cpl_table_load(modelfile, 1, 0);
00218 error_if (modeltab == NULL, cpl_error_get_code(), "Could not "
00219 "load the table with the model parameters");
00220
00221
00222 argonframe = cpl_frameset_find_const(framelist, NACO_SPC_ARGON);
00223 error_if (argonframe == NULL, CPL_ERROR_DATA_NOT_FOUND, "No input frame "
00224 "is tagged %s", NACO_SPC_ARGON);
00225
00226 argonfile = cpl_frame_get_filename(argonframe);
00227 skip_if (argonfile == NULL);
00228
00229 argontab = cpl_table_load(argonfile, 1, 0);
00230 error_if (argontab == NULL, cpl_error_get_code(), "Could not "
00231 "load the table with the argon lines");
00232
00233
00234 nargonlines = cpl_table_get_nrow(argontab);
00235
00236 argonlinex = cpl_vector_wrap(nargonlines,
00237 cpl_table_get_data_double(argontab,
00238 NACO_SPC_LAB_WAVE));
00239 skip_if(argonlinex == NULL);
00240
00241 argonliney = cpl_vector_wrap(nargonlines,
00242 cpl_table_get_data_double(argontab,
00243 NACO_SPC_LAB_INTENS));
00244 skip_if(argonliney == NULL);
00245
00246 #ifdef NACO_SPC_WAVECAL_LOG
00247 bug_if(cpl_vector_add_scalar(argonliney, 1.0));
00248 skip_if(cpl_vector_logarithm(argonliney, exp(1.0)));
00249 #endif
00250
00251 argonlines = cpl_bivector_wrap_vectors(argonlinex, argonliney);
00252 bug_if(argonlines == NULL);
00253
00254 skip_if(irplib_framelist_load_propertylist_all(rawframes, 0, "^("
00255 NACO_PFITS_REGEXP_SPCWAVE "|"
00256 NACO_PFITS_REGEXP_SPCWAVE_PAF
00257 ")$", CPL_FALSE));
00258
00259 taglist = naco_framelist_set_tag(rawframes, naco_spc_make_tag, &nsets);
00260 skip_if(taglist == NULL);
00261
00262 cpl_msg_info(cpl_func, "Identified %d setting(s) in %d frames",
00263 nsets, irplib_framelist_get_size(rawframes));
00264
00265
00266 for (i=0 ; i < nsets ; i++) {
00267 int n_one;
00268 cpl_error_code error;
00269
00270
00271 cpl_msg_info(cpl_func, "Reducing data set %d of %d", i+1, nsets);
00272
00273
00274 f_one = irplib_framelist_extract(rawframes, taglist[i]);
00275
00276 bug_if (f_one == NULL);
00277
00278 n_one = irplib_framelist_get_size(f_one);
00279
00280
00281 bug_if(irplib_framelist_set_tag_all(f_one, NACO_SPC_LAMPWAVE_RAW));
00282
00283 cpl_msg_info(cpl_func, "Reducing frame set %d of %d (size=%d) with "
00284 "setting: %s", i+1, nsets, n_one, taglist[i]);
00285
00286 error = naco_spc_wavecal_reduce(lamp_wave, disp2d, qclist, taglist[i],
00287 f_one, modeltab, argonlines, parlist);
00288
00289
00290 if (error) {
00291 if (nsets > 1)
00292 irplib_error_recover(cleanstate, "Could not do the wavelength "
00293 "calibration for this setting");
00294 } else {
00295 cpl_errorstate prestate = cpl_errorstate_get();
00296
00297 skip_if(naco_spc_wavecal_qc(qclist, paflist, f_one));
00298
00299
00300 bug_if (cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,
00301 NACO_CALIB_ARC_MAP));
00302
00303
00304
00305 (void)irplib_framelist_set(f_one, (cpl_frame*)modelframe, n_one);
00306 (void)irplib_framelist_set(f_one, (cpl_frame*)argonframe, n_one+1);
00307 (void)naco_spc_wavecal_save(framelist, parlist, qclist, paflist,
00308 lamp_wave, disp2d, i+1, f_one);
00309 (void)irplib_framelist_unset(f_one, n_one+1, NULL);
00310 (void)irplib_framelist_unset(f_one, n_one, NULL);
00311 skip_if(!cpl_errorstate_is_equal(prestate));
00312
00313 do {
00314 cpl_image_delete(cpl_imagelist_unset(lamp_wave, 0));
00315 } while (cpl_imagelist_get_size(lamp_wave) > 0);
00316
00317 nb_good++;
00318 }
00319 cpl_propertylist_empty(qclist);
00320 cpl_propertylist_empty(paflist);
00321 irplib_framelist_delete(f_one);
00322 f_one = NULL;
00323 }
00324
00325 irplib_ensure(nb_good > 0, CPL_ERROR_DATA_NOT_FOUND,
00326 "None of the %d sets could be reduced", nsets);
00327
00328 end_skip;
00329
00330 cpl_free(taglist);
00331 cpl_imagelist_delete(lamp_wave);
00332 cpl_table_delete(modeltab);
00333 cpl_bivector_unwrap_vectors(argonlines);
00334 (void)cpl_vector_unwrap(argonlinex);
00335 (void)cpl_vector_unwrap(argonliney);
00336 cpl_table_delete(argontab);
00337 irplib_framelist_delete(f_one);
00338 irplib_framelist_delete(allframes);
00339 irplib_framelist_delete(rawframes);
00340 cpl_propertylist_delete(qclist);
00341 cpl_propertylist_delete(paflist);
00342 cpl_polynomial_delete(disp2d);
00343
00344 return cpl_error_get_code();
00345 }
00346
00347
00360
00361 static cpl_error_code naco_spc_wavecal_reduce(cpl_imagelist * imglist,
00362 cpl_polynomial * disp2d,
00363 cpl_propertylist * qclist,
00364 const char * tag,
00365 const irplib_framelist * framelist,
00366 const cpl_table * modeltab,
00367 const cpl_bivector * argonlines,
00368 const cpl_parameterlist * parlist)
00369 {
00370 cpl_image * self = NULL;
00371 cpl_image * corrected = NULL;
00372 cpl_imagelist * difflist = cpl_imagelist_new();
00373 cpl_polynomial * disp1d = NULL;
00374 cpl_polynomial * collapse = cpl_polynomial_new(1);
00375 const int nplot = naco_parameterlist_get_int(parlist, RECIPE_STRING,
00376 NACO_PARAM_PLOT);
00377 const cpl_size deg0 = 0;
00378 cpl_polynomial * phdisp = cpl_polynomial_new(1);
00379 const cpl_propertylist * plist
00380 = irplib_framelist_get_propertylist_const(framelist, 0);
00381 const char * specmode
00382 = irplib_pfits_get_string(plist, NACO_PFITS_STRING_SPECMODE);
00383 const double wlen
00384 = irplib_pfits_get_double(plist, NACO_PFITS_DOUBLE_CWLEN);
00385 cpl_propertylist * lampkeys = cpl_propertylist_new();
00386 cpl_stats * stats = NULL;
00387 double adumin, adumax;
00388 double mse = 0.0;
00389 cpl_vector * center = cpl_vector_new(2);
00390 int ny;
00391
00392 bug_if (0);
00393 bug_if (imglist == NULL);
00394 bug_if (qclist == NULL);
00395 bug_if (framelist == NULL);
00396 bug_if (modeltab == NULL);
00397 bug_if (argonlines == NULL);
00398 bug_if (parlist == NULL);
00399 bug_if (cpl_imagelist_get_size(imglist));
00400
00401
00402 bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_BOOL_LAMP1, 1));
00403 bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_INT_LAMP2, 0));
00404
00405 skip_if(naco_imagelist_load_diff(difflist, framelist, lampkeys));
00406
00407 bug_if(0);
00408
00409 if (cpl_imagelist_get_size(difflist) > 1) {
00410 cpl_msg_warning(cpl_func, "Averaging %d difference images "
00411 "into one image for setting %s",
00412 (int)cpl_imagelist_get_size(difflist), tag);
00413 self = cpl_imagelist_collapse_create(difflist);
00414 } else {
00415 self = cpl_imagelist_unset(difflist, 0);
00416 }
00417
00418 stats = cpl_stats_new_from_image(self, CPL_STATS_MIN | CPL_STATS_MAX);
00419 adumin = cpl_stats_get_min(stats);
00420 adumax = cpl_stats_get_max(stats);
00421
00422 cpl_msg_info(cpl_func, "Difference image for '%s' has ADUs in range: "
00423 "%g -> %g", tag, adumin, adumax);
00424 if (adumin < 0.0) {
00425 cpl_msg_info(cpl_func, "Setting negative ADUs to zero");
00426 bug_if(cpl_image_threshold(self, 0.0, FLT_MAX, 0.0, FLT_MAX));
00427 }
00428
00429 if (nplot > 2) {
00430 cpl_errorstate prestate = cpl_errorstate_get();
00431 cpl_plot_image("", "t 'Difference image'", "", self);
00432 if (!cpl_errorstate_is_equal(prestate)) {
00433 cpl_errorstate_set(prestate);
00434 }
00435 }
00436
00437 corrected = cpl_image_duplicate(self);
00438 skip_if(naco_spc_wavecal_distortion(corrected, qclist, parlist));
00439
00440 ny = cpl_image_get_size_y(self);
00441 bug_if (0);
00442
00443
00444 skip_if(naco_spc_physdisp_fill(phdisp, specmode, modeltab));
00445
00446 cpl_msg_info(cpl_func, "Wavelength range using physical model [micron]: "
00447 "%g -> %g",
00448 cpl_polynomial_eval_1d(phdisp, 0.5, NULL),
00449 cpl_polynomial_eval_1d(phdisp, 0.5 + ny, NULL));
00450
00451 if (naco_parameterlist_get_bool(parlist, RECIPE_STRING, NACO_PARAM_FORCE)) {
00452
00453 const cpl_size idegree = 0;
00454 const double dwlen
00455 = cpl_polynomial_eval_1d(phdisp, 0.5*(1+ny), NULL) - wlen;
00456 const double newval
00457 = cpl_polynomial_get_coeff(phdisp, &idegree) - dwlen;
00458
00459 bug_if(cpl_polynomial_set_coeff(phdisp, &idegree, newval));
00460 }
00461
00462 cpl_msg_info(cpl_func, "Central Wavelength (model <=> CWLEN) [micron]: "
00463 "%g <=> %g", cpl_polynomial_eval_1d(phdisp, 0.5*(1+ny), NULL),
00464 wlen);
00465
00466
00467 skip_if(naco_spc_wavecal_1d(imglist, qclist, self, plist, tag, phdisp,
00468 argonlines, parlist));
00469
00470 skip_if(irplib_polynomial_fit_2d_dispersion(disp2d,
00471 cpl_imagelist_get(imglist, 0),
00472 4, &mse));
00473
00474 cpl_msg_info(cpl_func, "2D-dispersion with MSE=%g for setting %s", mse, tag);
00475 skip_if(cpl_polynomial_dump(disp2d, stdout));
00476
00477 skip_if(naco_spc_wavecal_interpolate_rejected(cpl_imagelist_get(imglist, 0),
00478 disp2d));
00479
00480 bug_if(cpl_vector_set(center, 0, 0.5*(1+cpl_image_get_size_x(self))));
00481 bug_if(cpl_vector_set(center, 1, 0.5*(1+cpl_image_get_size_y(self))));
00482
00483 bug_if(cpl_propertylist_append_double(qclist, "ESO QC WLEN",
00484 cpl_polynomial_eval(disp2d, center)));
00485
00486
00487 bug_if(cpl_polynomial_set_coeff(collapse, °0,
00488 0.5 * (1+cpl_image_get_size_x(self))));
00489
00490 disp1d = cpl_polynomial_extract(disp2d, 0, collapse);
00491 cpl_msg_info(cpl_func, "Central 1D-dispersion (at x=%g)",
00492 0.5*(1+cpl_image_get_size_x(self)));
00493 skip_if(cpl_polynomial_dump(disp1d, stdout));
00494
00495 end_skip;
00496
00497 if (cpl_error_get_code()) {
00498 cpl_image_delete(self);
00499 cpl_image_delete(corrected);
00500 } else {
00501 cpl_imagelist_set(imglist, self, 1);
00502 cpl_imagelist_set(imglist, corrected, 2);
00503 }
00504
00505 cpl_vector_delete(center);
00506 cpl_propertylist_delete(lampkeys);
00507 cpl_imagelist_delete(difflist);
00508 cpl_stats_delete(stats);
00509 cpl_polynomial_delete(phdisp);
00510 cpl_polynomial_delete(disp1d);
00511 cpl_polynomial_delete(collapse);
00512
00513 return cpl_error_get_code();
00514 }
00515
00516
00517
00530
00531 static cpl_error_code naco_spc_wavecal_1d(cpl_imagelist * self,
00532 cpl_propertylist * qclist,
00533 const cpl_image * spec2d,
00534 const cpl_propertylist * plist,
00535 const char * tag,
00536 const cpl_polynomial * phdisp,
00537 const cpl_bivector * argonlines,
00538 const cpl_parameterlist* parlist)
00539 {
00540
00541 cpl_errorstate prestate = cpl_errorstate_get();
00542 const int nx = cpl_image_get_size_x(spec2d);
00543 const int ny = cpl_image_get_size_y(spec2d);
00544 cpl_vector * vspec1d = NULL;
00545 cpl_polynomial * disp = NULL;
00546 cpl_polynomial * dispcen = NULL;
00547 cpl_polynomial * phshift = cpl_polynomial_duplicate(phdisp);
00548 cpl_polynomial * dispdif = cpl_polynomial_new(1);
00549
00550 cpl_vector * linepix
00551 = cpl_vector_wrap(cpl_bivector_get_size(argonlines),
00552 cpl_calloc(cpl_bivector_get_size(argonlines),
00553 sizeof(double)));
00554 double slitw = 0.0;
00555 const double wfwhm = 4.0;
00556 double xtrunc;
00557 double xc, xcmean, xcstdev;
00558 const int nplot = naco_parameterlist_get_int(parlist, RECIPE_STRING,
00559 NACO_PARAM_PLOT);
00560 const int plotstep = nplot > 0 ? nx / (1<<nplot) : nx + 1;
00561 const int degree = cpl_polynomial_get_degree(phdisp);
00562 const int fitdeg = degree > 4 ? degree : 4;
00563 cpl_image * imgdisp = cpl_image_new(nx, ny, cpl_image_get_type(spec2d));
00564 cpl_vector * vxcall = cpl_vector_new(nx);
00565
00566
00567 const int hshiftmax = ny/4;
00568 irplib_line_spectrum_model model;
00569 const double pixstep = 0.25;
00570 const double pixtol = 1e-5;
00571 const int istart = nx/2;
00572 const int maxite = fitdeg * 100;
00573 int ispec = istart;
00574 double wl2dmin = FLT_MAX;
00575 double wl2dmax = 0.0;
00576 cpl_boolean isfirst = CPL_TRUE;
00577
00578 bug_if(0);
00579 bug_if(qclist == NULL);
00580 bug_if(spec2d == NULL);
00581 bug_if(plist == NULL);
00582 bug_if(phdisp == NULL);
00583 bug_if(argonlines == NULL);
00584
00585
00586 skip_if(naco_spc_wavecal_get_slitw(plist, &slitw));
00587
00588 cpl_msg_info(cpl_func, "Slitwidth [pixel]: %g", slitw);
00589
00590 xtrunc = 0.5 * slitw + 5.0 * wfwhm * CPL_MATH_SIG_FWHM;
00591
00592 memset(&model, 0, sizeof(model));
00593 model.wslit = slitw;
00594 model.wfwhm = wfwhm;
00595 model.xtrunc = xtrunc;
00596 model.lines = argonlines;
00597 model.linepix = linepix;
00598 model.cost = 0;
00599
00600 vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
00601 #ifdef NACO_SPC_WAVECAL_LOG
00602 bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
00603 skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
00604 #endif
00605
00606 if (nplot > 0) {
00607 char * title = cpl_sprintf("t 'Uncalibrated 1D-spectrum "
00608 "using %s' w linespoints", tag);
00609 cpl_vector * vphys = cpl_vector_new(ny);
00610 cpl_bivector * bspec1d = cpl_bivector_wrap_vectors(vphys, vspec1d);
00611
00612 (void)cpl_vector_fill_polynomial(vphys, phdisp, 1.0, 1.0);
00613
00614
00615 cpl_plot_bivector("set grid;set xlabel 'Wavelength [micron]';"
00616 "set ylabel 'Intensity [ADU]';", title, "",
00617 bspec1d);
00618 cpl_free(title);
00619 cpl_vector_delete(vphys);
00620 cpl_bivector_unwrap_vectors(bspec1d);
00621 if (!cpl_errorstate_is_equal(prestate)) {
00622 cpl_errorstate_set(prestate);
00623 }
00624 }
00625
00626 skip_if(irplib_polynomial_shift_1d_from_correlation(phshift, vspec1d,
00627 (void*)&model,
00628 irplib_vector_fill_line_spectrum,
00629 hshiftmax, nplot > 0,
00630 NULL));
00631
00632 if (nplot > 0) {
00633 bug_if(irplib_plot_spectrum_and_model(vspec1d, phshift, (void*)&model,
00634 irplib_vector_fill_line_spectrum));
00635 }
00636
00637 bug_if(irplib_polynomial_subtract(dispdif, phshift, phdisp));
00638
00639 cpl_msg_info(cpl_func, "Changes to model polynomial by XC is of degree %d",
00640 (int)cpl_polynomial_get_degree(dispdif));
00641 skip_if(cpl_polynomial_dump(dispdif, stdout));
00642
00643 disp = cpl_polynomial_duplicate(phshift);
00644
00645 dispcen = cpl_polynomial_duplicate(disp);
00646
00647
00648 for (; ispec <= nx; ispec++) {
00649 const unsigned prevcost = model.cost;
00650
00651 if (!isfirst) {
00652 cpl_vector_delete(vspec1d);
00653 vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
00654 #ifdef NACO_SPC_WAVECAL_LOG
00655 bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
00656 skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
00657 #endif
00658 }
00659
00660 xc = 0.0;
00661 if (irplib_polynomial_find_1d_from_correlation
00662 (disp, fitdeg, vspec1d, (void *)&model,
00663 irplib_vector_fill_line_spectrum, pixtol, pixstep, 2, maxite,
00664 &xc)) {
00665 irplib_error_recover(prestate, "Could not calibrate column %d of "
00666 "%d", ispec, nx);
00667 cpl_polynomial_copy(disp, dispcen);
00668 xc = 0.0;
00669 } else {
00670 double wl2d = cpl_polynomial_eval_1d(disp, 0.5, NULL);
00671
00672 if (wl2d < wl2dmin) wl2dmin = wl2d;
00673
00674 wl2d = cpl_polynomial_eval_1d(disp, ny + 0.5, NULL);
00675 if (wl2d > wl2dmax) wl2dmax = wl2d;
00676
00677 if (ispec % plotstep == 0) {
00678 bug_if(irplib_plot_spectrum_and_model
00679 (vspec1d, disp,
00680 (void*)&model,
00681 irplib_vector_fill_line_spectrum));
00682 }
00683 #ifdef IRPLIB_SPC_DUMP
00684
00685 if (ispec == istart) {
00686 irplib_polynomial_tabulate(disp, vspec1d, (void *)&model,
00687 irplib_vector_fill_line_spectrum,
00688 50, 0.1);
00689 }
00690 #endif
00691 }
00692
00693 bug_if(cpl_vector_set(vxcall, ispec-1, xc));
00694
00695 cpl_msg_info(cpl_func, "XC(%d): %g (cost=%u of %u)", ispec, xc,
00696 model.cost-prevcost, model.cost);
00697
00698 bug_if(naco_image_fill_column_from_dispersion(imgdisp, ispec, xc <= 0.0,
00699 disp));
00700
00701 if (isfirst) {
00702 double cdisp;
00703 const double cwl = cpl_polynomial_eval_1d(disp, 0.5*ny + 0.5,
00704 &cdisp);
00705
00706 isfirst = CPL_FALSE;
00707 cpl_msg_info(cpl_func, "Center of setting %s has range %g -> %g "
00708 "-> %g [um], center dispersion %g [nm/pixel] and "
00709 "dispersion (of degree %d):", tag,
00710 cpl_polynomial_eval_1d(disp, 0.5, NULL),
00711 cwl,
00712 cpl_polynomial_eval_1d(disp, ny + 0.5, NULL),
00713 1e3*cdisp,
00714 (int)cpl_polynomial_get_degree(disp));
00715 skip_if(cpl_polynomial_dump(disp, stdout));
00716
00717 cpl_polynomial_copy(dispcen, disp);
00718
00719 bug_if(irplib_polynomial_subtract(dispdif, disp, phshift));
00720
00721 cpl_msg_info(cpl_func, "Changes to model polynomial by search is of"
00722 " degree %d", (int)cpl_polynomial_get_degree(dispdif));
00723 skip_if(cpl_polynomial_dump(dispdif, stdout));
00724
00725 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR",
00726 xc));
00727 }
00728 }
00729
00730
00731 cpl_polynomial_copy(disp, dispcen);
00732
00733 for (ispec = istart-1; ispec > 0; ispec--) {
00734 const unsigned prevcost = model.cost;
00735
00736 cpl_vector_delete(vspec1d);
00737 vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
00738 #ifdef NACO_SPC_WAVECAL_LOG
00739 bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
00740 skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
00741 #endif
00742
00743 xc = 0.0;
00744 if (irplib_polynomial_find_1d_from_correlation
00745 (disp, fitdeg, vspec1d, (void *)&model,
00746 irplib_vector_fill_line_spectrum, pixtol, pixstep, 2, maxite, &xc)) {
00747 if (ispec == 1 && wl2dmin >= wl2dmax) {
00748 error_if (0, cpl_error_get_code(),
00749 "None of the columns could be calibrated");
00750 }
00751
00752 irplib_error_recover(prestate, "Could not calibrate column %d of "
00753 "%d", ispec, nx);
00754 cpl_polynomial_copy(disp, dispcen);
00755 } else {
00756 double wl2d = cpl_polynomial_eval_1d(disp, 0.5, NULL);
00757
00758 if (wl2d < wl2dmin) wl2dmin = wl2d;
00759
00760 wl2d = cpl_polynomial_eval_1d(disp, ny + 0.5, NULL);
00761 if (wl2d > wl2dmax) wl2dmax = wl2d;
00762
00763 if (ispec % plotstep == 0) {
00764 bug_if(irplib_plot_spectrum_and_model
00765 (vspec1d, disp,
00766 (void*)&model,
00767 irplib_vector_fill_line_spectrum));
00768 }
00769 }
00770
00771 bug_if(cpl_vector_set(vxcall, ispec-1, xc));
00772
00773 cpl_msg_info(cpl_func, "XC(%d): %g (cost=%u of %u)", ispec, xc,
00774 model.cost-prevcost, model.cost);
00775
00776 bug_if(naco_image_fill_column_from_dispersion(imgdisp, ispec, xc <= 0.0,
00777 disp));
00778 }
00779
00780 if (nplot > 0) {
00781 cpl_plot_vector("set grid;", "t 'XC over spatial range' w linespoints",
00782 "", vxcall);
00783 }
00784
00785 xcmean = cpl_vector_get_mean(vxcall);
00786 xcstdev = cpl_vector_get_stdev(vxcall);
00787
00788 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR MEAN",
00789 xcmean));
00790 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR STDEV",
00791 xcstdev));
00792
00793 cpl_msg_info(cpl_func,"Cross-correlation mean and stdev for setting %s: %g "
00794 "%g", tag, xcmean, xcstdev);
00795 cpl_msg_info(cpl_func, "Total fitting cost: %u", model.cost);
00796
00797 skip_if(naco_spc_wavecal_count_lines(qclist, argonlines, wl2dmin, wl2dmax));
00798
00799 end_skip;
00800
00801 if (cpl_error_get_code()) {
00802 cpl_image_delete(imgdisp);
00803 } else {
00804 cpl_imagelist_set(self, imgdisp, 0);
00805 }
00806
00807 cpl_vector_delete(linepix);
00808 cpl_vector_delete(vxcall);
00809 cpl_polynomial_delete(dispdif);
00810 cpl_polynomial_delete(disp);
00811 cpl_polynomial_delete(dispcen);
00812 cpl_polynomial_delete(phshift);
00813 cpl_vector_delete(vspec1d);
00814
00815 return cpl_error_get_code();
00816 }
00817
00818
00819
00828
00829 static cpl_error_code naco_spc_physdisp_fill(cpl_polynomial * self,
00830 const char * mode,
00831 const cpl_table * modeltab)
00832 {
00833
00834 int imode;
00835 const int nrows = cpl_table_get_nrow(modeltab);
00836 const char ** smode = cpl_table_get_data_string_const(modeltab,
00837 NACO_SPC_LAB_MODE);
00838
00839 bug_if(self == NULL);
00840 bug_if(mode == NULL);
00841 bug_if(modeltab == NULL);
00842 bug_if(cpl_polynomial_get_dimension(self) != 1);
00843
00844 skip_if (smode == NULL);
00845
00846 for (imode = 0; imode < nrows; imode++) {
00847
00848 skip_if(smode[imode] == NULL);
00849
00850 if (!strcmp(mode, smode[imode])) break;
00851 }
00852
00853 error_if (imode == nrows, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported value "
00854 "'%s' for " NACO_PFITS_STRING_SPECMODE, mode);
00855
00856 cpl_msg_info(cpl_func, "Finding dispersion relation for spectrum mode "
00857 "%d/%d: %s ", imode, nrows, mode);
00858
00859 skip_if(naco_spc_physdisp_transform
00860 (self,
00861 cpl_table_get_double(modeltab, NACO_SPC_LAB_XMIN, imode, NULL),
00862 cpl_table_get_double(modeltab, NACO_SPC_LAB_XMAX, imode, NULL),
00863 cpl_table_get_int (modeltab, NACO_SPC_LAB_ORDER, imode, NULL),
00864 cpl_table_get_double(modeltab, NACO_SPC_LAB_C1, imode, NULL),
00865 cpl_table_get_double(modeltab, NACO_SPC_LAB_C2, imode, NULL),
00866 cpl_table_get_double(modeltab, NACO_SPC_LAB_C3, imode, NULL),
00867 cpl_table_get_double(modeltab, NACO_SPC_LAB_C4, imode, NULL)));
00868
00869 #ifdef NACO_SPC_WAVECAL_S54_3_SH
00870 if (!strcmp("S54_3_SH", mode)) {
00871 double p0 = 1.36983;
00872 double p1 = 0.000165591;
00873 double p2 = 2.86676e-07;
00874 cpl_size degree = 0;
00875
00876 bug_if(cpl_polynomial_set_coeff(self, °ree, p0));
00877 degree++;
00878 bug_if(cpl_polynomial_set_coeff(self, °ree, p1));
00879 degree++;
00880 bug_if(cpl_polynomial_set_coeff(self, °ree, p2));
00881 degree++;
00882 bug_if(cpl_polynomial_set_coeff(self, °ree, 0.0));
00883 degree++;
00884 bug_if(cpl_polynomial_set_coeff(self, °ree, 0.0));
00885
00886 cpl_msg_warning(cpl_func, "Changing phdisp to simple fit:");
00887 skip_if(cpl_polynomial_dump(self, stdout));
00888 }
00889 #endif
00890
00891 end_skip;
00892
00893 return cpl_error_get_code();
00894 }
00895
00896
00897
00912
00913 static cpl_error_code naco_spc_physdisp_transform(cpl_polynomial * self,
00914 double xmin, double xmax,
00915 int fit_order,
00916 double c1, double c2,
00917 double c3, double c4)
00918 {
00919
00920 const double alpha = 2.0/(xmax - xmin);
00921 const double beta = -(xmax + xmin) / (xmax - xmin);
00922 double value;
00923 double lambdamin1, lambdamax1;
00924 double lambdamin2, lambdamax2;
00925 cpl_size degree;
00926
00927 bug_if(self == NULL);
00928 bug_if(cpl_polynomial_get_dimension(self) != 1);
00929
00930
00931 skip_if(xmin >= xmax);
00932
00933 value = 1e-4 * (c1 - 0.5 * c3);
00934 degree = 0;
00935 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00936
00937 value = 1e-4 * (c2 - 1.5 * c4);
00938 degree = 1;
00939 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00940
00941 if (fit_order > 2) {
00942 value = 1e-4 * 1.5 * c3;
00943 degree = 2;
00944 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00945
00946 if (fit_order > 3) {
00947 value = 1e-4 * 2.5 * c4;
00948 degree = 3;
00949 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00950
00951 skip_if(fit_order > 4);
00952 }
00953 } else {
00954 skip_if(fit_order < 2);
00955 }
00956
00957
00958 lambdamin1 = cpl_polynomial_eval_1d(self, -1.0, NULL);
00959 lambdamax1 = cpl_polynomial_eval_1d(self, 1.0, NULL);
00960
00961
00962
00963
00964
00965
00966 bug_if(cpl_polynomial_shift_1d(self, 0, beta));
00967
00968 degree = 1;
00969 value = cpl_polynomial_get_coeff(self, °ree) * alpha;
00970 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00971
00972 if (fit_order > 2) {
00973 degree = 2;
00974 value = cpl_polynomial_get_coeff(self, °ree) * alpha * alpha;
00975 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00976
00977 if (fit_order > 3) {
00978 degree = 3;
00979 value = cpl_polynomial_get_coeff(self, °ree) * alpha * alpha
00980 * alpha;
00981 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00982 }
00983 }
00984
00985 lambdamin2 = cpl_polynomial_eval_1d(self, xmin, NULL);
00986 lambdamax2 = cpl_polynomial_eval_1d(self, xmax, NULL);
00987
00988 skip_if(cpl_polynomial_get_degree(self) != fit_order - 1);
00989
00990 skip_if(cpl_polynomial_dump(self, stdout));
00991
00992 cpl_msg_debug(cpl_func, "Interpolation minimum=%g: %g (%g)", xmin,
00993 lambdamin1, lambdamin2-lambdamin1);
00994 cpl_msg_debug(cpl_func, "Interpolation maximum=%g: %g (%g)", xmax,
00995 lambdamax1, lambdamax2-lambdamax1);
00996
00997 end_skip;
00998
00999 return cpl_error_get_code();
01000 }
01001
01002
01003
01013
01014 static cpl_error_code naco_spc_wavecal_get_slitw(const cpl_propertylist * self,
01015 double * pslitw)
01016 {
01017 const char * sslitw;
01018 int nvals;
01019 unsigned uslitw;
01020 double pixscale;
01021
01022
01023 bug_if(self == NULL);
01024 bug_if(pslitw == NULL);
01025
01026 sslitw = irplib_pfits_get_string(self, NACO_PFITS_STRING_SLITNAME);
01027 skip_if(sslitw == NULL);
01028
01029 nvals = sscanf(sslitw, "Slit_%u", &uslitw);
01030
01031 error_if(nvals != 1, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported value of '"
01032 NACO_PFITS_STRING_SLITNAME ": %s", sslitw);
01033
01034 pixscale = irplib_pfits_get_double(self, NACO_PFITS_DOUBLE_PIXSCALE);
01035 skip_if(0);
01036 error_if(pixscale <= 0.0, CPL_ERROR_ILLEGAL_INPUT, "Non-positive value of '"
01037 NACO_PFITS_DOUBLE_PIXSCALE ": %g", pixscale);
01038
01039 *pslitw = (double)uslitw/(1000.0*pixscale);
01040
01041 end_skip;
01042
01043 return cpl_error_get_code();
01044 }
01045
01046
01047
01057
01058 static cpl_error_code
01059 naco_image_fill_column_from_dispersion(cpl_image * self,
01060 int ispec, cpl_boolean is_bad,
01061 const cpl_polynomial * disp)
01062 {
01063
01064 const int ny = cpl_image_get_size_y(self);
01065 int i;
01066
01067 bug_if(self == NULL);
01068 bug_if(disp == NULL);
01069 bug_if(cpl_polynomial_get_dimension(disp) != 1);
01070 bug_if(cpl_polynomial_get_degree(disp) < 1);
01071
01072 for (i = 1; i <= ny; i++) {
01073 const double value = cpl_polynomial_eval_1d(disp, (double)i, NULL);
01074 cpl_image_set(self, ispec, i, value);
01075 if (is_bad) cpl_image_reject(self, ispec, i);
01076 }
01077
01078 end_skip;
01079
01080 return cpl_error_get_code();
01081 }
01082
01083
01084
01093
01094 static
01095 cpl_error_code naco_spc_wavecal_distortion(cpl_image * self,
01096 cpl_propertylist * qclist,
01097 const cpl_parameterlist * parlist)
01098 {
01099
01100 const int fitdeg = 2;
01101 cpl_image * copy = NULL;
01102 const int nx = cpl_image_get_size_x(self);
01103 const int ny = cpl_image_get_size_y(self);
01104 cpl_apertures * lines = NULL;
01105 cpl_polynomial* distortion = NULL;
01106 cpl_polynomial* yid2d = cpl_polynomial_new(2);
01107 cpl_vector * profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
01108 cpl_size power[] = {0, 1};
01109 const int nplot = naco_parameterlist_get_int(parlist, RECIPE_STRING,
01110 NACO_PARAM_PLOT);
01111 cpl_polynomial* center = cpl_polynomial_new(1);
01112 cpl_polynomial* dist1d = NULL;
01113 cpl_vector * dist1dfix = NULL;
01114 const cpl_size i0 = 0;
01115 const cpl_size i1 = 1;
01116 const double xcent = 0.5*(nx + 1);
01117 const double ycent = 0.5*(ny + 1);
01118
01119 bug_if(0);
01120 bug_if(self == NULL);
01121 bug_if(qclist == NULL);
01122 bug_if(parlist == NULL);
01123
01124
01125
01126 bug_if(cpl_image_turn(self, 1));
01127
01128 distortion = irplib_distortion_estimate(self, 1, 1, nx, ny,
01129 CPL_FALSE, 1e8,
01130 33,
01131 0.33, fitdeg, &lines);
01132
01133 error_if(distortion == NULL, cpl_error_get_code(), "Curvature estimation "
01134 "failed");
01135
01136 if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
01137 skip_if(cpl_polynomial_dump(distortion, stdout));
01138 cpl_apertures_dump(lines, stdout);
01139 }
01140
01141 skip_if(naco_spc_wavecal_qc_lines(qclist, self, lines));
01142
01143
01144 bug_if(cpl_polynomial_set_coeff(yid2d, power, 1.0));
01145
01146
01147 bug_if(cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
01148 CPL_KERNEL_DEF_WIDTH));
01149
01150
01151 copy = cpl_image_duplicate(self);
01152 error_if (cpl_image_warp_polynomial(self, copy, distortion, yid2d, profile,
01153 CPL_KERNEL_DEF_WIDTH, profile,
01154 CPL_KERNEL_DEF_WIDTH),
01155 cpl_error_get_code(), "Distortion correction failed");
01156
01157
01158 bug_if(cpl_image_turn(self, -1));
01159
01160 if (nplot > 1) {
01161 cpl_errorstate prestate = cpl_errorstate_get();
01162 cpl_plot_image("", "t 'Distortion corrected image'", "", self);
01163 if (!cpl_errorstate_is_equal(prestate)) {
01164 cpl_errorstate_set(prestate);
01165 }
01166
01167
01168 (void)cpl_image_turn(copy, -1);
01169
01170 (void)cpl_image_subtract(copy, self);
01171
01172 cpl_plot_image("", "t 'Distortion correction'", "", copy);
01173 if (!cpl_errorstate_is_equal(prestate)) {
01174 cpl_errorstate_set(prestate);
01175 }
01176
01177 }
01178
01179 skip_if(cpl_polynomial_dump(distortion, stdout));
01180
01181
01182 bug_if(cpl_polynomial_set_coeff(center, &i0, xcent));
01183
01184 dist1d = cpl_polynomial_extract(distortion, 1, center);
01185
01186
01187 bug_if(cpl_polynomial_set_coeff(center, &i1, 1.0));
01188 bug_if(cpl_polynomial_set_coeff(center, &i0, 0.0));
01189
01190
01191 bug_if(irplib_polynomial_subtract(center, dist1d, center));
01192
01193 if (cpl_polynomial_get_degree(center) > 0) {
01194 const cpl_size ndist1d = cpl_polynomial_get_degree(dist1d);
01195 cpl_size dist1dnreal;
01196
01197 cpl_msg_info(cpl_func, "On the center column (x=%g) the distortion poly"
01198 "nomial should be P(y)=y, its deviation from that has deg"
01199 "ree %d:", xcent, (int)cpl_polynomial_get_degree(center));
01200 skip_if(cpl_polynomial_dump(center, stdout));
01201
01202 if (ndist1d > 0) {
01203 cpl_errorstate prestate = cpl_errorstate_get();
01204 dist1dfix = cpl_vector_new(ndist1d);
01205 if (irplib_polynomial_solve_1d_all(dist1d, dist1dfix,
01206 &dist1dnreal)) {
01207 dist1dnreal = 0;
01208 irplib_error_recover(prestate, "Could not compute fix-points for "
01209 "%d-degree polynomial", (int)ndist1d);
01210 }
01211 } else {
01212 dist1dnreal = 0;
01213 }
01214
01215 if (dist1dnreal > 0) {
01216 cpl_vector * dist1dfixreal = dist1dnreal == ndist1d ? dist1dfix
01217 : cpl_vector_wrap(dist1dnreal, cpl_vector_get_data(dist1dfix));
01218 cpl_msg_info(cpl_func, "The distortion correction has %d fix-"
01219 "point(s) on the center column:", (int)dist1dnreal);
01220 cpl_vector_dump(dist1dfixreal, stdout);
01221 if (dist1dfixreal != dist1dfix)
01222 (void)cpl_vector_unwrap(dist1dfixreal);
01223 } else if (cpl_polynomial_get_coeff(dist1d, &i0) != 0.0) {
01224
01225 cpl_msg_info(cpl_func, "The distortion correction has "
01226 "no fix-points on the center column");
01227 } else {
01228
01229 cpl_msg_info(cpl_func, "The distortion correction has "
01230 "no fix-points on the center column");
01231 }
01232
01233 cpl_msg_info(cpl_func, "The distortion correction moves the detector "
01234 "center at (%g,%g) by (%g,%g)", xcent, ycent, 0.0,
01235 cpl_polynomial_eval_1d(dist1d, ycent, NULL)-ycent);
01236 } else if (cpl_polynomial_get_coeff(center, &i0) != 0.0) {
01237 cpl_msg_info(cpl_func, "The distortion correction has no fix-points "
01238 "on the center column, their Y-offset are [pixel]: %g",
01239 cpl_polynomial_get_coeff(center, &i0));
01240 } else {
01241 cpl_msg_info(cpl_func, "The distortion correction has all points "
01242 "on the center column (at x=%g) as fix-points", xcent);
01243 }
01244
01245
01246 power[0] = power[1] = 0;
01247 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DIST1",
01248 cpl_polynomial_get_coeff(distortion,
01249 power)));
01250 power[0] = 1;
01251 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTY",
01252 cpl_polynomial_get_coeff(distortion,
01253 power)));
01254 power[0] = 2;
01255 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTYY",
01256 cpl_polynomial_get_coeff(distortion,
01257 power)));
01258
01259 power[0] = power[1] = 1;
01260 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTXY",
01261 cpl_polynomial_get_coeff(distortion,
01262 power)));
01263 power[0] = 0;
01264 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTX",
01265 cpl_polynomial_get_coeff(distortion,
01266 power)));
01267 power[1] = 2;
01268 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTXX",
01269 cpl_polynomial_get_coeff(distortion,
01270 power)));
01271
01272 end_skip;
01273
01274
01275
01276 cpl_image_delete(copy);
01277 cpl_apertures_delete(lines);
01278 cpl_vector_delete(profile);
01279 cpl_vector_delete(dist1dfix);
01280 cpl_polynomial_delete(distortion);
01281 cpl_polynomial_delete(yid2d);
01282 cpl_polynomial_delete(center);
01283 cpl_polynomial_delete(dist1d);
01284
01285 return cpl_error_get_code();
01286 }
01287
01288
01296
01297 static cpl_error_code naco_spc_wavecal_qc(cpl_propertylist * qclist,
01298 cpl_propertylist * paflist,
01299 const irplib_framelist * rawframes)
01300 {
01301
01302 const cpl_propertylist * reflist
01303 = irplib_framelist_get_propertylist_const(rawframes, 0);
01304 const char pafcopy[] = "^(" NACO_PFITS_REGEXP_SPCWAVE_PAF ")$";
01305
01306
01307 bug_if (0);
01308
01309
01310
01311 skip_if (cpl_propertylist_copy_property_regexp(paflist, reflist, pafcopy,
01312 0));
01313 skip_if (cpl_propertylist_append(paflist, qclist));
01314
01315 bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
01316 IRPLIB_PFITS_REGEXP_RECAL_LAMP
01317 ")$", 0));
01318 end_skip;
01319
01320 return cpl_error_get_code();
01321 }
01322
01323
01335
01336 static cpl_error_code naco_spc_wavecal_fill_table(cpl_table * self,
01337 const cpl_polynomial * disp2d)
01338 {
01339
01340 const int degree = cpl_polynomial_get_degree(disp2d);
01341 const char * lunit = "micron";
01342 int i, j;
01343
01344 bug_if (self == NULL);
01345 bug_if (cpl_polynomial_get_dimension(disp2d) != 2);
01346 bug_if (degree < 1);
01347
01348 bug_if(cpl_table_set_size(self, 1));
01349
01350 for (i=0; i <= degree; i++) {
01351 for (j = 0; j <= i; j++) {
01352 const cpl_size powers[2] = {i-j, j};
01353 const double value = cpl_polynomial_get_coeff(disp2d, powers);
01354 char * label = cpl_sprintf("DISP2D_%d_%d", i-j, j);
01355 char * unit = i > 1 ? cpl_sprintf("%s/pixel^%d", lunit, i)
01356 : cpl_sprintf(i ? "%s/pixel" : "%s", lunit);
01357
01358 cpl_table_new_column(self, label, CPL_TYPE_DOUBLE);
01359 cpl_table_set_column_unit(self, label, unit);
01360 cpl_table_set_double(self, label, 0, value);
01361
01362 cpl_free(label);
01363 cpl_free(unit);
01364 bug_if(0);
01365 }
01366 }
01367
01368 end_skip;
01369
01370 return cpl_error_get_code();
01371 }
01372
01373
01386
01387 static cpl_error_code naco_spc_wavecal_save(cpl_frameset * set_tot,
01388 const cpl_parameterlist * parlist,
01389 const cpl_propertylist * qclist,
01390 const cpl_propertylist * paflist,
01391 const cpl_imagelist * lamp_wave,
01392 const cpl_polynomial * disp2d,
01393 int set_nb,
01394 const irplib_framelist * rawframes)
01395 {
01396 cpl_frameset * proframes = irplib_frameset_cast(rawframes);
01397 cpl_table * table2d = cpl_table_new(1);
01398 char * filename = NULL;
01399
01400
01401
01402 bug_if (0);
01403
01404
01405 filename = cpl_sprintf(RECIPE_STRING "_set%02d" CPL_DFS_FITS, set_nb);
01406 skip_if (irplib_dfs_save_image(set_tot, parlist, proframes,
01407 cpl_imagelist_get_const(lamp_wave, 0),
01408 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
01409 NACO_CALIB_ARC_MAP, qclist, NULL,
01410 naco_pipe_id, filename));
01411
01412 bug_if(naco_spc_wavecal_fill_table(table2d, disp2d));
01413
01414 skip_if(cpl_table_save(table2d, NULL, NULL, filename, CPL_IO_EXTEND));
01415
01416
01417 cpl_free(filename);
01418 filename = cpl_sprintf(RECIPE_STRING "_set%02d_diff" CPL_DFS_FITS, set_nb);
01419 skip_if (irplib_dfs_save_image(set_tot, parlist, proframes,
01420 cpl_imagelist_get_const(lamp_wave, 1),
01421 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
01422 NACO_CALIB_ARC_DIFF, qclist, NULL,
01423 naco_pipe_id, filename));
01424
01425 skip_if (cpl_image_save(cpl_imagelist_get_const(lamp_wave, 2), filename,
01426 CPL_BPP_IEEE_FLOAT, NULL, CPL_IO_EXTEND));
01427
01428 #ifdef NACO_SAVE_PAF
01429 cpl_free(filename);
01430 filename = cpl_sprintf(RECIPE_STRING "_set%02d" CPL_DFS_PAF, set_nb);
01431 skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, paflist, filename));
01432 #else
01433 bug_if(paflist == NULL);
01434 #endif
01435
01436 end_skip;
01437
01438 cpl_table_delete(table2d);
01439 cpl_free(filename);
01440 cpl_frameset_delete(proframes);
01441
01442 return cpl_error_get_code();
01443
01444 }
01445
01446
01447
01456
01457 static cpl_error_code naco_spc_wavecal_count_lines(cpl_propertylist * self,
01458 const cpl_bivector * lines,
01459 double wlmin,
01460 double wlmax)
01461 {
01462
01463 const cpl_vector * xlines = cpl_bivector_get_x_const(lines);
01464 const double * dxlines = cpl_vector_get_data_const(xlines);
01465 int minline, maxline;
01466 int clines;
01467
01468
01469 bug_if (self == NULL);
01470 bug_if (lines == NULL);
01471
01472 bug_if (wlmin < 0.0);
01473 bug_if (wlmax < wlmin);
01474
01475
01476 minline = cpl_vector_find(xlines, wlmin);
01477
01478
01479 if (dxlines[minline] < wlmin) minline++;
01480
01481
01482 maxline = cpl_vector_find(xlines, wlmax);
01483
01484
01485 if (dxlines[maxline] > wlmax) maxline--;
01486
01487 clines = maxline >= minline ? maxline - minline : 0;
01488
01489 bug_if(cpl_propertylist_append_int(self, "ESO QC DISP NUMCAT", clines));
01490
01491 end_skip;
01492
01493 return cpl_error_get_code();
01494 }
01495
01496
01504
01505 static cpl_error_code
01506 naco_spc_wavecal_interpolate_rejected(cpl_image * self,
01507 const cpl_polynomial * disp2d)
01508 {
01509
01510 const int nz = cpl_image_count_rejected(self);
01511 const int nx = cpl_image_get_size_x(self);
01512 const int ny = cpl_image_get_size_y(self);
01513 double power[2];
01514 cpl_vector * vpower = cpl_vector_wrap(2, power);
01515 int i, j;
01516 int k = nz;
01517
01518 bug_if(self == NULL);
01519 bug_if(disp2d == NULL);
01520
01521 if (nz > 0) cpl_msg_info(cpl_func, "Interpolating %d poorly calibrated "
01522 "pixels in the wavelength map", nz);
01523
01524 for (i = 1; i <= nx && k > 0; i++) {
01525 for (j = 1; j <= ny && k > 0; j++) {
01526 if (cpl_image_is_rejected(self, i, j)) {
01527 power[0] = (double)i;
01528 power[1] = (double)j;
01529 cpl_image_set(self, i, j, cpl_polynomial_eval(disp2d, vpower));
01530 cpl_image_reject(self, i, j);
01531 k--;
01532 }
01533 }
01534 }
01535
01536 end_skip;
01537
01538 cpl_vector_unwrap(vpower);
01539
01540 return cpl_error_get_code();
01541 }
01542
01543
01544
01553
01554 static cpl_error_code naco_spc_wavecal_qc_lines(cpl_propertylist * self,
01555 const cpl_image * spec2d,
01556 const cpl_apertures * lines)
01557 {
01558
01559 const int nlines = cpl_apertures_get_size(lines);
01560 const int ny = cpl_image_get_size_y(spec2d);
01561 const double ycen = 0.5 * (ny + 1);
01562 int i, igood;
01563 char * label = NULL;
01564 cpl_vector * vmedian = cpl_vector_new(nlines);
01565 double median;
01566
01567 bug_if(self == NULL);
01568 bug_if(spec2d == NULL);
01569 bug_if(lines == NULL);
01570
01571 bug_if(cpl_propertylist_append_int(self, "ESO QC ARCS NUM", nlines));
01572
01573 igood = 0;
01574 for(i = 1; i <= nlines; i++) {
01575 cpl_errorstate prestate = cpl_errorstate_get();
01576 const double flux = cpl_apertures_get_flux(lines, i);
01577 const double xcen = cpl_apertures_get_centroid_x(lines, i);
01578 double fwhm_x, fwhm_y;
01579
01580 if (cpl_image_get_fwhm(spec2d, xcen, ycen, &fwhm_x, &fwhm_y)) {
01581 irplib_error_recover(prestate, "Could not compute the FWHM for "
01582 "aperture %d of %d (with xcentroid=%g, flux=%g",
01583 i, nlines, xcen, flux);
01584 fwhm_x = -1.0;
01585 }
01586
01587 if (fwhm_x > 0.0) {
01588 cpl_vector_set(vmedian, igood++, fwhm_x);
01589 }
01590
01591 cpl_free(label);
01592 label = cpl_sprintf("ESO QC ARCS%d XPOS", i);
01593 cpl_propertylist_append_double(self, label, xcen);
01594
01595 cpl_free(label);
01596 label = cpl_sprintf("ESO QC ARCS%d FWHM", i);
01597
01598 cpl_propertylist_append_double(self, label, fwhm_x);
01599
01600 cpl_free(label);
01601 label = cpl_sprintf("ESO QC ARCS%d FLUX", i);
01602
01603 cpl_propertylist_append_double(self, label, flux);
01604 }
01605 bug_if(0);
01606
01607 bug_if(cpl_propertylist_append_int(self, "ESO QC ARCS NUMGOOD", igood));
01608
01609 if (igood > 0) {
01610 bug_if(cpl_vector_set_size(vmedian, igood));
01611 median = cpl_vector_get_median(vmedian);
01612 } else {
01613 median = -1.0;
01614 }
01615
01616 bug_if(cpl_propertylist_append_double(self, "ESO QC FWHM MED", median));
01617
01618 end_skip;
01619
01620 cpl_vector_delete(vmedian);
01621 cpl_free(label);
01622
01623 return cpl_error_get_code();
01624 }