https://mooseframework.inl.gov
Loading...
Searching...
No Matches
SobolReporter.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 "SobolReporter.h"
11#include "SobolSampler.h"
12#include "SobolCalculators.h"
14
15// MOOSE includes
16#include "MooseVariable.h"
18#include "ThreadedNodeLoop.h"
19
20#include "libmesh/quadrature.h"
21
22#include <numeric>
23
24registerMooseObject("StochasticToolsApp", SobolReporter);
25
28{
30 params.addClassDescription("Compute SOBOL statistics values of a given VectorPostprocessor or "
31 "Reporter objects and vectors.");
32 params.addParam<SamplerName>("sampler", "SobolSampler object.");
33
34 params.addParam<std::vector<VectorPostprocessorName>>(
35 "vectorpostprocessors",
36 "List of VectorPostprocessor(s) to utilized for statistic computations.");
37
38 params.addParam<std::vector<ReporterName>>(
39 "reporters", {}, "List of Reporter values to utilized for statistic computations.");
40
41 params.addParam<std::vector<Real>>(
42 "ci_levels",
43 std::vector<Real>(),
44 "A vector of confidence levels to consider, values must be in (0, 1).");
45 params.addParam<unsigned int>(
46 "ci_replicates",
47 10000,
48 "The number of replicates to use when computing confidence level intervals.");
49 params.addParam<unsigned int>("ci_seed",
50 1,
51 "The random number generator seed used for creating replicates "
52 "while computing confidence level intervals.");
53 return params;
54}
55
57 : GeneralReporter(parameters),
58 _sobol_sampler(getSampler<SobolSampler>("sampler")),
59 _ci_levels(getParam<std::vector<Real>>("ci_levels")),
60 _ci_replicates(getParam<unsigned int>("ci_replicates")),
61 _ci_seed(getParam<unsigned int>("ci_seed")),
62 _initialized(false)
63{
64 // CI levels error checking
65 if (!_ci_levels.empty())
66 {
67 if (*std::min_element(_ci_levels.begin(), _ci_levels.end()) <= 0)
68 paramError("ci_levels", "The supplied levels must be greater than zero.");
69 else if (*std::max_element(_ci_levels.begin(), _ci_levels.end()) >= 1)
70 paramError("ci_levels", "The supplied levels must be less than 1.0");
71 }
72
73 if ((!isParamValid("reporters") && !isParamValid("vectorpostprocessors")) ||
74 (getParam<std::vector<ReporterName>>("reporters").empty() &&
75 getParam<std::vector<VectorPostprocessorName>>("vectorpostprocessors").empty()))
77 "The 'vectorpostprocessors' and/or 'reporters' parameters must be defined and non-empty.");
78}
79
80void
82{
83 if (_initialized)
84 return;
85
86 // Stats for Reporters
87 if (isParamValid("reporters"))
88 {
89 std::vector<std::string> unsupported_types;
90 const auto & reporter_names = getParam<std::vector<ReporterName>>("reporters");
91 for (const auto & r_name : reporter_names)
92 {
93 if (hasReporterValueByName<std::vector<Real>>(r_name))
94 declareValueHelper<Real>(r_name);
95 else if (hasReporterValueByName<std::vector<std::vector<Real>>>(r_name))
96 declareValueHelper<std::vector<Real>>(r_name);
97 else
98 unsupported_types.emplace_back(r_name.getCombinedName());
99 }
100
101 if (!unsupported_types.empty())
102 paramError("reporters",
103 "The following reporter value(s) do not have a type supported by the "
104 "StatisticsReporter:\n",
105 MooseUtils::join(unsupported_types, ", "));
106 }
107
108 // Stats for VPP
109 if (isParamValid("vectorpostprocessors"))
110 {
111 const auto & vpp_names = getParam<std::vector<VectorPostprocessorName>>("vectorpostprocessors");
112 for (const auto & vpp_name : vpp_names)
113 {
114 const VectorPostprocessor & vpp_object =
116 const std::set<std::string> & vpp_vectors = vpp_object.getVectorNames();
117 for (const auto & vec_name : vpp_vectors)
118 {
119 ReporterName r_name(vpp_name, vec_name);
120 declareValueHelper<Real>(r_name);
121 }
122 }
123 }
124
125 _initialized = true;
126}
127
128void
129SobolReporter::store(nlohmann::json & json) const
130{
131 Reporter::store(json);
132 if (!_ci_levels.empty())
133 json["confidence_intervals"] = {{"method", "percentile"},
134 {"levels", _ci_levels},
135 {"replicates", _ci_replicates},
136 {"seed", _ci_seed}};
137
138 json["num_params"] = _sobol_sampler.getNumberOfCols();
139 json["indices"].push_back("FIRST_ORDER");
140 json["indices"].push_back("TOTAL");
142 json["indices"].push_back("SECOND_ORDER");
143}
144
145template <typename T>
146void
148{
149 const auto & mode = _fe_problem.getReporterData().getReporterMode(r_name);
150 const auto & data = getReporterValueByName<std::vector<T>>(r_name);
151 const std::string s_name = r_name.getObjectName() + "_" + r_name.getValueName();
152 if (!_ci_levels.empty())
154 s_name,
156 data,
157 mode,
159 MooseEnum("percentile", "percentile"),
162 _ci_seed);
163 else
164 declareValueByName<SobolState<T>, SobolReporterContext<std::vector<T>, T>>(
165 s_name, REPORTER_MODE_ROOT, data, mode, _sobol_sampler);
166}
167
168template <typename InType, typename OutType>
170 const libMesh::ParallelObject & other,
171 const MooseObject & producer,
173 const InType & data,
174 const ReporterProducerEnum & mode,
175 const SobolSampler & sampler)
176 : ReporterGeneralContext<SobolState<OutType>>(other, producer, state),
177 _data(data),
178 _data_mode(mode),
179 _sampler(sampler),
180 _calc(other, "SOBOL", _sampler.resample())
181{
182}
183
184template <typename InType, typename OutType>
186 const libMesh::ParallelObject & other,
187 const MooseObject & producer,
189 const InType & data,
190 const ReporterProducerEnum & mode,
191 const SobolSampler & sampler,
192 const MooseEnum & ci_method,
193 const std::vector<Real> & ci_levels,
194 unsigned int ci_replicates,
195 unsigned int ci_seed)
196 : SobolReporterContext<InType, OutType>(other, producer, state, data, mode, sampler)
197{
199 StochasticTools::makeBootstrapCalculator<std::vector<InType>, std::vector<OutType>>(
200 ci_method, other, ci_levels, ci_replicates, ci_seed, _calc);
201}
202
203template <typename InType, typename OutType>
204void
206{
207 auto & val = this->_state.value(); // Convenience
208 val.first.clear();
209 val.second.clear();
210
211 const bool is_dist = _data_mode == REPORTER_MODE_DISTRIBUTED;
212 if (is_dist || this->processor_id() == 0)
213 {
214 const std::size_t ncol =
215 _sampler.resample() ? 2 * _sampler.getNumberOfCols() + 2 : _sampler.getNumberOfCols() + 2;
216 const std::vector<InType> data_reshape =
217 StochasticTools::reshapeVector(_data, ncol, /*row_major =*/true);
218
219 val.first = _calc.compute(data_reshape, is_dist);
220 if (_ci_calc_ptr)
221 val.second = _ci_calc_ptr->compute(data_reshape, is_dist);
222 }
223
225}
226
227template <typename InType, typename OutType>
228void
230{
231 storeSobol(json, this->_state.value(), _sampler.getNumberOfCols());
232}
233
234template <typename InType, typename OutType>
235void
237 const SobolState<OutType> & val,
238 unsigned int nparam)
239{
240 if (val.first.empty())
241 return;
242
243 // Convenience
244 const unsigned int nlevels = val.second.size();
245
246 std::pair<std::vector<OutType>, std::vector<std::vector<OutType>>> first_order;
247 std::pair<std::vector<OutType>, std::vector<std::vector<OutType>>> total;
248
249 first_order.first.assign(val.first.begin(), val.first.begin() + nparam);
250 total.first.assign(val.first.begin() + nparam, val.first.begin() + nparam + nparam);
251 if (nlevels > 0)
252 {
253 first_order.second.resize(nlevels);
254 total.second.resize(nlevels);
255 for (const auto & l : make_range(nlevels))
256 {
257 first_order.second[l].assign(val.second[l].begin(), val.second[l].begin() + nparam);
258 total.second[l].assign(val.second[l].begin() + nparam,
259 val.second[l].begin() + nparam + nparam);
260 }
261 }
262 json["FIRST_ORDER"] = first_order;
263 json["TOTAL"] = total;
264
265 if (val.first.size() > 2 * nparam)
266 {
267 std::pair<std::vector<std::vector<OutType>>, std::vector<std::vector<std::vector<OutType>>>>
268 second_order;
269
270 second_order.first.resize(nparam, std::vector<OutType>(nparam));
271 for (const auto & i : make_range(nparam))
272 second_order.first[i][i] = val.first[i];
273 unsigned int ind = 2 * nparam;
274 for (const auto & i : make_range(nparam))
275 for (const auto & j : make_range(i + 1, nparam))
276 {
277 second_order.first[i][j] = val.first[ind++];
278 second_order.first[j][i] = second_order.first[i][j];
279 }
280
281 if (nlevels > 0)
282 {
283 second_order.second.resize(nlevels, second_order.first);
284
285 for (const auto & l : make_range(nlevels))
286 {
287 for (const auto & i : make_range(nparam))
288 second_order.second[l][i][i] = val.second[l][i];
289 ind = 2 * nparam;
290 for (const auto & i : make_range(nparam))
291 for (const auto & j : make_range(i + 1, nparam))
292 {
293 second_order.second[l][i][j] = val.second[l][ind++];
294 second_order.second[l][j][i] = second_order.second[l][i][j];
295 }
296 }
297 }
298 json["SECOND_ORDER"] = second_order;
299 }
300}
301
302template void SobolReporter::declareValueHelper<Real>(const ReporterName & r_name);
303template class SobolReporterContext<std::vector<Real>, Real>;
304template void SobolReporter::declareValueHelper<std::vector<Real>>(const ReporterName & r_name);
305template class SobolReporterContext<std::vector<std::vector<Real>>, std::vector<Real>>;
const double T
const ReporterMode REPORTER_MODE_DISTRIBUTED
const ReporterMode REPORTER_MODE_ROOT
registerMooseObject("StochasticToolsApp", SobolReporter)
std::pair< std::vector< OutType >, std::vector< std::vector< OutType > > > SobolState
void ErrorVector unsigned int
const VectorPostprocessor & getVectorPostprocessorObjectByName(const std::string &object_name, const THREAD_ID tid=0) const
const ReporterData & getReporterData() const
static InputParameters validParams()
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
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
const ReporterProducerEnum & getReporterMode(const ReporterName &reporter_name) const
virtual void clear() final
bool hasReporterValueByName(const ReporterName &reporter_name) const
const std::string & getObjectName() const
const std::string & getValueName() const
T & declareValueByName(const ReporterValueName &value_name, Args &&... args)
virtual void store(nlohmann::json &json) const
dof_id_type getNumberOfCols() const
virtual void finalize() override
static void storeSobol(nlohmann::json &json, const SobolState< OutType > &val, unsigned int nparam)
StochasticTools::SobolCalculator< InType, OutType > _calc
Storage for the SobolCalculator object, this is created in constructor.
virtual void store(nlohmann::json &json) const override
std::unique_ptr< StochasticTools::BootstrapCalculator< std::vector< InType >, std::vector< OutType > > > _ci_calc_ptr
Storage for the BootstrapCalculator for the desired confidence interval calculations (optional)
SobolReporterContext(const libMesh::ParallelObject &other, const MooseObject &producer, ReporterState< SobolState< OutType > > &state, const InType &data, const ReporterProducerEnum &mode, const SobolSampler &sampler)
Computes Sobol sensitivity indices, see SobolCalculators.
bool _initialized
Whether or not initialize() has been called for reporter value declaration.
const unsigned int & _ci_replicates
Number of CI replicates to use in Bootstrap methods.
virtual void initialize() override
const unsigned int & _ci_seed
Random seed for producing CI replicates.
virtual void store(nlohmann::json &json) const override
static InputParameters validParams()
const std::vector< Real > & _ci_levels
CI levels to be computed.
SobolReporter(const InputParameters &parameters)
void declareValueHelper(const ReporterName &r_name)
Helper for adding Sobol reporter values.
const SobolSampler & _sobol_sampler
The sampler that generated the samples that produced results for the _results_vectors.
A class used to perform Monte Carlo sampling for performing Sobol sensitivity analysis.
bool resample() const
Resampling flag, see SobolStatistics.
FEProblemBase & _fe_problem
const std::set< std::string > & getVectorNames() const
std::vector< T > resample(const std::vector< T > &data, MooseRandom &generator, const std::size_t seed_index=0)
std::vector< std::vector< T > > reshapeVector(const std::vector< T > &vec, std::size_t n, bool row_major)
Reshape a vector into matrix-like vector of vectors.