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

Generated on Fri Apr 18 14:11:41 2008 for UVES Pipeline Reference Manual by  doxygen 1.5.1