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_GHOSTING_FUNCTOR_H
21 : #define LIBMESH_GHOSTING_FUNCTOR_H
22 :
23 : // Local Includes
24 : #include "libmesh/libmesh_common.h"
25 : #include "libmesh/id_types.h"
26 : #include "libmesh/mesh_base.h"
27 : #include "libmesh/reference_counted_object.h"
28 : #include "libmesh/dof_object.h"
29 :
30 : // C++ Includes
31 : #include <unordered_map>
32 :
33 : namespace libMesh
34 : {
35 :
36 : // Forward Declarations
37 : class CouplingMatrix;
38 : class Elem;
39 : #ifdef LIBMESH_ENABLE_PERIODIC
40 : class PeriodicBoundaries;
41 : #endif
42 :
43 : /**
44 : * This abstract base class defines the interface by which library
45 : * code and user code can report associations between elements. These
46 : * associations between elements may be used to keep copies of
47 : * non-local elements retained on a distributed mesh, may be used to
48 : * keep element degrees of freedom properly communicated on a
49 : * distributed vector, and/or may be used to insert coupling entries
50 : * between elements' degrees of freedom to a sparsity matrix.
51 : *
52 : *
53 : * We can think of three levels of "element dependencies". An element
54 : * K1 has a coupling dependency on K2 if the dofs on K1 might (modulo
55 : * the coupling matrix) need sparsity pattern entries for dofs on K2.
56 : * An element K1 has an algebraic dependency on K2 if a processor
57 : * which owns K1 might need to examine the solution dof values on K2.
58 : * An element K1 has a geometric dependency on K2 if a processor which
59 : * owns K1 might need to examine the geometry of K2. For any element
60 : * K, we could call the set of coupling-ghosted ("coupled") elements
61 : * C(K), call the set of algebraic-ghosted ("evaluable") elements E(K),
62 : * and call the set of geometry-ghosted ("ghosted") elements G(K).
63 : *
64 : * It should be safe to assume that, for any element K, C(K) implies
65 : * E(K) implies G(K). These will be one-way implications in some
66 : * problems and equality relations in others.
67 : *
68 : * We can think of these as operators on sets of elements in the
69 : * obvious way, e.g.: G({K}) = {G(Ki) for all Ki in {K}}.
70 : *
71 : * The user should omit from their implementations relations which we
72 : * already have enough information to understand implicitly. For
73 : * instance, K is obviously in C(K), so a GhostingFunctor should never
74 : * bother telling us so. We pass a processor_id_type parameter to the
75 : * GhostingFunctor::operator(), e.g. when determining what ghosted
76 : * elements need to be sent to that processor while redistributing,
77 : * and a GhostingFunctor should not return any elements which already
78 : * have that processor_id. We determine what ancestor elements should
79 : * be ghosted based on what active elements are being ghosted, and a
80 : * GhostingFunctor should not return any elements which are not
81 : * active.
82 : *
83 : * We may have a PeriodicBoundary, a hanging node constraint equation,
84 : * or a user-defined constraint equation which creates a dependency
85 : * between two elements; if so then we don't need the user to also
86 : * tell us about that relation. The DefaultCoupling functor will make
87 : * both direct and periodic neighbor elements algebraically ghosted by
88 : * default.
89 : *
90 : * However, note that geometric ghosting information needs to all be
91 : * inferrable (e.g. with PeriodicBoundary objects already all
92 : * attached) *before* a mesh is prepared for use; otherwise ghost
93 : * elements may be prematurely deleted and become unrecoverable.
94 : *
95 : *
96 : * For iterating over ghosted elements:
97 : *
98 : * MeshBase::active_elements_begin() gives the first iterator to all
99 : * geometrically ghosted elements. (this means all elements on any
100 : * mesh which isn't distributed)
101 : *
102 : * MeshBase::evaluable_elements_begin() gives the first iterator to
103 : * all algebraically evaluable elements, which is a superset of
104 : * all algebraically ghosted elements. (rarely a strict superset, but
105 : * low order geometrically ghosted elements surrounded by enough
106 : * algebraically ghosted elements may become evaluable "by accident")
107 : *
108 : *
109 : * Users may only care about a subset of variables in distant
110 : * evaluable elements, so we could imagine defining E_v(K) for each
111 : * variable number v, in which case E(K) under our previous definition
112 : * is the union of E_v(K) forall v, and this is what would be included
113 : * in G(K) when deciding what to ghost, but our send_list would only
114 : * include the subset of variables we need, so communication and
115 : * memory use would be much reduced. However, for efficiency and API
116 : * simplicity, we instead define the isomorphic operator E'(K) which
117 : * gives a set of ordered pairs of elements and variable-number-sets,
118 : * from which a consistent E(K) would be derived by ignoring the
119 : * variable-number-sets.
120 : *
121 : * For C(K), there are similar issues: e.g. we may want some
122 : * discontinuous variables to couple only within their own element but
123 : * other discontinuous variables to couple in a DG/FVM way. This could
124 : * extend to more than one variable index: i.e. a dof for variable v1
125 : * in element K1 would depend on a dof for variable v2 in element K2
126 : * iff K2 is in C_v1_v2(K1). This would induce a consistent E_v(K) =
127 : * union of C_w_v(K) forall variable indices w. Again, the equivalent
128 : * API alternative we use here is for C'(K) to return a set of ordered
129 : * pairs of elements and variable-number-pair-sets.
130 : *
131 : * We return variable-stuff-sets as pointers to CouplingMatrix. That
132 : * way, in the common case where the user cares about all variables and
133 : * couple to all variables, all the functor needs to return for
134 : * variable-number-sets and variable-number-pair-sets is nullptr (which
135 : * as in other libMesh APIs will be interpreted and documented to mean
136 : * the full set). In the common case where the user wants coupling
137 : * between elements to match coupling within elements, the functor can
138 : * return the same pointer as DofMap::_coupling_matrix. Even in the
139 : * less common cases, the user can store common variable-number-sets
140 : * and variable-number-pair sets as CouplingMatrix members of a
141 : * functor object of their subclass, and setting up a few of those
142 : * matrices then setting lots of those pointers is cheap.
143 : *
144 : * The definition of the CouplingMatrix for a variable-dependent E'
145 : * should be consistent with the requirements that would have been
146 : * imposed had that matrix been used for a C'. In other words, if the
147 : * returned CouplingMatrix CM has CM(i,j)==true for any i, then
148 : * variable j will be evaluable on the algebraically ghosted element.
149 : *
150 : * After a GhostingFunctor has been created, a reference to it can be
151 : * passed to MeshBase::add_ghosting_functor to expand geometric
152 : * ghosting, or to DofMap::add_algebraic_ghosting_functor to expand
153 : * both algebraic and geometric ghosting, or to
154 : * DofMap::add_coupling_functor to expand coupling along with both
155 : * types of ghosting.
156 : *
157 : * Note that when an element is specified in algebraic ghosting or
158 : * coupling queries, only degrees of freedom for the variables
159 : * supported on that element are thereby ghosted and/or coupled.
160 : * Any unsupported variable dofs associated with the element's nodes
161 : * (e.g. subdomain-restricted variables on a neighboring subdomain)
162 : * will be unaffected.
163 : *
164 : * Typical usage of the GhostingFunctor would be to add a geometric ghosting
165 : * functor before the mesh preparation is completed; progmatically, this would
166 : * be before MeshBase::prepare_for_use() is called, but many different libMesh
167 : * idioms internally call this function. The algebraic and coupling ghosting
168 : * functors normally are added before EquationSystems::init() is called.
169 : * However, in some circumstances, solution evaluation may be needed within the
170 : * GhostingFunctor in order to determine the ghosting, in which case the appropriate
171 : * functor would need to be added after EquationSystems::init(). In this case,
172 : * the user will need to reinitialize certain parts of the DofMap for
173 : * algebraic and coupling functors. For algebraic ghosting functors, the
174 : * user will need to call DofMap::reinit_send_list() and then reinitialize
175 : * any NumericVectors that are GHOSTED, e.g. the System::current_local_solution.
176 : * For coupling ghosting, the user will also need to recompute the sparsity
177 : * pattern via DofMap::clear_sparsity() and then DofMap::compute_sparsity() and
178 : * then reinitialize any SparseMatrix objects attached to the System, e.g.
179 : * the system.get_system_matrix().
180 : *
181 : * \author Roy H. Stogner
182 : * \date 2016
183 : */
184 : class GhostingFunctor : public ReferenceCountedObject<GhostingFunctor>
185 : {
186 : public:
187 :
188 : /**
189 : * Constructor. Empty in the base class.
190 : */
191 462625 : GhostingFunctor(): _mesh(nullptr) {}
192 :
193 : /**
194 : * Constructor using mesh
195 : */
196 319587 : GhostingFunctor(const MeshBase & mesh): _mesh(&mesh) {}
197 :
198 : /**
199 : * Copy Constructor
200 : */
201 30684 : GhostingFunctor(const GhostingFunctor & other) :
202 : ReferenceCountedObject<GhostingFunctor>(other),
203 30684 : _mesh (other._mesh)
204 2032 : {}
205 :
206 : /**
207 : * Virtual destructor; this is an abstract base class.
208 : */
209 6318 : virtual ~GhostingFunctor() = default;
210 :
211 : /**
212 : * A clone() is needed because GhostingFunctor can not be shared between
213 : * different meshes. The operations in GhostingFunctor are mesh dependent.
214 : */
215 0 : virtual std::unique_ptr<GhostingFunctor> clone () const
216 : // Let us return nullptr for backward compatibility.
217 : // We will come back to mark this function as pure virtual
218 : // once the API upgrade is done.
219 0 : { return nullptr; }
220 :
221 : /**
222 : * It should be called after cloning a ghosting functor.
223 : * Ghosting functor is mesh dependent
224 : */
225 1421700 : virtual void set_mesh(const MeshBase * mesh) { _mesh = mesh; }
226 :
227 : #ifdef LIBMESH_ENABLE_PERIODIC
228 : // Set PeriodicBoundaries to couple
229 0 : virtual void set_periodic_boundaries(const PeriodicBoundaries *) {}
230 : #endif
231 :
232 : /**
233 : * Return the mesh associated with ghosting functor
234 : */
235 : const MeshBase * get_mesh() const { libmesh_assert(_mesh); return _mesh; }
236 :
237 : /**
238 : * What elements do we care about and what variables do we care
239 : * about on each element?
240 : */
241 : typedef std::map<const Elem*, const CouplingMatrix*, CompareDofObjectsByPIDAndThenID> map_type;
242 :
243 : /**
244 : * For the specified range of active elements, what other elements
245 : * currently living (whether local or ghosted) on this processor
246 : * need to be coupled/ghosted to accommodate them? Don't bother to
247 : * return any results which already have processor_id p.
248 : *
249 : * This API is new, and we should replace "ignoring those on
250 : * processor p" with "ignoring those which match a predicate
251 : * functor" eventually.
252 : */
253 : virtual void operator() (const MeshBase::const_element_iterator & range_begin,
254 : const MeshBase::const_element_iterator & range_end,
255 : processor_id_type p,
256 : map_type & coupled_elements) = 0;
257 :
258 : /**
259 : * GhostingFunctor subclasses which cache data will need to
260 : * initialize that cache. We call mesh_reinit() whenever the
261 : * relevant Mesh has changed, but before remote elements on a
262 : * distributed mesh are deleted.
263 : */
264 0 : virtual void mesh_reinit () {};
265 :
266 : /**
267 : * For algebraic ghosting or coupling functors we also call
268 : * dofmap_reinit() later, after dofs have been distributed on the
269 : * new mesh but before the functors have been queried for send_list
270 : * or sparsity pattern calculations.
271 : */
272 513793 : virtual void dofmap_reinit () {};
273 :
274 : /**
275 : * GhostingFunctor subclasses with relatively long-lasting caches
276 : * may want to redistribute those caches whenever the relevant Mesh
277 : * is redistributed; we will give them an opportunity when that
278 : * happens. At the point in the code where this is called, element
279 : * processor ids have been set to their new destinations, and those
280 : * elements have been copied to their new destinations, but the
281 : * elements have not yet been deleted by the processors which
282 : * previously held them..
283 : */
284 0 : virtual void redistribute () {};
285 :
286 : /**
287 : * GhostingFunctor subclasses with relatively long-lasting caches
288 : * may want to delete the no-longer-relevant parts of those caches
289 : * after a redistribution is complete.
290 : */
291 6543 : virtual void delete_remote_elements () {};
292 :
293 : protected:
294 : const MeshBase * _mesh;
295 : };
296 :
297 : } // namespace libMesh
298 :
299 : #endif // LIBMESH_GHOSTING_FUNCTOR_H
|