libMesh
Loading...
Searching...
No Matches
eigen_sparse_matrix.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 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
35namespace libMesh
36{
37
38
39//-----------------------------------------------------------------------
40// EigenSparseMatrix members
41template <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,
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
63template <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
120template <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
140template <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
152template <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
165template <typename T>
167 SparseMatrix<T>(comm_in),
168 _closed (false)
169{
170}
171
172
173
174template <typename T>
176{
177 _mat.resize(0,0);
178
179 _closed = false;
180 this->_is_initialized = false;
181}
182
183
184
185template <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
201template <typename T>
202std::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
214template <typename T>
215std::unique_ptr<SparseMatrix<T>> EigenSparseMatrix<T>::clone () const
216{
217 return std::make_unique<EigenSparseMatrix<T>>(*this);
218}
219
220
221
222template <typename T>
224{
225 libmesh_assert (this->initialized());
226
227 return cast_int<numeric_index_type>(_mat.rows());
228}
229
230
231
232template <typename T>
234{
235 libmesh_assert (this->initialized());
236
237 return cast_int<numeric_index_type>(_mat.cols());
238}
239
240
241
242template <typename T>
247
248
249
250template <typename T>
252{
253 return this->m();
254}
255
256
257
258template <typename T>
263
264
265
266template <typename T>
268{
269 return this->n();
270}
271
272
273
274template <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
288template <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
302template <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
311template <typename T>
312void 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
327template <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
340template <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
363template <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
385template <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
407template class LIBMESH_EXPORT EigenSparseMatrix<Number>;
408
409} // namespace libMesh
410
411
412#endif // #ifdef LIBMESH_HAVE_EIGEN
Defines a dense matrix for use in Finite Element-type computations.
The EigenSparseMatrix class wraps a sparse matrix object from the Eigen library.
virtual void zero() override
Set all entries to 0.
virtual void get_diagonal(NumericVector< T > &dest) const override
Copies the diagonal part of the matrix into dest.
DataType _mat
Actual Eigen::SparseMatrix<> we are wrapping.
virtual Real l1_norm() const override
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.
virtual numeric_index_type m() const override
virtual void clear() override
Restores the SparseMatrix<T> to a pristine state.
virtual std::unique_ptr< SparseMatrix< T > > clone() const override
virtual Real linfty_norm() const override
bool _closed
Flag indicating if the matrix has been closed yet.
virtual std::unique_ptr< SparseMatrix< T > > zero_clone() const override
EigenSparseMatrix(const Parallel::Communicator &comm)
Constructor; initializes the matrix to be empty, without any structure, i.e.
virtual numeric_index_type row_stop() const override
virtual T operator()(const numeric_index_type i, const numeric_index_type j) const override
virtual void get_transpose(SparseMatrix< T > &dest) const override
Copies the transpose of the matrix into dest, which may be *this.
virtual void set(const numeric_index_type i, const numeric_index_type j, const T value) override
Set the element (i,j) to value.
virtual numeric_index_type n() const override
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 col_start() const override
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.
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 numeric_index_type row_start() const override
virtual numeric_index_type col_stop() const override
This class provides a nice interface to the Eigen C++-based data structures for serial vectors.
virtual void close() override
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...
DataType _vec
Actual Eigen::SparseVector<> we are wrapping.
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
Generic sparse matrix.
virtual numeric_index_type n() const =0
virtual numeric_index_type m() const =0
bool _is_initialized
Flag indicating whether or not the matrix has been initialized.
bool _is_initialized
Flag that tells if init() has been called.
Definition libmesh.C:305
The libMesh namespace provides an interface to certain functionality in the library.
ParallelType
Defines an enum for parallel data structure types.
libmesh_assert(ctx)
dof_id_type numeric_index_type
Definition id_types.h:99
bool initialized()
Checks that library initialization has been done.
Definition libmesh.C:324
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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:176
static const bool value
Definition xdr_io.C:55