Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/models/coupled/land_model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ end
function compute_tendencies!(state, model::LandModel)
grid = get_grid(model)
compute_tendencies!(state, grid, model.surface_hydrology)
compute_tendencies!(state, grid, model.soil, model.constants)
# Pass the surface hydrology so that evapotranspiration is applied as a sink in the soil water tendency
compute_tendencies!(state, grid, model.soil, model.constants, model.surface_hydrology)
# Snow tendencies after surface hydrology; no-op without snow (`nothing`)
compute_tendencies!(state, grid, model.snow, model.constants, model.atmosphere)
compute_tendencies!(state, grid, model.vegetation, model.constants, model.atmosphere)
Expand Down
10 changes: 8 additions & 2 deletions src/processes/soil/soil_coupled.jl
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,20 @@ end

Compute tendencies for soil energy, water, and carbon state variables on `grid`
based on the given values in `constants`.

An optional `surface_hydrology` process may be supplied (by the coupled `LandModel`) so that its
evapotranspiration scheme (`get_evapotranspiration`) is applied as a sink term in the soil
water tendency. Without it (standalone soil), no evapotranspiration is removed from the soil.
"""
function compute_tendencies!(
state, grid,
soil::SoilEnergyWaterCarbon,
constants::PhysicalConstants
constants::PhysicalConstants,
surface_hydrology::Optional{AbstractSurfaceHydrology} = nothing
)
evapotranspiration = isnothing(surface_hydrology) ? nothing : get_evapotranspiration(surface_hydrology)
# TODO: consider implementing fused kernel here?
compute_tendencies!(state, grid, soil.hydrology, soil, constants)
compute_tendencies!(state, grid, soil.hydrology, soil, constants, evapotranspiration)
compute_tendencies!(state, grid, soil.biogeochem, soil, constants)
compute_tendencies!(state, grid, soil.energy, soil, constants)
return nothing
Expand Down
21 changes: 21 additions & 0 deletions test/coupled_models/land_model_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,27 @@ using Oceananigans.BoundaryConditions: BoundaryCondition, Flux
energy_top_bc = integrator.state.internal_energy.boundary_conditions.top
@test isa(energy_top_bc, BoundaryCondition{<:Flux})
@test energy_top_bc.condition == integrator.state.ground_heat_flux
# Check that ground evaporation is applied as a sink in the soil water tendency (issue #203).
# Compute the tendencies once with zero and once with nonzero ground evaporation; the difference
# in the top-layer saturation tendency must equal E / (Δz * porosity). The evaporation flux is set
# after the boundary conditions since the SEB solve recomputes it from the skin temperature.
state = integrator.state
function top_saturation_tendency(E)
Terrarium.reset_tendencies!(state)
compute_boundary_conditions!(state, land)
set!(state.evaporation_ground, E)
compute_tendencies!(state, land)
return Array(interior(state.tendencies.saturation_water_ice))[1, 1, end]
end
E = 2.0e-8 # m/s
dsat_no_ET = top_saturation_tendency(0.0)
dsat_ET = top_saturation_tendency(E)
Δz_top = Terrarium.Δzᵃᵃᶜ(1, 1, grid.Nz, grid)
strat = Terrarium.get_stratigraphy(soil)
bgc = Terrarium.get_biogeochemistry(soil)
por = Terrarium.porosity(1, 1, grid.Nz, grid, get_fields(state, strat, bgc), strat, bgc)
@test dsat_ET < dsat_no_ET
@test dsat_no_ET - dsat_ET ≈ E / (Δz_top * por)
# Advance one timestep
timestep!(integrator, 60.0)
@test all(isfinite.(integrator.state.saturation_water_ice))
Expand Down
Loading