Skip to content

Implement HBVSimulator orchestration class #144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
MAfarrag opened this issue Apr 4, 2025 · 2 comments
Open

Implement HBVSimulator orchestration class #144

MAfarrag opened this issue Apr 4, 2025 · 2 comments
Labels

Comments

@MAfarrag
Copy link
Member

MAfarrag commented Apr 4, 2025

Description

  • ntroduce a new HBVSimulator class that manages simulation over time by orchestrating calls to step_run() on HBV model variants. This centralizes time control, improves reusability, and supports calibration and testing workflows.

  • Create a wrapper class called HBVSimulator that encapsulates the orchestration logic needed to:

  • Run hydrological simulations over time (multi-step execution),

  • Handle parameter objects, state tracking, and forcing data,

  • Allow model variant injection (e.g. lumped, lake, distributed),

  • Provide a consistent interface for:

    • Running a simulation loop
    • Resetting states
    • Logging or exporting results.

current status

Currently, each HBV model defines a step_run() function, but:

  • There is no consistent runner for stepping through time.
  • Each calibration or simulation script reimplements the time loop manually.
  • There is no clean separation between hydrologic model logic and time management.

By creating HBVSimulator, we encapsulate the "controller" or "simulation engine" that calls step_run() repeatedly.

class module

Create new file:

src/Hapi/core/simulator.py

New class

from typing import Type, List
import numpy as np
from Hapi.models.schemas import HBVParameters, HBVState, SimulationConstants, Forcing
from Hapi.rrm.base_model import BaseHBVModel

class HBVSimulator:
    def __init__(
        self,
        model: BaseHBVModel,
        parameters: HBVParameters,
        constants: SimulationConstants,
        initial_state: HBVState,
    ):
        self.model = model
        self.parameters = parameters
        self.constants = constants
        self.state = initial_state
        self.q_sim: List[float] = []
        self.states: List[HBVState] = []

    def run(self, forcings: List[Forcing]):
        for forcing in forcings:
            q, new_state = self.model.step_run(
                self.parameters, self.constants, forcing, self.state
            )
            self.q_sim.append(q)
            self.states.append(new_state)
            self.state = new_state

    def reset(self, state: HBVState):
        self.q_sim = []
        self.states = []
        self.state = state

methods.

Feature Description
run() Executes the model over a time series of forcings (e.g. precipitation, temperature)
reset() Resets the simulator to a clean state
get_results() (Optional) Returns discharge and state arrays
set_parameters() (Optional) Allows replacing parameters (for calibration)
support variant injection Accept any BaseHBVModel subclass (lumped, lake, etc.)
@MAfarrag
Copy link
Member Author

MAfarrag commented Apr 4, 2025

graph LR
    main[run.py / calibration.py]
    simulator[core/simulator.py]
    model[rrm/hbv.py or hbv_lake.py]
    base[rrm/base_model.py]
    mixins[core/mixins.py]
    schemas[models/schemas.py]

    main --> simulator
    simulator --> model
    model --> base
    base --> mixins
    simulator --> schemas
    model --> schemas


Loading

@MAfarrag
Copy link
Member Author

MAfarrag commented Apr 4, 2025

  • All HBV models operate on raw vectors (e.g., p, p2, v, St), with no named structure or object orientation for inputs and states.
classDiagram
    class HBVModel {
        +step_run(p, p2, v, St)
    }

    class HBVLakeModel {
        +step_run(p, p2, v, St)
    }

    class HBVLumpedModel {
        +step_run(p, p2, v, St)
    }

    class HBVOldModel {
        +step_run(p, p2, v, St)
    }

    class HBVBergestromModel {
        +step_run(p, p2, v, St)
    }

Loading
  • All models now consume clearly typed objects using dataclasses (or Pydantic). The simulation is now explicit and readable.
classDiagram
    class HBVParameters {
        - ltt: float
        - utt: float
        - cfmax: float
        - ...
    }

    class SimulationConstants {
        - tfac: float
        - area: float
    }

    class Forcing {
        - temp: float
        - precip: float
        - evap: float
        - ll_temp: float
    }

    class HBVState {
        - sp: float
        - sm: float
        - uz: float
        - lz: float
        - wc: float
    }

    class HBVModel {
        +step_run(HBVParameters, SimulationConstants, Forcing, HBVState)
    }

    class HBVLakeModel {
        +step_run(HBVParameters, SimulationConstants, Forcing, HBVState)
    }

    class HBVLumpedModel {
        +step_run(HBVParameters, SimulationConstants, Forcing, HBVState)
    }

    class HBVBergestromModel {
        +step_run(HBVParameters, SimulationConstants, Forcing, HBVState)
    }

    class HBVOldModel {
        +step_run(HBVParameters, SimulationConstants, Forcing, HBVState)
    }
Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Todo
Development

No branches or pull requests

1 participant