https://mooseframework.inl.gov
Loading...
Searching...
No Matches
NEML2FEInterpolation.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 NEML2_ENABLED
11
12// libmesh includes
13#include "libmesh/petsc_vector.h"
14
15// Torch includes
16#include <ATen/ops/from_blob.h>
17
18// NEML2 includes
19#include "neml2/tensors/functions/discretization/scatter.h"
20#include "neml2/tensors/functions/discretization/interpolate.h"
21
22// MOOSE includes
24
26
29{
31
33 "This user object provides an interface to NEML2 for finite element "
34 "interpolation of variables and their gradients. It gathers the shape "
35 "functions and DOF maps for each variable in the assembly and provides "
36 "them as NEML2 tensors for use in NEML2 models.");
37
38 params.addRequiredParam<UserObjectName>(
39 "assembly", "The NEML2Assembly object to use to provide assembly information");
40
42 execute_options = {EXEC_INITIAL, EXEC_LINEAR};
43 params.set<ExecFlagEnum>("execute_on") = execute_options;
44 params.suppressParameter<ExecFlagEnum>("execute_on");
45
46 return params;
47}
48
50 : ElementUserObject(parameters), _neml2_assembly(getUserObject<NEML2Assembly>("assembly"))
51{
52}
53
54const neml2::Tensor &
55NEML2FEInterpolation::getValue(const std::string & var_name)
56{
57 auto [it, success] = _vars.emplace(var_name, neml2::Tensor());
58
59 if (success)
60 {
61 const auto * var = getMOOSEVariable(var_name);
62 _phis.emplace(var->feType(), &var->phi());
63 _moose_vars.emplace(var_name, var);
64 }
65
66 return it->second;
67}
68
69const neml2::Tensor &
70NEML2FEInterpolation::getGradient(const std::string & var_name)
71{
72 auto [it, success] = _grad_vars.emplace(var_name, neml2::Tensor());
73
74 if (success)
75 {
76 const auto * var = getMOOSEVariable(var_name);
77 _grad_phis.emplace(var->feType(), &var->gradPhi());
78 _moose_vars.emplace(var_name, var);
79 }
80
81 return it->second;
82}
83
84const neml2::Tensor &
85NEML2FEInterpolation::getPhi(const std::string & var_name)
86{
87 const auto * var = getMOOSEVariable(var_name);
88
89 const auto it = _neml2_phi.find(var->feType());
90 if (it != _neml2_phi.end())
91 return it->second;
92
93 _phis.emplace(var->feType(), &var->phi());
94 auto [it2, success] = _neml2_phi.emplace(var->feType(), neml2::Tensor());
95 return it2->second;
96}
97
98const neml2::Tensor &
99NEML2FEInterpolation::getPhiGradient(const std::string & var_name)
100{
101 const auto * var = getMOOSEVariable(var_name);
102
103 const auto it = _neml2_grad_phi.find(var->feType());
104 if (it != _neml2_grad_phi.end())
105 return it->second;
106
107 _grad_phis.emplace(var->feType(), &var->gradPhi());
108 auto [it2, success] = _neml2_grad_phi.emplace(var->feType(), neml2::Tensor());
109 return it2->second;
110}
111
112const neml2::Tensor &
113NEML2FEInterpolation::getDofMap(const std::string & var_name)
114{
115 return _neml2_dof_map[var_name];
116}
117
118const std::vector<dof_id_type> &
119NEML2FEInterpolation::getGlobalDofMap(const std::string & var_name)
120{
121 return _moose_dof_map_global[var_name];
122}
123
124int64_t
126{
127 return _local_ndof;
128}
129
131NEML2FEInterpolation::getMOOSEVariable(const std::string & var_name) const
132{
133 const auto * var = &_fe_problem.getVariable(
135 const auto * var_fe = dynamic_cast<const MooseVariableFE<Real> *>(var);
136
137 if (!var_fe)
138 mooseError("NEML2FEInterpolation only supports variables of type MooseVariableFE<Real>");
139
140 if (var_fe->scalingFactor() != 1)
141 mooseError("Scaling factors other than unity are not yet supported");
142
143 // check domain restrictions for compatibility
144 if (!var_fe->hasBlocks(blockIDs()))
145 mooseError("The variable '",
146 var_fe->name(),
147 "' must be defined on all blocks '",
148 name(),
149 "' is defined on.");
150
151 return var_fe;
152}
153
154void
156{
157 _petsc_solution = dynamic_cast<const PetscVector<Real> *>(_sys.currentSolution());
158
159 // check if the solution vector is of a supported type
160 if (!_petsc_solution)
161 mooseError("Only solution vectors of type PetscVector are currently supported");
162
163 if (_tid != 0)
165}
166
167void
173
174void
179
180void
185
186void
188{
190 return;
191
192 _ndofe.clear();
193 _moose_dof_map.clear();
194 _moose_dof_map_global.clear();
195 _moose_phi.clear();
196 _moose_grad_phi.clear();
197 _local_ndof = 0;
198}
199
200void
202{
203 auto & main_uo = _fe_problem.getUserObject<NEML2FEInterpolation>(name(), /*tid=*/0);
204 for (const auto & [var_name, var] : main_uo._moose_vars)
205 {
206 _moose_vars.emplace(var_name, getMOOSEVariable(var_name));
207 if (main_uo._phis.count(var->feType()))
208 getPhi(var_name);
209 if (main_uo._grad_phis.count(var->feType()))
210 getPhiGradient(var_name);
211 }
212}
213
214void
216{
217 const auto & other = cast_ref<const NEML2FEInterpolation &>(y);
218 mooseAssert(_fem_context_up_to_date == other._fem_context_up_to_date,
219 "NEML2FEInterpolation becomes out of sync with other thread");
220
222 return;
223
224 auto merge_map_vecs = [](auto & map1, const auto & map2)
225 {
226 for (const auto & [key, map2_val] : map2)
227 {
228 auto & map1_val = map1[key];
229 map1_val.insert(map1_val.end(), map2_val.begin(), map2_val.end());
230 }
231 };
232
233 merge_map_vecs(_moose_dof_map, other._moose_dof_map);
234 merge_map_vecs(_moose_phi, other._moose_phi);
235 merge_map_vecs(_moose_grad_phi, other._moose_grad_phi);
236}
237
238void
240{
242 return;
243
244 // DOF indices
245 const auto & nl_dof_map = _sys.dofMap();
246 for (const auto & [var_name, var] : _moose_vars)
247 {
248 nl_dof_map.dof_indices(_current_elem, _dof_indices, var->number());
249 auto [it, success] = _ndofe.emplace(var->feType(), _dof_indices.size());
250 if (!success && std::size_t(it->second) != _dof_indices.size())
251 mooseError("DOF map size mismatch for variable ",
252 var_name,
253 ", got ",
254 it->second,
255 " and ",
256 _dof_indices.size());
257 auto & moose_dof_map = _moose_dof_map[var_name];
258 auto & moose_dof_map_global = _moose_dof_map_global[var_name];
259 for (auto dof : _dof_indices)
260 {
261 moose_dof_map.push_back(_petsc_solution->map_global_to_local_index(dof));
262 moose_dof_map_global.push_back(dof);
263 }
264 }
265
266 // shape function values
267 for (const auto & [fetype, phi] : _phis)
268 {
269 auto & moose_phi = _moose_phi[fetype];
270 for (auto i : index_range(*phi))
271 for (auto qp : index_range(_q_point))
272 moose_phi.push_back((*phi)[i][qp]);
273 }
274
275 // shape function gradients
276 for (const auto & [fetype, grad_phi] : _grad_phis)
277 {
278 auto & moose_grad_phi = _moose_grad_phi[fetype];
279 for (auto i : index_range(*grad_phi))
280 for (auto qp : index_range(_q_point))
281 for (auto j : make_range(3))
282 moose_grad_phi.push_back((*grad_phi)[i][qp](j));
283 }
284}
285
286void
288{
289 TIME_SECTION("finalize", 1, "Updating FEM context and interpolations for NEML2");
290
293
296}
297
298void
300{
301 TIME_SECTION("updateFEMContext", 2, "Updating FEM context for NEML2");
302
303 updateDofMap();
304 updatePhi();
306
307 // done
309}
310
311void
313{
314 auto device = _app.getLibtorchDevice();
315 auto nelem = _neml2_assembly.numElem();
316
317 for (auto & [var_name, moose_dof_map] : _moose_dof_map)
318 {
319 auto var = _moose_vars.at(var_name);
320 auto ndofe = _ndofe.at(var->feType());
321
322 // sanity check on sizes
323 if (moose_dof_map.size() != std::size_t(nelem * ndofe))
325 "dof map size mismatch, expected ", nelem * ndofe, " but got ", moose_dof_map.size());
326
327 // convert to neml2 tensor
328 _neml2_dof_map[var_name] =
329 neml2::Tensor(at::from_blob(moose_dof_map.data(), {nelem, ndofe}, torch::kInt64), 2)
330 .to(device);
331
332 _local_ndof = std::max(_local_ndof, _neml2_dof_map[var_name].max().item<int64_t>() + 1);
333 }
334}
335
336void
338{
339 auto device = _app.getLibtorchDevice();
340 auto nelem = _neml2_assembly.numElem();
341 auto nqp = _neml2_assembly.numQP();
342
343 for (auto & [fetype, moose_phi] : _moose_phi)
344 {
345 auto ndofe = _ndofe.at(fetype);
346
347 // sanity check on sizes
348 if (moose_phi.size() != std::size_t(nelem * ndofe * nqp))
349 mooseError("shape function size mismatch, expected ",
350 nelem * ndofe * nqp,
351 " but got ",
352 moose_phi.size());
353 _neml2_phi[fetype] =
354 neml2::Tensor(at::from_blob(moose_phi.data(), {nelem, ndofe, nqp}, torch::kFloat64), 3)
355 .to(device);
356 }
357}
358
359void
361{
362 auto device = _app.getLibtorchDevice();
363 auto nelem = _neml2_assembly.numElem();
364 auto nqp = _neml2_assembly.numQP();
365
366 for (auto & [fetype, moose_grad_phi] : _moose_grad_phi)
367 {
368 auto ndofe = _ndofe.at(fetype);
369
370 // sanity check on sizes
371 if (moose_grad_phi.size() != std::size_t(nelem * ndofe * nqp * 3))
372 mooseError("shape function gradient size mismatch, expected ",
373 nelem * ndofe * nqp * 3,
374 " but got ",
375 moose_grad_phi.size());
376 _neml2_grad_phi[fetype] =
377 neml2::Tensor(at::from_blob(moose_grad_phi.data(), {nelem, ndofe, nqp, 3}, torch::kFloat64),
378 3)
379 .to(device);
380 }
381}
382
383void
385{
386 TIME_SECTION("updateInterpolations", 2, "Updating FEM interpolations for NEML2");
387
388 // convert the local solution vector to neml2 tensor
389 auto sol = at::from_blob(const_cast<Real *>(_petsc_solution->get_array_read()),
390 {local_ndof()},
391 torch::kFloat64)
392 .to(_app.getLibtorchDevice());
393
394 // interpolate variable values
395 for (auto & [var_name, val] : _vars)
396 {
397 const auto & dof_map = _neml2_dof_map[var_name];
398 const auto fetype = _moose_vars[var_name]->feType();
399 const auto & phi = _neml2_phi[fetype];
400 auto sol_scattered = neml2::discretization::scatter(sol, dof_map);
401 val = neml2::discretization::interpolate(sol_scattered, phi);
402 }
403
404 // interpolate variable gradients
405 for (auto & [var_name, val] : _grad_vars)
406 {
407 const auto & dof_map = _neml2_dof_map[var_name];
408 const auto fetype = _moose_vars[var_name]->feType();
409 const auto & grad_phi = _neml2_grad_phi[fetype];
410 auto sol_scattered = neml2::discretization::scatter(sol, dof_map);
411 val = neml2::discretization::interpolate(sol_scattered, grad_phi);
412 }
413
414 // close solution and residual vector access
415 const_cast<PetscVector<Real> *>(_petsc_solution)->restore_array();
416
417 // done
418 _interp_up_to_date = true;
419}
420
421#endif
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", NEML2FEInterpolation)
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:117
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.
This user object caches assembly information from MOOSE.
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...
static InputParameters validParams()
const neml2::Tensor & getPhiGradient(const std::string &var_name)
Get the shape function gradient associated with a MOOSE variable.
const neml2::Tensor & getGradient(const std::string &var_name)
Get the variable gradient of a MOOSE nonlinear variable converted to a NEML2 tensor.
const neml2::Tensor & getDofMap(const std::string &var_name)
Get the local dof map associated with a MOOSE variable.
std::unordered_map< std::string, neml2::Tensor > _vars
coupled variables (by value) requested by other objects
const NEML2Assembly & _neml2_assembly
Assembly.
virtual void syncWithMainThread()
std::unordered_map< std::string, neml2::Tensor > _neml2_dof_map
void invalidateFEMContext()
Invalidate the cached FEM context such as dof map, shape functions, etc.
void invalidateInterpolations()
Invalidate the cached interpolations.
bool _interp_up_to_date
Whether the current interpolations are up to date.
NEML2FEInterpolation(const InputParameters &parameters)
std::unordered_map< std::string, std::vector< int64_t > > _moose_dof_map
const neml2::Tensor & getValue(const std::string &var_name)
Get the variable value of a MOOSE nonlinear variable converted to a NEML2 tensor.
std::vector< dof_id_type > _dof_indices
Helper vector to store local dof indices.
std::unordered_map< FEType, std::vector< Real > > _moose_phi
std::unordered_map< FEType, const VariablePhiGradient * > _grad_phis
std::unordered_map< FEType, neml2::Tensor > _neml2_phi
const MooseVariableFE< Real > * getMOOSEVariable(const std::string &var_name) const
Helper to get the MOOSE variable and check for common restrictions.
void meshChanged() override
Called on this object when the mesh changes.
void execute() override
Execute method.
void threadJoin(const UserObject &) override
Must override.
int64_t _local_ndof
Number of local dofs (including ghost dofs)
std::unordered_map< FEType, int64_t > _ndofe
cached information on the requested function spaces
std::unordered_map< FEType, neml2::Tensor > _neml2_grad_phi
std::unordered_map< std::string, neml2::Tensor > _grad_vars
coupled variables (by gradient) requested by other objects
bool _fem_context_up_to_date
Whether the current FEM context is up to date.
virtual void updateInterpolations()
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, const MooseVariableFE< Real > * > _moose_vars
moose variables that have been coupled
std::unordered_map< std::string, std::vector< dof_id_type > > _moose_dof_map_global
const PetscVector< Real > * _petsc_solution
PETSc solution vector.
std::unordered_map< FEType, const VariablePhiValue * > _phis
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)
const neml2::Tensor & getPhi(const std::string &var_name)
Get the shape function associated with a MOOSE variable.
void finalize() override
Finalize.
void initialize() override
Called before execute() is ever called so that data can be cleared.
std::unordered_map< FEType, std::vector< Real > > _moose_grad_phi
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.
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
ExecFlagEnum getDefaultExecFlagEnum()
Definition MooseUtils.C:972
@ VAR_FIELD_STANDARD
Definition MooseTypes.h:777
@ VAR_SOLVER
Definition MooseTypes.h:770