Challenge

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

Aim:

To simulate the isentropic flow through a quasi 1D subsonic-supersonic nozzle using the Macormack method.

Introduction:

We consider a steady, isentropic flow through a convergent-divergent nozzle. This nozzle consists of a convergent section, throat section, and divergent section. The flow at the inlet to the nozzle comes from a reservoir where the pressure and temperature are denoted as `P_0` and `T_0` respectively. The cross-sectional area is large and hence velocity is very small. Here we are dealing with a particular case of Quasi 1D flow which means the flow is varied only in x-direction.

Mach number is a dimensionless quantity representing the ratio of flow of velocity to the local velocity of sound.

In the convergent section, this Mach number is less than 1 (M<1) therefore it is called Subsonic flow through the nozzle. In the divergent section, it is greater than 1 (M>1) thus called supersonic flow as the velocity of fluid-particle is more than that of sound. In the throat section velocity of the fluid-particle is equal to the local velocity of sound (M=1).

Governing Equation:

The flow through the nozzle is governed by the Navier Stokes equation which can be represented in both conservation and non-conservation form. Also, they can be further expressed in terms of integral and differential forms. All this equation can be converted into other just by doing mathematical operations on them.

To reduce the complexity of the notation we drop the use of prime to denote a dimensionless variable for density, temperature, velocity, and area.

Non conservation form:

Conservation form:

Continuity: =0

Momentum:

Energy:

where,

the dimensionless quantity is stated as

`T'=T/T_0`=`(Flow __temperature)/(Reserviour__temperature)`

`rho'=rho/rho_0`= `(Flow__density)/(Reserviour__ density)`

`x'=x/L` L is nozzle Length

`V'=V/a_0`=`(Flow __velocity)/(Speed__of__sound)`

`A'=A/A_0=( Area__of__nozzl e)/(Throat__area__at__sonic__section)`

Mac-Cormack method:

MacCormack's method is an explicit finite difference scheme for second-order accuracy with first-order terms in both space and time. It is a variant of the Lax-Wendroff approach but in a simpler way. Here, it uses the predictor-corrector step wherein the predictor step, space terms are replaced by forward differencing, and in the corrector step, they are replaced by backward differencing. The solution is updated and average time derivatives of predictor and corrector step are calculated for every grid point and time step.

Steps for Non-conservative form:

1) Setting up initial conditions

The area of the nozzle varies as

At x=1.5 is the throat of the nozzle, convergent section occurs for x<1.5, and the divergent section occurs at x>1.5

Initial conditions for density(rho), temperature(t) & velocity(v)

2) Calculation of the time step

Time step can be found by CFL criteria for 1D flow,

Where C=courant number, a= local speed of sound`=sqrtT`, V=local flow velocity at a point in the flow

Therefore, a new time step will be

`Deltat=min( C. (Deltax)/(sqrtT'+V'))`

These time steps are calculated for all given temperature and velocity grid points and then the minimum of it is considered.

3) Predictor step

We set up spatial derivatives as forwarding differences.

For the continuity equation,

For the Momentum equation,

For the energy equation,

Now we obtain predicted quantity using the Taylor series,

4) Corrector step

Here we set up spatial derivatives as backward differences.

For the continuity equation,

For the momentum equation,

For the energy equation,

The average timer derivative is calculated both from the predictor and corrector step.

The final solution will be,

5) Boundary conditions (B.C)

These are important because, without the proper physical implementation and representation of boundary conditions, we may not obtain the proper solution for our flow problem. There will be 2 boundary conditions, one at point 1 in the grid representing inflow B.C (subsonic) and other at point N in the grid representing outflow B.C (supersonic).

Subsonic inflow B.C

We must stipulate the value of two independent flow variables whereas the value of one other variable must be allowed to float. We choose velocity (V) as float variable because on a physical basis we know the mass flow through the nozzle must be allowed to adjust to the proper steady state, thus allowing V to float makes sense as part of this adjustment.

`V_1=2*V_2-V_3`

Supersonic outflow B.C

Here all the variables must be allowed to float. For this, we choose linear extrapolation based on the flow field variables at the internal points.

Steps for Conservative form:

1) Setting up initial conditions

Values of density, temperature varies accordingly,

Value of mass flow

Here we have the solution vector U, Flux vector F, and the source term J as

A pure form of flux terms,

Primitive variables can be obtained using the solution vector by:

2) Calculation of the time step

"Same as non-conservation form"

3) Predictor step

Here Flux terms use a forward differencing scheme.

Then the solution is updated using the Taylor series

`barU_1^(t+Deltat)=U_1^t+((delU_1)/(delt))^t*Deltat`

Similarly for `bar(U_2)` and `bar(U_3)`

4) Corrector step

Here Flux terms are solved in backward differencing.

Then the average of predictor and corrector step is found the same as we did in non-conservative form.

At last, the final corrected step can be obtained by using the Taylor series.

Finally, the primitive variables are decoded by,

5) Boundary condition.

Subsonic inflow boundary flow

Two properties are fixed, one is allowed to float.

`U1(1)=rho(1)*a(1)`

`U2(1)=2*U2(2)-U2(3)`

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

`V(1)=(U2(1))/(U1(1))`

Supersonic outflow boundary outflow

All properties are allowed to float.

MATLAB code:

Main code

clear all
close all
clc

%inputs
n=31;
L=3;
x=linspace(0,L,n);

%courrant number
c=0.5;

%time step
nt=1400;

tic
%function for non conservative form
[rho1,t1,v1,m1,mach1,pr1,rho_t1,t_t1,v_t1,m_t1,mach_t1,pr_t1]=non_conservative_flow(n,L,c,nt);
%simulation time(non conservative form)
non_cons_time=toc

tic
%function for conservative form
[rho2,t2,v2,m2,mach2,pr2,rho_t2,t_t2,v_t2,m_t2,mach_t2,pr_t2]=conservative_flow(n,L,c,nt);
%simulation time(conservative form)
cons_time=toc


%Variation of flow parameters along xaxis
figure(3)
subplot(4,1,1)
plot(x,rho1,'r','linewidth',1.5);
hold on
plot(x,rho2,'b*');
title('Variation of flow parameters along x axis')
ylabel("rho'")
legend('Non-conservation form','Conservation form')
set(legend,'location','northeastoutside')
grid on

subplot(4,1,2)
plot(x,pr1,'color','r','linewidth',1.5);
hold on
plot(x,pr2,'b*');
ylabel("pr'")
legend('Non-conservation form','Conservation form')
set(legend,'location','northeastoutside')
grid on

subplot(4,1,3)
plot(x,t1,'r','linewidth',1.5);
hold on
plot(x,t2,'b*');
ylabel("t'")
legend('Non-conservation form','Conservation form')
set(legend,'location','northeastoutside')
grid on

subplot(4,1,4)
plot(x,mach1,'r','linewidth',1.5);
hold on
plot(x,mach2,'b*');
ylabel("mach'")
legend('Non-conservation form','Conservation form')
set(legend,'location','northeastoutside')
grid on



%Variation of flow parameters at the throat(density, pressure,
%temperature,mach number)
figure(4)
subplot(4,1,1)
plot(linspace(1,nt,nt),rho_t1,'r','linewidth',1.5);
hold on
plot(linspace(1,nt,nt),rho_t2,'b','linewidth',1.5);
title('Variation of flow parameters')
ylabel("rho'")
legend('Non-conservation form','Conservation form')
set(legend,'location','northeastoutside')
grid on

subplot(4,1,2)
plot(linspace(1,nt,nt),pr_t1,'r','linewidth',1.5);
hold on
plot(linspace(1,nt,nt),pr_t2,'b','linewidth',1.5);
ylabel("pr'")
legend('Non-conservation form','Conservation form')
set(legend,'location','northeastoutside')
grid on

subplot(4,1,3)
plot(linspace(1,nt,nt),t_t1,'r','linewidth',1.5);
hold on
plot(linspace(1,nt,nt),t_t2,'b','linewidth',1.5);
ylabel("t'")
legend('Non-conservation form','Conservation form')
set(legend,'location','northeastoutside')
grid on

subplot(4,1,4)
plot(linspace(1,nt,nt),mach_t1,'r','linewidth',1.5);
hold on
plot(linspace(1,nt,nt),mach_t2,'b','linewidth',1.5);
ylabel("pr'")
legend('Non-conservation form','Conservation form')
set(legend,'location','northeastoutside')
grid on

%Mass flow rate comparison
figure(5)
plot(x,m1,'r','linewidth',1.5)
hold on
plot(x,m2,'b','linewidth',1.5)
xlabel('Mass flow rate')
ylabel('Distance through nozzle(x)')
title('Comparison of mass flow rate')
legend('Non-conservation form','Conservation form')

Function Code:

Non-conservative form:

function [rho1,t1,v1,m1,mach1,pr1,rho_t1,t_t1,v_t1,m_t1,mach_t1,pr_t1]=non_conservative_flow(n,L,c,nt)

%inputs
x=linspace(0,L,n);
dx=x(2)-x(1);
gamma=1.4;

%area of nozzle
a=1+2.2*(x-1.5).^2;
%area at throat
throat=find(a==1)

%calculate initial profile
rho1= 1-0.3146*x;
t1=1-0.2314*x;   %t=temperature
v1=(0.1+1.09*x).*t1.^0.5;

for i=1:n
  dt_cal(i)= (c*dx)/((t1(i)).^0.5+v1(i));  
end
dt=min(dt_cal);

%outer time loop
for k=1:nt
  
    rho_old=rho1;
    t_old=t1;
    v_old=v1;
    
    %predictor step
    for j = 2:n-1
  
        dvdx=(v1(j+1)-v1(j))/dx;
        drhodx=(rho1(j+1)-rho1(j))/dx;
        dtdx=(t1(j+1)-t1(j))/dx;
        dlogadx=(log(a(j+1))-log(a(j)))/dx;
        
        %continunty equation
        drhodt_p(j)=-rho1(j)*dvdx-rho1(j)*v1(j)*dlogadx-v1(j)*drhodx;
        
        %momentum equation
        dvdt_p(j)=-v1(j)*dvdx-(1/gamma)*(dtdx+(t1(j)/rho1(j))*drhodx);
        
        %energy equation
        dtdt_p(j)=-v1(j)*dtdx-(gamma-1)*t1(j)*(dvdx+v1(j)*dlogadx);
        
        %solution update
        v1(j) = v1(j) + dvdt_p(j)*dt;
        t1(j) = t1(j) + dtdt_p(j)*dt;
        rho1(j) = rho1(j) + drhodt_p(j)*dt;
        
    end
    
    %corrector step
    for j = 2:n-1
        
        dvdx=(v1(j)-v1(j-1))/dx;
        drhodx=(rho1(j)-rho1(j-1))/dx;
        dtdx=(t1(j)-t1(j-1))/dx;
        dlogadx=(log(a(j))-log(a(j-1)))/dx;
        
        %continunty equation
        drhodt_c(j)=-rho1(j)*dvdx-rho1(j)*v1(j)*dlogadx-v1(j)*drhodx;
        
        %momentum equation
        dvdt_c(j)=-v1(j)*dvdx-(1/gamma)*(dtdx+(t1(j)/rho1(j))*drhodx);
        
        %energy equation
        dtdt_c(j)=-v1(j)*dtdx-(gamma-1)*t1(j)*(dvdx+v1(j)*dlogadx);
        
    end
    
    %compute the avg time value
    drhodt=0.5*(drhodt_p + drhodt_c);
    dvdt=0.5*(dvdt_p + dvdt_c);
    dtdt=0.5*(dtdt_p + dtdt_c);
    
    for i=2:n-1
    %Final solution
    rho1(i) = rho_old(i) + drhodt(i)*dt;
    v1(i) = v_old(i) + dvdt(i)*dt;
    t1(i) = t_old(i) + dtdt(i)*dt;
    end
    
    %apply the boundary conditions
    %inlet
    v1(1)=2*v1(2)-v1(3);
    
    %outlet
    rho1(n)=2*rho1(n-1)-rho1(n-2);    
    v1(n)=2*v1(n-1)-v1(n-2);
    t1(n)=2*t1(n-1)-t1(n-2);
    
    %calculating solutions
    %mass flow rate
    m1=rho1.*v1.*a;
    %mach number
    mach1=v1./(t1.^0.5);
    %pressure ratio
    pr1=rho1.*t1;
    
    %throat values
    rho_t1(k)=rho1(throat);
    t_t1(k)=t1(throat);
    v_t1(k)=v1(throat);
    m_t1(k)=m1(throat);
    mach_t1(k)=mach1(throat);
    pr_t1(k)=pr1(throat);
    
    %plotting mass flow rate at different time steps
    figure(1)
    if k==50
        plot(x,m1,'r','linewidth',1.5)
        hold on
    elseif k==100
        plot(x,m1,'b','linewidth',1.5)
        hold on
    elseif k==150
        plot(x,m1,'g','linewidth',1.5)
        hold on
    elseif k==200
        plot(x,m1,'y','linewidth',1.5)
        hold on
    elseif k==400
        plot(x,m1,'k','linewidth',1.5)
        hold on
    elseif k==800
        plot(x,m1,'c','linewidth',1.5)
        hold on
    elseif k==1400
        plot(x,m1,'m','linewidth',1.5)
        hold on
       grid on
       title('Variation of mass flow rate at different time step (Non-conservstive form)')
       ylabel('Non dimensional mass flow rate')
       xlabel('Length of nozzle')
       legend({'50 time steps','100 time steps','150 time steps','200 time steps','400 time steps','800 time steps','1400 time steps'}); 
    end
end
end

Conservative form:

function [rho,t,v,m,mach,pr,rho_t2,t_t2,v_t2,m_t2,mach_t2,pr_t2]=conservative_flow(n,L,c,nt)

%inputs
x=linspace(0,L,n);
dx=x(2)-x(1);
gamma=1.4;

%calculate initial profile
%area of nozzle
a=1+2.2*(x-1.5).^2;
%area at throat
throat=find(a==1);

%rho(density) and t (temperature)
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

%velocity
v=0.59./(rho.*a);

%solution vector
u1=rho.*a;
u2=rho.*a.*v;
u3=rho.*a.*((t./(gamma-1))+((gamma/2).*(v.^2)));

%time step
dt=min((c.*dx)./(t.^0.5+v));

%outer time loop
for k=1:nt
  
    %copy terms
    rho_old=rho;
    t_old=t;
    v_old=v;
    
    u1_old=u1;
    u2_old=u2;
    u3_old=u3;
    
    %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 step
    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);
        
        %continunty 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;
        
    end
    
    %obtainig primitive variables and flux value
    rho=u1./a;
    v=u2./u1;
    t=(gamma-1)*((u3./u1)-((gamma*(v.^2))./2));
    
    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;
        
        dadx1(j)=(a(j)-a(j-1))/dx;
        j3(j)=(1/gamma)*(rho(j)*t(j))*dadx1(j);
        
        %continunty equation
        du1dt_c(j)=-df1dx(j);
        
        %momentum equation
        du2dt_c(j)=-df2dx(j)+j3(j);
        
        %energy equation
        du3dt_c(j)=-df3dx(j);
        
    end
    
    %compute the avg time value
    du1dt=0.5*(du1dt_p + du1dt_c);
    du2dt=0.5*(du2dt_p + du2dt_c);
    du3dt=0.5*(du3dt_p + du3dt_c);
    
    for i=2:n-1
    %Final solution
    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 the boundary conditions
    %inlet
    u1(1)=rho(1)*a(1);
    u2(1)=2*u2(2)-u2(3);
    v(1)=u2(1)/u1(1);
    u3(1)=u1(1)*((t(1)/(gamma-1))+((gamma/2)*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 values of primtive variables
    rho=u1./a;
    v=u2./u1;
    t=(gamma-1)*((u3./u1)-((gamma/2)*(v.^2)));
    
    %calculating solutions
    %mass flow rate
    m=rho.*v.*a;
    %mach number
    mach=v./(t.^0.5);
    %pressure ratio
    pr=rho.*t;
    
    %throat values
    rho_t2(k)=rho(throat);
    t_t2(k)=t(throat);
    v_t2(k)=v(throat);
    m_t2(k)=m(throat);
    mach_t2(k)=mach(throat);
    pr_t2(k)=pr(throat);
    
    %plotting mass flow rate at different 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==150
        plot(x,m,'g','linewidth',1.5)
        hold on
    elseif k==200
        plot(x,m,'y','linewidth',1.5)
        hold on
    elseif k==400
        plot(x,m,'k','linewidth',1.5)
        hold on
    elseif k==800
        plot(x,m,'c','linewidth',1.5)
        hold on
    elseif k==1400
        plot(x,m,'m','linewidth',1.5)
        hold on
       grid on
       title('Variation of mass flow rate at different time step (conservative form)')
       ylabel('Non dimensional mass flow rate')
       xlabel('Length of nozzle')
       legend({'50 time steps','100 time steps','150 time steps','200 time steps','400 time steps','800 time steps','1400 time steps'}); 
    end
end
end

Output & Conclusion:

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

From the graph, it can be inferred that the conservation form is more stable than compared to non-conservation form as the variation is less. It can also be inferred that after 400-time steps the graph stabilizes and proceeds almost linearly.

2) Time-wise variation of the primitive variables

A similar result can be obtained for both conservation and non-conservation form in terms of primitive variables(Density, Pressure ratio, Temperature, Mach No.) at the throat section. Thus we can conclude that both governing equations conclude the same results for this flow problem through the nozzle. But when the shock wave is considered the results will deviate for both conservational and non-conservational forms.

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

Non-conservative form:

It can be seen from the graph that after a 400-time step the graph stabilizes and negligible change can be seen for a later time step.

Conservative form:

It can be inferred that the graph starts stabilizing after 400-time steps. Since then very less change can be seen.

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

From the plot, we can see that the mass flow rate for the non-conservation form varies a lot when compared to the conservation form which appears to be stable. Also, the conservation form is close to the analytical solution as given in the book.

5) Grid Dependency test

rho' T' P' Mach no.
Exact analytical solution 0.634 0.833 0.528 1
Non-Conservational form (Grid size=31) 0.6387 0.8365 0.5342 0.9994
Conservational form (Grid size=31) 0.6534 0.8410 0.5487 0.9780
Non- Conservational form (Grid size=61) 0.6377 0.8354 0.5327 0.9998
Conservational form (Grid Size=61) 0.6391 0.8355 0.5340 0.9979

Thus we can conclude that after 31 grid size if we increases its refinement it will result in similar results and no major change will be obtained for primitive values. the results of non-conservation form are more close to analytical solution than that of conservation form.

6) Effect of CFL number (Non-Conservation form)

Courant number rho' T' P' Mach no.
Exact analytical solution 0.634 0.833 0.534 1
0.5 0.6387 0.8365 0.5342 0.9994
0.7 0.6391 0.8366 0.5346 0.9992
0.9 0.6395 0.8368 0.5351 0.9989
1.1 0.6399 0.8369 0.5355 0.9987
1.2 NaN NaN NaN NaN

we get get accurate results till c=1.1 after that the solution is blown away.

7) Computational time

Time(s)
Non-Conservation form (Grid size=31) 3.6871
Conservation form (Grid size=31) 3.8336
Non-Conservation form (Grid size=61) 3.5711
Conservation form (Grid size=61) 3.9001

The time conservation is little more than a non-conservation form that may be due to little more complexity in solving the equations

Appendix:

Figures for grid size=61

1. Steady-state distribution of primitive variables inside the nozzle


2. Time-wise variation of the primitive variables


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

4. Comparison of Normalized mass flow rate distributions of both 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.