"""Preprocessing helpers for heat pump and refrigeration targeting."""
from typing import Tuple
import numpy as np
from ....classes.problem_table import ProblemTable
from ....lib.config import Configuration
from ....lib.enums import PT
from ....lib.schemas.hpr import HeatPumpTargetInputs
from ....utils.miscellaneous import clean_composite_curve, linear_interpolation
from .shared import create_stream_collection_of_background_profile
__all__ = ["construct_HPRTargetInputs"]
################################################################################
# Public API
################################################################################
################################################################################
# Helper Functions
################################################################################
def _prepare_hpr_background_profile(
*,
Q_hpr_target: float,
T_vals: np.ndarray,
H_vals: np.ndarray,
zone_config: Configuration,
is_heat_pumping: bool,
is_cold: bool,
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, object]:
should_trim_to_target = ((is_cold) and (is_heat_pumping)) or (
(not is_cold) and (not is_heat_pumping)
)
if should_trim_to_target:
T_vals, H_vals = _get_reduced_bckgrd_cascade_till_Q_target(
Q_hpr_target, T_vals, H_vals, is_cold=is_cold
)
T_vals, H_vals, z_amb = _get_simplified_bckgrd_cascade_and_z_amb(
T_vals=T_vals,
H_vals=H_vals,
zone_config=zone_config,
is_cold=is_cold,
)
return (
T_vals,
H_vals,
z_amb,
create_stream_collection_of_background_profile(T_vals, H_vals),
)
def _apply_temperature_shift_for_hpr_stream_dtmin_cont(
T_vals: np.ndarray,
dtmin_hp: float,
) -> Tuple[np.ndarray, np.ndarray]:
return T_vals - dtmin_hp, T_vals + dtmin_hp
def _get_reduced_bckgrd_cascade_till_Q_target(
Q_hpr_target: float,
T_vals: np.ndarray,
H_vals: np.ndarray,
*,
is_cold: bool = True,
) -> Tuple[np.ndarray, np.ndarray]:
if is_cold:
if H_vals[0] < Q_hpr_target:
return T_vals, H_vals
i = H_vals.size - np.searchsorted(H_vals[::-1], Q_hpr_target, side="left") - 1
if i == T_vals.size - 1:
raise ValueError("Target for heat pumping cannot be zero.")
T_vals[i] = linear_interpolation(
Q_hpr_target, H_vals[i], H_vals[i + 1], T_vals[i], T_vals[i + 1]
)
H_vals[i] = Q_hpr_target
return T_vals[i:], H_vals[i:]
if -H_vals[-1] < Q_hpr_target:
return T_vals, H_vals
i = np.searchsorted(-H_vals, Q_hpr_target, side="left")
if i == 0:
raise ValueError("Target for refrigeration cannot be zero.")
T_vals[i] = linear_interpolation(
-Q_hpr_target, H_vals[i], H_vals[i - 1], T_vals[i], T_vals[i - 1]
)
H_vals[i] = -Q_hpr_target
return T_vals[: i + 1], H_vals[: i + 1]
def _get_z_ambient(
T_vals: np.ndarray,
T_amb_star: float,
is_cold: bool,
) -> Tuple[np.ndarray, float]:
if is_cold:
return np.where(T_vals > T_amb_star, 1.0, 0.0)
return np.where(T_vals < T_amb_star, -1.0, 0.0)
def _get_simplified_bckgrd_cascade_and_z_amb(
T_vals: np.ndarray,
H_vals: np.ndarray,
zone_config: Configuration,
*,
is_cold: bool,
) -> Tuple[np.ndarray, float]:
sign = 1 if is_cold else -1
T_amb_star = (
zone_config.T_ENV + (zone_config.DT_ENV_CONT + zone_config.DT_CONT_HP) * sign
)
T_vals, H_vals = _add_T_amb_interval(
T_vals, H_vals, T_amb_star, zone_config.DT_PHASE_CHANGE, is_cold
)
z_amb = _get_z_ambient(T_vals=T_vals, T_amb_star=T_amb_star, is_cold=is_cold)
H_vals += z_amb
T_vals, H_vals = clean_composite_curve(T_vals, H_vals)
z_amb = _get_z_ambient(
T_vals=T_vals,
T_amb_star=zone_config.T_ENV
+ (zone_config.DT_ENV_CONT + zone_config.DT_CONT_HP) * sign,
is_cold=is_cold,
)
H_vals -= z_amb
T_vals, H_vals, z_amb = _extend_profile_with_temperature_margin(
T_vals, H_vals, z_amb, dt_margin=10.0
)
return T_vals, H_vals, z_amb
def _add_T_amb_interval(
T_vals: np.ndarray,
H_vals: np.ndarray,
T_amb: float,
dt_phase_change: float,
is_cold: bool,
) -> Tuple[np.ndarray, np.ndarray]:
H_label = PT.H_NET_COLD if is_cold else PT.H_NET_HOT
pt = ProblemTable({PT.T: T_vals, H_label: H_vals})
T_amb_ls = (
[T_amb, T_amb + dt_phase_change]
if is_cold
else [T_amb, T_amb - dt_phase_change]
)
pt.insert_temperature_interval(T_amb_ls)
return pt[PT.T], pt[H_label]
def _extend_profile_with_temperature_margin(
T_vals: np.ndarray,
H_vals: np.ndarray,
z_amb: np.ndarray,
*,
dt_margin: float = 10.0,
) -> Tuple[np.ndarray, np.ndarray]:
if T_vals.size == 0:
return T_vals, H_vals
T_ext = np.empty(T_vals.size + 2, dtype=T_vals.dtype)
H_ext = np.empty(H_vals.size + 2, dtype=H_vals.dtype)
z_ext = np.empty(z_amb.size + 2, dtype=z_amb.dtype)
T_ext[0] = T_vals[0] + dt_margin
T_ext[1:-1] = T_vals
T_ext[-1] = T_vals[-1] - dt_margin
H_ext[0] = H_vals[0]
H_ext[1:-1] = H_vals
H_ext[-1] = H_vals[-1]
z_ext[0] = z_amb[0]
z_ext[1:-1] = z_amb
z_ext[-1] = z_amb[-1]
return T_ext, H_ext, z_ext