SIMPLER for Compressible Hyperbolic Flow (Euler-like)
clc; clear;
% Grid setup
nx = 100; ny = 50;
Lx = 2; Ly = 1;
dx = Lx / nx; dy = Ly / ny;
x = linspace(0, Lx, nx+2);
y = linspace(0, Ly, ny+2);
[X, Y] = meshgrid(x, y);
% Flow properties
gamma = 1.4;
rho = ones(nx+2, ny+2);
u = ones(nx+1, ny+2); % staggered u
v = zeros(nx+2, ny+1); % staggered v
p = ones(nx+2, ny+2); % pressure
E = p./((gamma - 1) * rho); % total energy
% Airfoil mask (simple ellipse)
cx = Lx/2; cy = Ly/2; rx = 0.1; ry = 0.05;
airfoil = ((X - cx).^2 / rx^2 + (Y - cy).^2 / ry^2) <= 1;
% Solver parameters
maxIter = 1000;
tolerance = 1e-5;
alpha_p = 0.3;
alpha_u = 0.7;
for iter = 1:maxIter
u_old = u; v_old = v; p_old = p;
% Boundary Conditions
u(1,:) = 1.0; % Inlet
u(end,:) = u(end-1,:); % Outlet (Neumann)
u(:,[1 end]) = 0; v(:,[1 end]) = 0;
% Apply mask (airfoil no-penetration)
for i = 2:nx+1
for j = 2:ny+1
if airfoil(j,i)
u(i,j) = 0; v(i,j) = 0;
end
end
end
% --- Momentum update (Euler equations) ---
for i = 2:nx
for j = 2:ny+1
if airfoil(j,i), continue; end
dpdx = (p(i+1,j) - p(i-1,j)) / (2*dx);
u(i,j) = u(i,j) - alpha_u * dpdx / rho(i,j);
end
end
for i = 2:nx+1
for j = 2:ny
if airfoil(j,i), continue; end
dpdy = (p(i,j+1) - p(i,j-1)) / (2*dy);
v(i,j) = v(i,j) - alpha_u * dpdy / rho(i,j);
end
end
% --- Pressure correction (SIMPLER style) ---
for i = 2:nx+1
for j = 2:ny+1
if airfoil(j,i), continue; end
div = ((u(i-1,j) - u(i,j))/dx + (v(i,j-1) - v(i,j))/dy);
p(i,j) = p(i,j) + alpha_p * rho(i,j) * div;
end
end
% --- Convergence check ---
err = max([max(max(abs(u - u_old))), max(max(abs(p - p_old)))]);
if err < tolerance
disp(['Converged in ', num2str(iter), ' iterations']);
break;
end
end
% --- Plot velocity field ---
u_plot = 0.5 * (u(1:end-1,:) + u(2:end,:));
v_plot = 0.5 * (v(:,1:end-1) + v(:,2:end));
u_plot(airfoil) = NaN;
v_plot(airfoil) = NaN;
figure;
quiver(X', Y', u_plot, v_plot, 'k');
hold on;
contour(X, Y, airfoil, [1 1], 'r', 'LineWidth', 2);
xlabel('X'); ylabel('Y');
title('SIMPLER - Euler-like Compressible Flow (Hyperbolic)');
axis equal;
Parabolic
clc; clear;
% Domain and grid
nx = 100; ny = 50;
Lx = 2; Ly = 1;
dx = Lx / nx; dy = Ly / ny;
x = linspace(0, Lx, nx+2);
y = linspace(0, Ly, ny+2);
[X, Y] = meshgrid(x, y);
% Physical parameters
rho = 1.0; mu = 1.5e-5;
dt = 0.001; t_end = 1; nt = round(t_end/dt);
Re = 1000;
% Initialize variables
u = zeros(nx+1, ny+2); % u-velocity
v = zeros(nx+2, ny+1); % v-velocity
p = zeros(nx+2, ny+2); % pressure
% Airfoil-like ellipse mask
cx = Lx/2; cy = Ly/2; rx = 0.1; ry = 0.05;
airfoil = ((X - cx).^2 / rx^2 + (Y - cy).^2 / ry^2) <= 1;
% Relaxation factors
alpha_p = 0.3;
alpha_u = 0.7;
% Time-stepping loop (parabolic)
for time = 1:nt
u_old = u; v_old = v; p_old = p;
% --- Boundary conditions ---
u(1,:) = 1.0; % Inlet
u(end,:) = u(end-1,:); % Outlet
u(:,[1 end]) = 0;
v(:,[1 end]) = 0;
v(1,:) = 0; v(end,:) = 0;
% --- Apply airfoil mask (no-slip) ---
for i = 2:nx+1
for j = 2:ny+1
if airfoil(j,i)
u(i,j) = 0;
v(i,j) = 0;
end
end
end
% --- Pressure prediction (from continuity) ---
div_uv = zeros(nx+2, ny+2);
for i = 2:nx+1
for j = 2:ny+1
div_uv(i,j) = ((u(i-1,j) - u(i,j))/dx + (v(i,j-1) - v(i,j))/dy);
end
end
p = p + alpha_p * rho * div_uv;
% --- Momentum equations (explicit time update) ---
for i = 2:nx
for j = 2:ny+1
if airfoil(j,i), continue; end
du2dx = (u(i+1,j)^2 - u(i-1,j)^2)/(2*dx);
duvdy = ((u(i,j+1)+u(i,j))*(v(i,j+1)+v(i+1,j+1)) - (u(i,j)+u(i,j-1))*(v(i,j-1)+v(i+1,j-1))) / (4*dy);
dpdx = (p(i+1,j) - p(i,j))/dx;
d2udx2 = (u(i+1,j) - 2*u(i,j) + u(i-1,j)) / dx^2;
d2udy2 = (u(i,j+1) - 2*u(i,j) + u(i,j-1)) / dy^2;
u(i,j) = u(i,j) + dt * ( ...
- du2dx - duvdy ...
- dpdx / rho ...
+ mu * (d2udx2 + d2udy2) );
end
end
for i = 2:nx+1
for j = 2:ny
if airfoil(j,i), continue; end
dv2dy = (v(i,j+1)^2 - v(i,j-1)^2)/(2*dy);
duvdx = ((v(i+1,j)+v(i,j))*(u(i+1,j)+u(i+1,j+1)) - (v(i,j)+v(i-1,j))*(u(i-1,j)+u(i-1,j+1))) / (4*dx);
dpdy = (p(i,j+1) - p(i,j))/dy;
d2vdx2 = (v(i+1,j) - 2*v(i,j) + v(i-1,j)) / dx^2;
d2vdy2 = (v(i,j+1) - 2*v(i,j) + v(i,j-1)) / dy^2;
v(i,j) = v(i,j) + dt * ( ...
- duvdx - dv2dy ...
- dpdy / rho ...
+ mu * (d2vdx2 + d2vdy2) );
end
end
% --- Convergence check ---
err_u = max(max(abs(u - u_old)));
err_v = max(max(abs(v - v_old)));
err_p = max(max(abs(p - p_old)));
if mod(time, 100) == 0
fprintf("Time step %d: max error = %.6f\n", time, max([err_u err_v err_p]));
end
end
% --- Plot result ---
u_c = 0.5 * (u(1:end-1,:) + u(2:end,:));
v_c = 0.5 * (v(:,1:end-1) + v(:,2:end));
u_c(airfoil) = NaN; v_c(airfoil) = NaN;
figure;
quiver(X', Y', u_c, v_c, 'k');
hold on;
contour(X, Y, airfoil, [1 1], 'r', 'LineWidth', 2);
xlabel('X'); ylabel('Y');
title('SIMPLER - Parabolic (Unsteady Incompressible Flow)');
axis equal tight;
Elliptic
clc; clear;
% Domain
nx = 100; ny = 50;
Lx = 2; Ly = 1;
dx = Lx / nx; dy = Ly / ny;
x = linspace(0, Lx, nx+2);
y = linspace(0, Ly, ny+2);
[X, Y] = meshgrid(x, y);
% Physical properties
rho = 1.0;
mu = 1.5e-3; % viscosity
Re = 1000;
u = zeros(nx+1, ny+2);
v = zeros(nx+2, ny+1);
p = zeros(nx+2, ny+2);
% Airfoil shape (ellipse mask)
cx = Lx/2; cy = Ly/2; rx = 0.1; ry = 0.05;
airfoil = ((X - cx).^2 / rx^2 + (Y - cy).^2 / ry^2) <= 1;
% Relaxation factors
alpha_p = 0.3;
alpha_u = 0.7;
maxIter = 1000;
tolerance = 1e-5;
for iter = 1:maxIter
u_old = u;
v_old = v;
p_old = p;
% --- Boundary conditions ---
u(1,:) = 1.0; % Inlet
u(end,:) = u(end-1,:); % Outlet
u(:,[1 end]) = 0;
v(:,[1 end]) = 0;
v(1,:) = 0; v(end,:) = 0;
% Apply no-slip on airfoil
for i = 2:nx+1
for j = 2:ny+1
if airfoil(j,i)
u(i,j) = 0; v(i,j) = 0;
end
end
end
% --- Pressure correction from continuity (SIMPLER) ---
div_uv = zeros(nx+2, ny+2);
for i = 2:nx+1
for j = 2:ny+1
div_uv(i,j) = (u(i-1,j)-u(i,j))/dx + (v(i,j-1)-v(i,j))/dy;
end
end
p = p + alpha_p * rho * div_uv;
% --- Momentum Equations (Steady) ---
for i = 2:nx
for j = 2:ny+1
if airfoil(j,i), continue; end
du2dx = (u(i+1,j)^2 - u(i-1,j)^2)/(2*dx);
duvdy = ((u(i,j+1)+u(i,j))*(v(i,j+1)+v(i+1,j+1)) - (u(i,j)+u(i,j-1))*(v(i,j-1)+v(i+1,j-1))) / (4*dy);
dpdx = (p(i+1,j) - p(i,j)) / dx;
d2udx2 = (u(i+1,j) - 2*u(i,j) + u(i-1,j)) / dx^2;
d2udy2 = (u(i,j+1) - 2*u(i,j) + u(i,j-1)) / dy^2;
u(i,j) = u(i,j) + alpha_u * ...
(-du2dx - duvdy - dpdx/rho + mu*(d2udx2 + d2udy2));
end
end
for i = 2:nx+1
for j = 2:ny
if airfoil(j,i), continue; end
dv2dy = (v(i,j+1)^2 - v(i,j-1)^2)/(2*dy);
duvdx = ((v(i+1,j)+v(i,j))*(u(i+1,j)+u(i+1,j+1)) - (v(i,j)+v(i-1,j))*(u(i-1,j)+u(i-1,j+1))) / (4*dx);
dpdy = (p(i,j+1) - p(i,j)) / dy;
d2vdx2 = (v(i+1,j) - 2*v(i,j) + v(i-1,j)) / dx^2;
d2vdy2 = (v(i,j+1) - 2*v(i,j) + v(i,j-1)) / dy^2;
v(i,j) = v(i,j) + alpha_u * ...
(-duvdx - dv2dy - dpdy/rho + mu*(d2vdx2 + d2vdy2));
end
end
% --- Convergence check ---
err = max([max(max(abs(u - u_old))), max(max(abs(v - v_old))), max(max(abs(p - p_old)))]);
if mod(iter, 50) == 0
fprintf("Iter %d: Max Error = %.6f\n", iter, err);
end
if err < tolerance
fprintf("Converged in %d iterations\n", iter);
break;
end
end
% --- Plot velocity field ---
u_c = 0.5 * (u(1:end-1,:) + u(2:end,:));
v_c = 0.5 * (v(:,1:end-1) + v(:,2:end));
u_c(airfoil) = NaN;
v_c(airfoil) = NaN;
figure;
quiver(X', Y', u_c, v_c, 'k');
hold on;
contour(X, Y, airfoil, [1 1], 'r', 'LineWidth', 2);
xlabel('X'); ylabel('Y');
title('SIMPLER - Steady Incompressible Flow (Elliptic)');
axis equal tight;
SIMPLEC HYPERBOLA
% SIMPLEC algorithm for 2D incompressible flow (e.g., lid-driven cavity)
clear; clc;
% Grid
nx = 50; ny = 50;
Lx = 1; Ly = 1;
dx = Lx / nx; dy = Ly / ny;
% Physical parameters
rho = 1.0;
mu = 0.01;
U_lid = 1.0;
maxIter = 500;
tolerance = 1e-4;
% Initialize fields
u = zeros(nx+1, ny+2); % staggered in x
v = zeros(nx+2, ny+1); % staggered in y
p = zeros(nx+2, ny+2); % pressure
% Under-relaxation
alpha_u = 0.7;
alpha_p = 0.3;
for iter = 1:maxIter
u_old = u; v_old = v; p_old = p;
% --- Boundary Conditions ---
u(:,end) = U_lid; % lid velocity
u(:,1) = 0; u(:,end) = U_lid;
v(1,:) = 0; v(end,:) = 0;
% --- Momentum Equations (Discretized) ---
for i = 2:nx
for j = 2:ny+1
Ae = mu/dx; Aw = mu/dx; An = mu/dy; As = mu/dy;
Ap_u = Ae + Aw + An + As;
u(i,j) = (Ae*u(i+1,j) + Aw*u(i-1,j) + ...
An*u(i,j+1) + As*u(i,j-1) + ...
dx*(p(i,j) - p(i+1,j))) / Ap_u;
end
end
for i = 2:nx+1
for j = 2:ny
Ae = mu/dx; Aw = mu/dx; An = mu/dy; As = mu/dy;
Ap_v = Ae + Aw + An + As;
v(i,j) = (Ae*v(i+1,j) + Aw*v(i-1,j) + ...
An*v(i,j+1) + As*v(i,j-1) + ...
dy*(p(i,j) - p(i,j+1))) / Ap_v;
end
end
% --- Pressure Correction (SIMPLEC) ---
p_corr = zeros(nx+2, ny+2);
for i = 2:nx+1
for j = 2:ny+1
div = ((u(i-1,j) - u(i,j))/dx + (v(i,j-1) - v(i,j))/dy);
p_corr(i,j) = p_corr(i,j) - alpha_p * div;
end
end
% --- Pressure and Velocity Correction ---
p = p + p_corr;
for i = 2:nx
for j = 2:ny+1
u(i,j) = u(i,j) + (p_corr(i,j) - p_corr(i+1,j)) * dx;
end
end
for i = 2:nx+1
for j = 2:ny
v(i,j) = v(i,j) + (p_corr(i,j) - p_corr(i,j+1)) * dy;
end
end
% --- Convergence Check ---
err_u = max(max(abs(u - u_old)));
err_v = max(max(abs(v - v_old)));
err_p = max(max(abs(p - p_old)));
if err_u < tolerance && err_v < tolerance && err_p < tolerance
disp(['Converged in ', num2str(iter), ' iterations']);
break;
end
end
% --- Post-processing ---
[X, Y] = meshgrid(linspace(0,Lx,nx+2), linspace(0,Ly,ny+2));
u_center = 0.5 * (u(1:end-1,:) + u(2:end,:));
v_center = 0.5 * (v(:,1:end-1) + v(:,2:end));
quiver(X', Y', u_center, v_center);
title('Velocity Field');
xlabel('X'); ylabel('Y');
Parbola
% SIMPLEC Algorithm - 2D Parabolic Flow (Incompressible)
clc; clear;
% Grid setup
nx = 50; ny = 25;
Lx = 2; Ly = 1;
dx = Lx / nx; dy = Ly / ny;
x = linspace(0, Lx, nx+2); y = linspace(0, Ly, ny+2);
% Physical properties
rho = 1; mu = 1.5e-5;
U_in = 1; % inlet velocity
% Initialize fields
u = zeros(nx+1, ny+2); % u-velocity (x-dir)
v = zeros(nx+2, ny+1); % v-velocity (y-dir)
p = zeros(nx+2, ny+2); % pressure
% SIMPLEC relaxation factors
alpha_u = 0.7;
alpha_p = 0.3;
max_iter = 500;
tolerance = 1e-5;
% Time stepping (parabolic in time)
for iter = 1:max_iter
u_old = u; v_old = v; p_old = p;
% --- Boundary Conditions ---
u(1,:) = U_in; % Inlet
u(end,:) = u(end-1,:); % Outlet (Neumann)
v(1,:) = 0; v(end,:) = 0;
u(:,1) = 0; u(:,end) = 0; % Bottom/top wall
v(:,1) = 0; v(:,end) = 0;
% --- Solve u-momentum ---
for i = 2:nx
for j = 2:ny+1
ue = u(i+1,j); uw = u(i-1,j);
un = u(i,j+1); us = u(i,j-1);
dpdx = (p(i,j) - p(i+1,j)) / dx;
Ap = rho * (2/dx^2 + 2/dy^2);
u(i,j) = ((rho/dx^2)*(ue + uw) + (rho/dy^2)*(un + us) - dpdx) / Ap;
end
end
% --- Solve v-momentum ---
for i = 2:nx+1
for j = 2:ny
ve = v(i+1,j); vw = v(i-1,j);
vn = v(i,j+1); vs = v(i,j-1);
dpdy = (p(i,j) - p(i,j+1)) / dy;
Ap = rho * (2/dx^2 + 2/dy^2);
v(i,j) = ((rho/dx^2)*(ve + vw) + (rho/dy^2)*(vn + vs) - dpdy) / Ap;
end
end
% --- Pressure Correction using continuity ---
p_corr = zeros(nx+2, ny+2);
for i = 2:nx+1
for j = 2:ny+1
div = ((u(i-1,j) - u(i,j))/dx + (v(i,j-1) - v(i,j))/dy);
p_corr(i,j) = alpha_p * div;
end
end
% --- Correct Pressure and Velocities ---
p = p + p_corr;
for i = 2:nx
for j = 2:ny+1
u(i,j) = u(i,j) + alpha_u * (p_corr(i,j) - p_corr(i+1,j)) * dx;
end
end
for i = 2:nx+1
for j = 2:ny
v(i,j) = v(i,j) + alpha_u * (p_corr(i,j) - p_corr(i,j+1)) * dy;
end
end
% --- Convergence Check ---
err_u = max(max(abs(u - u_old)));
err_v = max(max(abs(v - v_old)));
err_p = max(max(abs(p - p_old)));
if max([err_u, err_v, err_p]) < tolerance
disp(['Converged in ', num2str(iter), ' iterations']);
break;
end
end
% --- Post-Processing ---
[X, Y] = meshgrid(x, y);
u_center = 0.5 * (u(1:end-1,:) + u(2:end,:));
v_center = 0.5 * (v(:,1:end-1) + v(:,2:end));
quiver(X', Y', u_center, v_center);
xlabel('X'); ylabel('Y'); title('Velocity Field (SIMPLEC)');
Elliptic
clc; clear;
% Domain and grid
nx = 100; ny = 50;
Lx = 2; Ly = 1;
dx = Lx / nx; dy = Ly / ny;
% Grid
x = linspace(0, Lx, nx+2);
y = linspace(0, Ly, ny+2);
[X, Y] = meshgrid(x, y);
% Flow properties
rho = 1.0;
mu = 1.5e-5;
U_in = 1.0;
% Initialize fields
u = zeros(nx+1, ny+2); % staggered in x
v = zeros(nx+2, ny+1); % staggered in y
p = zeros(nx+2, ny+2); % pressure
% SIMPLEC parameters
alpha_u = 0.7;
alpha_p = 0.3;
max_iter = 1000;
tolerance = 1e-5;
% Create airfoil mask (elliptical obstacle in center)
cx = Lx/2; cy = Ly/2;
rx = 0.1; ry = 0.05;
airfoil_mask = ((X - cx).^2 / rx^2 + (Y - cy).^2 / ry^2) <= 1;
% Main loop
for iter = 1:max_iter
u_old = u; v_old = v; p_old = p;
% --- Apply boundary conditions ---
u(1,:) = U_in; % inlet
u(end,:) = u(end-1,:); % outlet (Neumann)
u(:,[1 end]) = 0; % top/bottom wall
v(1,:) = 0; v(end,:) = 0;
v(:,[1 end]) = 0;
% --- Momentum equations ---
for i = 2:nx
for j = 2:ny+1
if airfoil_mask(j,i), u(i,j) = 0; continue; end
ue = u(i+1,j); uw = u(i-1,j);
un = u(i,j+1); us = u(i,j-1);
dpdx = (p(i,j) - p(i+1,j)) / dx;
Ap = rho * (2/dx^2 + 2/dy^2);
u(i,j) = ((rho/dx^2)*(ue + uw) + (rho/dy^2)*(un + us) - dpdx) / Ap;
end
end
for i = 2:nx+1
for j = 2:ny
if airfoil_mask(j,i), v(i,j) = 0; continue; end
ve = v(i+1,j); vw = v(i-1,j);
vn = v(i,j+1); vs = v(i,j-1);
dpdy = (p(i,j) - p(i,j+1)) / dy;
Ap = rho * (2/dx^2 + 2/dy^2);
v(i,j) = ((rho/dx^2)*(ve + vw) + (rho/dy^2)*(vn + vs) - dpdy) / Ap;
end
end
% --- Pressure correction ---
p_corr = zeros(nx+2, ny+2);
for i = 2:nx+1
for j = 2:ny+1
if airfoil_mask(j,i), continue; end
div = ((u(i-1,j) - u(i,j))/dx + (v(i,j-1) - v(i,j))/dy);
p_corr(i,j) = alpha_p * div;
end
end
% --- Correct pressure and velocities ---
p = p + p_corr;
for i = 2:nx
for j = 2:ny+1
u(i,j) = u(i,j) + alpha_u * (p_corr(i,j) - p_corr(i+1,j)) * dx;
end
end
for i = 2:nx+1
for j = 2:ny
v(i,j) = v(i,j) + alpha_u * (p_corr(i,j) - p_corr(i,j+1)) * dy;
end
end
% --- Convergence check ---
err = max([max(max(abs(u - u_old))), max(max(abs(v - v_old))), max(max(abs(p - p_old)))]);
if err < tolerance
disp(['Converged in ', num2str(iter), ' iterations']);
break;
end
end
% --- Postprocessing: Plot velocity field ---
u_center = 0.5 * (u(1:end-1,:) + u(2:end,:));
v_center = 0.5 * (v(:,1:end-1) + v(:,2:end));
u_center(airfoil_mask) = NaN;
v_center(airfoil_mask) = NaN;
figure;
quiver(X', Y', u_center, v_center);
hold on;
contour(X, Y, airfoil_mask, [1 1], 'k', 'LineWidth', 2);
title('Flow Field using SIMPLEC (Elliptic Navier-Stokes)');
xlabel('X'); ylabel('Y'); axis equal;
PISO hyperbola
clc; clear;
% Domain
nx = 100; ny = 50;
Lx = 4; Ly = 2;
dx = Lx / nx; dy = Ly / ny;
x = linspace(0, Lx, nx);
y = linspace(0, Ly, ny);
[X, Y] = meshgrid(x, y);
% Flow parameters
gamma = 1.4;
rho = ones(ny, nx);
u = ones(ny, nx) * 2; % Mach 2 inflow
v = zeros(ny, nx);
p = ones(ny, nx);
dt = 0.001;
time_steps = 500;
% Blunt body (circular)
cx = Lx/3; cy = Ly/2; r = 0.3;
blunt = ((X - cx).^2 + (Y - cy).^2) <= r^2;
% Main time loop
for t = 1:time_steps
% Step 1: Predictor - compute momentum fluxes
rhou = rho .* u;
rhov = rho .* v;
E = p/(gamma - 1) + 0.5*rho.*(u.^2 + v.^2);
% Compute fluxes in x and y directions
Fx = [rhou; rhou.^2 ./ rho + p; rhou.*rhov ./ rho; (E + p).*u];
Fy = [rhov; rhou.*rhov ./ rho; rhov.^2 ./ rho + p; (E + p).*v];
% Update using finite volume
for i = 2:nx-1
for j = 2:ny-1
if blunt(j,i), continue; end
rho(j,i) = rho(j,i) - dt/dx * (rhou(j,i+1) - rhou(j,i));
u(j,i) = u(j,i) - dt/dx * ((u(j,i+1)^2 + p(j,i+1)/rho(j,i+1)) - ...
(u(j,i)^2 + p(j,i)/rho(j,i)));
v(j,i) = v(j,i) - dt/dy * ((v(j+1,i)^2 + p(j+1,i)/rho(j+1,i)) - ...
(v(j,i)^2 + p(j,i)/rho(j,i)));
p(j,i) = p(j,i) - gamma * p(j,i) * ( ...
(u(j,i+1) - u(j,i))/dx + (v(j+1,i) - v(j,i))/dy ) * dt;
end
end
% PISO Correction Step 1
% Recalculate pressure correction from continuity
% Correct u, v accordingly (basic form shown)
for i = 2:nx-1
for j = 2:ny-1
if blunt(j,i), continue; end
div_uv = (u(j,i+1) - u(j,i-1))/(2*dx) + (v(j+1,i) - v(j-1,i))/(2*dy);
p(j,i) = p(j,i) - gamma * p(j,i) * div_uv * dt;
u(j,i) = u(j,i) - dt * (p(j,i+1) - p(j,i-1))/(2*dx) / rho(j,i);
v(j,i) = v(j,i) - dt * (p(j+1,i) - p(j-1,i))/(2*dy) / rho(j,i);
end
end
% PISO Correction Step 2 (optional second corrector)
% Boundary conditions
rho(:,1) = 1; u(:,1) = 2; v(:,1) = 0; p(:,1) = 1; % inlet
rho(:,end) = rho(:,end-1); p(:,end) = p(:,end-1); % outlet
u(blunt) = 0; v(blunt) = 0; % blunt body
% Visualization every N steps
if mod(t,50) == 0
contourf(X, Y, sqrt(u.^2 + v.^2), 20, 'LineColor','none');
colorbar; axis equal tight;
title(['Velocity Magnitude at t = ' num2str(t*dt)]);
drawnow;
end
end
Parabola
clc; clear;
% Domain setup
nx = 100; ny = 100;
Lx = 2.0; Ly = 2.0;
dx = Lx/nx; dy = Ly/ny;
x = linspace(0, Lx, nx);
y = linspace(0, Ly, ny);
[X, Y] = meshgrid(x, y);
% Time and physical parameters
dt = 0.002; % Time step
nt = 1000; % Number of time steps
Re = 100; % Reynolds number
nu = 1/Re; % Kinematic viscosity
rho = 1; % Density
% Velocity and pressure fields
u = zeros(ny, nx+1); % staggered in x
v = zeros(ny+1, nx); % staggered in y
p = zeros(ny, nx); % cell-centered
% Define blunt body mask (cylinder)
cx = Lx/2; cy = Ly/2; R = 0.2;
blunt = ((X - cx).^2 + (Y - cy).^2) < R^2;
% Main PISO loop over time
for t = 1:nt
u_star = u;
v_star = v;
% Apply inlet and wall BCs
u(:,1) = 1; % Inlet
u(:,end) = u(:,end-1); % Outlet (Neumann)
v(:,1) = 0; v(:,end) = 0;
u([1 end],:) = 0; v([1 end],:) = 0;
% Predictor: solve u*, v* without updated pressure
for i = 2:nx
for j = 2:ny-1
if blunt(j,i), continue; end
% u-momentum
dudt = -((u(j,i+1)^2 - u(j,i-1)^2)/(2*dx)) ...
- ((v(j+1,i)*u(j+1,i) - v(j-1,i)*u(j-1,i))/(2*dy)) ...
+ nu * ((u(j,i+1) - 2*u(j,i) + u(j,i-1))/dx^2 + ...
(u(j+1,i) - 2*u(j,i) + u(j-1,i))/dy^2) ...
- (p(j,i) - p(j,i-1))/dx / rho;
u_star(j,i) = u(j,i) + dt * dudt;
% v-momentum
dvdt = -((u(j,i+1)*v(j,i+1) - u(j,i-1)*v(j,i-1))/(2*dx)) ...
- ((v(j+1,i)^2 - v(j-1,i)^2)/(2*dy)) ...
+ nu * ((v(j,i+1) - 2*v(j,i) + v(j,i-1))/dx^2 + ...
(v(j+1,i) - 2*v(j,i) + v(j-1,i))/dy^2) ...
- (p(j,i) - p(j-1,i))/dy / rho;
v_star(j,i) = v(j,i) + dt * dvdt;
end
end
% Pressure correction (from continuity)
div = zeros(ny, nx);
for i = 2:nx-1
for j = 2:ny-1
div(j,i) = ((u_star(j,i+1) - u_star(j,i))/dx + ...
(v_star(j+1,i) - v_star(j,i))/dy);
end
end
% Solve pressure Poisson equation
for it = 1:100
p_old = p;
for i = 2:nx-1
for j = 2:ny-1
if blunt(j,i), continue; end
p(j,i) = 0.25*(p(j+1,i) + p(j-1,i) + p(j,i+1) + p(j,i-1) ...
- rho*(dx^2)*(div(j,i))/dt);
end
end
if max(max(abs(p - p_old))) < 1e-4
break;
end
end
% Velocity correction (PISO step)
for i = 2:nx
for j = 2:ny-1
if blunt(j,i), continue; end
u(j,i) = u_star(j,i) - dt/dx * (p(j,i) - p(j,i-1))/rho;
v(j,i) = v_star(j,i) - dt/dy * (p(j,i) - p(j-1,i))/rho;
end
end
% Optional second pressure correction (PISO enhancement)
% Skipped for simplicity
% Display results every 100 steps
if mod(t,100)==0
u_center = 0.5*(u(:,1:end-1) + u(:,2:end));
v_center = 0.5*(v(1:end-1,:) + v(2:end,:));
vel = sqrt(u_center.^2 + v_center.^2);
vel(blunt) = NaN;
contourf(X, Y, vel, 20, 'LineColor','none');
title(['Velocity Magnitude at time step: ' num2str(t)]);
axis equal tight;
colorbar;
drawnow;
end
end
Elliptic
clc; clear;
% Grid parameters
nx = 100; ny = 100;
Lx = 2.0; Ly = 2.0;
dx = Lx/nx; dy = Ly/ny;
x = linspace(0, Lx, nx);
y = linspace(0, Ly, ny);
[X, Y] = meshgrid(x, y);
% Physical properties
rho = 1; % Density
Re = 100; % Reynolds number
nu = 1/Re; % Kinematic viscosity
% Fields
u = ones(ny, nx); % x-velocity initialized to inflow
v = zeros(ny, nx); % y-velocity
p = zeros(ny, nx); % Pressure
% Blunt body mask (circular cylinder)
cx = Lx/2; cy = Ly/2; R = 0.2;
blunt = ((X - cx).^2 + (Y - cy).^2) < R^2;
% Iteration parameters
max_iter = 1000;
tol = 1e-5;
dt = 0.01; % pseudo-time step for PISO-like steady simulation
for iter = 1:max_iter
u_star = u;
v_star = v;
% Predictor step: update velocities (pseudo-unsteady)
for i = 2:nx-1
for j = 2:ny-1
if blunt(j,i), continue; end
% Convective and diffusive terms for u
du = -u(j,i)*(u(j,i+1)-u(j,i-1))/(2*dx) ...
- v(j,i)*(u(j+1,i)-u(j-1,i))/(2*dy) ...
+ nu*((u(j,i+1) - 2*u(j,i) + u(j,i-1))/dx^2 + ...
(u(j+1,i) - 2*u(j,i) + u(j-1,i))/dy^2);
% Convective and diffusive terms for v
dv = -u(j,i)*(v(j,i+1)-v(j,i-1))/(2*dx) ...
- v(j,i)*(v(j+1,i)-v(j-1,i))/(2*dy) ...
+ nu*((v(j,i+1) - 2*v(j,i) + v(j,i-1))/dx^2 + ...
(v(j+1,i) - 2*v(j,i) + v(j-1,i))/dy^2);
u_star(j,i) = u(j,i) + dt * (du - (1/rho)*(p(j,i+1) - p(j,i))/dx);
v_star(j,i) = v(j,i) + dt * (dv - (1/rho)*(p(j+1,i) - p(j,i))/dy);
end
end
% Pressure correction from continuity
div = zeros(ny, nx);
for i = 2:nx-1
for j = 2:ny-1
div(j,i) = ((u_star(j,i) - u_star(j,i-1))/dx + ...
(v_star(j,i) - v_star(j-1,i))/dy);
end
end
% Pressure Poisson equation
for it_p = 1:100
p_old = p;
for i = 2:nx-1
for j = 2:ny-1
if blunt(j,i), continue; end
p(j,i) = 0.25*(p(j+1,i) + p(j-1,i) + p(j,i+1) + p(j,i-1) - ...
rho/dt * div(j,i) * dx^2);
end
end
if max(max(abs(p - p_old))) < 1e-4
break;
end
end
% Correct velocities
for i = 2:nx-1
for j = 2:ny-1
if blunt(j,i), continue; end
u(j,i) = u_star(j,i) - dt/dx * (p(j,i) - p(j,i-1))/rho;
v(j,i) = v_star(j,i) - dt/dy * (p(j,i) - p(j-1,i))/rho;
end
end
% Boundary conditions
u(:,1) = 1; % Inlet
u(:,end) = u(:,end-1); % Outlet
u([1 end],:) = 0; % Top/bottom walls
v(:,[1 end]) = 0;
v([1 end],:) = 0;
u(blunt) = 0; v(blunt) = 0;
% Convergence check
res = max(max(abs(div)));
if res < tol
fprintf('Converged at iteration %d\n', iter);
break;
end
% Plot every 100 iterations
if mod(iter,100) == 0
u_center = u;
v_center = v;
vel = sqrt(u_center.^2 + v_center.^2);
vel(blunt) = NaN;
contourf(X, Y, vel, 20, 'LineColor','none');
axis equal tight;
title(['Steady Flow Velocity Magnitude – Iteration: ' num2str(iter)]);
colorbar;
drawnow;
end
end
SIMPLE hyperbola
clc; clear;
% Grid setup
nx = 100; ny = 50;
Lx = 2; Ly = 1;
dx = Lx / nx; dy = Ly / ny;
x = linspace(0, Lx, nx+2);
y = linspace(0, Ly, ny+2);
[X, Y] = meshgrid(x, y);
% Physical parameters
rho = 1.0;
dt = 0.001; t_end = 0.5; nt = round(t_end/dt);
% Initialize fields
u = zeros(nx+1, ny+2);
v = zeros(nx+2, ny+1);
p = zeros(nx+2, ny+2);
% Elliptic airfoil mask
cx = Lx/2; cy = Ly/2; rx = 0.1; ry = 0.05;
airfoil = ((X - cx).^2 / rx^2 + (Y - cy).^2 / ry^2) <= 1;
% SIMPLE loop for hyperbolic flow
for t = 1:nt
u_old = u; v_old = v; p_old = p;
% --- Boundary conditions ---
u(1,:) = 1.0; % inlet
u(end,:) = u(end-1,:); % outlet
u(:,[1 end]) = 0;
v(:,[1 end]) = 0;
v(1,:) = 0; v(end,:) = 0;
% No-slip on airfoil
for i = 2:nx+1
for j = 2:ny+1
if airfoil(j,i)
u(i,j) = 0;
v(i,j) = 0;
end
end
end
% --- Momentum equations (inviscid hyperbolic form) ---
for i = 2:nx
for j = 2:ny+1
if airfoil(j,i), continue; end
u_adv = -u(i,j) * (u(i+1,j) - u(i-1,j)) / (2*dx) ...
- v(i,j) * (u(i,j+1) - u(i,j-1)) / (2*dy);
u_pres = -(p(i+1,j) - p(i,j)) / dx / rho;
u(i,j) = u(i,j) + dt * (u_adv + u_pres);
end
end
for i = 2:nx+1
for j = 2:ny
if airfoil(j,i), continue; end
v_adv = -u(i,j) * (v(i+1,j) - v(i-1,j)) / (2*dx) ...
- v(i,j) * (v(i,j+1) - v(i,j-1)) / (2*dy);
v_pres = -(p(i,j+1) - p(i,j)) / dy / rho;
v(i,j) = v(i,j) + dt * (v_adv + v_pres);
end
end
% --- Pressure correction (Poisson-type from continuity) ---
div_uv = zeros(nx+2, ny+2);
for i = 2:nx+1
for j = 2:ny+1
div_uv(i,j) = (u(i-1,j)-u(i,j))/dx + (v(i,j-1)-v(i,j))/dy;
end
end
p = p + 0.3 * rho * div_uv; % relaxation factor
% --- Correct velocity (SIMPLE) ---
for i = 2:nx
for j = 2:ny+1
u(i,j) = u(i,j) - dt * (p(i+1,j) - p(i,j)) / dx / rho;
end
end
for i = 2:nx+1
for j = 2:ny
v(i,j) = v(i,j) - dt * (p(i,j+1) - p(i,j)) / dy / rho;
end
end
% --- Print progress ---
if mod(t, 50) == 0
fprintf("Time step %d/%d complete\n", t, nt);
end
end
% --- Plot results ---
u_c = 0.5 * (u(1:end-1,:) + u(2:end,:));
v_c = 0.5 * (v(:,1:end-1) + v(:,2:end));
u_c(airfoil) = NaN;
v_c(airfoil) = NaN;
figure;
quiver(X', Y', u_c, v_c, 'k');
hold on;
contour(X, Y, airfoil, [1 1], 'r', 'LineWidth', 2);
xlabel('X'); ylabel('Y');
title('SIMPLE - Hyperbolic (Unsteady Inviscid Flow)');
axis equal tight;
Parabolic
clc; clear;
% Domain
nx = 200; ny = 100;
Lx = 1.0; Ly = 0.5;
dx = Lx / nx; dy = Ly / ny;
x = linspace(0, Lx, nx+1);
y = linspace(0, Ly, ny+1);
% Parameters
rho = 1.0;
nu = 1.5e-5;
U_inlet = 1.0;
% Initialize
u = zeros(ny+1, nx+1); % velocity in x-direction
v = zeros(ny+1, nx+1); % velocity in y-direction
p = zeros(ny+1, nx+1); % pressure
u(:,1) = U_inlet; % inlet condition
% SIMPLE parameters
alpha_u = 0.7;
alpha_p = 0.3;
max_iter = 500;
tol = 1e-5;
% Marching in x (parabolic treatment)
for i = 2:nx+1
u_old = u(:,i-1); % use previous x-location
% Apply wall and farfield BCs
u(1,i) = 0; % wall (no-slip)
v(1,i) = 0;
u(end,i) = U_inlet; % free-stream
v(end,i) = 0;
% Iterative SIMPLE loop at each x-location
for iter = 1:max_iter
u_star = u(:,i);
p_corr = zeros(ny+1,1);
% Solve x-momentum (only y-derivatives matter in boundary layer)
for j = 2:ny
dudy = (u(j+1,i) - 2*u(j,i) + u(j-1,i)) / dy^2;
conv = u(j,i-1)*(u(j,i-1) - u(j-1,i-1))/dy; % upstream conv
u_star(j) = u(j,i-1) + dx * (nu * dudy - conv);
end
% Solve pressure correction using continuity
for j = 2:ny
div = (u_star(j) - u_star(j-1))/dy;
p_corr(j) = p_corr(j) - alpha_p * rho * div;
end
% Correct u
for j = 2:ny
u(j,i) = u_star(j) - dx/rho * (p_corr(j+1) - p_corr(j))/dy;
end
% Recompute v from continuity
for j = 2:ny
v(j,i) = v(j-1,i) - dy * (u(j,i) - u(j,i-1)) / dx;
end
% Check convergence
if max(abs(u(:,i) - u_star)) < tol
break;
end
end
end
% Plot results
[X, Y] = meshgrid(x, y);
figure;
contourf(X, Y, u, 20, 'LineColor', 'none');
colorbar;
xlabel('x'); ylabel('y');
title('Velocity Profile u(x,y) - SIMPLE for Parabolic Flow');
figure;
quiver(X, Y, u, v, 2);
xlabel('x'); ylabel('y');
title('Velocity Field (u, v)');
Elliptic
clc; clear;
% Domain
nx = 100; ny = 50;
Lx = 2.0; Ly = 1.0;
dx = Lx / nx; dy = Ly / ny;
x = linspace(0, Lx, nx+2);
y = linspace(0, Ly, ny+2);
[X, Y] = meshgrid(x, y);
% Parameters
rho = 1.0;
nu = 1e-3;
U_inlet = 1.0;
max_iter = 500;
tol = 1e-4;
alpha_p = 0.3;
% Field variables
u = zeros(ny+2, nx+3); % u at cell faces in x
v = zeros(ny+3, nx+2); % v at cell faces in y
p = zeros(ny+2, nx+2); % pressure at cell centers
% Airfoil mask (elliptical)
cx = Lx/2; cy = Ly/2; rx = 0.2; ry = 0.1;
airfoil = ((X - cx).^2 / rx^2 + (Y - cy).^2 / ry^2) <= 1;
% SIMPLE loop
for iter = 1:max_iter
u_old = u; v_old = v; p_old = p;
% Boundary conditions
u(:,1) = U_inlet; % Inlet
u(:,end) = u(:,end-1); % Outlet (Neumann)
v(:,1) = 0; v(:,end) = 0;
u([1 end],:) = 0; v([1 end],:) = 0; % top/bottom wall
% No-slip at airfoil
for i = 2:nx+1
for j = 2:ny+1
if airfoil(j,i)
u(j,i) = 0; v(j,i) = 0;
end
end
end
% --- Solve momentum equations ---
% Internal nodes only
for i = 2:nx+1
for j = 2:ny+1
if airfoil(j,i), continue; end
ue = u(j,i+1); uw = u(j,i-1);
un = u(j+1,i); us = u(j-1,i);
ve = v(j,i+1); vw = v(j,i);
du2dx = (ue^2 - uw^2) / (2*dx);
duvdy = ((v(j+1,i)*u(j+1,i) - v(j-1,i)*u(j-1,i)) / (2*dy));
dpdx = (p(j,i+1) - p(j,i)) / dx;
d2udx2 = (ue - 2*u(j,i) + uw) / dx^2;
d2udy2 = (un - 2*u(j,i) + us) / dy^2;
u(j,i) = u(j,i) + 0.1 * ( ...
-du2dx - duvdy - dpdx/rho + nu*(d2udx2 + d2udy2) );
end
end
for i = 2:nx+1
for j = 2:ny+1
if airfoil(j,i), continue; end
vn = v(j+1,i); vs = v(j-1,i);
ve = v(j,i+1); vw = v(j,i-1);
ue = u(j,i+1); uw = u(j,i);
dv2dy = (vn^2 - vs^2) / (2*dy);
duvdx = ((u(j,i+1)*v(j,i+1) - u(j,i-1)*v(j,i-1)) / (2*dx));
dpdy = (p(j+1,i) - p(j,i)) / dy;
d2vdx2 = (ve - 2*v(j,i) + vw) / dx^2;
d2vdy2 = (vn - 2*v(j,i) + vs) / dy^2;
v(j,i) = v(j,i) + 0.1 * ( ...
-duvdx - dv2dy - dpdy/rho + nu*(d2vdx2 + d2vdy2) );
end
end
% --- Pressure correction from continuity ---
div = zeros(size(p));
for i = 2:nx+1
for j = 2:ny+1
div(j,i) = ((u(j,i) - u(j,i-1))/dx + (v(j,i) - v(j-1,i))/dy);
end
end
p = p - alpha_p * rho * div;
% --- Velocity correction ---
for i = 2:nx+1
for j = 2:ny+1
u(j,i) = u(j,i) - dx/rho * (p(j,i) - p(j,i-1));
v(j,i) = v(j,i) - dy/rho * (p(j,i) - p(j-1,i));
end
end
% Convergence check
err_u = max(max(abs(u - u_old)));
err_v = max(max(abs(v - v_old)));
err_p = max(max(abs(p - p_old)));
if max([err_u, err_v, err_p]) < tol
fprintf("Converged in %d iterations\n", iter);
break;
end
end
% Plot velocity magnitude
u_c = 0.5*(u(:,1:end-1) + u(:,2:end));
v_c = 0.5*(v(1:end-1,:) + v(2:end,:));
vel_mag = sqrt(u_c.^2 + v_c.^2);
vel_mag(airfoil) = NaN;
figure;
contourf(X, Y, vel_mag, 20, 'LineColor', 'none');
colorbar;
title('Velocity Magnitude - SIMPLE for Elliptic Flow');
xlabel('x'); ylabel('y');
axis equal tight;
figure;
quiver(X, Y, u_c, v_c, 2);
hold on;
contour(X, Y, airfoil, [1 1], 'r', 'LineWidth', 2);
title('Velocity Field (u, v)');
xlabel('x'); ylabel('y');
axis equal tight;