Challenge

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 for conservative and non-conservative from of governing equations using MacCromack’s method.

THEORY

A convergent-divergent nozzle converts subsonic flow at inlet into supersonic flow at outlet.

We consider a steady-isentropic flow through the nozzle shown above. The inlet flow comes from a reservoir and the cross-sectional are of the reservoir is large (theoretically it tends to infinity). For this problem, the flow varies in x and y direction, i.e., 2D flow. But we assume that flow property only varies on the x-axis. Such a flow is called quasi-one-dimensional flow.

The macCormack's technique is a predictor corrector method.

The governing equations can be written in non-conservative and conservation form. Non-dimensional form of these equations are used for simulation the flow. The non-dimensional variables are referenced to the reservoir values.

Non-conservative form

1. Continuity Equation

`(deltap^')/(deltat^') = -rho^'(deltaV^')/(deltax^')-rho^'V^'(delta(ln A^'))/(deltax^') - V^'(deltarho^')/(deltax^')`

2. Momentum equation

`(deltaV^')/(deltat^') = V^'(deltaV^')/(deltax^')-(1/gamma)((deltaT^')/(deltax^')+t^'/rho^'*(deltarho^')/(deltax^'))`

3. Energy equation

`(deltaT^')/(deltat^') = -V^'(deltaT^')/(deltax^') - (gamma-1)*T^'[(deltaV^')/(deltax^')+V^'(deltaln(A)^')/(deltax^')]`

Where,

Using the MacCormack's approach,

In the predictor step, the governing equations are given as, ,



After the predictor step, we update the values of density, velocity and time,


Now we go to corrector step. Here the governing equations are given as,

After the corrector steps, we find the average time derivates. They are found with the help of the following equations,

Then, we update the values of density, velocity, and temperature using the following equations


Lastly, we find the outflow boundary values.

Conservative Form (non-dimensional)

1. Contiunity Equation

2. Momentum Equation

3. Energy Equation

Consider U as solutiong vector, F as flux vetor and J as source term. Then,

Now, the conservative form of the governing equations become,

The flow variables are calculated as,

density, temperature and velocity is given by,

U1, U2, U3 are given as,

Flux and source term values in terms of U is given as,

Initial conditions

Boundary conditions

CODE

1. Function code for non-conservative form

function [rho,v,t,mass_flow_rate,pressure,mach_no] = non_conservative_form(x,gamma,dx,n,nt,cfl)
        %calculate initial profiles 
        rho = 1-0.3149*x; %density
        t = 1-0.2314*x; %temperature
        v = (0.1+1.09*x).*t.^0.5; %velocity
        %area
        a=1+2.2*(x-1.5).^2; 
        %neck area
        neck = find(a==1);
        %timeloop
        for k=1:nt
            dt = min(cfl*dx./(sqrt(t)+v));
        
            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
                drho_dt_p(j) = -rho(j)*dvdx - rho(j)*v(j)*dlogadx - v(j)*drhodx;
                %momentum
                dv_dt_p(j) = -v(j)*dvdx - (1/gamma)*(dtdx + (t(j)/rho(j))*drhodx);
                %energy
                dt_dt_p(j) = -v(j)*dtdx - (gamma-1)*t(j)*(dvdx + v(j)*dlogadx);
        
                %solution update
                rho(j) = rho(j) + drho_dt_p(j)*dt;
                v(j) = v(j) + dv_dt_p(j)*dt;
                t(j) = t(j) + dt_dt_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
                drho_dt_c(j) = -rho(j)*dvdx - rho(j)*v(j)*dlogadx - v(j)*drhodx;
                %momentum
                dv_dt_c(j) = -v(j)*dvdx - (1/gamma)*(dtdx + (t(j)/rho(j))*drhodx);
                %energy
                dt_dt_c(j) = -v(j)*dtdx - (gamma-1)*t(j)*(dvdx + v(j)*dlogadx);
            end
        
            %compute avg time derivative
            drhodt = 0.5*(drho_dt_p+drho_dt_c);
            dvdt = 0.5*(dv_dt_p+dv_dt_c);
            dtdt = 0.5*(dt_dt_p+dt_dt_c);
        
            %final solution update
            for m = 2:n-1
                rho(m) = rho_old(m) +drhodt(m)*dt;
                v(m)= v_old(m) + dvdt(m)*dt;
                t(m)= t_old(m) + dtdt(m)*dt;
            end
        
            %apply 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);

            %final mass flow rate
            mass_flow_rate = rho.*v.*a;
            %final pressures
            pressure = rho.*t;
            %final mach nos
            mach_no = v./sqrt(t);

            v_k(k)=v(neck);
            rho_k(k) = rho(neck);
            t_k(k) = t(neck);
            mass_flow_rate_k(k)=mass_flow_rate(neck);
            pressure_k(k)=pressure(neck);
            mach_no_k(k)=mach_no(neck);

            %comparing mass flow rates at different timesteps
            figure(1)
            if  k== 1
                plot(x,mass_flow_rate,'color','red','LineWidth',1);
                hold on
            elseif k==50
                plot(x,mass_flow_rate,'color','blue','LineWidth',1);
                hold on
            elseif k==100
                plot(x,mass_flow_rate,'color','green','LineWidth',1);
                hold on
            elseif k==200
                plot(x,mass_flow_rate,'color','magenta','LineWidth',1);
                hold on
            elseif k==400
                plot(x,mass_flow_rate,'color','cyan','LineWidth',1);
                hold on
            elseif k==800
                plot(x,mass_flow_rate,'color','black','LineWidth',1);
                hold on
            elseif k==1400
                plot(x,mass_flow_rate,'color','yellow','LineWidth',1);
                hold on
            end
            title('Mass flow rate of non conservative approach');
            xlabel('Length of the domain')
            ylabel('Mass Flow Rate')
            grid on
            legend('Mass Flow rate at timestep 1','Mass Flow rate at timestep 50','Mass Flow rate at timestep 100','Mass Flow rate at timestep 200','Mass Flow rate at timestep 400','Mass Flow rate at timestep 800','Mass Flow rate at timestep 1400');
        
        end
        %Time-wise variation of the primitive variables - non conservative
        figure(5)
        plot(rho_k,'color','red','LineWidth',1)
        hold on
        plot(v_k,'color','blue','LineWidth',1)
        plot(t_k,'color','green','LineWidth',1)
        plot(mach_no_k,'color','cyan','LineWidth',1)
        plot(mass_flow_rate_k,'color','magenta','LineWidth',1)
        plot(pressure_k,'color','black','LineWidth',1)
        title('Time-wise variation of the primitive variables - non conservative at the nozzle throat')
        legend('Desnity','Velocity','Temperature','Mach Number','Mass Flow Rate','Pressure')
        xlabel('Time Steps')
        ylabel('Primitive Values')
        grid on
end

2. Function code for conservative form

function [rho,v,t,mass_flow_rate,pressure,mach_no] = conservative_form(x,gamma,dx,n,nt,cfl)

        for k=1:n
            %density and temp values 
            if (x(k)<=0.5)
                rho(k)=1;
                t(k)=1;
            elseif (x(k)>=0.5) && (x(k) <= 1.5)
                rho(k)=1-(0.366*(x(k)-0.5));
                t(k)=1-0.167*(x(k)-0.5);
            else 
                rho(k)=0.634-0.3879*(x(k)-1.5);
                t(k)=0.833-0.3507*(x(k)-1.5);
            end
            %area
            a = 1+2.2*(x-1.5).^2; 
            %velocity value
            v(k) = 0.59/(rho(k)*a(k));
        end
        
        %making copies or v, t, rho
        vold = v;
        told=t;
        rho_old=rho; 
        %neck area
        throat = find(a==1);
        
        %initial solution vectors 
        U1 = rho.*a;
        U2 = rho.*a.*v;
        U3 = rho.*((t./(gamma-1))+(gamma/2).*v.^2).*a;
        
        %mac cormack method
        %time loop
        for i=1:nt
            dt = min(cfl.*dx./(sqrt(t)+v)); %adaptive timestep
            %make copies of solution vector
            U1old=U1;
            U2old=U2;
            U3old=U3;
        
            F1 = U2;
            F2 = (U2.^2./U1)+((gamma-1)/gamma)*(U3-(0.5*gamma*U2.^2./U1));
            F3 = (gamma*U3.*(U2./U1))-((0.5*gamma*(gamma-1)).*(U2.^3)./(U1.^2));
            %predictor method
            for j=2:n-1
                %source term-J2
                J2(j)=(1/gamma)*rho(j)*t(j)*((a(j+1)-a(j))/dx);
                %contuinity eqn
                dU1_dt_p(j) = -((F1(j+1)-F1(j))/dx);
                %momentum eqn 
                dU2_dt_p(j) = -((F2(j+1)-F2(j))/dx)+J2(j);
                %energy eqn
                dU3_dt_p(j) = -((F3(j+1)-F3(j))/dx);
                %updating solution vectors 
                U1(j) = U1old(j)+dU1_dt_p(j)*dt;
                U2(j) = U2old(j)+dU2_dt_p(j)*dt;
                U3(j) = U3old(j)+dU3_dt_p(j)*dt;
            end
        
            %finding rho, v, and t from U1, U2, and U3
            rho = U1./a;
            v = U2./U1;
            t= (gamma-1).*((U3./U1)-(0.5*gamma.*v.^2));
            %updating flux vectors 
            F1 = U2;
            F2 = (U2.^2./U1)+((gamma-1)/gamma)*(U3-(0.5*gamma.*U2.^2./U1));
            F3 = (gamma*U3.*U2./U1)-((0.5*gamma*(gamma-1)).*U2.^3./U1.^2);
            %Corrector Method
            for j=2:n-1
                %source term-J2
                J2(j)=(1/gamma)*rho(j)*t(j)*((a(j)-a(j-1))/dx);
                %contuinity eqn
                dU1_dt_c(j) = -((F1(j)-F1(j-1))/dx);
                %momentum eqn 
                dU2_dt_c(j) = -((F2(j)-F2(j-1))/dx)+J2(j);
                %energy eqn
                dU3_dt_c(j) = -((F3(j)-F3(j-1))/dx);
            end
            %Computing avg time derivatives of solution vectors 
            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 m = 2:n-1
                U1(m) = U1old(m)+dU1_dt_avg(m)*dt;
                U2(m) = U2old(m)+dU2_dt_avg(m)*dt;
                U3(m) = U3old(m)+dU3_dt_avg(m)*dt;
            end 
            %Inlet BC
            U1(1) = a(1);
            U2(1) = 2*U2(2)-U2(3);
            U3(1) = U1(1)*((t(1)/(gamma-1))+(0.5*gamma*(U2(1)/U1(1))^2));
            %Outlet BC
            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 rho,v,t
            rho = U1./a;
            v = U2./U1;
            t= (gamma-1).*((U3./U1)-(0.5*gamma.*v.^2));
            
            %final mass flow rate
            mass_flow_rate = rho.*v.*a;
            %final pressures
            pressure = rho.*t;
            %final mach nos
            mach_no = v./sqrt(t);

            rho_k(i)=rho(throat);
            v_k(i)=v(throat);
            t_k(i)=t(throat);
            mass_flow_rate_k(i)=mass_flow_rate(throat);
            pressure_k(i)=pressure(throat);
            mach_no_k(i)=mach_no(throat);

        
            %comparing mass flow rates at different timesteps
            figure(2)
            if  i== 1
                plot(x,mass_flow_rate,'color','red','LineWidth',1);
                hold on
            elseif i==50
                plot(x,mass_flow_rate,'color','blue','LineWidth',1);
                hold on
            elseif i==100
                plot(x,mass_flow_rate,'color','green','LineWidth',1);
                hold on
            elseif i==200
                plot(x,mass_flow_rate,'color','magenta','LineWidth',1);
                hold on
            elseif i==400
                plot(x,mass_flow_rate,'color','cyan','LineWidth',1);
                hold on
            elseif i==800
                plot(x,mass_flow_rate,'color','black','LineWidth',1);
                hold on
            elseif i==1400
                plot(x,mass_flow_rate,'color','yellow','LineWidth',1);
                hold on
            end
            title('Mass flow rate of conservative approach');
            xlabel('Length of the domain')
            ylabel('Mass Flow Rate')
            grid on
            legend('Mass Flow rate at timestep 1','Mass Flow rate at timestep 50','Mass Flow rate at timestep 100','Mass Flow rate at timestep 200','Mass Flow rate at timestep 400','Mass Flow rate at timestep 800','Mass Flow rate at timestep 1400');
        end
        %Time-wise variation of the primitive variables - conservative
        figure(6)
        plot(rho_k,'color','red','LineWidth',1)
        hold on
        plot(v_k,'color','blue','LineWidth',1)
        plot(t_k,'color','green','LineWidth',1')
        plot(mach_no_k,'color','cyan','LineWidth',1)
        plot(mass_flow_rate_k,'color','magenta','LineWidth',1)
        plot(pressure_k,'color','black','LineWidth',1)
        title('Time-wise variation of the primitive variables - conservative at the nozzle throat')
        legend('Desnity','Velocity','Temperature','Mach Number','Mass Flow Rate','Pressure')
        xlabel('Time Steps')
        ylabel('Primitive Values')
        grid on



end

3. Main code

clear all
close all
clc

%inputs
n = 31;
x =linspace(0,3,n);
dx = x(2)-x(1);
gamma = 1.4; 
%timesteps
nt = 1400;
%courants number 
cfl=0.5; 

% calling non conservative function 
tic
[rho_nc,v_nc,t_nc,mass_flow_rate_nc,pressure_nc,mach_no_nc] = non_conservative_form(x,gamma,dx,n,nt,cfl);
nc_time_31node = toc;
% calling conservative function
tic
[rho_c,v_c,t_c,mass_flow_rate_c,pressure_c,mach_no_c] = conservative_form(x,gamma,dx,n,nt,cfl);
c_time_31node = toc;


%plots 
%steady state plot of primitive values - non conservative 
figure(3)
plot(x,rho_nc,'color','red','LineWidth',1)
hold on
plot(x,v_nc,'color','blue','LineWidth',1)
plot(x,t_nc,'color','green','LineWidth',1)
plot(x,mach_no_nc,'color','cyan','LineWidth',1)
plot(x,mass_flow_rate_nc,'color','magenta','LineWidth',1)
plot(x,pressure_nc,'color','black','LineWidth',1)
title('Steady-state distribution of primitive variables inside the nozzle - non conservative  ')
legend('Desnity','Velocity','Temperature','Mach Number','Mass Flow Rate','Pressure')
xlabel('Length of the domain')
ylabel('Primitive Values')
grid on

%steady state plot of primitive values - conservative 
figure(4)
plot(x,rho_c,'color','red','LineWidth',1)
hold on
plot(x,v_c,'color','blue','LineWidth',1)
plot(x,t_c,'color','green','LineWidth',1)
plot(x,mach_no_c,'color','cyan','LineWidth',1')
plot(x,mass_flow_rate_c,'color', 'magenta','LineWidth',1)
plot(x,pressure_c,'color','black','LineWidth',1)
title('Steady-state distribution of primitive variables inside the nozzle - conservative')
legend('Desnity','Velocity','Temperature','Mach Number','Mass Flow Rate','Pressure')
xlabel('Length of the domain')
ylabel('Primitive Values')
grid on

%normalized mass flow rates
figure(7)
plot(x,mass_flow_rate_nc,'color','r','linewidth',1)
hold on
plot(x,mass_flow_rate_c,'color','blue','linewidth',1)
xlabel('Mass Flow rates')
ylabel('Length of the domain')
title('Normalized mass flow rates')
legend('Mass Flow Rate - Non-conservative form','Mass Flow Rate - Conservative form')
grid on 

CODE EXPLAINATION

Function code:

In the function code, data which are common for both approaches are taken from the main code. In both cases, we have a predictor method. After this, we have solution update. After solution update, we have the corrector step. After this, we have final solution update. Then we find the initial and boundary conditions. This is run in a time loop of 1400 timesteps. This means it run for 1400 times.

Main Code:

Common data are created and then the respective functions are called. Then using data taken from the functions after they are executed, the required plots are created.

RESULTS AND CONCLUSION

1. NON CONSERVATIVE FORM

Mass Flow Rate

Primitive variables values inside the nozzle

Primitive variables at the throat of the nozzle at all timesteps

2. CONSERVATIVE FORM

Mass flow rate

Primitive variables values inside the nozzle

Primitive variables at the throat of the nozzle at all timesteps

3. Normalized mass flow rate

Grid Independence Test

This test tells us if our solution is dependent on the mesh. This means that change is mesh should not result in large/notable changes in our solution. When this happens, it means that out solution is grid independent. This test is carried out at 2 different mesh values. It is done at n=31 and n=61 and some values at the last node are taken for comparasion.

Conservative approach Non - Conservative approach
n=31 n=61 Difference n=31 n=61 Difference
Velocity 1.865912 1.863861 0.0020507 1.861787 1.863112 -0.00132433
Density 0.052717 0.052563 0.0001541 0.052857 0.05265 0.000206893
Temperature 0.305479 0.307164 -0.001685 0.308274 0.307893 0.000381504
Time Taken 89.74761 86.52621 3.2214072 90.2853 90.61938 -0.3340774

Here in the above table, we can see that the difference is values at n=31 and n=61 are of negligible amount. This means that our soultion at n=31 is already grid independent.

CONCLUSIONS

In the case of non-conservative approach, from the mass flow rate plot, we can see that between 400 and 800 timesteps, the mass flow rate is normalized and remains as such till 1400th timestep. The primitive variables values at the throat of the nozzel vary till approximately 600 timesteps and then remain unchanged. From the steady state plots, we can see that at the outlet, the mach no. is the highest. Similar characteristic is seen with velocity also. For density, temperature and pressure, the opposite is seen. They are at the lowest at the outlet.

In conservative form, the majority of the characteristics are similar to the non-conservative form.

In the case of normalized mass flow rate comparision, the conservative approach looks to be more stable compared to the non conservative approach

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.