DNDSR 0.2.1
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
Mesh_Helpers.hpp
Go to the documentation of this file.
1/** @file Mesh_Helpers.hpp
2 * @brief Unified mesh helpers: read, prepare, build boundary, serialize.
3 *
4 * Thin wrappers that compose the canonical mesh assembly pipeline from
5 * lower-level UnstructuredMesh / UnstructuredMeshSerialRW methods.
6 * Mirror the Python helpers in DNDSR.Geom.utils.
7 *
8 * See docs/dev/mesh_helpers_design.md for the design document.
9 */
10#pragma once
11
12#include "Mesh.hpp"
14
15#include <functional>
16#include <string>
17
18namespace DNDS::Geom
19{
20
21 // -----------------------------------------------------------------------
22 // BuildGhostPrimary: the 5-step connectivity+ghost sequence
23 // -----------------------------------------------------------------------
24
25 /** @brief Build connectivity and ghost layer for a freshly-distributed mesh.
26 *
27 * This 5-step sequence is identical across all read paths (CGNS serial,
28 * H5 parallel, H5 distributed).
29 *
30 * @param nGhostLayers Number of cell2cell hops for ghost cells (default 1).
31 */
32 inline void BuildGhostPrimary(UnstructuredMesh &mesh, int nGhostLayers = 1)
33 {
34 mesh.RecoverNode2CellAndNode2Bnd();
35 mesh.RecoverCell2CellAndBnd2Cell();
36 mesh.BuildGhostPrimary(nGhostLayers);
37 mesh.AdjGlobal2LocalPrimary();
38 mesh.AdjGlobal2LocalN2CB();
39 }
40
41 // -----------------------------------------------------------------------
42 // ReadMeshFromCGNS
43 // -----------------------------------------------------------------------
44
45 /** @brief Read a CGNS mesh, partition, and optionally elevate/bisect.
46 *
47 * After this call the mesh is distributed with ghost cells and local
48 * indices, but NOT solver-ready (no faces, no ghost N2CB).
49 *
50 * @param mesh Fresh UnstructuredMesh (constructed with mpi, dim).
51 * @param reader UnstructuredMeshSerialRW bound to @p mesh.
52 * @param meshFile Path to the CGNS file.
53 * @param partOpts Metis partition options.
54 * @param periodicTol Tolerance for periodic boundary deduplication.
55 * @param elevation 0 = none, 1 = O1->O2.
56 * @param bisect Number of bisection passes (0..4).
57 * @param nameMapper Optional callback mapping BC names to IDs
58 * (for the CGNS reader). If nullptr, the reader's
59 * default AutoAppendName2ID is used.
60 */
61 inline void ReadMeshFromCGNS(
64 const std::string &meshFile,
65 const PartitionOptions &partOpts = {},
66 real periodicTol = 1e-9,
67 int elevation = 0,
68 int bisect = 0,
69 std::function<t_index(const std::string &)> nameMapper = nullptr)
70 {
71 auto &mpi = mesh->getMPI();
72 int dim = mesh->getDim();
73
74 if (nameMapper)
75 reader->ReadFromCGNSSerial(meshFile, nameMapper);
76 else
77 reader->ReadFromCGNSSerial(meshFile);
78
79 reader->Deduplicate1to1Periodic(periodicTol);
80 reader->BuildCell2Cell();
81 reader->MeshPartitionCell2Cell(partOpts);
82 reader->PartitionReorderToMeshCell2Cell();
83
85
86 // --- Optional O2 elevation ---
87 if (elevation == 1)
88 {
90 DNDS_MAKE_SSP(meshO2, mpi, dim);
91 meshO2->BuildO2FromO1Elevation(*mesh);
92 std::swap(meshO2, mesh);
93
94 reader->mesh = mesh;
96 }
97
98 // --- Optional bisection ---
99 DNDS_assert(bisect >= 0 && bisect <= 4);
100 for (int iter = 1; iter <= bisect; iter++)
101 {
102 ssp<UnstructuredMesh> meshO2;
103 DNDS_MAKE_SSP(meshO2, mpi, dim);
104 meshO2->BuildO2FromO1Elevation(*mesh);
105
106 meshO2->RecoverNode2CellAndNode2Bnd();
107 meshO2->RecoverCell2CellAndBnd2Cell();
108 meshO2->BuildGhostPrimary();
109
110 ssp<UnstructuredMesh> meshO1B;
111 DNDS_MAKE_SSP(meshO1B, mpi, dim);
112 meshO1B->BuildBisectO1FormO2(*meshO2);
113
114 std::swap(meshO1B, mesh);
115 reader->mesh = mesh;
117
118 index nCell = mesh->NumCellGlobal();
119 index nNode = mesh->NumNodeGlobal();
120 if (mpi.rank == 0)
121 log() << fmt::format("Mesh Direct Bisect {} done, nCell [{}], nNode [{}]",
122 iter, nCell, nNode)
123 << std::endl;
124 }
125 }
126
127 // -----------------------------------------------------------------------
128 // ReadMeshFromH5
129 // -----------------------------------------------------------------------
130
131 /** @brief Read a mesh from DNDSR H5 with even-split + ParMetis repartition.
132 *
133 * Works with any number of MPI ranks regardless of how the file was written.
134 */
135 inline void ReadMeshFromH5(
138 const std::string &h5Path,
139 const PartitionOptions &partOpts = {})
140 {
141 auto &mpi = mesh.getMPI();
142 auto [pathMod, pathPart] = factory.ModifyFilePath(h5Path, mpi, "part_%d", true);
143 Serializer::SerializerBaseSSP serializerP = factory.BuildSerializer(mpi);
144
145 if (mpi.rank == 0)
146 log() << "ReadMeshFromH5: distributed read via [" << factory.type
147 << "]" << std::endl;
148
149 serializerP->OpenFile(pathMod, true);
150 mesh.ReadSerializeAndDistribute(serializerP, "meshPart", partOpts);
151 serializerP->CloseFile();
152
154 }
155
156 /** @brief Read a pre-partitioned mesh from H5 (exact np match required).
157 *
158 * Uses ReadSerialize (no repartitioning). The file must have been written
159 * with the same number of MPI ranks.
160 */
164 const std::string &h5Path)
165 {
166 auto &mpi = mesh.getMPI();
167 auto [pathMod, pathPart] = factory.ModifyFilePath(h5Path, mpi, "part_%d", true);
168 Serializer::SerializerBaseSSP serializerP = factory.BuildSerializer(mpi);
169
170 if (mpi.rank == 0)
171 log() << "ReadMeshFromH5Parallel: reading via [" << factory.type
172 << "]" << std::endl;
173
174 serializerP->OpenFile(pathMod, true);
175 mesh.ReadSerialize(serializerP, "meshPart");
176 serializerP->CloseFile();
177
179 }
180
181 // -----------------------------------------------------------------------
182 // PrepareMesh
183 // -----------------------------------------------------------------------
184
185 /** @brief Options for PrepareMesh. */
187 {
188 int reorderCells = 0; ///< 0 = natural, 1 = reorder
189 int reorderParts = 1; ///< nParts for ReorderLocalCells
190 bool buildSerialOut = true; ///< build serial output arrays
191 };
192
193 /** @brief Prepare a distributed mesh for solver use.
194 *
195 * Steps: cell reorder, face interpolation, ghost N2CB, optional serial output.
196 * Does NOT include: elevation smoothing, wall distance, coord transforms,
197 * periodic nodes, VTK connectivity, boundary mesh.
198 * Those remain solver / caller responsibility.
199 *
200 * @param mesh Distributed mesh (output of ReadMeshFromCGNS / ReadMeshFromH5).
201 * @param reader The reader bound to @p mesh.
202 * @param opts Options controlling reordering and serial output.
203 */
204 inline void PrepareMesh(
207 const PrepareMeshOptions &opts = {})
208 {
209 auto &mpi = mesh.getMPI();
210
211 if (opts.reorderCells == 1)
212 mesh.ReorderLocalCells(opts.reorderParts);
213
214 mesh.InterpolateFace();
215 mesh.AssertOnFaces();
216
217 mesh.AdjLocal2GlobalN2CB();
218 mesh.BuildGhostN2CB();
219 mesh.AdjGlobal2LocalN2CB();
220 log() << fmt::format("{}, NumBndGhost {}", mpi.rank, mesh.NumBndGhost())
221 << std::endl;
222
223 // Owned nodes must have all cell neighbors resolved to local indices.
224 // Ghost (son) nodes may have unresolved neighbors encoded as negative.
225 for (index iNode = 0; iNode < mesh.NumNode(); iNode++)
226 for (index iCell : mesh.node2cell.father->operator[](iNode))
227 DNDS_assert(iCell >= 0);
228
229 if (opts.buildSerialOut)
230 {
231 mesh.AdjLocal2GlobalPrimary();
232 reader.BuildSerialOut();
233 mesh.AdjGlobal2LocalPrimary();
234 }
235 }
236
237 // -----------------------------------------------------------------------
238 // BuildBndMesh
239 // -----------------------------------------------------------------------
240
241 /** @brief Extract the boundary surface mesh from a solver-ready volume mesh.
242 *
243 * @param mesh The volume mesh (must have faces built).
244 * @param meshBnd Output boundary mesh (constructed with dim-1).
245 * @param readerBnd Reader bound to @p meshBnd.
246 * @param buildSerialOut Whether to build serial output for the bnd mesh.
247 */
248 inline void BuildBndMesh(
250 UnstructuredMesh &meshBnd,
251 UnstructuredMeshSerialRW &readerBnd,
252 bool buildSerialOut = true)
253 {
254 mesh.ConstructBndMesh(meshBnd);
255 if (buildSerialOut)
256 {
258 readerBnd.BuildSerialOut();
260 }
261 }
262
263 // -----------------------------------------------------------------------
264 // SerializeMesh
265 // -----------------------------------------------------------------------
266
267 /** @brief Write a partitioned mesh to H5 for later distributed read.
268 *
269 * The Python equivalent of the C++ ``partitionMeshOnly`` path.
270 */
271 inline void SerializeMesh(
273 const std::string &outputPath,
275 {
276 auto &mpi = mesh.getMPI();
277 auto [pathMod, pathPart] = factory.ModifyFilePath(outputPath, mpi, "part_%d", false);
278 Serializer::SerializerBaseSSP serializerP = factory.BuildSerializer(mpi);
279
280 serializerP->OpenFile(pathMod, false);
281 mesh.AdjLocal2GlobalPrimary();
282 mesh.WriteSerialize(serializerP, "meshPart");
283 mesh.AdjGlobal2LocalPrimary();
284 serializerP->CloseFile();
285 }
286
287 // -----------------------------------------------------------------------
288 // MeshH5Path (naming convention)
289 // -----------------------------------------------------------------------
290
291 /** @brief Build the conventional H5 filename for a partitioned mesh.
292 *
293 * Convention: ``{base}_part_{mpiSize}[_elevated][_bisectN]``
294 * (The caller / SerializerFactory appends the actual extension.)
295 */
296 inline std::string MeshH5Path(
297 const std::string &base, int mpiSize,
298 int elevation = 0, int bisect = 0)
299 {
300 using namespace std::literals;
301 std::string name = base + "_part_" + std::to_string(mpiSize);
302 if (elevation == 1)
303 name += "_elevated";
304 if (bisect > 0)
305 name += "_bisect" + std::to_string(bisect);
306 return name;
307 }
308
309} // namespace DNDS::Geom
#define DNDS_MAKE_SSP(ssp,...)
Definition Defines.hpp:217
#define DNDS_assert(expr)
Debug-only assertion (compiled out when DNDS_NDEBUG is defined). Prints the expression + file/line + ...
Definition Errors.hpp:112
Configurable factory that builds either a SerializerJSON or a SerializerH5 with all tunables exposed ...
void BuildGhostPrimary(UnstructuredMesh &mesh, int nGhostLayers=1)
Build connectivity and ghost layer for a freshly-distributed mesh.
void ReadMeshFromCGNS(ssp< UnstructuredMesh > &mesh, ssp< UnstructuredMeshSerialRW > &reader, const std::string &meshFile, const PartitionOptions &partOpts={}, real periodicTol=1e-9, int elevation=0, int bisect=0, std::function< t_index(const std::string &)> nameMapper=nullptr)
Read a CGNS mesh, partition, and optionally elevate/bisect.
void BuildBndMesh(UnstructuredMesh &mesh, UnstructuredMesh &meshBnd, UnstructuredMeshSerialRW &readerBnd, bool buildSerialOut=true)
Extract the boundary surface mesh from a solver-ready volume mesh.
int32_t t_index
Definition Geometric.hpp:6
void SerializeMesh(UnstructuredMesh &mesh, const std::string &outputPath, Serializer::SerializerFactory &factory)
Write a partitioned mesh to H5 for later distributed read.
void ReadMeshFromH5(UnstructuredMesh &mesh, Serializer::SerializerFactory factory, const std::string &h5Path, const PartitionOptions &partOpts={})
Read a mesh from DNDSR H5 with even-split + ParMetis repartition.
std::string MeshH5Path(const std::string &base, int mpiSize, int elevation=0, int bisect=0)
Build the conventional H5 filename for a partitioned mesh.
void PrepareMesh(UnstructuredMesh &mesh, UnstructuredMeshSerialRW &reader, const PrepareMeshOptions &opts={})
Prepare a distributed mesh for solver use.
void ReadMeshFromH5Parallel(UnstructuredMesh &mesh, Serializer::SerializerFactory factory, const std::string &h5Path)
Read a pre-partitioned mesh from H5 (exact np match required).
ssp< SerializerBase > SerializerBaseSSP
int64_t index
Global row / DOF index type (signed 64-bit; handles multi-billion-cell meshes).
Definition Defines.hpp:112
std::shared_ptr< T > ssp
Shortened alias for std::shared_ptr used pervasively in DNDSR.
Definition Defines.hpp:143
double real
Canonical floating-point scalar used throughout DNDSR (double precision).
Definition Defines.hpp:110
std::ostream & log()
Return the current DNDSR log stream (either std::cout or the installed file).
Definition Defines.cpp:50
Options for PrepareMesh.
bool buildSerialOut
build serial output arrays
int reorderCells
0 = natural, 1 = reorder
int reorderParts
nParts for ReorderLocalCells
void BuildSerialOut()
should be called to build data for serial out
Definition Mesh.cpp:193
Config-backed factory selecting between JSON and HDF5 serializers.
std::tuple< std::string, std::string > ModifyFilePath(std::string fname, const MPIInfo &mpi, const std::string &rank_part_fmt="%06d", bool read=false) const
Expand a user-supplied base file name into the backend-specific path layout.
std::string type
Backend selector: "JSON" or "H5".
SerializerBaseSSP BuildSerializer(const MPIInfo &mpi) const
Instantiate the selected serializer and apply its tunables.
DistributedHex3D mesh
const DNDS::index nCell
const DNDS::index nNode