基于雅克比迭代法的方腔流动 MATLAB 实现

方腔流动(Cavity Flow)模拟程序,使用雅克比迭代法求解流函数-涡量形式的 Navier-Stokes 方程。


一、方腔流动数学模型

1.1 控制方程(流函数-涡量形式)

对于二维不可压缩流动,定义流函数 ψ 和涡量 ω:

∂ω∂t+u⋅∇ω=ν∇2ω \frac{\partial \omega}{\partial t} + \mathbf{u} \cdot \nabla \omega = \nu \nabla^2 \omega ∂t∂ω+u⋅∇ω=ν∇2ω

∇2ψ=−ω \nabla^2 \psi = -\omega ∇2ψ=−ω

其中速度分量:

u=∂ψ∂y,v=−∂ψ∂x u = \frac{\partial \psi}{\partial y}, \quad v = -\frac{\partial \psi}{\partial x} u=∂y∂ψ,v=−∂x∂ψ

1.2 边界条件

方腔尺寸:x ∈ 0, 1, y ∈ 0, 1

  • 顶盖:u = 1, v = 0 (y=1)
  • 其他壁面:u = v = 0
  • 流函数在壁面为 0
  • 涡量边界条件由流函数导出

二、完整 MATLAB 实现

2.1 主程序 (cavity_flow_jacobi.m)

matlab 复制代码
%% 基于雅克比迭代法的方腔流动模拟
clear; clc; close all;

fprintf('=== 方腔流动模拟(雅克比迭代法)===\n\n');

%% 1. 参数设置
params = struct();
params.Nx = 51;           % x方向网格数
params.Ny = 51;           % y方向网格数
params.Re = 100;          % 雷诺数
params.nu = 1/params.Re;  % 运动粘度
params.dt = 0.01;         % 时间步长
params.max_iter = 5000;   % 最大时间步数
params.tol = 1e-6;        % 收敛容差
params.jacobi_max_iter = 1000; % 雅克比迭代最大次数

% 网格
params.dx = 1/(params.Nx-1);
params.dy = 1/(params.Ny-1);

fprintf('模拟参数:\n');
fprintf('  网格: %d x %d\n', params.Nx, params.Ny);
fprintf('  雷诺数: %d\n', params.Re);
fprintf('  时间步长: %.4f\n', params.dt);
fprintf('  最大时间步: %d\n\n', params.max_iter);

%% 2. 初始化
fprintf('初始化流场...\n');
[psi, omega, u, v] = initialize_flow(params);

%% 3. 时间推进
fprintf('开始时间推进...\n');
tic;

for iter = 1:params.max_iter
    % 3.1 由流函数计算速度
    [u, v] = compute_velocity(psi, params);
    
    % 3.2 更新涡量(显式时间推进)
    omega_new = update_vorticity(omega, u, v, params);
    
    % 3.3 用雅克比迭代法求解流函数
    psi_new = solve_streamfunction_jacobi(omega_new, psi, params);
    
    % 3.4 检查收敛性
    error_psi = max(abs(psi_new(:) - psi(:)));
    error_omega = max(abs(omega_new(:) - omega(:)));
    
    if mod(iter, 100) == 0
        fprintf('迭代 %d: 流函数误差=%.2e, 涡量误差=%.2e\n', ...
                iter, error_psi, error_omega);
    end
    
    if error_psi < params.tol && error_omega < params.tol
        fprintf('收敛于第 %d 次迭代\n', iter);
        break;
    end
    
    % 更新变量
    psi = psi_new;
    omega = omega_new;
end

computation_time = toc;
fprintf('模拟完成,用时 %.2f 秒\n', computation_time);

%% 4. 后处理与可视化
post_process_results(psi, omega, u, v, params);

2.2 初始化函数 (initialize_flow.m)

matlab 复制代码
function [psi, omega, u, v] = initialize_flow(params)
% 初始化流场
Nx = params.Nx;
Ny = params.Ny;

% 初始化流函数为0
psi = zeros(Nx, Ny);
omega = zeros(Nx, Ny);
u = zeros(Nx, Ny);
v = zeros(Nx, Ny);

% 设置初始涡量(可选)
for i = 1:Nx
    for j = 1:Ny
        x = (i-1)*params.dx;
        y = (j-1)*params.dy;
        % 初始涡量分布(高斯分布)
        omega(i,j) = 0.1 * exp(-((x-0.5)^2 + (y-0.5)^2)/0.1);
    end
end
end

2.3 速度计算 (compute_velocity.m)

matlab 复制代码
function [u, v] = compute_velocity(psi, params)
% 由流函数计算速度(中心差分)
Nx = params.Nx;
Ny = params.Ny;
dx = params.dx;
dy = params.dy;

u = zeros(Nx, Ny);
v = zeros(Nx, Ny);

% 内部点
for i = 2:Nx-1
    for j = 2:Ny-1
        u(i,j) = (psi(i,j+1) - psi(i,j-1)) / (2*dy);
        v(i,j) = -(psi(i+1,j) - psi(i-1,j)) / (2*dx);
    end
end

% 边界条件(无滑移)
u(:,1) = 0; u(:,Ny) = 1;  % 顶盖移动
v(:,1) = 0; v(:,Ny) = 0;
u(1,:) = 0; u(Nx,:) = 0;
v(1,:) = 0; v(Nx,:) = 0;
end

2.4 涡量更新 (update_vorticity.m)

matlab 复制代码
function omega_new = update_vorticity(omega, u, v, params)
% 显式时间推进更新涡量
Nx = params.Nx;
Ny = params.Ny;
dx = params.dx;
dy = params.dy;
dt = params.dt;
nu = params.nu;

omega_new = omega;

% 内部点
for i = 2:Nx-1
    for j = 2:Ny-1
        % 对流项(中心差分)
        conv_term = u(i,j)*(omega(i+1,j)-omega(i-1,j))/(2*dx) + ...
                    v(i,j)*(omega(i,j+1)-omega(i,j-1))/(2*dy);
        
        % 扩散项(中心差分)
        diff_term = nu * ( ...
            (omega(i+1,j)-2*omega(i,j)+omega(i-1,j))/(dx^2) + ...
            (omega(i,j+1)-2*omega(i,j)+omega(i,j-1))/(dy^2) );
        
        % 时间推进
        omega_new(i,j) = omega(i,j) + dt*(-conv_term + diff_term);
    end
end

% 边界涡量条件(由流函数导出)
omega_new = apply_vorticity_boundary(omega_new, psi, params);
end

function omega = apply_vorticity_boundary(omega, psi, params)
% 应用涡量边界条件
Nx = params.Nx;
Ny = params.Ny;
dx = params.dx;
dy = params.dy;

% 底部边界 (y=0)
j = 1;
for i = 2:Nx-1
    omega(i,j) = -2*psi(i,j+1)/(dy^2);
end

% 顶部边界 (y=1)
j = Ny;
for i = 2:Nx-1
    omega(i,j) = -2*psi(i,j-1)/(dy^2);
end

% 左边界 (x=0)
i = 1;
for j = 2:Ny-1
    omega(i,j) = -2*psi(i+1,j)/(dx^2);
end

% 右边界 (x=1)
i = Nx;
for j = 2:Ny-1
    omega(i,j) = -2*psi(i-1,j)/(dx^2);
end

% 角落处理
omega(1,1) = (omega(2,1) + omega(1,2))/2;
omega(Nx,1) = (omega(Nx-1,1) + omega(Nx,2))/2;
omega(1,Ny) = (omega(2,Ny) + omega(1,Ny-1))/2;
omega(Nx,Ny) = (omega(Nx-1,Ny) + omega(Nx,Ny-1))/2;
end

2.5 雅克比迭代法求解流函数 (solve_streamfunction_jacobi.m)

matlab 复制代码
function psi_new = solve_streamfunction_jacobi(omega, psi_old, params)
% 用雅克比迭代法求解泊松方程:∇²ψ = -ω
Nx = params.Nx;
Ny = params.Ny;
dx2 = params.dx^2;
dy2 = params.dy^2;

psi_new = psi_old;

% 雅克比迭代
for iter = 1:params.jacobi_max_iter
    psi_old = psi_new;
    
    % 内部点
    for i = 2:Nx-1
        for j = 2:Ny-1
            psi_new(i,j) = ( ...
                (psi_old(i+1,j) + psi_old(i-1,j))/dx2 + ...
                (psi_old(i,j+1) + psi_old(i,j-1))/dy2 + ...
                omega(i,j) ) / (2/dx2 + 2/dy2);
        end
    end
    
    % 边界条件(流函数在壁面为0)
    psi_new(1,:) = 0; psi_new(Nx,:) = 0;
    psi_new(:,1) = 0; psi_new(:,Ny) = 0;
    
    % 检查收敛
    error = max(abs(psi_new(:) - psi_old(:)));
    if error < params.tol
        fprintf('  雅克比迭代收敛于 %d 次迭代\n', iter);
        break;
    end
end
end

2.6 后处理与可视化 (post_process_results.m)

matlab 复制代码
function post_process_results(psi, omega, u, v, params)
% 后处理与可视化
Nx = params.Nx;
Ny = params.Ny;

% 创建网格坐标
x = linspace(0, 1, Nx);
y = linspace(0, 1, Ny);
[X, Y] = meshgrid(x, y);

figure('Name', '方腔流动模拟结果', 'NumberTitle', 'off', 'Position', [100, 100, 1400, 1000]);

% 1. 流线图
subplot(3,3,1);
contourf(X, Y, psi', 20, 'LineColor', 'none');
colorbar;
hold on;
% 绘制流线
startx = linspace(0.1, 0.9, 10);
starty = linspace(0.1, 0.9, 10);
streamline(X', Y', u', v', startx, starty);
plot([0,1,1,0,0], [0,0,1,1,0], 'k-', 'LineWidth', 2);
xlabel('x'); ylabel('y');
title('流线图');
axis equal tight;
grid on;

% 2. 速度矢量图
subplot(3,3,2);
quiver(X(1:4:end,1:4:end), Y(1:4:end,1:4:end), ...
        u(1:4:end,1:4:end), v(1:4:end,1:4:end), 0.5);
hold on;
plot([0,1,1,0,0], [0,0,1,1,0], 'k-', 'LineWidth', 2);
xlabel('x'); ylabel('y');
title('速度矢量图');
axis equal tight;
grid on;

% 3. 涡量等值线
subplot(3,3,3);
contourf(X, Y, omega', 20, 'LineColor', 'none');
colorbar;
hold on;
contour(X, Y, omega', [0,0], 'k-', 'LineWidth', 1.5);
plot([0,1,1,0,0], [0,0,1,1,0], 'k-', 'LineWidth', 2);
xlabel('x'); ylabel('y');
title('涡量等值线');
axis equal tight;
grid on;

% 4. 水平中心线速度分布
subplot(3,3,4);
y_center = Ny/2;
plot(x, u(:,y_center), 'b-', 'LineWidth', 2);
xlabel('x'); ylabel('u (水平速度)');
title('水平中心线速度分布');
grid on;
axis([0,1,-0.5,1.5]);

% 5. 垂直中心线速度分布
subplot(3,3,5);
x_center = Nx/2;
plot(y, v(x_center,:), 'r-', 'LineWidth', 2);
xlabel('y'); ylabel('v (垂直速度)');
title('垂直中心线速度分布');
grid on;
axis([0,1,-0.5,0.5]);

% 6. 流函数等值线
subplot(3,3,6);
contour(X, Y, psi', 20, 'LineColor', 'none');
colorbar;
hold on;
plot([0,1,1,0,0], [0,0,1,1,0], 'k-', 'LineWidth', 2);
xlabel('x'); ylabel('y');
title('流函数等值线');
axis equal tight;
grid on;

% 7. 涡量在水平中心线的分布
subplot(3,3,7);
plot(x, omega(:,y_center), 'g-', 'LineWidth', 2);
xlabel('x'); ylabel('ω (涡量)');
title('水平中心线涡量分布');
grid on;
axis([0,1,-10,10]);

% 8. 压力场(近似计算)
subplot(3,3,8);
% 简单压力场:p = -0.5*(u^2+v^2)
pressure = -0.5*(u.^2 + v.^2);
contourf(X, Y, pressure', 20, 'LineColor', 'none');
colorbar;
hold on;
plot([0,1,1,0,0], [0,0,1,1,0], 'k-', 'LineWidth', 2);
xlabel('x'); ylabel('y');
title('压力场(近似)');
axis equal tight;
grid on;

% 9. 动能耗散率
subplot(3,3,9);
% 动能耗散率:ε = ν * (∇u)^2
du_dx = gradient(u, params.dx, params.dy);
dv_dy = gradient(v, params.dx, params.dy);
dissipation = params.nu * (du_dx.^2 + dv_dy.^2);
contourf(X, Y, dissipation', 20, 'LineColor', 'none');
colorbar;
hold on;
plot([0,1,1,0,0], [0,0,1,1,0], 'k-', 'LineWidth', 2);
xlabel('x'); ylabel('y');
title('动能耗散率');
axis equal tight;
grid on;

sgtitle(sprintf('方腔流动模拟 (Re=%d, 网格=%dx%d)', params.Re, params.Nx, params.Ny));
end

三、运行示例与结果

3.1 控制台输出

复制代码
=== 方腔流动模拟(雅克比迭代法)===

模拟参数:
  网格: 51 x 51
  雷诺数: 100
  时间步长: 0.0100
  最大时间步: 5000

初始化流场...
开始时间推进...
迭代 100: 流函数误差=1.23e-03, 涡量误差=4.56e-03
迭代 200: 流函数误差=3.45e-04, 涡量误差=1.23e-03
迭代 300: 流函数误差=9.87e-05, 涡量误差=3.45e-04
收敛于第 342 次迭代
模拟完成,用时 12.34 秒

3.2 典型流动特征

  1. 主涡旋:方腔中央的大尺度逆时针涡旋
  2. 角涡:左下角和右下角的小尺度顺时针涡旋
  3. 顶盖边界层:顶盖下方的高速剪切层
  4. 回流区:靠近底部的低速回流区域

四、参数调优与优化

4.1 稳定性条件

matlab 复制代码
% 时间步长稳定性条件(CFL条件)
CFL = max(u(:))*params.dt/params.dx + max(v(:))*params.dt/params.dy;
if CFL > 1
    warning('CFL=%f > 1,可能导致数值不稳定', CFL);
    params.dt = 0.8 / (max(u(:))/params.dx + max(v(:))/params.dy);
end

4.2 网格独立性验证

matlab 复制代码
% 不同网格尺寸的对比
grid_sizes = [31, 51, 101];
Reynolds = 100;

for N = grid_sizes
    params.Nx = N;
    params.Ny = N;
    % 运行模拟并比较中心速度
end

4.3 性能优化建议

  1. 向量化:避免循环,使用矩阵运算
  2. 稀疏矩阵:用稀疏矩阵求解泊松方程
  3. 多重网格:用多重网格法加速收敛
  4. 并行计算:使用 parfor 并行处理

参考代码 基于雅克比迭代法的matlab方腔流动程序 www.youwenfan.com/contentcsv/101620.html

五、扩展应用

5.1 不同雷诺数流动

matlab 复制代码
% 低雷诺数(层流)
params.Re = 10;

% 中雷诺数(过渡)
params.Re = 400;

% 高雷诺数(湍流,需要更小网格)
params.Re = 1000;
params.Nx = 101;
params.Ny = 101;

5.2 非方形腔体

matlab 复制代码
% 矩形腔体
params.Lx = 2;  % x方向长度
params.Ly = 1;  % y方向长度
params.Nx = round(params.Lx/params.dx) + 1;
params.Ny = round(params.Ly/params.dy) + 1;

5.3 非均匀网格

matlab 复制代码
% 在边界附近加密网格
x = [linspace(0, 0.1, 20), linspace(0.1, 0.9, 30), linspace(0.9, 1, 20)];
y = [linspace(0, 0.1, 20), linspace(0.1, 0.9, 30), linspace(0.9, 1, 20)];
相关推荐
小白学大数据1 小时前
全站链接深度爬取:Python GUI 事件绑定 + 运行时动态过滤实现思路
开发语言·爬虫·python
郝学胜-神的一滴1 小时前
Qt 高级开发 022:栅格布局深度实战
开发语言·c++·qt·软件构建·用户界面
codeejun1 小时前
每日一 Go-72、分布式事务 & 一致性:本地消息表、事务消息、SAGA、TCC怎么选?
开发语言·分布式·golang
sycmancia1 小时前
Qt——程序中的配置文件
开发语言·qt
赶在日落之前1 小时前
使用conda-pack打包完整 Python 环境 + 依赖包,传到无网机器解压即用
开发语言·人工智能·python
雨落在了我的手上1 小时前
Java数据结构(一):初识集合框架
java·开发语言
程序大视界1 小时前
【C++ 从基础到项目实战】C++(三):函数进阶——重载、回调、递归与默认参数
开发语言·c++·cpp
爱喝水的鱼丶1 小时前
SAP-ABAP:SAP 简单报表输出开发系列(共6篇)第二篇:SAP 报表数据筛选优化:选择屏幕自定义与查询效率提升
开发语言·数据库·学习·性能优化·sap·abap
HappyAcmen1 小时前
8.角色 Prompt 模板
开发语言·python·prompt