Setting up your own problem¶
The best way to set up a new problem is to find an existing problem setup that is similar. The main steps are:
- Write the initialization script
- Write routines for source terms, custom boundary conditions, or other customizations
- Write a Riemann solver (if solving a new system of equations)
- Write a Makefile if using any custom Fortran code
- Write a setplot.py file for visualization
If needed for your problem, custom Riemann solvers, boundary condition routines, source term routines, and other functions can all be written in Python but you may prefer to write some of them in Fortran for performance reasons. The latter approach requires direct use of f2py. See Porting a problem from Clawpack 4.6.x to PyClaw for more details.
Writing the initialization script¶
This script should:
- Import the appropriate package (pyclaw or petclaw)
- Instantiate a
Solver
and specify the Riemann solver to use- Set the boundary conditions
- Define the domain through a
Domain
object- Define a
Solution
object- Set the initial condition
Usually the script then instantiates a Controller
, sets the
initial solution and solver, and calls run()
.
Setting initial conditions¶
Once you have initialized a Solution object, it contains a member state.q whose first dimension is num_eqn and whose remaining dimensions are those of the grid. Now you must set the initial condition. For instance
>>> import numpy as np
>>> Y,X = np.meshgrid(state.grid.y.centers,state.grid.x.centers)
>>> r = np.sqrt(X**2 + Y**2)
>>> width = 0.2
>>> state.q[0,:,:] = (np.abs(r-0.5)<=width)*(1.+np.cos(np.pi*(r-0.5)/width))
>>> state.q[1,:,:] = 0.
>>> state.q[2,:,:] = 0.
Note that in a parallel run we only wish to set the local values of the state
so the appropriate geometry object to use here is the
Grid
class.
Setting auxiliary variables¶
If the problem involves coefficients that vary in space or a mapped grid, the required fields are stored in state.aux. In order to use such fields, you must pass the num_aux argument to the State initialization
>>> state = pyclaw.State(domain,solver.num_eqn,num_aux)
The number of fields in state.aux (i.e., the length of its first dimension) is set equal to num_aux. The values of state.aux are set in the same way as those of state.q.
Setting boundary conditions¶
The boundary conditions are specified through solver.bc_lower and
solver.bc_upper, each of which is a list of length solver.num_dim
. The
ordering of the boundary conditions in each list is the same as the ordering of
the Dimensions in the Grid; typically \((x,y)\). Thus
solver.bc_lower[0]
specifies the boundary condition at the left boundary
and solver.bc_upper[0]
specifies the condition at the right boundary.
Similarly, solver.bc_lower[1]
and solver.bc_upper[1]
specify the
boundary conditions at the top and bottom of the domain.
PyClaw includes the following built-in boundary condition implementations:
pyclaw.BC.periodic
- periodicpyclaw.BC.extrap
- zero-order extrapolationpyclaw.BC.wall
- solid wall conditions, assuming that the 2nd/3rd component of q is the normal velocity in x/y.
Other boundary conditions can be implemented by using pyclaw.BC.custom
, and
providing a custom BC function. The attribute solver.user_bc_lower/upper must
be set to the corresponding function handle. For instance
>>> def custom_bc(state,dim,t,qbc,num_ghost):
... for i in xrange(num_ghost):
... qbc[0,i,:] = q0
>>> solver.bc_lower[0] = pyclaw.BC.custom
>>> solver.user_bc_lower = custom_bc
If the state.aux
array is used, boundary conditions must be set for it
in a similar way, using solver.aux_bc_lower
and solver.aux_bc_upper
.
Note that although state is passed to the BC routines, they should
NEVER modify state. Rather, they should modify qbc/auxbc.
Setting solver options¶
Using your own Riemann solver¶
The Riemann package has solvers for many hyperbolic systems. If your problem involves a new system, you will need to write your own Riemann solver. A nice example of how to compile and import your own Riemann solver can be seen `here https://github.com/damiansra/empyclaw/tree/master/maxwell_1d_homogeneous`_. You will need to:
- Put the Riemann solver in the same directory as your Python script
- Write a short makefile calling f2py
- import the Riemann solver module in your Python script
Here are some tips if you are converting an old Clawpack 4.5 or earlier Riemann solver:
- Rename the file from .f to .f90 and switch to free-format Fortran
- Move the spatial index (i) to the last place in all array indexing
Please do contribute your solver to the package by sending a pull request on Github or e-mailing one of the developers. To add your Riemann solver to the Clawpack Riemann package, you will need to:
- Place the .f90 file(s) in clawpack/riemann/src.
- Add the solver to the list in clawpack/riemann/setup.py
- Add the solver to the list in clawpack/riemann/src/python/riemann/setup.py
- Add the solver to the list in clawpack/riemann/src/python/riemann/Makefile
- Add the solver to the list in clawpack/riemann/src/python/riemann/__init__.py
For very simple problems in one dimension, it may be worthwhile to write the Riemann solver in Python, especially if you are more comfortable with Python than with Fortran. For two-dimensional problems, or one-dimensional problems requiring fine grids (or if you are impatient) the solver should be written in Fortran. The best approach is generally to find a similar solver in the Riemann package and modify it to solve your system.
Adding source terms¶
Non-hyperbolic terms (representing, e.g., reaction or diffusion) can be included in a PyClaw simulation by providing an appropriate function handle to
- solver.step_source if using Classic Clawpack. In this case, the function specified should modify q by taking a step on the equation \(q_t = \psi(q)\).
- solver.dq_src if using SharpClaw. In this case, the function should return \(\Delta t \cdot \psi(q)\).
For an example, see pyclaw/examples/euler_2d/shockbubble.py.
Setting up the Makefile¶
Generally you can just copy the Makefile from an example in pyclaw/examples and replace the value of RP_SOURCES. Make sure the example you choose has the same dimensionality. Also be sure to use the f-wave targets if your Riemann solver is an f-wave solver.