uves_wavecal_identify.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/07/23 14:57:30 $
00023  * $Revision: 1.28 $
00024  * $Name: uves-3_9_0 $
00025  * $Log: uves_wavecal_identify.c,v $
00026  * Revision 1.28  2007/07/23 14:57:30  jmlarsen
00027  * Make workaround work
00028  *
00029  * Revision 1.27  2007/07/23 12:40:37  jmlarsen
00030  * Update to CPL4
00031  *
00032  * Revision 1.26  2007/06/06 08:17:33  amodigli
00033  * replace tab with 4 spaces
00034  *
00035  * Revision 1.25  2007/05/22 11:46:15  jmlarsen
00036  * Removed 1d wavecal mode which was not supported
00037  *
00038  * Revision 1.24  2007/05/16 16:33:42  amodigli
00039  * fixed leak
00040  *
00041  * Revision 1.23  2007/05/10 08:32:48  jmlarsen
00042  * Minor output message change
00043  *
00044  * Revision 1.22  2007/05/07 14:26:44  jmlarsen
00045  * Added QC.NLINSOL parameter
00046  *
00047  * Revision 1.21  2007/05/07 07:13:59  jmlarsen
00048  * Made resolution computation robust against negative dl/dx
00049  *
00050  * Revision 1.20  2007/04/27 07:22:57  jmlarsen
00051  * Implemented possibility to use automatic polynomial degree
00052  *
00053  * Revision 1.19  2007/04/13 07:34:54  jmlarsen
00054  * Removed dead code
00055  *
00056  * Revision 1.18  2007/04/10 07:12:09  jmlarsen
00057  * Changed interface of polynomial_regression_2d()
00058  *
00059  * Revision 1.17  2007/03/15 12:36:44  jmlarsen
00060  * Added experimental ppm code
00061  *
00062  * Revision 1.16  2007/03/05 10:24:14  jmlarsen
00063  * Do kappa-sigma rejection only in second loop
00064  *
00065  * Revision 1.15  2007/02/22 15:37:35  jmlarsen
00066  * Use kappa-sigma clipping when fitting dispersion
00067  *
00068  * Revision 1.14  2007/01/15 08:58:51  jmlarsen
00069  * Added text output
00070  *
00071  * Revision 1.13  2006/11/06 15:19:42  jmlarsen
00072  * Removed unused include directives
00073  *
00074  * Revision 1.12  2006/10/12 11:36:48  jmlarsen
00075  * Reduced max line length
00076  *
00077  * Revision 1.11  2006/10/10 11:20:11  jmlarsen
00078  * Renamed line table columns to match MIDAS
00079  *
00080  * Revision 1.10  2006/08/17 14:11:25  jmlarsen
00081  * Use assure_mem macro to check for memory allocation failure
00082  *
00083  * Revision 1.9  2006/08/17 13:56:53  jmlarsen
00084  * Reduced max line length
00085  *
00086  * Revision 1.8  2006/08/11 14:36:37  jmlarsen
00087  * Added profiling info
00088  *
00089  * Revision 1.7  2006/08/07 11:35:08  jmlarsen
00090  * Removed hardcoded constant
00091  *
00092  * Revision 1.6  2006/07/14 12:52:57  jmlarsen
00093  * Exported/renamed function find_nearest
00094  *
00095  * Revision 1.5  2006/07/14 12:44:26  jmlarsen
00096  * Use less significant digits
00097  *
00098  * Revision 1.4  2006/04/24 09:33:48  jmlarsen
00099  * Shortened max line length
00100  *
00101  * Revision 1.3  2006/03/03 13:54:11  jmlarsen
00102  * Changed syntax of check macro
00103  *
00104  * Revision 1.2  2006/02/15 13:19:15  jmlarsen
00105  * Reduced source code max. line length
00106  *
00107  * Revision 1.1  2006/02/03 07:46:30  jmlarsen
00108  * Moved recipe implementations to ./uves directory
00109  *
00110  * Revision 1.31  2005/12/20 08:11:44  jmlarsen
00111  * Added CVS  entry
00112  *
00113  */
00114 
00115 /*----------------------------------------------------------------------------*/
00119 /*----------------------------------------------------------------------------*/
00122 #ifdef HAVE_CONFIG_H
00123 #  include <config.h>
00124 #endif
00125 
00126 #include <uves_wavecal_identify.h>
00127 
00128 #include <uves_wavecal_utils.h>
00129 #include <uves_utils.h>
00130 #include <uves_utils_wrappers.h>
00131 #include <uves_error.h>
00132 #include <uves_msg.h>
00133 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 0, 0)
00134 #include <cpl_ppm.h> /* missing from cpl.h */
00135 #else
00136 #include <irplib_ppm.h>
00137 #endif
00138 
00139 #include <cpl.h>
00140 
00141 #include <math.h>
00142 #include <float.h>
00143 
00144 #define USE_PPM 0
00145 
00146 static cpl_error_code verify_calibration(const cpl_table *selected,
00147                                          const cpl_table *linetable, 
00148                      double TOLERANCE,
00149                                          double red_chisq);
00150 static cpl_error_code compute_lambda(cpl_table *linetable, 
00151                      const polynomial *dispersion_relation, 
00152                      const polynomial *dispersion_variance,
00153                                      bool verbose);
00154 
00155 static int identify_lines(cpl_table *linetable, 
00156                           const cpl_table *line_refer, 
00157                           double ALPHA);
00158 
00159 static polynomial *calibrate_global(const cpl_table *linetable,
00160                                     cpl_table **selected,
00161                     int degree, bool verbose,
00162                                     bool reject,
00163                     double TOLERANCE, 
00164                                     double kappa,
00165                     double *red_chisq, 
00166                     polynomial **dispersion_variance,
00167                     double *pixelsize,
00168                     double *rms_wlu,
00169                     double *rms_pixels);
00170 
00171 /*----------------------------------------------------------------------------*/
00211 /*----------------------------------------------------------------------------*/
00212 
00213 polynomial *
00214 uves_wavecal_identify(cpl_table *linetable, 
00215               const cpl_table *line_refer, 
00216               const polynomial *guess_dispersion, 
00217               int DEGREE, double TOLERANCE, 
00218               double ALPHA, double MAXERROR,
00219                       double kappa)
00220 {
00221     polynomial *dispersion_relation = NULL; /* Result */
00222     polynomial *dispersion_variance = NULL; /* Variance of result, 
00223                            written to line table */
00224     int current_id; /* Current and previous number of line identifications */
00225     int previous_id;
00226     int idloop;             /* Number of iterations of grand loop */
00227     int n;                  /* Number of iterations in ID loop */
00228     double pixelsize;       /* Average conversion factor between pixels and wlu */
00229     double red_chisq;       /* Reduced chi^2 of fit         */
00230     cpl_table *selected = NULL;  /* Lines used in final fit */
00231     
00232     passure( linetable        != NULL, " ");
00233     passure( line_refer       != NULL, " ");
00234     passure( guess_dispersion != NULL, " ");
00235 
00236     assure( 0 < ALPHA && ALPHA <= 1, CPL_ERROR_ILLEGAL_INPUT, 
00237         "Illegal alpha = %e", ALPHA);
00238 
00239     /* Calculate LambdaC from the initial dispersion relation */
00240     {
00241     cpl_table_new_column(linetable, LINETAB_LAMBDAC    , CPL_TYPE_DOUBLE);
00242     cpl_table_new_column(linetable, "dLambdaC"         , CPL_TYPE_DOUBLE);
00243     cpl_table_new_column(linetable, LINETAB_PIXELSIZE  , CPL_TYPE_DOUBLE);
00244     cpl_table_new_column(linetable, LINETAB_RESIDUAL   , CPL_TYPE_DOUBLE);
00245     cpl_table_new_column(linetable, "Residual_pix"     , CPL_TYPE_DOUBLE);
00246     cpl_table_new_column(linetable, "Lambda_candidate" , CPL_TYPE_DOUBLE);
00247     cpl_table_new_column(linetable, "dLambda_candidate", CPL_TYPE_DOUBLE);
00248     cpl_table_new_column(linetable, "dLambda_cat_sq"   , CPL_TYPE_DOUBLE);
00249     cpl_table_new_column(linetable, "dLambda_nn_sq"    , CPL_TYPE_DOUBLE);
00250 
00251     /* Create columns 'Ident' and 'dIdent' (uncertainty) and fill with
00252        invalid (no identification made) */
00253     cpl_table_new_column(linetable, "Ident", CPL_TYPE_DOUBLE);
00254     cpl_table_new_column(linetable, "dIdent",CPL_TYPE_DOUBLE);
00255     cpl_table_set_column_invalid(linetable, "Ident", 0, cpl_table_get_nrow(linetable));
00256     cpl_table_set_column_invalid(linetable, "dIdent",0, cpl_table_get_nrow(linetable));
00257     
00258     /* Residuals are not calculated because 'Ident' is invalid */
00259     check( compute_lambda(linetable, guess_dispersion, NULL, false), 
00260            "Error applying dispersion relation");
00261     }
00262 
00263 
00264 #if USE_PPM
00265     for (idloop = 2; idloop <= 2; idloop += 1)
00266 #else
00267     for (idloop = 1; idloop <= 2; idloop += 1)
00268 #endif
00269     {
00270 
00271         current_id = 0;
00272         n = 0;
00273         /* Iterate until no more identifications can be made */
00274         do {
00275         double rms_wlu;
00276         double rms_pixels;
00277                 bool reject = (idloop == 2);
00278 #if USE_PPM
00279                 int nident_ppm;
00280 #endif
00281         
00282         previous_id = current_id;
00283         n++;
00284         
00285         /* Identify lines */
00286         check( current_id = identify_lines(linetable, line_refer, ALPHA), 
00287                "Error identifying lines");
00288 
00289 
00290 #if USE_PPM
00291                 /* Try PPM */
00292                 check( nident_ppm = uves_wavecal_identify_lines_ppm(linetable, line_refer),
00293                        "Error during point pattern matching");
00294 
00295                 cpl_table_erase_column(linetable, "Ident");
00296                 cpl_table_duplicate_column(linetable, "Ident", linetable, "Ident_ppm");
00297                 current_id = nident_ppm;
00298 
00299                 /* FIXME: This only works if 'dIdent' is constant.
00300                    We should propagate error bars during ppm matching */
00301                 cpl_table_fill_column_window(linetable, "dIdent",
00302                                              0, cpl_table_get_nrow(linetable),
00303                                              cpl_table_get_column_mean(linetable, "dIdent"));
00304 #endif
00305 
00306         /* Calibrate with 
00307          * 1st loop: tolerance=infinity (i.e. all identified lines are considered good). 
00308          * 2nd loop: use specified tolerance (ignore outliers)
00309          */
00310         uves_polynomial_delete(&dispersion_relation);
00311         uves_polynomial_delete(&dispersion_variance);
00312 
00313         check( dispersion_relation = calibrate_global(
00314                linetable, NULL,
00315                            DEGREE, false,
00316                            reject,
00317                TOLERANCE,
00318                kappa,
00319                &red_chisq,
00320                &dispersion_variance,
00321                &pixelsize,
00322                &rms_wlu,
00323                &rms_pixels),
00324                "Could not perform global calibration");
00325 
00326         uves_msg_debug("Average pixelsize = %f wlu", pixelsize);
00327                 if (idloop == 1)
00328                     {
00329                         uves_msg("%d identifications made. RMS = %.5f wlu = %.3f "
00330                                  "pixels (no rejection)", 
00331                                  current_id, rms_wlu, rms_pixels);
00332                     }
00333                 else
00334                     {
00335                         uves_msg("%d identifications made. RMS = %.5f wlu = %.3f "
00336                                  "pixels (%f %s rejection, kappa = %.1f)", 
00337                                  current_id, rms_wlu, rms_pixels,
00338                                  fabs(TOLERANCE), (TOLERANCE > 0) ? "pixels" : "wlu",
00339                                  kappa);
00340                     }
00341 #if USE_PPM
00342                 uves_msg("%d identifications from point pattern matching",
00343                          nident_ppm);
00344 #endif
00345         
00346         assure( rms_pixels < MAXERROR, CPL_ERROR_CONTINUE,
00347             "Wavelength calibration did not converge. "
00348             "After %d iterations the RMS was %f pixels. "
00349             "Try to improve on the initial solution", n, rms_pixels);
00350         
00351 
00352         /* Apply calibration result */
00353         check( compute_lambda(linetable, dispersion_relation, dispersion_variance,
00354                                       false),
00355                "Error applying dispersion relation");
00356 
00357 
00358         }
00359         while (current_id > previous_id) ;
00360 
00361 
00362 
00363         if (idloop == 1)
00364         {
00365             /* 
00366              * Remove all identifications and repeat
00367              */
00368             
00369             uves_msg("Identification loop converged. Resetting identifications");
00370             cpl_table_set_column_invalid(linetable, "Ident", 0, 
00371                          cpl_table_get_nrow(linetable));
00372         }
00373     }
00374 
00375     /* Calibrate again with a global polynomial, but this time don't
00376        use lines with residuals worse than TOLERANCE */
00377     uves_polynomial_delete(&dispersion_relation);
00378     uves_polynomial_delete(&dispersion_variance);
00379     uves_free_table(&selected);
00380     
00381     check( dispersion_relation = calibrate_global(linetable,
00382                                                   &selected,
00383                                                   DEGREE, true,
00384                                                   true,  /* do rejection? */
00385                                                   TOLERANCE,
00386                                                   kappa,
00387                                                   &red_chisq,
00388                                                   &dispersion_variance,
00389                                                   NULL, NULL, NULL),
00390            "Could not perform global calibration");
00391     
00392     /* Update the computed wavelengths */
00393     check( compute_lambda(linetable, dispersion_relation, dispersion_variance,
00394                           true), 
00395            "Error applying dispersion relation");
00396     
00397     /* Add columns 'Select' and 'NLinSol' to linetable.
00398        The columns defines which lines were identified,
00399        and which lines were used in the final fit */
00400     {
00401         int i, j;
00402 
00403         /* Tables are sorted by Order, X */
00404 
00405         cpl_table_new_column(linetable, "NLinSol", CPL_TYPE_INT);
00406         cpl_table_new_column(linetable, "Select", CPL_TYPE_INT);
00407 
00408         cpl_table_fill_column_window_int(linetable, "NLinSol", 
00409                                          0, cpl_table_get_nrow(linetable),
00410                                          0);
00411         cpl_table_fill_column_window_int(linetable, "Select", 
00412                                          0, cpl_table_get_nrow(linetable),
00413                                          0);
00414 
00415         j = 0;
00416         for (i = 0; i < cpl_table_get_nrow(selected); i++) {
00417             int order = cpl_table_get_int(selected, "Order", i, NULL);
00418             double  x = cpl_table_get_double(selected, "X", i, NULL);
00419             int order2;
00420             double x2;
00421 
00422             /* Find this line in the original linetable */
00423             passure( j < cpl_table_get_nrow(linetable), "%d %d",
00424                      j, cpl_table_get_nrow(linetable));
00425             do {
00426                 order2 = cpl_table_get_int(linetable, "Order", j, NULL);
00427                 x2     = cpl_table_get_double(linetable, "X", j, NULL);
00428                 if (cpl_table_is_valid(linetable, "Ident", j))
00429                     {
00430                         cpl_table_set_int(linetable, "Select", j, 1);
00431                     }
00432                 j++;
00433 
00434             } while (order2 < order || x2 < x - 0.1);
00435             
00436             passure( order2 == order && fabs(x2 - x) < 0.1,
00437                      "%d %d %g %g", order2, order, x2, x);
00438             
00439             cpl_table_set_int(linetable, "NLinSol", j-1, 1);
00440         }
00441     }
00442 
00443     /* Display results */
00444     check( verify_calibration(selected, linetable, TOLERANCE, red_chisq), 
00445        "Error verifying calibration");
00446     
00447   cleanup:
00448     uves_free_table(&selected);
00449     uves_polynomial_delete(&dispersion_variance);
00450     return dispersion_relation;
00451 }
00452 
00453 /*----------------------------------------------------------------------------*/
00467 /*----------------------------------------------------------------------------*/
00468 static cpl_error_code
00469 verify_calibration(const cpl_table *selected,
00470                    const cpl_table *linetable, double TOLERANCE,
00471                    double red_chisq)
00472 {
00473     cpl_table *brightest  = NULL;
00474     double median_intensity;
00475     int ninvalid;    /* Number of unidentified lines among the brightest half */
00476     double ratio;
00477     double rms_wlu;
00478     double rms_pixels;
00479     
00480     {
00481     double mean;
00482     double stdev;
00483     
00484     check(( mean = cpl_table_get_column_mean (selected, LINETAB_RESIDUAL),
00485         stdev= cpl_table_get_column_stdev(selected, LINETAB_RESIDUAL),
00486         rms_wlu = sqrt(mean*mean + stdev*stdev),
00487         
00488         mean = cpl_table_get_column_mean (selected, "Residual_pix"),
00489         stdev= cpl_table_get_column_stdev(selected, "Residual_pix"),
00490         rms_pixels = sqrt(mean*mean + stdev*stdev)),
00491           "Error reading RMS of fit");
00492     }
00493     
00494     uves_msg("%d lines accepted", cpl_table_get_nrow(selected));
00495     uves_msg("Average RMS of calibration (tolerance = %.3f %s) = %.5f wlu = %.4f pixels ~ %.1f m/s",
00496          fabs(TOLERANCE),
00497          (TOLERANCE > 0) ? "pixels" : "wlu",
00498          rms_wlu, rms_pixels, 
00499              rms_wlu * SPEED_OF_LIGHT/cpl_table_get_column_mean(selected,
00500                                                                 LINETAB_LAMBDAC));
00501 
00502     uves_msg("Reduced chi^2 of calibration = %f", red_chisq);
00503 
00504     if (red_chisq < .01)
00505     {
00506         uves_msg_warning("Reduced chi^2 of fit is less than 1/100: %f", 
00507                  red_chisq);
00508     }
00509     if (red_chisq > 100)
00510     {
00511         uves_msg_warning("Reduced chi^2 of fit is greater than 100: %f", 
00512                  red_chisq);
00513     }
00514     
00515     check(( median_intensity = cpl_table_get_column_median(linetable, "Peak"),
00516         brightest = uves_extract_table_rows(linetable, "Peak", 
00517                         CPL_GREATER_THAN, 
00518                         median_intensity),
00519         ninvalid = cpl_table_count_invalid(brightest, "Ident")),
00520       "Error counting identifications");
00521 
00522     ratio = 1 - ((double) ninvalid)/cpl_table_get_nrow(brightest);
00523     uves_msg("Percentage of identifications among the half brighter lines : %.2f %%",
00524          100*ratio);
00525 
00526   cleanup:
00527     uves_free_table(&brightest);
00528 
00529     return cpl_error_get_code();
00530 }
00531 
00532 /*----------------------------------------------------------------------------*/
00546 /*----------------------------------------------------------------------------*/
00547 static cpl_error_code
00548 compute_lambda(cpl_table *linetable, 
00549            const polynomial *dispersion_relation, 
00550            const polynomial *dispersion_variance,
00551                bool verbose)
00552 {
00553     int i;
00554     bool printed_warning = false;
00555     
00556     /* Check input */
00557     passure(linetable           != NULL, " ");
00558     passure(dispersion_relation != NULL, " ");
00559     /* 'dispersion_variance' may be NULL */
00560     
00561     passure( uves_polynomial_get_dimension(dispersion_relation) == 2, "%d", 
00562          uves_polynomial_get_dimension(dispersion_relation));
00563     
00564     /* Input columns */
00565     passure(cpl_table_has_column(linetable, "X")           , " ");
00566     passure(cpl_table_has_column(linetable, "Order")       , " ");
00567     passure(cpl_table_has_column(linetable, "Ident")       , " ");
00568     /* Output columns */
00569     passure(cpl_table_has_column(linetable, LINETAB_LAMBDAC)     , " ");
00570     /* The column 'dLambdaC' is set to invalid if 'dispersion_variance' is NULL */
00571     passure(cpl_table_has_column(linetable, "dLambdaC")    , " ");  
00572     passure(cpl_table_has_column(linetable, "dIdent")      , " ");
00573     passure(cpl_table_has_column(linetable, LINETAB_RESIDUAL), " ");
00574     passure(cpl_table_has_column(linetable, "Residual_pix"), " ");
00575     passure(cpl_table_has_column(linetable, LINETAB_PIXELSIZE)   , " ");
00576     
00577     /* The linetable is sorted w.r.t. order. 
00578        Move to the first order above minorder */
00579     for(i = 0; i < cpl_table_get_nrow(linetable); i++)
00580     {
00581         int order;
00582         double x, dfdx;
00583         double lambdac, dlambdac, pixelsize;
00584         order = cpl_table_get_int(linetable, "Order", i, NULL);
00585         
00586         x     = cpl_table_get_double(linetable, "X", i, NULL);
00587         
00588         /* Evaluate the dispersion relation
00589            m.lambda = f(x,m)  (2d global fit)  */
00590         
00591         lambdac =
00592         uves_polynomial_evaluate_2d(dispersion_relation, x, order) / order;
00593         
00594         /* Pixelsize = dl/dx = (df/dx)/m  (for fixed m) */
00595             dfdx = uves_polynomial_derivative_2d(dispersion_relation, x, order, 1);
00596             if (dfdx < 0) {
00597                 if (!printed_warning && verbose) {
00598                     uves_msg_warning("Inferred dispersion (dlambda/dx) is negative at"
00599                                      "(x, order) = (%f, %d)", x, order);
00600                     printed_warning = true;  /* To avoid repeating the same warning */
00601                 }
00602                 else {
00603                     uves_msg_debug("Inferred dispersion (dlambda/dx) is negative at "
00604                                    "(x, order) = (%f, %d)", x, order);
00605                 }
00606             }
00607             pixelsize = dfdx / order;
00608         
00609         check(( cpl_table_set_double(linetable, LINETAB_LAMBDAC , i, lambdac),
00610             cpl_table_set_double(linetable, LINETAB_PIXELSIZE, i, pixelsize)),
00611             "Error writing table");
00612         
00613         if (dispersion_variance != NULL)
00614         {
00615             /* d( lambda  (x, order) ) = 
00616                d( lambda*m(x, order) ) / m    */
00617             dlambdac = 
00618             sqrt(uves_polynomial_evaluate_2d(dispersion_variance, x, order))
00619             / order;
00620             
00621             cpl_table_set_double(linetable, "dLambdaC" , i, dlambdac);
00622         }
00623         else
00624         {
00625             /* Only the ratio of a line's "dLambdaC" to other
00626                lines' are used, so set "dLambdaC" to a constant value
00627                when the actual uncertainty is not known
00628             */
00629             cpl_table_set_double(linetable, "dLambdaC" , i, 1.0);
00630         }
00631         
00632         /* If line is identified, calculate residual */
00633         if (cpl_table_is_valid(linetable, "Ident", i)) 
00634         {
00635             double ident = cpl_table_get_double(linetable, "Ident", i, NULL);
00636             cpl_table_set_double(linetable, LINETAB_RESIDUAL, i,
00637                      ident - lambdac);
00638             cpl_table_set_double(linetable, "Residual_pix", i, 
00639                      (ident - lambdac)/pixelsize);
00640         }
00641         else
00642         {
00643             cpl_table_set_invalid(linetable, LINETAB_RESIDUAL, i);
00644             cpl_table_set_invalid(linetable, "Residual_pix", i);
00645         }
00646     }
00647     
00648     /* Sort by 'Order' (ascending), then 'X' (ascending) */
00649     check( uves_sort_table_2(linetable, "Order", "X", false, false), 
00650        "Error sorting table");
00651     
00652   cleanup:
00653     return cpl_error_get_code();
00654 }
00655 
00656 
00657 /*----------------------------------------------------------------------------*/
00694 /*----------------------------------------------------------------------------*/
00695 
00696 static int
00697 identify_lines(cpl_table *linetable, const cpl_table *line_refer, double ALPHA)
00698 {
00699     int number_identifications = 0;      /* Result */
00700     int linetable_size;
00701     int linerefer_size;
00702     int row;
00703     int *histogram = NULL;
00704     const double minlog  = -5.0;         /* Histogram (it's sort of ugly
00705                         to hardcode these numbers, but
00706                         as long as it works, ...) */
00707     const double maxlog  = 15.0;
00708     const int nbins       = 400;
00709     double error = 0;                    /* Dimensionless factor
00710                         that controls IDs */
00711     double average_dlambda_com = 0;      /* Average of uncertainty of 
00712                         predicted wavelenghts */
00713 
00714     /* Check input */
00715     passure( linetable  != NULL, " ");
00716     /* Line table input columns */
00717     passure( cpl_table_has_column(linetable, LINETAB_LAMBDAC  ), " "); /* Predicted
00718                                       wavelength  */
00719     passure( cpl_table_has_column(linetable, "dLambdaC" ), " "); /* Predicted wavelength 
00720                                     uncertainty  */
00721     passure( cpl_table_has_column(linetable, "X"        ), " "); /* Line position, used
00722                                     only for messaging */
00723     passure( cpl_table_has_column(linetable, "Order"    ), " "); /* Absolute order number 
00724                                     of line */
00725     passure( cpl_table_has_column(linetable, "Xwidth"   ), " "); /* Line width (sigma) */
00726     passure( cpl_table_has_column(linetable, LINETAB_PIXELSIZE), " "); /* Pixelsize */
00727 
00728     /* Line table output columns */
00729     passure( cpl_table_has_column(linetable, "Ident"    ), " "); /* Identified catalogue 
00730                                     wavelength */
00731     passure( cpl_table_has_column(linetable, "dIdent"   ), " "); /* Uncertainty of IDed
00732                                     catalogue wavelength */
00733 
00734     /* Catalogue */
00735     passure( line_refer != NULL, " ");
00736     passure( cpl_table_has_column(line_refer, "Wave" ), " ");    /* Catalogue wavelength */
00737     passure( cpl_table_has_column(line_refer, "dWave"), " ");    /* Uncertainty of
00738                                     catalogue wavelength */
00739     
00740     linetable_size = cpl_table_get_nrow(linetable);
00741     linerefer_size = cpl_table_get_nrow(line_refer);
00742     assure(linerefer_size >= 1, CPL_ERROR_ILLEGAL_INPUT, "Empty line reference table");
00743     
00744     /* Parameter */
00745     passure( 0 < ALPHA && ALPHA <= 1, "%e", ALPHA);
00746 
00747     /* Get average uncertainty of predicted wavelength */
00748     average_dlambda_com = cpl_table_get_column_median(linetable, "dLambdaC");
00749 
00750     /* Initialize histogram to zero */
00751     histogram = cpl_calloc(nbins, sizeof(int));
00752     assure_mem( histogram );
00753     
00754 
00755     /* First: Find distance to closest catalogue match, 
00756        distance to nearest neighbour, 
00757        and calculate histogram (to get average of distances to nearest neighbour) */
00758     for (row = 0; row < linetable_size; row++) {
00759     double lambda_com;                 /* Computed (predicted) wavelength */
00760     double line_width;                 /* Line width (sigma) in wlu       */
00761     double line_fwhm;                  /* Line FWHM in wlu                */
00762     int order;                         /* (Absolute) order of detected wavelength */
00763     double lambda_cat;                 /* Catalogue wavelength */
00764     double lambda_cat_sigma;           /* Catalogue wavelength uncertainty */
00765     double distance_cat_sq;            /* Distance to catalogue wavelength (squared) */
00766     double nn_distance_sq;             /* Distance to nearest neighbour (squared) */
00767     int row_cat;                       /* Row number of best matching catalogue wavelength */
00768     
00769     /* Read line table */
00770     lambda_com  = cpl_table_get_double(linetable, LINETAB_LAMBDAC   , row, NULL);
00771     order       = cpl_table_get_int   (linetable, "Order"     , row, NULL);
00772 
00773     
00774     line_width = 
00775         cpl_table_get_double(linetable, "Xwidth"    , row, NULL) *
00776         fabs(cpl_table_get_double(linetable, LINETAB_PIXELSIZE , row, NULL)); 
00777     /* Convert pixel->wlu */
00778 
00779     line_fwhm = TWOSQRT2LN2 * line_width;
00780     
00781     /* Find closest match in catalogue */
00782     row_cat          = uves_wavecal_find_nearest(
00783         line_refer, lambda_com, 0, linerefer_size - 1);
00784     lambda_cat       = cpl_table_get_double(line_refer, "Wave", row_cat, NULL);
00785     lambda_cat_sigma = cpl_table_get_double(line_refer, "dWave",row_cat, NULL);
00786 
00787     /* Distance to closest match */
00788     distance_cat_sq = (lambda_com - lambda_cat)*(lambda_com - lambda_cat);
00789     
00790         /* Determine the distance to the next neighbour
00791      * There are (max) 4 candiates: 2 neigbours in spectrum (i.e. line table)
00792      *                          and 2 neigbours in line catalogue
00793      */
00794     {
00795         double lambda_com_prev, lambda_com_next;
00796         int order_prev, order_next;
00797         double lambda_cat_prev, lambda_cat_next;
00798 
00799         nn_distance_sq = DBL_MAX;
00800 
00801         /* Read previous and next rows of line table */
00802         if (row >= 1) 
00803         {
00804             order_prev      = cpl_table_get_int   (
00805             linetable, "Order"  , row - 1, NULL);
00806             lambda_com_prev = cpl_table_get_double(
00807             linetable, LINETAB_LAMBDAC, row - 1, NULL);
00808             
00809             if (order == order_prev) 
00810             {
00811                 nn_distance_sq = uves_min_double(nn_distance_sq,
00812                                  (lambda_com_prev - lambda_com)*
00813                                  (lambda_com_prev - lambda_com)
00814                 );
00815             }
00816         }
00817 
00818         if (row <= linetable_size - 2) 
00819         {
00820             order_next      = cpl_table_get_int   (linetable, "Order", 
00821                                row + 1, NULL);
00822             lambda_com_next = cpl_table_get_double(linetable, LINETAB_LAMBDAC,
00823                                row + 1, NULL);
00824             
00825             if (order == order_next) 
00826             {
00827                 nn_distance_sq = uves_min_double(nn_distance_sq,
00828                                  (lambda_com_next - lambda_com)*
00829                                  (lambda_com_next - lambda_com)
00830                 );
00831             }
00832         }
00833         
00834         /* Read previous and next rows of catalogue */
00835         if (row_cat >= 1)
00836         {
00837             lambda_cat_prev = cpl_table_get_double(
00838             line_refer, "Wave", row_cat - 1, NULL);
00839 
00840             nn_distance_sq = uves_min_double(
00841             nn_distance_sq,
00842             (lambda_cat_prev - lambda_cat)*
00843             (lambda_cat_prev - lambda_cat)
00844             );
00845         }
00846         if (row_cat <= linerefer_size - 2) 
00847         {
00848             lambda_cat_next = cpl_table_get_double(
00849             line_refer, "Wave", row_cat + 1, NULL);
00850 
00851             nn_distance_sq = uves_min_double(
00852             nn_distance_sq,
00853             (lambda_cat_next - lambda_cat)*
00854             (lambda_cat_next - lambda_cat)
00855             );
00856         }
00857 
00858         /* Update distance to nearest neighbour with a 
00859            safety margin (determined by parameter ALPHA < 1) */
00860         if (nn_distance_sq < DBL_MAX)
00861         {
00862             nn_distance_sq *= ALPHA*ALPHA;
00863         }
00864         
00865     }/* Find next neighbour */
00866     
00867     /* Update line table */
00868     cpl_table_set_double(linetable, "Lambda_candidate", row, lambda_cat);
00869     cpl_table_set_double(linetable, "dLambda_candidate",row, lambda_cat_sigma);
00870     cpl_table_set_double(linetable, "dLambda_cat_sq", row, distance_cat_sq);
00871     cpl_table_set_double(linetable, "dLambda_nn_sq", row, nn_distance_sq);
00872 
00873     /* Update histogram with the interval
00874        [distance_cat_sq ; nn_distance_sq]  (in units of line_fwhm) */
00875     {
00876         int ilow  = uves_round_double((0.5*log(distance_cat_sq/(line_fwhm*line_fwhm))
00877                        - minlog)/(maxlog - minlog) * nbins);
00878         int ihigh = uves_round_double((0.5*log(nn_distance_sq /(line_fwhm*line_fwhm))
00879                        - minlog)/(maxlog - minlog) * nbins);
00880         int i;
00881         
00882         for (i = uves_max_int(ilow, 0); i < uves_min_int(ihigh, nbins); i++) 
00883         {
00884             histogram[i] += 1;
00885         }
00886     }
00887     }/* ... finding neighbours */
00888     
00889     /* Determine error as peak of histogram */
00890     {
00891     int i;
00892     int maxfreq = -1;
00893     for (i = 0; i < nbins; i++) 
00894         {
00895         uves_msg_debug("histogram[%d] = %d", i, histogram[i]);
00896         if (histogram[i] > maxfreq) 
00897             {
00898             maxfreq = histogram[i];
00899             error   = exp( i / ((double)nbins) * (maxlog - minlog) + minlog ) ;
00900             /* == the dimensionless factor to be multiplied by Xwidth */
00901             }
00902         }
00903     uves_msg_debug("Dimensionless error factor is %f", error);
00904     }
00905     
00906     /* Sketch of situation:
00907        
00908   lambda_com                  Nearest neighbour
00909 
00910       |                            |
00911       |    |                       |
00912       |    |                       |
00913       |    |                       |
00914            |
00915 
00916     lambda_cat
00917 
00918 
00919      The 'average' (as inferred from the histogram)
00920      midpoint between 'lambda_cat' and 'nearest neighbour'
00921      is at   'error' * 'line_fwhm' .
00922     */
00923     
00924     /* Make the identification if
00925        
00926     1) the catalogue candidate is within two sigma:
00927          | lambda_cat - lambda_com | < 2 * dlambda_com
00928 
00929     and
00930 
00931     2) after multiplying the distance to the nearest neighbour by ALPHA < 1,
00932     the nearest neighbour is farther away than the catalogue wavelength 
00933          distance_nn  >  distance_cat
00934     and farther away than the tolerance
00935          distance_nn  >  line_fwhm * error
00936      
00937     */
00938     for (row = 0; row < linetable_size; row++)
00939     {
00940         double distance_cat_sq;              /* Distance to catalogue wavelength (squared) */
00941         double nn_distance_sq;               /* Distance to nearest neighbour (squared) */
00942         double tolerance_sq;
00943         double dlambda_com;
00944         double line_width;                   /* Line width (1 sigma) */
00945         double line_fwhm;
00946         double lambda_cat;
00947         double lambda_cat_sigma;             /* Uncertainty of lambda_cat */
00948         
00949         lambda_cat       = cpl_table_get_double(linetable,  "Lambda_candidate", row, NULL);
00950         lambda_cat_sigma = cpl_table_get_double(linetable, "dLambda_candidate", row, NULL);
00951         
00952         
00953         /* Sigma less than 1 pixel is usually not
00954            justified by the data (which obviously 
00955            has a resolution of only 1 pixel). Such
00956            an underenstimation of the uncertainty
00957            leads to wrong identifications.
00958            Therefore use a width of at least 1 pixel */
00959         line_width =
00960         uves_max_double(1, cpl_table_get_double(linetable, "Xwidth"    , row, NULL)) *
00961         fabs(cpl_table_get_double(linetable, LINETAB_PIXELSIZE , row, NULL));
00962         /* convert to wlu */
00963         
00964         line_fwhm = TWOSQRT2LN2 * line_width;
00965 
00966         /* As the uncertainty of the computed wavelength is used
00967          *  line_fwhm (in w.l.u.)
00968          * To take into account the fact that lines near the edge of
00969          * the chip have larger error of the computed wavelength,
00970          * this is also scaled according to the accuracy of the dispersion
00971          * relation, i.e. multiplied by  dl/<dl>,
00972          * where <dl> is an average, say the median, of uncertainties of
00973          * all predicted wavelengths.
00974          */
00975         
00976         dlambda_com = line_fwhm 
00977         * cpl_table_get_double(linetable, "dLambdaC"  , row, NULL)
00978         / average_dlambda_com;
00979         
00980         tolerance_sq = line_fwhm*line_fwhm * error*error;
00981         
00982         distance_cat_sq = cpl_table_get_double(linetable, "dLambda_cat_sq", row, NULL);
00983         nn_distance_sq  = cpl_table_get_double(linetable, "dLambda_nn_sq" , row, NULL);
00984         
00985 #if WANT_BIG_LOGFILE
00986         uves_msg_debug("(order,x) = (%d,%f) lcom = %f+-%f lcat = %f "
00987                "dist_cat = %f (%f pixels) tolerance = %.3f error = %f "
00988                "nn = %f (%f pixels)", 
00989                cpl_table_get_int   (linetable, "Order"  , row, NULL),
00990                cpl_table_get_double(linetable, "X"      , row, NULL),
00991                cpl_table_get_double(linetable, LINETAB_LAMBDAC, row, NULL),
00992                dlambda_com,
00993                lambda_cat,
00994                sqrt(distance_cat_sq),
00995                sqrt(distance_cat_sq)
00996                /cpl_table_get_double(linetable, LINETAB_PIXELSIZE, row, NULL),
00997                sqrt(tolerance_sq),
00998                error,
00999                sqrt(nn_distance_sq),
01000                sqrt(nn_distance_sq)
01001                /cpl_table_get_double(linetable, LINETAB_PIXELSIZE, row, NULL));
01002 #endif
01003         
01004         /* Make the ID? */
01005         if (distance_cat_sq < (dlambda_com)*(dlambda_com)
01006         && tolerance_sq < nn_distance_sq
01007         && distance_cat_sq < nn_distance_sq)
01008         {
01009             number_identifications++;
01010             cpl_table_set_double(linetable, "Ident", row, lambda_cat);
01011             cpl_table_set_double(linetable, "dIdent",row, lambda_cat_sigma);
01012 #if WANT_BIG_LOGFILE
01013             uves_msg_debug("ID made");
01014 #endif
01015         }
01016         else 
01017         {
01018             if (cpl_table_is_valid(linetable, "Ident", row)) {
01019             number_identifications++;                      
01020             /* Also count lines that were already identified */
01021             uves_msg_debug("Line at (%d,%f) does not match ID criterion anymore",
01022                        cpl_table_get_int   (linetable, "Order", row, NULL),
01023                        cpl_table_get_double(linetable, "X", row, NULL)
01024             );
01025         }
01026         }
01027     }
01028 
01029   cleanup:
01030     cpl_free(histogram);
01031     return number_identifications;
01032 }
01033 
01034 /*----------------------------------------------------------------------------*/
01060 /*----------------------------------------------------------------------------*/
01061 static polynomial *
01062 calibrate_global(const cpl_table *linetable,
01063                  cpl_table **selected,
01064          int degree, bool verbose,
01065                  bool reject,
01066          double TOLERANCE,
01067                  double kappa,
01068          double *red_chisq, polynomial **dispersion_variance,
01069          double *pixelsize,
01070          double *rms_wlu,
01071          double *rms_pixels)
01072 {
01073     polynomial *dispersion_relation = NULL; /* Result */
01074     cpl_table *identified = NULL;
01075     int valid_ids = 
01076     cpl_table_get_nrow(linetable) - 
01077     cpl_table_count_invalid(linetable, "Ident");
01078     int rejected;
01079     
01080     passure( (pixelsize == NULL) == (rms_wlu    == NULL) &&
01081          (pixelsize == NULL) == (rms_pixels == NULL), " ");
01082 
01083     assure( degree < 0 ||
01084             valid_ids >= (degree + 1)*(degree + 1), CPL_ERROR_ILLEGAL_INPUT,
01085         "There are not enough identifications to create a %d.-degree global fit. "
01086         "%d needed. %d found", degree, (degree + 1)*(degree + 1), valid_ids);
01087     
01088     identified = cpl_table_duplicate(linetable);
01089     assure_mem(identified);
01090 
01091     /* Delete rows with invalid 'Ident' and large residuals */
01092     if (reject)
01093         {
01094             check_nomsg( rejected = uves_delete_bad_lines(identified, TOLERANCE, kappa) );
01095             uves_msg_debug("%d lines rejected %f %f", rejected, TOLERANCE, kappa);
01096         }
01097     else
01098         {
01099             check( uves_erase_invalid_table_rows(identified, "Ident"),
01100                    "Error erasing un-identified lines");
01101         }
01102 
01103     
01104     /* Create column 'Aux' = 'Order' * 'Ident' */
01105     check((  cpl_table_duplicate_column(identified, "Aux", identified, "Ident"),
01106              cpl_table_multiply_columns(identified, "Aux", "Order"),
01107              
01108              /* Create column 'dAux' = 'Order' * 'dIdent' */
01109              cpl_table_duplicate_column(identified, "dAux", identified, "dIdent"),
01110              cpl_table_multiply_columns(identified, "dAux", "Order")),
01111           "Error setting up temporary table");
01112 
01113     /* Fit */
01114     
01115     if (degree >= 0) {
01116         check( dispersion_relation =
01117                uves_polynomial_regression_2d(identified, 
01118                                              "X", "Order", "Aux", 
01119                                              "dAux", /* Use "dAux" for weighting,
01120                                                         to be able to compute an uncertainty
01121                                                         of WAVEC.
01122                                                         
01123                                                         It would probably make more sense
01124                                                         to use the uncertainty of 'dX' for
01125                                                         weighting. */
01126                                              degree, degree,
01127                                              NULL, NULL, NULL,     /* Don't add extra columns */
01128                                              NULL,                 /* mse */
01129                                              red_chisq,
01130                                              dispersion_variance, 
01131                                              reject ? kappa : -1, -1),
01132                "Error fitting polynomial. Possible cause: too few (%d) "
01133                "line identifications", valid_ids);
01134     } 
01135     else {
01136         int max_degree = 8;
01137         double min_rms = -1; /* disabled */
01138         double min_reject = -1; /* disabled */
01139         check( dispersion_relation =
01140                uves_polynomial_regression_2d_autodegree(identified,
01141                                                         "X", "Order", "Aux", 
01142                                                         "dAux", 
01143                                                         NULL, NULL, NULL,  
01144                                                         NULL, 
01145                                                         red_chisq,
01146                                                         dispersion_variance,
01147                                                         reject ? kappa : -1,
01148                                                         max_degree, max_degree, 
01149                                                         min_rms, min_reject,
01150                                                         verbose,
01151                                                         NULL, NULL, 0, NULL),
01152                "Error fitting polynomial. Possible cause: too few (%d) "
01153                "line identifications", valid_ids);
01154     }
01155 
01156     if (pixelsize != NULL)
01157     {
01158         /* Compute parameters if requested */
01159 
01160         check( compute_lambda(identified, dispersion_relation, NULL,
01161                                   false),
01162            "Error applying dispersion relation");
01163         
01164         *pixelsize = cpl_table_get_column_median(identified, LINETAB_PIXELSIZE);
01165         *rms_wlu   = cpl_table_get_column_stdev (identified, LINETAB_RESIDUAL);
01166         *rms_pixels= cpl_table_get_column_stdev (identified, "Residual_pix");
01167     }
01168 
01169     if (selected != NULL) {
01170         *selected = cpl_table_duplicate(identified);
01171     }
01172 
01173   cleanup:
01174     uves_free_table(&identified);
01175     if (cpl_error_get_code() != CPL_ERROR_NONE)
01176     {
01177         uves_polynomial_delete(&dispersion_relation);
01178     }
01179     
01180     return dispersion_relation;
01181 }
01182 
01183 
01184 
01185 /*----------------------------------------------------------------------------*/
01192 /*----------------------------------------------------------------------------*/
01193 
01194 int
01195 uves_wavecal_identify_lines_ppm(cpl_table *linetable, const cpl_table *line_refer)
01196 {
01197     int result = 0;
01198     int minorder, maxorder;
01199     int order;
01200     cpl_table *lt_order = NULL;
01201     cpl_table *refer_order = NULL;
01202     cpl_vector *peaks = NULL;
01203     cpl_vector *lines = NULL;
01204     cpl_bivector *ids = NULL;
01205 
01206     assure( cpl_table_has_column(linetable, LINETAB_LAMBDAC), CPL_ERROR_DATA_NOT_FOUND,
01207             "Missing column %s", LINETAB_LAMBDAC);
01208 
01209     assure( cpl_table_has_column(linetable, LINETAB_PIXELSIZE), CPL_ERROR_DATA_NOT_FOUND,
01210             "Missing column %s", LINETAB_PIXELSIZE);
01211 
01212     assure( cpl_table_has_column(linetable, "Order"), CPL_ERROR_DATA_NOT_FOUND,
01213             "Missing column %s", "Order");
01214 
01215     minorder = uves_round_double( cpl_table_get_column_min(linetable, "Order"));
01216     maxorder = uves_round_double( cpl_table_get_column_max(linetable, "Order"));
01217 
01218     /* Reset identifications */
01219     if (cpl_table_has_column(linetable, "Ident_ppm"))
01220         {
01221             cpl_table_erase_column(linetable, "Ident_ppm");
01222         }
01223 
01224     cpl_table_new_column(linetable, "Ident_ppm", CPL_TYPE_DOUBLE);
01225     
01226     for (order = minorder; order <= maxorder; order++)
01227         {
01228             const double tolerance = 0.05; /* relative tolerance on interval ratios */
01229             double min_lambda, max_lambda;
01230             double min_disp, max_disp;
01231 
01232             /* Extract current order */
01233            
01234             uves_free_table(&lt_order);
01235             lt_order = uves_extract_table_rows(linetable, "Order",
01236                                                CPL_EQUAL_TO, order); /* Uses integer comparison */
01237 
01238             check_nomsg((min_lambda = cpl_table_get_column_min(lt_order, LINETAB_LAMBDAC),
01239                          max_lambda = cpl_table_get_column_max(lt_order, LINETAB_LAMBDAC),
01240                          min_disp   = cpl_table_get_column_min(lt_order, LINETAB_PIXELSIZE)*0.99,
01241                          max_disp   = cpl_table_get_column_max(lt_order, LINETAB_PIXELSIZE)*1.01));
01242                         
01243             uves_free_table(&refer_order);
01244             refer_order = uves_extract_table_rows(line_refer, "Wave", CPL_GREATER_THAN,
01245                                                   min_lambda);
01246             uves_extract_table_rows_local(refer_order, "Wave", CPL_LESS_THAN,
01247                                           max_lambda);
01248 
01249             /* Convert to vectors */
01250             {
01251                 int i;
01252                 uves_free_vector(&peaks);
01253                 peaks = cpl_vector_new(cpl_table_get_nrow(lt_order));
01254                 for (i = 0; i < cpl_vector_get_size(peaks); i++)
01255                     {
01256                         cpl_vector_set(peaks, i, cpl_table_get_double(lt_order, "X", i, NULL));
01257                     }
01258                 
01259                 uves_free_vector(&lines);
01260                 lines = cpl_vector_new(cpl_table_get_nrow(refer_order));
01261                 for (i = 0; i < cpl_vector_get_size(lines); i++)
01262                     {
01263                         cpl_vector_set(lines, i, cpl_table_get_double(refer_order, "Wave", i, NULL));
01264                     }
01265             }
01266             
01267             /* Not sure if this is necessary for the PPM algorithm */
01268             cpl_vector_sort(peaks, 1);
01269             cpl_vector_sort(lines, 1);
01270 
01271             uves_msg_debug("Call ppm with %d peaks, %d lines, dispersion range = %f - %f A/pixel",
01272                            cpl_vector_get_size(peaks), 
01273                            cpl_vector_get_size(lines),
01274                            min_disp, max_disp);
01275 
01276             uves_free_bivector(&ids);
01277 
01278 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 0, 0)
01279             ids = cpl_ppm_match_positions(peaks, lines,
01280                                           min_disp, max_disp,
01281                                           tolerance, 
01282                                           NULL, NULL);
01283 #else
01284             ids = irplib_ppm_match_positions(peaks, lines,
01285                                              min_disp, max_disp,
01286                                              tolerance);
01287 #endif
01288 
01289 
01290 
01291             if (ids == NULL)
01292                 {
01293                     uves_msg_warning("Order %d: Point pattern matching failed", order);
01294                     if (cpl_error_get_code() != CPL_ERROR_NONE)
01295                         {
01296                             uves_msg_debug("%s at %s", cpl_error_get_message(),
01297                                            cpl_error_get_where());
01298                             uves_error_reset();
01299                         }
01300                 }
01301             else
01302                 {
01303                     int i, j;
01304 
01305                     uves_msg_debug("%d identifications from point pattern matching (order %d)",
01306                                    cpl_bivector_get_size(ids), order);
01307 
01308                     result += cpl_bivector_get_size(ids);
01309 
01310                     for (i = 0; i < cpl_table_get_nrow(linetable); i++) {
01311 
01312                         if (cpl_table_get_int(linetable, "Order", i, NULL) == order)
01313                             for (j = 0; j < cpl_bivector_get_size(ids); j++)
01314                                 {
01315                                     if (fabs(cpl_table_get_double(linetable, "X", i, NULL) -
01316                                              cpl_bivector_get_x_data(ids)[j]) < 0.001)
01317                                         cpl_table_set_double(linetable, "Ident_ppm", i,
01318                                                              cpl_bivector_get_y_data(ids)[j]);
01319                                 }
01320                     }
01321                 }
01322         }
01323     
01324   cleanup:
01325     uves_free_table(&lt_order);
01326     uves_free_table(&refer_order);
01327     uves_free_vector(&peaks);
01328     uves_free_vector(&lines);
01329     uves_free_bivector(&ids);
01330 
01331     return result;
01332 }

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