Skip to content

Deduplicate hydrological routines across HBV variants #145

Open
0 of 1 issue completed
Open
@MAfarrag

Description

@MAfarrag

Refactor all common hydrological routines (precipitation, snow, soil, response, routing) into shared mixins. Update BaseHBVModel to inherit from these mixins. Update HBV variant implementations to reuse shared routines unless overriding behavior.

Current state

  • Each HBV variant implements its own version of snow, soil, routing, and response functions.
  • These implementations are nearly identical, with small differences (e.g., extra lake handling, different parameters).
  • Any bug fix or enhancement must be made in multiple places, risking inconsistency.

Objective

  • Centralize shared routines (like snow(), soil(), etc.).
  • Let each model extend only the parts it needs (via mixins or method overrides).
  • Reduce maintenance effort and enforce consistency.
Routine Description Common Across Differences
precipitation() Splits precip into rain/snow based on thresholds All models Some include pcorr, others don’t
snow() Handles snowpack melt and refreeze All models Minor naming differences; some pass tfac, some don’t
soil() Computes soil moisture, recharge, evapotranspiration All models Some include capillary flux, some skip it
response() Routes water through upper/lower zones All models Some use two/three outflows; lumped/distributed logic varies
routing() Applies MAXBAS weighting Most models Same logic in all
lake() Only in lake variant Unique Keep as-is in HBVLakeModel

Tasks

  1. Create Shared Mixins
    These mixins contain shared routines. Each can be inherited by any model variant.
# src/Hapi/core/mixins.py

class PrecipitationMixin:
    def precipitation(self, temp, ltt, utt, prec, rfcf, sfcf, pcorr=1.0):
        ...

class SnowMixin:
    def snow(self, temp, ttm, cfmax, cfr, cwh, rf, sf, wc_old, sp_old):
        ...

class SoilMixin:
    def soil(self, fc, beta, etf, temp, tm, e_corr, lp, tfac, c_flux,
             infiltration, ep, sm_old, uz_old):
        ...

class ResponseMixin:
    def response(self, tfac, perc, alpha, k, k1, area, lz_old, uz_int_1):
        ...

class RoutingMixin:
    def routing(self, q, maxbas=1):
        ...
  1. Update Base Model to Use Mixins
class BaseHBVModel(
    PrecipitationMixin,
    SnowMixin,
    SoilMixin,
    ResponseMixin,
    RoutingMixin
):
    pass
  1. Update All Model Variants
    Refactor all variants to:
  • Inherit from BaseHBVModel instead of defining their own versions of these routines.
  • Only override routines that actually differ.
class HBVLakeModel(BaseHBVModel):
    def lake(...):
        ...
  1. Unify Interfaces Across Implementations
    Some current discrepancies:
  • Parameter names like cfmax vs CFMAX
  • Missing default values
  • Use of positional args instead of keyword args
    Fix: Normalize function signatures and standardize argument names across all mixin routines.

Summary tasks:

  • Create PrecipitationMixin, SnowMixin, SoilMixin, ResponseMixin, RoutingMixin.
  • Move shared logic from HBV variants into mixins
  • Standardize function signatures and parameter naming
  • Update BaseHBVModel to inherit from mixins
  • Refactor HBV variant classes to use shared methods
  • Write unit tests for mixins
  • Write integration tests for refactored models

File Structure

src/Hapi/
├── core/
│   ├── mixins.py          ← 🔹 New
│   └── simulator.py
├── rrm/
│   ├── base_model.py      ← updated to inherit mixins
│   ├── hbv.py
│   ├── hbv_lake.py
│   └── ...

Sub-issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions