Source code for mogestpy.quantity.hydrological.muskingum

"""
Muskingum routing method for hydrological flow routing.

This module implements the Muskingum method for hydrological flow routing,
including both linear and non-linear routing methods in upstream and downstream directions.
"""

from typing import Sequence


[docs] class Muskingum: """ Implementation of the Muskingum method for hydrological flow routing. This class provides methods for flow routing using the Muskingum method, including linear and non-linear variants for both upstream and downstream routing. """
[docs] @staticmethod def downstream_routing( upstream: Sequence[float], k: float, x: float, dt: float ) -> list[float]: """ Perform downstream routing from upstream to downstream using the linear Muskingum method. Args: upstream (list): List of upstream flow values k (float): Muskingum storage coefficient (time) x (float): Muskingum weighting factor (dimensionless, 0 ≤ x ≤ 0.5) dt (float): Time step Returns: list: List of downstream flow values """ # Calculate coefficients denominator = (2 * k * (1 - x)) + dt c0 = (dt - (2 * k * x)) / denominator c1 = (dt + (2 * k * x)) / denominator c2 = ((2 * k * (1 - x)) - dt) / denominator n = len(upstream) downstream = [0] * n # Initial downstream value is equal to upstream value downstream[0] = upstream[0] # Loop through from the second to the last entries for i in range(1, n): downstream[i] = ( c0 * upstream[i] + c1 * upstream[i - 1] + c2 * downstream[i - 1] ) return downstream
@staticmethod def _calculate_rk4_coefficients( s_current: float, k: float, x: float, m: float, dt: float, inflow_current: float, inflow_next: float, is_downstream: bool = True, ) -> tuple[float, float, float, float]: """ Calculate Runge-Kutta 4th order coefficients for Muskingum routing. Args: s_current (float): Current storage k (float): Muskingum storage coefficient x (float): Muskingum weighting factor m (float): Muskingum exponent for non-linearity dt (float): Time step inflow_current (float): Current inflow/outflow value inflow_next (float): Next inflow/outflow value is_downstream (bool): True for downstream routing, False for upstream Returns: tuple: The four Runge-Kutta coefficients (k1, k2, k3, k4) """ factor = -1 / (1 - x) if is_downstream else 1 / x avg_inflow = 0.5 * (inflow_current + inflow_next) k1 = factor * ((s_current / k) ** (1 / m) - inflow_current) k2 = factor * (((s_current + 0.5 * dt * k1) / k) ** (1 / m) - avg_inflow) k3 = factor * (((s_current + 0.5 * dt * k2) / k) ** (1 / m) - avg_inflow) k4 = factor * (((s_current + dt * k3) / k) ** (1 / m) - inflow_next) return k1, k2, k3, k4
[docs] @staticmethod def downstream_fork( k: float, x: float, m: float, dt: float, inflow: Sequence[float] ) -> list[float]: """ Non-linear Muskingum model with fourth-order Runge-Kutta method for routing from upstream to downstream. This method implements the non-linear Muskingum model using a fourth-order Runge-Kutta numerical integration scheme to route flow from upstream to downstream. Args: k (float): Muskingum storage coefficient (time) x (float): Muskingum weighting factor (dimensionless, 0 ≤ x ≤ 0.5) m (float): Muskingum exponent for non-linearity dt (float): Time step inflow (list): List of inflow values (upstream hydrograph) Returns: list: List of outflow values (downstream hydrograph) """ n = len(inflow) outflow = [0] * n outflow[0] = inflow[0] s = [0] * n for i in range(n - 1): # Calculate storage s[i] = k * (x * inflow[i] + (1 - x) * outflow[i]) ** m # Calculate Runge-Kutta coefficients k1, k2, k3, k4 = Muskingum._calculate_rk4_coefficients( s[i], k, x, m, dt, inflow[i], inflow[i + 1], is_downstream=True ) # Update storage and calculate outflow s[i + 1] = s[i] + dt * (k1 + 2 * k2 + 2 * k3 + k4) / 6 outflow[i + 1] = ( 1 / (1 - x) * ((s[i + 1] / k) ** (1 / m) - x * inflow[i + 1]) ) return outflow
[docs] @staticmethod def upstream_fork( k: float, x: float, m: float, dt: float, outflow: Sequence[float] ) -> list[float]: """ Non-linear Muskingum model with fourth-order Runge-Kutta method for routing from downstream to upstream. This method implements the non-linear Muskingum model using a fourth-order Runge-Kutta numerical integration scheme to route flow from downstream to upstream. Args: k (float): Muskingum storage coefficient (time) x (float): Muskingum weighting factor (dimensionless, 0 ≤ x ≤ 0.5) m (float): Muskingum exponent for non-linearity dt (float): Time step outflow (list): List of outflow values (downstream hydrograph) Returns: list: List of inflow values (upstream hydrograph) """ n = len(outflow) inflow = [0] * n inflow[n - 1] = outflow[n - 1] s = [0] * n for i in range(n - 1, 0, -1): # Calculate storage s[i] = k * (x * inflow[i] + (1 - x) * outflow[i]) ** m # Calculate Runge-Kutta coefficients k1, k2, k3, k4 = Muskingum._calculate_rk4_coefficients( s[i], k, x, m, dt, outflow[i], outflow[i - 1], is_downstream=False ) # Update storage and calculate inflow s[i - 1] = s[i] - dt * (k1 + 2 * k2 + 2 * k3 + k4) / 6 inflow[i - 1] = ( 1 / x * (s[i - 1] / k) ** (1 / m) - (1 - x) / x * outflow[i - 1] ) return inflow