Challenge

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

OBJECTIVE OF THE CHALLENGE:

Objective of the challenge is to simulate the isentropic flow through a 1D subsonic-supersonic nozzle by deriving the governing (continuity,momentum and energy) equations in both conserved and non conserved form using Maccormack's technique.

Governing equations in non conservative form :

continuity equation (non-dimensional):

Momentum equation(non-dimensional):

Energy equation(non-dimensional):

all the primitive variables like ρ',v',A',T,'x', in the above equations are non-dimensionalised ,which are calculated by dividing them with the values at inlet which is considered as reservior

Conservative form of equations:

continuity equation:

=0

momentum equation:

Energy equation:

Maccormack's technique:

It is a widely used discretization technique to obtain numerical solution for hyperbolic Partial Differential Equtions

In Maccormack's method solution is found in two steps namely predictor step and corrector step explicitely. In predictor step an initial solution is found by using the initial boundary conditions by using forward differencing scheme and in the corrector step solution found in the predictor step is used to find an updated solution and then mean of both the solutions(otained in predictor and corrector steps) gives the final solution.

For non-conservative form no changes in the equations have been made to perform simulations but for conservative form governing equations are not solved directly instead , flux terms are written in the form of solution vectors inturn these solution vectors are function of primitive variables .

f1=u2;
f2=(u2.^2/u1)+(((gamma-1)/gamma).*(u3-(gamma/2).*(u2.^2/u1)));
f3=(gamma.*(u2.*u3./u1))-((gamma*(gamma-1)/2).*(u2.^3./u1.^2));

j2=(1/gamma)*rho_c(k)*t_c(k)*dloga_dx;

where u1,u2,u3 are functions of primitive variables

u1=rho_c.*a;
u2=rho_c.*a.*v_c;
v_c=u2./u1;
u3=rho_c.*((t_c./(gamma-1))+(gamma/2).*v_c.^2).*a;

with the above terms governing equations in conserved form can be written as

After this setup the whole process is same as followed in non-conserved form. Finally after corrector step's solution update primitive variables are extracted from the Solution terms u1,u2,u3.

Code for conservative_function:

function [rho_c,v_c,t_c,pr_c,rho_thr,v_thr,t_thr,m_c,time_c,pr_thr]=conservative_form_quassi_1D(n,x,dx,gamma,c,dt)
clear all
close all
clc

% grid points
n=31;
x=linspace(0,3,n);
% mesh
dx=x(2)-x(1);
% area
L = 3;
a = 1 +2.2*((x-(L/2)).^2);


% initial values of primitive variables
for i = 1:n
    if x(i)>= 0 && x(i)<=L/6
        rho_c(i) = 1;
        t_c(i) = 1;
    end
    if x(i)>=L/6 && x(i)<=L/2
        rho_c(i) = 1 -0.366*(x(i)-0.5);
        t_c(i) = 1 -0.167*(x(i)-0.5);
    end
    if x(i)>=L/2
        rho_c(i) = 0.634-0.3879*(x(i)-1.5);
        t_c(i) = 0.833-0.3507*(x(i)-1.5);
    end
end
  
gamma=1.4;
c=0.5;
% defining solution vector variables
v_c = 0.59./(rho_c.*a);
u1 = rho_c.*a;
u2 = u1.*v_c;
u3 = u1.*((t_c/(gamma-1)) + (gamma*0.5*(v_c.^2)));

%throat values
thr=find(a==1);
%dt = 0.0267;

% predictor step
for z=1:1400
  
dt = min(c*(dx./(sqrt(t_c)+v_c)));
time_c=dt*1400;
  
  u1_old=u1;
  u2_old=u2;
  u3_old=u3;
  
  
  % defining flux terms
    f1 = u2;
    f2 = ((u2.^2)./u1) + (((gamma-1)/gamma)*(u3 - ((gamma*0.5*(u2.^2))./u1)));
    f3 = ((gamma*u2.*u3)./u1) - ((gamma*0.5*(gamma-1)*(u2.^3))./(u1.^2));
 
    for k=2:n-1
        
        df1dx(k)=(f1(k+1)-f1(k))/dx;
        df2dx(k)=(f2(k+1)-f2(k))/dx;
        df3dx(k)=(f3(k+1)-f3(k))/dx;
    
        dloga_dx=(a(k+1)-a(k))/dx;
        
        j2=(1/gamma)*rho_c(k)*t_c(k)*dloga_dx; 
   
        du1dt_p(k)=-df1dx(k);
        du2dt_p(k)=-df2dx(k)+j2;
        du3dt_p(k)=-df3dx(k);
   
        % solution update
        u1(k)=u1(k)+du1dt_p(k)*dt;
        u2(k)=u2(k)+du2dt_p(k)*dt;
        u3(k)=u3(k)+du3dt_p(k)*dt;
      end
      
    
 
 % extracting primitive variables from solution vector
 rho_c=u1./a;
 v_c=u2./u1;
 t_c=(gamma-1)*((u3./u1)-(gamma/2)*(v_c.^2));
 pr=rho_c.*t_c;

 
  % defining flux terms
    f1 = u2;
    f2 = ((u2.^2)./u1) + (((gamma-1)/gamma)*(u3 - ((gamma*0.5*(u2.^2))./u1)));
    f3 = ((gamma*u2.*u3)./u1) - ((gamma*0.5*(gamma-1)*(u2.^3))./(u1.^2));
 
% corrector step
    for k=2:n-1
        
        df1dx(k)=(f1(k)-f1(k-1))/dx;
        df2dx(k)=(f2(k)-f2(k-1))/dx;
        df3dx(k)=(f3(k)-f3(k-1))/dx;
   
        dloga_dx=(a(k)-a(k-1))/dx;
        j2=(1/gamma)*rho_c(k)*t_c(k)*dloga_dx; 
        
        du1dt_c(k)=-df1dx(k);
        du2dt_c(k)=-df2dx(k)+j2;
        du3dt_c(k)=-df3dx(k);
      end
      
   
          %finding average values
          du1dt_avg=0.5*(du1dt_p+du1dt_c);
          du2dt_avg=0.5*(du2dt_p+du2dt_c);
          du3dt_avg=0.5*(du3dt_p+du3dt_c);
for j=2:n-1      
         % solution update  
         u1(j)=u1_old(j)+du1dt_avg(j)*dt;
         u2(j)=u2_old(j)+du2dt_avg(j)*dt;
         u3(j)=u3_old(j)+du3dt_avg(j)*dt;
 end
 
   
 % boundary conditions
% inlet

% extracting primitive variables 


rho_c = u1./a;
v_c = u2./u1;
t_c = (gamma-1)*((u3./u1) - ((gamma/2)*(v_c.^2)));
pr_c=rho_c.*t_c;


    
% Boundary Nodes
% Inlet
u1(1) = rho_c(1)*a(1);
u2(1) = 2*u2(2) - u2(3);
u3(1) = u1(1)*((t_c(1)/(gamma-1))+(0.5*gamma*(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);

% mass flow rate
m_c=(rho_c.*a.*v_c);
 
 % throat values for different time step
 rho_thr(z)=rho_c(thr);
 v_thr(z)=v_c(thr);
 t_thr(z)=t_c(thr);
 pr_thr(z)=pr(thr);
 
 
 %plot for mass flow rate
    figure(4)
   if z==1
    hold on
     plot(x,m_c,'r','linewidth',3)
     hold on 
   elseif z==50
     plot(x,m_c,'y','linewidth',3)
     hold  on
           elseif z==100
     plot(x,m_c,'g','linewidth',3)
     hold on
                   elseif z==200
     plot(x,m_c,'c','linewidth',3)
     hold on
                          elseif z==700
     plot(x,m_c,'--b')
    
     hold on
     xlabel('time steps')

     ylabel('mass flow rate ')
     title('mass flow rate--time wise variation along the length of the nozzle')
     legend('0dt','50dt','100dt','200dt','700dt')
     
   end  
  

  end

endfunction

  

Code for non- conservative function:

function [rho,v,t,m_n,pr,a,rho_th,v_th,t_th,pr_th,time_n]=Non_conservative_form(x,n,gamma,dx,c);
clear all
close all
clc

% grid points
n=31
x=linspace(0,3,n);
% mesh
dx=x(2)-x(1);

% defining input variables
rho= 1-0.3146.*x;
t=1-0.2314.*x;
v=(0.1 + 1.09.*x).*t.^0.5;

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

gamma=1.4
c=0.5
nt=1400
% throat value
th=find(a==1)
for i=1:nt
dt=min(c.*(dx./(sqrt(t)+v)));
time_n=dt*nt;
 
rho_old=rho;
v_old=v;
t_old=t;

for j=2:n-1
  % Non-conservative form
   %predictor step
   drhodx=(rho(j+1)-rho(j))/dx;
   dvdx=(v(j+1)-v(j))/dx;
   dtdx=(t(j+1)-t(j))/dx;
   dlog_a_dx=(log(a(j+1))-log(a(j)))/dx;
   
   drhodt_p(j)=-rho(j)*(dvdx)-rho(j)*v(j)*(dlog_a_dx)-v(j)*drhodx;
   dvdt_p(j)=-v(j)*(dvdx)-(1/gamma)*(dtdx+(t(j)/rho(j))*drhodx);
   dtdt_p(j)=-v(j)*(dtdx)-(gamma-1)*t(j)*(dvdx+v(j)*dlog_a_dx);
   
   %solution update 
   rho(j)=rho(j)+drhodt_p(j)*dt;
   v(j)=v(j)+dvdt_p(j)*dt;
   t(j)=t(j)+dtdt_p(j)*dt;
end
    
 for j=2:n-1 
   %corrector step
   drhodx=(rho(j)-rho(j-1))/dx;
   dvdx=(v(j)-v(j-1))/dx;
   dtdx=(t(j)-t(j-1))/dx;
   dlog_a_dx=(log(a(j))-log(a(j-1)))/dx;
   
   drhodt_c(j)=-rho(j)*(dvdx)-rho(j)*v(j)*(dlog_a_dx)-v(j)*drhodx;
   dvdt_c(j)=-v(j)*(dvdx)-(1/gamma)*(dtdx+(t(j)/rho(j))*drhodx);
   dtdt_c(j)=-v(j)*(dtdx)-(gamma-1)*t(j)*(dvdx+v(j)*dlog_a_dx);
 end
 
 
   %computing avg values
   drhodt_avg=0.5*(drhodt_p+drhodt_c);
   dvdt_avg=0.5*(dvdt_p+dvdt_c);
   dtdt_avg=0.5*(dtdt_p+dtdt_c);
   
    % final solution update
 for k=2:n-1
       rho(k)=rho_old(k)+drhodt_avg(k)*dt;
       v(k)=v_old(k)+dvdt_avg(k)*dt;
       t(k)=t_old(k)+dtdt_avg(k)*dt;
  end   
       
  %appying boundary conditions
  % inlet
  v(1)=2*v(2)-v(3);

  %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);
  
  % mass flow rate
  m_n=rho.*a.*v;
  % pressure ratio
  pr=rho.*t;
  
  % thaoat values 
  rho_th(i)=rho(th);
  v_th(i)=v(th);
  t_th(i)=t(th);
  pr_th(i)=pr(th);
  
  %plot for mass flow rate
   figure(2)
  if i==1
   hold on
    plot(x,m_n,'r','linewidth',3)
    hold on 
  elseif i==50
    plot(x,m_n,'b','linewidth',3)
    hold  on
          elseif i==100
    plot(x,m_n,'g','linewidth',3)
    hold on
                  elseif i==200
    plot(x,m_n,'c','linewidth',3)
    hold on
                         elseif i==700
    plot(x,m_n,'--b','linewidth',3)
    hold on
                              
    xlabel('time steps')
    ylabel('mass flow rate ')
    title('mass flow rate--time wise variation along the length of nozzle')
    legend('0dt','50dt','100dt','200dt','700dt')
    title('Non -conservative mass flow rate at different time steps ')
    
                     
  end
    
end
 
endfunction
 plot(x,m_n)
 

 

Main code:

clear all
close all
clc
  
 n=31;
 nt=1400
 c=0.5;
 x=linspace(0,3,n);
 dx=x(2)-x(1);
 gamma=1.4
 % non conseravtive form
 [rho,v,t,m_n,pr,a,rho_th,v_th,t_th,pr_th,time_n]=Non_conservative_form(x,n,gamma,dx,c);
 
 
 %conservative form
 [rho_c,v_c,t_c,pr_c,rho_thr,v_thr,t_thr,m_c,time_c,pr_thr]=conservative_form_quassi_1D(n,x,dx,gamma,c)

 % primitive variables at steady state non-conservative form
 figure(1)
 
 %density
 subplot(4,1,1)
 plot(x,rho)
 xlabel('length of the nozzle')
 ylabel('density')
 title('primitive variables at steady state')
 
 %velocity
 subplot(4,1,2)
 plot(x,v)
 xlabel('length of the nozzle')
 ylabel('velocity')
 
 %temperature
 subplot(4,1,3)
 plot(x,t)
 xlabel('length of the nozzle')
 ylabel('temperature')
 
 %pressure ratio
 subplot(4,1,4)
 plot(x,pr)
 xlabel('length of the nozzle')
 ylabel('pressure ratio')
 
  % primitive variables at steady state conservative form
  figure(5)
 
 %density
 subplot(4,1,1)
 plot(x,rho_c)
 xlabel('length of the nozzle')
 ylabel('density')
 title('primitive variables at steady state')
 
 %velocity
 subplot(4,1,2)
 plot(x,v_c)
 xlabel('length of the nozzle')
 ylabel('velocity')
 
 %temperature
 subplot(4,1,3)
 plot(x,t_c)
 xlabel('length of the nozzle')
 ylabel('temperature')
 
 %pressure ratio
 subplot(4,1,4)
 plot(x,pr_c)
 xlabel('length of the nozzle')
 ylabel('pressure ratio')

 
 % variation of primitive variables with respect to time
 
 figure(6)
 
 %density
 subplot(4,1,1)
 plot(rho_th)
 xlabel('Time steps')
 ylabel('density')
 title('variation of primitive variables- time marching(non-conservative)')
 
 %velocity
 subplot(4,1,2)
 plot(v_th)
 xlabel('Time steps')
 ylabel('velocity')
 
 %temperature
 subplot(4,1,3)
 plot(t_th)
 xlabel('Time steps')
 ylabel('temperature')
 
 %pressure ratio
 subplot(4,1,4)
 plot(pr_th)
 xlabel('rime steps')
 ylabel('pressure ratio')

 
 % variation of primitive variables with respect to time conservative
 figure(3)
 
 %density
 subplot(4,1,1)
 plot(rho_thr)
 xlabel('Time steps')
 ylabel('density')
 title('variation of primitive variables- time marching(conservative)')
 
 %velocity
 subplot(4,1,2)
 plot(v_thr)
 xlabel('Time steps')
 ylabel('velocity')
 
 %temperature
 subplot(4,1,3)
 plot(t_thr)
 xlabel('Time steps')
 ylabel('temperature')
 
 %pressure ratio
 subplot(4,1,4)
 plot(pr_thr)
 xlabel('Time steps')
 ylabel('pressure ratio')
 
 % normalized mass flow rate
 figure(7)
 plot(x,m_n)
 hold on 
 plot(x,m_c)
 xlabel('length 0f nozzle')
 ylabel('mass flow')
title('normalized mass flow rate')
legend('non-conservative','conservative')


 

Results and Discussion:

Distribution of primitive variables through the length of the nozzle at steady state.( Non-conservative form):

Distribution of primitive variables through the length of the nozzle at steady state. (conservative form):

from the above plots ,all the primitive variables except velocity decreases gradually in the form of hyperbolic curves. Inlet conditions are assumed to be a reservoir where temperature and density are assumed to be unity and constant at inlet and velocity is allowed to float and both the plots are alike.

Variation of primitive variables with respect to time (time marching ) non-conservative:

Variation of primitive variables with respect to time (time marching ) conservative:

Above plot says that ,at initial time steps variables were oscillating and are unsteady but got settled after 600 time steps, non-conservative form has less oscillations when compared to conservative form .


These initial oscillations are due to a phenomena well explained with a 'rubber band' example, when a rubber band is stretched to its maximum elastic limit and released it goes most compression in initial stages and very less at later stages the same effect is seen here. Initially due to some sudden contractions and expansions oscillations in the variables is seen.

Mass flow along the length of the nozzle at different time steps non-conservative form :

Number of grids n=31

n=61

The above plots are for mass flow along the length of the nozzle ,initial curve which is coloured red is for initial conditions assumed hence we named it as '0dt' which is in the form of a 'sine' wave. Initial conditions are assumed in such a way that density and velocity are hyperbolic in nature multiplied with area which is parabolic.


In time marching ,mass flow slowly started to converge and moving towards stable conditions and at 200 time steps it is close to constant mass flow rate but after reaching 700 time steps it is constant through out the length of the nozzle exactly equal to the analytical value 0.579 calculated at throat using primitive variables .


But in real situations it is never going to happen as we have fixed density and temperature to be constant resulting in velocity very close to zero but not actually.
second plot refers to mass flow rate for 61 grid points which is discussed in grid independency section.

Mass flow along the length of the nozzle at different time steps conservative form :

N=31

n=61

Plots for mass flow along the length for conserved form shows that , the initial conditions are chosen in such a way which has very less instabilities as the time marching continues instabilities develop in the flow and after reaching 700 time steps it converges to a constant value which is again 0.579 ,calculated at throat.

Normalized mass flow:

N=31

N=61

The above plots shows the advantage of conservative form of equations over non-conservative form in preserving mass in the flow filed which does not conclude that conservative form of equations gives better results. Better preservation of mass in conserved form is because mass flow itself is a dependent variable in the equations where as in non conservative form primary variables are dependent variables and mass flow is obtained from them secondarily. By this we can justify that why conservative form equations are labelled so.

Grid independency test:

FORM density ratio temperature ratio pressure ratio velocity ratio
Exact solutions calculated at throat 0.634 0.833 0.528 1.000
Non-conservative(n=61) 0.637 0.8359 0.5326 0.9137
conservative(n=61) 0.638 0.8351 0.533 0.9132
Non-conservative(n=31) 0.638 0.836 0.534 0.914
conservative(n=31) 0.650 0.840 0.546 0.899

Grid independency test:

Grid independence is very seriously considered in CFD. In general we simulate solutions for n grid points over the flow field until you reach a solution, if you double the grid points to 2n then you might get an different solution with different values it is because you are decreasing the size of grid or mesh by increasing the grid points and you have to continue it till you reach a solution which is insensitive to grid size .

In our case by increasing the grid points to 61 from initial size of 31 grids we have obtained a solutions which are tabulated above. we haven't achieved better results even after doubling the grid points .Hence our simulation is Grid independent.

conclusion:

1.From the above results and discussion, we can say that there is no superiority of conservative form over non-conservative form of equations, but conservative form gives better mass conservation and in the non-conservative form primitive variables are preserved well.

2.Complexity of solving conservative form is slightly more when compared to non-conservative form because in conservative form primitive variables are not directly solved but have to be decoded from the flux terms.

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.