https://mooseframework.inl.gov
Loading...
Searching...
No Matches
TorchFEInterpolation.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#ifdef MOOSE_LIBTORCH_ENABLED
11
12// libmesh includes
13#include "libmesh/petsc_vector.h"
14
15// MOOSE includes
17#include "TorchFEMUtils.h"
18
19using namespace libMesh;
20
22
25{
27
29 "This user object provides an interface to libtorch for finite element "
30 "interpolation of variables and their gradients. It gathers the shape "
31 "functions and DOF maps for each variable in the assembly and provides "
32 "them as libtorch tensors for use in batched finite-element kernels.");
33
34 params.addRequiredParam<UserObjectName>(
35 "assembly", "The TorchAssembly object to use to provide assembly information");
36
38 execute_options = {EXEC_INITIAL, EXEC_LINEAR};
39 params.set<ExecFlagEnum>("execute_on") = execute_options;
40 params.suppressParameter<ExecFlagEnum>("execute_on");
41
42 return params;
43}
44
46 : ElementUserObject(parameters), _assembly(getUserObject<TorchAssembly>("assembly"))
47{
48}
49
50const at::Tensor &
51TorchFEInterpolation::getValue(const std::string & var_name)
52{
53 auto [it, success] = _vars.emplace(var_name, at::Tensor());
54
55 if (success)
56 {
57 const auto * var = getMOOSEVariable(var_name);
58 _phis.emplace(var->feType(), &var->phi());
59 _moose_vars.emplace(var_name, var);
60 }
61
62 return it->second;
63}
64
65const at::Tensor &
66TorchFEInterpolation::getGradient(const std::string & var_name)
67{
68 auto [it, success] = _grad_vars.emplace(var_name, at::Tensor());
69
70 if (success)
71 {
72 const auto * var = getMOOSEVariable(var_name);
73 _grad_phis.emplace(var->feType(), &var->gradPhi());
74 _moose_vars.emplace(var_name, var);
75 }
76
77 return it->second;
78}
79
80const at::Tensor &
81TorchFEInterpolation::getPhi(const std::string & var_name)
82{
83 const auto * var = getMOOSEVariable(var_name);
84
85 const auto it = _torch_phi.find(var->feType());
86 if (it != _torch_phi.end())
87 return it->second;
88
89 _phis.emplace(var->feType(), &var->phi());
90 auto [it2, success] = _torch_phi.emplace(var->feType(), at::Tensor());
91 return it2->second;
92}
93
94const at::Tensor &
95TorchFEInterpolation::getPhiGradient(const std::string & var_name)
96{
97 const auto * var = getMOOSEVariable(var_name);
98
99 const auto it = _torch_grad_phi.find(var->feType());
100 if (it != _torch_grad_phi.end())
101 return it->second;
102
103 _grad_phis.emplace(var->feType(), &var->gradPhi());
104 auto [it2, success] = _torch_grad_phi.emplace(var->feType(), at::Tensor());
105 return it2->second;
106}
107
108const at::Tensor &
109TorchFEInterpolation::getDofMap(const std::string & var_name)
110{
111 return _torch_dof_map[var_name];
112}
113
114const std::vector<dof_id_type> &
115TorchFEInterpolation::getGlobalDofMap(const std::string & var_name)
116{
117 return _moose_dof_map_global[var_name];
118}
119
120int64_t
122{
123 return _local_ndof;
124}
125
127TorchFEInterpolation::getMOOSEVariable(const std::string & var_name) const
128{
129 const auto * var = &_fe_problem.getVariable(
131 const auto * var_fe = dynamic_cast<const MooseVariableFE<Real> *>(var);
132
133 if (!var_fe)
134 mooseError("TorchFEInterpolation only supports variables of type MooseVariableFE<Real>");
135
136 if (var_fe->scalingFactor() != 1)
137 mooseError("Scaling factors other than unity are not yet supported");
138
139 // check domain restrictions for compatibility
140 if (!var_fe->hasBlocks(blockIDs()))
141 mooseError("The variable '",
142 var_fe->name(),
143 "' must be defined on all blocks '",
144 name(),
145 "' is defined on.");
146
147 return var_fe;
148}
149
150void
152{
153 _petsc_solution = dynamic_cast<const PetscVector<Real> *>(_sys.currentSolution());
154
155 // check if the solution vector is of a supported type
156 if (!_petsc_solution)
157 mooseError("Only solution vectors of type PetscVector are currently supported");
158
159 if (_tid != 0)
161}
162
163void
169
170void
175
176void
181
182void
184{
186 return;
187
188 _ndofe.clear();
189 _moose_dof_map.clear();
190 _moose_dof_map_global.clear();
191 _moose_phi.clear();
192 _moose_grad_phi.clear();
193 _local_ndof = 0;
194}
195
196void
198{
199 auto & main_uo = _fe_problem.getUserObject<TorchFEInterpolation>(name(), /*tid=*/0);
200 for (const auto & [var_name, var] : main_uo._moose_vars)
201 {
202 _moose_vars.emplace(var_name, getMOOSEVariable(var_name));
203 if (main_uo._phis.count(var->feType()))
204 getPhi(var_name);
205 if (main_uo._grad_phis.count(var->feType()))
206 getPhiGradient(var_name);
207 }
208}
209
210void
212{
213 const auto & other = cast_ref<const TorchFEInterpolation &>(y);
214 mooseAssert(_fem_context_up_to_date == other._fem_context_up_to_date,
215 "TorchFEInterpolation becomes out of sync with other thread");
216
218 return;
219
220 auto merge_map_vecs = [](auto & map1, const auto & map2)
221 {
222 for (const auto & [key, map2_val] : map2)
223 {
224 auto & map1_val = map1[key];
225 map1_val.insert(map1_val.end(), map2_val.begin(), map2_val.end());
226 }
227 };
228
229 merge_map_vecs(_moose_dof_map, other._moose_dof_map);
230 merge_map_vecs(_moose_phi, other._moose_phi);
231 merge_map_vecs(_moose_grad_phi, other._moose_grad_phi);
232}
233
234void
236{
238 return;
239
240 // DOF indices
241 const auto & nl_dof_map = _sys.dofMap();
242 for (const auto & [var_name, var] : _moose_vars)
243 {
244 nl_dof_map.dof_indices(_current_elem, _dof_indices, var->number());
245 auto [it, success] = _ndofe.emplace(var->feType(), _dof_indices.size());
246 if (!success && std::size_t(it->second) != _dof_indices.size())
247 mooseError("DOF map size mismatch for variable ",
248 var_name,
249 ", got ",
250 it->second,
251 " and ",
252 _dof_indices.size());
253 auto & moose_dof_map = _moose_dof_map[var_name];
254 auto & moose_dof_map_global = _moose_dof_map_global[var_name];
255 for (auto dof : _dof_indices)
256 {
257 moose_dof_map.push_back(_petsc_solution->map_global_to_local_index(dof));
258 moose_dof_map_global.push_back(dof);
259 }
260 }
261
262 // shape function values
263 for (const auto & [fetype, phi] : _phis)
264 {
265 auto & moose_phi = _moose_phi[fetype];
266 for (auto i : index_range(*phi))
267 for (auto qp : index_range(_q_point))
268 moose_phi.push_back((*phi)[i][qp]);
269 }
270
271 // shape function gradients
272 for (const auto & [fetype, grad_phi] : _grad_phis)
273 {
274 auto & moose_grad_phi = _moose_grad_phi[fetype];
275 for (auto i : index_range(*grad_phi))
276 for (auto qp : index_range(_q_point))
277 for (auto j : make_range(3))
278 moose_grad_phi.push_back((*grad_phi)[i][qp](j));
279 }
280}
281
282void
284{
285 TIME_SECTION("finalize", 1, "Updating FEM context and interpolations for the Torch FEM kernels");
286
289
292}
293
294void
296{
297 TIME_SECTION("updateFEMContext", 2, "Updating FEM context for the Torch FEM kernels");
298
299 updateDofMap();
300 updatePhi();
302
303 // done
305}
306
307void
309{
310 auto device = _app.getLibtorchDevice();
311 auto nelem = _assembly.numElem();
312
313 for (auto & [var_name, moose_dof_map] : _moose_dof_map)
314 {
315 auto var = _moose_vars.at(var_name);
316 auto ndofe = _ndofe.at(var->feType());
317
318 // sanity check on sizes
319 if (moose_dof_map.size() != std::size_t(nelem * ndofe))
321 "dof map size mismatch, expected ", nelem * ndofe, " but got ", moose_dof_map.size());
322
323 // convert to a libtorch tensor
324 _torch_dof_map[var_name] =
325 at::from_blob(moose_dof_map.data(), {nelem, ndofe}, torch::kInt64).to(device);
326
327 _local_ndof = std::max(_local_ndof, _torch_dof_map[var_name].max().item<int64_t>() + 1);
328 }
329}
330
331void
333{
334 auto device = _app.getLibtorchDevice();
335 auto nelem = _assembly.numElem();
336 auto nqp = _assembly.numQP();
337
338 for (auto & [fetype, moose_phi] : _moose_phi)
339 {
340 auto ndofe = _ndofe.at(fetype);
341
342 // sanity check on sizes
343 if (moose_phi.size() != std::size_t(nelem * ndofe * nqp))
344 mooseError("shape function size mismatch, expected ",
345 nelem * ndofe * nqp,
346 " but got ",
347 moose_phi.size());
348 _torch_phi[fetype] =
349 at::from_blob(moose_phi.data(), {nelem, ndofe, nqp}, torch::kFloat64).to(device);
350 }
351}
352
353void
355{
356 auto device = _app.getLibtorchDevice();
357 auto nelem = _assembly.numElem();
358 auto nqp = _assembly.numQP();
359
360 for (auto & [fetype, moose_grad_phi] : _moose_grad_phi)
361 {
362 auto ndofe = _ndofe.at(fetype);
363
364 // sanity check on sizes
365 if (moose_grad_phi.size() != std::size_t(nelem * ndofe * nqp * 3))
366 mooseError("shape function gradient size mismatch, expected ",
367 nelem * ndofe * nqp * 3,
368 " but got ",
369 moose_grad_phi.size());
370 _torch_grad_phi[fetype] =
371 at::from_blob(moose_grad_phi.data(), {nelem, ndofe, nqp, 3}, torch::kFloat64).to(device);
372 }
373}
374
375void
377{
378 TIME_SECTION("updateInterpolations", 2, "Updating FEM interpolations for the Torch FEM kernels");
379
380 // convert the local solution vector to a libtorch tensor
381 auto sol = at::from_blob(const_cast<Real *>(_petsc_solution->get_array_read()),
382 {local_ndof()},
383 torch::kFloat64)
384 .to(_app.getLibtorchDevice());
385
386 // interpolate variable values
387 for (auto & [var_name, val] : _vars)
388 {
389 const auto & dof_map = _torch_dof_map[var_name];
390 const auto fetype = _moose_vars[var_name]->feType();
391 const auto & phi = _torch_phi[fetype];
392 auto sol_scattered = TorchFEM::scatter(sol, dof_map);
393 val = TorchFEM::interpolate(sol_scattered, phi);
394 }
395
396 // interpolate variable gradients
397 for (auto & [var_name, val] : _grad_vars)
398 {
399 const auto & dof_map = _torch_dof_map[var_name];
400 const auto fetype = _moose_vars[var_name]->feType();
401 const auto & grad_phi = _torch_grad_phi[fetype];
402 auto sol_scattered = TorchFEM::scatter(sol, dof_map);
403 val = TorchFEM::interpolate(sol_scattered, grad_phi);
404 }
405
406 // close solution and residual vector access
407 const_cast<PetscVector<Real> *>(_petsc_solution)->restore_array();
408
409 // done
410 _interp_up_to_date = true;
411}
412
413#endif // MOOSE_LIBTORCH_ENABLED
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
const ExecFlagType EXEC_INITIAL
Definition Moose.C:31
const ExecFlagType EXEC_LINEAR
Definition Moose.C:32
registerMooseObject("MooseApp", TorchFEInterpolation)
virtual const std::set< SubdomainID > & blockIDs() const
Return the block subdomain ids for this object Note, if this is not block restricted,...
static InputParameters validParams()
const Elem *const & _current_elem
The current element pointer (available during execute())
const MooseArray< Point > & _q_point
A MultiMooseEnum object to hold "execute_on" flags.
T & getUserObject(const std::string &name, unsigned int tid=0) const
Get the user object by its name.
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
Returns the variable reference for requested variable which must be of the expected_var_type (Nonline...
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void suppressParameter(const std::string &name)
This method suppresses an inherited parameter so that it isn't required or valid in the derived class...
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump.
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
torch::DeviceType getLibtorchDevice() const
Get the device torch is supposed to be running on.
Definition MooseApp.h:114
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
MooseApp & _app
The MOOSE application this is associated with.
Definition MooseBase.h:375
Class for stuff related to variables.
virtual const NumericVector< Number > *const & currentSolution() const =0
The solution vector that is currently being operated on.
virtual libMesh::DofMap & dofMap()
Gets writeable reference to the dof map.
This user object caches assembly information (JxWxT) from MOOSE as a batched at::Tensor for the Torch...
int64_t numQP() const
Number of quadrature points per element.
int64_t numElem() const
Number of active elements on this rank.
This user object serves as the "interface" for interpolating MOOSE variable values and gradients from...
void invalidateInterpolations()
Invalidate the cached interpolations.
void invalidateFEMContext()
Invalidate the cached FEM context such as dof map, shape functions, etc.
std::unordered_map< FEType, std::vector< Real > > _moose_phi
void initialize() override
Called before execute() is ever called so that data can be cleared.
std::unordered_map< FEType, at::Tensor > _torch_grad_phi
const std::vector< dof_id_type > & getGlobalDofMap(const std::string &var_name)
Similar to getDofMap, but returns the global dof map (as a flattened vector of dof_id_type)
std::unordered_map< std::string, at::Tensor > _vars
coupled variables (by value) requested by other objects
bool _fem_context_up_to_date
Whether the current FEM context is up to date.
int64_t _local_ndof
Number of local dofs (including ghost dofs)
const at::Tensor & getDofMap(const std::string &var_name)
Get the local dof map associated with a MOOSE variable.
static InputParameters validParams()
std::unordered_map< std::string, at::Tensor > _grad_vars
coupled variables (by gradient) requested by other objects
const at::Tensor & getPhiGradient(const std::string &var_name)
Get the shape function gradient associated with a MOOSE variable.
virtual void updateInterpolations()
std::unordered_map< std::string, const MooseVariableFE< Real > * > _moose_vars
moose variables that have been coupled
std::unordered_map< FEType, const VariablePhiGradient * > _grad_phis
std::vector< dof_id_type > _dof_indices
Helper vector to store local dof indices.
void meshChanged() override
Called on this object when the mesh changes.
const at::Tensor & getGradient(const std::string &var_name)
Get the variable gradient of a MOOSE nonlinear variable converted to a libtorch tensor.
const TorchAssembly & _assembly
Assembly.
void threadJoin(const UserObject &) override
Must override.
std::unordered_map< FEType, int64_t > _ndofe
cached information on the requested function spaces
void execute() override
Execute method.
void initialSetup() override
Gets called at the beginning of the simulation before this object is asked to do its job.
std::unordered_map< std::string, std::vector< int64_t > > _moose_dof_map
void finalize() override
Finalize.
std::unordered_map< FEType, std::vector< Real > > _moose_grad_phi
std::unordered_map< std::string, std::vector< dof_id_type > > _moose_dof_map_global
bool _interp_up_to_date
Whether the current interpolations are up to date.
std::unordered_map< std::string, at::Tensor > _torch_dof_map
const libMesh::PetscVector< Real > * _petsc_solution
PETSc solution vector.
std::unordered_map< FEType, at::Tensor > _torch_phi
const at::Tensor & getValue(const std::string &var_name)
Get the variable value of a MOOSE nonlinear variable converted to a libtorch tensor.
const at::Tensor & getPhi(const std::string &var_name)
Get the shape function associated with a MOOSE variable.
const MooseVariableFE< Real > * getMOOSEVariable(const std::string &var_name) const
Helper to get the MOOSE variable and check for common restrictions.
virtual void syncWithMainThread()
TorchFEInterpolation(const InputParameters &parameters)
std::unordered_map< FEType, const VariablePhiValue * > _phis
FEProblemBase & _fe_problem
Reference to the FEProblemBase for this user object.
const THREAD_ID _tid
Thread ID of this postprocessor.
SystemBase & _sys
Reference to the system object for this user object.
Base class for user-specific data.
Definition UserObject.h:20
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
numeric_index_type map_global_to_local_index(const numeric_index_type i) const
const PetscScalar * get_array_read() const
ExecFlagEnum getDefaultExecFlagEnum()
@ VAR_FIELD_STANDARD
Definition MooseTypes.h:781
@ VAR_SOLVER
Definition MooseTypes.h:774
at::Tensor scatter(const at::Tensor &v, const at::Tensor &dof_map)
Gather global solution values into element-local DOF values: out[e,a,...] = v[dof_map[e,...
at::Tensor interpolate(const at::Tensor &elem_dofs, const at::Tensor &basis)
Interpolate element-local DOF values onto quadrature points by contracting over the per-element DOF a...
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
auto index_range(const T &sizable)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)