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
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 #ifdef HAVE_CONFIG_H
00141 # include <config.h>
00142 #endif
00143
00144
00151
00152
00153
00154 #include <uves_backsub.h>
00155
00156 #include <uves_parameters.h>
00157 #include <uves_pfits.h>
00158 #include <uves_dump.h>
00159 #include <uves_utils.h>
00160 #include <uves_utils_wrappers.h>
00161 #include <uves_utils_cpl.h>
00162 #include <uves_error.h>
00163 #include <uves_msg.h>
00164 #include <uves.h>
00165
00166 #include <cpl.h>
00167 #include <string.h>
00168 #include <stdbool.h>
00169 #include <float.h>
00170
00171
00172
00173 static int first_order(const polynomial *order_locations, int nx);
00174 static int last_order (const polynomial *order_locations, int nx, int ny);
00175 static cpl_error_code lower_to_average(cpl_image *image, int RADX, int RADY);
00176 static double sample_background(const cpl_image *image, int x0, double y_0,
00177 int radius_x, int radius_y, int nx, int ny,
00178 background_measure_method BM_METHOD);
00179 static cpl_error_code subtract_background(cpl_image *image, cpl_image *background_im,
00180 const polynomial *background_pol);
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 #define BACKSUB_FLAT_SMOOTHX_BLUE (25.0/4096)
00193 #define BACKSUB_FLAT_SMOOTHX_RED (50.0/4096)
00194 #define BACKSUB_FLAT_SMOOTHY_BLUE (100.0/2048)
00195 #define BACKSUB_FLAT_SMOOTHY_RED (300.0/2048)
00196
00197 #define BACKSUB_SCI_SMOOTHX_BLUE (300.0/4096)
00198 #define BACKSUB_SCI_SMOOTHX_RED (300.0/4096)
00199 #define BACKSUB_SCI_SMOOTHY_BLUE (200.0/2048)
00200 #define BACKSUB_SCI_SMOOTHY_RED (500.0/2048)
00201
00202 #define BACKSUB_SMOOTHY_WLEN 859.9
00203
00206
00207
00208
00209
00210
00218
00219
00220 cpl_parameterlist *
00221 uves_backsub_define_parameters(void)
00222 {
00223 const char *name = "";
00224 char *full_name = NULL;
00225 cpl_parameterlist *parameters = NULL;
00226 cpl_parameter *p = NULL;
00227
00228 parameters = cpl_parameterlist_new();
00229
00230
00231 name = "mmethod";
00232 full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00233
00234 uves_parameter_new_enum(p, full_name,
00235 CPL_TYPE_STRING,
00236 "Background measuring method. If equal to 'median' "
00237 "the background is sampled using the median of a subwindow. "
00238 "If 'minimum', the subwindow minimum value is used. "
00239 "If 'no', no background subtraction is done.",
00240 UVES_BACKSUB_ID,
00241 "median",
00242 3,
00243 "median", "minimum", "no");
00244 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00245 cpl_parameterlist_append(parameters, p);
00246 cpl_free(full_name);
00247
00248
00249 name = "npoints";
00250 full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00251 uves_parameter_new_range(p, full_name,
00252 CPL_TYPE_INT,
00253 "This is the number of columns in interorder space "
00254 "used to sample the background.",
00255 UVES_BACKSUB_ID,
00256 82, 0, INT_MAX);
00257 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00258 cpl_parameterlist_append(parameters, p);
00259 cpl_free(full_name);
00260
00261
00262 name = "radiusy";
00263 full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00264 uves_parameter_new_range(p, full_name,
00265 CPL_TYPE_INT,
00266 "The height (in pixels) of the background sampling "
00267 "window is (2*radiusy + 1). "
00268 "This parameter is not corrected for binning.",
00269 UVES_BACKSUB_ID,
00270 2, 0, INT_MAX);
00271 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00272 cpl_parameterlist_append(parameters, p);
00273 cpl_free(full_name);
00274
00275
00276 name = "sdegree";
00277 full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00278 uves_parameter_new_range(p, full_name,
00279 CPL_TYPE_INT,
00280 "Degree of interpolating splines. Currently "
00281 "only degree = 1 is supported",
00282 UVES_BACKSUB_ID,
00283 1, 0, INT_MAX);
00284 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00285 cpl_parameterlist_append(parameters, p);
00286 cpl_free(full_name);
00287
00288
00289 name = "smoothx";
00290 full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00291 uves_parameter_new_range(p, full_name,
00292 CPL_TYPE_DOUBLE,
00293 "If spline interpolation is used to measure the background, "
00294 "the x-radius of the post-smoothing window is "
00295 "(smoothx * image_width). Here, 'image_width' is the image "
00296 "width after binning. If negative, the default values are used: "
00297 make_str(BACKSUB_FLAT_SMOOTHX_BLUE) " for blue flat-field frames, "
00298 make_str(BACKSUB_FLAT_SMOOTHX_RED) " for red flat-field frames, "
00299 make_str(BACKSUB_SCI_SMOOTHX_BLUE) " for blue science frames and "
00300 make_str(BACKSUB_SCI_SMOOTHX_RED) " for red science frames.",
00301 UVES_BACKSUB_ID,
00302 -1.0, -DBL_MAX, DBL_MAX);
00303 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00304 cpl_parameterlist_append(parameters, p);
00305 cpl_free(full_name);
00306
00307
00308 name = "smoothy";
00309 full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00310 uves_parameter_new_range(p, full_name,
00311 CPL_TYPE_DOUBLE,
00312 "If spline interpolation is used to measure the "
00313 "background, the y-radius of the post-smoothing "
00314 "window is (smoothy * image_height). Here, "
00315 "'image_height' is the image height after binning. "
00316 "If negative, the default values are used: "
00317 make_str(BACKSUB_FLAT_SMOOTHY_BLUE) " for blue flat-field frames, "
00318 make_str(BACKSUB_FLAT_SMOOTHY_RED) " for red flat-field frames, "
00319 make_str(BACKSUB_SCI_SMOOTHY_BLUE) " for blue science frames and "
00320 make_str(BACKSUB_SCI_SMOOTHY_RED) " for red science frames.",
00321 UVES_BACKSUB_ID,
00322 -1.0, -DBL_MAX, DBL_MAX);
00323 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00324 cpl_parameterlist_append(parameters, p);
00325 cpl_free(full_name);
00326
00327 if (cpl_error_get_code() != CPL_ERROR_NONE)
00328 {
00329 cpl_msg_error(__func__, "Creation of spline background subtraction "
00330 "parameters failed: '%s'", cpl_error_get_where());
00331 cpl_parameterlist_delete(parameters);
00332 return NULL;
00333 }
00334 else
00335 {
00336 return parameters;
00337 }
00338 }
00339
00340
00350
00351 background_measure_method
00352 uves_get_bm_method(const cpl_parameterlist *parameters, const char *context,
00353 const char *subcontext)
00354 {
00355 const char *bm = "";
00356 background_measure_method result = 0;
00357
00358 check( uves_get_parameter(parameters, context, subcontext, "mmethod", CPL_TYPE_STRING, &bm),
00359 "Could not read parameter");
00360
00361 if (strcmp(bm, "median" ) == 0) result = BM_MEDIAN;
00362 else if (strcmp(bm, "minimum") == 0) result = BM_MINIMUM;
00363 else if (strcmp(bm, "no" ) == 0) result = BM_NO;
00364 else
00365 {
00366 assure(false, CPL_ERROR_ILLEGAL_INPUT,
00367 "No such background measuring method: '%s'", bm);
00368 }
00369
00370 cleanup:
00371 return result;
00372 }
00373
00374
00408
00409
00410 cpl_error_code
00411 uves_backsub_spline(cpl_image *image, const uves_propertylist *raw_header,
00412 const cpl_table *ordertable, const polynomial *order_locations,
00413 const cpl_parameterlist *parameters, const char *context,
00414 enum uves_chip chip,
00415 bool flat_field,
00416 cpl_image **background)
00417 {
00418
00419 background_measure_method BM_METHOD;
00420 int npoints;
00421 int radius_y;
00422 int bin_x=1;
00423 int bin_y=1;
00424
00425 int sdegree;
00426 double SMOOTHX;
00427 double SMOOTHY;
00428
00429
00430 int nx, ny;
00431 int x, y;
00432 int stepx;
00433 int radius_x;
00434 int smooth_x, smooth_y;
00435
00436 passure( image != NULL, " ");
00437 passure( raw_header != NULL, " ");
00438 passure( ordertable != NULL, " ");
00439 passure( order_locations != NULL, " ");
00440 passure( parameters != NULL, " ");
00441 passure( context != NULL, " ");
00442 passure( uves_polynomial_get_dimension(order_locations) == 2,
00443 "%d", uves_polynomial_get_dimension(order_locations));
00444 passure( background != NULL, " ");
00445
00446
00447 check( BM_METHOD = uves_get_bm_method(parameters, context, UVES_BACKSUB_ID),
00448 "Error getting background measuring method");
00449
00450 check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00451 "npoints", CPL_TYPE_INT , &npoints) , "Could not read parameter");
00452 check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00453 "radiusy", CPL_TYPE_INT , &radius_y), "Could not read parameter");
00454
00455 check(bin_x=uves_pfits_get_binx(raw_header),"error getting %s",UVES_BINX);
00456 check(bin_y=uves_pfits_get_biny(raw_header),"error getting %s",UVES_BINY);
00457
00458 radius_y = uves_round_double((double)radius_y/bin_y);
00459
00460 check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00461 "sdegree", CPL_TYPE_INT , &sdegree) , "Could not read parameter");
00462 check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00463 "smoothx", CPL_TYPE_DOUBLE, &SMOOTHX) , "Could not read parameter");
00464 check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00465 "smoothy", CPL_TYPE_DOUBLE, &SMOOTHY) , "Could not read parameter");
00466
00467
00468
00469 nx = cpl_image_get_size_x(image);
00470 ny = cpl_image_get_size_y(image);
00471
00472
00473 if (BM_METHOD == BM_NO)
00474 {
00475 uves_msg("Skipping background subtraction");
00476
00477
00478 check( *background = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE),
00479 "Error allocating image");
00480 }
00481 else {
00482
00483 if (SMOOTHX < 0)
00484 {
00485 if (chip == UVES_CHIP_BLUE)
00486 {
00487 SMOOTHX = (flat_field) ?
00488 BACKSUB_FLAT_SMOOTHX_BLUE : BACKSUB_SCI_SMOOTHX_BLUE;
00489 }
00490 else
00491 {
00492 SMOOTHX = (flat_field) ?
00493 BACKSUB_FLAT_SMOOTHX_RED : BACKSUB_SCI_SMOOTHX_RED;
00494 }
00495 }
00496 if (SMOOTHY < 0)
00497 {
00498 double wlen;
00499
00500
00501
00502 check( wlen = uves_pfits_get_gratwlen(raw_header, chip),
00503 "Error reading central wavelength");
00504
00505
00506
00507 if (wlen < BACKSUB_SMOOTHY_WLEN)
00508 {
00509 SMOOTHY = (flat_field) ?
00510 BACKSUB_FLAT_SMOOTHY_BLUE : BACKSUB_SCI_SMOOTHY_BLUE;
00511 }
00512 else
00513 {
00514 SMOOTHY = (flat_field) ?
00515 BACKSUB_FLAT_SMOOTHY_RED : BACKSUB_SCI_SMOOTHY_RED;
00516 }
00517 }
00518
00519 assure( 0 < SMOOTHX, CPL_ERROR_ILLEGAL_INPUT, "Illegal smoothx factor: %e", SMOOTHX);
00520 assure( 0 < SMOOTHY, CPL_ERROR_ILLEGAL_INPUT, "Illegal smoothy factor: %e", SMOOTHY);
00521
00522 smooth_x = uves_round_double(SMOOTHX * nx - 0.5);
00523 smooth_y = uves_round_double(SMOOTHY * ny - 0.5);
00524
00525 assure( 0 < npoints, CPL_ERROR_ILLEGAL_INPUT,
00526 "Illegal number of sample points: %d", npoints);
00527 stepx = nx / npoints;
00528 assure( 0 < stepx, CPL_ERROR_ILLEGAL_INPUT, "Illegal step size: %d", stepx);
00529 radius_x = stepx/2;
00530 assure( 0 < radius_x, CPL_ERROR_ILLEGAL_INPUT, "Illegal x sample radius: %d", radius_x);
00531 assure( 0 < radius_y, CPL_ERROR_ILLEGAL_INPUT, "Illegal y sample radius: %d", radius_y);
00532 assure( 0 < smooth_x, CPL_ERROR_ILLEGAL_INPUT, "Illegal x sample smooth: %d", smooth_x);
00533 assure( 0 < smooth_y, CPL_ERROR_ILLEGAL_INPUT, "Illegal y sample smooth: %d", smooth_y);
00534 assure( sdegree == 1, CPL_ERROR_UNSUPPORTED_MODE,
00535 "Spline degree must be 1. It is %d", sdegree);
00536
00537 uves_msg("Sample window (pixels): radx, rady = %d, %d", radius_x, radius_y);
00538
00539 check( *background = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE),
00540 "Error allocating background image");
00541
00542
00543
00544 for (x = stepx; x <= nx; x += stepx) {
00545 int order, minorder, maxorder;
00546
00547
00548 minorder = cpl_table_get_column_min(ordertable, "Order");
00549
00550
00551 while (uves_round_double(
00552 uves_polynomial_evaluate_2d(order_locations, x + radius_x, minorder - 0.5)
00553 ) - radius_y < 1 ||
00554 uves_round_double(
00555 uves_polynomial_evaluate_2d(order_locations, x - radius_x, minorder - 0.5))
00556 - radius_y < 1 )
00557 {
00558 int sign;
00559
00560 for (sign = -1; sign <= 1; sign += 2)
00561 {
00562 assure(
00563 uves_polynomial_evaluate_2d(order_locations,
00564 x + sign*radius_x, minorder+1 - 0.5) >
00565 uves_polynomial_evaluate_2d(order_locations,
00566 x + sign*radius_x, minorder - 0.5),
00567 CPL_ERROR_ILLEGAL_INPUT,
00568 "Order polynomial is not well-formed: "
00569 "p(%d, %f) = %e; p(%d, %f) = %e",
00570 x + sign*radius_x, minorder+1 - 0.5, uves_polynomial_evaluate_2d(
00571 order_locations, x + sign*radius_x, minorder+1 - 0.5
00572 ),
00573 x + sign*radius_x, minorder - 0.5, uves_polynomial_evaluate_2d(
00574 order_locations, x + sign*radius_x, minorder - 0.5)
00575 );
00576 }
00577
00578 minorder += 1;
00579 }
00580
00581 maxorder = cpl_table_get_column_max(ordertable, "Order");
00582
00583
00584 while (uves_round_double(
00585 uves_polynomial_evaluate_2d(order_locations, x + radius_x, maxorder + 0.5)
00586 ) + radius_y > ny ||
00587 uves_round_double(
00588 uves_polynomial_evaluate_2d(order_locations, x - radius_x, maxorder + 0.5)
00589 ) + radius_y > ny ) {
00590 int sign;
00591 for (sign = -1; sign <= 1; sign += 2)
00592 {
00593 assure(
00594 uves_polynomial_evaluate_2d(
00595 order_locations, x + sign*radius_x, maxorder-1 - 0.5) <
00596 uves_polynomial_evaluate_2d(order_locations,
00597 x + sign*radius_x, maxorder - 0.5),
00598 CPL_ERROR_ILLEGAL_INPUT,
00599 "Order polynomial is not well-formed: "
00600 "p(%d, %f) = %e; p(%d, %f) = %e",
00601 x + sign*radius_x, maxorder-1 - 0.5, uves_polynomial_evaluate_2d(
00602 order_locations, x + sign*radius_x, maxorder-1 - 0.5),
00603 x + sign*radius_x, maxorder - 0.5, uves_polynomial_evaluate_2d(
00604 order_locations, x + sign*radius_x, maxorder - 0.5)
00605 );
00606 }
00607
00608 maxorder -= 1;
00609 }
00610
00611
00612 while (uves_round_double(uves_polynomial_evaluate_2d(
00613 order_locations, x + radius_x, minorder - 1.5)
00614 ) - radius_y >= 1 &&
00615 uves_round_double(uves_polynomial_evaluate_2d(
00616 order_locations, x - radius_x, minorder - 1.5)
00617 ) - radius_y >= 1 )
00618 {
00619 int sign;
00620 for (sign = -1; sign <= 1; sign += 2)
00621 {
00622 assure(
00623 uves_polynomial_evaluate_2d(
00624 order_locations, x + sign*radius_x, minorder-1 - 1.5) <
00625 uves_polynomial_evaluate_2d(
00626 order_locations, x + sign*radius_x, minorder - 1.5),
00627 CPL_ERROR_ILLEGAL_INPUT,
00628 "Order polynomial is not well-formed: "
00629 "p(%d, %f) = %e ; p(%d, %f) = %e",
00630 x + sign*radius_x, minorder-1 - 1.5,
00631 uves_polynomial_evaluate_2d(
00632 order_locations, x + sign*radius_x, minorder-1 - 1.5),
00633 x + sign*radius_x, minorder - 1.5,
00634 uves_polynomial_evaluate_2d(
00635 order_locations, x + sign*radius_x, minorder - 1.5));
00636 }
00637
00638 minorder -= 1;
00639 }
00640
00641
00642 while (uves_round_double( uves_polynomial_evaluate_2d(
00643 order_locations, x + radius_x, maxorder + 1.5)
00644 ) + radius_y <= ny &&
00645 uves_round_double( uves_polynomial_evaluate_2d(
00646 order_locations, x - radius_x, maxorder + 1.5)
00647 ) + radius_y <= ny ) {
00648 int sign;
00649 for (sign = -1; sign <= 1; sign += 2)
00650 {
00651 assure(
00652 uves_polynomial_evaluate_2d(
00653 order_locations, x + sign*radius_x, maxorder+1 + 1.5)
00654 >
00655 uves_polynomial_evaluate_2d(
00656 order_locations, x + sign*radius_x, maxorder + 1.5),
00657 CPL_ERROR_ILLEGAL_INPUT,
00658 "Order polynomial is not well-formed: "
00659 "p(%d, %f) = %e ; p(%d, %f) = %e",
00660 x + sign*radius_x, maxorder+1 + 1.5,
00661 uves_polynomial_evaluate_2d(
00662 order_locations, x + sign*radius_x, maxorder+1 + 1.5),
00663 x + sign*radius_x, maxorder + 1.5,
00664 uves_polynomial_evaluate_2d(
00665 order_locations, x + sign*radius_x, maxorder + 1.5));
00666 }
00667
00668 maxorder += 1;
00669 }
00670
00671 uves_msg_debug("(x, order) = (%d, %f - %f) ", x, minorder-.5, maxorder+.5);
00672
00673 for (order = minorder; order <= maxorder; order++) {
00674 int ylo, yhi;
00675 double backlo, backhi;
00676
00677
00678
00679
00680
00681 ylo = uves_round_double(
00682 uves_polynomial_evaluate_2d(order_locations, x, order - 0.5) );
00683 yhi = uves_round_double(
00684 uves_polynomial_evaluate_2d(order_locations, x, order + 0.5) );
00685
00686
00687 assure( yhi > ylo, CPL_ERROR_ILLEGAL_INPUT,
00688 "Order polynomial is not well-formed: "
00689 "p(%d, %f) = %d ; p(%d, %f) = %d",
00690 x, order - 0.5, ylo,
00691 x, order + 0.5, yhi);
00692
00693
00694 check( backlo =
00695 sample_background(
00696 image, x, ylo, radius_x, radius_y, nx, ny, BM_METHOD),
00697 "Error sampling background level");
00698
00699 check( backhi = sample_background(
00700 image, x, yhi, radius_x, radius_y, nx, ny, BM_METHOD),
00701 "Error sampling background level");
00702
00703 uves_msg_debug("Background sample at (x, y, order) = (%d, %d, %f) = %f",
00704 x, ylo, order-0.5, backlo);
00705 uves_msg_debug("Background sample at (x, y, order) = (%d, %d, %f) = %f",
00706 x, yhi, order+0.5, backhi);
00707
00708
00709 if (order == minorder) {
00710 for (y = 1; y <= ylo; y++) {
00711 double back = backlo + (backhi - backlo)*(y - ylo)/(yhi - ylo);
00712 cpl_image_set(*background, x, y, back);
00713
00714 cpl_image_set(*background, x, y, back);
00715 }
00716 }
00717
00718
00719 for (y = ylo; y <= yhi; y++) {
00720 double back;
00721 back = backlo + (backhi - backlo) * (y - ylo) / (yhi - ylo);
00722
00723 cpl_image_set(*background, x, y, back);
00724 }
00725
00726
00727 if (order == maxorder) {
00728 for (y = yhi; y <= ny; y++) {
00729 double back;
00730 back = backlo + (backhi - backlo) * (y - ylo) / (yhi - ylo);
00731
00732 cpl_image_set(*background, x, y, back);
00733 }
00734 }
00735 }
00736 }
00737
00738
00739 for (y = 1; y <= ny; y++) {
00740 int col;
00741 for (col = stepx; col+stepx <= nx; col += stepx) {
00742 int pis_rejected;
00743
00744 double backlo, backhi;
00745
00746
00747 backlo = cpl_image_get(*background, col , y, &pis_rejected);
00748 backhi = cpl_image_get(*background, col+stepx, y, &pis_rejected);
00749
00750
00751 if (col == stepx)
00752 for (x = 1; x <= col; x++)
00753 {
00754 double back = backlo + (backhi - backlo) * (x - col) / stepx;
00755 cpl_image_set(*background, x, y, back);
00756 }
00757
00758
00759 for (x = col; x <= col + stepx; x++)
00760 {
00761 double back = backlo + (backhi - backlo) * (x - col) / stepx;
00762 cpl_image_set(*background, x, y, back);
00763 }
00764
00765
00766 if (col+stepx+stepx > nx)
00767 for (x = col; x <= nx; x++)
00768 {
00769 double back = backlo + (backhi - backlo) * (x - col) / stepx;
00770 cpl_image_set(*background, x, y, back);
00771 }
00772 }
00773 }
00774
00775
00776
00777
00778
00779 uves_msg("Smoothing window (pixels): smox, smoy = %d, %d", smooth_x, smooth_y);
00780 check( uves_filter_image_average(*background, smooth_x, smooth_y),
00781 "Error applying average filter to background image");
00782
00783 uves_msg("Subtracting background image");
00784
00785 check( subtract_background(image, *background, NULL),
00786 "Error subtracting background image");
00787
00788
00789 }
00790
00791
00792 cleanup:
00793 return cpl_error_get_code();
00794 }
00795
00796
00841
00842 cpl_error_code
00843 uves_backsub_poly(cpl_image *image,
00844 const cpl_table *orders, const polynomial *order_locations,
00845 background_measure_method BM_METHOD,
00846 int NPOINTS,
00847 int radius_y,
00848 int DEGX,
00849 int DEGY,
00850 double KAPPA)
00851 {
00852 cpl_table *t = NULL;
00853 polynomial *background = NULL;
00854 int nx, ny;
00855 int stepx, stepy;
00856 int radius_x;
00857 double mse, rmse;
00858 int total_clipped = 0;
00859
00860 if (BM_METHOD == BM_NO)
00861 {
00862 uves_msg("Skipping background subtraction");
00863 }
00864 else
00865 {
00866 passure( image != NULL, " ");
00867 passure( orders == NULL || order_locations == NULL, " ");
00868
00869 nx = cpl_image_get_size_x(image);
00870 ny = cpl_image_get_size_y(image);
00871
00872 assure( NPOINTS < nx, CPL_ERROR_ILLEGAL_INPUT,
00873 "Number of sample columns (%d) larger than image width (%d pixels)",
00874 NPOINTS, nx);
00875
00876 stepx = nx/NPOINTS;
00877 stepy = ny/NPOINTS;
00878
00879 radius_x = stepx/2;
00880
00881
00882 if (orders != NULL)
00883 {
00884
00885
00886 int x, ordersrow, row;
00887
00888
00889 passure( cpl_table_has_column(orders, "Slope"), " ");
00890 passure( cpl_table_has_column(orders, "Intersept"), " ");
00891
00892 passure( cpl_table_get_column_type(orders, "Slope") == CPL_TYPE_DOUBLE,
00893 "%s",
00894 uves_tostring_cpl_type(cpl_table_get_column_type(orders, "Slope")));
00895
00896 passure( cpl_table_get_column_type(orders, "Intersept") == CPL_TYPE_DOUBLE,
00897 "%s",
00898 uves_tostring_cpl_type(cpl_table_get_column_type(orders, "Slope")));
00899
00900
00901
00902 passure( uves_table_is_sorted_double(orders, "Intersept", false), " ");
00903
00904
00905 assure ( cpl_table_get_nrow(orders) >= 2, CPL_ERROR_ILLEGAL_INPUT,
00906 "Only %d line(s) in order table", cpl_table_get_nrow(orders));
00907
00908 t = cpl_table_new( (nx/stepx + 1)*(cpl_table_get_nrow(orders) + 1) );
00909 cpl_table_new_column(t, "X", CPL_TYPE_INT);
00910 cpl_table_new_column(t, "Y", CPL_TYPE_INT);
00911 cpl_table_new_column(t, "Z", CPL_TYPE_DOUBLE);
00912
00913 row = 0;
00914 for (ordersrow = -1; ordersrow < cpl_table_get_nrow(orders); ordersrow++)
00915 {
00916 double slope, intersept;
00917
00918
00919
00920
00921 if (ordersrow == -1)
00922 {
00923 slope = cpl_table_get_double(
00924 orders, "Slope" , 0, NULL);
00925
00926
00927
00928 intersept =
00929 0.5*cpl_table_get_double(orders, "Intersept", 0, NULL) -
00930 0.5*cpl_table_get_double(orders, "Intersept", 1, NULL) ;
00931 }
00932 else if (ordersrow == cpl_table_get_nrow(orders) - 1)
00933 {
00934 slope = cpl_table_get_double(
00935 orders, "Slope" , ordersrow, NULL);
00936
00937
00938
00939 intersept =
00940 0.5*cpl_table_get_double(
00941 orders, "Intersept", ordersrow, NULL) -
00942 0.5*cpl_table_get_double(
00943 orders, "Intersept", ordersrow-1, NULL) ;
00944 }
00945 else
00946 {
00947 slope =
00948 (cpl_table_get_double(
00949 orders, "Slope", ordersrow , NULL) +
00950 cpl_table_get_double(
00951 orders, "Slope", ordersrow+1, NULL) ) / 2;
00952
00953 intersept =
00954 (cpl_table_get_double(
00955 orders, "Intersept", ordersrow , NULL) +
00956 cpl_table_get_double(
00957 orders, "Intersept", ordersrow+1, NULL) ) / 2;
00958 }
00959
00960
00961 for (x = 1 + stepx/2; x <= nx; x += stepx)
00962 {
00963 int y = uves_round_double(intersept + slope * x);
00964
00965 if (1 <= y && y <= ny)
00966 {
00967 double z;
00968
00969 check( z = sample_background(
00970 image,
00971 x, y,
00972 radius_x, radius_y,
00973 nx, ny,
00974 BM_METHOD),
00975 "Error sampling background "
00976 "(x, y) = (%d, %d)", x, y);
00977
00978 cpl_table_set_int (t, "X" , row, x);
00979 cpl_table_set_int (t, "Y" , row, y);
00980 cpl_table_set_double(t, "Z" , row, z);
00981 row++;
00982 }
00983 }
00984 }
00985
00986 cpl_table_set_size(t, row);
00987
00988 }
00989
00990 else if (order_locations != NULL)
00991 {
00992
00993
00994 int x, minorder, maxorder, order;
00995 int row;
00996
00997
00998 assure( uves_polynomial_get_dimension(order_locations) == 2,
00999 CPL_ERROR_ILLEGAL_INPUT,
01000 "Order location polynomial must be 2d. It is %d!",
01001 uves_polynomial_get_dimension(order_locations));
01002
01003 check(( minorder = first_order(order_locations, nx),
01004 maxorder = last_order(order_locations, nx, ny)),
01005 "Error getting min. and max. order numbers");
01006
01007 t = cpl_table_new( (nx/stepx + 1) * (maxorder-minorder+1));
01008 cpl_table_new_column(t, "X", CPL_TYPE_INT);
01009 cpl_table_new_column(t, "Y", CPL_TYPE_INT);
01010 cpl_table_new_column(t, "Z", CPL_TYPE_DOUBLE);
01011
01012 row = 0;
01013 for (order = minorder; order <= maxorder; order++) {
01014
01015 for (x = 1+stepx/2; x <= nx; x += stepx) {
01016 int y = uves_round_double(
01017 uves_polynomial_evaluate_2d(order_locations, x, order + 0.5));
01018
01019 if (1 <= y && y <= ny) {
01020 double z;
01021
01022 check( z = sample_background(image,
01023 x, y,
01024 radius_x, radius_y,
01025 nx, ny,
01026 BM_METHOD),
01027 "Error sampling background (x, order) = (%d, %d+0.5)",
01028 x, order);
01029
01030 cpl_table_set_int (t, "X" , row, x);
01031 cpl_table_set_int (t, "Y" , row, y);
01032 cpl_table_set_double(t, "Z" , row, z);
01033 row++;
01034 }
01035 }
01036 }
01037
01038 cpl_table_set_size(t, row);
01039 }
01040 else
01041 {
01042
01043 int x, y, row;
01044
01045 t = cpl_table_new((nx/stepx + 1) * (ny/stepy + 1));
01046 cpl_table_new_column(t, "X" , CPL_TYPE_INT);
01047 cpl_table_new_column(t, "Y" , CPL_TYPE_INT);
01048 cpl_table_new_column(t, "Z" , CPL_TYPE_DOUBLE);
01049
01050 row = 0;
01051 for (y = 1 + stepy/2; y <= ny; y += stepy)
01052 {
01053 for (x = 1+stepx/2; x <= nx; x += stepx)
01054 {
01055 double z;
01056
01057 check( z = sample_background(image,
01058 x, y,
01059 radius_x, radius_y,
01060 nx, ny,
01061 BM_METHOD),
01062 "Error sampling background (x, y) = (%d, %d)", x, y);
01063
01064 cpl_table_set_int (t, "X" , row, x);
01065 cpl_table_set_int (t, "Y" , row, y);
01066 cpl_table_set_double(t, "Z" , row, z);
01067 row++;
01068 }
01069 }
01070 cpl_table_set_size(t, row);
01071 }
01072
01073
01074
01075 total_clipped = 0;
01076 {
01077 int n_clipped;
01078 do {
01079 assure( cpl_table_get_nrow(t) > (DEGX + 1)*(DEGY + 1),
01080 CPL_ERROR_ILLEGAL_OUTPUT,
01081 "Too few sample points available (%d point(s)) to make the fit "
01082 "(more than %d points needed). "
01083 "Increase number of sample points or increase kappa",
01084 cpl_table_get_nrow(t), (DEGX + 1)*(DEGY + 1));
01085
01086
01087 uves_polynomial_delete(&background);
01088 check( background = uves_polynomial_regression_2d(
01089 t, "X", "Y", "Z", NULL,
01090 DEGX, DEGY, "Zfit", NULL, NULL, &mse,
01091 NULL, NULL, -1, -1),
01092 "Error fitting polynomial");
01093
01094
01095 cpl_table_duplicate_column(t, "Residual", t, "Z");
01096 cpl_table_subtract_columns(t, "Residual", "Zfit");
01097
01098
01099
01100
01101
01102
01103 cpl_table_subtract_scalar(t, "Residual",
01104 cpl_table_get_column_median(t, "Residual"));
01105 rmse = cpl_table_get_column_stdev(t, "Residual");
01106
01107
01108 if (KAPPA > 0)
01109 {
01110 check( n_clipped = uves_select_table_rows(
01111 t, "Residual", CPL_GREATER_THAN, KAPPA * rmse),
01112 "Error selecting rows");
01113 }
01114 else
01115 {
01116 n_clipped = 0;
01117 }
01118
01119 total_clipped += n_clipped;
01120
01121 uves_msg_debug("RMS = %f. %d of %d points rejected in kappa-sigma clipping",
01122 rmse, n_clipped, cpl_table_get_nrow(t));
01123
01124 cpl_table_erase_selected(t);
01125
01126 if (n_clipped > 0)
01127 {
01128 cpl_table_erase_column(t, "Zfit");
01129 cpl_table_erase_column(t, "Residual");
01130 }
01131
01132 } while (n_clipped > 0);
01133 }
01134
01135
01136
01137 {
01138 double percentage =
01139 100.0 * ( (double)total_clipped ) / (total_clipped + cpl_table_get_nrow(t));
01140
01141 if (KAPPA > 0) {
01142 uves_msg("%d of %d points (%.2f %%) were rejected in "
01143 "kappa-sigma clipping. RMS = %.2f ADU",
01144 total_clipped,
01145 cpl_table_get_nrow(t) + total_clipped,
01146 percentage,
01147 sqrt(mse));
01148 }
01149
01150
01151 if (orders == NULL && order_locations == NULL)
01152 {
01153 if (total_clipped == 0)
01154 {
01155 uves_msg_warning("No points rejected during background "
01156 "estimation. Background subtraction is "
01157 "uncertain. Try to decrease KAPPA "
01158 "(current value is %f)", KAPPA);
01159 }
01160 if (percentage > 40)
01161 {
01162 uves_msg_warning("%f %% of the sample points were "
01163 "rejected during "
01164 "background estimation", percentage);
01165 }
01166 }
01167 }
01168
01169 check( subtract_background(image, NULL, background),
01170 "Error subtracting background polynomial");
01171 }
01172
01173 cleanup:
01174 uves_free_table(&t);
01175 uves_polynomial_delete(&background);
01176
01177 return cpl_error_get_code();
01178 }
01179
01180
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225 cpl_error_code
01226 uves_backsub_smooth(cpl_image *image, int RADX, int RADY, int ITER)
01227 {
01228 cpl_image *background = NULL;
01229 int i;
01230
01231 assure( RADX >= 0 && RADY >= 0, CPL_ERROR_ILLEGAL_INPUT,
01232 "Negative radius ((%d)x(%d))", RADX, RADY);
01233 assure( ITER >= 1, CPL_ERROR_ILLEGAL_INPUT,
01234 "Non-positive number of iterations (%d)", ITER);
01235
01236
01237 background = cpl_image_duplicate(image);
01238
01239 for (i = 0; i < ITER; i++) {
01240
01241 uves_msg("i = %d", i);
01242 check( lower_to_average(background,
01243 RADX, RADY), "Error smoothing image");
01244 }
01245
01246
01247 check( cpl_image_subtract(image, background), "Could not subtract background image");
01248
01249 cleanup:
01250 uves_free_image(&background);
01251
01252 return cpl_error_get_code();
01253 }
01254
01255
01274
01275
01276 static double
01277 sample_background(const cpl_image *image, int x0, double y_0,
01278 int radius_x, int radius_y, int nx, int ny,
01279 background_measure_method BM_METHOD)
01280 {
01281 double result = 0;
01282
01283 cpl_table *temp = NULL;
01284 bool found_good = false;
01285 int row;
01286 int x, y;
01287
01288 check(
01289 (temp = cpl_table_new( (2*radius_x + 1) * (2*radius_y + 1) ),
01290 row = 0,
01291 cpl_table_new_column(temp, "Flux", CPL_TYPE_DOUBLE)),
01292 "Error allocating table");
01293
01294 for(y = y_0 - radius_y; y <= y_0 + radius_y; y++)
01295 {
01296 for (x = x0 - radius_x; x <= x0 + radius_x; x++)
01297 {
01298 if (1 <= x && x <= nx &&
01299 1 <= y && y <= ny)
01300 {
01301 int pis_rejected;
01302 double flux = cpl_image_get(image, x, y, &pis_rejected);
01303 if( !pis_rejected )
01304 {
01305 cpl_table_set(temp, "Flux", row, flux);
01306 found_good = true;
01307 }
01308 else
01309 {
01310 cpl_table_set_invalid(temp, "Flux", row);
01311 }
01312 }
01313 else
01314 {
01315 cpl_table_set_invalid(temp, "Flux", row);
01316 }
01317
01318 row++;
01319 }
01320 }
01321
01322 assure( found_good, CPL_ERROR_ILLEGAL_INPUT, "No valid pixels in sample window");
01323
01324 if (BM_METHOD == BM_MEDIAN)
01325 {
01326 result = cpl_table_get_column_median(temp, "Flux");
01327 }
01328 else if (BM_METHOD == BM_MINIMUM)
01329 {
01330 result = cpl_table_get_column_min(temp, "Flux");
01331 }
01332 else
01333 {
01334 assure( false, CPL_ERROR_UNSUPPORTED_MODE,
01335 "Unsupported background sample method: %d", BM_METHOD);
01336 }
01337
01338 cleanup:
01339 uves_free_table(&temp);
01340 return result;
01341 }
01342
01343
01352
01353 static int
01354 first_order(const polynomial *order_locations, int nx)
01355 {
01356 int result;
01357
01358 result = 0;
01359 while (uves_polynomial_evaluate_2d(order_locations, 1 , result + 0.5) < 1 ||
01360 uves_polynomial_evaluate_2d(order_locations, nx, result + 0.5) < 1 )
01361 {
01362 result++;
01363 }
01364
01365 while (uves_polynomial_evaluate_2d(order_locations, 1 , result - 0.5) >= 1 ||
01366 uves_polynomial_evaluate_2d(order_locations, nx, result - 0.5) >= 1 )
01367 {
01368 result -= 1;
01369
01370
01371 assure( result > -100000,
01372 CPL_ERROR_CONTINUE,
01373 "Invalid polynomial: p(x=1, order=%d) = %f p(x=%d, order=%d) = %f",
01374 result, uves_polynomial_evaluate_2d(order_locations, 1.0, result),
01375 nx, result, uves_polynomial_evaluate_2d(order_locations, nx, result));
01376 }
01377
01378 cleanup:
01379 return result;
01380 }
01381
01382
01383
01393
01394 static int
01395 last_order(const polynomial *order_locations, int nx, int ny)
01396 {
01397 int result;
01398
01399 result = 0;
01400 while (uves_polynomial_evaluate_2d(order_locations, 1 , result - 0.5) > ny ||
01401 uves_polynomial_evaluate_2d(order_locations, nx, result - 0.5) > ny )
01402 {
01403 result--;
01404 }
01405
01406 while (uves_polynomial_evaluate_2d(order_locations, 1 , result + 1.5) <= ny ||
01407 uves_polynomial_evaluate_2d(order_locations, nx, result + 1.5) <= ny )
01408 {
01409 result += 1;
01410
01411
01412 assure( result < 100000,
01413 CPL_ERROR_CONTINUE,
01414 "Invalid polynomial: p(x=1, order=%d) = %f p(x=%d, order=%d) = %f",
01415 result, uves_polynomial_evaluate_2d(order_locations, 1.0, result),
01416 nx, result, uves_polynomial_evaluate_2d(order_locations, nx, result));
01417 }
01418
01419 cleanup:
01420 return result;
01421 }
01422
01423
01435
01436 static cpl_error_code
01437 lower_to_average(cpl_image *image, int RADX, int RADY)
01438 {
01439 cpl_image *average = NULL;
01440 double *image_data = NULL;
01441 double *average_data = NULL;
01442 int nx, ny;
01443 int x, y;
01444
01445 passure( image != NULL, "Null image");
01446 nx = cpl_image_get_size_x(image);
01447 ny = cpl_image_get_size_y(image);
01448
01449
01450 uves_msg("Filtering...");
01451 check( average = cpl_image_duplicate(image), "Error copying image");
01452 check( uves_filter_image_average(average, RADX, RADY), "Error applying average filter");
01453 uves_msg("done");
01454
01455 image_data = cpl_image_get_data(image);
01456 average_data = cpl_image_get_data(average);
01457 uves_msg("Lowering...");
01458 for (y = 0; y < ny; y++)
01459 {
01460 for (x = 0; x < nx; x++)
01461 {
01462 if (image_data[x + y*nx] > average_data[x + y*nx])
01463 {
01464 image_data[x + y*nx] = average_data[x + y*nx];
01465 }
01466 }
01467 }
01468 uves_msg("done");
01469
01470 cleanup:
01471 uves_free_image(&average);
01472
01473 return cpl_error_get_code();
01474 }
01475
01476
01488
01489
01490 static cpl_error_code
01491 subtract_background(cpl_image *image, cpl_image *background_im,
01492 const polynomial *background_pol)
01493 {
01494 int nx, ny;
01495 int x, y;
01496
01497 double *image_data;
01498 double *background_data = NULL;
01499
01500 passure(image != NULL, " ");
01501
01502 passure((background_im == NULL) != (background_pol == NULL), " ");
01503
01504
01505 assure(cpl_image_count_rejected(image) == 0,
01506 CPL_ERROR_UNSUPPORTED_MODE, "Input image contains bad pixels");
01507 assure(cpl_image_get_type(image) == CPL_TYPE_DOUBLE,
01508 CPL_ERROR_UNSUPPORTED_MODE,
01509 "Input image is of type %s. double expected",
01510 uves_tostring_cpl_type(cpl_image_get_type(image)));
01511
01512 if (background_im != NULL)
01513 {
01514 assure(cpl_image_count_rejected(background_im) == 0,
01515 CPL_ERROR_UNSUPPORTED_MODE, "Background image contains bad pixels");
01516 assure(cpl_image_get_type(background_im) == CPL_TYPE_DOUBLE,
01517 CPL_ERROR_UNSUPPORTED_MODE,
01518 "Background image is of type %s. double expected",
01519 uves_tostring_cpl_type(cpl_image_get_type(background_im)));
01520 }
01521
01522 image_data = cpl_image_get_data_double(image);
01523 if (background_im != NULL)
01524 {
01525 background_data = cpl_image_get_data_double(background_im);
01526 }
01527
01528 nx = cpl_image_get_size_x(image);
01529 ny = cpl_image_get_size_y(image);
01530
01531 for (y = 1; y <= ny; y++)
01532 {
01533 for (x = 1; x <= nx; x++)
01534 {
01535 double back;
01536 double flux, new_flux;
01537
01538 if (background_im != NULL)
01539 {
01540
01541 back = background_data[(x-1) + (y-1) * nx];
01542 }
01543 else
01544 {
01545
01546 back = uves_polynomial_evaluate_2d(background_pol,
01547 x,
01548 y);
01549 }
01550
01551
01552 flux = image_data[(x-1) + (y-1) * nx];
01553
01554
01555 #if 0
01556
01557 if (back < 0)
01558 {
01559 back = 0.0;
01560 }
01561 if (back > flux)
01562 {
01563 back = flux;
01564 }
01565
01566
01567
01568
01569 new_flux = uves_max_double(0, flux - back);
01570 #else
01571 new_flux = flux-back;
01572 #endif
01573
01574
01575 image_data[(x-1) + (y-1) * nx] = new_flux;
01576
01577 if (background_im != NULL)
01578 {
01579
01580 background_data[(x-1) + (y-1) * nx] = flux - new_flux;
01581 }
01582 }
01583 }
01584
01585 cleanup:
01586 return cpl_error_get_code();
01587 }