Source code for simulator.pumps.system_curve
from __future__ import annotations
"""System-head models for pump/system matching."""
from dataclasses import dataclass, asdict
from typing import Any, Mapping
[docs]
@dataclass(frozen=True)
class QuadraticSystemCurve:
"""System curve H = H_static + K Q^exponent.
For turbulent piping and cooling passages, exponent=2 is the usual first
model. Units are intentionally tied to the input data: if Q is in gpm and H
is in ft, then K has units ft / gpm^2. For Frank White Example 11.6, Q is in
thousands of gal/min, so K has units ft / (1000 gal/min)^2.
"""
static_head_ft: float = 0.0
k: float = 0.0
exponent: float = 2.0
flow_unit: str = "gpm"
head_unit: str = "ft"
[docs]
@classmethod
def from_dict(cls, data: Mapping[str, Any]) -> "QuadraticSystemCurve":
curve = dict(data.get("system_curve", data))
model = str(curve.get("model", "quadratic")).lower()
if model not in {"quadratic", "power", "system_quadratic"}:
raise ValueError(f"Unsupported system curve model: {model!r}")
return cls(
static_head_ft=float(curve.get("static_head_ft", curve.get("static_head", 0.0))),
k=float(curve.get("k", curve.get("loss_coefficient", 0.0))),
exponent=float(curve.get("exponent", 2.0)),
flow_unit=str(curve.get("flow_unit", data.get("flow_unit", "gpm"))),
head_unit=str(curve.get("head_unit", data.get("head_unit", "ft"))),
)
[docs]
def head_ft(self, flow: float) -> float:
return float(self.static_head_ft) + float(self.k) * (max(float(flow), 0.0) ** float(self.exponent))
[docs]
def to_dict(self) -> dict[str, Any]:
return asdict(self)