Challenge

Week 7 - Simulation of a 1D Super-sonic nozzle flow simulation using Macormack Method

Simulation of a 1D Super-sonic nozzle flow simulation using Macormack Method:

The Macormack method is a widely used discretization scheme for the numerical solution of hyperbolic partial differential equations.

The MacCormack method is a variation of the two-step Lax–Wendroff scheme but is much simpler in application. To illustrate the algorithm, consider the following first order hyperbolic equation

`(delu)/(delt)+a*(delu)/(delx)=0`

The application of MacCormack method to the above equation proceeds in two steps; a predictor step which is followed by a corrector step.

Predictor step:

In the predictor step, a "provisional" value of u at time level n+1 is estimated as follows

`u_i^(n+1) = u_i^n-a(Deltat)/(Deltax)(u_(i+1)^n-u_i^n)`

The above equation is obtained by replacing the spatial and temporal derivatives in the previous first order hyperbolic equation using forward differences.

Corrector step:

In the corrector step, the predicted value `u_i^(n+1)` is corrected according to the equation

``u_i^(n+1) = u_i^(n+1/2)-a(Deltat)/(2Deltax)(u_(i)^(n+1)-u_(i-1)^(n+1`

Note that the corrector step uses backward finite difference approximations for spatial derivative. The time-step used in the corrector step is `(Deltat)/2` in contrast to the `Deltat` used in the predictor step.

Replacing the `u_i^(n+1/2)` term by the temporal average

`u_i^(n+1/2) = (u_i^n+u_i^(n+1))/2`

to obtain the corrector step as

`u_i^(n+1) = (u_i^n+u_i^(n+1))/2-a(Deltat)/(2Deltax)(u_(i)^(n+1)-u_(i-1)^(n+1))`

Main program:

The functions for the conservative and non conservative form are called and the comparison of mass flow rates between both forms is plotted.

clear all
close all
clc


%Inputs
n = 31;
x = linspace(0,3,n);
dx = x(2)-x(1);
gamma = 1.4;
throat = round(n/2);



%Analytical solution
a = 1+(2.2*(x-1.5).^2);
b = a*-1;
m = 0;

%Finding the mach number at eaxh points through out the nozzle
%Till the throat

for i = 1:throat
    residual = 1;
while residual > 1e-9
    m = m + 1e-4;
    residual = ((1/m^2)*((2/(gamma+1))*(1+((gamma-1)/2)*m^2))^((gamma+1)/(gamma-1)))-a(i)^2;
end
mach_number(i) = m;
end

%From throat to the exit
for i = (throat+1):n
    residual = 1;
while residual > 1e-9
    m = m + 1e-4;
    residual = ((1/m^2)*((2/(gamma+1))*(1+((gamma-1)/2)*m^2))^((gamma+1)/(gamma-1)))-a(i)^2;
    residual  = residual*-1;
end
mach_number(i) = m;
end


t  = (1+((gamma-1)/2).*mach_number.^2).^(-1);
rho = (1+((gamma-1)/2).*mach_number.^2).^(-1/(gamma-1))
p = rho.*t;



%Calling the functions
%Non conservation form
m_nc = Non_conservation_form(n,x,dx,gamma,throat)

%Conservation form
m_c = Conservation_form(n,x,dx,gamma,throat)

%Plotting Comparison of mass flow rates between the two forms 
figure(9)
plot(x,m_nc)
hold on
plot(x,m_c)
xlabel('Nozzle length')
ylabel('Mass flow rate')
legend('Non conservation form','Conservation form')
title('Comparison of mass flow rates between the two forms')

Functions:

function m = Non_conservation_form(n,x,dx,gamma,throat)


%Calculate initial profiles
rho = 1-0.3146*x;%Density
t = 1-0.2314*x; %t = temperature
v = (0.1+1.09*x).*t.^0.5;%Velocity

%Area
a = 1+2.2*(x-1.5).^2;

%Time step
nt = 1400;
dt = 0.02;

%CFL number calculation
CFL = max((v+sqrt(t))*dt/dx);

%Outer time loop
for k = 1:nt

     %Copying old values
     rho_old = rho;
     v_old = v;
     t_old = t;

     %predictor method
     for j = 2:n-1
        
        dvdx = (v(j+1)-v(j))/dx;
        drhodx = (rho(j+1)-rho(j))/dx;
        dtdx = (t(j+1)-t(j))/dx;
        dlog_a_dx = (log(a(j+1))-log(a(j)))/dx;

         %Continuity equation
         drhodt_p(j) = -rho(j)*dvdx-rho(j)*v(j)*dlog_a_dx-v(j)*drhodx;

         %Momentun equation
         dvdt_p(j) = -v(j)*dvdx-(1/gamma)*(dtdx+(t(j)/rho(j))*drhodx);

         %Energy equation
         dtdt_p(j) = -v(j)*dtdx-(gamma-1)*(dvdx+v(j)*dlog_a_dx);
         
         %Solution update   
         eho(j) = rho(j)+drhodt_p(j)*dt;
         t(j) = t(j)+dtdt_p(j)*dt;
         v(j) = v(j)+dvdt_p(j)*dt;
     end
     
      %Corrector method
      for j = 2:n-1

        dvdx = (v(j)-v(j-1))/dx;
        drhodx = (rho(j)-rho(j-1))/dx;
        dtdx = (t(j)-t(j-1))/dx;
        dlog_a_dx = (log(a(j))-log(a(j-1)))/dx;

         %Continuity equation
         drhodt_c(j) = -rho(j)*dvdx-rho(j)*v(j)*dlog_a_dx-v(j)*drhodx;

         %Momentun equation
         dvdt_c(j) = -v(j)*dvdx-(1/gamma)*(dtdx+(t(j)/rho(j))*drhodx);

         %Energy equation
         dtdt_c(j) = -v(j)*dtdx-(gamma-1)*(dvdx+v(j)*dlog_a_dx);
         
        
     end
       

     %compute the average time derivative
     dvdt = 0.5*(dvdt_p+dvdt_c);
     drhodt = 0.5*(drhodt_p+drhodt_c);
     dtdt = 0.5*(dtdt_p+dtdt_c);

     %Final solution update
     for i = 2:n-1
         rho(i) = rho_old(i)+drhodt(i)*dt;
         v(i) = v_old(i)+dvdt(i)*dt;
         t(i) = t_old(i)+dtdt(i)*dt;
     end
     %Apply boundary conditions
     %Inlet
     v(1) = 2*v(2)-v(3);

     %Outlet
     v(n) = 2*v(n-1)-v(n-2);
     rho(n) = 2*rho(n-1)-rho(n-2);
     t(n) = 2*t(n-1)-t(n-2);
     
     %Pressure
     p = rho.*t;

     %Mach number
     M = v./sqrt(t);

     %Mass flow rate
     m = rho.*a.*v;

    %Plotting Variation of mass flow rate at different time steps
     figure(4)
     hold on
     if k == 1
         plot(x,m);
     end
    if k == 1
         plot(x,m);
     end
    if k == 50
         plot(x,m);
     end
    if k == 250
         plot(x,m);
     end
    if k == 500
         plot(x,m);
     end
    if k == 750
         plot(x,m);
     end
    if k == 1400
         plot(x,m);
     end
     
    %Values at the throat 
    rho_th(k) = rho(throat);
    v_th(k) = v(throat); 
    t_th(k) = t(throat);
    p_th(k) = p(throat);
    M_th(k) = M(throat);
  
end
xlabel('Nozzle length')
ylabel('Mass flow rate')
legend('1dt','50dt','250dt','500dt','750dt','1400dt')    
title('Variation of mass flow rate at different time steps (Non conservation form)')

%Plotting Steady state primitive variable profile
figure(1)
 subplot(5,1,1)
     plot(x,v)
     xlabel('Nozzle length')
     ylabel('velocity')
     title('Steady state primitive variables profile (Non conservation form)')
   
     subplot(5,1,2)
     plot(x,rho)
     xlabel('Nozzle length')
     ylabel('Density')
    

     subplot(5,1,3)
     plot(x,t)
     xlabel('Nozzle length')
     ylabel('Temperature')

     subplot(5,1,4)
     plot(x,p)
     xlabel('Nozzle length')
     ylabel('Pressure')

     subplot(5,1,5)
     plot(x,M)
     xlabel('Nozzle length')
     ylabel('Mach number')

     %Plotting Transient variation of primitive variables at throat
     figure(2)
     subplot(5,1,1)
     plot(v_th)
     xlabel('time step')
     ylabel('velocity')
     title('Transient variation primitive variables at throat (Non conservation form)')
   
     subplot(5,1,2)
     plot(rho_th)
     xlabel('time step')
     ylabel('Density')
    

     subplot(5,1,3)
     plot(t_th)
     xlabel('time step')
     ylabel('Temperature')

     subplot(5,1,4)
     plot(p_th)
     xlabel('time step')
     ylabel('Pressure')

     subplot(5,1,5)
     plot(M_th)
     xlabel('time step')
     ylabel('Mach number')

     %Plotting steady state mass flow rate
     figure(3)
     plot(x,m)
     xlabel('length')
     ylabel('Mass flow rate')
     title('Steady state mass flow rate (Non conservation form)')

end
function m = Conservation_form(n,x,dx,gamma,throat)


%Initial conditions
for i = 1:n
    if x(i)>=0 && x(i) <= 0.5
        rho(i)= 1;
        t(i) = 1;

    elseif 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);

    elseif 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
     

 
%Nozzle Area
a = 1 + 2.2*(x - 1.5).^2;

%Velocity
v = 0.59./(rho.*a);%(Assuming constant mass flow rate)

%Pressure
p = rho.*t;

%Solution vectors
U1 = rho.*a;
z = ones(1,n);
U2 = 0.59.*z;
U3 = U1.*(t/(gamma-1)+(gamma/2).*v.^2);

%Time step
nt = 1400;

%CFL number
CFL = 0.5;

%Outer time loop
for k = 1:nt

     %Adaptive time step
     dt = max((CFL.*dx)./(v+sqrt(t)))

     %Copying old values of solution vectors
     U1_old = U1;
     U2_old = U2;
     U3_old = U3;

     %Initializing flux variables
      F1 = U2;
      F2 = ((U2.^2)./U1)+((gamma-1)/gamma)*(U3-(gamma/2)*((U2.^2./U1)));
      F3 = gamma*U2.*U3./U1-0.5*gamma*(gamma-1)*(U2.^3./U1.^2);


     %predictor method
     for j = 2:n-1
        
        
         %Continuity equation
         dU1dt_p(j) = -(F1(j+1)-F1(j))/dx;

         %Source term
         J2(j) = (1/gamma)*rho(j)*t(j)*(a(j+1)-a(j))/dx;

         %Momentun equation
         dU2dt_p(j) = -(F2(j+1)-F2(j))/dx+J2(j);

         %Energy equation
         dU3dt_p(j) = -(F3(j+1)-F3(j))/dx;
         
         %Solution update
         U1(j) = U1(j)+dU1dt_p(j)*dt;
         U2(j) = U2(j)+dU2dt_p(j)*dt;
         U3(j) = U3(j)+dU3dt_p(j)*dt;
         
     end
     %Primitive variables
     rho = U1./a;
     t = (gamma-1)*(U3./U1-(gamma/2)*(U2./U1).^2);

     %Reinitializing flux variables
     F1 = U2;
     F2 = ((U2.^2)./U1)+((gamma-1)/gamma)*(U3-(gamma/2)*((U2.^2./U1)));
     F3 = gamma*U2.*U3./U1-0.5*gamma*(gamma-1)*(U2.^3./U1.^2);


      %Corrector method
      for j = 2:n-1

         %Continuity equation
         dU1dt_c(j) = -(F1(j)-F1(j-1))/dx;
         
         %Source term
         J2(j) = (1/gamma)*rho(j)*t(j)*(a(j)-a(j-1))/dx;

         %Momentun equation
         dU2dt_c(j) = -(F2(j)-F2(j-1))/dx+J2(j);

         %Energy equation
         dU3dt_c(j) = -(F3(j)-F3(j-1))/dx;
         
        
     end
       

     %compute the average time derivative
     dU1dt = 0.5*(dU1dt_p+dU1dt_c);
     dU2dt = 0.5*(dU2dt_p+dU2dt_c);
     dU3dt = 0.5*(dU3dt_p+dU3dt_c);

     %Final solution update
     for i = 2:n-1
         U1(i) = U1_old(i)+dU1dt(i)*dt;
         U2(i) = U2_old(i)+dU2dt(i)*dt;
         U3(i) = U3_old(i)+dU3dt(i)*dt;
     end

     %Apply boundary conditions
     %Inlet
     U1(1) = a(1);
     U2(1) = 2*U2(2) - U2(3);
     U3(1) = U1(1)*(t(1)/(gamma-1)+0.5*gamma*v(1)^2);

     %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);
     
   %Final update of primitive variables
    rho = U1./a;
    v = U2./U1;
    t = (gamma-1).*(U3./U1-(gamma/2).*(U2./U1).^2);
    p = rho.*t;
    M = v./t.*0.5;
    m = U2;

    %Primitive variables at the throat
    rho_th(k) = rho(throat);
    v_th(k) = v(throat); 
    t_th(k) = t(throat);
    p_th(k) = p(throat);
    M_th(k) = M(throat);



%Plotting Variation of mass flow rate at different time steps
     figure(8)
     hold on
     if k == 1
         plot(x,m);
     end
     if k == 50
         plot(x,m);
     end
     if k == 250
         plot(x,m);
     end
     if k == 500
         plot(x,m);
     end
     if k == 750
         plot(x,m);
     end
     if k == 1400
         plot(x,m);
     end
     
  
  
end
xlabel('Nozzle length')
ylabel('Mass flow rate')
legend('1dt','50dt','250dt','500dt','750dt','1400dt')    
title('Variation of mass flow rate at different time steps (Conservation form)')


%Plotting Steady state primitive variable profile
figure(5)
 subplot(5,1,1)
     plot(x,v)
     xlabel('Nozzle length')
     ylabel('velocity')
     title('Steady state primitive variables profile (Conservation form)')
   
     subplot(5,1,2)
     plot(x,rho)
     xlabel('Nozzle length')
     ylabel('Density')
    

     subplot(5,1,3)
     plot(x,t)
     xlabel('Nozzle length')
     ylabel('Temperature')

     subplot(5,1,4)
     plot(x,p)
     xlabel('Nozzle length')
     ylabel('Pressure')

     subplot(5,1,5)
     plot(x,M)
     xlabel('Nozzle length')
     ylabel('Mach number')

     %Plotting Transient variation of primitive variables at throat
     figure(6)
     subplot(5,1,1)
     plot(v_th)
     xlabel('time step')
     ylabel('velocity')
     title('Transient variation of primitive variables at throat (Conservation form)')
   
     subplot(5,1,2)
     plot(rho_th)
     xlabel('time step')
     ylabel('Density')
    

     subplot(5,1,3)
     plot(t_th)
     xlabel('time step')
     ylabel('Temperature')

     subplot(5,1,4)
     plot(p_th)
     xlabel('time step')
     ylabel('Pressure')

     subplot(5,1,5)
     plot(M_th)
     xlabel('time step')
     ylabel('Mach number')

     %Plotting steady state mass flow rate
     figure(7)
     plot(x,m)
     xlabel('length')
     ylabel('Mass flow rate')
     title('Steady state mass flow rate (Conservation form)')

     end

Plots:

Non conservation form:

The above plots are drawn for each parameters such as Mach number,Density,Pressure,temperature for each time steps.

Initially, the values of all the parameters are very high and there are instabilities.And as the time step increases the plots become stable.

Here the mass flow rate is plotted as a function of non dimensional distance through the nozzle. Six different time steps are used in the graphs in time marching procedure.

As we can see from the graph after 250 time steps the plot starts to become stable

Conservation form:

The above plots are drawn for each parameters such as Mach number,Density,Pressure,temperature for each time steps.

Initially, the values of all the parameters are very high and there are instabilities.And as the time step increases the plots become stable.

It is clearly seen that the values of conservative form have less oscillations than the non conservative form.

Here the mass flow rate is plotted as a function of non dimensional distance through the nozzle. Six different time steps are used in the graphs in time marching procedure.

As we can see from the graph after 250 time steps the plot starts to become stable

The variation in mass flow rate is less in the conservative form.

Comparison of mass flow rates between the two forms:

From the above plot we can conclude thatthe mass flow rate for conservative form along the length of nozzle shows the values are almost stable and there are very less instabilities.Whereas the mass flow rate in non conservative form is showing more instabilities in graph which say that the mass flow rate is at some points of nozzle is more(inflow & outflow boundaries) and becomes less at throat and varies.

Grid independance test:

Non conservation form:

When n = 31,

rho = 0.639

t = 0.836

p = 0.533

M = 0.999

When n = 61

rho = 0.638

t = 0.835

p = 0.532

M = 1

Conservation form:

When n = 31,

rho = 0.652

t = 0.841

p = 0.548

M = 0.978

When n = 61

rho = 0.639

t = 0.835

p = 0.534

M = 1

Analytical solution:

rho = 0.634

t = 0.833

p = 0.528

M = 1

Note that all the variables are in thier dimensionless forms.

From the above values the 61 grid points are closer to the analytical solution than the 31 grid points.So accuracy of solution increases with increase in grid points

Conclusion:

1. Mass flow rate is more stable in the conservative form.

2. Accuracy of the solution increases as the number of grid points increases.

3. The values of the primitive variables are same in both the forms.

Your portfolio, next

Ship work like this
in your own course.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.