https://mooseframework.inl.gov
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"
13 #include "BootstrapCalculators.h"
14 
15 // MOOSE includes
16 #include "MooseVariable.h"
18 #include "ThreadedNodeLoop.h"
19 
20 #include "libmesh/quadrature.h"
21 
22 #include <numeric>
23 
24 registerMooseObject("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()))
76  mooseError(
77  "The 'vectorpostprocessors' and/or 'reporters' parameters must be defined and non-empty.");
78 }
79 
80 void
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 
128 void
129 SobolReporter::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");
141  if (_sobol_sampler.resample())
142  json["indices"].push_back("SECOND_ORDER");
143 }
144 
145 template <typename T>
146 void
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"),
160  _ci_levels,
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 
168 template <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 
184 template <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 {
198  _ci_calc_ptr =
199  StochasticTools::makeBootstrapCalculator<std::vector<InType>, std::vector<OutType>>(
200  ci_method, other, ci_levels, ci_replicates, ci_seed, _calc);
201 }
202 
203 template <typename InType, typename OutType>
204 void
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 
227 template <typename InType, typename OutType>
228 void
230 {
231  storeSobol(json, this->_state.value(), _sampler.getNumberOfCols());
232 }
233 
234 template <typename InType, typename OutType>
235 void
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 
302 template void SobolReporter::declareValueHelper<Real>(const ReporterName & r_name);
304 template void SobolReporter::declareValueHelper<std::vector<Real>>(const ReporterName & r_name);
305 template class SobolReporterContext<std::vector<std::vector<Real>>, std::vector<Real>>;
A class used to perform Monte Carlo sampling for performing Sobol sensitivity analysis.
Definition: SobolSampler.h:23
std::string join(Iterator begin, Iterator end, const std::string &delimiter)
T & declareValueByName(const ReporterValueName &value_name, Args &&... args)
const SobolSampler & _sobol_sampler
The sampler that generated the samples that produced results for the _results_vectors.
Definition: SobolReporter.h:46
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.
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
bool resample() const
Resampling flag, see SobolStatistics.
Definition: SobolSampler.h:31
const ReporterMode REPORTER_MODE_ROOT
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) ...
void declareValueHelper(const ReporterName &r_name)
Helper for adding Sobol reporter values.
std::vector< T > resample(const std::vector< T > &data, MooseRandom &generator, const std::size_t seed_index=0)
static InputParameters validParams()
const std::vector< Real > & _ci_levels
CI levels to be computed.
Definition: SobolReporter.h:49
virtual void store(nlohmann::json &json) const
bool isParamValid(const std::string &name) const
const ReporterData & getReporterData() const
static void storeSobol(nlohmann::json &json, const SobolState< OutType > &val, unsigned int nparam)
const unsigned int & _ci_seed
Random seed for producing CI replicates.
Definition: SobolReporter.h:55
std::pair< std::vector< OutType >, std::vector< std::vector< OutType > >> SobolState
Definition: SobolReporter.h:62
virtual void finalize() override
const T & getParam(const std::string &name) const
bool _initialized
Whether or not initialize() has been called for reporter value declaration.
Definition: SobolReporter.h:58
const VectorPostprocessor & getVectorPostprocessorObjectByName(const std::string &object_name, const THREAD_ID tid=0) const
void paramError(const std::string &param, Args... args) const
const ReporterMode REPORTER_MODE_DISTRIBUTED
const std::string & getObjectName() const
const unsigned int & _ci_replicates
Number of CI replicates to use in Bootstrap methods.
Definition: SobolReporter.h:52
SobolReporter(const InputParameters &parameters)
Definition: SobolReporter.C:56
virtual void initialize() override
Definition: SobolReporter.C:81
virtual void store(nlohmann::json &json) const override
const ReporterProducerEnum & getReporterMode(const ReporterName &reporter_name) const
virtual void store(nlohmann::json &json) const override
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
FEProblemBase & _fe_problem
registerMooseObject("StochasticToolsApp", SobolReporter)
static InputParameters validParams()
Definition: SobolReporter.C:27
StochasticTools::SobolCalculator< InType, OutType > _calc
Storage for the SobolCalculator object, this is created in constructor.
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
const std::string & getValueName() const
SobolReporterContext(const libMesh::ParallelObject &other, const MooseObject &producer, ReporterState< SobolState< OutType >> &state, const InType &data, const ReporterProducerEnum &mode, const SobolSampler &sampler)
const std::set< std::string > & getVectorNames() const
void ErrorVector unsigned int
dof_id_type getNumberOfCols() const
Computes Sobol sensitivity indices, see SobolCalculators.
Definition: SobolReporter.h:23
bool hasReporterValueByName(const ReporterName &reporter_name) const