LCOV - code coverage report
Current view: top level - include/base - sparsity_pattern.h (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 22 24 91.7 %
Date: 2025-08-19 19:27:09 Functions: 8 9 88.9 %
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             : #ifndef LIBMESH_SPARSITY_PATTERN_H
      20             : #define LIBMESH_SPARSITY_PATTERN_H
      21             : 
      22             : // Local Includes
      23             : #include "libmesh/elem_range.h"
      24             : #include "libmesh/threads_allocators.h"
      25             : #include "libmesh/parallel_object.h"
      26             : 
      27             : // C++ includes
      28             : #include <algorithm> // is_sorted
      29             : #include <unordered_set>
      30             : #include <vector>
      31             : 
      32             : namespace libMesh
      33             : {
      34             : 
      35             : // Forward declarations
      36             : class DofMap;
      37             : class CouplingMatrix;
      38             : class StaticCondensationDofMap;
      39             : 
      40             : /**
      41             :  * This defines the sparsity pattern, or graph, of a sparse matrix.
      42             :  * The format is quite simple -- the global indices of the nonzero entries
      43             :  * in each row are packed into a vector.  The global indices (i,j) of the
      44             :  * nth nonzero entry of row i are given by j = sparsity_pattern[i][n];
      45             :  *
      46             :  * \author Roy Stogner
      47             :  * \date 2010
      48             :  * \brief Defines the sparsity pattern of a sparse matrix.
      49             :  */
      50             : namespace SparsityPattern // use a namespace so member classes can be forward-declared.
      51             : {
      52             : typedef std::vector<dof_id_type, Threads::scalable_allocator<dof_id_type>> Row;
      53       39481 : class Graph : public std::vector<Row> {};
      54             : 
      55       39481 : class NonlocalGraph : public std::map<dof_id_type, Row> {};
      56             : 
      57             : /**
      58             :  * Splices the two sorted ranges [begin,middle) and [middle,end)
      59             :  * into one sorted range [begin,end).  This method is much like
      60             :  * std::inplace_merge except it assumes the intersection
      61             :  * of the two sorted ranges is empty and that any element in
      62             :  * each range occurs only once in that range.  Additionally,
      63             :  * this sort occurs in-place, while std::inplace_merge may
      64             :  * use a temporary buffer.
      65             :  */
      66             : template<typename BidirectionalIterator>
      67             : static void sort_row (const BidirectionalIterator begin,
      68             :                       BidirectionalIterator       middle,
      69             :                       const BidirectionalIterator end);
      70             : 
      71             : 
      72             : 
      73             :   /**
      74             :    * Abstract base class to be used to add user-defined implicit
      75             :    * degree of freedom couplings.
      76             :    */
      77             :   class AugmentSparsityPattern
      78             :   {
      79             :   public:
      80             :     virtual ~AugmentSparsityPattern () = default;
      81             : 
      82             :     /**
      83             :      * User-defined function to augment the sparsity pattern.
      84             :      */
      85             :     virtual void augment_sparsity_pattern (SparsityPattern::Graph & sparsity,
      86             :                                            std::vector<dof_id_type> & n_nz,
      87             :                                            std::vector<dof_id_type> & n_oz) = 0;
      88             :   };
      89             : 
      90             : 
      91             : 
      92             : /**
      93             :  * This helper class can be called on multiple threads to compute
      94             :  * the sparsity pattern (or graph) of the sparse matrix resulting
      95             :  * from the discretization.  This pattern may be used directly by
      96             :  * a particular sparse matrix format (e.g. \p LaspackMatrix)
      97             :  * or indirectly (e.g. \p PetscMatrixBase).  In the latter case the
      98             :  * number of nonzeros per row of the matrix is needed for efficient
      99             :  * preallocation.  In this case it suffices to provide estimate
     100             :  * (but bounding) values, and in this case the threaded method can
     101             :  * take some short-cuts for efficiency.
     102             :  */
     103             : class Build : public ParallelObject
     104             : {
     105             : public:
     106             :   Build (const DofMap & dof_map_in,
     107             :          const CouplingMatrix * dof_coupling_in,
     108             :          const std::vector<GhostingFunctor *> & coupling_functors_in,
     109             :          const bool implicit_neighbor_dofs_in,
     110             :          const bool need_full_sparsity_pattern_in,
     111             :          const bool calculate_constrained_in = false,
     112             :          const StaticCondensationDofMap * sc = nullptr);
     113             : 
     114             :   /**
     115             :    * Special functions.
     116             :    * - The Build object holds references to DofMap and coupling
     117             :    *   functors, therefore it can't be assigned.
     118             :    */
     119             :   Build (const Build &) = default;
     120             :   Build & operator= (const Build &) = delete;
     121             :   Build (Build &&) = default;
     122             :   Build & operator= (Build &&) = delete;
     123       83358 :   ~Build () = default;
     124             : 
     125             :   /**
     126             :    * Splitting constructor, for use in multithreaded loops.
     127             :    */
     128             :   Build (Build & other, Threads::split);
     129             : 
     130             :   /**
     131             :    * Add entries from a range of elements to this object's sparsity
     132             :    * pattern.
     133             :    */
     134             :   void operator()(const ConstElemRange & range);
     135             : 
     136             :   /**
     137             :    * Combine the sparsity pattern in \p other with this object's
     138             :    * sparsity pattern.  Useful in multithreaded loops.
     139             :    */
     140             :   void join (const Build & other);
     141             : 
     142             :   /**
     143             :    * Send sparsity pattern data relevant to other processors to those
     144             :    * processors, and receive and incorporate data relevant to us.
     145             :    */
     146             :   void parallel_sync ();
     147             : 
     148             :   /**
     149             :    * Rows of sparse matrix indices, indexed by the offset from the
     150             :    * first DoF on this processor.
     151             :    */
     152        1240 :   const SparsityPattern::Graph & get_sparsity_pattern() const
     153        1240 :   { return sparsity_pattern; }
     154             : 
     155             :   /**
     156             :    * Rows of sparse matrix indices, mapped from global DoF number,
     157             :    * which belong on other processors.  Stored here only temporarily
     158             :    * until a parallel_sync() sends them where they belong.
     159             :    */
     160             :   const SparsityPattern::NonlocalGraph & get_nonlocal_pattern() const
     161             :   { return nonlocal_pattern; }
     162             : 
     163             :   /**
     164             :    * The total number of nonzeros in the global matrix.
     165             :    */
     166             :   std::size_t n_nonzeros() const;
     167             : 
     168             :   /**
     169             :    * The number of on-processor nonzeros in my portion of the
     170             :    * global matrix.
     171             :    */
     172        2270 :   const std::vector<dof_id_type> & get_n_nz() const
     173       43634 :   { return n_nz; }
     174             : 
     175             :   /**
     176             :    * The number of off-processor nonzeros in my portion of the
     177             :    * global matrix.
     178             :    */
     179        2218 :   const std::vector<dof_id_type> & get_n_oz() const
     180       41370 :   { return n_oz; }
     181             : 
     182             :   /**
     183             :    * Let a user-provided AugmentSparsityPattern subclass modify our
     184             :    * sparsity structure.
     185             :    */
     186             :   void apply_extra_sparsity_object(SparsityPattern::AugmentSparsityPattern & asp);
     187             : 
     188             :   /**
     189             :    * Let a user-provided function modify our sparsity structure.
     190             :    */
     191           0 :   void apply_extra_sparsity_function(void (*func)(SparsityPattern::Graph & sparsity,
     192             :                                                    std::vector<dof_id_type> & n_nz,
     193             :                                                    std::vector<dof_id_type> & n_oz,
     194             :                                                    void * context),
     195             :                                       void * context)
     196           0 :   { func(sparsity_pattern, n_nz, n_oz, context); }
     197             : 
     198             :   /**
     199             :    * Clear the "full" details of our sparsity structure, leaving only
     200             :    * the counts of non-zero entries.
     201             :    */
     202       37861 :   void clear_full_sparsity()
     203             :   {
     204       36651 :     sparsity_pattern.clear();
     205        1210 :     nonlocal_pattern.clear();
     206       37861 :   }
     207             : 
     208             : private:
     209             :   const DofMap & dof_map;
     210             :   const CouplingMatrix * dof_coupling;
     211             :   const std::vector<GhostingFunctor *> & coupling_functors;
     212             :   const bool implicit_neighbor_dofs;
     213             :   const bool need_full_sparsity_pattern;
     214             :   const bool calculate_constrained;
     215             :   const StaticCondensationDofMap * const sc;
     216             : 
     217             :   /**
     218             :    * If there are "spider" nodes in the mesh (i.e. a single node which
     219             :    * is connected to many 1D elements) and Constraints, we can end up
     220             :    * sorting the same set of DOFs multiple times in handle_vi_vj(),
     221             :    * only to find that it has no net effect on the final sparsity. In
     222             :    * such cases it is much faster to keep track of (element_dofs_i,
     223             :    * element_dofs_j) pairs which have already been handled and not
     224             :    * repeat the computation. We use this data structure to keep track
     225             :    * of hashes of sets of dofs we have already seen, thus avoiding
     226             :    * unnecessary calculations.
     227             :    */
     228             :   std::unordered_set<dof_id_type> hashed_dof_sets;
     229             : 
     230             :   /// A dummy work vector to avoid repeated memory allocations
     231             :   std::vector<dof_id_type> dummy_vec;
     232             : 
     233             :   void handle_vi_vj(const std::vector<dof_id_type> & element_dofs_i,
     234             :                     const std::vector<dof_id_type> & element_dofs_j);
     235             : 
     236             :   void sorted_connected_dofs(const Elem * elem,
     237             :                              std::vector<dof_id_type> & dofs_vi,
     238             :                              unsigned int vi);
     239             : 
     240             : #ifndef LIBMESH_ENABLE_DEPRECATED
     241             : private:
     242             : #endif
     243             : 
     244             :   SparsityPattern::Graph sparsity_pattern;
     245             : 
     246             :   SparsityPattern::NonlocalGraph nonlocal_pattern;
     247             : 
     248             :   std::vector<dof_id_type> n_nz;
     249             : 
     250             :   std::vector<dof_id_type> n_oz;
     251             : };
     252             : 
     253             : }
     254             : 
     255             : 
     256             : 
     257             : // ------------------------------------------------------------
     258             : // SparsityPattern inline member functions
     259             : template<typename BidirectionalIterator>
     260             : inline
     261    39346947 : void SparsityPattern::sort_row (const BidirectionalIterator begin,
     262             :                                 BidirectionalIterator       middle,
     263             :                                 const BidirectionalIterator end)
     264             : {
     265             :   // Assure we have the conditions for an inplace_merge
     266             : #ifdef DEBUG
     267     3973576 :   libmesh_assert(std::is_sorted(begin, middle));
     268     3973576 :   libmesh_assert(std::is_sorted(middle, end));
     269             : #endif
     270     3973576 :   libmesh_assert(std::unique(begin, middle) == middle);
     271     3973576 :   libmesh_assert(std::unique(middle, end) == end);
     272             : 
     273    43320523 :   std::inplace_merge(begin, middle, end);
     274             : 
     275             :   // Assure the algorithm worked if we are in DEBUG mode
     276             : #ifdef DEBUG
     277     3973576 :   libmesh_assert (std::is_sorted(begin,end));
     278             : #endif
     279             : 
     280             :   // Make sure the two ranges did not contain any common elements
     281     3973576 :   libmesh_assert (std::unique (begin, end) == end);
     282    39346947 : }
     283             : 
     284             : } // namespace libMesh
     285             : 
     286             : #endif // LIBMESH_SPARSITY_PATTERN_H

Generated by: LCOV version 1.14