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
00114
00117 #ifdef HAVE_CONFIG_H
00118 # include <config.h>
00119 #endif
00120
00121 #include <uves_wavecal_search.h>
00122 #include <uves_utils.h>
00123 #include <uves_utils_wrappers.h>
00124 #include <uves_utils_cpl.h>
00125 #include <uves_pfits.h>
00126 #include <uves_dump.h>
00127 #include <uves_error.h>
00128 #include <uves_msg.h>
00129
00130 #include <cpl.h>
00131 #include <float.h>
00132
00133 #define FIT_SLOPE 1
00134 #define WEIGHTED_FIT 1
00135
00136
00137 static double
00138 xcenter(const cpl_image *image, const cpl_image *noise, int xlo, int xhi, int row,
00139 centering_method CENTERING_METHOD, int bin_disp,
00140 double *sigma, double *intensity, double *dx0, double *slope, double *background);
00141
00142 static cpl_error_code
00143 detect_lines(const cpl_image *spectrum, const cpl_image *noise,
00144 const uves_propertylist *spectrum_header,
00145 bool flat_fielded,
00146 int RANGE, double THRESHOLD, centering_method CENTERING_METHOD,
00147 int bin_disp,
00148 const polynomial *order_locations, cpl_image *arcframe,
00149 cpl_table *linetable,
00150 int *ndetected, int *nrows);
00151
00152
00182
00183 cpl_table *
00184 uves_wavecal_search(const cpl_image *spectrum, const cpl_image *noise,
00185 const uves_propertylist *spectrum_header,
00186 bool flat_fielded,
00187 const polynomial *order_locations, cpl_image *arcframe,
00188 int RANGE, int MINLINES, int MAXLINES,
00189 centering_method CENTERING_METHOD,
00190 int bin_disp)
00191 {
00192 cpl_table *linetable = NULL;
00193
00194 int nx, ny, norders;
00195 double threshold_low;
00196 double threshold_high;
00197 double threshold = 0;
00198 int lines_in_table;
00199 int lines_detected;
00200 bool max_thresh_found = false;
00201
00202 passure( spectrum != NULL, "Null input spectrum");
00203 passure( order_locations != NULL, "Null polynomial");
00204 passure( arcframe != NULL, "Null raw image");
00205
00206 if (flat_fielded) {
00207 assure( cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE,
00208 CPL_ERROR_TYPE_MISMATCH,
00209 "Spectrum image type is %s, must be double",
00210 uves_tostring_cpl_type(cpl_image_get_type(spectrum)));
00211 }
00212
00213 check(( nx = cpl_image_get_size_x(spectrum),
00214 norders = cpl_image_get_size_y(spectrum)), "Error reading input spectrum");
00215 check( ny = cpl_image_get_size_y(arcframe), "Error reading input image");
00216 assure(nx == cpl_image_get_size_x(arcframe), CPL_ERROR_INCOMPATIBLE_INPUT,
00217 "Spectrum and image widths are different (%d and %d)",
00218 nx, cpl_image_get_size_x(arcframe));
00219
00220 assure( MINLINES <= MAXLINES, CPL_ERROR_ILLEGAL_INPUT,
00221 "minlines=%d maxlines=%d", MINLINES, MAXLINES );
00222
00223
00224 check(( linetable = cpl_table_new(MAXLINES),
00225 cpl_table_new_column(linetable, "X" , CPL_TYPE_DOUBLE),
00226 cpl_table_new_column(linetable, "dX" , CPL_TYPE_DOUBLE),
00227 cpl_table_new_column(linetable, "Xwidth", CPL_TYPE_DOUBLE),
00228 cpl_table_new_column(linetable, "Y" , CPL_TYPE_INT),
00229 cpl_table_new_column(linetable, "Peak" , CPL_TYPE_DOUBLE),
00230 cpl_table_new_column(linetable, "Background" , CPL_TYPE_DOUBLE),
00231 cpl_table_new_column(linetable, "Slope" , CPL_TYPE_DOUBLE)),
00232 "Could not create line table");
00233
00234 uves_msg("Searching for emission lines");
00235
00236 threshold_low = 0.0;
00237
00238
00239 if (flat_fielded) {
00240 threshold_high = 10.0;
00241 }
00242 else {
00243 threshold_high = cpl_image_get_mean(spectrum);
00244
00245 assure( threshold_high > 0, CPL_ERROR_ILLEGAL_INPUT,
00246 "Spectrum median flux is %e. Must be positive",
00247 cpl_image_get_median(spectrum));
00248 }
00249
00250 max_thresh_found = false;
00251
00252
00253
00254 lines_detected = 0;
00255 while( (lines_detected < MINLINES || MAXLINES < lines_detected) &&
00256 fabs(threshold_low - threshold_high) > DBL_EPSILON )
00257 {
00258 threshold = (threshold_low + threshold_high)/2.0;
00259
00260 check( detect_lines(spectrum, noise, spectrum_header,
00261 flat_fielded,
00262 RANGE, threshold, CENTERING_METHOD,
00263 bin_disp,
00264 order_locations,
00265 NULL,
00266 linetable,
00267 &lines_detected,
00268 &lines_in_table),
00269 "Could not search for emission lines");
00270
00271
00272
00273
00274 if (lines_detected < MINLINES)
00275 {
00276 max_thresh_found = true;
00277 threshold_high = threshold;
00278 }
00279 else if (MAXLINES < lines_detected)
00280 {
00281 if (!max_thresh_found)
00282 {
00283 threshold_high *= 2;
00284 }
00285 else
00286 {
00287 threshold_low = threshold;
00288 }
00289 }
00290 }
00291
00292 assure( MINLINES <= lines_detected && lines_detected <= MAXLINES,
00293 CPL_ERROR_CONTINUE,
00294 "Could not detect between %d and %d lines. Try to increase search range",
00295 MINLINES, MAXLINES);
00296
00297
00298 check( detect_lines(spectrum, noise, spectrum_header,
00299 flat_fielded,
00300 RANGE, threshold, CENTERING_METHOD,
00301 bin_disp,
00302 order_locations,
00303 arcframe,
00304 linetable,
00305 &lines_detected,
00306 &lines_in_table),
00307 "Could not search for emission lines");
00308
00309
00310 check( cpl_table_set_size(linetable, lines_in_table),
00311 "Could not resize line table");
00312
00313 uves_sort_table_1(linetable, "X", false);
00314
00315 cleanup:
00316 #if 0
00317 uves_free_image(&temp);
00318 #endif
00319 if (cpl_error_get_code() != CPL_ERROR_NONE)
00320 {
00321 uves_free_table(&linetable);
00322 }
00323 else
00324 {
00325
00326 passure( cpl_table_get_ncol(linetable) == 7, "%d",
00327 cpl_table_get_ncol(linetable));
00328 passure( cpl_table_has_column(linetable, "X" ), " ");
00329 passure( cpl_table_has_column(linetable, "dX" ), " ");
00330 passure( cpl_table_has_column(linetable, "Xwidth"), " ");
00331 passure( cpl_table_has_column(linetable, "Y" ), " ");
00332 passure( cpl_table_has_column(linetable, "Peak" ), " ");
00333 passure( cpl_table_has_column(linetable, "Background" ), " ");
00334 passure( cpl_table_has_column(linetable, "Slope" ), " ");
00335
00336 }
00337 return linetable;
00338 }
00339
00340
00391
00392 static cpl_error_code
00393 detect_lines(const cpl_image *spectrum, const cpl_image *noise,
00394 const uves_propertylist *spectrum_header,
00395 bool flat_fielded,
00396 int RANGE, double THRESHOLD, centering_method CENTERING_METHOD,
00397 int bin_disp,
00398 const polynomial *order_locations, cpl_image *arcframe,
00399 cpl_table *linetable,
00400 int *ndetected, int *nrows)
00401 {
00402 int norders;
00403 int minorder;
00404 int MAXLINES;
00405
00406 int nx;
00407 int x, order;
00408
00409 const double *spectrum_data;
00410 const double *noise_data;
00411
00412
00413 passure( spectrum != NULL, " ");
00414 passure( noise != NULL, " ");
00415 passure( spectrum_header != NULL, " ");
00416 nx = cpl_image_get_size_x(spectrum);
00417 norders = cpl_image_get_size_y(spectrum);
00418
00419
00420
00421 assure( cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE,
00422 CPL_ERROR_UNSUPPORTED_MODE,
00423 "Image type must be double. It is %s",
00424 uves_tostring_cpl_type(cpl_image_get_type(spectrum)));
00425
00426 spectrum_data = cpl_image_get_data_double_const(spectrum);
00427 noise_data = cpl_image_get_data_double_const(noise);
00428
00429 passure( RANGE > 0, "%d", RANGE);
00430
00431 if (arcframe != NULL)
00432 {
00433 passure( order_locations != NULL, " ");
00434 passure( nx == cpl_image_get_size_x(arcframe),
00435 "%d %d", nx, cpl_image_get_size_x(arcframe));
00436 }
00437
00438 passure( linetable != NULL, " ");
00439 MAXLINES = cpl_table_get_nrow(linetable);
00440 passure( cpl_table_get_ncol(linetable) == 7, "%d",
00441 cpl_table_get_ncol(linetable));
00442 passure( cpl_table_has_column(linetable, "X" ), " ");
00443 passure( cpl_table_has_column(linetable, "dX" ), " ");
00444 passure( cpl_table_has_column(linetable, "Xwidth"), " ");
00445 passure( cpl_table_has_column(linetable, "Y" ), " ");
00446 passure( cpl_table_has_column(linetable, "Peak" ), " ");
00447 passure( cpl_table_has_column(linetable, "Background" ), " ");
00448 passure( cpl_table_has_column(linetable, "Slope" ), " ");
00449
00450 assure( THRESHOLD > 0, CPL_ERROR_ILLEGAL_INPUT, "Illegal threshold: %e",
00451 THRESHOLD);
00452
00453 check( minorder = uves_pfits_get_crval2(spectrum_header),
00454 "Error reading order number of first row");
00455
00456 *ndetected = 0;
00457 *nrows = 0;
00458
00459
00460 for (order = minorder; order < minorder + norders; order++) {
00461 int spectrum_row = order - minorder + 1;
00462 int ndetected_order = 0;
00463 for (x = 1; x <= nx; x++) {
00464 double flux, dflux;
00465 int peak_width = 0;
00466 int xlo, xhi;
00467 double local_median;
00468
00469
00470
00471 flux = spectrum_data[(x-1) + (spectrum_row - 1) * nx];
00472 dflux = noise_data [(x-1) + (spectrum_row - 1) * nx];
00473
00474 xlo = uves_max_int(x - RANGE, 1);
00475 xhi = uves_min_int(x + RANGE, nx);
00476
00477 local_median = cpl_image_get_median_window(
00478 spectrum,
00479 uves_max_int(xlo, 1 ), spectrum_row,
00480 uves_min_int(xhi, nx), spectrum_row);
00481
00482 while(x <= nx &&
00483 (
00484 (!flat_fielded && flux - local_median > THRESHOLD)
00485 ||
00486 (flat_fielded && (flux - local_median) > THRESHOLD * dflux)
00487 )
00488 ) {
00489 #if WANT_BIG_LOGFILE
00490 uves_msg_debug("threshold = %f\tx = %d\tflux = %f\tmedian = %f",
00491 THRESHOLD, x, flux, local_median);
00492 #endif
00493
00494 x += 1;
00495 peak_width += 1;
00496
00497 if (x <= nx) {
00498
00499
00500
00501
00502 flux = spectrum_data[(x-1) + (spectrum_row - 1) * nx];
00503 xlo = uves_max_int(x - RANGE, 1);
00504 xhi = uves_min_int(x + RANGE, nx);
00505 local_median = cpl_image_get_median_window(
00506 spectrum,
00507 uves_max_int(xlo, 1 ), spectrum_row,
00508 uves_min_int(xhi, nx), spectrum_row);
00509 }
00510 }
00511
00512
00513 if (peak_width > 0) {
00514 double x_peak, dx = 0, sigma, slope, back;
00515 check( x_peak = xcenter(spectrum, noise,
00516 uves_max_int(1, x - peak_width),
00517
00518 uves_max_int(1, x - 1),
00519
00520 spectrum_row,
00521 CENTERING_METHOD,
00522 bin_disp,
00523 &sigma,
00524 &flux,
00525 &dx,
00526 &slope,
00527 &back),
00528 "Could not locate peak center");
00529
00530 #if WANT_BIG_LOGFILE
00531 uves_msg_debug("(Order, x, flux) = (%d, %f, %f)",
00532 order, x_peak, flux);
00533 #endif
00534
00535
00536 if (*nrows < MAXLINES) {
00537 check(( cpl_table_set_int (linetable, "Y" , *nrows, order),
00538 cpl_table_set_double(linetable, "X" , *nrows, x_peak),
00539 cpl_table_set_double(linetable, "dX" , *nrows, dx),
00540 cpl_table_set_double(linetable, "Xwidth", *nrows, sigma),
00541 cpl_table_set_double(linetable, "Peak" , *nrows, flux),
00542 cpl_table_set_double(linetable, "Background" , *nrows, back),
00543 cpl_table_set_double(linetable, "Slope" , *nrows, slope)),
00544 "Could not update line table row %d", *nrows);
00545 (*nrows)++;
00546 }
00547
00548 ndetected_order++;
00549 (*ndetected)++;
00550
00551 if (arcframe != NULL) {
00552 int x1;
00553 int pen = 0;
00554 int ny = cpl_image_get_size_y(arcframe);
00555
00556
00557 for (x1 = uves_max_int(
00558 1 , uves_round_double(
00559 x_peak - peak_width - 0*RANGE/2.0));
00560 x1 <= uves_min_int(
00561 nx, uves_round_double(
00562 x_peak + peak_width + 0*RANGE/2.0));
00563 x1++) {
00564 check( cpl_image_set(
00565 arcframe,
00566 x1,
00567 uves_min_int(
00568 ny,
00569 uves_max_int(
00570 1,
00571 (int) uves_polynomial_evaluate_2d(
00572 order_locations, x1, order)
00573 )),
00574 pen),
00575 "Error writing input image");
00576 check( cpl_image_set(
00577 arcframe,
00578 uves_min_int(
00579 nx,
00580 uves_max_int((int) x_peak, 1)),
00581 uves_min_int(
00582 ny,
00583 uves_max_int(
00584 1,
00585 (int) uves_polynomial_evaluate_2d(
00586 order_locations, x1, order)
00587 - 10)),
00588 pen),
00589 "Error writing input image");
00590 }
00591 }
00592 }
00593 }
00594 if (arcframe != NULL) uves_msg_debug("Order #%d: %d lines detected",
00595 order, ndetected_order);
00596 }
00597
00598
00599 {
00600 int i;
00601 int doublets_removed = 0;
00602 for (i = 0; i+1 < *nrows; i++) {
00603 if (fabs(cpl_table_get_double(linetable, "X", i , NULL) -
00604 cpl_table_get_double(linetable, "X", i+1, NULL)) < 2.0)
00605 {
00606
00607
00608
00609
00610 check( cpl_table_erase_window(linetable, i, 2),
00611 "Error removing rows");
00612 *nrows -= 2;
00613 *ndetected -= 2;
00614
00615 check( cpl_table_set_size(linetable,
00616 cpl_table_get_nrow(linetable) + 2),
00617 "Could not resize line table");
00618
00619 doublets_removed++;
00620 }
00621 }
00622 if (doublets_removed > 0)
00623 {
00624 uves_msg_debug("%d doublet%s removed",
00625 doublets_removed, doublets_removed > 1 ? "s" : "");
00626 }
00627 }
00628
00629 uves_msg("Range = %d pixels; threshold = %.2f %s; %d lines detected",
00630 RANGE, THRESHOLD, flat_fielded ? "stdev" : "ADU", *ndetected);
00631
00632 cleanup:
00633 return cpl_error_get_code();
00634 }
00635
00636
00661
00662 static double
00663 xcenter(const cpl_image *image, const cpl_image *noise, int xlo, int xhi, int row,
00664 centering_method CENTERING_METHOD, int bin_disp,
00665 double *sigma, double *intensity, double *dx0, double *slope, double *background)
00666 {
00667 double x0;
00668 cpl_matrix *covariance = NULL;
00669 const double *image_data;
00670 bool converged;
00671 int lo_r, hi_r;
00672
00673 int nx = cpl_image_get_size_x(image);
00674
00675 passure(cpl_image_get_type(image) == CPL_TYPE_DOUBLE, " ");
00676
00677 image_data = cpl_image_get_data_double_const(image);
00678
00679
00680
00681 lo_r = 6;
00682 hi_r = 8;
00683 if (bin_disp >= 2)
00684 {
00685 lo_r = 4;
00686 hi_r = 5;
00687 }
00688
00689 {
00690 int xm = (xlo+xhi)/2;
00691
00692 xlo = uves_max_int(1, xm - lo_r);
00693 xhi = uves_min_int(nx, xm + lo_r);
00694 }
00695
00696
00697 do {
00698 converged = true;
00699 if (1 < xlo && 0 <
00700
00701
00702
00703 image_data[(xlo-1-1) + (row - 1) * nx] &&
00704 image_data[(xlo-1-1) + (row - 1) * nx] <
00705 image_data[(xlo -1) + (row - 1) * nx] )
00706 {
00707 converged = false;
00708 xlo -= 1;
00709 }
00710
00711 if (xhi < nx && 0 <
00712
00713
00714
00715 image_data[(xhi+1-1) + (row - 1) * nx] &&
00716 image_data[(xhi+1-1) + (row - 1) * nx] <
00717 image_data[(xhi -1) + (row - 1) * nx] )
00718 {
00719 converged = false;
00720 xhi += 1;
00721 }
00722
00723 if ((xhi-xlo+1) >= hi_r)
00724 {
00725 converged = true;
00726 }
00727
00728 } while (!converged);
00729
00730
00731 if (CENTERING_METHOD == CENTERING_GAUSSIAN)
00732 {
00733 #if WEIGHTED_FIT
00734 uves_fit_1d_image(image, noise, NULL,
00735 #else
00736 uves_fit_1d_image(image, NULL, NULL,
00737 #endif
00738 true, false, false,
00739 xlo, xhi, row,
00740 &x0, sigma, intensity, background, slope,
00741 #if WEIGHTED_FIT
00742 NULL, NULL, &covariance,
00743 #else
00744 NULL, NULL, NULL,
00745 #endif
00746
00747 #if FIT_SLOPE
00748 uves_gauss_linear, uves_gauss_linear_derivative, 5);
00749 #else
00750 uves_gauss, uves_gauss_derivative, 4);
00751 *slope = 0;
00752 #endif
00753
00754
00755
00756
00757 if (cpl_error_get_code() == CPL_ERROR_NONE)
00758 {
00759
00760 #if WEIGHTED_FIT
00761 *dx0 = sqrt(cpl_matrix_get(covariance, 0, 0));
00762 #else
00763 *dx0 = *sigma / sqrt(*intensity);
00764 #endif
00765
00766 #if WANT_BIG_LOGFILE
00767 uves_msg_debug("Gaussian fit succeeded at (x, row, N) = (%f, %d, %d)",
00768 x0, row, xhi-xlo+1);
00769 #endif
00770 }
00771 else if (cpl_error_get_code() == CPL_ERROR_CONTINUE)
00772 {
00773
00774 uves_error_reset();
00775 #if WANT_BIG_LOGFILE
00776 uves_msg_debug("Gaussian fit failed at (x, row, N) ="
00777 " (%f, %d, %d), using centroid",
00778 x0, row, xhi-xlo+1);
00779 #endif
00780 *dx0 = *sigma / sqrt(*intensity);
00781 }
00782 else if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
00783 {
00784 uves_error_reset();
00785
00786
00787 uves_msg_debug("Covariance matrix computation failed");
00788 *dx0 = *sigma / sqrt(*intensity);
00789 }
00790
00791 assure(cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
00792 "Gaussian fitting failed");
00793
00794 #if WANT_BIG_LOGFILE
00795 uves_msg_debug("Fit = (x0=%f, sigma=%f, norm=%f, backg=%f, N=%d)",
00796 x0,
00797 *sigma,
00798 *intensity,
00799 background,
00800 xhi - xlo + 1);
00801 #endif
00802
00803
00804
00805
00806
00807
00808
00809 *intensity = *background + (*intensity)/(sqrt(2*M_PI) * (*sigma));
00810
00811 }
00812 else
00813 {
00814 assure (false, CPL_ERROR_UNSUPPORTED_MODE,
00815 "Centering method (no. %d) is unsupported",
00816 CENTERING_METHOD);
00817 }
00818
00819 cleanup:
00820 uves_free_matrix(&covariance);
00821 return x0;
00822 }
00823