
简介这是一份基于Shan-Chen模型的3D多孔介质LBM流动模拟MATLAB代码。面向流体力学、渗流力学、地质工程与能源环境领域的研究者和学习者尤其适合初涉LBM、希望快速开展多相/多组分孔隙尺度仿真的读者。压缩包内仅1个m文件整体体积2KB核心脚本为Shan Chen in 3D.m涵盖多孔介质随机结构生成、Shan-Chen相互作用势、流体外力驱动、速度与压力场提取等关键环节并配有必要的参数设置运行后可直接获得三维孔隙空间内的流场分布、渗透率与压力梯度等结果。与OpenLB等大型开源框架相比该脚本结构紧凑、依赖少便于逐行阅读和二次开发。目前已有273人学习下载。借助该脚本可免去从零搭建LBM程序的繁琐工作直观理解Shan-Chen模型的物理机制与数值实现也可在此基础上修改孔隙结构、松弛时间或密度参数进一步分析多孔介质中流体输运特性作为教学演示或科研预实验的轻量工具。1. 拿到 3D 多孔介质的 Shan-Chen 脚本后先别急着跑不少人在 GitHub、CSDN 或学校 FTP 上扒到Shan Chen in 3D.m这类文件双击运行半分钟后弹出一张颜色斑驳的三维图就以为跑通了。实际上这个脚本里的信息量比表面看到的要大得多它同时包含了 D3Q19 速度离散、伪势 interparticle force、以及多孔介质固体节点的排斥力处理这三个模块任何一个设错参数结果都不是报错而是看起来正常但物理解错了。我拆这份脚本时最大的感受是Shan-Chen 模型在 MATLAB 里实现门槛不在 LBM 本身而在力的耦合方式和多孔介质边界怎么定义。这篇文章就从怎么拆、怎么改、怎么算对渗透率三个层次讲适合已经跑过一些 LBM 案例、打算把伪势模型用到数字化岩心或滤材流动分析的读者。2. Shan-Chen 伪势模型的力耦合机制与网格离散2.1 D3Q19 速度集与分布函数的内存布局Shan-Chen 模型本质上是单松弛时间BGK碰撞算子的扩展因此速度离散和标准 LBM 完全相同。3D 模拟里最常见的是 D3Q1918 个邻居方向加 1 个静止方向。Shan Chen in 3D.m中的典型做法是定义三组速度向量% D3Q19 速度分量单位格点速度 cx [0, 1,-1, 0, 0, 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 0, 0, 0, 0]; cy [0, 0, 0, 1,-1, 0, 0, 1, 1,-1,-1, 0, 0, 0, 0, 1,-1, 1,-1]; cz [0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1]; w [1/3, ... 1/18*ones(1,6), ... 1/36*ones(1,12)]; cs2 1/3; % 格子声速平方这里cx/cy/cz按静止 → 面邻居 → 角邻居顺序排列与权重数组w一一对应。注意这个顺序必须和脚本里f(:,:,:,k)的第四维索引保持一致一旦乱序分布函数在流方向的迁移会完全错位。MATLAB 里处理这种多维数组比 C 语言直观但内存开销也要心里有数double精度下100×100×100×19的数组就占 152 MB。我一般会把网格开到64^3做概念验证确认力模型工作正常后再放大。2.2 伪势相互作用力的两种写法Shan-Chen 模型的核心是引入一个依赖于局部密度的势函数psi(rho)流体粒子间的相互作用力写作% 作用在节点 x 上的总力 F_fluid -psi(rho(x)) * sum( w_i * psi(rho(x e_i)) * e_i );脚本里常见的是取psi(rho) rho0 * (1 - exp(-rho/rho0))其中rho0是参考密度通常取 1.0。这个势函数的作用是高密度区域对低密度区域产生排斥从而自发形成相分离。如果你需要模拟液滴或气泡关键在于这个psi的选取而不是调大调小某个表面张力系数——表面张力不是直接设定的是psi的一阶和二阶导数共同决定的。要注意力的符号G 是耦合强度F -G * psi * sum(...)G 为正代表排斥为负代表吸引。脚本里如果出现F G * psi * ...说明作者的符号习惯不同改写时务必统一否则接触角行为会完全反转。2.3 速度修正宏观速度要减掉半个力Shan-Chen 模型里有一个极易被忽略的细节宏观速度不能直接用sum(f_i * e_i) / rho计算因为作用力已经改变了动量分布。正确做法是% 碰撞前计算宏观速度含力修正 ux sum(f(:,:,:,idx2:2:end) .* cx, 4) ./ rho; uy sum(f(:,:,:,idx3:3:end) .* cy, 4) ./ rho; uz sum(f(:,:,:,idx4:4:end) .* cz, 4) ./ rho; % 修正u_eq u tau * F / rho ux_eq ux tau .* Fx ./ rho; uy_eq uy tau .* Fy ./ rho; uz_eq uz tau .* Fz ./ rho;这里的tau是 BGK 松弛时间。为什么必须这样做因为碰撞算子要求平衡分布基于实际物理速度构造而动量方程里力对速度的贡献是半个时间步。如果你用未修正的速度去算平衡分布压力场会出现虚假振荡尤其在相界面附近密度梯度大的位置速度场会有规律的棋盘状噪声。3. 多孔介质构建与边界条件反弹、周期和固体节点力3.1 数字化孔介质从随机球到真实 CT 扫描Shan Chen in 3D.m脚本里的多孔介质通常是程序化生成的最常见的方式是随机撒球。这类生成方法的好处是孔隙度和比面可控且不需要外部文件。核心代码逻辑% 在网格内随机生成 N 个半径 r 的球体相交形成的固体骨架 solid false(nx, ny, nz); for s 1:N cx randi([2, nx-1]); cy randi([2, ny-1]); cz randi([2, nz-1]); [X, Y, Z] ndgrid(1:nx, 1:ny, 1:nz); sphere_mask (X - cx).^2 (Y - cy).^2 (Z - cz).^2 r^2; solid solid | sphere_mask; end随机球法生成的骨架连通性往往不太均匀如果你需要更接近真实岩心的拓扑结构可以把 CT 扫描的体素序列读进来。读取时保持一个原则固体边界至少留一个格点的流体间隙否则边界反弹和力插值都会出问题。孔隙度的校验方法很简单porosity 1 - sum(solid(:)) / numel(solid);算出来与目标孔隙度差异较大时调整球半径或球数量而不是事后删节点。3.2 边界处理反弹边界与周期性入口出口的组合多孔介质流动模拟中固体表面用标准反弹格式half-way bounce-back处理入口和出口则做成周期性。反弹格式的代码在 MATLAB 里写成索引交换% 反弹把指向固体的分布函数反向回弹 for k 1:Q opp opposite(k); % 反向索引如 1-2, 3-4 bounce_mask solid (neighbor_f(:, :, :, k) 0); f(bounce_mask) f_old(bounce_mask, opp); end这么做实际上是把节点速度改为无滑移且质量守恒。针对多孔介质入口出口用周期性边界比较省事但需要注意如果流体受外力驱动如设定一个小体积力这个力要加在每个流体节点上而不是靠入口压力差——这是周期性边界与压力边界的关键区别。注意如果用压力边界如 Zou-He 格式在计算渗透率时要额外记录入口和出口的密度差反推出压力梯度。周期性边界加体力则直接由动量方程关系得到压力梯度无需额外处理。3.3 固体节点的排斥力让流体绕道的关键这是 Shan-Chen 模型做多孔介质流动最微妙的部分。流体和固体的相互作用力通常写成% 作用在流体节点上的固体排斥力 F_ads -G_ads * psi(rho(x)) * sum( w_i * s(x e_i) * e_i );这里的s(xe_i)是固体标记1 或 0。G_ads是流体-固体耦合强度。当G_ads为正时流体被固体排斥为负时流体被吸引。在多孔介质的两相驱替模拟中G_ads实际上控制了接触角的大小也就是润湿性——这个参数对渗透率的影响可能超过孔隙结构本身。调试时建议单独跑一个平板通道入口给一个恒定速度观察速度剖面是否呈现抛物线形状。如果剖面不对称或边界处出现速度滑移多半是固体标记边界与反弹边界不在同一层格点上或者F_ads中固体邻域权重没有用w_i加权。4. 可观测量的提取与误差排查渗透率、压力梯度和接触角4.1 渗透率计算达西定律只对层流成立多孔介质流动的标准输出是渗透率K定义来自达西定律% 计算平均流速与压力梯度 ux_mean mean(ux(2:end-1, 2:end-1, 2:end-1), all); dpdx (rho_inlet - rho_outlet) * cs2 / Lx; % 压力梯度格子单位 % 运动黏度格子单位 nu cs2 * (tau - 0.5); % 渗透率 K nu * ux_mean / dpdx;注意达西定律只在低雷诺数层流下成立。如果tau接近 0.5比如 0.5001数值黏度极小可能在孔隙喉道处产生局部惯性效应算出来的 K 会偏大。反之tau太大如大于 1则黏性过强物理上接近蠕变流但数值误差也增大。推荐的调试范围是tau 0.55 ~ 0.8。4.2 常见假收敛现象与判断方法很多人发现脚本运行很久但密度场不分离或者分离缓慢。这往往是引力强度G和松弛时间tau的配合出了问题。Shan-Chen 模型存在一个临界值G_crit低于这个值系统不会自发相分离。粗略估计方式是扫描一组 G 值绘制最大密度差随 G 变化的曲线拐点即临界耦合强度。另一个高频问题初始密度场完全均匀然后只靠力启动相分离数值上需要等很久。我的做法是在初始场中加入小幅随机扰动rho_init rho0 0.01 * rho0 * (rand(nx, ny, nz) - 0.5);这样分离成核更快也避免了对称性导致的死锁状态——尤其在完全对称的球状孔隙结构中没有扰动系统可能永远停留在均匀态。4.3 分布函数后处理的索引陷阱这份 MATLAB 脚本中f(:,:,:,k)的第四维索引如果用了循环展开修改代码时注意一个常见误用MATLAB 按列优先存储但多维数组的第四维是最慢变化的维度。当你做f(:, :, :, idx) ...时性能尚可但如果写for i, j, k, f(...) ...嵌套循环速度会慢至少一个量级。建议在关键循环前加上向量化索引比如用f(:,:,:,1)表示静止方向然后整体操作。5. 让 Shan-Chen 脚本从能跑变成能用于研究的几个进阶技巧这章分享三个实际工作中让我省过一天以上时间的调试方法和一段可直接用的验证代码都围绕这份 MATLAB 脚本的边界与力项展开。第一个技巧是用已知解析解做单相验证把G设为 0关闭伪势力把多孔介质替换成一个完整平板通道用Poiseuille解析解对比数值速度剖面。偏差在 1% 以内才算边界条件写对了。这个方法比直接拿多孔介质结果对比文献要可靠得多因为多孔介质里没有解析解误差来源很难定位。第二个技巧是接触角的定量标定。三维里直接量接触角不方便常用替代方案是在一个平面上放置一个圆柱液滴横截面后从二维轮廓读出接触角。MATLAB 里用contour提取密度等值线选密度为(rho_liquid rho_vapor)/2的位置作界面然后在三相接触点附近拟合切线角度% 提取密度等值线坐标 C contour3(X, Y, Z, rho3d, [rho_mid rho_mid]); % 手动选点/用 interp 拟合界面形状再计算切线斜率把G_ads从负到正扫描一遍你会得到接触角从 0° 到 180° 的单调曲线这个标定曲线一旦做出后续所有润湿性参数都不用再拍脑袋。第三个技巧是跟 OpenLB 对照基准。OpenLB 的porous_media算例里提供了标准算例输出如果你想确认 MATLAB 脚本的结果合理先把两边网格和参数对齐——相同的tau、相同的G换算公式、相同的反弹边界处理方式然后用 K 值做对比偏差在 3% 以内说明实现一致。MATLAB 用于原型验证、OpenLB 用于大规模计算这个搭配在多孔介质研究里很常见。用 OpenLB 的 3D 多孔介质算例时OpenLB 里的ShanChenForces模块要求传入psi函数指针而 MATLAB 脚本里psi是内置在循环里的。对比时先把psi(rho) 1 - exp(-rho)改成与 MATLAB 脚本完全一致的rho0*(1-exp(-rho/rho0))否则力的幅度差一个量级渗透率对数坐标下能差出近两个数量级。最后提一个所有伪势模型都通用的验收标准质量守恒。在每个时间步统计总质量sum(rho(:))如果每万步的质量漂移超过 0.1%基本可以断定反弹边界处有泄漏或力的离散不对称。这种问题在 MATLAB 里极难靠肉眼从云图发现但曲线一画就露馅% 每个时间步记录质量画质量-时间曲线 mass_history(t) sum(rho(:)); plot(mass_history);一条近似水平线说明代码是对的斜线或周期性波动就回头查F_ads的对称性和反弹边界的索引映射。这个习惯值得保留到所有 LBM 项目里——理论上 LBM 的质量守恒是离散精确的任何漂移都说明实现有 bug而不是模型有数值误差。本文还有配套的精品资源点击获取