Source code for ecoengine.objects.dhwsystems.InstantWHSystem

from __future__ import annotations

from ecoengine.constants.constants import _RHO_CP, _W_TO_KBTUH
from .DHWSystem import DHWSystem


[docs] class InstantWHSystem(DHWSystem): """ Instantaneous (tankless) water heater system. No storage tank — the heater meets demand in real time each timestep. Sizing sets the minimum capacity needed to serve peak instantaneous demand; storage volume is always zero. Load shifting is not supported because there is no tank to pre-charge. """
[docs] def __init__( self, supply_temp_f: float, storage_temp_f: float, defrost_factor: float = 1.0, ): super().__init__( water_heaters=[], storage_tank=None, supply_temp_f=supply_temp_f, storage_temp_f=storage_temp_f, defrost_factor=defrost_factor, )
# ------------------------------------------------------------------ # Factory constructor # ------------------------------------------------------------------
[docs] @classmethod def from_size( cls, building, supply_temp_f: float, storage_temp_f: float, defrost_factor: float = 1.0, ) -> InstantWHSystem: """ Size the system for the given building, then return it. Parameters ---------- building : Building supply_temp_f : float storage_temp_f : float defrost_factor : float """ system = cls( supply_temp_f=supply_temp_f, storage_temp_f=storage_temp_f, defrost_factor=defrost_factor, ) system.size(building) return system
# ------------------------------------------------------------------ # Sizing # ------------------------------------------------------------------
[docs] def size(self, building, **kwargs) -> None: """ Set minimum capacity to serve peak instantaneous demand. Capacity is the kBTU/hr required to heat the peak one-minute demand volume from design inlet temperature to supply temperature. Storage volume is always zero. Parameters ---------- building : Building Must have a ClimateZone so that design inlet temperature is available. **kwargs Accepted but ignored (load-shift params, strat_slope, etc.). """ design_inlet_temp_f = self._require_design_inlet_temp(building) delta_t = self.supply_temp_f - design_inlet_temp_f # Peak instantaneous generation rate [gal/hr at supply temp] peak_gph = building.daily_dhw_use_supplyT_gal * float(max(building.peak_load_shape)) * 60.0 self._minimum_capacity_kbtuh = peak_gph * _RHO_CP * delta_t / self.defrost_factor / 1000.0 self._minimum_storage_storageT_gal = 0.0
# ------------------------------------------------------------------ # Simulation # ------------------------------------------------------------------
[docs] def simulate_step( self, building, timestep_interval: int, interval_min: int = 1, mode: str = "normal", ) -> dict: """ Serve demand instantly each timestep — no tank draw or charge cycle. Capacity is computed from this timestep's actual demand and inlet temperature, so it tracks demand exactly. Usable volume is always zero (no storage). """ demand_supplyT_gal = building.get_dhw_load_supplyT_gal(timestep_interval, interval_min) oat_f = building.get_oat_f(timestep_interval, interval_min) inlet_temp_f = building.get_inlet_water_temp_f(timestep_interval, interval_min) delta_t = max(self.supply_temp_f - inlet_temp_f, 1.0) capacity_kbtuh = ( demand_supplyT_gal * (60.0 / interval_min) * _RHO_CP * delta_t / self.defrost_factor / 1000.0 ) return { "demand_supplyT_gal": demand_supplyT_gal, "usable_volume_supplyT_gal": 0.0, "heater_output_kbtuh": capacity_kbtuh, "heater_power_in_kw": capacity_kbtuh / _W_TO_KBTUH, # COP of 1.0 "oat_f": oat_f, "inlet_water_temp_f": inlet_temp_f, "tank_temps_f": [self.supply_temp_f] * 6, "mode": "normal", }