https://mooseframework.inl.gov
DirectPerturbationReporter.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 
12 
13 registerMooseObject("StochasticToolsApp", DirectPerturbationReporter);
14 
17 {
19  params.addClassDescription("Compute local sensitivities using the direct perturbation method.");
20 
21  params.addRequiredParam<SamplerName>("sampler",
22  "Direct Perturbation sampler used to generate samples.");
23  params.addParam<std::vector<VectorPostprocessorName>>(
24  "vectorpostprocessors",
25  {},
26  "List of VectorPostprocessor(s) to utilize for sensitivity computations.");
27  params.addParam<std::vector<ReporterName>>(
28  "reporters", {}, "List of Reporter values to utilize for sensitivity computations.");
29 
30  params.addParam<bool>("relative_sensitivity",
31  false,
32  "If the reporter should return relative or absolute sensitivities.");
33 
34  return params;
35 }
36 
38  : GeneralReporter(parameters),
39  _sampler(getSampler<DirectPerturbationSampler>("sampler")),
40  _relative_sensitivity(getParam<bool>("relative_sensitivity")),
41  _initialized(false)
42 {
43  if (getParam<std::vector<ReporterName>>("reporters").empty() &&
44  getParam<std::vector<VectorPostprocessorName>>("vectorpostprocessors").empty())
45  mooseError(
46  "The 'vectorpostprocessors' and/or 'reporters' parameters must be defined and non-empty.");
47 }
48 
49 void
51 {
52  // It is enough to do this once
53  if (_initialized)
54  return;
55 
56  // Sensitivities from Reporters
57  std::vector<std::string> unsupported_types;
58  for (const auto & r_name : getParam<std::vector<ReporterName>>("reporters"))
59  {
60  if (hasReporterValueByName<std::vector<Real>>(r_name))
61  declareValueHelper<Real>(r_name);
62  else if (hasReporterValueByName<std::vector<std::vector<Real>>>(r_name))
63  declareValueHelper<std::vector<Real>>(r_name);
64  else
65  unsupported_types.push_back(r_name.getCombinedName());
66  }
67 
68  if (!unsupported_types.empty())
69  paramError("reporters",
70  "The following reporter value(s) do not have a type supported by the "
71  "DirectPerturbationReporter:\n",
72  MooseUtils::join(unsupported_types, ", "));
73 
74  // Sensitivities from VPPs
75  for (const auto & vpp_name :
76  getParam<std::vector<VectorPostprocessorName>>("vectorpostprocessors"))
77  for (const auto & vec_name :
79  declareValueHelper<Real>(ReporterName(vpp_name, vec_name));
80  _initialized = true;
81 }
82 
83 template <typename DataType>
84 void
86 {
87  // We create a reporter value for the sensitivities based on the input
88  const auto & data = getReporterValueByName<std::vector<DataType>>(r_name);
89  const std::string s_name = r_name.getObjectName() + "_" + r_name.getValueName();
90  declareValueByName<std::vector<DataType>, DirectPerturbationReporterContext<DataType>>(
92 }
93 
94 template <typename DataType>
96  const libMesh::ParallelObject & other,
97  const MooseObject & producer,
98  ReporterState<std::vector<DataType>> & state,
99  DirectPerturbationSampler & sampler,
100  const std::vector<DataType> & data,
101  const bool relative_sensitivity)
102  : ReporterGeneralContext<std::vector<DataType>>(other, producer, state),
103  _sampler(sampler),
104  _data(data),
105  _relative_sensitivity(relative_sensitivity)
106 {
107  this->_state.value().resize(_sampler.getNumberOfCols());
108 }
109 
110 template <typename DataType>
111 void
113 {
114  const dof_id_type offset = _sampler.getLocalRowBegin();
115  const dof_id_type num_columns = _sampler.getNumberOfCols();
116 
117  // If we are computing the relative sensitivity, we will need
118  // the reference value. So the process that has that will communicate it
119  // to everybody. We reuse the initialization function for the reference
120  // value as well
121  auto reference_value = initializeDataType(_data[0]);
122  if (_relative_sensitivity)
123  {
124  if (_sampler.getLocalRowBegin() == 0)
125  reference_value = _data[0];
126 
127  this->comm().sum(reference_value);
128  }
129 
130  for (const auto param_i : make_range(num_columns))
131  {
132  // If we need relative coefficients we need to normalize the difference
133  const auto interval = _relative_sensitivity ? _sampler.getRelativeInterval(param_i)
134  : _sampler.getAbsoluteInterval(param_i);
135 
136  dof_id_type left_i;
137  dof_id_type right_i;
138  // Depending on which method we use, the indices will change
139  if (_sampler.perturbationMethod() == "central_difference")
140  {
141  left_i = 2 * param_i + 1;
142  right_i = 2 * param_i + 2;
143  }
144  else
145  {
146  left_i = param_i + 1;
147  right_i = 0;
148  }
149 
150  const bool left_i_in_owned_range =
151  _sampler.getLocalRowBegin() <= left_i && left_i < _sampler.getLocalRowEnd();
152  const bool right_i_in_owned_range =
153  _sampler.getLocalRowBegin() <= right_i && right_i < _sampler.getLocalRowEnd();
154 
155  if (left_i_in_owned_range || right_i_in_owned_range)
156  {
157  const dof_id_type copy_i = left_i_in_owned_range ? left_i - offset : right_i - offset;
158  this->_state.value()[param_i] = initializeDataType(_data[copy_i]);
159  }
160 
161  // We add the contribution from one side
162  if (left_i_in_owned_range)
163  addSensitivityContribution(
164  this->_state.value()[param_i], _data[left_i - offset], reference_value, interval);
165 
166  // We add the contribution from the other side
167  if (right_i_in_owned_range)
168  addSensitivityContribution(
169  this->_state.value()[param_i], _data[right_i - offset], reference_value, -interval);
170  }
171 
172  // We gather the contributions across all processors
173  this->vectorSum();
174 }
175 
176 template <typename DataType>
177 void
179  DataType & add_to,
180  const DataType & to_add,
181  const DataType & reference_value,
182  const Real interval) const
183 {
184  // DataType is a numeric type that we can sum (excluding bool)
185  if constexpr (std::is_arithmetic<DataType>::value && !std::is_same<DataType, bool>::value)
186  {
187  add_to += to_add / (_relative_sensitivity ? interval * reference_value : interval);
188  return;
189  }
190  // DataType is a vector type
191  else if constexpr (is_std_vector<DataType>::value)
192  {
193  // It can still be anything in the vector elements, so we will check this later
194  using VectorValueType = typename DataType::value_type;
195 
196  mooseAssert(add_to.size() == to_add.size(), "The vectors for summation have different sizes!");
197 
198  // Check if the vector elements are of a numeric type
199  if constexpr (std::is_arithmetic<VectorValueType>::value &&
200  !std::is_same<VectorValueType, bool>::value)
201  {
202  for (const auto index : index_range(add_to))
203  add_to[index] +=
204  to_add[index] / (_relative_sensitivity ? interval * reference_value[index] : interval);
205  return;
206  }
207  // Check if the vector elements are also vectors
208  else if constexpr (is_std_vector<VectorValueType>::value)
209  {
210  // This is as deep as we will go for now
211  using InnerValueType = typename VectorValueType::value_type;
212 
213  // Check if the inner vector elements are of a numeric type
214  if constexpr (std::is_arithmetic<InnerValueType>::value &&
215  !std::is_same<InnerValueType, bool>::value)
216  {
217  // Iterate over each inner vector in the outer vector
218  for (auto & inner_index : index_range(add_to))
219  {
220  mooseAssert(add_to[inner_index].size() == to_add[inner_index].size(),
221  "The vectors for summation have different sizes!");
222  for (const auto index : index_range(add_to[inner_index]))
223  add_to[inner_index][index] +=
224  to_add[inner_index][index] /
225  (_relative_sensitivity ? interval * reference_value[inner_index][index] : interval);
226  }
227  return;
228  }
229  else
230  static_assert(Moose::always_false<DataType>,
231  "Sensitivity coefficient computation is not implemented for the given type!");
232  }
233  }
234  else
235  static_assert(Moose::always_false<DataType>,
236  "Sensitivity coefficient computation is not implemented for the given type!");
237 }
238 
239 template <typename DataType>
240 DataType
242  const DataType & example_output) const
243 {
244  // DataType is a numeric type so we just return 0
245  if constexpr (std::is_arithmetic<DataType>::value && !std::is_same<DataType, bool>::value)
246  return 0.0;
247  // DataType is a vector type
248  else if constexpr (is_std_vector<DataType>::value)
249  {
250  // It can still be anything in the vector elements, so we will check this later
251  using VectorValueType = typename DataType::value_type;
252 
253  // Check if the vector elements are of a numeric type
254  if constexpr (std::is_arithmetic<VectorValueType>::value &&
255  !std::is_same<VectorValueType, bool>::value)
256  return std::vector<VectorValueType>(example_output.size(), 0);
257  // Check if the vector elements are also vectors
258  else if constexpr (is_std_vector<VectorValueType>::value)
259  {
260  // This is as deep as we will go for now
261  using InnerValueType = typename VectorValueType::value_type;
262 
263  // Check if the inner vector elements are of a numeric type
264  if constexpr (std::is_arithmetic<InnerValueType>::value &&
265  !std::is_same<InnerValueType, bool>::value)
266  {
267  auto return_vector = std::vector<VectorValueType>(example_output.size());
268  // Iterate over each inner vector in the outer vector
269  for (auto & inner_index : index_range(example_output))
270  return_vector[inner_index].resize(example_output.size(), 0.0);
271  return return_vector;
272  }
273  }
274  else
275  static_assert(Moose::always_false<DataType>,
276  "Sensitivity coefficient computation is not implemented for the given type!");
277  }
278  else
279  static_assert(Moose::always_false<DataType>,
280  "Sensitivity coefficient initialization is not implemented for the given type!");
281 }
std::string join(Iterator begin, Iterator end, const std::string &delimiter)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
A class used to generate samples for a direct perturbation analysis.
registerMooseObject("StochasticToolsApp", DirectPerturbationReporter)
const ReporterMode REPORTER_MODE_ROOT
Reporter class for computing and displaying local sensitivity coefficients around a nominal value usi...
ReporterState< std::vector< DataType > > & _state
static InputParameters validParams()
void declareValueHelper(const ReporterName &r_name)
Helper for adding direct perturbation-based reporter values.
static InputParameters validParams()
const bool _relative_sensitivity
If relative sensitivity should be computed.
DirectPerturbationReporterContext(const libMesh::ParallelObject &other, const MooseObject &producer, ReporterState< std::vector< DataType >> &state, DirectPerturbationSampler &sampler, const std::vector< DataType > &data, const bool relative_sensitivity)
Constructor.
void addRequiredParam(const std::string &name, const std::string &doc_string)
DataType initializeDataType(const DataType &example_output) const
Initialize the sensitivity container, split into a separate function due to the different constructor...
const T & getParam(const std::string &name) const
const VectorPostprocessor & getVectorPostprocessorObjectByName(const std::string &object_name, const THREAD_ID tid=0) const
void paramError(const std::string &param, Args... args) const
const std::string & getObjectName() const
Reporter context for computing direct perturbation-based sensitivity coefficients.
DirectPerturbationSampler & _sampler
Reference to the direct perturbation sampler.
void addSensitivityContribution(DataType &add_to, const DataType &to_add, const DataType &reference_value, const Real interval) const
Compute direct perturbation sensitivity, split into a separate function due to the different operator...
FEProblemBase & _fe_problem
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
T & value(const std::size_t time_index=0)
DirectPerturbationReporter(const InputParameters &parameters)
const std::string & getValueName() const
DirectPerturbationSampler & _sampler
Direct perturbation sampler.
virtual void initialize() override final
const std::set< std::string > & getVectorNames() const
auto index_range(const T &sizable)
dof_id_type getNumberOfCols() const
bool hasReporterValueByName(const ReporterName &reporter_name) const
bool _initialized
Whether or not initialize() has been called for reporter value declaration.
uint8_t dof_id_type