1#include <libmesh/boundary_info.h>
2#include <libmesh/elem.h>
3#include <libmesh/mesh.h>
4#include <libmesh/mesh_generation.h>
5#include <libmesh/mesh_netgen_interface.h>
6#include <libmesh/mesh_tetgen_interface.h>
7#include <libmesh/mesh_tet_interface.h>
8#include <libmesh/mesh_tools.h>
9#include <libmesh/parallel_implementation.h>
31 (
mesh, xmin, xmax, ymin, ymax, zmin, zmax, flip_tris);
34 return (xmax-xmin)*(ymax-ymin)*(zmax-zmin)/6;
49#ifdef LIBMESH_HAVE_NETGEN
62#ifdef LIBMESH_ENABLE_AMR
78#ifdef LIBMESH_HAVE_TETGEN
99 Real expected_volume = 0)
101#ifdef LIBMESH_ENABLE_EXCEPTIONS
105 bool threw_desired_exception =
false;
108 expected_n_nodes, expected_volume);
111 std::regex msg_regex(re);
112 CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
113 threw_desired_exception =
true;
115 catch (CppUnit::Exception & e) {
119 CPPUNIT_ASSERT_MESSAGE(
"Unexpected exception type thrown",
false);
121 CPPUNIT_ASSERT(threw_desired_exception);
130 Real expected_volume = 0)
135 CPPUNIT_ASSERT_EQUAL(
mesh.
n_elem(), expected_n_elem);
138 CPPUNIT_ASSERT_EQUAL(
mesh.
n_nodes(), expected_n_nodes);
140 if (expected_volume != 0)
145 for (
const auto & elem :
mesh.element_ptr_range())
147 CPPUNIT_ASSERT_EQUAL(elem->type(),
TET4);
150 CPPUNIT_ASSERT(!elem->is_flipped());
158 for (
const auto & elem :
mesh.element_ptr_range())
160 for (
auto s : elem->side_index_range())
162 auto neigh = elem->neighbor_ptr(s);
172 auto side = elem->side_ptr(s);
173 auto normal = (side->point(1) - side->point(0)).cross
174 (side->point(2) - side->point(0));
176 if (normal * side->vertex_average() > 0)
189 std::unique_ptr<UnstructuredMesh> holemesh =
193 -2, 2, -2, 2, -2, 2);
195 const Real hole_volume =
196 build_octahedron(*holemesh,
false, -1, 1, -1, 1, -1, 1);
199 std::make_unique<std::vector<std::unique_ptr<UnstructuredMesh>>>();
201 holes->push_back(std::move(holemesh));
205 const Real expected_volume =
212#ifdef LIBMESH_ENABLE_AMR
216 std::unique_ptr<UnstructuredMesh> holemesh =
224 std::make_unique<std::vector<std::unique_ptr<UnstructuredMesh>>>();
226 holes->push_back(std::move(holemesh));
242 bool flip_tris =
false,
243 bool flip_some_tris =
false)
247 const Real expected_volume =
248 build_octahedron(
mesh, flip_tris, -1, 1, -1, 1, -0.1, 0.1);
252 for (
auto elem :
mesh.element_ptr_range())
254 Point center = elem->vertex_average();
255 if ((center(0) > 0 &&
273 bool flip_tris =
false)
275 const Real expected_volume =
276 build_octahedron(
mesh, flip_tris, -1, 1, -1, 1, -0.1, 0.1);
279 for (
auto elem :
mesh.element_ptr_range())
281 Point center = elem->vertex_average();
307 auto add_tet = [&
mesh](std::array<dof_id_type,4> nodes)
331#ifdef LIBMESH_HAVE_TETGEN
377#ifdef LIBMESH_HAVE_NETGEN
455 const Real expected_volume =
456 build_octahedron(
mesh,
false, -1, 1, -1, 1, -0.1, 0.1);
464 for (
const auto & elem :
mesh.element_ptr_range())
466 CPPUNIT_ASSERT_EQUAL(elem->type(),
TET10);
467 CPPUNIT_ASSERT_EQUAL(elem->n_nodes(), 10u);
468 CPPUNIT_ASSERT(!elem->is_flipped());
484 const Real expected_volume =
485 build_octahedron(
mesh,
false, -1, 1, -1, 1, -0.1, 0.1);
493 for (
const auto & elem :
mesh.element_ptr_range())
495 CPPUNIT_ASSERT_EQUAL(elem->type(),
TET14);
496 CPPUNIT_ASSERT_EQUAL(elem->n_nodes(), 14u);
497 CPPUNIT_ASSERT(!elem->is_flipped());
514 build_octahedron(
mesh,
false, -1, 1, -1, 1, -0.1, 0.1);
520 const Real eps = 0.05;
521 std::map<std::pair<Point,Point>,
Point> expected;
523 for (
const auto & elem :
mesh.element_ptr_range())
525 libmesh_assert_equal_to(elem->type(),
TRI6);
528 const Point & pa = elem->point(e);
529 const Point & pb = elem->point((e+1)%3);
530 auto key = pa < pb ? std::make_pair(pa, pb)
531 : std::make_pair(pb, pa);
532 if (expected.count(key))
536 Point & mid = elem->point(e+3);
537 mid += eps * mid.
unit();
546 unsigned int n_checked = 0;
547 for (
const auto & elem :
mesh.element_ptr_range())
548 for (
auto s : elem->side_index_range())
550 if (elem->neighbor_ptr(s))
continue;
552 auto side = elem->build_side_ptr(s);
555 const Point & pa = side->point(e);
556 const Point & pb = side->point((e+1)%3);
557 auto key = pa < pb ? std::make_pair(pa, pb)
558 : std::make_pair(pb, pa);
559 auto it = expected.find(key);
560 if (it == expected.end())
562 const Point & exp = it->second;
563 const Point & got = side->point(e+3);
564 LIBMESH_ASSERT_FP_EQUAL(exp(0), got(0),
TOLERANCE);
565 LIBMESH_ASSERT_FP_EQUAL(exp(1), got(1),
TOLERANCE);
566 LIBMESH_ASSERT_FP_EQUAL(exp(2), got(2),
TOLERANCE);
571 CPPUNIT_ASSERT_GREATER(0u, n_checked);
588 build_octahedron(
mesh,
false, -1, 1, -1, 1, -0.1, 0.1);
592 const Real eps = 0.05;
593 std::map<std::pair<Point,Point>,
Point> expected_mid;
594 std::map<std::array<Point,3>,
Point> expected_cen;
596 for (
const auto & elem :
mesh.element_ptr_range())
598 libmesh_assert_equal_to(elem->type(),
TRI7);
601 const Point & pa = elem->point(e);
602 const Point & pb = elem->point((e+1)%3);
603 auto key = pa < pb ? std::make_pair(pa, pb)
604 : std::make_pair(pb, pa);
605 if (!expected_mid.count(key))
607 Point & mid = elem->point(e+3);
608 mid += eps * mid.
unit();
609 expected_mid[key] = mid;
613 std::array<Point,3> corners =
614 {elem->point(0), elem->point(1), elem->point(2)};
615 std::sort(corners.begin(), corners.end());
616 Point & cen = elem->point(6);
617 cen += eps * cen.
unit();
618 expected_cen[corners] = cen;
623 unsigned int n_mid = 0, n_cen = 0;
624 for (
const auto & elem :
mesh.element_ptr_range())
625 for (
auto s : elem->side_index_range())
627 if (elem->neighbor_ptr(s))
continue;
628 auto side = elem->build_side_ptr(s);
629 CPPUNIT_ASSERT_EQUAL(side->type(),
TRI7);
632 const Point & pa = side->point(e);
633 const Point & pb = side->point((e+1)%3);
634 auto key = pa < pb ? std::make_pair(pa, pb)
635 : std::make_pair(pb, pa);
636 auto it = expected_mid.find(key);
637 if (it == expected_mid.end())
continue;
638 const Point & exp = it->second;
639 const Point & got = side->point(e+3);
640 LIBMESH_ASSERT_FP_EQUAL(exp(0), got(0),
TOLERANCE);
641 LIBMESH_ASSERT_FP_EQUAL(exp(1), got(1),
TOLERANCE);
642 LIBMESH_ASSERT_FP_EQUAL(exp(2), got(2),
TOLERANCE);
645 std::array<Point,3> corners =
646 {side->point(0), side->point(1), side->point(2)};
647 std::sort(corners.begin(), corners.end());
648 auto it = expected_cen.find(corners);
649 if (it == expected_cen.end())
continue;
650 const Point & exp = it->second;
651 const Point & got = side->point(6);
652 LIBMESH_ASSERT_FP_EQUAL(exp(0), got(0),
TOLERANCE);
653 LIBMESH_ASSERT_FP_EQUAL(exp(1), got(1),
TOLERANCE);
654 LIBMESH_ASSERT_FP_EQUAL(exp(2), got(2),
TOLERANCE);
658 CPPUNIT_ASSERT_GREATER(0u, n_mid);
659 CPPUNIT_ASSERT_GREATER(0u, n_cen);
665#ifdef LIBMESH_ENABLE_AMR
CPPUNIT_TEST(testNetGenQuadraticCurved)
void testSphereShell(UnstructuredMesh &mesh, MeshTetInterface &triangulator)
CPPUNIT_TEST(testNetGenTet14)
CPPUNIT_TEST(testNetGenSphereShell)
CPPUNIT_TEST(testNetGenTets)
CPPUNIT_TEST(testNetGenFlippedTris)
void testNetGenTet14Curved()
void testNetGenSphereShell()
LIBMESH_CPPUNIT_TEST_SUITE(MeshTetTest)
The goal of this test is to verify proper operation of the interfaces to tetrahedralization libraries...
void testTrisToTetsError(UnstructuredMesh &mesh, MeshTetInterface &triangulator, bool flip_tris=false)
CPPUNIT_TEST(testNetGenError)
CPPUNIT_TEST(testNetGenTet14Curved)
void testNetGenFlippedTris()
void testNetGenQuadraticCurved()
void testTetsToTets(MeshBase &mesh, MeshTetInterface &triangulator)
void testExceptionBase(const char *re, MeshBase &mesh, MeshTetInterface &tetinterface, dof_id_type expected_n_elem=DofObject::invalid_id, dof_id_type expected_n_nodes=DofObject::invalid_id, Real expected_volume=0)
void testTetInterfaceBase(MeshBase &mesh, MeshTetInterface &triangulator, dof_id_type expected_n_elem=DofObject::invalid_id, dof_id_type expected_n_nodes=DofObject::invalid_id, Real expected_volume=0)
void testNetGenQuadratic()
void testTrisToTets(UnstructuredMesh &mesh, MeshTetInterface &triangulator, bool flip_tris=false, bool flip_some_tris=false)
void testHole(UnstructuredMesh &mesh, MeshTetInterface &triangulator)
void testBcids(UnstructuredMesh &mesh)
CPPUNIT_TEST(testNetGenHole)
void testNetGenNonOriented()
CPPUNIT_TEST(testNetGenNonOriented)
CPPUNIT_TEST(testNetGenQuadratic)
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
std::size_t n_boundary_ids() const
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
virtual Node *& set_node(const unsigned int i)
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
A class to represent the internal "this should never happen" errors, to be thrown by "libmesh_error()...
This is the MeshBase class.
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
virtual dof_id_type n_elem() const =0
void all_second_order(const bool full_ordered=true)
Calls the range-based version of this function with a range consisting of all elements in the mesh.
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 dof_id_type n_nodes() const =0
virtual void delete_elem(Elem *e)=0
Removes element e from the mesh.
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 void all_complete_order()
Calls the range-based version of this function with a range consisting of all elements in the mesh.
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
void unset_is_prepared()
Tells this we have done some operation where we should no longer consider ourself prepared.
Class MeshTetInterface provides an abstract interface for tetrahedralization of meshes by subclasses.
ElemType & elem_type()
Sets and/or gets the desired element type.
virtual void triangulate()=0
This is the main public interface for this function.
Real & desired_volume()
Sets and/or gets the desired tetrahedron volume.
void attach_hole_list(std::unique_ptr< std::vector< std::unique_ptr< UnstructuredMesh > > > holes)
Attaches a vector of Mesh pointers defining holes which will be meshed around.
void set_verbosity(unsigned int v)
Sets a verbosity level, defaulting to 0 (print nothing), to be set as high as 100 (print everything).
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Class NetGenMeshInterface provides an interface for tetrahedralization of meshes using the NetGen lib...
virtual void triangulate() override
Method invokes NetGen library to compute a tetrahedralization.
A Point defines a location in LIBMESH_DIM dimensional Real space.
Class TetGenMeshInterface provides an interface for tetrahedralization of meshes using the TetGen lib...
TypeVector< T > unit() const
The UnstructuredMesh class is derived from the MeshBase class.
Communicator * TestCommWorld
CPPUNIT_TEST_SUITE_REGISTRATION(MeshTetTest)
The libMesh namespace provides an interface to certain functionality in the library.
static constexpr Real TOLERANCE
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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...