Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Water balance computation #525

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft

Water balance computation #525

wants to merge 2 commits into from

Conversation

SouthEndMusic
Copy link
Contributor

@SouthEndMusic SouthEndMusic commented Jan 14, 2025

Issue addressed

Fixes #90

Explanation

I created a new script water_balance.jl, with:

  • Structs with arrays for in-place computations of water balance errors
  • Associated constructors
  • Functions for evaluating the water balance errors for vertical and over_land separately

I have a few open questions about this:

  • How to deal with the start of the simulation? I.e. data from before and after a timestep is needed to compute a water balance error. An explicit example: how to obtain storage_total_prev after the first timestep in compute_water_balance! for vertical processes? Is such data (i.e. satwaterdepth, ustoredept) always initialized before start of time stepping?
  • What is the cleanest way to deduce how much cells (n) there are (for array initialization)?
  • Please check which variables I have to use to cover all water storage in the model
  • What should be done with the water balance data (in this PR)? Should we already implement an error when certain bounds are exceeded? Should the data be written to an output file?

Checklist

  • Updated tests or added new tests
  • Branch is up to date with master
  • Tests & pre-commit hooks pass
  • Updated documentation if needed
  • Updated changelog.qmd if needed

Additional Notes (optional)

Add any additional notes or information that may be helpful.

@SouthEndMusic SouthEndMusic marked this pull request as draft January 14, 2025 10:44
@SouthEndMusic SouthEndMusic changed the title Water balance computation setup Water balance computation Jan 14, 2025
(; flow_length, flow_width) = subsurface.parameters

storage_total .= satwaterdepth
storage_total .+= ustoredepth
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During model initialization, ustoredepth is not set based on ustorelayerdepth (state). As discussed, it could for example be added in the initialization of the model, for that the ustoredepth! function can be used after the states are set (after this line for the model type sbm: https://github.com/Deltares/Wflow.jl/blob/master/src/sbm_model.jl#L390).

(; ssf, ssfin) = subsurface.variables
(; flow_length, flow_width) = subsurface.parameters

storage_total .= satwaterdepth
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few storage variables are missing:
get_snow_storage(snow) .+ get_snow_water(snow)
get_glacier_store(glacier) .* get_glacier_fraction(glacier)
get_water_depth(demand.paddy)
model.land.interception.variables.canopy_storage

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lateral snow transport is often used when snow modelling is included, see also https://github.com/Deltares/Wflow.jl/blob/master/src/sbm.jl#L88. For the water balance this means the lateral snow fluxes need to be included.

storage_total .+= ustoredepth

inflow_total .= vertical.atmospheric_forcing.precipitation
inflow_total .+= runoff.variables.net_runoff_river
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

net_runoff_river is not an inflow (it is an outflow). allocation refers to model.land.allocation.

Suggested change
inflow_total .+= runoff.variables.net_runoff_river
inflow_total .+= get_irrigation_allocated(allocation)

inflow_total .+= runoff.variables.net_runoff_river
inflow_total .+= 1000.0 * ssfin ./ (flow_length .* flow_width)

outflow_total .= runoff_land
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

net_runoff refers to model.land.soil.variables.net_runoff

Suggested change
outflow_total .= runoff_land
outflow_total .= net_runoff

inflow_total .+= 1000.0 * ssfin ./ (flow_length .* flow_width)

outflow_total .= runoff_land
outflow_total .+= net_runoff_river
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As part of water demand computations water can be abstracted: land.allocation.variables.act_groundwater_abst. This should be added to outflow_total. Suggest to use a wrapper method here similar to get_irrigation_allocated(allocation).

(; runoff_land, net_runoff_river) = runoff.variables

(; subsurface) = lateral
(; ssf, ssfin) = subsurface.variables
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that these variables refer to the LateralSSF struct (kinematic wave for lateral subsurface flow). It would be nice to also have water balance computations for the sbm_gwf model type that makes use of Darcy groundwater flow for a single unconfined layer (see also \src\sbm_gwf_model.jl and \src\groundwater\aquifer.jl).

return nothing
end

struct WaterBalanceOverLand{T <: AbstractFloat} # Terms in [?]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have water balance computations for the available routing options (suggest for example to rename to WaterBalanceRouting if this struct is used to store water balance components for the different routing options).


copyto!(storage_total_prev, storage_total)

#TODO : What to do with results?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now I think it is fine to compute the errors and these variables can be written as output (netCDF (gridded and scalar) or CSV).

WaterBalanceOverLand(ntuple(_ -> fill(float_type(Nan), n), 6)...)
end

# function compute_water_balance!(model, water_balance::WaterBalanceOverLand)::Nothing
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For most routing options an internal time step (different from the model time step) is used. The variable volume is available and initialized (either cold or warm state). Outflow variables (e.g. q_av) are available for the model time step, but inflow variables are mostly only available at the internal time step.

Kinematic wave overland flow

  • outflow: q_av
  • inflow: qin + qlat * flow_length (internal time step), instead of qlat * flow_length, inwater` can also be used (valid for model time step)

Kinematic wave river flow

  • outflow: q_av
  • inflow: q_in + (qlat + _inflow) * flow_length (internal time step) (as for the kinematic wave overland flow, inwater (valid for model time step) can also be used (to replace qlat * flow_length)

Local inertial river flow (with optional floodplain routing scheme)
A cumulative volume error is computed, see also the code starting here https://github.com/Deltares/Wflow.jl/blob/master/src/routing/surface_local_inertial.jl#L479. I think it would be useful to have also error(s) available per model time step as part of water_balance.jl. If floodplain routing is included I would recommend to compute the water balance for river and floodplain (not separated).

Local inertial river and overland flow
A cumulative error is computed, see also the code starting here https://github.com/Deltares/Wflow.jl/blob/master/src/routing/surface_local_inertial.jl#L1033. For the water balance computation per model time step it is enough to consider land_v.volume.

When many variables are involved (as for local inertial routing) it probably makes sense to compute a net_flux.

Kinematic wave subsurface flow
outflow: ssf + exfiltwater * flow_length * flow_width
inflow: ssfin + recharge * flow_length
Note: see for units of variables https://github.com/Deltares/Wflow.jl/blob/master/src/routing/subsurface.jl#L87.

Groundwater flow
Here Q is used as the net flux, see also: https://github.com/Deltares/Wflow.jl/blob/master/src/groundwater/aquifer.jl#L432

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

include mass/water balance checks
2 participants