∗ Multigrid
pyro solves elliptic problems (like Laplace's equation or Poisson's equation) through multigrid. This accelerates the convergence of simple relaxation by moving the solution down and up through a series of grids. Chapter 8 of the notes describe the basics of multigrid:
There are three solvers:

The core solver, provided in the class MG.CellCenterMG2d
solves constantcoefficient Helmholtz problems of the form:
(α  β ∇^{2}) φ = f

The class variable_coeff_MG.VarCoeffCCMG2d solves variable
coefficient Poisson problems of the form:
∇· (η ∇ φ) = f
This class inherits the core functionality from MG.CellCenterMG2d. 
The class general_MG.GeneralMG2d solves a general elliptic
equation of the form:
αφ + ∇· (β ∇ φ) + γ · ∇ φ = f
This class inherits the core functionality from MG.CellCenterMG2d. This solver is the only one to support inhomogeneous boundary conditions.
We simply use Vcycles in our implementation, and restrict ourselves to square grids with zoning a power of 2.
The multigrid solver is not controlled through pyro.py since there is no timedependence in pure elliptic problems. Instead, there are a few scripts in the multigrid/ subdirectory that demonstrate its use.
∗ Examples
multigrid test
A basic multigrid test is run as:
./mg_test_simple.py
The mg_test_simple.py script solves a Poisson equation with a known analytic solution. This particular example comes from the text "A Multigrid Tutorial, 2nd Ed.". The example is:
u_{xx} + u_{yy} =
2 [(16x^{2})y^{2}(1y^{2}) +
(16y^{2})x^{2}(1x^{2})]
on [0,1] × [0,1] with u = 0 on the boundary.
The solution to this is shown below.
Since this has a known analytic solution:
u(x,y) = (x^{2}  x^{4})(y^{4}  y^{2})
We can assess the convergence of our solver by running at a variety of resolutions and computing the norm of the error with respect to the analytic solution. This is shown below:
The dotted line is 2^{nd} order convergence, which we match perfectly.
The movie below shows the smoothing at each level to realize this solution:
projection
Another example that uses multigrid to extract the divergence free part of a velocity field is run as:
./projectperiodic.py
Given a vector field, U, we can decompose it into a divergence free part, U^{d}, and the gradient of a scalar, φ:
U = U^{d} + ∇ φ
We can project out the divergence free part by taking the divergence, leading to an elliptic equation:
∇^{2} φ = ∇ · U
The projectperiodic.py script starts with a divergence free velocity field, adds to it the gradient of a scalar, and then projects it to recover the divergence free part. The error can found by comparing the original velocity field to the recovered field. The results are shown below:
Left is the original u velocity, middle is the modified field after adding the gradient of the scalar, and right is the recovered field.
Jupyter Notebook
A jupyter notebook showing how to use the basic solver can be found here: multigridexamples.ipynb
∗ Exercises
Explorations
 Try doing just smoothing, no multigrid. Show that it still converges second order if you use enough iterations, but that the amount of time needed to get a solution is much greater.
Extensions
 Implement inhomogeneous dirichlet boundary conditions
 Add a different bottom solver to the multigrid algorithm
 Make the multigrid solver work for nonsquare domains