Skip to content

Commit c93d0ef

Browse files
authored
add and use new free drainage BC (#1161)
1 parent f379719 commit c93d0ef

File tree

6 files changed

+124
-22
lines changed

6 files changed

+124
-22
lines changed

docs/src/APIs/Soil.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ ClimaLand.Soil.HeatFluxBC
7272
ClimaLand.Soil.WaterFluxBC
7373
ClimaLand.Soil.TemperatureStateBC
7474
ClimaLand.Soil.FreeDrainage
75+
ClimaLand.Soil.EnergyWaterFreeDrainage
7576
ClimaLand.Soil.RichardsAtmosDrivenFluxBC
7677
ClimaLand.Soil.AtmosDrivenFluxBC
7778
ClimaLand.Soil.WaterHeatBC

experiments/long_runs/soil.jl

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,8 @@ function setup_model(FT, start_date, domain, earth_param_set)
122122
(:soil,),
123123
)
124124
zero_flux = Soil.HeatFluxBC((p, t) -> 0.0)
125-
boundary_conditions = (;
126-
top = top_bc,
127-
bottom = Soil.WaterHeatBC(;
128-
water = Soil.FreeDrainage(),
129-
heat = zero_flux,
130-
),
131-
)
125+
boundary_conditions =
126+
(; top = top_bc, bottom = Soil.EnergyWaterFreeDrainage())
132127
soil = soil_model_type(;
133128
boundary_conditions = boundary_conditions,
134129
sources = sources,

src/integrated/land.jl

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,8 @@ function LandModel{FT}(;
114114
)
115115

116116
zero_flux = Soil.HeatFluxBC((p, t) -> 0.0)
117-
boundary_conditions = (;
118-
top = top_bc,
119-
bottom = Soil.WaterHeatBC(;
120-
water = Soil.FreeDrainage(),
121-
heat = zero_flux,
122-
),
123-
)
117+
boundary_conditions =
118+
(; top = top_bc, bottom = Soil.EnergyWaterFreeDrainage())
124119
soil = soil_model_type(;
125120
boundary_conditions = boundary_conditions,
126121
sources = sources,

src/integrated/soil_canopy_model.jl

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,8 @@ function SoilCanopyModel{FT}(;
8989
prognostic_land_components,
9090
)
9191
zero_flux = Soil.HeatFluxBC((p, t) -> 0.0)
92-
boundary_conditions = (;
93-
top = top_bc,
94-
bottom = Soil.WaterHeatBC(;
95-
water = Soil.FreeDrainage(),
96-
heat = zero_flux,
97-
),
98-
)
92+
boundary_conditions =
93+
(; top = top_bc, bottom = Soil.EnergyWaterFreeDrainage())
9994
soil = soil_model_type(;
10095
boundary_conditions = boundary_conditions,
10196
sources = sources,

src/standalone/Soil/boundary_conditions.jl

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ using ClimaCore: Geometry
1010
export TemperatureStateBC,
1111
MoistureStateBC,
1212
FreeDrainage,
13+
EnergyWaterFreeDrainage,
1314
HeatFluxBC,
1415
WaterFluxBC,
1516
AtmosDrivenFluxBC,
@@ -48,9 +49,14 @@ end
4849

4950
"""
5051
FreeDrainage <: AbstractWaterBC
52+
5153
A concrete type of soil boundary condition, for use at
5254
the BottomBoundary only, where the flux is set to be
53-
`F = -K∇h = -K`.
55+
`F = -K∇h = -K`.
56+
57+
This is not tied to any boundary condition for the heat equation.
58+
To account for the energy flux resulting from free drainage of liquid
59+
water, please see `EnergyWaterFreeDrainage`.
5460
"""
5561
struct FreeDrainage <: AbstractWaterBC end
5662

@@ -569,6 +575,39 @@ function WaterHeatBC(; water, heat)
569575
return WaterHeatBC{typeof(water), typeof(heat)}(water, heat)
570576
end
571577

578+
"""
579+
EnergyWaterFreeDrainage <: AbstractEnergyHydrologyBC
580+
581+
A concrete type of soil boundary condition, for use at
582+
the BottomBoundary only, where the fluxes are set to be
583+
`F_liq = -K∇h = -K`, `F_energy = -K ρe_liq`.
584+
585+
That is, this enforces that the free drainage boundary condition
586+
for liquid water is paired the the corresponding loss of energy
587+
that that entails.
588+
"""
589+
struct EnergyWaterFreeDrainage <: AbstractEnergyHydrologyBC end
590+
591+
function soil_boundary_fluxes!(
592+
bc::EnergyWaterFreeDrainage,
593+
boundary::ClimaLand.BottomBoundary,
594+
soil::EnergyHydrology,
595+
Δz,
596+
Y,
597+
p,
598+
t,
599+
)
600+
FT = eltype(Δz)
601+
K_c = Fields.level(p.soil.K, 1)
602+
T_c = Fields.level(p.soil.T, 1)
603+
@. p.soil.bottom_bc.water = -1 * K_c
604+
@. p.soil.bottom_bc.heat =
605+
-1 *
606+
K_c *
607+
volumetric_internal_energy_liq(T_c, soil.parameters.earth_param_set)
608+
return nothing
609+
end
610+
572611
"""
573612
AtmosDrivenFluxBC{
574613
A <: AbstractAtmosphericDrivers,

test/standalone/Soil/soil_bc.jl

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,83 @@ for FT in (Float32, Float64)
192192

193193
@test abs(flux_expected - flux_int) < eps(FT)
194194
end
195+
196+
@testset "Test water+energy free drainage BC, FT = $FT" begin
197+
earth_param_set = LP.LandParameters(FT)
198+
ν = FT(0.495)
199+
K_sat = FT(0.0443 / 3600 / 100) # m/s
200+
S_s = FT(1e-3) #inverse meters
201+
vg_n = FT(2.0)
202+
vg_α = FT(2.6) # inverse meters
203+
hydrology_cm = vanGenuchten{FT}(; α = vg_α, n = vg_n)
204+
θ_r = FT(0.1)
205+
ν_ss_om = FT(0.0)
206+
ν_ss_quartz = FT(1.0)
207+
ν_ss_gravel = FT(0.0)
208+
209+
parameters = Soil.EnergyHydrologyParameters(
210+
FT;
211+
ν,
212+
ν_ss_om,
213+
ν_ss_quartz,
214+
ν_ss_gravel,
215+
hydrology_cm,
216+
K_sat,
217+
S_s,
218+
θ_r,
219+
)
220+
221+
zmax = FT(0)
222+
zmin = FT(-1)
223+
nelems = 20
224+
domain = Column(; zlim = (zmin, zmax), nelements = nelems)
225+
226+
zero_water_flux_bc = WaterFluxBC((p, t) -> 0.0)
227+
zero_heat_flux_bc = HeatFluxBC((p, t) -> 0.0)
228+
boundary_conditions = (;
229+
top = WaterHeatBC(;
230+
water = zero_water_flux_bc,
231+
heat = zero_heat_flux_bc,
232+
),
233+
bottom = EnergyWaterFreeDrainage(),
234+
)
235+
sources = ()
236+
soil = Soil.EnergyHydrology{FT}(;
237+
parameters,
238+
domain,
239+
boundary_conditions,
240+
sources,
241+
)
242+
243+
Y, p, coords = initialize(soil)
244+
Y.soil.ϑ_l .= ν / 2
245+
Y.soil.θ_i .= 0
246+
T = coords.subsurface.z .* 10 .+ FT(290.0)
247+
ρc_s =
248+
Soil.volumetric_heat_capacity.(
249+
Y.soil.ϑ_l,
250+
Y.soil.θ_i,
251+
parameters.ρc_ds,
252+
parameters.earth_param_set,
253+
)
254+
Y.soil.ρe_int .=
255+
Soil.volumetric_internal_energy.(
256+
Y.soil.θ_i,
257+
ρc_s,
258+
T,
259+
parameters.earth_param_set,
260+
)
261+
set_initial_cache! = ClimaLand.make_set_initial_cache(soil)
262+
set_initial_cache!(p, Y, 0.0)
263+
flux_expected_water = -1 .* ClimaCore.Fields.level(p.soil.K, 1)
264+
T1 = ClimaCore.Fields.level(p.soil.T, 1)
265+
flux_expected_energy =
266+
flux_expected_water .*
267+
Soil.volumetric_internal_energy_liq.(T1, parameters.earth_param_set)
268+
@test all(parent(p.soil.bottom_bc.heat) .≈ parent(flux_expected_energy))
269+
@test all(parent(p.soil.bottom_bc.water) .≈ parent(flux_expected_water))
270+
271+
end
195272
end
196273

197274

0 commit comments

Comments
 (0)