https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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
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())
46 "The 'vectorpostprocessors' and/or 'reporters' parameters must be defined and non-empty.");
47}
48
49void
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
83template <typename DataType>
84void
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
94template <typename DataType>
96 const libMesh::ParallelObject & other,
97 const MooseObject & producer,
98 ReporterState<std::vector<DataType>> & state,
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
110template <typename DataType>
111void
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
176template <typename DataType>
177void
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
239template <typename DataType>
240DataType
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}
registerMooseObject("StochasticToolsApp", DirectPerturbationReporter)
const ReporterMode REPORTER_MODE_ROOT
Reporter context for computing direct perturbation-based sensitivity coefficients.
DirectPerturbationSampler & _sampler
Reference to the direct perturbation sampler.
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 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...
DataType initializeDataType(const DataType &example_output) const
Initialize the sensitivity container, split into a separate function due to the different constructor...
Reporter class for computing and displaying local sensitivity coefficients around a nominal value usi...
DirectPerturbationSampler & _sampler
Direct perturbation sampler.
const bool _relative_sensitivity
If relative sensitivity should be computed.
DirectPerturbationReporter(const InputParameters &parameters)
static InputParameters validParams()
void declareValueHelper(const ReporterName &r_name)
Helper for adding direct perturbation-based reporter values.
bool _initialized
Whether or not initialize() has been called for reporter value declaration.
virtual void initialize() override final
A class used to generate samples for a direct perturbation analysis.
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)
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 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)
dof_id_type getNumberOfCols() const
FEProblemBase & _fe_problem
const std::set< std::string > & getVectorNames() const