uves_wavecal_search.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: 2012/03/02 16:43:12 $
00023  * $Revision: 1.33 $
00024  * $Name: uves-5_0_0 $
00025  * $Log: uves_wavecal_search.c,v $
00026  * Revision 1.33  2012/03/02 16:43:12  amodigli
00027  * fixed warning related to upgrade to CPL6
00028  *
00029  * Revision 1.32  2011/12/08 13:59:43  amodigli
00030  * Fox warnings with CPL6
00031  *
00032  * Revision 1.31  2011/03/25 07:44:19  amodigli
00033  * cleaned output
00034  *
00035  * Revision 1.30  2011/03/23 12:27:31  amodigli
00036  * changed QC key as user likes
00037  *
00038  * Revision 1.29  2011/03/23 10:08:31  amodigli
00039  * added QC to better characterize wave accuracy
00040  *
00041  * Revision 1.28  2010/09/24 09:32:10  amodigli
00042  * put back QFITS dependency to fix problem spot by NRI on FIBER mode (with MIDAS calibs) data
00043  *
00044  * Revision 1.26  2007/08/21 13:08:26  jmlarsen
00045  * Removed irplib_access module, largely deprecated by CPL-4
00046  *
00047  * Revision 1.25  2007/06/06 08:17:34  amodigli
00048  * replace tab with 4 spaces
00049  *
00050  * Revision 1.24  2007/05/02 13:20:01  jmlarsen
00051  * Take error bars into account in line searching if arclamp was flat-fielded
00052  *
00053  * Revision 1.23  2007/04/24 12:50:29  jmlarsen
00054  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00055  *
00056  * Revision 1.22  2007/04/20 14:46:45  jmlarsen
00057  * Added commented out code
00058  *
00059  * Revision 1.21  2007/03/05 10:25:08  jmlarsen
00060  * Include slope in Gaussian fit
00061  *
00062  * Revision 1.20  2007/02/23 13:33:38  jmlarsen
00063  * Added code to test unweighted fitting
00064  *
00065  * Revision 1.19  2007/02/22 15:38:26  jmlarsen
00066  * Use linear background term in Gaussian fit
00067  *
00068  * Revision 1.18  2006/11/15 15:02:15  jmlarsen
00069  * Implemented const safe workarounds for CPL functions
00070  *
00071  * Revision 1.16  2006/11/15 14:04:08  jmlarsen
00072  * Removed non-const version of parameterlist_get_first/last/next which is already
00073  * in CPL, added const-safe wrapper, unwrapper and deallocator functions
00074  *
00075  * Revision 1.15  2006/11/06 15:19:42  jmlarsen
00076  * Removed unused include directives
00077  *
00078  * Revision 1.14  2006/08/18 13:51:01  jmlarsen
00079  * Moved one message from info to debug level
00080  *
00081  * Revision 1.13  2006/08/17 13:56:53  jmlarsen
00082  * Reduced max line length
00083  *
00084  * Revision 1.12  2006/08/17 09:18:47  jmlarsen
00085  * Removed CPL2 code
00086  *
00087  * Revision 1.11  2006/08/11 14:38:24  jmlarsen
00088  * Minor text output change
00089  *
00090  * Revision 1.10  2006/08/11 09:01:17  jmlarsen
00091  * Set unextracted bins to zero flux rather than marking them as bad
00092  *
00093  * Revision 1.9  2006/07/14 12:45:58  jmlarsen
00094  * Removed a few messages
00095  *
00096  * Revision 1.8  2006/07/03 13:29:30  jmlarsen
00097  * Adapted to new 1d-fitting function interface
00098  *
00099  * Revision 1.7  2006/06/13 12:05:11  jmlarsen
00100  * Shortened max line length
00101  *
00102  * Revision 1.6  2006/05/12 15:06:30  jmlarsen
00103  * Killed code for method = gravity
00104  *
00105  * Revision 1.5  2006/04/24 09:34:26  jmlarsen
00106  * Adapted to new interface of gaussian fitting routine
00107  *
00108  * Revision 1.4  2006/03/03 13:54:11  jmlarsen
00109  * Changed syntax of check macro
00110  *
00111  * Revision 1.3  2006/02/15 13:19:15  jmlarsen
00112  * Reduced source code max. line length
00113  *
00114  * Revision 1.2  2006/02/08 07:52:16  jmlarsen
00115  * Added function returning library version
00116  *
00117  * Revision 1.34  2006/01/12 15:41:14  jmlarsen
00118  * Moved gauss. fitting to irplib
00119  *
00120  * Revision 1.33  2005/12/20 08:11:44  jmlarsen
00121  * Added CVS  entry
00122  *
00123  */
00124 
00125 /*----------------------------------------------------------------------------*/
00129 /*----------------------------------------------------------------------------*/
00132 #ifdef HAVE_CONFIG_H
00133 #  include <config.h>
00134 #endif
00135 
00136 #include <uves_wavecal_search.h>
00137 #include <uves_utils.h>
00138 #include <uves_utils_wrappers.h>
00139 #include <uves_utils_cpl.h>
00140 #include <uves_pfits.h>
00141 #include <uves_dump.h>
00142 #include <uves_error.h>
00143 #include <uves_msg.h>
00144 #include <uves_qclog.h>
00145 
00146 #include <cpl.h>
00147 #include <float.h>
00148 
00149 #define FIT_SLOPE 1
00150 #define WEIGHTED_FIT 1   /* Define to zero to get unweighted fit of emmision line
00151                             (like MIDAS) */
00152 
00153 static double
00154 xcenter(const cpl_image *image, const cpl_image *noise, int xlo, int xhi, int row,
00155     centering_method CENTERING_METHOD, int bin_disp,
00156     double *sigma, double *intensity, double *dx0, double *slope, double *background);
00157 
00158 static cpl_error_code
00159 detect_lines(const cpl_image *spectrum, const cpl_image *noise, 
00160          const uves_propertylist *spectrum_header, 
00161              bool flat_fielded,
00162          int RANGE, double THRESHOLD, centering_method CENTERING_METHOD, 
00163              int bin_disp,
00164          const polynomial *order_locations, cpl_image *arcframe, 
00165          cpl_table *linetable, 
00166          int *ndetected, int *nrows);
00167 
00168 /*----------------------------------------------------------------------------*/
00198 /*----------------------------------------------------------------------------*/
00199 cpl_table *
00200 uves_wavecal_search(const cpl_image *spectrum, const cpl_image *noise,
00201                     const uves_propertylist *spectrum_header,
00202                     bool flat_fielded,
00203                     const polynomial *order_locations, cpl_image *arcframe,
00204                     int RANGE, int MINLINES, int MAXLINES,
00205                     centering_method CENTERING_METHOD,int bin_disp,
00206                     const int trace, const int window,  cpl_table* qclog)
00207 {
00208     cpl_table *linetable = NULL;       /* Result */
00209 
00210     int nx, ny, norders;               /* Dimensions of raw image, number of orders */
00211     double threshold_low;              /* Threshold limits used for binary search */
00212     double threshold_high;
00213     double threshold = 0;             /* Current threshold */
00214     int lines_in_table;               /* Number of lines in line table */
00215     int lines_detected;               /* Number of lines actually found */
00216     bool max_thresh_found = false;    /* Is 'threshold_high' large enough? */
00217   
00218 
00219     passure( spectrum        != NULL, "Null input spectrum");
00220     passure( order_locations != NULL, "Null polynomial");
00221     passure( arcframe        != NULL, "Null raw image");
00222 
00223     if (flat_fielded) {
00224         assure( cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE,
00225                 CPL_ERROR_TYPE_MISMATCH,
00226                 "Spectrum image type is %s, must be double",
00227                 uves_tostring_cpl_type(cpl_image_get_type(spectrum)));
00228     }
00229     
00230     check(( nx      = cpl_image_get_size_x(spectrum),
00231         norders = cpl_image_get_size_y(spectrum)), "Error reading input spectrum");
00232     check( ny      = cpl_image_get_size_y(arcframe), "Error reading input image");
00233     assure(nx == cpl_image_get_size_x(arcframe), CPL_ERROR_INCOMPATIBLE_INPUT, 
00234        "Spectrum and image widths are different (%d and %" CPL_SIZE_FORMAT ")",
00235        nx, cpl_image_get_size_x(arcframe));
00236     
00237     assure( MINLINES <= MAXLINES, CPL_ERROR_ILLEGAL_INPUT, 
00238         "minlines=%d maxlines=%d", MINLINES, MAXLINES );
00239     
00240     /* Initialize result line table */
00241     check(( linetable = cpl_table_new(MAXLINES),
00242         cpl_table_new_column(linetable, "X"     , CPL_TYPE_DOUBLE),
00243         cpl_table_new_column(linetable, "dX"    , CPL_TYPE_DOUBLE),
00244         cpl_table_new_column(linetable, "Xwidth", CPL_TYPE_DOUBLE),
00245         cpl_table_new_column(linetable, "Y"     , CPL_TYPE_INT),
00246         cpl_table_new_column(linetable, "Peak"  , CPL_TYPE_DOUBLE),
00247         cpl_table_new_column(linetable, "Background" , CPL_TYPE_DOUBLE),
00248         cpl_table_new_column(linetable, "Slope" , CPL_TYPE_DOUBLE)),
00249       "Could not create line table");
00250     
00251     uves_msg("Searching for emission lines");
00252 
00253     threshold_low  = 0.0;
00254 
00255     /* This start (guess) value is doubled until too few lines are detected */
00256     if (flat_fielded) {
00257         threshold_high = 10.0; /* dimensionless, number of stdevs above continuum */
00258     }
00259     else {
00260         threshold_high = cpl_image_get_mean(spectrum);
00261 
00262         assure( threshold_high > 0, CPL_ERROR_ILLEGAL_INPUT,
00263                 "Spectrum median flux is %e. Must be positive",
00264                 cpl_image_get_median(spectrum));
00265     }
00266     
00267     max_thresh_found = false;
00268 
00269     /* Detect lines and adjust threshold
00270        until MINLINES <= lines_detected <= MAXLINES */
00271     lines_detected = 0;
00272 
00273 
00274     char qc_key[40];
00275  
00276     int kk=0;
00277     while( (lines_detected < MINLINES || MAXLINES < lines_detected) && 
00278         fabs(threshold_low - threshold_high) > DBL_EPSILON )
00279     {
00280        kk++;
00281         threshold = (threshold_low + threshold_high)/2.0;
00282 
00283         check( detect_lines(spectrum, noise, spectrum_header,
00284                                 flat_fielded,
00285                 RANGE, threshold, CENTERING_METHOD,
00286                                 bin_disp,
00287                 order_locations,
00288                 NULL,
00289                 linetable,
00290                 &lines_detected,
00291                 &lines_in_table),
00292            "Could not search for emission lines");
00293         
00294         /* Update threshold */
00295         /* 'threshold_high' is doubled until the threshold is too high.
00296            Then a binary search is performed. */
00297         if (lines_detected < MINLINES)
00298         {
00299             max_thresh_found = true;
00300             threshold_high = threshold;
00301         }
00302         else if (MAXLINES < lines_detected) 
00303         {
00304             if (!max_thresh_found)
00305             {
00306                 threshold_high *= 2;
00307             }
00308             else
00309             {                
00310                 threshold_low = threshold;
00311             }
00312         }
00313         sprintf(qc_key,"QC TRACE%d WIN%d NLINDET%d",trace,window,kk);
00314         uves_msg_debug("ThAr lamp on trace %d window %d detected lines %d",
00315                  trace,window,lines_detected);
00316         ck0_nomsg(uves_qclog_add_int(qclog,qc_key,lines_detected,
00317                                         "ThAr lamp detected lines","%d"));
00318 
00319         sprintf(qc_key,"QC TRACE%d WIN%d NLINDET NITERS",trace,window);
00320         ck0_nomsg(uves_qclog_add_int(qclog,qc_key,kk+1,
00321                                              "Number of iterations",
00322                                              "%d"));
00323 
00324     } /* end while loop */
00325 
00326     assure( MINLINES <= lines_detected && lines_detected <= MAXLINES, 
00327         CPL_ERROR_CONTINUE,
00328         "Could not detect between %d and %d lines. Try to increase search range",
00329         MINLINES, MAXLINES);
00330     
00331     /* Draw detections on input image  */
00332     check( detect_lines(spectrum, noise, spectrum_header,
00333                         flat_fielded,
00334             RANGE, threshold, CENTERING_METHOD,
00335                         bin_disp,
00336             order_locations,
00337             arcframe,
00338             linetable,
00339             &lines_detected,
00340             &lines_in_table),
00341        "Could not search for emission lines");
00342     
00343     /* Remove the last part of the line table (garbage) */
00344     check( cpl_table_set_size(linetable, lines_in_table), 
00345        "Could not resize line table");
00346     
00347     uves_sort_table_1(linetable, "X", false);
00348     
00349   cleanup:
00350 #if 0 /* if flat-fielded */
00351     uves_free_image(&temp);
00352 #endif
00353     if (cpl_error_get_code() != CPL_ERROR_NONE)
00354     {
00355         uves_free_table(&linetable);
00356     }
00357     else
00358     {
00359         /* Returned is... */
00360         passure( cpl_table_get_ncol(linetable) == 7, "%" CPL_SIZE_FORMAT "",
00361              cpl_table_get_ncol(linetable));
00362         passure( cpl_table_has_column(linetable, "X"     ), " ");
00363         passure( cpl_table_has_column(linetable, "dX"    ), " ");
00364         passure( cpl_table_has_column(linetable, "Xwidth"), " ");
00365         passure( cpl_table_has_column(linetable, "Y"     ), " ");
00366         passure( cpl_table_has_column(linetable, "Peak"  ), " ");
00367         passure( cpl_table_has_column(linetable, "Background" ), " ");
00368         passure( cpl_table_has_column(linetable, "Slope" ), " ");
00369         
00370     }
00371     return linetable;
00372 }
00373 
00374 /*----------------------------------------------------------------------------*/
00425 /*----------------------------------------------------------------------------*/
00426 static cpl_error_code
00427 detect_lines(const cpl_image *spectrum, const cpl_image *noise, 
00428          const uves_propertylist *spectrum_header, 
00429              bool flat_fielded,
00430          int RANGE, double THRESHOLD, centering_method CENTERING_METHOD, 
00431              int bin_disp,
00432          const polynomial *order_locations, cpl_image *arcframe, 
00433          cpl_table *linetable, 
00434          int *ndetected, int *nrows)
00435 {
00436     int norders;      /* Number of orders */
00437     int minorder;     /* Relative order number of first row in spectrum image */
00438     int MAXLINES;     /* Number of rows in line table (max no. of 
00439              lines to search for) */
00440     int nx;           /* Width of spectrum (and raw image) */
00441     int x, order;     /* 'order' always counts from 1 */
00442     
00443     const double *spectrum_data;
00444     const double *noise_data;
00445 
00446     /* Check input */
00447     passure( spectrum        != NULL, " ");
00448     passure( noise           != NULL, " ");
00449     passure( spectrum_header != NULL, " ");
00450     nx      = cpl_image_get_size_x(spectrum);
00451     norders = cpl_image_get_size_y(spectrum);
00452     
00453     /* For efficiency reasons, get direct pointer to buffer,
00454        support only CPL_TYPE_DOUBLE */
00455     assure( cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE,
00456         CPL_ERROR_UNSUPPORTED_MODE,
00457         "Image type must be double. It is %s", 
00458         uves_tostring_cpl_type(cpl_image_get_type(spectrum)));
00459 
00460     spectrum_data = cpl_image_get_data_double_const(spectrum);
00461     noise_data    = cpl_image_get_data_double_const(noise);
00462 
00463     passure( RANGE > 0, "%d", RANGE);
00464 
00465     if (arcframe != NULL)
00466     {
00467         passure( order_locations != NULL, " ");
00468         passure( nx == cpl_image_get_size_x(arcframe), 
00469              "%d %" CPL_SIZE_FORMAT "", nx, cpl_image_get_size_x(arcframe));
00470     }
00471     
00472     passure( linetable != NULL, " ");
00473     MAXLINES = cpl_table_get_nrow(linetable);
00474     passure( cpl_table_get_ncol(linetable) == 7, "%" CPL_SIZE_FORMAT "",
00475          cpl_table_get_ncol(linetable));
00476     passure( cpl_table_has_column(linetable, "X"     ), " ");
00477     passure( cpl_table_has_column(linetable, "dX"    ), " ");
00478     passure( cpl_table_has_column(linetable, "Xwidth"), " ");
00479     passure( cpl_table_has_column(linetable, "Y"     ), " ");
00480     passure( cpl_table_has_column(linetable, "Peak"  ), " ");
00481     passure( cpl_table_has_column(linetable, "Background" ), " ");
00482     passure( cpl_table_has_column(linetable, "Slope" ), " ");
00483     
00484     assure( THRESHOLD > 0, CPL_ERROR_ILLEGAL_INPUT, "Illegal threshold: %e",
00485         THRESHOLD);
00486 
00487     check( minorder = uves_pfits_get_crval2(spectrum_header), 
00488        "Error reading order number of first row");
00489 
00490     *ndetected = 0;    /* Counts the number of lines detected so far. */
00491     *nrows = 0;        /* A pointer to the first unused row in the
00492                   line table */
00493     
00494     for (order = minorder; order < minorder + norders; order++) {
00495         int spectrum_row = order - minorder + 1;
00496         int ndetected_order = 0;
00497         for (x = 1; x <= nx; x++) {
00498         double flux, dflux;
00499         int peak_width = 0;
00500         int xlo, xhi;
00501         double local_median;
00502         
00503         /* Check if there is a peak and determine its position and width */
00504         // flux = cpl_image_get(spectrum, x, spectrum_row, &pis_rejected);
00505         flux  = spectrum_data[(x-1) + (spectrum_row - 1) * nx];
00506                 dflux = noise_data   [(x-1) + (spectrum_row - 1) * nx];
00507         
00508         xlo = uves_max_int(x - RANGE, 1);
00509         xhi = uves_min_int(x + RANGE, nx);
00510         
00511         local_median = cpl_image_get_median_window(
00512             spectrum,
00513             uves_max_int(xlo, 1 ), spectrum_row,
00514             uves_min_int(xhi, nx), spectrum_row);
00515         
00516         while(x <= nx && 
00517                       (
00518                           (!flat_fielded && flux - local_median > THRESHOLD) 
00519                           ||
00520                           (flat_fielded && (flux - local_median) > THRESHOLD * dflux)
00521                           )
00522                     ) {
00523 #if WANT_BIG_LOGFILE
00524             uves_msg_debug("threshold = %f\tx = %d\tflux = %f\tmedian = %f", 
00525                    THRESHOLD, x, flux, local_median);
00526 #endif
00527             
00528             x += 1;
00529             peak_width += 1;
00530             
00531             if (x <= nx) {
00532             /* flux =
00533                cpl_image_get(spectrum, x,
00534                spectrum_row, &pis_rejected);
00535             */
00536             flux = spectrum_data[(x-1) + (spectrum_row - 1) * nx];
00537             xlo = uves_max_int(x - RANGE, 1);
00538             xhi = uves_min_int(x + RANGE, nx);
00539             local_median = cpl_image_get_median_window(
00540                 spectrum,
00541                 uves_max_int(xlo, 1 ), spectrum_row,
00542                 uves_min_int(xhi, nx), spectrum_row);
00543             }
00544         }
00545         /* x is now first position that is below (median + threshold) */
00546         
00547         if (peak_width > 0) {
00548             double x_peak, dx = 0, sigma, slope, back;
00549             check( x_peak = xcenter(spectrum, noise,
00550                         uves_max_int(1, x - peak_width), 
00551                         /* First position above threshold */ 
00552                         uves_max_int(1, x - 1),          
00553                         /* Last  position above threshold */ 
00554                         spectrum_row,
00555                         CENTERING_METHOD,
00556                                             bin_disp,
00557                         &sigma,
00558                         &flux,
00559                         &dx,
00560                                             &slope,
00561                                             &back),
00562                "Could not locate peak center");
00563             
00564 #if WANT_BIG_LOGFILE
00565             uves_msg_debug("(Order, x, flux) = (%d, %f, %f)", 
00566                    order, x_peak, flux);
00567 #endif        
00568             /* Add line to line table, but only if less
00569                lines that MAXLINES have been detected */
00570             if (*nrows < MAXLINES) {
00571             check(( cpl_table_set_int   (linetable, "Y"     , *nrows, order),
00572                 cpl_table_set_double(linetable, "X"     , *nrows, x_peak),
00573                 cpl_table_set_double(linetable, "dX"    , *nrows, dx),
00574                 cpl_table_set_double(linetable, "Xwidth", *nrows, sigma),
00575                 cpl_table_set_double(linetable, "Peak"  , *nrows, flux),
00576                 cpl_table_set_double(linetable, "Background" , *nrows, back),
00577                 cpl_table_set_double(linetable, "Slope" , *nrows, slope)),
00578                   "Could not update line table row %d", *nrows);
00579             (*nrows)++;
00580             }
00581             
00582             ndetected_order++;
00583             (*ndetected)++;
00584             
00585             if (arcframe != NULL) {
00586             int x1;
00587             int pen = 0;  /* Value to write */
00588             int ny = cpl_image_get_size_y(arcframe);
00589             /* We already know 'nx' from the width of the spectrum image */
00590             
00591             for (x1  = uves_max_int(
00592                  1 , uves_round_double(
00593                      x_peak - peak_width - 0*RANGE/2.0)); 
00594                  x1 <= uves_min_int(
00595                  nx, uves_round_double(
00596                      x_peak + peak_width + 0*RANGE/2.0)); 
00597                  x1++) {
00598                 check( cpl_image_set(
00599                        arcframe,
00600                        x1,
00601                        uves_min_int(
00602                        ny, 
00603                        uves_max_int(
00604                            1, 
00605                            (int) uves_polynomial_evaluate_2d(
00606                            order_locations, x1, order)     
00607                            )), 
00608                        pen),
00609                    "Error writing input image");
00610                 check( cpl_image_set(
00611                        arcframe,
00612                        uves_min_int(
00613                        nx,
00614                        uves_max_int((int) x_peak, 1)),
00615                        uves_min_int(
00616                        ny, 
00617                        uves_max_int(
00618                            1,
00619                            (int) uves_polynomial_evaluate_2d(
00620                            order_locations, x1, order)
00621                            - 10)), 
00622                        pen),
00623                    "Error writing input image");
00624             }
00625             }
00626         } /* line found */
00627         }/* for x */
00628         if (arcframe != NULL) uves_msg_debug("Order #%d: %d lines detected", 
00629                          order, ndetected_order);
00630     }/* for order */
00631     
00632     /* Remove doublets */
00633     {
00634     int i;
00635     int doublets_removed = 0;
00636     for (i = 0; i+1 < *nrows; i++) {
00637         if (fabs(cpl_table_get_double(linetable, "X", i  , NULL) - 
00638              cpl_table_get_double(linetable, "X", i+1, NULL))  < 2.0) 
00639         {
00640             /* If a doublet was found, delete it. 
00641                Make sure the table stays the same size
00642                by adding two rows at the end. */
00643 
00644             check( cpl_table_erase_window(linetable, i, 2),
00645                "Error removing rows");
00646             *nrows -= 2;
00647             *ndetected -= 2;
00648             
00649             check( cpl_table_set_size(linetable, 
00650                           cpl_table_get_nrow(linetable) + 2),
00651                "Could not resize line table");
00652             
00653             doublets_removed++;
00654         }
00655     }
00656     if (doublets_removed > 0)
00657         {
00658         uves_msg_debug("%d doublet%s removed", 
00659                    doublets_removed, doublets_removed > 1 ? "s" : "");
00660         }
00661     }
00662     
00663             uves_msg("Range = %d pixels; threshold = %.2f %s; %d lines detected", 
00664          RANGE, THRESHOLD, flat_fielded ? "stdev" : "ADU", *ndetected);
00665     
00666   cleanup:    
00667     return cpl_error_get_code();
00668 }
00669 
00670 /*----------------------------------------------------------------------------*/
00695 /*----------------------------------------------------------------------------*/
00696 static double
00697 xcenter(const cpl_image *image, const cpl_image *noise, int xlo, int xhi, int row,
00698     centering_method CENTERING_METHOD, int bin_disp,
00699     double *sigma, double *intensity, double *dx0, double *slope, double *background)
00700 {
00701     double x0;           /* Result */
00702     cpl_matrix *covariance = NULL;
00703     const double *image_data;
00704     bool converged;
00705     int lo_r, hi_r;
00706     
00707     int nx = cpl_image_get_size_x(image);
00708 
00709     passure(cpl_image_get_type(image) == CPL_TYPE_DOUBLE, " ");
00710 
00711     image_data = cpl_image_get_data_double_const(image);
00712 
00713     /* Make sure fit window is 13-19 pixels
00714        (7-9 pixels for binned CCD) */
00715     lo_r = 6;
00716     hi_r = 8;
00717     if (bin_disp >= 2) 
00718         {
00719             lo_r = 4;
00720             hi_r = 5;
00721         }
00722 
00723     {
00724         int xm = (xlo+xhi)/2;
00725 
00726         xlo = uves_max_int(1, xm - lo_r);
00727         xhi = uves_min_int(nx, xm + lo_r);
00728     }
00729 
00730     /* Increase fit window (up to 19 pixels) */
00731     do {
00732         converged = true;
00733         if (1 < xlo && 0 <
00734             //cpl_image_get(image, xlo - 1, row, &pis_rejected) &&
00735             //cpl_image_get(image, xlo - 1, row, &pis_rejected) <
00736             //cpl_image_get(image, xlo    , row, &pis_rejected) )
00737             image_data[(xlo-1-1) + (row - 1) * nx] &&
00738             image_data[(xlo-1-1) + (row - 1) * nx] <
00739             image_data[(xlo  -1) + (row - 1) * nx] )
00740             {
00741                 converged = false;
00742                 xlo -= 1;
00743             }
00744         
00745         if (xhi < nx && 0 <
00746             //cpl_image_get(image, xhi + 1, row, &pis_rejected) && 
00747             //cpl_image_get(image, xhi + 1, row, &pis_rejected) <
00748             //cpl_image_get(image, xhi    , row, &pis_rejected) )
00749             image_data[(xhi+1-1) + (row - 1) * nx] &&
00750             image_data[(xhi+1-1) + (row - 1) * nx] <
00751             image_data[(xhi  -1) + (row - 1) * nx] )
00752             {
00753                 converged = false;
00754                 xhi += 1;
00755             }
00756 
00757         if ((xhi-xlo+1) >= hi_r) 
00758             {
00759                 converged = true;
00760             }
00761 
00762     } while (!converged);
00763 
00764     /* Get precise location */
00765     if (CENTERING_METHOD == CENTERING_GAUSSIAN)
00766     {
00767 #if WEIGHTED_FIT
00768         uves_fit_1d_image(image, noise, NULL,
00769 #else /* Unweighted fit like MIDAS which gives larger sigma */
00770         uves_fit_1d_image(image, NULL, NULL,
00771 #endif
00772                   true, false, false,
00773                   xlo, xhi, row,
00774                   &x0, sigma, intensity, background, slope,
00775 #if WEIGHTED_FIT
00776                   NULL, NULL, &covariance,
00777 #else
00778                   NULL, NULL, NULL,
00779 #endif
00780 
00781 #if FIT_SLOPE
00782                               uves_gauss_linear, uves_gauss_linear_derivative, 5);
00783 #else
00784                               uves_gauss, uves_gauss_derivative, 4);
00785             *slope = 0;
00786 #endif
00787 
00788         /* The fitting routine sometimes (i.e. regularly) fails
00789          * because of low statistics.
00790          * Recover from specific fitting errors */
00791         if (cpl_error_get_code() == CPL_ERROR_NONE)
00792         {
00793             /* Variance is guaranteed to be positive */
00794 #if WEIGHTED_FIT
00795             *dx0 = sqrt(cpl_matrix_get(covariance, 0, 0));
00796 #else
00797             *dx0 = *sigma / sqrt(*intensity);
00798 #endif
00799 
00800 #if WANT_BIG_LOGFILE
00801              uves_msg_debug("Gaussian fit succeeded at (x, row, N) = (%f, %d, %d)",
00802                     x0, row, xhi-xlo+1);
00803 #endif
00804         }
00805         else if (cpl_error_get_code() == CPL_ERROR_CONTINUE)
00806         {
00807             /* Fitting failed */
00808             uves_error_reset();
00809 #if WANT_BIG_LOGFILE
00810             uves_msg_debug("Gaussian fit failed at (x, row, N) ="
00811                    " (%f, %d, %d), using centroid", 
00812                    x0, row, xhi-xlo+1);
00813 #endif
00814             *dx0 = *sigma / sqrt(*intensity);
00815         }
00816         else if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
00817         {
00818             uves_error_reset();
00819             
00820             /* Fitting succeeded but covariance computation failed */
00821             uves_msg_debug("Covariance matrix computation failed");
00822             *dx0 = *sigma / sqrt(*intensity);
00823         }
00824         
00825         assure(cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
00826            "Gaussian fitting failed");
00827 
00828 #if WANT_BIG_LOGFILE
00829         uves_msg_debug("Fit   = (x0=%f, sigma=%f, norm=%f, backg=%f, N=%d)", 
00830                x0,
00831                *sigma,
00832                *intensity,
00833                background,
00834                xhi - xlo + 1);
00835 #endif
00836 
00837         /* 'intensity' is the norm (area) of the gaussian fit.
00838            But we need to return the height above zero
00839            (for MIDAS compatibility). 
00840            height = f(x0) = background + norm/sqrt(2pi sigma^2)
00841         */
00842 
00843         *intensity = *background + (*intensity)/(sqrt(2*M_PI) * (*sigma));
00844 
00845     }
00846     else   /*  if (CENTERING_METHOD == CENTERING_GRAVITY) */
00847     {
00848         assure (false, CPL_ERROR_UNSUPPORTED_MODE,
00849             "Centering method (no. %d) is unsupported", 
00850             CENTERING_METHOD);
00851     }
00852 
00853   cleanup:
00854     uves_free_matrix(&covariance);
00855     return x0;
00856 }
00857 

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