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

Generated on 28 Feb 2012 for UVES Pipeline Reference Manual by  doxygen 1.6.1