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