FLAG  1.0b1
Exact Fourier-Laguerre transform in spherical coordinates
flag_spherlaguerre.c
Go to the documentation of this file.
1  // FLAG package
2 // Copyright (C) 2012
3 // Boris Leistedt & Jason McEwen
4 
5 #include "flag.h"
6 #include <math.h>
7 #include <stdlib.h>
8 #include <complex.h>
9 #include <fftw3.h>
10 #include <ssht.h>
11 #include <assert.h>
12 
13 #define MIN(a,b) ((a) < (b) ? (a) : (b))
14 
15 
16 double eval_laguerre(double z, int n, int alpha)
17 {
18  int k;
19  double p1, p2, p3;
20  p1 = 1.0 ;
21  p2 = 0.0;
22  for (k = 1; k <= n; k++){
23  p3 = p2;
24  p2 = p1;
25  p1 = ( (alpha + 2.0 * k - 1.0 - z) * p2 - (alpha + k - 1.0) * p3 ) / k;
26  }
27  return(p1);
28 }
29 
30 double eval_laguerre_rescaled(double z, int n, int alpha, double normfac)
31 {
32  int k;
33  double p1, p2, p3;
34  p1 = 1.0 / normfac ;
35  p2 = 0.0;
36  for (k = 1; k <= n; k++){
37  p3 = p2;
38  p2 = p1;
39  p1 = ( (alpha + 2.0 * k - 1.0 - z) * p2 - (alpha + k - 1.0) * p3 ) / k;
40  }
41  return(p1);
42 }
43 
44 long factorial(int n)
45 {
46  int i, res = 1;
47  for(i = 1; i <= n; i++)
48  res *= i;
49  return(res);
50 }
51 
52 long factorial_range(int min, int max)
53 {
54  int i, res = 1;
55  for(i = min; i <= max; i++)
56  res *= i;
57  return(res);
58 }
59 
60 void flag_spherlaguerre_quadrature(double *roots, double *weights, int N, int alpha)
61 {
62  double infbound ;
63  double supbound ;
64  const int NITERMAX = 2000;
65  const int MAXIT = 250;
66  int niter, i, n;
67  int facalpha = factorial_range(N+1, N+alpha);
68 
69  double h = 1.0 / (double) N;
70  double vinf, vsup, p1, p2, pp, z = 0.0, z1, temp;
71  double normfac = 1.0;
72 
73  // First low-bound
74  infbound = h;
75 
76  for (n = 0; n < N; n++)
77  {
78  if( n > 100 )
79  h = 0.1;
80  supbound = infbound;
81  normfac = eval_laguerre_rescaled(z, n, alpha, normfac);
82 
83  temp = eval_laguerre_rescaled(infbound, N, alpha, normfac);
84  vinf = temp;
85  vsup = temp;
86 
87  niter = 0;
88  while( vinf * vsup >= 0 && niter < NITERMAX ){
89  supbound += h;
90  vsup = eval_laguerre_rescaled(supbound, N, alpha, normfac);
91  niter++;
92  }
93 
94  niter = 0;
95  while( vinf * vsup < 0 && niter < NITERMAX ){
96  infbound += h;
97  vinf = eval_laguerre_rescaled(infbound, N, alpha, normfac);
98  niter++;
99  }
100  infbound -= h;
101  vinf = eval_laguerre_rescaled(infbound, N, alpha, normfac);
102 
103  // Linear interpolation for root first estimation
104  z = infbound - vinf * (supbound-infbound) / (vsup-vinf);
105 
106  // Prepare for next iteration
107  infbound = supbound;
108 
109  //printf(" %i %f ", n, z);
110  //printf(" %1.1e ",normfac);
111  // Refine using Newton scheme
112  for (i = 1; i <= MAXIT; i++)
113  {
114  p1 = eval_laguerre_rescaled(z, N, alpha, normfac);
115  p2 = eval_laguerre_rescaled(z, N-1, alpha, normfac);
116  // Derivative
117  pp = (N * p1 - N * p2) / z;
118  z1 = z;
119  // Newton step
120  z = z1 - p1/pp;
121  //printf(" %f ", z);
122  if( cabs(z - z1) < 1e-16 ){
123  //printf("MAXIT = %i err = %2.2e\n",i,cabs(taubis-tau));
124  break;
125  }
126  }
127  //printf("\n");
128  // Store final root estimate
129  roots[n] = z;
130  weights[n] = (facalpha / pow(N+1, 2.0)) * z * pow( (exp(z / 4.0) / normfac) * (exp(z / 4.0) / eval_laguerre_rescaled(z, N+1, alpha, normfac)) , 2.0);
131  // Correct weights for classical Gauss-Laguerre quadrature with generalised polynomrials :
132  // weights[n] = (facalpha / pow(N+1, 2.0)) * z / pow( eval_laguerre(z, N+1, alpha), 2.0) ;
133  }
134 
135  // Specific unstable solution
136  if( N == 2 && alpha == 2){
137  roots[0] = 2.0;
138  roots[1] = 6.0;
139  weights[0] = 2.770896037098993835 * pow(roots[0],2.0);
140  weights[1] = 5.603177687399098925 * pow(roots[1],2.0);
141  }
142 
143  // Check order
144  for (n = 1; n < N-1; n++)
145  if( roots[n] <= roots[n-1] )
146  printf("Problem with %ith root! : %f < %f < %f\n",
147  n, roots[n-1], roots[n], roots[n+1]);
148 
149 }
150 
151 
152 
153 double flag_spherlaguerre_tau(double R, int N)
154 {
155  assert(R > 0.0);
156  double Rmax = flag_spherlaguerre_Rmax(N);
157  return R / Rmax;
158 }
159 
161 {
162  assert(N > 1);
163  const int alpha = ALPHA;
164  double R;
165 
166  /*
167  double *roots = (double*)calloc(N+1, sizeof(double));
168  double *weights = (double*)calloc(N+1, sizeof(double));
169  flag_spherlaguerre_quadrature(roots, weights, N+1, alpha);
170  double tau_bis = roots[N];
171  free(roots);
172  free(weights);
173  */
174 
175  if( N < 5 ){
176 
177  double *roots = (double*)calloc(N, sizeof(double));
178  double *weights = (double*)calloc(N, sizeof(double));
179  flag_spherlaguerre_quadrature(roots, weights, N, alpha);
180  R = roots[N-1];
181  free(roots);
182  free(weights);
183 
184  }else{
185 
186  double infbound, supbound = 3.95 * N + 10;
187  double vinf, vsup, p1, p2, pp, taubis;
188  double h = (double)N/1000;
189  const int MAXIT = 250;
190  int i;
191 
192  infbound = supbound;
193  double normfac = eval_laguerre(infbound, N, alpha);
194  double temp = eval_laguerre_rescaled(infbound, N, alpha, normfac);
195 
196  vinf = temp;
197  vsup = temp;
198 
199  while( vinf * vsup >= 0 && infbound > 0 ){
200  infbound -= h;
201  vinf = eval_laguerre_rescaled(infbound, N, alpha, normfac);
202  }
203 
204  while( vinf * vsup < 0 && supbound > 0 ){
205  supbound -= h;
206  vsup = eval_laguerre_rescaled(supbound, N, alpha, normfac);
207  }
208  supbound += h;
209  vsup = eval_laguerre_rescaled(infbound, N-1, alpha, normfac);
210 
211  // Linear interpolation for root first estimation
212  R = infbound - vinf * (supbound-infbound) / (vsup-vinf);
213 
214  for (i = 1; i <= MAXIT; i++)
215  {
216  p1 = eval_laguerre_rescaled(R, N, alpha, normfac);
217  p2 = eval_laguerre_rescaled(R, N-1, alpha, normfac);
218  // Derivative
219  pp = (N * p1 - N * p2) / R;
220  taubis = R;
221  // Newton step
222  R = taubis - p1/pp;
223  if( cabs(taubis - R) < 1e-16 ){
224  //printf("MAXIT = %i err = %2.2e\n",i,cabs(taubis-tau));
225  break;
226  }
227  }
228  }
229 
230  //printf("R = %4.4e\n",R);
231  //printf("Taubis = %4.4e\n",tau_bis);
232 
233  return R;
234 }
235 
236 void flag_spherlaguerre_sampling(double *nodes, double *weights, double tau, int N)
237 {
238  assert(tau > 0.0);
239  assert(N > 1);
240  const int alpha = ALPHA;
241 
242  flag_spherlaguerre_quadrature(nodes, weights, N, alpha);
243 
244  int n;
245  for (n=0; n<N; n++){
246  //weights[n] *= exp(nodes[n]);// * pow(tau, alpha + 1);
247  nodes[n] *= tau;
248  //printf("Node %i = %f with weight %f \n",n,nodes[n],weights[n]);
249  }
250 
251 }
252 
253 void flag_spherlaguerre_allocate_sampling(double **nodes, double **weights, int N)
254 {
255  assert(N > 1);
256  *nodes = (double*)calloc(N, sizeof(double));
257  *weights = (double*)calloc(N, sizeof(double));
258  assert(nodes != NULL);
259  assert(weights != NULL);
260 }
261 
262 void flag_spherlaguerre_analysis(double *fn, const double *f, const double *nodes, const double *weights, double tau, int N)
263 {
264  assert(N > 1);
265  int i, n;
266  const int alpha = ALPHA;
267 
268  double r, factor, lagu0, lagu1, lagu2;
269 
270  for(i=0; i<N; i++)
271  {
272  r = nodes[i]/tau;
273  factor = weights[i] * f[i] * exp(-r/2.0) ;
274 
275  lagu0 = 0.0;
276  lagu1 = 1.0;
277 
278  fn[0] += factor * pow(factorial_range(1, alpha), -0.5) * lagu1;
279 
280  for (n = 1; n < N; n++)
281  {
282  lagu2 =
283  (
284  (alpha + 2 * n - 1 - r) * lagu1 -
285  (alpha + n - 1) * lagu0
286  ) / n;
287 
288  fn[n] += factor * pow(factorial_range(n+1, n+alpha), -0.5) * lagu2;
289 
290  lagu0 = lagu1;
291  lagu1 = lagu2;
292  }
293  }
294 
295 }
296 
297 void flag_spherlaguerre_synthesis(double *f, const double *fn, const double *nodes, int Nnodes, double tau, int N)
298 {
299  flag_spherlaguerre_synthesis_gen(f, fn, nodes, Nnodes, tau, N, ALPHA);
300 }
301 
302 
303 void flag_spherlaguerre_synthesis_gen(double *f, const double *fn, const double *nodes, int Nnodes, double tau, int N, int alpha)
304 {
305  assert(N > 1);
306  assert(Nnodes > 1);
307  int i, n;
308  complex double factor, lagu0, lagu1, lagu2, r;
309 
310  for (i = 0; i < Nnodes; i++)
311  {
312  r = nodes[i]/tau;
313  factor = exp(-r/2.0);
314 
315  lagu0 = 0.0;
316  lagu1 = 1.0;
317 
318  f[i] += factor * pow(factorial_range(1, alpha), -0.5) * lagu1 * fn[0];
319 
320  for (n = 1; n < N; n++)
321  {
322  lagu2 =
323  (
324  (alpha + 2 * n - 1 - r) * lagu1 -
325  (alpha + n - 1) * lagu0
326  ) / n;
327 
328  f[i] += factor * pow(factorial_range(n+1, n+alpha), -0.5) * lagu2 * fn[n];
329 
330  lagu0 = lagu1;
331  lagu1 = lagu2;
332  }
333  }
334 }
335 
336 
337 void flag_spherlaguerre_mapped_analysis(complex double *fn, const complex double *f, const double *nodes, const double *weights, double tau, int N, int mapsize)
338 {
339  assert(N > 1);
340  assert(mapsize > 1);
341  int i, n, l, offset_i, offset_n;
342  double factor, lagu0, lagu1, lagu2, r;
343  const int alpha = ALPHA;
344 
345  double *temp = (double*)calloc(N, sizeof(double));
346  //double normfac;
347 
348  for(i=0; i<N; i++)
349  {
350 
351  r = nodes[i]/tau;
352  factor = weights[i] * exp(-r/4.0);
353 
354  lagu0 = 0.0;
355  lagu1 = 1.0 * exp(-r/4.0);
356 
357  temp[0] = factor * pow(factorial_range(1, alpha), -0.5) * lagu1;
358 
359  for (n = 1; n < N; n++)
360  {
361  lagu2 =
362  (
363  (alpha + 2 * n - 1 - r) * lagu1 -
364  (alpha + n - 1) * lagu0
365  ) / n;
366 
367  temp[n] = factor * pow(factorial_range(n+1, n+alpha), -0.5) * lagu2;
368 
369  lagu0 = lagu1;
370  lagu1 = lagu2;
371  }
372 
373  offset_i = i * mapsize;
374  for (n = 0; n < N; n++)
375  {
376  offset_n = n * mapsize;
377  for(l=0; l<mapsize; l++)
378  {
379  fn[l+offset_n] += f[l+offset_i] * temp[n];
380  }
381  }
382  }
383 
384  free(temp);
385 
386 
387 }
388 
389 void flag_spherlaguerre_mapped_synthesis(complex double *f, const complex double *fn, const double *nodes, int Nnodes, double tau, int N, int mapsize)
390 {
391  assert(N > 1);
392  assert(Nnodes > 1);
393  assert(mapsize > 1);
394  int i, n, l, offset_n, offset_i;
395  const int alpha = ALPHA;
396 
397  double r;
398  double factor, lagu0, lagu1, lagu2;
399  double *temp = (double*)calloc(N, sizeof(double));
400 
401  for (i = 0; i < Nnodes; i++)
402  {
403  r = nodes[i]/tau;
404  factor = exp(-r/4.0);
405  // was factor = (1.0/r) * exp(-r/2.0) * (1.0/sqrt(tau));
406 
407  lagu0 = 0.0;
408  lagu1 = 1.0 * exp(-r/4.0);
409 
410  temp[0] = factor * pow(factorial_range(1, alpha), -0.5) * lagu1 ;
411 
412  for (n = 1; n < N; n++)
413  {
414  lagu2 =
415  (
416  (alpha + 2 * n - 1 - r) * lagu1 -
417  (alpha + n - 1) * lagu0
418  ) / n;
419 
420  temp[n] = factor * pow(factorial_range(n+1, n+alpha), -0.5) * lagu2;
421 
422  lagu0 = lagu1;
423  lagu1 = lagu2;
424 
425  }
426 
427  offset_i = i * mapsize;
428  for (n = 0; n < N; n++)
429  {
430  offset_n = n * mapsize;
431  for(l=0; l<mapsize; l++)
432  {
433  f[l+offset_i] += temp[n] * fn[l+offset_n];
434  }
435  }
436  }
437 
438  free(temp);
439 
440 }
441 
442 
443 void flag_spherlaguerre_basis(double *KN, const int N, const double *nodes, int Nnodes, double tau)
444 {
445  assert(Nnodes > 0);
446  assert(N > 0);
447  int i, n;
448  const int alpha = ALPHA;
449  double factor, lagu0, lagu1, lagu2, r;
450 
451  for (i = 0; i < Nnodes; i++)
452  {
453  r = nodes[i]/tau;
454  factor = exp(-r/2.0);
455 
456  lagu0 = 0.0;
457  lagu1 = 1.0;
458 
459  KN[i * N] = factor * pow(factorial_range(1, alpha), -0.5) * lagu1;
460 
461  if ( N > 1 ) {
462 
463  for (n = 1; n < N; n++)
464  {
465  lagu2 = ( (alpha + 2 * n - 1 - r) * lagu1 -
466  (alpha + n - 1) * lagu0 ) / n;
467  lagu0 = lagu1;
468  lagu1 = lagu2;
469  KN[ i * N + n ] = factor * pow(factorial_range(n+1, n+alpha), -0.5) * lagu2;
470  }
471 
472  }
473 
474  }
475 
476 }
477 
478 
479 void flag_spherbessel_sampling(double *nodes, double *weights, double R, int N)
480 {
481  assert(R > 0.0);
482  assert(N > 1);
483  const int alpha = ALPHA;
484 
485  flag_spherlaguerre_quadrature(nodes, weights, N, alpha);
486  double tau = R / nodes[N-1];
487 
488  int n;
489  for (n=0; n<N; n++){
490  weights[n] = 1;
491  nodes[n] *= tau;
492  //printf("Node %i = %f with weight %f \n",n,nodes[n],weights[n]);
493  }
494 
495 }
long factorial_range(int min, int max)
void flag_spherlaguerre_synthesis_gen(double *f, const double *fn, const double *nodes, int Nnodes, double tau, int N, int alpha)
void flag_spherlaguerre_mapped_synthesis(complex double *f, const complex double *fn, const double *nodes, int Nnodes, double tau, int N, int mapsize)
void flag_spherbessel_sampling(double *nodes, double *weights, double R, int N)
double eval_laguerre(double z, int n, int alpha)
double flag_spherlaguerre_Rmax(int N)
void flag_spherlaguerre_allocate_sampling(double **nodes, double **weights, int N)
#define ALPHA
Definition: flag.h:4
void flag_spherlaguerre_basis(double *KN, const int N, const double *nodes, int Nnodes, double tau)
double flag_spherlaguerre_tau(double R, int N)
double eval_laguerre_rescaled(double z, int n, int alpha, double normfac)
void flag_spherlaguerre_mapped_analysis(complex double *fn, const complex double *f, const double *nodes, const double *weights, double tau, int N, int mapsize)
void flag_spherlaguerre_sampling(double *nodes, double *weights, double tau, int N)
long factorial(int n)
void flag_spherlaguerre_quadrature(double *roots, double *weights, int N, int alpha)
void flag_spherlaguerre_synthesis(double *f, const double *fn, const double *nodes, int Nnodes, double tau, int N)
void flag_spherlaguerre_analysis(double *fn, const double *f, const double *nodes, const double *weights, double tau, int N)