irplib_wavecal.c

00001 /* $Id: irplib_wavecal.c,v 1.40 2009/11/09 13:32:54 llundin Exp $
00002  *
00003  * This file is part of the IRPLIB Pipeline
00004  * Copyright (C) 2002,2003 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., 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: llundin $
00023  * $Date: 2009/11/09 13:32:54 $
00024  * $Revision: 1.40 $
00025  * $Name: uves-4_9_1 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033                                    Includes
00034  -----------------------------------------------------------------------------*/
00035 
00036 #include <string.h>
00037 #include <math.h>
00038 #include <cpl.h>
00039 
00040 #ifdef HAVE_GSL
00041 #include <gsl/gsl_multimin.h>
00042 #endif
00043 
00044 #include "irplib_wavecal_impl.h"
00045 
00046 /* Needed for irplib_errorstate_dump_debug() */
00047 #include "irplib_utils.h"
00048 
00049 /*-----------------------------------------------------------------------------
00050                                Private types
00051  -----------------------------------------------------------------------------*/
00052 
00053 typedef struct {
00054 
00055     const cpl_vector * observed;
00056     cpl_polynomial   * disp1d;
00057     cpl_vector       * spectrum;
00058     irplib_base_spectrum_model * param;
00059     cpl_error_code  (* filler)(cpl_vector *, const cpl_polynomial *,
00060                                irplib_base_spectrum_model *, int);
00061     cpl_vector       * vxc;
00062     double             xc;
00063     int                maxxc;
00064     double             mxc;
00065     cpl_polynomial   * mdisp;
00066     int                ishift;
00067 
00068 } irplib_multimin;
00069 
00070 /*-----------------------------------------------------------------------------
00071                                Defines
00072  -----------------------------------------------------------------------------*/
00073 
00074 #ifndef inline
00075 #define inline /* inline */
00076 #endif
00077 
00078 #define IRPLIB_MAX(A,B) ((A) > (B) ? (A) : (B))
00079 #define IRPLIB_MIN(A,B) ((A) < (B) ? (A) : (B))
00080 
00081 /* Detect presence of cpl_polynoimial_fit() via fingerprinting */
00082 #if defined cpl_test_polynomial_abs
00083 #define HAVE_CPL_POLYNOMIAL_FIT
00084 #endif
00085 
00086 /*-----------------------------------------------------------------------------
00087                                    Private functions
00088  -----------------------------------------------------------------------------*/
00089 
00090 #ifdef HAVE_GSL
00091 static double irplib_gsl_correlation(const gsl_vector *, void *);
00092 #endif
00093 
00094 /*----------------------------------------------------------------------------*/
00098 /*----------------------------------------------------------------------------*/
00099 
00103 /*----------------------------------------------------------------------------*/
00111 /*----------------------------------------------------------------------------*/
00112 int irplib_bivector_count_positive(const cpl_bivector * self,
00113                                   double               x_min,
00114                                   double               x_max)
00115 {
00116 
00117     const int      nself = cpl_bivector_get_size(self);
00118     const double * px    = cpl_bivector_get_x_data_const(self);
00119     const double * py    = cpl_bivector_get_y_data_const(self);
00120     int            npos  = 0;
00121     int            i     = 0;
00122 
00123     cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, -1);
00124     cpl_ensure(x_min <= x_max, CPL_ERROR_ILLEGAL_INPUT, -2);
00125     
00126     /* FIXME: Use cpl_vector_find() */
00127     while (i < nself && px[i] < x_min) i++;
00128     while (i < nself && px[i] < x_max)
00129         if (py[i++] > 0) npos++;
00130 
00131     return npos;
00132 }
00133 
00134 /*----------------------------------------------------------------------------*/
00144 /*----------------------------------------------------------------------------*/
00145 cpl_error_code irplib_polynomial_fit_2d_dispersion(cpl_polynomial * self,
00146                                                    const cpl_image * imgwave,
00147                                                    int fitdeg, double * presid)
00148 {
00149 
00150     const int        nx = cpl_image_get_size_x(imgwave);
00151     const int        ny = cpl_image_get_size_y(imgwave);
00152     const int        nbad = cpl_image_count_rejected(imgwave);
00153     const int        nsamp = nx * ny - nbad;
00154 #ifdef HAVE_CPL_POLYNOMIAL_FIT
00155     cpl_matrix     * xy_pos;
00156 #else
00157     cpl_bivector   * xy_pos;
00158     cpl_polynomial * copy;
00159 #endif
00160     double         * xdata;
00161     double         * ydata;
00162     cpl_vector     * wlen;
00163     double         * dwlen;
00164     int i, j;
00165     int k = 0;
00166 
00167     cpl_ensure_code(self    != NULL, CPL_ERROR_NULL_INPUT);
00168     cpl_ensure_code(imgwave != NULL, CPL_ERROR_NULL_INPUT);
00169     cpl_ensure_code(presid  != NULL, CPL_ERROR_NULL_INPUT);
00170     cpl_ensure_code(fitdeg > 0,      CPL_ERROR_ILLEGAL_INPUT);
00171 
00172     cpl_ensure_code(cpl_polynomial_get_dimension(self) == 2,
00173                     CPL_ERROR_ILLEGAL_INPUT);
00174 
00175 #ifdef HAVE_CPL_POLYNOMIAL_FIT
00176     xy_pos = cpl_matrix_new(2, nsamp);
00177     xdata = cpl_matrix_get_data(xy_pos);
00178     ydata = xdata + nsamp;
00179 #else
00180     xy_pos = cpl_bivector_new(nsamp);
00181     xdata = cpl_bivector_get_x_data(xy_pos);
00182     ydata = cpl_bivector_get_y_data(xy_pos);
00183 #endif
00184 
00185     dwlen = (double*)cpl_malloc(nsamp * sizeof(double));
00186     wlen = cpl_vector_wrap(nsamp, dwlen);
00187 
00188     for (i=1; i <= nx; i++) {
00189         for (j=1; j <= ny; j++) {
00190             int is_bad;
00191             const double value = cpl_image_get(imgwave, i, j, &is_bad);
00192             if (!is_bad) {
00193                 xdata[k] = i;
00194                 ydata[k] = j;
00195                 dwlen[k] = value;
00196                 k++;
00197             }
00198         }
00199     }
00200 
00201     cpl_msg_info(cpl_func, "Fitting 2D polynomial to %d X %d image, ignoring "
00202                  "%d poorly calibrated pixels", nx, ny, nbad);
00203 
00204 #ifdef HAVE_CPL_POLYNOMIAL_FIT
00205     if (cpl_polynomial_fit(self, xy_pos, NULL, wlen, NULL, CPL_FALSE, NULL,
00206                            &fitdeg) == CPL_ERROR_NONE && presid != NULL) {
00207         cpl_vector_fill_polynomial_fit_residual(wlen, wlen, NULL, self, xy_pos,
00208                                                 NULL);
00209         *presid = cpl_vector_product(wlen, wlen)/nsamp;
00210     }
00211     cpl_matrix_delete(xy_pos);
00212 #else
00213     /* FIXME: Waiting for new API of fitting function */
00214     copy = cpl_polynomial_fit_2d_create(xy_pos, wlen, fitdeg, presid);
00215     cpl_polynomial_copy(self, copy);
00216     cpl_polynomial_delete(copy);
00217     cpl_bivector_delete(xy_pos);
00218 #endif
00219 
00220     cpl_vector_delete(wlen);
00221 
00222     cpl_ensure_code(k == nsamp, CPL_ERROR_UNSPECIFIED);
00223 
00224     return CPL_ERROR_NONE;
00225 }
00226 
00227 
00228 /*----------------------------------------------------------------------------*/
00246 /*----------------------------------------------------------------------------*/
00247 cpl_error_code
00248 irplib_polynomial_find_1d_from_correlation(cpl_polynomial * self,
00249                                            int maxdeg,
00250                                            const cpl_vector * obs,
00251                                            irplib_base_spectrum_model * model,
00252                                            cpl_error_code (* filler)
00253                                            (cpl_vector *,
00254                                             const cpl_polynomial *,
00255                                             irplib_base_spectrum_model *, int),
00256                                            double pixtol,
00257                                            double pixstep,
00258                                            int hsize,
00259                                            int maxite,
00260                                            double * pxc)
00261 {
00262 
00263 #ifdef HAVE_GSL
00264     const gsl_multimin_fminimizer_type * T = gsl_multimin_fminimizer_nmsimplex;
00265     gsl_multimin_fminimizer * minimizer;
00266     gsl_multimin_function my_func;
00267     irplib_multimin data;
00268     gsl_vector * dispgsl;
00269     gsl_vector * stepsize;
00270     gsl_vector * dispprev;
00271     int status = GSL_CONTINUE;
00272     const int nobs = cpl_vector_get_size(obs);
00273     const int nfit = maxdeg + 1;
00274     cpl_errorstate prestate = cpl_errorstate_get();
00275     /* Convert pixel step to wavelength step on detector center */
00276     const double wlstep =
00277         cpl_polynomial_eval_1d_diff(self, 0.5 * (nobs + pixstep),
00278                                     0.5 * (nobs - pixstep), NULL);
00279     double wlstepi = wlstep;
00280     double size;
00281     int iter;
00282     int i;
00283 
00284 #endif
00285 
00286     cpl_ensure_code(self   != NULL, CPL_ERROR_NULL_INPUT);
00287     cpl_ensure_code(obs    != NULL, CPL_ERROR_NULL_INPUT);
00288     cpl_ensure_code(model  != NULL, CPL_ERROR_NULL_INPUT);
00289     cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
00290     cpl_ensure_code(pxc    != NULL, CPL_ERROR_NULL_INPUT);
00291 
00292     cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00293                     CPL_ERROR_ILLEGAL_INPUT);
00294 
00295     cpl_ensure_code(cpl_polynomial_get_degree(self) > 0,
00296                     CPL_ERROR_ILLEGAL_INPUT);
00297 
00298     cpl_ensure_code(maxdeg  >=  0, CPL_ERROR_ILLEGAL_INPUT);
00299     cpl_ensure_code(pixtol  > 0.0, CPL_ERROR_ILLEGAL_INPUT);
00300     cpl_ensure_code(pixstep > 0.0, CPL_ERROR_ILLEGAL_INPUT);
00301     cpl_ensure_code(hsize   >=  0, CPL_ERROR_ILLEGAL_INPUT);
00302     cpl_ensure_code(maxite  >=  0, CPL_ERROR_ILLEGAL_INPUT);
00303 
00304 #ifndef HAVE_GSL
00305     return cpl_error_set_message(cpl_func, CPL_ERROR_UNSUPPORTED_MODE,
00306                                  "GSL is not available");
00307 #else
00308 
00309     minimizer = gsl_multimin_fminimizer_alloc(T, (size_t)nfit);
00310 
00311     cpl_ensure_code(minimizer != NULL, CPL_ERROR_ILLEGAL_OUTPUT);
00312        
00313     dispgsl  = gsl_vector_alloc(nfit);
00314     stepsize = gsl_vector_alloc(nfit);
00315     dispprev = gsl_vector_alloc(nfit);
00316 
00317     for (i=0; i < nfit; i++) {
00318         const double value = cpl_polynomial_get_coeff(self, &i);
00319         gsl_vector_set(dispgsl, i, value);
00320         gsl_vector_set(stepsize, i, wlstepi);
00321         wlstepi /= (double)nobs;
00322     }
00323 
00324     my_func.n = nfit;
00325     my_func.f = &irplib_gsl_correlation;
00326     my_func.params = (void *)(&data);
00327 
00328     data.observed = obs;
00329     data.disp1d   = self;
00330     data.spectrum = cpl_vector_new(nobs + 2 * hsize);
00331     data.vxc      = cpl_vector_new(1 + 2 * hsize);
00332     data.param    = model;
00333     data.filler   = filler;
00334     data.maxxc    = 0; /* Output */
00335     data.ishift   = 0; /* Output */
00336     data.mxc      = -1.0; /* Output */
00337     data.mdisp    = NULL; /* Output */
00338 
00339     gsl_multimin_fminimizer_set (minimizer, &my_func, dispgsl, stepsize);
00340 
00341     for (iter = 0; status == GSL_CONTINUE && iter < maxite; iter++) {
00342 
00343         const double fprev = minimizer->fval;
00344 
00345         gsl_vector_memcpy(dispprev, minimizer->x);
00346         status = gsl_multimin_fminimizer_iterate(minimizer);
00347 
00348         if (status || !cpl_errorstate_is_equal(prestate)) break;
00349 
00350         size = gsl_multimin_fminimizer_size (minimizer);
00351         status = gsl_multimin_test_size (size, pixtol);
00352      
00353         if (status == GSL_SUCCESS) {
00354             cpl_msg_debug(cpl_func, "converged to minimum at");
00355 
00356             if (nfit == 0) {
00357                 cpl_msg_debug(cpl_func, "%5d %g df() = %g size = %g", 
00358                               iter,
00359                               gsl_vector_get (minimizer->x, 0)
00360                               - gsl_vector_get (dispprev, 0), 
00361                               minimizer->fval - fprev, size);
00362             } else if (nfit == 1) {
00363                 cpl_msg_debug(cpl_func, "%5d %g %g df() = %g size = %g", 
00364                               iter,
00365                               gsl_vector_get (minimizer->x, 0)
00366                               - gsl_vector_get (dispprev, 0), 
00367                               gsl_vector_get (minimizer->x, 1)
00368                               - gsl_vector_get (dispprev, 1), 
00369                               minimizer->fval - fprev, size);
00370             } else {
00371                 cpl_msg_debug(cpl_func, "%5d %g %g %g df() = %g size = %g", 
00372                               iter,
00373                               gsl_vector_get (minimizer->x, 0)
00374                               - gsl_vector_get (dispprev, 0), 
00375                               gsl_vector_get (minimizer->x, 1)
00376                               - gsl_vector_get (dispprev, 1), 
00377                               gsl_vector_get (minimizer->x, 2)
00378                               - gsl_vector_get (dispprev, 2), 
00379                               minimizer->fval - fprev, size);
00380             }
00381         }
00382     }
00383 
00384     if (status == GSL_SUCCESS && cpl_errorstate_is_equal(prestate)) {
00385         if (data.mxc > -minimizer->fval) {
00386             *pxc = data.mxc;
00387             cpl_msg_warning(cpl_func, "Local maximum: %g(%d) > %g",
00388                             data.mxc, data.ishift, -minimizer->fval);
00389             cpl_polynomial_shift_1d(data.mdisp, 0, (double)data.ishift);
00390             cpl_polynomial_copy(self, data.mdisp);
00391             status = GSL_CONTINUE;
00392         } else {
00393             *pxc = -minimizer->fval;
00394             for (i=0; i < nfit; i++) {
00395                 const double value = gsl_vector_get(minimizer->x, i);
00396                 cpl_polynomial_set_coeff(self, &i, value);
00397             }
00398         }
00399     }
00400 
00401     cpl_vector_delete(data.spectrum);
00402     cpl_vector_delete(data.vxc);
00403     cpl_polynomial_delete(data.mdisp);
00404     gsl_multimin_fminimizer_free(minimizer);
00405     gsl_vector_free(dispgsl);
00406     gsl_vector_free(dispprev);
00407     gsl_vector_free(stepsize);
00408 
00409     cpl_ensure_code(status != GSL_CONTINUE, CPL_ERROR_CONTINUE);
00410     cpl_ensure_code(status == GSL_SUCCESS, CPL_ERROR_DATA_NOT_FOUND);
00411     cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
00412 
00413     return CPL_ERROR_NONE;
00414 #endif
00415 }
00416 
00417 
00418 /*----------------------------------------------------------------------------*/
00447 /*----------------------------------------------------------------------------*/
00448 cpl_error_code
00449 irplib_vector_fill_line_spectrum(cpl_vector * self,
00450                                  const cpl_polynomial * disp,
00451                                  irplib_base_spectrum_model * lsslamp,
00452                                  int hsize)
00453 {
00454 
00455     irplib_line_spectrum_model * arclamp
00456         = (irplib_line_spectrum_model *)lsslamp;
00457     cpl_error_code error;
00458 
00459     cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
00460 
00461     arclamp->cost++;
00462 
00463     error = irplib_vector_fill_line_spectrum_model(self,
00464                                                    arclamp->linepix,
00465                                                    arclamp->erftmp,
00466                                                    disp,
00467                                                    arclamp->lines,
00468                                                    arclamp->wslit,
00469                                                    arclamp->wfwhm,
00470                                                    arclamp->xtrunc,
00471                                                    hsize, CPL_FALSE, CPL_FALSE,
00472                                                    &(arclamp->ulines));
00473     cpl_ensure_code(!error, error);
00474 
00475     arclamp->xcost++;
00476 
00477     return CPL_ERROR_NONE;
00478 }
00479 
00480 /*----------------------------------------------------------------------------*/
00494 /*----------------------------------------------------------------------------*/
00495 cpl_error_code
00496 irplib_vector_fill_logline_spectrum(cpl_vector * self,
00497                                     const cpl_polynomial * disp,
00498                                     irplib_base_spectrum_model * lsslamp,
00499                                     int hsize)
00500 {
00501 
00502     irplib_line_spectrum_model * arclamp
00503         = (irplib_line_spectrum_model *)lsslamp;
00504     cpl_error_code error;
00505 
00506     cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
00507 
00508     arclamp->cost++;
00509 
00510     error = irplib_vector_fill_line_spectrum_model(self,
00511                                                    arclamp->linepix,
00512                                                    arclamp->erftmp,
00513                                                    disp,
00514                                                    arclamp->lines,
00515                                                    arclamp->wslit,
00516                                                    arclamp->wfwhm,
00517                                                    arclamp->xtrunc,
00518                                                    hsize, CPL_FALSE, CPL_TRUE,
00519                                                    &(arclamp->ulines));
00520     cpl_ensure_code(!error, error);
00521 
00522     arclamp->xcost++;
00523 
00524     return CPL_ERROR_NONE;
00525 }
00526 
00527 
00528 /*----------------------------------------------------------------------------*/
00542 /*----------------------------------------------------------------------------*/
00543 cpl_error_code
00544 irplib_vector_fill_line_spectrum_fast(cpl_vector * self,
00545                                       const cpl_polynomial * disp,
00546                                       irplib_base_spectrum_model * lsslamp,
00547                                       int hsize)
00548 {
00549 
00550     irplib_line_spectrum_model * arclamp
00551         = (irplib_line_spectrum_model *)lsslamp;
00552     cpl_error_code error;
00553 
00554     cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
00555 
00556     arclamp->cost++;
00557 
00558     error = irplib_vector_fill_line_spectrum_model(self,
00559                                                    arclamp->linepix,
00560                                                    arclamp->erftmp,
00561                                                    disp,
00562                                                    arclamp->lines,
00563                                                    arclamp->wslit,
00564                                                    arclamp->wfwhm,
00565                                                    arclamp->xtrunc,
00566                                                    hsize, CPL_TRUE, CPL_FALSE,
00567                                                    &(arclamp->ulines));
00568     cpl_ensure_code(!error, error);
00569 
00570     arclamp->xcost++;
00571 
00572     return CPL_ERROR_NONE;
00573 }
00574 
00575 /*----------------------------------------------------------------------------*/
00589 /*----------------------------------------------------------------------------*/
00590 cpl_error_code
00591 irplib_vector_fill_logline_spectrum_fast(cpl_vector * self,
00592                                          const cpl_polynomial * disp,
00593                                          irplib_base_spectrum_model * lsslamp,
00594                                          int hsize)
00595 {
00596 
00597     irplib_line_spectrum_model * arclamp
00598         = (irplib_line_spectrum_model *)lsslamp;
00599     cpl_error_code error;
00600 
00601     cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
00602 
00603     arclamp->cost++;
00604 
00605     error = irplib_vector_fill_line_spectrum_model(self,
00606                                                    arclamp->linepix,
00607                                                    arclamp->erftmp,
00608                                                    disp,
00609                                                    arclamp->lines,
00610                                                    arclamp->wslit,
00611                                                    arclamp->wfwhm,
00612                                                    arclamp->xtrunc,
00613                                                    hsize, CPL_TRUE, CPL_TRUE,
00614                                                    &(arclamp->ulines));
00615     cpl_ensure_code(!error, error);
00616 
00617     arclamp->xcost++;
00618 
00619     return CPL_ERROR_NONE;
00620 }
00621 
00622 /*----------------------------------------------------------------------------*/
00633 /*----------------------------------------------------------------------------*/
00634 cpl_error_code irplib_plot_spectrum_and_model(const cpl_vector * self,
00635                                               const cpl_polynomial * disp1d,
00636                                               irplib_base_spectrum_model * model,
00637                                               cpl_error_code (* filler)
00638                                               (cpl_vector *,
00639                                                const cpl_polynomial *,
00640                                                irplib_base_spectrum_model *,
00641                                                int))
00642 {
00643 
00644     cpl_errorstate prestate = cpl_errorstate_get();
00645     cpl_vector * wl;
00646     cpl_vector * spectrum;
00647     cpl_vector * vxc;
00648     const int len = cpl_vector_get_size(self);
00649     double maxval, xc;
00650     int ixc;
00651     int error = 0;
00652 
00653     cpl_ensure_code(self   != NULL, CPL_ERROR_NULL_INPUT);
00654     cpl_ensure_code(disp1d != NULL, CPL_ERROR_NULL_INPUT);
00655     cpl_ensure_code(model  != NULL, CPL_ERROR_NULL_INPUT);
00656     cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
00657 
00658     cpl_ensure_code(cpl_polynomial_get_dimension(disp1d) == 1,
00659                     CPL_ERROR_ILLEGAL_INPUT);
00660 
00661     cpl_ensure_code(cpl_polynomial_get_degree(disp1d) > 0,
00662                     CPL_ERROR_ILLEGAL_INPUT);
00663 
00664     wl = cpl_vector_new(len);
00665     spectrum = cpl_vector_new(len);
00666     vxc = cpl_vector_new(1);
00667 
00668     error |= (int)cpl_vector_fill_polynomial(wl, disp1d, 1.0, 1.0);
00669     error |= filler(spectrum, disp1d, model, 0);
00670 
00671     ixc = cpl_vector_correlate(vxc, self, spectrum);
00672     xc = cpl_vector_get(vxc, 0);
00673 
00674     maxval = cpl_vector_get_max(spectrum);
00675     if (maxval != 0.0) 
00676         error |= cpl_vector_multiply_scalar(spectrum,
00677                                              cpl_vector_get_max(self)/maxval);
00678     if (!error) {
00679         const cpl_vector * spair[] = {wl, self, spectrum};
00680         char * pre = cpl_sprintf("set grid;set xlabel 'Wavelength (%g -> %g)'; "
00681                                  "set ylabel 'Intensity';", cpl_vector_get(wl, 0),
00682                                  cpl_vector_get(wl, len-1));
00683         char * title = cpl_sprintf("t 'Observed and modelled spectra (%d pixel "
00684                                    "XC=%g) ' w linespoints", len, xc);
00685 
00686         error = cpl_plot_vectors(pre, title, "", spair, 3);
00687         cpl_free(pre);
00688         cpl_free(title);
00689     }
00690 
00691     cpl_vector_delete(wl);
00692     cpl_vector_delete(spectrum);
00693     cpl_vector_delete(vxc);
00694 
00695     cpl_errorstate_set(prestate);
00696 
00697     return CPL_ERROR_NONE;
00698 }
00699 
00700 /*----------------------------------------------------------------------------*/
00718 /*----------------------------------------------------------------------------*/
00719 cpl_error_code
00720 irplib_bivector_find_shift_from_correlation(cpl_bivector * self,
00721                                             const cpl_polynomial * disp,
00722                                             const cpl_vector * obs,
00723                                             irplib_base_spectrum_model * model,
00724                                             cpl_error_code (*filler)
00725                                             (cpl_vector *,
00726                                              const cpl_polynomial *,
00727                                              irplib_base_spectrum_model *, int),
00728                                             int hsize,
00729                                             cpl_boolean doplot,
00730                                             double *pxc)
00731 {
00732 
00733     const int      nobs   = cpl_vector_get_size(obs);
00734     const int      nmodel = 2 * hsize + nobs;
00735     cpl_vector   * xself = cpl_bivector_get_x(self);
00736     cpl_vector   * yself = cpl_bivector_get_y(self);
00737     cpl_vector   * mspec1d;
00738     cpl_vector   * xcorr;
00739     cpl_error_code error = CPL_ERROR_NONE;
00740     double         xcprev, xcnext;
00741     int            ixc, imax = 0;
00742     int i;
00743 
00744     cpl_ensure_code(self   != NULL, CPL_ERROR_NULL_INPUT);
00745     cpl_ensure_code(disp   != NULL, CPL_ERROR_NULL_INPUT);
00746     cpl_ensure_code(obs    != NULL, CPL_ERROR_NULL_INPUT);
00747     cpl_ensure_code(model  != NULL, CPL_ERROR_NULL_INPUT);
00748     cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
00749     cpl_ensure_code(hsize  >  0,    CPL_ERROR_ILLEGAL_INPUT);
00750 
00751     mspec1d = cpl_vector_new(nmodel);
00752 
00753     if (filler(mspec1d, disp, model, hsize)) {
00754         cpl_vector_delete(mspec1d);
00755         return cpl_error_set_where(cpl_func);
00756     }
00757 
00758     /* Should not be able to fail now */
00759     xcorr = cpl_vector_new(1 + 2 * hsize);
00760     ixc = cpl_vector_correlate(xcorr, mspec1d, obs);
00761 
00762 #ifdef IRPLIB_SPC_DUMP
00763     /* Need irplib_wavecal.c rev. 1.12 through 1.15 */
00764     irplib_polynomial_dump_corr_step(disp, xcorr, "Shift");
00765 #endif
00766 
00767     cpl_vector_delete(mspec1d);
00768 
00769     /* Find local maxima. */
00770     /* FIXME(?): Also include stationary points */
00771     i = 0;
00772     xcprev = cpl_vector_get(xcorr, i);
00773     xcnext = cpl_vector_get(xcorr, i+1);
00774 
00775     if (xcprev >= xcnext) {
00776         /* 1st data point is an extreme */
00777         /* FIXME: This could also be an error, recoverable by caller by
00778            increasing hsize */
00779         imax++;
00780 
00781         cpl_vector_set(xself, 0, i - hsize);
00782         cpl_vector_set(yself, 0, xcprev);
00783 
00784     }
00785 
00786     for (i = 1; i < 2 * hsize; i++) {
00787         const double xc = xcnext;
00788         xcnext = cpl_vector_get(xcorr, i+1);
00789         if (xc >= xcprev && xc >= xcnext) {
00790             /* Found (local) maximum at shift i - hsize */
00791             int j;
00792 
00793             imax++;
00794 
00795             if (cpl_bivector_get_size(self) < imax) {
00796                 cpl_vector_set_size(xself, imax);
00797                 cpl_vector_set_size(yself, imax);
00798             }
00799 
00800             for (j = imax-1; j > 0; j--) {
00801                 if (xc <= cpl_vector_get(yself, j-1)) break;
00802                 cpl_vector_set(xself, j, cpl_vector_get(xself, j-1));
00803                 cpl_vector_set(yself, j, cpl_vector_get(yself, j-1));
00804             }
00805             cpl_vector_set(xself, j, i - hsize);
00806             cpl_vector_set(yself, j, xc);
00807         }
00808         xcprev = xc;
00809     }
00810 
00811     /* assert( i == 2 * hsize ); */
00812 
00813     if (xcnext >= xcprev) {
00814         /* Last data point is an extreme */
00815         /* FIXME: This could also be an error, recoverable by caller by
00816            increasing hsize */
00817         int j;
00818 
00819         imax++;
00820 
00821         if (cpl_bivector_get_size(self) < imax) {
00822             cpl_vector_set_size(xself, imax);
00823             cpl_vector_set_size(yself, imax);
00824         }
00825 
00826         for (j = imax-1; j > 0; j--) {
00827             if (xcnext <= cpl_vector_get(yself, j-1)) break;
00828             cpl_vector_set(xself, j, cpl_vector_get(xself, j-1));
00829             cpl_vector_set(yself, j, cpl_vector_get(yself, j-1));
00830         }
00831         cpl_vector_set(xself, j, i - hsize);
00832         cpl_vector_set(yself, j, xcnext);
00833 
00834     }
00835 
00836     if (doplot) {
00837         cpl_vector * xvals = cpl_vector_new(1 + 2 * hsize);
00838         cpl_bivector * bcorr = cpl_bivector_wrap_vectors(xvals, xcorr);
00839         double x = (double)-hsize;
00840         char * title = cpl_sprintf("t 'Cross-correlation of shifted %d-pixel "
00841                                    "spectrum (XCmax=%g at %d)' w linespoints",
00842                                    nobs, cpl_vector_get(xcorr, ixc),
00843                                    ixc - hsize);
00844 
00845         for (i = 0; i < 1 + 2 * hsize; i++, x += 1.0) {
00846             cpl_vector_set(xvals, i, x);
00847         }
00848 
00849         cpl_plot_bivector("set grid;set xlabel 'Offset [pixel]';", title,
00850                              "", bcorr);
00851         cpl_bivector_unwrap_vectors(bcorr);
00852         cpl_vector_delete(xvals);
00853         cpl_free(title);
00854     }
00855 
00856     if (pxc != NULL) *pxc = cpl_vector_get(xcorr, hsize);
00857 
00858     cpl_vector_delete(xcorr);
00859 
00860     if (imax < 1) {
00861         error = CPL_ERROR_DATA_NOT_FOUND;
00862     } else if (cpl_bivector_get_size(self) > imax) {
00863         cpl_vector_set_size(xself, imax);
00864         cpl_vector_set_size(yself, imax);
00865     }
00866 
00867     /* Propagate error, if any */
00868     return cpl_error_set(cpl_func, error);
00869 }
00870 
00871 /*----------------------------------------------------------------------------*/
00884 /*----------------------------------------------------------------------------*/
00885 cpl_error_code
00886 irplib_polynomial_shift_1d_from_correlation(cpl_polynomial * self,
00887                                             const cpl_vector * obs,
00888                                             irplib_base_spectrum_model * model,
00889                                             cpl_error_code (*filler)
00890                                             (cpl_vector *,
00891                                              const cpl_polynomial *,
00892                                              irplib_base_spectrum_model *, int),
00893                                             int hsize,
00894                                             cpl_boolean doplot,
00895                                             double * pxc)
00896 {
00897 
00898     const int      nobs   = cpl_vector_get_size(obs);
00899     const int      nmodel = 2 * hsize + nobs;
00900     cpl_vector   * mspec1d;
00901     cpl_vector   * xcorr;
00902     cpl_error_code error;
00903     int            ixc, xxc;
00904     double         xc;
00905 
00906     cpl_ensure_code(self   != NULL, CPL_ERROR_NULL_INPUT);
00907     cpl_ensure_code(obs    != NULL, CPL_ERROR_NULL_INPUT);
00908     cpl_ensure_code(model  != NULL, CPL_ERROR_NULL_INPUT);
00909     cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
00910     cpl_ensure_code(hsize  >  0,    CPL_ERROR_ILLEGAL_INPUT);
00911 
00912     mspec1d = cpl_vector_new(nmodel);
00913 
00914     if (filler(mspec1d, self, model, hsize)) {
00915         cpl_vector_delete(mspec1d);
00916         cpl_ensure_code(0, cpl_error_get_code());
00917     }
00918 
00919     /* Should not be able to fail now */
00920     xcorr = cpl_vector_new(1 + 2 * hsize);
00921     ixc = cpl_vector_correlate(xcorr, mspec1d, obs);
00922 
00923 #ifdef IRPLIB_SPC_DUMP
00924     /* Need irplib_wavecal.c rev. 1.12 through 1.15 */
00925     irplib_polynomial_dump_corr_step(self, xcorr, "Shift");
00926 #endif
00927 
00928     cpl_vector_delete(mspec1d);
00929 
00930     xxc = ixc - hsize;
00931 
00932     error = cpl_polynomial_shift_1d(self, 0, (double)xxc);
00933 
00934     xc = cpl_vector_get(xcorr, ixc);
00935 
00936     cpl_msg_info(cpl_func, "Shifting %d pixels (%g < %g)", xxc,
00937                  cpl_vector_get(xcorr, hsize), xc);
00938 
00939     if (doplot) {
00940         cpl_vector * xvals = cpl_vector_new(1 + 2 * hsize);
00941         cpl_bivector * bcorr = cpl_bivector_wrap_vectors(xvals, xcorr);
00942         int i;
00943         double x = (double)-hsize;
00944         char * title = cpl_sprintf("t 'Cross-correlation of shifted %d-pixel "
00945                                    "spectrum (XCmax=%g at %d)' w linespoints",
00946                                    nobs, cpl_vector_get(xcorr, ixc), xxc);
00947 
00948         for (i = 0; i < 1 + 2 * hsize; i++, x += 1.0) {
00949             cpl_vector_set(xvals, i, x);
00950         }
00951 
00952         cpl_plot_bivector("set grid;set xlabel 'Offset [pixel]';", title,
00953                              "", bcorr);
00954         cpl_bivector_unwrap_vectors(bcorr);
00955         cpl_vector_delete(xvals);
00956         cpl_free(title);
00957     }
00958 
00959     cpl_vector_delete(xcorr);
00960 
00961     cpl_ensure_code(!error, error);
00962 
00963     if (pxc != NULL) *pxc = xc;
00964 
00965     return CPL_ERROR_NONE;
00966 
00967 }
00968 
00969 
00970 /*----------------------------------------------------------------------------*/
00990 /*----------------------------------------------------------------------------*/
00991 cpl_error_code
00992 irplib_vector_fill_line_spectrum_model(cpl_vector * self,
00993                                        cpl_vector * linepix,
00994                                        cpl_vector * erftmp,
00995                                        const cpl_polynomial * disp,
00996                                        const cpl_bivector * lines,
00997                                        double wslit,
00998                                        double wfwhm,
00999                                        double xtrunc,
01000                                        int hsize,
01001                                        cpl_boolean dofast,
01002                                        cpl_boolean dolog,
01003                                        unsigned * pulines)
01004 {
01005 
01006     cpl_errorstate     prestate;
01007     const double       sigma = wfwhm * CPL_MATH_SIG_FWHM;
01008     const cpl_vector * xlines  = cpl_bivector_get_x_const(lines);
01009     const double     * dxlines = cpl_vector_get_data_const(xlines);
01010     const double     * dylines = cpl_bivector_get_y_data_const(lines);
01011     double           * plinepix
01012         = linepix ? cpl_vector_get_data(linepix) : NULL;
01013     const int          nlines  = cpl_vector_get_size(xlines);
01014     const int          nself   = cpl_vector_get_size(self);
01015     double           * dself   = cpl_vector_get_data(self);
01016     cpl_polynomial   * dispi;
01017     double           * profile = NULL;
01018     const int          i0 = 0;
01019     const double       p0 = cpl_polynomial_get_coeff(disp, &i0);
01020     double             wl;
01021     double             xpos = (double)(1-hsize)-xtrunc;
01022     const double       xmax = (double)(nself-hsize)+xtrunc;
01023     double             xderiv, xextreme;
01024     cpl_error_code     error = CPL_ERROR_NONE;
01025     int                iline;
01026     unsigned           ulines = 0;
01027 
01028     cpl_ensure_code(self    != NULL, CPL_ERROR_NULL_INPUT);
01029     cpl_ensure_code(disp    != NULL, CPL_ERROR_NULL_INPUT);
01030     cpl_ensure_code(lines   != NULL, CPL_ERROR_NULL_INPUT);
01031 
01032     cpl_ensure_code(wslit  >  0.0, CPL_ERROR_ILLEGAL_INPUT);
01033     cpl_ensure_code(wfwhm  >  0.0, CPL_ERROR_ILLEGAL_INPUT);
01034     cpl_ensure_code(hsize  >= 0,   CPL_ERROR_ILLEGAL_INPUT);
01035     cpl_ensure_code(xtrunc >  0.0, CPL_ERROR_ILLEGAL_INPUT);
01036     cpl_ensure_code(nself  > 2 * hsize, CPL_ERROR_ILLEGAL_INPUT);
01037 
01038     cpl_ensure_code(cpl_polynomial_get_dimension(disp) == 1,
01039                     CPL_ERROR_ILLEGAL_INPUT);
01040     cpl_ensure_code(cpl_polynomial_get_degree(disp) > 0,
01041                     CPL_ERROR_ILLEGAL_INPUT);
01042 
01043     /* The smallest wavelength contributing to the spectrum. */
01044     wl = cpl_polynomial_eval_1d(disp, xpos, &xderiv);
01045 
01046     if (wl <= 0.0) return
01047         cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT, __FILE__,
01048                                     __LINE__, "Non-positive wavelength at x=%g: "
01049                                     "P(x)=%g, P'(x)=%g", xpos, wl, xderiv);
01050 
01051     if (xderiv <= 0.0) return
01052         cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT, __FILE__,
01053                                     __LINE__, "Non-increasing dispersion at "
01054                                     "x=%g: P'(x)=%g, P(x)=%g", xpos, xderiv, wl);
01055 
01056     /* Find the 1st line */
01057     iline = cpl_vector_find(xlines, wl);
01058 
01059     /* The first line must be at least at wl */
01060     if (dxlines[iline] < wl) iline++;
01061 
01062     if (iline >= nlines) return
01063         cpl_error_set_message_macro(cpl_func, CPL_ERROR_DATA_NOT_FOUND, __FILE__,
01064                                     __LINE__, "The %d-line catalogue has only "
01065                                     "lines below P(%g)=%g > %g", nlines, xpos,
01066                                     wl, dxlines[nlines-1]);
01067 
01068     memset(dself, 0, nself * sizeof(double));
01069 
01070     dispi = cpl_polynomial_duplicate(disp);
01071 
01072     /* Verify monotony of dispersion */
01073     cpl_polynomial_derivative(dispi, 0);
01074 
01075     prestate = cpl_errorstate_get();
01076 
01077     if (cpl_polynomial_solve_1d(dispi, 0.5*(nlines+1), &xextreme, 1)) {
01078         cpl_errorstate_set(prestate);
01079     } else if (xpos < xextreme && xextreme < xmax) {
01080         cpl_polynomial_delete(dispi);
01081         return cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
01082                                            __FILE__, __LINE__, "Non-monotone "
01083                                            "dispersion at x=%g: P'(x)=0, "
01084                                            "P(x)=%g", xextreme,
01085                                            cpl_polynomial_eval_1d(disp, xextreme,
01086                                                                   NULL));
01087     }
01088 
01089     if (dofast) {
01090         const int npix = 1+(int)xtrunc;
01091 
01092         if (erftmp != NULL && cpl_vector_get_size(erftmp) == npix &&
01093             cpl_vector_get(erftmp, 0) > 0.0) {
01094             profile = cpl_vector_get_data(erftmp);
01095         } else {
01096 
01097             const double yval =  0.5 / wslit;
01098             const double x0p  =  0.5 * wslit + 0.5;
01099             const double x0n  = -0.5 * wslit + 0.5;
01100             double       x1diff
01101                 = irplib_erf_antideriv(x0p, sigma)
01102                 - irplib_erf_antideriv(x0n, sigma);
01103             int          ipix;
01104 
01105             if (erftmp == NULL) {
01106                 profile = (double*)cpl_malloc(sizeof(double)*(size_t)npix);
01107             } else {
01108                 cpl_vector_set_size(erftmp, npix);
01109                 profile = cpl_vector_get_data(erftmp);
01110             }
01111 
01112             profile[0] = 2.0 * yval * x1diff;
01113 
01114             for (ipix = 1; ipix < npix; ipix++) {
01115                 const double x1 = (double)ipix;
01116                 const double x1p = x1 + 0.5 * wslit + 0.5;
01117                 const double x1n = x1 - 0.5 * wslit + 0.5;
01118                 const double x0diff = x1diff;
01119 
01120                 x1diff = irplib_erf_antideriv(x1p, sigma)
01121                     - irplib_erf_antideriv(x1n, sigma);
01122 
01123                 profile[ipix] = yval * (x1diff - x0diff);
01124 
01125             }
01126         }
01127     }
01128 
01129     cpl_polynomial_copy(dispi, disp);
01130 
01131     /* FIXME: A custom version of cpl_polynomial_solve_1d() which returns
01132        P'(xpos) can be used for the 1st NR-iteration. */
01133     /* Further, the sign of P'(xpos) could be checked for all lines. */
01134     /* Perform 1st NR-iteration in solving for P(xpos) = dxlines[iline] */
01135     xpos -= (wl - dxlines[iline]) / xderiv;
01136 
01137     /* Iterate through the lines */
01138     for (; !error && iline < nlines; iline++) {
01139 
01140         /* Lines may have a non-physical intensity (e.g. zero) to indicate some
01141            property of the line, e.g. unknown intensity due to blending */
01142         if (dylines[iline] <= 0.0) continue;
01143 
01144         /* Use 1st guess, if available (Use 0.0 to flag unavailable) */
01145         if (plinepix != NULL && plinepix[iline] > 0.0) xpos = plinepix[iline];
01146 
01147         if (xpos > xmax) xpos = xmax; /* FIXME: Better to limit xpos ? */
01148 
01149         /* Find the (sub-) pixel position of the line */
01150         error = cpl_polynomial_set_coeff(dispi, &i0, p0 - dxlines[iline]) ||
01151             cpl_polynomial_solve_1d(dispi, xpos, &xpos, 1);
01152 
01153         if (xpos > xmax) {
01154             if (error) {
01155                 error = 0;
01156                 cpl_msg_debug(cpl_func, "Stopping spectrum fill at line %d/%d "
01157                              "at xpos=%g > xmax=%g",
01158                              iline, nlines, xpos, xmax);
01159                 cpl_errorstate_dump(prestate, CPL_FALSE,
01160                                     irplib_errorstate_dump_debug);
01161                 cpl_errorstate_set(prestate);
01162             }
01163             break;
01164         } else if (error) {
01165             if (linepix != NULL && ulines) (void)cpl_vector_fill(linepix, 0.0);
01166             (void)cpl_error_set_message_macro(cpl_func, cpl_error_get_code(),
01167                                               __FILE__, __LINE__,
01168                                               "Could not find pixel-position "
01169                                               "of line %d/%d at wavelength=%g."
01170                                               " xpos=%g, xmax=%g",
01171                                               iline, nlines, dxlines[iline],
01172                                               xpos, xmax);
01173             break;
01174         } else if (dofast) {
01175             const double frac  = fabs(xpos - floor(xpos));
01176 #ifdef IRPLIB_WAVECAL_FAST_FAST
01177             const double frac0 = 1.0 - frac; /* Weight opposite of distance */
01178 #else
01179             /* Center intensity correctly */
01180             const double ep1pw = irplib_erf_antideriv(frac + 0.5 * wslit, sigma);
01181             const double en1pw = irplib_erf_antideriv(frac + 0.5 * wslit - 1.0,
01182                                                       sigma);
01183             const double ep1nw = irplib_erf_antideriv(frac - 0.5 * wslit, sigma);
01184             const double en1nw = irplib_erf_antideriv(frac - 0.5 * wslit - 1.0,
01185                                                       sigma);
01186             const double frac0
01187                 = (en1nw - en1pw) / (ep1pw - en1pw - ep1nw + en1nw);
01188 
01189 #endif
01190             const double frac1 = 1.0 - frac0;
01191             const double yval0 = frac0 * dylines[iline];
01192             const double yval1 = frac1 * dylines[iline];
01193             const int    npix  = 1+(int)xtrunc;
01194             int          ipix;
01195             int          i0n    = hsize - 1 + floor(xpos);
01196             int          i0p    = i0n;
01197             int          i1n    = i0n + 1;
01198             int          i1p    = i1n;
01199             cpl_boolean  didline = CPL_FALSE;
01200 
01201 
01202             /* Update 1st guess for next time, if available */
01203             if (plinepix != NULL) plinepix[iline] =  xpos;
01204 
01205             if (frac0 < 0.0) {
01206                 (void)cpl_error_set_message_macro(cpl_func,
01207                                                   CPL_ERROR_UNSPECIFIED,
01208                                                   __FILE__, __LINE__,
01209                                                   "Illegal split at x=%g: %g + "
01210                                                   "%g = 1", xpos, frac0, frac1);
01211 #ifdef IRPLIB_WAVEVAL_DEBUG
01212             } else {
01213                 cpl_msg_warning(cpl_func,"profile split at x=%g: %g + %g = 1",
01214                                 xpos, frac0, frac1);
01215 #endif
01216             }
01217 
01218             for (ipix = 0; ipix < npix; ipix++, i0n--, i0p++, i1n--, i1p++) {
01219 
01220                 if (i0n >= 0 && i0n < nself) {
01221                     dself[i0n] += yval0 * profile[ipix];
01222                     didline = CPL_TRUE;
01223                 }
01224                 if (i1n >= 0 && i1n < nself && ipix + 1 < npix) {
01225                     dself[i1n] += yval1 * profile[ipix+1];
01226                     didline = CPL_TRUE;
01227                 }
01228 
01229                 if (ipix == 0) continue;
01230 
01231                 if (i0p >= 0 && i0p < nself) {
01232                     dself[i0p] += yval0 * profile[ipix];
01233                     didline = CPL_TRUE;
01234                 }
01235                 if (i1p >= 0 && i1p < nself && ipix + 1 < npix) {
01236                     dself[i1p] += yval1 * profile[ipix+1];
01237                     didline = CPL_TRUE;
01238                 }
01239             }
01240 
01241             if (didline) ulines++;
01242 
01243         } else {
01244             const double yval = 0.5 * dylines[iline] / wslit;
01245             const int    ifirst = IRPLIB_MAX((int)(xpos-xtrunc+0.5), 1-hsize);
01246             const int    ilast  = IRPLIB_MIN((int)(xpos+xtrunc), nself-hsize);
01247             int          ipix;
01248             const double x0 = (double)ifirst - xpos;
01249             const double x0p = x0 + 0.5*wslit - 0.5;
01250             const double x0n = x0 - 0.5*wslit - 0.5;
01251             double       x1diff
01252                 = irplib_erf_antideriv(x0p, sigma)
01253                 - irplib_erf_antideriv(x0n, sigma);
01254 
01255             /* Update 1st guess for next time, if available */
01256             if (plinepix != NULL) plinepix[iline] =  xpos;
01257 
01258             if (ilast >= ifirst) ulines++;
01259 
01260             for (ipix = ifirst; ipix <= ilast; ipix++) {
01261                 const double x1 = (double)ipix - xpos;
01262                 const double x1p = x1 + 0.5*wslit + 0.5;
01263                 const double x1n = x1 - 0.5*wslit + 0.5;
01264                 const double x0diff = x1diff;
01265 
01266                 x1diff = irplib_erf_antideriv(x1p, sigma)
01267                     - irplib_erf_antideriv(x1n, sigma);
01268 
01269                 dself[ipix+hsize-1] += yval * (x1diff - x0diff);
01270 
01271             }
01272         }
01273     }
01274 
01275     cpl_polynomial_delete(dispi);
01276     if (erftmp == NULL) cpl_free(profile);
01277 
01278     cpl_ensure_code(!error, cpl_error_get_code());
01279 
01280     if (dolog) {
01281         int i;
01282         for (i = 0; i < nself; i++) {
01283             dself[i] = dself[i] > 0.0 ? log(1.0 + dself[i]) : 0.0;
01284         }
01285     }
01286 
01287     if (!ulines) return
01288         cpl_error_set_message_macro(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
01289                                     __FILE__, __LINE__, "The %d-line "
01290                                     "catalogue has no lines in the range "
01291                                     "%g -> P(%g)=%g", nlines, wl, xmax,
01292                                     cpl_polynomial_eval_1d(disp, xmax, NULL));
01293 
01294     if (pulines != NULL) *pulines = ulines;
01295 
01296     return CPL_ERROR_NONE;
01297 }
01298 
01299 /*----------------------------------------------------------------------------*/
01308 /*----------------------------------------------------------------------------*/
01309 inline double irplib_erf_antideriv(double x, double sigma)
01310 {
01311     return x * erf( x / (sigma * CPL_MATH_SQRT2))
01312        + 2.0 * sigma/CPL_MATH_SQRT2PI * exp(-0.5 * x * x / (sigma * sigma));
01313 }
01314 
01315 
01316 #ifdef HAVE_GSL
01317 
01318 /*----------------------------------------------------------------------------*/
01326 /*----------------------------------------------------------------------------*/
01327 static double irplib_gsl_correlation(const gsl_vector * self, void * data)
01328 {
01329 
01330     irplib_multimin * mindata = (irplib_multimin *)data;
01331     cpl_errorstate prestate = cpl_errorstate_get();
01332     int nobs, nmodel, ndiff;
01333     int i;
01334 
01335     cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
01336     cpl_ensure(data != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
01337 
01338     cpl_ensure(mindata->filler   != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
01339     cpl_ensure(mindata->observed != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
01340     cpl_ensure(mindata->spectrum != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
01341 
01342     nobs   = cpl_vector_get_size(mindata->observed);
01343     nmodel = cpl_vector_get_size(mindata->spectrum);
01344     ndiff  = nmodel - nobs;
01345 
01346     cpl_ensure((ndiff & 1) == 0, CPL_ERROR_ILLEGAL_INPUT, GSL_NAN);
01347 
01348     cpl_ensure(cpl_vector_get_size(mindata->vxc) == 1 + ndiff,
01349                CPL_ERROR_ILLEGAL_INPUT, GSL_NAN);
01350 
01351     ndiff /= 2;
01352 
01353     for (i=0; i < (int)self->size; i++) {
01354         const double value = gsl_vector_get(self, i);
01355         cpl_polynomial_set_coeff(mindata->disp1d, &i, value);
01356     }
01357 
01358     if (mindata->filler(mindata->spectrum, mindata->disp1d,
01359                         mindata->param, ndiff)
01360         || !cpl_errorstate_is_equal(prestate)) {
01361 
01362         /* The fill failed. Ensure the discarding of this candidate by
01363            setting the cross-correlation to its minimum possible value. */
01364 
01365         (void)cpl_vector_fill(mindata->vxc, -1.0);
01366 
01367         mindata->maxxc = ndiff;
01368 
01369         if (!cpl_errorstate_is_equal(prestate)) {
01370                 cpl_msg_debug(cpl_func, "Spectrum fill failed:");
01371                 cpl_errorstate_dump(prestate, CPL_FALSE,
01372                                     irplib_errorstate_dump_debug);
01373                 cpl_errorstate_set(prestate);
01374         }
01375     } else {
01376 
01377         mindata->maxxc = cpl_vector_correlate(mindata->vxc,
01378                                               mindata->spectrum,
01379                                               mindata->observed);
01380     }
01381 
01382 #ifdef IRPLIB_SPC_DUMP
01383     /* Need irplib_wavecal.c rev. 1.12 through 1.15 */
01384     irplib_polynomial_dump_corr_step(mindata->disp1d, mindata->vxc,
01385                                      "Optimize");
01386 #endif
01387 
01388     mindata->xc = cpl_vector_get(mindata->vxc, ndiff);
01389 
01390     if (mindata->maxxc != ndiff &&
01391         cpl_vector_get(mindata->vxc, mindata->maxxc) > mindata->mxc) {
01392         const irplib_base_spectrum_model * arclamp
01393             = (const irplib_base_spectrum_model *)mindata->param;
01394 
01395         if (mindata->mdisp == NULL) {
01396             mindata->mdisp = cpl_polynomial_duplicate(mindata->disp1d);
01397         } else {
01398             cpl_polynomial_copy(mindata->mdisp, mindata->disp1d);
01399         }
01400         mindata->mxc = cpl_vector_get(mindata->vxc, mindata->maxxc);
01401         mindata->ishift = mindata->maxxc - ndiff;
01402         cpl_msg_debug(cpl_func, "Local maximum: %g(%d) > %g(%d) (cost=%u:%u. "
01403                       "lines=%u)", mindata->mxc, mindata->maxxc, mindata->xc,
01404                       ndiff, arclamp->cost, arclamp->xcost, arclamp->ulines);
01405     }
01406 
01407     return -mindata->xc;
01408 }
01409 
01410 #endif
01411 
01412 /*----------------------------------------------------------------------------*/
01435 /*----------------------------------------------------------------------------*/
01436 cpl_error_code
01437 irplib_polynomial_find_1d_from_correlation_all(cpl_polynomial * self,
01438                                                int maxdeg,
01439                                                const cpl_vector * obs,
01440                                                int nmaxima,
01441                                                int linelim,
01442                                                irplib_base_spectrum_model* model,
01443                                                cpl_error_code (* filler)
01444                                                (cpl_vector *,
01445                                                 const cpl_polynomial *,
01446                                                 irplib_base_spectrum_model *,
01447                                                 int),
01448                                                double pixtol,
01449                                                double pixstep,
01450                                                int hsize,
01451                                                int maxite,
01452                                                int maxfail,
01453                                                int maxcont,
01454                                                cpl_boolean doplot,
01455                                                double * pxc)
01456 {
01457 
01458 #ifdef HAVE_GSL
01459 
01460     cpl_errorstate     prestate = cpl_errorstate_get();
01461     cpl_polynomial   * start;
01462     cpl_polynomial   * cand;
01463     cpl_polynomial   * backup;
01464     cpl_error_code     error = CPL_ERROR_NONE;
01465     double             xc;
01466     cpl_bivector     * xtshift = cpl_bivector_new(nmaxima ? nmaxima : 1);
01467     const cpl_vector * xtshiftx = cpl_bivector_get_x_const(xtshift);
01468     const cpl_vector * xtshifty = cpl_bivector_get_y_const(xtshift);
01469     int                nshift;
01470     int                imaximum = -1;
01471     int                imaxima;
01472 
01473 #endif
01474 
01475     cpl_ensure_code(self   != NULL, CPL_ERROR_NULL_INPUT);
01476     cpl_ensure_code(obs    != NULL, CPL_ERROR_NULL_INPUT);
01477     cpl_ensure_code(model  != NULL, CPL_ERROR_NULL_INPUT);
01478     cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
01479     cpl_ensure_code(pxc    != NULL, CPL_ERROR_NULL_INPUT);
01480 
01481     cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
01482                     CPL_ERROR_ILLEGAL_INPUT);
01483 
01484     cpl_ensure_code(cpl_polynomial_get_degree(self) > 0,
01485                     CPL_ERROR_ILLEGAL_INPUT);
01486 
01487     cpl_ensure_code(maxdeg  >=  0, CPL_ERROR_ILLEGAL_INPUT);
01488     cpl_ensure_code(pixtol  > 0.0, CPL_ERROR_ILLEGAL_INPUT);
01489     cpl_ensure_code(pixstep > 0.0, CPL_ERROR_ILLEGAL_INPUT);
01490     cpl_ensure_code(hsize   >=  0, CPL_ERROR_ILLEGAL_INPUT);
01491     cpl_ensure_code(maxite  >=  0, CPL_ERROR_ILLEGAL_INPUT);
01492     cpl_ensure_code(nmaxima >=  0, CPL_ERROR_ILLEGAL_INPUT);
01493     cpl_ensure_code(maxfail >   0, CPL_ERROR_ILLEGAL_INPUT);
01494     cpl_ensure_code(maxcont >   0, CPL_ERROR_ILLEGAL_INPUT);
01495     cpl_ensure_code(linelim >=  0, CPL_ERROR_ILLEGAL_INPUT);
01496 
01497 #ifndef HAVE_GSL
01498     /* Avoid unused variable warning */
01499     cpl_ensure_code(doplot == CPL_TRUE || doplot == CPL_FALSE,
01500                     CPL_ERROR_ILLEGAL_INPUT);
01501     return cpl_error_set_message(cpl_func, CPL_ERROR_UNSUPPORTED_MODE,
01502                                  "GSL is not available");
01503 #else
01504 
01505     if (irplib_bivector_find_shift_from_correlation(xtshift, self, obs,
01506                                                     model, filler,
01507                                                     hsize, doplot, &xc)) {
01508         cpl_bivector_delete(xtshift);
01509         return cpl_error_set_where(cpl_func);
01510     }
01511 
01512     if (model->ulines > (unsigned)linelim) {
01513         /* The initial, optimal (integer) shift */
01514         const double xxc = cpl_vector_get(xtshiftx, 0);
01515         const double xc0 = cpl_vector_get(xtshifty, 0);
01516 
01517         cpl_msg_warning(cpl_func, "Doing only shift=%g pixels with lines=%u > "
01518                         "%d and XC=%g", xxc, model->ulines, linelim, xc0);
01519 
01520         cpl_polynomial_shift_1d(self, 0, xxc);
01521 
01522         *pxc = xc0;
01523 
01524         cpl_bivector_delete(xtshift);
01525 
01526         return CPL_ERROR_NONE;
01527     }
01528 
01529     start  = cpl_polynomial_duplicate(self);
01530     cand   = cpl_polynomial_new(1);
01531     backup = cpl_polynomial_new(1);
01532 
01533     /* Number of (local) maxima to use as starting point of the optimization */
01534     nshift = cpl_bivector_get_size(xtshift);
01535     if (nmaxima == 0 || nmaxima > nshift) nmaxima = nshift;
01536 
01537     cpl_msg_info(cpl_func, "Optimizing %d/%d local shift-maxima "
01538                  "(no-shift xc=%g. linelim=%d)", nmaxima, nshift, xc, linelim);
01539     if (cpl_msg_get_level() <= CPL_MSG_DEBUG)
01540         cpl_bivector_dump(xtshift, stdout);
01541 
01542     for (imaxima = 0; imaxima < nmaxima; imaxima++) {
01543         /* The initial, optimal (integer) shift */
01544         const double xxc = cpl_vector_get(xtshiftx, imaxima);
01545         double xtpixstep = pixstep;
01546         double xtpixtol  = pixtol;
01547         double xtxc;
01548         cpl_boolean ok = CPL_FALSE;
01549         int nfail;
01550 
01551 
01552         cpl_polynomial_copy(cand, start);
01553         cpl_polynomial_shift_1d(cand, 0, xxc);
01554         cpl_polynomial_copy(backup, cand);
01555 
01556         /* Increase tolerance until convergence */
01557         for (nfail = 0; nfail < maxfail; nfail++, xtpixtol *= 2.0,
01558                  xtpixstep *= 2.0) {
01559             int restart = maxcont;
01560             do {
01561                 error = irplib_polynomial_find_1d_from_correlation
01562                     (cand, maxdeg, obs, model,
01563                      filler, xtpixtol, xtpixstep, 2,
01564                      maxite, &xtxc);
01565             } while (error == CPL_ERROR_CONTINUE && --restart);
01566 
01567             if (!error) {
01568                 cpl_msg_debug(cpl_func, "XC(imax=%d/%d:xtpixtol=%g): %g "
01569                               "(cost=%u:%u)", 1+imaxima, nmaxima, xtpixtol,
01570                               xtxc, model->cost, model->xcost);
01571                 break;
01572             }
01573             cpl_msg_warning(cpl_func, "Increasing xtpixtol from %g (%g, imax="
01574                             "%d/%d)", xtpixtol, xtpixstep, 1+imaxima, nmaxima);
01575             if (model->ulines > (unsigned)linelim) {
01576                 cpl_msg_warning(cpl_func, "Stopping search-refinement via "
01577                                 "catalogue with %u lines > %u", model->ulines,
01578                                 linelim);
01579                 break;
01580             }
01581             cpl_polynomial_copy(cand, start);
01582         }
01583 
01584         /* Decrease tolerance until inconvergence, keep previous */
01585         for (; !error && xtpixtol > 0.0; xtpixtol *= 0.25, xtpixstep *= 0.5) {
01586             int restart = maxcont;
01587 
01588             cpl_polynomial_copy(backup, cand);
01589             do {
01590                 error = irplib_polynomial_find_1d_from_correlation
01591                     (cand, maxdeg, obs, model, filler,
01592                      xtpixtol, xtpixstep, 2, maxite, &xtxc);
01593             } while (error == CPL_ERROR_CONTINUE && --restart);
01594             if (error) break;
01595             ok = CPL_TRUE;
01596             cpl_msg_debug(cpl_func, "XC(imax=%d/%d:xtpixtol=%g): %g (cost=%u:%u"
01597                           ". ulines=%u)", 1+imaxima, nmaxima, xtpixtol, xtxc,
01598                           model->cost, model->xcost, model->ulines);
01599             if (model->ulines > (unsigned)linelim) {
01600                 cpl_msg_info(cpl_func, "Stopping search-refinement via "
01601                              "catalogue with %u lines > %u", model->ulines,
01602                              linelim);
01603                 break;
01604             }
01605         }
01606 
01607         if (error) {
01608             error = 0;
01609             cpl_errorstate_dump(prestate, CPL_FALSE,
01610                                 irplib_errorstate_dump_debug);
01611             cpl_errorstate_set(prestate);
01612             cpl_polynomial_copy(cand, backup);
01613         }
01614         if (ok && xtxc > xc) {
01615             imaximum = imaxima;
01616             cpl_polynomial_copy(self, cand);
01617             xc = xtxc;
01618 
01619             cpl_msg_info(cpl_func, "XC(imax=%d/%d): %g -> %g (initial-shift=%g. "
01620                          "cost=%u:%u. lines=%u)", 1+imaxima, nmaxima,
01621                          cpl_vector_get(xtshifty, imaxima), xtxc,
01622                          cpl_vector_get(xtshiftx, imaxima), model->cost,
01623                          model->xcost, model->ulines);
01624         } else {
01625             cpl_msg_info(cpl_func, "xc(imax=%d/%d): %g -> %g (initial-shift=%g. "
01626                          "cost=%u:%u. lines=%u)", 1+imaxima, nmaxima,
01627                          cpl_vector_get(xtshifty, imaxima), xtxc,
01628                          cpl_vector_get(xtshiftx, imaxima),
01629                          model->cost, model->xcost, model->ulines);
01630         }
01631     }
01632 
01633     cpl_polynomial_delete(start);
01634     cpl_polynomial_delete(backup);
01635     cpl_polynomial_delete(cand);
01636 
01637     if (imaximum < 0) {
01638         error = cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
01639                                       "XC could not be optimized over %d "
01640                                       "local shift-maxima (xc=%g)", nmaxima, xc);
01641     } else {
01642         cpl_msg_info(cpl_func, "Maximal XC=%g (up from %g, with initial pixel-"
01643                      "shift of %g) at %d/%d local shift-maximi", xc,
01644                      cpl_vector_get(xtshifty, imaximum),
01645                      cpl_vector_get(xtshiftx, imaximum),
01646                      1+imaximum, nmaxima);
01647 
01648         if (doplot) {
01649             irplib_plot_spectrum_and_model(obs, self, model, filler);
01650         }
01651 
01652         *pxc = xc;
01653     }
01654 
01655     cpl_bivector_delete(xtshift);
01656 
01657     return error;
01658 
01659 #endif
01660 
01661 }

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