https://mooseframework.inl.gov
EqualValueBoundaryConstraint.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 // MOOSE includes
12 #include "MooseMesh.h"
13 
14 #include "libmesh/null_output_iterator.h"
15 #include "libmesh/parallel.h"
16 #include "libmesh/parallel_elem.h"
17 #include "libmesh/parallel_node.h"
18 
19 namespace // Anonymous namespace for helpers
20 {
31 struct CompareElemsByLevel
32 {
33  bool operator()(const Elem * a, const Elem * b) const
34  {
35  libmesh_assert(a);
36  libmesh_assert(b);
37  const unsigned int al = a->level(), bl = b->level();
38  const dof_id_type aid = a->id(), bid = b->id();
39 
40  return (al == bl) ? aid < bid : al < bl;
41  }
42 };
43 
44 } // anonymous namespace
45 
47 
50 {
52  params.addClassDescription(
53  "Constraint for enforcing that variables on each side of a boundary are equivalent.");
54  params.addParam<unsigned int>(
55  "primary",
56  "The ID of the primary node. If no ID is provided, first node of secondary set is chosen.");
57  params.addParam<Point>("primary_node_coord", "Coordinates of the primary node to locate.");
58  params.addParam<std::vector<unsigned int>>("secondary_node_ids", "The IDs of the secondary node");
59  params.addParam<BoundaryName>("secondary", "The boundary ID associated with the secondary side");
60  params.addRequiredParam<Real>("penalty", "The penalty used for the boundary term");
61  return params;
62 }
63 
65  : NodalConstraint(parameters), _penalty(getParam<Real>("penalty"))
66 {
68 }
69 
70 void
72 {
74 }
75 
76 void
78 {
81  ghostPrimary();
82 }
83 
84 void
86 {
87  // user provided nothing
88  if (!isParamValid("secondary_node_ids") && !isParamValid("secondary"))
89  paramError("secondary", "Either secondary or secondary_node_ids must be provided.");
90 
91  // user provided conflicting params
92  if (isParamValid("secondary_node_ids") && isParamValid("secondary"))
93  paramError("secondary",
94  "Both 'secondary' and 'secondary_node_ids' parameters are set. They are mutually "
95  "exclusive.");
96 
97  // Fill in _connected_nodes, which defines local secondary nodes in the base class
98  //
99  // Note that later on when we pick the primary node from the secondary node set, we
100  // will make sure to remove it from _connected_nodes
101  _connected_nodes.clear();
102 
103  // user provided boundary name
104  if (isParamValid("secondary"))
105  {
106  const auto & secondary_bnd = getParam<BoundaryName>("secondary");
107  const auto & secondary_nodes = _mesh.getNodeList(_mesh.getBoundaryID(secondary_bnd));
108 
109  for (const auto & nid : secondary_nodes)
110  if (_mesh.nodeRef(nid).processor_id() == _subproblem.processor_id())
111  _connected_nodes.push_back(nid);
112  }
113  // user provided node ids
114  else if (isParamValid("secondary_node_ids"))
115  {
116  const auto & secondary_node_ids = getParam<std::vector<unsigned int>>("secondary_node_ids");
117  for (const auto & nid : secondary_node_ids)
118  if (_mesh.queryNodePtr(nid) &&
119  _mesh.nodeRef(nid).processor_id() == _subproblem.processor_id())
120  _connected_nodes.push_back(nid);
121  }
122 }
123 
124 void
126 {
127  // user provided nothing
128  if (isParamValid("primary") && isParamValid("primary_node_coord"))
129  mooseError(
130  "Both 'primary' and 'primary_node_coord' parameters are set. They are mutually exclusive.");
131 
132  dof_id_type primary_node_id = Node::invalid_id;
133 
134  // user provided primary node coordinates
135  if (isParamValid("primary_node_coord"))
136  primary_node_id = getPrimaryNodeIDByCoord();
137  // user provided primary node id
138  else if (isParamValid("primary"))
139  primary_node_id = getParam<unsigned int>("primary");
140  // no primary node provided, so we pick one from secondary nodes
141  else
142  {
143  // If the user provided secondary node ids, set primary node to first one
144  if (isParamValid("secondary_node_ids"))
145  {
146  if (_connected_nodes.size())
147  primary_node_id = _connected_nodes[0];
148  }
149  // otherwise, we pick the minimum node id from the secondary node set
150  else
151  {
152  if (_connected_nodes.size())
153  primary_node_id = (*std::min_element(_connected_nodes.begin(), _connected_nodes.end()));
154  _mesh.comm().min(primary_node_id);
155  }
156  }
157 
158  mooseAssert(primary_node_id != Node::invalid_id, "We should have found a primary node");
159 
160  // Remove primary node from secondary nodes
161  auto it = std::find(_connected_nodes.begin(), _connected_nodes.end(), primary_node_id);
162  if (it != _connected_nodes.end())
163  _connected_nodes.erase(it);
164 
165  // Store primary node id
166  _primary_node_vector.resize(1);
167  _primary_node_vector[0] = primary_node_id;
168 }
169 
172 {
173  const Real eps = libMesh::TOLERANCE;
174  std::unordered_set<dof_id_type> local_primary_node_ids;
175  const auto & primary_node_coord = getParam<Point>("primary_node_coord");
176 
177  // Gather local candidates
178  for (const auto & bnd_node : *_mesh.getBoundaryNodeRange())
179  {
180  if ((*(bnd_node->_node) - primary_node_coord).norm() < eps)
181  {
182  // The primary node we found should belong to the secondary node set
183  //
184  // Note that we do not immediately break once a match is found because in theory, although it
185  // is extremely unlikely, there could be multiple coinciding nodes on the secondary boundary
186  // that match the provided coordinates. In that case, we would like to emit a meaning error
187  // message.
188  if (std::find(_connected_nodes.begin(), _connected_nodes.end(), bnd_node->_node->id()) !=
189  _connected_nodes.end())
190  local_primary_node_ids.insert(bnd_node->_node->id());
191  }
192  }
193 
194  // Gather all candidates from all ranks
195  const std::vector<dof_id_type> local_node_vec(local_primary_node_ids.begin(),
196  local_primary_node_ids.end());
197  std::vector<std::vector<dof_id_type>> gathered_node_vecs;
198  _mesh.comm().allgather(local_node_vec, gathered_node_vecs);
199 
200  // Deduplicate
201  std::unordered_set<dof_id_type> global_primary_node_ids;
202  for (const auto & vec : gathered_node_vecs)
203  global_primary_node_ids.insert(vec.begin(), vec.end());
204 
205  // Make sure we found one and exactly one
206  if (global_primary_node_ids.size() == 0)
207  mooseError("Couldn't find a node ID for the specified primary_node_coord.");
208  else if (global_primary_node_ids.size() > 1)
209  mooseError("Multiple nodes found for the specified primary_node_coord.");
210 
211  return *global_primary_node_ids.begin();
212 }
213 
214 void
216 {
217  const auto & node_to_elem_map = _mesh.nodeToElemMap();
218  auto node_to_elem_pair = node_to_elem_map.find(_primary_node_vector[0]);
219  bool found_elems = (node_to_elem_pair != node_to_elem_map.end());
220 
221  // Add elements connected to primary node to Ghosted Elements.
222 
223  // On a distributed mesh, these elements might have already been
224  // remoted, in which case we need to gather them back first.
225  if (!_mesh.getMesh().is_serial())
226  {
227 #ifndef NDEBUG
228  bool someone_found_elems = found_elems;
229  _mesh.getMesh().comm().max(someone_found_elems);
230  mooseAssert(someone_found_elems, "Missing entry in node to elem map");
231 #endif
232 
233  std::set<Elem *, CompareElemsByLevel> primary_elems_to_ghost;
234  std::set<Node *> nodes_to_ghost;
235  if (found_elems)
236  {
237  for (dof_id_type id : node_to_elem_pair->second)
238  {
239  Elem * elem = _mesh.queryElemPtr(id);
240  if (elem)
241  {
242  primary_elems_to_ghost.insert(elem);
243 
244  const unsigned int n_nodes = elem->n_nodes();
245  for (unsigned int n = 0; n != n_nodes; ++n)
246  nodes_to_ghost.insert(elem->node_ptr(n));
247  }
248  }
249  }
250 
251  // Send nodes first since elements need them
252  _mesh.getMesh().comm().allgather_packed_range(&_mesh.getMesh(),
253  nodes_to_ghost.begin(),
254  nodes_to_ghost.end(),
256 
257  _mesh.getMesh().comm().allgather_packed_range(&_mesh.getMesh(),
258  primary_elems_to_ghost.begin(),
259  primary_elems_to_ghost.end(),
261 
262  // After allgather_packed_range(), rebuild internal connectivity.
263  // This updates ghost nodes/elements across processors and reconstructs node_to_elem_map.
264  _mesh.update();
265 
266  // Find elems again now that we know they're there
267  const auto & new_node_to_elem_map = _mesh.nodeToElemMap();
268  node_to_elem_pair = new_node_to_elem_map.find(_primary_node_vector[0]);
269  found_elems = (node_to_elem_pair != new_node_to_elem_map.end());
270  }
271 
272  if (!found_elems)
273  mooseError("Couldn't find any elements connected to primary node");
274 
275  const std::vector<dof_id_type> & elems = node_to_elem_pair->second;
276 
277  if (elems.size() == 0)
278  mooseError("Couldn't find any elements connected to primary node");
279  _subproblem.addGhostedElem(elems[0]);
280 }
281 
282 Real
284 {
285  switch (type)
286  {
287  case Moose::Secondary:
288  return (_u_secondary[_i] - _u_primary[_j]) * _penalty;
289  case Moose::Primary:
290  return (_u_primary[_j] - _u_secondary[_i]) * _penalty;
291  }
292  return 0.;
293 }
294 
295 Real
297 {
298  switch (type)
299  {
301  return _penalty;
303  return -_penalty;
305  return _penalty;
307  return -_penalty;
308  default:
309  mooseError("Unsupported type");
310  break;
311  }
312  return 0.;
313 }
MooseMesh & _mesh
Reference to this Kernel&#39;s mesh object.
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
int eps(unsigned int i, unsigned int j)
2D version
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
Definition: KokkosUtils.h:40
void updateConstrainedNodes()
Update the sets of nodes with constrained DOFs.
ConstraintType
Definition: MooseTypes.h:806
dof_id_type getPrimaryNodeIDByCoord() const
Get the primary node ID by searching for the node with coordinates matching _primary_node_coord on th...
const VariableValue & _u_primary
Holds the current solution at the current quadrature point.
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition: MooseBase.h:467
static constexpr Real TOLERANCE
unsigned int _j
virtual void meshChanged() override
Called on this object when the mesh changes.
virtual const Node * queryNodePtr(const dof_id_type i) const
Definition: MooseMesh.C:860
const VariableValue & _u_secondary
Value of the unknown variable this BC is action on.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const Parallel::Communicator & comm() const
static InputParameters validParams()
virtual const Node & nodeRef(const dof_id_type i) const
Definition: MooseMesh.C:834
unsigned int _i
Counter for primary and secondary nodes.
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...
virtual Elem * queryElemPtr(const dof_id_type i)
Definition: MooseMesh.C:3252
std::vector< dof_id_type > _primary_node_vector
node IDs of the primary node
const dof_id_type n_nodes
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition: MooseMesh.C:3575
void min(const T &r, T &o, Request &req) const
std::vector< dof_id_type > _connected_nodes
node IDs connected to the primary node (secondary nodes)
void ghostPrimary()
Ghost elements and nodes connected to the primary node.
SubProblem & _subproblem
Reference to this kernel&#39;s SubProblem.
const std::vector< dof_id_type > & getNodeList(boundary_id_type nodeset_id) const
Return a writable reference to a vector of node IDs that belong to nodeset_id.
Definition: MooseMesh.C:3597
libmesh_assert(ctx)
void update()
Calls buildNodeListFromSideList(), buildNodeList(), and buildBndElemList().
Definition: MooseMesh.C:599
const std::string & type() const
Get the type of this class.
Definition: MooseBase.h:93
void pickPrimaryNode()
Pick the primary node from user input or from the secondary node set.
registerMooseObject("MooseApp", EqualValueBoundaryConstraint)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
EqualValueBoundaryConstraint(const InputParameters &parameters)
virtual void addGhostedElem(dof_id_type elem_id)=0
Will make sure that all dofs connected to elem_id are ghosted to this processor.
void populateSecondaryNodes()
Populate the set of secondary nodes from user input.
ConstraintJacobianType
Definition: MooseTypes.h:845
virtual Real computeQpJacobian(Moose::ConstraintJacobianType type) override
Computes the jacobian for the constraint.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:281
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...
Real _penalty
Penalty if constraint is not satisfied.
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object...
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition: MooseBase.h:209
virtual Real computeQpResidual(Moose::ConstraintType type) override
Computes the residual for the current secondary node.
processor_id_type processor_id() const
libMesh::StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode * > * getBoundaryNodeRange()
Definition: MooseMesh.C:1312
BoundaryID getBoundaryID(const BoundaryName &boundary_name) const
Get the associated BoundaryID for the boundary name.
Definition: MooseMesh.C:1714
uint8_t dof_id_type
const std::map< dof_id_type, std::vector< dof_id_type > > & nodeToElemMap()
If not already created, creates a map from every node to all elements to which they are connected...
Definition: MooseMesh.C:1201