Transfer Functions and Linear Active Networks Using Operational Amplifiers
final_report
1. Numerical Solution of a Compressible Choked-Nozzle by
Solving the Quasi-1D Euler Equations
CFD 237 Final Report
Taylor Hugh Morgan
University of California, Irvine
Abstract
We numerically solve the quasi-1D Euler equations to capture subsonic and
supersonic flow in a choked-nozzle. We experiment with a variety of numeri-
cal schemes including: Jameson-Schmidt-Turkel (JST) and first-order Steger
flux vector splitting. We also attempt the second-order Roe approximate Rie-
mann solver with MUSCL and limiters because it is a higher-order scheme
and potentially more reliable. Had we more time, we would have attempted
other schemes. We compare the steady state solution of each scheme to the
analytic solution.
Keywords: Compressible flow, Quasi-1D, Shock Capturing
1. Introduction
Using the method of characteristics an analytic solution to the quasi-
1D Euler equations for compressible flow can be obtained. We compare the
steady state solutions of the numeric simulations to the analytic solution.
Thus this is an excellent set of equations to test our numerical schemes.
The nonlinear Euler equations are as follows
∂ ¯W
∂t
+
∂¯F
∂t
= Q (1)
where ¯W = WS(x) and ¯F = FS(x).
W =
ρ
ρu
ρE
(2)
Preprint submitted to Dr. Feng Liu December 10, 2016
2. F =
ρu
ρuu + p
ρuH
(3)
Q =
0
pS (x)
0
(4)
We solve these equations referencing the papers and information you provided
with the assignment. In referencing the papers, we keep in mind that our ¯W
and ¯F are typically represented by U and F respectively.
Common procedure to solve these equations is to imagine each grid block
point has some inward and outward flux and that the internal values are
simply an average representation of the net flux. Thus we use finite-volume
methods. The key to knowing if our numerical method is accurately repre-
sents what is physically taking place, however, is to first obtain an analytic
solution.
1.1. The Analytic Solution
Using tabulated values from the isentropic, steady-state area-mach num-
ber relations, we calculated the approximate Mach number, total tempera-
ture, and total pressure as a function of x. Figure 1 shows the profiles for
both subsonic and supersonic flows. In the numerical methods section we
look at the total values and mach number and compare them to these values.
However, the supersonic case we see here is not an exact representation of
what we should see in our choked nozzles. The supersonic flow case should
have a stationary shock wave near the outlet because of the discontinuity
between the back pressure (pb) and the flow pressure. We can analytically
solve for the location of and magnitude of the shock for better comparison.
We also recognize that because of the numerical diffusion present in our
schemes that the sharp peaks in the subsonic case should be smoothed out
as well.
2. Numerical Methods
Convergence occurred within .2 to 0.5 seconds for most schemes. JST
converged most quickly because the maximum wave speed Rj was set to
2
3. 0 2 4 6 8 10
x(m)
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0 P, T, and M for subsonic flow (Pb = 9atm)
M
T/T0
P/P0
0 2 4 6 8 10
x(m)
0.0
0.5
1.0
1.5
2.0 P, T, and M for supersonic flow (Pb = 4atm)
M
T/T0
P/P0
Figure 1: the analytic solution to subsonic and supersonic flows for a choked nozzles. No
shock occurs at the outlet until we impose a back-pressure at the outlet.
3
4. |λmax| or |u| + a, whereas in the Steger scheme Rj was broken into its con-
stituent |λ1|, |λ2|, |λ3|, etc. I had some freedom to chose some values general
to all of the heretofore mentioned schemes.
Important to note: I used a grid of 100 points (δx = 0.1) and CFL
= 1.0. All of the following plots represent the steady-state behavior of the
numerical solution.
Attached in this project are several files:
• this project writeup
• finalproject.py which is the main script to be run (from either a GUI
or command line)
• initialconditions.py which provides the simulation with either the sub-
sonic or supersonic initial conditions, which is useful when debugging
errors
• genPDE1D.py which generally handles how boundary conditions are
applied and has the option to include chemical species reaction and
diffusion
• quasi1DEuler.py which does the grunt-work of the system, contains the
numerical methods, and solves the differential equations
As you can tell, for this project I chose to use Python as my programming
language for the following reasons:
• It is an object oriented language, which allows for better organization
and modularity (I plan on using this code in future research).
• It is a high-level, easy-to-use language with versatile debuggers and
guis (such as Spyder).
• Libraries like numba, numpy, cython, and others allow for just in time
(jit) compilation and vectorization, which can reach speeds comparable
to C and Fortran. See https://jakevdp.github.io/blog/2013/06/
15/numba-vs-cython-take-2/
A sample of python code for the JST scheme is located in section 1 of the
appendix.
4
5. 2.1. The Jameson-Schmidt-Turkel (JST) Scheme
When experimenting with diffusion coefficients we found that α2 = 1 and
β2 = 1 was stable for both subsonic and supersonic schemes. Changing them
around allowed us to better capture the shock transition and sharp gradients.
We used the aforementioned values of α2 and β2 in the following plots for
consistency.
You will notice in the following plots that:
1. sharp peaks, especially in the subsonic case where the Mach number
reaches the sonic point and near the shock, are smoothed out
2. the sonic point has moved forward slightly in the subsonic case
The smoothing occurs because of numerical diffusion. Adjusting α2 and β2
allows us to better capture these features, but that is more of an art than
actual science.
2.1.1. 3-stage scheme
The 3-stage scheme was unique in that it was very sensitive to α2, β1, and
β2 - aka the diffusion flux coefficients. Because it was giving me problems
when I followed the instructions provided in the handout, I resorted to the
calculation of dissipation flux given in the paper outlining JST. Following
their calculation of diffusion led to a much nosier solution (see figure 2). The
solution still fits the general trend. One interesting feature is that the sonic
point is actually closer to the center of grid (the true location of the choked
nozzle).
Another thing I noticed is that the subsonic case was even more sensitive
to the outlet pressure. I had to try several different values of back pressure
(pb) before I was able to recapture the correct solution at around 6.5atm.
2.1.2. A better 3-stage scheme
In class it was mentioned that there is a ”better” 3-stage Runge-Kutta
scheme using α2 = 1/2 and α1 = 1/3 instead of α2 = 3/5 and α1 = 3/5.
These coefficients were given in class. See Fig 3. These coefficients led to a
much smoother and less noisy solution. This and higher stage (4th and 5th
order) schemes were much less noisy.
2.1.3. 4-stage scheme
For the 4-stage scheme α1 = 1/4, α2 = 1/3, and α3 = 1/2. Something to
notice for the 4 and 5-stage schemes is the drifting of the sonic point from
around x=5 to x=6 meters.
5
6. (a) Subsonic case (b) Supersonic case
Figure 2: the numeric solution to subsonic and supersonic flows for a choked nozzle using
the JST 3-stage scheme and dissipation flux from the JST paper. Shock occurs at the
outlet for the supersonic case.
0 2 4 6 8 10
x(m)
0.0
0.2
0.4
0.6
0.8
1.0
1.2
JST "better" 3-stage scheme
Mach
TT0
PP0
(a) Subsonic case
0 2 4 6 8 10
x(m)
0.0
0.2
0.4
0.6
0.8
1.0
1.2
1.4
1.6
1.8
JST "better" 3-stage scheme
Mach
TT0
PP0
(b) Supersonic case
Figure 3: the numeric solution to subsonic and supersonic flows in a choked nozzle using
the JST ”better” 3-stage scheme and dissipation flux from the JST paper. Shock occurs
at the outlet for the supersonic case.
6
7. (a) Subsonic case (b) Supersonic case
Figure 4: the numeric solution to subsonic and supersonic flows in a choked nozzle using
the JST 4-stage scheme and dissipation flux from the JST paper.
2.1.4. 5-stage scheme
For the 5-stage scheme α1 = 1/4, α2 = 1/6, α3 = 3/8, and α4 = 1/2.
There is not, however, a noticeable visual between the 4-stage and 5-stage
solution. We plot the difference in the steady-state solution as well (see Fig
6).
2.2. First-order Steger Flux-Vector splitting
Steger flux-vector splitting scheme about twice as long to stabilize than
the JST Scheme. My hypothesis is that since JST is overly-diffusive, it
smooths out the solution very quickly. Steger converges more slowly - but
is more physically representative of the shock solution. Another feature to
notice is that the shock has drifted downstream.
We obtain this numerical method by simple modification to the JST
scheme. For JST scheme we use a Rj (maximum wave speed) for our dissi-
pation flux that is simply calculated by using Rj = |λmax| = |u|+a. We split
|λmax| into |λ1|, |λ2|, |λ3| where |λ1| = |u|, |λ2| = |u + a|, and |λ3| = |u − a|
and apply that to their corresponding vector in the PDE. By minimizing the
dissipation flux, we get a less diffuse, and more physical solution, especially
in the case of shock at the exit (see Fig 7). Suprisingly, we actually see the
sonic point move back to the center (x=5). It seems overall that the Ste-
ger method, through minimal manipulation, becomes a much better overall
solution.
7
8. 0 2 4 6 8 10
x(m)
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0
JST 5-stage scheme
Mach
TT0
PP0
(a) Subsonic case
0 2 4 6 8 10
x(m)
0.0
0.2
0.4
0.6
0.8
1.0
1.2
1.4
1.6
1.8
JST 5-stage scheme
Mach
TT0
PP0
(b) Supersonic case
Figure 5: the numeric solution to subsonic and supersonic flows in a choked nozzle using
the JST 5-stage scheme and dissipation flux from the JST paper.
0 2 4 6 8 10
0.0
0.5
1.0
1.5
2.0
2.5
3.0
3.5 1e−6
|Mach4stage −Mach3stage|
|Mach5stage −Mach3stage|
|Mach5stage −Mach4stage|
Figure 6: The absolute difference in Mach number between stages. As we expect, the
largest difference is between the 5 and ”better” 3 stage schemes.
8
9. Figure 7: the numeric solution to subsonic (top) and supersonic (bottom) flows for a
choked nozzle using the Steger flux-vector splitting. Time integration was done using
Runge-Kutta 5-stage scheme. Notice the sharpness of the transition between where the
shock occurs compared to JST scheme. The sonic point is also located closer to x=5
compared to the JST scheme.
9
10. 2.3. Second-order Roe Approximate Riemann Solver and MUSCL with lim-
iter
The aforementioned schemes, Steger flux-vector splitting and JST, were
only first-order accurate. I got a little gutsy for this last one and attempted
to get a second-order scheme to work. I chose the second-order Roe Approx-
imate Riemann solver with limiters. I chose to move onto this one because I
was able to find a lot of source material about this scheme online and in the
papers provided. While experimenting I found that several parameters are
undefined and there is a more stable combination. For example
1. with the shock at the outlet case, not using limiters caused the simu-
lation to blow up and
2. calculating maximum wave speed using |u| + a, as in the case of the
JST scheme, led to a more stable solution.
This was the more difficult of the codes to develop because it is very
unstable without limiters. This meant that I needed to develop the entire
code and then work backwards to debug. I began by setting φ±
= 0 and
Rj = |u| + a, meaning it was approximately a JST scheme. Which, as we
already know, is quite stable. Then I moved on to calculate φ±
using lecture
notes.
φ±
= max
2∆+∆−
∆2
+ + ∆2
− +
, 0 (5)
where
∆+ = ¯Wj+1 − ¯Wj (6)
and
∆− = ¯Wj − ¯Wj−1 (7)
and is a small number (≈ 1e − 6).
After much sweat and tears, a final solution was reached only after ap-
plying limiters. Figure 8 shows the total quantities for the method. I assume
that some problems need to be fixed, especially in the case of maximum wave
speed, which I believe is incorrect. That will be my next step.
3. Results and Discussion
Overall the Steger scheme, I felt at least, came out on top. It is a clean,
accurate solution with very little modification from the JST scheme. Roe
approximate Riemann solver took a lot more effort and ended up being very
10
11. 0 2 4 6 8 10
x(m)
0.0
0.2
0.4
0.6
0.8
1.0
1.2
Second-order Roe approx Riemann with MUSCL and limiter
Mach
TT0
PP0
0 2 4 6 8 10
x(m)
0.0
0.2
0.4
0.6
0.8
1.0
1.2
1.4
1.6
1.8
Second-order Roe approx Riemann with MUSCL and limiter
Mach
TT0
PP0
Figure 8: the numeric solution to subsonic (top) and supersonic (bottom) flows for a
choked nozzle using the Roe approximate Riemann solver and MUSCL with limiters.
Time integration was done using Runge-Kutta 5-stage scheme.
11
12. 0 2 4 6 8 10
x(m)
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0
JST 5-stage scheme
Mach
rho/max(rho)
p/max(p)
T/max(T)
(a) Subsonic case
0 2 4 6 8 10
x(m)
0.0
0.2
0.4
0.6
0.8
1.0
1.2
1.4
1.6
1.8
JST 5-stage scheme
Mach
rho/max(rho)
p/max(p)
T/max(T)
(b) Supersonic case
Figure 9: the numeric solution to subsonic and supersonic flows in a choked nozzle using
the JST 5-stage scheme and dissipation flux from the JST paper.
wiggly. In the project statement you asked for us to include plots of tempera-
ture, density, pressure, and Mach number. Figures 9-11 show the normalized
values for temperature, density, and pressure, as well as Mach number, for
the three numerical methods all with 5-stage Runge-Kutta for the time in-
tegration. I made the figures smaller so that they didn’t take up too many
pages; but they are vector images so you should be able to zoom up on them
without a problem.
4. Conclusion
I am excited to move these numerical methods to 2 and three dimensions.
This course applied directly to my research and I am very grateful that I was
able to take the class. Thank you for this opportunity.
5. Appendix
5.1. Python JST Sample
For example, I can simplify the entire residual of the JST using Python’s
dictionaries using this code:
# vj is pressure sensor term
p = self.fields[’p’]
vj[1:-1] = np.abs((p[2:] - 2 * p[1:-1] + p[:-2]) / (p[2:] + 2 * p[1:-1] + p[:-2]))
12
13. 0 2 4 6 8 10
x(m)
0.0
0.2
0.4
0.6
0.8
1.0 Steger 5-stage scheme
Mach/max(Mach)
rho/max(rho)
p/max(p)
T/max(T)
(a) Subsonic case
0 2 4 6 8 10
x(m)
0.0
0.2
0.4
0.6
0.8
1.0
1.2
1.4
1.6
1.8 Steger 5-stage scheme
Mach
rho/max(rho)
p/max(p)
T/max(T)
(b) Supersonic case
Figure 10: the numeric solution to subsonic and supersonic flows in a choked nozzle using
the Steger flux-vector splitting and 5-stage Runge-Kutta time integration.
0 2 4 6 8 10
x(m)
0.0
0.2
0.4
0.6
0.8
1.0
1.2
Second-order Roe approx Riemann with MUSCL and limiter
Mach
rho/max(rho)
p/max(p)
T/max(T)
(a) Subsonic case
0 2 4 6 8 10
x(m)
0.0
0.2
0.4
0.6
0.8
1.0
1.2
1.4
1.6
1.8
Second-order Roe approx Riemann with MUSCL and limiter
Mach
rho/max(rho)
p/max(p)
T/max(T)
(b) Supersonic case
Figure 11: the numeric solution to subsonic (top) and supersonic (bottom) flows for a
choked nozzle using the Roe approximate Riemann solver and MUSCL with limiters.
Time integration was done using Runge-Kutta 5-stage scheme.
13
14. # Qj - second order Euler flux
hbar = (self.F[fn][:-1] + self.F[fn][1:]) / 2
Qj[1:-1] = hbar[1:] - hbar[:-1]
# Dj - second order dissipation flux
# R_j - maximum sound speed
u = self.fields[’u’]
R_j = np.abs(self.fields[’u’]) + self.soundspeed
# deltaW - first order forward differencing of W
deltaW[:-1] = W[1:] - W[:-1]
delta3W[3:] = W[3:] - 3*W[2:-1] + 3*W[1:-2] - W[:-3]
delta3W[0:2] = -W[0:1] + 3*W[1:2] - 3*W[2:3] + W[3:4]
alpha = [0.5, 1.0]
beta = [1./32., 1.0]
Sj = np.max(np.array([vj[1:],vj[:-1]]), 0)
eps2 = np.max(np.array([alpha[0] * np.ones(self.npx-1), alpha[1] * Sj]), 0)
eps4 = np.max(np.array([np.zeros(self.npx-1), beta[0] - beta[1] * eps2]), 0)
d_j = eps2 * R_j * deltaW[:-1] - eps4 * R_j * delta3W[:-1]
Dj[1:-1] = d_j[1:] - d_j[:-1]
Rj = (Qj - Dj) / self.Vol - self.Source[sn]
which can calculate the residual for any of the equations without having to
pass functions back and forth and having to update variables.
14