136 #include <uves_wavecal_search.h>
137 #include <uves_utils.h>
138 #include <uves_utils_wrappers.h>
139 #include <uves_utils_cpl.h>
140 #include <uves_pfits.h>
141 #include <uves_dump.h>
142 #include <uves_error.h>
143 #include <uves_msg.h>
144 #include <uves_qclog.h>
150 #define WEIGHTED_FIT 1
154 xcenter(
const cpl_image *image,
const cpl_image *noise,
int xlo,
int xhi,
int row,
155 centering_method CENTERING_METHOD,
int bin_disp,
156 double *sigma,
double *intensity,
double *dx0,
double *slope,
double *background);
158 static cpl_error_code
159 detect_lines(
const cpl_image *spectrum,
const cpl_image *noise,
162 int RANGE,
double THRESHOLD, centering_method CENTERING_METHOD,
164 const polynomial *order_locations, cpl_image *arcframe,
165 cpl_table *linetable,
166 int *ndetected,
int *nrows);
203 const polynomial *order_locations, cpl_image *arcframe,
204 int RANGE,
int MINLINES,
int MAXLINES,
205 centering_method CENTERING_METHOD,
int bin_disp,
206 const int trace,
const int window, cpl_table* qclog)
208 cpl_table *linetable = NULL;
211 double threshold_low;
212 double threshold_high;
213 double threshold = 0;
216 bool max_thresh_found =
false;
219 passure( spectrum != NULL,
"Null input spectrum");
220 passure( order_locations != NULL,
"Null polynomial");
221 passure( arcframe != NULL,
"Null raw image");
224 assure( cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE,
225 CPL_ERROR_TYPE_MISMATCH,
226 "Spectrum image type is %s, must be double",
230 check(( nx = cpl_image_get_size_x(spectrum),
231 norders = cpl_image_get_size_y(spectrum)),
"Error reading input spectrum");
232 check( ny = cpl_image_get_size_y(arcframe),
"Error reading input image");
233 assure(nx == cpl_image_get_size_x(arcframe), CPL_ERROR_INCOMPATIBLE_INPUT,
234 "Spectrum and image widths are different (%d and %" CPL_SIZE_FORMAT
")",
235 nx, cpl_image_get_size_x(arcframe));
237 assure( MINLINES <= MAXLINES, CPL_ERROR_ILLEGAL_INPUT,
238 "minlines=%d maxlines=%d", MINLINES, MAXLINES );
241 check(( linetable = cpl_table_new(MAXLINES),
242 cpl_table_new_column(linetable,
"X" , CPL_TYPE_DOUBLE),
243 cpl_table_new_column(linetable,
"dX" , CPL_TYPE_DOUBLE),
244 cpl_table_new_column(linetable,
"Xwidth", CPL_TYPE_DOUBLE),
245 cpl_table_new_column(linetable,
"Y" , CPL_TYPE_INT),
246 cpl_table_new_column(linetable,
"Peak" , CPL_TYPE_DOUBLE),
247 cpl_table_new_column(linetable,
"Background" , CPL_TYPE_DOUBLE),
248 cpl_table_new_column(linetable,
"Slope" , CPL_TYPE_DOUBLE)),
249 "Could not create line table");
250 cpl_table_set_column_unit(linetable,
"X",
"pix");
251 cpl_table_set_column_unit(linetable,
"dX",
"pix");
252 cpl_table_set_column_unit(linetable,
"Xwidth",
"pix");
253 cpl_table_set_column_unit(linetable,
"Y",
"pix");
254 cpl_table_set_column_unit(linetable,
"Peak",
"ADU");
255 cpl_table_set_column_unit(linetable,
"Background",
"ADU");
256 cpl_table_set_column_unit(linetable,
"Slope",
" ");
257 uves_msg(
"Searching for emission lines");
263 threshold_high = 10.0;
266 threshold_high = cpl_image_get_mean(spectrum);
268 assure( threshold_high > 0, CPL_ERROR_ILLEGAL_INPUT,
269 "Spectrum median flux is %e. Must be positive",
270 cpl_image_get_median(spectrum));
273 max_thresh_found =
false;
283 while( (lines_detected < MINLINES || MAXLINES < lines_detected) &&
284 fabs(threshold_low - threshold_high) > DBL_EPSILON )
287 threshold = (threshold_low + threshold_high)/2.0;
291 RANGE, threshold, CENTERING_METHOD,
298 "Could not search for emission lines");
303 if (lines_detected < MINLINES)
305 max_thresh_found =
true;
306 threshold_high = threshold;
308 else if (MAXLINES < lines_detected)
310 if (!max_thresh_found)
316 threshold_low = threshold;
319 sprintf(qc_key,
"QC TRACE%d WIN%d NLINDET%d",trace,window,kk);
320 uves_msg_debug(
"ThAr lamp on trace %d window %d detected lines %d",
321 trace,window,lines_detected);
323 "ThAr lamp detected lines",
"%d"));
330 sprintf(qc_key,
"QC TRACE%d WIN%d NLINDET NITERS",trace,window);
332 assure( MINLINES <= lines_detected && lines_detected <= MAXLINES,
334 "Could not detect between %d and %d lines. Try to increase search range",
340 RANGE, threshold, CENTERING_METHOD,
347 "Could not search for emission lines");
350 check( cpl_table_set_size(linetable, lines_in_table),
351 "Could not resize line table");
353 uves_sort_table_1(linetable,
"X",
false);
357 uves_free_image(&temp);
359 if (cpl_error_get_code() != CPL_ERROR_NONE)
361 uves_free_table(&linetable);
366 passure( cpl_table_get_ncol(linetable) == 7,
"%" CPL_SIZE_FORMAT
"",
367 cpl_table_get_ncol(linetable));
368 passure( cpl_table_has_column(linetable,
"X" ),
" ");
369 passure( cpl_table_has_column(linetable,
"dX" ),
" ");
370 passure( cpl_table_has_column(linetable,
"Xwidth"),
" ");
371 passure( cpl_table_has_column(linetable,
"Y" ),
" ");
372 passure( cpl_table_has_column(linetable,
"Peak" ),
" ");
373 passure( cpl_table_has_column(linetable,
"Background" ),
" ");
374 passure( cpl_table_has_column(linetable,
"Slope" ),
" ");
432 static cpl_error_code
436 int RANGE,
double THRESHOLD, centering_method CENTERING_METHOD,
438 const polynomial *order_locations, cpl_image *arcframe,
439 cpl_table *linetable,
440 int *ndetected,
int *nrows)
449 const double *spectrum_data;
450 const double *noise_data;
453 passure( spectrum != NULL,
" ");
455 passure( spectrum_header != NULL,
" ");
456 nx = cpl_image_get_size_x(spectrum);
457 norders = cpl_image_get_size_y(spectrum);
461 assure( cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE,
462 CPL_ERROR_UNSUPPORTED_MODE,
463 "Image type must be double. It is %s",
466 spectrum_data = cpl_image_get_data_double_const(spectrum);
467 noise_data = cpl_image_get_data_double_const(noise);
469 passure( RANGE > 0,
"%d", RANGE);
471 if (arcframe != NULL)
473 passure( order_locations != NULL,
" ");
474 passure( nx == cpl_image_get_size_x(arcframe),
475 "%d %" CPL_SIZE_FORMAT
"", nx, cpl_image_get_size_x(arcframe));
478 passure( linetable != NULL,
" ");
479 MAXLINES = cpl_table_get_nrow(linetable);
480 passure( cpl_table_get_ncol(linetable) == 7,
"%" CPL_SIZE_FORMAT
"",
481 cpl_table_get_ncol(linetable));
482 passure( cpl_table_has_column(linetable,
"X" ),
" ");
483 passure( cpl_table_has_column(linetable,
"dX" ),
" ");
484 passure( cpl_table_has_column(linetable,
"Xwidth"),
" ");
485 passure( cpl_table_has_column(linetable,
"Y" ),
" ");
486 passure( cpl_table_has_column(linetable,
"Peak" ),
" ");
487 passure( cpl_table_has_column(linetable,
"Background" ),
" ");
488 passure( cpl_table_has_column(linetable,
"Slope" ),
" ");
490 assure( THRESHOLD > 0, CPL_ERROR_ILLEGAL_INPUT,
"Illegal threshold: %e",
494 "Error reading order number of first row");
500 for (order = minorder; order < minorder + norders; order++) {
501 int spectrum_row = order - minorder + 1;
502 int ndetected_order = 0;
503 for (x = 1; x <= nx; x++) {
511 flux = spectrum_data[(x-1) + (spectrum_row - 1) * nx];
512 dflux = noise_data [(x-1) + (spectrum_row - 1) * nx];
514 xlo = uves_max_int(x - RANGE, 1);
515 xhi = uves_min_int(x + RANGE, nx);
517 local_median = cpl_image_get_median_window(
519 uves_max_int(xlo, 1 ), spectrum_row,
520 uves_min_int(xhi, nx), spectrum_row);
524 (!flat_fielded && flux - local_median > THRESHOLD)
526 (flat_fielded && (flux - local_median) > THRESHOLD * dflux)
531 THRESHOLD, x, flux, local_median);
542 flux = spectrum_data[(x-1) + (spectrum_row - 1) * nx];
543 xlo = uves_max_int(x - RANGE, 1);
544 xhi = uves_min_int(x + RANGE, nx);
545 local_median = cpl_image_get_median_window(
547 uves_max_int(xlo, 1 ), spectrum_row,
548 uves_min_int(xhi, nx), spectrum_row);
553 if (peak_width > 0) {
554 double x_peak, dx = 0, sigma, slope, back;
556 uves_max_int(1, x - peak_width),
558 uves_max_int(1, x - 1),
568 "Could not locate peak center");
572 order, x_peak, flux);
576 if (*nrows < MAXLINES) {
577 check(( cpl_table_set_int (linetable,
"Y" , *nrows, order),
578 cpl_table_set_double(linetable,
"X" , *nrows, x_peak),
579 cpl_table_set_double(linetable,
"dX" , *nrows, dx),
580 cpl_table_set_double(linetable,
"Xwidth", *nrows, sigma),
581 cpl_table_set_double(linetable,
"Peak" , *nrows, flux),
582 cpl_table_set_double(linetable,
"Background" , *nrows, back),
583 cpl_table_set_double(linetable,
"Slope" , *nrows, slope)),
584 "Could not update line table row %d", *nrows);
591 if (arcframe != NULL) {
594 int ny = cpl_image_get_size_y(arcframe);
597 for (x1 = uves_max_int(
598 1 , uves_round_double(
599 x_peak - peak_width - 0*RANGE/2.0));
601 nx, uves_round_double(
602 x_peak + peak_width + 0*RANGE/2.0));
604 check( cpl_image_set(
612 order_locations, x1, order)
615 "Error writing input image");
616 check( cpl_image_set(
620 uves_max_int((
int) x_peak, 1)),
626 order_locations, x1, order)
629 "Error writing input image");
634 if (arcframe != NULL)
uves_msg_debug(
"Order #%d: %d lines detected",
635 order, ndetected_order);
641 int doublets_removed = 0;
642 for (i = 0; i+1 < *nrows; i++) {
643 if (fabs(cpl_table_get_double(linetable,
"X", i , NULL) -
644 cpl_table_get_double(linetable,
"X", i+1, NULL)) < 2.0)
650 check( cpl_table_erase_window(linetable, i, 2),
651 "Error removing rows");
655 check( cpl_table_set_size(linetable,
656 cpl_table_get_nrow(linetable) + 2),
657 "Could not resize line table");
662 if (doublets_removed > 0)
665 doublets_removed, doublets_removed > 1 ?
"s" :
"");
669 uves_msg(
"Range = %d pixels; threshold = %.2f %s; %d lines detected",
670 RANGE, THRESHOLD, flat_fielded ?
"stdev" :
"ADU", *ndetected);
673 return cpl_error_get_code();
703 xcenter(
const cpl_image *image,
const cpl_image *noise,
int xlo,
int xhi,
int row,
704 centering_method CENTERING_METHOD,
int bin_disp,
705 double *sigma,
double *intensity,
double *dx0,
double *slope,
double *background)
708 cpl_matrix *covariance = NULL;
709 const double *image_data;
713 int nx = cpl_image_get_size_x(image);
715 passure(cpl_image_get_type(image) == CPL_TYPE_DOUBLE,
" ");
717 image_data = cpl_image_get_data_double_const(image);
730 int xm = (xlo+xhi)/2;
732 xlo = uves_max_int(1, xm - lo_r);
733 xhi = uves_min_int(nx, xm + lo_r);
743 image_data[(xlo-1-1) + (row - 1) * nx] &&
744 image_data[(xlo-1-1) + (row - 1) * nx] <
745 image_data[(xlo -1) + (row - 1) * nx] )
755 image_data[(xhi+1-1) + (row - 1) * nx] &&
756 image_data[(xhi+1-1) + (row - 1) * nx] <
757 image_data[(xhi -1) + (row - 1) * nx] )
763 if ((xhi-xlo+1) >= hi_r)
768 }
while (!converged);
771 if (CENTERING_METHOD == CENTERING_GAUSSIAN)
774 uves_fit_1d_image(image, noise, NULL,
776 uves_fit_1d_image(image, NULL, NULL,
780 &x0, sigma, intensity, background, slope,
782 NULL, NULL, &covariance,
797 if (cpl_error_get_code() == CPL_ERROR_NONE)
801 *dx0 = sqrt(cpl_matrix_get(covariance, 0, 0));
803 *dx0 = *sigma / sqrt(*intensity);
807 uves_msg_debug(
"Gaussian fit succeeded at (x, row, N) = (%f, %d, %d)",
811 else if (cpl_error_get_code() == CPL_ERROR_CONTINUE)
817 " (%f, %d, %d), using centroid",
820 *dx0 = *sigma / sqrt(*intensity);
822 else if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
828 *dx0 = *sigma / sqrt(*intensity);
831 assure(cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
832 "Gaussian fitting failed");
835 uves_msg_debug(
"Fit = (x0=%f, sigma=%f, norm=%f, backg=%f, N=%d)",
849 *intensity = *background + (*intensity)/(sqrt(2*M_PI) * (*sigma));
854 assure (
false, CPL_ERROR_UNSUPPORTED_MODE,
855 "Centering method (no. %d) is unsupported",
860 uves_free_matrix(&covariance);
int uves_gauss_linear(const double x[], const double a[], double *result)
Evaluate a gaussian with linear background.
#define passure(BOOL,...)
int uves_gauss_derivative(const double x[], const double a[], double result[])
Evaluate the derivatives of a gaussian.
int uves_qclog_add_int(cpl_table *table, const char *key_name, const int value, const char *key_help, const char *format)
Add integer key to QC-LOG table.
#define uves_msg(...)
Print a message on 'info' or 'debug' level.
int uves_gauss(const double x[], const double a[], double *result)
Evaluate a gaussian.
int uves_gauss_linear_derivative(const double x[], const double a[], double result[])
Evaluate the derivatives of a gaussian with linear background.
static double xcenter(const cpl_image *image, const cpl_image *noise, int xlo, int xhi, int row, centering_method CENTERING_METHOD, int bin_disp, double *sigma, double *intensity, double *dx0, double *slope, double *background)
Refine the center position of an initially detected emission line.
cpl_table * uves_wavecal_search(const cpl_image *spectrum, const cpl_image *noise, const uves_propertylist *spectrum_header, bool flat_fielded, const polynomial *order_locations, cpl_image *arcframe, int RANGE, int MINLINES, int MAXLINES, centering_method CENTERING_METHOD, int bin_disp, const int trace, const int window, cpl_table *qclog)
Search for a given number of emission lines.
double uves_polynomial_evaluate_2d(const polynomial *p, double x1, double x2)
Evaluate a 2d polynomial.
const char * uves_tostring_cpl_type(cpl_type t)
Convert a CPL type to a string.
#define uves_error_reset()
#define uves_msg_debug(...)
Print a debug message.
double uves_pfits_get_crval2(const uves_propertylist *plist)
Find out the crval2.
static cpl_error_code detect_lines(const cpl_image *spectrum, const cpl_image *noise, const uves_propertylist *spectrum_header, bool flat_fielded, int RANGE, double THRESHOLD, centering_method CENTERING_METHOD, int bin_disp, const polynomial *order_locations, cpl_image *arcframe, cpl_table *linetable, int *ndetected, int *nrows)
Find emission lines above a certain threshold.