CR2RE Pipeline Reference Manual 1.6.2
irplib_wavecal.c
1/*
2 * This file is part of the IRPLIB Pipeline
3 * Copyright (C) 2002,2003,2014 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24/*-----------------------------------------------------------------------------
25 Includes
26 -----------------------------------------------------------------------------*/
27
28#include "irplib_wavecal_impl.h"
29
30/* Needed for irplib_errorstate_dump_debug() */
31#include "irplib_utils.h"
32
33#include <string.h>
34#include <math.h>
35
36#ifdef HAVE_GSL
37#include <gsl/gsl_multimin.h>
38#endif
39
40/*-----------------------------------------------------------------------------
41 Private types
42 -----------------------------------------------------------------------------*/
43
44#ifdef HAVE_GSL
45
46typedef struct {
47
48 const cpl_vector * observed;
49 cpl_polynomial * disp1d;
50 cpl_vector * spectrum;
51 irplib_base_spectrum_model * param;
52 cpl_error_code (* filler)(cpl_vector *, const cpl_polynomial *,
53 irplib_base_spectrum_model *);
54 cpl_vector * vxc;
55 double xc;
56 int maxxc;
57 double mxc;
58 cpl_polynomial * mdisp;
59 int ishift;
60
61} irplib_multimin;
62
63#endif /* HAVE_GSL */
64
65/*-----------------------------------------------------------------------------
66 Defines
67 -----------------------------------------------------------------------------*/
68
69#ifndef inline
70#define inline /* inline */
71#endif
72
73#define IRPLIB_MAX(A,B) ((A) > (B) ? (A) : (B))
74#define IRPLIB_MIN(A,B) ((A) < (B) ? (A) : (B))
75
76/*-----------------------------------------------------------------------------
77 Private functions
78 -----------------------------------------------------------------------------*/
79
80#ifdef HAVE_GSL
81static double irplib_gsl_correlation(const gsl_vector *, void *);
82#endif
83
84static cpl_error_code
85irplib_polynomial_find_1d_from_correlation_(cpl_polynomial *, int,
86 const cpl_vector *,
87 irplib_base_spectrum_model *,
88 cpl_error_code (*)
89 (cpl_vector *,
90 const cpl_polynomial *,
91 irplib_base_spectrum_model *),
92 double, double, int, int,
93 double *, cpl_boolean *);
94
95
96/*----------------------------------------------------------------------------*/
100/*----------------------------------------------------------------------------*/
101
105/*----------------------------------------------------------------------------*/
113/*----------------------------------------------------------------------------*/
114int irplib_bivector_count_positive(const cpl_bivector * self,
115 double x_min,
116 double x_max)
117{
118
119 const int nself = cpl_bivector_get_size(self);
120 const double * px = cpl_bivector_get_x_data_const(self);
121 const double * py = cpl_bivector_get_y_data_const(self);
122 int npos = 0;
123 int i = 0;
124
125 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, -1);
126 cpl_ensure(x_min <= x_max, CPL_ERROR_ILLEGAL_INPUT, -2);
127
128 /* FIXME: Use cpl_vector_find() */
129 while (i < nself && px[i] < x_min) i++;
130 while (i < nself && px[i] < x_max)
131 if (py[i++] > 0) npos++;
132
133 return npos;
134}
135
136/*----------------------------------------------------------------------------*/
146/*----------------------------------------------------------------------------*/
147cpl_error_code irplib_polynomial_fit_2d_dispersion(cpl_polynomial * self,
148 const cpl_image * imgwave,
149 int fitdeg, double * presid)
150{
151
152 const int nx = cpl_image_get_size_x(imgwave);
153 const int ny = cpl_image_get_size_y(imgwave);
154 const int nbad = cpl_image_count_rejected(imgwave);
155 const int nsamp = nx * ny - nbad;
156 cpl_matrix * xy_pos;
157 double * xdata;
158 double * ydata;
159 cpl_vector * wlen;
160 double * dwlen;
161 const cpl_size nfitdeg = (cpl_size)fitdeg;
162 int i, j;
163 int k = 0;
164
165 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
166 cpl_ensure_code(imgwave != NULL, CPL_ERROR_NULL_INPUT);
167 cpl_ensure_code(presid != NULL, CPL_ERROR_NULL_INPUT);
168 cpl_ensure_code(fitdeg > 0, CPL_ERROR_ILLEGAL_INPUT);
169
170 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 2,
171 CPL_ERROR_ILLEGAL_INPUT);
172
173 xy_pos = cpl_matrix_new(2, nsamp);
174 xdata = cpl_matrix_get_data(xy_pos);
175 ydata = xdata + nsamp;
176
177 dwlen = (double*)cpl_malloc(nsamp * sizeof(double));
178 wlen = cpl_vector_wrap(nsamp, dwlen);
179
180 for (i=1; i <= nx; i++) {
181 for (j=1; j <= ny; j++) {
182 int is_bad;
183 const double value = cpl_image_get(imgwave, i, j, &is_bad);
184 if (!is_bad) {
185 xdata[k] = i;
186 ydata[k] = j;
187 dwlen[k] = value;
188 k++;
189 }
190 }
191 }
192
193 cpl_msg_info(cpl_func, "Fitting 2D polynomial to %d X %d image, ignoring "
194 "%d poorly calibrated pixels", nx, ny, nbad);
195
196 if (cpl_polynomial_fit(self, xy_pos, NULL, wlen, NULL, CPL_FALSE, NULL,
197 &nfitdeg) == CPL_ERROR_NONE && presid != NULL) {
198 cpl_vector_fill_polynomial_fit_residual(wlen, wlen, NULL, self, xy_pos,
199 NULL);
200 *presid = cpl_vector_product(wlen, wlen)/nsamp;
201 }
202 cpl_matrix_delete(xy_pos);
203 cpl_vector_delete(wlen);
204
205 cpl_ensure_code(k == nsamp, CPL_ERROR_UNSPECIFIED);
206
207 return CPL_ERROR_NONE;
208}
209
210
211/*----------------------------------------------------------------------------*/
229/*----------------------------------------------------------------------------*/
230cpl_error_code
232 int maxdeg,
233 const cpl_vector * obs,
234 irplib_base_spectrum_model * model,
235 cpl_error_code (* filler)
236 (cpl_vector *,
237 const cpl_polynomial *,
238 irplib_base_spectrum_model *),
239 double pixtol,
240 double pixstep,
241 int hsize,
242 int maxite,
243 double * pxc)
244{
245 cpl_boolean restart = CPL_FALSE;
246 const cpl_error_code error = irplib_polynomial_find_1d_from_correlation_
247 (self, maxdeg, obs, model, filler, pixtol, pixstep, hsize, maxite, pxc,
248 &restart);
249
250 return error ? cpl_error_set_where(cpl_func) :
251 (restart ? cpl_error_set(cpl_func, CPL_ERROR_CONTINUE)
252 : CPL_ERROR_NONE);
253}
254
255/*----------------------------------------------------------------------------*/
276/*----------------------------------------------------------------------------*/
277static cpl_error_code
278irplib_polynomial_find_1d_from_correlation_(cpl_polynomial * self,
279 int maxdeg,
280 const cpl_vector * obs,
281 irplib_base_spectrum_model * model,
282 cpl_error_code (* filler)
283 (cpl_vector *,
284 const cpl_polynomial *,
285 irplib_base_spectrum_model *),
286 double pixtol,
287 double pixstep,
288 int hsize,
289 int maxite,
290 double * pxc,
291 cpl_boolean * prestart)
292{
293
294#ifdef HAVE_GSL
295 const gsl_multimin_fminimizer_type * T = gsl_multimin_fminimizer_nmsimplex;
296 gsl_multimin_fminimizer * minimizer;
297 gsl_multimin_function my_func;
298 irplib_multimin data;
299 gsl_vector * dispgsl;
300 gsl_vector * stepsize;
301 gsl_vector * dispprev;
302 int status = GSL_CONTINUE;
303 const int nobs = cpl_vector_get_size(obs);
304 const cpl_size nfit = maxdeg + 1;
305 cpl_errorstate prestate = cpl_errorstate_get();
306 /* Convert pixel step to wavelength step on detector center */
307 const double wlstep =
308 cpl_polynomial_eval_1d_diff(self, 0.5 * (nobs + pixstep),
309 0.5 * (nobs - pixstep), NULL);
310 double wlstepi = wlstep;
311 int iter;
312 cpl_size i;
313
314#endif
315
316 cpl_ensure_code(prestart != NULL, CPL_ERROR_NULL_INPUT);
317 *prestart = CPL_FALSE;
318 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
319 cpl_ensure_code(obs != NULL, CPL_ERROR_NULL_INPUT);
320 cpl_ensure_code(model != NULL, CPL_ERROR_NULL_INPUT);
321 cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
322 cpl_ensure_code(pxc != NULL, CPL_ERROR_NULL_INPUT);
323
324 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
325 CPL_ERROR_ILLEGAL_INPUT);
326
327 cpl_ensure_code(cpl_polynomial_get_degree(self) > 0,
328 CPL_ERROR_ILLEGAL_INPUT);
329
330 cpl_ensure_code(maxdeg >= 0, CPL_ERROR_ILLEGAL_INPUT);
331 cpl_ensure_code(pixtol > 0.0, CPL_ERROR_ILLEGAL_INPUT);
332 cpl_ensure_code(pixstep > 0.0, CPL_ERROR_ILLEGAL_INPUT);
333 cpl_ensure_code(hsize >= 0, CPL_ERROR_ILLEGAL_INPUT);
334 cpl_ensure_code(maxite >= 0, CPL_ERROR_ILLEGAL_INPUT);
335
336#ifndef HAVE_GSL
337 return cpl_error_set_message(cpl_func, CPL_ERROR_UNSUPPORTED_MODE,
338 "GSL is not available");
339#else
340
341 minimizer = gsl_multimin_fminimizer_alloc(T, (size_t)nfit);
342
343 cpl_ensure_code(minimizer != NULL, CPL_ERROR_ILLEGAL_OUTPUT);
344
345 dispgsl = gsl_vector_alloc((size_t)nfit);
346 stepsize = gsl_vector_alloc((size_t)nfit);
347 dispprev = gsl_vector_alloc((size_t)nfit);
348
349 for (i=0; i < nfit; i++) {
350 const double value = cpl_polynomial_get_coeff(self, &i);
351 gsl_vector_set(dispgsl, (size_t)i, value);
352 gsl_vector_set(stepsize, (size_t)i, wlstepi);
353 wlstepi /= (double)nobs;
354 }
355
356 my_func.n = nfit;
357 my_func.f = &irplib_gsl_correlation;
358 my_func.params = (void *)(&data);
359
360 data.observed = obs;
361 data.disp1d = self;
362 data.spectrum = cpl_vector_new(nobs + 2 * hsize);
363 data.vxc = cpl_vector_new(1 + 2 * hsize);
364 data.xc = 0;
365 data.param = model;
366 data.filler = filler;
367 data.maxxc = 0; /* Output */
368 data.ishift = 0; /* Output */
369 data.mxc = -1.0; /* Output */
370 data.mdisp = NULL; /* Output */
371
372 gsl_multimin_fminimizer_set (minimizer, &my_func, dispgsl, stepsize);
373
374 for (iter = 0; status == GSL_CONTINUE && iter < maxite; iter++) {
375
376 double size;
377 const double fprev = minimizer->fval;
378
379 gsl_vector_memcpy(dispprev, minimizer->x);
380 status = gsl_multimin_fminimizer_iterate(minimizer);
381
382 if (status || !cpl_errorstate_is_equal(prestate)) break;
383
384 size = gsl_multimin_fminimizer_size (minimizer);
385 status = gsl_multimin_test_size (size, pixtol);
386
387 if (status == GSL_SUCCESS) {
388 cpl_msg_debug(cpl_func, "converged to minimum at");
389
390 if (nfit == 0) {
391 cpl_msg_debug(cpl_func, "%5d %g df() = %g size = %g",
392 iter,
393 gsl_vector_get (minimizer->x, 0)
394 - gsl_vector_get (dispprev, 0),
395 minimizer->fval - fprev, size);
396 } else if (nfit == 1) {
397 cpl_msg_debug(cpl_func, "%5d %g %g df() = %g size = %g",
398 iter,
399 gsl_vector_get (minimizer->x, 0)
400 - gsl_vector_get (dispprev, 0),
401 gsl_vector_get (minimizer->x, 1)
402 - gsl_vector_get (dispprev, 1),
403 minimizer->fval - fprev, size);
404 } else {
405 cpl_msg_debug(cpl_func, "%5d %g %g %g df() = %g size = %g",
406 iter,
407 gsl_vector_get (minimizer->x, 0)
408 - gsl_vector_get (dispprev, 0),
409 gsl_vector_get (minimizer->x, 1)
410 - gsl_vector_get (dispprev, 1),
411 gsl_vector_get (minimizer->x, 2)
412 - gsl_vector_get (dispprev, 2),
413 minimizer->fval - fprev, size);
414 }
415 }
416 }
417
418 if (status == GSL_SUCCESS && cpl_errorstate_is_equal(prestate)) {
419 if (data.mxc > -minimizer->fval) {
420 *pxc = data.mxc;
421 cpl_msg_warning(cpl_func, "Local maximum: %g(%d) > %g",
422 data.mxc, data.ishift, -minimizer->fval);
423 cpl_polynomial_shift_1d(data.mdisp, 0, (double)data.ishift);
424 cpl_polynomial_copy(self, data.mdisp);
425 *prestart = CPL_TRUE;
426 } else {
427 *pxc = -minimizer->fval;
428 for (i=0; i < nfit; i++) {
429 const double value = gsl_vector_get(minimizer->x, i);
430 cpl_polynomial_set_coeff(self, &i, value);
431 }
432 }
433 }
434
435 cpl_vector_delete(data.spectrum);
436 cpl_vector_delete(data.vxc);
437 cpl_polynomial_delete(data.mdisp);
438 gsl_multimin_fminimizer_free(minimizer);
439 gsl_vector_free(dispgsl);
440 gsl_vector_free(dispprev);
441 gsl_vector_free(stepsize);
442
443 cpl_ensure_code(status != GSL_CONTINUE, CPL_ERROR_CONTINUE);
444 cpl_ensure_code(status == GSL_SUCCESS, CPL_ERROR_DATA_NOT_FOUND);
445 cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
446
447 return CPL_ERROR_NONE;
448#endif
449}
450
451
452/*----------------------------------------------------------------------------*/
480/*----------------------------------------------------------------------------*/
481cpl_error_code
483 const cpl_polynomial * disp,
484 irplib_base_spectrum_model * lsslamp)
485{
486
487 irplib_line_spectrum_model * arclamp
488 = (irplib_line_spectrum_model *)lsslamp;
489 cpl_error_code error;
490
491 cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
492
493 arclamp->cost++;
494
496 arclamp->linepix,
497 arclamp->erftmp,
498 disp,
499 arclamp->lines,
500 arclamp->wslit,
501 arclamp->wfwhm,
502 arclamp->xtrunc,
503 0, CPL_FALSE, CPL_FALSE,
504 &(arclamp->ulines));
505 cpl_ensure_code(!error, error);
506
507 arclamp->xcost++;
508
509 return CPL_ERROR_NONE;
510}
511
512/*----------------------------------------------------------------------------*/
525/*----------------------------------------------------------------------------*/
526cpl_error_code
528 const cpl_polynomial * disp,
529 irplib_base_spectrum_model * lsslamp)
530{
531
532 irplib_line_spectrum_model * arclamp
533 = (irplib_line_spectrum_model *)lsslamp;
534 cpl_error_code error;
535
536 cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
537
538 arclamp->cost++;
539
541 arclamp->linepix,
542 arclamp->erftmp,
543 disp,
544 arclamp->lines,
545 arclamp->wslit,
546 arclamp->wfwhm,
547 arclamp->xtrunc,
548 0, CPL_FALSE, CPL_TRUE,
549 &(arclamp->ulines));
550 cpl_ensure_code(!error, error);
551
552 arclamp->xcost++;
553
554 return CPL_ERROR_NONE;
555}
556
557
558/*----------------------------------------------------------------------------*/
571/*----------------------------------------------------------------------------*/
572cpl_error_code
574 const cpl_polynomial * disp,
575 irplib_base_spectrum_model * lsslamp)
576{
577
578 irplib_line_spectrum_model * arclamp
579 = (irplib_line_spectrum_model *)lsslamp;
580 cpl_error_code error;
581
582 cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
583
584 arclamp->cost++;
585
587 arclamp->linepix,
588 arclamp->erftmp,
589 disp,
590 arclamp->lines,
591 arclamp->wslit,
592 arclamp->wfwhm,
593 arclamp->xtrunc,
594 0, CPL_TRUE, CPL_FALSE,
595 &(arclamp->ulines));
596 cpl_ensure_code(!error, error);
597
598 arclamp->xcost++;
599
600 return CPL_ERROR_NONE;
601}
602
603/*----------------------------------------------------------------------------*/
616/*----------------------------------------------------------------------------*/
617cpl_error_code
619 const cpl_polynomial * disp,
620 irplib_base_spectrum_model * lsslamp)
621{
622
623 irplib_line_spectrum_model * arclamp
624 = (irplib_line_spectrum_model *)lsslamp;
625 cpl_error_code error;
626
627 cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
628
629 arclamp->cost++;
630
632 arclamp->linepix,
633 arclamp->erftmp,
634 disp,
635 arclamp->lines,
636 arclamp->wslit,
637 arclamp->wfwhm,
638 arclamp->xtrunc,
639 0, CPL_TRUE, CPL_TRUE,
640 &(arclamp->ulines));
641 cpl_ensure_code(!error, error);
642
643 arclamp->xcost++;
644
645 return CPL_ERROR_NONE;
646}
647
648/*----------------------------------------------------------------------------*/
659/*----------------------------------------------------------------------------*/
660cpl_error_code irplib_plot_spectrum_and_model(const cpl_vector * self,
661 const cpl_polynomial * disp1d,
662 irplib_base_spectrum_model * model,
663 cpl_error_code (* filler)
664 (cpl_vector *,
665 const cpl_polynomial *,
666 irplib_base_spectrum_model *))
667{
668
669 cpl_errorstate prestate = cpl_errorstate_get();
670 cpl_vector * wl;
671 cpl_vector * spectrum;
672 cpl_vector * vxc;
673 const int len = cpl_vector_get_size(self);
674 double maxval, xc;
675 int ixc;
676 int error = 0;
677
678 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
679 cpl_ensure_code(disp1d != NULL, CPL_ERROR_NULL_INPUT);
680 cpl_ensure_code(model != NULL, CPL_ERROR_NULL_INPUT);
681 cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
682
683 cpl_ensure_code(cpl_polynomial_get_dimension(disp1d) == 1,
684 CPL_ERROR_ILLEGAL_INPUT);
685
686 cpl_ensure_code(cpl_polynomial_get_degree(disp1d) > 0,
687 CPL_ERROR_ILLEGAL_INPUT);
688
689 wl = cpl_vector_new(len);
690 spectrum = cpl_vector_new(len);
691 vxc = cpl_vector_new(1);
692
693 error |= (int)cpl_vector_fill_polynomial(wl, disp1d, 1.0, 1.0);
694 error |= filler(spectrum, disp1d, model);
695
696 ixc = cpl_vector_correlate(vxc, self, spectrum);
697 xc = cpl_vector_get(vxc, ixc);
698
699 maxval = cpl_vector_get_max(spectrum);
700 if (maxval != 0.0)
701 error |= cpl_vector_multiply_scalar(spectrum,
702 cpl_vector_get_max(self)/maxval);
703 if (!error) {
704 const cpl_vector * spair[] = {wl, self, spectrum};
705 char * pre = cpl_sprintf("set grid;set xlabel 'Wavelength (%g -> %g)'; "
706 "set ylabel 'Intensity';", cpl_vector_get(wl, 0),
707 cpl_vector_get(wl, len-1));
708 char * title = cpl_sprintf("t 'Observed and modelled spectra (%d pixel "
709 "XC=%g) ' w linespoints", len, xc);
710
711 (void)cpl_plot_vectors(pre, title, "", spair, 3);
712 cpl_free(pre);
713 cpl_free(title);
714 }
715
716 cpl_vector_delete(wl);
717 cpl_vector_delete(spectrum);
718 cpl_vector_delete(vxc);
719
720 cpl_errorstate_set(prestate);
721
722 return CPL_ERROR_NONE;
723}
724
725/*----------------------------------------------------------------------------*/
745/*----------------------------------------------------------------------------*/
746cpl_error_code
748 const cpl_polynomial * disp,
749 const cpl_vector * obs,
750 irplib_base_spectrum_model * model,
751 cpl_error_code (*filler)
752 (cpl_vector *,
753 const cpl_polynomial *,
754 irplib_base_spectrum_model *),
755 int hsize,
756 cpl_boolean doplot,
757 double *pxc)
758{
759
760 const int nobs = cpl_vector_get_size(obs);
761 const int nmodel = 2 * hsize + nobs;
762 cpl_polynomial * shdisp;
763 cpl_vector * xself = cpl_bivector_get_x(self);
764 cpl_vector * yself = cpl_bivector_get_y(self);
765 cpl_vector * mspec1d;
766 cpl_vector * xcorr;
767 cpl_error_code error = CPL_ERROR_NONE;
768 double xcprev, xcnext;
769 int ixc, imax = 0;
770 int i;
771
772 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
773 cpl_ensure_code(disp != NULL, CPL_ERROR_NULL_INPUT);
774 cpl_ensure_code(obs != NULL, CPL_ERROR_NULL_INPUT);
775 cpl_ensure_code(model != NULL, CPL_ERROR_NULL_INPUT);
776 cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
777 cpl_ensure_code(hsize > 0, CPL_ERROR_ILLEGAL_INPUT);
778
779 shdisp = cpl_polynomial_duplicate(disp);
780
781 /* Shift reference by -hsize so filler can be used without offset */
782 if (cpl_polynomial_shift_1d(shdisp, 0, -hsize)) {
783 cpl_polynomial_delete(shdisp);
784 return cpl_error_set_where(cpl_func);
785 }
786
787 mspec1d = cpl_vector_new(nmodel);
788
789 if (filler(mspec1d, shdisp, model)) {
790 cpl_vector_delete(mspec1d);
791 return cpl_error_set_where(cpl_func);
792 }
793
794 /* Should not be able to fail now */
795 xcorr = cpl_vector_new(1 + 2 * hsize);
796 ixc = cpl_vector_correlate(xcorr, mspec1d, obs);
797
798#ifdef IRPLIB_SPC_DUMP
799 /* Need irplib_wavecal.c rev. 1.12 through 1.15 */
800 irplib_polynomial_dump_corr_step(shdisp, xcorr, "Shift");
801#endif
802
803 cpl_vector_delete(mspec1d);
804 cpl_polynomial_delete(shdisp);
805
806 /* Find local maxima. */
807 /* FIXME(?): Also include stationary points */
808 i = 0;
809 xcprev = cpl_vector_get(xcorr, i);
810 xcnext = cpl_vector_get(xcorr, i+1);
811
812 if (xcprev >= xcnext) {
813 /* 1st data point is an extreme */
814 /* FIXME: This could also be an error, recoverable by caller by
815 increasing hsize */
816 imax++;
817
818 cpl_vector_set(xself, 0, i - hsize);
819 cpl_vector_set(yself, 0, xcprev);
820
821 }
822
823 for (i = 1; i < 2 * hsize; i++) {
824 const double xc = xcnext;
825 xcnext = cpl_vector_get(xcorr, i+1);
826 if (xc >= xcprev && xc >= xcnext) {
827 /* Found (local) maximum at shift i - hsize */
828 int j;
829
830 imax++;
831
832 if (cpl_bivector_get_size(self) < imax) {
833 cpl_vector_set_size(xself, imax);
834 cpl_vector_set_size(yself, imax);
835 }
836
837 for (j = imax-1; j > 0; j--) {
838 if (xc <= cpl_vector_get(yself, j-1)) break;
839 cpl_vector_set(xself, j, cpl_vector_get(xself, j-1));
840 cpl_vector_set(yself, j, cpl_vector_get(yself, j-1));
841 }
842 cpl_vector_set(xself, j, i - hsize);
843 cpl_vector_set(yself, j, xc);
844 }
845 xcprev = xc;
846 }
847
848 /* assert( i == 2 * hsize ); */
849
850 if (xcnext >= xcprev) {
851 /* Last data point is an extreme */
852 /* FIXME: This could also be an error, recoverable by caller by
853 increasing hsize */
854 int j;
855
856 imax++;
857
858 if (cpl_bivector_get_size(self) < imax) {
859 cpl_vector_set_size(xself, imax);
860 cpl_vector_set_size(yself, imax);
861 }
862
863 for (j = imax-1; j > 0; j--) {
864 if (xcnext <= cpl_vector_get(yself, j-1)) break;
865 cpl_vector_set(xself, j, cpl_vector_get(xself, j-1));
866 cpl_vector_set(yself, j, cpl_vector_get(yself, j-1));
867 }
868 cpl_vector_set(xself, j, i - hsize);
869 cpl_vector_set(yself, j, xcnext);
870
871 }
872
873 if (doplot) {
874 /* Vector of -hsize, 1-hsize, 2-hsize, ..., 0, ..., hsize */
875 cpl_vector * xvals = cpl_vector_new(1 + 2 * hsize);
876 cpl_bivector * bcorr = cpl_bivector_wrap_vectors(xvals, xcorr);
877 double x = (double)-hsize;
878 char * title = cpl_sprintf("t 'Cross-correlation of shifted %d-pixel "
879 "spectrum (XCmax=%g at %d)' w linespoints",
880 nobs, cpl_vector_get(xcorr, ixc),
881 ixc - hsize);
882
883 for (i = 0; i < 1 + 2 * hsize; i++, x += 1.0) {
884 cpl_vector_set(xvals, i, x);
885 }
886
887 cpl_plot_bivector("set grid;set xlabel 'Offset [pixel]';", title,
888 "", bcorr);
889 cpl_bivector_unwrap_vectors(bcorr);
890 cpl_vector_delete(xvals);
891 cpl_free(title);
892 }
893
894 if (pxc != NULL) *pxc = cpl_vector_get(xcorr, hsize);
895
896 cpl_vector_delete(xcorr);
897
898 if (imax < 1) {
899 error = CPL_ERROR_DATA_NOT_FOUND;
900 } else if (cpl_bivector_get_size(self) > imax) {
901 cpl_vector_set_size(xself, imax);
902 cpl_vector_set_size(yself, imax);
903 }
904
905 /* Propagate error, if any */
906 return cpl_error_set(cpl_func, error);
907}
908
909/*----------------------------------------------------------------------------*/
922/*----------------------------------------------------------------------------*/
923cpl_error_code
925 const cpl_vector * obs,
926 irplib_base_spectrum_model * model,
927 cpl_error_code (*filler)
928 (cpl_vector *,
929 const cpl_polynomial *,
930 irplib_base_spectrum_model *),
931 int hsize,
932 cpl_boolean doplot,
933 double * pxc)
934{
935
936 const int nobs = cpl_vector_get_size(obs);
937 const int nmodel = 2 * hsize + nobs;
938 cpl_vector * mspec1d;
939 cpl_vector * xcorr;
940 cpl_error_code error;
941 int ixc, xxc;
942 double xc;
943
944 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
945 cpl_ensure_code(obs != NULL, CPL_ERROR_NULL_INPUT);
946 cpl_ensure_code(model != NULL, CPL_ERROR_NULL_INPUT);
947 cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
948 cpl_ensure_code(hsize > 0, CPL_ERROR_ILLEGAL_INPUT);
949
950 /* Shift reference by -hsize so filler can be used without offset */
951 cpl_ensure_code(!cpl_polynomial_shift_1d(self, 0, -hsize),
952 cpl_error_get_code());
953
954 mspec1d = cpl_vector_new(nmodel);
955
956 if (filler(mspec1d, self, model)) {
957 cpl_vector_delete(mspec1d);
958 return cpl_error_set_where(cpl_func);
959 }
960
961 /* Should not be able to fail now */
962 xcorr = cpl_vector_new(1 + 2 * hsize);
963 ixc = cpl_vector_correlate(xcorr, mspec1d, obs);
964
965#ifdef IRPLIB_SPC_DUMP
966 /* Need irplib_wavecal.c rev. 1.12 through 1.15 */
967 irplib_polynomial_dump_corr_step(self, xcorr, "Shift");
968#endif
969
970 cpl_vector_delete(mspec1d);
971
972 error = cpl_polynomial_shift_1d(self, 0, (double)ixc);
973
974 xc = cpl_vector_get(xcorr, ixc);
975
976 xxc = ixc - hsize; /* The effect of the two shifts */
977
978 cpl_msg_info(cpl_func, "Shifting %d pixels (%g < %g)", xxc,
979 cpl_vector_get(xcorr, hsize), xc);
980
981 if (doplot) {
982 cpl_vector * xvals = cpl_vector_new(1 + 2 * hsize);
983 cpl_bivector * bcorr = cpl_bivector_wrap_vectors(xvals, xcorr);
984 int i;
985 double x = (double)-hsize;
986 char * title = cpl_sprintf("t 'Cross-correlation of shifted %d-pixel "
987 "spectrum (XCmax=%g at %d)' w linespoints",
988 nobs, cpl_vector_get(xcorr, ixc), xxc);
989
990 for (i = 0; i < 1 + 2 * hsize; i++, x += 1.0) {
991 cpl_vector_set(xvals, i, x);
992 }
993
994 cpl_plot_bivector("set grid;set xlabel 'Offset [pixel]';", title,
995 "", bcorr);
996 cpl_bivector_unwrap_vectors(bcorr);
997 cpl_vector_delete(xvals);
998 cpl_free(title);
999 }
1000
1001 cpl_vector_delete(xcorr);
1002
1003 cpl_ensure_code(!error, error);
1004
1005 if (pxc != NULL) *pxc = xc;
1006
1007 return CPL_ERROR_NONE;
1008
1009}
1010
1011
1012/*----------------------------------------------------------------------------*/
1033/*----------------------------------------------------------------------------*/
1034cpl_error_code
1036 cpl_vector * linepix,
1037 cpl_vector * erftmp,
1038 const cpl_polynomial * disp,
1039 const cpl_bivector * lines,
1040 double wslit,
1041 double wfwhm,
1042 double xtrunc,
1043 int hsize,
1044 cpl_boolean dofast,
1045 cpl_boolean dolog,
1046 cpl_size * pulines)
1047{
1048
1049 cpl_errorstate prestate;
1050 const double sigma = wfwhm * CPL_MATH_SIG_FWHM;
1051 const cpl_vector * xlines = cpl_bivector_get_x_const(lines);
1052 const double * dxlines = cpl_vector_get_data_const(xlines);
1053 const double * dylines = cpl_bivector_get_y_data_const(lines);
1054 double * plinepix
1055 = linepix ? cpl_vector_get_data(linepix) : NULL;
1056 const int nlines = cpl_vector_get_size(xlines);
1057 const int nself = cpl_vector_get_size(self);
1058 double * dself = cpl_vector_get_data(self);
1059 cpl_polynomial * dispi;
1060 double * profile = NULL;
1061 const cpl_size i0 = 0;
1062 const double p0 = cpl_polynomial_get_coeff(disp, &i0);
1063 double wl;
1064 double xpos = (double)(1-hsize)-xtrunc;
1065 const double xmax = (double)(nself-hsize)+xtrunc;
1066 double xderiv, xextreme;
1067 cpl_error_code error = CPL_ERROR_NONE;
1068 int iline;
1069 cpl_size ulines = 0;
1070
1071 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
1072 cpl_ensure_code(disp != NULL, CPL_ERROR_NULL_INPUT);
1073 cpl_ensure_code(lines != NULL, CPL_ERROR_NULL_INPUT);
1074
1075 cpl_ensure_code(wslit > 0.0, CPL_ERROR_ILLEGAL_INPUT);
1076 cpl_ensure_code(wfwhm > 0.0, CPL_ERROR_ILLEGAL_INPUT);
1077 cpl_ensure_code(hsize >= 0, CPL_ERROR_ILLEGAL_INPUT);
1078 cpl_ensure_code(xtrunc > 0.0, CPL_ERROR_ILLEGAL_INPUT);
1079 cpl_ensure_code(nself > 2 * hsize, CPL_ERROR_ILLEGAL_INPUT);
1080
1081 cpl_ensure_code(cpl_polynomial_get_dimension(disp) == 1,
1082 CPL_ERROR_ILLEGAL_INPUT);
1083 cpl_ensure_code(cpl_polynomial_get_degree(disp) > 0,
1084 CPL_ERROR_ILLEGAL_INPUT);
1085
1086 /* The smallest wavelength contributing to the spectrum. */
1087 wl = cpl_polynomial_eval_1d(disp, xpos, &xderiv);
1088
1089 if (wl <= 0.0) return
1090 cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT, __FILE__,
1091 __LINE__, "Non-positive wavelength at x=%g: "
1092 "P(x)=%g, P'(x)=%g", xpos, wl, xderiv);
1093
1094 if (xderiv <= 0.0) return
1095 cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT, __FILE__,
1096 __LINE__, "Non-increasing dispersion at "
1097 "x=%g: P'(x)=%g, P(x)=%g", xpos, xderiv, wl);
1098
1099 /* Find the 1st line */
1100 iline = cpl_vector_find(xlines, wl);
1101
1102 /* The first line must be at least at wl */
1103 if (dxlines[iline] < wl) iline++;
1104
1105 if (iline >= nlines) return
1106 cpl_error_set_message_macro(cpl_func, CPL_ERROR_DATA_NOT_FOUND, __FILE__,
1107 __LINE__, "The %d-line catalogue has only "
1108 "lines below P(%g)=%g > %g", nlines, xpos,
1109 wl, dxlines[nlines-1]);
1110
1111 memset(dself, 0, nself * sizeof(double));
1112
1113 dispi = cpl_polynomial_duplicate(disp);
1114
1115 /* Verify monotony of dispersion */
1116 cpl_polynomial_derivative(dispi, 0);
1117
1118 prestate = cpl_errorstate_get();
1119
1120 if (cpl_polynomial_solve_1d(dispi, 0.5*(nlines+1), &xextreme, 1)) {
1121 cpl_errorstate_set(prestate);
1122 } else if (xpos < xextreme && xextreme < xmax) {
1123 cpl_polynomial_delete(dispi);
1124 return cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
1125 __FILE__, __LINE__, "Non-monotone "
1126 "dispersion at x=%g: P'(x)=0, "
1127 "P(x)=%g", xextreme,
1128 cpl_polynomial_eval_1d(disp, xextreme,
1129 NULL));
1130 }
1131
1132 if (dofast) {
1133 const int npix = 1+(int)xtrunc;
1134
1135 if (erftmp != NULL && cpl_vector_get_size(erftmp) == npix &&
1136 cpl_vector_get(erftmp, 0) > 0.0) {
1137 profile = cpl_vector_get_data(erftmp);
1138 } else {
1139
1140 const double yval = 0.5 / wslit;
1141 const double x0p = 0.5 * wslit + 0.5;
1142 const double x0n = -0.5 * wslit + 0.5;
1143 double x1diff
1144 = irplib_erf_antideriv(x0p, sigma)
1145 - irplib_erf_antideriv(x0n, sigma);
1146 int ipix;
1147
1148 if (erftmp == NULL) {
1149 profile = (double*)cpl_malloc(sizeof(double)*(size_t)npix);
1150 } else {
1151 cpl_vector_set_size(erftmp, npix);
1152 profile = cpl_vector_get_data(erftmp);
1153 }
1154
1155 profile[0] = 2.0 * yval * x1diff;
1156
1157 for (ipix = 1; ipix < npix; ipix++) {
1158 const double x1 = (double)ipix;
1159 const double x1p = x1 + 0.5 * wslit + 0.5;
1160 const double x1n = x1 - 0.5 * wslit + 0.5;
1161 const double x0diff = x1diff;
1162
1163 x1diff = irplib_erf_antideriv(x1p, sigma)
1164 - irplib_erf_antideriv(x1n, sigma);
1165
1166 profile[ipix] = yval * (x1diff - x0diff);
1167
1168 }
1169 }
1170 }
1171
1172 cpl_polynomial_copy(dispi, disp);
1173
1174 /* FIXME: A custom version of cpl_polynomial_solve_1d() which returns
1175 P'(xpos) can be used for the 1st NR-iteration. */
1176 /* Further, the sign of P'(xpos) could be checked for all lines. */
1177 /* Perform 1st NR-iteration in solving for P(xpos) = dxlines[iline] */
1178 xpos -= (wl - dxlines[iline]) / xderiv;
1179
1180 /* Iterate through the lines */
1181 for (; !error && iline < nlines; iline++) {
1182
1183 /* Lines may have a non-physical intensity (e.g. zero) to indicate some
1184 property of the line, e.g. unknown intensity due to blending */
1185 if (dylines[iline] <= 0.0) continue;
1186
1187 /* Use 1st guess, if available (Use 0.0 to flag unavailable) */
1188 if (plinepix != NULL && plinepix[iline] > 0.0) xpos = plinepix[iline];
1189
1190 if (xpos > xmax) xpos = xmax; /* FIXME: Better to limit xpos ? */
1191
1192 /* Find the (sub-) pixel position of the line */
1193 error = cpl_polynomial_set_coeff(dispi, &i0, p0 - dxlines[iline]) ||
1194 cpl_polynomial_solve_1d(dispi, xpos, &xpos, 1);
1195
1196 if (xpos > xmax) {
1197 if (error) {
1198 error = 0;
1199 cpl_msg_debug(cpl_func, "Stopping spectrum fill at line %d/%d "
1200 "at xpos=%g > xmax=%g",
1201 iline, nlines, xpos, xmax);
1202 cpl_errorstate_dump(prestate, CPL_FALSE,
1204 cpl_errorstate_set(prestate);
1205 }
1206 break;
1207 } else if (error) {
1208 if (linepix != NULL && ulines) (void)cpl_vector_fill(linepix, 0.0);
1209 (void)cpl_error_set_message_macro(cpl_func, cpl_error_get_code(),
1210 __FILE__, __LINE__,
1211 "Could not find pixel-position "
1212 "of line %d/%d at wavelength=%g."
1213 " xpos=%g, xmax=%g",
1214 iline, nlines, dxlines[iline],
1215 xpos, xmax);
1216 break;
1217 } else if (dofast) {
1218 const double frac = fabs(xpos - floor(xpos));
1219#ifdef IRPLIB_WAVECAL_FAST_FAST
1220 const double frac0 = 1.0 - frac; /* Weight opposite of distance */
1221#else
1222 /* Center intensity correctly */
1223 const double ep1pw = irplib_erf_antideriv(frac + 0.5 * wslit, sigma);
1224 const double en1pw = irplib_erf_antideriv(frac + 0.5 * wslit - 1.0,
1225 sigma);
1226 const double ep1nw = irplib_erf_antideriv(frac - 0.5 * wslit, sigma);
1227 const double en1nw = irplib_erf_antideriv(frac - 0.5 * wslit - 1.0,
1228 sigma);
1229 const double frac0
1230 = (en1nw - en1pw) / (ep1pw - en1pw - ep1nw + en1nw);
1231
1232#endif
1233 const double frac1 = 1.0 - frac0;
1234 const double yval0 = frac0 * dylines[iline];
1235 const double yval1 = frac1 * dylines[iline];
1236 const int npix = 1+(int)xtrunc;
1237 int ipix;
1238 int i0n = hsize - 1 + floor(xpos);
1239 int i0p = i0n;
1240 int i1n = i0n + 1;
1241 int i1p = i1n;
1242 cpl_boolean didline = CPL_FALSE;
1243
1244
1245 /* Update 1st guess for next time, if available */
1246 if (plinepix != NULL) plinepix[iline] = xpos;
1247
1248 if (frac0 < 0.0) {
1249 (void)cpl_error_set_message_macro(cpl_func,
1250 CPL_ERROR_UNSPECIFIED,
1251 __FILE__, __LINE__,
1252 "Illegal split at x=%g: %g + "
1253 "%g = 1", xpos, frac0, frac1);
1254#ifdef IRPLIB_WAVEVAL_DEBUG
1255 } else {
1256 cpl_msg_warning(cpl_func,"profile split at x=%g: %g + %g = 1",
1257 xpos, frac0, frac1);
1258#endif
1259 }
1260
1261 for (ipix = 0; ipix < npix; ipix++, i0n--, i0p++, i1n--, i1p++) {
1262
1263 if (i0n >= 0 && i0n < nself) {
1264 dself[i0n] += yval0 * profile[ipix];
1265 didline = CPL_TRUE;
1266 }
1267 if (i1n >= 0 && i1n < nself && ipix + 1 < npix) {
1268 dself[i1n] += yval1 * profile[ipix+1];
1269 didline = CPL_TRUE;
1270 }
1271
1272 if (ipix == 0) continue;
1273
1274 if (i0p >= 0 && i0p < nself) {
1275 dself[i0p] += yval0 * profile[ipix];
1276 didline = CPL_TRUE;
1277 }
1278 if (i1p >= 0 && i1p < nself && ipix + 1 < npix) {
1279 dself[i1p] += yval1 * profile[ipix+1];
1280 didline = CPL_TRUE;
1281 }
1282 }
1283
1284 if (didline) ulines++;
1285
1286 } else {
1287 const double yval = 0.5 * dylines[iline] / wslit;
1288 const int ifirst = IRPLIB_MAX((int)(xpos-xtrunc+0.5), 1-hsize);
1289 const int ilast = IRPLIB_MIN((int)(xpos+xtrunc), nself-hsize);
1290 int ipix;
1291 const double x0 = (double)ifirst - xpos;
1292 const double x0p = x0 + 0.5*wslit - 0.5;
1293 const double x0n = x0 - 0.5*wslit - 0.5;
1294 double x1diff
1295 = irplib_erf_antideriv(x0p, sigma)
1296 - irplib_erf_antideriv(x0n, sigma);
1297
1298 /* Update 1st guess for next time, if available */
1299 if (plinepix != NULL) plinepix[iline] = xpos;
1300
1301 if (ilast >= ifirst) ulines++;
1302
1303 for (ipix = ifirst; ipix <= ilast; ipix++) {
1304 const double x1 = (double)ipix - xpos;
1305 const double x1p = x1 + 0.5*wslit + 0.5;
1306 const double x1n = x1 - 0.5*wslit + 0.5;
1307 const double x0diff = x1diff;
1308
1309 x1diff = irplib_erf_antideriv(x1p, sigma)
1310 - irplib_erf_antideriv(x1n, sigma);
1311
1312 dself[ipix+hsize-1] += yval * (x1diff - x0diff);
1313
1314 }
1315 }
1316 }
1317
1318 cpl_polynomial_delete(dispi);
1319 if (erftmp == NULL) cpl_free(profile);
1320
1321 cpl_ensure_code(!error, cpl_error_get_code());
1322
1323 if (dolog) {
1324 int i;
1325 for (i = 0; i < nself; i++) {
1326 dself[i] = dself[i] > 0.0 ? log(1.0 + dself[i]) : 0.0;
1327 }
1328 }
1329
1330 if (!ulines) return
1331 cpl_error_set_message_macro(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
1332 __FILE__, __LINE__, "The %d-line "
1333 "catalogue has no lines in the range "
1334 "%g -> P(%g)=%g", nlines, wl, xmax,
1335 cpl_polynomial_eval_1d(disp, xmax, NULL));
1336
1337 if (pulines != NULL) *pulines = ulines;
1338
1339 return CPL_ERROR_NONE;
1340}
1341
1342/*----------------------------------------------------------------------------*/
1351/*----------------------------------------------------------------------------*/
1352inline double irplib_erf_antideriv(double x, double sigma)
1353{
1354 return x * erf( x / (sigma * CPL_MATH_SQRT2))
1355 + 2.0 * sigma/CPL_MATH_SQRT2PI * exp(-0.5 * x * x / (sigma * sigma));
1356}
1357
1358
1359#ifdef HAVE_GSL
1360
1361/*----------------------------------------------------------------------------*/
1368/*----------------------------------------------------------------------------*/
1369static double irplib_gsl_correlation(const gsl_vector * self, void * data)
1370{
1371
1372 irplib_multimin * mindata = (irplib_multimin *)data;
1373 cpl_errorstate prestate = cpl_errorstate_get();
1374 int nobs, nmodel, ndiff;
1375 cpl_size i;
1376
1377 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
1378 cpl_ensure(data != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
1379
1380 cpl_ensure(mindata->filler != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
1381 cpl_ensure(mindata->observed != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
1382 cpl_ensure(mindata->spectrum != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
1383
1384 nobs = cpl_vector_get_size(mindata->observed);
1385 nmodel = cpl_vector_get_size(mindata->spectrum);
1386 ndiff = nmodel - nobs;
1387
1388 cpl_ensure((ndiff & 1) == 0, CPL_ERROR_ILLEGAL_INPUT, GSL_NAN);
1389
1390 cpl_ensure(cpl_vector_get_size(mindata->vxc) == 1 + ndiff,
1391 CPL_ERROR_ILLEGAL_INPUT, GSL_NAN);
1392
1393 ndiff /= 2;
1394
1395 for (i=0; i < (cpl_size)self->size; i++) {
1396 const double value = gsl_vector_get(self, (size_t)i);
1397 cpl_polynomial_set_coeff(mindata->disp1d, &i, value);
1398 }
1399
1400 /* Shift reference by -ndiff so filler can be used without offset.
1401 The subsequent polynomial shift is reduced by -ndiff. */
1402 cpl_ensure_code(!cpl_polynomial_shift_1d(mindata->disp1d, 0, -ndiff),
1403 cpl_error_get_code());
1404
1405 if (mindata->filler(mindata->spectrum, mindata->disp1d,
1406 mindata->param)
1407 || !cpl_errorstate_is_equal(prestate)) {
1408
1409 /* The fill failed. Ensure the discarding of this candidate by
1410 setting the cross-correlation to its minimum possible value. */
1411
1412 (void)cpl_vector_fill(mindata->vxc, -1.0);
1413
1414 mindata->maxxc = ndiff;
1415
1416 if (!cpl_errorstate_is_equal(prestate)) {
1417 cpl_msg_debug(cpl_func, "Spectrum fill failed:");
1418 cpl_errorstate_dump(prestate, CPL_FALSE,
1420 cpl_errorstate_set(prestate);
1421 }
1422 } else {
1423
1424 mindata->maxxc = cpl_vector_correlate(mindata->vxc,
1425 mindata->spectrum,
1426 mindata->observed);
1427 }
1428
1429#ifdef IRPLIB_SPC_DUMP
1430 /* Need irplib_wavecal.c rev. 1.12 through 1.15 */
1431 irplib_polynomial_dump_corr_step(mindata->disp1d, mindata->vxc,
1432 "Optimize");
1433#endif
1434
1435 mindata->xc = cpl_vector_get(mindata->vxc, ndiff);
1436
1437 if (mindata->maxxc != ndiff &&
1438 cpl_vector_get(mindata->vxc, mindata->maxxc) > mindata->mxc) {
1439 const irplib_base_spectrum_model * arclamp
1440 = (const irplib_base_spectrum_model *)mindata->param;
1441
1442 if (mindata->mdisp == NULL) {
1443 mindata->mdisp = cpl_polynomial_duplicate(mindata->disp1d);
1444 } else {
1445 cpl_polynomial_copy(mindata->mdisp, mindata->disp1d);
1446 }
1447 mindata->mxc = cpl_vector_get(mindata->vxc, mindata->maxxc);
1448 mindata->ishift = mindata->maxxc; /* Offset -ndiff pre-shifted above */
1449 cpl_msg_debug(cpl_func, "Local maximum: %g(%d) > %g(%d) (cost=%u:%u. "
1450 "lines=%u)", mindata->mxc, mindata->maxxc, mindata->xc,
1451 ndiff, (unsigned)arclamp->cost, (unsigned)arclamp->xcost,
1452 (unsigned)arclamp->ulines);
1453 }
1454
1455 return -mindata->xc;
1456}
1457
1458#endif
1459
1460/*----------------------------------------------------------------------------*/
1483/*----------------------------------------------------------------------------*/
1484cpl_error_code
1486 int maxdeg,
1487 const cpl_vector * obs,
1488 int nmaxima,
1489 int linelim,
1490 irplib_base_spectrum_model* model,
1491 cpl_error_code (* filler)
1492 (cpl_vector *,
1493 const cpl_polynomial *,
1494 irplib_base_spectrum_model *),
1495 double pixtol,
1496 double pixstep,
1497 int hsize,
1498 int maxite,
1499 int maxfail,
1500 int maxcont,
1501 cpl_boolean doplot,
1502 double * pxc)
1503{
1504
1505#ifdef HAVE_GSL
1506
1507 cpl_errorstate prestate = cpl_errorstate_get();
1508 cpl_polynomial * start;
1509 cpl_polynomial * cand;
1510 cpl_polynomial * backup;
1511 cpl_error_code error = CPL_ERROR_NONE;
1512 double xc;
1513 cpl_bivector * xtshift = cpl_bivector_new(nmaxima ? nmaxima : 1);
1514 const cpl_vector * xtshiftx = cpl_bivector_get_x_const(xtshift);
1515 const cpl_vector * xtshifty = cpl_bivector_get_y_const(xtshift);
1516 int nshift;
1517 int imaximum = -1;
1518 int imaxima;
1519
1520#endif
1521
1522 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
1523 cpl_ensure_code(obs != NULL, CPL_ERROR_NULL_INPUT);
1524 cpl_ensure_code(model != NULL, CPL_ERROR_NULL_INPUT);
1525 cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
1526 cpl_ensure_code(pxc != NULL, CPL_ERROR_NULL_INPUT);
1527
1528 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
1529 CPL_ERROR_ILLEGAL_INPUT);
1530
1531 cpl_ensure_code(cpl_polynomial_get_degree(self) > 0,
1532 CPL_ERROR_ILLEGAL_INPUT);
1533
1534 cpl_ensure_code(maxdeg >= 0, CPL_ERROR_ILLEGAL_INPUT);
1535 cpl_ensure_code(pixtol > 0.0, CPL_ERROR_ILLEGAL_INPUT);
1536 cpl_ensure_code(pixstep > 0.0, CPL_ERROR_ILLEGAL_INPUT);
1537 cpl_ensure_code(hsize >= 0, CPL_ERROR_ILLEGAL_INPUT);
1538 cpl_ensure_code(maxite >= 0, CPL_ERROR_ILLEGAL_INPUT);
1539 cpl_ensure_code(nmaxima >= 0, CPL_ERROR_ILLEGAL_INPUT);
1540 cpl_ensure_code(maxfail > 0, CPL_ERROR_ILLEGAL_INPUT);
1541 cpl_ensure_code(maxcont > 0, CPL_ERROR_ILLEGAL_INPUT);
1542 cpl_ensure_code(linelim >= 0, CPL_ERROR_ILLEGAL_INPUT);
1543
1544#ifndef HAVE_GSL
1545 /* Avoid unused variable warning */
1546 cpl_ensure_code(doplot == CPL_TRUE || doplot == CPL_FALSE,
1547 CPL_ERROR_ILLEGAL_INPUT);
1548 return cpl_error_set_message(cpl_func, CPL_ERROR_UNSUPPORTED_MODE,
1549 "GSL is not available");
1550#else
1551
1552 if (irplib_bivector_find_shift_from_correlation(xtshift, self, obs,
1553 model, filler,
1554 hsize, doplot, &xc)) {
1555 cpl_bivector_delete(xtshift);
1556 return cpl_error_set_where(cpl_func);
1557 }
1558
1559 if (model->ulines > (cpl_size)linelim) {
1560 /* The initial, optimal (integer) shift */
1561 const double xxc = cpl_vector_get(xtshiftx, 0);
1562 const double xc0 = cpl_vector_get(xtshifty, 0);
1563
1564 cpl_msg_warning(cpl_func, "Doing only shift=%g pixels with lines=%u > "
1565 "%d and XC=%g", xxc, (unsigned)model->ulines, linelim,
1566 xc0);
1567
1568 cpl_polynomial_shift_1d(self, 0, xxc);
1569
1570 *pxc = xc0;
1571
1572 cpl_bivector_delete(xtshift);
1573
1574 return CPL_ERROR_NONE;
1575 }
1576
1577 start = cpl_polynomial_duplicate(self);
1578 cand = cpl_polynomial_new(1);
1579 backup = cpl_polynomial_new(1);
1580
1581 /* Number of (local) maxima to use as starting point of the optimization */
1582 nshift = cpl_bivector_get_size(xtshift);
1583 if (nmaxima == 0 || nmaxima > nshift) nmaxima = nshift;
1584
1585 cpl_msg_info(cpl_func, "Optimizing %d/%d local shift-maxima "
1586 "(no-shift xc=%g. linelim=%d)", nmaxima, nshift, xc, linelim);
1587 if (cpl_msg_get_level() <= CPL_MSG_DEBUG)
1588 cpl_bivector_dump(xtshift, stdout);
1589
1590 for (imaxima = 0; imaxima < nmaxima; imaxima++) {
1591 /* The initial, optimal (integer) shift */
1592 const double xxc = cpl_vector_get(xtshiftx, imaxima);
1593 double xtpixstep = pixstep;
1594 double xtpixtol = pixtol;
1595 double xtxc;
1596 cpl_boolean ok = CPL_FALSE;
1597 int nfail;
1598
1599
1600 cpl_polynomial_copy(cand, start);
1601 cpl_polynomial_shift_1d(cand, 0, xxc);
1602 cpl_polynomial_copy(backup, cand);
1603
1604 /* Increase tolerance until convergence */
1605 for (nfail = 0; nfail < maxfail; nfail++, xtpixtol *= 2.0,
1606 xtpixstep *= 2.0) {
1607 int restart = maxcont;
1608 cpl_boolean redo;
1609
1610 do {
1611 if (error) {
1612 cpl_errorstate_dump(prestate, CPL_FALSE,
1614 cpl_errorstate_set(prestate);
1615 }
1616 error = irplib_polynomial_find_1d_from_correlation_
1617 (cand, maxdeg, obs, model,
1618 filler, xtpixtol, xtpixstep, 2,
1619 maxite, &xtxc, &redo);
1620 if (redo && !error) error = CPL_ERROR_CONTINUE;
1621 } while (((!error && redo) || error == CPL_ERROR_CONTINUE)
1622 && --restart);
1623
1624 if (!error && !redo) {
1625 cpl_msg_debug(cpl_func, "XC(imax=%d/%d:xtpixtol=%g): %g "
1626 "(cost=%u:%u)", 1+imaxima, nmaxima, xtpixtol,
1627 xtxc, (unsigned)model->cost,
1628 (unsigned)model->xcost);
1629 break;
1630 }
1631 cpl_msg_warning(cpl_func, "Increasing xtpixtol from %g (%g, imax="
1632 "%d/%d)", xtpixtol, xtpixstep, 1+imaxima, nmaxima);
1633 if (model->ulines > (cpl_size)linelim) {
1634 cpl_msg_warning(cpl_func, "Stopping search-refinement via "
1635 "catalogue with %u lines > %d",
1636 (unsigned)model->ulines, linelim);
1637 break;
1638 }
1639 cpl_polynomial_copy(cand, start);
1640 }
1641
1642 /* Decrease tolerance until divergence, keep previous */
1643 for (; !error && xtpixtol > 0.0; xtpixtol *= 0.25, xtpixstep *= 0.5) {
1644 int restart = maxcont;
1645 cpl_boolean redo;
1646
1647 cpl_polynomial_copy(backup, cand);
1648 do {
1649 if (error) {
1650 cpl_errorstate_dump(prestate, CPL_FALSE,
1652 cpl_errorstate_set(prestate);
1653 }
1654 error = irplib_polynomial_find_1d_from_correlation_
1655 (cand, maxdeg, obs, model, filler,
1656 xtpixtol, xtpixstep, 2, maxite, &xtxc, &redo);
1657 if (redo && !error) error = CPL_ERROR_CONTINUE;
1658 } while (((!error && redo) || error == CPL_ERROR_CONTINUE)
1659 && --restart);
1660 if (error) break;
1661 ok = CPL_TRUE;
1662 if (redo) break;
1663 cpl_msg_debug(cpl_func, "XC(imax=%d/%d:xtpixtol=%g): %g (cost=%u:%u"
1664 ". ulines=%u)", 1+imaxima, nmaxima, xtpixtol, xtxc,
1665 (unsigned)model->cost, (unsigned)model->xcost,
1666 (unsigned)model->ulines);
1667 if (model->ulines > (cpl_size)linelim) {
1668 cpl_msg_info(cpl_func, "Stopping search-refinement via "
1669 "catalogue with %u lines > %u",
1670 (unsigned)model->ulines, linelim);
1671 break;
1672 }
1673 }
1674
1675 if (error) {
1676 error = 0;
1677 cpl_errorstate_dump(prestate, CPL_FALSE,
1679 cpl_errorstate_set(prestate);
1680 cpl_polynomial_copy(cand, backup);
1681 }
1682 if (ok && xtxc > xc) {
1683 imaximum = imaxima;
1684 cpl_polynomial_copy(self, cand);
1685 xc = xtxc;
1686
1687 cpl_msg_info(cpl_func, "XC(imax=%d/%d): %g -> %g (initial-shift=%g. "
1688 "cost=%u:%u. lines=%u)", 1+imaxima, nmaxima,
1689 cpl_vector_get(xtshifty, imaxima), xtxc,
1690 cpl_vector_get(xtshiftx, imaxima),
1691 (unsigned)model->cost, (unsigned)model->xcost,
1692 (unsigned)model->ulines);
1693 } else {
1694 cpl_msg_info(cpl_func, "xc(imax=%d/%d): %g -> %g (initial-shift=%g. "
1695 "cost=%u:%u. lines=%u)", 1+imaxima, nmaxima,
1696 cpl_vector_get(xtshifty, imaxima), xtxc,
1697 cpl_vector_get(xtshiftx, imaxima),
1698 (unsigned)model->cost, (unsigned)model->xcost,
1699 (unsigned)model->ulines);
1700 }
1701 }
1702
1703 cpl_polynomial_delete(start);
1704 cpl_polynomial_delete(backup);
1705 cpl_polynomial_delete(cand);
1706
1707 if (imaximum < 0) {
1708 /* The initial, optimal (integer) shift */
1709 const double xxc = cpl_vector_get(xtshiftx, 0);
1710 const double xc0 = cpl_vector_get(xtshifty, 0);
1711
1712 error = cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
1713 "Could not improve XC=%g over %d "
1714 "local shift-maxima, best at shift %g",
1715 xc0, nmaxima, xxc);
1716 } else {
1717 cpl_msg_info(cpl_func, "Maximal XC=%g (up from %g, with initial pixel-"
1718 "shift of %g) at %d/%d local shift-maximi", xc,
1719 cpl_vector_get(xtshifty, imaximum),
1720 cpl_vector_get(xtshiftx, imaximum),
1721 1+imaximum, nmaxima);
1722
1723 if (doplot) {
1724 irplib_plot_spectrum_and_model(obs, self, model, filler);
1725 }
1726
1727 *pxc = xc;
1728 }
1729
1730 cpl_bivector_delete(xtshift);
1731
1732 return error;
1733
1734#endif
1735
1736}
void irplib_errorstate_dump_debug(unsigned self, unsigned first, unsigned last)
Dump a single CPL error at the CPL debug level.
Definition: irplib_utils.c:158
int irplib_bivector_count_positive(const cpl_bivector *self, double x_min, double x_max)
Count the positive Y-entries in a given X-range.
cpl_error_code irplib_vector_fill_line_spectrum(cpl_vector *self, const cpl_polynomial *disp, irplib_base_spectrum_model *lsslamp)
Generate a 1D spectrum from a model and a dispersion relation.
cpl_error_code irplib_bivector_find_shift_from_correlation(cpl_bivector *self, const cpl_polynomial *disp, const cpl_vector *obs, irplib_base_spectrum_model *model, cpl_error_code(*filler)(cpl_vector *, const cpl_polynomial *, irplib_base_spectrum_model *), int hsize, cpl_boolean doplot, double *pxc)
Find shift(s) that maximizes (locally) the cross-correlation.
double irplib_erf_antideriv(double x, double sigma)
The antiderivative of erx(x/sigma/sqrt(2)) with respect to x.
cpl_error_code irplib_polynomial_fit_2d_dispersion(cpl_polynomial *self, const cpl_image *imgwave, int fitdeg, double *presid)
Fit a 2D-dispersion from an image of wavelengths.
cpl_error_code irplib_vector_fill_line_spectrum_fast(cpl_vector *self, const cpl_polynomial *disp, irplib_base_spectrum_model *lsslamp)
Generate a 1D spectrum from a model and a dispersion relation.
cpl_error_code irplib_vector_fill_logline_spectrum_fast(cpl_vector *self, const cpl_polynomial *disp, irplib_base_spectrum_model *lsslamp)
Generate a 1D spectrum from a model and a dispersion relation.
cpl_error_code irplib_plot_spectrum_and_model(const cpl_vector *self, const cpl_polynomial *disp1d, irplib_base_spectrum_model *model, cpl_error_code(*filler)(cpl_vector *, const cpl_polynomial *, irplib_base_spectrum_model *))
Plot a 1D spectrum and one from a model.
cpl_error_code irplib_polynomial_find_1d_from_correlation_all(cpl_polynomial *self, int maxdeg, const cpl_vector *obs, int nmaxima, int linelim, irplib_base_spectrum_model *model, cpl_error_code(*filler)(cpl_vector *, const cpl_polynomial *, irplib_base_spectrum_model *), double pixtol, double pixstep, int hsize, int maxite, int maxfail, int maxcont, cpl_boolean doplot, double *pxc)
Modify self by maximizing the cross-correlation across all maxima.
cpl_error_code irplib_vector_fill_line_spectrum_model(cpl_vector *self, cpl_vector *linepix, cpl_vector *erftmp, const cpl_polynomial *disp, const cpl_bivector *lines, double wslit, double wfwhm, double xtrunc, int hsize, cpl_boolean dofast, cpl_boolean dolog, cpl_size *pulines)
Generate a 1D spectrum from (arc) lines and a dispersion relation.
cpl_error_code irplib_polynomial_find_1d_from_correlation(cpl_polynomial *self, int maxdeg, const cpl_vector *obs, irplib_base_spectrum_model *model, cpl_error_code(*filler)(cpl_vector *, const cpl_polynomial *, irplib_base_spectrum_model *), double pixtol, double pixstep, int hsize, int maxite, double *pxc)
Modify self by maximizing the cross-correlation.
cpl_error_code irplib_vector_fill_logline_spectrum(cpl_vector *self, const cpl_polynomial *disp, irplib_base_spectrum_model *lsslamp)
Generate a 1D spectrum from a model and a dispersion relation.
cpl_error_code irplib_polynomial_shift_1d_from_correlation(cpl_polynomial *self, const cpl_vector *obs, irplib_base_spectrum_model *model, cpl_error_code(*filler)(cpl_vector *, const cpl_polynomial *, irplib_base_spectrum_model *), int hsize, cpl_boolean doplot, double *pxc)
Shift self by the amount that maximizes the cross-correlation.