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