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