Forcing data

eWaterCycle can load or generate forcing data for a model using the forcing module.

          In:
import ewatercycle.forcing

Model specific forcing classes can be listed with

3         In:
from rich import print

print(ewatercycle.forcing.sources)
ForcingSources[
    "DistributedMakkinkForcing",
    "DistributedUserForcing",
    "GenericDistributedForcing",
    "GenericLumpedForcing",
    "HypeForcing",
    "LisfloodForcing",
    "LumpedMakkinkForcing",
    "LumpedUserForcing",
    "MarrmotForcing",
    "PCRGlobWBForcing",
    "WflowForcing",
]

Existing forcing from external source

We first show how existing forcing data can be loaded with eWaterCycle. The wflow example parameter set already includes forcing data that was generated manually by the scientists at Deltares.

4         In:
from ewatercycle.parameter_sets import available_parameter_sets

parameter_set = available_parameter_sets(target_model="wflow")["wflow_rhine_sbm_nc"]

forcing = ewatercycle.forcing.sources["WflowForcing"](
    directory=str(parameter_set.directory),
    start_time="1991-01-01T00:00:00Z",
    end_time="1991-12-31T00:00:00Z",
    shape=None,
    # Additional information about the external forcing data needed for the model configuration
    netcdfinput="inmaps.nc",
    Precipitation="/P",
    EvapoTranspiration="/PET",
    Temperature="/TEMP",
)
print(forcing)
WflowForcing(
    start_time='1991-01-01T00:00:00Z',
    end_time='1991-12-31T00:00:00Z',
    directory=PosixPath('/home/bart/ewatercycle/parameter-sets/wflow_rhine_sbm_nc'),
    shape=None,
    filenames={},
    netcdfinput='inmaps.nc',
    Precipitation='/P',
    EvapoTranspiration='/PET',
    Temperature='/TEMP',
    Inflow=None
)

As you can see, the forcing consists of a generic part which is the same for all eWaterCycle models, and a model-specific part (forcing_info). If you’re familiar with wflow, you might recognize that the model-specific settings map directly to wflow configuration settings.

Generating forcing data

In most cases, you will not have access to tailor-made forcing data, and manually pre-processing existing datasets can be quite a pain. eWaterCycle includes a forcing generator that can do all the required steps to go from the available datasets (ERA5, ERA-Interim, etc) to whatever format the models require. This is done through ESMValTool recipes.

The most simple forcing available only contains NetCDF files for precipitation and air temperature. These are the “generic” forcing generators:

Usually, (potential) evaporation is required. For this eWaterCycle includes forcing computed using Makkink’s equation:

For example, to generate forcing for the Rhine river basin for 2001 and 2002 you can use the following code:

5         In:
from ewatercycle.testing.fixtures import rhine_shape

shape = rhine_shape()
forcing = ewatercycle.forcing.sources["GenericDistributedForcing"].generate(
    dataset="ERA5",
    start_time="2000-01-01T00:00:00Z",
    end_time="2001-01-01T00:00:00Z",
    shape=shape.absolute(),
)
print(forcing)
ERROR 1: PROJ: proj_create_from_database: Open of /home/bart/micromamba/envs/ewc3.11/share/proj failed
ERROR 1: PROJ: proj_create_from_database: Open of /home/bart/micromamba/envs/ewc3.11/share/proj failed
GenericDistributedForcing(
    start_time='2000-01-01T00:00:00Z',
    end_time='2001-01-01T00:00:00Z',
    directory=PosixPath('/home/bart/esmvaltool_output/ewcrepty2fypdu_20240312_154014/work/diagnostic/script'),
    shape=PosixPath('/home/bart/git/ewatercycle/src/ewatercycle/testing/data/Rhine/Rhine.shp'),
    filenames={
        'pr': 'OBS6_ERA5_reanaly_1_day_pr_2000-2001.nc',
        'tas': 'OBS6_ERA5_reanaly_1_day_tas_2000-2001.nc'
    }
)

As a second example, we can generate forcing from the EC-Earth3 climate model data. This can be for historical data, but also climate scenarios.

This time we’ll demonstrate the LumpedMakkinkForcing:

6         In:
# See https://www.climate4impact.eu/c4i-frontend/search for an overview of models,
# experiments, and ensemble members.
cmip_dataset = {
    "dataset": "EC-Earth3",  # Name of the model
    "project": "CMIP6",
    "grid": "gr",
    "exp": "historical",  # historical, or climate scenario
    "ensemble": "r6i1p1f1",  # ensemble member
}

forcing = ewatercycle.forcing.sources["LumpedMakkinkForcing"].generate(
    dataset=cmip_dataset,
    start_time="2000-01-01T00:00:00Z",
    end_time="2001-01-01T00:00:00Z",
    shape=shape.absolute(),
)
print(forcing)
ERROR 1: PROJ: proj_create_from_database: Open of /home/bart/micromamba/envs/ewc3.11/share/proj failed
ERROR 1: PROJ: proj_create_from_database: Open of /home/bart/micromamba/envs/ewc3.11/share/proj failed
LumpedMakkinkForcing(
    start_time='2000-01-01T00:00:00Z',
    end_time='2001-01-01T00:00:00Z',
    directory=PosixPath('/home/bart/esmvaltool_output/ewcrep3p_5ibfk_20240312_155600/work/diagnostic/script'),
    shape=PosixPath('/home/bart/git/ewatercycle/src/ewatercycle/testing/data/Rhine/Rhine.shp'),
    filenames={
        'pr': 'CMIP6_EC-Earth3_day_historical_r6i1p1f1_pr_gr_2000-2001.nc',
        'tas': 'CMIP6_EC-Earth3_day_historical_r6i1p1f1_tas_gr_2000-2001.nc',
        'rsds': 'CMIP6_EC-Earth3_day_historical_r6i1p1f1_rsds_gr_2000-2001.nc',
        'evspsblpot': 'Derived_Makkink_evspsblpot.nc'
    }
)

Loading generated forcing

Generated forcing is automatically saved to the ESMValTool output directory. A yaml file is stored there as well, such that you can easily reload the forcing later without having to generate it again.

7         In:
reloaded_forcing = ewatercycle.forcing.sources["WflowForcing"].load(
    directory="/home/bart/esmvaltool_output/ewcrepofsot6jc_20240312_133128/work/diagnostic/script"
)
print(reloaded_forcing)
WflowForcing(
    start_time='1990-01-01T00:00:00Z',
    end_time='1990-01-31T00:00:00Z',
    directory=PosixPath('/home/bart/esmvaltool_output/ewcrepofsot6jc_20240312_133128/work/diagnostic/script'),
    shape=None,
    filenames={},
    netcdfinput='wflow_ERA-Interim_Rhine_1990_1990.nc',
    Precipitation='/pr',
    EvapoTranspiration='/pet',
    Temperature='/tas',
    Inflow=None
)

User-defined forcing

If you require variables that are not included in the previous examples, or need to compute a different variable for your model, you can make use of the UserForcing classes:

For these you define the variables and a post-processing function.

As an example, we can recreate Makkink forcing in the following way:

8         In:
from ewatercycle._forcings.makkink import derive_e_pot

lumped_forcing = ewatercycle.forcing.sources["LumpedUserForcing"].generate(
    start_time="2000-01-01T00:00:00Z",
    end_time="2001-01-01T00:00:00Z",
    dataset=cmip_dataset,
    shape=shape,
    variables=(
        "pr",
        "tas",
        "rsds",
    ),  # required variables
    postprocessor=derive_e_pot,  # post-processing function that adds e_pot
)
ERROR 1: PROJ: proj_create_from_database: Open of /home/bart/micromamba/envs/ewc3.11/share/proj failed
ERROR 1: PROJ: proj_create_from_database: Open of /home/bart/micromamba/envs/ewc3.11/share/proj failed

Model-specific forcing

For some models (e.g. lisflood) additional computations are done, as some steps require data and/or code that is not available to ESMValTool. Apart from some standard parameters (start time, datasets, etc.), the forcing generator sometimes requires additional model-specific options.

For our wflow example case, we need to pass the DEM file to the ESMValTool recipe as well. All model-specific options are listed in their documentation.

Current forcing generation dataset sources

eWaterCycle uses ESMValTool to generate forcing data. You can generate forcing from the ERA5 and ERA-Interim datasets. There is also support for generating forcing from datasets on ESGF by supplying a Dataset object to the ewatercycle.base.forcing.Defaultforcing.generate method.

9         In:
generated_forcing = ewatercycle.forcing.sources["WflowForcing"].generate(
    dataset="ERA-Interim",
    start_time="1990-01-01T00:00:00Z",
    end_time="1990-01-31T00:00:00Z",
    shape=shape.absolute(),
    dem_file=f"{parameter_set.directory}/staticmaps/wflow_dem.map",
)
print(generated_forcing)
ERROR 1: PROJ: proj_create_from_database: Open of /home/bart/micromamba/envs/ewc3.11/share/proj failed
ERROR 1: PROJ: proj_create_from_database: Open of /home/bart/micromamba/envs/ewc3.11/share/proj failed
WflowForcing(
    start_time='1990-01-01T00:00:00Z',
    end_time='1990-01-31T00:00:00Z',
    directory=PosixPath('/home/bart/esmvaltool_output/ewcrepssyninpz_20240312_155637/work/diagnostic/script'),
    shape=PosixPath('/home/bart/git/ewatercycle/src/ewatercycle/testing/data/Rhine/Rhine.shp'),
    filenames={},
    netcdfinput='wflow_ERA-Interim_Rhine_1990_1990.nc',
    Precipitation='/pr',
    EvapoTranspiration='/pet',
    Temperature='/tas',
    Inflow=None
)

To make your own forcing generator, see the adding models documentation.