Show code cell content
# Suppress distracting outputs in these examples
# Note: this cell should be hidden with the tag "hide-cell"
import logging
import warnings
warnings.filterwarnings("ignore", category=UserWarning)
logger = logging.getLogger("esmvalcore")
logger.setLevel(logging.WARNING)
Forcing data
eWaterCycle can load or generate forcing data for a model using the forcing
module.
import ewatercycle.forcing
Model specific forcing classes can be listed with
from rich import print
print(ewatercycle.forcing.sources)
ForcingSources[ "CaravanForcing", "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.
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:
GenericDistributedForcing for distributed models aka grid based models
GenericLumpedForcing for lumped models aka point based models
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:
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)
GenericDistributedForcing( start_time='2000-01-01T00:00:00Z', end_time='2001-01-01T00:00:00Z', directory=PosixPath('/home/bart/esmvaltool_output/ewcrepr_pqguq0_20240605_140621/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
:
# 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)
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' } )
Finding climate data
To find CMIP datasets (and their ensembles) that fit your needs, you can use the esgf_search function from ewatercycle.esmvaltool.search.
For example, to find CMIP datasets with the “ssp585” scenario, that can be used to generate Makkink forcing:
from ewatercycle.esmvaltool.search import search_esgf
valid_datasets = search_esgf(
experiment="ssp585",
frequency="day",
variables=["pr", "tas", "rsds"]
),
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.
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:
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
)
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](https://esgf.llnl.gov/) by supplying a [Dataset object](autoapi/ewatercycle/esmvaltool/models/index.html#ewatercycle.esmvaltool.models.Dataset) to the `ewatercycle.base.forcing.Defaultforcing.generate` method.
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)
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.