HydPy-GA (base model)

The HydPy-GA base model provides features to implement infiltration methods based on Green & Ampt-like wetting fronts.

Method Features

class hydpy.models.ga.ga_model.Model[source]

Bases: AdHocModel

HydPy-GA (base model).

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:
DOCNAME: DocName = ('GA', 'base model')
REUSABLE_METHODS: ClassVar[tuple[type[ReusableMethod], ...]] = ()
class hydpy.models.ga.ga_model.Calc_SurfaceWaterSupply_V1[source]

Bases: Method

Take rainfall as the possible supply for infiltration through the soil’s surface.

Requires the control parameter:

NmbSoils

Requires the input sequence:

Rainfall

Calculates the flux sequence:

SurfaceWaterSupply

Basic equation:

\(SurfaceWaterSupply = Rainfall\)

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> inputs.rainfall = 2.0
>>> model.calc_surfacewatersupply_v1()
>>> fluxes.surfacewatersupply
surfacewatersupply(2.0, 2.0)
class hydpy.models.ga.ga_model.Calc_SoilWaterSupply_V1[source]

Bases: Method

Take capillary rise as the possible supply for water additions through the soil’s bottom.

Requires the control parameter:

NmbSoils

Requires the input sequence:

CapillaryRise

Calculates the flux sequence:

SoilWaterSupply

Basic equation:

\(SoilWaterSupply = CapillaryRise\)

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> inputs.capillaryrise = 2.0
>>> model.calc_soilwatersupply_v1()
>>> fluxes.soilwatersupply
soilwatersupply(2.0, 2.0)
class hydpy.models.ga.ga_model.Calc_Demand_V1[source]

Bases: Method

Take evaporation as the demand for extracting water from the soil’s surface and

body.

Requires the control parameter:

NmbSoils

Requires the input sequence:

Evaporation

Calculates the flux sequence:

Demand

Basic equation:

\(Demand = Evaporation\)

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> inputs.evaporation = 2.0
>>> model.calc_demand_v1()
>>> fluxes.demand
demand(2.0, 2.0)
class hydpy.models.ga.ga_model.Return_RelativeMoisture_V1[source]

Bases: Method

Calculate and return the relative soil water content for the given bin-soil combination.

Required by the methods:

Infiltrate_WettingFrontBins_V1 Percolate_FilledBin_V1 Redistribute_Front_V1 Return_CapillaryDrive_V1 Return_Conductivity_V1 Shift_Front_V1

Requires the control parameters:

ResidualMoisture SaturationMoisture

Requires the state sequence:

Moisture

Basic equation (Lai et al. (2015), equation 11):

\(RelativeMoisture = \frac{FrontMoisture - ResidualMoisture}{SaturationMoisture - ResidualMoisture}\)

Method Return_RelativeMoisture_V1 prevents returning values smaller than zero or larger than one that might arise due to violations of the residualor saturation water content.

Examples:

>>> from hydpy.models.ga import *
>>> simulationstep("1h")
>>> parameterstep("1h")
>>> nmbsoils(2)
>>> nmbbins(5)
>>> residualmoisture(0.1, 0.2)
>>> saturationmoisture(0.5, 0.8)
>>> states.moisture = [[0.0, 0.0],
...                    [0.1, 0.2],
...                    [0.3, 0.65],
...                    [0.5, 0.8],
...                    [1.0, 1.0]]
>>> from hydpy import round_
>>> for soil in range(2):
...     for bin_ in range(5):
...         print(f"soil: {soil}, bin: {bin_} -> relativemoisture ", end="")
...         round_(model.return_relativemoisture_v1(bin_, soil))
soil: 0, bin: 0 -> relativemoisture 0.0
soil: 0, bin: 1 -> relativemoisture 0.0
soil: 0, bin: 2 -> relativemoisture 0.5
soil: 0, bin: 3 -> relativemoisture 1.0
soil: 0, bin: 4 -> relativemoisture 1.0
soil: 1, bin: 0 -> relativemoisture 0.0
soil: 1, bin: 1 -> relativemoisture 0.0
soil: 1, bin: 2 -> relativemoisture 0.75
soil: 1, bin: 3 -> relativemoisture 1.0
soil: 1, bin: 4 -> relativemoisture 1.0
class hydpy.models.ga.ga_model.Return_Conductivity_V1[source]

Bases: Method

Based on the Brooks-Corey soil moisture characteristic model (Brooks and Corey, 1966), calculate and return the conductivity for the given bin-soil combination.

Required by the methods:

Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Percolate_FilledBin_V1 Perform_GARTO_V1 Redistribute_Front_V1 Shift_Front_V1

Required submethod:

Return_RelativeMoisture_V1

Requires the control parameters:

ResidualMoisture SaturationMoisture SaturatedConductivity PoreSizeDistribution

Requires the state sequence:

Moisture

Basic equation (Lai et al. (2015), equation 11):

\(Conductivity = SaturatedConductivity \cdot RelativeMoisture^{3 + 2 / PoreSizeDistribution}\)

Examples:

>>> from hydpy.models.ga import *
>>> simulationstep("1h")
>>> parameterstep("1h")
>>> nmbsoils(2)
>>> nmbbins(3)
>>> residualmoisture(0.1, 0.2)
>>> saturationmoisture(0.5, 0.8)
>>> poresizedistribution(0.3, 0.4)
>>> saturatedconductivity(10.0, 20.0)
>>> states.moisture = [[0.1, 0.0],
...                    [0.3, 0.5],
...                    [0.5, 1.0]]
>>> from hydpy import round_
>>> for soil in range(2):
...     for bin_ in range(3):
...         print(f"soil: {soil}, bin: {bin_} -> conductivity ", end="")
...         round_(model.return_conductivity_v1(bin_, soil))
soil: 0, bin: 0 -> conductivity 0.0
soil: 0, bin: 1 -> conductivity 0.012304
soil: 0, bin: 2 -> conductivity 10.0
soil: 1, bin: 0 -> conductivity 0.0
soil: 1, bin: 1 -> conductivity 0.078125
soil: 1, bin: 2 -> conductivity 20.0
class hydpy.models.ga.ga_model.Return_CapillaryDrive_V1[source]

Bases: Method

Based on the Brooks-Corey soil moisture characteristic model (Brooks and Corey, 1966), calculate and return the capillary drive between the water contents of the given bins for the defined soil.

Required by the methods:

Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Perform_GARTO_V1 Redistribute_Front_V1 Shift_Front_V1

Required submethod:

Return_RelativeMoisture_V1

Requires the control parameters:

ResidualMoisture SaturationMoisture AirEntryPotential PoreSizeDistribution

Requires the state sequence:

Moisture

Basic equation (Lai et al. (2015), equation 11):

\(CapillaryDrive_{bin1,bin2} = \frac{AirEntryPotential}{3 \cdot PoreSizeDistribution + 1} \cdot \begin{cases} RelativeMoisture_{bin2}^{3 + 1 / PoreSizeDistribution} - RelativeMoisture_{bin1}^{3 + 1 / PoreSizeDistribution} &|\ Moisture_{bin2} < SaturationMoisture \\ 3 \cdot PoreSizeDistribution + 2 - RelativeMoisture_{bin1}^{3 + 1 / PoreSizeDistribution} &|\ Moisture_{bin2} = SaturationMoisture \end{cases}\)

Examples:

>>> from hydpy.models.ga import *
>>> simulationstep("1h")
>>> parameterstep("1h")
>>> nmbsoils(2)
>>> nmbbins(3)
>>> residualmoisture(0.1, 0.2)
>>> saturationmoisture(0.5, 0.8)
>>> airentrypotential(0.1, 0.2)
>>> poresizedistribution(0.3, 0.4)
>>> saturatedconductivity(10.0, 20.0)
>>> states.moisture = [[0.1, 0.0],
...                    [0.3, 0.5],
...                    [0.5, 1.0]]
>>> from hydpy import round_
>>> for soil in range(2):
...     for bin_ in range(2):
...         print(f"soil: {soil}, bin: {bin_} -> capillarydrive ", end="")
...         round_(model.return_capillarydrive_v1(bin_, bin_ + 1, soil))
soil: 0, bin: 0 -> capillarydrive 0.000653
soil: 0, bin: 1 -> capillarydrive 0.151979
soil: 1, bin: 0 -> capillarydrive 0.002009
soil: 1, bin: 1 -> capillarydrive 0.2889
class hydpy.models.ga.ga_model.Percolate_FilledBin_V1[source]

Bases: Method

Calculate the percolation of water through the filled first bin due to gravitational forcing.

Required by the methods:

Execute_Infiltration_V1 Perform_GARTO_V1

Required submethods:

Return_RelativeMoisture_V1 Return_Conductivity_V1

Requires the control parameters:

DT SoilDepth ResidualMoisture SaturationMoisture SaturatedConductivity PoreSizeDistribution

Requires the state sequence:

Moisture

Updates the flux sequence:

Percolation

Updates the state sequence:

FrontDepth

Updates the aide sequence:

ActualSurfaceWater

Basic equation:

\(Percolation = DT \cdot Conductivity\)

Example:

For simplicity, we make each soil compartment’s first (and only) bin saturated so that actual conductivity equals saturated conductivity:

>>> from hydpy.models.ga import *
>>> simulationstep("1h")
>>> parameterstep("1h")
>>> nmbsoils(3)
>>> nmbbins(2)
>>> dt(0.5)
>>> soildepth(100.0, 200.0, 300.0)
>>> residualmoisture(0.1)
>>> saturationmoisture(0.5)
>>> poresizedistribution(0.3)
>>> saturatedconductivity(6.0, 8.0, 10.0)
>>> states.moisture = 0.5
>>> aides.actualsurfacewater = 2.0, 4.0, 6.0
>>> fluxes.percolation = 1.0
>>> for soil in range(3):
...     model.percolate_filledbin_v1(soil)
>>> aides.actualsurfacewater
actualsurfacewater(0.0, 0.0, 1.0)
>>> fluxes.percolation
percolation(3.0, 5.0, 6.0)

By the way, Percolate_FilledBin_V1 sets the first bin’s front depth to the respective soil compartment’s depth:

>>> states.frontdepth
frontdepth([[100.0, 200.0, 300.0],
            [nan, nan, nan]])
class hydpy.models.ga.ga_model.Return_DryDepth_V1[source]

Bases: Method

Calculate and return the “dry depth”.

Required by the methods:

Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Perform_GARTO_V1 Redistribute_Front_V1 Shift_Front_V1

Requires the control parameters:

DT SaturationMoisture SaturatedConductivity

Requires the derived parameter:

EffectiveCapillarySuction

Requires the state sequence:

Moisture

Basic equations (Lai et al. (2015), equation 7, modified, see issue 89):

:math:` frac{tau + sqrt{tau^2 + 4 cdot tau cdot EffectiveCapillarySuction}}{2}`

:math:` tau = DT cdot frac{SaturatedConductivity}{SaturationMoisture - FrontMoisture}`

Example:

>>> from hydpy.models.ga import *
>>> simulationstep("1h")
>>> parameterstep("1h")
>>> nmbsoils(3)
>>> nmbbins(2)
>>> dt(0.5)
>>> residualmoisture(0.1, 0.2, 0.2)
>>> saturationmoisture(0.5, 0.8, 0.8)
>>> poresizedistribution(0.3, 0.4, 0.4)
>>> saturatedconductivity(10.0, 20.0, 20.0)
>>> airentrypotential(0.1, 0.2, 0.2)
>>> derived.effectivecapillarysuction.update()
>>> states.moisture = [[0.3, 0.5, 0.8], [nan, nan, nan]]
>>> from hydpy import round_
>>> for soil in range(3):
...     round_(model.return_drydepth_v1(soil))
25.151711
33.621747
inf
class hydpy.models.ga.ga_model.Return_LastActiveBin_V1[source]

Bases: Method

Find the index of the last active bin (that either contains a wetting front or uniform moisture over the complete soil depth).

Required by the methods:

Execute_Infiltration_V1 Perform_GARTO_V1 Shift_Front_V1

Requires the control parameter:

NmbBins

Requires the state sequence:

Moisture

Example:

>>> from hydpy.models.ga import *
>>> simulationstep("1h")
>>> parameterstep("1h")
>>> nmbsoils(3)
>>> nmbbins(3)
>>> states.moisture = [[0.1, 0.1, 0.1],
...                    [0.1, 0.5, 0.5],
...                    [0.1, 1.0, 0.1]]
>>> for soil in range(3):
...     print(f"soil: {soil} -> bin: {model.return_lastactivebin_v1(soil)}")
soil: 0 -> bin: 0
soil: 1 -> bin: 2
soil: 2 -> bin: 1
class hydpy.models.ga.ga_model.Active_Bin_V1[source]

Bases: Method

Activate a bin to the right of the bin with the given index.

Required by the method:

Infiltrate_WettingFrontBins_V1

Requires the control parameters:

DT SoilDepth SaturationMoisture SaturatedConductivity

Requires the derived parameter:

EffectiveCapillarySuction

Updates the state sequences:

Moisture FrontDepth

Updates the log sequence:

MoistureChange

Updates the aide sequence:

ActualSurfaceWater

We need to activate another bin if the current last bin’s moisture decreases and rainfall intensity exceeds saturated conductivity.

Basic equations (related to Lai et al. (2015)):

\(MoistureChange_{bin+1} = \frac{ActualSurfaceWater - DT \cdot 2 \cdot Conductivity_{bin}}{DryDepth}\)

\(Moisture_{bin+1} = Moisture_{bin} + MoistureChange_{bin+1}\)

\(Infiltration_{bin+1} = DT \cdot SaturatedConductivity \cdot \left( \frac{EffectiveCapillarySuction}{DryDepth} + 1 \right)\)

\(FrontDepth_{bin+1} = \frac{Infiltration_{bin+1}}{MoistureChange_{bin+1}}\)

The calculation of infiltration and the new front depth follows equation 4 of Lai et al. (2015), except for using \(Moisture_{bin}\) instead of \(ResidualMoisture\) and \(Moisture_{bin+1}\) instead of \(SaturationMoisture\). Regarding the moisture change, Lai et al. (2015) does not seem to mention the given basic equation explicitly.

Examples:

Method Active_Bin_V1 is a little complicated, so we perform multiple test calculations considering different special cases. We use the following setting for all these test calculations.

>>> from hydpy.models.ga_garto import *
>>> simulationstep("1h")
>>> parameterstep("1h")
>>> nmbsoils(1)
>>> nmbbins(3)
>>> dt(0.25)
>>> sealed(False)
>>> soilarea(1.0)
>>> soildepth(1000.0)
>>> residualmoisture(0.1)
>>> saturationmoisture(0.5)
>>> airentrypotential(0.1)
>>> poresizedistribution(0.3)
>>> saturatedconductivity(10.0)
>>> derived.soilareafraction.update()
>>> derived.effectivecapillarysuction.update()

We define a test function that applies Active_Bin_V1 for a definable initial surface water depth. The function checks that the water volume remains unchanged, prints the moisture change, the resulting moisture state, and the depth of the new active front (as calculated by Active_Bin_V1), and additionally prints the related infiltration (which Active_Bin_V1 does not calculate on its own):

>>> from hydpy.core.objecttools import repr_, repr_values
>>> def check(actualsurfacewater):
...     states.moisture = [[0.1], [0.3], [0.1]]
...     states.frontdepth = [[1000.0], [500.0], [0.0]]
...     logs.moisturechange = [[nan], [-inf], [nan]]
...     aides.actualsurfacewater = actualsurfacewater
...     old_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
...     model.active_bin_v1(1, 0)
...     new_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
...     assert old_volume == new_volume
...     infiltration = actualsurfacewater - aides.actualsurfacewater[0]
...     print(f"moisturechange: {repr_values(logs.moisturechange[:, 0])}")
...     print(f"moisture: {repr_values(states.moisture[:, 0])}")
...     print(f"infiltration: {repr_(infiltration)}")
...     print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")

The first example deals with a moderate rainfall intensity (a relatively small surface water depth), where everything works as described by the basic equations defined above:

>>> check(actualsurfacewater=1.0)
moisturechange: nan, -inf, 0.155311
moisture: 0.1, 0.3, 0.455311
infiltration: 1.0
frontdepth: 1000.0, 500.0, 6.438686

For high rainfall intensities, the calculated moisture change could result in the actual moisture exceeding the saturation moisture. In such cases, Active_Bin_V1 corrects the moisture but leaves the moisture change as is:

ToDo: clip the moisture change?

>>> check(actualsurfacewater=5.0)
moisturechange: nan, -inf, 0.780401
moisture: 0.1, 0.3, 0.5
infiltration: 2.55963
frontdepth: 1000.0, 500.0, 12.798152

A particularity of method Active_Bin_V1 is to set the moisture change to its highest possible value if the original moisture change (following the basic equation) is negative. Such situations can arise when the pre-existing active fronts have already infiltrated a significant amount of the rainfall available for the given numerical timestep:

ToDo: set the moisture change to zero?

>>> check(actualsurfacewater=0.001)
moisturechange: nan, -inf, 0.2
moisture: 0.1, 0.3, 0.5
infiltration: 0.001
frontdepth: 1000.0, 500.0, 0.005

Even for zero remaining surface water, Active_Bin_V1 activates a bin and sets its moisture value to the saturation value (without calculating any infiltration):

>>> check(actualsurfacewater=0.0)
moisturechange: nan, -inf, 0.2
moisture: 0.1, 0.3, 0.5
infiltration: 0.0
frontdepth: 1000.0, 500.0, 0.0

A very special case is when the initially calculated moisture change (following the basic equation) is zero. Only then, Active_Bin_V1 refrains from activating another bin:

Active_Bin_V1 checks if the initially calculated moisture change (following the basic equation) is zero. Only then does it refrain from activating another bin:

>>> actualsurfacewater=control.dt * 2.0 * model.return_conductivity_v1(1, 0)
>>> check(actualsurfacewater=actualsurfacewater)
moisturechange: nan, -inf, 0.0
moisture: 0.1, 0.3, 0.1
infiltration: 0.0
frontdepth: 1000.0, 500.0, 0.0

The following two examples illustrate highly deviating ways of front activation around the “zero moisture change” case (the second example also shows that infiltration becomes restricted when the front depth would otherwise overshoot the soil depth):

>>> check(actualsurfacewater=actualsurfacewater-1e-5)
moisturechange: nan, -inf, 0.2
moisture: 0.1, 0.3, 0.5
infiltration: 0.006142
frontdepth: 1000.0, 500.0, 0.03071
>>> check(actualsurfacewater=actualsurfacewater+1e-5)
moisturechange: nan, -inf, 0.000002
moisture: 0.1, 0.3, 0.300002
infiltration: 0.001563
frontdepth: 1000.0, 500.0, 1000.0
class hydpy.models.ga.ga_model.Shift_Front_V1[source]

Bases: Method

Increase the selected bin’s wetting front depth without modifying its relative moisture following a variation of the Talbot-Ogden equation (Talbot and Ogden, 2008).

Required by the method:

Infiltrate_WettingFrontBins_V1

Required submethods:

Return_RelativeMoisture_V1 Return_LastActiveBin_V1 Return_DryDepth_V1 Return_Conductivity_V1 Return_CapillaryDrive_V1

Requires the control parameters:

DT NmbBins SoilDepth ResidualMoisture SaturationMoisture SaturatedConductivity AirEntryPotential PoreSizeDistribution

Requires the derived parameter:

EffectiveCapillarySuction

Requires the aide sequence:

InitialSurfaceWater

Updates the state sequences:

Moisture FrontDepth

Updates the log sequence:

MoistureChange

Updates the aide sequence:

ActualSurfaceWater

Method Shift_Front_V1 applies for active wetting front bins that are not the last active bin or that are saturated (Moisture equals SaturationMoisture). The latter holds only for periods with rainfall intensity exceeding saturated conductivity.

Basic equation (Lai et al. (2015), equation 8, modified):

\(FrontDepth_{bin, new} = FrontDepth_{bin, old} + DT \cdot \frac{Conductivity_{bin-1} - Conductivity_{bin}} {Moisture_{bin} - Moisture_{bin-1}} \cdot \left(1 + \frac{CapillaryDrive_{0, LastActiveBin} + InitialSurfaceWater}{FrontDepth_{bin}} \right)\)

Note the used equation deviates from equation 8 of Lai et al. (2015) in adding the initial surface water depth to the effective capillary drive, which increases infiltration. Using InitialSurfaceWater instead of ActualSurfaceWater assures the bin processing order does not affect the individual infiltration rates.

Examples:

For comparison, we perform the following examples similar to those of method Active_Bin_V1. The general setting is identical, except that we initialise one more bin:

>>> from hydpy.models.ga_garto import *
>>> simulationstep("1h")
>>> parameterstep("1h")
>>> nmbsoils(1)
>>> nmbbins(4)
>>> dt(0.25)
>>> sealed(False)
>>> soilarea(1.0)
>>> soildepth(1000.0)
>>> residualmoisture(0.1)
>>> saturationmoisture(0.5)
>>> airentrypotential(0.1)
>>> poresizedistribution(0.3)
>>> saturatedconductivity(10.0)
>>> derived.soilareafraction.update()
>>> derived.effectivecapillarysuction.update()

The test function also behaves similarly but allows for more modifications of the initial states, supports selecting the considered bin, and applies Shift_Front_V1 instead of Active_Bin_V1:

>>> from hydpy.core.objecttools import repr_, repr_values
>>> def check(
...         bin_, initialsurfacewater, actualsurfacewater, frontdepth, moisture
...     ):
...     states.moisture = [[m] for m in moisture]
...     states.frontdepth = [[fd] for fd in frontdepth]
...     logs.moisturechange = nan
...     aides.initialsurfacewater = initialsurfacewater
...     aides.actualsurfacewater = actualsurfacewater
...     old_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
...     model.shift_front_v1(bin_, 0)
...     new_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
...     assert old_volume == new_volume
...     infiltration = actualsurfacewater - aides.actualsurfacewater[0]
...     print(f"moisturechange: {repr_values(logs.moisturechange[:, 0])}")
...     print(f"moisture: {repr_values(states.moisture[:, 0])}")
...     print(f"infiltration: {repr_(infiltration)}")
...     print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")

Shift_Front_V1 is to be applied on non-last active wetting front bins and the last bin if it is saturated. We start with demonstrating its functionality for the latter case.

The first example is standard so far that the given basic equation applies without additional restrictions and initial and actual surface water depths are identical. 2.75 mm of the available surface water infiltrate and shift the wetting front by about 13.75 mm:

>>> check(bin_=2, initialsurfacewater=10.0, actualsurfacewater=10.0,
...       frontdepth=[1000.0, 500.0, 100.0, 0.0],
...       moisture=[0.1, 0.3, 0.5, 0.1])
moisturechange: nan, nan, nan, nan
moisture: 0.1, 0.3, 0.5, 0.1
infiltration: 2.750428
frontdepth: 1000.0, 500.0, 113.752138, 0.0

Next, we decrease the amount of available surface water to 1 mm but let the initial surface water depth at 10 mm. Thus, the potential infiltration stays as is, but the actual infiltration reduces to 1 mm (and the front shift to 5 mm):

>>> check(bin_=2, initialsurfacewater=10.0, actualsurfacewater=1.0,
...       frontdepth=[1000.0, 500.0, 100.0, 0.0],
...       moisture=[0.1, 0.3, 0.5, 0.1])
moisturechange: nan, nan, nan, nan
moisture: 0.1, 0.3, 0.5, 0.1
infiltration: 1.0
frontdepth: 1000.0, 500.0, 105.0, 0.0

For small or zero initial front depths, Shift_Front_V1 uses the method Return_DryDepth_V1 to advance the front instead of the basic equation:

>>> from hydpy import round_
>>> round_(model.return_drydepth_v1(0))
6.399076
>>> check(bin_=2, initialsurfacewater=10.0, actualsurfacewater=10.0,
...       frontdepth=[1000.0, 500.0, 0.0, 0.0],
...       moisture=[0.1, 0.3, 0.5, 0.1])
moisturechange: nan, nan, nan, nan
moisture: 0.1, 0.3, 0.5, 0.1
infiltration: 1.279815
frontdepth: 1000.0, 500.0, 6.399076, 0.0

Shift_Front_V1 prevents a wetting front from overshooting the soil depth but not the depth of other fronts:

>>> check(bin_=2, initialsurfacewater=10.0, actualsurfacewater=10.0,
...       frontdepth=[1000.0, 999.0, 998.0, 0.0],
...       moisture=[0.1, 0.3, 0.5, 0.1])
moisturechange: nan, nan, nan, nan
moisture: 0.1, 0.3, 0.5, 0.1
infiltration: 0.4
frontdepth: 1000.0, 999.0, 1000.0, 0.0

In principle, Shift_Front_V1 works for the active, non-last bins as described above:

>>> check(bin_=1, initialsurfacewater=10.0, actualsurfacewater=1.0,
...       frontdepth=[1000.0, 300.0, 200.0, 100.0],
...       moisture=[0.2, 0.3, 0.4, 0.5])
moisturechange: nan, nan, nan, nan
moisture: 0.2, 0.3, 0.4, 0.5
infiltration: 0.003176
frontdepth: 1000.0, 300.031762, 200.0, 100.0

However, for these bins, it also applies to rain-free periods. Then, its front shifts as usual while keeping its relative moisture. As the considered bin cannot (completely) take the corrensponding absolute moisture decrease from the surface, it takes water from the last active bin instead, decreasing its depth but not its relative moisture:

>>> check(bin_=1, initialsurfacewater=0.0, actualsurfacewater=0.0,
...       frontdepth=[1000.0, 300.0, 200.0, 100.0],
...       moisture=[0.2, 0.3, 0.4, 0.5])
moisturechange: nan, nan, nan, nan
moisture: 0.2, 0.3, 0.4, 0.5
infiltration: 0.0
frontdepth: 1000.0, 300.030738, 200.0, 99.969262

If the last active bin does not contain enough water, the second-last bin must help out:

>>> check(bin_=1, initialsurfacewater=0.0, actualsurfacewater=0.0,
...       frontdepth=[1000.0, 300.0, 200.0, 0.01],
...       moisture=[0.2, 0.3, 0.4, 0.5])
moisturechange: nan, nan, nan, 0.0
moisture: 0.2, 0.3, 0.4, 0.2
infiltration: 0.0
frontdepth: 1000.0, 300.030738, 199.979262, 0.0

If all bins that possess higher relative moisture than the considered bin do not contain enough water, the shift of the wetting front becomes restricted:

>>> check(bin_=1, initialsurfacewater=0.0, actualsurfacewater=0.0,
...       frontdepth=[1000.0, 300.0, 0.02, 0.01],
...       moisture=[0.2, 0.3, 0.4, 0.5])
moisturechange: nan, nan, 0.0, 0.0
moisture: 0.2, 0.3, 0.2, 0.2
infiltration: 0.0
frontdepth: 1000.0, 300.03, 0.0, 0.0

All examples above show that Shift_Front_V1 never modifies MoistureChange, except when deactivating a bin. Then, it sets the moisture change to zero.

class hydpy.models.ga.ga_model.Redistribute_Front_V1[source]

Bases: Method

Modify the selected bin’s wetting front depth and relative moisture content based on a Green & Ampt redistribution equation.

Required by the method:

Infiltrate_WettingFrontBins_V1

Required submethods:

Return_RelativeMoisture_V1 Return_DryDepth_V1 Return_Conductivity_V1 Return_CapillaryDrive_V1

Requires the control parameters:

NmbBins DT SoilDepth ResidualMoisture SaturationMoisture SaturatedConductivity AirEntryPotential PoreSizeDistribution

Requires the derived parameter:

EffectiveCapillarySuction

Updates the state sequences:

Moisture FrontDepth

Updates the log sequence:

MoistureChange

Updates the aide sequence:

ActualSurfaceWater

Redistribute_Front_V1 applies for the last active wetting front bin when rainfall intensity does not exceed saturated conductivity.

Basic equations (Lai et al. (2015), equation 6)

\(p = \cases{1.7 &| ActualSurfaceWater = 0 \\ 1.0 &| ActualSurfaceWater > 0}\)

\(MoistureChange_{bin} = \frac{1}{FrontDepth_{bin}} \cdot \left( ActualSurfaceWater - DT \cdot \left( Conductivity_{bin} - \frac{p \cdot SaturatedConductivity \cdot CapillaryDrive_{bin-1,bin}} {FrontDepth_{bin}} \right) \right)\)

\(Moisture_{bin,old} = Moisture_{bin,new} + MoistureChange_{bin}\)

\(Infiltration_{bin} = DT \cdot SaturatedConductivity \cdot \left( 1 + \frac{EffectiveCapillarySuction}{FrontDepth_{bin}} \right)\)

\(FrontDepth_{bin,new} = \frac{Infiltration_{bin} + FrontDepth_{bin,old} \cdot (Moisture_{bin,old} - Moisture_{bin-1})} {Moisture_{bin,new} - Moisture_{bin-1}}\)

Lai et al. (2015) define only the calculation of the moisture change explicitly. The infiltration calculation and the corresponding shift of the wetting front depth rest on the GARTO source code provided by the authors. One might have expected to use \(Conductivity_{bin}\) and \(CapillaryDrive_{bin-1,bin}\) instead of \(SaturatedConductivity\) and \(EffectiveCapillarySuction\). There is a remark of the authors (possibly concerning the \(CapillaryDrive_{bin-1,bin}\) vs \(EffectiveCapillarySuction\) issue only) that oscillations in infiltration rates might show up otherwise. Maybe we can discuss this with the authors or investigate ourselves in more detail later.

If the bin’s initial front depth is zero, the basic equations for calculating moisture change and infiltration become obsolete. Redistribute_Front_V1 then proceeds as follows:

\(MoistureChange_{bin} = (ActualSurfaceWater - DT \cdot Conductivity_{bin-1}) / DryDepth\)

\(Infiltration_{bin} = DT \cdot SaturatedConductivity \cdot \left( 1 + \frac{EffectiveCapillarySuction}{DryDepth} \right)\)

Examples:

For comparison, we perform the following examples similar to those of method Shift_Front_V1. The general setting is identical:

>>> from hydpy.models.ga_garto import *
>>> simulationstep("1h")
>>> parameterstep("1h")
>>> nmbsoils(1)
>>> nmbbins(4)
>>> dt(0.25)
>>> sealed(False)
>>> soilarea(1.0)
>>> soildepth(1000.0)
>>> residualmoisture(0.1)
>>> saturationmoisture(0.5)
>>> airentrypotential(0.1)
>>> poresizedistribution(0.3)
>>> saturatedconductivity(10.0)
>>> derived.soilareafraction.update()
>>> derived.effectivecapillarysuction.update()

The test function behaves similarly. However it neglects the initial surface water depth, which is not a relevant input to Redistribute_Front_V1, and considers percolation, which Redistribute_Front_V1 might update when deactivating surface wetting fronts:

>>> from hydpy.core.objecttools import repr_, repr_values
>>> def check(bin_, actualsurfacewater, frontdepth, moisture):
...     states.moisture = [[m] for m in moisture]
...     states.frontdepth = [[fd] for fd in frontdepth]
...     logs.moisturechange = nan
...     aides.actualsurfacewater = actualsurfacewater
...     fluxes.percolation[0] = 0.0
...     old_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
...     model.redistribute_front_v1(bin_, 0)
...     new_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
...     assert old_volume == new_volume + fluxes.percolation[0]
...     infiltration = actualsurfacewater - aides.actualsurfacewater[0]
...     print(f"moisturechange: {repr_values(logs.moisturechange[:, 0])}")
...     print(f"moisture: {repr_values(states.moisture[:, 0])}")
...     print(f"infiltration: {repr_(infiltration)}")
...     print(f"percolation: {repr_(fluxes.percolation[0])}")
...     print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")

In the first example, the given basic equations apply without modifications. Due to missing surface water, relative moisture decreases. Consequently, the front’s depth increases to keep the bin’s total water volume:

>>> check(bin_=2, actualsurfacewater=0.0,
...       frontdepth=[1000.0, 500.0, 100.0, 0.0],
...       moisture=[0.1, 0.3, 0.4, 0.1])
moisturechange: nan, nan, -0.001553, nan
moisture: 0.1, 0.3, 0.398447, 0.1
infiltration: 0.0
percolation: 0.0
frontdepth: 1000.0, 500.0, 101.57736, 0.0

With enough available surface water, the bin’s relative soil moisture increases. In the following example, this moisture increase outweighs the actual infiltration. So the front depth must must decrease to keep the absolute water volume.

>>> check(bin_=2, actualsurfacewater=5.0,
...       frontdepth=[1000.0, 500.0, 100.0, 0.0],
...       moisture=[0.1, 0.3, 0.4, 0.1])
moisturechange: nan, nan, 0.048449, nan
moisture: 0.1, 0.3, 0.448449, 0.1
infiltration: 2.503816
percolation: 0.0
frontdepth: 1000.0, 500.0, 84.229985, 0.0

For zero initial front depth, Redistribute_Front_V1 prefers the alternative equations for calculating moisture change and infiltration defined above:

>>> check(bin_=2, actualsurfacewater=0.5,
...       frontdepth=[1000.0, 500.0, 0.0, 0.0],
...       moisture=[0.1, 0.3, 0.4, 0.1])
moisturechange: nan, nan, 0.077656, nan
moisture: 0.1, 0.3, 0.477656, 0.1
infiltration: 0.5
percolation: 0.0
frontdepth: 1000.0, 500.0, 2.814434, 0.0

Redistribute_Front_V1 ensures the updated moisture content does not exceed the saturation content, even if the calculated moisture change suggests so:

ToDo: clip moisture change?

>>> check(bin_=2, actualsurfacewater=20.0,
...       frontdepth=[1000.0, 500.0, 100.0, 0.0],
...       moisture=[0.1, 0.3, 0.4, 0.1])
moisturechange: nan, nan, 0.198449, nan
moisture: 0.1, 0.3, 0.5, 0.1
infiltration: 2.503816
percolation: 0.0
frontdepth: 1000.0, 500.0, 62.519079, 0.0

A moisture decrease that would result in falling below the moisture value of the left neighbour bin causes the deactivation of the affected bin. If the left neighbour contains an active wetting front, Redistribute_Front_V1 adds the remaining soil water and infiltration to this bin by increasing its front depth:

ToDo: What if the front depth of the left neigbour bin exceeds soil depth

afterwards?

>>> check(bin_=2, actualsurfacewater=0.001,
...       frontdepth=[1000.0, 500.0, 100.0, 0.0],
...       moisture=[0.1, 0.3, 0.30001, 0.1])
moisturechange: nan, nan, 0.0, nan
moisture: 0.1, 0.3, 0.1, 0.1
infiltration: 0.001
percolation: 0.0
frontdepth: 1000.0, 500.01, 0.0, 0.0

If the left neighbour is the first, completely “filled” bin, the remaining soil water and infiltration increase its moisture content:

>>> soildepth(500.0)
>>> check(bin_=1, actualsurfacewater=0.001,
...       frontdepth=[500.0, 100.0, 0.0, 0.0],
...       moisture=[0.3, 0.30001, 0.1, 0.1])
moisturechange: nan, 0.0, nan, nan
moisture: 0.300004, 0.300004, 0.300004, 0.300004
infiltration: 0.001
percolation: 0.0
frontdepth: 500.0, 0.0, 0.0, 0.0
ToDo: In the original GARTO code, the remaining soil water and infiltration

become percolation. However, when evaporation interferes with the original equations, this simplification can result in percolation rates larger than saturated conductivity. We observed this in the continuous event example, where percolation was 20 mm/h (the rainfall rate) in the 21st hour despite a saturated conductivity of 13.2 mm/h. For our assumption, the percolation rate is 12.8 mm/h. Nevertheless, we should keep this deviation from the original implementation in mind for a while; in case it brings unexpected side effects in future applications.

class hydpy.models.ga.ga_model.Infiltrate_WettingFrontBins_V1[source]

Bases: Method

Process infiltration into the wetting front bins.

Required by the methods:

Execute_Infiltration_V1 Perform_GARTO_V1

Required submethods:

Return_RelativeMoisture_V1 Return_DryDepth_V1 Return_Conductivity_V1 Return_CapillaryDrive_V1 Active_Bin_V1 Shift_Front_V1 Redistribute_Front_V1

Requires the control parameters:

NmbBins DT SoilDepth ResidualMoisture SaturationMoisture SaturatedConductivity AirEntryPotential PoreSizeDistribution

Requires the derived parameter:

EffectiveCapillarySuction

Requires the aide sequence:

InitialSurfaceWater

Updates the state sequences:

Moisture FrontDepth

Updates the log sequence:

MoistureChange

Updates the aide sequence:

ActualSurfaceWater

Infiltrate_WettingFrontBins_V1 does not perform any calculations itself but selects the proper submethods to do so. It either does nothing (if the filled bin is saturated) or calls Redistribute_Front_V1, Shift_Front_V1, or Active_Bin_V1 (primarily depending on the initial surface water depth and the current moisture contents).

Infiltrate_WettingFrontBins_V1 is specifically designed for ga_garto.

Examples:

Instead of triggering actual calculations, we try to show how Infiltrate_WettingFrontBins_V1 selects the mentioned methods based on mocking them. Therefore, we must import the model in pure Python mode:

>>> from hydpy.core.importtools import reverse_model_wildcard_import
>>> reverse_model_wildcard_import()
>>> from hydpy import pub, print_vector
>>> with pub.options.usecython(False):
...     from hydpy.models.ga import *
...     simulationstep("1h")
...     parameterstep("1h")

We define only those parameters required for selecting the proper methods:

>>> nmbsoils(1)
>>> nmbbins(5)
>>> dt(0.25)
>>> saturationmoisture(0.6)
>>> saturatedconductivity(10.0)

The following test function prepares the initial surface water depth, the (current) relative moisture, and the (previous) moisture change. Afterwards, it replaces the mentioned methods with mocks, invokes Infiltrate_WettingFrontBins_V1, and prints the passed arguments of all mock calls:

>>> from unittest.mock import patch
>>> def check(initialsurfacewater, moisture, moisturechange):
...     states.moisture = [[m] for m in moisture]
...     logs.moisturechange = [[mc] for mc in moisturechange]
...     aides.initialsurfacewater = initialsurfacewater
...     with patch.object(
...         model, "redistribute_front_v1"
...     ) as redistribute_front_v1, patch.object(
...         model, "shift_front_v1"
...     ) as shift_front_v1, patch.object(
...         model, "active_bin_v1"
...     ) as active_bin_v1:
...         model.infiltrate_wettingfrontbins_v1(0)
...     for mock in (shift_front_v1, redistribute_front_v1, active_bin_v1):
...         if mock.called:
...             print(mock._extract_mock_name(), end=": ")
...             print_vector([str(call)[4:] for call in mock.mock_calls])

If the first (filled) bin is saturated, Infiltrate_WettingFrontBins_V1 does nothing:

>>> check(initialsurfacewater=20.0,
...       moisture=[0.6, 0.6, 0.6, 0.6, 0.6],
...       moisturechange=[0.0, 0.0, 0.0, 0.0, 0.0])

If a wetting front bin is saturated, Infiltrate_WettingFrontBins_V1 calls either Shift_Front_V1 or Redistribute_Front_V1, depending on whether the surface water depth (rainfall intensity) exceeds saturated conductivity or not:

>>> check(initialsurfacewater=20.0,
...       moisture=[0.1, 0.6, 0.6, 0.6, 0.6],
...       moisturechange=[0.0, 0.0, 0.0, 0.0, 0.0])
shift_front_v1: (1, 0)
>>> check(initialsurfacewater=2.0,
...       moisture=[0.1, 0.6, 0.6, 0.6, 0.6],
...       moisturechange=[0.0, 0.0, 0.0, 0.0, 0.0])
redistribute_front_v1: (1, 0)

If all bins are active, Infiltrate_WettingFrontBins_V1 calls Shift_Front_V1 for all bins except for the last one, for which it calls Redistribute_Front_V1:

>>> check(initialsurfacewater=2.0,
...       moisture=[0.1, 0.2, 0.3, 0.4, 0.5],
...       moisturechange=[0.0, 0.0, 0.0, 0.0, 0.0])
shift_front_v1: (1, 0), (2, 0), (3, 0)
redistribute_front_v1: (4, 0)

If there is at least one inactivated bin and the last active bin is not saturated, Infiltrate_WettingFrontBins_V1 either calls Active_Bin_V1 to activate a new bin right to it or calls Redistribute_Front_V1, depending on whether rainfall intensity exceeds saturated conductivity and the active bin’s relative moisture decreased previously or not:

>>> check(initialsurfacewater=20.0,
...       moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
...       moisturechange=[0.0, 0.0, 0.0, -1.0, 0.0])
shift_front_v1: (1, 0), (2, 0)
active_bin_v1: (3, 0)
>>> check(initialsurfacewater=2.0,
...       moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
...       moisturechange=[0.0, 0.0, 0.0, -1.0, 0.0])
shift_front_v1: (1, 0), (2, 0)
redistribute_front_v1: (3, 0)
>>> check(initialsurfacewater=20.0,
...       moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
...       moisturechange=[0.0, 0.0, 0.0, 0.0, 0.0])
shift_front_v1: (1, 0), (2, 0)
redistribute_front_v1: (3, 0)
>>> check(initialsurfacewater=2.0,
...       moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
...       moisturechange=[0.0, 0.0, 0.0, 0.0, 0.0])
shift_front_v1: (1, 0), (2, 0)
redistribute_front_v1: (3, 0)
>>> reverse_model_wildcard_import()
class hydpy.models.ga.ga_model.Merge_FrontDepthOvershootings_V1[source]

Bases: Method

Merge those neighbour bins where the wetting front’s depth of the right neighbour exceeds the wetting front’s depth of the left neighbour.

Required by the methods:

Execute_Infiltration_V1 Perform_GARTO_V1

Requires the control parameter:

NmbBins

Updates the state sequences:

Moisture FrontDepth

Updates the log sequence:

MoistureChange

Examples:

For comparison, we perform the following examples similar to those of method Active_Bin_V1. However, in contrast to Active_Bin_V1, Merge_FrontDepthOvershootings_V1 only needs to know the number of available bins and their current states only, making the general set-up much shorter:

>>> from hydpy.models.ga_garto import *
>>> parameterstep()
>>> nmbsoils(1)
>>> nmbbins(5)
>>> sealed(False)
>>> soilarea(1.0)
>>> soildepth(1000.0)
>>> derived.soilareafraction.update()

Instead of accepting different values for the actual surface water depth, the test function here allows defining the respective front’s depth, moisture and moisture change:

>>> from hydpy.core.objecttools import repr_, repr_values
>>> def check(frontdepth, moisture, moisturechange):
...     states.frontdepth = [[fd] for fd in frontdepth]
...     states.moisture = [[m] for m in moisture]
...     logs.moisturechange = [[mc] for mc in moisturechange]
...     old_volume = round(model.watercontent, 12)
...     model.merge_frontdepthovershootings_v1(0)
...     new_volume = round(model.watercontent, 12)
...     assert old_volume == new_volume
...     print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")
...     print(f"moisture: {repr_values(states.moisture[:, 0])}")
...     print(f"moisturechange: {repr_values(logs.moisturechange[:, 0])}")

Nothing happens as long as all bins have smaller front depths than their left neighbours. Note that Merge_FrontDepthOvershootings_V1 also becomes active only if relative moisture increases from left to right. Hence, in the following example, there is no merging of the two inactive bins, which (as usual) both have zero front depths:

>>> check(frontdepth=[1000.0, 500.0, 100.0, 0.0, 0.0],
...       moisture=[0.1, 0.3, 0.5, 0.1, 0.1],
...       moisturechange=[0.2, 0.4, 0.6, 0.0, 0.0])
frontdepth: 1000.0, 500.0, 100.0, 0.0, 0.0
moisture: 0.1, 0.3, 0.5, 0.1, 0.1
moisturechange: 0.2, 0.4, 0.6, 0.0, 0.0

For equal depths, Merge_FrontDepthOvershootings_V1 deactivates the left neighbour bin and sets the moisture change of the left neighbour to zero:

>>> check(frontdepth=[1000.0, 500.0, 500.0, 0.0, 0.0],
...       moisture=[0.1, 0.3, 0.5, 0.1, 0.1],
...       moisturechange=[0.2, 0.4, 0.6, 0.0, 0.0])
frontdepth: 1000.0, 500.0, 0.0, 0.0, 0.0
moisture: 0.1, 0.5, 0.1, 0.1, 0.1
moisturechange: 0.2, 0.0, 0.0, 0.0, 0.0

In case of an overshooting, Merge_FrontDepthOvershootings_V1 must add the (additional) water content of the (deactivated) right neighbour to the (preserved) left neighbour:

>>> check(frontdepth=[1000.0, 500.0, 600.0, 0.0, 0.0],
...       moisture=[0.1, 0.3, 0.5, 0.1, 0.1],
...       moisturechange=[0.2, 0.4, 0.6, 0.0, 0.0])
frontdepth: 1000.0, 550.0, 0.0, 0.0, 0.0
moisture: 0.1, 0.5, 0.1, 0.1, 0.1
moisturechange: 0.2, 0.0, 0.0, 0.0, 0.0

All right neighbours of a deactivated bin move (at least) one place to the left:

>>> check(frontdepth=[1000.0, 500.0, 600.0, 400.0, 0.0],
...       moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
...       moisturechange=[0.2, 0.4, 0.6, 0.8, 0.0])
frontdepth: 1000.0, 550.0, 400.0, 0.0, 0.0
moisture: 0.1, 0.3, 0.4, 0.1, 0.1
moisturechange: 0.2, 0.0, 0.8, 0.0, 0.0

If the last bin is active, it gets properly deactivated:

>>> check(frontdepth=[1000.0, 500.0, 600.0, 400.0, 300.0],
...       moisture=[0.1, 0.2, 0.3, 0.4, 0.5],
...       moisturechange=[0.2, 0.4, 0.6, 0.8, 1.0])
frontdepth: 1000.0, 550.0, 400.0, 300.0, 0.0
moisture: 0.1, 0.3, 0.4, 0.5, 0.1
moisturechange: 0.2, 0.0, 0.8, 1.0, 0.0

The two last examples demonstrate that the underlying algorithm works stably in case multiple mergings are necessary:

>>> check(frontdepth=[1000.0, 500.0, 600.0, 700.0, 0.0],
...       moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
...       moisturechange=[0.2, 0.4, 0.6, 0.8, 0.0])
frontdepth: 1000.0, 600.0, 0.0, 0.0, 0.0
moisture: 0.1, 0.4, 0.1, 0.1, 0.1
moisturechange: 0.2, 0.0, 0.0, 0.0, 0.0
>>> check(frontdepth=[1000.0, 500.0, 600.0, 400.0, 500.0],
...       moisture=[0.1, 0.2, 0.3, 0.4, 0.5],
...       moisturechange=[0.2, 0.4, 0.6, 0.8, 1.0])
frontdepth: 1000.0, 550.0, 450.0, 0.0, 0.0
moisture: 0.1, 0.3, 0.5, 0.1, 0.1
moisturechange: 0.2, 0.0, 0.0, 0.0, 0.0
class hydpy.models.ga.ga_model.Merge_SoilDepthOvershootings_V1[source]

Bases: Method

Merge bins with wetting front depth larger than soil depth with their left neighbour bins and add their water excess to percolation.

Required by the methods:

Execute_Infiltration_V1 Perform_GARTO_V1

Requires the control parameters:

NmbBins SoilDepth

Updates the flux sequence:

Percolation

Updates the state sequences:

FrontDepth Moisture

Updates the log sequence:

MoistureChange

Merge_SoilDepthOvershootings_V1 assumes proper sorting of wetting front depths (decreasing from left to right), as ensured by Merge_FrontDepthOvershootings_V1.

Examples:

For comparison, we perform the following examples similar to those of the related method Merge_FrontDepthOvershootings_V1. The general setting is identical:

>>> from hydpy.models.ga_garto import *
>>> parameterstep()
>>> nmbsoils(1)
>>> nmbbins(5)
>>> sealed(False)
>>> soilarea(1.0)
>>> soildepth(1000.0)
>>> derived.soilareafraction.update()

The test function is similar but must also consider percolation:

>>> from hydpy.core.objecttools import repr_, repr_values
>>> def check(frontdepth, moisture, moisturechange):
...     states.frontdepth = [[fd] for fd in frontdepth]
...     states.moisture = [[m] for m in moisture]
...     logs.moisturechange = [[mc] for mc in moisturechange]
...     fluxes.percolation = 0.0
...     old_volume = round(model.watercontent, 12)
...     model.merge_soildepthovershootings_v1(0)
...     new_volume = round(model.watercontent + fluxes.percolation[0], 12)
...     assert old_volume == new_volume
...     print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")
...     print(f"moisture: {repr_values(states.moisture[:, 0])}")
...     print(f"moisturechange: {repr_values(logs.moisturechange[:, 0])}")
...     print(f"percolation: {repr_(fluxes.percolation[0])}")

Nothing happens as long as all bins have smaller front depths than their left neighbours. Note that Merge_SoilDepthOvershootings_V1 also becomes active only if relative moisture increases from left to right. Hence, in the following example, there is no merging of the two inactive bins, which (as usual) both have zero front depths:

>>> check(frontdepth=[1000.0, 900.0, 800.0, 0.0, 0.0],
...       moisture=[0.1, 0.2, 0.3, 0.1, 0.1],
...       moisturechange=[0.0, 1.0, 2.0, 0.0, 0.0])
frontdepth: 1000.0, 900.0, 800.0, 0.0, 0.0
moisture: 0.1, 0.2, 0.3, 0.1, 0.1
moisturechange: 0.0, 1.0, 2.0, 0.0, 0.0
percolation: 0.0

If a single front’s depth reaches the soil bottom exactly, Merge_SoilDepthOvershootings_V1 deactivates the affected bin and takes its relative moisture value as the new initial moisture:

>>> check(frontdepth=[1000.0, 1000.0, 0.0, 0.0, 0.0],
...       moisture=[0.1, 0.2, 0.1, 0.1, 0.1],
...       moisturechange=[0.0, 1.0, 0.0, 0.0, 0.0])
frontdepth: 1000.0, 0.0, 0.0, 0.0, 0.0
moisture: 0.2, 0.2, 0.2, 0.2, 0.2
moisturechange: 0.0, 0.0, 0.0, 0.0, 0.0
percolation: 0.0

Parts of the front lying below the soil’s bottom become percolation:

>>> check(frontdepth=[1000.0, 1100.0, 0.0, 0.0, 0.0],
...       moisture=[0.1, 0.2, 0.1, 0.1, 0.1],
...       moisturechange=[0.0, 1.0, 0.0, 0.0, 0.0])
frontdepth: 1000.0, 0.0, 0.0, 0.0, 0.0
moisture: 0.2, 0.2, 0.2, 0.2, 0.2
moisturechange: 0.0, 0.0, 0.0, 0.0, 0.0
percolation: 10.0

All remaining active wetting front bins move (at least) one place to the left:

>>> check(frontdepth=[1000.0, 1100.0, 800.0, 700.0, 600.0],
...       moisture=[0.1, 0.2, 0.3, 0.4, 0.5],
...       moisturechange=[0.0, 1.0, 2.0, 3.0, 4.0])
frontdepth: 1000.0, 800.0, 700.0, 600.0, 0.0
moisture: 0.2, 0.3, 0.4, 0.5, 0.2
moisturechange: 0.0, 2.0, 3.0, 4.0, 0.0
percolation: 10.0

The two last examples demonstrate that the underlying algorithm works stably in case multiple mergings are necessary:

>>> check(frontdepth=[1000.0, 1200.0, 1100.0, 700.0, 0.0],
...       moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
...       moisturechange=[0.0, 1.0, 2.0, 3.0, 0.0])
frontdepth: 1000.0, 700.0, 0.0, 0.0, 0.0
moisture: 0.3, 0.4, 0.3, 0.3, 0.3
moisturechange: 0.0, 3.0, 0.0, 0.0, 0.0
percolation: 30.0
>>> check(frontdepth=[1000.0, 1200.0, 1200.0, 1100.0, 1100.0],
...       moisture=[0.1, 0.2, 0.3, 0.4, 0.5],
...       moisturechange=[0.0, 1.0, 2.0, 3.0, 4.0])
frontdepth: 1000.0, 0.0, 0.0, 0.0, 0.0
moisture: 0.5, 0.5, 0.5, 0.5, 0.5
moisturechange: 0.0, 0.0, 0.0, 0.0, 0.0
percolation: 60.0
class hydpy.models.ga.ga_model.Water_AllBins_V1[source]

Bases: Method

Water the soil’s body by (potentially) adding water to all active bins.

Required by the methods:

Add_SoilWater_V1 Perform_GARTO_V1

Requires the control parameters:

NmbBins SoilDepth SaturationMoisture

Updates the flux sequence:

SoilWaterAddition

Updates the state sequences:

Moisture FrontDepth

Updates the log sequence:

MoistureChange

The soil water addition calculated by Water_AllBins_V1 equals the defined soil water supply, except adding the complete supply would exceed the saturation water content.

Note that the caller needs to pass the supply as a method parameter, which allows him to decide whether to add everything in one simulation step or multiple numerical substeps.

Examples:

We prepare a single shallow soil compartment divided into four bins:

>>> from hydpy.models.ga_garto import *
>>> simulationstep("1d")
>>> parameterstep("1d")
>>> nmbsoils(1)
>>> nmbbins(4)
>>> dt(0.5)
>>> sealed(False)
>>> soilarea(1.0)
>>> soildepth(100.0)
>>> saturationmoisture(0.5)
>>> derived.soilareafraction.update()

The following test function works similar to the one defined for demonstrating Active_Bin_V1 but considers the soil water addition instead of infiltration:

>>> from hydpy.core.objecttools import repr_, repr_values
>>> def check(soilwatersupply, moisture, frontdepth):
...     fluxes.soilwatersupply[0] = soilwatersupply
...     states.moisture = [[m] for m in moisture]
...     states.frontdepth = [[fd] for fd in frontdepth]
...     logs.moisturechange = [[1.0], [2.0], [3.0], [4.0]]
...     fluxes.soilwateraddition[0] = 0.0
...     old_volume = round(model.watercontent, 12)
...     model.water_allbins_v1(0, soilwatersupply)
...     new_volume = round(model.watercontent, 12)
...     assert old_volume + fluxes.soilwateraddition[0] == new_volume
...     print(f"soilwatersupply: {repr_(fluxes.soilwatersupply[0])}")
...     print(f"moisture: {repr_values(states.moisture[:, 0])}")
...     print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")
...     print(f"moisturechange: {repr_values(logs.moisturechange[:, 0])}")
...     print(f"soilwateraddition: {repr_(fluxes.soilwateraddition[0])}")

For zero soil water supply, Water_AllBins_V1 does nothing:

>>> check(soilwatersupply=0.0,
...       moisture=[0.1, 0.3, 0.1, 0.1],
...       frontdepth=[100.0, 50.0, 0.0, 0.0])
soilwatersupply: 0.0
moisture: 0.1, 0.3, 0.1, 0.1
frontdepth: 100.0, 50.0, 0.0, 0.0
moisturechange: 1.0, 2.0, 3.0, 4.0
soilwateraddition: 0.0

Water_AllBins_V1 tries to add the supply to the dryest bin by increasing its relative moisture content:

>>> check(soilwatersupply=5.0,
...       moisture=[0.1, 0.3, 0.1, 0.1],
...       frontdepth=[100.0, 50.0, 0.0, 0.0])
soilwatersupply: 5.0
moisture: 0.2, 0.3, 0.2, 0.2
frontdepth: 100.0, 50.0, 0.0, 0.0
moisturechange: 0.0, 2.0, 3.0, 4.0
soilwateraddition: 5.0

If a bin is not the last active bin, its highest possible moisture content is restricted by the relative moisture value of its right neighbour bin. If two bins get the same moisture, one of them becomes obsolete, so we can remove it and shift all its right neighbours one place to the left:

>>> check(soilwatersupply=10.0,
...       moisture=[0.1, 0.3, 0.1, 0.1],
...       frontdepth=[100.0, 50.0, 0.0, 0.0])
soilwatersupply: 10.0
moisture: 0.3, 0.3, 0.3, 0.3
frontdepth: 100.0, 0.0, 0.0, 0.0
moisturechange: 0.0, 3.0, 4.0, 0.0
soilwateraddition: 10.0

If the first bin cannot take enough water, Water_AllBins_V1 updates the front depth and increases the water content of the second bin:

>>> check(soilwatersupply=20.0,
...       moisture=[0.1, 0.3, 0.1, 0.1],
...       frontdepth=[100.0, 50.0, 0.0, 0.0])
soilwatersupply: 20.0
moisture: 0.4, 0.4, 0.4, 0.4
frontdepth: 100.0, 0.0, 0.0, 0.0
moisturechange: 0.0, 3.0, 4.0, 0.0
soilwateraddition: 20.0

However, no bin can possess relative moisture higher than indicated by saturation moisture:

>>> check(soilwatersupply=40.0,
...       moisture=[0.1, 0.3, 0.1, 0.1],
...       frontdepth=[100.0, 50.0, 0.0, 0.0])
soilwatersupply: 40.0
moisture: 0.5, 0.5, 0.5, 0.5
frontdepth: 100.0, 0.0, 0.0, 0.0
moisturechange: 0.0, 3.0, 4.0, 0.0
soilwateraddition: 30.0

Water_AllBins_V1 deactivates multiple bins when necessary:

>>> check(soilwatersupply=40.0,
...       moisture=[0.1, 0.3, 0.5, 0.1],
...       frontdepth=[100.0, 50.0, 0.0, 0.0])
soilwatersupply: 40.0
moisture: 0.5, 0.5, 0.5, 0.5
frontdepth: 100.0, 0.0, 0.0, 0.0
moisturechange: 0.0, 4.0, 0.0, 0.0
soilwateraddition: 30.0
>>> check(soilwatersupply=10.0,
...       moisture=[0.1, 0.2, 0.3, 0.4],
...       frontdepth=[100.0, 75.0, 50.0, 25.0])
soilwatersupply: 10.0
moisture: 0.333333, 0.4, 0.333333, 0.333333
frontdepth: 100.0, 25.0, 0.0, 0.0
moisturechange: 0.0, 4.0, 0.0, 0.0
soilwateraddition: 10.0
>>> check(soilwatersupply=30.0,
...       moisture=[0.1, 0.2, 0.3, 0.4],
...       frontdepth=[100.0, 75.0, 50.0, 25.0])
soilwatersupply: 30.0
moisture: 0.5, 0.5, 0.5, 0.5
frontdepth: 100.0, 0.0, 0.0, 0.0
moisturechange: 0.0, 0.0, 0.0, 0.0
soilwateraddition: 25.0

The last two examples demonstrate, similar to the first example, that Water_AllBins_V1 adjusts the relative moisture value of all non-active bins after increasing the moisture of the first bin:

>>> check(soilwatersupply=10.0,
...       moisture=[0.1, 0.1, 0.1, 0.1],
...       frontdepth=[100.0, 0.0, 0.0, 0.0])
soilwatersupply: 10.0
moisture: 0.2, 0.2, 0.2, 0.2
frontdepth: 100.0, 0.0, 0.0, 0.0
moisturechange: 0.0, 2.0, 3.0, 4.0
soilwateraddition: 10.0
>>> check(soilwatersupply=50.0,
...       moisture=[0.1, 0.1, 0.1, 0.1],
...       frontdepth=[100.0, 0.0, 0.0, 0.0])
soilwatersupply: 50.0
moisture: 0.5, 0.5, 0.5, 0.5
frontdepth: 100.0, 0.0, 0.0, 0.0
moisturechange: 0.0, 2.0, 3.0, 4.0
soilwateraddition: 40.0
class hydpy.models.ga.ga_model.Withdraw_AllBins_V1[source]

Bases: Method

Take withdrawal from the available surface water and (potentially) from all active bins.

Required by the methods:

Perform_GARTO_V1 Remove_SoilWater_V1

Requires the control parameters:

NmbBins SoilDepth ResidualMoisture

Updates the flux sequence:

Withdrawal

Updates the state sequences:

Moisture FrontDepth

Updates the aide sequence:

ActualSurfaceWater

The withdrawal calculated by Withdraw_AllBins_V1 equals the defined demand, except no water exceeding the residual moisture is left. Hence, for example, actual evaporation is more suitable for specifying the demand than potential evaporation.

Note that the caller needs to pass the demand as a method parameter, which allows him to decide whether to subtract everything in one simulation step or multiple numerical substeps.

Examples:

We prepare a single shallow soil compartment divided into four bins:

>>> from hydpy.models.ga_garto import *
>>> simulationstep("1d")
>>> parameterstep("1d")
>>> nmbsoils(1)
>>> nmbbins(4)
>>> dt(0.5)
>>> sealed(False)
>>> soilarea(1.0)
>>> soildepth(100.0)
>>> residualmoisture(0.1)
>>> derived.soilareafraction.update()

The following test function works similar to the one defined for demonstrating Active_Bin_V1 but considers the withdrawal instead of infiltration:

>>> from hydpy.core.objecttools import repr_, repr_values
>>> def check(demand, actualsurfacewater, frontdepth, moisture):
...     states.moisture = [[m] for m in moisture]
...     states.frontdepth = [[fd] for fd in frontdepth]
...     logs.moisturechange = nan
...     aides.actualsurfacewater = actualsurfacewater
...     fluxes.withdrawal[0] = 0.0
...     old_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
...     model.withdraw_allbins_v1(0, control.dt * demand)
...     new_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
...     assert old_volume == new_volume + fluxes.withdrawal[0]
...     print(f"withdrawal: {repr_(fluxes.withdrawal[0])}")
...     print(f"actualsurfacewater: {repr_(aides.actualsurfacewater[0])}")
...     print(f"moisture: {repr_values(states.moisture[:, 0])}")
...     print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")

For zero demand, Withdraw_AllBins_V1 does nothing:

>>> check(demand=0.0, actualsurfacewater=20.0,
...       frontdepth=[100.0, 50.0, 0.0, 0.0],
...       moisture=[0.1, 0.3, 0.1, 0.1])
withdrawal: 0.0
actualsurfacewater: 20.0
moisture: 0.1, 0.3, 0.1, 0.1
frontdepth: 100.0, 50.0, 0.0, 0.0

If possible, Withdraw_AllBins_V1 withdraws only surface water:

>>> check(demand=10.0, actualsurfacewater=20.0,
...       frontdepth=[100.0, 50.0, 0.0, 0.0],
...       moisture=[0.1, 0.3, 0.1, 0.1])
withdrawal: 5.0
actualsurfacewater: 15.0
moisture: 0.1, 0.3, 0.1, 0.1
frontdepth: 100.0, 50.0, 0.0, 0.0

If no surface water is available, Withdraw_AllBins_V1 tries to take all withdrawal from the wettest bin by reducing its relative moisture content:

>>> check(demand=10.0, actualsurfacewater=0.0,
...       frontdepth=[100.0, 50.0, 0.0, 0.0],
...       moisture=[0.1, 0.3, 0.1, 0.1])
withdrawal: 5.0
actualsurfacewater: 0.0
moisture: 0.1, 0.2, 0.1, 0.1
frontdepth: 100.0, 50.0, 0.0, 0.0

The following example shows that Withdraw_AllBins_V1 still prefers surface water over soil water if the demand exceeds the available surface water:

>>> check(demand=10.0, actualsurfacewater=2.5,
...       frontdepth=[100.0, 50.0, 0.0, 0.0],
...       moisture=[0.1, 0.3, 0.1, 0.1])
withdrawal: 5.0
actualsurfacewater: 0.0
moisture: 0.1, 0.25, 0.1, 0.1
frontdepth: 100.0, 50.0, 0.0, 0.0

If the wettest bin does not contain enough water, Withdraw_AllBins_V1 proceeds from right to left in taking the remaining demand:

>>> check(demand=10.0, actualsurfacewater=0.0,
...       frontdepth=[100.0, 75.0, 50.0, 25.0],
...       moisture=[0.1, 0.2, 0.3, 0.4])
withdrawal: 5.0
actualsurfacewater: 0.0
moisture: 0.1, 0.2, 0.25, 0.1
frontdepth: 100.0, 75.0, 50.0, 0.0

However, Withdraw_AllBins_V1 never takes more water than indicated by soil’s residual moisture:

>>> check(demand=40.0, actualsurfacewater=0.0,
...       frontdepth=[100.0, 75.0, 50.0, 25.0],
...       moisture=[0.1, 0.2, 0.3, 0.4])
withdrawal: 15.0
actualsurfacewater: 0.0
moisture: 0.1, 0.1, 0.1, 0.1
frontdepth: 100.0, 0.0, 0.0, 0.0

The last two examples show that Withdraw_AllBins_V1 can also take water from the filled bin (if it is not already dry, as in the previous example):

>>> check(demand=10.0, actualsurfacewater=0.0,
...       frontdepth=[100.0, 0.0, 0.0, 0.0],
...       moisture=[0.2, 0.2, 0.2, 0.2])
withdrawal: 5.0
actualsurfacewater: 0.0
moisture: 0.15, 0.2, 0.2, 0.2
frontdepth: 100.0, 0.0, 0.0, 0.0
>>> check(demand=40.0, actualsurfacewater=0.0,
...       frontdepth=[100.0, 0.0, 0.0, 0.0],
...       moisture=[0.2, 0.2, 0.2, 0.2])
withdrawal: 10.0
actualsurfacewater: 0.0
moisture: 0.1, 0.2, 0.2, 0.2
frontdepth: 100.0, 0.0, 0.0, 0.0

As the last examples show, Withdraw_AllBins_V1 does not update the other bins’ moisture after removing water from the filled bin, which is surprising but agrees with the author’s GARTO source code and gave better results for shallow soils in some comparisons.

class hydpy.models.ga.ga_model.Perform_GARTO_V1[source]

Bases: Method

Perform the GARTO algorithm for the numerical substeps and aggregate their results.

Required submethods:

Return_LastActiveBin_V1 Return_Conductivity_V1 Return_DryDepth_V1 Return_CapillaryDrive_V1 Percolate_FilledBin_V1 Infiltrate_WettingFrontBins_V1 Merge_FrontDepthOvershootings_V1 Merge_SoilDepthOvershootings_V1 Water_AllBins_V1 Withdraw_AllBins_V1

Requires the control parameters:

NmbSoils NmbBins DT SoilDepth Sealed ResidualMoisture SaturationMoisture SaturatedConductivity AirEntryPotential PoreSizeDistribution

Requires the derived parameters:

NmbSubsteps EffectiveCapillarySuction

Requires the flux sequences:

SurfaceWaterSupply SoilWaterSupply Demand

Updates the state sequences:

Moisture FrontDepth

Updates the log sequence:

MoistureChange

Updates the aide sequences:

InitialSurfaceWater ActualSurfaceWater

Calculates the flux sequences:

Infiltration Percolation SoilWaterAddition Withdrawal SurfaceRunoff

Method Perform_GARTO_V1 executes its submethods Percolate_FilledBin_V1, Infiltrate_WettingFrontBins_V1, Merge_FrontDepthOvershootings_V1, Merge_SoilDepthOvershootings_V1, Water_AllBins_V1, and Withdraw_AllBins_V1 in the order of mentioning on all non-sealed soil compartments. Additionally, it converts surface water that cannot infiltrate (or evaporate) during a numerical substep immediately to surface runoff (no ponding). So, it provides all core functionalities of application model ga_garto, and the explanations and test results for ga_garto essentially apply to Perform_GARTO_V1, too.

class hydpy.models.ga.ga_model.Calc_TotalInfiltration_V1[source]

Bases: Method

Calculate the average infiltration from all soil compartments.

Requires the control parameter:

NmbSoils

Requires the derived parameter:

SoilAreaFraction

Requires the flux sequence:

Infiltration

Calculates the flux sequence:

TotalInfiltration

Basic equation:

\(TotalInfiltration = \sum_{i=1}^{NmbSoils} SoilAreaFraction_i \cdot Infiltration_i\)

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> derived.soilareafraction(0.8, 0.2)
>>> fluxes.infiltration = 1.0, 2.0
>>> model.calc_totalinfiltration_v1()
>>> fluxes.totalinfiltration
totalinfiltration(1.2)
class hydpy.models.ga.ga_model.Calc_TotalPercolation_V1[source]

Bases: Method

Calculate the average percolation from all soil compartments.

Requires the control parameter:

NmbSoils

Requires the derived parameter:

SoilAreaFraction

Requires the flux sequence:

Percolation

Calculates the flux sequence:

TotalPercolation

Basic equation:

\(TotalPercolation = \sum_{i=1}^{NmbSoils} SoilAreaFraction_i \cdot Percolation_i\)

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> derived.soilareafraction(0.8, 0.2)
>>> fluxes.percolation = 1.0, 2.0
>>> model.calc_totalpercolation_v1()
>>> fluxes.totalpercolation
totalpercolation(1.2)
class hydpy.models.ga.ga_model.Calc_TotalSoilWaterAddition_V1[source]

Bases: Method

Calculate the average soil water addition to all soil compartments.

Requires the control parameter:

NmbSoils

Requires the derived parameter:

SoilAreaFraction

Requires the flux sequence:

SoilWaterAddition

Calculates the flux sequence:

TotalSoilWaterAddition

Basic equation:

\(TotalSoilWaterAddition = \sum_{i=1}^{NmbSoils} SoilAreaFraction_i \cdot SoilWaterAddition_i\)

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> derived.soilareafraction(0.8, 0.2)
>>> fluxes.soilwateraddition = 1.0, 2.0
>>> model.calc_totalsoilwateraddition_v1()
>>> fluxes.totalsoilwateraddition
totalsoilwateraddition(1.2)
class hydpy.models.ga.ga_model.Calc_TotalWithdrawal_V1[source]

Bases: Method

Calculate the average withdrawal from all soil compartments.

Requires the control parameter:

NmbSoils

Requires the derived parameter:

SoilAreaFraction

Requires the flux sequence:

Withdrawal

Calculates the flux sequence:

TotalWithdrawal

Basic equation:

\(TotalWithdrawal = \sum_{i=1}^{NmbSoils} SoilAreaFraction_i \cdot Withdrawal_i\)

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> derived.soilareafraction(0.8, 0.2)
>>> fluxes.withdrawal = 1.0, 2.0
>>> model.calc_totalwithdrawal_v1()
>>> fluxes.totalwithdrawal
totalwithdrawal(1.2)
class hydpy.models.ga.ga_model.Calc_TotalSurfaceRunoff_V1[source]

Bases: Method

Calculate the average surface runoff from all soil compartments.

Requires the control parameter:

NmbSoils

Requires the derived parameter:

SoilAreaFraction

Requires the flux sequence:

SurfaceRunoff

Calculates the flux sequence:

TotalSurfaceRunoff

Basic equation:

\(TotalSurfaceRunoff = \sum_{i=1}^{NmbSoils} SoilAreaFraction_i \cdot SurfaceRunoff_i\)

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> derived.soilareafraction(0.8, 0.2)
>>> fluxes.surfacerunoff = 1.0, 2.0
>>> model.calc_totalsurfacerunoff_v1()
>>> fluxes.totalsurfacerunoff
totalsurfacerunoff(1.2)
class hydpy.models.ga.ga_model.Set_InitialSurfaceWater_V1[source]

Bases: Method

Set the given initial surface water depth for the selected soil compartment.

Requires the control parameter:

DT

Calculates the aide sequence:

InitialSurfaceWater

Example:

Note that Set_InitialSurfaceWater_V1 multiplies the given value with DT to adjust it to the numerical substep width:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> dt.value = 0.5
>>> model.set_initialsurfacewater_v1(0, 2.0)
>>> model.set_initialsurfacewater_v1(1, 4.0)
>>> aides.initialsurfacewater
initialsurfacewater(1.0, 2.0)
class hydpy.models.ga.ga_model.Set_ActualSurfaceWater_V1[source]

Bases: Method

Set the given actual surface water depth for the selected soil compartment.

Requires the control parameter:

DT

Calculates the aide sequence:

ActualSurfaceWater

Example:

Note that Set_ActualSurfaceWater_V1 multiplies the given value with DT to adjust it to the numerical substep width:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> dt.value = 0.5
>>> model.set_actualsurfacewater_v1(0, 2.0)
>>> model.set_actualsurfacewater_v1(1, 4.0)
>>> aides.actualsurfacewater
actualsurfacewater(1.0, 2.0)
class hydpy.models.ga.ga_model.Set_SoilWaterSupply_V1[source]

Bases: Method

Set the (potential) water supply to the soil’s body.

Calculates the flux sequence:

SoilWaterSupply

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> model.set_soilwatersupply_v1(0, 2.0)
>>> model.set_soilwatersupply_v1(1, 4.0)
>>> fluxes.soilwatersupply
soilwatersupply(2.0, 4.0)
class hydpy.models.ga.ga_model.Set_SoilWaterDemand_V1[source]

Bases: Method

Set the (potential) water withdrawal from the soil’s surface and body.

Calculates the flux sequence:

Demand

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> model.set_soilwaterdemand_v1(0, 2.0)
>>> model.set_soilwaterdemand_v1(1, 4.0)
>>> fluxes.demand
demand(2.0, 4.0)
class hydpy.models.ga.ga_model.Execute_Infiltration_V1[source]

Bases: Method

Calculate infiltration (and percolation).

Required submethods:

Return_LastActiveBin_V1 Return_Conductivity_V1 Return_DryDepth_V1 Return_CapillaryDrive_V1 Percolate_FilledBin_V1 Infiltrate_WettingFrontBins_V1 Merge_FrontDepthOvershootings_V1 Merge_SoilDepthOvershootings_V1

Requires the control parameters:

NmbBins DT SoilDepth ResidualMoisture SaturationMoisture SaturatedConductivity AirEntryPotential PoreSizeDistribution

Requires the derived parameters:

NmbSubsteps EffectiveCapillarySuction

Requires the aide sequence:

InitialSurfaceWater

Updates the state sequences:

Moisture FrontDepth

Updates the log sequence:

MoistureChange

Updates the aide sequence:

ActualSurfaceWater

Calculates the flux sequences:

Infiltration Percolation SurfaceRunoff

The interface method Execute_Infiltration_V1 subsequently executes the GARTO methods Percolate_FilledBin_V1, Infiltrate_WettingFrontBins_V1, Merge_FrontDepthOvershootings_V1, and Merge_SoilDepthOvershootings_V1 for all numerical substeps.

class hydpy.models.ga.ga_model.Add_SoilWater_V1[source]

Bases: Method

Add the (direct) soil water supply to the soil’s body.

Required submethod:

Water_AllBins_V1

Requires the control parameters:

NmbBins SoilDepth SaturationMoisture

Requires the flux sequence:

SoilWaterSupply

Updates the state sequences:

FrontDepth Moisture

Updates the log sequence:

MoistureChange

Calculates the flux sequence:

SoilWaterAddition

The interface method Add_SoilWater_V1 only calls Withdraw_AllBins_V1.

class hydpy.models.ga.ga_model.Remove_SoilWater_V1[source]

Bases: Method

Remove the water demand from the soil’s body and eventually from the soil’s surface.

Required submethod:

Withdraw_AllBins_V1

Requires the control parameters:

NmbBins SoilDepth ResidualMoisture

Requires the flux sequence:

Demand

Updates the state sequences:

FrontDepth Moisture

Updates the aide sequence:

ActualSurfaceWater

Calculates the flux sequence:

Withdrawal

The interface method Remove_SoilWater_V1 only calls Withdraw_AllBins_V1. Hence, whether Remove_SoilWater_V1 can remove surface water depends on the order the different interface methods are applied and is thus a decision of the calling model.

class hydpy.models.ga.ga_model.Get_Infiltration_V1[source]

Bases: Method

Get the current infiltration to the selected soil compartment.

Calculates the flux sequence:

Infiltration

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> fluxes.infiltration = 2.0, 4.0
>>> from hydpy import round_
>>> round_(model.get_infiltration_v1(0))
2.0
>>> round_(model.get_infiltration_v1(1))
4.0
class hydpy.models.ga.ga_model.Get_Percolation_V1[source]

Bases: Method

Get the current percolation from the selected soil compartment.

Calculates the flux sequence:

Percolation

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> fluxes.percolation = 2.0, 4.0
>>> from hydpy import round_
>>> round_(model.get_percolation_v1(0))
2.0
>>> round_(model.get_percolation_v1(1))
4.0
class hydpy.models.ga.ga_model.Get_SoilWaterAddition_V1[source]

Bases: Method

Get the current soil water addition to the selected soil compartment.

Calculates the flux sequence:

SoilWaterAddition

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> fluxes.soilwateraddition = 2.0, 4.0
>>> from hydpy import round_
>>> round_(model.get_soilwateraddition_v1(0))
2.0
>>> round_(model.get_soilwateraddition_v1(1))
4.0
class hydpy.models.ga.ga_model.Get_SoilWaterRemoval_V1[source]

Bases: Method

Get the current soil (and surface water) withdrawal from the selected soil compartment.

Calculates the flux sequence:

Withdrawal

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> fluxes.withdrawal = 2.0, 4.0
>>> from hydpy import round_
>>> round_(model.get_soilwaterremoval_v1(0))
2.0
>>> round_(model.get_soilwaterremoval_v1(1))
4.0
class hydpy.models.ga.ga_model.Get_SoilWaterContent_V1[source]

Bases: Method

Get the current soil water content of the selected soil compartment.

Requires the control parameters:

NmbBins Sealed SoilDepth

Requires the state sequences:

Moisture FrontDepth

Basic equation:

\(SoilWaterContent = Moisture_1 \cdot SoilDepth + \sum_{i=2}^{NmbBins} (Moisture_i - Moisture_{i-1}) \cdot FrontDepth_i\)

Example:

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(3)
>>> nmbbins(4)
>>> sealed(False, False, True)
>>> soilarea(1.0, 2.0, 3.0)
>>> soildepth(100.0, 200, nan)
>>> residualmoisture(0.1, 0.2, nan)
>>> saturationmoisture(0.5, 0.8, nan)
>>> states.moisture = [[0.3, 0.2, nan],
...                    [0.3, 0.3, nan],
...                    [0.3, 0.5, nan],
...                    [0.3, 0.8, nan]]
>>> states.frontdepth = [[100.0, 200.0, nan],
...                      [0.0, 150.0, nan],
...                      [0.0, 100.0, nan],
...                      [0.0, 50.0, nan]]
>>> from hydpy import round_
>>> round_(model.get_soilwatercontent_v1(0))
30.0
>>> round_(model.get_soilwatercontent_v1(1))
90.0
>>> round_(model.get_soilwatercontent_v1(2))
0.0
class hydpy.models.ga.ga_model.BaseModel[source]

Bases: AdHocModel

General base class for GARTO-like Green-Ampt models.

check_waterbalance(initial_conditions: dict[str, dict[str, dict[str, float | ndarray[Any, dtype[float64]]]]]) float[source]

Determine the water balance error of the previous simulation run in mm.

Method check_waterbalance() calculates the balance error as follows:

\(\sum_{t=t0}^{t1} \big( Rainfall_t - TotalPercolation_t + TotalSoilWaterAddition_t - TotalWithdrawal_t - Percolation_t \big) +b\big( WaterVolume_{t0} - WaterVolume_{t1} \big)\)

The returned error should always be in scale with numerical precision so that it does not affect the simulation results in any relevant manner.

Pick the required initial conditions before starting the simulation via property conditions. See the integration tests of the application model ga_garto for some examples.

property watercontents: ndarray[Any, dtype[float64]]

The unique water content of each soil compartment in mm.

Property watercontents generally returns zero values for sealed soil compartments:

>>> from hydpy.models.ga_garto import *
>>> parameterstep()
>>> nmbsoils(3)
>>> nmbbins(4)
>>> sealed(False, False, True)
>>> soilarea(1.0, 2.0, 3.0)
>>> soildepth(100.0, 200, nan)
>>> residualmoisture(0.1, 0.2, nan)
>>> saturationmoisture(0.5, 0.8, nan)
>>> derived.soilareafraction.update()
>>> states.moisture = [[0.3, 0.2, nan],
...                    [0.3, 0.3, nan],
...                    [0.3, 0.5, nan],
...                    [0.3, 0.8, nan]]
>>> states.frontdepth = [[100.0, 200.0, nan],
...                      [0.0, 150.0, nan],
...                      [0.0, 100.0, nan],
...                      [0.0, 50.0, nan]]
>>> from hydpy import print_vector
>>> print_vector(model.watercontents)
30.0, 90.0, 0.0
property watercontent: float

The average water content of all soil compartments in mm.

Property watercontent includes sealed soil compartments in the average, which is why the presence of sealing reduces the returned value:

>>> from hydpy.models.ga_garto import *
>>> parameterstep()
>>> nmbsoils(3)
>>> nmbbins(4)
>>> sealed(False, False, True)
>>> soilarea(1.0, 2.0, 3.0)
>>> soildepth(100.0, 200, nan)
>>> residualmoisture(0.1, 0.2, nan)
>>> saturationmoisture(0.5, 0.8, nan)
>>> derived.soilareafraction.update()
>>> states.moisture = [[0.3, 0.2, nan],
...                    [0.3, 0.3, nan],
...                    [0.3, 0.5, nan],
...                    [0.3, 0.8, nan]]
>>> states.frontdepth = [[100.0, 200.0, nan],
...                      [0.0, 150.0, nan],
...                      [0.0, 100.0, nan],
...                      [0.0, 50.0, nan]]
>>> from hydpy import round_
>>> round_(model.watercontent)
35.0
>>> soilarea(1.0, 2.0, 0.0)
>>> derived.soilareafraction.update()
>>> round_(model.watercontent)
70.0
REUSABLE_METHODS: ClassVar[tuple[type[ReusableMethod], ...]] = ()
class hydpy.models.ga.ga_model.Base_SoilModel_V1[source]

Bases: BaseModel, SoilModel_V1

Base class for HydPy-GA models that comply with the SoilModel_V1 submodel interface.

prepare_nmbzones

Set the number of soil compartments.

>>> from hydpy.models.ga_garto_submodel1 import *
>>> parameterstep()
>>> model.prepare_nmbzones(2)
>>> nmbsoils
nmbsoils(2)
REUSABLE_METHODS: ClassVar[tuple[type[ReusableMethod], ...]] = ()
cymodel: CyModelProtocol | None
parameters: parametertools.Parameters
sequences: sequencetools.Sequences
masks: masktools.Masks
DOCNAME: DocName

Parameter Features

Control parameters

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

Bases: SubParameters

Control parameters of model ga.

The following classes are selected:
class hydpy.models.ga.ga_control.NmbSoils(subvars: SubParameters)[source]

Bases: Parameter

The number of separately modelled soil compartments in the subbasin [-].

Required by the methods:

Calc_Demand_V1 Calc_SoilWaterSupply_V1 Calc_SurfaceWaterSupply_V1 Calc_TotalInfiltration_V1 Calc_TotalPercolation_V1 Calc_TotalSoilWaterAddition_V1 Calc_TotalSurfaceRunoff_V1 Calc_TotalWithdrawal_V1 Perform_GARTO_V1

NDIM: int = 0
TYPE

alias of int

TIME: bool | None = None
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (1, None)
name: str = 'nmbsoils'

Name of the variable in lowercase letters.

unit: str = '-'

Unit of the variable.

class hydpy.models.ga.ga_control.NmbBins(subvars: SubParameters)[source]

Bases: Parameter

The number of available bins for each soil compartment [-].

Required by the methods:

Add_SoilWater_V1 Execute_Infiltration_V1 Get_SoilWaterContent_V1 Infiltrate_WettingFrontBins_V1 Merge_FrontDepthOvershootings_V1 Merge_SoilDepthOvershootings_V1 Perform_GARTO_V1 Redistribute_Front_V1 Remove_SoilWater_V1 Return_LastActiveBin_V1 Shift_Front_V1 Water_AllBins_V1 Withdraw_AllBins_V1

Each soil compartment consists of multiple bins. Bins are the “places” where we model individual wetting fronts with different relative moisture values. Hence, NmbBins determines the maximum number of wetting fronts we can simulate simultaneously.

The first bin is unique, as it is always “filled” (as if its wetting front covers the considered soil column completely). Hence, for a single 1-front Green & Ampt calculation, one must prepare (at least) two bins. Then, the first bin handles the initial soil moisture, while the second bin handles the wetting front’s moisture and depth.

NDIM: int = 0
TYPE

alias of int

TIME: bool | None = None
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (2, None)
name: str = 'nmbbins'

Name of the variable in lowercase letters.

unit: str = '-'

Unit of the variable.

class hydpy.models.ga.ga_control.DT(subvars: SubParameters)[source]

Bases: Parameter

The length of the numerical substeps [T].

Required by the methods:

Active_Bin_V1 Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Percolate_FilledBin_V1 Perform_GARTO_V1 Redistribute_Front_V1 Return_DryDepth_V1 Set_ActualSurfaceWater_V1 Set_InitialSurfaceWater_V1 Shift_Front_V1

NDIM: int = 0
TYPE

alias of float

TIME: bool | None = False
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (None, None)
trim(lower=None, upper=None) bool[source]

Adjust DT when necessary, so the simulation period is an integer multiple.

Assume we want to perform a simulation over intervals of 30 minutes but define DT in hours:

>>> from hydpy.models.ga import *
>>> simulationstep("30m")
>>> parameterstep("1h")

A tenth of an hour then is a fifth of the simulation interval:

>>> dt(0.1)
>>> dt
dt(0.1)
>>> dt.value
0.2

The numerical substeps cannot be longer than the simulation intervals:

>>> dt(1.0)
>>> dt
dt(0.5)

Zero or negative values are also impossible, of course. The chosen minimum numerical stepsize is one second:

>>> dt(0.0)
>>> dt
dt(0.000278)
>>> from hydpy import pub
>>> with pub.options.parameterstep("1s"):
...     dt
dt(1.0)

When necessary, values within the allowed range are reduced to ensure the simulation interval is an integer multiple:

>>> dt(0.3)
>>> dt
dt(0.25)
name: str = 'dt'

Name of the variable in lowercase letters.

unit: str = 'T'

Unit of the variable.

class hydpy.models.ga.ga_control.Sealed(subvars: SubParameters)[source]

Bases: Parameter

Flag indicating if a (soil) compartment is sealed for infiltration [-].

Required by the methods:

Get_SoilWaterContent_V1 Perform_GARTO_V1

NDIM: int = 1
TYPE

alias of bool

TIME: bool | None = None
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (False, True)
name: str = 'sealed'

Name of the variable in lowercase letters.

unit: str = '-'

Unit of the variable.

class hydpy.models.ga.ga_control.SoilArea(subvars: SubParameters)[source]

Bases: Parameter

The area of each soil compartment [km²].

NDIM: int = 1
TYPE

alias of float

TIME: bool | None = None
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (0.0, None)
name: str = 'soilarea'

Name of the variable in lowercase letters.

unit: str = 'km²'

Unit of the variable.

class hydpy.models.ga.ga_control.SoilDepth(subvars: SubParameters)[source]

Bases: Parameter

Depth of the considered soil domains [mm].

Required by the methods:

Active_Bin_V1 Add_SoilWater_V1 Execute_Infiltration_V1 Get_SoilWaterContent_V1 Infiltrate_WettingFrontBins_V1 Merge_SoilDepthOvershootings_V1 Percolate_FilledBin_V1 Perform_GARTO_V1 Redistribute_Front_V1 Remove_SoilWater_V1 Shift_Front_V1 Water_AllBins_V1 Withdraw_AllBins_V1

NDIM: int = 1
TYPE

alias of float

TIME: bool | None = None
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (0.0, None)
name: str = 'soildepth'

Name of the variable in lowercase letters.

unit: str = 'mm'

Unit of the variable.

class hydpy.models.ga.ga_control.ResidualMoisture(subvars: SubParameters)[source]

Bases: Parameter

Relative residual water content [-].

Required by the methods:

Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Percolate_FilledBin_V1 Perform_GARTO_V1 Redistribute_Front_V1 Remove_SoilWater_V1 Return_CapillaryDrive_V1 Return_Conductivity_V1 Return_RelativeMoisture_V1 Shift_Front_V1 Withdraw_AllBins_V1

NDIM: int = 1
TYPE

alias of float

TIME: bool | None = None
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (0.0, 1.0)
trim(lower=None, upper=None) bool[source]

Trim ResidualMoisture following \(0 \leq ResidualMoisture \leq SaturationMoisture \leq 1\).

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(5)
>>> residualmoisture(-0.5, 0.0, 0.5, 1.0, 1.5)
>>> residualmoisture
residualmoisture(0.0, 0.0, 0.5, 1.0, 1.0)
>>> saturationmoisture.values = 0.4, 0.5, 0.6, 0.7, 0.8
>>> residualmoisture(0.6)
>>> residualmoisture
residualmoisture(0.4, 0.5, 0.6, 0.6, 0.6)
name: str = 'residualmoisture'

Name of the variable in lowercase letters.

unit: str = '-'

Unit of the variable.

class hydpy.models.ga.ga_control.SaturationMoisture(subvars: SubParameters)[source]

Bases: Parameter

Relative saturation water content [-].

Required by the methods:

Active_Bin_V1 Add_SoilWater_V1 Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Percolate_FilledBin_V1 Perform_GARTO_V1 Redistribute_Front_V1 Return_CapillaryDrive_V1 Return_Conductivity_V1 Return_DryDepth_V1 Return_RelativeMoisture_V1 Shift_Front_V1 Water_AllBins_V1

NDIM: int = 1
TYPE

alias of float

TIME: bool | None = None
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (0.0, 1.0)
trim(lower=None, upper=None) bool[source]

Trim SaturationMoisture following \(0 \leq ResidualMoisture \leq SaturationMoisture \leq 1\).

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(5)
>>> saturationmoisture(-0.5, 0.0, 0.5, 1.0, 1.5)
>>> saturationmoisture
saturationmoisture(0.0, 0.0, 0.5, 1.0, 1.0)
>>> residualmoisture.values = 0.2, 0.3, 0.4, 0.5, 0.6
>>> saturationmoisture(0.4)
>>> saturationmoisture
saturationmoisture(0.4, 0.4, 0.4, 0.5, 0.6)
name: str = 'saturationmoisture'

Name of the variable in lowercase letters.

unit: str = '-'

Unit of the variable.

class hydpy.models.ga.ga_control.SaturatedConductivity(subvars: SubParameters)[source]

Bases: Parameter

Saturated hydraulic conductivity [mm/T].

Required by the methods:

Active_Bin_V1 Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Percolate_FilledBin_V1 Perform_GARTO_V1 Redistribute_Front_V1 Return_Conductivity_V1 Return_DryDepth_V1 Shift_Front_V1

NDIM: int = 1
TYPE

alias of float

TIME: bool | None = True
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (0.0, None)
name: str = 'saturatedconductivity'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_control.PoreSizeDistribution(subvars: SubParameters)[source]

Bases: Parameter

Pore-size distribution parameter [-].

Required by the methods:

Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Percolate_FilledBin_V1 Perform_GARTO_V1 Redistribute_Front_V1 Return_CapillaryDrive_V1 Return_Conductivity_V1 Shift_Front_V1

NDIM: int = 1
TYPE

alias of float

TIME: bool | None = None
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (0.0, None)
name: str = 'poresizedistribution'

Name of the variable in lowercase letters.

unit: str = '-'

Unit of the variable.

class hydpy.models.ga.ga_control.AirEntryPotential(subvars: SubParameters)[source]

Bases: Parameter

Air entry potential [mm].

Required by the methods:

Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Perform_GARTO_V1 Redistribute_Front_V1 Return_CapillaryDrive_V1 Shift_Front_V1

NDIM: int = 1
TYPE

alias of float

TIME: bool | None = None
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (0.0, None)
name: str = 'airentrypotential'

Name of the variable in lowercase letters.

unit: str = 'mm'

Unit of the variable.

Derived parameters

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

Bases: SubParameters

Derived parameters of model ga.

The following classes are selected:
class hydpy.models.ga.ga_derived.NmbSubsteps(subvars: SubParameters)[source]

Bases: Parameter

The number of numerical substeps in each simulation step [-].

Required by the methods:

Execute_Infiltration_V1 Perform_GARTO_V1

NDIM: int = 0
TYPE

alias of int

TIME: bool | None = None
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (1, inf)
update() None[source]

Calculate the number of substeps based on \(NmbSubsteps = 1 / DT\).

>>> from hydpy.models.ga import *
>>> simulationstep("1h")
>>> parameterstep("1h")
>>> dt(0.5)
>>> derived.nmbsubsteps.update()
>>> derived.nmbsubsteps
nmbsubsteps(2)
name: str = 'nmbsubsteps'

Name of the variable in lowercase letters.

unit: str = '-'

Unit of the variable.

class hydpy.models.ga.ga_derived.SoilAreaFraction(subvars: SubParameters)[source]

Bases: Parameter

The area fraction of each soil compartment [-].

Required by the methods:

Calc_TotalInfiltration_V1 Calc_TotalPercolation_V1 Calc_TotalSoilWaterAddition_V1 Calc_TotalSurfaceRunoff_V1 Calc_TotalWithdrawal_V1

NDIM: int = 1
TYPE

alias of float

TIME: bool | None = None
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (0.0, 1.0)
update() None[source]

Calculate the fractions based on \(SoilAreaFraction_i = SoilArea_i / \Sigma SoilArea\).

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(5)
>>> soilarea(10.0, 40.0, 20.0, 25.0, 5.0)
>>> derived.soilareafraction.update()
>>> derived.soilareafraction
soilareafraction(0.1, 0.4, 0.2, 0.25, 0.05)
name: str = 'soilareafraction'

Name of the variable in lowercase letters.

unit: str = '-'

Unit of the variable.

class hydpy.models.ga.ga_derived.EffectiveCapillarySuction(subvars: SubParameters)[source]

Bases: Parameter

The effective capillary suction according to the Brooks-Corey soil moisture characteristic model (Brooks and Corey, 1966) [mm].

Required by the methods:

Active_Bin_V1 Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Perform_GARTO_V1 Redistribute_Front_V1 Return_DryDepth_V1 Shift_Front_V1

NDIM: int = 1
TYPE

alias of float

TIME: bool | None = None
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (0.0, None)
update() None[source]

Calculate the effective capillary suction based on the current values of AirEntryPotential and PoreSizeDistribution.

The used equation follows equation 13 of Lai et al. (2015) if setting the initial equal to the residual water content:

\(EffectiveCapillarySuction = AirEntryPotential \cdot \frac{3 \cdot PoreSizeDistribution + 2}{3 \cdot PoreSizeDistribution + 1}\)

name: str = 'effectivecapillarysuction'

Name of the variable in lowercase letters.

unit: str = 'mm'

Unit of the variable.

Sequence Features

Input sequences

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

Bases: InputSequences

Input sequences of model ga.

The following classes are selected:
class hydpy.models.ga.ga_inputs.Rainfall(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: InputSequence

Rainfall [mm/T].

Required by the method:

Calc_SurfaceWaterSupply_V1

NDIM: int = 0
NUMERIC: bool = False
STANDARD_NAME: ClassVar[StandardInputNames] = 'precipitation'
name: str = 'rainfall'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_inputs.CapillaryRise(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: InputSequence

Capillary rise [mm/T].

Required by the method:

Calc_SoilWaterSupply_V1

NDIM: int = 0
NUMERIC: bool = False
STANDARD_NAME: ClassVar[StandardInputNames] = 'capillary_rise'
name: str = 'capillaryrise'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_inputs.Evaporation(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: InputSequence

Evaporation [mm/T].

Required by the method:

Calc_Demand_V1

NDIM: int = 0
NUMERIC: bool = False
STANDARD_NAME: ClassVar[StandardInputNames] = 'evapotranspiration'
name: str = 'evaporation'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

Flux sequences

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

Bases: FluxSequences

Flux sequences of model ga.

The following classes are selected:
class hydpy.models.ga.ga_fluxes.SurfaceWaterSupply(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: FluxSequence

Water supply to the soil’s surface [mm/T].

Calculated by the method:

Calc_SurfaceWaterSupply_V1

Required by the method:

Perform_GARTO_V1

NDIM: int = 1
NUMERIC: bool = False
name: str = 'surfacewatersupply'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_fluxes.SoilWaterSupply(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: FluxSequence

Water supply to the soil’s body (e.g., capillary rise) [mm/T].

Calculated by the methods:

Calc_SoilWaterSupply_V1 Set_SoilWaterSupply_V1

Required by the methods:

Add_SoilWater_V1 Perform_GARTO_V1

NDIM: int = 1
NUMERIC: bool = False
name: str = 'soilwatersupply'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_fluxes.Demand(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: FluxSequence

(Potential) water withdrawal from the soil’s surface and body [mm/T].

Calculated by the methods:

Calc_Demand_V1 Set_SoilWaterDemand_V1

Required by the methods:

Perform_GARTO_V1 Remove_SoilWater_V1

NDIM: int = 1
NUMERIC: bool = False
name: str = 'demand'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_fluxes.Infiltration(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: FluxSequence

Infiltration through the soil’s surface [mm/T].

Calculated by the methods:

Execute_Infiltration_V1 Get_Infiltration_V1 Perform_GARTO_V1

Required by the method:

Calc_TotalInfiltration_V1

NDIM: int = 1
NUMERIC: bool = False
name: str = 'infiltration'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_fluxes.Percolation(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: FluxSequence

Percolation through the soil’s bottom [mm/T].

Calculated by the methods:

Execute_Infiltration_V1 Get_Percolation_V1 Perform_GARTO_V1

Updated by the methods:

Merge_SoilDepthOvershootings_V1 Percolate_FilledBin_V1

Required by the method:

Calc_TotalPercolation_V1

NDIM: int = 1
NUMERIC: bool = False
name: str = 'percolation'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_fluxes.SoilWaterAddition(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: FluxSequence

Actual addition of soil water due to processes like capillary rise [mm/T].

Calculated by the methods:

Add_SoilWater_V1 Get_SoilWaterAddition_V1 Perform_GARTO_V1

Updated by the method:

Water_AllBins_V1

Required by the method:

Calc_TotalSoilWaterAddition_V1

NDIM: int = 1
NUMERIC: bool = False
name: str = 'soilwateraddition'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_fluxes.Withdrawal(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: FluxSequence

Withdrawal from the soil’s surface or body (e.g. due to evaporation) [mm/T].

Calculated by the methods:

Get_SoilWaterRemoval_V1 Perform_GARTO_V1 Remove_SoilWater_V1

Updated by the method:

Withdraw_AllBins_V1

Required by the method:

Calc_TotalWithdrawal_V1

NDIM: int = 1
NUMERIC: bool = False
name: str = 'withdrawal'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_fluxes.SurfaceRunoff(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: FluxSequence

Surface runoff [mm/T].

Calculated by the methods:

Execute_Infiltration_V1 Perform_GARTO_V1

Required by the method:

Calc_TotalSurfaceRunoff_V1

NDIM: int = 1
NUMERIC: bool = False
name: str = 'surfacerunoff'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_fluxes.TotalInfiltration(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: FluxSequence

Average infiltration of the whole subbasin [mm/T].

Calculated by the method:

Calc_TotalInfiltration_V1

NDIM: int = 0
NUMERIC: bool = False
name: str = 'totalinfiltration'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_fluxes.TotalPercolation(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: FluxSequence

Average percolation of the whole subbasin [mm/T].

Calculated by the method:

Calc_TotalPercolation_V1

NDIM: int = 0
NUMERIC: bool = False
name: str = 'totalpercolation'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_fluxes.TotalSoilWaterAddition(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: FluxSequence

Average soil water addition to the whole subbasin [mm/T].

Calculated by the method:

Calc_TotalSoilWaterAddition_V1

NDIM: int = 0
NUMERIC: bool = False
name: str = 'totalsoilwateraddition'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_fluxes.TotalWithdrawal(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: FluxSequence

Average withdrawal of the whole subbasin [mm/T].

Calculated by the method:

Calc_TotalWithdrawal_V1

NDIM: int = 0
NUMERIC: bool = False
name: str = 'totalwithdrawal'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

class hydpy.models.ga.ga_fluxes.TotalSurfaceRunoff(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: FluxSequence

Average surface runoff of the whole subbasin [mm/T].

Calculated by the method:

Calc_TotalSurfaceRunoff_V1

NDIM: int = 0
NUMERIC: bool = False
name: str = 'totalsurfacerunoff'

Name of the variable in lowercase letters.

unit: str = 'mm/T'

Unit of the variable.

State sequences

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

Bases: StateSequences

State sequences of model ga.

The following classes are selected:
  • Moisture() The relative soil moisture of each bin (within the wetting front) [-].

  • FrontDepth() The depth of the wetting front in each bin [-].

class hydpy.models.ga.ga_states.Moisture(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: StateSequence

The relative soil moisture of each bin (within the wetting front) [-].

Updated by the methods:

Active_Bin_V1 Add_SoilWater_V1 Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Merge_FrontDepthOvershootings_V1 Merge_SoilDepthOvershootings_V1 Perform_GARTO_V1 Redistribute_Front_V1 Remove_SoilWater_V1 Shift_Front_V1 Water_AllBins_V1 Withdraw_AllBins_V1

Required by the methods:

Get_SoilWaterContent_V1 Percolate_FilledBin_V1 Return_CapillaryDrive_V1 Return_Conductivity_V1 Return_DryDepth_V1 Return_LastActiveBin_V1 Return_RelativeMoisture_V1

The current moisture of inactive bins usually equals the “initial moisture” of the first “filled” bin. However, withdrawal (e.g. due to evaporation) can result in moisture values of inactive bins larger than the initial moisture.

ToDo: What is the reason behind this behaviour? Can we change it?

NDIM: int = 2
NUMERIC: bool = False
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (0.0, 1.0)
trim(lower=None, upper=None) bool[source]

Trim the relative moisture following \(ResidualMoisture \leq Moisture \leq SaturationMoisture\).

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> nmbbins(5)
>>> residualmoisture(0.2, 0.4)
>>> saturationmoisture(0.8, 0.6)
>>> states.moisture([[0.0, 0.0],
...                  [0.2, 0.4],
...                  [0.5, 0.5],
...                  [0.8, 0.6],
...                  [1.0, 1.0]])
>>> states.moisture
moisture([[0.2, 0.4],
          [0.2, 0.4],
          [0.5, 0.5],
          [0.8, 0.6],
          [0.8, 0.6]])
name: str = 'moisture'

Name of the variable in lowercase letters.

unit: str = '-'

Unit of the variable.

class hydpy.models.ga.ga_states.FrontDepth(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: StateSequence

The depth of the wetting front in each bin [-].

Updated by the methods:

Active_Bin_V1 Add_SoilWater_V1 Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Merge_FrontDepthOvershootings_V1 Merge_SoilDepthOvershootings_V1 Percolate_FilledBin_V1 Perform_GARTO_V1 Redistribute_Front_V1 Remove_SoilWater_V1 Shift_Front_V1 Water_AllBins_V1 Withdraw_AllBins_V1

Required by the method:

Get_SoilWaterContent_V1

The current wetting front depth of inactive bins is zero. But zero front depth does not necessarily mean a bin is inactive.

NDIM: int = 2
NUMERIC: bool = False
SPAN: tuple[int | float | bool | None, int | float | bool | None] = (0.0, None)
trim(lower=None, upper=None) bool[source]

Trim the wetting front depth following \(0 \leq FrontDepth \leq SoilDepth\).

>>> from hydpy.models.ga import *
>>> parameterstep()
>>> nmbsoils(2)
>>> nmbbins(5)
>>> soildepth(100.0, 500.0)
>>> states.frontdepth([[-10.0, -10.0],
...                    [0.0, 0.0],
...                    [50.0, 250.0],
...                    [100.0, 500.0],
...                    [110.0, 510.0]])
>>> states.frontdepth
frontdepth([[0.0, 0.0],
            [0.0, 0.0],
            [50.0, 250.0],
            [100.0, 500.0],
            [100.0, 500.0]])
name: str = 'frontdepth'

Name of the variable in lowercase letters.

unit: str = '-'

Unit of the variable.

Log sequences

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

Bases: LogSequences

Log sequences of model ga.

The following classes are selected:
class hydpy.models.ga.ga_logs.MoistureChange(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: LogSequence

The (last) change in soil moisture of each bin [-].

Updated by the methods:

Active_Bin_V1 Add_SoilWater_V1 Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Merge_FrontDepthOvershootings_V1 Merge_SoilDepthOvershootings_V1 Perform_GARTO_V1 Redistribute_Front_V1 Shift_Front_V1 Water_AllBins_V1

Some methods of ga_garto take the direction of the last moisture change as a marker for a bin’s state:

ToDo: Would constants like “INACTIVE” or “REDISTRIBUTION” simplify the methods?

NDIM: int = 2
NUMERIC: bool = False
name: str = 'moisturechange'

Name of the variable in lowercase letters.

unit: str = '-'

Unit of the variable.

Aide sequences

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

Bases: AideSequences

Aide sequences of model ga.

The following classes are selected:
class hydpy.models.ga.ga_aides.InitialSurfaceWater(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: AideSequence

The initial surface water depth at the beginning of a numerical substep [mm].

Calculated by the method:

Set_InitialSurfaceWater_V1

Updated by the method:

Perform_GARTO_V1

Required by the methods:

Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Shift_Front_V1

NDIM: int = 1
NUMERIC: bool = False
name: str = 'initialsurfacewater'

Name of the variable in lowercase letters.

unit: str = 'mm'

Unit of the variable.

class hydpy.models.ga.ga_aides.ActualSurfaceWater(subvars: ModelSequences[ModelSequence, FastAccess])[source]

Bases: AideSequence

The actual surface water depth [mm].

Calculated by the method:

Set_ActualSurfaceWater_V1

Updated by the methods:

Active_Bin_V1 Execute_Infiltration_V1 Infiltrate_WettingFrontBins_V1 Percolate_FilledBin_V1 Perform_GARTO_V1 Redistribute_Front_V1 Remove_SoilWater_V1 Shift_Front_V1 Withdraw_AllBins_V1

NDIM: int = 1
NUMERIC: bool = False
name: str = 'actualsurfacewater'

Name of the variable in lowercase letters.

unit: str = 'mm'

Unit of the variable.

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

Bases: AideSequences

Aide sequences of model ga.

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

Bases: SubParameters

Control parameters of model ga.

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

Bases: SubParameters

Derived parameters of model ga.

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

Bases: FluxSequences

Flux sequences of model ga.

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

Bases: InputSequences

Input sequences of model ga.

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

Bases: LogSequences

Log sequences of model ga.

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

Bases: StateSequences

State sequences of model ga.

The following classes are selected:
  • Moisture() The relative soil moisture of each bin (within the wetting front) [-].

  • FrontDepth() The depth of the wetting front in each bin [-].