LCOV - code coverage report
Current view: top level - include/ghosting - ghosting_functor.h (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 9 14 64.3 %
Date: 2025-08-19 19:27:09 Functions: 7 12 58.3 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.14