LevelS C++ support library  3.82
wigner.cc
Go to the documentation of this file.
1 /*
2  * This file is part of libcxxsupport.
3  *
4  * libcxxsupport is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * libcxxsupport is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with libcxxsupport; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 /*
20  * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik
21  * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
22  * (DLR).
23  */
24 
25 /*! \file wigner.cc
26  * Several C++ classes for calculating Wigner matrices
27  *
28  * Copyright (C) 2009-2016 Max-Planck-Society
29  * \author Martin Reinecke and others (see individual classes)
30  */
31 
32 #include "wigner.h"
33 #include "lsconstants.h"
34 
35 using namespace std;
36 
37 void wigner_d_halfpi_risbo_scalar::do_line0 (double *l1, int j)
38  {
39  double xj = pq/j;
40  for (int i=n; i>=1; --i)
41  l1[i] = xj*sqt[j]*(sqt[j-i]*l1[i] - sqt[i]*l1[i-1]);
42  l1[0] = pq*l1[0];
43  }
44 void wigner_d_halfpi_risbo_scalar::do_line (const double *l1, double *l2,
45  int j, int k)
46  {
47  double xj = pq/j;
48  double t1 = xj*sqt[j-k];
49  double t2 = xj*sqt[k];
50  for (int i=n; i>=1; --i)
51  l2[i] = t1 * (sqt[j-i]*l2[i] - sqt[i]*l2[i-1])
52  +t2 * (sqt[j-i]*l1[i] + sqt[i]*l1[i-1]);
53  l2[0] = sqt[j] * (t2*l1[0]+t1*l2[0]);
54  }
55 
56 wigner_d_halfpi_risbo_scalar::wigner_d_halfpi_risbo_scalar(int lmax)
57  : pq(.5*sqrt(2.)), sqt(2*lmax+1), d(lmax+2,lmax+2), n(-1)
58  { for (tsize m=0; m<sqt.size(); ++m) sqt[m] = sqrt(double(m)); }
59 
60 const arr2<double> &wigner_d_halfpi_risbo_scalar::recurse ()
61  {
62  ++n;
63  if (n==0)
64  d[0][0] = 1;
65  else if (n==1)
66  {
67  d[0][0] = .5; d[0][1] =-pq;
68  d[1][0] = pq; d[1][1] = 0.;
69  }
70  else
71  {
72 //padding
73  int flip = 1;
74  for (int i=0; i<n; ++i)
75  {
76  d[i][n]=flip*d[i][n-2];
77  d[n][i]=flip*d[n-2][i];
78  flip=-flip;
79  }
80  d[n][n]=flip*d[n-2][n];
81 
82  do_line (d[n-1],d[n],2*n-1,n);
83  for (int k=n; k>=2; --k)
84  {
85  do_line (d[k-2],d[k-1],2*n-1,k-1);
86  do_line (d[k-1],d[k],2*n,k);
87  }
88  do_line0 (d[0],2*n-1);
89  do_line (d[0],d[1],2*n,1);
90  do_line0 (d[0],2*n);
91  }
92  return d;
93  }
94 
95 void wigner_d_risbo_scalar::do_line0 (double *l1, int j)
96  {
97  double xj = 1./j;
98  l1[j] = -p*l1[j-1];
99  for (int i=j-1; i>=1; --i)
100  l1[i] = xj*sqt[j]*(q*sqt[j-i]*l1[i] - p*sqt[i]*l1[i-1]);
101  l1[0] = q*l1[0];
102  }
103 void wigner_d_risbo_scalar::do_line (const double *l1, double *l2, int j, int k)
104  {
105  double xj = 1./j;
106  double t1 = xj*sqt[j-k]*q, t2 = xj*sqt[j-k]*p;
107  double t3 = xj*sqt[k]*p, t4 = xj*sqt[k]*q;
108  l2[j] = sqt[j] * (t4*l1[j-1]-t2*l2[j-1]);
109  for (int i=j-1; i>=1; --i)
110  l2[i] = t1*sqt[j-i]*l2[i] - t2*sqt[i]*l2[i-1]
111  +t3*sqt[j-i]*l1[i] + t4*sqt[i]*l1[i-1];
112  l2[0] = sqt[j] * (t3*l1[0]+t1*l2[0]);
113  }
114 
115 wigner_d_risbo_scalar::wigner_d_risbo_scalar(int lmax, double ang)
116  : p(sin(ang/2)), q(cos(ang/2)), sqt(2*lmax+1),
117  d(lmax+1,2*lmax+1), n(-1)
118  { for (tsize m=0; m<sqt.size(); ++m) sqt[m] = sqrt(double(m)); }
119 
120 const arr2<double> &wigner_d_risbo_scalar::recurse ()
121  {
122  ++n;
123  if (n==0)
124  d[0][0] = 1;
125  else if (n==1)
126  {
127  d[0][0] = q*q; d[0][1] = -p*q*sqt[2]; d[0][2] = p*p;
128  d[1][0] = -d[0][1]; d[1][1] = q*q-p*p; d[1][2] = d[0][1];
129  }
130  else
131  {
132  // padding
133  int sign = (n&1)? -1 : 1;
134  for (int i=0; i<=2*n-2; ++i)
135  {
136  d[n][i] = sign*d[n-2][2*n-2-i];
137  sign=-sign;
138  }
139  do_line (d[n-1],d[n],2*n-1,n);
140  for (int k=n; k>=2; --k)
141  {
142  do_line (d[k-2],d[k-1],2*n-1,k-1);
143  do_line (d[k-1],d[k],2*n,k);
144  }
145  do_line0 (d[0],2*n-1);
146  do_line (d[0],d[1],2*n,1);
147  do_line0 (d[0],2*n);
148  }
149  return d;
150  }
151 
152 wigner_d_halfpi_risbo_openmp::wigner_d_halfpi_risbo_openmp(int lmax)
153  : pq(.5*sqrt(2.)), sqt(2*lmax+1), d(lmax+2,lmax+2),
154  dd(lmax+2,lmax+2), n(-1)
155  { for (tsize m=0; m<sqt.size(); ++m) sqt[m] = sqrt(double(m)); }
156 
157 const arr2<double> &wigner_d_halfpi_risbo_openmp::recurse ()
158  {
159  ++n;
160  if (n==0)
161  d[0][0] = 1;
162  else if (n==1)
163  {
164  d.fast_alloc(3,3);
165  d[0][0] = .5; d[0][1] =-pq;
166  d[1][0] = pq; d[1][1] = 0.;
167  }
168  else
169  {
170 //padding
171  int flip = 1;
172  for (int i=0; i<n; ++i)
173  {
174  d[i][n]=flip*d[i][n-2];
175  d[n][i]=flip*d[n-2][i];
176  flip=-flip;
177  }
178  d[n][n]=flip*d[n-2][n];
179 
180  for (int j=2*n-1; j<=2*n; ++j)
181  {
182  dd.fast_alloc(n+2,n+2);
183  double tmpx1 = pq/j;
184  dd[0][0] = pq*d[0][0];
185  for (int i=1;i<=n; ++i)
186  dd[0][i] = tmpx1*sqt[j]*(sqt[j-i]*d[0][i] - sqt[i]*d[0][i-1]);
187 #pragma omp parallel
188 {
189  int k;
190 #pragma omp for schedule(static)
191  for (k=1; k<=n; ++k)
192  {
193  double stmp1=sqt[j-k]*tmpx1;
194  double stmp2=sqt[k]*tmpx1;
195  double save1 = stmp1*d[k][0], save2 = stmp2*d[k-1][0];
196  dd[k][0] = sqt[j]*(save1+save2);
197  for (int i=1; i<=n; ++i)
198  {
199  dd[k][i] = sqt[i]*(save2-save1);
200  save1 = stmp1*d[k][i];
201  save2 = stmp2*d[k-1][i];
202  dd[k][i] += sqt[j-i]*(save1+save2);
203  }
204  }
205 }
206  dd.swap(d);
207  }
208  }
209  return d;
210  }
211 
212 wigner_d_risbo_openmp::wigner_d_risbo_openmp(int lmax, double ang)
213  : p(sin(ang/2)), q(cos(ang/2)), sqt(2*lmax+1),
214  d(lmax+1,2*lmax+1), dd(lmax+1,2*lmax+1), n(-1)
215  { for (tsize m=0; m<sqt.size(); ++m) sqt[m] = sqrt(double(m)); }
216 
217 const arr2<double> &wigner_d_risbo_openmp::recurse ()
218  {
219  ++n;
220  if (n==0)
221  d[0][0] = 1;
222  else if (n==1)
223  {
224  d[0][0] = q*q; d[0][1] = -p*q*sqt[2]; d[0][2] = p*p;
225  d[1][0] = -d[0][1]; d[1][1] = q*q-p*p; d[1][2] = d[0][1];
226  }
227  else
228  {
229  // padding
230  int sign = (n&1)? -1 : 1;
231  for (int i=0; i<=2*n-2; ++i)
232  {
233  d[n][i] = sign*d[n-2][2*n-2-i];
234  sign=-sign;
235  }
236  for (int j=2*n-1; j<=2*n; ++j)
237  {
238  double xj = 1./j;
239  dd[0][0] = q*d[0][0];
240  for (int i=1;i<j; ++i)
241  dd[0][i] = xj*sqt[j]*(q*sqt[j-i]*d[0][i] - p*sqt[i]*d[0][i-1]);
242  dd[0][j] = -p*d[0][j-1];
243 #pragma omp parallel
244 {
245  int k;
246 #pragma omp for schedule(static)
247  for (k=1; k<=n; ++k)
248  {
249  double t1 = xj*sqt[j-k]*q, t2 = xj*sqt[j-k]*p;
250  double t3 = xj*sqt[k ]*p, t4 = xj*sqt[k ]*q;
251  dd[k][0] = xj*sqt[j]*(q*sqt[j-k]*d[k][0] + p*sqt[k]*d[k-1][0]);
252  for (int i=1; i<j; ++i)
253  dd[k][i] = t1*sqt[j-i]*d[k ][i] - t2*sqt[i]*d[k ][i-1]
254  + t3*sqt[j-i]*d[k-1][i] + t4*sqt[i]*d[k-1][i-1];
255  dd[k][j] = -t2*sqt[j]*d[k][j-1] + t4*sqt[j]*d[k-1][j-1];
256  }
257 }
258  dd.swap(d);
259  }
260  }
261  return d;
262  }
263 
264 
266  double epsilon)
267  : eps(epsilon), lmax(lmax_),
268  logsum(2*lmax+1), lc05(thetas.size()), ls05(thetas.size()),
269  flm1(2*lmax+1), flm2(2*lmax+1),
270  cf(maxscale+1-minscale), costh(thetas.size()), xl(lmax+1),
271  thetaflip(thetas.size()),
272  m1(-1234567890), m2(-1234567890), am1(-1234567890), am2(-1234567890),
273  mlo(-1234567890), mhi(-1234567890),
274  fx(lmax+2), result(lmax+1)
275  {
276  planck_assert(lmax>=0,"lmax too small");
277  logsum[0] = 0.;
278  for (tsize m=1; m<logsum.size(); ++m)
279  logsum[m] = logsum[m-1]+log(static_cast<long double>(m));
280  for (tsize lm=0; lm<flm1.size(); ++lm)
281  {
282  flm1[lm] = sqrt(1./(lm+1.));
283  flm2[lm] = sqrt(lm/(lm+1.));
284  }
285  for (tsize i=0; i<cf.size(); ++i)
286  cf[i] = ldexp(1.,(int(i)+minscale)*large_exponent2);
287 
288  fsmall = ldexp(1.,-large_exponent2);
289  fbig = ldexp(1.,large_exponent2);
290 
291  for (tsize i=0; i<thetas.size(); ++i)
292  {
293  double theta=fmodulo(thetas[i],twopi);
294  if (theta>pi) theta-=twopi;
295  thetaflip[i]=(theta<0);
296  theta=abs(theta); // now theta is in (0; pi)
297  // tiny adjustments to make sure cos and sin (theta/2) are positive
298  if (theta==0.) theta=1e-16;
299  if (abs_approx(theta,pi,1e-15)) theta=pi-1e-15;
300  costh[i]=cos(theta);
301  lc05[i]=log(cos(0.5L*theta));
302  ls05[i]=log(sin(0.5L*theta));
303  }
304  xl[0]=0;
305  for (tsize l=1; l<xl.size(); ++l) xl[l]=1./l;
306 
307  for (tsize l=0; l<fx.size(); ++l)
308  fx[l][0]=fx[l][1]=fx[l][2]=0.;
309  }
310 
311 void wignergen_scalar::prepare (int m1_, int m2_)
312  {
313  if ((m1_==m1) && (m2_==m2)) return;
314 
315  int mlo_=abs(m1_), mhi_=abs(m2_);
316  if (mhi_<mlo_) swap(mhi_,mlo_);
317  bool ms_similar = ((mhi==mhi_) && (mlo==mlo_));
318  bool flip_m_sign = ms_similar && ((m1*m2)!=(m1_*m2_));
319 
320  m1=m1_; m2=m2_;
321  mlo=am1=abs(m1); mhi=am2=abs(m2);
322  if (mhi<mlo) swap(mhi,mlo);
323 
324  if (ms_similar)
325  {
326  if (flip_m_sign)
327  for (int l=mhi; l<lmax; ++l)
328  fx[l+1][1]=-fx[l+1][1];
329  }
330  else
331  {
332  for (int l=mhi; l<lmax; ++l)
333  {
334  double t = flm1[l+m1]*flm1[l-m1]*flm1[l+m2]*flm1[l-m2];
335  double lt = 2*l+1;
336  double l1 = l+1;
337  fx[l+1][0]=l1*lt*t;
338  fx[l+1][1]=m1*m2*xl[l]*xl[l+1];
339  t = flm2[l+m1]*flm2[l-m1]*flm2[l+m2]*flm2[l-m2];
340  fx[l+1][2]=t*l1*xl[l];
341  }
342  }
343 
344  prefactor = 0.5L*(logsum[2*mhi]-logsum[mhi+mlo]-logsum[mhi-mlo]);
345 
346  preMinus = false;
347  if (mhi==am1)
348  {
349  cosPow = mhi-m2; sinPow = mhi+m2;
350  if (m1>=0)
351  { swap(cosPow, sinPow); preMinus=((mhi-m2)&1); }
352  }
353  else
354  {
355  cosPow = mhi+m1; sinPow = mhi-m1;
356  if (m2<0)
357  { swap(cosPow, sinPow); preMinus=((mhi+m1)&1); }
358  }
359  }
360 
361 const arr<double> &wignergen_scalar::calc (int nth, int &firstl)
362  {
363  calc(nth, firstl, result);
364  return result;
365  }
366 
367 void wignergen_scalar::calc (int nth, int &firstl, arr<double> &resx) const
368  {
369  int l=mhi;
370  const dbl3 *fy = &fx[0];
371  const double cth = costh[nth];
372  double *res = &resx[0];
373  long double logval = prefactor + lc05[nth]*cosPow + ls05[nth]*sinPow;
374  logval *= inv_ln2;
375  int scale = int (logval/large_exponent2)-minscale;
376  double rec1 = 0.;
377  double rec2 = double(exp(ln2*(logval-(scale+minscale)*large_exponent2)));
378  if (preMinus ^ (thetaflip[nth] && ((am1+am2)&1))) rec2 = -rec2;
379 
380  while(scale<0) // iterate until we reach the realm of IEEE numbers
381  {
382  if (++l>lmax) break;
383  rec1 = (cth - fy[l][1])*fy[l][0]*rec2 - fy[l][2]*rec1;
384  if (++l>lmax) break;
385  rec2 = (cth - fy[l][1])*fy[l][0]*rec1 - fy[l][2]*rec2;
386 
387  while (abs(rec2)>fbig)
388  {
389  rec1 *= fsmall;
390  rec2 *= fsmall;
391  ++scale;
392  }
393  }
394 
395  if (scale<0) { firstl=lmax+1; return; }
396  rec1 *= cf[scale];
397  rec2 *= cf[scale];
398 
399  for (;l<lmax-1;l+=2) // iterate until we cross the eps threshold
400  {
401  if (abs(rec2)>eps) break;
402  rec1 = (cth - fy[l+1][1])*fy[l+1][0]*rec2 - fy[l+1][2]*rec1;
403  if (abs(rec1)>eps) { swap(rec1,rec2); ++l; break; }
404  rec2 = (cth - fy[l+2][1])*fy[l+2][0]*rec1 - fy[l+2][2]*rec2;
405  }
406  if ((abs(rec2)<=eps) && (++l<=lmax))
407  {
408  rec1 = (cth - fy[l][1])*fy[l][0]*rec2 - fy[l][2]*rec1;
409  swap (rec1,rec2);
410  }
411 
412  if ((l==lmax)&&(abs(rec2)<=eps)) { firstl=lmax+1; return; }
413  firstl = l;
414  if (l>lmax) return;
415 
416  res[l]=rec2;
417 
418  for (;l<lmax-1;l+=2)
419  {
420  res[l+1] = rec1 = (cth - fy[l+1][1])*fy[l+1][0]*rec2 - fy[l+1][2]*rec1;
421  res[l+2] = rec2 = (cth - fy[l+2][1])*fy[l+2][0]*rec1 - fy[l+2][2]*rec2;
422  }
423  while (true)
424  {
425  if (++l>lmax) break;
426  res[l] = rec1 = (cth - fy[l][1])*fy[l][0]*rec2 - fy[l][2]*rec1;
427  if (++l>lmax) break;
428  res[l] = rec2 = (cth - fy[l][1])*fy[l][0]*rec1 - fy[l][2]*rec2;
429  }
430  }
431 
432 #ifdef __SSE2__
433 
434 #define RENORMALIZE \
435  do \
436  { \
437  double rec1a, rec1b, rec2a, rec2b, cfa, cfb; \
438  rec1.writeTo(rec1a,rec1b); rec2.writeTo(rec2a,rec2b); \
439  corfac.writeTo(cfa,cfb); \
440  while (abs(rec2a)>fbig) \
441  { \
442  rec1a*=fsmall; rec2a*=fsmall; ++scale1; \
443  cfa = (scale1<0) ? 0. : cf[scale1]; \
444  } \
445  while (abs(rec2b)>fbig) \
446  { \
447  rec1b*=fsmall; rec2b*=fsmall; ++scale2; \
448  cfb = (scale2<0) ? 0. : cf[scale2]; \
449  } \
450  rec1.readFrom(rec1a,rec1b); rec2.readFrom(rec2a,rec2b); \
451  corfac.readFrom(cfa,cfb); \
452  } \
453  while(0)
454 
455 #define GETPRE(prea,preb,lv) \
456  prea=(cth-fy[lv][1])*fy[lv][0]; \
457  preb=fy[lv][2];
458 
459 #define NEXTSTEP(prea,preb,prec,pred,reca,recb,lv) \
460  { \
461  prec = fy[lv][1]; \
462  preb *= reca; \
463  prea *= recb; \
464  V2df t0 (fy[lv][0]); \
465  prec = cth-prec; \
466  pred = fy[lv][2]; \
467  reca = prea-preb; \
468  prec *= t0; \
469  }
470 
471 const arr_align<V2df,16> &wignergen::calc (int nth1, int nth2, int &firstl)
472  {
473  calc(nth1, nth2, firstl, result2);
474  return result2;
475  }
476 
477 void wignergen::calc (int nth1, int nth2, int &firstl,
478  arr_align<V2df,16> &resx) const
479  {
480  int l=mhi;
481  const dbl3 *fy = &fx[0];
482  const V2df cth(costh[nth1],costh[nth2]);
483  V2df *res = &resx[0];
484  long double logval1 = prefactor + lc05[nth1]*cosPow + ls05[nth1]*sinPow,
485  logval2 = prefactor + lc05[nth2]*cosPow + ls05[nth2]*sinPow;
486  logval1 *= inv_ln2;
487  logval2 *= inv_ln2;
488  int scale1 = int (logval1/large_exponent2)-minscale,
489  scale2 = int (logval2/large_exponent2)-minscale;
490  V2df rec1(0.);
491  double tr1 = double(exp(ln2*(logval1-(scale1+minscale)*large_exponent2))),
492  tr2 = double(exp(ln2*(logval2-(scale2+minscale)*large_exponent2)));
493  if (preMinus ^ (thetaflip[nth1] && ((am1+am2)&1))) tr1 = -tr1;
494  if (preMinus ^ (thetaflip[nth2] && ((am1+am2)&1))) tr2 = -tr2;
495  V2df rec2(tr1,tr2);
496  V2df corfac ((scale1<0) ? 0. : cf[scale1], (scale2<0) ? 0. : cf[scale2]);
497 
498  V2df eps2(eps);
499  V2df fbig2(fbig);
500 
501  V2df pre0,pre1,pre2,pre3;
502 
503  GETPRE(pre0,pre1,l+1)
504  if ((scale1<0) && (scale2<0))
505  {
506  while (true)
507  {
508  if (++l>lmax) break;
509  NEXTSTEP(pre0,pre1,pre2,pre3,rec1,rec2,l+1)
510  if (++l>lmax) break;
511  NEXTSTEP(pre2,pre3,pre0,pre1,rec2,rec1,l+1)
512  if (any(abs(rec2).gt(fbig2)))
513  {
514  RENORMALIZE;
515  if ((scale1>=0) || (scale2>=0)) break;
516  }
517  }
518  }
519 
520  if (l<=lmax)
521  {
522  GETPRE(pre0,pre1,l+1)
523  while (true)
524  {
525  V2df t1;
526  res[l]=t1=rec2*corfac;
527  if (any(abs(t1).gt(eps2)))
528  break;
529 
530  if (++l>lmax) break;
531  NEXTSTEP(pre0,pre1,pre2,pre3,rec1,rec2,l+1)
532 
533  res[l]=t1=rec1*corfac;
534  if (any(abs(t1).gt(eps2)))
535  { swap(rec1,rec2); break; }
536 
537  if (++l>lmax) break;
538  NEXTSTEP(pre2,pre3,pre0,pre1,rec2,rec1,l+1)
539 
540  if (any(abs(rec2).gt(fbig2)))
541  RENORMALIZE;
542  }
543  }
544  if ((l==lmax)&&(!any(abs(rec2).gt(eps2)))) { firstl=lmax+1; return; }
545  firstl=l;
546  if (l>lmax) return;
547 
548  GETPRE(pre0,pre1,l+1)
549  while (true)
550  {
551  V2df t1;
552  res[l]=t1=rec2*corfac;
553  if (all(abs(t1).ge(eps2)))
554  break;
555 
556  if (++l>lmax) break;
557  NEXTSTEP(pre0,pre1,pre2,pre3,rec1,rec2,l+1)
558 
559  res[l]=t1=rec1*corfac;
560  if (all(abs(t1).ge(eps2)))
561  { swap(rec1,rec2); break; }
562 
563  if (++l>lmax) break;
564  NEXTSTEP(pre2,pre3,pre0,pre1,rec2,rec1,l+1)
565 
566  if (any(abs(rec2).gt(fbig2)))
567  RENORMALIZE;
568  }
569 
570  if (l>lmax) return;
571  rec1*=corfac;
572  rec2*=corfac;
573 
574  GETPRE(pre0,pre1,l+1)
575  for (;l<lmax-1;l+=2)
576  {
577  res[l] = rec2;
578  NEXTSTEP(pre0,pre1,pre2,pre3,rec1,rec2,l+2)
579  res[l+1] = rec1;
580  NEXTSTEP(pre2,pre3,pre0,pre1,rec2,rec1,l+3)
581  }
582 
583  res[l] = rec2;
584  if (++l<=lmax)
585  {
586  NEXTSTEP(pre0,pre1,pre2,pre3,rec1,rec2,l+1)
587  res[l] = rec1;
588  }
589  }
590 
591 #endif /* __SSE2__ */
592 
593 wigner_estimator::wigner_estimator (int lmax_, double epsPow_)
594  : lmax(lmax_), xlmax(1./lmax_), epsPow(epsPow_) {}
595 
596 void wigner_estimator::prepare_m (int m1_, int m2_)
597  {
598  m1=abs(m1_); m2=abs(m2_);
599  mbig=max(m1,m2);
600  double cos1=m1*xlmax, cos2=m2*xlmax;
601  double s1s2=sqrt((1.-cos1*cos1)*(1.-cos2*cos2));
602  cosm1m2=cos1*cos2+s1s2;
603  }
604 
605 bool wigner_estimator::canSkip (double theta) const
606  {
607  if (mbig==lmax) return false; // don't have a good criterion for this case
608  double delta = m1*m1 + m2*m2 - abs(2.*m1*m2*cos(theta));
609  double sth = sin(theta);
610  if (abs_approx(sth,0.,1e-7)) return (delta>1.); // close to a pole
611  return (((sqrt(delta)-epsPow)*cosm1m2/abs(sth)) > lmax);
612  }
Definition: arr.h:329
void swap(arr2T &other)
Definition: arr.h:456
std::size_t tsize
Definition: datatypes.h:116
void prepare(int m1_, int m2_)
Definition: wigner.cc:311
wignergen_scalar(int lmax_, const arr< double > &thetas, double epsilon)
Definition: wigner.cc:265
const arr< double > & calc(int nth, int &firstl)
Definition: wigner.cc:361
#define planck_assert(testval, msg)
double fmodulo(double v1, double v2)
Definition: math_utils.h:71
void fast_alloc(tsize sz1, tsize sz2)
Definition: arr.h:401
tsize size() const
Definition: arr.h:57
bool abs_approx(F a, F b, F epsilon=1e-5)
Definition: math_utils.h:51
T sign(const T &signvalue)
Definition: math_utils.h:88

Generated on Thu Jul 28 2022 17:32:06 for LevelS C++ support library