https://mooseframework.inl.gov
Loading...
Searching...
No Matches
ComputeUserObjectsThread.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
11#include "Problem.h"
12#include "SystemBase.h"
13#include "ElementUserObject.h"
15#include "SideUserObject.h"
16#include "InterfaceUserObject.h"
17#include "ShapeSideUserObject.h"
19#include "NodalUserObject.h"
20#include "SwapBackSentinel.h"
21#include "FEProblem.h"
22#include "MaterialBase.h"
23#include "DomainUserObject.h"
24#include "AuxiliarySystem.h"
25#include "MooseTypes.h"
26
27#include "libmesh/numeric_vector.h"
28
30 const TheWarehouse::Query & query)
31 : ThreadedElementLoop<ConstElemRange>(problem),
32 _query(query),
33 _query_subdomain(_query),
34 _query_boundary(_query),
35 _aux_sys(problem.getAuxiliarySystem())
36{
37}
38
39// Splitting Constructor
41 : ThreadedElementLoop<ConstElemRange>(x._fe_problem),
42 _query(x._query),
43 _query_subdomain(x._query_subdomain),
44 _query_boundary(x._query_boundary),
45 _aux_sys(x._aux_sys)
46{
47}
48
50
51void
53{
54 // for the current thread get block objects for the current subdomain and *all* side objects
55 std::vector<UserObject *> objs;
58 objs);
59
62 .condition<AttribInterfaces>(Interfaces::DomainUserObject)
63 .queryInto(_all_domain_objs);
64
65 std::vector<UserObject *> side_objs;
68 .condition<AttribInterfaces>(Interfaces::SideUserObject)
69 .queryInto(side_objs);
70
71 objs.insert(objs.begin(), side_objs.begin(), side_objs.end());
72
73 // collect dependencies and run subdomain setup
75
76 std::set<MooseVariableFEBase *> needed_moose_vars;
77 std::unordered_set<unsigned int> needed_mat_props;
78 std::set<TagID> needed_fe_var_vector_tags;
79 for (const auto obj : objs)
80 {
81 auto v_obj = dynamic_cast<MooseVariableDependencyInterface *>(obj);
82 if (v_obj)
83 {
84 const auto & v_deps = v_obj->getMooseVariableDependencies();
85 needed_moose_vars.insert(v_deps.begin(), v_deps.end());
86 }
87
88 auto m_obj = dynamic_cast<MaterialPropertyInterface *>(obj);
89 if (m_obj)
90 {
91 auto & m_deps = m_obj->getMatPropDependencies();
92 needed_mat_props.insert(m_deps.begin(), m_deps.end());
93 }
94
95 auto c_obj = dynamic_cast<Coupleable *>(obj);
96 if (c_obj)
97 {
98 const auto & tag_deps = c_obj->getFEVariableCoupleableVectorTags();
99 needed_fe_var_vector_tags.insert(tag_deps.begin(), tag_deps.end());
100 }
101
102 obj->subdomainSetup();
103 }
105 _subdomain, needed_fe_var_vector_tags, _tid);
106
108 _fe_problem.setActiveFEVariableCoupleableVectorTags(needed_fe_var_vector_tags, _tid);
109 _fe_problem.prepareMaterials(needed_mat_props, _subdomain, _tid);
110
115}
116
117void
119{
120 _fe_problem.prepare(elem, _tid);
122
123 // Set up Sentinel class so that, even if reinitMaterials() throws, we
124 // still remember to swap back during stack unwinding.
127
128 for (const auto & uo : _element_objs)
129 {
130 uo->execute();
131
132 // update the aux solution vector if writable coupled variables are used
133 if (uo->hasWritableCoupledVariables())
134 for (auto * var : uo->getWritableCoupledVariables())
135 var->insert(_aux_sys.solution());
136 }
137
138 for (auto & uo : _domain_objs)
139 {
140 uo->preExecuteOnElement();
141 uo->executeOnElement();
142 }
143
144 // UserObject Jacobians
146 {
147 // Prepare shape functions for ShapeElementUserObjects
148 const auto & jacobian_moose_vars = _fe_problem.getUserObjectJacobianVariables(_tid);
149 for (const auto & jvar : jacobian_moose_vars)
150 {
151 unsigned int jvar_id = jvar->number();
152 auto && dof_indices = jvar->dofIndices();
153
155 for (const auto uo : _shape_element_objs)
156 uo->executeJacobianWrapper(jvar_id, dof_indices);
157 }
158 }
159}
160
161void
163 unsigned int side,
164 BoundaryID bnd_id,
165 const Elem * lower_d_elem /*=nullptr*/)
166{
167 std::vector<UserObject *> userobjs;
168 queryBoundary(Interfaces::SideUserObject, bnd_id, userobjs);
169 if (userobjs.size() == 0 && _domain_objs.size() == 0)
170 return;
171
172 _fe_problem.reinitElemFace(elem, side, _tid);
173
174 // Reinitialize lower-dimensional variables for use in boundary Materials
175 if (lower_d_elem)
176 _fe_problem.reinitLowerDElem(lower_d_elem, _tid);
177
178 // Set up Sentinel class so that, even if reinitMaterialsFace() throws, we
179 // still remember to swap back during stack unwinding.
181 _fe_problem.reinitMaterialsFaceOnBoundary(bnd_id, elem->subdomain_id(), _tid);
183
184 for (const auto & uo : userobjs)
185 uo->execute();
186
187 for (auto & uo : _domain_objs)
188 {
189 uo->preExecuteOnBoundary();
190 uo->executeOnBoundary();
191 }
192
193 // UserObject Jacobians
194 std::vector<ShapeSideUserObject *> shapers;
196 if (_fe_problem.currentlyComputingJacobian() && shapers.size() > 0)
197 {
198 // Prepare shape functions for ShapeSideUserObjects
199 const auto & jacobian_moose_vars = _fe_problem.getUserObjectJacobianVariables(_tid);
200 for (const auto & jvar : jacobian_moose_vars)
201 {
202 unsigned int jvar_id = jvar->number();
203 auto && dof_indices = jvar->dofIndices();
204
206
207 for (const auto & uo : shapers)
208 uo->executeJacobianWrapper(jvar_id, dof_indices);
209 }
210 }
211}
212
213void
214ComputeUserObjectsThread::onInternalSide(const Elem * elem, unsigned int side)
215{
216 // Pointer to the neighbor we are currently working on.
217 const Elem * neighbor = elem->neighbor_ptr(side);
218
219 if (_internal_side_objs.size() == 0 && _domain_objs.size() == 0)
220 return;
221
223 _fe_problem.reinitNeighbor(elem, side, _tid);
224
225 // Set up Sentinels so that, even if one of the reinitMaterialsXXX() calls throws, we
226 // still remember to swap back during stack unwinding.
228 _fe_problem.reinitMaterialsFace(elem->subdomain_id(), _tid);
229
231 _fe_problem.reinitMaterialsNeighbor(neighbor->subdomain_id(), _tid);
232
233 for (const auto & uo : _internal_side_objs)
234 if (!uo->blockRestricted() || uo->hasBlocks(neighbor->subdomain_id()))
235 uo->execute();
236
237 for (auto & uo : _domain_objs)
238 if (!uo->blockRestricted() || uo->hasBlocks(neighbor->subdomain_id()))
239 {
240 uo->preExecuteOnInternalSide();
241 uo->executeOnInternalSide();
242 }
243}
244
245void
246ComputeUserObjectsThread::onExternalSide(const Elem * elem, unsigned int side)
247{
248 // We are not initializing any materials here because objects that perform calculations should
249 // run onBoundary. onExternalSide should be used for mesh updates (e.g. adding/removing
250 // boundaries). Note that _current_elem / _current_side are not getting updated either.
251 for (auto & uo : _domain_objs)
252 uo->executeOnExternalSide(elem, side);
253}
254
255void
256ComputeUserObjectsThread::onInterface(const Elem * elem, unsigned int side, BoundaryID bnd_id)
257{
258 // Pointer to the neighbor we are currently working on.
259 const Elem * neighbor = elem->neighbor_ptr(side);
260 if (!(neighbor->active()))
261 return;
262
263 std::vector<UserObject *> interface_objs;
264 queryBoundary(Interfaces::InterfaceUserObject, bnd_id, interface_objs);
265
266 bool has_domain_objs = false;
267 // we need to check all domain user objects because a domain user object may not be active
268 // on the current subdomain but should be executed on the interface that it attaches to
269 for (const auto * const domain_uo : _all_domain_objs)
270 if (domain_uo->shouldExecuteOnInterface())
271 {
272 has_domain_objs = true;
273 break;
274 }
275
276 // if we do not have any interface user objects and domain user objects on the current
277 // interface
278 if (interface_objs.empty() && !has_domain_objs)
279 return;
280
282 _fe_problem.reinitNeighbor(elem, side, _tid);
283
284 // Set up Sentinels so that, even if one of the reinitMaterialsXXX() calls throws, we
285 // still remember to swap back during stack unwinding.
286
288 _fe_problem.reinitMaterialsFaceOnBoundary(bnd_id, elem->subdomain_id(), _tid);
290
292 _fe_problem.reinitMaterialsNeighbor(neighbor->subdomain_id(), _tid);
293
294 // Has to happen after face and neighbor properties have been computed. Note that we don't use
295 // a sentinel here because FEProblem::swapBackMaterialsFace is going to handle face materials,
296 // boundary materials, and interface materials (e.g. it queries the boundary material data
297 // with the current element and side
299
300 for (const auto & uo : interface_objs)
301 uo->execute();
302
303 for (auto & uo : _all_domain_objs)
304 if (uo->shouldExecuteOnInterface())
305 {
306 uo->preExecuteOnInterface();
307 uo->executeOnInterface();
308 }
309}
310
311void
317
318void
322
323void
325{
327 {
328 const auto & console = _fe_problem.console();
329 const auto & execute_on = _fe_problem.getCurrentExecuteOnFlag();
330 console << "[DBG] Computing elemental user objects on " << execute_on << std::endl;
331 mooseDoOnce(console << "[DBG] Execution order of objects types on each element then its sides:"
332 << std::endl;
333 // onElement
334 console << "[DBG] - element user objects" << std::endl;
335 console << "[DBG] - domain user objects" << std::endl;
336 console << "[DBG] - element user objects contributing to the Jacobian" << std::endl;
337
338 // onBoundary
339 console << "[DBG] - side user objects" << std::endl;
340 console << "[DBG] - domain user objects executing on sides" << std::endl;
341 console << "[DBG] - side user objects contributing to the Jacobian" << std::endl;
342
343 // onInternalSide
344 console << "[DBG] - internal side user objects" << std::endl;
345 console << "[DBG] - domain user objects executing on internal sides" << std::endl;
346
347 // onInterface
348 console << "[DBG] - interface user objects" << std::endl;
349 console << "[DBG] - domain user objects executing at interfaces" << std::endl;);
350 }
351}
352
353void
355{
357 return;
358
359 // Gather all user objects that may execute
360 // TODO: restrict this gathering of boundary objects to boundaries that are present
361 // in the current block
362 std::vector<ShapeSideUserObject *> shapers;
363 const_cast<ComputeUserObjectsThread *>(this)->queryBoundary(
365
366 std::vector<SideUserObject *> side_uos;
367 const_cast<ComputeUserObjectsThread *>(this)->queryBoundary(
369
370 std::vector<InterfaceUserObject *> interface_objs;
371 const_cast<ComputeUserObjectsThread *>(this)->queryBoundary(
373
374 std::vector<const DomainUserObject *> domain_interface_uos;
375 for (const auto * const domain_uo : _domain_objs)
376 if (domain_uo->shouldExecuteOnInterface())
377 domain_interface_uos.push_back(domain_uo);
378
379 // Approximation of the number of user objects currently executing
380 const auto num_objects = _element_objs.size() + _domain_objs.size() + _shape_element_objs.size() +
381 side_uos.size() + shapers.size() + _internal_side_objs.size() +
382 interface_objs.size() + domain_interface_uos.size();
383
384 const auto & console = _fe_problem.console();
385 const auto & execute_on = _fe_problem.getCurrentExecuteOnFlag();
386
387 if (num_objects > 0)
388 {
390 return;
391
392 console << "[DBG] Ordering of User Objects on block " << _subdomain << std::endl;
393 // Output specific ordering of objects
394 printExecutionOrdering<ElementUserObject>(_element_objs, "element user objects");
395 printExecutionOrdering<DomainUserObject>(_domain_objs, "domain user objects");
397 printExecutionOrdering<ShapeElementUserObject>(
398 _shape_element_objs, "element user objects contributing to the Jacobian");
399 printExecutionOrdering<SideUserObject>(side_uos, "side user objects");
401 printExecutionOrdering<ShapeSideUserObject>(shapers,
402 "side user objects contributing to the Jacobian");
403 printExecutionOrdering<InternalSideUserObject>(_internal_side_objs,
404 "internal side user objects");
405 printExecutionOrdering<InterfaceUserObject>(interface_objs, "interface user objects");
406 console << "[DBG] Only user objects active on local element/sides are executed" << std::endl;
407 }
408 else if (num_objects == 0 && !_blocks_exec_printed.count(_subdomain))
409 console << "[DBG] No User Objects on block " << _subdomain << " on " << execute_on.name()
410 << std::endl;
411
412 // Mark subdomain as having printed to avoid printing again
414}
@ InternalSideUserObject
@ ShapeSideUserObject
@ InterfaceUserObject
@ ShapeElementUserObject
boundary_id_type BoundaryID
Class for threaded computation of UserObjects.
std::vector< DomainUserObject * > _all_domain_objs
std::vector< ElementUserObject * > _element_objs
virtual void post() override
Called after the element range loop.
virtual void onInternalSide(const Elem *elem, unsigned int side) override
Called when doing internal edge assembling.
const TheWarehouse::Query _query
virtual void onElement(const Elem *elem) override
Assembly of the element (not including surface assembly)
virtual void onInterface(const Elem *elem, unsigned int side, BoundaryID bnd_id) override
Called when doing interface assembling.
virtual void onBoundary(const Elem *elem, unsigned int side, BoundaryID bnd_id, const Elem *lower_d_elem=nullptr) override
Called when doing boundary assembling.
void printBlockExecutionInformation() const override
Print information about the loop, mostly order of execution of particular objects.
void queryBoundary(Interfaces iface, BoundaryID bnd, std::vector< T > &results)
ComputeUserObjectsThread(FEProblemBase &problem, const TheWarehouse::Query &query)
void printGeneralExecutionInformation() const override
Print general information about the loop, like the ordering of class of objects.
void join(const ComputeUserObjectsThread &)
virtual void onExternalSide(const Elem *elem, unsigned int side) override
Called when iterating over external sides (no side neighbor)
std::vector< ShapeElementUserObject * > _shape_element_objs
void querySubdomain(Interfaces iface, std::vector< T > &results)
std::vector< DomainUserObject * > _domain_objs
virtual void subdomainChanged() override
Called every time the current subdomain changes (i.e.
std::vector< InternalSideUserObject * > _internal_side_objs
Interface for objects that needs coupling capabilities.
Definition Coupleable.h:53
std::set< TagID > & getFEVariableCoupleableVectorTags()
Definition Coupleable.h:120
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
void reinitMaterialsFace(SubdomainID blk_id, const THREAD_ID tid, bool swap_stateful=true, const std::deque< MaterialBase * > *reinit_mats=nullptr)
reinit materials on element faces
virtual void prepareFaceShapes(unsigned int var, const THREAD_ID tid) override
virtual void prepareShapes(unsigned int var, const THREAD_ID tid) override
virtual void reinitElem(const Elem *elem, const THREAD_ID tid) override
virtual void swapBackMaterialsFace(const THREAD_ID tid)
const std::vector< const MooseVariableFEBase * > & getUserObjectJacobianVariables(const THREAD_ID tid) const
const MaterialWarehouse & getMaterialWarehouse() const
void reinitMaterials(SubdomainID blk_id, const THREAD_ID tid, bool swap_stateful=true)
virtual void prepare(const Elem *elem, const THREAD_ID tid) override
void reinitMaterialsNeighbor(SubdomainID blk_id, const THREAD_ID tid, bool swap_stateful=true, const std::deque< MaterialBase * > *reinit_mats=nullptr)
reinit materials on the neighboring element face
virtual void swapBackMaterialsNeighbor(const THREAD_ID tid)
void clearActiveMaterialProperties(const THREAD_ID tid)
Clear the active material properties.
virtual void clearActiveElementalMooseVariables(const THREAD_ID tid) override
Clear the active elemental MooseVariableFEBase.
virtual void prepareFace(const Elem *elem, const THREAD_ID tid) override
void prepareMaterials(const std::unordered_set< unsigned int > &consumer_needed_mat_props, const SubdomainID blk_id, const THREAD_ID tid)
Add the MooseVariables and the material properties that the current materials depend on to the depend...
void reinitElemFace(const Elem *elem, unsigned int side, BoundaryID, const THREAD_ID tid)
virtual void reinitLowerDElem(const Elem *lower_d_elem, const THREAD_ID tid, const std::vector< Point > *const pts=nullptr, const std::vector< Real > *const weights=nullptr) override
const ExecFlagType & getCurrentExecuteOnFlag() const
Return/set the current execution flag.
void reinitMaterialsFaceOnBoundary(const BoundaryID boundary_id, const SubdomainID blk_id, const THREAD_ID tid, const bool swap_stateful=true, const std::deque< MaterialBase * > *const reinit_mats=nullptr)
reinit materials on element faces on a boundary (internal or external) This specific routine helps us...
void reinitMaterialsBoundary(BoundaryID boundary_id, const THREAD_ID tid, bool swap_stateful=true, const std::deque< MaterialBase * > *reinit_mats=nullptr)
reinit materials on a boundary
virtual void setActiveElementalMooseVariables(const std::set< MooseVariableFEBase * > &moose_vars, const THREAD_ID tid) override
Set the MOOSE variables to be reinited on each element.
virtual void swapBackMaterials(const THREAD_ID tid)
virtual void setActiveFEVariableCoupleableVectorTags(std::set< TagID > &vtags, const THREAD_ID tid) override
bool shouldPrintExecution(const THREAD_ID tid) const
Check whether the problem should output execution orders at this time.
virtual void subdomainSetup(SubdomainID subdomain, const THREAD_ID tid)
void reinitMaterialsInterface(BoundaryID boundary_id, const THREAD_ID tid, bool swap_stateful=true)
virtual void reinitNeighbor(const Elem *elem, unsigned int side, const THREAD_ID tid) override
An interface for accessing Materials.
virtual const std::unordered_set< unsigned int > & getMatPropDependencies() const
Retrieve the set of material properties that this object depends on.
void updateBlockFEVariableCoupledVectorTagDependency(SubdomainID id, std::set< TagID > &needed_fe_var_vector_tags, THREAD_ID tid=0) const
const std::set< MooseVariableFieldBase * > & getMooseVariableDependencies() const
Retrieve the set of MooseVariableFieldBase that this object depends on.
const ConsoleStream & console() const
Return console handle.
Definition Problem.h:48
const bool & currentlyComputingJacobian() const
Returns true if the problem is in the process of computing the Jacobian.
Definition SubProblem.h:692
The "SwapBackSentinel" class's destructor guarantees that FEProblemBase::swapBackMaterials{Face,...
NumericVector< Number > & solution()
Definition SystemBase.h:203
QueryCache is a convenient way to construct and pass around (possible partially constructed) warehous...
QueryCache & condition(Args &&... args)
Adds a new condition to the query.
QueryCache clone() const
clone creates and returns an independent copy of the query in its current state.
SubdomainID _subdomain
The subdomain for the current element.
std::set< SubdomainID > _blocks_exec_printed
Keep track of which blocks were visited.
Base class for assembly-like calculations.
query_obj query
const BoundaryID ANY_BOUNDARY_ID
Definition MooseTypes.C:21