libMesh
diagonal_matrix_test.C
Go to the documentation of this file.
1 // libmesh includes
2 #include <libmesh/diagonal_matrix.h>
3 #include <libmesh/parallel.h>
4 #include <libmesh/dense_matrix.h>
5 #include <libmesh/id_types.h>
6 #include <libmesh/numeric_vector.h>
7 
8 #include "libmesh_cppunit.h"
9 #include "test_comm.h"
10 
11 #include <memory>
12 #include <numeric>
13 
14 #define UNUSED 0
15 
16 using namespace libMesh;
17 
18 namespace
19 {
20 template <typename T>
21 T
22 termial(T n)
23 {
24  return n * (n + 1) / 2;
25 }
26 }
27 
28 class DiagonalMatrixTest : public CppUnit::TestCase
29 {
30 public:
31  LIBMESH_CPPUNIT_TEST_SUITE(DiagonalMatrixTest);
32 
33  CPPUNIT_TEST(testSizes);
34  CPPUNIT_TEST(testNumerics);
35  CPPUNIT_TEST(testClone);
36 
37  CPPUNIT_TEST_SUITE_END();
38 
39 public:
40  void setUp()
41  {
42  _comm = TestCommWorld;
43  _matrix = std::make_unique<DiagonalMatrix<Number>>(*_comm);
44 
45  numeric_index_type root_block_size = 2;
46  _local_size = root_block_size + static_cast<numeric_index_type>(_comm->rank());
47  _global_size = 0;
48  _i.push_back(0);
49 
50  for (processor_id_type p = 0; p < _comm->size(); ++p)
51  {
52  numeric_index_type block_size = root_block_size + static_cast<numeric_index_type>(p);
53  _global_size += block_size;
54  _i.push_back(_global_size);
55  }
56 
57  _matrix->init(_global_size, UNUSED, _local_size, UNUSED);
58  }
59 
60  void tearDown() {}
61 
62  void testSizes()
63  {
64  LOG_UNIT_TEST;
65 
66  CPPUNIT_ASSERT_EQUAL(_global_size, _matrix->m());
67  CPPUNIT_ASSERT_EQUAL(_global_size, _matrix->n());
68  CPPUNIT_ASSERT_EQUAL(_i[_comm->rank()], _matrix->row_start());
69  CPPUNIT_ASSERT_EQUAL(_i[_comm->rank() + 1], _matrix->row_stop());
70  }
71 
72  void testNumerics()
73  {
74  LOG_UNIT_TEST;
75 
76  numeric_index_type beginning_index = _matrix->row_start();
77  numeric_index_type end_index = _matrix->row_stop();
78 
79  CPPUNIT_ASSERT_EQUAL(_local_size, numeric_index_type(_matrix->row_stop() - _matrix->row_start()));
80 
81  _matrix->zero();
82 
83  // In general we don't want to mix these calls without an intervening close(), but since these
84  // calls are not actually doing anything for this matrix type it's ok here
85  _matrix->add(beginning_index, beginning_index + 1, 1);
86  _matrix->set(beginning_index + 1, beginning_index, 1);
87 
88  // Test that off-diagonal elements are always zero
89  LIBMESH_ASSERT_NUMBERS_EQUAL(0, (*_matrix)(beginning_index, beginning_index + 1), _tolerance);
90  LIBMESH_ASSERT_NUMBERS_EQUAL(0, (*_matrix)(beginning_index + 1, beginning_index), _tolerance);
91 
92  // Test add
93  {
94  for (numeric_index_type i = beginning_index; i < end_index; ++i)
95  _matrix->add(i, i, i);
96 
97  // Also add to rank 0
98  _matrix->add(0, 0, 1);
99 
100  CPPUNIT_ASSERT(!_matrix->closed());
101 
102  _matrix->close();
103  CPPUNIT_ASSERT(_matrix->closed());
104 
105  for (numeric_index_type i = beginning_index; i < end_index; ++i)
106  {
107  if (i)
108  LIBMESH_ASSERT_NUMBERS_EQUAL((*_matrix)(i, i), i, _tolerance);
109  else
110  LIBMESH_ASSERT_NUMBERS_EQUAL((*_matrix)(i, i), _comm->size(), _tolerance);
111  }
112  }
113 
114  // Test set
115  {
116  for (numeric_index_type i = beginning_index; i < end_index; ++i)
117  if (i != _global_size - 1)
118  _matrix->set(i, i, i);
119 
120  if (_comm->rank() == 0)
121  _matrix->set(_global_size - 1, _global_size - 1, 0);
122 
123  CPPUNIT_ASSERT(!_matrix->closed());
124 
125  _matrix->close();
126  CPPUNIT_ASSERT(_matrix->closed());
127 
128  for (numeric_index_type i = beginning_index; i < end_index; ++i)
129  {
130  if (i != _global_size - 1)
131  LIBMESH_ASSERT_NUMBERS_EQUAL(i, (*_matrix)(i, i), _tolerance);
132  else
133  LIBMESH_ASSERT_NUMBERS_EQUAL(0, (*_matrix)(i, i), _tolerance);
134  }
135  }
136 
137  std::vector<numeric_index_type> rows(_local_size);
138  std::iota(rows.begin(), rows.end(), beginning_index);
139 
140  // Test dense matrix add, get diagonal, SparseMatrix add, get transpose
141  {
142  DenseMatrix<Number> dense(_local_size, _local_size);
143 
144  for (numeric_index_type local_index = 0, global_index = beginning_index;
145  local_index < _local_size;
146  ++local_index, ++global_index)
147  dense(local_index, local_index) = global_index;
148 
149  _matrix->zero();
150 
151  // rows-columns overload for DenseMatrix add
152  _matrix->add_matrix(dense, rows, rows);
153 
154  // Close not really necessary here because we didn't do anything off-process but still good
155  // practice
156  _matrix->close();
157 
158  for (numeric_index_type i = beginning_index; i < end_index; ++i)
159  LIBMESH_ASSERT_NUMBERS_EQUAL(i, (*_matrix)(i, i), _tolerance);
160 
161  // Build
162  auto diagonal = NumericVector<Number>::build(*_comm);
163  // Allocate storage
164  diagonal->init(_matrix->diagonal());
165  // Fill entries
166  _matrix->get_diagonal(*diagonal);
167 
168  // Build
169  DiagonalMatrix<Number> copy(*_comm);
170  // Allocate storage
171  copy.init(*_matrix);
172  // Fill entries from diagonal
173  copy = std::move(*diagonal);
174 
175  // Single dof-indices overload for DenseMatrix add
176  _matrix->add_matrix(dense, rows);
177  _matrix->close();
178 
179  for (numeric_index_type i = beginning_index; i < end_index; ++i)
180  LIBMESH_ASSERT_NUMBERS_EQUAL(2 * i, (*_matrix)(i, i), _tolerance);
181 
182  // SparseMatrix add
183  _matrix->add(-1, copy);
184 
185  for (numeric_index_type i = beginning_index; i < end_index; ++i)
186  LIBMESH_ASSERT_NUMBERS_EQUAL(i, (*_matrix)(i, i), _tolerance);
187 
188  _matrix->get_transpose(copy);
189 
190  for (numeric_index_type i = beginning_index; i < end_index; ++i)
191  LIBMESH_ASSERT_NUMBERS_EQUAL(i, copy(i, i), _tolerance);
192  }
193 
194  // Test norms
195  {
196  LIBMESH_ASSERT_FP_EQUAL(termial(_global_size - 1), _matrix->l1_norm(), _tolerance);
197  LIBMESH_ASSERT_FP_EQUAL(_global_size - 1, _matrix->linfty_norm(), _tolerance);
198  }
199 
200  // Test zero_rows
201  {
202  _matrix->zero_rows(rows, 1);
203  for (numeric_index_type i = beginning_index; i < end_index; ++i)
204  for (numeric_index_type j = beginning_index; j < end_index; ++j)
205  {
206  if (i == j)
207  LIBMESH_ASSERT_NUMBERS_EQUAL(1, (*_matrix)(i, j), _tolerance);
208  else
209  LIBMESH_ASSERT_NUMBERS_EQUAL(0, (*_matrix)(i, j), _tolerance);
210  }
211  }
212  }
213 
214  void testClone()
215  {
216  LOG_UNIT_TEST;
217 
218  {
219  // Create copy, test that it can go out of scope
220  auto copy = _matrix->clone();
221 
222  // Check that matrices have the same local/global sizes
223  CPPUNIT_ASSERT_EQUAL(copy->m(), _matrix->m());
224  CPPUNIT_ASSERT_EQUAL(copy->n(), _matrix->n());
225  CPPUNIT_ASSERT_EQUAL(copy->local_m(), _matrix->local_m());
226  CPPUNIT_ASSERT_EQUAL(copy->row_start(), _matrix->row_start());
227  CPPUNIT_ASSERT_EQUAL(copy->row_stop(), _matrix->row_stop());
228 
229  // Check that copy has same values as original
230  LIBMESH_ASSERT_FP_EQUAL(copy->l1_norm(), _matrix->l1_norm(), _tolerance);
231  }
232 
233  {
234  // Create zero copy
235  auto zero_copy = _matrix->zero_clone();
236 
237  // Check that matrices have the same local/global sizes
238  CPPUNIT_ASSERT_EQUAL(zero_copy->m(), _matrix->m());
239  CPPUNIT_ASSERT_EQUAL(zero_copy->n(), _matrix->n());
240  CPPUNIT_ASSERT_EQUAL(zero_copy->local_m(), _matrix->local_m());
241  CPPUNIT_ASSERT_EQUAL(zero_copy->row_start(), _matrix->row_start());
242  CPPUNIT_ASSERT_EQUAL(zero_copy->row_stop(), _matrix->row_stop());
243 
244  // Check that zero_copy has same values as original
245  LIBMESH_ASSERT_FP_EQUAL(0.0, zero_copy->l1_norm(), _tolerance);
246  }
247  }
248 
249 private:
250 
252  std::unique_ptr<DiagonalMatrix<Number>> _matrix;
254  std::vector<numeric_index_type> _i;
255  const Real _tolerance = TOLERANCE * TOLERANCE;
256 };
257 
virtual void zero() override final
Sets all elements of the matrix to 0 and resets any decomposition flag which may have been previously...
Definition: dense_matrix.h:911
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:171
static constexpr Real TOLERANCE
The libMesh namespace provides an interface to certain functionality in the library.
void iota(ForwardIter first, ForwardIter last, T value)
Utility::iota was created back when std::iota was just an SGI STL extension.
Definition: utility.h:229
std::vector< numeric_index_type > _i
uint8_t processor_id_type
dof_id_type numeric_index_type
Definition: id_types.h:99
std::unique_ptr< DiagonalMatrix< Number > > _matrix
Diagonal matrix class whose underlying storage is a vector.
CPPUNIT_TEST_SUITE_REGISTRATION(DiagonalMatrixTest)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Parallel::Communicator * _comm
static std::unique_ptr< NumericVector< T > > build(const Parallel::Communicator &comm, SolverPackage solver_package=libMesh::default_solver_package(), ParallelType parallel_type=AUTOMATIC)
Builds a NumericVector on the processors in communicator comm using the linear solver package specifi...
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.
numeric_index_type _local_size