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/09/17 08:11:27 $
00023  * $Revision: 1.43 $
00024  * $Name: uves-3_4_5 $
00025  * $Log: uves_rebin.c,v $
00026  * Revision 1.43  2007/09/17 08:11:27  amodigli
00027  * added support CPL_TYPE_INT
00028  *
00029  * Revision 1.42  2007/08/21 13:08:26  jmlarsen
00030  * Removed irplib_access module, largely deprecated by CPL-4
00031  *
00032  * Revision 1.41  2007/06/21 07:29:11  jmlarsen
00033  * Fixed memory error
00034  *
00035  * Revision 1.40  2007/06/19 11:59:37  amodigli
00036  * added several uves_msg statements to check vs flames_obs_scired
00037  *
00038  * Revision 1.39  2007/06/18 15:35:27  jmlarsen
00039  * Added support for in/out image type=float (used in FLAMES)
00040  *
00041  * Revision 1.38  2007/06/06 08:17:33  amodigli
00042  * replace tab with 4 spaces
00043  *
00044  * Revision 1.37  2007/05/22 11:38:13  jmlarsen
00045  * Removed MIDAS flag for good
00046  *
00047  * Revision 1.36  2007/05/07 10:18:27  jmlarsen
00048  * Added option to enforce positive resulting values (useful for error bars)
00049  *
00050  * Revision 1.35  2007/05/03 15:21:10  jmlarsen
00051  * Decreased output message verbosity
00052  *
00053  * Revision 1.34  2007/04/27 07:21:15  jmlarsen
00054  * Show warning but don't fail if dispersion is ill-formed
00055  *
00056  * Revision 1.33  2007/04/24 12:50:29  jmlarsen
00057  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00058  *
00059  * Revision 1.32  2007/01/17 13:28:07  jmlarsen
00060  * Shortened line
00061  *
00062  * Revision 1.31  2006/11/15 15:02:15  jmlarsen
00063  * Implemented const safe workarounds for CPL functions
00064  *
00065  * Revision 1.29  2006/11/15 14:04:08  jmlarsen
00066  * Removed non-const version of parameterlist_get_first/last/next which is 
00067  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
00068  *
00069  * Revision 1.28  2006/11/13 14:23:55  jmlarsen
00070  * Removed workarounds for CPL const bugs
00071  *
00072  * Revision 1.27  2006/11/06 15:19:41  jmlarsen
00073  * Removed unused include directives
00074  *
00075  * Revision 1.26  2006/10/31 09:15:34  jmlarsen
00076  * Fixed buffer overrun
00077  *
00078  * Revision 1.25  2006/10/10 11:28:19  jmlarsen
00079  * Renamed line table columns to match MIDAS
00080  *
00081  * Revision 1.24  2006/10/10 11:20:11  jmlarsen
00082  * Renamed line table columns to match MIDAS
00083  *
00084  * Revision 1.23  2006/10/02 08:37:35  jmlarsen
00085  * Do not avoid reserving space for bad pixels near edge of orders, like MIDAS
00086  *
00087  * Revision 1.22  2006/09/20 12:53:57  jmlarsen
00088  * Replaced stringcat functions with uves_sprintf()
00089  *
00090  * Revision 1.21  2006/09/11 13:58:41  jmlarsen
00091  * Changed CRVAL1 from 1 to 0 in rebinned image
00092  *
00093  * Revision 1.20  2006/08/17 14:40:06  jmlarsen
00094  * Added missing documentation
00095  *
00096  * Revision 1.19  2006/08/17 13:56:53  jmlarsen
00097  * Reduced max line length
00098  *
00099  * Revision 1.18  2006/08/17 09:17:39  jmlarsen
00100  * Removed CPL2 code
00101  *
00102  * Revision 1.17  2006/08/10 10:52:58  jmlarsen
00103  * Removed workaround for cpl_image_get_bpm
00104  *
00105  * Revision 1.16  2006/08/07 11:35:35  jmlarsen
00106  * Disabled parameter environment variable mode
00107  *
00108  * Revision 1.15  2006/06/01 14:43:17  jmlarsen
00109  * Added missing documentation
00110  *
00111  * Revision 1.14  2006/05/08 11:36:10  jmlarsen
00112  * Fixed normalization bug for bins at edge of order
00113  *
00114  * Revision 1.13  2006/05/05 13:57:01  jmlarsen
00115  * Implemented more careful flux interpolation
00116  *
00117  * Revision 1.12  2006/04/06 08:39:36  jmlarsen
00118  * Added void to function prototype
00119  *
00120  * Revision 1.11  2006/03/03 13:54:11  jmlarsen
00121  * Changed syntax of check macro
00122  *
00123  * Revision 1.10  2006/02/03 07:46:30  jmlarsen
00124  * Moved recipe implementations to ./uves directory
00125  *
00126  * Revision 1.9  2006/01/31 08:24:29  jmlarsen
00127  * Wrapper for cpl_image_get_bpm
00128  *
00129  * Revision 1.8  2006/01/25 16:13:20  jmlarsen
00130  * Changed interface of gauss.fitting routine
00131  *
00132  * Revision 1.7  2005/12/19 16:17:56  jmlarsen
00133  * Replaced bool -> int
00134  *
00135  * Revision 1.6  2005/12/16 14:22:23  jmlarsen
00136  * Removed midas test data; Added sof files
00137  *
00138  * Revision 1.5  2005/12/02 10:41:49  jmlarsen
00139  * Minor update
00140  *
00141  * Revision 1.4  2005/11/28 08:18:12  jmlarsen
00142  * Replaced cpl_mask_get_bpm -> cpl_image_get_bpm
00143  *
00144  * Revision 1.3  2005/11/24 15:09:06  jmlarsen
00145  * Implemented 2d extraction/rebinning/merging
00146  *
00147  * Revision 1.2  2005/11/24 11:54:46  jmlarsen
00148  * Added support for CPL 3 interface
00149  *
00150  * Revision 1.1  2005/11/11 13:18:54  jmlarsen
00151  * Reorganized code, renamed source files
00152  *
00153  */
00154 
00155 #ifdef HAVE_CONFIG_H
00156 #  include <config.h>
00157 #endif
00158 
00159 /*----------------------------------------------------------------------------*/
00166 /*----------------------------------------------------------------------------*/
00169 /*-----------------------------------------------------------------------------
00170                                 Includes
00171  -----------------------------------------------------------------------------*/
00172 
00173 #include <uves_rebin.h>
00174 
00175 #include <uves_parameters.h>
00176 #include <uves.h>
00177 #include <uves_pfits.h>
00178 #include <uves_dump.h>
00179 #include <uves_utils.h>
00180 #include <uves_utils_wrappers.h>
00181 #include <uves_wavecal_utils.h>
00182 #include <uves_error.h>
00183 
00184 #include <cpl.h>
00185 
00186 /*-----------------------------------------------------------------------------
00187                             Functions prototypes
00188  -----------------------------------------------------------------------------*/
00189 inline static double
00190 integrate_flux(const double *spectrum_data_double,
00191                const float  *spectrum_data_float,
00192                const int  *spectrum_data_int,
00193                const cpl_binary *spectrum_bad,
00194                int spectrum_row,
00195                int nx,
00196                double x_min, double x_max,
00197                bool threshold_to_positive,
00198                bool *is_bad);
00199 
00200 /*-----------------------------------------------------------------------------
00201                             Implementation
00202  -----------------------------------------------------------------------------*/
00203 
00204 /*----------------------------------------------------------------------------*/
00212 /*----------------------------------------------------------------------------*/
00213 cpl_parameterlist *
00214 uves_rebin_define_parameters(void)
00215 {
00216     const char *name = "";
00217     char *full_name = NULL;
00218     cpl_parameter *p = NULL;
00219     cpl_parameterlist *parameters = NULL;
00220     
00221     parameters = cpl_parameterlist_new();
00222     
00223     {
00224     name = "wavestep";
00225     full_name = uves_sprintf("%s.%s", UVES_REBIN_ID, name);
00226     uves_parameter_new_value(p, full_name,
00227                  CPL_TYPE_DOUBLE,
00228                  "The bin size (in w.l.u.) in wavelength space. "
00229                  "If negative, a step size of "
00230                  "2/3 * ( average pixel size ) is used.",
00231                  UVES_REBIN_ID,
00232                  -1.0);
00233     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00234     cpl_parameterlist_append(parameters, p);
00235     cpl_free(full_name);
00236 
00237     name = "scale";
00238     full_name = uves_sprintf("%s.%s", UVES_REBIN_ID, name);
00239     uves_parameter_new_value(p, full_name,
00240                  CPL_TYPE_BOOL,
00241                  "Whether or not to multiply by the factor "
00242                  "dx/dlambda (pixels per wavelength) "
00243                  "during the rebinning. This option is disabled "
00244                  "as default in concordance with the "
00245                  "method used in the MIDAS pipeline. This "
00246                  "option should be set to true "
00247                  "to convert the observed flux (in pixel-space) "
00248                  "to a flux per wavelength (in "
00249                  "wavelength-space).",
00250                  UVES_REBIN_ID,
00251                  false);
00252     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00253     cpl_parameterlist_append(parameters, p);
00254     cpl_free(full_name);
00255     }
00256     
00257     if (cpl_error_get_code() != CPL_ERROR_NONE)
00258     {
00259         cpl_msg_error(__func__, "Creation of rebinning parameters failed: '%s'", 
00260               cpl_error_get_where());
00261         cpl_parameterlist_delete(parameters);
00262         return NULL;
00263     }
00264     else
00265     {
00266         return parameters;
00267     }
00268 }
00269 
00270 /*----------------------------------------------------------------------------*/
00315 /*----------------------------------------------------------------------------*/
00316 cpl_image *
00317 uves_rebin(const cpl_image *spectrum,
00318        const cpl_parameterlist *parameters, const char *context,
00319        const cpl_table *linetable, const polynomial *dispersion_relation, 
00320        int first_abs_order, int last_abs_order,
00321        int n_traces,
00322            bool threshold_to_positive,
00323        uves_propertylist **rebinned_header)
00324 {
00325     double wavestep;
00326     bool scale;
00327     cpl_image *rebinned       = NULL;   /* Result */
00328     double *rebinned_data_double = NULL;
00329     float  *rebinned_data_float  = NULL;
00330     int  *rebinned_data_int  = NULL;
00331     cpl_mask *rebinned_badmap = NULL;   /* Map of unused bins */
00332     cpl_binary *rebinned_bad  = NULL;
00333 
00334     const double *spectrum_data_double = NULL;   /* Direct pointer to input data */
00335     const float  *spectrum_data_float  = NULL;   /* unused pointer remains NULL */
00336     const int  *spectrum_data_int  = NULL;   /* unused pointer remains NULL */
00337 
00338     const cpl_mask *spectrum_badmap = NULL;
00339     const cpl_binary *spectrum_bad  = NULL;
00340 
00341     polynomial *disprel_1d    = NULL;   /* Dispersion relation for 1 order */
00342 
00343     int nx, ny, nlambda, norders;     /* Image dimensions */
00344     int order;
00345     bool warning_shown = false;
00346 
00347    
00348     passure( spectrum != NULL, " ");
00349     passure( dispersion_relation != NULL, " ");
00350     passure( rebinned_header != NULL, " ");
00351     
00352     assure( cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE ||
00353             cpl_image_get_type(spectrum) == CPL_TYPE_FLOAT ||
00354             cpl_image_get_type(spectrum) == CPL_TYPE_INT,
00355             CPL_ERROR_TYPE_MISMATCH,
00356         "Spectrum must have type double, float or int. It is '%s'",
00357         uves_tostring_cpl_type(cpl_image_get_type(spectrum)));
00358 
00359     /* Get recipe parameters */
00360     check( uves_get_parameter(parameters, context, UVES_REBIN_ID, "wavestep", 
00361                   CPL_TYPE_DOUBLE, &wavestep ), 
00362        "Could not read parameter");
00363     check( uves_get_parameter(parameters, context, UVES_REBIN_ID, "scale"   , 
00364                   CPL_TYPE_BOOL,   &scale    ), 
00365        "Could not read parameter");
00366     
00367 
00368     /* Set sample bin width if user didn't */
00369     if (wavestep < 0)
00370     {
00371         double pixelsize;
00372         check( pixelsize = cpl_table_get_column_mean(linetable, LINETAB_PIXELSIZE),
00373            "Error reading mean pixelsize");
00374         uves_msg_debug("Average pixelsize = %f w.l.u.", pixelsize);
00375 
00376         wavestep = pixelsize*2.0/3;
00377         }
00378     
00379     assure( wavestep > 0 , CPL_ERROR_ILLEGAL_INPUT, 
00380         "Illegal step size: %e wlu", wavestep);
00381     assure( n_traces >= 1, CPL_ERROR_ILLEGAL_INPUT,
00382         "Illegal number of traces: %d", n_traces);
00383 
00384     nx = cpl_image_get_size_x(spectrum);
00385     ny = cpl_image_get_size_y(spectrum);
00386     
00387     assure( ny % n_traces == 0, CPL_ERROR_INCOMPATIBLE_INPUT,
00388         "Spectrum image height (%d) is not a multiple of "
00389         "the number of traces (%d). Confused, bailing out",
00390         ny, n_traces);
00391     
00392     norders         = ny / n_traces;
00393 
00394 
00395     if (cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE) {
00396         spectrum_data_double   = cpl_image_get_data_double_const(spectrum);
00397     }
00398     else if (cpl_image_get_type(spectrum) == CPL_TYPE_FLOAT) {
00399         spectrum_data_float   = cpl_image_get_data_float_const(spectrum);
00400     } else {
00401         spectrum_data_int   = cpl_image_get_data_int_const(spectrum);
00402     }
00403     spectrum_badmap = cpl_image_get_bpm_const(spectrum);
00404     spectrum_bad    = cpl_mask_get_data_const(spectrum_badmap);
00405 
00406     assure( norders >= 1, CPL_ERROR_ILLEGAL_INPUT, "Empty spectrum");
00407     assure( uves_round_double(fabs(first_abs_order - last_abs_order)) + 1 == norders, 
00408         CPL_ERROR_INCOMPATIBLE_INPUT,
00409         "Spectrum contains %d orders, but line table absolute "
00410         "order numbering is %d - %d",
00411         norders, first_abs_order, last_abs_order);
00412 
00413 
00414     check( *rebinned_header = uves_initialize_image_header(
00415            "Angstrom",                        /* CTYPE */
00416            (n_traces > 1) ? "PIXEL" : "ORDER",
00417            (scale) ? "FLUX PER WAVEL" : "FLUX", /* BUNIT */
00418            0.0, 1.0,                            /* CRVAL  */
00419            1.0, 1.0,                            /* CRPIX  */
00420            wavestep, 1.0),                      /* CDELT  */
00421        "Error setting up rebinned image header");
00422     /* CRVAL1 is set to zero. It should really be set to WSTARTi
00423        for the i'th row of the image (but obviously that's not possible).
00424        CRVAL1 is set to zero so that the true starting position of
00425        the i'th image row is simply calculated as  CRVAL1 + WSTARTi.
00426     */
00427        
00428     /* Get width of rebinned image and offsets for each order */
00429     nlambda = -1;                      /* Maximum number of bins in any order */
00430 
00431     for (order = 1; order <= norders; order++)
00432     {
00433         /*int trace = 1;*/
00434                           /* In the case where there are more traces in each order 
00435                  (2d extraction), just use the 1st trace to get the
00436                  wavelength range for the current order. The wavelength
00437                  range is the same for all traces. 
00438                   */
00439         /* int spectrum_row = (order - 1)*n_traces + trace; */
00440         int absorder = uves_absolute_order(first_abs_order, last_abs_order, order);
00441         double lambda_min, lambda_max;
00442         int nbins;
00443         
00444         int minx, maxx;  /* Range of good pixels in current order */
00445         
00446         minx = 1;  
00447 /* The following is commented out to get the same
00448    alignment as MIDAS
00449         while (minx <= nx && cpl_image_is_rejected(spectrum, minx, spectrum_row)) minx++;
00450 */
00451         maxx = nx; 
00452 /*        while (maxx >=  1 && cpl_image_is_rejected(spectrum, maxx, spectrum_row)) maxx--; */
00453         if ( minx > nx )
00454         {
00455             uves_msg_debug("Nothing extracted in order #%d", order);
00456             minx = maxx = nx/2;
00457         }
00458         
00459         lambda_min = uves_polynomial_evaluate_2d(
00460         dispersion_relation, minx - 0.5, absorder)/absorder;
00461         lambda_max = uves_polynomial_evaluate_2d(
00462         dispersion_relation, maxx + 0.5, absorder)/absorder;
00463         
00464         nbins =
00465         uves_round_double(lambda_max / wavestep) -
00466         uves_round_double(lambda_min / wavestep) + 1;
00467             
00468         nlambda = uves_max_int(nlambda, nbins);  
00469         
00470         check( uves_pfits_set_wstart(
00471                *rebinned_header, order,
00472                wavestep * uves_round_double(lambda_min / wavestep)),
00473            "Error writing adding WSTART keyword to header");
00474         
00475         check( uves_pfits_set_wend( 
00476                *rebinned_header, order,
00477                wavestep * uves_round_double(lambda_max / wavestep)),
00478            "Error writing adding WEND keyword to header");
00479         
00480         uves_msg_debug("Rebinning abs. order #%d. "
00481                "Range = %d - %d pix = %f - %f wlu, %d bins", 
00482                absorder,
00483                minx, maxx,
00484                lambda_min,
00485                lambda_max,
00486                nbins);
00487         }
00488 
00489     
00490     uves_msg_debug("Step size = %f wlu (%d orders x %d bins)", wavestep, norders, nlambda);
00491     
00492     /* Do the rebinning */
00493 
00494     /* Create empty image */
00495     check_nomsg( rebinned = cpl_image_new(nlambda, norders*n_traces, cpl_image_get_type(spectrum)));
00496     assure_mem( rebinned );
00497 
00498     if (cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE) {
00499         rebinned_data_double   = cpl_image_get_data_double(rebinned);
00500     }
00501     else if (cpl_image_get_type(spectrum) == CPL_TYPE_FLOAT) {
00502         rebinned_data_float   = cpl_image_get_data_float(rebinned);
00503     } else {
00504         rebinned_data_int   = cpl_image_get_data_int(rebinned);
00505     }
00506     rebinned_badmap = cpl_image_get_bpm(rebinned);
00507     rebinned_bad    = cpl_mask_get_data(rebinned_badmap);
00508         
00509     /* Reject all pixels in output image,
00510        accept as values are computed */
00511     uves_image_reject_all(rebinned);
00512 
00513     for (order = 1; order <= norders; order++)
00514     {
00515         int absorder = uves_absolute_order(first_abs_order, last_abs_order, order);
00516         double lambda_start;        /* Center of first wavel. bin */
00517         int trace;
00518 
00519         /* uves_msg_progress(order - 1, norders, ".."); */
00520             
00521         check( lambda_start = uves_pfits_get_wstart(*rebinned_header, order),
00522            "Error reading product header");
00523 
00524         /* For efficiency, collapse 2d polynomial to 1d only once per order */
00525         uves_polynomial_delete(&disprel_1d);
00526         check( disprel_1d = uves_polynomial_collapse(dispersion_relation,
00527                              2,   /* Independent variable number */
00528                              absorder),
00529            "Error getting 1d dispersion relation for absolute order #%d", absorder);
00530         
00531 
00532         
00533         for (trace = 1; trace <= n_traces; trace++) 
00534         {
00535             int spectrum_row = (order - 1)*n_traces + trace;
00536             int bin;
00537 
00538             double x = 1;
00539             double x_min = 1;
00540             double x_max = 1;
00541             
00542             for (bin = 1; bin <= nlambda && x_min <= nx+0.5; bin++)
00543             {
00544                 double lambda = lambda_start + (bin-1) * wavestep;
00545                 /* Solve   f(x, m) = lambda*m  for x  */
00546                 int multiplicity = 1;
00547                 double x_guess = x;
00548                  
00549 
00550            
00551                             x     =  uves_polynomial_solve_1d(disprel_1d,
00552                                                               lambda * absorder,
00553                                                               x_guess, 
00554                                                               multiplicity);
00555                 
00556                             if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00557                                 uves_error_reset();
00558                                 if (!warning_shown) {
00559                                     uves_msg_warning("Could not invert dispersion relation at "
00560                                                      "order = %d, x = %f. This might be caused "
00561                                                      "by fitting a too high degree polynomial to "
00562                                                      "too few lines. Decrease dispersion "
00563                                                      "polynomial degree "
00564                                                      "or relax rejection parameters!",
00565                                                      absorder, x_guess);
00566                                     warning_shown = true;
00567                                 }
00568                                 x = x_guess;
00569                             }
00570                             else {
00571                                 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00572                                         cpl_error_get_code(),
00573                                         "Could not invert dispersion relation");
00574                             }
00575 
00576            
00577                 x_guess = x;
00578                             x_min = uves_polynomial_solve_1d(
00579                                 disprel_1d,
00580                                 (lambda - 0.5*wavestep) * absorder,
00581                                 x_guess,
00582                                 multiplicity);
00583                             
00584                             if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00585                                 uves_error_reset();
00586                                 if (!warning_shown) {
00587                                     uves_msg_warning("Could not invert dispersion relation at "
00588                                                      "order = %d, x = %f. This might be caused "
00589                                                      "by fitting a too high degree polynomial to "
00590                                                      "too few lines. Decrease dispersion "
00591                                                      "polynomial degree "
00592                                                      "or relax rejection parameters!",
00593                                                      absorder, x_guess);
00594                                     warning_shown = true;
00595                                 }
00596                                 x_min = x_guess;
00597                             }
00598                             else {
00599                                 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00600                                         cpl_error_get_code(),
00601                                         "Could not invert dispersion relation");
00602                             }
00603 
00604 
00605                             x_max = uves_polynomial_solve_1d(
00606                                 disprel_1d,
00607                                 (lambda + 0.5*wavestep) * absorder,
00608                                 x_guess,
00609                                 multiplicity);
00610                             
00611                             if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00612                                 uves_error_reset();
00613                                 if (!warning_shown) {
00614                                     uves_msg_warning("Could not invert dispersion relation at "
00615                                                      "order = %d, x = %f. This might be caused "
00616                                                      "by fitting a too high degree polynomial to "
00617                                                      "too few lines. Decrease dispersion "
00618                                                      "polynomial degree "
00619                                                      "or relax rejection parameters!",
00620                                                      absorder, x_guess);
00621                                     warning_shown = true;
00622                                 }
00623                                 x_max = x_guess;
00624                             }
00625                             else {
00626                                 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00627                                         cpl_error_get_code(),
00628                                         "Could not invert dispersion relation");
00629                             }
00630                             
00631                 /* If bin overlaps with source image */
00632                 if (uves_max_double(0.5, uves_min_double(nx+0.5, x_min)) <
00633                 uves_max_double(0.5, uves_min_double(nx+0.5, x_max)))
00634                 {
00635                     /* Measure average flux in range [xmin; xmax]:
00636 
00637                        flux_x  = [ int_xmin^xmax f(x) dx ] / (xmax-xmin)
00638                     */
00639 
00640                     bool pis_rejected;
00641                     double flux_x = integrate_flux(
00642                         spectrum_data_double,
00643                         spectrum_data_float,
00644                         spectrum_data_int,
00645                         spectrum_bad,
00646                         spectrum_row,
00647                         nx,
00648                         uves_max_double(0.5, uves_min_double(nx+0.5, x_min)),
00649                         uves_max_double(0.5, uves_min_double(nx+0.5, x_max)),
00650                         threshold_to_positive,
00651                         &pis_rejected) 
00652                         / ( uves_max_double(0.5, uves_min_double(nx+0.5, x_max)) -
00653                             uves_max_double(0.5, uves_min_double(nx+0.5, x_min)) );
00654                     
00655                     if (!pis_rejected)
00656                     {
00657                         /* Convert to flux per wavelength if requested */
00658 
00659                         double dldx;
00660 
00661 
00662                         if (scale)
00663                         {
00664                             /*  For constant m: 
00665                              *   dl/dx = d(l*m)/dx / m
00666                              */    
00667                             dldx = uves_polynomial_derivative_2d(
00668                             dispersion_relation, x, absorder, 1)
00669                             / absorder;
00670                         }
00671                         else
00672                         {
00673                             dldx = 1;
00674                         }
00675                         
00676                         /* Density in wavelength space :   
00677                            N_lambda = N_x / |dl/dx|  */
00678 
00679                         if (cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE) {
00680                             rebinned_data_double[(bin-1) + 
00681                                           (spectrum_row-1)*nlambda] = 
00682                                 flux_x / fabs(dldx);
00683                         }
00684                         else if (cpl_image_get_type(spectrum) == CPL_TYPE_FLOAT) {
00685                             rebinned_data_float[(bin-1) + 
00686                                                 (spectrum_row-1)*nlambda] = 
00687                                 flux_x / fabs(dldx);
00688                         } else {
00689                             rebinned_data_int[(bin-1) + 
00690                                                 (spectrum_row-1)*nlambda] = 
00691                                 flux_x / fabs(dldx);
00692 
00693 
00694             }
00695 
00696 
00697                         rebinned_bad[(bin-1) +
00698                              (spectrum_row-1)*nlambda] =
00699                         CPL_BINARY_0;
00700                     }
00701                     else
00702                     {
00703                         /* Interpolation interval had no good pixels */
00704                                             /* Pixel marked as bad */
00705                     }
00706 
00707                 }
00708                 else
00709                 {
00710                     /* Current wavelength bin is outside input image */
00711                                     /* Pixel marked as bad */
00712                 }
00713 
00714 
00715             }/* for each wavelength bin */
00716                 } /* for trace */
00717 
00718     } /* for order */
00719     /* Done rebinning */
00720 
00721 
00722   cleanup:
00723     uves_polynomial_delete(&disprel_1d);
00724     if (cpl_error_get_code() != CPL_ERROR_NONE)
00725     {
00726         uves_free_image(&rebinned);
00727         uves_free_propertylist(rebinned_header);
00728     }
00729 
00730     return rebinned;
00731 }
00732 
00733 /*----------------------------------------------------------------------------*/
00758 /*----------------------------------------------------------------------------*/
00759 inline static double
00760 integrate_flux(const double *spectrum_data_double,
00761                const float *spectrum_data_float,
00762                const int *spectrum_data_int,
00763                const cpl_binary *spectrum_bad,
00764                int spectrum_row,
00765                int nx,
00766                double x_min, double x_max,
00767                bool threshold_to_positive,
00768                bool *is_bad)
00769 {
00770     double sum = 0;           /* Result */
00771     double sum_interval = 0;  /* The length of the interval defined as the unioun
00772                  of good pixels */
00773     int x;
00774     int first_good = 0;
00775 
00776     *is_bad = true;           /* Until at least one good pixel found */
00777     
00778     for (x  = uves_min_int(nx, uves_max_int(1, uves_round_double(x_min)));
00779      /* The thresholding is necessary, or nx+0.5 would be rounded to nx+1
00780         which would cause a memory error */
00781      x <= uves_min_int(nx, uves_max_int(1, uves_round_double(x_max)));
00782      x++)
00783     {  
00784 
00785         if (spectrum_bad[(x-1) + (spectrum_row-1)*nx] == CPL_BINARY_0)
00786         /* If good pixel */
00787         {
00788             double flux;             /* "Raw" flux of current bin */
00789             double interval_length;
00790             double current_term;     /* Integral over current pixel */
00791            
00792             /* Use a piecewise linear profile like this
00793              *   
00794              *                   C
00795              *  interpolant  => / \
00796              *              ---/---\-- <= "raw" flux
00797              *              | /     \|
00798              *              |/       B
00799              *              A        |________ <= non-continous interpolation
00800              *             /|     
00801              *    __________|        
00802              *
00803              * The flux levels A and B are midway between the current
00804              * pixel flux and its neighbours' levels.
00805              * C is chosen so that the integrated flux over the current 
00806              * pixel equals the observed flux.
00807              *
00808              * This interpolant is continous as well as flux conserving.
00809              */
00810             
00811             int x_prev = x-1;
00812             int x_next = x+1;
00813             bool pis_rejected_prev = (x_prev < 1 ) || 
00814             (spectrum_bad[(x_prev-1) + (spectrum_row-1)*nx] == CPL_BINARY_1);
00815             bool pis_rejected_next = (nx < x_next) || 
00816             (spectrum_bad[(x_next-1) + (spectrum_row-1)*nx] == CPL_BINARY_1);
00817 
00818             if (spectrum_data_double != NULL) {
00819                 flux = spectrum_data_double[(x-1) + (spectrum_row-1)*nx];
00820             }
00821             else if (spectrum_data_float != NULL) {
00822                 flux = spectrum_data_float [(x-1) + (spectrum_row-1)*nx];
00823             } else {
00824                 flux = spectrum_data_int [(x-1) + (spectrum_row-1)*nx];
00825         }
00826             
00827             if (!pis_rejected_prev && !pis_rejected_next)
00828             {
00829                 /* Define flux at pixel borders (A and B) as 
00830                    mean value of this and neighbouring pixel */
00831 
00832                 double flux_minus, flux_plus;
00833                 if (spectrum_data_double != NULL) {
00834                     flux_minus =
00835                         (flux + spectrum_data_double[(x_prev-1) + (spectrum_row-1)*nx])
00836                         / 2.0;
00837                     flux_plus =
00838                         (flux + spectrum_data_double[(x_next-1) + (spectrum_row-1)*nx])
00839                         / 2.0;
00840                 }
00841                 else if (spectrum_data_float != NULL) { 
00842                     flux_minus =
00843                         (flux + spectrum_data_float[(x_prev-1) + (spectrum_row-1)*nx])
00844                         / 2.0;
00845                     flux_plus =
00846                         (flux + spectrum_data_float[(x_next-1) + (spectrum_row-1)*nx])
00847                         / 2.0;
00848                 } else {
00849                     flux_minus =
00850                         (flux + spectrum_data_int[(x_prev-1) + (spectrum_row-1)*nx])
00851                         / 2.0;
00852                     flux_plus =
00853                         (flux + spectrum_data_int[(x_next-1) + (spectrum_row-1)*nx])
00854                         / 2.0;
00855         }
00856                 
00857                 /* Define flux at pixel center, fluxc, so that the average flux is
00858                  * equal to the "raw" flux:
00859                  *
00860                  * ((flux- + fluxc)/2 + (flux+ + fluxc)/2) / 2 = flux
00861                  * =>  flux- + flux+ + 2fluxc = 4flux
00862                  * =>  fluxc = ...
00863                  */
00864                 {
00865                     double flux_center = 2*flux - (flux_minus + flux_plus) / 2.0;
00866                     
00867                     /* Line slopes */
00868                     double slope_minus = (flux_center - flux_minus )/ 0.5;
00869                     double slope_plus  = (flux_plus   - flux_center) / 0.5;
00870                     
00871                     /*  Define overlap between [x_min; x_max] and
00872                         interval between A-C:  [x-0.5; x]) */
00873                     double lo1 = uves_max_double(x-0.5, uves_min_double(x, x_min));
00874                     double hi1 = uves_max_double(x-0.5, uves_min_double(x, x_max));
00875                     double dy1 = hi1-lo1;
00876                     
00877                     /*  Define overlap between [x_min; x_max] and
00878                         interval between C-B:  [x; x+0.5]) */
00879                     double lo2 = uves_max_double(x, uves_min_double(x+0.5, x_min));
00880                     double hi2 = uves_max_double(x, uves_min_double(x+0.5, x_max));
00881                     double dy2 = hi2-lo2;
00882                     
00883                     /* Integrate interpolant over A-C and C-B */
00884                     /* A-C: interpolant(x) = flux_center + slope_minus *(x-x)
00885                        C-B: interpolant(x) = flux_center + slope_plus  *(x-x)
00886                     */
00887                 
00888 
00889 
00890                     current_term =
00891                         dy1 * (flux_center + slope_minus * ((lo1+hi1)/2.0 - x))
00892                         +
00893                         dy2 * (flux_center + slope_plus  * ((lo2+hi2)/2.0 - x));
00894                     
00895                     interval_length = dy1 + dy2;
00896                 }
00897                 
00898             }/* Neighbours are good */
00899             else
00900             {
00901                 interval_length = 
00902                 uves_min_double(x_max, x+0.5) -
00903                 uves_max_double(x_min, x-0.5);
00904 
00905                 current_term = interval_length * flux;
00906             }
00907             
00908             if (*is_bad) {
00909                 first_good = x;
00910             }
00911             *is_bad = false;
00912             
00913             sum += current_term;
00914             sum_interval += interval_length; 
00915         }
00916     }
00917     
00918     if (sum_interval == 0)
00919     {
00920         *is_bad = true;
00921         return -1;
00922     }
00923     else
00924     {
00925         /* In case of bad pixels, rescale sum to full interval
00926            (If there are only good pixels then sum_interval == x_max-x_min)
00927         */
00928             double result =  sum*(x_max-x_min)/sum_interval;
00929 
00930             if (threshold_to_positive) {
00931                 if (result == 0) {
00932                     /* give up */
00933                     *is_bad = true;
00934                     return -1;
00935                 }
00936                 else {
00937                     result = fabs(result);
00938                 }
00939             }
00940             return result;
00941     }
00942 }
00943 

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