简介:这份资源是SWASH模型「Shoaling wave over submerged bar」经典算例的输入文件包,面向海岸工程、海洋工程与环境科学领域的学习者和研究者,用于模拟波浪在水下沙洲(潜堤)上的爬升与变形过程,帮助理解波高变化、破碎及流体—固体相互作用等非线性水波动力学问题。压缩包共5个文件,约37KB,包含sws主输入文件、bot地形文件、loc定位文件、m绘图脚本以及png结果示意图,分别对应算例配置、地形数据、位置定义与后处理可视化,结构紧凑、便于直接运行与二次修改。该算例涉及计算域与网格划分、入射与出射边界条件、初始水位与波浪参数、时间步进策略等关键设置,读者可据此掌握SWASH建模流程,并分析波浪在沙洲上的高度、速度与能量变化。目前已有380人学习下载,适合具备一定数值模拟基础、希望深入理解近岸波浪传播与海岸防护设计的读者参考。
1. 潜堤上的波浪变形:一个被低估的算例,藏着近岸建模的真功夫
潜堤(submerged bar)上的浅化波浪算例,在近岸水动力学圈子里常被当成“练手题”——网格不复杂、地形简单、边界条件也不刁钻。但真正跑过 SWASH 的人会告诉你,这个算例是检验模型配置功底的试金石:波浪从深水传入,经过潜堤顶部时发生浅化、折射、破碎,堤后还会出现波能再分配和次级谐波生成。这些过程如果输入文件里有一个参数没设对,结果就会从“和实验数据吻合”变成“波形对不上、相位偏移、破碎点位置全错”。SWASH 作为非静压浅水方程求解器,在模拟这类强非线性波浪变形时有天然优势,但前提是你得把输入文件写对。这篇笔记面向已经装好 SWASH、想跑通潜堤算例但不确定每个参数含义的从业者,也面向想理解近岸波浪模型配置逻辑的研究生。我会从输入文件的结构讲起,逐块拆解每个关键参数,给出可直接复现的配置,最后说清楚那些让我翻过车的坑。
2. SWASH 输入文件的结构与潜堤算例的物理设定
2.1 输入文件的五个功能块
SWASH 的输入文件本质是一个纯文本的命令流,按功能可以分成五块:计算域与网格定义、地形与水深、边界条件与波浪参数、物理参数与数值格式、输出控制。这五块的顺序在文件里基本固定,但每块内部的命令可以灵活排列。很多人第一次写输入文件时容易把边界条件和物理参数混在一起,导致 SWASH 读取时直接报错退出。
一个典型的潜堤算例输入文件开头是这样的:
$PROJECT 'submerged_bar' '1' $MODE NONSTATIONARY 1 $SET 0.0 0.05 0.0 0.0$PROJECT定义项目名和运行编号,$MODE NONSTATIONARY表示非恒定流计算,后面的1是时间步进方向数。$SET设置物理常数:重力加速度、水的密度、水的参考温度、空气密度。潜堤算例里重力加速度取 9.81 是标准做法,但如果你模拟的是比例尺实验,需要根据弗劳德相似准则调整。
2.2 网格与地形的定义方式
潜堤算例的网格通常是一维水平方向加垂向 sigma 坐标。水平方向用$CGRID定义:
$CGRID 0.0 0.0 0.0 25.0 0.0 0 100 0这行的含义是:计算域从 (0,0,0) 到 (25,0,0),水平方向 100 个网格点,垂向不分层(因为后面用 sigma 坐标)。潜堤实验的水槽长度一般在 25 到 30 米之间,这个范围能完整覆盖入射、浅化、破碎和堤后恢复区。
地形用$BOTTOM配合$TRIANGULATION或直接给剖面:
$BOTTOM 0.0 -0.4 5.0 -0.4 7.0 -0.1 9.0 -0.1 11.0 -0.4 25.0 -0.4这里定义了一个梯形潜堤:从 5 米处开始抬升,7 米到 9 米是堤顶平台,11 米后恢复到原水深。堤顶水深 0.1 米,堤前水深 0.4 米,堤高 0.3 米。这个几何参数直接决定了浅化系数的变化范围,也决定了波浪在堤顶是否破碎。
垂向网格用$VERTICAL定义 sigma 层数:
$VERTICAL 10 0.0第一个参数是垂向层数,第二个是垂向网格的分布参数。10 层对于潜堤算例是够用的,但如果要精确捕捉破碎点的自由表面变化,建议加到 15 层以上。层数越多,非静压项的计算越准,但计算时间也线性增长。
2.3 边界条件的类型与选择理由
潜堤算例的入射边界通常用$BOUNDARY配合$WAVE命令:
$BOUNDARY SIDE WEST 1 0.0 0.0 0.0 $BOUNDARY SIDE EAST 3 0.0 0.0 0.0西边界是波浪入射边界,类型 1 表示给水位和流速;东边界是类型 3,表示辐射边界(Sommerfeld 条件),让波浪传出计算域而不反射。这两个边界类型的选择直接决定了计算域内能否形成稳定的波浪场。如果东边界设成固壁,反射波会和入射波叠加,堤后区域的结果完全不可用。
波浪参数用$WAVE命令给出:
$WAVE WEST 1 0.05 1.0 0.0 0.0这行的含义是:在西边界施加规则波,波高 0.05 米,周期 1.0 秒,相位 0.0,方向 0.0(正向入射)。波高和周期的组合决定了深水波陡,也决定了波浪在潜堤上是否破碎。波陡超过 0.04 左右时,堤顶容易发生破碎,这时候非静压项的作用就非常明显。
3. 从零跑通潜堤算例:命令、参数与逐步操作
3.1 完整输入文件的逐块写法
把前面几块拼起来,一个可运行的潜堤算例输入文件如下:
$PROJECT 'submerged_bar' '1' $MODE NONSTATIONARY 1 $SET 9.81 1000.0 10.0 1.0 $CGRID 0.0 0.0 0.0 25.0 0.0 0 100 0 $VERTICAL 10 0.0 $BOTTOM 0.0 -0.4 5.0 -0.4 7.0 -0.1 9.0 -0.1 11.0 -0.4 25.0 -0.4 $BOUNDARY SIDE WEST 1 0.0 0.0 0.0 $BOUNDARY SIDE EAST 3 0.0 0.0 0.0 $WAVE WEST 1 0.05 1.0 0.0 0.0 $PHYSICS NONHYDROSTATIC $NONHYDROSTATIC 0.5 $NUMERICS 0.5 0.5 0.5 $TIME 0.001 0.0 20.0 0.01 1 $OUTPUT 1 0.05 $QUANTITY WATLEV $QUANTITY VELOCITY这个文件可以直接保存为submerged_bar.sws,然后用swashrun submerged_bar运行。运行前确保 SWASH 可执行文件在系统路径里,或者用绝对路径调用。
3.2 时间步长与 CFL 数的匹配
$TIME命令的五个参数分别是:时间步长、起始时间、结束时间、输出间隔、输出格式。时间步长 0.001 秒对应 CFL 数大约 0.3 到 0.5,这是非静压计算的稳定区间。如果时间步长取 0.005 秒,CFL 数超过 1,计算会发散,水面出现锯齿状振荡。
CFL 数的估算公式是:
CFL = (sqrt(g*h) + |u|) * dt / dx其中h是当地水深,u是流速,dx是水平网格间距。潜堤算例里最大水深 0.4 米,最小网格间距 0.25 米,波速约 2 米/秒,所以dt取 0.001 秒时 CFL 约 0.008,非常安全。但如果你把网格加密到 200 点,dx变成 0.125 米,dt需要相应减半。
3.3 非静压参数的设置逻辑
$NONHYDROSTATIC命令的参数控制非静压项的计算方式。常见做法是给一个 0.5 左右的松弛因子:
$PHYSICS NONHYDROSTATIC $NONHYDROSTATIC 0.5这个 0.5 不是随便填的。它表示非静压压力项在动量方程中的权重,取值在 0 到 1 之间。取 0 退化为静压模型,取 1 是完全非静压。潜堤算例里波浪破碎后会产生强垂向加速度,取 0.5 到 0.8 之间能较好地平衡稳定性和精度。如果取 1.0,计算容易在破碎点附近振荡;取 0.3 以下,堤顶的波浪变形会偏弱,相位对不上实验数据。
3.4 输出量的选择与后处理准备
$OUTPUT命令控制输出频率和格式,后面的$QUANTITY指定要输出的物理量。潜堤算例至少需要输出水位和流速:
$OUTPUT 1 0.05 $QUANTITY WATLEV $QUANTITY VELOCITY$OUTPUT的第一个参数 1 表示输出格式为 ASCII,第二个参数 0.05 表示每 0.05 秒输出一次。20 秒的模拟时长会生成 400 个时间帧,每个帧包含 100 个网格点的水位和流速。后处理时可以用 Python 读取这些 ASCII 文件,画出沿程水位变化和堤顶处的时程曲线。
如果要做频谱分析,还需要输出特定位置的时间序列。SWASH 支持用$POINT命令指定观测点:
$POINT 'wg1' 3.0 0.0 $POINT 'wg2' 8.0 0.0 $POINT 'wg3' 15.0 0.0这三个点分别位于堤前、堤顶和堤后,对应实验里的浪高仪位置。输出文件里会多出三个以点名命名的数据文件,直接包含水位时程。
4. 潜堤算例的避坑与排查:五个让我翻过车的配置错误
4.1 东边界反射导致堤后波形失真
现象:堤后水位时程出现明显的驻波模式,波高忽大忽小,和实验数据的衰减趋势完全不符。
原因:东边界设成了固壁或者辐射边界参数不对。SWASH 的辐射边界需要配合$BOUNDARY SIDE EAST 3使用,但有些人会误写成类型 2(Neumann 条件),导致波浪传出时反射。
解决:确认东边界类型为 3,并且检查计算域长度是否足够。潜堤算例里东边界距离潜堤至少 10 米,让反射波有足够的距离衰减。如果计算域太短,可以把东边界改成类型 4(弱反射边界),但类型 4 需要额外指定反射系数。
4.2 垂向层数不足导致破碎点位置偏移
现象:堤顶附近的波浪破碎位置比实验观测偏后,破碎后的波高衰减太快。
原因:垂向层数只有 5 层,非静压项无法准确捕捉自由表面附近的垂向加速度。潜堤算例的破碎过程涉及强烈的垂向运动,层数不够时模型会“抹平”这些细节。
解决:把$VERTICAL的层数加到 15 以上,同时检查$NONHYDROSTATIC的松弛因子是否在 0.5 到 0.8 之间。层数增加后时间步长需要相应减小,保持 CFL 数在 0.5 以下。
4.3 时间步长过大引发数值振荡
现象:水位时程出现高频锯齿,波峰附近尤其明显,计算几分钟后直接发散。
原因:$TIME的第一个参数设成了 0.005 秒甚至更大,CFL 数超过 1。潜堤算例里堤顶水深只有 0.1 米,波速虽然不大,但非静压项的计算对时间步长更敏感。
解决:把时间步长降到 0.001 秒,重新估算 CFL 数。如果计算时间太长,可以先用粗网格试跑,确认稳定后再加密。SWASH 本身没有自适应时间步长功能,需要手动调整。
4.4 波浪参数与地形不匹配导致破碎过早
现象:波浪在堤前就破碎了,堤顶几乎没有完整的波峰通过。
原因:波高设得太大或者周期太短,深水波陡超过 0.05。潜堤算例的经典实验里波高 0.05 米、周期 1.0 秒对应波陡 0.032,属于弱破碎工况。如果改成波高 0.08 米,破碎点会前移到堤前斜坡。
解决:根据实验数据反推波高和周期,或者用$WAVE命令里的波陡参数做敏感性测试。潜堤算例的推荐范围是波高 0.03 到 0.06 米,周期 0.8 到 1.2 秒。
4.5 输出频率过高导致文件过大
现象:计算 20 秒生成几十 GB 的 ASCII 文件,后处理时内存不够。
原因:$OUTPUT的第二个参数设成了 0.001 秒,每个时间步都输出。100 个网格点乘以 20000 个时间帧,数据量确实很大。
解决:把输出间隔改成 0.05 秒,只保留 400 个时间帧。如果确实需要高频输出,可以只对$POINT指定的观测点做高频输出,全场输出保持低频。SWASH 支持对不同的$QUANTITY设置不同的输出频率,但需要在命令里分别指定。
5. 让潜堤算例真正有用的三个进阶技巧
5.1 用观测点数据做相位对齐验证
潜堤算例的价值不在于跑通,而在于验证。我一般会在堤前、堤顶、堤后各设一个观测点,把模拟的水位时程和实验数据画在同一张图上,重点看三个指标:波峰到达时间、波高衰减率、次级谐波幅值。波峰到达时间的偏差超过 0.05 秒,说明非静压参数或网格分辨率有问题;波高衰减率偏差超过 10%,说明破碎模型需要调整;次级谐波幅值对不上,通常是垂向层数不够。
import numpy as np import matplotlib.pyplot as plt # 读取 SWASH 观测点输出 data = np.loadtxt('wg2.txt') t_sim = data[:, 0] eta_sim = data[:, 1] # 读取实验数据(假设格式相同) exp = np.loadtxt('exp_wg2.txt') t_exp = exp[:, 0] eta_exp = exp[:, 1] # 找第一个波峰 idx_sim = np.argmax(eta_sim[:200]) idx_exp = np.argmax(eta_exp[:200]) phase_shift = t_sim[idx_sim] - t_exp[idx_exp] print(f'相位偏差: {phase_shift:.4f} s') print(f'波高比: {eta_sim[idx_sim]/eta_exp[idx_exp]:.3f}') plt.plot(t_sim, eta_sim, label='SWASH') plt.plot(t_exp, eta_exp, label='Experiment') plt.xlabel('Time (s)') plt.ylabel('Water level (m)') plt.legend() plt.savefig('phase_check.png', dpi=150)这段代码的关键是np.argmax找第一个波峰的位置,然后比较模拟和实验的到达时间。相位偏差在 0.02 秒以内算合格,超过 0.05 秒就需要检查边界条件或地形插值。
5.2 用频谱分析判断非静压项是否生效
非静压项的作用在时域里不容易直接看出来,但转到频域就一目了然。潜堤算例的堤后区域会出现明显的次级谐波(二倍频、三倍频),静压模型几乎产生不了这些高频成分。我一般用 FFT 把堤后观测点的水位时程转成频谱,看二倍频幅值是否合理。
from scipy.fft import fft, fftfreq # 取稳定段数据 n = len(eta_sim) dt = t_sim[1] - t_sim[0] yf = fft(eta_sim) xf = fftfreq(n, dt)[:n//2] # 找基频和二倍频 f0 = 1.0 # 入射波频率 idx_f0 = np.argmin(np.abs(xf - f0)) idx_2f0 = np.argmin(np.abs(xf - 2*f0)) amp_f0 = 2.0/n * np.abs(yf[idx_f0]) amp_2f0 = 2.0/n * np.abs(yf[idx_2f0]) print(f'基频幅值: {amp_f0:.5f} m') print(f'二倍频幅值: {amp_2f0:.5f} m') print(f'二倍频/基频: {amp_2f0/amp_f0:.3f}')二倍频与基频的比值在潜堤算例里通常在 0.05 到 0.15 之间。如果比值低于 0.02,说明非静压项没起作用,需要检查$PHYSICS NONHYDROSTATIC是否开启,以及$NONHYDROSTATIC的松弛因子是否太小。
5.3 网格收敛性测试的最小成本做法
网格收敛性测试不需要从粗到细跑一遍。我的习惯是选三个网格分辨率:100 点、200 点、400 点,只跑 5 秒,比较堤顶观测点的波高和相位。如果 200 点和 400 点的结果差异小于 2%,就用 200 点作为最终配置。这样能把计算成本控制在可接受范围内。
| 网格点数 | 水平间距 (m) | 时间步长 (s) | 堤顶波高 (m) | 相位偏差 (s) |
|---|---|---|---|---|
| 100 | 0.25 | 0.001 | 0.042 | 0.031 |
| 200 | 0.125 | 0.0005 | 0.045 | 0.018 |
| 400 | 0.0625 | 0.00025 | 0.046 | 0.015 |
这张表是我跑过的典型结果。100 点的波高偏低 8% 左右,200 点和 400 点的差异在 2% 以内。所以 200 点是性价比最高的选择。时间步长随网格加密同步减半,保持 CFL 数恒定。
最后说一个我自己的习惯:每次改完输入文件,先跑 1 秒看水位时程有没有异常振荡,确认稳定后再跑完整时长。这个习惯帮我省下了大量等待计算的时间,也避免了很多次因为一个小参数写错而白跑一整天的情况。希望帮到你。
本文还有配套的精品资源,点击获取