NFFT  3.4.1
nfsft.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2002, 2017 Jens Keiner, Stefan Kunis, Daniel Potts
3  *
4  * This program is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU General Public License as published by the Free Software
6  * Foundation; either version 2 of the License, or (at your option) any later
7  * version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12  * details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc., 51
16  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
25 #include "config.h"
26 
27 /* Include standard C headers. */
28 #include <math.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #ifdef HAVE_COMPLEX_H
32 #include <complex.h>
33 #endif
34 
35 #ifdef _OPENMP
36 #include <omp.h>
37 #endif
38 
39 /* Include NFFT3 utilities header. */
40 
41 /* Include NFFT3 library header. */
42 #include "nfft3.h"
43 
44 #include "infft.h"
45 
46 /* Include private associated Legendre functions header. */
47 #include "legendre.h"
48 
49 /* Include private API header. */
50 #include "api.h"
51 
52 
62 #define NFSFT_DEFAULT_NFFT_CUTOFF 6
63 
69 #define NFSFT_DEFAULT_THRESHOLD 1000
70 
76 #define NFSFT_BREAK_EVEN 5
77 
84 static struct nfsft_wisdom wisdom = {false,0U,-1,-1,0,0,0,0,0};
85 
108 static inline void c2e(nfsft_plan *plan)
109 {
110  int k;
111  int n;
112  double _Complex last;
113  double _Complex act;
114  double _Complex *xp;
115  double _Complex *xm;
116  int low;
117  int up;
118  int lowe;
119  int upe;
121  /* Set the first row to order to zero since it is unused. */
122  memset(plan->f_hat_intern,0U,(2*plan->N+2)*sizeof(double _Complex));
123 
124  /* Determine lower and upper bounds for loop processing even terms. */
125  lowe = -plan->N + (plan->N%2);
126  upe = -lowe;
127 
128  /* Process even terms. */
129  for (n = lowe; n <= upe; n += 2)
130  {
131  /* Compute new coefficients \f$\left(c_k^n\right)_{k=-M,\ldots,M}\f$ from
132  * old coefficients $\left(b_k^n\right)_{k=0,\ldots,M}$. */
133  xm = &(plan->f_hat_intern[NFSFT_INDEX(-1,n,plan)]);
134  xp = &(plan->f_hat_intern[NFSFT_INDEX(+1,n,plan)]);
135  for(k = 1; k <= plan->N; k++)
136  {
137  *xp *= 0.5;
138  *xm-- = *xp++;
139  }
140  /* Set the first coefficient in the array corresponding to this order to
141  * zero since it is unused. */
142  *xm = 0.0;
143  }
144 
145  /* Determine lower and upper bounds for loop processing odd terms. */
146  low = -plan->N + (1-plan->N%2);
147  up = -low;
148 
149  /* Process odd terms incorporating the additional sine term
150  * \f$\sin \vartheta\f$. */
151  for (n = low; n <= up; n += 2)
152  {
153  /* Compute new coefficients \f$\left(c_k^n\right)_{k=-M,\ldots,M}\f$ from
154  * old coefficients $\left(b_k^n\right)_{k=0,\ldots,M-1}$ incorporating
155  * the additional term \f$\sin \vartheta\f$. */
156  plan->f_hat_intern[NFSFT_INDEX(0,n,plan)] *= 2.0;
157  xp = &(plan->f_hat_intern[NFSFT_INDEX(-plan->N-1,n,plan)]);
158  /* Set the first coefficient in the array corresponding to this order to zero
159  * since it is unused. */
160  *xp++ = 0.0;
161  xm = &(plan->f_hat_intern[NFSFT_INDEX(plan->N,n,plan)]);
162  last = *xm;
163  *xm = 0.5 * _Complex_I * (0.5*xm[-1]);
164  *xp++ = -(*xm--);
165  for (k = plan->N-1; k > 0; k--)
166  {
167  act = *xm;
168  *xm = 0.5 * _Complex_I * (0.5*(xm[-1] - last));
169  *xp++ = -(*xm--);
170  last = act;
171  }
172  *xm = 0.0;
173  }
174 }
175 
186 static inline void c2e_transposed(nfsft_plan *plan)
187 {
188  int k;
189  int n;
190  double _Complex last;
191  double _Complex act;
192  double _Complex *xp;
193  double _Complex *xm;
194  int low;
195  int up;
196  int lowe;
197  int upe;
199  /* Determine lower and upper bounds for loop processing even terms. */
200  lowe = -plan->N + (plan->N%2);
201  upe = -lowe;
202 
203  /* Process even terms. */
204  for (n = lowe; n <= upe; n += 2)
205  {
206  /* Compute new coefficients \f$\left(b_k^n\right)_{k=0,\ldots,M}\f$ from
207  * old coefficients $\left(c_k^n\right)_{k=-M,\ldots,M}$. */
208  xm = &(plan->f_hat[NFSFT_INDEX(-1,n,plan)]);
209  xp = &(plan->f_hat[NFSFT_INDEX(+1,n,plan)]);
210  for(k = 1; k <= plan->N; k++)
211  {
212  *xp += *xm--;
213  *xp++ *= 0.5;;
214  }
215  }
216 
217  /* Determine lower and upper bounds for loop processing odd terms. */
218  low = -plan->N + (1-plan->N%2);
219  up = -low;
220 
221  /* Process odd terms. */
222  for (n = low; n <= up; n += 2)
223  {
224  /* Compute new coefficients \f$\left(b_k^n\right)_{k=0,\ldots,M-1}\f$ from
225  * old coefficients $\left(c_k^n\right)_{k=0,\ldots,M-1}$. */
226  xm = &(plan->f_hat[NFSFT_INDEX(-1,n,plan)]);
227  xp = &(plan->f_hat[NFSFT_INDEX(+1,n,plan)]);
228  for(k = 1; k <= plan->N; k++)
229  {
230  *xp++ -= *xm--;
231  }
232 
233  plan->f_hat[NFSFT_INDEX(0,n,plan)] =
234  -0.25*_Complex_I*plan->f_hat[NFSFT_INDEX(1,n,plan)];
235  last = plan->f_hat[NFSFT_INDEX(1,n,plan)];
236  plan->f_hat[NFSFT_INDEX(1,n,plan)] =
237  -0.25*_Complex_I*plan->f_hat[NFSFT_INDEX(2,n,plan)];
238 
239  xp = &(plan->f_hat[NFSFT_INDEX(2,n,plan)]);
240  for (k = 2; k < plan->N; k++)
241  {
242  act = *xp;
243  *xp = -0.25 * _Complex_I * (xp[1] - last);
244  xp++;
245  last = act;
246  }
247  *xp = 0.25 * _Complex_I * last;
248 
249  plan->f_hat[NFSFT_INDEX(0,n,plan)] *= 2.0;
250  }
251 }
252 
253 void nfsft_init(nfsft_plan *plan, int N, int M)
254 {
255  /* Call nfsft_init_advanced with default flags. */
258 }
259 
260 void nfsft_init_advanced(nfsft_plan* plan, int N, int M,
261  unsigned int flags)
262 {
263  /* Call nfsft_init_guru with the flags and default NFFT cut-off. */
264  nfsft_init_guru(plan, N, M, flags, PRE_PHI_HUT | PRE_PSI | FFTW_INIT | NFFT_OMP_BLOCKWISE_ADJOINT |
266 }
267 
268 void nfsft_init_guru(nfsft_plan *plan, int N, int M, unsigned int flags,
269  unsigned int nfft_flags, int nfft_cutoff)
270 {
271  int *nfft_size; /*< NFFT size */
272  int *fftw_size; /*< FFTW size */
273 
274  /* Save the flags in the plan. */
275  plan->flags = flags;
276 
277  /* Save the bandwidth N and the number of samples M in the plan. */
278  plan->N = N;
279  plan->M_total = M;
280 
281  /* Calculate the next greater power of two with respect to the bandwidth N
282  * and the corresponding exponent. */
283  //next_power_of_2_exp_int(plan->N,&plan->NPT,&plan->t);
284 
285  /* Save length of array of Fourier coefficients. Owing to the data layout the
286  * length is (2N+2)(2N+2) */
287  plan->N_total = (2*plan->N+2)*(2*plan->N+2);
288 
289  /* Allocate memory for auxilliary array of spherical Fourier coefficients,
290  * if neccesary. */
291  if (plan->flags & NFSFT_PRESERVE_F_HAT)
292  {
293  plan->f_hat_intern = (double _Complex*) nfft_malloc(plan->N_total*
294  sizeof(double _Complex));
295  }
296 
297  /* Allocate memory for spherical Fourier coefficients, if neccesary. */
298  if (plan->flags & NFSFT_MALLOC_F_HAT)
299  {
300  plan->f_hat = (double _Complex*) nfft_malloc(plan->N_total*
301  sizeof(double _Complex));
302  }
303 
304  /* Allocate memory for samples, if neccesary. */
305  if (plan->flags & NFSFT_MALLOC_F)
306  {
307  plan->f = (double _Complex*) nfft_malloc(plan->M_total*sizeof(double _Complex));
308  }
309 
310  /* Allocate memory for nodes, if neccesary. */
311  if (plan->flags & NFSFT_MALLOC_X)
312  {
313  plan->x = (double*) nfft_malloc(plan->M_total*2*sizeof(double));
314  }
315 
316  /* Check if fast algorithm is activated. */
317  if (plan->flags & NFSFT_NO_FAST_ALGORITHM)
318  {
319  }
320  else
321  {
322  nfft_size = (int*)nfft_malloc(2*sizeof(int));
323  fftw_size = (int*)nfft_malloc(2*sizeof(int));
324 
326  nfft_size[0] = 2*plan->N+2;
327  nfft_size[1] = 2*plan->N+2;
328  fftw_size[0] = 4*plan->N;
329  fftw_size[1] = 4*plan->N;
330 
332  nfft_init_guru(&plan->plan_nfft, 2, nfft_size, plan->M_total, fftw_size,
333  nfft_cutoff, nfft_flags,
334  FFTW_ESTIMATE | FFTW_DESTROY_INPUT);
335 
336  /* Assign angle array. */
337  plan->plan_nfft.x = plan->x;
338  /* Assign result array. */
339  plan->plan_nfft.f = plan->f;
340  /* Assign Fourier coefficients array. */
341  plan->plan_nfft.f_hat = plan->f_hat;
342 
345  /* Precompute. */
346  //nfft_precompute_one_psi(&plan->plan_nfft);
347 
348  /* Free auxilliary arrays. */
349  nfft_free(nfft_size);
350  nfft_free(fftw_size);
351  }
352 
353  plan->mv_trafo = (void (*) (void* ))nfsft_trafo;
354  plan->mv_adjoint = (void (*) (void* ))nfsft_adjoint;
355 }
356 
357 void nfsft_precompute(int N, double kappa, unsigned int nfsft_flags,
358  unsigned int fpt_flags)
359 {
360  int n; /*< The order n */
361 
362  /* Check if already initialized. */
363  if (wisdom.initialized == true)
364  {
365  return;
366  }
367 
368 #ifdef _OPENMP
369  #pragma omp parallel default(shared)
370  {
371  int nthreads = omp_get_num_threads();
372  int threadid = omp_get_thread_num();
373  #pragma omp single
374  {
375  wisdom.nthreads = nthreads;
376  }
377  }
378 #endif
379 
380  /* Save the precomputation flags. */
381  wisdom.flags = nfsft_flags;
382 
383  /* Compute and save N_max = 2^{\ceil{log_2 N}} as next greater
384  * power of two with respect to N. */
385  X(next_power_of_2_exp_int)(N,&wisdom.N_MAX,&wisdom.T_MAX);
386 
387  /* Check, if precomputation for direct algorithms needs to be performed. */
388  if (wisdom.flags & NFSFT_NO_DIRECT_ALGORITHM)
389  {
390  wisdom.alpha = NULL;
391  wisdom.beta = NULL;
392  wisdom.gamma = NULL;
393  }
394  else
395  {
396  /* Allocate memory for three-term recursion coefficients. */
397  wisdom.alpha = (double*) nfft_malloc((wisdom.N_MAX+1)*(wisdom.N_MAX+2)*
398  sizeof(double));
399  wisdom.beta = (double*) nfft_malloc((wisdom.N_MAX+1)*(wisdom.N_MAX+2)*
400  sizeof(double));
401  wisdom.gamma = (double*) nfft_malloc((wisdom.N_MAX+1)*(wisdom.N_MAX+2)*
402  sizeof(double));
404  /* Compute three-term recurrence coefficients alpha_k^n, beta_k^n, and
405  * gamma_k^n. */
406  alpha_al_all(wisdom.alpha,wisdom.N_MAX);
407  beta_al_all(wisdom.beta,wisdom.N_MAX);
408  gamma_al_all(wisdom.gamma,wisdom.N_MAX);
409  }
410 
411  /* Check, if precomputation for fast algorithms needs to be performed. */
412  if (wisdom.flags & NFSFT_NO_FAST_ALGORITHM)
413  {
414  }
415  else if (wisdom.N_MAX >= NFSFT_BREAK_EVEN)
416  {
417  /* Precompute data for DPT/FPT. */
418 
419  /* Check, if recursion coefficients have already been calculated. */
420  if (wisdom.alpha != NULL)
421  {
422 #ifdef _OPENMP
423  #pragma omp parallel default(shared) private(n)
424  {
425  int nthreads = omp_get_num_threads();
426  int threadid = omp_get_thread_num();
427  #pragma omp single
428  {
429  wisdom.nthreads = nthreads;
430  wisdom.set_threads = (fpt_set*) nfft_malloc(nthreads*sizeof(fpt_set));
431  }
432 
433  wisdom.set_threads[threadid] = fpt_init(wisdom.N_MAX+1, wisdom.T_MAX,
434  fpt_flags | FPT_AL_SYMMETRY | FPT_PERSISTENT_DATA);
435  for (n = 0; n <= wisdom.N_MAX; n++)
436  fpt_precompute(wisdom.set_threads[threadid],n,&wisdom.alpha[ROW(n)],
437  &wisdom.beta[ROW(n)], &wisdom.gamma[ROW(n)],n,kappa);
438  }
439 
440 #else
441  /* Use the recursion coefficients to precompute FPT data using persistent
442  * arrays. */
443  wisdom.set = fpt_init(wisdom.N_MAX+1, wisdom.T_MAX,
444  fpt_flags | FPT_AL_SYMMETRY | FPT_PERSISTENT_DATA);
445  for (n = 0; n <= wisdom.N_MAX; n++)
446  {
447  /*fprintf(stderr,"%d\n",n);
448  fflush(stderr);*/
449  /* Precompute data for FPT transformation for order n. */
450  fpt_precompute(wisdom.set,n,&wisdom.alpha[ROW(n)],&wisdom.beta[ROW(n)],
451  &wisdom.gamma[ROW(n)],n,kappa);
452  }
453 #endif
454  }
455  else
456  {
457 #ifdef _OPENMP
458  #pragma omp parallel default(shared) private(n)
459  {
460  double *alpha, *beta, *gamma;
461  int nthreads = omp_get_num_threads();
462  int threadid = omp_get_thread_num();
463  #pragma omp single
464  {
465  wisdom.nthreads = nthreads;
466  wisdom.set_threads = (fpt_set*) nfft_malloc(nthreads*sizeof(fpt_set));
467  }
468 
469  alpha = (double*) nfft_malloc((wisdom.N_MAX+2)*sizeof(double));
470  beta = (double*) nfft_malloc((wisdom.N_MAX+2)*sizeof(double));
471  gamma = (double*) nfft_malloc((wisdom.N_MAX+2)*sizeof(double));
472  wisdom.set_threads[threadid] = fpt_init(wisdom.N_MAX+1, wisdom.T_MAX,
473  fpt_flags | FPT_AL_SYMMETRY);
474 
475  for (n = 0; n <= wisdom.N_MAX; n++)
476  {
477  alpha_al_row(alpha,wisdom.N_MAX,n);
478  beta_al_row(beta,wisdom.N_MAX,n);
479  gamma_al_row(gamma,wisdom.N_MAX,n);
480 
481  /* Precompute data for FPT transformation for order n. */
482  fpt_precompute(wisdom.set_threads[threadid],n,alpha,beta,gamma,n,
483  kappa);
484  }
485  /* Free auxilliary arrays. */
486  nfft_free(alpha);
487  nfft_free(beta);
488  nfft_free(gamma);
489  }
490 #else
491  /* Allocate memory for three-term recursion coefficients. */
492  wisdom.alpha = (double*) nfft_malloc((wisdom.N_MAX+2)*sizeof(double));
493  wisdom.beta = (double*) nfft_malloc((wisdom.N_MAX+2)*sizeof(double));
494  wisdom.gamma = (double*) nfft_malloc((wisdom.N_MAX+2)*sizeof(double));
495  wisdom.set = fpt_init(wisdom.N_MAX+1, wisdom.T_MAX,
496  fpt_flags | FPT_AL_SYMMETRY);
497  for (n = 0; n <= wisdom.N_MAX; n++)
498  {
499  /*fprintf(stderr,"%d NO_DIRECT\n",n);
500  fflush(stderr);*/
501  /* Compute three-term recurrence coefficients alpha_k^n, beta_k^n, and
502  * gamma_k^n. */
503  alpha_al_row(wisdom.alpha,wisdom.N_MAX,n);
504  beta_al_row(wisdom.beta,wisdom.N_MAX,n);
505  gamma_al_row(wisdom.gamma,wisdom.N_MAX,n);
506 
507  /* Precompute data for FPT transformation for order n. */
508  fpt_precompute(wisdom.set,n,wisdom.alpha,wisdom.beta,wisdom.gamma,n,
509  kappa);
510  }
511  /* Free auxilliary arrays. */
512  nfft_free(wisdom.alpha);
513  nfft_free(wisdom.beta);
514  nfft_free(wisdom.gamma);
515 #endif
516  wisdom.alpha = NULL;
517  wisdom.beta = NULL;
518  wisdom.gamma = NULL;
519  }
520  }
521 
522  /* Wisdom has been initialised. */
523  wisdom.initialized = true;
524 }
525 
526 void nfsft_forget(void)
527 {
528  /* Check if wisdom has been initialised. */
529  if (wisdom.initialized == false)
530  {
531  /* Nothing to do. */
532  return;
533  }
534 
535  /* Check, if precomputation for direct algorithms has been performed. */
536  if (wisdom.flags & NFSFT_NO_DIRECT_ALGORITHM)
537  {
538  }
539  else
540  {
541  /* Free arrays holding three-term recurrence coefficients. */
542  nfft_free(wisdom.alpha);
543  nfft_free(wisdom.beta);
544  nfft_free(wisdom.gamma);
545  wisdom.alpha = NULL;
546  wisdom.beta = NULL;
547  wisdom.gamma = NULL;
548  }
549 
550  /* Check, if precomputation for fast algorithms has been performed. */
551  if (wisdom.flags & NFSFT_NO_FAST_ALGORITHM)
552  {
553  }
554  else if (wisdom.N_MAX >= NFSFT_BREAK_EVEN)
555  {
556 #ifdef _OPENMP
557  int k;
558  for (k = 0; k < wisdom.nthreads; k++)
559  fpt_finalize(wisdom.set_threads[k]);
560  nfft_free(wisdom.set_threads);
561 #else
562  /* Free precomputed data for FPT transformation. */
563  fpt_finalize(wisdom.set);
564 #endif
565  }
566 
567  /* Wisdom is now uninitialised. */
568  wisdom.initialized = false;
569 }
570 
571 
573 {
574  if (!plan)
575  return;
576 
577  /* Finalise the nfft plan. */
578  nfft_finalize(&plan->plan_nfft);
579 
580  /* De-allocate memory for auxilliary array of spherical Fourier coefficients,
581  * if neccesary. */
582  if (plan->flags & NFSFT_PRESERVE_F_HAT)
583  {
584  nfft_free(plan->f_hat_intern);
585  }
586 
587  /* De-allocate memory for spherical Fourier coefficients, if necessary. */
588  if (plan->flags & NFSFT_MALLOC_F_HAT)
589  {
590  //fprintf(stderr,"deallocating f_hat\n");
591  nfft_free(plan->f_hat);
592  }
593 
594  /* De-allocate memory for samples, if neccesary. */
595  if (plan->flags & NFSFT_MALLOC_F)
596  {
597  //fprintf(stderr,"deallocating f\n");
598  nfft_free(plan->f);
599  }
600 
601  /* De-allocate memory for nodes, if neccesary. */
602  if (plan->flags & NFSFT_MALLOC_X)
603  {
604  //fprintf(stderr,"deallocating x\n");
605  nfft_free(plan->x);
606  }
607 }
608 
609 void nfsft_trafo_direct(nfsft_plan *plan)
610 {
611  int m; /*< The node index */
612  int k; /*< The degree k */
613  int n; /*< The order n */
614  int n_abs; /*< The absolute value of the order n, ie n_abs = |n| */
615  double *alpha; /*< Pointer to current three-term recurrence
616  coefficient alpha_k^n for associated Legendre
617  functions P_k^n */
618  double *gamma; /*< Pointer to current three-term recurrence
619  coefficient beta_k^n for associated Legendre
620  functions P_k^n */
621  double _Complex *a; /*< Pointer to auxilliary array for Clenshaw algor. */
622  double _Complex it1; /*< Auxilliary variable for Clenshaw algorithm */
623  double _Complex it2; /*< Auxilliary variable for Clenshaw algorithm */
624  double _Complex temp; /*< Auxilliary variable for Clenshaw algorithm */
625  double _Complex f_m; /*< The final function value f_m = f(x_m) for a
626  single node. */
627  double stheta; /*< Current angle theta for Clenshaw algorithm */
628  double sphi; /*< Current angle phi for Clenshaw algorithm */
629 
630 #ifdef MEASURE_TIME
631  plan->MEASURE_TIME_t[0] = 0.0;
632  plan->MEASURE_TIME_t[1] = 0.0;
633  plan->MEASURE_TIME_t[2] = 0.0;
634 #endif
635 
636  if (wisdom.flags & NFSFT_NO_DIRECT_ALGORITHM)
637  {
638  return;
639  }
640 
641  /* Copy spherical Fourier coefficients, if necessary. */
642  if (plan->flags & NFSFT_PRESERVE_F_HAT)
643  {
644  memcpy(plan->f_hat_intern,plan->f_hat,plan->N_total*
645  sizeof(double _Complex));
646  }
647  else
648  {
649  plan->f_hat_intern = plan->f_hat;
650  }
651 
652  /* Check, if we compute with L^2-normalized spherical harmonics. If so,
653  * multiply spherical Fourier coefficients with corresponding normalization
654  * weight. */
655  if (plan->flags & NFSFT_NORMALIZED)
656  {
657  /* Traverse Fourier coefficients array. */
658 #ifdef _OPENMP
659  #pragma omp parallel for default(shared) private(k,n)
660 #endif
661  for (k = 0; k <= plan->N; k++)
662  {
663  for (n = -k; n <= k; n++)
664  {
665  /* Multiply with normalization weight. */
666  plan->f_hat_intern[NFSFT_INDEX(k,n,plan)] *=
667  sqrt((2*k+1)/(4.0*KPI));
668  }
669  }
670  }
671 
672  /* Distinguish by bandwidth M. */
673  if (plan->N == 0)
674  {
675  /* N = 0 */
676 
677  /* Constant function */
678  for (m = 0; m < plan->M_total; m++)
679  {
680  plan->f[m] = plan->f_hat_intern[NFSFT_INDEX(0,0,plan)];
681  }
682  }
683  else
684  {
685  /* N > 0 */
686 
687  /* Evaluate
688  * \sum_{k=0}^N \sum_{n=-k}^k a_k^n P_k^{|n|}(cos theta_m) e^{i n phi_m}
689  * = \sum_{n=-N}^N \sum_{k=|n|}^N a_k^n P_k^{|n|}(cos theta_m)
690  * e^{i n phi_m}.
691  */
692 #ifdef _OPENMP
693  #pragma omp parallel for default(shared) private(m,stheta,sphi,f_m,n,a,n_abs,alpha,gamma,it2,it1,k,temp)
694 #endif
695  for (m = 0; m < plan->M_total; m++)
696  {
697  /* Scale angle theta from [0,1/2] to [0,pi] and apply cosine. */
698  stheta = cos(2.0*KPI*plan->x[2*m+1]);
699  /* Scale angle phi from [-1/2,1/2] to [-pi,pi]. */
700  sphi = 2.0*KPI*plan->x[2*m];
701 
702  /* Initialize result for current node. */
703  f_m = 0.0;
704 
705  /* For n = -N,...,N, evaluate
706  * b_n := \sum_{k=|n|}^N a_k^n P_k^{|n|}(cos theta_m)
707  * using Clenshaw's algorithm.
708  */
709  for (n = -plan->N; n <= plan->N; n++)
710  {
711  /* Get pointer to Fourier coefficients vector for current order n. */
712  a = &(plan->f_hat_intern[NFSFT_INDEX(0,n,plan)]);
713 
714  /* Take absolute value of n. */
715  n_abs = abs(n);
716 
717  /* Get pointers to three-term recurrence coefficients arrays. */
718  alpha = &(wisdom.alpha[ROW(n_abs)]);
719  gamma = &(wisdom.gamma[ROW(n_abs)]);
720 
721  /* Clenshaw's algorithm */
722  it2 = a[plan->N];
723  it1 = a[plan->N-1];
724  for (k = plan->N; k > n_abs + 1; k--)
725  {
726  temp = a[k-2] + it2 * gamma[k];
727  it2 = it1 + it2 * alpha[k] * stheta;
728  it1 = temp;
729  }
730 
731  /* Compute final step if neccesary. */
732  if (n_abs < plan->N)
733  {
734  it2 = it1 + it2 * wisdom.alpha[ROWK(n_abs)+1] * stheta;
735  }
736 
737  /* Compute final result by multiplying the fixed part
738  * gamma_|n| (1-cos^2(theta))^{|n|/2}
739  * for order n and the exponential part
740  * e^{i n phi}
741  * and add the result to f_m.
742  */
743  f_m += it2 * wisdom.gamma[ROW(n_abs)] *
744  pow(1- stheta * stheta, 0.5*n_abs) * cexp(_Complex_I*n*sphi);
745  }
746 
747  /* Write result f_m for current node to array f. */
748  plan->f[m] = f_m;
749  }
750  }
751 }
752 
753 void nfsft_adjoint_direct(nfsft_plan *plan)
754 {
755  int m; /*< The node index */
756  int k; /*< The degree k */
757  int n; /*< The order n */
758  int n_abs; /*< The absolute value of the order n, ie n_abs = |n| */
759  double *alpha; /*< Pointer to current three-term recurrence
760  coefficient alpha_k^n for associated Legendre
761  functions P_k^n */
762  double *gamma; /*< Pointer to current three-term recurrence
763  coefficient beta_k^n for associated Legendre
764  functions P_k^n */
765  double _Complex it1; /*< Auxilliary variable for Clenshaw algorithm */
766  double _Complex it2; /*< Auxilliary variable for Clenshaw algorithm */
767  double _Complex temp; /*< Auxilliary variable for Clenshaw algorithm */
768  double stheta; /*< Current angle theta for Clenshaw algorithm */
769  double sphi; /*< Current angle phi for Clenshaw algorithm */
770 
771 #ifdef MEASURE_TIME
772  plan->MEASURE_TIME_t[0] = 0.0;
773  plan->MEASURE_TIME_t[1] = 0.0;
774  plan->MEASURE_TIME_t[2] = 0.0;
775 #endif
776 
777  if (wisdom.flags & NFSFT_NO_DIRECT_ALGORITHM)
778  {
779  return;
780  }
781 
782  /* Initialise spherical Fourier coefficients array with zeros. */
783  memset(plan->f_hat,0U,plan->N_total*sizeof(double _Complex));
784 
785  /* Distinguish by bandwidth N. */
786  if (plan->N == 0)
787  {
788  /* N == 0 */
789 
790  /* Constant function */
791  for (m = 0; m < plan->M_total; m++)
792  {
793  plan->f_hat[NFSFT_INDEX(0,0,plan)] += plan->f[m];
794  }
795  }
796  else
797  {
798  /* N > 0 */
799 
800 #ifdef _OPENMP
801  /* Traverse all orders n. */
802  #pragma omp parallel for default(shared) private(n,n_abs,alpha,gamma,m,stheta,sphi,it2,it1,k,temp)
803  for (n = -plan->N; n <= plan->N; n++)
804  {
805  /* Take absolute value of n. */
806  n_abs = abs(n);
807 
808  /* Get pointers to three-term recurrence coefficients arrays. */
809  alpha = &(wisdom.alpha[ROW(n_abs)]);
810  gamma = &(wisdom.gamma[ROW(n_abs)]);
811 
812  /* Traverse all nodes. */
813  for (m = 0; m < plan->M_total; m++)
814  {
815  /* Scale angle theta from [0,1/2] to [0,pi] and apply cosine. */
816  stheta = cos(2.0*KPI*plan->x[2*m+1]);
817  /* Scale angle phi from [-1/2,1/2] to [-pi,pi]. */
818  sphi = 2.0*KPI*plan->x[2*m];
819 
820  /* Transposed Clenshaw algorithm */
821 
822  /* Initial step */
823  it1 = plan->f[m] * wisdom.gamma[ROW(n_abs)] *
824  pow(1 - stheta * stheta, 0.5*n_abs) * cexp(-_Complex_I*n*sphi);
825  plan->f_hat[NFSFT_INDEX(n_abs,n,plan)] += it1;
826  it2 = 0.0;
827 
828  if (n_abs < plan->N)
829  {
830  it2 = it1 * wisdom.alpha[ROWK(n_abs)+1] * stheta;
831  plan->f_hat[NFSFT_INDEX(n_abs+1,n,plan)] += it2;
832  }
833 
834  /* Loop for transposed Clenshaw algorithm */
835  for (k = n_abs+2; k <= plan->N; k++)
836  {
837  temp = it2;
838  it2 = alpha[k] * stheta * it2 + gamma[k] * it1;
839  it1 = temp;
840  plan->f_hat[NFSFT_INDEX(k,n,plan)] += it2;
841  }
842  }
843  }
844 #else
845  /* Traverse all nodes. */
846  for (m = 0; m < plan->M_total; m++)
847  {
848  /* Scale angle theta from [0,1/2] to [0,pi] and apply cosine. */
849  stheta = cos(2.0*KPI*plan->x[2*m+1]);
850  /* Scale angle phi from [-1/2,1/2] to [-pi,pi]. */
851  sphi = 2.0*KPI*plan->x[2*m];
852 
853  /* Traverse all orders n. */
854  for (n = -plan->N; n <= plan->N; n++)
855  {
856  /* Take absolute value of n. */
857  n_abs = abs(n);
858 
859  /* Get pointers to three-term recurrence coefficients arrays. */
860  alpha = &(wisdom.alpha[ROW(n_abs)]);
861  gamma = &(wisdom.gamma[ROW(n_abs)]);
862 
863  /* Transposed Clenshaw algorithm */
864 
865  /* Initial step */
866  it1 = plan->f[m] * wisdom.gamma[ROW(n_abs)] *
867  pow(1 - stheta * stheta, 0.5*n_abs) * cexp(-_Complex_I*n*sphi);
868  plan->f_hat[NFSFT_INDEX(n_abs,n,plan)] += it1;
869  it2 = 0.0;
870 
871  if (n_abs < plan->N)
872  {
873  it2 = it1 * wisdom.alpha[ROWK(n_abs)+1] * stheta;
874  plan->f_hat[NFSFT_INDEX(n_abs+1,n,plan)] += it2;
875  }
876 
877  /* Loop for transposed Clenshaw algorithm */
878  for (k = n_abs+2; k <= plan->N; k++)
879  {
880  temp = it2;
881  it2 = alpha[k] * stheta * it2 + gamma[k] * it1;
882  it1 = temp;
883  plan->f_hat[NFSFT_INDEX(k,n,plan)] += it2;
884  }
885  }
886  }
887 #endif
888  }
889 
890  /* Check, if we compute with L^2-normalized spherical harmonics. If so,
891  * multiply spherical Fourier coefficients with corresponding normalization
892  * weight. */
893  if (plan->flags & NFSFT_NORMALIZED)
894  {
895  /* Traverse Fourier coefficients array. */
896 #ifdef _OPENMP
897  #pragma omp parallel for default(shared) private(k,n)
898 #endif
899  for (k = 0; k <= plan->N; k++)
900  {
901  for (n = -k; n <= k; n++)
902  {
903  /* Multiply with normalization weight. */
904  plan->f_hat[NFSFT_INDEX(k,n,plan)] *=
905  sqrt((2*k+1)/(4.0*KPI));
906  }
907  }
908  }
909 
910  /* Set unused coefficients to zero. */
911  if (plan->flags & NFSFT_ZERO_F_HAT)
912  {
913  for (n = -plan->N; n <= plan->N+1; n++)
914  {
915  memset(&plan->f_hat[NFSFT_INDEX(-plan->N-1,n,plan)],0U,
916  (plan->N+1+abs(n))*sizeof(double _Complex));
917  }
918  }
919 }
920 
922 {
923  int k; /*< The degree k */
924  int n; /*< The order n */
925 #ifdef MEASURE_TIME
926  ticks t0, t1;
927 #endif
928  #ifdef DEBUG
929  double t, t_pre, t_nfft, t_fpt, t_c2e, t_norm;
930  t_pre = 0.0;
931  t_norm = 0.0;
932  t_fpt = 0.0;
933  t_c2e = 0.0;
934  t_nfft = 0.0;
935  #endif
936 
937 #ifdef MEASURE_TIME
938  plan->MEASURE_TIME_t[0] = 0.0;
939  plan->MEASURE_TIME_t[1] = 0.0;
940  plan->MEASURE_TIME_t[2] = 0.0;
941 #endif
942 
943  if (wisdom.flags & NFSFT_NO_FAST_ALGORITHM)
944  {
945  return;
946  }
947 
948  /* Check, if precomputation was done and that the bandwidth N is not too
949  * big.
950  */
951  if (wisdom.initialized == 0 || plan->N > wisdom.N_MAX)
952  {
953  return;
954  }
955 
956  /* Check, if slow transformation should be used due to small bandwidth. */
957  if (plan->N < NFSFT_BREAK_EVEN)
958  {
959  /* Use NDSFT. */
960  nfsft_trafo_direct(plan);
961  }
962 
963  /* Check for correct value of the bandwidth N. */
964  else if (plan->N <= wisdom.N_MAX)
965  {
966  /* Copy spherical Fourier coefficients, if necessary. */
967  if (plan->flags & NFSFT_PRESERVE_F_HAT)
968  {
969  memcpy(plan->f_hat_intern,plan->f_hat,plan->N_total*
970  sizeof(double _Complex));
971  }
972  else
973  {
974  plan->f_hat_intern = plan->f_hat;
975  }
976 
977  /* Propagate pointer values to the internal NFFT plan to assure
978  * consistency. Pointers may have been modified externally.
979  */
980  plan->plan_nfft.x = plan->x;
981  plan->plan_nfft.f = plan->f;
982  plan->plan_nfft.f_hat = plan->f_hat_intern;
983 
984  /* Check, if we compute with L^2-normalized spherical harmonics. If so,
985  * multiply spherical Fourier coefficients with corresponding normalization
986  * weight. */
987  if (plan->flags & NFSFT_NORMALIZED)
988  {
989  /* Traverse Fourier coefficients array. */
990 #ifdef _OPENMP
991  #pragma omp parallel for default(shared) private(k,n)
992 #endif
993  for (k = 0; k <= plan->N; k++)
994  {
995  for (n = -k; n <= k; n++)
996  {
997  /* Multiply with normalization weight. */
998  plan->f_hat_intern[NFSFT_INDEX(k,n,plan)] *=
999  sqrt((2*k+1)/(4.0*KPI));
1000  }
1001  }
1002  }
1003 
1004 #ifdef MEASURE_TIME
1005  t0 = getticks();
1006 #endif
1007  /* Check, which polynomial transform algorithm should be used. */
1008  if (plan->flags & NFSFT_USE_DPT)
1009  {
1010 #ifdef _OPENMP
1011  #pragma omp parallel for default(shared) private(n) num_threads(wisdom.nthreads)
1012  for (n = -plan->N; n <= plan->N; n++)
1013  fpt_trafo_direct(wisdom.set_threads[omp_get_thread_num()],abs(n),
1014  &plan->f_hat_intern[NFSFT_INDEX(abs(n),n,plan)],
1015  &plan->f_hat_intern[NFSFT_INDEX(0,n,plan)],
1016  plan->N,0U);
1017 #else
1018  /* Use direct discrete polynomial transform DPT. */
1019  for (n = -plan->N; n <= plan->N; n++)
1020  {
1021  //fprintf(stderr,"nfsft_trafo: n = %d\n",n);
1022  //fflush(stderr);
1023  fpt_trafo_direct(wisdom.set,abs(n),
1024  &plan->f_hat_intern[NFSFT_INDEX(abs(n),n,plan)],
1025  &plan->f_hat_intern[NFSFT_INDEX(0,n,plan)],
1026  plan->N,0U);
1027  }
1028 #endif
1029  }
1030  else
1031  {
1032 #ifdef _OPENMP
1033  #pragma omp parallel for default(shared) private(n) num_threads(wisdom.nthreads)
1034  for (n = -plan->N; n <= plan->N; n++)
1035  fpt_trafo(wisdom.set_threads[omp_get_thread_num()],abs(n),
1036  &plan->f_hat_intern[NFSFT_INDEX(abs(n),n,plan)],
1037  &plan->f_hat_intern[NFSFT_INDEX(0,n,plan)],
1038  plan->N,0U);
1039 #else
1040  /* Use fast polynomial transform FPT. */
1041  for (n = -plan->N; n <= plan->N; n++)
1042  {
1043  //fprintf(stderr,"nfsft_trafo: n = %d\n",n);
1044  //fflush(stderr);
1045  fpt_trafo(wisdom.set,abs(n),
1046  &plan->f_hat_intern[NFSFT_INDEX(abs(n),n,plan)],
1047  &plan->f_hat_intern[NFSFT_INDEX(0,n,plan)],
1048  plan->N,0U);
1049  }
1050 #endif
1051  }
1052 #ifdef MEASURE_TIME
1053  t1 = getticks();
1054  plan->MEASURE_TIME_t[0] = nfft_elapsed_seconds(t1,t0);
1055 #endif
1056 
1057 #ifdef MEASURE_TIME
1058  t0 = getticks();
1059 #endif
1060  /* Convert Chebyshev coefficients to Fourier coefficients. */
1061  c2e(plan);
1062 #ifdef MEASURE_TIME
1063  t1 = getticks();
1064  plan->MEASURE_TIME_t[1] = nfft_elapsed_seconds(t1,t0);
1065 #endif
1066 
1067 #ifdef MEASURE_TIME
1068  t0 = getticks();
1069 #endif
1070  /* Check, which nonequispaced discrete Fourier transform algorithm should
1071  * be used.
1072  */
1073  if (plan->flags & NFSFT_USE_NDFT)
1074  {
1075  /* Use NDFT. */
1076  nfft_trafo_direct(&plan->plan_nfft);
1077  }
1078  else
1079  {
1080  /* Use NFFT. */
1081  //fprintf(stderr,"nfsft_adjoint: nfft_trafo\n");
1082  nfft_trafo_2d(&plan->plan_nfft);
1083  }
1084 #ifdef MEASURE_TIME
1085  t1 = getticks();
1086  plan->MEASURE_TIME_t[2] = nfft_elapsed_seconds(t1,t0);
1087 #endif
1088  }
1089 }
1090 
1092 {
1093  int k; /*< The degree k */
1094  int n; /*< The order n */
1095 #ifdef MEASURE_TIME
1096  ticks t0, t1;
1097 #endif
1098 
1099 #ifdef MEASURE_TIME
1100  plan->MEASURE_TIME_t[0] = 0.0;
1101  plan->MEASURE_TIME_t[1] = 0.0;
1102  plan->MEASURE_TIME_t[2] = 0.0;
1103 #endif
1104 
1105  if (wisdom.flags & NFSFT_NO_FAST_ALGORITHM)
1106  {
1107  return;
1108  }
1109 
1110  /* Check, if precomputation was done and that the bandwidth N is not too
1111  * big.
1112  */
1113  if (wisdom.initialized == 0 || plan->N > wisdom.N_MAX)
1114  {
1115  return;
1116  }
1117 
1118  /* Check, if slow transformation should be used due to small bandwidth. */
1119  if (plan->N < NFSFT_BREAK_EVEN)
1120  {
1121  /* Use adjoint NDSFT. */
1122  nfsft_adjoint_direct(plan);
1123  }
1124  /* Check for correct value of the bandwidth N. */
1125  else if (plan->N <= wisdom.N_MAX)
1126  {
1127  //fprintf(stderr,"nfsft_adjoint: Starting\n");
1128  //fflush(stderr);
1129  /* Propagate pointer values to the internal NFFT plan to assure
1130  * consistency. Pointers may have been modified externally.
1131  */
1132  plan->plan_nfft.x = plan->x;
1133  plan->plan_nfft.f = plan->f;
1134  plan->plan_nfft.f_hat = plan->f_hat;
1135 
1136 #ifdef MEASURE_TIME
1137  t0 = getticks();
1138 #endif
1139  /* Check, which adjoint nonequispaced discrete Fourier transform algorithm
1140  * should be used.
1141  */
1142  if (plan->flags & NFSFT_USE_NDFT)
1143  {
1144  //fprintf(stderr,"nfsft_adjoint: Executing nfft_adjoint_direct\n");
1145  //fflush(stderr);
1146  /* Use adjoint NDFT. */
1147  nfft_adjoint_direct(&plan->plan_nfft);
1148  }
1149  else
1150  {
1151  //fprintf(stderr,"nfsft_adjoint: Executing nfft_adjoint\n");
1152  //fflush(stderr);
1153  //fprintf(stderr,"nfsft_adjoint: nfft_adjoint\n");
1154  /* Use adjoint NFFT. */
1155  nfft_adjoint_2d(&plan->plan_nfft);
1156  }
1157 #ifdef MEASURE_TIME
1158  t1 = getticks();
1159  plan->MEASURE_TIME_t[2] = nfft_elapsed_seconds(t1,t0);
1160 #endif
1161 
1162  //fprintf(stderr,"nfsft_adjoint: Executing c2e_transposed\n");
1163  //fflush(stderr);
1164 #ifdef MEASURE_TIME
1165  t0 = getticks();
1166 #endif
1167  /* Convert Fourier coefficients to Chebyshev coefficients. */
1168  c2e_transposed(plan);
1169 #ifdef MEASURE_TIME
1170  t1 = getticks();
1171  plan->MEASURE_TIME_t[1] = nfft_elapsed_seconds(t1,t0);
1172 #endif
1173 
1174 #ifdef MEASURE_TIME
1175  t0 = getticks();
1176 #endif
1177  /* Check, which transposed polynomial transform algorithm should be used */
1178  if (plan->flags & NFSFT_USE_DPT)
1179  {
1180 #ifdef _OPENMP
1181  #pragma omp parallel for default(shared) private(n) num_threads(wisdom.nthreads)
1182  for (n = -plan->N; n <= plan->N; n++)
1183  fpt_transposed_direct(wisdom.set_threads[omp_get_thread_num()],abs(n),
1184  &plan->f_hat[NFSFT_INDEX(abs(n),n,plan)],
1185  &plan->f_hat[NFSFT_INDEX(0,n,plan)],
1186  plan->N,0U);
1187 #else
1188  /* Use transposed DPT. */
1189  for (n = -plan->N; n <= plan->N; n++)
1190  {
1191  //fprintf(stderr,"nfsft_adjoint: Executing dpt_transposed\n");
1192  //fflush(stderr);
1193  fpt_transposed_direct(wisdom.set,abs(n),
1194  &plan->f_hat[NFSFT_INDEX(abs(n),n,plan)],
1195  &plan->f_hat[NFSFT_INDEX(0,n,plan)],
1196  plan->N,0U);
1197  }
1198 #endif
1199  }
1200  else
1201  {
1202 #ifdef _OPENMP
1203  #pragma omp parallel for default(shared) private(n) num_threads(wisdom.nthreads)
1204  for (n = -plan->N; n <= plan->N; n++)
1205  fpt_transposed(wisdom.set_threads[omp_get_thread_num()],abs(n),
1206  &plan->f_hat[NFSFT_INDEX(abs(n),n,plan)],
1207  &plan->f_hat[NFSFT_INDEX(0,n,plan)],
1208  plan->N,0U);
1209 #else
1210  //fprintf(stderr,"nfsft_adjoint: fpt_transposed\n");
1211  /* Use transposed FPT. */
1212  for (n = -plan->N; n <= plan->N; n++)
1213  {
1214  //fprintf(stderr,"nfsft_adjoint: Executing fpt_transposed\n");
1215  //fflush(stderr);
1216  fpt_transposed(wisdom.set,abs(n),
1217  &plan->f_hat[NFSFT_INDEX(abs(n),n,plan)],
1218  &plan->f_hat[NFSFT_INDEX(0,n,plan)],
1219  plan->N,0U);
1220  }
1221 #endif
1222  }
1223 #ifdef MEASURE_TIME
1224  t1 = getticks();
1225  plan->MEASURE_TIME_t[0] = nfft_elapsed_seconds(t1,t0);
1226 #endif
1227 
1228  /* Check, if we compute with L^2-normalized spherical harmonics. If so,
1229  * multiply spherical Fourier coefficients with corresponding normalization
1230  * weight. */
1231  if (plan->flags & NFSFT_NORMALIZED)
1232  {
1233  //fprintf(stderr,"nfsft_adjoint: Normalizing\n");
1234  //fflush(stderr);
1235  /* Traverse Fourier coefficients array. */
1236 #ifdef _OPENMP
1237  #pragma omp parallel for default(shared) private(k,n)
1238 #endif
1239  for (k = 0; k <= plan->N; k++)
1240  {
1241  for (n = -k; n <= k; n++)
1242  {
1243  /* Multiply with normalization weight. */
1244  plan->f_hat[NFSFT_INDEX(k,n,plan)] *=
1245  sqrt((2*k+1)/(4.0*KPI));
1246  }
1247  }
1248  }
1249 
1250  /* Set unused coefficients to zero. */
1251  if (plan->flags & NFSFT_ZERO_F_HAT)
1252  {
1253  //fprintf(stderr,"nfsft_adjoint: Setting to zero\n");
1254  //fflush(stderr);
1255  for (n = -plan->N; n <= plan->N+1; n++)
1256  {
1257  memset(&plan->f_hat[NFSFT_INDEX(-plan->N-1,n,plan)],0U,
1258  (plan->N+1+abs(n))*sizeof(double _Complex));
1259  }
1260  }
1261  //fprintf(stderr,"nfsft_adjoint: Finished\n");
1262  //fflush(stderr);
1263  }
1264 }
1265 
1266 void nfsft_precompute_x(nfsft_plan *plan)
1267 {
1268  /* Pass angle array to NFFT plan. */
1269  plan->plan_nfft.x = plan->x;
1270 
1271  /* Precompute. */
1272  if (plan->plan_nfft.flags & PRE_ONE_PSI)
1274 }
1275 /* \} */
void nfsft_init_advanced(nfsft_plan *plan, int N, int M, unsigned int flags)
Definition: nfsft.c:260
static void c2e(nfsft_plan *plan)
Converts coefficients with , from a linear combination of Chebyshev polynomials to coefficients m...
Definition: nfsft.c:108
double * gamma
Precomputed recursion coefficients /f$^n/f$ for /f$k = 0,/ldots, N_{{max}}; n=-k,/ldots,k/f$ of associated Legendre-functions /f$P_k^n/f$.
#define NFSFT_MALLOC_F_HAT
Definition: nfft3.h:579
double * x
the nodes for ,
Definition: nfft3.h:574
#define FPT_PERSISTENT_DATA
If set, TODO complete comment.
Definition: nfft3.h:632
void(* mv_trafo)(void *)
Transform.
Definition: nfft3.h:574
fftw_complex * f_hat
Fourier coefficients.
Definition: nfft3.h:192
#define NFSFT_NORMALIZED
Definition: nfft3.h:575
#define NFSFT_MALLOC_X
Definition: nfft3.h:578
void nfsft_trafo(nfsft_plan *plan)
Definition: nfsft.c:921
#define NFSFT_PRESERVE_F_HAT
Definition: nfft3.h:581
Wisdom structure.
void nfsft_adjoint(nfsft_plan *plan)
Definition: nfsft.c:1091
fftw_complex * f_hat
Fourier coefficients.
Definition: nfft3.h:574
R nfft_elapsed_seconds(ticks t1, ticks t0)
Return number of elapsed seconds between two time points.
int N
the bandwidth
Definition: nfft3.h:574
void fpt_transposed(fpt_set set, const int m, double _Complex *x, double _Complex *y, const int k_end, const unsigned int flags)
Definition: fpt.c:1566
void nfsft_precompute(int N, double kappa, unsigned int nfsft_flags, unsigned int fpt_flags)
Definition: nfsft.c:357
data structure for an NFSFT (nonequispaced fast spherical Fourier transform) plan with double precisi...
Definition: nfft3.h:574
fpt_set set
Structure for discrete polynomial transform (DPT)
#define NFSFT_BREAK_EVEN
The break-even bandwidth .
Definition: nfsft.c:76
#define NFSFT_NO_FAST_ALGORITHM
Definition: nfft3.h:590
#define NFSFT_ZERO_F_HAT
Definition: nfft3.h:591
int N_MAX
Stores precomputation flags.
bool initialized
Indicates wether the structure has been initialized.
void fpt_precompute(fpt_set set, const int m, double *alpha, double *beta, double *gam, int k_start, const double threshold)
Definition: fpt.c:881
void alpha_al_all(R *alpha, const int N)
Compute three-term-recurrence coefficients of associated Legendre functions for .
Definition: legendre.c:89
unsigned int flags
the planner flags
Definition: nfft3.h:574
void nfsft_init(nfsft_plan *plan, int N, int M)
Definition: nfsft.c:253
Holds data for a set of cascade summations.
Definition: fpt.c:94
fftw_complex * f
Samples.
Definition: nfft3.h:192
#define NFSFT_DEFAULT_NFFT_CUTOFF
The default NFFT cutoff parameter.
Definition: nfsft.c:62
void nfft_free(void *p)
#define FFTW_INIT
Definition: nfft3.h:203
nfft_plan plan_nfft
the internal NFFT plan
Definition: nfft3.h:574
NFFT_INT M_total
Total number of samples.
Definition: nfft3.h:574
double MEASURE_TIME_t[3]
Measured time for each step if MEASURE_TIME is set.
Definition: nfft3.h:574
#define X(name)
Include header for C99 complex datatype.
Definition: fastsum.h:57
#define FFT_OUT_OF_PLACE
Definition: nfft3.h:202
#define PRE_PSI
Definition: nfft3.h:197
#define NFSFT_NO_DIRECT_ALGORITHM
Definition: nfft3.h:589
void * nfft_malloc(size_t n)
NFFT_INT N_total
Total number of Fourier coefficients.
Definition: nfft3.h:574
double * alpha
Precomputed recursion coefficients /f$^n/f$ for /f$k = 0,/ldots, N_{{max}}; n=-k,/ldots,k/f$ of associated Legendre-functions /f$P_k^n/f$.
void nfft_finalize(nfft_plan *ths)
fftw_complex * f
Samples.
Definition: nfft3.h:574
void nfft_precompute_one_psi(nfft_plan *ths)
fpt_set fpt_init(const int M, const int t, const unsigned int flags)
Definition: fpt.c:755
#define NFSFT_MALLOC_F
Definition: nfft3.h:580
#define NFSFT_USE_NDFT
Definition: nfft3.h:576
void nfsft_finalize(nfsft_plan *plan)
Definition: nfsft.c:572
void(* mv_adjoint)(void *)
Adjoint transform.
Definition: nfft3.h:574
void beta_al_all(R *alpha, const int N)
Compute three-term-recurrence coefficients of associated Legendre functions for .
Definition: legendre.c:98
double * beta
Precomputed recursion coefficients /f$^n/f$ for /f$k = 0,/ldots, N_{{max}}; n=-k,/ldots,k/f$ of associated Legendre-functions /f$P_k^n/f$.
static void c2e_transposed(nfsft_plan *plan)
Transposed version of the function c2e.
Definition: nfsft.c:186
void gamma_al_all(R *alpha, const int N)
Compute three-term-recurrence coefficients of associated Legendre functions for .
Definition: legendre.c:107
Header file for the nfft3 library.
double * x
Nodes in time/spatial domain, size is doubles.
Definition: nfft3.h:192
#define PRE_PHI_HUT
Definition: nfft3.h:193
#define FPT_AL_SYMMETRY
If set, TODO complete comment.
Definition: nfft3.h:636
static struct nfsft_wisdom wisdom
The global wisdom structure for precomputed data.
Definition: nfsft.c:84
#define PRE_ONE_PSI
Definition: nfft3.h:206
unsigned flags
Flags for precomputation, (de)allocation, and FFTW usage, default setting is PRE_PHI_HUT | PRE_PSI | ...
Definition: nfft3.h:192
fftw_complex * f_hat_intern
Internally used pointer to spherical Fourier coefficients.
Definition: nfft3.h:574
int T_MAX
The logarithm /f$t = N_{{max}}/f$ of the maximum bandwidth.
#define NFSFT_INDEX(k, n, plan)
Definition: nfft3.h:594
void nfsft_forget(void)
Definition: nfsft.c:526
#define NFSFT_USE_DPT
Definition: nfft3.h:577