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