Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow instantaneous water heaters w/ larger tank volumes #1860

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions BuildResidentialHPXML/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2184,7 +2184,7 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument
water_heater_type_choices = OpenStudio::StringVector.new
water_heater_type_choices << Constants::None
water_heater_type_choices << HPXML::WaterHeaterTypeStorage
water_heater_type_choices << HPXML::WaterHeaterTypeTankless
water_heater_type_choices << HPXML::WaterHeaterTypeInstantaneous
water_heater_type_choices << HPXML::WaterHeaterTypeHeatPump
water_heater_type_choices << HPXML::WaterHeaterTypeCombiStorage
water_heater_type_choices << HPXML::WaterHeaterTypeCombiTankless
Expand Down Expand Up @@ -2262,7 +2262,7 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument

arg = OpenStudio::Measure::OSArgument::makeChoiceArgument('water_heater_usage_bin', water_heater_usage_bin_choices, false)
arg.setDisplayName('Water Heater: Usage Bin')
arg.setDescription("The usage of the water heater. Only applies if Efficiency Type is UniformEnergyFactor and Type is not #{HPXML::WaterHeaterTypeTankless}. Does not apply to space-heating boilers. If not provided, the OS-HPXML default (see <a href='#{docs_base_url}#conventional-storage'>Conventional Storage</a>, <a href='#{docs_base_url}#heat-pump'>Heat Pump</a>) is used.")
arg.setDescription("The usage of the water heater. Only applies if Efficiency Type is UniformEnergyFactor and Type is not #{HPXML::WaterHeaterTypeInstantaneous}. Does not apply to space-heating boilers. If not provided, the OS-HPXML default (see <a href='#{docs_base_url}#conventional-storage'>Conventional Storage</a>, <a href='#{docs_base_url}#heat-pump'>Heat Pump</a>) is used.")
args << arg

arg = OpenStudio::Measure::OSArgument::makeDoubleArgument('water_heater_recovery_efficiency', false)
Expand Down Expand Up @@ -2291,7 +2291,7 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument

arg = OpenStudio::Measure::OSArgument::makeDoubleArgument('water_heater_jacket_rvalue', false)
arg.setDisplayName('Water Heater: Jacket R-value')
arg.setDescription("The jacket R-value of water heater. Doesn't apply to #{HPXML::WaterHeaterTypeTankless} or #{HPXML::WaterHeaterTypeCombiTankless}. If not provided, defaults to no jacket insulation.")
arg.setDescription("The jacket R-value of water heater. Doesn't apply to #{HPXML::WaterHeaterTypeInstantaneous} or #{HPXML::WaterHeaterTypeCombiTankless}. If not provided, defaults to no jacket insulation.")
arg.setUnits('h-ft^2-R/Btu')
args << arg

Expand Down Expand Up @@ -6547,7 +6547,7 @@ def self.set_water_heating_systems(hpxml_bldg, args)
energy_factor = args[:water_heater_efficiency]
elsif args[:water_heater_efficiency_type] == 'UniformEnergyFactor'
uniform_energy_factor = args[:water_heater_efficiency]
if water_heater_type != HPXML::WaterHeaterTypeTankless
if water_heater_type != HPXML::WaterHeaterTypeInstantaneous
usage_bin = args[:water_heater_usage_bin]
end
end
Expand All @@ -6557,11 +6557,11 @@ def self.set_water_heating_systems(hpxml_bldg, args)
recovery_efficiency = args[:water_heater_recovery_efficiency]
end

if [HPXML::WaterHeaterTypeTankless, HPXML::WaterHeaterTypeCombiTankless].include? water_heater_type
if [HPXML::WaterHeaterTypeInstantaneous, HPXML::WaterHeaterTypeCombiTankless].include? water_heater_type
args[:water_heater_tank_volume] = nil
end

if [HPXML::WaterHeaterTypeTankless].include? water_heater_type
if [HPXML::WaterHeaterTypeInstantaneous].include? water_heater_type
heating_capacity = nil
recovery_efficiency = nil
elsif [HPXML::WaterHeaterTypeCombiTankless, HPXML::WaterHeaterTypeCombiStorage].include? water_heater_type
Expand All @@ -6580,7 +6580,7 @@ def self.set_water_heating_systems(hpxml_bldg, args)
end
end

if not [HPXML::WaterHeaterTypeTankless, HPXML::WaterHeaterTypeCombiTankless].include? water_heater_type
if not [HPXML::WaterHeaterTypeInstantaneous, HPXML::WaterHeaterTypeCombiTankless].include? water_heater_type
if args[:water_heater_jacket_rvalue].to_f > 0
jacket_r_value = args[:water_heater_jacket_rvalue]
end
Expand Down
6 changes: 3 additions & 3 deletions BuildResidentialHPXML/measure.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<schema_version>3.1</schema_version>
<name>build_residential_hpxml</name>
<uid>a13a8983-2b01-4930-8af2-42030b6e4233</uid>
<version_id>8dfdc271-772e-46a3-a611-71ca703a96c2</version_id>
<version_modified>2024-10-14T23:23:50Z</version_modified>
<version_id>22cac8e6-3e14-43cf-8f35-936ea8d5c875</version_id>
<version_modified>2024-10-16T18:14:35Z</version_modified>
<xml_checksum>2C38F48B</xml_checksum>
<class_name>BuildResidentialHPXML</class_name>
<display_name>HPXML Builder</display_name>
Expand Down Expand Up @@ -7544,7 +7544,7 @@
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>F2C64E58</checksum>
<checksum>7ABB3719</checksum>
</file>
<file>
<filename>constants.rb</filename>
Expand Down
18 changes: 9 additions & 9 deletions HPXMLtoOpenStudio/measure.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<schema_version>3.1</schema_version>
<name>hpxm_lto_openstudio</name>
<uid>b1543b30-9465-45ff-ba04-1d1f85e763bc</uid>
<version_id>5c60d469-73ac-415f-b37f-8b8401c8d5f3</version_id>
<version_modified>2024-10-16T17:32:33Z</version_modified>
<version_id>4bc6959d-1dff-4e25-9af0-3460e4f474a5</version_id>
<version_modified>2024-10-16T18:14:39Z</version_modified>
<xml_checksum>D8922A73</xml_checksum>
<class_name>HPXMLtoOpenStudio</class_name>
<display_name>HPXML to OpenStudio Translator</display_name>
Expand Down Expand Up @@ -327,7 +327,7 @@
<filename>defaults.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>1B4820ED</checksum>
<checksum>5FEBB017</checksum>
</file>
<file>
<filename>energyplus.rb</filename>
Expand Down Expand Up @@ -357,7 +357,7 @@
<filename>hpxml.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>F866C769</checksum>
<checksum>B1AABDBA</checksum>
</file>
<file>
<filename>hpxml_schema/HPXML.xsd</filename>
Expand All @@ -375,7 +375,7 @@
<filename>hpxml_schematron/EPvalidator.xml</filename>
<filetype>xml</filetype>
<usage_type>resource</usage_type>
<checksum>BD9733AC</checksum>
<checksum>C2F5CF6D</checksum>
</file>
<file>
<filename>hpxml_schematron/iso-schematron.xsd</filename>
Expand Down Expand Up @@ -627,7 +627,7 @@
<filename>waterheater.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>6F8A18EC</checksum>
<checksum>661771DC</checksum>
</file>
<file>
<filename>weather.rb</filename>
Expand Down Expand Up @@ -663,7 +663,7 @@
<filename>test_defaults.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>9DD97EAF</checksum>
<checksum>5E703194</checksum>
</file>
<file>
<filename>test_enclosure.rb</filename>
Expand Down Expand Up @@ -735,13 +735,13 @@
<filename>test_validation.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>7CB39E62</checksum>
<checksum>6766741E</checksum>
</file>
<file>
<filename>test_water_heater.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>A293B678</checksum>
<checksum>9277F61D</checksum>
</file>
<file>
<filename>test_weather.rb</filename>
Expand Down
4 changes: 2 additions & 2 deletions HPXMLtoOpenStudio/resources/defaults.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4945,13 +4945,13 @@ def self.get_water_heater_temperature(eri_version)
end
end

# Gets the default performance adjustment for a tankless water heater. Multiplier on efficiency
# Gets the default performance adjustment for an instantaneous water heater. Multiplier on efficiency
# to account for cycling.
#
# @param water_heating_system [HPXML::WaterHeatingSystem] The HPXML water heating system of interest
# @return [Double] Water heater performance adjustment (frac)
def self.get_water_heater_performance_adjustment(water_heating_system)
return unless water_heating_system.water_heater_type == HPXML::WaterHeaterTypeTankless
return unless water_heating_system.water_heater_type == HPXML::WaterHeaterTypeInstantaneous
if not water_heating_system.energy_factor.nil?
return 0.92 # Applies to EF, ANSI 301-2019
elsif not water_heating_system.uniform_energy_factor.nil?
Expand Down
2 changes: 1 addition & 1 deletion HPXMLtoOpenStudio/resources/hpxml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ class HPXML < Object
WaterHeaterTypeCombiStorage = 'space-heating boiler with storage tank'
WaterHeaterTypeCombiTankless = 'space-heating boiler with tankless coil'
WaterHeaterTypeHeatPump = 'heat pump water heater'
WaterHeaterTypeTankless = 'instantaneous water heater'
WaterHeaterTypeInstantaneous = 'instantaneous water heater'
WaterHeaterTypeStorage = 'storage water heater'
WaterHeaterUsageBinVerySmall = 'very small'
WaterHeaterUsageBinLow = 'low'
Expand Down
4 changes: 2 additions & 2 deletions HPXMLtoOpenStudio/resources/hpxml_schematron/EPvalidator.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2139,7 +2139,7 @@
<sch:rule context='/h:HPXML/h:Building/h:BuildingDetails/h:Systems/h:WaterHeating/h:WaterHeatingSystem'>
<sch:assert role='ERROR' test='count(../h:HotWaterDistribution) = 1'>Expected 1 element(s) for xpath: ../HotWaterDistribution</sch:assert> <!-- See [HotWaterDistribution] -->
<sch:assert role='ERROR' test='count(../h:WaterFixture) &gt;= 1'>Expected 1 or more element(s) for xpath: ../WaterFixture</sch:assert> <!-- See [WaterFixture] -->
<sch:assert role='ERROR' test='count(h:WaterHeaterType) = 1'>Expected 1 element(s) for xpath: WaterHeaterType</sch:assert> <!-- See [WaterHeatingSystemType=Tank] or [WaterHeatingSystemType=Tankless] or [WaterHeatingSystemType=HeatPump] or [WaterHeatingSystemType=CombiIndirect] or [WaterHeatingSystemType=CombiTanklessCoil] -->
<sch:assert role='ERROR' test='count(h:WaterHeaterType) = 1'>Expected 1 element(s) for xpath: WaterHeaterType</sch:assert> <!-- See [WaterHeatingSystemType=Tank] or [WaterHeatingSystemType=Instantaneous] or [WaterHeatingSystemType=HeatPump] or [WaterHeatingSystemType=CombiIndirect] or [WaterHeatingSystemType=CombiTanklessCoil] -->
<sch:assert role='ERROR' test='h:WaterHeaterType[text()="storage water heater" or text()="instantaneous water heater" or text()="heat pump water heater" or text()="space-heating boiler with storage tank" or text()="space-heating boiler with tankless coil"] or not(h:WaterHeaterType)'>Expected WaterHeaterType to be 'storage water heater' or 'instantaneous water heater' or 'heat pump water heater' or 'space-heating boiler with storage tank' or 'space-heating boiler with tankless coil'</sch:assert>
</sch:rule>
</sch:pattern>
Expand Down Expand Up @@ -2177,7 +2177,7 @@
</sch:pattern>

<sch:pattern>
<sch:title>[WaterHeatingSystemType=Tankless]</sch:title>
<sch:title>[WaterHeatingSystemType=Instantaneous]</sch:title>
<sch:rule context='/h:HPXML/h:Building/h:BuildingDetails/h:Systems/h:WaterHeating/h:WaterHeatingSystem[h:WaterHeaterType="instantaneous water heater"]'>
<sch:assert role='ERROR' test='count(h:FuelType) = 1'>Expected 1 element(s) for xpath: FuelType</sch:assert>
<sch:assert role='ERROR' test='h:FuelType[text()="natural gas" or text()="fuel oil" or text()="fuel oil 1" or text()="fuel oil 2" or text()="fuel oil 4" or text()="fuel oil 5/6" or text()="diesel" or text()="propane" or text()="kerosene" or text()="coal" or text()="coke" or text()="bituminous coal" or text()="anthracite coal" or text()="electricity" or text()="wood" or text()="wood pellets"] or not(h:FuelType)'>Expected FuelType to be 'natural gas' or 'fuel oil' or 'fuel oil 1' or 'fuel oil 2' or 'fuel oil 4' or 'fuel oil 5/6' or 'diesel' or 'propane' or 'kerosene' or 'coal' or 'coke' or 'bituminous coal' or 'anthracite coal' or 'electricity' or 'wood' or 'wood pellets'</sch:assert>
Expand Down
14 changes: 7 additions & 7 deletions HPXMLtoOpenStudio/resources/waterheater.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ def self.apply_dhw_appliances(runner, model, weather, spaces, hpxml_bldg, hpxml_
hpxml_bldg.water_heating_systems.each do |dhw_system|
if dhw_system.water_heater_type == HPXML::WaterHeaterTypeStorage
apply_tank(model, runner, spaces, hpxml_bldg, hpxml_header, dhw_system, schedules_file, unavailable_periods, plantloop_map)
elsif dhw_system.water_heater_type == HPXML::WaterHeaterTypeTankless
apply_tankless(model, runner, spaces, hpxml_bldg, hpxml_header, dhw_system, schedules_file, unavailable_periods, plantloop_map)
elsif dhw_system.water_heater_type == HPXML::WaterHeaterTypeInstantaneous
apply_instantaneous(model, runner, spaces, hpxml_bldg, hpxml_header, dhw_system, schedules_file, unavailable_periods, plantloop_map)
elsif dhw_system.water_heater_type == HPXML::WaterHeaterTypeHeatPump
apply_heatpump(model, runner, spaces, hpxml_bldg, hpxml_header, dhw_system, schedules_file, unavailable_periods, plantloop_map)
elsif [HPXML::WaterHeaterTypeCombiStorage, HPXML::WaterHeaterTypeCombiTankless].include? dhw_system.water_heater_type
Expand Down Expand Up @@ -95,7 +95,7 @@ def self.apply_tank(model, runner, spaces, hpxml_bldg, hpxml_header, water_heati
# @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies
# @param plantloop_map [Hash] Map of HPXML System ID => OpenStudio PlantLoop objects
# @return [nil]
def self.apply_tankless(model, runner, spaces, hpxml_bldg, hpxml_header, water_heating_system, schedules_file, unavailable_periods, plantloop_map)
def self.apply_instantaneous(model, runner, spaces, hpxml_bldg, hpxml_header, water_heating_system, schedules_file, unavailable_periods, plantloop_map)
loc_space, loc_schedule = Geometry.get_space_or_schedule_from_location(water_heating_system.location, model, spaces)
unit_multiplier = hpxml_bldg.building_construction.number_of_units
water_heating_system.heating_capacity = 100000000000.0 * unit_multiplier
Expand Down Expand Up @@ -1573,15 +1573,15 @@ def self.calc_ef_from_uef(water_heating_system)
if water_heating_system.fuel_type == HPXML::FuelTypeElectricity
if water_heating_system.water_heater_type == HPXML::WaterHeaterTypeStorage
return [2.4029 * water_heating_system.uniform_energy_factor - 1.2844, 0.96].min
elsif water_heating_system.water_heater_type == HPXML::WaterHeaterTypeTankless
elsif water_heating_system.water_heater_type == HPXML::WaterHeaterTypeInstantaneous
return water_heating_system.uniform_energy_factor
elsif water_heating_system.water_heater_type == HPXML::WaterHeaterTypeHeatPump
return 1.2101 * water_heating_system.uniform_energy_factor - 0.6052
end
else # Fuel
if water_heating_system.water_heater_type == HPXML::WaterHeaterTypeStorage
return 0.9066 * water_heating_system.uniform_energy_factor + 0.0711
elsif water_heating_system.water_heater_type == HPXML::WaterHeaterTypeTankless
elsif water_heating_system.water_heater_type == HPXML::WaterHeaterTypeInstantaneous
return water_heating_system.uniform_energy_factor
end
end
Expand Down Expand Up @@ -1816,7 +1816,7 @@ def self.calc_tank_UA(act_vol, water_heating_system, solar_fraction, nbeds)
# Calculates the U value, UA of the tank and conversion efficiency (eta_c)
# based on the Uniform Energy Factor, First Hour Rating, and Recovery Efficiency of the tank
# Source: Maguire and Roberts 2020 - https://www.ashrae.org/file%20library/conferences/specialty%20conferences/2020%20building%20performance/papers/d-bsc20-c039.pdf
if water_heating_system.water_heater_type == HPXML::WaterHeaterTypeTankless
if water_heating_system.water_heater_type == HPXML::WaterHeaterTypeInstantaneous
if not water_heating_system.energy_factor.nil?
eta_c = water_heating_system.energy_factor * water_heating_system.performance_adjustment
elsif not water_heating_system.uniform_energy_factor.nil?
Expand Down Expand Up @@ -2002,7 +2002,7 @@ def self.create_new_heater(name:, water_heating_system: nil, act_vol:, t_set_c:
new_heater.setTankVolume(UnitConversions.convert(act_vol, 'gal', 'm^3'))
new_heater.setHeaterThermalEfficiency(eta_c) unless eta_c.nil?
new_heater.setMaximumTemperatureLimit(99.0)
if [HPXML::WaterHeaterTypeTankless, HPXML::WaterHeaterTypeCombiTankless].include? tank_type
if [HPXML::WaterHeaterTypeInstantaneous, HPXML::WaterHeaterTypeCombiTankless].include? tank_type
new_heater.setHeaterControlType('Modulate')
else
new_heater.setHeaterControlType('Cycle')
Expand Down
18 changes: 9 additions & 9 deletions HPXMLtoOpenStudio/tests/test_defaults.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3234,27 +3234,27 @@ def test_storage_water_heaters
assert_equal(HPXML::WaterHeaterTankModelTypeMixed, default_hpxml_bldg.water_heating_systems[0].tank_model_type)
end

def test_tankless_water_heaters
def test_instantaneous_water_heaters
# Test inputs not overridden by defaults
hpxml, hpxml_bldg = _create_hpxml('base-dhw-tankless-gas.xml')
hpxml, hpxml_bldg = _create_hpxml('base-dhw-instantaneous-gas.xml')
hpxml_bldg.water_heating_systems[0].performance_adjustment = 0.88
XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path)
_default_hpxml, default_hpxml_bldg = _test_measure()
_test_default_tankless_water_heater_values(default_hpxml_bldg, [0.88])
_test_default_instantaneous_water_heater_values(default_hpxml_bldg, [0.88])

# Test defaults w/ EF
hpxml_bldg.water_heating_systems[0].performance_adjustment = nil
XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path)
_default_hpxml, default_hpxml_bldg = _test_measure()
_test_default_tankless_water_heater_values(default_hpxml_bldg, [0.92])
_test_default_instantaneous_water_heater_values(default_hpxml_bldg, [0.92])

# Test defaults w/ UEF
hpxml_bldg.water_heating_systems[0].energy_factor = nil
hpxml_bldg.water_heating_systems[0].uniform_energy_factor = 0.93
hpxml_bldg.water_heating_systems[0].first_hour_rating = 5.7
XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path)
_default_hpxml, default_hpxml_bldg = _test_measure()
_test_default_tankless_water_heater_values(default_hpxml_bldg, [0.94])
_test_default_instantaneous_water_heater_values(default_hpxml_bldg, [0.94])
end

def test_heat_pump_water_heaters
Expand Down Expand Up @@ -5518,10 +5518,10 @@ def _test_default_storage_water_heater_values(hpxml_bldg, *expected_wh_values)
end
end

def _test_default_tankless_water_heater_values(hpxml_bldg, *expected_wh_values)
tankless_water_heaters = hpxml_bldg.water_heating_systems.select { |w| w.water_heater_type == HPXML::WaterHeaterTypeTankless }
assert_equal(expected_wh_values.size, tankless_water_heaters.size)
tankless_water_heaters.each_with_index do |wh_system, idx|
def _test_default_instantaneous_water_heater_values(hpxml_bldg, *expected_wh_values)
instantaneous_water_heaters = hpxml_bldg.water_heating_systems.select { |w| w.water_heater_type == HPXML::WaterHeaterTypeInstantaneous }
assert_equal(expected_wh_values.size, instantaneous_water_heaters.size)
instantaneous_water_heaters.each_with_index do |wh_system, idx|
performance_adjustment, = expected_wh_values[idx]

assert_equal(performance_adjustment, wh_system.performance_adjustment)
Expand Down
2 changes: 1 addition & 1 deletion HPXMLtoOpenStudio/tests/test_validation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,7 @@ def test_schema_schematron_warning_messages
hpxml, hpxml_bldg = _create_hpxml('base-dhw-multiple.xml')
hpxml_bldg.water_heating_systems.each do |water_heating_system|
if [HPXML::WaterHeaterTypeStorage,
HPXML::WaterHeaterTypeTankless].include? water_heating_system.water_heater_type
HPXML::WaterHeaterTypeInstantaneous].include? water_heating_system.water_heater_type
water_heating_system.energy_factor = 0.1
end
end
Expand Down
Loading