Skip to content

Commit 430b75a

Browse files
Merge #129
129: Move `test_algs` to docs, split env r=charleskawczynski a=charleskawczynski This PR: - Moves `test_algs` to the docs, since it's mostly concerned with plotting - Removes `Plots` from the test env, and adds Plots to the docs env - Adds a docs section for test problems, where we can add more documentation to the problems we're testing - Adds a docs Manifest file, since we'll dev CTS there - Adds a small helper function, `problem_algo` that we can use in the test and plotting code I tried out ODEConvergenceTester.jl with these problems, and it's working nicely, so I'm inclined to use that in addition to our comparison plots, which I'm fine with extending. #115 improves some aspects of the plotting, but it seems a bit more like a report generator, and I'd like to think a bit more about how we want to pave the way towards mature documentation. In addition, the latex strings seem a bit cumbersome to maintain compared to plain markdown / equations This is a step towards #122. Co-authored-by: Charles Kawczynski <[email protected]>
2 parents 38a54a0 + d8331c0 commit 430b75a

File tree

12 files changed

+732
-188
lines changed

12 files changed

+732
-188
lines changed

docs/Manifest.toml

Lines changed: 532 additions & 1 deletion
Large diffs are not rendered by default.

docs/Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
[deps]
22
ClimaTimeSteppers = "595c0a79-7f3d-439a-bc5a-b232dc3bde79"
3+
DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e"
34
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
45
DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244"
6+
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
7+
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
8+
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

docs/make.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ makedocs(
1818
"newtons_method.md",
1919
"callbacks.md",
2020
"Background" => ["background/lsrk.md", "background/ssprk.md", "background/ark.md", "background/mrrk.md"],
21+
"test_problems.md",
22+
"algo_comparisons.md",
2123
"references.md",
2224
],
2325
)

docs/src/algo_comparisons.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using ClimaTimeSteppers
2+
using Test
3+
cts_dir = pkgdir(ClimaTimeSteppers)
4+
5+
ENV["GKSwstype"] = "nul" # avoid displaying plots
6+
7+
include(joinpath(@__DIR__, "plotting_utils.jl"))
8+
include(joinpath(cts_dir, "test", "utils.jl"))
9+
include(joinpath(cts_dir, "test", "problems.jl"))
10+
11+
@testset "IMEX ARK Algorithms" begin
12+
tab1 = (ARS111, ARS121)
13+
tab2 = (ARS122, ARS232, ARS222, IMKG232a, IMKG232b, IMKG242a, IMKG242b)
14+
tab2 = (tab2..., IMKG252a, IMKG252b, IMKG253a, IMKG253b, IMKG254a)
15+
tab2 = (tab2..., IMKG254b, IMKG254c, HOMMEM1)
16+
tab3 = (ARS233, ARS343, ARS443, IMKG342a, IMKG343a, DBM453)
17+
tabs = [tab1..., tab2..., tab3...]
18+
test_algs("IMEX ARK", tabs, ark_analytic_nonlin_test_cts(Float64), 400)
19+
test_algs("IMEX ARK", tabs, ark_analytic_sys_test_cts(Float64), 60)
20+
test_algs("IMEX ARK", tabs, ark_analytic_test_cts(Float64), 16000; super_convergence = ARS121)
21+
end

docs/src/algo_comparisons.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Algorithm comparisons
2+
3+
In this section, we compare the solution errors and convergence orders for several test problems and algorithms.
4+
5+
```@example
6+
include("algo_comparisons.jl")
7+
```
8+
9+
Plots for `ark_analytic`:
10+
![](output/solutions_ark_analytic_imex_ark.png)
11+
![](output/errors_ark_analytic_imex_ark.png)
12+
![](output/orders_ark_analytic_imex_ark.png)
13+
14+
Plots for `ark_analytic_nonlin`:
15+
![](output/solutions_ark_analytic_nonlin_imex_ark.png)
16+
![](output/errors_ark_analytic_nonlin_imex_ark.png)
17+
![](output/orders_ark_analytic_nonlin_imex_ark.png)
18+
19+
Plots for `ark_analytic_sys`:
20+
![](output/solutions_ark_analytic_sys_imex_ark.png)
21+
![](output/errors_ark_analytic_sys_imex_ark.png)
22+
![](output/orders_ark_analytic_sys_imex_ark.png)
23+
24+
## References
25+
26+
- [Example Programs for ARK ode (SUNDIALS)](http://runge.math.smu.edu/ARKode_example.pdf)

docs/src/algorithms.md

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,6 @@ IMEXARKAlgorithm
1717
IMEXARKTableau
1818
```
1919

20-
The convergence orders of the provided methods are verified using test cases from [ARKode](http://runge.math.smu.edu/ARKode_example.pdf). Plots of the solutions to these test cases, the errors of these solutions, and the convergence orders with respect to `dt` are shown below.
21-
22-
```@setup plots
23-
using Pkg
24-
Pkg.activate("../../test")
25-
Pkg.instantiate()
26-
include("../../test/convergence.jl")
27-
Pkg.activate(".")
28-
```
29-
30-
Plots for `ark_analytic`:
31-
![](output/solutions_ark_analytic_imex_ark.png)
32-
![](output/errors_ark_analytic_imex_ark.png)
33-
![](output/orders_ark_analytic_imex_ark.png)
34-
35-
Plots for `ark_analytic_nonlin`:
36-
![](output/solutions_ark_analytic_nonlin_imex_ark.png)
37-
![](output/errors_ark_analytic_nonlin_imex_ark.png)
38-
![](output/orders_ark_analytic_nonlin_imex_ark.png)
39-
40-
Plots for `ark_analytic_sys`:
41-
![](output/solutions_ark_analytic_sys_imex_ark.png)
42-
![](output/errors_ark_analytic_sys_imex_ark.png)
43-
![](output/orders_ark_analytic_sys_imex_ark.png)
44-
4520
## Low-Storage Runge--Kutta (LSRK) methods
4621

4722
Low-storage Runger--Kutta methods reduce the number stages that need to be stored.

docs/src/plotting_utils.jl

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
using Test
2+
import Printf
3+
import Plots
4+
5+
"""
6+
test_algs(
7+
algs_name,
8+
algs,
9+
test_case,
10+
num_steps;
11+
save_every_n_steps = max(1, Int(fld(num_steps, 500))),
12+
no_increment_algs = (),
13+
)
14+
15+
Check that all of the specified ODE algorithms have the predicted convergence
16+
order, and that the increment formulations give the same results as the tendency
17+
formulations. Generate plots that show the algorithms' solutions for the
18+
specified test case, the errors of these solutions, and the convergence of these
19+
errors with respect to `dt`.
20+
21+
# Arguments
22+
- `algs_name::String`: the name of the collection of algorithms
23+
- `tableaus`: an array of tableaus
24+
- `test_case::IntegratorTestCase`: the test case to use
25+
- `num_steps::Int`: the numerical solutions for the solution and error plots
26+
are computed with `dt = t_end / num_steps`, while the solutions for
27+
the convergence plots are computed with `dt`, `dt / sqrt(10)`, and
28+
`dt * sqrt(10)`
29+
- `save_every_n_steps::Int`: the solution and error plots show only show the
30+
values at every `n`-th step; the default value is such that 500-999 steps
31+
are plotted (unless there are fewer than 500 steps, in which case every
32+
step is plotted)
33+
"""
34+
function test_algs(
35+
algs_name,
36+
tableaus,
37+
test_case,
38+
num_steps;
39+
save_every_n_steps = Int(cld(num_steps, 500)),
40+
super_convergence = nothing,
41+
)
42+
(; test_name, linear_implicit, t_end, analytic_sol) = test_case
43+
FT = typeof(t_end)
44+
linestyles = (:solid, :dash, :dot, :dashdot, :dashdotdot)
45+
plot_kwargs = (;
46+
size = (1000, 600),
47+
margin = 4Plots.mm,
48+
titlelocation = :left,
49+
legend_position = :outerright,
50+
palette = :glasbey_bw_minc_20_maxl_70_n256,
51+
)
52+
53+
plot1_dt = t_end / num_steps
54+
plot1_saveat = 0:(plot1_dt * save_every_n_steps):t_end
55+
plot1a = Plots.plot(;
56+
title = "Solution Norms of $algs_name Methods for `$test_name` \
57+
(with dt = 10^$(Printf.@sprintf "%.1f" log10(plot1_dt)))",
58+
xlabel = "t",
59+
ylabel = "Solution Norm: ||Y_computed||",
60+
plot_kwargs...,
61+
)
62+
plot1b = Plots.plot(;
63+
title = "Solution Errors of $algs_name Methods for `$test_name` \
64+
(with dt = 10^$(Printf.@sprintf "%.1f" log10(plot1_dt)))",
65+
xlabel = "t",
66+
ylabel = "Error Norm: ||Y_computed - Y_analytic||",
67+
yscale = :log10,
68+
plot_kwargs...,
69+
)
70+
plot1b_ymin = typemax(FT) # dynamically set ylim because some errors are 0
71+
plot1b_ymax = typemin(FT)
72+
73+
t_end_string = t_end % 1 == 0 ? string(Int(t_end)) : Printf.@sprintf("%.2f", t_end)
74+
plot2_dts = [plot1_dt / sqrt(10), plot1_dt, plot1_dt * sqrt(10)]
75+
plot2 = Plots.plot(;
76+
title = "Convergence Orders of $algs_name Methods for `$test_name` \
77+
(at t = $t_end_string)",
78+
xlabel = "dt",
79+
ylabel = "Error Norm: ||Y_computed - Y_analytic||",
80+
xscale = :log10,
81+
yscale = :log10,
82+
plot_kwargs...,
83+
)
84+
85+
analytic_sols = map(analytic_sol, plot1_saveat)
86+
analytic_end_sol = [analytic_sols[end]]
87+
88+
for tab in tableaus
89+
(prob, alg) = problem_algo(test_case, tab)
90+
predicted_order = if super_convergence == tab
91+
CTS.theoretical_convergence_order(tab()) + 1
92+
else
93+
CTS.theoretical_convergence_order(tab())
94+
end
95+
linestyle = linestyles[(predicted_order - 1) % length(linestyles) + 1]
96+
alg_name = string(nameof(tab))
97+
98+
# Use tstops to fix saving issues due to machine precision (e.g. if the
99+
# integrator needs to save at t but it stops at t - eps(), it will skip
100+
# over saving at t, unless tstops forces it to round t - eps() to t).
101+
solve_args = (; dt = plot1_dt, saveat = plot1_saveat, tstops = plot1_saveat)
102+
tendency_sols = solve(deepcopy(prob), alg; solve_args...).u
103+
tendency_norms = @. norm(tendency_sols)
104+
tendency_errs = @. norm(tendency_sols - analytic_sols)
105+
min_err = minimum(x -> x == 0 ? typemax(FT) : x, tendency_errs)
106+
plot1b_ymin = min(plot1b_ymin, min_err)
107+
plot1b_ymax = max(plot1b_ymax, maximum(tendency_errs))
108+
tendency_errs .= max.(tendency_errs, eps(FT(0))) # plotting 0 breaks the log scale
109+
Plots.plot!(plot1a, plot1_saveat, tendency_norms; label = alg_name, linestyle)
110+
Plots.plot!(plot1b, plot1_saveat, tendency_errs; label = alg_name, linestyle)
111+
112+
tendency_end_sols = map(dt -> solve(deepcopy(prob), alg; dt).u[end], plot2_dts)
113+
tendency_end_errs = @. norm(tendency_end_sols - analytic_end_sol)
114+
_, computed_order = hcat(ones(length(plot2_dts)), log10.(plot2_dts)) \ log10.(tendency_end_errs)
115+
@test computed_order predicted_order rtol = 0.1
116+
@info "(alg, computed, predicted) = $alg, $computed_order, $predicted_order"
117+
label = "$alg_name ($(Printf.@sprintf "%.3f" computed_order))"
118+
Plots.plot!(plot2, plot2_dts, tendency_end_errs; label, linestyle)
119+
end
120+
Plots.plot!(plot1b; ylim = (plot1b_ymin / 2, plot1b_ymax * 2))
121+
122+
mkpath("output")
123+
file_suffix = "$(test_name)_$(lowercase(replace(algs_name, " " => "_")))"
124+
Plots.savefig(plot1a, joinpath("output", "solutions_$(file_suffix).png"))
125+
Plots.savefig(plot1b, joinpath("output", "errors_$(file_suffix).png"))
126+
Plots.savefig(plot2, joinpath("output", "orders_$(file_suffix).png"))
127+
end

docs/src/test_problems.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Test problems
2+
3+
TODO: fill out

src/callbacks.jl

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@ function finalize!(f!, integrator) end
2727
export EveryXWallTimeSeconds, EveryXSimulationTime, EveryXSimulationSteps
2828

2929
"""
30-
EveryXWallTimeSeconds(f!, Δwt, comm_ctx::ClimaComms.AbstractCommsContext;
31-
atinit=false)
30+
EveryXWallTimeSeconds(
31+
f!,
32+
Δwt,
33+
comm_ctx::ClimaComms.AbstractCommsContext;
34+
atinit=false
35+
)
3236
3337
Trigger `f!(integrator)` every `Δwt` wallclock seconds.
3438
@@ -75,8 +79,7 @@ function EveryXWallTimeSeconds(f!, Δwt, comm_ctx::ClimaComms.AbstractCommsConte
7579
end
7680

7781
"""
78-
EveryXSimulationTime(f!, Δt;
79-
atinit=false)
82+
EveryXSimulationTime(f!, Δt; atinit=false)
8083
8184
Trigger `f!(integrator)` every `Δt` simulation time.
8285
@@ -119,8 +122,7 @@ function EveryXSimulationTime(f!, Δt; atinit = false)
119122
end
120123

121124
"""
122-
EveryXSimulationSteps(f!, Δsteps;
123-
atinit=false)
125+
EveryXSimulationSteps(f!, Δsteps; atinit=false)
124126
125127
Trigger `f!(integrator)` every `Δsteps` simulation steps.
126128

test/Project.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
[deps]
22
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
3-
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
43
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
54
ClimaComms = "3a4d1b5c-c61d-41fd-a00a-5873ba7a1b0d"
65
ClimaCommsMPI = "5f86816e-8b66-43b2-912e-75384f99de49"
@@ -16,8 +15,6 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1615
LinearOperators = "5c8ed15e-5a4c-59e4-a42b-c7e8811fb125"
1716
MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195"
1817
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
19-
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
20-
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
2118
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
2219
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
2320
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"

0 commit comments

Comments
 (0)