- Replace all unstructured positional parameter vectors (e.g. p, p2, v, St) used in HBV variants and routines with typed, named objects using Python's dataclasses or Pydantic models.
In HBV models like hbv.py, hbv_lake.py, etc., model routines use:
def step_run(p, p2, v, St):
ltt = p[0]
utt = p[1]
ttm = p[2]
...
These are flat list or np.ndarray objects with up to 20+ parameters. Access relies on fixed ordering, which is error-prone and hard to understand.
What To Introduce
- Define new structured classes like this:
- @DataClass Option (preferred for performance & simplicity):
from dataclasses import dataclass
from typing import List
@dataclass
class HBVParameters:
ltt: float
utt: float
ttm: float
cfmax: float
fc: float
ecorr: float
etf: float
lp: float
k: float
k1: float
alpha: float
beta: float
cwh: float
cfr: float
c_flux: float
perc: float
rfcf: float
sfcf: float
maxbas: int
@dataclass
class SimulationConstants:
tfac: float
area: float
@dataclass
class Forcing:
prec: float
temp: float
evap: float
ll_temp: float
@dataclass
class HBVState:
sp: float
sm: float
uz: float
lz: float
wc: float
- In all routines across hbv*.py, replace:
| Old |
New |
| p[i] |
params.name |
| p2[0], p2[1] |
constants.tfac, constants.area |
| v[0], v[1], etc. |
forcing.prec, forcing.temp, ... |
| St[0], St[1], etc. |
state.sp, state.sm, ... |
def step_run(p, p2, v, St):
ltt = p[0]
tfac = p2[0]
prec = v[0]
sm = St[1]
...
def step_run(self, params: HBVParameters, constants: SimulationConstants,
forcing: Forcing, state: HBVState):
rf, sf = self.precipitation(forcing.temp, params.ltt, params.utt, forcing.prec,
params.rfcf, params.sfcf)
...
Refactoring strategy
1 - Define HBVParameters, SimulationConstants, Forcing, HBVState in a new module:
src/Hapi/models/schemas.py
2- Update step_run() signatures across:
- hbv.py, hbv_lake.py, hbvold.py, hbvlumped.py, hbv_bergestrom92.py
Example:
def step_run(self, params: HBVParameters, constants: SimulationConstants,
forcing: Forcing, state: HBVState) -> Tuple[float, HBVState]:
3- Update downstream calls in wrappers/calibration code:
- Replace any array slicing into params/state with object instantiation.
4- Optionally, implement from_vector() static methods on HBVParameters, etc.:
@staticmethod
def from_vector(vec: List[float]) -> "HBVParameters":
return HBVParameters(*vec[:19])
Issues
In HBV models like hbv.py, hbv_lake.py, etc., model routines use:
These are flat list or np.ndarray objects with up to 20+ parameters. Access relies on fixed ordering, which is error-prone and hard to understand.
What To Introduce
Refactoring strategy
1 - Define HBVParameters, SimulationConstants, Forcing, HBVState in a new module:
2- Update step_run() signatures across:
Example:
3- Update downstream calls in wrappers/calibration code:
4- Optionally, implement from_vector() static methods on HBVParameters, etc.:
Issues
HBVSimulatororchestration class #144BaseHBVModel#142