【浅水模型MATLAB】尝试完成一个数值模拟竞赛题

【浅水模型MATLAB】尝试完成一个数值模拟竞赛题

  • 前言
  • 题目描述
  • 问题分析
  • 理论基础
    • 控制方程
    • 数值方法
    • 边界条件
  • 代码框架与关键代码
  • 结果展示
  • 写在最后

更新于2024年5月25日

前言

最近看到第四届水科学数值模拟创新大赛的通知,就好奇翻看了前几年的比赛试题。发现去年的一个试题十分有趣,而且实现难度不是很大。因此,想着自己动手,从零开始学一下原理、做一下模型、编一下代码。

由于本人平时用Matlab较多,且Matlab代码可读性较强,容易与数学公式联系。所以,以下代码部分均用的Matlab。
如果你习惯别的代码,也想做类似的建模尝试,十分欢迎一起交流!(最近有点想转python代码了,希望感兴趣的同志来一起交流)
如果各位朋友发现了文章或代码中的错误,亦或是改进之处,请不吝赐教,欢迎大家留言,一起改进模型!本博客文章将持续更新,上面也会标注提出改进建议的同志们。(不过,本人最近在忙活毕业论文,可能更新不及时)

同时,想要完整代码的朋友请联系我,我可无偿提供脚本文件。

希望同大家一起进步!

通知链接:关于公布第三届水科学数值模拟创新大赛复赛试题的通知
题目链接:河道水动力模拟(青年组).pdf

题目描述

某浅水湖泊承担着涵养水源、净化环境、调节径流、维护区域生物多样性等多种重要的水安全保障功能。由于该湖泊地处平原地带,湖体局部水动力条件微弱,需通过有限的外调水量增强湖泊整体水动力,实现活水提质。
研究湖泊为矩形平底浅水湖泊,长L = 10km,宽 W = 5km,糙率为n = 0.02(Manning系数);该湖泊通过3个入口与1个出口与外部河道连通,入口及出口口门宽均为100m;3个入口总入湖流量为 100m3/s,出口水位为2.0m;多年监测数据表明,该湖泊东北区约占整个湖体 1/4 面积大小的区域(下图阴影区域)水动力偏弱,需通过调控入口流量增强该区水动力。
在这里插入图片描述

问题分析

根据题目描述,我们可以设计一个二维浅水方程模型(垂向平均水动力方程)。涉及到的边界条件包括入流边界条件、水位边界条件。
其次,模型的计算域是一个简单的矩形。因此,我们可以采用结构化矩形网格和笛卡尔坐标系。同时,这样的处理方式简化了建模过程。
此外,计算区域中没有浅滩,所有的区域水深都大于0,即没有干-湿边界的问题。这也简化了问题本身,简化了建模过程。

设计模型的思路如下:

  1. 设计一个二维浅水方程的求解器,通过一个简单的溃坝算例测试其性能(也可以从一维浅水方程求解器开始,这样更为简单);
  2. 尝试加入两种边界条件,使其正常运行;
  3. 根据上图要求,完成整个模型。

本博文内容就省略前面两个步骤了,直接描述如何构建整个模型。但是,我也确实进行了前两个步骤,我认为对于模型开发而言,前两个步骤是十分必要的。

理论基础

在原理上,我参考了Liang等1的数值模拟研究。他们的模型采用了有限体积法,以Godunov型方法为框架,求解了适应复杂地形并保持良好平衡特性的二维浅水方程。

控制方程

矩阵形式的浅水方程如下:
∂ U ∂ t + ∂ E ( U ) ∂ x + ∂ G ( U ) ∂ y = S ( U ) U = ( h h u h v ) , E ( U ) = ( h u h u 2 + g h 2 2 h u v ) , G ( U ) = ( h v h u v h v 2 + g h 2 2 ) , S ( U ) = ( 0 − τ b x ρ − g h ∂ z b ∂ x − τ b y ρ − g h ∂ z b ∂ y ) \dfrac{\partial \bold{U}}{\partial t} + \dfrac{\partial \bold{E(U)}}{\partial x} + \dfrac{\partial \bold{G(U)}}{\partial y} = \bold{S(U)} \\[6pt] \bold{U} = \left( \begin{matrix} h \\ hu \\ hv \end{matrix} \right), \bold{E(U)} = \left( \begin{matrix} hu \\ hu^2+\dfrac{gh^2}{2} \\ huv \end{matrix} \right), \bold{G(U)} = \left( \begin{matrix} hv \\ huv \\ hv^2+\dfrac{gh^2}{2} \end{matrix} \right), \\[6pt] \bold{S(U)} = \left( \begin{matrix} 0 \\ -\dfrac{\tau_{bx}}{\rho}-gh\dfrac{\partial z_b}{\partial x} \\ -\dfrac{\tau_{by}}{\rho}-gh\dfrac{\partial z_b}{\partial y} \end{matrix} \right) tU+xE(U)+yG(U)=S(U)U= hhuhv ,E(U)= huhu2+2gh2huv ,G(U)= hvhuvhv2+2gh2 ,S(U)= 0ρτbxghxzbρτbyghyzb
式中, h h h表示水深, η η η表示水位, u u u v v v分别表示两个方向的水平流速, z b z_b zb表示底高程, ρ \rho ρ表示水体密度;切应力 τ \tau τ的表达式:
τ b x = ρ C f u u 2 + v 2 τ b y = ρ C f v u 2 + v 2 C f = g n 2 h 1 / 3 \tau_{bx}=\rho C_f u \sqrt{u^2 + v^2} \\[6pt] \tau_{by}=\rho C_f v \sqrt{u^2 + v^2} \\[6pt] C_f = gn^2 h^{1/3} τbx=ρCfuu2+v2 τby=ρCfvu2+v2 Cf=gn2h1/3
式中,n表示Manning系数。水位η、水深h及水底高程zb的相对关系是:
η = h + z b \eta = h + z_b η=h+zb

由于传统的Godunov型有限体积法不能保证水体在静止状态时压力与底坡源项的平衡,即会在静水条件下产生虚假流动。因此,Liang等改进了上述方程,得到了如下的平衡形式:
U = ( η h u h v ) , E ( U ) = ( h u h u 2 + 1 2 g ( η 2 − 2 η z b ) h u v ) , G ( U ) = ( h v h u v h v 2 + 1 2 g ( η 2 − 2 η z b ) ) , S ( U ) = ( 0 − τ b x ρ − g η ∂ z b ∂ x − τ b y ρ − g η ∂ z b ∂ y ) \bold{U} = \left( \begin{matrix} η \\ hu \\ hv \end{matrix} \right), \bold{E(U)} = \left( \begin{matrix} hu \\ hu^2+\dfrac{1}{2}g(\eta^2-2\eta z_b) \\ huv \end{matrix} \right), \\[6pt] \bold{G(U)} = \left( \begin{matrix} hv \\ huv \\ hv^2+\dfrac{1}{2}g(\eta^2-2\eta z_b) \end{matrix} \right), \bold{S(U)} = \left( \begin{matrix} 0 \\ -\dfrac{\tau_{bx}}{\rho}-g\eta\dfrac{\partial z_b}{\partial x} \\ -\dfrac{\tau_{by}}{\rho}-g\eta\dfrac{\partial z_b}{\partial y} \end{matrix} \right) U= ηhuhv ,E(U)= huhu2+21g(η22ηzb)huv ,G(U)= hvhuvhv2+21g(η22ηzb) ,S(U)= 0ρτbxgηxzbρτbygηyzb
上述这个方程组就是我们的模型的基础!

数值方法

首先,我们将u、v、h等物理量定义在网格的中心。从左至右,网格的编号依次为i = 1,2,3, …, M;从下至上,网格的编号依次为j = 1,2,3, …, N。因此,网格中心的坐标写作 x i , j x_{i,j} xi,j y i , j y_{i,j} yi,j,网格大小可写作 Δ x i = x i + 1 / 2 − x i − 1 / 2 \Delta x_{i} = x_{i+1/2} - x_{i-1/2} Δxi=xi+1/2xi1/2 y j = y j + 1 / 2 − y j − 1 / 2 y_{j}=y_{j+1/2} - y_{j-1/2} yj=yj+1/2yj1/2
在时间域上,模型采用二阶龙格库塔格式。已知n时间步的水力变量 U n \bold{U}^n Un,则下一时间步的 U n + 1 \bold{U}^{n+1} Un+1为:
U ( 1 ) − U n Δ t = − ( ∂ F ∂ x + ∂ G ∂ y ) n + S n U ( 2 ) − U ( 1 ) Δ t = − ( ∂ F ∂ x + ∂ G ∂ y ) ( 1 ) + S ( 1 ) U n + 1 = 1 2 ( U n + U ( 2 ) ) \dfrac{\bold{U}^{(1)}-\bold{U}^{n}}{\Delta t} = -(\dfrac{\partial \bold{F}}{\partial x}+ \dfrac{\partial \bold{G}}{\partial y})^n+\bold{S}^n \\[6pt] \dfrac{\bold{U}^{(2)}-\bold{U}^{(1)}}{\Delta t}= -(\dfrac{\partial \bold{F}}{\partial x}+ \dfrac{\partial \bold{G}}{\partial y})^{(1)}+\bold{S}^{(1)} \\[6pt] \bold{U}^{n+1} = \dfrac{1}{2}(\bold{U}^{n}+\bold{U}^{(2)}) ΔtU(1)Un=(xF+yG)n+SnΔtU(2)U(1)=(xF+yG)(1)+S(1)Un+1=21(Un+U(2))
式中的 Δ t \Delta t Δt表示时间步长,它是通过CFL条件来确定的;每一次时间步进时, Δ t \Delta t Δt的计算过程如下:
Δ t = C m i n ( Δ t x , Δ t y ) Δ t x = m i n [ Δ x i ∣ u i ∣ + g h i ] Δ t y = m i n [ Δ y j ∣ v j ∣ + g h j ] \Delta t=C min(\Delta t_x, \Delta t_y) \\[6pt] \Delta t_x = min[\dfrac{\Delta x_i}{|u_i|+\sqrt{gh_i}}] \\[6pt] \Delta t_y = min[\dfrac{\Delta y_j}{|v_j|+\sqrt{gh_j}}] Δt=Cmin(Δtx,Δty)Δtx=min[ui+ghi Δxi]Δty=min[vj+ghj Δyj]
式中,C表示Courant数字;数值计算稳定的必要条件是C<1.0。一般的,C取0.5~0.75。对于时间步进式中的通量导数项,它的离散形式如下:
∂ F ∂ x = F i + 1 / 2 , j − F i − 1 / 2 , j Δ x ∂ G ∂ y = G i , j + 1 / 2 − G i , j − 1 / 2 Δ y \dfrac{\partial \bold{F}}{\partial x} = \dfrac{\bold{F}_{i+1/2,j} - \bold{F}_{i-1/2,j}}{\Delta x} \\[6pt] \dfrac{\partial \bold{G}}{\partial y} = \dfrac{\bold{G}_{i,j+1/2} - \bold{G}_{i,j-1/2}}{\Delta y} xF=ΔxFi+1/2,jFi1/2,jyG=ΔyGi,j+1/2Gi,j1/2
在求解网格边界(i+1/2, j)和(i, j+1/2)处的通量时,需要通过一个局部黎曼问题的求解器,以确定网格边界处的通量F和G。在此,我们选择HLL求解这个局部黎曼问题。对于网格边界处的水位、水深、流速等物理量的值,我们则通过分段线性重构的方式得到。

分段线性重构可以得到一个边界左右(或上下)两侧的物理量值。分段线性重构的数学表达式如下:
U i + 1 / 2 , j L = U i , j + Δ x i 2 L i m ( U i , j − U i − 1 , j x i − x i − 1 , U i + 1 , j − U i , j x i + 1 − x i ) U i + 1 / 2 , j R = U i + 1 , j − Δ x i + 1 2 L i m ( U i + 1 , j − U i , j x i + 1 − x i , U i + 2 , j − U i + 1 , j x i + 2 − x i + 1 ) U i , j + 1 / 2 L = U i , j + Δ y j 2 L i m ( U i , j − U i , j − 1 y j − y j − 1 , U i , j + 1 − U i , j y j + 1 − y j ) U i , j + 1 / 2 R = U i , j + 1 − Δ y j + 1 2 L i m ( U i , j + 1 − U i , j y j + 1 − y j + 1 , U i , j + 2 − U i , j + 1 y j + 2 − y j + 1 ) U_{i+1/2,j}^L = U_{i,j} + \dfrac{\Delta x_{i}}{2}Lim(\dfrac{U_{i,j}-U_{i-1,j}}{x_{i}-x_{i-1}},\dfrac{U_{i+1,j}-U_{i,j}}{x_{i+1}-x_{i}})\\[6pt] U_{i+1/2,j}^R = U_{i+1,j} - \dfrac{\Delta x_{i+1}}{2}Lim(\dfrac{U_{i+1,j}-U_{i,j}}{x_{i+1}-x_{i}},\dfrac{U_{i+2,j}-U_{i+1,j}}{x_{i+2}-x_{i+1}})\\[6pt] U_{i,j+1/2}^L = U_{i,j} + \dfrac{\Delta y_{j}}{2}Lim(\dfrac{U_{i,j}-U_{i,j-1}}{y_{j}-y_{j-1}},\dfrac{U_{i,j+1}-U_{i,j}}{y_{j+1}-y_{j}})\\[6pt] U_{i,j+1/2}^R = U_{i,j+1} - \dfrac{\Delta y_{j+1}}{2}Lim(\dfrac{U_{i,j+1}-U_{i,j}}{y_{j+1}-y_{j+1}},\dfrac{U_{i,j+2}-U_{i,j+1}}{y_{j+2}-y_{j+1}}) Ui+1/2,jL=Ui,j+2ΔxiLim(xixi1Ui,jUi1,j,xi+1xiUi+1,jUi,j)Ui+1/2,jR=Ui+1,j2Δxi+1Lim(xi+1xiUi+1,jUi,j,xi+2xi+1Ui+2,jUi+1,j)Ui,j+1/2L=Ui,j+2ΔyjLim(yjyj1Ui,jUi,j1,yj+1yjUi,j+1Ui,j)Ui,j+1/2R=Ui,j+12Δyj+1Lim(yj+1yj+1Ui,j+1Ui,j,yj+2yj+1Ui,j+2Ui,j+1)
式中的U可以表示水位、水深、流速等任一物理量,Lim则表示斜率限制器。为了保持数值稳定,本模型采用了minmod限制器:
m i n m o d ( a , b ) = { 0 , a b ≤ 0 m i n ( ∣ a ∣ , ∣ b ∣ ) , a b > 0 minmod(a,b)= \begin{cases} 0,\quad& ab \leq0 \\ min(|a|,|b|),\quad& ab>0 \end{cases} minmod(a,b)={0,min(a,b),ab0ab>0

在通过斜率限制器进行分段线性重构后,得到了网格边界的水位、水深、流速,也计算出了网格边界处的通量FL、FR、GL和GR。之后通过HLL求解器得到网格边界处的F和G。下面以x方向为例,列出HLL求解器的表达式:
F = { F L , s L ≥ 0 F ∗ , s L < 0 < s R F R , s R ≤ 0 F ∗ = s R F L − s L F R + s L s R ( U R − U L ) s R − s L s L = m i n ( u L − g h L , u s − g h s ) s R = m i n ( u R + g h R , u s + g h s ) u s = 1 2 ( u L + u R ) + g h L − g h R g h s = g h L + g h R 2 + u L + u R 4 \bold{F} = \begin{cases} \bold{F}_L,\quad& s_L \geq 0 \\ \bold{F}^*,\quad& s_L <0<s_R\\ \bold{F}_R,\quad& s_R \leq 0 \end{cases} \\[6pt] \bold{F}^* = \dfrac{s_R\bold{F}_L-s_L\bold{F}_R + s_L s_R(\bold{U}_R-\bold{U}_L)}{s_R-s_L}\\[6pt] s_L = min(u_L-\sqrt{gh_L},u_s-\sqrt{gh_s})\\[6pt] s_R = min(u_R+\sqrt{gh_R},u_s+\sqrt{gh_s})\\[6pt] u_s = \dfrac{1}{2} (u_L + u_R)+\sqrt{gh_L}-\sqrt{gh_R}\\[6pt] \sqrt{gh_s} = \dfrac{\sqrt{gh_L}+\sqrt{gh_R}}{2} + \dfrac{u_L+u_R}{4} F= FL,F,FR,sL0sL<0<sRsR0F=sRsLsRFLsLFR+sLsR(URUL)sL=min(uLghL ,usghs )sR=min(uR+ghR ,us+ghs )us=21(uL+uR)+ghL ghR ghs =2ghL +ghR +4uL+uR

边界条件

本模型涉及了三边界条件,一是入流边界,二是水位边界,三是固壁边界(采用free-slip边界)。这两个边界的在《【CFD小工坊】浅水模型的边界条件》中有介绍。
我们以右侧边界M+1/2为例,此网格左侧水深hL、法向流速uL,以及右侧水深h* 、法向流速u*满足:
u L + 2 c L = u ∗ + 2 c ∗ c L = g h L , c ∗ = g h ∗ u_L+2c_L = u^* + 2c^*\\[6pt] c_L = \sqrt{gh_L},c^* = \sqrt{gh^*} uL+2cL=u+2ccL=ghL ,c=gh
当采用流量边界时,右侧网格的单宽流量q被指定,即 q = h ∗ u ∗ q=h^*u^* q=hu已知,则有:
u L + 2 c L = u ∗ + 2 c ∗ = q h ∗ + 2 g h ∗ = q c ∗ 2 / g + 2 g h ∗ u_L+2c_L = u^* + 2c^* = \dfrac{q}{h^*} + 2\sqrt{gh^*} = \dfrac{q}{{c^*}^2/g} + 2\sqrt{gh^*} uL+2cL=u+2c=hq+2gh =c2/gq+2gh
化简后,上述方程为 c ∗ c^* c的一元三次方程:
2 c ∗ 3 − ( u L + 2 g h L ) c ∗ 2 + g q = 0 2{c^*}^3 - (u_L + 2\sqrt{gh_L}){c^*}^2 + gq = 0 2c3(uL+2ghL )c2+gq=0
求出方程c^*后,所有的物理量都能被指定。

对于水位边界,边界处的h*被指定,则有
u ∗ = u L ∗ + 2 c L − 2 c ∗ = u L ∗ + 2 g h L − 2 g h ∗ u^* = u_L^*+2c_L - 2c^*=u_L^*+ 2\sqrt{gh_L} -2\sqrt{gh^*} u=uL+2cL2c=uL+2ghL 2gh

对于固壁边界,法向速度和通量被定义为0。在求解过程中,可设置h* = hL

代码框架与关键代码

我的模型代码主要分为五个部分:

  1. 参数设置:设置物理参数、网格参数、时间参数等。代码如下所示:
grav = 9.81;            % Gravitational acceleration
rho = 1000;             % Density
CFL = 0.5;              % Courant Number

Lx = 10000;             % Length of the domain
Ly = 5000;              % Width of the domain
n = 0.02;               % Manning coefficient

zb0 = 0.0;              % Bottom elevation
eta0 = 2.0;             % Initial water elevation
h0 = 2.0;               % Initial water depth

dx = 25;                % Grid spacing
dy = 25;                % Grid spacing
dt = 0.2;               % Time spacing at the first step
dtmax = 4.0;            % allowed max time step (s)
tend = 3600;            % End of the simulation time
plot_int = 60;          % Time interval to next plot

Q_in = 100;             % Total discharge of the inlets
eta_out = 2.0;          % Specified water level of the outlet

我设置网格为边长25m的正方形,底高程为zb0=0.0,初始水位与出口水位一致,即eta0 = 2.0。Courant数设置为0.5,初始时间步为0.2s,之后的每一个时间步通过CFL条件计算得到。

  1. 网格构建:网格有两个要素需要定义,一是网格的四个节点(Xp和Yp),二是网格的中心点(Xc和Yc);网格中心点也即水力物理量定义的位置。
%% Construct the grid
Nx = Lx/dx;     Ny = Ly/dy;
xp = [0:dx:Lx];         % Points
yp = [0:dy:Ly];
xc = [0.5:dx:Lx];       % Cell centers
yc = [0.5:dy:Ly];
[Xp Yp] = meshgrid(xp, yp);
[Xc Yc] = meshgrid(xc, yc);
  1. 初始化:设置底高程zb,计算zb的梯度zbx和zby;之后再设置初始流速u、v为零。
%% Initialization
zbc = zb0 * ones(Ny,Nx);
zbp = zb0 * ones(Ny+1,Nx+1);

zbx = (0.5*(zbp(1:end-1,2:end)+zbp(2:end,2:end)) - ...
       0.5*(zbp(1:end-1,1:end-1)+zbp(2:end,1:end-1)) ) /dx;
zby = (0.5*(zbp(2:end,1:end-1)+zbp(2:end,2:end)) - ...
       0.5*(zbp(1:end-1,1:end-1)+zbp(1:end-1,2:end)) ) /dy;

eta = eta0 * ones(Ny,Nx);
h = eta - zbc;
u = zeros(Ny,Nx);       v = zeros(Ny,Nx);
  1. 主循环:(1)计算网格边界处的水位、水深、流速值;(2)设置边界条件;(3)计算通量项FL、FR、GL和GR;(4)利用HLL求解通量F和G;(5)计算源项S;(6)计算新一个时间步的eta、h、u和v。
%% Main Loop
t = 0;
tplot = 0;
while(t<tend)
    % estimate the dt
    dtx = dx./(abs(u)+sqrt(grav*h) + 1E-8);
    dty = dy./(abs(v)+sqrt(grav*h) + 1E-8);
    dt1 = min(min(dtx,[],"all"), min(dty,[],"all"));
    dt = min(dtmax, CFL*dt1);
    clear dt1 dtx dty
    
    etan = eta;     hn = h;
    un = u;         vn = v;
    % 2rd-order Runge-Kutta Method
    for k = 1:2
        % 1. reconstruct the flow data
        % 1.1 x-direction reconstruction (Natural closed boundary)
        e_ = [eta(:,1), eta, eta(:,end)];
        u_ = [u(:,1), u, u(:,end)];
        v_ = [v(:,1), v, v(:,end)];
        de = minmod((e_(:,3:end)-e_(:,2:end-1))/dx, ...
                    (e_(:,2:end-1)-e_(:,1:end-2))/dx);
        du = minmod((u_(:,3:end)-u_(:,2:end-1))/dx, ...
                    (u_(:,2:end-1)-u_(:,1:end-2))/dx);
        dv = minmod((v_(:,3:end)-v_(:,2:end-1))/dx, ...
                    (v_(:,2:end-1)-v_(:,1:end-2))/dx);
        exL = [eta(:,1), eta+0.5*dx*de];
        exR = [eta-0.5*dx*de, eta(:,end)];
        hxL = exL - 0.5*(zbp(1:end-1,:) + zbp(2:end,:));
        hxR = exR - 0.5*(zbp(1:end-1,:) + zbp(2:end,:));
        uxL = [u(:,1), u+0.5*dx*du];
        uxR = [u-0.5*dx*du, u(:,end)];
        vxL = [v(:,1), v+0.5*dx*dv];
        vxR = [v-0.5*dx*dv, v(:,end)];
        clear e_ u_ v_ de du dv
        % 1.2 y-direction reconstruction (Natural closed boundary)
        e_ = [eta(1,:); eta; eta(end,:)];
        u_ = [u(1,:); u; u(end,:)];
        v_ = [v(1,:); v; v(end,:)];
        de = minmod((e_(3:end,:)-e_(2:end-1,:))/dy, ...
                    (e_(2:end-1,:)-e_(1:end-2,:))/dy);
        du = minmod((u_(3:end,:)-u_(2:end-1,:))/dy, ...
                    (u_(2:end-1,:)-u_(1:end-2,:))/dy);
        dv = minmod((v_(3:end,:)-v_(2:end-1,:))/dy, ...
                    (v_(2:end-1,:)-v_(1:end-2,:))/dy);
        eyL = [eta(1,:); eta+0.5*dy*de];
        eyR = [eta-0.5*dy*de; eta(end,:)];
        hyL = eyL - 0.5*(zbp(:,1:end-1) + zbp(:,2:end));
        hyR = eyR - 0.5*(zbp(:,1:end-1) + zbp(:,2:end));
        uyL = [u(1,:); u+0.5*dy*du];
        uyR = [u-0.5*dy*de; u(end,:)];
        vyL = [v(1,:); v+0.5*dy*dv];
        vyR = [v-0.5*dy*dv; v(end,:)];
        clear e_ u_ v_ de du dv

        % 2. boundary conditions
        q = Q_in/100;
        % 2.1. west boundary (inflow)
        ff = find((yc>2450).*(yc<2550));
        for j = ff
            c_s = Equ3Iter(2.0, -uxR(j,1)-2*sqrt(grav*hxR(j,1)), 0, grav*q, ...
                           sqrt(grav*hxR(j,1)));
            h_s = c_s.^2/grav;      u_s = q/h_s;
            hxL(j,1) = h_s;         uxL(j,1) = u_s;
            exL(j,1) = h_s + 0.5*(zbp(j,1)+zbp(j+1,1));
            vxL(j,1) = 0.0;
        end
        % 2.2. east boundary (outflow)
        ff = find((yc>1450).*(yc<1550));
        for j = ff
            h_s = eta_out - 0.5*(zbp(j,end)+zbp(j+1,end));
            u_s = uxL(j,end) + 2*sqrt(grav*hxL(j,end)) - 2*sqrt(grav*h_s);
            hxR(j,end) = h_s;         uxR(j,end) = u_s;
            exR(j,end) = h_s + 0.5*(zbp(j,end)+zbp(j+1,end));
            vxR(j,end) = 0.0;
        end
        % 2.3. south boundary (inflow)
        ff = find((xc>1950).*(xc<2050));
        for i = ff
            c_s = Equ3Iter(2.0, -vyR(1,i)-2*sqrt(grav*hyR(1,i)), 0, grav*q, ...
                           sqrt(grav*hyR(1,i)));
            h_s = c_s.^2/grav;      u_s = q/h_s;
            hyL(1,i) = h_s;         vyL(1,i) = u_s;
            eyL(1,i) = h_s + 0.5*(zbp(1,i)+zbp(1,i+1));
            uyL(1,i) = 0.0;
        end
        % 2.4. north boundary (inflow)
        ff = find((xc>3950).*(xc<4050));
        for i = ff
            c_s = Equ3Iter(2.0, -vyL(end,i)-2*sqrt(grav*hyL(end,i)), 0, -grav*q, ...
                           sqrt(grav*hyL(end,i)));
            h_s = c_s.^2/grav;      u_s = q/h_s;
            hyR(end,i) = h_s;     	vyR(end,i) = -u_s;
            eyR(end,i) = h_s + 0.5*(zbp(end,i)+zbp(end,i+1));
            uyR(end,i) = 0.0;
        end

        clear u_s h_s ff j i
        % 3. flux terms (F and G)
        F1L = hxL.*uxL;
        F2L = hxL.*uxL.*uxL + 0.5*grav*(exL.*exL - ...
              exL.*(zbp(1:end-1,:)+zbp(2:end,:)));
        F3L = hxL.*uxL.*vxL;
        F1R = hxR.*uxR;
        F2R = hxR.*uxR.*uxR + 0.5*grav*(exR.*exR - ...
              exR.*(zbp(1:end-1,:)+zbp(2:end,:)));
        F3R = hxR.*uxR.*vxR;

        G1L = hyL.*vyL;
        G2L = hyL.*uyL.*vyL;
        G3L = hyL.*vyL.*vyL + 0.5*grav*(eyL.*eyL - ...
              eyL.*(zbp(:,1:end-1)+zbp(:,2:end)));
        G1R = hyR.*vyR;
        G2R = hyR.*uyR.*vyR;
        G3R = hyR.*vyR.*vyR + 0.5*grav*(eyR.*eyR - ...
              eyR.*(zbp(:,1:end-1)+zbp(:,2:end)));

        % 4. calculate the flux by HLL
        [sxL sxR] = WaveSpeed(hxL, hxR, uxL, uxR);
        F1 = HLLSolver(F1L, F1R, sxL,sxR, exL,exR);
        F2 = HLLSolver(F2L, F2R, sxL,sxR, hxL.*uxL,hxR.*uxR);
        F3 = HLLSolver(F3L, F3R, sxL,sxR, hxL.*vxL,hxR.*vxR);
        [syL syR] = WaveSpeed(hyL, hyR, vyL, vyR);
        G1 = HLLSolver(G1L, G1R, syL,syR, eyL,eyR);
        G2 = HLLSolver(G2L, G2R, syL,syR, hyL.*uyL,hyR.*uyR);
        G3 = HLLSolver(G3L, G3R, syL,syR, hyL.*vyL,hyR.*vyR);
        clear sxL sxR syL syR F1L F1R F2L F2R F3L F3R G1L G1R G2L G2R G3L G3R
        % 4.1. west boundary
        F1(:,1) = 0;        F3(:,1) = 0;
        F2(:,1) = 0.5*grav*(exR(:,1).^2 - exR(:,1).*(zbp(1:end-1,1)+zbp(2:end,1)));
        %      inflow
        ff = find((yc>2450).*(yc<2550));
        F1(ff,1) = hxL(ff,1).*uxL(ff,1);
        F2(ff,1) = F2(ff,1) + hxL(ff,1).*uxL(ff,1).*uxL(ff,1);
        F3(ff,1) = hxL(ff,1).*uxL(ff,1).*vxL(ff,1);
        % 4.2. east boundary
        F1(:,end) = 0;   	F3(:,end) = 0;
        F2(:,end) = 0.5*grav*(exL(:,end).^2 - exL(:,end).*(zbp(1:end-1,end)+zbp(2:end,end)));
        %      outflow
        ff = find((yc>1450).*(yc<1550));
        F1(ff,end) = hxR(ff,end).*uxR(ff,end);
        F2(ff,end) = F2(ff,end) + hxR(ff,end).*uxR(ff,end).*uxR(ff,end);
        F3(ff,end) = hxR(ff,end).*uxR(ff,end).*vxR(ff,end);
        % 4.3. south boundary
        G1(1,:) = 0;        G2(1,:) = 0;
        G3(1,:) = 0.5*grav*(eyR(1,:).^2 - eyR(1,:).*(zbp(1,1:end-1)+zbp(1,2:end)));
        %      inflow
        ff = find((xc>1950).*(xc<2050));
        G1(1,ff) = hyL(1,ff).*vyL(1,ff);
        G2(1,ff) = hyL(1,ff).*uyL(1,ff).*vyL(1,ff);
        G3(1,ff) = G3(1,ff) + hyL(1,ff).*vyL(1,ff).*vyL(1,ff);
        % 4.4. north boundary
        G1(end,:) = 0;      G2(end,:) = 0;
        G3(end,:) = 0.5*grav*(eyL(end,:).^2 - eyL(end,:).*(zbp(end,1:end-1)+zbp(end,2:end)));
        %      inflow
        ff = find((xc>3950).*(xc<4050));
	    G1(end,ff) = hyR(end,ff).*vyR(end,ff);
        G2(end,ff) = hyR(end,ff).*uyR(end,ff).*vyR(end,ff);
        G3(end,ff) = G3(end,ff) + hyR(end,ff).*vyR(end,ff).*vyR(end,ff);
        
        clear ff exL exR eyL eyR hxL hxR hyL hyR uxL uxR uyL uyR vxL vxR vyL vyR
        % 5. source terms
        Cf = grav * n.^2 .* h.^(-1/3);
        tau_x = rho*Cf.* u .*sqrt(u.*u + v.*v);
        tau_y = rho*Cf.* v .*sqrt(u.*u + v.*v);
        S1 = zeros(Ny,Nx);
        S2 = -tau_x/rho - grav*eta.*zbx;
        S3 = -tau_y/rho - grav*eta.*zby;

        % 6. time step
        % 6.1 solve eta
        eta = eta - dt/dx*(F1(:,2:end)-F1(:,1:end-1)) ...
                  - dt/dy*(G1(2:end,:)-G1(1:end-1,:)) + dt*S1;
        % 6.2 solve h*u
        hu = h.*u - dt/dx*(F2(:,2:end)-F2(:,1:end-1)) ...
                  - dt/dy*(G2(2:end,:)-G2(1:end-1,:)) + dt*S2;
        % 6.3 solve h*v
        hv = h.*v - dt/dx*(F3(:,2:end)-F3(:,1:end-1)) ...
                  - dt/dy*(G3(2:end,:)-G3(1:end-1,:)) + dt*S3;

        h = eta - zbc;
        u = hu./h;
        v = hv./h;
        clear hu hv k
    end
    
    t = t+dt;
    eta = 0.5*(eta + etan);
    h = eta - zbc;
    u = 0.5*(u + un);
    v = 0.5*(v + vn);
    clear etan hn un vn
    
    % 7. plot
    disp(['T = ' num2str(t)  's now.']);
    if (t >= plot_int*tplot)
        figure(1)
        set(gcf,'position',[962,42,958,953]);
        subplot(2,1,1)
        axis([0 Lx 0 Ly])
        pcolor(Xc, Yc, eta), shading interp, colormap jet, colorbar, hold on
        % quiver(Xc, Yc, u, v, 'w')
        title(['Water Level (m) @ T = ' num2str(t)  's'])
        set(gca,'FontName','Times New Roman','FontSize',14)

        subplot(2,1,2)
        axis([0 Lx 0 Ly])
        pcolor(Xc, Yc, sqrt(u.*u+v.*v)), shading interp, colormap jet, colorbar, hold on
        quiver(Xc, Yc, u, v, 'w')
        title(['Velocity (m/s) @ T = ' num2str(t)  's'])
        set(gca,'FontName','Times New Roman','FontSize',14)
        tplot = tplot + 1;
    end
end
  1. 其余子函数:包括minmod限制器、HLL求解器、一元三次方程求解器Equ3Iter等。

结果展示

在这里插入图片描述

写在最后

  1. 这个代码可以运行,但是总体上计算的并不快。我不知道是不是matlab编译器本身的原因。如果有用别的代码进行尝试的朋友,可以留言说说你们的计算速度如何。
  2. 实际的入流边界条件远比我考虑的复杂,首先要考虑是临界流还是亚临界流,而本模型默认用亚临界流的入流条件;其次,我将入流边界处的流速设定为均匀分布的,这不一定符合实际,可能用下列公式更好。

流量边界条件:
对于这m条边界上的总流量 Q Q Q,某一网格 i i i边上的单宽流量 q i q_i qi是:
q i = L i ′ h i 1.5 C i ∑ k = 1 m L k ′ h k 1.5 C k Q q_i = \dfrac{L'_i h_i^{1.5}C_i}{\sum^{m}_{k=1} L'_k h_k^{1.5}C_k} Q qi=k=1mLkhk1.5CkLihi1.5CiQ
式中, L ′ L' L表示流量边界对应网格边的边长, h h h表示对应网格的水深, C C C表示对应网格的摩阻力项,有 C = h 1 / 6 n C = \dfrac{h^{1/6}}{n} C=nh1/6,n为曼宁系数。之后根据求出的单宽流量,依次处理每个边界网格的通量值。


  1. Liang Q , Marche F .Numerical resolution of well-balanced shallow water equations with complex source terms[J].Advances in Water Resources, 2009, 32(6):873-884.DOI:10.1016/j.advwatres.2009.02.010. ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/657289.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

信息安全法规和标准

《全国人民代表大会常务委员会关于维护互联网安全的决定》规定&#xff0c;威胁互联网运行安全的行为&#xff1a;&#xff08;1&#xff09;侵入国家事务、国防建设、尖端科学技术领域的计算机信息系统&#xff0c;&#xff08;2&#xff09;故意制作、传播计算机病毒等破坏性…

[ue5]建模场景学习笔记(1)——混合材质

卷首&#xff1a;这部分会记录建模场景等相关学习内容&#xff0c;与ue引擎学习笔记不同的是&#xff0c;可能会略过一些基础内容&#xff0c;因为部分知识在blender中已经学习过了&#xff0c;不再继续记录。 1.需求分析&#xff1a; 想构建一个山地的场景&#xff0c;在ue5中…

在豆包这事上,字节看得很明白

大数据产业创新服务媒体 ——聚焦数据 改变商业 导语&#xff1a; 1.基于豆包的话炉/猫箱APP市场反响一般 2.价格战对于豆包来说是副产物 3.价格战对大模型市场是良性的 4.豆包接下来会推广至国际社会 因为宣称价格比行业便宜99.3%&#xff0c;豆包成功出圈了。根据火山引擎公…

通过安全的云开发环境重新发现 DevOps 的心跳

云开发平台如何“提升” DevOps 首先&#xff0c;我来简单介绍一下什么是云开发环境&#xff1a;它通常运行带有应用程序的 Linux 操作系统&#xff0c;提供预配置的环境&#xff0c;允许进行编码、编译和其他类似于本地环境的操作。从实现的角度来看&#xff0c;这样的环境类…

猫耳 WebSocket 跨端优化实践

前言 在现代的移动应用程序中&#xff0c;长连接是一种不可或缺的能力&#xff0c;包括但不限于推送、实时通信、信令控制等常见场景。在猫耳FM的直播业务中&#xff0c;我们同样使用了 WebSocket 长连接作为我们实时通信的基础。 在我们推进用户体验优化的工作中&#xff0c;…

如何将音频中的人声分离出来?

想要把一段视频中的人声跟背景音乐分离开来&#xff0c;找个好一点的音频处理软件就能把声音分离了&#xff0c;常见的有以下方法&#xff0c;一起来看看吧。 pr 打开软件&#xff0c;然后将电脑上的音频文件&#xff0c;上传到软件中&#xff0c;然后按住[ctrla]选择所有音频…

6-继承

6-继承 1、基本语法和方式2、继承的基本特点2.1 三种继承方式相同的基本点2.2 三种继承方式的差别2.3 公有继承的独有特点 3、子类的构造、析构3.1 子类的构造3.2 子类的析构3.3 子类的拷贝构造函数3.4 子类的拷贝赋值 4、多重继承4.1 内存布局4.2 类型转换4.3 名字冲突问题 5、…

C语言 | Leetcode C语言题解之第117题填充每个节点的下一个右侧节点指针II

题目&#xff1a; 题解&#xff1a; void handle(struct Node **last, struct Node **p, struct Node **nextStart) {if (*last) {(*last)->next *p;}if (!(*nextStart)) {*nextStart *p;}*last *p; }struct Node *connect(struct Node *root) {if (!root) {return NULL…

【小呆的力学笔记】连续介质力学的知识点回顾一:运动和变形

文章目录 1. 运动的描述2. 拉格朗日描述下的变形2.1 线元的变化2.2 体元的变化2.3 面元的变化 1. 运动的描述 在连续介质力学中&#xff0c;存在着两种对运动的描述&#xff0c;一种为拉格朗日描述&#xff0c;即通过描述每个物质点的运动来描述整个变形体的运动&#xff0c;也…

解决IDEA菜单栏找不到VCS的问题,且使用IDEA推送新项目到托管仓库

问题描述&#xff1a; 在idea软件中使用git推送项目&#xff0c;idea页面顶部菜单栏无VCS 解决方案&#xff1a; 一&#xff1a;File->Settings->Version Control-> 点击 ->选择项目->VCS:->点击ok&#xff1a; 二&#xff1a;托管平台创建一个Git仓库来保…

基于遗传优化的货柜货物摆放优化问题求解matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于遗传优化的货柜货物摆放优化问题求解matlab仿真。在一个货架上&#xff0c;初始状态下&#xff0c;随机将货物放在货柜上&#xff0c;优化之后&#xff0c;整…

openresty(Nginx) 隐藏 软包名称及版本号 升级版本

1 访问错误或者异常的URL 2 修改配置&#xff0c;重新编译&#xff0c;升级 #修改版本等 vim ./bundle/nginx-1.13.6/src/core/nginx.h #define nginx_version 1013006 #define NGINX_VERSION "1.13.6" #define NGINX_VER "openresty/&q…

玩转STM32-直接存储器DMA(详细-慢工出细活)

文章目录 一、DMA介绍1.1 DMA简介1.2 DMA结构 二、DMA相关寄存器&#xff08;了解&#xff09;三、DMA的工作过程&#xff08;掌握&#xff09;四、DMA应用实例4.1 DMA常用库函数4.2 实例程序 一、DMA介绍 1.1 DMA简介 DMA用来提供外设与外设之间、外设与存储器之间、存储器与…

中国企业出海,哪些业务需要负载均衡?

国内企业出海的进程正在加速。中国的出海企业剑指跨境电商、社交、游戏、短剧等市场&#xff0c;其中尤其以跨境电商的数据最为突出。据官方数据&#xff0c;2023年我国跨境电商进出口总额达到2.38万亿元&#xff0c;比2016年增长近50倍&#xff0c;占货物贸易总规模的5.7%。 …

【Mybatis】映射文件中获取单个参数和多个参数的写法

xml的映射文件中获取接口方法中传来的参数是直接用#{}的方式来获取的 那么接下来&#xff0c;我们就具体来说一下获取参数里边的各种规则和用法 1.单个参数&#xff0c;比如上面的getOneUser&#xff0c;只有一个id值作为参数 Mybatis对于只有一个参数的情况下&#xff0c;不…

机器学习-5-如何进行交叉验证

参考一文带您了解交叉验证(Cross-Validation):数据科学家必须掌握的7种交叉验证技术 参考如何在机器学习中使用交叉验证(实例) 1 交叉验证 1.1 交叉验证的本质 针对中小型数据集常用的一种用于观察模型稳定性的方法——交叉验证。 交叉验证是用来观察模型的稳定性的一种方…

计算机毕业设计hadoop+spark+hive物流大数据分析平台 物流预测系统 物流信息爬虫 物流大数据 机器学习 深度学习

流程&#xff1a; 1.Python爬虫采集物流数据等存入mysql和.csv文件&#xff1b; 2.使用pandasnumpy或者MapReduce对上面的数据集进行数据清洗生成最终上传到hdfs&#xff1b; 3.使用hive数据仓库完成建库建表导入.csv数据集&#xff1b; 4.使用hive之hive_sql进行离线计算&…

基于NAMUR开放式架构(NOA)的工业设备数据采集方案

一 NAMUR开放式架构 传统自动化金字塔结构的优越性在过去许多年里已被证明。然而&#xff0c;传统的自动化金字塔在获取和利用对物联网和工业4.0有价值的数据方面却存在一定挑战。这是因为传统系统通常是封闭的&#xff0c;数据访问受到限制&#xff0c;难以集成到新的数字化解…

eclipse启动时间过长的问题

项目场景&#xff1a; 由于我用eclipse比较习惯&#xff0c;虽然IDEA很好&#xff0c;但是因为收费&#xff0c;所以在个人开发学习过程中一直还是使用eclipse&#xff0c;本文不讨论eclipse与IDEA孰优孰劣问题。 开发环境&#xff1a; 操作系统&#xff1a;Windows 11 22631…

HCIP-Datacom-ARST自选题库__BGP/MPLS IP VPN简答【3道题】

1.在BGP/MPLSIPVPN场景中&#xff0c;如果PE设备收到到达同一目的网络的多条路由时&#xff0c;将按照定的顺序选择最优路由。请将以下内容按照比较顺序进行排序。 2.在如图所示的BGP/MPLSIP VPN网络中&#xff0c;管理员准备通过Hub-Spoke组网实现H站点对VPM流量的集中管控&am…