Skip to content

Commit

Permalink
Merge pull request #18 from bigladder/table-based-models
Browse files Browse the repository at this point in the history
Add table based models for single-speed and two-speed systems
  • Loading branch information
nealkruis authored Jul 21, 2024
2 parents cde5c14 + f8fc8f6 commit 2b761ae
Show file tree
Hide file tree
Showing 10 changed files with 899 additions and 546 deletions.
33 changes: 5 additions & 28 deletions examples/generate-205.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,13 @@
# import cbor2
import json

import resdx.rating_solver

seer2 = 14.3
hspf2 = 7.5
cop_c, solution_c = optimize.newton(
lambda x: resdx.DXUnit(
staging_type=resdx.StagingType.TWO_STAGE,
rated_gross_cooling_cop=x,
input_seer=seer2,
rating_standard=resdx.AHRIVersion.AHRI_210_240_2023,
).seer()
- seer2,
seer2 / 3.33,
full_output=True,
)
cop_h, solution_h = optimize.newton(
lambda x: resdx.DXUnit(
staging_type=resdx.StagingType.TWO_STAGE,
rated_gross_heating_cop=x,
input_hspf=hspf2,
rating_standard=resdx.AHRIVersion.AHRI_210_240_2023,
).hspf()
- hspf2,
hspf2 / 2.0,
full_output=True,
)
dx_unit = resdx.DXUnit(
staging_type=resdx.StagingType.TWO_STAGE,
rated_gross_cooling_cop=cop_c,
rated_gross_heating_cop=cop_h,
input_seer=seer2,
input_hspf=hspf2,

dx_unit = resdx.rating_solver.make_rating_unit(
staging_type=resdx.StagingType.TWO_STAGE, seer=seer2, hspf=hspf2
)

size = resdx.to_u(dx_unit.rated_net_total_cooling_capacity[0], "ton_ref")
Expand Down
320 changes: 148 additions & 172 deletions examples/inverse-calculations.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# %%
import csv
from copy import deepcopy
import numpy as np
from scipy import optimize

Expand All @@ -12,16 +14,95 @@
linear_string,
quadratic,
quadratic_string,
cubic,
cubic_string,
quartic,
quartic_string,
# cubic,
# cubic_string,
# quartic,
# quartic_string,
calculate_r_squared,
)

import resdx


class CurveFit:
def __init__(self, function, regression_string, initial_coefficient_guesses):
self.function = function
self.regression_string = regression_string
self.initial_coefficient_guesses = initial_coefficient_guesses


linear_curve_fit = CurveFit(linear, linear_string, (1, 1))
quadratic_curve_fit = CurveFit(quadratic, quadratic_string, (1, 1, 1))


class RatingRegression:
def __init__(
self,
staging_type: resdx.StagingType,
calculation,
target_title: str,
initial_guess,
rating_range: DisplayData,
secondary_range: DisplayData,
curve_fit: CurveFit,
):
self.staging_type = staging_type
self.calculation = calculation
self.target_title = target_title
self.initial_guess = initial_guess
self.rating_range = rating_range
self.secondary_range = secondary_range
self.curve_fit = curve_fit

def evaluate(self, output_name):
display_data = []
for secondary_value in self.secondary_range.data_values:
series_name = f"{self.secondary_range.name}={secondary_value:.2}"

print(f"Evaluating {self.staging_type.name} ({series_name})")
try:
inputs, coefficients = get_inverse_values(
self.rating_range,
lambda x, target: self.calculation(
x, target, self.staging_type, secondary_value
),
self.initial_guess,
curve_fit_function=self.curve_fit.function,
curve_fit_guesses=self.curve_fit.initial_coefficient_guesses,
)
except RuntimeError as e:
raise RuntimeError(
f"Unable to find solution for {self.staging_type.name} ({series_name}): {e}"
)

display_data.append(
DisplayData(
inputs,
name=series_name,
native_units="W/W",
line_properties=MarkersOnly(),
)
)
curve_fit_string = self.curve_fit.regression_string(
self.rating_range.name, *coefficients
)
curve_fit_data = [
self.curve_fit.function(rating, *coefficients)
for rating in self.rating_range.data_values
]
r2 = calculate_r_squared(inputs, curve_fit_data)
display_data.append(
DisplayData(
curve_fit_data,
name=f"{series_name}: {curve_fit_string}, R2={r2:.4g}",
native_units="W/W",
line_properties=LinesOnly(),
)
)

plot(self.rating_range, display_data, self.target_title, output_name)


def plot(x, ys, y_axis_name, figure_name):
plot = DimensionalPlot(x)
for y in ys:
Expand Down Expand Up @@ -61,182 +142,77 @@ def get_inverse_values(
return inverse_values, curve_fit_coefficients


def make_plot(target_range, systems, axis_title, figure_name):
display_data = []
for system_name, system in systems.items():
print(f"Calculating system: {system_name}")
try:
inputs, coefficients = get_inverse_values(
target_range,
system["calculation"],
initial_guess=system["initial_guess"],
curve_fit_function=system["curve_fit"]["function"],
curve_fit_guesses=system["curve_fit"]["guesses"],
)
except RuntimeError as e:
raise RuntimeError(f"Unable to find solution for {system_name}: {e}")

display_data.append(
DisplayData(
inputs,
name=system_name,
native_units="W/W",
line_properties=MarkersOnly(),
)
)
curve_fit_string = system["curve_fit"]["string"](
target_range.name, *coefficients
)
curve_fit_data = [
system["curve_fit"]["function"](metric, *coefficients)
for metric in target_range.data_values
]
r2 = calculate_r_squared(inputs, curve_fit_data)
display_data.append(
DisplayData(
curve_fit_data,
name=f"{system_name}: {curve_fit_string}, R2={r2:.4g}",
native_units="W/W",
line_properties=LinesOnly(),
)
)

plot(target_range, display_data, axis_title, figure_name)


# Cooling

cooling_systems = {
"Single Speed": {
"calculation": lambda cop, seer: resdx.DXUnit(
rated_gross_cooling_cop=cop, input_seer=seer
).seer(),
"initial_guess": lambda x: x / 3.0,
"curve_fit": {
"function": quadratic,
"string": quadratic_string,
"guesses": (1, 1, 1),
},
},
"Two Speed": {
"calculation": lambda cop, seer: resdx.DXUnit(
staging_type=resdx.StagingType.TWO_STAGE,
rated_gross_cooling_cop=cop,
input_seer=seer,
).seer(),
"initial_guess": lambda x: x / 3.0,
"curve_fit": {
"function": quadratic,
"string": quadratic_string,
"guesses": (1, 1, 1),
},
},
}


make_plot(
DimensionalData(np.linspace(6, 26.5, 10), name="SEER2", native_units="Btu/Wh"),
cooling_systems,
"Gross COP (at Afull conditions)",
"cooling-cop-v-seer",
def seer_function(cop_82_min, seer, staging_type, seer_eer_ratio):
return resdx.DXUnit(
staging_type=staging_type,
input_seer=seer,
input_eer=seer / seer_eer_ratio,
rated_net_total_cooling_cop_82_min=cop_82_min,
input_hspf=10.0,
).seer()


two_speed_cooling_regression = RatingRegression(
staging_type=resdx.StagingType.TWO_STAGE,
calculation=seer_function,
target_title="Net COP (at B low conditions)",
initial_guess=lambda target: target / 3.0,
rating_range=DimensionalData(
np.linspace(6, 26.5, 2), name="SEER2", native_units="Btu/Wh"
), # All straight lines don't need more than two points
secondary_range=DimensionalData(
np.linspace(1.2, 2.0, 10), name="SEER2/EER2", native_units="W/W"
),
curve_fit=linear_curve_fit,
)

seer_eer_ratio_range = np.linspace(1.2, 2.0, 10)


vs_cooling_systems = {}

for seer_eer_ratio in seer_eer_ratio_range:
vs_cooling_systems[f"SEER2/EER2={seer_eer_ratio:.2}"] = {
"calculation": lambda eir_r, seer, ratio=seer_eer_ratio: resdx.DXUnit(
staging_type=resdx.StagingType.VARIABLE_SPEED,
min_net_total_cooling_eir_ratio_82=eir_r,
input_eer=seer / ratio,
input_seer=seer,
input_hspf=10.0,
).seer(),
"initial_guess": lambda _: 0.75,
"curve_fit": {
"function": linear,
"string": linear_string,
"guesses": (1, 1),
},
}

make_plot(
DimensionalData(np.linspace(14, 35, 10), name="SEER2", native_units="Btu/Wh"),
vs_cooling_systems,
"Net COP 82 max / Net COP 82 min",
"cooling-vs-eir_r-v-seer",
variable_speed_cooling_regression = deepcopy(two_speed_cooling_regression)
variable_speed_cooling_regression.staging_type = resdx.StagingType.VARIABLE_SPEED
variable_speed_cooling_regression.rating_range = DimensionalData(
np.linspace(14, 35, 3), name="SEER2", native_units="Btu/Wh"
)

# two_speed_cooling_regression.evaluate("cooling-two-speed-cop82-v-seer")
# variable_speed_cooling_regression.evaluate("cooling-variable-speed-cop82-v-seer")


# Heating
heating_systems = {
"Single Speed": {
"calculation": lambda cop, hspf: resdx.DXUnit(
rated_gross_heating_cop=cop, input_hspf=hspf
).hspf(),
"initial_guess": lambda x: x / 2.0,
"curve_fit": {
"function": quartic,
"string": quartic_string,
"guesses": (1, 1, 1, 1, 1),
},
},
"Two Speed": {
"calculation": lambda cop, hspf: resdx.DXUnit(
staging_type=resdx.StagingType.TWO_STAGE,
rated_gross_heating_cop=cop,
input_hspf=hspf,
).hspf(),
"initial_guess": lambda x: x / 2.0,
"curve_fit": {
"function": cubic,
"string": cubic_string,
"guesses": (1, 1, 1, 1),
},
},
}

hspf_range = DimensionalData(
np.linspace(5, 16, 10), name="HSPF2", native_units="Btu/Wh"
def hspf_function(cop_47, hspf, staging_type, cap17m):
return resdx.DXUnit(
staging_type=staging_type,
rated_net_heating_capacity=fr_u(3.0, "ton_ref"),
rated_net_heating_capacity_17=fr_u(3.0, "ton_ref") * cap17m,
rated_net_heating_cop=cop_47,
input_hspf=hspf,
input_seer=19.0,
input_eer=10.0,
).hspf()


single_speed_heating_regression = RatingRegression(
staging_type=resdx.StagingType.SINGLE_STAGE,
calculation=hspf_function,
target_title="Net COP (at H1 full conditions)",
initial_guess=lambda target: target / 2.0,
rating_range=DimensionalData(
np.linspace(5, 11, 5), name="HSPF2", native_units="Btu/Wh"
),
secondary_range=DimensionalData(
[0.5, 0.55, 0.6, 0.7, 0.8, 1.1], name="Q17/Q47", native_units="Btu/Btu"
),
curve_fit=quadratic_curve_fit,
)

two_speed_heating_regression = deepcopy(single_speed_heating_regression)
two_speed_heating_regression.staging_type = resdx.StagingType.TWO_STAGE

make_plot(
hspf_range,
heating_systems,
"Gross COP (at H1full conditions)",
"heating-cop-v-hspf",
variable_speed_heating_regression = deepcopy(single_speed_heating_regression)
variable_speed_heating_regression.staging_type = resdx.StagingType.VARIABLE_SPEED
variable_speed_cooling_regression.rating_range = DimensionalData(
np.linspace(5, 16, 5), name="HSPF2", native_units="Btu/Wh"
)

cap_17_maintenance_range = [0.5, 0.55, 0.6, 0.7, 0.8, 1.1]


vs_heating_systems = {}

for cap_17_maintenance in cap_17_maintenance_range:
vs_heating_systems[f"Q17/Q47={cap_17_maintenance:.2}"] = {
"calculation": lambda cop, hspf, cap_m=cap_17_maintenance: resdx.DXUnit(
staging_type=resdx.StagingType.VARIABLE_SPEED,
rated_net_heating_capacity=fr_u(3.0, "ton_ref"),
rated_net_heating_capacity_17=fr_u(3.0, "ton_ref") * cap_m,
rated_net_heating_cop=cop,
input_eer=10,
input_seer=19.0,
input_hspf=hspf,
).hspf(),
"initial_guess": lambda x: x / 2.0,
"curve_fit": {
"function": quadratic,
"string": quadratic_string,
"guesses": (1, 1, 1),
},
}

make_plot(
hspf_range,
vs_heating_systems,
"Net COP (at H1full conditions)",
"heating-vs-cop-v-hspf",
)
single_speed_heating_regression.evaluate("heating-single-speed-cop47-v-hspf")
two_speed_heating_regression.evaluate("heating-two-speed-cop47-v-hspf")
variable_speed_heating_regression.evaluate("heating-variable-speed-cop47-v-hspf")
Loading

0 comments on commit 2b761ae

Please sign in to comment.