Skip to content

Commit

Permalink
Update check of state variables
Browse files Browse the repository at this point in the history
Checking list of standard names (`input.state.variables`).
  • Loading branch information
vers-w committed Dec 18, 2024
1 parent 8b38fb2 commit 3d50d76
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 140 deletions.
4 changes: 1 addition & 3 deletions src/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -979,9 +979,7 @@ function prepare_writer(
# create a separate state output netCDF that will hold the last timestep of all states
# but only if config.state.path_output has been set
if haskey(config, "state") && haskey(config.state, "path_output")
# TODO: revert back to state checking
# state_ncnames = check_states(config)
state_ncnames = ncnames(config.state.variables)
state_ncnames = check_states(config)
state_map = out_map(state_ncnames, modelmap)
nc_state_path = output_path(config, config.state.path_output)
@info "Create a state output netCDF file `$nc_state_path`."
Expand Down
2 changes: 2 additions & 0 deletions src/standard_name.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const sbm_standard_name_map = Dict{String, ComposedFunction}(
"river_water__volume" => @optic(_.lateral.river.variables.volume),
"floodplain_water__volume" => @optic(_.lateral.river.floodplain.variables.volume),
"floodplain_water__depth" => @optic(_.lateral.river.floodplain.variables.h),
"floodplain_water__volume_flow_rate" =>
@optic(_.lateral.river.floodplain.variables.q),
"reservoir_water__volume" =>
@optic(_.lateral.river.boundary_conditions.reservoir.variables.volume),
"soil_water_sat-zone_top__recharge_volume_flux" =>
Expand Down
207 changes: 74 additions & 133 deletions src/states.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
get_snow_states(model_type::AbstractString)
Extract required snow model states, given a certain `model_type`. Returns a tuple with the
required states (internal names as symbols).
required states (standard name).
"""
function get_snow_states(model_type::AbstractString)
if model_type == "sbm" || model_type == "sbm_gwf"
states = (:snow_storage, :snow_water)
states = ("snowpack~dry__leq-depth", "snowpack~liquid__depth")
elseif model_type == "sediment"
states = ()
else
Expand All @@ -19,11 +19,11 @@ end
get_glacier_states(model_type::AbstractString)
Extract required glacier model states, given a certain `model_type`. Returns a tuple with
the required states (internal names as symbols).
the required states (standard name).
"""
function get_glacier_states(model_type::AbstractString)
if model_type == "sbm" || model_type == "sbm_gwf"
states = (:glacier_store,)
states = ("glacier_ice__leq-volume",)
elseif model_type == "sediment"
states = ()
else
Expand All @@ -36,11 +36,11 @@ end
get_interception_states(model_type::AbstractString)
Extract required interception model states, given a certain `model_type`. Returns a tuple
with the required states (internal names as symbols).
with the required states (standard name).
"""
function get_interception_states(model_type::AbstractString)
if model_type == "sbm" || model_type == "sbm_gwf"
states = (:canopy_storage,)
states = ("vegetation_canopy_water__storage",)
elseif model_type == "sediment"
states = ()
else
Expand All @@ -58,9 +58,16 @@ modelled. Returns a tuple with the required states (internal names as symbols).
function get_soil_states(model_type::AbstractString; snow = false)
if model_type == "sbm" || model_type == "sbm_gwf"
if snow
states = (:satwaterdepth, :tsoil, :ustorelayerdepth)
states = (
"soil_water_sat-zone__depth",
"soil_surface__temperature",
"soil_water_unsat-zone__depth-per-soil_layer",
)
else
states = (:satwaterdepth, :ustorelayerdepth)
states = (
"soil_water_sat-zone__depth",
"soil_water_unsat-zone__depth-per-soil_layer",
)
end
elseif model_type == "sediment"
states = ()
Expand All @@ -72,51 +79,28 @@ end

function get_sediment_states()
states = (
:leftover_clay,
:leftover_silt,
:leftover_sand,
:leftover_sagg,
:leftover_lagg,
:leftover_gravel,
:store_clay,
:store_silt,
:store_sand,
:store_sagg,
:store_lagg,
:store_gravel,
:clay,
:silt,
:sand,
:sagg,
:lagg,
:gravel,
"river_water_clay__mass",
"river_bed_clay__mass",
"river_water_gravel__mass",
"river_bed_gravel__mass",
"river_water_aggregates~large__mass",
"river_bed_aggregates~large__mass",
"river_water_clay__mass_flow_rate",
"river_water_gravel__mass_flow_rate",
"river_water_aggregates~large__mass_flow_rate",
"river_water_aggregates~small__mass_flow_rate",
"river_water_sand__mass_flow_rate",
"river_water_silt__mass_flow_rate",
"river_water_aggregates~small__mass",
"river_bed_aggregates~small__mass",
"river_water_sand__mass",
"river_bed_sand__mass",
"river_water_silt__mass",
"river_bed_silt__mass",
)
return states
end

"""
add_to_required_states(required_states::Tuple, key_entry::Tuple, states::Tuple)
add_to_required_states(required_states::Tuple, key_entry::Tuple, states::Nothing)
Function to iterate through the list of `states` and add these to the `required_states`
variable. This is a tuple of tuples, that contains the correct "prefix" to the state
category (provided by the `key_entry` variable). This is added in front of each element in
the list of `states`, and the `required_states` tuple is returned.
When `nothing` is passed as the `states`, the `required_states` variable is simply returned.
"""
function add_to_required_states(required_states::Tuple, key_entry::Tuple, states::Tuple)
for state in states
required_states = (required_states..., (key_entry..., state))
end

return required_states
end

function add_to_required_states(required_states::Tuple, key_entry::Tuple, states::Nothing)
return required_states
end

"""
extract_required_states(config::Config)
Expand Down Expand Up @@ -156,12 +140,12 @@ function extract_required_states(config::Config)

# Subsurface states
if model_type == "sbm_gwf"
ssf_states = (:head,)
ssf_states = ("subsurface_water__hydraulic_head",)
elseif model_type == "sediment"
ssf_states = nothing
ssf_states = ()
else
do_subsurface_flow = get(config.model, "kinematic-wave_subsurface", true)::Bool
ssf_states = do_subsurface_flow ? (:ssf,) : nothing
ssf_states = do_subsurface_flow ? ("subsurface_water__volume_flow_rate",) : ()
end

# Land states
Expand All @@ -176,101 +160,58 @@ function extract_required_states(config::Config)
"kinematic-wave",
)::String
if land_routing == "local-inertial"
land_states = (:qx, :qy, :h, :h_av)
elseif land_routing == "kinematic-wave"
if model_type == "sbm" || model_type == "sbm_gwf"
land_states = (:q, :h, :h_av)
else
land_states = (:q, :h)
end
land_states = (
"land_surface_water__x_component_of_volume_flow_rate",
"land_surface_water__y_component_of_volume_flow_rate",
"land_surface_water__depth",
"land_surface_water__time_average_of_depth",
)
else
land_states = (
"land_surface_water__volume_flow_rate",
"land_surface_water__depth",
"land_surface_water__time_average_of_depth",
)
end
end

# River states
if model_type == "sediment"
river_states = get_sediment_states()
elseif model_type == "sbm" || model_type == "sbm_gwf"
river_states = (:q, :h, :h_av)
else
river_states = (:q, :h)
river_states = (
"river_water__volume_flow_rate",
"river_water__depth",
"river_water__time_average_of_depth",
)
end

# Floodplain states
floodplain_states = do_floodplains ? (:q, :h) : nothing
floodplain_states =
do_floodplains ? ("floodplain_water__volume_flow_rate", "floodplain_water__depth") :
()

# Lake and reservoir states
lake_states = do_lakes ? (:waterlevel,) : nothing
reservoir_states = do_reservoirs ? (:volume,) : nothing
lake_states = do_lakes ? ("lake_water_level__elevation",) : ()
reservoir_states = do_reservoirs ? ("reservoir_water__volume",) : ()

# Paddy states
paddy_states = do_paddy ? (:h,) : nothing
paddy_states = do_paddy ? ("land_surface_water~paddy__depth",) : ()

# Add required states to a tuple, similar to the keys in the output of
# `ncnames(config.state.variables)`
required_states = snow_states...,
glacier_states...,
interception_states...,
soil_states...,
ssf_states...,
land_states...,
river_states...,
floodplain_states...,
lake_states...,
reservoir_states...,
paddy_states...

# Build required states in a tuple, similar to the keys in the output of
# `ncnames(config.state)`
required_states = ()
# Add snow, glacier, interception and sbm soil states to dict
required_states =
add_to_required_states(required_states, (:vertical, :snow, :variables), snow_states)
required_states = add_to_required_states(
required_states,
(:vertical, :glacier, :variables),
glacier_states,
)
required_states = add_to_required_states(
required_states,
(:vertical, :interception, :variables),
interception_states,
)
required_states =
add_to_required_states(required_states, (:vertical, :soil, :variables), soil_states)
# Add subsurface states to dict
if model_type == "sbm_gwf"
key_entry = (:lateral, :subsurface, :flow, :aquifer, :variables)
else
key_entry = (:lateral, :subsurface, :variables)
end
required_states = add_to_required_states(required_states, key_entry, ssf_states)
# Add land states to dict
required_states =
add_to_required_states(required_states, (:lateral, :land, :variables), land_states)
# Add sediment states to dict
if model_type == "sediment"
required_states = add_to_required_states(
required_states,
(:lateral, :river, :sediment_flux, :variables),
river_states,
)
else
required_states = add_to_required_states(
required_states,
(:lateral, :river, :variables),
river_states,
)
end
# Add floodplain states to dict
required_states = add_to_required_states(
required_states,
(:lateral, :river, :floodplain, :variables),
floodplain_states,
)
# Add lake states to dict
required_states = add_to_required_states(
required_states,
(:lateral, :river, :boundary_conditions, :lake, :variables),
lake_states,
)
# Add reservoir states to dict
required_states = add_to_required_states(
required_states,
(:lateral, :river, :boundary_conditions, :reservoir, :variables),
reservoir_states,
)
# Add paddy states to dict
required_states = add_to_required_states(
required_states,
(:vertical, :demand, :paddy, :variables),
paddy_states,
)
return required_states
end

Expand All @@ -283,7 +224,7 @@ required states. If not all states are covered, an error is thrown to warn the u
provided than required, a warning is logged, and the unnecessary state is removed.
"""
function check_states(config::Config)
state_ncnames = ncnames(config.state)
state_ncnames = ncnames(config.state.variables)

# Get required states
required_states = extract_required_states(config)
Expand Down
4 changes: 1 addition & 3 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,7 @@ function set_states!(instate_path, model; type = nothing, dimname = nothing)
(; network, vertical, config) = model

# Check if required states are covered
# TODO: revert back to state checking
# state_ncnames = check_states(config)
state_ncnames = ncnames(config.state.variables)
state_ncnames = check_states(config)

# states in netCDF include dim time (one value) at index 3 or 4, 3 or 4 dims are allowed
NCDataset(instate_path) do ds
Expand Down
2 changes: 1 addition & 1 deletion test/run_sbm.jl
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ config.model.floodplain_1d = true
config.model.river_routing = "local-inertial"
config.model.land_routing = "kinematic-wave"
config.input.parameters["floodplain_water__sum_of_volume-per-depth"] = "floodplain_volume"
config.state.variables.floodplain_water__volume = "q_floodplain"
config.state.variables.floodplain_water__volume_flow_rate = "q_floodplain"
config.state.variables.floodplain_water__depth = "h_floodplain"

model = Wflow.initialize_sbm_model(config)
Expand Down

0 comments on commit 3d50d76

Please sign in to comment.