{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Approximate solvers for the Euler equations of gas dynamics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this chapter we discuss approximate solvers for the one-dimensional Euler equations:\n", "\n", "\\begin{align}\n", " \\rho_t + (\\rho u)_x & = 0 \\\\\n", " (\\rho u)_t + (\\rho u^2 + p)_x & = 0 \\\\\n", " E_t + ((E+p)u)_x & = 0.\n", "\\end{align}\n", "\n", "As in [Euler](Euler.ipynb), we focus on the case of an ideal gas, for which the total energy is given by\n", "\n", "\\begin{align} \\label{EA:EOS}\n", " E = \\frac{p}{\\gamma-1} + \\frac{1}{2}\\rho u^2.\n", "\\end{align}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To examine the Python code for this chapter, and for the exact Riemann solution, see:\n", "\n", " - [exact_solvers/euler.py](exact_solvers/euler.py) ...\n", " [on github.](https://github.com/clawpack/riemann_book/blob/FA16/exact_solvers/euler.py)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Roe solver" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We first derive a Roe solver for the Euler equations, following the same approach as in [Shallow_water_approximate](Shallow_water_approximate.ipynb). Namely, we assume that $\\hat{A} = f'(\\hat{q})$ for some average state $\\hat{q}$, and impose the condition of conservation:\n", "\n", "\\begin{align} \\label{EA:cons}\n", " f'(\\hat{q}) (q_r - q_\\ell) & = f(q_r) - f(q_\\ell).\n", "\\end{align}\n", "\n", "We will need the following quantities:\n", "\n", "\\begin{align}\n", "q & = \\begin{pmatrix} \\rho \\\\ \\rho u \\\\ E \\end{pmatrix}, \\ \\ \\ \\ \\ \\ f(q) = \\begin{pmatrix} \\rho u \\\\ \\rho u^2 + p \\\\ H u \\rho \\end{pmatrix}, \\\\\n", "f'(\\hat{q}) & = \\begin{pmatrix} \n", " 0 & 1 & 0 \\\\ \n", " \\frac{\\gamma-3}{2}\\hat{u}^2 & (3-\\gamma)\\hat{u} & \\gamma-1 \\\\\n", " \\frac{\\gamma-1}{2}\\hat{u}^3 - \\hat{u}\\hat{H} & \\hat{H} - (\\gamma-1)\\hat{u}^2 & \\gamma \\hat{u} \\end{pmatrix}.\n", "\\end{align}\n", "\n", "Here $H = \\frac{E+p}{\\rho}$ is the enthalpy. We have rewritten most expressions involving $E$ in terms of $H$ because it simplifies the derivation that follows. We now solve (\\ref{EA:cons}) to find $\\hat{u}$ and $\\hat{H}$. It turns out that, for the case of a polytropic ideal gas, the average density $\\hat{\\rho}$ plays no role in the Roe solver.\n", "\n", "The first equation of (\\ref{EA:cons}) is an identity, satisfied independently of our choice of $\\hat{q}$. The second equation is (using (\\ref{EA:EOS}))\n", "\n", "\\begin{align}\n", " \\frac{\\gamma-3}{2}\\hat{u}^2 (\\rho_r - \\rho_\\ell) + (3-\\gamma)\\hat{u}(\\rho_r u_r - \\rho_\\ell u_\\ell) \\\\ + (\\gamma-1)\\left( \\frac{p_r-p_\\ell}{\\gamma-1} + \\frac{1}{2}(\\rho_r u_r^2 - \\rho_\\ell u_\\ell^2) \\right) & = \\rho_r u_r^2 - \\rho_\\ell u_\\ell^2 + p_r - p_\\ell,\n", "\\end{align}\n", "\n", "which simplifies to a quadratic equation for $\\hat{u}$:\n", "\n", "\\begin{align} \\label{EA:u_quadratic}\n", " (\\rho_r - \\rho_\\ell)\\hat{u}^2 - 2(\\rho_r u_r - \\rho_\\ell u_\\ell) \\hat{u} + (\\rho_r u_r^2 - \\rho_\\ell u_\\ell^2) & = 0,\n", "\\end{align}\n", "\n", "with roots\n", "\n", "\\begin{align}\n", " \\hat{u}_\\pm & = \\frac{\\rho_r u_r - \\rho_\\ell u_\\ell \\mp \\sqrt{\\rho_r \\rho_\\ell} (u_\\ell - u_r)}{\\rho_r - \\rho_\\ell} = \\frac{\\sqrt{\\rho_r} u_r \\pm \\sqrt{\\rho_\\ell} u_\\ell}{\\sqrt{\\rho_r}\\pm\\sqrt{\\rho_\\ell}}\n", "\\end{align}\n", "\n", "Notice that this is identical to the Roe average of the velocity for the shallow water equations, if we replace the density $\\rho$ with depth $h$. As before, we choose the root $u_+$ since it is well defined for all values of $\\rho_r, \\rho_\\ell$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next we find $\\hat{H}$ by solving the last equation of (\\ref{EA:cons}), which reads \n", "\\begin{align}\n", " \\left( \\frac{\\gamma-1}{2}\\hat{u}^3 - \\hat{u}\\hat{H} \\right)(\\rho_r - \\rho_\\ell) \\\\ + \\left( \\hat{H} - (\\gamma-1)\\hat{u}^2 \\right)(\\rho_r u_r - \\rho_\\ell u_\\ell) + \\gamma \\hat{u}(E_r - E_\\ell) & = H_r u_r \\rho_r - H_\\ell u_\\ell \\rho_\\ell.\n", "\\end{align} \n", "We can simplify this using the equality $\\gamma E = \\rho H + \\frac{\\gamma-1}{2}\\rho u^2$ and solve for $\\hat{H}$ to find \n", "\\begin{align}\n", " \\hat{H}_{\\pm} & = \\frac{\\rho_r H_r (u_r - \\hat{u}_+) - \\rho_\\ell H_\\ell (u_\\ell - \\hat{u}_+)}{\\rho_r u_r - \\rho_\\ell u_\\ell - \\hat{u}_\\pm(\\rho_r -\\rho_\\ell)} \\\\\n", " & = \\frac{\\rho_r H_r (u_r - \\hat{u}_+) - \\rho_\\ell H_\\ell (u_\\ell - \\hat{u}_+)}{\\pm\\sqrt{\\rho_r \\rho_\\ell}(u_r-u_\\ell)} \\\\\n", " & = \\frac{\\rho_r H_r - \\rho_\\ell H_\\ell \\mp\\sqrt{\\rho_r \\rho_\\ell}(H_r - H_\\ell)}{\\rho_r - \\rho_\\ell} \\\\\n", " & = \\frac{\\sqrt{\\rho_r}H_r \\pm \\sqrt{\\rho_\\ell} H_\\ell}{\\sqrt{\\rho_r}\\pm\\sqrt{\\rho_\\ell}}.\n", "\\end{align} \n", "Once more, we take the plus sign in the final expression for $\\hat{H}$, giving the Roe averages\n", "$$\n", "\\hat{u} = \\frac{\\sqrt{\\rho_r} u_r + \\sqrt{\\rho_\\ell} u_\\ell}{\\sqrt{\\rho_r} + \\sqrt{\\rho_\\ell}},\n", "\\qquad \\hat{H} = \\frac{\\sqrt{\\rho_r}H_r + \\sqrt{\\rho_\\ell} H_\\ell}{\\sqrt{\\rho_r} + \\sqrt{\\rho_\\ell}}.\n", "$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To implement the Roe solver, we also need the eigenvalues and eigenvectors of the averaged flux Jacobian $f'(\\hat{q})$. These are just the eigenvalues of the true Jacobian, evaluated at the averaged state:\n", "\\begin{align}\n", " \\lambda_1 & = \\hat{u} - \\hat{c}, & \\lambda_2 & = \\hat{u} & \\lambda_3 & = \\hat{u} + \\hat{c},\n", "\\end{align} \n", "\\begin{align}\n", "r_1 & = \\begin{bmatrix} 1 \\\\ \\hat{u}-\\hat{c} \\\\ \\hat{H}-\\hat{u}\\hat{c}\\end{bmatrix} &\n", "r_2 & = \\begin{bmatrix} 1 \\\\ \\hat{u} \\\\ \\frac{1}{2}\\hat{u}^2 \\end{bmatrix} &\n", "r_3 & = \\begin{bmatrix} 1 \\\\ \\hat{u}+\\hat{c} \\\\ \\hat{H}+\\hat{u}\\hat{c}\\end{bmatrix}.\n", "\\end{align}\n", "Here $\\hat{c} = \\sqrt{(\\gamma-1)(\\hat{H}-\\hat{u}^2/2)}$.\n", "\n", "Solving the system of equations\n", "\\begin{align}\n", "q_r - q_\\ell & = \\sum_{p=1}^3 {\\mathcal W}_p = \\sum_{p=1}^3 \\alpha_p r_p\n", "\\end{align} \n", "for the wave strengths gives\n", "\\begin{align}\n", " \\alpha_2 & = \\delta_1 + (\\gamma-1)\\frac{\\hat{u}\\delta_2 - \\delta_3}{\\hat{c}^2} \\\\\n", " \\alpha_3 & = \\frac{\\delta_2 + (\\hat{c}-\\hat{u})\\delta_1 - \\hat{c}\\alpha_2}{2\\hat{c}} \\\\\n", " \\alpha_1 & = \\delta_1 - \\alpha_2 - \\alpha_3,\n", "\\end{align} \n", "where $\\delta = q_r - q_\\ell$. We now have everything we need to implement the Roe solver." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "hide" ] }, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "hide" ] }, "outputs": [], "source": [ "%config InlineBackend.figure_format = 'svg'\n", "import numpy as np\n", "from exact_solvers import euler\n", "from utils import riemann_tools as rt\n", "from ipywidgets import interact\n", "from ipywidgets import widgets\n", "State = euler.Primitive_State" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def roe_averages(q_l, q_r, gamma=1.4):\n", " rho_sqrt_l = np.sqrt(q_l[0])\n", " rho_sqrt_r = np.sqrt(q_r[0])\n", " p_l = (gamma-1.)*(q_l[2]-0.5*(q_l[1]**2)/q_l[0])\n", " p_r = (gamma-1.)*(q_r[2]-0.5*(q_r[1]**2)/q_r[0])\n", " denom = rho_sqrt_l + rho_sqrt_r\n", " u_hat = (q_l[1]/rho_sqrt_l + q_r[1]/rho_sqrt_r)/denom\n", " H_hat = ((q_l[2]+p_l)/rho_sqrt_l + (q_r[2]+p_r)/rho_sqrt_r)/denom\n", " c_hat = np.sqrt((gamma-1)*(H_hat-0.5*u_hat**2))\n", " \n", " return u_hat, c_hat, H_hat\n", " \n", " \n", "def Euler_roe(q_l, q_r, gamma=1.4):\n", " \"\"\"\n", " Approximate Roe solver for the Euler equations.\n", " \"\"\"\n", " \n", " rho_l = q_l[0]\n", " rhou_l = q_l[1]\n", " u_l = rhou_l/rho_l\n", " rho_r = q_r[0]\n", " rhou_r = q_r[1]\n", " u_r = rhou_r/rho_r\n", " \n", " u_hat, c_hat, H_hat = roe_averages(q_l, q_r, gamma)\n", " \n", " dq = q_r - q_l\n", " \n", " s1 = u_hat - c_hat\n", " s2 = u_hat\n", " s3 = u_hat + c_hat\n", " \n", " alpha2 = (gamma-1.)/c_hat**2 *((H_hat-u_hat**2)*dq[0]+u_hat*dq[1]-dq[2])\n", " alpha3 = (dq[1] + (c_hat - u_hat)*dq[0] - c_hat*alpha2) / (2.*c_hat)\n", " alpha1 = dq[0] - alpha2 - alpha3\n", " \n", " r1 = np.array([1., u_hat-c_hat, H_hat - u_hat*c_hat])\n", " r2 = np.array([1., u_hat, 0.5*u_hat**2])\n", " q_l_star = q_l + alpha1*r1\n", " q_r_star = q_l_star + alpha2*r2\n", " \n", " states = np.column_stack([q_l,q_l_star,q_r_star,q_r])\n", " speeds = [s1, s2, s3]\n", " wave_types = ['contact','contact', 'contact']\n", " \n", " def reval(xi):\n", " rho = (xi