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

Generated on Fri Apr 18 14:11:42 2008 for UVES Pipeline Reference Manual by  doxygen 1.5.1