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: 2010/11/09 17:23:13 $
00023  * $Revision: 1.51 $
00024  * $Name: uves-5_0_0 $
00025  * $Log: uves_rebin.c,v $
00026  * Revision 1.51  2010/11/09 17:23:13  amodigli
00027  * added integrate_noise() and made changes to properly rebin noise spectrum (sum in quadrature over variance, than take sqrt)
00028  *
00029  * Revision 1.50  2010/09/24 09:32:07  amodigli
00030  * put back QFITS dependency to fix problem spot by NRI on FIBER mode (with MIDAS calibs) data
00031  *
00032  * Revision 1.48  2010/06/08 11:25:47  amodigli
00033  * changed wavestep parmeters range to -1.0,-1.0,DBL_MAX
00034  *
00035  * Revision 1.47  2010/06/07 09:48:46  amodigli
00036  * changed unit: Angstrom->Ang
00037  *
00038  * Revision 1.46  2010/06/02 13:10:12  amodigli
00039  * set wavestep as parameter with range, min allowed is -1, max allowed is 0.4
00040  *
00041  * Revision 1.45  2010/02/13 12:22:31  amodigli
00042  * removed inlines (let's do work to compiler)
00043  *
00044  * Revision 1.44  2009/01/27 10:11:30  amodigli
00045  * fixed problem bue to cpl_image_get_bpm() API change
00046  *
00047  * Revision 1.43  2007/09/17 08:11:27  amodigli
00048  * added support CPL_TYPE_INT
00049  *
00050  * Revision 1.42  2007/08/21 13:08:26  jmlarsen
00051  * Removed irplib_access module, largely deprecated by CPL-4
00052  *
00053  * Revision 1.41  2007/06/21 07:29:11  jmlarsen
00054  * Fixed memory error
00055  *
00056  * Revision 1.40  2007/06/19 11:59:37  amodigli
00057  * added several uves_msg statements to check vs flames_obs_scired
00058  *
00059  * Revision 1.39  2007/06/18 15:35:27  jmlarsen
00060  * Added support for in/out image type=float (used in FLAMES)
00061  *
00062  * Revision 1.38  2007/06/06 08:17:33  amodigli
00063  * replace tab with 4 spaces
00064  *
00065  * Revision 1.37  2007/05/22 11:38:13  jmlarsen
00066  * Removed MIDAS flag for good
00067  *
00068  * Revision 1.36  2007/05/07 10:18:27  jmlarsen
00069  * Added option to enforce positive resulting values (useful for error bars)
00070  *
00071  * Revision 1.35  2007/05/03 15:21:10  jmlarsen
00072  * Decreased output message verbosity
00073  *
00074  * Revision 1.34  2007/04/27 07:21:15  jmlarsen
00075  * Show warning but don't fail if dispersion is ill-formed
00076  *
00077  * Revision 1.33  2007/04/24 12:50:29  jmlarsen
00078  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00079  *
00080  * Revision 1.32  2007/01/17 13:28:07  jmlarsen
00081  * Shortened line
00082  *
00083  * Revision 1.31  2006/11/15 15:02:15  jmlarsen
00084  * Implemented const safe workarounds for CPL functions
00085  *
00086  * Revision 1.29  2006/11/15 14:04:08  jmlarsen
00087  * Removed non-const version of parameterlist_get_first/last/next which is 
00088  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
00089  *
00090  * Revision 1.28  2006/11/13 14:23:55  jmlarsen
00091  * Removed workarounds for CPL const bugs
00092  *
00093  * Revision 1.27  2006/11/06 15:19:41  jmlarsen
00094  * Removed unused include directives
00095  *
00096  * Revision 1.26  2006/10/31 09:15:34  jmlarsen
00097  * Fixed buffer overrun
00098  *
00099  * Revision 1.25  2006/10/10 11:28:19  jmlarsen
00100  * Renamed line table columns to match MIDAS
00101  *
00102  * Revision 1.24  2006/10/10 11:20:11  jmlarsen
00103  * Renamed line table columns to match MIDAS
00104  *
00105  * Revision 1.23  2006/10/02 08:37:35  jmlarsen
00106  * Do not avoid reserving space for bad pixels near edge of orders, like MIDAS
00107  *
00108  * Revision 1.22  2006/09/20 12:53:57  jmlarsen
00109  * Replaced stringcat functions with uves_sprintf()
00110  *
00111  * Revision 1.21  2006/09/11 13:58:41  jmlarsen
00112  * Changed CRVAL1 from 1 to 0 in rebinned image
00113  *
00114  * Revision 1.20  2006/08/17 14:40:06  jmlarsen
00115  * Added missing documentation
00116  *
00117  * Revision 1.19  2006/08/17 13:56:53  jmlarsen
00118  * Reduced max line length
00119  *
00120  * Revision 1.18  2006/08/17 09:17:39  jmlarsen
00121  * Removed CPL2 code
00122  *
00123  * Revision 1.17  2006/08/10 10:52:58  jmlarsen
00124  * Removed workaround for cpl_image_get_bpm
00125  *
00126  * Revision 1.16  2006/08/07 11:35:35  jmlarsen
00127  * Disabled parameter environment variable mode
00128  *
00129  * Revision 1.15  2006/06/01 14:43:17  jmlarsen
00130  * Added missing documentation
00131  *
00132  * Revision 1.14  2006/05/08 11:36:10  jmlarsen
00133  * Fixed normalization bug for bins at edge of order
00134  *
00135  * Revision 1.13  2006/05/05 13:57:01  jmlarsen
00136  * Implemented more careful flux interpolation
00137  *
00138  * Revision 1.12  2006/04/06 08:39:36  jmlarsen
00139  * Added void to function prototype
00140  *
00141  * Revision 1.11  2006/03/03 13:54:11  jmlarsen
00142  * Changed syntax of check macro
00143  *
00144  * Revision 1.10  2006/02/03 07:46:30  jmlarsen
00145  * Moved recipe implementations to ./uves directory
00146  *
00147  * Revision 1.9  2006/01/31 08:24:29  jmlarsen
00148  * Wrapper for cpl_image_get_bpm
00149  *
00150  * Revision 1.8  2006/01/25 16:13:20  jmlarsen
00151  * Changed interface of gauss.fitting routine
00152  *
00153  * Revision 1.7  2005/12/19 16:17:56  jmlarsen
00154  * Replaced bool -> int
00155  *
00156  * Revision 1.6  2005/12/16 14:22:23  jmlarsen
00157  * Removed midas test data; Added sof files
00158  *
00159  * Revision 1.5  2005/12/02 10:41:49  jmlarsen
00160  * Minor update
00161  *
00162  * Revision 1.4  2005/11/28 08:18:12  jmlarsen
00163  * Replaced cpl_mask_get_bpm -> cpl_image_get_bpm
00164  *
00165  * Revision 1.3  2005/11/24 15:09:06  jmlarsen
00166  * Implemented 2d extraction/rebinning/merging
00167  *
00168  * Revision 1.2  2005/11/24 11:54:46  jmlarsen
00169  * Added support for CPL 3 interface
00170  *
00171  * Revision 1.1  2005/11/11 13:18:54  jmlarsen
00172  * Reorganized code, renamed source files
00173  *
00174  */
00175 
00176 #ifdef HAVE_CONFIG_H
00177 #  include <config.h>
00178 #endif
00179 
00180 /*----------------------------------------------------------------------------*/
00187 /*----------------------------------------------------------------------------*/
00190 /*-----------------------------------------------------------------------------
00191                                 Includes
00192  -----------------------------------------------------------------------------*/
00193 
00194 #include <uves_rebin.h>
00195 
00196 #include <uves_parameters.h>
00197 #include <uves.h>
00198 #include <uves_pfits.h>
00199 #include <uves_dump.h>
00200 #include <uves_utils.h>
00201 #include <uves_utils_wrappers.h>
00202 #include <uves_wavecal_utils.h>
00203 #include <uves_error.h>
00204 
00205 #include <cpl.h>
00206 
00207 /*-----------------------------------------------------------------------------
00208                             Functions prototypes
00209  -----------------------------------------------------------------------------*/
00210 static double
00211 integrate_flux(const double *spectrum_data_double,
00212                const float  *spectrum_data_float,
00213                const int  *spectrum_data_int,
00214                const cpl_binary *spectrum_bad,
00215                int spectrum_row,
00216                int nx,
00217                double x_min, double x_max,
00218                bool threshold_to_positive,
00219                bool *is_bad);
00220 static double
00221 integrate_noise(const double *spectrum_data_double,
00222                const float  *spectrum_data_float,
00223                const int  *spectrum_data_int,
00224                const cpl_binary *spectrum_bad,
00225                int spectrum_row,
00226                int nx,
00227                double x_min, double x_max,
00228                bool threshold_to_positive,
00229                bool *is_bad);
00230 
00231 /*-----------------------------------------------------------------------------
00232                             Implementation
00233  -----------------------------------------------------------------------------*/
00234 
00235 /*----------------------------------------------------------------------------*/
00243 /*----------------------------------------------------------------------------*/
00244 cpl_parameterlist *
00245 uves_rebin_define_parameters(void)
00246 {
00247     const char *name = "";
00248     char *full_name = NULL;
00249     cpl_parameter *p = NULL;
00250     cpl_parameterlist *parameters = NULL;
00251     
00252     parameters = cpl_parameterlist_new();
00253     
00254     {
00255     name = "wavestep";
00256     full_name = uves_sprintf("%s.%s", UVES_REBIN_ID, name);
00257     uves_parameter_new_range(p, full_name,
00258                  CPL_TYPE_DOUBLE,
00259                  "The bin size (in w.l.u.) in wavelength space. "
00260                  "If negative, a step size of "
00261                  "2/3 * ( average pixel size ) is used.",
00262                  UVES_REBIN_ID,
00263                              -1.0,-1.0,DBL_MAX);
00264     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00265     cpl_parameterlist_append(parameters, p);
00266     cpl_free(full_name);
00267 
00268     name = "scale";
00269     full_name = uves_sprintf("%s.%s", UVES_REBIN_ID, name);
00270     uves_parameter_new_value(p, full_name,
00271                  CPL_TYPE_BOOL,
00272                  "Whether or not to multiply by the factor "
00273                  "dx/dlambda (pixels per wavelength) "
00274                  "during the rebinning. This option is disabled "
00275                  "as default in concordance with the "
00276                  "method used in the MIDAS pipeline. This "
00277                  "option should be set to true "
00278                  "to convert the observed flux (in pixel-space) "
00279                  "to a flux per wavelength (in "
00280                  "wavelength-space).",
00281                  UVES_REBIN_ID,
00282                  false);
00283     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00284     cpl_parameterlist_append(parameters, p);
00285     cpl_free(full_name);
00286     }
00287     
00288     if (cpl_error_get_code() != CPL_ERROR_NONE)
00289     {
00290         cpl_msg_error(__func__, "Creation of rebinning parameters failed: '%s'", 
00291               cpl_error_get_where());
00292         cpl_parameterlist_delete(parameters);
00293         return NULL;
00294     }
00295     else
00296     {
00297         return parameters;
00298     }
00299 }
00300 
00301 /*----------------------------------------------------------------------------*/
00346 /*----------------------------------------------------------------------------*/
00347 cpl_image *
00348 uves_rebin(const cpl_image *spectrum,
00349        const cpl_parameterlist *parameters, const char *context,
00350        const cpl_table *linetable, const polynomial *dispersion_relation, 
00351        int first_abs_order, int last_abs_order,
00352        int n_traces,
00353            bool threshold_to_positive,
00354            bool is_noise,
00355        uves_propertylist **rebinned_header)
00356 {
00357     double wavestep;
00358     bool scale;
00359     cpl_image *spectrum_local       = NULL;   /* input */
00360     cpl_image *rebinned       = NULL;   /* Result */
00361     double *rebinned_data_double = NULL;
00362     float  *rebinned_data_float  = NULL;
00363     int  *rebinned_data_int  = NULL;
00364     cpl_mask *rebinned_badmap = NULL;   /* Map of unused bins */
00365     cpl_binary *rebinned_bad  = NULL;
00366 
00367     const double *spectrum_data_double = NULL;   /* Direct pointer to input data */
00368     const float  *spectrum_data_float  = NULL;   /* unused pointer remains NULL */
00369     const int  *spectrum_data_int  = NULL;   /* unused pointer remains NULL */
00370 
00371     const cpl_mask *spectrum_badmap = NULL;
00372     const cpl_binary *spectrum_bad  = NULL;
00373 
00374     polynomial *disprel_1d    = NULL;   /* Dispersion relation for 1 order */
00375 
00376     int nx, ny, nlambda, norders;     /* Image dimensions */
00377     int order;
00378     bool warning_shown = false;
00379 
00380    
00381     passure( spectrum != NULL, " ");
00382     passure( dispersion_relation != NULL, " ");
00383     passure( rebinned_header != NULL, " ");
00384     
00385     assure( cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE ||
00386             cpl_image_get_type(spectrum) == CPL_TYPE_FLOAT ||
00387             cpl_image_get_type(spectrum) == CPL_TYPE_INT,
00388             CPL_ERROR_TYPE_MISMATCH,
00389         "Spectrum must have type double, float or int. It is '%s'",
00390         uves_tostring_cpl_type(cpl_image_get_type(spectrum)));
00391 
00392     /* Get recipe parameters */
00393     check( uves_get_parameter(parameters, context, UVES_REBIN_ID, "wavestep", 
00394                   CPL_TYPE_DOUBLE, &wavestep ), 
00395        "Could not read parameter");
00396     check( uves_get_parameter(parameters, context, UVES_REBIN_ID, "scale"   , 
00397                   CPL_TYPE_BOOL,   &scale    ), 
00398        "Could not read parameter");
00399     
00400 
00401     /* Set sample bin width if user didn't */
00402     if (wavestep < 0)
00403     {
00404         double pixelsize;
00405         check( pixelsize = cpl_table_get_column_mean(linetable, LINETAB_PIXELSIZE),
00406            "Error reading mean pixelsize");
00407         uves_msg_debug("Average pixelsize = %f w.l.u.", pixelsize);
00408 
00409         wavestep = pixelsize*2.0/3;
00410         }
00411     
00412     assure( wavestep > 0 , CPL_ERROR_ILLEGAL_INPUT, 
00413         "Illegal step size: %e wlu", wavestep);
00414     assure( n_traces >= 1, CPL_ERROR_ILLEGAL_INPUT,
00415         "Illegal number of traces: %d", n_traces);
00416 
00417     nx = cpl_image_get_size_x(spectrum);
00418     ny = cpl_image_get_size_y(spectrum);
00419     
00420     assure( ny % n_traces == 0, CPL_ERROR_INCOMPATIBLE_INPUT,
00421         "Spectrum image height (%d) is not a multiple of "
00422         "the number of traces (%d). Confused, bailing out",
00423         ny, n_traces);
00424     
00425     norders         = ny / n_traces;
00426 
00427     spectrum_local=(cpl_image*) spectrum;
00428 
00429     if(is_noise) {       
00430        cpl_image_power(spectrum_local,2);
00431     }
00432 
00433     if (cpl_image_get_type(spectrum_local) == CPL_TYPE_DOUBLE) {
00434         spectrum_data_double   = cpl_image_get_data_double(spectrum_local);
00435     }
00436     else if (cpl_image_get_type(spectrum_local) == CPL_TYPE_FLOAT) {
00437         spectrum_data_float   = cpl_image_get_data_float(spectrum_local);
00438     } else {
00439         spectrum_data_int   = cpl_image_get_data_int(spectrum_local);
00440     }
00441     check_nomsg(spectrum_badmap = cpl_image_get_bpm(spectrum_local));
00442     check_nomsg(spectrum_bad    = cpl_mask_get_data_const(spectrum_badmap));
00443 
00444     assure( norders >= 1, CPL_ERROR_ILLEGAL_INPUT, "Empty spectrum");
00445     assure( uves_round_double(fabs(first_abs_order - last_abs_order)) + 1 == norders, 
00446         CPL_ERROR_INCOMPATIBLE_INPUT,
00447         "Spectrum contains %d orders, but line table absolute "
00448         "order numbering is %d - %d",
00449         norders, first_abs_order, last_abs_order);
00450 
00451 
00452     check( *rebinned_header = uves_initialize_image_header(
00453            "Ang",                        /* CTYPE */
00454            (n_traces > 1) ? "PIXEL" : "ORDER",
00455            (scale) ? "FLUX PER WAVEL" : "FLUX", /* BUNIT */
00456            0.0, 1.0,                            /* CRVAL  */
00457            1.0, 1.0,                            /* CRPIX  */
00458            wavestep, 1.0),                      /* CDELT  */
00459        "Error setting up rebinned image header");
00460     /* CRVAL1 is set to zero. It should really be set to WSTARTi
00461        for the i'th row of the image (but obviously that's not possible).
00462        CRVAL1 is set to zero so that the true starting position of
00463        the i'th image row is simply calculated as  CRVAL1 + WSTARTi.
00464     */
00465        
00466     /* Get width of rebinned image and offsets for each order */
00467     nlambda = -1;                      /* Maximum number of bins in any order */
00468 
00469     for (order = 1; order <= norders; order++)
00470     {
00471         /*int trace = 1;*/
00472                           /* In the case where there are more traces in each order 
00473                  (2d extraction), just use the 1st trace to get the
00474                  wavelength range for the current order. The wavelength
00475                  range is the same for all traces. 
00476                   */
00477         /* int spectrum_row = (order - 1)*n_traces + trace; */
00478         int absorder = uves_absolute_order(first_abs_order, last_abs_order, order);
00479         double lambda_min, lambda_max;
00480         int nbins;
00481         
00482         int minx, maxx;  /* Range of good pixels in current order */
00483         
00484         minx = 1;  
00485 /* The following is commented out to get the same
00486    alignment as MIDAS
00487         while (minx <= nx && cpl_image_is_rejected(spectrum, minx, spectrum_row)) minx++;
00488 */
00489         maxx = nx; 
00490 /*        while (maxx >=  1 && cpl_image_is_rejected(spectrum, maxx, spectrum_row)) maxx--; */
00491         if ( minx > nx )
00492         {
00493             uves_msg_debug("Nothing extracted in order #%d", order);
00494             minx = maxx = nx/2;
00495         }
00496         
00497         lambda_min = uves_polynomial_evaluate_2d(
00498         dispersion_relation, minx - 0.5, absorder)/absorder;
00499         lambda_max = uves_polynomial_evaluate_2d(
00500         dispersion_relation, maxx + 0.5, absorder)/absorder;
00501         
00502         nbins =
00503         uves_round_double(lambda_max / wavestep) -
00504         uves_round_double(lambda_min / wavestep) + 1;
00505             
00506         nlambda = uves_max_int(nlambda, nbins);  
00507         
00508         check( uves_pfits_set_wstart(
00509                *rebinned_header, order,
00510                wavestep * uves_round_double(lambda_min / wavestep)),
00511            "Error writing adding WSTART keyword to header");
00512         
00513         check( uves_pfits_set_wend( 
00514                *rebinned_header, order,
00515                wavestep * uves_round_double(lambda_max / wavestep)),
00516            "Error writing adding WEND keyword to header");
00517         
00518         uves_msg_debug("Rebinning abs. order #%d. "
00519                "Range = %d - %d pix = %f - %f wlu, %d bins", 
00520                absorder,
00521                minx, maxx,
00522                lambda_min,
00523                lambda_max,
00524                nbins);
00525         }
00526 
00527     
00528     uves_msg_debug("Step size = %f wlu (%d orders x %d bins)", wavestep, norders, nlambda);
00529     
00530     /* Do the rebinning */
00531 
00532     /* Create empty image */
00533     check_nomsg( rebinned = cpl_image_new(nlambda, norders*n_traces, cpl_image_get_type(spectrum_local)));
00534     assure_mem( rebinned );
00535 
00536     if (cpl_image_get_type(spectrum_local) == CPL_TYPE_DOUBLE) {
00537         rebinned_data_double   = cpl_image_get_data_double(rebinned);
00538     }
00539     else if (cpl_image_get_type(spectrum_local) == CPL_TYPE_FLOAT) {
00540         rebinned_data_float   = cpl_image_get_data_float(rebinned);
00541     } else {
00542         rebinned_data_int   = cpl_image_get_data_int(rebinned);
00543     }
00544     rebinned_badmap = cpl_image_get_bpm(rebinned);
00545     rebinned_bad    = cpl_mask_get_data(rebinned_badmap);
00546         
00547     /* Reject all pixels in output image,
00548        accept as values are computed */
00549     uves_image_reject_all(rebinned);
00550 
00551     for (order = 1; order <= norders; order++)
00552     {
00553         int absorder = uves_absolute_order(first_abs_order, last_abs_order, order);
00554         double lambda_start;        /* Center of first wavel. bin */
00555         int trace;
00556 
00557         /* uves_msg_progress(order - 1, norders, ".."); */
00558             
00559         check( lambda_start = uves_pfits_get_wstart(*rebinned_header, order),
00560            "Error reading product header");
00561 
00562         /* For efficiency, collapse 2d polynomial to 1d only once per order */
00563         uves_polynomial_delete(&disprel_1d);
00564         check( disprel_1d = uves_polynomial_collapse(dispersion_relation,
00565                              2,   /* Independent variable number */
00566                              absorder),
00567            "Error getting 1d dispersion relation for absolute order #%d", absorder);
00568         
00569 
00570         
00571         for (trace = 1; trace <= n_traces; trace++) 
00572         {
00573             int spectrum_row = (order - 1)*n_traces + trace;
00574             int bin;
00575 
00576             double x = 1;
00577             double x_min = 1;
00578             double x_max = 1;
00579             
00580             for (bin = 1; bin <= nlambda && x_min <= nx+0.5; bin++)
00581             {
00582                 double lambda = lambda_start + (bin-1) * wavestep;
00583                 /* Solve   f(x, m) = lambda*m  for x  */
00584                 int multiplicity = 1;
00585                 double x_guess = x;
00586                  
00587 
00588            
00589                             x     =  uves_polynomial_solve_1d(disprel_1d,
00590                                                               lambda * absorder,
00591                                                               x_guess, 
00592                                                               multiplicity);
00593                 
00594                             if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00595                                 uves_error_reset();
00596                                 if (!warning_shown) {
00597                                     uves_msg_warning("Could not invert dispersion relation at "
00598                                                      "order = %d, x = %f. This might be caused "
00599                                                      "by fitting a too high degree polynomial to "
00600                                                      "too few lines. Decrease dispersion "
00601                                                      "polynomial degree "
00602                                                      "or relax rejection parameters!",
00603                                                      absorder, x_guess);
00604                                     warning_shown = true;
00605                                 }
00606                                 x = x_guess;
00607                             }
00608                             else {
00609                                 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00610                                         cpl_error_get_code(),
00611                                         "Could not invert dispersion relation");
00612                             }
00613 
00614            
00615                 x_guess = x;
00616                             x_min = uves_polynomial_solve_1d(
00617                                 disprel_1d,
00618                                 (lambda - 0.5*wavestep) * absorder,
00619                                 x_guess,
00620                                 multiplicity);
00621                             
00622                             if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00623                                 uves_error_reset();
00624                                 if (!warning_shown) {
00625                                     uves_msg_warning("Could not invert dispersion relation at "
00626                                                      "order = %d, x = %f. This might be caused "
00627                                                      "by fitting a too high degree polynomial to "
00628                                                      "too few lines. Decrease dispersion "
00629                                                      "polynomial degree "
00630                                                      "or relax rejection parameters!",
00631                                                      absorder, x_guess);
00632                                     warning_shown = true;
00633                                 }
00634                                 x_min = x_guess;
00635                             }
00636                             else {
00637                                 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00638                                         cpl_error_get_code(),
00639                                         "Could not invert dispersion relation");
00640                             }
00641 
00642 
00643                             x_max = uves_polynomial_solve_1d(
00644                                 disprel_1d,
00645                                 (lambda + 0.5*wavestep) * absorder,
00646                                 x_guess,
00647                                 multiplicity);
00648                             
00649                             if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00650                                 uves_error_reset();
00651                                 if (!warning_shown) {
00652                                     uves_msg_warning("Could not invert dispersion relation at "
00653                                                      "order = %d, x = %f. This might be caused "
00654                                                      "by fitting a too high degree polynomial to "
00655                                                      "too few lines. Decrease dispersion "
00656                                                      "polynomial degree "
00657                                                      "or relax rejection parameters!",
00658                                                      absorder, x_guess);
00659                                     warning_shown = true;
00660                                 }
00661                                 x_max = x_guess;
00662                             }
00663                             else {
00664                                 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00665                                         cpl_error_get_code(),
00666                                         "Could not invert dispersion relation");
00667                             }
00668                             
00669                 /* If bin overlaps with source image */
00670                 if (uves_max_double(0.5, uves_min_double(nx+0.5, x_min)) <
00671                 uves_max_double(0.5, uves_min_double(nx+0.5, x_max)))
00672                 {
00673                     /* Measure average flux in range [xmin; xmax]:
00674 
00675                        flux_x  = [ int_xmin^xmax f(x) dx ] / (xmax-xmin)
00676                     */
00677 
00678                     bool pis_rejected;
00679                     double p_min=uves_max_double(0.5, uves_min_double(nx+0.5, x_min));
00680                     double p_max=uves_max_double(0.5, uves_min_double(nx+0.5, x_max));
00681                     double flux_x =0;
00682                     if(is_noise) {
00683                        flux_x = integrate_noise(
00684                           spectrum_data_double,
00685                           spectrum_data_float,
00686                           spectrum_data_int,
00687                           spectrum_bad,
00688                           spectrum_row,
00689                           nx,
00690                           p_min,
00691                           p_max,
00692                           threshold_to_positive,
00693                           &pis_rejected) 
00694                           / (( p_max -p_min) * ( p_max -p_min));
00695 
00696                     } else {
00697                        flux_x = integrate_flux(
00698                           spectrum_data_double,
00699                           spectrum_data_float,
00700                           spectrum_data_int,
00701                           spectrum_bad,
00702                           spectrum_row,
00703                           nx,
00704                           p_min,
00705                           p_max,
00706                           threshold_to_positive,
00707                           &pis_rejected) 
00708                           / ( p_max - p_min );
00709                     }
00710                     if (!pis_rejected)
00711                     {
00712                         /* Convert to flux per wavelength if requested */
00713 
00714                         double dldx;
00715  
00716 
00717                         if (scale)
00718                         {
00719                             /*  For constant m: 
00720                              *   dl/dx = d(l*m)/dx / m
00721                              */    
00722                             dldx = uves_polynomial_derivative_2d(
00723                             dispersion_relation, x, absorder, 1)
00724                             / absorder;
00725  
00726                             if(is_noise) {
00727                                dldx *= dldx;
00728                             }                           
00729                         }
00730                         else
00731                         {
00732                             dldx = 1;
00733                         }
00734                         
00735                         /* Density in wavelength space :   
00736                            N_lambda = N_x / |dl/dx|  */
00737 
00738                         if (cpl_image_get_type(spectrum_local) == CPL_TYPE_DOUBLE) {
00739                             rebinned_data_double[(bin-1) + 
00740                                           (spectrum_row-1)*nlambda] = 
00741                                 flux_x / fabs(dldx);
00742                         }
00743                         else if (cpl_image_get_type(spectrum_local) == CPL_TYPE_FLOAT) {
00744                             rebinned_data_float[(bin-1) + 
00745                                                 (spectrum_row-1)*nlambda] = 
00746                                 flux_x / fabs(dldx);
00747                         } else {
00748                             rebinned_data_int[(bin-1) + 
00749                                                 (spectrum_row-1)*nlambda] = 
00750                                 flux_x / fabs(dldx);
00751 
00752 
00753             }
00754 
00755 
00756                         rebinned_bad[(bin-1) +
00757                              (spectrum_row-1)*nlambda] =
00758                         CPL_BINARY_0;
00759                     }
00760                     else
00761                     {
00762                         /* Interpolation interval had no good pixels */
00763                                             /* Pixel marked as bad */
00764                     }
00765 
00766                 }
00767                 else
00768                 {
00769                     /* Current wavelength bin is outside input image */
00770                                     /* Pixel marked as bad */
00771                 }
00772 
00773 
00774             }/* for each wavelength bin */
00775                 } /* for trace */
00776 
00777     } /* for order */
00778     /* Done rebinning */
00779     if(is_noise) {
00780        cpl_image_power(rebinned,0.5);
00781     }
00782 
00783 
00784   cleanup:
00785     uves_polynomial_delete(&disprel_1d);
00786     if (cpl_error_get_code() != CPL_ERROR_NONE)
00787     {
00788         uves_free_image(&rebinned);
00789         uves_free_propertylist(rebinned_header);
00790     }
00791 
00792     return rebinned;
00793 }
00794 
00795 /*----------------------------------------------------------------------------*/
00820 /*----------------------------------------------------------------------------*/
00821 static double
00822 integrate_flux(const double *spectrum_data_double,
00823                const float *spectrum_data_float,
00824                const int *spectrum_data_int,
00825                const cpl_binary *spectrum_bad,
00826                int spectrum_row,
00827                int nx,
00828                double x_min, double x_max,
00829                bool threshold_to_positive,
00830                bool *is_bad)
00831 {
00832     double sum = 0;           /* Result */
00833     double sum_interval = 0;  /* The length of the interval defined as the unioun
00834                  of good pixels */
00835     int x;
00836     int first_good = 0;
00837 
00838     *is_bad = true;           /* Until at least one good pixel found */
00839     
00840     for (x  = uves_min_int(nx, uves_max_int(1, uves_round_double(x_min)));
00841      /* The thresholding is necessary, or nx+0.5 would be rounded to nx+1
00842         which would cause a memory error */
00843      x <= uves_min_int(nx, uves_max_int(1, uves_round_double(x_max)));
00844      x++)
00845     {  
00846 
00847         if (spectrum_bad[(x-1) + (spectrum_row-1)*nx] == CPL_BINARY_0)
00848         /* If good pixel */
00849         {
00850             double flux;             /* "Raw" flux of current bin */
00851             double interval_length;
00852             double current_term;     /* Integral over current pixel */
00853            
00854             /* Use a piecewise linear profile like this
00855              *   
00856              *                   C
00857              *  interpolant  => / \
00858              *              ---/---\-- <= "raw" flux
00859              *              | /     \|
00860              *              |/       B
00861              *              A        |________ <= non-continous interpolation
00862              *             /|     
00863              *    __________|        
00864              *
00865              * The flux levels A and B are midway between the current
00866              * pixel flux and its neighbours' levels.
00867              * C is chosen so that the integrated flux over the current 
00868              * pixel equals the observed flux.
00869              *
00870              * This interpolant is continous as well as flux conserving.
00871              */
00872             
00873             int x_prev = x-1;
00874             int x_next = x+1;
00875             bool pis_rejected_prev = (x_prev < 1 ) || 
00876             (spectrum_bad[(x_prev-1) + (spectrum_row-1)*nx] == CPL_BINARY_1);
00877             bool pis_rejected_next = (nx < x_next) || 
00878             (spectrum_bad[(x_next-1) + (spectrum_row-1)*nx] == CPL_BINARY_1);
00879 
00880             if (spectrum_data_double != NULL) {
00881                 flux = spectrum_data_double[(x-1) + (spectrum_row-1)*nx];
00882             }
00883             else if (spectrum_data_float != NULL) {
00884                 flux = spectrum_data_float [(x-1) + (spectrum_row-1)*nx];
00885             } else {
00886                 flux = spectrum_data_int [(x-1) + (spectrum_row-1)*nx];
00887         }
00888             
00889             if (!pis_rejected_prev && !pis_rejected_next)
00890             {
00891                 /* Define flux at pixel borders (A and B) as 
00892                    mean value of this and neighbouring pixel */
00893                 /* CHANGE in case of noise divide by 4 instead of 2 
00894                    (input has to be variance) */
00895                 double flux_minus, flux_plus;
00896                 if (spectrum_data_double != NULL) {
00897                     flux_minus =
00898                         (flux + spectrum_data_double[(x_prev-1) + (spectrum_row-1)*nx])
00899                         / 2.0;
00900                     flux_plus =
00901                         (flux + spectrum_data_double[(x_next-1) + (spectrum_row-1)*nx])
00902                         / 2.0;
00903                 }
00904                 else if (spectrum_data_float != NULL) { 
00905                     flux_minus =
00906                         (flux + spectrum_data_float[(x_prev-1) + (spectrum_row-1)*nx])
00907                         / 2.0;
00908                     flux_plus =
00909                         (flux + spectrum_data_float[(x_next-1) + (spectrum_row-1)*nx])
00910                         / 2.0;
00911                 } else {
00912                     flux_minus =
00913                         (flux + spectrum_data_int[(x_prev-1) + (spectrum_row-1)*nx])
00914                         / 2.0;
00915                     flux_plus =
00916                         (flux + spectrum_data_int[(x_next-1) + (spectrum_row-1)*nx])
00917                         / 2.0;
00918         }
00919                 
00920                 /* Define flux at pixel center, fluxc, so that the average flux is
00921                  * equal to the "raw" flux:
00922                  *
00923                  * ((flux- + fluxc)/2 + (flux+ + fluxc)/2) / 2 = flux
00924                  * =>  flux- + flux+ + 2fluxc = 4flux
00925                  * =>  fluxc = ...
00926                  */
00927                 {
00928                     double flux_center = 2*flux - (flux_minus + flux_plus) / 2.0;
00929                     /* CHANGE:   4*flux + (flux_minus + flux_plus) / 4.0 */
00930 
00931                     /* Line slopes */
00932                     double slope_minus = (flux_center - flux_minus )/ 0.5;
00933                     double slope_plus  = (flux_plus   - flux_center) / 0.5;
00934                     /* CHANGE: 
00935                               (flux_center + flux_minus )/ 0.25;
00936                      (flux_plus   + flux_center) / 0.25;
00937                     */
00938                     /*  Define overlap between [x_min; x_max] and
00939                         interval between A-C:  [x-0.5; x]) */
00940                     double lo1 = uves_max_double(x-0.5, uves_min_double(x, x_min));
00941                     double hi1 = uves_max_double(x-0.5, uves_min_double(x, x_max));
00942                     double dy1 = hi1-lo1;
00943                     
00944                     /*  Define overlap between [x_min; x_max] and
00945                         interval between C-B:  [x; x+0.5]) */
00946                     double lo2 = uves_max_double(x, uves_min_double(x+0.5, x_min));
00947                     double hi2 = uves_max_double(x, uves_min_double(x+0.5, x_max));
00948                     double dy2 = hi2-lo2;
00949                     
00950                     /* Integrate interpolant over A-C and C-B */
00951                     /* A-C: interpolant(x) = flux_center + slope_minus *(x-x)
00952                        C-B: interpolant(x) = flux_center + slope_plus  *(x-x)
00953                     */
00954                 
00955 
00956 
00957                     current_term =
00958                         dy1 * (flux_center + slope_minus * ((lo1+hi1)/2.0 - x))
00959                         +
00960                         dy2 * (flux_center + slope_plus  * ((lo2+hi2)/2.0 - x));
00961                     /* CHANGE
00962                    current_term =
00963                         (dy1)^2 * (flux_center + slope_minus * ((lo1+hi1)/2.0 - x)^2)
00964                         +
00965                         (dy2)^2 * (flux_center + slope_plus  * ((lo2+hi2)/2.0 - x)^2);
00966 
00967                     */
00968                     interval_length = dy1 + dy2;
00969                 }
00970                 
00971             }/* Neighbours are good */
00972             else
00973             {
00974                 interval_length = 
00975                 uves_min_double(x_max, x+0.5) -
00976                 uves_max_double(x_min, x-0.5);
00977 
00978                 current_term = interval_length * flux;
00979                 /* CHANGE 
00980                 current_term = (interval_length)^2 * flux;
00981                 */
00982             }
00983             
00984             if (*is_bad) {
00985                 first_good = x;
00986             }
00987             *is_bad = false;
00988             
00989             sum += current_term;
00990             sum_interval += interval_length; 
00991         }
00992     }
00993     
00994     if (sum_interval == 0)
00995     {
00996         *is_bad = true;
00997         return -1;
00998     }
00999     else
01000     {
01001         /* In case of bad pixels, rescale sum to full interval
01002            (If there are only good pixels then sum_interval == x_max-x_min)
01003         */
01004             double result =  sum*(x_max-x_min)/sum_interval;
01005             /* CHANGE
01006             double result =  sum*[(x_max-x_min)/sum_interval]^2;
01007             */
01008             if (threshold_to_positive) {
01009                 if (result == 0) {
01010                     /* give up */
01011                     *is_bad = true;
01012                     return -1;
01013                 }
01014                 else {
01015                     result = fabs(result);
01016                 }
01017             }
01018             return result;
01019     }
01020 }
01021 
01022 
01023 /*----------------------------------------------------------------------------*/
01048 /*----------------------------------------------------------------------------*/
01049 static double
01050 integrate_noise(const double *spectrum_data_double,
01051                const float *spectrum_data_float,
01052                const int *spectrum_data_int,
01053                const cpl_binary *spectrum_bad,
01054                int spectrum_row,
01055                int nx,
01056                double x_min, double x_max,
01057                bool threshold_to_positive,
01058                bool *is_bad)
01059 {
01060     double sum = 0;           /* Result */
01061     double sum_interval = 0;  /* The length of the interval defined as the unioun
01062                  of good pixels */
01063     int x;
01064     int first_good = 0;
01065 
01066     *is_bad = true;           /* Until at least one good pixel found */
01067     
01068     for (x  = uves_min_int(nx, uves_max_int(1, uves_round_double(x_min)));
01069      /* The thresholding is necessary, or nx+0.5 would be rounded to nx+1
01070         which would cause a memory error */
01071      x <= uves_min_int(nx, uves_max_int(1, uves_round_double(x_max)));
01072      x++)
01073     {  
01074 
01075         if (spectrum_bad[(x-1) + (spectrum_row-1)*nx] == CPL_BINARY_0)
01076         /* If good pixel */
01077         {
01078             double flux;             /* "Raw" flux of current bin */
01079             double interval_length;
01080             double current_term;     /* Integral over current pixel */
01081            
01082             /* Use a piecewise linear profile like this
01083              *   
01084              *                   C
01085              *  interpolant  => / \
01086              *              ---/---\-- <= "raw" flux
01087              *              | /     \|
01088              *              |/       B
01089              *              A        |________ <= non-continous interpolation
01090              *             /|     
01091              *    __________|        
01092              *
01093              * The flux levels A and B are midway between the current
01094              * pixel flux and its neighbours' levels.
01095              * C is chosen so that the integrated flux over the current 
01096              * pixel equals the observed flux.
01097              *
01098              * This interpolant is continous as well as flux conserving.
01099              */
01100             
01101             int x_prev = x-1;
01102             int x_next = x+1;
01103             bool pis_rejected_prev = (x_prev < 1 ) || 
01104             (spectrum_bad[(x_prev-1) + (spectrum_row-1)*nx] == CPL_BINARY_1);
01105             bool pis_rejected_next = (nx < x_next) || 
01106             (spectrum_bad[(x_next-1) + (spectrum_row-1)*nx] == CPL_BINARY_1);
01107 
01108             if (spectrum_data_double != NULL) {
01109                 flux = spectrum_data_double[(x-1) + (spectrum_row-1)*nx];
01110             }
01111             else if (spectrum_data_float != NULL) {
01112                 flux = spectrum_data_float [(x-1) + (spectrum_row-1)*nx];
01113             } else {
01114                 flux = spectrum_data_int [(x-1) + (spectrum_row-1)*nx];
01115         }
01116             
01117             if (!pis_rejected_prev && !pis_rejected_next)
01118             {
01119                 /* Define flux at pixel borders (A and B) as 
01120                    mean value of this and neighbouring pixel */
01121                 /* CHANGED in case of noise divide by 4 instead of 2 
01122                    (input is to be variance) */
01123                 double flux_minus, flux_plus;
01124                 if (spectrum_data_double != NULL) {
01125                     flux_minus =
01126                         (flux + spectrum_data_double[(x_prev-1) + (spectrum_row-1)*nx])
01127                         / 4.0;
01128                     flux_plus =
01129                         (flux + spectrum_data_double[(x_next-1) + (spectrum_row-1)*nx])
01130                         / 4.0;
01131                 }
01132                 else if (spectrum_data_float != NULL) { 
01133                     flux_minus =
01134                         (flux + spectrum_data_float[(x_prev-1) + (spectrum_row-1)*nx])
01135                         / 4.0;
01136                     flux_plus =
01137                         (flux + spectrum_data_float[(x_next-1) + (spectrum_row-1)*nx])
01138                         / 4.0;
01139                 } else {
01140                     flux_minus =
01141                         (flux + spectrum_data_int[(x_prev-1) + (spectrum_row-1)*nx])
01142                         / 4.0;
01143                     flux_plus =
01144                         (flux + spectrum_data_int[(x_next-1) + (spectrum_row-1)*nx])
01145                         / 4.0;
01146         }
01147                 
01148                 /* Define flux at pixel center, fluxc, so that the average flux is
01149                  * equal to the "raw" flux:
01150                  *
01151                  * ((flux- + fluxc)/2 + (flux+ + fluxc)/2) / 2 = flux
01152                  * =>  flux- + flux+ + 2fluxc = 4flux
01153                  * =>  fluxc = ...
01154                  */
01155                 {
01156                     double flux_center = 4*flux - (flux_minus + flux_plus) / 4.0;
01157                     /* CHANGED:   4*flux + (flux_minus + flux_plus) / 4.0 */
01158 
01159                     /* Line slopes */
01160                     double slope_minus = 4.0 * (flux_center + flux_minus );
01161                     double slope_plus  = 4.0 * (flux_plus   + flux_center);
01162                     /* CHANGED for variance: 
01163                               (flux_center + flux_minus )/ 0.25;
01164                               (flux_plus   + flux_center) / 0.25;
01165                     */
01166                     /*  Define overlap between [x_min; x_max] and
01167                         interval between A-C:  [x-0.5; x]) */
01168                     double lo1 = uves_max_double(x-0.5, uves_min_double(x, x_min));
01169                     double hi1 = uves_max_double(x-0.5, uves_min_double(x, x_max));
01170                     double dy1 = hi1-lo1;
01171                     
01172                     /*  Define overlap between [x_min; x_max] and
01173                         interval between C-B:  [x; x+0.5]) */
01174                     double lo2 = uves_max_double(x, uves_min_double(x+0.5, x_min));
01175                     double hi2 = uves_max_double(x, uves_min_double(x+0.5, x_max));
01176                     double dy2 = hi2-lo2;
01177                     
01178                     /* Integrate interpolant over A-C and C-B */
01179                     /* A-C: interpolant(x) = flux_center + slope_minus *(x-x)
01180                        C-B: interpolant(x) = flux_center + slope_plus  *(x-x)
01181                     */
01182                 
01183 
01184 
01185                     current_term =
01186                         dy1*dy1 * (flux_center + slope_minus * 
01187                                   ((lo1+hi1)/2.0 - x) * ((lo1+hi1)/2.0 - x)   )
01188                         +
01189                         dy2*dy2 * (flux_center + slope_plus  * 
01190                                  ((lo2+hi2)/2.0 - x)  * ((lo2+hi2)/2.0 - x)  );
01191                     /* CHANGED
01192                    current_term =
01193                         (dy1)^2 * (flux_center + slope_minus * ((lo1+hi1)/2.0 - x)^2)
01194                         +
01195                         (dy2)^2 * (flux_center + slope_plus  * ((lo2+hi2)/2.0 - x)^2);
01196 
01197                     */
01198                     interval_length = dy1 + dy2;
01199                 }
01200                 
01201             }/* Neighbours are good */
01202             else
01203             {
01204                 interval_length = 
01205                 uves_min_double(x_max, x+0.5) -
01206                 uves_max_double(x_min, x-0.5);
01207 
01208                 current_term = interval_length * interval_length * flux;
01209                 /* CHANGED 
01210                 current_term = (interval_length)^2 * flux;
01211                 */
01212             }
01213             
01214             if (*is_bad) {
01215                 first_good = x;
01216             }
01217             *is_bad = false;
01218             
01219             sum += current_term;
01220             sum_interval += interval_length; 
01221         }
01222     }
01223     
01224     if (sum_interval == 0)
01225     {
01226         *is_bad = true;
01227         return -1;
01228     }
01229     else
01230     {
01231         /* In case of bad pixels, rescale sum to full interval
01232            (If there are only good pixels then sum_interval == x_max-x_min)
01233         */
01234             double result =  sum*(x_max-x_min)/sum_interval*
01235                                  (x_max-x_min)/sum_interval;
01236             /* CHANGED
01237             double result =  sum*[(x_max-x_min)/sum_interval]^2;
01238             */
01239             if (threshold_to_positive) {
01240                 if (result == 0) {
01241                     /* give up */
01242                     *is_bad = true;
01243                     return -1;
01244                 }
01245                 else {
01246                     result = fabs(result);
01247                 }
01248             }
01249             return result;
01250     }
01251 }
01252 
01253 
01254 

Generated on 9 Mar 2012 for UVES Pipeline Reference Manual by  doxygen 1.6.1