{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "###### Content under Creative Commons Attribution license CC-BY 4.0, code under MIT license (c)2014 L.A. Barba, C.D. Cooper, G.F. Forsyth. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Riding the wave" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sod's test problems" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sod's test problems are standard benchmarks used to assess the accuracy of numerical solvers. The tests use a classic example of one-dimensional compressible flow: the shock-tube problem. Sod (1978) chose initial conditions and numerical discretization parameters for the shock-tube problem and used these to test several schemes, including Lax-Wendroff and MacCormack's. Since then, many others have followed Sod's example and used the same tests on new numerical methods.\n", "\n", "The shock-tube problem is so useful for testing numerical methods because it is one of the few problems that allows an exact solution of the Euler equations for compressible flow.\n", "\n", "This notebook complements the previous lessons of the course module [_\"Riding the wave: convection problems\"_](https://github.com/numerical-mooc/numerical-mooc/tree/master/lessons/03_wave) with Sod's test problems as an independent coding exercise. We'll lay out the problem for you, but leave important bits of code for you to write on your own. Good luck!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### What's a shock tube?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A shock tube is an idealized device that generates a one-dimensional shock wave in a compressible gas. The setting allows an analytical solution of the Euler equations, which is very useful for comparing with the numerical results to assess their accuracy. \n", "\n", "Picture a tube with two regions containing gas at different pressures, separated by an infinitely-thin, rigid diaphragm. The gas is initially at rest, and the left region is at a higher pressure than the region to the right of the diaphragm. At time $t = 0.0 s$, the diaphragm is ruptured instantaneously. \n", "\n", "What happens? \n", "\n", "You get a shock wave. The gas at high pressure, no longer constrained by the diaphragm, rushes into the lower-pressure area and a one-dimensional unsteady flow is established, consisting of:\n", "\n", "* a shock wave traveling to the right\n", "* an expansion wave traveling to the left\n", "* a moving contact discontinuity\n", "\n", "The shock-tube problem is an example of a *Riemann problem* and it has an analytical solution, as we said. The situation is illustrated in Figure 1." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![shocktube](./figures/shocktube.png)\n", "#### Figure 1. The shock-tube problem." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The Euler equations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Euler equations govern the motion of an inviscid fluid (no viscosity). They consist of the conservation laws of mass and momentum, and often we also need to work with the energy equation. \n", "\n", "Let's consider a 1D flow with velocity $u$ in the $x$-direction. The Euler equations for a fluid with density $\\rho$ and pressure $p$ are:\n", "\n", "$$\n", "\\begin{align}\n", "\\frac{\\partial \\rho}{\\partial t} + \\frac{\\partial}{\\partial x}(\\rho u) &= 0 \\\\\n", "\\frac{\\partial}{\\partial t}(\\rho u) + \\frac{\\partial}{\\partial x} (\\rho u^2 + p)&=0\n", "\\end{align}\n", "$$\n", "\n", "... plus the energy equation, which we can write in this form:\n", "\n", "$$\n", "\\begin{equation}\n", "\\frac{\\partial}{\\partial t}(\\rho e_T) + \\frac{\\partial}{\\partial x} (\\rho u e_T +p u)=0\n", "\\end{equation}\n", "$$\n", "\n", "where $e_T=e+u^2/2$ is the total energy per unit mass, equal to the internal energy plus the kinetic energy (per unit mass).\n", "\n", "Written in vector form, you can see that the Euler equations bear a strong resemblance to the traffic-density equation that has been the focus of this course module so far. Here is the vector representation of the Euler equation:\n", "\n", "$$\n", "\\begin{equation}\n", "\\frac{\\partial }{\\partial t} \\underline{\\mathbf{u}} + \\frac{\\partial }{\\partial x} \\underline{\\mathbf{f}} = 0\n", "\\end{equation}\n", "$$\n", "\n", "The big difference with our previous work is that the variables $\\underline{\\mathbf{u}}$ and $\\underline{\\mathbf{f}}$ are *vectors*. If you review the [Phugoid Full Model](https://nbviewer.jupyter.org/github/numerical-mooc/numerical-mooc/blob/master/lessons/01_phugoid/01_03_PhugoidFullModel.ipynb) lesson, you will recall that we can solve for several values at once using the vector form of an equation. In the Phugoid Module, it was an ODE—now we apply the same procedure to a PDE. \n", "\n", "Let's take a look at what $\\underline{\\mathbf{u}}$ and $\\underline{\\mathbf{f}}$ consist of." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The conservative form" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Many works in the early days of computational fluid dynamics in the 1960s showed that using the conservation form of the Euler equations is more accurate for situations with shock waves. And as you already saw, the shock-tube solutions do contain shocks.\n", "\n", "The conserved variables $\\underline{\\mathbf{u}}$ for Euler's equations are\n", "\n", "$$\n", "\\begin{equation}\n", "\\underline{\\mathbf{u}} = \\left[\n", "\\begin{array}{c}\n", "\\rho \\\\\n", "\\rho u \\\\\n", "\\rho e_T \\\\ \n", "\\end{array}\n", "\\right]\n", "\\end{equation}\n", "$$\n", "\n", "where $\\rho$ is the density of the fluid, $u$ is the velocity of the fluid and $e_T = e + \\frac{u^2}{2}$ is the specific total energy; $\\underline{\\mathbf{f}}$ is the flux vector:\n", "\n", "$$\n", "\\begin{equation}\n", "\\underline{\\mathbf{f}} = \\left[\n", "\\begin{array}{c}\n", "\\rho u \\\\\n", "\\rho u^2 + p \\\\\n", "(\\rho e_T + p) u \\\\\n", "\\end{array}\n", "\\right]\n", "\\end{equation}\n", "$$\n", "\n", "where $p$ is the pressure of the fluid.\n", "\n", "If we put together the conserved variables and the flux vector into our PDE, we get the following set of equations:\n", "\n", "$$\n", "\\begin{equation}\n", " \\frac{\\partial}{\\partial t}\n", " \\left[\n", " \\begin{array}{c}\n", " \\rho \\\\\n", " \\rho u \\\\\n", " \\rho e_T \\\\\n", " \\end{array}\n", " \\right] +\n", " \\frac{\\partial}{\\partial x}\n", " \\left[\n", " \\begin{array}{c}\n", " \\rho u \\\\\n", " \\rho u^2 + p \\\\\n", " (\\rho e_T + p) u \\\\\n", " \\end{array}\n", " \\right] =\n", " 0\n", "\\end{equation}\n", "$$\n", "\n", "There's one major problem there. We have 3 equations and 4 unknowns. But there is a solution! We can use an equation of state to calculate the pressure—in this case, we'll use the ideal gas law." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Calculating the pressure" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For an ideal gas, the equation of state is\n", "\n", "$$\n", "e = e(\\rho, p) = \\frac{p}{(\\gamma -1) \\rho}\n", "$$\n", "\n", "where $\\gamma = 1.4$ is a reasonable value to model air, \n", "\n", "$$\n", "\\therefore p = (\\gamma -1)\\rho e\n", "$$ \n", "\n", "Recall from above that\n", "\n", "$$\n", "e_T = e+\\frac{1}{2} u^2\n", "$$\n", "\n", "$$\n", "\\therefore e = e_T - \\frac{1}{2}u^2\n", "$$\n", "\n", "Putting it all together, we arrive at an equation for the pressure\n", "\n", "$$\n", "p = (\\gamma -1)\\left(\\rho e_T - \\frac{\\rho u^2}{2}\\right)\n", "$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Flux in terms of $\\underline{\\mathbf{u}}$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With the traffic model, the flux was a function of traffic density. For the Euler equations, the three equations we have are coupled and the flux *vector* is a function of $\\underline{\\mathbf{u}}$, the vector of conserved variables:\n", "\n", "$$\n", "\\underline{\\mathbf{f}} = f(\\underline{\\mathbf{u}})\n", "$$\n", "\n", "In order to get everything squared away, we need to represent $\\underline{\\mathbf{f}}$ in terms of $\\underline{\\mathbf{u}}$.\n", "We can introduce a little shorthand for the $\\underline{\\mathbf{u}}$ and $\\underline{\\mathbf{f}}$ vectors and define:\n", "\n", "$$\n", "\\underline{\\mathbf{u}} =\n", "\\left[\n", " \\begin{array}{c}\n", " u_1 \\\\\n", " u_2 \\\\\n", " u_3 \\\\\n", " \\end{array}\n", "\\right] =\n", "\\left[\n", " \\begin{array}{c}\n", " \\rho \\\\\n", " \\rho u \\\\\n", " \\rho e_T \\\\\n", " \\end{array}\n", "\\right]\n", "$$\n", "\n", "$$\n", "\\underline{\\mathbf{f}} =\n", "\\left[\n", " \\begin{array}{c}\n", " f_1 \\\\\n", " f_2 \\\\\n", " f_3 \\\\\n", " \\end{array}\n", "\\right] =\n", "\\left[\n", " \\begin{array}{c}\n", " \\rho u \\\\\n", " \\rho u^2 + p \\\\\n", " (\\rho e_T + p) u \\\\\n", " \\end{array}\n", "\\right]\n", "$$ \n", "\n", "With a little algebraic trickery, we can represent the pressure vector using quantities from the $\\underline{\\mathbf{u}}$ vector.\n", "\n", "$$\n", "p = (\\gamma -1)\\left(u_3 - \\frac{1}{2} \\frac{u^2_2}{u_1} \\right)\n", "$$\n", "\n", "Now that pressure can be represented in terms of $\\underline{\\mathbf{u}}$, the rest of $\\underline{\\mathbf{f}}$ isn't too difficult to resolve:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$$\\underline{\\mathbf{f}} = \\left[ \\begin{array}{c}\n", "f_1 \\\\\n", "f_2 \\\\\n", "f_3 \\\\ \\end{array} \\right] =\n", "\\left[ \\begin{array}{c}\n", "u_2\\\\\n", "\\frac{u^2_2}{u_1} + (\\gamma -1)\\left(u_3 - \\frac{1}{2} \\frac{u^2_2}{u_1} \\right) \\\\\n", "\\left(u_3 + (\\gamma -1)\\left(u_3 - \\frac{1}{2} \\frac{u^2_2}{u_1}\\right) \\right) \\frac{u_2}{u_1}\\\\ \\end{array}\n", "\\right]$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Test conditions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The first test proposed by Sod in his 1978 paper is as follows. \n", "\n", "In a tube spanning from $x = -10 \\text{m}$ to $x = 10 \\text{m}$ with the rigid membrane at $x = 0 \\text{m}$, we have the following initial gas states:\n", "\n", "$$\n", "\\underline{IC}_L =\n", "\\left[\n", " \\begin{array}{c}\n", " \\rho_L \\\\\n", " u_L \\\\\n", " p_L \\\\\n", " \\end{array}\n", "\\right] =\n", "\\left[\n", " \\begin{array}{c}\n", " 1.0 \\, kg/m^3 \\\\\n", " 0 \\, m/s \\\\\n", " 100 \\, kN/m^2 \\\\\n", " \\end{array}\n", "\\right]\n", "$$\n", "\n", "$$\n", "\\underline{IC}_R =\n", "\\left[\n", " \\begin{array}{c}\n", " \\rho_R \\\\\n", " u_R \\\\\n", " p_R \\\\\n", " \\end{array}\n", "\\right] =\n", "\\left[\n", " \\begin{array}{c}\n", " 0.125 \\, kg/m^3 \\\\\n", " 0 \\, m/s \\\\\n", " 10 \\, kN/m^2 \\\\\n", " \\end{array}\n", "\\right]\n", "$$\n", "\n", "where $\\underline{IC}_L$ are the initial density, velocity and pressure on the left side of the tube membrane and $\\underline{IC}_R$ are the initial density, velocity and pressure on the right side of the tube membrane. \n", "\n", "The analytical solution to this test for the velocity, pressure and density, looks like the plots in Figure 2." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![shock_analytic](./figures/shock_tube_.01.png)\n", ". \n", "\n", "#### Figure 2. Analytical solution for Sod's first test." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The Richtmyer method" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For this exercise, you will be using a new scheme called the Richtmyer method. Like the MacCormack method that we learned in [lesson 2](https://nbviewer.jupyter.org/github/numerical-mooc/numerical-mooc/blob/master/lessons/03_wave/03_02_convectionSchemes.ipynb), Richtmyer is a *two-step method*, given by:\n", "\n", "$$\n", "\\begin{align}\n", "\\underline{\\mathbf{u}}^{n+\\frac{1}{2}}_{i+\\frac{1}{2}} &= \\frac{1}{2} \\left( \\underline{\\mathbf{u}}^n_{i+1} + \\underline{\\mathbf{u}}^n_i \\right) - \n", "\\frac{\\Delta t}{2 \\Delta x} \\left( \\underline{\\mathbf{f}}^n_{i+1} - \\underline{\\mathbf{f}}^n_i\\right) \\\\\n", "\\underline{\\mathbf{u}}^{n+1}_i &= \\underline{\\mathbf{u}}^n_i - \\frac{\\Delta t}{\\Delta x} \\left(\\underline{\\mathbf{f}}^{n+\\frac{1}{2}}_{i+\\frac{1}{2}} - \\underline{\\mathbf{f}}^{n+\\frac{1}{2}}_{i-\\frac{1}{2}} \\right)\n", "\\end{align}\n", "$$\n", "\n", "The flux vectors used in the second step are obtained by evaluating the flux functions on the output of the first step:\n", "\n", "$$\n", "\\underline{\\mathbf{f}}^{n+\\frac{1}{2}}_{i+\\frac{1}{2}} = \\underline{\\mathbf{f}}\\left(\\underline{\\mathbf{u}}^{n+\\frac{1}{2}}_{i+\\frac{1}{2}}\\right)\n", "$$\n", "\n", "The first step is like a *predictor* of the solution: if you look closely, you'll see that we are applying a Lax-Friedrichs scheme here. The second step is a *corrector* that applies a leapfrog update. Figure 3 gives a sketch of the stencil for Richtmyer method, where the \"intermediate time\" $n+1/2$ will require a temporary variable in your code, just like we had in the MacCormack scheme." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![richtmyer](./figures/richtmyer.png)\n", "\n", "\n", "#### Figure 3. Stencil of Richtmyer scheme." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Coding assignment" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Your mission, should you wish to accept it, is to calculate the pressure, density and velocity across the shock tube at time $t = 0.01 s$ using the Richtmyer method. Good luck!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Reference" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Sod, Gary A. (1978), \"A survey of several finite difference methods for systems of nonlinear hyperbolic conservation laws,\" *J. Comput. Phys.*, Vol. 27, pp. 1–31 DOI: [10.1016/0021-9991(78)90023-2](http://dx.doi.org/10.1016%2F0021-9991%2878%2990023-2) // [PDF from unicamp.br](http://www.fem.unicamp.br/~phoenics/EM974/TG%20PHOENICS/BRUNO%20GALETTI%20TG%202013/a%20survey%20of%20several%20finite%20difference%20methods%20for%20systems%20of%20nonlinear%20hyperbolic%20conservation%20laws%20Sod%201978.pdf), checked Oct. 28, 2014." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "###### The cell below loads the style of the notebook." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.core.display import HTML\n", "css_file = '../../styles/numericalmoocstyle.css'\n", "HTML(open(css_file, 'r').read())" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (MOOC)", "language": "python", "name": "py36-mooc" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.5" } }, "nbformat": 4, "nbformat_minor": 1 }