ewatercycle.base.forcing

Base classes for eWaterCycle forcings.

Configuring ESMValTool

To download data from ESFG via ESMValTool you will need a ~/.esmvaltool/config-user.yml file with something like:

search_esgf: when_missing
download_dir: ~/climate_data
rootpath:
    CMIP6: ~/climate_data/CMIP6
drs:
    CMIP6: ESGF

A config file can be generated with:

esmvaltool config get-config-user

See ESMValTool configuring docs for more information.

Module Contents

ewatercycle.base.forcing.logger
ewatercycle.base.forcing.FORCING_YAML = 'ewatercycle_forcing.yaml'
ewatercycle.base.forcing.AnyForcing
ewatercycle.base.forcing.Postprocessor: TypeAlias
class ewatercycle.base.forcing.DefaultForcing

Bases: pydantic.BaseModel

Container for forcing data.

Parameters:
  • directory – Directory where forcing data files are stored.

  • start_time – Start time of forcing in UTC and ISO format string e.g. ‘YYYY-MM-DDTHH:MM:SSZ’.

  • end_time – End time of forcing in UTC and ISO format string e.g. ‘YYYY-MM-DDTHH:MM:SSZ’.

  • shape – Path to a shape file. Used for spatial selection. If relative then it is relative to the given directory.

  • filenames – Dictionary of the variables contained in this forcing object, as well as the file names. Default value is empty, for backwards compatibility.

start_time: str
end_time: str
directory: Annotated[pathlib.Path, AfterValidator(_to_absolute_path)]
shape: pathlib.Path | None
filenames: dict[str, str]
classmethod generate(dataset: str | ewatercycle.esmvaltool.schema.Dataset | dict, start_time: str, end_time: str, shape: str | pathlib.Path, directory: str | None = None, variables: tuple[str, Ellipsis] = (), postprocessor: Postprocessor | None = None, **model_specific_options) AnyForcing

Generate forcings for a model.

The forcing is generated with help of ESMValTool.

Parameters:
  • dataset – Dataset to get forcing data from. When string is given a predefined dataset is looked up in ewatercycle.esmvaltool.datasets.DATASETS. When dict given it is passed to ewatercycle.esmvaltool.models.Dataset constructor.

  • start_time – Start time of forcing in UTC and ISO format string e.g. ‘YYYY-MM-DDTHH:MM:SSZ’.

  • end_time – nd time of forcing in UTC and ISO format string e.g. ‘YYYY-MM-DDTHH:MM:SSZ’.

  • shape – Path to a shape file. Used for spatial selection.

  • directory – Directory in which forcing should be written. If not given will create timestamped directory.

  • variables – Variables which need to be downloaded/preprocessed by ESMValTool.

  • postprocessor – A custom post-processor that can, e.g., derive additional variables based on the ESMValTool recipe output. Must return the names & filenames of the variables it derived.

save()

Export forcing data for later use.

classmethod load(directory: str | pathlib.Path)

Load previously generated or imported forcing data.

Parameters:

directory – forcing data directory; must contain ewatercycle_forcing.yaml file

Returns: Forcing object

to_xarray() xarray.Dataset

Return this Forcing object as an xarray Dataset.

variables() tuple[str, Ellipsis]

Return the names of the variables. Shorthand for self.filenames.keys()

class ewatercycle.base.forcing.DistributedUserForcing

Bases: DefaultForcing

Forcing object with user-specified downloaded variables and postprocessing.

Examples:

To generate forcing from ERA5 for the Rhine catchment for 2000-2001, retrieving the ‘pr’, ‘tas’ and ‘rsds’ variables, and applying the Makkink evaporation postprocessor.

from pathlib import Path
from rich import print
from ewatercycle.base.forcing import DistributedUserForcing

cmip_dataset = {
    "dataset": "EC-Earth3",
    "project": "CMIP6",
    "grid": "gr",
    "exp": "historical",
    "ensemble": "r6i1p1f1",
}
shape = Path("./src/ewatercycle/testing/data/Rhine/Rhine.shp")
forcing = DistributedUserForcing.generate(
    dataset=cmip_dataset,
    start_time='2000-01-01T00:00:00Z',
    end_time='2001-01-01T00:00:00Z',
    shape=str(shape.absolute()),
    variables=("pr", "tas"),
)
print(forcing)

Gives something like:

DistributedUserForcing(
    start_time='2000-01-01T00:00:00Z',
    end_time='2001-01-01T00:00:00Z',
    directory=PosixPath('/home/bart/esmvaltool_output/ewcrepvl1jeunb_20240305_131155/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'
    }
)
class ewatercycle.base.forcing.LumpedUserForcing

Bases: DistributedUserForcing

Forcing object with user-specified downloaded variables and postprocessing.

Examples:

To generate lumped forcing from ERA5 for the Rhine catchment for 2000-2001, retrieving the ‘pr’, ‘tas’ and ‘rsds’ variables, and applying the Makkink evaporation postprocessor.

from pathlib import Path
from rich import print
from ewatercycle.base.forcing import LumpedUserForcing

cmip_dataset = {
    "dataset": "EC-Earth3",
    "project": "CMIP6",
    "grid": "gr",
    "exp": "historical",
    "ensemble": "r6i1p1f1",
}
shape = Path("./src/ewatercycle/testing/data/Rhine/Rhine.shp")
forcing = LumpedUserForcing.generate(
    dataset=cmip_dataset,
    start_time='2000-01-01T00:00:00Z',
    end_time='2001-01-01T00:00:00Z',
    shape=str(shape.absolute()),
    variables=("pr", "tas"),
)
print(forcing)

Gives something like:

LumpedUserForcing(
    start_time='2000-01-01T00:00:00Z',
    end_time='2001-01-01T00:00:00Z',
    directory=PosixPath('/home/bart/esmvaltool_output/ewcrepvl1jeunb_20240305_131155/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'
    }
)
class ewatercycle.base.forcing.GenericDistributedForcing

Bases: _GenericForcing, DistributedUserForcing

Generic forcing data for a distributed model.

Examples

To generate forcing from ERA5 for the Rhine catchment for 2000-2001:

from pathlib import Path
from rich import print
from ewatercycle.base.forcing import GenericDistributedForcing

shape = Path("./src/ewatercycle/testing/data/Rhine/Rhine.shp")
forcing = GenericDistributedForcing.generate(
    dataset='ERA5',
    start_time='2000-01-01T00:00:00Z',
    end_time='2001-01-01T00:00:00Z',
    shape=shape.absolute(),
)
print(forcing)

Gives something like:

GenericDistributedForcing(
    model='generic_distributed',
    start_time='2000-01-01T00:00:00Z',
    end_time='2001-01-01T00:00:00Z',
    directory=PosixPath('/home/verhoes/git/eWaterCycle/ewatercycle/esmvaltool_output/tmp05upitxoewcrep_20230815_154640/work/diagnostic/script'),
    shape=PosixPath('/home/verhoes/git/eWaterCycle/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',
    }
)

To generate forcing from CMIP6 for the Rhine catchment for 2000-2001 (make sure ESMValTool is configured correctly):

from pathlib import Path
from rich import print
from ewatercycle.base.forcing import GenericDistributedForcing

shape = Path("./src/ewatercycle/testing/data/Rhine/Rhine.shp")
cmip_dataset = {
    "dataset": "EC-Earth3",
    "project": "CMIP6",
    "grid": "gr",
    "exp": ["historical",],
    "ensemble": "r6i1p1f1",
}

forcing = GenericDistributedForcing.generate(
    dataset=cmip_dataset,
    start_time="2000-01-01T00:00:00Z",
    end_time="2001-01-01T00:00:00Z",
    shape=shape.absolute(),
)
print(forcing)

Gives something like:

GenericDistributedForcing(
    start_time='2000-01-01T00:00:00Z',
    end_time='2001-01-01T00:00:00Z',
    directory=PosixPath('/home/verhoes/git/eWaterCycle/ewatercycle/esmvaltool_output/ewcrep0ibzlds__20230904_082748/work/diagnostic/script'),
    shape=PosixPath('/home/verhoes/git/eWaterCycle/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',
    }
)
class ewatercycle.base.forcing.GenericLumpedForcing

Bases: _GenericForcing, LumpedUserForcing

Generic forcing data for a lumped model.

Example

To generate forcing from ERA5 for the Rhine catchment for 2000-2001:

from pathlib import Path
from rich import print
from ewatercycle.base.forcing import GenericLumpedForcing

shape = Path("./src/ewatercycle/testing/data/Rhine/Rhine.shp")
forcing = GenericLumpedForcing.generate(
    dataset='ERA5',
    start_time='2000-01-01T00:00:00Z',
    end_time='2001-01-01T00:00:00Z',
    shape=shape.absolute(),
)
print(forcing)

Gives something like:

GenericLumpedForcing(
    model='generic_distributed',
    start_time='2000-01-01T00:00:00Z',
    end_time='2001-01-01T00:00:00Z',
    directory=PosixPath('/home/verhoes/git/eWaterCycle/ewatercycle/esmvaltool_output/ewcrep90hmnvat_20230816_124951/work/diagnostic/script'),
    shape=PosixPath('/home/verhoes/git/eWaterCycle/ewatercycle/src/ewatercycle/testing/data/Rhine/Rhine.shp'),
    pr='OBS6_ERA5_reanaly_1_day_pr_2000-2001.nc',
    tas='OBS6_ERA5_reanaly_1_day_tas_2000-2001.nc',
    tasmin='OBS6_ERA5_reanaly_1_day_tasmin_2000-2001.nc',
    tasmax='OBS6_ERA5_reanaly_1_day_tasmax_2000-2001.nc'
)

To generate forcing from CMIP6 for the Rhine catchment for 2000-2001 (make sure ESMValTool is configured correctly):

from pathlib import Path
from rich import print
from ewatercycle.base.forcing import GenericLumpedForcing

shape = Path("./src/ewatercycle/testing/data/Rhine/Rhine.shp")
cmip_dataset = {
    "dataset": "EC-Earth3",
    "project": "CMIP6",
    "grid": "gr",
    "exp": ["historical",],
    "ensemble": "r6i1p1f1",
}

forcing = GenericLumpedForcing.generate(
    dataset=cmip_dataset,
    start_time="2000-01-01T00:00:00Z",
    end_time="2001-01-01T00:00:00Z",
    shape=shape.absolute(),
)
print(forcing)