Showing posts with label code. Show all posts
Showing posts with label code. Show all posts

Sunday 31 March 2024

13th Step of the 12 steps to Navier-Stokes 😑

     Indeed, the 13th step now exists! This case is called the case of the backward facing step (BFS)! ⬜ This is an unofficial continuation to this. If I get it approved by Dr. Barba, then it will be official. The original series is in Python but I coded this in MATLAB without using many MATLAB specific functions so the code can be translated to other programing languages 🖧 quite easily.

The Code

%% clear and close
close all
clear
clc
%% define spatial and temporal grids
l_square = 1; % length of square
h = l_square/50; % grid spacing
dt = 0.1; % time step
L = 21; % cavity length
D = 2; % cavity depth
Nx = round((L/h)+1); % grid points in x-axis
Ny = round((D/h)+1); % grid points in y-axis
nu = 0.000015111; % kinematic viscosity
Uinf = 0.0060444; % free stream velocity / inlet velocity / lid velocity
cfl = dt*Uinf/h; % % cfl number
travel = 4; % times the disturbance travels entire length of computational domain
TT = travel*L/Uinf; % total time
ns = TT/dt; % number of time steps
Re = l_square*Uinf/nu; % Reynolds number
rho = 1.2047; % fluid density
%% initialize flowfield
u = zeros(Nx,Ny); % x-velocity
v = zeros(Nx,Ny); % y-velocity
p = zeros(Nx,Ny); % pressure
i = 2:Nx-1; % spatial interior nodes in x-axis
j = 2:Ny-1; % spatial interior nodes in y-axis
[X, Y] = meshgrid(0:h:L, 0:h:D); % spatial grid
maxNumCompThreads('automatic'); % select CPU cores
%% solve 2D Navier-Stokes equations
for nt = 1:ns
pn = p;
p(i, j) = (pn(i+1, j)+pn(i-1, j)+pn(i, j+1)+pn(i, j-1))/4 ...
-h*rho/(8*dt)*(u(i+1, j)-u(i-1, j)+v(i, j+1)-v(i, j-1)); % pressure poisson
p(1, :) = p(2, :); % dp/dx = 0 at x = 0
p(Nx, :) = 0; % p = 0 at x = L
p(:, 1) = p(:, 2); % dp/dy = 0 at y = 0
p(:, Ny) = p(:, Ny-1); % dp/dy = 0 at y = D
p(round(1:1*Nx/L), round(1:1*Ny/D)) = 0; % step geometry
p(round(1*Nx/L), round(1:1*Ny/D)) = p(round(1*Nx/L)+1, round(1:1*Ny/D)); % dp/dx = 0 at x = 1 and y = 0 to 1
p(1:round(1*Nx/L), round(1*Ny/D)) = p(1:round(1*Nx/L), round(1*Ny/D)+1); % dp/dy = 0 at x = 0 to 1 and y = 1
p(1:round(1*Nx/L), 1) = p(1:round(1*Nx/L), 2); % dp/dy = 0 at x = 0 to 1 and y = 1
un = u;
vn = v;
u(i, j) = un(i, j)-dt/(2 * h)*(un(i, j).*(un(i+1, j)-un(i-1, j))+vn(i, j).*(un(i, j+1)-un(i, j-1))) ...
-dt/(2*rho*h)*(p(i+1, j)-p(i-1, j)) ...
+nu*dt/h^2*(un(i+1, j)+un(i-1, j)+un(i, j+1)+un(i, j-1)-4*un(i, j)); % x-momentum
u(round(1:1*Nx/L), round(1:1*Ny/D)) = 0; % step geometry
u(1, round(1:1*Ny/D)) = 0; % u = 0 at x = 0 and y = 0 to 1
u(1, round(1*Ny/D:2*Ny/D)) = Uinf; % u = Uinf at x = 0 and y = 1 to 2
u(round(1*Nx/L), round(1:1*Ny/D)) = 0; % u = 0 at x = 1 and y = 0 to 1
u(1:round(1*Nx/L), round(1*Ny/D)) = 0; % u = 0 at x = 0 to 1 and y = 1
u(1:round(1*Nx/L), 1) = 0; % u = 0 at x = 0 to 1 and y = 1
u(Nx, :) = u(Nx-1, :); % du/dx = 0 at x = L
u(:, 1) = 0; % u = 0 at y = 0
u(:, Ny) = 0; % u = 0 at y = D
v(i, j) = vn(i, j)-dt/(2*h)*(un(i, j).*(vn(i+1, j)-vn(i-1, j))+vn(i, j).*(vn(i, j+1)-vn(i, j-1))) ...
-dt/(2*rho*h)*(p(i, j+1)-p(i, j-1)) ...
+ nu*dt/h^2*(vn(i+1, j)+vn(i-1, j)+vn(i, j+1)+vn(i, j-1)-4*vn(i, j)); % y-momentum
v(round(1:1*Nx/L), round(1:1*Ny/D)) = 0; % step geometry
v(1, round(1:1*Ny/D)) = 0; % v = 0 at x = 0 and y = 0 to 1
v(1, round(1*Ny/D:2*Ny/D)) = 0; % v = Uinf at x = 0 and y = 1 to 2
v(round(1*Nx/L), round(1:1*Ny/D)) = 0; % v = 0 at x = 1 and y = 0 to 1
v(1:round(1*Nx/L), round(1*Ny/D)) = 0; % v = 0 at x = 0 to 1 and y = 1
v(1:round(1*Nx/L), 1) = 0; % v = 0 at x = 0 to 1 and y = 1
v(Nx, :) = v(Nx-1, :); % dv/dx = 0 at x = L
v(:, 1) = 0; % u = 0 at y = 0
v(:, Ny) = 0; % u = 0 at y = D
end
%% post-processing
velocity_magnitude = sqrt(u.^2 + v.^2); % velocity magnitude
u1 = u; % u-velocity for plotting with box
v1 = v; % v-velocity for plotting with box
p1 = p; % p-velocity for plotting with box
u1(1:round(1*Nx/L) , 1:round(1*Ny/D)) = NaN; % step geometry
v1(1:round(1*Nx/L) , 1:round(1*Ny/D)) = NaN; % step geometry
p1(1:round(1*Nx/L) , 1:round(1*Ny/D)) = NaN; % step geometry
velocity_magnitude1 = sqrt(u1.^2 + v1.^2); % velocity magnitude with box
%% Visualize velocity vectors and pressure contours
hold on
contourf(X, Y, u1', 64, 'LineColor', 'none'); % contour plot
set(gca, 'FontSize', 20)
% skip = 20;
% quiver(X(1:skip:end, 1:skip:end), Y(1:skip:end, 1:skip:end),...
% u1(1:skip:end, 1:skip:end)', v1(1:skip:end, 1:skip:end)', 1, 'k','LineWidth', 0.1); % Velocity vectors
% hh = streamslice(X, Y, u1', v1',2); % Streamlines
% set(hh, 'Color', 'k','LineWidth', 01);
colorbar; % Add color bar
colormap parula % Set color map
axis equal % Set true scale
xlim([0 L]); % Set axis limits
ylim([0 D]);
xticks([0 9 L]) % Set ticks
yticks([0 D]) % Set ticks
xt = [0 21]; % draw top wall
yt = [2 2];
xb = [1 21]; % draw bottom wall
yb = [0 0];
xbox = [0 1 1 0 0]; % draw box
ybox = [0 0 1 1 0];
plot(xbox, ybox, 'k', 'LineWidth', 2)
plot(xt, yt, 'k', 'LineWidth', 2)
plot(xb, yb, 'k', 'LineWidth', 2)
% clim([0 max(velocity_magnitude(:))]) % legend limits
% title('Velocity [m/s]');
xlabel('x [m]');
ylabel('y [m]');

     The results from this code at Re 400 are presented in Fig. 1. The re-attachment length is ~8 m from the trailing-edge of the box, which is same as previously published results, from example in [1].

Fig. 1, post-processes results

     Thank you for reading! If you want to hire me as your next PhD student, please do reach out!

References

 [1] Irisarri, D., Hauke, G. Stabilized virtual element methods for the unsteady incompressible Navier–Stokes equations. Calcolo 56, 38 (2019). https://doi.org/10.1007/s10092-019-0332-5

Saturday 26 August 2023

Open - Source coded 3D Navier–Stokes equations in C++

     Here are 3D Navier–Stokes equations configured for lid-driven cavity flow. The syntax is C++. The results from this code are shown in Fig. 1. From the pressure-Poisson equation, I removed mixed derivative terms to improve solution stability. 😆

p[i][j][k] = ((p[i+1][j][k] + p[i-1][j][k]) * h * h + (p[i][j+1][k] + p[i][j-1][k]) * h * h + (p[i][j][k+1] + p[i][j][k-1]) * h * h) / (2 * (h * h + h * h + h * h)) - h * h * h * h * h * h / (2 * (h * h + h * h + h * h)) * (rho * (1 / dt * ((u(i+1, j, k) - u(i-1, j, k)) / (2 * h) + (v(i, j+1, k) - v(i, j-1, k)) / (2 * h) + (w(i, j, k+1) - w(i, j, k-1)) / (2 * h))));

p[0][j][k] = p[1][j][k];

p[num_i - 1][j][k] = p[num_i - 2][j][k];

p[i][0][k] = p[i][1][k];

p[i][num_j - 1][k] = p[i][num_j - 2][k];

p[i][j][0] = p[i][j][1];

p[i][j][num_k - 1] = 0.0;

u[i][j][k] = u[i][j][k] - u[i][j][k] * dt / (2 * h) * (u[i+1][j][k] - u[i-1][j][k]) - v[i][j][k] * dt / (2 * h) * (u[i][j+1][k] - u[i][j-1][k]) - w[i][j][k] * dt / (2 * h) * (u[i][j][k+1] - u[i][j][k-1]) - dt / (2 * rho * h) * (p[i+1][j][k] - p[i-1][j][k]) + nu * (dt / (h * h) * (u[i+1][j][k] - 2 * u[i][j][k] + u[i-1][j][k]) + dt / (h * h) * (u[i][j+1] [k] - 2 * u[i][j][k] + u[i][j-1][k]) + dt / (h * h) * (u[i][j][k+1] - 2 * u[i][j][k] + u[i][j][k-1]));

u[0][j][k] = 0.0;

u[num_i - 1][j][k] = 0.0;

u[i][0][k] = 0.0;

u[i][num_j - 1][k] = 0.0;

u[i][j][0] = 0.0;

u[i][j][num_k - 1] = -Uinf;

v[i][j][k] = v[i][j][k] - u[i][j][k] * dt / (2 * h) * (v[i+1][j][k] - v[i-1][j][k]) - v[i][j][k] * dt / (2 * h) * (v[i][j+1][k] - v[i][j-1][k]) - w[i][j][k] * dt / (2 * h) * (v[i][j][k+1] - v[i][j][k-1]) - dt / (2 * rho * h) * (p[i][j+1][k] - p[i][j-1][k]) + nu * (dt / (h * h) * (v[i+1][j][k] - 2 * v[i][j][k] + v[i-1][j][k]) + dt / (h * h) * (v[i][j+1][k] - 2 * v[i][j][k] + v[i][j-1][k]) + dt / (h * h) * (v[i][j][k+1] - 2 * v[i][j][k] + v[i][j][k-1]));

v[0][j][k] = 0.0;

v[num_i - 1][j][k] = 0.0;

v[i][0][k] = 0.0;

v[i][num_j - 1][k] = 0.0;

v[i][j][0] = 0.0;

v[i][j][num_k - 1] = 0.0;

w[i][j][k] = w[i][j][k] - u[i][j][k] * dt / (2 * h) * (w[i+1][j][k] - w[i-1][j][k]) - v[i][j][k] * dt / (2 * h) * (w[i][j+1][k] - w[i][j-1][k]) - w[i][j][k] * dt / (2 * h) * (w[i][j][k+1] - w[i][j][k-1]) - dt / (2 * rho * h) * (p[i][j][k+1] - p[i][j][k-1]) + nu * (dt / (h * h) * (w[i+1][j][k] - 2 * w[i][j][k] + w[i-1][j][k]) + dt / (h * h) * (w[i][j+1][k] - 2 * w[i][j][k] + w[i][j-1][k]) + dt / (h * h) * (w[i][j][k+1] - 2 * w[i][j][k] + w[i][j][k-1]));

w[0][j][k] = 0.0;

w[num_i - 1][j][k] = 0.0;

w[i][0][k] = 0.0;

w[i][num_j - 1][k] = 0.0;

w[i][j][0] = 0.0;

w[i][j][num_k - 1] = 0.0;


Fig. 1, Velocity and pressure iso-surfaces


     Of course constants need to be defined, such as grid spacing in space and time, density, kinematic viscosity. These equations have been validated, as you might have read and here already! Happy coding!

     If you want to hire me as your PhD student in the research projects related to turbo-machinery, aerodynamics, renewable energy, please reach out. Thank you very much for reading.

Monday 26 March 2018

1D Transient Diffusion (MATLAB code)


clear; clc;% clear the screen and memory

Nx=500; %number of space nodes

Nt=10000; %number of time nodes

Lx=0.3; %length of space (m)

Lt=10; %length of physical time (s)

dx=Lx/(Nx-1); %grid spacing

dt=Lt/(Nt-1); %time step

c=0.000097; %speed of wave (constant)

a=c*dt/dx.^2;

u=100*ones(Nx,1); %initialization of matrix for the property under investigation

x=zeros(Nx,1); %initialization of space

for i=1:Nx-1 %space loop

    x(i+1)=x(i)+dx;

end

u(1)=-20; %boundary condition

u(Nx)=50; %boundary condition

for t=0:dt:Lt %time loop

    un=u; %u(i,t)

    for i=2:Nx-1 %solution loop, backward in space forward in time

        u(i)=((1-2*a)*un(i))+a*(un(i+1)+un(i-1)); %discretized equation, u(i,t+1)

    end

    plot(x,u) %plotting

    title({t;'Time Elaplsed (s)'},'FontSize',38.5);

    pause(0.001)

end
 
 

Friday 23 March 2018

1D non-Linear Convection (MATLAB code)


clear; clc;% clear the screen and memory

Nx=41; %number of space nodes

Nt=82; %number of time nodes

Lx=2; %length of space (m)

Lt=1; %length of time (s)

dx=Lx/(Nx-1); %grid spacing

dt=Lt/(Nt-1); %time step

a=dt/dx;

u=ones(Nx,1); %initialization of solution matrix

x=zeros(Nx,1); %initialization of space

hold on

for i=1:Nx-1 %space loop

    x(i+1)=x(i)+dx;

end

for i=0.5/dx:1/dx %initial conditions

    u(i)=2;

end

for t=1:Nt %time loop

    un=u; %u(i,t)

    for i=2:Nx %solution loop, backward in space forward in time

        u(i)=un(i)-u(i)*a*(un(i)-un(i-1)); %discretized equation, u(i,t+1)

    end

    plot(x,u,'k') %plotting

    pause(0.1)

end

1D Linear Convection (MATLAB code) (Updated with CFL condition)


clear; clc;% clear the screen and memory

Nx=41; %number of space nodes

Nt=82; %number of time nodes

Lx=2; %length of space (m)

Lt=1; %length of time (s)

dx=Lx/(Nx-1); %grid spacing

dt=Lt/(Nt-1); %time step

c=2; %speed of wave (constant)

a=c*dt/dx;

u=ones(Nx,1); %initialization of solution matrix

x=zeros(Nx,1); %initialization of space

hold on

for i=1:Nx-1 %space loop

    x(i+1)=x(i)+dx;

end

for i=0.5/dx:1/dx %initial conditions

    u(i)=2;

end

for t=1:Nt %time loop

    un=u; %u(i,t)

    for i=2:Nx %solution loop, backward in space forward in time

        u(i)=un(i)-a*(un(i)-un(i-1)); %discretized equation, u(i,t+1)

    end

    plot(x,u,'k') %plotting

    pause(0.1)

end



New Code, with the CFL condition satisfied.


clear; clc;% clear the screen and memory

Nx=13; %number of space nodes

Lx=2; %length of space (m)

Lt=1; %length of time (s)

dx=Lx/(Nx-1); %grid spacing

c=2; %speed of wave (constant)

dt=dx*0.1/c; %time step, Courant number = 0.1

Nt=(Lt/dt)+1; %number of time nodes

a=c*dt/dx;

u=ones(Nx,1); %initialization of solution matrix

x=zeros(Nx,1); %initialization of space

t=zeros(fix(Nt),1); %initialization of space

hold on

for i=1:Nt-1

    t(i+1)=t(i)+dt;

end

for i=1:Nx-1 %space loop

    x(i+1)=x(i)+dx;

end

for i=0.5/dx:1/dx %initial conditions

    u(i)=2;

end

for j=0:dt:Lt %time loop

    un=u; %u(i,t)

    for i=2:Nx %solution loop, backward in space forward in time

        u(i)=un(i)-a*(un(i)-un(i-1)); %discretized equation, u(i,t+1)

    end

    plot(x,u,'k') %plotting

    pause(0.1)

end

Friday 9 March 2018

Solve PDEs using MATLAB (Code)

This is a post about a code I wrote to solve  1-D Poisson's equations. The method employed is called the finite difference method. For 1-D Laplace equation, the RHS of the equation mentioned below goes to zero. Hence all the terms in the B(i) loop equal zero. Also, B(1) and B(Nx) terms equal to the boundary conditions only. I hope this code helps you in learning something.

The example equation is mentioned below.
d2y/dx2 = x2+1 and y(0)=10, y(1)=20

The result of the code is a plot between the dependent and the independent variables, as shown in Fig. 1. The accuracy of the solutions lie around 1.5 % of the analytical solution.

%solution to 1D Poisson's equations with dirichlet boundary conditions, 2nd order accurate, uniform grid
clear; clc;
Nx=101; %Enter the number of grid points
clc;
A=zeros(Nx,Nx); %Stiffness matrix
B=zeros(Nx,1); %Dependent variable vector, also used for boundary conditions and other known terms
x=zeros(Nx,1); %Independent variable vector
x(Nx)=1; %Domain size
dx=x(Nx)/(Nx-1); %Grid spacing
B(1)=(((x(1).^2)+1)*(dx.^2))-10; %Enter the function the PDE equals to multiplied by the square of the grid spacing minus the first boundary condition
B(Nx)=(((x(Nx).^2)+1)*(dx.^2))-20; %Enter the function the PDE equals to multiplied by the square of the grid spacing minus the second boundary condition
for i=2:Nx-1 %Off boundary values for the dependent variable vector
    B(i)=((x(i).^2)+1)*(dx.^2); %Enter the function the PDE equals to multiplied by the the square of the grid spacing
end
for i=1:Nx-1 %Loop for independent variable
    x(i+1)=(i)*dx;
end
for i=1:Nx %Diagonal terms for the stiffness matrix
    A(i,i)=-2;
end
for i=1:Nx-1 %Off diagonal terms for the stiffness matrix
    A(i,i+1)=1;
    A(i+1,i)=1;
end
X=A\B;
hold on
set(gca,'FontSize',28)
xlabel('Independent Variable','FontSize',38.5)
ylabel('Dependent Variable','FontSize',38.5)
title('Dependent VS Independent Variable (d^2y/dx^2 = x^2+1)','FontSize',38.5);
plot(x,X)


Fig. 1. Plot from the code

Wednesday 21 February 2018

Solve ODEs using MATLAB (Code)

I have decided to teach myself some CFD coding using my own intuition and some free online tutorials. This is a post about code I wrote to solve a first order ordinary differential equation. The method employed is called the finite difference method. I will start by coding equations using this method and will slowly move to finite volume method. I hope this code helps you in learning something.

The equation in question is mentioned below.
dy/dx = x+4 and y(0)=3

A uniform grid was employed, as I have not yet figured out how to make non uniform grid. When I figure it out, I will update it here, which will be soon.

The code, mentioned below, starts with a variable called Nx, which represents the total number of grid points in which the domain is divided in to. A rule of thumb, the more points in the domain, more accurate the solution becomes at the cost of computation resources, mainly CPU time and RAM and storage.

x and y are the vectors in which the known and the unknown values are stored. x has the known values, like the length of a pipe through which a fluid flow or a rod through which heat flows etc. y stores the unknown values like temperature of the rod or velocity of the fluid etc. The values are stored at nodes.

y(1) means first value in the vector y. which also happens to be our boundary condition. y is the value of the function at x=0. x=0 is the first value in in the x vector, written as x(1).

x(Nx-1) represents the domain size. Minimum domain size is usually zero e.g. starting point of a rod or a pipe and maximum can be any real number.

To calculate the grid spacing, represented by dx, the domain size was divided by the number of elements. In this example, we have four nodes, two at corners and two in-between, forming a total of three elements.

First order finite difference method was used to discretize the given equation. And a for loop was used for the solution. Using 4 grid points, the solution has an accuracy of 2.22% against the analytical solution of the equation which can be verified by hand calculations. Thank you for reading.

%solution to dy/dx=x+4 y(0)=3
%uniform grid
clear; clc;
Nx=4; %number of grid points
x=zeros(Nx,1); %x vector, known, goes from some known value to maximum value of the domain
y=zeros(Nx,1); %y vector, one value known due to boundary condition rest unknown
y(1)=3; %boundary condition
x(Nx-1)=1; %domain size
dx=x(Nx-1)/(Nx-1); %grid spacing
for i=1:Nx-1
    x(i+1)=(i)*dx;
    y(i+1)=(dx.*(x(i)+4))+y(i); %discretized differential equation
end

Friday 23 October 2015

LU Decomposition MATLAB





%Please don't mess around with my code
clc;
R=input('How many variables are there in your system of linear equations? ');



clc;
disp ('Please enter the elements of the Coefficient matrix "A" and the Constant/Known matrix "B" starting from first equation');



A=zeros(R,R);

B=zeros(R,1);
for H=1:R

for i=1:R

fprintf ('Coefficient Matrix Column \b'), disp(i), fprintf ('\b\b Row \b'), disp(H);

I=input(' ');



A(H,i)=A(H,i)+I;
end

fprintf ('Known Matrix Row \b'), disp(H);

J=input(' ');



B(H,1)=B(H,1)+J;
end
clc;

[L,U] = lu(A);

Y = L\B;

X = U\Y;
fprintf ('The Coefficient Matrix "A" is \n'), disp(A);

fprintf ('The Constant/Known Matrix "B" is \n'), disp(B);

fprintf ('The Solution Matrix "X" is \n'), disp(X);