Line data Source code
1 : // The libMesh Finite Element Library.
2 : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 :
4 : // This library is free software; you can redistribute it and/or
5 : // modify it under the terms of the GNU Lesser General Public
6 : // License as published by the Free Software Foundation; either
7 : // version 2.1 of the License, or (at your option) any later version.
8 :
9 : // This library is distributed in the hope that it will be useful,
10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : // Lesser General Public License for more details.
13 :
14 : // You should have received a copy of the GNU Lesser General Public
15 : // License along with this library; if not, write to the Free Software
16 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 :
18 :
19 :
20 : #ifndef LIBMESH_MESH_COMMUNICATION_H
21 : #define LIBMESH_MESH_COMMUNICATION_H
22 :
23 : // Local Includes
24 : #include "libmesh/compare_elems_by_level.h"
25 : #include "libmesh/libmesh_common.h"
26 : #include "libmesh/mesh_base.h"
27 :
28 : // C++ Includes
29 : #include <set>
30 : #include <utility>
31 : #include <unordered_map>
32 : #include <vector>
33 :
34 : namespace libMesh
35 : {
36 :
37 : // Forward declarations
38 : class MeshBase;
39 : class DistributedMesh;
40 :
41 : // This is for backwards compatibility, but if your code relies on
42 : // forward declarations in our headers then fix it.
43 : class ParallelMesh;
44 :
45 : /**
46 : * This is the \p MeshCommunication class. It handles all the details
47 : * of communicating mesh information from one processor to another. All
48 : * parallelization of the \p Mesh data structures is done via this class.
49 : *
50 : * \author Benjamin S. Kirk
51 : * \date 2003
52 : */
53 : class MeshCommunication
54 : {
55 : public:
56 :
57 : /**
58 : * Constructor.
59 : */
60 : MeshCommunication () = default;
61 :
62 : /**
63 : * Destructor.
64 : */
65 : ~MeshCommunication () = default;
66 :
67 : /**
68 : * Clears all data structures and resets to a pristine state.
69 : */
70 : void clear ();
71 :
72 : // /**
73 : // * Finds all the processors that may contain
74 : // * elements that neighbor my elements. This list
75 : // * is guaranteed to include all processors that border
76 : // * any of my elements, but may include additional ones as
77 : // * well. This method computes bounding boxes for the
78 : // * elements on each processor and checks for overlaps.
79 : // */
80 : // void find_neighboring_processors(const MeshBase &);
81 :
82 : /**
83 : * This method takes a mesh (which is assumed to reside on
84 : * processor 0) and broadcasts it to all the other processors.
85 : * It also broadcasts any boundary information the mesh has
86 : * associated with it.
87 : */
88 : void broadcast (MeshBase &) const;
89 :
90 : /**
91 : * This method takes a parallel distributed mesh and redistributes
92 : * the elements. Specifically, any elements stored on a given
93 : * processor are sent to the processor which "owns" them. Similarly,
94 : * any elements assigned to the current processor but stored on
95 : * another are received. Once this step is completed any required ghost
96 : * elements are updated. The final result is that each processor stores
97 : * only the elements it actually owns and any ghost elements required
98 : * to satisfy data dependencies. This method can be invoked after a
99 : * partitioning step to affect the new partitioning.
100 : *
101 : * Redistribution can also be done with newly coarsened elements'
102 : * neighbors only.
103 : */
104 : void redistribute (DistributedMesh & mesh,
105 : bool newly_coarsened_only = false) const;
106 :
107 : /**
108 : *
109 : */
110 : void gather_neighboring_elements (DistributedMesh &) const;
111 :
112 : /**
113 : * Examine a just-coarsened mesh, and for any newly-coarsened elements,
114 : * send the associated ghosted elements to the processor which needs them.
115 : */
116 : void send_coarse_ghosts (MeshBase &) const;
117 :
118 : /**
119 : * This method takes an input \p DistributedMesh which may be
120 : * distributed among all the processors. Each processor then
121 : * sends its local nodes and elements to processor \p root_id.
122 : * The end result is that a previously distributed \p DistributedMesh
123 : * will be serialized on processor \p root_id. Since this method is
124 : * collective it must be called by all processors. For the special
125 : * case of \p root_id equal to \p DofObject::invalid_processor_id
126 : * this function performs an allgather.
127 : */
128 : void gather (const processor_id_type root_id, MeshBase &) const;
129 :
130 : /**
131 : * This method takes an input \p DistributedMesh which may be
132 : * distributed among all the processors. Each processor then
133 : * sends its local nodes and elements to the other processors.
134 : * The end result is that a previously distributed \p DistributedMesh
135 : * will be serialized on each processor. Since this method is
136 : * collective it must be called by all processors.
137 : */
138 60 : void allgather (MeshBase & mesh) const
139 78246 : { MeshCommunication::gather(DofObject::invalid_processor_id, mesh); }
140 :
141 : /**
142 : * This method takes an input \p DistributedMesh which may be
143 : * distributed among all the processors. Each processor
144 : * deletes all elements which are neither local elements nor "ghost"
145 : * elements which touch local elements, and deletes all nodes which
146 : * are not contained in local or ghost elements.
147 : * The end result is that a previously serial \p DistributedMesh
148 : * will be distributed between processors. Since this method is
149 : * collective it must be called by all processors.
150 : *
151 : * The std::set is a list of extra elements that you _don't_ want
152 : * to delete. These will be left on the current processor along with
153 : * local elements and ghosted neighbors.
154 : */
155 : void delete_remote_elements (DistributedMesh &, const std::set<Elem *> &) const;
156 :
157 : /**
158 : * This method assigns globally unique, partition-agnostic
159 : * indices to the nodes and elements in the mesh. The approach
160 : * is to compute the Hilbert space-filling curve key and use its
161 : * value to assign an index in [0,N_global). Since the Hilbert key
162 : * is unique for each spatial location, two objects occupying the
163 : * same location will be assigned the same global id. Thus, this
164 : * method can also be useful for identifying duplicate nodes
165 : * which may occur during parallel refinement.
166 : */
167 : void assign_global_indices (MeshBase &) const;
168 :
169 : /**
170 : * Throw an error if we have any index clashes in the numbering used by
171 : * assign_global_indices.
172 : */
173 : void check_for_duplicate_global_indices (MeshBase & ) const;
174 :
175 : /**
176 : * This method determines a locally unique, contiguous
177 : * index for each object in the input range.
178 : */
179 : template <typename ForwardIterator>
180 : void find_local_indices (const libMesh::BoundingBox &,
181 : const ForwardIterator &,
182 : const ForwardIterator &,
183 : std::unordered_map<dof_id_type, dof_id_type> &) const;
184 :
185 : /**
186 : * This method determines a globally unique, partition-agnostic
187 : * index for each object in the input range.
188 : */
189 : template <typename ForwardIterator>
190 : void find_global_indices (const Parallel::Communicator & communicator,
191 : const libMesh::BoundingBox &,
192 : const ForwardIterator &,
193 : const ForwardIterator &,
194 : std::vector<dof_id_type> &) const;
195 :
196 : /**
197 : * Copy ids of ghost elements from their local processors.
198 : */
199 : void make_elems_parallel_consistent (MeshBase &);
200 :
201 : #ifdef LIBMESH_ENABLE_AMR
202 : /**
203 : * Copy p levels of ghost elements from their local processors.
204 : */
205 : void make_p_levels_parallel_consistent (MeshBase &);
206 : #endif // LIBMESH_ENABLE_AMR
207 :
208 : /**
209 : * Assuming all ids on local nodes are globally unique, and
210 : * assuming all processor ids are parallel consistent, this function makes
211 : * all other ids parallel consistent.
212 : */
213 : void make_node_ids_parallel_consistent (MeshBase &);
214 :
215 : /**
216 : * Assuming all unique_ids on local nodes are globally unique, and
217 : * assuming all processor ids are parallel consistent, this function makes
218 : * all ghost unique_ids parallel consistent.
219 : */
220 : void make_node_unique_ids_parallel_consistent (MeshBase &);
221 :
222 : /**
223 : * Assuming all processor ids are parallel consistent, this function
224 : * makes all ghost boundary ids on nodes parallel consistent.
225 : */
226 : void make_node_bcids_parallel_consistent (MeshBase &);
227 :
228 : /**
229 : * Assuming all processor ids on nodes touching local elements
230 : * are parallel consistent, this function makes all other processor ids
231 : * parallel consistent as well.
232 : */
233 : void make_node_proc_ids_parallel_consistent (MeshBase &);
234 :
235 : /**
236 : * Assuming all processor ids on nodes touching local elements
237 : * are parallel consistent, this function makes processor ids
238 : * on new nodes on other processors parallel consistent as well.
239 : */
240 : void make_new_node_proc_ids_parallel_consistent (MeshBase &);
241 :
242 : /**
243 : * Copy processor_ids and ids on ghost nodes from their
244 : * local processors. This is useful for code which wants to add
245 : * nodes to a distributed mesh.
246 : */
247 : void make_nodes_parallel_consistent (MeshBase &);
248 :
249 : /**
250 : * Copy processor_ids and ids on new nodes from their local
251 : * processors.
252 : */
253 : void make_new_nodes_parallel_consistent (MeshBase &);
254 : };
255 :
256 :
257 : // Related utilities
258 :
259 : // What to use to fill sets of connected nodes and elements
260 : typedef std::set<const Node *> connected_node_set_type;
261 : typedef std::set<const Elem *, CompareElemIdsByLevel> connected_elem_set_type;
262 :
263 : // Ask a mesh's ghosting functors to insert into a set all elements
264 : // that are either on or connected to processor id \p pid. Ask only
265 : // for elements in the range from \p elem_it before \p elem_end;
266 : // typically this may be mesh.active_pid_elements_*(pid)
267 : void query_ghosting_functors(const MeshBase & mesh,
268 : processor_id_type pid,
269 : MeshBase::const_element_iterator elem_it,
270 : MeshBase::const_element_iterator elem_end,
271 : connected_elem_set_type & connected_elements);
272 :
273 : // Take a set of elements and insert all immediate
274 : // children of elements in the given range
275 : void connect_children(const MeshBase & mesh,
276 : MeshBase::const_element_iterator elem_it,
277 : MeshBase::const_element_iterator elem_end,
278 : connected_elem_set_type & connected_elements);
279 :
280 : // Take a set of elements and insert all elements' ancestors and
281 : // subactive descendants as well. If a mesh is provided and has any
282 : // constraint rows, insert elements with the constraining nodes for
283 : // any constrained nodes in our set.
284 : //
285 : // \deprecated This method is now deprecated, because it does not
286 : // handle recursive dependencies. Use the new
287 : // connect_element_dependencies method instead.
288 : #ifdef LIBMESH_ENABLE_DEPRECATED
289 : void connect_families(connected_elem_set_type & connected_elements,
290 : const MeshBase * mesh = nullptr);
291 : #endif // LIBMESH_ENABLE_DEPRECATED
292 :
293 : // Take a set of elements and create a set of connected nodes.
294 : void reconnect_nodes (connected_elem_set_type & connected_elements,
295 : connected_node_set_type & connected_nodes);
296 :
297 : // Take a set of elements and of nodes, and insert all
298 : // libMesh-mandated element of them: ancestor elements,
299 : // immediate children, subactive descendents of active elements,
300 : // interior_parents, nodes of any of those elements, and elements used
301 : // to constrain any of those nodes. This must be done recursively
302 : // (well, repeatedly; we unroll) in the general case, since a node
303 : // constraint can require a new element that can require other new
304 : // elements with new nodes with new constraints.
305 : void connect_element_dependencies(const MeshBase & mesh,
306 : connected_elem_set_type & connected_elements,
307 : connected_node_set_type & connected_nodes);
308 :
309 : // Takes already-examined sets and not-yet-examined sets, returns more sets
310 : // in need of examination (or empty sets if done).
311 : std::pair<connected_elem_set_type, connected_node_set_type>
312 : connect_element_dependencies(const MeshBase & mesh,
313 : const connected_elem_set_type & connected_elements,
314 : const connected_node_set_type & connected_nodes,
315 : const connected_elem_set_type & new_connected_elements,
316 : const connected_node_set_type & new_connected_nodes);
317 :
318 : //--------------------------------------------------------------
319 : // MeshCommunication inline members
320 :
321 :
322 : } // namespace libMesh
323 :
324 : #endif // LIBMESH_MESH_COMMUNICATION_H
|