@@ -2,7 +2,6 @@ module Simulations
2
2
using ClimaTimeSteppers
3
3
using ClimaComms
4
4
import ClimaComms: context, device
5
- using SciMLBase
6
5
using Dates
7
6
import ClimaUtilities. TimeManager: ITime, date
8
7
import ClimaDiagnostics
@@ -12,50 +11,67 @@ using ClimaLand.ModelSetup
12
11
include (" initial_conditions.jl" )
13
12
14
13
"""
15
- LandSimulation{
16
- M <: ClimaLand.AbstractModel,
17
- T <: ClimaTimeSteppers.DistributedODEAlgorithm,
18
- UC,
19
- DI,
20
- RC,
21
- CA <: SciMLBase.CallbackSet,
22
- I <: SciMLBase.DEIntegrator,
23
- }
24
-
25
- the ClimaLand LandSimulation struct, which specifies
14
+ LandSimulation
15
+
16
+ The ClimaLand LandSimulation struct, which specifies
26
17
- the discrete set of equations to solve (defined by the `model`);
27
- - the timestepping algorithm;
18
+ - the timestepping algorithm (in `timestepper.algo`) ;
28
19
- user callbacks (passed as a tuple) to be executed at specific times in the simulations;
29
20
- the diagnostics to output (optional).
30
21
31
22
User callbacks are optional: examples currently include callbacks that estimate the time
32
23
to solution and SYPD of the simulation as it runs, checkpoint the state, or check the solution
33
24
for NaNs. Others can be added here.
34
25
35
- Diagnostics are implemented as callbacks, and are also optional.
36
- However, a default is provided. `diagnostics` is expected to be a
37
- list of `ClimaDiagnostics.ScheduledDiagnostics`.
26
+ `diagnostics` are provided as a list of `ClimaDiagnostics.ScheduledDiagnostics`,
27
+ with default specified by `default_diagnostics`.
28
+
29
+ The private field `_required_callbacks` consists of callbacks that are required
30
+ for the simulation to run correctly. Currently, this includes the callbacks
31
+ which update the atmospheric forcing and update the LAI using prescribed data.
38
32
39
- Finally, the private field _required_callbacks consists of callbacks that are required for the
40
- simulation to run correctly. Currently, this includes the callbacks which update the atmospheric
41
- forcing and update the LAI using prescribed data.
33
+ Quick tips
34
+ ==========
35
+
36
+ 1. Accessing the state
37
+ ```julia
38
+ sim.u
39
+ ```
40
+ 2. Accessing the current time
41
+ ```julia
42
+ sim.t
43
+ ```
44
+ 3. Accessing the current date
45
+ ```julia
46
+ import ClimaUtilities.TimeManager: date
47
+ date(sim.t)
48
+ ```
49
+ 4. Providing a specific new monthly diagnostics
50
+ ```julia
51
+ diagnostic = ClimaLand.Diagnostics.monthly_average.(["lhf", "shf"])
52
+ ```
42
53
"""
43
- struct LandSimulation{
54
+ mutable struct LandSimulation{
55
+ STATE,
56
+ CACHE,
57
+ TIME,
58
+ TUP_TIME,
44
59
M <: ClimaLand.AbstractModel ,
45
- T <: ClimaTimeSteppers.DistributedODEAlgorithm ,
46
- UC,
60
+ T,
47
61
DI,
48
62
RC,
49
- CA <: SciMLBase.CallbackSet ,
50
- I <: SciMLBase.DEIntegrator ,
63
+ UC,
51
64
}
65
+ u:: STATE
66
+ p:: CACHE
67
+ t:: TIME
68
+ dt:: TIME
69
+ tspan:: TUP_TIME
52
70
model:: M
53
71
timestepper:: T
54
- user_callbacks:: UC
55
- diagnostics:: DI
72
+ diagnostic_handler:: DI
56
73
required_callbacks:: RC
57
- callbacks:: CA
58
- _integrator:: I
74
+ user_callbacks:: UC
59
75
end
60
76
61
77
function LandSimulation (
@@ -128,53 +144,43 @@ function LandSimulation(
128
144
jac_prototype = ClimaLand. FieldMatrixWithSolver (Y),
129
145
Wfact = jacobian!,
130
146
)
131
- T_imp! = SciMLBase . ODEFunction ( imp_tendency!; jac_kwargs... )
147
+ T_imp! = (; f = imp_tendency!, jac_kwargs... )
132
148
end
133
149
134
150
# Create SciML ODE Problem
135
- problem = SciMLBase. ODEProblem (
136
- ClimaTimeSteppers. ClimaODEFunction (
151
+ func = ClimaTimeSteppers. ClimaODEFunction (
137
152
T_exp! = exp_tendency!,
138
153
T_imp! = T_imp!,
139
154
dss! = ClimaLand. dss!,
140
- ),
141
- Y,
142
- (t0, tf),
143
- p,
144
- )
155
+ )
145
156
146
157
# Required callbacks
147
158
updateat = [promote (t0: (ITime (3600 * 3 )): tf... )... ]
148
159
drivers = ClimaLand. get_drivers (model)
149
160
updatefunc = ClimaLand. make_update_drivers (drivers)
150
161
driver_cb = ClimaLand. DriverUpdateCallback (updateat, updatefunc)
151
- required_callbacks = (driver_cb,) # TBD: can we update each step?
162
+ _required_callbacks = (driver_cb,) # TBD: can we update each step?
152
163
153
164
diagnostics = isnothing (diagnostics) ? () : diagnostics
154
165
diagnostic_handler =
155
166
ClimaDiagnostics. DiagnosticsHandler (diagnostics, Y, p, t0; dt = Δt)
156
- diag_cb = ClimaDiagnostics. DiagnosticsCallback (diagnostic_handler)
157
-
158
167
159
- # Collect all callbacks
160
- callbacks =
161
- SciMLBase. CallbackSet (user_callbacks... , required_callbacks... , diag_cb)
162
-
163
- _integrator = SciMLBase. init (
164
- problem,
165
- timestepper;
166
- dt = Δt,
167
- callback = callbacks,
168
- adaptive = false ,
169
- )
168
+ algo = timestepper
169
+ # u0 is used as prototype
170
+ prob = (; u0 = Y, f = func)
171
+ timestepper_cache = ClimaTimeSteppers. init_cache (prob, algo)
172
+ isnothing (func. cache!) || func. cache! (Y, p, t0)
170
173
return LandSimulation (
174
+ Y,
175
+ p,
176
+ t0,
177
+ Δt,
178
+ (t0, tf),
171
179
model,
172
- timestepper,
180
+ (; algo, func, cache = timestepper_cache),
181
+ diagnostic_handler,
182
+ _required_callbacks,
173
183
user_callbacks,
174
- diagnostics,
175
- required_callbacks,
176
- callbacks,
177
- _integrator,
178
184
)
179
185
end
180
186
@@ -185,7 +191,29 @@ Advances the land simulation `landsim` forward in time by one step,
185
191
updating `landsim` in place.
186
192
"""
187
193
function step! (landsim:: LandSimulation )
188
- SciMLBase. step! (landsim. _integrator)
194
+ landsim. t += landsim. dt
195
+
196
+ ClimaTimeSteppers. step_u! (landsim, landsim. timestepper. cache)
197
+ for callback in landsim. _required_callbacks
198
+ callback. condition (landsim. u, landsim. t, landsim) && callback. affect! (landsim)
199
+ end
200
+ for callback in landsim. user_callbacks
201
+ callback. condition (landsim. u, landsim. t, landsim) && callback. affect! (landsim)
202
+ end
203
+ ClimaDiagnostics. orchestrate_diagnostics (landsim, landsim. diagnostic_handler)
204
+ end
205
+
206
+ # Compatibility with SciML
207
+ function Base. getproperty (landsim:: LandSimulation , symbol:: Symbol )
208
+ if symbol === :alg
209
+ return landsim. timestepper. algo
210
+ elseif symbol === :step
211
+ return landsim. t / landsim. dt
212
+ elseif symbol === :sol
213
+ return (; prob = (; f = landsim. timestepper. func, tspan = landsim. tspan))
214
+ else
215
+ return Base. getfield (landsim, symbol)
216
+ end
189
217
end
190
218
191
219
"""
@@ -195,7 +223,9 @@ Advances the land simulation `landsim` forward from the initial to final time,
195
223
updating `landsim` in place.
196
224
"""
197
225
function solve! (landsim:: LandSimulation )
198
- SciMLBase. solve! (landsim. _integrator)
226
+ while landsim. t < last (landsim. tspan)
227
+ step! (landsim)
228
+ end
199
229
end
200
230
201
231
@@ -232,7 +262,7 @@ function Base.show(io::IO, landsim::LandSimulation)
232
262
io,
233
263
" $(model_type) Simulation\n " ,
234
264
" ├── Running on: $(device_type) \n " ,
235
- " └── Current date: $(date (landsim. _integrator . t)) \n " ,
265
+ " └── Current date: $(date (landsim. t)) \n " ,
236
266
)
237
267
end
238
268
end # module
0 commit comments