28#include "irplib_wavecal_impl.h"
30#include "irplib_wlxcorr.h"
57#define IRPLIB_MAX(A, B) ((A) > (B) ? (A) : (B))
58#define IRPLIB_MIN(A, B) ((A) < (B) ? (A) : (B))
60#define IRPLIB_PTR_SWAP(a, b) \
62 void *irplib_ptr_swap = (a); \
64 (b) = irplib_ptr_swap; \
71static void irplib_wlxcorr_estimate(cpl_vector *,
76 const cpl_polynomial *,
80static int irplib_wlxcorr_signal_resample(cpl_vector *,
82 const cpl_bivector *);
84cpl_vector_fill_lss_profile_symmetric(cpl_vector *,
double,
double);
85static cpl_error_code irplib_wlcalib_fill_spectrum(cpl_vector *,
88 const cpl_polynomial *,
91static cpl_boolean irplib_wlcalib_is_lines(
const cpl_vector *,
92 const cpl_polynomial *,
137irplib_wlxcorr_best_poly(
const cpl_vector *spectrum,
138 const cpl_bivector *lines_catalog,
140 const cpl_polynomial *guess_poly,
141 const cpl_vector *wl_error,
149 const int spec_sz = cpl_vector_get_size(spectrum);
150 const int nfree = cpl_vector_get_size(wl_error);
154 cpl_vector *init_pts_wl;
155 cpl_matrix *init_pts_x;
158 cpl_vector *conv_kernel = NULL;
159 cpl_polynomial *poly_sol;
160 cpl_polynomial *poly_candi;
161 const double *pwl_error = cpl_vector_get_data_const(wl_error);
164 const cpl_boolean symsamp = CPL_TRUE;
165 const cpl_boolean is_lines =
166 irplib_wlcalib_is_lines(cpl_bivector_get_x_const(lines_catalog),
167 guess_poly, spec_sz, 1.0);
179 cpl_msg_debug(cpl_func,
180 "Checking %d^%d dispersion polynomials (slitw=%g, "
181 "fwhm=%g) against %d-point observed spectrum with%s "
182 "catalog resampling",
183 nsamples, nfree, slitw, fwhm, spec_sz, is_lines ?
"out" :
"");
185 cpl_ensure(xc != NULL, CPL_ERROR_NULL_INPUT, NULL);
187 cpl_ensure(spectrum != NULL, CPL_ERROR_NULL_INPUT, NULL);
188 cpl_ensure(lines_catalog != NULL, CPL_ERROR_NULL_INPUT, NULL);
189 cpl_ensure(guess_poly != NULL, CPL_ERROR_NULL_INPUT, NULL);
190 cpl_ensure(wl_error != NULL, CPL_ERROR_NULL_INPUT, NULL);
191 cpl_ensure(nfree >= 2, CPL_ERROR_ILLEGAL_INPUT, NULL);
192 cpl_ensure(nsamples > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
194 cpl_ensure(1 + degree == nfree, CPL_ERROR_ILLEGAL_INPUT, NULL);
196 cpl_ensure(cpl_polynomial_get_dimension(guess_poly) == 1,
197 CPL_ERROR_ILLEGAL_INPUT, NULL);
202 for (i = 0; i < nfree; i++) {
203 if (pwl_error[i] != 0.0)
206 cpl_ensure(i < nfree, CPL_ERROR_ILLEGAL_INPUT, NULL);
211 conv_kernel = irplib_wlxcorr_convolve_create_kernel(slitw, fwhm);
212 cpl_ensure(conv_kernel != NULL, CPL_ERROR_ILLEGAL_INPUT, NULL);
216 init_pts_x = cpl_matrix_new(1, nfree);
217 init_pts_wl = cpl_vector_new(nfree);
218 pts_wl = cpl_vector_new(nfree);
219 for (i = 0; i < nfree; i++) {
220 const double xpos = spec_sz * i / (double)degree;
222 cpl_polynomial_eval_1d(guess_poly, xpos, NULL) - 0.5 * pwl_error[i];
224 cpl_matrix_set(init_pts_x, 0, i, xpos);
225 cpl_vector_set(init_pts_wl, i, wlpos);
230 vxcorrs = xcorrs != NULL ? cpl_vector_new(ntests) : NULL;
232 poly_sol = cpl_polynomial_new(1);
233 poly_candi = cpl_polynomial_new(1);
234 model = cpl_vector_new(spec_sz);
235 vxc = cpl_vector_new(1);
236 dxc = cpl_vector_get_data_const(vxc);
239 for (i = 0; i < ntests; i++) {
245 for (deg = degree; deg >= 0; deg--, idiv /= nsamples) {
246 const int imod = idiv % nsamples;
247 const double wlpos = cpl_vector_get(init_pts_wl, deg) +
248 imod * pwl_error[deg] / nsamples;
253 cpl_vector_set(pts_wl, deg, wlpos);
260 degree_loc = (cpl_size)degree;
261 cpl_polynomial_fit(poly_candi, init_pts_x, &symsamp, pts_wl, NULL,
262 CPL_FALSE, NULL, °ree_loc);
264 irplib_wlxcorr_estimate(vxc, model, spectrum, lines_catalog,
265 conv_kernel, poly_candi, slitw, fwhm);
267 cpl_vector_set(vxcorrs, i, *dxc);
271 IRPLIB_PTR_SWAP(poly_sol, poly_candi);
275 cpl_vector_delete(model);
276 cpl_vector_delete(vxc);
277 cpl_vector_delete(conv_kernel);
278 cpl_vector_delete(pts_wl);
279 cpl_matrix_delete(init_pts_x);
280 cpl_vector_delete(init_pts_wl);
281 cpl_polynomial_delete(poly_candi);
283#ifdef CPL_WLCALIB_FAIL_ON_CONSTANT
285 if (cpl_polynomial_get_degree(poly_sol) == 0) {
286 cpl_polynomial_delete(poly_sol);
287 cpl_vector_delete(vxcorrs);
289 cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT,
293 cpl_errorstate_dump(prestate, CPL_FALSE, NULL);
302 cpl_errorstate prestate = cpl_errorstate_get();
304 *wlres = irplib_wlxcorr_gen_spc_table(spectrum, lines_catalog, slitw,
305 fwhm, guess_poly, poly_sol);
306 if (*wlres == NULL) {
307 cpl_polynomial_delete(poly_sol);
308 cpl_vector_delete(vxcorrs);
310 cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT,
315 cpl_errorstate_set(prestate);
320 if (xcorrs != NULL) {
365irplib_wlxcorr_best_poly_prop(
const cpl_vector *spectrum,
366 const cpl_bivector *lines_catalog,
368 const cpl_polynomial *guess_poly,
369 const cpl_vector *wl_error,
377 const int spec_sz = cpl_vector_get_size(spectrum);
378 const int nfree = cpl_vector_get_size(wl_error);
382 cpl_vector *init_pts_wl;
383 cpl_matrix *init_pts_x;
386 cpl_vector *conv_kernel = NULL;
387 cpl_polynomial *poly_sol;
388 cpl_polynomial *poly_candi;
389 const double *pwl_error = cpl_vector_get_data_const(wl_error);
392 const cpl_boolean symsamp = CPL_TRUE;
393 const cpl_boolean is_lines =
394 irplib_wlcalib_is_lines(cpl_bivector_get_x_const(lines_catalog),
395 guess_poly, spec_sz, 1.0);
407 cpl_msg_debug(cpl_func,
408 "Checking %d^%d dispersion polynomials (slitw=%g, "
409 "fwhm=%g) against %d-point observed spectrum with%s "
410 "catalog resampling",
411 nsamples, nfree, slitw, fwhm, spec_sz, is_lines ?
"out" :
"");
413 cpl_ensure(xc != NULL, CPL_ERROR_NULL_INPUT, NULL);
415 cpl_ensure(spectrum != NULL, CPL_ERROR_NULL_INPUT, NULL);
416 cpl_ensure(lines_catalog != NULL, CPL_ERROR_NULL_INPUT, NULL);
417 cpl_ensure(guess_poly != NULL, CPL_ERROR_NULL_INPUT, NULL);
418 cpl_ensure(wl_error != NULL, CPL_ERROR_NULL_INPUT, NULL);
419 cpl_ensure(nfree >= 1, CPL_ERROR_ILLEGAL_INPUT, NULL);
420 cpl_ensure(nsamples > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
422 cpl_ensure(1 + degree == nfree, CPL_ERROR_ILLEGAL_INPUT, NULL);
424 cpl_ensure(cpl_polynomial_get_dimension(guess_poly) == 1,
425 CPL_ERROR_ILLEGAL_INPUT, NULL);
430 for (i = 0; i < nfree; i++) {
431 if (pwl_error[i] != 0.0)
434 cpl_ensure(i < nfree, CPL_ERROR_ILLEGAL_INPUT, NULL);
439 conv_kernel = irplib_wlxcorr_convolve_create_kernel(slitw, fwhm);
440 cpl_ensure(conv_kernel != NULL, CPL_ERROR_ILLEGAL_INPUT, NULL);
444 init_pts_x = cpl_matrix_new(1, nfree);
445 init_pts_wl = cpl_vector_new(nfree);
446 pts_wl = cpl_vector_new(nfree);
447 const double degree_loc2 = degree == 0 ? 1 : (double)degree;
448 for (i = 0; i < nfree; i++) {
449 const double xpos = spec_sz * i / degree_loc2;
451 cpl_polynomial_eval_1d(guess_poly, xpos, NULL) - 0.5 * pwl_error[i];
453 cpl_matrix_set(init_pts_x, 0, i, xpos);
454 cpl_vector_set(init_pts_wl, i, wlpos);
459 vxcorrs = xcorrs != NULL ? cpl_vector_new(ntests) : NULL;
461 poly_sol = cpl_polynomial_new(1);
462 poly_candi = cpl_polynomial_new(1);
463 model = cpl_vector_new(spec_sz);
464 vxc = cpl_vector_new(1);
465 dxc = cpl_vector_get_data_const(vxc);
468 for (i = 0; i < ntests; i++) {
475 for (deg = degree; deg >= 0; deg--, idiv /= nsamples) {
476 const int imod = idiv % nsamples;
477 const double wlpos = cpl_vector_get(init_pts_wl, deg) +
478 imod * pwl_error[deg] / nsamples;
483 cpl_vector_set(pts_wl, deg, wlpos);
490 degree_loc = (cpl_size)degree;
491 cpl_polynomial_fit(poly_candi, init_pts_x, &symsamp, pts_wl, NULL,
492 CPL_FALSE, NULL, °ree_loc);
495 degree_loc = cpl_polynomial_get_degree(guess_poly);
496 for (power = degree + 1; power < degree_loc + 1; power++) {
497 cpl_polynomial_set_coeff(poly_candi, &power,
498 cpl_polynomial_get_coeff(guess_poly,
503 irplib_wlxcorr_estimate(vxc, model, spectrum, lines_catalog,
504 conv_kernel, poly_candi, slitw, fwhm);
506 cpl_vector_set(vxcorrs, i, *dxc);
510 IRPLIB_PTR_SWAP(poly_sol, poly_candi);
521 cpl_vector_delete(model);
522 cpl_vector_delete(vxc);
523 cpl_vector_delete(conv_kernel);
524 cpl_vector_delete(pts_wl);
525 cpl_matrix_delete(init_pts_x);
526 cpl_vector_delete(init_pts_wl);
527 cpl_polynomial_delete(poly_candi);
529#ifdef CPL_WLCALIB_FAIL_ON_CONSTANT
531 if (cpl_polynomial_get_degree(poly_sol) == 0) {
532 cpl_polynomial_delete(poly_sol);
533 cpl_vector_delete(vxcorrs);
535 cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT,
539 cpl_errorstate_dump(prestate, CPL_FALSE, NULL);
548 cpl_errorstate prestate = cpl_errorstate_get();
550 *wlres = irplib_wlxcorr_gen_spc_table(spectrum, lines_catalog, slitw,
551 fwhm, guess_poly, poly_sol);
552 if (*wlres == NULL) {
553 cpl_polynomial_delete(poly_sol);
554 cpl_vector_delete(vxcorrs);
556 cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT,
561 cpl_errorstate_set(prestate);
566 if (xcorrs != NULL) {
596irplib_wlxcorr_gen_spc_table(
const cpl_vector *spectrum,
597 const cpl_bivector *lines_catalog,
600 const cpl_polynomial *guess_poly,
601 const cpl_polynomial *corr_poly)
603 cpl_vector *conv_kernel = NULL;
604 cpl_bivector *gen_init;
605 cpl_bivector *gen_corr;
606 cpl_table *spc_table;
608 const double xtrunc = 0.5 * slitw + 5.0 * fwhm * CPL_MATH_SIG_FWHM;
609 const int spec_sz = cpl_vector_get_size(spectrum);
610 const cpl_boolean guess_resamp =
611 !irplib_wlcalib_is_lines(cpl_bivector_get_x_const(lines_catalog),
612 guess_poly, spec_sz, 1.0);
613 const cpl_boolean corr_resamp =
614 !irplib_wlcalib_is_lines(cpl_bivector_get_x_const(lines_catalog),
615 corr_poly, spec_sz, 1.0);
616 cpl_error_code error;
618 cpl_msg_debug(cpl_func,
619 "Table for guess dispersion polynomial (slitw=%g, "
620 "fwhm=%g) with %d-point observed spectrum with%s catalog re"
622 slitw, fwhm, spec_sz, guess_resamp ?
"out" :
"");
623 cpl_msg_debug(cpl_func,
624 "Table for corr. dispersion polynomial (slitw=%g, "
625 "fwhm=%g) with %d-point observed spectrum with%s catalog re"
627 slitw, fwhm, spec_sz, corr_resamp ?
"out" :
"");
630 cpl_ensure(spectrum, CPL_ERROR_NULL_INPUT, NULL);
631 cpl_ensure(lines_catalog, CPL_ERROR_NULL_INPUT, NULL);
632 cpl_ensure(guess_poly, CPL_ERROR_NULL_INPUT, NULL);
633 cpl_ensure(corr_poly, CPL_ERROR_NULL_INPUT, NULL);
636 if (guess_resamp || corr_resamp) {
637 conv_kernel = irplib_wlxcorr_convolve_create_kernel(slitw, fwhm);
639 if (conv_kernel == NULL) {
640 cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
643 "convolution kernel");
649 gen_init = cpl_bivector_new(spec_sz);
651 error = irplib_wlcalib_fill_spectrum(cpl_bivector_get_y(gen_init),
652 lines_catalog, conv_kernel,
658 NULL, NULL, guess_poly,
659 lines_catalog, slitw, fwhm,
660 xtrunc, 0, CPL_FALSE,
664 if (error || cpl_vector_fill_polynomial(cpl_bivector_get_x(gen_init),
666 cpl_vector_delete(conv_kernel);
667 cpl_bivector_delete(gen_init);
668 cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT, __FILE__,
671 "emission spectrum");
676 gen_corr = cpl_bivector_new(spec_sz);
678 error = irplib_wlcalib_fill_spectrum(cpl_bivector_get_y(gen_corr),
679 lines_catalog, conv_kernel,
685 NULL, NULL, corr_poly,
686 lines_catalog, slitw, fwhm,
687 xtrunc, 0, CPL_FALSE,
691 if (error || cpl_vector_fill_polynomial(cpl_bivector_get_x(gen_corr),
693 cpl_vector_delete(conv_kernel);
694 cpl_bivector_delete(gen_init);
695 cpl_bivector_delete(gen_corr);
696 cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT, __FILE__,
699 "emission spectrum");
702 cpl_vector_delete(conv_kernel);
705 spc_table = cpl_table_new(spec_sz);
706 cpl_table_new_column(spc_table, IRPLIB_WLXCORR_COL_WAVELENGTH,
708 cpl_table_new_column(spc_table, IRPLIB_WLXCORR_COL_CAT_INIT,
710 cpl_table_new_column(spc_table, IRPLIB_WLXCORR_COL_CAT_FINAL,
712 cpl_table_new_column(spc_table, IRPLIB_WLXCORR_COL_OBS, CPL_TYPE_DOUBLE);
715 pgen = cpl_bivector_get_x_data_const(gen_corr);
716 cpl_table_copy_data_double(spc_table, IRPLIB_WLXCORR_COL_WAVELENGTH, pgen);
717 pgen = cpl_bivector_get_y_data_const(gen_corr);
718 cpl_table_copy_data_double(spc_table, IRPLIB_WLXCORR_COL_CAT_FINAL, pgen);
719 pgen = cpl_vector_get_data_const(spectrum);
720 cpl_table_copy_data_double(spc_table, IRPLIB_WLXCORR_COL_OBS, pgen);
721 pgen = cpl_bivector_get_y_data_const(gen_init);
722 cpl_table_copy_data_double(spc_table, IRPLIB_WLXCORR_COL_CAT_INIT, pgen);
723 cpl_bivector_delete(gen_init);
724 cpl_bivector_delete(gen_corr);
743irplib_wlxcorr_cat_extract(
const cpl_bivector *lines_catalog,
747 const int nlines = cpl_bivector_get_size(lines_catalog);
748 int wave_min_id, wave_max_id;
749 cpl_vector *sub_cat_wl;
750 cpl_vector *sub_cat_int;
751 const cpl_vector *xlines = cpl_bivector_get_x_const(lines_catalog);
752 const double *dxlines = cpl_vector_get_data_const(xlines);
754 cpl_ensure(lines_catalog != NULL, CPL_ERROR_NULL_INPUT, NULL);
757 wave_min_id = (int)cpl_vector_find(xlines, wave_min);
758 if (wave_min_id < 0) {
759 cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT, __FILE__,
761 "The starting wavelength cannot be found");
766 if (dxlines[wave_min_id] <= wave_min)
770 wave_max_id = (int)cpl_vector_find(xlines, wave_max);
771 if (wave_max_id < 0) {
772 cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT, __FILE__,
774 "The ending wavelength cannot be found");
778 if (dxlines[wave_max_id] >= wave_max)
783 cpl_ensure(wave_min_id <= wave_max_id, CPL_ERROR_ILLEGAL_INPUT, NULL);
785 if (wave_min_id < 0 || wave_max_id == nlines) {
786 cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT, __FILE__,
788 "The %d-line catalogue "
789 "has no lines in the range %g -> %g",
790 nlines, wave_min, wave_max);
794 sub_cat_wl = cpl_vector_extract(xlines, wave_min_id, wave_max_id, 1);
795 sub_cat_int = cpl_vector_extract(cpl_bivector_get_y_const(lines_catalog),
796 wave_min_id, wave_max_id, 1);
798 return cpl_bivector_wrap_vectors(sub_cat_wl, sub_cat_int);
820irplib_wlxcorr_convolve_create_kernel(
double slitw,
double fwhm)
822 const double sigma = fwhm * CPL_MATH_SIG_FWHM;
823 const int size = 1 + (int)(5.0 * sigma + 0.5 * slitw);
824 cpl_vector *kernel = cpl_vector_new(size);
827 if (cpl_vector_fill_lss_profile_symmetric(kernel, slitw, fwhm)) {
828 cpl_vector_delete(kernel);
830 (void)cpl_error_set_where(cpl_func);
851irplib_wlxcorr_convolve(cpl_vector *smoothed,
const cpl_vector *conv_kernel)
862 cpl_ensure(smoothed, CPL_ERROR_NULL_INPUT, -1);
863 cpl_ensure(conv_kernel, CPL_ERROR_NULL_INPUT, -1);
866 nsamples = cpl_vector_get_size(smoothed);
867 ihwidth = cpl_vector_get_size(conv_kernel) - 1;
868 cpl_ensure(ihwidth < nsamples, CPL_ERROR_ILLEGAL_INPUT, -1);
869 psymm = cpl_vector_get_data_const(conv_kernel);
870 psmoothe = cpl_vector_get_data(smoothed);
873 raw = cpl_vector_duplicate(smoothed);
874 praw = cpl_vector_get_data(raw);
877 for (i = 0; i < ihwidth; i++) {
878 psmoothe[i] = praw[i] * psymm[0];
879 for (j = 1; j <= ihwidth; j++) {
880 const int k = i - j < 0 ? 0 : i - j;
881 psmoothe[i] += (praw[k] + praw[i + j]) * psymm[j];
885 for (i = ihwidth; i < nsamples - ihwidth; i++) {
886 psmoothe[i] = praw[i] * psymm[0];
887 for (j = 1; j <= ihwidth; j++)
888 psmoothe[i] += (praw[i - j] + praw[i + j]) * psymm[j];
890 for (i = nsamples - ihwidth; i < nsamples; i++) {
891 psmoothe[i] = praw[i] * psymm[0];
892 for (j = 1; j <= ihwidth; j++) {
893 const int k = i + j > nsamples - 1 ? nsamples - 1 : i + j;
894 psmoothe[i] += (praw[k] + praw[i - j]) * psymm[j];
897 cpl_vector_delete(raw);
913irplib_wlxcorr_plot_solution(
const cpl_polynomial *init,
914 const cpl_polynomial *comp,
915 const cpl_polynomial *sol,
919 int nsamples, nplots;
920 cpl_vector **vectors;
924 if (init == NULL || comp == NULL)
928 nsamples = pix_stop - pix_start + 1;
935 vectors = cpl_malloc((nplots + 1) *
sizeof(cpl_vector *));
936 for (i = 0; i < nplots + 1; i++)
937 vectors[i] = cpl_vector_new(nsamples);
941 for (i = 0; i < nsamples; i++) {
942 cpl_vector_set(vectors[0], i, pix_start + i);
943 cpl_vector_set(vectors[1], i,
944 cpl_polynomial_eval_1d(init, (
double)(pix_start + i),
946 cpl_vector_set(vectors[2], i,
947 cpl_polynomial_eval_1d(comp, (
double)(pix_start + i),
950 cpl_vector_set(vectors[3], i,
951 cpl_polynomial_eval_1d(sol, (
double)(pix_start + i),
956 cpl_plot_vectors(
"set grid;set xlabel 'Position (pixels)';",
957 "t '1-Initial / 2-Computed / 3-Solution' w lines",
"",
958 (
const cpl_vector **)vectors, nplots + 1);
961 for (i = 0; i < nplots + 1; i++)
962 cpl_vector_delete(vectors[i]);
967 vectors = cpl_malloc((nplots + 1) *
sizeof(cpl_vector *));
968 for (i = 0; i < nplots + 1; i++)
969 vectors[i] = cpl_vector_new(nsamples);
973 for (i = 0; i < nsamples; i++) {
975 cpl_vector_set(vectors[0], i, pix_start + i);
976 diff = cpl_polynomial_eval_1d(comp, (
double)(pix_start + i), NULL) -
977 cpl_polynomial_eval_1d(init, (
double)(pix_start + i), NULL);
978 cpl_vector_set(vectors[1], i, diff);
980 diff = cpl_polynomial_eval_1d(sol, (
double)(pix_start + i), NULL) -
981 cpl_polynomial_eval_1d(init, (
double)(pix_start + i), NULL);
982 cpl_vector_set(vectors[2], i, diff);
988 cpl_bivector *bivector;
989 bivector = cpl_bivector_wrap_vectors(vectors[0], vectors[1]);
990 cpl_plot_bivector(
"set grid;set xlabel 'Position (pixels)';set ylabel "
991 "'Wavelength difference';",
992 "t 'Computed-Initial wavelenth' w lines",
"",
994 cpl_bivector_unwrap_vectors(bivector);
998 "set grid;set xlabel 'Position (pixels)';",
999 "t '1-Computed - Initial / 2--Solution - Initial' w lines",
"",
1000 (
const cpl_vector **)vectors, nplots + 1);
1004 for (i = 0; i < nplots + 1; i++)
1005 cpl_vector_delete(vectors[i]);
1025irplib_wlxcorr_plot_spc_table(
const cpl_table *spc_table,
1027 int first_plotted_line,
1028 int last_plotted_line)
1030 char title_loc[1024];
1031 cpl_vector **vectors;
1032 cpl_vector **sub_vectors;
1033 cpl_vector *tmp_vec;
1035 double mean1, mean3;
1036 int start_ind, stop_ind, hsize_pix;
1040 if (first_plotted_line > last_plotted_line)
1042 if (spc_table == NULL)
1046 nsamples = cpl_table_get_nrow(spc_table);
1050 "t '%s - 1-Initial catalog/2-Corrected catalog/3-Observed' w lines",
1052 title_loc[1023] = (char)0;
1054 vectors = cpl_malloc(4 *
sizeof(cpl_vector *));
1055 vectors[0] = cpl_vector_wrap(
1056 nsamples, cpl_table_get_data_double((cpl_table *)spc_table,
1057 IRPLIB_WLXCORR_COL_WAVELENGTH));
1059 cpl_vector_wrap(nsamples,
1060 cpl_table_get_data_double((cpl_table *)spc_table,
1061 IRPLIB_WLXCORR_COL_CAT_INIT));
1062 vectors[2] = cpl_vector_wrap(
1063 nsamples, cpl_table_get_data_double((cpl_table *)spc_table,
1064 IRPLIB_WLXCORR_COL_CAT_FINAL));
1066 cpl_vector_wrap(nsamples,
1067 cpl_table_get_data_double((cpl_table *)spc_table,
1068 IRPLIB_WLXCORR_COL_OBS));
1071 mean1 = cpl_vector_get_mean(vectors[1]);
1072 mean3 = cpl_vector_get_mean(vectors[3]);
1073 if (fabs(mean3) > 1)
1074 cpl_vector_multiply_scalar(vectors[3], fabs(mean1 / mean3));
1076 cpl_plot_vectors(
"set grid;set xlabel 'Wavelength (nm)';", title_loc,
"",
1077 (
const cpl_vector **)vectors, 4);
1080 if (fabs(mean3) > 1)
1081 cpl_vector_multiply_scalar(vectors[3], mean3 / mean1);
1085 "t '%s - 1-Initial catalog/2-Corrected catalog/3-Observed "
1086 "(ZOOMED)' w lines",
1088 title_loc[1023] = (char)0;
1089 tmp_vec = cpl_vector_duplicate(vectors[2]);
1090 for (i = 0; i < last_plotted_line; i++) {
1093 if ((max = cpl_vector_get_max(tmp_vec)) <= 0.0)
1095 for (j = 0; j < nsamples; j++) {
1096 if (cpl_vector_get(tmp_vec, j) == max)
1099 if (j - hsize_pix < 0)
1102 start_ind = j - hsize_pix;
1103 if (j + hsize_pix > nsamples - 1)
1104 stop_ind = nsamples - 1;
1106 stop_ind = j + hsize_pix;
1107 for (j = start_ind; j <= stop_ind; j++)
1108 cpl_vector_set(tmp_vec, j, 0.0);
1110 if (i + 1 >= first_plotted_line) {
1111 sub_vectors = cpl_malloc(4 *
sizeof(cpl_vector *));
1113 cpl_vector_extract(vectors[0], start_ind, stop_ind, 1);
1115 cpl_vector_extract(vectors[1], start_ind, stop_ind, 1);
1117 cpl_vector_extract(vectors[2], start_ind, stop_ind, 1);
1119 cpl_vector_extract(vectors[3], start_ind, stop_ind, 1);
1121 cpl_plot_vectors(
"set grid;set xlabel 'Wavelength (nm)';",
1122 title_loc,
"", (
const cpl_vector **)sub_vectors,
1125 cpl_vector_delete(sub_vectors[0]);
1126 cpl_vector_delete(sub_vectors[1]);
1127 cpl_vector_delete(sub_vectors[2]);
1128 cpl_vector_delete(sub_vectors[3]);
1129 cpl_free(sub_vectors);
1132 cpl_vector_delete(tmp_vec);
1134 cpl_vector_unwrap(vectors[0]);
1135 cpl_vector_unwrap(vectors[1]);
1136 cpl_vector_unwrap(vectors[2]);
1137 cpl_vector_unwrap(vectors[3]);
1153irplib_wlxcorr_catalog_plot(
const cpl_bivector *cat,
double wmin,
double wmax)
1156 cpl_bivector *subcat;
1157 cpl_vector *subcat_x;
1158 cpl_vector *subcat_y;
1159 const double *pwave;
1160 int nvals, nvals_tot;
1170 nvals_tot = cpl_bivector_get_size(cat);
1173 pwave = cpl_bivector_get_x_data_const(cat);
1174 if (pwave[0] >= wmin)
1178 if (pwave[nvals_tot - 1] <= wmax)
1179 stop = nvals_tot - 1;
1183 while ((i < nvals_tot - 1) && (pwave[i] < wmin))
1187 while ((i > 0) && (pwave[i] > wmax))
1191 if (start >= stop) {
1192 cpl_msg_error(cpl_func,
"Cannot plot the catalog");
1195 nvals = stop - start + 1;
1199 cpl_vector_extract(cpl_bivector_get_x_const(cat), start, stop, 1);
1201 cpl_vector_extract(cpl_bivector_get_y_const(cat), start, stop, 1);
1202 subcat = cpl_bivector_wrap_vectors(subcat_x, subcat_y);
1207 "set grid;set xlabel 'Wavelength (nm)';set ylabel 'Emission';",
1208 "t 'Catalog Spectrum' w lines",
"", subcat);
1212 "set grid;set xlabel 'Wavelength (nm)';set ylabel 'Emission';",
1213 "t 'Catalog Spectrum' w impulses",
"", subcat);
1215 cpl_bivector_unwrap_vectors(subcat);
1216 cpl_vector_delete(subcat_x);
1217 cpl_vector_delete(subcat_y);
1241irplib_wlxcorr_estimate(cpl_vector *vxc,
1243 const cpl_vector *spectrum,
1244 const cpl_bivector *lines_catalog,
1245 const cpl_vector *conv_kernel,
1246 const cpl_polynomial *poly_candi,
1250 cpl_errorstate prestate = cpl_errorstate_get();
1251 const int hsize = cpl_vector_get_size(vxc) / 2;
1253 if (conv_kernel != NULL) {
1254 irplib_wlcalib_fill_spectrum(model, lines_catalog, conv_kernel,
1258 const double xtrunc = 0.5 * slitw + 5.0 * fwhm * CPL_MATH_SIG_FWHM;
1261 lines_catalog, slitw, fwhm,
1262 xtrunc, 0, CPL_FALSE, CPL_FALSE,
1266 if (cpl_errorstate_is_equal(prestate))
1267 cpl_vector_correlate(vxc, model, spectrum);
1269 if (!cpl_errorstate_is_equal(prestate)) {
1270 cpl_vector_fill(vxc, 0.0);
1273 cpl_errorstate_set(prestate);
1292irplib_wlcalib_is_lines(
const cpl_vector *wavelengths,
1293 const cpl_polynomial *disp1d,
1297 const int nlines = cpl_vector_get_size(wavelengths);
1299 const double dispersion =
1300 cpl_polynomial_eval_1d_diff(disp1d, 0.5 * spec_sz + 1.0, 0.5 * spec_sz,
1302 const double range = cpl_vector_get(wavelengths, nlines - 1) -
1303 cpl_vector_get(wavelengths, 0);
1305 cpl_ensure(wavelengths != NULL, CPL_ERROR_NULL_INPUT, CPL_FALSE);
1306 cpl_ensure(disp1d != NULL, CPL_ERROR_NULL_INPUT, CPL_FALSE);
1307 cpl_ensure(cpl_polynomial_get_dimension(disp1d) == 1,
1308 CPL_ERROR_ILLEGAL_INPUT, CPL_FALSE);
1309 cpl_ensure(range > 0.0, CPL_ERROR_ILLEGAL_INPUT, CPL_FALSE);
1311 return nlines * fabs(dispersion) <= tol * fabs(range) ? CPL_TRUE
1331static cpl_error_code
1332irplib_wlcalib_fill_spectrum(cpl_vector *self,
1333 const cpl_bivector *lines_catalog,
1334 const cpl_vector *conv_kernel,
1335 const cpl_polynomial *poly,
1338 const int size = cpl_vector_get_size(self);
1339 const int nlines = cpl_bivector_get_size(lines_catalog);
1340 const cpl_vector *xlines = cpl_bivector_get_x_const(lines_catalog);
1341 const double *dxlines = cpl_vector_get_data_const(xlines);
1342 cpl_bivector *sub_cat;
1343 cpl_vector *sub_cat_x;
1344 cpl_vector *sub_cat_y;
1345 cpl_vector *wl_limits;
1346 double wave_min, wave_max;
1347 int wave_min_id, wave_max_id;
1351 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
1352 cpl_ensure_code(lines_catalog != NULL, CPL_ERROR_NULL_INPUT);
1353 cpl_ensure_code(conv_kernel != NULL, CPL_ERROR_NULL_INPUT);
1354 cpl_ensure_code(poly != NULL, CPL_ERROR_NULL_INPUT);
1355 cpl_ensure_code(size > 0, CPL_ERROR_ILLEGAL_INPUT);
1359 wl_limits = cpl_vector_new(size + 1);
1360 cpl_vector_fill_polynomial(wl_limits, poly, 0.5 - search_hs, 1);
1363 wave_min = cpl_vector_get(wl_limits, 0);
1364 wave_max = cpl_vector_get(wl_limits, size);
1367 wave_min_id = cpl_vector_find(xlines, wave_min);
1369 if (dxlines[wave_min_id] > wave_min)
1372 if (wave_min_id < 0) {
1373 cpl_vector_delete(wl_limits);
1374 return cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
1377 "catalogue only has lines above %g",
1382 wave_max_id = cpl_vector_find(xlines, wave_max);
1384 if (dxlines[wave_max_id] < wave_max)
1387 if (wave_max_id == nlines) {
1388 cpl_vector_delete(wl_limits);
1389 return cpl_error_set_message_macro(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
1392 "catalogue only has lines below %g",
1398 nsub = 1 + wave_max_id - wave_min_id;
1399 cpl_ensure_code(nsub > 1, CPL_ERROR_ILLEGAL_INPUT);
1403 sub_cat_x = cpl_vector_wrap(nsub, wave_min_id + (
double *)dxlines);
1405 cpl_vector_wrap(nsub,
1406 wave_min_id + (
double *)cpl_bivector_get_y_data_const(
1408 sub_cat = cpl_bivector_wrap_vectors(sub_cat_x, sub_cat_y);
1411 error = irplib_wlxcorr_signal_resample(self, wl_limits, sub_cat);
1413 cpl_vector_delete(wl_limits);
1414 cpl_bivector_unwrap_vectors(sub_cat);
1415 (void)cpl_vector_unwrap(sub_cat_x);
1416 (void)cpl_vector_unwrap(sub_cat_y);
1418 cpl_ensure_code(!error, CPL_ERROR_ILLEGAL_INPUT);
1421 cpl_ensure_code(!irplib_wlxcorr_convolve(self, conv_kernel),
1422 cpl_error_get_code());
1424 return CPL_ERROR_NONE;
1440irplib_wlxcorr_signal_resample(cpl_vector *resampled,
1441 const cpl_vector *xbounds,
1442 const cpl_bivector *hires)
1444 const int hrsize = cpl_bivector_get_size(hires);
1445 const cpl_vector *xhires;
1446 const cpl_vector *yhires;
1447 const double *pxhires;
1448 const double *pyhires;
1449 const double *pxbounds;
1450 cpl_vector *ybounds;
1451 cpl_bivector *boundary;
1458 if ((!resampled) || (!xbounds) || (!hires))
1462 nsamples = cpl_vector_get_size(resampled);
1465 presampled = cpl_vector_get_data(resampled);
1466 pxbounds = cpl_vector_get_data_const(xbounds);
1467 xhires = cpl_bivector_get_x_const(hires);
1468 yhires = cpl_bivector_get_y_const(hires);
1469 pxhires = cpl_vector_get_data_const(xhires);
1470 pyhires = cpl_vector_get_data_const(yhires);
1473 ybounds = cpl_vector_new(cpl_vector_get_size(xbounds));
1474 boundary = cpl_bivector_wrap_vectors((cpl_vector *)xbounds, ybounds);
1475 pybounds = cpl_vector_get_data(ybounds);
1478 if (cpl_bivector_get_size(boundary) != nsamples + 1) {
1479 cpl_bivector_unwrap_vectors(boundary);
1480 cpl_vector_delete(ybounds);
1485 itt = cpl_vector_find(xhires, pxbounds[0]);
1488 if (cpl_bivector_interpolate_linear(boundary, hires)) {
1489 cpl_bivector_unwrap_vectors(boundary);
1490 cpl_vector_delete(ybounds);
1496 while (pxhires[itt] < pxbounds[0])
1499 for (i = 0; i < nsamples; i++) {
1504 double xlow = pxbounds[i];
1505 double x = pxhires[itt];
1507 if (x > pxbounds[i + 1])
1508 x = pxbounds[i + 1];
1511 presampled[i] = pybounds[i] * (x - xlow);
1514 while ((pxhires[itt] < pxbounds[i + 1]) && (itt < hrsize)) {
1515 const double xprev = x;
1516 x = pxhires[itt + 1];
1517 if (x > pxbounds[i + 1])
1518 x = pxbounds[i + 1];
1519 presampled[i] += pyhires[itt] * (x - xlow);
1526 presampled[i] += pybounds[i + 1] * (pxbounds[i + 1] - xlow);
1530 presampled[i] /= 2 * (pxbounds[i + 1] - pxbounds[i]);
1532 cpl_bivector_unwrap_vectors(boundary);
1533 cpl_vector_delete(ybounds);
1560static cpl_error_code
1561cpl_vector_fill_lss_profile_symmetric(cpl_vector *self,
1565 const double sigma = fwhm * CPL_MATH_SIG_FWHM;
1566 const int n = cpl_vector_get_size(self);
1570 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
1571 cpl_ensure_code(slitw > 0.0, CPL_ERROR_ILLEGAL_INPUT);
1572 cpl_ensure_code(fwhm > 0.0, CPL_ERROR_ILLEGAL_INPUT);
1577 (void)cpl_vector_set(self, 0,
1582 for (i = 1; i < n; i++) {
1584 const double x1p = i + 0.5 * slitw + 0.5;
1585 const double x1n = i - 0.5 * slitw + 0.5;
1586 const double x0p = i + 0.5 * slitw - 0.5;
1587 const double x0n = i - 0.5 * slitw - 0.5;
1588 const double val = 0.5 / slitw *
1593 (void)cpl_vector_set(self, i, val);
1596 return CPL_ERROR_NONE;
double irplib_erf_antideriv(double x, double sigma)
The antiderivative of erx(x/sigma/sqrt(2)) with respect to x.
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.