Files
mfem/tests/unit/mesh/test_periodic_mesh.cpp
T

103 lines
3.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"
#include <algorithm>
using namespace mfem;
template<typename T>
bool InArray(const T* begin, size_t sz, T i)
{
const T *end = begin + sz;
return std::find(begin, end, i) != end;
}
bool IndicesAreConnected(const Table &t, int i, int j)
{
return InArray(t.GetRow(i), t.RowSize(i), j)
&& InArray(t.GetRow(j), t.RowSize(j), i);
}
TEST_CASE("Periodic mesh", "[Mesh]")
{
int n = 3;
SECTION("1D periodic mesh")
{
Mesh orig_mesh = Mesh::MakeCartesian1D(n);
std::vector<Vector> translations = {Vector({(real_t) 1.0})};
Mesh mesh = Mesh::MakePeriodic(
orig_mesh,
orig_mesh.CreatePeriodicVertexMapping(translations));
REQUIRE(mesh.GetNV() == n);
const Table &e2e = mesh.ElementToElementTable();
REQUIRE(IndicesAreConnected(e2e, 0, 2));
REQUIRE(IndicesAreConnected(e2e, 0, 1));
REQUIRE(IndicesAreConnected(e2e, 1, 2));
}
SECTION("2D periodic mesh")
{
auto el = GENERATE(Element::TRIANGLE, Element::QUADRILATERAL);
bool sfc = false; // <-- Lexicographic instead of SFC ordering
Mesh orig_mesh = Mesh::MakeCartesian2D(n, n, el, false, 1.0, 1.0, sfc);
std::vector<Vector> translations = {Vector({1.0,0.0}), Vector({0.0,1.0})};
Mesh mesh = Mesh::MakePeriodic(
orig_mesh,
orig_mesh.CreatePeriodicVertexMapping(translations));
REQUIRE(mesh.GetNV() == pow(n-1,2) + 2*(n-1) + 1);
if (el == Element::QUADRILATERAL)
{
const Table &e2e = mesh.ElementToElementTable();
for (int i=0; i<n; ++i)
{
// Bottom row connected to top row
REQUIRE(IndicesAreConnected(e2e, i, i + n*(n-1)));
// Left column connected to right column
REQUIRE(IndicesAreConnected(e2e, i*n, n-1 + i*n));
}
}
}
SECTION("3D periodic mesh")
{
auto el = GENERATE(Element::TETRAHEDRON, Element::HEXAHEDRON, Element::WEDGE);
bool sfc = false; // <-- Lexicographic instead of SFC ordering
Mesh orig_mesh = Mesh::MakeCartesian3D(n, n, n, el, 1.0, 1.0, 1.0, sfc);
std::vector<Vector> translations =
{
Vector({1.0, 0.0, 0.0}),
Vector({0.0, 1.0, 0.0}),
Vector({0.0, 0.0, 1.0})
};
Mesh mesh = Mesh::MakePeriodic(
orig_mesh,
orig_mesh.CreatePeriodicVertexMapping(translations));
REQUIRE(mesh.GetNV() == pow(n-1,3) + 3*pow(n-1,2) + 3*(n-1) + 1);
if (el == Element::HEXAHEDRON)
{
const Table &e2e = mesh.ElementToElementTable();
int n2 = n*n;
for (int j=0; j<n; ++j)
{
for (int i=0; i<n; ++i)
{
// z=0 face connected to z=1 face
REQUIRE(IndicesAreConnected(e2e, i + j*n, i + j*n + n2*(n-1)));
// y=0 face connected to y=1 face
REQUIRE(IndicesAreConnected(e2e, i + j*n2, i + j*n2 + n*(n-1)));
// x=0 face connected to x=1 face
REQUIRE(IndicesAreConnected(e2e, i*n + j*n2, i*n + j*n2 + n-1));
}
}
}
}
}