From bc1834617f85cf19624ef79e1f55f7e15c62cf64 Mon Sep 17 00:00:00 2001 From: Brendan Date: Tue, 16 Jan 2024 11:46:35 +0100 Subject: [PATCH 1/6] Added total water storage --- src/sbm.jl | 35 +++++++++++++++++++++++++++++++++++ src/sbm_model.jl | 17 +++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/sbm.jl b/src/sbm.jl index a85254bf7..e9ae822e3 100644 --- a/src/sbm.jl +++ b/src/sbm.jl @@ -194,6 +194,8 @@ waterlevel_land::Vector{T} | "mm" # Water level river [mm] waterlevel_river::Vector{T} | "mm" + # Total water storage (excluding floodplain volume) [mm] + total_storage::Vector{T} | "mm" function SBM{T,N,M}(args...) where {T,N,M} equal_size_vectors(args) @@ -597,6 +599,7 @@ function initialize_sbm(nc, config, riverfrac, inds) leaf_area_index = fill(mv, n), waterlevel_land = fill(mv, n), waterlevel_river = zeros(Float, n), #set to zero to account for cells outside river domain + total_storage = zeros(Float, n) # Set the total water storage from initialized values ) return sbm @@ -1049,3 +1052,35 @@ function update_after_subsurfaceflow(sbm::SBM, zi, exfiltsatwater) sbm.zi[i] = zi[i] end end + +function update_total_water_storage(sbm::SBM, rnet, rrouting, lrouting) + + # Set the total storage to zero + fill!(sbm.total_storage, 0) + + # Burn the river routing values + sbm.total_storage[rnet] = ( + rrouting.h_av .* sbm.riverfrac[rnet] * 0.001 # convert to mm + ) + + # Chunk the data for parallel computing + threaded_foreach(1:sbm.n, basesize=1000) do i + + # Cumulate per vertical type + # Maybe re-categorize in the future + # Unique are those that are not always present + unique = sbm.glacierstore[i] * sbm.glacierfrac[i] + surface = ( + sbm.snow[i] + sbm.snowwater[i] + sbm.canopystorage[i] + ) + sub_surfuce = sbm.ustoredepth[i] + sbm.satwaterdepth[i] + lateral = ( + lrouting.h_av[i] * (1 - sbm.riverfrac[i]) * 0.001 # convert to mm + ) + + # Add everything to the total water storage + sbm.total_storage[i] += ( + unique + surface + sub_surfuce + lateral + ) + end +end diff --git a/src/sbm_model.jl b/src/sbm_model.jl index 907bbd9bc..ecc07ca3a 100644 --- a/src/sbm_model.jl +++ b/src/sbm_model.jl @@ -376,6 +376,7 @@ function update(model::Model{N,L,V,R,W,T}) where {N,L,V,R,W,T<:SbmModel} # update lateral subsurface flow domain (kinematic wave) update(lateral.subsurface, network.land, network.frac_toriver) model = update_after_subsurfaceflow(model) + model = update_total_water_storage(model) end """ @@ -438,6 +439,22 @@ function update_after_subsurfaceflow( return model end +function update_total_water_storage( + model::Model{N,L,V,R,W,T}, +) where {N,L,V,R,W,T<:SbmModel} + @unpack lateral, vertical, network, clock, config = model + + # Update the total water storage based on vertical states + # TODO Maybe look at routing in the near future + update_total_water_storage( + vertical, + network.index_river, + lateral.river, + lateral.land, + ) + return model +end + function set_states(model::Model{N,L,V,R,W,T}) where {N,L,V,R,W,T<:SbmModel} @unpack lateral, vertical, network, config = model From a6246c164063cfb33ff9c1b28ee97cb360280b15 Mon Sep 17 00:00:00 2001 From: Brendan Date: Tue, 16 Jan 2024 11:55:14 +0100 Subject: [PATCH 2/6] Added storage to doc variables --- docs/src/model_docs/params_vertical.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/model_docs/params_vertical.md b/docs/src/model_docs/params_vertical.md index de39ff770..f0ecd5253 100644 --- a/docs/src/model_docs/params_vertical.md +++ b/docs/src/model_docs/params_vertical.md @@ -116,6 +116,7 @@ specific_leaf = "Sl" | **`leaf_area_index`** | leaf area index | m``^2`` m``{-2}`` | - | | `waterlevel_land` | water level land | mm | - | | `waterlevel_river` | water level river | mm | - | +| `total_storage` | total water storage (excluding floodplains) | mm | - | ## [HBV](@id params_hbv) From 2b6053c37343443c29bfa5958e5ad2c9f47c687a Mon Sep 17 00:00:00 2001 From: Brendan Date: Wed, 17 Jan 2024 11:02:58 +0100 Subject: [PATCH 3/6] Updated bmi test; added check for tws value --- test/bmi.jl | 6 +++--- test/run_sbm.jl | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/bmi.jl b/test/bmi.jl index bb89cdf57..979ff6284 100644 --- a/test/bmi.jl +++ b/test/bmi.jl @@ -20,9 +20,9 @@ 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) == 183 - @test BMI.get_output_item_count(model) == 183 - @test BMI.get_input_var_names(model)[[1, 5, 150, 174]] == [ + @test BMI.get_input_item_count(model) == 184 + @test BMI.get_output_item_count(model) == 184 + @test BMI.get_input_var_names(model)[[1, 5, 151, 175]] == [ "vertical.nlayers", "vertical.θᵣ", "lateral.river.sl", diff --git a/test/run_sbm.jl b/test/run_sbm.jl index f55cb7d32..a67cdf286 100644 --- a/test/run_sbm.jl +++ b/test/run_sbm.jl @@ -80,6 +80,8 @@ end @test sbm.runoff[50063] == 0.0 @test sbm.soilevap[50063] == 0.0 @test sbm.snow[5] ≈ 3.592840840467347f0 + @test sbm.total_storage[50063] ≈ 559.70849973344f0 + @test sbm.total_storage[429] ≈ 583.9800667536956f0 # river cell end # run the second timestep @@ -92,6 +94,8 @@ model = Wflow.run_timestep(model) @test sbm.runoff[50063] == 0.0 @test sbm.soilevap[50063] ≈ 0.006358004660566856f0 @test sbm.snow[5] ≈ 3.667748983774868f0 + @test sbm.total_storage[50063] ≈ 559.7935411649405f0 + @test sbm.total_storage[429] ≈ 589.7026699582976f0 # river cell end @testset "subsurface flow" begin From 8b0b95942617794b19d20e9a5aceddf0ce28fc4c Mon Sep 17 00:00:00 2001 From: Brendan Date: Wed, 24 Jan 2024 11:43:15 +0100 Subject: [PATCH 4/6] Update with github comments (24-01) --- docs/src/model_docs/params_vertical.md | 2 +- src/sbm.jl | 46 +++++++++++++++++++++----- src/sbm_model.jl | 7 ++++ test/run_sbm.jl | 4 +-- 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/docs/src/model_docs/params_vertical.md b/docs/src/model_docs/params_vertical.md index f0ecd5253..03a7817c0 100644 --- a/docs/src/model_docs/params_vertical.md +++ b/docs/src/model_docs/params_vertical.md @@ -116,7 +116,7 @@ specific_leaf = "Sl" | **`leaf_area_index`** | leaf area index | m``^2`` m``{-2}`` | - | | `waterlevel_land` | water level land | mm | - | | `waterlevel_river` | water level river | mm | - | -| `total_storage` | total water storage (excluding floodplains) | mm | - | +| `total_storage` | total water storage (excluding floodplains, lakes and reservoirs) | mm | - | ## [HBV](@id params_hbv) diff --git a/src/sbm.jl b/src/sbm.jl index 954b0ab51..33dafad26 100644 --- a/src/sbm.jl +++ b/src/sbm.jl @@ -194,7 +194,7 @@ waterlevel_land::Vector{T} | "mm" # Water level river [mm] waterlevel_river::Vector{T} | "mm" - # Total water storage (excluding floodplain volume) [mm] + # Total water storage (excluding floodplain volume, lakes and reservoirs) [mm] total_storage::Vector{T} | "mm" function SBM{T,N,M}(args...) where {T,N,M} @@ -1053,14 +1053,43 @@ function update_after_subsurfaceflow(sbm::SBM, zi, exfiltsatwater) end end -function update_total_water_storage(sbm::SBM, rnet, rrouting, lrouting) +@doc """ +Update the total water storage per cell at the end of a timestep. + +Takes the following parameters: +- sbm: + The vertical concept (SBM struct) +- river_network: + The indices of the river cells in relation to the active cells, i.e. model.network.index_river +- cell_xsize: + Size in X direction of the cells acquired from model.network.land.xl +- cell_ysize: + Size in Y direction of the cells acquired from model.network.land.yl +- river_routing: + The river routing struct, i.e. model.lateral.river +- land_routing: + The land routing struct, i.e. model.lateral.land +""" +function update_total_water_storage( + sbm::SBM, + river_network, + cell_xsize, + cell_ysize, + river_routing, + land_routing +) + # Get length active river cells + nriv = length(river_network) # Set the total storage to zero fill!(sbm.total_storage, 0) # Burn the river routing values - sbm.total_storage[rnet] = ( - rrouting.h_av .* sbm.riverfrac[rnet] * 0.001 # convert to mm + sbm.total_storage[river_network] = ( + ( river_routing.h_av[1:nriv] .* river_routing.width[1:nriv] .* + river_routing.dl[1:nriv] ) ./ + ( cell_xsize[river_network] .* cell_ysize[river_network] ) * + 1000 # Convert to mm ) # Chunk the data for parallel computing @@ -1068,19 +1097,18 @@ function update_total_water_storage(sbm::SBM, rnet, rrouting, lrouting) # Cumulate per vertical type # Maybe re-categorize in the future - # Unique are those that are not always present - unique = sbm.glacierstore[i] * sbm.glacierfrac[i] surface = ( + sbm.glacierstore[i] * sbm.glacierfrac[i] + sbm.snow[i] + sbm.snowwater[i] + sbm.canopystorage[i] ) - sub_surfuce = sbm.ustoredepth[i] + sbm.satwaterdepth[i] + sub_surface = sbm.ustoredepth[i] + sbm.satwaterdepth[i] lateral = ( - lrouting.h_av[i] * (1 - sbm.riverfrac[i]) * 0.001 # convert to mm + land_routing.h_av[i] * (1 - sbm.riverfrac[i]) * 1000 # convert to mm ) # Add everything to the total water storage sbm.total_storage[i] += ( - unique + surface + sub_surfuce + lateral + surface + sub_surface + lateral ) end end diff --git a/src/sbm_model.jl b/src/sbm_model.jl index ecc07ca3a..4d7bab950 100644 --- a/src/sbm_model.jl +++ b/src/sbm_model.jl @@ -439,6 +439,11 @@ function update_after_subsurfaceflow( return model end +@doc """ +Update of the total water storage at the end of each timestep per model cell. + +This is done here at model level. +""" function update_total_water_storage( model::Model{N,L,V,R,W,T}, ) where {N,L,V,R,W,T<:SbmModel} @@ -449,6 +454,8 @@ function update_total_water_storage( update_total_water_storage( vertical, network.index_river, + network.land.xl, + network.land.yl, lateral.river, lateral.land, ) diff --git a/test/run_sbm.jl b/test/run_sbm.jl index a67cdf286..f9a9c2976 100644 --- a/test/run_sbm.jl +++ b/test/run_sbm.jl @@ -81,7 +81,7 @@ end @test sbm.soilevap[50063] == 0.0 @test sbm.snow[5] ≈ 3.592840840467347f0 @test sbm.total_storage[50063] ≈ 559.70849973344f0 - @test sbm.total_storage[429] ≈ 583.9800667536956f0 # river cell + @test sbm.total_storage[429] ≈ 597.4578475404879f0 # river cell end # run the second timestep @@ -95,7 +95,7 @@ model = Wflow.run_timestep(model) @test sbm.soilevap[50063] ≈ 0.006358004660566856f0 @test sbm.snow[5] ≈ 3.667748983774868f0 @test sbm.total_storage[50063] ≈ 559.7935411649405f0 - @test sbm.total_storage[429] ≈ 589.7026699582976f0 # river cell + @test sbm.total_storage[429] ≈ 617.0062092646873f0 # river cell end @testset "subsurface flow" begin From a0aec189d8cb9f890bc7e579dbdcc7a7a301410b Mon Sep 17 00:00:00 2001 From: Brendan Date: Wed, 24 Jan 2024 11:47:58 +0100 Subject: [PATCH 5/6] Updated changelog --- docs/src/changelog.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/src/changelog.md b/docs/src/changelog.md index 4a2391ed1..c2bbf7a49 100644 --- a/docs/src/changelog.md +++ b/docs/src/changelog.md @@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixed + +### Changed + +### Added +- Total water storage as an export variable for `SBM` concept. This is the total water stored + per grid cell in millimeters. Excluded from this variable are the floodplain, lakes and + reservoirs. + ## v0.7.3 - 2024-01-12 ### Fixed From 893dbf5110eb6c7374ba34a01388bdf58d445a79 Mon Sep 17 00:00:00 2001 From: Brendan Date: Thu, 25 Jan 2024 10:46:37 +0100 Subject: [PATCH 6/6] Deleted '@doc' --- src/sbm.jl | 2 +- src/sbm_model.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sbm.jl b/src/sbm.jl index 33dafad26..9cc336074 100644 --- a/src/sbm.jl +++ b/src/sbm.jl @@ -1053,7 +1053,7 @@ function update_after_subsurfaceflow(sbm::SBM, zi, exfiltsatwater) end end -@doc """ +""" Update the total water storage per cell at the end of a timestep. Takes the following parameters: diff --git a/src/sbm_model.jl b/src/sbm_model.jl index 4d7bab950..6ef34b51f 100644 --- a/src/sbm_model.jl +++ b/src/sbm_model.jl @@ -439,7 +439,7 @@ function update_after_subsurfaceflow( return model end -@doc """ +""" Update of the total water storage at the end of each timestep per model cell. This is done here at model level.