% 中山大学 19320053 廉嘉诚
clc;
clf;
clear;
% ---参数初始化---
% 流体密度
rho = 1e3;
% 雷诺数
Re = 3200;
% 动力粘性系数
mu = 1/Re;
% 误差限度
SOR_error_limit = 1e-3;
% 迭代次数限度
FTCS_MaxTimes = 1e5;
SOR_MaxTimes = 1e5;
% 题设顶部移动速度
U_assume = 1;
% ---网格初始化---
% 步长
h = 0.01;
% 时间步长
dt = 0.001;
% 坐标系
x_border = [-0.5 0.5]';
y_border = [0 1]';
x = x_border(1):h:x_border(2);
y = y_border(1):h:y_border(2);
[X,Y] = meshgrid(y,x);
% 矩阵长度
length = size(X,1);
% 场
Zeta = zeros(size(X));
Psi = zeros(size(X));
P = zeros(size(X));
PG = zeros([length 4]); % 1 左边界 2 右边界 3 下边界 4 上边界
Sp = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
U1 = zeros(size(X));
V1 = zeros(size(X));
% 缓存
tmp = zeros(size(X));
% 获得 SOR 迭代法最佳松弛因子
factor = GetOptimalRelaxationFactor(length,length);
% 开始求解
for Zeta_FTCS_times = 1:1:FTCS_MaxTimes
% 流函数 超松弛迭代
% 内点
for Psi_SOR_times = 1:1:SOR_MaxTimes
dPsi_max = 0;
for i = 2:1:length-1
for j = 2:1:length-1
% 增量
dPsi = -factor*Psi(i,j)...
+factor/4*(...
Psi(i,j+1)...
+Psi(i,j-1)...
+Psi(i+1,j)...
+Psi(i-1,j)...
+h^2*Zeta(i,j));
% 取增量绝对值的最大值
dPsi_max = max([dPsi_max abs(dPsi)]);
% 基点的新值
Psi(i,j) = Psi(i,j) + dPsi;
end
end
% 直到误差小于一定限度,流函数的迭代方程收敛,才能进入涡量的迭代
if dPsi_max < SOR_error_limit
break;
end
end
% 涡量 FTCS 格式
% 边界点(跳过角点)
for i = 2:1:length-1
% 下侧
Zeta(i,1) = -2.0*Psi(i,2)/(h*h)+2.0*U_assume/h;
% 上侧
Zeta(i,length) = -2.0*Psi(i,length-1)/(h*h);
end
for j = 2:1:length-1
% 左侧
Zeta(1,j) = -2.0*Psi(2,j)/(h*h);
% 右侧
Zeta(length,j) = -2.0*Psi(length-1,j)/(h*h);
end
% 内点
Zeta_right = MatrixTranslation(Zeta,1,0);
Zeta_left = MatrixTranslation(Zeta,-1,0);
Zeta_up = MatrixTranslation(Zeta,0,1);
Zeta_down = MatrixTranslation(Zeta,0,-1);
Psi_right = MatrixTranslation(Psi,1,0);
Psi_left = MatrixTranslation(Psi,-1,0);
Psi_up = MatrixTranslation(Psi,0,1);
Psi_down = MatrixTranslation(Psi,0,-1);
U_dZeta_dx = (Psi_up-Psi_down).*(Zeta_right-Zeta_left)/(4*h^2);
V_dZeta_dy = -(Psi_right-Psi_left).*(Zeta_up-Zeta_down)/(4*h^2);
mu_Nabla_Zeta = mu*(Zeta_right+Zeta_left+Zeta_up+Zeta_down-4*Zeta)/h^2;
Zeta_tmp = Zeta + dt*(-U_dZeta_dx-V_dZeta_dy+mu_Nabla_Zeta);
Zeta(2:length-1,2:length-1) = Zeta_tmp(2:length-1,2:length-1);
end
% 流速
U = (Psi_up-Psi_down)/(2*h);
V = -(Psi_right-Psi_left)/(2*h);
% 压强梯度
% 边界点(跳过角点)
for i = 2:1:length-1
% 下侧
PG(i,3) = rho/h^2*mu*V(i,2);
% 上侧
PG(i,4) = rho/h^2*mu*V(i,length-1);;
end
for j = 2:1:length-1
% 左侧
PG(j,1) = rho/h^2*mu*U(2,j);
% 右侧
PG(j,2) = rho/h^2*mu*U(length-1,j);
end
% 压强 超松弛迭代
Psi_right_up = MatrixTranslation(Psi,1,1);
Psi_right_down = MatrixTranslation(Psi,1,-1);
Psi_left_up = MatrixTranslation(Psi,-1,1);
Psi_left_down = MatrixTranslation(Psi,-1,-1);
Sp = 2*rho/h^2*(...
(Psi_right-2*Psi+Psi_left)*(Psi_up-2*Psi+Psi_down) ...
-(Psi_right_up-Psi_right_down-Psi_left_up+Psi_left_down)/4);
for P_SOR_times = 1:1:SOR_MaxTimes
dP_max = 0;
for i = 1:1:length
for j = 1:1:length
% 跳过角点
if i == 1 || i == length
if j == 1 || j == length
continue;
end
end
p1 = P(i,j);
% 边界点
% 下侧
if j == 1
p1 = P(i,2)-PG(i,3)*h;
continue;
% 上侧
elseif j == length
p1 = P(i,length-1)+PG(i,4)*h;
continue;
end
% 左侧
if i == 1
p1 = P(2,j)-PG(j,1)*h;
continue;
% 右侧
elseif i == length
p1 = P(length-1,j)+PG(j,2)*h;
continue;
end
% 内点
p2 = (...
P(i,j+1)...
+P(i,j-1)...
+P(i+1,j)...
+P(i-1,j)...
+h^2*Sp(i,j));
dP = -factor*p1+factor/4*p2;
% 取增量绝对值的最大值
dP_max = max([dP_max abs(dP)]);
% 基点的新值
P(i,j) = P(i,j) + dP;
end
end
% 直到误差小于一定限度,流函数的迭代方程收敛,才能进入涡量的迭代
if dP_max < SOR_error_limit
break;
end
end
% 流函数等高线
figure(1);
clf;
contour(Y,X,Psi,Psi(floor(length/2),:));
shading interp;
hold on;
contour(Y,X,Psi,Psi(:,floor(6*length/7)));
hold off;
title('流函数等高线图');
xlabel('x');
ylabel('y');
axis('square','tight');
colorbar;
% 涡量等高线
figure(2);
clf;
hold on;
contour(Y,X,Zeta,Zeta(floor(length/2),:));
hold off;
shading interp;
title('涡量等高线图');
xlabel('x');
ylabel('y');
axis('square','tight');
colorbar;
% 水平速度等高线
figure(3);
clf;
hold on;
contour(Y,X,U,U(:,floor(length/5)));
contour(Y,X,U,U(:,floor(2*length/5)));
contour(Y,X,U,U(:,floor(3*length/5)));
contour(Y,X,U,U(:,floor(4*length/5)));
hold off;
shading interp;
title('水平速度等高线图');
xlabel('x');
ylabel('y');
axis('square','tight');
colorbar;
% 竖直速度等高线
figure(4);
clf;
hold on;
contour(Y,X,V,V(floor(length/5),:));
contour(Y,X,V,V(floor(2*length/5),:));
contour(Y,X,V,V(floor(3*length/5),:));
contour(Y,X,V,V(floor(4*length/5),:));
hold off;
shading interp;
title('竖直速度等高线图');
xlabel('x');
ylabel('y');
axis('square','tight');
colorbar;
% 压强等高线
figure(4);
clf;
hold on;
contour(Y,X,P,P(floor(length/2),:));
contour(Y,X,P,P(floor(length/4),:));
contour(Y,X,P,P(floor(3*length/4),:));
hold off;
shading interp;
title('压强等高线图');
xlabel('x');
ylabel('y');
axis('square','tight');
colorbar;
function [factor] = GetOptimalRelaxationFactor(m,n)
% 获得 SOR 法最佳松弛因子
mu = 1/2*(cos(pi/m)+cos(pi/n));
factor = 2*(1-(1-mu^2)^0.5)/mu^2;
end
function [A] = MatrixTranslation(A,xstep,ystep)
% 将矩阵在 x 方向上平移 xstep 个单位,在 y 方向上平移 ystep 个单位
% 这个平移不是仿射变换,只是元素相对位置的平移
% 空余的位置用 0 补充
% 移动距离超出矩阵长度的会得到全零
if abs(xstep) >= size(A,1) || abs(ystep) >= size(A,2)
A = zeros(size(A));
return;
end
A = A;
if xstep > 0
A = A(:,1:size(A,2)-xstep);
A = [zeros(size(A,1),xstep) A];
end
if xstep < 0
A = A(:,1-xstep:size(A,2));
A = [A zeros(size(A,1),-xstep)];
end
if ystep > 0
A = A(1+ystep:size(A,1),:);
A = [A;zeros(ystep,size(A,2))];
end
if ystep < 0
A = A(1:size(A,1)+ystep,:);
A = [zeros(-ystep,size(A,2));A];
end
end
function [A] = DeleteElementForLargerSpace(A,n)
% 输入一个行向量或者列向量,输出一个全部元素属于输入的列向量
% 使得输出的列向量各元素之间的间隔变大
% 共减少 n 个元素
for times = 1:1:n
length = size(A,1)*size(A,2);
delta = zeros(length-1,1);
for i = 1:1:length-1
delta(i) = abs(A(i)-A(i+1));
end
[M,I] = min(delta);
A_tmp = zeros(length-1,1);
for i = 1:1:I-1
A_tmp(i) = A(i);
end
for i = I+1:1:length
A_tmp(i-1) = A(i);
end
A = A_tmp;
end
end
第一版代码
% 中山大学 19320053 廉嘉诚
clc;
clear;
% ---参数初始化---
% 雷诺数
Re = 10;
% 误差限度
error_limit = 1e-6;
% 误差
error = 9999;
% 迭代次数限度
iterationTimes_limit = 100;
% 迭代次数
iterationTimes = 0;
% ---网格初始化---
% 步长
dx = 0.005;
dy = 0.005;
% 边界
x_border = [-0.5 0.5]';
y_border = [0 1]';
% 边界向量
x = x_border(1):dx:x_border(2);
y = y_border(1):dy:y_border(2);
% 求 X 和 Y 矩阵
% X 矩阵每一行都是 X 向量
% Y 矩阵每一列都是 Y 向量
% 和 XOY 坐标系的直觉相配
[X,Y] = meshgrid(x,y);
% 涡量初始化
Zeta = zeros(size(X));
% 流函数初始化
Psi = zeros(size(X));
% 速度初始化
U = zeros(size(X));
V = zeros(size(X));
for j = 1:1:size(X,2)
U(1,j) = 1;
end
% 获得 SOR 迭代法最佳松弛因子
factor = GetOptimalRelaxationFactor(size(Zeta,1),size(Zeta,2));
% error > error_limit &&
% 循环迭代
while iterationTimes < iterationTimes_limit
% 迭代涡量
[Zeta,dZeta_max] = Iteration_Vorticity(Zeta,Psi,U,V,factor,dx,1/Re);
% 迭代流函数
[Psi,dPsi_max] = Iteration_StreamFunction(Psi,Zeta,factor,dx);
% 迭代速度
[U,V,dU_max,dV_max] = Iteration_Velocity(Psi,U,V,dx);
% 取最大误差
error = max([dZeta_max dPsi_max dU_max dV_max]);
% 迭代次数加 1
iterationTimes = iterationTimes + 1;
end
figure();
% 等高线
contour(X,Y,Psi,50);
shading interp;
function [factor] = GetOptimalRelaxationFactor(m,n)
% 获得 SOR 法最佳松弛因子
mu = 1/2*(cos(pi/m)+cos(pi/n));
factor = 2*(1-(1-mu^2)^0.5)/mu^2;
end
function [Zeta_New] = MatrixTranslation(Zeta,xstep,ystep)
% 将矩阵在 x 方向上平移 xstep 个单位,在 y 方向上平移 ystep 个单位
% 这个平移不是仿射变换,只是元素相对位置的平移
% 空余的位置用 0 补充
% 移动距离超出矩阵长度的会得到全零
if abs(xstep) >= size(Zeta,1) || abs(ystep) >= size(Zeta,2)
Zeta_New = zeros(size(Zeta));
return;
end
Zeta_New = Zeta;
if xstep > 0
Zeta_New = Zeta_New(:,1:size(Zeta,2)-xstep);
Zeta_New = [zeros(size(Zeta,1),xstep) Zeta_New];
end
if xstep < 0
Zeta_New = Zeta_New(:,1-xstep:size(Zeta,2));
Zeta_New = [Zeta_New zeros(size(Zeta,1),-xstep)];
end
if ystep > 0
Zeta_New = Zeta_New(1:size(Zeta,1)-ystep,:);
Zeta_New = [zeros(ystep,size(Zeta,2));Zeta_New];
end
if ystep < 0
Zeta_New = Zeta_New(1-ystep:size(Zeta,1),:);
Zeta_New = [Zeta_New;zeros(-ystep,size(Zeta,2))];
end
end
function [Zeta_new,dZeta_max] = Iteration_Vorticity(Zeta,Psi,U,V,factor,h,mu)
% 迭代涡量
% Zeta 涡量矩阵
% Psi 流函数矩阵
% U,V 速度矩阵
% factor 超松弛因子
% h 步长
% mu 动力粘性系数
% 使用 mesh 函数得到的 X,Y 得到的坐标系为
% i 行号从小到大代表直角坐标系中纵坐标从小到大
% j 列号从小到大代表直角坐标系中横坐标从小到大
% 初始化
Zeta_new = zeros(size(Zeta));
dZeta_max = 0;
% 迭代 Zeta
for i = 1:1:size(Zeta,1)
for j = 1:1:size(Zeta,2)
% 边界条件
% 顶部的水平固壁边界
if i == 1
Zeta_new(i,j) = 2*(Psi(i,j)-Psi(i+1,j)+U(i,j)*h)/h^2;
continue;
% 底部的水平移动边界
elseif i == size(Zeta,1)
Zeta_new(i,j) = 2*(Psi(i-1,j)-Psi(i,j))/h^2;
continue;
end
% 左侧的竖直固壁边界
if j == 1
Zeta_new(i,j) = 2*(Psi(i,j)-Psi(i,j+1))/h^2;
continue;
% 右侧的竖直固壁边界
elseif j == size(Zeta,2)
Zeta_new(i,j) = 2*(Psi(i,j-1)-Psi(i,j))/h^2;
continue;
end
% 超松弛迭代
% 增量
dZeta = (1-factor)*Zeta(i,j)+factor*((1-1/mu*h*U(i,j))*Zeta(i,j+1)+Zeta(i,j-1)+(1-1/mu*h*V(i,j))*Zeta(i+1,j)+Zeta(i-1,j))/(4-1/mu*h*(U(i,j)+V(i,j)));
% 取增量绝对值的最大值
dZeta_max = max([dZeta_max abs(dZeta)]);
% 基点的新值
Zeta_new(i,j) = Zeta(i,j) + dZeta;
end
end
end
function [Psi_new,dPsi_max] = Iteration_StreamFunction(Psi,Zeta,factor,h)
% 迭代流函数
% Psi 流函数矩阵
% Zeta 涡量矩阵
% factor 超松弛因子
% h 步长
% 使用 mesh 函数得到的 X,Y 得到的坐标系为
% i 行号从小到大代表直角坐标系中纵坐标从小到大
% j 列号从小到大代表直角坐标系中横坐标从小到大
% 初始化
Psi_new = zeros(size(Zeta));
dPsi_max = 0;
% 迭代 Zeta
for i = 1:1:size(Psi,1)
for j = 1:1:size(Psi,2)
% 边界条件
% 顶部的水平固壁边界
if i == 1
continue;
% 底部的水平移动边界
elseif i == size(Zeta,1)
continue;
end
% 左侧的竖直固壁边界
if j == 1
continue;
% 右侧的竖直固壁边界
elseif j == size(Zeta,2)
continue;
end
% 超松弛迭代
% 增量
dPsi = (1-factor)*Psi(i,j)+factor/4*(Psi(i,j+1)+Psi(i,j-1)+Psi(i+1,j)+Psi(i-1,j)+h^2*Zeta(i,j));
% 取增量绝对值的最大值
dPsi_max = max([dPsi_max abs(dPsi)]);
% 基点的新值
Psi_new(i,j) = Psi(i,j) + dPsi;
end
end
end
function [U_new,V_new,dU_max,dV_max] = Iteration_Velocity(Psi,U,V,h)
% 迭代速度
% Psi 流函数矩阵
% U,V 速度矩阵
% h 步长
% 使用 mesh 函数得到的 X,Y 得到的坐标系为
% i 行号从小到大代表直角坐标系中纵坐标从小到大
% j 列号从小到大代表直角坐标系中横坐标从小到大
% ψ_(row+1,col) 公式语境下的 ψ_(i,j+1)
Psi_right = MatrixTranslation(Psi,-1,0);
% ψ_(row-1,col) 公式语境下的 ψ_(i,j-1)
Psi_left = MatrixTranslation(Psi,1,0);
% ψ_(row,col+1) 公式语境下的 ψ_(i+1,j)
Psi_up = MatrixTranslation(Psi,0,-1);
% ψ_(row,col-1) 公式语境下的 ψ_(i-1,j)
Psi_down = MatrixTranslation(Psi,0,1);
% 公式语境下的 u_(i,j+1/2)
U_right = (Psi_right-Psi)/h;
% 公式语境下的 u_(i,j-1/2)
U_left = (Psi-Psi_left)/h;
% 公式语境下的 v_(i+1/2,j)
V_down = -(Psi_up-Psi)/h;
% 公式语境下的 v_(i-1/2,j)
V_up = -(Psi-Psi_down)/h;
U_tmp = 1/2*(U_left+U_right);
V_tmp = 1/2*(V_up+V_down);
U_new = U;
V_new = V;
U_new(2:size(U,1)-1,2:size(U,2)-1) = U_tmp(2:size(U,1)-1,2:size(U,2)-1);
V_new(2:size(V,1)-1,2:size(V,2)-1) = V_tmp(2:size(V,1)-1,2:size(V,2)-1);
dU_max = max(max(abs(U_new-U)));
dV_max = max(max(abs(V_new-V)));
end
% function [U_new,V_new,dU_max,dV_max] = Iteration_PressureGradient(Psi,U,V,h)
%
% end
% function [U_new,V_new,dU_max,dV_max] = Iteration_PoissonEqTerm_Sp(Psi,U,V,h)
%
% end
做出来是发散的
看了工作区,我觉得应该是 Zeta 的问题,虽然 Zeta 和 Psi 是交替迭代的,但是 Zeta 发散得更快
后面发现我是把增量写错了……因为是增量,所以开头不是 (1-ω) ζ_(i,j)^n
而是 -ω ζ_(i,j)^n
% 增量
dZeta = -factor*Zeta(i,j)+factor*((1-1/mu*h*U(i,j))*Zeta(i,j+1)+Zeta(i,j-1)+(1-1/mu*h*V(i,j))*Zeta(i+1,j)+Zeta(i-1,j))/(4-1/mu*h*(U(i,j)+V(i,j)));
% 增量
dPsi = factor*Psi(i,j)+factor/4*(Psi(i,j+1)+Psi(i,j-1)+Psi(i+1,j)+Psi(i-1,j)+h^2*Zeta(i,j));
然后又发散了
实在是不知道哪里有问题,看公式,如果公式没错的话,那么 Zeta 不用改,那就是速度有问题了
工作区里面的速度确实很怪
速度的公式是
从工作区看 Psi 也挺正常的,数量级一直很小,为什么会出错呢……
手算了一下,跟工作区还是比较符合的
u(2,5/2) = (454.59-(-519.44))/0.005 = 194806
u(2,3/2) = (-519.44-0)/0.005 = -103888
u(2,2) = (194806+(-103888))/2 = 45459
之后又看到了超松弛的一个错误
我没有在迭代的时候实时更新……
正确的更新是
% 基点的新值
Zeta(i,j) = Zeta(i,j) + dZeta;
% 基点的新值
Psi(i,j) = Psi(i,j) + dPsi;
改了之后还是发散……
这次我觉得已经不需要看工作区了
或者说看头几次工作区是什么样子的我看不出什么东西
为了方便排错,我把矩阵平移的函数重新写为更和谐的形式
function [A] = MatrixTranslation(A,istep,jstep)
% 将矩阵在行号增大的方向上平移 istep 个单位,在列号增大的方向上平移 jstep 个单位
% 这个平移不是仿射变换,只是元素相对位置的平移
% 空余的位置用 0 补充
% 移动距离超出矩阵长度的会得到全零
if abs(istep) >= size(A,1) || abs(jstep) >= size(A,2)
A = zeros(size(A));
return;
end
if istep > 0
A = A(1:size(A,1)-istep,:);
A = [zeros(istep,size(A,2));A];
end
if istep < 0
A = A(1-istep:size(A,1),:);
A = [A;zeros(-istep,size(A,2))];
end
if jstep > 0
A = A(:,1:size(A,2)-jstep);
A = [zeros(size(A,1),jstep) A];
end
if jstep < 0
A = A(:,1-jstep:size(A,2));
A = [A zeros(size(A,1),-jstep)];
end
end
之前想的是在 x y 正方向上移动……现在已经看不懂了
一步步走,发现有一步中从 e2 跳到 e50 多,Zeta 的误差是第一个飙上去的
朋友说是有可能公式中分母接近 0 的问题
因此我把一阶导的差分格式中的基点去掉了
但是还是发散……
% 中山大学 19320053 廉嘉诚
clc;
clear;
% ---参数初始化---
% 雷诺数
Re = 10;
% 误差限度
error_limit = 1e-6;
% 误差
error = 9999;
% 迭代次数限度
iterationTimes_limit = 9999;
% 迭代次数
iterationTimes = 0;
% ---网格初始化---
% 步长
dx = 0.01;
dy = 0.01;
% 边界
x_border = [-0.5 0.5]';
y_border = [0 1]';
% 边界向量
x = x_border(1):dx:x_border(2);
y = y_border(1):dy:y_border(2);
% 求 X 和 Y 矩阵
% X 矩阵每一行都是 X 向量
% Y 矩阵每一列都是 Y 向量
% 和 XOY 坐标系的直觉相配
[X,Y] = meshgrid(x,y);
% 涡量初始化
Zeta = zeros(size(X));
% 流函数初始化
Psi = zeros(size(X));
% 速度初始化
U = zeros(size(X));
V = zeros(size(X));
for j = 1:1:size(X,2)
U(1,j) = 1;
end
figure();
% 获得 SOR 迭代法最佳松弛因子
factor = GetOptimalRelaxationFactor(size(Zeta,1),size(Zeta,2));
% 循环迭代
while error > error_limit && iterationTimes < iterationTimes_limit
% 迭代涡量
[Zeta,dZeta_max] = Iteration_Vorticity(Zeta,Psi,U,V,factor,dx,1/Re);
% 迭代流函数
[Psi,dPsi_max] = Iteration_StreamFunction(Psi,Zeta,factor,dx);
% 迭代速度
[U,V,dU_max,dV_max] = Iteration_Velocity(Psi,U,V,dx);
% 取最大误差
error = max([dZeta_max dPsi_max dU_max dV_max]);
% 迭代次数加 1
iterationTimes = iterationTimes + 1;
% 等高线
contour(X,Y,Psi,50);
shading interp;
end
function [factor] = GetOptimalRelaxationFactor(m,n)
% 获得 SOR 法最佳松弛因子
mu = 1/2*(cos(pi/m)+cos(pi/n));
factor = 2*(1-(1-mu^2)^0.5)/mu^2;
end
function [A] = MatrixTranslation(A,istep,jstep)
% 将矩阵在行号增大的方向上平移 istep 个单位,在列号增大的方向上平移 jstep 个单位
% 这个平移不是仿射变换,只是元素相对位置的平移
% 空余的位置用 0 补充
% 移动距离超出矩阵长度的会得到全零
if abs(istep) >= size(A,1) || abs(jstep) >= size(A,2)
A = zeros(size(A));
return;
end
if istep > 0
A = A(1:size(A,1)-istep,:);
A = [zeros(istep,size(A,2));A];
end
if istep < 0
A = A(1-istep:size(A,1),:);
A = [A;zeros(-istep,size(A,2))];
end
if jstep > 0
A = A(:,1:size(A,2)-jstep);
A = [zeros(size(A,1),jstep) A];
end
if jstep < 0
A = A(:,1-jstep:size(A,2));
A = [A zeros(size(A,1),-jstep)];
end
end
function [Zeta,dZeta_max] = Iteration_Vorticity(Zeta,Psi,U,V,factor,h,mu)
% 迭代涡量
% Zeta 涡量矩阵
% Psi 流函数矩阵
% U,V 速度矩阵
% factor 超松弛因子
% h 步长
% mu 动力粘性系数
% 使用 mesh 函数得到的 X,Y 得到的坐标系为
% i 行号从小到大代表直角坐标系中纵坐标从小到大
% j 列号从小到大代表直角坐标系中横坐标从小到大
% 初始化
dZeta_max = 0;
% 迭代 Zeta
for i = 1:1:size(Zeta,1)
for j = 1:1:size(Zeta,2)
% 边界条件
% 顶部的水平固壁边界
if i == 1
Zeta(i,j) = 2*(Psi(i,j)-Psi(i+1,j)+U(i,j)*h)/h^2;
continue;
% 底部的水平移动边界
elseif i == size(Zeta,1)
Zeta(i,j) = 2*(Psi(i-1,j)-Psi(i,j))/h^2;
continue;
end
% 左侧的竖直固壁边界
if j == 1
Zeta(i,j) = 2*(Psi(i,j)-Psi(i,j+1))/h^2;
continue;
% 右侧的竖直固壁边界
elseif j == size(Zeta,2)
Zeta(i,j) = 2*(Psi(i,j-1)-Psi(i,j))/h^2;
continue;
end
% 超松弛迭代
% 增量
dZeta = -factor*Zeta(i,j)+factor/4*((1-1/2*1/mu*h*U(i,j))*Zeta(i,j+1)+(1+1/2*1/mu*h*U(i,j))*Zeta(i,j-1)+(1-1/2*1/mu*h*V(i,j))*Zeta(i+1,j)+(1+1/2*1/mu*h*V(i,j))*Zeta(i-1,j));
% 取增量绝对值的最大值
dZeta_max = max([dZeta_max abs(dZeta)]);
% 基点的新值
Zeta(i,j) = Zeta(i,j) + dZeta;
end
end
end
function [Psi,dPsi_max] = Iteration_StreamFunction(Psi,Zeta,factor,h)
% 迭代流函数
% Psi 流函数矩阵
% Zeta 涡量矩阵
% factor 超松弛因子
% h 步长
% 使用 mesh 函数得到的 X,Y 得到的坐标系为
% i 行号从小到大代表直角坐标系中纵坐标从小到大
% j 列号从小到大代表直角坐标系中横坐标从小到大
% 初始化
dPsi_max = 0;
% 迭代 Zeta
for i = 1:1:size(Psi,1)
for j = 1:1:size(Psi,2)
% 边界条件
% 顶部的水平固壁边界
if i == 1
continue;
% 底部的水平移动边界
elseif i == size(Zeta,1)
continue;
end
% 左侧的竖直固壁边界
if j == 1
continue;
% 右侧的竖直固壁边界
elseif j == size(Zeta,2)
continue;
end
% 超松弛迭代
% 增量
dPsi = -factor*Psi(i,j)+factor/4*(Psi(i,j+1)+Psi(i,j-1)+Psi(i+1,j)+Psi(i-1,j)+h^2*Zeta(i,j));
% 取增量绝对值的最大值
dPsi_max = max([dPsi_max abs(dPsi)]);
% 基点的新值
Psi(i,j) = Psi(i,j) + dPsi;
end
end
end
function [U_new,V_new,dU_max,dV_max] = Iteration_Velocity(Psi,U,V,h)
% 迭代速度
% Psi 流函数矩阵
% U,V 速度矩阵
% h 步长
% 使用 mesh 函数得到的 X,Y 得到的坐标系为
% i 行号从小到大代表直角坐标系中纵坐标从小到大
% j 列号从小到大代表直角坐标系中横坐标从小到大
% ψ_(row+1,col) 公式语境下的 ψ_(i,j+1)
Psi_up = MatrixTranslation(Psi,-1,0);
% ψ_(row-1,col) 公式语境下的 ψ_(i,j-1)
Psi_down = MatrixTranslation(Psi,1,0);
% ψ_(row,col+1) 公式语境下的 ψ_(i+1,j)
Psi_right = MatrixTranslation(Psi,0,-1);
% ψ_(row,col-1) 公式语境下的 ψ_(i-1,j)
Psi_left = MatrixTranslation(Psi,0,1);
% 公式语境下的 u_(i,j+1/2)
U_up = (Psi_up-Psi)/h;
% 公式语境下的 u_(i,j-1/2)
U_down = (Psi-Psi_down)/h;
% 公式语境下的 v_(i+1/2,j)
V_right = -(Psi_right-Psi)/h;
% 公式语境下的 v_(i-1/2,j)
V_left = -(Psi-Psi_left)/h;
U_tmp = 1/2*(U_down+U_up);
V_tmp = 1/2*(V_left+V_right);
U_new = U;
V_new = V;
U_new(2:size(U,1)-1,2:size(U,2)-1) = U_tmp(2:size(U,1)-1,2:size(U,2)-1);
V_new(2:size(V,1)-1,2:size(V,2)-1) = V_tmp(2:size(V,1)-1,2:size(V,2)-1);
dU_max = max(max(abs(U_new-U)));
dV_max = max(max(abs(V_new-V)));
end
% function [U_new,V_new,dU_max,dV_max] = Iteration_PressureGradient(Psi,U,V,h)
%
% end
% function [U_new,V_new,dU_max,dV_max] = Iteration_PoissonEqTerm_Sp(Psi,U,V,h)
%
% end
迭代前几步,contour(X,Y,Psi,50);
画图得到
到这里已经发散得很厉害了
之后就不用看了
看了很多遍了,实在觉得没有问题
我想想,SOR 涉及到三个变量
我现在的做法是,在 while 中对这三个变量分开迭代,每一个变量迭代的时候其他变量不变
如果我真的什么地方都没有错了的话,那就说明我不能在一个变量迭代的时候保持别人不变
合在一起求的代码
% 中山大学 19320053 廉嘉诚
clc;
clear;
% ---参数初始化---
% 雷诺数
Re = 10;
% 动力粘性系数
mu = 1/Re;
% 误差限度
error_limit = 1e-6;
% 误差
error = 9999;
% 迭代次数限度
iterationTimes_limit = 9999;
% 迭代次数
iterationTimes = 0;
% ---网格初始化---
% 步长
h = 0.01;
% 坐标系
x_border = [-0.5 0.5]';
y_border = [0 1]';
x = x_border(1):h:x_border(2);
y = y_border(1):h:y_border(2);
[X,Y] = meshgrid(x,y);
% 涡量场
Zeta = zeros(size(X));
Psi = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
for j = 1:1:size(X,2)
U(1,j) = 1;
end
figure();
% 获得 SOR 迭代法最佳松弛因子
factor = GetOptimalRelaxationFactor(size(Zeta,1),size(Zeta,2));
% 直到误差小于误差限度或者迭代次数超过迭代次数限度时才停止迭代
while error > error_limit && iterationTimes < iterationTimes_limit
dZeta_max = 0;
dPsi_max = 0;
dU_max = 0;
dV_max = 0;
% 迭代
for i = 1:1:size(Zeta,1)
for j = 1:1:size(Zeta,2)
% 边界条件
% 顶部的水平固壁边界
if i == 1
Zeta(i,j) = 2*(Psi(i,j)-Psi(i+1,j)+U(i,j)*h)/h^2;
continue;
% 底部的水平移动边界
elseif i == size(Zeta,1)
Zeta(i,j) = 2*(Psi(i-1,j)-Psi(i,j))/h^2;
continue;
end
% 左侧的竖直固壁边界
if j == 1
Zeta(i,j) = 2*(Psi(i,j)-Psi(i,j+1))/h^2;
continue;
% 右侧的竖直固壁边界
elseif j == size(Zeta,2)
Zeta(i,j) = 2*(Psi(i,j-1)-Psi(i,j))/h^2;
continue;
end
% 超松弛迭代
% 增量
dZeta = -factor*Zeta(i,j)+factor/4*((1-1/2*1/mu*h*U(i,j))*Zeta(i,j+1)+(1+1/2*1/mu*h*U(i,j))*Zeta(i,j-1)+(1-1/2*1/mu*h*V(i,j))*Zeta(i+1,j)+(1+1/2*1/mu*h*V(i,j))*Zeta(i-1,j));
% 取增量绝对值的最大值
dZeta_max = max([dZeta_max abs(dZeta)]);
% 基点的新值
Zeta(i,j) = Zeta(i,j) + dZeta;
% 增量
dPsi = -factor*Psi(i,j)+factor/4*(Psi(i,j+1)+Psi(i,j-1)+Psi(i+1,j)+Psi(i-1,j)+h^2*Zeta(i,j));
% 取增量绝对值的最大值
dPsi_max = max([dPsi_max abs(dPsi)]);
% 基点的新值
Psi(i,j) = Psi(i,j) + dPsi;
u_half_up = (Psi(i+1,j)-Psi(i,j))/h;
u_half_down = (Psi(i,j)-Psi(i-1,j))/h;
v_half_right = -(Psi(i,j+1)-Psi(i,j))/h;
v_half_left = -(Psi(i,j)-Psi(i,j-1))/h;
u_new = 1/2*(u_half_up+u_half_down);
v_new = 1/2*(v_half_right+v_half_left);
dU = u_new - U(i,j);
dV = v_new - V(i,j);
dU_max = max([dU_max abs(dU)]);
dV_max = max([dV_max abs(dU)]);
U(i,j) = u_new;
V(i,j) = v_new;
end
end
% 取最大误差
error = max([dZeta_max dPsi_max dU_max dV_max]);
% 迭代次数加 1
iterationTimes = iterationTimes + 1;
end
% 等高线
contour(X,Y,Psi,50);
shading interp;
function [factor] = GetOptimalRelaxationFactor(m,n)
% 获得 SOR 法最佳松弛因子
mu = 1/2*(cos(pi/m)+cos(pi/n));
factor = 2*(1-(1-mu^2)^0.5)/mu^2;
end
结果还是发散
我看别人对涡量使用 FTCS 是可以的
于是我也写了一个对涡量使用 FTCS 的
% 中山大学 19320053 廉嘉诚
clc;
clear;
% ---参数初始化---
% 雷诺数
Re = 10;
% 动力粘性系数
mu = 1/Re;
% 误差限度
error_limit = 1e-6;
% 误差
error = 9999;
% 迭代次数限度
iterationTimes_limit = 9999;
% 迭代次数
iterationTimes = 0;
% 网格步长
h = 0.01;
% 时间步长
dt = h^2/(4*mu);
% ---网格初始化---
% 坐标系
x_border = [-0.5 0.5]';
y_border = [0 1]';
x = x_border(1):h:x_border(2);
y = y_border(1):h:y_border(2);
[X,Y] = meshgrid(x,y);
% 涡量场
Zeta = zeros(size(X));
Zeta_old = zeros(size(X));
Psi = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
for j = 1:1:size(X,2)
U(1,j) = 1;
end
figure();
% 获得 SOR 迭代法最佳松弛因子
factor = GetOptimalRelaxationFactor(size(Zeta,1),size(Zeta,2));
% 直到误差小于误差限度或者迭代次数超过迭代次数限度时才停止迭代
while error > error_limit && iterationTimes < iterationTimes_limit
% 迭代
for i = 1:1:size(X,1)
for j = 1:1:size(X,2)
% 边界条件
% 速度和流函数的边界值保持不变,所以这里只有涡量的边界值更新
% 顶部的水平固壁边界
if i == 1
Zeta(i,j) = 2*(Psi(i,j)-Psi(i+1,j)+U(i,j)*h)/h^2;
continue;
% 底部的水平移动边界
elseif i == size(X,1)
Zeta(i,j) = 2*(Psi(i-1,j)-Psi(i,j))/h^2;
continue;
end
% 左侧的竖直固壁边界
if j == 1
Zeta(i,j) = 2*(Psi(i,j)-Psi(i,j+1))/h^2;
continue;
% 右侧的竖直固壁边界
elseif j == size(X,2)
Zeta(i,j) = 2*(Psi(i,j-1)-Psi(i,j))/h^2;
continue;
end
% 流函数 超松弛迭代
dPsi = -factor*Psi(i,j)+factor/4*(Psi(i,j+1)+Psi(i,j-1)+Psi(i+1,j)+Psi(i-1,j)+h^2*Zeta(i,j));
error = max([error abs(dPsi)]);
Psi(i,j) = Psi(i,j) + dPsi;
% 速度
U(i,j) = (Psi(i+1,j)-Psi(i-1,j))/(2*h);
V(i,j) = -(Psi(i,j+1)-Psi(i,j-1))/(2*h);
% 涡量 FTCS 格式
U_dZeta_dx = U(i,j)*(Zeta_old(i,j+1)-Zeta_old(i,j-1))/(2*h);
V_dZeta_dy = V(i,j)*(Zeta_old(i+1,j)-Zeta_old(i-1,j))/(2*h);
mu_Nabla_Zeta = mu*(Zeta_old(i,j+1)+Zeta_old(i,j-1)+Zeta_old(i+1,j)+Zeta_old(i-1,j)-4*Zeta_old(i,j))/h^2;
Zeta(i,j) = Zeta_old(i,j)+dt*(-U_dZeta_dx-V_dZeta_dy+mu_Nabla_Zeta);
end
end
Zeta_old = Zeta;
% 迭代次数加 1
iterationTimes = iterationTimes + 1;
end
% 等高线
contour(X,Y,Psi,50);
shading interp;
function [factor] = GetOptimalRelaxationFactor(m,n)
% 获得 SOR 法最佳松弛因子
mu = 1/2*(cos(pi/m)+cos(pi/n));
factor = 2*(1-(1-mu^2)^0.5)/mu^2;
end
但是还是发散……不懂
对各变量超松弛放在一起的方法加密网格,得到
唉……这个趋势是真的看不出来什么东西
我反复看了别人的计算
别人都没有在迭代公式中计算速度
https://www.zhihu.com/question/52835189
https://curiosityfluids.com/2016/03/14/streamfunction-vorticity-solution-lid-driven-cavity-flow/
虽然我觉得没有差别,但是我还是做了一个
% 中山大学 19320053 廉嘉诚
clc;
clear;
% ---参数初始化---
% 雷诺数
Re = 10;
% 动力粘性系数
mu = 1/Re;
% 误差限度
error_limit = 1e-6;
% 误差
error = 9999;
% 迭代次数限度
iterationTimes_limit = 9999;
% 迭代次数
iterationTimes = 0;
% 顶板速度
U_assume = 1;
% ---网格初始化---
% 步长
h = 0.005;
% 时间步长
dt = h^2/(4*mu);
% 坐标系
x_border = [-0.5 0.5]';
y_border = [0 1]';
x = x_border(1):h:x_border(2);
y = y_border(1):h:y_border(2);
[X,Y] = meshgrid(x,y);
% 涡量场
Zeta = zeros(size(X));
Psi = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
for j = 1:1:size(X,2)
U(1,j) = U_assume;
end
figure();
% 获得 SOR 迭代法最佳松弛因子
factor = GetOptimalRelaxationFactor(size(Zeta,1),size(Zeta,2));
% 直到误差小于误差限度或者迭代次数超过迭代次数限度时才停止迭代
while error > error_limit && iterationTimes < iterationTimes_limit
% 涡量 FTCS 格式
Zeta_right = MatrixTranslation(Zeta,0,1);
Zeta_left = MatrixTranslation(Zeta,0,-1);
Zeta_up = MatrixTranslation(Zeta,1,0);
Zeta_down = MatrixTranslation(Zeta,-1,0);
Psi_right = MatrixTranslation(Psi,0,1);
Psi_left = MatrixTranslation(Psi,0,-1);
Psi_up = MatrixTranslation(Psi,1,0);
Psi_down = MatrixTranslation(Psi,-1,0);
U_dZeta_dx = (Psi_up-Psi_down).*(Zeta_right-Zeta_left)/(4*h^2);
V_dZeta_dy = -(Psi_right-Psi_left).*(Zeta_up-Zeta_down)/(4*h^2);
mu_Nabla_Zeta = mu*(Zeta_right+Zeta_left+Zeta_up+Zeta_down-4*Zeta)/h^2;
Zeta = Zeta + dt*(-U_dZeta_dx-V_dZeta_dy+mu_Nabla_Zeta);
% 涡量边界条件
for i = 1:1:size(Zeta,1)
for j = 1:1:size(Zeta,2)
% 底部的水平移动边界
if i == 1
Zeta(i,j) = 2*(Psi(i,j)-Psi(i+1,j)+U_assume*h)/h^2;
continue;
% 顶部的水平固壁边界
elseif i == size(Zeta,1)
Zeta(i,j) = 2*(Psi(i-1,j)-Psi(i,j))/h^2;
continue;
end
% 左侧的竖直固壁边界
if j == 1
Zeta(i,j) = 2*(Psi(i,j)-Psi(i,j+1))/h^2;
continue;
% 右侧的竖直固壁边界
elseif j == size(Zeta,2)
Zeta(i,j) = 2*(Psi(i,j-1)-Psi(i,j))/h^2;
continue;
end
end
end
% 流函数 普通迭代
Psi_right = MatrixTranslation(Psi,0,1);
Psi_left = MatrixTranslation(Psi,0,-1);
Psi_up = MatrixTranslation(Psi,1,0);
Psi_down = MatrixTranslation(Psi,-1,0);
Psi_tmp = 1/4*(Psi_right+Psi_left+Psi_up+Psi_down+h^2*Zeta);
error = max(max(abs(Psi_tmp-Psi)));
Psi = Psi_tmp;
iterationTimes = iterationTimes + 1;
end
% 等高线
contour(X,Y,Psi,50);
shading interp;
function [factor] = GetOptimalRelaxationFactor(m,n)
% 获得 SOR 法最佳松弛因子
mu = 1/2*(cos(pi/m)+cos(pi/n));
factor = 2*(1-(1-mu^2)^0.5)/mu^2;
end
function [A] = MatrixTranslation(A,istep,jstep)
% 将矩阵在行号增大的方向上平移 istep 个单位,在列号增大的方向上平移 jstep 个单位
% 这个平移不是仿射变换,只是元素相对位置的平移
% 空余的位置用 0 补充
% 移动距离超出矩阵长度的会得到全零
if abs(istep) >= size(A,1) || abs(jstep) >= size(A,2)
A = zeros(size(A));
return;
end
if istep > 0
A = A(1+istep:size(A,1),:);
A = [A;zeros(istep,size(A,2))];
end
if istep < 0
A = A(1:size(A,1)+istep,:);
A = [zeros(-istep,size(A,2));A];
end
if jstep > 0
A = A(:,1+jstep:size(A,2));
A = [A zeros(size(A,1),jstep)];
end
if jstep < 0
A = A(:,1:size(A,2)+jstep);
A = [zeros(size(A,1),-jstep) A];
end
end
仍然发散
用回超松弛
% 中山大学 19320053 廉嘉诚
clc;
clear;
% ---参数初始化---
% 雷诺数
Re = 10;
% 动力粘性系数
mu = 1/Re;
% 误差限度
error_limit = 1e-6;
% 误差
error = 9999;
% 迭代次数限度
iterationTimes_limit = 9999;
% 迭代次数
iterationTimes = 0;
% 网格步长
h = 0.01;
% 时间步长
dt = h^2/(4*mu);
% 顶板速度
U_assume = 1;
% ---网格初始化---
% 坐标系
x_border = [-0.5 0.5]';
y_border = [0 1]';
x = x_border(1):h:x_border(2);
y = y_border(1):h:y_border(2);
[X,Y] = meshgrid(x,y);
% 涡量场
Zeta = zeros(size(X));
Psi = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
for j = 1:1:size(X,2)
U(1,j) = U_assume;
end
figure();
% 获得 SOR 迭代法最佳松弛因子
factor = GetOptimalRelaxationFactor(size(Zeta,1),size(Zeta,2));
% 直到误差小于误差限度或者迭代次数超过迭代次数限度时才停止迭代
while error > error_limit && iterationTimes < iterationTimes_limit
% 涡量 FTCS 格式
Zeta_right = MatrixTranslation(Zeta,0,1);
Zeta_left = MatrixTranslation(Zeta,0,-1);
Zeta_up = MatrixTranslation(Zeta,1,0);
Zeta_down = MatrixTranslation(Zeta,-1,0);
Psi_right = MatrixTranslation(Psi,0,1);
Psi_left = MatrixTranslation(Psi,0,-1);
Psi_up = MatrixTranslation(Psi,1,0);
Psi_down = MatrixTranslation(Psi,-1,0);
U_dZeta_dx = (Psi_up-Psi_down).*(Zeta_right-Zeta_left)/(4*h^2);
V_dZeta_dy = -(Psi_right-Psi_left).*(Zeta_up-Zeta_down)/(4*h^2);
mu_Nabla_Zeta = mu*(Zeta_right+Zeta_left+Zeta_up+Zeta_down-4*Zeta)/h^2;
Zeta = Zeta + dt*(-U_dZeta_dx-V_dZeta_dy+mu_Nabla_Zeta);
% 迭代
for i = 1:1:size(X,1)
for j = 1:1:size(X,2)
% 边界条件
% 速度和流函数的边界值保持不变,所以这里只有涡量的边界值更新
% 顶部的水平固壁边界
if i == 1
Zeta(i,j) = 2*(Psi(i,j)-Psi(i+1,j)+U_assume*h)/h^2;
continue;
% 底部的水平移动边界
elseif i == size(X,1)
Zeta(i,j) = 2*(Psi(i-1,j)-Psi(i,j))/h^2;
continue;
end
% 左侧的竖直固壁边界
if j == 1
Zeta(i,j) = 2*(Psi(i,j)-Psi(i,j+1))/h^2;
continue;
% 右侧的竖直固壁边界
elseif j == size(X,2)
Zeta(i,j) = 2*(Psi(i,j-1)-Psi(i,j))/h^2;
continue;
end
% 流函数 超松弛迭代
dPsi = -factor*Psi(i,j)+factor/4*(Psi(i,j+1)+Psi(i,j-1)+Psi(i+1,j)+Psi(i-1,j)+h^2*Zeta(i,j));
error = max([error abs(dPsi)]);
Psi(i,j) = Psi(i,j) + dPsi;
end
end
% 迭代次数加 1
iterationTimes = iterationTimes + 1;
% 等高线
contour(X,Y,Psi,50);
shading interp;
end
% 等高线
contour(X,Y,Psi,50);
shading interp;
function [factor] = GetOptimalRelaxationFactor(m,n)
% 获得 SOR 法最佳松弛因子
mu = 1/2*(cos(pi/m)+cos(pi/n));
factor = 2*(1-(1-mu^2)^0.5)/mu^2;
end
function [A] = MatrixTranslation(A,istep,jstep)
% 将矩阵在行号增大的方向上平移 istep 个单位,在列号增大的方向上平移 jstep 个单位
% 这个平移不是仿射变换,只是元素相对位置的平移
% 空余的位置用 0 补充
% 移动距离超出矩阵长度的会得到全零
if abs(istep) >= size(A,1) || abs(jstep) >= size(A,2)
A = zeros(size(A));
return;
end
if istep > 0
A = A(1+istep:size(A,1),:);
A = [A;zeros(istep,size(A,2))];
end
if istep < 0
A = A(1:size(A,1)+istep,:);
A = [zeros(-istep,size(A,2));A];
end
if jstep > 0
A = A(:,1+jstep:size(A,2));
A = [A zeros(size(A,1),jstep)];
end
if jstep < 0
A = A(:,1:size(A,2)+jstep);
A = [zeros(size(A,1),-jstep) A];
end
end
感觉结果都是一样的
我换了这么多格式,等高线图的趋势还是一样的,那肯定问题出在一个不随格式改变的地方
同时我觉得这个 FTCS 格式还不如我的超松弛快呢
搜到了别人包含可以跑的代码的文章
extension://bfdogplmndidlpjfhoijckpakkdjkkil/pdf/viewer.html?file=http%3A%2F%2Fakshaybatra.yolasite.com%2Fresources%2F2D%2520lid%2520diven%2520cavity%2520final%2520%2520report.pdf
%AuthorAKSHAY BATRA
%MAE 561 Computational Fluid Dynamics
%FINAL PROJECT - LID DRIVEN CAVITY FLOW IN RECATANGULAR CAVITY
%Due on Dec 12 2014.
%-------------------------------------------------------------------------
clear all
close all
clf;
nx=101;ny=101; nt=100000; re=1000; dt=0.001;% Settting the initial parameters
no_it=100000;% number of iterations
Beta=1.5;% relaxation factors
err=0.001;% parameter for SOR iteration
ds=.01;%dx=dy=ds
x=0:ds:1; y=0:ds:1;%dimensions of the cavity
t=0.0;
%-------------------------------------------------------------------------
phi=zeros(nx,ny); omega=zeros(nx,ny); % initializing the variables
u = zeros(nx,ny); v = zeros(nx,ny);
x2d=zeros(nx,ny); y2d=zeros(nx,ny);
b=zeros(nx,ny);p=zeros(nx,ny);pn=zeros(nx,ny);
w=zeros(nx,ny); %p-q/(nx-1),
%-------------------------------------------------------------------------
%Stream Function calculation
for t_step=1:nt % time steps starts
for iter=1:no_it % streamfunction calculation
w=phi; % by SOR iteration
for i=2:nx-1;
for j=2:ny-1
phi(i,j)=0.25*Beta*(phi(i+1,j)+phi(i-1,j)+phi(i,j+1)+phi(i,j-1)+ds*ds*omega(i,j))+(1.0-Beta)*phi(i,j);
end
end
Err=0.0;
for i=1:nx
for j=1:ny
Err=Err+abs(w(i,j)-phi(i,j));
end
end
if Err <= err,
break;
end % stop if iteration has converged
end
%--------------------------------------------------------------------------
%boundary conditions for the Vorticity
for i=2:nx-1
for j=2:ny-1
omega(i,1)=-2.0*phi(i,2)/(ds*ds); % bottom wall
omega(i,ny)=-2.0*phi(i,ny-1)/(ds*ds)-2.0/ds; % top wall
omega(1,j)=-2.0*phi(2,j)/(ds*ds); % right wall
omega(nx,j)=-2.0*phi(nx-1,j)/(ds*ds); % left wall
end
end
%--------------------------------------------------------------------------
% RHS Calculation
for i=2:nx-1;
for j=2:ny-1 % compute
w(i,j)=-0.25*((phi(i,j+1)-phi(i,j-1))*(omega(i+1,j)-omega(i-1,j))...
-(phi(i+1,j)-phi(i-1,j))*(omega(i,j+1)-omega(i,j-1)))/(ds*ds)...
+(1/re)*(omega(i+1,j)+omega(i-1,j)+omega(i,j+1)+omega(i,j-1)-4.0*omega(i,j))/(ds*ds);
end
end
%--------------------------------------------------------------------------
% Update the vorticity
omega(2:nx-1,2:ny-1)=omega(2:nx-1,2:ny-1)+dt*w(2:nx-1,2:ny-1);
t=t+dt; % increment the time
for i=1:nx
for j=1:ny
x2d(i,j)=x(i);
y2d(i,j)=y(j);
end
end
%-------------------------------------------------------------------------
%calculation of U and V
for i = 2:nx-1
for j = 2:ny-1
u(i,j)=(phi(i,j+1)-phi(i,j))/(2*ds);
v(i,j)=(phi(i+1,j)-phi(i,j))/(2*ds);
u(:,ny) = 1;
v(nx,:) =.02;
end
end
end
%--------------------------------------------------------------------------
%calculation of pressure
rhs=zeros(nx,ny);
for i=2:nx-1
for j=2:ny-1
rhs(i,j)=(((phi(i-1,j)-2*phi(i,j)+phi(i+1,j))/(ds*ds))...
*((phi(i,j-1)-2*phi(i,j)+phi(i,j+1))/(ds*ds)))...
- (phi(i+1,j+1)-phi(i+1,j-1)-phi(i-1,j+1)+phi(i-1,j-1))/(4*(ds*ds));
p(i,j)=(.25*(pn(i+1,j)+pn(i-1,j) + pn(i,j+1)+pn(i,j-1))- 0.5*((rhs(i,j)*ds^2*ds^2)));
end
pn=p;
end
%--------------------------------------------------------------------------
% Visualization of the results
figure(1)
contourf(x2d,y2d,omega,[-3:1:-1 -0.5 0.0 0.5 1:1:5 ]),xlabel('nx'),...
ylabel('ny'),title('Vorticity');axis('square','tight');colorbar
title('Vorticity') % plot vorticity
figure(2)
contour(x2d,y2d,phi,[10^-10 10^-7 10^-5 10^-4 0.0100...
0.0300 0.0500 0.0700 0.0900 0.100 0.1100 0.1150 0.1175]),xlabel('nx'),
ylabel('ny'),title('stream function');axis('square','tight');colorbar %streamfunction
figure(3)
contourf(x2d,y2d,u),xlabel('nx'),ylabel('ny'),...
title('U-velocity');axis('square','tight');colorbar
figure(4)
contourf(x2d,y2d,v),xlabel('nx'),ylabel('ny'),...
title('V-velocity');axis('square','tight');colorbar
figure(5)
contourf(x2d,y2d,p,([-2.0:.01:2])),xlabel('nx'),ylabel('ny'),...
title('pressure');
figure(6)
quiver (x2d,y2d,u,v)...,xlabel('nx'),ylabel('ny'),title('VelocityVectour Plot'); axis([0 1 0 1]),axis('square')
%-------------------------------------------------------------------------
%I have been able to get the vorticies in the stream function contour at the corner but
%they are really small(for re 100). I have run the solution to 100,000 iteration at a
%time step of .001. It took 9-10 hours for the solution to compute.Then
%similarlyfor the Re 1000 took even longer but i was able to get the vorticies.
别人的结果是真的漂亮
我发现我跟别人的思路主要不同就在于,别人是在每一个时间步内都要把流函数的迭代格式迭代若干不,一直到流函数收敛,而我是对于每一个时间步,只对流函数迭代一次
这是正确的,因为实际上迭代格式迭代到收敛才代表这个方程解出来了
照着他的写,我写出来就不一样……佛了
正确的是
我写的是
我在右侧比他少了一个负号
噢……我知道了,是我泰勒推错了
即使如此,我改了之后还是写出不出来,会卡在流函数的超松弛迭代那一步
% 中山大学 19320053 廉嘉诚
clc;
clear;
% ---参数初始化---
% 雷诺数
Re = 10;
% 动力粘性系数
mu = 1/Re;
% 误差限度
FTCS_error_limit = 1e-6;
SOR_error_limit = 1e-3;
% 误差
error = 9999;
% 迭代次数限度
iterationTimes_limit = 9999;
% 迭代次数
iterationTimes = 0;
% 题设顶部移动速度
U_assume = 1;
% ---网格初始化---
% 步长
h = 0.01;
% 时间步长
dt = 0.001;
% 涡量最大迭代次数
MaxTimes = 1e5;
% 坐标系
x_border = [-0.5 0.5]';
y_border = [0 1]';
x = x_border(1):h:x_border(2);
y = y_border(1):h:y_border(2);
[X,Y] = meshgrid(x,y);
% 涡量场
Zeta = zeros(size(X));
Zeta_old = zeros(size(X));
Psi = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
for j = 1:1:size(X,2)
U(1,j) = U_assume;
end
figure();
% 获得 SOR 迭代法最佳松弛因子
% factor = GetOptimalRelaxationFactor(size(Zeta,1),size(Zeta,2));
factor = 1.5;
% 开始求解
for times = 1:1:MaxTimes
while true
% 流函数 超松弛迭代
% 内点
dPsi_max = 0;
for i = 2:1:size(Zeta,1)-1
for j = 2:1:size(Zeta,2)-1
% 增量
dPsi = -factor*Psi(i,j)+factor/4*(Psi(i,j+1)+Psi(i,j-1)+Psi(i+1,j)+Psi(i-1,j)+h^2*Zeta(i,j));
% 取增量绝对值的最大值
dPsi_max = max([dPsi_max abs(dPsi)]);
% 基点的新值
Psi(i,j) = Psi(i,j) + dPsi;
end
end
% 直到误差小于一定限度,流函数的迭代方程收敛,才能进入涡量的迭代
if dPsi_max < SOR_error_limit
break;
end
end
% 涡量 FTCS 格式
% 边界点(跳过角点)
for j = 2:1:size(Zeta,2)-1
Zeta(1,j) = 2*(-Psi(i+1,j)+U_assume*h)/h^2;
Zeta(size(Zeta,1),j) = -2*Psi(i-1,j)/h^2;
end
for i = 2:1:size(Zeta,1)-1
Zeta(i,1) = -2*Psi(i,j+1)/h^2;
Zeta(i,size(Zeta,2)) = -2*Psi(i,j-1)/h^2;
end
% 内点
% Zeta_right = MatrixTranslation(Zeta,0,1);
% Zeta_left = MatrixTranslation(Zeta,0,-1);
% Zeta_up = MatrixTranslation(Zeta,1,0);
% Zeta_down = MatrixTranslation(Zeta,-1,0);
%
% Psi_right = MatrixTranslation(Psi,0,1);
% Psi_left = MatrixTranslation(Psi,0,-1);
% Psi_up = MatrixTranslation(Psi,1,0);
% Psi_down = MatrixTranslation(Psi,-1,0);
%
% U_dZeta_dx = (Psi_up-Psi_down).*(Zeta_right-Zeta_left)/(4*h^2);
% V_dZeta_dy = -(Psi_right-Psi_left).*(Zeta_up-Zeta_down)/(4*h^2);
% mu_Nabla_Zeta = mu*(Zeta_right+Zeta_left+Zeta_up+Zeta_down-4*Zeta)/h^2;
% Zeta_tmp = Zeta + dt*(-U_dZeta_dx-V_dZeta_dy+mu_Nabla_Zeta);
% Zeta(2:size(Zeta,1)-1,2:size(Zeta,2)-1) = Zeta_tmp(2:size(Zeta,1)-1,2:size(Zeta,2)-1);
Zeta_old = Zeta;
for i = 2:1:size(Zeta,1)-1
for j = 2:1:size(Zeta,2)-1
dZeta = dt*(-(Psi(i+1,j)-Psi(i-1,j))*(Zeta_old(i,j+1)-Zeta_old(i,j-1))/(4*h^2)...
+(Psi(i,j+1)-Psi(i,j-1))*(Zeta_old(i+1,j)-Zeta_old(i-1,j))/(4*h^2)...
+mu*(Zeta_old(i,j+1)+Zeta_old(i,j-1)+Zeta_old(i+1,j)+Zeta_old(i-1,j)-4*Zeta_old(i,j))/h^2);
Zeta_old(i,j) = Zeta(i,j) + dZeta;
end
end
Zeta(2:size(Zeta,1)-1,2:size(Zeta,2)-1) = Zeta_old(2:size(Zeta,1)-1,2:size(Zeta,2)-1);
end
% 等高线
contour(X,Y,Psi,50);
shading interp;
function [factor] = GetOptimalRelaxationFactor(m,n)
% 获得 SOR 法最佳松弛因子
mu = 1/2*(cos(pi/m)+cos(pi/n));
factor = 2*(1-(1-mu^2)^0.5)/mu^2;
end
function [A] = MatrixTranslation(A,istep,jstep)
% 将矩阵在行号增大的方向上平移 istep 个单位,在列号增大的方向上平移 jstep 个单位
% 这个平移不是仿射变换,只是元素相对位置的平移
% 空余的位置用 0 补充
% 移动距离超出矩阵长度的会得到全零
if abs(istep) >= size(A,1) || abs(jstep) >= size(A,2)
A = zeros(size(A));
return;
end
if istep > 0
A = A(1+istep:size(A,1),:);
A = [A;zeros(istep,size(A,2))];
end
if istep < 0
A = A(1:size(A,1)+istep,:);
A = [zeros(-istep,size(A,2));A];
end
if jstep > 0
A = A(:,1+jstep:size(A,2));
A = [A zeros(size(A,1),jstep)];
end
if jstep < 0
A = A(:,1:size(A,2)+jstep);
A = [zeros(size(A,1),-jstep) A];
end
end
照着答案写的 FTCS 也还是不行
Zeta_old = Zeta;
for i = 2:1:length-1
for j = 2:1:size(Zeta,2)-1
dZeta = -0.25*((Psi(i,j+1)-Psi(i,j-1))*(Zeta(i+1,j)-Zeta(i-1,j))...
-(Psi(i+1,j)-Psi(i-1,j))*(Zeta(i,j+1)-Zeta(i,j-1)))/(h*h)...
+mu*(Zeta(i+1,j)+Zeta(i-1,j)+Zeta(i,j+1)+Zeta(i,j-1)-4.0*Zeta(i,j))/(h*h);
Zeta_old(i,j) = Zeta(i,j) + dt*dZeta;
end
end
Zeta = Zeta_old;
再改,我直接全部都复制他的
% 中山大学 19320053 廉嘉诚
clc;
clear;
% ---参数初始化---
% 雷诺数
Re = 10;
% 动力粘性系数
mu = 1/Re;
% 误差限度
SOR_error_limit = 1e-3;
% 迭代次数限度
FTCS_MaxTimes = 1e5;
SOR_MaxTimes = 1e5;
% 题设顶部移动速度
U_assume = 1;
% ---网格初始化---
% 步长
h = 0.01;
% 时间步长
dt = 0.001;
% 坐标系
x_border = [-0.5 0.5]';
y_border = [0 1]';
x = x_border(1):h:x_border(2);
y = y_border(1):h:y_border(2);
[X,Y] = meshgrid(x,y);
% 矩阵长度
length = size(X,1);
% 涡量场
Zeta = zeros(size(X));
Psi = zeros(size(X));
tmp = zeros(size(X));
figure();
% 获得 SOR 迭代法最佳松弛因子
% factor = GetOptimalRelaxationFactor(length,length);
factor = 1.5;
% 开始求解
for FTCS_times = 1:1:FTCS_MaxTimes
for SOR_times = 1:1:SOR_MaxTimes
% % 流函数 超松弛迭代
%
% % 内点
%
% dPsi_max = 0;
%
% for i = 2:1:length-1
% for j = 2:1:length-1
%
% % 增量
% dPsi = -factor*Psi(i,j)+factor/4*(Psi(i,j+1)+Psi(i,j-1)+Psi(i+1,j)+Psi(i-1,j)+h^2*Zeta(i,j));
% % 取增量绝对值的最大值
% dPsi_max = max([dPsi_max abs(dPsi)]);
% % 基点的新值
% Psi(i,j) = Psi(i,j) + dPsi;
% end
% end
%
% % 直到误差小于一定限度,流函数的迭代方程收敛,才能进入涡量的迭代
% if dPsi_max < SOR_error_limit
% break;
% end
tmp = Psi; % by SOR iteration
for i=2:length-1;
for j=2:length-1
Psi(i,j)=0.25*factor*(Psi(i+1,j)+Psi(i-1,j)+Psi(i,j+1)+Psi(i,j-1)+h*h*Zeta(i,j))+(1.0-factor)*Psi(i,j);
end
end
Err=0.0;
for i=1:length
for j=1:length
Err=Err+abs(tmp(i,j)-Psi(i,j));
end
end
if Err <= SOR_error_limit
break;
end % stop if iteration has converged
end
% 涡量 FTCS 格式
% 边界点(跳过角点)
for i = 2:1:length-1
Zeta(i,1) = -2.0*Psi(i,2)/(h*h);
Zeta(i,length) = -2.0*Psi(i,length-1)/(h*h)-2.0*U_assume/h;
end
for j = 2:1:length-1
Zeta(1,j) = -2.0*Psi(2,j)/(h*h);
Zeta(length,j) = -2.0*Psi(length-1,j)/(h*h);
end
% 内点
% Zeta_right = MatrixTranslation(Zeta,1,0);
% Zeta_left = MatrixTranslation(Zeta,-1,0);
% Zeta_up = MatrixTranslation(Zeta,0,1);
% Zeta_down = MatrixTranslation(Zeta,0,-1);
%
% Psi_right = MatrixTranslation(Psi,1,0);
% Psi_left = MatrixTranslation(Psi,-1,0);
% Psi_up = MatrixTranslation(Psi,0,1);
% Psi_down = MatrixTranslation(Psi,0,-1);
%
% U_dZeta_dx = (Psi_up-Psi_down).*(Zeta_right-Zeta_left)/(4*h^2);
% V_dZeta_dy = -(Psi_right-Psi_left).*(Zeta_up-Zeta_down)/(4*h^2);
% mu_Nabla_Zeta = mu*(Zeta_right+Zeta_left+Zeta_up+Zeta_down-4*Zeta)/h^2;
% Zeta_tmp = Zeta + dt*(-U_dZeta_dx-V_dZeta_dy+mu_Nabla_Zeta);
% Zeta(2:length-1,2:length-1) = Zeta_tmp(2:length-1,2:length-1);
for i=2:length-1;
for j=2:length-1 % compute
tmp(i,j) = -0.25*((Psi(i,j+1)-Psi(i,j-1))*(Zeta(i+1,j)-Zeta(i-1,j))...
-(Psi(i+1,j)-Psi(i-1,j))*(Zeta(i,j+1)-Zeta(i,j-1)))/(h*h)...
+mu*(Zeta(i+1,j)+Zeta(i-1,j)+Zeta(i,j+1)+Zeta(i,j-1)-4.0*Zeta(i,j))/(h*h);
end
end
Zeta(2:length-1,2:length-1) = Zeta(2:length-1,2:length-1)+dt*tmp(2:length-1,2:length-1);
end
% 等高线
contour(X,Y,Psi,50);
shading interp;
function [factor] = GetOptimalRelaxationFactor(m,n)
% 获得 SOR 法最佳松弛因子
mu = 1/2*(cos(pi/m)+cos(pi/n));
factor = 2*(1-(1-mu^2)^0.5)/mu^2;
end
function [A] = MatrixTranslation(A,xstep,ystep)
% 将矩阵在 x 方向上平移 xstep 个单位,在 y 方向上平移 ystep 个单位
% 这个平移不是仿射变换,只是元素相对位置的平移
% 空余的位置用 0 补充
% 移动距离超出矩阵长度的会得到全零
if abs(xstep) >= size(A,1) || abs(ystep) >= size(A,2)
A = zeros(size(A));
return;
end
A = A;
if xstep > 0
A = A(:,1:size(A,2)-xstep);
A = [zeros(size(A,1),xstep) A];
end
if xstep < 0
A = A(:,1-xstep:size(A,2));
A = [A zeros(size(A,1),-xstep)];
end
if ystep > 0
A = A(1+ystep:size(A,1),:);
A = [A;zeros(ystep,size(A,2))];
end
if ystep < 0
A = A(1:size(A,1)+ystep,:);
A = [zeros(-ystep,size(A,2));A];
end
end
还是不行……太怪了
后面试出来是我雷诺数太小了,设了 Re = 1000 就好了
更进一步,都用我自己写的
% 中山大学 19320053 廉嘉诚
clc;
clear;
% ---参数初始化---
% 雷诺数
Re = 1000;
% 动力粘性系数
mu = 1/Re;
% 误差限度
SOR_error_limit = 1e-3;
% 迭代次数限度
FTCS_MaxTimes = 1e5;
SOR_MaxTimes = 1e5;
% 题设顶部移动速度
U_assume = 1;
% ---网格初始化---
% 步长
h = 0.01;
% 时间步长
dt = 0.001;
% 坐标系
x_border = [-0.5 0.5]';
y_border = [0 1]';
x = x_border(1):h:x_border(2);
y = y_border(1):h:y_border(2);
[X,Y] = meshgrid(x,y);
% 矩阵长度
length = size(X,1);
% 涡量场
Zeta = zeros(size(X));
Psi = zeros(size(X));
tmp = zeros(size(X));
figure();
% 获得 SOR 迭代法最佳松弛因子
% factor = GetOptimalRelaxationFactor(length,length);
factor = 1.5;
% 开始求解
for FTCS_times = 1:1:FTCS_MaxTimes
for SOR_times = 1:1:SOR_MaxTimes
% 流函数 超松弛迭代
% 内点
dPsi_max = 0;
for i = 2:1:length-1
for j = 2:1:length-1
% 增量
dPsi = -factor*Psi(i,j)+factor/4*(Psi(i,j+1)+Psi(i,j-1)+Psi(i+1,j)+Psi(i-1,j)+h^2*Zeta(i,j));
% 取增量绝对值的最大值
dPsi_max = max([dPsi_max abs(dPsi)]);
% 基点的新值
Psi(i,j) = Psi(i,j) + dPsi;
end
end
% 直到误差小于一定限度,流函数的迭代方程收敛,才能进入涡量的迭代
if dPsi_max < SOR_error_limit
break;
end
end
% 涡量 FTCS 格式
% 边界点(跳过角点)
for i = 2:1:length-1
Zeta(i,1) = -2.0*Psi(i,2)/(h*h);
Zeta(i,length) = -2.0*Psi(i,length-1)/(h*h)-2.0*U_assume/h;
end
for j = 2:1:length-1
Zeta(1,j) = -2.0*Psi(2,j)/(h*h);
Zeta(length,j) = -2.0*Psi(length-1,j)/(h*h);
end
% 内点
Zeta_right = MatrixTranslation(Zeta,1,0);
Zeta_left = MatrixTranslation(Zeta,-1,0);
Zeta_up = MatrixTranslation(Zeta,0,1);
Zeta_down = MatrixTranslation(Zeta,0,-1);
Psi_right = MatrixTranslation(Psi,1,0);
Psi_left = MatrixTranslation(Psi,-1,0);
Psi_up = MatrixTranslation(Psi,0,1);
Psi_down = MatrixTranslation(Psi,0,-1);
U_dZeta_dx = (Psi_up-Psi_down).*(Zeta_right-Zeta_left)/(4*h^2);
V_dZeta_dy = -(Psi_right-Psi_left).*(Zeta_up-Zeta_down)/(4*h^2);
mu_Nabla_Zeta = mu*(Zeta_right+Zeta_left+Zeta_up+Zeta_down-4*Zeta)/h^2;
Zeta_tmp = Zeta + dt*(-U_dZeta_dx-V_dZeta_dy+mu_Nabla_Zeta);
Zeta(2:length-1,2:length-1) = Zeta_tmp(2:length-1,2:length-1);
end
% 等高线
contourf(Y,X,Psi,15);
shading interp;
function [factor] = GetOptimalRelaxationFactor(m,n)
% 获得 SOR 法最佳松弛因子
mu = 1/2*(cos(pi/m)+cos(pi/n));
factor = 2*(1-(1-mu^2)^0.5)/mu^2;
end
function [A] = MatrixTranslation(A,xstep,ystep)
% 将矩阵在 x 方向上平移 xstep 个单位,在 y 方向上平移 ystep 个单位
% 这个平移不是仿射变换,只是元素相对位置的平移
% 空余的位置用 0 补充
% 移动距离超出矩阵长度的会得到全零
if abs(xstep) >= size(A,1) || abs(ystep) >= size(A,2)
A = zeros(size(A));
return;
end
A = A;
if xstep > 0
A = A(:,1:size(A,2)-xstep);
A = [zeros(size(A,1),xstep) A];
end
if xstep < 0
A = A(:,1-xstep:size(A,2));
A = [A zeros(size(A,1),-xstep)];
end
if ystep > 0
A = A(1+ystep:size(A,1),:);
A = [A;zeros(ystep,size(A,2))];
end
if ystep < 0
A = A(1:size(A,1)+ystep,:);
A = [zeros(-ystep,size(A,2));A];
end
end
图片输出方式改一下就好了
这个时候输出的 dPsi_max = 8.89e-10
如果我再回来使用两个超松弛,那依然是发散的
% 中山大学 19320053 廉嘉诚
clc;
clear;
% ---参数初始化---
% 雷诺数
Re = 1000;
% 动力粘性系数
mu = 1/Re;
% 误差限度
SOR_error_limit = 1e-3;
% 迭代次数限度
FTCS_MaxTimes = 1e5;
SOR_MaxTimes = 1e5;
% 题设顶部移动速度
U_assume = 1;
% ---网格初始化---
% 步长
h = 0.01;
% 时间步长
dt = 0.001;
% 坐标系
x_border = [-0.5 0.5]';
y_border = [0 1]';
x = x_border(1):h:x_border(2);
y = y_border(1):h:y_border(2);
[X,Y] = meshgrid(x,y);
% 矩阵长度
length = size(X,1);
% 涡量场
Zeta = zeros(size(X));
Psi = zeros(size(X));
tmp = zeros(size(X));
figure();
% 获得 SOR 迭代法最佳松弛因子
% factor = GetOptimalRelaxationFactor(length,length);
factor = 1.5;
% 开始求解
for FTCS_times = 1:1:FTCS_MaxTimes
for SOR_times = 1:1:SOR_MaxTimes
% 流函数 超松弛迭代
% 内点
dPsi_max = 0;
for i = 2:1:length-1
for j = 2:1:length-1
% 增量
dPsi = -factor*Psi(i,j)+factor/4*(Psi(i,j+1)+Psi(i,j-1)+Psi(i+1,j)+Psi(i-1,j)+h^2*Zeta(i,j));
% 取增量绝对值的最大值
dPsi_max = max([dPsi_max abs(dPsi)]);
% 基点的新值
Psi(i,j) = Psi(i,j) + dPsi;
end
end
% 直到误差小于一定限度,流函数的迭代方程收敛,才能进入涡量的迭代
if dPsi_max < SOR_error_limit
break;
end
end
% 速度
Psi_right = MatrixTranslation(Psi,1,0);
Psi_left = MatrixTranslation(Psi,-1,0);
Psi_up = MatrixTranslation(Psi,0,1);
Psi_down = MatrixTranslation(Psi,0,-1);
U_tmp = (Psi_up-Psi_down)/(2*h);
V_tmp = -(Psi_right-Psi_left)/(2*h);
U(2:length-1,2:length-1) = U_tmp(2:length-1,2:length-1);
V(2:length-1,2:length-1) = V_tmp(2:length-1,2:length-1);
% 涡量 超松弛迭代
% 边界点(跳过角点)
for i = 2:1:length-1
Zeta(i,1) = -2.0*Psi(i,2)/(h*h);
Zeta(i,length) = -2.0*Psi(i,length-1)/(h*h)-2.0*U_assume/h;
end
for j = 2:1:length-1
Zeta(1,j) = -2.0*Psi(2,j)/(h*h);
Zeta(length,j) = -2.0*Psi(length-1,j)/(h*h);
end
% 涡量
% 内点
for i = 2:1:length-1
for j = 2:1:length-1
dZeta = -factor*Zeta(i,j)...
+factor/4*(...
(1-1/2*1/mu*h*U(i,j))*Zeta(i+1,j)...
+(1+1/2*1/mu*h*U(i,j))*Zeta(i-1,j)...
+(1-1/2*1/mu*h*V(i,j))*Zeta(i,j+1)...
+(1+1/2*1/mu*h*V(i,j))*Zeta(i,j-1));
Zeta(i,j) = Zeta(i,j) + dZeta;
end
end
end
% 等高线
contourf(Y,X,Psi,15);
shading interp;
function [factor] = GetOptimalRelaxationFactor(m,n)
% 获得 SOR 法最佳松弛因子
mu = 1/2*(cos(pi/m)+cos(pi/n));
factor = 2*(1-(1-mu^2)^0.5)/mu^2;
end
function [A] = MatrixTranslation(A,xstep,ystep)
% 将矩阵在 x 方向上平移 xstep 个单位,在 y 方向上平移 ystep 个单位
% 这个平移不是仿射变换,只是元素相对位置的平移
% 空余的位置用 0 补充
% 移动距离超出矩阵长度的会得到全零
if abs(xstep) >= size(A,1) || abs(ystep) >= size(A,2)
A = zeros(size(A));
return;
end
A = A;
if xstep > 0
A = A(:,1:size(A,2)-xstep);
A = [zeros(size(A,1),xstep) A];
end
if xstep < 0
A = A(:,1-xstep:size(A,2));
A = [A zeros(size(A,1),-xstep)];
end
if ystep > 0
A = A(1+ystep:size(A,1),:);
A = [A;zeros(ystep,size(A,2))];
end
if ystep < 0
A = A(1:size(A,1)+ystep,:);
A = [zeros(-ystep,size(A,2));A];
end
end
那就这样吧hhhh起码能算出来了,而且也有我自己做的
之后我灵光一闪,想到,既然一个超松弛要迭代到收敛才能进行下一步,那我是不是可以在一个循环体里面一前一后放两个超松弛,它们都收敛了再进入下一个循环,于是我写了这样的代码
可惜还是发散,那我就没辙了,理论知识不足
% 中山大学 19320053 廉嘉诚
clc;
clf;
clear;
% ---参数初始化---
% 流体密度
rho = 1e3;
% 雷诺数
Re = 3200;
% 动力粘性系数
mu = 1/Re;
% 误差限度
SOR_error_limit = 1e-3;
% 迭代次数限度
MaxTimes = 1e5;
SOR_MaxTimes = 1e5;
% 题设顶部移动速度
U_assume = 1;
% ---网格初始化---
% 步长
h = 0.01;
% 时间步长
dt = 0.001;
% 坐标系
x_border = [-0.5 0.5]';
y_border = [0 1]';
x = x_border(1):h:x_border(2);
y = y_border(1):h:y_border(2);
[X,Y] = meshgrid(y,x);
% 矩阵长度
length = size(X,1);
% 场
Zeta = zeros(size(X));
Psi = zeros(size(X));
P = zeros(size(X));
PG = zeros([length 4]); % 1 左边界 2 右边界 3 下边界 4 上边界
Sp = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
U1 = zeros(size(X));
V1 = zeros(size(X));
% 缓存
tmp = zeros(size(X));
% 获得 SOR 迭代法最佳松弛因子
factor = GetOptimalRelaxationFactor(length,length);
% 开始求解
for times = 1:1:MaxTimes
% 流函数 超松弛迭代
for Psi_SOR_times = 1:1:SOR_MaxTimes
% 内点
dPsi_max = 0;
for i = 2:1:length-1
for j = 2:1:length-1
% 增量
dPsi = -factor*Psi(i,j)...
+factor/4*(...
Psi(i,j+1)...
+Psi(i,j-1)...
+Psi(i+1,j)...
+Psi(i-1,j)...
+h^2*Zeta(i,j));
% 取增量绝对值的最大值
dPsi_max = max([dPsi_max abs(dPsi)]);
% 基点的新值
Psi(i,j) = Psi(i,j) + dPsi;
end
end
% 直到误差小于一定限度,流函数的迭代方程收敛,才能进入涡量的迭代
if dPsi_max < SOR_error_limit
break;
end
end
% 涡量 超松弛迭代
% 速度
Psi_right = MatrixTranslation(Psi,1,0);
Psi_left = MatrixTranslation(Psi,-1,0);
Psi_up = MatrixTranslation(Psi,0,1);
Psi_down = MatrixTranslation(Psi,0,-1);
U_tmp = (Psi_up-Psi_down)/(2*h);
V_tmp = -(Psi_right-Psi_left)/(2*h);
U(2:length-1,2:length-1) = U_tmp(2:length-1,2:length-1);
V(2:length-1,2:length-1) = V_tmp(2:length-1,2:length-1);
for Zeta_SOR_times = 1:1:SOR_MaxTimes
dZeta_max = 0;
% 边界点(跳过角点)
for i = 2:1:length-1
% 下侧
dZeta = -2.0*Psi(i,2)/(h*h)+2.0*U_assume/h-Zeta(i,1);
dZeta_max = max([dZeta_max abs(dZeta)]);
Zeta(i,1) = Zeta(i,1) + dZeta;
% 上侧
dZeta = -2.0*Psi(i,length-1)/(h*h)-Zeta(i,length);
dZeta_max = max([dZeta_max abs(dZeta)]);
Zeta(i,length) = Zeta(i,length) + dZeta;
end
for j = 2:1:length-1
% 左侧
dZeta = -2.0*Psi(2,j)/(h*h)-Zeta(1,j);
dZeta_max = max([dZeta_max abs(dZeta)]);
Zeta(1,j) = Zeta(1,j) + dZeta;
% 右侧
dZeta = -2.0*Psi(length-1,j)/(h*h)-Zeta(length,j);
dZeta_max = max([dZeta_max abs(dZeta)]);
Zeta(length,j) = Zeta(length,j) + dZeta;
end
% 内点
for i = 2:1:length-1
for j = 2:1:length-1
dZeta = -factor*Zeta(i,j)...
+factor/4*(...
(1-1/2*1/mu*h*U(i,j))*Zeta(i+1,j)...
+(1+1/2*1/mu*h*U(i,j))*Zeta(i-1,j)...
+(1-1/2*1/mu*h*V(i,j))*Zeta(i,j+1)...
+(1+1/2*1/mu*h*V(i,j))*Zeta(i,j-1));
dZeta_max = max([dZeta_max abs(dZeta)]);
Zeta(i,j) = Zeta(i,j) + dZeta;
end
end
% 直到误差小于一定限度,流函数的迭代方程收敛,才能进入涡量的迭代
if dZeta_max < SOR_error_limit
break;
end
end
end
% 流速
U = (Psi_up-Psi_down)/(2*h);
V = -(Psi_right-Psi_left)/(2*h);
% 压强梯度
% 边界点(跳过角点)
for i = 2:1:length-1
% 下侧
PG(i,3) = rho/h^2*mu*V(i,2);
% 上侧
PG(i,4) = rho/h^2*mu*V(i,length-1);;
end
for j = 2:1:length-1
% 左侧
PG(j,1) = rho/h^2*mu*U(2,j);
% 右侧
PG(j,2) = rho/h^2*mu*U(length-1,j);
end
% 压强 超松弛迭代
Psi_right_up = MatrixTranslation(Psi,1,1);
Psi_right_down = MatrixTranslation(Psi,1,-1);
Psi_left_up = MatrixTranslation(Psi,-1,1);
Psi_left_down = MatrixTranslation(Psi,-1,-1);
Sp = 2*rho/h^2*(...
(Psi_right-2*Psi+Psi_left)*(Psi_up-2*Psi+Psi_down) ...
-(Psi_right_up-Psi_right_down-Psi_left_up+Psi_left_down)/4);
for P_SOR_times = 1:1:SOR_MaxTimes
dP_max = 0;
for i = 1:1:length
for j = 1:1:length
% 跳过角点
if i == 1 || i == length
if j == 1 || j == length
continue;
end
end
p1 = P(i,j);
% 边界点
% 下侧
if j == 1
p1 = P(i,2)-PG(i,3)*h;
continue;
% 上侧
elseif j == length
p1 = P(i,length-1)+PG(i,4)*h;
continue;
end
% 左侧
if i == 1
p1 = P(2,j)-PG(j,1)*h;
continue;
% 右侧
elseif i == length
p1 = P(length-1,j)+PG(j,2)*h;
continue;
end
% 内点
p2 = (...
P(i,j+1)...
+P(i,j-1)...
+P(i+1,j)...
+P(i-1,j)...
+h^2*Sp(i,j));
dP = -factor*p1+factor/4*p2;
% 取增量绝对值的最大值
dP_max = max([dP_max abs(dP)]);
% 基点的新值
P(i,j) = P(i,j) + dP;
end
end
% 直到误差小于一定限度,流函数的迭代方程收敛,才能进入涡量的迭代
if dP_max < SOR_error_limit
break;
end
end
% 流函数等高线
figure(1);
clf;
contour(Y,X,Psi,Psi(floor(length/2),:));
shading interp;
hold on;
contour(Y,X,Psi,Psi(:,floor(6*length/7)));
hold off;
title('流函数等高线图');
xlabel('x');
ylabel('y');
axis('square','tight');
colorbar;
% 涡量等高线
figure(2);
clf;
hold on;
contour(Y,X,Zeta,Zeta(floor(length/2),:));
hold off;
shading interp;
title('涡量等高线图');
xlabel('x');
ylabel('y');
axis('square','tight');
colorbar;
% 水平速度等高线
figure(3);
clf;
hold on;
contour(Y,X,U,U(:,floor(length/5)));
contour(Y,X,U,U(:,floor(2*length/5)));
contour(Y,X,U,U(:,floor(3*length/5)));
contour(Y,X,U,U(:,floor(4*length/5)));
hold off;
shading interp;
title('水平速度等高线图');
xlabel('x');
ylabel('y');
axis('square','tight');
colorbar;
% 竖直速度等高线
figure(4);
clf;
hold on;
contour(Y,X,V,V(floor(length/5),:));
contour(Y,X,V,V(floor(2*length/5),:));
contour(Y,X,V,V(floor(3*length/5),:));
contour(Y,X,V,V(floor(4*length/5),:));
hold off;
shading interp;
title('竖直速度等高线图');
xlabel('x');
ylabel('y');
axis('square','tight');
colorbar;
% 压强等高线
figure(4);
clf;
hold on;
contour(Y,X,P,P(floor(length/2),:));
contour(Y,X,P,P(floor(length/4),:));
contour(Y,X,P,P(floor(3*length/4),:));
hold off;
shading interp;
title('压强等高线图');
xlabel('x');
ylabel('y');
axis('square','tight');
colorbar;
function [factor] = GetOptimalRelaxationFactor(m,n)
% 获得 SOR 法最佳松弛因子
mu = 1/2*(cos(pi/m)+cos(pi/n));
factor = 2*(1-(1-mu^2)^0.5)/mu^2;
end
function [A] = MatrixTranslation(A,xstep,ystep)
% 将矩阵在 x 方向上平移 xstep 个单位,在 y 方向上平移 ystep 个单位
% 这个平移不是仿射变换,只是元素相对位置的平移
% 空余的位置用 0 补充
% 移动距离超出矩阵长度的会得到全零
if abs(xstep) >= size(A,1) || abs(ystep) >= size(A,2)
A = zeros(size(A));
return;
end
A = A;
if xstep > 0
A = A(:,1:size(A,2)-xstep);
A = [zeros(size(A,1),xstep) A];
end
if xstep < 0
A = A(:,1-xstep:size(A,2));
A = [A zeros(size(A,1),-xstep)];
end
if ystep > 0
A = A(1+ystep:size(A,1),:);
A = [A;zeros(ystep,size(A,2))];
end
if ystep < 0
A = A(1:size(A,1)+ystep,:);
A = [zeros(-ystep,size(A,2));A];
end
end
function [A] = DeleteElementForLargerSpace(A,n)
% 输入一个行向量或者列向量,输出一个全部元素属于输入的列向量
% 使得输出的列向量各元素之间的间隔变大
% 共减少 n 个元素
for times = 1:1:n
length = size(A,1)*size(A,2);
delta = zeros(length-1,1);
for i = 1:1:length-1
delta(i) = abs(A(i)-A(i+1));
end
[M,I] = min(delta);
A_tmp = zeros(length-1,1);
for i = 1:1:I-1
A_tmp(i) = A(i);
end
for i = I+1:1:length
A_tmp(i-1) = A(i);
end
A = A_tmp;
end
end
这个涡量图是真的难画得好看
如果单纯让 contourf 来选择等高线分布的话,那么等高线条数加到很大也画不出正中心的涡
% 涡量等高线
figure(2);
[M,c] = contourf(Y,X,Zeta,5000);
shading interp;
title('涡量等高线图');
axis('square','tight');
colorbar;
但是如果直接取涡量场的一行作为等高线值的话,又会在一些地方特别密集,也很丑
% 涡量等高线
figure(2);
[M,c] = contourf(Y,X,Zeta,Zeta(floor(length/2),:));
shading interp;
title('涡量等高线图');
axis('square','tight');
colorbar;
tmp1 = Zeta(floor(length/2),1:floor(2*length/5));
tmp2 = Zeta(floor(length/2),floor(2*length/5):floor(3*length/5));
tmp3 = Zeta(floor(length/2),floor(3*length/5):length);
tmp1 = DeleteElementForLargerSpace(tmp1,10);
tmp2 = tmp2';
tmp3 = DeleteElementForLargerSpace(tmp3,10);
tmp = [tmp1;tmp2;tmp3];
% 涡量等高线
figure(2);
[M,c] = contourf(Y,X,Zeta,tmp);
shading interp;
title('涡量等高线图');
axis('square','tight');
colorbar;
function [A] = DeleteElementForLargerSpace(A,n)
% 输入一个行向量或者列向量,输出一个全部元素属于输入的列向量
% 使得输出的列向量各元素之间的间隔变大
% 共减少 n 个元素
for times = 1:1:n
length = size(A,1)*size(A,2);
delta = zeros(length-1,1);
for i = 1:1:length-1
delta(i) = abs(A(i)-A(i+1));
end
[M,I] = min(delta);
A_tmp = zeros(length-1,1);
for i = 1:1:I-1
A_tmp(i) = A(i);
end
for i = I+1:1:length
A_tmp(i-1) = A(i);
end
A = A_tmp;
end
end
最后没有办法,只能放弃填充的计划了hhh
然后是流函数图中的小涡的问题
首先我觉得应该是看小涡的数量级,然后人为地按照那个数量级去画
噢,这里我改了边界条件,所以图的方向和上面的图不一样
% 流函数等高线
figure(1);
contour(Y,X,Psi,Psi(floor(length/2),:));
shading interp;
hold on;
contour(Y,X,Psi,[1e-7:1e-7:1e-6]);
contour(Y,X,Psi,[1e-6:1e-6:1e-5]);
contour(Y,X,Psi,[1e-5:1e-5:1e-4]);
contour(Y,X,Psi,[1e-4:1e-4:1e-3]);
hold off;
title('流函数等高线图');
xlabel('x');
ylabel('y');
axis('square','tight');
colorbar;
后来果然发现人为做数量级是不可靠的,真正的等高线值还是要从原矩阵之中取
% 流函数等高线
figure(1);
contour(Y,X,Psi,Psi(floor(length/2),:));
shading interp;
hold on;
contour(Y,X,Psi,Psi(:,floor(6*length/7)));
hold off;
title('流函数等高线图');
xlabel('x');
ylabel('y');
axis('square','tight');
colorbar;