Elliptical PDE Solvers#
Motivation#
In many PDEs, we have the famous elliptical system of the form:
where \(\nabla^2\) is the Laplacian operator, \(f\) is a source term, \(u\) is the unknown, \(\mathbf{L}\) is a matrix representation of the Laplacian operator, and \(\mathbf{F}\) is a matrix representation of the source term. So we need to solve this equation for the unknown \(\mathbf{u}\). Fortunately, many PDEs have a simple linear operator, \(\nabla^2\), so we can simply solve this with an inversion method.
Typically we have to use some sort of linear solver in order to do the inverse. There are traditional inversion schemes, , e.g. Jacobi, Successive OverRelaxation (SOR), Optimized SOR, etc, but these methods can be extremely expensive because they can take a long time to converge. There are other iterative schemes which have magnitudes of order of speed up, e.g. Steepest Descent, Conjugate Gradient (CG), Preconditioned CG, Multi-Grid schemes, etc. However, there is an alternative method to solving simple elliptical PDEs whereby we use the Discrete Sine Transform. These are my notes about the formulation, the use cases and also my imagined pseudo-code.
Formulation#
Let’s take a field, \(u\), which describes some quantity of interest
and derive a time-independent solution which takes the form of a generic Elliptical PDE.
Technically, we can decompose the field, \(u\), into two fields. For example, we could have
We will propose one such decomposition here. We observe that all known boundary conditions can appear on the right hand side (RHS) of the PDE (67) because they are known. So we can write the decomposition of the PDE as an interior PDE and an exterior PDE:
We can say that the interior PDE, \(u_\mathrm{I}\), is zero along the boundaries and the exterior PDE, \(u_\mathrm{B}\), is zero everywhere except the boundaries. Notice: The only nonzero values of the \(u_\mathrm{B}\) term are along the boundaries. So we can write the PDE constraint as:
where the values along the boundary \(\partial\Omega\) are what we set them as and the values within the domain \(\Omega\) are “unknown” and the values. So we can rewrite the solution to the PDE in (67) taking into account the decomposition.
where we see that we’re left with Dirichlet boundary conditions (BC) for the interior PDE. The extra term \(\nabla^2 u_\mathrm{B}\) can be thought of as removing the contaminated values from the interior points. Now we can see that the solution to this PDE will satisfy the following decomposition
whereby we simply need to solve the interior PDE given by equation (71) and then add the boundary values from our original PDE (67).
Discrete Sine Transformation#
Now we have an elliptical PDE which is zero on all of the boundaries, i.e. Dirichlet boundary conditions. This means we can use ultra-fast methods to solve this like the Discrete Sine Transform (DST). This particular solver does work on linear Elliptical PDEs with Dirichlet boundary conditions.
The Laplacian operator in DST space is:
There are two DST types that we can use. The first one is the DST-I transform given by this equation
This transformation is useful when we have an unknown, \(u\), a RHS, \(r\), and Dirichlet BCs all on the same grid. The other type of DST transform, i.e. DST-II, and it is given by
This transformation is useful with \(u,r\) are defined at the cell center but the Dirichlet BCs are on the cell corners.
So both the interior points and the boundary values are both satisfied. Now, let’s say that the interior points, \(\vec{\mathbf{x}}\),
To rename them, let’s call PDE 1, \(u_1\), the solution of the PDE at the interior points with dirichlet boundaries, \(u_I\), and let’s call PDE 2, \(u_2\), the solution of the PDE at the boundaries with all interior points being zero, \(u_B\).
So going back to the original PDE (67), we can incorporate these constraints into the solutions:
Use Cases#
There are some PDEs where we define a PDE in terms of a derived variable however, we have access to some measurements of the original variable. For example, let’s say that we observe some variable, \(\xi\), that has a relationship with a PDE field, \(u\).
where \(\theta=\{\alpha,\beta\}\)
Example: Quasi-Geostrophic Equations
We have many approximate models for sea surface height (SSH), \(\eta\). One such model is called the Quasi-Geostrophic (QG) Equations. In this model, we can directly relate SSH to the streamfunction, \(\psi\), and subsequently the potential vorticity, \(q\). Let’s define these as scalar fields as
where the input vector \(\vec{\mathbf{x}}=[x,y]^\top\) defined on a bounded domain, \(\vec{\mathbf{x}}\in\Omega\sub\mathbb{R}^2\). Both the PV and streamfunction are derived variables of SSH given by the following relationship:
where \(a=\frac{g}{f_0},b=\frac{f_0^2}{c_1^2}\). The QG equations relate the variables via the following PDE:
To simplify the PDE, we can write everything in terms of SSH, \(\eta\). So substituting \(\eta\) into each of the derived variables \(\psi,q\) gives us
Now, we can substitute these values in terms of SSH into the QG equation.
However, the QG equations describe a PDE which time steps through a derived quantity of SSH, i.e. the Helmholtz operator, \((\alpha\nabla^2 - \beta^2)\). So this means, that we can will have boundary values of SSH but not boundary values of the Helmholtz of SSH.
Imagine we have to time step with \(\eta^n\), we need to isolate the right-hand side of the PDE, which gives us:
but of course, now we have to solve the inverse Helmholtz operator to isolate \(\eta\). Let \(\mathbf{L}_\mathrm{H}=(\nabla^2 -\beta)\) be the linear operator we wish to invert and \(\mathbf{F}=-a\det\boldsymbol{J}(\eta,\nabla^2\eta)\) be the RHS of the equation. So we would do a linear solve:
How we actually solve this equation is where we can use the generic algorithm that we outlined below. Now we can step forward in time with our generic time stepper, \(\boldsymbol{g}\), to give us the next time step \(t+1\) for \(\eta\).
Practical Algorithm#
Define field of interest
domain: Domain = ...
u: Field = init_field(domain)
f: Field = init_source(domain)
Solve PDE and BCs on the Full Field
u = PDESolver(f, rhs_fn, bcs_fn)
Parse the field into a zero field but maintaining the boundaries
u_b = zero_interior(u)
u_b = bcs_fn(u)
Apply the same PDE and Boundary Conditions on the empty Field
f_b = PDESolver(u_b, rhs_fn, bcs_fn)
Remove the Boundary Effects on the Solution
f_I = f[1:-1,1:-1] - f_b[1:-1,1:-1]
Do Inversion for Elliptical PDE
matvec_Ax: Callable = ...
u_I = LinearSolve(matvec_Ax, b=f_I)
Add the boundaries to the field
u = zeros_like(u)
u[1:-1,1:-1] = u_I
u[bc_indices] = u_B
PseudoCde#
High Level#
# get derived variable
q, u_bc = load_state(...)
# define callable function
matvec_Ax: Callable = ...
# solve for variable
u: Field = LinearSolve(q, matvec_Ax)
# add boundary conditions
u: Field = boundary_conditions(u, u_bv)
# calculate RHS
rhs: Field = RHS(u, q)
# step once
u_new: Field = TimeStepper(dt, u, rhs)