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