Challenge

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

In this problem we consider the steady, isentropic flow through a convergent divergent nozzle as shown below.

The flow at the inlet to the nozzle comes from a reservoir where the pressure and temperature are denoted by `p_0 and T_0` respectively. The cross-sectional area of the reservoir is large(`Ararroo`), and hence the velocity is very small(`Vrarr0`). Thus `p_0 and T_0` are stagnation values. The flow expands isentropically to supersonic speeds at the nozzle exit, where the exit pressure,temperature,velocity and Mach number are denoted by `p_e,T_e,V_e and M_e` respectively. The flow is locally subsonic in the convergent section of the nozzle, sonic at the throat and supersonic at the divergent section. The sonic flow(M=1) at the throat means that the local velocity at this location is equal to the local speed of sound. So at throat velocity is `V=V^**=a^**`. Similarly the area, pressure and temperature are deonted by `A^**,p^** and T^**`.

We assume that at a given section, where the cross-sectional area is `A`, the flow properties are uniform across the section. Hence although the area of the nozzle changes as a function of distance along the nozzle `x`, therefore in reality the flow field is two-dimensional, we make assumption that the flow properties vary along with `x`; this is tantamount to assuming uniform flow properties across any given cross-section. Such flow is defined as 'Quasi one dimensional flow'.

Then we have to find out the Governing equation for this problem(both Non-conservative and Conservative form). Here we employing the Non-dimensional forms of governing equations.

So we need to Non-dimensionalize the variables also.

Non-dimensional temperature, `T'=T/T_0`

Non-dimensional density, `rho'=rho/rho_0`

Non-dimensional length, `x'=x/L`

where L is the length of the nozzle

Non-dimensional velocity, `V'=V/a_0`

where `a_0` is the speed of the sound in the reservoir. `a_0=sqrt(gammaRT)`

Non-dimensional time, `t'=t/(L/a_0)`

Non-dimensional area, `A'=A/A^**`

Mach number, `M=V/a`

In terms of non dimensional velocity and temperature, this equation can be rewritten as

`M=(V')/sqrt(T)`

After finding out the Governing equations for both terms, the next step is solving by Macormack method.

Macormack Method

In the normal case solving is done by with an initial condition and move onto the next time step with help of suitable discretization scheme. In Macormack Method we are not going directly into the next time step. Before going to the next time step we have to do the predictor step and corrector step. Macormack Method consist of mainly 5 steps.

  1. Predictor step
  2. Intermediate solution update
  3. Corrector step
  4. Averaging time derivative
  5. Final solution update

example

Let 'f' be any function, and we are solving using Macormack method.

  • Predictor step

Here we have to find out the time derivative. In this step we employ forward difference scheme for the spacial terms.

`((delf)/(delt))_p`

  • Intermediate solution update

`f^**=f_i+((delf)/(delt))_pdt`

  • Corrector step

Like the predictor step, here we need to find out the time derivative. But here we employing backward difference scheme for spacial terms. Also we have to use the updated values obtained from the predictor step(`f^**`) here.

`((delf^**)/(delt))_c`

  • Averaging

Here we averaging the results obtained from the predictor step and corrector step

`((delf)/(delt))_(avg)=[((delf)/(delt))_p+((delf^**)/(delt))_c]/2`

  • Final solution update

`f=f_i+((delf)/(delt))_(avg)dt`

NON DIMENSIONAL GOVERNING EQUATIONS SOLVING

Area profile

`A=1+2.2(x-1.5)^2`

let `0<=x<=3`

Calculation of time step

`dt=C.dx/(V+a)`

where C is the CFL number

V is the local velocity

a is the speed of sound

Mass flow rate calculation

Mass flow rate = `rhoAV`

  • NON-CONSERVATIVE FORM

Continuity equation

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

Momentum equation

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

Energy equation

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

Initial conditions are,

`rho'=1-0.3146x'`

`T'=1-0.2314x'`

`V'=(0.1+1.09x')T'^(1/2)`

By Marcomack method,

Predictor step,

Intermediate solution update,

Corrector step,

Averaging time derivatives,

Final solution update,

Boundary conditions

Subsonic inflow boundary,

`V_1=2V_2-V_3`

Subsonic outflow boundary,

`V_n=2V_(n-1)-V_(n-2)`

`rho_n=2rho_(n-1)-rho_(n-2)`

`T_n=2T_(n-1)-T_(n-2)`

  • CONSERVATIVE FORM

Continuity equation

`(del(rho'A'))/(delt')+(del(rho'A'V'))/(delx')=0`

Momentum equation

`(del(rho'A'V'))/(delt')+(del[rho'A'V'^2+(1/gamma)p'A'])/(delx')=1/gammap'(delA')/(delx')`

Energy equation

`(del[rho'((e')/(gamma-1)+gamma/2V'^2)A'])/(delt')+(del[rho'((e')/(gamma-1)+gamma/2V'^2)V'A'+p'A'V'])/(delx')=0`

To simplify these equations we introduce some new terms which include the solution vector `U`, Flux vector `F` and source term `J`.

`U_1=rho'A'`

`U_2=rho'A'V'`

`U_3=rho'((e')/(gamma-1)+gamma/2V'^2)A'`

`F_1=rho'A'V'`

`F_2=rho'A'V'^2+(1/gamma)p'A'`

`F_3=rho'((e')/(gamma-1)+gamma/2V'^2)V'A'+p'A'V'`

`J_2=1/gammap'(delA')/(delx')`

By using these terms we can rewrite the equations as follows,

`(delU_1)/(delt')=-(delF_1)/(delx')`

`(delU_2)/(delt')=-(delF_2)/(delx')+J_2`

`(delU_3)/(delt')=-(delF_3)/(delx')`

The primitive variables can be calculated as follows,

`rho'=U_1/(A')`

`V'=U_2/U_1`

`T'=e'=(gamma-1)(U_3/U_1-gamma/2V'^2)`

`p'=rho'T'`

Expressing flex terms and source terms in terms of solution vectors,

Initial conditions are,

solution variable initialization,

By Macormack method,

The predictor step,

`((delU_1)/(delx))_i^t=-((F_(1(i+1))^t-F_(1(i))^t)/dx)`

`((delU_2)/(delx))_i^t=-((F_(2(i+1))^t-F_(2(i))^t)/dx)+ubrace([(1/gamma)rho_iT_i((A_(i+1)-A_(i))/dx)])_("J_2")`

`((delU_3)/(delx))_i^t=-((F_(3(i+1))^t-F_(3(i))^t)/dx)`

Intermediate solution update,

`(bar U_1)_i^(t+dt)=(U_1)_i^t+((delU_1)/(delt))_i^tdt`

`(bar U_2)_i^(t+dt)=(U_2)_i^t+((delU_2)/(delt))_i^tdt`

`(bar U_3)_i^(t+dt)=(U_3)_i^t+((delU_3)/(delt))_i^tdt`

Then update the primitive variables.

The corrector step,

`((del barU_1)/(delx))_i^t=-((bar F_(1(i))^t-bar F_(1(i-1))^t)/dx)`

`((delbar U_2)/(delx))_i^t=-((bar F_(2(i))^t-bar F_(2(i-1))^t)/dx)+ubrace([(1/gamma)rho_iT_i((A_(i)-A_(i-1))/dx)])_("J_2")`

`((del barU_3)/(delx))_i^t=-((bar F_(3(i))^t-bar F_(3(i-1))^t)/dx)`

Averaging,

`((delU_1)/(delt))_(avg)=[((delU_1)/(delt))_i^t+((delbar U_1)/(delt))_i^t]/2`

`((delU_2)/(delt))_(avg)=[((delU_2)/(delt))_i^t+((delbar U_2)/(delt))_i^t]/2`

`((delU_3)/(delt))_(avg)=[((delU_3)/(delt))_i^t+((delbar U_3)/(delt))_i^t]/2`

Final solution update,

`(U_1)_i^(t+dt)=(U_1)_i^t+((delU_1)/(delt))_(avg)dt`

`(U_2)_i^(t+dt)=(U_2)_i^t+((delU_2)/(delt))_(avg)dt`

`(U_3)_i^(t+dt)=(U_3)_i^t+((delU_3)/(delt))_(avg)dt`

After this step we need to update the primitive variables.

Boundary conditions

Subsonic inflow boundary,

`U_(1(i=1))=(rho'A')_(i=1)=A'_(i=1)=`Fixed value

`U_(2(i=1))=2U_(2(i=2))-U_(2(i=3))`

`U_3=U_1(T_1/(gamma-1)+gamma/2V'^2)`

Supersonic outflow boundary,

`(U_1)_n=2(U_1)_(n-1)-(U_1)_(n-2)`

`(U_2)_n=2(U_2)_(n-1)-(U_2)_(n-2)`

`(U_3)_n=2(U_3)_(n-1)-(U_3)_(n-2)`

MATLAB PROGRAM

  • Main Program Code
% main function supersonic flow

clear all
close all
clc

%inputs
n=31;
x=linspace(0,3,n);
dx=x(2)-x(1);
gamma = 1.4;
%area
a = 1+2.2*(x-1.5).^2;
%cfl number
cfl = 0.5;
%time step
nt = 1400;

%non conservative
[rho,v,t,p,m,mfr,m_nc,p_nc,rho_nc,t_nc] = non_conservative(x,cfl,dx,nt,n,gamma);

%conservative
[rho_c,v_c,t_c,p_c,m_c,mfr_c,m_c_t,p_c_t,rho_c_t,t_c_t] = conservative(x,cfl,dx,nt,n,gamma,a);


%plotting

% 1.primitive variables vs x
%non conservative form


figure(3)
%Mach number
subplot(4,1,1)
plot(x,m)
xlabel('x')
ylabel('Mach number')
title('Primitive variables vs x(non conservative)')
grid on


subplot(4,1,2)
plot(x,p)
xlabel('x')
ylabel('Pressure')
grid on

subplot(4,1,3)
plot(x,rho)
xlabel('x')
ylabel('Density')
grid on

subplot(4,1,4)
plot(x,t)
xlabel('x')
ylabel('Temperature')
grid on

%conservative form
figure(4)

subplot(4,1,1)
plot(x,m_c)
xlabel('x')
ylabel('Mach number')
title('Primitive variables vs x(conservative)')
grid on

subplot(4,1,2)
plot(x,p_c)
xlabel('x')
ylabel('Pressure')
grid on

subplot(4,1,3)
plot(x,rho_c)
xlabel('x')
ylabel('Density')
grid on

subplot(4,1,4)
plot(x,t_c)
xlabel('x')
ylabel('Temperature')
grid on


% 2.time wise variation of primitive variable

%mach number
figure(5)
plot(1:nt, m_nc)
hold on
plot(1:nt, m_c_t)
xlabel('time step')
ylabel('mach number')
legend('non conservative','conservative')
title('Time wise variation of Mach number')
grid on

%pressure
figure(6)
plot(1:nt, p_nc)
hold on
plot(1:nt, p_c_t)
xlabel('time step')
ylabel('pressure')
legend('non conservative','conservative')
title('Time wise variation of Pressure')
grid on

%density
figure(7)
plot(1:nt, rho_nc)
hold on
plot(1:nt, rho_c_t)
xlabel('time step')
ylabel('density')
legend('non conservative','conservative')
title('Time wise variation of Density')
grid on

%temperature
figure(8)
plot(1:nt, t_nc)
hold on
plot(1:nt, t_c_t)
xlabel('time step')
ylabel('temperature')
legend('non conservative','conservative')
title('Time wise variation of Temperature')
grid on


% 4.comparison of normalized mass flow rate distributions of both forms
figure(9)
plot(x,mfr,'linewidth',1.5)
hold on
plot(x,mfr_c,'linewidth',1.5)
xlabel('x')
ylabel('Mass flow distribution')
legend({'non conservative','conservative'},'location','best')
title('Mass flow rate distribution')
grid on
  • FUNCTION CODE for Non-Conservative form
function [rho,v,t,p,m,mfr,m_nc,p_nc,rho_nc,t_nc] = non_conservative(x,cfl,dx,nt,n,gamma,a)

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

    %time step
    dt = min((cfl*dx)./(v+sqrt(t)));

    %outer time loop
    for k=1:nt
    
        rho_old = rho;
        t_old = t;
        v_old = v;

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

            %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


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

        end

        %computing average time derivative

        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;
        end


        %applying 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);

        %Primitive variables updation
        p=rho.*t;       %pressure
        m=v./(t.^0.5);  %mach number
        mfr=rho.*a.*v;  %mass flow rate

        %Primitive variables at throat
        m_nc(k) = m(16);
        p_nc(k) = p(16);
        rho_nc(k) = rho(16);
        t_nc(k) = t(16);

        % plotting mass flow rate distribution inside nozzle at different time
        % steps
        figure(1)
        if k==50
            plot(x,mfr,'linewidth',1.5)
            hold on
        elseif k==100
            plot(x,mfr,'linewidth',1.5)
            hold on
        elseif k==150
            plot(x,mfr,'linewidth',1.5)
            hold on
        elseif k==300
            plot(x,mfr,'linewidth',1.5)
            hold on
        elseif k==600
            plot(x,mfr,'linewidth',1.5)
            hold on
        elseif k==900
            plot(x,mfr,'linewidth',1.5)
            hold on
        elseif k==1400
            plot(x,mfr,'linewidth',1.5)

        end


    end
    xlabel('x')
    ylabel('mass flow rate')
    legend('50 time steps','100 time steps','150 time steps','300 time steps','600 time steps','900 time steps','1400 time steps')
    title('mass flow distribution inside the nozzle at different time steps(non conservative method)')
    grid on
    
end
  • FUNCTION CODE for Conservative form
function [rho_c,v_c,t_c,p_c,m_c,mfr_c,m_c_t,p_c_t,rho_c_t,t_c_t] = conservative(x,cfl,dx,nt,n,gamma,a)

    %initial profiles
    for i=1:n

        if x(i)>=0 && x(i)<=0.5
            %Density
            rho_c(i) = 1.0;
            %temperature
            t_c(i) = 1.0;

        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.5

            rho_c(i) = 0.634 - (0.3879*(x(i)-1.5));
            t_c(i) = 0.833 - (0.3507*(x(i)-1.5));

        end

    end

    %velocity
    v_c = 0.59./(rho_c.*a);
    
    %time step
    dt_c = min((cfl*dx)./(v_c+sqrt(t_c)));

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

    %outer time loop
    for k=1:nt

        uold1=u1;
        uold2=u2;
        uold3=u3;

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

        %predictor method

        for j=2:n-1

            df1dx = (f1(j+1)-f1(j))/dx;
            df2dx = (f2(j+1)-f2(j))/dx;
            df3dx = (f3(j+1)-f3(j))/dx;
            dadx = (a(j+1)-a(j))/dx;
            j2(j) = (1/gamma)*rho_c(j)*t_c(j)*dadx;

            %continuity equation
            du1dt_p(j) = -df1dx;

            %momentum equation
            du2dt_p(j) = -df2dx+j2(j);

            %energy equation
            du3dt_p(j) = -df3dx;

            %solution update
            u1(j) = u1(j)+du1dt_p(j)*dt_c;
            u2(j) = u2(j)+du2dt_p(j)*dt_c;
            u3(j) = u3(j)+du3dt_p(j)*dt_c;

        end

        %premitive variables updation
        rho_c = u1./a;
        v_c = u2./u1;
        t_c = (gamma-1)*((u3./u1)-(0.5*gamma*v_c.^2));
        p_c = rho_c.*t_c;

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

        %corrector method

        for j=2:n-1

            df1dx = (f1(j)-f1(j-1))/dx;
            df2dx = (f2(j)-f2(j-1))/dx;
            df3dx = (f3(j)-f3(j-1))/dx;
            dadx = (a(j)-a(j-1))/dx;
            j2(j) = (1/gamma)*rho_c(j)*t_c(j)*dadx;

            %continuity equation
            du1dt_c(j) = -df1dx;

            %momentum equation
            du2dt_c(j) = -df2dx+j2(j);

            %energy equation
            du3dt_c(j) = -df3dx;

        end

        %computing 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) = uold1(i)+du1dt(i)*dt_c;
            u2(i) = uold2(i)+du2dt(i)*dt_c;
            u3(i) = uold3(i)+du3dt(i)*dt_c;

        end




        %applying boundary conditions

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

        %primitive variables updation
        rho_c = u1./a;                                      %density
        v_c = u2./u1;                                       %velocity
        t_c = (gamma-1)*((u3./u1)-(0.5*gamma*v_c.^2));      %temperature
        p_c = rho_c.*t_c;                                   %pressure
        m_c=v_c./(t_c.^0.5);                                %mach number
        mfr_c=rho_c.*a.*v_c;                                %mass flow rate

        %primitive variables at throat
        m_c_t(k) = m_c(16);
        p_c_t(k) = p_c(16);
        rho_c_t(k) = rho_c(16);
        t_c_t(k) = t_c(16);

        % plotting mass flow rate distribution inside nozzle at different time
        % steps
        figure(2)
        if k==50
            plot(x,mfr_c,'linewidth',1.5)
            hold on
        elseif k==100
            plot(x,mfr_c,'linewidth',1.5)
            hold on
        elseif k==150
            plot(x,mfr_c,'linewidth',1.5)
            hold on
        elseif k==300
            plot(x,mfr_c,'linewidth',1.5)
            hold on
        elseif k==600
            plot(x,mfr_c,'linewidth',1.5)
            hold on
        elseif k==900
            plot(x,mfr_c,'linewidth',1.5)
            hold on
        elseif k==1400
            plot(x,mfr_c,'linewidth',1.5)

        end


    end 

    xlabel('x')
    ylabel('mass flow rate')
    legend({'50 time steps','100 time steps','150 time steps','300 time steps','600 time steps','900 time steps','1400 time steps'},'location','northwest')
    title('mass flow distribution inside the nozzle at different time steps(conservative method)')
    grid on

end

OUTPUTS - Graphs

  • Steady state distribution of primitive variables inside the nozzle ( NON-CONSERVATIVE FORM )

  • Steady state distribution of primitive variables inside the nozzle ( CONSERVATIVE FORM )

  • Time wise variation of Mach number

  • Time wise variation of Pressure

  • Time wise variation of Density

  • Time wise variation of Temperature

  • Variation of Mass flow rate distribution inside the nozzle at different time steps ( NON-CONSERVATIVE FORM )

  • Variation of Mass flow rate distribution inside the nozzle at different time steps ( CONSERVATIVE FORM )

  • Comparison of Normalized mass flow rate distribution of both forms

CONCLUSION

  • From these graphs we can conclude that Conservative form is far better than Non conservative form.
  • From the 'Mass flow rate distribution at different time step' graph and 'Time wise variation of primitive variables' graph we can easily understands that Conservative form become stable faster than the Non-Conservative form.
  • It can be observed that at smaller time steps the behaviour of Non-Conservative form shows highly unstable results than the Conservative form.
  • It can be observed that after 300 time steps, all the primitive variables and mass flow rate distributions are showing stable results.
  • The Macormack method provides quite stable and exact solutions. Because here we are not directly going to next time step. Here we have additional steps, which are predictor step,corrector step and averaging. Then only we updating the solution. And this is the reason why we are getting more stable and exact solutions.
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.