@@ -74,21 +74,6 @@ long = FT(-92.2000) # degree
74
74
# Height of the sensor at the site
75
75
atmos_h = FT (32 ) # m
76
76
77
- # Setup the domain for the model:
78
- nelements = 10
79
- zmin = FT (- 2 )
80
- zmax = FT (0 )
81
- f_root_to_shoot = FT (3.5 )
82
- plant_ν = FT (2.46e-4 )
83
- n_stem = Int64 (1 )
84
- n_leaf = Int64 (1 )
85
- h_stem = FT (9 )
86
- h_leaf = FT (9.5 )
87
- compartment_midpoints = [h_stem / 2 , h_stem + h_leaf / 2 ]
88
- compartment_surfaces = [zmax, h_stem, h_stem + h_leaf]
89
- land_domain =
90
- Column (; zlim = (zmin, zmax), nelements = nelements, longlat = (long, lat));
91
-
92
77
# Specify the time range and dt value over which to perform the simulation.
93
78
t0 = Float64 (150 * 3600 * 24 )# start mid year
94
79
N_days = 100
@@ -112,6 +97,15 @@ dt = Float64(30)
112
97
earth_param_set,
113
98
FT,
114
99
);
100
+
101
+ # Setup the domain for the model:
102
+
103
+ nelements = 10
104
+ zmin = FT (- 2 )
105
+ zmax = FT (0 )
106
+ domain =
107
+ Column (; zlim = (zmin, zmax), nelements = nelements, longlat = (long, lat));
108
+
115
109
# # Setup the Coupled Canopy and Soil Physics Model
116
110
117
111
# We want to simulate the canopy-soil system together, so the model type
@@ -121,15 +115,15 @@ dt = Float64(30)
121
115
# type and arguments as well as the canopy model component types, component
122
116
# arguments, and the canopy model arguments, so we first need to initialize
123
117
# all of these.
118
+ prognostic_land_components = (:canopy , :soil , :soilco2 );
124
119
125
120
# For our soil model, we will choose the
126
121
# [`EnergyHydrology`](https://clima.github.io/ClimaLand.jl/dev/APIs/Soil/#Soil-Models-2)
127
122
# and set up all the necessary arguments. See the
128
123
# [tutorial](https://clima.github.io/ClimaLand.jl/dev/generated/Soil/soil_energy_hydrology/)
129
124
# on the model for a more detailed explanation of the soil model.
130
125
131
- # Define the parameters for the soil model and provide them to the model
132
- # parameters struct:
126
+ # Define the parameters for the soil model and provide them to the model constructor.
133
127
134
128
# Soil parameters
135
129
soil_ν = FT (0.5 ) # m3/m3
@@ -138,184 +132,146 @@ soil_S_s = FT(1e-3) # 1/m
138
132
soil_vg_n = FT (2.05 ) # unitless
139
133
soil_vg_α = FT (0.04 ) # inverse meters
140
134
θ_r = FT (0.067 ); # m3/m3
141
-
142
- # Soil heat transfer parameters
143
135
ν_ss_quartz = FT (0.1 )
144
136
ν_ss_om = FT (0.1 )
145
137
ν_ss_gravel = FT (0.0 );
138
+
146
139
z_0m_soil = FT (0.1 )
147
140
z_0b_soil = FT (0.1 )
148
141
soil_ϵ = FT (0.98 )
149
142
soil_α_PAR = FT (0.2 )
150
143
soil_α_NIR = FT (0.4 )
151
144
152
- soil_domain = land_domain
153
145
soil_albedo = ClimaLand. Soil. ConstantTwoBandSoilAlbedo {FT} (;
154
146
PAR_albedo = soil_α_PAR,
155
147
NIR_albedo = soil_α_NIR,
156
148
)
157
- soil_ps = Soil. EnergyHydrologyParameters (
158
- FT;
159
- ν = soil_ν,
160
- ν_ss_om = ν_ss_om,
161
- ν_ss_quartz = ν_ss_quartz,
162
- ν_ss_gravel = ν_ss_gravel,
163
- hydrology_cm = vanGenuchten {FT} (; α = soil_vg_α, n = soil_vg_n),
164
- K_sat = soil_K_sat,
149
+ runoff_model = ClimaLand. Soil. Runoff. NoRunoff ()
150
+
151
+ soil = EnergyHydrology {FT} (
152
+ domain,
153
+ (; atmos, radiation),
154
+ earth_param_set;
155
+ prognostic_land_components,
156
+ albedo = soil_albedo,
157
+ runoff = runoff_model,
158
+ additional_sources = (ClimaLand. RootExtraction {FT} (),),
159
+ retention_parameters = (;
160
+ ν = soil_ν,
161
+ θ_r,
162
+ K_sat = soil_K_sat,
163
+ hydrology_cm = vanGenuchten {FT} (; α = soil_vg_α, n = soil_vg_n),
164
+ ),
165
+ composition_parameters = (; ν_ss_om, ν_ss_quartz, ν_ss_gravel),
165
166
S_s = soil_S_s,
166
- θ_r = θ_r,
167
- earth_param_set = earth_param_set,
168
167
z_0m = z_0m_soil,
169
168
z_0b = z_0b_soil,
170
169
emissivity = soil_ϵ,
171
- albedo = soil_albedo,
172
170
);
173
171
174
- soil_args = (domain = soil_domain, parameters = soil_ps)
175
- soil_model_type = Soil. EnergyHydrology{FT}
176
-
177
172
# For the heterotrophic respiration model, see the
178
173
# [documentation](https://clima.github.io/ClimaLand.jl/previews/PR214/dynamicdocs/pages/soil_biogeochemistry/microbial_respiration/)
179
174
# to understand the parameterisation.
180
175
# The domain is defined similarly to the soil domain described above.
181
- soilco2_type = Soil. Biogeochemistry. SoilCO2Model{FT}
182
- soilco2_ps = SoilCO2ModelParameters (FT);
183
- Csom = ClimaLand. PrescribedSoilOrganicCarbon {FT} (TimeVaryingInput ((t) -> 5 ))
184
- soilco2_args = (; domain = soil_domain, parameters = soilco2_ps)
185
-
186
- # Next we need to set up the [`CanopyModel`](https://clima.github.io/ClimaLand.jl/dev/APIs/canopy/Canopy/#Canopy-Model-Structs).
187
- # For more details on the specifics of this model see the previous tutorial.
188
-
189
- # Begin by declaring the component types of the canopy model. Unlike in the
190
- # previous tutorial, collect the arguments to each component into tuples and do
191
- # not instantiate the component models yet. The constructor for the
192
- # SoilPlantHydrologyModel will use these arguments and internally instatiate the
193
- # component CanopyModel and RichardsModel instances. This is done so that the
194
- # constructor may enforce consistency constraints between the two models, and
195
- # this must be done internally from the constructor.
196
-
197
- canopy_component_types = (;
198
- autotrophic_respiration = Canopy. AutotrophicRespirationModel{FT},
199
- radiative_transfer = Canopy. TwoStreamModel{FT},
200
- photosynthesis = Canopy. FarquharModel{FT},
201
- conductance = Canopy. MedlynConductanceModel{FT},
202
- hydraulics = Canopy. PlantHydraulicsModel{FT},
176
+ soil_organic_carbon =
177
+ ClimaLand. PrescribedSoilOrganicCarbon {FT} (TimeVaryingInput ((t) -> 5 ));
178
+ co2_prognostic_soil = Soil. Biogeochemistry. PrognosticMet (soil. parameters);
179
+ drivers = Soil. Biogeochemistry. SoilDrivers (
180
+ co2_prognostic_soil,
181
+ soil_organic_carbon,
182
+ atmos,
203
183
);
184
+ soilco2 = Soil. Biogeochemistry. SoilCO2Model {FT} (; domain, drivers);
204
185
205
- # Then provide arguments to the canopy radiative transfer, stomatal conductance,
206
- # and photosynthesis models as was done in the previous tutorial.
207
-
208
- autotrophic_respiration_args =
209
- (; parameters = AutotrophicRespirationParameters (FT))
210
-
211
- radiative_transfer_args = (;
212
- parameters = TwoStreamParameters (
213
- FT;
214
- G_Function = ConstantGFunction (FT (0.5 )),
215
- α_PAR_leaf = 0.1 ,
216
- α_NIR_leaf = 0.45 ,
217
- τ_PAR_leaf = 0.05 ,
218
- τ_NIR_leaf = 0.25 ,
219
- Ω = 0.69 ,
220
- )
221
- )
222
-
223
- conductance_args = (; parameters = MedlynConductanceParameters (FT; g1 = 141 ))
224
-
225
- is_c3 = FT (1 ) # set the photosynthesis mechanism to C3
226
- photosynthesis_args =
227
- (; parameters = FarquharParameters (FT, is_c3; Vcmax25 = FT (5e-5 )));
228
-
229
- K_sat_plant = FT (1.8e-8 )
230
-
231
- # Read in LAI from MODIS data
232
- surface_space = land_domain. space. surface;
186
+ # Read in prescribed LAI at the site from global MODIS data
187
+ surface_space = domain. space. surface;
233
188
modis_lai_ncdata_path = ClimaLand. Artifacts. modis_lai_multiyear_paths (;
234
189
start_date = start_date + Second (t0),
235
190
end_date = start_date + Second (t0) + Second (tf),
236
- )
191
+ );
237
192
LAI = ClimaLand. prescribed_lai_modis (
238
193
modis_lai_ncdata_path,
239
194
surface_space,
240
195
start_date,
241
196
);
242
197
# Get the maximum LAI at this site over the first year of the simulation
243
198
maxLAI =
244
- FluxnetSimulations. get_maxLAI_at_site (modis_lai_ncdata_path[1 ], lat, long)
199
+ FluxnetSimulations. get_maxLAI_at_site (modis_lai_ncdata_path[1 ], lat, long);
200
+
201
+ # For a coupled SoilCanopyModel, we provide a flag to the canopy that indicates
202
+ # the ground forcing is prognostic (i.e. the soil model) rather than prescribed.
203
+ ground = ClimaLand. PrognosticSoilConditions {FT} ();
204
+
205
+ # Next we need to set up the [`CanopyModel`](https://clima.github.io/ClimaLand.jl/dev/APIs/canopy/Canopy/#Canopy-Model-Structs).
206
+ # For more details on the specifics of this model see the previous tutorial.
207
+ surface_domain = ClimaLand. Domains. obtain_surface_domain (domain);
208
+
209
+ # Let's overwrite some default parameters for the canopy model components.
210
+ # This involves constructing the components individually and then
211
+ # passing them to the canopy model constructor.
212
+
213
+ # Canopy conductance
214
+ conductance = Canopy. MedlynConductanceModel {FT} (surface_domain; g1 = 141 );
215
+
216
+ # Canopy radiative transfer
217
+ radiation_parameters = (;
218
+ G_Function = ConstantGFunction (FT (0.5 )),
219
+ α_PAR_leaf = 0.1 ,
220
+ α_NIR_leaf = 0.45 ,
221
+ τ_PAR_leaf = 0.05 ,
222
+ τ_NIR_leaf = 0.25 ,
223
+ Ω = 0.69 ,
224
+ );
225
+ radiative_transfer = TwoStreamModel {FT} (surface_domain; radiation_parameters);
245
226
227
+ # Canopy photosynthesis
228
+ photosynthesis_parameters = (; is_c3 = FT (1 ), Vcmax25 = FT (5e-5 ));
229
+ photosynthesis = FarquharModel {FT} (surface_domain; photosynthesis_parameters);
230
+
231
+ # Canopy hydraulics
232
+ n_stem = Int64 (1 )
233
+ n_leaf = Int64 (1 )
234
+ h_stem = FT (9 )
235
+ h_leaf = FT (9.5 )
236
+ f_root_to_shoot = FT (3.5 )
237
+ plant_ν = FT (0.7 )
238
+ plant_S_s = FT (1e-2 * 0.0098 )
246
239
SAI = FT (0.00242 )
247
240
RAI = (SAI + maxLAI) * f_root_to_shoot;
248
- ai_parameterization = PrescribedSiteAreaIndex {FT} (LAI, SAI, RAI)
249
-
241
+ K_sat_plant = FT (1.8e-8 )
250
242
ψ63 = FT (- 4 / 0.0098 )
251
243
Weibull_param = FT (4 )
252
- a = FT (0.05 * 0.0098 )
253
-
254
244
conductivity_model =
255
245
PlantHydraulics. Weibull {FT} (K_sat_plant, ψ63, Weibull_param)
256
-
257
- retention_model = PlantHydraulics. LinearRetentionCurve {FT} (a)
258
-
259
- plant_ν = FT (0.7 )
260
- plant_S_s = FT (1e-2 * 0.0098 )
261
-
262
- plant_hydraulics_ps = PlantHydraulics. PlantHydraulicsParameters (;
263
- ai_parameterization = ai_parameterization,
246
+ hydraulics = Canopy. PlantHydraulicsModel {FT} (
247
+ surface_domain,
248
+ LAI;
249
+ SAI,
250
+ RAI,
251
+ n_stem,
252
+ n_leaf,
253
+ h_stem,
254
+ h_leaf,
264
255
ν = plant_ν,
265
256
S_s = plant_S_s,
266
- rooting_depth = FT (1.0 ),
267
- conductivity_model = conductivity_model,
268
- retention_model = retention_model,
257
+ conductivity_model,
258
+ rooting_depth = FT (1 ),
269
259
)
270
260
271
- plant_hydraulics_args = (
272
- parameters = plant_hydraulics_ps,
273
- n_stem = n_stem,
274
- n_leaf = n_leaf,
275
- compartment_midpoints = compartment_midpoints,
276
- compartment_surfaces = compartment_surfaces,
261
+ canopy = ClimaLand. Canopy. CanopyModel {FT} (
262
+ surface_domain,
263
+ (; atmos, radiation, ground),
264
+ LAI,
265
+ earth_param_set;
266
+ prognostic_land_components = (:canopy , :soil , :soilco2 ),
267
+ conductance,
268
+ radiative_transfer,
269
+ photosynthesis,
270
+ hydraulics,
277
271
);
278
272
279
- # We may now collect all of the canopy component argument tuples into one
280
- # arguments tuple for the canopy component models.
281
-
282
- canopy_component_args = (;
283
- autotrophic_respiration = autotrophic_respiration_args,
284
- radiative_transfer = radiative_transfer_args,
285
- photosynthesis = photosynthesis_args,
286
- conductance = conductance_args,
287
- hydraulics = plant_hydraulics_args,
288
- );
289
-
290
- # We also need to provide the shared parameter struct to the canopy.
291
- z0_m = FT (2 )
292
- z0_b = FT (0.2 )
293
-
294
- shared_params = SharedCanopyParameters {FT, typeof(earth_param_set)} (
295
- z0_m,
296
- z0_b,
297
- earth_param_set,
298
- )
299
- canopy_domain = obtain_surface_domain (land_domain)
300
- canopy_model_args = (; parameters = shared_params, domain = canopy_domain);
301
-
302
- # We may now instantiate the integrated plant and soil model. In this example,
303
- # we will compute transpiration diagnostically, and work with prescribed
304
- # atmospheric and radiative flux conditions from the observations at the Ozark
305
- # site as was done in the previous tutorial.
306
-
307
- land_input = (atmos = atmos, radiation = radiation, soil_organic_carbon = Csom)
308
-
309
- land = SoilCanopyModel {FT} (;
310
- soilco2_type = soilco2_type,
311
- soilco2_args = soilco2_args,
312
- land_args = land_input,
313
- soil_model_type = soil_model_type,
314
- soil_args = soil_args,
315
- canopy_component_types = canopy_component_types,
316
- canopy_component_args = canopy_component_args,
317
- canopy_model_args = canopy_model_args,
318
- );
273
+ # Now we can combine the soil and canopy models into a single combined model.
274
+ land = SoilCanopyModel {FT} (soilco2, soil, canopy);
319
275
320
276
# Now we can initialize the state vectors and model coordinates, and initialize
321
277
# the explicit/implicit tendencies as usual. The Richard's equation time
@@ -329,8 +285,7 @@ jacobian! = make_jacobian(land);
329
285
jac_kwargs =
330
286
(; jac_prototype = ClimaLand. FieldMatrixWithSolver (Y), Wfact = jacobian!);
331
287
332
- # We need to provide initial conditions for the soil and canopy hydraulics
333
- # models:
288
+ # We need to provide initial conditions for the model:
334
289
Y. soil. ϑ_l = FT (0.4 )
335
290
Y. soil. θ_i = FT (0.0 )
336
291
T_0 = FT (288.7 )
@@ -346,24 +301,24 @@ Y.soil.ρe_int =
346
301
347
302
Y. soilco2. C .= FT (0.000412 ) # set to atmospheric co2, mol co2 per mol air
348
303
304
+ canopy_retention_model = canopy. hydraulics. parameters. retention_model
349
305
ψ_stem_0 = FT (- 1e5 / 9800 )
350
306
ψ_leaf_0 = FT (- 2e5 / 9800 )
351
307
352
308
S_l_ini =
353
309
inverse_water_retention_curve .(
354
- retention_model ,
310
+ canopy_retention_model ,
355
311
[ψ_stem_0, ψ_leaf_0],
356
312
plant_ν,
357
313
plant_S_s,
358
314
)
359
-
360
315
for i in 1 : 2
361
316
Y. canopy. hydraulics. ϑ_l.:($ i) .=
362
317
augmented_liquid_fraction .(plant_ν, S_l_ini[i])
363
- end ;
364
-
365
- # Select the timestepper and solvers needed for the specific problem.
318
+ end
319
+ evaluate! (Y. canopy. energy. T, atmos. T, t0)
366
320
321
+ # Choose the timestepper and solver needed for the problem.
367
322
timestepper = CTS. ARS343 ()
368
323
ode_algo = CTS. IMEXAlgorithm (
369
324
timestepper,
@@ -374,7 +329,6 @@ ode_algo = CTS.IMEXAlgorithm(
374
329
);
375
330
376
331
# Now set the initial values for the cache variables for the combined soil and plant model.
377
-
378
332
set_initial_cache! = make_set_initial_cache (land)
379
333
set_initial_cache! (p, Y, t0);
380
334
0 commit comments