Chi-Tech
quadrature_gausslegendre.cc
Go to the documentation of this file.
3#include <cmath>
4
5#include "ChiObjectFactory.h"
6
7#include "chi_runtime.h"
8#include "chi_log.h"
9
10#include <algorithm>
11
12#define uint unsigned int
13#define scint static_cast<int>
14
15namespace chi_math
16{
17
19
21{
23
24 // clang-format off
25 params.SetGeneralDescription("General Gauss-Legendre quadrature");
26 params.SetDocGroup("LuaQuadrature");
27 // clang-format on
28
29 params.ChangeExistingParamToOptional("order", 0);
31 "max_root_finding_iters",
32 1000,
33 "Maximum number of iterations used during root finding");
35 "root_finding_tol",
36 1.0e-12,
37 "Root finding iterative tolerance");
38
39
40 params.AddOptionalParameter("N", 1, "Number of quadrature points.");
41
42 return params;
43}
44
46 const chi::InputParameters& params)
47 : chi_math::Quadrature(params)
48{
49 const auto& assigned_params = params.ParametersAtAssignment();
50
51 const int param_count =
52 int(assigned_params.Has("order")) + int(assigned_params.Has("N"));
53 ChiInvalidArgumentIf(param_count == 2,
54 "Either \"order\" or \"N\" must be specified, not both");
55
56 const uint max_iters = params.GetParamValue<uint>("max_root_finding_iters");
57 const double tol = params.GetParamValue<double>("root_finding_tol");
58
59 if (assigned_params.Has("order"))
60 {
61 const uint N = std::ceil(((int)order_ + 1) / 2.0);
62 Initialize(N, verbose_, max_iters, tol);
63 }
64 else
65 {
66 const uint N = assigned_params.GetParamValue<uint>("N");
67 order_ = static_cast<QuadratureOrder>(std::min(scint(2 * N + 1), 43));
68 Initialize(N, verbose_, max_iters, tol);
69 }
70}
71
72// ###################################################################
73/**Populates the abscissae and weights for a Gauss-Legendre
74 * quadrature given the degree \f$ p \f$ of the mononomial such that
75 * the quadrature rule integrates exactly the weighted integrand
76 * \f$ \rho(x) x^{p} \f$, with \f$ \rho(x) := 1 \f$,
77 * on the interval \f$ [-1;+1] \f$.
78 * The number of points generated will be ceil((O+1)/2).*/
80 bool verbose,
81 unsigned int max_iters,
82 double tol)
83 : chi_math::Quadrature(in_order)
84{
85 const unsigned int N = std::ceil(((int)order_ + 1) / 2.0);
86 Initialize(N, verbose, max_iters, tol);
87}
88
89// ###################################################################
90/**Populates the abscissae and weights for a Gauss-Legendre
91 * quadrature given the number of desired quadrature points. The
92 * order of the quadrature will be 2N-1.*/
94 bool verbose,
95 unsigned int max_iters,
96 double tol)
97 : chi_math::Quadrature((QuadratureOrder)(2 * N - 1))
98{
99 Initialize(N, verbose, max_iters, tol);
100}
101
102// ###################################################################
103/**Populates the abscissae and weights for a Gauss-Legendre
104 * quadrature given the number of desired quadrature points.*/
106 bool verbose,
107 unsigned int max_iters,
108 double tol)
109{
110 switch (order_)
111 {
112 default:
113 {
114 if (verbose)
115 Chi::log.Log() << "Initializing Gauss-Legendre Quadrature "
116 "with "
117 << N << " q-points";
118
119 //========================= Compute the roots
120 auto roots = FindRoots(N, max_iters, tol);
121 for (auto v : roots)
122 qpoints_.emplace_back(v);
123
124 //========================= Compute the weights
125 weights_.resize(N, 1.0);
126 for (size_t k = 0; k < qpoints_.size(); k++)
127 {
128 weights_[k] = 2.0 * (1.0 - qpoints_[k][0] * qpoints_[k][0]) /
129 ((N + 1) * (N + 1) * Legendre(N + 1, qpoints_[k][0]) *
130 Legendre(N + 1, qpoints_[k][0]));
131
132 if (verbose)
133 Chi::log.Log() << "root[" << k << "]=" << qpoints_[k][0]
134 << ", weight=" << weights_[k];
135 } // for abscissae
136
137 break;
138 }
139 } // switch order
140
141 range_ = {-1, +1};
142}
143
144// ###################################################################
145/** Finds the roots of the Legendre polynomial.
146 *
147 * The algorithm is that depicted in:
148 *
149 * [1] Barrera-Figueroa, et al., "Multiple root finder algorithm for Legendre
150 * and Chebyshev polynomials via Newton's method", Annales Mathematicae et
151 * Informaticae, 33 (2006) pp. 3-13.
152 *
153 * \param N Is the order of the polynomial.
154 * \param roots Is a reference to the roots.
155 * \param max_iters Maximum newton iterations to perform for each root.
156 * Default: 1000.
157 * \param tol Tolerance at which the newton iteration will be terminated.
158 * Default: 1.0e-12.
159 *
160 * \author Jan*/
161std::vector<double> QuadratureGaussLegendre::FindRoots(unsigned int N,
162 unsigned int max_iters,
163 double tol)
164{
165 //======================================== Populate init guess
166 // This initial guess proved to be quite important
167 // at higher N since the roots start to get
168 // squeezed to -1 and 1.
169 int num_search_intvls = 1000;
170 if (N > 64) num_search_intvls *= 10;
171 if (N > 256) num_search_intvls *= 10;
172 if (N > 768) num_search_intvls *= 10;
173
174 if (N > 2056)
175 {
176 num_search_intvls *= 10;
178 << "chi_math::QuadratureGaussLegendre::FindRoots: "
179 << "The order of the polynomial for which to find the roots is "
180 << "greater than 2056. Accuracy of the root finder will be diminished "
181 << "along with a reduction in stability.";
182 }
183
184 // For this code we simply check to see where the
185 // polynomial changes sign.
186 double delta = 2.0 / num_search_intvls;
187 std::vector<double> xk(N, 0.0);
188 int counter = -1;
189 for (size_t i = 0; i < num_search_intvls; i++)
190 {
191 double x_i = -1.0 + i * delta;
192 double x_ip1 = x_i + delta;
193
194 if (Legendre(N, x_i) * Legendre(N, x_ip1) < 0.0)
195 xk[++counter] = (x_ip1 + x_i) / 2.0;
196 }
197
198 //======================================== Apply algorithm
199 // Refer to equation 4.3 in [1]. Sum 1 (S1) is used in the
200 // computation of B at x_k. Sum 2 (S2) is used in equation 4.3.
201 // Equation 4.3 is broken up into pieces as follows:
202 // - a = block bracket containing the second derivative
203 // - b = denominator
204 // - c = everything but xold
205 for (int k = 0; k < N; k++)
206 {
207 for (size_t iteration = 0; iteration < max_iters; iteration++)
208 {
209 double xold = xk[k];
210 double f = Legendre(N, xold); // Function evaluation
211 double fp = dLegendredx(N, xold); // First derivative
212 double fpp = d2Legendredx2(N, xold); // Second derivative
213
214 //===================== Compute sum 1
215 double S1 = 0.0;
216 for (int i = 0; i <= (k - 1); i++)
217 S1 += 1.0 / (xk[k] - xk[i]);
218
219 //===================== Compute B at x_k
220 double B_xk = fp - f * S1;
221
222 //===================== Compute sum 2
223 double S2 = 0.0;
224 for (int i = 0; i <= (k - 1); i++)
225 S2 += 1.0 / (xk[k] - xk[i]) / (xk[k] - xk[i]);
226
227 //===================== Compute final formula
228 double a = fpp + f * S2;
229 double b = B_xk * B_xk + fp * fp - f * a;
230 double c = 2.0 * f * B_xk / b;
231
232 xk[k] = xold - c;
233
234 if (std::fabs(xk[k] - xold) < tol) break;
235 } // for iteration
236 } // for k
237
238 std::stable_sort(xk.begin(), xk.end());
239
240 return xk;
241}
242
243} // namespace chi_math
#define ChiInvalidArgumentIf(condition, message)
static chi::ChiLog & log
Definition: chi_runtime.h:81
LogStream Log0Warning()
Definition: chi_log.h:231
LogStream Log(LOG_LVL level=LOG_0)
Definition: chi_log.cc:35
void SetDocGroup(const std::string &doc_group)
const ParameterBlock & ParametersAtAssignment() const
void AddOptionalParameter(const std::string &name, T value, const std::string &doc_string)
void SetGeneralDescription(const std::string &description)
void ChangeExistingParamToOptional(const std::string &name, T value, const std::string &doc_string="")
T GetParamValue(const std::string &param_name) const
void Initialize(unsigned int N, bool verbose, unsigned int max_iters, double tol)
QuadratureGaussLegendre(const chi::InputParameters &params)
static chi::InputParameters GetInputParameters()
static std::vector< double > FindRoots(unsigned int N, unsigned int max_iters=1000, double tol=1.0e-12)
static chi::InputParameters GetInputParameters()
Definition: quadrature.cc:66
std::vector< chi_math::QuadraturePointXYZ > qpoints_
Definition: quadrature.h:37
std::pair< double, double > range_
Definition: quadrature.h:45
QuadratureOrder order_
Definition: quadrature.h:36
std::vector< double > weights_
Definition: quadrature.h:38
double d2Legendredx2(int N, double x)
Definition: legendrepoly.cc:54
double dLegendredx(int N, double x)
Definition: legendrepoly.cc:37
QuadratureOrder
Definition: quadrature.h:12
RegisterChiObject(chi_math, QuadratureGaussChebyshev)
double Legendre(int N, double x)
Definition: legendrepoly.cc:11
#define scint
#define uint