Challenge

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

Objective:

The main objective of this challenge is to implement all the CFD techniques which we have learned so far. In some cases, more than one CFD technique will be used to solve the same flow problem. This is done to give you some comparison of the strengths and weakness of one technique versus another and a feeling for the relative difficulty of setting up one technique on the computer compared to another.

The solution is computed by MacCormack technique, which is an explicit finite difference scheme that is very popular in CFD. The MacCormack method is multi-level, meaning that there is a multistep process to reach the solution. These steps are traditionally called predictor and corrector, where an averaging can then be performed. The averaging at each time step is what allows for the higher accuracy while using a relatively simple finite difference scheme.

NOTE: A step-by-step procedure of the MacCormack method can be found in Anderson.

INITIAL SETUP OF THE PROBLEM:

We are considering the steady, isentropic flow through a convergent and divergent nozzle as below. The flow properties are defined at inlet and outlet as mentioned in the figure as the nozzle is connected to a reservoir where area tends to infinity.

Even though the flow is in both X and Y directions, we are assuming the flow is Quasi One-Dimensional flow. As we already know the set of governing equations for quasi 1D flow as follows:

After introducing Non-Dimensional variables, the following set of equations will get for Non conservative form:

For Conservative form:

The equations for Quasi 1D flow can be expressed in generic form. Let us define the elements of the solutions vector as U, the flux vector as F and the Source term as J as follows:

Octave Function program for Non-Conservative form:

function [v,rho,t,m,mach,pr,v_t,rho_t,t_t,m_t,mach_t,pr_t] = Non_conservative_form(L,n,c,nt,throat)
% Initial variables
x = linspace(0,L,n);
dx = x(2)-x(1);

% initial profiles of non dimensional numbers
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
gamma = 1.4;                     %adiabatic index

% Caluculating time step using courant number criteria
for i = 1:n
del_t(i) = c*(dx/(t(i)^0.5+v(i)));
endfor
% Minimum value of delta t will give more accutacy
dt = min(del_t)

%outer time loop
for k = 1:nt
  % saving 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;
    dlogadx = (log(a(j+1))-log(a(j)))/dx;
    
    % continuity equation
    drhodt_p(j) = -rho(j)*dvdx-rho(j)*v(j)*dlogadx-v(j)*drhodx;
    %momentum 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)*t(j)*(dvdx+v(j)*dlogadx);
    
    %updating old values
    rho(j) = rho(j)+drhodt_p(j)*dt;
    v(j) = v(j)+dvdt_p(j)*dt;
    t(j) = t(j)+dtdt_p(j)*dt;
  endfor
  
  %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;
    dlogadx = (log(a(j))-log(a(j-1)))/dx;
    
    % Continuity equation
    drhodt_c(j) = -rho(j)*dvdx-rho(j)*v(j)*dlogadx-v(j)*drhodx;
    % Momentum 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)*t(j)*(dvdx+v(j)*dlogadx);
     
  endfor
  
  % co mputing the average values
    drhodt  = 0.5*(drhodt_p+drhodt_c);
    dvdt    = 0.5*(dvdt_p+dvdt_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
  endfor
  
  
  % boundary conditions
  rho(1) = 1;
  v(1) = 2*v(2)-v(3);
  t(1) = 1;
  
  %final boundary
  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);
  
  % Caluculating mass flow rate
  m = rho.*a.*v;
  
  %caluculating pressure
  pr = rho.*t
  
  % caluculating mach number
  mach = v./(t.^0.5);
  
% Caluculating flow variables at throat
v_t(k) = v(throat);
rho_t(k) = rho(throat);
t_t(k) = t(throat);
m_t(k) = m(throat);
pr_t(k) = pr(throat);
mach_t(k) = mach(throat);


% Plotting mass flow rate by varying time steps
  figure(1)
 if k==50
   plot(x,m,'r', 'linewidth',1.5);
   hold on
 elseif k == 100
   plot(x,m,'b', 'linewidth',1.5);
   hold on
 elseif k == 200
   plot(x,m,'g', 'linewidth',1.5);
   hold on
 elseif k == 500
   plot(x,m,'k', 'linewidth',1.5);
   hold on
 elseif k == 700
   plot(x,m,'c', 'linewidth',1.5);
   hold on
 elseif k == 1400
   plot(x,m,'y', 'linewidth',1.5);
  
 xlabel('Distance through Nozzle along X-Axis');
 ylabel('Non_Dimensional Flow Rate');
 title(sprintf('Comparision of mass flow rate at Different time steps'));
 legend({'50 timesteps','100 timesteps','200 timesteps','500 timesteps','700 timesteps','1400 timesteps'})
 end
endfor
endfunction

Octave Function program for Conservative form:

function [v,rho,t,m,mach,pr,v_t,rho_t,t_t,m_t,mach_t,pr_t] = Conservative_form(L,c,n,nt,throat)
  % Initial variables
  x = linspace(0,L,n);
  dx= x(2)-x(1);
  a= 1+2.2*(x-1.5).^2;
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);
  endif
endfor

 
  % Initial conditions
  v = 0.59./(rho.*a);
  gamma = 1.4;
  
  % Solution vector parameters
  pr = rho.*t;
  u1 = rho.*a;
  u2 = rho.*a.*v;
  u3 = u1.*((t./(gamma-1))+(gamma/2).*(v.^2));
  
  %Caluculating the time step using courant number
  %dt = min (c.*(dx./(t.^0.5)+v));
   dt = 0.0267;
  %outer time loop
  for k = 1:nt
    %saving old values
    u1_old = u1;
    u2_old = u2;
    u3_old = u3;
    
    
    % Pure form of the flux terms
    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);
    
    % predictor method
    for j = 2:n-1
      df1dx(j) = (f1(j+1)-f1(j))/dx;
      df2dx(j) = (f2(j+1)-f2(j))/dx;
      df3dx(j) = (f3(j+1)-f3(j))/dx;
      dadx(j) = (a(j+1)-a(j))/dx;
      j2(j) = (1/gamma)*rho(j)*t(j)*dadx(j);
      
      % Continuity equation
      du1dt_p(j) = -df1dx(j);
      
      % Momentum equation
      du2dt_p(j) = -df2dx(j)+j2(j);
      
      %energy equation
      du3dt_p(j)= -df3dx(j);
      
      % 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;
    endfor
 
  % Getting primitive terms from above data
    
    rho = u1./a;
    v = u2./u1;
    t = (gamma-1)*((u3./u1)-(gamma*v.^2./2));
    
    % Pure form of flux terms for corrector step.
    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);
    
    % corrector step
    for j = 2:n-1
     df1dx(j) = (f1(j)-f1(j-1))/dx;
      df2dx(j) = (f2(j)-f2(j-1))/dx;
      df3dx(j) = (f3(j)-f3(j-1))/dx;
      dadx(j) = (a(j)-a(j-1))/dx;
      j2(j) = (1/gamma)*rho(j)*t(j)*dadx(j);
      
      % Continuity equation
      du1dt_c(j) = -df1dx(j);
      
      % Momentum equation
      du2dt_c(j) = -df2dx(j)+j2(j);
      
      %energy equation
      du3dt_c(j)= -df3dx(j);
      
    endfor
    
     % average derivative
    
    du1dt = 0.5*(du1dt_p+du1dt_c);
    du2dt = 0.5*(du2dt_p+du2dt_c);
    du3dt = 0.5*(du3dt_p + du3dt_c);
    
    % final solution
    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;
    endfor
    
      % boundary conditions
    % At Inlet
    % Before setting up the boundary conditions, we shuold note that "rho" is fixed and independant value 
     u1(1) = rho(1)*a(1);
     u2(1) = 2*u2(2)-u2(3); %As u2 consists of floatinf value "v", which is caluculated from internal grid points
     v(1)= u2(1)/u1(1);
     u3(1) = u1(1)*((t(1)/(gamma-1))+(gamma/2)*v(1)^2);
     
     % At Outlet 
     % The flow properties at outlet will get from internal grid points at "n"
     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);
     
     % Caluculating Primitive terms
     rho = u1./a;
     v = u2./u1;
     t = (gamma-1)*((u3./u1)-(gamma/2)*v.^2);
     
     % caluculating solutions
     
  % Caluculating mass flow rate
  m = rho.*a.*v;        % Caluculating mass flow rate
  pr = rho.*t;          %caluculating pressure  
  mach = v./(t.^0.5);   % caluculating mach number
  
  
% Caluculating flow variables at throat
v_t(k) = v(throat);
rho_t(k) = rho(throat);
t_t(k) = t(throat);
m_t(k) = m(throat);
pr_t(k) = pr(throat);
mach_t(k) = mach(throat);


% Plotting mass flow rate by varying time steps
  figure(2)
 if k==50
   plot(x,m,'r', 'linewidth',1.5);
   hold on
 elseif k == 100
   plot(x,m,'b', 'linewidth',1.5);
   hold on
 elseif k == 200
   plot(x,m,'g', 'linewidth',1.5);
   hold on
 elseif k == 500
   plot(x,m,'k', 'linewidth',1.5);
   hold on
 elseif k == 700
   plot(x,m,'c', 'linewidth',1.5);
   hold on
 elseif k == 1400
   plot(x,m,'y', 'linewidth',1.5);
  
 xlabel('Distance through Nozzle along X-Axis');
 ylabel('Non_Dimensional Flow Rate');
 title(sprintf('Comparision of mass flow rate at Different time steps'));
 legend({'50 timesteps','100 timesteps','200 timesteps','500 timesteps','700 timesteps','1400 timesteps'})
 endif

  endfor
endfunction

Main Program:

clear all
close all
clc

% Input variables
n = 31;
l = 3;
x = linspace(0,l,n);
nt = 1400;
c = 0.5;
% To have an exact throat
throat = ((n-1)/2)+1;

tic
% Function for Non-Conservative form
[v,rho,t,m,mach,pr,v_t,rho_t,t_t,m_t,mach_t,pr_t] = Non_conservative_form(L,n,c,nt,throat)
Non_conservative_sim_time = toc;

tic
% Function for Conservative form
[V,Rho,T,M,Mach,Pr,V_t,Rho_t,T_t,M_t,Mach_t,Pr_t] = Conservative_form(L,n,c,nt,throat)
Conservative_sim_time = toc;

% Plot for Steady-state distribution of primitive variables inside the nozzle
figure(3)
plot1 = subplot(4,1,1)
plot(x,mach,'linewidth',1.5);
hold on ;
plot(x,Mach,'color','r',"*", 'markersize',3);
ylabel("Mach'",'fontsize',12,'fontweight','bold');
h= legend(plot1,{'Non-Conservative form', 'Conservative form'});
set(h,'Location','northeastoutside');
title('Steady-state distribution of flow variables', 'fontsize', 12, 'fontweight','bold');
axis([0 3 0 3.5]);

plot2 = subplot(4,1,2)
plot(x,pr,'linewidth',1.5);
hold on ;
plot(x,Pr,'color','r',"*", 'markersize',3);
ylabel("Pr'",'fontsize',12,'fontweight','bold');
h= legend(plot2,{'Non-Conservative form', 'Conservative form'});
set(h,'Location','northeastoutside');
axis([0 3 0 1]);

plot3 = subplot(4,1,3)
plot(x,rho,'linewidth',1.5);
hold on ;
plot(x,Rho,'color','r',"*", 'markersize',3);
ylabel("Rho'",'fontsize',12,'fontweight','bold');
h= legend(plot3,{'Non-Conservative form', 'Conservative form'});
set(h,'Location','northeastoutside');
axis([0 3 0 1]);

plot4 = subplot(4,1,4)
plot(x,t,'linewidth',1.5);
hold on ;
plot(x,T,'color','r',"*", 'markersize',3);
ylabel("T'",'fontsize',12,'fontweight','bold');
h= legend(plot4,{'Non-Conservative form', 'Conservative form'});
set(h,'Location','northeastoutside');
axis([0 3 0 1]);


figure(4)
t1= subplot(4,1,1);
plot(linspace(1,nt,nt),mach_t,'linewidth',1.5);
hold on 
plot(linspace(1,nt,nt),Mach_t,'color','r','linewidth',1.5);
ylabel("Mach'",'fontsize',12,'fontweight','bold');
axis([0 1400 0 3.5]);
h = legend(t1,{'Non-Conservative form','Conservative form'});
set(h,'Location','northeastoutside');
title('Time-wise variation of the primitive variables', 'fontsize', 12, 'fontweight','bold');

t2= subplot(4,1,2);
plot(linspace(1,nt,nt),pr_t,'linewidth',1.5);
hold on 
plot(linspace(1,nt,nt),Pr_t,'color','r','linewidth',1.5);
ylabel("Pr'",'fontsize',12,'fontweight','bold')'
axis([0 1400 0 1]);
h = legend(t2,{'Non-Conservative form','Conservative form'});
set(h,'Location','northeastoutside');


t3= subplot(4,1,3);
plot(linspace(1,nt,nt),rho_t,'linewidth',1.5);
hold on 
plot(linspace(1,nt,nt),Rho_t,'color','r','linewidth',1.5);
ylabel("Rho'",'fontsize',12,'fontweight','bold')'
axis([0 1400 0 1]);
h = legend(t3,{'Non-Conservative form','Conservative form'});
set(h,'Location','northeastoutside');


t4= subplot(4,1,4);
plot(linspace(1,nt,nt),t_t,'linewidth',1.5);
hold on 
plot(linspace(1,nt,nt),T_t,'color','r','linewidth',1.5);
ylabel("T'",'fontsize',12,'fontweight','bold')'
axis([0 1400 0 1]);
h = legend(t4,{'Non-Conservative form','Conservative form'});
set(h,'Location','northeastoutside');

% Variation between mass flow rates of both forms
figure(5)
plot(x,m,'linewidth',1.5);
hold on ;
plot(x,M,'color','r','linewidth',1.5);
hold on;
plot(x,linspace(0.579,0.579,n),'color','k','--','markersize',3);
grid on;
xlabel('Distance through Nozzle along X-Axis');
ylabel('Non_Dimensional Flow Rate');
legend({'Non-Conservative form','Conservative form', 'Exact Analytical solution'});
title('Comparision of mass flow rate at Different time steps', 'fontsize', 12, 'fontweight','bold');
axis([0 3 0.575 0.6]);

RESULTS:

1)Steady-state distribution of primitive variables inside the nozzle:

The plots for the steady state distribuition of flow variables is similar for both conservative and Non Conservative forms at 1400 time steps which are matching with analytical solutions provided in Anderson book and the plot is as follows:

2) Time-wise variation of the primitive variables:

From the above plot results the following observations are noted:

a) For both forms, the steady state is acheived approximately after 500 time steps and after 700 time steps, the plots are alomst matching with exact solution with minimal error.

b) Compared to Conservative, the Non Conservative form obatained accurate values as the solutions of pressure, density and temperature are almost matching with exact solutions.

c) The behaviour of residuals for the conversation form is not as good as that for the conversation form of equations. For Non Conservation form the residual becomes low from order of 10^-1 to 10^-6 after 1400 time steps, where as for conservative decay only to 10^-3 to 10^-1.

d)By time wise variations of flow variables plot, we can easily track the values at particular timestep.

e) Non Conservative leads to smaller residue compared to Conservative because of the quality index is depends on the rate of decay of residue.

3) Variation of Mass flow rate distribution inside the nozzle at different time steps during the time-marching process:

A) Non Conservative form: The timewise variation of the flow and its approach to the steady state provided by the mass flow variations shown in below figure. Six different curves are shown, each for a different time during the course of time marching process.

Observations:

1) Intially looking for 50 timesteps, the curve osciliates heavily and for 100 time steps the mass flow rate chaged radically. However after 200 timesteps, the mass flow distribution is a straight, and horizontal line across the graph.

2) After 500 and 700 time steps the flow is constant which satisfies our basic law which is pVA = constant.

3) As per the above plot, we will get the steady state around 700 timesteps itself, but for accurate results upto three decimal accuracy we are going about 1400 time steps.

B) Conservative form:

The time wise variation of the flow same as like non conservative form, the mass flow variations are shown for conservative form are shown below. Here also we are taking six differnt plots as like above.

Observations:

1) By looking at the above plot, we can get to know that initially the curve at 50 time steps osciliates heavily but for 100 time steps it becomes some what Humped distribution.

2) After 200 time steps, the mass flow distribution becoming more constant.

3) After 500 and 700 time steps, the mass flow rate becomes approximately equals to a constant value. Moreover it is quite close to analytical value.

4) Comparison of Normalized mass flow rate distributions of both forms:

The comparision of mass flow rates for both Non conservative and conservative forms are shown in the below figure.

Observations:

a) By looking to above plot, we can come to know that the plot of conservative form is more satisfactory compared to the Non Conservative form.

b) The main reason for above statement is that the mass flow distribution is becoming more closer value to analytical solution. Where as in Non Conservative form, a small amount of variation with sharp oscillations at both inlet and outlet.

c)By seeing the red line we can come to know that the results are much closer to the analytical solution and more over the oscillations are very less compared to Non Conservative form.

The main reason behind the conversation form does a better job is that the mass flow is one of the dependant variables in the equations. Where as in Non Conservative form, the dependant variables are the primitive variables and the mass flow is obtained after the outcome of primitive variables.

GRID INDEPENDENCE TEST:

By looking the above plot and statements, we cannot come to conclude that the conversation form is more accurate and superior than non Conservative form. If we consider the primitive variables such as temperature, pressure, and mach number at nozzle thorat. The following table shows the results of both conservative and Non conservative form compared with analytical data while the number of grid points are of 31 and 61.

Primitive variables

Non- Conservative form

Conservative form

Analytical solution

N = 31

N = 61

N = 31

N = 61

Rho

0.639

0.638

0.649

0.646

0.634

Mach

0.999

1.0

0.985

0.998

1.000

Pressure

0.534

0.532

0.544

0.534

0.528

Temperature

0.836

0.835

0.839

0.836

0.833

The last column of the above table repersents the exact analytical solution. By observing the values of second column and fourth column, the values of the Non conservative form is nearly close to the exact solution. The comparisonof the third row and fifth row ( n = 61), we can get to know that the values of conservative comes closer to the analytical solution, but in the case of non conservative form the values at n = 31 itself are closer to the eaxct values. Note that by doubling the number of grid points, the steady state results are slighty closer to the exact values, this clearly shows the indication of Grid Independence for the conversation form resuts. For alla practical purposes, we have grid independence with 31 grid points.

CONCLUSION:

As we applied both the Non Conservation form and Conservation forms for solutions of the subsonic- supersonic isentropic nozzle which is considered as Quasi 1D an compared all the results. We can comclude that the results are same for both forms, the main difference between is that the conservative form have superiority when it comes to mass flow distribution where as the Non Conservative form yeilds better values when it comes to primitve variables. And when it comes to caluculation effort to achive a solution, the conservative form takes more time than Non conservative because the values has to decode from the flux variables.

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.