1. 项目概述与核心价值
做渗流数值模拟的人,十有八九都遇到过同一个坎:饱和区计算挺顺利,一到非饱和区就开始出幺蛾子——要么迭代半天不收敛,要么孔压分布云图看着就不对劲,要么降雨入渗边界死活算不出想要的效果。回头看问题根源,大多出在“非饱和区处理逻辑”这一环没理顺。
我最初接触这个题目是在做边坡降雨入渗分析的时候。当时用的是有限元渗流程序,前几次试算总是出现一个诡异现象:坡顶表层孔压明明应该呈负值(吸力状态),算出来的结果却跳成了正压,导致有效应力分布整个错乱。排查了半天,发现问题根本不在边界条件,也不在网格质量,而是非饱和区的本构关系定义不当——程序在饱和度与孔压之间切换时走了错误的判定路径。从那以后我就专门整理了一套非饱和区的处理逻辑,这题的本质其实就是搞清楚一组问题:什么时候把单元当饱和算,什么时候当非饱和算,两者之间怎么平滑过渡,强非线性带来的收敛问题怎么压得住。
这篇内容主要面向三类人:做岩土工程、水利工程、环境岩土方向的数值模拟工程师;刚接触渗流分析的研究生和高年级本科生;以及需要用软件(比如GeoStudio、ABAQUS、FLAC3D、COMSOL等)进行降雨入渗、库水位骤降、尾矿坝浸润线分析的一线技术人员。看完至少能解决三个实际问题:第一,建立起非饱和-饱和统一分析的正确概念框架;第二,拿到一套可以直接套用的判定逻辑和参数处理流程;第三,遇到不收敛、振荡问题时,知道该从哪里下手排查。
2. 非饱和区处理逻辑的整体设计思路
任何渗流分析,第一步都是把问题域里每个单元/节点的水力状态搞清楚。非饱和区处理逻辑的顶层设计,核心是三件事:状态划分、本构模型、迭代策略。
2.1 为什么不能沿用“自由面以上无水”的传统思路
早年做渗流分析,很多人喜欢用电拟法或者只算饱和渗流,把自由面(潜水面)以上区域直接当“干区”处理,认为这个区域不参与渗流。这在稳定渗流、地层较简单时还算能凑合用,但一旦涉及瞬态过程、降雨入渗、蒸发、地下水位波动,这种简化会带来严重偏差。
原因在于:非饱和区并非完全无水,而是水以薄膜水和毛细水的形式赋存于孔隙中,孔隙中同时存在水和空气两相。基质吸力(负孔压)驱动下的水分运动,在降雨工况下恰恰是补给饱和区的主要路径——坡体安全系数在降雨过程中快速下降,很大程度上就是因为雨水先入渗到非饱和带,然后才逐步抬升浸润线。如果把非饱和区直接一刀切掉,相当于切掉了整个水分交换通道,计算结果必然失真。
所以现代有限元/有限差分软件里,普遍的做法是把“饱和渗流”和“非饱和渗流”纳入同一个控制方程框架下处理,用统一的Richards方程或者扩展Darcy定律来覆盖全域。这就是开头说的“非饱和区处理逻辑”的骨架:全域统一建模,在单元/节点级别动态判定状态,用同一套控制方程搭配不同的本构参数来描述两种水力状态。
2.2 状态判定逻辑的三种做法和选型权衡
把全域非饱和区识别出来,常见有三种程式化做法:
按孔压判定纯饱和区(最原始):设定一个阈值,孔压大于等于0判饱和,小于0判非饱和。优点是实现简单,缺点是临界点附近单元在迭代中反复跨变,极易振荡——你算第3步它还是非饱和,第4步孔压变成正的了,它被切成饱和,第5步又跌回去,整个迭代过程反复震荡,最终要么不收敛要么得到锯齿状孔压分布。
按饱和度判定:用饱和度阈值(如 ( S_e > 0.99 ) 视为饱和)来做状态切换。这个方法比单看孔压更稳一些,但仍然存在“干湿来回切换”的问题,只是切换频率低一些。
孔压-饱和度联动判定(推荐):同时检测孔压和饱和度,两个条件都满足才允许状态翻转,并且引入一个滞回区间(比如孔压在-0.5kPa到0.5kPa之间视为过渡带,不强制翻转状态)。这个方法牺牲了一点“理论上的精确”,但换来了数值稳定性的极大提升。在实际工程模拟中,这种数值稳定性比所谓的精度更有价值。
我的经验体会是,在没有强理论依据要求精确捕捉自由面突变的前提下,尽量用第三种联动判定,并且配合后文提到的初始场处理,能把大多数实际工程问题的计算振荡压到可接受范围。
2.3 控制方程与参数互换的基础框架
搭建非饱和区的核心水力关系,目前主流做法依然以Richards方程为主:
[ \frac{\partial \theta}{\partial t}
abla\cdot\left[ K(h) ablah \right] + S ]
其中 (\theta) 是体积含水率,(h) 是压力水头(负值对应非饱和区),(K(h)) 是随压力水头变化的渗透系数函数,(S) 是源汇项。还有一个常用的变体是混合形式Richards方程,同时用含水率和压力水头作变量,好处是对质量守恒的保持更好——具体到程序实现里,如果你是自己写代码,我强烈建议用混合形式,可以明显缓解数值振荡造成的质量不守恒。
这里要重点提醒一点:非饱和区的材料参数不是一组固定值,而是两条函数曲线——土水特征曲线(SWCC,也就是吸力-含水率关系)和渗透系数函数((K(h)) / (K(\theta)) / (K(S_e)))。这两条曲线必须和饱和渗透系数 (K_s) 保持一致性。很多人算到一半不收敛,回头排查发现土水特征曲线和渗透系数函数根本不自洽——比如SWCC取自文献A,渗透性函数又取自文献B,二者对应的孔径分布假设完全不同,导致程序在迭代中算法无法收敛。
3. 核心参数与模型实现要点
这章节把非饱和区模型中的关键参数、函数形式和实操取值建议拆开来讲。
3.1 土水特征曲线的选择与拟合
现在使用最广泛的是van Genuchten模型(简称VG模型),它的表达式是:
[ S_e = \frac{\theta - \theta_r}{\theta_s - \theta_r} = \left[ \frac{1}{1 + (\alpha |h|)^n} \right]^m ]
其中 (S_e) 是有效饱和度,(\theta_r) 是残余含水率,(\theta_s) 是饱和含水率,(\alpha)、(n)、(m)(通常取 (m=1-1/n))是拟合参数。
实际拟合的时候,有几个坑值得注意:
- 参数 (\alpha) 的量纲是1/cm或1/m,和压力水头直接相关,取值差距极大(砂土可能0.1~0.5 /cm,黏土可能0.001~0.01 /cm),千万不能拿来通用。
- (n) 控制土水特征曲线的陡峭程度,砂土通常2~5,黏土通常1.1~1.5,n越大曲线越陡。
- 如果遇到级配不良的土或者裂隙性黏土,VG曲线拟合R方很低时,可以试试Brooks-Corey模型或者分段的FX模型(Fredlund-Xing),后者在高吸力段表现通常更好。
我的建议是:手头没有实测SWCC的话,优先从工程类比和地区经验数据找相近土的曲线参数,千万不要自己随手造数。你输入一个拟合度很差的SWCC,等于从源头上埋下了误差,后面算得再漂亮都是自欺欺人。
3.2 非饱和渗透系数函数的关联式
非饱和渗透系数 (K(h)) 通常通过SWCC曲线用Mualem模型推导:
[ K(S_e) = K_s \cdot S_e^l \left[ 1 - (1 - S_e^{1/m})^m \right]^2 ]
其中 (l) 是孔隙关联参数,通常取0.5(VG模型默认搭配)。
实操中有个容易被忽视的问题:当有效饱和度趋近于0(高吸力段)时,(K(h)) 会变得极其小(可能到10^-12甚至10^-14 m/s量级),造成有限元方程的刚度矩阵条件数剧增,数值求解困难。这个阶段通常的处理办法是设置一个渗透系数下限(比如 (K_{min} = 10^{-10} \text{ m/s})),低于下限时强制取下限值。这里的取舍逻辑是,低饱和度下实际渗透能力确实趋近于零,与其不过收敛,不如给一个下限保证求解稳定性。
另一个与饱和渗透系数相关的点是:各向异性土的 (K_s) 要区分水平和垂直方向。非饱和区的 (K(h)) 也相应按方向分别定义,很多软件默认只输入一个标量 (K_s),遇到层状地层和成层土时误差会成倍放大。
3.3 干湿循环中的滞回效应要不要考虑
土体在干燥和湿润过程中,SWCC并不是同一条曲线——干燥路径的吸力高于湿润路径的吸力,两条SWCC之间夹出一个滞回圈。在循环荷载、频繁干湿交替的场景(比如库水位消落带、灌溉期土壤剖面)中,滞回效应若不考虑,孔压和含水率的响应会出现相位差和幅值偏差。
但滞回模型的引入,对数值模拟来说代价很高:每一个单元的干湿状态历史都必须独立存储,材料模块需要维护各单元的状态机,已经调试好的收敛流程会变得相当脆弱。我的建议是分场景处理:
- 单向入渗工况(比如一次强降雨,没有明显干湿往复),可以不考虑滞回,误差可控。
- 长期循环工况(比如库水位反复升降),至少考虑简化的滞回,或者用中间SWCC折中曲线做一个补偿。
- 对于绝大多数工程稳定分析,不考虑滞回效应是可以接受的工程近似,报告中注明即可。
4. 实操过程与关键环节实现
下面的流程基于我常用的有限元渗流程序操作经验整理,逻辑上在GeoStudio、ABAQUS、COMSOL等平台上都能对应上。
4.1 初始条件与稳态非饱和场的建立
正确处理非饱和区的第一步,是建立合理的初始孔压场。很多人图省事直接把初始孔压设成0,或者只用饱和渗流结果初始赋值,这是后期不收敛的重要诱因。
标准做法是两步走:
第一步,稳态非饱和渗流求解:施加真实的边界条件(比如上游水位、下游水位、地表降雨入渗强度初始值),运行一个稳态求解,让整个计算域的孔压场先稳定下来。这个稳态解通常是一个既包含饱和区(正孔压),也包含非饱和区(负孔压)的空间分布场。
第二步,以稳态解作为瞬态初始场:把第一步得到的节点孔压场作为瞬态分析的初始条件。这样做的核心目的是让非饱和区在瞬态计算开始时就处于一个“力学和渗流都平衡”的状态,避免初始场内部继续发生剧烈的重分布,把数值振荡的火苗提前扑灭。
实际踩坑记录:早期我做库水位骤降分析时,初始条件用了“最高水位饱和渗流解”,结果水位骤降一启动,上部非饱和区大面积爆发负孔压,与下部饱和区之间形成巨大的水力梯度,第一两个时间步就出现几十个单元不收敛。改成“分级稳态建场”之后(先保持高水位稳态、再瞬态骤降),问题直接消除。
4.2 时间步长控制与干湿切换稳定性
非饱和区求解的时间步策略比饱和区严格得多,主要原因是非饱和渗透系数随孔压变化呈强非线性,时间步太长,孔压增量过大,就可能在相邻单元间造成“跨越式”切换。
好的做法是使用自适应时间步进:
- 初始时间步可以设得较小(比如1秒到10秒,取决于问题的特征响应时间)。
- 每个时间步收敛后,根据迭代次数或误差指标自动调整下一步长。
- 当最大孔压增量超过预设阈值(比如0.1kPa)时,将时间步减半并重算;当增量控制在阈值的1/3以内且迭代稳定时,可以适度放大步长。
时间积分方案的选择也会影响振荡:向后欧拉(Backward Euler)是最稳的,无条件稳定但有一些数值耗散;Crank-Nicolson格式时间精度高一些,但在强非线性+干湿切换问题中容易产生非物理振荡。我的选择策略是:瞬态初期用向后欧拉,等场变量进入平稳发展段后再切换到Crank-Nicolson。有少数软件支持自动切换(比如COMSOL的广义alpha法),可以直接用默认设置,但要留意时间步不能太大。
4.3 单元状态切换的缓存与冻结策略
在有限元实现中,“非饱和区处理逻辑”的核心代码模块通常是一个状态判定函数,大致伪码逻辑如下:
for each element/node i: current_h = h_i current_S = Se_i # 饱和 -> 非饱和切换 if state_i == saturated and current_h < -transition: state_i = unsaturated # 非饱和 -> 饱和切换 if state_i == unsaturated and current_h > 0 and current_S > 0.99: state_i = saturated # 过渡带一律保持原状态,不翻转 if state_i == saturated and current_h >= -transition and current_h <= 0: # stay saturated if state_i == unsaturated and current_h >= 0 and current_S <= 0.99: # stay unsaturated update_material_properties(state_i)这里的核心逻辑在于滞回区间的引入(transition值通常取0.1~0.5kPa)。有了这个冻结策略,单元状态不会在边界处来回抖动,矩阵系数也不会频繁突变。
实操中用到的另一个技巧是“过松弛阻尼”:当单元状态翻转后,下一迭代步的材料参数变化量乘以一个阻尼系数(比如0.3~0.6),可以防止状态翻转导致的渗透系数跳变(比如从10^-7跳到10^-10)直接冲击Newton-Raphson迭代。这个阻尼不是标准教科书内容,但实测非常有效。
4.4 边界条件的施加方式
非饱和区计算中,边界条件的施加逻辑和饱和区有些区别。
对于降雨入渗边界,关键在于区分“入渗控制”和“积水控制”:
- 当降雨强度小于地表入渗能力时,边界按流量边界处理,施加 (q = q_{rain})。
- 当地表达到饱和、开始积水时,边界应切换为孔压约束——地表孔压约束为0(或积水深度对应的压力水头)。
这个“流量边界—孔压边界切换”逻辑在实际程序中通常通过一个自由面边界算法实现。很多初学者把降雨强度一直当流量边界加载,导致地表孔压越算越正(虚高),甚至超过积水深度对应的压力水头,完全失真。
排水边界方面,如果是自由排水面(比如坡脚渗出段),应设置“允许出流、不允许回流”的边界条件——存在正孔压梯度时排水,孔压低于大气压时边界关闭。这一块在GeoStudio中是默认处理,在ABAQUS里需要自己配Surface Film Condition,比较绕,需要留心。
5. 常见问题排查与经验速查
这部分把项目里常见的“翻车”场景整理成排查手册,按诊断路径来写。
5.1 不收敛的十种检查姿势
遇到非饱和区计算不收敛,先别急着调网格加密,按下面顺序逐个排查:
- 初始孔压场是否合理——最常见的问题根源,先检查初始负孔压分布是否符合保持毛细现象基本原理(原则上竖直方向孔压梯度应考虑静水梯度,不能自由设定成常数)。
- SWCC参数是否自洽—— (S_e=1) 处曲线是否连续过渡到饱和区,有没有断点。
- 渗透系数下限是否设置——高吸力区 (K(h)) 是不是低到了破坏矩阵条件数的程度。
- 时间步长是否合适——把初始时间步减小两个数量级,如果收敛性显著改善,说明问题在时间离散精度。
- 单元状态是否高频翻转——输出状态变量变化历史,如果某个单元状态反复切换,检查判定阈值设置。
- 边界是否在状态切换附近振荡——降雨边界、排水边界最容易出现,考虑引入边界切换滞回。
- 材料参数空间突变——相邻单元如果土层渗透系数或SWCC差异过大,容易在土层界面上产生数值震荡,可以尝试在界面附近做过渡网格。
- 孔隙水压缩性是否设置——真三维计算中忽略水的压缩模量,可能让方程变为病态。
- 非饱和区单元积分方式——低阶单元配单点积分容易锁死或振荡。
- 矩阵求解器设置——非线性求解的线性化残差阈值设置是否合理,直接放宽线性残差到 (10^{-2}) 试算,如果迭代很快收敛但精度损失可接受,那就说明之前线性残差阈值太苛刻。
5.2 干湿切换造成的孔压锯齿
现象:孔压场在自由面附近出现一正一负交替的锯齿状分布,看起来像“像素噪点”。
这个问题的本质是“空间离散尺度上状态翻转不完备”。具体讲,自由面并不恰好穿过单元节点,而是穿过单元内部。当单元内部一部分处于饱和状态、一部分处于非饱和状态时,如果材料参数以单元为单位突变,就会产生这种锯齿状分布。
处理建议:
- 优先用“节点判定+单元插值”的方式,而不是“单元判定”的粗粒度方式。
- 在自由面附近做局部网格加密,让单元尽可能小,自由面穿过单元的梯度更平缓。
- 如果软件不支持节点判定,这一步可以用“伪弹性地基”式的过渡区补偿——给界面附近的单元一个等效渗透系数折减,平滑参数跳变。
5.3 降雨入渗边界不排水
典型表现:降雨条件已经加到边界上了,但地下水位没什么反应,总流量统计又显示大量水“丢失”了。
排查思路:
- 先看降雨强度是否远小于土壤入渗能力——如果是小强度长历时降雨,入渗翼可能发展很慢,水位响应本就不明显,这是物理现象而不是程序问题。
- 检查地表单元的渗透系数是否被非饱和区部分拉低了,导致实际入渗能力骤降。有些程序对边界单元的 (K(h)) 用边界处孔压插值,如果表面单元在计算初期就形成了很低的负孔压,会直接抑制后续入渗——这时可能需要将表面层的初始吸力设定在合理范围内(不可任意加大)。
- 检查是否误把“总降雨量”当“净入渗量”施加了,忽略了地表径流量这一部分。
- 在瞬态分析中,边界流量在非饱和条件下也应乘以相对渗透系数 (K_r),如果程序在边界上没有做这层折减,就会高估入渗量。
5.4 非饱和区变形耦合的留意点
如果分析类型是流固耦合(比固结分析、边坡稳定性分析),非饱和区除了渗流自由度还有变形自由度,问题会再多一层复杂度。
非饱和土的有效应力表达方式和饱和土不同,常见的Bishop有效应力公式:
[ \sigma' = (\sigma - u_a) + \chi (u_a - u_w) ]
其中 (\chi) 是有效应力参数(通常取饱和度),(u_a) 是孔隙气压力,(u_w) 是孔隙水压力。在非饱和区,把 (u_w) 当负孔压代入的计算结果是:吸力增加有效应力,土体被视为更“硬”。这个趋势在趋势场上是正确的,但量值上误差可能很大,特别是高饱和度区。做耦合分析时,务必清楚程序采用的是哪种有效应力框架,以及是否考虑了 (\chi) 随饱和度的变化——否则你会得到看起来合理但实际不可靠的结论。
5.5 操作工具层面的避坑建议
工具层面,针对不同软件平台的使用经验我分别说几句,仅供参考:
- GeoStudio(SEEP/W + SLOPE/W):处理非饱和区相对友好,SWCC输入界面直接,在“饱-非饱和”分析选项中,记得点选“Include Negative Pore-Water Pressures”选项,否则非饱和区吸力被忽略。
- ABAQUS:用Soil模块做渗流分析时,孔隙比-对数应力-吸力模型参数设定要仔细核对单位制和场变量输出设置。吸力用负孔压表示,初始条件需要定义一致的孔压场。土水特征曲线要填在Permeability模块对应的Absorption参数里,别漏。
- COMSOL:Richards方程模块内置VG模型,但默认参数顺序和文献顺序可能不同,用前先核对帮助文档中的参数定义顺序,我见过有人把alpha和n填反了,算了半天云图倒是能出,结果完全错误。
- FLAC3D:自带饱和/非饱和渗流分析的切换逻辑,默认非饱和扩散系数用饱和扩散系数替代,高吸力段行为处理粗糙,做非饱和分析需自行设置相对渗透系数函数,手册里这部分的示例代码值得参照。
6. 最后分享一个小技巧
做非饱和区分析,我强烈建议每一步都留下“状态变量检查”的习惯。无论用什么软件,输出里至少包含饱和度、孔压、状态标识符(是饱和还是非饱和)这三项。每次算完,先看状态标识符的分布是否合理——哪个区域饱和、哪个区域非饱和、过渡带在哪里,是否符合工程常识。很多时候,云图单独看都能看过去,但把状态标识符和孔压、饱和度一起叠起来看,问题立刻暴露。
另外,如果项目允许,尽量做一次“无降雨对照工况”,只比有雨和无雨两种条件下的孔压场差异。这个方法花不了多少算力,但能快速帮你检验非饱和区逻辑是否在正轨上——如果无雨工况算出来非饱和区孔压场自己乱动,那说明初始场或边界有什么问题,先别急着加到复杂工况里去算。按这个顺序做,你会发现所谓“难搞的非饱和区”,其实也没那么可怕,关键是每一步都别急着跳过去。