Tip

For an interactive online version click here: Binder badge

Update forcing data#

Once you have a DELWAQ model, you may want to update your model in order to add new emission data, add sample locations, use different hydrological forcing data, create and run different scenarios etc.

With HydroMT, you can easily read your model and update one or several components of your model using the update function of the command line interface (CLI). Here are the steps and some examples on how to update the model forcing.

All lines in this notebook which starts with ! are executed from the command line. Within the notebook environment the logging messages are shown after completion. You can also copy these lines and paste them in your shell to get more feedback.

This notebook supposes that you already run the delwaq build EM example notebook and that you have a EM_test D-Emissions model available in the examples folder.

Import packages#

In this notebook, we will use some functions of HydroMT to visualize available data. Here are the libaries to import.

[1]:
import xarray as xr

Hydrological forcing data from Wflow#

D-Emissions or D-Water Quality models can use meteo/hydrological input data from Wflow. The steps to get these data available for your model are:

More information on the meteo/hydrological forcing link between Wflow and DELWAQ is available in docs (Wflow_outputs).

Selection of the Wfow outputs#

For our D-Emissions model, we will use hydrological data from the wflow_piave hydrologic model. For a D-Emissions model, the required meteo/hydrological inputs are:

  • precipitation

  • the amount of the precipitation that infiltrates into the soil from unpaved areas

  • the amount of the precipitation that goes directly to surface runoff from paved areas

  • the amount of the precipitation that goes directly to surface runoff from unpaved areas

  • exfiltration from the saturated and unsaturated store of the soil

  • volumetric water content of the soil pores in the root zone ie root zone soil moisture

If you wish to include transport to the river (overland flow and soil) in D-Emission, then also:

  • overland flow

  • subsurface flow

In order to get these data from Wflow, you need to save these fluxes after the model run. These output fluxes are specified in the Wflow TOML configuration file.

To set these options, you can either edit the TOML file manually or use HydroMT to help you do the trick using the hydromt update CLI API!

Here is the HydroMT configuration file needed to update the Wflow model (note in that file both fluxes for demission and for delwaq models are listed):

[2]:
fn_yml = 'wflow_update.yml'
with open(fn_yml, 'r') as f:
    txt = f.read()
print(txt)
steps:
  - setup_config:
      data:
        time.starttime: "2010-02-02T00:00:00"
        time.endtime: "2010-02-10T00:00:00"
        time.timestepsecs: 86400
        # Variables to save for a coupling between wflow and demission + delwaq
        output.netcdf_grid.variables.atmosphere_water__precipitation_volume_flux: "precip"
        output.netcdf_grid.variables.land_surface__evapotranspiration_volume_flux: "infilt"
        output.netcdf_grid.variables.compacted_soil_surface_water__excess_volume_flux: "runUnp"
        output.netcdf_grid.variables.non_compacted_soil_surface_water__excess_volume_flux: "runPav"
        output.netcdf_grid.variables.soil_surface_water_unsaturated_zone__exfiltration_volume_flux: "exfiltustore"
        output.netcdf_grid.variables.soil_surface_water_saturated_zone__exfiltration_volume_flux: "exfiltsatstore"
        output.netcdf_grid.variables.soil_water_root_zone__volume_percentage: "vwcproot"
        output.netcdf_grid.variables.river_water__volume_flow_rate: "q_river"
        output.netcdf_grid.variables.river_water__volume: "vol_river"
        output.netcdf_grid.variables.land_surface_water__volume_flow_rate: "q_land"
        output.netcdf_grid.variables.land_surface_water__to_river_volume_flow_rate: "land_to_river"
        output.netcdf_grid.variables.subsurface_water__volume_flow_rate: "q_ssf"
        output.netcdf_grid.variables.subsurface_water__to_river_volume_flow_rate: "ssf_to_river"
        # Only add if reservoirs in the model
        output.netcdf_grid.variables.reservoir_water__volume: "vol_reservoir"
        output.netcdf_grid.variables.reservoir_water__outgoing_volume_flow_rate: "q_reservoir"
        # Only add if 1d floodplain in the model
        # output.netcdf_grid.variables.floodplain_water__volume: "vol_floodplain"

  - config.write:

And the hydromt update CLI to use:

[3]:
! hydromt update wflow_sbm wflow_piave -i wflow_update.yml --fo -vvv
2026-01-19 02:35:04,479 - hydromt - log - INFO - HydroMT version: 1.3.0
2026-01-19 02:35:04,506 - hydromt.model.model - model - INFO - Initializing wflow_sbm model from hydromt_wflow (v1.0.1).
2026-01-19 02:35:04,506 - hydromt.data_catalog.data_catalog - data_catalog - INFO - Parsing data catalog from /home/runner/miniconda3/envs/hydromt_delwaq/lib/python3.11/site-packages/hydromt_wflow/data/parameters_data.yml
2026-01-19 02:35:04,538 - hydromt.hydromt_wflow.wflow_base - wflow_base - INFO - Supported Wflow.jl version v1+
2026-01-19 02:35:04,538 - hydromt.hydromt_wflow.components.config - config - INFO - Reading model config file from /home/runner/work/hydromt_delwaq/hydromt_delwaq/docs/_examples/wflow_piave/wflow_sbm.toml.
2026-01-19 02:35:04,539 - hydromt - log - INFO - HydroMT version: 1.3.0
2026-01-19 02:35:04,540 - hydromt - log - INFO - HydroMT version: 1.3.0
2026-01-19 02:35:04,792 - hydromt.model.model - model - INFO - update: setup_config
2026-01-19 02:35:04,793 - hydromt.model.model - model - INFO - setup_config.data={'time.starttime': '2010-02-02T00:00:00', 'time.endtime': '2010-02-10T00:00:00', 'time.timestepsecs': 86400, 'output.netcdf_grid.variables.atmosphere_water__precipitation_volume_flux': 'precip', 'output.netcdf_grid.variables.land_surface__evapotranspiration_volume_flux': 'infilt', 'output.netcdf_grid.variables.compacted_soil_surface_water__excess_volume_flux': 'runUnp', 'output.netcdf_grid.variables.non_compacted_soil_surface_water__excess_volume_flux': 'runPav', 'output.netcdf_grid.variables.soil_surface_water_unsaturated_zone__exfiltration_volume_flux': 'exfiltustore', 'output.netcdf_grid.variables.soil_surface_water_saturated_zone__exfiltration_volume_flux': 'exfiltsatstore', 'output.netcdf_grid.variables.soil_water_root_zone__volume_percentage': 'vwcproot', 'output.netcdf_grid.variables.river_water__volume_flow_rate': 'q_river', 'output.netcdf_grid.variables.river_water__volume': 'vol_river', 'output.netcdf_grid.variables.land_surface_water__volume_flow_rate': 'q_land', 'output.netcdf_grid.variables.land_surface_water__to_river_volume_flow_rate': 'land_to_river', 'output.netcdf_grid.variables.subsurface_water__volume_flow_rate': 'q_ssf', 'output.netcdf_grid.variables.subsurface_water__to_river_volume_flow_rate': 'ssf_to_river', 'output.netcdf_grid.variables.reservoir_water__volume': 'vol_reservoir', 'output.netcdf_grid.variables.reservoir_water__outgoing_volume_flow_rate': 'q_reservoir'}
2026-01-19 02:35:04,793 - hydromt.model.model - model - INFO - update: config.write
2026-01-19 02:35:04,793 - hydromt.model.model - model - INFO - config.write.filename=None
2026-01-19 02:35:04,793 - hydromt.model.model - model - INFO - config.write.config_root=None
2026-01-19 02:35:04,793 - hydromt.hydromt_wflow.components.config - config - INFO - Writing model config to /home/runner/work/hydromt_delwaq/hydromt_delwaq/docs/_examples/wflow_piave/wflow_sbm.toml.

The example above means the following: run hydromt with:

  • update wflow: i.e. update a wflow model

  • wflow_piave_subbasin: model folder to update

  • -i wflow_update_forcing.yml: setup configuration file containing the components to update and their different options

  • --fo: allow to overwrite an existing model.

  • -v: give some extra verbosity (2 * v) to display feedback on screen. Now debug messages are provided.

The next step would then be to run the wflow_piave model using our updated TOML configuration file.

Available hydrological data from Wflow#

For our D-Emissions model, we will use hydrological data from the wflow_piave hydrologic model.

The model was already run beforehand and the wflow_piave outputs are stored in the wflow_piave/run_default/output.nc in NetCDF format. Let’s have a look at the model outputs and see what data is available and for which periods.

Note: You can also inspect the file using Panoply or QGIS.

[4]:
# Open the file
wflow_output_fn = 'wflow_piave/run_default/output.nc'
outputs = xr.open_dataset(wflow_output_fn, chunks={"time": 10})
#Print available variables and start and end time
print(f"Available outputs from wflow: {outputs.data_vars}")
times = outputs.time.values
print(f"Outputs available from {times[0]} to {times[-1]}")
Available outputs from wflow: Data variables:
    infilt          (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    vwcproot        (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    vol_reservoir   (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    vol_river       (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    runPav          (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    precip          (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    exfiltustore    (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    runUnp          (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    q_land          (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    exfiltsatstore  (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    land_to_river   (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    q_river         (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    ssf_to_river    (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    q_reservoir     (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
    q_ssf           (time, lat, lon) float32 98kB dask.array<chunksize=(8, 53, 58), meta=np.ndarray>
Outputs available from 2010-02-03T00:00:00.000000000 to 2010-02-10T00:00:00.000000000

We recognize from above all the variables and names we set previously in the wflow_update.yml file. All the required variables are present and available for 9 days in February 2010.

Registering the wflow outputs as a HydroMT data source#

As we are using hydrological forcing from a user defined run of the wflow model, the wflow output format and attributes can be different depending on the user settings. Wflow outputs are then considered as local or user data source and therefore need to be added to the HydroMT list of data sources using a local yaml library file.

Below you can see the local_sources.yml file corresponding to our wflow outputs:

[5]:
fn_yml = 'local_sources.yml'
with open(fn_yml, 'r') as f:
    txt = f.read()
print(txt)
wflow_output_em:
  data_adapter:
    rename:
      q_ssf: q_ss
      ssf_to_river: exfiltssf
    unit_mult:
      exfiltssf: 1.15741e-05
      q_ss: 1.15741e-05
  data_type: RasterDataset
  driver:
    name: raster_xarray
    options:
      chunks:
        lat: -1
        lon: -1
        time: 1
      preprocess: harmonise_dims
  metadata:
    attrs:
      exfiltsatstore:
        unit: mm
      exfiltssf:
        unit: m3/s
      exfiltustore:
        unit: mm
      infilt:
        unit: mm
      precip:
        unit: mm
      q_land:
        unit: m3/s
      q_ss:
        unit: m3/s
      runPav:
        unit: mm
      runUnp:
        unit: mm
      vwcproot:
        unit: '%'
    category: hydro
    crs: 4326
  uri: wflow_piave/run_default/output.nc
wflow_output_wq:
  data_adapter:
    rename:
      land_to_river: land>sfw
      q_reservoir: sfw>sfw_2
      q_river: sfw>sfw_1
      ssf_to_river: soil>sfw
      vol_reservoir: sfw_2
      vol_river: sfw_1
    unit_mult:
      soil>sfw: 1.15741e-05
  data_type: RasterDataset
  driver:
    name: raster_xarray
    options:
      chunks:
        lat: -1
        lon: -1
        time: 1
      preprocess: harmonise_dims
  metadata:
    attrs:
      land>sfw:
        unit: m3/s
      sfw>sfw_1:
        unit: m3/s
      sfw>sfw_2:
        unit: m3/s
      sfw_1:
        unit: m3
      sfw_2:
        unit: m3
      soil>sfw:
        unit: m3/s
    category: hydro
    crs: 4326
  uri: wflow_piave/run_default/output.nc

Here are some explanations about the file. You can have a look at the HydroMT yaml data libary documentation for more information.

The first thing to define in the yaml library is the name of the data source you want to add in HydroMT. For example, here we use the name wflow_output_em for the EM variables definition and wflow_output_wq for the WQ variables. This name is important and is used in the HydroMT config .yml file to tell HydroMT which data source you wish to use. Once the name of the data source is set, the data attributes are listed:

  • path: path to where the data is stored.

  • crs: coordinate system of the data.

  • data_type: HydroMT DataCatalog type either RasterDataset (gridded data), GeoDataFrame (vector data), DataFrame (tables), Dataset (non-geospatial N-dim data) or GeoDataset (point timeseries).

  • driver: driver used to open the data. For example raster (GDAL compliant raster file), netcdf (NetCDF file), zarr (zarr file) or vector (GDAL compliant vector file). See the hydromt docs for all options.

  • driver_kwargs: optional arguments to read the data. Depends on the driver.

  • meta: optional additional information on the data.

  • rename: list used to rename the variables inside of the data to HydroMT compliant names. The format is “name_in_dataset: name_in_HydroMT”. Note that the names present in the NetCDF file are the ones set up in the wflow TOML file. The list of standard HydroMT names for demission forcing variables are: time, precip, infilt, runPav, runUnp, exfilt*, q_ss and q_land.

  • attrs unit: unit attribute of the variables in the data. Used by Delwaq only in order to convert from mm to m3/s and from m to m3 (requires complex unit conversion than just a multiplication or addition with a constant value).

Model setup configuration#

As with building, you can prepare a HydroMT configuration file that includes every components and settings that you want to run during your update.

The configuratio file (yml) contains the model setup configuration and determines which components are updated and in which sequence and sets optional arguments for each component. This configuration is passed to hydromt using -i <path_to_configuration_file>.

Each header as shown between [...] (e.g. [setup_hydrology_forcing]) corresponds with a model component which are explained in the docs(model_components).

Let’s open the example configuration file delwaq_update_EM_forcing.yml from the model repository [examples folder] and have a look at the settings.

[6]:
fn_ini = 'delwaq_update_EM_forcing.yml'
with open(fn_ini, 'r') as f:
    txt = f.read()
print(txt)
steps:
  - setup_hydrology_forcing:
      hydro_forcing_fn: wflow_output_em
      starttime: "2010-02-04 00:00:00"
      endtime: "2010-02-10 00:00:00"
      timestepsecs: 86400
      include_transport: True

  - config.write:

  - forcing.write:

  - write_waqgeom:

Here we can see that we will run setup_hydrology_forcing component to prepare daily hydrological forcing for 8 days in February 2010 using our wflow_output.

Note that the add_volume_offset function is set to True. This is because Delwaq needs water volumes at the beginning of the timestep. In some models, like wflow, volumes are written at the end of the timestep and therefore an offset of one timestep needs to be added for consistency.

You can find more information on the different components and their options in the docs (model_components).

HydroMT CLI update interface#

Using the hydromt update API, we can update one or several components of an already existing Delwaq model. Let’s get an overview of the available options:

[7]:
# Print the options available from the update command
! hydromt update --help
Usage: hydromt update [OPTIONS] MODEL MODEL_ROOT

  Update a specific component of a model.

  Set an output directory to copy the edited model to a new folder, otherwise
  maps are overwritten.

  Example usage: --------------

  Update Wflow model components outlined in an .yml configuration file and
  write the model to a directory: hydromt update wflow_sbm /path/to/model_root
  -o /path/to/model_out  -i /path/to/wflow_config.yml  -d
  /path/to/data_catalog.yml -v

Options:
  -o, --model-out DIRECTORY  Output model folder. Maps in MODEL_ROOT are
                             overwritten if left empty.
  -i, --config PATH          Path to hydroMT configuration file, for the model
                             specific implementation.  [required]
  -d, --data TEXT            Path to local yaml data catalog file OR name of
                             predefined data catalog.
  --dd, --deltares-data      Flag: Shortcut to add the "deltares_data" catalog
  --fo, --force-overwrite    Flag: If provided overwrite existing model files
  --cache                    Flag: If provided cache tiled rasterdatasets
  -q, --quiet                Decrease verbosity.
  -v, --verbose              Increase verbosity.
  --help                     Show this message and exit.

Update demission forcing layers#

[8]:
# NOTE: copy this line (without !) to your shell for more direct feedback
! hydromt update demission ./EM_test -i delwaq_update_EM_forcing.yml -d local_sources.yml --fo -vv
2026-01-19 02:35:11,424 - hydromt - log - INFO - HydroMT version: 1.3.0
2026-01-19 02:35:11,450 - hydromt.data_catalog.data_catalog - data_catalog - INFO - Parsing data catalog from local_sources.yml
2026-01-19 02:35:11,470 - hydromt.model.model - model - INFO - Initializing demission model from hydromt_delwaq (v0.3.2.dev0).
2026-01-19 02:35:11,470 - hydromt - log - INFO - HydroMT version: 1.3.0
2026-01-19 02:35:11,470 - hydromt - log - INFO - HydroMT version: 1.3.0
2026-01-19 02:35:11,493 - hydromt.model.model - model - INFO - update: setup_hydrology_forcing
2026-01-19 02:35:11,493 - hydromt.model.model - model - INFO - setup_hydrology_forcing.include_transport=True
2026-01-19 02:35:11,493 - hydromt.model.model - model - INFO - setup_hydrology_forcing.hydro_forcing_fn=wflow_output_em
2026-01-19 02:35:11,493 - hydromt.model.model - model - INFO - setup_hydrology_forcing.starttime=2010-02-04 00:00:00
2026-01-19 02:35:11,493 - hydromt.model.model - model - INFO - setup_hydrology_forcing.endtime=2010-02-10 00:00:00
2026-01-19 02:35:11,493 - hydromt.model.model - model - INFO - setup_hydrology_forcing.timestepsecs=86400
2026-01-19 02:35:11,496 - hydromt.data_catalog.sources.data_source - data_source - INFO - Reading wflow_output_em RasterDataset data from /home/runner/work/hydromt_delwaq/hydromt_delwaq/docs/_examples/wflow_piave/run_default/output.nc
2026-01-19 02:35:11,709 - hydromt.gis.raster - raster - WARNING - No numerical nodata value found, skipping set_nodata
2026-01-19 02:35:11,717 - hydromt.hydromt_delwaq.components.forcing - forcing - INFO - NetCDF copy of the forcing file dynamicdata/dynamicdata.nc not found in model root, skip reading.
2026-01-19 02:35:11,718 - hydromt.model.components.config - config - WARNING - No default model config was found at /home/runner/work/hydromt_delwaq/hydromt_delwaq/docs/_examples/EM_test/emission.inp. It wil be initialized as empty dictionary
2026-01-19 02:35:11,719 - hydromt.model.model - model - INFO - update: config.write
2026-01-19 02:35:11,719 - hydromt.hydromt_delwaq.components.config - config - INFO - Writing model config to file.
2026-01-19 02:35:11,720 - hydromt.model.model - model - INFO - update: forcing.write
2026-01-19 02:35:11,720 - hydromt.model.model - model - INFO - forcing.write.filename=dynamicdata/{name}.dat
2026-01-19 02:35:11,721 - hydromt.model.model - model - INFO - forcing.write.write_nc=False
Writing dynamic data: 100%|███████████████████████| 7/7 [00:00<00:00, 26.57it/s]
2026-01-19 02:35:12,002 - hydromt.model.model - model - INFO - update: write_waqgeom

The example above means the following: run hydromt with:

  • update demission: i.e. update a delwaq model

  • ./EM_test_full: model folder

  • -i delwaq_update_EM_forcing.yml: setup configuration file containing the components to update and their different options

  • -d local_sources.yml: local data library, here containing the hydrological outputs from wflow.

  • --fo: allow to update and overwrite an existing model.

  • -v: give some extra verbosity (2 * v) to display feedback on screen. Now debug messages are provided.

Visualization of the outputs#

From the information above, you can see that the different forcing variables where updated. If you have a look at the output files, you can see that the hydrological data were added to the dynamicdata folder but also several information were added in the config folder.

[9]:
import os
root = 'EM_test'
for path, _, files in os.walk(root):
    print(path)
    for name in files:
        if name.endswith('.xml'):
            continue
        print(f' - {name}')
EM_test
 - hydromt_data.yml
 - hydromt.log
EM_test/staticdata
 - ghs_pop_2015.dat
 - slope.dat
 - river.dat
 - streamorder.dat
 - ptiddown.dat
 - porosity.dat
 - soil_thickness.dat
 - staticdata.nc
 - gdp_world.dat
EM_test/hydromodel
 - river.tif
 - modelmap.tif
 - ptiddown.tif
 - elevtn.tif
 - ptid.tif
 - rivarea.tif
 - basins.tif
 - resarea.tif
 - rivwth.tif
 - ldd.tif
 - rivlen.tif
EM_test/config
 - B2_outputtimes.inc
 - B7_geometry.inc
 - B4_nrofexch.inc
 - B2_stations.inc
 - B7_geometry.bin
 - B1_timestamp.inc
 - B5_boundlist.inc
 - B2_nrofmon.inc
 - B7_hydrology.inc
 - B2_timers_only.inc
 - B7_geometry-parameters.inc
 - B3_nrofseg.inc
 - B3_attributes.inc
 - B2_monareas.inc
 - B3_waqgeom.nc
 - B2_timers.inc
 - B2_sysclock.inc
 - B7_surf.inc
EM_test/dynamicdata
 - hydrology.bin
EM_test/geoms
 - monareas.geojson
 - basins.geojson

You can have a look at some of these files:

[10]:
import os
model_path = './EM_test'
fn_config = 'config/B1_timestamp.inc'
with open(os.path.join(model_path,fn_config), 'r') as f:
    txt = f.read()
print(txt)
'T0: 2010.02.04 00:00:00  (scu=       1s)'

For the hydrological data directly, the main files are:

  • dynamicdata/hydrology.bin (Binary data)

  • config/B7_hydrology.inc (Headers for the variables inside of hydrology.bin)

You can also see that a NetCDF file was created: B3_waqgeom.nc. This file can be used to produce NetCDF outputs directly when running D-Emissions or D-Water Quality but also to visualize the model in Delft-FEWS.

[11]:
import os
model_path = './EM_test'
fn_config = 'config/B7_hydrology.inc'
with open(os.path.join(model_path,fn_config), 'r') as f:
    txt = f.read()
print(txt)
SEG_FUNCTIONS
Rainfall RunoffPav RunoffUnp Infiltr Exfiltr vwcproot Overland Subsurface