Chi-Tech
GolubFischer.cc
Go to the documentation of this file.
1#include "GolubFischer.h"
2
3#include "chi_runtime.h"
4#include "chi_log.h"
5
6#include <cmath>
7
8/**Master callable function that will return a reference to the abscissae and
9 * weights of the discrete angles.*/
11{
12 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "Getting Discrete Scattering Angles" << '\n';
13
14 for (int m=0; m<mell.size(); m++)
15 {
16 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "Moment " << m << " " << mell[m];
17 }
18
19 std::vector<double> in_mell;
20 in_mell = mell;
21
22 int N = in_mell.size()-1;
23 int n = (N+1)/2;
24
25 xn_wn_.resize(n, std::pair<double,double>(0.0, 0.0));
26
27 if (N==0)
28 return xn_wn_;
29
30 /* Legendre recurrence coefficients */
31 Tvecdbl a; a.resize(2*n,0.0);
32 Tvecdbl b; b.resize(2*n,0.0);
33 Tvecdbl c; c.resize(2*n,0.0);
34
35 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "a,b,c:\n";
36 for(int j=0; j<2*n; j++)
37 {
38 a[j] = 0.0;
39 b[j] = j/(2.0*j+1);
40 c[j] = (j+1.0)/(2*j+1);
41 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2)
42 << a[j] << " "
43 << b[j] << " "
44 << c[j] << " \n";
45
46 }
47
48 MCA(in_mell, a, b, c);
49
51
52 for (int i=0; i<n; i++)
53 {
54 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "i " << xn_wn_[i].first << " " << xn_wn_[i].second << '\n';
55 }
56
57 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "Done" << '\n';
58
59 return xn_wn_;
60}
61
62/**Applies the Modified Chebyshev Algorithm contained in [1] to find the
63 * recursion coefficients for the orthogonal polynomials.*/
65{
66 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "MCA Start" << '\n';
67
68 int N = in_mell.size()-1;
69 int n = (N+1)/2;
70
71 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "N " << N << " n " << n << '\n';
72 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "alpha, beta" << '\n';
73
74 alpha_.resize(n + 1, 0.0);
75 beta_.resize(n + 1, 0.0);
76
77 std::vector<std::vector<double>> sigma(n+1,std::vector<double>(2*n+1,0.0));
78
79
80 for(int ell=0; ell<2*n; ell++)
81 {
82 sigma[0][ell] = in_mell[ell];
83 }
84
85 alpha_[0] = a[0] + c[0] * sigma[0][1] / sigma[0][0];
86 beta_[0] = in_mell[0];
87
88 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << 0 << " " << alpha_[0] << " " << beta_[0] << "\n";
89
90
91 for(int k=1; k<n+1; k++)
92 {
93 for(int ell=k; ell<(2*n-k+1); ell++)
94 {
95 double sigmakm2ell = 0.0;
96
97 if (k==1)
98 {
99 sigmakm2ell = 0.0;
100 }
101 else
102 {
103 sigmakm2ell = sigma[k-2][ell];
104 }
105 sigma[k][ell] = c[ell]*sigma[k-1][ell+1]
106 - (alpha_[k - 1] - a[ell]) * sigma[k - 1][ell]
107 - beta_[k - 1] * sigmakm2ell
108 +b[ell]*sigma[k-1][ell-1];
109 }
110 alpha_[k] = a[k]
111 -c[k-1]*(sigma[k-1][k]/sigma[k-1][k-1])
112 +c[k]*(sigma[k][k+1]/sigma[k][k]);
113 beta_[k] = c[k - 1] * sigma[k][k] / sigma[k - 1][k - 1];
114
115 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << k << " " << alpha_[k] << " " << beta_[k] << "\n";
116 }
117
118 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "Done" << '\n';
119}
120
121/**Finds the roots of the orthogonal polynomial.*/
122void chi_math::GolubFischer::RootsOrtho(int& N, Tvecdbl& in_alpha, Tvecdbl& in_beta)
123{
124 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "RootsOrtho Start" << '\n';
125
126 int maxiters = 1000;
127 double tol = 1.0e-6;
128 double adder = 0.999*2/std::max(N-1,1);
129
130 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "Check 1: Init guess" << '\n';
131
132 Tvecdbl xn; xn.resize(N, 0.0);
133 Tvecdbl wn; wn.resize(N, 0.0);
134
135 for(int i=0; i<N; i++)
136 {
137 xn[i] = -0.999+i*adder;
138 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "x[" << i << "]=" << xn[i] << "\n";
139 }
140
141
142
143 Tvecdbl norm; norm.resize(N+1, 0.0);
144 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "Check 2 " << in_beta[0] << '\n';
145 norm[0] = in_beta[0];
146 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "Check 3a norms" << '\n';
147 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << norm[0] << '\n';
148 for (int i=1; i<(N+1); i++)
149 {
150 norm[i]=in_beta[i]*norm[i-1];
151 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << norm[i] << '\n';
152 }
153
154 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "Check 3" << '\n';
155
156 for (int k=0; k<N; k++)
157 {
158 int i = 0;
159
160 while (i<maxiters)
161 {
162 double xold = xn[k];
163 double a = Ortho(N, xold, in_alpha, in_beta);
164 double b = dOrtho(N, xold, in_alpha, in_beta);
165 double c = 0;
166
167 for (int j=0; j<k; j++)
168 {
169 c = c+(1.0/(xold-xn[j]));
170 }
171
172 double xnew = xold-(a/(b-a*c));
173 if (std::isnan(xnew))
174 {
175 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "xnew " << i << " " << xnew << " y=" << a << std::endl;
176 Chi::Exit(EXIT_FAILURE);
177 }
178
179 double res = std::fabs(xnew-xold);
180 xn[k] = xnew;
181
182 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "xnew " << i << " " << xnew << " y=" << a << std::endl;
183
184 if (res<tol)
185 {
186 break;
187 }
188
189 i = i+1;
190 }//while
191
192 }//for k
193
194 for (int i=0; i<N-1; i++)
195 {
196 for (int j=0; j<N-i-1; j++)
197 {
198 if (xn[j]>xn[j+1])
199 {
200 double tempx = xn[j+1];
201 double tempw = wn[j+1];
202 xn[j+1] = xn[j];
203 wn[j+1] = wn[j];
204 xn[j] = tempx;
205 wn[j] = tempw;
206 }
207 }
208 }
209
210 for (int i=0; i<N; i++)
211 {
212 wn[i] = 0.0;
213
214 for (int k=0; k<N; k++)
215 {
216 wn[i] += Ortho(k, xn[i], in_alpha, in_beta)*
217 Ortho(k, xn[i], in_alpha, in_beta)/norm[k];
218 }
219
220 wn[i] = 1.0/wn[i];
221 }
222 for (int i=0; i<N; i++)
223 {
224 xn_wn_[i].first = xn[i];
225 xn_wn_[i].second = wn[i];
226 }
227
228 Chi::log.Log(chi::ChiLog::LOG_LVL::LOG_0VERBOSE_2) << "Done" << '\n';
229}
230
231/**Computes the function evaluation of the orthogonal polynomials.*/
232double chi_math::GolubFischer::Ortho(int ell, double x, Tvecdbl& in_alpha, Tvecdbl& in_beta)
233{
234 if (ell==0)
235 {
236 return 1;
237 }
238
239 if (ell==1)
240 {
241 return (x-in_alpha[0]);
242 }
243
244 double Pnm1 = 1.0;
245 double Pn = (x-in_alpha[0]);
246 double Pnp1 = 0.0;
247
248 for (int n=2; n<ell+1; n++)
249 {
250 int ns = n-1;
251 Pnp1 = (x-in_alpha[ns])*Pn-in_beta[ns]*Pnm1;
252 Pnm1 = Pn;
253 Pn = Pnp1;
254 }
255
256 return Pnp1;
257}
258
259/**Computes the derivative of the orthogonal polynomials.*/
260double chi_math::GolubFischer::dOrtho(int ell, double x, Tvecdbl& in_alpha, Tvecdbl& in_beta)
261{
262
263 double eps = 0.000001;
264 double y2 = Ortho(ell, x+eps, in_alpha, in_beta);
265 double y1 = Ortho(ell, x-eps, in_alpha, in_beta);
266
267 double m = (y2-y1)/2.0/eps;
268
269 return m;
270}
std::vector< double > Tvecdbl
Definition: GolubFischer.h:36
std::vector< std::pair< double, double > > AnglePairs
Definition: GolubFischer.h:35
static void Exit(int error_code)
Definition: chi_runtime.cc:342
static chi::ChiLog & log
Definition: chi_runtime.h:81
LogStream Log(LOG_LVL level=LOG_0)
Definition: chi_log.cc:35
void RootsOrtho(int &N, Tvecdbl &in_alpha, Tvecdbl &in_beta)
void MCA(Tvecdbl &in_mell, Tvecdbl &a, Tvecdbl &b, Tvecdbl &c)
Definition: GolubFischer.cc:64
double dOrtho(int ell, double x, Tvecdbl &in_alpha, Tvecdbl &in_beta)
AnglePairs & GetDiscreteScatAngles(Tvecdbl &mell)
Definition: GolubFischer.cc:10
double Ortho(int ell, double x, Tvecdbl &in_alpha, Tvecdbl &in_beta)