libMesh
eigen_sparse_matrix.C
Go to the documentation of this file.
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>
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  libmesh_assert_equal_to (m_in, m_l);
52  libmesh_assert_equal_to (n_in, n_l);
53  libmesh_assert_greater (nnz, 0);
54 
55  _mat.resize(m_in, n_in);
56  _mat.reserve(Eigen::Matrix<numeric_index_type, Eigen::Dynamic, 1>::Constant(m_in,nnz));
57 
58  this->_is_initialized = true;
59 }
60 
61 
62 
63 template <typename T>
65 {
66  // Ignore calls on initialized objects
67  if (this->initialized())
68  return;
69 
70  // We need the DofMap for this!
71  libmesh_assert(this->_dof_map);
72 
73  // Clear initialized matrices
74  if (this->initialized())
75  this->clear();
76 
77  const numeric_index_type n_rows = this->_dof_map->n_dofs();
78  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  const numeric_index_type n_l = this->_dof_map->n_dofs_on_processor(0);
84  const numeric_index_type m_l = n_l;
85 #endif
86 
87  // Eigen Matrices only work for uniprocessor cases
88  libmesh_assert_equal_to (m_l, n_rows);
89  libmesh_assert_equal_to (n_l, n_cols);
90 
91  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  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  libmesh_assert_equal_to (n_nz.size(), n_l);
101  libmesh_assert_equal_to (n_oz.size(), n_l);
102 
103  if (n_rows==0)
104  {
105  _mat.resize(0,0);
106  return;
107  }
108 
109  _mat.resize(n_rows,n_cols);
110  _mat.reserve(n_nz);
111 
112  this->_is_initialized = true;
113 
114  libmesh_assert_equal_to (n_rows, this->m());
115  libmesh_assert_equal_to (n_cols, this->n());
116 }
117 
118 
119 
120 template <typename T>
122  const std::vector<numeric_index_type> & rows,
123  const std::vector<numeric_index_type> & cols)
124 
125 {
126  libmesh_assert (this->initialized());
127  unsigned int n_rows = cast_int<unsigned int>(rows.size());
128  unsigned int n_cols = cast_int<unsigned int>(cols.size());
129  libmesh_assert_equal_to (dm.m(), n_rows);
130  libmesh_assert_equal_to (dm.n(), n_cols);
131 
132 
133  for (unsigned int i=0; i<n_rows; i++)
134  for (unsigned int j=0; j<n_cols; j++)
135  this->add(rows[i],cols[j],dm(i,j));
136 }
137 
138 
139 
140 template <typename T>
142 {
143  EigenSparseVector<T> & dest = cast_ref<EigenSparseVector<T> &>(dest_in);
144 
145  dest._vec = _mat.diagonal();
146 
147  dest.close();
148 }
149 
150 
151 
152 template <typename T>
154 {
155  EigenSparseMatrix<T> & dest = cast_ref<EigenSparseMatrix<T> &>(dest_in);
156 
157  dest._mat = _mat.transpose();
158 
159  dest._is_initialized = true;
160  dest._closed = true;
161 }
162 
163 
164 
165 template <typename T>
167  SparseMatrix<T>(comm_in),
168  _closed (false)
169 {
170 }
171 
172 
173 
174 template <typename T>
176 {
177  _mat.resize(0,0);
178 
179  _closed = false;
180  this->_is_initialized = false;
181 }
182 
183 
184 
185 template <typename T>
187 {
188  // This doesn't just zero, it clears the entire non-zero structure!
189  _mat.setZero();
190 
191  if (this->_sp)
192  {
193  // Re-reserve our non-zero structure
194  const std::vector<numeric_index_type> & n_nz = this->_sp->get_n_nz();
195  _mat.reserve(n_nz);
196  }
197 }
198 
199 
200 
201 template <typename T>
202 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  auto ret = std::make_unique<EigenSparseMatrix<T>>(*this);
207  ret->zero();
208 
209  return ret;
210 }
211 
212 
213 
214 template <typename T>
215 std::unique_ptr<SparseMatrix<T>> EigenSparseMatrix<T>::clone () const
216 {
217  return std::make_unique<EigenSparseMatrix<T>>(*this);
218 }
219 
220 
221 
222 template <typename T>
224 {
225  libmesh_assert (this->initialized());
226 
227  return cast_int<numeric_index_type>(_mat.rows());
228 }
229 
230 
231 
232 template <typename T>
234 {
235  libmesh_assert (this->initialized());
236 
237  return cast_int<numeric_index_type>(_mat.cols());
238 }
239 
240 
241 
242 template <typename T>
244 {
245  return 0;
246 }
247 
248 
249 
250 template <typename T>
252 {
253  return this->m();
254 }
255 
256 
257 
258 template <typename T>
260 {
261  return 0;
262 }
263 
264 
265 
266 template <typename T>
268 {
269  return this->n();
270 }
271 
272 
273 
274 template <typename T>
276  const numeric_index_type j,
277  const T value)
278 {
279  libmesh_assert (this->initialized());
280  libmesh_assert_less (i, this->m());
281  libmesh_assert_less (j, this->n());
282 
283  _mat.coeffRef(i,j) = value;
284 }
285 
286 
287 
288 template <typename T>
290  const numeric_index_type j,
291  const T value)
292 {
293  libmesh_assert (this->initialized());
294  libmesh_assert_less (i, this->m());
295  libmesh_assert_less (j, this->n());
296 
297  _mat.coeffRef(i,j) += value;
298 }
299 
300 
301 
302 template <typename T>
304  const std::vector<numeric_index_type> & dof_indices)
305 {
306  this->add_matrix (dm, dof_indices, dof_indices);
307 }
308 
309 
310 
311 template <typename T>
312 void EigenSparseMatrix<T>::add (const T a_in, const SparseMatrix<T> & X_in)
313 {
314  libmesh_assert (this->initialized());
315  libmesh_assert_equal_to (this->m(), X_in.m());
316  libmesh_assert_equal_to (this->n(), X_in.n());
317 
318  const EigenSparseMatrix<T> & X =
319  cast_ref<const EigenSparseMatrix<T> &> (X_in);
320 
321  _mat += X._mat*a_in;
322 }
323 
324 
325 
326 
327 template <typename T>
329  const numeric_index_type j) const
330 {
331  libmesh_assert (this->initialized());
332  libmesh_assert_less (i, this->m());
333  libmesh_assert_less (j, this->n());
334 
335  return _mat.coeff(i,j);
336 }
337 
338 
339 
340 template <typename T>
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  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  for (auto row : make_range(this->m()))
352  {
353  EigenSM::InnerIterator it(_mat, row);
354  for (; it; ++it)
355  abs_col_sums[it.col()] += std::abs(it.value());
356  }
357 
358  return *(std::max_element(abs_col_sums.begin(), abs_col_sums.end()));
359 }
360 
361 
362 
363 template <typename T>
365 {
366  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  for (auto row : make_range(this->m()))
371  {
372  Real current_abs_row_sum = 0.;
373  EigenSM::InnerIterator it(_mat, row);
374  for (; it; ++it)
375  current_abs_row_sum += std::abs(it.value());
376 
377  max_abs_row_sum = std::max(max_abs_row_sum, current_abs_row_sum);
378  }
379 
380  return max_abs_row_sum;
381 }
382 
383 
384 
385 template <typename T>
387  std::vector<numeric_index_type> & indices,
388  std::vector<T> & values) const
389 {
390  indices.clear();
391  values.clear();
392 
393  // InnerIterator is over rows in RowMajor ordering
394  static_assert(EigenSM::IsRowMajor);
395 
396  for (EigenSM::InnerIterator it(_mat, i); it; ++it)
397  {
398  indices.push_back(it.col());
399  values.push_back(it.value());
400  }
401 }
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
virtual void set(const numeric_index_type i, const numeric_index_type j, const T value) override
Set the element (i,j) to value.
The EigenSparseMatrix class wraps a sparse matrix object from the Eigen library.
virtual void init(const numeric_index_type m, const numeric_index_type n, const numeric_index_type m_l, const numeric_index_type n_l, const numeric_index_type nnz=30, const numeric_index_type noz=10, const numeric_index_type blocksize=1) override
Initialize SparseMatrix with the specified sizes.
virtual void add(const numeric_index_type i, const numeric_index_type j, const T value) override
Add value to the element (i,j).
virtual numeric_index_type m() const override
virtual numeric_index_type row_stop() const override
DataType _vec
Actual Eigen::SparseVector<> we are wrapping.
bool _closed
Flag indicating if the matrix has been closed yet.
virtual std::unique_ptr< SparseMatrix< T > > clone() const override
Provides a uniform interface to vector storage schemes for different linear algebra libraries...
Definition: vector_fe_ex5.C:44
unsigned int m() const
The libMesh namespace provides an interface to certain functionality in the library.
virtual void close() override
Calls the NumericVector&#39;s internal assembly routines, ensuring that the values are consistent across ...
DataType _mat
Actual Eigen::SparseMatrix<> we are wrapping.
virtual void get_transpose(SparseMatrix< T > &dest) const override
Copies the transpose of the matrix into dest, which may be *this.
Generic sparse matrix.
Definition: vector_fe_ex5.C:46
virtual void zero() override
Set all entries to 0.
virtual numeric_index_type n() const override
virtual void get_diagonal(NumericVector< T > &dest) const override
Copies the diagonal part of the matrix into dest.
dof_id_type numeric_index_type
Definition: id_types.h:99
bool _is_initialized
Flag that tells if init() has been called.
Definition: libmesh.C:315
EigenSparseMatrix(const Parallel::Communicator &comm)
Constructor; initializes the matrix to be empty, without any structure, i.e.
bool _is_initialized
Flag indicating whether or not the matrix has been initialized.
virtual numeric_index_type m() const =0
libmesh_assert(ctx)
virtual numeric_index_type col_stop() const override
virtual T operator()(const numeric_index_type i, const numeric_index_type j) const override
virtual numeric_index_type row_start() const override
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual Real linfty_norm() const override
virtual numeric_index_type col_start() const override
virtual void clear() override
Restores the SparseMatrix<T> to a pristine state.
static const bool value
Definition: xdr_io.C:55
virtual void get_row(numeric_index_type i, std::vector< numeric_index_type > &indices, std::vector< T > &values) const override
Get a row from the matrix.
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition: int_range.h:140
bool initialized()
Checks that library initialization has been done.
Definition: libmesh.C:334
virtual std::unique_ptr< SparseMatrix< T > > zero_clone() const override
virtual Real l1_norm() const override
unsigned int n() const
Defines a dense matrix for use in Finite Element-type computations.
Definition: dof_map.h:75
This class provides a nice interface to the Eigen C++-based data structures for serial vectors...
virtual numeric_index_type n() const =0
ParallelType
Defines an enum for parallel data structure types.
virtual void add_matrix(const DenseMatrix< T > &dm, const std::vector< numeric_index_type > &rows, const std::vector< numeric_index_type > &cols) override
Add the full matrix dm to the SparseMatrix.