Week 7 - Simulation of a 1D Super-sonic nozzle flow simulation using Macormack Method
Simulation of a 1D supersonic nozzle flow using Maccormack method
The flow at the inlet to the nozzle arrives from the reservoir where the pressure and temperature are denoted by Po and Co. The cross-sectional area of the reservoir is very large and hence the fluid velocity is very low. The flow expands from subsonic to supersonic flow, whereas the velocity of the fluid at the throat is equal to the sonic velocity.
Governing equation
The assumptions made for solving nozzle flow problems is that the flow properties varies only in the x-direction and remains uniform across any given cross-section. This type of problem is called quasi 1D flow problem. The integral form of the governing equations are
Continuity equation
Momentum equation
Energy equations
The integral form of governing equations should be converted into corresponding PDE form such that the PDE can be numerically solved to obtain the primitive variables such as velocity, density, temperature, pressure and so on. A control volume of negligible dimensions(tending to zero) is selected and the above integral form of governing equation is applied to CV and solved to obtain both conservative and non-conservative form of PDE.
Conservative form of governing equation
Continuity equation
Momentum equation
Energy equation
Non-Conservative form of Governing equation
Continuity equation
Momentum equation
Energy equation
, , , , ,,
The prime in the above equations represents the non-dimensional form of governing equation. Non-dimensional form of Navier stokes equation can ease the analysis of the problem and it reduces the number of parameters.
The difference between the conservative and non-conservative form of governing equation is that both forms give the same analytical solution but the different numerical output. Conservative form provides accurate results and it can provide better results in the presence of shocks or discontinuities.
Steps for solving the Nozzle flow problem
Meshing
The given 1D domain is divided into n number of elements. For Nozzle flow problem the length of nozzle is chosen as 3 and the length is divided into 30 elements.
Discretization
The PDE is discretized and solved for the points in the domain. Maccormack method is used for discretizing the equation. Maccormack method gives better results for the hyperbolic equation and it is also called as a shock-capturing method. These methods can provide stable solutions in the presence of shock. Hence they are used in nozzle flow problems. In Maccormack method combination of both forward and backward differencing schemes can be used to solve for the primitive variables. Non-conservative and conservative form of governing equations are solved by using this method
The time step used for the simulation is
The minimum value of is used such that the time marching solution is following the actual unsteady flow variation that exists in nature.
Steps involved in Maccormack method
- Predictor step(forward differencing)
- Solution update
- Corrector step( Backward differencing)
- Determining the average of the time derivative
- Final solution update
Non-conservative form of Governing equation
In the non-conservative form of governing equation the continuity, momentum and energy equations can be discretized directly to obtain the primitive variables such as density, velocity and temperature.
The initial and boundary conditions are
Conservative form of governing equation
In the conservative form of governing equation, the primitive variables are grouped and they are represented in terms of solution vector U, flux vector F and source term J. The resulting equation is solved to obtain updated values of the density, velocity, temperature and so on
Now the governing equation can be written as
To obtain the primitive variables the solution vector U1, U2, U3 must be decoded.
It is better to write F1, F2, F3 in terms of U1, U2, U3 to avoid the occurrence of instabilities during the time marching solution.
The initial and boundary condition for the conservative form of governing equations are
Initial conditions
Matlab code
Main Program
%%Main Program
clear all
close all
clc
%inputs
n=31
x=linspace(0,3,n);
dx=x(2)-x(1);
a=1+(2.2*(x-1.5).^2)
gamma=1.4
nt=1400
%% calculation
% non conservative form
tic
[v_nc,t_nc,rho_nc,mass_flow_rate_nc,mach_nc,p_nc,t_nct,rho_nct,mach_nct,p_nct,mass_flow_rate_nct]=non_conservative_form(x,dx,n,a,gamma,nt)
simu_time_non_conservative=toc
%% conservative form
tic
[v_c,t_c,rho_c,mass_flow_rate_c,mach_c,p_c,t_ct,rho_ct,mach_ct,p_ct,mass_flow_rate_ct]=conservativeform(x,dx,n,a,gamma,nt)
simu_time_conservative=toc
%% Plotting Steady state variation
%Temperature
subplot(4,1,1)
grid on
title('Steady state distribution of primitive variables')
plot(x,t_nc,'k')
hold on
plot(x,t_c,'*')
xlabel('Length of Nozzle')
ylabel('Temperature')
hold on
%density
subplot(4,1,2)
grid on
plot(x,rho_nc,'k')
hold on
plot(x,rho_c,'*')
xlabel('Length of Nozzle')
ylabel('density')
hold on
%mach number
subplot(4,1,3)
grid on
plot(x,mach_nc,'k')
hold on
plot(x,mach_c,'*')
xlabel('Length of Nozzle')
ylabel('mach number')
hold on
%Pressure
subplot(4,1,4)
grid on
plot(x,p_nc,'k')
hold on
plot(x,p_c,'*')
xlabel('Length of Nozzle')
ylabel('Pressure')
legend('non conservative form','conservative form')
hold on
%% Plotting transient variation
time=1:nt
%Temperature
subplot(4,1,1)
grid on
title('Timewise distribution of primitive variables at Throat')
plot(time,t_nct,'k')
hold on
plot(time,t_ct,'r')
xlabel('Time step')
ylabel('Temperature')
hold on
%%density
subplot(4,1,2)
grid on
title('Timewise distribution of primitive variables at Throat')
plot(time,rho_nct,'k')
hold on
plot(time,rho_ct,'r')
xlabel('Time step')
ylabel('Density ')
hold on
%mach number
subplot(4,1,3)
grid on
title('Timewise distribution of primitive variables at Throat')
plot(time,mach_nct,'k')
hold on
plot(time,mach_ct,'r')
xlabel('Time step')
ylabel('mach number')
hold on
%Pressure
subplot(4,1,4)
grid on
title('Timewise distribution of primitive variables at Throat')
plot(time,p_nct,'k')
hold on
plot(time,p_ct,'r')
xlabel('Time step')
ylabel('Pressure')
hold on
legend('non conservative form','conservative form')
grid on
%% Plotting Normalized mass flow rate
title('Mass flow rate for both conservative and non conservative form')
plot(x,mass_flow_rate_nc,'k')
hold on
plot(x,mass_flow_rate_c,'r')
hold on
grid on
legend('non conservative form','conservative form')
xlabel('Length of nozzle')
ylabel('Mass flow rate')
%% Mass flow rate at throat different time steps
title('Mass flow rate at throat for different time steps')
plot(time,mass_flow_rate_nct,'k')
hold on
plot(time,mass_flow_rate_ct,'r')
hold on
grid on
legend('non conservative form','conservative form')
%% exact vs analytical
rho_e=[0.995,0.994,0.992,0.990,0.987,0.983,0.978,0.970,0.958,0.942,0.920,0.888,0.844,0.787,0.716,0.634,0.547,0.461,0.382,0.315,0.258,0.213,0.176,0.147,0.124,0.105,0.090,0.078,0.068,0.059,0.052]
plot(x,rho_e,'*')
hold on
plot(x,rho_c,'k')
hold on
plot(x,rho_nc,'r')
xlabel('length of nozzle')
ylabel('Density')
grid on
legend('Exact','conservative','nonconservative')
title('Exact vs Numerical values for density')
Conservative form
function [v_c,t_c,rho_c,mass_flow_rate_c,mach_c,p_c,t_ct,rho_ct,mach_ct,p_ct,mass_flow_rate_ct]=conservativeform(x,dx,n,a,gamma,nt,dt)
for w=1:n
if x(w)>=0 && x(w)<=0.5
rho_c(w)=1
t_c(w)=1
elseif x(w)>=0.5 && x(w)<=1.5
rho_c(w)=1-(0.366*(x(w)-0.5))
t_c(w)=1-(0.167*(x(w)-0.5))
elseif x(w)>=1.5 && x(w)<=3
rho_c(w)=0.634-(0.3879*(x(w)-1.5))
t_c(w)=0.833-(0.3507*(x(w)-1.5))
end
end
%time step
c=0.5
throat=find(a==1)
% Properties
p_c=rho_c.*t_c
v_c=0.59./(rho_c.*a)
dt= min(c*(dx./((t_c.^0.5)+v_c)))
mass_flow_rate_c=rho_c.*a.*v_c
u1=rho_c.*a
u2= u1.*v_c
u3=((t_c./(gamma-1))+(gamma*0.5.*(v_c.^2))).*u1
mach_c=v_c./(t_c.^0.5)
% initialization
p_init=p_c
v_init=v_c
mass_flow_rate_init=mass_flow_rate_c
u1_init=u1
u2_init=u2
u3_init=u3
mach_init=mach_c
for d=1:nt
% storing values
u1_old=u1;
u2_old=u2;
u3_old=u3;
F1=u2;
F2=((u2.^2)./u1)+(((gamma-1)/gamma)*(u3-(((u2.^2)./u1)*0.5*gamma)))
F3=((gamma.*u2.*u3)./u1)-(0.5*gamma*(gamma-1).*((u2.^3)./(u1.^2)))
for j=2:n-1
dadx(j)=(log(a(j+1))-log(a(j)))/(dx)
J(j)=(((gamma-1)/gamma)*(u3(j)-(((u2(j)^2)/u1(j))*0.5*gamma)))*dadx(j)
% Preditor step
du1_dt_p(j)=-((F1(j+1)-F1(j))/dx)
du2_dt_p(j)=-((F2(j+1)-F2(j))/dx)+J(j)
du3_dt_p(j)=-((F3(j+1)-F3(j))/dx)
% Solution update
u1(j)=u1(j)+(du1_dt_p(j)*dt)
u2(j)=u2(j)+(du2_dt_p(j)*dt)
u3(j)=u3(j)+(du3_dt_p(j)*dt)
end
%properties update
v_c=u2./u1
t_c=(gamma-1)*((u3./u1)-(gamma*0.5.*v_c.^2))
rho_c=u1./a
p_c=rho_c.*t_c
F1=u2;
F2=((u2.^2)./u1)+(((gamma-1)/gamma)*(u3-(((u2.^2)./u1)*0.5*gamma)))
F3=((gamma.*u2.*u3)./u1)-(0.5*gamma*(gamma-1).*((u2.^3)./(u1.^2)))
for j=2:n-1
dadx(j)=(log(a(j))-log(a(j-1)))/(dx)
J(j)=(((gamma-1)/gamma)*(u3(j)-(((u2(j)^2)/u1(j))*0.5*gamma)))*dadx(j)
% corrector step
du1_dt_c(j)=-((F1(j)-F1(j-1))/dx)
du2_dt_c(j)=-((F2(j)-F2(j-1))/dx)+J(j)
du3_dt_c(j)=-((F3(j)-F3(j-1))/dx)
du1_dt(j)=0.5*(du1_dt_p(j)+du1_dt_c(j))
du2_dt(j)=0.5*(du2_dt_p(j)+du2_dt_c(j))
du3_dt(j)=0.5*(du3_dt_p(j)+du3_dt_c(j))
u1(j)=u1_old(j)+(du1_dt(j)*dt)
u2(j)=u2_old(j)+(du2_dt(j)*dt)
u3(j)=u3_old(j)+(du3_dt(j)*dt)
end
u1(1)=rho_c(1)*a(1)
u2(1)=2*u2(2)-u2(3)
u3(1)=((t_c(1)/(gamma-1))+(gamma*0.5*(v_c(1)^2)))*u1(1)
u1(n)=2*u1(n-1)-u1(n-2)
u2(n)=2*u2(n-1)-u2(n-2)
u3(n)=2*u3(n-1)-u3(n-2)
%properties update
v_c=u2./u1
t_c=(gamma-1)*((u3./u1)-(gamma*0.5.*v_c.^2))
rho_c=u1./a
p_c=rho_c.*t_c
mass_flow_rate_c=rho_c.*a.*v_c
mach_c=v_c./(t_c.^0.5)
% Throat values
t_ct=t_c(throat)
rho_ct=rho_c(throat)
mach_ct=mach_c(throat)
p_ct=p_c(throat)
mass_flow_rate_ct=mass_flow_rate_c(throat)
%% plotting mass flow rate inside the nozzle for different time step
if d==50
plot(x,mass_flow_rate_c,'k')
hold on
elseif d==100
plot(x,mass_flow_rate_c,'*')
hold on
elseif d==200
plot(x,mass_flow_rate_c,'b')
hold on
elseif d==600
plot(x,mass_flow_rate_c,'g')
hold on
elseif d==800
plot(x,mass_flow_rate_c,'o')
hold on
elseif d==1400
plot(x,mass_flow_rate_c,'r')
hold on
grid on
title('Variation of mass flow rate along the nozzle for different time step-conservative form')
legend('50','100','200','600','800','1400')
xlabel('length of nozzle')
ylabel('mass flow rate')
end
end
end
Non Conservative form
function [v_nc,t_nc,rho_nc,mass_flow_rate_nc,mach_nc,p_nc,t_nct,rho_nct,mach_nct,p_nct,mass_flow_rate_nct]=non_conservative_form(x,dx,n,a,gamma,nt,dt)
throat=find(a==1)
rho_nc=1-0.3146*x
t_nc=1-0.2314*x
v_nc=(0.1+1.09*x).*t_nc.^0.5
%Time step
c=0.5
dt= min(c*(dx./((t_nc.^0.5)+v_nc)))
%% calculating primitive variables by Macormack method
for d=1:nt
rho_old_nc=rho_nc
t_old_nc=t_nc
v_old_nc=v_nc
for j=2:n-1
%% Preditor Step (Forward differencing)
dvdx=(v_nc(j+1)-v_nc(j))/dx
dtdx=(t_nc(j+1)-t_nc(j))/dx
drhodx=(rho_nc(j+1)-rho_nc(j))/dx
dadx=(log(a(j+1))-log(a(j)))/dx
% Continuity equation
drhodt_p(j)=-(rho_nc(j)*dvdx)-(rho_nc(j)*v_nc(j)*dadx)-(v_nc(j)*drhodx)
% Momentum equation
dvdt_p(j)=-(v_nc(j)*dvdx)-((1/gamma)*(dtdx+(t_nc(j)/rho_nc(j))*drhodx))
% Energy equation
dtdt_p(j)=-(v_nc(j)*dtdx)-((gamma-1)*t_nc(j)*(dvdx+(v_nc(j)*dadx)))
v_nc(j)=v_nc(j)+dvdt_p(j)*dt
t_nc(j)=t_nc(j)+dtdt_p(j)*dt
rho_nc(j)=rho_nc(j)+drhodt_p(j)*dt
end
%% corrector step
for j=2:n-1
dvdx=(v_nc(j)-v_nc(j-1))/dx
dtdx=(t_nc(j)-t_nc(j-1))/dx
drhodx=(rho_nc(j)-rho_nc(j-1))/dx
dadx=(log(a(j))-log(a(j-1)))/dx
% Continuity equation
drhodt_c(j)=-(rho_nc(j)*dvdx)-(rho_nc(j)*v_nc(j)*dadx)-(v_nc(j)*drhodx)
% Momentum equation
dvdt_c(j)=-(v_nc(j)*dvdx)-((1/gamma)*(dtdx+(t_nc(j)/rho_nc(j))*drhodx))
% Energy equation
dtdt_c(j)=-(v_nc(j)*dtdx)-((gamma-1)*t_nc(j)*(dvdx+(v_nc(j)*dadx)))
end
drhodt=0.5*(drhodt_p+drhodt_c)
dvdt=0.5*(dvdt_p+dvdt_c)
dtdt=0.5*(dtdt_p+dtdt_c)
for j=2:n-1
v_nc(j)=v_old_nc(j)+dvdt(j)*dt
t_nc(j)=t_old_nc(j)+dtdt(j)*dt
rho_nc(j)=rho_old_nc(j)+drhodt(j)*dt
end
% starting point
v_nc(1)=2*v_nc(2)-v_nc(3)
t_nc(1)=1
rho_nc(1)=1
% end point
v_nc(n)=2*v_nc(n-1)-v_nc(n-2)
t_nc(n)=2*t_nc(n-1)-t_nc(n-2)
rho_nc(n)=2*rho_nc(n-1)-rho_nc(n-2)
mass_flow_rate_nc=rho_nc.*a.*v_nc
mach_nc=v_nc./(t_nc.^0.5)
p_nc=rho_nc.*t_nc
%% Throat values
t_nct=t_nc(throat)
rho_nct=rho_nc(throat)
mach_nct=mach_nc(throat)
p_nct=p_nc(throat)
mass_flow_rate_nct=mass_flow_rate_nc(throat)
%% plotting mass flow rate inside the nozzle for different time step
if d==50
plot(x,mass_flow_rate_nc,'k')
hold on
elseif d==100
plot(x,mass_flow_rate_nc,'*')
hold on
elseif d==200
plot(x,mass_flow_rate_nc,'b')
hold on
elseif d==600
plot(x,mass_flow_rate_nc,'g')
hold on
elseif d==800
plot(x,mass_flow_rate_nc,'o')
hold on
elseif d==1400
plot(x,mass_flow_rate_nc,'r')
hold on
grid on
title('Variation of mass flow rate along the nozzle for different time step-Non conservative form')
legend('50','100','200','600','800','1400')
xlabel('length of nozzle')
ylabel('mass flow rate')
end
end
end
Results and discussion
1) Steady-state distribution of primitive variables inside the nozzle
From the above graph, it can be concluded Mach number increases with an increase in the value of x. At the throat, the value of the Mach number is equal to 1. And there is a gradual decrease in the temperature, pressure and density. Both conservative and non-conservative form gives similar results.
At timestep=1400 the numerical solution matches with the exact solution with the least amount of error.
2)Time vice variation of primitive variables
The above graph shows the timewise distribution of primitive variables at the throat
3) Variation of Mass flow rate distribution inside the nozzle at different time steps during the time-marching process
Above graph represents the variation of mass flow rate along the length of the nozzle at different time steps. The value of mass flow rate obtained from both conservative and non-conservative form shows consistency at the time step of 600 and above.
The total time taken for solving the conservative form is more when compared to non-conservative form.
4)Comparison of Normalized mass flow rate distributions of both forms
It can be observed from the graph that the mass flow rate is preserved and shows stability for conservative form rather than the non-conservative form. This is because the mass flow rate is the primitive variable for the conservative form. But in non-conservative form, the primitive variables are density, velocity and so on. The mass flow rate is calculated separately for non-conservative form.
5) Grid independence test
From the table, it can be concluded that as the number of grid points increases the solution accuracy increases and the non-conservative form show better results than the conservative form.
Conclusion:
The non-conservative form produces accurate results for the primitive variable and the conservative form gives better results for the flux variable.