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