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