uves_wavecal_firstsolution.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.23 $
00024  * $Name: uves-5_0_0 $
00025  * $Log: uves_wavecal_firstsolution.c,v $
00026  * Revision 1.23  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.21  2007/08/21 13:08:26  jmlarsen
00030  * Removed irplib_access module, largely deprecated by CPL-4
00031  *
00032  * Revision 1.20  2007/06/06 08:17:33  amodigli
00033  * replace tab with 4 spaces
00034  *
00035  * Revision 1.19  2007/05/25 07:05:21  jmlarsen
00036  * Decreased  warning verbosity
00037  *
00038  * Revision 1.18  2007/04/26 13:21:04  jmlarsen
00039  * Made more robust against inaccurate abs_order polynomial
00040  *
00041  * Revision 1.17  2007/04/10 07:11:56  jmlarsen
00042  * Changed interface of polynomial_regression_2d()
00043  *
00044  * Revision 1.16  2007/03/05 10:22:24  jmlarsen
00045  * Fixed bug in computation of max/min physical order number
00046  *
00047  * Revision 1.15  2007/01/15 08:58:20  jmlarsen
00048  * More robust polynomial fitting
00049  *
00050  * Revision 1.14  2007/01/10 12:40:12  jmlarsen
00051  * Removed unused parameter
00052  *
00053  * Revision 1.13  2006/12/07 08:29:58  jmlarsen
00054  * Compute correct Ynew column for FLAMES
00055  *
00056  * Revision 1.12  2006/11/24 16:24:32  jmlarsen
00057  * Added check of abs order polynomial
00058  *
00059  * Revision 1.11  2006/11/15 15:02:15  jmlarsen
00060  * Implemented const safe workarounds for CPL functions
00061  *
00062  * Revision 1.9  2006/11/15 14:04:08  jmlarsen
00063  * Removed non-const version of parameterlist_get_first/last/next which is 
00064  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
00065  *
00066  * Revision 1.8  2006/11/06 15:19:42  jmlarsen
00067  * Removed unused include directives
00068  *
00069  * Revision 1.7  2006/08/18 07:07:43  jmlarsen
00070  * Switched order of cpl_calloc arguments
00071  *
00072  * Revision 1.6  2006/07/14 12:43:47  jmlarsen
00073  * Documentation update
00074  *
00075  * Revision 1.5  2006/07/03 13:29:45  jmlarsen
00076  * Reduced max line length
00077  *
00078  * Revision 1.4  2006/03/03 13:54:11  jmlarsen
00079  * Changed syntax of check macro
00080  *
00081  * Revision 1.3  2006/02/15 13:19:15  jmlarsen
00082  * Reduced source code max. line length
00083  *
00084  * Revision 1.2  2006/02/08 09:25:05  jmlarsen
00085  * Fixed bug caused by == comparison of doubles
00086  *
00087  * Revision 1.1  2006/02/03 07:46:30  jmlarsen
00088  * Moved recipe implementations to ./uves directory
00089  *
00090  * Revision 1.27  2005/12/20 08:11:44  jmlarsen
00091  * Added CVS  entry
00092  *
00093  */
00094 /*----------------------------------------------------------------------------*/
00095 /*
00096  * @addtogroup uves_wavecal
00097  */
00098 /*----------------------------------------------------------------------------*/
00101 #ifdef HAVE_CONFIG_H
00102 #  include <config.h>
00103 #endif
00104 
00105 #include <uves_wavecal_firstsolution.h>
00106 
00107 #include <uves_utils.h>
00108 #include <uves_utils_wrappers.h>
00109 #include <uves_dump.h>
00110 #include <uves_error.h>
00111 #include <uves_msg.h>
00112 
00113 #include <cpl.h>
00114 
00115 #include <math.h>
00116 
00117 static int *
00118 write_physical_order(cpl_table *linetable,
00119              const polynomial *absolute_order, 
00120                      const cpl_table *ordertable,
00121              const polynomial *order_locations,
00122              int *first_abs_order, int *last_abs_order);
00123 
00124 static double
00125 calculate_shift(const cpl_table *linetable, const cpl_table *previous, 
00126         const char *column, const char *reference_column, 
00127         double range, double step, double tolerance);
00128 
00129 static double
00130 cross_correlation(double shift, 
00131           const cpl_table *t1, const cpl_table *t2,
00132           const char *column, const char* reference_column, 
00133           int minref, int maxref, double tolerance);
00134 
00135 static polynomial *apply_shift(const cpl_table *previous, 
00136                    const double shift, const int degree, double *mse);
00137 
00138 /*----------------------------------------------------------------------------*/
00185 /*----------------------------------------------------------------------------*/
00186 polynomial *
00187 uves_wavecal_firstsolution(cpl_table *linetable,
00188                const cpl_table *guess, 
00189                polynomial **absolute_order, 
00190                            const cpl_table *ordertable,
00191                            const polynomial *order_locations,
00192                bool flames,
00193                double offset,
00194                int **relative_order, 
00195                int DEGREE, double CORREL_RANGE, double CORREL_STEP,
00196                double CORREL_TOLERANCE, double MAXERROR, 
00197                int *first_abs_order, int *last_abs_order)
00198 {
00199     polynomial *initial_dispersion = NULL;
00200     polynomial *new_absorder = NULL;
00201     const char *er_msg = NULL;
00202     double shift;
00203     double mse;
00204 
00205     /* Get physical order numbering */
00206     check( *relative_order =   write_physical_order(linetable, *absolute_order, 
00207                                                     ordertable,
00208                             order_locations,
00209                             first_abs_order,
00210                             last_abs_order),
00211        "Could not calculate absolute order numbers");
00212 
00213     /* Update the 'absolute_order' map */
00214     {
00215     int row;
00216 
00217     /* Create column for Y-location (in pixels) of order */
00218     cpl_table_new_column(linetable, "Ynew", CPL_TYPE_DOUBLE);
00219     for (row = 0; row < cpl_table_get_nrow(linetable); row++)
00220         {
00221         /* For historical reasons, the column 'Y' contains the
00222            (relative) order number while 'Ynew' contains 
00223            the y-coordinate (in pixels) of the emission line. */
00224         int order = cpl_table_get_int   (linetable, "Y", row, NULL);
00225         double x  = cpl_table_get_double(linetable, "X", row, NULL);
00226         
00227         cpl_table_set_double(
00228             linetable, "Ynew", row, 
00229             uves_polynomial_evaluate_2d(order_locations, x, order));
00230         }
00231 
00232     assure_nomsg( cpl_error_get_code() == CPL_ERROR_NONE,
00233               cpl_error_get_code() );
00234 
00235     new_absorder =
00236         uves_polynomial_regression_2d(linetable, "X", "Ynew", "Order",
00237                       NULL,              /* uncertainty of order number */
00238                       DEGREE, DEGREE,
00239                       NULL, NULL, NULL,  /* New columns */
00240                       NULL, NULL,        /* mse, chi^2 */
00241                       NULL,              /* variance pol. */
00242                       -1, -1);           /* kappa */
00243 
00244     if (cpl_error_get_code() != CPL_ERROR_NONE) /* Singular matrix, or too few points */
00245         {
00246         er_msg = uves_sprintf("%s", cpl_error_get_message());
00247         
00248         uves_error_reset();
00249         uves_msg_warning("Could not make global fit of absolute order number (%s). "
00250                  "Polynomial is not updated",
00251                  er_msg);
00252         }
00253     else
00254         {
00255         uves_polynomial_delete(absolute_order);
00256         *absolute_order = uves_polynomial_duplicate(new_absorder);
00257         }
00258 
00259     /* Calculate absolute_order wrt center of orders, but add offset to Ynew column */
00260     if (flames)
00261         {
00262         cpl_table_add_scalar(linetable, "Ynew", + offset);
00263         }
00264     }
00265 
00266     /* Sort linetable by 'Order' (ascending), then 'X' (ascending) */
00267     uves_sort_table_2(linetable, "Order", "X", false, false);
00268 
00269     /* Cross correlation of guess (linetable) and linetable */
00270     /* Step size should not be less than 2*tolerance */
00271     check( shift = calculate_shift(guess, linetable, "X", "Order", 
00272                    CORREL_RANGE, CORREL_STEP, CORREL_TOLERANCE),
00273        "Could not calculate shift of position w.r.t. guess solution");
00274 
00275     /* Apply shift to guess solution
00276      * Note that it doesn't help to simply call uves_polynomial_shift()
00277      * on the guess solution
00278      * because the requested 'DEGREE' might be different from
00279      * the degree used in the guess solution
00280      */
00281     
00282     check( initial_dispersion = apply_shift(guess, shift, DEGREE, &mse),
00283        "Could not calculate initial dispersion relation");
00284     /* This fit may fail if the input guess table has too few or badly
00285        distributed points, but there is not much to do about that */
00286 
00287     /* Check quality of initial solution */
00288     if(mse > MAXERROR*MAXERROR) 
00289     {
00290         uves_msg_warning("RMS of initial fit (%f pixels) is greater "
00291                  "than tolerance (%f pixels)", sqrt(mse), MAXERROR);
00292     }
00293     
00294   cleanup:
00295     uves_free_string_const(&er_msg);
00296     uves_polynomial_delete(&new_absorder);
00297     if (cpl_error_get_code() != CPL_ERROR_NONE)
00298     {
00299         uves_polynomial_delete(&initial_dispersion);
00300     }
00301     
00302     return initial_dispersion;
00303 }
00304 
00305 /*----------------------------------------------------------------------------*/
00320 /*----------------------------------------------------------------------------*/
00321 static polynomial *
00322 apply_shift(const cpl_table *guess, double shift, int degree, double *mse)
00323 {
00324     polynomial *result = NULL;
00325     cpl_table *t = NULL;
00326     
00327     /* Copy guess table */
00328     check( t = cpl_table_duplicate(guess),
00329        "Error duplicating table");
00330     
00331     /* Create auxillary column  Ident*Order  */
00332     check(( cpl_table_duplicate_column(t, "ident_order", t, "Ident"),
00333         cpl_table_multiply_columns(t, "ident_order", "Order")),
00334       /* ident_order = Ident * Order */
00335       "Error creating auxillary column");
00336     
00337     /* Shift x values */
00338     check( cpl_table_add_scalar(t, "X", shift), "Error shifting column 'X'");
00339 
00340     /* Fit lambda*m = f(x, m) */
00341     /* Don't use uncertainties because they might not exist in guess solution */
00342     result = uves_polynomial_regression_2d(t, "X", "Order", "ident_order", NULL,
00343                        degree, degree,
00344                        NULL, NULL, NULL,
00345                        mse, NULL,
00346                        NULL, -1, -1);
00347 
00348     /* If failed, set error to SINGULAR_MATRIX */
00349     if (cpl_error_get_code() != CPL_ERROR_NONE) /* Singular matrix or too few points */
00350     {
00351         uves_error_reset();
00352 
00353         assure( false, CPL_ERROR_SINGULAR_MATRIX,
00354             "Polynomial fitting failed");
00355     }
00356 
00357   cleanup:
00358     uves_free_table(&t);
00359     return result;
00360 }
00361 
00362 /*----------------------------------------------------------------------------*/
00385 /*----------------------------------------------------------------------------*/
00386 
00387 static double
00388 calculate_shift(const cpl_table *linetable, const cpl_table *guess, const char *column,
00389         const char *reference_column, double range, double step, double tolerance)
00390 {
00391     cpl_type t;
00392     int minorder, maxorder;
00393     int N, i;
00394     double shift, max_corr, median_corr, maxpos = 0;
00395     cpl_table *temp = NULL;
00396 
00397     assure( cpl_table_has_column(linetable, column), 
00398         CPL_ERROR_ILLEGAL_INPUT, "Table has no '%s' column", column);
00399     assure( cpl_table_has_column(guess , column), 
00400         CPL_ERROR_ILLEGAL_INPUT, "Table has no '%s' column", column);
00401     assure( cpl_table_has_column(linetable, reference_column),
00402         CPL_ERROR_ILLEGAL_INPUT, "Table has no '%s' column", reference_column);
00403     assure( cpl_table_has_column(guess , reference_column), 
00404         CPL_ERROR_ILLEGAL_INPUT, "Table has no '%s' column", reference_column);
00405     assure( range > 0, CPL_ERROR_ILLEGAL_INPUT, "Range = %f", range);
00406 
00407     t = cpl_table_get_column_type(linetable, column);
00408     assure( t == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
00409         "Column '%s' has type '%s'. Double expected", column, uves_tostring_cpl_type(t));
00410 
00411     t = cpl_table_get_column_type(guess, column);
00412     assure( t == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
00413         "Column '%s' has type '%s'. Double expected", column, uves_tostring_cpl_type(t));
00414 
00415     t = cpl_table_get_column_type(linetable, reference_column);
00416     assure( t == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
00417         "Ref. column '%s' has type '%s'. Integer expected", 
00418         reference_column, uves_tostring_cpl_type(t));
00419     
00420     t = cpl_table_get_column_type(guess, reference_column);
00421     assure( t == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
00422         "Ref. column '%s' has type '%s'. Integer expected",
00423         reference_column, uves_tostring_cpl_type(t));
00424 
00425     /* Identify common orders    */
00426     check(( minorder = 
00427         uves_max_int(cpl_table_get_column_min(guess, reference_column), 
00428              cpl_table_get_column_min(linetable, reference_column)),
00429         maxorder = 
00430         uves_min_int(cpl_table_get_column_max(guess, reference_column), 
00431              cpl_table_get_column_max(linetable, reference_column))),
00432       "Error reading column '%s'", reference_column);
00433     
00434     assure(maxorder >= minorder, CPL_ERROR_ILLEGAL_INPUT, "No common orders found");
00435     
00436     uves_msg("Min/max common absolute orders = %d - %d", minorder, maxorder);
00437     
00438     /* Find maximum of cross correlation function 
00439        for shifts in [-range ; range]
00440     */
00441 
00442     /* Count number of candidates,
00443        so we can create a table of the correct size
00444        which is used to get the median of
00445        all cross-correlation values */
00446     N = 0;
00447     for (shift = -range; shift <= range; shift += step) 
00448     {
00449         N += 1;
00450     }
00451 
00452     temp = cpl_table_new(N);
00453     cpl_table_new_column(temp, "Corr", CPL_TYPE_DOUBLE);
00454 
00455     max_corr = -1;
00456     maxpos = 0;
00457     for (shift = -range, i = 0;
00458      i < N;
00459      shift += step , i++) 
00460     {
00461         double corr;
00462         check( corr = cross_correlation(shift, linetable, guess, column, 
00463                         reference_column, minorder, maxorder, tolerance),
00464            "Error calculating spectrum cross correlation for shift = %f pixel(s)", 
00465            shift);
00466         
00467         /* Update table */
00468         check( cpl_table_set_double(temp, "Corr", i, corr),
00469            "Error updating table");
00470         
00471         uves_msg_debug("Correlation(shift=%f) = %f", shift, corr);
00472         
00473         if (corr > max_corr) 
00474         {
00475             max_corr = corr;
00476             maxpos = shift;
00477         }
00478     }
00479 
00480     /* To estimate significance,
00481        compare the detected max cross-correlation 
00482        value to "no correlation" estimated as the
00483        median of all cross-corr. values */
00484 
00485     median_corr = cpl_table_get_column_median(temp, "Corr");
00486     
00487     /* Correlation value is integer ; don't divide by zero */
00488     if (median_corr < 0.5)
00489     {
00490         median_corr = 1;
00491     }
00492 
00493     uves_msg("Estimated shift compared to guess solution is %f pixels (%.2f sigma detection)",
00494          maxpos, max_corr / median_corr);
00495 
00496     /* The correlation peak is usually 
00497        ~30 or more times the background,
00498        so warn if peak value is less than, say,
00499        10 times background. */
00500     if (max_corr / median_corr < 10)
00501     {
00502         uves_msg_warning("Cross-correlation with guess solution is "
00503                  "only %f times no correlation (usually >30). "
00504                  "Make sure that the guess solution is within ~10 pixels "
00505                  "of the real dispersion relation; otherwise the following "
00506                  "wavelength calibration is likely to fail or converge "
00507                  "to a wrong solution",
00508                  max_corr / median_corr);
00509     }
00510     
00511   cleanup:
00512     uves_free_table(&temp);
00513     return maxpos;
00514 }
00515 
00516 /*----------------------------------------------------------------------------*/
00538 /*----------------------------------------------------------------------------*/
00539 static double
00540 cross_correlation(double shift,
00541           const cpl_table *t1, const cpl_table *t2,
00542           const char *column, const char* reference_column, 
00543           int minref, int maxref, double tolerance)
00544 {
00545     double result = 0;  /* The result */
00546     int i1 = 0;         /* Pointers to table rows */
00547     int i2 = 0;
00548 
00549     /* For efficiency reasons, retrieve the pointers to the columns */
00550     const double *col1 = cpl_table_get_data_double_const(t1, column);
00551     const double *col2 = cpl_table_get_data_double_const(t2, column);
00552     const int *ref1 = cpl_table_get_data_int_const(t1, reference_column);
00553     const int *ref2 = cpl_table_get_data_int_const(t2, reference_column);
00554 
00555     int N1 = cpl_table_get_nrow(t1);
00556     int N2 = cpl_table_get_nrow(t2);
00557 
00558     assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
00559         "Error reading input table");
00560     
00561     /* Search for matching rows */
00562     while (i1 < N1 && ref1[i1] <= maxref && 
00563        i2 < N2 && ref2[i2] <= maxref) {
00564     if      (i1 < minref || ref1[i1] < ref2[i2])
00565         i1++;
00566     else if (i2 < minref || ref1[i1] > ref2[i2])
00567         i2++;
00568     else {
00569         /* Reference values match */
00570         double difference = col2[i2] - (col1[i1] + shift);
00571         
00572         if      (difference > tolerance)
00573         {
00574             i1++;
00575         }
00576         else if (difference < -tolerance)
00577         {
00578             i2++;
00579         }
00580         else {
00581         /* Matching rows found: |col2-col1-shift| <= tolerance.
00582            Update result and continue search */
00583         result += 1.0;
00584         i2++;
00585         }
00586     }
00587     }
00588 
00589 
00590   cleanup:
00591     return result;
00592 }
00593 
00594 
00595 /*----------------------------------------------------------------------------*/
00614 /*----------------------------------------------------------------------------*/
00615 static int *
00616 write_physical_order(cpl_table *linetable, const polynomial *absolute_order,
00617                      const cpl_table *ordertable,
00618              const polynomial *order_locations,
00619              int *first_abs_order, int *last_abs_order)
00620 {
00621     int *relative_order = NULL; /* Result */
00622     int *physical_order = NULL;
00623     int minorder, maxorder;
00624     int maxphysical;
00625     cpl_table *temp = NULL;
00626     const polynomial *map = NULL;
00627 
00628     double *sum = NULL;   /* Auxillary variables used to calculate the average */
00629     int      *N = NULL;
00630     
00631     int i;
00632 
00633     check( cpl_table_new_column(linetable, "Order", CPL_TYPE_INT),
00634        "Error creating column");
00635 
00636     check( cpl_table_new_column(linetable, "AbsOrder", CPL_TYPE_DOUBLE),
00637        "Error creating column");
00638     
00639     check(( minorder = cpl_table_get_column_min(ordertable, "Order"),
00640         maxorder = cpl_table_get_column_max(ordertable, "Order")),
00641       "Could not read min. and max. order numbers");
00642 
00643     assure( minorder > 0, CPL_ERROR_ILLEGAL_INPUT,
00644         "Non-positive order number (%d) in linetable", minorder);
00645     
00646     physical_order = cpl_calloc(maxorder + 1, sizeof(int));
00647     assure_mem( physical_order );
00648     
00649     /* First calculate the estimation of the
00650        absolute order number at each line position */
00651     for (i = 0; i < cpl_table_get_nrow(linetable); i++) {
00652     double x, y;
00653     double absorder;
00654     int order;
00655     
00656     order = cpl_table_get_int   (linetable, "Y", i, NULL); 
00657         /* The column 'Y' contains the (relative) order number */
00658 
00659     x     = cpl_table_get_double(linetable, "X", i, NULL);
00660 
00661     y = uves_polynomial_evaluate_2d(order_locations, x, order);
00662 
00663         absorder = uves_polynomial_evaluate_2d(absolute_order, x, y);
00664 
00665         uves_msg_debug("Order #%d: Absolute order = %f at x = %f",
00666                order, absorder, x);
00667 
00668         cpl_table_set_double(linetable, "AbsOrder", i, absorder);
00669     }
00670  
00671     {
00672         int degree = 1;
00673         int coeff1, coeff2;  /* absorder = coeff1 + coeff2 * relative_order */
00674         int order;
00675         int relorder_median;
00676         int absorder_median;
00677 
00678         check_nomsg( map = 
00679                      uves_polynomial_regression_1d(linetable,
00680                                                    "Y", "AbsOrder", NULL,
00681                                                    degree, 
00682                                                    NULL, NULL, NULL, -1));
00683         
00684         relorder_median = uves_round_double(cpl_table_get_column_median(linetable, "Y"));
00685         absorder_median = uves_round_double(uves_polynomial_evaluate_1d(map, relorder_median));
00686             
00687         if (uves_polynomial_derivative_1d(map, relorder_median) > 0) {
00688             coeff2 = 1;
00689         }
00690         else {
00691             coeff2 = -1;
00692         }
00693         
00694         coeff1 = absorder_median - coeff2 * relorder_median;
00695 
00696     uves_msg_debug("Assuming relation: abs.order = %d + (%d) * rel.order",
00697                        coeff1, coeff2);
00698         
00699         maxphysical = -1;
00700         for (order = minorder; order <= maxorder; order++) {
00701             physical_order[order] = coeff1 + coeff2 * order;
00702             
00703             assure(physical_order[order] > 0, CPL_ERROR_ILLEGAL_OUTPUT,
00704                    "Estimated physical order number is non-positive (%d)", 
00705                    physical_order[order]);
00706             
00707             if (physical_order[order] > maxphysical) 
00708                 {
00709                     maxphysical = physical_order[order];
00710                 }
00711 
00712             uves_msg_debug("Mapping relative order #%d to absolute order #%d", 
00713                            order, physical_order[order]);
00714         }
00715         
00716         /* Get first and last physical orders */
00717         *first_abs_order = physical_order[minorder];
00718         *last_abs_order  = physical_order[maxorder];
00719         
00720         passure( *first_abs_order - *last_abs_order == coeff2*(minorder - maxorder),
00721                  "%d %d %d %d %d",
00722                  *first_abs_order, *last_abs_order, coeff2, minorder, maxorder);
00723         
00724     }
00725 
00726     /* Then write this rounded mean value to every row of the table */
00727     for (i = 0; i < cpl_table_get_nrow(linetable); i++) {
00728     int order;
00729     order = cpl_table_get_int (linetable, "Y", i, NULL);
00730     cpl_table_set_int(linetable, "Order", i, physical_order[order]);
00731     }
00732 
00733     /* Calculate the inverse of 'physical_order' */
00734     relative_order = cpl_calloc(maxphysical + 1, sizeof(int));
00735     for (i = 0; i <= maxorder; i++)
00736     {
00737         relative_order[physical_order[i]] = i;
00738     }
00739     
00740   cleanup:
00741     uves_free_table(&temp);
00742     uves_polynomial_delete_const(&map);
00743     cpl_free(sum);
00744     cpl_free(physical_order);
00745     cpl_free(N);
00746 
00747     return relative_order;
00748 }

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