libMesh
augment_sparsity_on_interface.C
Go to the documentation of this file.
1 // local includes
3 
4 // libMesh includes
5 #include "libmesh/elem.h"
6 #include "libmesh/boundary_info.h"
7 #include "libmesh/elem_side_builder.h"
8 
9 using namespace libMesh;
10 
12  boundary_id_type crack_boundary_lower,
13  boundary_id_type crack_boundary_upper) :
14  _mesh(mesh),
15  _crack_boundary_lower(crack_boundary_lower),
16  _crack_boundary_upper(crack_boundary_upper),
17  _initialized(false)
18 {
19  this->mesh_reinit();
20 }
21 
23 {
25  return _lower_to_upper;
26 }
27 
29 {
30  this->_initialized = true;
31 
32  // Loop over all elements (not just local elements) to make sure we find
33  // "neighbor" elements on opposite sides of the crack.
34 
35  // Map from (elem, side) to vertex average
36  std::map<std::pair<const Elem *, unsigned char>, Point> lower;
37  std::map<std::pair<const Elem *, unsigned char>, Point> upper;
38 
39  // To avoid extraneous allocation when getting element side vertex averages
40  std::unique_ptr<const Elem> side_elem;
41 
42  for (const auto & elem : _mesh.active_element_ptr_range())
43  for (auto side : elem->side_index_range())
44  if (elem->neighbor_ptr(side) == nullptr)
45  {
47  {
48  elem->build_side_ptr(side_elem, side);
49 
50  lower[std::make_pair(elem, side)] = side_elem->vertex_average();
51  }
52 
54  {
55  elem->build_side_ptr(side_elem, side);
56 
57  upper[std::make_pair(elem, side)] = side_elem->vertex_average();
58  }
59  }
60 
61  // If we're doing a reinit on a distributed mesh then we may not see
62  // all the vertex averages, or even a matching number of vertex averages.
63  // std::size_t n_lower = lower.size();
64  // std::size_t n_upper = upper.size();
65  // libmesh_assert(n_lower == n_upper);
66 
67  // Clear _lower_to_upper. This map will be used for matrix assembly later on.
68  _lower_to_upper.clear();
69 
70  // Clear _upper_to_lower. This map will be used for element ghosting
71  // on distributed meshes, communication send_list construction in
72  // parallel, and sparsity calculations
73  _upper_to_lower.clear();
74 
75  // We do an N^2 search to find elements with matching vertex averages. This could be optimized,
76  // e.g. by first sorting the vertex averages based on their (x,y,z) location.
77  {
78  for (const auto & [lower_key, lower_val] : lower)
79  {
80  // find closest vertex average in upper
81  Real min_distance = std::numeric_limits<Real>::max();
82 
83  for (const auto & [upper_key, upper_val] : upper)
84  {
85  Real distance = (upper_val - lower_val).norm();
86  if (distance < min_distance)
87  {
88  min_distance = distance;
89  _lower_to_upper[lower_key] = upper_key.first;
90  }
91  }
92 
93  // For pairs with local elements, we should have found a
94  // matching pair by now.
95  const Elem * elem = lower_key.first;
96  const Elem * neighbor = _lower_to_upper[lower_key];
97  if (min_distance < TOLERANCE)
98  {
99  // fill up the inverse map
100  _upper_to_lower[neighbor] = elem;
101  }
102  else
103  {
104  libmesh_assert_not_equal_to(elem->processor_id(), _mesh.processor_id());
105  // This must have a false positive; a remote element would
106  // have been closer.
107  _lower_to_upper.erase(lower_key);
108  }
109  }
110 
111  // Let's make sure we didn't miss any upper elements either
112 #ifndef NDEBUG
113  for (const auto & upper_pr : upper)
114  {
115  const Elem * neighbor = upper_pr.first.first;
116  if (neighbor->processor_id() != _mesh.processor_id())
117  continue;
118  ElementMap::const_iterator utl_it =
119  _upper_to_lower.find(neighbor);
120  libmesh_assert(utl_it != _upper_to_lower.end());
121  }
122 #endif
123  }
124 }
125 
126 void AugmentSparsityOnInterface::operator()
127  (const MeshBase::const_element_iterator & range_begin,
128  const MeshBase::const_element_iterator & range_end,
130  map_type & coupled_elements)
131 {
132  libmesh_assert(this->_initialized);
133 
134  const CouplingMatrix * const null_mat = nullptr;
135 
136  for (const auto & elem : as_range(range_begin, range_end))
137  {
138  if (elem->processor_id() != p)
139  coupled_elements.emplace(elem, null_mat);
140 
141  for (auto side : elem->side_index_range())
142  if (elem->neighbor_ptr(side) == nullptr)
143  {
144  ElementSideMap::const_iterator ltu_it =
145  _lower_to_upper.find(std::make_pair(elem, side));
146  if (ltu_it != _lower_to_upper.end())
147  {
148  const Elem * neighbor = ltu_it->second;
149  if (neighbor->processor_id() != p)
150  coupled_elements.emplace(neighbor, null_mat);
151  }
152  }
153 
154  ElementMap::const_iterator utl_it =
155  _upper_to_lower.find(elem);
156  if (utl_it != _upper_to_lower.end())
157  {
158  const Elem * neighbor = utl_it->second;
159  if (neighbor->processor_id() != p)
160  coupled_elements.emplace(neighbor, null_mat);
161  }
162 
163  }
164 }
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
The definition of the const_element_iterator struct.
Definition: mesh_base.h:2216
static constexpr Real TOLERANCE
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
bool _initialized
Make sure we&#39;ve been initialized before use.
std::map< const Elem *, const CouplingMatrix *, CompareDofObjectsByPIDAndThenID > map_type
What elements do we care about and what variables do we care about on each element?
The libMesh namespace provides an interface to certain functionality in the library.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:165
Real distance(const Point &p)
This is the MeshBase class.
Definition: mesh_base.h:75
boundary_id_type _crack_boundary_lower
Boundary IDs for the lower and upper faces of the "crack" in the mesh.
uint8_t processor_id_type
AugmentSparsityOnInterface(MeshBase &mesh, boundary_id_type crack_boundary_lower, boundary_id_type crack_boundary_upper)
Constructor.
int8_t boundary_id_type
Definition: id_types.h:51
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
Definition: simple_range.h:57
libmesh_assert(ctx)
auto norm(const T &a) -> decltype(std::abs(a))
Definition: tensor_tools.h:74
ElementMap _upper_to_lower
The inverse (ignoring sides) of the above map.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual void mesh_reinit() override
Rebuild the cached _lower_to_upper map whenever our Mesh has changed.
ElementSideMap _lower_to_upper
A map from (lower element ID, side ID) to matching upper element ID.
processor_id_type processor_id() const
std::map< std::pair< const Elem *, unsigned char >, const Elem * > ElementSideMap
processor_id_type processor_id() const
Definition: dof_object.h:905
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
MeshBase & _mesh
The Mesh we&#39;re calculating on.
const ElementSideMap & get_lower_to_upper() const
This class defines a coupling matrix.