Skip to content

Commit

Permalink
Merge pull request #868 from NREL/split-combi-system
Browse files Browse the repository at this point in the history
Two boiler approach for combi system
  • Loading branch information
shorowit authored Apr 15, 2022
2 parents 4ea596c + 6b7361d commit 62f3722
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 174 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ __New Features__
- The `WaterFixturesUsageMultiplier` input now also applies to general water use internal gains and recirculation pump energy (for some control types).
- Relaxes requirement for `ConditionedFloorAreaServed` for air distribution systems; now only needed if duct surface areas not provided.
- **Breaking change**: Each `VentilationFan` must have one (and only one) `UsedFor...` element set to true.
- Updates combi boiler model to be simpler, faster, and more robust by using separate space/water heating plant loops and boilers.
- BuildResidentialHPXML measure:
- **Breaking change**: Changes the zip code argument name to `site_zip_code`.
- Adds support for ambient foundations for single-family attached and apartment units.
Expand Down
40 changes: 20 additions & 20 deletions HPXMLtoOpenStudio/measure.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<schema_version>3.0</schema_version>
<name>hpxm_lto_openstudio</name>
<uid>b1543b30-9465-45ff-ba04-1d1f85e763bc</uid>
<version_id>56a21f99-cfb8-488b-8783-2177a1cdc4e2</version_id>
<version_modified>20220411T223247Z</version_modified>
<version_id>2a19d7d9-f4a4-4b5b-b8db-ba93dcdaa3d3</version_id>
<version_modified>20220415T140250Z</version_modified>
<xml_checksum>D8922A73</xml_checksum>
<class_name>HPXMLtoOpenStudio</class_name>
<display_name>HPXML to OpenStudio Translator</display_name>
Expand Down Expand Up @@ -169,12 +169,6 @@
<usage_type>resource</usage_type>
<checksum>BF53D293</checksum>
</file>
<file>
<filename>test_water_heater.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>B415B698</checksum>
</file>
<file>
<filename>test_lighting.rb</filename>
<filetype>rb</filetype>
Expand Down Expand Up @@ -433,12 +427,6 @@
<usage_type>resource</usage_type>
<checksum>8ABCD77B</checksum>
</file>
<file>
<filename>waterheater.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>9C3C60BB</checksum>
</file>
<file>
<filename>geometry.rb</filename>
<filetype>rb</filetype>
Expand Down Expand Up @@ -510,12 +498,6 @@
<usage_type>resource</usage_type>
<checksum>9EB9D0AE</checksum>
</file>
<file>
<filename>constants.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>BCE31C4F</checksum>
</file>
<file>
<filename>meta_measure.rb</filename>
<filetype>rb</filetype>
Expand All @@ -528,5 +510,23 @@
<usage_type>resource</usage_type>
<checksum>FF182243</checksum>
</file>
<file>
<filename>test_water_heater.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>E955AF3A</checksum>
</file>
<file>
<filename>constants.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>FA749B6E</checksum>
</file>
<file>
<filename>waterheater.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>3B95C662</checksum>
</file>
</files>
</measure>
8 changes: 0 additions & 8 deletions HPXMLtoOpenStudio/resources/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,6 @@ def self.ObjectNameClothesDryerExhaust
return 'clothes dryer exhaust'
end

def self.ObjectNameCombiWaterHeatingEnergy(water_heater_name)
return "#{water_heater_name} dhw energy"
end

def self.ObjectNameCombiSpaceHeatingEnergy(water_heater_name)
return "#{water_heater_name} htg energy"
end

def self.ObjectNameComponentLoadsProgram
return 'component loads program'
end
Expand Down
116 changes: 37 additions & 79 deletions HPXMLtoOpenStudio/resources/waterheater.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,13 @@ def self.apply_heatpump(model, runner, loc_space, loc_schedule, weather, water_h

def self.apply_combi(model, runner, loc_space, loc_schedule, water_heating_system, ec_adj, solar_thermal_system)
solar_fraction = get_water_heater_solar_fraction(water_heating_system, solar_thermal_system)

boiler, boiler_plant_loop = get_combi_boiler_and_plant_loop(model, water_heating_system.related_hvac_idref)
boiler.setName('combi boiler')
boiler.additionalProperties.setFeature('HPXML_ID', water_heating_system.id) # Used by reporting measure
boiler.additionalProperties.setFeature('IsCombiBoiler', true) # Used by reporting measure

obj_name_combi = Constants.ObjectNameWaterHeater
convlim = model.getConvergenceLimits
convlim.setMinimumPlantIterations(3) # add one more minimum plant iteration to achieve better energy balance across plant loops.

if water_heating_system.water_heater_type == HPXML::WaterHeaterTypeCombiStorage
if water_heating_system.standby_loss <= 0
Expand Down Expand Up @@ -188,50 +189,32 @@ def self.apply_combi(model, runner, loc_space, loc_schedule, water_heating_syste
alternate_stp_sch.setValue(alt_temp)
new_heater.setIndirectAlternateSetpointTemperatureSchedule(alternate_stp_sch)

# Create hx setpoint schedule to specify source side temperature
hx_stp_sch = OpenStudio::Model::ScheduleConstant.new(model)
hx_stp_sch.setName("#{obj_name_combi} HX Spt")
# Create setpoint schedule to specify source side temperature
source_stp_sch = OpenStudio::Model::ScheduleConstant.new(model)
source_stp_sch.setName("#{obj_name_combi} Source Spt")
boiler_spt_mngr = model.getSetpointManagerScheduleds.select { |spt_mngr| spt_mngr.setpointNode.get == boiler_plant_loop.loopTemperatureSetpointNode }[0]
boiler_spt = boiler_spt_mngr.to_SetpointManagerScheduled.get.schedule.to_ScheduleConstant.get.value
hx_temp = (UnitConversions.convert(water_heating_system.temperature, 'F', 'C') + deadband(water_heating_system.water_heater_type) / 2.0 + boiler_spt) / 2.0 # tank source side inlet temperature, degree C
hx_stp_sch.setValue(hx_temp)
boiler_heating_spt = boiler_spt_mngr.to_SetpointManagerScheduled.get.schedule.to_ScheduleConstant.get.value
# tank source side inlet temperature, degree C
source_stp_sch.setValue(boiler_heating_spt)
# reset dhw boiler setpoint
boiler_spt_mngr.to_SetpointManagerScheduled.get.setSchedule(source_stp_sch)
boiler_plant_loop.autosizeMaximumLoopFlowRate()

# change loop equipment operation scheme to heating load
scheme_dhw = OpenStudio::Model::PlantEquipmentOperationHeatingLoad.new(model)
scheme_dhw.addEquipment(1000000000, new_heater)
loop.setPrimaryPlantEquipmentOperationScheme(scheme_dhw)

# Create loop for source side
source_loop = create_new_loop(model, 'dhw source loop', hx_temp)
source_loop.autosizeMaximumLoopFlowRate()

# Create heat exchanger
combi_hx = create_new_hx(model, Constants.ObjectNameTankHX)

# Add heat exchanger to the load distribution scheme
# Add dhw boiler to the load distribution scheme
scheme = OpenStudio::Model::PlantEquipmentOperationHeatingLoad.new(model)
scheme.addEquipment(1000000000, combi_hx)
source_loop.setPrimaryPlantEquipmentOperationScheme(scheme)

# Add components to the tank source side plant loop
source_loop.addSupplyBranchForComponent(combi_hx)

new_pump = create_new_pump(model)
new_pump.autosizeRatedFlowRate()
new_pump.addToNode(source_loop.supplyInletNode)

new_source_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, hx_stp_sch)
new_source_manager.addToNode(source_loop.supplyOutletNode)

source_loop.addDemandBranchForComponent(new_heater)

# Add heat exchanger to boiler loop
boiler_plant_loop.addDemandBranchForComponent(combi_hx)
scheme.addEquipment(1000000000, boiler)
boiler_plant_loop.setPrimaryPlantEquipmentOperationScheme(scheme)
boiler_plant_loop.addDemandBranchForComponent(new_heater)
boiler_plant_loop.setPlantLoopVolume(0.001) # Cannot be auto-calculated because of large default tank source side mfr(set to be overwritten by EMS)

loop.addSupplyBranchForComponent(new_heater)

add_ec_adj(model, new_heater, ec_adj, loc_space, water_heating_system, boiler, combi_hx)
add_ec_adj(model, new_heater, ec_adj, loc_space, water_heating_system, boiler)

return loop
end
Expand Down Expand Up @@ -979,16 +962,27 @@ def self.add_hpwh_control_program(model, obj_name_hpwh, amb_temp_sensor, hpwh_bo

def self.get_combi_boiler_and_plant_loop(model, heating_source_id)
# Search for the right boiler OS object
boiler = nil
plant_loop = nil
boiler_hw = nil
plant_loop_hw = nil
model.getBoilerHotWaters.each do |bhw|
sys_id = bhw.additionalProperties.getFeatureAsString('HPXML_ID')
if sys_id.is_initialized && sys_id.get == heating_source_id
boiler = bhw
plant_loop = boiler.plantLoop.get
next unless sys_id.is_initialized && sys_id.get == heating_source_id

plant_loop = bhw.plantLoop.get
plant_loop_hw = plant_loop.clone(model).to_PlantLoop.get

# set pump power for water heating to zero
plant_loop_hw.supplyComponents.each do |comp|
if comp.to_BoilerHotWater.is_initialized
boiler_hw = comp.to_BoilerHotWater.get
end
next unless comp.to_PumpVariableSpeed.is_initialized

pump_hw = comp.to_PumpVariableSpeed.get
pump_hw.setRatedPowerConsumption(0.0)
end
end
return boiler, plant_loop
return boiler_hw, plant_loop_hw
end

def self.get_desuperheatercoil(water_heating_system, model)
Expand Down Expand Up @@ -1231,7 +1225,7 @@ def self.get_default_num_bathrooms(num_beds)
num_baths = num_beds / 2.0 + 0.5
end

def self.add_ec_adj(model, heater, ec_adj, loc_space, water_heating_system, combi_boiler = nil, combi_hx = nil)
def self.add_ec_adj(model, heater, ec_adj, loc_space, water_heating_system, combi_boiler = nil)
adjustment = ec_adj - 1.0

if loc_space.nil? # WH is not in a zone, set the other equipment to be in a random space
Expand All @@ -1256,12 +1250,6 @@ def self.add_ec_adj(model, heater, ec_adj, loc_space, water_heating_system, comb

# Sensors
if [HPXML::WaterHeaterTypeCombiStorage, HPXML::WaterHeaterTypeCombiTankless].include? water_heating_system.water_heater_type
ec_adj_sensor_hx = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Fluid Heat Exchanger Heat Transfer Energy')
ec_adj_sensor_hx.setName("#{combi_hx.name} energy")
ec_adj_sensor_hx.setKeyName(combi_hx.name.to_s)
ec_adj_sensor_boiler_heating = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Boiler Heating Energy')
ec_adj_sensor_boiler_heating.setName("#{combi_boiler.name} heating energy")
ec_adj_sensor_boiler_heating.setKeyName(combi_boiler.name.to_s)
ec_adj_sensor_boiler = OpenStudio::Model::EnergyManagementSystemSensor.new(model, "Boiler #{EPlus.fuel_type(fuel_type)} Rate")
ec_adj_sensor_boiler.setName("#{combi_boiler.name} energy")
ec_adj_sensor_boiler.setKeyName(combi_boiler.name.to_s)
Expand Down Expand Up @@ -1295,15 +1283,9 @@ def self.add_ec_adj(model, heater, ec_adj, loc_space, water_heating_system, comb
ec_adj_program.setName("#{heater.name} EC_adj")
if [HPXML::WaterHeaterTypeCombiStorage, HPXML::WaterHeaterTypeCombiTankless].include? water_heating_system.water_heater_type
ec_adj_program.addLine("Set dhw_e_cons = #{ec_adj_oncyc_sensor.name} + #{ec_adj_offcyc_sensor.name}")
ec_adj_program.addLine('Set htg_e_cons = dhw_e_cons')
ec_adj_program.addLine("If #{ec_adj_sensor_boiler_heating.name} > 0")
ec_adj_program.addLine(" Set dhw_frac = (@Abs #{ec_adj_sensor_hx.name} / #{ec_adj_sensor_boiler_heating.name})")
ec_adj_program.addLine(' Set dhw_frac = (@Min dhw_frac 1)')
ec_adj_program.addLine(" Set dhw_e_cons = dhw_e_cons + dhw_frac * #{ec_adj_sensor_boiler.name}")
ec_adj_program.addLine(" Set htg_e_cons = htg_e_cons + (1.0 - dhw_frac) * #{ec_adj_sensor_boiler.name}")
ec_adj_program.addLine("If #{ec_adj_sensor_boiler.name} > 0")
ec_adj_program.addLine(" Set dhw_e_cons = dhw_e_cons + #{ec_adj_sensor_boiler.name}")
ec_adj_program.addLine('EndIf')
ec_adj_program.addLine('Set boiler_dhw_energy = dhw_e_cons * 3600 * SystemTimeStep')
ec_adj_program.addLine('Set boiler_htg_energy = htg_e_cons * 3600 * SystemTimeStep')
elsif water_heating_system.water_heater_type == HPXML::WaterHeaterTypeHeatPump
ec_adj_program.addLine("Set dhw_e_cons = #{ec_adj_sensor.name} + #{ec_adj_oncyc_sensor.name} + #{ec_adj_offcyc_sensor.name} + #{ec_adj_hp_sensor.name} + #{ec_adj_fan_sensor.name}")
else
Expand All @@ -1327,30 +1309,6 @@ def self.add_ec_adj(model, heater, ec_adj, loc_space, water_heating_system, comb
ec_adj_output_var.setUnits('J')
ec_adj_output_var.additionalProperties.setFeature('FuelType', EPlus.fuel_type(fuel_type)) # Used by reporting measure
ec_adj_output_var.additionalProperties.setFeature('HPXML_ID', water_heating_system.id) # Used by reporting measure

if [HPXML::WaterHeaterTypeCombiStorage, HPXML::WaterHeaterTypeCombiTankless].include? water_heating_system.water_heater_type
# EMS Output Variables for combi dhw energy reporting (before EC_adj is applied)

# DHW energy use:
boiler_dhw_output_var = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, 'boiler_dhw_energy')
boiler_dhw_output_var.setName("#{Constants.ObjectNameCombiWaterHeatingEnergy(heater.name)} outvar")
boiler_dhw_output_var.setTypeOfDataInVariable('Summed')
boiler_dhw_output_var.setUpdateFrequency('SystemTimestep')
boiler_dhw_output_var.setEMSProgramOrSubroutineName(ec_adj_program)
boiler_dhw_output_var.setUnits('J')
boiler_dhw_output_var.additionalProperties.setFeature('FuelType', EPlus.fuel_type(fuel_type)) # Used by reporting measure
boiler_dhw_output_var.additionalProperties.setFeature('HPXML_ID', water_heating_system.id) # Used by reporting measure

# Space heating energy use:
boiler_htg_output_var = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, 'boiler_htg_energy')
boiler_htg_output_var.setName("#{Constants.ObjectNameCombiSpaceHeatingEnergy(heater.name)} outvar")
boiler_htg_output_var.setTypeOfDataInVariable('Summed')
boiler_htg_output_var.setUpdateFrequency('SystemTimestep')
boiler_htg_output_var.setEMSProgramOrSubroutineName(ec_adj_program)
boiler_htg_output_var.setUnits('J')
boiler_htg_output_var.additionalProperties.setFeature('FuelType', EPlus.fuel_type(fuel_type)) # Used by reporting measure
boiler_htg_output_var.additionalProperties.setFeature('HPXML_ID', water_heating_system.related_hvac_system.id) # Used by reporting measure
end
end

def self.get_default_hot_water_temperature(eri_version)
Expand Down
38 changes: 8 additions & 30 deletions HPXMLtoOpenStudio/tests/test_water_heater.rb
Original file line number Diff line number Diff line change
Expand Up @@ -885,25 +885,14 @@ def test_tank_indirect
assert_in_epsilon(t_set, wh.setpointTemperatureSchedule.get.to_ScheduleConstant.get.value, 0.001)
assert_equal(1.0, wh.offCycleLossFractiontoThermalZone)

# Heat exchanger
assert_equal(1, model.getHeatExchangerFluidToFluids.size)
hx = model.getHeatExchangerFluidToFluids[0]
hx_attached_to_boiler = false
hx_attached_to_tank = false
tank_attached_to_boiler = false
model.getPlantLoops.each do |plant_loop|
next if plant_loop.demandComponents.select { |comp| comp == hx }.empty?
next if plant_loop.supplyComponents.select { |comp| comp.name.get.include? 'boiler' }.empty?

hx_attached_to_boiler = true
end
model.getPlantLoops.each do |plant_loop|
next if plant_loop.supplyComponents.select { |comp| comp == hx }.empty?
next if plant_loop.demandComponents.select { |comp| comp == wh }.empty?
next if plant_loop.supplyComponents.select { |comp| comp.name.get.include? 'boiler' }.empty?

hx_attached_to_tank = true
tank_attached_to_boiler = true
end
assert_equal(hx_attached_to_boiler, true)
assert_equal(hx_attached_to_tank, true)
assert_equal(tank_attached_to_boiler, true)
end

def test_tank_combi_tankless
Expand Down Expand Up @@ -933,25 +922,14 @@ def test_tank_combi_tankless
assert_in_epsilon(t_set, wh.setpointTemperatureSchedule.get.to_ScheduleConstant.get.value, 0.001)
assert_equal(1.0, wh.offCycleLossFractiontoThermalZone)

# Heat exchanger
assert_equal(1, model.getHeatExchangerFluidToFluids.size)
hx = model.getHeatExchangerFluidToFluids[0]
hx_attached_to_boiler = false
hx_attached_to_tank = false
tank_attached_to_boiler = false
model.getPlantLoops.each do |plant_loop|
next if plant_loop.demandComponents.select { |comp| comp == hx }.empty?
next if plant_loop.supplyComponents.select { |comp| comp.name.get.include? 'boiler' }.empty?

hx_attached_to_boiler = true
end
model.getPlantLoops.each do |plant_loop|
next if plant_loop.supplyComponents.select { |comp| comp == hx }.empty?
next if plant_loop.demandComponents.select { |comp| comp == wh }.empty?
next if plant_loop.supplyComponents.select { |comp| comp.name.get.include? 'boiler' }.empty?

hx_attached_to_tank = true
tank_attached_to_boiler = true
end
assert_equal(hx_attached_to_boiler, true)
assert_equal(hx_attached_to_tank, true)
assert_equal(tank_attached_to_boiler, true)
end

def test_tank_heat_pump
Expand Down
9 changes: 3 additions & 6 deletions ReportSimulationOutput/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2315,6 +2315,9 @@ def get_object_output_variables_by_key(model, object, class_name)
else
return { [to_ft[fuel], EUT::HeatingHeatPumpBackup] => ["Boiler #{fuel} Energy"] }
end
else
fuel = object.to_BoilerHotWater.get.fuelType
return { [to_ft[fuel], EUT::HotWater] => ["Boiler #{fuel} Energy"] }
end

elsif object.to_CoilCoolingDXSingleSpeed.is_initialized || object.to_CoilCoolingDXMultiSpeed.is_initialized
Expand Down Expand Up @@ -2433,12 +2436,6 @@ def get_object_output_variables_by_key(model, object, class_name)
elsif object.name.to_s.include? Constants.ObjectNameWaterHeaterAdjustment(nil)
fuel = object.additionalProperties.getFeatureAsString('FuelType').get
return { [to_ft[fuel], EUT::HotWater] => [object.name.to_s] }
elsif object.name.to_s.include? Constants.ObjectNameCombiWaterHeatingEnergy(nil)
fuel = object.additionalProperties.getFeatureAsString('FuelType').get
return { [to_ft[fuel], EUT::HotWater] => [object.name.to_s] }
elsif object.name.to_s.include? Constants.ObjectNameCombiSpaceHeatingEnergy(nil)
fuel = object.additionalProperties.getFeatureAsString('FuelType').get
return { [to_ft[fuel], EUT::Heating] => [object.name.to_s] }
else
return { ems: [object.name.to_s] }
end
Expand Down
6 changes: 3 additions & 3 deletions ReportSimulationOutput/measure.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<schema_version>3.0</schema_version>
<name>report_simulation_output</name>
<uid>df9d170c-c21a-4130-866d-0d46b06073fd</uid>
<version_id>45301192-6a9e-49bf-8995-6f5d4e36372a</version_id>
<version_modified>20220408T155840Z</version_modified>
<version_id>9d5b0a6b-ef2b-441b-944f-8f071d46b4ec</version_id>
<version_modified>20220413T231147Z</version_modified>
<xml_checksum>9BF1E6AC</xml_checksum>
<class_name>ReportSimulationOutput</class_name>
<display_name>HPXML Simulation Output Report</display_name>
Expand Down Expand Up @@ -1588,7 +1588,7 @@
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>A52FB9B7</checksum>
<checksum>3316272E</checksum>
</file>
</files>
</measure>
Loading

0 comments on commit 62f3722

Please sign in to comment.