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
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00143
00146 #ifdef HAVE_CONFIG_H
00147 # include <config.h>
00148 #endif
00149
00150 #include <uves_wavecal_identify.h>
00151
00152 #include <uves_wavecal_utils.h>
00153 #include <uves_utils.h>
00154 #include <uves_utils_wrappers.h>
00155 #include <uves_error.h>
00156 #include <uves_msg.h>
00157 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 0, 0)
00158 #include <cpl_ppm.h>
00159 #else
00160 #include <irplib_ppm.h>
00161 #endif
00162 #include <uves_qclog.h>
00163 #include <cpl.h>
00164
00165 #include <math.h>
00166 #include <float.h>
00167
00168 #define USE_PPM 0
00169
00170 static cpl_error_code verify_calibration(const cpl_table *selected,
00171 const cpl_table *linetable,
00172 double TOLERANCE,
00173 double red_chisq,cpl_table* qclog);
00174 static cpl_error_code compute_lambda(cpl_table *linetable,
00175 const polynomial *dispersion_relation,
00176 const polynomial *dispersion_variance,
00177 bool verbose);
00178
00179 static int identify_lines(cpl_table *linetable,
00180 const cpl_table *line_refer,
00181 double ALPHA);
00182
00183 static polynomial *calibrate_global(const cpl_table *linetable,
00184 cpl_table **selected,
00185 int degree, bool verbose,
00186 bool reject,
00187 double TOLERANCE,
00188 double kappa,
00189 double *red_chisq,
00190 polynomial **dispersion_variance,
00191 double *pixelsize,
00192 double *rms_wlu,
00193 double *rms_pixels);
00194
00195
00235
00236
00237 polynomial *
00238 uves_wavecal_identify(cpl_table *linetable,
00239 const cpl_table *line_refer,
00240 const polynomial *guess_dispersion,
00241 int DEGREE, double TOLERANCE,
00242 double ALPHA, double MAXERROR,
00243 double kappa,
00244 const int trace,const int window,cpl_table* qclog)
00245 {
00246 polynomial *dispersion_relation = NULL;
00247 polynomial *dispersion_variance = NULL;
00248
00249 int current_id;
00250 int previous_id;
00251 int idloop;
00252 int n;
00253 double pixelsize;
00254 double red_chisq;
00255 cpl_table *selected = NULL;
00256 char qc_key[40];
00257
00258 passure( linetable != NULL, " ");
00259 passure( line_refer != NULL, " ");
00260 passure( guess_dispersion != NULL, " ");
00261
00262 assure( 0 < ALPHA && ALPHA <= 1, CPL_ERROR_ILLEGAL_INPUT,
00263 "Illegal alpha = %e", ALPHA);
00264
00265
00266 {
00267 cpl_table_new_column(linetable, LINETAB_LAMBDAC , CPL_TYPE_DOUBLE);
00268 cpl_table_new_column(linetable, "dLambdaC" , CPL_TYPE_DOUBLE);
00269 cpl_table_new_column(linetable, LINETAB_PIXELSIZE , CPL_TYPE_DOUBLE);
00270 cpl_table_new_column(linetable, LINETAB_RESIDUAL , CPL_TYPE_DOUBLE);
00271 cpl_table_new_column(linetable, "Residual_pix" , CPL_TYPE_DOUBLE);
00272 cpl_table_new_column(linetable, "Lambda_candidate" , CPL_TYPE_DOUBLE);
00273 cpl_table_new_column(linetable, "dLambda_candidate", CPL_TYPE_DOUBLE);
00274 cpl_table_new_column(linetable, "dLambda_cat_sq" , CPL_TYPE_DOUBLE);
00275 cpl_table_new_column(linetable, "dLambda_nn_sq" , CPL_TYPE_DOUBLE);
00276
00277
00278
00279 cpl_table_new_column(linetable, "Ident", CPL_TYPE_DOUBLE);
00280 cpl_table_new_column(linetable, "dIdent",CPL_TYPE_DOUBLE);
00281 cpl_table_set_column_invalid(linetable, "Ident", 0, cpl_table_get_nrow(linetable));
00282 cpl_table_set_column_invalid(linetable, "dIdent",0, cpl_table_get_nrow(linetable));
00283
00284
00285 check( compute_lambda(linetable, guess_dispersion, NULL, false),
00286 "Error applying dispersion relation");
00287 }
00288
00289
00290 #if USE_PPM
00291 for (idloop = 2; idloop <= 2; idloop += 1)
00292 #else
00293 for (idloop = 1; idloop <= 2; idloop += 1)
00294 #endif
00295 {
00296
00297 current_id = 0;
00298 n = 0;
00299
00300 do {
00301 double rms_wlu;
00302 double rms_pixels;
00303 bool reject = (idloop == 2);
00304 #if USE_PPM
00305 int nident_ppm;
00306 #endif
00307
00308 previous_id = current_id;
00309 n++;
00310
00311
00312 check( current_id = identify_lines(linetable, line_refer, ALPHA),
00313 "Error identifying lines");
00314
00315
00316 #if USE_PPM
00317
00318 check( nident_ppm = uves_wavecal_identify_lines_ppm(linetable, line_refer),
00319 "Error during point pattern matching");
00320
00321 cpl_table_erase_column(linetable, "Ident");
00322 cpl_table_duplicate_column(linetable, "Ident", linetable, "Ident_ppm");
00323 current_id = nident_ppm;
00324
00325
00326
00327 cpl_table_fill_column_window(linetable, "dIdent",
00328 0, cpl_table_get_nrow(linetable),
00329 cpl_table_get_column_mean(linetable, "dIdent"));
00330 #endif
00331
00332
00333
00334
00335
00336 uves_polynomial_delete(&dispersion_relation);
00337 uves_polynomial_delete(&dispersion_variance);
00338
00339 check( dispersion_relation = calibrate_global(
00340 linetable, NULL,
00341 DEGREE, false,
00342 reject,
00343 TOLERANCE,
00344 kappa,
00345 &red_chisq,
00346 &dispersion_variance,
00347 &pixelsize,
00348 &rms_wlu,
00349 &rms_pixels),
00350 "Could not perform global calibration");
00351
00352 uves_msg_debug("Average pixelsize = %f wlu", pixelsize);
00353 if (idloop == 1)
00354 {
00355 uves_msg("%d identifications made. RMS = %.5f wlu = %.3f "
00356 "pixels (no rejection)",
00357 current_id, rms_wlu, rms_pixels);
00358
00359
00360
00361
00362 }
00363 else
00364 {
00365 uves_msg("%d identifications made. RMS = %.5f wlu = %.3f "
00366 "pixels (%f %s rejection, kappa = %.1f)",
00367 current_id, rms_wlu, rms_pixels,
00368 fabs(TOLERANCE), (TOLERANCE > 0) ? "pixels" : "wlu",
00369 kappa);
00370 }
00371
00372 sprintf(qc_key,"QC TRACE%d WIN%d NLINID%d",trace,window,idloop);
00373 ck0_nomsg(uves_qclog_add_int(qclog,qc_key,current_id,
00374 "ThAr lamp identified lines",
00375 "%d"));
00376
00377 #if USE_PPM
00378 uves_msg("%d identifications from point pattern matching",
00379 nident_ppm);
00380 #endif
00381
00382 assure( rms_pixels < MAXERROR, CPL_ERROR_CONTINUE,
00383 "Wavelength calibration did not converge. "
00384 "After %d iterations the RMS was %f pixels. "
00385 "Try to improve on the initial solution", n, rms_pixels);
00386
00387
00388
00389 check( compute_lambda(linetable, dispersion_relation, dispersion_variance,
00390 false),
00391 "Error applying dispersion relation");
00392
00393
00394 }
00395 while (current_id > previous_id) ;
00396
00397 sprintf(qc_key,"QC TRACE%d WIN%d NLINID NITERS",trace,window);
00398 ck0_nomsg(uves_qclog_add_int(qclog,qc_key,idloop+1,
00399 "Number of iterations",
00400 "%d"));
00401
00402
00403
00404 if (idloop == 1)
00405 {
00406
00407
00408
00409
00410 uves_msg("Identification loop converged. Resetting identifications");
00411 cpl_table_set_column_invalid(linetable, "Ident", 0,
00412 cpl_table_get_nrow(linetable));
00413 }
00414 }
00415
00416
00417
00418 uves_polynomial_delete(&dispersion_relation);
00419 uves_polynomial_delete(&dispersion_variance);
00420 uves_free_table(&selected);
00421
00422 check( dispersion_relation = calibrate_global(linetable,
00423 &selected,
00424 DEGREE, true,
00425 true,
00426 TOLERANCE,
00427 kappa,
00428 &red_chisq,
00429 &dispersion_variance,
00430 NULL, NULL, NULL),
00431 "Could not perform global calibration");
00432
00433
00434 check( compute_lambda(linetable, dispersion_relation, dispersion_variance,
00435 true),
00436 "Error applying dispersion relation");
00437
00438
00439
00440
00441 {
00442 int i, j;
00443
00444
00445
00446 cpl_table_new_column(linetable, "NLinSol", CPL_TYPE_INT);
00447 cpl_table_new_column(linetable, "Select", CPL_TYPE_INT);
00448
00449 cpl_table_fill_column_window_int(linetable, "NLinSol",
00450 0, cpl_table_get_nrow(linetable),
00451 0);
00452 cpl_table_fill_column_window_int(linetable, "Select",
00453 0, cpl_table_get_nrow(linetable),
00454 0);
00455
00456 j = 0;
00457 for (i = 0; i < cpl_table_get_nrow(selected); i++) {
00458 int order = cpl_table_get_int(selected, "Order", i, NULL);
00459 double x = cpl_table_get_double(selected, "X", i, NULL);
00460 int order2;
00461 double x2;
00462
00463
00464 passure( j < cpl_table_get_nrow(linetable), "%d %" CPL_SIZE_FORMAT "",
00465 j, cpl_table_get_nrow(linetable));
00466 do {
00467 order2 = cpl_table_get_int(linetable, "Order", j, NULL);
00468 x2 = cpl_table_get_double(linetable, "X", j, NULL);
00469 if (cpl_table_is_valid(linetable, "Ident", j))
00470 {
00471 cpl_table_set_int(linetable, "Select", j, 1);
00472 }
00473 j++;
00474
00475 } while (order2 < order || x2 < x - 0.1);
00476
00477 passure( order2 == order && fabs(x2 - x) < 0.1,
00478 "%d %d %g %g", order2, order, x2, x);
00479
00480 cpl_table_set_int(linetable, "NLinSol", j-1, 1);
00481 }
00482 }
00483
00484
00485 check( verify_calibration(selected, linetable, TOLERANCE, red_chisq,qclog),
00486 "Error verifying calibration");
00487
00488 cleanup:
00489 uves_free_table(&selected);
00490 uves_polynomial_delete(&dispersion_variance);
00491 return dispersion_relation;
00492 }
00493
00494
00508
00509 static cpl_error_code
00510 verify_calibration(const cpl_table *selected,
00511 const cpl_table *linetable, double TOLERANCE,
00512 double red_chisq, cpl_table* qclog)
00513 {
00514 cpl_table *brightest = NULL;
00515 double median_intensity;
00516 int ninvalid;
00517 double ratio;
00518 double rms_wlu;
00519 double rms_pixels;
00520 double rms_speed;
00521 char qc_key[40];
00522
00523 {
00524 double mean;
00525 double stdev;
00526
00527 check(( mean = cpl_table_get_column_mean (selected, LINETAB_RESIDUAL),
00528 stdev= cpl_table_get_column_stdev(selected, LINETAB_RESIDUAL),
00529 rms_wlu = sqrt(mean*mean + stdev*stdev),
00530
00531 mean = cpl_table_get_column_mean (selected, "Residual_pix"),
00532 stdev= cpl_table_get_column_stdev(selected, "Residual_pix"),
00533 rms_pixels = sqrt(mean*mean + stdev*stdev)),
00534 "Error reading RMS of fit");
00535 }
00536 rms_speed=rms_wlu * SPEED_OF_LIGHT/
00537 cpl_table_get_column_mean(selected,LINETAB_LAMBDAC);
00538 uves_msg("%" CPL_SIZE_FORMAT " lines accepted", cpl_table_get_nrow(selected));
00539 uves_msg("Average RMS of calibration (tolerance = %.3f %s) = %.5f wlu = %.4f pixels ~ %.1f m/s",
00540 fabs(TOLERANCE),
00541 (TOLERANCE > 0) ? "pixels" : "wlu",
00542 rms_wlu, rms_pixels, rms_speed);
00543
00544 sprintf(qc_key,"QC LINE RESIDRMS WLU");
00545 ck0_nomsg(uves_qclog_add_double(qclog,qc_key,rms_wlu,
00546 "Line ID RMS TRACE0 WIN2 [Ang]",
00547 "%f"));
00548 sprintf(qc_key,"QC LINE RESIDRMS PIX");
00549 ck0_nomsg(uves_qclog_add_double(qclog,qc_key,rms_pixels,
00550 "Line ID RMS TRACE0 WIN2 [pix]",
00551 "%f"));
00552 sprintf(qc_key,"QC LINE RESIDRMS SPEED");
00553 ck0_nomsg(uves_qclog_add_double(qclog,qc_key,rms_speed,
00554 "Line ID RMS TRACE0 WIN2 [m/s]",
00555 "%f"));
00556
00557
00558 uves_msg("Reduced chi^2 of calibration = %f", red_chisq);
00559 sprintf(qc_key,"QC LINE IDCHI2");
00560 ck0_nomsg(uves_qclog_add_double(qclog,qc_key,red_chisq,
00561 "Reduced chi^2 of line ID TRACE0 WIN2",
00562 "%f"));
00563
00564 if (red_chisq < .01)
00565 {
00566 uves_msg_warning("Reduced chi^2 of fit is less than 1/100: %f",
00567 red_chisq);
00568 }
00569 if (red_chisq > 100)
00570 {
00571 uves_msg_warning("Reduced chi^2 of fit is greater than 100: %f",
00572 red_chisq);
00573 }
00574
00575 check(( median_intensity = cpl_table_get_column_median(linetable, "Peak"),
00576 brightest = uves_extract_table_rows(linetable, "Peak",
00577 CPL_GREATER_THAN,
00578 median_intensity),
00579 ninvalid = cpl_table_count_invalid(brightest, "Ident")),
00580 "Error counting identifications");
00581
00582 ratio = 1 - ((double) ninvalid)/cpl_table_get_nrow(brightest);
00583 uves_msg("Percentage of identifications among the half brighter lines : %.2f %%",
00584 100*ratio);
00585
00586 sprintf(qc_key,"QC LINE HALFBRIG");
00587 ck0_nomsg(uves_qclog_add_double(qclog,qc_key,100*ratio,
00588 "Half brighter lines frac TRACE0 WIN2",
00589 "%f"));
00590
00591 cleanup:
00592 uves_free_table(&brightest);
00593
00594 return cpl_error_get_code();
00595 }
00596
00597
00611
00612 static cpl_error_code
00613 compute_lambda(cpl_table *linetable,
00614 const polynomial *dispersion_relation,
00615 const polynomial *dispersion_variance,
00616 bool verbose)
00617 {
00618 int i;
00619 bool printed_warning = false;
00620
00621
00622 passure(linetable != NULL, " ");
00623 passure(dispersion_relation != NULL, " ");
00624
00625
00626 passure( uves_polynomial_get_dimension(dispersion_relation) == 2, "%d",
00627 uves_polynomial_get_dimension(dispersion_relation));
00628
00629
00630 passure(cpl_table_has_column(linetable, "X") , " ");
00631 passure(cpl_table_has_column(linetable, "Order") , " ");
00632 passure(cpl_table_has_column(linetable, "Ident") , " ");
00633
00634 passure(cpl_table_has_column(linetable, LINETAB_LAMBDAC) , " ");
00635
00636 passure(cpl_table_has_column(linetable, "dLambdaC") , " ");
00637 passure(cpl_table_has_column(linetable, "dIdent") , " ");
00638 passure(cpl_table_has_column(linetable, LINETAB_RESIDUAL), " ");
00639 passure(cpl_table_has_column(linetable, "Residual_pix"), " ");
00640 passure(cpl_table_has_column(linetable, LINETAB_PIXELSIZE) , " ");
00641
00642
00643
00644 for(i = 0; i < cpl_table_get_nrow(linetable); i++)
00645 {
00646 int order;
00647 double x, dfdx;
00648 double lambdac, dlambdac, pixelsize;
00649 order = cpl_table_get_int(linetable, "Order", i, NULL);
00650
00651 x = cpl_table_get_double(linetable, "X", i, NULL);
00652
00653
00654
00655
00656 lambdac =
00657 uves_polynomial_evaluate_2d(dispersion_relation, x, order) / order;
00658
00659
00660 dfdx = uves_polynomial_derivative_2d(dispersion_relation, x, order, 1);
00661 if (dfdx < 0) {
00662 if (!printed_warning && verbose) {
00663 uves_msg_warning("Inferred dispersion (dlambda/dx) is negative at"
00664 "(x, order) = (%f, %d)", x, order);
00665 printed_warning = true;
00666 }
00667 else {
00668 uves_msg_debug("Inferred dispersion (dlambda/dx) is negative at "
00669 "(x, order) = (%f, %d)", x, order);
00670 }
00671 }
00672 pixelsize = dfdx / order;
00673
00674 check(( cpl_table_set_double(linetable, LINETAB_LAMBDAC , i, lambdac),
00675 cpl_table_set_double(linetable, LINETAB_PIXELSIZE, i, pixelsize)),
00676 "Error writing table");
00677
00678 if (dispersion_variance != NULL)
00679 {
00680
00681
00682 dlambdac =
00683 sqrt(uves_polynomial_evaluate_2d(dispersion_variance, x, order))
00684 / order;
00685
00686 cpl_table_set_double(linetable, "dLambdaC" , i, dlambdac);
00687 }
00688 else
00689 {
00690
00691
00692
00693
00694 cpl_table_set_double(linetable, "dLambdaC" , i, 1.0);
00695 }
00696
00697
00698 if (cpl_table_is_valid(linetable, "Ident", i))
00699 {
00700 double ident = cpl_table_get_double(linetable, "Ident", i, NULL);
00701 cpl_table_set_double(linetable, LINETAB_RESIDUAL, i,
00702 ident - lambdac);
00703 cpl_table_set_double(linetable, "Residual_pix", i,
00704 (ident - lambdac)/pixelsize);
00705 }
00706 else
00707 {
00708 cpl_table_set_invalid(linetable, LINETAB_RESIDUAL, i);
00709 cpl_table_set_invalid(linetable, "Residual_pix", i);
00710 }
00711 }
00712
00713
00714 check( uves_sort_table_2(linetable, "Order", "X", false, false),
00715 "Error sorting table");
00716
00717 cleanup:
00718 return cpl_error_get_code();
00719 }
00720
00721
00722
00759
00760
00761 static int
00762 identify_lines(cpl_table *linetable, const cpl_table *line_refer, double ALPHA)
00763 {
00764 int number_identifications = 0;
00765 int linetable_size;
00766 int linerefer_size;
00767 int row;
00768 int *histogram = NULL;
00769 const double minlog = -5.0;
00770
00771
00772 const double maxlog = 15.0;
00773 const int nbins = 400;
00774 double error = 0;
00775
00776 double average_dlambda_com = 0;
00777
00778
00779
00780 passure( linetable != NULL, " ");
00781
00782 passure( cpl_table_has_column(linetable, LINETAB_LAMBDAC ), " ");
00783
00784 passure( cpl_table_has_column(linetable, "dLambdaC" ), " ");
00785
00786 passure( cpl_table_has_column(linetable, "X" ), " ");
00787
00788 passure( cpl_table_has_column(linetable, "Order" ), " ");
00789
00790 passure( cpl_table_has_column(linetable, "Xwidth" ), " ");
00791 passure( cpl_table_has_column(linetable, LINETAB_PIXELSIZE), " ");
00792
00793
00794 passure( cpl_table_has_column(linetable, "Ident" ), " ");
00795
00796 passure( cpl_table_has_column(linetable, "dIdent" ), " ");
00797
00798
00799
00800 passure( line_refer != NULL, " ");
00801 passure( cpl_table_has_column(line_refer, "Wave" ), " ");
00802 passure( cpl_table_has_column(line_refer, "dWave"), " ");
00803
00804
00805 linetable_size = cpl_table_get_nrow(linetable);
00806 linerefer_size = cpl_table_get_nrow(line_refer);
00807 assure(linerefer_size >= 1, CPL_ERROR_ILLEGAL_INPUT, "Empty line reference table");
00808
00809
00810 passure( 0 < ALPHA && ALPHA <= 1, "%e", ALPHA);
00811
00812
00813 average_dlambda_com = cpl_table_get_column_median(linetable, "dLambdaC");
00814
00815
00816 histogram = cpl_calloc(nbins, sizeof(int));
00817 assure_mem( histogram );
00818
00819
00820
00821
00822
00823 for (row = 0; row < linetable_size; row++) {
00824 double lambda_com;
00825 double line_width;
00826 double line_fwhm;
00827 int order;
00828 double lambda_cat;
00829 double lambda_cat_sigma;
00830 double distance_cat_sq;
00831 double nn_distance_sq;
00832 int row_cat;
00833
00834
00835 lambda_com = cpl_table_get_double(linetable, LINETAB_LAMBDAC , row, NULL);
00836 order = cpl_table_get_int (linetable, "Order" , row, NULL);
00837
00838
00839 line_width =
00840 cpl_table_get_double(linetable, "Xwidth" , row, NULL) *
00841 fabs(cpl_table_get_double(linetable, LINETAB_PIXELSIZE , row, NULL));
00842
00843
00844 line_fwhm = TWOSQRT2LN2 * line_width;
00845
00846
00847 row_cat = uves_wavecal_find_nearest(
00848 line_refer, lambda_com, 0, linerefer_size - 1);
00849 lambda_cat = cpl_table_get_double(line_refer, "Wave", row_cat, NULL);
00850 lambda_cat_sigma = cpl_table_get_double(line_refer, "dWave",row_cat, NULL);
00851
00852
00853 distance_cat_sq = (lambda_com - lambda_cat)*(lambda_com - lambda_cat);
00854
00855
00856
00857
00858
00859 {
00860 double lambda_com_prev, lambda_com_next;
00861 int order_prev, order_next;
00862 double lambda_cat_prev, lambda_cat_next;
00863
00864 nn_distance_sq = DBL_MAX;
00865
00866
00867 if (row >= 1)
00868 {
00869 order_prev = cpl_table_get_int (
00870 linetable, "Order" , row - 1, NULL);
00871 lambda_com_prev = cpl_table_get_double(
00872 linetable, LINETAB_LAMBDAC, row - 1, NULL);
00873
00874 if (order == order_prev)
00875 {
00876 nn_distance_sq = uves_min_double(nn_distance_sq,
00877 (lambda_com_prev - lambda_com)*
00878 (lambda_com_prev - lambda_com)
00879 );
00880 }
00881 }
00882
00883 if (row <= linetable_size - 2)
00884 {
00885 order_next = cpl_table_get_int (linetable, "Order",
00886 row + 1, NULL);
00887 lambda_com_next = cpl_table_get_double(linetable, LINETAB_LAMBDAC,
00888 row + 1, NULL);
00889
00890 if (order == order_next)
00891 {
00892 nn_distance_sq = uves_min_double(nn_distance_sq,
00893 (lambda_com_next - lambda_com)*
00894 (lambda_com_next - lambda_com)
00895 );
00896 }
00897 }
00898
00899
00900 if (row_cat >= 1)
00901 {
00902 lambda_cat_prev = cpl_table_get_double(
00903 line_refer, "Wave", row_cat - 1, NULL);
00904
00905 nn_distance_sq = uves_min_double(
00906 nn_distance_sq,
00907 (lambda_cat_prev - lambda_cat)*
00908 (lambda_cat_prev - lambda_cat)
00909 );
00910 }
00911 if (row_cat <= linerefer_size - 2)
00912 {
00913 lambda_cat_next = cpl_table_get_double(
00914 line_refer, "Wave", row_cat + 1, NULL);
00915
00916 nn_distance_sq = uves_min_double(
00917 nn_distance_sq,
00918 (lambda_cat_next - lambda_cat)*
00919 (lambda_cat_next - lambda_cat)
00920 );
00921 }
00922
00923
00924
00925 if (nn_distance_sq < DBL_MAX)
00926 {
00927 nn_distance_sq *= ALPHA*ALPHA;
00928 }
00929
00930 }
00931
00932
00933 cpl_table_set_double(linetable, "Lambda_candidate", row, lambda_cat);
00934 cpl_table_set_double(linetable, "dLambda_candidate",row, lambda_cat_sigma);
00935 cpl_table_set_double(linetable, "dLambda_cat_sq", row, distance_cat_sq);
00936 cpl_table_set_double(linetable, "dLambda_nn_sq", row, nn_distance_sq);
00937
00938
00939
00940 {
00941 int ilow = uves_round_double((0.5*log(distance_cat_sq/(line_fwhm*line_fwhm))
00942 - minlog)/(maxlog - minlog) * nbins);
00943 int ihigh = uves_round_double((0.5*log(nn_distance_sq /(line_fwhm*line_fwhm))
00944 - minlog)/(maxlog - minlog) * nbins);
00945 int i;
00946
00947 for (i = uves_max_int(ilow, 0); i < uves_min_int(ihigh, nbins); i++)
00948 {
00949 histogram[i] += 1;
00950 }
00951 }
00952 }
00953
00954
00955 {
00956 int i;
00957 int maxfreq = -1;
00958 for (i = 0; i < nbins; i++)
00959 {
00960 uves_msg_debug("histogram[%d] = %d", i, histogram[i]);
00961 if (histogram[i] > maxfreq)
00962 {
00963 maxfreq = histogram[i];
00964 error = exp( i / ((double)nbins) * (maxlog - minlog) + minlog ) ;
00965
00966 }
00967 }
00968 uves_msg_debug("Dimensionless error factor is %f", error);
00969 }
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003 for (row = 0; row < linetable_size; row++)
01004 {
01005 double distance_cat_sq;
01006 double nn_distance_sq;
01007 double tolerance_sq;
01008 double dlambda_com;
01009 double line_width;
01010 double line_fwhm;
01011 double lambda_cat;
01012 double lambda_cat_sigma;
01013
01014 lambda_cat = cpl_table_get_double(linetable, "Lambda_candidate", row, NULL);
01015 lambda_cat_sigma = cpl_table_get_double(linetable, "dLambda_candidate", row, NULL);
01016
01017
01018
01019
01020
01021
01022
01023
01024 line_width =
01025 uves_max_double(1, cpl_table_get_double(linetable, "Xwidth" , row, NULL)) *
01026 fabs(cpl_table_get_double(linetable, LINETAB_PIXELSIZE , row, NULL));
01027
01028
01029 line_fwhm = TWOSQRT2LN2 * line_width;
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041 dlambda_com = line_fwhm
01042 * cpl_table_get_double(linetable, "dLambdaC" , row, NULL)
01043 / average_dlambda_com;
01044
01045 tolerance_sq = line_fwhm*line_fwhm * error*error;
01046
01047 distance_cat_sq = cpl_table_get_double(linetable, "dLambda_cat_sq", row, NULL);
01048 nn_distance_sq = cpl_table_get_double(linetable, "dLambda_nn_sq" , row, NULL);
01049
01050 #if WANT_BIG_LOGFILE
01051 uves_msg_debug("(order,x) = (%d,%f) lcom = %f+-%f lcat = %f "
01052 "dist_cat = %f (%f pixels) tolerance = %.3f error = %f "
01053 "nn = %f (%f pixels)",
01054 cpl_table_get_int (linetable, "Order" , row, NULL),
01055 cpl_table_get_double(linetable, "X" , row, NULL),
01056 cpl_table_get_double(linetable, LINETAB_LAMBDAC, row, NULL),
01057 dlambda_com,
01058 lambda_cat,
01059 sqrt(distance_cat_sq),
01060 sqrt(distance_cat_sq)
01061 /cpl_table_get_double(linetable, LINETAB_PIXELSIZE, row, NULL),
01062 sqrt(tolerance_sq),
01063 error,
01064 sqrt(nn_distance_sq),
01065 sqrt(nn_distance_sq)
01066 /cpl_table_get_double(linetable, LINETAB_PIXELSIZE, row, NULL));
01067 #endif
01068
01069
01070 if (distance_cat_sq < (dlambda_com)*(dlambda_com)
01071 && tolerance_sq < nn_distance_sq
01072 && distance_cat_sq < nn_distance_sq)
01073 {
01074 number_identifications++;
01075 cpl_table_set_double(linetable, "Ident", row, lambda_cat);
01076 cpl_table_set_double(linetable, "dIdent",row, lambda_cat_sigma);
01077 #if WANT_BIG_LOGFILE
01078 uves_msg_debug("ID made");
01079 #endif
01080 }
01081 else
01082 {
01083 if (cpl_table_is_valid(linetable, "Ident", row)) {
01084 number_identifications++;
01085
01086 uves_msg_debug("Line at (%d,%f) does not match ID criterion anymore",
01087 cpl_table_get_int (linetable, "Order", row, NULL),
01088 cpl_table_get_double(linetable, "X", row, NULL)
01089 );
01090 }
01091 }
01092 }
01093
01094 cleanup:
01095 cpl_free(histogram);
01096 return number_identifications;
01097 }
01098
01099
01125
01126 static polynomial *
01127 calibrate_global(const cpl_table *linetable,
01128 cpl_table **selected,
01129 int degree, bool verbose,
01130 bool reject,
01131 double TOLERANCE,
01132 double kappa,
01133 double *red_chisq, polynomial **dispersion_variance,
01134 double *pixelsize,
01135 double *rms_wlu,
01136 double *rms_pixels)
01137 {
01138 polynomial *dispersion_relation = NULL;
01139 cpl_table *identified = NULL;
01140 int valid_ids =
01141 cpl_table_get_nrow(linetable) -
01142 cpl_table_count_invalid(linetable, "Ident");
01143 int rejected;
01144
01145 passure( (pixelsize == NULL) == (rms_wlu == NULL) &&
01146 (pixelsize == NULL) == (rms_pixels == NULL), " ");
01147
01148 assure( degree < 0 ||
01149 valid_ids >= (degree + 1)*(degree + 1), CPL_ERROR_ILLEGAL_INPUT,
01150 "There are not enough identifications to create a %d.-degree global fit. "
01151 "%d needed. %d found", degree, (degree + 1)*(degree + 1), valid_ids);
01152
01153 identified = cpl_table_duplicate(linetable);
01154 assure_mem(identified);
01155
01156
01157 if (reject)
01158 {
01159 check_nomsg( rejected = uves_delete_bad_lines(identified, TOLERANCE, kappa) );
01160 uves_msg_debug("%d lines rejected %f %f", rejected, TOLERANCE, kappa);
01161 }
01162 else
01163 {
01164 check( uves_erase_invalid_table_rows(identified, "Ident"),
01165 "Error erasing un-identified lines");
01166 }
01167
01168
01169
01170 check(( cpl_table_duplicate_column(identified, "Aux", identified, "Ident"),
01171 cpl_table_multiply_columns(identified, "Aux", "Order"),
01172
01173
01174 cpl_table_duplicate_column(identified, "dAux", identified, "dIdent"),
01175 cpl_table_multiply_columns(identified, "dAux", "Order")),
01176 "Error setting up temporary table");
01177
01178
01179
01180 if (degree >= 0) {
01181 check( dispersion_relation =
01182 uves_polynomial_regression_2d(identified,
01183 "X", "Order", "Aux",
01184 "dAux",
01185
01186
01187
01188
01189
01190
01191 degree, degree,
01192 NULL, NULL, NULL,
01193 NULL,
01194 red_chisq,
01195 dispersion_variance,
01196 reject ? kappa : -1, -1),
01197 "Error fitting polynomial. Possible cause: too few (%d) "
01198 "line identifications", valid_ids);
01199 }
01200 else {
01201 int max_degree = 8;
01202 double min_rms = -1;
01203 double min_reject = -1;
01204 check( dispersion_relation =
01205 uves_polynomial_regression_2d_autodegree(identified,
01206 "X", "Order", "Aux",
01207 "dAux",
01208 NULL, NULL, NULL,
01209 NULL,
01210 red_chisq,
01211 dispersion_variance,
01212 reject ? kappa : -1,
01213 max_degree, max_degree,
01214 min_rms, min_reject,
01215 verbose,
01216 NULL, NULL, 0, NULL),
01217 "Error fitting polynomial. Possible cause: too few (%d) "
01218 "line identifications", valid_ids);
01219 }
01220
01221 if (pixelsize != NULL)
01222 {
01223
01224
01225 check( compute_lambda(identified, dispersion_relation, NULL,
01226 false),
01227 "Error applying dispersion relation");
01228
01229 *pixelsize = cpl_table_get_column_median(identified, LINETAB_PIXELSIZE);
01230 *rms_wlu = cpl_table_get_column_stdev (identified, LINETAB_RESIDUAL);
01231 *rms_pixels= cpl_table_get_column_stdev (identified, "Residual_pix");
01232 }
01233
01234 if (selected != NULL) {
01235 *selected = cpl_table_duplicate(identified);
01236 }
01237
01238 cleanup:
01239 uves_free_table(&identified);
01240 if (cpl_error_get_code() != CPL_ERROR_NONE)
01241 {
01242 uves_polynomial_delete(&dispersion_relation);
01243 }
01244
01245 return dispersion_relation;
01246 }
01247
01248
01249
01250
01257
01258
01259 int
01260 uves_wavecal_identify_lines_ppm(cpl_table *linetable, const cpl_table *line_refer)
01261 {
01262 int result = 0;
01263 int minorder, maxorder;
01264 int order;
01265 cpl_table *lt_order = NULL;
01266 cpl_table *refer_order = NULL;
01267 cpl_vector *peaks = NULL;
01268 cpl_vector *lines = NULL;
01269 cpl_bivector *ids = NULL;
01270
01271 assure( cpl_table_has_column(linetable, LINETAB_LAMBDAC), CPL_ERROR_DATA_NOT_FOUND,
01272 "Missing column %s", LINETAB_LAMBDAC);
01273
01274 assure( cpl_table_has_column(linetable, LINETAB_PIXELSIZE), CPL_ERROR_DATA_NOT_FOUND,
01275 "Missing column %s", LINETAB_PIXELSIZE);
01276
01277 assure( cpl_table_has_column(linetable, "Order"), CPL_ERROR_DATA_NOT_FOUND,
01278 "Missing column %s", "Order");
01279
01280 minorder = uves_round_double( cpl_table_get_column_min(linetable, "Order"));
01281 maxorder = uves_round_double( cpl_table_get_column_max(linetable, "Order"));
01282
01283
01284 if (cpl_table_has_column(linetable, "Ident_ppm"))
01285 {
01286 cpl_table_erase_column(linetable, "Ident_ppm");
01287 }
01288
01289 cpl_table_new_column(linetable, "Ident_ppm", CPL_TYPE_DOUBLE);
01290
01291 for (order = minorder; order <= maxorder; order++)
01292 {
01293 const double tolerance = 0.05;
01294 double min_lambda, max_lambda;
01295 double min_disp, max_disp;
01296
01297
01298
01299 uves_free_table(<_order);
01300 lt_order = uves_extract_table_rows(linetable, "Order",
01301 CPL_EQUAL_TO, order);
01302
01303 check_nomsg((min_lambda = cpl_table_get_column_min(lt_order, LINETAB_LAMBDAC),
01304 max_lambda = cpl_table_get_column_max(lt_order, LINETAB_LAMBDAC),
01305 min_disp = cpl_table_get_column_min(lt_order, LINETAB_PIXELSIZE)*0.99,
01306 max_disp = cpl_table_get_column_max(lt_order, LINETAB_PIXELSIZE)*1.01));
01307
01308 uves_free_table(&refer_order);
01309 refer_order = uves_extract_table_rows(line_refer, "Wave", CPL_GREATER_THAN,
01310 min_lambda);
01311 uves_extract_table_rows_local(refer_order, "Wave", CPL_LESS_THAN,
01312 max_lambda);
01313
01314
01315 {
01316 int i;
01317 uves_free_vector(&peaks);
01318 peaks = cpl_vector_new(cpl_table_get_nrow(lt_order));
01319 for (i = 0; i < cpl_vector_get_size(peaks); i++)
01320 {
01321 cpl_vector_set(peaks, i, cpl_table_get_double(lt_order, "X", i, NULL));
01322 }
01323
01324 uves_free_vector(&lines);
01325 lines = cpl_vector_new(cpl_table_get_nrow(refer_order));
01326 for (i = 0; i < cpl_vector_get_size(lines); i++)
01327 {
01328 cpl_vector_set(lines, i, cpl_table_get_double(refer_order, "Wave", i, NULL));
01329 }
01330 }
01331
01332
01333 cpl_vector_sort(peaks, 1);
01334 cpl_vector_sort(lines, 1);
01335
01336 uves_msg_debug("Call ppm with %" CPL_SIZE_FORMAT " peaks, %" CPL_SIZE_FORMAT " lines, dispersion range = %f - %f A/pixel",
01337 cpl_vector_get_size(peaks),
01338 cpl_vector_get_size(lines),
01339 min_disp, max_disp);
01340
01341 uves_free_bivector(&ids);
01342
01343 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 0, 0)
01344 ids = cpl_ppm_match_positions(peaks, lines,
01345 min_disp, max_disp,
01346 tolerance,
01347 NULL, NULL);
01348 #else
01349 ids = irplib_ppm_match_positions(peaks, lines,
01350 min_disp, max_disp,
01351 tolerance);
01352 #endif
01353
01354
01355
01356 if (ids == NULL)
01357 {
01358 uves_msg_warning("Order %d: Point pattern matching failed", order);
01359 if (cpl_error_get_code() != CPL_ERROR_NONE)
01360 {
01361 uves_msg_debug("%s at %s", cpl_error_get_message(),
01362 cpl_error_get_where());
01363 uves_error_reset();
01364 }
01365 }
01366 else
01367 {
01368 int i, j;
01369
01370 uves_msg_debug("%" CPL_SIZE_FORMAT " identifications from point pattern matching (order %d)",
01371 cpl_bivector_get_size(ids), order);
01372
01373 result += cpl_bivector_get_size(ids);
01374
01375 for (i = 0; i < cpl_table_get_nrow(linetable); i++) {
01376
01377 if (cpl_table_get_int(linetable, "Order", i, NULL) == order)
01378 for (j = 0; j < cpl_bivector_get_size(ids); j++)
01379 {
01380 if (fabs(cpl_table_get_double(linetable, "X", i, NULL) -
01381 cpl_bivector_get_x_data(ids)[j]) < 0.001)
01382 cpl_table_set_double(linetable, "Ident_ppm", i,
01383 cpl_bivector_get_y_data(ids)[j]);
01384 }
01385 }
01386 }
01387 }
01388
01389 cleanup:
01390 uves_free_table(<_order);
01391 uves_free_table(&refer_order);
01392 uves_free_vector(&peaks);
01393 uves_free_vector(&lines);
01394 uves_free_bivector(&ids);
01395
01396 return result;
01397 }