hydpy-dev / hydpy

A framework for the development and application of hydrological models based on Python
GNU Lesser General Public License v3.0
35 stars 16 forks source link

Modularisation: submodel interfaces for potential evapotranspiration #95

Closed tyralla closed 1 year ago

tyralla commented 1 year ago

Starting with issue #90, we introduced a new submodel concept for improving the modularisation level of the models implemented in HydPy. The first concrete realisation is the GARTO submodel, which can be added to HydPy-L (and, in the future, to other main models as well) to simulate the effects of infiltration excess on runoff generation. This realisation of the submodel concept works, but we still need to work out many details to improve its usability. However, before doing so, we prefer to start another realisation to gain more experience on possible use cases.

The second possible use case is a potential evapotranspiration interface. So far, our only effort to factor out evapotranspiration was to implement evap_v001(which we now name evap_fao). evap_fao calculates the FAO grass reference evapotranspiration, and main models like lland_v2 and wland_v001 can take this data as input. However, evap_fao is not really a submodel but is implemented as a stand-alone model which must be connected to other models via the input/output node mechanism. This mechanism (currently) limits us to the exchange of scalar potential evapotranspiration values and requires more configuration effort than desired.

The reason for selecting potential evapotranspiration (pet) as the second use case is that we currently try to extract the Turc-Wendling equation implemented in lland_v1 into the new model evap_tw (or evap_turcwendling?) and the “norm-temperature” approach implemented in all application models of base model hland into the new model evap_hbv (or something like evap_normed or evap_climate?). However, we cannot do so based on the input/output node mechanism. Both approaches do not calculate one scalar pet value per subbasin but individual values for different hydrological response units. We consider this an important feature when working with large subbasins, especially in mountainous regions with steep gradients of temperature and other meteorological factors. (Accordingly, evap_fao currently would not be a good choice in such situations.)

So, this opens the question if we should turn evap_fao into a submodel and design evap_tw and evap_hvb right from the start as submodels. If we decide so, this would likely mean we eliminate the input/output node mechanism sooner or later, which is still marked as an experimental feature in the documentation. The submodel concept has the potential to become superior in most (or all?) regards, and handling two modularisation strategies in parallel seems like an unnecessary effort. Going this way, we would also need to turn all meteo models into submodels.

What would we need to do?

To clarify the "who reads the input data" issue: Most evaporation methods require air temperature input. Snow-related methods do so as well. hland_v1, for example, currently adjusts the average basin temperature to the elevation of individual zones. If we still let hland_v1 do the job, it must do so only once for at least two purposes. Additionally, the evaporation and the snow module would receive consistent temperature estimates. These points speak for letting the main model preprocess the input time series. However, I tend to favour letting the submodels read and process the input data in this case, as it allows for more flexibility. More importantly, this would keep the input data requirements of the involved models transparent. Consider, for example, air pressure, which is required by very few evaporation methods (e.g. evap_fao). If hland_v1 were to supply all input data to the evaporation submodel and evap_fao, it would have to specify air pressure as required but actually use it only under specific configurations. (Regarding consistency: we could also factor out the height adjustment of air temperature so that users could use it as a sub-submodel and be free to select the same approach for different purposes. However, we have not decided if we will support that submodels can reference other submodels. So far, it is not forbidden.)

tyralla commented 1 year ago

Decide if we still need evap_fao as a stand-alone model. This is not required for usual HydPy projects (where we model the complete water balance of river catchments) but would help if we want to calculate pet time series for other purposes.

When implementing (a preliminary?) version of evap_tw, it was easy to make it both a stand-alone model and a submodel. The trick (for an AdHocModel) is to let the appropriate interface method just call the run method. For example:

class Determine_PotentialEvapotranspiration_V2(modeltools.Method):

    SUBMETHODS = (
        Calc_AdjustedAirTemperature_V1,
        Calc_ReferenceEvapotranspiration_V2,
    )
    CONTROLPARAMETERS = (
        evap_control.NmbHRU,
        evap_control.Altitude,
        evap_control.CoastFactor,
        evap_control.EvapotranspirationFactor,
    )
    REQUIREDSEQUENCES = (
        evap_inputs.GlobalRadiation,
        evap_inputs.AirTemperature,
    )
    RESULTSEQUENCES = (evap_fluxes.ReferenceEvapotranspiration,)

    @staticmethod
    def __call__(model: modeltools.AdHocModel) -> None:
        model.run()

This helps avoid code duplications and additional tests. So, there seems to be no reason to refrain from making evap_fao both a stand-alone model and a submodel, as well.

tyralla commented 1 year ago

Decide if the evap submodels read their input data or receive (possibly adjusted) input data from the main model.

We decided on reading. See this comment in #90.

tyralla commented 1 year ago
  • Eventually, support letting submodels read input time series on their own

Again, see this comment in #90.

tyralla commented 1 year ago

I realised only lland_v2 uses method Calc_ET0_WET0_V1 for calculating "delayed" evaporation from water bodies, but lland_v1 does not. I will add it to lland_v1 before removing lland_v2 to not lose any functionalities due to this refactoring.

tyralla commented 1 year ago
  • Increase the dimensionality of the already available parameter and sequence classes of evap from zero to one and adjust all equations accordingly.

Finished. Now, one can use evap_fao56 for calculating reference evapotranspiration for different hydrological response units. The only difference in the computed values stems from a temperature adjustment to (the altitude of) the individual units and, eventually, applying different evapotranspiration adjustment factors.

tyralla commented 1 year ago

Also, I added evap_io for reading reference evapotranspiration time series from files. This allowed fusing lland_v1 and lland_v2, which is also completed (including documentation updates).

tyralla commented 1 year ago

The next step is to let wland use the new reference evapotranspiration submodels. I suspected the implementation would be straightforward but encountered one nasty detail.

wland comes with two sequences for potential evapotranspiration. PETL is 1-dimensional and contains individual values for all "land" units. PES is 0-dimensional and includes a single value for the surface water area.

I see two possible solutions:

  1. Expect that the length of the PET (evap) vector is larger by one than the PET (wland) vector, and say, for example, the first entry of the PET (evap) vector is reserved for wland's surface water area.
  2. Let the user choose two (possibly different) evap models for the PETL and PES.

The latter approach is definitely more flexible and, most likely, less error-prone. The additional configuration effort seems acceptable. However, this conflicts with our current assumption that each primary model instance reference only one submodel of a specific interface (see this comment in #90).

In my opinion, we should extend the general strategy of referencing submodels to make the second solution possible.

sivogel commented 1 year ago

It might take some effort, but I am also convinced that that it will be worthwhile to make this possible. Especially if you think of the evaporation of the LARSIM models this distinction between potential lake and land evapotranspiration simplifies many things.

BGWKlein commented 1 year ago

I would also prefer the 2. option, defining the first time series as wlands urface water area could lead to confusions and contradicts in my opinion the object oriented HydPy approach

tyralla commented 1 year ago

The second option is implemented! And I improved a few related things so far (and switched to Python 3.11!) that I finally dared to merge into master. I need to update Travis' permissions. After that, the online documentation will also be up-to-date.

tyralla commented 1 year ago

So far, we can connect the submodels evap_io, evap_fao56, and evap_tw2002 to all applications models derived from the base models lland and wland. Now it is time to extract evap_hbv96 from hland.

All versions of hland perform the following steps for calculating potential evapotranspiration:

We already discussed some aspects, but we still need to settle our targets before I should start introducing changes.

Nowadays, it is expected to either use externally interpolated meteorological input data or let the hydrological modelling system perform the interpolation on the fly. HydPy supports both approaches. Hence, there seems no need to keep the parameters zrelt, zrele, and zrelp, which are primarily thought for adjusting station data (measured at a specific elevation) to a subbasin (with a different mean elevation). If I remember correctly, we agreed to remove all these control parameters. Instead, we could introduce a single derived parameter that automatically calculates the mean basin elevation based on the zones' elevation and size. We would then use this single parameter for adjusting the (given) basin averages of temperature, evaporation, and precipitation to the individual zones.

If we go this way, most steps are straightforward. We would move the evapotranspiration elevation adjustment factor from hland to evap and leave the temperature elevation adjustment factor in hland.

However, at least one aspect needs extra consideration.

hland has no "specific" parameter to adjust the calculated reference evapotranspiration to different zone types. There is only the parameter ECorr, which could, for example, be used to reflect the different evapotranspiration rates of different crops but could also be configured in other manners. In contrast, lland and wland provide special parameters that adjust reference evapotranspiration based on crop- and month-specific factors. For consistency with our previous modularisation steps, we should move ECorr from hland to evap. But then, ECorr would not be directly connectable to the land-use types of hland.

We could add a parameter to hland that is similar to the mentioned ones of lland and wland. Or, we could move the "land-use-adjustment logic" from all main models to evap. So far, I have no idea how, but I tend to favour the second approach. When thinking about the planned modularisation of actual evaporation processes (!!! extracting MORECS from lland !!!), we may need to synchronise the land-use handling of main models and their submodels anyhow. Should we possibly also standardise land-use types?

I suggest starting as described above (moving ECorr, or, more precisely, removing it from hland and using EvapotranspirationFactor within evap instead) if no one disagrees.

Maybe we can collect ideas on sharing land-use information in the meantime.

tyralla commented 1 year ago

I prefer to implement some significant general submodel functionalities for sharing parameter information before continuing here. See this comment in #90.

tyralla commented 1 year ago

I need to update Travis' permissions. After that, the online documentation will also be up-to-date.

There was also an issue due to pushing unnecessary, too-large files to GitHub Pages. Solved by b8a06173d4621ec1e2c208ec5d62e801a523175e. The online documentation now describes evap_io, evap_fao56, evap_tw2002, and the adjustments to HydPy-L(ARSIM) and HydPy-W(ALRUS).

tyralla commented 1 year ago

We made the necessary progress to continue extraction evap_hbv96 from hland. However, I encountered another problem or necessary decision when starting with it.

HBV96 adjusts the estimated potential evapotranspiration to the current precipitation rate (see Calc_EPC_V1). That means, we evap_hbv96 must know about the precipitation falling in the individual zones. Unfortunately, the required precipitation must also be corrected beforehand, which needs adjusting the air temperature to the heights of the respective zones.

I see the following options:

If no one objects, I check if the third option is feasible.

tyralla commented 1 year ago
  • The only drawback: evap_hbv96 would not work as a stand-alone model.

Just a spontaneous idea: Could we introduce a precip_io model (similar to evap_io)? evap_hbv96 could either take the required precipitation from a precip_io or, and that is the idea, from its main model (by somehow handling its main model like a submodel). It is a first thought we can wait to follow. However, it would be great if something like that would work as it would simplify implementing stand-alone models and increase flexibility significantly.

tyralla commented 1 year ago

evap_hbv96 now works and can query its precipitation data from its main model or a "real" submodel (see here for the technical status). However, the LahnH example project is still out of order since I have not adopted the meteorological input series. And I think we should first allow the same mechanism for air temperature as for precipitation. First, in doing so, we would not need to duplicate huge amounts of the available input data. Second, we will likely introduce "temperature submodels" later, anyhow, which would mean we need to revert some of these changes.

tyralla commented 1 year ago

It seems we are ready. I just pushed all relevant commits to master, the docs are up-to-date. The next step will be refactoring actual evapotranspiration. This might somehow influence our potential evaporation submodels, but this can be discussed in a separate issue. We can re-open this issue if we encounter any general deficits in our potential evapotranspiration models or want to think about fine-tuning parameter names or things like that.