三次样条核:工程设置与诊断验证
从粒子间距、平滑长度比、支持半径倍数三个输入反推三次样条核的 h、支持半径与内部邻居数,给出 1D/2D/3D 归一化常数、链表格元尺寸与 CFL 的配套取值,并附可复算的三维设置算例。
三次样条核:工程设置与诊断验证
三次样条核的工程配置只需要锁定三个输入:粒子间距 、平滑长度比 、支持半径倍数 。本文用 mm、、 的三维算例,把这三个数推成 mm、 mm、内部邻居数 44.6,并给出可直接抄用的核函数与导数实现、链表格元边长和配套时间步。三次样条核的多数"数值噪声"抱怨其实可以归到三个可测量上:核的二阶矩给出的有效平滑宽度、离散归一化量 的分布、以及拉伸区里 的粒子对数量。
配对不稳定:从谱条件到粒子对计数
三次样条核的傅里叶变换在邻居数偏高时出现负瓣,规则排布失稳并坍缩成对。三维中的经验阈值约在 60 个邻居附近,用 反推:
现场判定不看谱,只数粒子对:定义 为粒子 邻域内 的邻居个数。规则初始排布下 ;一旦配对, 会出现 1 到 2 的密集取值,全场非零粒子数从 0 跳到数千。这个指标比压力噪声曲线更早给出信号,且不需要任何后处理假设。
| (,三维) | 预期行为 | |
|---|---|---|
| 1.0 | 33.5 | 稳定,无配对 |
| 1.1 | 44.6 | 稳定,余量约 25% |
| 1.2 | 57.9 | 临界,拉伸区开始出现成对 |
| 1.3 | 73.6 | 失稳,团聚成对 |
推荐参数台账
| 参数 | 符号 | 本算例取值 | 依据 |
|---|---|---|---|
| 粒子间距 | 5.0 mm | 最细结构至少铺 5 个粒子 | |
| 平滑长度比 | 1.1 | 三维邻居数 44.6,低于阈值 60 | |
| 支持半径倍数 | 2 | 三次样条定义域上界 | |
| 支持半径 | 11.0 mm | ||
| 格元边长 | — | 11.0 mm | 三维 27 格元覆盖 |
| 时间步 | s | ||
| 人工黏性 | 0.1 | 抑制压力振铃,与物理黏度分开记录 | |
| 内部邻居数下限 | 20 | 低于此值核近似退化 |
可复算的核函数与设置脚本
import math
SIGMA = {1: 2.0/3.0, 2: 10.0/(7.0*math.pi), 3: 1.0/math.pi}
def cubic_w(q):
if q >= 2.0: return 0.0
if q < 1.0: return 1.0 - 1.5*q*q + 0.75*q**3
return 0.25*(2.0-q)**3
def cubic_dw(q): # dw/dq
if q >= 2.0: return 0.0
if q < 1.0: return -3.0*q + 2.25*q*q
return -0.75*(2.0-q)**2
def kernel(r, h, d): # W
return SIGMA[d]*cubic_w(r/h)/h**d
def kernel_grad(r, h, d): # dW/dr
return SIGMA[d]*cubic_dw(r/h)/h**(d+1)
def setup(dp, eta, kappa, d, cs, vmax):
h, rc = eta*dp, kappa*h
N = (4.0/3.0)*math.pi*(kappa*eta)**3 if d == 3 else math.pi*(kappa*eta)**2
return dict(h=h, rc=rc, N_expected=round(N, 2),
cell=rc, dt=0.25*h/max(cs, 10.0*vmax))
print(setup(dp=0.005, eta=1.1, kappa=2.0, d=3, cs=20.0, vmax=1.5))
# {'h': 0.0055, 'rc': 0.011, 'N_expected': 44.6, 'cell': 0.011, 'dt': 6.875e-05}
诊断脚本
import math
SIGMA3 = 1.0/math.pi
def w(q):
if q >= 2.0: return 0.0
return 1.0-1.5*q*q+0.75*q**3 if q < 1.0 else 0.25*(2.0-q)**3
def dw(q):
if q >= 2.0: return 0.0
return -3.0*q+2.25*q*q if q < 1.0 else -0.75*(2.0-q)**2
def diagnose(pos, m, rho, h, dp, rc):
V = [mi/ri for mi, ri in zip(m, rho)]
S, beta, pairs = [], [], 0
for i, xi in enumerate(pos):
s = gx = gy = gz = 0.0
for j, xj in enumerate(pos):
r = math.dist(xi, xj)
if r >= rc or r == 0.0: continue
q = r/h
s += V[j]*SIGMA3*w(q)/h**3
g = SIGMA3*dw(q)/h**4
gx += V[j]*g*(xi[0]-xj[0])/r
gy += V[j]*g*(xi[1]-xj[1])/r
gz += V[j]*g*(xi[2]-xj[2])/r
if r < 0.5*dp: pairs += 1
S.append(s); beta.append(math.sqrt(gx*gx+gy*gy+gz*gz))
print("S min/mean/max = %.3f / %.3f / %.3f" % (min(S), sum(S)/len(S), max(S)))
print("beta max = %.3e" % max(beta))
print("paired pairs = %d (expect 0)" % pairs)
return S, beta
脚本里的三个输出对应三种不同的失效:S 的最小值低说明几何截断或归一化常数错;beta 偏大说明局部无序;pairs 非零说明配对不稳定。
三个归一化常数必须按维度取定
三次样条核写成尺度分离形式,把全部维度依赖集中到前置常数上:
无量纲形状函数 分三段定义,上界 就是支持半径的来源:
由全空间归一化 得 、、。三维可当场核对:,乘 恰为 1;二维对应 ,乘 得 1.0000。
维度混用会直接污染密度。二维算例里误用 ,规则格点上的离散归一化量 落到 ,密度整体偏低 30%;三维算例里误用 则得到 ,密度虚高 43%。这两个数字应当直接写成代码断言。
用目标邻居数反推平滑长度比
内部粒子的邻居数只由乘积 决定,与 的绝对值无关:
代入 、:,,二维同样参数只有 个邻居。三次样条在三维中的配对不稳定阈值约在 60 个邻居附近,因此 应落在 0.95~1.10;把 提到 1.3,邻居数升到 ,越界。这条关系也说明跨维度不能照抄 :同一个 1.1 在二维给 15 个邻居,在三维给 45 个。
支持半径、格元边长与搜索成本
链表搜索的格元边长取 时,二维检查 9 个格元、三维检查 27 个。本算例中 mm, mm,单个格元容纳 个粒子,每步要做 次距离判定才能筛出 44.6 个真邻居,筛选效率约 15.5%。 粒子体系单次邻居表重建约 次判定。
若把格元边长误设成 mm, 会跨越 5 个格元,必须遍历 个格元而不是 27 个,遍历开销变为 4.6 倍。规则是格元边长不小于 。
时间步与人工黏性的配套取值
时间步随 与最大声速缩放,换核但不改 时 基本不变:
取 m/s 得 m/s,本算例用 m/s,对应最大密度波动约 , s。人工黏性取 Monaghan 形式 、,只在接近声速的压缩对之间起作用; 若与物理黏度混记,后处理会把数值耗散误判成黏性效应。
故障模式与判定试验
| 现象 | 根因 | 判定试验 |
|---|---|---|
| 内部密度整体偏低约 30% | 二维算例误用三维 | 规则格点算 ,正确应得 0.999,误用得 0.700 |
| 内部密度虚高约 43% | 三维算例误用二维 | 同上,误用得 1.4286 |
| 拉伸区出现成对粒子团 | 使三维邻居数达 73.6,越过配对阈值 | 统计 的粒子对,正常为 0,配对时可达数千 |
| 邻居表重建耗时是预估的 4.6 倍 | 格元边长设成 而非 ,需遍历 125 个格元 | 打印单次查询的格元计数,三维应为 27 |
| 首步即发散 | 未随 缩放 | 减半重跑;若仍发散则查 是否取了物理声速 |
| 自由面粒子被吸向壁面 | 表面 仅约 0.5,压力估计偏低 | 分别统计内部与表面粒子的 分布 |
| 压力场出现与 同尺度的高频振铃 | 三阶导数在 处跳变 6.0,噪声以 进入 | 把 减半,若振铃幅度降到约 1/8 则确认为该项 |
| 拉伸区粒子聚成对,压力反而变平滑 | 使 ,越过配对阈值 | 统计 非零粒子数,同时把 降到 1.0 重跑 |
| 重构 的相对误差远大于 0.1% | 核二阶矩被误当成 ,实际为 | 用 重算理论偏差并对比实测 |
| 内部 只有 0.70 | 三维算例用了二维常数 或反之 | 打印所用 ,与 、 对照 |
| 壁面附近粒子被吸住 | 表面 ,压力被低估 | 按 分档统计内部/近表面/表面三组密度均值 |
| 时间步减半后振铃不变 | 误差来自核而非积分器 | 同上第 1 行,检查振铃随 的缩放指数 |
自由面与壁面的截断诊断
同一套粒子在内部与表面的表现差异极大,必须分开统计。三维中把粒子按 分成三档: 视为内部, 视为近表面, 视为表面或角点。三次样条核在表面处 ,若不做 Shepard 重归一化,密度被低估一半,压力随之被低估,表现为粒子被壁面"吸住"。诊断时不要把这个当作核函数缺陷:它是几何截断,正确的处置是补边界粒子或改用重归一化核,而不是给密度强行加下限。
核的形状函数及其光滑阶数
三次样条核的分段形状函数在 处拼接,工程上真正需要知道的是它在哪一阶导数上失去连续性:
逐阶求导可验证 、、 在 处两侧都等于 、、,因此该核是 的。但三阶导数不连续:
跳变幅度 6.0。核在三维中的三阶径向导数携带 的阶跃,这一项会以 的形式进入压力噪声。若仿真中压力场出现与粒子间距同尺度的高频振铃,而 与邻居数都正常,应当怀疑的就是这个跳变,而不是时间步。
二阶矩给出的有效平滑宽度
诊断"结果被抹平了多少",最直接的工具是核的二阶矩。三维中
分段积分给出 ,代入 得 。按每方向折算,等效方差为 ,等效标准差 。取 mm,等效平滑宽度 mm——任何比 3 mm 更细的流场结构在三次样条核下都会被抹掉。
用同一组数据可以预判重构误差。对 做核插值,规则格点上的一阶误差项是 。在 mm 处该偏差为 mm²;若评估点位于 mm,真值 mm²,相对误差 。所以"三次样条核把结果算歪了"在二阶场量上通常只有千分之一量级,真正的误差源是下面两项。
离散归一化量与梯度一致性量
离散化之后,连续归一化不再自动成立,必须逐粒子检查:
内部规则粒子上 应落在 附近(三维、 时实测 0.998~1.001)。自由面上的粒子因为核被几何截断, 约为 ;壁面角点可低到 0.25。 的理想值是零向量,实测其模长应小于 倍的 ;若 的模长与 同量级,说明该粒子处于极度无序区,梯度近似已经失效。
判断准则很简单: 的最小值决定是否出现伪力,而不是均值。均值 0.99 但最小值 0.30 的算例,在最小值所在位置会产生肉眼可见的粒子堆积。
参考资料
- Monaghan J.J., Lattanzio J.C., A refined particle method for astrophysical problems, Astronomy and Astrophysics, 149, 135–143, 1985.
- Dehnen W., Aly H., Improving convergence in smoothed particle hydrodynamics simulations without pairing instability, Monthly Notices of the Royal Astronomical Society, 425, 1068–1082, 2012.
- Liu M.B., Liu G.R., Smoothed Particle Hydrodynamics (SPH): an Overview and Recent Developments, Archives of Computational Methods in Engineering, 17, 25–76, 2010.
- Violeau D., Fluid Mechanics and the SPH Method: Theory and Applications, Oxford University Press, 2012.
- Monaghan J.J., Smoothed Particle Hydrodynamics, Annual Review of Astronomy and Astrophysics, 30, 543–574, 1992.
- Gingold R.A., Monaghan J.J., Smoothed particle hydrodynamics: theory and application to non-spherical stars, Monthly Notices of the Royal Astronomical Society, 181, 375–389, 1977.
- Zhu Q., Hernquist L., Li Y., Numerical convergence in smoothed particle hydrodynamics, The Astrophysical Journal, 800, 6, 2015.
- Price D.J., Smoothed particle hydrodynamics and magnetohydrodynamics, Journal of Computational Physics, 231, 759–794, 2012.