Skip to content

Commit 8e59140

Browse files
author
Martin D. Weinberg
committed
Update test codes to handle high-order Ylm evaluation using prenormalized Legendre evaluation
1 parent f6f2f3f commit 8e59140

3 files changed

Lines changed: 178 additions & 161 deletions

File tree

utils/ICs/DiskEval.H

Lines changed: 94 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ private:
7676
EmpCylSL::AxiDiskPtr model;
7777
double xmin, xmax, dx, ascl;
7878
int lmax, numr;
79-
bool logr, xscl;
79+
bool logr, xscl, prenorm=true;
8080

8181
static const std::string cachefile;
8282

@@ -94,42 +94,126 @@ private:
9494
exp(0.5*(lgamma(1.0+l-m) - lgamma(1.0+l+m)));
9595
}
9696

97-
//! Ylm evaluation
98-
// CAUTION: this will fail at l>150 owing to double precision issues.
99-
double Ylm(int l, int m, double cosx)
97+
98+
//! Standard recursion
99+
//! CAUTION: this will fail at l>150 owing to double precision issues.
100+
double Ylm_standard(int l, int m, double cosx)
100101
{
101102
int M = abs(m);
102103
double plm = plgndr(l, M, cosx);
103104
if (std::isnan(plm) or std::isinf(plm))
104-
std::cout << "Failure in pldndr at l=" << l
105+
std::cout << "Failure in plgndr at l=" << l
105106
<< " m=" << m << " cosx=" << cosx << std::endl;
106107
return Nlm(l, M) * plm * pow(-1.0, M);
107108
}
108109

109110
//! Partial derivative of Ylm in theta
110-
double Zlm(int l, int m, double cosx)
111+
//! Standard version
112+
double Zlm_standard(int l, int m, double cosx)
111113
{
112114
if (l==0 or fabs(cosx)>=1.0) return 0.0;
113115

114116
int M = abs(m);
115117
double dplm = dplgndr(l, M, cosx);
116118
if (std::isnan(dplm) or std::isinf(dplm))
117-
std::cout << "Failure in pldndr at l=" << l
119+
std::cout << "Failure in dplgndr at l=" << l
118120
<< " m=" << m << " cosx=" << cosx << std::endl;
119121

120122
return -Nlm(l, M) * dplm * pow(-1.0, M) * sqrt(1.0 - cosx*cosx);
121123
}
122124

125+
126+
//! Prenormalized Ylm evaluation
127+
double Ylm_prenorm(int L, int m, double x)
128+
{
129+
int M = abs(m);
130+
131+
// Initial value precompile
132+
constexpr double ylm00 = 0.5/sqrt(M_PI);
133+
134+
// Assign initial value
135+
double pmm = ylm00;
136+
137+
// Recurrence to get l=m=M
138+
if (M>0) {
139+
double somx2 = std::sqrt( (1.0 - x)*(1.0 + x) );
140+
for (int l=1; l<=M; l++) {
141+
pmm = -std::sqrt(1.0 + 0.5/l)*somx2*pmm;
142+
}
143+
}
144+
145+
// Even or odd M?
146+
double facM = 1.0;
147+
if (M & 0x1) facM = -1.0;
148+
149+
// We are done if L equals M
150+
if (L == M) {
151+
return pmm * facM;
152+
}
153+
else {
154+
// L=M+1
155+
double pmmp1 = std::sqrt(1.0 + 2.0*(M+1))*x*pmm, pll = 0.0;
156+
if (L == M+1) {
157+
return pmmp1 * facM;
158+
}
159+
// L>M+1 recursion
160+
else {
161+
for (int l=M+2; l<=L; l++) {
162+
// Recursion constants
163+
double pfac = (2.0*l + 1.0)/(2.0*l - 3.0)/(l*l - M*M);
164+
double alpha = std::sqrt( pfac * (4*(l-1)*(l-1) - 1 ) );
165+
double beta = std::sqrt( pfac * ((l-1)*(l-1) - M*M ) );
166+
// Compute next term
167+
pll = alpha*x*pmmp1 - beta*pmm;
168+
pmm = pmmp1;
169+
pmmp1 = pll;
170+
}
171+
return pll * facM;
172+
}
173+
}
174+
}
175+
176+
//! Derivative of Ylm prenormalized
177+
double Zlm_prenorm(int L, int m, double x)
178+
{
179+
int M = abs(m);
180+
double Ylmp = Ylm_prenorm(L+1, M, x), Ylm = Ylm_prenorm(L, M, x);
181+
double fac = -1.0/std::sqrt(1.0 - x*x);
182+
double fac2 = 2.0*L + 1.0, fac3 = 2.0*L + 3.0;
183+
return fac*( Ylm*x*(1.0 + L) - Ylmp*std::sqrt( fac2/fac3*(fac2 + L*L - M*M) ) );
184+
}
185+
186+
//! Ylm evaluation
187+
double Ylm(int l, int m, double cosx)
188+
{
189+
if (prenorm)
190+
return Ylm_prenorm(l, m, cosx);
191+
else
192+
return Ylm_standard(l, m, cosx);
193+
}
194+
195+
//! Ylm derivative
196+
double Zlm(int l, int m, double cosx)
197+
{
198+
if (prenorm)
199+
return Zlm_prenorm(l, m, cosx);
200+
else
201+
return Zlm_standard(l, m, cosx);
202+
}
203+
204+
//! Coordinate scaling: scaled to physical
123205
double x_to_r(double x)
124206
{
125207
return ascl * x/(1.0 - x);
126208
}
127209

210+
//! Coordinate scaling: physical to scaled
128211
double r_to_x(double r)
129212
{
130213
return r/(r + ascl);
131214
}
132215

216+
// Coordinate scaling: Jacobian
133217
double dr_to_dx(double x)
134218
{
135219
return ascl/(1.0 - x)/(1.0 - x);
@@ -149,6 +233,9 @@ public:
149233
//! Evaluation where the return tuple is potential, dPhi/dR, dPhi/dz, dPhi/dphi
150234
std::tuple<double, double, double, double> operator()(double R, double z, double phi=0);
151235

236+
//! Set prenorm (true) standard (false) evaluation
237+
void setPrenorm(bool b) { prenorm = b; }
238+
152239
};
153240

154241
#endif

utils/ICs/DiskEval.cc

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <yaml-cpp/yaml.h> // YAML support
66

77
#include <Progress.H> // Progress bar
8+
#include <localmpi.H> // MPI variables
89

910
#include <DiskEval.H>
1011

@@ -72,14 +73,14 @@ DiskEval::DiskEval
7273
#pragma omp parallel
7374
{
7475
numthrd = omp_get_num_threads();
75-
int myid = omp_get_thread_num();
76-
if (myid==0)
76+
int tid = omp_get_thread_num();
77+
if (myid==0 and tid==0)
7778
std::cout << "Number of threads=" << numthrd << std::endl;
7879
}
7980
#endif
8081

8182
std::shared_ptr<progress::progress_display> progress;
82-
if (use_progress) {
83+
if (use_progress and myid==0 and tid==0) {
8384
std::cout << std::endl << "Begin: exact force evaluation"
8485
<< std::endl << "-----------------------------"
8586
<< std::endl;
@@ -509,14 +510,16 @@ void DiskEval::write_cache()
509510
}
510511

511512
} else {
512-
std::cerr << std::endl
513-
<< "DiskEval: could not open cache file <"
514-
<< cachefile << "> for writing" << std::endl;
513+
if (myid==0)
514+
std::cerr << std::endl
515+
<< "DiskEval: could not open cache file <"
516+
<< cachefile << "> for writing" << std::endl;
515517
}
516518

517-
std::cerr << std::endl
518-
<< "DiskEval: wrote cache file <"
519-
<< cachefile << ">" << std::endl;
519+
if (myid==0)
520+
std::cerr << std::endl
521+
<< "DiskEval: wrote cache file <"
522+
<< cachefile << ">" << std::endl;
520523
}
521524

522525
bool DiskEval::read_cache()

0 commit comments

Comments
 (0)