diff --git a/cpp/test/CMakeLists.txt b/cpp/test/CMakeLists.txt index a12aac898e4..e2a8e2a9b76 100644 --- a/cpp/test/CMakeLists.txt +++ b/cpp/test/CMakeLists.txt @@ -42,6 +42,7 @@ add_executable( common/sort.cpp fem/functionspace.cpp mesh/distributed_mesh.cpp + mesh/rectangle.cpp mesh/generation.cpp common/CIFailure.cpp refinement/interval.cpp diff --git a/cpp/test/mesh/rectangle.cpp b/cpp/test/mesh/rectangle.cpp new file mode 100644 index 00000000000..47a3835139c --- /dev/null +++ b/cpp/test/mesh/rectangle.cpp @@ -0,0 +1,211 @@ +// Copyright (C) 2024 Paul T. Kühner +// +// This file is part of DOLFINX (https://www.fenicsproject.org) +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + +using namespace dolfinx; +using namespace Catch::Matchers; + +TEMPLATE_TEST_CASE("Rectangle quadrilateral mesh", + "[mesh][rectangle][quadrilateral]", float, double) +{ + using T = TestType; + + const std::array lower = {0, 0}; + const std::array upper = {1, 1}; + + mesh::Mesh mesh = dolfinx::mesh::create_rectangle( + MPI_COMM_SELF, {lower, upper}, {1, 1}, mesh::CellType::quadrilateral); + + // vertex layout: + // 1---3 + // | | + // | | + // | | + // 0---2 + std::vector expected_x = { + /* v_0 */ 0, 0, 0, + /* v_1 */ 0, 1, 0, + /* v_2 */ 1, 0, 0, + /* v_3 */ 1, 1, 0, + }; + + CHECK_THAT(mesh.geometry().x(), + RangeEquals(expected_x, [](auto a, auto b) + { return std::abs(a - b) <= EPS; })); + + // edge layout: + // x-2-x + // | | + // 0 3 + // | | + // x-1-x + mesh.topology()->create_connectivity(1, 0); + auto e_to_v = mesh.topology()->connectivity(1, 0); + REQUIRE(e_to_v); + + CHECK_adjacency_list_equal(*e_to_v, {/* e_0 */ {0, 1}, + /* e_1 */ {0, 2}, + /* e_2 */ {1, 3}, + /* e_3 */ {2, 3}}); +} + +TEMPLATE_TEST_CASE("Rectangle triangle mesh (right)", + "[mesh][rectangle][triangle][right]", float, double) +{ + using T = TestType; + + const std::array lower = {0, 0}; + const std::array upper = {1, 1}; + + mesh::Mesh mesh = dolfinx::mesh::create_rectangle( + MPI_COMM_SELF, {lower, upper}, {1, 1}, mesh::CellType::triangle, + mesh::DiagonalType::right); + + // vertex layout: + // 3---2 + // | /| + // | / | + // |/ | + // 0---1 + std::vector expected_x = {/* v_0 */ 0, 0, 0, + /* v_1 */ 1, 0, 0, + /* v_2 */ 1, 1, 0, + /* v_3 */ 0, 1, 0}; + + CHECK_THAT(mesh.geometry().x(), + RangeEquals(expected_x, [](auto a, auto b) + { return std::abs(a - b) <= EPS; })); + + // edge layout: + // x-4-x + // | /| + // 2 1 3 + // |/ | + // x-0-x + mesh.topology()->create_connectivity(1, 0); + auto e_to_v = mesh.topology()->connectivity(1, 0); + REQUIRE(e_to_v); + + CHECK_adjacency_list_equal(*e_to_v, {/* e_0 */ {0, 1}, + /* e_1 */ {0, 2}, + /* e_2 */ {0, 3}, + /* e_3 */ {1, 2}, + /* e_4 */ {2, 3}}); +} + +TEMPLATE_TEST_CASE("Rectangle triangle mesh (left)", + "[mesh][rectangle][triangle][left]", float, double) +{ + using T = TestType; + + const std::array lower = {0, 0}; + const std::array upper = {1, 1}; + + mesh::Mesh mesh = dolfinx::mesh::create_rectangle( + MPI_COMM_SELF, {lower, upper}, {1, 1}, mesh::CellType::triangle, + mesh::DiagonalType::left); + + // vertex layout: + // 2---3 + // |\ | + // | \ | + // | \| + // 0---1 + std::vector expected_x = { + /* v_0 */ 0, 0, 0, + /* v_1 */ 1, 0, 0, + /* v_2 */ 0, 1, 0, + /* v_3 */ 1, 1, 0, + }; + + CHECK_THAT(mesh.geometry().x(), + RangeEquals(expected_x, [](auto a, auto b) + { return std::abs(a - b) <= EPS; })); + + // edge layout: + // x-4-x + // |\ | + // 1 2 3 + // | \| + // x-0-x + mesh.topology()->create_connectivity(1, 0); + auto e_to_v = mesh.topology()->connectivity(1, 0); + REQUIRE(e_to_v); + + CHECK_adjacency_list_equal(*e_to_v, {/* e_0 */ {0, 1}, + /* e_1 */ {0, 2}, + /* e_2 */ {1, 2}, + /* e_3 */ {1, 3}, + /* e_4 */ {2, 3}}); +} + +TEMPLATE_TEST_CASE("Rectangle triangle mesh (crossed)", + "[mesh][rectangle][triangle][crossed]", float, double) +{ + using T = TestType; + + const std::array lower = {0, 0}; + const std::array upper = {1, 1}; + + mesh::Mesh mesh = dolfinx::mesh::create_rectangle( + MPI_COMM_SELF, {lower, upper}, {1, 1}, mesh::CellType::triangle, + mesh::DiagonalType::crossed); + + // vertex layout: + // 3---4 + // |\ /| + // | 2 | + // |/ \| + // 0---1 + std::vector expected_x = { + /* v_0 */ 0, 0, 0, + /* v_1 */ 1, 0, 0, + /* v_2 */ .5, .5, 0, + /* v_3 */ 0, 1, 0, + /* v_4 */ 1, 1, 0, + }; + + CHECK_THAT(mesh.geometry().x(), + RangeEquals(expected_x, [](auto a, auto b) + { return std::abs(a - b) <= EPS; })); + + // edge layout: + // x-7-x + // |5 6| + // 2 x 4 + // |1 3| + // x-0-x + mesh.topology()->create_connectivity(1, 0); + auto e_to_v = mesh.topology()->connectivity(1, 0); + REQUIRE(e_to_v); + + CHECK_adjacency_list_equal(*e_to_v, {/* e_0 */ {0, 1}, + /* e_1 */ {0, 2}, + /* e_2 */ {0, 3}, + /* e_3 */ {1, 2}, + /* e_4 */ {1, 4}, + /* e_5 */ {2, 3}, + /* e_6 */ {2, 4}, + /* e_7 */ {3, 4}}); +} diff --git a/cpp/test/mesh/util.h b/cpp/test/mesh/util.h new file mode 100644 index 00000000000..5fe02779dc4 --- /dev/null +++ b/cpp/test/mesh/util.h @@ -0,0 +1,29 @@ +// Copyright (C) 2024 Paul T. Kühner +// +// This file is part of DOLFINX (https://www.fenicsproject.org) +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include +#include + +#include +#include + +#include + +template +constexpr auto EPS = std::numeric_limits::epsilon(); + +template +void CHECK_adjacency_list_equal( + const dolfinx::graph::AdjacencyList& adj_list, + const std::vector>& expected_list) +{ + REQUIRE(static_cast(adj_list.num_nodes()) == expected_list.size()); + + for (T i = 0; i < adj_list.num_nodes(); i++) + CHECK_THAT(adj_list.links(i), Catch::Matchers::RangeEquals(expected_list[i])); +}