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
00095 #ifdef HAVE_CONFIG_H
00096 # include <config.h>
00097 #endif
00098
00099 #include <uves_wavecal_firstsolution.h>
00100
00101 #include <uves_utils.h>
00102 #include <uves_utils_wrappers.h>
00103 #include <uves_dump.h>
00104 #include <uves_error.h>
00105 #include <uves_msg.h>
00106
00107 #include <irplib_access.h>
00108 #include <cpl.h>
00109
00110 #include <math.h>
00111
00112 static int *
00113 write_physical_order(cpl_table *linetable,
00114 const polynomial *absolute_order,
00115 const cpl_table *ordertable,
00116 const polynomial *order_locations,
00117 int *first_abs_order, int *last_abs_order);
00118
00119 static double
00120 calculate_shift(const cpl_table *linetable, const cpl_table *previous,
00121 const char *column, const char *reference_column,
00122 double range, double step, double tolerance);
00123
00124 static double
00125 cross_correlation(double shift,
00126 const cpl_table *t1, const cpl_table *t2,
00127 const char *column, const char* reference_column,
00128 int minref, int maxref, double tolerance);
00129
00130 static polynomial *apply_shift(const cpl_table *previous,
00131 const double shift, const int degree, double *mse);
00132
00133
00180
00181 polynomial *
00182 uves_wavecal_firstsolution(cpl_table *linetable,
00183 const cpl_table *guess,
00184 polynomial **absolute_order,
00185 const cpl_table *ordertable,
00186 const polynomial *order_locations,
00187 bool flames,
00188 double offset,
00189 int **relative_order,
00190 int DEGREE, double CORREL_RANGE, double CORREL_STEP,
00191 double CORREL_TOLERANCE, double MAXERROR,
00192 int *first_abs_order, int *last_abs_order)
00193 {
00194 polynomial *initial_dispersion = NULL;
00195 polynomial *new_absorder = NULL;
00196 const char *er_msg = NULL;
00197 double shift;
00198 double mse;
00199
00200
00201 check( *relative_order = write_physical_order(linetable, *absolute_order,
00202 ordertable,
00203 order_locations,
00204 first_abs_order,
00205 last_abs_order),
00206 "Could not calculate absolute order numbers");
00207
00208
00209 {
00210 int row;
00211
00212
00213 cpl_table_new_column(linetable, "Ynew", CPL_TYPE_DOUBLE);
00214 for (row = 0; row < cpl_table_get_nrow(linetable); row++)
00215 {
00216
00217
00218
00219 int order = cpl_table_get_int (linetable, "Y", row, NULL);
00220 double x = cpl_table_get_double(linetable, "X", row, NULL);
00221
00222 cpl_table_set_double(
00223 linetable, "Ynew", row,
00224 uves_polynomial_evaluate_2d(order_locations, x, order));
00225 }
00226
00227 assure_nomsg( cpl_error_get_code() == CPL_ERROR_NONE,
00228 cpl_error_get_code() );
00229
00230 new_absorder =
00231 uves_polynomial_regression_2d(linetable, "X", "Ynew", "Order",
00232 NULL,
00233 DEGREE, DEGREE,
00234 NULL, NULL, NULL,
00235 NULL, NULL,
00236 NULL,
00237 -1, -1);
00238
00239 if (cpl_error_get_code() != CPL_ERROR_NONE)
00240 {
00241 er_msg = uves_sprintf("%s", cpl_error_get_message());
00242
00243 uves_error_reset();
00244 uves_msg_warning("Could not make global fit of absolute order number (%s). "
00245 "Polynomial is not updated",
00246 er_msg);
00247 }
00248 else
00249 {
00250 uves_polynomial_delete(absolute_order);
00251 *absolute_order = uves_polynomial_duplicate(new_absorder);
00252 }
00253
00254
00255 if (flames)
00256 {
00257 cpl_table_add_scalar(linetable, "Ynew", + offset);
00258 }
00259 }
00260
00261
00262 uves_sort_table_2(linetable, "Order", "X", false, false);
00263
00264
00265
00266 check( shift = calculate_shift(guess, linetable, "X", "Order",
00267 CORREL_RANGE, CORREL_STEP, CORREL_TOLERANCE),
00268 "Could not calculate shift of position w.r.t. guess solution");
00269
00270
00271
00272
00273
00274
00275
00276
00277 check( initial_dispersion = apply_shift(guess, shift, DEGREE, &mse),
00278 "Could not calculate initial dispersion relation");
00279
00280
00281
00282
00283 if(mse > MAXERROR*MAXERROR)
00284 {
00285 uves_msg_warning("RMS of initial fit (%f pixels) is greater "
00286 "than tolerance (%f pixels)", sqrt(mse), MAXERROR);
00287 }
00288
00289 cleanup:
00290 uves_free_string_const(&er_msg);
00291 uves_polynomial_delete(&new_absorder);
00292 if (cpl_error_get_code() != CPL_ERROR_NONE)
00293 {
00294 uves_polynomial_delete(&initial_dispersion);
00295 }
00296
00297 return initial_dispersion;
00298 }
00299
00300
00315
00316 static polynomial *
00317 apply_shift(const cpl_table *guess, double shift, int degree, double *mse)
00318 {
00319 polynomial *result = NULL;
00320 cpl_table *t = NULL;
00321
00322
00323 check( t = cpl_table_duplicate(guess),
00324 "Error duplicating table");
00325
00326
00327 check(( cpl_table_duplicate_column(t, "ident_order", t, "Ident"),
00328 cpl_table_multiply_columns(t, "ident_order", "Order")),
00329
00330 "Error creating auxillary column");
00331
00332
00333 check( cpl_table_add_scalar(t, "X", shift), "Error shifting column 'X'");
00334
00335
00336
00337 result = uves_polynomial_regression_2d(t, "X", "Order", "ident_order", NULL,
00338 degree, degree,
00339 NULL, NULL, NULL,
00340 mse, NULL,
00341 NULL, -1, -1);
00342
00343
00344 if (cpl_error_get_code() != CPL_ERROR_NONE)
00345 {
00346 uves_error_reset();
00347
00348 assure( false, CPL_ERROR_SINGULAR_MATRIX,
00349 "Polynomial fitting failed");
00350 }
00351
00352 cleanup:
00353 uves_free_table(&t);
00354 return result;
00355 }
00356
00357
00380
00381
00382 static double
00383 calculate_shift(const cpl_table *linetable, const cpl_table *guess, const char *column,
00384 const char *reference_column, double range, double step, double tolerance)
00385 {
00386 cpl_type t;
00387 int minorder, maxorder;
00388 int N, i;
00389 double shift, max_corr, median_corr, maxpos = 0;
00390 cpl_table *temp = NULL;
00391
00392 assure( cpl_table_has_column(linetable, column),
00393 CPL_ERROR_ILLEGAL_INPUT, "Table has no '%s' column", column);
00394 assure( cpl_table_has_column(guess , column),
00395 CPL_ERROR_ILLEGAL_INPUT, "Table has no '%s' column", column);
00396 assure( cpl_table_has_column(linetable, reference_column),
00397 CPL_ERROR_ILLEGAL_INPUT, "Table has no '%s' column", reference_column);
00398 assure( cpl_table_has_column(guess , reference_column),
00399 CPL_ERROR_ILLEGAL_INPUT, "Table has no '%s' column", reference_column);
00400 assure( range > 0, CPL_ERROR_ILLEGAL_INPUT, "Range = %f", range);
00401
00402 t = cpl_table_get_column_type(linetable, column);
00403 assure( t == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
00404 "Column '%s' has type '%s'. Double expected", column, uves_tostring_cpl_type(t));
00405
00406 t = cpl_table_get_column_type(guess, column);
00407 assure( t == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
00408 "Column '%s' has type '%s'. Double expected", column, uves_tostring_cpl_type(t));
00409
00410 t = cpl_table_get_column_type(linetable, reference_column);
00411 assure( t == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
00412 "Ref. column '%s' has type '%s'. Integer expected",
00413 reference_column, uves_tostring_cpl_type(t));
00414
00415 t = cpl_table_get_column_type(guess, reference_column);
00416 assure( t == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
00417 "Ref. column '%s' has type '%s'. Integer expected",
00418 reference_column, uves_tostring_cpl_type(t));
00419
00420
00421 check(( minorder =
00422 uves_max_int(cpl_table_get_column_min(guess, reference_column),
00423 cpl_table_get_column_min(linetable, reference_column)),
00424 maxorder =
00425 uves_min_int(cpl_table_get_column_max(guess, reference_column),
00426 cpl_table_get_column_max(linetable, reference_column))),
00427 "Error reading column '%s'", reference_column);
00428
00429 assure(maxorder >= minorder, CPL_ERROR_ILLEGAL_INPUT, "No common orders found");
00430
00431 uves_msg("Min/max common absolute orders = %d - %d", minorder, maxorder);
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441 N = 0;
00442 for (shift = -range; shift <= range; shift += step)
00443 {
00444 N += 1;
00445 }
00446
00447 temp = cpl_table_new(N);
00448 cpl_table_new_column(temp, "Corr", CPL_TYPE_DOUBLE);
00449
00450 max_corr = -1;
00451 maxpos = 0;
00452 for (shift = -range, i = 0;
00453 i < N;
00454 shift += step , i++)
00455 {
00456 double corr;
00457 check( corr = cross_correlation(shift, linetable, guess, column,
00458 reference_column, minorder, maxorder, tolerance),
00459 "Error calculating spectrum cross correlation for shift = %f pixel(s)",
00460 shift);
00461
00462
00463 check( cpl_table_set_double(temp, "Corr", i, corr),
00464 "Error updating table");
00465
00466 uves_msg_debug("Correlation(shift=%f) = %f", shift, corr);
00467
00468 if (corr > max_corr)
00469 {
00470 max_corr = corr;
00471 maxpos = shift;
00472 }
00473 }
00474
00475
00476
00477
00478
00479
00480 median_corr = cpl_table_get_column_median(temp, "Corr");
00481
00482
00483 if (median_corr < 0.5)
00484 {
00485 median_corr = 1;
00486 }
00487
00488 uves_msg("Estimated shift compared to guess solution is %f pixels (%.2f sigma detection)",
00489 maxpos, max_corr / median_corr);
00490
00491
00492
00493
00494
00495 if (max_corr / median_corr < 10)
00496 {
00497 uves_msg_warning("Cross-correlation with guess solution is "
00498 "only %f times no correlation (usually >30). "
00499 "Make sure that the guess solution is within ~10 pixels "
00500 "of the real dispersion relation; otherwise the following "
00501 "wavelength calibration is likely to fail or converge "
00502 "to a wrong solution",
00503 max_corr / median_corr);
00504 }
00505
00506 cleanup:
00507 uves_free_table(&temp);
00508 return maxpos;
00509 }
00510
00511
00533
00534 static double
00535 cross_correlation(double shift,
00536 const cpl_table *t1, const cpl_table *t2,
00537 const char *column, const char* reference_column,
00538 int minref, int maxref, double tolerance)
00539 {
00540 double result = 0;
00541 int i1 = 0;
00542 int i2 = 0;
00543
00544
00545 const double *col1 = irplib_table_get_data_double_const(t1, column);
00546 const double *col2 = irplib_table_get_data_double_const(t2, column);
00547 const int *ref1 = irplib_table_get_data_int_const(t1, reference_column);
00548 const int *ref2 = irplib_table_get_data_int_const(t2, reference_column);
00549
00550 int N1 = cpl_table_get_nrow(t1);
00551 int N2 = cpl_table_get_nrow(t2);
00552
00553 assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
00554 "Error reading input table");
00555
00556
00557 while (i1 < N1 && ref1[i1] <= maxref &&
00558 i2 < N2 && ref2[i2] <= maxref) {
00559 if (i1 < minref || ref1[i1] < ref2[i2])
00560 i1++;
00561 else if (i2 < minref || ref1[i1] > ref2[i2])
00562 i2++;
00563 else {
00564
00565 double difference = col2[i2] - (col1[i1] + shift);
00566
00567 if (difference > tolerance)
00568 {
00569 i1++;
00570 }
00571 else if (difference < -tolerance)
00572 {
00573 i2++;
00574 }
00575 else {
00576
00577
00578 result += 1.0;
00579 i2++;
00580 }
00581 }
00582 }
00583
00584
00585 cleanup:
00586 return result;
00587 }
00588
00589
00590
00609
00610 static int *
00611 write_physical_order(cpl_table *linetable, const polynomial *absolute_order,
00612 const cpl_table *ordertable,
00613 const polynomial *order_locations,
00614 int *first_abs_order, int *last_abs_order)
00615 {
00616 int *relative_order = NULL;
00617 int *physical_order = NULL;
00618 int minorder, maxorder;
00619 int maxphysical;
00620 cpl_table *temp = NULL;
00621 const polynomial *map = NULL;
00622
00623 double *sum = NULL;
00624 int *N = NULL;
00625
00626 int i;
00627
00628 check( cpl_table_new_column(linetable, "Order", CPL_TYPE_INT),
00629 "Error creating column");
00630
00631 check( cpl_table_new_column(linetable, "AbsOrder", CPL_TYPE_DOUBLE),
00632 "Error creating column");
00633
00634 check(( minorder = cpl_table_get_column_min(ordertable, "Order"),
00635 maxorder = cpl_table_get_column_max(ordertable, "Order")),
00636 "Could not read min. and max. order numbers");
00637
00638 assure( minorder > 0, CPL_ERROR_ILLEGAL_INPUT,
00639 "Non-positive order number (%d) in linetable", minorder);
00640
00641 physical_order = cpl_calloc(maxorder + 1, sizeof(int));
00642 assure_mem( physical_order );
00643
00644
00645
00646 for (i = 0; i < cpl_table_get_nrow(linetable); i++) {
00647 double x, y;
00648 double absorder;
00649 int order;
00650
00651 order = cpl_table_get_int (linetable, "Y", i, NULL);
00652
00653
00654 x = cpl_table_get_double(linetable, "X", i, NULL);
00655
00656 y = uves_polynomial_evaluate_2d(order_locations, x, order);
00657
00658 absorder = uves_polynomial_evaluate_2d(absolute_order, x, y);
00659
00660 uves_msg_debug("Order #%d: Absolute order = %f at x = %f",
00661 order, absorder, x);
00662
00663 cpl_table_set_double(linetable, "AbsOrder", i, absorder);
00664 }
00665
00666 {
00667 int degree = 1;
00668 int coeff1, coeff2;
00669 int order;
00670 int relorder_median;
00671 int absorder_median;
00672
00673 check_nomsg( map =
00674 uves_polynomial_regression_1d(linetable,
00675 "Y", "AbsOrder", NULL,
00676 degree,
00677 NULL, NULL, NULL, -1));
00678
00679 relorder_median = uves_round_double(cpl_table_get_column_median(linetable, "Y"));
00680 absorder_median = uves_round_double(uves_polynomial_evaluate_1d(map, relorder_median));
00681
00682 if (uves_polynomial_derivative_1d(map, relorder_median) > 0) {
00683 coeff2 = 1;
00684 }
00685 else {
00686 coeff2 = -1;
00687 }
00688
00689 coeff1 = absorder_median - coeff2 * relorder_median;
00690
00691 uves_msg_debug("Assuming relation: abs.order = %d + (%d) * rel.order",
00692 coeff1, coeff2);
00693
00694 maxphysical = -1;
00695 for (order = minorder; order <= maxorder; order++) {
00696 physical_order[order] = coeff1 + coeff2 * order;
00697
00698 assure(physical_order[order] > 0, CPL_ERROR_ILLEGAL_OUTPUT,
00699 "Estimated physical order number is non-positive (%d)",
00700 physical_order[order]);
00701
00702 if (physical_order[order] > maxphysical)
00703 {
00704 maxphysical = physical_order[order];
00705 }
00706
00707 uves_msg_debug("Mapping relative order #%d to absolute order #%d",
00708 order, physical_order[order]);
00709 }
00710
00711
00712 *first_abs_order = physical_order[minorder];
00713 *last_abs_order = physical_order[maxorder];
00714
00715 passure( *first_abs_order - *last_abs_order == coeff2*(minorder - maxorder),
00716 "%d %d %d %d %d",
00717 *first_abs_order, *last_abs_order, coeff2, minorder, maxorder);
00718
00719 }
00720
00721
00722 for (i = 0; i < cpl_table_get_nrow(linetable); i++) {
00723 int order;
00724 order = cpl_table_get_int (linetable, "Y", i, NULL);
00725 cpl_table_set_int(linetable, "Order", i, physical_order[order]);
00726 }
00727
00728
00729 relative_order = cpl_calloc(maxphysical + 1, sizeof(int));
00730 for (i = 0; i <= maxorder; i++)
00731 {
00732 relative_order[physical_order[i]] = i;
00733 }
00734
00735 cleanup:
00736 uves_free_table(&temp);
00737 uves_polynomial_delete_const(&map);
00738 cpl_free(sum);
00739 cpl_free(physical_order);
00740 cpl_free(N);
00741
00742 return relative_order;
00743 }