uves_backsub.c

00001 /*                                                                              *
00002  *   This file is part of the ESO UVES Pipeline                                 *
00003  *   Copyright (C) 2004,2005 European Southern Observatory                      *
00004  *                                                                              *
00005  *   This library is free software; you can redistribute it and/or modify       *
00006  *   it under the terms of the GNU General Public License as published by       *
00007  *   the Free Software Foundation; either version 2 of the License, or          *
00008  *   (at your option) any later version.                                        *
00009  *                                                                              *
00010  *   This program is distributed in the hope that it will be useful,            *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of             *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
00013  *   GNU General Public License for more details.                               *
00014  *                                                                              *
00015  *   You should have received a copy of the GNU General Public License          *
00016  *   along with this program; if not, write to the Free Software                *
00017  *   Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA       *
00018  *                                                                              */
00019 
00020 /*
00021  * $Author: amodigli $
00022  * $Date: 2007/06/06 08:17:33 $
00023  * $Revision: 1.42 $
00024  * $Name: uves-3_3_1 $
00025  * $Log: uves_backsub.c,v $
00026  * Revision 1.42  2007/06/06 08:17:33  amodigli
00027  * replace tab with 4 spaces
00028  *
00029  * Revision 1.41  2007/05/22 11:29:39  jmlarsen
00030  * Removed MIDAS flag for good
00031  *
00032  * Revision 1.40  2007/04/24 12:50:29  jmlarsen
00033  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00034  *
00035  * Revision 1.39  2007/04/10 07:06:17  jmlarsen
00036  * Changed interface of polynomial_regression_2d()
00037  *
00038  * Revision 1.38  2007/03/28 11:38:21  jmlarsen
00039  * Killed MIDAS flag, removed dead code
00040  *
00041  * Revision 1.37  2007/02/12 10:04:24  jmlarsen
00042  * Added debugging statements
00043  *
00044  * Revision 1.36  2007/02/09 08:50:58  jmlarsen
00045  * Use define's rather than hard-coded recipe names
00046  *
00047  * Revision 1.35  2007/01/15 08:46:48  jmlarsen
00048  * Shortened lines
00049  *
00050  * Revision 1.34  2006/11/15 15:02:14  jmlarsen
00051  * Implemented const safe workarounds for CPL functions
00052  *
00053  * Revision 1.32  2006/11/15 14:04:08  jmlarsen
00054  * Removed non-const version of parameterlist_get_first/last/next which is
00055  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
00056  *
00057  * Revision 1.31  2006/11/06 15:19:41  jmlarsen
00058  * Removed unused include directives
00059  *
00060  * Revision 1.30  2006/09/20 12:53:57  jmlarsen
00061  * Replaced stringcat functions with uves_sprintf()
00062  *
00063  * Revision 1.29  2006/09/11 08:20:44  jmlarsen
00064  * Renamed identifier reserved by POSIX
00065  *
00066  * Revision 1.28  2006/08/23 09:33:03  jmlarsen
00067  * Renamed local variables shadowing POSIX reserved names
00068  *
00069  * Revision 1.27  2006/08/17 13:56:52  jmlarsen
00070  * Reduced max line length
00071  *
00072  * Revision 1.26  2006/08/11 14:36:11  jmlarsen
00073  * Implemented workaround for slow cpl_table_erase_selected
00074  *
00075  * Revision 1.25  2006/08/07 11:35:35  jmlarsen
00076  * Disabled parameter environment variable mode
00077  *
00078  * Revision 1.24  2006/07/14 12:18:33  jmlarsen
00079  * Disable compiler warning
00080  *
00081  * Revision 1.23  2006/07/03 12:57:50  jmlarsen
00082  * Threshold background image to positive
00083  *
00084  * Revision 1.22  2006/06/13 11:54:24  jmlarsen
00085  * Don't threshold to zero
00086  *
00087  * Revision 1.21  2006/06/01 13:04:11  jmlarsen
00088  * Moved doxygen marker to exclude documentation of #define's
00089  *
00090  * Revision 1.20  2006/04/06 08:29:06  jmlarsen
00091  * Minor doc change
00092  *
00093  * Revision 1.19  2006/03/24 13:54:27  jmlarsen
00094  * Use different smoothing default values depending on type of frame (flat or science)
00095  *
00096  * Revision 1.18  2006/03/09 10:51:14  jmlarsen
00097  * Changed order of for loops
00098  *
00099  * Revision 1.17  2006/03/03 13:54:11  jmlarsen
00100  * Changed syntax of check macro
00101  *
00102  * Revision 1.16  2006/02/28 09:15:22  jmlarsen
00103  * Minor update
00104  *
00105  * Revision 1.15  2006/02/17 10:12:32  jmlarsen
00106  * Removed mixed code-declarations
00107  *
00108  * Revision 1.14  2006/02/15 13:19:15  jmlarsen
00109  * Reduced source code max. line length
00110  *
00111  * Revision 1.13  2005/12/19 16:17:55  jmlarsen
00112  * Replaced bool -> int
00113  *
00114  */
00115 
00116 #ifdef HAVE_CONFIG_H
00117 #  include <config.h>
00118 #endif
00119 
00120 /*----------------------------------------------------------------------------*/
00127 /*----------------------------------------------------------------------------*/
00128 
00129 
00130 #include <uves_backsub.h>
00131 
00132 #include <uves_parameters.h>
00133 #include <uves_pfits.h>
00134 #include <uves_dump.h>
00135 #include <uves_utils.h>
00136 #include <uves_utils_wrappers.h>
00137 #include <uves_utils_cpl.h>
00138 #include <uves_error.h>
00139 #include <uves_msg.h>
00140 #include <uves.h>
00141 
00142 #include <irplib_access.h>
00143 #include <cpl.h>
00144 
00145 #include <stdbool.h>
00146 #include <float.h>
00147 /*-----------------------------------------------------------------------------
00148                             Functions prototypes
00149  -----------------------------------------------------------------------------*/
00150 static int first_order(const polynomial *order_locations, int nx);
00151 static int last_order (const polynomial *order_locations, int nx, int ny);
00152 static cpl_error_code lower_to_average(cpl_image *image, int RADX, int RADY);
00153 static double sample_background(const cpl_image *image, int x0, double y_0,
00154                 int radius_x, int radius_y, int nx, int ny,
00155                 background_measure_method BM_METHOD);
00156 static cpl_error_code subtract_background(cpl_image *image, cpl_image *background_im, 
00157                       const polynomial *background_pol);
00158 
00159 /*-----------------------------------------------------------------------------
00160                                 Defines
00161  -----------------------------------------------------------------------------*/
00162 
00163 /* This is sort of ugly, because we fine tune parameters depending on
00164    wavelength and also different for masterflat/science exposures.
00165    A 'perfect' background subtraction algorithm should not need to
00166    know about its context.
00167 */ 
00168 
00169 #define BACKSUB_FLAT_SMOOTHX_BLUE (25.0/4096)
00170 #define BACKSUB_FLAT_SMOOTHX_RED  (50.0/4096)
00171 #define BACKSUB_FLAT_SMOOTHY_BLUE (100.0/2048)
00172 #define BACKSUB_FLAT_SMOOTHY_RED  (300.0/2048)
00173 
00174 #define BACKSUB_SCI_SMOOTHX_BLUE  (300.0/4096)
00175 #define BACKSUB_SCI_SMOOTHX_RED   (300.0/4096)
00176 #define BACKSUB_SCI_SMOOTHY_BLUE  (200.0/2048)
00177 #define BACKSUB_SCI_SMOOTHY_RED   (500.0/2048)
00178 
00179 #define BACKSUB_SMOOTHY_WLEN 859.9
00180 
00183 /*-----------------------------------------------------------------------------
00184                             Implementation
00185  -----------------------------------------------------------------------------*/
00186 
00187 /*----------------------------------------------------------------------------*/
00195 /*----------------------------------------------------------------------------*/
00196 
00197 cpl_parameterlist *
00198 uves_backsub_define_parameters(void)
00199 {
00200     const char *name = "";
00201     char *full_name = NULL;
00202     cpl_parameterlist *parameters = NULL;
00203     cpl_parameter *p = NULL;
00204 
00205     parameters = cpl_parameterlist_new();
00206     
00207     //
00208     name = "mmethod";
00209     full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00210     
00211     uves_parameter_new_enum(p, full_name,
00212                    CPL_TYPE_STRING,
00213                    "Background measuring method. If equal to 'median' "
00214                    "the background is sampled using the median of a subwindow. "
00215                    "If 'minimum', the subwindow minimum value is used. "
00216                    "If 'no', no background subtraction is done.",
00217                    UVES_BACKSUB_ID,
00218                    "median",                        /* Default */
00219                    3,                               /* Number of options */
00220                    "median", "minimum", "no");      /* List of options */
00221     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00222     cpl_parameterlist_append(parameters, p);
00223     cpl_free(full_name);
00224 
00225     //
00226     name = "npoints";
00227     full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00228     uves_parameter_new_range(p, full_name,
00229                  CPL_TYPE_INT,
00230                  "This is the number of columns in interorder space "
00231                  "used to sample the background.",
00232                  UVES_BACKSUB_ID,
00233                  82, 0, INT_MAX);
00234     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00235     cpl_parameterlist_append(parameters, p);
00236     cpl_free(full_name);
00237     
00238     //
00239     name = "radiusy";
00240     full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00241     uves_parameter_new_range(p, full_name,
00242                 CPL_TYPE_INT,
00243                 "The height (in pixels) of the background sampling "
00244                 "window is (2*radiusy + 1). "
00245                 "This parameter is not corrected for binning.",
00246                 UVES_BACKSUB_ID,
00247                 2, 0, INT_MAX);
00248     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00249     cpl_parameterlist_append(parameters, p);
00250     cpl_free(full_name);
00251     
00252     //
00253     name = "sdegree";
00254     full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00255     uves_parameter_new_range(p, full_name,
00256                  CPL_TYPE_INT,
00257                  "Degree of interpolating splines. Currently "
00258                  "only degree = 1 is supported",
00259                  UVES_BACKSUB_ID,
00260                  1, 0, INT_MAX);
00261     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00262     cpl_parameterlist_append(parameters, p);
00263     cpl_free(full_name);
00264 
00265     //
00266     name = "smoothx";
00267     full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00268     uves_parameter_new_range(p, full_name,
00269                  CPL_TYPE_DOUBLE,
00270                  "If spline interpolation is used to measure the background, "
00271                  "the x-radius of the post-smoothing window is "
00272                  "(smoothx * image_width). Here, 'image_width' is the image "
00273                  "width after binning. If negative, the default values are used: "
00274                  make_str(BACKSUB_FLAT_SMOOTHX_BLUE) " for blue flat-field frames, "
00275                  make_str(BACKSUB_FLAT_SMOOTHX_RED) " for red flat-field frames, "
00276                  make_str(BACKSUB_SCI_SMOOTHX_BLUE) " for blue science frames and "
00277                  make_str(BACKSUB_SCI_SMOOTHX_RED) " for red science frames.",
00278                  UVES_BACKSUB_ID,
00279                  -1.0, -DBL_MAX, DBL_MAX);
00280     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00281     cpl_parameterlist_append(parameters, p);
00282     cpl_free(full_name);
00283     
00284     //
00285     name = "smoothy";
00286     full_name = uves_sprintf("%s.%s", UVES_BACKSUB_ID, name);
00287     uves_parameter_new_range(p, full_name,
00288                  CPL_TYPE_DOUBLE,
00289                  "If spline interpolation is used to measure the "
00290                  "background, the y-radius of the post-smoothing "
00291                  "window is (smoothy * image_height). Here, "
00292                  "'image_height' is the image height after binning. "
00293                  "If negative, the default values are used: "
00294                  make_str(BACKSUB_FLAT_SMOOTHY_BLUE) " for blue flat-field frames, "
00295                  make_str(BACKSUB_FLAT_SMOOTHY_RED) " for red flat-field frames, "
00296                  make_str(BACKSUB_SCI_SMOOTHY_BLUE) " for blue science frames and "
00297                  make_str(BACKSUB_SCI_SMOOTHY_RED) " for red science frames.",
00298                  UVES_BACKSUB_ID,
00299                  -1.0, -DBL_MAX, DBL_MAX);
00300     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00301     cpl_parameterlist_append(parameters, p);
00302     cpl_free(full_name);
00303 
00304     if (cpl_error_get_code() != CPL_ERROR_NONE)
00305     {
00306         cpl_msg_error(__func__, "Creation of spline background subtraction "
00307               "parameters failed: '%s'", cpl_error_get_where());
00308         cpl_parameterlist_delete(parameters);
00309         return NULL;
00310     }
00311     else
00312     {
00313         return parameters;
00314     }
00315 }
00316 
00317 /*----------------------------------------------------------------------------*/
00327 /*----------------------------------------------------------------------------*/
00328 background_measure_method
00329 uves_get_bm_method(const cpl_parameterlist *parameters, const char *context, 
00330            const char *subcontext)
00331 {
00332     const char *bm = "";
00333     background_measure_method result = 0;
00334 
00335     check( uves_get_parameter(parameters, context, subcontext, "mmethod", CPL_TYPE_STRING, &bm),
00336        "Could not read parameter");
00337     
00338     if      (strcmp(bm, "median" ) == 0) result = BM_MEDIAN;
00339     else if (strcmp(bm, "minimum") == 0) result = BM_MINIMUM;
00340     else if (strcmp(bm, "no"     ) == 0) result = BM_NO;
00341     else
00342     {
00343         /* Impossible */ assure(false, CPL_ERROR_ILLEGAL_INPUT, 
00344                     "No such background measuring method: '%s'", bm);
00345     }
00346     
00347   cleanup:
00348     return result;
00349 }
00350     
00351 /*----------------------------------------------------------------------------*/
00385 /*----------------------------------------------------------------------------*/
00386 
00387 cpl_error_code
00388 uves_backsub_spline(cpl_image *image, const uves_propertylist *raw_header,
00389             const cpl_table *ordertable, const polynomial *order_locations,
00390             const cpl_parameterlist *parameters, const char *context, 
00391             enum uves_chip chip,
00392             bool flat_field,
00393             cpl_image **background)
00394 {
00395     /* Recipe parameters */
00396     background_measure_method BM_METHOD;
00397     int npoints;
00398     int radius_y;
00399     int sdegree;
00400     double SMOOTHX;
00401     double SMOOTHY;
00402     
00403     /* Local variables */
00404     int nx, ny;
00405     int x, y;
00406     int stepx;
00407     int radius_x;
00408     int smooth_x, smooth_y;        /* Window radius in pixels */
00409     
00410     passure( image != NULL, " ");
00411     passure( raw_header != NULL, " ");
00412     passure( ordertable != NULL, " ");
00413     passure( order_locations != NULL, " ");
00414     passure( parameters != NULL, " ");
00415     passure( context != NULL, " ");
00416     passure( uves_polynomial_get_dimension(order_locations) == 2, 
00417          "%d", uves_polynomial_get_dimension(order_locations));
00418     passure( background != NULL, " ");
00419 
00420     /* Get recipe parameters */
00421     check( BM_METHOD = uves_get_bm_method(parameters, context, UVES_BACKSUB_ID),
00422        "Error getting background measuring method");
00423     
00424     check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00425                   "npoints", CPL_TYPE_INT   , &npoints) , "Could not read parameter");
00426     check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00427                   "radiusy", CPL_TYPE_INT   , &radius_y), "Could not read parameter");
00428     check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00429                   "sdegree", CPL_TYPE_INT   , &sdegree) , "Could not read parameter");
00430     check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00431                   "smoothx", CPL_TYPE_DOUBLE, &SMOOTHX) , "Could not read parameter");
00432     check( uves_get_parameter(parameters, context, UVES_BACKSUB_ID,
00433                   "smoothy", CPL_TYPE_DOUBLE, &SMOOTHY) , "Could not read parameter");
00434 
00435    
00436     /* Get other parameters */
00437     nx = cpl_image_get_size_x(image);
00438     ny = cpl_image_get_size_y(image);
00439 
00440 
00441     if (BM_METHOD == BM_NO)
00442     {
00443         uves_msg("Skipping background subtraction");
00444 
00445         /* Calculate a zero-background */
00446         check( *background = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE),
00447            "Error allocating image");
00448     }
00449     else {
00450     /* If negative, set default values for smoothx, smoothy */
00451     if (SMOOTHX < 0)
00452         {
00453         if (chip == UVES_CHIP_BLUE)
00454             {
00455             SMOOTHX = (flat_field) ? 
00456                 BACKSUB_FLAT_SMOOTHX_BLUE : BACKSUB_SCI_SMOOTHX_BLUE;
00457             }
00458         else
00459             {
00460             SMOOTHX = (flat_field) ? 
00461                 BACKSUB_FLAT_SMOOTHX_RED : BACKSUB_SCI_SMOOTHX_RED;
00462             }
00463         }
00464     if (SMOOTHY < 0)
00465         {
00466         double wlen;
00467         
00468         /* Read wavelength from raw header */
00469         
00470         check( wlen = uves_pfits_get_gratwlen(raw_header, chip),
00471                "Error reading central wavelength");
00472         
00473         /* The criterion is not if the chip is BLUE/RED,
00474            but whether the wlen is < 860A */
00475         if (wlen < BACKSUB_SMOOTHY_WLEN)
00476             {
00477             SMOOTHY = (flat_field) ? 
00478                 BACKSUB_FLAT_SMOOTHY_BLUE : BACKSUB_SCI_SMOOTHY_BLUE;
00479             }
00480         else
00481             {
00482             SMOOTHY = (flat_field) ? 
00483                 BACKSUB_FLAT_SMOOTHY_RED : BACKSUB_SCI_SMOOTHY_RED;
00484             }
00485         }
00486     
00487     assure( 0 < SMOOTHX, CPL_ERROR_ILLEGAL_INPUT, "Illegal smoothx factor: %e", SMOOTHX);
00488     assure( 0 < SMOOTHY, CPL_ERROR_ILLEGAL_INPUT, "Illegal smoothy factor: %e", SMOOTHY);
00489     
00490     smooth_x = uves_round_double(SMOOTHX * nx - 0.5);
00491     smooth_y = uves_round_double(SMOOTHY * ny - 0.5);
00492     
00493     assure( 0 < npoints, CPL_ERROR_ILLEGAL_INPUT, 
00494         "Illegal number of sample points: %d", npoints);
00495     stepx = nx / npoints;
00496     assure( 0 < stepx, CPL_ERROR_ILLEGAL_INPUT, "Illegal step size: %d", stepx);
00497     radius_x = stepx/2;
00498     assure( 0 < radius_x, CPL_ERROR_ILLEGAL_INPUT, "Illegal x sample radius: %d", radius_x);
00499     assure( 0 < radius_y, CPL_ERROR_ILLEGAL_INPUT, "Illegal y sample radius: %d", radius_y);
00500     assure( 0 < smooth_x, CPL_ERROR_ILLEGAL_INPUT, "Illegal x sample smooth: %d", smooth_x);
00501     assure( 0 < smooth_y, CPL_ERROR_ILLEGAL_INPUT, "Illegal y sample smooth: %d", smooth_y);
00502     assure( sdegree == 1, CPL_ERROR_UNSUPPORTED_MODE, 
00503         "Spline degree must be 1. It is %d", sdegree);
00504     
00505     uves_msg("Sample window (pixels): radx, rady = %d, %d", radius_x, radius_y);
00506     
00507     check( *background = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE), 
00508            "Error allocating background image");
00509     
00510     /* Process */
00511     
00512     for (x = stepx; x <= nx; x += stepx) {
00513         int order, minorder, maxorder;
00514         /* Find min. and max. order where background positions are inside image  */
00515             
00516         minorder = cpl_table_get_column_min(ordertable, "Order");
00517             
00518         /* If outside image, move to inside image */
00519         while (uves_round_double(
00520                uves_polynomial_evaluate_2d(order_locations, x + radius_x, minorder - 0.5)
00521                ) - radius_y < 1 ||
00522            uves_round_double(
00523                uves_polynomial_evaluate_2d(order_locations, x - radius_x, minorder - 0.5))
00524            - radius_y < 1  )
00525         {
00526             int sign;
00527 
00528             for (sign = -1; sign <= 1; sign += 2)
00529             {
00530                 assure( 
00531                 uves_polynomial_evaluate_2d(order_locations,
00532                                 x + sign*radius_x, minorder+1 - 0.5) >
00533                 uves_polynomial_evaluate_2d(order_locations,
00534                                 x + sign*radius_x, minorder   - 0.5),
00535                 CPL_ERROR_ILLEGAL_INPUT,
00536                 "Order polynomial is not well-formed: "
00537                 "p(%d, %f) = %e; p(%d, %f) = %e",
00538                 x + sign*radius_x, minorder+1 - 0.5, uves_polynomial_evaluate_2d(
00539                     order_locations, x + sign*radius_x, minorder+1 - 0.5
00540                     ),
00541                 x + sign*radius_x, minorder   - 0.5, uves_polynomial_evaluate_2d(
00542                     order_locations, x + sign*radius_x, minorder   - 0.5)
00543                 );
00544             }
00545 
00546             minorder += 1;
00547         }
00548             
00549         maxorder = cpl_table_get_column_max(ordertable, "Order");
00550         
00551         /* If outside image, move to inside image */
00552         while (uves_round_double( 
00553                uves_polynomial_evaluate_2d(order_locations, x + radius_x, maxorder + 0.5)
00554                ) + radius_y > ny ||
00555            uves_round_double( 
00556                uves_polynomial_evaluate_2d(order_locations, x - radius_x, maxorder + 0.5)
00557                ) + radius_y > ny  ) {
00558         int sign;
00559         for (sign = -1; sign <= 1; sign += 2)
00560             {
00561             assure( 
00562                 uves_polynomial_evaluate_2d(
00563                 order_locations, x + sign*radius_x, maxorder-1 - 0.5) <
00564                 uves_polynomial_evaluate_2d(order_locations, 
00565                             x + sign*radius_x, maxorder   - 0.5), 
00566                 CPL_ERROR_ILLEGAL_INPUT,
00567                 "Order polynomial is not well-formed: "
00568                 "p(%d, %f) = %e; p(%d, %f) = %e",
00569                 x + sign*radius_x, maxorder-1 - 0.5, uves_polynomial_evaluate_2d(
00570                 order_locations, x + sign*radius_x, maxorder-1 - 0.5),
00571                 x + sign*radius_x, maxorder   - 0.5, uves_polynomial_evaluate_2d(
00572                 order_locations, x + sign*radius_x, maxorder   - 0.5)
00573                 );
00574             }
00575                 
00576         maxorder -= 1;
00577         }
00578         
00579             /* Move to min. order inside image */
00580             while (uves_round_double(uves_polynomial_evaluate_2d(
00581                                          order_locations, x + radius_x, minorder - 1.5)
00582                        ) - radius_y >= 1 &&
00583                    uves_round_double(uves_polynomial_evaluate_2d(
00584                                          order_locations, x - radius_x, minorder - 1.5)
00585                        ) - radius_y >= 1  )
00586                 {
00587                     int sign;
00588                     for (sign = -1; sign <= 1; sign += 2)
00589                         {
00590                             assure( 
00591                                 uves_polynomial_evaluate_2d(
00592                                     order_locations, x + sign*radius_x, minorder-1 - 1.5) <
00593                                 uves_polynomial_evaluate_2d(
00594                                     order_locations, x + sign*radius_x, minorder   - 1.5), 
00595                                 CPL_ERROR_ILLEGAL_INPUT,
00596                                 "Order polynomial is not well-formed: "
00597                                 "p(%d, %f) = %e ; p(%d, %f) = %e",
00598                                 x + sign*radius_x, minorder-1 - 1.5, 
00599                                 uves_polynomial_evaluate_2d(
00600                                     order_locations, x + sign*radius_x, minorder-1 - 1.5),
00601                                 x + sign*radius_x, minorder   - 1.5,
00602                                 uves_polynomial_evaluate_2d(
00603                                     order_locations, x + sign*radius_x, minorder   - 1.5));
00604                         }
00605                     
00606                     minorder -= 1;
00607                 }
00608             
00609             /* Move to max. order inside image */
00610             while (uves_round_double( uves_polynomial_evaluate_2d(
00611                                           order_locations, x + radius_x, maxorder + 1.5)
00612                        ) + radius_y <= ny &&
00613                    uves_round_double( uves_polynomial_evaluate_2d(
00614                                           order_locations, x - radius_x, maxorder + 1.5)
00615                        ) + radius_y <= ny  ) {
00616                 int sign;
00617                 for (sign = -1; sign <= 1; sign += 2)
00618                     {
00619                         assure( 
00620                             uves_polynomial_evaluate_2d(
00621                                 order_locations, x + sign*radius_x, maxorder+1 + 1.5)
00622                             >
00623                             uves_polynomial_evaluate_2d(
00624                                 order_locations, x + sign*radius_x, maxorder   + 1.5),
00625                             CPL_ERROR_ILLEGAL_INPUT,
00626                             "Order polynomial is not well-formed: "
00627                             "p(%d, %f) = %e ; p(%d, %f) = %e",
00628                             x + sign*radius_x, maxorder+1 + 1.5,
00629                             uves_polynomial_evaluate_2d(
00630                                 order_locations, x + sign*radius_x, maxorder+1 + 1.5),
00631                             x + sign*radius_x, maxorder   + 1.5,
00632                             uves_polynomial_evaluate_2d(
00633                                 order_locations, x + sign*radius_x, maxorder   + 1.5));
00634                     }
00635                 
00636                 maxorder += 1;
00637             }
00638         
00639         uves_msg_debug("(x, order) = (%d, %f - %f)  ", x, minorder-.5, maxorder+.5);
00640         
00641         for (order = minorder; order <= maxorder; order++) {
00642         int ylo, yhi;
00643         double backlo, backhi;
00644             
00645         /* Sample background above and below order using the median of a window
00646          * with size (2*radius_x + 1) * (2*radius_y + 1)
00647          */
00648             
00649         ylo = uves_round_double( 
00650             uves_polynomial_evaluate_2d(order_locations, x, order - 0.5) );
00651         yhi = uves_round_double(
00652             uves_polynomial_evaluate_2d(order_locations, x, order + 0.5) );
00653 
00654         /* Fail cleanly if input polynomial is corrupted */
00655         assure( yhi > ylo, CPL_ERROR_ILLEGAL_INPUT,
00656             "Order polynomial is not well-formed: "
00657             "p(%d, %f) = %d ; p(%d, %f) = %d",
00658             x, order - 0.5, ylo,
00659             x, order + 0.5, yhi);
00660             
00661             
00662         check( backlo = 
00663                sample_background(
00664                image, x, ylo, radius_x, radius_y, nx, ny, BM_METHOD),
00665                "Error sampling background level");
00666             
00667         check( backhi = sample_background(
00668                image, x, yhi, radius_x, radius_y, nx, ny, BM_METHOD),
00669                "Error sampling background level");
00670                    
00671         uves_msg_debug("Background sample at (x, y, order) = (%d, %d, %f) = %f",
00672                    x, ylo, order-0.5, backlo);
00673         uves_msg_debug("Background sample at (x, y, order) = (%d, %d, %f) = %f",
00674                    x, yhi, order+0.5, backhi);
00675     
00676         /* Extrapolate (linearly, or constant if MIDAS) if first order */
00677         if (order == minorder) {
00678             for (y = 1; y <= ylo; y++) {
00679             double back = backlo + (backhi - backlo)*(y - ylo)/(yhi - ylo);
00680             cpl_image_set(*background, x, y, back);
00681 
00682                         cpl_image_set(*background, x, y, back);
00683             }
00684         }
00685             
00686         /* Make a linear interpolation (1-degree, no-smooth spline) from ylo to yhi */
00687         for (y = ylo; y <= yhi; y++) {
00688             double back;
00689             back = backlo + (backhi - backlo) * (y - ylo) / (yhi - ylo);
00690             /* We know that yhi > ylo */
00691             cpl_image_set(*background, x, y, back);
00692         }
00693             
00694         /* Extrapolate (linearly, or constant if MIDAS) if last order */
00695         if (order == maxorder) {
00696             for (y = yhi; y <= ny; y++) {
00697             double back;
00698             back = backlo + (backhi - backlo) * (y - ylo) / (yhi - ylo);
00699 
00700                         cpl_image_set(*background, x, y, back);
00701                     }
00702         }
00703         }
00704     }/* For column...  */
00705 
00706     /* Now interpolate between columns */
00707     for (y = 1; y <= ny; y++) {
00708         int col;
00709         for (col = stepx; col+stepx <= nx; col += stepx) {
00710         int pis_rejected; /* Not used, all pixels read are good; they've just been set */
00711             
00712         double backlo, backhi;
00713             
00714         /* Read this and next column */
00715         backlo = cpl_image_get(*background, col      , y, &pis_rejected);
00716         backhi = cpl_image_get(*background, col+stepx, y, &pis_rejected);
00717         
00718         /* Extrapolate (linear) before first column */
00719         if (col == stepx)
00720             for (x = 1; x <= col; x++)
00721             {
00722                 double back = backlo + (backhi - backlo) * (x - col) / stepx;
00723                 cpl_image_set(*background, x, y, back);
00724             }
00725             
00726         /* Interpolate between columns */
00727         for (x = col; x <= col + stepx; x++)
00728             {
00729             double back = backlo + (backhi - backlo) * (x - col) / stepx;
00730             cpl_image_set(*background, x, y, back);
00731             }
00732 
00733         /* Extrapolate (linear) after last column */
00734         if (col+stepx+stepx > nx)
00735             for (x = col; x <= nx; x++)
00736             {
00737                 double back = backlo + (backhi - backlo) * (x - col) / stepx;
00738                 cpl_image_set(*background, x, y, back);
00739             }
00740         }
00741     }
00742 
00743     /* All pixels in background image have been set.
00744      * Smooth background. 
00745      */
00746 
00747     uves_msg("Smoothing window (pixels): smox, smoy = %d, %d", smooth_x, smooth_y);
00748 
00749     check( uves_filter_image_average(*background, smooth_x, smooth_y), 
00750            "Error applying average filter to background image");
00751 
00752     uves_msg("Subtracting background image");
00753 
00754     check( subtract_background(image, *background, NULL),
00755            "Error subtracting background image");
00756     } /* BM_METHOD was not 'no' */
00757 
00758   cleanup:
00759     return cpl_error_get_code();
00760 }
00761 
00762 /*----------------------------------------------------------------------------*/
00807 /*----------------------------------------------------------------------------*/
00808 cpl_error_code
00809 uves_backsub_poly(cpl_image *image,
00810           const cpl_table *orders, const polynomial *order_locations, 
00811           background_measure_method BM_METHOD,
00812           int NPOINTS,
00813           int radius_y,
00814           int DEGX, 
00815           int DEGY,
00816           double KAPPA)
00817 {
00818     cpl_table  *t          = NULL;
00819     polynomial *background = NULL;
00820     int nx, ny;
00821     int stepx, stepy;                   /* Step size */
00822     int radius_x;                       /* Sample window x-radius */
00823     double mse, rmse;                   /* mse, rms of fit */
00824     int total_clipped = 0;
00825     
00826     if (BM_METHOD == BM_NO)
00827     {
00828         uves_msg("Skipping background subtraction");
00829     }
00830     else
00831     {
00832         passure( image != NULL, " ");
00833         passure( orders == NULL || order_locations == NULL, " ");
00834         
00835         nx = cpl_image_get_size_x(image);
00836         ny = cpl_image_get_size_y(image);
00837         
00838         assure( NPOINTS < nx, CPL_ERROR_ILLEGAL_INPUT,
00839             "Number of sample columns (%d) larger than image width (%d pixels)", 
00840             NPOINTS, nx);
00841         
00842         stepx = nx/NPOINTS;
00843         stepy = ny/NPOINTS;
00844 
00845         radius_x = stepx/2;
00846     
00847         /* First sample background */
00848         if (orders != NULL)
00849         {
00850             /* Using the order table */
00851 
00852             int x, ordersrow, row;
00853         
00854             /* Check input */
00855             passure( cpl_table_has_column(orders, "Slope"), " ");
00856             passure( cpl_table_has_column(orders, "Intersept"), " ");
00857 
00858             passure( cpl_table_get_column_type(orders, "Slope") == CPL_TYPE_DOUBLE,
00859                  "%s", 
00860                  uves_tostring_cpl_type(cpl_table_get_column_type(orders, "Slope")));
00861         
00862             passure( cpl_table_get_column_type(orders, "Intersept") == CPL_TYPE_DOUBLE,
00863                  "%s",
00864                  uves_tostring_cpl_type(cpl_table_get_column_type(orders, "Slope")));
00865         
00866             /* This check is computationally cheap because 
00867                there are never very many order lines */
00868             passure( uves_table_is_sorted_double(orders, "Intersept", false), " ");
00869         
00870             /* Need at least two lines to identify inter-order region */
00871             assure ( cpl_table_get_nrow(orders) >= 2, CPL_ERROR_ILLEGAL_INPUT, 
00872                  "Only %d line(s) in order table", cpl_table_get_nrow(orders));
00873         
00874             t = cpl_table_new( (nx/stepx + 1)*(cpl_table_get_nrow(orders) + 1) );
00875             cpl_table_new_column(t, "X", CPL_TYPE_INT);
00876             cpl_table_new_column(t, "Y", CPL_TYPE_INT);
00877             cpl_table_new_column(t, "Z", CPL_TYPE_DOUBLE);
00878         
00879             row = 0;
00880             for (ordersrow = -1; ordersrow < cpl_table_get_nrow(orders); ordersrow++)
00881             {
00882                 double slope, intersept;
00883             
00884                 /* Sample positions between this and the next orderline */
00885             
00886                 /* Lowest and highest orders are special cases */
00887                 if (ordersrow == -1)
00888                 {
00889                     slope     = cpl_table_get_double(
00890                     orders, "Slope"    , 0, NULL);
00891 
00892                     /* Interorder space below lowest order line is at: 
00893                        intersept0 - (intersept1-intersept0)/2 */
00894                     intersept =    
00895                     0.5*cpl_table_get_double(orders, "Intersept", 0, NULL) -
00896                     0.5*cpl_table_get_double(orders, "Intersept", 1, NULL) ;
00897                 }
00898                 else if (ordersrow == cpl_table_get_nrow(orders) - 1)
00899                 {
00900                     slope     = cpl_table_get_double(
00901                     orders, "Slope"    , ordersrow, NULL);
00902                     
00903                     /* Interorder space above highest order line is at:
00904                        intersept(N) + (intersept(N)-intersept(N-1))/2 */
00905                     intersept =    
00906                     0.5*cpl_table_get_double(
00907                         orders, "Intersept", ordersrow, NULL) -
00908                     0.5*cpl_table_get_double(
00909                         orders, "Intersept", ordersrow-1, NULL) ;
00910                 }
00911                 else   /* The most common case */
00912                 {
00913                     slope = 
00914                     (cpl_table_get_double(
00915                         orders, "Slope", ordersrow  , NULL) +
00916                      cpl_table_get_double(
00917                          orders, "Slope", ordersrow+1, NULL) ) / 2;
00918                     
00919                     intersept      = 
00920                     (cpl_table_get_double(
00921                         orders, "Intersept", ordersrow  , NULL) +
00922                      cpl_table_get_double(
00923                          orders, "Intersept", ordersrow+1, NULL) ) / 2;
00924                 }
00925             
00926                 /* Sample the interorder space */
00927                 for (x = 1 + stepx/2; x <= nx; x += stepx)
00928                 {
00929                     int y = uves_round_double(intersept + slope * x);
00930                 
00931                     if (1 <= y && y <= ny)
00932                     {
00933                         double z;
00934                     
00935                         check( z = sample_background(
00936                                image, 
00937                                x, y,
00938                                radius_x, radius_y,
00939                                nx, ny,
00940                                BM_METHOD),
00941                            "Error sampling background "
00942                            "(x, y) = (%d, %d)", x, y);
00943 
00944                         cpl_table_set_int   (t, "X" , row, x);
00945                         cpl_table_set_int   (t, "Y" , row, y);
00946                         cpl_table_set_double(t, "Z" , row, z);
00947                         row++;
00948                     }
00949                 }
00950             } /* for ordersrow... */
00951         
00952             cpl_table_set_size(t, row);
00953 
00954         }/* if  orders != NULL */
00955         
00956         else if (order_locations != NULL)
00957         {
00958             /* Sample background using the polynomial */
00959 
00960             int x, minorder, maxorder, order;
00961             int row;        /* Pointing to row in temporary table */
00962         
00963             /* Check input */
00964             assure( uves_polynomial_get_dimension(order_locations) == 2, 
00965                 CPL_ERROR_ILLEGAL_INPUT,
00966                 "Order location polynomial must be 2d. It is %d!", 
00967                 uves_polynomial_get_dimension(order_locations));
00968             
00969             check(( minorder = first_order(order_locations, nx),
00970                 maxorder = last_order(order_locations, nx, ny)),
00971                "Error getting min. and max. order numbers");
00972 
00973             t = cpl_table_new( (nx/stepx + 1) * (maxorder-minorder+1));
00974             cpl_table_new_column(t, "X", CPL_TYPE_INT);
00975             cpl_table_new_column(t, "Y", CPL_TYPE_INT);
00976             cpl_table_new_column(t, "Z", CPL_TYPE_DOUBLE);
00977         
00978             row = 0;
00979             for (order = minorder; order <= maxorder; order++) {
00980             /* Sample the interorder space from (minorder+0.5) to (maxorder+0.5) */
00981             for (x = 1+stepx/2; x <= nx; x += stepx) {
00982                 int y = uves_round_double(
00983                 uves_polynomial_evaluate_2d(order_locations, x, order + 0.5));
00984                 
00985                 if (1 <= y && y <= ny) {
00986                 double z;
00987                 
00988                 check( z = sample_background(image, 
00989                                  x, y,
00990                                  radius_x, radius_y,
00991                                  nx, ny,
00992                                  BM_METHOD),
00993                        "Error sampling background (x, order) = (%d, %d+0.5)",
00994                        x, order);
00995                 
00996                 cpl_table_set_int   (t, "X" , row, x);
00997                 cpl_table_set_int   (t, "Y" , row, y);
00998                 cpl_table_set_double(t, "Z" , row, z);
00999                 row++;
01000                 }
01001             }
01002             }
01003             
01004             cpl_table_set_size(t, row);
01005         }
01006         else
01007         { 
01008             /* Grid sampling (order positions unknown) */
01009             int x, y, row;
01010         
01011             t = cpl_table_new((nx/stepx + 1) * (ny/stepy + 1));
01012             cpl_table_new_column(t, "X" , CPL_TYPE_INT);
01013             cpl_table_new_column(t, "Y" , CPL_TYPE_INT);
01014             cpl_table_new_column(t, "Z" , CPL_TYPE_DOUBLE);
01015         
01016             row = 0;
01017             for (y = 1 + stepy/2; y <= ny; y += stepy) 
01018             {
01019                 for (x = 1+stepx/2; x <= nx; x += stepx) 
01020                 {
01021                     double z;
01022                 
01023                     check( z = sample_background(image, 
01024                                  x, y,
01025                                  radius_x, radius_y,
01026                                  nx, ny,
01027                                  BM_METHOD),
01028                        "Error sampling background (x, y) = (%d, %d)", x, y);
01029                 
01030                     cpl_table_set_int   (t, "X" , row, x);
01031                     cpl_table_set_int   (t, "Y" , row, y);
01032                     cpl_table_set_double(t, "Z" , row, z);
01033                     row++;
01034                 }
01035             }
01036             cpl_table_set_size(t, row);
01037         }
01038         
01039         /* Sampling done. Fit poly. */
01040 
01041         total_clipped = 0;
01042         {
01043         int n_clipped;
01044         do {
01045             assure( cpl_table_get_nrow(t) > (DEGX + 1)*(DEGY + 1), 
01046                 CPL_ERROR_ILLEGAL_OUTPUT,
01047                 "Too few sample points available (%d point(s)) to make the fit "
01048                 "(more than %d points needed). "
01049                 "Increase number of sample points or increase kappa",
01050                 cpl_table_get_nrow(t),  (DEGX + 1)*(DEGY + 1));
01051         
01052             /* Fit, calculate Zfit */
01053             uves_polynomial_delete(&background);
01054             check( background = uves_polynomial_regression_2d(
01055                    t, "X", "Y", "Z", NULL,
01056                    DEGX, DEGY, "Zfit", NULL, NULL, &mse,
01057                    NULL, NULL, -1, -1),
01058                "Error fitting polynomial");
01059         
01060             /* Residual := Z - Zfit */
01061             cpl_table_duplicate_column(t, "Residual", t, "Z");
01062             cpl_table_subtract_columns(t, "Residual", "Zfit");
01063         
01064             /* Compute residuals w.r.t. median of Z 
01065                (i.e. subtract median(residual) from all residuals),
01066                then get stdev based on this new mean/median value.
01067                This is to make kappa sigma clipping more robust */
01068 
01069             cpl_table_subtract_scalar(t, "Residual", 
01070                           cpl_table_get_column_median(t, "Residual"));
01071             rmse = cpl_table_get_column_stdev(t, "Residual");
01072 
01073             /* One-sided kappa-sigma clipping */
01074             if (KAPPA > 0)
01075             {
01076                 check( n_clipped = uves_select_table_rows(
01077                        t,  "Residual", CPL_GREATER_THAN, KAPPA * rmse),
01078                    "Error selecting rows");
01079             }
01080             else
01081             {
01082                 n_clipped = 0;
01083             }
01084             
01085             total_clipped += n_clipped;
01086         
01087             uves_msg_debug("RMS = %f. %d of %d points rejected in kappa-sigma clipping",
01088                    rmse, n_clipped, cpl_table_get_nrow(t));
01089             
01090             uves_table_erase_selected_dfs02356(t);
01091 
01092             if (n_clipped > 0)
01093             {
01094                 cpl_table_erase_column(t, "Zfit");
01095                 cpl_table_erase_column(t, "Residual");
01096             }
01097         
01098         } while (n_clipped > 0);
01099         }
01100 
01101         /* Try to do some quality checking of the background subtraction.
01102            The number of rejected points (the signal) is often around 10-20 %  */
01103         {
01104         double percentage = 
01105             100.0 * ( (double)total_clipped ) / (total_clipped + cpl_table_get_nrow(t));
01106         
01107         if (KAPPA > 0) {
01108             uves_msg("%d of %d points (%.2f %%) were rejected in "
01109                  "kappa-sigma clipping. RMS = %.2f ADU", 
01110                  total_clipped,
01111                  cpl_table_get_nrow(t) + total_clipped,
01112                  percentage,
01113                  sqrt(mse));
01114         }
01115         
01116         /* For grid sampling: */
01117         if (orders == NULL && order_locations == NULL) 
01118             {
01119             if (total_clipped == 0)
01120                 {
01121                 uves_msg_warning("No points rejected during background "
01122                          "estimation. Background subtraction is "
01123                          "uncertain. Try to decrease KAPPA "
01124                          "(current value is %f)", KAPPA);
01125                 }
01126             if (percentage > 40)
01127                 {
01128                 uves_msg_warning("%f %% of the sample points were "
01129                          "rejected during "
01130                          "background estimation", percentage);
01131                 }
01132             }
01133         }
01134         
01135         check( subtract_background(image, NULL, background),
01136            "Error subtracting background polynomial");
01137     } /* BM_METHOD wasn't 'no' */
01138     
01139   cleanup:
01140     uves_free_table(&t);
01141     uves_polynomial_delete(&background);
01142     
01143     return cpl_error_get_code();
01144 }
01145 
01146 /*----------------------------------------------------------------------------*/
01160 /*----------------------------------------------------------------------------*/
01161 /* Recipe parameter creation code for this function
01162 / * Backsmoothx, Backsmoothy * /
01163     uves_parameter_new_range(p, uves_orderpos.preproc.backsmoothx,
01164                 CPL_TYPE_INT,
01165                 "Radius of window used for average filtering in the "
01166                 "background subtraction (mode=smooth) step",
01167                 uves_orderpos.preproc,
01168                 5, 0, INT_MAX);
01169     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "backsmoothx");
01170     cpl_parameterlist_append(recipe->parameters, p);
01171     
01172     uves_parameter_new_range(p, uves_orderpos.preproc.backsmoothy,
01173                 CPL_TYPE_INT,
01174                 "Radius of window used for average filtering in the "
01175                 "background subtraction (mode=smooth) step",
01176                 uves_orderpos.preproc,
01177                 30, 0, INT_MAX);
01178     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "backsmoothy");
01179     cpl_parameterlist_append(recipe->parameters, p);
01180 
01181 / * Backsmoothiter * /
01182     uves_parameter_new_range(p, uves_orderpos.preproc.backsmoothiter,
01183                 CPL_TYPE_INT,
01184                 "Number of iterations when estimating the background "
01185                 "(mode=smooth)",
01186                 uves_orderpos.preproc,
01187                 10, 1, INT_MAX);
01188     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "backsmoothiter");
01189     cpl_parameterlist_append(recipe->parameters, p);
01190 */
01191 cpl_error_code
01192 uves_backsub_smooth(cpl_image *image, int RADX, int RADY, int ITER)
01193 {
01194     cpl_image  *background  = NULL;
01195     int i;
01196     
01197     assure( RADX >= 0 && RADY >= 0, CPL_ERROR_ILLEGAL_INPUT,
01198         "Negative radius ((%d)x(%d))", RADX, RADY);
01199     assure( ITER >= 1, CPL_ERROR_ILLEGAL_INPUT, 
01200         "Non-positive number of iterations (%d)", ITER);
01201     
01202     /* First estimate background */
01203     background = cpl_image_duplicate(image);
01204     
01205     for (i = 0; i < ITER; i++) {
01206     uves_msg_progress(i, ITER, "..");
01207     uves_msg("i = %d", i);
01208     check( lower_to_average(background,
01209                 RADX, RADY), "Error smoothing image");
01210     }
01211     
01212     /* Then subtract background */
01213     check( cpl_image_subtract(image, background), "Could not subtract background image");
01214     
01215   cleanup:
01216     uves_free_image(&background);
01217 
01218     return cpl_error_get_code();
01219 }
01220 
01221 /*----------------------------------------------------------------------------*/
01240 /*----------------------------------------------------------------------------*/
01241 
01242 static double
01243 sample_background(const cpl_image *image, int x0, double y_0,
01244           int radius_x, int radius_y, int nx, int ny,
01245           background_measure_method BM_METHOD)
01246 {
01247     double result = 0;
01248     /* Use a table to calculate the median. Invalid rows are ignored */
01249     cpl_table *temp = NULL;
01250     bool found_good = false;
01251     int row;
01252     int x, y;
01253 
01254     check( 
01255     (temp = cpl_table_new( (2*radius_x + 1) * (2*radius_y + 1) ),
01256      row = 0,
01257      cpl_table_new_column(temp, "Flux", CPL_TYPE_DOUBLE)),
01258     "Error allocating table");
01259 
01260     for(y = y_0 - radius_y; y <= y_0 + radius_y; y++)
01261     {
01262         for (x = x0 - radius_x; x <= x0 + radius_x; x++)
01263         {
01264             if (1 <= x && x <= nx &&
01265             1 <= y && y <= ny)
01266             {
01267                 int pis_rejected;
01268                 double flux = cpl_image_get(image, x, y, &pis_rejected);
01269                 if( !pis_rejected )
01270                 {
01271                     cpl_table_set(temp, "Flux", row, flux);
01272                     found_good = true;
01273                 }
01274                 else
01275                 {
01276                     cpl_table_set_invalid(temp, "Flux", row);
01277                 }
01278             }
01279             else
01280             {
01281                 cpl_table_set_invalid(temp, "Flux", row);
01282             }
01283             
01284             row++;
01285         }
01286     }
01287 
01288     assure( found_good, CPL_ERROR_ILLEGAL_INPUT, "No valid pixels in sample window");
01289 
01290     if (BM_METHOD == BM_MEDIAN)
01291     {
01292         result = cpl_table_get_column_median(temp, "Flux");
01293     }
01294     else if (BM_METHOD == BM_MINIMUM)
01295     {
01296         result = cpl_table_get_column_min(temp, "Flux");
01297     }
01298     else
01299     {
01300         assure( false, CPL_ERROR_UNSUPPORTED_MODE,
01301             "Unsupported background sample method: %d", BM_METHOD);
01302     }
01303 
01304   cleanup:
01305     uves_free_table(&temp);
01306     return result;
01307 }
01308 
01309 /*----------------------------------------------------------------------------*/
01318 /*----------------------------------------------------------------------------*/
01319 static int
01320 first_order(const polynomial *order_locations, int nx)
01321 {
01322     int result;
01323     
01324     result = 0;
01325     while (uves_polynomial_evaluate_2d(order_locations, 1 , result + 0.5) < 1 ||
01326        uves_polynomial_evaluate_2d(order_locations, nx, result + 0.5) < 1 )
01327     {
01328         result++;
01329     }
01330 
01331     while (uves_polynomial_evaluate_2d(order_locations, 1 , result - 0.5) >= 1 ||
01332        uves_polynomial_evaluate_2d(order_locations, nx, result - 0.5) >= 1 )
01333     {
01334         result -= 1;
01335         
01336         /* Fail cleanly even if 'order_locations' is corrupted */
01337         assure( result > -100000, 
01338             CPL_ERROR_CONTINUE,
01339             "Invalid polynomial: p(x=1, order=%d) = %f  p(x=%d, order=%d) = %f",
01340             result, uves_polynomial_evaluate_2d(order_locations, 1.0, result),
01341             nx, result, uves_polynomial_evaluate_2d(order_locations, nx, result));
01342     }
01343     
01344   cleanup:
01345     return result;
01346 }
01347 
01348 
01349 /*----------------------------------------------------------------------------*/
01359 /*----------------------------------------------------------------------------*/
01360 static int
01361 last_order(const polynomial *order_locations, int nx, int ny)
01362 {
01363     int result;
01364     
01365     result = 0;
01366     while (uves_polynomial_evaluate_2d(order_locations, 1 , result - 0.5) > ny ||
01367        uves_polynomial_evaluate_2d(order_locations, nx, result - 0.5) > ny )
01368     {
01369         result--;
01370     }
01371 
01372     while (uves_polynomial_evaluate_2d(order_locations, 1 , result + 1.5) <= ny ||
01373        uves_polynomial_evaluate_2d(order_locations, nx, result + 1.5) <= ny )
01374     {
01375         result += 1;
01376         
01377         /* Fail cleanly even if 'order_locations' is corrupted */
01378         assure( result < 100000, 
01379             CPL_ERROR_CONTINUE,
01380             "Invalid polynomial: p(x=1, order=%d) = %f  p(x=%d, order=%d) = %f",
01381             result, uves_polynomial_evaluate_2d(order_locations, 1.0, result),
01382             nx, result, uves_polynomial_evaluate_2d(order_locations, nx, result));
01383     }
01384     
01385   cleanup:
01386     return result;
01387 }
01388 
01389 /*----------------------------------------------------------------------------*/
01401 /*----------------------------------------------------------------------------*/
01402 static cpl_error_code
01403 lower_to_average(cpl_image *image, int RADX, int RADY)
01404 {
01405     cpl_image  *average = NULL;
01406     double *image_data = NULL;
01407     double *average_data = NULL;
01408     int nx, ny;
01409     int x, y;
01410     
01411     passure( image != NULL, "Null image");
01412     nx = cpl_image_get_size_x(image);
01413     ny = cpl_image_get_size_y(image);
01414     
01415     /* Create smoothed image */
01416     uves_msg("Filtering...");
01417     check( average    = cpl_image_duplicate(image), "Error copying image");
01418     check( uves_filter_image_average(average, RADX, RADY), "Error applying average filter");
01419     uves_msg("done");
01420     
01421     image_data   = irplib_image_get_data(image);
01422     average_data = irplib_image_get_data(average);
01423     uves_msg("Lowering...");
01424     for (y = 0; y < ny; y++)
01425     {
01426         for (x = 0; x < nx; x++)
01427         {
01428             if (image_data[x + y*nx] > average_data[x + y*nx]) 
01429             {
01430                 image_data[x + y*nx] = average_data[x + y*nx];
01431             }
01432         }
01433     }
01434     uves_msg("done");
01435     
01436   cleanup:
01437     uves_free_image(&average);
01438     
01439     return cpl_error_get_code();
01440 }
01441 
01442 /*----------------------------------------------------------------------------*/
01454 /*----------------------------------------------------------------------------*/
01455     
01456 static cpl_error_code
01457 subtract_background(cpl_image *image, cpl_image *background_im, 
01458             const polynomial *background_pol)
01459 {
01460     int nx, ny;
01461     int x, y;
01462 
01463     double *image_data;
01464     double *background_data = NULL;
01465 
01466     passure(image != NULL, " ");
01467     /* Exactly one of 'background_im' and 'background_pol' must be non-NULL */
01468     passure((background_im == NULL) != (background_pol == NULL), " ");
01469 
01470     /* For efficiency, don't call cpl_image_get() */
01471     assure(cpl_image_count_rejected(image) == 0, 
01472        CPL_ERROR_UNSUPPORTED_MODE, "Input image contains bad pixels");
01473     assure(cpl_image_get_type(image) == CPL_TYPE_DOUBLE,
01474        CPL_ERROR_UNSUPPORTED_MODE, 
01475        "Input image is of type %s. double expected", 
01476        uves_tostring_cpl_type(cpl_image_get_type(image)));
01477 
01478     if (background_im != NULL)
01479     {
01480         assure(cpl_image_count_rejected(background_im) == 0, 
01481            CPL_ERROR_UNSUPPORTED_MODE, "Background image contains bad pixels");
01482         assure(cpl_image_get_type(background_im) == CPL_TYPE_DOUBLE, 
01483            CPL_ERROR_UNSUPPORTED_MODE, 
01484            "Background image is of type %s. double expected", 
01485            uves_tostring_cpl_type(cpl_image_get_type(background_im)));
01486     }
01487 
01488     image_data = irplib_image_get_data_double(image);
01489     if (background_im != NULL)
01490     {
01491         background_data = irplib_image_get_data_double(background_im);
01492     }
01493 
01494     nx = cpl_image_get_size_x(image);
01495     ny = cpl_image_get_size_y(image);
01496 
01497     for (y = 1; y <= ny; y++)
01498     {
01499         for (x = 1; x <= nx; x++)
01500         {
01501             double back;
01502             double flux, new_flux;
01503             
01504             if (background_im != NULL)
01505             {
01506                 /* Slow:  back = cpl_image_get(background_im, x, y, &pis_rejected); */
01507                 back = background_data[(x-1) + (y-1) * nx]; 
01508             }
01509             else
01510             {
01511                 /* Evaluate at (x,y) */
01512                 back = uves_polynomial_evaluate_2d(background_pol, 
01513                                    x,
01514                                    y);
01515             }
01516             
01517             /* Slow: flux = cpl_image_get(image, x, y, &pis_rejected);  */
01518             flux = image_data[(x-1) + (y-1) * nx];
01519             
01520 /* Exclude these sanity checks for backwards compatibility */
01521 #if 0
01522             /* Make sure the estimated background is between zero and flux-value */
01523             if (back < 0)
01524             {
01525                 back = 0.0;
01526             }
01527             if (back > flux)
01528             {
01529                 back = flux;
01530             }
01531             
01532             /* Then subtract the background.
01533              * Pixel flux may be negative. Make sure the result is non-negative.
01534              */
01535                     new_flux = uves_max_double(0, flux - back);
01536 #else
01537             new_flux = flux-back;            
01538 #endif
01539             
01540             /* Slow: cpl_image_set(image, x, y, new_flux); */
01541             image_data[(x-1) + (y-1) * nx] = new_flux; 
01542             
01543             if (background_im != NULL)
01544             {
01545                 /* Slow: cpl_image_set(background_im, x, y, flux - new_flux); */
01546                 background_data[(x-1) + (y-1) * nx] = 
01547                 uves_max_double(0, flux - new_flux);
01548             }
01549         }
01550     }/* for each pixel... */
01551     
01552   cleanup:
01553     return cpl_error_get_code();
01554 }

Generated on Tue Jun 19 14:39:15 2007 for UVES Pipeline Reference Manual by  doxygen 1.4.6