libMesh
numeric_vector_test.h
Go to the documentation of this file.
1 #ifndef NUMERIC_VECTOR_TEST_H
2 #define NUMERIC_VECTOR_TEST_H
3 
4 // test includes
5 #include "test_comm.h"
6 
7 // libMesh includes
8 #include <libmesh/parallel.h>
9 #include <libmesh/fuzzy_equals.h>
10 #include <libmesh/int_range.h>
11 
12 #include "libmesh_cppunit.h"
13 
14 #include <memory>
15 
16 #define NUMERICVECTORTEST \
17  CPPUNIT_TEST( testLocalize ); \
18  CPPUNIT_TEST( testLocalizeBase ); \
19  CPPUNIT_TEST( testLocalizeIndices ); \
20  CPPUNIT_TEST( testLocalizeIndicesBase ); \
21  CPPUNIT_TEST( testLocalizeToOne ); \
22  CPPUNIT_TEST( testLocalizeToOneBase ); \
23  CPPUNIT_TEST( testNorms ); \
24  CPPUNIT_TEST( testNormsBase ); \
25  CPPUNIT_TEST( testOperations ); \
26  CPPUNIT_TEST( testOperationsBase ); \
27  CPPUNIT_TEST( testWriteAndRead ); \
28  CPPUNIT_TEST( testWriteAndReadBase );
29 
30 // Tests to add manually, on subclasses supporting them
31 // CPPUNIT_TEST( testSubvectors );
32 // CPPUNIT_TEST( testSubvectorsBase );
33 
34 
35 template <class DerivedClass>
36 class NumericVectorTest : public CppUnit::TestCase {
37 
38 protected:
40 
41  std::string libmesh_suite_name;
42 
44 
45 public:
46  void setUp()
47  {
48  // By default we'll use the whole communicator in parallel;
49  // Serial-only NumericVector subclasses will need to override
50  // this and set something else first.
51  if (!my_comm)
53 
54  block_size = 10;
55 
56  // a different size on each processor.
58  static_cast<unsigned int>(my_comm->rank());
59 
60  global_size = 0;
61  for (libMesh::processor_id_type p=0; p<my_comm->size(); p++)
62  global_size += (block_size + static_cast<unsigned int>(p));
63  }
64 
65  void tearDown()
66  {}
67 
68  template <class Base, class Derived>
69  void Operations()
70  {
71  auto v_ptr = std::make_unique<Derived>(*my_comm, global_size, local_size);
72  Base & v = *v_ptr;
73 
75  first = v.first_local_index(),
76  last = v.last_local_index();
77 
78  for (libMesh::dof_id_type n=first; n != last; n++)
79  v.set (n, static_cast<libMesh::Number>(n+1));
80  v.close();
81 
82  auto v_clone = v.clone();
83  auto & vorig = *v_clone;
84 
85  CPPUNIT_ASSERT(relative_fuzzy_equals(v, vorig));
86 
87  v += v;
88 
89  CPPUNIT_ASSERT(!relative_fuzzy_equals(v, vorig));
90 
91  for (libMesh::dof_id_type n=first; n != last; n++)
92  LIBMESH_ASSERT_NUMBERS_EQUAL
93  (v(n), libMesh::Real(2*n+2),
95 
96  v *= v;
97 
98  for (libMesh::dof_id_type n=first; n != last; n++)
99  LIBMESH_ASSERT_NUMBERS_EQUAL
100  (v(n), libMesh::Real(4*n*n+8*n+4),
102 
103  v -= vorig;
104 
105  for (libMesh::dof_id_type n=first; n != last; n++)
106  LIBMESH_ASSERT_NUMBERS_EQUAL
107  (v(n), libMesh::Real(4*n*n+7*n+3),
109 
110  v /= vorig;
111 
112  for (libMesh::dof_id_type n=first; n != last; n++)
113  LIBMESH_ASSERT_NUMBERS_EQUAL
114  (v(n), libMesh::Real(4*n+3),
116 
117  v.add(1);
118  for (libMesh::dof_id_type n=first; n != last; n++)
119  LIBMESH_ASSERT_NUMBERS_EQUAL
120  (v(n), libMesh::Real(4*n+4),
122 
123  v.add(2, vorig);
124  for (libMesh::dof_id_type n=first; n != last; n++)
125  LIBMESH_ASSERT_NUMBERS_EQUAL
126  (v(n), libMesh::Real(6*n+6),
128 
129  v.scale(1/libMesh::Real(3));
130  for (libMesh::dof_id_type n=first; n != last; n++)
131  LIBMESH_ASSERT_NUMBERS_EQUAL
132  (v(n), libMesh::Real(2*n+2),
134 
135  v = 4;
136  for (libMesh::dof_id_type n=first; n != last; n++)
137  LIBMESH_ASSERT_NUMBERS_EQUAL
138  (v(n), libMesh::Real(4),
140 
141  v = vorig;
142  for (libMesh::dof_id_type n=first; n != last; n++)
143  LIBMESH_ASSERT_NUMBERS_EQUAL
144  (v(n), libMesh::Real(n+1),
146 
147  v.reciprocal();
148  for (libMesh::dof_id_type n=first; n != last; n++)
149  LIBMESH_ASSERT_NUMBERS_EQUAL
150  (v(n), 1/libMesh::Real(n+1),
152 
153  LIBMESH_ASSERT_NUMBERS_EQUAL
154  (v.dot(vorig), libMesh::Real(global_size),
156  }
157 
158 
159  template <class Base, class Derived>
160  void Subvectors()
161  {
162  auto v_ptr = std::make_unique<Derived>(*my_comm, global_size, local_size);
163  Base & v = *v_ptr;
164 
166  first = v.first_local_index(),
167  last = v.last_local_index();
168 
169  const unsigned int sub_local_size = block_size/2;
170  const unsigned int sub_global_size = sub_local_size * my_comm->size();
171 
172  for (auto supplying_global_rows : {false, true})
173  for (auto get_not_create : {false, true})
174  {
175  // We don't have such an option?
176  if (get_not_create && supplying_global_rows)
177  continue;
178 
179  for (libMesh::dof_id_type n=first; n != last; n++)
180  v.set (n, static_cast<libMesh::Number>(n+1));
181  v.close();
182 
183  std::unique_ptr<Base> s_ptr =
184  std::make_unique<Derived>(*my_comm, sub_global_size,
185  sub_local_size);
186 
188  sub_first = s_ptr->first_local_index(),
189  sub_last = s_ptr->last_local_index();
190 
191  CPPUNIT_ASSERT_EQUAL
192  (sub_first, libMesh::dof_id_type(sub_local_size *
193  my_comm->rank()));
194 
195  CPPUNIT_ASSERT_EQUAL
196  (sub_last, libMesh::dof_id_type(sub_local_size *
197  (my_comm->rank()+1)));
198 
199  std::vector<libMesh::dof_id_type> rows;
200  for (auto i : libMesh::make_range(sub_local_size))
201  rows.push_back(first+2*i);
202 
203  if (supplying_global_rows)
204  my_comm->allgather(rows);
205 
206  if (get_not_create)
207  {
209  v.get_subvector(rows).release();
210  s_ptr.reset(dynamic_cast<Base *>(subvec_ptr));
211  }
212  else
213  v.create_subvector(*s_ptr, rows, supplying_global_rows);
214 
215  Base & s = *s_ptr;
216 
217  for (auto i : libMesh::make_range(sub_local_size))
218  LIBMESH_ASSERT_NUMBERS_EQUAL
219  (s(sub_first+i), libMesh::Real(first+2*i+1),
221 
222  for (libMesh::dof_id_type n=sub_first; n != sub_last; n++)
223  s.set(n, (my_comm->rank()+1) * n);
224  s.close();
225 
226  // If we "get" a subvector then we're set up to "restore" it
227  // afterwards; if not then we're done.
228  if (!get_not_create)
229  continue;
230 
231  v.restore_subvector(std::move(s_ptr), rows);
232 
233  for (libMesh::dof_id_type n=first; n != last; n++)
234  {
235  const libMesh::dof_id_type offset = n - first;
236  if (offset < 2*sub_local_size && !(offset%2))
237  LIBMESH_ASSERT_NUMBERS_EQUAL
238  (v(n),
239  libMesh::Real((my_comm->rank()+1) *
240  ((offset/2) + sub_first)),
242  else
243  LIBMESH_ASSERT_NUMBERS_EQUAL
244  (v(n), libMesh::Real(n+1),
246  }
247  }
248  }
249 
250  template <class Base, class Derived>
252  {
253  auto v_ptr = std::make_unique<Derived>(*my_comm, global_size, local_size);
254  Base & v = *v_ptr;
255 
257  first = v.first_local_index(),
258  last = v.last_local_index();
259 
260  for (libMesh::dof_id_type n=first; n != last; n++)
261  v.set (n, static_cast<libMesh::Number>(n+1));
262  v.close();
263 
264  v.print_matlab(libmesh_suite_name+"_vector.m");
265 
266  // Let's make sure we don't have any race conditions; we have
267  // multiple SparseMatrix subclasses that might be trying to read
268  // and write the same file.
269 
271 
272 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
273  // We're not supporting complex reads quite yet
274  return;
275 #endif
276 
277  auto v_new_ptr = std::make_unique<Derived>(*my_comm, global_size, local_size);
278  Base & v_new = *v_new_ptr;
279 
280  v_new.read_matlab(libmesh_suite_name+"_vector.m");
281 
283 
284  CPPUNIT_ASSERT_EQUAL(v.l1_norm_diff(v_new), libMesh::Real(0));
285  }
286 
287  template <class Base, class Derived>
288  void Norms()
289  {
290  auto v_ptr = std::make_unique<Derived>(*my_comm, global_size, local_size);
291  Base & v = *v_ptr;
292 
294  first = v.first_local_index(),
295  last = v.last_local_index();
296 
297  for (libMesh::dof_id_type n=first; n != last; n++)
298  v.set (n, -static_cast<libMesh::Number>(n));
299  v.close();
300  for (libMesh::dof_id_type n=first; n != last; n++)
301  v.add (n, -static_cast<libMesh::Number>(n));
302  v.close();
303 
304  const libMesh::Real exact_l1 =
306  const libMesh::Real exact_l2 =
307  std::sqrt(libMesh::Real(global_size-1) *
308  (2*global_size) *
309  (2*global_size-1) / 3);
310  LIBMESH_ASSERT_NUMBERS_EQUAL(v.sum(), -exact_l1,
312  LIBMESH_ASSERT_FP_EQUAL(v.l1_norm(), exact_l1,
314  LIBMESH_ASSERT_FP_EQUAL(v.l2_norm(), exact_l2,
316  LIBMESH_ASSERT_FP_EQUAL(v.linfty_norm(), 2*(global_size-libMesh::Real(1)),
318 
319  auto u_ptr = std::make_unique<Derived>(*my_comm, global_size, local_size);
320  Base & u = *u_ptr;
321  for (libMesh::dof_id_type n=first; n != last; n++)
322  u.set (n, -static_cast<libMesh::Number>(n * n));
323  u.close();
324 
325  Derived diff_derived(*my_comm, global_size, local_size);
326  Base & diff = diff_derived;
327  diff = u;
328  diff -= v;
329  diff.close();
330 
331  // Use a relative tolerance here; the norms are O(1e5) when our
332  // processor count gets big enough, at which point O(1e-12) is
333  // testing for exact equality...
334  const auto diff_norm = diff.l2_norm();
335  const auto norm_diff = u.l2_norm_diff(v);
336  LIBMESH_ASSERT_FP_EQUAL(diff_norm, norm_diff,
337  (std::abs(diff_norm)+std::abs(norm_diff)) *
339  }
340 
341  template <class Base, class Derived>
342  void Localize(bool to_one=false)
343  {
344  const libMesh::processor_id_type root_pid = 0;
345 
346  {
347  auto v_ptr = std::make_unique<Derived>(*my_comm, global_size, local_size);
348  Base & v = *v_ptr;
349  std::vector<libMesh::Number> l(global_size);
350 
352  first = v.first_local_index(),
353  last = v.last_local_index();
354 
355  for (libMesh::dof_id_type n=first; n != last; n++)
356  v.set (n, static_cast<libMesh::Number>(n));
357  v.close();
358  for (libMesh::dof_id_type n=first; n != last; n++)
359  v.add (n, static_cast<libMesh::Number>(n));
360  v.close();
361 
362  if (!to_one)
363  v.localize(l);
364  else
365  v.localize_to_one(l,root_pid);
366 
367  if (!to_one || my_comm->rank() == root_pid)
368  // Yes I really mean v.size()
369  for (libMesh::dof_id_type i=0; i<v.size(); i++)
370  LIBMESH_ASSERT_NUMBERS_EQUAL
372 
373  for (libMesh::dof_id_type n=first; n != last; n++)
374  {
375  const auto value = static_cast<libMesh::Number>(n);
376  v.insert (&value, std::vector<libMesh::numeric_index_type>({n}));
377  }
378  v.close();
379 
380  if (!to_one)
381  v.localize(l);
382  else
383  v.localize_to_one(l,root_pid);
384 
385  if (!to_one || my_comm->rank() == root_pid)
386  // Yes I really mean v.size()
387  for (libMesh::dof_id_type i=0; i<v.size(); i++)
388  LIBMESH_ASSERT_NUMBERS_EQUAL
390  }
391  }
392 
393 
394  template <class Base, class Derived>
396  {
397  {
398  auto v_ptr = std::make_unique<Derived>(*my_comm, global_size, local_size);
399  Base & v = *v_ptr;
400 
401  // Let's try pulling the same number of entries from each processor
402  std::vector<libMesh::Number> values(block_size * my_comm->size());
403  std::vector<libMesh::dof_id_type> indices;
404  indices.reserve(block_size * my_comm->size());
405 
407  first = v.first_local_index(),
408  last = v.last_local_index();
409 
410  for (libMesh::dof_id_type n=first; n != last; n++)
411  v.set (n, static_cast<libMesh::Number>(n));
412  v.close();
413 
414  libMesh::dof_id_type end_index = 0;
415  for (libMesh::processor_id_type p=0; p<my_comm->size(); p++)
416  {
417  end_index += block_size + p;
418  for (unsigned int j = 0; j != block_size; ++j)
419  indices.push_back(end_index-j-1);
420  }
421 
422  v.localize(values, indices);
423 
424  end_index = 0;
425  for (libMesh::processor_id_type p=0; p<my_comm->size(); p++)
426  {
427  end_index += block_size + p;
428  for (unsigned int j = 0; j != block_size; ++j)
429  LIBMESH_ASSERT_NUMBERS_EQUAL
430  (values[p*block_size+j], libMesh::Real(end_index-j-1),
432  }
433  }
434  }
435 
437  {
438  LOG_UNIT_TEST;
439 
440  Localize<DerivedClass,DerivedClass>();
441  }
442 
444  {
445  LOG_UNIT_TEST;
446 
447  Localize<libMesh::NumericVector<libMesh::Number>,DerivedClass>();
448  }
449 
451  {
452  LOG_UNIT_TEST;
453 
454  Localize<DerivedClass,DerivedClass >(true);
455  }
456 
458  {
459  LOG_UNIT_TEST;
460 
461  Localize<libMesh::NumericVector<libMesh::Number>,DerivedClass>(true);
462  }
463 
465  {
466  LOG_UNIT_TEST;
467 
468  LocalizeIndices<DerivedClass,DerivedClass >();
469  }
470 
472  {
473  LOG_UNIT_TEST;
474 
475  LocalizeIndices<libMesh::NumericVector<libMesh::Number>,DerivedClass>();
476  }
477 
478  void testNorms()
479  {
480  LOG_UNIT_TEST;
481 
482  Norms<DerivedClass,DerivedClass >();
483  }
484 
486  {
487  LOG_UNIT_TEST;
488 
489  Norms<libMesh::NumericVector<libMesh::Number>,DerivedClass>();
490  }
491 
493  {
494  LOG_UNIT_TEST;
495 
496  Operations<DerivedClass,DerivedClass >();
497  }
498 
500  {
501  LOG_UNIT_TEST;
502 
503  Operations<libMesh::NumericVector<libMesh::Number>,DerivedClass>();
504  }
505 
507  {
508  LOG_UNIT_TEST;
509 
510  Subvectors<DerivedClass,DerivedClass >();
511  }
512 
514  {
515  LOG_UNIT_TEST;
516 
517  Subvectors<libMesh::NumericVector<libMesh::Number>,DerivedClass>();
518  }
519 
521  {
522  LOG_UNIT_TEST;
523 
524  WriteAndRead<DerivedClass,DerivedClass >();
525  }
526 
528  {
529  LOG_UNIT_TEST;
530 
531  WriteAndRead<libMesh::NumericVector<libMesh::Number>,DerivedClass>();
532  }
533 };
534 
535 #endif
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
static constexpr Real TOLERANCE
void barrier() const
processor_id_type rank() const
Provides a uniform interface to vector storage schemes for different linear algebra libraries...
Definition: vector_fe_ex5.C:44
uint8_t processor_id_type
Definition: id_types.h:104
void Localize(bool to_one=false)
processor_id_type size() const
libMesh::Parallel::Communicator * my_comm
virtual std::unique_ptr< NumericVector< T > > get_subvector(const std::vector< numeric_index_type > &)
Creates a view into this vector using the indices in rows.
unsigned int global_size
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static const bool value
Definition: xdr_io.C:55
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
bool relative_fuzzy_equals(const T &var1, const T2 &var2, const Real tol=TOLERANCE *TOLERANCE)
Function to check whether two variables are equal within a relative tolerance.
Definition: fuzzy_equals.h:78
std::string libmesh_suite_name
uint8_t dof_id_type
Definition: id_types.h:67