HeatTransPlan / backend /app /models /analysis.py
drzg15's picture
Initial code commit with LFS for binaries
c993983
"""
Analysis request/response models for pinch analysis, HPI, and status quo comparison.
"""
from __future__ import annotations
from typing import Any, Dict, List, Optional, Union
from pydantic import BaseModel, Field
# ---------------------------------------------------------------------------
# Pinch Analysis
# ---------------------------------------------------------------------------
class PinchStream(BaseModel):
"""A single stream for pinch analysis input."""
name: str = ""
CP: float # Heat capacity rate (kW/°C)
T_supply: float # Supply temperature (°C)
T_target: float # Target temperature (°C)
class PinchRequest(BaseModel):
"""Input to the pinch analysis endpoint."""
streams: List[PinchStream]
T_min: float # Minimum temperature difference (°C)
class CompositeDiagramData(BaseModel):
"""H-T data for hot and cold composite curves."""
hot: Dict[str, List[float]] = Field(default_factory=lambda: {"H": [], "T": []})
cold: Dict[str, List[float]] = Field(default_factory=lambda: {"H": [], "T": []})
class PinchResult(BaseModel):
"""Full output of pinch analysis."""
pinch_temperature: float
hot_utility: float # Minimum hot utility (kW)
cold_utility: float # Minimum cold utility (kW)
T_min: float
temperatures: List[float] # Sorted shifted temperature intervals
# Problem table
problem_table: List[Dict[str, float]]
# Heat cascade
heat_cascade: List[Dict[str, float]]
unfeasible_heat_cascade: List[Dict[str, float]]
# Diagrams (lists of H, T values for plotting)
shifted_composite_diagram: CompositeDiagramData = Field(default_factory=CompositeDiagramData)
composite_diagram: CompositeDiagramData = Field(default_factory=CompositeDiagramData)
grand_composite_curve: Dict[str, List[float]] = Field(default_factory=lambda: {"H": [], "T": []})
# Stream info for labelling charts
streams_data: List[Dict[str, Any]] = Field(default_factory=list)
# ---------------------------------------------------------------------------
# Heat Pump Integration
# ---------------------------------------------------------------------------
class HeatPumpEntry(BaseModel):
"""Detailed summary of an available heat pump."""
name: str
cop: Optional[float] = None
t_source: Optional[float] = None
t_sink: Optional[float] = None
q_source: Optional[float] = None
q_sink: Optional[float] = None
coverage: Optional[float] = None
available: bool = True
reason: str = ""
class HPIRequest(BaseModel):
"""Input to the HPI endpoint."""
pinch_result: PinchResult
hp_types: List[str] = Field(
default_factory=lambda: [
"Prototypical Stirling",
"VHTHP (HFC/HFO)",
"SHP and HTHPs (HFC/HFO)",
"SHP and HTHPs (R717)",
]
)
class HPIntegrationResult(BaseModel):
"""Result for a single heat pump type."""
hp_type: str
COP: Optional[float] = None
Q_ko: Optional[float] = None # Condenser heat (kW)
Q_ev: Optional[float] = None # Evaporator heat (kW)
T_source: Optional[float] = None
T_sink: Optional[float] = None
delta_T: Optional[float] = None
feasible: bool = False
# GCC integration points for charting
source_points: Dict[str, List[float]] = Field(default_factory=lambda: {"H": [], "T": []})
sink_points: Dict[str, List[float]] = Field(default_factory=lambda: {"H": [], "T": []})
class HPIResult(BaseModel):
"""Output of HPI analysis — one entry per HP type evaluated."""
integrations: List[HPIntegrationResult] = Field(default_factory=list)
heat_pumps: List[HeatPumpEntry] = Field(default_factory=list)
excluded_heat_pumps: List[HeatPumpEntry] = Field(default_factory=list)
gcc_data: Dict[str, List[float]] = Field(default_factory=lambda: {"H": [], "T": []})
# ---------------------------------------------------------------------------
# Status Quo Comparison
# ---------------------------------------------------------------------------
class EnergyDemand(BaseModel):
"""Current energy demand for one stream (user-entered)."""
stream_name: str = ""
heating_kW: float = 0.0
cooling_kW: float = 0.0
class StatusQuoRequest(BaseModel):
"""Input to the status quo comparison endpoint."""
current_demands: List[EnergyDemand]
pinch_hot_utility: float
pinch_cold_utility: float
class StatusQuoResult(BaseModel):
"""Comparison of current vs pinch-optimal demands."""
total_current_heating: float
total_current_cooling: float
pinch_hot_utility: float
pinch_cold_utility: float
heating_savings_kW: float
cooling_savings_kW: float
heating_savings_pct: float
cooling_savings_pct: float