https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MorrisReporter.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 "MorrisReporter.h"
11
12#include "MorrisSampler.h"
13
14registerMooseObject("StochasticToolsApp", MorrisReporter);
15
18{
20 params.addClassDescription("Compute global sensitivities using the Morris method.");
21
22 params.addRequiredParam<SamplerName>("sampler", "Morris sampler used to generate samples.");
23 params.addParam<std::vector<VectorPostprocessorName>>(
24 "vectorpostprocessors",
25 "List of VectorPostprocessor(s) to utilized for statistic computations.");
26 params.addParam<std::vector<ReporterName>>(
27 "reporters", {}, "List of Reporter values to utilized for statistic computations.");
28
29 // Confidence Levels
30 params.addParam<std::vector<Real>>(
31 "ci_levels",
32 std::vector<Real>(),
33 "A vector of confidence levels to consider, values must be in (0, 1).");
34 params.addParam<unsigned int>("ci_replicates",
35 10000,
36 "The number of replicates to use when computing confidence level "
37 "intervals. This is basically the number of times the statistics "
38 "are recomputed with a random selection of indices.");
39 params.addParam<unsigned int>("ci_seed",
40 1,
41 "The random number generator seed used for creating replicates "
42 "while computing confidence level intervals.");
43 return params;
44}
45
47 : GeneralReporter(parameters),
48 _sampler(getSampler("sampler")),
49 _ci_levels(getParam<std::vector<Real>>("ci_levels")),
50 _ci_replicates(getParam<unsigned int>("ci_replicates")),
51 _ci_seed(getParam<unsigned int>("ci_seed")),
52 _initialized(false)
53{
54 if (!dynamic_cast<MorrisSampler *>(&_sampler))
55 paramError("sampler", "Computing Morris sensitivities requires the use of a Morris sampler.");
56
57 // CI levels error checking
58 if (!_ci_levels.empty())
59 {
60 if (*std::min_element(_ci_levels.begin(), _ci_levels.end()) <= 0)
61 paramError("ci_levels", "The supplied levels must be greater than zero.");
62 else if (*std::max_element(_ci_levels.begin(), _ci_levels.end()) >= 1)
63 paramError("ci_levels", "The supplied levels must be less than 1.0");
64 }
65
66 if ((!isParamValid("reporters") && !isParamValid("vectorpostprocessors")) ||
67 (getParam<std::vector<ReporterName>>("reporters").empty() &&
68 getParam<std::vector<VectorPostprocessorName>>("vectorpostprocessors").empty()))
70 "The 'vectorpostprocessors' and/or 'reporters' parameters must be defined and non-empty.");
71}
72
73void
75{
76 if (_initialized)
77 return;
78
79 // Stats for Reporters
80 if (isParamValid("reporters"))
81 {
82 std::vector<std::string> unsupported_types;
83 for (const auto & r_name : getParam<std::vector<ReporterName>>("reporters"))
84 {
85 if (hasReporterValueByName<std::vector<Real>>(r_name))
86 declareValueHelper<Real>(r_name);
87 else if (hasReporterValueByName<std::vector<std::vector<Real>>>(r_name))
88 declareValueHelper<std::vector<Real>>(r_name);
89 else
90 unsupported_types.push_back(r_name.getCombinedName());
91 }
92
93 if (!unsupported_types.empty())
94 paramError("reporters",
95 "The following reporter value(s) do not have a type supported by the "
96 "MorrisReporter:\n",
97 MooseUtils::join(unsupported_types, ", "));
98 }
99
100 // Stats for VPP
101 if (isParamValid("vectorpostprocessors"))
102 for (const auto & vpp_name :
103 getParam<std::vector<VectorPostprocessorName>>("vectorpostprocessors"))
104 for (const auto & vec_name :
106 declareValueHelper<Real>(ReporterName(vpp_name, vec_name));
107 _initialized = true;
108}
109
110void
111MorrisReporter::store(nlohmann::json & json) const
112{
113 Reporter::store(json);
114 if (!_ci_levels.empty())
115 json["confidence_intervals"] = {{"method", "percentile"},
116 {"levels", _ci_levels},
117 {"replicates", _ci_replicates},
118 {"seed", _ci_seed}};
119 json["num_params"] = _sampler.getNumberOfCols();
120 json["num_trajectories"] = _sampler.getNumberOfRows() / (_sampler.getNumberOfCols() + 1);
121 if (_sampler.parameters().isParamValid("levels"))
122 json["levels"] = _sampler.parameters().get<unsigned int>("levels");
123}
124
125template <typename DataType>
126void
128{
129 const auto & data = getReporterValueByName<std::vector<DataType>>(r_name);
130 const std::string s_name = r_name.getObjectName() + "_" + r_name.getValueName();
131 if (!_ci_levels.empty())
133 s_name,
135 _sampler,
136 data,
137 MooseEnum("percentile", "percentile"),
140 _ci_seed);
141 else
142 declareValueByName<MorrisState<DataType>, MorrisReporterContext<DataType>>(
143 s_name, REPORTER_MODE_ROOT, _sampler, data);
144}
145
146template <typename DataType>
148 const MooseObject & producer,
150 Sampler & sampler,
151 const std::vector<DataType> & data)
152 : ReporterGeneralContext<MorrisState<DataType>>(other, producer, state),
153 _sampler(sampler),
154 _data(data)
155{
156 MultiMooseEnum items("mean meanabs stddev", "mean meanabs stddev", true);
157 _mu_calc = StochasticTools::makeCalculator<std::vector<DataType>, DataType>(items[0], other);
158 _mustar_calc = StochasticTools::makeCalculator<std::vector<DataType>, DataType>(items[1], other);
159 _sig_calc = StochasticTools::makeCalculator<std::vector<DataType>, DataType>(items[2], other);
160
161 // Initialize state
162 auto & mu = this->_state.value()["mu"].first;
163 mu.resize(_sampler.getNumberOfCols());
164 auto & mu_star = this->_state.value()["mu_star"].first;
165 mu_star.resize(_sampler.getNumberOfCols());
166 auto & sig = this->_state.value()["sigma"].first;
167 sig.resize(_sampler.getNumberOfCols());
168}
169
170template <typename DataType>
172 const MooseObject & producer,
174 Sampler & sampler,
175 const std::vector<DataType> & data,
176 const MooseEnum & ci_method,
177 const std::vector<Real> & ci_levels,
178 unsigned int ci_replicates,
179 unsigned int ci_seed)
180 : MorrisReporterContext<DataType>(other, producer, state, sampler, data)
181{
182 _ci_mu_calc = StochasticTools::makeBootstrapCalculator<std::vector<DataType>, DataType>(
183 ci_method, other, ci_levels, ci_replicates, ci_seed, *_mu_calc);
184 _ci_mustar_calc = StochasticTools::makeBootstrapCalculator<std::vector<DataType>, DataType>(
185 ci_method, other, ci_levels, ci_replicates, ci_seed, *_mustar_calc);
186 _ci_sig_calc = StochasticTools::makeBootstrapCalculator<std::vector<DataType>, DataType>(
187 ci_method, other, ci_levels, ci_replicates, ci_seed, *_sig_calc);
188
189 // Initialize state
190 auto & mu = this->_state.value()["mu"].second;
191 mu.resize(_sampler.getNumberOfCols());
192 auto & mu_star = this->_state.value()["mu_star"].second;
193 mu_star.resize(_sampler.getNumberOfCols());
194 auto & sig = this->_state.value()["sigma"].second;
195 sig.resize(_sampler.getNumberOfCols());
196}
197
198template <typename DataType>
199void
201{
202 dof_id_type offset;
203 if (_data.size() == _sampler.getNumberOfRows())
204 offset = _sampler.getLocalRowBegin();
205 else if (_data.size() == _sampler.getNumberOfLocalRows())
206 offset = 0;
207 else
208 mooseError("Data size inconsistency. Expected data vector to have ",
209 _sampler.getNumberOfLocalRows(),
210 " (local) or ",
211 _sampler.getNumberOfRows(),
212 " (global) elements, but actually has ",
213 _data.size(),
214 " elements. Are you using the same sampler?");
215
216 const dof_id_type nc = _sampler.getNumberOfCols(); // convenience
217 if (_sampler.getNumberOfLocalRows() % (nc + 1) > 0)
219 "Sampler does not have an appropriate number of rows. Are you using a Morris sampler?");
220
221 std::vector<std::vector<DataType>> elem_effects(
222 nc, std::vector<DataType>(_sampler.getNumberOfLocalRows() / (nc + 1)));
223 RealEigenMatrix x(nc + 1, nc);
224 std::vector<DataType> y(nc + 1);
225
226 for (dof_id_type p = 0; p < _sampler.getNumberOfLocalRows(); ++p)
227 {
228 dof_id_type traj = p / (nc + 1);
229 dof_id_type tind = p % (nc + 1);
230 const std::vector<Real> row = _sampler.getNextLocalRow();
231 for (unsigned int k = 0; k < nc; ++k)
232 x(tind, k) = row[k];
233 y[tind] = _data[p + offset];
234
235 if (tind == nc)
236 {
237 const std::vector<DataType> ee = computeElementaryEffects(x, y);
238 for (unsigned int k = 0; k < nc; ++k)
239 elem_effects[k][traj] = ee[k];
240 }
241 }
242
243 auto & mu = this->_state.value()["mu"];
244 auto & mustar = this->_state.value()["mu_star"];
245 auto & sig = this->_state.value()["sigma"];
246 for (unsigned int k = 0; k < nc; ++k)
247 {
248 mu.first[k] = _mu_calc->compute(elem_effects[k], true);
249 mustar.first[k] = _mustar_calc->compute(elem_effects[k], true);
250 sig.first[k] = _sig_calc->compute(elem_effects[k], true);
251
252 if (_ci_mu_calc)
253 mu.second[k] = _ci_mu_calc->compute(elem_effects[k], true);
254 if (_ci_mustar_calc)
255 mustar.second[k] = _ci_mustar_calc->compute(elem_effects[k], true);
256 if (_ci_sig_calc)
257 sig.second[k] = _ci_sig_calc->compute(elem_effects[k], true);
258 }
259}
260
261template <>
262std::vector<Real>
264 const std::vector<Real> & y) const
265{
266 const auto k = y.size() - 1;
267 const RealEigenMatrix dx = x.bottomRows(k) - x.topRows(k);
268 RealEigenVector dy(k);
269 for (unsigned int j = 0; j < k; ++j)
270 dy(j) = y[j + 1] - y[j];
271
272 const RealEigenVector u = dx.fullPivLu().solve(dy);
273 return std::vector<Real>(u.data(), u.data() + u.size());
274}
275
276template <>
277std::vector<std::vector<Real>>
279 const RealEigenMatrix & x, const std::vector<std::vector<Real>> & y) const
280{
281 const auto k = y.size() - 1;
282 const RealEigenMatrix dx = x.bottomRows(k) - x.topRows(k);
283 const auto solver = dx.fullPivLu();
284 RealEigenVector dy(k);
285 std::vector<std::vector<Real>> ee(k, std::vector<Real>(y[0].size()));
286 for (unsigned int i = 0; i < y[0].size(); ++i)
287 {
288 for (unsigned int j = 0; j < k; ++j)
289 dy(j) = y[j + 1][i] - y[j][i];
290 const RealEigenVector u = solver.solve(dy);
291 for (unsigned int j = 0; j < k; ++j)
292 ee[j][i] = u(j);
293 }
294 return ee;
295}
296
297template void MorrisReporter::declareValueHelper<Real>(const ReporterName & r_name);
298template class MorrisReporterContext<Real>;
299template void MorrisReporter::declareValueHelper<std::vector<Real>>(const ReporterName & r_name);
const std::vector< double > y
const std::vector< double > x
const double mu
const Real p
void mooseError(Args &&... args)
registerMooseObject("StochasticToolsApp", MorrisReporter)
std::map< std::string, std::pair< std::vector< DataType >, std::vector< std::vector< DataType > > > > MorrisState
const ReporterMode REPORTER_MODE_ROOT
void ErrorVector unsigned int
const VectorPostprocessor & getVectorPostprocessorObjectByName(const std::string &object_name, const THREAD_ID tid=0) const
static InputParameters validParams()
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
void addClassDescription(const std::string &doc_string)
bool isParamValid(const std::string &name) const
const InputParameters & parameters() const
void paramError(const std::string &param, Args... args) const
void mooseError(Args &&... args) const
const T & getParam(const std::string &name) const
bool isParamValid(const std::string &name) const
std::unique_ptr< StochasticTools::BootstrapCalculator< std::vector< DataType >, DataType > > _ci_mustar_calc
std::unique_ptr< StochasticTools::Calculator< std::vector< DataType >, DataType > > _mu_calc
Storage for the Calculator object for the desired stat, this is created in constructor.
std::unique_ptr< StochasticTools::Calculator< std::vector< DataType >, DataType > > _mustar_calc
std::vector< DataType > computeElementaryEffects(const RealEigenMatrix &x, const std::vector< DataType > &y) const
Function for computing elementary effects for a single set of trajectories This is meant to be specia...
std::unique_ptr< StochasticTools::BootstrapCalculator< std::vector< DataType >, DataType > > _ci_sig_calc
std::unique_ptr< StochasticTools::BootstrapCalculator< std::vector< DataType >, DataType > > _ci_mu_calc
Storage for the BootstrapCalculator for the desired confidence interval calculations (optional)
virtual void finalize() override
std::unique_ptr< StochasticTools::Calculator< std::vector< DataType >, DataType > > _sig_calc
MorrisReporterContext(const libMesh::ParallelObject &other, const MooseObject &producer, ReporterState< MorrisState< DataType > > &state, Sampler &sampler, const std::vector< DataType > &data)
Sampler & _sampler
Morris sampler (don't need any specific functions, but should be this type)
virtual void store(nlohmann::json &json) const override
Sampler & _sampler
Morris sampler (don't need any specific functions, but should be this type)
bool _initialized
Whether or not initialize() has been called for reporter value declaration.
const unsigned int & _ci_seed
Random seed for producing CI replicates.
const unsigned int & _ci_replicates
Number of CI replicates to use in Bootstrap methods.
virtual void initialize() override final
const std::vector< Real > & _ci_levels
CI levels to be computed.
MorrisReporter(const InputParameters &parameters)
static InputParameters validParams()
void declareValueHelper(const ReporterName &r_name)
Helper for adding Morris reporter values.
A class used to perform Monte Carlo sampling for performing Morris sensitivity analysis.
bool hasReporterValueByName(const ReporterName &reporter_name) const
const std::string & getObjectName() const
const std::string & getValueName() const
T & value(const std::size_t time_index=0)
T & declareValueByName(const ReporterValueName &value_name, Args &&... args)
virtual void store(nlohmann::json &json) const
dof_id_type getNumberOfRows() const
dof_id_type getNumberOfCols() const
FEProblemBase & _fe_problem
const std::set< std::string > & getVectorNames() const