https://mooseframework.inl.gov
PolynomialChaosTrainer.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 "PolynomialChaosTrainer.h"
11 #include "Sampler.h"
12 #include "CartesianProduct.h"
13 
14 registerMooseObject("StochasticToolsApp", PolynomialChaosTrainer);
15 
18 {
20  params.addClassDescription("Computes and evaluates polynomial chaos surrogate model.");
21  params.addRequiredParam<unsigned int>("order", "Maximum polynomial order.");
22  params.addRequiredParam<std::vector<DistributionName>>(
23  "distributions", "Names of the distributions samples were taken from.");
24  MooseEnum rtype("integration ols auto", "auto");
25  params.addParam<MooseEnum>(
26  "regression_type",
27  rtype,
28  "The type of regression to perform for finding polynomial coefficents.");
29  params.addParam<Real>("penalty", 0.0, "Ridge regularization penalty factor for OLS regression.");
30 
31  params.suppressParameter<MooseEnum>("response_type");
32  return params;
33 }
34 
36  : SurrogateTrainer(parameters),
37  _predictor_row(getPredictorData()),
38  _order(declareModelData<unsigned int>("_order", getParam<unsigned int>("order"))),
39  _ndim(declareModelData<unsigned int>("_ndim", _sampler.getNumberOfCols())),
40  _tuple(declareModelData<std::vector<std::vector<unsigned int>>>(
41  "_tuple", StochasticTools::MultiDimPolynomialGenerator::generateTuple(_ndim, _order))),
42  _ncoeff(declareModelData<std::size_t>("_ncoeff", _tuple.size())),
43  _coeff(declareModelData<std::vector<Real>>("_coeff")),
44  _poly(declareModelData<std::vector<std::unique_ptr<const PolynomialQuadrature::Polynomial>>>(
45  "_poly")),
46  _ridge_penalty(getParam<Real>("penalty")),
47  _quad_sampler(dynamic_cast<QuadratureSampler *>(&_sampler))
48 {
49  // Check if number of distributions is correct
51  paramError("distributions",
52  "Sampler number of columns does not match number of inputted distributions.");
53 
54  auto rtype_enum = getParam<MooseEnum>("regression_type");
55  if (rtype_enum == "auto")
56  _rtype = _quad_sampler ? 0 : 1;
57  else
58  _rtype = rtype_enum == "integration" ? 0 : 1;
59 
60  if (_rtype == 0 && _quad_sampler &&
61  (!_pvals.empty() || _pcols.size() != _sampler.getNumberOfCols()))
62  paramError("sampler",
63  "QuadratureSampler must use all Sampler columns for training, and cannot be"
64  " used with other Reporters - otherwise, quadrature integration does not work.");
65  if (_rtype == 0 && _ridge_penalty != 0.0)
66  paramError("penalty",
67  "Ridge regularization penalty is only relevant if 'regression_type = ols'.");
68 
69  // Make polynomials
70  for (const auto & nm : getParam<std::vector<DistributionName>>("distributions"))
72 
73  // Create calculators for standardization
74  if (_rtype == 1)
75  {
76  _calculators.resize(_ncoeff * 3);
77  for (const auto & term : make_range(_ncoeff))
78  {
80  _calculators[3 * term + 1] = StochasticTools::makeCalculator(MooseEnumItem("stddev"), *this);
81  _calculators[3 * term + 2] = StochasticTools::makeCalculator(MooseEnumItem("sum"), *this);
82  }
83  }
84 }
85 
86 void
88 {
89  _coeff.assign(_ncoeff, 0.0);
90 
91  if (_rtype == 1)
92  {
94  paramError("order",
95  "Number of data points (",
97  ") must be greater than the number of terms in the polynomial (",
98  _ncoeff,
99  ").");
101  _rhs.resize(_ncoeff);
102  for (auto & calc : _calculators)
103  calc->initializeCalculator();
104  _r_sum = 0.0;
105  }
106 }
107 
108 void
110 {
111  // Evaluate polynomials to avoid duplication
112  DenseMatrix<Real> poly_val(_ndim, _order);
113  for (unsigned int d = 0; d < _ndim; ++d)
114  for (unsigned int i = 0; i < _order; ++i)
115  poly_val(d, i) = _poly[d]->compute(i, _predictor_row[d], /*normalize=*/_rtype == 0);
116 
117  // Evaluate multi-dimensional polynomials
118  std::vector<Real> basis(_ncoeff, 1.0);
119  for (const auto i : make_range(_ncoeff))
120  for (const auto d : make_range(_ndim))
121  basis[i] *= poly_val(d, _tuple[i][d]);
122 
123  // For integration
124  if (_rtype == 0)
125  {
126  const Real fact = (*_rval) * (_quad_sampler ? _quad_sampler->getQuadratureWeight(_row) : 1.0);
127  for (const auto i : make_range(_ncoeff))
128  _coeff[i] += fact * basis[i];
129  }
130  // For least-squares
131  else
132  {
133  // Loop over coefficients
134  for (const auto i : make_range(_ncoeff))
135  {
136  // Matrix is symmetric, so we'll add the upper diagonal later
137  for (const auto j : make_range(i + 1))
138  _matrix(i, j) += basis[i] * basis[j];
139  _rhs(i) += basis[i] * (*_rval);
140 
141  for (unsigned int c = i * 3; c < (i + 1) * 3; ++c)
142  _calculators[c]->updateCalculator(basis[i]);
143  }
144  _r_sum += (*_rval);
145 
146  if (_ridge_penalty != 0.0)
147  for (const auto i : make_range(_ncoeff))
148  _matrix(i, i) += _ridge_penalty;
149  }
150 }
151 
152 void
154 {
155  if (_rtype == 0)
156  {
157  gatherSum(_coeff);
158  if (!_quad_sampler)
159  for (std::size_t i = 0; i < _ncoeff; ++i)
161  }
162  else
163  {
165  gatherSum(_rhs.get_values());
166  for (auto & calc : _calculators)
167  calc->finalizeCalculator(true);
168  gatherSum(_r_sum);
169 
170  std::vector<Real> mu(_ncoeff);
171  std::vector<Real> sig(_ncoeff);
172  std::vector<Real> sum_pf(_ncoeff);
173  for (const auto i : make_range(_ncoeff))
174  {
175  mu[i] = i > 0 ? _calculators[3 * i]->getValue() : 0.0;
176  sig[i] = i > 0 ? _calculators[3 * i + 1]->getValue() : 1.0;
177  sum_pf[i] = _calculators[3 * i + 2]->getValue();
178  }
179 
180  const Real n = getCurrentSampleSize();
181  for (const auto i : make_range(_ncoeff))
182  {
183  for (const auto j : make_range(i + 1))
184  {
185  _matrix(i, j) -= (mu[j] * sum_pf[i] + mu[i] * sum_pf[j]);
186  _matrix(i, j) += n * mu[i] * mu[j];
187  _matrix(i, j) /= (sig[i] * sig[j]);
188  _matrix(j, i) = _matrix(i, j);
189  }
190  _rhs(i) = (_rhs(i) - mu[i] * _r_sum) / sig[i];
191  }
192 
193  DenseVector<Real> sol;
194  _matrix.lu_solve(_rhs, sol);
195  _coeff = sol.get_values();
196 
197  for (unsigned int i = 1; i < _ncoeff; ++i)
198  {
199  _coeff[i] /= sig[i];
200  _coeff[0] -= _coeff[i] * mu[i];
201  }
202  }
203 }
A class used to produce samples based on quadrature for Polynomial Chaos.
unsigned int getCurrentSampleSize() const
unsigned int _rtype
The method in which to perform the regression (0=integration, 1=OLS)
std::size_t & _ncoeff
Total number of coefficient (defined by size of _tuple)
const Real & _ridge_penalty
The penalty parameter for Ridge regularization.
std::vector< std::vector< unsigned int > > & _tuple
A _ndim-by-_ncoeff matrix containing the appropriate one-dimensional polynomial order.
std::unique_ptr< const Polynomial > makePolynomial(const Distribution *dist)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
virtual void train() override
std::vector< unsigned int > _pcols
Columns from sampler for predictors.
std::vector< const Real * > _pvals
Predictor values from reporters.
const unsigned int & _order
Maximum polynomial order. The sum of 1D polynomial orders does not go above this value.
static InputParameters validParams()
void addRequiredParam(const std::string &name, const std::string &doc_string)
void suppressParameter(const std::string &name)
std::unique_ptr< Calculator< InType, OutType > > makeCalculator(const MooseEnumItem &item, const libMesh::ParallelObject &other)
Definition: Calculators.h:335
std::vector< std::unique_ptr< const PolynomialQuadrature::Polynomial > > & _poly
The distributions used for sampling.
dof_id_type _row
During training loop, this is the row index of the data.
void gatherSum(T &value)
Enum for batch type in stochastic tools MultiApp.
static const std::string mu
Definition: NS.h:123
QuadratureSampler * _quad_sampler
QuadratureSampler pointer, necessary for applying quadrature weights.
const T & getParam(const std::string &name) const
Real getQuadratureWeight(dof_id_type row_index) const
const std::vector< Real > & _predictor_row
Predictor values.
void paramError(const std::string &param, Args... args) const
std::vector< Real > & get_values()
const Distribution & getDistributionByName(const DistributionName &name) const
virtual void postTrain() override
void lu_solve(const DenseVector< Real > &b, DenseVector< Real > &x)
registerMooseObject("StochasticToolsApp", PolynomialChaosTrainer)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
This is the main trainer base class.
Polynomials and quadratures based on defined distributions for Polynomial Chaos.
std::vector< Real > & _coeff
These are the coefficients we are after in the PC expansion.
void resize(const unsigned int new_m, const unsigned int new_n)
IntRange< T > make_range(T beg, T end)
DenseMatrix< Real > _matrix
void addClassDescription(const std::string &doc_string)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
unsigned int & _ndim
Total number of parameters/dimensions.
static InputParameters validParams()
std::vector< std::unique_ptr< RealCalculator > > _calculators
Calculators used for standardization in linear regression.
PolynomialChaosTrainer(const InputParameters &parameters)
void ErrorVector unsigned int
dof_id_type getNumberOfCols() const
virtual void preTrain() override