diff --git a/copper/unitarydirectexpansion.py b/copper/unitarydirectexpansion.py index 4b065db..4f87d15 100644 --- a/copper/unitarydirectexpansion.py +++ b/copper/unitarydirectexpansion.py @@ -52,6 +52,7 @@ def __init__( }, }, indoor_fan_speeds=1, + fan_power_unit="kW", ): global log_fan self.type = "UnitaryDirectExpansion" @@ -67,28 +68,59 @@ def __init__( else: if indoor_fan_power == None: # This is 400 cfm/ton and 0.365 W/cfm. Equation 11.1 from AHRI 210/240 (2024). - indoor_fan_power = 0.28434517 * ref_net_cap * 400 * 0.365 / 1000 + fan_power_unit = "kW" + indoor_fan_power = Units( + value=Units(value=ref_net_cap, unit=ref_cap_unit).conversion( + new_unit="ton" + ) + * 400 + * 0.365, + unit="W", + ).conversion(new_unit=fan_power_unit) if not log_fan: logging.info(f"Default fan power used: {indoor_fan_power} kW") log_fan = True - ref_gross_cap = ref_net_cap + indoor_fan_power + ref_gross_cap = Units( + value=Units(value=ref_net_cap, unit=ref_cap_unit).conversion( + new_unit=fan_power_unit + ) + + indoor_fan_power, + unit=fan_power_unit, + ).conversion(ref_cap_unit) else: if ref_net_cap != None: logging.error("Input must be one and only one capacity input") raise ValueError("Input must be one and only one capacity input") if indoor_fan_power == None: # This is 400 cfm/ton and 0.365 W/cfm. Equation 11.1 from AHRI 210/240 (2024). - indoor_fan_power = ( - 0.28434517 - * 400 - * 0.365 - * (ref_gross_cap / 1000) - / (1 + 0.28434517 * 400 * 0.365) - ) + fan_power_unit = "kW" + indoor_fan_power = Units( + value=( + 400 + * 0.365 + * Units(value=ref_gross_cap, unit=ref_cap_unit).conversion( + new_unit="ton" + ) + ) + / ( + 1 + + 400 + * 0.365 + * Units(value=1.0, unit=ref_cap_unit).conversion(new_unit="ton") + * Units(value=1.0, unit="W").conversion(new_unit=ref_cap_unit) + ), + unit="W", + ).conversion(new_unit=fan_power_unit) if not log_fan: logging.info(f"Default fan power used: {indoor_fan_power} kW") log_fan = True - ref_net_cap = ref_gross_cap - indoor_fan_power + ref_net_cap = Units( + value=Units(value=ref_gross_cap, unit=ref_cap_unit).conversion( + new_unit=fan_power_unit + ) + - indoor_fan_power, + unit=fan_power_unit, + ).conversion(ref_cap_unit) self.ref_cap_unit = ref_cap_unit if self.ref_cap_unit != "kW": ref_net_cap_ton = Units(value=ref_net_cap, unit=self.ref_cap_unit) @@ -99,6 +131,7 @@ def __init__( else: self.ref_net_cap = ref_net_cap self.ref_gross_cap = ref_gross_cap + self.ref_cap_unit = ref_cap_unit # Get attributes self.full_eff = full_eff @@ -117,10 +150,10 @@ def __init__( self.part_eff_ref_std_alt = part_eff_ref_std_alt self.condenser_type = condenser_type self.compressor_speed = compressor_speed - self.ref_cap_unit = ref_cap_unit self.indoor_fan_speeds_mapping = indoor_fan_speeds_mapping self.indoor_fan_speeds = indoor_fan_speeds self.indoor_fan_power = indoor_fan_power + self.fan_power_unit = fan_power_unit # Define rated temperatures # air entering drybulb, air entering wetbulb, entering condenser temperature, leaving condenser temperature diff --git a/copper/units.py b/copper/units.py index 77907d2..c056985 100644 --- a/copper/units.py +++ b/copper/units.py @@ -69,16 +69,22 @@ def conversion(self, new_unit): return self.value * (kbtu_to_kw / ton_to_kbtu) elif self.unit == "W": return self.value * (kbtu_to_kw / (ton_to_kbtu * 1000)) + if self.unit == "ton": + return self.value elif new_unit == "kW": if self.unit == "ton": return self.value / (kbtu_to_kw / ton_to_kbtu) if self.unit == "W": return self.value / 1000 + if self.unit == "kW": + return self.value elif new_unit == "W": if self.unit == "ton": return self.value / (kbtu_to_kw / (ton_to_kbtu * 1000)) if self.unit == "kW": return self.value * 1000 + if self.unit == "W": + return self.value elif new_unit == "degC": if self.unit == "degF": return (self.value - 32) * 5 / 9 diff --git a/tests/test_unitarydirectexpansion.py b/tests/test_unitarydirectexpansion.py index b5871fd..27f39a3 100644 --- a/tests/test_unitarydirectexpansion.py +++ b/tests/test_unitarydirectexpansion.py @@ -30,8 +30,8 @@ class UnitaryDirectExpansion(TestCase): ) def test_calc_eff_ect(self): - ieer = round(self.dx_unit_dft.calc_rated_eff(), 1) - self.assertTrue(5.7 == ieer, f"{ieer} is different than 5.7") + ieer = round(self.dx_unit_dft.calc_rated_eff(unit="eer"), 1) + self.assertTrue(7.5 == ieer, f"{ieer} is different than 7.5") # Two-speed fan unit dx_unit_two_speed = self.dx_unit_dft @@ -39,6 +39,69 @@ def test_calc_eff_ect(self): ieer_two_spd = round(dx_unit_two_speed.calc_rated_eff(), 2) assert ieer_two_spd > ieer + def test_check_net_gross_capacity(self): + # Check that the difference between the gross and net capacity is the indoor fan power + assert round( + cp.Units( + value=self.dx_unit_dft.ref_gross_cap - self.dx_unit_dft.ref_net_cap, + unit=self.dx_unit_dft.ref_cap_unit, + ).conversion(new_unit="kW"), + 3, + ) == round(self.dx_unit_dft.indoor_fan_power, 3) + + # Same check but with "ton" based capacity + dx_unit_alt = cp.UnitaryDirectExpansion( + compressor_type="scroll", + condenser_type="air", + compressor_speed="constant", + ref_cap_unit="ton", + ref_gross_cap=2.5, + full_eff=5.89, + full_eff_unit="cop", + part_eff_ref_std="ahri_340/360", + model="simplified_bf", + sim_engine="energyplus", + set_of_curves=self.lib.get_set_of_curves_by_name("D208122216").curves, + ) + assert round( + cp.Units( + value=dx_unit_alt.ref_gross_cap - dx_unit_alt.ref_net_cap, + unit=dx_unit_alt.ref_cap_unit, + ).conversion(new_unit="kW"), + 3, + ) == round(dx_unit_alt.indoor_fan_power, 3) + + def test_check_lib_ieer(self): + # Get all curves from the library + filters = [("eqp_type", "UnitaryDirectExpansion")] + curves = self.lib.find_set_of_curves_from_lib( + filters=filters, part_eff_flag=True + ) + + for i in range(len(curves)): + # Get equipment from curves from the library + eqp = curves[i].eqp + + # Assign a default PLF curve + plf_f_plr = cp.Curve(eqp=eqp, c_type="linear") + plf_f_plr.out_var = "plf-f-plr" + plf_f_plr.type = "linear" + plf_f_plr.coeff1 = 1 - eqp.degradation_coefficient * 0.9 # TODO: to revise + plf_f_plr.coeff2 = eqp.degradation_coefficient * 0.9 + plf_f_plr.x_min = 0 + plf_f_plr.x_max = 1 + plf_f_plr.out_min = 0 + plf_f_plr.out_max = 1 + + # Re-assigne curve to equipment + eqp.set_of_curves = curves[i].curves + eqp.set_of_curves.append(plf_f_plr) + + # Check that the IEER is always better than full load EER + assert round(eqp.full_eff, 2) < round( + eqp.calc_rated_eff(eff_type="part", unit="eer"), 3 + ) + def test_multi_speed(self): # Two-speed fan unit dx_unit_two_speed = self.dx_unit_dft