16#include "libmesh/dense_matrix_impl.h"
19#ifdef LIBMESH_HAVE_EXTERNAL_BOOST
20#pragma GCC diagnostic push
21#pragma GCC diagnostic ignored "-Wparentheses"
22#include <boost/math/special_functions/legendre.hpp>
23#include <boost/math/special_functions/hermite.hpp>
24#pragma GCC diagnostic pop
33std::unique_ptr<const Polynomial>
38 return std::make_unique<const Legendre>(dist->
getParam<Real>(
"lower_bound"),
39 dist->
getParam<Real>(
"upper_bound"));
41 const Normal * n_dist =
dynamic_cast<const Normal *
>(dist);
43 return std::make_unique<const Hermite>(dist->
getParam<Real>(
"mean"),
44 dist->
getParam<Real>(
"standard_deviation"));
46 ::mooseError(
"Polynomials for '", dist->
type(),
"' distributions have not been implemented.");
54 ::mooseError(
"Polynomial child class must override this method.");
61 ::mooseError(
"Polynomial child class must override this method.");
67 ::mooseError(
"Polynomial type has not been implemented.");
74 const unsigned int )
const
76 ::mooseError(
"Polynomial type has not been implemented.");
83 std::vector<Real> & )
const
85 ::mooseError(
"Clenshaw quadrature has not been implemented for this polynomial type.");
91 const unsigned int nprod = order.size();
94 return (order[0] == 0 ? 1.0 : 0.0);
96 return (order[0] == order[1] ?
innerProduct(order[0]) : 0.0);
98 unsigned int poly_order = std::accumulate(order.begin(), order.end(), 0);
99 unsigned int quad_order = (poly_order % 2 == 0 ? poly_order : poly_order - 1) / 2;
101 std::vector<Real> xq;
102 std::vector<Real> wq;
106 for (
unsigned int q = 0; q < xq.size(); ++q)
109 for (
unsigned int i = 0; i < nprod; ++i)
110 prod *=
compute(order[i], xq[q],
false);
114 return val / std::accumulate(wq.begin(), wq.end(), 0.0);
118 :
Polynomial(), _lower_bound(lower_bound), _upper_bound(upper_bound)
125 std::string type =
"Legendre";
134 json[
"type"] =
"Legendre";
143 ::mooseError(
"The requested polynomial point is outside of distribution bounds.");
156 ::mooseError(
"The requested polynomial point is outside of distribution bounds.");
166 const unsigned int m)
const
181 std::vector<Real> & points,
182 std::vector<Real> & weights)
const
189 std::vector<Real> & points,
190 std::vector<Real> & weights)
const
195 for (
unsigned int i = 0; i < points.size(); ++i)
196 points[i] = points[i] * dx + xav;
202 return 1. / (2. *
static_cast<Real
>(order) + 1.);
206legendre(
const unsigned int order,
const Real
x,
const Real lower_bound,
const Real upper_bound)
208 Real xref = 2 / (upper_bound - lower_bound) * (
x - (upper_bound + lower_bound) / 2);
209#ifdef LIBMESH_HAVE_EXTERNAL_BOOST
212 return boost::math::legendre_p(order, xref);
220 for (
unsigned int k = 0; k <= (order % 2 == 0 ? order / 2 : (order - 1) / 2); ++k)
223 Real(Utility::binomial(order, k)) * Real(Utility::binomial(2 * order - 2 * k, order));
224 Real sgn = (k % 2 == 0 ? 1.0 : -1.0);
225 unsigned int ord = order - 2 * k;
226 val += sgn * coeff *
pow(xref, ord);
228 return val /
pow(2.0, order);
233 return ((2.0 * ord - 1.0) * xref *
legendre(order - 1, xref) -
234 (ord - 1.0) *
legendre(order - 2, xref)) /
245 return (Real)Utility::factorial(order);
251 std::string type =
"Hermite";
260 json[
"type"] =
"Hermite";
281 Real val =
hermite(order - m, xref);
282 for (
unsigned int i = 0; i < m; ++i)
283 val *=
static_cast<Real
>(order - i) /
_sig;
290 std::vector<Real> & points,
291 std::vector<Real> & weights)
const
297hermite(
const unsigned int order,
const Real
x,
const Real
mu,
const Real sig)
299 Real xref = (
x -
mu) / sig;
300#ifdef LIBMESH_HAVE_EXTERNAL_BOOST
306 Real val = boost::math::hermite(order, xref);
307 val /=
pow(M_SQRT2, order);
316 for (
unsigned int m = 0; m <= (order % 2 == 0 ? order / 2 : (order - 1) / 2); ++m)
318 Real sgn = (m % 2 == 0 ? 1.0 : -1.0);
320 1.0 / Real(Utility::factorial(m) * Utility::factorial(order - 2 * m)) /
pow(2.0, m);
321 unsigned int ord = order - 2 * m;
322 val += sgn * coeff *
pow(xref, ord);
324 return val * Utility::factorial(order);
327 return xref *
hermite(order - 1, xref) -
328 (
static_cast<Real
>(order) - 1.0) *
hermite(order - 2, xref);
334 std::vector<Real> & points,
335 std::vector<Real> & weights,
336 const Real lower_bound,
337 const Real upper_bound)
339 unsigned int n = order + 1;
343 DenseMatrix<Real> mat(n, n);
344 DenseVector<Real> lambda(n);
345 DenseVector<Real> lambdai(n);
346 DenseMatrix<Real> vec(n, n);
347 for (
unsigned int i = 1; i < n; ++i)
350 mat(i, i - 1) = ri / std::sqrt(((2. * ri - 1.) * (2. * ri + 1.)));
351 mat(i - 1, i) = mat(i, i - 1);
353 mat.evd_right(lambda, lambdai, vec);
355 Real dx = (upper_bound - lower_bound) / 2.0;
356 Real xav = (upper_bound + lower_bound) / 2.0;
357 for (
unsigned int i = 0; i < n; ++i)
359 points[i] = lambda(i) * dx + xav;
360 weights[i] = vec(0, i) * vec(0, i);
366 std::vector<Real> & points,
367 std::vector<Real> & weights,
372 unsigned int n = order + 1;
376 DenseMatrix<Real> mat(n, n);
377 DenseVector<Real> lambda(n);
378 DenseVector<Real> lambdai(n);
379 DenseMatrix<Real> vec(n, n);
380 for (
unsigned int i = 1; i < n; ++i)
382 mat(i, i - 1) = std::sqrt(
static_cast<Real
>(i));
383 mat(i - 1, i) = mat(i, i - 1);
385 mat.evd_right(lambda, lambdai, vec);
387 for (
unsigned int i = 0; i < n; ++i)
389 points[i] =
mu + lambda(i) * sig;
390 weights[i] = vec(0, i) * vec(0, i);
395clenshaw_curtis(
const unsigned int order, std::vector<Real> & points, std::vector<Real> & weights)
398 unsigned int N = order + (order % 2);
399 points.resize(N + 1);
400 weights.resize(N + 1);
409 std::vector<Real> dk(N / 2 + 1);
410 for (
unsigned int k = 0; k <= (N / 2); ++k)
411 dk[k] = ((k == 0 || k == (N / 2)) ? 1.0 : 2.0) / (1.0 - 4.0 * (Real)k * (Real)k);
413 for (
unsigned int n = 0; n <= (N / 2); ++n)
415 Real theta = (Real)n * M_PI / ((Real)N);
416 points[n] = -std::cos(theta);
417 for (
unsigned int k = 0; k <= (N / 2); ++k)
420 ((n == 0 || n == (N / 2)) ? 0.5 : 1.0) * std::cos((Real)k * theta * 2.0) / ((Real)N);
421 weights[n] += Dnk * dk[k];
425 for (
unsigned int n = 0; n < (N / 2); ++n)
427 points[N - n] = -points[n];
428 weights[N - n] = weights[n];
430 weights[N / 2] *= 2.0;
434 std::vector<std::unique_ptr<const Polynomial>> & poly)
436 if (npoints.size() != poly.size())
437 ::mooseError(
"List of number of 1D quadrature points must be same size as number of Polynomial "
440 std::vector<std::vector<Real>> qpoints_1D(poly.size());
441 std::vector<std::vector<Real>> qweights_1D(poly.size());
442 for (
unsigned int d = 0;
d < poly.size(); ++
d)
443 poly[
d]->gaussQuadrature(npoints[
d] - 1, qpoints_1D[
d], qweights_1D[
d]);
445 _quad = std::make_unique<const StochasticTools::WeightedCartesianProduct<Real, Real>>(
446 qpoints_1D, qweights_1D);
450 std::vector<std::unique_ptr<const Polynomial>> & poly)
455 std::vector<std::vector<unsigned int>> tuple_1d(
_ndim);
456 for (
unsigned int d = 0;
d <
_ndim; ++
d)
458 tuple_1d[
d].resize(max_order);
459 for (
unsigned int i = 0; i < max_order; ++i)
465 unsigned int maxq = max_order - 1;
466 unsigned int minq = (max_order >
_ndim ? max_order -
_ndim : 0);
467 for (std::size_t
p = 0;
p < tensor_tuple.
numRows(); ++
p)
469 std::vector<unsigned int> dorder = tensor_tuple.
computeRow(
p);
470 unsigned int q = std::accumulate(dorder.begin(), dorder.end(), 0);
471 if (q <= maxq && q >= minq)
473 int sgn = ((max_order - q - 1) % 2 == 0 ? 1 : -1);
474 _coeff.push_back(sgn * Utility::binomial(
_ndim - 1,
_ndim + q - max_order));
476 std::vector<std::vector<Real>> qpoints_1D(
_ndim);
477 std::vector<std::vector<Real>> qweights_1D(
_ndim);
478 for (
unsigned int d = 0;
d < poly.size(); ++
d)
479 poly[
d]->gaussQuadrature(dorder[
d], qpoints_1D[
d], qweights_1D[
d]);
482 qpoints_1D, qweights_1D));
512 for (
unsigned int i = 0; i <
_npoints.size() - 1; ++i)
516 ::mooseError(
"Point index requested is greater than number of points.");
522 std::vector<std::unique_ptr<const Polynomial>> & poly)
526 std::vector<std::vector<unsigned int>> tuple_1d(
_ndim);
527 for (
unsigned int d = 0;
d <
_ndim; ++
d)
529 tuple_1d[
d].resize(max_order);
530 for (
unsigned int i = 0; i < max_order; ++i)
537 std::map<std::vector<Real>, Real> quad_map;
538 unsigned int maxq = max_order - 1;
539 unsigned int minq = (max_order >
_ndim ? max_order -
_ndim : 0);
540 for (std::size_t
p = 0;
p < tensor_tuple.
numRows(); ++
p)
542 std::vector<unsigned int> dorder = tensor_tuple.
computeRow(
p);
543 unsigned int q = std::accumulate(dorder.begin(), dorder.end(), 0);
544 if (q <= maxq && q >= minq)
546 int sgn = ((max_order - q - 1) % 2 == 0 ? 1 : -1);
547 Real coeff =
static_cast<Real
>(sgn * Utility::binomial(
_ndim - 1,
_ndim + q - max_order));
549 std::vector<std::vector<Real>> qpoints_1D(
_ndim);
550 std::vector<std::vector<Real>> qweights_1D(
_ndim);
551 for (
unsigned int d = 0;
d < poly.size(); ++
d)
552 poly[
d]->clenshawQuadrature(dorder[
d], qpoints_1D[
d], qweights_1D[
d]);
556 for (
unsigned int i = 0; i < quad.
numRows(); ++i)
562 for (
const auto & it : quad_map)
570 std::unique_ptr<const PolynomialQuadrature::Polynomial> & ptr,
573 ptr->store(stream, context);
579 std::unique_ptr<const PolynomialQuadrature::Polynomial> & ptr,
582 std::string poly_type;
583 dataLoad(stream, poly_type, context);
584 if (poly_type ==
"Legendre")
586 Real lower_bound, upper_bound;
587 dataLoad(stream, lower_bound, context);
588 dataLoad(stream, upper_bound, context);
589 ptr = std::make_unique<const PolynomialQuadrature::Legendre>(lower_bound, upper_bound);
591 else if (poly_type ==
"Hermite")
596 ptr = std::make_unique<const PolynomialQuadrature::Hermite>(mean, stddev);
599 ::mooseError(
"Unknown Polynomaial type: ", poly_type);
const std::vector< double > x
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
void dataStore(std::ostream &stream, LineSegment &l, void *context)
void dataLoad(std::istream &stream, std::unique_ptr< const PolynomialQuadrature::Polynomial > &ptr, void *context)
void dataStore(std::ostream &stream, std::unique_ptr< const PolynomialQuadrature::Polynomial > &ptr, void *context)
const std::string & type() const
const T & getParam(const std::string &name) const
A class used to generate a normal distribution.
std::vector< std::pair< std::vector< Real >, Real > > _quadrature
ClenshawCurtisGrid(const unsigned int max_order, std::vector< std::unique_ptr< const Polynomial > > &poly)
virtual void store(std::ostream &stream, void *context) const override
virtual void gaussQuadrature(const unsigned int order, std::vector< Real > &points, std::vector< Real > &weights) const override
Gauss-Hermite quadrature: sum(weights) = sqrt(2\pi)
virtual Real innerProduct(const unsigned int order) const override
Hermite(const Real mu, const Real sig)
virtual Real computeDerivative(const unsigned int order, const Real x, const unsigned int m=1) const override
Compute derivative of Hermite polynomial P'n = nP{n-1}.
virtual Real compute(const unsigned int order, const Real x, const bool normalize=true) const override
Hermite polynomial using static function then scales by <P_n^2> = n!
Real computeDerivativeRef(const unsigned int order, const Real x, const unsigned int m=1) const
virtual Real innerProduct(const unsigned int order) const override
virtual void clenshawQuadrature(const unsigned int order, std::vector< Real > &points, std::vector< Real > &weights) const override
Just normal Clenshaw Curtis with shifted points.
virtual Real computeDerivative(const unsigned int order, const Real x, const unsigned int m=1) const override
Compute derivative of Legendre polynomial Recursive algorithm: d^m/dx^m P_n = (n + m - 1)d^(m-1)/dx^(...
virtual void gaussQuadrature(const unsigned int order, std::vector< Real > &points, std::vector< Real > &weights) const override
Gauss-Legendre quadrature: sum(weights) = 2.
virtual Real compute(const unsigned int order, const Real x, const bool normalize=true) const override
Legendre polynomial using static function then scales by <P_n^2> = 1 / (2n+1)
virtual void store(std::ostream &stream, void *context) const override
General polynomial class with function for evaluating a polynomial of a given order at a given point.
virtual void store(std::ostream &stream, void *context) const
Real productIntegral(const std::vector< unsigned int > order) const
virtual Real innerProduct(const unsigned int order) const =0
virtual void gaussQuadrature(const unsigned int order, std::vector< Real > &points, std::vector< Real > &weights) const =0
virtual void clenshawQuadrature(const unsigned int order, std::vector< Real > &points, std::vector< Real > &weights) const
virtual Real computeDerivative(const unsigned int order, const Real x, const unsigned int m=1) const
Computes the mth derivative of polynomial: d^mP_n/dx^m.
virtual Real compute(const unsigned int order, const Real x, const bool normalize=true) const
std::vector< int > _coeff
Modification of quadrature weight based on polynomial order.
virtual std::vector< Real > quadraturePoint(const unsigned int n) const override
Quadrature point n.
virtual Real quadratureWeight(const unsigned int n) const override
Weight for quadrature point n.
std::vector< std::unique_ptr< const StochasticTools::WeightedCartesianProduct< Real, Real > > > _quad
Container for all the combinations of quadrature products.
std::vector< std::size_t > _npoints
Cumulative number of points for each quadrature product.
unsigned int gridIndex(const unsigned int n) const
Helper function to find which quadrature product to use.
SmolyakGrid(const unsigned int max_order, std::vector< std::unique_ptr< const Polynomial > > &poly)
std::unique_ptr< const StochasticTools::WeightedCartesianProduct< Real, Real > > _quad
TensorGrid(const std::vector< unsigned int > &npoints, std::vector< std::unique_ptr< const Polynomial > > &poly)
Polynomials and quadratures based on defined distributions for Polynomial Chaos.
std::unique_ptr< const Polynomial > makePolynomial(const Distribution *dist)
void gauss_legendre(const unsigned int order, std::vector< Real > &points, std::vector< Real > &weights, const Real lower_bound, const Real upper_bound)
Generalized formula for any polynomial order.
void clenshaw_curtis(const unsigned int order, std::vector< Real > &points, std::vector< Real > &weights)
Real legendre(const unsigned int order, const Real x, const Real lower_bound=-1.0, const Real upper_bound=1.0)
Legendre polynomial of specified order.
Real hermite(const unsigned int order, const Real x, const Real mu=0.0, const Real sig=1.0)
Hermite polynomial of specified order.
void gauss_hermite(const unsigned int order, std::vector< Real > &points, std::vector< Real > &weights, const Real mu, const Real sig)
Generalized formula for any polynomial order.