Skip to content

Commit 17e446e

Browse files
AlexisRenchonychnli
andcommitted
Add a AbstractSoilMoistureStressModel, 3 methods
This commits adds a portion of Yuchen Li PR #1330, a new Canopy component: AbstractSoilMoistureStressModel, with 3 methods: the existing one (Tuzet) which was previously in PlantHydraulics, a Piecewise method using dry to wet soil moisture, and no moisture stress. NOTE: some new formatting it seems using JuliaFormatter v1 Co-authored-by: AlexisRenchon <[email protected]> Co-authored-by: ychnli <[email protected]>
1 parent 6648726 commit 17e446e

File tree

26 files changed

+795
-186
lines changed

26 files changed

+795
-186
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Soil moisture stress
2+
3+
```@meta
4+
CurrentModule = ClimaLand.Canopy
5+
```
6+
7+
## Models and Parameters
8+
9+
```@docs
10+
ClimaLand.Canopy.TuzetMoistureStressParameters
11+
ClimaLand.Canopy.TuzetMoistureStressModel
12+
ClimaLand.Canopy.TuzetMoistureStressModel{FT}()
13+
ClimaLand.Canopy.PiecewiseMoistureStressParameters
14+
ClimaLand.Canopy.PiecewiseMoistureStressParameters()
15+
ClimaLand.Canopy.PiecewiseMoistureStressModel
16+
ClimaLand.Canopy.PiecewiseMoistureStressModel{FT}()
17+
ClimaLand.Canopy.PiecewiseMoistureStressParametersFromHydrology()
18+
ClimaLand.Canopy.NoMoistureStressModel
19+
```
20+
21+
## Methods
22+
23+
```@docs
24+
ClimaLand.Canopy.compute_piecewise_moisture_stress
25+
ClimaLand.Canopy.update_soil_moisture_stress!
26+
```

docs/src/tutorials/calibration/obs_site_level_calibration.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ function G(Vcmax25, g1)
238238
simulation.start_date,
239239
simulation.start_date + Day(20),
240240
stop_date,
241-
)
241+
),
242242
)
243243
return observation
244244
end;

docs/src/tutorials/calibration/perfect_model_site_level_calibration.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ function G(Vcmax25)
206206
lhf,
207207
simulation.start_date,
208208
simulation.start_date + Day(20),
209-
)
209+
),
210210
)
211211
return observation
212212
end

experiments/integrated/fluxnet/ozark_pmodel.jl

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ dt = Float64(450) # 7.5 minutes
112112
atmos_h,
113113
start_date,
114114
earth_param_set,
115-
FT,
115+
FT;
116+
construct_prescribed_soil = false,
116117
)
117118

118119

@@ -179,6 +180,17 @@ conductance = PModelConductance{FT}()
179180
# Set up photosynthesis
180181
photosynthesis = PModel{FT}()
181182

183+
# Set up soil moisture stress
184+
soil_moisture_stress_params = PiecewiseMoistureStressParameters(
185+
FT;
186+
θ_c = FT(0.60),
187+
θ_w = FT(0.10),
188+
c = FT(1.0),
189+
β0 = FT(1.0),
190+
)
191+
soil_moisture_stress =
192+
PiecewiseMoistureStressModel{FT}(soil_moisture_stress_params)
193+
182194
# Set up plant hydraulics
183195
# Read in LAI from MODIS data
184196
surface_space = land_domain.space.surface;
@@ -222,6 +234,7 @@ canopy = Canopy.CanopyModel{FT}(
222234
radiative_transfer,
223235
photosynthesis,
224236
conductance,
237+
soil_moisture_stress,
225238
hydraulics,
226239
energy,
227240
)
@@ -265,7 +278,8 @@ simulation = LandSimulation(
265278
set_ic!,
266279
updateat,
267280
diagnostics = diags,
268-
);
281+
)
282+
269283
@time solve!(simulation)
270284

271285
comparison_data = FluxnetSimulations.get_comparison_data(site_ID, time_offset)

experiments/integrated/performance/conservation/ozark_conservation.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ for float_type in (Float32, Float64)
8686
[parent(sv.saveval[k].drivers.T)[1] for k in 1:length(sv.t)]
8787
@assert mean(
8888
abs.(
89-
cos.(radiation.θs.(sv.t, radiation.start_date)) .- cache_cosθs
89+
cos.(radiation.θs.(sv.t, radiation.start_date)) .- cache_cosθs,
9090
),
9191
) < eps(FT)
9292
T_mutable = Vector{FT}(undef, 1)
@@ -201,7 +201,7 @@ for float_type in (Float32, Float64)
201201
eps(FT) .+
202202
abs.(
203203
(soil_mass_change_actual - soil_mass_change_exp) ./
204-
soil_mass_change_exp
204+
soil_mass_change_exp,
205205
),
206206
label = "Soil Water Balance",
207207
)
@@ -211,7 +211,7 @@ for float_type in (Float32, Float64)
211211
eps(FT) .+
212212
abs.(
213213
(canopy_mass_change_actual - canopy_mass_change_exp) ./
214-
canopy_mass_change_exp
214+
canopy_mass_change_exp,
215215
),
216216
label = "Canopy Water Balance",
217217
)
@@ -272,7 +272,7 @@ for float_type in (Float32, Float64)
272272
eps(FT) .+
273273
abs.(
274274
(soil_energy_change_actual - soil_energy_change_exp) ./
275-
soil_energy_change_exp
275+
soil_energy_change_exp,
276276
),
277277
label = "Soil Energy Balance",
278278
)

ext/land_sim_vis/leaderboard/leaderboard.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ function compute_monthly_leaderboard(
205205
months =
206206
Dates.month.(
207207
Dates.DateTime(sim_var.attributes["start_date"]) .+
208-
Dates.Second.(times)
208+
Dates.Second.(times),
209209
)
210210
months_split, sim_vec_split, rmse_vec_split, bias_vec_split =
211211
partition_by_val(12, months, sim_vec, rmse_vec, bias_vec)

ext/neural_snow/DataTools.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ function serreze_qc(input::DataFrame, id::Int, state::AbstractString)
761761
data[!, :tmax] = maxmin[!, :tmax]
762762
flags =
763763
ismissing.(
764-
data[1:(end - 1), [:SWE, :precip, :air_temp_avg, :tmin, :tmax]]
764+
data[1:(end - 1), [:SWE, :precip, :air_temp_avg, :tmin, :tmax]],
765765
)
766766
flags[!, :date] = data[1:(end - 1), :date]
767767

src/diagnostics/default_diagnostics.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ function default_diagnostics(
112112
diagnostics = get_short_diagnostics(model)
113113
else
114114
@assert typeof(output_vars) <: Vector{String}
115-
@assert all([var possible_diags for var in output_vars])
115+
@assert all([var in possible_diags for var in output_vars])
116116
diagnostics = output_vars
117117
end
118118

@@ -178,7 +178,7 @@ function default_diagnostics(
178178
diagnostics = possible_diags
179179
else
180180
@assert typeof(output_vars) <: Vector{String}
181-
@assert all([var possible_diags for var in output_vars])
181+
@assert all([var in possible_diags for var in output_vars])
182182
diagnostics = output_vars
183183
end
184184

src/diagnostics/land_compute_methods.jl

Lines changed: 17 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,14 @@ function compute_stomatal_conductance!(
115115
end
116116

117117
function compute_stomatal_conductance!(out, Y, p, t, land_model::CanopyModel)
118-
compute_stomatal_conductance!(out, Y, p, t, land_model, canopy.conductance)
118+
compute_stomatal_conductance!(
119+
out,
120+
Y,
121+
p,
122+
t,
123+
land_model,
124+
land_model.conductance,
125+
)
119126
end
120127

121128
function compute_stomatal_conductance!(
@@ -273,61 +280,6 @@ function compute_leaf_water_potential!(out, Y, p, t, land_model::CanopyModel)
273280
end
274281
end
275282

276-
function compute_moisture_stress_factor!(
277-
out,
278-
Y,
279-
p,
280-
t,
281-
land_model::Union{SoilCanopyModel, LandModel},
282-
)
283-
canopy = land_model.canopy
284-
hydraulics = canopy.hydraulics
285-
n_stem = hydraulics.n_stem
286-
n_leaf = hydraulics.n_leaf
287-
n = n_stem + n_leaf
288-
289-
earth_param_set = canopy.parameters.earth_param_set
290-
grav = LP.grav(earth_param_set)
291-
ρ_l = LP.ρ_cloud_liq(earth_param_set)
292-
(; sc, pc) = canopy.photosynthesis.parameters
293-
ψ = p.canopy.hydraulics.ψ
294-
if isnothing(out)
295-
out = zeros(land_model.canopy.domain.space.surface) # Allocates
296-
fill!(field_values(out), NaN)
297-
@. out = moisture_stress(ψ.:($$n) * ρ_l * grav, sc, pc)
298-
return out
299-
else
300-
@. out = moisture_stress(ψ.:($$n) * ρ_l * grav, sc, pc)
301-
end
302-
end
303-
function compute_moisture_stress_factor!(
304-
out,
305-
Y,
306-
p,
307-
t,
308-
land_model::Union{CanopyModel},
309-
)
310-
canopy = land_model
311-
hydraulics = canopy.hydraulics
312-
n_stem = hydraulics.n_stem
313-
n_leaf = hydraulics.n_leaf
314-
n = n_stem + n_leaf
315-
316-
earth_param_set = canopy.parameters.earth_param_set
317-
grav = LP.grav(earth_param_set)
318-
ρ_l = LP.ρ_cloud_liq(earth_param_set)
319-
(; sc, pc) = canopy.photosynthesis.parameters
320-
ψ = p.canopy.hydraulics.ψ
321-
if isnothing(out)
322-
out = zeros(land_model.canopy.domain.space.surface) # Allocates
323-
fill!(field_values(out), NaN)
324-
@. out = moisture_stress(ψ.:($$n) * ρ_l * grav, sc, pc)
325-
return out
326-
else
327-
@. out = moisture_stress(ψ.:($$n) * ρ_l * grav, sc, pc)
328-
end
329-
end
330-
331283
# @diagnostic_compute "flux_per_ground_area" Union{SoilCanopyModel, LandModel} p.canopy.hydraulics.fa # return a Tuple
332284
@diagnostic_compute "root_flux_per_ground_area" Union{
333285
SoilCanopyModel,
@@ -340,6 +292,13 @@ end
340292
CanopyModel,
341293
} p.canopy.hydraulics.area_index.leaf
342294

295+
# Canopy - Soil moisture stress
296+
@diagnostic_compute "moisture_stress_factor" Union{
297+
SoilCanopyModel,
298+
LandModel,
299+
CanopyModel,
300+
} p.canopy.soil_moisture_stress.βm
301+
343302
# Canopy - Hydraulics
344303
@diagnostic_compute "root_area_index" Union{
345304
SoilCanopyModel,
@@ -574,8 +533,8 @@ end # Convert from kg C to mol CO2.
574533

575534
## Other ##
576535
@diagnostic_compute "sw_albedo" Union{SoilCanopyModel, LandModel} p.α_sfc
577-
@diagnostic_compute "lw_up" Union{SoilCanopyModel, LandModel} p.LW_u
578-
@diagnostic_compute "sw_up" Union{SoilCanopyModel, LandModel} p.SW_u
536+
@diagnostic_compute "lw_up" Union{SoilCanopyModel, LandModel, CanopyModel} p.LW_u
537+
@diagnostic_compute "sw_up" Union{SoilCanopyModel, LandModel, CanopyModel} p.SW_u
579538
@diagnostic_compute "surface_runoff" Union{SoilCanopyModel, LandModel} p.soil.R_s
580539
@diagnostic_compute "subsurface_runoff" Union{SoilCanopyModel, LandModel} p.soil.R_ss
581540

src/integrated/land.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,17 @@ function LandModel{FT}(;
184184
energy_model = PrescribedCanopyTempModel{FT}()
185185
end
186186

187+
if :soil_moisture_stress in propertynames(canopy_component_types)
188+
soil_moisture_stress_model =
189+
canopy_component_types.soil_moisture_stress(
190+
canopy_component_args.soil_moisture_stress...,
191+
)
192+
else
193+
@info "No soil moisture stress model provided, using NoMoistureStressModel (βm = 1.0)"
194+
soil_moisture_stress_model =
195+
ClimaLand.Canopy.NoMoistureStressModel{FT}()
196+
end
197+
187198
canopy = Canopy.CanopyModel{FT}(;
188199
autotrophic_respiration = canopy_component_types.autotrophic_respiration(
189200
canopy_component_args.autotrophic_respiration...,
@@ -197,6 +208,7 @@ function LandModel{FT}(;
197208
conductance = canopy_component_types.conductance(
198209
canopy_component_args.conductance...,
199210
),
211+
soil_moisture_stress = soil_moisture_stress_model,
200212
hydraulics = canopy_component_types.hydraulics(;
201213
transpiration = transpiration,
202214
canopy_component_args.hydraulics...,

0 commit comments

Comments
 (0)