begin
import Pkg
# careful: this is _not_ a reproducible environment
# activate the local environment
Pkg.activate(".")
Pkg.instantiate()
using PlutoUI, PlutoLinks
using CairoMakie
end
@revise using Ariadne
Implicit = @ingredients(joinpath(dirname(pathof(Ariadne)), "../examples/implicit.jl"));
using SummationByPartsOperators
Caching for
du1.
function heat_1D!(du, u, (D1m, D1p), t)
du1 = D1p * u
mul!(du, D1m, du1)
return
end
heat_1D! (generic function with 1 method)
# initial conditions
f(x) = sin(x * π)
f (generic function with 1 method)
begin
xmin = 0.0
xmax = 1.0
polydeg = 3
elements = 40
end
40
begin
D_local = legendre_derivative_operator(xmin = -1.0, xmax = 1.0, N = polydeg + 1)
mesh = UniformPeriodicMesh1D(; xmin, xmax, Nx = elements)
end
UniformPeriodicMesh1D{Float64} with 40 cells in (0.0, 1.0)
begin
D1m = couple_discontinuously(D_local, mesh, Val(:minus))
D1p = couple_discontinuously(D_local, mesh, Val(:plus))
end
First derivative operator {T=Float64} on 4 Lobatto Legendre nodes in [-1.0, 1.0]
coupled discontinuously (upwind: Val{:plus}()) on UniformPeriodicMesh1D{Float64} with 40 cells in (0.0, 1.0)
x = grid(D1m);
u₀ = f.(x);
lines(x, u₀)
function solve_heat_1D(G!, x, Δt, t_final, initial_condition, p)
ts = 0.0:Δt:t_final
u₀ = initial_condition.(x)
hist = [copy(u₀)]
callback = (u) -> push!(hist, copy(u))
Implicit.solve(G!, heat_1D!, u₀, p, Δt, ts; callback)
return ts, hist
end
solve_heat_1D (generic function with 1 method)
begin
Δt = 0.01
t_final = 50.0
end
50.0
ts, hist_E = solve_heat_1D(Implicit.G_Euler!, x, Δt, t_final, f, (D1m, D1p));
_, hist_M = solve_heat_1D(Implicit.G_Midpoint!, x, Δt, t_final, f, (D1m, D1p));
_, hist_T = solve_heat_1D(Implicit.G_Trapezoid!, x, Δt, t_final, f, (D1m, D1p));
@time solve_heat_1D(Implicit.G_Midpoint!, x, Δt, t_final, f, (D1m, D1p));
function plot_timesteps(x, hist, ts, points; title = "")
fig = Figure()
ax = Axis(fig[1, 1]; title)
for p in points
lines!(ax, x, hist[p], label = "t = $(ts[p])")
end
axislegend(ax, position = :cb)
return fig
end
plot_timesteps (generic function with 1 method)
plot_timesteps(x, hist_E, ts, [1, 2, 3, 4, 5, 10, length(ts)]; title = "Euler Δt=$(Δt)")
plot_timesteps(x, hist_M, ts, [1, 2, 3, 4, 5, 10, length(ts)]; title = "Midpoint Δt=$(Δt)")
plot_timesteps(x, hist_T, ts, [1, 2, 3, 4, 5, 10, length(ts)]; title = "Trapezoid Δt=$(Δt)")
Jacobian
using LinearAlgebra
J_E = Implicit.jacobian(Implicit.G_Euler!, heat_1D!, zero(x), (D1m, D1p), 0.1, 0.0)
160×160 SparseArrays.SparseMatrixCSC{Float64, Int64} with 960 stored entries:
⎡⢻⣶⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⎤
⎢⠀⠈⠿⣧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠈⠿⣧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠈⠿⣧⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠘⠻⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠻⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⢻⣶⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣶⡀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠿⣧⡀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠿⣧⡀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠿⣧⣀⠀⎥
⎣⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠻⣦⎦
J_M = Implicit.jacobian(Implicit.G_Midpoint!, heat_1D!, zero(x), (D1m, D1p), 0.1, 0.0)
160×160 SparseArrays.SparseMatrixCSC{Float64, Int64} with 960 stored entries:
⎡⢻⣶⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⎤
⎢⠀⠈⠿⣧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠈⠿⣧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠈⠿⣧⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠘⠻⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠻⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⢻⣶⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣶⡀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠿⣧⡀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠿⣧⡀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠿⣧⣀⠀⎥
⎣⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠻⣦⎦
J_T = Implicit.jacobian(Implicit.G_Trapezoid!, heat_1D!, zero(x), (D1m, D1p), 0.1, 0.0)
160×160 SparseArrays.SparseMatrixCSC{Float64, Int64} with 960 stored entries:
⎡⢻⣶⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⎤
⎢⠀⠈⠿⣧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠈⠿⣧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠈⠿⣧⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠘⠻⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠻⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⢻⣶⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣶⡀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠿⣧⡀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠿⣧⡀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠿⣧⣀⠀⎥
⎣⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠻⣦⎦
J_M .* 2 + I == J_E
true
J_M == J_T
true
Upwind
begin
nnodes = 120
accuracy_order = 3
D = upwind_operators(
periodic_derivative_operator;
accuracy_order, xmin, xmax, N = nnodes
)
x_U = grid(D.minus)
end
0.0:0.008333333333333333:0.9916666666666667
_, hist_EU = solve_heat_1D(Implicit.G_Euler!, x_U, Δt, t_final, f, (D.minus, D.plus));
_, hist_MU = solve_heat_1D(Implicit.G_Midpoint!, x_U, Δt, t_final, f, (D.minus, D.plus));
plot_timesteps(x_U, hist_EU, ts, [1, 2, 3, 4, 5, 10, length(ts)]; title = "Euler-Upwind Δt=$(Δt)")
Oscillations at the boundary
@bind i PlutoUI.Slider(1:length(ts))
t=0.0
let
fig = Figure(title = "t = $(ts[i])")
ax = Axis(fig[1, 1])
lines!(ax, x, hist_E[i], label = "Euler")
lines!(ax, x, hist_M[i], label = "Midpoint")
# lines!(ax, x, hist_T[i], label="Trapezoid")
axislegend(ax)
fig
end
lines(x, hist_E[10])
lines(x, hist_M[10])