NFFT Logo 3.2.3
wigner.c
1 /*
2  * Copyright (c) 2002, 2012 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 
19 /* $Id: wigner.c 3896 2012-10-10 12:19:26Z tovo $ */
20 
21 #include <math.h>
22 #include <stdio.h>
23 #include "infft.h"
24 #include "wigner.h"
25 #include "nfft3util.h"
26 
27 double SO3_alpha(const int m1, const int m2, const int j)
28 {
29  const int M = MAX(ABS(m1),ABS(m2)), mini = MIN(ABS(m1),ABS(m2));
30 
31  if (j < 0)
32  return K(0.0);
33  else if (j == 0)
34  {
35  if (m1 == 0 && m2 == 0)
36  return K(1.0);
37  if (m1 == m2)
38  return K(0.5);
39  else
40  return IF((m1+m2)%2,K(0.0),K(-0.5));
41  }
42  else if (j < M - mini)
43  return IF(j%2,K(0.5),K(-0.5));
44  else if (j < M)
45  return K(0.5) * SIGNF((R)m1)*SIGNF((R)m2);
46  else
47  return
48  SQRT(((R)(j+1))/((R)(j+1-m1)))
49  * SQRT(((R)(2*j+1))/((R)(j+1+m1)))
50  * SQRT(((R)(j+1))/((R)(j+1-m2)))
51  * SQRT(((R)(2*j+1))/((R)(j+1+m2)));
52 }
53 
54 double SO3_beta(const int m1, const int m2, const int j)
55 {
56  if (j < 0)
57  return K(0.0);
58  else if (j < MAX(ABS(m1),ABS(m2)))
59  return K(0.5);
60  else if (m1 == 0 || m2 == 0)
61  return K(0.0);
62  else
63  {
64  const R m1a = FABS((R)m1), m2a = FABS((R)m2);
65  return -COPYSIGN(
66  ((SQRT(m1a)*SQRT(m2a))/((R)j))
67  * SQRT(m1a/((R)(j+1-m1)))
68  * SQRT(((R)(2*j+1))/((R)(j+1+m1)))
69  * SQRT(m2a/((R)(j+1-m2)))
70  * SQRT(((R)(2*j+1))/((R)(j+1+m2))),
71  SIGNF((R)m1)*SIGNF((R)m2));
72  }
73 }
74 
75 double SO3_gamma(const int m1, const int m2, const int j)
76 {
77  if (MAX(ABS(m1),ABS(m2)) < j)
78  return -(((R)(j+1))/((R)j)) * SQRT((((R)(j-m1))/((R)(j+1-m1)))
79  *(((R)(j+m1))/((R)(j+1+m1)))*(((R)(j-m2))/((R)(j+1-m2)))
80  *(((R)(j+m2))/((R)(j+1+m2))));
81  else if (j == -1)
82  return IF(m1 > m2 || !((m1 + m2) % 2), K(1.0), K(-1.0))
83  * nfft_lambda2((R)ABS(m2 - m1),(R)ABS(m2 + m1));
84  else
85  return K(0.0);
86 }
87 
88 /*compute the coefficients for all degrees*/
89 
90 inline void SO3_alpha_row(double *alpha, int N, int k, int m)
91 {
92  int j;
93  double *alpha_act = alpha;
94  for (j = -1; j <= N; j++)
95  *alpha_act++ = SO3_alpha(k, m, j);
96 }
97 
98 inline void SO3_beta_row(double *beta, int N, int k, int m)
99 {
100  int j;
101  double *beta_act = beta;
102  for (j = -1; j <= N; j++)
103  *beta_act++ = SO3_beta(k, m, j);
104 }
105 
106 inline void SO3_gamma_row(double *gamma, int N, int k, int m)
107 {
108  int j;
109  double *gamma_act = gamma;
110  for (j = -1; j <= N; j++)
111  *gamma_act++ = SO3_gamma(k, m, j);
112 }
113 
114 /*compute for all degrees l and orders k*/
115 
116 inline void SO3_alpha_matrix(double *alpha, int N, int m)
117 {
118  int i, j;
119  double *alpha_act = alpha;
120  for (i = -N; i <= N; i++)
121  {
122  for (j = -1; j <= N; j++)
123  {
124  *alpha_act = SO3_alpha(i, m, j);
125  alpha_act++;
126  }
127  }
128 }
129 
130 inline void SO3_beta_matrix(double *alpha, int N, int m)
131 {
132  int i, j;
133  double *alpha_act = alpha;
134  for (i = -N; i <= N; i++)
135  {
136  for (j = -1; j <= N; j++)
137  {
138  *alpha_act = SO3_beta(i, m, j);
139  alpha_act++;
140  }
141  }
142 }
143 
144 inline void SO3_gamma_matrix(double *alpha, int N, int m)
145 {
146  int i, j;
147  double *alpha_act = alpha;
148  for (i = -N; i <= N; i++)
149  {
150  for (j = -1; j <= N; j++)
151  {
152  *alpha_act = SO3_gamma(i, m, j);
153  alpha_act++;
154  }
155  }
156 }
157 
158 /*compute all 3termrecurrence coeffs*/
159 
160 inline void SO3_alpha_all(double *alpha, int N)
161 {
162  int q;
163  int i, j, m;
164  double *alpha_act = alpha;
165  q = 0;
166  for (m = -N; m <= N; m++)
167  {
168  for (i = -N; i <= N; i++)
169  {
170  for (j = -1; j <= N; j++)
171  {
172  *alpha_act = SO3_alpha(i, m, j);
173  fprintf(stdout, "alpha_all_%d^[%d,%d]=%f\n", j, i, m,
174  SO3_alpha(i, m, j));
175  alpha_act++;
176  q = q + 1;
177 
178  }
179  }
180  }
181 }
182 
183 inline void SO3_beta_all(double *alpha, int N)
184 {
185  int i, j, m;
186  double *alpha_act = alpha;
187  for (m = -N; m <= N; m++)
188  {
189  for (i = -N; i <= N; i++)
190  {
191  for (j = -1; j <= N; j++)
192  {
193  *alpha_act = SO3_beta(i, m, j);
194  alpha_act++;
195  }
196  }
197  }
198 }
199 
200 inline void SO3_gamma_all(double *alpha, int N)
201 {
202  int i, j, m;
203  double *alpha_act = alpha;
204  for (m = -N; m <= N; m++)
205  {
206  for (i = -N; i <= N; i++)
207  {
208  for (j = -1; j <= N; j++)
209  {
210  *alpha_act = SO3_gamma(i, m, j);
211  alpha_act++;
212  }
213  }
214  }
215 }
216 
217 inline void eval_wigner(double *x, double *y, int size, int k, double *alpha,
218  double *beta, double *gamma)
219 {
220  /* Evaluate the wigner function d_{k,nleg} (l,x) for the vector
221  * of knots x[0], ..., x[size-1] by the Clenshaw algorithm
222  */
223  int i, j;
224  double a, b, x_val_act, a_old;
225  double *x_act, *y_act;
226  double *alpha_act, *beta_act, *gamma_act;
227 
228  /* Traverse all nodes. */
229  x_act = x;
230  y_act = y;
231  for (i = 0; i < size; i++)
232  {
233  a = 1.0;
234  b = 0.0;
235  x_val_act = *x_act;
236 
237  if (k == 0)
238  {
239  *y_act = 1.0;
240  }
241  else
242  {
243  alpha_act = &(alpha[k]);
244  beta_act = &(beta[k]);
245  gamma_act = &(gamma[k]);
246  for (j = k; j > 1; j--)
247  {
248  a_old = a;
249  a = b + a_old * ((*alpha_act) * x_val_act + (*beta_act));
250  b = a_old * (*gamma_act);
251  alpha_act--;
252  beta_act--;
253  gamma_act--;
254  }
255  *y_act = (a * ((*alpha_act) * x_val_act + (*beta_act)) + b);
256  }
257  x_act++;
258  y_act++;
259  }
260 }
261 
262 inline int eval_wigner_thresh(double *x, double *y, int size, int k,
263  double *alpha, double *beta, double *gamma, double threshold)
264 {
265 
266  int i, j;
267  double a, b, x_val_act, a_old;
268  double *x_act, *y_act;
269  double *alpha_act, *beta_act, *gamma_act;
270 
271  /* Traverse all nodes. */
272  x_act = x;
273  y_act = y;
274  for (i = 0; i < size; i++)
275  {
276  a = 1.0;
277  b = 0.0;
278  x_val_act = *x_act;
279 
280  if (k == 0)
281  {
282  *y_act = 1.0;
283  }
284  else
285  {
286  alpha_act = &(alpha[k]);
287  beta_act = &(beta[k]);
288  gamma_act = &(gamma[k]);
289  for (j = k; j > 1; j--)
290  {
291  a_old = a;
292  a = b + a_old * ((*alpha_act) * x_val_act + (*beta_act));
293  b = a_old * (*gamma_act);
294  alpha_act--;
295  beta_act--;
296  gamma_act--;
297  }
298  *y_act = (a * ((*alpha_act) * x_val_act + (*beta_act)) + b);
299  if (fabs(*y_act) > threshold)
300  {
301  return 1;
302  }
303  }
304  x_act++;
305  y_act++;
306  }
307  return 0;
308 }
309 
310 /************************************************************************/
311 /* L2 normed wigner little d, WHERE THE DEGREE OF THE FUNCTION IS EQUAL
312  TO ONE OF ITS ORDERS. This is the function to use when starting the
313  three-term recurrence at orders (m1,m2)
314 
315  Note that, by definition, since I am starting the recurrence with this
316  function, that the degree j of the function is equal to max(abs(m1), abs(m2) ).
317  */
318 
319 double wigner_start(int m1, int m2, double theta)
320 {
321 
322  int i, l, delta;
323  int cosPower, sinPower;
324  int absM1, absM2;
325  double dl, dm1, dm2, normFactor, sinSign;
326  double dCP, dSP;
327  double max;
328  double min;
329 
330  max = (double) (ABS(m1) > ABS(m2) ? ABS(m1) : ABS(m2));
331  min = (double) (ABS(m1) < ABS(m2) ? ABS(m1) : ABS(m2));
332 
333  l = max;
334  delta = l - min;
335 
336  absM1 = ABS(m1);
337  absM2 = ABS(m2);
338  dl = (double) l;
339  dm1 = (double) m1;
340  dm2 = (double) m2;
341  sinSign = 1.;
342  normFactor = 1.;
343 
344  for (i = 0; i < delta; i++)
345  normFactor *= SQRT((2. * dl - ((double) i)) / (((double) i) + 1.));
346 
347  /* need to adjust to make the L2-norm equal to 1 */
348 
349  normFactor *= SQRT((2. * dl + 1.) / 2.);
350 
351  if (l == absM1)
352  if (m1 >= 0)
353  {
354  cosPower = l + m2;
355  sinPower = l - m2;
356  if ((l - m2) % 2)
357  sinSign = -1.;
358  }
359  else
360  {
361  cosPower = l - m2;
362  sinPower = l + m2;
363  }
364  else if (m2 >= 0)
365  {
366  cosPower = l + m1;
367  sinPower = l - m1;
368  }
369  else
370  {
371  cosPower = l - m1;
372  sinPower = l + m1;
373  if ((l + m1) % 2)
374  sinSign = -1.;
375  }
376 
377  dCP = (double) cosPower;
378  dSP = (double) sinPower;
379 
380  return normFactor * sinSign * POW(sin(theta / 2), dSP) * POW(cos(theta / 2),
381  dCP);
382 }

Generated on Tue Apr 30 2013 by Doxygen 1.8.1