Example using HBV model in eWaterCycle

1         In:
# general python
import warnings
warnings.filterwarnings("ignore", category=UserWarning)

import numpy as np
from pathlib import Path
import pandas as pd
import matplotlib.pyplot as plt
2         In:
# general eWC
import ewatercycle
import ewatercycle.models
import ewatercycle.forcing

Install required plugin with pip:

pip install ewatercycle-HBV

set up paths

3         In:
path = Path.cwd()
forcing_path = path / "Forcing"
forcing_path.mkdir(exist_ok=True)

add parameter info

Array of initial storage terms - we keep these constant for now: Si, Su, Sf, Ss

4         In:
s_0 = np.array([0,  100,  0,  5, 0])

Array of parameters min/max bounds as a reference: Imax, Ce, Sumax, beta, Pmax, T_lag, Kf, Ks

5         In:
p_min_initial= np.array([0,   0.2,  40,    .5,   .001,   1,     .01,  .0001, 6])
p_max_initial = np.array([8,    1,  800,   4,    .3,     10,    .1,   .01, 0.1])
p_names = ["$I_{max}$",  "$C_e$",  "$Su_{max}$", "β",  "$P_{max}$",  "$T_{lag}$",   "$K_f$",   "$K_s$", "FM"]
S_names = ["Interception storage", "Unsaturated Rootzone Storage", "Fastflow storage", "Groundwater storage", "Snowpack storage"]
param_names = ["Imax","Ce",  "Sumax", "Beta",  "Pmax",  "Tlag",   "Kf",   "Ks", "FM"]
stor_names = ["Si", "Su", "Sf", "Ss", "Sp"]

Set initial as mean of max,min

6         In:
par_0 = (p_min_initial + p_max_initial)/2

Specify start and end date

7         In:
experiment_start_date = "1997-08-01T00:00:00Z"
experiment_end_date = "2000-08-31T00:00:00Z"
HRU_id = 1620500
alpha = 1.2626

Forcing

8         In:
from ewatercycle_HBV.forcing import HBVForcing

we use camels forcing as an example, which is fully integrated Newman, 2014. The seperate text file is hosted here for easy access without having to download the whole dataset (13gb).

9         In:
camels_forcing = HBVForcing(start_time = experiment_start_date,
                          end_time = experiment_end_date,
                          directory = forcing_path,
                          camels_file = f'0{HRU_id}_lump_cida_forcing_leap.txt',
                          alpha= alpha
                          )

Setting up the model

10         In:
from ewatercycle.models import HBV
11         In:
model = HBV(forcing=camels_forcing)
12         In:
config_file, _ = model.setup(
            parameters=','.join([str(p) for p in par_0]),
    initial_storage=','.join([str(s) for s in s_0]),
           )
13         In:
model.initialize(config_file)

Running model

14         In:
Q_m = []
time = []
while model.time < model.end_time:
    model.update()
    Q_m.append(model.get_value("Q"))
    time.append(pd.Timestamp(model.time_as_datetime.date()))

After running the model: finalize to shut everything down

15         In:
model.finalize()

Process results

16         In:
df = pd.DataFrame(data=Q_m,columns=["Modeled discharge"],index=time)
17         In:
fig, ax = plt.subplots(1,1)
df.plot(ax=ax,label="Modeled discharge HBV-bmi")
ax.legend(bbox_to_anchor=(1,1));
_images/example_model_run_HBV_31_0.png

Using Local HBV model in eWaterCycle

eWaterCycle uses Docker containters to ensure the user has no issues with versioning. When model.initialize(..) is called, in the background a docker containter is started up. This has many benefits for interoperability, but can be slow down a small model like HBV. For this reason, we can use a local model. the first few steps are the same thus these are not repeated. We do need the bmi model locally in the form of a python package.

pip install HBV

Setting up the Local model

We then import the HBVLocal model through the eWaterCycle package:

19         In:
from ewatercycle_HBV.model import HBVLocal
20         In:
model = HBVLocal(forcing=camels_forcing)
21         In:
config_file, _ = model.setup(
            parameters=','.join([str(p) for p in par_0]),
            initial_storage=','.join([str(s) for s in s_0]),
           )
22         In:
model.initialize(config_file)

Running model

23         In:
Q_m = []
time = []
while model.time < model.end_time:
    model.update()
    Q_m.append(model.get_value("Q"))
    time.append(pd.Timestamp(model.time_as_datetime.date()))

After running the model: finalize to shut everything down

24         In:
model.finalize()

Process results

We see these yield the same results, but if we time it: the local model is much faster.

32         In:
df_local = pd.DataFrame(data=Q_m,columns=["Modeled discharge local"],index=time)
33         In:
fig, ax = plt.subplots(1,1)
df.plot(ax=ax)
df_local.plot(ax=ax,ls="--")
ax.legend(bbox_to_anchor=(1,1));
_images/example_model_run_HBV_48_0.png