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