Co-authored-by: camierjs <camierjs@gmail.com> Co-authored-by: Veselin Dobrev <dobrev@llnl.gov>
224 lines
5.6 KiB
C++
224 lines
5.6 KiB
C++
// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
|
|
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
|
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
|
//
|
|
// This file is part of the MFEM library. For more information and source code
|
|
// availability visit https://mfem.org.
|
|
//
|
|
// MFEM is free software; you can redistribute it and/or modify it under the
|
|
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
|
// CONTRIBUTING.md for details.
|
|
|
|
#include "mfem.hpp"
|
|
#include "unit_tests.hpp"
|
|
|
|
using namespace mfem;
|
|
|
|
class TestMesh : public Mesh
|
|
{
|
|
public:
|
|
using Mesh::GetTriOrientation;
|
|
using Mesh::ComposeTriOrientations;
|
|
using Mesh::InvertTriOrientation;
|
|
using Mesh::GetQuadOrientation;
|
|
using Mesh::ComposeQuadOrientations;
|
|
using Mesh::InvertQuadOrientation;
|
|
};
|
|
|
|
void TriPerm(int i, int *v)
|
|
{
|
|
v[0] = int((i + 1) / 2) % 3;
|
|
v[1] = (7 - i) % 3;
|
|
v[2] = (int(i / 2)+ 2) % 3;
|
|
}
|
|
|
|
int QuadPermGen(int i, int s)
|
|
{
|
|
if (i % 2 == 0)
|
|
{
|
|
return (4 + s - i / 2) % 4;
|
|
}
|
|
else
|
|
{
|
|
return (4 - s + (i - 1)/2) % 4;
|
|
}
|
|
}
|
|
|
|
void QuadPerm(int i, int *v)
|
|
{
|
|
for (int j=0; j<4; j++)
|
|
{
|
|
v[j] = QuadPermGen(i, j);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Face Orientation", "[FaceOrientation]")
|
|
{
|
|
SECTION("Triangle")
|
|
{
|
|
const int va[3] = {0,1,2};
|
|
int vb[3] = {0,1,2};
|
|
int vc[3] = {0,1,2};
|
|
|
|
for (int i=0; i<6; i++)
|
|
{
|
|
TriPerm(i, vb);
|
|
|
|
int ori_a_b = TestMesh::GetTriOrientation(va, vb);
|
|
int ori_b_a = TestMesh::GetTriOrientation(vb, va);
|
|
|
|
int inv_ori_a_b = TestMesh::InvertTriOrientation(ori_a_b);
|
|
|
|
REQUIRE(inv_ori_a_b == ori_b_a);
|
|
|
|
for (int j=0; j<6; j++)
|
|
{
|
|
TriPerm(j, vc);
|
|
|
|
int ori_b_c = TestMesh::GetTriOrientation(vb, vc);
|
|
|
|
int test_ori = TestMesh::ComposeTriOrientations(ori_a_b, ori_b_c);
|
|
|
|
int ori_a_c = TestMesh::GetTriOrientation(va, vc);
|
|
|
|
REQUIRE(test_ori == ori_a_c);
|
|
}
|
|
}
|
|
}
|
|
SECTION("Quadrilateral")
|
|
{
|
|
const int va[4] = {0,1,2,3};
|
|
int vb[4] = {0,1,2,3};
|
|
int vc[4] = {0,1,2,3};
|
|
|
|
for (int i=0; i<8; i++)
|
|
{
|
|
QuadPerm(i, vb);
|
|
|
|
int ori_a_b = TestMesh::GetQuadOrientation(va, vb);
|
|
int ori_b_a = TestMesh::GetQuadOrientation(vb, va);
|
|
|
|
int inv_ori_a_b = TestMesh::InvertQuadOrientation(ori_a_b);
|
|
|
|
REQUIRE(inv_ori_a_b == ori_b_a);
|
|
|
|
for (int j=0; j<8; j++)
|
|
{
|
|
QuadPerm(j, vc);
|
|
|
|
int ori_b_c = TestMesh::GetQuadOrientation(vb, vc);
|
|
|
|
int test_ori = TestMesh::ComposeQuadOrientations(ori_a_b, ori_b_c);
|
|
|
|
int ori_a_c = TestMesh::GetQuadOrientation(va, vc);
|
|
|
|
REQUIRE(test_ori == ori_a_c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
constexpr Geometry::Type GetFaceType(Geometry::Type geom_t)
|
|
{
|
|
switch (geom_t)
|
|
{
|
|
case Geometry::SEGMENT:
|
|
return Geometry::POINT;
|
|
case Geometry::TRIANGLE:
|
|
return Geometry::SEGMENT;
|
|
case Geometry::SQUARE:
|
|
return Geometry::SEGMENT;
|
|
case Geometry::TETRAHEDRON:
|
|
return Geometry::TRIANGLE;
|
|
case Geometry::CUBE:
|
|
return Geometry::SQUARE;
|
|
default:
|
|
return Geometry::INVALID;
|
|
}
|
|
}
|
|
|
|
template <Geometry::Type geom>
|
|
void test_geom()
|
|
{
|
|
constexpr auto face_t = GetFaceType(geom);
|
|
using face_t_consts = Geometry::Constants<face_t>;
|
|
|
|
Mesh mesh;
|
|
constexpr int n1d = 1;
|
|
|
|
switch (geom)
|
|
{
|
|
case Geometry::SEGMENT:
|
|
mesh = Mesh::MakeCartesian1D(n1d, Element::SEGMENT);
|
|
break;
|
|
case Geometry::TRIANGLE:
|
|
mesh = Mesh::MakeCartesian2D(n1d, n1d, Element::TRIANGLE);
|
|
break;
|
|
case Geometry::SQUARE:
|
|
mesh = Mesh::MakeCartesian2D(n1d, n1d, Element::QUADRILATERAL);
|
|
break;
|
|
case Geometry::TETRAHEDRON:
|
|
mesh = Mesh::MakeCartesian3D(n1d, n1d, n1d, Element::TETRAHEDRON);
|
|
break;
|
|
case Geometry::CUBE:
|
|
mesh = Mesh::MakeCartesian3D(n1d, n1d, n1d, Element::HEXAHEDRON);
|
|
break;
|
|
default:
|
|
MFEM_ABORT("");
|
|
}
|
|
|
|
Element *be0 = mesh.GetBdrElement(0);
|
|
MFEM_VERIFY(be0->GetGeometryType() == face_t, "");
|
|
int f, o;
|
|
mesh.GetBdrElementFace(0, &f, &o);
|
|
const Element *face = mesh.GetFace(f);
|
|
int *be0_v = be0->GetVertices();
|
|
const int *face_v = face->GetVertices();
|
|
for (o = 0; o < face_t_consts::NumOrient; o++)
|
|
{
|
|
const int *face_perm = face_t_consts::Orient[o];
|
|
for (int i = 0; i < face_t_consts::NumVert; i++)
|
|
{
|
|
be0_v[i] = face_v[face_perm[i]];
|
|
}
|
|
IsoparametricTransformation bdr_tr, face_tr;
|
|
mesh.GetBdrElementTransformation(0, &bdr_tr);
|
|
mesh.GetFaceTransformation(f, &face_tr);
|
|
IntegrationPoint bdr_ip;
|
|
bdr_ip.Set3(0.1, 0.3, 0.0);
|
|
int inv_o;
|
|
mesh.GetBdrElementFace(0, &f, &inv_o);
|
|
MFEM_VERIFY(inv_o == face_t_consts::InvOrient[o], "");
|
|
IntegrationPoint face_ip = Mesh::TransformBdrElementToFace(
|
|
be0->GetGeometryType(), inv_o, bdr_ip);
|
|
Vector bdr_pt, face_pt;
|
|
bdr_tr.Transform(bdr_ip, bdr_pt);
|
|
face_tr.Transform(face_ip, face_pt);
|
|
REQUIRE(bdr_pt.DistanceTo(face_pt) == MFEM_Approx(0.0));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Boundary Element Face Orientation", "[FaceOrientation]")
|
|
{
|
|
SECTION("SEGMENT")
|
|
{
|
|
test_geom<Geometry::SEGMENT>();
|
|
}
|
|
SECTION("TRIANGLE")
|
|
{
|
|
test_geom<Geometry::TRIANGLE>();
|
|
}
|
|
SECTION("SQUARE")
|
|
{
|
|
test_geom<Geometry::SQUARE>();
|
|
}
|
|
SECTION("TETRAHEDRON")
|
|
{
|
|
test_geom<Geometry::TETRAHEDRON>();
|
|
}
|
|
SECTION("CUBE")
|
|
{
|
|
test_geom<Geometry::CUBE>();
|
|
}
|
|
}
|