irplib_wavecal.c

00001 /* $Id: irplib_wavecal.c,v 1.52 2012/08/03 21:05:32 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: 2012/08/03 21:05:32 $
00024  * $Revision: 1.52 $
00025  * $Name: HEAD $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033                                    Includes
00034  -----------------------------------------------------------------------------*/
00035 
00036 /* TEMPORARY SUPPORT OF CPL 5.x */
00037 #include <cpl.h>
00038 
00039 #ifndef CPL_SIZE_FORMAT
00040 #define CPL_SIZE_FORMAT "d"
00041 #define cpl_size int
00042 #endif
00043 /* END TEMPORARY SUPPORT OF CPL 5.x */
00044 
00045 #include "irplib_wavecal_impl.h"
00046 
00047 /* Needed for irplib_errorstate_dump_debug() */
00048 #include "irplib_utils.h"
00049 
00050 #include <string.h>
00051 #include <math.h>
00052 
00053 #ifdef HAVE_GSL
00054 #include <gsl/gsl_multimin.h>
00055 #endif
00056 
00057 /*-----------------------------------------------------------------------------
00058                                Private types
00059  -----------------------------------------------------------------------------*/
00060 
00061 typedef struct {
00062 
00063     const cpl_vector * observed;
00064     cpl_polynomial   * disp1d;
00065     cpl_vector       * spectrum;
00066     irplib_base_spectrum_model * param;
00067     cpl_error_code  (* filler)(cpl_vector *, const cpl_polynomial *,
00068                                irplib_base_spectrum_model *);
00069     cpl_vector       * vxc;
00070     double             xc;
00071     int                maxxc;
00072     double             mxc;
00073     cpl_polynomial   * mdisp;
00074     int                ishift;
00075 
00076 } irplib_multimin;
00077 
00078 /*-----------------------------------------------------------------------------
00079                                Defines
00080  -----------------------------------------------------------------------------*/
00081 
00082 #ifndef inline
00083 #define inline /* inline */
00084 #endif
00085 
00086 #define IRPLIB_MAX(A,B) ((A) > (B) ? (A) : (B))
00087 #define IRPLIB_MIN(A,B) ((A) < (B) ? (A) : (B))
00088 
00089 /*-----------------------------------------------------------------------------
00090                                    Private functions
00091  -----------------------------------------------------------------------------*/
00092 
00093 #ifdef HAVE_GSL
00094 static double irplib_gsl_correlation(const gsl_vector *, void *);
00095 #endif
00096 
00097 static cpl_error_code
00098 irplib_polynomial_find_1d_from_correlation_(cpl_polynomial *, int,
00099                                             const cpl_vector *,
00100                                             irplib_base_spectrum_model *,
00101                                             cpl_error_code (*)
00102                                             (cpl_vector *,
00103                                              const cpl_polynomial *,
00104                                              irplib_base_spectrum_model *),
00105                                             double, double, int, int,
00106                                             double *, cpl_boolean *);
00107 
00108 
00109 /*----------------------------------------------------------------------------*/
00113 /*----------------------------------------------------------------------------*/
00114 
00118 /*----------------------------------------------------------------------------*/
00126 /*----------------------------------------------------------------------------*/
00127 int irplib_bivector_count_positive(const cpl_bivector * self,
00128                                   double               x_min,
00129                                   double               x_max)
00130 {
00131 
00132     const int      nself = cpl_bivector_get_size(self);
00133     const double * px    = cpl_bivector_get_x_data_const(self);
00134     const double * py    = cpl_bivector_get_y_data_const(self);
00135     int            npos  = 0;
00136     int            i     = 0;
00137 
00138     cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, -1);
00139     cpl_ensure(x_min <= x_max, CPL_ERROR_ILLEGAL_INPUT, -2);
00140     
00141     /* FIXME: Use cpl_vector_find() */
00142     while (i < nself && px[i] < x_min) i++;
00143     while (i < nself && px[i] < x_max)
00144         if (py[i++] > 0) npos++;
00145 
00146     return npos;
00147 }
00148 
00149 /*----------------------------------------------------------------------------*/
00159 /*----------------------------------------------------------------------------*/
00160 cpl_error_code irplib_polynomial_fit_2d_dispersion(cpl_polynomial * self,
00161                                                    const cpl_image * imgwave,
00162                                                    int fitdeg, double * presid)
00163 {
00164 
00165     const int        nx = cpl_image_get_size_x(imgwave);
00166     const int        ny = cpl_image_get_size_y(imgwave);
00167     const int        nbad = cpl_image_count_rejected(imgwave);
00168     const int        nsamp = nx * ny - nbad;
00169     cpl_matrix     * xy_pos;
00170     double         * xdata;
00171     double         * ydata;
00172     cpl_vector     * wlen;
00173     double         * dwlen;
00174     const cpl_size   nfitdeg = (cpl_size)fitdeg;
00175     int i, j;
00176     int k = 0;
00177 
00178     cpl_ensure_code(self    != NULL, CPL_ERROR_NULL_INPUT);
00179     cpl_ensure_code(imgwave != NULL, CPL_ERROR_NULL_INPUT);
00180     cpl_ensure_code(presid  != NULL, CPL_ERROR_NULL_INPUT);
00181     cpl_ensure_code(fitdeg > 0,      CPL_ERROR_ILLEGAL_INPUT);
00182 
00183     cpl_ensure_code(cpl_polynomial_get_dimension(self) == 2,
00184                     CPL_ERROR_ILLEGAL_INPUT);
00185 
00186     xy_pos = cpl_matrix_new(2, nsamp);
00187     xdata = cpl_matrix_get_data(xy_pos);
00188     ydata = xdata + nsamp;
00189 
00190     dwlen = (double*)cpl_malloc(nsamp * sizeof(double));
00191     wlen = cpl_vector_wrap(nsamp, dwlen);
00192 
00193     for (i=1; i <= nx; i++) {
00194         for (j=1; j <= ny; j++) {
00195             int is_bad;
00196             const double value = cpl_image_get(imgwave, i, j, &is_bad);
00197             if (!is_bad) {
00198                 xdata[k] = i;
00199                 ydata[k] = j;
00200                 dwlen[k] = value;
00201                 k++;
00202             }
00203         }
00204     }
00205 
00206     cpl_msg_info(cpl_func, "Fitting 2D polynomial to %d X %d image, ignoring "
00207                  "%d poorly calibrated pixels", nx, ny, nbad);
00208 
00209     if (cpl_polynomial_fit(self, xy_pos, NULL, wlen, NULL, CPL_FALSE, NULL,
00210                            &nfitdeg) == CPL_ERROR_NONE && presid != NULL) {
00211         cpl_vector_fill_polynomial_fit_residual(wlen, wlen, NULL, self, xy_pos,
00212                                                 NULL);
00213         *presid = cpl_vector_product(wlen, wlen)/nsamp;
00214     }
00215     cpl_matrix_delete(xy_pos);
00216     cpl_vector_delete(wlen);
00217 
00218     cpl_ensure_code(k == nsamp, CPL_ERROR_UNSPECIFIED);
00219 
00220     return CPL_ERROR_NONE;
00221 }
00222 
00223 
00224 /*----------------------------------------------------------------------------*/
00242 /*----------------------------------------------------------------------------*/
00243 cpl_error_code
00244 irplib_polynomial_find_1d_from_correlation(cpl_polynomial * self,
00245                                            int maxdeg,
00246                                            const cpl_vector * obs,
00247                                            irplib_base_spectrum_model * model,
00248                                            cpl_error_code (* filler)
00249                                            (cpl_vector *,
00250                                             const cpl_polynomial *,
00251                                             irplib_base_spectrum_model *),
00252                                            double pixtol,
00253                                            double pixstep,
00254                                            int hsize,
00255                                            int maxite,
00256                                            double * pxc)
00257 {
00258     cpl_boolean restart = CPL_FALSE;
00259     const cpl_error_code error = irplib_polynomial_find_1d_from_correlation_
00260         (self, maxdeg, obs, model, filler, pixtol, pixstep, hsize, maxite, pxc,
00261          &restart);
00262 
00263     return error ? cpl_error_set_where(cpl_func) :
00264         (restart ? cpl_error_set(cpl_func, CPL_ERROR_CONTINUE)
00265          : CPL_ERROR_NONE);
00266 }
00267 
00268 /*----------------------------------------------------------------------------*/
00289 /*----------------------------------------------------------------------------*/
00290 static cpl_error_code
00291 irplib_polynomial_find_1d_from_correlation_(cpl_polynomial * self,
00292                                             int maxdeg,
00293                                             const cpl_vector * obs,
00294                                             irplib_base_spectrum_model * model,
00295                                             cpl_error_code (* filler)
00296                                             (cpl_vector *,
00297                                              const cpl_polynomial *,
00298                                              irplib_base_spectrum_model *),
00299                                             double pixtol,
00300                                             double pixstep,
00301                                             int hsize,
00302                                             int maxite,
00303                                             double * pxc,
00304                                             cpl_boolean * prestart)
00305 {
00306 
00307 #ifdef HAVE_GSL
00308     const gsl_multimin_fminimizer_type * T = gsl_multimin_fminimizer_nmsimplex;
00309     gsl_multimin_fminimizer * minimizer;
00310     gsl_multimin_function my_func;
00311     irplib_multimin data;
00312     gsl_vector * dispgsl;
00313     gsl_vector * stepsize;
00314     gsl_vector * dispprev;
00315     int status = GSL_CONTINUE;
00316     const int nobs = cpl_vector_get_size(obs);
00317     const cpl_size nfit = maxdeg + 1;
00318     cpl_errorstate prestate = cpl_errorstate_get();
00319     /* Convert pixel step to wavelength step on detector center */
00320     const double wlstep =
00321         cpl_polynomial_eval_1d_diff(self, 0.5 * (nobs + pixstep),
00322                                     0.5 * (nobs - pixstep), NULL);
00323     double wlstepi = wlstep;
00324     double size;
00325     int iter;
00326     cpl_size i;
00327 
00328 #endif
00329 
00330     cpl_ensure_code(prestart != NULL, CPL_ERROR_NULL_INPUT);
00331     *prestart = CPL_FALSE;
00332     cpl_ensure_code(self     != NULL, CPL_ERROR_NULL_INPUT);
00333     cpl_ensure_code(obs      != NULL, CPL_ERROR_NULL_INPUT);
00334     cpl_ensure_code(model    != NULL, CPL_ERROR_NULL_INPUT);
00335     cpl_ensure_code(filler   != NULL, CPL_ERROR_NULL_INPUT);
00336     cpl_ensure_code(pxc      != NULL, CPL_ERROR_NULL_INPUT);
00337 
00338     cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00339                     CPL_ERROR_ILLEGAL_INPUT);
00340 
00341     cpl_ensure_code(cpl_polynomial_get_degree(self) > 0,
00342                     CPL_ERROR_ILLEGAL_INPUT);
00343 
00344     cpl_ensure_code(maxdeg  >=  0, CPL_ERROR_ILLEGAL_INPUT);
00345     cpl_ensure_code(pixtol  > 0.0, CPL_ERROR_ILLEGAL_INPUT);
00346     cpl_ensure_code(pixstep > 0.0, CPL_ERROR_ILLEGAL_INPUT);
00347     cpl_ensure_code(hsize   >=  0, CPL_ERROR_ILLEGAL_INPUT);
00348     cpl_ensure_code(maxite  >=  0, CPL_ERROR_ILLEGAL_INPUT);
00349 
00350 #ifndef HAVE_GSL
00351     return cpl_error_set_message(cpl_func, CPL_ERROR_UNSUPPORTED_MODE,
00352                                  "GSL is not available");
00353 #else
00354 
00355     minimizer = gsl_multimin_fminimizer_alloc(T, (size_t)nfit);
00356 
00357     cpl_ensure_code(minimizer != NULL, CPL_ERROR_ILLEGAL_OUTPUT);
00358        
00359     dispgsl  = gsl_vector_alloc((size_t)nfit);
00360     stepsize = gsl_vector_alloc((size_t)nfit);
00361     dispprev = gsl_vector_alloc((size_t)nfit);
00362 
00363     for (i=0; i < nfit; i++) {
00364         const double value = cpl_polynomial_get_coeff(self, &i);
00365         gsl_vector_set(dispgsl, (size_t)i, value);
00366         gsl_vector_set(stepsize, (size_t)i, wlstepi);
00367         wlstepi /= (double)nobs;
00368     }
00369 
00370     my_func.n = nfit;
00371     my_func.f = &irplib_gsl_correlation;
00372     my_func.params = (void *)(&data);
00373 
00374     data.observed = obs;
00375     data.disp1d   = self;
00376     data.spectrum = cpl_vector_new(nobs + 2 * hsize);
00377     data.vxc      = cpl_vector_new(1 + 2 * hsize);
00378     data.param    = model;
00379     data.filler   = filler;
00380     data.maxxc    = 0; /* Output */
00381     data.ishift   = 0; /* Output */
00382     data.mxc      = -1.0; /* Output */
00383     data.mdisp    = NULL; /* Output */
00384 
00385     gsl_multimin_fminimizer_set (minimizer, &my_func, dispgsl, stepsize);
00386 
00387     for (iter = 0; status == GSL_CONTINUE && iter < maxite; iter++) {
00388 
00389         const double fprev = minimizer->fval;
00390 
00391         gsl_vector_memcpy(dispprev, minimizer->x);
00392         status = gsl_multimin_fminimizer_iterate(minimizer);
00393 
00394         if (status || !cpl_errorstate_is_equal(prestate)) break;
00395 
00396         size = gsl_multimin_fminimizer_size (minimizer);
00397         status = gsl_multimin_test_size (size, pixtol);
00398      
00399         if (status == GSL_SUCCESS) {
00400             cpl_msg_debug(cpl_func, "converged to minimum at");
00401 
00402             if (nfit == 0) {
00403                 cpl_msg_debug(cpl_func, "%5d %g df() = %g size = %g", 
00404                               iter,
00405                               gsl_vector_get (minimizer->x, 0)
00406                               - gsl_vector_get (dispprev, 0), 
00407                               minimizer->fval - fprev, size);
00408             } else if (nfit == 1) {
00409                 cpl_msg_debug(cpl_func, "%5d %g %g df() = %g size = %g", 
00410                               iter,
00411                               gsl_vector_get (minimizer->x, 0)
00412                               - gsl_vector_get (dispprev, 0), 
00413                               gsl_vector_get (minimizer->x, 1)
00414                               - gsl_vector_get (dispprev, 1), 
00415                               minimizer->fval - fprev, size);
00416             } else {
00417                 cpl_msg_debug(cpl_func, "%5d %g %g %g df() = %g size = %g", 
00418                               iter,
00419                               gsl_vector_get (minimizer->x, 0)
00420                               - gsl_vector_get (dispprev, 0), 
00421                               gsl_vector_get (minimizer->x, 1)
00422                               - gsl_vector_get (dispprev, 1), 
00423                               gsl_vector_get (minimizer->x, 2)
00424                               - gsl_vector_get (dispprev, 2), 
00425                               minimizer->fval - fprev, size);
00426             }
00427         }
00428     }
00429 
00430     if (status == GSL_SUCCESS && cpl_errorstate_is_equal(prestate)) {
00431         if (data.mxc > -minimizer->fval) {
00432             *pxc = data.mxc;
00433             cpl_msg_warning(cpl_func, "Local maximum: %g(%d) > %g",
00434                             data.mxc, data.ishift, -minimizer->fval);
00435             cpl_polynomial_shift_1d(data.mdisp, 0, (double)data.ishift);
00436             cpl_polynomial_copy(self, data.mdisp);
00437             *prestart = CPL_TRUE;
00438         } else {
00439             *pxc = -minimizer->fval;
00440             for (i=0; i < nfit; i++) {
00441                 const double value = gsl_vector_get(minimizer->x, i);
00442                 cpl_polynomial_set_coeff(self, &i, value);
00443             }
00444         }
00445     }
00446 
00447     cpl_vector_delete(data.spectrum);
00448     cpl_vector_delete(data.vxc);
00449     cpl_polynomial_delete(data.mdisp);
00450     gsl_multimin_fminimizer_free(minimizer);
00451     gsl_vector_free(dispgsl);
00452     gsl_vector_free(dispprev);
00453     gsl_vector_free(stepsize);
00454 
00455     cpl_ensure_code(status != GSL_CONTINUE, CPL_ERROR_CONTINUE);
00456     cpl_ensure_code(status == GSL_SUCCESS, CPL_ERROR_DATA_NOT_FOUND);
00457     cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
00458 
00459     return CPL_ERROR_NONE;
00460 #endif
00461 }
00462 
00463 
00464 /*----------------------------------------------------------------------------*/
00492 /*----------------------------------------------------------------------------*/
00493 cpl_error_code
00494 irplib_vector_fill_line_spectrum(cpl_vector * self,
00495                                  const cpl_polynomial * disp,
00496                                  irplib_base_spectrum_model * lsslamp)
00497 {
00498 
00499     irplib_line_spectrum_model * arclamp
00500         = (irplib_line_spectrum_model *)lsslamp;
00501     cpl_error_code error;
00502 
00503     cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
00504 
00505     arclamp->cost++;
00506 
00507     error = irplib_vector_fill_line_spectrum_model(self,
00508                                                    arclamp->linepix,
00509                                                    arclamp->erftmp,
00510                                                    disp,
00511                                                    arclamp->lines,
00512                                                    arclamp->wslit,
00513                                                    arclamp->wfwhm,
00514                                                    arclamp->xtrunc,
00515                                                    0, CPL_FALSE, CPL_FALSE,
00516                                                    &(arclamp->ulines));
00517     cpl_ensure_code(!error, error);
00518 
00519     arclamp->xcost++;
00520 
00521     return CPL_ERROR_NONE;
00522 }
00523 
00524 /*----------------------------------------------------------------------------*/
00537 /*----------------------------------------------------------------------------*/
00538 cpl_error_code
00539 irplib_vector_fill_logline_spectrum(cpl_vector * self,
00540                                     const cpl_polynomial * disp,
00541                                     irplib_base_spectrum_model * lsslamp)
00542 {
00543 
00544     irplib_line_spectrum_model * arclamp
00545         = (irplib_line_spectrum_model *)lsslamp;
00546     cpl_error_code error;
00547 
00548     cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
00549 
00550     arclamp->cost++;
00551 
00552     error = irplib_vector_fill_line_spectrum_model(self,
00553                                                    arclamp->linepix,
00554                                                    arclamp->erftmp,
00555                                                    disp,
00556                                                    arclamp->lines,
00557                                                    arclamp->wslit,
00558                                                    arclamp->wfwhm,
00559                                                    arclamp->xtrunc,
00560                                                    0, CPL_FALSE, CPL_TRUE,
00561                                                    &(arclamp->ulines));
00562     cpl_ensure_code(!error, error);
00563 
00564     arclamp->xcost++;
00565 
00566     return CPL_ERROR_NONE;
00567 }
00568 
00569 
00570 /*----------------------------------------------------------------------------*/
00583 /*----------------------------------------------------------------------------*/
00584 cpl_error_code
00585 irplib_vector_fill_line_spectrum_fast(cpl_vector * self,
00586                                       const cpl_polynomial * disp,
00587                                       irplib_base_spectrum_model * lsslamp)
00588 {
00589 
00590     irplib_line_spectrum_model * arclamp
00591         = (irplib_line_spectrum_model *)lsslamp;
00592     cpl_error_code error;
00593 
00594     cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
00595 
00596     arclamp->cost++;
00597 
00598     error = irplib_vector_fill_line_spectrum_model(self,
00599                                                    arclamp->linepix,
00600                                                    arclamp->erftmp,
00601                                                    disp,
00602                                                    arclamp->lines,
00603                                                    arclamp->wslit,
00604                                                    arclamp->wfwhm,
00605                                                    arclamp->xtrunc,
00606                                                    0, CPL_TRUE, CPL_FALSE,
00607                                                    &(arclamp->ulines));
00608     cpl_ensure_code(!error, error);
00609 
00610     arclamp->xcost++;
00611 
00612     return CPL_ERROR_NONE;
00613 }
00614 
00615 /*----------------------------------------------------------------------------*/
00628 /*----------------------------------------------------------------------------*/
00629 cpl_error_code
00630 irplib_vector_fill_logline_spectrum_fast(cpl_vector * self,
00631                                          const cpl_polynomial * disp,
00632                                          irplib_base_spectrum_model * lsslamp)
00633 {
00634 
00635     irplib_line_spectrum_model * arclamp
00636         = (irplib_line_spectrum_model *)lsslamp;
00637     cpl_error_code error;
00638 
00639     cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
00640 
00641     arclamp->cost++;
00642 
00643     error = irplib_vector_fill_line_spectrum_model(self,
00644                                                    arclamp->linepix,
00645                                                    arclamp->erftmp,
00646                                                    disp,
00647                                                    arclamp->lines,
00648                                                    arclamp->wslit,
00649                                                    arclamp->wfwhm,
00650                                                    arclamp->xtrunc,
00651                                                    0, CPL_TRUE, CPL_TRUE,
00652                                                    &(arclamp->ulines));
00653     cpl_ensure_code(!error, error);
00654 
00655     arclamp->xcost++;
00656 
00657     return CPL_ERROR_NONE;
00658 }
00659 
00660 /*----------------------------------------------------------------------------*/
00671 /*----------------------------------------------------------------------------*/
00672 cpl_error_code irplib_plot_spectrum_and_model(const cpl_vector * self,
00673                                               const cpl_polynomial * disp1d,
00674                                               irplib_base_spectrum_model * model,
00675                                               cpl_error_code (* filler)
00676                                               (cpl_vector *,
00677                                                const cpl_polynomial *,
00678                                                irplib_base_spectrum_model *))
00679 {
00680 
00681     cpl_errorstate prestate = cpl_errorstate_get();
00682     cpl_vector * wl;
00683     cpl_vector * spectrum;
00684     cpl_vector * vxc;
00685     const int len = cpl_vector_get_size(self);
00686     double maxval, xc;
00687     int ixc;
00688     int error = 0;
00689 
00690     cpl_ensure_code(self   != NULL, CPL_ERROR_NULL_INPUT);
00691     cpl_ensure_code(disp1d != NULL, CPL_ERROR_NULL_INPUT);
00692     cpl_ensure_code(model  != NULL, CPL_ERROR_NULL_INPUT);
00693     cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
00694 
00695     cpl_ensure_code(cpl_polynomial_get_dimension(disp1d) == 1,
00696                     CPL_ERROR_ILLEGAL_INPUT);
00697 
00698     cpl_ensure_code(cpl_polynomial_get_degree(disp1d) > 0,
00699                     CPL_ERROR_ILLEGAL_INPUT);
00700 
00701     wl = cpl_vector_new(len);
00702     spectrum = cpl_vector_new(len);
00703     vxc = cpl_vector_new(1);
00704 
00705     error |= (int)cpl_vector_fill_polynomial(wl, disp1d, 1.0, 1.0);
00706     error |= filler(spectrum, disp1d, model);
00707 
00708     ixc = cpl_vector_correlate(vxc, self, spectrum);
00709     xc = cpl_vector_get(vxc, ixc);
00710 
00711     maxval = cpl_vector_get_max(spectrum);
00712     if (maxval != 0.0) 
00713         error |= cpl_vector_multiply_scalar(spectrum,
00714                                              cpl_vector_get_max(self)/maxval);
00715     if (!error) {
00716         const cpl_vector * spair[] = {wl, self, spectrum};
00717         char * pre = cpl_sprintf("set grid;set xlabel 'Wavelength (%g -> %g)'; "
00718                                  "set ylabel 'Intensity';", cpl_vector_get(wl, 0),
00719                                  cpl_vector_get(wl, len-1));
00720         char * title = cpl_sprintf("t 'Observed and modelled spectra (%d pixel "
00721                                    "XC=%g) ' w linespoints", len, xc);
00722 
00723         (void)cpl_plot_vectors(pre, title, "", spair, 3);
00724         cpl_free(pre);
00725         cpl_free(title);
00726     }
00727 
00728     cpl_vector_delete(wl);
00729     cpl_vector_delete(spectrum);
00730     cpl_vector_delete(vxc);
00731 
00732     cpl_errorstate_set(prestate);
00733 
00734     return CPL_ERROR_NONE;
00735 }
00736 
00737 /*----------------------------------------------------------------------------*/
00757 /*----------------------------------------------------------------------------*/
00758 cpl_error_code
00759 irplib_bivector_find_shift_from_correlation(cpl_bivector * self,
00760                                             const cpl_polynomial * disp,
00761                                             const cpl_vector * obs,
00762                                             irplib_base_spectrum_model * model,
00763                                             cpl_error_code (*filler)
00764                                             (cpl_vector *,
00765                                              const cpl_polynomial *,
00766                                              irplib_base_spectrum_model *),
00767                                             int hsize,
00768                                             cpl_boolean doplot,
00769                                             double *pxc)
00770 {
00771 
00772     const int        nobs   = cpl_vector_get_size(obs);
00773     const int        nmodel = 2 * hsize + nobs;
00774     cpl_polynomial * shdisp;
00775     cpl_vector     * xself = cpl_bivector_get_x(self);
00776     cpl_vector     * yself = cpl_bivector_get_y(self);
00777     cpl_vector     * mspec1d;
00778     cpl_vector     * xcorr;
00779     cpl_error_code   error = CPL_ERROR_NONE;
00780     double           xcprev, xcnext;
00781     int              ixc, imax = 0;
00782     int              i;
00783 
00784     cpl_ensure_code(self   != NULL, CPL_ERROR_NULL_INPUT);
00785     cpl_ensure_code(disp   != NULL, CPL_ERROR_NULL_INPUT);
00786     cpl_ensure_code(obs    != NULL, CPL_ERROR_NULL_INPUT);
00787     cpl_ensure_code(model  != NULL, CPL_ERROR_NULL_INPUT);
00788     cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
00789     cpl_ensure_code(hsize  >  0,    CPL_ERROR_ILLEGAL_INPUT);
00790 
00791     shdisp = cpl_polynomial_duplicate(disp);
00792 
00793     /* Shift reference by -hsize so filler can be used without offset */
00794     if (cpl_polynomial_shift_1d(shdisp, 0, -hsize)) {
00795         cpl_polynomial_delete(shdisp);
00796         return cpl_error_set_where(cpl_func);
00797     }
00798 
00799     mspec1d = cpl_vector_new(nmodel);
00800 
00801     if (filler(mspec1d, shdisp, model)) {
00802         cpl_vector_delete(mspec1d);
00803         return cpl_error_set_where(cpl_func);
00804     }
00805 
00806     /* Should not be able to fail now */
00807     xcorr = cpl_vector_new(1 + 2 * hsize);
00808     ixc = cpl_vector_correlate(xcorr, mspec1d, obs);
00809 
00810 #ifdef IRPLIB_SPC_DUMP
00811     /* Need irplib_wavecal.c rev. 1.12 through 1.15 */
00812     irplib_polynomial_dump_corr_step(shdisp, xcorr, "Shift");
00813 #endif
00814 
00815     cpl_vector_delete(mspec1d);
00816     cpl_polynomial_delete(shdisp);
00817 
00818     /* Find local maxima. */
00819     /* FIXME(?): Also include stationary points */
00820     i = 0;
00821     xcprev = cpl_vector_get(xcorr, i);
00822     xcnext = cpl_vector_get(xcorr, i+1);
00823 
00824     if (xcprev >= xcnext) {
00825         /* 1st data point is an extreme */
00826         /* FIXME: This could also be an error, recoverable by caller by
00827            increasing hsize */
00828         imax++;
00829 
00830         cpl_vector_set(xself, 0, i - hsize);
00831         cpl_vector_set(yself, 0, xcprev);
00832 
00833     }
00834 
00835     for (i = 1; i < 2 * hsize; i++) {
00836         const double xc = xcnext;
00837         xcnext = cpl_vector_get(xcorr, i+1);
00838         if (xc >= xcprev && xc >= xcnext) {
00839             /* Found (local) maximum at shift i - hsize */
00840             int j;
00841 
00842             imax++;
00843 
00844             if (cpl_bivector_get_size(self) < imax) {
00845                 cpl_vector_set_size(xself, imax);
00846                 cpl_vector_set_size(yself, imax);
00847             }
00848 
00849             for (j = imax-1; j > 0; j--) {
00850                 if (xc <= cpl_vector_get(yself, j-1)) break;
00851                 cpl_vector_set(xself, j, cpl_vector_get(xself, j-1));
00852                 cpl_vector_set(yself, j, cpl_vector_get(yself, j-1));
00853             }
00854             cpl_vector_set(xself, j, i - hsize);
00855             cpl_vector_set(yself, j, xc);
00856         }
00857         xcprev = xc;
00858     }
00859 
00860     /* assert( i == 2 * hsize ); */
00861 
00862     if (xcnext >= xcprev) {
00863         /* Last data point is an extreme */
00864         /* FIXME: This could also be an error, recoverable by caller by
00865            increasing hsize */
00866         int j;
00867 
00868         imax++;
00869 
00870         if (cpl_bivector_get_size(self) < imax) {
00871             cpl_vector_set_size(xself, imax);
00872             cpl_vector_set_size(yself, imax);
00873         }
00874 
00875         for (j = imax-1; j > 0; j--) {
00876             if (xcnext <= cpl_vector_get(yself, j-1)) break;
00877             cpl_vector_set(xself, j, cpl_vector_get(xself, j-1));
00878             cpl_vector_set(yself, j, cpl_vector_get(yself, j-1));
00879         }
00880         cpl_vector_set(xself, j, i - hsize);
00881         cpl_vector_set(yself, j, xcnext);
00882 
00883     }
00884 
00885     if (doplot) {
00886         /* Vector of -hsize, 1-hsize, 2-hsize, ..., 0, ..., hsize */
00887         cpl_vector * xvals = cpl_vector_new(1 + 2 * hsize);
00888         cpl_bivector * bcorr = cpl_bivector_wrap_vectors(xvals, xcorr);
00889         double x = (double)-hsize;
00890         char * title = cpl_sprintf("t 'Cross-correlation of shifted %d-pixel "
00891                                    "spectrum (XCmax=%g at %d)' w linespoints",
00892                                    nobs, cpl_vector_get(xcorr, ixc),
00893                                    ixc - hsize);
00894 
00895         for (i = 0; i < 1 + 2 * hsize; i++, x += 1.0) {
00896             cpl_vector_set(xvals, i, x);
00897         }
00898 
00899         cpl_plot_bivector("set grid;set xlabel 'Offset [pixel]';", title,
00900                              "", bcorr);
00901         cpl_bivector_unwrap_vectors(bcorr);
00902         cpl_vector_delete(xvals);
00903         cpl_free(title);
00904     }
00905 
00906     if (pxc != NULL) *pxc = cpl_vector_get(xcorr, hsize);
00907 
00908     cpl_vector_delete(xcorr);
00909 
00910     if (imax < 1) {
00911         error = CPL_ERROR_DATA_NOT_FOUND;
00912     } else if (cpl_bivector_get_size(self) > imax) {
00913         cpl_vector_set_size(xself, imax);
00914         cpl_vector_set_size(yself, imax);
00915     }
00916 
00917     /* Propagate error, if any */
00918     return cpl_error_set(cpl_func, error);
00919 }
00920 
00921 /*----------------------------------------------------------------------------*/
00934 /*----------------------------------------------------------------------------*/
00935 cpl_error_code
00936 irplib_polynomial_shift_1d_from_correlation(cpl_polynomial * self,
00937                                             const cpl_vector * obs,
00938                                             irplib_base_spectrum_model * model,
00939                                             cpl_error_code (*filler)
00940                                             (cpl_vector *,
00941                                              const cpl_polynomial *,
00942                                              irplib_base_spectrum_model *),
00943                                             int hsize,
00944                                             cpl_boolean doplot,
00945                                             double * pxc)
00946 {
00947 
00948     const int      nobs   = cpl_vector_get_size(obs);
00949     const int      nmodel = 2 * hsize + nobs;
00950     cpl_vector   * mspec1d;
00951     cpl_vector   * xcorr;
00952     cpl_error_code error;
00953     int            ixc, xxc;
00954     double         xc;
00955 
00956     cpl_ensure_code(self   != NULL, CPL_ERROR_NULL_INPUT);
00957     cpl_ensure_code(obs    != NULL, CPL_ERROR_NULL_INPUT);
00958     cpl_ensure_code(model  != NULL, CPL_ERROR_NULL_INPUT);
00959     cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
00960     cpl_ensure_code(hsize  >  0,    CPL_ERROR_ILLEGAL_INPUT);
00961 
00962     /* Shift reference by -hsize so filler can be used without offset */
00963     cpl_ensure_code(!cpl_polynomial_shift_1d(self, 0, -hsize),
00964                     cpl_error_get_code());
00965 
00966     mspec1d = cpl_vector_new(nmodel);
00967 
00968     if (filler(mspec1d, self, model)) {
00969         cpl_vector_delete(mspec1d);
00970         cpl_ensure_code(0, cpl_error_get_code());
00971     }
00972 
00973     /* Should not be able to fail now */
00974     xcorr = cpl_vector_new(1 + 2 * hsize);
00975     ixc = cpl_vector_correlate(xcorr, mspec1d, obs);
00976 
00977 #ifdef IRPLIB_SPC_DUMP
00978     /* Need irplib_wavecal.c rev. 1.12 through 1.15 */
00979     irplib_polynomial_dump_corr_step(self, xcorr, "Shift");
00980 #endif
00981 
00982     cpl_vector_delete(mspec1d);
00983 
00984     error = cpl_polynomial_shift_1d(self, 0, (double)ixc);
00985 
00986     xc = cpl_vector_get(xcorr, ixc);
00987 
00988     xxc = ixc - hsize; /* The effect of the two shifts */
00989 
00990     cpl_msg_info(cpl_func, "Shifting %d pixels (%g < %g)", xxc,
00991                  cpl_vector_get(xcorr, hsize), xc);
00992 
00993     if (doplot) {
00994         cpl_vector * xvals = cpl_vector_new(1 + 2 * hsize);
00995         cpl_bivector * bcorr = cpl_bivector_wrap_vectors(xvals, xcorr);
00996         int i;
00997         double x = (double)-hsize;
00998         char * title = cpl_sprintf("t 'Cross-correlation of shifted %d-pixel "
00999                                    "spectrum (XCmax=%g at %d)' w linespoints",
01000                                    nobs, cpl_vector_get(xcorr, ixc), xxc);
01001 
01002         for (i = 0; i < 1 + 2 * hsize; i++, x += 1.0) {
01003             cpl_vector_set(xvals, i, x);
01004         }
01005 
01006         cpl_plot_bivector("set grid;set xlabel 'Offset [pixel]';", title,
01007                              "", bcorr);
01008         cpl_bivector_unwrap_vectors(bcorr);
01009         cpl_vector_delete(xvals);
01010         cpl_free(title);
01011     }
01012 
01013     cpl_vector_delete(xcorr);
01014 
01015     cpl_ensure_code(!error, error);
01016 
01017     if (pxc != NULL) *pxc = xc;
01018 
01019     return CPL_ERROR_NONE;
01020 
01021 }
01022 
01023 
01024 /*----------------------------------------------------------------------------*/
01044 /*----------------------------------------------------------------------------*/
01045 cpl_error_code
01046 irplib_vector_fill_line_spectrum_model(cpl_vector * self,
01047                                        cpl_vector * linepix,
01048                                        cpl_vector * erftmp,
01049                                        const cpl_polynomial * disp,
01050                                        const cpl_bivector * lines,
01051                                        double wslit,
01052                                        double wfwhm,
01053                                        double xtrunc,
01054                                        int hsize,
01055                                        cpl_boolean dofast,
01056                                        cpl_boolean dolog,
01057                                        cpl_size * pulines)
01058 {
01059 
01060     cpl_errorstate     prestate;
01061     const double       sigma = wfwhm * CPL_MATH_SIG_FWHM;
01062     const cpl_vector * xlines  = cpl_bivector_get_x_const(lines);
01063     const double     * dxlines = cpl_vector_get_data_const(xlines);
01064     const double     * dylines = cpl_bivector_get_y_data_const(lines);
01065     double           * plinepix
01066         = linepix ? cpl_vector_get_data(linepix) : NULL;
01067     const int          nlines  = cpl_vector_get_size(xlines);
01068     const int          nself   = cpl_vector_get_size(self);
01069     double           * dself   = cpl_vector_get_data(self);
01070     cpl_polynomial   * dispi;
01071     double           * profile = NULL;
01072     const cpl_size     i0 = 0;
01073     const double       p0 = cpl_polynomial_get_coeff(disp, &i0);
01074     double             wl;
01075     double             xpos = (double)(1-hsize)-xtrunc;
01076     const double       xmax = (double)(nself-hsize)+xtrunc;
01077     double             xderiv, xextreme;
01078     cpl_error_code     error = CPL_ERROR_NONE;
01079     int                iline;
01080     cpl_size           ulines = 0;
01081 
01082     cpl_ensure_code(self    != NULL, CPL_ERROR_NULL_INPUT);
01083     cpl_ensure_code(disp    != NULL, CPL_ERROR_NULL_INPUT);
01084     cpl_ensure_code(lines   != NULL, CPL_ERROR_NULL_INPUT);
01085 
01086     cpl_ensure_code(wslit  >  0.0, CPL_ERROR_ILLEGAL_INPUT);
01087     cpl_ensure_code(wfwhm  >  0.0, CPL_ERROR_ILLEGAL_INPUT);
01088     cpl_ensure_code(hsize  >= 0,   CPL_ERROR_ILLEGAL_INPUT);
01089     cpl_ensure_code(xtrunc >  0.0, CPL_ERROR_ILLEGAL_INPUT);
01090     cpl_ensure_code(nself  > 2 * hsize, CPL_ERROR_ILLEGAL_INPUT);
01091 
01092     cpl_ensure_code(cpl_polynomial_get_dimension(disp) == 1,
01093                     CPL_ERROR_ILLEGAL_INPUT);
01094     cpl_ensure_code(cpl_polynomial_get_degree(disp) > 0,
01095                     CPL_ERROR_ILLEGAL_INPUT);
01096 
01097     /* The smallest wavelength contributing to the spectrum. */
01098     wl = cpl_polynomial_eval_1d(disp, xpos, &xderiv);
01099 
01100     if (wl <= 0.0) return
01101         cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT, __FILE__,
01102                                     __LINE__, "Non-positive wavelength at x=%g: "
01103                                     "P(x)=%g, P'(x)=%g", xpos, wl, xderiv);
01104 
01105     if (xderiv <= 0.0) return
01106         cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT, __FILE__,
01107                                     __LINE__, "Non-increasing dispersion at "
01108                                     "x=%g: P'(x)=%g, P(x)=%g", xpos, xderiv, wl);
01109 
01110     /* Find the 1st line */
01111     iline = cpl_vector_find(xlines, wl);
01112 
01113     /* The first line must be at least at wl */
01114     if (dxlines[iline] < wl) iline++;
01115 
01116     if (iline >= nlines) return
01117         cpl_error_set_message_macro(cpl_func, CPL_ERROR_DATA_NOT_FOUND, __FILE__,
01118                                     __LINE__, "The %d-line catalogue has only "
01119                                     "lines below P(%g)=%g > %g", nlines, xpos,
01120                                     wl, dxlines[nlines-1]);
01121 
01122     memset(dself, 0, nself * sizeof(double));
01123 
01124     dispi = cpl_polynomial_duplicate(disp);
01125 
01126     /* Verify monotony of dispersion */
01127     cpl_polynomial_derivative(dispi, 0);
01128 
01129     prestate = cpl_errorstate_get();
01130 
01131     if (cpl_polynomial_solve_1d(dispi, 0.5*(nlines+1), &xextreme, 1)) {
01132         cpl_errorstate_set(prestate);
01133     } else if (xpos < xextreme && xextreme < xmax) {
01134         cpl_polynomial_delete(dispi);
01135         return cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
01136                                            __FILE__, __LINE__, "Non-monotone "
01137                                            "dispersion at x=%g: P'(x)=0, "
01138                                            "P(x)=%g", xextreme,
01139                                            cpl_polynomial_eval_1d(disp, xextreme,
01140                                                                   NULL));
01141     }
01142 
01143     if (dofast) {
01144         const int npix = 1+(int)xtrunc;
01145 
01146         if (erftmp != NULL && cpl_vector_get_size(erftmp) == npix &&
01147             cpl_vector_get(erftmp, 0) > 0.0) {
01148             profile = cpl_vector_get_data(erftmp);
01149         } else {
01150 
01151             const double yval =  0.5 / wslit;
01152             const double x0p  =  0.5 * wslit + 0.5;
01153             const double x0n  = -0.5 * wslit + 0.5;
01154             double       x1diff
01155                 = irplib_erf_antideriv(x0p, sigma)
01156                 - irplib_erf_antideriv(x0n, sigma);
01157             int          ipix;
01158 
01159             if (erftmp == NULL) {
01160                 profile = (double*)cpl_malloc(sizeof(double)*(size_t)npix);
01161             } else {
01162                 cpl_vector_set_size(erftmp, npix);
01163                 profile = cpl_vector_get_data(erftmp);
01164             }
01165 
01166             profile[0] = 2.0 * yval * x1diff;
01167 
01168             for (ipix = 1; ipix < npix; ipix++) {
01169                 const double x1 = (double)ipix;
01170                 const double x1p = x1 + 0.5 * wslit + 0.5;
01171                 const double x1n = x1 - 0.5 * wslit + 0.5;
01172                 const double x0diff = x1diff;
01173 
01174                 x1diff = irplib_erf_antideriv(x1p, sigma)
01175                     - irplib_erf_antideriv(x1n, sigma);
01176 
01177                 profile[ipix] = yval * (x1diff - x0diff);
01178 
01179             }
01180         }
01181     }
01182 
01183     cpl_polynomial_copy(dispi, disp);
01184 
01185     /* FIXME: A custom version of cpl_polynomial_solve_1d() which returns
01186        P'(xpos) can be used for the 1st NR-iteration. */
01187     /* Further, the sign of P'(xpos) could be checked for all lines. */
01188     /* Perform 1st NR-iteration in solving for P(xpos) = dxlines[iline] */
01189     xpos -= (wl - dxlines[iline]) / xderiv;
01190 
01191     /* Iterate through the lines */
01192     for (; !error && iline < nlines; iline++) {
01193 
01194         /* Lines may have a non-physical intensity (e.g. zero) to indicate some
01195            property of the line, e.g. unknown intensity due to blending */
01196         if (dylines[iline] <= 0.0) continue;
01197 
01198         /* Use 1st guess, if available (Use 0.0 to flag unavailable) */
01199         if (plinepix != NULL && plinepix[iline] > 0.0) xpos = plinepix[iline];
01200 
01201         if (xpos > xmax) xpos = xmax; /* FIXME: Better to limit xpos ? */
01202 
01203         /* Find the (sub-) pixel position of the line */
01204         error = cpl_polynomial_set_coeff(dispi, &i0, p0 - dxlines[iline]) ||
01205             cpl_polynomial_solve_1d(dispi, xpos, &xpos, 1);
01206 
01207         if (xpos > xmax) {
01208             if (error) {
01209                 error = 0;
01210                 cpl_msg_debug(cpl_func, "Stopping spectrum fill at line %d/%d "
01211                              "at xpos=%g > xmax=%g",
01212                              iline, nlines, xpos, xmax);
01213                 cpl_errorstate_dump(prestate, CPL_FALSE,
01214                                     irplib_errorstate_dump_debug);
01215                 cpl_errorstate_set(prestate);
01216             }
01217             break;
01218         } else if (error) {
01219             if (linepix != NULL && ulines) (void)cpl_vector_fill(linepix, 0.0);
01220             (void)cpl_error_set_message_macro(cpl_func, cpl_error_get_code(),
01221                                               __FILE__, __LINE__,
01222                                               "Could not find pixel-position "
01223                                               "of line %d/%d at wavelength=%g."
01224                                               " xpos=%g, xmax=%g",
01225                                               iline, nlines, dxlines[iline],
01226                                               xpos, xmax);
01227             break;
01228         } else if (dofast) {
01229             const double frac  = fabs(xpos - floor(xpos));
01230 #ifdef IRPLIB_WAVECAL_FAST_FAST
01231             const double frac0 = 1.0 - frac; /* Weight opposite of distance */
01232 #else
01233             /* Center intensity correctly */
01234             const double ep1pw = irplib_erf_antideriv(frac + 0.5 * wslit, sigma);
01235             const double en1pw = irplib_erf_antideriv(frac + 0.5 * wslit - 1.0,
01236                                                       sigma);
01237             const double ep1nw = irplib_erf_antideriv(frac - 0.5 * wslit, sigma);
01238             const double en1nw = irplib_erf_antideriv(frac - 0.5 * wslit - 1.0,
01239                                                       sigma);
01240             const double frac0
01241                 = (en1nw - en1pw) / (ep1pw - en1pw - ep1nw + en1nw);
01242 
01243 #endif
01244             const double frac1 = 1.0 - frac0;
01245             const double yval0 = frac0 * dylines[iline];
01246             const double yval1 = frac1 * dylines[iline];
01247             const int    npix  = 1+(int)xtrunc;
01248             int          ipix;
01249             int          i0n    = hsize - 1 + floor(xpos);
01250             int          i0p    = i0n;
01251             int          i1n    = i0n + 1;
01252             int          i1p    = i1n;
01253             cpl_boolean  didline = CPL_FALSE;
01254 
01255 
01256             /* Update 1st guess for next time, if available */
01257             if (plinepix != NULL) plinepix[iline] =  xpos;
01258 
01259             if (frac0 < 0.0) {
01260                 (void)cpl_error_set_message_macro(cpl_func,
01261                                                   CPL_ERROR_UNSPECIFIED,
01262                                                   __FILE__, __LINE__,
01263                                                   "Illegal split at x=%g: %g + "
01264                                                   "%g = 1", xpos, frac0, frac1);
01265 #ifdef IRPLIB_WAVEVAL_DEBUG
01266             } else {
01267                 cpl_msg_warning(cpl_func,"profile split at x=%g: %g + %g = 1",
01268                                 xpos, frac0, frac1);
01269 #endif
01270             }
01271 
01272             for (ipix = 0; ipix < npix; ipix++, i0n--, i0p++, i1n--, i1p++) {
01273 
01274                 if (i0n >= 0 && i0n < nself) {
01275                     dself[i0n] += yval0 * profile[ipix];
01276                     didline = CPL_TRUE;
01277                 }
01278                 if (i1n >= 0 && i1n < nself && ipix + 1 < npix) {
01279                     dself[i1n] += yval1 * profile[ipix+1];
01280                     didline = CPL_TRUE;
01281                 }
01282 
01283                 if (ipix == 0) continue;
01284 
01285                 if (i0p >= 0 && i0p < nself) {
01286                     dself[i0p] += yval0 * profile[ipix];
01287                     didline = CPL_TRUE;
01288                 }
01289                 if (i1p >= 0 && i1p < nself && ipix + 1 < npix) {
01290                     dself[i1p] += yval1 * profile[ipix+1];
01291                     didline = CPL_TRUE;
01292                 }
01293             }
01294 
01295             if (didline) ulines++;
01296 
01297         } else {
01298             const double yval = 0.5 * dylines[iline] / wslit;
01299             const int    ifirst = IRPLIB_MAX((int)(xpos-xtrunc+0.5), 1-hsize);
01300             const int    ilast  = IRPLIB_MIN((int)(xpos+xtrunc), nself-hsize);
01301             int          ipix;
01302             const double x0 = (double)ifirst - xpos;
01303             const double x0p = x0 + 0.5*wslit - 0.5;
01304             const double x0n = x0 - 0.5*wslit - 0.5;
01305             double       x1diff
01306                 = irplib_erf_antideriv(x0p, sigma)
01307                 - irplib_erf_antideriv(x0n, sigma);
01308 
01309             /* Update 1st guess for next time, if available */
01310             if (plinepix != NULL) plinepix[iline] =  xpos;
01311 
01312             if (ilast >= ifirst) ulines++;
01313 
01314             for (ipix = ifirst; ipix <= ilast; ipix++) {
01315                 const double x1 = (double)ipix - xpos;
01316                 const double x1p = x1 + 0.5*wslit + 0.5;
01317                 const double x1n = x1 - 0.5*wslit + 0.5;
01318                 const double x0diff = x1diff;
01319 
01320                 x1diff = irplib_erf_antideriv(x1p, sigma)
01321                     - irplib_erf_antideriv(x1n, sigma);
01322 
01323                 dself[ipix+hsize-1] += yval * (x1diff - x0diff);
01324 
01325             }
01326         }
01327     }
01328 
01329     cpl_polynomial_delete(dispi);
01330     if (erftmp == NULL) cpl_free(profile);
01331 
01332     cpl_ensure_code(!error, cpl_error_get_code());
01333 
01334     if (dolog) {
01335         int i;
01336         for (i = 0; i < nself; i++) {
01337             dself[i] = dself[i] > 0.0 ? log(1.0 + dself[i]) : 0.0;
01338         }
01339     }
01340 
01341     if (!ulines) return
01342         cpl_error_set_message_macro(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
01343                                     __FILE__, __LINE__, "The %d-line "
01344                                     "catalogue has no lines in the range "
01345                                     "%g -> P(%g)=%g", nlines, wl, xmax,
01346                                     cpl_polynomial_eval_1d(disp, xmax, NULL));
01347 
01348     if (pulines != NULL) *pulines = ulines;
01349 
01350     return CPL_ERROR_NONE;
01351 }
01352 
01353 /*----------------------------------------------------------------------------*/
01362 /*----------------------------------------------------------------------------*/
01363 inline double irplib_erf_antideriv(double x, double sigma)
01364 {
01365     return x * erf( x / (sigma * CPL_MATH_SQRT2))
01366        + 2.0 * sigma/CPL_MATH_SQRT2PI * exp(-0.5 * x * x / (sigma * sigma));
01367 }
01368 
01369 
01370 #ifdef HAVE_GSL
01371 
01372 /*----------------------------------------------------------------------------*/
01379 /*----------------------------------------------------------------------------*/
01380 static double irplib_gsl_correlation(const gsl_vector * self, void * data)
01381 {
01382 
01383     irplib_multimin * mindata = (irplib_multimin *)data;
01384     cpl_errorstate prestate = cpl_errorstate_get();
01385     int nobs, nmodel, ndiff;
01386     cpl_size i;
01387 
01388     cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
01389     cpl_ensure(data != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
01390 
01391     cpl_ensure(mindata->filler   != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
01392     cpl_ensure(mindata->observed != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
01393     cpl_ensure(mindata->spectrum != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
01394 
01395     nobs   = cpl_vector_get_size(mindata->observed);
01396     nmodel = cpl_vector_get_size(mindata->spectrum);
01397     ndiff  = nmodel - nobs;
01398 
01399     cpl_ensure((ndiff & 1) == 0, CPL_ERROR_ILLEGAL_INPUT, GSL_NAN);
01400 
01401     cpl_ensure(cpl_vector_get_size(mindata->vxc) == 1 + ndiff,
01402                CPL_ERROR_ILLEGAL_INPUT, GSL_NAN);
01403 
01404     ndiff /= 2;
01405 
01406     for (i=0; i < (cpl_size)self->size; i++) {
01407         const double value = gsl_vector_get(self, (size_t)i);
01408         cpl_polynomial_set_coeff(mindata->disp1d, &i, value);
01409     }
01410 
01411     /* Shift reference by -ndiff so filler can be used without offset.
01412        The subsequent polynomial shift is reduced by -ndiff. */
01413     cpl_ensure_code(!cpl_polynomial_shift_1d(mindata->disp1d, 0, -ndiff),
01414                     cpl_error_get_code());
01415 
01416     if (mindata->filler(mindata->spectrum, mindata->disp1d,
01417                         mindata->param)
01418         || !cpl_errorstate_is_equal(prestate)) {
01419 
01420         /* The fill failed. Ensure the discarding of this candidate by
01421            setting the cross-correlation to its minimum possible value. */
01422 
01423         (void)cpl_vector_fill(mindata->vxc, -1.0);
01424 
01425         mindata->maxxc = ndiff;
01426 
01427         if (!cpl_errorstate_is_equal(prestate)) {
01428                 cpl_msg_debug(cpl_func, "Spectrum fill failed:");
01429                 cpl_errorstate_dump(prestate, CPL_FALSE,
01430                                     irplib_errorstate_dump_debug);
01431                 cpl_errorstate_set(prestate);
01432         }
01433     } else {
01434 
01435         mindata->maxxc = cpl_vector_correlate(mindata->vxc,
01436                                               mindata->spectrum,
01437                                               mindata->observed);
01438     }
01439 
01440 #ifdef IRPLIB_SPC_DUMP
01441     /* Need irplib_wavecal.c rev. 1.12 through 1.15 */
01442     irplib_polynomial_dump_corr_step(mindata->disp1d, mindata->vxc,
01443                                      "Optimize");
01444 #endif
01445 
01446     mindata->xc = cpl_vector_get(mindata->vxc, ndiff);
01447 
01448     if (mindata->maxxc != ndiff &&
01449         cpl_vector_get(mindata->vxc, mindata->maxxc) > mindata->mxc) {
01450         const irplib_base_spectrum_model * arclamp
01451             = (const irplib_base_spectrum_model *)mindata->param;
01452 
01453         if (mindata->mdisp == NULL) {
01454             mindata->mdisp = cpl_polynomial_duplicate(mindata->disp1d);
01455         } else {
01456             cpl_polynomial_copy(mindata->mdisp, mindata->disp1d);
01457         }
01458         mindata->mxc = cpl_vector_get(mindata->vxc, mindata->maxxc);
01459         mindata->ishift = mindata->maxxc; /* Offset -ndiff pre-shifted above */
01460         cpl_msg_debug(cpl_func, "Local maximum: %g(%d) > %g(%d) (cost=%u:%u. "
01461                       "lines=%u)", mindata->mxc, mindata->maxxc, mindata->xc,
01462                       ndiff, (unsigned)arclamp->cost, (unsigned)arclamp->xcost,
01463                       (unsigned)arclamp->ulines);
01464     }
01465 
01466     return -mindata->xc;
01467 }
01468 
01469 #endif
01470 
01471 /*----------------------------------------------------------------------------*/
01494 /*----------------------------------------------------------------------------*/
01495 cpl_error_code
01496 irplib_polynomial_find_1d_from_correlation_all(cpl_polynomial * self,
01497                                                int maxdeg,
01498                                                const cpl_vector * obs,
01499                                                int nmaxima,
01500                                                int linelim,
01501                                                irplib_base_spectrum_model* model,
01502                                                cpl_error_code (* filler)
01503                                                (cpl_vector *,
01504                                                 const cpl_polynomial *,
01505                                                 irplib_base_spectrum_model *),
01506                                                double pixtol,
01507                                                double pixstep,
01508                                                int hsize,
01509                                                int maxite,
01510                                                int maxfail,
01511                                                int maxcont,
01512                                                cpl_boolean doplot,
01513                                                double * pxc)
01514 {
01515 
01516 #ifdef HAVE_GSL
01517 
01518     cpl_errorstate     prestate = cpl_errorstate_get();
01519     cpl_polynomial   * start;
01520     cpl_polynomial   * cand;
01521     cpl_polynomial   * backup;
01522     cpl_error_code     error = CPL_ERROR_NONE;
01523     double             xc;
01524     cpl_bivector     * xtshift = cpl_bivector_new(nmaxima ? nmaxima : 1);
01525     const cpl_vector * xtshiftx = cpl_bivector_get_x_const(xtshift);
01526     const cpl_vector * xtshifty = cpl_bivector_get_y_const(xtshift);
01527     int                nshift;
01528     int                imaximum = -1;
01529     int                imaxima;
01530 
01531 #endif
01532 
01533     cpl_ensure_code(self   != NULL, CPL_ERROR_NULL_INPUT);
01534     cpl_ensure_code(obs    != NULL, CPL_ERROR_NULL_INPUT);
01535     cpl_ensure_code(model  != NULL, CPL_ERROR_NULL_INPUT);
01536     cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
01537     cpl_ensure_code(pxc    != NULL, CPL_ERROR_NULL_INPUT);
01538 
01539     cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
01540                     CPL_ERROR_ILLEGAL_INPUT);
01541 
01542     cpl_ensure_code(cpl_polynomial_get_degree(self) > 0,
01543                     CPL_ERROR_ILLEGAL_INPUT);
01544 
01545     cpl_ensure_code(maxdeg  >=  0, CPL_ERROR_ILLEGAL_INPUT);
01546     cpl_ensure_code(pixtol  > 0.0, CPL_ERROR_ILLEGAL_INPUT);
01547     cpl_ensure_code(pixstep > 0.0, CPL_ERROR_ILLEGAL_INPUT);
01548     cpl_ensure_code(hsize   >=  0, CPL_ERROR_ILLEGAL_INPUT);
01549     cpl_ensure_code(maxite  >=  0, CPL_ERROR_ILLEGAL_INPUT);
01550     cpl_ensure_code(nmaxima >=  0, CPL_ERROR_ILLEGAL_INPUT);
01551     cpl_ensure_code(maxfail >   0, CPL_ERROR_ILLEGAL_INPUT);
01552     cpl_ensure_code(maxcont >   0, CPL_ERROR_ILLEGAL_INPUT);
01553     cpl_ensure_code(linelim >=  0, CPL_ERROR_ILLEGAL_INPUT);
01554 
01555 #ifndef HAVE_GSL
01556     /* Avoid unused variable warning */
01557     cpl_ensure_code(doplot == CPL_TRUE || doplot == CPL_FALSE,
01558                     CPL_ERROR_ILLEGAL_INPUT);
01559     return cpl_error_set_message(cpl_func, CPL_ERROR_UNSUPPORTED_MODE,
01560                                  "GSL is not available");
01561 #else
01562 
01563     if (irplib_bivector_find_shift_from_correlation(xtshift, self, obs,
01564                                                     model, filler,
01565                                                     hsize, doplot, &xc)) {
01566         cpl_bivector_delete(xtshift);
01567         return cpl_error_set_where(cpl_func);
01568     }
01569 
01570     if (model->ulines > (cpl_size)linelim) {
01571         /* The initial, optimal (integer) shift */
01572         const double xxc = cpl_vector_get(xtshiftx, 0);
01573         const double xc0 = cpl_vector_get(xtshifty, 0);
01574 
01575         cpl_msg_warning(cpl_func, "Doing only shift=%g pixels with lines=%u > "
01576                         "%d and XC=%g", xxc, (unsigned)model->ulines, linelim,
01577                         xc0);
01578 
01579         cpl_polynomial_shift_1d(self, 0, xxc);
01580 
01581         *pxc = xc0;
01582 
01583         cpl_bivector_delete(xtshift);
01584 
01585         return CPL_ERROR_NONE;
01586     }
01587 
01588     start  = cpl_polynomial_duplicate(self);
01589     cand   = cpl_polynomial_new(1);
01590     backup = cpl_polynomial_new(1);
01591 
01592     /* Number of (local) maxima to use as starting point of the optimization */
01593     nshift = cpl_bivector_get_size(xtshift);
01594     if (nmaxima == 0 || nmaxima > nshift) nmaxima = nshift;
01595 
01596     cpl_msg_info(cpl_func, "Optimizing %d/%d local shift-maxima "
01597                  "(no-shift xc=%g. linelim=%d)", nmaxima, nshift, xc, linelim);
01598     if (cpl_msg_get_level() <= CPL_MSG_DEBUG)
01599         cpl_bivector_dump(xtshift, stdout);
01600 
01601     for (imaxima = 0; imaxima < nmaxima; imaxima++) {
01602         /* The initial, optimal (integer) shift */
01603         const double xxc = cpl_vector_get(xtshiftx, imaxima);
01604         double xtpixstep = pixstep;
01605         double xtpixtol  = pixtol;
01606         double xtxc;
01607         cpl_boolean ok = CPL_FALSE;
01608         int nfail;
01609 
01610 
01611         cpl_polynomial_copy(cand, start);
01612         cpl_polynomial_shift_1d(cand, 0, xxc);
01613         cpl_polynomial_copy(backup, cand);
01614 
01615         /* Increase tolerance until convergence */
01616         for (nfail = 0; nfail < maxfail; nfail++, xtpixtol *= 2.0,
01617                  xtpixstep *= 2.0) {
01618             int restart = maxcont;
01619             cpl_boolean redo;
01620 
01621             do {
01622                 if (error) {
01623                     cpl_errorstate_dump(prestate, CPL_FALSE,
01624                                         irplib_errorstate_dump_debug);
01625                     cpl_errorstate_set(prestate);
01626                 }
01627                 error = irplib_polynomial_find_1d_from_correlation_
01628                     (cand, maxdeg, obs, model,
01629                      filler, xtpixtol, xtpixstep, 2,
01630                      maxite, &xtxc, &redo);
01631                 if (redo && !error) error = CPL_ERROR_CONTINUE;
01632             } while (((!error && redo) || error == CPL_ERROR_CONTINUE)
01633                      && --restart);
01634 
01635             if (!error && !redo) {
01636                 cpl_msg_debug(cpl_func, "XC(imax=%d/%d:xtpixtol=%g): %g "
01637                               "(cost=%u:%u)", 1+imaxima, nmaxima, xtpixtol,
01638                               xtxc, (unsigned)model->cost,
01639                               (unsigned)model->xcost);
01640                 break;
01641             }
01642             cpl_msg_warning(cpl_func, "Increasing xtpixtol from %g (%g, imax="
01643                             "%d/%d)", xtpixtol, xtpixstep, 1+imaxima, nmaxima);
01644             if (model->ulines > (cpl_size)linelim) {
01645                 cpl_msg_warning(cpl_func, "Stopping search-refinement via "
01646                                 "catalogue with %u lines > %d",
01647                                 (unsigned)model->ulines, linelim);
01648                 break;
01649             }
01650             cpl_polynomial_copy(cand, start);
01651         }
01652 
01653         /* Decrease tolerance until divergence, keep previous */
01654         for (; !error && xtpixtol > 0.0; xtpixtol *= 0.25, xtpixstep *= 0.5) {
01655             int restart = maxcont;
01656             cpl_boolean redo;
01657 
01658             cpl_polynomial_copy(backup, cand);
01659             do {
01660                 if (error) {
01661                     cpl_errorstate_dump(prestate, CPL_FALSE,
01662                                         irplib_errorstate_dump_debug);
01663                     cpl_errorstate_set(prestate);
01664                 }
01665                 error = irplib_polynomial_find_1d_from_correlation_
01666                     (cand, maxdeg, obs, model, filler,
01667                      xtpixtol, xtpixstep, 2, maxite, &xtxc, &redo);
01668                 if (redo && !error) error = CPL_ERROR_CONTINUE;
01669             } while (((!error && redo) || error == CPL_ERROR_CONTINUE)
01670                      && --restart);
01671             if (error) break;
01672             ok = CPL_TRUE;
01673             if (redo) break;
01674             cpl_msg_debug(cpl_func, "XC(imax=%d/%d:xtpixtol=%g): %g (cost=%u:%u"
01675                           ". ulines=%u)", 1+imaxima, nmaxima, xtpixtol, xtxc,
01676                           (unsigned)model->cost, (unsigned)model->xcost,
01677                           (unsigned)model->ulines);
01678             if (model->ulines > (cpl_size)linelim) {
01679                 cpl_msg_info(cpl_func, "Stopping search-refinement via "
01680                              "catalogue with %u lines > %u",
01681                              (unsigned)model->ulines, linelim);
01682                 break;
01683             }
01684         }
01685 
01686         if (error) {
01687             error = 0;
01688             cpl_errorstate_dump(prestate, CPL_FALSE,
01689                                 irplib_errorstate_dump_debug);
01690             cpl_errorstate_set(prestate);
01691             cpl_polynomial_copy(cand, backup);
01692         }
01693         if (ok && xtxc > xc) {
01694             imaximum = imaxima;
01695             cpl_polynomial_copy(self, cand);
01696             xc = xtxc;
01697 
01698             cpl_msg_info(cpl_func, "XC(imax=%d/%d): %g -> %g (initial-shift=%g. "
01699                          "cost=%u:%u. lines=%u)", 1+imaxima, nmaxima,
01700                          cpl_vector_get(xtshifty, imaxima), xtxc,
01701                          cpl_vector_get(xtshiftx, imaxima),
01702                          (unsigned)model->cost, (unsigned)model->xcost,
01703                          (unsigned)model->ulines);
01704         } else {
01705             cpl_msg_info(cpl_func, "xc(imax=%d/%d): %g -> %g (initial-shift=%g. "
01706                          "cost=%u:%u. lines=%u)", 1+imaxima, nmaxima,
01707                          cpl_vector_get(xtshifty, imaxima), xtxc,
01708                          cpl_vector_get(xtshiftx, imaxima),
01709                          (unsigned)model->cost, (unsigned)model->xcost,
01710                          (unsigned)model->ulines);
01711         }
01712     }
01713 
01714     cpl_polynomial_delete(start);
01715     cpl_polynomial_delete(backup);
01716     cpl_polynomial_delete(cand);
01717 
01718     if (imaximum < 0) {
01719       /* The initial, optimal (integer) shift */
01720         const double xxc = cpl_vector_get(xtshiftx, 0);
01721         const double xc0 = cpl_vector_get(xtshifty, 0);
01722 
01723         error = cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
01724                                       "Could not improve XC=%g over %d "
01725                                       "local shift-maxima, best at shift %g",
01726                                       xc0, nmaxima, xxc);
01727     } else {
01728         cpl_msg_info(cpl_func, "Maximal XC=%g (up from %g, with initial pixel-"
01729                      "shift of %g) at %d/%d local shift-maximi", xc,
01730                      cpl_vector_get(xtshifty, imaximum),
01731                      cpl_vector_get(xtshiftx, imaximum),
01732                      1+imaximum, nmaxima);
01733 
01734         if (doplot) {
01735             irplib_plot_spectrum_and_model(obs, self, model, filler);
01736         }
01737 
01738         *pxc = xc;
01739     }
01740 
01741     cpl_bivector_delete(xtshift);
01742 
01743     return error;
01744 
01745 #endif
01746 
01747 }

Generated on 3 Mar 2013 for DETMON Pipeline Reference Manual by  doxygen 1.6.1