98 #include <uves_cd_align_impl.h>
101 #include <uves_plot.h>
102 #include <uves_parameters.h>
103 #include <uves_dfs.h>
104 #include <uves_pfits.h>
105 #include <uves_qclog.h>
106 #include <uves_recipe.h>
107 #include <uves_utils_cpl.h>
108 #include <uves_utils_wrappers.h>
109 #include <uves_error.h>
110 #include <uves_msg.h>
119 uves_cal_cd_align_define_parameters(cpl_parameterlist *parameters);
124 #define cpl_plugin_get_info uves_cal_cd_align_get_info
126 UVES_CD_ALIGN_ID, UVES_CD_ALIGN_DOM, uves_cal_cd_align_define_parameters,
127 "Jonas M. Larsen",
"cpl@eso.org",
128 "Measures the reproducability of the cross disperser positioning",
129 "Given two input frames (CD_ALIGN_xxx where xxx = BLUE or RED) which contain only\n"
130 "one echelle order, this recipe measures the shift in the cross-dispersion \n"
131 "direction of that order. For RED input frames, only the lower chip is processed.\n"
133 "The recipe produces a CD_ALIGN_TABLE_xxxx (with xxxx = BLUE or REDL) with columns\n"
135 "YCENi: Centroid from Gaussian fit (for i = 1,2)\n"
136 "SIGMAi: Stdev from Gaussian fit\n"
137 "BACKi: Constant background from Gaussian fit\n"
138 "NORMi: Normalization constant from Gaussian fit\n"
139 "YDIFF: Difference YCEN2 - YCEN1 of centroid positions\n"
141 "and the QC-parameters ESO.QC.YDIFF(AVG|MED|RMS), which are the average,\n"
142 "median and root-mean-square of the y-shift, respectively.\n");
149 uves_cal_cd_align_define_parameters(cpl_parameterlist *parameters)
151 const char *subcontext = NULL;
152 const char *recipe_id = make_str(UVES_CD_ALIGN_ID);
157 if (uves_define_global_parameters(parameters) != CPL_ERROR_NONE)
163 uves_par_new_range(
"steps",
165 "Step size in pixels",
169 uves_par_new_range(
"xborder",
171 "Exclude a border region of this size (pixels)",
175 uves_par_new_range(
"window",
177 "The half window height used for Gaussian fitting",
180 return (cpl_error_get_code() != CPL_ERROR_NONE);
202 uves_cd_align_process(
const cpl_image *im1,
203 const cpl_image *im2,
212 cpl_table *result = NULL;
214 const cpl_image *images[2];
215 cpl_image *rows = NULL;
218 cpl_size num_fits, fit_succeeded;
222 nx = cpl_image_get_size_x(images[0]);
223 ny = cpl_image_get_size_y(images[0]);
225 if (debug_mode)
check( uves_save_image_local(
"CD alignment frame",
"cd_align1",
226 images[0], chip, -1, -1,
227 rotated_header1,
true),
228 "Error saving 1st CD aligment frame");
230 if (debug_mode)
check( uves_save_image_local(
"CD alignment frame",
"cd_align2",
231 images[1], chip, -1, -1,
232 rotated_header2,
true),
233 "Error saving 2nd CD aligment frame");
235 assure( cpl_image_get_size_x(images[0]) == cpl_image_get_size_x(images[1]) &&
236 cpl_image_get_size_y(images[0]) == cpl_image_get_size_y(images[1]),
237 CPL_ERROR_INCOMPATIBLE_INPUT,
238 "Images sizes: %" CPL_SIZE_FORMAT
"x%" CPL_SIZE_FORMAT
" and %" CPL_SIZE_FORMAT
"x%" CPL_SIZE_FORMAT
"",
239 cpl_image_get_size_x(images[0]),
240 cpl_image_get_size_y(images[0]),
241 cpl_image_get_size_x(images[1]),
242 cpl_image_get_size_y(images[1]) );
245 result = cpl_table_new(nx); row = 0;
246 cpl_table_new_column(result,
"X" , CPL_TYPE_INT);
247 cpl_table_new_column(result,
"YCEN1", CPL_TYPE_DOUBLE);
248 cpl_table_new_column(result,
"YCEN2", CPL_TYPE_DOUBLE);
249 cpl_table_new_column(result,
"SIGMA1", CPL_TYPE_DOUBLE);
250 cpl_table_new_column(result,
"SIGMA2", CPL_TYPE_DOUBLE);
251 cpl_table_new_column(result,
"BACK1", CPL_TYPE_DOUBLE);
252 cpl_table_new_column(result,
"BACK2", CPL_TYPE_DOUBLE);
253 cpl_table_new_column(result,
"NORM1", CPL_TYPE_DOUBLE);
254 cpl_table_new_column(result,
"NORM2", CPL_TYPE_DOUBLE);
256 cpl_table_set_column_unit(result,
"X",
"pix");
257 cpl_table_set_column_unit(result,
"YCEN1",
"pix");
258 cpl_table_set_column_unit(result,
"YCEN2",
"pix");
259 cpl_table_set_column_unit(result,
"SIGMA1",
"pix");
260 cpl_table_set_column_unit(result,
"SIGMA2",
"pix");
261 cpl_table_set_column_unit(result,
"BACK1",
"ADU");
262 cpl_table_set_column_unit(result,
"BACK2",
"ADU");
263 cpl_table_set_column_unit(result,
"NORM1",
"ADU");
264 cpl_table_set_column_unit(result,
"NORM2",
"ADU");
271 for (im = 0; im < 2; im++)
276 uves_free_image(&rows);
277 rows = cpl_image_collapse_create(images[im], direction);
279 cpl_image_get_maxpos(rows, &max_col, &(max_row[im]));
280 uves_msg(
"Row of max flux (%" CPL_SIZE_FORMAT
". image) = %" CPL_SIZE_FORMAT
"", (cpl_size)im+1, max_row[im]);
282 assure( max_col == 1, CPL_ERROR_ILLEGAL_OUTPUT,
283 "Something went wrong, max_col in collapsed image is = %" CPL_SIZE_FORMAT
"", max_col);
290 for (x = 1 + xborder; x <= nx - xborder; x += steps)
293 for (im = 0; im < 2; im++)
295 bool horizontal =
false;
296 bool fix_background =
false;
297 bool fit_background =
false;
298 int number_of_parameters = 4;
299 double y_0, sigma, norm, background;
300 int ylow = uves_max_int(1, uves_min_int(ny, max_row[im] - window));
301 int yhigh = uves_max_int(1, uves_min_int(ny, max_row[im] + window));
303 uves_fit_1d_image(images[im],
305 horizontal, fix_background, fit_background,
307 &y_0, &sigma, &norm, &background, NULL,
311 number_of_parameters);
314 if (cpl_error_get_code() == CPL_ERROR_CONTINUE)
318 uves_msg_warning(
"Fitting window (%" CPL_SIZE_FORMAT
", %" CPL_SIZE_FORMAT
") - (%" CPL_SIZE_FORMAT
", %" CPL_SIZE_FORMAT
") failed",
319 (cpl_size)x, (cpl_size)ylow,
320 (cpl_size)x, (cpl_size)yhigh);
326 assure( cpl_error_get_code() == CPL_ERROR_NONE,
327 cpl_error_get_code(),
328 "Gaussian fitting failed");
330 cpl_table_set_int (result,
"X" , row, x);
331 cpl_table_set_double(result, (im == 0) ?
"YCEN1" :
"YCEN2", row, y_0);
332 cpl_table_set_double(result, (im == 0) ?
"SIGMA1":
"SIGMA2", row, sigma);
333 cpl_table_set_double(result, (im == 0) ?
"BACK1" :
"BACK2", row, norm);
334 cpl_table_set_double(result, (im == 0) ?
"NORM1" :
"NORM2", row, background);
340 cpl_table_set_size(result, row);
342 uves_msg_low(
"Was able to fit %" CPL_SIZE_FORMAT
" of %" CPL_SIZE_FORMAT
" columns", fit_succeeded, num_fits);
344 check(( cpl_table_duplicate_column(result,
"YDIFF", result,
"YCEN2"),
345 cpl_table_subtract_columns(result,
"YDIFF",
"YCEN1")),
346 "Error calculating residuals of fit");
347 cpl_table_set_column_unit(result,
"YDIFF",
"pix");
349 cpl_size num_valid = cpl_table_get_nrow(result) - cpl_table_count_invalid(result,
"YDIFF");
351 assure( num_valid >= 1, CPL_ERROR_ILLEGAL_OUTPUT,
352 "Only %" CPL_SIZE_FORMAT
" valid YDIFF value(s), 1 or more needed",
358 uves_free_image(&rows);
374 cd_align_qclog(
const cpl_table *cdalign,
378 cpl_table *qclog = NULL;
379 double mean, sigma, median;
382 "Error during QC initialization");
384 mean = cpl_table_get_column_mean (cdalign,
"YDIFF");
385 sigma = cpl_table_get_column_stdev (cdalign,
"YDIFF");
386 median = cpl_table_get_column_median(cdalign,
"YDIFF");
390 "Test-of-CD-Alignment",
397 "Average Y difference",
403 "Median Y difference",
413 uves_msg(
"Average shift = %.4f +- %.4f pixels",
431 avg_flux(
const cpl_image *im)
434 cpl_image *median_filt = NULL;
435 bool extrapolate_border =
true;
450 median_filt = cpl_image_duplicate(im);
457 cpl_image_get_mean (median_filt) -
458 cpl_image_get_median(median_filt);
461 uves_free_image(&median_filt);
475 uves_cal_cd_align_exe(cpl_frameset *frames,
const cpl_parameterlist *parameters,
476 const char *starttime)
479 cpl_image *raw_images[2][2] = {{NULL, NULL}, {NULL, NULL}};
494 cpl_table* qclog[2] = {NULL, NULL};
499 cpl_table *cd_align = NULL;
502 int steps, xborder, window;
506 const char *product_filename = NULL;
509 const char *raw_filename[2];
512 const char* PROCESS_CHIP=NULL;
514 check( uves_get_parameter(parameters, NULL,
"uves",
"debug",
515 CPL_TYPE_BOOL, &debug_mode),
"Could not read parameter");
517 check( uves_get_parameter(parameters, NULL,
"uves",
"process_chip", CPL_TYPE_STRING, &PROCESS_CHIP),
518 "Could not read parameter");
521 check( uves_get_parameter(parameters, NULL, make_str(UVES_CD_ALIGN_ID),
"steps",
522 CPL_TYPE_INT , &steps),
"Could not read parameter");
523 check( uves_get_parameter(parameters, NULL, make_str(UVES_CD_ALIGN_ID),
"xborder",
524 CPL_TYPE_INT , &xborder),
"Could not read parameter");
525 check( uves_get_parameter(parameters, NULL, make_str(UVES_CD_ALIGN_ID),
"window",
526 CPL_TYPE_INT , &window),
"Could not read parameter");
529 check( uves_load_cd_align(frames,
539 "Error loading raw frame");
541 uves_msg(
"Using %s", raw_filename[0]);
542 uves_msg(
"Using %s", raw_filename[1]);
547 chip = UVES_CHIP_BLUE;
556 uves_msg(
"1. REDL average flux per pixel = %f ADU", avg_flux(raw_images[0][raw_index_l]));
557 uves_msg(
"2. REDL average flux per pixel = %f ADU", avg_flux(raw_images[1][raw_index_l]));
559 uves_msg(
"1. REDU average flux per pixel = %f ADU", avg_flux(raw_images[0][raw_index_u]));
560 uves_msg(
"2. REDU average flux per pixel = %f ADU", avg_flux(raw_images[1][raw_index_u]));
563 chip = UVES_CHIP_REDL;
571 check( cd_align = uves_cd_align_process(raw_images[0][raw_index],
572 raw_images[1][raw_index],
573 rotated_headers[0][raw_index],
574 rotated_headers[1][raw_index],
580 "Error during processing");
582 check( qclog[0] = cd_align_qclog(cd_align,
583 raw_headers[0][raw_index],
585 "Could not compute QC");
589 product_filename = uves_cd_align_filename(chip);
590 check( uves_frameset_insert(frames,
592 CPL_FRAME_GROUP_PRODUCT,
593 CPL_FRAME_TYPE_TABLE,
594 CPL_FRAME_LEVEL_FINAL,
596 UVES_CD_ALIGN_TABLE(blue),
597 raw_headers[0][raw_index],
601 make_str(UVES_CD_ALIGN_ID),
602 PACKAGE
"/" PACKAGE_VERSION,
606 "Could not add CD align table %s to frameset", product_filename);
608 uves_msg(
"CD align table %s (%s) added to frameset",
609 product_filename, UVES_CD_ALIGN_TABLE(blue));
612 uves_free_image(&raw_images[0][0]);
613 uves_free_image(&raw_images[0][1]);
614 uves_free_image(&raw_images[1][0]);
615 uves_free_image(&raw_images[1][1]);
616 uves_free_propertylist(&raw_headers[0][0]);
617 uves_free_propertylist(&raw_headers[0][1]);
618 uves_free_propertylist(&raw_headers[1][0]);
619 uves_free_propertylist(&raw_headers[1][1]);
620 uves_free_propertylist(&rotated_headers[0][0]);
621 uves_free_propertylist(&rotated_headers[0][1]);
622 uves_free_propertylist(&rotated_headers[1][0]);
623 uves_free_propertylist(&rotated_headers[1][1]);
625 uves_free_table(&qclog[0]);
626 uves_free_string_const(&product_filename);
627 uves_free_table(&cd_align);
628 uves_free_propertylist(&product_header);
cpl_error_code uves_filter_image_median(cpl_image **image, int xwindow, int ywindow, bool extrapolate_border)
Median filter.
#define uves_msg_warning(...)
Print an warning message.
int uves_qclog_add_string(cpl_table *table, const char *key_name, const char *value, const char *key_help, const char *format)
Add string key to QC-LOG table.
int uves_gauss_derivative(const double x[], const double a[], double result[])
Evaluate the derivatives of a gaussian.
int uves_qclog_add_double(cpl_table *table, const char *key_name, const double value, const char *key_help, const char *format)
Add double key to QC-LOG table.
uves_propertylist * uves_propertylist_new(void)
Create an empty property list.
#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_chip_get_index(enum uves_chip chip)
Convert to integer.
#define uves_error_reset()
#define uves_msg_low(...)
Print a message on a lower message level.
const char * uves_chip_tostring_upper(enum uves_chip chip)
Convert to string.
const char * uves_string_toupper(char *s)
Convert all lowercase characters in a string into uppercase characters.
cpl_table * uves_qclog_init(const uves_propertylist *raw_header, enum uves_chip chip)
Init QC-LOG table.