Skip to content

Commit

Permalink
moved some low power HPWH inputs to hpxml.py
Browse files Browse the repository at this point in the history
  • Loading branch information
mnblonsky committed Aug 29, 2024
1 parent b781132 commit 49350c6
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 48 deletions.
35 changes: 12 additions & 23 deletions ochre/Equipment/WaterHeater.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,12 +413,8 @@ class HeatPumpWaterHeater(ElectricResistanceWaterHeater):
def __init__(self, hp_only_mode=False, water_nodes=12, **kwargs):
super().__init__(water_nodes=water_nodes, **kwargs)

self.low_power_hpwh = kwargs.get('Low Power HPWH', False)

# Control parameters
self.hp_only_mode = hp_only_mode
if self.low_power_hpwh:
self.hp_only_mode = True
self.er_only_mode = False # True when ambient temp is very hot or cold, forces HP off
hp_on_time = kwargs.get('HPWH Minimum On Time (min)', 10)
hp_off_time = kwargs.get('HPWH Minimum Off Time (min)', 0)
Expand All @@ -428,26 +424,19 @@ def __init__(self, hp_only_mode=False, water_nodes=12, **kwargs):
self.deadband_temp = kwargs.get('Deadband Temperature (C)', 8.17) # different default than ERWH

# Nominal COP based on simulation of the UEF test procedure at varying COPs
if self.low_power_hpwh: #TODO: can read a lot of these directly when properly integrated into HPXML
self.cop_nominal = 4.2
self.hp_cop = self.cop_nominal
self.hp_capacity_nominal = 1499.4
hp_power_nominal = self.hp_capacity_nominal / self.cop_nominal # in W
self.hp_capacity_nominal = hp_power_nominal * self.hp_cop # in W
self.hp_capacity = self.hp_capacity_nominal # in W
self.low_power_hpwh = kwargs.get('Low Power HPWH', False)
self.cop_nominal = kwargs['HPWH COP (-)']
self.hp_cop = self.cop_nominal
if self.cop_nominal < 2:
self.warn("Low Nominal COP:", self.cop_nominal)

# Heat pump capacity and power parameters - hardcoded for now
if 'HPWH Capacity (W)' in kwargs:
self.hp_capacity_nominal = kwargs['HPWH Capacity (W)'] # max heating capacity, in W
else:
self.cop_nominal = kwargs['HPWH COP (-)']
self.hp_cop = self.cop_nominal
if self.cop_nominal < 2:
self.warn("Low Nominal COP:", self.cop_nominal)

# Heat pump capacity and power parameters - hardcoded for now
if 'HPWH Capacity (W)' in kwargs:
self.hp_capacity_nominal = kwargs['HPWH Capacity (W)'] # max heating capacity, in W
else:
hp_power_nominal = kwargs.get('HPWH Power (W)', 500) # in W
self.hp_capacity_nominal = hp_power_nominal * self.hp_cop # in W
self.hp_capacity = self.hp_capacity_nominal # in W
hp_power_nominal = kwargs.get('HPWH Power (W)', 500) # in W
self.hp_capacity_nominal = hp_power_nominal * self.hp_cop # in W
self.hp_capacity = self.hp_capacity_nominal # in W
self.parasitic_power = kwargs.get('HPWH Parasitics (W)', 1) # Standby power in W
self.fan_power = kwargs.get('HPWH Fan Power (W)', 35) # in W

Expand Down
53 changes: 28 additions & 25 deletions ochre/utils/hpxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,7 @@ def parse_water_heater(water_heater, water, construction, solar_fraction=0):
# Inputs from HPXML
water_heater_type = water_heater['WaterHeaterType']
is_electric = water_heater['FuelType'] == 'electricity'
t_set = convert(water_heater.get('HotWaterTemperature', 125), 'degF', 'degC')
energy_factor = water_heater.get('EnergyFactor')
uniform_energy_factor = water_heater.get('UniformEnergyFactor')
n_beds = construction['Number of Bedrooms (-)']
Expand All @@ -932,7 +933,6 @@ def parse_water_heater(water_heater, water, construction, solar_fraction=0):
first_hour_rating = water_heater.get('FirstHourRating')
recovery_efficiency = water_heater.get('RecoveryEfficiency')
tank_jacket_r = water_heater.get('WaterHeaterInsulation', {}).get('Jacket', {}).get('JacketRValue', 0)
low_power_hpwh = False

# calculate actual volume from rated volume
if volume_gal is not None:
Expand Down Expand Up @@ -960,9 +960,6 @@ def parse_water_heater(water_heater, water, construction, solar_fraction=0):
elif water_heater_type == 'heat pump water heater':
assert is_electric
eta_c = 1
if uniform_energy_factor == 4.9: #FIXME: temporary flag for designating 120V HPWHs in panels branch of ResStock
low_power_hpwh = True

# HPWH UA calculation taken from ResStock:
# https://github.com/NREL/resstock/blob/run/restructure-v3/resources/hpxml-measures/HPXMLtoOpenStudio/resources/waterheater.rb#L765
if volume_gal <= 58.0:
Expand Down Expand Up @@ -1018,7 +1015,6 @@ def parse_water_heater(water_heater, water, construction, solar_fraction=0):

else:
raise OCHREException(f'Unknown water heater type: {water_heater_type}')


# Increase insulation from tank jacket (reduces UA)
if tank_jacket_r:
Expand All @@ -1036,26 +1032,19 @@ def parse_water_heater(water_heater, water, construction, solar_fraction=0):
if eta_c > 1.0:
raise OCHREException('A water heater heat source (either burner or element) efficiency of > 1 has been calculated.'
' Double check water heater inputs.')

if low_power_hpwh:
t_set = convert(140, 'degF', 'degC')
t_temper = convert(125, 'degF', 'degC')
else:
t_set = convert(water_heater.get('HotWaterTemperature', 125), 'degF', 'degC')
t_temper = t_set

wh = {
'Equipment Name': water_heater_type,
'Fuel': water_heater['FuelType'].capitalize(),
'Zone': parse_zone_name(water_heater['Location']),
'Setpoint Temperature (C)': t_set,
'Temepring Valve Setpoint (C)': t_temper,
"Equipment Name": water_heater_type,
"Fuel": water_heater["FuelType"].capitalize(),
"Zone": parse_zone_name(water_heater["Location"]),
"Setpoint Temperature (C)": t_set,
"Tempering Valve Setpoint (C)": None,
# 'Heat Transfer Coefficient (W/m^2/K)': u,
'UA (W/K)': convert(ua, 'Btu/hour/degR', 'W/K'),
'Efficiency (-)': eta_c,
'Energy Factor (-)': energy_factor,
'Tank Volume (L)': volume,
'Tank Height (m)': height,
'Low Power HPWH': low_power_hpwh,
"UA (W/K)": convert(ua, "Btu/hour/degR", "W/K"),
"Efficiency (-)": eta_c,
"Energy Factor (-)": energy_factor,
"Tank Volume (L)": volume,
"Tank Height (m)": height,
}
if heating_capacity is not None:
wh['Capacity (W)'] = convert(heating_capacity, 'Btu/hour', 'W')
Expand All @@ -1064,8 +1053,22 @@ def parse_water_heater(water_heater, water, construction, solar_fraction=0):
# add HPWH COP, from ResStock, defaults to using UEF
if uniform_energy_factor is None:
uniform_energy_factor = (0.60522 + energy_factor) / 1.2101
cop = 1.174536058 * uniform_energy_factor # Based on simulation of the UEF test procedure at varying COPs
wh['HPWH COP (-)'] = cop

# Add/update parameters for low power HPWH
# FIXME: temporary flag for designating 120V HPWHs in panels branch of ResStock
if uniform_energy_factor == 4.9:
wh.update({
"Low Power HPWH": True,
"HPWH COP (-)": 4.2,
"HPWH Capacity (W)": 1499.4,
"Setpoint Temperature (C)": convert(140, "degF", "degC"),
"Tempering Valve Setpoint (C)": convert(125, "degF", "degC"),
"hp_only_mode": True,
})
else:
# Based on simulation of the UEF test procedure at varying COPs
wh["HPWH COP (-)"] = 1.174536058 * uniform_energy_factor

if water_heater_type == 'instantaneous water heater' and wh['Fuel'] != 'Electricity':
on_time_frac = [0.0269, 0.0333, 0.0397, 0.0462, 0.0529][n_beds - 1]
wh['Parasitic Power (W)'] = 5 + 60 * on_time_frac
Expand Down

0 comments on commit 49350c6

Please sign in to comment.