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

Generated on Thu Nov 15 14:32:27 2007 for UVES Pipeline Reference Manual by  doxygen 1.5.1