28#include "irplib_wavecal_impl.h"
31#include "irplib_utils.h"
37#include <gsl/gsl_multimin.h>
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 *);
58 cpl_polynomial * mdisp;
73#define IRPLIB_MAX(A,B) ((A) > (B) ? (A) : (B))
74#define IRPLIB_MIN(A,B) ((A) < (B) ? (A) : (B))
81static double irplib_gsl_correlation(
const gsl_vector *,
void *);
85irplib_polynomial_find_1d_from_correlation_(cpl_polynomial *,
int,
87 irplib_base_spectrum_model *,
90 const cpl_polynomial *,
91 irplib_base_spectrum_model *),
92 double,
double,
int,
int,
93 double *, cpl_boolean *);
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);
125 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, -1);
126 cpl_ensure(x_min <= x_max, CPL_ERROR_ILLEGAL_INPUT, -2);
129 while (i < nself && px[i] < x_min) i++;
130 while (i < nself && px[i] < x_max)
131 if (py[i++] > 0) npos++;
148 const cpl_image * imgwave,
149 int fitdeg,
double * presid)
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;
161 const cpl_size nfitdeg = (cpl_size)fitdeg;
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);
170 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 2,
171 CPL_ERROR_ILLEGAL_INPUT);
173 xy_pos = cpl_matrix_new(2, nsamp);
174 xdata = cpl_matrix_get_data(xy_pos);
175 ydata = xdata + nsamp;
177 dwlen = (
double*)cpl_malloc(nsamp *
sizeof(
double));
178 wlen = cpl_vector_wrap(nsamp, dwlen);
180 for (i=1; i <= nx; i++) {
181 for (j=1; j <= ny; j++) {
183 const double value = cpl_image_get(imgwave, i, j, &is_bad);
193 cpl_msg_info(cpl_func,
"Fitting 2D polynomial to %d X %d image, ignoring "
194 "%d poorly calibrated pixels", nx, ny, nbad);
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,
200 *presid = cpl_vector_product(wlen, wlen)/nsamp;
202 cpl_matrix_delete(xy_pos);
203 cpl_vector_delete(wlen);
205 cpl_ensure_code(k == nsamp, CPL_ERROR_UNSPECIFIED);
207 return CPL_ERROR_NONE;
233 const cpl_vector * obs,
234 irplib_base_spectrum_model * model,
235 cpl_error_code (* filler)
237 const cpl_polynomial *,
238 irplib_base_spectrum_model *),
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,
250 return error ? cpl_error_set_where(cpl_func) :
251 (restart ? cpl_error_set(cpl_func, CPL_ERROR_CONTINUE)
278irplib_polynomial_find_1d_from_correlation_(cpl_polynomial * self,
280 const cpl_vector * obs,
281 irplib_base_spectrum_model * model,
282 cpl_error_code (* filler)
284 const cpl_polynomial *,
285 irplib_base_spectrum_model *),
291 cpl_boolean * prestart)
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();
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;
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);
324 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
325 CPL_ERROR_ILLEGAL_INPUT);
327 cpl_ensure_code(cpl_polynomial_get_degree(self) > 0,
328 CPL_ERROR_ILLEGAL_INPUT);
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);
337 return cpl_error_set_message(cpl_func, CPL_ERROR_UNSUPPORTED_MODE,
338 "GSL is not available");
341 minimizer = gsl_multimin_fminimizer_alloc(T, (
size_t)nfit);
343 cpl_ensure_code(minimizer != NULL, CPL_ERROR_ILLEGAL_OUTPUT);
345 dispgsl = gsl_vector_alloc((
size_t)nfit);
346 stepsize = gsl_vector_alloc((
size_t)nfit);
347 dispprev = gsl_vector_alloc((
size_t)nfit);
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;
357 my_func.f = &irplib_gsl_correlation;
358 my_func.params = (
void *)(&data);
362 data.spectrum = cpl_vector_new(nobs + 2 * hsize);
363 data.vxc = cpl_vector_new(1 + 2 * hsize);
366 data.filler = filler;
372 gsl_multimin_fminimizer_set (minimizer, &my_func, dispgsl, stepsize);
374 for (iter = 0; status == GSL_CONTINUE && iter < maxite; iter++) {
377 const double fprev = minimizer->fval;
379 gsl_vector_memcpy(dispprev, minimizer->x);
380 status = gsl_multimin_fminimizer_iterate(minimizer);
382 if (status || !cpl_errorstate_is_equal(prestate))
break;
384 size = gsl_multimin_fminimizer_size (minimizer);
385 status = gsl_multimin_test_size (size, pixtol);
387 if (status == GSL_SUCCESS) {
388 cpl_msg_debug(cpl_func,
"converged to minimum at");
391 cpl_msg_debug(cpl_func,
"%5d %g df() = %g size = %g",
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",
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);
405 cpl_msg_debug(cpl_func,
"%5d %g %g %g df() = %g size = %g",
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);
418 if (status == GSL_SUCCESS && cpl_errorstate_is_equal(prestate)) {
419 if (data.mxc > -minimizer->fval) {
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;
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);
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);
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());
447 return CPL_ERROR_NONE;
483 const cpl_polynomial * disp,
484 irplib_base_spectrum_model * lsslamp)
487 irplib_line_spectrum_model * arclamp
488 = (irplib_line_spectrum_model *)lsslamp;
489 cpl_error_code error;
491 cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
503 0, CPL_FALSE, CPL_FALSE,
505 cpl_ensure_code(!error, error);
509 return CPL_ERROR_NONE;
528 const cpl_polynomial * disp,
529 irplib_base_spectrum_model * lsslamp)
532 irplib_line_spectrum_model * arclamp
533 = (irplib_line_spectrum_model *)lsslamp;
534 cpl_error_code error;
536 cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
548 0, CPL_FALSE, CPL_TRUE,
550 cpl_ensure_code(!error, error);
554 return CPL_ERROR_NONE;
574 const cpl_polynomial * disp,
575 irplib_base_spectrum_model * lsslamp)
578 irplib_line_spectrum_model * arclamp
579 = (irplib_line_spectrum_model *)lsslamp;
580 cpl_error_code error;
582 cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
594 0, CPL_TRUE, CPL_FALSE,
596 cpl_ensure_code(!error, error);
600 return CPL_ERROR_NONE;
619 const cpl_polynomial * disp,
620 irplib_base_spectrum_model * lsslamp)
623 irplib_line_spectrum_model * arclamp
624 = (irplib_line_spectrum_model *)lsslamp;
625 cpl_error_code error;
627 cpl_ensure_code(arclamp != NULL, CPL_ERROR_NULL_INPUT);
639 0, CPL_TRUE, CPL_TRUE,
641 cpl_ensure_code(!error, error);
645 return CPL_ERROR_NONE;
661 const cpl_polynomial * disp1d,
662 irplib_base_spectrum_model * model,
663 cpl_error_code (* filler)
665 const cpl_polynomial *,
666 irplib_base_spectrum_model *))
669 cpl_errorstate prestate = cpl_errorstate_get();
671 cpl_vector * spectrum;
673 const int len = cpl_vector_get_size(self);
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);
683 cpl_ensure_code(cpl_polynomial_get_dimension(disp1d) == 1,
684 CPL_ERROR_ILLEGAL_INPUT);
686 cpl_ensure_code(cpl_polynomial_get_degree(disp1d) > 0,
687 CPL_ERROR_ILLEGAL_INPUT);
689 wl = cpl_vector_new(len);
690 spectrum = cpl_vector_new(len);
691 vxc = cpl_vector_new(1);
693 error |= (int)cpl_vector_fill_polynomial(wl, disp1d, 1.0, 1.0);
694 error |= filler(spectrum, disp1d, model);
696 ixc = cpl_vector_correlate(vxc, self, spectrum);
697 xc = cpl_vector_get(vxc, ixc);
699 maxval = cpl_vector_get_max(spectrum);
701 error |= cpl_vector_multiply_scalar(spectrum,
702 cpl_vector_get_max(self)/maxval);
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);
711 (void)cpl_plot_vectors(pre, title,
"", spair, 3);
716 cpl_vector_delete(wl);
717 cpl_vector_delete(spectrum);
718 cpl_vector_delete(vxc);
720 cpl_errorstate_set(prestate);
722 return CPL_ERROR_NONE;
748 const cpl_polynomial * disp,
749 const cpl_vector * obs,
750 irplib_base_spectrum_model * model,
751 cpl_error_code (*filler)
753 const cpl_polynomial *,
754 irplib_base_spectrum_model *),
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;
767 cpl_error_code error = CPL_ERROR_NONE;
768 double xcprev, xcnext;
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);
779 shdisp = cpl_polynomial_duplicate(disp);
782 if (cpl_polynomial_shift_1d(shdisp, 0, -hsize)) {
783 cpl_polynomial_delete(shdisp);
784 return cpl_error_set_where(cpl_func);
787 mspec1d = cpl_vector_new(nmodel);
789 if (filler(mspec1d, shdisp, model)) {
790 cpl_vector_delete(mspec1d);
791 return cpl_error_set_where(cpl_func);
795 xcorr = cpl_vector_new(1 + 2 * hsize);
796 ixc = cpl_vector_correlate(xcorr, mspec1d, obs);
798#ifdef IRPLIB_SPC_DUMP
800 irplib_polynomial_dump_corr_step(shdisp, xcorr,
"Shift");
803 cpl_vector_delete(mspec1d);
804 cpl_polynomial_delete(shdisp);
809 xcprev = cpl_vector_get(xcorr, i);
810 xcnext = cpl_vector_get(xcorr, i+1);
812 if (xcprev >= xcnext) {
818 cpl_vector_set(xself, 0, i - hsize);
819 cpl_vector_set(yself, 0, xcprev);
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) {
832 if (cpl_bivector_get_size(self) < imax) {
833 cpl_vector_set_size(xself, imax);
834 cpl_vector_set_size(yself, imax);
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));
842 cpl_vector_set(xself, j, i - hsize);
843 cpl_vector_set(yself, j, xc);
850 if (xcnext >= xcprev) {
858 if (cpl_bivector_get_size(self) < imax) {
859 cpl_vector_set_size(xself, imax);
860 cpl_vector_set_size(yself, imax);
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));
868 cpl_vector_set(xself, j, i - hsize);
869 cpl_vector_set(yself, j, xcnext);
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),
883 for (i = 0; i < 1 + 2 * hsize; i++, x += 1.0) {
884 cpl_vector_set(xvals, i, x);
887 cpl_plot_bivector(
"set grid;set xlabel 'Offset [pixel]';", title,
889 cpl_bivector_unwrap_vectors(bcorr);
890 cpl_vector_delete(xvals);
894 if (pxc != NULL) *pxc = cpl_vector_get(xcorr, hsize);
896 cpl_vector_delete(xcorr);
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);
906 return cpl_error_set(cpl_func, error);
925 const cpl_vector * obs,
926 irplib_base_spectrum_model * model,
927 cpl_error_code (*filler)
929 const cpl_polynomial *,
930 irplib_base_spectrum_model *),
936 const int nobs = cpl_vector_get_size(obs);
937 const int nmodel = 2 * hsize + nobs;
938 cpl_vector * mspec1d;
940 cpl_error_code error;
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);
951 cpl_ensure_code(!cpl_polynomial_shift_1d(self, 0, -hsize),
952 cpl_error_get_code());
954 mspec1d = cpl_vector_new(nmodel);
956 if (filler(mspec1d, self, model)) {
957 cpl_vector_delete(mspec1d);
958 return cpl_error_set_where(cpl_func);
962 xcorr = cpl_vector_new(1 + 2 * hsize);
963 ixc = cpl_vector_correlate(xcorr, mspec1d, obs);
965#ifdef IRPLIB_SPC_DUMP
967 irplib_polynomial_dump_corr_step(self, xcorr,
"Shift");
970 cpl_vector_delete(mspec1d);
972 error = cpl_polynomial_shift_1d(self, 0, (
double)ixc);
974 xc = cpl_vector_get(xcorr, ixc);
978 cpl_msg_info(cpl_func,
"Shifting %d pixels (%g < %g)", xxc,
979 cpl_vector_get(xcorr, hsize), xc);
982 cpl_vector * xvals = cpl_vector_new(1 + 2 * hsize);
983 cpl_bivector * bcorr = cpl_bivector_wrap_vectors(xvals, xcorr);
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);
990 for (i = 0; i < 1 + 2 * hsize; i++, x += 1.0) {
991 cpl_vector_set(xvals, i, x);
994 cpl_plot_bivector(
"set grid;set xlabel 'Offset [pixel]';", title,
996 cpl_bivector_unwrap_vectors(bcorr);
997 cpl_vector_delete(xvals);
1001 cpl_vector_delete(xcorr);
1003 cpl_ensure_code(!error, error);
1005 if (pxc != NULL) *pxc = xc;
1007 return CPL_ERROR_NONE;
1036 cpl_vector * linepix,
1037 cpl_vector * erftmp,
1038 const cpl_polynomial * disp,
1039 const cpl_bivector * lines,
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);
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);
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;
1069 cpl_size ulines = 0;
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);
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);
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);
1087 wl = cpl_polynomial_eval_1d(disp, xpos, &xderiv);
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);
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);
1100 iline = cpl_vector_find(xlines, wl);
1103 if (dxlines[iline] < wl) iline++;
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]);
1111 memset(dself, 0, nself *
sizeof(
double));
1113 dispi = cpl_polynomial_duplicate(disp);
1116 cpl_polynomial_derivative(dispi, 0);
1118 prestate = cpl_errorstate_get();
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,
1133 const int npix = 1+(int)xtrunc;
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);
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;
1148 if (erftmp == NULL) {
1149 profile = (
double*)cpl_malloc(
sizeof(
double)*(size_t)npix);
1151 cpl_vector_set_size(erftmp, npix);
1152 profile = cpl_vector_get_data(erftmp);
1155 profile[0] = 2.0 * yval * x1diff;
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;
1166 profile[ipix] = yval * (x1diff - x0diff);
1172 cpl_polynomial_copy(dispi, disp);
1178 xpos -= (wl - dxlines[iline]) / xderiv;
1181 for (; !error && iline < nlines; iline++) {
1185 if (dylines[iline] <= 0.0)
continue;
1188 if (plinepix != NULL && plinepix[iline] > 0.0) xpos = plinepix[iline];
1190 if (xpos > xmax) xpos = xmax;
1193 error = cpl_polynomial_set_coeff(dispi, &i0, p0 - dxlines[iline]) ||
1194 cpl_polynomial_solve_1d(dispi, xpos, &xpos, 1);
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);
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(),
1211 "Could not find pixel-position "
1212 "of line %d/%d at wavelength=%g."
1213 " xpos=%g, xmax=%g",
1214 iline, nlines, dxlines[iline],
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;
1230 = (en1nw - en1pw) / (ep1pw - en1pw - ep1nw + en1nw);
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;
1238 int i0n = hsize - 1 + floor(xpos);
1242 cpl_boolean didline = CPL_FALSE;
1246 if (plinepix != NULL) plinepix[iline] = xpos;
1249 (void)cpl_error_set_message_macro(cpl_func,
1250 CPL_ERROR_UNSPECIFIED,
1252 "Illegal split at x=%g: %g + "
1253 "%g = 1", xpos, frac0, frac1);
1254#ifdef IRPLIB_WAVEVAL_DEBUG
1256 cpl_msg_warning(cpl_func,
"profile split at x=%g: %g + %g = 1",
1257 xpos, frac0, frac1);
1261 for (ipix = 0; ipix < npix; ipix++, i0n--, i0p++, i1n--, i1p++) {
1263 if (i0n >= 0 && i0n < nself) {
1264 dself[i0n] += yval0 * profile[ipix];
1267 if (i1n >= 0 && i1n < nself && ipix + 1 < npix) {
1268 dself[i1n] += yval1 * profile[ipix+1];
1272 if (ipix == 0)
continue;
1274 if (i0p >= 0 && i0p < nself) {
1275 dself[i0p] += yval0 * profile[ipix];
1278 if (i1p >= 0 && i1p < nself && ipix + 1 < npix) {
1279 dself[i1p] += yval1 * profile[ipix+1];
1284 if (didline) ulines++;
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);
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;
1299 if (plinepix != NULL) plinepix[iline] = xpos;
1301 if (ilast >= ifirst) ulines++;
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;
1312 dself[ipix+hsize-1] += yval * (x1diff - x0diff);
1318 cpl_polynomial_delete(dispi);
1319 if (erftmp == NULL) cpl_free(profile);
1321 cpl_ensure_code(!error, cpl_error_get_code());
1325 for (i = 0; i < nself; i++) {
1326 dself[i] = dself[i] > 0.0 ? log(1.0 + dself[i]) : 0.0;
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));
1337 if (pulines != NULL) *pulines = ulines;
1339 return CPL_ERROR_NONE;
1354 return x * erf( x / (sigma * CPL_MATH_SQRT2))
1355 + 2.0 * sigma/CPL_MATH_SQRT2PI * exp(-0.5 * x * x / (sigma * sigma));
1369static double irplib_gsl_correlation(
const gsl_vector * self,
void * data)
1372 irplib_multimin * mindata = (irplib_multimin *)data;
1373 cpl_errorstate prestate = cpl_errorstate_get();
1374 int nobs, nmodel, ndiff;
1377 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
1378 cpl_ensure(data != NULL, CPL_ERROR_NULL_INPUT, GSL_NAN);
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);
1384 nobs = cpl_vector_get_size(mindata->observed);
1385 nmodel = cpl_vector_get_size(mindata->spectrum);
1386 ndiff = nmodel - nobs;
1388 cpl_ensure((ndiff & 1) == 0, CPL_ERROR_ILLEGAL_INPUT, GSL_NAN);
1390 cpl_ensure(cpl_vector_get_size(mindata->vxc) == 1 + ndiff,
1391 CPL_ERROR_ILLEGAL_INPUT, GSL_NAN);
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);
1402 cpl_ensure_code(!cpl_polynomial_shift_1d(mindata->disp1d, 0, -ndiff),
1403 cpl_error_get_code());
1405 if (mindata->filler(mindata->spectrum, mindata->disp1d,
1407 || !cpl_errorstate_is_equal(prestate)) {
1412 (void)cpl_vector_fill(mindata->vxc, -1.0);
1414 mindata->maxxc = ndiff;
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);
1424 mindata->maxxc = cpl_vector_correlate(mindata->vxc,
1429#ifdef IRPLIB_SPC_DUMP
1431 irplib_polynomial_dump_corr_step(mindata->disp1d, mindata->vxc,
1435 mindata->xc = cpl_vector_get(mindata->vxc, ndiff);
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;
1442 if (mindata->mdisp == NULL) {
1443 mindata->mdisp = cpl_polynomial_duplicate(mindata->disp1d);
1445 cpl_polynomial_copy(mindata->mdisp, mindata->disp1d);
1447 mindata->mxc = cpl_vector_get(mindata->vxc, mindata->maxxc);
1448 mindata->ishift = mindata->maxxc;
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);
1455 return -mindata->xc;
1487 const cpl_vector * obs,
1490 irplib_base_spectrum_model* model,
1491 cpl_error_code (* filler)
1493 const cpl_polynomial *,
1494 irplib_base_spectrum_model *),
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;
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);
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);
1528 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
1529 CPL_ERROR_ILLEGAL_INPUT);
1531 cpl_ensure_code(cpl_polynomial_get_degree(self) > 0,
1532 CPL_ERROR_ILLEGAL_INPUT);
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);
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");
1554 hsize, doplot, &xc)) {
1555 cpl_bivector_delete(xtshift);
1556 return cpl_error_set_where(cpl_func);
1559 if (model->ulines > (cpl_size)linelim) {
1561 const double xxc = cpl_vector_get(xtshiftx, 0);
1562 const double xc0 = cpl_vector_get(xtshifty, 0);
1564 cpl_msg_warning(cpl_func,
"Doing only shift=%g pixels with lines=%u > "
1565 "%d and XC=%g", xxc, (
unsigned)model->ulines, linelim,
1568 cpl_polynomial_shift_1d(self, 0, xxc);
1572 cpl_bivector_delete(xtshift);
1574 return CPL_ERROR_NONE;
1577 start = cpl_polynomial_duplicate(self);
1578 cand = cpl_polynomial_new(1);
1579 backup = cpl_polynomial_new(1);
1582 nshift = cpl_bivector_get_size(xtshift);
1583 if (nmaxima == 0 || nmaxima > nshift) nmaxima = nshift;
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);
1590 for (imaxima = 0; imaxima < nmaxima; imaxima++) {
1592 const double xxc = cpl_vector_get(xtshiftx, imaxima);
1593 double xtpixstep = pixstep;
1594 double xtpixtol = pixtol;
1596 cpl_boolean ok = CPL_FALSE;
1600 cpl_polynomial_copy(cand, start);
1601 cpl_polynomial_shift_1d(cand, 0, xxc);
1602 cpl_polynomial_copy(backup, cand);
1605 for (nfail = 0; nfail < maxfail; nfail++, xtpixtol *= 2.0,
1607 int restart = maxcont;
1612 cpl_errorstate_dump(prestate, CPL_FALSE,
1614 cpl_errorstate_set(prestate);
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)
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);
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);
1639 cpl_polynomial_copy(cand, start);
1643 for (; !error && xtpixtol > 0.0; xtpixtol *= 0.25, xtpixstep *= 0.5) {
1644 int restart = maxcont;
1647 cpl_polynomial_copy(backup, cand);
1650 cpl_errorstate_dump(prestate, CPL_FALSE,
1652 cpl_errorstate_set(prestate);
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)
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);
1677 cpl_errorstate_dump(prestate, CPL_FALSE,
1679 cpl_errorstate_set(prestate);
1680 cpl_polynomial_copy(cand, backup);
1682 if (ok && xtxc > xc) {
1684 cpl_polynomial_copy(self, cand);
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);
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);
1703 cpl_polynomial_delete(start);
1704 cpl_polynomial_delete(backup);
1705 cpl_polynomial_delete(cand);
1709 const double xxc = cpl_vector_get(xtshiftx, 0);
1710 const double xc0 = cpl_vector_get(xtshifty, 0);
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",
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);
1730 cpl_bivector_delete(xtshift);
void irplib_errorstate_dump_debug(unsigned self, unsigned first, unsigned last)
Dump a single CPL error at the CPL debug level.
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.