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