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 #ifdef HAVE_CONFIG_H
00068 # include <config.h>
00069 #endif
00070
00071
00078
00079
00080
00081
00082
00083 #include <uves_cd_align_impl.h>
00084
00085 #include <uves.h>
00086 #include <uves_plot.h>
00087 #include <uves_parameters.h>
00088 #include <uves_dfs.h>
00089 #include <uves_pfits.h>
00090 #include <uves_qclog.h>
00091 #include <uves_recipe.h>
00092 #include <uves_utils_cpl.h>
00093 #include <uves_utils_wrappers.h>
00094 #include <uves_error.h>
00095 #include <uves_msg.h>
00096
00097 #include <cpl.h>
00098
00099
00100
00101
00102
00103 static int
00104 uves_cal_cd_align_define_parameters(cpl_parameterlist *parameters);
00105
00106
00107
00108
00109 #define cpl_plugin_get_info uves_cal_cd_align_get_info
00110 UVES_RECIPE_DEFINE(
00111 UVES_CD_ALIGN_ID, UVES_CD_ALIGN_DOM, uves_cal_cd_align_define_parameters,
00112 "Jonas M. Larsen", "cpl@eso.org",
00113 "Measures the reproducability of the cross disperser positioning",
00114 "Given two input frames (CD_ALIGN_xxx where xxx = BLUE or RED) which contain only\n"
00115 "one echelle order, this recipe measures the shift in the cross-dispersion \n"
00116 "direction of that order. For RED input frames, only the lower chip is processed.\n"
00117 "\n"
00118 "The recipe produces a CD_ALIGN_TABLE_xxxx (with xxxx = BLUE or REDL) with columns\n"
00119 "X: Column number\n"
00120 "YCENi: Centroid from Gaussian fit (for i = 1,2)\n"
00121 "SIGMAi: Stdev from Gaussian fit\n"
00122 "BACKi: Constant background from Gaussian fit\n"
00123 "NORMi: Normalization constant from Gaussian fit\n"
00124 "YDIFF: Difference YCEN2 - YCEN1 of centroid positions\n"
00125 "\n"
00126 "and the QC-parameters ESO.QC.YDIFF(AVG|MED|RMS), which are the average,\n"
00127 "median and root-mean-square of the y-shift, respectively.\n");
00128
00129
00130
00131
00133 static int
00134 uves_cal_cd_align_define_parameters(cpl_parameterlist *parameters)
00135 {
00136 const char *subcontext = NULL;
00137 const char *recipe_id = make_str(UVES_CD_ALIGN_ID);
00138
00139
00140
00141
00142 if (uves_define_global_parameters(parameters) != CPL_ERROR_NONE)
00143 {
00144 return -1;
00145 }
00146
00147
00148 uves_par_new_range("steps",
00149 CPL_TYPE_INT,
00150 "Step size in pixels",
00151 100, 1, INT_MAX);
00152
00153
00154 uves_par_new_range("xborder",
00155 CPL_TYPE_INT,
00156 "Exclude a border region of this size (pixels)",
00157 200, 0, INT_MAX);
00158
00159
00160 uves_par_new_range("window",
00161 CPL_TYPE_INT,
00162 "The half window height used for Gaussian fitting",
00163 50, 1, INT_MAX);
00164
00165 return (cpl_error_get_code() != CPL_ERROR_NONE);
00166 }
00167
00168
00185
00186 cpl_table *
00187 uves_cd_align_process(const cpl_image *im1,
00188 const cpl_image *im2,
00189 const uves_propertylist *rotated_header1,
00190 const uves_propertylist *rotated_header2,
00191 int steps,
00192 int xborder,
00193 int window,
00194 bool DEBUG,
00195 enum uves_chip chip)
00196 {
00197 cpl_table *result = NULL;
00198 int row = 0;
00199 const cpl_image *images[2];
00200 cpl_image *rows = NULL;
00201 int max_row[2];
00202 int nx, ny, x;
00203 int num_fits, fit_succeeded;
00204
00205 images[0] = im1;
00206 images[1] = im2;
00207 nx = cpl_image_get_size_x(images[0]);
00208 ny = cpl_image_get_size_y(images[0]);
00209
00210 if (DEBUG) check( uves_save_image_local("CD alignment frame", "cd_align1",
00211 images[0], chip, -1, -1,
00212 rotated_header1, true),
00213 "Error saving 1st CD aligment frame");
00214
00215 if (DEBUG) check( uves_save_image_local("CD alignment frame", "cd_align2",
00216 images[1], chip, -1, -1,
00217 rotated_header2, true),
00218 "Error saving 2nd CD aligment frame");
00219
00220 assure( cpl_image_get_size_x(images[0]) == cpl_image_get_size_x(images[1]) &&
00221 cpl_image_get_size_y(images[0]) == cpl_image_get_size_y(images[1]),
00222 CPL_ERROR_INCOMPATIBLE_INPUT,
00223 "Images sizes: %dx%d and %dx%d",
00224 cpl_image_get_size_x(images[0]),
00225 cpl_image_get_size_y(images[0]),
00226 cpl_image_get_size_x(images[1]),
00227 cpl_image_get_size_y(images[1]) );
00228
00229
00230 result = cpl_table_new(nx); row = 0;
00231 cpl_table_new_column(result, "X" , CPL_TYPE_INT);
00232 cpl_table_new_column(result, "YCEN1", CPL_TYPE_DOUBLE);
00233 cpl_table_new_column(result, "YCEN2", CPL_TYPE_DOUBLE);
00234 cpl_table_new_column(result, "SIGMA1", CPL_TYPE_DOUBLE);
00235 cpl_table_new_column(result, "SIGMA2", CPL_TYPE_DOUBLE);
00236 cpl_table_new_column(result, "BACK1", CPL_TYPE_DOUBLE);
00237 cpl_table_new_column(result, "BACK2", CPL_TYPE_DOUBLE);
00238 cpl_table_new_column(result, "NORM1", CPL_TYPE_DOUBLE);
00239 cpl_table_new_column(result, "NORM2", CPL_TYPE_DOUBLE);
00240 assure_mem( result );
00241
00242
00243 {
00244 int im;
00245 for (im = 0; im < 2; im++)
00246 {
00247 int direction = 1;
00248 int max_col;
00249
00250 uves_free_image(&rows);
00251 rows = cpl_image_collapse_create(images[im], direction);
00252
00253 cpl_image_get_maxpos(rows, &max_col, &(max_row[im]));
00254 uves_msg("Row of max flux (%d. image) = %d", im+1, max_row[im]);
00255
00256 assure( max_col == 1, CPL_ERROR_ILLEGAL_OUTPUT,
00257 "Something went wrong, max_col in collapsed image is = %d", max_col);
00258 }
00259 }
00260
00261 num_fits = 0;
00262 fit_succeeded = 0;
00263 for (x = 1 + xborder; x <= nx - xborder; x += steps)
00264 {
00265 int im;
00266 for (im = 0; im < 2; im++)
00267 {
00268 bool horizontal = false;
00269 bool fix_background = false;
00270 bool fit_background = false;
00271 int number_of_parameters = 4;
00272 double y_0, sigma, norm, background;
00273 int ylow = uves_max_int(1, uves_min_int(ny, max_row[im] - window));
00274 int yhigh = uves_max_int(1, uves_min_int(ny, max_row[im] + window));
00275
00276 uves_fit_1d_image(images[im],
00277 NULL, NULL,
00278 horizontal, fix_background, fit_background,
00279 ylow, yhigh, x,
00280 &y_0, &sigma, &norm, &background, NULL,
00281 NULL, NULL,
00282 NULL,
00283 uves_gauss, uves_gauss_derivative,
00284 number_of_parameters);
00285
00286 num_fits += 1;
00287 if (cpl_error_get_code() == CPL_ERROR_CONTINUE)
00288 {
00289 uves_error_reset();
00290
00291 uves_msg_warning("Fitting window (%d, %d) - (%d, %d) failed",
00292 x, ylow, x, yhigh);
00293 }
00294 else
00295 {
00296 fit_succeeded += 1;
00297
00298 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00299 cpl_error_get_code(),
00300 "Gaussian fitting failed");
00301
00302 cpl_table_set_int (result, "X" , row, x);
00303 cpl_table_set_double(result, (im == 0) ? "YCEN1" : "YCEN2", row, y_0);
00304 cpl_table_set_double(result, (im == 0) ? "SIGMA1": "SIGMA2", row, sigma);
00305 cpl_table_set_double(result, (im == 0) ? "BACK1" : "BACK2", row, norm);
00306 cpl_table_set_double(result, (im == 0) ? "NORM1" : "NORM2", row, background);
00307 }
00308 }
00309 row++;
00310 }
00311
00312 cpl_table_set_size(result, row);
00313
00314 uves_msg_low("Was able to fit %d of %d columns", fit_succeeded, num_fits);
00315
00316 check(( cpl_table_duplicate_column(result, "YDIFF", result, "YCEN2"),
00317 cpl_table_subtract_columns(result, "YDIFF", "YCEN1")),
00318 "Error calculating residuals of fit");
00319
00320 {
00321 int num_valid = cpl_table_get_nrow(result) - cpl_table_count_invalid(result, "YDIFF");
00322
00323 assure( num_valid >= 1, CPL_ERROR_ILLEGAL_OUTPUT,
00324 "Only %d valid YDIFF value(s), 1 or more needed",
00325 num_valid);
00326 }
00327
00328
00329 cleanup:
00330 uves_free_image(&rows);
00331 return result;
00332 }
00333
00334
00343
00344
00345 static cpl_table*
00346 cd_align_qclog(const cpl_table *cdalign,
00347 const uves_propertylist *raw_header,
00348 enum uves_chip chip)
00349 {
00350 cpl_table *qclog = NULL;
00351 double mean, sigma, median;
00352
00353 check( qclog = uves_qclog_init(raw_header, chip),
00354 "Error during QC initialization");
00355
00356 mean = cpl_table_get_column_mean (cdalign, "YDIFF");
00357 sigma = cpl_table_get_column_stdev (cdalign, "YDIFF");
00358 median = cpl_table_get_column_median(cdalign, "YDIFF");
00359
00360 uves_qclog_add_string(qclog,
00361 "QC TEST1 ID",
00362 "Test-of-CD-Alignment",
00363 "Name of QC test",
00364 "%s");
00365
00366 uves_qclog_add_double(qclog,
00367 "QC YDIFFAVG",
00368 mean,
00369 "Average Y difference",
00370 "%8.4f");
00371
00372 uves_qclog_add_double(qclog,
00373 "QC YDIFFMED",
00374 median,
00375 "Median Y difference",
00376 "%8.4f");
00377
00378 uves_qclog_add_double(qclog,
00379 "QC YDIFFRMS",
00380 sigma,
00381 "RMS Y difference",
00382 "%8.4f");
00383
00384
00385 uves_msg("Average shift = %.4f +- %.4f pixels",
00386 mean, sigma);
00387
00388
00389 cleanup:
00390 return qclog;
00391 }
00392
00393
00401
00402 static double
00403 avg_flux(const cpl_image *im)
00404 {
00405 double result = 0;
00406 cpl_image *median_filt = NULL;
00407 bool extrapolate_border = true;
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422 median_filt = cpl_image_duplicate(im);
00423 assure_mem( median_filt );
00424
00425 uves_filter_image_median(&median_filt, 1, 1,
00426 extrapolate_border);
00427
00428 result =
00429 cpl_image_get_mean (median_filt) -
00430 cpl_image_get_median(median_filt);
00431
00432 cleanup:
00433 uves_free_image(&median_filt);
00434 return result;
00435 }
00436
00437
00445
00446 static void
00447 uves_cal_cd_align_exe(cpl_frameset *frames, const cpl_parameterlist *parameters,
00448 const char *starttime)
00449 {
00450
00451 cpl_image *raw_images[2][2] = {{NULL, NULL}, {NULL, NULL}};
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463 uves_propertylist *raw_headers[2][2] = {{NULL, NULL}, {NULL, NULL}};
00464 uves_propertylist *rotated_headers[2][2] = {{NULL, NULL}, {NULL, NULL}};
00465
00466 cpl_table* qclog[2] = {NULL, NULL};
00467
00468
00469 uves_propertylist *product_header = NULL;
00470 cpl_table *cd_align = NULL;
00471
00472
00473 int steps, xborder, window;
00474 bool DEBUG;
00475
00476
00477 const char *product_filename = NULL;
00478 bool blue;
00479 enum uves_chip chip;
00480 const char *raw_filename[2];
00481 int raw_index;
00482
00483 const char* PROCESS_CHIP=NULL;
00484
00485 check( uves_get_parameter(parameters, NULL, "uves", "debug",
00486 CPL_TYPE_BOOL, &DEBUG), "Could not read parameter");
00487
00488 check( uves_get_parameter(parameters, NULL, "uves", "process_chip", CPL_TYPE_STRING, &PROCESS_CHIP),
00489 "Could not read parameter");
00490
00491 check( uves_get_parameter(parameters, NULL, make_str(UVES_CD_ALIGN_ID), "steps",
00492 CPL_TYPE_INT , &steps), "Could not read parameter");
00493 check( uves_get_parameter(parameters, NULL, make_str(UVES_CD_ALIGN_ID), "xborder",
00494 CPL_TYPE_INT , &xborder), "Could not read parameter");
00495 check( uves_get_parameter(parameters, NULL, make_str(UVES_CD_ALIGN_ID), "window",
00496 CPL_TYPE_INT , &window), "Could not read parameter");
00497
00498
00499 check( uves_load_cd_align(frames,
00500 &raw_filename[0],
00501 &raw_filename[1],
00502 raw_images[0],
00503 raw_images[1],
00504 raw_headers[0],
00505 raw_headers[1],
00506 rotated_headers[0],
00507 rotated_headers[1],
00508 &blue),
00509 "Error loading raw frame");
00510
00511 uves_msg("Using %s", raw_filename[0]);
00512 uves_msg("Using %s", raw_filename[1]);
00513
00514
00515 if (blue)
00516 {
00517 chip = UVES_CHIP_BLUE;
00518 }
00519 else
00520 {
00521 if (DEBUG)
00522 {
00523 int raw_index_l = uves_chip_get_index(UVES_CHIP_REDL);
00524 int raw_index_u = uves_chip_get_index(UVES_CHIP_REDU);
00525
00526 uves_msg("1. REDL average flux per pixel = %f ADU", avg_flux(raw_images[0][raw_index_l]));
00527 uves_msg("2. REDL average flux per pixel = %f ADU", avg_flux(raw_images[1][raw_index_l]));
00528
00529 uves_msg("1. REDU average flux per pixel = %f ADU", avg_flux(raw_images[0][raw_index_u]));
00530 uves_msg("2. REDU average flux per pixel = %f ADU", avg_flux(raw_images[1][raw_index_u]));
00531 }
00532
00533 chip = UVES_CHIP_REDL;
00534 }
00535
00536 raw_index = uves_chip_get_index(chip);
00537
00538 uves_msg("Processing %s chip",
00539 uves_chip_tostring_upper(chip));
00540
00541 check( cd_align = uves_cd_align_process(raw_images[0][raw_index],
00542 raw_images[1][raw_index],
00543 rotated_headers[0][raw_index],
00544 rotated_headers[1][raw_index],
00545 steps,
00546 xborder,
00547 window,
00548 DEBUG,
00549 chip),
00550 "Error during processing");
00551
00552 check( qclog[0] = cd_align_qclog(cd_align,
00553 raw_headers[0][raw_index],
00554 chip),
00555 "Could not compute QC");
00556
00557 product_header = uves_propertylist_new();
00558 product_filename = uves_cd_align_filename(chip);
00559 check( uves_frameset_insert(frames,
00560 cd_align,
00561 CPL_FRAME_GROUP_PRODUCT,
00562 CPL_FRAME_TYPE_TABLE,
00563 CPL_FRAME_LEVEL_FINAL,
00564 product_filename,
00565 UVES_CD_ALIGN_TABLE(blue),
00566 raw_headers[0][raw_index],
00567 product_header,
00568 NULL,
00569 parameters,
00570 make_str(UVES_CD_ALIGN_ID),
00571 PACKAGE "/" PACKAGE_VERSION,
00572 qclog,
00573 starttime, true,
00574 0),
00575 "Could not add CD align table %s to frameset", product_filename);
00576
00577 uves_msg("CD align table %s (%s) added to frameset",
00578 product_filename, UVES_CD_ALIGN_TABLE(blue));
00579
00580 cleanup:
00581 uves_free_image(&raw_images[0][0]);
00582 uves_free_image(&raw_images[0][1]);
00583 uves_free_image(&raw_images[1][0]);
00584 uves_free_image(&raw_images[1][1]);
00585 uves_free_propertylist(&raw_headers[0][0]);
00586 uves_free_propertylist(&raw_headers[0][1]);
00587 uves_free_propertylist(&raw_headers[1][0]);
00588 uves_free_propertylist(&raw_headers[1][1]);
00589 uves_free_propertylist(&rotated_headers[0][0]);
00590 uves_free_propertylist(&rotated_headers[0][1]);
00591 uves_free_propertylist(&rotated_headers[1][0]);
00592 uves_free_propertylist(&rotated_headers[1][1]);
00593
00594 uves_free_table(&qclog[0]);
00595 uves_free_string_const(&product_filename);
00596 uves_free_table(&cd_align);
00597 uves_free_propertylist(&product_header);
00598
00599 return;
00600 }
00601
00602