Skip to content
Snippets Groups Projects
Commit 7e6abc2a authored by ENRI's avatar ENRI
Browse files

Merge branch 'dev'

parents 19146c45 370e9807
Branches
Tags V.3.0.1
No related merge requests found
#HP_Model
"""
Interpolated Calculator
Interpolated Heat Pump Calculator
This class processes data from a CSV file containing power-related information. It performs the following steps:
This library provides a powerful tool for processing and interpolating data related to heat pump systems. The main class, `HeatPump`, is designed to handle the following tasks:
1. Data Preparation:
- Reads the CSV file into a pandas DataFrame.
- Sorts the DataFrame by 'n_comp_perc', 'T_source_in', 'T_sink_out', and 'Q_dot_H'.
- Create an array with all unique n_comp_perc values.
- Converts per 'n_comp_perc' value the relevant columns into a numpy 2D array, with T_source_in and T_sink_out as coordinates.
- Assigns the relevant 'P_comp' value to each point in the array.
2. KD-Tree Creation:
- Constructs a KD-Tree for each of the 2D arrays.
- Saves the KD-Trees within the class.
3. User Queries:
- 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 value.
4. Interpolation Method:
- Utilizes a normalized inverse distance weighting (IDW) technique.
- Reads a CSV file containing information, such as compressor rpm percentage, source and sink temperatures, heating power, and electrical power.
- Sorts the data and extracts unique compressor rpm percentage values.
- Organizes the data into separate sets based on the unique rpm percentages, storing the corresponding coordinate values (T_source_in, T_sink_out) and power values (heating power, electrical power).
- Constructs efficient KD-Trees for each set of coordinate data to enable fast nearest neighbor searches.
2. Interpolation:
- Provides a method to calculate the interpolated value at a specified coordinate point (T_source_in, T_sink_out) using an inverse distance weighting (IDW) technique.
- The interpolation can be performed for various power-related values, such as compressor rpm percentage, electrical power, Coefficient of Performance (COP), and second law efficiency (exergetic efficiency).
3. User-Friendly Interfaces:
- Offers several methods to directly calculate the interpolated values for specific use cases, such as `getN_comp_perc`, `getElectricalPower`, `getCOP`, and `getEta_II`.
- These methods handle the underlying interpolation process and return the desired values, making it easy for users to integrate the library into their applications.
The `HeatPump` class is designed to be efficient, accurate, and user-friendly, providing a comprehensive solution for working with heat pump data and performing various interpolations. It can be particularly useful for researchers, engineers, or anyone involved in the design, optimization, or analysis of heat pump systems.
"""
import enum
......@@ -32,7 +28,6 @@
from typing import Union
class PowerTypes(enum.Enum):
N_COMP_PERC = enum.auto()
ELECTRICAL = enum.auto()
HEATING = enum.auto()
......@@ -42,7 +37,7 @@ class HeatPump:
def __init__(self, *, csvFile: str, verbose: bool = False) -> None:
"""
Initializes the class by reading a CSV file and creating a KD-Tree.
Initializes the HeatPump class by reading a CSV file and creating KD-Trees for efficient nearest neighbor searches.
Args:
csvFile (str): Path to the CSV file containing the data points. The CSV file should have the following headers (in order):
......@@ -59,7 +54,7 @@ def __init__(self, *, csvFile: str, verbose: bool = False) -> None:
Notes:
- Reads the specified CSV file into a pandas DataFrame.
- Processes the data to extract unique power percentages and create coordinate sets.
- Constructs KD-Trees for efficient nearest neighbor searches.
- Constructs KD-Trees for each set of coordinate data to enable fast nearest neighbor searches.
"""
self.__readCSV(csvFile, verbose)
......@@ -103,7 +98,7 @@ def __readCSV(self, csvFile: str, verbose: bool = False) -> None:
def __processData(self, verbose: bool = False) -> None:
"""
Sorts the pandas DataFrame. The DataFrame is then extracted into NumPy n-dimensional arrays.
Sorts the pandas DataFrame and extracts the data into separate sets based on unique power percentages.
Args:
verbose (bool, optional): If True, feedback messages are printed during initialization. Defaults to False.
......@@ -115,7 +110,7 @@ def __processData(self, verbose: bool = False) -> None:
- Sorts the DataFrame by specified columns ('n_comp_perc', 'T_source_in', 'T_sink_out', 'Q_dot_H').
- Extracts unique 'n_comp_perc' values and counts them.
- Slices the DataFrame into sets based on unique power percentages.
- Saves coordinate values (T_source_in, T_sink_out) and corresponding power values (heatingPower, electricalPower).
- Saves coordinate values (T_source_in, T_sink_out) and corresponding power values (heatingPower, electricalPower) for each set.
"""
# Sort the DataFrame by specified columns and reset the index
......@@ -143,7 +138,7 @@ def __processData(self, verbose: bool = False) -> None:
def __createKDTree(self, verbose: bool = False) -> None:
"""
Creates a KD-Tree from the coordinate data.
Creates a KD-Tree from the coordinate data for each set of unique power percentages.
Args:
verbose (bool, optional): If True, feedback messages are printed during KD-Tree creation. Defaults to False.
......@@ -153,7 +148,7 @@ def __createKDTree(self, verbose: bool = False) -> None:
Notes:
- The KD-Tree is constructed for efficient nearest neighbor searches.
- Each coordinate value set has its own KD-Tree.
- Each set of coordinate values has its own KD-Tree.
"""
self.kdTree = [cKDTree(self.coords[index]) for index in range(len(self.powerPercentage))]
......@@ -163,121 +158,68 @@ def __createKDTree(self, verbose: bool = False) -> None:
# ====================================================================================================
def __getInterpolatedValue(self, T_source_in: float, T_sink_out: float, setIndex: int, K: int, type: PowerTypes, decayPower: int = 1) -> float:
def __interpolate(self, distances: list[float], nearbyValues: list[float]) -> float:
"""
Calculates the interpolated value at the specified coordinate point.
Performs inverse distance weighting (IDW) interpolation to estimate a value based on nearby points.
Args:
T_source_in (float): Source temerature (inlet).
T_sink_out (float): Sink temperature (outlet).
setIndex (int): The index of the coordinate set (corresponding to the unique powerPercentages)
K (int): Number of neighbors to consider during interpolation.
type (PowerTypes): Selector for the value needed at the specified coordinate.
decayPower (int, optional): The KDTree distances are raised to the decayPower. Defaults to 1 (no decay).
distances (list[float]): The distances to the nearby points.
nearbyValues (list[float]): The values of the nearby points.
Returns:
float: Interpolated value based on the specified type.
float: The interpolated value.
Notes:
- The function uses inverse distance normalization weighting for interpolation.
- Handles cases where the total distance is 0 or K is 1 to avoid division by zero.
Example:
>>> instance = MyClass() # Create an instance of your class
>>> interpolated_value = instance.__getInterpolatedValue(80.0, 45.0, 2, 3, PowerTypes.HEATING)
>>> print(interpolated_value)
123.45
- Applies a normalized inverse distance weighting technique to calculate the interpolated value.
- Handles cases where the total distance is 0 or the number of nearby points is 1 to avoid division by zero.
"""
if type not in PowerTypes:
print("Invalid type selected.")
return 0
point = (T_source_in, T_sink_out)
distances, indices = self.kdTree[setIndex].query(point, k=K)
distances **= decayPower
totalDistance = sum(distances)
# Inverse distance normalization weighting with handling for more than 2 points
try:
weights = [(totalDistance - d) / (totalDistance * (K - 1)) for d in distances]
weights = [(totalDistance - d) / (totalDistance * (len(distances) - 1)) for d in distances]
except ZeroDivisionError:
print("Division by zero! Total distance is 0 or K is 1.")
print("Division by zero! Total distance is 0 or len(distances) is 1.")
# Interpolate values
interpolatedValue = 0
for index in range(K):
if type == PowerTypes.N_COMP_PERC:
nearbyPowerValue = self.powerPercentage[setIndex][indices[index]]
elif type == PowerTypes.HEATING:
nearbyPowerValue = self.heatingPower[setIndex][indices[index]]
else:
nearbyPowerValue = self.electricalPower[setIndex][indices[index]]
interpolatedValue += weights[index] * nearbyPowerValue # Assuming each point has a 'value' attribute
interpolatedValue = sum(weights[index] * nearbyValues[index] for index in range(len(distances))) # Assuming each point has a 'value' attribute
return interpolatedValue
# ====================================================================================================
def __findTwoSmallest(self, arr : list[float]) -> tuple:
"""
Finds the indices of the two smallest elements in the given list.
Args:
arr (list[float]): A list of floating-point numbers.
Returns:
tuple: A tuple containing the indices of the smallest and second smallest elements.
Example:
>>> my_list = [5.2, 3.1, 7.8, 2.5, 4.9]
>>> self.__findTwoSmallest(my_list)
(3, 1)
"""
numberOfValuesToBeFound = 2
sorted_indices = sorted(range(len(arr)), key=lambda i: arr[i])
return tuple(sorted_indices[:numberOfValuesToBeFound])
# ====================================================================================================
def __find_y_given_x(self, x: float, point1: tuple[float, float], point2: tuple[float, float]) -> float:
def __getPowerValue(self, T_source_in: float, T_sink_out: float, setIndex: int, type: PowerTypes, decayPower: int = 1) -> float:
"""
Calculates the y-value given an x-value using a linear equation (y = mx + c).
Calculates the interpolated power value at the specified coordinate point.
Args:
x (float): The x-value for which we want to find the y-value.
point1 (tuple[float, float]): First coordinate point (x1, y1).
point2 (tuple[float, float]): Second coordinate point (x2, y2).
T_source_in (float): Source temperature (inlet).
T_sink_out (float): Sink temperature (outlet).
setIndex (int): The index of the coordinate set (corresponding to the unique powerPercentages).
type (PowerTypes): Selector for the value needed at the specified coordinate (ELECTRICAL or HEATING).
decayPower (int, optional): The KDTree distances are raised to the decayPower. Defaults to 1 (no decay).
Returns:
float: The corresponding y-value.
float: Interpolated value based on the specified type.
Notes:
- The function calculates the slope (m) and y-intercept (c) based on the two given coordinate points.
- The linear equation y = mx + c represents the relationship between x and y.
Example:
>>> find_y_given_x(2.5, (2, 3), (3, 7))
5.0
- Uses the KD-Tree to find the 4 nearest neighbor points to the specified coordinate.
"""
x1, y1 = point1
x2, y2 = point2
# Calculate the slope (m) using the difference in y and x coordinates
m = (y2 - y1) / (x2 - x1)
if type not in PowerTypes:
print("Invalid type selected.")
return 0
# Calculate the y-intercept (c) using one of the points
c = y1 - m * x1
# Calculate the y-value using the linear equation
y = m * x + c
K = 4 # For power values of the 4 nearest neighbors are considered
point = (T_source_in, T_sink_out)
distances, indices = self.kdTree[setIndex].query(point, k=K)
distances **= decayPower
nearbyPowerValue = [self.heatingPower[setIndex][indices[index]] if type == PowerTypes.HEATING else self.electricalPower[setIndex][indices[index]] for index in range(K)]
return y
return self.__interpolate(distances, nearbyPowerValue)
# ====================================================================================================
......@@ -307,7 +249,7 @@ def getN_comp_perc(self, *, T_source_in: float, T_sink_out: float, Q_dot_H: floa
Calculates the interpolated compressor rpm-percentage at the specified coordinate point.
Args:
T_source_in (float): Source temerature (inlet).
T_source_in (float): Source temperature (inlet).
T_sink_out (float): Sink temperature (outlet).
Q_dot_H (float): Heating power.
_returnIndices (bool, optional): Whether to return the indices of the 2 sets the return value is located between. Defaults to False.
......@@ -316,27 +258,29 @@ def getN_comp_perc(self, *, T_source_in: float, T_sink_out: float, Q_dot_H: floa
Union[float, tuple]: Interpolated compressor rpm-percentage value or a tuple of (rpm-percentage value, indices of the 2 sets this value is located between).
Notes:
- The function uses interpolation to estimate the compressor rpm-percentage based on the given temperatures and heating power.
- It considers the K nearest neighbors to perform the interpolation.
- Ensure that the provided coordinate point lies within the valid range of data for accurate results.
- Uses interpolation to estimate the compressor rpm-percentage based on the given temperatures and heating power.
- Considers the K nearest neighbors to perform the interpolation.
- Ensures that the provided coordinate point lies within the valid range of data for accurate results.
- The argument _returnIndices is intended for internal use within the class. It passes the relevant sets for a next interpolation step.
"""
point = (T_source_in, T_sink_out)
K = 4 #Neighboring points to consider per plane
# Find the relevant plains
heatingPowers = [self.__getInterpolatedValue(*point, index, K, PowerTypes.HEATING) for index in range(len(self.powerPercentage))]
deltaQ_dot_H = [abs(hp - Q_dot_H) for hp in heatingPowers]
indices = self.__findTwoSmallest(deltaQ_dot_H)
# Find the 2 relevant sets
heatingPowers = [self.__getPowerValue(*point, index, PowerTypes.HEATING) for index in range(len(self.powerPercentage))]
distances = [abs(hp - Q_dot_H) for hp in heatingPowers]
indices = sorted(range(len(distances)), key=lambda i: distances[i])[:2]
# Compile the data for the 2 relevant sets
relevantDistances = [distances[index] for index in indices]
relevantPowerPercentages = [self.powerPercentage[index] for index in indices]
# compile coords to find point
coords = [(heatingPowers[values], self.powerPercentage[values]) for values in indices]
powerPercentage = self.__interpolate(relevantDistances, relevantPowerPercentages)
if _returnIndices:
return self.__find_y_given_x(Q_dot_H, *coords), indices
return powerPercentage, indices
else:
return self.__find_y_given_x(Q_dot_H, *coords)
return powerPercentage
# ====================================================================================================
......@@ -345,7 +289,7 @@ def getElectricalPower(self, *, T_source_in: float, T_sink_out: float, Q_dot_H:
Calculates the interpolated electrical power value at the specified coordinate point.
Args:
T_source_in (float): Source temerature (inlet).
T_source_in (float): Source temperature (inlet).
T_sink_out (float): Sink temperature (outlet).
Q_dot_H (float): Heating power.
......@@ -353,28 +297,29 @@ def getElectricalPower(self, *, T_source_in: float, T_sink_out: float, Q_dot_H:
float: Interpolated electrical power value.
Note:
- getN_comp_perc already finds the valid 2 sets between which will be interpolated
- The `getN_comp_perc` method already finds the valid 2 sets between which the value will be interpolated.
"""
point = (T_source_in, T_sink_out)
# Find the 2 relevant sets
powerPercentage, indices = self.getN_comp_perc(T_source_in=T_source_in, T_sink_out=T_sink_out, Q_dot_H=Q_dot_H, _returnIndices=True)
electricalPower = [self.__getInterpolatedValue(*point, value, 4, PowerTypes.ELECTRICAL) for value in indices]
# compile coords to find point
coords = [(self.powerPercentage[value], electricalPower[index]) for index, value in enumerate(indices)]
# Compile the data for the 2 relevant sets
electricalPower = [self.__getPowerValue(*point, value, PowerTypes.ELECTRICAL) for value in indices]
distances = [abs(self.powerPercentage[index] - powerPercentage) for index in indices]
return self.__find_y_given_x(powerPercentage, *coords)
return self.__interpolate(distances, electricalPower)
# ====================================================================================================
def getCOP(self, *, T_source_in: float, T_sink_out: float, Q_dot_H: float) -> float:
"""
Calculates the interpolated COP value at the specified coordinate point.
Calculates the interpolated Coefficient of Performance (COP) value at the specified coordinate point.
Args:
T_source_in (float): Source temerature (in).
T_sink_out (float): Sink temperature (out).
T_source_in (float): Source temperature (inlet).
T_sink_out (float): Sink temperature (outlet).
Q_dot_H (float): Heating power.
Returns:
......@@ -387,11 +332,11 @@ def getCOP(self, *, T_source_in: float, T_sink_out: float, Q_dot_H: float) -> fl
def getEta_II(self, *, T_source_in: float, T_sink_out: float, Q_dot_H: float) -> float:
"""
Calculates the interpolated second law efficiency value at the specified coordinate point.
Calculates the interpolated second law efficiency (exergetic efficiency) value at the specified coordinate point.
Args:
T_source_in (float): Source temerature (in).
T_sink_out (float): Sink temperature (out).
T_source_in (float): Source temperature (inlet).
T_sink_out (float): Sink temperature (outlet).
Q_dot_H (float): Heating power.
Returns:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment