From 2e049c5dfb5fc97b7b055fdd718692eb11e41524 Mon Sep 17 00:00:00 2001 From: Willem van Verseveld Date: Mon, 18 Mar 2024 16:26:00 +0100 Subject: [PATCH 1/8] Remove lower limit of zero for `sbm.runoff` Setting a lower limit of zero for `sbm.runoff` originates from the wflow_sbm Python implementation, when surface runoff was computed with one kinematic wave, to avoid a very slow kinematic wave solution. In the Python code the kinematic wave was split into a river and land component. While for river runoff the lower limit was removed, this was not done for land runoff yet. --- src/sbm.jl | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sbm.jl b/src/sbm.jl index adc103df4..2a3cf7870 100644 --- a/src/sbm.jl +++ b/src/sbm.jl @@ -136,7 +136,7 @@ excesswatersoil::Vector{T} # Excess water for compacted fraction [mm Δt⁻¹] excesswaterpath::Vector{T} - # Total surface runoff from infiltration and saturation excess [mm Δt⁻¹] + # Total surface runoff from infiltration, saturation excess and actual open water evaporation [mm Δt⁻¹] runoff::Vector{T} # Volumetric water content [-] per soil layer (including θᵣ and saturated zone) vwc::Vector{SVector{N,T}} | "-" @@ -1071,14 +1071,12 @@ function update_after_subsurfaceflow(sbm::SBM, zi, exfiltsatwater) ustoredepth = sum(@view usld[1:n_usl]) - runoff = max( + runoff = exfiltustore + exfiltsatwater[i] + sbm.excesswater[i] + sbm.runoff_land[i] + - sbm.infiltexcess[i] - sbm.ae_openw_l[i], - 0.0, - ) + sbm.infiltexcess[i] - sbm.ae_openw_l[i] # volumetric water content per soil layer and root zone vwc = sbm.vwc[i] From ca98831839b5b3e277b8507ad3daf9ad5e32f150 Mon Sep 17 00:00:00 2001 From: Willem van Verseveld Date: Mon, 18 Mar 2024 16:38:21 +0100 Subject: [PATCH 2/8] Change description `runoff` --- docs/src/model_docs/params_vertical.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/model_docs/params_vertical.md b/docs/src/model_docs/params_vertical.md index fde92c15b..bd44de2e8 100644 --- a/docs/src/model_docs/params_vertical.md +++ b/docs/src/model_docs/params_vertical.md @@ -115,7 +115,7 @@ profile `kv` is used and `z_layered` is required as input. | `exfiltustore` | water exfiltrating from unsaturated store because of change in water table | mm Δt``^{-1}`` | - | | `excesswatersoil` | excess water for non-compacted fraction | mm Δt``^{-1}`` | - | | `excesswaterpath` | excess water for compacted fraction | mm Δt``^{-1}`` | - | -| `runoff` | total surface runoff from infiltration and saturation excess | mm Δt``^{-1}`` | - | +| `runoff` | total surface runoff from infiltration, saturation excess and actual evaporation (`ae_openw_l`) | mm Δt``^{-1}`` | - | | `vwc` | volumetric water content per soil layer (including θᵣ and saturated zone) | - | - | | `vwc_perc` | volumetric water content per soil layer (including θᵣ and saturated zone) | % | - | | `rootstore` | root water storage in unsaturated and saturated zone (excluding θᵣ) | mm| - | From 80a8fef33196411d9bac97f710b3057d5f127121 Mon Sep 17 00:00:00 2001 From: Willem van Verseveld Date: Tue, 19 Mar 2024 10:38:39 +0100 Subject: [PATCH 3/8] Extend `sbm` tests Compute mean values of variables runoff, soilevap and snow, and add variables actevap and actinfilt. --- test/run_sbm.jl | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/test/run_sbm.jl b/test/run_sbm.jl index 7e2194976..8cab8eff6 100644 --- a/test/run_sbm.jl +++ b/test/run_sbm.jl @@ -77,9 +77,12 @@ end @test sbm.θₛ[50063] ≈ 0.48755401372909546f0 @test sbm.θᵣ[50063] ≈ 0.15943120419979095f0 - @test sbm.runoff[50063] == 0.0 - @test sbm.soilevap[50063] == 0.0 + @test mean(sbm.runoff) ≈ 0.0416027711985709f0 + @test mean(sbm.soilevap) ≈ 0.00616346765710303f0 + @test mean(sbm.actevap) ≈ 0.5393128846181061f0 + @test mean(sbm.actinfilt) ≈ 1.4860556930083888f0 @test sbm.snow[5] ≈ 3.592840840467347f0 + @test mean(sbm.snow) ≈ 0.035197394854698104f0 @test sbm.total_storage[50063] ≈ 559.70849973344f0 @test sbm.total_storage[429] ≈ 597.4578475404879f0 # river cell end @@ -91,9 +94,12 @@ model = Wflow.run_timestep(model) sbm = model.vertical @test sbm.θₛ[50063] ≈ 0.48755401372909546f0 @test sbm.θᵣ[50063] ≈ 0.15943120419979095f0 - @test sbm.runoff[50063] == 0.0 - @test sbm.soilevap[50063] ≈ 0.006358004660566856f0 + @test mean(sbm.runoff) ≈ 0.23657364759232993f0 + @test mean(sbm.soilevap) ≈ 0.015275916086112940 + @test mean(sbm.actevap) ≈ 0.29716147685525746f0 + @test mean(sbm.actinfilt) ≈ 0.08829600284076534f0 @test sbm.snow[5] ≈ 3.667748983774868f0 + @test mean(sbm.snow) ≈ 0.03209680141455693f0 @test sbm.total_storage[50063] ≈ 559.7935411649405f0 @test sbm.total_storage[429] ≈ 617.0062092646873f0 # river cell end From 2c68dee8024c467a9a414caa31bfe4bc64561778 Mon Sep 17 00:00:00 2001 From: Willem van Verseveld Date: Tue, 19 Mar 2024 11:28:47 +0100 Subject: [PATCH 4/8] Update changelog --- docs/src/changelog.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/src/changelog.md b/docs/src/changelog.md index cd78cf337..2b764045e 100644 --- a/docs/src/changelog.md +++ b/docs/src/changelog.md @@ -28,6 +28,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 model parameters are defined, and it is not expected that exposing these variables is required (e.g. for model coupling) while code changes for these variables (including struct fields) are required. +- Remove lower limit of zero for computation of `runoff` variable of `SBM` vertical concept + as it may result in water balance errors. As part of the `runoff` computation, actual open + water evaporation `ae_openw_l` is subtracted, which may result in negative `runoff` + values. This lower limit was implemented in the Python version of wflow\_sbm, to avoid a + very slow kinematic wave solution for surface flow computation (no distinction between a + kinematic wave for overland and river flow). When in the Python version of wflow_sbm the + kinematic wave for surface flow was split into a river and land component, the lower limit + was removed for river runoff, but not for land runoff. ### Added - Total water storage as an export variable for `SBM` concept. This is the total water stored From 95e4e78f821612a06c69055f74300cc6d9042648 Mon Sep 17 00:00:00 2001 From: Willem van Verseveld Date: Thu, 4 Apr 2024 16:42:30 +0200 Subject: [PATCH 5/8] Add `net_runoff` variable to `SBM` --- src/flow.jl | 18 +++++++++++++++--- src/sbm.jl | 8 ++++++-- test/bmi.jl | 4 ++-- test/run_sbm.jl | 3 ++- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/flow.jl b/src/flow.jl index c10087a93..d81873196 100644 --- a/src/flow.jl +++ b/src/flow.jl @@ -1644,7 +1644,7 @@ end """ set_land_inwater(model::Model{N,L,V,R,W,T}) where {N,L,V,R,W,T<:SbmGwfModel} -Set `inwater` of the lateral land component for the `SbmGwgModel` type. +Set `inwater` of the lateral land component for the `SbmGwfModel` type. """ function set_land_inwater(model::Model{N,L,V,R,W,T}) where {N,L,V,R,W,T<:SbmGwfModel} @unpack lateral, vertical, network, config = model @@ -1657,10 +1657,22 @@ function set_land_inwater(model::Model{N,L,V,R,W,T}) where {N,L,V,R,W,T<:SbmGwfM end lateral.land.inwater .= - (vertical.runoff .* network.land.xl .* network.land.yl .* 0.001) ./ + (vertical.net_runoff .* network.land.xl .* network.land.yl .* 0.001) ./ lateral.land.Δt .+ drainflux end +""" + set_land_inwater(model::Model{N,L,V,R,W,T}) where {N,L,V,R,W,T<:SbmModel} + +Set `inwater` of the lateral land component for the `SbmModel` type. +""" +function set_land_inwater(model::Model{N,L,V,R,W,T}) where {N,L,V,R,W,T<:SbmModel} + @unpack lateral, vertical, network = model + lateral.land.inwater .= + (vertical.net_runoff .* network.land.xl .* network.land.yl .* 0.001) ./ + lateral.land.Δt +end + """ set_land_inwater(model) @@ -1794,7 +1806,7 @@ function surface_routing( @unpack lateral, vertical, network, clock = model @. lateral.land.runoff = ( - (vertical.runoff / 1000.0) * (network.land.xl * network.land.yl) / vertical.Δt + + (vertical.net_runoff / 1000.0) * (network.land.xl * network.land.yl) / vertical.Δt + ssf_toriver + # net_runoff_river ( diff --git a/src/sbm.jl b/src/sbm.jl index 5ee50d2dd..ebfe607ba 100644 --- a/src/sbm.jl +++ b/src/sbm.jl @@ -136,8 +136,10 @@ excesswatersoil::Vector{T} # Excess water for compacted fraction [mm Δt⁻¹] excesswaterpath::Vector{T} - # Total surface runoff from infiltration, saturation excess and actual open water evaporation [mm Δt⁻¹] + # Total surface runoff from infiltration and saturation excess and actual open water evaporation [mm Δt⁻¹] runoff::Vector{T} + # Net surface runoff (surface runoff - actual open water evaporation) [mm Δt⁻¹] + net_runoff::Vector{T} # Volumetric water content [-] per soil layer (including θᵣ and saturated zone) vwc::Vector{SVector{N,T}} | "-" # Volumetric water content [%] per soil layer (including θᵣ and saturated zone) @@ -632,6 +634,7 @@ function initialize_sbm(nc, config, riverfrac, inds) excesswatersoil = fill(mv, n), excesswaterpath = fill(mv, n), runoff = fill(mv, n), + net_runoff = fill(mv, n), net_runoff_river = fill(mv, n), vwc = svectorscopy(vwc, Val{maxlayers}()), vwc_perc = svectorscopy(vwc_perc, Val{maxlayers}()), @@ -1076,7 +1079,7 @@ function update_after_subsurfaceflow(sbm::SBM, zi, exfiltsatwater) exfiltsatwater[i] + sbm.excesswater[i] + sbm.runoff_land[i] + - sbm.infiltexcess[i] - sbm.ae_openw_l[i] + sbm.infiltexcess[i] # volumetric water content per soil layer and root zone vwc = sbm.vwc[i] @@ -1117,6 +1120,7 @@ function update_after_subsurfaceflow(sbm::SBM, zi, exfiltsatwater) sbm.exfiltsatwater[i] = exfiltsatwater[i] sbm.exfiltustore[i] = exfiltustore sbm.runoff[i] = runoff + sbm.net_runoff[i] = runoff - sbm.ae_openw_l[i] sbm.vwc[i] = vwc sbm.vwc_perc[i] = vwc_perc sbm.rootstore[i] = rootstore diff --git a/test/bmi.jl b/test/bmi.jl index b5e46fb1e..66a97ad46 100644 --- a/test/bmi.jl +++ b/test/bmi.jl @@ -20,8 +20,8 @@ tomlpath = joinpath(@__DIR__, "sbm_config.toml") @testset "model information functions" begin @test BMI.get_component_name(model) == "sbm" - @test BMI.get_input_item_count(model) == 192 - @test BMI.get_output_item_count(model) == 192 + @test BMI.get_input_item_count(model) == 193 + @test BMI.get_output_item_count(model) == 193 to_check = [ "vertical.nlayers", "vertical.θᵣ", diff --git a/test/run_sbm.jl b/test/run_sbm.jl index 96d9f8619..148e524b6 100644 --- a/test/run_sbm.jl +++ b/test/run_sbm.jl @@ -94,7 +94,8 @@ model = Wflow.run_timestep(model) sbm = model.vertical @test sbm.θₛ[50063] ≈ 0.48755401372909546f0 @test sbm.θᵣ[50063] ≈ 0.15943120419979095f0 - @test mean(sbm.runoff) ≈ 0.23657364759232993f0 + @test mean(sbm.net_runoff) ≈ 0.23657364759232993f0 + @test mean(sbm.runoff) ≈ 0.2369017651524159f0 @test mean(sbm.soilevap) ≈ 0.015275916086112940 @test mean(sbm.actevap) ≈ 0.29716147685525746f0 @test mean(sbm.actinfilt) ≈ 0.08829600284076534f0 From b753e08e1b703777a18d7d3207de8abd47d9c6a2 Mon Sep 17 00:00:00 2001 From: Willem van Verseveld Date: Thu, 4 Apr 2024 16:54:10 +0200 Subject: [PATCH 6/8] Fix `WflowServer` tests --- server/test/client.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/test/client.jl b/server/test/client.jl index 5f0f31d2e..45051e81f 100644 --- a/server/test/client.jl +++ b/server/test/client.jl @@ -33,8 +33,8 @@ end @testset "model information functions" begin @test request((fn = "get_component_name",)) == Dict("component_name" => "sbm") - @test request((fn = "get_input_item_count",)) == Dict("input_item_count" => 192) - @test request((fn = "get_output_item_count",)) == Dict("output_item_count" => 192) + @test request((fn = "get_input_item_count",)) == Dict("input_item_count" => 193) + @test request((fn = "get_output_item_count",)) == Dict("output_item_count" => 193) to_check = [ "vertical.nlayers", "vertical.θᵣ", From 0bf3bdc4f55c1294d6037bd368ea0a14bde0edf1 Mon Sep 17 00:00:00 2001 From: Willem van Verseveld Date: Thu, 4 Apr 2024 22:26:37 +0200 Subject: [PATCH 7/8] Update docs and changelog --- docs/src/changelog.md | 23 +++++++++++++---------- docs/src/model_docs/params_vertical.md | 3 ++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/src/changelog.md b/docs/src/changelog.md index 170504a92..65f774665 100644 --- a/docs/src/changelog.md +++ b/docs/src/changelog.md @@ -24,8 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Close netCDF `NCDataset` with state variables in extended BMI function `save_state`. ### Changed -- Stop exposing scalar variables through BMI. The `BMI.get_value_ptr` function was - not working correctly for scalar model variables (a `view` was applied). Only a few scalar +- Stop exposing scalar variables through BMI. The `BMI.get_value_ptr` function was not + working correctly for scalar model variables (a `view` was applied). Only a few scalar model parameters are defined, and it is not expected that exposing these variables is required (e.g. for model coupling) while code changes for these variables (including struct fields) are required. @@ -35,14 +35,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 length `dl` at a ghost node should be set through the model parameter netCDF file (`riverlength_bc`), providing this boundary condition through the `[model]` settings in the TOML file (`model.riverlength_bc`) has been deprecated. -- Remove lower limit of zero for computation of `runoff` variable of `SBM` vertical concept - as it may result in water balance errors. As part of the `runoff` computation, actual open - water evaporation `ae_openw_l` is subtracted, which may result in negative `runoff` - values. This lower limit was implemented in the Python version of wflow\_sbm, to avoid a - very slow kinematic wave solution for surface flow computation (no distinction between a - kinematic wave for overland and river flow). When in the Python version of wflow_sbm the - kinematic wave for surface flow was split into a river and land component, the lower limit - was removed for river runoff, but not for land runoff. +- As part of the vertical `SBM` concept: 1) add variable `net_runoff` (land runoff minus + actual open water evaporation `ae_openw_l`) and 2) change the definition of variable + `runoff` by removing the subtraction of `ae_openw_l` (total land runoff). The variable + `net_runoff` is now input to the kinematic wave for overland flow (replaces the original + `runoff` variable as input). The lower limit of the original `runoff` variable was set at + zero, which may result in water balance errors. This lower limit was implemented in the + Python version of wflow\_sbm, to avoid a very slow kinematic wave solution for surface + flow computation (no distinction between a kinematic wave for overland and river flow). + When in the Python version of wflow\_sbm the kinematic wave for surface flow was split + into a river and land component, the lower limit was removed for river runoff + (`net_runoff_river`), but not for land runoff. ### Added - Total water storage as an export variable for `SBM` concept. This is the total water stored diff --git a/docs/src/model_docs/params_vertical.md b/docs/src/model_docs/params_vertical.md index bd44de2e8..214fe3c17 100644 --- a/docs/src/model_docs/params_vertical.md +++ b/docs/src/model_docs/params_vertical.md @@ -115,7 +115,8 @@ profile `kv` is used and `z_layered` is required as input. | `exfiltustore` | water exfiltrating from unsaturated store because of change in water table | mm Δt``^{-1}`` | - | | `excesswatersoil` | excess water for non-compacted fraction | mm Δt``^{-1}`` | - | | `excesswaterpath` | excess water for compacted fraction | mm Δt``^{-1}`` | - | -| `runoff` | total surface runoff from infiltration, saturation excess and actual evaporation (`ae_openw_l`) | mm Δt``^{-1}`` | - | +| `runoff` | total surface runoff from infiltration and saturation excess | mm Δt``^{-1}`` | - | +| `net_runoff` | net surface runoff (`runoff` - `ae_openw_l`) | mm Δt``^{-1}`` | - | | `vwc` | volumetric water content per soil layer (including θᵣ and saturated zone) | - | - | | `vwc_perc` | volumetric water content per soil layer (including θᵣ and saturated zone) | % | - | | `rootstore` | root water storage in unsaturated and saturated zone (excluding θᵣ) | mm| - | From 12f20bcea09cfed031cc40ed230e9a27f11f4da9 Mon Sep 17 00:00:00 2001 From: Willem van Verseveld Date: Mon, 8 Apr 2024 11:50:57 +0200 Subject: [PATCH 8/8] Update description `runoff` variable `SBM` struct Co-authored-by: JoostBuitink <44062204+JoostBuitink@users.noreply.github.com> --- src/sbm.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sbm.jl b/src/sbm.jl index ebfe607ba..ba508ddb5 100644 --- a/src/sbm.jl +++ b/src/sbm.jl @@ -136,7 +136,7 @@ excesswatersoil::Vector{T} # Excess water for compacted fraction [mm Δt⁻¹] excesswaterpath::Vector{T} - # Total surface runoff from infiltration and saturation excess and actual open water evaporation [mm Δt⁻¹] + # Total surface runoff from infiltration and saturation excess (excluding actual open water evaporation) [mm Δt⁻¹] runoff::Vector{T} # Net surface runoff (surface runoff - actual open water evaporation) [mm Δt⁻¹] net_runoff::Vector{T}