www.mooseframework.org
ComputeUserObjectsThread.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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, bnd_id, _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::onInterface(const Elem * elem, unsigned int side, BoundaryID bnd_id)
256 {
257  // Pointer to the neighbor we are currently working on.
258  const Elem * neighbor = elem->neighbor_ptr(side);
259  if (!(neighbor->active()))
260  return;
261 
262  std::vector<UserObject *> interface_objs;
263  queryBoundary(Interfaces::InterfaceUserObject, bnd_id, interface_objs);
264 
265  bool has_domain_objs = false;
266  // we need to check all domain user objects because a domain user object may not be active
267  // on the current subdomain but should be executed on the interface that it attaches to
268  for (const auto * const domain_uo : _all_domain_objs)
269  if (domain_uo->shouldExecuteOnInterface())
270  {
271  has_domain_objs = true;
272  break;
273  }
274 
275  // if we do not have any interface user objects and domain user objects on the current
276  // interface
277  if (interface_objs.empty() && !has_domain_objs)
278  return;
279 
281  _fe_problem.reinitNeighbor(elem, side, _tid);
282 
283  // Set up Sentinels so that, even if one of the reinitMaterialsXXX() calls throws, we
284  // still remember to swap back during stack unwinding.
285 
287  _fe_problem.reinitMaterialsFace(elem->subdomain_id(), _tid);
289 
291  _fe_problem.reinitMaterialsNeighbor(neighbor->subdomain_id(), _tid);
292 
293  // Has to happen after face and neighbor properties have been computed. Note that we don't use
294  // a sentinel here because FEProblem::swapBackMaterialsFace is going to handle face materials,
295  // boundary materials, and interface materials (e.g. it queries the boundary material data
296  // with the current element and side
298 
299  for (const auto & uo : interface_objs)
300  uo->execute();
301 
302  for (auto & uo : _all_domain_objs)
303  if (uo->shouldExecuteOnInterface())
304  {
305  uo->preExecuteOnInterface();
306  uo->executeOnInterface();
307  }
308 }
309 
310 void
312 {
315 }
316 
317 void
319 {
320 }
321 
322 void
324 {
326  {
327  const auto & console = _fe_problem.console();
328  const auto & execute_on = _fe_problem.getCurrentExecuteOnFlag();
329  console << "[DBG] Computing elemental user objects on " << execute_on << std::endl;
330  mooseDoOnce(console << "[DBG] Execution order of objects types on each element then its sides:"
331  << std::endl;
332  // onElement
333  console << "[DBG] - element user objects" << std::endl;
334  console << "[DBG] - domain user objects" << std::endl;
335  console << "[DBG] - element user objects contributing to the Jacobian" << std::endl;
336 
337  // onBoundary
338  console << "[DBG] - side user objects" << std::endl;
339  console << "[DBG] - domain user objects executing on sides" << std::endl;
340  console << "[DBG] - side user objects contributing to the Jacobian" << std::endl;
341 
342  // onInternalSide
343  console << "[DBG] - internal side user objects" << std::endl;
344  console << "[DBG] - domain user objects executing on internal sides" << std::endl;
345 
346  // onInterface
347  console << "[DBG] - interface user objects" << std::endl;
348  console << "[DBG] - domain user objects executing at interfaces" << std::endl;);
349  }
350 }
351 
352 void
354 {
356  return;
357 
358  // Gather all user objects that may execute
359  // TODO: restrict this gathering of boundary objects to boundaries that are present
360  // in the current block
361  std::vector<ShapeSideUserObject *> shapers;
362  const_cast<ComputeUserObjectsThread *>(this)->queryBoundary(
364 
365  std::vector<SideUserObject *> side_uos;
366  const_cast<ComputeUserObjectsThread *>(this)->queryBoundary(
368 
369  std::vector<InterfaceUserObject *> interface_objs;
370  const_cast<ComputeUserObjectsThread *>(this)->queryBoundary(
372 
373  std::vector<const DomainUserObject *> domain_interface_uos;
374  for (const auto * const domain_uo : _domain_objs)
375  if (domain_uo->shouldExecuteOnInterface())
376  domain_interface_uos.push_back(domain_uo);
377 
378  // Approximation of the number of user objects currently executing
379  const auto num_objects = _element_objs.size() + _domain_objs.size() + _shape_element_objs.size() +
380  side_uos.size() + shapers.size() + _internal_side_objs.size() +
381  interface_objs.size() + domain_interface_uos.size();
382 
383  const auto & console = _fe_problem.console();
384  const auto & execute_on = _fe_problem.getCurrentExecuteOnFlag();
385 
386  if (num_objects > 0)
387  {
388  if (_blocks_exec_printed.count(_subdomain))
389  return;
390 
391  console << "[DBG] Ordering of User Objects on block " << _subdomain << std::endl;
392  // Output specific ordering of objects
393  printExecutionOrdering<ElementUserObject>(_element_objs, "element user objects");
394  printExecutionOrdering<DomainUserObject>(_domain_objs, "domain user objects");
396  printExecutionOrdering<ShapeElementUserObject>(
397  _shape_element_objs, "element user objects contributing to the Jacobian");
398  printExecutionOrdering<SideUserObject>(side_uos, "side user objects");
400  printExecutionOrdering<ShapeSideUserObject>(shapers,
401  "side user objects contributing to the Jacobian");
402  printExecutionOrdering<InternalSideUserObject>(_internal_side_objs,
403  "internal side user objects");
404  printExecutionOrdering<InterfaceUserObject>(interface_objs, "interface user objects");
405  console << "[DBG] Only user objects active on local element/sides are executed" << std::endl;
406  }
407  else if (num_objects == 0 && !_blocks_exec_printed.count(_subdomain))
408  console << "[DBG] No User Objects on block " << _subdomain << " on " << execute_on.name()
409  << std::endl;
410 
411  // Mark subdomain as having printed to avoid printing again
413 }
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.
NumericVector< Number > & solution()
Definition: SystemBase.h:182
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
virtual void reinitElemFace(const Elem *elem, unsigned int side, BoundaryID bnd_id, const THREAD_ID tid) override
boundary_id_type BoundaryID
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 prepare(const Elem *elem, const THREAD_ID tid) override
virtual void onInternalSide(const Elem *elem, unsigned int side) override
Called when doing internal edge assembling.
std::vector< InternalSideUserObject * > _internal_side_objs
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:654
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:23
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}.