https://mooseframework.inl.gov
InverseMapping.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 "InverseMapping.h"
11 #include "SubProblem.h"
12 #include "Assembly.h"
13 #include "NonlinearSystemBase.h"
14 
15 #include "libmesh/sparse_matrix.h"
16 
17 registerMooseObject("StochasticToolsApp", InverseMapping);
18 
21 {
23 
24  params.addClassDescription("Evaluates surrogate models and maps the results back to a full "
25  "solution field for given variables.");
26  params.addParam<std::vector<UserObjectName>>(
27  "surrogate", std::vector<UserObjectName>(), "The names of the surrogates for each variable.");
28  params.addRequiredParam<UserObjectName>(
29  "mapping", "The name of the mapping object which provides the inverse mapping function.");
30  params.addRequiredParam<std::vector<VariableName>>(
31  "variable_to_fill",
32  "The names of the variables that this object is supposed to populate with the "
33  "reconstructed results.");
34  params.addRequiredParam<std::vector<VariableName>>(
35  "variable_to_reconstruct",
36  "The names of the variables in the nonlinear system which we would like to approximate. This "
37  "is important for DoF information.");
38  params.addRequiredParam<std::vector<Real>>(
39  "parameters",
40  "The input parameters for the surrogate. If no surrogate is supplied these are assumed to be "
41  "the coordinates in the latent space.");
42  params.declareControllable("parameters");
43 
44  return params;
45 }
46 
48  : GeneralUserObject(parameters),
49  MappingInterface(this),
51  _var_names_to_fill(getParam<std::vector<VariableName>>("variable_to_fill")),
52  _var_names_to_reconstruct(getParam<std::vector<VariableName>>("variable_to_reconstruct")),
53  _surrogate_model_names(getParam<std::vector<UserObjectName>>("surrogate")),
54  _input_parameters(getParam<std::vector<Real>>("parameters"))
55 {
56  if (_var_names_to_fill.size() != _var_names_to_reconstruct.size())
57  paramError("variable_to_fill",
58  "The number of variables to fill should be the same as the number of entries in "
59  "`variable_to_reconstruct`");
60  if (_surrogate_model_names.size())
61  {
62  if (_var_names_to_fill.size() != _surrogate_model_names.size())
63  paramError("surrogate",
64  "The number of surrogates should match the number of variables which need to be "
65  "reconstructed!");
66  }
67 }
68 
69 void
71 {
72  _mapping = &getMapping("mapping");
73 
74  _surrogate_models.clear();
75  for (const auto & name : _surrogate_model_names)
77 
78  _variable_to_fill.clear();
80 
81  const auto & mapping_variable_names = _mapping->getVariableNames();
82 
83  // We query the links to the MooseVariables mentioned in the input parameters
84  for (const auto & var_i : index_range(_var_names_to_reconstruct))
85  {
86  if (std::find(mapping_variable_names.begin(),
87  mapping_variable_names.end(),
88  _var_names_to_reconstruct[var_i]) == mapping_variable_names.end())
89  paramError("variable_to_reconstruct",
90  "Couldn't find mapping for " + _var_names_to_reconstruct[var_i] +
91  "! Double check the training process and make sure that the mapping includes "
92  "the given variable!");
93 
95  _variable_to_reconstruct.push_back(
97 
98  auto & fe_type_reconstruct = _variable_to_reconstruct.back()->feType();
99  auto & fe_type_fill = _variable_to_fill.back()->feType();
100 
101  if (fe_type_reconstruct != fe_type_fill)
102  paramError("variable_to_fill",
103  "The FEtype should match the ones defined for `variable_to_reconstruct`");
104 
105  if (fe_type_reconstruct.family == SCALAR)
106  paramError("variable_to_fill", "InverseMapping does not support SCALAR variables!");
107  }
108 }
109 
110 void
112 {
113  for (auto var_i : index_range(_var_names_to_reconstruct))
114  {
115  MooseVariableFieldBase & var_to_fill = *_variable_to_fill[var_i];
116  MooseVariableFieldBase & var_to_reconstruct = *_variable_to_reconstruct[var_i];
117 
118  // We create a temporary solution vector that will store the reconstructed solution.
119  std::unique_ptr<NumericVector<Number>> temporary_vector =
120  var_to_reconstruct.sys().solution().zero_clone();
121 
122  std::vector<Real> reduced_coefficients;
123  if (_surrogate_models.size())
124  _surrogate_models[var_i]->evaluate(_input_parameters, reduced_coefficients);
125  else
126  reduced_coefficients = _input_parameters;
127 
128  // The sanity check on the size of reduced_coefficients is happening in the inverse mapping
129  // function
130  DenseVector<Real> reconstructed_solution;
132  _var_names_to_reconstruct[var_i], reduced_coefficients, reconstructed_solution);
133 
134  // We set the global DoF indices of the requested variable. The underlying assumption here is
135  // that we are reconstructing the solution in an application which has the same ordering in the
136  // extracted `dofs` vector as the one which was used to serialize the solution vectors in
137  // `SerializedSolutionTransfer`.
138  var_to_reconstruct.sys().setVariableGlobalDoFs(_var_names_to_reconstruct[var_i]);
139 
140  // Get the DoF indices
141  const auto & dofs = var_to_reconstruct.sys().getVariableGlobalDoFs();
142 
143  // Get the dof map to be able to determine the local dofs easily
144  const auto & dof_map = var_to_reconstruct.sys().system().get_dof_map();
145  dof_id_type local_dof_begin = dof_map.first_dof();
146  dof_id_type local_dof_end = dof_map.end_dof();
147 
148  // Populate the temporary vector with the reconstructed solution
149  for (const auto & dof_i : index_range(dofs))
150  if (dofs[dof_i] >= local_dof_begin && dofs[dof_i] < local_dof_end)
151  temporary_vector->set(dofs[dof_i], reconstructed_solution(dof_i));
152 
153  // Get the system and variable numbers for the dof objects
154  unsigned int to_sys_num = _variable_to_fill[var_i]->sys().system().number();
155  unsigned int to_var_num = var_to_fill.sys().system().variable_number(_var_names_to_fill[var_i]);
156 
157  unsigned int from_sys_num = var_to_reconstruct.sys().system().number();
158  unsigned int from_var_num =
159  var_to_reconstruct.sys().system().variable_number(_var_names_to_reconstruct[var_i]);
160 
161  // Get a link to the mesh for the loops over dof objects
162  const MeshBase & to_mesh = _fe_problem.mesh().getMesh();
163 
164  // First, we cover nodal degrees of freedom.
165  for (const auto & node : to_mesh.local_node_ptr_range())
166  {
167  const auto n_dofs = node->n_dofs(to_sys_num, to_var_num);
168  // We have nothing to do if we don't have dofs at this node
169  if (n_dofs < 1)
170  continue;
171 
172  // For special cases we might have multiple dofs for the same node (hierarchic types)
173  for (auto dof_i : make_range(n_dofs))
174  {
175  // Get the dof ids for the from/to variables
176  const auto & to_dof_id = node->dof_number(to_sys_num, to_var_num, dof_i);
177  const auto & from_dof_id = node->dof_number(from_sys_num, from_var_num, dof_i);
178 
179  // Fill the dof of the variable using the dof of the temporary variable
180  var_to_fill.sys().solution().set(to_dof_id, (*temporary_vector)(from_dof_id));
181  }
182  }
183 
184  // Then we move on to element-based degrees of freedom. Considering that we don't
185  // support scalar variables at the moment, this should take care of every remaining
186  // local entry. Of course, we'll only need this part if the variable is not nodal.
187  if (!_variable_to_reconstruct[var_i]->isNodal())
188  for (auto & elem : as_range(to_mesh.local_elements_begin(), to_mesh.local_elements_end()))
189  {
190  // Check how many dofs we have on the current element, if none we have nothing to do
191  const auto n_dofs = elem->n_dofs(to_sys_num, to_var_num);
192  if (n_dofs < 1)
193  continue;
194 
195  // Loop over the dofs and populate the variable
196  for (auto dof_i : make_range(n_dofs))
197  {
198  // Get the dof for the from/to variables
199  const auto & to_dof_id = elem->dof_number(to_sys_num, to_var_num, dof_i);
200  const auto & from_dof_id = elem->dof_number(from_sys_num, from_var_num, dof_i);
201 
202  var_to_fill.sys().solution().set(to_dof_id, (*temporary_vector)(from_dof_id));
203  }
204  }
205 
206  // Close the solution to make sure we can output the variable
207  var_to_fill.sys().solution().close();
208  }
209 }
void execute() override
const std::vector< VariableName > & _var_names_to_fill
The names of the variables which serve as a container for the reconstructed solution.
SCALAR
static InputParameters validParams()
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
NumericVector< Number > & solution()
VariableMappingBase & getMapping(const std::string &name) const
Get the mapping using the parameters of the moose object.
const std::vector< UserObjectName > & _surrogate_model_names
The names of the surrogate models for each variable.
virtual std::unique_ptr< NumericVector< Number > > zero_clone() const =0
virtual libMesh::System & system()=0
T & getSurrogateModelByName(const UserObjectName &name) const
Get a sampler with a given name.
const std::vector< Real > & _input_parameters
Input parameters for the surrogate models.
static InputParameters validParams()
virtual const std::string & name() const
void addRequiredParam(const std::string &name, const std::string &doc_string)
virtual const MooseVariableFieldBase & getVariable(const THREAD_ID tid, const std::string &var_name, Moose::VarKindType expected_var_type=Moose::VarKindType::VAR_ANY, Moose::VarFieldType expected_var_field_type=Moose::VarFieldType::VAR_FIELD_ANY) const override
unsigned int variable_number(std::string_view var) const
registerMooseObject("StochasticToolsApp", InverseMapping)
unsigned int number() const
virtual void inverse_map(const VariableName &vname, const std::vector< Real > &reduced_order_vector, DenseVector< Real > &full_order_vector) const =0
Map a reduced-order vector (from the latent space) back to a full-order solution vector (in DenseVect...
MeshBase & getMesh()
void initialSetup() override
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
const std::vector< dof_id_type > & getVariableGlobalDoFs()
const std::vector< VariableName > & _var_names_to_reconstruct
The names of the variables in the nonlinear system whose reconstruction we are working on...
void paramError(const std::string &param, Args... args) const
virtual void close()=0
InverseMapping(const InputParameters &params)
VariableMappingBase * _mapping
Link to the mapping object which provides the inverse mapping function.
An interface class that helps getting access to Mapping objects.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void evaluate(const std::vector< Real > &q_vector, const DenseMatrix< Real > &data, std::vector< Real > &out)
Interface for objects that need to use samplers.
FEProblemBase & _fe_problem
A user object which takes a surrogate (or just user supplied values) to determine coordinates in a la...
std::vector< MooseVariableFieldBase * > _variable_to_reconstruct
Links to the MooseVariables from the nonlinear system whose dof numbering we need to populate the var...
std::vector< MooseVariableFieldBase * > _variable_to_fill
Links to the MooseVariables of the requested variables.
virtual const std::vector< VariableName > & getVariableNames()
Get the available variable names in this mapping.
const THREAD_ID _tid
IntRange< T > make_range(T beg, T end)
virtual MooseMesh & mesh() override
void addClassDescription(const std::string &doc_string)
virtual void set(const numeric_index_type i, const Number value)=0
dof_id_type first_dof(const processor_id_type proc) const
void setVariableGlobalDoFs(const std::string &var_name)
SystemBase & sys()
const DofMap & get_dof_map() const
void declareControllable(const std::string &name, std::set< ExecFlagType > execute_flags={})
auto index_range(const T &sizable)
std::vector< SurrogateModel * > _surrogate_models
Links to the surrogate models which provide functions to determine the coordinates in the latent spac...
uint8_t dof_id_type