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

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