Skip to content

Add AutoSparseJacobian algorithm for implicit solver #3859

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions .buildkite/Manifest-v1.11.toml
Original file line number Diff line number Diff line change
Expand Up @@ -363,14 +363,16 @@ version = "0.5.18"
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"

[[deps.ClimaAtmos]]
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"]
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"]
path = ".."
uuid = "b2c96348-7fb7-4fe0-8da9-78d88439e717"
version = "0.31.0"

[[deps.ClimaComms]]
deps = ["Adapt", "Logging", "LoggingExtras"]
git-tree-sha1 = "75b9d1a3b4e3efa2cbbae2eb7b52f14c0b38ccf0"
git-tree-sha1 = "d341c3fc97a98dbecd6b635f34638b2d9771f94e"
repo-rev = "dy/memory_api"
repo-url = "https://github.com/CliMA/ClimaComms.jl.git"
uuid = "3a4d1b5c-c61d-41fd-a00a-5873ba7a1b0d"
version = "0.6.8"
weakdeps = ["CUDA", "MPI"]
Expand All @@ -381,9 +383,11 @@ weakdeps = ["CUDA", "MPI"]

[[deps.ClimaCore]]
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"]
git-tree-sha1 = "14d3d5810ce1e3c990450a2ce7abc6a1e162855f"
git-tree-sha1 = "a273452127dbb052f2963e3c1095730a996d49a6"
repo-rev = "main"
repo-url = "https://github.com/CliMA/ClimaCore.jl.git"
uuid = "d414da3d-4745-48bb-8d80-42e94e092884"
version = "0.14.35"
version = "0.14.36"
weakdeps = ["CUDA", "Krylov"]

[deps.ClimaCore.extensions]
Expand Down Expand Up @@ -2318,6 +2322,20 @@ deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
version = "1.11.0"

[[deps.SparseMatrixColorings]]
deps = ["ADTypes", "DocStringExtensions", "LinearAlgebra", "PrecompileTools", "Random", "SparseArrays"]
git-tree-sha1 = "ab958b4fec46d1f1d057bb8e2a99bfdb90744646"
uuid = "0a514795-09f3-496d-8182-132a7b665d35"
version = "0.4.20"

[deps.SparseMatrixColorings.extensions]
SparseMatrixColoringsCliqueTreesExt = "CliqueTrees"
SparseMatrixColoringsColorsExt = "Colors"

[deps.SparseMatrixColorings.weakdeps]
CliqueTrees = "60701a23-6482-424a-84db-faee86b9b1f8"
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"

[[deps.SpecialFunctions]]
deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"]
git-tree-sha1 = "41852b8679f78c8d8961eeadc8f62cef861a52e3"
Expand Down
121 changes: 121 additions & 0 deletions .buildkite/ci_driver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,127 @@ include(joinpath(pkgdir(CA), "post_processing", "ci_plots.jl"))
ref_job_id = config.parsed_args["reference_job_id"]
reference_job_id = isnothing(ref_job_id) ? simulation.job_id : ref_job_id

if (
config.parsed_args["debug_approximate_jacobian"] &&
!config.parsed_args["use_dense_jacobian"]
)
Y_end = integrator.u
t_end = integrator.t
(; p, dt) = integrator
timestepper_alg = integrator.alg
tableau_coefficients =
timestepper_alg isa CA.CTS.RosenbrockAlgorithm ?
timestepper_alg.tableau.Γ : timestepper_alg.tableau.a_imp
jacobian =
timestepper_alg isa CA.CTS.RosenbrockAlgorithm ? integrator.cache.W :
integrator.cache.newtons_method_cache.j

FT = eltype(Y_end)
γs = filter(!iszero, CA.LinearAlgebra.diag(tableau_coefficients))
dtγ = FT(float(dt) * γs[end])
scalar_names = CA.scalar_field_names(Y_end)
block_keys = Iterators.product(scalar_names, scalar_names)

exact_jacobian_alg = CA.AutoDenseJacobian()
all_approx_jacobian_algs =
jacobian.alg isa CA.AutoSparseJacobian ?
(; manual = jacobian.alg.sparse_jacobian_alg, auto = jacobian.alg) :
(; manual = jacobian.alg)
exact_blocks =
CA.first_column_block_arrays(exact_jacobian_alg, Y_end, p, dtγ, t_end)
all_approx_blocks = map(all_approx_jacobian_algs) do jacobian_alg
CA.first_column_block_arrays(jacobian_alg, Y_end, p, dtγ, t_end)
end
block_rescalings = CA.first_column_rescaling_arrays(Y_end, p, t_end)

table_kwargs = (;
columns_width = 5,
crop = :none,
formatters = ft_printf("%1.0e"),
row_labels = collect(scalar_names),
show_header = false,
tf = tf_matrix,
vlines = [1],
)
highlighters = (
Highlighter((d, i, j) -> d[i, j] < 1e-12; foreground = :dark_gray),
Highlighter((d, i, j) -> 1e-12 <= d[i, j] < 1e-6; foreground = :blue),
Highlighter((d, i, j) -> 1e-6 <= d[i, j] < 1e-3; foreground = :cyan),
Highlighter((d, i, j) -> 1e-3 <= d[i, j] < 1e-1; foreground = :green),
Highlighter((d, i, j) -> 1e-1 <= d[i, j] < 1; foreground = :yellow),
Highlighter((d, i, j) -> d[i, j] == 1; foreground = :light_red),
Highlighter((d, i, j) -> d[i, j] > 1; foreground = :light_magenta),
)
rms(block) = sqrt(mean(abs2.(block)))

@info "Debugging Jacobian in first column of final state"

exact_table_kwargs = (; table_kwargs..., highlighters = highlighters[1])
exact_rms_values = map(block_keys) do block_key
rms(exact_blocks[block_key])
end
exact_rescaled_rms_values = map(block_keys) do block_key
rms(exact_blocks[block_key] .* block_rescalings[block_key])
end
@info "exact, RMS per block [unnormalized]:"
pretty_table(exact_rms_values; exact_table_kwargs...)
@info "exact, rescaled RMS per block [s^-1]:"
pretty_table(exact_rescaled_rms_values; exact_table_kwargs...)
println("<$('='^70)>\n")

approx_table_kwargs = (; table_kwargs..., highlighters)
if jacobian.alg isa CA.AutoSparseJacobian
approx_diff_rescaled_rms_values = map(block_keys) do block_key
(; manual, auto) = all_approx_blocks
rescaling = block_rescalings[block_key]
haskey(manual, block_key) &&
!(manual[block_key] isa CA.UniformScaling) ?
rms((manual[block_key] - auto[block_key]) .* rescaling) : FT(0)
end
@info "manual approx - auto approx, rescaled RMS per block [s^-1]:"
pretty_table(approx_diff_rescaled_rms_values; approx_table_kwargs...)
end
for (approx_name, approx_blocks) in pairs(all_approx_blocks)
approx_error_rescaled_rms_values = map(block_keys) do block_key
approx_error =
haskey(approx_blocks, block_key) ?
approx_blocks[block_key] - exact_blocks[block_key] :
exact_blocks[block_key]
rescaling = block_rescalings[block_key]
rms(approx_error .* rescaling)
end
@info "$approx_name approx - exact, rescaled RMS per block [s^-1]:"
pretty_table(approx_error_rescaled_rms_values; approx_table_kwargs...)
end
println("<$('='^70)>\n")
if jacobian.alg isa CA.AutoSparseJacobian
approx_diff_relative_rms_values = map(block_keys) do block_key
(; manual, auto) = all_approx_blocks
rescaling = block_rescalings[block_key]
approx_diff_rms_value =
haskey(manual, block_key) &&
!(manual[block_key] isa CA.UniformScaling) ?
rms((manual[block_key] - auto[block_key])) : FT(0)
approx_diff_rms_value == 0 ? FT(0) :
approx_diff_rms_value / rms(exact_blocks[block_key])
end
@info "manual approx - auto approx, relative RMS per block [unitless]:"
pretty_table(approx_diff_relative_rms_values; approx_table_kwargs...)
end
for (approx_name, approx_blocks) in pairs(all_approx_blocks)
approx_error_relative_rms_values = map(block_keys) do block_key
approx_error_rms_value =
haskey(approx_blocks, block_key) ?
rms(approx_blocks[block_key] - exact_blocks[block_key]) :
rms(exact_blocks[block_key])
approx_error_rms_value == 0 ? FT(0) :
approx_error_rms_value / rms(exact_blocks[block_key])
end
@info "$approx_name approx - exact, relative RMS per block [unitless]:"
pretty_table(approx_error_relative_rms_values; approx_table_kwargs...)
end
end

if sol_res.ret_code == :simulation_crashed
error(
"The ClimaAtmos simulation has crashed. See the stack trace for details.",
Expand Down
2 changes: 2 additions & 0 deletions .buildkite/gpu_pipeline/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ steps:
- julia --project=.buildkite -e 'using Pkg; Pkg.precompile()'
- julia --project=.buildkite -e 'using CUDA; CUDA.precompile_runtime()'
- julia --project=.buildkite -e 'using Pkg; Pkg.status()'
- julia --project=.buildkite -e 'using Pkg; Pkg.add(Pkg.PackageSpec(;name="ClimaComms", rev="dy/memory_api"))'
- julia --project=.buildkite -e 'using Pkg; Pkg.add(Pkg.PackageSpec(;name="ClimaCore", rev="main"))'

agents:
slurm_gpus: 1
Expand Down
2 changes: 2 additions & 0 deletions .buildkite/longruns_gpu/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ steps:
- julia --project=.buildkite -e 'using Pkg; Pkg.precompile()'
- julia --project=.buildkite -e 'using CUDA; CUDA.precompile_runtime()'
- julia --project=.buildkite -e 'using Pkg; Pkg.status()'
- julia --project=.buildkite -e 'using Pkg; Pkg.add(Pkg.PackageSpec(;name="ClimaComms", rev="dy/memory_api"))'
- julia --project=.buildkite -e 'using Pkg; Pkg.add(Pkg.PackageSpec(;name="ClimaCore", rev="main"))'

agents:
slurm_gpus: 1
Expand Down
4 changes: 3 additions & 1 deletion .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ steps:

- echo "--- Instantiate .buildkite"
- "julia --project=.buildkite -e 'using Pkg; Pkg.instantiate(;verbose=true); Pkg.precompile(;strict=true); using CUDA; CUDA.precompile_runtime(); Pkg.status()'"
- julia --project=.buildkite -e 'using Pkg; Pkg.add(Pkg.PackageSpec(;name="ClimaComms", rev="dy/memory_api"))'
- julia --project=.buildkite -e 'using Pkg; Pkg.add(Pkg.PackageSpec(;name="ClimaCore", rev="main"))'

agents:
slurm_cpus_per_task: 8
Expand Down Expand Up @@ -631,7 +633,7 @@ steps:
--job_id amip_target_edonly_nonequil
artifact_paths: "amip_target_edonly_nonequil/output_active/*"
agents:
slurm_mem: 20GB
slurm_mem: 64GB

- group: "Diagnostic EDMFX"
steps:
Expand Down
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ NullBroadcasts = "0d71be07-595a-4f89-9529-4065a4ab43a6"
RRTMGP = "a01a1ee8-cea4-48fc-987c-fc7878d79da1"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
SparseMatrixColorings = "0a514795-09f3-496d-8182-132a7b665d35"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
SurfaceFluxes = "49b00bb7-8bd4-4f2b-b78c-51cd0450215f"
Expand Down Expand Up @@ -64,6 +65,7 @@ NullBroadcasts = "0.1"
RRTMGP = "0.21.3"
Random = "1"
SciMLBase = "2.12"
SparseMatrixColorings = "0.4.20"
StaticArrays = "1.7"
Statistics = "1"
SurfaceFluxes = "0.11, 0.12"
Expand Down
9 changes: 9 additions & 0 deletions config/default_configs/default_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ jvp_step_adjustment:
use_dense_jacobian:
help: "Whether to use a dense Jacobian matrix that is computed using forward-mode automatic differentiation and inverted using LU factorization [`true`, `false` (default)]"
value: false
use_auto_jacobian:
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)]"
value: true # TODO: Change this to false
auto_jacobian_padding_bands:
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`)"
value: 2 # TODO: Change this to 0
debug_approximate_jacobian:
help: "Whether to compare approximations of the Jacobian matrix in the first column of the final state against the exact Jacobian [`true`, `false` (default)]"
value: true # TODO: Change this to false
update_jacobian_every:
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)]"
value: "solve"
Expand Down
2 changes: 1 addition & 1 deletion reproducibility_tests/ref_counter.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
248
249

# **README**
#
Expand Down
1 change: 1 addition & 0 deletions src/ClimaAtmos.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ include(
joinpath("prognostic_equations", "implicit", "manual_sparse_jacobian.jl"),
)
include(joinpath("prognostic_equations", "implicit", "auto_dense_jacobian.jl"))
include(joinpath("prognostic_equations", "implicit", "auto_sparse_jacobian.jl"))
include(joinpath("prognostic_equations", "implicit", "autodiff_utils.jl"))

include(joinpath("prognostic_equations", "water_advection.jl"))
Expand Down
Loading
Loading