Skip to content

Commit bbe3545

Browse files
committed
Revive SSPKnoth
1 parent b3dbb71 commit bbe3545

File tree

16 files changed

+940
-331
lines changed

16 files changed

+940
-331
lines changed

docs/Manifest.toml

Lines changed: 200 additions & 268 deletions
Large diffs are not rendered by default.

docs/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
1111
DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244"
1212
Krylov = "ba0b0d4f-ebba-5204-a429-3ac8c609bfb7"
1313
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
14+
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
1415
NVTX = "5da4648a-3479-48b8-97b9-01cb529c0a1f"
1516
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
1617
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
1718
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
19+
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
1820
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

docs/make.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
using Documenter, DocumenterCitations
22
using ClimaTimeSteppers
3+
using Literate
4+
5+
tutorial_basedir = "tutorials"
6+
tutorial_basedir_from_here = joinpath(@__DIR__, "src", tutorial_basedir)
7+
8+
jl_files_in_basedir = filter(endswith(".jl"), readdir(tutorial_basedir_from_here))
9+
10+
println("Building literate tutorials...")
11+
generated_tutorials = String[]
12+
for filename in jl_files_in_basedir
13+
Literate.markdown(
14+
joinpath(tutorial_basedir_from_here, filename),
15+
tutorial_basedir_from_here;
16+
flavor = Literate.CommonMarkFlavor(),
17+
)
18+
push!(generated_tutorials, joinpath(tutorial_basedir, replace(filename, ".jl" => ".md")))
19+
end
320

421
# https://github.com/jheinen/GR.jl/issues/278#issuecomment-587090846
522
ENV["GKSwstype"] = "nul"
@@ -12,12 +29,14 @@ pages = [
1229
"Algorithm Formulations" => [
1330
"ODE Solvers" => "algorithm_formulations/ode_solvers.md",
1431
"Newtons Method" => "algorithm_formulations/newtons_method.md",
32+
"Rosenbrock Method" => "algorithm_formulations/rosenbrock.md",
1533
"Old LSRK Formulations" => "algorithm_formulations/lsrk.md",
1634
"Old MRRK Formulations" => "algorithm_formulations/mrrk.md",
1735
],
1836
"Test problems" => [
1937
"test_problems/index.md",
2038
],
39+
"Tutorials" => generated_tutorials,
2140
"API docs" => [
2241
"ODE Solvers" => "api/ode_solvers.md",
2342
"Newtons Method" => "api/newtons_method.md",
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Rosenbrock methods
2+
3+
In this page, we introduce Rosenbrock-type methods to solve ordinary
4+
differential equations. In doing do, we roughly follow Chapter IV.7 of "Solving
5+
Ordinary Differential Equations II" by Hairer and Wanner. (Beware, notation is
6+
not the same.). In this spirit, let us introduce the need for Rosenbrock-type
7+
methods in the same way as Hairer and Wanner, by quoting Rosenbrock himself:
8+
9+
> When the functions are non-linear, implicit equations can in general be solved
10+
> only by iteration. This is a severe drawback, as it adds to the problem of
11+
> stability, that of convergence of the iterative process. An alternative, which
12+
> avoids this difficulty, is ...
13+
14+
Rosenbrock method!
15+
16+
Before reading this page, we recommend reading the page on ODE solvers first
17+
[TODO: Add link]
18+
19+
## Introduction to the formalism
20+
21+
Let us consider an ordinary differential equation of the form
22+
23+
$$ \frac{d}{dt}u(t) = T(u(t), t)\,,$$
24+
25+
where $u$ is the state, $T$ is the tendency,
26+
and $t$ the time. For the sake of simplicity, let us ignore the explicit time
27+
dependency in the tendency (we will get back to that at the end).
28+
29+
The simplest way to introduce the Rosenbrock method is to start from a
30+
diagonally implicit Runge-Kutta scheme (see page on DIRK). In an implicit
31+
Runge-Kutta method with $s$ stages and tableau $a, b, c$, the updated value
32+
$u_1$ for a step of size $\Delta t$ is obtained starting from the known value $u_0$
33+
with
34+
35+
$$ u_1 = u_0 + \sum_{i=1}^s b_i k_i\,, $$
36+
with
37+
$$ k_i = \Delta t T ( u_0 + \sum_{j=1}^{i-1}\alpha_{ij}k_j + \alpha_{ii} k_i)\,. $$
38+
$\alpha_{ij}$, $b_i$ are carefully chosen coefficients.
39+
40+
Rosenbrock's idea consists in linearizing $T$. This operation can be interpreted
41+
as taking one iteration for Netwon solver and yields
42+
43+
$$ k_i = \Delta t T(g_i) + \Delta t T'(g_i) \alpha_{ii} k_i $$
44+
45+
with $J(g_i)$ Jacobian of the tendency and with
46+
47+
$$ g_i = u_0 + \sum_{j=1}^{i-1}\alpha_{ij} k_j $$
48+
49+
In Rosenbrock-type methods, the Jacobian $T'$ is replaced with linear combinations
50+
of the Jacobian evaluated at $u_0$, $J$:
51+
$$ T'(g_i) \alpha_{ii} k_i \approx J \sum_{j=1}^{i-1}\gamma_{ij} k_j + J \gamma_{ii} k_i\,,$$
52+
with $\gamma_{ij}$ other coefficients that can be chosen.
53+
54+
Now, each stage consists of solving a system of linear equations in $k_i$ with
55+
matrix $I - \Delta t \gamma_{ii}$: $$ (I - J \Delta t \gamma_{ii}) k_i = \Delta
56+
t T(g_i) + J \sum_{j=1}^{i-1}\gamma_{ij} k_j$$ for each $i$ in $1, \dots, s$.
57+
Once $k_i$ are known, $u_1$ can is easily computed and the process repeated for
58+
the next step.
59+
60+
In practice, there are computational advantages at implementing a slight
61+
variation of what presented here.
62+
63+
Let us define $\tilde{k}_{i} = \sum_{j=1}^{i} \gamma_{ij} k_j$. If the matrix
64+
$\gamma_{ij}$ is invertible, we can move freely from $k_i$ to $\tilde{k}_i$. A
65+
convenient step is to also define $C$, as
66+
67+
$$ C = diag(\gamma_{11}^{-1}, \gamma_{22}^{-1}, \dots, \gamma_{ss}^{-1}) - \Gamma^{-1} $$
68+
69+
Which establishes that
70+
71+
$$ k_i = \frac{\tilde{k}_i}{\gamma_{ii}} - \sum_{j=1}^{i -1} c_{ij} \tilde{k}_j$$
72+
Substituting this, we obtain the following equations
73+
74+
$$ (J \Delta t \gamma_{ii} - 1) \tilde{k}_i = - \Delta
75+
t \gamma_{ii} T(g_i) - \gamma_{ii} J \sum_{j=1}^{i-1}c_{ij} \tilde{k}_j \,, $$
76+
77+
$$ g_i = u_0 + \sum_{j=1}^{i-1}a_{ij} \tilde{k}_j \,,$$
78+
79+
$$ u_1 = u_0 + \sum_{j=1}^{s} m_j \tilde{k}_j\,,$$
80+
with
81+
$$ (a_{ij}) = (\alpha_{ij}) \Gamma^{-1}\,, $$ and $$ (m_i) = (b_i) \Gamma^{-1} $$
82+
83+
Finally, small changes are required to add support for explicit time derivative:
84+
85+
$$ (J \Delta t \gamma_{ii} - 1) \tilde{k}_i = - \Delta
86+
t \gamma_{ii} T( t_0 + \alpha_i \Delta t, g_i) - \gamma_{ii} J \sum_{j=1}^{i-1}c_{ij} \tilde{k}_j - \Delta
87+
t \gamma_{ii} \gamma_i \Delta
88+
t \frac{\partial T}{\partial t}(t_0, u_0) $$
89+
90+
where we defined
91+
92+
$\alpha_{i} = \sum_{j=1}^{i-1}\alpha_{ij} $
93+
94+
$ \gamma _{i} = \sum_{j=1}^{i}\gamma_{ij} $
95+
96+
> :note: You may wonder, what is up with all these ugly minus signs? Why don't
97+
> we cancel them out? The reason for this is because we want to have the
98+
> prefactor $(J \Delta t \gamma_{ii} - 1)$. This is called `Wfact` in the
99+
> language of `DifferentialEquations.jl`. Most other algorithms specify this
100+
> quantity, so it is convenient to be consistent.
101+
102+
## Implementation
103+
104+
In `ClimaTimeSteppers.jl`, we implement the last equation presented in the
105+
previous section. Currently, the only Rosenbrock-type algorithm implemented is
106+
`SSPKnoth`. `SSPKnoth` is 3-stage, second-order accurate Rosenbrock with
107+
108+
$$ \alpha = \begin{bmatrix}
109+
0 & 0 & 0 \\
110+
1 & 0 & 0 \\
111+
\frac{1}{4} & \frac{1}{4} & 0 \\
112+
\end{bmatrix} $$
113+
114+
$$ \Gamma = \begin{bmatrix}
115+
1 & 0 & 0 \\
116+
1 & 1 & 0 \\
117+
-\frac{3}{4} & \frac{3}{4} & 1 \\
118+
\end{bmatrix} $$
119+
120+
and $$ b = (\frac{1}{6}, \frac{1}{6}, \frac{2}{3}) $$.
121+
122+
At each stage, the state is updated to $g_i$ and precomputed quantities are updated. Tendencies are computed and, unless the stage is the last, DSS is applied to the sum of all the tendencies. After the last stage, DSS is applied to the incremented state.

docs/src/api/ode_solvers.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ HOMMEM1
5151
ARK2GKC
5252
ARK437L2SA1
5353
ARK548L2SA2
54+
SSPKnoth
5455
```
5556

5657
## Explicit Algorithm Names

docs/src/dev/report_gen.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ let # Convergence
1717
title = "All Algorithms"
1818
algorithm_names = map(T -> T(), all_subtypes(ClimaTimeSteppers.AbstractAlgorithmName))
1919
algorithm_names = filter(name -> !(name isa ARK437L2SA1 || name isa ARK548L2SA2), algorithm_names) # too high order
20+
21+
# NOTE: Some imperfections in the convergence order for SSPKnoth are to be
22+
# expected because we are not using the exact Jacobian
23+
2024
verify_convergence(title, algorithm_names, ark_analytic_nonlin_test_cts(Float64), 200)
2125
verify_convergence(title, algorithm_names, ark_analytic_sys_test_cts(Float64), 400)
2226
verify_convergence(title, algorithm_names, ark_analytic_test_cts(Float64), 40000; super_convergence = (ARS121(),))
@@ -29,6 +33,8 @@ let # Convergence
2933
num_steps_scaling_factor = 4,
3034
numerical_reference_algorithm_name = ARS343(),
3135
)
36+
rosenbrock_schems = filter(name -> name isa ClimaTimeSteppers.RosenbrockAlgorithmName, algorithm_names)
37+
verify_convergence(title, rosenbrock_schems, climacore_1Dheat_test_implicit_cts(Float64), 400)
3238
verify_convergence(
3339
title,
3440
algorithm_names,

docs/src/plotting_utils.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ imex_convergence_orders(::ARK548L2SA2) = (5, 5, 5)
5959
imex_convergence_orders(::SSP22Heuns) = (2, 2, 2)
6060
imex_convergence_orders(::SSP33ShuOsher) = (3, 3, 3)
6161
imex_convergence_orders(::RK4) = (4, 4, 4)
62+
# SSPKnoth is not really an IMEX method
63+
imex_convergence_orders(::SSPKnoth) = (2, 2, 2)
6264

6365
# Compute a confidence interval for the convergence order, returning the
6466
# estimated convergence order and its uncertainty.
@@ -113,6 +115,8 @@ function verify_convergence(
113115
default_dt = t_end / num_steps
114116

115117
algorithm(algorithm_name::ClimaTimeSteppers.ERKAlgorithmName) = ExplicitAlgorithm(algorithm_name)
118+
algorithm(algorithm_name::ClimaTimeSteppers.SSPKnoth) =
119+
ClimaTimeSteppers.RosenbrockAlgorithm(ClimaTimeSteppers.tableau(ClimaTimeSteppers.SSPKnoth()))
116120
algorithm(algorithm_name::ClimaTimeSteppers.IMEXARKAlgorithmName) =
117121
IMEXAlgorithm(algorithm_name, NewtonsMethod(; max_iters = linear_implicit ? 1 : 2))
118122

0 commit comments

Comments
 (0)