LCOV - code coverage report
Current view: top level - src/numerics - eigen_sparse_matrix.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4257 (1b0007) with base 332933 Lines: 113 137 82.5 %
Date: 2025-09-29 22:07:10 Functions: 49 55 89.1 %
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             : // Local includes
      21             : #include "libmesh/libmesh_config.h"
      22             : 
      23             : #ifdef LIBMESH_HAVE_EIGEN
      24             : 
      25             : #include "libmesh/eigen_sparse_vector.h"
      26             : #include "libmesh/eigen_sparse_matrix.h"
      27             : #include "libmesh/dense_matrix.h"
      28             : #include "libmesh/dof_map.h"
      29             : #include "libmesh/sparsity_pattern.h"
      30             : 
      31             : // C++ Includes
      32             : #include <memory>
      33             : 
      34             : 
      35             : namespace libMesh
      36             : {
      37             : 
      38             : 
      39             : //-----------------------------------------------------------------------
      40             : // EigenSparseMatrix members
      41             : template <typename T>
      42        1073 : void EigenSparseMatrix<T>::init (const numeric_index_type m_in,
      43             :                                  const numeric_index_type n_in,
      44             :                                  const numeric_index_type libmesh_dbg_var(m_l),
      45             :                                  const numeric_index_type libmesh_dbg_var(n_l),
      46             :                                  const numeric_index_type nnz,
      47             :                                  const numeric_index_type,
      48             :                                  const numeric_index_type)
      49             : {
      50             :   // noz ignored...  only used for multiple processors!
      51          30 :   libmesh_assert_equal_to (m_in, m_l);
      52          30 :   libmesh_assert_equal_to (n_in, n_l);
      53          30 :   libmesh_assert_greater  (nnz, 0);
      54             : 
      55        1073 :   _mat.resize(m_in, n_in);
      56        1073 :   _mat.reserve(Eigen::Matrix<numeric_index_type, Eigen::Dynamic, 1>::Constant(m_in,nnz));
      57             : 
      58        1073 :   this->_is_initialized = true;
      59        1073 : }
      60             : 
      61             : 
      62             : 
      63             : template <typename T>
      64         557 : void EigenSparseMatrix<T>::init (const ParallelType)
      65             : {
      66             :   // Ignore calls on initialized objects
      67         557 :   if (this->initialized())
      68           0 :     return;
      69             : 
      70             :   // We need the DofMap for this!
      71           0 :   libmesh_assert(this->_dof_map);
      72             : 
      73             :   // Clear initialized matrices
      74           0 :   if (this->initialized())
      75           0 :     this->clear();
      76             : 
      77         557 :   const numeric_index_type n_rows   = this->_dof_map->n_dofs();
      78           0 :   const numeric_index_type n_cols   = n_rows;
      79             : 
      80             : #ifndef NDEBUG
      81             :   // The following variables are only used for assertions,
      82             :   // so avoid declaring them when asserts are inactive.
      83           0 :   const numeric_index_type n_l = this->_dof_map->n_dofs_on_processor(0);
      84           0 :   const numeric_index_type m_l = n_l;
      85             : #endif
      86             : 
      87             :   // Eigen Matrices only work for uniprocessor cases
      88           0 :   libmesh_assert_equal_to (m_l, n_rows);
      89           0 :   libmesh_assert_equal_to (n_l, n_cols);
      90             : 
      91         557 :   const std::vector<numeric_index_type> & n_nz = this->_sp->get_n_nz();
      92             : 
      93             : #ifndef NDEBUG
      94             :   // The following variables are only used for assertions,
      95             :   // so avoid declaring them when asserts are inactive.
      96           0 :   const std::vector<numeric_index_type> & n_oz = this->_sp->get_n_oz();
      97             : #endif
      98             : 
      99             :   // Make sure the sparsity pattern isn't empty
     100           0 :   libmesh_assert_equal_to (n_nz.size(), n_l);
     101           0 :   libmesh_assert_equal_to (n_oz.size(), n_l);
     102             : 
     103         557 :   if (n_rows==0)
     104             :     {
     105           0 :       _mat.resize(0,0);
     106           0 :       return;
     107             :     }
     108             : 
     109         557 :   _mat.resize(n_rows,n_cols);
     110           0 :   _mat.reserve(n_nz);
     111             : 
     112         557 :   this->_is_initialized = true;
     113             : 
     114           0 :   libmesh_assert_equal_to (n_rows, this->m());
     115           0 :   libmesh_assert_equal_to (n_cols, this->n());
     116             : }
     117             : 
     118             : 
     119             : 
     120             : template <typename T>
     121     1049309 : void EigenSparseMatrix<T>::add_matrix(const DenseMatrix<T> & dm,
     122             :                                       const std::vector<numeric_index_type> & rows,
     123             :                                       const std::vector<numeric_index_type> & cols)
     124             : 
     125             : {
     126           8 :   libmesh_assert (this->initialized());
     127          16 :   unsigned int n_rows = cast_int<unsigned int>(rows.size());
     128          16 :   unsigned int n_cols = cast_int<unsigned int>(cols.size());
     129           8 :   libmesh_assert_equal_to (dm.m(), n_rows);
     130           8 :   libmesh_assert_equal_to (dm.n(), n_cols);
     131             : 
     132             : 
     133     7817236 :   for (unsigned int i=0; i<n_rows; i++)
     134   125153781 :     for (unsigned int j=0; j<n_cols; j++)
     135   118386110 :       this->add(rows[i],cols[j],dm(i,j));
     136     1049309 : }
     137             : 
     138             : 
     139             : 
     140             : template <typename T>
     141           0 : void EigenSparseMatrix<T>::get_diagonal (NumericVector<T> & dest_in) const
     142             : {
     143           0 :   EigenSparseVector<T> & dest = cast_ref<EigenSparseVector<T> &>(dest_in);
     144             : 
     145           0 :   dest._vec = _mat.diagonal();
     146             : 
     147           0 :   dest.close();
     148           0 : }
     149             : 
     150             : 
     151             : 
     152             : template <typename T>
     153         147 : void EigenSparseMatrix<T>::get_transpose (SparseMatrix<T> & dest_in) const
     154             : {
     155           2 :   EigenSparseMatrix<T> & dest = cast_ref<EigenSparseMatrix<T> &>(dest_in);
     156             : 
     157         147 :   dest._mat = _mat.transpose();
     158             : 
     159         147 :   dest._is_initialized = true;
     160         147 :   dest._closed = true;
     161         147 : }
     162             : 
     163             : 
     164             : 
     165             : template <typename T>
     166        1184 : EigenSparseMatrix<T>::EigenSparseMatrix (const Parallel::Communicator & comm_in) :
     167             :   SparseMatrix<T>(comm_in),
     168        1184 :   _closed (false)
     169             : {
     170        1184 : }
     171             : 
     172             : 
     173             : 
     174             : template <typename T>
     175         815 : void EigenSparseMatrix<T>::clear ()
     176             : {
     177         815 :   _mat.resize(0,0);
     178             : 
     179         815 :   _closed = false;
     180         815 :   this->_is_initialized = false;
     181         815 : }
     182             : 
     183             : 
     184             : 
     185             : template <typename T>
     186        2143 : void EigenSparseMatrix<T>::zero ()
     187             : {
     188             :   // This doesn't just zero, it clears the entire non-zero structure!
     189        2143 :   _mat.setZero();
     190             : 
     191        2143 :   if (this->_sp)
     192             :   {
     193             :     // Re-reserve our non-zero structure
     194           0 :     const std::vector<numeric_index_type> & n_nz = this->_sp->get_n_nz();
     195           0 :     _mat.reserve(n_nz);
     196             :   }
     197        2143 : }
     198             : 
     199             : 
     200             : 
     201             : template <typename T>
     202          71 : std::unique_ptr<SparseMatrix<T>> EigenSparseMatrix<T>::zero_clone () const
     203             : {
     204             :   // TODO: If there is a more efficient way to make a zeroed-out copy
     205             :   // of an EigenSM, we should call that instead.
     206          73 :   auto ret = std::make_unique<EigenSparseMatrix<T>>(*this);
     207          71 :   ret->zero();
     208             : 
     209          73 :   return ret;
     210             : }
     211             : 
     212             : 
     213             : 
     214             : template <typename T>
     215         213 : std::unique_ptr<SparseMatrix<T>> EigenSparseMatrix<T>::clone () const
     216             : {
     217         213 :   return std::make_unique<EigenSparseMatrix<T>>(*this);
     218             : }
     219             : 
     220             : 
     221             : 
     222             : template <typename T>
     223        4227 : numeric_index_type EigenSparseMatrix<T>::m () const
     224             : {
     225        3858 :   libmesh_assert (this->initialized());
     226             : 
     227        4313 :   return cast_int<numeric_index_type>(_mat.rows());
     228             : }
     229             : 
     230             : 
     231             : 
     232             : template <typename T>
     233        4258 : numeric_index_type EigenSparseMatrix<T>::n () const
     234             : {
     235        3831 :   libmesh_assert (this->initialized());
     236             : 
     237        4317 :   return cast_int<numeric_index_type>(_mat.cols());
     238             : }
     239             : 
     240             : 
     241             : 
     242             : template <typename T>
     243        5771 : numeric_index_type EigenSparseMatrix<T>::row_start () const
     244             : {
     245        5771 :   return 0;
     246             : }
     247             : 
     248             : 
     249             : 
     250             : template <typename T>
     251         943 : numeric_index_type EigenSparseMatrix<T>::row_stop () const
     252             : {
     253         943 :   return this->m();
     254             : }
     255             : 
     256             : 
     257             : 
     258             : template <typename T>
     259         850 : numeric_index_type EigenSparseMatrix<T>::col_start () const
     260             : {
     261         850 :   return 0;
     262             : }
     263             : 
     264             : 
     265             : 
     266             : template <typename T>
     267         284 : numeric_index_type EigenSparseMatrix<T>::col_stop () const
     268             : {
     269         284 :   return this->n();
     270             : }
     271             : 
     272             : 
     273             : 
     274             : template <typename T>
     275      127371 : void EigenSparseMatrix<T>::set (const numeric_index_type i,
     276             :                                 const numeric_index_type j,
     277             :                                 const T value)
     278             : {
     279        3572 :   libmesh_assert (this->initialized());
     280        3572 :   libmesh_assert_less (i, this->m());
     281        3572 :   libmesh_assert_less (j, this->n());
     282             : 
     283      127371 :   _mat.coeffRef(i,j) = value;
     284      127371 : }
     285             : 
     286             : 
     287             : 
     288             : template <typename T>
     289       17081 : void EigenSparseMatrix<T>::add (const numeric_index_type i,
     290             :                                 const numeric_index_type j,
     291             :                                 const T value)
     292             : {
     293         128 :   libmesh_assert (this->initialized());
     294         128 :   libmesh_assert_less (i, this->m());
     295         128 :   libmesh_assert_less (j, this->n());
     296             : 
     297   118402679 :   _mat.coeffRef(i,j) += value;
     298       17081 : }
     299             : 
     300             : 
     301             : 
     302             : template <typename T>
     303     1008403 : void EigenSparseMatrix<T>::add_matrix(const DenseMatrix<T> & dm,
     304             :                                       const std::vector<numeric_index_type> & dof_indices)
     305             : {
     306     1008403 :   this->add_matrix (dm, dof_indices, dof_indices);
     307     1008403 : }
     308             : 
     309             : 
     310             : 
     311             : template <typename T>
     312         305 : void EigenSparseMatrix<T>::add (const T a_in, const SparseMatrix<T> & X_in)
     313             : {
     314           4 :   libmesh_assert (this->initialized());
     315           4 :   libmesh_assert_equal_to (this->m(), X_in.m());
     316           4 :   libmesh_assert_equal_to (this->n(), X_in.n());
     317             : 
     318             :   const EigenSparseMatrix<T> & X =
     319           4 :     cast_ref<const EigenSparseMatrix<T> &> (X_in);
     320             : 
     321         309 :   _mat += X._mat*a_in;
     322         305 : }
     323             : 
     324             : 
     325             : 
     326             : 
     327             : template <typename T>
     328        1520 : T EigenSparseMatrix<T>::operator () (const numeric_index_type i,
     329             :                                      const numeric_index_type j) const
     330             : {
     331          64 :   libmesh_assert (this->initialized());
     332          64 :   libmesh_assert_less (i, this->m());
     333          64 :   libmesh_assert_less (j, this->n());
     334             : 
     335        1520 :   return _mat.coeff(i,j);
     336             : }
     337             : 
     338             : 
     339             : 
     340             : template <typename T>
     341        1211 : Real EigenSparseMatrix<T>::l1_norm () const
     342             : {
     343             :   // There does not seem to be a straightforward way to iterate over
     344             :   // the columns of an EigenSparseMatrix.  So we use some extra
     345             :   // storage and keep track of the column sums while going over the
     346             :   // row entries...
     347        1211 :   std::vector<Real> abs_col_sums(this->n());
     348             : 
     349             :   // For a row-major Eigen SparseMatrix like we're using, the
     350             :   // InnerIterator iterates over the non-zero entries of rows.
     351       20239 :   for (auto row : make_range(this->m()))
     352             :     {
     353       18462 :       EigenSM::InnerIterator it(_mat, row);
     354      155392 :       for (; it; ++it)
     355      144054 :         abs_col_sums[it.col()] += std::abs(it.value());
     356             :     }
     357             : 
     358        1279 :   return *(std::max_element(abs_col_sums.begin(), abs_col_sums.end()));
     359             : }
     360             : 
     361             : 
     362             : 
     363             : template <typename T>
     364         572 : Real EigenSparseMatrix<T>::linfty_norm () const
     365             : {
     366         572 :   Real max_abs_row_sum = 0.;
     367             : 
     368             :   // For a row-major Eigen SparseMatrix like we're using, the
     369             :   // InnerIterator iterates over the non-zero entries of rows.
     370       17010 :   for (auto row : make_range(this->m()))
     371             :     {
     372       16438 :       Real current_abs_row_sum = 0.;
     373       15978 :       EigenSM::InnerIterator it(_mat, row);
     374      143748 :       for (; it; ++it)
     375      130882 :         current_abs_row_sum += std::abs(it.value());
     376             : 
     377       16438 :       max_abs_row_sum = std::max(max_abs_row_sum, current_abs_row_sum);
     378             :     }
     379             : 
     380         572 :   return max_abs_row_sum;
     381             : }
     382             : 
     383             : 
     384             : 
     385             : template <typename T>
     386        1208 : void EigenSparseMatrix<T>::get_row(numeric_index_type i,
     387             :                                    std::vector<numeric_index_type> & indices,
     388             :                                    std::vector<T> & values) const
     389             : {
     390          32 :   indices.clear();
     391          32 :   values.clear();
     392             : 
     393             :   // InnerIterator is over rows in RowMajor ordering
     394             :   static_assert(EigenSM::IsRowMajor);
     395             : 
     396        5826 :   for (EigenSM::InnerIterator it(_mat, i); it; ++it)
     397             :     {
     398        4618 :       indices.push_back(it.col());
     399        4618 :       values.push_back(it.value());
     400             :     }
     401        1208 : }
     402             : 
     403             : 
     404             : 
     405             : //------------------------------------------------------------------
     406             : // Explicit instantiations
     407             : template class LIBMESH_EXPORT EigenSparseMatrix<Number>;
     408             : 
     409             : } // namespace libMesh
     410             : 
     411             : 
     412             : #endif // #ifdef LIBMESH_HAVE_EIGEN

Generated by: LCOV version 1.14