Project

SImulation of 1D Superosnic nozzle flow using Maccormack's method

Objectives:

  • Implement both the Conservative and Non-conservative form of governing equations.
  • Display the timewise variation of the field variables.
  • Display the steady state variation of the flow field variables for the conservative and Non conservative form of the Quasi 1D flow.
  • Comparison of mass flow rates for Conservative and Non conservative forms
  • Performing a grid dependancy test.

In this problem, we study the case of isentropic flow through a convergent-divergent nozzle. The flow is subsonic at the inlet (M<1), sonic at the throat (M=1) and supersonic at the exit (M>1). We assume that the flow comes to the inlet from the reservoir. The area tends to infinity and hence the velocity is almost zero. But this is not the case, since at the inlet, the area has a finite value and hence M>0. Here, we assume the field variables vary only with x, hence its said to be quasi-one dimensional flow.

The governing eqautions are obtained in the PDE form using non-dimensionalized variables T',ρ', p' and A' ( Temperature, density, pressure and area respectively). The nozzle flow is a non-linear hyperbolic PDE problem.

Governing Equations:

1) Non Conservative form

a) Continuity equation

`(delrho)/(delt) = -rho*(delV)/(delx) - rho*V*(del(lnA))/(delx) - V*(delrho)/(delx)`

b) Momentum Equation

`(delV)/(delt)= -V*(delV)/(delx) - (1/gamma)*((delT)/(delx) + T/rho*(delrho)/(delx))`

c) Energy Equation

`(delT)/(delt)= -V*(delT)/(delx) - (gamma - 1)*T*((delV)/(delx) + V*(del(lnA))/(delx))`

2) Conservative form (In generic form)

Solution vectors:

`U1 = rho*A`

`U2 = rho*A*v`

`U3 = rho*A*((T/(gamma - 1)) + ((gamma/2)*(V^2)))`

Flux vectorss:

`F1 = U2`

`F2 = ((U2)^2)/(U1) + ((gamma-1)/gamma)*(U3 - (gamma*(U2)^2)/(2*U1))`

`F3 = ((gamma*U2*U3)/(U1)) - ((gamma*(gamma-1)/2)*((U2)^3/(U1)^2))`

Source term:

`J2 = 1/gamma*p*((delA)/(delx))`

The problem is solved using Maccormack method which is a predictor-corrector type method. The number of grid points 'n' chosen is 31. Different initial conditions for 'rho','v','T' and 'A' are assumed for the non conservative and conservative forms. A Courant number of 0.5 is chosen. The time step 'dt' is calculated based on the Courant number, speed of sound and initial velocity.

Following is the code for the main program :

Main Program 

close all
clear all
clc

% Main program to simulate 1D Subsonic-Supersonic isentropic nozzle flow using Maccormacks's technique 
% Non conservative and Conservative forms are used 

% Input conditions 

L = 3; % Length of nozzle 
n = 31; % Number of grid points 
x = linspace(0,L,n); % Grid 
dx = x(2) - x(1); % Distance between each node 
gamma = 1.4; % Specific heat ratio 

nt = 1400; % Number of time steps

C = 0.5; % Assumption of Courant number 

% Initial conditions (Non dimensionalized) 
rho = 1 - 0.3146*x; % Density
T = 1 - 0.2314*x; % Temperature 
v = (0.1 + (1.09*x)).*T.^0.5; % Velocity 
A = 1 + 2.2*(x - 1.5).^2; % Area 

% Throat position % A = A* at throat 
n_throat = (n - 1)/2; % Throat is at 1.5m 

a = sqrt(T); % Non dimensionalized Speed of sound 

% Time step using CFL criteria 
dt = min((C*dx)./(a + v));  % Non conservative 

% --Non Conservative Solver--

tic 
[mass_flow rho T p M] = Non_conservative_1D_supersonic_nozzle(n,x,dx,gamma,nt,rho,T,v,A,n_throat,a,dt);
t1 = toc; 

fprintf('Computation time (Non conservative) = %0.3f \n',t1);

% --Conservative Solver--

tic
[mass_flow_c rho_c T_c p_c M_c] = Conservative_1D_supersonic_nozzle(n,x,dx,gamma,nt,C,A,n_throat);
t2 = toc; 

fprintf('Computation time (Conservative) = %0.3f \n',t2);

% Steady state variations of mass flow rate of Conservative and Non conservative forms

figure(7) 

plot(x,mass_flow,'g','linewidth',1.25); % Non conservative
hold on 
plot(x,mass_flow_c,'r','linewidth',1.25); % Conservative
y = 0.579; % Exact analytical solution
line([0 3],[y y],'linewidth',1.25);
title('Steady state mass flow variations');
legend('Non conservative','Conservative','Exact analytical solution','Location','north')
xlabel('x/L')
ylabel('Non dimensional mass flow (\rhoVA)/(\rho_{o}a_{o}A^{*})')
grid minor 

Following is the function for Non conservative form :

% Non conservative solver for 1D Subsonic-Supersonic nozzle flow using Maccormack's method 

function [mass_flow rho T p M] = Non_conservative_1D_supersonic_nozzle(n,x,dx,gamma,nt,rho,T,v,A,n_throat,a,dt)

for k = 1:nt % Time loop 
    
    % Creating a copy of density, velocity and temperature
    rho_old = rho;
    v_old = v;
    T_old = T; 
        
    for i = 2:n-1 % Loop for inner nodes 
        
        % Predictor step (using forward differencing) 
        
        dv_dx = (v(i+1) - v(i))/dx;
        drho_dx = (rho(i+1) - rho(i))/dx; 
        dT_dx = (T(i+1) - T(i))/dx;
        dlogA_dx = (log(A(i+1)) - log(A(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));
        
       
      % First 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 (using backward differencing)
        
    for i = 2:n-1 % Loop for inner nodes 
        
        dv_dx = (v(i) - v(i-1))/dx;
        drho_dx = (rho(i) - rho(i-1))/dx; 
        dT_dx = (T(i) - T(i-1))/dx;
        dlogA_dx = (log(A(i)) - log(A(i-1)))/dx;
        
        % Continuity equation 
        drho_dt_c(i) = (-rho(i)*dv_dx) - (rho(i)*v(i)*dlogA_dx) - (v(i)*drho_dx);
        
        % Momentum equation 
        dv_dt_c(i) = (-v(i)*dv_dx) - ((1/gamma)*(dT_dx + (T(i)/rho(i))*drho_dx));
        
        % Energy equation 
        dT_dt_c(i) = (-v(i)*dT_dx) - ((gamma - 1)*T(i)*(dv_dx + v(i)*dlogA_dx));
        
    end 
    
    % Computing Average time derivative 
    
    drho_dt_avg = 0.5*(drho_dt_p + drho_dt_c);
    dv_dt_avg = 0.5*(dv_dt_p + dv_dt_c);
    dT_dt_avg = 0.5*(dT_dt_p + dT_dt_c);
          
    % Final solution update 
    
    for j = 2:n-1 
        
        rho(j) = rho_old(j) + drho_dt_avg(j)*dt; 
        v(j) = v_old(j) + dv_dt_avg(j)*dt;
        T(j) = T_old(j) + dT_dt_avg(j)*dt;
        
    end 
    
    % Applying Boundary conditions 
    % Inlet 
    
    rho(1) = 1;
    v(1) = 2*v(2) - v(3);
    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);
    
    M = v./sqrt(T); % Mach number 
    mass_flow = rho.*A.*v; % Mass flow rate (Non dimensional)
    p = rho.*T; % Pressure (Non dimensional) 
    
    % Nozzle throat flow field variables 
    
    p_throat(k) = p(n_throat); % Pressure 
    rho_throat(k) = rho(n_throat); % Density 
    T_throat(k) = T(n_throat); % Temperature 
    M_throat(k) = M(n_throat); % Mach number 
    
        
    % Instantaneous distribution of mass flow rate as a function of distance at different time steps
    
    figure(3) 
    
    if (k == 1)
        plot(x,mass_flow,'--b')
        hold on  
           elseif (k == 50)
             plot(x,mass_flow,'g','linewidth',1.25)
               elseif (k == 100)
                   plot(x,mass_flow,'m','linewidth',1.25)
                     elseif (k == 150)
                       plot(x,mass_flow,'r','linewidth',1.25)
                         elseif (k == 200)
                           plot(x,mass_flow,'c','linewidth',1.25)
                             elseif (k == 700)
                               plot(x,mass_flow,'k','linewidth',1.25)
             
                    
title('Instantaneous distribution of mass flow rate as a function of distance at different time steps (Non conservative')
xlabel('Non dimensional distance(x)');
ylabel('Non dimensional mass flow (\rhoVA)/(\rho_{o}a_{o}A^{*})');
legend('0\Deltat','50\Deltat','100\Deltat','150\Deltat','200\Deltat','700\Deltat');
grid minor

    end
     
end 


% Plotting results for conditions at nozzle throat

figure(1) 

subplot(4,1,1);
suptitle('Timewise variation of flow field at nozzle throat - Time step vs Field variables (Non conservative)')
plot(p_throat,'r')
title('Pressure');
ylabel('p/p_{o}'); 
axis([0 1400 0.4 1.2])
grid minor

subplot(4,1,2);
plot(rho_throat,'b')
title('Density');
ylabel('\rho/\rho_{o}'); 
axis([0 1400 0.6 1.1])
grid minor

subplot(4,1,3);
plot(T_throat,'g')
title('Temperature');
ylabel('T/T_{o}'); 
axis([0 1400 0.6 1.1])
grid minor

subplot(4,1,4);
plot(M_throat,'m')
title('Mach number');
xlabel('Number of time steps(k)');
ylabel('Mach number'); 
axis([0 1400 0.5 1.5])
grid minor

% Plotting steady state values 

figure(2) 

subplot(4,1,1);
suptitle('Steady state profile of properties of Quasi-1D flow (Non conservative)')
plot(x,p,'r')
ylabel('p/p_{o}'); 
axis([0 3 0 1.2]);
legend('Pressure ratio')
grid minor

subplot(4,1,2);
plot(x,rho,'b')
ylabel('\rho/\rho_{o}'); 
axis([0 3 0 1.2]);
legend('Density ratio')
grid minor

subplot(4,1,3);
plot(x,T,'g')
ylabel('T/T_{o}'); 
axis([0 3 0 1.2]);
legend('Temperature ratio')
grid minor

subplot(4,1,4);
plot(x,M,'m')
ylabel('Mach number');
legend('Mach number','Location','best')
axis([0 3 0 4]);
grid minor

Following is the function for Conservative form :

% Conservative solver for 1D Subsonic-Supersonic nozzle flow using Maccormack's method 

function [mass_flow_c rho_c T_c p_c M_c] = Conservative_1D_supersonic_nozzle(n,x,dx,gamma,nt,C,A,n_throat)

% Initial conditions 

for i = 1:length(x)
    
   if (x(i) >= 0 && x(i) < 0.5)
    
     rho_c(i) = 1;
     T_c(i) = 1; 
    
     elseif (x(i) >= 0.5 && x(i) < 1.5)
    
        rho_c(i) = 1 - 0.366*(x(i) - 0.5);
        T_c(i) = 1 - 0.167*(x(i) - 0.5);
    
          elseif (x(i) >= 1.5 && x(i) <= 3)
    
            rho_c(i) = 0.634 - 0.3879*(x(i) - 1.5);
            T_c(i) = 0.833 - 0.3507*(x(i) - 1.5); 
            
   end
   
   
end 

rho_c_old = rho_c;
v_c = 0.59./(rho_c.*A); % Analytical mass flow rate = 0.59 
p_c = rho_c.*T_c; %  Non dimenisonal Pressure
mass_flow_c_initial = rho_c.*A.*v_c;

% Initializing solution vectors 

U1 = rho_c.*A;
U2 = rho_c.*A.*v_c;
U3 = rho_c.*A.*((T_c/(gamma - 1)) + ((gamma/2)*(v_c.^2)));

a_c = sqrt(T_c); % Non dimensionalized speed of sound 
dt_c = min((C.*dx)./(a_c + v_c)); % Time step using CFL criteria 

for k = 1:nt % time loop 
    
    % Creating a copy of solution vectors 
    
    U1_old = U1;
    U2_old = U2;
    U3_old = U3; 
        
    % Defining flux terms 
    
    F1 = U2;
    F2 = (U2.^2./U1) + ((gamma-1)/gamma)*(U3 - (gamma*U2.^2)./(2*U1));
    F3 = ((gamma*U2.*U3)./U1) - ((gamma*(gamma-1)/2)*(U2.^3./U1.^2));
    
             
     for i = 2:n-1 % Loop for inner nodes 
        
        J2(i) = (1/gamma).*rho_c(i).*T_c(i).*((A(i+1)-A(i))/dx);
        dF1_dx = (F1(i+1) - F1(i))/dx;
        dF2_dx = (F2(i+1) - F2(i))/dx;
        dF3_dx = (F3(i+1) - F3(i))/dx;
                
        % Predictor step 
        
        dU1_dt_p(i) = - dF1_dx;
        dU2_dt_p(i) = - dF2_dx + J2(i);
        dU3_dt_p(i) = - dF3_dx; 
        
        % First solution update 
        
        U1(i) = U1(i) + dU1_dt_p(i)*dt_c;
        U2(i) = U2(i) + dU2_dt_p(i)*dt_c;
        U3(i) = U3(i) + dU3_dt_p(i)*dt_c;
        
      end 
      
    % Updating flux and primitive variables 
    
    F1 = U2;
    F2 = (U2.^2./U1) + ((gamma-1)/gamma)*(U3 - (gamma*U2.^2)./(2*U1));
    F3 = ((gamma*U2.*U3)./U1) - ((gamma*(gamma-1)/2)*(U2.^3./U1.^2)); 
    
    rho_c = U1./A;
    v_c = U2./U1;
    T_c = (gamma -1)*(U3./U1 - (gamma/2)*v_c.^2);
  
    for i = 2:n-1 % Corrector step 
        
        J2(i) = (1/gamma).*rho_c(i).*T_c(i).*((A(i)-A(i-1))/dx);
        dF1_dx = (F1(i) - F1(i-1))/dx;
        dF2_dx = (F2(i) - F2(i-1))/dx;
        dF3_dx = (F3(i) - F3(i-1))/dx;
                
               
        dU1_dt_c(i) = - dF1_dx;
        dU2_dt_c(i) = - dF2_dx + J2(i);
        dU3_dt_c(i) = - dF3_dx; 
        
    end 
    
    % Computing average time derivatives 
    
    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 j = 2:n-1 
        
        U1(j) = U1_old(j) + dU1_dt_avg(j)*dt_c;
        U2(j) = U2_old(j) + dU2_dt_avg(j)*dt_c;
        U3(j) = U3_old(j) + dU3_dt_avg(j)*dt_c;
        
    end 
    
    % Applying boundary conditions 
    
    % Inlet
    U1(1) = rho_c(1)*A(1); % rho = 1 at i = 1
    U2(1) = 2*U2(2) - U2(3);
    U3(1) = U1(1).*(((T_c(1)/(gamma-1)) + ((gamma/2)*v_c(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_c = U1./A;
    v_c = U2./U1;
    T_c = (gamma - 1)*((U3./U1) - ((gamma/2)*v_c.^2));
    p_c = rho_c.*T_c; 
    
    M_c = v_c./sqrt(T_c); % Mach number 
    mass_flow_c = rho_c.*A.*v_c; % Mass flow rate (Non dimensional)
    
    % Nozzle throat flow field variables 
    
    p_throat_c(k) = p_c(n_throat); % Pressure 
    rho_throat_c(k) = rho_c(n_throat); % Density 
    T_throat_c(k) = T_c(n_throat); % Temperature 
    M_throat_c(k) = M_c(n_throat); % Mach number 
    
      
    figure(4) 
    
    if (k == 1)
        plot(x,mass_flow_c_initial,'--b')
        hold on  
           elseif (k == 100)
              plot(x,mass_flow_c,'m','linewidth',1.25)
                  elseif (k == 200)
                      plot(x,mass_flow_c,'c','linewidth',1.25)
                          elseif (k == 700)
                              plot(x,mass_flow_c,'k','linewidth',1.25)
             
                    
title('Instantaneous distribution of mass flow rate as a function of distance at different time steps (Conservative)')
xlabel('Non dimensional distance(x)');
ylabel('Non dimensional mass flow (\rhoVA)/(\rho_{o}a_{o}A^{*})');
legend('0\Deltat','100\Deltat','200\Deltat','700\Deltat');
ylim([0.4 0.7]);
grid minor

    end
     
end 

figure(5) 

subplot(4,1,1);
suptitle('Steady state profile of properties of Quasi-1D flow (Conservative)')
plot(x,p_c,'r')
ylabel('p/p_{o}'); 
axis([0 3 0 1.2]);
legend('Pressure ratio')
grid minor

subplot(4,1,2);
plot(x,rho_c,'b')
ylabel('\rho/\rho_{o}'); 
axis([0 3 0 1.2]);
legend('Density ratio')
grid minor

subplot(4,1,3);
plot(x,T_c,'g')
ylabel('T/T_{o}'); 
axis([0 3 0 1.2]);
legend('Temperature ratio')
grid minor

subplot(4,1,4);
plot(x,M_c,'m')
ylabel('Mach number');
legend('Mach number','Location','best')
axis([0 3 0 4]);
grid minor

figure(6) 

subplot(4,1,1);
suptitle('Timewise variation of flow field at nozzle throat - Time step vs Field variables (Conservative)')
plot(p_throat_c,'r')
title('Pressure');
ylabel('p/p_{o}'); 
axis([0 1400 0.4 1.2])
grid minor

subplot(4,1,2);
plot(rho_throat_c,'b')
title('Density');
ylabel('\rho/\rho_{o}'); 
axis([0 1400 0.6 1.1])
grid minor

subplot(4,1,3);
plot(T_throat_c,'g')
title('Temperature');
ylabel('T/T_{o}'); 
axis([0 1400 0.6 1.1])
grid minor

subplot(4,1,4);
plot(M_throat_c,'m')
title('Mach number');
xlabel('Number of time steps(k)');
ylabel('Mach number'); 
axis([0 1400 0.5 1.5])
grid minor

Results:

1) Timewise variation of flow field variables at nozzle throat

i) Non conservative

ii) Conservative

The pressure, density, temperature and Mach number at the nozzle throat are plotted as a function of number of time steps. We see that there are oscillations that take place initially in the Non conservative form which dies out as the number of time steps increases. This is called as the 'rubber band effect' , where initially it is stretched and as steady state is reached, the field variables are less stretched or 'relaxed'. Whereas in the Conservative form, the oscillations are of small amplitude and die down quickly and becomes stable.

2) Minimum number of iterations to converge:

We see that the minimum number of iterations to converge for the Conserative form is more. This is because we are not directly solving the primtive variables. Rather the solution vectors are solved after which the flux vectors are obtained which are then used to obtain primitve variables. In the Conservative form, the flux vector is the dependant quantity. Whereas in the Non conservative form, the primitive variables are the dependant quantity.

3) Steady state values of properties

i) Non conservative

ii) Conservative

From both the steady state plots, we see that for the pressure, density and temperature drops at the outlet at the nozzle as expected. The Mach number increases as the flow reaches the outlet as it reaches supersonic speed.

4) Distribution of Mass flow rates as a function of time steps (Non conservative)

In this graph, the non dimensionalized mass flow rate is plotted as a function of distance along the nozzle. The dotted line represents the initial mass flow rate at '0deltat'. At '50deltat', the mass flow rate has changed considerably. From '100deltat' to '200deltat', we see that the mass flow keeps varying in the nozzle due to transient variations. Later, it starts becoming stable. At '700deltat' the mass flow has converged to a steady state value. It is close to the analytical result of 0.579 (mass flow rate).

5) Distribution of Mass flow rates as a function of time steps (Conservative)

Compared to the previous plot for Non conservative, we see that there is less transient variations in the mass flow at different time steps and converges in a smoother way. The variations in mass flow is much less severe in the Conservative approach.

6) Steady state mass flow variations (Conservative and Non conservative)

Here the steady state mass flow predicted by the Conservative form is more stable compared to the Non conservative form. The Non conservative has oscillations at the inlet and outlet of the nozzle. The steady state mass flow obtained by Conservative form is more closer to the analytical solution (0.579) compared to the Non conservative form. The mass flow is well conserved in the Conservative form as it is the dependant variable (along with the other flux variables) whereas the primtive variables are the dependant quantity in the Non conservative form.

7) Grid Dependance test

Here the effect of Grid dependance is employed to the problem. We see in both the Conservative and Non conservative form, when we increase the number of grid points to 61, the value of primitive variables are closer to the analytical solution. But the values of primitive variables at 31 grid points is also close to the values at 'n=61'. Hence we can say that at 'n=31', we achieved grid independance.

We see that the values of Non conservative form is closer to the analytical solution. By increasing the number of grid points to 61 for the Conservative form, the primitve variable values are closer to the analytical solution but less accurate compared to the Non conservative form with 31 grid points. The residuals are smaller in case of the Non conservative approach.

In conclusion, the superiority of one method over the other depends on the conservation,accuracy, residuals and computational efficiency. But we cannot establish the superiority of Conservative or Non conservative in this given case.

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.