libMesh
Loading...
Searching...
No Matches
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 (testQuad4SkewAngle)
 
 CPPUNIT_TEST (testHex8SkewAngle)
 
 CPPUNIT_TEST (testQuad4Size)
 
 CPPUNIT_TEST (testHex8Size)
 
 CPPUNIT_TEST (testQuad4Taper)
 
 CPPUNIT_TEST (testQuad4Condition)
 
 CPPUNIT_TEST (testHex8Condition)
 
 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 testQuad4SkewAngle ()
 
void testHex8SkewAngle ()
 
void testQuad4Size ()
 
void testHex8Size ()
 
void testQuad4Taper ()
 
void testQuad4Condition ()
 
void testHex8Condition ()
 
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)
 
Elem * buildC0Polyhedron (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 1275 of file volume_test.C.

1276 {
1277 std::unique_ptr<libMesh::Node> mid_elem_node;
1278 std::unique_ptr<Elem> polyhedron = std::make_unique<C0Polyhedron>(sides, mid_elem_node);
1279 if (mid_elem_node)
1280 mesh.add_node(std::move(mid_elem_node));
1281 polyhedron->set_id() = 0;
1282 Elem * elem = mesh.add_elem(std::move(polyhedron));
1283 libmesh_assert(dynamic_cast<C0Polyhedron *>(elem));
1285
1286 return elem;
1287 }
The C0Polyhedron is an element in 3D with an arbitrary (but fixed) number of polygonal first-order (C...
dof_id_type & set_id()
Definition dof_object.h:841
This is the base class from which all geometric element types are derived.
Definition elem.h:96
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly created (or read) mesh for use.
Definition mesh_base.C:824
virtual Node * add_node(Node *n)=0
Add Node n to the end of the vertex array.
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
MeshBase & mesh
libmesh_assert(ctx)

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

Referenced by testC0PolyhedronCube(), and testC0PolyhedronHexagonalPrism().

◆ 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 1246 of file volume_test.C.

1248 {
1249 const unsigned int n_points = pts.size();
1250
1251 // Create Nodes
1252 std::vector<std::unique_ptr<Node>> nodes(n_points);
1253 for (unsigned int i=0; i<n_points; i++)
1254 nodes[i] = Node::build(pts[i], /*id*/ i);
1255
1256 // Create Elem, assign nodes
1257 std::unique_ptr<Elem> elem = Elem::build(elem_type, /*parent*/ nullptr);
1258
1259 // Make sure we were passed consistent input to build this type of Elem
1260 libmesh_error_msg_if(elem->n_nodes() != n_points,
1261 "Wrong number of points "
1262 << n_points
1263 << " provided to build a "
1264 << Utility::enum_to_string(elem_type));
1265
1266 for (unsigned int i=0; i<n_points; i++)
1267 elem->set_node(i, nodes[i].get());
1268
1269 // Return Elem and Nodes we created
1270 return std::make_pair(std::move(elem), std::move(nodes));
1271 }
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition elem.C:382
static std::unique_ptr< Node > build(const Node &n)
Definition node.h:315
std::string enum_to_string(const T e)

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

Referenced by test_elem_invertible(), testHex8Condition(), testHex8Size(), testHex8SkewAngle(), testQuad4AspectRatio(), testQuad4Condition(), testQuad4Jacobian(), testQuad4MinMaxAngle(), testQuad4Size(), testQuad4SkewAngle(), testQuad4Taper(), testQuad4Warpage(), testTet4DihedralAngle(), testTet4Jacobian(), and testTri3AspectRatio().

◆ CPPUNIT_TEST() [1/31]

VolumeTest::CPPUNIT_TEST ( testC0PolygonHexagon  )

◆ CPPUNIT_TEST() [2/31]

VolumeTest::CPPUNIT_TEST ( testC0PolygonPentagon  )

◆ CPPUNIT_TEST() [3/31]

VolumeTest::CPPUNIT_TEST ( testC0PolygonQuad  )

◆ CPPUNIT_TEST() [4/31]

VolumeTest::CPPUNIT_TEST ( testC0PolygonSquare  )

◆ CPPUNIT_TEST() [5/31]

VolumeTest::CPPUNIT_TEST ( testC0PolyhedronCube  )

◆ CPPUNIT_TEST() [6/31]

VolumeTest::CPPUNIT_TEST ( testC0PolyhedronHexagonalPrism  )

◆ CPPUNIT_TEST() [7/31]

VolumeTest::CPPUNIT_TEST ( testEdge3Invertible  )

◆ CPPUNIT_TEST() [8/31]

VolumeTest::CPPUNIT_TEST ( testEdge3Volume  )

◆ CPPUNIT_TEST() [9/31]

VolumeTest::CPPUNIT_TEST ( testEdge4Invertible  )

◆ CPPUNIT_TEST() [10/31]

VolumeTest::CPPUNIT_TEST ( testHex20PLevelTrueCentroid  )

◆ CPPUNIT_TEST() [11/31]

VolumeTest::CPPUNIT_TEST ( testHex8Condition  )

◆ CPPUNIT_TEST() [12/31]

VolumeTest::CPPUNIT_TEST ( testHex8Size  )

◆ CPPUNIT_TEST() [13/31]

VolumeTest::CPPUNIT_TEST ( testHex8SkewAngle  )

◆ CPPUNIT_TEST() [14/31]

VolumeTest::CPPUNIT_TEST ( testHex8TrueCentroid  )

◆ CPPUNIT_TEST() [15/31]

VolumeTest::CPPUNIT_TEST ( testPrism6TrueCentroid  )

◆ CPPUNIT_TEST() [16/31]

VolumeTest::CPPUNIT_TEST ( testPyramid5TrueCentroid  )

◆ CPPUNIT_TEST() [17/31]

VolumeTest::CPPUNIT_TEST ( testQuad4AspectRatio  )

◆ CPPUNIT_TEST() [18/31]

VolumeTest::CPPUNIT_TEST ( testQuad4Condition  )

◆ CPPUNIT_TEST() [19/31]

VolumeTest::CPPUNIT_TEST ( testQuad4Invertible  )

◆ CPPUNIT_TEST() [20/31]

VolumeTest::CPPUNIT_TEST ( testQuad4Jacobian  )

◆ CPPUNIT_TEST() [21/31]

VolumeTest::CPPUNIT_TEST ( testQuad4MinMaxAngle  )

◆ CPPUNIT_TEST() [22/31]

VolumeTest::CPPUNIT_TEST ( testQuad4Size  )

◆ CPPUNIT_TEST() [23/31]

VolumeTest::CPPUNIT_TEST ( testQuad4SkewAngle  )

◆ CPPUNIT_TEST() [24/31]

VolumeTest::CPPUNIT_TEST ( testQuad4Taper  )

◆ CPPUNIT_TEST() [25/31]

VolumeTest::CPPUNIT_TEST ( testQuad4TrueCentroid  )

◆ CPPUNIT_TEST() [26/31]

VolumeTest::CPPUNIT_TEST ( testQuad4Warpage  )

◆ CPPUNIT_TEST() [27/31]

VolumeTest::CPPUNIT_TEST ( testTet4DihedralAngle  )

◆ CPPUNIT_TEST() [28/31]

VolumeTest::CPPUNIT_TEST ( testTet4Jacobian  )

◆ CPPUNIT_TEST() [29/31]

VolumeTest::CPPUNIT_TEST ( testTri3AspectRatio  )

◆ CPPUNIT_TEST() [30/31]

VolumeTest::CPPUNIT_TEST ( testTri3TrueCentroid  )

◆ CPPUNIT_TEST() [31/31]

VolumeTest::CPPUNIT_TEST ( testTwistedVolume  )

◆ 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 64 of file volume_test.C.

65 {
66 }

◆ tearDown()

void VolumeTest::tearDown ( )
inline

Definition at line 68 of file volume_test.C.

69 {
70 }

◆ test_elem_invertible()

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

Definition at line 1549 of file volume_test.C.

1551 {
1552 // Construct Elem of desired type
1553 auto [elem, nodes] = this->construct_elem(pts, elem_type);
1554 libmesh_ignore(nodes);
1555
1556 // Return whether or not this Elem has an invertible map
1557 return elem->has_invertible_map();
1558 }
std::pair< std::unique_ptr< Elem >, std::vector< std::unique_ptr< Node > > > construct_elem(const std::vector< Point > &pts, ElemType elem_type)
void libmesh_ignore(const Args &...)

References construct_elem(), and libMesh::libmesh_ignore().

Referenced by testEdge3Invertible(), testEdge4Invertible(), and testQuad4Invertible().

◆ test_true_centroid_and_volume()

void VolumeTest::test_true_centroid_and_volume ( ElemType  elem_type)
inlineprotected

Definition at line 1562 of file volume_test.C.

1563 {
1564 // Check that derived class true_centroid() gives same result as
1565 // the base class Elem::true_centroid() on a 2x2x2 mesh of 10%
1566 // distorted elements.
1567 {
1568 ReplicatedMesh mesh(*TestCommWorld);
1569
1571 /*nelem=*/2, /*nelem=*/2, /*nelem=*/2,
1572 /*xmin=*/-1, /*xmax=*/1,
1573 /*ymin=*/-1, /*ymax=*/1,
1574 /*zmin=*/-1, /*zmax=*/1,
1575 elem_type);
1576
1578 /*factor=*/0.1,
1579 /*perturb_boundary=*/false);
1580
1581 for (const auto & elem : mesh.element_ptr_range())
1582 {
1583 Point derived_centroid = elem->true_centroid();
1584 Point base_centroid = elem->Elem::true_centroid();
1585
1586 // Debugging: check results in detail
1587 // auto flags = libMesh::out.flags();
1588 // libMesh::out << std::scientific << std::setprecision(16);
1589 // libMesh::out << "derived_centroid = " << derived_centroid << std::endl;
1590 // libMesh::out << "base_centroid = " << base_centroid << std::endl;
1591 // libMesh::out.flags(flags);
1592
1593 CPPUNIT_ASSERT(derived_centroid.absolute_fuzzy_equals(base_centroid, 50*TOLERANCE*TOLERANCE));
1594
1595 // Make sure that base class and "optimized" routines for computing the cell volume agree
1596 Real derived_volume = elem->volume();
1597 Real base_volume = elem->Elem::volume();
1598 LIBMESH_ASSERT_FP_EQUAL(base_volume, derived_volume, 50*TOLERANCE*TOLERANCE);
1599 }
1600 }
1601 }
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:41
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
bool absolute_fuzzy_equals(const TypeVector< T > &rhs, Real tol=TOLERANCE) const
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.
void distort(MeshBase &mesh, const Real factor, const bool perturb_boundary=false)
Randomly perturb the nodal locations.
static constexpr Real TOLERANCE
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

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

Referenced by testHex8TrueCentroid(), testPrism6TrueCentroid(), and testPyramid5TrueCentroid().

◆ testC0Polygon()

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

Definition at line 1191 of file volume_test.C.

1193 {
1194 Mesh mesh(*TestCommWorld);
1195
1196 const auto np = points.size();
1197 std::unique_ptr<Elem> polygon = std::make_unique<C0Polygon>(np);
1198
1199 for (auto p : make_range(np))
1200 polygon->set_node(p, mesh.add_point(points[p], p));
1201
1202 polygon->set_id() = 0;
1203 Elem * elem = mesh.add_elem(std::move(polygon));
1204
1205 const Real derived_volume = elem->volume();
1206 const Real base_volume = elem->Elem::volume();
1207 LIBMESH_ASSERT_FP_EQUAL(base_volume, derived_volume, TOLERANCE*TOLERANCE);
1208 LIBMESH_ASSERT_FP_EQUAL(derived_volume, expected_volume, TOLERANCE*TOLERANCE);
1209
1210 this->testC0PolygonMethods(mesh, np);
1211 }
void testC0PolygonMethods(MeshBase &mesh, unsigned int n_sides)
virtual Real volume() const
Definition elem.C:3865
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition mesh.h:51
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

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

Referenced by testC0PolygonHexagon(), testC0PolygonPentagon(), testC0PolygonQuad(), and testC0PolygonSquare().

◆ testC0PolygonHexagon()

void VolumeTest::testC0PolygonHexagon ( )
inline

Definition at line 1233 of file volume_test.C.

1234 {
1235 LOG_UNIT_TEST;
1236 testC0Polygon({{0,0}, {1,0}, {1.5,0.5}, {1,1}, {0,1}, {-0.5, 0.5}}, 1.5);
1237 }
void testC0Polygon(const std::vector< Point > &points, Real expected_volume)

References testC0Polygon().

◆ testC0PolygonMethods()

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

Definition at line 1290 of file volume_test.C.

1292 {
1293 Elem * elem = mesh.query_elem_ptr(0);
1294 bool found_elem = elem;
1295 mesh.comm().max(found_elem);
1296 CPPUNIT_ASSERT(found_elem);
1297
1298 if (!elem)
1299 return;
1300
1301 CPPUNIT_ASSERT_EQUAL(elem->type(), C0POLYGON);
1302 CPPUNIT_ASSERT_EQUAL(elem->n_nodes(), n_sides);
1303 CPPUNIT_ASSERT_EQUAL(elem->n_sub_elem(), n_sides);
1304 CPPUNIT_ASSERT_EQUAL(elem->n_sides(), n_sides);
1305 CPPUNIT_ASSERT_EQUAL(elem->n_vertices(), n_sides);
1306 CPPUNIT_ASSERT_EQUAL(elem->n_edges(), n_sides);
1307
1308 // Even number of sides
1309 if (!(n_sides%2))
1310 {
1311 const unsigned int nsover2 = n_sides/2;
1312 for (auto i : make_range(nsover2))
1313 {
1314 CPPUNIT_ASSERT_EQUAL(elem->opposite_side(i), i+nsover2);
1315 CPPUNIT_ASSERT_EQUAL(elem->opposite_side(i+nsover2), i);
1316 }
1317 }
1318
1319 for (unsigned int i : make_range(n_sides))
1320 {
1321 CPPUNIT_ASSERT(elem->is_vertex(i));
1322 CPPUNIT_ASSERT(!elem->is_edge(i));
1323 CPPUNIT_ASSERT(!elem->is_face(i));
1324 CPPUNIT_ASSERT(elem->is_node_on_side(i,i));
1325 CPPUNIT_ASSERT(elem->is_node_on_edge(i,i));
1326 CPPUNIT_ASSERT(elem->is_node_on_side((i+1)%n_sides,i));
1327 CPPUNIT_ASSERT(elem->is_node_on_edge((i+1)%n_sides,i));
1328 std::vector<unsigned int> nodes = elem->nodes_on_side(i);
1329 CPPUNIT_ASSERT_EQUAL(nodes.size(), std::size_t(2));
1330 CPPUNIT_ASSERT(nodes[0] == i ||
1331 nodes[1] == i);
1332 CPPUNIT_ASSERT(nodes[0] == (i+1)%n_sides ||
1333 nodes[1] == (i+1)%n_sides);
1334 std::vector<unsigned int> edge_nodes = elem->nodes_on_edge(i);
1335 CPPUNIT_ASSERT(nodes == edge_nodes);
1336
1337
1338 CPPUNIT_ASSERT_EQUAL(elem->local_side_node(i,0), i);
1339 CPPUNIT_ASSERT_EQUAL(elem->local_side_node(i,1), (i+1)%n_sides);
1340 CPPUNIT_ASSERT_EQUAL(elem->local_edge_node(i,0), i);
1341 CPPUNIT_ASSERT_EQUAL(elem->local_edge_node(i,1), (i+1)%n_sides);
1342
1343 auto edge = elem->side_ptr(i);
1344 CPPUNIT_ASSERT_EQUAL(edge->type(), EDGE2);
1345 CPPUNIT_ASSERT_EQUAL(edge->node_ptr(0), mesh.node_ptr(i));
1346 CPPUNIT_ASSERT_EQUAL(edge->node_ptr(1), mesh.node_ptr((i+1)%n_sides));
1347 }
1348
1349 CPPUNIT_ASSERT(!elem->is_flipped());
1350 elem->flip(&mesh.get_boundary_info());
1351 CPPUNIT_ASSERT(elem->is_flipped());
1352 elem->flip(&mesh.get_boundary_info());
1353 }
void max(const T &r, T &o, Request &req) const
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
virtual unsigned int n_vertices() const =0
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const =0
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
virtual unsigned int n_nodes() const =0
virtual bool is_flipped() const =0
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
virtual bool is_face(const unsigned int i) const =0
virtual std::vector< unsigned int > nodes_on_edge(const unsigned int) 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 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_sub_elem() const =0
virtual bool is_edge(const unsigned int i) const =0
virtual unsigned int opposite_side(const unsigned int s) const
Definition elem.C:3959
virtual bool is_vertex(const unsigned int i) const =0
virtual ElemType type() const =0
virtual bool is_node_on_edge(const unsigned int n, const unsigned int e) const =0
virtual unsigned int n_edges() const =0
virtual unsigned int n_sides() const =0
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition mesh_base.h:170
virtual const Node * node_ptr(const dof_id_type i) const =0
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
const Parallel::Communicator & comm() const

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(), libMesh::Parallel::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().

Referenced by testC0Polygon().

◆ testC0PolygonPentagon()

void VolumeTest::testC0PolygonPentagon ( )
inline

Definition at line 1227 of file volume_test.C.

1228 {
1229 LOG_UNIT_TEST;
1230 testC0Polygon({{0,0}, {1,0}, {1.5,0.5}, {1,1}, {0,1}}, 1.25);
1231 }

References testC0Polygon().

◆ testC0PolygonQuad()

void VolumeTest::testC0PolygonQuad ( )
inline

Definition at line 1221 of file volume_test.C.

1222 {
1223 LOG_UNIT_TEST;
1224 testC0Polygon({{0,0}, {1,0}, {1,2}, {-1,1}}, 2.5);
1225 }

References testC0Polygon().

◆ testC0PolygonSquare()

void VolumeTest::testC0PolygonSquare ( )
inline

Definition at line 1215 of file volume_test.C.

1216 {
1217 LOG_UNIT_TEST;
1218 testC0Polygon({{0,0}, {1,0}, {1,1}, {0,1}}, 1);
1219 }

References testC0Polygon().

◆ testC0PolyhedronCube()

void VolumeTest::testC0PolyhedronCube ( )
inlineprotected

Definition at line 1439 of file volume_test.C.

1440 {
1441 ReplicatedMesh mesh(*TestCommWorld);
1442
1443 mesh.add_point(Point(0, 0, 0), 0);
1444 mesh.add_point(Point(1, 0, 0), 1);
1445 mesh.add_point(Point(1, 1, 0), 2);
1446 mesh.add_point(Point(0, 1, 0), 3);
1447 mesh.add_point(Point(0, 0, 1), 4);
1448 mesh.add_point(Point(1, 0, 1), 5);
1449 mesh.add_point(Point(1, 1, 1), 6);
1450 mesh.add_point(Point(0, 1, 1), 7);
1451
1452 // See notes in elem_test.h
1453 const std::vector<std::vector<unsigned int>> nodes_on_side =
1454 { {0, 1, 2, 3}, // min z
1455 {0, 1, 5, 4}, // min y
1456 {2, 6, 5, 1}, // max x
1457 {2, 3, 7, 6}, // max y
1458 {0, 4, 7, 3}, // min x
1459 {5, 6, 7, 4} }; // max z
1460
1461 // Build all the sides.
1462 std::vector<std::shared_ptr<Polygon>> sides(nodes_on_side.size());
1463
1464 for (auto s : index_range(nodes_on_side))
1465 {
1466 const auto & nodes_on_s = nodes_on_side[s];
1467 sides[s] = std::make_shared<C0Polygon>(nodes_on_s.size());
1468 for (auto i : index_range(nodes_on_s))
1469 sides[s]->set_node(i, mesh.node_ptr(nodes_on_s[i]));
1470 }
1471
1472 const auto poly = dynamic_cast<C0Polyhedron *>(buildC0Polyhedron(sides, mesh));
1473 testElemVolume(poly, 1);
1474 #ifdef LIBMESH_ENABLE_EXCEPTIONS
1475 testC0PolyhedronMethods(mesh, /*midnode*/false);
1476
1477 // Check routine for subtet side to poly side mapping
1478 // NOTE: this test is hard coded to the elements used right now (to be reworked)
1479 const auto subtet0_sides_to_poly_sides = poly->subelement_sides_to_poly_sides(0);
1480 CPPUNIT_ASSERT_EQUAL(libMesh::invalid_int, subtet0_sides_to_poly_sides[0]);
1481 CPPUNIT_ASSERT_EQUAL(1, subtet0_sides_to_poly_sides[1]);
1482 CPPUNIT_ASSERT_EQUAL(0, subtet0_sides_to_poly_sides[2]);
1483 CPPUNIT_ASSERT_EQUAL(2, subtet0_sides_to_poly_sides[3]);
1484 #else
1485 testC0PolyhedronMethods(mesh, /*midnode*/true);
1486 #endif
1487 }
void testElemVolume(const Elem *elem, Real expected_volume)
Elem * buildC0Polyhedron(std::vector< std::shared_ptr< Polygon > > sides, MeshBase &mesh)
void testC0PolyhedronMethods(MeshBase &mesh, bool has_midnode)
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.
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
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

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

◆ testC0PolyhedronHexagonalPrism()

void VolumeTest::testC0PolyhedronHexagonalPrism ( )
inlineprotected

Definition at line 1491 of file volume_test.C.

1492 {
1493 ReplicatedMesh mesh(*TestCommWorld);
1494
1495 mesh.add_point(Point(0, -2, 0), 0);
1496 mesh.add_point(Point(-1, -1, 0), 1);
1497 mesh.add_point(Point(-1, 1, 0), 2);
1498 mesh.add_point(Point(0, 2, 0), 3);
1499 mesh.add_point(Point(1, 1, 0), 4);
1500 mesh.add_point(Point(1, -1, 0), 5);
1501 mesh.add_point(Point(0, -2, 1), 6);
1502 mesh.add_point(Point(-1, -1, 1), 7);
1503 mesh.add_point(Point(-1, 1, 1), 8);
1504 mesh.add_point(Point(0, 2, 1), 9);
1505 mesh.add_point(Point(1, 1, 1), 10);
1506 mesh.add_point(Point(1, -1, 1), 11);
1507
1508 // See notes in elem_test.h
1509 // With this ordering, we'll need to use a mid-node to tetrahedralize it
1510 const std::vector<std::vector<unsigned int>> nodes_on_side =
1511 { {0, 1, 2, 3, 4, 5},
1512 {0, 1, 7, 6},
1513 {1, 2, 8, 7},
1514 {2, 3, 9, 8},
1515 {3, 4, 10, 9},
1516 {4, 5, 11, 10},
1517 {5, 0, 6, 11},
1518 {6, 7, 8, 9, 10, 11} };
1519
1520 // Build all the sides.
1521 std::vector<std::shared_ptr<Polygon>> sides(nodes_on_side.size());
1522
1523 for (auto s : index_range(nodes_on_side))
1524 {
1525 const auto & nodes_on_s = nodes_on_side[s];
1526 sides[s] = std::make_shared<C0Polygon>(nodes_on_s.size());
1527 for (auto i : index_range(nodes_on_s))
1528 sides[s]->set_node(i, mesh.node_ptr(nodes_on_s[i]));
1529 }
1530
1531 const auto poly = dynamic_cast<C0Polyhedron *>(buildC0Polyhedron(sides, mesh));
1532 CPPUNIT_ASSERT_EQUAL((unsigned int)13, poly->n_nodes()); // we should have a mid node
1533 testElemVolume(poly, 6);
1534 testC0PolyhedronMethods(mesh, /*midnode*/true);
1535
1536 // Check routine for subtet side to poly side mapping
1537 const auto subtet0_sides_to_poly_sides = poly->subelement_sides_to_poly_sides(0);
1538 CPPUNIT_ASSERT_EQUAL(0, subtet0_sides_to_poly_sides[0]);
1539 CPPUNIT_ASSERT_EQUAL(libMesh::invalid_int, subtet0_sides_to_poly_sides[1]);
1540 CPPUNIT_ASSERT_EQUAL(libMesh::invalid_int, subtet0_sides_to_poly_sides[2]);
1541 CPPUNIT_ASSERT_EQUAL(libMesh::invalid_int, subtet0_sides_to_poly_sides[3]);
1542 }

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

◆ testC0PolyhedronMethods()

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

Definition at line 1357 of file volume_test.C.

1358 {
1359 Elem * elem = mesh.query_elem_ptr(0);
1360 bool found_elem = elem;
1361 mesh.comm().max(found_elem);
1362 CPPUNIT_ASSERT(found_elem);
1363
1364 if (!elem)
1365 return;
1366
1367 CPPUNIT_ASSERT_EQUAL(elem->type(), C0POLYHEDRON);
1368
1369 const int V = elem->n_vertices();
1370 const int E = elem->n_edges();
1371 const int F = elem->n_faces();
1372
1373 if (!has_midnode)
1374 CPPUNIT_ASSERT_EQUAL(int(elem->n_nodes()), V);
1375 else
1376 CPPUNIT_ASSERT_EQUAL(int(elem->n_nodes()), V + 1);
1377 CPPUNIT_ASSERT_EQUAL(int(elem->n_sides()), F);
1378
1379 // Euler characteristic for polygons homeomorphic to spheres is 2
1380 CPPUNIT_ASSERT_EQUAL(V-E+F, 2);
1381
1382 int FE = 0;
1383 int FV = 0;
1384
1385 std::vector<int> sides_on_vertex(V, 0);
1386 for (auto s : make_range(F))
1387 {
1388 auto side = elem->build_side_ptr(s);
1389 CPPUNIT_ASSERT_EQUAL(side->type(), C0POLYGON);
1390 FE += side->n_edges();
1391 const int SV = side->n_vertices();
1392 FV += SV;
1393
1394 auto nos = elem->nodes_on_side(s);
1395 CPPUNIT_ASSERT_EQUAL(nos.size(), std::size_t(SV));
1396
1397 for (auto v : make_range(SV))
1398 {
1399 Node * sidenode = side->node_ptr(v);
1400 const unsigned int n = elem->get_node_index(sidenode);
1401 CPPUNIT_ASSERT(n != invalid_uint);
1402 ++sides_on_vertex[n];
1403
1404 // We're just looking at first order so far
1405 CPPUNIT_ASSERT(side->is_vertex(v));
1406 CPPUNIT_ASSERT(!side->is_edge(v));
1407 CPPUNIT_ASSERT(elem->is_vertex(n));
1408 CPPUNIT_ASSERT(!elem->is_edge(n));
1409 CPPUNIT_ASSERT(!elem->is_face(n));
1410 CPPUNIT_ASSERT(elem->is_node_on_side(n, s));
1411 CPPUNIT_ASSERT(std::find(nos.begin(), nos.end(), n) != nos.end());
1412 }
1413 }
1414
1415 // We hit every edge from 2 faces
1416 CPPUNIT_ASSERT_EQUAL(E*2, FE);
1417
1418 // We hit every vertex from at least 3 faces
1419 CPPUNIT_ASSERT_LESSEQUAL(FV, V*3); // V*3 <= FV
1420 for (auto sov : sides_on_vertex)
1421 CPPUNIT_ASSERT_LESSEQUAL(sov, 3); // 3 <= sov
1422
1423 CPPUNIT_ASSERT(!elem->is_flipped());
1424 }
virtual unsigned int n_faces() const =0
unsigned int get_node_index(const Node *node_ptr) const
Definition elem.h:2675
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i)=0
A specific instantiation of the FEBase class.
Definition fe.h:128
A Node is like a Point, but with more information.
Definition node.h:55
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

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(), libMesh::Parallel::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().

Referenced by testC0PolyhedronCube(), and testC0PolyhedronHexagonalPrism().

◆ testEdge3Invertible()

void VolumeTest::testEdge3Invertible ( )
inline

Definition at line 252 of file volume_test.C.

253 {
254 LOG_UNIT_TEST;
255
256 // 1.) This is the original test which started the investigation
257 // of determining invertibility. In this test, the actual
258 // midpoint of nodes 0 and 1 is 0.5*(1.100328e2 + 1.176528e2) =
259 // 113.8428, so we can see that the middle node is closer to the
260 // left endpoint. In this case, it is too close and the element is
261 // not invertible.
262 bool invertible = test_elem_invertible({
263 Point(-3.566160e1, -6.690970e-1, 1.100328e2),
264 Point(-3.566160e1, -6.690970e-1, 1.176528e2),
265 Point(-3.566160e1, -6.690970e-1, 1.115568e2)}, EDGE3);
266 CPPUNIT_ASSERT(!invertible);
267
268 // 2.) Just like case 1, but now node 2 is at the midpoint, so
269 // this case is invertible.
270 invertible = test_elem_invertible({
271 Point(-3.566160e1, -6.690970e-1, 1.100328e2),
272 Point(-3.566160e1, -6.690970e-1, 1.176528e2),
273 Point(-3.566160e1, -6.690970e-1, 113.8428)}, EDGE3);
274 CPPUNIT_ASSERT(invertible);
275
276 // 3.) Non-collinear case where the mid-edge node is "above" and "way
277 // past" the right endpoint. This case is not invertible
278 invertible = test_elem_invertible({Point(0, 0, 0), Point(1, 0, 0), Point(3.5, 1.5, 0)}, EDGE3);
279 CPPUNIT_ASSERT(!invertible);
280 }
bool test_elem_invertible(const std::vector< Point > &pts, ElemType elem_type)

References libMesh::EDGE3, and test_elem_invertible().

◆ testEdge3Volume()

void VolumeTest::testEdge3Volume ( )
inline

Definition at line 208 of file volume_test.C.

209 {
210 LOG_UNIT_TEST;
211
212 Mesh mesh(*TestCommWorld);
213 MeshTools::Generation::build_line (mesh, /*nelem=*/1, 0., 1., EDGE3);
214 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(3), mesh.n_nodes());
215
216 auto edge3 = mesh.query_elem_ptr(0);
217 if (!edge3) // We may be on a distributed mesh
218 return;
219
220 // Check unperturbed, straight edge case
221 LIBMESH_ASSERT_FP_EQUAL(1.0, edge3->volume(), TOLERANCE*TOLERANCE);
222
223 // Get references to the individual Edge3 nodes
224 auto & middle_node = edge3->node_ref(2);
225 auto & right_node = edge3->node_ref(1);
226
227 // Check middle node perturbed in +x direction case. This should
228 // not change the volume because it's still a straight line
229 // element.
230 middle_node = Point(0.5 + 1.e-3, 0., 0.);
231 LIBMESH_ASSERT_FP_EQUAL(1.0, edge3->volume(), TOLERANCE*TOLERANCE);
232
233 // Check middle node perturbed in -x direction case. This should
234 // not change the volume because it's still a straight line
235 // element.
236 middle_node = Point(0.5 - 1.e-3, 0., 0.);
237 LIBMESH_ASSERT_FP_EQUAL(1.0, edge3->volume(), TOLERANCE*TOLERANCE);
238
239 // Check volume of actual curved element against pre-computed value.
240 middle_node = Point(0.5, 0.25, 0.);
241 right_node = Point(1., 1., 0.);
242 LIBMESH_ASSERT_FP_EQUAL(1.4789428575446, edge3->volume(), TOLERANCE);
243
244 // Compare with volume computed by base class Elem::volume() call
245 // which uses quadrature. We don't expect this to have full
246 // floating point accuracy.
247 middle_node = Point(0.5, 0.1, 0.);
248 right_node = Point(1., 0., 0.);
249 LIBMESH_ASSERT_FP_EQUAL(edge3->Elem::volume(), edge3->volume(), 1e-4);
250 }
virtual dof_id_type n_nodes() 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.
uint8_t dof_id_type
Definition id_types.h:67

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

◆ testEdge4Invertible()

void VolumeTest::testEdge4Invertible ( )
inline

Definition at line 282 of file volume_test.C.

283 {
284 LOG_UNIT_TEST;
285
286 // Reference Elem should be invertible
287 {
288 const Elem & edge4 = ReferenceElem::get(EDGE4);
289 CPPUNIT_ASSERT(edge4.has_invertible_map());
290 }
291
292 // If node 2 goes to the left past -5/9 = -.555, the element becomes non-invertible
293 {
294 // x2 > -5/9, the map is still invertible
295 bool invertible =
296 test_elem_invertible({Point(-1, 0, 0), Point(1, 0, 0), Point(-0.5, 0, 0), Point(Real(1)/3, 0, 0)},
297 EDGE4);
298 CPPUNIT_ASSERT(invertible);
299
300 // x2 < -5/9, it is too close to x0 now
301 invertible =
302 test_elem_invertible({Point(-1, 0, 0), Point(1, 0, 0), Point(-0.57, 0, 0), Point(Real(1)/3, 0, 0)},
303 EDGE4);
304 CPPUNIT_ASSERT(!invertible);
305 }
306
307 // If node 2 goes to the right past 5/21 ~ 0.2381, the element becomes non-invertible
308 {
309 // x2 < 5/21, the map should still be invertible
310 bool invertible =
311 test_elem_invertible({Point(-1, 0, 0), Point(1, 0, 0), Point(Real(3)/21, 0, 0), Point(Real(1)/3, 0, 0)},
312 EDGE4);
313 CPPUNIT_ASSERT(invertible);
314
315 // x2 > 5/21, x2 is too close to x3 now
316 invertible =
317 test_elem_invertible({Point(-1, 0, 0), Point(1, 0, 0), Point(Real(6)/21, 0, 0), Point(Real(1)/3, 0, 0)},
318 EDGE4);
319 CPPUNIT_ASSERT(!invertible);
320 }
321 }
virtual bool has_invertible_map(Real tol=TOLERANCE *TOLERANCE) const
Definition elem.C:3016
const Elem & get(const ElemType type_in)

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

◆ testElemVolume()

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

Definition at line 1428 of file volume_test.C.

1430 {
1431 const Real derived_volume = elem->volume();
1432 const Real base_volume = elem->Elem::volume();
1433 LIBMESH_ASSERT_FP_EQUAL(base_volume, derived_volume, TOLERANCE*TOLERANCE);
1434 LIBMESH_ASSERT_FP_EQUAL(derived_volume, expected_volume, TOLERANCE*TOLERANCE);
1435 }

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

Referenced by testC0PolyhedronCube(), and testC0PolyhedronHexagonalPrism().

◆ testHex20PLevelTrueCentroid()

void VolumeTest::testHex20PLevelTrueCentroid ( )
inline

Definition at line 157 of file volume_test.C.

158 {
159 LOG_UNIT_TEST;
160
161 // Test that Elem base class true_centroid() implementation works
162 // for an elevated p_level HEX20
163 {
164#ifdef LIBMESH_ENABLE_AMR
165 ReplicatedMesh mesh(*TestCommWorld);
167 /*nelem=*/1, /*nelem=*/1, /*nelem=*/1,
168 /*xmin=*/-1, /*xmax=*/1,
169 /*ymin=*/-1, /*ymax=*/1,
170 /*zmin=*/-1, /*zmax=*/1,
171 HEX20);
172 Elem * hex20 = mesh.elem_ptr(0);
173 hex20->set_p_level(1);
174 Point true_centroid = hex20->true_centroid();
175 LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(0), TOLERANCE*TOLERANCE);
176 LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(1), TOLERANCE*TOLERANCE);
177 LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(2), TOLERANCE*TOLERANCE);
178#endif // LIBMESH_ENABLE_AMR
179 }
180 }
virtual Point true_centroid() const
Definition elem.C:515
void set_p_level(const unsigned int p)
Sets the value of the p-refinement level for the element.
virtual const Elem * elem_ptr(const dof_id_type i) const =0

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().

◆ testHex8Condition()

void VolumeTest::testHex8Condition ( )
inline

Definition at line 1081 of file volume_test.C.

1082 {
1083 LOG_UNIT_TEST;
1084
1085 auto cond_of = [this](const std::vector<Point> & pts)
1086 {
1087 auto [elem, nodes] = this->construct_elem(pts, HEX8);
1088 libmesh_ignore(nodes);
1089 return elem->quality(CONDITION);
1090 };
1091
1092 // Unit cube -> 1
1093 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0,
1094 /*actual=*/cond_of({Point(0,0,0), Point(1,0,0), Point(1,1,0), Point(0,1,0),
1095 Point(0,0,1), Point(1,0,1), Point(1,1,1), Point(0,1,1)}), TOLERANCE);
1096
1097 // 2x1x1 box: at each corner |A|_F^2 = 6, |det| = 2,
1098 // |A^-1|_F^2 = 9/4, so kappa = sqrt(6 * 9/4)/3 = sqrt(6)/2
1099 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/std::sqrt(Real(6))/2.,
1100 /*actual=*/cond_of({Point(0,0,0), Point(2,0,0), Point(2,1,0), Point(0,1,0),
1101 Point(0,0,1), Point(2,0,1), Point(2,1,1), Point(0,1,1)}), TOLERANCE);
1102 }

References libMesh::CONDITION, construct_elem(), libMesh::HEX8, libMesh::libmesh_ignore(), libMesh::Real, and libMesh::TOLERANCE.

◆ testHex8Size()

void VolumeTest::testHex8Size ( )
inline

Definition at line 979 of file volume_test.C.

980 {
981 LOG_UNIT_TEST;
982
983 auto size_of = [this](const std::vector<Point> & pts)
984 {
985 auto [elem, nodes] = this->construct_elem(pts, HEX8);
986 libmesh_ignore(nodes);
987 return elem->quality(SIZE);
988 };
989
990 // Affine boxes (uniform Jacobian) score 1 at any scale.
991 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0,
992 /*actual=*/size_of({Point(0,0,0), Point(1,0,0), Point(1,1,0), Point(0,1,0),
993 Point(0,0,1), Point(1,0,1), Point(1,1,1), Point(0,1,1)}), TOLERANCE);
994 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0,
995 /*actual=*/size_of({Point(0,0,0), Point(2,0,0), Point(2,1,0), Point(0,1,0),
996 Point(0,0,1), Point(2,0,1), Point(2,1,1), Point(0,1,1)}), TOLERANCE);
997
998 // A frustum: 2x2 base, unit top shrunk toward the axis. Bottom
999 // corners have nodal volume 4, top corners 1; the element volume is
1000 // 7/3 and the ideal cube's nodal-det/volume ratio is 1, so the ideal
1001 // nodal volume at this element's volume is 7/3. The worst corner
1002 // ratio is (1)/(7/3) = 3/7.
1003 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/Real(3)/7,
1004 /*actual=*/size_of({Point(0,0,0), Point(2,0,0), Point(2,2,0), Point(0,2,0),
1005 Point(0.5,0.5,1), Point(1.5,0.5,1), Point(1.5,1.5,1), Point(0.5,1.5,1)}), TOLERANCE);
1006 }

References construct_elem(), libMesh::HEX8, libMesh::libmesh_ignore(), libMesh::Real, libMesh::SIZE, and libMesh::TOLERANCE.

◆ testHex8SkewAngle()

void VolumeTest::testHex8SkewAngle ( )
inline

Definition at line 901 of file volume_test.C.

902 {
903 LOG_UNIT_TEST;
904
905 // Case 1: A unit cube has mutually orthogonal principal axes, so
906 // its skew angle is exactly 0.
907 {
908 std::vector<Point> pts = {
909 Point(0, 0, 0), Point(1, 0, 0), Point(1, 1, 0), Point(0, 1, 0),
910 Point(0, 0, 1), Point(1, 0, 1), Point(1, 1, 1), Point(0, 1, 1)};
911 auto [elem, nodes] = this->construct_elem(pts, HEX8);
912 libmesh_ignore(nodes);
913
914 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0.0, /*actual=*/elem->quality(SKEW_ANGLE), TOLERANCE);
915 }
916
917 // Case 2: Shear the top face of a unit cube by k in the
918 // x-direction. Only the zeta principal axis tilts, becoming
919 // (k, 0, 1); the xi and eta axes stay orthogonal. The largest
920 // |cos| between any pair of axes is then k / sqrt(k^2 + 1).
921 {
922 auto test_sheared_hex = [this](Real k)
923 {
924 std::vector<Point> pts = {
925 Point(0, 0, 0), Point(1, 0, 0), Point(1, 1, 0), Point(0, 1, 0),
926 Point(k, 0, 1), Point(1+k, 0, 1), Point(1+k, 1, 1), Point(k, 1, 1)};
927 auto [elem, nodes] = this->construct_elem(pts, HEX8);
928 libmesh_ignore(nodes);
929
930 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/std::abs(k) / std::sqrt(k*k + 1),
931 /*actual=*/elem->quality(SKEW_ANGLE), TOLERANCE);
932 };
933
934 // k = 1 -> 1/sqrt(2) ~ 0.7071
935 test_sheared_hex(1.0);
936 // k = 0.5 -> 0.5/sqrt(1.25) ~ 0.4472
937 test_sheared_hex(0.5);
938 }
939 }

References construct_elem(), libMesh::HEX8, libMesh::libmesh_ignore(), libMesh::Real, libMesh::SKEW_ANGLE, and libMesh::TOLERANCE.

◆ testHex8TrueCentroid()

void VolumeTest::testHex8TrueCentroid ( )
inline

Definition at line 154 of file volume_test.C.

154{ LOG_UNIT_TEST; test_true_centroid_and_volume(HEX8); }
void test_true_centroid_and_volume(ElemType elem_type)

References libMesh::HEX8, and test_true_centroid_and_volume().

◆ testPrism6TrueCentroid()

void VolumeTest::testPrism6TrueCentroid ( )
inline

Definition at line 155 of file volume_test.C.

155{ LOG_UNIT_TEST; test_true_centroid_and_volume(PRISM6); }

References libMesh::PRISM6, and test_true_centroid_and_volume().

◆ testPyramid5TrueCentroid()

void VolumeTest::testPyramid5TrueCentroid ( )
inline

Definition at line 137 of file volume_test.C.

138 {
139 LOG_UNIT_TEST;
140
141 // Test Pyramid5::true_centroid() gives the correct result for a reference element
142 {
143 const Elem & pyr5 = ReferenceElem::get(PYRAMID5);
144 Point true_centroid = pyr5.true_centroid();
145 LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(0), TOLERANCE*TOLERANCE);
146 LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(1), TOLERANCE*TOLERANCE);
147 LIBMESH_ASSERT_FP_EQUAL(0.25, true_centroid(2), TOLERANCE*TOLERANCE);
148 }
149
150 // Currently there is not an optimized Pyramid5::true_centroid() to compare against
152 }

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

◆ testQuad4AspectRatio()

void VolumeTest::testQuad4AspectRatio ( )
inline

Definition at line 414 of file volume_test.C.

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

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

◆ testQuad4Condition()

void VolumeTest::testQuad4Condition ( )
inline

Definition at line 1042 of file volume_test.C.

1043 {
1044 LOG_UNIT_TEST;
1045
1046 // CONDITION = max over corners of the Jacobian condition number
1047 // kappa = |A|_F |A^-1|_F / 2 = (|e0|^2 + |e1|^2) / (2 |e0 x e1|),
1048 // which is 1 for a square corner and grows with stretch or skew.
1049 auto cond_of = [this](const std::vector<Point> & pts)
1050 {
1051 auto [elem, nodes] = this->construct_elem(pts, QUAD4);
1052 libmesh_ignore(nodes);
1053 return elem->quality(CONDITION);
1054 };
1055
1056 // Unit square -> 1
1057 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0,
1058 /*actual=*/cond_of({Point(0,0,0), Point(1,0,0), Point(1,1,0), Point(0,1,0)}), TOLERANCE);
1059
1060 // 2x1 rectangle -> (4 + 1) / (2 * 2) = 1.25 at every corner
1061 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.25,
1062 /*actual=*/cond_of({Point(0,0,0), Point(2,0,0), Point(2,1,0), Point(0,1,0)}), TOLERANCE);
1063
1064 // Unit-edge rhombus with interior angle theta -> kappa = 1/sin(theta)
1065 {
1066 auto rhombus_condition = [&cond_of](Real theta)
1067 {
1068 const Real c = std::cos(theta), s = std::sin(theta);
1069 return cond_of({Point(0,0,0), Point(1,0,0), Point(1.+c,s,0), Point(c,s,0)});
1070 };
1071
1072 // theta = pi/6 -> 1/sin(pi/6) = 2
1073 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1./std::sin(libMesh::pi/6),
1074 /*actual=*/rhombus_condition(libMesh::pi/6), TOLERANCE);
1075 // theta = pi/3 -> 1/sin(pi/3) = 2/sqrt(3)
1076 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1./std::sin(libMesh::pi/3),
1077 /*actual=*/rhombus_condition(libMesh::pi/3), TOLERANCE);
1078 }
1079 }

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

◆ testQuad4Invertible()

void VolumeTest::testQuad4Invertible ( )
inline

Definition at line 323 of file volume_test.C.

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

References libMesh::pi, libMesh::QUAD4, libMesh::Real, and test_elem_invertible().

◆ testQuad4Jacobian()

void VolumeTest::testQuad4Jacobian ( )
inline

Definition at line 790 of file volume_test.C.

791 {
792 LOG_UNIT_TEST;
793
794 // Rhombus QUAD4. This case should have a JACOBIAN and
795 // SCALED_JACOBIAN value of sin(theta), where "theta" is the
796 // specified amount that we "sheared" the element by on creation.
797 // The JACOBIAN and SCALED_JACOBIAN are the same for this element
798 // because the edge lengths are all = 1.
799 {
800 // Helper lambda function that constructs a rhombus quad with
801 // interior acute angle theta.
802 auto test_rhombus_quad = [this](Real theta)
803 {
804 Real ct = std::cos(theta);
805 Real st = std::sin(theta);
806 std::vector<Point> pts = {
807 Point(0, 0, 0),
808 Point(1, 0, 0),
809 Point(1. + ct, st, 0),
810 Point( ct, st, 0)};
811 auto [elem, nodes] = this->construct_elem(pts, QUAD4);
812 libmesh_ignore(nodes);
813
814 Real jac = elem->quality(JACOBIAN);
815 Real scaled_jac = elem->quality(SCALED_JACOBIAN);
816
817 // Debugging
818 // libMesh::out << "jac = " << jac << std::endl;
819 // libMesh::out << "scaled_jac = " << scaled_jac << std::endl;
820
821 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/std::abs(std::sin(theta)), /*actual=*/jac, TOLERANCE);
822 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/std::abs(std::sin(theta)), /*actual=*/scaled_jac, TOLERANCE);
823 };
824
825 // 2a) Rhombus with interior angle theta=pi/6.
826 test_rhombus_quad(libMesh::pi / 6);
827
828 // 2b) Rhombus with interior angle theta=pi/3.
829 test_rhombus_quad(libMesh::pi / 3);
830 }
831 }

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

◆ testQuad4MinMaxAngle()

void VolumeTest::testQuad4MinMaxAngle ( )
inline

Definition at line 687 of file volume_test.C.

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

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

◆ testQuad4Size()

void VolumeTest::testQuad4Size ( )
inline

Definition at line 941 of file volume_test.C.

942 {
943 LOG_UNIT_TEST;
944
945 // Relative SIZE = min over corners of min(tau, 1/tau), where tau is
946 // the corner nodal Jacobian determinant divided by that of an ideal
947 // element of the same volume (the mean nodal determinant). It is 1
948 // for any element with a uniform Jacobian (any affine element, at
949 // any scale) and drops below 1 as the Jacobian varies across the
950 // element.
951 auto size_of = [this](const std::vector<Point> & pts)
952 {
953 auto [elem, nodes] = this->construct_elem(pts, QUAD4);
954 libmesh_ignore(nodes);
955 return elem->quality(SIZE);
956 };
957
958 // Affine elements (uniform Jacobian) all score 1, regardless of
959 // scale or shape: unit square, a larger square, a stretched
960 // rectangle, and a sheared rhombus.
961 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0,
962 /*actual=*/size_of({Point(0,0,0), Point(1,0,0), Point(1,1,0), Point(0,1,0)}), TOLERANCE);
963 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0,
964 /*actual=*/size_of({Point(0,0,0), Point(2,0,0), Point(2,2,0), Point(0,2,0)}), TOLERANCE);
965 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0,
966 /*actual=*/size_of({Point(0,0,0), Point(2,0,0), Point(2,1,0), Point(0,1,0)}), TOLERANCE);
967 {
968 const Real c = std::cos(libMesh::pi/6), s = std::sin(libMesh::pi/6);
969 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0,
970 /*actual=*/size_of({Point(0,0,0), Point(1,0,0), Point(1.+c,s,0), Point(c,s,0)}), TOLERANCE);
971 }
972
973 // Trapezoid with corner nodal areas {6, 6, 4, 4} (mean 5): the
974 // worst corner ratio is 4/5 = 0.8.
975 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0.8,
976 /*actual=*/size_of({Point(0,0,0), Point(3,0,0), Point(2,2,0), Point(0,2,0)}), TOLERANCE);
977 }

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

◆ testQuad4SkewAngle()

void VolumeTest::testQuad4SkewAngle ( )
inline

Definition at line 833 of file volume_test.C.

834 {
835 LOG_UNIT_TEST;
836
837 // The SKEW_ANGLE metric is the Verdict "skew": the maximum |cos A|
838 // between the element's principal axes. 0 means perfectly
839 // orthogonal (unskewed), larger (up to 1) means more skewed.
840
841 // Case 1: A unit square has orthogonal principal axes, so its skew
842 // angle is exactly 0.
843 {
844 std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(1, 1, 0), Point(0, 1, 0)};
845 auto [elem, nodes] = this->construct_elem(pts, QUAD4);
846 libmesh_ignore(nodes);
847
848 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0.0, /*actual=*/elem->quality(SKEW_ANGLE), TOLERANCE);
849 }
850
851 // Case 2: For a rhombus with interior angle theta, the two
852 // principal axes are separated by theta, so the skew metric is
853 // |cos(theta)|. This is also invariant to rigid body rotation, so
854 // we rotate the rhombus about the z-axis before checking.
855 {
856 auto test_rhombus_quad = [this](Real theta)
857 {
858 const Real ct = std::cos(theta);
859 const Real st = std::sin(theta);
860 std::vector<Point> pts = {
861 Point(0, 0, 0),
862 Point(1, 0, 0),
863 Point(1. + ct, st, 0),
864 Point( ct, st, 0)};
865
866 // Rotate all points about the z-axis by 30 degrees to confirm
867 // the metric is rotation invariant.
868 const Real cr = std::cos(libMesh::pi / 6);
869 const Real sr = std::sin(libMesh::pi / 6);
870 RealTensorValue Rz(cr, -sr, 0,
871 sr, cr, 0,
872 0, 0, 1);
873 for (auto & pt : pts)
874 pt = Rz * pt;
875
876 auto [elem, nodes] = this->construct_elem(pts, QUAD4);
877 libmesh_ignore(nodes);
878
879 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/std::abs(ct), /*actual=*/elem->quality(SKEW_ANGLE), TOLERANCE);
880 };
881
882 // theta = pi/2 -> |cos| = 0 (orthogonal)
883 test_rhombus_quad(libMesh::pi / 2);
884 // theta = pi/3 -> |cos| = 0.5
885 test_rhombus_quad(libMesh::pi / 3);
886 // theta = pi/6 -> |cos| = sqrt(3)/2
887 test_rhombus_quad(libMesh::pi / 6);
888 }
889
890 // Case 3: A degenerate quad with a zero-length principal axis
891 // returns 0 by the Verdict convention.
892 {
893 std::vector<Point> pts = {Point(0, 0, 0), Point(0, 0, 0), Point(1, 1, 0), Point(1, 1, 0)};
894 auto [elem, nodes] = this->construct_elem(pts, QUAD4);
895 libmesh_ignore(nodes);
896
897 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0.0, /*actual=*/elem->quality(SKEW_ANGLE), TOLERANCE);
898 }
899 }

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

◆ testQuad4Taper()

void VolumeTest::testQuad4Taper ( )
inline

Definition at line 1008 of file volume_test.C.

1009 {
1010 LOG_UNIT_TEST;
1011
1012 // TAPER = min over the two opposite-edge pairs of (shorter/longer
1013 // length), in (0, 1], with 1 meaning no taper.
1014 auto taper_of = [this](const std::vector<Point> & pts)
1015 {
1016 auto [elem, nodes] = this->construct_elem(pts, QUAD4);
1017 libmesh_ignore(nodes);
1018 return elem->quality(TAPER);
1019 };
1020
1021 // Unit square -> both pairs equal -> 1
1022 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0,
1023 /*actual=*/taper_of({Point(0,0,0), Point(1,0,0), Point(1,1,0), Point(0,1,0)}), TOLERANCE);
1024
1025 // 2x1 rectangle -> opposite edges equal (parallelogram) -> no taper -> 1
1026 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0,
1027 /*actual=*/taper_of({Point(0,0,0), Point(2,0,0), Point(2,1,0), Point(0,1,0)}), TOLERANCE);
1028
1029 // Rhombus (unit edges) -> all edges equal -> no taper -> 1
1030 {
1031 const Real c = std::cos(libMesh::pi/3), s = std::sin(libMesh::pi/3);
1032 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/1.0,
1033 /*actual=*/taper_of({Point(0,0,0), Point(1,0,0), Point(1.+c,s,0), Point(c,s,0)}), TOLERANCE);
1034 }
1035
1036 // Symmetric trapezoid: bottom edge length 4, top edge length 2, the
1037 // two slanted edges equal -> worst pair ratio = 2/4 = 0.5
1038 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0.5,
1039 /*actual=*/taper_of({Point(0,0,0), Point(4,0,0), Point(3,1,0), Point(1,1,0)}), TOLERANCE);
1040 }

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

◆ testQuad4TrueCentroid()

void VolumeTest::testQuad4TrueCentroid ( )
inline

Definition at line 85 of file volume_test.C.

86 {
87 LOG_UNIT_TEST;
88
89 // Test Quad4::true_centroid() override
90 {
91 const Elem & quad4 = ReferenceElem::get(QUAD4);
92 Point true_centroid = quad4.true_centroid();
93 LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(0), TOLERANCE*TOLERANCE);
94 LIBMESH_ASSERT_FP_EQUAL(0, true_centroid(1), TOLERANCE*TOLERANCE);
95
96 // Compare to centroid computed via generic base class implementation
97 Point base_class_centroid = quad4.Elem::true_centroid();
98 CPPUNIT_ASSERT(true_centroid.absolute_fuzzy_equals(base_class_centroid, TOLERANCE*TOLERANCE));
99 }
100
101 // Check that "optimized" Quad4::true_centroid() gives same result
102 // as "generic" Elem::true_centroid() on a mesh of 10% distorted elements.
103 {
104 ReplicatedMesh mesh(*TestCommWorld);
105
107 /*nx=*/3, /*ny=*/3,
108 /*xmin=*/0., /*xmax=*/1.,
109 /*ymin=*/0., /*ymax=*/1.,
110 QUAD4);
111
113 /*factor=*/0.1,
114 /*perturb_boundary=*/false);
115
116 for (const auto & elem : mesh.element_ptr_range())
117 {
118 Point derived_centroid = elem->true_centroid();
119 Point base_centroid = elem->Elem::true_centroid();
120
121 // Debugging: check results in detail
122 // auto flags = libMesh::out.flags();
123 // libMesh::out << std::scientific << std::setprecision(16);
124 // libMesh::out << "derived_centroid = " << derived_centroid << std::endl;
125 // libMesh::out << "base_centroid = " << base_centroid << std::endl;
126 // libMesh::out.flags(flags);
127
128 CPPUNIT_ASSERT(derived_centroid.absolute_fuzzy_equals(base_centroid, TOLERANCE*TOLERANCE));
129
130 Real derived_volume = elem->volume();
131 Real base_volume = elem->Elem::volume();
132 LIBMESH_ASSERT_FP_EQUAL(base_volume, derived_volume, TOLERANCE*TOLERANCE);
133 }
134 }
135 }
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.

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().

◆ testQuad4Warpage()

void VolumeTest::testQuad4Warpage ( )
inline

Definition at line 607 of file volume_test.C.

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

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

◆ testTet4DihedralAngle()

void VolumeTest::testTet4DihedralAngle ( )
inline

Definition at line 1104 of file volume_test.C.

1105 {
1106 LOG_UNIT_TEST;
1107
1108 // Construct a tetrahedron whose projection into the x-y plane looks like the unit square,
1109 // and where the apex node is just slightly out of the x-y plane. This element should have
1110 // reasonable MIN,MAX_ANGLE values but MIN,MAX_DIHEDRAL angles of nearly 0. This is an
1111 // example that demonstrates one should not solely use edge angles to determine Elem quality
1112 // in 3D.
1113 std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(0, 1, 0), Point(1, 1, 0.01)};
1114 auto [elem, nodes] = this->construct_elem(pts, TET4);
1115 libmesh_ignore(nodes);
1116
1117 Real min_angle = elem->quality(MIN_ANGLE);
1118 Real max_angle = elem->quality(MAX_ANGLE);
1119 Real min_dihedral_angle = elem->quality(MIN_DIHEDRAL_ANGLE);
1120 Real max_dihedral_angle = elem->quality(MAX_DIHEDRAL_ANGLE);
1121
1122 // Debugging
1123 // libMesh::out << "Squashed Tet4 min_angle = " << min_angle << " degrees" << std::endl;
1124 // libMesh::out << "Squashed Tet4 max_angle = " << max_angle << " degrees" << std::endl;
1125 // libMesh::out << "Squashed Tet4 min_dihedral_angle = " << min_dihedral_angle << " degrees" << std::endl;
1126 // libMesh::out << "Squashed Tet4 max_dihedral_angle = " << max_dihedral_angle << " degrees" << std::endl;
1127
1128 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/44.9985676771277, /*actual=*/min_angle, TOLERANCE);
1129 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/90, /*actual=*/max_angle, TOLERANCE);
1130
1131 // Assert that both min and max dihedral angles are less than 1 degree (a very low quality element)
1132 CPPUNIT_ASSERT_LESS(Real(1), min_dihedral_angle);
1133 CPPUNIT_ASSERT_LESS(Real(1), max_dihedral_angle);
1134 }

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

◆ testTet4Jacobian()

void VolumeTest::testTet4Jacobian ( )
inline

Definition at line 1136 of file volume_test.C.

1137 {
1138 LOG_UNIT_TEST;
1139
1140 {
1141 // Same element as in testTet4DihedralAngle(). Here we verify that
1142 // the element is low quality since the SCALED_JACOBIAN is < O(h)
1143 // as h -> 0, and h can be arbitrarily small in the squashed element.
1144 Real h = Real(1)/100;
1145 std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(0, 1, 0), Point(1, 1, h)};
1146 auto [elem, nodes] = this->construct_elem(pts, TET4);
1147 libmesh_ignore(nodes);
1148
1149 Real jac = elem->quality(JACOBIAN);
1150 Real scaled_jac = elem->quality(SCALED_JACOBIAN);
1151
1152 // Debugging
1153 // libMesh::out << "Squashed Tet4 jac = " << jac << std::endl;
1154 // libMesh::out << "Squashed Tet4 scaled_jac = " << scaled_jac << std::endl;
1155
1156 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/h, /*actual=*/jac, TOLERANCE);
1157 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/h/(h*h+1)/std::sqrt(h*h+2),
1158 /*actual=*/scaled_jac, TOLERANCE * TOLERANCE);
1159 }
1160
1161 {
1162 // A representative Tet generated by calling build_cube(). This
1163 // element has minimum interior edge angle of approximately
1164 // 35.26 degrees, so it it is not a simple refinement of the
1165 // reference element. It is not located at the origin, but still
1166 // has a simple to compute value for the JACOBIAN and
1167 // SCALED_JACOBIAN quality metrics.
1168 std::vector<Point> pts = {
1169 Point(2.5, 2.5, 4.5),
1170 Point(3.5, 1.5, 5.5),
1171 Point(1.5, 1.5, 5.5),
1172 Point(2.5, 2.5, 5.5)
1173 };
1174 auto [elem, nodes] = this->construct_elem(pts, TET4);
1175 libmesh_ignore(nodes);
1176
1177 Real jac = elem->quality(JACOBIAN);
1178 Real scaled_jac = elem->quality(SCALED_JACOBIAN);
1179
1180 // Debugging
1181 // libMesh::out << "build_cube() Tet4 jac = " << jac << std::endl;
1182 // libMesh::out << "build_cube() Tet4 scaled_jac = " << scaled_jac << std::endl;
1183
1184 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/2, /*actual=*/jac, TOLERANCE);
1185 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/Real(1)/std::sqrt(Real(6)), /*actual=*/scaled_jac, TOLERANCE);
1186 }
1187 }

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

◆ testTri3AspectRatio()

void VolumeTest::testTri3AspectRatio ( )
inline

Definition at line 562 of file volume_test.C.

563 {
564 LOG_UNIT_TEST;
565
566 // Case 1) Reference TRI3
567 {
568 std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(0, 1, 0)};
569 auto [elem, nodes] = this->construct_elem(pts, TRI3);
570 libmesh_ignore(nodes);
571
572 // Compute the aspect ratio for the reference Tri
573 // The expected value is ~ 1.44338
574 Real aspect_ratio = elem->quality(ASPECT_RATIO);
575 // libMesh::out << "Unit TRI3 aspect ratio = " << aspect_ratio << std::endl;
576 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/Real(5)/2/std::sqrt(Real(3)), /*actual=*/aspect_ratio, TOLERANCE);
577 }
578
579 // Case 2) Equilateral TRI3
580 {
581 std::vector<Point> pts = {Point(0, 0, 0), Point(1, 0, 0), Point(0.5, 0.5*std::sqrt(3), 0)};
582 auto [elem, nodes] = this->construct_elem(pts, TRI3);
583 libmesh_ignore(nodes);
584
585 // Compute the aspect ratio for the reference Tri
586 // The expected value is 1.0
587 Real aspect_ratio = elem->quality(ASPECT_RATIO);
588 // libMesh::out << "Equilateral TRI3 aspect ratio = " << aspect_ratio << std::endl;
589 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/Real(1), /*actual=*/aspect_ratio, TOLERANCE);
590 }
591
592 // Case 3) Reference TRI3 with one leg length = L >> 1
593 {
594 Real L = 10.;
595 std::vector<Point> pts = {Point(0, 0, 0), Point(L, 0, 0), Point(0, 1, 0)};
596 auto [elem, nodes] = this->construct_elem(pts, TRI3);
597 libmesh_ignore(nodes);
598
599 // Compute the aspect ratio for the reference Tri
600 // The expected value is ~ 11.5759
601 Real aspect_ratio = elem->quality(ASPECT_RATIO);
602 // libMesh::out << "TRI3 with leg length L = " << L << ", aspect ratio = " << aspect_ratio << std::endl;
603 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/Real(1)/std::sqrt(Real(3)) * (Real(2)*L + Real(1)/(2*L)), /*actual=*/aspect_ratio, TOLERANCE);
604 }
605 }

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

◆ testTri3TrueCentroid()

void VolumeTest::testTri3TrueCentroid ( )
inline

Definition at line 72 of file volume_test.C.

73 {
74 LOG_UNIT_TEST;
75
76 // The true_centroid() == vertex_average() == (1/3, 1/3) for reference Tri3
77 {
78 const Elem & tri3 = ReferenceElem::get(TRI3);
79 Point true_centroid = tri3.true_centroid();
80 LIBMESH_ASSERT_FP_EQUAL(Real(1)/3, true_centroid(0), TOLERANCE*TOLERANCE);
81 LIBMESH_ASSERT_FP_EQUAL(Real(1)/3, true_centroid(1), TOLERANCE*TOLERANCE);
82 }
83 }

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

◆ testTwistedVolume()

void VolumeTest::testTwistedVolume ( )
inline

Definition at line 182 of file volume_test.C.

183 {
184 LOG_UNIT_TEST;
185
186 ReplicatedMesh mesh(*TestCommWorld);
187
188 // Build an element type that will fall back on our generic
189 // quadrature-based Elem::volume()
191 /*nelem=*/1, /*nelem=*/1, /*nelem=*/1,
192 /*xmin=*/-1, /*xmax=*/1,
193 /*ymin=*/-1, /*ymax=*/1,
194 /*zmin=*/-1, /*zmax=*/1,
195 PRISM21);
196
197 // Pick an element and twist it
198 Elem * prism6 = mesh.elem_ptr(0);
199 prism6->point(1) *= -1;
200 prism6->point(1) += 2*prism6->point(0);
201
202 // The real test here is that volume() doesn't throw
203 const Real vol = prism6->volume();
204 const Real gold_vol = 3+Real(5)/9;
205 CPPUNIT_ASSERT_LESS(TOLERANCE, std::abs(vol-gold_vol));
206 }
const Point & point(const unsigned int i) const
Definition elem.h:2583

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().


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