2 #include <libmesh/elem.h> 3 #include <libmesh/enum_elem_type.h> 4 #include <libmesh/face_c0polygon.h> 5 #include <libmesh/mesh_generation.h> 6 #include <libmesh/mesh_modification.h> 7 #include <libmesh/mesh.h> 8 #include <libmesh/reference_elem.h> 9 #include <libmesh/replicated_mesh.h> 10 #include <libmesh/node.h> 11 #include <libmesh/enum_to_string.h> 12 #include <libmesh/tensor_value.h> 13 #include <libmesh/enum_elem_quality.h> 29 CPPUNIT_TEST( testTwistedVolume );
30 CPPUNIT_TEST( testEdge3Volume );
31 CPPUNIT_TEST( testEdge3Invertible );
32 CPPUNIT_TEST( testEdge4Invertible );
33 CPPUNIT_TEST( testQuad4Invertible );
34 CPPUNIT_TEST( testTri3TrueCentroid );
35 CPPUNIT_TEST( testQuad4TrueCentroid );
36 CPPUNIT_TEST( testPyramid5TrueCentroid );
37 CPPUNIT_TEST( testHex8TrueCentroid );
38 CPPUNIT_TEST( testPrism6TrueCentroid );
39 CPPUNIT_TEST( testHex20PLevelTrueCentroid );
40 CPPUNIT_TEST( testQuad4AspectRatio );
41 CPPUNIT_TEST( testQuad4Warpage );
42 CPPUNIT_TEST( testQuad4MinMaxAngle );
43 CPPUNIT_TEST( testQuad4Jacobian );
44 CPPUNIT_TEST( testTri3AspectRatio );
45 CPPUNIT_TEST( testTet4DihedralAngle );
46 CPPUNIT_TEST( testTet4Jacobian );
47 CPPUNIT_TEST( testC0PolygonSquare );
48 CPPUNIT_TEST( testC0PolygonQuad );
49 CPPUNIT_TEST( testC0PolygonPentagon );
50 CPPUNIT_TEST( testC0PolygonHexagon );
51 CPPUNIT_TEST_SUITE_END();
87 Point base_class_centroid = quad4.Elem::true_centroid();
106 for (
const auto & elem :
mesh.element_ptr_range())
108 Point derived_centroid = elem->true_centroid();
109 Point base_centroid = elem->Elem::true_centroid();
120 Real derived_volume = elem->volume();
121 Real base_volume = elem->Elem::volume();
141 test_true_centroid_and_volume(
PYRAMID5);
154 #ifdef LIBMESH_ENABLE_AMR 168 #endif // LIBMESH_ENABLE_AMR 189 prism6->
point(1) *= -1;
195 CPPUNIT_ASSERT_LESS(
TOLERANCE, std::abs(vol-gold_vol));
204 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(3),
mesh.
n_nodes());
214 auto & middle_node = edge3->
node_ref(2);
215 auto & right_node = edge3->node_ref(1);
220 middle_node =
Point(0.5 + 1.e-3, 0., 0.);
226 middle_node =
Point(0.5 - 1.e-3, 0., 0.);
230 middle_node =
Point(0.5, 0.25, 0.);
231 right_node =
Point(1., 1., 0.);
232 LIBMESH_ASSERT_FP_EQUAL(1.4789428575446, edge3->volume(),
TOLERANCE);
237 middle_node =
Point(0.5, 0.1, 0.);
238 right_node =
Point(1., 0., 0.);
239 LIBMESH_ASSERT_FP_EQUAL(edge3->Elem::volume(), edge3->volume(), std::sqrt(
TOLERANCE));
252 bool invertible = test_elem_invertible({
253 Point(-3.566160e1, -6.690970e-1, 1.100328e2),
254 Point(-3.566160e1, -6.690970e-1, 1.176528e2),
255 Point(-3.566160e1, -6.690970e-1, 1.115568e2)},
EDGE3);
256 CPPUNIT_ASSERT(!invertible);
260 invertible = test_elem_invertible({
261 Point(-3.566160e1, -6.690970e-1, 1.100328e2),
262 Point(-3.566160e1, -6.690970e-1, 1.176528e2),
263 Point(-3.566160e1, -6.690970e-1, 113.8428)},
EDGE3);
264 CPPUNIT_ASSERT(invertible);
269 CPPUNIT_ASSERT(!invertible);
286 test_elem_invertible({
Point(-1, 0, 0),
Point(1, 0, 0),
Point(-0.5, 0, 0),
Point(
Real(1)/3, 0, 0)},
288 CPPUNIT_ASSERT(invertible);
292 test_elem_invertible({
Point(-1, 0, 0),
Point(1, 0, 0),
Point(-0.57, 0, 0),
Point(
Real(1)/3, 0, 0)},
294 CPPUNIT_ASSERT(!invertible);
301 test_elem_invertible({
Point(-1, 0, 0),
Point(1, 0, 0),
Point(
Real(3)/21, 0, 0),
Point(
Real(1)/3, 0, 0)},
303 CPPUNIT_ASSERT(invertible);
307 test_elem_invertible({
Point(-1, 0, 0),
Point(1, 0, 0),
Point(
Real(6)/21, 0, 0),
Point(
Real(1)/3, 0, 0)},
309 CPPUNIT_ASSERT(!invertible);
321 std::vector<Point> pts = {
Point(0, 0, 0),
Point(1, 0, 0),
Point(1, 1, 0),
Point(0, 1, 0)};
322 bool invertible = test_elem_invertible(pts,
QUAD4);
323 CPPUNIT_ASSERT(invertible);
332 for (
auto & pt : pts)
335 invertible = test_elem_invertible(pts,
QUAD4);
336 CPPUNIT_ASSERT(invertible);
343 for (
auto & pt : pts)
346 invertible = test_elem_invertible(pts,
QUAD4);
347 CPPUNIT_ASSERT(invertible);
354 for (
int cnt=0; cnt<3; ++cnt)
355 for (
auto & pt : pts)
358 invertible = test_elem_invertible(pts,
QUAD4);
359 CPPUNIT_ASSERT(invertible);
370 const Real alpha = .5;
373 test_elem_invertible({
Point(0, 0, 0),
Point(1, 0, 0),
Point(alpha, alpha, 0),
Point(0, 1, 0)},
QUAD4);
375 CPPUNIT_ASSERT(!invertible);
381 const Real alpha = -0.25;
384 test_elem_invertible({
Point(0, 0, 0),
Point(1, 0, 0),
Point(alpha, 1, 0),
Point(0, 1, 0)},
QUAD4);
386 CPPUNIT_ASSERT(!invertible);
392 const Real alpha = std::log(2);
395 test_elem_invertible({
Point(alpha, alpha, alpha),
396 Point(alpha, alpha, alpha),
397 Point(alpha, alpha, alpha),
400 CPPUNIT_ASSERT(!invertible);
413 std::vector<Point> pts = {
Point(0, 0, 0),
Point(1, 0, 0),
Point(1, 1, 0),
Point(0, 1, 0)};
414 auto [elem, nodes] = this->construct_elem(pts,
QUAD4);
419 CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, aspect_ratio,
TOLERANCE);
428 for (
auto & pt : pts)
432 CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, aspect_ratio,
TOLERANCE);
439 for (
auto & pt : pts)
443 CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, aspect_ratio,
TOLERANCE);
450 for (
int cnt=0; cnt<3; ++cnt)
451 for (
auto & pt : pts)
455 CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, aspect_ratio,
TOLERANCE);
464 auto test_rhombus_quad = [
this](
Real theta)
466 Real ct = std::cos(theta);
467 Real st = std::sin(theta);
468 std::vector<Point> pts = {
471 Point(1. + ct, st, 0),
473 auto [elem, nodes] = this->construct_elem(pts,
QUAD4);
478 CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/st, aspect_ratio,
TOLERANCE);
494 auto test_rectangle_quad = [
this](
Real a)
496 std::vector<Point> pts = {
Point(0, 0, 0),
Point(a, 0, 0),
Point(a, 1, 0),
Point(0, 1, 0)};
497 auto [elem, nodes] = this->construct_elem(pts,
QUAD4);
502 CPPUNIT_ASSERT_DOUBLES_EQUAL(a, aspect_ratio,
TOLERANCE);
506 test_rectangle_quad(2.0);
509 test_rectangle_quad(1e6);
523 std::vector<Point> pts = {
Point(0, 0, 0),
Point(1, 0, 0),
Point(1, 0, 0),
Point(0, 1, 0)};
524 auto [elem, nodes] = this->construct_elem(pts,
QUAD4);
528 CPPUNIT_ASSERT_DOUBLES_EQUAL(2.5, aspect_ratio,
TOLERANCE);
533 auto test_trapezoid_quad = [
this](
Real a)
536 std::vector<Point> pts = {
Point(0, 0, 0),
Point(1, 0, 0),
Point(1-a, 1, 0),
Point(a, 1, 0)};
537 auto [elem, nodes] = this->construct_elem(pts,
QUAD4);
541 CPPUNIT_ASSERT_DOUBLES_EQUAL(1./(1. - a), aspect_ratio,
TOLERANCE);
545 test_trapezoid_quad(1./3);
548 test_trapezoid_quad(0.5);
558 std::vector<Point> pts = {
Point(0, 0, 0),
Point(1, 0, 0),
Point(0, 1, 0)};
559 auto [elem, nodes] = this->construct_elem(pts,
TRI3);
566 CPPUNIT_ASSERT_DOUBLES_EQUAL(
Real(5)/2/std::sqrt(
Real(3)), aspect_ratio,
TOLERANCE);
571 std::vector<Point> pts = {
Point(0, 0, 0),
Point(1, 0, 0),
Point(0.5, 0.5*std::sqrt(3), 0)};
572 auto [elem, nodes] = this->construct_elem(pts,
TRI3);
579 CPPUNIT_ASSERT_DOUBLES_EQUAL(
Real(1), aspect_ratio,
TOLERANCE);
585 std::vector<Point> pts = {
Point(0, 0, 0),
Point(L, 0, 0),
Point(0, 1, 0)};
586 auto [elem, nodes] = this->construct_elem(pts,
TRI3);
606 std::vector<Point> pts = {
Point(0, 0, 0),
Point(1, 0, 0),
Point(1, 1, 0),
Point(0, 1, 0)};
607 auto [elem, nodes] = this->construct_elem(pts,
QUAD4);
612 CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, warpage,
TOLERANCE);
621 for (
auto & pt : pts)
624 warpage = elem->quality(
WARP);
625 CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, warpage,
TOLERANCE);
632 for (
auto & pt : pts)
635 warpage = elem->quality(
WARP);
636 CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, warpage,
TOLERANCE);
643 for (
int cnt=0; cnt<3; ++cnt)
644 for (
auto & pt : pts)
647 warpage = elem->quality(
WARP);
648 CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, warpage,
TOLERANCE);
653 auto test_warped_quad = [
this](
Real h)
655 std::vector<Point> pts = {
Point(0, 0, 0),
Point(1, 0, 0),
Point(1, 1, h),
Point(0, 1, 0)};
656 auto [elem, nodes] = this->construct_elem(pts,
QUAD4);
663 CPPUNIT_ASSERT_DOUBLES_EQUAL(
Real(1) / (h*h + 1), warpage,
TOLERANCE);
668 test_warped_quad(0.1);
673 test_warped_quad(0.3);
686 std::vector<Point> pts = {
Point(0, 0, 0),
Point(1, 0, 0),
Point(1, 1, 0),
Point(0, 1, 0)};
687 auto [elem, nodes] = this->construct_elem(pts,
QUAD4);
694 CPPUNIT_ASSERT_DOUBLES_EQUAL(90, min_angle,
TOLERANCE);
695 CPPUNIT_ASSERT_DOUBLES_EQUAL(90, max_angle,
TOLERANCE);
705 for (
auto & pt : pts)
711 CPPUNIT_ASSERT_DOUBLES_EQUAL(90, min_angle,
TOLERANCE);
712 CPPUNIT_ASSERT_DOUBLES_EQUAL(90, max_angle,
TOLERANCE);
720 for (
auto & pt : pts)
726 CPPUNIT_ASSERT_DOUBLES_EQUAL(90, min_angle,
TOLERANCE);
727 CPPUNIT_ASSERT_DOUBLES_EQUAL(90, max_angle,
TOLERANCE);
735 for (
int cnt=0; cnt<3; ++cnt)
736 for (
auto & pt : pts)
742 CPPUNIT_ASSERT_DOUBLES_EQUAL(90, min_angle,
TOLERANCE);
743 CPPUNIT_ASSERT_DOUBLES_EQUAL(90, max_angle,
TOLERANCE);
754 auto test_rhombus_quad = [
this](
Real theta)
756 Real ct = std::cos(theta);
757 Real st = std::sin(theta);
758 std::vector<Point> pts = {
761 Point(1. + ct, st, 0),
763 auto [elem, nodes] = this->construct_elem(pts,
QUAD4);
792 auto test_rhombus_quad = [
this](
Real theta)
794 Real ct = std::cos(theta);
795 Real st = std::sin(theta);
796 std::vector<Point> pts = {
799 Point(1. + ct, st, 0),
801 auto [elem, nodes] = this->construct_elem(pts,
QUAD4);
811 CPPUNIT_ASSERT_DOUBLES_EQUAL(std::abs(std::sin(theta)), jac,
TOLERANCE);
812 CPPUNIT_ASSERT_DOUBLES_EQUAL(std::abs(std::sin(theta)), scaled_jac,
TOLERANCE);
832 std::vector<Point> pts = {
Point(0, 0, 0),
Point(1, 0, 0),
Point(0, 1, 0),
Point(1, 1, 0.01)};
833 auto [elem, nodes] = this->construct_elem(pts,
TET4);
847 CPPUNIT_ASSERT_DOUBLES_EQUAL(44.9985676771277, min_angle,
TOLERANCE);
848 CPPUNIT_ASSERT_DOUBLES_EQUAL(90, max_angle,
TOLERANCE);
851 CPPUNIT_ASSERT_LESS(1.0, min_dihedral_angle);
852 CPPUNIT_ASSERT_LESS(1.0, max_dihedral_angle);
864 std::vector<Point> pts = {
Point(0, 0, 0),
Point(1, 0, 0),
Point(0, 1, 0),
Point(1, 1, h)};
865 auto [elem, nodes] = this->construct_elem(pts,
TET4);
875 CPPUNIT_ASSERT_DOUBLES_EQUAL(h, jac,
TOLERANCE);
876 CPPUNIT_ASSERT_DOUBLES_EQUAL(h/std::sqrt(h*h + 2), scaled_jac,
TOLERANCE);
886 std::vector<Point> pts = {
887 Point(2.5, 2.5, 4.5),
888 Point(3.5, 1.5, 5.5),
889 Point(1.5, 1.5, 5.5),
892 auto [elem, nodes] = this->construct_elem(pts,
TET4);
902 CPPUNIT_ASSERT_DOUBLES_EQUAL(2, jac,
TOLERANCE);
910 Real expected_volume)
914 const auto np = points.size();
915 std::unique_ptr<Elem> polygon = std::make_unique<C0Polygon>(np);
924 const Real base_volume = elem->Elem::volume();
928 this->testC0PolygonMethods(
mesh, np);
936 testC0Polygon({{0,0}, {1,0}, {1,1}, {0,1}}, 1);
942 testC0Polygon({{0,0}, {1,0}, {1,2}, {-1,1}}, 2.5);
948 testC0Polygon({{0,0}, {1,0}, {1.5,0.5}, {1,1}, {0,1}}, 1.25);
954 testC0Polygon({{0,0}, {1,0}, {1.5,0.5}, {1,1}, {0,1}, {-0.5, 0.5}}, 1.5);
963 std::pair<std::unique_ptr<Elem>, std::vector<std::unique_ptr<Node>>>
967 const unsigned int n_points = pts.size();
970 std::vector<std::unique_ptr<Node>> nodes(n_points);
971 for (
unsigned int i=0; i<n_points; i++)
975 std::unique_ptr<Elem> elem =
Elem::build(elem_type,
nullptr);
978 libmesh_error_msg_if(elem->n_nodes() != n_points,
979 "Wrong number of points " 981 <<
" provided to build a " 984 for (
unsigned int i=0; i<n_points; i++)
985 elem->set_node(i) = nodes[i].get();
988 return std::make_pair(std::move(elem), std::move(nodes));
994 unsigned int n_sides)
997 bool found_elem = elem;
999 CPPUNIT_ASSERT(found_elem);
1005 CPPUNIT_ASSERT_EQUAL(elem->
n_nodes(), n_sides);
1006 CPPUNIT_ASSERT_EQUAL(elem->
n_sub_elem(), n_sides);
1007 CPPUNIT_ASSERT_EQUAL(elem->
n_sides(), n_sides);
1008 CPPUNIT_ASSERT_EQUAL(elem->
n_vertices(), n_sides);
1009 CPPUNIT_ASSERT_EQUAL(elem->
n_edges(), n_sides);
1014 const unsigned int nsover2 = n_sides/2;
1025 CPPUNIT_ASSERT(!elem->
is_edge(i));
1026 CPPUNIT_ASSERT(!elem->
is_face(i));
1032 CPPUNIT_ASSERT_EQUAL(nodes.size(), std::size_t(2));
1033 CPPUNIT_ASSERT(nodes[0] == i ||
1035 CPPUNIT_ASSERT(nodes[0] == (i+1)%n_sides ||
1036 nodes[1] == (i+1)%n_sides);
1037 std::vector<unsigned int> edge_nodes = elem->
nodes_on_edge(i);
1038 CPPUNIT_ASSERT(nodes == edge_nodes);
1047 CPPUNIT_ASSERT_EQUAL(edge->type(),
EDGE2);
1048 CPPUNIT_ASSERT_EQUAL(edge->node_ptr(0),
mesh.
node_ptr(i));
1049 CPPUNIT_ASSERT_EQUAL(edge->node_ptr(1),
mesh.
node_ptr((i+1)%n_sides));
1066 auto [elem, nodes] = this->construct_elem(pts, elem_type);
1070 return elem->has_invertible_map();
1094 for (
const auto & elem :
mesh.element_ptr_range())
1096 Point derived_centroid = elem->true_centroid();
1097 Point base_centroid = elem->Elem::true_centroid();
1109 Real derived_volume = elem->volume();
1110 Real base_volume = elem->Elem::volume();
virtual Point true_centroid() const
void set_p_level(const unsigned int p)
Sets the value of the p-refinement level for the element.
ElemType
Defines an enum for geometric element types.
void testQuad4TrueCentroid()
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
void testQuad4Invertible()
void testEdge4Invertible()
void testPrism6TrueCentroid()
virtual bool is_face(const unsigned int i) const =0
libMesh::Parallel::Communicator * TestCommWorld
static constexpr Real TOLERANCE
void testQuad4MinMaxAngle()
void testC0PolygonHexagon()
bool test_elem_invertible(const std::vector< Point > &pts, ElemType elem_type)
This is the base class from which all geometric element types are derived.
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
const Parallel::Communicator & comm() const
void testPyramid5TrueCentroid()
The libMesh namespace provides an interface to certain functionality in the library.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
void testC0PolygonSquare()
virtual bool is_flipped() 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.
This is the MeshBase class.
void testC0Polygon(const std::vector< Point > &points, Real expected_volume)
void testEdge3Invertible()
virtual bool is_node_on_edge(const unsigned int n, const unsigned int e) const =0
void libmesh_ignore(const Args &...)
void testC0PolygonPentagon()
const Node & node_ref(const unsigned int i) const
virtual unsigned int n_nodes() const =0
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const =0
void testC0PolygonMethods(MeshBase &mesh, unsigned int n_sides)
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
void testTri3TrueCentroid()
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const =0
Similar to Elem::local_side_node(), but instead of a side id, takes an edge id and a node id on that ...
void testTet4DihedralAngle()
virtual unsigned int n_edges() const =0
CPPUNIT_TEST_SUITE_REGISTRATION(VolumeTest)
bool absolute_fuzzy_equals(const TypeVector< T > &rhs, Real tol=TOLERANCE) const
void testTri3AspectRatio()
void test_true_centroid_and_volume(ElemType elem_type)
virtual void flip(BoundaryInfo *boundary_info)=0
Flips the element (by swapping node and neighbor pointers) to have a mapping Jacobian of opposite sig...
std::string enum_to_string(const T e)
void testHex20PLevelTrueCentroid()
virtual std::vector< unsigned int > nodes_on_edge(const unsigned int) const =0
virtual const Elem * elem_ptr(const dof_id_type i) const =0
virtual unsigned int n_sides() const =0
static std::unique_ptr< Node > build(const Node &n)
virtual unsigned int n_vertices() const =0
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
void max(const T &r, T &o, Request &req) const
std::pair< std::unique_ptr< Elem >, std::vector< std::unique_ptr< Node > > > construct_elem(const std::vector< Point > &pts, ElemType elem_type)
virtual bool is_vertex(const unsigned int i) const =0
virtual Real volume() const
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...
virtual bool has_invertible_map(Real tol=TOLERANCE *TOLERANCE) const
virtual unsigned int n_sub_elem() const =0
void testQuad4AspectRatio()
virtual const Node * node_ptr(const dof_id_type i) const =0
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
virtual unsigned int opposite_side(const unsigned int s) const
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
const Point & point(const unsigned int i) const
virtual bool is_edge(const unsigned int i) const =0
const Elem & get(const ElemType type_in)
virtual dof_id_type n_nodes() const =0
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
void testHex8TrueCentroid()
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.