|
DNDSR 0.1.0.dev1+gcd065ad
Distributed Numeric Data Structure for CFV
|
Note (2026-04-20): This file was audited. Several items previously listed as open have been verified as complete and are now struck through. Remaining high-priority open items include: replacing global
add_compile_options(still present inDndsCompilerFlags.cmake), removing duplicate#includedirectives in Euler headers, and replacing rawassert()calls inSolver/ODE.hpp.
CMAKE_CXX_STANDARD_REQUIREDBUILD_SHARED_LIBS corruption: restore value after fmt add_subdirectoryadd_compile_options / add_definitions (50+ calls) with per-target target_compile_options, target_compile_definitions, target_compile_features. Current global flags leak into third-party subdirectories (fmt, SuperLU, pybind11)cmake_minimum_required(VERSION 3.1) from subdirectory CMakeLists files (resets CMake policies, the root already requires 3.21)CMAKE_USE_RELATIVE_PATHSinclude(cmakeCommonUtils.cmake) per subdirectory; one include() in the root suffices since function definitions persist-std=c++17 flag; CMAKE_CXX_STANDARD 17 already handles it-Wall warning blockdnds_external_deps INTERFACE library target to replace raw DNDS_EXTERNAL_LIBS/DNDS_EXTERNAL_INCLUDES variable listscmakeCommonUtils.cmake: remove dead CMake version checksLLVM variable in add_fast_flags is kept: used for LLVM Clang on Windows)euler_library_*_shared)~~ (done)CONFIGURE_DEPENDS with file(GLOB) callsfind_library/find_path with find_package for external deps (ZLIB, HDF5, CGNS, Metis, ParMetis, Eigen, Boost, CGAL, nlohmann_json). Create imported targets with proper transitive propertiesDNDS_USE_PRECOMPILED_HEADER ON) now that infrastructure exists~~ (deferred — PCH targets exist but default remains OFF to avoid build issues with varying compiler/toolchain setups; explicitly enable with -DDNDS_USE_PRECOMPILED_HEADER=ON when desired)enable_testing() and register C++ unit tests with CTestDNDS_BUILD_TESTS cache optionadd_test() so ctest runs Python tests tooCMakePresets.json with Debug, Release, CUDA, and CI configurationsCMAKE_INSTALL_PREFIX; let users override itCMAKE_CURRENT_SOURCE_DIR/_internal); use a proper staging areafile(INSTALL ...) calls; use install() rules onlyfind_package(DNDSR) if neededapp/Euler/euler*.cpp) into a single executable with a runtime model-selection argument or a single main.cpp.in with configure_fileEulerEvaluator.hpp (lines 1440-1671, ~230 lines of manual method signature listings) into a less fragile mechanismcmake.args (split "-G Ninja" into ["-G", "Ninja"])build.tool-args = ["-j0"] to bounded ["-j8"] to prevent OOM"DNDSR" = "src/DNDSR" in [tool.scikit-build.wheel.packages][tool.pytest.ini_options] with testpaths, markers, timeoutcmake.define entries for essential build optionsEulerEvaluator.hpp lines 889-1045) into a separate BC evaluator classCompressRecPart, CompressInc, AddFixedIncrement, lines 1047-1393) into a limiter class.hpp header and into the .hxx implementation filesConfiguration structs (lines 114-610) into a separate EulerSolverConfig.hpp with its own JSON serializationif constexpr (model == NS_SA || model == NS_SA_3D) and if constexpr (model == NS_2EQ || model == NS_2EQ_3D) each appear 14 times across Euler .hpp/.hxx files. Extract model-specific behavior into traits or policy classes to eliminate duplicationElements.hpp (2,642 lines) into: ElementTypes.hpp (enums + topology tables), ElementGeometry.hpp (shape functions + Jacobians), ElementIO.hpp (CGNS/VTK conversion utilities)Quadrature.hpp (1,103 lines) into: QuadratureData.hpp (raw point/weight tables, 636 lines of static data), Quadrature.hpp (class and integration logic)UnstructuredMesh (Mesh.hpp:25-806) is a god struct: ~50 data members, ~60+ methods, and 9 .cpp implementation files spanning topology building, ghost communication, face interpolation, I/O, elevation, reordering, and output. UnstructuredMeshSerialRW (Mesh.hpp:821-1058) has 16 declared- but-unused adjacency fields (lines 862-877) and mixes reading, partitioning, and serial output in a single struct.
Mesh.hpp): Replaced 12 identical methods (168 lines) with 4 generic templates (IndexGlobal2Local<TPair>, IndexLocal2Global<TPair>, IndexLocal2Global_NoSon<TPair>, IndexGlobal2Local_NoSon<TPair>) plus 12 one-line named wrappers. Zero call-site changes required~~ (done)ConvertAdjEntries helper** (Mesh.hpp + Mesh.cpp): Added ConvertAdjEntries<TAdj, TFn>(adj, nRows, fn) template. Applied to 8 of 12 adjacency methods (Primary, PrimaryForBnd, C2CFace). N2CB methods preserved verbatim (they use #pragma omp parallel for). Facial and C2F methods preserved (inline ghost mapping lookups)~~ (done)PermuteRows helper** (Mesh.hpp + Mesh.cpp): Added PermuteRows<TPair, TFn>(pair, nRows, old2new) template that handles both CSR (Decompress/ResizeRow/Compress) and fixed-size arrays via if constexpr (TPair::IsCSR()). Replaced 6 permutation blocks (~70 lines) in ReorderLocalCells() with 6 one-line calls~~ (done)UnstructuredMeshSerialRW (lines 862-877): 16 adjacency arrays declared "not used for now" — preserved intentionally; may be used in future serial I/O pathsReadFromCGNSSerial(): extracted 3 anonymous-namespace free functions in Mesh_Serial_ReadFromCGNS.cpp: AssembleZoneNodes(), SeparateVolumeAndBoundaryElements(), BuildBnd2CellSerial()InterpolateFace(): extracted 5 anonymous-namespace free functions in Mesh.cpp: EnumerateFacesFromCells(), CollectFaces(), CompactFacesAndRemapCell2Face(), MatchBoundariesToFaces(), AssignGhostFacesToCells()ReorderLocalCells(): extracted ComputeCellPermutation() anonymous-namespace helper in Mesh.cppPrintSerialPartVTKDataArray(): extracted BuildVTKCellTopology() and WritePVTUMasterFile() anonymous-namespace helpers in Mesh_Plts.cppBuildNodeWallDist** from Mesh_Plts.cpp (an I/O file) to new Mesh_WallDist.cpp — it's a geometry computation depending on CGAL, not an output method (done)#include "Solver/Direct.hpp" in Mesh.hpp and Mesh_DeviceView.hpp with forward declarations of Direct::SerialSymLUStructure and Direct::DirectPrecControl. Full include moved to the 2 .cpp files that need it (Mesh.cpp, Mesh_Serial_Partition.cpp)~~ (done)auto mesh = this; indirection pattern in SetPeriodicGeometry(), AssertOnN2CB(), ReadSerialize(), and BuildNodeWallDist() — replaced with direct member accesszlibCompressedSize, zlibCompressData, and compressLevel from VTK output; removed unused fnameIn variable from PLT output__GetCoords overloads** (Mesh.hpp): kept as-is — the 4-overload structure (2 non-periodic + 2 periodic) is the right design for performance on hot paths; consolidation would add runtime branching inside inner loopsMeshTopology**: adjacency arrays, state flags, state transitions (the 5 MeshAdjState fields and their assertions)MeshIO**: serialization (WriteSerialize/ReadSerialize), VTK/PLT/CGNS output (currently in Mesh_Plts.cpp), CGNS/OpenFOAM reading (currently in Mesh_Serial_ReadFromCGNS.cpp)MeshElevation**: O1-to-O2 elevation, bisection, smooth solvers (currently in Mesh_Elevation.cpp + Mesh_Elevation_SmoothSolver.cpp). Factor shared setup (KD-tree, boundary gathering) out of the 4 smooth solver variants; remove V1Old if deprecatedMeshReordering**: local cell reordering, partition start trackingUnstructuredMesh becomes a thin facade holding a MeshTopology plus coordinate data, with component access methodsInterpolateTopology (Mesh.cpp:26-42), dead code after continue (Mesh_Serial_BuildCell2Cell.cpp:416-438), debug print blocksstd::cout/std::cerr calls (found in Mesh_Serial_ReadFromCGNS.cpp, Mesh.cpp) with DNDS::log()Mesh_Serial_BuildCell2Cell.cpp:386-404 uses #pragma omp critical for progress output inside a parallel loop. Use thread-local counters or atomic operations insteadThroughout the mesh code, if (isPeriodic) appears in every major method (25+ sites across Mesh.cpp and Mesh.hpp). Consider extracting periodic-specific behavior into a policy or strategy pattern so that non-periodic mesh paths remain clean.
UnstructuredMesh from struct (all ~30+ data members public) to class with private members and public accessor methods (can be done incrementally as part of UnstructuredMesh Phase 3 above)EulerEvaluator public surface: make internal buffers (lambdaFace*, uGradBuf*, fluxWallSum, symLU, etc.) private; expose only through accessors where neededEulerEvaluator.hpp and establish clear public API vs. internal state boundariesDNDS_check_throw for user-facing validation in Euler and CFV modules (currently 286 combined DNDS_assert calls but zero DNDS_check_throw; no runtime validation in release builds)assert() calls in Solver/ODE.hpp (lines 400, 429, 501, 643, 666, 1034) with DNDS_assertstd::cout calls in Euler with the project's log() function or a proper logging mechanism#include directives: DNDS/JsonUtil.hpp is included twice in EulerEvaluator.hpp, EulerSolver.hpp, and EulerEvaluatorSettings.hpp; Solver/Linear.hpp is included twice in EulerSolver.hpptest_FiniteVolume.cpp) from the CFV production library (line 27 of src/CFV/CMakeLists.txt)test/Geom/OversetCart/ (7-file library package) out of test/ into src/ since it is library code, not testssrc/Geom/GeomUtils.py (outdated duplicate of utils.py with bugs)src/check.py (stale integration test, superseded by test/)Doctest v2.4.11 is integrated under external/doctest/. Tests live in test/cpp/. Built with cmake -DDNDS_BUILD_TESTS=ON, run with ctest -R dnds_. MPI tests registered at np=1, np=2, np=4.
test_Array.cpp — all 5 layouts (StaticFixed, Fixed, StaticMax, Max, CSR), resize, compress/decompress, clone, copy, swap, edge cases (zero-size, single-element), JSON serialization round-trip, array signature, hashtest_MPI.cpp — MPIInfo, Allreduce (SUM/MAX, real/index), AllreduceOneReal/OneIndex, Scan, Allgather, Bcast, Barrier, Alltoall, BasicType_To_MPIIntType, CommStrategytest_ArrayTransformer.cpp — ParArray basics, pull-based ghost comm (StaticFixed, Fixed, CSR, std::array elements), persistent pull, BorrowGGIndexing, push communicationtest_ArrayDerived.cpp — ArrayAdjacency (basics, ghost comm, clone, fixed-size), ArrayEigenVector (basics, static/dynamic, ghost comm), ArrayEigenMatrix (static, dynamic, NonUniform rows, ghost comm), ArrayEigenMatrixBatch (basics, ghost comm), ArrayEigenUniMatrixBatch (static, dynamic)test_ArrayDOF.cpp — setConstant (scalar, matrix), operator+= (scalar, array, matrix), operator-=, operator*= (scalar, array element-wise, matrix), operator/=, addTo, norm2, norm2 (difference), dot, min, max, sum, componentWiseNorm1, operator= (copy), clone, scalar-array multiplytest_IndexMapping.cpp — GlobalOffsetsMapping (uniform, non-uniform, search), OffsetAscendIndexMapping (pull-based, search_indexAppend, empty ghost set)test_Serializer.cpp — SerializerJSON scalar round-trip, vector round-trip, uint8 (with/without codec), path operations, shared pointer deduplication. test/conftest.py with an MPI fixturetest/conftest.py)[tool.pytest.ini_options] to pyproject.toml: testpaths = ["test"], custom markers (mpi, cuda, slow), and a default timeoutsys.path.append hack in test/DNDS/test_basic.py (unnecessary with a proper editable install)test/Geom/test_basic_geom.py: remove the while True: pass infinite loop (line 85) that makes the test hangtest/CFV/test_basic_cfv.py: add assertions on reconstruction coefficient values, metric correctness, RHS conservationtest/CFV/test_basic_fv.py: add assertions on cell/face metric norms, gradient operator accuracytest/EulerP/test_basic_eulerP.py: add assertions on primitive variable conversion, eigenvalue positivity, flux conservationtest/EulerP/test_solver.py: add assertions on conservation property preservation, time integration convergencetest/DNDS/test_arraydof.py: convert to pytest-compatible structure, add CUDA skip markerapp/Geom/elements_Test.cpp to doctest)Solver/Linear.hpp (GMRES, PCG) and Solver/ODE.hpp (ImplicitEuler, SDIRK4, BDF2) to enable Python testingStatus: COMPLETE — The
python/DNDSR/tree is fully implemented. The following section documents what was done for reference. Remaining items (stub generation cleanup, test import fixes) are minor polish.
The current layout mixes C++ headers, pybind11 bindings, compiled .so files, Python __init__.py, and .pyi stubs all inside src/DNDS/, src/Geom/, etc. This causes:
cmake --install places .so files into the source tree (src/*/_internal/)__init__.py at src/__init__.py and src/DNDSR/__init__.py_pre_import() functions for CDLL preloading.pyi into package .pyi) producing duplicate from __future__ imports and stale artifactssys.path.append hacks to find the packageC++ sources (*.hpp, *.cpp, *_pybind.cpp) remain in src/ unchanged.
python/DNDSR/__init__.py (imports DNDS, Geom, CFV, EulerP)python/DNDSR/_loader.py (consolidated CDLL preload: one function preload_libs(module_name) that loads the correct shared libs based on the calling module, using a lib search path relative to the install prefix)python/DNDSR/DNDS/__init__.py (calls _loader, then from ._ext.dnds_pybind11 import *, factory functions, MPI init)python/DNDSR/Geom/__init__.py, CFV/__init__.py, EulerP/__init__.py (same pattern)Debug_Py.py, utils.py, EulerP_Solver.pypython/DNDSR/py.typed marker_ext/__init__.py in each submodule${CMAKE_CURRENT_SOURCE_DIR}/_internal to ${PROJECT_SOURCE_DIR}/python/DNDSR/<Module>/_extDNDSR/lib to ${PROJECT_SOURCE_DIR}/python/DNDSR/_lib (or keep in install prefix)run-pybind11-stubgen.sh to output to stubs/ instead of in-tree concatenation[tool.scikit-build.wheel.packages] to "DNDSR" = "python/DNDSR"DNDSR/DNDS = src/DNDS mappings.so into the wheel automatically since the cmake install targets land inside python/DNDSR/sys.path.append hacks from test filesfrom DNDSR import DNDS (works with pip install -e .)pip install -e . before running testsrun-pybind11-stubgen.sh to output clean per-file stubs into stubs/DNDSR/ (no concatenation, no append)python/DNDSR/ for PEP 561 compliance, or configure pyproject.toml to include stubs/ in the wheelplaceholder_submodule.pyi filessrc/__init__.py, src/DNDSR/__init__.pysrc/DNDS/__init__.py, src/Geom/__init__.py, etc.src/*/_internal/ directories (.so files, .pyi files)src/DNDS/__init__.pyi and other in-tree stubssrc/run-pybind11-stubgen.sh (updated) or move to scripts/| Mode | What happens |
|---|---|
| Pure C++ build | cmake --build . -t euler — only compiles C++ under src/, no Python artifacts |
| Editable install | pip install -e . — builds pybind11 targets, installs .so into python/DNDSR/*/_ext/, pip links python/DNDSR/ |
| Editable C++ rebuild | cmake --build build_py -t dnds_pybind11 ... && cmake --install build_py — .so lands in python/, Python picks it up immediately |
| Package build | pip install . — wheel contains DNDSR/ with .so files, pure Python, and stubs |