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