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

Generated on 28 Feb 2012 for UVES Pipeline Reference Manual by  doxygen 1.6.1