Loading [MathJax]/extensions/tex2jax.js
https://mooseframework.inl.gov
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
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"
14 #include "ShapeElementUserObject.h"
15 #include "SideUserObject.h"
16 #include "InterfaceUserObject.h"
17 #include "ShapeSideUserObject.h"
18 #include "InternalSideUserObject.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)
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 
51 void
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 
60  _query.clone()
62  .condition<AttribInterfaces>(Interfaces::DomainUserObject)
63  .queryInto(_all_domain_objs);
64 
65  std::vector<UserObject *> side_objs;
66  _query.clone()
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 
117 void
119 {
120  _fe_problem.prepare(elem, _tid);
121  _fe_problem.reinitElem(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  {
135  Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
136  for (auto * var : uo->getWritableCoupledVariables())
137  var->insert(_aux_sys.solution());
138  }
139  }
140 
141  for (auto & uo : _domain_objs)
142  {
143  uo->preExecuteOnElement();
144  uo->executeOnElement();
145  }
146 
147  // UserObject Jacobians
149  {
150  // Prepare shape functions for ShapeElementUserObjects
151  const auto & jacobian_moose_vars = _fe_problem.getUserObjectJacobianVariables(_tid);
152  for (const auto & jvar : jacobian_moose_vars)
153  {
154  unsigned int jvar_id = jvar->number();
155  auto && dof_indices = jvar->dofIndices();
156 
157  _fe_problem.prepareShapes(jvar_id, _tid);
158  for (const auto uo : _shape_element_objs)
159  uo->executeJacobianWrapper(jvar_id, dof_indices);
160  }
161  }
162 }
163 
164 void
166  unsigned int side,
167  BoundaryID bnd_id,
168  const Elem * lower_d_elem /*=nullptr*/)
169 {
170  std::vector<UserObject *> userobjs;
171  queryBoundary(Interfaces::SideUserObject, bnd_id, userobjs);
172  if (userobjs.size() == 0 && _domain_objs.size() == 0)
173  return;
174 
175  _fe_problem.reinitElemFace(elem, side, _tid);
176 
177  // Reinitialize lower-dimensional variables for use in boundary Materials
178  if (lower_d_elem)
179  _fe_problem.reinitLowerDElem(lower_d_elem, _tid);
180 
181  // Set up Sentinel class so that, even if reinitMaterialsFace() throws, we
182  // still remember to swap back during stack unwinding.
186 
187  for (const auto & uo : userobjs)
188  uo->execute();
189 
190  for (auto & uo : _domain_objs)
191  {
192  uo->preExecuteOnBoundary();
193  uo->executeOnBoundary();
194  }
195 
196  // UserObject Jacobians
197  std::vector<ShapeSideUserObject *> shapers;
199  if (_fe_problem.currentlyComputingJacobian() && shapers.size() > 0)
200  {
201  // Prepare shape functions for ShapeSideUserObjects
202  const auto & jacobian_moose_vars = _fe_problem.getUserObjectJacobianVariables(_tid);
203  for (const auto & jvar : jacobian_moose_vars)
204  {
205  unsigned int jvar_id = jvar->number();
206  auto && dof_indices = jvar->dofIndices();
207 
209 
210  for (const auto & uo : shapers)
211  uo->executeJacobianWrapper(jvar_id, dof_indices);
212  }
213  }
214 }
215 
216 void
217 ComputeUserObjectsThread::onInternalSide(const Elem * elem, unsigned int side)
218 {
219  // Pointer to the neighbor we are currently working on.
220  const Elem * neighbor = elem->neighbor_ptr(side);
221 
222  // Get the global id of the element and the neighbor
223  const dof_id_type elem_id = elem->id(), neighbor_id = neighbor->id();
224 
225  if (_internal_side_objs.size() == 0 && _domain_objs.size() == 0)
226  return;
227  if (!((neighbor->active() && (neighbor->level() == elem->level()) && (elem_id < neighbor_id)) ||
228  (neighbor->level() < elem->level())))
229  return;
230 
232  _fe_problem.reinitNeighbor(elem, side, _tid);
233 
234  // Set up Sentinels so that, even if one of the reinitMaterialsXXX() calls throws, we
235  // still remember to swap back during stack unwinding.
237  _fe_problem.reinitMaterialsFace(elem->subdomain_id(), _tid);
238 
240  _fe_problem.reinitMaterialsNeighbor(neighbor->subdomain_id(), _tid);
241 
242  for (const auto & uo : _internal_side_objs)
243  if (!uo->blockRestricted() || uo->hasBlocks(neighbor->subdomain_id()))
244  uo->execute();
245 
246  for (auto & uo : _domain_objs)
247  if (!uo->blockRestricted() || uo->hasBlocks(neighbor->subdomain_id()))
248  {
249  uo->preExecuteOnInternalSide();
250  uo->executeOnInternalSide();
251  }
252 }
253 
254 void
255 ComputeUserObjectsThread::onExternalSide(const Elem * elem, unsigned int side)
256 {
257  // We are not initializing any materials here because objects that perform calculations should
258  // run onBoundary. onExternalSide should be used for mesh updates (e.g. adding/removing
259  // boundaries). Note that _current_elem / _current_side are not getting updated either.
260  for (auto & uo : _domain_objs)
261  uo->executeOnExternalSide(elem, side);
262 }
263 
264 void
265 ComputeUserObjectsThread::onInterface(const Elem * elem, unsigned int side, BoundaryID bnd_id)
266 {
267  // Pointer to the neighbor we are currently working on.
268  const Elem * neighbor = elem->neighbor_ptr(side);
269  if (!(neighbor->active()))
270  return;
271 
272  std::vector<UserObject *> interface_objs;
273  queryBoundary(Interfaces::InterfaceUserObject, bnd_id, interface_objs);
274 
275  bool has_domain_objs = false;
276  // we need to check all domain user objects because a domain user object may not be active
277  // on the current subdomain but should be executed on the interface that it attaches to
278  for (const auto * const domain_uo : _all_domain_objs)
279  if (domain_uo->shouldExecuteOnInterface())
280  {
281  has_domain_objs = true;
282  break;
283  }
284 
285  // if we do not have any interface user objects and domain user objects on the current
286  // interface
287  if (interface_objs.empty() && !has_domain_objs)
288  return;
289 
291  _fe_problem.reinitNeighbor(elem, side, _tid);
292 
293  // Set up Sentinels so that, even if one of the reinitMaterialsXXX() calls throws, we
294  // still remember to swap back during stack unwinding.
295 
297  _fe_problem.reinitMaterialsFace(elem->subdomain_id(), _tid);
299 
301  _fe_problem.reinitMaterialsNeighbor(neighbor->subdomain_id(), _tid);
302 
303  // Has to happen after face and neighbor properties have been computed. Note that we don't use
304  // a sentinel here because FEProblem::swapBackMaterialsFace is going to handle face materials,
305  // boundary materials, and interface materials (e.g. it queries the boundary material data
306  // with the current element and side
308 
309  for (const auto & uo : interface_objs)
310  uo->execute();
311 
312  for (auto & uo : _all_domain_objs)
313  if (uo->shouldExecuteOnInterface())
314  {
315  uo->preExecuteOnInterface();
316  uo->executeOnInterface();
317  }
318 }
319 
320 void
322 {
325 }
326 
327 void
329 {
330 }
331 
332 void
334 {
336  {
337  const auto & console = _fe_problem.console();
338  const auto & execute_on = _fe_problem.getCurrentExecuteOnFlag();
339  console << "[DBG] Computing elemental user objects on " << execute_on << std::endl;
340  mooseDoOnce(console << "[DBG] Execution order of objects types on each element then its sides:"
341  << std::endl;
342  // onElement
343  console << "[DBG] - element user objects" << std::endl;
344  console << "[DBG] - domain user objects" << std::endl;
345  console << "[DBG] - element user objects contributing to the Jacobian" << std::endl;
346 
347  // onBoundary
348  console << "[DBG] - side user objects" << std::endl;
349  console << "[DBG] - domain user objects executing on sides" << std::endl;
350  console << "[DBG] - side user objects contributing to the Jacobian" << std::endl;
351 
352  // onInternalSide
353  console << "[DBG] - internal side user objects" << std::endl;
354  console << "[DBG] - domain user objects executing on internal sides" << std::endl;
355 
356  // onInterface
357  console << "[DBG] - interface user objects" << std::endl;
358  console << "[DBG] - domain user objects executing at interfaces" << std::endl;);
359  }
360 }
361 
362 void
364 {
366  return;
367 
368  // Gather all user objects that may execute
369  // TODO: restrict this gathering of boundary objects to boundaries that are present
370  // in the current block
371  std::vector<ShapeSideUserObject *> shapers;
372  const_cast<ComputeUserObjectsThread *>(this)->queryBoundary(
374 
375  std::vector<SideUserObject *> side_uos;
376  const_cast<ComputeUserObjectsThread *>(this)->queryBoundary(
378 
379  std::vector<InterfaceUserObject *> interface_objs;
380  const_cast<ComputeUserObjectsThread *>(this)->queryBoundary(
382 
383  std::vector<const DomainUserObject *> domain_interface_uos;
384  for (const auto * const domain_uo : _domain_objs)
385  if (domain_uo->shouldExecuteOnInterface())
386  domain_interface_uos.push_back(domain_uo);
387 
388  // Approximation of the number of user objects currently executing
389  const auto num_objects = _element_objs.size() + _domain_objs.size() + _shape_element_objs.size() +
390  side_uos.size() + shapers.size() + _internal_side_objs.size() +
391  interface_objs.size() + domain_interface_uos.size();
392 
393  const auto & console = _fe_problem.console();
394  const auto & execute_on = _fe_problem.getCurrentExecuteOnFlag();
395 
396  if (num_objects > 0)
397  {
398  if (_blocks_exec_printed.count(_subdomain))
399  return;
400 
401  console << "[DBG] Ordering of User Objects on block " << _subdomain << std::endl;
402  // Output specific ordering of objects
403  printExecutionOrdering<ElementUserObject>(_element_objs, "element user objects");
404  printExecutionOrdering<DomainUserObject>(_domain_objs, "domain user objects");
406  printExecutionOrdering<ShapeElementUserObject>(
407  _shape_element_objs, "element user objects contributing to the Jacobian");
408  printExecutionOrdering<SideUserObject>(side_uos, "side user objects");
410  printExecutionOrdering<ShapeSideUserObject>(shapers,
411  "side user objects contributing to the Jacobian");
412  printExecutionOrdering<InternalSideUserObject>(_internal_side_objs,
413  "internal side user objects");
414  printExecutionOrdering<InterfaceUserObject>(interface_objs, "interface user objects");
415  console << "[DBG] Only user objects active on local element/sides are executed" << std::endl;
416  }
417  else if (num_objects == 0 && !_blocks_exec_printed.count(_subdomain))
418  console << "[DBG] No User Objects on block " << _subdomain << " on " << execute_on.name()
419  << std::endl;
420 
421  // Mark subdomain as having printed to avoid printing again
423 }
const std::set< MooseVariableFieldBase * > & getMooseVariableDependencies() const
Retrieve the set of MooseVariableFieldBase that this object depends on.
virtual void onBoundary(const Elem *elem, unsigned int side, BoundaryID bnd_id, const Elem *lower_d_elem=nullptr) override
Called when doing boundary assembling.
Base class for assembly-like calculations.
virtual void prepareFace(const Elem *elem, const THREAD_ID tid) override
virtual void post() override
Called after the element range loop.
std::vector< ElementUserObject * > _element_objs
std::vector< ShapeElementUserObject * > _shape_element_objs
void querySubdomain(Interfaces iface, std::vector< T > &results)
QueryCache is a convenient way to construct and pass around (possible partially constructed) warehous...
Definition: TheWarehouse.h:208
void printBlockExecutionInformation() const override
Print information about the loop, mostly order of execution of particular objects.
virtual void prepare(const Elem *elem, const THREAD_ID tid) override
NumericVector< Number > & solution()
Definition: SystemBase.h:195
void printGeneralExecutionInformation() const override
Print general information about the loop, like the ordering of class of objects.
const ExecFlagType & getCurrentExecuteOnFlag() const
Return/set the current execution flag.
virtual void onElement(const Elem *elem) override
Assembly of the element (not including surface assembly)
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 onInterface(const Elem *elem, unsigned int side, BoundaryID bnd_id) override
Called when doing interface assembling.
void queryBoundary(Interfaces iface, BoundaryID bnd, std::vector< T > &results)
void clearActiveMaterialProperties(const THREAD_ID tid)
Clear the active material properties.
virtual void subdomainChanged() override
Called every time the current subdomain changes (i.e.
const MaterialWarehouse & getMaterialWarehouse() const
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
ComputeUserObjectsThread(FEProblemBase &problem, const TheWarehouse::Query &query)
virtual void swapBackMaterialsFace(const THREAD_ID tid)
virtual void prepareFaceShapes(unsigned int var, const THREAD_ID tid) override
virtual void setActiveElementalMooseVariables(const std::set< MooseVariableFEBase *> &moose_vars, const THREAD_ID tid) override
Set the MOOSE variables to be reinited on each element.
const std::vector< const MooseVariableFEBase * > & getUserObjectJacobianVariables(const THREAD_ID tid) const
bool shouldPrintExecution(const THREAD_ID tid) const
Check whether the problem should output execution orders at this time.
virtual void reinitElem(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
boundary_id_type BoundaryID
virtual void onExternalSide(const Elem *elem, unsigned int side) override
Called when iterating over external sides (no side neighbor)
const TheWarehouse::Query _query
void join(const ComputeUserObjectsThread &)
QueryCache clone() const
clone creates and returns an independent copy of the query in its current state.
Definition: TheWarehouse.h:292
virtual void swapBackMaterialsNeighbor(const THREAD_ID tid)
query_obj query
std::set< SubdomainID > _blocks_exec_printed
Keep track of which blocks were visited.
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
Interface for objects that needs coupling capabilities.
Definition: Coupleable.h:45
const ConsoleStream & console() const
Return console handle.
Definition: Problem.h:48
virtual void swapBackMaterials(const THREAD_ID tid)
void updateBlockFEVariableCoupledVectorTagDependency(SubdomainID id, std::set< TagID > &needed_fe_var_vector_tags, THREAD_ID tid=0) const
Update FE variable coupleable vector tag vector.
virtual void subdomainSetup(SubdomainID subdomain, const THREAD_ID tid)
An interface for accessing Materials.
void reinitMaterials(SubdomainID blk_id, const THREAD_ID tid, bool swap_stateful=true)
Class for threaded computation of UserObjects.
virtual void onInternalSide(const Elem *elem, unsigned int side) override
Called when doing internal edge assembling.
std::vector< InternalSideUserObject * > _internal_side_objs
void reinitElemFace(const Elem *elem, unsigned int side, BoundaryID, const THREAD_ID tid)
QueryCache & condition(Args &&... args)
Adds a new condition to the query.
Definition: TheWarehouse.h:284
SubdomainID _subdomain
The subdomain for the current element.
std::vector< DomainUserObject * > _domain_objs
virtual void reinitNeighbor(const Elem *elem, unsigned int side, const THREAD_ID tid) override
const bool & currentlyComputingJacobian() const
Returns true if the problem is in the process of computing the Jacobian.
Definition: SubProblem.h:686
virtual void setActiveFEVariableCoupleableVectorTags(std::set< TagID > &vtags, const THREAD_ID tid) override
virtual void prepareShapes(unsigned int var, const THREAD_ID tid) override
void reinitMaterialsInterface(BoundaryID boundary_id, const THREAD_ID tid, bool swap_stateful=true)
const std::unordered_set< unsigned int > & getMatPropDependencies() const
Retrieve the set of material properties that this object depends on.
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...
std::set< TagID > & getFEVariableCoupleableVectorTags()
Definition: Coupleable.h:106
virtual void clearActiveElementalMooseVariables(const THREAD_ID tid) override
Clear the active elemental MooseVariableFEBase.
const BoundaryID ANY_BOUNDARY_ID
Definition: MooseTypes.C:21
uint8_t dof_id_type
std::vector< DomainUserObject * > _all_domain_objs
The "SwapBackSentinel" class&#39;s destructor guarantees that FEProblemBase::swapBackMaterials{Face,Neighbor}() is called even when an exception is thrown from FEProblemBase::reinitMaterials{Face,Neighbor}.