#include #include #include "serif/discretization/domain/mesh/topology.hpp" #include "serif/discretization/domain/schema/schemas.hpp" #include "serif/discretization/domain/schema/validation/all.hpp" namespace { namespace domain = serif::discretization::domain; /** @brief Represent the core, envelope, vacuum and their interfaces without a finite-element backend. */ [[nodiscard]] domain::mesh::MeshTopologyData layered_topology() { return { .elementDomainIDs = {1, 2, 3}, .faceElements = {{.firstElementID = 0, .secondElementID = 1}, {.firstElementID = 1, .secondElementID = 2}, {.firstElementID = 2}}, .boundaryElementBoundaryIDs = {1, 2}, .boundaryElementFaceIDs = {1, 2} }; } } TEST_CASE("Physical schema validation uses backend-independent mesh connectivity", "[unit][discretization][domain]") { const domain::mesh::MeshTopology topology(layered_topology()); const auto result = domain::schema::validation::validate_schema(topology); REQUIRE(result); CHECK(result.relation_count() == 7); CHECK(topology.element_neighbors(0) == std::vector{1}); CHECK((topology.element_neighbors(1) == std::vector{0, 2})); CHECK(topology.boundary_elements_on_face(1) == std::vector{0}); CHECK(topology.boundary_element_face(1) == 2); CHECK(topology.face_elements(2).secondElementID == -1); } TEST_CASE("Neutral topology rejects invalid indexing before deriving adjacency", "[unit][discretization][domain]") { domain::mesh::MeshTopologyData data = layered_topology(); SECTION("A face names an absent volume element") { data.faceElements.front().firstElementID = 3; } SECTION("Boundary labels and faces have different counts") { data.boundaryElementFaceIDs.pop_back(); } SECTION("A boundary names an absent face") { data.boundaryElementFaceIDs.front() = 3; } CHECK_THROWS(domain::mesh::MeshTopology(data)); } TEST_CASE("Neutral topology retains unresolved and multiply labelled boundary faces", "[unit][discretization][domain]") { domain::mesh::MeshTopologyData data = layered_topology(); data.boundaryElementBoundaryIDs.insert(data.boundaryElementBoundaryIDs.end(), {7, 8}); data.boundaryElementFaceIDs.insert(data.boundaryElementFaceIDs.end(), {1, -1}); const domain::mesh::MeshTopology topology(data); CHECK((topology.boundary_elements_on_face(1) == std::vector{0, 2})); CHECK(topology.boundary_element_face(3) == -1); CHECK(topology.boundary_element_boundary_id(3) == 8); CHECK(topology.element_neighbors(-1).empty()); CHECK(topology.boundary_elements_on_face(100).empty()); CHECK(topology.element_domain_id(100) == 0); }