This notebook illustrates some features of the exact solution to the 1-dimensional constant coefficient acoustics equations, as described in more detail in Chapter 3 of (LeVeque 2002). Since acoustic equations are a landmark example of linear wave propagation, we will begin with a brief derivation of the equations. This will also help having a self contained document.
The linear acoustic equations can be obtained by linearizing the conservation of mass and momentum for an element of fluid. The conservation of mass and momentum for a fluid element are given by
\begin{align*} \frac{\partial \rho}{\partial t} + \nabla \cdot \left(\rho \bar{u}\right) = 0 \\ \frac{d \rho \bar{u}}{dt} = -\nabla P \end{align*}
where $d/dt$ denotes the material derivative: $\frac{d}{dt} = \frac{\partial}{\partial t} + \bar{u} \cdot \nabla$. In one dimension, these can be easily rewritten as
\begin{align*} \rho_t + (\rho u)_x = 0, \\ (\rho u)_t + (\rho u^2 + P(\rho))_x =0, \end{align*}
where we assumed the pressure is a function of the density, which is only accurate for small perturbations around some equilibrium state given by $\rho_0$ and $u_0$. Linearizing the equation around $\rho_0$ and $u_0 =0$, we obtain a simpler system for the perturbations,
\begin{align*} \rho_t + (\rho u)_x = 0, \\ (\rho u)_t + P'(\rho_0)\rho_x =0. \end{align*}
where, somewhat abusing the notation, $\rho$ and $u$ are now the perturbations around $\rho_0$ and $u_0 = 0$. As perturbations on the pressure and density satisfy
\begin{align*} p\approx P'(\rho_0)\rho, \\ \rho u \approx \rho_0 u, \end{align*}
we can rewrite the system of linear acoustic equations as
\begin{align*} \left[ \begin{array}{c} p \\ u \end{array} \right]_t
with $K_0=\rho_0 P'(\rho_0)$ the bulk modulus of compressibility for the media where the waves are propagating. It tells us how compressible is a material; a higher value implies less compressibility. The eigenvalues of the coefficient matrix $A$ are $\pm c$, where
\begin{align*} c = \sqrt{{K_0}/{\rho_0}}. \end{align*}
This is the speed of sound in the medium, the Newton-Laplace equation. This is consistent with the more general approach to obtaining the speed of sound from a general equation of state, $c=\sqrt{(\partial P)/\partial \rho)_s}$, where the derivative is taken with entropy $s$ held constant. See Euler_equations.html and Euler_equations_TammanEOS.ipynb for examples of nonlinear acoustics in compressible gas dynamics.
In a more general framework, acoustic equations are a linear hyperbolic system of two equations for $q = [p, u]^T$, where $p$ is the pressure perturbation and $u$ is the velocity. As we just derived, the system is $q_t + Aq_x = 0$, where the coefficient matrix is
\begin{align*} A = \left[\begin{array}{cc}0&K\\1/\rho&0\end{array}\right], \end{align*}
where $\rho$ is the density and $K$ the bulk modulus (note we dropped the subscripts for simplicity). The sound speed and acoustic impedance are given by $c = \sqrt{K/\rho}$ and $Z=\rho c=\sqrt{K\rho}$, respectively. The impedance can be understood as the resitance of the medium to the propagation of acoustic waves. In order to solve the Riemann problem, we would like to solve this system subject to the initial condition on $q(x,t)$,
\begin{align*} q(x,0) = \begin{cases} q_\ell & \text{if } x \le 0, \\ q_r & \text{if } x > 0. \end{cases} \end{align*}
The solution can be obtained by transforming the linear system into two uncoupled advection equations, see (LeVeque 2002). When transformed back to the original coordinates the solution will have the following structure,
The structure in the $x-t$ plane shows two waves propagating at velocities $s_1=-c$ and $s_2=c$, which correspond to the two eigenvalues of $A$. At time zero the initial condition remains true, but at times $t>0$ a third state emerges, $q_m$, and it can be calculated from the eigenvectors of the matrix $A$. The corresponding eigenvectors are
\begin{align*} r_1 = \left[\begin{array}{c}-Z\\1\end{array}\right], \qquad r_2 = \left[\begin{array}{c}Z\\1\end{array}\right]. \end{align*}
For arbitrary states $q_\ell$ and $q_r$, the Riemann solution consists of two waves propagating with velocities $\pm c$ with an intermediate state $q_m$ that is connected to $q_\ell$ by a multiple of $r_1$ and to $q_r$ by a multiple of $r_2$. Therefore, the left and right states are connected through a linear combination of $r_1$ and $r_2$,
\begin{align*} q_r-q_\ell = \Delta q = \alpha_1 r_1 + \alpha_2 r_2, \end{align*}
where $\Delta q = [\Delta p, \Delta u]^T$. We can write this in more general form form as \begin{align*} R \alpha = \Delta q, \end{align*}
where $\alpha=[\alpha_1, \alpha_2]^T$ and $R=[r_1,r_2]$ is the matrix of column eigenvectors,
\begin{align*} R = \left[\begin{array}{cc}-Z& Z\\1 & 1\end{array}\right]. \end{align*}
This matrix is always nonsingular provided $Z>0$, as it must be in practice, so we can solve this linear system for $\alpha$ to obtain,
\begin{align*} \alpha_1 = \frac{-\Delta p + Z\Delta u}{2Z}, \ \ \ \ \ \ \alpha_2 = \frac{\Delta p + Z\Delta u}{2Z}. \end{align*}
We can now obtain the value of $q_m$ in terms of $q_\ell$ or $q_r$
\begin{align} q_m = q_\ell + \alpha_1 r_1 = q_r - \alpha_2 r_2. \label{eq:acussol} \end{align}
Note that the form of the eigenvectors shows that in any propagating discontinuity, the jump in $p$ is $\pm Z$ times the jump in $u$. More generally, the eigenvectors of the coefficient matrix of a linear hyperbolic system reveal the relation between jumps in the different components of $q$ across a wave propagating with speed given by the corresponding eigenvalue. For acoustics, the impedance is the physical parameter that determines this relation.
Here we provide some very simple initial data, and we call the linear Riemann solver. This will output the three states $q_l$, $q_m$ and $q_r$, and the speeds of the two waves.
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import widgets
from ipywidgets import interact
from exact_solvers import acoustics, interactive_pplanes
from utils import riemann_tools
rho = 1. # density
bulk = 4. # bulk modulus
c = np.sqrt(bulk/rho) # sound speed
Z = np.sqrt(bulk*rho) # impedance
print("Density rho = %g, Bulk modulus K = %g" % (rho,bulk))
print("Sound speed c = %g, Impedance Z = %g" % (c,Z))
ql = np.array([1,2]) # Left state
qr = np.array([2,-2]) # Right state
states, speeds, reval = acoustics.exact_riemann_solution(ql ,qr, [rho, bulk])
print("The states ql, qm and qr are: ")
print(states)
print(" ")
print("The left and right wave speeds are:")
print(speeds)
We can also show the structure of the solution in the $p-u$ phase plane:
ppplot=interactive_pplanes.acoustics_phase_plane_plot()
ppplot(ql[0],ql[1],qr[0],qr[1],rho,bulk)
As we already showed in the previous section, one way to understand the solution to a linear system like acoustics equations is by looking at the phase plane. The middle state $q_m$ generated between the two waves must be connected to $q_l$ by a multiple of the first eigenvector and to $q_r$ by a multiple of the second eigenvector,as it is evident from equation (\ref{eq:acussol}). Therefore, the solution of the Riemann problem is nothing more but the intersection of the line generated by the first eigenvector going through $q_l$ with the line generated by the second eigenvector going through $q_r$. This is easier to understand visually, like in the interactive plot we show next.
# Initial states [pressure, velocity]
ql = [10.0, -5.0]
qr = [40.0, 5.0]
# Acoustic eqs. parameters
rho = 2.0
bulk = 1.0
interactive_pplanes.acoustics_interactive_phase_plane(ql,qr,rho,bulk)
Note that the eigenvectors are given in terms of the impedance $Z$, which depends on the density $\rho$ and the bulk modulus $K$. Therefore, when $\rho$ and $K$ are modified the eigenvectors change and consequently the slope of the lines changes as well.
We will begin by defining a function that calls the exact solver in exact_solvers/acoustics.py and plots the solution for different interesting examples
def plot_riemann_solution(ql, qr, aux):
ex_states, ex_speeds, reval = acoustics.exact_riemann_solution(ql ,qr, aux)
plot_function = riemann_tools.make_plot_function(ex_states, ex_speeds, reval, layout='vertical',
variable_names=['pressure', 'velocity'],
aux=(np.array(aux),np.array(aux)),
plot_chars=[acoustics.lambda1,
acoustics.lambda2])
return interact(plot_function, t=widgets.FloatSlider(value=0.0,min=0,max=1.0),
which_char=widgets.Dropdown(options=[None,1,2],description='Show characteristics'));
If the velocity is 0 in both initial states (the shock tube problem) then the resulting Riemann solution consists of pressure jumps of equal magnitude propagating in each direction, with equal and opposite jumps in velocity.
ql = np.array([5,0])
qr = np.array([1,0])
rho = 1.0
bulk = 4.0
plot_riemann_solution(ql, qr, [rho, bulk]);
The solution in the phase plane is given by
ppplot(ql[0],ql[1],qr[0],qr[1],rho,bulk)
As another example, suppose the pressure is initially the same in the left and right states, while the velocities are non-zero with $u_r = -u_\ell > 0$. Particles are converging from both sides and if the initial states have this symmetry, then the result is a middle state $q_m$ in which the velocity is 0 (and the pressure is higher than on either side).
ql = np.array([3,2])
qr = np.array([3,-2])
rho = 1.0
bulk = 20.0
plot_riemann_solution(ql, qr, [rho, bulk]);
The solution in the phase plane and the particle trajectories are the following:
ppplot=interactive_pplanes.acoustics_phase_plane_plot()
rho = 1
bulk = 1
ppplot(ql[0],ql[1],qr[0],qr[1],rho,bulk)
If you discard half the solution (for $x>0$ or for $x<0$) then what you see can be viewed as the solution to a problem with fluid streaming at constant velocity toward a solid wall. The result is an acoustic wave that moves away from the wall, and the fluid behind the shock has been decelerated to velocity 0, i.e. it is stationary at the wall.
This type of Riemann solution is critical when imposing solid wall boundary conditions in a numerical method. If ghost cells are introduced outside the domain and the state in the ghost cell set by reflecting the interior solution with the symmetry seen here (equal pressure, negated velocity), then the solution to the Riemann problem at the cell interfaces yields a solution that satisfies the desired boundary conditions.
Note it is possible to extend the Riemann problem solution for acoustic equations to cases where there are different materials on the left and right side. This is useful to solve the acoustic wave propagation across interfaces or heterogeneous media, and it will be explored further in the section on acoustic equations for heterogeneous media.