最小化每个面上所有至 k 阶导数的跳跃:
权重
局部系统
迭代求解——方案见下文。
三种内积选择
重构迭代方案(VariationalReconstruction.hpp:938-1031)
DoReconstructionIter — Jacobi / SOR 扫描(测试使用 Jacobi)。DoReconstructionIterDiff — Jacobian-向量乘积(GMRES 内层)。DoReconstructionIterSOR — SOR,可选反向扫描。DoReconstruction2nd、DoReconstruction2ndGrad。Construct* 调用template <int dim = 2>
class VariationalReconstruction : public FiniteVolume {
public:
void ConstructMetrics(); // 通过 FiniteVolume
void ConstructBaseAndWeight(tFGetBoundaryWeight id2faceDircWeight = …); // 基 + 缓存的导数值
void ConstructRecCoeff(); // A, B, A^{-1} B, 辅助矩阵
// …
};
ConstructMetrics 构建的内容ConstructBaseAndWeight 构建的内容cellBaseMoment — 每个单元的基矩。faceAlignedScales、faceMajorCoordScale。cellDiffBaseCache、faceDiffBaseCache — 所有求积点上、模板中每个邻居的缓存导数值。bndVRCaches — 用于 BC 加权 VR 的边界面缓存。ConstructRecCoeff 构建的内容matrixAB、vectorB — 每个邻居的右端项块。matrixAAInvB、vectorAInvB — 预计算的 matrixSecondary、matrixAHalf_GG — 辅助重构系统。matrixA、matrixACholeskyL、volIntCholeskyL — 完整系统 + 稠密局部求解的 Cholesky 分解。所有数组均为 ArrayEigenMatrix* 或 ArrayEigenUniMatrixBatch*——即在支持 MPI 的分布式内存块上的 Eigen 映射。
FiniteVolume — 度量缓存class FiniteVolume : public DeviceTransferable<FiniteVolume> {
real sumVolume, minVolume{veryLargeReal}, maxVolume, volGlobal;
tScalarPair volumeLocal; // 每个单元的 volume
tScalarPair faceArea; // 每个面的 area
tRecAtrPair cellAtr, faceAtr; // (NDOF, NDIFF, Order, intOrder)
tCoeffPair cellIntJacobiDet, faceIntJacobiDet;
t3VecsPair faceUnitNorm; // 每个面求积点处的 normal
t3VecPair faceMeanNorm;
t3VecPair cellBary, faceCent, cellCent;
t3VecsPair cellIntPPhysics, faceIntPPhysics;
t3VecPair cellAlignedHBox, cellMajorHBox;
t3MatPair cellMajorCoord, cellInertia;
tScalarPair cellSmoothScale;
int axisSymmetric = 0; // 楔形轴对称
std::set<index> axisFaces;
// CRTP: to_device(), to_host(), device(), deviceView<B>()
};
支持 CUDA 传输。 FiniteVolume(以及 VariationalReconstruction)继承自 DeviceTransferable<FiniteVolume>。调用一次 fv.to_device() 即可将整个度量缓存迁移到 GPU 作为设备端视图。
enum RiemannSolverType {
UnknownRS = 0,
Roe = 1, HLLC = 2, HLLEP = 3, HLLEP_V1 = 21,
Roe_M1 = 11, Roe_M2 = 12, Roe_M3 = 13, Roe_M4 = 14, Roe_M5 = 15,
Roe_M6 = 16, Roe_M7 = 17, Roe_M8 = 18, Roe_M9 = 19,
};
| 变体 | 熵修正 / 特征值策略 |
|---|---|
Roe |
标准 Roe + Harten–Yee |
Roe_M1 |
cLLF(中心 + 局部 Lax–Friedrichs) |
Roe_M2 |
Lax–Friedrichs |
Roe_M3 |
LD Roe(低耗散) |
Roe_M4 |
ID Roe(中等耗散) |
Roe_M5 |
LD cLLF |
Roe_M6 |
仅 H-修正 |
Roe_M7 |
仅 Harten–Yee,无 H-修正 |
Roe_M8 |
H-修正 + Harten–Yee |
Roe_M9 |
保留(eigScheme 9,当前 assert false) |
HLLC |
Harten–Lax–van Leer–Contact |
HLLEP |
HLLE,带压力修正 |
HLLEP_V1 |
HLLEP 变体 1 |
// 共享辅助函数
template <int dim>
RoePreamble<dim> ComputeRoePreamble(ULm, URm, gamma, dumpInfo);
RoePreamble — 共享中间层template <int dim>
struct RoePreamble {
TVec veloLm, veloRm; // 原始速度
real rhoLm, rhoRm, pLm, pRm, HLm, HRm; // 原始状态
real veloLm0, veloRm0; // 法向速度分量
TVec veloRoe; // Roe 平均速度
real sqrtRhoLm, sqrtRhoRm;
real vsqrRoe, HRoe, asqrRoe, rhoRoe, aRoe;
};
template <int dim, int eigScheme>
void RoeFlux(UL, UR, ULm, URm, n, vgN,
/*out*/ flux,
/*out*/ dLambda,
fixScale, gamma, dumpInfo);
template <int dim, int type>
void HLLEPFlux_IdealGas(UL, UR, ULm, URm, n, vgN,
flux, …, gamma, dumpInfo);
template <int dim>
void HLLCFlux(UL, UR, ULm, URm, n, vgN, …);
所有 13 种变体共享 ComputeRoePreamble——Roe 平均、eigScheme 模板参数选择耗散/熵修正策略。
dim, eigScheme) 一次模板实例化,保持代码体积可控。NSFluxInvis<dim>、NSFluxVis<dim>(U, gradU, T, mu, n, flux, adiabaticWall, useQCR)。FWBAP_L2_Multiway — 通用 Eigen 数组。FWBAP_L2_Multiway_Polynomial2D — 2D 多项式加权范数。FWBAP_L2_Multiway_PolynomialOrth — 正交变体。FMEMM_Multiway_Polynomial2D — 修正极值-单调混合器。幂参数: p = 4;verySmallReal_pDiP = std::pow(verySmallReal, 1.0/p) 稳定化零点附近的值。
FWBAP_L2_BiwayFWBAP_L2_Cut_Biway — 符号截断FMINMOD_BiwayFVanLeer_BiwayFWBAP_L2_Biway_PolynomialNorm<dim, nVarsFixed>FMEMM_Biway_PolynomialNorm<dim, nVarsFixed>FWBAP_L2_Biway_PolynomialOrthConfiguration
"limiterProcedure": 0 // WBAP (V2)
"limiterProcedure": 1 // CWBAP (V3) ← 推荐
"usePPRecLimiter": true
正性保持——
LimiterUGrad(Euler 侧)钳制梯度;EvaluateURecBeta强制重构值的单元均值正性;EvaluateCellRHSAlpha强制 CFL 一致的单单元右端项缩放。
template <int nVarsFixed>
void DoLimiterWBAP_C(tUDof<nVarsFixed> &u,
tURec<nVarsFixed> &uRec,
tURec<nVarsFixed> &uRecNew,
tURec<nVarsFixed> &uRecBuf,
tSmoothIndicator &si,
bool ifAll,
tFM FM, // 守恒 → 特征变换
tFMI FMI, // 特征 → 守恒变换
bool putIntoNew = false);
template <int nVarsFixed>
void DoLimiterWBAP_3(...); // 三模态变体
si。FM)。FMI)。uRecNew(迭代方案的双缓冲)。DoCalculateSmoothIndicator<nVarsFixed, nVarsSee=2>(si, uRec, u, varsSee) — 变量子集上的经典指示器。DoCalculateSmoothIndicatorV1<nVarsFixed>(si, uRec, u, varsSee, FPost) — V1,支持用户提供的后处理。所有积分器继承自:
template <class TDATA, class TDTAU>
class ImplicitDualTimeStep {
using Frhs = std::function<void(TDATA&, TDATA&, TDTAU&, int, real, int)>;
using Fdt = std::function<void(TDATA&, TDTAU&, real, int)>;
using Fsolve = std::function<void(TDATA&, TDATA&, TDATA&, TDTAU&, real, real, TDATA&, int, real, int)>;
using Fstop = std::function<bool(int, TDATA&, int)>;
using Fincrement = std::function<void(TDATA&, TDATA&, real, int)>;
virtual void Step(TDATA &x, TDATA &xinc, const Frhs&, const Fdt&, const Fsolve&,
int maxIter, const Fstop&, const Fincrement&, real dt) = 0;
};
odeCode |
类 | 格式 |
|---|---|---|
103 |
ImplicitEulerDualTimeStep |
后向 Euler |
0 |
ImplicitBDFDualTimeStep |
BDF2 / BDF-k |
| — | ImplicitVBDFDualTimeStep |
变步长 BDF-k |
1 |
ImplicitSDIRK4DualTimeStep (schemeCode 0…4) |
SDIRK-4 · ESDIRK2/3 · 梯形 |
101 |
(1 的别名) |
(向后兼容 odeCode) |
401 |
ImplicitHermite3SimpleJacobianDualStep |
HM3 + p-Multigrid |
2 |
ExplicitSSPRK3TimeStepAsImplicitDualTimeStep |
SSP-RK3 |
SetExtraParams(json) 暴露特定格式的参数(如 nMG、incFScale)。
HM3(Hermite-3)是一种三阶 A-稳定隐式格式,有三种模式:
在 ImplicitHermite3SimpleJacobianDualStep::Step() 内部,非零 nMG 触发 p-Multigrid 光滑循环:
// 内层求解中的伪代码(第1250-1251行)
fdt (xMG, dTau, 1.0, /*upos=*/2); // 低阶伪时间步
frhs(rhsbuf[1], xMG, dTau, iter, 1.0, /*upos=*/2);
upos=2 参数告诉求值器在较低多项式阶上进行求值(层级过渡)。VR 提供 DownCastURecOrder(curOrder, iCell, uRec, downCastMethod) 在不同阶之间投影重构系数。
tpMG — 外部双时间循环中多重网格的开关。incFScale — 较低 MG 层级上的增量 Flux 缩放;已集成至熵修正路径(RELEASE_NOTES.md)。LimiterUGrad 中的正性保持限制器——防止低阶粗网格修正产生负密度/压力。SDIRK4 编码schemeCode = 0 — Nørsett 3 级 SDIRK-4schemeCode = 1 — 6 级 ARK 族 SDIRKschemeCode = 2 — Kennedy–Carpenter ESDIRK3schemeCode = 3 — 梯形schemeCode = 4 — ESDIRK2, γ = 1 − √2/2template <class TDATA>
class GMRES_LeftPreconditioned {
public:
GMRES_LeftPreconditioned(index dofSize);
void setSpace(int kSpace);
bool solve(const TDATA &rhs, TDATA &x,
FMatVec Ax, FPCApply PC,
int maxIter, real tol);
};
template <class TDATA, class TScalar>
class PCG_PreconditionedRes { … };
无矩阵:调用方提供 Ax 和 PC 函子。
由 EulerEvaluator 提供:
void LUSGSMatrixInit(JDiag, JSource, dTau, dt, alphaDiag, u, uRec, jacCode, t);
void LUSGSMatrixVec(alphaDiag, t, u, uInc, JDiag, AuInc);
void LUSGSMatrixToJacobianLU(alphaDiag, t, u, JDiag, jacLU);
void UpdateSGS(alphaDiag, t, rhs, u, uInc, uIncNew, JDiag,
forward, gsUpdate, sumInc, uIncIsZero = false);
void LUSGSMatrixSolveJacobianLU(alphaDiag, t, rhs, u, uInc, uIncNew,
bBuf, JDiag, jacLU,
uIncIsZero, sumInc);
void UpdateSGSWithRec(alphaDiag, t, rhs, u, uRec, uInc, uRecInc,
JDiag, forward, sumInc);
选择器
"gmresCode": 0 // 仅 LUSGS (廉价、鲁棒)
"gmresCode": 1 // GMRES (无矩阵 Krylov)
"gmresCode": 2 // LUSGS + GMRES (LUSGS 作为 GMRES 预条件子)
小块的直接路径:src/Solver/Direct.hpp(LU / LDLT)。可通过 cfd_externals 子模块启用可选的 SuperLU_dist。
Configuration是集体且昂贵的。通信是本地且廉价的。
一次性构建阶段 — 集体操作
trans.setFatherSon(father, son);
trans.createFatherGlobalMapping();
// collective: MPI_Allgather over local sizes
trans.createGhostMapping(pullGlobal);
// collective: sorts + dedups pullGlobal IN PLACE
// — saves a copy if you need the original
trans.createMPITypes();
// local: MPI_Type_create_hindexed describes
// the scattered rows to send/recv
// — ALSO resizes the son array to hold them
trans.initPersistentPull();
// local: MPI_Recv_init + MPI_Send_init
派生的MPI数据类型随着transformer持久存在——销毁前的拆卸成本为零。
热循环阶段 — 仅本地操作
for (int step = 0; step < N; ++step) {
trans.startPersistentPull(); // MPI_Startall
computeFluxes(/* reads ghosts */);
trans.waitPersistentPull(); // MPI_Waitall
}
trans.clearPersistentPull();
v0.2.0 错误修复:
globalSize() 曾经是集体操作,当某些进程走捷径时可能死锁。现在在 createFatherGlobalMapping 时缓存——完全本地化。
MPI::CommStrategy::Instance().GetArrayStrategy() 选择:
HIndexed — 默认MPI_Type_create_hindexed(count, blocklengths, displacements,
base_type, &new_type);
InSituPackinSituBuffer[rank].clear();
for (index i : pushingIndexLocal[rank])
inSituBuffer[rank].append(row(i));
MPI_Isend(inSituBuffer[rank].data(), ...);
HIndexed,驱动更倾向于平坦缓冲区。两种策略共用同一个公共API。选择是一个调优开关——不需要应用层更改。
BorrowGGIndexing — 避免重复集体Configuration// Primary array: does the full collective setup
ArrayTransformer<real, 5> cellUTrans;
cellUTrans.setFatherSon(uFather, uSon);
cellUTrans.createFatherGlobalMapping();
cellUTrans.createGhostMapping(pullGlobal);
cellUTrans.createMPITypes();
// Secondary array: reuses the *global + ghost* mapping.
// Only the MPI datatypes (which depend on the row size) are rebuilt.
ArrayTransformer<real, DynamicSize> recTrans;
recTrans.setFatherSon(uRecFather, uRecSon);
recTrans.BorrowGGIndexing(cellUTrans); // <-- key line
recTrans.createMPITypes();
recTrans.initPersistentPull();
效果: 在Euler流水线中,每个DOF数组(u、uPrev、uInc、uRec、uRecInc、uRecB……)共享一个从 cell2cell 邻接关系建立的Ghost映射。只有MPI数据类型不同,取决于各数组的行大小。
-DDNDS_DIST_MT_USE_OMP=ON 在整个调用链中激活线程化路径:
EigenVecMin、EigenVecSum 按线程折叠,然后合并。toLocalOMP / toGlobalOMP / bootstrapToLocalOMP 在邻接数组的行上并行化。FiniteVolume 中的许多 ConstructX() 方法通过 #pragma omp parallel for 在单元/面上循环。DoReconstructionIter 有OpenMP变体。CI默认值 OMP_NUM_THREADS=2(可通过 DNDS_TEST_OMP_THREADS 在Configuration时覆盖)。每个测试的MPI进程数可通过 DNDS_TEST_NP_LIST Configuration。
典型生产部署:每个NUMA节点1个MPI进程 × 内部OpenMP线程。 MPI处理跨socket/跨节点;OpenMP处理节点内部。
DeviceTransferable CRTPtemplate <class TDerived>
class DeviceTransferable {
public:
// Derived implements: device_array_list() returning a tuple of host-device arrays
void to_device(DeviceBackend B = DeviceBackend::CUDA);
void to_host();
DeviceBackend device() const;
template <DeviceBackend B> auto deviceView();
};
// Example user
class FiniteVolume : public DeviceTransferable<FiniteVolume> {
auto device_array_list() {
return std::tie(volumeLocal, faceArea, faceUnitNorm, cellBary,
cellInertia, cellIntJacobiDet, /* ... */);
}
};
fv.to_device();
auto dv = fv.deviceView<CUDA>();
launchKernel<<<blocks, threads>>>(dv);
fv.to_host();
UnstructuredMesh(连通性)FiniteVolume(度量)VariationalReconstruction(通过基类)VRDefines DOF数组构建:cmake --preset cuda → -DDNDS_USE_CUDA=ON · Thrust修复通过 CMAKE_CUDA_ARCHITECTURE=native。
问题: 标准的 Euler 求值器使用带编译时 nVars 的Eigen;Eigen矩阵运算无法清晰地降级为设备可调用的标量循环。在微小矩阵上启动CUDA内核的开销比数学运算本身还大。
解决方案: 在 src/EulerP/ 中实现的并行路径求值器:
nVars 进行标量循环。EvaluatorDeviceView<B>,其中 B ∈ {Host, CUDA}——相同接口,两个实现分别在独立的翻译单元中编译(.cpp 和 .cu)。*_Arg 结构体(如 RecGradient_Arg、Flux2nd_Arg),使启动代码无需知道参数顺序。template <DeviceBackend B>
struct EvaluatorDeviceView {
FiniteVolume::t_deviceView<B> fv;
BCHandlerDeviceView<B> bc;
PhysicsDeviceView<B> physics;
};
Python驱动:python/DNDSR/EulerP/EulerP_Solver.py 从Python编排完整的EulerP流水线,通过运行时标志选择CUDA。
class Evaluator {
ssp<CFV::FiniteVolume> fv;
ssp<BCHandler> bcHandler;
ssp<Physics> physics;
// face buffers (dense packed from ghost father+son)
tUFaceBuffer u_face_bufferL, u_face_bufferR;
tUScalarFaceBuffer uScalar_face_bufferL, uScalar_face_bufferR;
public:
// Setup
void BuildFaceBufferDof(TUDof &u);
void BuildFaceBufferDofScalar(TUScalar &u);
void PrepareFaceBuffer(int nVarsScalar);
// Pipeline kernels (each host-or-device via Evaluator_impl<B>)
void RecGradient (RecGradient_Arg &arg); // Green-Gauss + Barth-Jespersen
void Cons2PrimMu (Cons2PrimMu_Arg &arg);
void Cons2Prim (Cons2Prim_Arg &arg);
void RecFace2nd (RecFace2nd_Arg &arg); // 2nd-order face reconstruction
void Flux2nd (Flux2nd_Arg &arg); // inviscid + viscous face flux
};
Evaluator_impl<B>)。EvaluateRHS。src/Geom/Mesh/BenchmarkFiniteVolume.cu 在设备上使用不同的块大小对度量数组进行测试。host_device_vector<T> — 可在设备上镜像自身的向量;广泛应用于 FiniteVolume / UnstructuredMesh。to_device / to_host)——无隐藏同步。CMAKE_CUDA_ARCHITECTURE=native 修复了Thrust内部机制中的一类编译错误。to_device: 面缓冲区创建路径中的一个错误曾不必要地将主机缓冲区复制到设备;在v0.2.0中修复。py::classh 持有者: 确保CUDA指针在跨Python GC边界存活时PythonEuler 求值器扩展到CUDA(不仅仅是 EulerP)。MPI_Type_create_hindexed 在固定设备内存上实现GPU可知MPI。| 层 | 职责 |
|---|---|
SerializerBase |
抽象标量 / 向量 / 字节数组接口 |
SerializerH5 |
MPI 并行 HDF5(Collective I/O) |
SerializerJSON |
每进程 JSON(IsPerRank() == true),无 MPI 协调 |
Array |
每数组元数据、结构标记、平铺数据缓冲区 |
ParArray |
全局偏移、EvenSplit、CSR 全局行起始 |
ArrayPair |
父子捆绑 · ReadSerializeRedistributed |
ArrayRedistributor |
通过 ArrayTransformer 的 rendezvous 再分配 |
关键特性。 SerializerH5 中的每个方法都是 MPI-Collective 的 — 每个进程必须依相同顺序调用它们,即使该进程的 size == 0。未参与会导致挂起,而非崩溃。
SerializerBase — 公共接口// File lifecycle
virtual void OpenFile(const std::string &fName, bool read) = 0;
virtual void CloseFile() = 0;
// Path navigation (think HDF5 group structure)
virtual void CreatePath(const std::string &p) = 0;
virtual void GoToPath(const std::string &p) = 0;
virtual std::string GetCurrentPath() = 0;
virtual std::set<std::string> ListCurrentPath() = 0;
virtual bool IsPerRank() = 0; // true for JSON
virtual int GetMPIRank() = 0; int GetMPISize() = 0;
virtual const MPIInfo &getMPI() = 0;
// Scalars (per-rank)
virtual void WriteInt(const std::string &name, int64_t v) = 0;
virtual void WriteIndex/WriteReal/WriteString(...) = 0;
virtual void ReadInt /ReadIndex / ReadReal / ReadString(...) = 0;
// Vectors (COLLECTIVE under H5)
virtual void WriteIndexVector(const std::string &name, const std::vector<index> &v,
ArrayGlobalOffset offset) = 0;
virtual void ReadIndexVector (const std::string &name, std::vector<index> &v,
ArrayGlobalOffset &offset) = 0; // offset is in/out
// ... Rowsize, Real, SharedIndex, SharedRowsize
virtual void WriteUint8Array(const std::string &name, const uint8_t *data,
index size, ArrayGlobalOffset offset) = 0;
virtual void ReadUint8Array (const std::string &name, uint8_t *data,
index &size, ArrayGlobalOffset &offset) = 0;
ArrayGlobalOffset — 五种偏移模式static const index Offset_Parts = -1;
static const index Offset_One = -2;
static const index Offset_EvenSplit = -3;
static const index Offset_Unknown = UnInitIndex;
class ArrayGlobalOffset {
index _size{0};
index _offset{0};
public:
ArrayGlobalOffset(index sz, index ofs);
index size() const;
index offset() const;
ArrayGlobalOffset operator*(index R) const; // scales size (and offset if real)
ArrayGlobalOffset operator/(index R) const;
void CheckMultipleOf(index R) const;
bool operator==(const ArrayGlobalOffset &other) const;
bool isDist() const; // _offset >= 0
};
extern ArrayGlobalOffset ArrayGlobalOffset_Unknown, _One, _Parts, _EvenSplit;
| 哨兵 | 含义 |
|---|---|
Unknown |
从关联的 rank_offsets 数据集自动检测 |
Parts |
通过对本地大小的 MPI_Scan 计算偏移 |
One |
进程 0 写入 / 读取整个数据集 |
EvenSplit |
读:每个进程获取 ~nGlobal / nRanks 行 |
isDist() |
显式 {localSize, globalStart} |
当 nGlobal < nRanks(5 条记录分布在 8 个进程上)时,EvenSplitRange 会为某些进程分配 0 行。Collective的 HDF5 调用仍然要求每个进程都参与 — 而对空向量调用 std::vector<>::data() 可能返回 nullptr。
std::vector<index> v(size); // size may be 0
ReadDataVector<index>(name, v.data(), ...); // may pass nullptr → hang
调用侧的辅助函数如 __ReadSerializerData 和 ReadUint8Array 在 buf == nullptr 时会跳过 H5Dread,导致Collective操作挂起。
SerializerBase.cpp 中的每个调用者当 size == 0 时传递一个栈分配的虚拟指针:
index dummy;
ReadDataVector<index>(name,
size == 0 ? &dummy : v.data(),
...);
ReadUint8Array 暴露了两阶段模式:
data = nullptr,返回大小。所有Collective操作在空进程上以 0 计数的 hyperslab 继续 — 无需应用级分支。
效果: EulerSolver::ReadRestart 只需一次调用。用户在登录节点用 4 个进程写入,在计算分区用 1024 个进程重启,同一份 JSON Configuration即可运行。localRows == 0 的进程用空缓冲区参与每次Collective操作。
DNDS_DECLARE_CONFIGstruct ImplicitCFLControl {
real CFL = 10.0;
int nForceLocalStartStep = INT_MAX;
bool useLocalDt = true;
real RANSRelax = 1.0;
DNDS_DECLARE_CONFIG(ImplicitCFLControl) {
DNDS_FIELD(CFL, "CFL for implicit local dt");
DNDS_FIELD(nForceLocalStartStep, "Step to force local dt",
DNDS::Config::range(0));
DNDS_FIELD(useLocalDt, "Use local (vs uniform) dTau");
DNDS_FIELD(RANSRelax, "RANS under-relaxation factor",
DNDS::Config::range(0.0, 1.0));
config.check([](const T &s) -> DNDS::CheckResult {
if (s.RANSRelax <= 0) return {false, "RANSRelax must be positive"};
return {true, ""};
});
}
};
宏提供的内容。 无基类、无虚成员、无逐实例数据 — 结构体保持 POD 形态,对 CUDA 安全。底层生成静态 _dnds_do_register() 方法,将 FieldMeta 记录填充到 ConfigRegistry<T> 单例中。
// Simple scalars & bounded scalars
DNDS_FIELD(CFL, "CFL number");
DNDS_FIELD(nInternalIt, "Inner iterations", DNDS::Config::range(0));
DNDS_FIELD(relax, "Relaxation factor", DNDS::Config::range(0.0, 1.0));
// Enum with value names (appears in schema as enum constraint)
DNDS_FIELD(rsType, "Riemann solver type",
DNDS::Config::enum_values({"Roe","HLLC","HLLEP","HLLEP_V1",
"Roe_M1","Roe_M2","Roe_M3","Roe_M4",
"Roe_M5","Roe_M6","Roe_M7","Roe_M8","Roe_M9"}));
// Documentation kwargs — emitted as "x-..." extensions in schema
DNDS_FIELD(CFL, "CFL number", DNDS::Config::info("units", "nondim"),
DNDS::Config::info("ref", "Jameson 1985"));
// Nested sub-section
config.field_section(&T::frameRotation, "frameConstRotation", "Rotating frame");
// Arrays / maps of sub-objects
config.field_array_of<BoxInit> (&T::boxInits, "boxInitializers", "Box initializers");
config.field_map_of<CoarseCtrl> (&T::coarseList, "coarseGridList", "Per-level controls");
// Opaque JSON (for scheme-specific extras)
config.field_json (&T::extra, "odeSettingsExtra", "Opaque ODE scheme settings");
// Renaming / aliases (backward compatibility)
config.field_alias (&T::rsType, "riemannSolverType", "Riemann solver type");
// Emit the schema (run-time or ahead-of-time)
nlohmann::ordered_json schema = ConfigRegistry<EulerConfig>::Instance().emitSchema("Euler solver config");
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"description": "Euler solver config",
"properties": {
"CFL": { "type": "number", "default": 10.0, "description": "..." },
"rsType": { "type": "string", "default": "Roe",
"enum": ["Roe","HLLC",...,"Roe_M9"] }
}
}
./build/app/euler.exe --emit-schema > euler_schema.json
# 每个求解器输出约 107 KB 的模式
VS Code 及任何支持 JSON Schema 的编辑器可提供自动补全和内联验证。预计算的模式文件位于 cases/euler_schema.json、eulerSA3D_schema.json 等。
auto ® = ConfigRegistry<EulerConfig>::Instance();
reg.readFromJson(j, cfg); // 反序列化 + 范围检查
reg.validate(cfg); // 跨字段
reg.validateWithContext(cfg, ctx); // 使用 nVars、dim、modelCode
reg.validateKeys(userJson); // 对未知键抛出异常
validateKeys 是自动的 — 无需手动维护允许字段列表。
from DNDSR import DNDS
↓
python/DNDSR/__init__.py
↓
python/DNDSR/DNDS/__init__.py
├── _loader.preload("dnds") # ctypes.CDLL · RTLD_GLOBAL
├── from ._ext.dnds_pybind11 import * # pybind11 扩展
└── _init_mpi() # 导入时执行 MPI_Init_thread
_loader.py 在 pybind11 扩展打开之前以 RTLD_GLOBAL 加载外部依赖。如果之后以默认的 RTLD_LOCAL 加载,扩展将找不到其依赖的符号。
DNDSR.DNDS — 数组、MPI、serializerDNDSR.Geom — 网格读取与操作DNDSR.CFV — 有限体积 / VR / Fourier 分析DNDSR.EulerP — GPU 友好的 Euler 求值器顶层 __init__.py 导入全部四个模块,使得单个 from DNDSR import * 即可工作。
from DNDSR import DNDS
from DNDSR.Geom.utils import read_mesh, prepare_mesh, build_bnd_mesh
# 1. MPI bootstrap (implicit MPI_Init_thread already ran at import)
mpi = DNDS.MPIInfo(); mpi.setWorld()
# 2. Read a CGNS mesh with elevation and bisection
result = read_mesh(
"data/mesh/UniformSquare_10.cgns",
mpi = mpi,
dim = 2,
elevation = "O2", # Quad4 → Quad9
bisect = 1, # one round of h-refinement
)
# 3. Finish the mesh (build ghosts, interpolate faces, reorder cells)
prepare_mesh(result.mesh, result.reader)
# 4. Extract surface mesh and dump VTK
bnd = build_bnd_mesh(result.mesh)
result.mesh.BuildVTKConnectivity()
PEP 561 兼容。 包中附带 py.typed 标记;.pyi 存根在 cmake --install 期间由 pybind11-stubgen 自动生成。Pyright、mypy 和 Pylance 可看到完整的 C++ 类型签名。
from DNDSR.CFV import ModelEvaluator # pure-Python wrapper over pybind11 class
me = ModelEvaluator(mesh, fv, vr)
me.set_order(3)
# Fourier analysis: plug in a plane wave, read back the complex amplification
kx_range = np.linspace(-pi, pi, 200)
for kx in kx_range:
lam = me.fourier_amplification_factor(kx)
print(kx, lam.real, lam.imag)
这对研究框架的意义。 VR 的色散/耗散特性取决于阶数、限制器和内积选择。用 Python 框架在离散 Fourier 谱上扫描这些参数,意味着参数研究(限制器组合、内积选择、导数权重)可在数小时内完成,而非数周。
其他 Python 暴露的功能:
ArrayPair、ArrayEigenMatrix/Vector/BatchBuildUDof / BuildURec / BuildUGrad(类型化构造函数)to_device / to_hostMeshAdjState 枚举和 AdjPairTracked::idx 查询(仅查询,不从 Python 变更 — 有意为之)// app/Euler/euler.cpp — the entire file
#include "EulerSolver.hpp"
int main(int argc, char *argv[]) {
return DNDS::Euler::RunSingleBlockConsoleApp<
DNDS::Euler::NS>(argc, argv);
}
EulerModel)enum EulerModel {
NS, // 2D Navier-Stokes
NS_3D,
NS_SA, // 2D Spalart-Allmaras
NS_SA_3D,
NS_2D, // alias for NS
NS_2EQ, // k-omega two-equation
NS_2EQ_3D,
NS_EX, // reactive / multi-species
NS_EX_3D,
};
通过 EulerModel 模板派发,每个求解器生成一个可执行文件 — 共享源码,分离目标文件。
enum RANSModel {
RANS_None,
RANS_SA, // Spalart-Allmaras (IDDES capable)
RANS_KOWilcox, // Wilcox k-omega
RANS_KOSST, // Menter k-omega SST
RANS_RKE, // Realizable k-epsilon
};
每种模型都有对应的 RANSModelTraits<> 特化,包含其壁面边界条件、源项和谱半径。
EulerSolver — 顶层调度器Euler 模块扩展了 CFV 的通用 tUDof/tURec 别名,添加了
求解器专用的数组类型,提供更高级的算子(初始化、边界锚定、
保正限制器):
ArrayDOFV<N> 继承自 CFV::tUDof<N> (= ArrayDof<N,1>)。ArrayRECV<N> 继承自 CFV::tURec<N> (= ArrayDof<DynamicSize,N>)。template <EulerModel model>
class EulerSolver {
typedef EulerEvaluator<model> TEval;
static const int nVarsFixed = TEval::nVarsFixed;
MPIInfo mpi;
ssp<Geom::UnstructuredMesh> mesh, meshBnd;
TpVFV vfv; // VariationalReconstruction
ssp<Geom::UnstructuredMeshSerialRW> reader, readerBnd;
ssp<EulerEvaluator<model>> pEval;
ssp<BoundaryHandler<model>> pBCHandler;
// Solver state (DOF arrays)
ArrayDOFV<nVarsFixed> u, uIncBufODE, wAveraged, uAveraged;
ObjectPool<ArrayDOFV<nVarsFixed>> uPool; // rent/return buffers
ArrayRECV<nVarsFixed> uRec, uRecLimited, uRecNew, uRecNew1,
uRecOld, uRec1, uRecInc, uRecInc1,
uRecB, uRecB1;
JacobianDiagBlock<nVarsFixed> JD, JD1, JDTmp, JSource, JSource1, JSourceTmp;
ssp<JacobianLocalLU<nVarsFixed>> JLocalLU;
ArrayDOFV<1> alphaPP, alphaPP1, betaPP, betaPP1,
alphaPP_tmp, dTauTmp;
// Config + output
Configuration config; // nested sub-configs
nlohmann::ordered_json gSetting;
std::string output_stamp;
// ... outDist* / outSerial* / outDist2SerialTrans* for VTK
};
Configuration — 调节运行的一切参数每个小节都使用 DNDS_DECLARE_CONFIG,因此完整的 JSON Schema 会自动生成。
dtImplicit、nTimeStep、steadyQuit、useRestart、useImplicitPP、odeCode、odeSetting1..4、odeSettingsExtra(不透明 JSON)、dtCFLLimitScale、…useExplicit、nInternalRecStep、recLinearScheme(0 = SOR, 1 = GMRES)、nGmresSpace/Iter、fpcgReset*、recThreshold。outputIntervalStep、outputFormat(VTK、PLT、VTKHDF、series)、并行与串行写入。limiterProcedure、usePPRecLimiter、WBAP 阶数。gmresCode、Krylov 子空间、迭代次数。EulerEvaluatorSettings<model>。VRSettings。
--emit-schema将整个Configuration树导出为单个 JSON Schema 文档 —euler_schema.json/eulerSA3D_schema.json/ 等,每个约 107 KB。
EulerEvaluator<model> — 空间算子void EvaluateRHS(ArrayDOFV<nVarsFixed> &rhs,
JacobianDiagBlock<nVarsFixed> &JSource,
ArrayDOFV<nVarsFixed> &u,
ArrayRECV<nVarsFixed> &uRecUnlim,
ArrayRECV<nVarsFixed> &uRec,
ArrayDOFV<1> &uRecBeta,
ArrayDOFV<1> &cellRHSAlpha,
bool onlyOnHalfAlpha,
real t,
uint64_t flags = RHS_No_Flags);
RHS_Ignore_ViscosityRHS_Dont_Update_IntegrationRHS_Dont_Record_Bud_FluxRHS_Direct_2nd_Rec — 绕过 VR,使用基于 GG 的二阶RHS_Direct_2nd_Rec_1st_Conv — 二阶重构但一阶对流RHS_Direct_2nd_Rec_use_limiterRHS_Direct_2nd_Rec_already_have_uGradBufNoLimRHS_Recover_IncFScale标志位按位组合 — 覆盖 p-MG 和 PP 子步骤使用的回退/诊断模式。
EvaluateDt(...) — 基于 CFL 的局部 dt,基于谱半径。EvaluateURecBeta — 每个单元的 PP 限制器 β。EvaluateCellRHSAlpha — 每个单元的 RHS 缩放,用于 PP。LimiterUGrad — 梯度限制器,可选激波检测。LUSGSMatrixInit/Vec/ToJacobianLU 和 UpdateSGS(WithRec)。GetWallDist_AABB、GetWallDist_BatchedAABB、GetWallDist_Poisson。muEff(U, T),使用 Sutherland 或常数模型。每种 BC 都是一个实现通用接口的类;BoundaryHandler<model> 在运行时将面区域 ID 路由到 BC 实例。
| BC | 用途 |
|---|---|
BCWall |
无滑移壁面(绝热) |
BCWallIsothermal |
无滑移壁面,固定温度 |
BCWallInvis |
滑移 / 对称 |
BCSym |
显式对称面 |
BCFarField |
Riemann 不变量远场 |
BCIn |
指定入口 |
BCOut / BCOutP |
指定出口 / 压力出口 |
BCPeriodic |
标准周期 |
BCPeriodicRot |
旋转周期(叶轮机械) |
BCProfileIn |
表格化剖面(边界层, RANS) |
BCActuator |
致动盘源项 |
专用叶轮机械 BC:BCTotalInlet、BCRadialEqOutlet、BCMixingPlane,以及用于攻角自适应升力匹配的 CL 驱动(evaluator 中的 pCLDriver)。
euler_config_1DRiemann.jsoneuler_config_1DRiemann_LeBlanc.jsoneuler_config_1DSedov.jsoneuler_config_2DSedov.jsoneuler3D_config_Noh.jsoneuler_config_blast.jsoneuler_config_M2000Jet.jsoneuler_config_M5Diffraction.jsoneuler_config_cylinderHS.jsoneuler3D_config_SphereShock.jsoneuler_config_IV.json — 收敛性研究euler3D_config_TGV.json、euler3D_config_BenchTGV.jsonconfig_cylinderInvis_mg_bench.jsoneulerSA_config_0012_AOA15.json)和 k-ω(euler2EQ/...)变体,含 O2 升阶(..._Elev.json)和 MG 基准(config_0012_mg_bench.json)。eulerSA_config_30p30n.json。eulerSA3D_config_Rotor37.json。eulerSA3D_config_FanA1.json。tpMG、incFScale、与 LimiterUGrad 的保正耦合。euler2EQ / euler2EQ3D 可执行文件。BCWallIsothermal)。LimiterUGrad 中的保正重构限制器。source2nd、mergeMultiResidual、normOrd、restartOutAtInit、resBaseType 选项。RunImplicitEulervoid RunImplicitEuler() {
InitializeRunningEnvironment(env);
// optional restart
if (config.restartState.useRestart)
ReadRestart(config.dataIO.readRestart);
for (int step = 1; step <= config.timeMarch.nTimeStep; ++step) {
EvaluateDt(dt, u, uRec, CFL, dtMinAll, config.timeMarch.dtImplicit,
config.cflControl.useLocalDt, t);
// Inner pseudo-time loop (driven by the chosen ODE integrator)
odeIntegrator.Step(
u, uInc,
/*frhs*/ [&](rhs, u, dTau, iter, alpha, upos) { pEval->EvaluateRHS(...); },
/*fdt */ [&](u, dTau, alpha, upos) { pEval->EvaluateDt(...); },
/*fsolve*/ [&](x, rhs, uInc, dTau, alpha, ...) { Krylov + LUSGS; },
maxInnerIter, fStop, fIncrement, config.timeMarch.dtImplicit);
UpdateCFL();
if (step % config.outputControl.outputIntervalStep == 0)
PrintData(fname, series, …);
if (step % config.outputControl.restartInterval == 0)
PrintRestart(fname);
if (Converged() && config.timeMarch.steadyQuit) break;
}
}
上述 lambda 函数是 EulerEvaluator、GMRES_LeftPreconditioned 和 LUSGSMatrix* 的接入点 — ODE 积分器不知道是哪个求解器在实例化它。
| 模块 | C++ 可执行文件 | 测试用例 | Python 测试 | np 值 |
|---|---|---|---|---|
| DNDS | 8 | 249 | 9 | 1, 2, 4, 8 |
| Geom | 9 | 193 | 2 | 1, 2, 4, 8 |
| CFV | 4 | 67 | 43 | 1, 2, 4, 8 |
| Euler | 4 | 62 | 4 | 1, 2, 4, 8 |
| Solver | 4 | 29 | — | 1 |
总计: 29 个 C++ 可执行文件,600 个测试用例,58 个 Python 测试,涵盖 82 个 CTest 注册项。所有支持 MPI 的测试均按各 np 值在 CTest 中注册。串行测试超时 60–120 秒;并行测试超时 120–600 秒,视模块而定。
# Build + run everything
cmake -B build -DDNDS_BUILD_TESTS=ON
cmake --build build -t all_unit_tests -j8
ctest --test-dir build --output-on-failure
test_array — 布局、行视图、迭代器test_mpi — MPI 封装、集合操作test_array_transformer — 父/子 ghost 交换test_array_derived — AdjacencyRow、EigenMap 行test_array_dof — 向量空间操作、范数、AXPYtest_index_mapping — 全局 test_serializer — H5 + JSON、重分布test_permutation_transfer — MPL 重编号压缩/解压test_elements — 形函数、雅可比矩阵test_quadrature — 阶数、权重test_mesh_index_conversion — 状态转换test_mesh_pipeline — 完整构建链test_mesh_distributed_read — ParMetis 重分区test_mesh_connectivity — Inverse/Compose DSLtest_mesh_connectivity_ghost — GhostSpec BFStest_mesh_connectivity_interpolate — 面插值test_mesh_reorder — 逆 Cuthill-McKee/Hilbert 排序TEST_CASE("ArrayTransformer: round-trip ghost pull" *
doctest::description("np=1,2,4") *
doctest::timeout(120.0)) {
MPIInfo mpi; mpi.setWorld();
auto father = make_ssp<ParArray<real, 5>>();
auto son = make_ssp<ParArray<real, 5>>();
father->Resize(localN); father->createGlobalMapping();
// ... populate father ...
ArrayTransformer<real, 5> trans;
trans.setFatherSon(father, son);
trans.createFatherGlobalMapping();
trans.createGhostMapping(pullGlobal);
trans.createMPITypes();
trans.initPersistentPull();
trans.pullOnce();
CHECK(son->operator[](0).isApprox(expected, 1e-14));
}
test_reconstruction · 解析场上的 VR 收敛性测试。test_reconstruction3d · 3D 变体;Jacobi/SOR 对比。test_limiters · WBAP/CWBAP 在构造数据上的测试;覆盖全部限制器选项。test_device_transferable (仅 CUDA) · FiniteVolume 到 GPU 的往返传输。test_gas_thermo · 理想气体 Cv/Cp、T/p 关系、Mach→状态。test_riemann_solvers · 13 种变体,一维 Riemann 问题的精确解一致性。test_rans · SA + k-ω 源项、壁面距离积分、转捩位置。test_evaluator_pipeline · 在固定网格上的完整 EvaluateRHS — golden values。test_ode · ODE 基准测试上的 BDF/SDIRK/HM3(Van der Pol、刚性标量)。test_linear · 标准矩阵上的 GMRES + PCG 收敛性。test_direct · 小块 LU/LDLT 正确性。test_scalar · 标量输运对流-扩散回归测试。许多测试将计算结果与预先捕获的 golden values 进行比较,相对容差为 1e-6 到 1e-8。为了使这一点有意义,每次运行的结果必须字节级一致。
metisSeed = 42(固定值)。当 golden value 尚未捕获时,测试存储哨兵值 1e300:
const real gold_kinetic = 1e300; // TODO: capture
const real computed = evaluate();
if (gold_kinetic < 1e299)
CHECK(computed == doctest::Approx(gold_kinetic).epsilon(1e-8));
else
CHECK(std::isfinite(computed) && computed >= 0);
因此,新测试的首次运行是一个有限/非负的合理性检查,开发者随后在跟进提交中更新 golden value。
test/DNDS/test_basic.py(9 个测试)— import 链、MPIInfo、小数组往返。test/Geom/test_basic_geom.py(2 个测试)— CGNS 读取、升阶、对分。test/CFV/test_fv_correctness.py(16 个测试)— 壁面网格上的单元体积/面面积/雅可比正确性。test/CFV/test_vr_correctness.py(16 个测试)— sin(x)sin(y) 上的 VR 阶收敛。test/CFV/test_basic_fv.py + test_basic_cfv.py + test_cfv_dissdisp.py(11 个测试)— FV/CFV 冒烟测试与耗散-色散分析。test/EulerP/test_basic_eulerP.py(1 个测试)— 主机 + CUDA 往返。test/Euler/test_restart_redistribute.py(3 个测试)— 含 MPI 重分区的求解器重启。# Serial
pytest test/DNDS/test_basic.py -v
# MPI
mpirun -np 4 python -m pytest test/DNDS/test_basic.py
# Some tests support standalone
python test/DNDS/test_basic.py
mpirun -np 2 python test/DNDS/test_basic.py
# 1. Rebuild pybind11 shared libs
cmake --build build -t dnds_pybind11 geom_pybind11 \
cfv_pybind11 eulerP_pybind11 -j32
# 2. Reinstall into python/DNDSR/ (MANDATORY)
cmake --install build --component py
# 3. Only now, run tests
source venv/bin/activate
PYTHONPATH=<root>/python pytest test/ -v
在修改 C++ 源码后跳过安装步骤会导致残留的
.so 文件,并产生误导性的段错误,看起来像代码 bug。git checkout 会变更源码,但不会重新构建二进制文件。
{
"configurePresets": [
{
"name": "release-test",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"DNDS_BUILD_TESTS": "ON",
"DNDS_USE_OMP": "ON"
}
},
{ "name": "debug", "inherits": "release-test",
"cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } },
{ "name": "cuda", "inherits": "release-test",
"cacheVariables": { "DNDS_USE_CUDA": "ON",
"CMAKE_CUDA_ARCHITECTURES": "native" } },
{ "name": "ci", "inherits": "release-test",
"cacheVariables": { "DNDS_TEST_NP_LIST": "1;2;4",
"DNDS_TEST_OMP_THREADS": "2" } }
]
}
Collective目标:dnds_unit_tests、geom_unit_tests、cfv_unit_tests、euler_unit_tests、solver_unit_tests、all_unit_tests — 均设置为 EXCLUDE_FROM_ALL,因此普通的 cmake --build 仍能快速完成。
scikit-build-core# pyproject.toml
[build-system]
requires = ["scikit-build-core>=0.8", "pybind11", "pybind11-stubgen"]
build-backend = "scikit_build_core.build"
[project]
name = "DNDSR"
version = "0.2.0" # synchronized with VERSION file + git describe
[tool.scikit-build]
cmake.args = ["-DDNDS_BUILD_PYTHON=ON", "-DDNDS_PYBIND11_NO_LTO=ON"]
install.components = ["py"] # only install the py component
CC=mpicc CXX=mpicxx \
CMAKE_BUILD_PARALLEL_LEVEL=32 \
pip install -e .
*_pybind11 目标。python/DNDSR/*/_ext/。pybind11-stubgen 生成 .pyi 文件。python/DNDSR/_lib/。Conda/Anaconda Python 在二进制中嵌入了指向 conda 自带 libstdc++ 的 RPATH,其版本可能低于 MPI 编译器产生的版本。系统 Python 使用系统 libstdc++,避免了这种冲突。
—README.md
macOS 有专门的 fmtlib 变通方案,也已包含。
omp.h 包含问题。.clang-tidy Configuration理由保存在 docs/dev/clang_tidy_plan.md 中。.clang-tidy 禁用项(代表性)cppcoreguidelines-pro-bounds-pointer-arithmetic — 在 CSR/行扁平数组中不可避免。fuchsia-default-arguments-declarations — MPI 默认值。llvm-header-guard — 我们使用 #pragma once。modernize-use-trailing-return-type — 风格偏好。# Per-module histogram
python scripts/run_clang_tidy.py DNDS
python scripts/run_clang_tidy.py Geom
python scripts/run_clang_tidy.py CFV
python scripts/run_clang_tidy.py Euler
python scripts/run_clang_tidy.py Solver
Solver/Geom/CFV/Euler/EulerP 尚未清理 — 可应用相同的流程。.clang-tidy 的禁用Configuration可直接沿用。
doxygen_compat.py 同时在 Sphinx 和 Doxygen 中渲染。/doxygen/ 路径下。| 触发条件 | 耗时 |
|---|---|
| 无变动重建 | < 1 s |
| 仅修改 Markdown | ~10 s |
| 完整(Doxygen + Sphinx) | ~2.5 min |
cmake --build build -t serve-docs
# → http://localhost:8000 with hot reload
可压缩 Taylor–Green 涡,Re = 1600,100 次迭代,单 HPC 节点上固定 ~4k 单元/rank。
| 系列 | 求解器 | |
|---|---|---|
| BSSCA | DNDSR /BSSCA | 64 → 10240 ranks |
| BSSCT | DNDSR /BSSCA | 96 → 1920 ranks |
| CS | DNDSR /JS | 32 → 256 ranks |
kCI/s = 千单元-迭代/秒;一次单元-迭代为该单元上的一次 RHS 计算。

网格

AOA = 5°, 马赫数

AOA = 15°, 马赫数

AOA = 15°,
t = 0.2 时的密度,马赫 10 激波在 30° 楔上。

DITR U2R2,

BDF2
马赫 3 无粘流,15° 压缩拐角。

网格

密度,Re

压力,Re

密度,Re = 100
时间平均效果:

网格

时间平均

显式时间步长对比

马赫 0.1,32 条等值线(显式 2 阶 FV)

网格

涡量
Q-criterion 等值面,按马赫数着色。

网格

Q-criterion 等值面

密度

对角线上的密度

t = 0.6 时的密度

对角线上的密度
马赫 2000 射流




残差收敛
翼身组合体

表面网格

表面

表面

力系数收敛
struct GhostRequirement {
int cellRings = 1; // # of cell2cell rings
bool nodeNeighbor = true; // cell2cell by vertex share vs face share
bool complementNodes = true; // ghost cells keep all their nodes
bool complementBnds = true; // owned nodes keep all their bnds
};
nGhostLayers 只调整深度,不调整邻居的类型。edge2node、cell2edge、node2edge,遵循相同的 AdjPairTracked 规范。useCone × useClosure 布尔矩阵。docs/architecture/MeshDAGDesign.md(765 行)。NS_EX)— 成熟度提升,发布验证算例。EulerP 扩展到完整的 Euler 求值器。docs/dev/ 中拟定大纲。array_infrastructure.md — 自底向上遍历 Array → ArrayTransformer → ArrayPair → ArrayDof。MeshConnectivity.md — AdjPairTracked 状态机、ghost 规格 DSL、DAG 展望。Serialization.md — 分层 I/O、跨进程重启、偏移模式。Paradigm.md — 延迟抽象哲学,与 OpenFOAM/SU2 对比。Variational_Reconstruction.md / .pdf — 面泛函、内积选择及局部系统的完整推导。Shape_Functions.md — 逐单元形函数与积分。building.md — 外部依赖、头文件、CMake 预设。array_usage.md — 如何使用 Array/ArrayDof 编写代码。geom_usage.md — 网格构建与 VR 流水线。python_geom_guide.md — 完整的 Python Geom API 参考。serialization_usage.md — HDF5 检查点、重分布。style_guide.md — C++ 和 Python 规范。examples.md — 可运行的 examples/ex_*.cpp 程序。docs/tests/overview.md — 黄金值、确定性、测试套件汇总。docs/tests/{dnds,geom,cfv,euler,solver}_unit_tests.md。三条命令即可运行
cmake --preset release-test
cmake --build build -t euler -j32
mpirun -np 4 ./build/app/euler.exe cases/euler_config_IV.json
代码 · <repo/DNDSR> 文档 · cfdlab-thu.github.io/DNDSR 发布说明 · RELEASE_NOTES.md (v0.2.0)
清华大学 CFD 实验室
DNDSR 全面概述演示文稿 (中文版)。 此文件为自动生成。源文件位于: docs/presentations/DNDSR_overview/ 00_frontmatter_zh.md parts/zh/00_title.md parts/zh/01_opening.md ... parts/zh/10_roadmap.md 重新构建: bash docs/presentations/DNDSR_overview/build.sh --lang zh 直接渲染为 PDF: bash docs/presentations/DNDSR_overview/build.sh --lang zh --pdf 推荐查看器:"Marp for VS Code" 扩展 (内建 Mermaid + MathJax 支持)。 图片路径相对于最终 DNDSR_overview_zh.md 位置: ../elements/... 和 ../theory/... 溢出控制类 (按幻灯片追加为 Marp 指令): _class: dense -- 18px 基准字重 (紧凑表格 / 大量列表) _class: denser -- 16px 基准字重 (高密度参考幻灯片) _class: tight -- 14px 基准字重 (最大密度;谨慎使用) 注意:请保持 <style> 部分与 00_frontmatter.md 同步。