uves_merge.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: jmlarsen $
00022  * $Date: 2007/08/21 13:08:26 $
00023  * $Revision: 1.43 $
00024  * $Name: uves-3_4_5 $
00025  * $Log: uves_merge.c,v $
00026  * Revision 1.43  2007/08/21 13:08:26  jmlarsen
00027  * Removed irplib_access module, largely deprecated by CPL-4
00028  *
00029  * Revision 1.42  2007/06/21 11:28:57  jmlarsen
00030  * Added support for type float (for FLAMES)
00031  *
00032  * Revision 1.41  2007/06/06 08:17:33  amodigli
00033  * replace tab with 4 spaces
00034  *
00035  * Revision 1.40  2007/05/03 15:21:13  jmlarsen
00036  * Decreased output message verbosity
00037  *
00038  * Revision 1.39  2007/04/24 12:50:29  jmlarsen
00039  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00040  *
00041  * Revision 1.38  2007/02/09 08:57:54  jmlarsen
00042  * Include <float.h>
00043  *
00044  * Revision 1.37  2007/02/09 08:14:16  jmlarsen
00045  * Do not use CPL_PIXEL_MAXVAL which works only for integer images
00046  *
00047  * Revision 1.36  2007/02/08 07:34:28  jmlarsen
00048  * Minor doc change
00049  *
00050  * Revision 1.35  2006/11/15 15:02:14  jmlarsen
00051  * Implemented const safe workarounds for CPL functions
00052  *
00053  * Revision 1.33  2006/11/15 14:04:08  jmlarsen
00054  * Removed non-const version of parameterlist_get_first/last/next which is already
00055  * in CPL, added const-safe wrapper, unwrapper and deallocator functions
00056  *
00057  * Revision 1.32  2006/11/13 14:23:55  jmlarsen
00058  * Removed workarounds for CPL const bugs
00059  *
00060  * Revision 1.31  2006/11/06 15:19:41  jmlarsen
00061  * Removed unused include directives
00062  *
00063  * Revision 1.30  2006/09/11 14:00:11  jmlarsen
00064  * Minor documentation change
00065  *
00066  * Revision 1.29  2006/08/17 13:56:53  jmlarsen
00067  * Reduced max line length
00068  *
00069  * Revision 1.28  2006/08/17 09:16:47  jmlarsen
00070  * Removed CPL2 code
00071  *
00072  * Revision 1.27  2006/08/11 14:37:59  jmlarsen
00073  * Added input validation
00074  *
00075  * Revision 1.26  2006/08/10 10:50:12  jmlarsen
00076  * Removed workaround for cpl_image_get_bpm
00077  *
00078  * Revision 1.25  2006/07/03 13:16:42  jmlarsen
00079  * Reduced number of significant digits in message
00080  *
00081  * Revision 1.24  2006/04/06 08:38:56  jmlarsen
00082  * Changed char* -> const char* for static string
00083  *
00084  * Revision 1.23  2006/03/03 13:54:11  jmlarsen
00085  * Changed syntax of check macro
00086  *
00087  * Revision 1.22  2006/02/03 07:46:30  jmlarsen
00088  * Moved recipe implementations to ./uves directory
00089  *
00090  * Revision 1.21  2006/01/31 08:24:29  jmlarsen
00091  * Wrapper for cpl_image_get_bpm
00092  *
00093  * Revision 1.20  2006/01/25 16:13:20  jmlarsen
00094  * Changed interface of gauss.fitting routine
00095  *
00096  * Revision 1.19  2005/12/19 16:17:56  jmlarsen
00097  * Replaced bool -> int
00098  *
00099  * Revision 1.18  2005/12/16 14:22:23  jmlarsen
00100  * Removed midas test data; Added sof files
00101  *
00102  * Revision 1.17  2005/11/24 15:09:06  jmlarsen
00103  * Implemented 2d extraction/rebinning/merging
00104  *
00105  * Revision 1.16  2005/11/24 11:54:46  jmlarsen
00106  * Added support for CPL 3 interface
00107  *
00108  * Revision 1.15  2005/11/18 10:52:06  jmlarsen
00109  * Split into optimal/sum merge methods
00110  *
00111  * Revision 1.14  2005/11/11 13:18:54  jmlarsen
00112  * Reorganized code, renamed source files
00113  *
00114  */
00115 
00116 #ifdef HAVE_CONFIG_H
00117 #  include <config.h>
00118 #endif
00119 
00120 /*----------------------------------------------------------------------------*/
00126 /*----------------------------------------------------------------------------*/
00130 /*-----------------------------------------------------------------------------
00131                                 Includes
00132  -----------------------------------------------------------------------------*/
00133 
00134 #include <uves_merge.h>
00135 
00136 #include <uves_pfits.h>
00137 #include <uves_utils.h>
00138 #include <uves_utils_wrappers.h>
00139 #include <uves_dump.h>
00140 #include <uves_error.h>
00141 
00142 #include <cpl.h>
00143 #include <float.h>
00144 
00145 /*-----------------------------------------------------------------------------
00146                             Functions prototypes
00147  -----------------------------------------------------------------------------*/
00148 
00149 /*-----------------------------------------------------------------------------
00150                             Implementation
00151  -----------------------------------------------------------------------------*/
00152 
00153 /*----------------------------------------------------------------------------*/
00180 /*----------------------------------------------------------------------------*/
00181 
00182 cpl_image *
00183 uves_merge_orders(const cpl_image *spectrum, const cpl_image *spectrum_noise,
00184                   const uves_propertylist *spectrum_header,
00185                   merge_method m_method,
00186                   int n_traces,
00187                   uves_propertylist **merged_header,
00188                   cpl_image **merged_noise)
00189 {
00190     cpl_image *merged = NULL;    /* Result */
00191 
00192     const double *spectrum_data_double = NULL;
00193     const float  *spectrum_data_float  = NULL;
00194     const cpl_mask *spectrum_badmap    = NULL;
00195     const cpl_binary *spectrum_bad     = NULL;
00196 
00197     const double *noise_data_double = NULL;
00198     const float *noise_data_float   = NULL;
00199     const cpl_mask *noise_badmap    = NULL;
00200     const cpl_binary *noise_bad     = NULL;
00201     cpl_type type;               /* input/output images type */
00202 
00203     int nbins, ny, norders;          /* Input image size. ny = norders*n_traces */
00204     double wavestep;
00205     int bin_min = 0, bin_max = 0;    /* wavelength of min/max bin in units of 'wavestep' */
00206     int total_bins;
00207     int order, trace;
00208 
00209     passure( spectrum != NULL, " ");
00210     passure( spectrum_noise != NULL, " ");
00211     passure( spectrum_header != NULL, " ");
00212     passure( merged_header != NULL, " ");
00213     passure( merged_noise != NULL, " ");
00214 
00215     assure( m_method == MERGE_OPTIMAL || m_method == MERGE_SUM, CPL_ERROR_ILLEGAL_INPUT,
00216             "Unknown merge method: %d", m_method);
00217     
00218     assure( cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE ||
00219             cpl_image_get_type(spectrum) == CPL_TYPE_FLOAT,
00220             CPL_ERROR_TYPE_MISMATCH,
00221             "Spectrum must have type double or float. It is '%s'",
00222             uves_tostring_cpl_type(cpl_image_get_type(spectrum)));
00223     
00224     assure( cpl_image_get_type(spectrum_noise) == CPL_TYPE_DOUBLE ||
00225             cpl_image_get_type(spectrum_noise) == CPL_TYPE_FLOAT,
00226             CPL_ERROR_TYPE_MISMATCH,
00227             "Spectrum noise must have type double. It is '%s'",
00228             uves_tostring_cpl_type(cpl_image_get_type(spectrum_noise)));
00229 
00230     assure( cpl_image_get_type(spectrum) ==
00231             cpl_image_get_type(spectrum_noise),
00232             CPL_ERROR_TYPE_MISMATCH,
00233             "Spectrum and spectrum noise must have same type. They are "
00234             "%s and %s, respectively",
00235             uves_tostring_cpl_type(cpl_image_get_type(spectrum)),
00236             uves_tostring_cpl_type(cpl_image_get_type(spectrum_noise)) );
00237 
00238     type = cpl_image_get_type(spectrum);
00239 
00240     /* Read input spectrum geometry */
00241     nbins           = cpl_image_get_size_x(spectrum);
00242     ny              = cpl_image_get_size_y(spectrum);
00243 
00244     assure( cpl_image_get_size_x(spectrum_noise) == nbins &&
00245             cpl_image_get_size_y(spectrum_noise) == ny,
00246             CPL_ERROR_INCOMPATIBLE_INPUT,
00247             "Incompatible spectrum/noise image sizes: %dx%d vs. %dx%d",
00248             nbins, ny,
00249             cpl_image_get_size_x(spectrum_noise),
00250             cpl_image_get_size_y(spectrum_noise) );
00251     
00252     assure( ny % n_traces == 0, CPL_ERROR_INCOMPATIBLE_INPUT,
00253             "Spectrum image height (%d) is not a multiple of "
00254             "the number of traces (%d). Confused, bailing out",
00255             ny, n_traces);
00256 
00257     norders         = ny / n_traces;
00258     
00259     check( wavestep = uves_pfits_get_cdelt1(spectrum_header),
00260        "Error reading bin width");
00261 
00262     /* Get data pointers (for efficiency) */
00263    
00264     if (type == CPL_TYPE_DOUBLE) {
00265         spectrum_data_double   = cpl_image_get_data_double_const(spectrum);
00266     }
00267     else {
00268         spectrum_data_float   = cpl_image_get_data_float_const(spectrum);
00269     }
00270     spectrum_badmap = cpl_image_get_bpm_const(spectrum);
00271     spectrum_bad    = cpl_mask_get_data_const(spectrum_badmap);
00272     
00273     if (type == CPL_TYPE_DOUBLE) {
00274         noise_data_double = cpl_image_get_data_double_const(spectrum_noise);        
00275     }
00276     else {
00277         noise_data_float  = cpl_image_get_data_float_const(spectrum_noise);
00278     }
00279     noise_badmap = cpl_image_get_bpm_const(spectrum_noise);
00280     noise_bad    = cpl_mask_get_data_const(noise_badmap);
00281 
00282     /* Read max/min lambda */
00283     for (order = 1; order <= norders; order++)
00284     {
00285         double wstart, wend;
00286         check( wstart = uves_pfits_get_wstart(spectrum_header, order),
00287            "Error reading start wavelength for order #%d", order);
00288 
00289         check( wend = uves_pfits_get_wend(spectrum_header, order),
00290            "Error reading end wavelength for order #%d", order);
00291         
00292         uves_msg_debug("Order #%d: wstart - wend = %f - %f wlu", order, wstart, wend);
00293 
00294         if (order == 1)
00295         {
00296             bin_min = uves_round_double(wstart/wavestep);
00297             bin_max = uves_round_double(wend  /wavestep);
00298         }
00299         
00300         bin_min = uves_min_int(bin_min, uves_round_double(wstart/wavestep));
00301         bin_max = uves_max_int(bin_max, uves_round_double(wend  /wavestep));
00302     }
00303 
00304     total_bins = (bin_max - bin_min) + 1;
00305 
00306     uves_msg_debug("Merging orders into %d bins covering wavelengths %.3f - %.3f wlu", 
00307             total_bins, bin_min * wavestep, bin_max * wavestep);
00308 
00309     /* Initialize spectrum to zero and noise to negative */
00310     merged        = cpl_image_new(total_bins, n_traces, type);
00311     *merged_noise = cpl_image_new(total_bins, n_traces, type);
00312     cpl_image_add_scalar(*merged_noise, -1.0);
00313     
00314     /* Distribute input in output bins */
00315     for (order = 1; order <= norders; order++)
00316     {
00317         double wstart, wend;
00318         int wstart_bin, wend_bin;      /* In 1d space */
00319 
00320         check( wstart = uves_pfits_get_wstart(spectrum_header, order),
00321            "Error reading start wavelength for order #%d", order);
00322         
00323         check( wend = uves_pfits_get_wend(spectrum_header, order),
00324            "Error reading end wavelength for order #%d", order);
00325         
00326         wstart_bin = uves_round_double(wstart/wavestep);
00327         wend_bin   = uves_round_double(wend/wavestep);
00328 
00329         /* Loop over spatial traces (only 1 trace, unless extraction was 2d) */
00330         for (trace = 1; trace <= n_traces; trace++)
00331         {
00332             int spectrum_row = (order - 1)*n_traces + trace;
00333             int rel_bin;                   /* Counting columns in input spectrum */
00334             
00335             for (rel_bin = 1; rel_bin <= wend_bin - wstart_bin + 1; rel_bin++)
00336             {
00337                 double flux, noise;
00338                 double current_flux, new_flux;
00339                 double current_noise, new_noise;
00340                 double weight;
00341                 int pis_rejected, noise_rejected;
00342                 
00343                 /* merged_bin = (offset of order)  +  (offset inside order) */
00344                 int merged_bin = (wstart_bin - bin_min) + rel_bin;
00345                 
00346                 passure(1 <= merged_bin && merged_bin <= total_bins,
00347                     "%d %d %d", rel_bin, merged_bin, total_bins);
00348                 
00349                 /* This is slow:
00350                    check( flux  = cpl_image_get(spectrum      , 
00351                           rel_bin, spectrum_row, &pis_rejected);
00352                    noise = cpl_image_get(spectrum_noise, rel_bin, 
00353                     spectrum_row, &noise_rejected),
00354                    "Error reading input spectrum");
00355                 */
00356                 
00357                 if (type == CPL_TYPE_DOUBLE) {
00358                     flux  = spectrum_data_double[(rel_bin-1) + (spectrum_row-1) * nbins];
00359                     noise = noise_data_double   [(rel_bin-1) + (spectrum_row-1) * nbins];
00360 
00361                 }
00362                 else {
00363                     flux  = spectrum_data_float[(rel_bin-1) + (spectrum_row-1) * nbins];
00364                     noise = noise_data_float   [(rel_bin-1) + (spectrum_row-1) * nbins];
00365                 }
00366 
00367                 pis_rejected   = spectrum_bad[(rel_bin-1) + (spectrum_row-1) * nbins];
00368                 noise_rejected = noise_bad   [(rel_bin-1) + (spectrum_row-1) * nbins];
00369                 
00370                 if (!pis_rejected && !noise_rejected)
00371                 {
00372                     check(( current_flux  = cpl_image_get(
00373                         merged      , merged_bin, trace, &pis_rejected),
00374                         current_noise = cpl_image_get(
00375                         *merged_noise, merged_bin, trace, &pis_rejected)),
00376                        "Error reading merged spetrum");
00377 
00378                     weight = 1/(noise*noise);
00379                     
00380                     /*
00381                      * Optimal formulas for Variance and Flux are
00382                      *
00383                      *   Vn = ( 1/sigma1^2 + ... +  1/sigmaN^2)^-1
00384                      *   Fn = (f1/sigma1^2 + ... + fN/sigmaN^2) * Vn
00385                      *
00386                      * Update by using these recurrence relations
00387                      *
00388                      *   Fn+1 = (Fn/Vn + fn+1/(sigma_{n+1})^2) * Vn+1  for n > 1
00389                      *   Vn+1 = (Vn^-1 + 1/(sigma_{n+1})^2)^-1  for n > 1
00390                      *
00391                      *
00392                      *  In the case of method = sum,
00393                      *
00394                      *  Vn = sigma1^2 + ... + sigmaN^2
00395                      *  Fn = f1 + ... + fN
00396                      *
00397                      */
00398                     
00399                     if (current_noise > 0)
00400                     {
00401                         if (m_method == MERGE_OPTIMAL)
00402                         {
00403                             new_noise  = 1/(current_noise*current_noise);
00404                             new_noise += weight;
00405                             new_noise  = 1/sqrt(new_noise);
00406                         }
00407                         else if (m_method == MERGE_SUM)
00408                         {
00409                             new_noise = sqrt(current_noise*current_noise
00410                                      + noise*noise);
00411                         }
00412                         else
00413                         {
00414                             /* Impossible */
00415                             passure( false, "%d", m_method);
00416                         }
00417                     }
00418                     else
00419                     {
00420                         /* First time in this bin */
00421                         new_noise = noise;
00422                     }
00423                     
00424                     if (current_noise > 0)
00425                     {
00426                         if (m_method == MERGE_OPTIMAL)
00427                         {
00428                             new_flux = (current_flux / 
00429                                 (current_noise*current_noise)
00430                                 + flux * weight) * 
00431                             (new_noise*new_noise);
00432                         }
00433                         else if (m_method == MERGE_SUM)
00434                         {
00435                             new_flux = current_flux + flux;
00436                         }
00437                         else
00438                         {
00439                             /* Impossible */
00440                             passure( false, "%d", m_method);
00441                         }
00442                     }
00443                     else
00444                     {
00445                         new_flux = flux;
00446                     }
00447                     
00448                     check( cpl_image_set(
00449                            merged      , merged_bin, trace, new_flux),
00450                        "Error updating merged spectrum");
00451                     check( cpl_image_set(
00452                            *merged_noise, merged_bin, trace, new_noise),
00453                        "Error updating weights");
00454                     
00455 /*            uves_msg("Input flux = %e +- %e ;  
00456             Binned flux changed from %e +- %e to %e +- %e",
00457             flux, noise,
00458             current_flux, current_noise, new_flux, new_noise);*/
00459                     
00460                 } /* If pixel is good ... */
00461 
00462             } /* For each input bin */
00463 
00464         }/* For trace ... */
00465 
00466     }/* For order ... */
00467     
00468     /* Undefined bins have  (flux, noise) = (0, -1)  (the initial values).
00469      * Set to (flux, noise) = (0, 1)
00470      */
00471     check( cpl_image_threshold(*merged_noise, 
00472                    0, DBL_MAX,        /* Outside this interval */
00473                    1, 1),             /* Set to these values   */
00474        "Error setting undefined noise");
00475     
00476     if (merged_header != NULL)
00477     {
00478         check( *merged_header = uves_initialize_image_header(
00479                "WAVELENGTH", (n_traces > 1) ? "PIXEL" : " ", "FLUX",
00480                bin_min * wavestep, 1.0,
00481                1.0, 1.0,
00482                wavestep, 1.0),
00483            "Error initializing merged spectrum header");
00484     }
00485     
00486   cleanup:
00487     return merged;
00488 }
00489 
00490 /*----------------------------------------------------------------------------*/
00500 /*----------------------------------------------------------------------------*/
00501 merge_method
00502 uves_get_merge_method(const cpl_parameterlist *parameters, const char *context, 
00503               const char *subcontext)
00504 {
00505     const char *mm = "";
00506     merge_method result = 0;
00507     
00508     check( uves_get_parameter(parameters, context, subcontext, "merge", CPL_TYPE_STRING, &mm),
00509        "Could not read parameter");
00510     
00511     if      (strcmp(mm, "optimal") == 0) result = MERGE_OPTIMAL;
00512     else if (strcmp(mm, "sum"    ) == 0) result = MERGE_SUM;
00513     else
00514     {
00515         assure(false, CPL_ERROR_ILLEGAL_INPUT, "No such merging method: '%s'", mm);
00516     }
00517     
00518   cleanup:
00519     return result;
00520 }
00521     
00522 

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