20 #include "ssht/ssht.h"
22 #include "so3_types.h"
23 #include "so3_error.h"
24 #include "so3_sampling.h"
26 #define MIN(a,b) ((a < b) ? (a) : (b))
27 #define MAX(a,b) ((a > b) ? (a) : (b))
29 typedef void (*
inverse_complex_ssht)(complex
double *,
const complex
double *, int, int, int, ssht_dl_method_t, int);
30 typedef void (*
inverse_real_ssht)(
double *,
const complex
double *, int, int, ssht_dl_method_t, int);
31 typedef void (*
forward_complex_ssht)(complex
double *,
const complex
double *, int, int, int, ssht_dl_method_t, int);
32 typedef void (*
forward_real_ssht)(complex
double *,
const double *, int, int, ssht_dl_method_t, int);
35 complex
double *flmn,
const complex
double *f,
36 const so3_parameters_t *parameters
39 so3_sampling_t sampling;
40 so3_storage_t storage;
42 ssht_dl_method_t dl_method;
49 sampling = parameters->sampling_scheme;
50 storage = parameters->storage;
52 n_mode = parameters->n_mode;
53 dl_method = parameters->dl_method;
54 verbosity = parameters->verbosity;
55 steerable = parameters->steerable;
60 printf(
"%sComputing adjoint inverse transform using MW sampling with\n", SO3_PROMPT);
61 printf(
"%sparameters (L, N, reality) = (%d, %d, FALSE)\n", SO3_PROMPT, L, N);
63 printf(
"%sUsing routine so3_adjoint_inverse_direct with storage method %d...\n"
72 int mm_stride = 2*L-1;
76 int bext_stride = 2*L-1;
79 int n_start, n_stop, n_inc;
90 n_start = ((N-1) % 2 == 0) ? -N+1 : -N+2;
91 n_stop = ((N-1) % 2 == 0) ? N-1 : N-2;
95 n_start = ((N-1) % 2 != 0) ? -N+1 : -N+2;
96 n_stop = ((N-1) % 2 != 0) ? N-1 : N-2;
99 case SO3_N_MODE_MAXIMUM:
102 n_inc =
MAX(1,2*N - 2);
105 SO3_ERROR_GENERIC(
"Invalid n-mode.");
108 double *sqrt_tbl = calloc(2*(L-1)+2,
sizeof(*sqrt_tbl));
109 SO3_ERROR_MEM_ALLOC_CHECK(sqrt_tbl);
110 double *signs = calloc(L+1,
sizeof(*signs));
111 SO3_ERROR_MEM_ALLOC_CHECK(signs);
112 complex
double *exps = calloc(4,
sizeof(*exps));
113 SO3_ERROR_MEM_ALLOC_CHECK(exps);
114 complex
double *expsmm = calloc(2*L-1,
sizeof(*expsmm));
115 SO3_ERROR_MEM_ALLOC_CHECK(expsmm);
119 for (el = 0; el <= 2*(L-1)+1; ++el)
120 sqrt_tbl[el] = sqrt((
double)el);
121 for (m = 0; m <= L-1; m += 2)
127 for (i = 0; i < 4; ++i)
128 exps[i] = cexp(I*SO3_PION2*i);
129 for (mm = -L+1; mm <= L-1; ++mm)
130 expsmm[mm + mm_offset] = cexp(-I*mm*SSHT_PI/(2.0*L-1.0));
133 complex
double *Fmnb = calloc((2*L-1)*(2*L-1)*(2*N-1),
sizeof(*Fmnb));
134 SO3_ERROR_MEM_ALLOC_CHECK(Fmnb);
135 complex
double *inout = calloc((2*L-1)*(2*N-1),
sizeof(*inout));
136 SO3_ERROR_MEM_ALLOC_CHECK(inout);
137 fftw_plan plan = fftw_plan_dft_2d(
144 for (b = 0; b < L; ++b)
149 for (g = 0; g < 2*N-1; ++g)
155 a_stride*
sizeof(*f));
156 fftw_execute_dft(plan, inout, inout);
159 for (n = n_start; n <= n_stop; n += n_inc)
161 int n_shift = n < 0 ? 2*N-1 : 0;
162 for (m = -L+1; m <= L-1; ++m)
164 int m_shift = m < 0 ? 2*L-1 : 0;
165 Fmnb[b + bext_stride*(
166 m + m_offset + m_stride*(
168 inout[m + m_shift + m_stride*(
173 fftw_destroy_plan(plan);
176 for (n = n_start; n <= n_stop; n += n_inc)
177 for (m = -L+1; m <= L-1; ++m)
178 for (b = L; b < 2*L-1; ++b)
179 Fmnb[b + bext_stride*(
180 m + m_offset + m_stride*(
181 n + n_offset))] = 0.0;
185 complex
double *Fmnm = calloc((2*L-1)*(2*L-1)*(2*N-1),
sizeof(*Fmnm));
186 SO3_ERROR_MEM_ALLOC_CHECK(Fmnm);
188 plan = fftw_plan_dft_1d(
193 for (n = n_start; n <= n_stop; n += n_inc)
194 for (m = -L+1; m <= L-1; ++m)
197 Fmnb + 0 + bext_stride*(
198 m + m_offset + m_stride*(
200 bext_stride*
sizeof(*Fmnb));
201 fftw_execute_dft(plan, inout, inout);
204 for (mm = -L+1; mm <= L-1; ++mm)
206 int mm_shift = mm < 0 ? 2*L-1 : 0;
207 Fmnm[m + m_offset + m_stride*(
208 mm + mm_offset + mm_stride*(
210 inout[mm + mm_shift];
213 fftw_destroy_plan(plan);
217 for (n = n_start; n <= n_stop; n += n_inc)
218 for (mm = -L+1; mm <= L-1; ++mm)
219 for (m = -L+1; m <= L-1; ++m)
220 Fmnm[m + m_offset + m_stride*(
221 mm + mm_offset + mm_stride*(
223 expsmm[mm + mm_offset];
226 double *dl, *dl8 = NULL;
227 dl = ssht_dl_calloc(L, SSHT_DL_QUARTER);
228 SO3_ERROR_MEM_ALLOC_CHECK(dl);
229 if (dl_method == SSHT_DL_RISBO)
231 dl8 = ssht_dl_calloc(L, SSHT_DL_QUARTER_EXTENDED);
232 SO3_ERROR_MEM_ALLOC_CHECK(dl8);
234 int dl_offset = ssht_dl_get_offset(L, SSHT_DL_QUARTER);
235 int dl_stride = ssht_dl_get_stride(L, SSHT_DL_QUARTER);
236 for (n = -N+1; n <= N-1; ++n)
237 for (el = abs(n); el < L; ++el)
238 for (m = -el; m <= el; ++m)
245 for (el = L0; el < L; ++el)
253 if (el != 0 && el == L0)
255 for(eltmp = 0; eltmp <= L0; ++eltmp)
256 ssht_dl_beta_risbo_eighth_table(dl8, SO3_PION2, L,
257 SSHT_DL_QUARTER_EXTENDED,
258 eltmp, sqrt_tbl, signs);
259 ssht_dl_beta_risbo_fill_eighth2quarter_table(dl,
262 SSHT_DL_QUARTER_EXTENDED,
268 ssht_dl_beta_risbo_eighth_table(dl8, SO3_PION2, L,
269 SSHT_DL_QUARTER_EXTENDED,
270 el, sqrt_tbl, signs);
271 ssht_dl_beta_risbo_fill_eighth2quarter_table(dl,
274 SSHT_DL_QUARTER_EXTENDED,
280 case SSHT_DL_TRAPANI:
281 if (el != 0 && el == L0)
283 for(eltmp = 0; eltmp <= L0; ++eltmp)
284 ssht_dl_halfpi_trapani_eighth_table(dl, L,
287 ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl, L,
293 ssht_dl_halfpi_trapani_eighth_table(dl, L,
296 ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl, L,
303 SO3_ERROR_GENERIC(
"Invalid dl method");
311 n_start =
MAX(-N+1,-el);
312 n_stop =
MIN( N-1, el);
315 case SO3_N_MODE_EVEN:
316 n_start =
MAX(-N+1,-el);
317 n_start += (-n_start)%2;
318 n_stop =
MIN( N-1, el);
323 n_start =
MAX(-N+1,-el);
324 n_start += 1+n_start%2;
325 n_stop =
MIN( N-1, el);
326 n_stop -= 1-n_stop%2;
329 case SO3_N_MODE_MAXIMUM:
334 n_inc =
MAX(1,2*N-2);
344 SO3_ERROR_GENERIC(
"Invalid n-mode.");
348 double elfactor = (2.0*el+1.0)/(8.0*SO3_PI*SO3_PI);
352 for (mm = -el; mm <= el; ++mm)
356 double elmmsign = signs[el] * signs[abs(mm)];
358 for (n = n_start; n <= n_stop; n += n_inc)
360 double mmsign = mm >= 0 ? 1.0 : signs[el] * signs[abs(n)];
361 double elnsign = n >= 0 ? 1.0 : elmmsign;
364 double elnmm_factor = mmsign * elnsign * elfactor
365 * dl[abs(n) + dl_offset + abs(mm)*dl_stride];
367 for (m = -el; m <= el; ++m)
369 mmsign = mm >= 0 ? 1.0 : signs[el] * signs[abs(m)];
370 double elmsign = m >= 0 ? 1.0 : elmmsign;
373 int mod = ((m-n)%4 + 4)%4;
378 * dl[abs(m) + dl_offset + abs(mm)*dl_stride]
379 * Fmnm[m + m_offset + m_stride*(
380 mm + mm_offset + mm_stride*(
389 if (dl_method == SSHT_DL_RISBO)
399 printf(
"%sAdjoint inverse transform computed!\n", SO3_PROMPT);
403 complex
double *f,
const complex
double *flmn,
404 const so3_parameters_t *parameters
407 so3_sampling_t sampling;
408 so3_storage_t storage;
410 ssht_dl_method_t dl_method;
417 sampling = parameters->sampling_scheme;
418 storage = parameters->storage;
420 n_mode = parameters->n_mode;
421 dl_method = parameters->dl_method;
422 verbosity = parameters->verbosity;
423 steerable = parameters->steerable;
428 printf(
"%sComputing forward adjoint transform using MW sampling with\n", SO3_PROMPT);
429 printf(
"%sparameters (L, N, reality) = (%d, %d, FALSE)\n", SO3_PROMPT, L, N);
431 printf(
"%sUsing routine so3_adjoint_forward_direct with storage method %d...\n"
437 int el, m, n, mm, b, g;
440 int m_stride = 2*L-1;
444 int mm_stride = 2*L-1;
445 int a_stride = 2*L-1;
447 int bext_stride = 2*L-1;
450 complex
double* inout;
453 double *sqrt_tbl = calloc(2*(L-1)+2,
sizeof(*sqrt_tbl));
454 SO3_ERROR_MEM_ALLOC_CHECK(sqrt_tbl);
455 double *signs = calloc(L+1,
sizeof(*signs));
456 SO3_ERROR_MEM_ALLOC_CHECK(signs);
457 complex
double *exps = calloc(4,
sizeof(*exps));
458 SO3_ERROR_MEM_ALLOC_CHECK(exps);
459 complex
double *expsmm = calloc(2*L-1,
sizeof(*expsmm));
460 SO3_ERROR_MEM_ALLOC_CHECK(expsmm);
463 for (el = 0; el <= 2*L-1; ++el)
464 sqrt_tbl[el] = sqrt((
double)el);
465 for (m = 0; m <= L-1; m += 2)
471 for (i = 0; i < 4; ++i)
472 exps[i] = cexp(I*SO3_PION2*i);
473 for (mm = -L+1; mm <= L-1; ++mm)
474 expsmm[mm + mm_offset] = cexp(I*mm*SSHT_PI/(2.0*L-1.0));
479 complex
double *Gmnm = calloc((2*L-1)*(2*L-1)*(2*N-1),
sizeof(*Gmnm));
480 SO3_ERROR_MEM_ALLOC_CHECK(Gmnm);
482 int n_start, n_stop, n_inc;
485 double *dl = ssht_dl_calloc(L, SSHT_DL_QUARTER);
486 SO3_ERROR_MEM_ALLOC_CHECK(dl);
488 if (dl_method == SSHT_DL_RISBO)
490 dl8 = ssht_dl_calloc(L, SSHT_DL_QUARTER_EXTENDED);
491 SO3_ERROR_MEM_ALLOC_CHECK(dl8);
493 int dl_offset = ssht_dl_get_offset(L, SSHT_DL_QUARTER);
494 int dl_stride = ssht_dl_get_stride(L, SSHT_DL_QUARTER);
496 complex
double *mn_factors = calloc((2*L-1)*(2*N-1),
sizeof *mn_factors);
497 SO3_ERROR_MEM_ALLOC_CHECK(mn_factors);
504 for (el = L0; el <= L-1; ++el)
511 if (el != 0 && el == L0)
513 for(eltmp = 0; eltmp <= L0; ++eltmp)
514 ssht_dl_beta_risbo_eighth_table(
518 SSHT_DL_QUARTER_EXTENDED,
522 ssht_dl_beta_risbo_fill_eighth2quarter_table(dl,
525 SSHT_DL_QUARTER_EXTENDED,
531 ssht_dl_beta_risbo_eighth_table(
535 SSHT_DL_QUARTER_EXTENDED,
539 ssht_dl_beta_risbo_fill_eighth2quarter_table(
543 SSHT_DL_QUARTER_EXTENDED,
549 case SSHT_DL_TRAPANI:
550 if (el != 0 && el == L0)
552 for(eltmp = 0; eltmp <= L0; ++eltmp)
553 ssht_dl_halfpi_trapani_eighth_table(
559 ssht_dl_halfpi_trapani_fill_eighth2quarter_table(
568 ssht_dl_halfpi_trapani_eighth_table(
574 ssht_dl_halfpi_trapani_fill_eighth2quarter_table(
584 SO3_ERROR_GENERIC(
"Invalid dl method");
592 n_start =
MAX(-N+1,-el);
593 n_stop =
MIN( N-1, el);
596 case SO3_N_MODE_EVEN:
597 n_start =
MAX(-N+1,-el);
598 n_start += (-n_start)%2;
599 n_stop =
MIN( N-1, el);
604 n_start =
MAX(-N+1,-el);
605 n_start += 1+n_start%2;
606 n_stop =
MIN( N-1, el);
607 n_stop -= 1-n_stop%2;
610 case SO3_N_MODE_MAXIMUM:
615 n_inc =
MAX(1,2*N-2);
625 SO3_ERROR_GENERIC(
"Invalid n-mode.");
629 for (n = n_start; n <= n_stop; n += n_inc)
630 for (m = -el; m <= el; ++m)
634 int mod = ((n-m)%4 + 4)%4;
635 mn_factors[m + m_offset + m_stride*(
637 flmn[ind] * exps[mod];
640 for (mm = 0; mm <= el; ++mm)
644 double elmmsign = signs[el] * signs[mm];
648 for (n = n_start; n <= n_stop; n += n_inc)
650 double elnsign = n >= 0 ? 1.0 : elmmsign;
652 double elnmm_factor = elnsign
653 * dl[abs(n) + dl_offset + mm*dl_stride];
654 for (m = -el; m < 0; ++m)
655 Gmnm[mm + mm_offset + mm_stride*(
656 m + m_offset + m_stride*(
659 * mn_factors[m + m_offset + m_stride*(
661 * elmmsign * dl[-m + dl_offset + mm*dl_stride];
662 for (m = 0; m <= el; ++m)
663 Gmnm[mm + mm_offset + mm_stride*(
664 m + m_offset + m_stride*(
667 * mn_factors[m + m_offset + m_stride*(
669 * dl[m + dl_offset + mm*dl_stride];
676 if (dl_method == SSHT_DL_RISBO)
688 case SO3_N_MODE_EVEN:
689 n_start = ((N-1) % 2 == 0) ? -N+1 : -N+2;
690 n_stop = ((N-1) % 2 == 0) ? N-1 : N-2;
694 n_start = ((N-1) % 2 != 0) ? -N+1 : -N+2;
695 n_stop = ((N-1) % 2 != 0) ? N-1 : N-2;
698 case SO3_N_MODE_MAXIMUM:
701 n_inc =
MAX(1,2*N - 2);
704 SO3_ERROR_GENERIC(
"Invalid n-mode.");
708 for (n = n_start; n <= n_stop; n += n_inc)
709 for (m = -L+1; m <= L-1; ++m)
710 for (mm = -L+1; mm < 0; ++mm)
711 Gmnm[mm + mm_offset + mm_stride*(
712 m + m_offset + m_stride*(
715 * Gmnm[-mm + mm_offset + mm_stride*(
716 m + m_offset + m_stride*(
721 complex
double *w = calloc(4*L-3,
sizeof(*w));
722 SO3_ERROR_MEM_ALLOC_CHECK(w);
723 int w_offset = 2*(L-1);
724 for (mm = -2*(L-1); mm <= 2*(L-1); ++mm)
728 complex
double *wr = calloc(4*L-3,
sizeof(*w));
729 SO3_ERROR_MEM_ALLOC_CHECK(wr);
730 inout = calloc(4*L-3,
sizeof(*inout));
731 SO3_ERROR_MEM_ALLOC_CHECK(inout);
732 fftw_plan plan_bwd = fftw_plan_dft_1d(
737 fftw_plan plan_fwd = fftw_plan_dft_1d(
745 for (mm = 1; mm <= 2*L-2; ++mm)
746 inout[mm + w_offset] = w[mm - 2*(L-1) - 1 + w_offset];
747 for (mm = -2*(L-1); mm <= 0; ++mm)
748 inout[mm + w_offset] = w[mm + 2*(L-1) + w_offset];
750 fftw_execute_dft(plan_bwd, inout, inout);
753 for (mm = 0; mm <= 2*L-2; ++mm)
754 wr[mm + w_offset] = inout[mm - 2*(L-1) + w_offset];
755 for (mm = -2*(L-1); mm <= -1; ++mm)
756 wr[mm + w_offset] = inout[mm + 2*(L-1) + 1 + w_offset];
759 complex
double *Gmnm_pad = calloc(4*L-3,
sizeof(*Gmnm_pad));
760 SO3_ERROR_MEM_ALLOC_CHECK(Gmnm_pad);
761 complex
double *Fmnm = calloc((2*L-1)*(2*L-1)*(2*N-1),
sizeof(*Fmnm));
762 SO3_ERROR_MEM_ALLOC_CHECK(Fmnm);
763 for (n = n_start; n <= n_stop; n += n_inc)
764 for (m = -L+1; m <= L-1; ++m)
768 for (mm = -2*(L-1); mm <= -L; ++mm)
769 Gmnm_pad[mm+w_offset] = 0.0;
770 for (mm = L; mm <= 2*(L-1); ++mm)
771 Gmnm_pad[mm+w_offset] = 0.0;
772 for (mm = -(L-1); mm <= L-1; ++mm)
773 Gmnm_pad[mm + w_offset] =
774 Gmnm[mm + mm_offset + mm_stride*(
775 m + m_offset + m_stride*(
779 for (mm = 1; mm <= 2*L-2; ++mm)
780 inout[mm + w_offset] = Gmnm_pad[mm - 2*(L-1) - 1 + w_offset];
781 for (mm = -2*(L-1); mm <= 0; ++mm)
782 inout[mm + w_offset] = Gmnm_pad[mm + 2*(L-1) + w_offset];
784 fftw_execute_dft(plan_bwd, inout, inout);
786 for (mm = 0; mm <= 2*L-2; ++mm)
787 Gmnm_pad[mm + w_offset] = inout[mm - 2*(L-1) + w_offset];
788 for (mm = -2*(L-1); mm <= -1; ++mm)
789 Gmnm_pad[mm + w_offset] = inout[mm + 2*(L-1) + 1 + w_offset];
793 for (r = -2*(L-1); r <= 2*(L-1); ++r)
794 Gmnm_pad[r + w_offset] *= wr[r + w_offset];
797 for (mm = 1; mm <= 2*L-2; ++mm)
798 inout[mm + w_offset] = Gmnm_pad[mm - 2*(L-1) - 1 + w_offset];
799 for (mm = -2*(L-1); mm <= 0; ++mm)
800 inout[mm + w_offset] = Gmnm_pad[mm + 2*(L-1) + w_offset];
802 fftw_execute_dft(plan_fwd, inout, inout);
804 for (mm = 0; mm <= 2*L-2; ++mm)
805 Gmnm_pad[mm + w_offset] = inout[mm - 2*(L-1) + w_offset];
806 for (mm = -2*(L-1); mm <= -1; ++mm)
807 Gmnm_pad[mm + w_offset] = inout[mm + 2*(L-1) + 1 + w_offset];
810 for (mm = -(L-1); mm <= L-1; ++mm)
811 Fmnm[mm + mm_offset + mm_stride*(
812 m + m_offset + m_stride*(
814 Gmnm_pad[mm + w_offset]
815 * 4.0 * SSHT_PI * SSHT_PI / (4.0*L-3.0);
818 fftw_destroy_plan(plan_bwd);
819 fftw_destroy_plan(plan_fwd);
822 for (n = n_start; n <= n_stop; n += n_inc)
823 for (m = -L+1; m <= L-1; ++m)
824 for (mm = -L+1; mm <= L-1; ++mm)
825 Fmnm[mm + mm_offset + mm_stride*(
826 m + m_offset + m_stride*(
828 expsmm[mm + mm_offset];
831 complex
double *Fmnb = calloc((2*L-1)*(2*L-1)*(2*N-1),
sizeof(*Fmnb));
832 SO3_ERROR_MEM_ALLOC_CHECK(Fmnm);
834 fftw_plan plan = fftw_plan_dft_1d(
839 for (n = n_start; n <= n_stop; n += n_inc)
840 for (m = -L+1; m <= L-1; ++m)
843 for (mm = -L+1; mm <= L-1; ++mm)
845 int mm_shift = mm < 0 ? 2*L-1 : 0;
846 inout[mm + mm_shift] =
847 Fmnm[mm + mm_offset + mm_stride*(
848 m + m_offset + m_stride*(
849 n + n_offset))] / (2.0*L-1.0);
851 fftw_execute_dft(plan, inout, inout);
852 memcpy(Fmnb + 0 + bext_stride*(
853 m + m_offset + m_stride*(
856 bext_stride*
sizeof(*Fmnb));
860 fftw_destroy_plan(plan);
866 for (n = n_start; n <= n_stop; n += n_inc)
867 for (m = -L+1; m <= L-1; ++m)
869 int signmn = signs[abs(m+n)%2];
870 for (b = 0; b <= L-2; ++b)
871 Fmnb[b + bext_stride*(
872 m + m_offset + m_stride*(
875 * Fmnb[(2*L-2-b) + bext_stride*(
876 m + m_offset + m_stride*(
881 inout = calloc((2*L-1)*(2*N-1),
sizeof(*inout));
882 SO3_ERROR_MEM_ALLOC_CHECK(inout);
883 plan = fftw_plan_dft_2d(
889 double norm_factor = 1.0/(2.0*L-1.0)/(2.0*N-1.0);
891 for (b = 0; b < L; ++b)
893 for (
int i_count=0; i_count<(2*L-1)*(2*N-1); i_count++) {inout[i_count] = 0.0;}
896 for (n = n_start; n <= n_stop; n += n_inc)
898 int n_shift = n < 0 ? 2*N-1 : 0;
899 for (m = -L+1; m <= L-1; ++m)
901 int m_shift = m < 0 ? 2*L-1 : 0;
902 inout[m + m_shift + m_stride*(
904 Fmnb[b + bext_stride*(
905 m + m_offset + m_stride*(
906 n + n_offset))] * norm_factor;
909 fftw_execute_dft(plan, inout, inout);
914 for (g = 0; g < 2*N-1; ++g)
920 a_stride*
sizeof(*f));
924 fftw_destroy_plan(plan);
940 complex
double *flmn,
const double *f,
941 const so3_parameters_t *parameters
944 so3_sampling_t sampling;
945 so3_storage_t storage;
947 ssht_dl_method_t dl_method;
954 sampling = parameters->sampling_scheme;
955 storage = parameters->storage;
957 n_mode = parameters->n_mode;
958 dl_method = parameters->dl_method;
959 verbosity = parameters->verbosity;
960 steerable = parameters->steerable;
964 printf(
"%sComputing adjoint inverse transform using MW sampling with\n", SO3_PROMPT);
965 printf(
"%sparameters (L, N, reality) = (%d, %d, FALSE)\n", SO3_PROMPT, L, N);
967 printf(
"%sUsing routine so3_adjoint_inverse_direct_real with storage method %d...\n"
972 int m_stride = 2*L-1;
976 int mm_stride = 2*L-1;
978 int a_stride = 2*L-1;
980 int bext_stride = 2*L-1;
981 int g_stride = 2*N-1;
983 int n_start, n_stop, n_inc;
993 case SO3_N_MODE_EVEN:
995 n_stop = ((N-1) % 2 == 0) ? N-1 : N-2;
1000 n_stop = ((N-1) % 2 != 0) ? N-1 : N-2;
1003 case SO3_N_MODE_MAXIMUM:
1009 SO3_ERROR_GENERIC(
"Invalid n-mode.");
1012 double *sqrt_tbl = calloc(2*(L-1)+2,
sizeof(*sqrt_tbl));
1013 SO3_ERROR_MEM_ALLOC_CHECK(sqrt_tbl);
1014 double *signs = calloc(L+1,
sizeof(*signs));
1015 SO3_ERROR_MEM_ALLOC_CHECK(signs);
1016 complex
double *exps = calloc(4,
sizeof(*exps));
1017 SO3_ERROR_MEM_ALLOC_CHECK(exps);
1018 complex
double *expsmm = calloc(2*L-1,
sizeof(*expsmm));
1019 SO3_ERROR_MEM_ALLOC_CHECK(expsmm);
1023 for (el = 0; el <= 2*(L-1)+1; ++el)
1024 sqrt_tbl[el] = sqrt((
double)el);
1025 for (m = 0; m <= L-1; m += 2)
1031 for (i = 0; i < 4; ++i)
1032 exps[i] = cexp(I*SO3_PION2*i);
1033 for (mm = -L+1; mm <= L-1; ++mm)
1034 expsmm[mm + mm_offset] = cexp(-I*mm*SSHT_PI/(2.0*L-1.0));
1037 complex
double *Fmnb = calloc((2*L-1)*(2*L-1)*N,
sizeof(*Fmnb));
1038 SO3_ERROR_MEM_ALLOC_CHECK(Fmnb);
1039 double *fft_in = calloc((2*L-1)*(2*N-1),
sizeof(*fft_in));
1040 SO3_ERROR_MEM_ALLOC_CHECK(fft_in);
1041 complex
double *fft_out = calloc((2*L-1)*N,
sizeof(*fft_out));
1042 SO3_ERROR_MEM_ALLOC_CHECK(fft_out);
1044 fftw_plan plan = fftw_plan_dft_r2c_2d(
1050 for (b = 0; b < L; ++b)
1060 for (a = 0; a < 2*L-1; ++a)
1061 for (g = 0; g < 2*N-1; ++g)
1062 fft_in[g + g_stride*(
1072 for (n = n_start; n <= n_stop; n += n_inc)
1074 for (m = -L+1; m <= L-1; ++m)
1076 int m_shift = m < 0 ? 2*L-1 : 0;
1077 Fmnb[b + bext_stride*(
1078 m + m_offset + m_stride*(
1080 fft_out[n + n_stride*(
1085 fftw_destroy_plan(plan);
1088 for (n = n_start; n <= n_stop; n += n_inc)
1089 for (m = -L+1; m <= L-1; ++m)
1090 for (b = L; b < 2*L-1; ++b)
1091 Fmnb[b + bext_stride*(
1092 m + m_offset + m_stride*(
1093 n + n_offset))] = 0.0;
1096 complex
double *Fmnm = calloc((2*L-1)*(2*L-1)*(2*N-1),
sizeof(*Fmnm));
1097 SO3_ERROR_MEM_ALLOC_CHECK(Fmnm);
1098 complex
double *inout = calloc(2*L-1,
sizeof(*inout));
1099 SO3_ERROR_MEM_ALLOC_CHECK(inout);
1101 plan = fftw_plan_dft_1d(
1106 for (n = n_start; n <= n_stop; n += n_inc)
1107 for (m = -L+1; m <= L-1; ++m)
1110 Fmnb + 0 + bext_stride*(
1111 m + m_offset + m_stride*(
1113 bext_stride*
sizeof(*Fmnb));
1117 for (mm = -L+1; mm <= L-1; ++mm)
1119 int mm_shift = mm < 0 ? 2*L-1 : 0;
1120 Fmnm[m + m_offset + m_stride*(
1121 mm + mm_offset + mm_stride*(
1123 inout[mm + mm_shift];
1126 fftw_destroy_plan(plan);
1130 for (n = n_start; n <= n_stop; n += n_inc)
1131 for (mm = -L+1; mm <= L-1; ++mm)
1132 for (m = -L+1; m <= L-1; ++m)
1133 Fmnm[m + m_offset + m_stride*(
1134 mm + mm_offset + mm_stride*(
1136 expsmm[mm + mm_offset];
1139 double *dl, *dl8 = NULL;
1140 dl = ssht_dl_calloc(L, SSHT_DL_QUARTER);
1141 SO3_ERROR_MEM_ALLOC_CHECK(dl);
1142 if (dl_method == SSHT_DL_RISBO)
1144 dl8 = ssht_dl_calloc(L, SSHT_DL_QUARTER_EXTENDED);
1145 SO3_ERROR_MEM_ALLOC_CHECK(dl8);
1147 int dl_offset = ssht_dl_get_offset(L, SSHT_DL_QUARTER);
1148 int dl_stride = ssht_dl_get_stride(L, SSHT_DL_QUARTER);
1149 for (n = 0; n <= N-1; ++n)
1150 for (el = n; el < L; ++el)
1151 for (m = -el; m <= el; ++m)
1158 for (el = L0; el < L; ++el)
1166 if (el != 0 && el == L0)
1168 for(eltmp = 0; eltmp <= L0; ++eltmp)
1169 ssht_dl_beta_risbo_eighth_table(dl8, SO3_PION2, L,
1170 SSHT_DL_QUARTER_EXTENDED,
1171 eltmp, sqrt_tbl, signs);
1172 ssht_dl_beta_risbo_fill_eighth2quarter_table(dl,
1175 SSHT_DL_QUARTER_EXTENDED,
1181 ssht_dl_beta_risbo_eighth_table(dl8, SO3_PION2, L,
1182 SSHT_DL_QUARTER_EXTENDED,
1183 el, sqrt_tbl, signs);
1184 ssht_dl_beta_risbo_fill_eighth2quarter_table(dl,
1187 SSHT_DL_QUARTER_EXTENDED,
1193 case SSHT_DL_TRAPANI:
1194 if (el != 0 && el == L0)
1196 for(eltmp = 0; eltmp <= L0; ++eltmp)
1197 ssht_dl_halfpi_trapani_eighth_table(dl, L,
1200 ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl, L,
1206 ssht_dl_halfpi_trapani_eighth_table(dl, L,
1209 ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl, L,
1216 SO3_ERROR_GENERIC(
"Invalid dl method");
1224 case SO3_N_MODE_ALL:
1226 n_stop =
MIN( N-1, el);
1229 case SO3_N_MODE_EVEN:
1231 n_stop =
MIN( N-1, el);
1235 case SO3_N_MODE_ODD:
1237 n_stop =
MIN( N-1, el);
1238 n_stop -= 1-n_stop%2;
1241 case SO3_N_MODE_MAXIMUM:
1256 SO3_ERROR_GENERIC(
"Invalid n-mode.");
1260 double elfactor = (2.0*el+1.0)/(8.0*SO3_PI*SO3_PI);
1264 for (mm = -el; mm <= el; ++mm)
1268 double elmmsign = signs[el] * signs[abs(mm)];
1270 for (n = n_start; n <= n_stop; n += n_inc)
1272 double mmsign = mm >= 0 ? 1.0 : signs[el] * signs[n];
1275 double elnmm_factor = mmsign * elfactor
1276 * dl[n + dl_offset + abs(mm)*dl_stride];
1278 for (m = -el; m <= el; ++m)
1280 mmsign = mm >= 0 ? 1.0 : signs[el] * signs[abs(m)];
1281 double elmsign = m >= 0 ? 1.0 : elmmsign;
1284 int mod = ((m-n)%4 + 4)%4;
1289 * dl[abs(m) + dl_offset + abs(mm)*dl_stride]
1290 * Fmnm[m + m_offset + m_stride*(
1291 mm + mm_offset + mm_stride*(
1300 if (dl_method == SSHT_DL_RISBO)
1310 printf(
"%sAdjoint inverse transform computed!\n", SO3_PROMPT);
1314 double *f,
const complex
double *flmn,
1315 const so3_parameters_t *parameters
1318 so3_sampling_t sampling;
1319 so3_storage_t storage;
1320 so3_n_mode_t n_mode;
1321 ssht_dl_method_t dl_method;
1325 L0 = parameters->L0;
1328 sampling = parameters->sampling_scheme;
1329 storage = parameters->storage;
1331 n_mode = parameters->n_mode;
1332 dl_method = parameters->dl_method;
1333 verbosity = parameters->verbosity;
1334 steerable = parameters->steerable;
1339 printf(
"%sComputing forward adjoint transform using MW sampling with\n", SO3_PROMPT);
1340 printf(
"%sparameters (L, N, reality) = (%d, %d, FALSE)\n", SO3_PROMPT, L, N);
1342 printf(
"%sUsing routine so3_adjoint_forward_direct with storage method %d...\n"
1348 int el, m, n, mm, a, b, g;
1350 int m_stride = 2*L-1;
1354 int mm_stride = 2*L-1;
1355 int mm_offset = L-1;
1356 int a_stride = 2*L-1;
1358 int bext_stride = 2*L-1;
1359 int g_stride = 2*N-1;
1361 complex
double* inout;
1364 double *sqrt_tbl = calloc(2*(L-1)+2,
sizeof(*sqrt_tbl));
1365 SO3_ERROR_MEM_ALLOC_CHECK(sqrt_tbl);
1366 double *signs = calloc(L+1,
sizeof(*signs));
1367 SO3_ERROR_MEM_ALLOC_CHECK(signs);
1368 complex
double *exps = calloc(4,
sizeof(*exps));
1369 SO3_ERROR_MEM_ALLOC_CHECK(exps);
1370 complex
double *expsmm = calloc(2*L-1,
sizeof(*expsmm));
1371 SO3_ERROR_MEM_ALLOC_CHECK(expsmm);
1374 for (el = 0; el <= 2*L-1; ++el)
1375 sqrt_tbl[el] = sqrt((
double)el);
1376 for (m = 0; m <= L-1; m += 2)
1382 for (i = 0; i < 4; ++i)
1383 exps[i] = cexp(I*SO3_PION2*i);
1384 for (mm = -L+1; mm <= L-1; ++mm)
1385 expsmm[mm + mm_offset] = cexp(I*mm*SSHT_PI/(2.0*L-1.0));
1390 complex
double *Gmnm = calloc((2*L-1)*(2*L-1)*N,
sizeof(*Gmnm));
1391 SO3_ERROR_MEM_ALLOC_CHECK(Gmnm);
1393 int n_start, n_stop, n_inc;
1396 double *dl = ssht_dl_calloc(L, SSHT_DL_QUARTER);
1397 SO3_ERROR_MEM_ALLOC_CHECK(dl);
1399 if (dl_method == SSHT_DL_RISBO)
1401 dl8 = ssht_dl_calloc(L, SSHT_DL_QUARTER_EXTENDED);
1402 SO3_ERROR_MEM_ALLOC_CHECK(dl8);
1404 int dl_offset = ssht_dl_get_offset(L, SSHT_DL_QUARTER);
1405 int dl_stride = ssht_dl_get_stride(L, SSHT_DL_QUARTER);
1407 complex
double *mn_factors = calloc((2*L-1)*(2*N-1),
sizeof *mn_factors);
1408 SO3_ERROR_MEM_ALLOC_CHECK(mn_factors);
1415 for (el = L0; el <= L-1; ++el)
1422 if (el != 0 && el == L0)
1424 for(eltmp = 0; eltmp <= L0; ++eltmp)
1425 ssht_dl_beta_risbo_eighth_table(
1429 SSHT_DL_QUARTER_EXTENDED,
1433 ssht_dl_beta_risbo_fill_eighth2quarter_table(dl,
1436 SSHT_DL_QUARTER_EXTENDED,
1442 ssht_dl_beta_risbo_eighth_table(
1446 SSHT_DL_QUARTER_EXTENDED,
1450 ssht_dl_beta_risbo_fill_eighth2quarter_table(
1454 SSHT_DL_QUARTER_EXTENDED,
1460 case SSHT_DL_TRAPANI:
1461 if (el != 0 && el == L0)
1463 for(eltmp = 0; eltmp <= L0; ++eltmp)
1464 ssht_dl_halfpi_trapani_eighth_table(
1470 ssht_dl_halfpi_trapani_fill_eighth2quarter_table(
1479 ssht_dl_halfpi_trapani_eighth_table(
1485 ssht_dl_halfpi_trapani_fill_eighth2quarter_table(
1495 SO3_ERROR_GENERIC(
"Invalid dl method");
1502 case SO3_N_MODE_ALL:
1504 n_stop =
MIN( N-1, el);
1507 case SO3_N_MODE_EVEN:
1509 n_stop =
MIN( N-1, el);
1513 case SO3_N_MODE_ODD:
1515 n_stop =
MIN( N-1, el);
1516 n_stop -= 1-n_stop%2;
1519 case SO3_N_MODE_MAXIMUM:
1534 SO3_ERROR_GENERIC(
"Invalid n-mode.");
1538 for (n = n_start; n <= n_stop; n += n_inc)
1539 for (m = -el; m <= el; ++m)
1543 int mod = ((n-m)%4 + 4)%4;
1544 mn_factors[m + m_offset + m_stride*(
1546 flmn[ind] * exps[mod];
1549 for (mm = 0; mm <= el; ++mm)
1553 double elmmsign = signs[el] * signs[mm];
1555 for (n = n_start; n <= n_stop; n += n_inc)
1558 double elnmm_factor = dl[n + dl_offset + mm*dl_stride];
1559 for (m = -el; m < 0; ++m)
1560 Gmnm[mm + mm_offset + mm_stride*(
1561 m + m_offset + m_stride*(
1564 * mn_factors[m + m_offset + m_stride*(
1566 * elmmsign * dl[-m + dl_offset + mm*dl_stride];
1567 for (m = 0; m <= el; ++m)
1568 Gmnm[mm + mm_offset + mm_stride*(
1569 m + m_offset + m_stride*(
1572 * mn_factors[m + m_offset + m_stride*(
1574 * dl[m + dl_offset + mm*dl_stride];
1581 if (dl_method == SSHT_DL_RISBO)
1587 case SO3_N_MODE_ALL:
1593 case SO3_N_MODE_EVEN:
1595 n_stop = ((N-1) % 2 == 0) ? N-1 : N-2;
1598 case SO3_N_MODE_ODD:
1600 n_stop = ((N-1) % 2 != 0) ? N-1 : N-2;
1603 case SO3_N_MODE_MAXIMUM:
1609 SO3_ERROR_GENERIC(
"Invalid n-mode.");
1613 for (n = n_start; n <= n_stop; n += n_inc)
1614 for (m = -L+1; m <= L-1; ++m)
1615 for (mm = -L+1; mm < 0; ++mm)
1616 Gmnm[mm + mm_offset + mm_stride*(
1617 m + m_offset + m_stride*(
1620 * Gmnm[-mm + mm_offset + mm_stride*(
1621 m + m_offset + m_stride*(
1626 complex
double *w = calloc(4*L-3,
sizeof(*w));
1627 SO3_ERROR_MEM_ALLOC_CHECK(w);
1628 int w_offset = 2*(L-1);
1629 for (mm = -2*(L-1); mm <= 2*(L-1); ++mm)
1633 complex
double *wr = calloc(4*L-3,
sizeof(*w));
1634 SO3_ERROR_MEM_ALLOC_CHECK(wr);
1635 inout = calloc(4*L-3,
sizeof(*inout));
1636 SO3_ERROR_MEM_ALLOC_CHECK(inout);
1637 fftw_plan plan_bwd = fftw_plan_dft_1d(
1642 fftw_plan plan_fwd = fftw_plan_dft_1d(
1650 for (mm = 1; mm <= 2*L-2; ++mm)
1651 inout[mm + w_offset] = w[mm - 2*(L-1) - 1 + w_offset];
1652 for (mm = -2*(L-1); mm <= 0; ++mm)
1653 inout[mm + w_offset] = w[mm + 2*(L-1) + w_offset];
1655 fftw_execute_dft(plan_bwd, inout, inout);
1658 for (mm = 0; mm <= 2*L-2; ++mm)
1659 wr[mm + w_offset] = inout[mm - 2*(L-1) + w_offset];
1660 for (mm = -2*(L-1); mm <= -1; ++mm)
1661 wr[mm + w_offset] = inout[mm + 2*(L-1) + 1 + w_offset];
1664 complex
double *Gmnm_pad = calloc(4*L-3,
sizeof(*Gmnm_pad));
1665 SO3_ERROR_MEM_ALLOC_CHECK(Gmnm_pad);
1666 complex
double *Fmnm = calloc((2*L-1)*(2*L-1)*N,
sizeof(*Fmnm));
1667 SO3_ERROR_MEM_ALLOC_CHECK(Fmnm);
1668 for (n = n_start; n <= n_stop; n += n_inc)
1669 for (m = -L+1; m <= L-1; ++m)
1673 for (mm = -2*(L-1); mm <= -L; ++mm)
1674 Gmnm_pad[mm+w_offset] = 0.0;
1675 for (mm = L; mm <= 2*(L-1); ++mm)
1676 Gmnm_pad[mm+w_offset] = 0.0;
1677 for (mm = -(L-1); mm <= L-1; ++mm)
1678 Gmnm_pad[mm + w_offset] =
1679 Gmnm[mm + mm_offset + mm_stride*(
1680 m + m_offset + m_stride*(
1684 for (mm = 1; mm <= 2*L-2; ++mm)
1685 inout[mm + w_offset] = Gmnm_pad[mm - 2*(L-1) - 1 + w_offset];
1686 for (mm = -2*(L-1); mm <= 0; ++mm)
1687 inout[mm + w_offset] = Gmnm_pad[mm + 2*(L-1) + w_offset];
1689 fftw_execute_dft(plan_bwd, inout, inout);
1691 for (mm = 0; mm <= 2*L-2; ++mm)
1692 Gmnm_pad[mm + w_offset] = inout[mm - 2*(L-1) + w_offset];
1693 for (mm = -2*(L-1); mm <= -1; ++mm)
1694 Gmnm_pad[mm + w_offset] = inout[mm + 2*(L-1) + 1 + w_offset];
1698 for (r = -2*(L-1); r <= 2*(L-1); ++r)
1699 Gmnm_pad[r + w_offset] *= wr[r + w_offset];
1702 for (mm = 1; mm <= 2*L-2; ++mm)
1703 inout[mm + w_offset] = Gmnm_pad[mm - 2*(L-1) - 1 + w_offset];
1704 for (mm = -2*(L-1); mm <= 0; ++mm)
1705 inout[mm + w_offset] = Gmnm_pad[mm + 2*(L-1) + w_offset];
1707 fftw_execute_dft(plan_fwd, inout, inout);
1709 for (mm = 0; mm <= 2*L-2; ++mm)
1710 Gmnm_pad[mm + w_offset] = inout[mm - 2*(L-1) + w_offset];
1711 for (mm = -2*(L-1); mm <= -1; ++mm)
1712 Gmnm_pad[mm + w_offset] = inout[mm + 2*(L-1) + 1 + w_offset];
1715 for (mm = -(L-1); mm <= L-1; ++mm)
1716 Fmnm[mm + mm_offset + mm_stride*(
1717 m + m_offset + m_stride*(
1719 Gmnm_pad[mm + w_offset]
1720 * 4.0 * SSHT_PI * SSHT_PI / (4.0*L-3.0);
1723 fftw_destroy_plan(plan_bwd);
1724 fftw_destroy_plan(plan_fwd);
1727 for (n = n_start; n <= n_stop; n += n_inc)
1728 for (m = -L+1; m <= L-1; ++m)
1729 for (mm = -L+1; mm <= L-1; ++mm)
1730 Fmnm[mm + mm_offset + mm_stride*(
1731 m + m_offset + m_stride*(
1733 expsmm[mm + mm_offset];
1736 complex
double *Fmnb = calloc((2*L-1)*(2*L-1)*N,
sizeof(*Fmnb));
1737 SO3_ERROR_MEM_ALLOC_CHECK(Fmnm);
1739 fftw_plan plan = fftw_plan_dft_1d(
1744 for (n = n_start; n <= n_stop; n += n_inc)
1745 for (m = -L+1; m <= L-1; ++m)
1748 for (mm = -L+1; mm <= L-1; ++mm)
1750 int mm_shift = mm < 0 ? 2*L-1 : 0;
1751 inout[mm + mm_shift] =
1752 Fmnm[mm + mm_offset + mm_stride*(
1753 m + m_offset + m_stride*(
1754 n + n_offset))] / (2.0*L-1.0);
1756 fftw_execute_dft(plan, inout, inout);
1757 memcpy(Fmnb + 0 + bext_stride*(
1758 m + m_offset + m_stride*(
1761 bext_stride*
sizeof(*Fmnb));
1765 fftw_destroy_plan(plan);
1771 for (n = n_start; n <= n_stop; n += n_inc)
1772 for (m = -L+1; m <= L-1; ++m)
1774 int signmn = signs[abs(m+n)%2];
1775 for (b = 0; b <= L-2; ++b)
1776 Fmnb[b + bext_stride*(
1777 m + m_offset + m_stride*(
1780 * Fmnb[(2*L-2-b) + bext_stride*(
1781 m + m_offset + m_stride*(
1786 complex
double *fft_in = calloc((2*L-1)*N,
sizeof(*fft_in));
1787 SO3_ERROR_MEM_ALLOC_CHECK(fft_in);
1788 double *fft_out = calloc((2*L-1)*(2*N-1),
sizeof(*fft_out));
1789 SO3_ERROR_MEM_ALLOC_CHECK(fft_out);
1791 plan = fftw_plan_dft_c2r_2d(
1796 double norm_factor = 1.0/(2.0*L-1.0)/(2.0*N-1.0);
1798 for (b = 0; b < L; ++b)
1801 for (n = n_start; n <= n_stop; n += n_inc)
1803 for (m = -L+1; m <= L-1; ++m)
1805 int m_shift = m < 0 ? 2*L-1 : 0;
1806 fft_in[n + n_stride*(
1808 Fmnb[b + bext_stride*(
1809 m + m_offset + m_stride*(
1810 n + n_offset))] * norm_factor;
1819 for (a = 0; a < 2*L-1; ++a)
1820 for (g = 0; g < 2*N-1; ++g)
1823 g))] = fft_out[g + g_stride*(
1827 fftw_destroy_plan(plan);