diff --git a/HP_Model.py b/HP_Model.py index f6adcbd80f6e36faccb2e710a9d8112f953499f9..b87ec06db69b0e3d1b7c199a162a318dd0879eea 100644 --- a/HP_Model.py +++ b/HP_Model.py @@ -1,72 +1,77 @@ #HP_Model """ -Interpolated Power Calculator +Interpolated Calculator This class processes data from a CSV file containing power-related information. It performs the following steps: 1. Data Preparation: - Reads the CSV file into a pandas DataFrame. - - Sorts the DataFrame by 'PowerPercentage', 'sourceTemp', and 'condensationTemperature'. - - Converts relevant columns into a numpy 3D array, with (PowerPercentage, sourceTemp, condensationTemp) as coordinates. - - Assigns two values to each point in the array: 'heatingPower' and 'electricalPower'. + - Sorts the DataFrame by 'T_source_in', 'T_sink_out', and 'Q_dot_H'. + - Converts relevant columns into a numpy 3D array, with (T_source_in, T_sink_out, Q_dot_H) as coordinates. + - Assigns two values to each point in the array: 'n_comp_perc' and 'P_comp'. 2. KD-Tree Creation: - Constructs a KD-Tree for the entire 3D array. - Saves the KD-Tree within the class. 3. User Queries: - - Users can request power information for a specific point (given 'powerPercentage', 'sourceTemp', and 'condensationTemp'). - - Choose either 'heatingPower' or 'electricalPower'. + - Users can request information for a specific point (given 'T_source_in', 'T_sink_out', and 'Q_dot_H'). + - Choose either 'n_comp_perc', 'P_comp', 'COP' or 'eta_II'. - If the requested point does not exist in the 3D array, the KD-Tree identifies the closest points. - - Interpolates values from these nearby points to estimate the requested power value. + - Interpolates values from these nearby points to estimate the requested value. 4. Interpolation Method: - Utilizes a normalized inverse distance weighting (IDW) technique. """ +import enum import pandas as pd from scipy.spatial import cKDTree +class PowerTypes(enum.Enum): + N_COMP_PERC = enum.auto() + ELECTRICAL = enum.auto() + class HeatPump: # ==================================================================================================== - def __init__(self, csvFile: str, mul100: bool = False, verbose: bool = False) -> None: + def __init__(self, csvFile: str, mul1000: bool = False, verbose: bool = False) -> None: """ Initializes the class by reading a CSV file and creating a KD-Tree. Args: csvFile (str): Path to the CSV file containing the data points. The CSV file should have the following headers (in order): - - PowerPercentage - - SourceTemp - - CondensationTemp - - HeatingPower - - ElectricalPower - mul100 (bool, optional): When True, the PowerPercentage values are multiplied by 100. Defaults to False. + - n_comp_perc + - T_source_in + - T_sink_out + - Q_dot_H + - P_comp + mul1000 (bool, optional): When True, the Q_dot_H values are converted from kW to W. Defaults to False. verbose (bool, optional): If True, feedback messages are printed during initialization. Defaults to False. Returns: None """ - self.__readCSV(csvFile, mul100, verbose) + self.__readCSV(csvFile, mul1000, verbose) self.__createKDTree(verbose) # ==================================================================================================== - def __readCSV(self, csvFile: str, mul100: bool = False, verbose: bool = False) -> None: + def __readCSV(self, csvFile: str, mul1000: bool = False, verbose: bool = False) -> None: """ Reads and sorts the CSV file into a pandas DataFrame. The DataFrame is then extracted into NumPy n-dimensional arrays. Args: csvFile (str): Path to the CSV file containing the data points. The CSV file should have the following headers (in order): - - PowerPercentage - - SourceTemp - - CondensationTemp - - HeatingPower - - ElectricalPower - mul100 (bool, optional): When True, the PowerPercentage values are multiplied by 100. Defaults to False. + - n_comp_perc + - T_source_in + - T_sink_out + - Q_dot_H + - P_comp + mul1000 (bool, optional): When True, the Q_dot_H values are converted from kW to W. Defaults to False. verbose (bool, optional): If True, feedback messages are printed during initialization. Defaults to False. Returns: @@ -78,15 +83,15 @@ def __readCSV(self, csvFile: str, mul100: bool = False, verbose: bool = False) - self.dataframe = pd.read_csv(csvFile, sep=';') # Sort the DataFrame by specified columns and reset the index - self.dataframe = self.dataframe.sort_values(by=['PowerPercentage', 'SourceTemp', 'CondensationTemp']).reset_index(drop=True) + self.dataframe = self.dataframe.sort_values(by=['T_source_in', 'T_sink_out', 'Q_dot_H']).reset_index(drop=True) - if mul100: - self.dataframe['PowerPercentage'] *= 100 + if mul1000: + self.dataframe['Q_dot_H'] *= 1000 # Extract relevant columns - self.coords = self.dataframe[['PowerPercentage', 'SourceTemp', 'CondensationTemp']].values - self.heatingPower = self.dataframe["HeatingPower"].values - self.electricalPower = self.dataframe["ElectricalPower"].values + self.coords = self.dataframe[['T_source_in', 'T_sink_out', 'Q_dot_H']].values + self.powerPercentage = self.dataframe["n_comp_perc"].values + self.electricalPower = self.dataframe["P_comp"].values if verbose: print(f"The CSV file '{csvFile}' has been read.") @@ -113,26 +118,26 @@ def __createKDTree(self, verbose: bool = False) -> None: # ==================================================================================================== - def __getPower(self, powerPercentage: float, sourceTemp: float, condensationTemp: float, K: int = 3, type: str = "heating") -> float: + def __getPowerValue(self, T_source_in: float, T_sink_out: float, Q_dot_H: float, K: int = 3, type: PowerTypes = PowerTypes.ELECTRICAL) -> float: """ - Calculates the interpolated power value at the specified coordinate point. + Calculates the interpolated power or power related value at the specified coordinate point. Args: - powerPercentage (float): Power percentage value. - sourceTemp (float): Source temperature. - condensationTemp (float): Condensation temperature. + T_source_in (float): Source temerature (in). + T_sink_out (float): Sink temperature (out). + Q_dot_H (float): Heating power. K (int, optional): Number of neighbors to consider. Defaults to 3. - type (str, optional): Type of power ('heating' or 'electrical'). Defaults to 'heating'. + type (PowerTypes, optional): Type of power value. Defaults to ELECTRICAL. Returns: float: Interpolated power value. """ - if type not in ["heating", "electrical"]: - print(f"Invalid type '{type}' selected. Please choose 'heating' or 'electrical'.") + if type not in PowerTypes: + print("Invalid type selected.") return 0 - point = (powerPercentage, sourceTemp, condensationTemp) + point = (T_source_in, T_sink_out, Q_dot_H) distances, indices = self.kdTree.query(point, k=K) totalDistance = sum(distances) @@ -145,46 +150,85 @@ def __getPower(self, powerPercentage: float, sourceTemp: float, condensationTemp weights = [(totalDistance - d) / (totalDistance * (K - 1)) for d in distances] # Interpolate values - interpolatedPower = 0 + interpolatedPowerValue = 0 for index in range(K): - nearbyPower = self.heatingPower[indices[index]] if type == "heating" else self.electricalPower[indices[index]] - interpolatedPower += weights[index] * nearbyPower # Assuming each point has a 'value' attribute + nearbyPowerValue = self.powerPercentage[indices[index]] if type == PowerTypes.N_COMP_PERC else self.electricalPower[indices[index]] + interpolatedPowerValue += weights[index] * nearbyPowerValue # Assuming each point has a 'value' attribute - return interpolatedPower + return interpolatedPowerValue - # ==================================================================================================== + # ==================================================================================================== - def getHeatingPower(self, powerPercentage: float, sourceTemp: float, condensationTemp: float, K: int = 3) -> float: + def getN_comp_perc(self, T_source_in: float, T_sink_out: float, Q_dot_H: float, K: int = 3) -> float: """ - Calculates the interpolated heating power value at the specified coordinate point. + Calculates the interpolated compressor rpm-percentage at the specified coordinate point. Args: - powerPercentage (float): Power percentage value. - sourceTemp (float): Source temperature. - condensationTemp (float): Condensation temperature. + T_source_in (float): Source temerature (in). + T_sink_out (float): Sink temperature (out). + Q_dot_H (float): Heating power. K (int, optional): Number of neighbors to consider. Defaults to 3. Returns: - float: Interpolated heating power value. + float: Interpolated compressor rpm-percentage value. """ - - return self.__getPower(powerPercentage, sourceTemp, condensationTemp, K, "heating") + + return self.__getPowerValue(T_source_in, T_sink_out, Q_dot_H, K, PowerTypes.N_COMP_PERC) # ==================================================================================================== - def getElectricalPower(self, powerPercentage: float, sourceTemp: float, condensationTemp: float, K: int = 3) -> float: + def getElectricalPower(self, T_source_in: float, T_sink_out: float, Q_dot_H: float, K: int = 3) -> float: """ Calculates the interpolated electrical power value at the specified coordinate point. Args: - powerPercentage (float): Power percentage value. - sourceTemp (float): Source temperature. - condensationTemp (float): Condensation temperature. + T_source_in (float): Source temerature (in). + T_sink_out (float): Sink temperature (out). + Q_dot_H (float): Heating power. K (int, optional): Number of neighbors to consider. Defaults to 3. Returns: float: Interpolated electrical power value. """ - return self.__getPower(powerPercentage, sourceTemp, condensationTemp, K, "electrical") + return self.__getPowerValue(T_source_in, T_sink_out, Q_dot_H, K) + + # ==================================================================================================== + + def getCOP(self, T_source_in: float, T_sink_out: float, Q_dot_H: float, K: int = 3) -> float: + """ + Calculates the interpolated COP value at the specified coordinate point. + + Args: + T_source_in (float): Source temerature (in). + T_sink_out (float): Sink temperature (out). + Q_dot_H (float): Heating power. + K (int, optional): Number of neighbors to consider. Defaults to 3. + + Returns: + float: Interpolated COP value. + """ + + return (Q_dot_H / self.getElectricalPower(T_source_in, T_sink_out, Q_dot_H, K)) + + # ==================================================================================================== + + def getEta_II(self, T_source_in: float, T_sink_out: float, Q_dot_H: float, K: int = 3) -> float: + """ + Calculates the interpolated second law efficiency value at the specified coordinate point. + + Args: + T_source_in (float): Source temerature (in). + T_sink_out (float): Sink temperature (out). + Q_dot_H (float): Heating power. + K (int, optional): Number of neighbors to consider. Defaults to 3. + + Returns: + float: Interpolated second law efficiency value. + """ + + COP = self.getCOP(T_source_in, T_sink_out, Q_dot_H, K) + COP_Carnot = (T_sink_out + 273.15) / (T_sink_out - T_source_in) # in Kelvin! + + return (COP / COP_Carnot)