From fb65e7eaa4eea3d7d9e45b07bfaa7d969b44adb7 Mon Sep 17 00:00:00 2001 From: Vikas Kurapati Date: Wed, 29 Apr 2026 16:16:02 +0200 Subject: [PATCH 1/2] fixes for SeisSol periodic meshes --- src/meshreader/ParallelGMSHReader.h | 56 +++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/meshreader/ParallelGMSHReader.h b/src/meshreader/ParallelGMSHReader.h index 19dcb99..b11c6b6 100644 --- a/src/meshreader/ParallelGMSHReader.h +++ b/src/meshreader/ParallelGMSHReader.h @@ -13,7 +13,9 @@ #include #include +#include #include +#include #include #include "helper/Distributor.h" @@ -43,6 +45,7 @@ template class ParallelGMSHReader { logError() << meshFile << std::endl << parser.getErrorMessage(); } builder_.postprocess(); + validateIdentifyTopology(); convertBoundaryConditions(); nVertices_ = builder_.vertices.size(); @@ -77,6 +80,59 @@ template class ParallelGMSHReader { } private: + /** + * Checks that periodic vertex identification does not create non-manifold + * topology (i.e. identified faces shared by more than two cells). + */ + void validateIdentifyTopology() const { + if (builder_.identify.empty()) { + return; + } + + using FaceKey = std::array; + struct FaceKeyHash { + std::size_t operator()(const FaceKey& key) const { + return (key[0] * 73856093u) ^ (key[1] * 19349663u) ^ (key[2] * 83492791u); + } + }; + + std::unordered_map faceMultiplicity; + faceMultiplicity.reserve(builder_.elements.size() * (Dim + 1u)); + + bool hasNonManifoldFace = false; + FaceKey exampleFace{0, 0, 0}; + std::size_t exampleCount = 0; + + for (const auto& element : builder_.elements) { + for (int localFctNo = 0; localFctNo < Dim + 1u; ++localFctNo) { + FaceKey face{}; + for (int localNo = 0; localNo < Dim; ++localNo) { + const auto localNoElement = Facet2Nodes[localFctNo][localNo]; + const auto vertex = element[localNoElement]; + face[localNo] = builder_.identify[vertex]; + } + std::sort(face.begin(), face.end()); + + const auto count = ++faceMultiplicity[face]; + if (count > 2) { + hasNonManifoldFace = true; + exampleFace = face; + exampleCount = count; + } + } + } + + if (hasNonManifoldFace) { + logError() + << "Invalid periodic identify topology: found a face shared by more than two cells. " + << "Example canonical face ids: (" << exampleFace[0] << ", " << exampleFace[1] << ", " + << exampleFace[2] << ") with multiplicity " << exampleCount + << ". This mesh is too coarse or topologically incompatible with identify-vertex " + "periodic encoding. Refine the mesh near periodic boundaries and regenerate."; + MPI_Abort(comm_, EXIT_FAILURE); + } + } + /** * GMSH stores boundary conditions on a surface mesh whereas SeisSol expects * boundary conditions to be stored per element. In the following we convert From a8122614f9cbe859f2da63f907746ffe3cd84496 Mon Sep 17 00:00:00 2001 From: Vikas Kurapati Date: Thu, 30 Apr 2026 10:11:39 +0200 Subject: [PATCH 2/2] Address review Contains suggestions from Copilot --- src/meshreader/ParallelGMSHReader.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/meshreader/ParallelGMSHReader.h b/src/meshreader/ParallelGMSHReader.h index b11c6b6..4579d3f 100644 --- a/src/meshreader/ParallelGMSHReader.h +++ b/src/meshreader/ParallelGMSHReader.h @@ -89,7 +89,7 @@ template class ParallelGMSHReader { return; } - using FaceKey = std::array; + using FaceKey = std::array; struct FaceKeyHash { std::size_t operator()(const FaceKey& key) const { return (key[0] * 73856093u) ^ (key[1] * 19349663u) ^ (key[2] * 83492791u); @@ -124,11 +124,12 @@ template class ParallelGMSHReader { if (hasNonManifoldFace) { logError() - << "Invalid periodic identify topology: found a face shared by more than two cells. " + << "Invalid periodic identify topology: multiple distinct faces collapse to the same" + << "canonical face under indentify, yielding a face shared by more than two cells." << "Example canonical face ids: (" << exampleFace[0] << ", " << exampleFace[1] << ", " - << exampleFace[2] << ") with multiplicity " << exampleCount - << ". This mesh is too coarse or topologically incompatible with identify-vertex " - "periodic encoding. Refine the mesh near periodic boundaries and regenerate."; + << exampleFace[2] << ") with " << exampleCount + << ". Verify periodic entity pairing and the periodic section in the mesh file, " + << "and regenerate the mesh with consistent periodic definitions"; MPI_Abort(comm_, EXIT_FAILURE); } }