libMesh
Loading...
Searching...
No Matches
checkpoint.C
Go to the documentation of this file.
1#include "libmesh/cell_c0polyhedron.h"
2#include "libmesh/checkpoint_io.h"
3#include "libmesh/distributed_mesh.h"
4#include "libmesh/face_c0polygon.h"
5#include "libmesh/int_range.h"
6#include "libmesh/mesh.h"
7#include "libmesh/mesh_generation.h"
8#include "libmesh/node.h"
9#include "libmesh/parallel.h"
10#include "libmesh/partitioner.h"
11#include "libmesh/replicated_mesh.h"
12
13#include "test_comm.h"
14#include "libmesh_cppunit.h"
15
16
17using namespace libMesh;
18
19class CheckpointIOTest : public CppUnit::TestCase {
23public:
25
26#if LIBMESH_DIM > 1
37#if LIBMESH_DIM > 2
40#endif
41#endif
42
44
45protected:
46
47public:
48 void setUp()
49 {
50 }
51
52 void tearDown()
53 {
54 }
55
56 // Test that we can write multiple checkpoint files from a single processor.
57 template <typename MeshA, typename MeshB>
58 void testSplitter(bool binary, bool using_distmesh, bool skip_partition = false)
59 {
60 // The CheckpointIO-based splitter requires XDR.
61#ifdef LIBMESH_HAVE_XDR
62
63 // In this test, we partition the mesh into n_procs parts. Don't
64 // try to partition a DistributedMesh into more parts than we have
65 // processors, though.
66 const unsigned int n_procs = using_distmesh ?
67 std::min(static_cast<processor_id_type>(2), TestCommWorld->size()) :
68 2;
69
70 // The number of elements in the original mesh. For verification
71 // later.
72 dof_id_type original_n_elem = 0;
73
74 const std::string filename =
75 std::string("checkpoint_splitter.cp") + (binary ? "r" : "a");
76
77 {
78 MeshA mesh(*TestCommWorld);
79
81 4, 4,
82 0., 1.,
83 0., 1.,
84 QUAD4);
85
86 // Store the number of elements that were in the original mesh.
87 original_n_elem = mesh.n_elem();
88
89 // Partition the mesh into n_procs pieces
90 mesh.partition(n_procs);
91
92 // Write out checkpoint files for each piece. Since on a
93 // ReplicatedMesh we might have more pieces than we do
94 // processors, some processors may have to write out more than
95 // one piece.
96 CheckpointIO cpr(mesh);
97 cpr.current_processor_ids().clear();
98 for (processor_id_type pid = mesh.processor_id(); pid < n_procs; pid += mesh.n_processors())
99 cpr.current_processor_ids().push_back(pid);
100 cpr.current_n_processors() = n_procs;
101 cpr.binary() = binary;
102 cpr.parallel() = true;
103 cpr.write(filename);
104 }
105
106 TestCommWorld->barrier();
107
108 // Test that we can read in the files we wrote and sum up to the
109 // same total number of elements.
110 {
111 MeshB mesh(*TestCommWorld);
112 if (skip_partition)
114
115 CheckpointIO cpr(mesh);
116 cpr.current_n_processors() = n_procs;
117 cpr.binary() = binary;
118 cpr.read(filename);
119
120 // If we decided to skip partitioning, then we shouldn't be
121 // waiting for a partition() call to get our n_partitions()
122 // cache in order
123 if (skip_partition)
124 CPPUNIT_ASSERT_EQUAL(mesh.n_partitions(), n_procs);
125
126 std::size_t read_in_elements = 0;
127
128 for (unsigned pid=mesh.processor_id(); pid<n_procs; pid += mesh.n_processors())
129 {
130 read_in_elements += std::distance(mesh.pid_elements_begin(pid),
131 mesh.pid_elements_end(pid));
132 }
133 mesh.comm().sum(read_in_elements);
134
135 // Verify that we read in exactly as many elements as we started with.
136 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(read_in_elements), original_n_elem);
137 }
138#endif // LIBMESH_HAVE_XDR
139 }
140
141 void testC0PolygonCheckpoint(bool binary)
142 {
143#ifdef LIBMESH_HAVE_XDR
144 // Parallel element packing does not yet support runtime topology,
145 // so exercise serial CheckpointIO independently on rank 0.
146 if (TestCommWorld->rank() != 0)
147 return;
148
149 Parallel::Communicator comm_self;
150 const std::string filename =
151 std::string("checkpoint_c0polygon.cp") + (binary ? "r" : "a");
152 const std::vector<Point> points =
153 {{0., 0.}, {1., 0.}, {1.5, 0.5}, {1., 1.}, {0., 1.}};
154
155 {
156 Mesh mesh(comm_self, 2);
157 mesh.allow_renumbering(false);
158
159 auto polygon =
160 std::make_unique<C0Polygon>(cast_int<unsigned int>(points.size()));
161 polygon->set_id() = 0;
162 for (auto n : index_range(points))
163 polygon->set_node(n, mesh.add_point(points[n], n));
164
165 mesh.add_elem(std::move(polygon));
167
168 CheckpointIO checkpoint(mesh, binary);
169 checkpoint.write(filename);
170 }
171
172 {
173 Mesh mesh(comm_self);
174 CheckpointIO checkpoint(mesh, binary);
175 checkpoint.read(filename);
176
177 CPPUNIT_ASSERT_EQUAL(dof_id_type(1), mesh.n_elem());
178 CPPUNIT_ASSERT_EQUAL(dof_id_type(5), mesh.n_nodes());
179 CPPUNIT_ASSERT_EQUAL(2u, static_cast<unsigned int>(mesh.mesh_dimension()));
180
181 const Elem * elem = mesh.query_elem_ptr(0);
182 bool found_elem = elem;
183 mesh.comm().max(found_elem);
184 CPPUNIT_ASSERT(found_elem);
185
186 if (elem)
187 {
188 CPPUNIT_ASSERT_EQUAL(C0POLYGON, elem->type());
189 CPPUNIT_ASSERT_EQUAL(5u, elem->n_nodes());
190 CPPUNIT_ASSERT_EQUAL(5u, elem->n_vertices());
191 CPPUNIT_ASSERT_EQUAL(5u, elem->n_sides());
192 CPPUNIT_ASSERT_EQUAL(5u, elem->n_edges());
193
194 for (auto n : index_range(points))
195 {
196 CPPUNIT_ASSERT_EQUAL(cast_int<dof_id_type>(n), elem->node_id(n));
197 CPPUNIT_ASSERT_EQUAL(points[n], elem->point(n));
198
199 const auto side_nodes = elem->nodes_on_side(n);
200 CPPUNIT_ASSERT_EQUAL(std::size_t(2), side_nodes.size());
201 CPPUNIT_ASSERT_EQUAL(cast_int<unsigned int>(n), side_nodes[0]);
202 CPPUNIT_ASSERT_EQUAL
203 (cast_int<unsigned int>((n + 1) % points.size()), side_nodes[1]);
204 }
205 }
206 }
207
208 CheckpointIO::cleanup(filename, 1);
209#endif // LIBMESH_HAVE_XDR
210 }
211
212#if LIBMESH_DIM > 2
214 {
215#ifdef LIBMESH_HAVE_XDR
216 // Parallel element packing does not yet support runtime topology,
217 // so exercise serial CheckpointIO independently on rank 0.
218 if (TestCommWorld->rank() != 0)
219 return;
220
221 Parallel::Communicator comm_self;
222 const std::string filename =
223 std::string("checkpoint_c0polyhedron.cp") + (binary ? "r" : "a");
224 const std::vector<Point> points =
225 {{0., -2., 0.}, {-1., -1., 0.}, {-1., 1., 0.},
226 {0., 2., 0.}, {1., 1., 0.}, {1., -1., 0.},
227 {0., -2., 1.}, {-1., -1., 1.}, {-1., 1., 1.},
228 {0., 2., 1.}, {1., 1., 1.}, {1., -1., 1.}};
229 const std::vector<std::vector<unsigned int>> nodes_on_sides =
230 {{0, 1, 2, 3, 4, 5},
231 {0, 1, 7, 6},
232 {1, 2, 8, 7},
233 {2, 3, 9, 8},
234 {3, 4, 10, 9},
235 {4, 5, 11, 10},
236 {5, 0, 6, 11},
237 {6, 7, 8, 9, 10, 11}};
238
239 {
240 Mesh mesh(comm_self, 3);
241 mesh.allow_renumbering(false);
242 for (auto n : index_range(points))
243 mesh.add_point(points[n], n);
244
245 std::vector<std::shared_ptr<Polygon>> sides(nodes_on_sides.size());
246 for (auto s : index_range(nodes_on_sides))
247 {
248 const auto & side_nodes = nodes_on_sides[s];
249 auto side =
250 std::make_shared<C0Polygon>
251 (cast_int<unsigned int>(side_nodes.size()));
252 for (auto n : index_range(side_nodes))
253 side->set_node(n, mesh.node_ptr(side_nodes[n]));
254 sides[s] = std::move(side);
255 }
256
257 std::unique_ptr<Node> mid_elem_node;
258 auto polyhedron =
259 std::make_unique<C0Polyhedron>(sides, mid_elem_node);
260 CPPUNIT_ASSERT(mid_elem_node);
261
262 // Explicit id so DistributedMesh matches ReplicatedMesh
263 mid_elem_node->set_id(points.size());
264
265 mesh.add_node(std::move(mid_elem_node));
266 polyhedron->set_id() = 0;
267 mesh.add_elem(std::move(polyhedron));
269
270 CheckpointIO checkpoint(mesh, binary);
271 checkpoint.write(filename);
272 }
273
274 {
275 Mesh mesh(comm_self);
276 CheckpointIO checkpoint(mesh, binary);
277 checkpoint.read(filename);
278
279 CPPUNIT_ASSERT_EQUAL(dof_id_type(1), mesh.n_elem());
280 CPPUNIT_ASSERT_EQUAL(dof_id_type(13), mesh.n_nodes());
281 CPPUNIT_ASSERT_EQUAL(3u, static_cast<unsigned int>(mesh.mesh_dimension()));
282
283 const Elem * elem = mesh.query_elem_ptr(0);
284 bool found_elem = elem;
285 mesh.comm().max(found_elem);
286 CPPUNIT_ASSERT(found_elem);
287
288 if (elem)
289 {
290 CPPUNIT_ASSERT_EQUAL(C0POLYHEDRON, elem->type());
291 CPPUNIT_ASSERT_EQUAL(12u, elem->n_vertices());
292 CPPUNIT_ASSERT_EQUAL(13u, elem->n_nodes());
293 CPPUNIT_ASSERT_EQUAL(8u, elem->n_sides());
294 CPPUNIT_ASSERT_EQUAL(18u, elem->n_edges());
295 CPPUNIT_ASSERT_EQUAL(dof_id_type(12),
296 elem->node_id(elem->n_vertices()));
297
298 for (auto s : index_range(nodes_on_sides))
299 {
300 const auto side_nodes = elem->nodes_on_side(s);
301 CPPUNIT_ASSERT_EQUAL(nodes_on_sides[s].size(), side_nodes.size());
302 for (auto n : index_range(side_nodes))
303 CPPUNIT_ASSERT_EQUAL
304 (cast_int<dof_id_type>(nodes_on_sides[s][n]),
305 elem->node_id(side_nodes[n]));
306 }
307 }
308 }
309
310 CheckpointIO::cleanup(filename, 1);
311#endif // LIBMESH_HAVE_XDR
312 }
313#endif
314
316 {
317 LOG_UNIT_TEST;
318
319 testSplitter<DistributedMesh, ReplicatedMesh>(false, true);
320 }
321
323 {
324 LOG_UNIT_TEST;
325
326 testSplitter<DistributedMesh, ReplicatedMesh>(true, true);
327 }
328
330 {
331 LOG_UNIT_TEST;
332
333 testSplitter<ReplicatedMesh, DistributedMesh>(false, true);
334 }
335
337 {
338 LOG_UNIT_TEST;
339
340 testSplitter<ReplicatedMesh, DistributedMesh>(true, true);
341 }
342
344 {
345 LOG_UNIT_TEST;
346
347 testSplitter<ReplicatedMesh, ReplicatedMesh>(false, false);
348 }
349
351 {
352 LOG_UNIT_TEST;
353
354 testSplitter<ReplicatedMesh, ReplicatedMesh>(true, false);
355 }
356
358 {
359 LOG_UNIT_TEST;
360
361 testSplitter<DistributedMesh, DistributedMesh>(false, true);
362 }
363
365 {
366 LOG_UNIT_TEST;
367
368 testSplitter<DistributedMesh, DistributedMesh>(true, true);
369 }
370
372 {
373 LOG_UNIT_TEST;
374
376 }
377
379 {
380 LOG_UNIT_TEST;
381
383 }
384
385#if LIBMESH_DIM > 2
387 {
388 LOG_UNIT_TEST;
389
391 }
392
394 {
395 LOG_UNIT_TEST;
396
398 }
399#endif
400
402 {
403 LOG_UNIT_TEST;
404
405 testSplitter<DistributedMesh, DistributedMesh>(false, true, true);
406 }
407
408
409};
410
CPPUNIT_TEST_SUITE_REGISTRATION(CheckpointIOTest)
void testBinaryDistDistSplitter()
Definition checkpoint.C:364
CPPUNIT_TEST(testBinaryC0Polygon)
CPPUNIT_TEST(testAsciiRepRepSplitter)
void testSplitter(bool binary, bool using_distmesh, bool skip_partition=false)
Definition checkpoint.C:58
void testBinaryRepDistSplitter()
Definition checkpoint.C:336
void testC0PolyhedronCheckpoint(bool binary)
Definition checkpoint.C:213
void testAsciiRepDistSplitter()
Definition checkpoint.C:329
void testBinaryC0Polygon()
Definition checkpoint.C:378
CPPUNIT_TEST(testAsciiDistRepSplitter)
CPPUNIT_TEST(testBinaryDistRepSplitter)
LIBMESH_CPPUNIT_TEST_SUITE(CheckpointIOTest)
This test verifies that we can write files with the CheckpointIO object.
void testAsciiDistDistSplitter()
Definition checkpoint.C:357
void testBinaryRepRepSplitter()
Definition checkpoint.C:350
void testC0PolygonCheckpoint(bool binary)
Definition checkpoint.C:141
void testAsciiC0Polygon()
Definition checkpoint.C:371
void testAsciiRepRepSplitter()
Definition checkpoint.C:343
void testAsciiC0Polyhedron()
Definition checkpoint.C:386
CPPUNIT_TEST(testBinaryRepDistSplitter)
void testAsciiDistRepSplitter()
Definition checkpoint.C:315
CPPUNIT_TEST(testAsciiC0Polygon)
CPPUNIT_TEST(testBinaryC0Polyhedron)
CPPUNIT_TEST(testBinaryRepRepSplitter)
void testBinaryC0Polyhedron()
Definition checkpoint.C:393
void testBinaryDistRepSplitter()
Definition checkpoint.C:322
CPPUNIT_TEST(testAsciiDistDistSplitter)
CPPUNIT_TEST(testBinaryDistDistSplitter)
CPPUNIT_TEST(testAsciiC0Polyhedron)
CPPUNIT_TEST(testAsciiRepDistSplitter)
void testAsciiDistDistSplitterCache()
Definition checkpoint.C:401
void max(const T &r, T &o, Request &req) const
The CheckpointIO class can be used to write simplified restart files that can be used to restart simu...
const std::vector< processor_id_type > & current_processor_ids() const
Get/Set the processor id or processor ids to use.
virtual void read(const std::string &input_name) override
This method implements reading a mesh from a specified file.
bool binary() const
Get/Set the flag indicating if we should read/write binary.
const processor_id_type & current_n_processors() const
Get/Set the n_processors to use.
static void cleanup(const std::string &input_name, processor_id_type n_procs)
Used to remove a checkpoint directory and its corresponding files.
virtual void write(const std::string &name) override
This method implements writing a mesh to a specified file.
bool parallel() const
Get/Set the flag indicating if we should read/write binary.
dof_id_type & set_id()
Definition dof_object.h:827
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual unsigned int n_vertices() const =0
const Point & point(const unsigned int i) const
Definition elem.h:2462
virtual unsigned int n_nodes() const =0
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
virtual ElemType type() const =0
virtual unsigned int n_edges() const =0
virtual unsigned int n_sides() const =0
dof_id_type node_id(const unsigned int i) const
Definition elem.h:2484
virtual const Node * node_ptr(const dof_id_type i) const =0
unsigned int mesh_dimension() const
Definition mesh_base.C:430
virtual dof_id_type n_elem() const =0
void allow_renumbering(bool allow)
If false is passed in then this mesh will no longer be renumbered when being prepared for use.
Definition mesh_base.h:1355
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly created (or read) mesh for use.
Definition mesh_base.C:824
virtual dof_id_type n_nodes() const =0
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
unsigned int n_partitions() const
Definition mesh_base.h:1526
virtual Node * add_node(Node *n)=0
Add Node n to the end of the vertex array.
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
virtual void partition(const unsigned int n_parts)
Call the default partitioner (currently metis_partition()).
Definition mesh_base.C:1769
void skip_partitioning(bool skip)
If true is passed in then nothing on this mesh will be (re)partitioned.
Definition mesh_base.h:1429
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition mesh.h:51
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
Communicator * TestCommWorld
MeshBase & mesh
void build_square(UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 2D meshes.
The libMesh namespace provides an interface to certain functionality in the library.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
uint8_t dof_id_type
Definition id_types.h:67
uint8_t processor_id_type
Definition id_types.h:104