You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MATLAB中实现1D Richards方程的Neumann-Dirichlet上边界切换

一维Richards方程Picard迭代求解中顶部边界条件的MATLAB实现

我在MATLAB中采用全隐式有限差分法(Picard迭代)求解一维混合形式Richards方程,z轴向下为正(z=0为土壤表面)。底部边界(z=80cm)设为恒定负压水头-51cm;顶部边界(z=0cm)为随时间变化的降雨通量q=-P(t),且表面最大允许压头h=20cm。以下是我编写的处理该顶部边界条件的MATLAB代码:

% 1D Integer-order Richards' Equation (Picard Iteration Scheme)
clc;
clear; close all;

L = 80;                % Column length [cm]
T = 816;               % Total time [h]

Ks = 3.2;              % cm/h (Saturated hydraulic conductivity)
alpha_v = 0.076;       % 1/m  (van Genuchten parameter; if using cm throughout, strictly it should be converted to 1/cm)
nv = 1.86;
mv = 1 - 1/nv;
theta_s = 0.320;
theta_r = 0.032;

h_bot = -51;           % cm (Constant pressure head at the bottom boundary)

% Initial water content -> Initial pressure head
theta_init = 0.08;
Se = (theta_init-theta_r)/(theta_s-theta_r);
Psi_init = -( (Se^(-1/mv)-1)^(1/nv) )/alpha_v;  % cm (Negative)

dz = 0.1;              % cm
dt = 0.05;             % h

z = 0:dz:L;
t = 0:dt:T;
M = length(z);
N = length(t);

% Apply upper boundary pulse infiltration (Flux, positive downwards, unit: cm/h)
qTop = zeros(1,N);
q_pulse = 15/0.5;                  % 30 cm/h
events = [0 0.5; 240 240.5; 480 480.5];  % hours
for k = 1:size(events,1)
    qTop(t>=events(k,1) & t<=events(k,2)) = q_pulse;
end

% van Genuchten-Mualem Model
Kfun = @(h) (Ks .* ((1 - (alpha_v * abs(h)).^(nv-1) .* (1 + (alpha_v * abs(h)).^nv).^(-mv)).^2) ./ ...
               (1 + (alpha_v * abs(h)).^nv).^(mv/2));
Cfun = @(h) (theta_s - theta_r) .* alpha_v .* nv .* mv .* ((alpha_v .*abs(h)).^(nv-1)) .* ((1 + ( alpha_v *abs(h)).^nv).^(-mv-1));
Qfun = @(h) (theta_r + (theta_s - theta_r) .* (1 + (alpha_v *abs(h)).^nv).^(-mv));

% Result arrays
h = zeros(M, N);
theta = zeros(M, N);
q = zeros(M, N);

h(:,1) = Psi_init;
theta(:,1) = Qfun(Psi_init);

% Picard parameters
maxIter = 200;
tol = 1e-6;                  
iterate = zeros(N,1);

% Workspace for iterations
KK = zeros(M,1);
CC = zeros(M,1);

% Main time-stepping loop
for n = 1:N-1

    % Previous time step (converged solution)
    h_old = h(:,n);

    % Picard initial guess: use previous time step
    h_it = h_old;

    for it = 1:maxIter

        % Update nonlinear coefficients using current iteration solution (Picard: fix coefficients, solve linear equation for new h)
        for j = 1:M
            if h_it(j) > 0
                KK(j) = Ks;
                CC(j) = 0;
            else
                KK(j) = Kfun(h_it(j));
                CC(j) = Cfun(h_it(j));
            end
        end

        % Assemble tridiagonal linear system B*h_new = d
        B = zeros(M,M);
        d = zeros(M,1);

        % q = -K * (dh/dz + 1)
        h_max = 20;   % Maximum allowable pressure head (ponding depth)
        
        K12 = 0.5*(KK(1)+KK(2));
        qT = qTop(n+1);
        
          
         if qT > 0  % Water is being applied
            if h_it(1) < h_max
                B(1,1) = -1; B(1,2) = 1;
                d(1)   = dz * (qT/max(K12,1e-12) + 1); % [Correction] z is positive downwards, gravity term is -1
            else
                B(1,1) = 1; B(1,2) = 0; 
                d(1)   = h_max; % Ponding limit reached, force constant head
            end
        else       % Water application stopped
            if h_it(1) > 0
                B(1,1) = 1; B(1,2) = 0; 
                d(1)   = 0; % Surface is ponded, let it infiltrate under potential energy, set head to 0
            else
                B(1,1) = -1; B(1,2) = 1;
                d(1)   = dz * (0/max(K12,1e-12) + 1); % No ponding, zero flux boundary (qT=0)
            end
        end


        for j = 2:M-1
            Kjp = 0.5*(KK(j)+KK(j+1));   % K_{j+1/2}
            Kjm = 0.5*(KK(j)+KK(j-1));   % K_{j-1/2}

            B(j,j-1) = -(dt/(dz^2))*Kjm;
            B(j,j)   =  CC(j) + (dt/(dz^2))*(Kjm + Kjp);
            B(j,j+1) = -(dt/(dz^2))*Kjp;

            d(j) = CC(j)*h_old(j) - (dt/dz)*(Kjp - Kjm);
        end

        % Bottom boundary: Constant head
         B(M, M-1) = 0;
        B(M,M) = 1;
        d(M)   = h_bot;
        h_new = ThomasAlgorithm(B, d);

        % Convergence criterion
        err = max(abs(h_new - h_it));
        h_it = h_new;

        if err < tol
            iterate(n+1) = it;
            break;
        end
    end

    % Save converged solution for the current time step
    h(:,n+1) = h_it;

    % Calculate flux q
    for j = 1:M
        h_j = h(j, n+1);
        if h_j > 0
            K_j = Ks;
        else
            K_j = Kfun(h_j);
        end

        if j == 1
            dh_dz = (h(j+1, n+1) - h_j) / (-dz);
        elseif j == M
            dh_dz = (h_j - h(j-1, n+1)) / (-dz);
        else
            dh_dz = (h(j+1, n+1) - h(j-1, n+1)) / (-2*dz);
        end

        q(j, n+1) = -K_j * (dh_dz + 1);
    end
    
  for j = 1:M
       if h(j,n+1)<0
        theta(j,n+1)=Qfun(h(j,n+1));
       else
        theta(j,n+1)=theta_s;   
       
       end
  end

    fprintf('Picard-Richards: Time step %d / %d, Iterations: %d\n', n, N-1, max(1,iterate(n+1)));
end

% Thomas算法函数
function x = ThomasAlgorithm(A, d)
    % A 是三对角矩阵
    % d 是右端项
    n = length(d);
    
    % 创建向量
    c_prime = zeros(n, 1);
    d_prime = zeros(n, 1);
    
    % 前向消去
    c_prime(1) = A(1,2) / A(1,1);
    d_prime(1) = d(1) / A(1,1);
    
    for i = 2:n-1
        temp = A(i,i) - A(i,i-1) * c_prime(i-1);
        c_prime(i) = A(i,i+1) / temp;
        d_prime(i) = (d(i) - A(i,i-1) * d_prime(i-1)) / temp;
    end
    
    d_prime(n) = (d(n) - A(n,n-1) * d_prime(n-1)) / (A(n,n) - A(n,n-1) * c_prime(n-1));
    
    % 回代
    x = zeros(n, 1);
    x(n) = d_prime(n);
    
    for i = n-1:-1:1
        x(i) = d_prime(i) - c_prime(i) * x(i+1);
    end
end

内容的提问来源于stack exchange,提问作者user32543063

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 10:07:03