libMesh
Loading...
Searching...
No Matches
partitioner_test.h
Go to the documentation of this file.
1#ifndef PARTITIONER_TEST_H
2#define PARTITIONER_TEST_H
3
4#include <libmesh/distributed_mesh.h>
5#include <libmesh/elem.h>
6#include <libmesh/partitioner.h>
7#include <libmesh/replicated_mesh.h>
8#include <libmesh/mesh_generation.h>
9
10#include "test_comm.h"
11#include "libmesh_cppunit.h"
12
13
14#if LIBMESH_DIM > 2
15#define PARTITIONERTEST \
16 CPPUNIT_TEST( testBuild ); \
17 CPPUNIT_TEST( testPartitionEmpty ); \
18 CPPUNIT_TEST( testPartition1 ); \
19 CPPUNIT_TEST( testPartition2 ); \
20 CPPUNIT_TEST( testPartitionNProc );
21#else
22#define PARTITIONERTEST
23#endif
24
25using namespace libMesh;
26
27template <typename PartitionerSubclass, typename MeshClass>
28class PartitionerTest : public CppUnit::TestCase {
29protected:
30
31 std::string libmesh_suite_name;
32
33public:
34 void setUp()
35 {}
36
37 void tearDown()
38 {}
39
40 void testBuild()
41 {
42 PartitionerSubclass myclass;
43
44 PartitionerType type = myclass.type();
45
46 auto new_build = Partitioner::build(type);
47
48 CPPUNIT_ASSERT_EQUAL(new_build->type(), type);
49 }
50
52 {
53 MeshClass mesh(*TestCommWorld);
54
56 3, 3, 3,
57 0., 1., 0., 1., 0., 1.,
58 HEX8);
59
60 // FIXME: Splitting meshes into more than n_proc parts currently
61 // requires us to start with a mesh entirely assigned to proc 0
62 PartitionerSubclass newpart;
63 newpart.partition(mesh, 1);
64
65 for (auto elem : mesh.element_ptr_range())
66 CPPUNIT_ASSERT_EQUAL(elem->processor_id(), processor_id_type(0));
67
68 for (auto node : mesh.node_ptr_range())
69 CPPUNIT_ASSERT_EQUAL(node->processor_id(), processor_id_type(0));
70
71 // But then we can manually partition, into at most many parts as
72 // were requested.
73 newpart.partition(mesh, n_parts);
74
75 // We expect the partitioner not to suck - every processor
76 // rank (up to n_elem()) ought to have at least one element on it.
77 const processor_id_type n_nonempty =
78 std::min(n_parts, processor_id_type(3*3*3));
79
80 // Let's make sure we can see them all even on a DistributedMesh
82
83 processor_id_type nonempty_procs = 0;
84 for (processor_id_type p=0; p != n_nonempty; ++p)
85 {
86 const std::size_t n_elem_on_p =
87 std::distance(mesh.pid_elements_begin(p),
88 mesh.pid_elements_end(p));
89 if (n_elem_on_p)
90 nonempty_procs++;
91 }
92
93 // Unfortunately, it turns out that our partitioners *do* suck:
94 //
95 // * Metis and ParMetis can't reliably give us more than
96 // 13 non-empty ranks on the above 27 element mesh.
97 //
98 // * Our SFC partitioners are suboptimal with 8 or more ranks for
99 // only 27 elements: the smallest integer block size for 27/8
100 // elements-per-rank that won't overflow is 4, but that only fills
101 // 7 ranks, because we don't equidistribute the underflow.
102 CPPUNIT_ASSERT(nonempty_procs >= n_nonempty ||
103 nonempty_procs >= 13 ||
104 (nonempty_procs >= 7 &&
105 n_nonempty == 8) ||
106 (nonempty_procs >= 9 &&
107 n_nonempty >= 10));
108 }
109
111 {
112 LOG_UNIT_TEST;
113
114 MeshClass mesh(*TestCommWorld);
115 PartitionerSubclass newpart;
116
117 // With a 0 element mesh this should just give us 0 subpartitions
118 // regardless of n_procs
119 newpart.partition(mesh, TestCommWorld->size());
120 }
121
123 {
124 LOG_UNIT_TEST;
125
126 this->testPartition(1);
127 }
128
130 {
131 LOG_UNIT_TEST;
132
133 this->testPartition(2);
134 }
135
137 {
138 LOG_UNIT_TEST;
139
140 this->testPartition(TestCommWorld->size());
141 }
142};
143
144#define INSTANTIATE_PARTITIONER_TEST(partitionersubclass, meshclass) \
145 class PartitionerTest_##partitionersubclass##_##meshclass : \
146 public PartitionerTest<partitionersubclass, meshclass> { \
147 public: \
148 PartitionerTest_##partitionersubclass##_##meshclass() : \
149 PartitionerTest<partitionersubclass,meshclass>() { \
150 if (unitlog->summarized_logs_enabled()) \
151 this->libmesh_suite_name = "PartitionerTest"; \
152 else \
153 this->libmesh_suite_name = "PartitionerTest_" #partitionersubclass "_" #meshclass; \
154 } \
155 CPPUNIT_TEST_SUITE( PartitionerTest_##partitionersubclass##_##meshclass); \
156 PARTITIONERTEST \
157 CPPUNIT_TEST_SUITE_END(); \
158 }; \
159 \
160 CPPUNIT_TEST_SUITE_REGISTRATION( PartitionerTest_##partitionersubclass##_##meshclass );
161
162#endif
void testPartition(processor_id_type n_parts)
std::string libmesh_suite_name
virtual void allgather()
Gathers all elements and nodes of the mesh onto every processor.
Definition mesh_base.h:386
static std::unique_ptr< Partitioner > build(const PartitionerType solver_package)
Builds a Partitioner of the type specified by partitioner_type.
Communicator * TestCommWorld
MeshBase & mesh
void build_cube(UnstructuredMesh &mesh, const unsigned int nx=0, const unsigned int ny=0, const unsigned int nz=0, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const Real zmin=0., const Real zmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
Builds a (elements) cube.
The libMesh namespace provides an interface to certain functionality in the library.
PartitionerType
Defines an enum for mesh partitioner types.
uint8_t processor_id_type
Definition id_types.h:104