Package: hedges
Hyperbolic Educational Discontinuous Galerkin Equation SolverThis repository contains a Discontinuous Galerkin Python solver for 1D Hyperbolic PDEs. It is
intended to be used primarily for education and as such prioritizes clarity in the codebase over
computational efficiency or cleverness. It is designed to be extensible and modular so that support
for new hyperbolic systems is easy to implement, and comes out of the box with an example for
the 1D shallow water equations (SWE) with variable bathymetry, prescribed inflow, and free outflow.UsageOnce you've installed the dependencies listed inrequirements.txt(pip install -r requirements.txt), runningmain.pywill generate a full
animation of the SWE for several different variations on Gaussian inflows:python main.pyEach simulation result is saved in a sub-directory of theoutfolder according to the format<epoch timestamp>_<six-digit random hex>; the simulation data itself is saved insolution.csv,
the parameters for the simulation inparameters.csv, and a GIF of the solution animation is
saved atswe_1d.gif.The main script (main.py) instantiates several instances ofsimulation.SWEFlowRunner, which is
configured specifically for running simultaneous simulations for prescribed inflow and transmissive
outflow for the Shallow Water Equations. While that class may be useful as a reference
implementation for running several simulations, the following is a full example of
running a single simulation for the purpose of experimentation/modification:#!/usr/bin/env python# coding: utf-8# # 1D Discontinuous Galerkin Shallow Water Solver## We solve the 1D Shallow Water Equations in conservative form:## \begin{align*}#     h_t + q_x &= 0 \\#     q_t + \left[ \frac{q^2}{h} + \frac{1}{2} g h^2 \right]_x &= -g h b_x - C_f \left(\frac{q}{h}\right)^2# \end{align*}## We neglect friction so that $C_f = 0$.#importnumpyasnpimportmatplotlib.pyplotaspltimporthedges.bcasbcimporthedges.fluxesasfluxesimporthedges.quadratureasquadratureimporthedges.rkasrkimporthedges.swe_1d.pdeaspde# Physical parameters#g=1.0# gravity# Domain#tspan=(0.0,4.0)xspan=(-1,1)# Bathymetry parameters#b_smoothness=0.1b_amplitude=0.02b_slope=0.05assert(b_smoothness>0)# Inflow parameters#inflow_amplitude=0.05inflow_smoothness=1.0inflow_peak_time=2.0assert(inflow_amplitude>0)# Initial waveheight#h0=0.2assert(h0>0)defswe_bathymetry(x):"""Describes bathymetry with an upslope which is perturbed by a hyperbolic tangent function."""returnb_slope*x+b_amplitude*np.arctan(x/b_smoothness)defswe_bathymetry_derivative(x):"""Derivative of swe_bathymetry"""returnb_slope+b_amplitude/(b_smoothness*(1+np.square(x/b_smoothness)))defq_bc(t):"""Describes a Gaussian inflow, where the function transitions to a constant value upon attainingits maximum value.:param t: Time:return:"""t_np=np.array(t)returninflow_amplitude*np.exp(-np.square(np.minimum(t_np,inflow_peak_time*np.ones(t_np.shape))-inflow_peak_time)/(2*np.square(inflow_smoothness)))definitial_condition(x):"""Creates initial conditions for (h, uh).:param x: Computational domain:return:"""initial_height=h0*np.ones(x.shape)-swe_bathymetry(x)# horizontal water surfaceinitial_flow=q_bc(0)*np.ones(x.shape)# Start with inflow BCinitial_values=np.array((initial_height,initial_flow,))# Verify consistency of initial condition#ifnotnp.allclose(initial_values[1][0],q_bc(0)):raiseValueError('Initial flow condition must match prescribed inflow.')returninitial_values# Plot bathymetry and ICs#xl,xr=xspant0,tf=tspanxx=np.linspace(xl,xr,num=100)tt=np.linspace(t0,tf,num=100)fig,(h_ax,hv_ax,q_bc_ax)=plt.subplots(3,1)ic=initial_condition(xx)bb=swe_bathymetry(xx)qq_bc=q_bc(tt)# Plot initial wave height and bathymetry#h_ax.plot(xx,ic[0]+bb)h_ax.plot(xx,bb)h_ax.set_title('Initial wave height $h(x, 0)$')# Plot initial flow rate#hv_ax.plot(xx,ic[1])hv_ax.set_title('Initial flow rate $q(x, 0)$')# Plot flow rate at left boundary over simulation time#q_bc_ax.plot(tt,qq_bc)q_bc_ax.set_title('Boundary flow rate $q({}, t)$'.format(xl))plt.tight_layout()plt.show()# Instantiate solver with bathymetry#solver=pde.ShallowWater1D(b=swe_bathymetry,b_x=swe_bathymetry_derivative,gravity=g)t_interval_ms=20dt=t_interval_ms/1000surface_flux=fluxes.lax_friedrichs_fluxprint('Integrating ODE system...')solution=solver.solve(tspan=tspan,xspan=xspan,cell_count=16,polydeg=4,initial_condition=initial_condition,intercell_flux=surface_flux,left_boundary_flux=pde.ShallowWater1D.bc_prescribed_inflow(q_bc,gravity=g,surface_flux=surface_flux,),right_boundary_flux=bc.transmissive_boundary(surface_flux=surface_flux,direction=bc.Direction.DOWNSTREAM,),quad_rule=quadrature.gll,**{'method':rk.SSPRK33,'t_eval':np.arange(tspan[0],tspan[1],dt),'max_step':dt,# max time step for ODE solver'rtol':1.0e-6,'atol':1.0e-6,})# Plot solution animation#ani,plt=solver.plot_animation(solution,frame_interval=t_interval_ms)# Save animation to file#movie_name='swe_1d.gif'print('Writing movie to{}...'.format(movie_name))ani.save(movie_name,progress_callback=lambdai,n:print(f'Saving animation frame{i+1}/{n}')ifi%50==0elseNone)print('Animation written to{}.'.format(movie_name))plt.show()Theplot_animationfunction of thehedges.hyperbolic_solver_1d.Hyperbolic1DSolverbase class returns
a tuple of the form
(FuncAnimation,matplotlib) which
may be used to save individual frames or modify plots as desired. Subclass implementations may
optionally override the default plotting behavior, with a reference implementation provided inhedges.swe_1d.ShallowWater1D.A Jupyter notebook is provided in this repository athedges/main.ipynb, and may be viewed (and
interacted with) atBinderHub.Extending the SolverCurrently, only the 1D Shallow Water equations are implemented. However, support can easily be added
for other 1D hyperbolic PDE systems by simply subclassinghedges.hyperbolic_solver_1d.Hyperbolic1DSolverand implementing the fluxF(u), sourceS(u), and flux JacobianF'(u)terms for the desired
system in conservative form. Seehedges.swe_1d.ShallowWater1Dfor a reference implementation.A local Lax-Friedrichs flux is used as the approximate Riemann solver between cell
interfaces, but thesolvemethod of thehedges.hyperbolic_solver_1d.Hyperbolic1DSolverclass accepts
a function reference which can be used to implement e.g. HLL flux (or exact Riemann solvers).