HydPy-Evap-PET-AMBAV-1.0 (potential evapotranspiration based on AMBAV 1.0)

evap_pet_ambav1 is a submodel that supplies its main model with estimates of potential evapotranspiration from soils and potential evaporation from interception storages and water areas. It closely follows version 1.0 of the AMBAV model, as described by Löpmeier (2014), which was developed and used by the German Meteorological Service (DWD) to calculate soil evapotranspiration and interception evaporation for different crops based on the Penman-Monteith equation. We added a routine for calculating evaporation from water areas based on the pure Penman equation. The MORSIM/AMBAV issue on GitHub discusses this and other decisions in detail. We implemented evap_pet_ambav1 on behalf of the German Federal Institute of Hydrology (BfG) for modelling large river basins in central Europe.

evap_pet_ambav1 requires additional data about the catchment’s current state, which it usually queries from its main model, if possible:

  • The current air temperature.

  • The current precipitation.

  • The snow cover degree.

Additionally, evap_pet_ambav1 requires radiation-related data (potential sunshine duration, actual sunshine duration, and global radiation) that must be supplied by a “real” submodel that complies with the RadiationModel_V1 or the RadiationModel_V4 interface.

Integration tests

Note

When new to HydPy, consider reading section Integration Tests first.

The design of the following integration tests is similar to the one chosen for evap_aet_morsim to ease the comparison of both models.

We prepare a simulation period of three days for the first examples:

>>> from hydpy import pub
>>> pub.timegrids = "2000-08-01", "2000-08-04", "1d"

According to the intended usage as a submodel, evap_pet_ambav1 requires no connections to any nodes. Hence, assigning a model instance to a blank Element instance is sufficient:

>>> from hydpy import Element
>>> from hydpy.models.evap_pet_ambav1 import *
>>> parameterstep("1h")
>>> element = Element("element")
>>> element.model = model

The following parameter settings are comparable to the ones selected for evap_aet_morsim:

>>> nmbhru(1)
>>> hrutype(0)
>>> measuringheightwindspeed(10.0)
>>> leafalbedo(0.2)
>>> leafalbedosnow(0.8)
>>> groundalbedo(0.2)
>>> groundalbedosnow(0.8)
>>> leafareaindex(5.0)
>>> cropheight(10.0)
>>> leafresistance(40.0)

The following parameters have no direct equivalents in evap_aet_morsim:

>>> wetsoilresistance(100.0)
>>> soilresistanceincrease(1.0)
>>> wetnessthreshold(0.5)
>>> cloudtypefactor(0.2)
>>> nightcloudfactor(1.0)

We add submodels of type meteo_temp_io, meteo_precip_io, meteo_psun_sun_glob_io, and dummy_snowcover that supply additional information on the catchment’s state instead of complicating the comparisons by introducing complex main or submodels:

>>> with model.add_tempmodel_v2("meteo_temp_io"):
...     hruarea(1.0)
...     temperatureaddend(0.0)
>>> with model.add_precipmodel_v2("meteo_precip_io"):
...     hruarea(1.0)
...     precipitationfactor(1.0)
>>> with model.add_radiationmodel_v4("meteo_psun_sun_glob_io"):
...     pass
>>> with model.add_snowcovermodel_v1("dummy_snowcover"):
...     pass

Now, we can initialise an IntegrationTest object:

>>> from hydpy import IntegrationTest
>>> test = IntegrationTest(element)
>>> test.dateformat = "%d/%m"

The following meteorological input and snow cover data also agree with the first evap_aet_morsim examples:

>>> inputs.windspeed.series = 2.0
>>> inputs.relativehumidity.series = 80.0
>>> inputs.atmosphericpressure.series = 1000.0
>>> model.tempmodel.sequences.inputs.temperature.series = 15.0
>>> model.radiationmodel.sequences.inputs.sunshineduration.series = 6.0
>>> model.radiationmodel.sequences.inputs.possiblesunshineduration.series = 16.0
>>> model.radiationmodel.sequences.inputs.globalradiation.series = 190.0
>>> model.snowcovermodel.sequences.inputs.snowcover.series = 0.0

Only evap_pet_ambav1 requires precipitation data to simulate the wetness of the topmost soil layer for adjusting the soil surface’s albedo and resistance. We define precipitation to occur on the second day:

>>> model.precipmodel.sequences.inputs.precipitation.series = 0.0, 10.0, 0.0

In contrast to evap_aet_morsim, evap_pet_ambav1 even requires logged values when applied on daily timesteps to keep track of the temporal persistency of the topmost soil layer’s wetness:

>>> test.inits = ((states.soilresistance, 100.0),
...               (logs.loggedprecipitation, [0.0]),
...               (logs.loggedpotentialsoilevapotranspiration, [1.0]))

vegetation

The following configuration corresponds to the non-tree vegetation, deciduous trees, and conifers examples of evap_aet_morsim because evap_pet_ambav1 does not handle different kinds of vegetation distinctly:

>>> interception(True)
>>> soil(True)
>>> plant(True)
>>> water(False)

In the evap_aet_morsim examples, the resulting soil evapotranspiration values differ due to different amounts of intercepted water. In contrast, evap_pet_ambav1 calculates only potential values and thus does not consider storage contents. The differences between the individual days stem from the changing topmost soil layer’s wetness. In this context, note that the precipitation event of the second day only affects the results of the third day and later:

>>> test()
Click to see the table

water area

Switching from vegetated soil to an open water area requires setting the crop height to zero:

>>> interception(False)
>>> soil(False)
>>> plant(False)
>>> water(True)
>>> cropheight(0.0)

While evap_aet_morsim estimates an evaporation rate of 3.2 mm/day in the water area example, evap_pet_ambav1 estimates only 1.9 mm/day:

>>> test()
Click to see the table

snow

Now, we demonstrate the effect of snow on potential evapotranspiration from land areas by setting different snow cover degrees:

>>> interception(True)
>>> soil(True)
>>> plant(True)
>>> water(False)
>>> cropheight(10.0)
>>> model.snowcovermodel.sequences.inputs.snowcover.series = [0.0], [0.5], [1.0]

We set all precipitation values to 10 mm to focus only on the influence of the snow cover:

>>> model.precipmodel.sequences.inputs.precipitation.series = 10.0
>>> test.inits.loggedprecipitation = 10.0

In contrast to evap_aet_morsim, as discussed in the snow on non-tree vegetation example, evap_pet_ambav1 never suppresses evapotranspiration completely but adjusts the current albedo to the given snow-specific values, which are usually larger than those of the leaf and soil surfaces and so usually reduces evapotranspiration:

>>> test()
Click to see the table

hourly simulation, land

The following examples deal with an hourly simulation step:

>>> pub.timegrids = "2000-08-03", "2000-08-04", "1h"

We need to restore the values of all time-dependent parameters:

>>> for parameter in model.parameters.fixed:
...     parameter.restore()

As in the hourly simulation, land example, we switch to using meteo_glob_morsim instead of meteo_psun_sun_glob_io to gain the radiation-related data:

>>> with model.add_radiationmodel_v1("meteo_glob_morsim"):
...     latitude(54.1)
...     longitude(9.7)
...     angstromconstant(0.25)
...     angstromfactor(0.5)
...     angstromalternative(0.15)
>>> test = IntegrationTest(element)

The following meteorological input data also agree with the hourly simulation, land example of evap_aet_morsim:

>>> inputs.atmosphericpressure.series = (
...     1015.0, 1015.0, 1015.0, 1015.0, 1015.0, 1015.0, 1015.0, 1015.0, 1016.0, 1016.0,
...     1016.0, 1016.0, 1016.0, 1016.0, 1016.0, 1016.0, 1016.0, 1016.0, 1016.0, 1016.0,
...     1016.0, 1016.0, 1017.0, 1017.0)
>>> inputs.windspeed.series = (
...     0.8, 0.8, 0.8, 0.8, 0.8, 0.6, 0.9, 0.9, 0.9, 1.3, 1.5, 1.2, 1.3, 1.5, 1.9, 1.9,
...     2.3, 2.4, 2.5, 2.5, 2.2, 1.7, 1.7, 2.3)
>>> inputs.relativehumidity.series = (
...     95.1, 94.9, 95.9, 96.7, 97.2, 97.5, 97.7, 97.4, 96.8, 86.1, 76.8, 71.8, 67.5,
...     66.1, 63.4, 62.4, 61.1, 62.1, 67.0, 74.5, 81.2, 86.9, 90.1, 90.9)
>>> model.radiationmodel.sequences.inputs.sunshineduration.series = (
...     0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.2, 0.5, 0.7, 0.8, 0.5, 0.4, 0.5,
...     0.5, 0.3, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0)

In contrast to evap_aet_morsim, evap_pet_ambav1 does not require “daily” averages or sums of meteorological input data but calculates, e.g., hourly water area evaporation values and aggregates them to daily values later. But it needs to remember the last determined cloud coverage degree (which is only estimateable at daytime) and other factors related to the topmost soil layer’s wetness calculations:

>>> test.inits = (
...     (states.soilresistance, 100.0),
...     (states.cloudcoverage, 0.3),
...     (logs.loggedprecipitation, 0.0),
...     (logs.loggedwaterevaporation, 0.0),
...     (logs.loggedpotentialsoilevapotranspiration, 0.0),
...     (model.radiationmodel.sequences.logs.loggedsunshineduration,
...      [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.2, 0.1, 0.2, 0.1, 0.2, 0.2, 0.3, 0.0,
...       0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]),
...     (model.radiationmodel.sequences.logs.loggedunadjustedglobalradiation,
...      [0.0, 0.0, 0.0, 0.0, 0.0, 27.777778, 55.555556, 138.888889, 222.222222,
...       305.555556, 333.333333, 388.888889, 527.777778, 444.444444, 250.0,
...       222.222222, 166.666667, 111.111111, 55.555556, 27.777778, 0.0, 0.0, 0.0,
...       0.0]))

The contrived day is warm, free of snow and rain:

>>> model.tempmodel.sequences.inputs.temperature.series = (
...     16.9, 16.6, 16.4, 16.3, 16.0, 15.9, 16.0, 16.6, 17.4, 19.0, 20.3, 21.4, 21.3,
...     21.8, 22.9, 22.7, 22.5, 21.9, 21.4, 20.7, 19.4, 17.8, 17.0, 16.4)
>>> model.snowcovermodel.sequences.inputs.snowcover.series = 0.0
>>> model.precipmodel.sequences.inputs.precipitation.series = 0.0

Considering the hourly simulation, land example, evap_pet_ambav1 estimates higher potential interception evaporation rates and potential soil evapotranspiration rates that are (as to be expected) higher but roughly comparable to the actual soil evapotranspiration rates of evap_aet_morsim:

>>> test("evap_pet_ambav1_hourly_simulation_land",
...      axis1=(fluxes.potentialinterceptionevaporation,
...             fluxes.potentialsoilevapotranspiration))
Click to see the table
Click to see the graph

hourly simulation, water

evap_pet_ambav1 also calculates hourly water evaporation values, which show a clear diurnal pattern not apparent in the generally aggregated water evaporation values of evap_aet_morsim in example hourly simulation, water:

>>> test.inits.loggedwaterevaporation = 0.1
>>> interception(False)
>>> soil(False)
>>> plant(False)
>>> water(True)
>>> cropheight(0.0)
>>> test("evap_pet_ambav1_hourly_simulation_water",
...      axis1=(fluxes.waterevaporation, fluxes.dailywaterevaporation))
Click to see the table
Click to see the graph
class hydpy.models.evap_pet_ambav1.Model[source]

Bases: Main_TempModel_V1, Main_TempModel_V2B, Main_PrecipModel_V1, Main_PrecipModel_V2B, Main_RadiationModel_V1, Main_RadiationModel_V4, Main_SnowCoverModel_V1, Sub_ETModel, PETModel_V2

HydPy-Evap-PET-AMBAV-1.0 (potential evapotranspiration based on AMBAV 1.0).

The following “run methods” are called in the given sequence during each simulation step:
The following interface methods are available to main models using the defined model as a submodel:
The following “additional methods” might be called by one or more of the other methods or are meant to be directly called by the user:
Users can hook submodels into the defined main model if they satisfy one of the following interfaces:
  • TempModel_V1 Pure getter interface for using main models as sub-submodels.

  • TempModel_V2 Simple interface for determining the temperature in one step.

  • PrecipModel_V1 Pure getter interface for using main models as sub-submodels.

  • PrecipModel_V2 Simple interface for determining precipitation in one step.

  • RadiationModel_V1 Simple interface for determining all data in one step.

  • RadiationModel_V4 Pure getter interface for possible sunshine duration, actual sunshine duration, and global radiation.

  • SnowCoverModel_V1 Pure getter interface for using main models as sub-submodels or simple dummy models as submodels for querying the snow cover degree.

DOCNAME: DocName = ('Evap-PET-AMBAV-1.0', 'potential evapotranspiration based on AMBAV 1.0')
tempmodel: SubmodelProperty

Required submodel that complies with one of the following interfaces: TempModel_V1 or TempModel_V2.

precipmodel: modeltools.SubmodelProperty

Required submodel that complies with one of the following interfaces: PrecipModel_V1 or PrecipModel_V2.

radiationmodel: modeltools.SubmodelProperty

Required submodel that complies with one of the following interfaces: RadiationModel_V1 or RadiationModel_V4.

snowcovermodel: modeltools.SubmodelProperty

Required submodel that complies with the following interface: SnowCoverModel_V1.

REUSABLE_METHODS: ClassVar[tuple[type[ReusableMethod], ...]] = ()
preparemethod2arguments: dict[str, tuple[tuple[Any, ...], dict[str, Any]]]
cymodel: CyModelProtocol | None
parameters: parametertools.Parameters
sequences: sequencetools.Sequences
masks: masktools.Masks
class hydpy.models.evap_pet_ambav1.ControlParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)

Bases: SubParameters

Control parameters of model evap_pet_ambav1.

The following classes are selected:
  • NmbHRU() The number of separately modelled hydrological response units [-].

  • HRUType() Hydrological response unit type [-].

  • Water() A flag that indicates whether the individual zones are water areas or not.

  • Interception() A flag that indicates whether interception evaporation is relevant for the individual zones.

  • Soil() A flag that indicates whether soil evapotranspiration is relevant for the individual zones.

  • Plant() A flag that indicates whether the individual zones contain any vegetation.

  • MeasuringHeightWindSpeed() The height above ground of the wind speed measurements [m].

  • GroundAlbedo() The albedo of the snow-free ground (including soils, sealed surfaces, and water areas) [-].

  • GroundAlbedoSnow() The albedo of the snow-covered ground (including soils and sealed surfaces) [-].

  • LeafAlbedo() The albedo of the snow-free leaves [-].

  • LeafAlbedoSnow() The albedo of the snow-covered leaves [-].

  • LeafAreaIndex() Leaf area index [-].

  • CropHeight() Crop height [m].

  • CloudTypeFactor() Cloud type-specific factor for calculating atmospheric longwave counter radiation [-].

  • NightCloudFactor() Factor for adjusting daytime estimates of the cloud coverage degree to nighttime [-].

  • WetSoilResistance() Surface resistance of wet soils [s/m].

  • SoilResistanceIncrease() Increase in soil surface resistance if evaporation dominates precipitation [s/m/T].

  • WetnessThreshold() The ratio between precipitation and potential evapotranspiration above which the topmost soil layer becomes wet [-].

  • LeafResistance() Surface resistance of plant leaves [s/m].

class hydpy.models.evap_pet_ambav1.DerivedParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)

Bases: SubParameters

Derived parameters of model evap_pet_ambav1.

The following classes are selected:
  • MOY() References the “global” month of the year index array [-].

  • Hours() The length of the actual simulation step size in hours [h].

  • Days() The length of the actual simulation step size in days [d].

  • NmbLogEntries() The number of log entries required for a memory duration of 24 hours [-].

  • RoughnessLength() Roughness length [m].

  • AerodynamicResistanceFactor() Factor for calculating aerodynamic resistance [-].

class hydpy.models.evap_pet_ambav1.FactorSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)

Bases: FactorSequences

Factor sequences of model evap_pet_ambav1.

The following classes are selected:
class hydpy.models.evap_pet_ambav1.FixedParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)

Bases: SubParameters

Fixed parameters of model evap_pet_ambav1.

The following classes are selected:
class hydpy.models.evap_pet_ambav1.FluxSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)

Bases: FluxSequences

Flux sequences of model evap_pet_ambav1.

The following classes are selected:
class hydpy.models.evap_pet_ambav1.InputSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)

Bases: InputSequences

Input sequences of model evap_pet_ambav1.

The following classes are selected:
class hydpy.models.evap_pet_ambav1.LogSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)

Bases: LogSequences

Log sequences of model evap_pet_ambav1.

The following classes are selected:
class hydpy.models.evap_pet_ambav1.StateSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)

Bases: StateSequences

State sequences of model evap_pet_ambav1.

The following classes are selected: