https://mooseframework.inl.gov
PolynomialChaos.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "PolynomialChaos.h"
11 #include "Sampler.h"
12 #include "CartesianProduct.h"
13 
14 registerMooseObject("StochasticToolsApp", PolynomialChaos);
15 
18 {
20  params.addClassDescription("Computes and evaluates polynomial chaos surrogate model.");
21  return params;
22 }
23 
25  : SurrogateModel(parameters),
26  _order(getModelData<unsigned int>("_order")),
27  _ndim(getModelData<unsigned int>("_ndim")),
28  _ncoeff(getModelData<std::size_t>("_ncoeff")),
29  _tuple(getModelData<std::vector<std::vector<unsigned int>>>("_tuple")),
30  _coeff(getModelData<std::vector<Real>>("_coeff")),
31  _poly(
32  getModelData<std::vector<std::unique_ptr<const PolynomialQuadrature::Polynomial>>>("_poly"))
33 {
34 }
35 
36 Real
37 PolynomialChaos::evaluate(const std::vector<Real> & x) const
38 {
39  mooseAssert(x.size() == _ndim, "Number of inputted parameters does not match PC model.");
40 
41  DenseMatrix<Real> poly_val(_ndim, _order);
42 
43  // Evaluate polynomials to avoid duplication
44  for (unsigned int d = 0; d < _ndim; ++d)
45  for (unsigned int i = 0; i < _order; ++i)
46  poly_val(d, i) = _poly[d]->compute(i, x[d], /*normalize =*/false);
47 
48  Real val = 0;
49  for (std::size_t i = 0; i < _ncoeff; ++i)
50  {
51  Real tmp = _coeff[i];
52  for (unsigned int d = 0; d < _ndim; ++d)
53  tmp *= poly_val(d, _tuple[i][d]);
54  val += tmp;
55  }
56 
57  return val;
58 }
59 
60 const std::vector<std::vector<unsigned int>> &
62 {
63  return _tuple;
64 }
65 
66 unsigned
67 PolynomialChaos::getPolynomialOrder(const unsigned int dim, const unsigned int i) const
68 {
69  return _tuple[i][dim];
70 }
71 
72 const std::vector<Real> &
74 {
75  return _coeff;
76 }
77 
78 Real
80 {
81  mooseAssert(_coeff.size() > 0, "The coefficient matrix is empty.");
82  return _coeff[0];
83 }
84 
85 Real
87 {
88  Real var = 0;
89  for (std::size_t i = 1; i < _ncoeff; ++i)
90  {
91  Real norm = 1.0;
92  for (std::size_t d = 0; d < _ndim; ++d)
93  norm *= _poly[d]->innerProduct(_tuple[i][d]);
94  var += _coeff[i] * _coeff[i] * norm;
95  }
96 
97  return std::sqrt(var);
98 }
99 
100 Real
101 PolynomialChaos::powerExpectation(const unsigned int n) const
102 {
103  std::vector<StochasticTools::WeightedCartesianProduct<unsigned int, Real>> order;
104  order.reserve(_ndim);
105  std::vector<std::vector<Real>> c_1d(n, std::vector<Real>(_coeff.begin() + 1, _coeff.end()));
106  for (unsigned int d = 0; d < _ndim; ++d)
107  {
108  std::vector<std::vector<unsigned int>> order_1d(n, std::vector<unsigned int>(_ncoeff - 1));
109  for (std::size_t i = 1; i < _ncoeff; ++i)
110  for (unsigned int m = 0; m < n; ++m)
111  order_1d[m][i - 1] = _tuple[i][d];
112  order.push_back(StochasticTools::WeightedCartesianProduct<unsigned int, Real>(order_1d, c_1d));
113  }
114 
115  dof_id_type n_local, st_local, end_local;
117  order[0].numRows(), n_processors(), processor_id(), n_local, st_local, end_local);
118 
119  Real val = 0;
120  for (dof_id_type i = st_local; i < end_local; ++i)
121  {
122  Real tmp = order[0].computeWeight(i);
123  for (unsigned int d = 0; d < _ndim; ++d)
124  {
125  if (MooseUtils::absoluteFuzzyEqual(tmp, 0.0))
126  break;
127  std::vector<unsigned int> comb(n);
128  for (unsigned int m = 0; m < n; ++m)
129  comb[m] = order[d].computeValue(i, m);
130  tmp *= _poly[d]->productIntegral(comb);
131  }
132  val += tmp;
133  }
134 
135  return val;
136 }
137 
138 Real
139 PolynomialChaos::computeDerivative(const unsigned int dim, const std::vector<Real> & x) const
140 {
141  return computePartialDerivative({dim}, x);
142 }
143 
144 Real
145 PolynomialChaos::computePartialDerivative(const std::vector<unsigned int> & dim,
146  const std::vector<Real> & x) const
147 {
148  mooseAssert(x.size() == _ndim, "Number of inputted parameters does not match PC model.");
149 
150  std::vector<unsigned int> grad(_ndim);
151  for (const auto & d : dim)
152  {
153  mooseAssert(d < _ndim, "Specified dimension is greater than total number of parameters.");
154  grad[d]++;
155  }
156 
157  DenseMatrix<Real> poly_val(_ndim, _order);
158 
159  // Evaluate polynomials to avoid duplication
160  for (unsigned int d = 0; d < _ndim; ++d)
161  for (unsigned int i = 0; i < _order; ++i)
162  poly_val(d, i) = _poly[d]->computeDerivative(i, x[d], grad[d]);
163 
164  Real val = 0;
165  for (std::size_t i = 0; i < _ncoeff; ++i)
166  {
167  Real tmp = _coeff[i];
168  for (unsigned int d = 0; d < _ndim; ++d)
169  tmp *= poly_val(d, _tuple[i][d]);
170  val += tmp;
171  }
172 
173  return val;
174 }
175 
176 Real
177 PolynomialChaos::computeSobolIndex(const std::set<unsigned int> & ind) const
178 {
180 
181  // If set is empty, compute mean
182  if (ind.empty())
183  return computeMean();
184 
185  // Do some sanity checks in debug
186  mooseAssert(ind.size() <= _ndim, "Number of indices is greater than number of parameters.");
187  mooseAssert(*ind.rbegin() < _ndim, "Maximum index provided exceeds number of parameters.");
188 
189  Real val = 0.0;
191  {
192  Real tmp = _coeff[i] * _coeff[i];
193  for (unsigned int d = 0; d < _ndim; ++d)
194  {
195  if ((ind.find(d) != ind.end() && _tuple[i][d] > 0) ||
196  (ind.find(d) == ind.end() && _tuple[i][d] == 0))
197  {
198  tmp *= _poly[d]->innerProduct(_tuple[i][d]);
199  }
200  else
201  {
202  tmp = 0.0;
203  break;
204  }
205  }
206  val += tmp;
207  }
208 
209  return val;
210 }
211 
212 Real
213 PolynomialChaos::computeSobolTotal(const unsigned int dim) const
214 {
216 
217  // Do some sanity checks in debug
218  mooseAssert(dim < _ndim, "Requested dimension is greater than number of parameters.");
219 
220  Real val = 0.0;
222  if (_tuple[i][dim] > 0)
223  val += _coeff[i] * _coeff[i] * _poly[dim]->innerProduct(_tuple[i][dim]);
224 
225  return val;
226 }
227 
228 void
230 {
231  if (_n_local_coeff == std::numeric_limits<dof_id_type>::max())
233  n_processors(),
234  processor_id(),
238 }
239 
240 void
241 PolynomialChaos::store(nlohmann::json & json) const
242 {
243  json["order"] = _order;
244  json["ndim"] = getNumberOfParameters();
245  json["ncoeff"] = getNumberofCoefficients();
246  json["tuple"] = getPolynomialOrders();
247  json["coeff"] = getCoefficients();
248  for (const auto & p : _poly)
249  {
250  nlohmann::json jsonp;
251  p->store(jsonp);
252  json["poly"].push_back(jsonp);
253  }
254 }
virtual Real computeMean() const
Evaluate mean: = E[u].
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
dof_id_type _local_coeff_begin
unsigned int dim
Real computePartialDerivative(const std::vector< unsigned int > &dim, const std::vector< Real > &x) const
Evaluates sum of partial derivative of expansion.
std::size_t getNumberOfParameters() const
Access number of dimensions/parameters.
void store(nlohmann::json &json) const
void linearPartitionItems(dof_id_type num_items, dof_id_type num_chunks, dof_id_type chunk_id, dof_id_type &num_local_items, dof_id_type &local_items_begin, dof_id_type &local_items_end)
dof_id_type _local_coeff_end
std::size_t getNumberofCoefficients() const
Number of terms in expansion.
processor_id_type n_processors() const
static InputParameters validParams()
const std::vector< double > x
const std::size_t & _ncoeff
Total number of coefficient (defined by size of _tuple)
const std::vector< std::vector< unsigned int > > & _tuple
A _ndim-by-_ncoeff matrix containing the appropriate one-dimensional polynomial order.
static InputParameters validParams()
dof_id_type _n_local_coeff
Variables calculation and for looping over the computed coefficients in parallel. ...
Real computeDerivative(const unsigned int dim, const std::vector< Real > &x) const
Evaluates partial derivative of expansion: du(x)/dx_dim.
auto norm(const T &a) -> decltype(std::abs(a))
const std::vector< std::vector< unsigned int > > & getPolynomialOrders() const
Access polynomial orders from tuple /.
std::string grad(const std::string &var)
Definition: NS.h:91
virtual Real evaluate(const std::vector< Real > &x) const override
Evaluate surrogate model given a row of parameters.
Real powerExpectation(const unsigned int n) const
Compute expectation of a certain power of the QoI: E[(u-)^n].
const std::vector< Real > & _coeff
These are the coefficients we are after in the PC expansion.
Real computeSobolIndex(const std::set< unsigned int > &ind) const
Computes Sobol sensitivities S_{i_1,i_2,...,i_s}, where ind = i_1,i_2,...,i_s.
Real computeSobolTotal(const unsigned int dim) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Polynomials and quadratures based on defined distributions for Polynomial Chaos.
unsigned int getPolynomialOrder(const unsigned int dim, const unsigned int i) const
const unsigned int & _order
Maximum polynomial order. The sum of 1D polynomial orders does not go above this value.
void addClassDescription(const std::string &doc_string)
const std::vector< Real > & getCoefficients() const
Access computed expansion coefficients.
PolynomialChaos(const InputParameters &parameters)
registerMooseObject("StochasticToolsApp", PolynomialChaos)
processor_id_type processor_id() const
void ErrorVector unsigned int
virtual Real computeStandardDeviation() const
Evaluate standard deviation: = sqrt(E[(u-)^2])
void linearPartitionCoefficients() const
const std::vector< std::unique_ptr< const PolynomialQuadrature::Polynomial > > & _poly
The distributions used for sampling.
uint8_t dof_id_type
const unsigned int & _ndim
Total number of parameters/dimensions.