libMesh
Loading...
Searching...
No Matches
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
9using 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
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
126void 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}
std::map< std::pair< const Elem *, unsigned char >, const Elem * > ElementSideMap
ElementSideMap _lower_to_upper
A map from (lower element ID, side ID) to matching upper element ID.
const ElementSideMap & get_lower_to_upper() const
boundary_id_type _crack_boundary_lower
Boundary IDs for the lower and upper faces of the "crack" in the mesh.
bool _initialized
Make sure we've been initialized before use.
ElementMap _upper_to_lower
The inverse (ignoring sides) of the above map.
AugmentSparsityOnInterface(MeshBase &mesh, boundary_id_type crack_boundary_lower, boundary_id_type crack_boundary_upper)
Constructor.
MeshBase & _mesh
The Mesh we're calculating on.
virtual void mesh_reinit() override
Rebuild the cached _lower_to_upper map whenever our Mesh has changed.
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
This class defines a coupling matrix.
processor_id_type processor_id() const
Definition dof_object.h:881
This is the base class from which all geometric element types are derived.
Definition elem.h:96
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?
This is the MeshBase class.
Definition mesh_base.h:81
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition mesh_base.h:170
processor_id_type processor_id() const
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
MeshBase & mesh
The libMesh namespace provides an interface to certain functionality in the library.
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
int8_t boundary_id_type
Definition id_types.h:51
libmesh_assert(ctx)
static constexpr Real TOLERANCE
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
uint8_t processor_id_type
Definition id_types.h:104
The definition of the const_element_iterator struct.
Definition mesh_base.h:2556
Real distance(const Point &p)