uves_rebin.c

00001 /*                                                                              *
00002  *   This file is part of the ESO UVES Pipeline                                 *
00003  *   Copyright (C) 2004,2005 European Southern Observatory                      *
00004  *                                                                              *
00005  *   This library is free software; you can redistribute it and/or modify       *
00006  *   it under the terms of the GNU General Public License as published by       *
00007  *   the Free Software Foundation; either version 2 of the License, or          *
00008  *   (at your option) any later version.                                        *
00009  *                                                                              *
00010  *   This program is distributed in the hope that it will be useful,            *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of             *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
00013  *   GNU General Public License for more details.                               *
00014  *                                                                              *
00015  *   You should have received a copy of the GNU General Public License          *
00016  *   along with this program; if not, write to the Free Software                *
00017  *   Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA       *
00018  *                                                                              */
00019 
00020 /*
00021  * $Author: amodigli $
00022  * $Date: 2007/06/06 08:17:33 $
00023  * $Revision: 1.38 $
00024  * $Name: uves-3_3_1 $
00025  * $Log: uves_rebin.c,v $
00026  * Revision 1.38  2007/06/06 08:17:33  amodigli
00027  * replace tab with 4 spaces
00028  *
00029  * Revision 1.37  2007/05/22 11:38:13  jmlarsen
00030  * Removed MIDAS flag for good
00031  *
00032  * Revision 1.36  2007/05/07 10:18:27  jmlarsen
00033  * Added option to enforce positive resulting values (useful for error bars)
00034  *
00035  * Revision 1.35  2007/05/03 15:21:10  jmlarsen
00036  * Decreased output message verbosity
00037  *
00038  * Revision 1.34  2007/04/27 07:21:15  jmlarsen
00039  * Show warning but don't fail if dispersion is ill-formed
00040  *
00041  * Revision 1.33  2007/04/24 12:50:29  jmlarsen
00042  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00043  *
00044  * Revision 1.32  2007/01/17 13:28:07  jmlarsen
00045  * Shortened line
00046  *
00047  * Revision 1.31  2006/11/15 15:02:15  jmlarsen
00048  * Implemented const safe workarounds for CPL functions
00049  *
00050  * Revision 1.29  2006/11/15 14:04:08  jmlarsen
00051  * Removed non-const version of parameterlist_get_first/last/next which is 
00052  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
00053  *
00054  * Revision 1.28  2006/11/13 14:23:55  jmlarsen
00055  * Removed workarounds for CPL const bugs
00056  *
00057  * Revision 1.27  2006/11/06 15:19:41  jmlarsen
00058  * Removed unused include directives
00059  *
00060  * Revision 1.26  2006/10/31 09:15:34  jmlarsen
00061  * Fixed buffer overrun
00062  *
00063  * Revision 1.25  2006/10/10 11:28:19  jmlarsen
00064  * Renamed line table columns to match MIDAS
00065  *
00066  * Revision 1.24  2006/10/10 11:20:11  jmlarsen
00067  * Renamed line table columns to match MIDAS
00068  *
00069  * Revision 1.23  2006/10/02 08:37:35  jmlarsen
00070  * Do not avoid reserving space for bad pixels near edge of orders, like MIDAS
00071  *
00072  * Revision 1.22  2006/09/20 12:53:57  jmlarsen
00073  * Replaced stringcat functions with uves_sprintf()
00074  *
00075  * Revision 1.21  2006/09/11 13:58:41  jmlarsen
00076  * Changed CRVAL1 from 1 to 0 in rebinned image
00077  *
00078  * Revision 1.20  2006/08/17 14:40:06  jmlarsen
00079  * Added missing documentation
00080  *
00081  * Revision 1.19  2006/08/17 13:56:53  jmlarsen
00082  * Reduced max line length
00083  *
00084  * Revision 1.18  2006/08/17 09:17:39  jmlarsen
00085  * Removed CPL2 code
00086  *
00087  * Revision 1.17  2006/08/10 10:52:58  jmlarsen
00088  * Removed workaround for cpl_image_get_bpm
00089  *
00090  * Revision 1.16  2006/08/07 11:35:35  jmlarsen
00091  * Disabled parameter environment variable mode
00092  *
00093  * Revision 1.15  2006/06/01 14:43:17  jmlarsen
00094  * Added missing documentation
00095  *
00096  * Revision 1.14  2006/05/08 11:36:10  jmlarsen
00097  * Fixed normalization bug for bins at edge of order
00098  *
00099  * Revision 1.13  2006/05/05 13:57:01  jmlarsen
00100  * Implemented more careful flux interpolation
00101  *
00102  * Revision 1.12  2006/04/06 08:39:36  jmlarsen
00103  * Added void to function prototype
00104  *
00105  * Revision 1.11  2006/03/03 13:54:11  jmlarsen
00106  * Changed syntax of check macro
00107  *
00108  * Revision 1.10  2006/02/03 07:46:30  jmlarsen
00109  * Moved recipe implementations to ./uves directory
00110  *
00111  * Revision 1.9  2006/01/31 08:24:29  jmlarsen
00112  * Wrapper for cpl_image_get_bpm
00113  *
00114  * Revision 1.8  2006/01/25 16:13:20  jmlarsen
00115  * Changed interface of gauss.fitting routine
00116  *
00117  * Revision 1.7  2005/12/19 16:17:56  jmlarsen
00118  * Replaced bool -> int
00119  *
00120  * Revision 1.6  2005/12/16 14:22:23  jmlarsen
00121  * Removed midas test data; Added sof files
00122  *
00123  * Revision 1.5  2005/12/02 10:41:49  jmlarsen
00124  * Minor update
00125  *
00126  * Revision 1.4  2005/11/28 08:18:12  jmlarsen
00127  * Replaced cpl_mask_get_bpm -> cpl_image_get_bpm
00128  *
00129  * Revision 1.3  2005/11/24 15:09:06  jmlarsen
00130  * Implemented 2d extraction/rebinning/merging
00131  *
00132  * Revision 1.2  2005/11/24 11:54:46  jmlarsen
00133  * Added support for CPL 3 interface
00134  *
00135  * Revision 1.1  2005/11/11 13:18:54  jmlarsen
00136  * Reorganized code, renamed source files
00137  *
00138  */
00139 
00140 #ifdef HAVE_CONFIG_H
00141 #  include <config.h>
00142 #endif
00143 
00144 /*----------------------------------------------------------------------------*/
00151 /*----------------------------------------------------------------------------*/
00154 /*-----------------------------------------------------------------------------
00155                                 Includes
00156  -----------------------------------------------------------------------------*/
00157 
00158 #include <uves_rebin.h>
00159 
00160 #include <uves_parameters.h>
00161 #include <uves.h>
00162 #include <uves_pfits.h>
00163 #include <uves_dump.h>
00164 #include <uves_utils.h>
00165 #include <uves_utils_wrappers.h>
00166 #include <uves_wavecal_utils.h>
00167 #include <uves_error.h>
00168 
00169 #include <irplib_access.h>
00170 #include <cpl.h>
00171 
00172 /*-----------------------------------------------------------------------------
00173                             Functions prototypes
00174  -----------------------------------------------------------------------------*/
00175 inline static double
00176 integrate_flux(const double *spectrum_data,
00177            const cpl_binary *spectrum_bad,
00178            int spectrum_row,
00179            int nx,
00180            double x_min, double x_max,
00181                bool threshold_to_positive,
00182            bool *is_bad);
00183 
00184 /*-----------------------------------------------------------------------------
00185                             Implementation
00186  -----------------------------------------------------------------------------*/
00187 
00188 /*----------------------------------------------------------------------------*/
00196 /*----------------------------------------------------------------------------*/
00197 cpl_parameterlist *
00198 uves_rebin_define_parameters(void)
00199 {
00200     const char *name = "";
00201     char *full_name = NULL;
00202     cpl_parameter *p = NULL;
00203     cpl_parameterlist *parameters = NULL;
00204     
00205     parameters = cpl_parameterlist_new();
00206     
00207     {
00208     name = "wavestep";
00209     full_name = uves_sprintf("%s.%s", UVES_REBIN_ID, name);
00210     uves_parameter_new_value(p, full_name,
00211                  CPL_TYPE_DOUBLE,
00212                  "The bin size (in w.l.u.) in wavelength space. "
00213                  "If negative, a step size of "
00214                  "2/3 * ( average pixel size ) is used.",
00215                  UVES_REBIN_ID,
00216                  -1.0);
00217     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00218     cpl_parameterlist_append(parameters, p);
00219     cpl_free(full_name);
00220 
00221     name = "scale";
00222     full_name = uves_sprintf("%s.%s", UVES_REBIN_ID, name);
00223     uves_parameter_new_value(p, full_name,
00224                  CPL_TYPE_BOOL,
00225                  "Whether or not to multiply by the factor "
00226                  "dx/dlambda (pixels per wavelength) "
00227                  "during the rebinning. This option is disabled "
00228                  "as default in concordance with the "
00229                  "method used in the MIDAS pipeline. This "
00230                  "option should be set to true "
00231                  "to convert the observed flux (in pixel-space) "
00232                  "to a flux per wavelength (in "
00233                  "wavelength-space).",
00234                  UVES_REBIN_ID,
00235                  false);
00236     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00237     cpl_parameterlist_append(parameters, p);
00238     cpl_free(full_name);
00239     }
00240     
00241     if (cpl_error_get_code() != CPL_ERROR_NONE)
00242     {
00243         cpl_msg_error(__func__, "Creation of rebinning parameters failed: '%s'", 
00244               cpl_error_get_where());
00245         cpl_parameterlist_delete(parameters);
00246         return NULL;
00247     }
00248     else
00249     {
00250         return parameters;
00251     }
00252 }
00253 
00254 /*----------------------------------------------------------------------------*/
00299 /*----------------------------------------------------------------------------*/
00300 cpl_image *
00301 uves_rebin(const cpl_image *spectrum,
00302        const cpl_parameterlist *parameters, const char *context,
00303        const cpl_table *linetable, const polynomial *dispersion_relation, 
00304        int first_abs_order, int last_abs_order,
00305        int n_traces,
00306            bool threshold_to_positive,
00307        uves_propertylist **rebinned_header)
00308 {
00309     double wavestep;
00310     bool scale;
00311     cpl_image *rebinned       = NULL;   /* Result */
00312     double *rebinned_data     = NULL;
00313     cpl_mask *rebinned_badmap = NULL;   /* Map of unused bins */
00314     cpl_binary *rebinned_bad  = NULL;
00315 
00316     const double *spectrum_data     = NULL;   /* Direct pointers to input data */
00317 
00318     const cpl_mask *spectrum_badmap = NULL;
00319     const cpl_binary *spectrum_bad  = NULL;
00320 
00321     polynomial *disprel_1d    = NULL;   /* Dispersion relation for 1 order */
00322 
00323     int nx, ny, nlambda, norders;     /* Image dimensions */
00324     int order;
00325     bool warning_shown = false;
00326 
00327     passure( spectrum != NULL, " ");
00328     passure( dispersion_relation != NULL, " ");
00329     passure( rebinned_header != NULL, " ");
00330     
00331     assure( cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
00332         "Spectrum must have type double. It is '%s'",
00333         uves_tostring_cpl_type(cpl_image_get_type(spectrum)));
00334 
00335     /* Get recipe parameters */
00336     check( uves_get_parameter(parameters, context, UVES_REBIN_ID, "wavestep", 
00337                   CPL_TYPE_DOUBLE, &wavestep ), 
00338        "Could not read parameter");
00339     check( uves_get_parameter(parameters, context, UVES_REBIN_ID, "scale"   , 
00340                   CPL_TYPE_BOOL,   &scale    ), 
00341        "Could not read parameter");
00342     
00343     /* Set sample bin width if user didn't */
00344     if (wavestep < 0)
00345     {
00346         double pixelsize;
00347         check( pixelsize = cpl_table_get_column_mean(linetable, LINETAB_PIXELSIZE),
00348            "Error reading mean pixelsize");
00349         uves_msg_debug("Average pixelsize = %f w.l.u.", pixelsize);
00350 
00351         wavestep = pixelsize*2.0/3;
00352         }
00353     
00354     assure( wavestep > 0 , CPL_ERROR_ILLEGAL_INPUT, 
00355         "Illegal step size: %e wlu", wavestep);
00356     assure( n_traces >= 1, CPL_ERROR_ILLEGAL_INPUT,
00357         "Illegal number of traces: %d", n_traces);
00358 
00359     nx = cpl_image_get_size_x(spectrum);
00360     ny = cpl_image_get_size_y(spectrum);
00361     
00362     assure( ny % n_traces == 0, CPL_ERROR_INCOMPATIBLE_INPUT,
00363         "Spectrum image height (%d) is not a multiple of "
00364         "the number of traces (%d). Confused, bailing out",
00365         ny, n_traces);
00366     
00367     norders         = ny / n_traces;
00368 
00369     spectrum_data   = irplib_image_get_data_double_const(spectrum);
00370     spectrum_badmap = irplib_image_get_bpm_const(spectrum);
00371     spectrum_bad    = irplib_mask_get_data_const(spectrum_badmap);
00372 
00373     assure( norders >= 1, CPL_ERROR_ILLEGAL_INPUT, "Empty spectrum");
00374     assure( uves_round_double(fabs(first_abs_order - last_abs_order)) + 1 == norders, 
00375         CPL_ERROR_INCOMPATIBLE_INPUT,
00376         "Spectrum contains %d orders, but line table absolute "
00377         "order numbering is %d - %d",
00378         norders, first_abs_order, last_abs_order);
00379 
00380     check( *rebinned_header = uves_initialize_image_header(
00381            "Angstrom",                        /* CTYPE */
00382            (n_traces > 1) ? "PIXEL" : "ORDER",
00383            (scale) ? "FLUX PER WAVEL" : "FLUX", /* BUNIT */
00384            0.0, 1.0,                            /* CRVAL  */
00385            1.0, 1.0,                            /* CRPIX  */
00386            wavestep, 1.0),                      /* CDELT  */
00387        "Error setting up rebinned image header");
00388     /* CRVAL1 is set to zero. It should really be set to WSTARTi
00389        for the i'th row of the image (but obviously that's not possible).
00390        CRVAL1 is set to zero so that the true starting position of
00391        the i'th image row is simply calculated as  CRVAL1 + WSTARTi.
00392     */
00393        
00394     /* Get width of rebinned image and offsets for each order */
00395     nlambda = -1;                      /* Maximum number of bins in any order */
00396     for (order = 1; order <= norders; order++)
00397     {
00398         /*int trace = 1;*/
00399                           /* In the case where there are more traces in each order 
00400                  (2d extraction), just use the 1st trace to get the
00401                  wavelength range for the current order. The wavelength
00402                  range is the same for all traces. 
00403                   */
00404         /* int spectrum_row = (order - 1)*n_traces + trace; */
00405         int absorder = uves_absolute_order(first_abs_order, last_abs_order, order);
00406         double lambda_min, lambda_max;
00407         int nbins;
00408         
00409         int minx, maxx;  /* Range of good pixels in current order */
00410         
00411         minx = 1;  
00412 /* The following is commented out to get the same
00413    alignment as MIDAS
00414         while (minx <= nx && cpl_image_is_rejected(spectrum, minx, spectrum_row)) minx++;
00415 */
00416         maxx = nx; 
00417 /*        while (maxx >=  1 && cpl_image_is_rejected(spectrum, maxx, spectrum_row)) maxx--; */
00418         if ( minx > nx )
00419         {
00420             uves_msg_debug("Nothing extracted in order #%d", order);
00421             minx = maxx = nx/2;
00422         }
00423         
00424         lambda_min = uves_polynomial_evaluate_2d(
00425         dispersion_relation, minx - 0.5, absorder)/absorder;
00426         lambda_max = uves_polynomial_evaluate_2d(
00427         dispersion_relation, maxx + 0.5, absorder)/absorder;
00428         
00429         nbins =
00430         uves_round_double(lambda_max / wavestep) -
00431         uves_round_double(lambda_min / wavestep) + 1;
00432             
00433         nlambda = uves_max_int(nlambda, nbins);  
00434         
00435         check( uves_pfits_set_wstart(
00436                *rebinned_header, order,
00437                wavestep * uves_round_double(lambda_min / wavestep)),
00438            "Error writing adding WSTART keyword to header");
00439         
00440         check( uves_pfits_set_wend( 
00441                *rebinned_header, order,
00442                wavestep * uves_round_double(lambda_max / wavestep)),
00443            "Error writing adding WEND keyword to header");
00444         
00445         uves_msg_debug("Rebinning abs. order #%d. "
00446                "Range = %d - %d pix = %f - %f wlu, %d bins", 
00447                absorder,
00448                minx, maxx,
00449                lambda_min,
00450                lambda_max,
00451                nbins);
00452         }
00453     
00454     uves_msg_debug("Step size = %f wlu (%d orders x %d bins)", wavestep, norders, nlambda);
00455     
00456     /* Do the rebinning */
00457 
00458     /* Create empty image */
00459     check(( rebinned        = cpl_image_new(nlambda, norders*n_traces, CPL_TYPE_DOUBLE),
00460         rebinned_data   = irplib_image_get_data_double(rebinned),
00461         rebinned_badmap = irplib_image_get_bpm(rebinned),
00462         rebinned_bad    = irplib_mask_get_data(rebinned_badmap)),
00463        "Error allocating rebinned spectrum");
00464 
00465     /* Reject all pixels in output image,
00466        accept as values are computed */
00467     uves_image_reject_all(rebinned);
00468 
00469     for (order = 1; order <= norders; order++)
00470     {
00471         int absorder = uves_absolute_order(first_abs_order, last_abs_order, order);
00472         double lambda_start;        /* Center of first wavel. bin */
00473         int trace;
00474 
00475         /* uves_msg_progress(order - 1, norders, ".."); */
00476             
00477         check( lambda_start = uves_pfits_get_wstart(*rebinned_header, order),
00478            "Error reading product header");
00479 
00480         /* For efficiency, collapse 2d polynomial to 1d only once per order */
00481         uves_polynomial_delete(&disprel_1d);
00482         check( disprel_1d = uves_polynomial_collapse(dispersion_relation,
00483                              2,   /* Independent variable number */
00484                              absorder),
00485            "Error getting 1d dispersion relation for absolute order #%d", absorder);
00486         
00487         
00488         for (trace = 1; trace <= n_traces; trace++) 
00489         {
00490             int spectrum_row = (order - 1)*n_traces + trace;
00491             int bin;
00492 
00493             double x = 1;
00494             double x_min = 1;
00495             double x_max = 1;
00496             
00497             for (bin = 1; bin <= nlambda && x_min <= nx+0.5; bin++)
00498             {
00499                 double lambda = lambda_start + (bin-1) * wavestep;
00500                 /* Solve   f(x, m) = lambda*m  for x  */
00501                 int multiplicity = 1;
00502                 double x_guess = x;
00503                             
00504                             x     =  uves_polynomial_solve_1d(disprel_1d,
00505                                                               lambda * absorder,
00506                                                               x_guess, 
00507                                                               multiplicity);
00508                 
00509                             if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00510                                 uves_error_reset();
00511                                 if (!warning_shown) {
00512                                     uves_msg_warning("Could not invert dispersion relation at "
00513                                                      "order = %d, x = %f. This might be caused "
00514                                                      "by fitting a too high degree polynomial to "
00515                                                      "too few lines. Decrease dispersion "
00516                                                      "polynomial degree "
00517                                                      "or relax rejection parameters!",
00518                                                      absorder, x_guess);
00519                                     warning_shown = true;
00520                                 }
00521                                 x = x_guess;
00522                             }
00523                             else {
00524                                 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00525                                         cpl_error_get_code(),
00526                                         "Could not invert dispersion relation");
00527                             }
00528                             
00529                 x_guess = x;
00530                             x_min = uves_polynomial_solve_1d(
00531                                 disprel_1d,
00532                                 (lambda - 0.5*wavestep) * absorder,
00533                                 x_guess,
00534                                 multiplicity);
00535                             
00536                             if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00537                                 uves_error_reset();
00538                                 if (!warning_shown) {
00539                                     uves_msg_warning("Could not invert dispersion relation at "
00540                                                      "order = %d, x = %f. This might be caused "
00541                                                      "by fitting a too high degree polynomial to "
00542                                                      "too few lines. Decrease dispersion "
00543                                                      "polynomial degree "
00544                                                      "or relax rejection parameters!",
00545                                                      absorder, x_guess);
00546                                     warning_shown = true;
00547                                 }
00548                                 x_min = x_guess;
00549                             }
00550                             else {
00551                                 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00552                                         cpl_error_get_code(),
00553                                         "Could not invert dispersion relation");
00554                             }
00555                 
00556                             x_max = uves_polynomial_solve_1d(
00557                                 disprel_1d,
00558                                 (lambda + 0.5*wavestep) * absorder,
00559                                 x_guess,
00560                                 multiplicity);
00561                             
00562                             if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00563                                 uves_error_reset();
00564                                 if (!warning_shown) {
00565                                     uves_msg_warning("Could not invert dispersion relation at "
00566                                                      "order = %d, x = %f. This might be caused "
00567                                                      "by fitting a too high degree polynomial to "
00568                                                      "too few lines. Decrease dispersion "
00569                                                      "polynomial degree "
00570                                                      "or relax rejection parameters!",
00571                                                      absorder, x_guess);
00572                                     warning_shown = true;
00573                                 }
00574                                 x_max = x_guess;
00575                             }
00576                             else {
00577                                 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00578                                         cpl_error_get_code(),
00579                                         "Could not invert dispersion relation");
00580                             }
00581                             
00582                 /* If bin overlaps with source image */
00583                 if (uves_max_double(0.5, uves_min_double(nx+0.5, x_min)) <
00584                 uves_max_double(0.5, uves_min_double(nx+0.5, x_max)))
00585                 {
00586                     /* Measure average flux in range [xmin; xmax]:
00587 
00588                        flux_x  = [ int_xmin^xmax f(x) dx ] / (xmax-xmin)
00589                     */
00590 
00591                     bool pis_rejected;
00592                     double flux_x = integrate_flux(
00593                     spectrum_data,
00594                     spectrum_bad,
00595                     spectrum_row,
00596                     nx,
00597                     uves_max_double(0.5, uves_min_double(nx+0.5, x_min)),
00598                     uves_max_double(0.5, uves_min_double(nx+0.5, x_max)),
00599                                         threshold_to_positive,
00600                     &pis_rejected) 
00601                     / ( uves_max_double(0.5, uves_min_double(nx+0.5, x_max)) -
00602                         uves_max_double(0.5, uves_min_double(nx+0.5, x_min)) );
00603                     
00604                     if (!pis_rejected)
00605                     {
00606                         /* Convert to flux per wavelength if requested */
00607 
00608                         double dldx;
00609 
00610                         if (scale)
00611                         {
00612                             /*  For constant m: 
00613                              *   dl/dx = d(l*m)/dx / m
00614                              */    
00615                             dldx = uves_polynomial_derivative_2d(
00616                             dispersion_relation, x, absorder, 1)
00617                             / absorder;
00618                         }
00619                         else
00620                         {
00621                             dldx = 1;
00622                         }
00623                         
00624                         /* Density in wavelength space :   
00625                            N_lambda = N_x / |dl/dx|  */
00626                         rebinned_data[(bin-1) + 
00627                               (spectrum_row-1)*nlambda] = 
00628                         flux_x / fabs(dldx);
00629 
00630                         rebinned_bad[(bin-1) +
00631                              (spectrum_row-1)*nlambda] =
00632                         CPL_BINARY_0;
00633                     }
00634                     else
00635                     {
00636                         /* Interpolation interval had no good pixels */
00637                                             /* Pixel marked as bad */
00638                     }
00639                 }
00640                 else
00641                 {
00642                     /* Current wavelength bin is outside input image */
00643                                     /* Pixel marked as bad */
00644                 }
00645 
00646             }/* for each wavelength bin */
00647                 } /* for trace */
00648     } /* for order */
00649     /* Done rebinning */
00650 
00651   cleanup:
00652     uves_polynomial_delete(&disprel_1d);
00653     if (cpl_error_get_code() != CPL_ERROR_NONE)
00654     {
00655         uves_free_image(&rebinned);
00656         uves_free_propertylist(rebinned_header);
00657     }
00658 
00659     return rebinned;
00660 }
00661 
00662 /*----------------------------------------------------------------------------*/
00682 /*----------------------------------------------------------------------------*/
00683 inline static double
00684 integrate_flux(const double *spectrum_data,
00685            const cpl_binary *spectrum_bad,
00686            int spectrum_row,
00687            int nx,
00688            double x_min, double x_max,
00689                bool threshold_to_positive,
00690            bool *is_bad)
00691 {
00692     double sum = 0;           /* Result */
00693     double sum_interval = 0;  /* The length of the interval defined as the unioun
00694                  of good pixels */
00695     int x;
00696     int first_good = 0;
00697 
00698     *is_bad = true;           /* Until at least one good pixel found */
00699     
00700     for (x  = uves_min_int(nx, uves_max_int(1, uves_round_double(x_min)));
00701      /* The thresholding is necessary, or nx+0.5 would be rounded to nx+1
00702         which would cause a memory error */
00703      x <= uves_min_int(nx, uves_max_int(1, uves_round_double(x_max)));
00704      x++)
00705     {  
00706         if (spectrum_bad[(x-1) + (spectrum_row-1)*nx] == CPL_BINARY_0)
00707         /* If good pixel */
00708         {
00709             /* "Raw" flux of current bin */
00710             double flux = spectrum_data[(x-1) + (spectrum_row-1)*nx];
00711             double interval_length;
00712             double current_term;     /* Integral over current pixel */
00713             
00714             /* Use a piecewise linear profile like this
00715              *   
00716              *                   C
00717              *  interpolant  => / \
00718              *              ---/---\-- <= "raw" flux
00719              *              | /     \|
00720              *              |/       B
00721              *              A        |________ <= non-continous interpolation
00722              *             /|     
00723              *    __________|        
00724              *
00725              * The flux levels A and B are midway between the current
00726              * pixel flux and its neighbours' levels.
00727              * C is chosen so that the integrated flux over the current 
00728              * pixel equals the observed flux.
00729              *
00730              * This interpolant is continous as well as flux conserving.
00731              */
00732             
00733             int x_prev = x-1;
00734             int x_next = x+1;
00735             bool pis_rejected_prev = (x_prev < 1 ) || 
00736             (spectrum_bad[(x_prev-1) + (spectrum_row-1)*nx] == CPL_BINARY_1);
00737             bool pis_rejected_next = (nx < x_next) || 
00738             (spectrum_bad[(x_next-1) + (spectrum_row-1)*nx] == CPL_BINARY_1);
00739 
00740             if (!pis_rejected_prev && !pis_rejected_next)
00741             {
00742                 /* Define flux at pixel borders (A and B) as 
00743                    mean value of this and neighbouring pixel */
00744                 double flux_minus = 
00745                 (flux + spectrum_data[(x_prev-1) + (spectrum_row-1)*nx]) / 2.0;
00746                 double flux_plus  = 
00747                 (flux + spectrum_data[(x_next-1) + (spectrum_row-1)*nx]) / 2.0;
00748 
00749                 /* Define flux at pixel center, fluxc, so that the average flux is
00750                  * equal to the "raw" flux:
00751                  *
00752                  * ((flux- + fluxc)/2 + (flux+ + fluxc)/2) / 2 = flux
00753                  * =>  flux- + flux+ + 2fluxc = 4flux
00754                  * =>  fluxc = ...
00755                  */
00756                 double flux_center = 2*flux - (flux_minus + flux_plus) / 2.0;
00757                 
00758                 /* Line slopes */
00759                 double slope_minus = (flux_center - flux_minus )/ 0.5;
00760                 double slope_plus  = (flux_plus   - flux_center) / 0.5;
00761    
00762                 /*  Define overlap between [x_min; x_max] and
00763                 interval between A-C:  [x-0.5; x]) */
00764                 double lo1 = uves_max_double(x-0.5, uves_min_double(x, x_min));
00765                 double hi1 = uves_max_double(x-0.5, uves_min_double(x, x_max));
00766                 double dy1 = hi1-lo1;
00767 
00768                 /*  Define overlap between [x_min; x_max] and
00769                 interval between C-B:  [x; x+0.5]) */
00770                 double lo2 = uves_max_double(x, uves_min_double(x+0.5, x_min));
00771                 double hi2 = uves_max_double(x, uves_min_double(x+0.5, x_max));
00772                 double dy2 = hi2-lo2;
00773                             
00774                 /* Integrate interpolant over A-C and C-B */
00775                 /* A-C: interpolant(x) = flux_center + slope_minus *(x-x)
00776                    C-B: interpolant(x) = flux_center + slope_plus  *(x-x)
00777                 */
00778                 
00779                 current_term =
00780                 dy1 * (flux_center + slope_minus * ((lo1+hi1)/2.0 - x))
00781                 +
00782                 dy2 * (flux_center + slope_plus  * ((lo2+hi2)/2.0 - x));
00783                 
00784                 interval_length = dy1 + dy2;
00785                 
00786                 
00787             }/* Neighbours are good */
00788             else
00789             {
00790                 interval_length = 
00791                 uves_min_double(x_max, x+0.5) -
00792                 uves_max_double(x_min, x-0.5);
00793 
00794                 current_term = interval_length * flux;
00795             }
00796             
00797                     if (*is_bad) {
00798                         first_good = x;
00799                     }
00800             *is_bad = false;
00801             
00802             sum += current_term;
00803             sum_interval += interval_length;            
00804         }
00805     }
00806 
00807     if (sum_interval == 0)
00808     {
00809         *is_bad = true;
00810         return -1;
00811     }
00812     else
00813     {
00814         /* In case of bad pixels, rescale sum to full interval
00815            (If there are only good pixels then sum_interval == x_max-x_min)
00816         */
00817             double result =  sum*(x_max-x_min)/sum_interval;
00818 
00819             if (threshold_to_positive) {
00820                 if (result == 0) {
00821                     /* give up */
00822                     *is_bad = true;
00823                     return -1;
00824                 }
00825                 else {
00826                     result = fabs(result);
00827                 }
00828             }
00829 
00830             return result;
00831     }
00832 }
00833 

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