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