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