An example showing how to solve a nonlinear elliptic PDE. Also includes function-based boundary conditions.#
In this tutorial we show how Chaste can be used to solve nonlinear elliptic PDEs.
We will solve the PDE $\nabla .(u \nabla u) + 1 = 0$, on a square domain, with boundary
conditions $u=0$ on $y=0$, and Neumann boundary conditions: $(u \nabla u).\mathbf{n} = 0$ on $x=0$ and $x=1$;
and $(u \nabla u).\mathbf{n} = y$ on $y=1$.
For nonlinear PDEs, the finite element equations are of the form $\mathbf{F}(\mathbf{U})=0$, where
$\mathbf{U}=(U_1 , \dots , U_N)$ is a vector of the unknowns at each node, and $\mathbf{F}$ is some
non-linear vector valued function. To solve this, a nonlinear solver is required.
Chaste can solve this with Newton’s method, or (default) use PETSc’s nonlinear solvers.
Solvers of such nonlinear problems usually require the Jacobian of the problem, i.e. the
matrix $A = \partial F/ \partial U$, or at least an approximation of the Jacobian.
The following header files need to be included, as in the linear PDEs tutorial.
This is the solver for nonlinear elliptic PDEs.
In this test we also show how to define Neumman boundary conditions which
depend on spatial location, for which the following class is needed.
We will choose to use the Chaste Newton solver rather than PETSc’s nonlinear
solver.
As in the linear PDEs tutorial, we have to define the PDE class we want to
solve (assuming one has not already been created). Nonlinear elliptic PDEs
should inherit from AbstractNonlinearEllipticPde, which has five pure
methods which have to be implemented in this concrete class. Here, we define
the PDE $\nabla .(u \nabla u) + 1 = 0$.
The first is the part of the source term that is independent of $u$.
The second is the part of the source term that is dependent on $u$.
The third is the diffusion tensor, which unlike in the linear case can be
dependent on $u$. The diffusion tensor should be symmetric and positive definite.
We also need to provide the derivatives with respect to $u$ of the last two methods,
so that the Jacobian matrix can be assembled. The derivative of the nonlinear source
term is
And the derivative of the diffusion tensor is just the identity matrix.
We also need to define a (global) function that will become the Neumman boundary
conditions, via the FunctionalBoundaryCondition class (see below). This
function is $f(x,y) = y$.
Next, we define the test suite, as before.
Define a particular test.
As usual, first create a mesh.
Next, instantiate the PDE to be solved.
Then we have to define the boundary conditions. First, the Dirichlet boundary
condition, $u=0$ on $x=0$, using the boundary node iterator.
And then the Neumman conditions. Neumann boundary condition are defined on
surface elements, and for this problem, the Neumman boundary value depends
on the position in space, so we make use of the FunctionalBoundaryCondition
object, which contains a pointer to a function, and just returns the value
of that function for the required point when the GetValue method is called.
Loop over surface elements.
Get the $y$ value of any node (here, the zero-th).
If y=1…
… then associate the functional boundary condition, $(D \nabla u).n = y$,
with the surface element…
…else associate the zero boundary condition (i.e. zero flux) with this
element.
Note that in the above loop, the zero Neumman boundary condition was applied
to all surface elements for which $y \neq 1$, which included the Dirichlet surface
$y=0$. This is OK, as Dirichlet boundary conditions are applied to the finite
element matrix after Neumman boundary conditions, where the appropriate rows
in the matrix are overwritten.
This is the solver for solving nonlinear problems, which, as usual,
takes in the mesh, the PDE, and the boundary conditions.
The solver also needs to be given an initial guess, which will be
a PETSc vector. We can make use of a helper method to create it.
Optional: To use Chaste’s Newton solver to solve nonlinear vector equations that are
assembled, rather than the default PETSc nonlinear solvers, we can
do the following:
Optional: We can also manually set tolerances, and whether to print statistics, with
this nonlinear vector equation solver
Now call Solve, passing in the initial guess
Note that we could have got the solver to not use an analytical Jacobian
and use a numerically-calculated Jacobian instead, by passing in false as a second
parameter:
Once solved, we can check the obtained solution against the analytical
solution.
Finally, we have to remember to destroy the PETSc Vecs.