
写这篇东西的起因是我在帮一个场地调查项目做风险评估时需要快速判断地下水中苯污染羽的扩展范围。当时手头有场地的基础水文地质参数但缺一个能直观展示“污染到底会走到哪、浓度会剩多少”的工具。我试了传统的地下水软件也试了一些商用水质模型最后还是回到用Comsol搭污染物地下运移模型。今天就把整个复现过程完整写出来以苯污染为例从物理概念到建模操作、从参数取数到问题排查尽量让一个只有基础数值模拟经验的人也能跟着做下来。苯这个东西在化工、加油站、焦化厂这类场地太常见了。它属于典型的轻质非水相液体密度比水小泄漏后一部分会残留在地表以下形成污染源长期缓慢地向地下水释放溶解态苯。一旦进到含水层里它不会老老实实待在一个地方而是跟着地下水一起跑一边跑一边扩散、吸附、降解最后在地下水里形成一片形状像舌头的污染羽。要预测这片污染羽的形态和浓度数值模拟几乎是绕不开的手段。如果你正在做地下水环境影响评价、污染场地调查、修复方案设计或者只是研究生课程里想复现一个经典的地下水污染物运移算例这篇内容应该都对得上。我会把我踩过的坑、试过的参数、调过的求解器设置都摊开来讲。1. 项目背景与模型思路拆解1.1 苯污染问题的科学本质先搞清楚苯在地下水中到底经历了什么。溶解态苯从污染源进入含水层之后主要受到四种作用的支配对流、水动力弥散、吸附阻滞和生物降解。对流是污染物跟着地下水流方向前进这是污染羽迁移的“主引擎”。可以想象成往河流里倒了一桶墨水墨水会顺着水流往下游漂漂的速度基本等于水流速度。这个速度不是地下水本身的流速而是多孔介质中的孔隙流速也就是达西流速除以有效孔隙度。水动力弥散是污染羽不断向外扩散的现象它由两部分组成一是机械弥散因为含水层里的孔隙大小、弯曲程度各不相同水流路径和速度杂乱无章污染物颗粒走着走着就四散开来二是分子扩散浓度高的地方向浓度低的地方扩散。机械弥散通常远大于分子扩散尤其在流速不算特别低、模拟尺度不小的情况下。吸附阻滞是污染物在骨架颗粒表面的滞留效应。苯在地下水中运行时会有一部分吸附在土壤或岩石颗粒上暂时“走不动”。从宏观效果看污染物前锋的推进速度会被拉慢慢到只有孔隙流速的几分之一。数学上用一个阻滞因子R来表示R越大于1污染物走得越慢污染羽的扩展范围相对变小但残留时间变长。生物降解是苯在微生物作用下发生的好氧或厌氧分解。场地里苯自然衰减的重要因素但在数值模型里通常简化成一级降解反应单位时间以固定比率消失半衰期概念和放射性衰变类似。四件事各自有各自的数学表达放在一起就是一个带对流、扩散、吸附和反应项的偏微分方程污染物地下运移模型的全部内容归根到底就是把这个方程解出来。1.2 为什么选Comsol建这个模型很多同行第一反应是地下水污染物运移不是有MODFLOW加MT3DMS这种行业标准吗为什么用Comsol这个问题我确实被别人问过。如果你做的是正式的污染场地修复报告而且监管文件明确要求用MODFLOW系列那Comsol确实不是首选。但如果你做的是研究型工作、方案比选或者一维二维机理分析Comsol的优势就非常明显了。Comsol的地下水模拟基于Darcy定律或Brinkman方程溶质运移基于稀物质传递或多孔介质中的稀物质传递两者在同一个图形界面里建立多物理场耦合是原生支持的。这意味着水流场和浓度场可以同步求解不需要像传统地下水软件那样先单独算水流再导出流速场再填进溶质运移模块去跑。从建模体验上说Comsol更像是在写一个“可交互的偏微分方程模型”而不是被一套地下水模块的固定流程框住。热词里提到的“Comsol移动网格”“Comsol压电效应”很多人可能觉得Comsol是搞电磁和固体力学的其实污染运移只是它多物理场能力里很小的一个方向。不过这也说明Comsol的边界条件、网格、后处理框架是通用的你只要会Darcy定律和稀物质传递两套物理场就能接着扩展热传递、反应动力学甚至变形耦合的复杂问题。1.3 模型简化假设与适用场景任何数值模型都是对现实的取舍不简化没法算。我在复现这个苯污染模型时采用了如下一套常见的简化方案含水层均质各向同性忽略局部透镜体和裂隙影响地下水流场为稳态不随时间变化苯浓度低不考虑非水相流体的多相流动过程污染源以固定浓度持续释放吸附符合线性等温吸附阻滞因子为常数生物降解用单一的一级衰减速率表示模型为二维剖面沿含水层垂向变化被压缩到二维平面。这套假设对应的适用场景很清晰在初步风险评估阶段判断污染羽可能的影响范围在修复方案比选中比较不同方案的相对效果或者在教学里演示地下水污染物运移的基本规律。它不适用于需要精确刻画非水相流体在包气带中运移、复杂化学反应、或者强非均质地层的精细场地模拟。建模之前最忌讳的是把问题想得太复杂。我见过很多人第一步就想建三维、想考虑多相流、想把几十层地层都画进去结果参数全是猜的模型算出来反而没有任何可信度。先从简化模型跑通物理规律看得明明白白再逐步增加复杂度才是正确的路线。2. 建模前的参数准备与量纲检查2.1 地下水流参数怎么定污染运移模型的第一步是确定地下水流场流场的速度大小直接决定污染羽往哪走、走多快。地下水流参数的三个核心量是水力传导系数K、水力梯度i和有效孔隙度n。水力传导系数反映含水层让水通过的难易程度。中砂含水层大概在1e-4 m/s这个量级粉砂或细砂会低一到两个数量级。水力梯度通常由两个水头观测孔的水位差除以距离得到在没有实测数据时场地尺度上取0.001到0.005都算合理。我这次取K等于5e-5 m/si等于0.002计算结果达西流速q为K乘以i等于1e-7 m/s再除以有效孔隙度0.3得到孔隙流速约3.33e-7 m/s。这个数字单独看没概念换算成每年多少米就直观了。一年有3.156e7秒3.33e-7 m/s乘以3.156e7秒约等于10.5 m/yr。也就是说在没有任何阻滞和降解的情况下苯的理论最快迁移速度是每年十来米。如果模拟20年纯对流距离大约210米。这个估算对后面设计模型长度非常关键。记住一句话Comsol内部统一用国际单位制时间默认是秒。你可以把模型几何画成米浓度场用mg/L但方程里的时间变量永远是秒。很多复现翻车的人不是物理模型建错了而是单位换算错了比如把一天的降解速率直接当成每秒速率填进去污染物瞬间就降解没了。2.2 溶质运移参数与反应参数溶质运移的另一个关键参数组是弥散系数、阻滞因子和降解速率。弥散系数在模型中分为纵向和横向两个方向通常写成纵向弥散度乘以流速。纵向弥散度αL在场地尺度下常常取0.1到10米尺度越大取值越大。一个小尺度柱实验的弥散度可能只有几毫米到几厘米但场地尺度下由于含水层非均质性弥散度会大得多。我这次取纵向弥散度2米横向弥散度取纵向的十分之一即0.2米。有效弥散系数D_L约等于纵向弥散度乘孔隙流速2米乘以3.33e-7 m/s等于6.66e-7 m2/s。这个数值代表了污染羽在主流方向上被拉长、被稀释的能力。横向弥散系数大约6.66e-8 m2/s横向扩展很慢这解释了为什么污染羽通常比较窄、比较长。阻滞因子R的公式是R 1 ρb Kd / n。ρb是土的干密度约1600 kg/m3Kd是分配系数苯在含水层砂土中常见取0.1到1 L/kg。把0.1 L/kg代进去还需要注意单位换算1 L等于1e-3 m3ρb Kd / n 1600乘以0.1乘以0.001再除以0.3约等于0.53所以R约等于1.53。污染物前锋的实际速度就会从10.5 m/yr降到约6.9 m/yr。想一下这相当于污染物在含水层里“边走边停”慢了不少。降解速率λ在自然衰减评估里是最敏感也最没底的参数。苯的好氧降解较快厌氧降解较慢综合场地尺度常见取值在0.005到0.05每d之间。我这次取0.01每d也就是0.01每天换算成秒是0.01除以86400约等于1.16e-7每s。对应的半衰期是ln2除以0.01约69天。这意味着两个多月浓度就剩一半三个多月剩四分之一这个参数对污染羽的存量影响非常大。2.3 参数取值速查表下表是我在模型里实际使用的参数汇总方便你对照着设置。提醒一句这些是文献和工程经验范围内相对合理的取值不是任何特定场地的实测值。参数符号取值单位说明水力传导系数K5e-5m/s中砂量级水力梯度i0.002—区域水头差/距离有效孔隙度n0.3—对流动起作用的孔隙纵向弥散度αL2.0m场地尺度取值横向弥散度αT0.2m通常为纵的1/10分子扩散系数Dm1e-9m2/s基本固定可不调分配系数Kd0.1L/kg苯在砂土的取值干密度ρb1600kg/m3常见砂土取值阻滞因子R约1.53—由上述参数计算一级降解速率λ0.011/d自然衰减综合速率污染源浓度C010mg/L溶解态苯浓度模拟时长t_max20yr展示长期演化这张表最容易被低估的是弥散度和Kd它们的取值范围横跨一两甚至三四个数量级取值高低对结果的影响比K值还大。后文的敏感性分析再展开说。3. Comsol建模实操全过程3.1 新建模型与物理场选择我用的版本是Comsol 6.4如果你用的是6.2、6.3或者更旧的5.x版本界面布局会有一点差别但核心设置的名称基本都能对应上。打开模型向导后空间维度选二维物理场先添加“Darcy定律”Darcys Law再添加“稀物质传递”或者更贴近多孔介质的“多孔介质中的稀物质传递”。后者的好处是孔隙度、吸附、时间导数里的阻滞因子都已经内置好如果版本里没有这个选项就用普通稀物质传递再把阻带项手动加进去。研究类型选“瞬态”因为我们要看不间断的浓度演化过程而不是只关心最终稳态。这里有一个新手容易犯的错只添加稀物质传递自己写一个常流速场把模型跑完才发现流速和地下水水头场不一致污染羽的位置完全错误。只要你的场地不是严格意义上的均匀流或者你希望后面扩展井、非均质、垂向分层都最好在一开始就把Darcy定律加进来让水流场和浓度场实现真正的耦合。3.2 几何创建与边界条件几何本身很简单一个200米长、10米厚的矩形代表含水层剖面。污染源放在上游侧一部分区域常规模拟是让污染源位于左侧顶部附近的某个局部区域。实际操作中有两种方式表达污染源。第一种是把污染源简化为一条边界线例如在左侧边界上y方向取上段5米设为固定浓度10 mg/L。这种做法设置简单适合概念模型但缺点是污染源位于进水边界上水流会把苯向后带的现象不够自然。第二种更符合真实场地情形在模型内部用一个单独的小矩形代表已污染的残留源区例如把一个3米宽、3米高的小矩形放在左侧中部小矩形内部浓度固定为10 mg/L作为持续释放的污染源。小矩形仍然是含水层的一部分水可以流过污染物从这里持续向外扩散和对流。我推荐用第二种。在Comsol中画好一个大矩形后用“几何”菜单里的“分割”功能在大矩形内部切出小矩形并给这个小矩形单独一个域编号。切割时不要把小矩形切成一个独立的多余实体只是划分域。边界条件这样设置Darcy定律模型左边界设为水头50米右边界设为49.6米形成2/2000.01的水力梯度等一下这个梯度有点大了。如果是0.002200米两端水头差应为0.4米。所以左边界水头50米右边界49.6米正好差0.4米梯度0.002。顶边界和底边界设置为无通量代表隔水边界。稀物质传递上游边界浓度设为0因为流入含水层的水不含苯源区小矩形设为固定浓度10 mg/L右边界设为“流出”边界允许污染物随着水流离开模型顶底边界为无通量。如果源区小矩形和入口边界相邻需要仔细检查边界设置是否冲突尤其要注意不能让Darcy定律里源区边界的水头约束和浓度约束叠加。3.3 多物理场耦合与反应项设置水流和溶质运移的耦合点在于速度。Darcy定律求解后会给出达西速度场dl.U和dl.V但稀物质传递方程里需要的速度是孔隙流速也就是达西速度除以有效孔隙度。在稀物质传递物理场的“对流”节点里把速度分量表达式填成dl.U/n和dl.V/n。表达式里的n是你在模型里定义的孔隙度参数。有效弥散系数也要手动关联流速。在稀物质传递的“扩散”部分把扩散系数设置为各向异性或各向同性表达式为alphaL*abs(dl.U/n) Dm。这里abs(dl.U/n)是孔隙流速的模纵向弥散方向沿流速横向方向用alphaT*abs(dl.U/n)Dm。如果你的版本里可以直接选弥散张量物理场会更省事否则用表达式一样能实现。降解反应放在源项里表达式为-lambda_decay*C其中lambda_decay先换算成秒为单位。吸附阻滞的处理方式取决于物理场版本。如果是普通稀物质传递一种变通的办法是不要改方程而是把实际速度换成dl.U/(n*R)把实际弥散系数保持不变同时在反应项中照常写降解。因为阻滞因子的核心效果就是让污染物速度变慢在时间项中用R修正速度是工程上常用的简化做法。更严格的做法是在PDE方程里自己写时间导数系数但普通用户没有特殊需求不必这样较真。3.4 网格剖分与求解器的控制网格剖分是污染运移模型成败的分水岭。污染源附近浓度梯度大必须加密远场浓度平缓可以适当放粗。我的经验是源区及下游中心线附近最大单元尺寸取0.5到1米远离源区可以放宽到5米。用自由三角形网格或映射网格都可以但一定要保证在源区附近有足够密集的单元。为什么要加密到这个程度这涉及一个数值稳定性概念——佩克莱数Pe v乘以单元尺寸除以弥散系数。Pe过大对流项就像一辆失控的车数值解会产生振荡浓度场出现波浪状的正负交替。计算一下孔隙流速3.33e-7 m/s纵向弥散系数大约6.66e-7 m2/s若单元尺寸1米Pe约等于0.5非常安全如果单元尺寸拉到10米Pe约5振荡风险就很大。所以在源区和污染羽经过的路径上宁可多花一点计算时间也一定要把网格压到1米以下。时间步长也需要约束。瞬态求解器设置中时间列表可以直接设置0、30、90、180、365、730、1095、1825、3650、5475、7300天或直接用“范围”功能生成时间点。求解器不建议用默认的“自动步长”无限加大建议指定最大步长比如不超过30天。原因同样是数值稳定性Courant数要求流速乘以时间步长除以网格尺寸不能太大30天乘以3.33e-7 m/s约0.86米和1米网格配合得很好。求解器的相对容差用默认的0.01通常够用但污染物运移问题峰值浓度比较尖锐如果结果曲线有毛刺把相对容差调成0.001、绝对容差调成1e-5。4. 结果解读与模型校核4.1 污染羽演化形态分析模型跑完先画出几个时间点的浓度云图。正常结果应该是这样的污染羽从源区伸出逐渐向右边下游方向拉长形状像一个前细后宽又逐渐变窄的舌头。由于横向弥散远小于纵向弥散污染羽宽度不会太夸张中间有一条高浓度的核心线外围是低浓度包裹。看污染羽长度的时候注意不要拿高浓度做标准。风险评估里更关心的是低浓度阈值比如超过0.1 mg/L、1 mg/L这类管理限值的范围。因为苯的毒性效应日本、欧洲饮用水标准往往把苯限值定得比较严实际项目里用的评估阈值需要按当地标准来。在Comsol后处理里可以用“等值线”或“体量”功能提取固定浓度阈值包裹的区域导出它的最大纵向延伸距离和横向宽度。一个有价值的经验是污染羽长度并不等于孔隙流速乘以时间而是会小于这个值因为吸附阻滞和降解同时在拖后腿。按前面的参数十年孔隙流体的对流理论距离是105米但阻滞后污染物平均速度降到6.9 m/yr十年理论迁移距离只有69米再加上降解让外围浓度低于阈值肉眼可见的污染羽可能只有五十几米。这就是为什么不能用手算对流速度直接拍板风险评估范围。4.2 观测点穿透曲线为了量化污染羽到达某个位置的时间在模型里添加几个点或线记录浓度随时间的变化曲线。我习惯在下游30米、60米、100米和150米处各放一个观测点与源区同一垂向深度。穿透曲线的标准长相是浓度从零缓慢上升经过一个较长的时间段到达峰值然后可能缓慢下降或不降。30米处通常上升得最早、峰值最高100米处到达时间明显推迟峰值明显压低。把各观测点的首次检出时间和峰值浓度列一张表就能直接给风险评估提供核心数据。比如污染源持续释放的情况下下游100米处大约在多少年后首次超过某个阈值这对敏感目标的暴露评估非常有意义。如果模型结果里某条穿透曲线出现上升后突然下降再上升这种怪异的波动大概率是数值问题而不是真实物理回到网格和时间步设置里去找原因。4.3 用解析解校核模型数值模型建完必须做校核否则一旦参数或边界设置错了精美的云图也只是漂亮的错误结果。最简单的校核是和一维解析解对比。在一维无限域连续注入、对流弥散吸附降解的条件下Ogata-Banks解可以给出浓度随时间变化的解析结果。做法是单独取模型中心线那条水平剖面把二维结果沿流动方向提取出来与一维解析解公式计算的结果绘制在同一个坐标轴里对比。如果参数正确、边界条件设置合理两条曲线应该在很大范围内重合。误差主要来自横向弥散和模型边界的影响通常控制在10%以内没问题。如果不重合优先检查弥散系数表达式是否漏了流速关联以及源区浓度边界是否插值正确。我一直强调模型校核的意义解析解是一个“照妖镜”能把建模过程中隐藏的参数错误、单位错误、甚至几何错误快速照出来。Comsol里做这种对比很方便画一条一维截线导出数据再用Excel或Python绘图即可完成。5. 常见问题与排查技巧实录5.1 浓度场震荡和不收敛最常见的报错现象是求解器提示“未收敛”或者浓度云图上出现水波纹一样的条纹。原因几乎都指向同一个核心对流项太强而网格或时间步长太粗。我在这个模型里试过把网格从1米加粗到5米时间步长从30天加大到90天结果下游浓度曲线立即出现明显的数值振荡。解决办法分三步网格加密到满足Pe小于2时间步长控制到满足Courant数不大于1然后打开“稳定化”选项。Comsol稀物质传递默认会启用一致稳定化但如果你关闭了建议重新打开。需要注意的是迎风格式的稳定化会引入数值弥散让污染羽被人工抹宽峰值浓度被压低。如果你发现关闭稳定化后结果振荡打开稳定化后结果又太“胖”那真正问题仍然是网格不够密。网格加密永远是第一选择稳定化只是补救手段。5.2 负浓度从哪来污染物浓度本不该为负但Galerkin有限元求解对流扩散方程时浓度梯度陡峭处很容易出现小的负值。这通常发生在污染羽前缘附近那里浓度从10 mg/L突然降到接近于0。后处理阶段可以用if(C0,0,C)这类表达式把负值过滤掉让云图看起来干净但更重要的是找到根源。负浓度严重时说明网格剖分在污染羽前缘不够密或者时间步长太大对流项在一个步长里越过了好几个单元。我的经验是模型结果里只要有肉眼可辨的负浓度先别急着解释“吸附作用导致浓度降低”先去加密网格。网格细化后负值通常会消失或降到可以忽略的程度。5.3 边界反射带来的人为污染堆积边界条件设置不当的另一个典型表现是污染物明明还没有到达模型右边界边界附近的浓度却异常升高。这经常是因为出流边界被设成了“零扩散通量”或者“浓度为零”导致污染物在边界附近堆起来。正确的做法是把下游边界设为“流出”条件它允许污染物只通过对流通量离开模型同时不对扩散通量产生人为约束。另一个稳妥的安全措施是把模型几何画得足够长让污染羽在模拟时间内根本触碰不到下游边界。020年模拟、阻滞后年均速度6.9米理论迁移距离约140米模型总长200米下游留了60米余量这个距离够用。如果你把模拟时间延长到30年最好把模型长度加长到至少250米否则边界影响会污染后段结果。5.4 哪些参数最不能拍脑袋如果只能校准三个参数我选水力梯度、Kd和降解速率。水力梯度直接决定对流速度看似最基础但实际场地里局部梯度往往和区域平均梯度差很远尤其在抽水井或地形起伏明显的地方。Kd决定阻滞因子而不同文献里苯的Kd取值从0.04到几十都有直接导致污染羽速度差一个数量级。降解速率更是如此自然衰减判断的敏感参数现场用微宇宙实验或示踪试验才能比较可靠地确定。三个参数分别代表三种不确定性水力梯度是流场尺度误差Kd是介质吸附特性误差降解速率是生物化学过程误差。在正式报告里建议至少对这三个参数各做高低三个水平工况看关键指标的变化范围。Comsol的“参数扫描”可以一次性把所有组合跑完配合下一节讲到的python控制流水线作业很顺畅。6. 扩展方向批量计算与自动控制6.1 用Python控制Comsol跑参数扫描模型建好后一个不可避免的问题是参数不确定性。最简单的做法是手动改参数、手动跑模型但参数一多这个过程就变得极其痛苦。好消息是通过LiveLink for MATLAB或者开源库MPh可以在外部用脚本控制Comsol完成批量计算。MPh库的基本用法非常简单大致思路是启动Comsol后台加载模型文件修改参数求解再导出结果。一个典型流程是这样import mph client mph.start() model client.load(benzene_transport.mph) model.parameter(Kd, 0.1[L/kg]) model.parameter(lambda_decay, 0.01[1/d]) model.solve() # 这里可以提取观测点数据并写入结果文件这段代码只是示意实际使用前需要安装MPh并确认Comsol版本兼容。批量参数扫描时可以在Python里循环修改不同参数组合每个组合跑完后把观测点穿透曲线数据保存成CSV文件。几十组工况跑下来蒙特卡洛分析的数据基础就有了。热词里提到的“用Matlab控制Comsol”原理和Python类似官方支持更完善如果你手头只有Matlab许可证直接用LiveLink for MATLAB也是一样的效果。6.2 从二维到三维的真实场地延伸二维剖面模型能把基本规律讲清楚但真实场地总是有分层的、有透镜体的、有局部的低渗透区只靠二维很难完整回答所有问题。三维模型并不是多拉一个方向这么简单它意味着地层分层、各向异性渗透率、空间变化的弥散度都要有数据支撑计算量也会明显上升。做三维升级时建议控制变量保持物理场设置不变先把二维模型分别沿着走向和垂向拉伸逐段检查结果是否合理。三维模型的网格建议从粗网格起步逐步加密否则一个稍有规模的场地模型很容易就把电脑内存耗尽。如果有水文地质剖面图可以把地层边界导成CAD曲线再导入Comsol做几何切割这样三维模型至少在地层结构上有实打实的依据。修复方案模拟也是常见的扩展方向。在Darcy定律里加一个抽水井或者把某一小段区域设置成高渗透、高降解的反应墙就能模拟抽出处理或渗透反应墙修复方案。不需要新增太多物理场重点是对源项边界、井流量、反应墙反应速率参数的合理设定。做到这里一个用Comsol复现苯污染地下运移模型的完整流程就落地了。我个人在实际操作中最大的体会是这个模型的难点不在软件操作而在物理概念和参数的把控。苯的吸附参数取错了建模再精细也白搭网格和时间步设置没做好再好的物理模型也输出不了稳定的浓度场。建议你第一次复现时就用默认参数先跑通一个简单版本再逐步加入更复杂的条件。如果你能把解析解校核这一步做到误差10%以内这个模型拿去做风险评估、答辩或者项目汇报说服力都很强。