From 3d385049676edd22b6b30dca99674a586e3f5e5a Mon Sep 17 00:00:00 2001 From: Randy LeVeque Date: Sun, 23 Apr 2017 19:16:32 -0400 Subject: [PATCH 01/12] separated out code to compute trajectories and use to plot red/blue stripes. Illustrated in Euler_equations.ipynb where density is colored red to left and blue to right of contact discontinuity. --- Acoustics.ipynb | 181 +++++++++------------------- Euler_equations.ipynb | 264 +++++++++++++++++++++++++++-------------- utils/riemann_tools.py | 91 +++++++++----- 3 files changed, 289 insertions(+), 247 deletions(-) diff --git a/Acoustics.ipynb b/Acoustics.ipynb index 64565e5f..2098b14a 100644 --- a/Acoustics.ipynb +++ b/Acoustics.ipynb @@ -2,10 +2,7 @@ "cells": [ { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "\n", "# Riemann problem for acoustics\n", @@ -16,11 +13,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", @@ -30,10 +23,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "The next cell imports a module containing a function that takes a Riemann problem (left state, right state, and approximate solver), and computes the Riemann solution, as well as functions to plot the solution in various forms. " ] @@ -41,11 +31,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "from utils import riemann_tools" @@ -54,11 +40,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "from utils import animation_tools\n", @@ -69,10 +51,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "# Acoustics: exact solution\n", "We can use this to examine the exact solution of an acoustics Riemann problem.\n", @@ -96,11 +75,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "from clawpack.riemann.acoustics_1D_py import acoustics_1D\n", @@ -109,10 +84,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### Set some problem data needed by the solver:" ] @@ -120,11 +92,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "problem_data = {}\n", @@ -143,10 +111,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### Set the left and right states, and solve the Riemann problem" ] @@ -154,11 +119,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "q_l = np.array((1,4)) # Left state\n", @@ -170,10 +131,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### Plot the states in the phase plane:" ] @@ -181,11 +139,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "fig = plt.figure(figsize=(4,3))\n", @@ -195,10 +149,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### Plot the waves in the x-t plane, and the solution at one particular time:" ] @@ -206,11 +157,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "fig = riemann_tools.plot_riemann(states,s,riemann_eval,t=0.5)" @@ -218,10 +165,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### Animate the Riemann solution:" ] @@ -229,11 +173,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "riemann_tools.JSAnimate_plot_riemann(states,s,riemann_eval)" @@ -241,10 +181,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "## Shock tube problem:\n", "\n", @@ -254,11 +191,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "q_l = np.array((5,0)) # Left state\n", @@ -275,11 +208,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "riemann_tools.JSAnimate_plot_riemann(states,s,riemann_eval)" @@ -287,10 +216,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### Plot the particle trajectories\n", "\n", @@ -308,22 +234,26 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ - "riemann_tools.plot_riemann_trajectories(states,s,riemann_eval,i_vel=1)" + "wave_types = ['contact','contact'] # for a linear system of 2 equations\n", + "\n", + "# Specify number of trajectories to left and right:\n", + "num_left = 10\n", + "num_right = 10\n", + "\n", + "# compute trajectories:\n", + "x_traj, t_traj, xmax = riemann_tools.compute_riemann_trajectories(states, s, riemann_eval, wave_types,\n", + " i_vel=1, num_left=num_left, num_right=num_right)\n", + "\n", + "# plot trajectories along with waves in the x-t plane:\n", + "riemann_tools.plot_riemann_trajectories(x_traj, t_traj, s, wave_types)" ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "## Flow into a wall:\n", "\n", @@ -333,11 +263,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "q_l = np.array((3,2)) # Left state\n", @@ -354,35 +280,36 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "riemann_tools.JSAnimate_plot_riemann(states,s,riemann_eval)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Again we can plot particle trajectories:" + ] + }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ - "riemann_tools.plot_riemann_trajectories(states,s,riemann_eval,i_vel=1)" + "# compute trajectories:\n", + "x_traj, t_traj, xmax = riemann_tools.compute_riemann_trajectories(states, s, riemann_eval, wave_types,\n", + " i_vel=1, num_left=num_left, num_right=num_right)\n", + "\n", + "# plot trajectories along with waves in the x-t plane:\n", + "riemann_tools.plot_riemann_trajectories(x_traj, t_traj, s, wave_types)" ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "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.\n", "\n", @@ -406,9 +333,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", - "version": "2.7.13" + "version": "2.7.12" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/Euler_equations.ipynb b/Euler_equations.ipynb index a000808e..1f237760 100644 --- a/Euler_equations.ipynb +++ b/Euler_equations.ipynb @@ -17,7 +17,10 @@ "- [The Euler equations](#The-Euler-equations)\n", "- [Hyperbolic structure](#Hyperbolic-structure-of-the-Euler-equations)\n", "- [Exact solution of the Riemann problem](#Exact-solution-of-the-Riemann-problem)\n", - "- [Interactive Riemann solver](#Interactive-Riemann-solver)" + "- [Plot particle trajectories](#Plot-particle-trajectories)\n", + "- [Plot Riemann solution with advected colors](#Plot-Riemann-solution-with-advected-colors)\n", + "- [Interactive Riemann solver](#Interactive-Riemann-solver)\n", + "- [Riemann problems with vacuum](#Riemann-problems-with-vacuum)" ] }, { @@ -230,7 +233,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "%matplotlib inline\n", @@ -250,9 +255,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "from ipywidgets import interact # for interactive widgets\n", @@ -262,9 +265,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "def plot_integral_curves(plot_1=True,plot_3=False,gamma=1.4,rho_0=1.):\n", @@ -316,9 +317,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "def plot_hugoniot_loci(plot_1=True,plot_3=False,gamma=1.4,rho_0=1.):\n", @@ -374,7 +373,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "#%load exact_solvers/Euler.py" @@ -399,7 +400,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "def riemann_solution(left_state, right_state):\n", @@ -421,9 +424,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "left_state = Primitive_State(Density = 3.,\n", @@ -446,9 +447,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "Euler.phase_plane_plot(left_state, right_state)" @@ -466,9 +465,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "left_state = Primitive_State(Density = 1.,\n", @@ -485,7 +482,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": false, "scrolled": false }, "outputs": [], @@ -505,9 +501,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "left_state = Primitive_State(Density = 1.,\n", @@ -523,29 +517,106 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "Euler.phase_plane_plot(left_state, right_state)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot particle trajectories\n", + "\n", + "In the next plot of the Riemann solution in the $x$-$t$ plane, we also plot the trajectories of a set of particles initially distributed along the $x$ axis at $t=0$, with the spacing inversely proportional to the density. The evolution of the distance between particles gives an indication of how the density changes." + ] + }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "def plot_exact_riemann_solution(rho_l=3.,u_l=0.,p_l=3.,rho_r=1.,u_r=0.,p_r=1.,t=0.4): \n", + "left_state = Primitive_State(Density = 3.,\n", + " Velocity = 0.,\n", + " Pressure = 3.)\n", + "right_state = Primitive_State(Density = 1.,\n", + " Velocity = 0.,\n", + " Pressure = 1.)\n", + "\n", + "q_left = Euler.primitive_to_conservative(*left_state)\n", + "q_right = Euler.primitive_to_conservative(*right_state)\n", + "\n", + "ex_states, ex_speeds, reval, wave_types = Euler.exact_riemann_solution(q_left ,q_right, gamma)\n", + "\n", + "def reval_rho_u(x): \n", + " q = reval(x)\n", + " rho = q[0]\n", + " u = q[1]/q[0]\n", + " rho_u = np.vstack((rho,u))\n", + " return rho_u\n", + "\n", + "# Specify density of trajectories to left and right:\n", + "rho_l = q_left[0] / 10.\n", + "rho_r = q_right[0] / 10.\n", + "x_traj, t_traj, xmax = riemann_tools.compute_riemann_trajectories(ex_states, ex_speeds, reval_rho_u, wave_types,\n", + " i_vel=1, rho_left=rho_l, rho_right=rho_r)\n", + "riemann_tools.plot_riemann_trajectories(x_traj, t_traj, ex_speeds, wave_types)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Recall that the evolution of the distance between particles gives an indication of how the density changes. Note that it increases across the shock wave and decreases through the rarefaction wave, and that in general there is a jump in density across the contact discontinuity." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Riemann solution with advected colors\n", + "\n", + "The next cell defines a function to plot the Riemann solution with the density plot also showing an advected color to help visualize the flow better. The fluid to the left of $x=0$ initially is colored red and to the right of $x=0$ is colored blue, with stripes of different shades of these colors to help visualize the motion of the fluids." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def plot_exact_riemann_solution_stripes(rho_l=3.,u_l=0.,p_l=3.,rho_r=1.,u_r=0.,p_r=1.,t=0.4): \n", " q_l = Euler.primitive_to_conservative(rho_l,u_l,p_l)\n", " q_r = Euler.primitive_to_conservative(rho_r,u_r,p_r)\n", " \n", + " from matplotlib.mlab import find\n", + " \n", " x = np.linspace(-1.,1.,1000)\n", " states, speeds, reval, wave_types = Euler.exact_riemann_solution(q_l, q_r, gamma=gamma)\n", " q = reval(x/t)\n", " primitive = Euler.conservative_to_primitive(q[0],q[1],q[2])\n", " \n", + " # compute particle trajectories:\n", + " def reval_rho_u(x): \n", + " q = reval(x)\n", + " rho = q[0]\n", + " u = q[1]/q[0]\n", + " rho_u = np.vstack((rho,u))\n", + " return rho_u\n", + " \n", + " # Specify density of trajectories to left and right:\n", + " num_left = 10\n", + " num_right = 10\n", + " rho_left = q_l[0] / 10.\n", + " rho_right = q_r[0] / 10.\n", + " x_traj, t_traj, xmax = riemann_tools.compute_riemann_trajectories(states, speeds, reval_rho_u, wave_types,\n", + " i_vel=1, xmax=1, rho_left=rho_left, rho_right=rho_right)\n", + " \n", " fig = plt.figure(figsize=(18,6))\n", " names = ['Density','Velocity','Pressure']\n", " axes = [0]*3\n", @@ -558,82 +629,101 @@ " qmin = min(q)\n", " qdiff = qmax - qmin\n", " axes[i].set_ylim((qmin-0.1*qdiff,qmax+0.1*qdiff))\n", - " plt.show()" + " axes[i].set_xlim(-xmax,xmax)\n", + " \n", + " if i==0:\n", + " # plot stripes only on density plot\n", + " n = find(t > t_traj)\n", + " if len(n)==0:\n", + " n = 0\n", + " else:\n", + " n = min(n.max(), len(t_traj)-1)\n", + "\n", + " for i in range(1, x_traj.shape[1]-1):\n", + " j1 = find(x_traj[n,i] > x)\n", + " if len(j1)==0:\n", + " j1 = 0\n", + " else:\n", + " j1 = min(j1.max(), len(x)-1)\n", + " j2 = find(x_traj[n,i+1] > x)\n", + " if len(j2)==0:\n", + " j2 = 0\n", + " else:\n", + " j2 = min(j2.max(), len(x)-1)\n", + "\n", + " # set advected color for density plot:\n", + " if x_traj[0,i]<0: \n", + " # shades of red for fluid starting from x<0\n", + " if np.mod(i,2)==0:\n", + " c = [1,0,0]\n", + " else:\n", + " c = [1,0.8,0.8]\n", + " else:\n", + " # shades of blue for fluid starting from x<0\n", + " if np.mod(i,2)==0:\n", + " c = [0,0,1]\n", + " else:\n", + " c = [0.8,0.8,1]\n", + " plt.fill_between(x[j1:j2],q[j1:j2],0,color=c)\n", + " plt.show()\n", + " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Interactive Riemann solver\n", - "\n", - "Here you can set up your own Riemann problem and immediately see the solution. If you don't want to download and run the notebook, an online interactive version is [here](http://sagecell.sagemath.org/?z=eJytWNtu47YWfQ-Qf2BnHiLJsmzFGeAgqIsCnfaxOCgGpw-DwJAtOiaOLgwviTJf30VSlKjYSgdog8FEIdfeXPvKLbGat0KRRtf8lRSSNPz6irm1ulC8alXF9hl_NU9mn1fq-uoo2prIA-OvWcsVq9k3Snqho2yrZ3p9dX1V0iOhXXFQO8FoXTTNDltasbaJnnZV-rQTabf9vW1oqtyvx6Kui22e3cX311cEPx8-fPiDKi0aok7U6SJeB1GtXf3D6SZctPuK1uSFqRNhDVOsqIhUhaKSmOPwn8icWvx8geSgiUlyaGuuFS1JoQjsoQS2NiXhLWuUJB2JXk5UUDzUxSvZU1KQ_LP3mRDFazyqnpzBGqglz_SgWiEBpZbzoW0kFc847kkXjQJXkNwDaDZbrSDjwF_FqU11yh-ywSHuAeu7imyNZV_XD25NDyv5wyrc-HXYuO1XRiXC7ohAiV-xSkSgxG8YJW7tI_nF-Y1U9Og8JtjjSTm_IyRUSo3_HJpbGpGN8jLP4iQyxJZknX1KrD0JLEiS29jDxRlcBHABuHDw72IjW40VySkte0IHS6jhmXwSyh2UgOTKkok9RlzACIsRcejNouKnYsJ4Fd1mif2rB-6pGhELixjAgRUnevg_ObaCHIpnBu7IUbfHjjbISxulBblNIpiwAMVQEfmRrO-HJEQQkMLk5pdBFSmpQj7S8gcEtUPuNY_ZzYgXruBMQYbWfSSf6ZE1Ln-hkT4K1NdBI4uldfVJP7YNQ4-o2gPr6fawnYXtcixtSVXU-7IgnNxbW4wVMGIVxjnPlhFfIRJxkkQX3RnHF0_YnJ9gMsacIC6eIP72BG_WDmZpCRtmLfA5cus0JKPamCQkivKls2kA5guTD4lbvXzcZt6c7ztOXDxOxPE0ti7l0OMQXWFDnC9fimdqWmNB5KnFLvJRoCcd0YSHhDQtnp_Yrop4fO8zaMwl5Cv_aQvz7n1avXUn5EY4rSQdkG-TZ0D-W5yF4XzOVcxx3Xw31ymy72YnNo2ld9vSczlvYzUry4r6ZpoSTfavBEVYomRd6dmThaSBeTxlzbFNCaMiJbV8xKnuSo5wUEoiRGNh8-I2S4-6qnbuvtl-EZqmnWorXMB0md_Fns1vcKJUosWZgS9lioZaU3NXyv4A0pjWSk604kO7AosftnnYjv4JPXN2K7brLA-YrgNff8Sli_Aj-LoqSYNudCo4p800zj2pIFGDRvlnIRr4994bVTKnCHf2MxWPNOyVoxgs8fHTMMkH168NvkTwpmEtaSPt_R_c6zts2btvaIJ5tnJtCaVtIcEFPkGLS2jxNhk_-nnHlo0tmvBefJHuyvtGRSujT_Eg9cXNLsrOYUbg3gtgKICMvmCtK0R7GY_ZMznOVp5tEiNPaFwbjdEwGKDxjc5JNHq1m4HC5XiiIDcKrCK3bEt2RBxGR7-53ldzGi0lx-XgYxAept2GlfSh760Tb6y7G6yzc0xvhphaN12ectn01t3NWSfes25Wo154yXO6buowE9EQ5POm1bfE56LSJqnHbt220szNdrreFxLDb9tczj-4rDNd3Mwg93i0JlSskbw40AhXXGr-rde-8oFXI14Bv87-k9RFF0Gu2Muoi-NV8OeLnN5_nbSuTBR4_mnIoOHbUUmeF47L6eHNAcVb0klmHwsv1pmO361U3xbM6BDMGomfHcwMh4eOxX6KW9hx0AptzoTcBBAd7MNFIcQ3H0vHjwc6XwKNeXk1Trpx3y2C2WFQsRnz06vo2FJvpirErApuOOCMxCjJ-5m6V9UjNhYhLGLTT9QTxNjlcAsYPt2P286UYexeGOC2qPupX-k3c7eZD3v5uHfrBV1peMTtiNj0CDFFbEbEnUNshr07L-JfoAxXMmWr57nqWaZ6jqCe46WnrLTnxC9x4vOc-CwnPseJz3HiU07cc-r7RB_c1PktdVSB8Algp7WqxTuyyRLAUjMJdX5yOzIzQfBKZXjCq2aEX5J9o9soX6d3Qy4KVuOSRWVvx1dqt9UUZoDB8s1nexO_3qQ3_6PmHcY-_rd_hb3p4UXn0OuHZNMzwHjE0AjQBJpHGm3CmdKgvzLTOkErK8pyJ_XeWBPl6SZlizxowE_GDs8TQsHIBOusUJc-pWiD9IWV6rTdxFMIXFTRyNoD8VAzWh-Umwb4NFkGaSyzZrpcsuPRvOkbqaVFnRmUSap2rxWro8jsLzGQJVYuNVKL4U_vf_u5CAMyxqKD9B-KcGHUv9mgOdD4twni0KBtOwCfPLszt8n11c925kW3HZNjN_OZydb6Vlbo0QIu_5SayRFCha4U_JfqcXf56c32Ok75u8K25uf2c6NcvK_8PWFAxs9g7vsNn7wlo6jefjcJv9PwyQtvAPZfTcIG-2T1f7W6UjKoTM3BDx4iPEQ4iFVkIGLyTenvb-uhjIF85_OgORKFnhI0BfdhMPySEtQE9A2LQ59Agadd_BeW1ABm&lang=python)." + "Make a plot with only a time slider to illustrate this viewpoint with the Sod shock tube data:" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ - "interact(plot_exact_riemann_solution,\n", - " rho_l=widgets.FloatSlider(min=1.,max=10.,step=0.1,value=3.,description=r'$\\rho_l$'),\n", - " u_l=widgets.FloatSlider(min=-10.,max=10.,step=0.1,value=0.,description=r'$u_l$'),\n", - " p_l=widgets.FloatSlider(min=1.,max=10.,step=0.1,value=3.,description=r'$p_l$'),\n", - " rho_r=widgets.FloatSlider(min=1.,max=10.,step=0.1,value=1.,description=r'$\\rho_r$'),\n", - " u_r=widgets.FloatSlider(min=-10.,max=10.,step=0.1,value=0.,description=r'$u_r$'),\n", - " p_r=widgets.FloatSlider(min=1.,max=10.,step=0.1,value=1.,description=r'$p_r$'),\n", - " t=widgets.FloatSlider(min=0.1,max=1.,step=0.1,value=0.1));" + "def plot_exact_riemann_solution_stripes_t_slider(t):\n", + " plot_exact_riemann_solution_stripes(rho_l=3.,u_l=0.,p_l=3.,rho_r=1.,u_r=0.,p_r=1.,t=t)\n", + " \n", + "interact(plot_exact_riemann_solution_stripes_t_slider, \n", + " t=widgets.FloatSlider(min=0.1,max=1.,step=0.1,value=0.5));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Plot particle trajectories" + "Note the following in the figure above:\n", + "\n", + " - The edges of each stripe are being advected with the fluid velocity, so you can visualize how the fluid is moving.\n", + " - The width of each stripe initially is inversely proportional to the density of the fluid, so that the total mass of gas within each stripe is the same.\n", + " - The total mass within each stripe remains constant as the flow evolves, and the width of each stripe remains inversely proportional to the local density.\n", + " - The interface between the red and blue gas moves with the contact discontinuity. The velocity and pressure are constant but the density can vary across this wave." ] }, { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], + "cell_type": "markdown", + "metadata": {}, "source": [ - "left_state = Primitive_State(Density = 3.,\n", - " Velocity = 0.,\n", - " Pressure = 3.)\n", - "right_state = Primitive_State(Density = 1.,\n", - " Velocity = 0.,\n", - " Pressure = 1.)\n", - "\n", - "q_left = Euler.primitive_to_conservative(*left_state)\n", - "q_right = Euler.primitive_to_conservative(*right_state)\n", - "\n", - "ex_states, ex_speeds, reval, wave_types = Euler.exact_riemann_solution(q_left ,q_right, gamma)\n", - "\n", - "def reval_rho_u(x): \n", - " q = reval(x)\n", - " rho = q[0]\n", - " u = q[1]/q[0]\n", - " rho_u = np.vstack((rho,u))\n", - " return rho_u\n", + "## Interactive Riemann solver\n", "\n", - "# Specify density of trajectories to left and right:\n", - "rho_l = q_left[0] / 5.\n", - "rho_r = q_right[0] / 5.\n", - "riemann_tools.plot_riemann_trajectories(ex_states,ex_speeds,reval_rho_u,wave_types,i_vel=1,\n", - " rho_left=rho_l, rho_right=rho_r)" + "Here you can set up your own Riemann problem and immediately see the solution. If you don't want to download and run the notebook, an online interactive version is [here](http://sagecell.sagemath.org/?z=eJytWNtu47YWfQ-Qf2BnHiLJsmzFGeAgqIsCnfaxOCgGpw-DwJAtOiaOLgwviTJf30VSlKjYSgdog8FEIdfeXPvKLbGat0KRRtf8lRSSNPz6irm1ulC8alXF9hl_NU9mn1fq-uoo2prIA-OvWcsVq9k3Snqho2yrZ3p9dX1V0iOhXXFQO8FoXTTNDltasbaJnnZV-rQTabf9vW1oqtyvx6Kui22e3cX311cEPx8-fPiDKi0aok7U6SJeB1GtXf3D6SZctPuK1uSFqRNhDVOsqIhUhaKSmOPwn8icWvx8geSgiUlyaGuuFS1JoQjsoQS2NiXhLWuUJB2JXk5UUDzUxSvZU1KQ_LP3mRDFazyqnpzBGqglz_SgWiEBpZbzoW0kFc847kkXjQJXkNwDaDZbrSDjwF_FqU11yh-ywSHuAeu7imyNZV_XD25NDyv5wyrc-HXYuO1XRiXC7ohAiV-xSkSgxG8YJW7tI_nF-Y1U9Og8JtjjSTm_IyRUSo3_HJpbGpGN8jLP4iQyxJZknX1KrD0JLEiS29jDxRlcBHABuHDw72IjW40VySkte0IHS6jhmXwSyh2UgOTKkok9RlzACIsRcejNouKnYsJ4Fd1mif2rB-6pGhELixjAgRUnevg_ObaCHIpnBu7IUbfHjjbISxulBblNIpiwAMVQEfmRrO-HJEQQkMLk5pdBFSmpQj7S8gcEtUPuNY_ZzYgXruBMQYbWfSSf6ZE1Ln-hkT4K1NdBI4uldfVJP7YNQ4-o2gPr6fawnYXtcixtSVXU-7IgnNxbW4wVMGIVxjnPlhFfIRJxkkQX3RnHF0_YnJ9gMsacIC6eIP72BG_WDmZpCRtmLfA5cus0JKPamCQkivKls2kA5guTD4lbvXzcZt6c7ztOXDxOxPE0ti7l0OMQXWFDnC9fimdqWmNB5KnFLvJRoCcd0YSHhDQtnp_Yrop4fO8zaMwl5Cv_aQvz7n1avXUn5EY4rSQdkG-TZ0D-W5yF4XzOVcxx3Xw31ymy72YnNo2ld9vSczlvYzUry4r6ZpoSTfavBEVYomRd6dmThaSBeTxlzbFNCaMiJbV8xKnuSo5wUEoiRGNh8-I2S4-6qnbuvtl-EZqmnWorXMB0md_Fns1vcKJUosWZgS9lioZaU3NXyv4A0pjWSk604kO7AosftnnYjv4JPXN2K7brLA-YrgNff8Sli_Aj-LoqSYNudCo4p800zj2pIFGDRvlnIRr4994bVTKnCHf2MxWPNOyVoxgs8fHTMMkH168NvkTwpmEtaSPt_R_c6zts2btvaIJ5tnJtCaVtIcEFPkGLS2jxNhk_-nnHlo0tmvBefJHuyvtGRSujT_Eg9cXNLsrOYUbg3gtgKICMvmCtK0R7GY_ZMznOVp5tEiNPaFwbjdEwGKDxjc5JNHq1m4HC5XiiIDcKrCK3bEt2RBxGR7-53ldzGi0lx-XgYxAept2GlfSh760Tb6y7G6yzc0xvhphaN12ectn01t3NWSfes25Wo154yXO6buowE9EQ5POm1bfE56LSJqnHbt220szNdrreFxLDb9tczj-4rDNd3Mwg93i0JlSskbw40AhXXGr-rde-8oFXI14Bv87-k9RFF0Gu2Muoi-NV8OeLnN5_nbSuTBR4_mnIoOHbUUmeF47L6eHNAcVb0klmHwsv1pmO361U3xbM6BDMGomfHcwMh4eOxX6KW9hx0AptzoTcBBAd7MNFIcQ3H0vHjwc6XwKNeXk1Trpx3y2C2WFQsRnz06vo2FJvpirErApuOOCMxCjJ-5m6V9UjNhYhLGLTT9QTxNjlcAsYPt2P286UYexeGOC2qPupX-k3c7eZD3v5uHfrBV1peMTtiNj0CDFFbEbEnUNshr07L-JfoAxXMmWr57nqWaZ6jqCe46WnrLTnxC9x4vOc-CwnPseJz3HiU07cc-r7RB_c1PktdVSB8Algp7WqxTuyyRLAUjMJdX5yOzIzQfBKZXjCq2aEX5J9o9soX6d3Qy4KVuOSRWVvx1dqt9UUZoDB8s1nexO_3qQ3_6PmHcY-_rd_hb3p4UXn0OuHZNMzwHjE0AjQBJpHGm3CmdKgvzLTOkErK8pyJ_XeWBPl6SZlizxowE_GDs8TQsHIBOusUJc-pWiD9IWV6rTdxFMIXFTRyNoD8VAzWh-Umwb4NFkGaSyzZrpcsuPRvOkbqaVFnRmUSap2rxWro8jsLzGQJVYuNVKL4U_vf_u5CAMyxqKD9B-KcGHUv9mgOdD4twni0KBtOwCfPLszt8n11c925kW3HZNjN_OZydb6Vlbo0QIu_5SayRFCha4U_JfqcXf56c32Ok75u8K25uf2c6NcvK_8PWFAxs9g7vsNn7wlo6jefjcJv9PwyQtvAPZfTcIG-2T1f7W6UjKoTM3BDx4iPEQ4iFVkIGLyTenvb-uhjIF85_OgORKFnhI0BfdhMPySEtQE9A2LQ59Agadd_BeW1ABm&lang=python)." ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ - "Note that there is a jump in density across the contact discontinuity." + "interact(plot_exact_riemann_solution_stripes,\n", + " rho_l=widgets.FloatSlider(min=1.,max=10.,step=0.1,value=3.,description=r'$\\rho_l$'),\n", + " u_l=widgets.FloatSlider(min=-10.,max=10.,step=0.1,value=0.,description=r'$u_l$'),\n", + " p_l=widgets.FloatSlider(min=1.,max=10.,step=0.1,value=3.,description=r'$p_l$'),\n", + " rho_r=widgets.FloatSlider(min=1.,max=10.,step=0.1,value=1.,description=r'$\\rho_r$'),\n", + " u_r=widgets.FloatSlider(min=-10.,max=10.,step=0.1,value=0.,description=r'$u_r$'),\n", + " p_r=widgets.FloatSlider(min=1.,max=10.,step=0.1,value=1.,description=r'$p_r$'),\n", + " t=widgets.FloatSlider(min=0.1,max=1.,step=0.1,value=0.5));" ] }, { @@ -658,9 +748,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "left_state = Primitive_State(Density =0.,\n", @@ -676,9 +764,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "Euler.phase_plane_plot(left_state, right_state)" @@ -694,9 +780,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "left_state = Primitive_State(Density =1.,\n", @@ -712,9 +796,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "Euler.phase_plane_plot(left_state, right_state)" @@ -723,7 +805,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [] } diff --git a/utils/riemann_tools.py b/utils/riemann_tools.py index 9c4f61d4..babf0031 100644 --- a/utils/riemann_tools.py +++ b/utils/riemann_tools.py @@ -426,30 +426,20 @@ def JSAnimate_plot_riemann(states,speeds,riemann_eval, wave_types=None, times=No return anim -def plot_riemann_trajectories(states, s, riemann_eval, wave_types=None, - i_vel=1, fig=None, color='b', num_left=10, - num_right=10, xmax=None, rho_left=None, - rho_right=None,ax=None,t=None): +def compute_riemann_trajectories(states, s, riemann_eval, wave_types=None, + i_vel=1, num_left=10, num_right=10, + rho_left=None, rho_right=None, xmax=None): """ - Take an array of states and speeds s and plot the solution in the x-t plane, - along with particle trajectories. + Take an array of speeds s and compute particle trajectories. Only useful for systems where one component is velocity. - i_vel should be the index of this component. + i_vel should be the component of velocity in this case. - For rarefaction waves, the corresponding entry in s should be tuple of two values, - which are the wave speeds that bound the rarefaction fan. + For rarefaction waves, the corresponding entry in s should be tuple of + two values, which are the wave speeds that bound the rarefaction fan. """ - colors = {'shock': 'r', 'raref': 'b', 'contact': 'k'} - if wave_types is None: - wave_types = ['contact']*len(s) - - num_eqn,num_states = states.shape - if ax is None: - fig, ax = plt.subplots() - # auto scale the x axis? xmax_auto = (xmax is None) tmax = 1.0 @@ -458,19 +448,15 @@ def plot_riemann_trajectories(states, s, riemann_eval, wave_types=None, for i in range(len(s)): if wave_types[i] in ['shock','contact']: x1 = tmax * s[i] - ax.plot([0,x1],[0,tmax],color=colors[wave_types[i]]) if xmax_auto: xmax = max(xmax,abs(x1)) - else: # plot rarefaction fan + else: # rarefaction fan speeds = np.linspace(s[i][0],s[i][1],5) for ss in speeds: x1 = tmax * ss - ax.plot([0,x1],[0,tmax],color=colors['raref'],lw=0.5) if xmax_auto: xmax = max(xmax,abs(x1)) - ax.set_xlim(-xmax,xmax) - xx_left = np.linspace(-xmax,0,num_left) xx_right = np.linspace(0,xmax,num_right) @@ -481,22 +467,67 @@ def plot_riemann_trajectories(states, s, riemann_eval, wave_types=None, xx_right = np.arange(0, xmax, xmax*0.02/(rho_right + 1e-8)) xx = np.hstack((xx_left, xx_right)) - xtraj = [xx] + x_traj = [xx] nsteps = 200. dt = 1./nsteps - tt = np.linspace(0,1,nsteps+1) + t_traj = np.linspace(0,1,nsteps+1) q_old = riemann_eval(xx/1e-15) - for n in range(1,len(tt)): - q_new = riemann_eval(xx/tt[n]) + for n in range(1,len(t_traj)): + q_new = riemann_eval(xx/t_traj[n]) v_mid = 0.5*(q_old[i_vel,:] + q_new[i_vel,:]) xx = xx + dt*v_mid - xtraj.append(xx) + x_traj.append(xx) q_old = copy.copy(q_new) - xtraj = np.array(xtraj) - for j in range(xtraj.shape[1]): - plt.plot(xtraj[:,j],tt,'k') + x_traj = np.array(x_traj) + return x_traj, t_traj, xmax + + +def plot_riemann_trajectories(x_traj, t_traj, s, wave_types=None, color='b', + xmax=None, ax=None,t=None): + """ + Take an array of speeds s and plot the solution in the x-t plane, + along with particle trajectories. + + Only useful for systems where one component is velocity. + + For rarefaction waves, the corresponding entry in s should be tuple of + two values, which are the wave speeds that bound the rarefaction fan. + + """ + + colors = {'shock': 'r', 'raref': 'b', 'contact': 'k'} + if wave_types is None: + wave_types = ['contact']*len(s) + + if ax is None: + fig, ax = plt.subplots() + + # auto scale the x axis? + xmax_auto = (xmax is None) + + tmax = 1.0 + if xmax_auto: + xmax = 0. + for i in range(len(s)): + if wave_types[i] in ['shock','contact']: + x1 = tmax * s[i] + ax.plot([0,x1],[0,tmax],color=colors[wave_types[i]]) + if xmax_auto: + xmax = max(xmax,abs(x1)) + else: # plot rarefaction fan + speeds = np.linspace(s[i][0],s[i][1],5) + for ss in speeds: + x1 = tmax * ss + ax.plot([0,x1],[0,tmax],color=colors['raref'],lw=0.5) + if xmax_auto: + xmax = max(xmax,abs(x1)) + + ax.set_xlim(-xmax,xmax) + + for j in range(x_traj.shape[1]): + plt.plot(x_traj[:,j],t_traj,'k') if t is not None: ax.plot([-xmax,xmax],[t,t],'--k',linewidth=0.8) From ddd8257ce6b9f51ca2631db80fce1005666daf05 Mon Sep 17 00:00:00 2001 From: Randy LeVeque Date: Sun, 23 Apr 2017 22:25:53 -0400 Subject: [PATCH 02/12] fix exact_solvers/traffic_LWR.py to use new trajectories code. Also add snapshot_widget option to Traffic_flow.ipynb --- Traffic_flow.ipynb | 133 ++++++++++++----------------------- exact_solvers/traffic_LWR.py | 15 +++- 2 files changed, 58 insertions(+), 90 deletions(-) diff --git a/Traffic_flow.ipynb b/Traffic_flow.ipynb index caf6a2ef..70cc9f05 100644 --- a/Traffic_flow.ipynb +++ b/Traffic_flow.ipynb @@ -1,41 +1,15 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import matplotlib as mpl\n", - "mpl.rcParams['font.size'] = 12\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "from ipywidgets import interact, widgets\n", - "from utils import riemann_tools\n", - "from exact_solvers import traffic_LWR" - ] - }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "# Traffic flow: the Lighthill-Whitham-Richards model" ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "In this chapter we investigate a conservation law that models the flow of traffic. This model is sometimes referred to as the Lighthill-Whitham-Richards (or LWR) traffic model (see (Lighthill, 1955) and (Richards, 1956)). This model and the corresponding Riemann problem are discussed in many places; the discussion here is most closely related to that in Chapter 11 of (LeVeque, 2002).\n", "\n", @@ -54,36 +28,52 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "![](./figures/LWR-Velocity.png)" ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Combining the two equations above, our conservation law says\n", "\n", "$$\\rho_t + (\\rho (1-\\rho))_x = 0.$$\n", "\n", - "The function $\\rho(1-\\rho)$ is the flux, or the rate of flow of cars. Notice how the flux is zero when there are no cars and also when the road is completely full. The maximum flow of traffic actually occurs when the road is half full:" + "The function $\\rho(1-\\rho)$ is the flux, or the rate of flow of cars. Notice how the flux is zero when there are no cars and also when the road is completely full. The maximum flow of traffic actually occurs when the road is half full, as the plot below shows." ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "import matplotlib as mpl\n", + "mpl.rcParams['font.size'] = 12\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from ipywidgets import widgets\n", + "from utils import riemann_tools\n", + "from exact_solvers import traffic_LWR" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import interact # for interactive widgets\n", + "#from utils.snapshot_widgets import interact # for static figure that can be viewed online" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "rho = np.linspace(0,1)\n", @@ -95,10 +85,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "This equation is fundamentally different from the advection equation because the flux is **nonlinear**. This fact will have dramatic consequences for both the behavior of solutions and our numerical methods. But we can superficially make this equation look like the advection equation by using the chain rule to write\n", "\n", @@ -113,10 +100,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "## Example: Traffic jam\n", "\n", @@ -128,11 +112,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "def jam(rho_l=0.2,t=0.1):\n", @@ -149,15 +129,12 @@ " \n", "interact(jam,\n", " rho_l=widgets.FloatSlider(min=0.,max=0.9,value=0.2,description=r'$\\rho_l$'),\n", - " t=widgets.FloatSlider(min=0.,max=1.));" + " t=widgets.FloatSlider(min=0.,max=1.,step=0.1,value=0.5));" ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "## Speed of a shock wave: the Rankine-Hugoniot conditions\n", "\n", @@ -178,10 +155,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Returning to our traffic jam scenario, we set $\\rho_r=1$. Then we find that\n", "\n", @@ -236,10 +210,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "The plot below shows the solution density and vehicle trajectories for a green light at $x=0$." ] @@ -247,11 +218,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "def green_light(rho_r=0.,t=0.1):\n", @@ -271,15 +238,12 @@ "\n", "interact(green_light,\n", " rho_r=widgets.FloatSlider(min=0.,max=0.9,value=0.,description=r'$\\rho_r$'),\n", - " t=widgets.FloatSlider(min=0.,max=1.));" + " t=widgets.FloatSlider(min=0.,max=1.,step=0.1,value=0.5));" ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "How can we determine whether an initial discontinuity will lead to a shock or a rarefaction?\n", "- Shocks appear in regions where characteristics overlap:\n", @@ -301,10 +265,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "## Interactive Riemann solution\n", "\n", @@ -314,11 +275,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "def riemann_traffic_exact(rho_l,rho_r):\n", @@ -404,7 +361,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", - "version": "2.7.13" + "version": "2.7.12" } }, "nbformat": 4, diff --git a/exact_solvers/traffic_LWR.py b/exact_solvers/traffic_LWR.py index a43e8f44..6a84c8a6 100644 --- a/exact_solvers/traffic_LWR.py +++ b/exact_solvers/traffic_LWR.py @@ -40,5 +40,16 @@ def reval_with_speed(xi): u = 1-q qu = np.vstack((q,u)) return qu - riemann_tools.plot_riemann_trajectories(states, speeds, reval_with_speed, wave_types, - xmax=xmax,rho_left=q_l, rho_right=q_r,ax=ax,t=t) + + # density of particles for trajectories: + rho_left = q_l / 3. + rho_right = q_r / 3. + + # compute trajectories: + x_traj, t_traj, xmax = riemann_tools.compute_riemann_trajectories(states, + speeds, reval_with_speed, wave_types, + xmax=xmax,rho_left=rho_left, rho_right=rho_right) + + # plot trajectories along with waves in the x-t plane: + riemann_tools.plot_riemann_trajectories(x_traj, t_traj, speeds, wave_types, + xmax=xmax, ax=ax, t=t) From 660ed5351177ce217def246940d215f682abd46e Mon Sep 17 00:00:00 2001 From: Randy LeVeque Date: Mon, 24 Apr 2017 16:58:05 -0400 Subject: [PATCH 03/12] New Introduction.ipynb from old Prologue notebooks, with SW stripe examples. Added new function to utils/riemann_tools.py to make simple demo plots and improved setting of x_traj points so stripes are equal width near origin --- Introduction.ipynb | 302 +++++++++++++++++++++++++++++++++ exact_solvers/shallow_water.py | 101 +++++++++++ utils/riemann_tools.py | 7 +- 3 files changed, 409 insertions(+), 1 deletion(-) create mode 100644 Introduction.ipynb diff --git a/Introduction.ipynb b/Introduction.ipynb new file mode 100644 index 00000000..b5118cbc --- /dev/null +++ b/Introduction.ipynb @@ -0,0 +1,302 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction\n", + "\n", + "## What is a Riemann Problem?\n", + "\n", + "Bernhard Riemann studied [many problems](https://en.wikipedia.org/wiki/List_of_things_named_after_Bernhard_Riemann) in diverse mathematical fields, but for our purposes the term **Riemann problem** refers to a hyperbolic partial differential equation (PDE) together with special initial data: a piecewise constant function with a single jump discontinuity separating two states. For a hyperbolic system of $m$ PDEs, each of these states would be a vector with $m$ components, say $q_l$ for $x<0$ and $q_r$ for $x \\geq 0$. \n", + "\n", + "We will formally define what we mean by a hyperbolic system of PDEs shortly, but for now it suffices to know that these are the PDEs that naturally arise whenever we model wave propagation. If we study small amplitude waves then the equations may be linear (e.g. acoustics or linear elasticity, modeling seismic waves for example). These PDEs arise from linearizing nonlinear hyperbolic systems that must be used when we consider larger amplitude waves (e.g. the Euler equations of compressible gas dynamics, or nonlinear elastic wave equations)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## An example: the dam break problem\n", + "\n", + "To get a feel for what a Riemann problem and it's solution looks like, consider a *dam break* problem in which a dam initially separates water with constant depth $h_l$ to the left of the dam from water with depth $h_r$ to the right of the dam. Suppose the water is initially stationary, with velocity 0 on both sides of the dam. Now suppose we remove the dam at time $t=0$. What happens for $t>0$?\n", + "\n", + "If the water to the left of the dam is deeper than the water to the right (i.e. $h_l > h_r$) then we expect water to flow from left to right in some manner. In reality we might expect the flow to be somewhat turbulent and multidimensional, but suppose that we could idealize this with a one-dimensional model in which the velocity is purely horizontal and is constant throughout the depth of the fluid, so for $t>0$ the velocity varies only with $x$ and $t$, given by some function $u(x,t)$, and the depth is given by $h(x,t)$. \n", + "\n", + "In the notebook [Shallow_water.ipynb](Shallow_water.ipynb) we will discuss the one-dimensional **shallow water equations** that can be used to model this idealized situation. \n", + "\n", + "The animation below shows the solution to the shallow water equations in the situation just described. The water is colored red for water that is initially to the left of the dam and blue for water that is initially to the right. The stripes with different shading are to help you visualize the flow. Think of the color as a dye that is simply carried along with the water as it flows. In the notebook [Shallow_water_tracer.ipynb](Shallow_water_tracer.ipynb) we will see that we can in fact model this by adding another equation to the shallow water equations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "from exact_solvers import shallow_water\n", + "from ipywidgets import widgets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import interact # for interactive widgets\n", + "#from utils.snapshot_widgets import interact # for static figure that can be viewed online" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from exact_solvers import shallow_water\n", + "reload(shallow_water)\n", + "interact(shallow_water.make_demo_plot_function(h_l=3., h_r=1., u_l=0., u_r=0),\n", + " time=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.2));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Things to note about this animation\n", + "\n", + " - Initially the fluid velocity $u(x,0) \\equiv 0$ at $t=0$. For $t>0$, the water remain stationary far from away from the dam. The region where the water is not stationary grows linearly outward from $x=0$ as $t$ increases.\n", + " - The fluid is accelerated to the right everywhere as water starts to flow.\n", + " - Water upstream from the dam (for $x<0$) starts to accelerate slowly as the depth of the water starts to fall, and both the depth and the velocity remain continuous functions of $x$ in this region for all time. The depth and velocity vary through a **rarefaction wave** that moves upstream.\n", + " - The water downstream from the dam is stationary until a **shock wave** passes by, which instantaneously accelerates the fluid from $u_r=0$ to some constant velocity $u_m >0$. At the same time the depth increases from $h_r$ to $h_m$. This *middle state* depth and velocity is the same as the depth and velocity that the red water upstream from the dam also reaches once it has passed through the rarefaction wave and been fully accelerated.\n", + " - The shock wave moves at some constant velocity $s_r > u_m$.\n", + " - The rarefaction wave spreads out as time evolves and the left and right edges move at constant velocities $\\lambda_{l1}$ and $\\lambda_{m1}$. We will see later that these speeds are eigenvalues of a certain Jacobian matrices.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A **shock wave** is a type of wave often seen when solving nonlinear hyperbolic equations. The solution is discontinuous across a shock wave, which means that special mathematical techniques must be used to make sense of functions like this as solutions of a differential equation. It also means that special algorithmic techniques must be used to compute accurate numerical solutions to such equations. Simply replacing derivatives by finite differences typically does not work well. \n", + "\n", + "In the context of water waves, this shock wave is often called a **hydraulic jump**. In a real dam break problem the solution would not be discontinuous, but there might be turbulent bore that from far enough away looks like a discontinuity. The nonlinear shallow water equations can be used to model such flows in the sense that the jump in depth and velocity and the propagation speed of the shock wave closely approximate the hydraulic jump and speed of the bore." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Why is the Riemann problem important?\n", + "\n", + "Why study the simple case of piecewise constant initial data? Here are some motivations:\n", + "\n", + " - As we have just seen, even this simple initial data can lead to complicated solutions. \n", + " \n", + " - However, the solution is simple enough that there is some hope we can determine it exactly, even for nonlinear systems of PDEs.\n", + " \n", + " - In the animation above we noted that the shock wave and the two edges of the rarefaction wave are all moving at *constant speeds*. In fact if we plot contours of the depth (or the velocity) in the $x$-$t$ plane, we find that value of each variable is constant along any ray $x = at$ from the origin. In other words $h(x,t) = H(x/t)$ and $u(x,t) = U(x/t)$ for some functions $H$ and $U$ of a single variable. The solution is said to be a **similarity solution** and this structure greatly facilitates solving the Riemann problem. This is true even for nonlinear hyperbolic problems provided certain conditions are satisfied.\n", + "\n", + " - Developing an understanding of how the Riemann solution behaves for all possible choices of left and right states for a hyperbolic problem is essential for understanding the behavior of more complicated solutions.\n", + " \n", + " - The development of mathematical theory of hyperbolic problems has relied extensively on the understanding that comes from studying Riemann problems.\n", + " \n", + " - Many robust numerical methods for approximating the solution with more general initial data use the Riemann solution as an essential building block. The most basic method of this type is **Godunov's method**, described below. Numerical methods typically make use of *approximate Riemann solvers*, which are often computationally cheaper than an exact solver.\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The general Riemann problem for shallow water equations\n", + "\n", + "The more general Riemann problem for the shallow water equations has arbitrary depths $h_l, h_r \\geq 0$ and also arbitrary velocities $u_l$ and $u_r$ to the left and right of $x=0$. The dam break problem considered above is a special case where the $u_l = u_r = 0$. \n", + "\n", + "In the dam break problem considered above with $h_l > h_r$, the solution consists of a left-going rarefaction wave and a right-going shock wave. If we instead have $h_l < h_r$ with $u_l=u_r=0$, then the water would flow to the left and the Riemann solution would have a left-going shock wave and a right-going rarefaction wave." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "interact(shallow_water.make_demo_plot_function(h_l=1., h_r=3., u_l=0., u_r=0),\n", + " time=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.2));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By choosing non-zero velocities in the initial data, we can also obtain other combinations of shock and rarefaction waves. For example, if $u_l>0$ and $u_r<0$ (modeling two opposing streams of water colliding at $x=0$) then the Riemann solution consists of two shock waves:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "interact(shallow_water.make_demo_plot_function(h_l=1., h_r=1., u_l=0.8, u_r=-0.8),\n", + " time=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.2));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On the other hand, if $u_l<0$ and $u_r>0$ (so that the water is moving away from $x=0$ on both sides) then the solution consists of two rarefaction waves:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "interact(shallow_water.make_demo_plot_function(h_l=1., h_r=1., u_l=-0.8, u_r=0.8),\n", + " time=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.2));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the notebook [Shallow_water.ipynb](Shallow_water.ipynb) we will show how to solve the Riemann problem for arbitrary left and right states and in particular how to determine whether each wave is a shock or rarefaction wave." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Add a link to an $h$-$u$ phase plane plot where the states can be dragged, but that only shows the physical curves?**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Goals of this book\n", + "\n", + "The collection of Jupyter notebooks that make up this book will help you understand..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## When is a PDE hyperbolic?\n", + "\n", + "In this book we consider only first-order hyperbolic equations, meaning they involve only first derivatives in space and time. Many important hyperbolic PDE models can be written as a system of conservation laws:\n", + "\n", + "\\begin{align} \\label{intro:multiDconslaw}\n", + " q_t + \\nabla \\cdot F(q) & = 0.\n", + "\\end{align}\n", + "\n", + "Here $q(x,t)$ is a vector of conserved quantities (e.g. mass, momentum, energy) and each component of $F(q)$ is the corresponding flux. In practice (and in most of this book) we focus on one-dimensional problems, for which (\\ref{intro:multiDconslaw}) can be written\n", + "\n", + "\\begin{align} \\label{intro:conslaw}\n", + " q_t + f(q)_x & = 0.\n", + "\\end{align}\n", + "\n", + "If the flux in \\eqref{intro:conslaw} is a linear function $f(q)= Aq$ for some matrix $A$, then we have\n", + "\n", + "\\begin{align} \\label{intro:linconslaw}\n", + " q_t + A q_x & = 0,\n", + "\\end{align}\n", + "\n", + "We say that \\eqref{intro:linconslaw} is **hyperbolic** if $A$ is diagonalizable with real eigenvalues, and the nonlinear system \\eqref{intro:conslaw} is hyperbolic at some state $q$ if the Jacobian matrix $f'(q)$ is diagonalizable with real eigenvalues.\n", + "\n", + "A common property of these equations is that *information travels at finite speed* and they model *waves*. As we will see in more detail later, the eigenvalues correspond to *wave speeds* while the eigenvectors tell us about the relation between the components of $q$ in each wave.\n", + "\n", + "Some examples of physical problems that can be modeled with hyperbolic PDEs (and are included as examples in this book) are:\n", + "\n", + "- Sound waves\n", + "- Surface water waves\n", + "- Traffic flow\n", + "- Gas dynamics\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Godunov's method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# A linear example: acoustic waves\n", + "\n", + "We end this introduction with a sample linear system. Acoustic waves in one dimension can be modeled by the system of PDEs\n", + "\n", + "\\begin{align} \\label{intro:acoustics}\n", + " p_t + K u_x & = 0 \\\\\n", + " u_t + \\frac{1}{\\rho} p_x & = 0,\n", + "\\end{align}\n", + "\n", + "where $p$ represents the deviation from ambient pressure, $u$ is velocity, $K$ is the bulk modulus and $\\rho$ is the density of the medium. This first-order system is equivalent to the familiar wave equation $u_{tt} = c^2 u_{xx}$ with $c = \\sqrt{K/\\rho}$; recall that $c$ represents the speed of propagation of waves in the wave equation. Coming back to the first-order form \\eqref{intro:acoustics}, we can write it in the canonical form \\eqref{intro:linconslaw} by setting\n", + "\n", + "\\begin{align}\n", + " q & = \\begin{bmatrix} p \\\\ u \\end{bmatrix} &\n", + " A & = \\begin{bmatrix} 0 & K \\\\ 1/\\rho & 0 \\end{bmatrix}.\n", + "\\end{align}\n", + "\n", + "The eigenvalues of $A$ are $\\pm \\sqrt{K/\\rho} = \\pm c$; it is true in general that the speed of propagation of waves in \\eqref{intro:linconslaw} is given by the eigenvalues of $A$, and this hints at the importance of the hyperbolicity condition (that $A$ be diagonalizable with real eigenvalues)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The Riemann problem for acoustics\n", + "The Riemann problem consists of \\eqref{intro:acoustics} together with initial data\n", + "\n", + "\\begin{align}\n", + " (p_0,u_0) & = \\begin{cases} (p_l, u_l) & \\text{ for } x<0 \\\\\n", + " (p_r, u_r) & \\text{ for } x>0. \\end{cases}\n", + "\\end{align}\n", + "The solution of the Riemann problem for this simple linear system consists of two jumps, one proportional to each of the eigenvectors of $A$, and each moving with velocity equal to the corresponding eigenvalue of $A$. Between these two jumps lies a middle state different from the left and right states; we can think of solving the Riemann problem by finding the intersection (in the $p-u$ plane) of lines passing through the left and right states that are each parallel to the appropriate eigenvector of A. This example is explored in more detail in [Acoustics.ipynb](Acoustics.ipynb)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.core.display import display, HTML\n", + "app = open('phase_plane_acoustics_small.html','r').read()\n", + "display(HTML(app))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/exact_solvers/shallow_water.py b/exact_solvers/shallow_water.py index 2fe0aa1c..ba5bc4ba 100644 --- a/exact_solvers/shallow_water.py +++ b/exact_solvers/shallow_water.py @@ -394,3 +394,104 @@ def plot_hugoniot_loci(plot_1=True,plot_2=False,y_axis='hu'): plt.title('Hugoniot loci') plt.legend(legend,loc=1) plt.show() + +def make_demo_plot_function(h_l=3., h_r=1., u_l=0., u_r=0): + + def plot_shallow_water_demo(time=0.5): + import numpy as np + import matplotlib.pyplot as plt + from exact_solvers import shallow_water + from collections import namedtuple + from utils import riemann_tools + #from ipywidgets import widgets + State = namedtuple('State', shallow_water.conserved_variables) + Primitive_State = namedtuple('PrimState', shallow_water.primitive_variables) + plt.style.use('seaborn-talk') + g = 1. + + q_l = shallow_water.primitive_to_conservative(h_l,u_l) + q_r = shallow_water.primitive_to_conservative(h_r,u_r) + + from matplotlib.mlab import find + + x = np.linspace(-1.,1.,1000) + states, speeds, reval, wave_types = shallow_water.exact_riemann_solution(q_l,q_r,g) + q = np.array(reval(x/time)) + if time<0.02: + q[1] = np.where(x<0, q_l[1], q_r[1]) + + primitive = shallow_water.conservative_to_primitive(q[0],q[1]) + + # compute particle trajectories: + def reval_rho_u(x): + q = reval(x) + rho = q[0] + u = q[1]/q[0] + rho_u = np.vstack((rho,u)) + return rho_u + + # Specify density of trajectories to left and right: + num_left = 10 + num_right = 10 + rho_left = q_l[0] / 4. + rho_right = q_r[0] / 4. + x_traj, t_traj, xmax = riemann_tools.compute_riemann_trajectories(states, + speeds, reval_rho_u, wave_types, + i_vel=1, xmax=2, rho_left=rho_left, + rho_right=rho_right) + + fig = plt.figure(figsize=(18,6)) + names = ['Density','Velocity'] + axes = [0]*2 + for i in range(2): + axes[i] = fig.add_subplot(1,2,i+1) + q = primitive[i] + plt.plot(x,q,linewidth=3) + plt.title(names[i]) + qmax = max(q) + qmin = min(q) + qdiff = qmax - qmin + #axes[i].set_ylim((qmin-0.1*qdiff,qmax+0.1*qdiff)) + #axes[i].set_xlim(-xmax,xmax) + axes[i].set_xlim(-1,1) + + if i==0: + # plot stripes only on depth plot + n = find(time > t_traj) + if len(n)==0: + n = 0 + else: + n = min(n.max(), len(t_traj)-1) + + for i in range(1, x_traj.shape[1]-1): + j1 = find(x_traj[n,i] > x) + if len(j1)==0: + j1 = 0 + else: + j1 = min(j1.max(), len(x)-1) + j2 = find(x_traj[n,i+1] > x) + if len(j2)==0: + j2 = 0 + else: + j2 = min(j2.max(), len(x)-1) + + # set advected color for density plot: + if x_traj[0,i]<0: + # shades of red for fluid starting from x<0 + if np.mod(i,2)==0: + c = [1,0,0] + else: + c = [1,0.8,0.8] + else: + # shades of blue for fluid starting from x<0 + if np.mod(i,2)==0: + c = [0,0,1] + else: + c = [0.8,0.8,1] + plt.fill_between(x[j1:j2],q[j1:j2],0,color=c) + axes[0].set_ylim(0,3.5) + axes[1].set_ylim(-1,1) + plt.show() + + return plot_shallow_water_demo + diff --git a/utils/riemann_tools.py b/utils/riemann_tools.py index babf0031..3d240b20 100644 --- a/utils/riemann_tools.py +++ b/utils/riemann_tools.py @@ -462,9 +462,14 @@ def compute_riemann_trajectories(states, s, riemann_eval, wave_types=None, # instead define spacing based on density if available: if rho_left is not None: - xx_left = np.arange(-xmax, 0, xmax*0.02/(rho_left + 1e-8)) + #xx_left = np.arange(-xmax, 0, xmax*0.02/(rho_left + 1e-8)) + xx_1 = list(-np.arange(0, xmax, xmax*0.02/(rho_left + 1e-8))) + xx_1.reverse() + xx_left = np.array(xx_1) + if rho_right is not None: xx_right = np.arange(0, xmax, xmax*0.02/(rho_right + 1e-8)) + xx_right = xx_right[1:] # omit repeated 0 xx = np.hstack((xx_left, xx_right)) x_traj = [xx] From b4b0a19f9f5b695dec62cf6975e01c07ac4ca55d Mon Sep 17 00:00:00 2001 From: David Ketcheson Date: Tue, 25 Apr 2017 08:33:44 +0300 Subject: [PATCH 04/12] Minor cleanup of stripe plotting code. --- exact_solvers/shallow_water.py | 89 +++++++++++++++------------------- utils/riemann_tools.py | 13 +++-- 2 files changed, 44 insertions(+), 58 deletions(-) diff --git a/exact_solvers/shallow_water.py b/exact_solvers/shallow_water.py index ba5bc4ba..7c7bc7a0 100644 --- a/exact_solvers/shallow_water.py +++ b/exact_solvers/shallow_water.py @@ -396,65 +396,52 @@ def plot_hugoniot_loci(plot_1=True,plot_2=False,y_axis='hu'): plt.show() def make_demo_plot_function(h_l=3., h_r=1., u_l=0., u_r=0): + from matplotlib.mlab import find + import matplotlib.pyplot as plt + from exact_solvers import shallow_water + from utils import riemann_tools + plt.style.use('seaborn-talk') + + g = 1. + + q_l = shallow_water.primitive_to_conservative(h_l,u_l) + q_r = shallow_water.primitive_to_conservative(h_r,u_r) + + x = np.linspace(-1.,1.,1000) + states, speeds, reval, wave_types = shallow_water.exact_riemann_solution(q_l,q_r,g) + + # compute particle trajectories: + def reval_rho_u(x): + q = reval(x) + rho = q[0] + u = q[1]/q[0] + rho_u = np.vstack((rho,u)) + return rho_u + + x_traj, t_traj, xmax = \ + riemann_tools.compute_riemann_trajectories(states, speeds, reval_rho_u, + wave_types, i_vel=1, xmax=2, + rho_left=h_l/4., + rho_right=h_r/4.) + + num_vars = len(primitive_variables) def plot_shallow_water_demo(time=0.5): - import numpy as np - import matplotlib.pyplot as plt - from exact_solvers import shallow_water - from collections import namedtuple - from utils import riemann_tools - #from ipywidgets import widgets - State = namedtuple('State', shallow_water.conserved_variables) - Primitive_State = namedtuple('PrimState', shallow_water.primitive_variables) - plt.style.use('seaborn-talk') - g = 1. - - q_l = shallow_water.primitive_to_conservative(h_l,u_l) - q_r = shallow_water.primitive_to_conservative(h_r,u_r) - - from matplotlib.mlab import find - - x = np.linspace(-1.,1.,1000) - states, speeds, reval, wave_types = shallow_water.exact_riemann_solution(q_l,q_r,g) q = np.array(reval(x/time)) if time<0.02: q[1] = np.where(x<0, q_l[1], q_r[1]) primitive = shallow_water.conservative_to_primitive(q[0],q[1]) - - # compute particle trajectories: - def reval_rho_u(x): - q = reval(x) - rho = q[0] - u = q[1]/q[0] - rho_u = np.vstack((rho,u)) - return rho_u - - # Specify density of trajectories to left and right: - num_left = 10 - num_right = 10 - rho_left = q_l[0] / 4. - rho_right = q_r[0] / 4. - x_traj, t_traj, xmax = riemann_tools.compute_riemann_trajectories(states, - speeds, reval_rho_u, wave_types, - i_vel=1, xmax=2, rho_left=rho_left, - rho_right=rho_right) - + fig = plt.figure(figsize=(18,6)) - names = ['Density','Velocity'] - axes = [0]*2 - for i in range(2): - axes[i] = fig.add_subplot(1,2,i+1) + axes = [0]*num_vars + for i in range(num_vars): + axes[i] = fig.add_subplot(1,num_vars,i+1) q = primitive[i] - plt.plot(x,q,linewidth=3) - plt.title(names[i]) - qmax = max(q) - qmin = min(q) - qdiff = qmax - qmin - #axes[i].set_ylim((qmin-0.1*qdiff,qmax+0.1*qdiff)) - #axes[i].set_xlim(-xmax,xmax) + plt.plot(x,q,'-k',linewidth=3) + plt.title(primitive_variables[i]) axes[i].set_xlim(-1,1) - + if i==0: # plot stripes only on depth plot n = find(time > t_traj) @@ -476,7 +463,7 @@ def reval_rho_u(x): j2 = min(j2.max(), len(x)-1) # set advected color for density plot: - if x_traj[0,i]<0: + if x_traj[0,i]<0: # shades of red for fluid starting from x<0 if np.mod(i,2)==0: c = [1,0,0] @@ -489,9 +476,9 @@ def reval_rho_u(x): else: c = [0.8,0.8,1] plt.fill_between(x[j1:j2],q[j1:j2],0,color=c) + axes[0].set_ylim(0,3.5) axes[1].set_ylim(-1,1) plt.show() return plot_shallow_water_demo - diff --git a/utils/riemann_tools.py b/utils/riemann_tools.py index 3d240b20..5e0d9ce7 100644 --- a/utils/riemann_tools.py +++ b/utils/riemann_tools.py @@ -427,17 +427,16 @@ def JSAnimate_plot_riemann(states,speeds,riemann_eval, wave_types=None, times=No def compute_riemann_trajectories(states, s, riemann_eval, wave_types=None, - i_vel=1, num_left=10, num_right=10, - rho_left=None, rho_right=None, xmax=None): + i_vel=1, num_left=10, num_right=10, + rho_left=None, rho_right=None, xmax=None): """ Take an array of speeds s and compute particle trajectories. Only useful for systems where one component is velocity. i_vel should be the component of velocity in this case. - For rarefaction waves, the corresponding entry in s should be tuple of + For rarefaction waves, the corresponding entry in s should be tuple of two values, which are the wave speeds that bound the rarefaction fan. - """ xmax_auto = (xmax is None) @@ -466,7 +465,7 @@ def compute_riemann_trajectories(states, s, riemann_eval, wave_types=None, xx_1 = list(-np.arange(0, xmax, xmax*0.02/(rho_left + 1e-8))) xx_1.reverse() xx_left = np.array(xx_1) - + if rho_right is not None: xx_right = np.arange(0, xmax, xmax*0.02/(rho_right + 1e-8)) xx_right = xx_right[1:] # omit repeated 0 @@ -489,7 +488,7 @@ def compute_riemann_trajectories(states, s, riemann_eval, wave_types=None, return x_traj, t_traj, xmax -def plot_riemann_trajectories(x_traj, t_traj, s, wave_types=None, color='b', +def plot_riemann_trajectories(x_traj, t_traj, s, wave_types=None, color='b', xmax=None, ax=None,t=None): """ Take an array of speeds s and plot the solution in the x-t plane, @@ -497,7 +496,7 @@ def plot_riemann_trajectories(x_traj, t_traj, s, wave_types=None, color='b', Only useful for systems where one component is velocity. - For rarefaction waves, the corresponding entry in s should be tuple of + For rarefaction waves, the corresponding entry in s should be a tuple of two values, which are the wave speeds that bound the rarefaction fan. """ From decc0ef5a89a6ccd1457b620e4a83ab3ec20db54 Mon Sep 17 00:00:00 2001 From: David Ketcheson Date: Tue, 25 Apr 2017 08:46:44 +0300 Subject: [PATCH 05/12] Add acoustics phase plane demo. --- phase_plane_acoustics_small.html | 503 +++++++++++++++++++++++++++++++ 1 file changed, 503 insertions(+) create mode 100644 phase_plane_acoustics_small.html diff --git a/phase_plane_acoustics_small.html b/phase_plane_acoustics_small.html new file mode 100644 index 00000000..9865f35c --- /dev/null +++ b/phase_plane_acoustics_small.html @@ -0,0 +1,503 @@ +

Acoustics phase plane

+Drag the left and right states in the first plot to change them. +Drag the circle in the second plot to adjust the time. + +
+ From 65f9b998d44524a5d3ee60f93e907e877b82abf1 Mon Sep 17 00:00:00 2001 From: David Ketcheson Date: Tue, 25 Apr 2017 09:10:34 +0300 Subject: [PATCH 06/12] no reload in Python 3 --- Introduction.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Introduction.ipynb b/Introduction.ipynb index b5118cbc..4c4df775 100644 --- a/Introduction.ipynb +++ b/Introduction.ipynb @@ -54,11 +54,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ - "from exact_solvers import shallow_water\n", - "reload(shallow_water)\n", "interact(shallow_water.make_demo_plot_function(h_l=3., h_r=1., u_l=0., u_r=0),\n", " time=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.2));" ] From e63f58d8bf2facdf22e7109ce1bf5517165ae087 Mon Sep 17 00:00:00 2001 From: Randy LeVeque Date: Sun, 30 Apr 2017 21:45:46 -0400 Subject: [PATCH 07/12] change 'time' to 't' and initialize to 0 in Introduction --- Introduction.ipynb | 20 +++++++++----------- exact_solvers/shallow_water.py | 8 ++++---- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/Introduction.ipynb b/Introduction.ipynb index 4c4df775..959f4bc5 100644 --- a/Introduction.ipynb +++ b/Introduction.ipynb @@ -31,9 +31,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", @@ -54,13 +52,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "interact(shallow_water.make_demo_plot_function(h_l=3., h_r=1., u_l=0., u_r=0),\n", - " time=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.2));" + " t=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.));" ] }, { @@ -126,7 +122,7 @@ "outputs": [], "source": [ "interact(shallow_water.make_demo_plot_function(h_l=1., h_r=3., u_l=0., u_r=0),\n", - " time=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.2));" + " t=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.));" ] }, { @@ -143,7 +139,7 @@ "outputs": [], "source": [ "interact(shallow_water.make_demo_plot_function(h_l=1., h_r=1., u_l=0.8, u_r=-0.8),\n", - " time=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.2));" + " t=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.));" ] }, { @@ -160,7 +156,7 @@ "outputs": [], "source": [ "interact(shallow_water.make_demo_plot_function(h_l=1., h_r=1., u_l=-0.8, u_r=0.8),\n", - " time=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.2));" + " t=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.));" ] }, { @@ -269,7 +265,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "from IPython.core.display import display, HTML\n", diff --git a/exact_solvers/shallow_water.py b/exact_solvers/shallow_water.py index 7c7bc7a0..6028cfb9 100644 --- a/exact_solvers/shallow_water.py +++ b/exact_solvers/shallow_water.py @@ -426,9 +426,9 @@ def reval_rho_u(x): num_vars = len(primitive_variables) - def plot_shallow_water_demo(time=0.5): - q = np.array(reval(x/time)) - if time<0.02: + def plot_shallow_water_demo(t=0.5): + q = np.array(reval(x/t)) + if t<0.02: q[1] = np.where(x<0, q_l[1], q_r[1]) primitive = shallow_water.conservative_to_primitive(q[0],q[1]) @@ -444,7 +444,7 @@ def plot_shallow_water_demo(time=0.5): if i==0: # plot stripes only on depth plot - n = find(time > t_traj) + n = find(t > t_traj) if len(n)==0: n = 0 else: From 345c7988c965962e300233ffad30b7cf2791a745 Mon Sep 17 00:00:00 2001 From: Randy LeVeque Date: Sun, 30 Apr 2017 22:39:43 -0400 Subject: [PATCH 08/12] First pass at utils/jsanimate_widgets.py, illustrated in Introduction --- Introduction.ipynb | 19 +++++++-------- exact_solvers/shallow_water.py | 12 +++++++--- utils/jsanimate_widgets.py | 43 ++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 13 deletions(-) create mode 100644 utils/jsanimate_widgets.py diff --git a/Introduction.ipynb b/Introduction.ipynb index 959f4bc5..7bd7d23a 100644 --- a/Introduction.ipynb +++ b/Introduction.ipynb @@ -36,7 +36,7 @@ "source": [ "%matplotlib inline\n", "from exact_solvers import shallow_water\n", - "from ipywidgets import widgets" + "from ipywidgets import widgets, fixed" ] }, { @@ -45,8 +45,9 @@ "metadata": {}, "outputs": [], "source": [ - "from ipywidgets import interact # for interactive widgets\n", - "#from utils.snapshot_widgets import interact # for static figure that can be viewed online" + "#from ipywidgets import interact # for interactive widgets\n", + "#from utils.snapshot_widgets import interact # for static figure that can be viewed online\n", + "from utils.jsanimate_widgets import interact # for JSAnimation that can be viewed online" ] }, { @@ -56,7 +57,7 @@ "outputs": [], "source": [ "interact(shallow_water.make_demo_plot_function(h_l=3., h_r=1., u_l=0., u_r=0),\n", - " t=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.));" + " t=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.), fig=fixed(0))" ] }, { @@ -122,7 +123,7 @@ "outputs": [], "source": [ "interact(shallow_water.make_demo_plot_function(h_l=1., h_r=3., u_l=0., u_r=0),\n", - " t=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.));" + " t=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.), fig=fixed(0));" ] }, { @@ -139,7 +140,7 @@ "outputs": [], "source": [ "interact(shallow_water.make_demo_plot_function(h_l=1., h_r=1., u_l=0.8, u_r=-0.8),\n", - " t=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.));" + " t=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.), fig=fixed(0));" ] }, { @@ -156,7 +157,7 @@ "outputs": [], "source": [ "interact(shallow_water.make_demo_plot_function(h_l=1., h_r=1., u_l=-0.8, u_r=0.8),\n", - " t=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.));" + " t=widgets.FloatSlider(min=0.001,max=0.6,step=0.1,value=0.), fig=fixed(0));" ] }, { @@ -265,9 +266,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "from IPython.core.display import display, HTML\n", diff --git a/exact_solvers/shallow_water.py b/exact_solvers/shallow_water.py index 6028cfb9..2f3aed49 100644 --- a/exact_solvers/shallow_water.py +++ b/exact_solvers/shallow_water.py @@ -426,14 +426,19 @@ def reval_rho_u(x): num_vars = len(primitive_variables) - def plot_shallow_water_demo(t=0.5): + def plot_shallow_water_demo(t=0.5, fig=0): q = np.array(reval(x/t)) if t<0.02: q[1] = np.where(x<0, q_l[1], q_r[1]) primitive = shallow_water.conservative_to_primitive(q[0],q[1]) - fig = plt.figure(figsize=(18,6)) + if fig == 0: + fig = plt.figure(figsize=(18,6)) + show_fig = True + else: + show_fig = False + axes = [0]*num_vars for i in range(num_vars): axes[i] = fig.add_subplot(1,num_vars,i+1) @@ -479,6 +484,7 @@ def plot_shallow_water_demo(t=0.5): axes[0].set_ylim(0,3.5) axes[1].set_ylim(-1,1) - plt.show() + if show_fig: + plt.show() return plot_shallow_water_demo diff --git a/utils/jsanimate_widgets.py b/utils/jsanimate_widgets.py new file mode 100644 index 00000000..028d6e62 --- /dev/null +++ b/utils/jsanimate_widgets.py @@ -0,0 +1,43 @@ + +""" +Alternative interact function that creates a JSAnimation figure that can +be viewed online, e.g. on Github or nbviewer. +""" + +from __future__ import print_function + +print("Will create JSAnimation figures instead of interactive widget") + +def interact(f, **kwargs): + from utils import animation_tools + from IPython.display import display + from numpy import arange + from matplotlib import pyplot as plt + fargs = {} + for key in kwargs.keys(): + try: + fargs[key] = kwargs[key].value + except: + pass # if initial value not set for this parameter + if ('t' in fargs.keys()): + t0 = kwargs['t'].min + t1 = kwargs['t'].max + try: + dt = kwargs['t'].step + except: + dt = (t1 - t0)/10. + times = arange(t0,t1+dt,dt) + figs = [] + for t in times: + fargs['t'] = t + fig = plt.figure(figsize=(12,6)) + fargs['fig'] = fig + f(**fargs) + figs.append(fig) + plt.close(fig) + images = animation_tools.make_images(figs) + anim = animation_tools.JSAnimate_images(images) + display(anim) + else: + # just make one static plot if 't' is not a key: + f(**fargs) From 56d97f829e3596c8369307e787988eb75d64dc26 Mon Sep 17 00:00:00 2001 From: Randy LeVeque Date: Sat, 6 May 2017 13:29:02 -0400 Subject: [PATCH 09/12] Add a bit to Introduction --- Introduction.ipynb | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Introduction.ipynb b/Introduction.ipynb index 7bd7d23a..f845354f 100644 --- a/Introduction.ipynb +++ b/Introduction.ipynb @@ -31,7 +31,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "%matplotlib inline\n", @@ -130,7 +132,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "By choosing non-zero velocities in the initial data, we can also obtain other combinations of shock and rarefaction waves. For example, if $u_l>0$ and $u_r<0$ (modeling two opposing streams of water colliding at $x=0$) then the Riemann solution consists of two shock waves:" + "By choosing non-zero velocities in the initial data, we can also obtain other combinations of shock and rarefaction waves. For example, if the depth is initially the same everywhere ($h_l = h_r$) while the velocities satisfy $u_l>0$ and $u_r<0$ (modeling two opposing streams of water colliding at $x=0$) then the Riemann solution consists of two shock waves. Note that the water is deeper and stationary between the shock waves:" ] }, { @@ -223,7 +225,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Godunov's method" + "## Godunov's method\n", + "\n", + " - Add a brief description of Godunov's method and how it uses Riemann solutions.\n", + " - Mention the need for approximate Riemann solvers." ] }, { @@ -263,6 +268,13 @@ "The solution of the Riemann problem for this simple linear system consists of two jumps, one proportional to each of the eigenvectors of $A$, and each moving with velocity equal to the corresponding eigenvalue of $A$. Between these two jumps lies a middle state different from the left and right states; we can think of solving the Riemann problem by finding the intersection (in the $p-u$ plane) of lines passing through the left and right states that are each parallel to the appropriate eigenvector of A. This example is explored in more detail in [Acoustics.ipynb](Acoustics.ipynb)." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The figure below shows the phase plane (the $p$-$u$ plane for acoustics) and the location of $q_m$ relative to $q_l$ and $q_r$. You can drag the left and right states around to see how this changes the solution. Also shown in the other two plots are the pressure $p(x,t)$ and velocity $u(x,t)$ at one particular time $t=1$ for this Riemann solution." + ] + }, { "cell_type": "code", "execution_count": null, From 442fde212ad879e6ce842924e9faf5c2ed7b5cea Mon Sep 17 00:00:00 2001 From: Randy LeVeque Date: Sat, 6 May 2017 13:54:29 -0400 Subject: [PATCH 10/12] Add shallow water javascript to Introduction --- Introduction.ipynb | 38 +++++++++++++++++++----- phase_plane_shallow_water_small.html | 2 +- phase_plane_shallow_water_verysmall.html | 6 ++-- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/Introduction.ipynb b/Introduction.ipynb index f845354f..a8bae56b 100644 --- a/Introduction.ipynb +++ b/Introduction.ipynb @@ -169,20 +169,13 @@ "In the notebook [Shallow_water.ipynb](Shallow_water.ipynb) we will show how to solve the Riemann problem for arbitrary left and right states and in particular how to determine whether each wave is a shock or rarefaction wave." ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Add a link to an $h$-$u$ phase plane plot where the states can be dragged, but that only shows the physical curves?**" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Goals of this book\n", "\n", - "The collection of Jupyter notebooks that make up this book will help you understand..." + "The collection of Jupyter notebooks that make up this book will help you understand how to solve the Riemann problem for general hyperbolic PDE. This will be accomplished by working through examples for several different systems of equations. In the process you should also gain a better understanding of wave propagation phenomena in the context of several important applications. [Expand this?]" ] }, { @@ -285,6 +278,35 @@ "app = open('phase_plane_acoustics_small.html','r').read()\n", "display(HTML(app))" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Phase plane plot for the shallow water equations\n", + "\n", + "The phase plane plot for the nonlinear shallow water equations is more interesting. Since the eigenvectors of the Jacobian matrix vary with $q$, the curves connecting states separated by a single wave are not straight lines. There is also a distinction between the curves connecting states by a shock wave and those connecting states by a rarefaction wave. This is discussed in much more detail in the notebook [Shallow_water.ipynb](Shallow_water.ipynb), but here is an interactive view that allows you to see how the solution changes as you move the left and right states around in the phase plane:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.core.display import display, HTML\n", + "app = open('phase_plane_shallow_water_verysmall.html','r').read()\n", + "display(HTML(app))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/phase_plane_shallow_water_small.html b/phase_plane_shallow_water_small.html index ba0b641c..2c13b426 100644 --- a/phase_plane_shallow_water_small.html +++ b/phase_plane_shallow_water_small.html @@ -1,5 +1,5 @@ -

Shallow water phase plane

+

Shallow water phase plane

Drag the left and right states in the first plot to change them. Drag the circle in the second plot to adjust the time.
diff --git a/phase_plane_shallow_water_verysmall.html b/phase_plane_shallow_water_verysmall.html index a0ffd54b..94d8fbdd 100644 --- a/phase_plane_shallow_water_verysmall.html +++ b/phase_plane_shallow_water_verysmall.html @@ -1,7 +1,9 @@ +

Shallow water phase plane

+Drag the left and right states in the first plot to change them. +Drag the circle in the second plot to adjust the time.
@@ -1618,4 +1620,4 @@ }) }); } - \ No newline at end of file + From 7b4aab54ab2734ea34afd5aec00a7d2e223da419 Mon Sep 17 00:00:00 2001 From: David Ketcheson Date: Thu, 18 May 2017 08:54:47 +0300 Subject: [PATCH 11/12] Use prettier graphics in JSAnimation_plot_riemann. --- utils/riemann_tools.py | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/utils/riemann_tools.py b/utils/riemann_tools.py index 91ee6ad9..afcc8ad2 100644 --- a/utils/riemann_tools.py +++ b/utils/riemann_tools.py @@ -409,26 +409,17 @@ def real_plot_function(t): return real_plot_function def JSAnimate_plot_riemann(states,speeds,riemann_eval, wave_types=None, times=None, **kwargs): - try: - from utils import animation_tools - except: - try: - from clawpack.visclaw import animation_tools - except: - print("*** Warning: animation_tools not found") - - figs = [] # to collect figures at multiple times - if times is None: - times = np.linspace(0,0.9,10) - for t in times: - ax = plot_riemann(states,speeds,riemann_eval,wave_types,t=t, **kwargs) - figs.append(ax[0].figure) - plt.close(ax[0].figure) - - images = animation_tools.make_images(figs) - anim = animation_tools.JSAnimate_images(images, figsize=(8,4)) - return anim + from matplotlib import animation + fig, axes = plt.subplots(1,3,figsize=(12,4)) + + def fplot(frame_number): + for axis in axes: + axis.cla() + t = frame_number/10. + plot_riemann(states,speeds,riemann_eval,t=t,ax=axes) + return axes, + return animation.FuncAnimation(fig, fplot, frames=10, interval=200) def compute_riemann_trajectories(states, s, riemann_eval, wave_types=None, i_vel=1, num_left=10, num_right=10, From 38dcf01c1c897da02e842a9badfb01709b5027c5 Mon Sep 17 00:00:00 2001 From: David Ketcheson Date: Thu, 18 May 2017 10:48:56 +0300 Subject: [PATCH 12/12] Add changes from #71. --- Index.ipynb | 1 + Introduction.ipynb | 22 ++++++---------------- make_chapters.py | 1 + 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Index.ipynb b/Index.ipynb index 5398a126..7e0b3aae 100644 --- a/Index.ipynb +++ b/Index.ipynb @@ -13,6 +13,7 @@ "\n", "## Part I: The Riemann problem and its solution\n", "\n", + " 0. [Introduction](Introduction.ipynb)\n", " 1. [Advection](Advection.ipynb)\n", " 2. [Acoustics](Acoustics.ipynb)\n", " 3. [Traffic flow](Traffic_flow.ipynb)\n", diff --git a/Introduction.ipynb b/Introduction.ipynb index a8bae56b..bb7e9c2a 100644 --- a/Introduction.ipynb +++ b/Introduction.ipynb @@ -31,31 +31,21 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "from exact_solvers import shallow_water\n", - "from ipywidgets import widgets, fixed" + "from ipywidgets import widgets, fixed\n", + "from ipywidgets import interact" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#from ipywidgets import interact # for interactive widgets\n", - "#from utils.snapshot_widgets import interact # for static figure that can be viewed online\n", - "from utils.jsanimate_widgets import interact # for JSAnimation that can be viewed online" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "interact(shallow_water.make_demo_plot_function(h_l=3., h_r=1., u_l=0., u_r=0),\n", diff --git a/make_chapters.py b/make_chapters.py index 0e28c265..2a05bd83 100644 --- a/make_chapters.py +++ b/make_chapters.py @@ -2,6 +2,7 @@ import subprocess chapters = ['Preface', + 'Introduction', 'Traffic_flow', 'Shallow_water', 'Euler_approximate_solvers',