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

Generated on 8 Mar 2011 for UVES Pipeline Reference Manual by  doxygen 1.6.1