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

Generated on 8 Mar 2011 for UVES Pipeline Reference Manual by  doxygen 1.6.1