Global bucket run

The code sets up and runs the bucket model on a spherical domain, using ERA5 data.

First we import a lot of packages:

import ClimaComms
using ClimaCore
using ClimaUtilities
import Interpolations
import ClimaUtilities.TimeVaryingInputs:
    TimeVaryingInput, LinearInterpolation, PeriodicCalendar
ClimaComms.@import_required_backends
import ClimaTimeSteppers as CTS
import ClimaParams as CP
using ClimaLand.Bucket:
    BucketModel, BucketModelParameters, PrescribedBaregroundAlbedo
import ClimaLand
import ClimaLand.Parameters as LP
import ClimaLand.Simulations: LandSimulation, solve!
using Dates
using CairoMakie, ClimaAnalysis, GeoMakie, Printf, Statistics
import ClimaLand.LandSimVis as LandSimVis;
┌ Warning: Error requiring `IntervalArithmetic` from `TaylorSeries`
│   exception =
│    LoadError: UndefVarError: `IntervalBox` not defined in `TaylorSeries`
│    Suggestion: check for spelling errors or missing imports.
│    Stacktrace:
│      [1] top-level scope
│        @ ~/.julia/packages/TaylorSeries/ZBRjU/src/intervals.jl:171
│      [2] include(mapexpr::Function, mod::Module, _path::String)
│        @ Base ./Base.jl:307
│      [3] top-level scope
│        @ ~/.julia/packages/Requires/1eCOK/src/Requires.jl:40
│      [4] eval(m::Module, e::Any)
│        @ Core ./boot.jl:489
│      [5] EvalInto
│        @ ./boot.jl:494 [inlined]
│      [6] (::TaylorSeries.var"#__init__##4#__init__##5")()
│        @ TaylorSeries ~/.julia/packages/Requires/1eCOK/src/require.jl:101
│      [7] macro expansion
│        @ ./timing.jl:461 [inlined]
│      [8] err(f::Any, listener::Module, modname::String, file::String, line::Any)
│        @ Requires ~/.julia/packages/Requires/1eCOK/src/require.jl:47
│      [9] (::TaylorSeries.var"#__init__##2#__init__##3")()
│        @ TaylorSeries ~/.julia/packages/Requires/1eCOK/src/require.jl:100
│     [10] withpath(f::Any, path::String)
│        @ Requires ~/.julia/packages/Requires/1eCOK/src/require.jl:37
│     [11] (::TaylorSeries.var"#__init__##0#__init__##1")()
│        @ TaylorSeries ~/.julia/packages/Requires/1eCOK/src/require.jl:99
│     [12] foreach(f::typeof(invokelatest), itr::Vector{Function})
│        @ Base ./abstractarray.jl:3191
│     [13] loadpkg(pkg::Base.PkgId)
│        @ Requires ~/.julia/packages/Requires/1eCOK/src/require.jl:27
│     [14] run_package_callbacks(modkey::Base.PkgId)
│        @ Base ./loading.jl:1467
│     [15] _require_search_from_serialized(pkg::Base.PkgId, sourcepath::String, build_id::UInt128, stalecheck::Bool; reasons::Dict{String, Int64}, DEPOT_PATH::Vector{String})
│        @ Base ./loading.jl:2201
│     [16] _require_search_from_serialized
│        @ ./loading.jl:2076 [inlined]
│     [17] __require_prelocked(pkg::Base.PkgId, env::String)
│        @ Base ./loading.jl:2695
│     [18] _require_prelocked(uuidkey::Base.PkgId, env::String)
│        @ Base ./loading.jl:2560
│     [19] macro expansion
│        @ ./loading.jl:2488 [inlined]
│     [20] macro expansion
│        @ ./lock.jl:376 [inlined]
│     [21] __require(into::Module, mod::Symbol)
│        @ Base ./loading.jl:2453
│     [22] require(into::Module, mod::Symbol)
│        @ Base ./loading.jl:2429
│     [23] eval(m::Module, e::Any)
│        @ Core ./boot.jl:489
│     [24] include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String)
│        @ Base ./loading.jl:2952
│     [25] include_string
│        @ ./loading.jl:2962 [inlined]
│     [26] #61
│        @ ~/.julia/packages/Literate/On3EJ/src/Literate.jl:959 [inlined]
│     [27] task_local_storage(body::Literate.var"#61#62"{String, Bool, Module, String}, key::Symbol, val::String)
│        @ Base ./task.jl:298
│     [28] #59
│        @ ~/.julia/packages/Literate/On3EJ/src/Literate.jl:955 [inlined]
│     [29] (::IOCapture.var"#12#13"{Type{Union{}}, Literate.var"#59#60"{String, Bool, Module, String}, IOContext{Base.PipeEndpoint}, IOContext{Base.PipeEndpoint}, IOContext{Base.PipeEndpoint}, IOContext{Base.PipeEndpoint}})()
│        @ IOCapture ~/.julia/packages/IOCapture/MR051/src/IOCapture.jl:170
│     [30] with_logstate(f::IOCapture.var"#12#13"{Type{Union{}}, Literate.var"#59#60"{String, Bool, Module, String}, IOContext{Base.PipeEndpoint}, IOContext{Base.PipeEndpoint}, IOContext{Base.PipeEndpoint}, IOContext{Base.PipeEndpoint}}, logstate::Base.CoreLogging.LogState)
│        @ Base.CoreLogging ./logging/logging.jl:542
│     [31] with_logger(f::Function, logger::Base.CoreLogging.ConsoleLogger)
│        @ Base.CoreLogging ./logging/logging.jl:653
│     [32] capture(f::Literate.var"#59#60"{String, Bool, Module, String}; rethrow::Type, color::Bool, passthrough::Bool, capture_buffer::IOBuffer, io_context::Vector{Any})
│        @ IOCapture ~/.julia/packages/IOCapture/MR051/src/IOCapture.jl:167
│     [33] capture
│        @ ~/.julia/packages/IOCapture/MR051/src/IOCapture.jl:100 [inlined]
│     [34] execute_block(sb::Module, block::String; inputfile::String, fake_source::String, softscope::Bool, continue_on_error::Bool)
│        @ Literate ~/.julia/packages/Literate/On3EJ/src/Literate.jl:953
│     [35] execute_block
│        @ ~/.julia/packages/Literate/On3EJ/src/Literate.jl:935 [inlined]
│     [36] execute_markdown!(io::IOBuffer, sb::Module, block::String, outputdir::String; inputfile::String, fake_source::String, flavor::Literate.DocumenterFlavor, image_formats::Vector{Tuple{MIME, String}}, file_prefix::String, softscope::Bool, continue_on_error::Bool)
│        @ Literate ~/.julia/packages/Literate/On3EJ/src/Literate.jl:683
│     [37] (::Literate.var"#42#43"{Dict{String, Any}, IOBuffer, Module, Literate.CodeChunk, Int64})()
│        @ Literate ~/.julia/packages/Literate/On3EJ/src/Literate.jl:651
│     [38] cd(f::Literate.var"#42#43"{Dict{String, Any}, IOBuffer, Module, Literate.CodeChunk, Int64}, dir::String)
│        @ Base.Filesystem ./file.jl:112
│     [39] markdown(inputfile::String, outputdir::String; config::Dict{Any, Any}, kwargs::@Kwargs{execute::Bool, documenter::Bool, preprocess::var"#mdpre#generate_tutorial##2"{String}})
│        @ Literate ~/.julia/packages/Literate/On3EJ/src/Literate.jl:650
│     [40] markdown (repeats 2 times)
│        @ ~/.julia/packages/Literate/On3EJ/src/Literate.jl:614 [inlined]
│     [41] (::var"#generate_tutorial##0#generate_tutorial##1"{String})()
│        @ Main ~/work/ClimaLand.jl/ClimaLand.jl/docs/make.jl:47
│     [42] cd(f::var"#generate_tutorial##0#generate_tutorial##1"{String}, dir::String)
│        @ Base.Filesystem ./file.jl:112
│     [43] generate_tutorial(tutorials_dir::String, tutorial::String)
│        @ Main ~/work/ClimaLand.jl/ClimaLand.jl/docs/make.jl:37
│     [44] (::var"#12#13")(t::String)
│        @ Main ~/work/ClimaLand.jl/ClimaLand.jl/docs/make.jl:66
│     [45] foreach(f::var"#12#13", itr::Vector{String})
│        @ Base ./abstractarray.jl:3191
│     [46] top-level scope
│        @ ~/work/ClimaLand.jl/ClimaLand.jl/docs/make.jl:65
│     [47] include(mod::Module, _path::String)
│        @ Base ./Base.jl:306
│     [48] exec_options(opts::Base.JLOptions)
│        @ Base ./client.jl:317
│     [49] _start()
│        @ Base ./client.jl:550
│    in expression starting at /home/runner/.julia/packages/TaylorSeries/ZBRjU/src/intervals.jl:171
└ @ Requires ~/.julia/packages/Requires/1eCOK/src/require.jl:51

Set the simulation float type, determine the context (MPI or on a single node), and device type. Create a default output directory for diagnostics.

const FT = Float64;
context = ClimaComms.context()
ClimaComms.init(context)
device = ClimaComms.device()
device_suffix = device isa ClimaComms.CPUSingleThreaded ? "cpu" : "gpu"
root_path = "bucket_longrun_$(device_suffix)"
diagnostics_outdir = joinpath(root_path, "global_diagnostics")
outdir =
    ClimaUtilities.OutputPathGenerator.generate_output_path(diagnostics_outdir);

Set timestep, startdate, stopdate:

Δt = 900.0
start_date = DateTime(2008)
stop_date = DateTime(2009);

Create the domain - this is intentionally low resolution, about 4.5 degrees x 4.5 degrees, to run quickly when making the documentation on CPU.

nelements = (20, 7)
depth = FT(3.5)
dz_tuple = FT.((1.0, 0.05))
domain =
    ClimaLand.Domains.global_domain(FT; context, nelements, depth, dz_tuple);

Parameters:

toml_dict = LP.create_toml_dict(FT)
α_snow = FT(0.8)
albedo = PrescribedBaregroundAlbedo{FT}(α_snow, domain.space.surface)
bucket_parameters = BucketModelParameters(
    toml_dict;
    albedo,
    σS_c = FT(0.2),
    W_f = FT(0.2),
    z_0m = FT(1e-3),
    z_0b = FT(1e-3),
    κ_soil = FT(1.5),
    ρc_soil = FT(2e6),
    τc = FT(float(Δt)),
);

Low-resolution forcing data from ERA5 is used here, but high-resolution should be used for production runs.

atmos, radiation = ClimaLand.prescribed_forcing_era5(
    start_date,
    stop_date,
    domain.space.surface,
    toml_dict,
    FT;
    use_lowres_forcing = true,
    max_wind_speed = 25.0,
    time_interpolation_method = LinearInterpolation(PeriodicCalendar()),
    regridder_type = :InterpolationsRegridder,
    context,
);

Make the model:

bucket = BucketModel(
    parameters = bucket_parameters,
    domain = domain,
    atmosphere = atmos,
    radiation = radiation,
);

Create a function which sets the initial conditions. This should have the argument structure (Y,p,t, model) in order to be used by the LandSimulation struct, below:

function set_ic!(Y, p, t, bucket)
    coords = ClimaCore.Fields.coordinate_field(Y.bucket.T)
    T_sfc_0 = 271.0
    @. Y.bucket.T = T_sfc_0 + 40 * cosd(coords.lat)^4
    Y.bucket.W .= 0.15
    Y.bucket.Ws .= 0.0
    Y.bucket.σS .= 0.0
end
set_ic! (generic function with 1 method)

Define timestepper and ODE algorithm

timestepper = CTS.RK4()
timestepper = CTS.ExplicitAlgorithm(timestepper);

Create the simulation and solve it:

simulation = LandSimulation(
    start_date,
    stop_date,
    Δt,
    bucket;
    set_ic!,
    timestepper,
    outdir,
    user_callbacks = (),
);

solve!(simulation);

Make some plots:

short_names = ["lhf", "shf", "wsoil"]

LandSimVis.make_annual_timeseries(
    simulation;
    savedir = ".",
    short_names,
    plot_stem_name = "bucket_annual_timeseries",
)

LandSimVis.make_heatmaps(
    simulation;
    savedir = ".",
    short_names,
    date = stop_date,
    plot_stem_name = "bucket_heatmap",
)


This page was generated using Literate.jl.