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
00301 (void)irplib_framelist_set(f_one, (cpl_frame*)modelframe, n_one);
00302 (void)irplib_framelist_set(f_one, (cpl_frame*)argonframe, n_one+1);
00303 (void)naco_spc_wavecal_save(framelist, parlist, qclist, paflist,
00304 lamp_wave, disp2d, i+1, f_one);
00305 (void)irplib_framelist_unset(f_one, n_one+1, NULL);
00306 (void)irplib_framelist_unset(f_one, n_one, NULL);
00307 skip_if(!cpl_errorstate_is_equal(prestate));
00308
00309 do {
00310 cpl_image_delete(cpl_imagelist_unset(lamp_wave, 0));
00311 } while (cpl_imagelist_get_size(lamp_wave) > 0);
00312
00313 nb_good++;
00314 }
00315 cpl_propertylist_empty(qclist);
00316 cpl_propertylist_empty(paflist);
00317 irplib_framelist_delete(f_one);
00318 f_one = NULL;
00319 }
00320
00321 irplib_ensure(nb_good > 0, CPL_ERROR_DATA_NOT_FOUND,
00322 "None of the %d sets could be reduced", nsets);
00323
00324 end_skip;
00325
00326 cpl_free(taglist);
00327 cpl_imagelist_delete(lamp_wave);
00328 cpl_table_delete(modeltab);
00329 cpl_bivector_unwrap_vectors(argonlines);
00330 (void)cpl_vector_unwrap(argonlinex);
00331 (void)cpl_vector_unwrap(argonliney);
00332 cpl_table_delete(argontab);
00333 irplib_framelist_delete(f_one);
00334 irplib_framelist_delete(allframes);
00335 irplib_framelist_delete(rawframes);
00336 cpl_propertylist_delete(qclist);
00337 cpl_propertylist_delete(paflist);
00338 cpl_polynomial_delete(disp2d);
00339
00340 return cpl_error_get_code();
00341 }
00342
00343
00356
00357 static cpl_error_code naco_spc_wavecal_reduce(cpl_imagelist * imglist,
00358 cpl_polynomial * disp2d,
00359 cpl_propertylist * qclist,
00360 const char * tag,
00361 const irplib_framelist * framelist,
00362 const cpl_table * modeltab,
00363 const cpl_bivector * argonlines,
00364 const cpl_parameterlist * parlist)
00365 {
00366 cpl_image * self = NULL;
00367 cpl_image * corrected = NULL;
00368 cpl_imagelist * difflist = cpl_imagelist_new();
00369 cpl_polynomial * disp1d = NULL;
00370 cpl_polynomial * collapse = cpl_polynomial_new(1);
00371 const int nplot = naco_parameterlist_get_int(parlist, RECIPE_STRING,
00372 NACO_PARAM_PLOT);
00373 const int deg0 = 0;
00374 cpl_polynomial * phdisp = cpl_polynomial_new(1);
00375 const cpl_propertylist * plist
00376 = irplib_framelist_get_propertylist_const(framelist, 0);
00377 const char * specmode
00378 = irplib_pfits_get_string(plist, NACO_PFITS_STRING_SPECMODE);
00379 const double wlen
00380 = irplib_pfits_get_double(plist, NACO_PFITS_DOUBLE_CWLEN);
00381 cpl_propertylist * lampkeys = cpl_propertylist_new();
00382 cpl_stats * stats = NULL;
00383 double adumin, adumax;
00384 double mse = 0.0;
00385 cpl_vector * center = cpl_vector_new(2);
00386 int ny;
00387
00388 bug_if (0);
00389 bug_if (imglist == NULL);
00390 bug_if (qclist == NULL);
00391 bug_if (framelist == NULL);
00392 bug_if (modeltab == NULL);
00393 bug_if (argonlines == NULL);
00394 bug_if (parlist == NULL);
00395 bug_if (cpl_imagelist_get_size(imglist));
00396
00397
00398 bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_BOOL_LAMP1, 1));
00399 bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_INT_LAMP2, 0));
00400
00401 skip_if(naco_imagelist_load_diff(difflist, framelist, lampkeys));
00402
00403 bug_if(0);
00404
00405 if (cpl_imagelist_get_size(difflist) > 1) {
00406 cpl_msg_warning(cpl_func, "Averaging %d difference images into one image "
00407 "for setting %s", cpl_imagelist_get_size(difflist),
00408 tag);
00409 self = cpl_imagelist_collapse_create(difflist);
00410 } else {
00411 self = cpl_imagelist_unset(difflist, 0);
00412 }
00413
00414 stats = cpl_stats_new_from_image(self, CPL_STATS_MIN | CPL_STATS_MAX);
00415 adumin = cpl_stats_get_min(stats);
00416 adumax = cpl_stats_get_max(stats);
00417
00418 cpl_msg_info(cpl_func, "Difference image for '%s' has ADUs in range: "
00419 "%g -> %g", tag, adumin, adumax);
00420 if (adumin < 0.0) {
00421 cpl_msg_info(cpl_func, "Setting negative ADUs to zero");
00422 bug_if(cpl_image_threshold(self, 0.0, FLT_MAX, 0.0, FLT_MAX));
00423 }
00424
00425 if (nplot > 2) {
00426 cpl_errorstate prestate = cpl_errorstate_get();
00427 irplib_image_plot("", "t 'Difference image'", "", self);
00428 if (!cpl_errorstate_is_equal(prestate)) {
00429 cpl_errorstate_set(prestate);
00430 }
00431 }
00432
00433 corrected = cpl_image_duplicate(self);
00434 skip_if(naco_spc_wavecal_distortion(corrected, qclist, parlist));
00435
00436 ny = cpl_image_get_size_y(self);
00437 bug_if (0);
00438
00439
00440 skip_if(naco_spc_physdisp_fill(phdisp, specmode, modeltab));
00441
00442 cpl_msg_info(cpl_func, "Wavelength range using physical model [micron]: "
00443 "%g -> %g",
00444 cpl_polynomial_eval_1d(phdisp, 0.5, NULL),
00445 cpl_polynomial_eval_1d(phdisp, 0.5 + ny, NULL));
00446
00447 if (naco_parameterlist_get_bool(parlist, RECIPE_STRING, NACO_PARAM_FORCE)) {
00448
00449 const int idegree = 0;
00450 const double dwlen
00451 = cpl_polynomial_eval_1d(phdisp, 0.5*(1+ny), NULL) - wlen;
00452 const double newval
00453 = cpl_polynomial_get_coeff(phdisp, &idegree) - dwlen;
00454
00455 bug_if(cpl_polynomial_set_coeff(phdisp, &idegree, newval));
00456 }
00457
00458 cpl_msg_info(cpl_func, "Central Wavelength (model <=> CWLEN) [micron]: "
00459 "%g <=> %g", cpl_polynomial_eval_1d(phdisp, 0.5*(1+ny), NULL),
00460 wlen);
00461
00462
00463 skip_if(naco_spc_wavecal_1d(imglist, qclist, self, plist, tag, phdisp,
00464 argonlines, parlist));
00465
00466 skip_if(irplib_polynomial_fit_2d_dispersion(disp2d,
00467 cpl_imagelist_get(imglist, 0),
00468 4, &mse));
00469
00470 cpl_msg_info(cpl_func, "2D-dispersion with MSE=%g for setting %s", mse, tag);
00471 skip_if(cpl_polynomial_dump(disp2d, stdout));
00472
00473 skip_if(naco_spc_wavecal_interpolate_rejected(cpl_imagelist_get(imglist, 0),
00474 disp2d));
00475
00476 bug_if(cpl_vector_set(center, 0, 0.5*(1+cpl_image_get_size_x(self))));
00477 bug_if(cpl_vector_set(center, 1, 0.5*(1+cpl_image_get_size_y(self))));
00478
00479 bug_if(cpl_propertylist_append_double(qclist, "ESO QC WLEN",
00480 cpl_polynomial_eval(disp2d, center)));
00481
00482
00483 bug_if(cpl_polynomial_set_coeff(collapse, °0,
00484 0.5 * (1+cpl_image_get_size_x(self))));
00485
00486 disp1d = cpl_polynomial_extract(disp2d, 0, collapse);
00487 cpl_msg_info(cpl_func, "Central 1D-dispersion (at x=%g)",
00488 0.5*(1+cpl_image_get_size_x(self)));
00489 skip_if(cpl_polynomial_dump(disp1d, stdout));
00490
00491 end_skip;
00492
00493 if (cpl_error_get_code()) {
00494 cpl_image_delete(self);
00495 cpl_image_delete(corrected);
00496 } else {
00497 cpl_imagelist_set(imglist, self, 1);
00498 cpl_imagelist_set(imglist, corrected, 2);
00499 }
00500
00501 cpl_vector_delete(center);
00502 cpl_propertylist_delete(lampkeys);
00503 cpl_imagelist_delete(difflist);
00504 cpl_stats_delete(stats);
00505 cpl_polynomial_delete(phdisp);
00506 cpl_polynomial_delete(disp1d);
00507 cpl_polynomial_delete(collapse);
00508
00509 return cpl_error_get_code();
00510 }
00511
00512
00513
00526
00527 static cpl_error_code naco_spc_wavecal_1d(cpl_imagelist * self,
00528 cpl_propertylist * qclist,
00529 const cpl_image * spec2d,
00530 const cpl_propertylist * plist,
00531 const char * tag,
00532 const cpl_polynomial * phdisp,
00533 const cpl_bivector * argonlines,
00534 const cpl_parameterlist* parlist)
00535 {
00536
00537 cpl_errorstate prestate = cpl_errorstate_get();
00538 const int nx = cpl_image_get_size_x(spec2d);
00539 const int ny = cpl_image_get_size_y(spec2d);
00540 cpl_vector * vspec1d = NULL;
00541 cpl_polynomial * disp = NULL;
00542 cpl_polynomial * dispcen = NULL;
00543 cpl_polynomial * phshift = cpl_polynomial_duplicate(phdisp);
00544 cpl_polynomial * dispdif = cpl_polynomial_new(1);
00545
00546 cpl_vector * linepix
00547 = cpl_vector_wrap(cpl_bivector_get_size(argonlines),
00548 cpl_calloc(cpl_bivector_get_size(argonlines),
00549 sizeof(double)));
00550 double slitw = 0.0;
00551 const double wfwhm = 4.0;
00552 double xtrunc;
00553 double xc, xcmean, xcstdev;
00554 const int nplot = naco_parameterlist_get_int(parlist, RECIPE_STRING,
00555 NACO_PARAM_PLOT);
00556 const int plotstep = nplot > 0 ? nx / (1<<nplot) : nx + 1;
00557 const int degree = cpl_polynomial_get_degree(phdisp);
00558 const int fitdeg = degree > 4 ? degree : 4;
00559 cpl_image * imgdisp = cpl_image_new(nx, ny, cpl_image_get_type(spec2d));
00560 cpl_vector * vxcall = cpl_vector_new(nx);
00561
00562
00563 const int hshiftmax = ny/4;
00564 irplib_line_spectrum_model model;
00565 const double pixstep = 0.25;
00566 const double pixtol = 1e-5;
00567 const int istart = nx/2;
00568 const int maxite = fitdeg * 100;
00569 int ispec = istart;
00570 double wl2dmin = FLT_MAX;
00571 double wl2dmax = 0.0;
00572 cpl_boolean isfirst = CPL_TRUE;
00573
00574 bug_if(0);
00575 bug_if(qclist == NULL);
00576 bug_if(spec2d == NULL);
00577 bug_if(plist == NULL);
00578 bug_if(phdisp == NULL);
00579 bug_if(argonlines == NULL);
00580
00581
00582 skip_if(naco_spc_wavecal_get_slitw(plist, &slitw));
00583
00584 cpl_msg_info(cpl_func, "Slitwidth [pixel]: %g", slitw);
00585
00586 xtrunc = 0.5 * slitw + 5.0 * wfwhm * CPL_MATH_SIG_FWHM;
00587
00588 model.wslit = slitw;
00589 model.wfwhm = wfwhm;
00590 model.xtrunc = xtrunc;
00591 model.lines = argonlines;
00592 model.linepix = linepix;
00593 model.cost = 0;
00594
00595 vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
00596 #ifdef NACO_SPC_WAVECAL_LOG
00597 bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
00598 skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
00599 #endif
00600
00601 if (nplot > 0) {
00602 char * title = cpl_sprintf("t 'Uncalibrated 1D-spectrum "
00603 "using %s' w linespoints", tag);
00604 cpl_vector * vphys = cpl_vector_new(ny);
00605 cpl_bivector * bspec1d = cpl_bivector_wrap_vectors(vphys, vspec1d);
00606
00607 (void)cpl_vector_fill_polynomial(vphys, phdisp, 1.0, 1.0);
00608
00609
00610 irplib_bivector_plot("set grid;set xlabel 'Wavelength [micron]';"
00611 "set ylabel 'Intensity [ADU]';", title, "",
00612 bspec1d);
00613 cpl_free(title);
00614 cpl_vector_delete(vphys);
00615 cpl_bivector_unwrap_vectors(bspec1d);
00616 if (!cpl_errorstate_is_equal(prestate)) {
00617 cpl_errorstate_set(prestate);
00618 }
00619 }
00620
00621 skip_if(irplib_polynomial_shift_1d_from_correlation(phshift, vspec1d,
00622 (void*)&model,
00623 irplib_vector_fill_line_spectrum,
00624 hshiftmax, nplot > 0));
00625
00626 if (nplot > 0) {
00627 bug_if(irplib_plot_spectrum_and_model(vspec1d, phshift, (void*)&model,
00628 irplib_vector_fill_line_spectrum));
00629 }
00630
00631 bug_if(irplib_polynomial_subtract(dispdif, phshift, phdisp));
00632
00633 cpl_msg_info(cpl_func, "Changes to model polynomial by XC is of degree %d",
00634 cpl_polynomial_get_degree(dispdif));
00635 skip_if(cpl_polynomial_dump(dispdif, stdout));
00636
00637 disp = cpl_polynomial_duplicate(phshift);
00638
00639 dispcen = cpl_polynomial_duplicate(disp);
00640
00641
00642 for (; ispec <= nx; ispec++) {
00643 const unsigned prevcost = model.cost;
00644
00645 if (!isfirst) {
00646 cpl_vector_delete(vspec1d);
00647 vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
00648 #ifdef NACO_SPC_WAVECAL_LOG
00649 bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
00650 skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
00651 #endif
00652 }
00653
00654 xc = 0.0;
00655 if (irplib_polynomial_find_1d_from_correlation
00656 (disp, fitdeg, vspec1d, (void *)&model,
00657 irplib_vector_fill_line_spectrum, pixtol, pixstep, 2, maxite,
00658 &xc)) {
00659 irplib_error_recover(prestate, "Could not calibrate column %d of "
00660 "%d", ispec, nx);
00661 cpl_polynomial_copy(disp, dispcen);
00662 xc = 0.0;
00663 } else {
00664 double wl2d = cpl_polynomial_eval_1d(disp, 0.5, NULL);
00665
00666 if (wl2d < wl2dmin) wl2dmin = wl2d;
00667
00668 wl2d = cpl_polynomial_eval_1d(disp, ny + 0.5, NULL);
00669 if (wl2d > wl2dmax) wl2dmax = wl2d;
00670
00671 if (ispec % plotstep == 0) {
00672 bug_if(irplib_plot_spectrum_and_model
00673 (vspec1d, disp,
00674 (void*)&model,
00675 irplib_vector_fill_line_spectrum));
00676 }
00677 #ifdef IRPLIB_SPC_DUMP
00678
00679 if (ispec == istart) {
00680 irplib_polynomial_tabulate(disp, vspec1d, (void *)&model,
00681 irplib_vector_fill_line_spectrum,
00682 50, 0.1);
00683 }
00684 #endif
00685 }
00686
00687 bug_if(cpl_vector_set(vxcall, ispec-1, xc));
00688
00689 cpl_msg_info(cpl_func, "XC(%d): %g (cost=%u of %u)", ispec, xc,
00690 model.cost-prevcost, model.cost);
00691
00692 bug_if(naco_image_fill_column_from_dispersion(imgdisp, ispec, xc <= 0.0,
00693 disp));
00694
00695 if (isfirst) {
00696 double cdisp;
00697 const double cwl = cpl_polynomial_eval_1d(disp, 0.5*ny + 0.5,
00698 &cdisp);
00699
00700 isfirst = CPL_FALSE;
00701 cpl_msg_info(cpl_func, "Center of setting %s has range %g -> %g "
00702 "-> %g [um], center dispersion %g [nm/pixel] and "
00703 "dispersion (of degree %d):", tag,
00704 cpl_polynomial_eval_1d(disp, 0.5, NULL),
00705 cwl,
00706 cpl_polynomial_eval_1d(disp, ny + 0.5, NULL),
00707 1e3*cdisp,
00708 cpl_polynomial_get_degree(disp));
00709 skip_if(cpl_polynomial_dump(disp, stdout));
00710
00711 cpl_polynomial_copy(dispcen, disp);
00712
00713 bug_if(irplib_polynomial_subtract(dispdif, disp, phshift));
00714
00715 cpl_msg_info(cpl_func, "Changes to model polynomial by search is "
00716 "of degree %d", cpl_polynomial_get_degree(dispdif));
00717 skip_if(cpl_polynomial_dump(dispdif, stdout));
00718
00719 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR",
00720 xc));
00721 }
00722 }
00723
00724
00725 cpl_polynomial_copy(disp, dispcen);
00726
00727 for (ispec = istart-1; ispec > 0; ispec--) {
00728 const unsigned prevcost = model.cost;
00729
00730 cpl_vector_delete(vspec1d);
00731 vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
00732 #ifdef NACO_SPC_WAVECAL_LOG
00733 bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
00734 skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
00735 #endif
00736
00737 xc = 0.0;
00738 if (irplib_polynomial_find_1d_from_correlation
00739 (disp, fitdeg, vspec1d, (void *)&model,
00740 irplib_vector_fill_line_spectrum, pixtol, pixstep, 2, maxite, &xc)) {
00741 if (ispec == 1 && wl2dmin >= wl2dmax) {
00742 error_if (0, cpl_error_get_code(),
00743 "None of the columns could be calibrated");
00744 }
00745
00746 irplib_error_recover(prestate, "Could not calibrate column %d of "
00747 "%d", ispec, nx);
00748 cpl_polynomial_copy(disp, dispcen);
00749 } else {
00750 double wl2d = cpl_polynomial_eval_1d(disp, 0.5, NULL);
00751
00752 if (wl2d < wl2dmin) wl2dmin = wl2d;
00753
00754 wl2d = cpl_polynomial_eval_1d(disp, ny + 0.5, NULL);
00755 if (wl2d > wl2dmax) wl2dmax = wl2d;
00756
00757 if (ispec % plotstep == 0) {
00758 bug_if(irplib_plot_spectrum_and_model
00759 (vspec1d, disp,
00760 (void*)&model,
00761 irplib_vector_fill_line_spectrum));
00762 }
00763 }
00764
00765 bug_if(cpl_vector_set(vxcall, ispec-1, xc));
00766
00767 cpl_msg_info(cpl_func, "XC(%d): %g (cost=%u of %u)", ispec, xc,
00768 model.cost-prevcost, model.cost);
00769
00770 bug_if(naco_image_fill_column_from_dispersion(imgdisp, ispec, xc <= 0.0,
00771 disp));
00772 }
00773
00774 if (nplot > 0) {
00775 irplib_vector_plot("set grid;", "t 'XC over spatial range' w linespoints",
00776 "", vxcall);
00777 }
00778
00779 xcmean = cpl_vector_get_mean(vxcall);
00780 xcstdev = cpl_vector_get_stdev(vxcall);
00781
00782 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR MEAN",
00783 xcmean));
00784 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR STDEV",
00785 xcstdev));
00786
00787 cpl_msg_info(cpl_func,"Cross-correlation mean and stdev for setting %s: %g "
00788 "%g", tag, xcmean, xcstdev);
00789 cpl_msg_info(cpl_func, "Total fitting cost: %u", model.cost);
00790
00791 skip_if(naco_spc_wavecal_count_lines(qclist, argonlines, wl2dmin, wl2dmax));
00792
00793 end_skip;
00794
00795 if (cpl_error_get_code()) {
00796 cpl_image_delete(imgdisp);
00797 } else {
00798 cpl_imagelist_set(self, imgdisp, 0);
00799 }
00800
00801 cpl_vector_delete(linepix);
00802 cpl_vector_delete(vxcall);
00803 cpl_polynomial_delete(dispdif);
00804 cpl_polynomial_delete(disp);
00805 cpl_polynomial_delete(dispcen);
00806 cpl_polynomial_delete(phshift);
00807 cpl_vector_delete(vspec1d);
00808
00809 return cpl_error_get_code();
00810 }
00811
00812
00813
00822
00823 static cpl_error_code naco_spc_physdisp_fill(cpl_polynomial * self,
00824 const char * mode,
00825 const cpl_table * modeltab)
00826 {
00827
00828 int imode;
00829 const int nrows = cpl_table_get_nrow(modeltab);
00830 const char ** smode = cpl_table_get_data_string_const(modeltab,
00831 NACO_SPC_LAB_MODE);
00832
00833 bug_if(self == NULL);
00834 bug_if(mode == NULL);
00835 bug_if(modeltab == NULL);
00836 bug_if(cpl_polynomial_get_dimension(self) != 1);
00837
00838 skip_if (smode == NULL);
00839
00840 for (imode = 0; imode < nrows; imode++) {
00841
00842 skip_if(smode[imode] == NULL);
00843
00844 if (!strcmp(mode, smode[imode])) break;
00845 }
00846
00847 error_if (imode == nrows, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported value "
00848 "'%s' for " NACO_PFITS_STRING_SPECMODE, mode);
00849
00850 cpl_msg_info(cpl_func, "Finding dispersion relation for spectrum mode "
00851 "%d/%d: %s ", imode, nrows, mode);
00852
00853 skip_if(naco_spc_physdisp_transform
00854 (self,
00855 cpl_table_get_double(modeltab, NACO_SPC_LAB_XMIN, imode, NULL),
00856 cpl_table_get_double(modeltab, NACO_SPC_LAB_XMAX, imode, NULL),
00857 cpl_table_get_int (modeltab, NACO_SPC_LAB_ORDER, imode, NULL),
00858 cpl_table_get_double(modeltab, NACO_SPC_LAB_C1, imode, NULL),
00859 cpl_table_get_double(modeltab, NACO_SPC_LAB_C2, imode, NULL),
00860 cpl_table_get_double(modeltab, NACO_SPC_LAB_C3, imode, NULL),
00861 cpl_table_get_double(modeltab, NACO_SPC_LAB_C4, imode, NULL)));
00862
00863 #ifdef NACO_SPC_WAVECAL_S54_3_SH
00864 if (!strcmp("S54_3_SH", mode)) {
00865 double p0 = 1.36983;
00866 double p1 = 0.000165591;
00867 double p2 = 2.86676e-07;
00868 int degree = 0;
00869
00870 bug_if(cpl_polynomial_set_coeff(self, °ree, p0));
00871 degree++;
00872 bug_if(cpl_polynomial_set_coeff(self, °ree, p1));
00873 degree++;
00874 bug_if(cpl_polynomial_set_coeff(self, °ree, p2));
00875 degree++;
00876 bug_if(cpl_polynomial_set_coeff(self, °ree, 0.0));
00877 degree++;
00878 bug_if(cpl_polynomial_set_coeff(self, °ree, 0.0));
00879
00880 cpl_msg_warning(cpl_func, "Changing phdisp to simple fit:");
00881 skip_if(cpl_polynomial_dump(self, stdout));
00882 }
00883 #endif
00884
00885 end_skip;
00886
00887 return cpl_error_get_code();
00888 }
00889
00890
00891
00906
00907 static cpl_error_code naco_spc_physdisp_transform(cpl_polynomial * self,
00908 double xmin, double xmax,
00909 int fit_order,
00910 double c1, double c2,
00911 double c3, double c4)
00912 {
00913
00914 const double alpha = 2.0/(xmax - xmin);
00915 const double beta = -(xmax + xmin) / (xmax - xmin);
00916 double value;
00917 double lambdamin1, lambdamax1;
00918 double lambdamin2, lambdamax2;
00919 int degree;
00920
00921 bug_if(self == NULL);
00922 bug_if(cpl_polynomial_get_dimension(self) != 1);
00923
00924
00925 skip_if(xmin >= xmax);
00926
00927 value = 1e-4 * (c1 - 0.5 * c3);
00928 degree = 0;
00929 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00930
00931 value = 1e-4 * (c2 - 1.5 * c4);
00932 degree = 1;
00933 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00934
00935 if (fit_order > 2) {
00936 value = 1e-4 * 1.5 * c3;
00937 degree = 2;
00938 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00939
00940 if (fit_order > 3) {
00941 value = 1e-4 * 2.5 * c4;
00942 degree = 3;
00943 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00944
00945 skip_if(fit_order > 4);
00946 }
00947 } else {
00948 skip_if(fit_order < 2);
00949 }
00950
00951
00952 lambdamin1 = cpl_polynomial_eval_1d(self, -1.0, NULL);
00953 lambdamax1 = cpl_polynomial_eval_1d(self, 1.0, NULL);
00954
00955
00956
00957
00958
00959
00960 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE > CPL_VERSION(4, 5, 0)
00961 bug_if(cpl_polynomial_shift_1d(self, 0, beta));
00962 #else
00963 bug_if(cpl_polynomial_shift_1d(self, beta));
00964 #endif
00965
00966 degree = 1;
00967 value = cpl_polynomial_get_coeff(self, °ree) * alpha;
00968 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00969
00970 if (fit_order > 2) {
00971 degree = 2;
00972 value = cpl_polynomial_get_coeff(self, °ree) * alpha * alpha;
00973 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00974
00975 if (fit_order > 3) {
00976 degree = 3;
00977 value = cpl_polynomial_get_coeff(self, °ree) * alpha * alpha
00978 * alpha;
00979 bug_if(cpl_polynomial_set_coeff(self, °ree, value));
00980 }
00981 }
00982
00983 lambdamin2 = cpl_polynomial_eval_1d(self, xmin, NULL);
00984 lambdamax2 = cpl_polynomial_eval_1d(self, xmax, NULL);
00985
00986 skip_if(cpl_polynomial_get_degree(self) != fit_order - 1);
00987
00988 skip_if(cpl_polynomial_dump(self, stdout));
00989
00990 cpl_msg_debug(cpl_func, "Interpolation minimum=%g: %g (%g)", xmin,
00991 lambdamin1, lambdamin2-lambdamin1);
00992 cpl_msg_debug(cpl_func, "Interpolation maximum=%g: %g (%g)", xmax,
00993 lambdamax1, lambdamax2-lambdamax1);
00994
00995 end_skip;
00996
00997 return cpl_error_get_code();
00998 }
00999
01000
01001
01011
01012 static cpl_error_code naco_spc_wavecal_get_slitw(const cpl_propertylist * self,
01013 double * pslitw)
01014 {
01015 const char * sslitw;
01016 int nvals;
01017 unsigned uslitw;
01018 double pixscale;
01019
01020
01021 bug_if(self == NULL);
01022 bug_if(pslitw == NULL);
01023
01024 sslitw = irplib_pfits_get_string(self, NACO_PFITS_STRING_SLITNAME);
01025 skip_if(sslitw == NULL);
01026
01027 nvals = sscanf(sslitw, "Slit_%u", &uslitw);
01028
01029 error_if(nvals != 1, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported value of '"
01030 NACO_PFITS_STRING_SLITNAME ": %s", sslitw);
01031
01032 pixscale = irplib_pfits_get_double(self, NACO_PFITS_DOUBLE_PIXSCALE);
01033 skip_if(0);
01034 error_if(pixscale <= 0.0, CPL_ERROR_ILLEGAL_INPUT, "Non-positive value of '"
01035 NACO_PFITS_DOUBLE_PIXSCALE ": %g", pixscale);
01036
01037 *pslitw = (double)uslitw/(1000.0*pixscale);
01038
01039 end_skip;
01040
01041 return cpl_error_get_code();
01042 }
01043
01044
01045
01055
01056 static cpl_error_code
01057 naco_image_fill_column_from_dispersion(cpl_image * self,
01058 int ispec, cpl_boolean is_bad,
01059 const cpl_polynomial * disp)
01060 {
01061
01062 const int ny = cpl_image_get_size_y(self);
01063 int i;
01064
01065 bug_if(self == NULL);
01066 bug_if(disp == NULL);
01067 bug_if(cpl_polynomial_get_dimension(disp) != 1);
01068 bug_if(cpl_polynomial_get_degree(disp) < 1);
01069
01070 for (i = 1; i <= ny; i++) {
01071 const double value = cpl_polynomial_eval_1d(disp, (double)i, NULL);
01072 cpl_image_set(self, ispec, i, value);
01073 if (is_bad) cpl_image_reject(self, ispec, i);
01074 }
01075
01076 end_skip;
01077
01078 return cpl_error_get_code();
01079 }
01080
01081
01082
01091
01092 static
01093 cpl_error_code naco_spc_wavecal_distortion(cpl_image * self,
01094 cpl_propertylist * qclist,
01095 const cpl_parameterlist * parlist)
01096 {
01097
01098 const int fitdeg = 2;
01099 cpl_image * copy = NULL;
01100 const int nx = cpl_image_get_size_x(self);
01101 const int ny = cpl_image_get_size_y(self);
01102 cpl_apertures * lines = NULL;
01103 cpl_polynomial* distortion = NULL;
01104 cpl_polynomial* yid2d = cpl_polynomial_new(2);
01105 cpl_vector * profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
01106 int power[] = {0, 1};
01107 const int nplot = naco_parameterlist_get_int(parlist, RECIPE_STRING,
01108 NACO_PARAM_PLOT);
01109 cpl_polynomial* center = cpl_polynomial_new(1);
01110 cpl_polynomial* dist1d = NULL;
01111 cpl_vector * dist1dfix = NULL;
01112 const int i0 = 0;
01113 const int i1 = 1;
01114 const double xcent = 0.5*(nx + 1);
01115 const double ycent = 0.5*(ny + 1);
01116
01117 bug_if(0);
01118 bug_if(self == NULL);
01119 bug_if(qclist == NULL);
01120 bug_if(parlist == NULL);
01121
01122
01123
01124 bug_if(cpl_image_turn(self, 1));
01125
01126 distortion = irplib_distortion_estimate(self, 1, 1, nx, ny,
01127 CPL_FALSE, 1e8,
01128 33,
01129 0.33, fitdeg, &lines);
01130
01131 error_if(distortion == NULL, cpl_error_get_code(), "Curvature estimation "
01132 "failed");
01133
01134 if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
01135 skip_if(cpl_polynomial_dump(distortion, stdout));
01136 cpl_apertures_dump(lines, stdout);
01137 }
01138
01139 skip_if(naco_spc_wavecal_qc_lines(qclist, self, lines));
01140
01141
01142 bug_if(cpl_polynomial_set_coeff(yid2d, power, 1.0));
01143
01144
01145 bug_if(cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
01146 CPL_KERNEL_DEF_WIDTH));
01147
01148
01149 copy = cpl_image_duplicate(self);
01150 error_if (cpl_image_warp_polynomial(self, copy, distortion, yid2d, profile,
01151 CPL_KERNEL_DEF_WIDTH, profile,
01152 CPL_KERNEL_DEF_WIDTH),
01153 cpl_error_get_code(), "Distortion correction failed");
01154
01155
01156 bug_if(cpl_image_turn(self, -1));
01157
01158 if (nplot > 1) {
01159 cpl_errorstate prestate = cpl_errorstate_get();
01160 irplib_image_plot("", "t 'Distortion corrected image'", "", self);
01161 if (!cpl_errorstate_is_equal(prestate)) {
01162 cpl_errorstate_set(prestate);
01163 }
01164
01165
01166 (void)cpl_image_turn(copy, -1);
01167
01168 (void)cpl_image_subtract(copy, self);
01169
01170 irplib_image_plot("", "t 'Distortion correction'", "", copy);
01171 if (!cpl_errorstate_is_equal(prestate)) {
01172 cpl_errorstate_set(prestate);
01173 }
01174
01175 }
01176
01177 skip_if(cpl_polynomial_dump(distortion, stdout));
01178
01179
01180 bug_if(cpl_polynomial_set_coeff(center, &i0, xcent));
01181
01182 dist1d = cpl_polynomial_extract(distortion, 1, center);
01183
01184
01185 bug_if(cpl_polynomial_set_coeff(center, &i1, 1.0));
01186 bug_if(cpl_polynomial_set_coeff(center, &i0, 0.0));
01187
01188
01189 bug_if(irplib_polynomial_subtract(center, dist1d, center));
01190
01191 if (cpl_polynomial_get_degree(center) > 0) {
01192 const int ndist1d = cpl_polynomial_get_degree(dist1d);
01193 int dist1dnreal;
01194
01195 cpl_msg_info(cpl_func, "On the center column (x=%g) the distortion "
01196 "polynomial should be P(y)=y, its deviation from that has "
01197 "degree %d:", xcent, cpl_polynomial_get_degree(center));
01198 skip_if(cpl_polynomial_dump(center, stdout));
01199
01200 if (ndist1d > 0) {
01201 cpl_errorstate prestate = cpl_errorstate_get();
01202 dist1dfix = cpl_vector_new(ndist1d);
01203 if (irplib_polynomial_solve_1d_all(dist1d, dist1dfix,
01204 &dist1dnreal)) {
01205 dist1dnreal = 0;
01206 irplib_error_recover(prestate, "Could not compute fix-points for "
01207 "%d-degree polynomial", ndist1d);
01208 }
01209 } else {
01210 dist1dnreal = 0;
01211 }
01212
01213 if (dist1dnreal > 0) {
01214 cpl_vector * dist1dfixreal = dist1dnreal == ndist1d ? dist1dfix
01215 : cpl_vector_wrap(dist1dnreal, cpl_vector_get_data(dist1dfix));
01216 cpl_msg_info(cpl_func, "The distortion correction has "
01217 "%d fix-point(s) on the center column:", dist1dnreal);
01218 cpl_vector_dump(dist1dfixreal, stdout);
01219 if (dist1dfixreal != dist1dfix)
01220 (void)cpl_vector_unwrap(dist1dfixreal);
01221 } else if (cpl_polynomial_get_coeff(dist1d, &i0) != 0.0) {
01222
01223 cpl_msg_info(cpl_func, "The distortion correction has "
01224 "no fix-points on the center column");
01225 } else {
01226
01227 cpl_msg_info(cpl_func, "The distortion correction has "
01228 "no fix-points on the center column");
01229 }
01230
01231 cpl_msg_info(cpl_func, "The distortion correction moves the detector "
01232 "center at (%g,%g) by (%g,%g)", xcent, ycent, 0.0,
01233 cpl_polynomial_eval_1d(dist1d, ycent, NULL)-ycent);
01234 } else if (cpl_polynomial_get_coeff(center, &i0) != 0.0) {
01235 cpl_msg_info(cpl_func, "The distortion correction has no fix-points "
01236 "on the center column, their Y-offset are [pixel]: %g",
01237 cpl_polynomial_get_coeff(center, &i0));
01238 } else {
01239 cpl_msg_info(cpl_func, "The distortion correction has all points "
01240 "on the center column (at x=%g) as fix-points", xcent);
01241 }
01242
01243
01244 power[0] = power[1] = 0;
01245 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DIST1",
01246 cpl_polynomial_get_coeff(distortion,
01247 power)));
01248 power[0] = 1;
01249 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTY",
01250 cpl_polynomial_get_coeff(distortion,
01251 power)));
01252 power[0] = 2;
01253 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTYY",
01254 cpl_polynomial_get_coeff(distortion,
01255 power)));
01256
01257 power[0] = power[1] = 1;
01258 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTXY",
01259 cpl_polynomial_get_coeff(distortion,
01260 power)));
01261 power[0] = 0;
01262 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTX",
01263 cpl_polynomial_get_coeff(distortion,
01264 power)));
01265 power[1] = 2;
01266 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTXX",
01267 cpl_polynomial_get_coeff(distortion,
01268 power)));
01269
01270 end_skip;
01271
01272
01273
01274 cpl_image_delete(copy);
01275 cpl_apertures_delete(lines);
01276 cpl_vector_delete(profile);
01277 cpl_vector_delete(dist1dfix);
01278 cpl_polynomial_delete(distortion);
01279 cpl_polynomial_delete(yid2d);
01280 cpl_polynomial_delete(center);
01281 cpl_polynomial_delete(dist1d);
01282
01283 return cpl_error_get_code();
01284 }
01285
01286
01294
01295 static cpl_error_code naco_spc_wavecal_qc(cpl_propertylist * qclist,
01296 cpl_propertylist * paflist,
01297 const irplib_framelist * rawframes)
01298 {
01299
01300 const cpl_propertylist * reflist
01301 = irplib_framelist_get_propertylist_const(rawframes, 0);
01302 const char pafcopy[] = "^(" NACO_PFITS_REGEXP_SPCWAVE_PAF ")$";
01303
01304
01305 bug_if (0);
01306
01307
01308
01309 skip_if (cpl_propertylist_copy_property_regexp(paflist, reflist, pafcopy,
01310 0));
01311 skip_if (cpl_propertylist_append(paflist, qclist));
01312
01313 bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
01314 IRPLIB_PFITS_REGEXP_RECAL_LAMP
01315 ")$", 0));
01316 end_skip;
01317
01318 return cpl_error_get_code();
01319 }
01320
01321
01333
01334 static cpl_error_code naco_spc_wavecal_fill_table(cpl_table * self,
01335 const cpl_polynomial * disp2d)
01336 {
01337
01338 const int degree = cpl_polynomial_get_degree(disp2d);
01339 const char * lunit = "micron";
01340 int i, j;
01341
01342 bug_if (self == NULL);
01343 bug_if (cpl_polynomial_get_dimension(disp2d) != 2);
01344 bug_if (degree < 1);
01345
01346 bug_if(cpl_table_set_size(self, 1));
01347
01348 for (i=0; i <= degree; i++) {
01349 for (j = 0; j <= i; j++) {
01350 const int powers[2] = {i-j, j};
01351 const double value = cpl_polynomial_get_coeff(disp2d, powers);
01352 char * label = cpl_sprintf("DISP2D_%d_%d", i-j, j);
01353 char * unit = i > 1 ? cpl_sprintf("%s/pixel^%d", lunit, i)
01354 : cpl_sprintf(i ? "%s/pixel" : "%s", lunit);
01355
01356 cpl_table_new_column(self, label, CPL_TYPE_DOUBLE);
01357 cpl_table_set_column_unit(self, label, unit);
01358 cpl_table_set_double(self, label, 0, value);
01359
01360 cpl_free(label);
01361 cpl_free(unit);
01362 bug_if(0);
01363 }
01364 }
01365
01366 end_skip;
01367
01368 return cpl_error_get_code();
01369 }
01370
01371
01384
01385 static cpl_error_code naco_spc_wavecal_save(cpl_frameset * set_tot,
01386 const cpl_parameterlist * parlist,
01387 const cpl_propertylist * qclist,
01388 const cpl_propertylist * paflist,
01389 const cpl_imagelist * lamp_wave,
01390 const cpl_polynomial * disp2d,
01391 int set_nb,
01392 const irplib_framelist * rawframes)
01393 {
01394 cpl_frameset * proframes = irplib_frameset_cast(rawframes);
01395 cpl_table * table2d = cpl_table_new(1);
01396 char * filename = NULL;
01397
01398
01399
01400 bug_if (0);
01401
01402
01403 filename = cpl_sprintf(RECIPE_STRING "_set%02d" CPL_DFS_FITS, set_nb);
01404 skip_if (irplib_dfs_save_image(set_tot, parlist, proframes,
01405 cpl_imagelist_get_const(lamp_wave, 0),
01406 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
01407 NACO_CALIB_ARC_MAP, qclist, NULL,
01408 naco_pipe_id, filename));
01409
01410 bug_if(naco_spc_wavecal_fill_table(table2d, disp2d));
01411
01412 skip_if(cpl_table_save(table2d, NULL, NULL, filename, CPL_IO_EXTEND));
01413
01414
01415 cpl_free(filename);
01416 filename = cpl_sprintf(RECIPE_STRING "_set%02d_diff" CPL_DFS_FITS, set_nb);
01417 skip_if (irplib_dfs_save_image(set_tot, parlist, proframes,
01418 cpl_imagelist_get_const(lamp_wave, 1),
01419 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
01420 NACO_CALIB_ARC_DIFF, qclist, NULL,
01421 naco_pipe_id, filename));
01422
01423 skip_if (cpl_image_save(cpl_imagelist_get_const(lamp_wave, 2), filename,
01424 CPL_BPP_IEEE_FLOAT, NULL, CPL_IO_EXTEND));
01425
01426 cpl_free(filename);
01427 filename = cpl_sprintf(RECIPE_STRING "_set%02d" CPL_DFS_PAF, set_nb);
01428 skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, paflist, filename));
01429
01430 end_skip;
01431
01432 cpl_table_delete(table2d);
01433 cpl_free(filename);
01434 cpl_frameset_delete(proframes);
01435
01436 return cpl_error_get_code();
01437
01438 }
01439
01440
01441
01450
01451 static cpl_error_code naco_spc_wavecal_count_lines(cpl_propertylist * self,
01452 const cpl_bivector * lines,
01453 double wlmin,
01454 double wlmax)
01455 {
01456
01457 const cpl_vector * xlines = cpl_bivector_get_x_const(lines);
01458 const double * dxlines = cpl_vector_get_data_const(xlines);
01459 int minline, maxline;
01460 int clines;
01461
01462
01463 bug_if (self == NULL);
01464 bug_if (lines == NULL);
01465
01466 bug_if (wlmin < 0.0);
01467 bug_if (wlmax < wlmin);
01468
01469
01470 minline = cpl_vector_find(xlines, wlmin);
01471
01472
01473 if (dxlines[minline] < wlmin) minline++;
01474
01475
01476 maxline = cpl_vector_find(xlines, wlmax);
01477
01478
01479 if (dxlines[maxline] > wlmax) maxline--;
01480
01481 clines = maxline >= minline ? maxline - minline : 0;
01482
01483 bug_if(cpl_propertylist_append_int(self, "ESO QC DISP NUMCAT", clines));
01484
01485 end_skip;
01486
01487 return cpl_error_get_code();
01488 }
01489
01490
01498
01499 static cpl_error_code
01500 naco_spc_wavecal_interpolate_rejected(cpl_image * self,
01501 const cpl_polynomial * disp2d)
01502 {
01503
01504 const int nz = cpl_image_count_rejected(self);
01505 const int nx = cpl_image_get_size_x(self);
01506 const int ny = cpl_image_get_size_y(self);
01507 double power[2];
01508 cpl_vector * vpower = cpl_vector_wrap(2, power);
01509 int i, j;
01510 int k = nz;
01511
01512 bug_if(self == NULL);
01513 bug_if(disp2d == NULL);
01514
01515 if (nz > 0) cpl_msg_info(cpl_func, "Interpolating %d poorly calibrated "
01516 "pixels in the wavelength map", nz);
01517
01518 for (i = 1; i <= nx && k > 0; i++) {
01519 for (j = 1; j <= ny && k > 0; j++) {
01520 if (cpl_image_is_rejected(self, i, j)) {
01521 power[0] = (double)i;
01522 power[1] = (double)j;
01523 cpl_image_set(self, i, j, cpl_polynomial_eval(disp2d, vpower));
01524 cpl_image_reject(self, i, j);
01525 k--;
01526 }
01527 }
01528 }
01529
01530 end_skip;
01531
01532 cpl_vector_unwrap(vpower);
01533
01534 return cpl_error_get_code();
01535 }
01536
01537
01538
01547
01548 static cpl_error_code naco_spc_wavecal_qc_lines(cpl_propertylist * self,
01549 const cpl_image * spec2d,
01550 const cpl_apertures * lines)
01551 {
01552
01553 const int nlines = cpl_apertures_get_size(lines);
01554 const int ny = cpl_image_get_size_y(spec2d);
01555 const double ycen = 0.5 * (ny + 1);
01556 int i, igood;
01557 char * label = NULL;
01558 cpl_vector * vmedian = cpl_vector_new(nlines);
01559 double median;
01560
01561 bug_if(self == NULL);
01562 bug_if(spec2d == NULL);
01563 bug_if(lines == NULL);
01564
01565 bug_if(cpl_propertylist_append_int(self, "ESO QC ARCS NUM", nlines));
01566
01567 igood = 0;
01568 for(i = 1; i <= nlines; i++) {
01569 cpl_errorstate prestate = cpl_errorstate_get();
01570 const double flux = cpl_apertures_get_flux(lines, i);
01571 const double xcen = cpl_apertures_get_centroid_x(lines, i);
01572 double fwhm_x, fwhm_y;
01573
01574 if (cpl_image_get_fwhm(spec2d, xcen, ycen, &fwhm_x, &fwhm_y)) {
01575 irplib_error_recover(prestate, "Could not compute the FWHM for "
01576 "aperture %d of %d (with xcentroid=%g, flux=%g",
01577 i, nlines, xcen, flux);
01578 fwhm_x = -1.0;
01579 }
01580
01581 if (fwhm_x > 0.0) {
01582 cpl_vector_set(vmedian, igood++, fwhm_x);
01583 }
01584
01585 cpl_free(label);
01586 label = cpl_sprintf("ESO QC ARCS%d XPOS", i);
01587 cpl_propertylist_append_double(self, label, xcen);
01588
01589 cpl_free(label);
01590 label = cpl_sprintf("ESO QC ARCS%d FWHM", i);
01591
01592 cpl_propertylist_append_double(self, label, fwhm_x);
01593
01594 cpl_free(label);
01595 label = cpl_sprintf("ESO QC ARCS%d FLUX", i);
01596
01597 cpl_propertylist_append_double(self, label, flux);
01598 }
01599 bug_if(0);
01600
01601 bug_if(cpl_propertylist_append_int(self, "ESO QC ARCS NUMGOOD", igood));
01602
01603 if (igood > 0) {
01604 bug_if(cpl_vector_set_size(vmedian, igood));
01605 median = cpl_vector_get_median(vmedian);
01606 } else {
01607 median = -1.0;
01608 }
01609
01610 bug_if(cpl_propertylist_append_double(self, "ESO QC FWHM MED", median));
01611
01612 end_skip;
01613
01614 cpl_vector_delete(vmedian);
01615 cpl_free(label);
01616
01617 return cpl_error_get_code();
01618 }