libMesh
Loading...
Searching...
No Matches
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
35template <class DerivedClass>
36class NumericVectorTest : public CppUnit::TestCase {
37
38protected:
40
41 std::string libmesh_suite_name;
42
44
45public:
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>
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>
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
270 TestCommWorld->barrier();
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
282 TestCommWorld->barrier();
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
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
std::string libmesh_suite_name
void Localize(bool to_one=false)
libMesh::Parallel::Communicator * my_comm
processor_id_type size() const
processor_id_type rank() const
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
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.
Communicator * TestCommWorld
static constexpr Real TOLERANCE
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
uint8_t processor_id_type
Definition id_types.h:104
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