irplib_wlxcorr-test.c

00001 /* $Id: irplib_wlxcorr-test.c,v 1.15 2012/01/12 12:38:38 llundin Exp $
00002  *
00003  * This file is part of the ESO Common Pipeline Library
00004  * Copyright (C) 2001-2004 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: llundin $
00023  * $Date: 2012/01/12 12:38:38 $
00024  * $Revision: 1.15 $
00025  * $Name: uves-5_0_0 $
00026  */
00027 
00028 /*-----------------------------------------------------------------------------
00029                                    Includes
00030  -----------------------------------------------------------------------------*/
00031 
00032 #ifdef HAVE_CONFIG_H
00033 #include <config.h>
00034 #endif
00035 
00036 #include <irplib_wlxcorr.h>
00037 
00038 #include <irplib_wavecal_impl.h>
00039 
00040 #include <cpl_plot.h>
00041 
00042 #include <math.h>
00043 #include <float.h>
00044 
00045 /* TEMPORARY SUPPORT OF CPL 5.x */
00046 #ifndef CPL_SIZE_FORMAT
00047 #define CPL_SIZE_FORMAT "d"
00048 #define cpl_size int
00049 #endif
00050 /* END TEMPORARY SUPPORT OF CPL 5.x */
00051 
00052 
00053 
00054 /*----------------------------------------------------------------------------*/
00058 /*----------------------------------------------------------------------------*/
00059 
00060 
00061 /*-----------------------------------------------------------------------------
00062                             Private Function prototypes
00063  -----------------------------------------------------------------------------*/
00064 
00065 static void irplib_wlxcorr_best_poly_test(void);
00066 static void irplib_wlxcorr_best_poly_test_one(int, int, cpl_boolean, int, int);
00067 static void irplib_wlxcorr_convolve_create_kernel_test(void);
00068 static void irplib_wlxcorr_convolve_create_kernel_test_one(double, double);
00069 static double irplib_wlcalib_lss(double, double, double);
00070 static void irplib_wavecal_profile_compare(int, double, double);
00071 
00072 
00073 /*----------------------------------------------------------------------------*/
00077 /*----------------------------------------------------------------------------*/
00078 
00079 /*-----------------------------------------------------------------------------
00080                                   Main
00081  -----------------------------------------------------------------------------*/
00082 int main(void)
00083 {
00084     /* Initialize CPL + IRPLIB */
00085     cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_WARNING);
00086 
00087     irplib_wavecal_profile_compare(100, 4.0, 4.0);
00088     irplib_wlxcorr_convolve_create_kernel_test();
00089     irplib_wlxcorr_best_poly_test();
00090 
00091     return cpl_test_end(0);
00092 }
00093 
00094 
00095 static void irplib_wlxcorr_best_poly_test(void)
00096 {
00097     cpl_polynomial  *   poly;
00098     const cpl_boolean   do_bench = cpl_msg_get_level() <= CPL_MSG_INFO
00099         ? CPL_TRUE : CPL_FALSE;
00100     const int           spec_size = do_bench ? 1024 : 256;
00101     const int           nreps     = do_bench ? 3 : 1;
00102     const int           nsamples  = do_bench ? 30 : 10;
00103 
00104 
00105     /* 1st test: NULL input */
00106     poly = irplib_wlxcorr_best_poly(NULL, NULL, 1, NULL, NULL, 1, 1.0, 1.0,
00107                                     NULL, NULL, NULL);
00108     cpl_test_error(CPL_ERROR_NULL_INPUT);
00109     cpl_test_null( poly );
00110 
00111 #if 1
00112     /* 2nd test: Resampling of catalog lines */
00113     irplib_wlxcorr_best_poly_test_one(spec_size, spec_size*10, CPL_TRUE,
00114                                       nsamples, nreps);
00115 #endif
00116 
00117     /* 3rd test: No resampling of catalog lines */
00118     irplib_wlxcorr_best_poly_test_one(spec_size, spec_size/50,  CPL_FALSE,
00119                                       nsamples, nreps);
00120 }
00121 
00122 static void irplib_wlxcorr_best_poly_test_one(int spec_size, int cat_size,
00123                                               cpl_boolean do_resample,
00124                                               int nsamples, int nreps)
00125 {
00126     const int           degree     = 2;
00127     cpl_vector      *   spectrum   = cpl_vector_new(spec_size);
00128     cpl_bivector    *   catalog    = cpl_bivector_new(cat_size);
00129     cpl_polynomial  *   true_poly  = cpl_polynomial_new(1);
00130     cpl_polynomial  *   guess_poly = cpl_polynomial_new(1);
00131     cpl_vector      *   wl_err     = cpl_vector_new(degree+1);
00132     double              xc;
00133     const double        slitw = 2.0;
00134     const double        fwhm = 2.0;
00135     const double        xtrunc = 0.5 * slitw + 5.0 * fwhm * CPL_MATH_SIG_FWHM;
00136     const double        rel_error = 0.05; /* Introduce error */
00137 
00138     /* A black-body with T=253K should emit mostly in the range [2;50[ micron */
00139     const double        temp_bb = 253.0;
00140 
00141     const double        b_true = 2e-6;
00142     const double        a_true = 48e-6 / spec_size;
00143 
00144     const double        a_error = a_true * rel_error;
00145     const double        b_error = b_true * rel_error;
00146     const double        a = a_true + a_error;
00147     const double        b = b_true + b_error;
00148     double              wl_errmax;
00149     cpl_size            pow_ind;
00150     int                 i;
00151     FILE              * stream = cpl_msg_get_level() > CPL_MSG_INFO
00152         ? fopen("/dev/null", "a") : stdout;
00153 
00154 
00155     cpl_test_nonnull( stream );
00156 
00157     /* First guess P(x) = ax + b */
00158     /* The true and distorted polynomials */
00159     pow_ind = 1;
00160     cpl_polynomial_set_coeff(true_poly,  &pow_ind, a_true);
00161     cpl_polynomial_set_coeff(guess_poly, &pow_ind, a);
00162     pow_ind = 0;
00163     cpl_polynomial_set_coeff(true_poly,  &pow_ind, b_true);
00164     cpl_polynomial_set_coeff(guess_poly, &pow_ind, b);
00165 
00166     cpl_msg_info(cpl_func, "First guess polynomial:");
00167     cpl_polynomial_dump(guess_poly, stream);
00168 
00169     /* Try also to shift the guess of the solution */
00170     cpl_test_zero(cpl_polynomial_shift_1d(guess_poly, 0, 25.0));
00171 
00172     cpl_msg_info(cpl_func, "True polynomial:");
00173     cpl_polynomial_dump(true_poly, stream);
00174 
00175 
00176     if (do_resample) {
00177         cpl_vector * evalpoints = cpl_vector_new(spec_size);
00178 
00179         /* Wavelengths of the spectrum */
00180         cpl_vector_fill_polynomial(evalpoints, true_poly, 1.0, 1.0);
00181 
00182         /* Catalog */
00183         /* The sampled profile is a black body radiation */
00184         cpl_vector_fill_polynomial(cpl_bivector_get_x(catalog), true_poly,
00185                                    -1.0, 1.5 * spec_size / cat_size);
00186 
00187         cpl_photom_fill_blackbody(cpl_bivector_get_y(catalog), CPL_UNIT_LESS,
00188                                   cpl_bivector_get_x_const(catalog),
00189                                   CPL_UNIT_LENGTH, temp_bb);
00190 
00191         cpl_photom_fill_blackbody(spectrum, CPL_UNIT_LESS,
00192                                   evalpoints, CPL_UNIT_LENGTH, temp_bb);
00193 
00194         cpl_vector_delete(evalpoints);
00195 
00196     } else {
00197         /* Place some lines with different intensities */
00198         double * dx = cpl_bivector_get_x_data(catalog);
00199         double * dy = cpl_bivector_get_y_data(catalog);
00200 
00201         for (i = 0; i < cat_size; i++) {
00202             const double wli = cpl_polynomial_eval_1d(true_poly, 3.0 * i * i
00203                                                       -10.0, NULL);
00204 
00205             dx[i] = wli;
00206             dy[i] = sin(i * CPL_MATH_PI / cat_size);
00207 
00208         }
00209 
00210         irplib_vector_fill_line_spectrum_model(spectrum, NULL, NULL, true_poly,
00211                                                catalog, slitw, fwhm, xtrunc,
00212                                                0, CPL_FALSE, CPL_FALSE, NULL);
00213         cpl_test_error(CPL_ERROR_NONE);
00214     }
00215 
00216     /* FIXME: Add some random noise to the spectrum */
00217     
00218     if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
00219         cpl_plot_bivector( "", "t 'Catalog' w lines", "", catalog);
00220         cpl_plot_vector( "", "t 'Spectrum' w lines", "", spectrum);
00221     }
00222 
00223 
00224     /* Error */
00225     /* Compute an error bound certain to include to true solution */
00226     wl_errmax = cpl_polynomial_eval_1d(guess_poly, spec_size, NULL)
00227         - cpl_polynomial_eval_1d(true_poly, spec_size, NULL);
00228     cpl_vector_fill(wl_err, 2.0 * wl_errmax);
00229 
00230     /* Multiple calls for bench-marking */
00231 
00232     for (i=0; i < nreps; i++) {
00233         cpl_table      * wl_res;
00234         cpl_vector     * xcorrs;
00235         cpl_polynomial * poly
00236             = irplib_wlxcorr_best_poly(spectrum, catalog, degree,
00237                                        guess_poly, wl_err, nsamples,
00238                                        slitw, fwhm, &xc, &wl_res, &xcorrs);
00239         cpl_test_nonnull(poly);
00240         cpl_test_error(CPL_ERROR_NONE);
00241 
00242         if (i == 0 && poly != NULL) {
00243             if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
00244                 const char * labels[] = {IRPLIB_WLXCORR_COL_WAVELENGTH,
00245                                          IRPLIB_WLXCORR_COL_CAT_INIT,
00246                                          IRPLIB_WLXCORR_COL_CAT_FINAL,
00247                                          IRPLIB_WLXCORR_COL_OBS};
00248 
00249                 cpl_plot_vector( "", "t 'X corr values' w lines", "", xcorrs);
00250 
00251                 cpl_test_zero(cpl_plot_columns("", "", "", wl_res, labels, 4));
00252             }
00253 
00254             cpl_msg_info(cpl_func, "Corrected polynomial:");
00255             cpl_polynomial_dump(poly, stream);
00256 
00257             /* Corrected polynomial must be monotone, with same sign
00258                as a_true. */ 
00259             cpl_test_zero(cpl_polynomial_derivative(poly, 0));
00260             cpl_test_leq(0.0, a_true * cpl_polynomial_eval_1d(poly, 1.0, NULL));
00261             cpl_test_leq(0.0, a_true
00262                          * cpl_polynomial_eval_1d(poly, 0.5 * spec_size, NULL));
00263             cpl_test_leq(0.0, a_true
00264                          * cpl_polynomial_eval_1d(poly, spec_size, NULL));
00265 
00266             cpl_test_error(CPL_ERROR_NONE);
00267 
00268         }
00269 
00270         cpl_table_delete(wl_res);
00271         cpl_vector_delete(xcorrs);
00272         cpl_polynomial_delete(poly);
00273     }
00274 
00275     cpl_vector_delete(wl_err);
00276     cpl_vector_delete(spectrum);
00277     cpl_bivector_delete(catalog);
00278     cpl_polynomial_delete(true_poly);
00279     cpl_polynomial_delete(guess_poly);
00280     cpl_test_error(CPL_ERROR_NONE);
00281 
00282     if (stream != stdout) cpl_test_zero( fclose(stream) );
00283 
00284     return;
00285 }
00286 
00287 
00288 static void irplib_wlxcorr_convolve_create_kernel_test_one(double slitw,
00289                                                            double fwhm)
00290 {
00291 
00292     cpl_vector * kernel;
00293     double       sum = 0.0;
00294     /* Maximum value of profile */
00295     const double maxval = irplib_wlcalib_lss(0.0, slitw, fwhm);
00296     double       prev = maxval;
00297     int          n, i;
00298 
00299     cpl_msg_info(cpl_func, "Slit-width=%g, FWHM=%g", slitw, fwhm);
00300 
00301     kernel = irplib_wlxcorr_convolve_create_kernel(0.0, fwhm);
00302 
00303     cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
00304     cpl_test_null(kernel);
00305 
00306     kernel = irplib_wlxcorr_convolve_create_kernel(slitw, 0.0);
00307 
00308     cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
00309     cpl_test_null(kernel);
00310 
00311     kernel = irplib_wlxcorr_convolve_create_kernel(slitw, fwhm);
00312 
00313     cpl_test_nonnull(kernel);
00314 
00315     n = cpl_vector_get_size(kernel);
00316 
00317     for (i = 0; i < n; i++) {
00318         const double val = cpl_vector_get(kernel, i);
00319         sum += i ? 2.0*val : val; /* Non-central elements twice */
00320 
00321         /* Profile consists of non-negative values */
00322         cpl_test_leq(0.0, val);
00323 
00324         /* The max of the profile is less than maxval and decreases */
00325         cpl_test_leq(val, prev);
00326 
00327         if (i > 0) {
00328             /* The profile at i is less than the continuous profile at
00329                i - 0.5, and greater than that at i + 0.5 */
00330             cpl_test_leq(val, irplib_wlcalib_lss(i - 0.5, slitw, fwhm));
00331             cpl_test_leq(irplib_wlcalib_lss(i + 0.5, slitw, fwhm), val);
00332         }
00333 
00334         /* The profile has a FWHM (sligthly) greater than slitw */
00335         if ((double)i < 0.5 * slitw) {
00336             /* Thus if x is less than half the slit width, then
00337                the value has to be greater than half the maximum */
00338             cpl_test_leq(0.5 * maxval, val);
00339         } else if (val < 0.5 * maxval) {
00340             /* On the other hand, if the value is less than the maximum,
00341                then x must exceed half the slitw */
00342             cpl_test_leq(0.5*slitw, (double)i);
00343         }
00344 
00345         prev = val;
00346     }
00347 
00348     /* Integral is supposed to be 1 */
00349     cpl_test_abs(sum, 1.0, 1e-5); /* FIXME: Improve tolerance */
00350 
00351     if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
00352         char * title = cpl_sprintf("t 'LSS profile, slitw=%g, fwhm=%g' "
00353                                    "w linespoints", slitw, fwhm);
00354         cpl_plot_vector("set grid;", title, "", kernel);
00355         cpl_free(title);
00356     }
00357 
00358     cpl_vector_delete(kernel);
00359 }
00360 
00361 static void irplib_wlxcorr_convolve_create_kernel_test(void)
00362 {
00363 
00364     irplib_wlxcorr_convolve_create_kernel_test_one(0.86, 2.0);
00365     irplib_wlxcorr_convolve_create_kernel_test_one(1.72, 3.0);
00366     irplib_wlxcorr_convolve_create_kernel_test_one(40.0, 2.0);
00367     irplib_wlxcorr_convolve_create_kernel_test_one(3.0, 40.0);
00368 
00369 }
00370 
00371 
00372 /*----------------------------------------------------------------------------*/
00382 /*----------------------------------------------------------------------------*/
00383 static double irplib_wlcalib_lss(double x, double slitw, double fwhm)
00384 {
00385   const double sigmasqrt2 = fwhm * CPL_MATH_SIG_FWHM * CPL_MATH_SQRT2;
00386   const double result = 0.5 / slitw *
00387       (erf((x+0.5*slitw)/sigmasqrt2) - erf((x-0.5*slitw)/sigmasqrt2));
00388 
00389   cpl_test_lt(0.0, slitw);
00390   cpl_test_lt(0.0, sigmasqrt2);
00391 
00392   /* Protect against round-off (on SunOS 5.8) */
00393   return result < 0.0 ? 0.0 : result;
00394 
00395 }
00396 
00397 
00398 /*----------------------------------------------------------------------------*/
00407 /*----------------------------------------------------------------------------*/
00408 static void irplib_wavecal_profile_compare(int spec_size, double slitw,
00409                                            double fwhm)
00410 {
00411 
00412     cpl_vector     * spectrum1  = cpl_vector_new(spec_size);
00413     cpl_vector     * spectrum2  = cpl_vector_new(spec_size);
00414     cpl_bivector   * catalog    = cpl_bivector_new(2);
00415     cpl_polynomial * dispersion = cpl_polynomial_new(1);
00416     const double     a = 1.0;
00417     const double     b = 100.0;
00418     const double     xtrunc = 0.5 * slitw + 2.0 * fwhm * CPL_MATH_SIG_FWHM;
00419     double           mean;
00420     cpl_error_code   error;
00421     cpl_size         pow_ind;
00422 
00423 
00424     pow_ind = 1;
00425     cpl_polynomial_set_coeff(dispersion, &pow_ind, a);
00426     pow_ind = 0;
00427     cpl_polynomial_set_coeff(dispersion, &pow_ind, b);
00428 
00429     cpl_vector_set(cpl_bivector_get_x(catalog), 0, b + spec_size / 3.0);
00430     cpl_vector_set(cpl_bivector_get_y(catalog), 0, 100);
00431 
00432     cpl_vector_set(cpl_bivector_get_x(catalog), 1, b + spec_size / 1.5);
00433     cpl_vector_set(cpl_bivector_get_y(catalog), 1, 100);
00434 
00435     cpl_test_error(CPL_ERROR_NONE);
00436 
00437     error = irplib_vector_fill_line_spectrum_model(spectrum1, NULL, NULL,
00438                                                    dispersion, catalog, slitw,
00439                                                    fwhm, xtrunc, 0, CPL_FALSE,
00440                                                    CPL_FALSE, NULL);
00441     cpl_test_error(CPL_ERROR_NONE);
00442     cpl_test_eq(error, CPL_ERROR_NONE);
00443 
00444 
00445     error = irplib_vector_fill_line_spectrum_model(spectrum2, NULL, NULL,
00446                                                    dispersion, catalog, slitw,
00447                                                    fwhm, xtrunc, 0, CPL_TRUE,
00448                                                    CPL_FALSE, NULL);
00449     
00450     cpl_test_error(CPL_ERROR_NONE);
00451     cpl_test_eq(error, CPL_ERROR_NONE);
00452 
00453     if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
00454         error = cpl_plot_vector("set grid;", "t 'Spectrum' w lines", "",
00455                                 spectrum1);
00456         cpl_test_error(CPL_ERROR_NONE);
00457         cpl_test_eq(error, CPL_ERROR_NONE);
00458         error = cpl_plot_vector("set grid;", "t 'Spectrum' w lines", "",
00459                                 spectrum2);
00460         cpl_test_error(CPL_ERROR_NONE);
00461         cpl_test_eq(error, CPL_ERROR_NONE);
00462     }
00463 
00464     cpl_vector_subtract(spectrum1, spectrum2);
00465     mean = cpl_vector_get_mean(spectrum1);
00466     if (mean != 0.0) {
00467         cpl_msg_info(cpl_func, "Error: %g", mean);
00468         if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
00469             error = cpl_plot_vector("set grid;", "t 'Spectrum error' w lines",
00470                                     "", spectrum1);
00471             cpl_test_error(CPL_ERROR_NONE);
00472             cpl_test_eq(error, CPL_ERROR_NONE);
00473         }
00474     }
00475 
00476     cpl_polynomial_delete(dispersion);
00477     cpl_vector_delete(spectrum1);
00478     cpl_vector_delete(spectrum2);
00479     cpl_bivector_delete(catalog);
00480 
00481     cpl_test_error(CPL_ERROR_NONE);
00482 
00483 }

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