# 2021-10-15 Sparse Linear Algebra¶

## Last time¶

• Note on p-Laplacian activity

• Weak forms and jump conditions

• 2D wave equations via gas dynamics

• Appropriate time integrators

• Hamiltonian structure and energy drift

## Today¶

• Recap and questions

• Sparse direct solvers

• matrix orderings

• impact on formulation

• cost scaling

• Why iterative solvers

• Discussion with Ioana Fleming

using Plots
using LinearAlgebra
using SparseArrays

default(linewidth=4)

function plot_stability(Rz, title; xlims=(-2, 2), ylims=(-2, 2))
x = LinRange(xlims, xlims, 100)
y = LinRange(ylims, ylims, 100)
heatmap(x, y, (x, y) -> abs(Rz(x + 1im*y)), c=:bwr, clims=(0, 2), aspect_ratio=:equal, title=title)
end

struct RKTable
A::Matrix
b::Vector
c::Vector
function RKTable(A, b)
s = length(b)
A = reshape(A, s, s)
c = vec(sum(A, dims=2))
new(A, b, c)
end
end

function rk_stability(z, rk)
s = length(rk.b)
1 + z * rk.b' * ((I - z*rk.A) \ ones(s))
end

rk4 = RKTable([0 0 0 0; .5 0 0 0; 0 .5 0 0; 0 0 1 0], [1, 2, 2, 1] / 6)

function ode_rk_explicit(f, u0; tfinal=1., h=0.1, table=rk4)
u = copy(u0)
t = 0.
n, s = length(u), length(table.c)
fY = zeros(n, s)
thist = [t]
uhist = [u0]
while t < tfinal
tnext = min(t+h, tfinal)
h = tnext - t
for i in 1:s
ti = t + h * table.c[i]
Yi = u + h * sum(fY[:,1:i-1] * table.A[i,1:i-1], dims=2)
fY[:,i] = f(ti, Yi)
end
u += h * fY * table.b
t = tnext
push!(thist, t)
push!(uhist, u)
end
thist, hcat(uhist...)
end

function laplacian_matrix(n)
"Laplacian in n×n periodic domain"
h = 2 / n
rows = Vector{Int64}()
cols = Vector{Int64}()
vals = Vector{Float64}()
wrap(i) = (i + n - 1) % n + 1
idx(i, j) = (wrap(i)-1)*n + wrap(j)
stencil_diffuse = [-1, -1, 4, -1, -1] / h^2
for i in 1:n
for j in 1:n
append!(rows, repeat([idx(i,j)], 5))
append!(cols, [idx(i-1,j), idx(i,j-1), idx(i,j), idx(i+1,j), idx(i,j+1)])
append!(vals, stencil_diffuse)
end
end
sparse(rows, cols, vals)
end

laplacian_matrix (generic function with 1 method)


# Two forms of acoustic wave equation¶

Divide the momentum equation through by background density and dropping the tildes yields the standard form.

$\begin{split}\begin{pmatrix} \rho \\ \mathbf u \end{pmatrix}_t + \nabla\cdot \begin{bmatrix} \bar\rho \mathbf u \\ \rho \frac{a^2}{\bar\rho} I \end{bmatrix} = 0 .\end{split}$

Examine second equation

$\frac{a^2}{\bar\rho} \nabla\cdot\big[ \rho I \big] = \frac{a^2}{\bar\rho} \nabla \rho$
and thus \begin{pmatrix} \rho \ \mathbf u \end{pmatrix}_t +

(24)$\begin{bmatrix} & \bar\rho \nabla\cdot \\ \frac{a^2}{\bar\rho} \nabla & \\ \end{bmatrix}$
(25)$\begin{pmatrix} \rho \\ \mathbf u \end{pmatrix}$

Let’s differentiate the first equation,

$\rho_{tt} + \bar\rho\nabla\cdot(\mathbf u_t) = 0$
and substitute in the second equation
$\rho_{tt} = a^2 \nabla\cdot(\nabla \rho)$

• Note: we had to assume these derivatives exist!

We can reduce this to a first order system as

$\begin{split}\begin{pmatrix} \rho \\ \dot \rho \end{pmatrix}_t + \begin{bmatrix} & -I \\ -a^2 \nabla\cdot\nabla & \end{bmatrix} \begin{pmatrix} \rho \\ \dot\rho \end{pmatrix} = 0\end{split}$

## Question¶

• How is the problem size different?

• What might we be concerned about in choosing the second formulation?

# Wave operator¶

$\begin{split}\begin{pmatrix} \rho \\ \dot \rho \end{pmatrix}_t = \begin{bmatrix} & I \\ a^2 \nabla\cdot\nabla & \end{bmatrix} \begin{pmatrix} \rho \\ \dot\rho \end{pmatrix}\end{split}$
function wave_matrix(n; a=1)
Z = spzeros(n^2, n^2)
L = laplacian_matrix(n)
[Z I; -a^2*L Z]
end
wave_matrix(2)

8×8 SparseMatrixCSC{Float64, Int64} with 16 stored entries:
⋅     ⋅     ⋅     ⋅   1.0   ⋅    ⋅    ⋅
⋅     ⋅     ⋅     ⋅    ⋅   1.0   ⋅    ⋅
⋅     ⋅     ⋅     ⋅    ⋅    ⋅   1.0   ⋅
⋅     ⋅     ⋅     ⋅    ⋅    ⋅    ⋅   1.0
-4.0   2.0   2.0    ⋅    ⋅    ⋅    ⋅    ⋅
2.0  -4.0    ⋅    2.0   ⋅    ⋅    ⋅    ⋅
2.0    ⋅   -4.0   2.0   ⋅    ⋅    ⋅    ⋅
⋅    2.0   2.0  -4.0   ⋅    ⋅    ⋅    ⋅

A = wave_matrix(8; a=2) * .1
ev = eigvals(Matrix(A))
plot_stability(z -> rk_stability(z, rk4), "RK4", xlims=(-4, 4), ylims=(-4, 4))
scatter!(real(ev), imag(ev), color=:black) # Example 2D wave solver with RK4¶

n = 20
A = wave_matrix(n)
x = LinRange(-1, 1, n+1)[1:end-1]
y = x
rho0 = vec(exp.(-9*((x .+ 1e-4).^2 .+ y'.^2)))
sol0 = vcat(rho0, zero(rho0))
thist, solhist = ode_rk_explicit((t, sol) -> A * sol, sol0, h=.02)
size(solhist)

(800, 51)

@gif for tstep in 1:length(thist)
rho = solhist[1:n^2, tstep]
contour(x, y, reshape(rho, n, n), title="\$t =$(thist[tstep])\\$")
end

┌ Info: Saved animation to
│   fn = /home/jed/cu/numpde/slides/tmp.gif
└ @ Plots /home/jed/.julia/packages/Plots/1RWWg/src/animation.jl:114