libMesh
Public Member Functions | Protected Member Functions | List of all members
VolumeTest Class Reference
Inheritance diagram for VolumeTest:
[legend]

Public Member Functions

 LIBMESH_CPPUNIT_TEST_SUITE (VolumeTest)
 
 CPPUNIT_TEST (testTwistedVolume)
 
 CPPUNIT_TEST (testEdge3Volume)
 
 CPPUNIT_TEST (testEdge3Invertible)
 
 CPPUNIT_TEST (testEdge4Invertible)
 
 CPPUNIT_TEST (testQuad4Invertible)
 
 CPPUNIT_TEST (testTri3TrueCentroid)
 
 CPPUNIT_TEST (testQuad4TrueCentroid)
 
 CPPUNIT_TEST (testPyramid5TrueCentroid)
 
 CPPUNIT_TEST (testHex8TrueCentroid)
 
 CPPUNIT_TEST (testPrism6TrueCentroid)
 
 CPPUNIT_TEST (testHex20PLevelTrueCentroid)
 
 CPPUNIT_TEST (testQuad4AspectRatio)
 
 CPPUNIT_TEST (testQuad4Warpage)
 
 CPPUNIT_TEST (testQuad4MinMaxAngle)
 
 CPPUNIT_TEST (testQuad4Jacobian)
 
 CPPUNIT_TEST (testTri3AspectRatio)
 
 CPPUNIT_TEST (testTet4DihedralAngle)
 
 CPPUNIT_TEST (testTet4Jacobian)
 
 CPPUNIT_TEST (testC0PolygonSquare)
 
 CPPUNIT_TEST (testC0PolygonQuad)
 
 CPPUNIT_TEST (testC0PolygonPentagon)
 
 CPPUNIT_TEST (testC0PolygonHexagon)
 
 CPPUNIT_TEST (testC0PolyhedronCube)
 
 CPPUNIT_TEST (testC0PolyhedronHexagonalPrism)
 
 CPPUNIT_TEST_SUITE_END ()
 
void setUp ()
 
void tearDown ()
 
void testTri3TrueCentroid ()
 
void testQuad4TrueCentroid ()
 
void testPyramid5TrueCentroid ()
 
void testHex8TrueCentroid ()
 
void testPrism6TrueCentroid ()
 
void testHex20PLevelTrueCentroid ()
 
void testTwistedVolume ()
 
void testEdge3Volume ()
 
void testEdge3Invertible ()
 
void testEdge4Invertible ()
 
void testQuad4Invertible ()
 
void testQuad4AspectRatio ()
 
void testTri3AspectRatio ()
 
void testQuad4Warpage ()
 
void testQuad4MinMaxAngle ()
 
void testQuad4Jacobian ()
 
void testTet4DihedralAngle ()
 
void testTet4Jacobian ()
 
void testC0Polygon (const std::vector< Point > &points, Real expected_volume)
 
void testC0PolygonSquare ()
 
void testC0PolygonQuad ()
 
void testC0PolygonPentagon ()
 
void testC0PolygonHexagon ()
 

Protected Member Functions

std::pair< std::unique_ptr< Elem >, std::vector< std::unique_ptr< Node > > > construct_elem (const std::vector< Point > &pts, ElemType elem_type)
 
ElembuildC0Polyhedron (std::vector< std::shared_ptr< Polygon >> sides, MeshBase &mesh)
 
void testC0PolygonMethods (MeshBase &mesh, unsigned int n_sides)
 
void testC0PolyhedronMethods (MeshBase &mesh, bool has_midnode)
 
void testElemVolume (const Elem *elem, Real expected_volume)
 
void testC0PolyhedronCube ()
 
void testC0PolyhedronHexagonalPrism ()
 
bool test_elem_invertible (const std::vector< Point > &pts, ElemType elem_type)
 
void test_true_centroid_and_volume (ElemType elem_type)
 

Detailed Description

Definition at line 25 of file volume_test.C.

Member Function Documentation

◆ buildC0Polyhedron()

Elem* VolumeTest::buildC0Polyhedron ( std::vector< std::shared_ptr< Polygon >>  sides,
MeshBase mesh 
)
inlineprotected

Definition at line 997 of file volume_test.C.

References libMesh::MeshBase::add_elem(), libMesh::MeshBase::add_node(), libMesh::libmesh_assert(), mesh, libMesh::MeshBase::prepare_for_use(), and libMesh::DofObject::set_id().

998  {
999  std::unique_ptr<libMesh::Node> mid_elem_node;
1000  std::unique_ptr<Elem> polyhedron = std::make_unique<C0Polyhedron>(sides, mid_elem_node);
1001  if (mid_elem_node)
1002  mesh.add_node(std::move(mid_elem_node));
1003  polyhedron->set_id() = 0;
1004  Elem * elem = mesh.add_elem(std::move(polyhedron));
1005  libmesh_assert(dynamic_cast<C0Polyhedron *>(elem));
1007 
1008  return elem;
1009  }
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
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
dof_id_type & set_id()
Definition: dof_object.h:827
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
libmesh_assert(ctx)
virtual Node * add_node(Node *n)=0
Add Node n to the end of the vertex array.

◆ construct_elem()

std::pair<std::unique_ptr<Elem>, std::vector<std::unique_ptr<Node> > > VolumeTest::construct_elem ( const std::vector< Point > &  pts,
ElemType  elem_type 
)
inlineprotected

Definition at line 968 of file volume_test.C.

References libMesh::Node::build(), libMesh::Elem::build(), and libMesh::Utility::enum_to_string().

970  {
971  const unsigned int n_points = pts.size();
972 
973  // Create Nodes
974  std::vector<std::unique_ptr<Node>> nodes(n_points);
975  for (unsigned int i=0; i<n_points; i++)
976  nodes[i] = Node::build(pts[i], /*id*/ i);
977 
978  // Create Elem, assign nodes
979  std::unique_ptr<Elem> elem = Elem::build(elem_type, /*parent*/ nullptr);
980 
981  // Make sure we were passed consistent input to build this type of Elem
982  libmesh_error_msg_if(elem->n_nodes() != n_points,
983  "Wrong number of points "
984  << n_points
985  << " provided to build a "
986  << Utility::enum_to_string(elem_type));
987 
988  for (unsigned int i=0; i<n_points; i++)
989  elem->set_node(i, nodes[i].get());
990 
991  // Return Elem and Nodes we created
992  return std::make_pair(std::move(elem), std::move(nodes));
993  }
std::string enum_to_string(const T e)

◆ CPPUNIT_TEST() [1/24]

VolumeTest::CPPUNIT_TEST ( testTwistedVolume  )

◆ CPPUNIT_TEST() [2/24]

VolumeTest::CPPUNIT_TEST ( testEdge3Volume  )

◆ CPPUNIT_TEST() [3/24]

VolumeTest::CPPUNIT_TEST ( testEdge3Invertible  )

◆ CPPUNIT_TEST() [4/24]

VolumeTest::CPPUNIT_TEST ( testEdge4Invertible  )

◆ CPPUNIT_TEST() [5/24]

VolumeTest::CPPUNIT_TEST ( testQuad4Invertible  )

◆ CPPUNIT_TEST() [6/24]

VolumeTest::CPPUNIT_TEST ( testTri3TrueCentroid  )

◆ CPPUNIT_TEST() [7/24]

VolumeTest::CPPUNIT_TEST ( testQuad4TrueCentroid  )

◆ CPPUNIT_TEST() [8/24]

VolumeTest::CPPUNIT_TEST ( testPyramid5TrueCentroid  )

◆ CPPUNIT_TEST() [9/24]

VolumeTest::CPPUNIT_TEST ( testHex8TrueCentroid  )

◆ CPPUNIT_TEST() [10/24]

VolumeTest::CPPUNIT_TEST ( testPrism6TrueCentroid  )

◆ CPPUNIT_TEST() [11/24]

VolumeTest::CPPUNIT_TEST ( testHex20PLevelTrueCentroid  )

◆ CPPUNIT_TEST() [12/24]

VolumeTest::CPPUNIT_TEST ( testQuad4AspectRatio  )

◆ CPPUNIT_TEST() [13/24]

VolumeTest::CPPUNIT_TEST ( testQuad4Warpage  )

◆ CPPUNIT_TEST() [14/24]

VolumeTest::CPPUNIT_TEST ( testQuad4MinMaxAngle  )

◆ CPPUNIT_TEST() [15/24]

VolumeTest::CPPUNIT_TEST ( testQuad4Jacobian  )

◆ CPPUNIT_TEST() [16/24]

VolumeTest::CPPUNIT_TEST ( testTri3AspectRatio  )

◆ CPPUNIT_TEST() [17/24]

VolumeTest::CPPUNIT_TEST ( testTet4DihedralAngle  )

◆ CPPUNIT_TEST() [18/24]

VolumeTest::CPPUNIT_TEST ( testTet4Jacobian  )

◆ CPPUNIT_TEST() [19/24]

VolumeTest::CPPUNIT_TEST ( testC0PolygonSquare  )

◆ CPPUNIT_TEST() [20/24]

VolumeTest::CPPUNIT_TEST ( testC0PolygonQuad  )

◆ CPPUNIT_TEST() [21/24]

VolumeTest::CPPUNIT_TEST ( testC0PolygonPentagon  )

◆ CPPUNIT_TEST() [22/24]

VolumeTest::CPPUNIT_TEST ( testC0PolygonHexagon  )

◆ CPPUNIT_TEST() [23/24]

VolumeTest::CPPUNIT_TEST ( testC0PolyhedronCube  )

◆ CPPUNIT_TEST() [24/24]

VolumeTest::CPPUNIT_TEST ( testC0PolyhedronHexagonalPrism  )

◆ CPPUNIT_TEST_SUITE_END()

VolumeTest::CPPUNIT_TEST_SUITE_END ( )

◆ LIBMESH_CPPUNIT_TEST_SUITE()

VolumeTest::LIBMESH_CPPUNIT_TEST_SUITE ( VolumeTest  )

◆ setUp()

void VolumeTest::setUp ( )
inline

Definition at line 57 of file volume_test.C.

58  {
59  }

◆ tearDown()

void VolumeTest::tearDown ( )
inline

Definition at line 61 of file volume_test.C.

62  {
63  }

◆ test_elem_invertible()

bool VolumeTest::test_elem_invertible ( const std::vector< Point > &  pts,
ElemType  elem_type 
)
inlineprotected

Definition at line 1271 of file volume_test.C.

References libMesh::libmesh_ignore().

1273  {
1274  // Construct Elem of desired type
1275  auto [elem, nodes] = this->construct_elem(pts, elem_type);
1276  libmesh_ignore(nodes);
1277 
1278  // Return whether or not this Elem has an invertible map
1279  return elem->has_invertible_map();
1280  }
void libmesh_ignore(const Args &...)
std::pair< std::unique_ptr< Elem >, std::vector< std::unique_ptr< Node > > > construct_elem(const std::vector< Point > &pts, ElemType elem_type)
Definition: volume_test.C:968

◆ test_true_centroid_and_volume()

void VolumeTest::test_true_centroid_and_volume ( ElemType  elem_type)
inlineprotected

Definition at line 1284 of file volume_test.C.

References libMesh::TypeVector< T >::absolute_fuzzy_equals(), libMesh::MeshTools::Generation::build_cube(), libMesh::MeshTools::Modification::distort(), mesh, libMesh::Real, TestCommWorld, and libMesh::TOLERANCE.

1285  {
1286  // Check that derived class true_centroid() gives same result as
1287  // the base class Elem::true_centroid() on a 2x2x2 mesh of 10%
1288  // distorted elements.
1289  {
1291 
1293  /*nelem=*/2, /*nelem=*/2, /*nelem=*/2,
1294  /*xmin=*/-1, /*xmax=*/1,
1295  /*ymin=*/-1, /*ymax=*/1,
1296  /*zmin=*/-1, /*zmax=*/1,
1297  elem_type);
1298 
1300  /*factor=*/0.1,
1301  /*perturb_boundary=*/false);
1302 
1303  for (const auto & elem : mesh.element_ptr_range())
1304  {
1305  Point derived_centroid = elem->true_centroid();
1306  Point base_centroid = elem->Elem::true_centroid();
1307 
1308  // Debugging: check results in detail
1309  // auto flags = libMesh::out.flags();
1310  // libMesh::out << std::scientific << std::setprecision(16);
1311  // libMesh::out << "derived_centroid = " << derived_centroid << std::endl;
1312  // libMesh::out << "base_centroid = " << base_centroid << std::endl;
1313  // libMesh::out.flags(flags);
1314 
1315  CPPUNIT_ASSERT(derived_centroid.absolute_fuzzy_equals(base_centroid, 50*TOLERANCE*TOLERANCE));
1316 
1317  // Make sure that base class and "optimized" routines for computing the cell volume agree
1318  Real derived_volume = elem->volume();
1319  Real base_volume = elem->Elem::volume();
1320  LIBMESH_ASSERT_FP_EQUAL(base_volume, derived_volume, 50*TOLERANCE*TOLERANCE);
1321  }
1322  }
1323  }
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
static constexpr Real TOLERANCE
void distort(MeshBase &mesh, const Real factor, const bool perturb_boundary=false)
Randomly perturb the nodal locations.
MeshBase & mesh
bool absolute_fuzzy_equals(const TypeVector< T > &rhs, Real tol=TOLERANCE) const
Definition: type_vector.h:975
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
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.

◆ testC0Polygon()

void VolumeTest::testC0Polygon ( const std::vector< Point > &  points,
Real  expected_volume 
)
inline

Definition at line 913 of file volume_test.C.

References libMesh::MeshBase::add_elem(), libMesh::MeshBase::add_point(), libMesh::make_range(), mesh, libMesh::Real, TestCommWorld, libMesh::TOLERANCE, and libMesh::Elem::volume().

915  {
917 
918  const auto np = points.size();
919  std::unique_ptr<Elem> polygon = std::make_unique<C0Polygon>(np);
920 
921  for (auto p : make_range(np))
922  polygon->set_node(p, mesh.add_point(points[p], p));
923 
924  polygon->set_id() = 0;
925  Elem * elem = mesh.add_elem(std::move(polygon));
926 
927  const Real derived_volume = elem->volume();
928  const Real base_volume = elem->Elem::volume();
929  LIBMESH_ASSERT_FP_EQUAL(base_volume, derived_volume, TOLERANCE*TOLERANCE);
930  LIBMESH_ASSERT_FP_EQUAL(derived_volume, expected_volume, TOLERANCE*TOLERANCE);
931 
932  this->testC0PolygonMethods(mesh, np);
933  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
static constexpr Real TOLERANCE
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & 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.
void testC0PolygonMethods(MeshBase &mesh, unsigned int n_sides)
Definition: volume_test.C:1012
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual Real volume() const
Definition: elem.C:3462
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
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testC0PolygonHexagon()

void VolumeTest::testC0PolygonHexagon ( )
inline

Definition at line 955 of file volume_test.C.

956  {
957  LOG_UNIT_TEST;
958  testC0Polygon({{0,0}, {1,0}, {1.5,0.5}, {1,1}, {0,1}, {-0.5, 0.5}}, 1.5);
959  }
void testC0Polygon(const std::vector< Point > &points, Real expected_volume)
Definition: volume_test.C:913

◆ testC0PolygonMethods()

void VolumeTest::testC0PolygonMethods ( MeshBase mesh,
unsigned int  n_sides 
)
inlineprotected

Definition at line 1012 of file volume_test.C.

References libMesh::C0POLYGON, libMesh::ParallelObject::comm(), libMesh::EDGE2, libMesh::Elem::flip(), libMesh::MeshBase::get_boundary_info(), libMesh::Elem::is_edge(), libMesh::Elem::is_face(), libMesh::Elem::is_flipped(), libMesh::Elem::is_node_on_edge(), libMesh::Elem::is_node_on_side(), libMesh::Elem::is_vertex(), libMesh::Elem::local_edge_node(), libMesh::Elem::local_side_node(), libMesh::make_range(), TIMPI::Communicator::max(), mesh, libMesh::Elem::n_edges(), libMesh::Elem::n_nodes(), libMesh::Elem::n_sides(), libMesh::Elem::n_sub_elem(), libMesh::Elem::n_vertices(), libMesh::MeshBase::node_ptr(), libMesh::Elem::nodes_on_edge(), libMesh::Elem::nodes_on_side(), libMesh::Elem::opposite_side(), libMesh::MeshBase::query_elem_ptr(), libMesh::Elem::side_ptr(), and libMesh::Elem::type().

1014  {
1015  Elem * elem = mesh.query_elem_ptr(0);
1016  bool found_elem = elem;
1017  mesh.comm().max(found_elem);
1018  CPPUNIT_ASSERT(found_elem);
1019 
1020  if (!elem)
1021  return;
1022 
1023  CPPUNIT_ASSERT_EQUAL(elem->type(), C0POLYGON);
1024  CPPUNIT_ASSERT_EQUAL(elem->n_nodes(), n_sides);
1025  CPPUNIT_ASSERT_EQUAL(elem->n_sub_elem(), n_sides);
1026  CPPUNIT_ASSERT_EQUAL(elem->n_sides(), n_sides);
1027  CPPUNIT_ASSERT_EQUAL(elem->n_vertices(), n_sides);
1028  CPPUNIT_ASSERT_EQUAL(elem->n_edges(), n_sides);
1029 
1030  // Even number of sides
1031  if (!(n_sides%2))
1032  {
1033  const unsigned int nsover2 = n_sides/2;
1034  for (auto i : make_range(nsover2))
1035  {
1036  CPPUNIT_ASSERT_EQUAL(elem->opposite_side(i), i+nsover2);
1037  CPPUNIT_ASSERT_EQUAL(elem->opposite_side(i+nsover2), i);
1038  }
1039  }
1040 
1041  for (unsigned int i : make_range(n_sides))
1042  {
1043  CPPUNIT_ASSERT(elem->is_vertex(i));
1044  CPPUNIT_ASSERT(!elem->is_edge(i));
1045  CPPUNIT_ASSERT(!elem->is_face(i));
1046  CPPUNIT_ASSERT(elem->is_node_on_side(i,i));
1047  CPPUNIT_ASSERT(elem->is_node_on_edge(i,i));
1048  CPPUNIT_ASSERT(elem->is_node_on_side((i+1)%n_sides,i));
1049  CPPUNIT_ASSERT(elem->is_node_on_edge((i+1)%n_sides,i));
1050  std::vector<unsigned int> nodes = elem->nodes_on_side(i);
1051  CPPUNIT_ASSERT_EQUAL(nodes.size(), std::size_t(2));
1052  CPPUNIT_ASSERT(nodes[0] == i ||
1053  nodes[1] == i);
1054  CPPUNIT_ASSERT(nodes[0] == (i+1)%n_sides ||
1055  nodes[1] == (i+1)%n_sides);
1056  std::vector<unsigned int> edge_nodes = elem->nodes_on_edge(i);
1057  CPPUNIT_ASSERT(nodes == edge_nodes);
1058 
1059 
1060  CPPUNIT_ASSERT_EQUAL(elem->local_side_node(i,0), i);
1061  CPPUNIT_ASSERT_EQUAL(elem->local_side_node(i,1), (i+1)%n_sides);
1062  CPPUNIT_ASSERT_EQUAL(elem->local_edge_node(i,0), i);
1063  CPPUNIT_ASSERT_EQUAL(elem->local_edge_node(i,1), (i+1)%n_sides);
1064 
1065  auto edge = elem->side_ptr(i);
1066  CPPUNIT_ASSERT_EQUAL(edge->type(), EDGE2);
1067  CPPUNIT_ASSERT_EQUAL(edge->node_ptr(0), mesh.node_ptr(i));
1068  CPPUNIT_ASSERT_EQUAL(edge->node_ptr(1), mesh.node_ptr((i+1)%n_sides));
1069  }
1070 
1071  CPPUNIT_ASSERT(!elem->is_flipped());
1072  elem->flip(&mesh.get_boundary_info());
1073  CPPUNIT_ASSERT(elem->is_flipped());
1074  elem->flip(&mesh.get_boundary_info());
1075  }
virtual bool is_face(const unsigned int i) const =0
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
const Parallel::Communicator & comm() const
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:170
virtual bool is_flipped() const =0
virtual bool is_node_on_edge(const unsigned int n, const unsigned int e) const =0
virtual unsigned int n_nodes() const =0
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const =0
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 ...
virtual unsigned int n_edges() const =0
virtual void flip(BoundaryInfo *boundary_info)=0
Flips the element (by swapping node and neighbor pointers) to have a mapping Jacobian of opposite sig...
virtual std::vector< unsigned int > nodes_on_edge(const unsigned int) const =0
virtual unsigned int n_sides() const =0
virtual unsigned int n_vertices() const =0
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
virtual bool is_vertex(const unsigned int i) const =0
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
virtual unsigned int n_sub_elem() const =0
virtual const Node * node_ptr(const dof_id_type i) const =0
virtual unsigned int opposite_side(const unsigned int s) const
Definition: elem.C:3556
virtual ElemType type() const =0
virtual bool is_edge(const unsigned int i) const =0
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0

◆ testC0PolygonPentagon()

void VolumeTest::testC0PolygonPentagon ( )
inline

Definition at line 949 of file volume_test.C.

950  {
951  LOG_UNIT_TEST;
952  testC0Polygon({{0,0}, {1,0}, {1.5,0.5}, {1,1}, {0,1}}, 1.25);
953  }
void testC0Polygon(const std::vector< Point > &points, Real expected_volume)
Definition: volume_test.C:913

◆ testC0PolygonQuad()

void VolumeTest::testC0PolygonQuad ( )
inline

Definition at line 943 of file volume_test.C.

944  {
945  LOG_UNIT_TEST;
946  testC0Polygon({{0,0}, {1,0}, {1,2}, {-1,1}}, 2.5);
947  }
void testC0Polygon(const std::vector< Point > &points, Real expected_volume)
Definition: volume_test.C:913

◆ testC0PolygonSquare()

void VolumeTest::testC0PolygonSquare ( )
inline

Definition at line 937 of file volume_test.C.

938  {
939  LOG_UNIT_TEST;
940  testC0Polygon({{0,0}, {1,0}, {1,1}, {0,1}}, 1);
941  }
void testC0Polygon(const std::vector< Point > &points, Real expected_volume)
Definition: volume_test.C:913

◆ testC0PolyhedronCube()

void VolumeTest::testC0PolyhedronCube ( )
inlineprotected

Definition at line 1161 of file volume_test.C.

References libMesh::MeshBase::add_point(), libMesh::index_range(), libMesh::invalid_int, mesh, libMesh::MeshBase::node_ptr(), and TestCommWorld.

1162  {
1164 
1165  mesh.add_point(Point(0, 0, 0), 0);
1166  mesh.add_point(Point(1, 0, 0), 1);
1167  mesh.add_point(Point(1, 1, 0), 2);
1168  mesh.add_point(Point(0, 1, 0), 3);
1169  mesh.add_point(Point(0, 0, 1), 4);
1170  mesh.add_point(Point(1, 0, 1), 5);
1171  mesh.add_point(Point(1, 1, 1), 6);
1172  mesh.add_point(Point(0, 1, 1), 7);
1173 
1174  // See notes in elem_test.h
1175  const std::vector<std::vector<unsigned int>> nodes_on_side =
1176  { {0, 1, 2, 3}, // min z
1177  {0, 1, 5, 4}, // min y
1178  {2, 6, 5, 1}, // max x
1179  {2, 3, 7, 6}, // max y
1180  {0, 4, 7, 3}, // min x
1181  {5, 6, 7, 4} }; // max z
1182 
1183  // Build all the sides.
1184  std::vector<std::shared_ptr<Polygon>> sides(nodes_on_side.size());
1185 
1186  for (auto s : index_range(nodes_on_side))
1187  {
1188  const auto & nodes_on_s = nodes_on_side[s];
1189  sides[s] = std::make_shared<C0Polygon>(nodes_on_s.size());
1190  for (auto i : index_range(nodes_on_s))
1191  sides[s]->set_node(i, mesh.node_ptr(nodes_on_s[i]));
1192  }
1193 
1194  const auto poly = dynamic_cast<C0Polyhedron *>(buildC0Polyhedron(sides, mesh));
1195  testElemVolume(poly, 1);
1196  #ifdef LIBMESH_ENABLE_EXCEPTIONS
1197  testC0PolyhedronMethods(mesh, /*midnode*/false);
1198 
1199  // Check routine for subtet side to poly side mapping
1200  // NOTE: this test is hard coded to the elements used right now (to be reworked)
1201  const auto subtet0_sides_to_poly_sides = poly->subelement_sides_to_poly_sides(0);
1202  CPPUNIT_ASSERT_EQUAL(libMesh::invalid_int, subtet0_sides_to_poly_sides[0]);
1203  CPPUNIT_ASSERT_EQUAL(1, subtet0_sides_to_poly_sides[1]);
1204  CPPUNIT_ASSERT_EQUAL(0, subtet0_sides_to_poly_sides[2]);
1205  CPPUNIT_ASSERT_EQUAL(2, subtet0_sides_to_poly_sides[3]);
1206  #else
1207  testC0PolyhedronMethods(mesh, /*midnode*/true);
1208  #endif
1209  }
Elem * buildC0Polyhedron(std::vector< std::shared_ptr< Polygon >> sides, MeshBase &mesh)
Definition: volume_test.C:997
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testC0PolyhedronMethods(MeshBase &mesh, bool has_midnode)
Definition: volume_test.C:1079
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.
void testElemVolume(const Elem *elem, Real expected_volume)
Definition: volume_test.C:1150
const int invalid_int
A number which is used quite often to represent an invalid or uninitialized value for an integer...
Definition: libmesh.h:309
The C0Polyhedron is an element in 3D with an arbitrary (but fixed) number of polygonal first-order (C...
virtual const Node * node_ptr(const dof_id_type i) const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
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

◆ testC0PolyhedronHexagonalPrism()

void VolumeTest::testC0PolyhedronHexagonalPrism ( )
inlineprotected

Definition at line 1213 of file volume_test.C.

References libMesh::MeshBase::add_point(), libMesh::index_range(), libMesh::invalid_int, mesh, libMesh::MeshBase::node_ptr(), and TestCommWorld.

1214  {
1216 
1217  mesh.add_point(Point(0, -2, 0), 0);
1218  mesh.add_point(Point(-1, -1, 0), 1);
1219  mesh.add_point(Point(-1, 1, 0), 2);
1220  mesh.add_point(Point(0, 2, 0), 3);
1221  mesh.add_point(Point(1, 1, 0), 4);
1222  mesh.add_point(Point(1, -1, 0), 5);
1223  mesh.add_point(Point(0, -2, 1), 6);
1224  mesh.add_point(Point(-1, -1, 1), 7);
1225  mesh.add_point(Point(-1, 1, 1), 8);
1226  mesh.add_point(Point(0, 2, 1), 9);
1227  mesh.add_point(Point(1, 1, 1), 10);
1228  mesh.add_point(Point(1, -1, 1), 11);
1229 
1230  // See notes in elem_test.h
1231  // With this ordering, we'll need to use a mid-node to tetrahedralize it
1232  const std::vector<std::vector<unsigned int>> nodes_on_side =
1233  { {0, 1, 2, 3, 4, 5},
1234  {0, 1, 7, 6},
1235  {1, 2, 8, 7},
1236  {2, 3, 9, 8},
1237  {3, 4, 10, 9},
1238  {4, 5, 11, 10},
1239  {5, 0, 6, 11},
1240  {6, 7, 8, 9, 10, 11} };
1241 
1242  // Build all the sides.
1243  std::vector<std::shared_ptr<Polygon>> sides(nodes_on_side.size());
1244 
1245  for (auto s : index_range(nodes_on_side))
1246  {
1247  const auto & nodes_on_s = nodes_on_side[s];
1248  sides[s] = std::make_shared<C0Polygon>(nodes_on_s.size());
1249  for (auto i : index_range(nodes_on_s))
1250  sides[s]->set_node(i, mesh.node_ptr(nodes_on_s[i]));
1251  }
1252 
1253  const auto poly = dynamic_cast<C0Polyhedron *>(buildC0Polyhedron(sides, mesh));
1254  CPPUNIT_ASSERT_EQUAL((unsigned int)13, poly->n_nodes()); // we should have a mid node
1255  testElemVolume(poly, 6);
1256  testC0PolyhedronMethods(mesh, /*midnode*/true);
1257 
1258  // Check routine for subtet side to poly side mapping
1259  const auto subtet0_sides_to_poly_sides = poly->subelement_sides_to_poly_sides(0);
1260  CPPUNIT_ASSERT_EQUAL(0, subtet0_sides_to_poly_sides[0]);
1261  CPPUNIT_ASSERT_EQUAL(libMesh::invalid_int, subtet0_sides_to_poly_sides[1]);
1262  CPPUNIT_ASSERT_EQUAL(libMesh::invalid_int, subtet0_sides_to_poly_sides[2]);
1263  CPPUNIT_ASSERT_EQUAL(libMesh::invalid_int, subtet0_sides_to_poly_sides[3]);
1264  }
Elem * buildC0Polyhedron(std::vector< std::shared_ptr< Polygon >> sides, MeshBase &mesh)
Definition: volume_test.C:997
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testC0PolyhedronMethods(MeshBase &mesh, bool has_midnode)
Definition: volume_test.C:1079
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.
void testElemVolume(const Elem *elem, Real expected_volume)
Definition: volume_test.C:1150
const int invalid_int
A number which is used quite often to represent an invalid or uninitialized value for an integer...
Definition: libmesh.h:309
The C0Polyhedron is an element in 3D with an arbitrary (but fixed) number of polygonal first-order (C...
virtual const Node * node_ptr(const dof_id_type i) const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
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

◆ testC0PolyhedronMethods()

void VolumeTest::testC0PolyhedronMethods ( MeshBase mesh,
bool  has_midnode 
)
inlineprotected

Definition at line 1079 of file volume_test.C.

References libMesh::Elem::build_side_ptr(), libMesh::C0POLYGON, libMesh::C0POLYHEDRON, libMesh::ParallelObject::comm(), libMesh::Elem::get_node_index(), libMesh::invalid_uint, libMesh::Elem::is_edge(), libMesh::Elem::is_face(), libMesh::Elem::is_flipped(), libMesh::Elem::is_node_on_side(), libMesh::Elem::is_vertex(), libMesh::make_range(), TIMPI::Communicator::max(), mesh, libMesh::Elem::n_edges(), libMesh::Elem::n_faces(), libMesh::Elem::n_nodes(), libMesh::Elem::n_sides(), libMesh::Elem::n_vertices(), libMesh::Elem::nodes_on_side(), libMesh::MeshBase::query_elem_ptr(), and libMesh::Elem::type().

1080  {
1081  Elem * elem = mesh.query_elem_ptr(0);
1082  bool found_elem = elem;
1083  mesh.comm().max(found_elem);
1084  CPPUNIT_ASSERT(found_elem);
1085 
1086  if (!elem)
1087  return;
1088 
1089  CPPUNIT_ASSERT_EQUAL(elem->type(), C0POLYHEDRON);
1090 
1091  const int V = elem->n_vertices();
1092  const int E = elem->n_edges();
1093  const int F = elem->n_faces();
1094 
1095  if (!has_midnode)
1096  CPPUNIT_ASSERT_EQUAL(int(elem->n_nodes()), V);
1097  else
1098  CPPUNIT_ASSERT_EQUAL(int(elem->n_nodes()), V + 1);
1099  CPPUNIT_ASSERT_EQUAL(int(elem->n_sides()), F);
1100 
1101  // Euler characteristic for polygons homeomorphic to spheres is 2
1102  CPPUNIT_ASSERT_EQUAL(V-E+F, 2);
1103 
1104  int FE = 0;
1105  int FV = 0;
1106 
1107  std::vector<int> sides_on_vertex(V, 0);
1108  for (auto s : make_range(F))
1109  {
1110  auto side = elem->build_side_ptr(s);
1111  CPPUNIT_ASSERT_EQUAL(side->type(), C0POLYGON);
1112  FE += side->n_edges();
1113  const int SV = side->n_vertices();
1114  FV += SV;
1115 
1116  auto nos = elem->nodes_on_side(s);
1117  CPPUNIT_ASSERT_EQUAL(nos.size(), std::size_t(SV));
1118 
1119  for (auto v : make_range(SV))
1120  {
1121  Node * sidenode = side->node_ptr(v);
1122  const unsigned int n = elem->get_node_index(sidenode);
1123  CPPUNIT_ASSERT(n != invalid_uint);
1124  ++sides_on_vertex[n];
1125 
1126  // We're just looking at first order so far
1127  CPPUNIT_ASSERT(side->is_vertex(v));
1128  CPPUNIT_ASSERT(!side->is_edge(v));
1129  CPPUNIT_ASSERT(elem->is_vertex(n));
1130  CPPUNIT_ASSERT(!elem->is_edge(n));
1131  CPPUNIT_ASSERT(!elem->is_face(n));
1132  CPPUNIT_ASSERT(elem->is_node_on_side(n, s));
1133  CPPUNIT_ASSERT(std::find(nos.begin(), nos.end(), n) != nos.end());
1134  }
1135  }
1136 
1137  // We hit every edge from 2 faces
1138  CPPUNIT_ASSERT_EQUAL(E*2, FE);
1139 
1140  // We hit every vertex from at least 3 faces
1141  CPPUNIT_ASSERT_LESSEQUAL(FV, V*3); // V*3 <= FV
1142  for (auto sov : sides_on_vertex)
1143  CPPUNIT_ASSERT_LESSEQUAL(sov, 3); // 3 <= sov
1144 
1145  CPPUNIT_ASSERT(!elem->is_flipped());
1146  }
A Node is like a Point, but with more information.
Definition: node.h:52
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
Definition: libmesh.h:303
unsigned int get_node_index(const Node *node_ptr) const
Definition: elem.h:2551
virtual bool is_face(const unsigned int i) const =0
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i)=0
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
const Parallel::Communicator & comm() const
virtual bool is_flipped() const =0
A specific instantiation of the FEBase class.
Definition: fe.h:127
virtual unsigned int n_nodes() const =0
virtual unsigned int n_edges() const =0
virtual unsigned int n_sides() const =0
virtual unsigned int n_vertices() const =0
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
void max(const T &r, T &o, Request &req) const
virtual bool is_vertex(const unsigned int i) const =0
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
virtual unsigned int n_faces() const =0
virtual ElemType type() const =0
virtual bool is_edge(const unsigned int i) const =0
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0

◆ testEdge3Invertible()

void VolumeTest::testEdge3Invertible ( )
inline

Definition at line 245 of file volume_test.C.

References libMesh::EDGE3.

246  {
247  LOG_UNIT_TEST;
248 
249  // 1.) This is the original test which started the investigation
250  // of determining invertibility. In this test, the actual
251  // midpoint of nodes 0 and 1 is 0.5*(1.100328e2 + 1.176528e2) =
252  // 113.8428, so we can see that the middle node is closer to the
253  // left endpoint. In this case, it is too close and the element is
254  // not invertible.
255  bool invertible = test_elem_invertible({
256  Point(-3.566160e1, -6.690970e-1, 1.100328e2),
257  Point(-3.566160e1, -6.690970e-1, 1.176528e2),
258  Point(-3.566160e1, -6.690970e-1, 1.115568e2)}, EDGE3);
259  CPPUNIT_ASSERT(!invertible);
260 
261  // 2.) Just like case 1, but now node 2 is at the midpoint, so
262  // this case is invertible.
263  invertible = test_elem_invertible({
264  Point(-3.566160e1, -6.690970e-1, 1.100328e2),
265  Point(-3.566160e1, -6.690970e-1, 1.176528e2),
266  Point(-3.566160e1, -6.690970e-1, 113.8428)}, EDGE3);
267  CPPUNIT_ASSERT(invertible);
268 
269  // 3.) Non-collinear case where the mid-edge node is "above" and "way
270  // past" the right endpoint. This case is not invertible
271  invertible = test_elem_invertible({Point(0, 0, 0), Point(1, 0, 0), Point(3.5, 1.5, 0)}, EDGE3);
272  CPPUNIT_ASSERT(!invertible);
273  }
bool test_elem_invertible(const std::vector< Point > &pts, ElemType elem_type)
Definition: volume_test.C:1271
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39

◆ testEdge3Volume()

void VolumeTest::testEdge3Volume ( )
inline

Definition at line 201 of file volume_test.C.

References libMesh::MeshTools::Generation::build_line(), libMesh::EDGE3, mesh, libMesh::MeshBase::n_nodes(), libMesh::Elem::node_ref(), libMesh::MeshBase::query_elem_ptr(), TestCommWorld, and libMesh::TOLERANCE.

202  {
203  LOG_UNIT_TEST;
204 
206  MeshTools::Generation::build_line (mesh, /*nelem=*/1, 0., 1., EDGE3);
207  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(3), mesh.n_nodes());
208 
209  auto edge3 = mesh.query_elem_ptr(0);
210  if (!edge3) // We may be on a distributed mesh
211  return;
212 
213  // Check unperturbed, straight edge case
214  LIBMESH_ASSERT_FP_EQUAL(1.0, edge3->volume(), TOLERANCE*TOLERANCE);
215 
216  // Get references to the individual Edge3 nodes
217  auto & middle_node = edge3->node_ref(2);
218  auto & right_node = edge3->node_ref(1);
219 
220  // Check middle node perturbed in +x direction case. This should
221  // not change the volume because it's still a straight line
222  // element.
223  middle_node = Point(0.5 + 1.e-3, 0., 0.);
224  LIBMESH_ASSERT_FP_EQUAL(1.0, edge3->volume(), TOLERANCE*TOLERANCE);
225 
226  // Check middle node perturbed in -x direction case. This should
227  // not change the volume because it's still a straight line
228  // element.
229  middle_node = Point(0.5 - 1.e-3, 0., 0.);
230  LIBMESH_ASSERT_FP_EQUAL(1.0, edge3->volume(), TOLERANCE*TOLERANCE);
231 
232  // Check volume of actual curved element against pre-computed value.
233  middle_node = Point(0.5, 0.25, 0.);
234  right_node = Point(1., 1., 0.);
235  LIBMESH_ASSERT_FP_EQUAL(1.4789428575446, edge3->volume(), TOLERANCE);
236 
237  // Compare with volume computed by base class Elem::volume() call
238  // which uses quadrature. We don't expect this to have full
239  // floating point accuracy.
240  middle_node = Point(0.5, 0.1, 0.);
241  right_node = Point(1., 0., 0.);
242  LIBMESH_ASSERT_FP_EQUAL(edge3->Elem::volume(), edge3->volume(), 1e-4);
243  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
static constexpr Real TOLERANCE
MeshBase & mesh
const Node & node_ref(const unsigned int i) const
Definition: elem.h:2535
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
void build_line(UnstructuredMesh &mesh, const unsigned int nx, const Real xmin=0., const Real xmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 1D meshes.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
virtual dof_id_type n_nodes() const =0

◆ testEdge4Invertible()

void VolumeTest::testEdge4Invertible ( )
inline

Definition at line 275 of file volume_test.C.

References libMesh::EDGE4, libMesh::ReferenceElem::get(), libMesh::Elem::has_invertible_map(), and libMesh::Real.

276  {
277  LOG_UNIT_TEST;
278 
279  // Reference Elem should be invertible
280  {
281  const Elem & edge4 = ReferenceElem::get(EDGE4);
282  CPPUNIT_ASSERT(edge4.has_invertible_map());
283  }
284 
285  // If node 2 goes to the left past -5/9 = -.555, the element becomes non-invertible
286  {
287  // x2 > -5/9, the map is still invertible
288  bool invertible =
289  test_elem_invertible({Point(-1, 0, 0), Point(1, 0, 0), Point(-0.5, 0, 0), Point(Real(1)/3, 0, 0)},
290  EDGE4);
291  CPPUNIT_ASSERT(invertible);
292 
293  // x2 < -5/9, it is too close to x0 now
294  invertible =
295  test_elem_invertible({Point(-1, 0, 0), Point(1, 0, 0), Point(-0.57, 0, 0), Point(Real(1)/3, 0, 0)},
296  EDGE4);
297  CPPUNIT_ASSERT(!invertible);
298  }
299 
300  // If node 2 goes to the right past 5/21 ~ 0.2381, the element becomes non-invertible
301  {
302  // x2 < 5/21, the map should still be invertible
303  bool invertible =
304  test_elem_invertible({Point(-1, 0, 0), Point(1, 0, 0), Point(Real(3)/21, 0, 0), Point(Real(1)/3, 0, 0)},
305  EDGE4);
306  CPPUNIT_ASSERT(invertible);
307 
308  // x2 > 5/21, x2 is too close to x3 now
309  invertible =
310  test_elem_invertible({Point(-1, 0, 0), Point(1, 0, 0), Point(Real(6)/21, 0, 0), Point(Real(1)/3, 0, 0)},
311  EDGE4);
312  CPPUNIT_ASSERT(!invertible);
313  }
314  }
bool test_elem_invertible(const std::vector< Point > &pts, ElemType elem_type)
Definition: volume_test.C:1271
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual bool has_invertible_map(Real tol=TOLERANCE *TOLERANCE) const
Definition: elem.C:2914
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const Elem & get(const ElemType type_in)

◆ testElemVolume()

void VolumeTest::testElemVolume ( const Elem elem,
Real  expected_volume 
)
inlineprotected

Definition at line 1150 of file volume_test.C.

References libMesh::Real, libMesh::TOLERANCE, and libMesh::Elem::volume().

1152  {
1153  const Real derived_volume = elem->volume();
1154  const Real base_volume = elem->Elem::volume();
1155  LIBMESH_ASSERT_FP_EQUAL(base_volume, derived_volume, TOLERANCE*TOLERANCE);
1156  LIBMESH_ASSERT_FP_EQUAL(derived_volume, expected_volume, TOLERANCE*TOLERANCE);
1157  }
static constexpr Real TOLERANCE
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual Real volume() const
Definition: elem.C:3462

◆ testHex20PLevelTrueCentroid()

void VolumeTest::testHex20PLevelTrueCentroid ( )
inline

Definition at line 150 of file volume_test.C.

References libMesh::MeshTools::Generation::build_cube(), libMesh::MeshBase::elem_ptr(), libMesh::HEX20, mesh, libMesh::Elem::set_p_level(), TestCommWorld, libMesh::TOLERANCE, and libMesh::Elem::true_centroid().

151  {
152  LOG_UNIT_TEST;
153 
154  // Test that Elem base class true_centroid() implementation works
155  // for an elevated p_level HEX20
156  {
157 #ifdef LIBMESH_ENABLE_AMR
160  /*nelem=*/1, /*nelem=*/1, /*nelem=*/1,
161  /*xmin=*/-1, /*xmax=*/1,
162  /*ymin=*/-1, /*ymax=*/1,
163  /*zmin=*/-1, /*zmax=*/1,
164  HEX20);
165  Elem * hex20 = mesh.elem_ptr(0);
166  hex20->set_p_level(1);
167  Point true_centroid = hex20->true_centroid();
168  LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(0), TOLERANCE*TOLERANCE);
169  LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(1), TOLERANCE*TOLERANCE);
170  LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(2), TOLERANCE*TOLERANCE);
171 #endif // LIBMESH_ENABLE_AMR
172  }
173  }
virtual Point true_centroid() const
Definition: elem.C:575
void set_p_level(const unsigned int p)
Sets the value of the p-refinement level for the element.
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
static constexpr Real TOLERANCE
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
virtual const Elem * elem_ptr(const dof_id_type i) const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
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.

◆ testHex8TrueCentroid()

void VolumeTest::testHex8TrueCentroid ( )
inline

Definition at line 147 of file volume_test.C.

References libMesh::HEX8.

147 { LOG_UNIT_TEST; test_true_centroid_and_volume(HEX8); }
void test_true_centroid_and_volume(ElemType elem_type)
Definition: volume_test.C:1284

◆ testPrism6TrueCentroid()

void VolumeTest::testPrism6TrueCentroid ( )
inline

Definition at line 148 of file volume_test.C.

References libMesh::PRISM6.

148 { LOG_UNIT_TEST; test_true_centroid_and_volume(PRISM6); }
void test_true_centroid_and_volume(ElemType elem_type)
Definition: volume_test.C:1284

◆ testPyramid5TrueCentroid()

void VolumeTest::testPyramid5TrueCentroid ( )
inline

Definition at line 130 of file volume_test.C.

References libMesh::ReferenceElem::get(), libMesh::PYRAMID5, libMesh::TOLERANCE, and libMesh::Elem::true_centroid().

131  {
132  LOG_UNIT_TEST;
133 
134  // Test Pyramid5::true_centroid() gives the correct result for a reference element
135  {
136  const Elem & pyr5 = ReferenceElem::get(PYRAMID5);
137  Point true_centroid = pyr5.true_centroid();
138  LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(0), TOLERANCE*TOLERANCE);
139  LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(1), TOLERANCE*TOLERANCE);
140  LIBMESH_ASSERT_FP_EQUAL(0.25, true_centroid(2), TOLERANCE*TOLERANCE);
141  }
142 
143  // Currently there is not an optimized Pyramid5::true_centroid() to compare against
145  }
virtual Point true_centroid() const
Definition: elem.C:575
static constexpr Real TOLERANCE
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
void test_true_centroid_and_volume(ElemType elem_type)
Definition: volume_test.C:1284
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const Elem & get(const ElemType type_in)

◆ testQuad4AspectRatio()

void VolumeTest::testQuad4AspectRatio ( )
inline

Definition at line 407 of file volume_test.C.

References libMesh::ASPECT_RATIO, libMesh::libmesh_ignore(), libMesh::pi, libMesh::QUAD4, libMesh::Real, and libMesh::TOLERANCE.

408  {
409  LOG_UNIT_TEST;
410 
411  // Case 1: Test that rigid body rotations of a unit square
412  // quadrilateral that have no effect on the quality of the
413  // element.
414  {
415  // Construct unit square QUAD4
416  std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(1, 1, 0), Point(0, 1, 0)};
417  auto [elem, nodes] = this->construct_elem(pts, QUAD4);
418  libmesh_ignore(nodes);
419 
420  // 1a) Unit square aspect ratio should be == 1
421  Real aspect_ratio = elem->quality(ASPECT_RATIO);
422  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0, /*actual=*/aspect_ratio, TOLERANCE);
423 
424  // 1b) Rotate all points about x-axis by 90 degrees
425  Real cost = std::cos(.5*libMesh::pi);
426  Real sint = std::sin(.5*libMesh::pi);
427  RealTensorValue Rx(1, 0, 0,
428  0, cost, sint,
429  0, sint, cost);
430 
431  for (auto & pt : pts)
432  pt = Rx * pt;
433 
434  aspect_ratio = elem->quality(ASPECT_RATIO);
435  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0, /*actual=*/aspect_ratio, TOLERANCE);
436 
437  // 1c) Rotate all points about z-axis by 90 degrees
438  RealTensorValue Rz(cost, -sint, 0,
439  sint, cost, 0,
440  0, 0, 1);
441 
442  for (auto & pt : pts)
443  pt = Rz * pt;
444 
445  aspect_ratio = elem->quality(ASPECT_RATIO);
446  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0, /*actual=*/aspect_ratio, TOLERANCE);
447 
448  // 1d) Rotate all points about y-axis by 270 degrees
449  RealTensorValue Ry(cost, 0, sint,
450  0, 1, 0,
451  -sint, 0, cost);
452 
453  for (int cnt=0; cnt<3; ++cnt)
454  for (auto & pt : pts)
455  pt = Ry * pt;
456 
457  aspect_ratio = elem->quality(ASPECT_RATIO);
458  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0, /*actual=*/aspect_ratio, TOLERANCE);
459  }
460 
461  // Case 2: Rhombus QUAD4. This case should have an aspect ratio of
462  // 1/sin(theta), where theta is the acute interior angle of the
463  // rhombus.
464  {
465  // Helper lambda function that constructs a rhombus quad with
466  // interior acute angle theta.
467  auto test_rhombus_quad = [this](Real theta)
468  {
469  Real ct = std::cos(theta);
470  Real st = std::sin(theta);
471  std::vector<Point> pts = {
472  Point(0, 0, 0),
473  Point(1, 0, 0),
474  Point(1. + ct, st, 0),
475  Point( ct, st, 0)};
476  auto [elem, nodes] = this->construct_elem(pts, QUAD4);
477  libmesh_ignore(nodes);
478 
479  // The expected aspect ratio for the rhombus is 1/sin(theta)
480  Real aspect_ratio = elem->quality(ASPECT_RATIO);
481  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0/st, /*actual=*/aspect_ratio, TOLERANCE);
482  };
483 
484  // 2a) Rhombus with interior angle theta=pi/6. The expected
485  // aspect ratio in this case is 1/std::sin(pi/6) = 2
486  test_rhombus_quad(libMesh::pi / 6);
487 
488  // 2b) Rhombus with interior angle theta=pi/3. The expected
489  // aspect ratio in this case is 1/std::sin(pi/3) = 2/sqrt(3) = 1.155
490  test_rhombus_quad(libMesh::pi / 3);
491  }
492 
493  // Case 3) Rectangle QUAD4. The "old" and "new" aspect ratio metrics
494  // return the same result for this case, whih is simply the ratio of
495  // the longest to shortest side.
496  {
497  auto test_rectangle_quad = [this](Real a)
498  {
499  std::vector<Point> pts = {Point(0, 0, 0), Point(a, 0, 0), Point(a, 1, 0), Point(0, 1, 0)};
500  auto [elem, nodes] = this->construct_elem(pts, QUAD4);
501  libmesh_ignore(nodes);
502 
503  // The expected aspect ratio for the rectangle is "a"
504  Real aspect_ratio = elem->quality(ASPECT_RATIO);
505  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/a, /*actual=*/aspect_ratio, TOLERANCE);
506  };
507 
508  // 3a) Test case twice as long as it is tall
509  test_rectangle_quad(2.0);
510 
511  // 3b) Test no funny numerical stuff with extremely stretched case
512  test_rectangle_quad(1e6);
513  }
514 
515  // Case 4) Degenerate QUAD with zero length side. In the "old"
516  // aspect ratio metric we'd just get zero (as a stand-in for
517  // infinity) for this case since the minimum side length is zero,
518  // but using the new metric we get a non-zero value of 2.5. Thus,
519  // in the new metric it is possible to compare the aspect ratios
520  // of different degenerate QUAD elements rather than simply
521  // assigning all such elements a quality value of 0. Degenerate
522  // quadrilaterals are sometimes used as a "hack" to avoid having a
523  // separate subdomain of TRIs, and (surprisingly) many finite
524  // element operations just "work" on such elements.
525  {
526  std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(1, 0, 0), Point(0, 1, 0)};
527  auto [elem, nodes] = this->construct_elem(pts, QUAD4);
528  libmesh_ignore(nodes);
529 
530  Real aspect_ratio = elem->quality(ASPECT_RATIO);
531  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/2.5, /*actual=*/aspect_ratio, TOLERANCE);
532  }
533 
534  // Case 5) Trapezoid QUAD
535  {
536  auto test_trapezoid_quad = [this](Real a)
537  {
538  // 0 <= a <= 1/2
539  std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(1-a, 1, 0), Point(a, 1, 0)};
540  auto [elem, nodes] = this->construct_elem(pts, QUAD4);
541  libmesh_ignore(nodes);
542 
543  Real aspect_ratio = elem->quality(ASPECT_RATIO);
544  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1./(1. - a), /*actual=*/aspect_ratio, TOLERANCE);
545  };
546 
547  // 3a) Test "simple" trapezoid with expected aspect ratio 1.5
548  test_trapezoid_quad(1./3);
549 
550  // 3b) Test "degenerate" trapezoid with one zero length base
551  test_trapezoid_quad(0.5);
552  }
553  }
static constexpr Real TOLERANCE
void libmesh_ignore(const Args &...)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::pair< std::unique_ptr< Elem >, std::vector< std::unique_ptr< Node > > > construct_elem(const std::vector< Point > &pts, ElemType elem_type)
Definition: volume_test.C:968
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
const Real pi
.
Definition: libmesh.h:292

◆ testQuad4Invertible()

void VolumeTest::testQuad4Invertible ( )
inline

Definition at line 316 of file volume_test.C.

References libMesh::pi, libMesh::QUAD4, and libMesh::Real.

317  {
318  LOG_UNIT_TEST;
319 
320  // Case 1: Test that rigid body rotations have no effect on the
321  // invertibility of the reference element
322  {
323  // 1a) The reference element rotated into various different different planes.
324  std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(1, 1, 0), Point(0, 1, 0)};
325  bool invertible = test_elem_invertible(pts, QUAD4);
326  CPPUNIT_ASSERT(invertible);
327 
328  // 1b) Rotate all points about x-axis by 90 degrees
329  Real cost = std::cos(.5*libMesh::pi);
330  Real sint = std::sin(.5*libMesh::pi);
331  RealTensorValue Rx(1, 0, 0,
332  0, cost, sint,
333  0, sint, cost);
334 
335  for (auto & pt : pts)
336  pt = Rx * pt;
337 
338  invertible = test_elem_invertible(pts, QUAD4);
339  CPPUNIT_ASSERT(invertible);
340 
341  // 1c) Rotate all points about z-axis by 90 degrees
342  RealTensorValue Rz(cost, -sint, 0,
343  sint, cost, 0,
344  0, 0, 1);
345 
346  for (auto & pt : pts)
347  pt = Rz * pt;
348 
349  invertible = test_elem_invertible(pts, QUAD4);
350  CPPUNIT_ASSERT(invertible);
351 
352  // 1d) Rotate all points about y-axis by 270 degrees
353  RealTensorValue Ry(cost, 0, sint,
354  0, 1, 0,
355  -sint, 0, cost);
356 
357  for (int cnt=0; cnt<3; ++cnt)
358  for (auto & pt : pts)
359  pt = Ry * pt;
360 
361  invertible = test_elem_invertible(pts, QUAD4);
362  CPPUNIT_ASSERT(invertible);
363  }
364 
365  // Case 2: Planar quad with top right vertex displaced to the position
366  // (alpha, alpha). Some different cases are described below.
367  // .) alpha==1: affine case, always invertible
368  // .) 1/2 < alpha < 1: planar case, invertible
369  // .) alpha<=1/2: planar case but node is now at center of the
370  // element, should give a zero/negative Jacobian on the displaced
371  // Node -> not invertible.
372  {
373  const Real alpha = .5;
374 
375  bool invertible =
376  test_elem_invertible({Point(0, 0, 0), Point(1, 0, 0), Point(alpha, alpha, 0), Point(0, 1, 0)}, QUAD4);
377 
378  CPPUNIT_ASSERT(!invertible);
379  }
380 
381  // Case 3) Top right corner is moved to (alpha, 1, 0). Element
382  // becomes non-invertible when alpha < 0.
383  {
384  const Real alpha = -0.25;
385 
386  bool invertible =
387  test_elem_invertible({Point(0, 0, 0), Point(1, 0, 0), Point(alpha, 1, 0), Point(0, 1, 0)}, QUAD4);
388 
389  CPPUNIT_ASSERT(!invertible);
390  }
391 
392  // Case 4) Degenerate case - all 4 points at same location. This
393  // zero-volume element does not have an invertible map.
394  {
395  const Real alpha = std::log(2);
396 
397  bool invertible =
398  test_elem_invertible({Point(alpha, alpha, alpha),
399  Point(alpha, alpha, alpha),
400  Point(alpha, alpha, alpha),
401  Point(alpha, alpha, alpha)}, QUAD4);
402 
403  CPPUNIT_ASSERT(!invertible);
404  }
405  }
bool test_elem_invertible(const std::vector< Point > &pts, ElemType elem_type)
Definition: volume_test.C:1271
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
const Real pi
.
Definition: libmesh.h:292

◆ testQuad4Jacobian()

void VolumeTest::testQuad4Jacobian ( )
inline

Definition at line 783 of file volume_test.C.

References libMesh::JACOBIAN, libMesh::libmesh_ignore(), libMesh::pi, libMesh::QUAD4, libMesh::Real, libMesh::SCALED_JACOBIAN, and libMesh::TOLERANCE.

784  {
785  LOG_UNIT_TEST;
786 
787  // Rhombus QUAD4. This case should have a JACOBIAN and
788  // SCALED_JACOBIAN value of sin(theta), where "theta" is the
789  // specified amount that we "sheared" the element by on creation.
790  // The JACOBIAN and SCALED_JACOBIAN are the same for this element
791  // because the edge lengths are all = 1.
792  {
793  // Helper lambda function that constructs a rhombus quad with
794  // interior acute angle theta.
795  auto test_rhombus_quad = [this](Real theta)
796  {
797  Real ct = std::cos(theta);
798  Real st = std::sin(theta);
799  std::vector<Point> pts = {
800  Point(0, 0, 0),
801  Point(1, 0, 0),
802  Point(1. + ct, st, 0),
803  Point( ct, st, 0)};
804  auto [elem, nodes] = this->construct_elem(pts, QUAD4);
805  libmesh_ignore(nodes);
806 
807  Real jac = elem->quality(JACOBIAN);
808  Real scaled_jac = elem->quality(SCALED_JACOBIAN);
809 
810  // Debugging
811  // libMesh::out << "jac = " << jac << std::endl;
812  // libMesh::out << "scaled_jac = " << scaled_jac << std::endl;
813 
814  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/std::abs(std::sin(theta)), /*actual=*/jac, TOLERANCE);
815  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/std::abs(std::sin(theta)), /*actual=*/scaled_jac, TOLERANCE);
816  };
817 
818  // 2a) Rhombus with interior angle theta=pi/6.
819  test_rhombus_quad(libMesh::pi / 6);
820 
821  // 2b) Rhombus with interior angle theta=pi/3.
822  test_rhombus_quad(libMesh::pi / 3);
823  }
824  }
static constexpr Real TOLERANCE
void libmesh_ignore(const Args &...)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::pair< std::unique_ptr< Elem >, std::vector< std::unique_ptr< Node > > > construct_elem(const std::vector< Point > &pts, ElemType elem_type)
Definition: volume_test.C:968
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const Real pi
.
Definition: libmesh.h:292

◆ testQuad4MinMaxAngle()

void VolumeTest::testQuad4MinMaxAngle ( )
inline

Definition at line 680 of file volume_test.C.

References libMesh::libmesh_ignore(), libMesh::MAX_ANGLE, libMesh::MIN_ANGLE, libMesh::pi, libMesh::QUAD4, libMesh::Real, and libMesh::TOLERANCE.

681  {
682  LOG_UNIT_TEST;
683 
684  // Case 1: Test that rigid body rotations of a unit square
685  // quadrilateral that have no effect on the quality of the
686  // element.
687  {
688  // Construct unit square QUAD4
689  std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(1, 1, 0), Point(0, 1, 0)};
690  auto [elem, nodes] = this->construct_elem(pts, QUAD4);
691  libmesh_ignore(nodes);
692 
693  // 1a) Reference Elem should have min angle == max angle == pi/2
694  {
695  Real min_angle = elem->quality(MIN_ANGLE);
696  Real max_angle = elem->quality(MAX_ANGLE);
697  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/90, /*actual=*/min_angle, TOLERANCE);
698  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/90, /*actual=*/max_angle, TOLERANCE);
699  }
700 
701  // 1b) Rotate all points about x-axis by 90 degrees
702  Real cost = std::cos(.5*libMesh::pi);
703  Real sint = std::sin(.5*libMesh::pi);
704  RealTensorValue Rx(1, 0, 0,
705  0, cost, sint,
706  0, sint, cost);
707 
708  for (auto & pt : pts)
709  pt = Rx * pt;
710 
711  {
712  Real min_angle = elem->quality(MIN_ANGLE);
713  Real max_angle = elem->quality(MAX_ANGLE);
714  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/90, /*actual=*/min_angle, TOLERANCE);
715  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/90, /*actual=*/max_angle, TOLERANCE);
716  }
717 
718  // 1c) Rotate all points about z-axis by 90 degrees
719  RealTensorValue Rz(cost, -sint, 0,
720  sint, cost, 0,
721  0, 0, 1);
722 
723  for (auto & pt : pts)
724  pt = Rz * pt;
725 
726  {
727  Real min_angle = elem->quality(MIN_ANGLE);
728  Real max_angle = elem->quality(MAX_ANGLE);
729  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/90, /*actual=*/min_angle, TOLERANCE);
730  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/90, /*actual=*/max_angle, TOLERANCE);
731  }
732 
733  // 1d) Rotate all points about y-axis by 270 degrees
734  RealTensorValue Ry(cost, 0, sint,
735  0, 1, 0,
736  -sint, 0, cost);
737 
738  for (int cnt=0; cnt<3; ++cnt)
739  for (auto & pt : pts)
740  pt = Ry * pt;
741 
742  {
743  Real min_angle = elem->quality(MIN_ANGLE);
744  Real max_angle = elem->quality(MAX_ANGLE);
745  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/90, /*actual=*/min_angle, TOLERANCE);
746  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/90, /*actual=*/max_angle, TOLERANCE);
747  }
748  }
749 
750  // Case 2: Rhombus QUAD4. This case should have an interior min
751  // angle of theta and an interior max angle of pi-theta, where
752  // "theta" is the specified amount that we "sheared" the element
753  // by on creation
754  {
755  // Helper lambda function that constructs a rhombus quad with
756  // interior acute angle theta.
757  auto test_rhombus_quad = [this](Real theta)
758  {
759  Real ct = std::cos(theta);
760  Real st = std::sin(theta);
761  std::vector<Point> pts = {
762  Point(0, 0, 0),
763  Point(1, 0, 0),
764  Point(1. + ct, st, 0),
765  Point( ct, st, 0)};
766  auto [elem, nodes] = this->construct_elem(pts, QUAD4);
767  libmesh_ignore(nodes);
768 
769  Real min_angle = elem->quality(MIN_ANGLE);
770  Real max_angle = elem->quality(MAX_ANGLE);
771  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/Real(180) / libMesh::pi * theta, /*actual=*/min_angle, TOLERANCE);
772  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/Real(180) / libMesh::pi * (libMesh::pi - theta), /*actual=*/max_angle, TOLERANCE);
773  };
774 
775  // 2a) Rhombus with interior angle theta=pi/6.
776  test_rhombus_quad(libMesh::pi / 6);
777 
778  // 2b) Rhombus with interior angle theta=pi/3.
779  test_rhombus_quad(libMesh::pi / 3);
780  }
781  }
static constexpr Real TOLERANCE
void libmesh_ignore(const Args &...)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::pair< std::unique_ptr< Elem >, std::vector< std::unique_ptr< Node > > > construct_elem(const std::vector< Point > &pts, ElemType elem_type)
Definition: volume_test.C:968
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
const Real pi
.
Definition: libmesh.h:292

◆ testQuad4TrueCentroid()

void VolumeTest::testQuad4TrueCentroid ( )
inline

Definition at line 78 of file volume_test.C.

References libMesh::TypeVector< T >::absolute_fuzzy_equals(), libMesh::MeshTools::Generation::build_square(), libMesh::MeshTools::Modification::distort(), libMesh::ReferenceElem::get(), mesh, libMesh::QUAD4, libMesh::Real, TestCommWorld, libMesh::TOLERANCE, and libMesh::Elem::true_centroid().

79  {
80  LOG_UNIT_TEST;
81 
82  // Test Quad4::true_centroid() override
83  {
84  const Elem & quad4 = ReferenceElem::get(QUAD4);
85  Point true_centroid = quad4.true_centroid();
86  LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(0), TOLERANCE*TOLERANCE);
87  LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(1), TOLERANCE*TOLERANCE);
88 
89  // Compare to centroid computed via generic base class implementation
90  Point base_class_centroid = quad4.Elem::true_centroid();
91  CPPUNIT_ASSERT(true_centroid.absolute_fuzzy_equals(base_class_centroid, TOLERANCE*TOLERANCE));
92  }
93 
94  // Check that "optimized" Quad4::true_centroid() gives same result
95  // as "generic" Elem::true_centroid() on a mesh of 10% distorted elements.
96  {
98 
100  /*nx=*/3, /*ny=*/3,
101  /*xmin=*/0., /*xmax=*/1.,
102  /*ymin=*/0., /*ymax=*/1.,
103  QUAD4);
104 
106  /*factor=*/0.1,
107  /*perturb_boundary=*/false);
108 
109  for (const auto & elem : mesh.element_ptr_range())
110  {
111  Point derived_centroid = elem->true_centroid();
112  Point base_centroid = elem->Elem::true_centroid();
113 
114  // Debugging: check results in detail
115  // auto flags = libMesh::out.flags();
116  // libMesh::out << std::scientific << std::setprecision(16);
117  // libMesh::out << "derived_centroid = " << derived_centroid << std::endl;
118  // libMesh::out << "base_centroid = " << base_centroid << std::endl;
119  // libMesh::out.flags(flags);
120 
121  CPPUNIT_ASSERT(derived_centroid.absolute_fuzzy_equals(base_centroid, TOLERANCE*TOLERANCE));
122 
123  Real derived_volume = elem->volume();
124  Real base_volume = elem->Elem::volume();
125  LIBMESH_ASSERT_FP_EQUAL(base_volume, derived_volume, TOLERANCE*TOLERANCE);
126  }
127  }
128  }
virtual Point true_centroid() const
Definition: elem.C:575
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
static constexpr Real TOLERANCE
void distort(MeshBase &mesh, const Real factor, const bool perturb_boundary=false)
Randomly perturb the nodal locations.
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
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.
bool absolute_fuzzy_equals(const TypeVector< T > &rhs, Real tol=TOLERANCE) const
Definition: type_vector.h:975
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const Elem & get(const ElemType type_in)

◆ testQuad4Warpage()

void VolumeTest::testQuad4Warpage ( )
inline

Definition at line 600 of file volume_test.C.

References libMesh::libmesh_ignore(), libMesh::pi, libMesh::QUAD4, libMesh::Real, libMesh::TOLERANCE, and libMesh::WARP.

601  {
602  LOG_UNIT_TEST;
603 
604  // Case 1: Test that rigid body rotations of a unit square
605  // quadrilateral that have no effect on the quality of the
606  // element.
607  {
608  // Construct unit square QUAD4
609  std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(1, 1, 0), Point(0, 1, 0)};
610  auto [elem, nodes] = this->construct_elem(pts, QUAD4);
611  libmesh_ignore(nodes);
612 
613  // 1a) Any flat element should have warp == 1
614  Real warpage = elem->quality(WARP);
615  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0, /*actual=*/warpage, TOLERANCE);
616 
617  // 1b) Rotate all points about x-axis by 90 degrees
618  Real cost = std::cos(.5*libMesh::pi);
619  Real sint = std::sin(.5*libMesh::pi);
620  RealTensorValue Rx(1, 0, 0,
621  0, cost, sint,
622  0, sint, cost);
623 
624  for (auto & pt : pts)
625  pt = Rx * pt;
626 
627  warpage = elem->quality(WARP);
628  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0, /*actual=*/warpage, TOLERANCE);
629 
630  // 1c) Rotate all points about z-axis by 90 degrees
631  RealTensorValue Rz(cost, -sint, 0,
632  sint, cost, 0,
633  0, 0, 1);
634 
635  for (auto & pt : pts)
636  pt = Rz * pt;
637 
638  warpage = elem->quality(WARP);
639  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0, /*actual=*/warpage, TOLERANCE);
640 
641  // 1d) Rotate all points about y-axis by 270 degrees
642  RealTensorValue Ry(cost, 0, sint,
643  0, 1, 0,
644  -sint, 0, cost);
645 
646  for (int cnt=0; cnt<3; ++cnt)
647  for (auto & pt : pts)
648  pt = Ry * pt;
649 
650  warpage = elem->quality(WARP);
651  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0, /*actual=*/warpage, TOLERANCE);
652  }
653 
654  // Case 2: Unit square quadrilateral with Node 2 displaced by a distance h in the z-direction.
655  {
656  auto test_warped_quad = [this](Real h)
657  {
658  std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(1, 1, h), Point(0, 1, 0)};
659  auto [elem, nodes] = this->construct_elem(pts, QUAD4);
660  libmesh_ignore(nodes);
661 
662  Real warpage = elem->quality(WARP);
663  // libMesh::out << "QUAD with node 3 displaced by h = "
664  // << h << " in the z-direction , warpage = " << warpage
665  // << std::endl;
666  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/Real(1) / (h*h + 1), /*actual=*/warpage, TOLERANCE);
667  };
668 
669  // For h = 0.1, the expected warpage value is ~ 0.991, so not
670  // much different than the value of 1.0 for a flat element.
671  test_warped_quad(0.1);
672 
673  // For h = 0.3, the expected warpage value is ~ 0.917431, which
674  // is pretty close to the lower bound (0.9) of "acceptable"
675  // warpage, as suggested in the Cubit manual.
676  test_warped_quad(0.3);
677  }
678  }
static constexpr Real TOLERANCE
void libmesh_ignore(const Args &...)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::pair< std::unique_ptr< Elem >, std::vector< std::unique_ptr< Node > > > construct_elem(const std::vector< Point > &pts, ElemType elem_type)
Definition: volume_test.C:968
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
const Real pi
.
Definition: libmesh.h:292

◆ testTet4DihedralAngle()

void VolumeTest::testTet4DihedralAngle ( )
inline

Definition at line 826 of file volume_test.C.

References libMesh::libmesh_ignore(), libMesh::MAX_ANGLE, libMesh::MAX_DIHEDRAL_ANGLE, libMesh::MIN_ANGLE, libMesh::MIN_DIHEDRAL_ANGLE, libMesh::Real, libMesh::TET4, and libMesh::TOLERANCE.

827  {
828  LOG_UNIT_TEST;
829 
830  // Construct a tetrahedron whose projection into the x-y plane looks like the unit square,
831  // and where the apex node is just slightly out of the x-y plane. This element should have
832  // reasonable MIN,MAX_ANGLE values but MIN,MAX_DIHEDRAL angles of nearly 0. This is an
833  // example that demonstrates one should not solely use edge angles to determine Elem quality
834  // in 3D.
835  std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(0, 1, 0), Point(1, 1, 0.01)};
836  auto [elem, nodes] = this->construct_elem(pts, TET4);
837  libmesh_ignore(nodes);
838 
839  Real min_angle = elem->quality(MIN_ANGLE);
840  Real max_angle = elem->quality(MAX_ANGLE);
841  Real min_dihedral_angle = elem->quality(MIN_DIHEDRAL_ANGLE);
842  Real max_dihedral_angle = elem->quality(MAX_DIHEDRAL_ANGLE);
843 
844  // Debugging
845  // libMesh::out << "Squashed Tet4 min_angle = " << min_angle << " degrees" << std::endl;
846  // libMesh::out << "Squashed Tet4 max_angle = " << max_angle << " degrees" << std::endl;
847  // libMesh::out << "Squashed Tet4 min_dihedral_angle = " << min_dihedral_angle << " degrees" << std::endl;
848  // libMesh::out << "Squashed Tet4 max_dihedral_angle = " << max_dihedral_angle << " degrees" << std::endl;
849 
850  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/44.9985676771277, /*actual=*/min_angle, TOLERANCE);
851  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/90, /*actual=*/max_angle, TOLERANCE);
852 
853  // Assert that both min and max dihedral angles are less than 1 degree (a very low quality element)
854  CPPUNIT_ASSERT_LESS(Real(1), min_dihedral_angle);
855  CPPUNIT_ASSERT_LESS(Real(1), max_dihedral_angle);
856  }
static constexpr Real TOLERANCE
void libmesh_ignore(const Args &...)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::pair< std::unique_ptr< Elem >, std::vector< std::unique_ptr< Node > > > construct_elem(const std::vector< Point > &pts, ElemType elem_type)
Definition: volume_test.C:968
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39

◆ testTet4Jacobian()

void VolumeTest::testTet4Jacobian ( )
inline

Definition at line 858 of file volume_test.C.

References libMesh::JACOBIAN, libMesh::libmesh_ignore(), libMesh::Real, libMesh::SCALED_JACOBIAN, libMesh::TET4, and libMesh::TOLERANCE.

859  {
860  LOG_UNIT_TEST;
861 
862  {
863  // Same element as in testTet4DihedralAngle(). Here we verify that
864  // the element is low quality since the SCALED_JACOBIAN is < O(h)
865  // as h -> 0, and h can be arbitrarily small in the squashed element.
866  Real h = Real(1)/100;
867  std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(0, 1, 0), Point(1, 1, h)};
868  auto [elem, nodes] = this->construct_elem(pts, TET4);
869  libmesh_ignore(nodes);
870 
871  Real jac = elem->quality(JACOBIAN);
872  Real scaled_jac = elem->quality(SCALED_JACOBIAN);
873 
874  // Debugging
875  // libMesh::out << "Squashed Tet4 jac = " << jac << std::endl;
876  // libMesh::out << "Squashed Tet4 scaled_jac = " << scaled_jac << std::endl;
877 
878  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/h, /*actual=*/jac, TOLERANCE);
879  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/h/(h*h+1)/std::sqrt(h*h+2),
880  /*actual=*/scaled_jac, TOLERANCE * TOLERANCE);
881  }
882 
883  {
884  // A representative Tet generated by calling build_cube(). This
885  // element has minimum interior edge angle of approximately
886  // 35.26 degrees, so it it is not a simple refinement of the
887  // reference element. It is not located at the origin, but still
888  // has a simple to compute value for the JACOBIAN and
889  // SCALED_JACOBIAN quality metrics.
890  std::vector<Point> pts = {
891  Point(2.5, 2.5, 4.5),
892  Point(3.5, 1.5, 5.5),
893  Point(1.5, 1.5, 5.5),
894  Point(2.5, 2.5, 5.5)
895  };
896  auto [elem, nodes] = this->construct_elem(pts, TET4);
897  libmesh_ignore(nodes);
898 
899  Real jac = elem->quality(JACOBIAN);
900  Real scaled_jac = elem->quality(SCALED_JACOBIAN);
901 
902  // Debugging
903  // libMesh::out << "build_cube() Tet4 jac = " << jac << std::endl;
904  // libMesh::out << "build_cube() Tet4 scaled_jac = " << scaled_jac << std::endl;
905 
906  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/2, /*actual=*/jac, TOLERANCE);
907  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/Real(1)/std::sqrt(Real(6)), /*actual=*/scaled_jac, TOLERANCE);
908  }
909  }
static constexpr Real TOLERANCE
void libmesh_ignore(const Args &...)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::pair< std::unique_ptr< Elem >, std::vector< std::unique_ptr< Node > > > construct_elem(const std::vector< Point > &pts, ElemType elem_type)
Definition: volume_test.C:968
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39

◆ testTri3AspectRatio()

void VolumeTest::testTri3AspectRatio ( )
inline

Definition at line 555 of file volume_test.C.

References libMesh::ASPECT_RATIO, libMesh::libmesh_ignore(), libMesh::Real, libMesh::TOLERANCE, and libMesh::TRI3.

556  {
557  LOG_UNIT_TEST;
558 
559  // Case 1) Reference TRI3
560  {
561  std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(0, 1, 0)};
562  auto [elem, nodes] = this->construct_elem(pts, TRI3);
563  libmesh_ignore(nodes);
564 
565  // Compute the aspect ratio for the reference Tri
566  // The expected value is ~ 1.44338
567  Real aspect_ratio = elem->quality(ASPECT_RATIO);
568  // libMesh::out << "Unit TRI3 aspect ratio = " << aspect_ratio << std::endl;
569  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/Real(5)/2/std::sqrt(Real(3)), /*actual=*/aspect_ratio, TOLERANCE);
570  }
571 
572  // Case 2) Equilateral TRI3
573  {
574  std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(0.5, 0.5*std::sqrt(3), 0)};
575  auto [elem, nodes] = this->construct_elem(pts, TRI3);
576  libmesh_ignore(nodes);
577 
578  // Compute the aspect ratio for the reference Tri
579  // The expected value is 1.0
580  Real aspect_ratio = elem->quality(ASPECT_RATIO);
581  // libMesh::out << "Equilateral TRI3 aspect ratio = " << aspect_ratio << std::endl;
582  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/Real(1), /*actual=*/aspect_ratio, TOLERANCE);
583  }
584 
585  // Case 3) Reference TRI3 with one leg length = L >> 1
586  {
587  Real L = 10.;
588  std::vector<Point> pts = {Point(0, 0, 0), Point(L, 0, 0), Point(0, 1, 0)};
589  auto [elem, nodes] = this->construct_elem(pts, TRI3);
590  libmesh_ignore(nodes);
591 
592  // Compute the aspect ratio for the reference Tri
593  // The expected value is ~ 11.5759
594  Real aspect_ratio = elem->quality(ASPECT_RATIO);
595  // libMesh::out << "TRI3 with leg length L = " << L << ", aspect ratio = " << aspect_ratio << std::endl;
596  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/Real(1)/std::sqrt(Real(3)) * (Real(2)*L + Real(1)/(2*L)), /*actual=*/aspect_ratio, TOLERANCE);
597  }
598  }
static constexpr Real TOLERANCE
void libmesh_ignore(const Args &...)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::pair< std::unique_ptr< Elem >, std::vector< std::unique_ptr< Node > > > construct_elem(const std::vector< Point > &pts, ElemType elem_type)
Definition: volume_test.C:968
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39

◆ testTri3TrueCentroid()

void VolumeTest::testTri3TrueCentroid ( )
inline

Definition at line 65 of file volume_test.C.

References libMesh::ReferenceElem::get(), libMesh::Real, libMesh::TOLERANCE, libMesh::TRI3, and libMesh::Elem::true_centroid().

66  {
67  LOG_UNIT_TEST;
68 
69  // The true_centroid() == vertex_average() == (1/3, 1/3) for reference Tri3
70  {
71  const Elem & tri3 = ReferenceElem::get(TRI3);
72  Point true_centroid = tri3.true_centroid();
73  LIBMESH_ASSERT_FP_EQUAL(Real(1)/3, true_centroid(0), TOLERANCE*TOLERANCE);
74  LIBMESH_ASSERT_FP_EQUAL(Real(1)/3, true_centroid(1), TOLERANCE*TOLERANCE);
75  }
76  }
virtual Point true_centroid() const
Definition: elem.C:575
static constexpr Real TOLERANCE
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const Elem & get(const ElemType type_in)

◆ testTwistedVolume()

void VolumeTest::testTwistedVolume ( )
inline

Definition at line 175 of file volume_test.C.

References libMesh::MeshTools::Generation::build_cube(), libMesh::MeshBase::elem_ptr(), mesh, libMesh::Elem::point(), libMesh::PRISM21, libMesh::Real, TestCommWorld, libMesh::TOLERANCE, and libMesh::Elem::volume().

176  {
177  LOG_UNIT_TEST;
178 
180 
181  // Build an element type that will fall back on our generic
182  // quadrature-based Elem::volume()
184  /*nelem=*/1, /*nelem=*/1, /*nelem=*/1,
185  /*xmin=*/-1, /*xmax=*/1,
186  /*ymin=*/-1, /*ymax=*/1,
187  /*zmin=*/-1, /*zmax=*/1,
188  PRISM21);
189 
190  // Pick an element and twist it
191  Elem * prism6 = mesh.elem_ptr(0);
192  prism6->point(1) *= -1;
193  prism6->point(1) += 2*prism6->point(0);
194 
195  // The real test here is that volume() doesn't throw
196  const Real vol = prism6->volume();
197  const Real gold_vol = 3+Real(5)/9;
198  CPPUNIT_ASSERT_LESS(TOLERANCE, std::abs(vol-gold_vol));
199  }
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
static constexpr Real TOLERANCE
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
virtual const Elem * elem_ptr(const dof_id_type i) const =0
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual Real volume() const
Definition: elem.C:3462
const Point & point(const unsigned int i) const
Definition: elem.h:2459
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.

The documentation for this class was generated from the following file: