3#ifdef LIBMESH_HAVE_EXODUS_API
5#include "libmesh/cell_c0polyhedron.h"
6#include "libmesh/distributed_mesh.h"
7#include "libmesh/enum_to_string.h"
8#include "libmesh/exodusII_io.h"
9#include "libmesh/exodusII_io_helper.h"
10#include "libmesh/face_c0polygon.h"
11#include "libmesh/int_range.h"
12#include "libmesh/mesh_communication.h"
13#include "libmesh/mesh_generation.h"
14#include "libmesh/node.h"
15#include "libmesh/replicated_mesh.h"
24template <ElemType elem_type>
36 exii.
read(
"meshes/exodus_elements/read_exodus_" +
61 exii.
write(
"write_exodus_" +
68 exii_input.
read(
"write_exodus_" +
79 CPPUNIT_TEST(test_read_gold); \
80 CPPUNIT_TEST(test_write);
82#define INSTANTIATE_EXODUSTEST(elemtype) \
83 class ExodusTest_##elemtype : public ExodusTest<elemtype> \
86 ExodusTest_##elemtype() : ExodusTest<elemtype>() \
88 if (unitlog->summarized_logs_enabled()) \
89 this->libmesh_suite_name = "ExodusTest"; \
91 this->libmesh_suite_name = "ExodusTest_" #elemtype; \
93 CPPUNIT_TEST_SUITE(ExodusTest_##elemtype); \
95 CPPUNIT_TEST_SUITE_END(); \
98 CPPUNIT_TEST_SUITE_REGISTRATION(ExodusTest_##elemtype)
128 const std::vector<Point> points =
129 { {0, 0}, {1, 0}, {1.5, 0.5}, {1, 1}, {0, 1} };
134 std::unique_ptr<Elem> polygon =
135 std::make_unique<C0Polygon>(cast_int<unsigned int>(points.size()));
139 polygon->set_id() = 0;
154 exii.
write(
"write_exodus_C0POLYGON.e");
160 exii_input.
read(
"write_exodus_C0POLYGON.e");
165 CPPUNIT_ASSERT_EQUAL(cast_int<dof_id_type>(1), input_mesh.
n_elem());
168 bool found_elem = elem;
169 input_mesh.
comm().
max(found_elem);
170 CPPUNIT_ASSERT(found_elem);
176 CPPUNIT_ASSERT_EQUAL(5u, elem->
n_nodes());
179 CPPUNIT_ASSERT_EQUAL(cast_int<dof_id_type>(i), elem->
node_id(i));
204 const std::string &filename)
208 exii.
write(filename);
229 const std::vector<Point> &points,
230 const std::vector<std::vector<unsigned int>> &nodes_on_side)
235 std::vector<std::shared_ptr<Polygon>> sides(nodes_on_side.size());
238 const auto &nodes_on_s = nodes_on_side[s];
239 sides[s] = std::make_shared<C0Polygon>(nodes_on_s.size());
244 std::unique_ptr<Node> mid_elem_node;
245 std::unique_ptr<Elem> polyhedron =
246 std::make_unique<C0Polyhedron>(sides, mid_elem_node);
269 for (
auto &elem :
mesh.element_ptr_range())
270 elem->subdomain_id() = 1;
276 CPPUNIT_ASSERT_EQUAL(header_info.
num_dim, 3);
277 CPPUNIT_ASSERT_EQUAL(header_info.
num_elem, 8);
279 CPPUNIT_ASSERT_EQUAL(header_info.
num_face, 48);
290 const std::vector<Point> points =
291 { { 0, -2, 0}, {-1, -1, 0}, {-1, 1, 0},
292 { 0, 2, 0}, { 1, 1, 0}, { 1, -1, 0},
293 { 0, -2, 1}, {-1, -1, 1}, {-1, 1, 1},
294 { 0, 2, 1}, { 1, 1, 1}, { 1, -1, 1} };
296 const std::vector<std::vector<unsigned int>> nodes_on_side =
297 { {0, 1, 2, 3, 4, 5},
304 {6, 7, 8, 9, 10, 11} };
311 CPPUNIT_ASSERT_EQUAL(header_info.
num_dim, 3);
312 CPPUNIT_ASSERT_EQUAL(header_info.
num_elem, 1);
314 CPPUNIT_ASSERT_EQUAL(header_info.
num_face, 8);
325 const std::vector<Point> points =
326 { { 0, -2, 0}, {-1, -1, 0}, {-1, 1, 0},
327 { 0, 2, 0}, { 1, 1, 0}, { 1, -1, 0},
328 { 0, -2, 1}, {-1, -1, 1}, {-1, 1, 1},
329 { 0, 2, 1}, { 1, 1, 1}, { 1, -1, 1} };
331 const std::vector<std::vector<unsigned int>> nodes_on_side =
332 { {0, 1, 2, 3, 4, 5},
339 {6, 7, 8, 9, 10, 11} };
343 std::vector<std::vector<dof_id_type>> expected_nodes_on_side;
345 const bool have_output_elem = output_elem;
346 bool found_output_elem = have_output_elem;
348 CPPUNIT_ASSERT(found_output_elem);
352 expected_nodes_on_side.reserve(output_elem->
n_sides());
355 expected_nodes_on_side.emplace_back();
357 expected_nodes_on_side.back().push_back(output_elem->
node_id(n));
363 exii.
write(
"write_exodus_C0POLYHEDRON_HEXPRISM_READ.e");
369 exii_input.
read(
"write_exodus_C0POLYHEDRON_HEXPRISM_READ.e");
374 CPPUNIT_ASSERT_EQUAL(cast_int<dof_id_type>(1), input_mesh.
n_elem());
377 bool found_elem = elem;
378 input_mesh.
comm().
max(found_elem);
379 CPPUNIT_ASSERT(found_elem);
381 const bool can_compare = have_output_elem && elem;
382 bool found_comparable_elem = can_compare;
383 input_mesh.
comm().
max(found_comparable_elem);
384 CPPUNIT_ASSERT(found_comparable_elem);
390 CPPUNIT_ASSERT_EQUAL(12u, elem->
n_vertices());
391 CPPUNIT_ASSERT_EQUAL(8u, elem->
n_sides());
396 CPPUNIT_ASSERT_EQUAL(expected_nodes_on_side[s].size(), side_nodes.size());
397 for (
auto n :
index_range(expected_nodes_on_side[s]))
398 CPPUNIT_ASSERT_EQUAL(expected_nodes_on_side[s][n],
409 template <
typename MeshType>
415 const std::vector<Point> points =
416 { { 0, -2, 0}, {-1, -1, 0}, {-1, 1, 0}, { 0, 2, 0}, { 1, 1, 0}, { 1, -1, 0},
417 { 0, -2, 1}, {-1, -1, 1}, {-1, 1, 1}, { 0, 2, 1}, { 1, 1, 1}, { 1, -1, 1} };
421 const std::vector<std::vector<unsigned int>> nodes_on_side =
422 { {0, 1, 2, 3, 4, 5}, {0, 1, 7, 6}, {1, 2, 8, 7}, {2, 3, 9, 8},
423 {3, 4, 10, 9}, {4, 5, 11, 10}, {5, 0, 6, 11}, {6, 7, 8, 9, 10, 11} };
424 std::vector<std::shared_ptr<Polygon>> sides(nodes_on_side.size());
427 sides[s] = std::make_shared<C0Polygon>(nodes_on_side[s].size());
429 sides[s]->set_node(i,
mesh.
node_ptr(nodes_on_side[s][i]));
431 std::unique_ptr<Node> mid_elem_node;
432 std::unique_ptr<Elem> polyhedron =
433 std::make_unique<C0Polyhedron>(sides, mid_elem_node);
437 polyhedron->subdomain_id() = 1;
441 const std::vector<Point> hex_points =
442 { {5,0,0}, {6,0,0}, {6,1,0}, {5,1,0}, {5,0,1}, {6,0,1}, {6,1,1}, {5,1,1} };
446 for (
unsigned int i = 0; i != 8; ++i)
449 hex->subdomain_id() = 1;
458 exii.
write(filename);
465 if (input_mesh.processor_id() == 0)
466 exii_input.
read(filename);
469 input_mesh.prepare_for_use();
471 CPPUNIT_ASSERT_EQUAL(cast_int<dof_id_type>(2), input_mesh.n_elem());
474 unsigned int n_poly = 0, n_hex = 0;
475 for (
const auto & elem : input_mesh.active_local_element_ptr_range())
479 else if (elem->type() ==
HEX8)
482 input_mesh.comm().sum(n_poly);
483 input_mesh.comm().sum(n_hex);
484 CPPUNIT_ASSERT_EQUAL(1u, n_poly);
485 CPPUNIT_ASSERT_EQUAL(1u, n_hex);
491 test_write_and_read_mixed_poly_hex_impl<ReplicatedMesh>(
"write_exodus_mixed_poly_hex_repl.e");
497 test_write_and_read_mixed_poly_hex_impl<DistributedMesh>(
"write_exodus_mixed_poly_hex_dist.e");
508 template <
typename MeshType>
510 bool run_only_on_proc0 =
true)
515 const std::vector<Point> hex_points =
516 { {0,0,0}, {1,0,0}, {1,1,0}, {0,1,0}, {0,0,1}, {1,0,1}, {1,1,1}, {0,1,1} };
520 for (
unsigned int i = 0; i != 8; ++i)
523 hex->subdomain_id() = 1;
527 const std::vector<Point> tet_points =
528 { {5,0,0}, {6,0,0}, {5,1,0}, {5,0,1} };
532 for (
unsigned int i = 0; i != 4; ++i)
535 tet->subdomain_id() = 1;
549 const std::string suffix = run_only_on_proc0 ?
".e" :
553 auto write_mesh = [&
mesh, run_only_on_proc0](
const std::string & filename,
556 if (run_only_on_proc0)
560 exii.
write(filename);
574 write_mesh(basename + suffix,
false);
579 write_mesh(basename +
"_sides" + suffix,
true);
586 if (input_mesh.processor_id() == 0)
587 exii_input.
read(basename + suffix);
590 input_mesh.prepare_for_use();
592 CPPUNIT_ASSERT_EQUAL(cast_int<dof_id_type>(2), input_mesh.n_elem());
595 unsigned int n_hex = 0, n_tet = 0;
596 for (
const auto & elem : input_mesh.active_local_element_ptr_range())
598 if (elem->type() ==
HEX8)
600 else if (elem->type() ==
TET4)
603 input_mesh.comm().sum(n_hex);
604 input_mesh.comm().sum(n_tet);
605 CPPUNIT_ASSERT_EQUAL(1u, n_hex);
606 CPPUNIT_ASSERT_EQUAL(1u, n_tet);
611 std::set<subdomain_id_type> sbd_ids;
612 input_mesh.subdomain_ids(sbd_ids);
613 CPPUNIT_ASSERT_EQUAL(std::size_t(2), sbd_ids.size());
615 std::set<std::string> names;
616 for (
auto sid : sbd_ids)
617 names.insert(input_mesh.subdomain_name(sid));
618 CPPUNIT_ASSERT_EQUAL(std::size_t(1), names.count(
"solid"));
619 CPPUNIT_ASSERT_EQUAL(std::size_t(1), names.count(
"solid_HEX8"));
625 test_write_and_read_mixed_hex_tet_block_names_impl<ReplicatedMesh>(
"write_exodus_mixed_hex_tet_repl");
631 test_write_and_read_mixed_hex_tet_block_names_impl<DistributedMesh>(
"write_exodus_mixed_hex_tet_dist");
637 test_write_and_read_mixed_hex_tet_block_names_impl<ReplicatedMesh>
638 (
"write_exodus_mixed_hex_tet_all_ranks",
false);
661#ifdef LIBMESH_ENABLE_EXCEPTIONS
LIBMESH_CPPUNIT_TEST_SUITE(ExodusC0PolygonTest)
void build_pentagon(Mesh &mesh)
CPPUNIT_TEST(test_write_and_read_pentagon)
void test_write_and_read_pentagon()
void test_write_and_read_mixed_hex_tet_block_names_replicated()
CPPUNIT_TEST(test_write_and_read_hexagonal_prism)
CPPUNIT_TEST(test_write_and_read_mixed_hex_tet_block_names_replicated)
void test_write_and_read_mixed_poly_hex_replicated()
CPPUNIT_TEST(test_write_hexagonal_prism_header)
void test_write_hexagonal_prism_header()
void test_write_and_read_hexagonal_prism()
CPPUNIT_TEST(test_write_and_read_mixed_hex_tet_block_names_distributed)
CPPUNIT_TEST(test_write_and_read_mixed_poly_hex_distributed)
void test_write_and_read_mixed_hex_tet_block_names_impl(const std::string &basename, bool run_only_on_proc0=true)
CPPUNIT_TEST(test_write_and_read_mixed_hex_tet_block_names_all_ranks)
void test_write_cube_header()
void build_c0polyhedron(Mesh &mesh, const std::vector< Point > &points, const std::vector< std::vector< unsigned int > > &nodes_on_side)
void test_write_and_read_mixed_hex_tet_block_names_all_ranks()
ExodusHeaderInfo write_and_read_header(Mesh &mesh, const std::string &filename)
static void assert_distributed_if_parallel(const MeshBase &mesh)
void test_write_and_read_mixed_poly_hex_impl(const std::string &filename)
CPPUNIT_TEST(test_write_cube_header)
void test_write_and_read_mixed_hex_tet_block_names_distributed()
LIBMESH_CPPUNIT_TEST_SUITE(ExodusC0PolyhedronTest)
void test_write_and_read_mixed_poly_hex_distributed()
CPPUNIT_TEST(test_write_and_read_mixed_poly_hex_replicated)
bool meshes_equal_enough(Mesh &other_mesh, bool double_precision)
std::unique_ptr< Mesh > _mesh
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...
The DistributedMesh class is derived from the MeshBase class, and is intended to provide identical fu...
virtual dof_id_type n_elem() const override final
virtual const Elem * query_elem_ptr(const dof_id_type i) const override final
This is the base class from which all geometric element types are derived.
virtual unsigned int n_vertices() const =0
virtual unsigned int n_nodes() const =0
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
subdomain_id_type subdomain_id() const
virtual ElemType type() const =0
virtual unsigned int n_sides() const =0
dof_id_type node_id(const unsigned int i) const
IntRange< unsigned short > side_index_range() const
This is the ExodusII_IO_Helper class.
virtual void write_nodal_coordinates(const MeshBase &mesh, bool use_discontinuous=false)
Writes the nodal coordinates contained in "mesh".
void close() noexcept
Closes the ExodusII mesh file.
virtual void create(std::string filename)
Opens an ExodusII mesh file named filename for writing.
virtual void write_elements(const MeshBase &mesh, bool use_discontinuous=false)
Writes the elements contained in "mesh".
virtual void initialize(std::string title, const MeshBase &mesh, bool use_discontinuous=false)
Initializes the Exodus file.
void set_add_sides(bool add_sides)
Sets whether or not to write extra "side" elements.
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
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.
void write_added_sides(bool val)
By default, we only write out the elements physically stored in the mesh.
This is the MeshBase class.
void set_subdomain_name(subdomain_id_type id, const std::string &name, bool synchronous=false)
Sets the name for the provided id.
virtual bool is_serial() const
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
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.
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.
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
Communicator * TestCommWorld
CPPUNIT_TEST_SUITE_REGISTRATION(ExodusC0PolygonTest)
INSTANTIATE_EXODUSTEST(EDGE2)
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...
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...