Skip to content

Commit a4aeefc

Browse files
committed
global simulations
1 parent bc88136 commit a4aeefc

File tree

7 files changed

+408
-22
lines changed

7 files changed

+408
-22
lines changed

src/Artifacts.jl

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,36 @@ end
6060
"""
6161
era5_land_forcing_data2008_path(; context, lowres=false)
6262
63-
Return the path to the directory that contains the ERA5 forcing data for 2008.
63+
Return the path to the file that contains the ERA5 forcing data for 2008.
6464
65-
Optionally, you can pass the lowres=true keyword to download a lower spatial resolution version of the data.
65+
Optionally, you can pass the lowres=true keyword to download a lower spatial resolution version of the data and return the path to that file.
66+
If the high resolution data is not
67+
available locally, we also return the path to the low res data.
6668
"""
6769
function era5_land_forcing_data2008_folder_path(;
6870
context = nothing,
6971
lowres = false,
7072
)
73+
lowres_path = joinpath(
74+
@clima_artifact("era5_land_forcing_data2008_lowres", context),
75+
"era5_2008_1.0x1.0_lowres.nc",
76+
)
7177
if lowres
72-
return @clima_artifact("era5_land_forcing_data2008_lowres", context)
78+
return lowres_path
7379
else
74-
return @clima_artifact("era5_land_forcing_data2008", context)
80+
try
81+
hires_path = joinpath(
82+
@clima_artifact("era5_land_forcing_data2008", context),
83+
"era5_2008_1.0x1.0.nc",
84+
)
85+
86+
return hires_path
87+
catch
88+
@warn(
89+
"High resolution ERA5 forcing not available locally; downloading and using low resolution data instead."
90+
)
91+
return lowres_path
92+
end
7593
end
7694
end
7795

src/shared_utilities/utils.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ using ClimaUtilities.ClimaArtifacts
88
import Interpolations
99
import ClimaUtilities.SpaceVaryingInputs: SpaceVaryingInput
1010
import ClimaUtilities.Regridders: InterpolationsRegridder
11+
import ClimaUtilities.OnlineLogging: WallTimeInfo, report_walltime
1112

1213
export FTfromY, call_count_nans_state
1314

@@ -716,3 +717,14 @@ function landsea_mask(domain::Domains.AbstractDomain; kwargs...)
716717
)
717718
return landsea_mask(domain.space.surface; filepath, kwargs...)
718719
end
720+
721+
722+
function ReportCallback(Nsteps::Int)
723+
walltime_info = WallTimeInfo()
724+
everyNsteps(u, t, integrator) = mod(integrator.step, Nsteps) == 0
725+
report = let wt = walltime_info
726+
(integrator) -> report_walltime(wt, integrator)
727+
end
728+
report_cb = SciMLBase.DiscreteCallback(everyNsteps, report)
729+
return report_cb
730+
end

src/simulations/Simulations.jl

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
module Simulations
2+
using ClimaTimeSteppers
3+
using SciMLBase
4+
using Dates
5+
import ClimaUtilities.TimeVaryingInputs:
6+
TimeVaryingInput, LinearInterpolation, PeriodicCalendar
7+
import ClimaUtilities.ClimaArtifacts: @clima_artifact
8+
import ClimaUtilities.TimeManager: ITime, date
9+
import ClimaDiagnostics
10+
import ClimaParams as CP
11+
using ClimaLand
12+
import ClimaLand.Parameters as LP
13+
14+
include("domains.jl")
15+
include("initial_conditions.jl")
16+
include("spatial_parameters.jl")
17+
include("model_setup.jl")
18+
19+
struct LandSimulation{
20+
C,
21+
P,
22+
M <: ClimaLand.AbstractLandModel,
23+
D <: ClimaLand.Domains.AbstractDomain,
24+
T <: ClimaTimeSteppers.IMEXAlgorithm,
25+
UC,
26+
DI,
27+
RC,
28+
CA <: SciMLBase.CallbackSet,
29+
P <: SciMLBase.ODEProblem,
30+
}
31+
context::C
32+
params::P
33+
model::M
34+
domain::D
35+
timestepper::T
36+
user_callbacks::UC
37+
diagnostics::DI
38+
required_callbacks::RC
39+
callbacks::CA
40+
problem::P
41+
end
42+
43+
function GlobalLandSimulation(
44+
FT,
45+
context,
46+
start_date,
47+
t0,
48+
tf,
49+
Δt;
50+
params = LP.LandParameters(FT),
51+
domain = ClimaLand.global_domain(FT; comms_ctx = context),
52+
model = LandModel(domain, start_date, params, FT), # add assert
53+
set_ic! = ClimaLand.set_ic_from_file(
54+
ClimaLand.Artifacts.soil_ic_2008_50m_path(; context = context),
55+
), # could also support functions
56+
timestepper = ClimaTimeSteppers.IMEXAlgorithm(
57+
ClimaTimeSteppers.ARS111(),
58+
ClimaTimeSteppers.NewtonsMethod(
59+
max_iters = 3,
60+
update_j = ClimaTimeSteppers.UpdateEvery(
61+
ClimaTimeSteppers.NewNewtonIteration,
62+
),
63+
),
64+
),
65+
user_callbacks = (
66+
ClimaLand.NaNCheckCallback(
67+
Dates.Month(1),
68+
start_date,
69+
t0,# needs tobe ITime? promote
70+
Δt; # needs to be ITime? promote
71+
mask = ClimaLand.landsea_mask(domain),
72+
),
73+
ClimaLand.ReportCallback(1000),
74+
),
75+
diagnostics = (;
76+
output_vars = :short,
77+
average_period = :monthly,
78+
outdir = "",
79+
), # need to generalize
80+
)
81+
# convert times to Itime
82+
t0 = ITime(t0, epoch = start_date)
83+
tf = ITime(tf, epoch = start_date)
84+
Δt = ITime(Δt, epoch = start_date)
85+
t0, tf, Δt = promote(t0, tf, Δt)
86+
87+
# set initial conditions
88+
Y, p, cds = initialize(model)
89+
set_ic!(Y, p, model, t0)
90+
set_initial_cache! = make_set_initial_cache(model)
91+
set_initial_cache!(p, Y, t0)
92+
93+
# Create tendencies and jacobian update function
94+
exp_tendency! = make_exp_tendency(model)
95+
imp_tendency! = ClimaLand.make_imp_tendency(model)
96+
jacobian! = ClimaLand.make_jacobian(model)
97+
jac_kwargs = (;
98+
jac_prototype = ClimaLand.FieldMatrixWithSolver(Y),
99+
Wfact = jacobian!,
100+
)
101+
102+
# Create SciML ODE Problem
103+
problem = SciMLBase.ODEProblem(
104+
ClimaTimeSteppers.ClimaODEFunction(
105+
T_exp! = exp_tendency!,
106+
T_imp! = SciMLBase.ODEFunction(imp_tendency!; jac_kwargs...),
107+
dss! = ClimaLand.dss!,
108+
),
109+
Y,
110+
(t0, tf),
111+
p,
112+
)
113+
114+
# Required callbacks
115+
updateat = [promote(t0:(ITime(3600 * 3)):tf...)...]
116+
drivers = ClimaLand.get_drivers(model)
117+
updatefunc = ClimaLand.make_update_drivers(drivers)
118+
driver_cb = ClimaLand.DriverUpdateCallback(updateat, updatefunc)
119+
required_callbacks = (driver_cb,) # can we update each step?
120+
121+
# Diagnostics callbacks - can be generalized in the future
122+
if !(diagnostics isa Nothing)
123+
nc_writer = ClimaDiagnostics.Writers.NetCDFWriter(
124+
domain.space.subsurface,
125+
diagnostics.outdir;
126+
start_date,
127+
)
128+
129+
diags = ClimaLand.default_diagnostics(
130+
model,
131+
start_date;
132+
output_writer = nc_writer,
133+
output_vars = diagnostics.output_vars,
134+
average_period = diagnostics.average_period,
135+
)
136+
137+
diagnostic_handler =
138+
ClimaDiagnostics.DiagnosticsHandler(diags, Y, p, t0; dt = Δt)
139+
diag_cb = (ClimaDiagnostics.DiagnosticsCallback(diagnostic_handler),)
140+
else
141+
diag_cb = ()
142+
end
143+
144+
145+
# Collect all callbacks
146+
callbacks = SciMLBase.CallbackSet(
147+
user_callbacks...,
148+
diag_cb...,
149+
required_callbacks...,
150+
)
151+
152+
#_integrator = SciMLBase.init(problem, callbacks)
153+
154+
return LandSimulation(
155+
context,
156+
params,
157+
model,
158+
domain,
159+
timestepper,
160+
user_callbacks,
161+
diagnostics,
162+
_required_callbacks,
163+
callbacks,
164+
problem,
165+
t
166+
Y,
167+
__p
168+
#_integrator
169+
)
170+
end
171+
172+
function step!(landsimulation)
173+
integrator = SciMLBase.integrator(Y, p, t, callbacks)
174+
SciMLBase.step!(integrator)
175+
simulation.t[] = integrator.t
176+
end
177+
178+
function solve!(simulation)
179+
SciMLBase.solve!(problem, ode_algo, callbacks)
180+
end
181+
182+
function plot(landsimulation)
183+
184+
end
185+
186+
end#module

src/simulations/domains.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ function global_domain(
4444
dz_tuple = (10.0, 0.05),
4545
depth = 50.0,
4646
npolynomial = 0,
47+
comms_ctx = ClimaComms.context(),
4748
)
4849
if pkgversion(ClimaCore) < v"0.14.30" && apply_mask
4950
@warn "The land mask cannot be applied with ClimaCore < v0.14.30. Update ClimaCore for significant performance gains."
@@ -59,6 +60,7 @@ function global_domain(
5960
nelements,
6061
npolynomial,
6162
dz_tuple,
63+
comms_ctx,
6264
)
6365
if apply_mask
6466
surface_space = domain.space.surface # 2d space
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
function GlobalDomain(...)
2+
return SphericalShell()
3+
end
4+
5+
context = ;
6+
FT = ;
7+
param_set = ...earth_param_set(FT)
8+
parameter_maps = spatially_varying_maps(FT, ...)
9+
10+
domain = GlobalDomain(context, )
11+
land = LandModel(FT, domain, params, component_choices; parameter_maps)
12+
# if hires fails to download, use lowres (era5 forcing?)
13+
14+
15+
#set_ic!(Y, land, t0)
16+
timestepper = (alg::ImEx = ARS111, t0, dt, tf; start_date = nothing) # handled internally with itime, e.g. pass in seconds
17+
timestepper = (alg::ImEx = ARS111, t0::DateTime, dt::Seconds, duration::Period) # handled internally with itime
18+
user_callbacks # all SciML callbacks, but we provide helper functions for specific instances (nancheck, report, checkpoint)
19+
diagnostics # Tuple of scheduled diagnostics, diagnostics handler is constructed internally
20+
# driver is combine with user_callbacks and diagnostics callback internally to make the CB set
21+
output_dir # will have default
22+
#context # will have default, this includes the device, or take the device and create the context
23+
config = # specifies a default postprocessing/plots to make
24+
simulation = Simulation(land, set_ic!, domain, timestepper, user_callbacks, diagnostics, config)
25+
26+
27+
28+
29+

0 commit comments

Comments
 (0)