Skip to content

Commit 1e0e996

Browse files
Merge #130
130: Add convergence tests with ODEConvergenceTester r=charleskawczynski a=charleskawczynski This PR adds convergence tests using ODEConvergenceTester.jl, which yields the following output: <img width="500" alt="Screen Shot 2022-12-26 at 11 01 44 AM" src="https://user-images.githubusercontent.com/1880641/209576952-585a2ac9-7bfa-4267-9d01-d2403e26c739.png"> This was added into the test suite for now. I'd like the table to be a part of the docs, and tests in the test suite. Before doing this, we can improve the test problem documentation, since convergence orders for "`ark_analytic`" demonstrates both failed and super convergence, which suggests that there's something wrong or special about this problem compared to the others. The 903 super-convergence is especially striking. Co-authored-by: Charles Kawczynski <[email protected]>
2 parents 430b75a + a167549 commit 1e0e996

File tree

4 files changed

+136
-0
lines changed

4 files changed

+136
-0
lines changed

test/Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ Krylov = "ba0b0d4f-ebba-5204-a429-3ac8c609bfb7"
1414
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1515
LinearOperators = "5c8ed15e-5a4c-59e4-a42b-c7e8811fb125"
1616
MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195"
17+
ODEConvergenceTester = "42a5c2e1-f365-4540-8ca5-3684de3ecd95"
1718
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
19+
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
1820
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1921
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
2022
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
@@ -23,3 +25,5 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
2325

2426
[compat]
2527
OrdinaryDiffEq = "5.71.2"
28+
PrettyTables = "2"
29+
ODEConvergenceTester = "0.2"

test/convergence.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using ClimaTimeSteppers, LinearAlgebra, Test
2+
import PrettyTables
23

34
include(joinpath(@__DIR__, "convergence_utils.jl"))
45
include(joinpath(@__DIR__, "utils.jl"))
@@ -41,6 +42,43 @@ include(joinpath(@__DIR__, "problems.jl"))
4142
end
4243
end
4344

45+
#=
46+
using Revise; include("test/convergence.jl")
47+
results = tabulate_convergence_orders();
48+
=#
49+
function tabulate_convergence_orders()
50+
tabs = [
51+
ARS111,
52+
ARS121,
53+
ARS122,
54+
ARS232,
55+
ARS222,
56+
IMKG232a,
57+
IMKG232b,
58+
IMKG242a,
59+
IMKG242b,
60+
IMKG252a,
61+
IMKG252b,
62+
IMKG253a,
63+
IMKG253b,
64+
IMKG254a,
65+
IMKG254b,
66+
IMKG254c,
67+
HOMMEM1,
68+
ARS233,
69+
ARS343,
70+
ARS443,
71+
IMKG342a,
72+
IMKG343a,
73+
DBM453,
74+
]
75+
test_cases = all_test_cases(Float64)
76+
results = convergence_order_results(tabs, test_cases)
77+
tabulate_convergence_orders(test_cases, tabs, results)
78+
return results
79+
end
80+
tabulate_convergence_orders()
81+
4482
#=
4583
if ArrayType == Array
4684
for (prob, sol) in [

test/convergence_utils.jl

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import ODEConvergenceTester as OCT
2+
import OrdinaryDiffEq as ODE
13

24
"""
35
DirectSolver
@@ -47,3 +49,84 @@ function convergence_order(prob, sol, method, dts; kwargs...)
4749
_, order_est = hcat(ones(length(dts)), log2.(dts)) \ log2.(errs)
4850
return order_est
4951
end
52+
53+
function default_expected_order(alg, tab)
54+
return if tab isa CTS.AbstractIMEXARKTableau
55+
CTS.theoretical_convergence_order(tab)
56+
else
57+
ODE.alg_order(alg)
58+
end
59+
end
60+
61+
function test_convergence_order!(test_case, tab, results = Dict(); refinement_range)
62+
prob, alg = problem_algo(test_case, tab)
63+
expected_order = default_expected_order(alg, tab())
64+
cr = OCT.refinement_study(
65+
prob,
66+
alg;
67+
verbose = false,
68+
expected_order,
69+
refinement_range, # ::UnitRange, 2:4 is more fine than 1:3
70+
)
71+
computed_order = maximum(cr.computed_order)
72+
results[tab, test_case.test_name] = (; expected_order, computed_order)
73+
return nothing
74+
end
75+
76+
distance(theoretic, computed) = abs(computed - theoretic) / theoretic
77+
pass_conv(theoretic, computed) = distance(theoretic, computed) * 100 < 10
78+
fail_conv(theoretic, computed) = !pass_conv(computed, theoretic) && !super_conv(theoretic, computed)
79+
super_conv(theoretic, computed) = (computed - theoretic) / theoretic * 100 > 10
80+
81+
#= Calls `test_convergence_order!` for each combination of test case
82+
and algorithm, returns a `Dict` of the results. =#
83+
function convergence_order_results(tabs, test_cases)
84+
results = Dict()
85+
for test_case in test_cases
86+
@info "------------------ Test case: $(test_case.test_name)"
87+
for tab in tabs
88+
# @info "Running refinement study on $(nameof(tab))"
89+
test_convergence_order!(test_case, tab, results; refinement_range = 5:9)
90+
end
91+
end
92+
return results
93+
end
94+
95+
function tabulate_convergence_orders(test_cases, tabs, results)
96+
columns = map(test_cases) do test_case
97+
map(tab -> results[tab, test_case.test_name], tabs)
98+
end
99+
expected_order = map(tab -> default_expected_order(nothing, tab()), tabs)
100+
tab_names = map(tab -> "$tab ($(default_expected_order(nothing, tab())))", tabs)
101+
data = hcat(columns...)
102+
summary(result) = result.computed_order
103+
data_summary = map(d -> summary(d), data)
104+
105+
table_data = hcat(tab_names, data_summary)
106+
precentage_fail = sum(fail_conv.(getindex.(data, 1), getindex.(data, 2))) / length(data) * 100
107+
@info "Percentage of failed convergence order tests: $precentage_fail"
108+
fail_conv_hl = PrettyTables.Highlighter(
109+
(data, i, j) -> j 1 && fail_conv(expected_order[i], data[i, j]),
110+
PrettyTables.crayon"red bold",
111+
)
112+
super_conv_hl = PrettyTables.Highlighter(
113+
(data, i, j) -> j 1 && super_conv(expected_order[i], data[i, j]),
114+
PrettyTables.crayon"yellow bold",
115+
)
116+
tab_column_hl = PrettyTables.Highlighter((data, i, j) -> j == 1, PrettyTables.crayon"green bold")
117+
test_case_names = map(test_case -> test_case.test_name, test_cases)
118+
119+
header = (["Tableau (theoretic)", test_case_names...],
120+
# ["", ["" for tc in test_case_names]...],
121+
)
122+
123+
PrettyTables.pretty_table(
124+
table_data;
125+
header_crayon = PrettyTables.crayon"green bold",
126+
highlighters = (tab_column_hl, fail_conv_hl, super_conv_hl),
127+
title = "Computed convergence orders, red=fail, yellow=super-convergence",
128+
header,
129+
alignment = :c,
130+
crop = :none,
131+
)
132+
end

test/problems.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,3 +428,14 @@ function ark_analytic_sys_test_cts(::Type{FT}) where {FT}
428428
Wfact! = (W, Y, _, Δt, t) -> W .= Δt .* A .- I,
429429
)
430430
end
431+
432+
function all_test_cases(::Type{FT}) where {FT}
433+
return [
434+
ark_analytic_nonlin_test_cts(FT),
435+
ark_analytic_sys_test_cts(FT),
436+
ark_analytic_test_cts(FT),
437+
# onewaycouple_mri_test_cts(FT),
438+
# climacore_2Dheat_test_cts(FT),
439+
# climacore_1Dheat_test_cts(FT),
440+
]
441+
end

0 commit comments

Comments
 (0)