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
00113
00116 #ifdef HAVE_CONFIG_H
00117 # include <config.h>
00118 #endif
00119
00120 #include <uves_wavecal_identify.h>
00121
00122 #include <uves_wavecal_utils.h>
00123 #include <uves_utils.h>
00124 #include <uves_utils_wrappers.h>
00125 #include <uves_error.h>
00126 #include <uves_msg.h>
00127 #include <irplib_ppm.h>
00128
00129 #include <cpl.h>
00130
00131 #include <math.h>
00132 #include <float.h>
00133
00134 #define USE_PPM 0
00135
00136 static cpl_error_code verify_calibration(const cpl_table *selected,
00137 const cpl_table *linetable,
00138 double TOLERANCE,
00139 double red_chisq);
00140 static cpl_error_code compute_lambda(cpl_table *linetable,
00141 const polynomial *dispersion_relation,
00142 const polynomial *dispersion_variance,
00143 bool verbose);
00144
00145 static int identify_lines(cpl_table *linetable,
00146 const cpl_table *line_refer,
00147 double ALPHA);
00148
00149 static polynomial *calibrate_global(const cpl_table *linetable,
00150 cpl_table **selected,
00151 int degree, bool verbose,
00152 bool reject,
00153 double TOLERANCE,
00154 double kappa,
00155 double *red_chisq,
00156 polynomial **dispersion_variance,
00157 double *pixelsize,
00158 double *rms_wlu,
00159 double *rms_pixels);
00160
00161
00201
00202
00203 polynomial *
00204 uves_wavecal_identify(cpl_table *linetable,
00205 const cpl_table *line_refer,
00206 const polynomial *guess_dispersion,
00207 int DEGREE, double TOLERANCE,
00208 double ALPHA, double MAXERROR,
00209 double kappa)
00210 {
00211 polynomial *dispersion_relation = NULL;
00212 polynomial *dispersion_variance = NULL;
00213
00214 int current_id;
00215 int previous_id;
00216 int idloop;
00217 int n;
00218 double pixelsize;
00219 double red_chisq;
00220 cpl_table *selected = NULL;
00221
00222 passure( linetable != NULL, " ");
00223 passure( line_refer != NULL, " ");
00224 passure( guess_dispersion != NULL, " ");
00225
00226 assure( 0 < ALPHA && ALPHA <= 1, CPL_ERROR_ILLEGAL_INPUT,
00227 "Illegal alpha = %e", ALPHA);
00228
00229
00230 {
00231 cpl_table_new_column(linetable, LINETAB_LAMBDAC , CPL_TYPE_DOUBLE);
00232 cpl_table_new_column(linetable, "dLambdaC" , CPL_TYPE_DOUBLE);
00233 cpl_table_new_column(linetable, LINETAB_PIXELSIZE , CPL_TYPE_DOUBLE);
00234 cpl_table_new_column(linetable, LINETAB_RESIDUAL , CPL_TYPE_DOUBLE);
00235 cpl_table_new_column(linetable, "Residual_pix" , CPL_TYPE_DOUBLE);
00236 cpl_table_new_column(linetable, "Lambda_candidate" , CPL_TYPE_DOUBLE);
00237 cpl_table_new_column(linetable, "dLambda_candidate", CPL_TYPE_DOUBLE);
00238 cpl_table_new_column(linetable, "dLambda_cat_sq" , CPL_TYPE_DOUBLE);
00239 cpl_table_new_column(linetable, "dLambda_nn_sq" , CPL_TYPE_DOUBLE);
00240
00241
00242
00243 cpl_table_new_column(linetable, "Ident", CPL_TYPE_DOUBLE);
00244 cpl_table_new_column(linetable, "dIdent",CPL_TYPE_DOUBLE);
00245 cpl_table_set_column_invalid(linetable, "Ident", 0, cpl_table_get_nrow(linetable));
00246 cpl_table_set_column_invalid(linetable, "dIdent",0, cpl_table_get_nrow(linetable));
00247
00248
00249 check( compute_lambda(linetable, guess_dispersion, NULL, false),
00250 "Error applying dispersion relation");
00251 }
00252
00253
00254 #if USE_PPM
00255 for (idloop = 2; idloop <= 2; idloop += 1)
00256 #else
00257 for (idloop = 1; idloop <= 2; idloop += 1)
00258 #endif
00259 {
00260
00261 current_id = 0;
00262 n = 0;
00263
00264 do {
00265 double rms_wlu;
00266 double rms_pixels;
00267 bool reject = (idloop == 2);
00268 #if USE_PPM
00269 int nident_ppm;
00270 #endif
00271
00272 previous_id = current_id;
00273 n++;
00274
00275
00276 check( current_id = identify_lines(linetable, line_refer, ALPHA),
00277 "Error identifying lines");
00278
00279
00280 #if USE_PPM
00281
00282 check( nident_ppm = uves_wavecal_identify_lines_ppm(linetable, line_refer),
00283 "Error during point pattern matching");
00284
00285 cpl_table_erase_column(linetable, "Ident");
00286 cpl_table_duplicate_column(linetable, "Ident", linetable, "Ident_ppm");
00287 current_id = nident_ppm;
00288
00289
00290
00291 cpl_table_fill_column_window(linetable, "dIdent",
00292 0, cpl_table_get_nrow(linetable),
00293 cpl_table_get_column_mean(linetable, "dIdent"));
00294 #endif
00295
00296
00297
00298
00299
00300 uves_polynomial_delete(&dispersion_relation);
00301 uves_polynomial_delete(&dispersion_variance);
00302
00303 check( dispersion_relation = calibrate_global(
00304 linetable, NULL,
00305 DEGREE, false,
00306 reject,
00307 TOLERANCE,
00308 kappa,
00309 &red_chisq,
00310 &dispersion_variance,
00311 &pixelsize,
00312 &rms_wlu,
00313 &rms_pixels),
00314 "Could not perform global calibration");
00315
00316 uves_msg_debug("Average pixelsize = %f wlu", pixelsize);
00317 if (idloop == 1)
00318 {
00319 uves_msg("%d identifications made. RMS = %.5f wlu = %.3f "
00320 "pixels (no rejection)",
00321 current_id, rms_wlu, rms_pixels);
00322 }
00323 else
00324 {
00325 uves_msg("%d identifications made. RMS = %.5f wlu = %.3f "
00326 "pixels (%f %s rejection, kappa = %.1f)",
00327 current_id, rms_wlu, rms_pixels,
00328 fabs(TOLERANCE), (TOLERANCE > 0) ? "pixels" : "wlu",
00329 kappa);
00330 }
00331 #if USE_PPM
00332 uves_msg("%d identifications from point pattern matching",
00333 nident_ppm);
00334 #endif
00335
00336 assure( rms_pixels < MAXERROR, CPL_ERROR_CONTINUE,
00337 "Wavelength calibration did not converge. "
00338 "After %d iterations the RMS was %f pixels. "
00339 "Try to improve on the initial solution", n, rms_pixels);
00340
00341
00342
00343 check( compute_lambda(linetable, dispersion_relation, dispersion_variance,
00344 false),
00345 "Error applying dispersion relation");
00346
00347
00348 }
00349 while (current_id > previous_id) ;
00350
00351
00352
00353 if (idloop == 1)
00354 {
00355
00356
00357
00358
00359 uves_msg("Identification loop converged. Resetting identifications");
00360 cpl_table_set_column_invalid(linetable, "Ident", 0,
00361 cpl_table_get_nrow(linetable));
00362 }
00363 }
00364
00365
00366
00367 uves_polynomial_delete(&dispersion_relation);
00368 uves_polynomial_delete(&dispersion_variance);
00369 uves_free_table(&selected);
00370
00371 check( dispersion_relation = calibrate_global(linetable,
00372 &selected,
00373 DEGREE, true,
00374 true,
00375 TOLERANCE,
00376 kappa,
00377 &red_chisq,
00378 &dispersion_variance,
00379 NULL, NULL, NULL),
00380 "Could not perform global calibration");
00381
00382
00383 check( compute_lambda(linetable, dispersion_relation, dispersion_variance,
00384 true),
00385 "Error applying dispersion relation");
00386
00387
00388
00389
00390 {
00391 int i, j;
00392
00393
00394
00395 cpl_table_new_column(linetable, "NLinSol", CPL_TYPE_INT);
00396 cpl_table_new_column(linetable, "Select", CPL_TYPE_INT);
00397
00398 cpl_table_fill_column_window_int(linetable, "NLinSol",
00399 0, cpl_table_get_nrow(linetable),
00400 0);
00401 cpl_table_fill_column_window_int(linetable, "Select",
00402 0, cpl_table_get_nrow(linetable),
00403 0);
00404
00405 j = 0;
00406 for (i = 0; i < cpl_table_get_nrow(selected); i++) {
00407 int order = cpl_table_get_int(selected, "Order", i, NULL);
00408 double x = cpl_table_get_double(selected, "X", i, NULL);
00409 int order2;
00410 double x2;
00411
00412
00413 passure( j < cpl_table_get_nrow(linetable), "%d %d",
00414 j, cpl_table_get_nrow(linetable));
00415 do {
00416 order2 = cpl_table_get_int(linetable, "Order", j, NULL);
00417 x2 = cpl_table_get_double(linetable, "X", j, NULL);
00418 if (cpl_table_is_valid(linetable, "Ident", j))
00419 {
00420 cpl_table_set_int(linetable, "Select", j, 1);
00421 }
00422 j++;
00423
00424 } while (order2 < order || x2 < x - 0.1);
00425
00426 passure( order2 == order && fabs(x2 - x) < 0.1,
00427 "%d %d %g %g", order2, order, x2, x);
00428
00429 cpl_table_set_int(linetable, "NLinSol", j-1, 1);
00430 }
00431 }
00432
00433
00434 check( verify_calibration(selected, linetable, TOLERANCE, red_chisq),
00435 "Error verifying calibration");
00436
00437 cleanup:
00438 uves_free_table(&selected);
00439 uves_polynomial_delete(&dispersion_variance);
00440 return dispersion_relation;
00441 }
00442
00443
00457
00458 static cpl_error_code
00459 verify_calibration(const cpl_table *selected,
00460 const cpl_table *linetable, double TOLERANCE,
00461 double red_chisq)
00462 {
00463 cpl_table *brightest = NULL;
00464 double median_intensity;
00465 int ninvalid;
00466 double ratio;
00467 double rms_wlu;
00468 double rms_pixels;
00469
00470 {
00471 double mean;
00472 double stdev;
00473
00474 check(( mean = cpl_table_get_column_mean (selected, LINETAB_RESIDUAL),
00475 stdev= cpl_table_get_column_stdev(selected, LINETAB_RESIDUAL),
00476 rms_wlu = sqrt(mean*mean + stdev*stdev),
00477
00478 mean = cpl_table_get_column_mean (selected, "Residual_pix"),
00479 stdev= cpl_table_get_column_stdev(selected, "Residual_pix"),
00480 rms_pixels = sqrt(mean*mean + stdev*stdev)),
00481 "Error reading RMS of fit");
00482 }
00483
00484 uves_msg("%d lines accepted", cpl_table_get_nrow(selected));
00485 uves_msg("Average RMS of calibration (tolerance = %.3f %s) = %.5f wlu = %.4f pixels ~ %.1f m/s",
00486 fabs(TOLERANCE),
00487 (TOLERANCE > 0) ? "pixels" : "wlu",
00488 rms_wlu, rms_pixels,
00489 rms_wlu * SPEED_OF_LIGHT/cpl_table_get_column_mean(selected,
00490 LINETAB_LAMBDAC));
00491
00492 uves_msg("Reduced chi^2 of calibration = %f", red_chisq);
00493
00494 if (red_chisq < .01)
00495 {
00496 uves_msg_warning("Reduced chi^2 of fit is less than 1/100: %f",
00497 red_chisq);
00498 }
00499 if (red_chisq > 100)
00500 {
00501 uves_msg_warning("Reduced chi^2 of fit is greater than 100: %f",
00502 red_chisq);
00503 }
00504
00505 check(( median_intensity = cpl_table_get_column_median(linetable, "Peak"),
00506 brightest = uves_extract_table_rows(linetable, "Peak",
00507 CPL_GREATER_THAN,
00508 median_intensity),
00509 ninvalid = cpl_table_count_invalid(brightest, "Ident")),
00510 "Error counting identifications");
00511
00512 ratio = 1 - ((double) ninvalid)/cpl_table_get_nrow(brightest);
00513 uves_msg("Percentage of identifications among the half brighter lines : %.2f %%",
00514 100*ratio);
00515
00516 cleanup:
00517 uves_free_table(&brightest);
00518
00519 return cpl_error_get_code();
00520 }
00521
00522
00536
00537 static cpl_error_code
00538 compute_lambda(cpl_table *linetable,
00539 const polynomial *dispersion_relation,
00540 const polynomial *dispersion_variance,
00541 bool verbose)
00542 {
00543 int i;
00544 bool printed_warning = false;
00545
00546
00547 passure(linetable != NULL, " ");
00548 passure(dispersion_relation != NULL, " ");
00549
00550
00551 passure( uves_polynomial_get_dimension(dispersion_relation) == 2, "%d",
00552 uves_polynomial_get_dimension(dispersion_relation));
00553
00554
00555 passure(cpl_table_has_column(linetable, "X") , " ");
00556 passure(cpl_table_has_column(linetable, "Order") , " ");
00557 passure(cpl_table_has_column(linetable, "Ident") , " ");
00558
00559 passure(cpl_table_has_column(linetable, LINETAB_LAMBDAC) , " ");
00560
00561 passure(cpl_table_has_column(linetable, "dLambdaC") , " ");
00562 passure(cpl_table_has_column(linetable, "dIdent") , " ");
00563 passure(cpl_table_has_column(linetable, LINETAB_RESIDUAL), " ");
00564 passure(cpl_table_has_column(linetable, "Residual_pix"), " ");
00565 passure(cpl_table_has_column(linetable, LINETAB_PIXELSIZE) , " ");
00566
00567
00568
00569 for(i = 0; i < cpl_table_get_nrow(linetable); i++)
00570 {
00571 int order;
00572 double x, dfdx;
00573 double lambdac, dlambdac, pixelsize;
00574 order = cpl_table_get_int(linetable, "Order", i, NULL);
00575
00576 x = cpl_table_get_double(linetable, "X", i, NULL);
00577
00578
00579
00580
00581 lambdac =
00582 uves_polynomial_evaluate_2d(dispersion_relation, x, order) / order;
00583
00584
00585 dfdx = uves_polynomial_derivative_2d(dispersion_relation, x, order, 1);
00586 if (dfdx < 0) {
00587 if (!printed_warning && verbose) {
00588 uves_msg_warning("Inferred dispersion (dlambda/dx) is negative at"
00589 "(x, order) = (%f, %d)", x, order);
00590 printed_warning = true;
00591 }
00592 else {
00593 uves_msg_debug("Inferred dispersion (dlambda/dx) is negative at "
00594 "(x, order) = (%f, %d)", x, order);
00595 }
00596 }
00597 pixelsize = dfdx / order;
00598
00599 check(( cpl_table_set_double(linetable, LINETAB_LAMBDAC , i, lambdac),
00600 cpl_table_set_double(linetable, LINETAB_PIXELSIZE, i, pixelsize)),
00601 "Error writing table");
00602
00603 if (dispersion_variance != NULL)
00604 {
00605
00606
00607 dlambdac =
00608 sqrt(uves_polynomial_evaluate_2d(dispersion_variance, x, order))
00609 / order;
00610
00611 cpl_table_set_double(linetable, "dLambdaC" , i, dlambdac);
00612 }
00613 else
00614 {
00615
00616
00617
00618
00619 cpl_table_set_double(linetable, "dLambdaC" , i, 1.0);
00620 }
00621
00622
00623 if (cpl_table_is_valid(linetable, "Ident", i))
00624 {
00625 double ident = cpl_table_get_double(linetable, "Ident", i, NULL);
00626 cpl_table_set_double(linetable, LINETAB_RESIDUAL, i,
00627 ident - lambdac);
00628 cpl_table_set_double(linetable, "Residual_pix", i,
00629 (ident - lambdac)/pixelsize);
00630 }
00631 else
00632 {
00633 cpl_table_set_invalid(linetable, LINETAB_RESIDUAL, i);
00634 cpl_table_set_invalid(linetable, "Residual_pix", i);
00635 }
00636 }
00637
00638
00639 check( uves_sort_table_2(linetable, "Order", "X", false, false),
00640 "Error sorting table");
00641
00642 cleanup:
00643 return cpl_error_get_code();
00644 }
00645
00646
00647
00684
00685
00686 static int
00687 identify_lines(cpl_table *linetable, const cpl_table *line_refer, double ALPHA)
00688 {
00689 int number_identifications = 0;
00690 int linetable_size;
00691 int linerefer_size;
00692 int row;
00693 int *histogram = NULL;
00694 const double minlog = -5.0;
00695
00696
00697 const double maxlog = 15.0;
00698 const int nbins = 400;
00699 double error = 0;
00700
00701 double average_dlambda_com = 0;
00702
00703
00704
00705 passure( linetable != NULL, " ");
00706
00707 passure( cpl_table_has_column(linetable, LINETAB_LAMBDAC ), " ");
00708
00709 passure( cpl_table_has_column(linetable, "dLambdaC" ), " ");
00710
00711 passure( cpl_table_has_column(linetable, "X" ), " ");
00712
00713 passure( cpl_table_has_column(linetable, "Order" ), " ");
00714
00715 passure( cpl_table_has_column(linetable, "Xwidth" ), " ");
00716 passure( cpl_table_has_column(linetable, LINETAB_PIXELSIZE), " ");
00717
00718
00719 passure( cpl_table_has_column(linetable, "Ident" ), " ");
00720
00721 passure( cpl_table_has_column(linetable, "dIdent" ), " ");
00722
00723
00724
00725 passure( line_refer != NULL, " ");
00726 passure( cpl_table_has_column(line_refer, "Wave" ), " ");
00727 passure( cpl_table_has_column(line_refer, "dWave"), " ");
00728
00729
00730 linetable_size = cpl_table_get_nrow(linetable);
00731 linerefer_size = cpl_table_get_nrow(line_refer);
00732 assure(linerefer_size >= 1, CPL_ERROR_ILLEGAL_INPUT, "Empty line reference table");
00733
00734
00735 passure( 0 < ALPHA && ALPHA <= 1, "%e", ALPHA);
00736
00737
00738 average_dlambda_com = cpl_table_get_column_median(linetable, "dLambdaC");
00739
00740
00741 histogram = cpl_calloc(nbins, sizeof(int));
00742 assure_mem( histogram );
00743
00744
00745
00746
00747
00748 for (row = 0; row < linetable_size; row++) {
00749 double lambda_com;
00750 double line_width;
00751 double line_fwhm;
00752 int order;
00753 double lambda_cat;
00754 double lambda_cat_sigma;
00755 double distance_cat_sq;
00756 double nn_distance_sq;
00757 int row_cat;
00758
00759
00760 lambda_com = cpl_table_get_double(linetable, LINETAB_LAMBDAC , row, NULL);
00761 order = cpl_table_get_int (linetable, "Order" , row, NULL);
00762
00763
00764 line_width =
00765 cpl_table_get_double(linetable, "Xwidth" , row, NULL) *
00766 fabs(cpl_table_get_double(linetable, LINETAB_PIXELSIZE , row, NULL));
00767
00768
00769 line_fwhm = TWOSQRT2LN2 * line_width;
00770
00771
00772 row_cat = uves_wavecal_find_nearest(
00773 line_refer, lambda_com, 0, linerefer_size - 1);
00774 lambda_cat = cpl_table_get_double(line_refer, "Wave", row_cat, NULL);
00775 lambda_cat_sigma = cpl_table_get_double(line_refer, "dWave",row_cat, NULL);
00776
00777
00778 distance_cat_sq = (lambda_com - lambda_cat)*(lambda_com - lambda_cat);
00779
00780
00781
00782
00783
00784 {
00785 double lambda_com_prev, lambda_com_next;
00786 int order_prev, order_next;
00787 double lambda_cat_prev, lambda_cat_next;
00788
00789 nn_distance_sq = DBL_MAX;
00790
00791
00792 if (row >= 1)
00793 {
00794 order_prev = cpl_table_get_int (
00795 linetable, "Order" , row - 1, NULL);
00796 lambda_com_prev = cpl_table_get_double(
00797 linetable, LINETAB_LAMBDAC, row - 1, NULL);
00798
00799 if (order == order_prev)
00800 {
00801 nn_distance_sq = uves_min_double(nn_distance_sq,
00802 (lambda_com_prev - lambda_com)*
00803 (lambda_com_prev - lambda_com)
00804 );
00805 }
00806 }
00807
00808 if (row <= linetable_size - 2)
00809 {
00810 order_next = cpl_table_get_int (linetable, "Order",
00811 row + 1, NULL);
00812 lambda_com_next = cpl_table_get_double(linetable, LINETAB_LAMBDAC,
00813 row + 1, NULL);
00814
00815 if (order == order_next)
00816 {
00817 nn_distance_sq = uves_min_double(nn_distance_sq,
00818 (lambda_com_next - lambda_com)*
00819 (lambda_com_next - lambda_com)
00820 );
00821 }
00822 }
00823
00824
00825 if (row_cat >= 1)
00826 {
00827 lambda_cat_prev = cpl_table_get_double(
00828 line_refer, "Wave", row_cat - 1, NULL);
00829
00830 nn_distance_sq = uves_min_double(
00831 nn_distance_sq,
00832 (lambda_cat_prev - lambda_cat)*
00833 (lambda_cat_prev - lambda_cat)
00834 );
00835 }
00836 if (row_cat <= linerefer_size - 2)
00837 {
00838 lambda_cat_next = cpl_table_get_double(
00839 line_refer, "Wave", row_cat + 1, NULL);
00840
00841 nn_distance_sq = uves_min_double(
00842 nn_distance_sq,
00843 (lambda_cat_next - lambda_cat)*
00844 (lambda_cat_next - lambda_cat)
00845 );
00846 }
00847
00848
00849
00850 if (nn_distance_sq < DBL_MAX)
00851 {
00852 nn_distance_sq *= ALPHA*ALPHA;
00853 }
00854
00855 }
00856
00857
00858 cpl_table_set_double(linetable, "Lambda_candidate", row, lambda_cat);
00859 cpl_table_set_double(linetable, "dLambda_candidate",row, lambda_cat_sigma);
00860 cpl_table_set_double(linetable, "dLambda_cat_sq", row, distance_cat_sq);
00861 cpl_table_set_double(linetable, "dLambda_nn_sq", row, nn_distance_sq);
00862
00863
00864
00865 {
00866 int ilow = uves_round_double((0.5*log(distance_cat_sq/(line_fwhm*line_fwhm))
00867 - minlog)/(maxlog - minlog) * nbins);
00868 int ihigh = uves_round_double((0.5*log(nn_distance_sq /(line_fwhm*line_fwhm))
00869 - minlog)/(maxlog - minlog) * nbins);
00870 int i;
00871
00872 for (i = uves_max_int(ilow, 0); i < uves_min_int(ihigh, nbins); i++)
00873 {
00874 histogram[i] += 1;
00875 }
00876 }
00877 }
00878
00879
00880 {
00881 int i;
00882 int maxfreq = -1;
00883 for (i = 0; i < nbins; i++)
00884 {
00885 uves_msg_debug("histogram[%d] = %d", i, histogram[i]);
00886 if (histogram[i] > maxfreq)
00887 {
00888 maxfreq = histogram[i];
00889 error = exp( i / ((double)nbins) * (maxlog - minlog) + minlog ) ;
00890
00891 }
00892 }
00893 uves_msg_debug("Dimensionless error factor is %f", error);
00894 }
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928 for (row = 0; row < linetable_size; row++)
00929 {
00930 double distance_cat_sq;
00931 double nn_distance_sq;
00932 double tolerance_sq;
00933 double dlambda_com;
00934 double line_width;
00935 double line_fwhm;
00936 double lambda_cat;
00937 double lambda_cat_sigma;
00938
00939 lambda_cat = cpl_table_get_double(linetable, "Lambda_candidate", row, NULL);
00940 lambda_cat_sigma = cpl_table_get_double(linetable, "dLambda_candidate", row, NULL);
00941
00942
00943
00944
00945
00946
00947
00948
00949 line_width =
00950 uves_max_double(1, cpl_table_get_double(linetable, "Xwidth" , row, NULL)) *
00951 fabs(cpl_table_get_double(linetable, LINETAB_PIXELSIZE , row, NULL));
00952
00953
00954 line_fwhm = TWOSQRT2LN2 * line_width;
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966 dlambda_com = line_fwhm
00967 * cpl_table_get_double(linetable, "dLambdaC" , row, NULL)
00968 / average_dlambda_com;
00969
00970 tolerance_sq = line_fwhm*line_fwhm * error*error;
00971
00972 distance_cat_sq = cpl_table_get_double(linetable, "dLambda_cat_sq", row, NULL);
00973 nn_distance_sq = cpl_table_get_double(linetable, "dLambda_nn_sq" , row, NULL);
00974
00975 #if WANT_BIG_LOGFILE
00976 uves_msg_debug("(order,x) = (%d,%f) lcom = %f+-%f lcat = %f "
00977 "dist_cat = %f (%f pixels) tolerance = %.3f error = %f "
00978 "nn = %f (%f pixels)",
00979 cpl_table_get_int (linetable, "Order" , row, NULL),
00980 cpl_table_get_double(linetable, "X" , row, NULL),
00981 cpl_table_get_double(linetable, LINETAB_LAMBDAC, row, NULL),
00982 dlambda_com,
00983 lambda_cat,
00984 sqrt(distance_cat_sq),
00985 sqrt(distance_cat_sq)
00986 /cpl_table_get_double(linetable, LINETAB_PIXELSIZE, row, NULL),
00987 sqrt(tolerance_sq),
00988 error,
00989 sqrt(nn_distance_sq),
00990 sqrt(nn_distance_sq)
00991 /cpl_table_get_double(linetable, LINETAB_PIXELSIZE, row, NULL));
00992 #endif
00993
00994
00995 if (distance_cat_sq < (dlambda_com)*(dlambda_com)
00996 && tolerance_sq < nn_distance_sq
00997 && distance_cat_sq < nn_distance_sq)
00998 {
00999 number_identifications++;
01000 cpl_table_set_double(linetable, "Ident", row, lambda_cat);
01001 cpl_table_set_double(linetable, "dIdent",row, lambda_cat_sigma);
01002 #if WANT_BIG_LOGFILE
01003 uves_msg_debug("ID made");
01004 #endif
01005 }
01006 else
01007 {
01008 if (cpl_table_is_valid(linetable, "Ident", row)) {
01009 number_identifications++;
01010
01011 uves_msg_debug("Line at (%d,%f) does not match ID criterion anymore",
01012 cpl_table_get_int (linetable, "Order", row, NULL),
01013 cpl_table_get_double(linetable, "X", row, NULL)
01014 );
01015 }
01016 }
01017 }
01018
01019 cleanup:
01020 cpl_free(histogram);
01021 return number_identifications;
01022 }
01023
01024
01050
01051 static polynomial *
01052 calibrate_global(const cpl_table *linetable,
01053 cpl_table **selected,
01054 int degree, bool verbose,
01055 bool reject,
01056 double TOLERANCE,
01057 double kappa,
01058 double *red_chisq, polynomial **dispersion_variance,
01059 double *pixelsize,
01060 double *rms_wlu,
01061 double *rms_pixels)
01062 {
01063 polynomial *dispersion_relation = NULL;
01064 cpl_table *identified = NULL;
01065 int valid_ids =
01066 cpl_table_get_nrow(linetable) -
01067 cpl_table_count_invalid(linetable, "Ident");
01068 int rejected;
01069
01070 passure( (pixelsize == NULL) == (rms_wlu == NULL) &&
01071 (pixelsize == NULL) == (rms_pixels == NULL), " ");
01072
01073 assure( degree < 0 ||
01074 valid_ids >= (degree + 1)*(degree + 1), CPL_ERROR_ILLEGAL_INPUT,
01075 "There are not enough identifications to create a %d.-degree global fit. "
01076 "%d needed. %d found", degree, (degree + 1)*(degree + 1), valid_ids);
01077
01078 identified = cpl_table_duplicate(linetable);
01079 assure_mem(identified);
01080
01081
01082 if (reject)
01083 {
01084 check_nomsg( rejected = uves_delete_bad_lines(identified, TOLERANCE, kappa) );
01085 uves_msg_debug("%d lines rejected %f %f", rejected, TOLERANCE, kappa);
01086 }
01087 else
01088 {
01089 check( uves_erase_invalid_table_rows(identified, "Ident"),
01090 "Error erasing un-identified lines");
01091 }
01092
01093
01094
01095 check(( cpl_table_duplicate_column(identified, "Aux", identified, "Ident"),
01096 cpl_table_multiply_columns(identified, "Aux", "Order"),
01097
01098
01099 cpl_table_duplicate_column(identified, "dAux", identified, "dIdent"),
01100 cpl_table_multiply_columns(identified, "dAux", "Order")),
01101 "Error setting up temporary table");
01102
01103
01104
01105 if (degree >= 0) {
01106 check( dispersion_relation =
01107 uves_polynomial_regression_2d(identified,
01108 "X", "Order", "Aux",
01109 "dAux",
01110
01111
01112
01113
01114
01115
01116 degree, degree,
01117 NULL, NULL, NULL,
01118 NULL,
01119 red_chisq,
01120 dispersion_variance,
01121 reject ? kappa : -1, -1),
01122 "Error fitting polynomial. Possible cause: too few (%d) "
01123 "line identifications", valid_ids);
01124 }
01125 else {
01126 int max_degree = 8;
01127 double min_rms = -1;
01128 double min_reject = -1;
01129 check( dispersion_relation =
01130 uves_polynomial_regression_2d_autodegree(identified,
01131 "X", "Order", "Aux",
01132 "dAux",
01133 NULL, NULL, NULL,
01134 NULL,
01135 red_chisq,
01136 dispersion_variance,
01137 reject ? kappa : -1,
01138 max_degree, max_degree,
01139 min_rms, min_reject,
01140 verbose,
01141 NULL, NULL, 0, NULL),
01142 "Error fitting polynomial. Possible cause: too few (%d) "
01143 "line identifications", valid_ids);
01144 }
01145
01146 if (pixelsize != NULL)
01147 {
01148
01149
01150 check( compute_lambda(identified, dispersion_relation, NULL,
01151 false),
01152 "Error applying dispersion relation");
01153
01154 *pixelsize = cpl_table_get_column_median(identified, LINETAB_PIXELSIZE);
01155 *rms_wlu = cpl_table_get_column_stdev (identified, LINETAB_RESIDUAL);
01156 *rms_pixels= cpl_table_get_column_stdev (identified, "Residual_pix");
01157 }
01158
01159 if (selected != NULL) {
01160 *selected = cpl_table_duplicate(identified);
01161 }
01162
01163 cleanup:
01164 uves_free_table(&identified);
01165 if (cpl_error_get_code() != CPL_ERROR_NONE)
01166 {
01167 uves_polynomial_delete(&dispersion_relation);
01168 }
01169
01170 return dispersion_relation;
01171 }
01172
01173
01174
01175
01182
01183
01184 int
01185 uves_wavecal_identify_lines_ppm(cpl_table *linetable, const cpl_table *line_refer)
01186 {
01187 int result = 0;
01188 int minorder, maxorder;
01189 int order;
01190 cpl_table *lt_order = NULL;
01191 cpl_table *refer_order = NULL;
01192 cpl_vector *peaks = NULL;
01193 cpl_vector *lines = NULL;
01194 cpl_bivector *ids = NULL;
01195
01196 assure( cpl_table_has_column(linetable, LINETAB_LAMBDAC), CPL_ERROR_DATA_NOT_FOUND,
01197 "Missing column %s", LINETAB_LAMBDAC);
01198
01199 assure( cpl_table_has_column(linetable, LINETAB_PIXELSIZE), CPL_ERROR_DATA_NOT_FOUND,
01200 "Missing column %s", LINETAB_PIXELSIZE);
01201
01202 assure( cpl_table_has_column(linetable, "Order"), CPL_ERROR_DATA_NOT_FOUND,
01203 "Missing column %s", "Order");
01204
01205 minorder = uves_round_double( cpl_table_get_column_min(linetable, "Order"));
01206 maxorder = uves_round_double( cpl_table_get_column_max(linetable, "Order"));
01207
01208
01209 if (cpl_table_has_column(linetable, "Ident_ppm"))
01210 {
01211 cpl_table_erase_column(linetable, "Ident_ppm");
01212 }
01213
01214 cpl_table_new_column(linetable, "Ident_ppm", CPL_TYPE_DOUBLE);
01215
01216 for (order = minorder; order <= maxorder; order++)
01217 {
01218 const double tolerance = 0.05;
01219 double min_lambda, max_lambda;
01220 double min_disp, max_disp;
01221
01222
01223
01224 uves_free_table(<_order);
01225 lt_order = uves_extract_table_rows(linetable, "Order",
01226 CPL_EQUAL_TO, order);
01227
01228 check_nomsg((min_lambda = cpl_table_get_column_min(lt_order, LINETAB_LAMBDAC),
01229 max_lambda = cpl_table_get_column_max(lt_order, LINETAB_LAMBDAC),
01230 min_disp = cpl_table_get_column_min(lt_order, LINETAB_PIXELSIZE)*0.99,
01231 max_disp = cpl_table_get_column_max(lt_order, LINETAB_PIXELSIZE)*1.01));
01232
01233 uves_free_table(&refer_order);
01234 refer_order = uves_extract_table_rows(line_refer, "Wave", CPL_GREATER_THAN,
01235 min_lambda);
01236 uves_extract_table_rows_local(refer_order, "Wave", CPL_LESS_THAN,
01237 max_lambda);
01238
01239
01240 {
01241 int i;
01242 uves_free_vector(&peaks);
01243 peaks = cpl_vector_new(cpl_table_get_nrow(lt_order));
01244 for (i = 0; i < cpl_vector_get_size(peaks); i++)
01245 {
01246 cpl_vector_set(peaks, i, cpl_table_get_double(lt_order, "X", i, NULL));
01247 }
01248
01249 uves_free_vector(&lines);
01250 lines = cpl_vector_new(cpl_table_get_nrow(refer_order));
01251 for (i = 0; i < cpl_vector_get_size(lines); i++)
01252 {
01253 cpl_vector_set(lines, i, cpl_table_get_double(refer_order, "Wave", i, NULL));
01254 }
01255 }
01256
01257
01258 cpl_vector_sort(peaks, 1);
01259 cpl_vector_sort(lines, 1);
01260
01261 uves_msg_debug("Call ppm with %d peaks, %d lines, dispersion range = %f - %f A/pixel",
01262 cpl_vector_get_size(peaks),
01263 cpl_vector_get_size(lines),
01264 min_disp, max_disp);
01265
01266 uves_free_bivector(&ids);
01267 ids = irplib_ppm_match_positions(peaks, lines,
01268 min_disp, max_disp,
01269 tolerance);
01270
01271 if (ids == NULL)
01272 {
01273 uves_msg_warning("Order %d: Point pattern matching failed", order);
01274 if (cpl_error_get_code() != CPL_ERROR_NONE)
01275 {
01276 uves_msg_debug("%s at %s", cpl_error_get_message(),
01277 cpl_error_get_where());
01278 uves_error_reset();
01279 }
01280 }
01281 else
01282 {
01283 int i, j;
01284
01285 uves_msg_debug("%d identifications from point pattern matching (order %d)",
01286 cpl_bivector_get_size(ids), order);
01287
01288 result += cpl_bivector_get_size(ids);
01289
01290 for (i = 0; i < cpl_table_get_nrow(linetable); i++) {
01291
01292 if (cpl_table_get_int(linetable, "Order", i, NULL) == order)
01293 for (j = 0; j < cpl_bivector_get_size(ids); j++)
01294 {
01295 if (fabs(cpl_table_get_double(linetable, "X", i, NULL) -
01296 cpl_bivector_get_x_data(ids)[j]) < 0.001)
01297 cpl_table_set_double(linetable, "Ident_ppm", i,
01298 cpl_bivector_get_y_data(ids)[j]);
01299 }
01300 }
01301 }
01302 }
01303
01304 cleanup:
01305 uves_free_table(<_order);
01306 uves_free_table(&refer_order);
01307 uves_free_vector(&peaks);
01308 uves_free_vector(&lines);
01309 uves_free_bivector(&ids);
01310
01311 return result;
01312 }