Simulation of a 1D Super-sonic nozzle flow simulation using Macormack Method
Objective:
To write a code to solve the 1D supersonic nozzle flow equations using the Macormack Method
- Compare the results obtained using conservative and non-conservative forms of the governing equations
- Perform grid dependence test
Problem Setup:
Consider a steady , isentropic flow through a convergent -divergent nozzle as shown in the Fig.1.
The flow at the inlet to the nozzle comes from a reservoir where the pressure and temperature is constant.The cross-sectional area of the reservoir is so large that the velocity is almost Zero (`V~=0`).The flow expands isentropically to supersonic speeds at the nozzle exit .The flow is locally subsonic in the convergent section of the nozzle (`M<1`),sonic at the throat section (`M=1`) and supersonic at the divergent section (`M>1`).
Though in reality the flow field varies in the two-dimensional (xy plane), an assumption is made that the flow properties varies only along x axis ; the flow is defined as quasi-one-dimensional flow.
Fig.1
Governing Equations
A.Conservative Form
Non-Dimensional Form:
1.Continuity Equation:
`(delta(rho'.A'))/(deltat')+(delta(rho'.A'.v'))/(deltax')=0`
where:
`rho'=rho/rho_0` , `A'=A/(A_ast)` , `t'=t/((L/a_0))`
`v'=v/a_0` , `x'=x/L`
`rho_0rarr`Density of the reservoir `Lrarr`Length of the nozzle
`a_0rarr`Speed of sound in reservoir `A_astrarr`Sonic throat area
`rhorarr`Density of the fluid `vrarr`Velocity of the fluid
`Ararr`Area of the Nozzle
2.Momentum Equation:
`(delta(rho'.A'.v'))/(deltat')+(delta(rho'.A'.v' ^2+(1/gamma)rho'.A'))/(deltax')=(1/gamma).p'.(deltaA')/(deltax')`
where:
`p'=p/p_0`
`p_0rarr`Pressure of the reservoir `prarr`Pressure of the fluid
`gammararr`Specific heat ratio
3.Energy Equation:
`delta((rho'.((e')/(gamma-1)+gamma/2.v'^2).A'))/(deltat')+(delta(rho'.((e')/(gamma-1)+gamma/2.v'^2).v'.A'+p'.A'.v'))/(deltax')=0`
where:
`e'=e/e_0`
`e_0rarr`Energy of the reservoir
`e=C_V.T` `Trarr`Temperature
`e'=T'` `C_vrarr`Specific heat at constant volume
B.Non-Conservative Form
Non-Dimensional Form:
1.Continuity Equation:
`(deltarho')/(deltat')=-rho'.(deltav')/(deltax')-rho'.v'(delta(lnA'))/(deltax')-v'.(deltarho')/(deltax')`
2.Momentum Equation:
`(deltav')/(deltat')=-v'.(deltav')/(deltax')-(1/gamma)[(deltaT')/(deltax')+((T')/(rho')).(deltap')/(deltax')]`
3.Energy Equation:
`(deltaT')/(deltat')=-v'.(deltaT')/(deltax')-(gamma-1).T'[(deltav')/(deltax')+v'.(delta(ln(A')))/(deltax')]`
Macormack Method is used to solve the above partial differential equations .The derivations of the above equations and the background required to understand this project is explicated in the Chapter 7 of the book: John D. Anderson Jr. Computational Fluid Dynamics: The Basics with Applications.
Results:
1. Qualitative aspects of Quasi 1D nozzle flow at steady state:
Conservative form vs. Non-Conservative form(Grid-size n = 31)
It is clear that both the conservative and the non-conservative form return identical profiles at the steady state and the profiles matches exactly with the analytical values.
2. Non-Dimensional mass flow rate distribution at various time-steps:
a. Conservative Form: (Grid-size n = 31)
b. Non-Conservative Form: (Grid-size n = 31)
Although the non-conservation form and the conservation form have different initial conditions , it can be observed that variations in the mass flow rates are far less in the conservative form and closer to the exact analytical value of 0.579 .
3.Density, Temperature,Pressure,Mach number variation at the nozzle throat(Grid-size n = 31)
From the above graph , we can clearly observe that the conservative form converges quicker (approximately 400 iterations) and has lot less variations initially compared to non -conservative form .
Therefore, the minimum number of cycles for which the simulation should be run in order for convergence is around 400 for conservative form and around 1200 for non-conservative form.
After convergence , it can be observed that non-conservative form returns more accurate results compared to conservative form for the given grid size of n=31.
4. Comparison of the non-dimensional mass flow rates at steady state:
As evident from the plot the conservative form gives a mass flow rate variation that is close to a constant value and more accurate results at the steady state. The non-conservative form tends to show some oscillations at the inflow and outflow boundaries and is less satisfactory compared to the conservation form.
5.Grid dependency
For n=61
Non-dimensional mass flow rate comparision plot at steady state
Raise in the number of grid points to 61 has definitely increased the accuracy of the results. But the change is not so significant compared to results obtained from 31 grind points .Also at 61 grid points , both conservative and non-conservative results were very close to analytical solution.
6.Simulation time
For n=31
Execution time for Non-Conservative form is 2.46 Sec.
Execution time for Conservative form is 1.57 Sec.
For n=61
Execution time for Non-Conservative form is 3.02 Sec.
Execution time for Conservative form is 1.87 Sec.
Although convervative form requires more effort to code compared to non-conservative form. Once developed ,computational time for conservative form is much lesser than the non-conservative form.
Matlab Program:
Main Program
%********************* Nozzle Main program *******************************
clc
clear all
close all
%inputs
n=31; %number of nodes
x=linspace(0,3,n);
dx=x(2)-x(1);
gamma=1.4;
throat= ((n-1)/2)+1;% Throat point
C = 0.5; % Courant Number (specified for the problem)
% Non -Dimensional Area
A=1+(2.2*(x-1.5).^2);
%Time step
nt=1400;
dt=0.01;
tic
[rho,T,v,P,M,m,rho_throat,T_throat,v_throat,P_throat,M_throat,m_throat]= non_conservative_form(n,x,dx,gamma,throat,nt,dt,A);
Time_non_conservative=toc;
fprintf('Execution time for Non-Conservative form is %0.3g Sec. n' ,Time_non_conservative)
tic
[rho_c,T_c,v_c,P_c,M_c,m_c,rho_throat_c,T_throat_c,v_throat_c,P_throat_c,M_throat_c,m_throat_c]= conservative_form(n,x,dx,gamma,throat,nt,dt,A);
Time_conservative=toc;
fprintf('Execution time for Conservative form is %0.3g Sec. n ',Time_conservative)
figure(3)
subplot(2,3,1)
plot(x,rho,'r',x,rho_c,'b*')
xlabel('Length of nozzle(m)','FontWeight', 'bold')
ylabel('Non-Dimensional density','FontWeight', 'bold')
title('Density Profile','FontWeight', 'bold')
grid minor
legend('Non-Conservative','Conservative')
subplot(2,3,2)
plot(x,T,'r',x,T_c,'b*')
xlabel('Length of nozzle(m)','FontWeight', 'bold')
ylabel('Non-Dimensional Temperature','FontWeight', 'bold')
title('Temperature Profile','FontWeight', 'bold')
grid minor
legend('Non-Conservative','Conservative')
subplot(2,3,3)
plot(x,v,'r',x,v_c,'b*')
xlabel('Length of nozzle(m)','FontWeight', 'bold')
ylabel('Non-Dimensional Velocity','FontWeight', 'bold')
title('Velocity Profile','FontWeight', 'bold')
grid minor
legend('Non-Conservative','Conservative')
subplot(2,3,4)
plot(x,P,'r',x,P_c,'b*')
xlabel('Length of nozzle(m)','FontWeight', 'bold')
ylabel('Non-Dimensional Pressure','FontWeight', 'bold')
title('Pressure Profile','FontWeight', 'bold')
grid minor
legend('Non-Conservative','Conservative')
subplot(2,3,5)
plot(x,M,'r',x,M_c,'b*')
xlabel('Length of nozzle(m)','FontWeight', 'bold')
ylabel('Mach number','FontWeight', 'bold')
title('Mach number Profile','FontWeight', 'bold')
grid minor
legend('Non-Conservative','Conservative')
subplot(2,3,6)
plot(x,m,'r',x,m_c,'b*')
xlabel('Length of nozzle(m)','FontWeight', 'bold')
ylabel('Non-Dimensional Mass Flow Rate','FontWeight', 'bold')
title('Mass Flow Rate Profile','FontWeight', 'bold')
grid minor
legend('Non-Conservative','Conservative')
figure(4);
subplot(2,3,1)
plot(1:nt,rho_throat,'r',1:nt,rho_throat_c,'b')
hold on
line([0 nt],[0.634 0.634], 'color', 'm')
xlabel('Time(s)','FontWeight', 'bold')
ylabel('Non-Dimensional Density','FontWeight', 'bold')
title('Variation of Density at the Nozzle Throat','FontWeight', 'bold')
grid minor
legend('Non-Conservative','Conservative','Exact Solution')
subplot(2,3,2)
plot(1:nt,T_throat,'r',1:nt,T_throat_c,'b')
hold on
line([0 nt],[0.833 0.833], 'color', 'm')
xlabel('Time(s)','FontWeight', 'bold')
ylabel('Non-Dimensional Temperature','FontWeight', 'bold')
title('Variation of Temperature at the Nozzle Throat','FontWeight', 'bold')
grid minor
legend('Non-Conservative','Conservative','Exact Solution')
subplot(2,3,3)
plot(1:nt,v_throat,'r',1:nt,v_throat_c,'b')
xlabel('Time(s)','FontWeight', 'bold')
ylabel('Non-Dimensional Velocity','FontWeight', 'bold')
title('Variation of Velocity at the Nozzle Throat','FontWeight', 'bold')
grid minor
legend('Non-Conservative','Conservative')
subplot(2,3,4)
plot(1:nt,P_throat,'r',1:nt,P_throat_c,'b')
hold on
line([0 nt],[0.528 0.528], 'color', 'm')
xlabel('Time(s)','FontWeight', 'bold')
ylabel('Non-Dimensional Pressure','FontWeight', 'bold')
title('Variation of Pressure at the Nozzle Throat','FontWeight', 'bold')
grid minor
legend('Non-Conservative','Conservative','Exact Solution')
subplot(2,3,5)
plot(1:nt,M_throat,'r',1:nt,M_throat_c,'b')
hold on
line([0 nt],[1 1], 'color', 'm')
xlabel('Time(s)','FontWeight', 'bold')
ylabel(' Mach number','FontWeight', 'bold')
title('Variation of Mach number at the Nozzle Throat','FontWeight', 'bold')
grid minor
legend('Non-Conservative','Conservative','Exact Solution')
subplot(2,3,6)
plot(1:nt,m_throat,'r',1:nt,m_throat_c,'b')
hold on
line([0 nt],[0.579 0.579], 'color', 'm')
xlabel('Time(s)','FontWeight', 'bold')
ylabel('Non-Dimensional Mass Flow Rate','FontWeight', 'bold')
title('Variation of Mass Flow Rate at the Nozzle Throat','FontWeight', 'bold')
grid minor
legend('Non-Conservative','Conservative','Exact Solution')
Functions:
1.Conservatie_form
function [rho,T,v,P,M,m,rho_throat,T_throat,v_throat,P_throat,M_throat,m_throat]= conservative_form(n,x,dx,gamma,throat,nt,C,A)
%Calculating initial profiles
for i=1:n
if x(i)>=0 && x(i)<0.5
rho(i)=1;
T(i)=1;
else if x(i)>=0.5 && x(i)<1.5
rho(i)=1-(0.366*(x(i)-0.5));
T(i)=1-(0.167*(x(i)-0.5));
else if x(i)>=1.5 && x(i)<3.5
rho(i)=0.634-(0.3879*(x(i)-1.5));
T(i)=0.833-(0.3507*(x(i)-1.5));
end
end
end
end
% Defining non-dimensional velocity and non-dimensional pressure
v=0.59./(rho.*A);
P=rho.*T;
% Defining solution vectors U1, U2 and U3
U1=rho.*A;
U2=rho.*A.*v;
U3=rho.*A.*((T/(gamma-1))+(0.5*gamma.*v.*v));
%Outer time loop
for k=1:nt
% Copies of solution vectors
U1_ini=U1;
U2_ini=U2;
U3_ini=U3;
% Adaptable time step
dt=min(0.5.*dx./(sqrt(T) + v));
% Defining Flux vectors
F1=U2;
F2=((U2.^2)./(U1))+ ((gamma-1)/gamma).*(U3-(0.5*gamma.*U2.^2)./U1);
F3=((gamma.*U2.*U3)./U1)-(0.5*gamma*(gamma-1).*U2.^3)./(U1.^2);
% Predictor step
for i=2:n-1
dF1_dx=(F1(i+1)-F1(i))/dx;
dF2_dx=(F2(i+1)-F2(i))/dx;
dF3_dx=(F3(i+1)-F3(i))/dx;
% Continuity equation
dU1_dt_p(i)=-dF1_dx;
% Momentum equation
J2(i) = (1/gamma).*rho(i).*T(i).*((A(i+1)-A(i))/dx);
dU2_dt_p(i)=-dF2_dx+J2(i);
% Energy equation
dU3_dt_p(i)=-dF3_dx;
%solution update
U1(i)=U1(i)+dU1_dt_p(i)*dt;
U2(i)=U2(i)+dU2_dt_p(i)*dt;
U3(i)=U3(i)+dU3_dt_p(i)*dt;
end
% Updation of primitive variables and flux vectors
rho = U1./A;
v = U2./U1;
T = (gamma-1).*((U3./U1)-((gamma*v.^2)/2));
P=rho.*T;
F1=U2;
F2=((U2.^2)./(U1))+ ((gamma-1)/gamma).*(U3-(0.5*gamma.*U2.^2)./U1);
F3=((gamma.*U2.*U3)./U1)-(0.5.*gamma.*(gamma-1).*U2.^3)./(U1.^2);
% Corrector step
for j=2:n-1
dF1_dx=(F1(j)-F1(j-1))/dx;
dF2_dx=(F2(j)-F2(j-1))/dx;
dF3_dx=(F3(j)-F3(j-1))/dx;
% Continuity equation
dU1_dt_c(j)=-dF1_dx;
% Momentum equation
J2(j) = (1/gamma).*rho(j).*T(j).*((A(j)-A(j-1))/dx);
dU2_dt_c(j)=-dF2_dx+J2(j);
% Energy equation
dU3_dt_c(j)=-dF3_dx;
end
% Compute the average time derivative
dU1_dt_avg=0.5.*(dU1_dt_p+dU1_dt_c);
dU2_dt_avg=0.5.*(dU2_dt_p+dU2_dt_c);
dU3_dt_avg=0.5.*(dU3_dt_p+dU3_dt_c);
% Final solution update
for l=2:n-1
U1(l)=U1_ini(l)+dU1_dt_avg(l)*dt;
U2(l)=U2_ini(l)+dU2_dt_avg(l)*dt;
U3(l)=U3_ini(l)+dU3_dt_avg(l)*dt;
end
% Apply boundary conditions
% Inlet
U2(1) = 2*U2(2) - U2(3);
% Outlet
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);
% Updation of flow field variables
rho = U1./A;
v = U2./U1;
T = (gamma-1).*((U3./U1)-((gamma*v.^2)/2));
P=rho.*T;
% Calculating Mach number(M) and mass flow rate(m)
M= v./((T).^0.5);
m = rho.*v.*A;
% Capturing the values at throat for each iterations
rho_throat(k)=rho(throat);
v_throat(k)=v(throat);
T_throat(k)=T(throat);
P_throat(k)=P(throat);
M_throat(k)=M(throat);
m_throat(k)=m(throat);
% Ploting mass flow rate at different times
b=figure(2);
hold on;
if k ==50
plot(x,m,'b','linewidth',2);
else if k == 100
plot(x,m,'g','linewidth',2);
else if k == 150
plot(x,m,'r','linewidth',2);
else if k == 200
plot(x,m,'m','linewidth',2);
else if k == 700
plot(x,m,'-.','linewidth',2);
legend('50Deltat','100Deltat','150Deltat','200Deltat','700Deltat');
title('Variation of Mass flow rate at different time step(Conservative form)','FontWeight', 'bold', 'FontSize',12);
xlabel('Non-Dimensional Length of Nozzle (x/L)','FontWeight', 'bold', 'FontSize', 11 );
ylabel('Non -Dimensional Mass flow rate', 'FontWeight', 'bold', 'FontSize', 11)
grid minor
saveas(b, 'con_mass.png')
end
end
end
end
end
end
2. Non_conservative_form
function [rho,T,v,P,M,m,rho_throat,T_throat,v_throat,P_throat,M_throat,m_throat]= non_conservative_form(n,x,dx,gamma,throat,nt,C,A)
%Calculating initial profiles
rho=1-(0.3146*x);
T=1-(0.2314*x);
v=(0.1+(1.09*x)).*T.^(0.5);
%Outer time loop
for k=1:nt
rho_ini=rho;
T_ini=T;
v_ini=v;
% Time-step:
dt = 0.01;
% Predictor step
for i=2:n-1
dv_dx=(v(i+1)-v(i))/dx;
drho_dx=(rho(i+1)-rho(i))/dx;
dlogA_dx=(log(A(i+1))-log(A(i)))/dx;
dT_dx=(T(i+1)-T(i))/dx;
% continuity equation
drho_dt_p(i)=-rho(i)*dv_dx-rho(i)*v(i)*dlogA_dx-v(i)*drho_dx;
% momentum equation
dv_dt_p(i)=-v(i)*dv_dx-(1/gamma)*(dT_dx+((T(i)/rho(i))*drho_dx));
% energy equation
dT_dt_p(i)=-v(i)*dT_dx-(gamma-1)*T(i)*(dv_dx+(v(i)*dlogA_dx));
%solution update
rho(i)=rho(i)+drho_dt_p(i)*dt;
v(i)=v(i)+dv_dt_p(i)*dt;
T(i)=T(i)+dT_dt_p(i)*dt;
end
% Corrector step
for j=2:n-1
dv_dx_c=(v(j)-v(j-1))/dx;
drho_dx_c=(rho(j)-rho(j-1))/dx;
dlnA_dx_c=(log(A(j))-log(A(j-1)))/dx;
dT_dx_c=(T(j)-T(j-1))/dx;
% continuity equation
drho_dt_c(j)=-rho(j)*dv_dx_c-rho(j)*v(j)*dlnA_dx_c-v(j)*drho_dx_c;
% momentum equation
dv_dt_c(j)=-v(j)*dv_dx_c-(1/gamma)*(dT_dx_c+((T(j)/rho(j))*drho_dx_c));
% energy equation
dT_dt_c(j)=-v(j)*dT_dx_c-(gamma-1)*T(j)*(dv_dx_c+(v(j)*dlnA_dx_c));
end
% compute the average time derivative
drho_dt=0.5.*(drho_dt_p+drho_dt_c);
dv_dt=0.5.*(dv_dt_p+dv_dt_c);
dT_dt=0.5.*(dT_dt_p+dT_dt_c);
% Final solution update
for l=2:n-1
rho(l)=rho_ini(l)+drho_dt(l)*dt;
v(l)=v_ini(l)+dv_dt(l)*dt;
T(l)=T_ini(l)+dT_dt(l)*dt;
end
% Apply boundary conditions
% Inlet
v(1)=2*v(2)-v(3);
rho(1)=1;
T(1)=1;
% Outlet
rho(n)=2*rho(n-1)-rho(n-2);
v(n)=2*v(n-1)-v(n-2);
T(n)=2*T(n-1)-T(n-2);
%Computing Pressure(P), Mach number(M) and mass flow rate(m)
P=rho.*T;
M=(v./(T).^0.5);
m = rho.*v.*A;
% Capturing the values at throat for each iterations
rho_throat(k)=rho(throat);
v_throat(k)=v(throat);
T_throat(k)=T(throat);
P_throat(k)=P(throat);
M_throat(k)=M(throat);
m_throat(k)=m(throat);
% Ploting mass flow rate at different times
a=figure(1);
hold on;
if k ==50
plot(x,m,'b','linewidth',2);
else if k == 100
plot(x,m,'g','linewidth',2);
else if k == 150
plot(x,m,'r','linewidth',2);
else if k == 200
plot(x,m,'m','linewidth',2);
else if k == 700
plot(x,m,'-.','linewidth',2);
legend('50Deltat','100Deltat','150Deltat','200Deltat','700Deltat');
title('Variation of Mass flow rate at different time step(Non-Conservative form)','FontWeight', 'bold', 'FontSize',12);
xlabel('Non-Dimensional Length of Nozzle (x/L)','FontWeight', 'bold', 'FontSize', 11 );
ylabel('Non -Dimensional Mass flow rate', 'FontWeight', 'bold', 'FontSize', 11)
grid minor
saveas(a, 'Non-con_mass.png')
end
end
end
end
end
end
end
Please note that the above scripts are uploaded here.