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");
251 uves_msg(
"Searching for emission lines");
257 threshold_high = 10.0;
260 threshold_high = cpl_image_get_mean(spectrum);
262 assure( threshold_high > 0, CPL_ERROR_ILLEGAL_INPUT,
263 "Spectrum median flux is %e. Must be positive",
264 cpl_image_get_median(spectrum));
267 max_thresh_found =
false;
277 while( (lines_detected < MINLINES || MAXLINES < lines_detected) &&
278 fabs(threshold_low - threshold_high) > DBL_EPSILON )
281 threshold = (threshold_low + threshold_high)/2.0;
285 RANGE, threshold, CENTERING_METHOD,
292 "Could not search for emission lines");
297 if (lines_detected < MINLINES)
299 max_thresh_found =
true;
300 threshold_high = threshold;
302 else if (MAXLINES < lines_detected)
304 if (!max_thresh_found)
310 threshold_low = threshold;
313 sprintf(qc_key,
"QC TRACE%d WIN%d NLINDET%d",trace,window,kk);
314 uves_msg_debug(
"ThAr lamp on trace %d window %d detected lines %d",
315 trace,window,lines_detected);
317 "ThAr lamp detected lines",
"%d"));
324 sprintf(qc_key,
"QC TRACE%d WIN%d NLINDET NITERS",trace,window);
326 assure( MINLINES <= lines_detected && lines_detected <= MAXLINES,
328 "Could not detect between %d and %d lines. Try to increase search range",
334 RANGE, threshold, CENTERING_METHOD,
341 "Could not search for emission lines");
344 check( cpl_table_set_size(linetable, lines_in_table),
345 "Could not resize line table");
347 uves_sort_table_1(linetable,
"X",
false);
351 uves_free_image(&temp);
353 if (cpl_error_get_code() != CPL_ERROR_NONE)
355 uves_free_table(&linetable);
360 passure( cpl_table_get_ncol(linetable) == 7,
"%" CPL_SIZE_FORMAT
"",
361 cpl_table_get_ncol(linetable));
362 passure( cpl_table_has_column(linetable,
"X" ),
" ");
363 passure( cpl_table_has_column(linetable,
"dX" ),
" ");
364 passure( cpl_table_has_column(linetable,
"Xwidth"),
" ");
365 passure( cpl_table_has_column(linetable,
"Y" ),
" ");
366 passure( cpl_table_has_column(linetable,
"Peak" ),
" ");
367 passure( cpl_table_has_column(linetable,
"Background" ),
" ");
368 passure( cpl_table_has_column(linetable,
"Slope" ),
" ");
426 static cpl_error_code
427 detect_lines(
const cpl_image *spectrum,
const cpl_image *noise,
430 int RANGE,
double THRESHOLD, centering_method CENTERING_METHOD,
432 const polynomial *order_locations, cpl_image *arcframe,
433 cpl_table *linetable,
434 int *ndetected,
int *nrows)
443 const double *spectrum_data;
444 const double *noise_data;
447 passure( spectrum != NULL,
" ");
449 passure( spectrum_header != NULL,
" ");
450 nx = cpl_image_get_size_x(spectrum);
451 norders = cpl_image_get_size_y(spectrum);
455 assure( cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE,
456 CPL_ERROR_UNSUPPORTED_MODE,
457 "Image type must be double. It is %s",
460 spectrum_data = cpl_image_get_data_double_const(spectrum);
461 noise_data = cpl_image_get_data_double_const(noise);
463 passure( RANGE > 0,
"%d", RANGE);
465 if (arcframe != NULL)
467 passure( order_locations != NULL,
" ");
468 passure( nx == cpl_image_get_size_x(arcframe),
469 "%d %" CPL_SIZE_FORMAT
"", nx, cpl_image_get_size_x(arcframe));
472 passure( linetable != NULL,
" ");
473 MAXLINES = cpl_table_get_nrow(linetable);
474 passure( cpl_table_get_ncol(linetable) == 7,
"%" CPL_SIZE_FORMAT
"",
475 cpl_table_get_ncol(linetable));
476 passure( cpl_table_has_column(linetable,
"X" ),
" ");
477 passure( cpl_table_has_column(linetable,
"dX" ),
" ");
478 passure( cpl_table_has_column(linetable,
"Xwidth"),
" ");
479 passure( cpl_table_has_column(linetable,
"Y" ),
" ");
480 passure( cpl_table_has_column(linetable,
"Peak" ),
" ");
481 passure( cpl_table_has_column(linetable,
"Background" ),
" ");
482 passure( cpl_table_has_column(linetable,
"Slope" ),
" ");
484 assure( THRESHOLD > 0, CPL_ERROR_ILLEGAL_INPUT,
"Illegal threshold: %e",
488 "Error reading order number of first row");
494 for (order = minorder; order < minorder + norders; order++) {
495 int spectrum_row = order - minorder + 1;
496 int ndetected_order = 0;
497 for (x = 1; x <= nx; x++) {
505 flux = spectrum_data[(x-1) + (spectrum_row - 1) * nx];
506 dflux = noise_data [(x-1) + (spectrum_row - 1) * nx];
508 xlo = uves_max_int(x - RANGE, 1);
509 xhi = uves_min_int(x + RANGE, nx);
511 local_median = cpl_image_get_median_window(
513 uves_max_int(xlo, 1 ), spectrum_row,
514 uves_min_int(xhi, nx), spectrum_row);
518 (!flat_fielded && flux - local_median > THRESHOLD)
520 (flat_fielded && (flux - local_median) > THRESHOLD * dflux)
525 THRESHOLD, x, flux, local_median);
536 flux = spectrum_data[(x-1) + (spectrum_row - 1) * nx];
537 xlo = uves_max_int(x - RANGE, 1);
538 xhi = uves_min_int(x + RANGE, nx);
539 local_median = cpl_image_get_median_window(
541 uves_max_int(xlo, 1 ), spectrum_row,
542 uves_min_int(xhi, nx), spectrum_row);
547 if (peak_width > 0) {
548 double x_peak, dx = 0, sigma, slope, back;
550 uves_max_int(1, x - peak_width),
552 uves_max_int(1, x - 1),
562 "Could not locate peak center");
566 order, x_peak, flux);
570 if (*nrows < MAXLINES) {
571 check(( cpl_table_set_int (linetable,
"Y" , *nrows, order),
572 cpl_table_set_double(linetable,
"X" , *nrows, x_peak),
573 cpl_table_set_double(linetable,
"dX" , *nrows, dx),
574 cpl_table_set_double(linetable,
"Xwidth", *nrows, sigma),
575 cpl_table_set_double(linetable,
"Peak" , *nrows, flux),
576 cpl_table_set_double(linetable,
"Background" , *nrows, back),
577 cpl_table_set_double(linetable,
"Slope" , *nrows, slope)),
578 "Could not update line table row %d", *nrows);
585 if (arcframe != NULL) {
588 int ny = cpl_image_get_size_y(arcframe);
591 for (x1 = uves_max_int(
592 1 , uves_round_double(
593 x_peak - peak_width - 0*RANGE/2.0));
595 nx, uves_round_double(
596 x_peak + peak_width + 0*RANGE/2.0));
598 check( cpl_image_set(
606 order_locations, x1, order)
609 "Error writing input image");
610 check( cpl_image_set(
614 uves_max_int((
int) x_peak, 1)),
620 order_locations, x1, order)
623 "Error writing input image");
628 if (arcframe != NULL)
uves_msg_debug(
"Order #%d: %d lines detected",
629 order, ndetected_order);
635 int doublets_removed = 0;
636 for (i = 0; i+1 < *nrows; i++) {
637 if (fabs(cpl_table_get_double(linetable,
"X", i , NULL) -
638 cpl_table_get_double(linetable,
"X", i+1, NULL)) < 2.0)
644 check( cpl_table_erase_window(linetable, i, 2),
645 "Error removing rows");
649 check( cpl_table_set_size(linetable,
650 cpl_table_get_nrow(linetable) + 2),
651 "Could not resize line table");
656 if (doublets_removed > 0)
659 doublets_removed, doublets_removed > 1 ?
"s" :
"");
663 uves_msg(
"Range = %d pixels; threshold = %.2f %s; %d lines detected",
664 RANGE, THRESHOLD, flat_fielded ?
"stdev" :
"ADU", *ndetected);
667 return cpl_error_get_code();
697 xcenter(
const cpl_image *image,
const cpl_image *noise,
int xlo,
int xhi,
int row,
698 centering_method CENTERING_METHOD,
int bin_disp,
699 double *sigma,
double *intensity,
double *dx0,
double *slope,
double *background)
702 cpl_matrix *covariance = NULL;
703 const double *image_data;
707 int nx = cpl_image_get_size_x(image);
709 passure(cpl_image_get_type(image) == CPL_TYPE_DOUBLE,
" ");
711 image_data = cpl_image_get_data_double_const(image);
724 int xm = (xlo+xhi)/2;
726 xlo = uves_max_int(1, xm - lo_r);
727 xhi = uves_min_int(nx, xm + lo_r);
737 image_data[(xlo-1-1) + (row - 1) * nx] &&
738 image_data[(xlo-1-1) + (row - 1) * nx] <
739 image_data[(xlo -1) + (row - 1) * nx] )
749 image_data[(xhi+1-1) + (row - 1) * nx] &&
750 image_data[(xhi+1-1) + (row - 1) * nx] <
751 image_data[(xhi -1) + (row - 1) * nx] )
757 if ((xhi-xlo+1) >= hi_r)
762 }
while (!converged);
765 if (CENTERING_METHOD == CENTERING_GAUSSIAN)
768 uves_fit_1d_image(image, noise, NULL,
770 uves_fit_1d_image(image, NULL, NULL,
774 &x0, sigma, intensity, background, slope,
776 NULL, NULL, &covariance,
791 if (cpl_error_get_code() == CPL_ERROR_NONE)
795 *dx0 = sqrt(cpl_matrix_get(covariance, 0, 0));
797 *dx0 = *sigma / sqrt(*intensity);
801 uves_msg_debug(
"Gaussian fit succeeded at (x, row, N) = (%f, %d, %d)",
805 else if (cpl_error_get_code() == CPL_ERROR_CONTINUE)
811 " (%f, %d, %d), using centroid",
814 *dx0 = *sigma / sqrt(*intensity);
816 else if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
822 *dx0 = *sigma / sqrt(*intensity);
825 assure(cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
826 "Gaussian fitting failed");
829 uves_msg_debug(
"Fit = (x0=%f, sigma=%f, norm=%f, backg=%f, N=%d)",
843 *intensity = *background + (*intensity)/(sqrt(2*M_PI) * (*sigma));
848 assure (
false, CPL_ERROR_UNSUPPORTED_MODE,
849 "Centering method (no. %d) is unsupported",
854 uves_free_matrix(&covariance);