Skip to content

Commit 362d488

Browse files
committed
Add AutoSparseJacobian algorithm for implicit solver
1 parent 5557f30 commit 362d488

File tree

17 files changed

+726
-90
lines changed

17 files changed

+726
-90
lines changed

.buildkite/Manifest-v1.11.toml

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ version = "0.5.18"
363363
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
364364

365365
[[deps.ClimaAtmos]]
366-
deps = ["Adapt", "ArgParse", "Artifacts", "AtmosphericProfilesLibrary", "ClimaComms", "ClimaCore", "ClimaDiagnostics", "ClimaInterpolations", "ClimaParams", "ClimaTimeSteppers", "ClimaUtilities", "CloudMicrophysics", "Dates", "ForwardDiff", "Insolation", "Interpolations", "LazyArtifacts", "LazyBroadcast", "LinearAlgebra", "Logging", "NCDatasets", "NVTX", "NullBroadcasts", "RRTMGP", "Random", "SciMLBase", "StaticArrays", "Statistics", "SurfaceFluxes", "Thermodynamics", "UnrolledUtilities", "YAML"]
366+
deps = ["Adapt", "ArgParse", "Artifacts", "AtmosphericProfilesLibrary", "ClimaComms", "ClimaCore", "ClimaDiagnostics", "ClimaInterpolations", "ClimaParams", "ClimaTimeSteppers", "ClimaUtilities", "CloudMicrophysics", "Dates", "ForwardDiff", "Insolation", "Interpolations", "LazyArtifacts", "LazyBroadcast", "LinearAlgebra", "Logging", "NCDatasets", "NVTX", "NullBroadcasts", "RRTMGP", "Random", "SciMLBase", "SparseMatrixColorings", "StaticArrays", "Statistics", "SurfaceFluxes", "Thermodynamics", "UnrolledUtilities", "YAML"]
367367
path = ".."
368368
uuid = "b2c96348-7fb7-4fe0-8da9-78d88439e717"
369369
version = "0.31.0"
@@ -381,9 +381,11 @@ weakdeps = ["CUDA", "MPI"]
381381

382382
[[deps.ClimaCore]]
383383
deps = ["Adapt", "BandedMatrices", "BlockArrays", "ClimaComms", "CubedSphere", "DataStructures", "ForwardDiff", "GaussQuadrature", "GilbertCurves", "HDF5", "InteractiveUtils", "IntervalSets", "KrylovKit", "LazyBroadcast", "LinearAlgebra", "MultiBroadcastFusion", "NVTX", "PkgVersion", "RecursiveArrayTools", "RootSolvers", "SparseArrays", "StaticArrays", "Statistics", "UnrolledUtilities"]
384-
git-tree-sha1 = "14d3d5810ce1e3c990450a2ce7abc6a1e162855f"
384+
git-tree-sha1 = "a273452127dbb052f2963e3c1095730a996d49a6"
385+
repo-rev = "main"
386+
repo-url = "https://github.com/CliMA/ClimaCore.jl.git"
385387
uuid = "d414da3d-4745-48bb-8d80-42e94e092884"
386-
version = "0.14.35"
388+
version = "0.14.36"
387389
weakdeps = ["CUDA", "Krylov"]
388390

389391
[deps.ClimaCore.extensions]
@@ -2318,6 +2320,20 @@ deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"]
23182320
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
23192321
version = "1.11.0"
23202322

2323+
[[deps.SparseMatrixColorings]]
2324+
deps = ["ADTypes", "DocStringExtensions", "LinearAlgebra", "PrecompileTools", "Random", "SparseArrays"]
2325+
git-tree-sha1 = "ab958b4fec46d1f1d057bb8e2a99bfdb90744646"
2326+
uuid = "0a514795-09f3-496d-8182-132a7b665d35"
2327+
version = "0.4.20"
2328+
2329+
[deps.SparseMatrixColorings.extensions]
2330+
SparseMatrixColoringsCliqueTreesExt = "CliqueTrees"
2331+
SparseMatrixColoringsColorsExt = "Colors"
2332+
2333+
[deps.SparseMatrixColorings.weakdeps]
2334+
CliqueTrees = "60701a23-6482-424a-84db-faee86b9b1f8"
2335+
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
2336+
23212337
[[deps.SpecialFunctions]]
23222338
deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"]
23232339
git-tree-sha1 = "41852b8679f78c8d8961eeadc8f62cef861a52e3"

.buildkite/ci_driver.jl

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,133 @@ include(joinpath(pkgdir(CA), "post_processing", "ci_plots.jl"))
4545
ref_job_id = config.parsed_args["reference_job_id"]
4646
reference_job_id = isnothing(ref_job_id) ? simulation.job_id : ref_job_id
4747

48+
if (
49+
config.parsed_args["debug_approximate_jacobian"] &&
50+
!config.parsed_args["use_dense_jacobian"]
51+
)
52+
Y_end = integrator.u
53+
t_end = integrator.t
54+
(; p, dt) = integrator
55+
timestepper_alg = integrator.alg
56+
tableau_coefficients =
57+
timestepper_alg isa CA.CTS.RosenbrockAlgorithm ?
58+
timestepper_alg.tableau.Γ : timestepper_alg.tableau.a_imp
59+
jacobian =
60+
timestepper_alg isa CA.CTS.RosenbrockAlgorithm ? integrator.cache.W :
61+
integrator.cache.newtons_method_cache.j
62+
63+
FT = eltype(Y_end)
64+
γs = filter(!iszero, CA.LinearAlgebra.diag(tableau_coefficients))
65+
dtγ = FT(float(dt) * γs[end])
66+
scalar_names = CA.scalar_field_names(Y_end)
67+
block_keys = Iterators.product(scalar_names, scalar_names)
68+
69+
@info "Debugging Jacobian in first column of final state"
70+
rms(block) = sqrt(mean(abs2.(block)))
71+
highlighters = (
72+
Highlighter((d, i, j) -> d[i, j] < 1e-12; foreground = :dark_gray),
73+
Highlighter((d, i, j) -> 1e-12 <= d[i, j] < 1e-6; foreground = :green),
74+
Highlighter((d, i, j) -> 1e-6 <= d[i, j] < 1e-2; foreground = :blue),
75+
Highlighter((d, i, j) -> 1e-2 <= d[i, j] < 1e-1; foreground = :cyan),
76+
Highlighter((d, i, j) -> 1e-1 <= d[i, j] < 1; foreground = :light_cyan),
77+
Highlighter((d, i, j) -> d[i, j] == 1; foreground = :yellow),
78+
Highlighter((d, i, j) -> d[i, j] > 1; foreground = :red),
79+
)
80+
table_kwargs = (;
81+
columns_width = 5,
82+
crop = :none,
83+
formatters = ft_printf("%1.0e"),
84+
highlighters,
85+
row_labels = collect(scalar_names),
86+
show_header = false,
87+
tf = tf_matrix,
88+
vlines = [1],
89+
)
90+
91+
block_rescalings = CA.first_column_rescaling_arrays(Y_end, p, t_end)
92+
93+
exact_jacobian_alg = CA.AutoDenseJacobian()
94+
exact_blocks =
95+
CA.first_column_block_arrays(exact_jacobian_alg, Y_end, p, dtγ, t_end)
96+
exact_rms_values = map(block_keys) do block_key
97+
rms(exact_blocks[block_key])
98+
end
99+
exact_rescaled_rms_values = map(block_keys) do block_key
100+
rms(exact_blocks[block_key] .* block_rescalings[block_key])
101+
end
102+
@info "exact, RMS per block [inconsistent units]:"
103+
pretty_table(
104+
exact_rms_values;
105+
table_kwargs...,
106+
highlighters = highlighters[1],
107+
)
108+
@info "exact, rescaled RMS per block [s^-1]:"
109+
pretty_table(
110+
exact_rescaled_rms_values;
111+
table_kwargs...,
112+
highlighters = highlighters[1],
113+
)
114+
println("<$('='^70)>")
115+
116+
all_approx_jacobian_algs =
117+
jacobian.alg isa CA.AutoSparseJacobian ?
118+
(; manual = jacobian.alg.sparse_jacobian_alg, auto = jacobian.alg) :
119+
(; manual = jacobian.alg)
120+
all_approx_blocks = map(all_approx_jacobian_algs) do jacobian_alg
121+
CA.first_column_block_arrays(jacobian_alg, Y_end, p, dtγ, t_end)
122+
end
123+
if jacobian.alg isa CA.AutoSparseJacobian
124+
approx_diff_rescaled_rms_values = map(block_keys) do block_key
125+
(; manual, auto) = all_approx_blocks
126+
rescaling = block_rescalings[block_key]
127+
haskey(manual, block_key) &&
128+
!(manual[block_key] isa CA.UniformScaling) ?
129+
rms((manual[block_key] - auto[block_key]) .* rescaling) : FT(0)
130+
end
131+
@info "manual approx - auto approx, rescaled RMS per block [s^-1]:"
132+
pretty_table(approx_diff_rescaled_rms_values; table_kwargs...)
133+
end
134+
for (approx_name, approx_blocks) in pairs(all_approx_blocks)
135+
approx_error_rescaled_rms_values = map(block_keys) do block_key
136+
approx_error =
137+
haskey(approx_blocks, block_key) ?
138+
approx_blocks[block_key] - exact_blocks[block_key] :
139+
exact_blocks[block_key]
140+
rescaling = block_rescalings[block_key]
141+
rms(approx_error .* rescaling)
142+
end
143+
@info "$approx_name approx - exact, rescaled RMS per block [s^-1]:"
144+
pretty_table(approx_error_rescaled_rms_values; table_kwargs...)
145+
end
146+
println("<$('='^70)>")
147+
if jacobian.alg isa CA.AutoSparseJacobian
148+
approx_diff_relative_rms_values = map(block_keys) do block_key
149+
(; manual, auto) = all_approx_blocks
150+
rescaling = block_rescalings[block_key]
151+
approx_diff_rms_value =
152+
haskey(manual, block_key) &&
153+
!(manual[block_key] isa CA.UniformScaling) ?
154+
rms((manual[block_key] - auto[block_key])) : FT(0)
155+
approx_diff_rms_value == 0 ? FT(0) :
156+
approx_diff_rms_value / rms(exact_blocks[block_key])
157+
end
158+
@info "manual approx - auto approx, relative RMS per block [unitless]:"
159+
pretty_table(approx_diff_relative_rms_values; table_kwargs...)
160+
end
161+
for (approx_name, approx_blocks) in pairs(all_approx_blocks)
162+
approx_error_relative_rms_values = map(block_keys) do block_key
163+
approx_error_rms_value =
164+
haskey(approx_blocks, block_key) ?
165+
rms(approx_blocks[block_key] - exact_blocks[block_key]) :
166+
rms(exact_blocks[block_key])
167+
approx_error_rms_value == 0 ? FT(0) :
168+
approx_error_rms_value / rms(exact_blocks[block_key])
169+
end
170+
@info "$approx_name approx - exact, relative RMS per block [unitless]:"
171+
pretty_table(approx_error_relative_rms_values; table_kwargs...)
172+
end
173+
end
174+
48175
if sol_res.ret_code == :simulation_crashed
49176
error(
50177
"The ClimaAtmos simulation has crashed. See the stack trace for details.",

.buildkite/gpu_pipeline/pipeline.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ steps:
2424
- julia --project=.buildkite -e 'using Pkg; Pkg.precompile()'
2525
- julia --project=.buildkite -e 'using CUDA; CUDA.precompile_runtime()'
2626
- julia --project=.buildkite -e 'using Pkg; Pkg.status()'
27+
- julia --project=.buildkite -e 'using Pkg; Pkg.add(Pkg.PackageSpec(;name="ClimaCore", rev="main"))'
2728

2829
agents:
2930
slurm_gpus: 1

.buildkite/longruns_gpu/pipeline.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ steps:
2525
- julia --project=.buildkite -e 'using Pkg; Pkg.precompile()'
2626
- julia --project=.buildkite -e 'using CUDA; CUDA.precompile_runtime()'
2727
- julia --project=.buildkite -e 'using Pkg; Pkg.status()'
28+
- julia --project=.buildkite -e 'using Pkg; Pkg.add(Pkg.PackageSpec(;name="ClimaCore", rev="main"))'
2829

2930
agents:
3031
slurm_gpus: 1

.buildkite/pipeline.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ steps:
2828

2929
- echo "--- Instantiate .buildkite"
3030
- "julia --project=.buildkite -e 'using Pkg; Pkg.instantiate(;verbose=true); Pkg.precompile(;strict=true); using CUDA; CUDA.precompile_runtime(); Pkg.status()'"
31+
- "julia --project=.buildkite -e 'using Pkg; Pkg.add(Pkg.PackageSpec(;name=\"ClimaCore\", rev=\"main\"))'"
3132

3233
agents:
3334
slurm_cpus_per_task: 8
@@ -631,7 +632,7 @@ steps:
631632
--job_id amip_target_edonly_nonequil
632633
artifact_paths: "amip_target_edonly_nonequil/output_active/*"
633634
agents:
634-
slurm_mem: 20GB
635+
slurm_mem: 64GB
635636

636637
- group: "Diagnostic EDMFX"
637638
steps:

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ NullBroadcasts = "0d71be07-595a-4f89-9529-4065a4ab43a6"
3030
RRTMGP = "a01a1ee8-cea4-48fc-987c-fc7878d79da1"
3131
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
3232
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
33+
SparseMatrixColorings = "0a514795-09f3-496d-8182-132a7b665d35"
3334
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
3435
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
3536
SurfaceFluxes = "49b00bb7-8bd4-4f2b-b78c-51cd0450215f"
@@ -64,6 +65,7 @@ NullBroadcasts = "0.1"
6465
RRTMGP = "0.21.3"
6566
Random = "1"
6667
SciMLBase = "2.12"
68+
SparseMatrixColorings = "0.4.20"
6769
StaticArrays = "1.7"
6870
Statistics = "1"
6971
SurfaceFluxes = "0.11, 0.12"

config/default_configs/default_config.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ jvp_step_adjustment:
8989
use_dense_jacobian:
9090
help: "Whether to use a dense Jacobian matrix that is computed using forward-mode automatic differentiation and inverted using LU factorization [`true`, `false` (default)]"
9191
value: false
92+
use_auto_jacobian:
93+
help: "Whether to populate the entries of the sparse Jacobian matrix using forward-mode automatic differentiation with sparse matrix coloring (only used when `use_dense_jacobian` is `false`) [`true`, `false` (default)]"
94+
value: true # TODO: Change this to false
95+
auto_jacobian_padding_bands:
96+
help: "Minimum number of bands to add in every block of the sparse Jacobian matrix, eliminating errors from Jacobian entries that lie outside of the default sparsity pattern (only used when `use_auto_jacobian` is `true`; default is `0`)"
97+
value: 2 # TODO: Change this to 0
98+
debug_approximate_jacobian:
99+
help: "Whether to compare approximations of the Jacobian matrix in the first column of the final state against the exact Jacobian [`true`, `false` (default)]"
100+
value: true # TODO: Change this to false
92101
update_jacobian_every:
93102
help: "Frequency at which the Jacobian matrix should be updated (once per timestep, once per timestepper stage, or once per linear solve) [`dt`, `stage`, `solve` (default)]"
94103
value: "solve"

reproducibility_tests/ref_counter.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
248
1+
249
22

33
# **README**
44
#

src/ClimaAtmos.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ include(
6262
joinpath("prognostic_equations", "implicit", "manual_sparse_jacobian.jl"),
6363
)
6464
include(joinpath("prognostic_equations", "implicit", "auto_dense_jacobian.jl"))
65+
include(joinpath("prognostic_equations", "implicit", "auto_sparse_jacobian.jl"))
6566
include(joinpath("prognostic_equations", "implicit", "autodiff_utils.jl"))
6667

6768
include(joinpath("prognostic_equations", "water_advection.jl"))

0 commit comments

Comments
 (0)