libMesh
Loading...
Searching...
No Matches
exodus_test.C
Go to the documentation of this file.
1#include "mesh_elem_test.h"
2
3#ifdef LIBMESH_HAVE_EXODUS_API
4
5#include "libmesh/cell_c0polyhedron.h"
6#include "libmesh/enum_to_string.h"
7#include "libmesh/exodusII_io.h"
8#include "libmesh/face_c0polygon.h"
9#include "libmesh/int_range.h"
10#include "libmesh/mesh_communication.h"
11#include "libmesh/mesh_generation.h"
12#include "libmesh/node.h"
13
14#include <memory>
15#include <string>
16#include <vector>
17
18using namespace libMesh;
19
20template <ElemType elem_type>
21class ExodusTest : public MeshPerElemTest<elem_type>
22{
23public:
25 {
26 LOG_UNIT_TEST;
27
28 Mesh input_mesh(*TestCommWorld);
29
30 ExodusII_IO exii(input_mesh);
31 if (input_mesh.processor_id() == 0)
32 exii.read("meshes/exodus_elements/read_exodus_" +
33 Utility::enum_to_string(elem_type) + ".e");
34
35 MeshCommunication().broadcast(input_mesh);
36 input_mesh.prepare_for_use();
37
38 CPPUNIT_ASSERT(this->meshes_equal_enough(input_mesh, true));
39 }
40
42 {
43 LOG_UNIT_TEST;
44
45 // This is a *buffered* write; we use scope to make sure the
46 // ExodusII_IO object gets destructed (and thus is guaranteed to
47 // finish writing and close the file) before we try to read what
48 // was written.
49 {
50 ExodusII_IO exii(*this->_mesh);
51
52 // We still default to 32-char names for backwards
53 // compatibility, but we're writing a mesh with extra-long names
54 // in it for testing, so we manually enable longer names.
55 exii.set_max_name_length(80);
56
57 exii.write("write_exodus_" +
58 Utility::enum_to_string(elem_type) + ".e");
59 }
60
61 Mesh input_mesh(*TestCommWorld);
62 ExodusII_IO exii_input(input_mesh);
63 if (input_mesh.processor_id() == 0)
64 exii_input.read("write_exodus_" +
65 Utility::enum_to_string(elem_type) + ".e");
66
67 MeshCommunication().broadcast(input_mesh);
68 input_mesh.prepare_for_use();
69
70 CPPUNIT_ASSERT(this->meshes_equal_enough(input_mesh, true));
71 }
72};
73
74#define EXODUSTEST \
75 CPPUNIT_TEST(test_read_gold); \
76 CPPUNIT_TEST(test_write);
77
78#define INSTANTIATE_EXODUSTEST(elemtype) \
79 class ExodusTest_##elemtype : public ExodusTest<elemtype> \
80 { \
81 public: \
82 ExodusTest_##elemtype() : ExodusTest<elemtype>() \
83 { \
84 if (unitlog->summarized_logs_enabled()) \
85 this->libmesh_suite_name = "ExodusTest"; \
86 else \
87 this->libmesh_suite_name = "ExodusTest_" #elemtype; \
88 } \
89 CPPUNIT_TEST_SUITE(ExodusTest_##elemtype); \
90 EXODUSTEST; \
91 CPPUNIT_TEST_SUITE_END(); \
92 }; \
93 \
94 CPPUNIT_TEST_SUITE_REGISTRATION(ExodusTest_##elemtype)
95
99
100#if LIBMESH_DIM > 1
105
112
113class ExodusC0PolygonTest : public CppUnit::TestCase
114{
115public:
117
119
121
123 {
124 const std::vector<Point> points =
125 { {0, 0}, {1, 0}, {1.5, 0.5}, {1, 1}, {0, 1} };
126
127 for (auto p : index_range(points))
128 mesh.add_point(points[p], /*id=*/p);
129
130 std::unique_ptr<Elem> polygon =
131 std::make_unique<C0Polygon>(cast_int<unsigned int>(points.size()));
132 for (auto i : index_range(points))
133 polygon->set_node(i, mesh.node_ptr(i));
134
135 polygon->set_id() = 0;
136 Elem *elem = mesh.add_elem(std::move(polygon));
137 elem->subdomain_id() = 1;
139 }
140
142 {
143 LOG_UNIT_TEST;
144
146 this->build_pentagon(mesh);
147
148 {
149 ExodusII_IO exii(mesh);
150 exii.write("write_exodus_C0POLYGON.e");
151 }
152
153 Mesh input_mesh(*TestCommWorld);
154 ExodusII_IO exii_input(input_mesh);
155 if (input_mesh.processor_id() == 0)
156 exii_input.read("write_exodus_C0POLYGON.e");
157
158 MeshCommunication().broadcast(input_mesh);
159 input_mesh.prepare_for_use();
160
161 CPPUNIT_ASSERT_EQUAL(cast_int<dof_id_type>(1), input_mesh.n_elem());
162
163 const Elem *elem = input_mesh.query_elem_ptr(0);
164 bool found_elem = elem;
165 input_mesh.comm().max(found_elem);
166 CPPUNIT_ASSERT(found_elem);
167
168 if (!elem)
169 return;
170
171 CPPUNIT_ASSERT_EQUAL(C0POLYGON, elem->type());
172 CPPUNIT_ASSERT_EQUAL(5u, elem->n_nodes());
173
174 for (auto i : make_range(5))
175 CPPUNIT_ASSERT_EQUAL(cast_int<dof_id_type>(i), elem->node_id(i));
176 }
177};
178
180#endif // LIBMESH_DIM > 1
181
182#if LIBMESH_DIM > 2
183class ExodusC0PolyhedronTest : public CppUnit::TestCase
184{
185public:
187
191
193
195 const std::string &filename)
196 {
197 {
198 ExodusII_IO exii(mesh);
199 exii.write(filename);
200 }
201
202 TestCommWorld->barrier();
203
204 Mesh header_mesh(*TestCommWorld);
205 ExodusII_IO exii(header_mesh);
206 return exii.read_header(filename);
207 }
208
210 const std::vector<Point> &points,
211 const std::vector<std::vector<unsigned int>> &nodes_on_side)
212 {
213 for (auto p : index_range(points))
214 mesh.add_point(points[p], /*id=*/p);
215
216 std::vector<std::shared_ptr<Polygon>> sides(nodes_on_side.size());
217 for (auto s : index_range(nodes_on_side))
218 {
219 const auto &nodes_on_s = nodes_on_side[s];
220 sides[s] = std::make_shared<C0Polygon>(nodes_on_s.size());
221 for (auto i : index_range(nodes_on_s))
222 sides[s]->set_node(i, mesh.node_ptr(nodes_on_s[i]));
223 }
224
225 std::unique_ptr<Node> mid_elem_node;
226 std::unique_ptr<Elem> polyhedron =
227 std::make_unique<C0Polyhedron>(sides, mid_elem_node);
228 if (mid_elem_node)
229 mesh.add_node(std::move(mid_elem_node));
230
231 polyhedron->set_id() = 0;
232 Elem *elem = mesh.add_elem(std::move(polyhedron));
233 elem->subdomain_id() = 1;
236 }
237
239 {
240 LOG_UNIT_TEST;
241
244 -1., 1.,
245 -1., 1.,
246 -1., 1.,
249
250 for (auto &elem : mesh.element_ptr_range())
251 elem->subdomain_id() = 1;
253
254 ExodusHeaderInfo header_info =
255 this->write_and_read_header(mesh, "write_exodus_C0POLYHEDRON.e");
256
257 CPPUNIT_ASSERT_EQUAL(header_info.num_dim, 3);
258 CPPUNIT_ASSERT_EQUAL(header_info.num_elem, 8);
259 CPPUNIT_ASSERT_EQUAL(header_info.num_elem_blk, 1);
260 CPPUNIT_ASSERT_EQUAL(header_info.num_face, 48);
261 CPPUNIT_ASSERT_EQUAL(header_info.num_face_blk, 1);
262 CPPUNIT_ASSERT_EQUAL(header_info.num_node_sets, 0);
263 CPPUNIT_ASSERT_EQUAL(header_info.num_side_sets, 0);
264 }
265
267 {
268 LOG_UNIT_TEST;
269
271 const std::vector<Point> points =
272 { { 0, -2, 0}, {-1, -1, 0}, {-1, 1, 0},
273 { 0, 2, 0}, { 1, 1, 0}, { 1, -1, 0},
274 { 0, -2, 1}, {-1, -1, 1}, {-1, 1, 1},
275 { 0, 2, 1}, { 1, 1, 1}, { 1, -1, 1} };
276
277 const std::vector<std::vector<unsigned int>> nodes_on_side =
278 { {0, 1, 2, 3, 4, 5},
279 {0, 1, 7, 6},
280 {1, 2, 8, 7},
281 {2, 3, 9, 8},
282 {3, 4, 10, 9},
283 {4, 5, 11, 10},
284 {5, 0, 6, 11},
285 {6, 7, 8, 9, 10, 11} };
286
287 this->build_c0polyhedron(mesh, points, nodes_on_side);
288
289 ExodusHeaderInfo header_info =
290 this->write_and_read_header(mesh, "write_exodus_C0POLYHEDRON_HEXPRISM.e");
291
292 CPPUNIT_ASSERT_EQUAL(header_info.num_dim, 3);
293 CPPUNIT_ASSERT_EQUAL(header_info.num_elem, 1);
294 CPPUNIT_ASSERT_EQUAL(header_info.num_elem_blk, 1);
295 CPPUNIT_ASSERT_EQUAL(header_info.num_face, 8);
296 CPPUNIT_ASSERT_EQUAL(header_info.num_face_blk, 1);
297 CPPUNIT_ASSERT_EQUAL(header_info.num_node_sets, 0);
298 CPPUNIT_ASSERT_EQUAL(header_info.num_side_sets, 0);
299 }
300
302 {
303 LOG_UNIT_TEST;
304
306 const std::vector<Point> points =
307 { { 0, -2, 0}, {-1, -1, 0}, {-1, 1, 0},
308 { 0, 2, 0}, { 1, 1, 0}, { 1, -1, 0},
309 { 0, -2, 1}, {-1, -1, 1}, {-1, 1, 1},
310 { 0, 2, 1}, { 1, 1, 1}, { 1, -1, 1} };
311
312 const std::vector<std::vector<unsigned int>> nodes_on_side =
313 { {0, 1, 2, 3, 4, 5},
314 {0, 1, 7, 6},
315 {1, 2, 8, 7},
316 {2, 3, 9, 8},
317 {3, 4, 10, 9},
318 {4, 5, 11, 10},
319 {5, 0, 6, 11},
320 {6, 7, 8, 9, 10, 11} };
321
322 this->build_c0polyhedron(mesh, points, nodes_on_side);
323
324 std::vector<std::vector<dof_id_type>> expected_nodes_on_side;
325 const Elem *output_elem = mesh.query_elem_ptr(0);
326 const bool have_output_elem = output_elem;
327 bool found_output_elem = have_output_elem;
328 mesh.comm().max(found_output_elem);
329 CPPUNIT_ASSERT(found_output_elem);
330
331 if (output_elem)
332 {
333 expected_nodes_on_side.reserve(output_elem->n_sides());
334 for (auto s : output_elem->side_index_range())
335 {
336 expected_nodes_on_side.emplace_back();
337 for (const auto n : output_elem->nodes_on_side(s))
338 expected_nodes_on_side.back().push_back(output_elem->node_id(n));
339 }
340 }
341
342 {
343 ExodusII_IO exii(mesh);
344 exii.write("write_exodus_C0POLYHEDRON_HEXPRISM_READ.e");
345 }
346
347 Mesh input_mesh(*TestCommWorld);
348 ExodusII_IO exii_input(input_mesh);
349 if (input_mesh.processor_id() == 0)
350 exii_input.read("write_exodus_C0POLYHEDRON_HEXPRISM_READ.e");
351
352 MeshCommunication().broadcast(input_mesh);
353 input_mesh.prepare_for_use();
354
355 CPPUNIT_ASSERT_EQUAL(cast_int<dof_id_type>(1), input_mesh.n_elem());
356
357 const Elem *elem = input_mesh.query_elem_ptr(0);
358 bool found_elem = elem;
359 input_mesh.comm().max(found_elem);
360 CPPUNIT_ASSERT(found_elem);
361
362 const bool can_compare = have_output_elem && elem;
363 bool found_comparable_elem = can_compare;
364 input_mesh.comm().max(found_comparable_elem);
365 CPPUNIT_ASSERT(found_comparable_elem);
366
367 if (!can_compare)
368 return;
369
370 CPPUNIT_ASSERT_EQUAL(C0POLYHEDRON, elem->type());
371 CPPUNIT_ASSERT_EQUAL(12u, elem->n_vertices());
372 CPPUNIT_ASSERT_EQUAL(8u, elem->n_sides());
373
374 for (auto s : index_range(expected_nodes_on_side))
375 {
376 const auto side_nodes = elem->nodes_on_side(s);
377 CPPUNIT_ASSERT_EQUAL(expected_nodes_on_side[s].size(), side_nodes.size());
378 for (auto n : index_range(expected_nodes_on_side[s]))
379 CPPUNIT_ASSERT_EQUAL(expected_nodes_on_side[s][n],
380 elem->node_id(side_nodes[n]));
381 }
382 }
383};
384
386
390
394
400
401// These tests use PointLocator, which uses contains_point(), which
402// uses inverse_map(), which doesn't play nicely on Pyramids unless we
403// have exceptions support
404#ifdef LIBMESH_ENABLE_EXCEPTIONS
409#endif
410#endif // LIBMESH_DIM > 2
411
412#endif // LIBMESH_HAVE_EXODUS_API
LIBMESH_CPPUNIT_TEST_SUITE(ExodusC0PolygonTest)
void build_pentagon(Mesh &mesh)
CPPUNIT_TEST(test_write_and_read_pentagon)
void test_write_and_read_pentagon()
CPPUNIT_TEST(test_write_and_read_hexagonal_prism)
CPPUNIT_TEST(test_write_hexagonal_prism_header)
void test_write_hexagonal_prism_header()
void test_write_and_read_hexagonal_prism()
void build_c0polyhedron(Mesh &mesh, const std::vector< Point > &points, const std::vector< std::vector< unsigned int > > &nodes_on_side)
ExodusHeaderInfo write_and_read_header(Mesh &mesh, const std::string &filename)
CPPUNIT_TEST(test_write_cube_header)
LIBMESH_CPPUNIT_TEST_SUITE(ExodusC0PolyhedronTest)
void test_write()
Definition exodus_test.C:41
void test_read_gold()
Definition exodus_test.C:24
bool meshes_equal_enough(Mesh &other_mesh, bool double_precision)
std::unique_ptr< Mesh > _mesh
Definition elem_test.h:26
void max(const T &r, T &o, Request &req) const
void clear()
Clears the underlying data structures and restores the object to a pristine state with no data stored...
virtual dof_id_type n_elem() const override final
virtual const Elem * query_elem_ptr(const dof_id_type i) const override final
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
virtual unsigned int n_nodes() const =0
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
subdomain_id_type subdomain_id() const
Definition elem.h:2591
virtual ElemType type() const =0
virtual unsigned int n_sides() const =0
dof_id_type node_id(const unsigned int i) const
Definition elem.h:2484
IntRange< unsigned short > side_index_range() const
Definition elem.h:2727
This class is used as both an external data structure for passing around Exodus file header informati...
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition exodusII_io.h:53
void set_max_name_length(unsigned int max_length)
For backwards compatibility, libMesh currently truncates names in ExodusII output to the old default ...
virtual void write(const std::string &fname) override
This method implements writing a mesh to a specified file.
ExodusHeaderInfo read_header(const std::string &name)
Read only the header information, instead of the entire mesh.
virtual void read(const std::string &name) override
This method implements reading a mesh from a specified file.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition mesh_base.h:170
virtual const Node * node_ptr(const dof_id_type i) const =0
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 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.
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.
This is the MeshCommunication class.
void broadcast(MeshBase &) const
This method takes a mesh (which is assumed to reside on processor 0) and broadcasts it to all the oth...
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
Communicator * TestCommWorld
CPPUNIT_TEST_SUITE_REGISTRATION(ExodusC0PolygonTest)
INSTANTIATE_EXODUSTEST(EDGE2)
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.
std::string enum_to_string(const T e)
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
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