PyClaw is a solver for hyperbolic PDEs, based on Clawpack. You can read more about PyClaw in this paper (free version here.
In this notebook, we explore some basic PyClaw functionality. Before running the notebook, you should install Clawpack. The quick way is to just
pip install clawpack
In [ ]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from clawpack import pyclaw
from clawpack import riemann
To solve a problem, we'll need to create the following:
Let's start by creating a controller and specifying the simulation end time:
In [ ]:
claw = pyclaw.Controller()
claw.tfinal = 1.0
claw.keep_copy = True # Keep solution data in memory for plotting
claw.output_format = None # Don't write solution data to file
claw.num_output_times = 50 # Write 50 output frames
Like many solvers for nonlinear hyperbolic PDEs, PyClaw uses Riemann solvers. By specifying a Riemann solver, we will specify the system of PDEs that we want to solve.
Place your cursor at the end of the line in the box below and hit 'Tab' (for autocompletion). You'll see a dropdown list of all the Riemann solvers currently available in PyClaw. The ones with 'py' at the end of the name are written in pure Python; the others are Fortran, wrapped with f2py.
Note that this won't work if you're viewing the notebook online as HTML; you need to actually be running it.
In [ ]:
riemann.
We'll solve the one-dimensional acoustics equations: $$\begin{align} p_t + K u_x & = 0 \\ u_t + \frac{1}{\rho} p_x & = 0. \end{align}$$ Here $p, u$ are the pressure and velocity as functions of $x,t$, while $\rho, K$ are constants representing the density and bulk modulus of the material transmitting the waves. We'll specify these constants later.
We can do this using the first solver in the list. Notice that the solver we create here belongs to the controller that we created above.
In [ ]:
riemann_solver = riemann.acoustics_1D
claw.solver = pyclaw.ClawSolver1D(riemann_solver)
We also need to specify boundary conditions. We'll use periodic BCs, so that waves that go off one side of the domain come back in at the other:
In [ ]:
claw.solver.all_bcs = pyclaw.BC.periodic
In [ ]:
domain = pyclaw.Domain( (0.,), (1.,), (100,))
In [ ]:
claw.solution = pyclaw.Solution(claw.solver.num_eqn,domain)
The initial data is specified in an array named $q$. The pressure is contained in q[0,:] and the velocity in q[1,:]. We'll specify a wavepacket for the pressure and zero velocity.
In [ ]:
x=domain.grid.x.centers
bet=100; gam=5; x0=0.75
claw.solution.q[0,:] = np.exp(-bet * (x-x0)**2) * np.cos(gam * (x - x0))
claw.solution.q[1,:] = 0.
plt.plot(x, claw.solution.q[0,:],'-o')
In [ ]:
riemann_solver.cparam.
Two of these parameters are $\rho$ and $K$ in the equations above. The other two are the impedance $Z = \sqrt{\rho K}$ and sound speed $c = \sqrt{K/\rho}$. We specify these parameters in a dictionary that belongs to the solution object:
In [ ]:
import numpy as np
density = 1.0
bulk_modulus = 1.0
impedance = np.sqrt(density*bulk_modulus)
sound_speed = np.sqrt(density/bulk_modulus)
claw.solution.state.problem_data = {
'rho' : density,
'bulk': bulk_modulus,
'zz' : np.sqrt(density*bulk_modulus),
'cc' : np.sqrt(bulk_modulus/density)
}
Finally, let's run the simulation.
In [ ]:
status = claw.run()
In [ ]:
pressure = claw.frames[50].q[0,:]
plt.plot(x,pressure,'-o')
To examine the evolution more thoroughly, it's nice to see all the frames in sequence. We can do this as follows.
NOTE: The JSAnimation does not work below. If you execute this cell and try to start the animation, the javascript goes into an infinite loop.
In [ ]:
from matplotlib import animation
import matplotlib.pyplot as plt
from clawpack.visclaw.JSAnimation import IPython_display
import numpy as np
fig = plt.figure()
ax = plt.axes(xlim=(0, 1), ylim=(-0.2, 1.2))
frame = claw.frames[0]
pressure = frame.q[0,:]
line, = ax.plot([], [], lw=2)
def fplot(frame_number):
frame = claw.frames[frame_number]
pressure = frame.q[0,:]
line.set_data(x,pressure)
return line,
animation.FuncAnimation(fig, fplot, frames=len(claw.frames), interval=30)
That's it! Here are some things you might try for fun:
pyclaw.BC.+[Tab] to get a list of boundary conditions available).SharpClawSolver1D instead of a ClawSolver1D. How does this affect the final solution? You can read more about the methods in SharpClaw in this paper.
In [ ]: