https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PODMapping.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 "PODMapping.h"
11#include <slepcsvd.h>
12#include "MooseTypes.h"
13#include <petscdmda.h>
14
15registerMooseObject("StochasticToolsApp", PODMapping);
16
19{
21 params.addClassDescription("Class which provides a Proper Orthogonal Decomposition-based mapping "
22 "between full-order and reduced-order spaces.");
23 params.addParam<UserObjectName>(
24 "solution_storage", "The name of the storage reporter where the snapshots are located.");
25 params.addParam<std::vector<dof_id_type>>(
26 "num_modes_to_compute",
27 "The number of modes that this object should compute. "
28 "Modes with 0 eigenvalues are filtered out, so the real number of modes "
29 "might be lower than this. This is also used for setting the "
30 "subspace sizes for distributed singular value solves. By default, the subspace used for the "
31 "SVD is twice as big as the number of requested vectors. For more information see the SLEPc "
32 "manual. If not specified, only one mode is computed per variable.");
33 params.addParam<std::vector<Real>>(
34 "energy_threshold",
35 std::vector<Real>(),
36 "The energy threshold for the automatic truncation of the number of modes. In general, the "
37 "lower this number is the more information is retained about the system by keeping more POD "
38 "modes.");
39 params.addParam<std::string>("extra_slepc_options",
40 "",
41 "Additional options for the singular/eigenvalue solvers in SLEPc.");
42 return params;
43}
44
46 : VariableMappingBase(parameters),
48 _num_modes(isParamValid("num_modes_to_compute")
49 ? getParam<std::vector<dof_id_type>>("num_modes_to_compute")
50 : std::vector<dof_id_type>(_variable_names.size(), 1)),
51 _energy_threshold(getParam<std::vector<Real>>("energy_threshold")),
52 _left_basis_functions(declareModelData<std::map<VariableName, std::vector<DenseVector<Real>>>>(
53 "left_basis_functions")),
54 _right_basis_functions(declareModelData<std::map<VariableName, std::vector<DenseVector<Real>>>>(
55 "right_basis_functions")),
56 _singular_values(
57 declareModelData<std::map<VariableName, std::vector<Real>>>("singular_values")),
58 _extra_slepc_options(getParam<std::string>("extra_slepc_options")),
59 _parallel_storage(isParamValid("solution_storage")
60 ? &getUserObject<ParallelSolutionStorage>("solution_storage")
61 : nullptr),
62 _pod(StochasticTools::POD(_parallel_storage, _extra_slepc_options, _communicator))
63{
64 if (!isParamValid("filename"))
65 {
66 if (_num_modes.size() != _variable_names.size())
67 paramError("num_modes", "The number of modes should be defined for each variable!");
68
69 for (const auto & mode : _num_modes)
70 if (!mode)
71 paramError("num_modes", "The number of modes should always be a positive integer!");
72
73 if (_energy_threshold.size())
74 {
75 if (_energy_threshold.size() != _variable_names.size())
76 paramError("energy_threshold",
77 "The energy thresholds should be defined for each variable!");
78
79 for (const auto & threshold : _energy_threshold)
80 if (threshold < 0 || threshold >= 1)
81 paramError("energy_threshold",
82 "The energy thresholds should always be in the [0,1) range!");
83 }
84
85#if PETSC_VERSION_LESS_THAN(3, 14, 0)
86 mooseError("PODMapping is not supported with PETSc version below 3.14!");
87#else
88 for (const auto & vname : _variable_names)
89 {
90 _singular_values.emplace(vname, std::vector<Real>());
91 _left_basis_functions.emplace(vname, std::vector<DenseVector<Real>>());
92 _right_basis_functions.emplace(vname, std::vector<DenseVector<Real>>());
93 _mapping_ready_to_use.emplace(vname, false);
94 }
95#endif
96 }
97}
98
99void
100PODMapping::buildMapping(const VariableName &
101#if !PETSC_VERSION_LESS_THAN(3, 14, 0)
102 vname
103#endif
104)
105{
106#if !PETSC_VERSION_LESS_THAN(3, 14, 0)
109 "solution_storage",
110 "The parallel storage reporter is not supplied! We cannot build a mapping without data!");
111
112 if (_mapping_ready_to_use.find(vname) != _mapping_ready_to_use.end() &&
113 !_mapping_ready_to_use[vname])
114 {
115 auto it = std::find(_variable_names.begin(), _variable_names.end(), vname);
116 mooseAssert(it != _variable_names.end(), "Variable " + vname + " is not in PODMapping!");
117 unsigned int var_i = std::distance(_variable_names.begin(), it);
118 // Clear storage containers for the basis functions and singular values.
119 _left_basis_functions[vname].clear();
120 _right_basis_functions[vname].clear();
121 _singular_values[vname].clear();
122 // Find the number of modes that we would want to compute
123 std::size_t num_modes_compute = (std::size_t)_num_modes[var_i];
124 // Find the first element that satisfies the threshold
125 const Real threshold = (_energy_threshold.empty() ? 0.0 : _energy_threshold[var_i]) +
126 std::numeric_limits<Real>::epsilon();
127 // Use POD class to compute for a variable
128 _pod.computePOD(vname,
131 _singular_values[vname],
132 num_modes_compute,
133 threshold);
134 _mapping_ready_to_use[vname] = true;
135 }
136
137#endif
138}
139
140void
141PODMapping::map(const VariableName & vname,
142 const unsigned int global_sample_i,
143 std::vector<Real> & reduced_order_vector) const
144{
145 mooseAssert(_parallel_storage, "We need the parallel solution storage for this operation.");
146 mooseAssert(_left_basis_functions.find(vname) != _left_basis_functions.end(),
147 "The bases for the requested variable are not available!");
148 checkIfReadyToUse(vname);
149
150 // This takes the 0th snapshot because we only support steady-state simulations
151 // at the moment.
152 const auto & snapshot = _parallel_storage->getGlobalSample(global_sample_i, vname)[0];
153
154 const auto & bases = _left_basis_functions[vname];
155
156 reduced_order_vector.clear();
157 reduced_order_vector.resize(bases.size());
158 for (auto base_i : index_range(bases))
159 reduced_order_vector[base_i] = bases[base_i].dot(snapshot);
160}
161
162void
163PODMapping::map(const VariableName & vname,
164 const DenseVector<Real> & full_order_vector,
165 std::vector<Real> & reduced_order_vector) const
166{
167 checkIfReadyToUse(vname);
168
169 mooseAssert(_left_basis_functions.find(vname) != _left_basis_functions.end(),
170 "The bases for the requested variable are not available!");
171
172 const auto & bases = _left_basis_functions[vname];
173
174 reduced_order_vector.clear();
175 reduced_order_vector.resize(bases.size());
176 for (auto base_i : index_range(bases))
177 reduced_order_vector[base_i] = bases[base_i].dot(full_order_vector);
178}
179
180void
181PODMapping::inverse_map(const VariableName & vname,
182 const std::vector<Real> & reduced_order_vector,
183 DenseVector<Real> & full_order_vector) const
184{
185 mooseAssert(std::find(_variable_names.begin(), _variable_names.end(), vname) !=
186 _variable_names.end(),
187 "Variable " + vname + " is not in PODMapping!");
188
189 checkIfReadyToUse(vname);
190
191 if (reduced_order_vector.size() != _left_basis_functions[vname].size())
192 mooseError("The number of supplied reduced-order coefficients (",
193 reduced_order_vector.size(),
194 ") is not the same as the number of basis functions (",
195 _left_basis_functions[vname].size(),
196 ") for variable ",
197 vname,
198 "!");
199 // This zeros the DenseVector too
200 full_order_vector.resize(_left_basis_functions[vname][0].size());
201
202 for (auto base_i : index_range(reduced_order_vector))
203 for (unsigned int dof_i = 0; dof_i < _left_basis_functions[vname][base_i].size(); ++dof_i)
204 full_order_vector(dof_i) +=
205 reduced_order_vector[base_i] * _left_basis_functions[vname][base_i](dof_i);
206}
207
208const DenseVector<Real> &
209PODMapping::leftBasisFunction(const VariableName & vname, const unsigned int base_i)
210{
211 mooseAssert(std::find(_variable_names.begin(), _variable_names.end(), vname) !=
212 _variable_names.end(),
213 "Variable " + vname + " is not in PODMapping!");
214
215 checkIfReadyToUse(vname);
216
217 mooseAssert(base_i < _left_basis_functions[vname].size(),
218 "The POD for " + vname + " only has " +
219 std::to_string(_left_basis_functions[vname].size()) + " left modes!");
220
221 return _left_basis_functions[vname][base_i];
222}
223
224const DenseVector<Real> &
225PODMapping::rightBasisFunction(const VariableName & vname, const unsigned int base_i)
226{
227 mooseAssert(std::find(_variable_names.begin(), _variable_names.end(), vname) !=
228 _variable_names.end(),
229 "Variable " + vname + " is not in PODMapping!");
230
231 checkIfReadyToUse(vname);
232
233 mooseAssert(base_i < _right_basis_functions[vname].size(),
234 "The POD for " + vname + " only has " +
235 std::to_string(_right_basis_functions[vname].size()) + " right modes!");
236
237 return _right_basis_functions[vname][base_i];
238}
239
240const std::vector<DenseVector<Real>> &
241PODMapping::leftBasis(const VariableName & vname)
242{
243 checkIfReadyToUse(vname);
244 if (_left_basis_functions.find(vname) == _left_basis_functions.end())
245 mooseError("We are trying to access container for variable '",
246 vname,
247 "' but we don't have it in the POD mapping!");
248 return _left_basis_functions[vname];
249}
250
251const std::vector<DenseVector<Real>> &
252PODMapping::rightBasis(const VariableName & vname)
253{
254 checkIfReadyToUse(vname);
255 if (_right_basis_functions.find(vname) == _right_basis_functions.end())
256 mooseError("We are trying to access container for variable '",
257 vname,
258 "' but we don't have it in the POD mapping!");
259 return _right_basis_functions[vname];
260}
261
262const std::vector<Real> &
263PODMapping::singularValues(const VariableName & vname)
264{
265 checkIfReadyToUse(vname);
266 if (_singular_values.find(vname) == _singular_values.end())
267 mooseError("We are trying to access container for variable '",
268 vname,
269 "' but we don't have it in the POD mapping!");
270 return _singular_values[vname];
271}
registerMooseObject("StochasticToolsApp", PODMapping)
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
bool isParamValid(const std::string &name) const
Class which provides a Proper Orthogonal Decomposition (POD)-based mapping between full-order and red...
Definition PODMapping.h:24
const std::vector< Real > & singularValues(const VariableName &vname)
Return all of the singular values for a given variable.
Definition PODMapping.C:263
std::map< VariableName, std::vector< DenseVector< Real > > > & _left_basis_functions
Restartable container holding the basis functions for each variable.
Definition PODMapping.h:107
const DenseVector< Real > & leftBasisFunction(const VariableName &vname, const unsigned int base_i)
Get the base_i-th left basis function for a given variable.
Definition PODMapping.C:209
const std::vector< dof_id_type > _num_modes
The number of modes which need to be computed.
Definition PODMapping.h:101
const std::vector< DenseVector< Real > > & rightBasis(const VariableName &vname)
Return all of the right basis functions for a given variable.
Definition PODMapping.C:252
void inverse_map(const VariableName &vname, const std::vector< Real > &reduced_order_vector, DenseVector< Real > &full_order_vector) const override
Method used for mapping reduced-order solutions for a given variable onto the full-order space.
Definition PODMapping.C:181
const StochasticTools::POD _pod
The POD object which can be used to compute the basis functions/vectors.
Definition PODMapping.h:123
void map(const VariableName &vname, const DenseVector< Real > &full_order_vector, std::vector< Real > &reduced_order_vector) const override
Method used for mapping full-order solutions for a given variable onto a latent space.
Definition PODMapping.C:163
std::map< VariableName, std::vector< Real > > & _singular_values
Restartable container holding the singular values.
Definition PODMapping.h:113
virtual void buildMapping(const VariableName &vname) override
Abstract function for building mapping for a given variable.
Definition PODMapping.C:100
const std::vector< Real > & _energy_threshold
The energy thresholds for truncation of the number of modes, defined by the user.
Definition PODMapping.h:104
const ParallelSolutionStorage *const _parallel_storage
Link to the parallel storage which holds the solution fields that are used for the SVD.
Definition PODMapping.h:120
const std::vector< DenseVector< Real > > & leftBasis(const VariableName &vname)
Return all of the left basis functions for a given variable.
Definition PODMapping.C:241
const DenseVector< Real > & rightBasisFunction(const VariableName &vname, const unsigned int base_i)
Get the base_i-th right basis function for a given variable.
Definition PODMapping.C:225
PODMapping(const InputParameters &parameters)
Definition PODMapping.C:45
static InputParameters validParams()
Definition PODMapping.C:18
std::map< VariableName, std::vector< DenseVector< Real > > > & _right_basis_functions
Restartable container holding the basis functions for each variable.
Definition PODMapping.h:110
A Reporter which stores serialized solution fields for given variables in a distributed fashion.
const std::vector< DenseVector< Real > > & getGlobalSample(unsigned int global_sample_i, const VariableName &variable) const
Get the serialized solution field which is associated with a given global sample index and variable.
void computePOD(const VariableName &vname, std::vector< DenseVector< Real > > &left_basis_functions, std::vector< DenseVector< Real > > &right_basis_functions, std::vector< Real > &singular_values, const dof_id_type num_modes, const Real energy) const
Definition POD.C:40
This is an abstract base class for objects that provide mapping between a full-order and a latent spa...
static InputParameters validParams()
const std::vector< VariableName > & _variable_names
Storage for the names of the variables this mapping can handle.
void checkIfReadyToUse(const VariableName &libmesh_dbg_var(vname)) const
Check if we have a mapping for the variable and if it is ready to be used.
std::map< VariableName, bool > & _mapping_ready_to_use
Bool to decide if we already have the mapping built or not to make sure it is not computed multiple t...
Enum for batch type in stochastic tools MultiApp.