Skip to content

Commit

Permalink
Merge pull request #1849 from NREL/stratified_tank_bugfix
Browse files Browse the repository at this point in the history
Stratified tank bugfix
  • Loading branch information
shorowit authored Oct 4, 2024
2 parents e770f42 + 5dc674f commit 745026f
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 91 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ __Bugfixes__
- Fixes utility bill calculations if there is battery storage or a generator.
- BuildResidentialScheduleFile measure: Fixes possible divide by zero error during generation of stochastic clothes washer and dishwasher schedules.
- Allows negative values for `Building/Site/Elevation`.
- Fixes lower element height for a water heater using the advanced `WaterHeatingSystem/extension/TankModelType=stratified`.

## OpenStudio-HPXML v1.8.1

Expand Down
6 changes: 3 additions & 3 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>56ae4bc1-86cd-4cad-aeb2-5b3670066114</version_id>
<version_modified>2024-10-01T18:47:17Z</version_modified>
<version_id>2ecbdcc0-d0e3-4c8f-b8f8-a839e9bdbee1</version_id>
<version_modified>2024-10-04T17:02:56Z</version_modified>
<xml_checksum>D8922A73</xml_checksum>
<class_name>HPXMLtoOpenStudio</class_name>
<display_name>HPXML to OpenStudio Translator</display_name>
Expand Down Expand Up @@ -627,7 +627,7 @@
<filename>waterheater.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>7E9EBE10</checksum>
<checksum>1E7D40B1</checksum>
</file>
<file>
<filename>weather.rb</filename>
Expand Down
46 changes: 18 additions & 28 deletions HPXMLtoOpenStudio/resources/waterheater.rb
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,6 @@ def self.apply_heatpump(model, runner, spaces, hpxml_bldg, hpxml_header, water_h
t_set_c = get_t_set_c(water_heating_system.temperature, water_heating_system.water_heater_type)
loop = create_new_loop(model, t_set_c, hpxml_header.eri_calculation_version, unit_multiplier)

h_tank = 0.0188 * water_heating_system.tank_volume + 0.0935 # Linear relationship that gets GE height at 50 gal and AO Smith height at 80 gal

# Add in schedules for Tamb, RHamb, and the compressor
hpwh_tamb = Model.add_schedule_constant(
model,
Expand Down Expand Up @@ -203,7 +201,7 @@ def self.apply_heatpump(model, runner, spaces, hpxml_bldg, hpxml_header, water_h
coil = setup_hpwh_dxcoil(model, runner, water_heating_system, hpxml_bldg.elevation, obj_name, airflow_rate, unit_multiplier)

# WaterHeater:Stratified
tank = setup_hpwh_stratified_tank(model, water_heating_system, obj_name, h_tank, solar_fraction, hpwh_tamb, bottom_element_sp, top_element_sp, unit_multiplier, hpxml_bldg.building_construction.number_of_bedrooms)
tank = setup_hpwh_stratified_tank(model, water_heating_system, obj_name, solar_fraction, hpwh_tamb, bottom_element_sp, top_element_sp, unit_multiplier, hpxml_bldg.building_construction.number_of_bedrooms)
loop.addSupplyBranchForComponent(tank)

add_desuperheater(model, runner, water_heating_system, tank, loc_space, loc_schedule, loop, unit_multiplier)
Expand All @@ -221,7 +219,7 @@ def self.apply_heatpump(model, runner, spaces, hpxml_bldg, hpxml_header, water_h
fan.additionalProperties.setFeature('ObjectType', Constants::ObjectTypeWaterHeater) # Used by reporting measure

# WaterHeater:HeatPump:WrappedCondenser
hpwh = setup_hpwh_wrapped_condenser(model, obj_name, coil, tank, fan, h_tank, airflow_rate, hpwh_tamb, hpwh_rhamb, min_temp, max_temp, control_setpoint_schedule, unit_multiplier)
hpwh = setup_hpwh_wrapped_condenser(model, obj_name, coil, tank, fan, airflow_rate, hpwh_tamb, hpwh_rhamb, min_temp, max_temp, control_setpoint_schedule, unit_multiplier)

# Amb temp & RH sensors, temp sensor shared across programs
amb_temp_sensor, amb_rh_sensors = get_loc_temp_rh_sensors(model, obj_name, loc_space, loc_schedule, conditioned_zone)
Expand Down Expand Up @@ -901,7 +899,6 @@ def self.apply_solar_thermal(model, spaces, hpxml_bldg, plantloop_map)
# @param coil [TODO] TODO
# @param tank [TODO] TODO
# @param fan [TODO] TODO
# @param h_tank [TODO] TODO
# @param airflow_rate [TODO] TODO
# @param hpwh_tamb [TODO] TODO
# @param hpwh_rhamb [TODO] TODO
Expand All @@ -910,17 +907,12 @@ def self.apply_solar_thermal(model, spaces, hpxml_bldg, plantloop_map)
# @param setpoint_schedule [TODO] TODO
# @param unit_multiplier [Integer] Number of similar dwelling units
# @return [TODO] TODO
def self.setup_hpwh_wrapped_condenser(model, obj_name, coil, tank, fan, h_tank, airflow_rate, hpwh_tamb, hpwh_rhamb, min_temp, max_temp, setpoint_schedule, unit_multiplier)
h_condtop = (1.0 - (5.5 / 12.0)) * h_tank # in the 6th node of the tank (counting from top)
h_condbot = 0.01 * unit_multiplier # bottom node
h_hpctrl_up = (1.0 - (2.5 / 12.0)) * h_tank # in the 3rd node of the tank
h_hpctrl_low = (1.0 - (8.5 / 12.0)) * h_tank # in the 9th node of the tank

def self.setup_hpwh_wrapped_condenser(model, obj_name, coil, tank, fan, airflow_rate, hpwh_tamb, hpwh_rhamb, min_temp, max_temp, setpoint_schedule, unit_multiplier)
hpwh = OpenStudio::Model::WaterHeaterHeatPumpWrappedCondenser.new(model, coil, tank, fan, setpoint_schedule, model.alwaysOnDiscreteSchedule)
hpwh.setName("#{obj_name} hpwh")
hpwh.setDeadBandTemperatureDifference(3.89)
hpwh.setCondenserBottomLocation(h_condbot)
hpwh.setCondenserTopLocation(h_condtop)
hpwh.setCondenserBottomLocation((1.0 - (12 - 0.5) / 12.0) * tank.tankHeight.get) # in the 12th node of a 12-node tank (counting from top)
hpwh.setCondenserTopLocation((1.0 - (6 - 0.5) / 12.0) * tank.tankHeight.get) # in the 6th node of a 12-node tank (counting from top)
hpwh.setEvaporatorAirFlowRate(UnitConversions.convert(airflow_rate * unit_multiplier, 'ft^3/min', 'm^3/s'))
hpwh.setInletAirConfiguration('Schedule')
hpwh.setInletAirTemperatureSchedule(hpwh_tamb)
Expand All @@ -934,9 +926,9 @@ def self.setup_hpwh_wrapped_condenser(model, obj_name, coil, tank, fan, h_tank,
hpwh.setOffCycleParasiticElectricLoad(0)
hpwh.setParasiticHeatRejectionLocation('Outdoors')
hpwh.setTankElementControlLogic('MutuallyExclusive')
hpwh.setControlSensor1HeightInStratifiedTank(h_hpctrl_up)
hpwh.setControlSensor1HeightInStratifiedTank((1.0 - (3 - 0.5) / 12.0) * tank.tankHeight.get) # in the 3rd node of a 12-node tank (counting from top)
hpwh.setControlSensor1Weight(0.75)
hpwh.setControlSensor2HeightInStratifiedTank(h_hpctrl_low)
hpwh.setControlSensor2HeightInStratifiedTank((1.0 - (9 - 0.5) / 12.0) * tank.tankHeight.get) # in the 9th node of a 12-node tank (counting from top)

return hpwh
end
Expand Down Expand Up @@ -1023,15 +1015,16 @@ def self.setup_hpwh_dxcoil(model, runner, water_heating_system, elevation, obj_n
# @param model [OpenStudio::Model::Model] OpenStudio Model object
# @param water_heating_system [HPXML::WaterHeatingSystem] The HPXML water heating system of interest
# @param obj_name [String] Name for the OpenStudio object
# @param h_tank [TODO] TODO
# @param solar_fraction [TODO] TODO
# @param hpwh_tamb [TODO] TODO
# @param hpwh_bottom_element_sp [TODO] TODO
# @param hpwh_top_element_sp [TODO] TODO
# @param unit_multiplier [Integer] Number of similar dwelling units
# @param nbeds [Integer] Number of bedrooms in the dwelling unit
# @return [TODO] TODO
def self.setup_hpwh_stratified_tank(model, water_heating_system, obj_name, h_tank, solar_fraction, hpwh_tamb, hpwh_bottom_element_sp, hpwh_top_element_sp, unit_multiplier, nbeds)
def self.setup_hpwh_stratified_tank(model, water_heating_system, obj_name, solar_fraction, hpwh_tamb, hpwh_bottom_element_sp, hpwh_top_element_sp, unit_multiplier, nbeds)
h_tank = 0.0188 * water_heating_system.tank_volume + 0.0935 # m; Linear relationship that gets GE height at 50 gal and AO Smith height at 80 gal

# Calculate some geometry parameters for UA, the location of sensors and heat sources in the tank
v_actual = calc_storage_tank_actual_vol(water_heating_system.tank_volume, water_heating_system.fuel_type) # gal
a_tank, a_side = calc_tank_areas(v_actual, UnitConversions.convert(h_tank, 'm', 'ft')) # sqft
Expand All @@ -1054,9 +1047,6 @@ def self.setup_hpwh_stratified_tank(model, water_heating_system, obj_name, h_tan
e_cap *= unit_multiplier
parasitics *= unit_multiplier

h_UE = (1.0 - (3.5 / 12.0)) * h_tank # in the 3rd node of the tank (counting from top)
h_LE = (1.0 - (9.5 / 12.0)) * h_tank # in the 10th node of the tank (counting from top)

tank = OpenStudio::Model::WaterHeaterStratified.new(model)
tank.setName("#{obj_name} tank")
tank.setEndUseSubcategory('Domestic Hot Water')
Expand All @@ -1067,12 +1057,12 @@ def self.setup_hpwh_stratified_tank(model, water_heating_system, obj_name, h_tan
tank.heater1SetpointTemperatureSchedule.remove
tank.setHeater1SetpointTemperatureSchedule(hpwh_top_element_sp)
tank.setHeater1Capacity(UnitConversions.convert(e_cap, 'kW', 'W'))
tank.setHeater1Height(h_UE)
tank.setHeater1Height((1.0 - (3 - 0.5) / 12.0) * h_tank) # in the 3rd node of a 12-node tank (counting from top)
tank.setHeater1DeadbandTemperatureDifference(18.5)
tank.heater2SetpointTemperatureSchedule.remove
tank.setHeater2SetpointTemperatureSchedule(hpwh_bottom_element_sp)
tank.setHeater2Capacity(UnitConversions.convert(e_cap, 'kW', 'W'))
tank.setHeater2Height(h_LE)
tank.setHeater2Height((1.0 - (10 - 0.5) / 12.0) * h_tank) # in the 10th node of a 12-node tank (counting from top)
tank.setHeater2DeadbandTemperatureDifference(3.89)
tank.setHeaterFuelType(EPlus::FuelTypeElectricity)
tank.setHeaterThermalEfficiency(1.0)
Expand Down Expand Up @@ -1988,30 +1978,30 @@ def self.create_new_heater(name:, water_heating_system: nil, act_vol:, t_set_c:
act_vol *= unit_multiplier

if tank_model_type == HPXML::WaterHeaterTankModelTypeStratified
h_tank = get_tank_height() # ft
h_tank = UnitConversions.convert(get_tank_height(), 'ft', 'm')

# Add a WaterHeater:Stratified to the model
new_heater = OpenStudio::Model::WaterHeaterStratified.new(model)
new_heater.setEndUseSubcategory('Domestic Hot Water')
new_heater.setTankVolume(UnitConversions.convert(act_vol, 'gal', 'm^3'))
new_heater.setTankHeight(UnitConversions.convert(h_tank, 'ft', 'm'))
new_heater.setTankHeight(h_tank)
new_heater.setMaximumTemperatureLimit(90)
new_heater.setHeaterPriorityControl('MasterSlave')
configure_stratified_tank_setpoint_schedules(new_heater, schedules_file, t_set_c, model, runner, unavailable_periods)
new_heater.setHeater1Capacity(UnitConversions.convert(cap, 'kBtu/hr', 'W'))
new_heater.setHeater1Height(UnitConversions.convert(h_tank * 0.733333333, 'ft', 'm')) # node 4; height of upper element based on TRNSYS assumptions for an ERWH
new_heater.setHeater1Height((1.0 - (4 - 0.5) / 15) * h_tank) # in the 4th node of a 15-node tank (counting from top); height of upper element based on TRNSYS assumptions for an ERWH
new_heater.setHeater1DeadbandTemperatureDifference(5.556)
new_heater.setHeater2Capacity(UnitConversions.convert(cap, 'kBtu/hr', 'W'))
new_heater.setHeater2Height(UnitConversions.convert(h_tank * 0.733333333, 'ft', 'm')) # node 13; height of upper element based on TRNSYS assumptions for an ERWH
new_heater.setHeater2Height((1.0 - (13 - 0.5) / 15) * h_tank) # in the 13th node of a 15-node tank (counting from top); height of upper element based on TRNSYS assumptions for an ERWH
new_heater.setHeater2DeadbandTemperatureDifference(5.556)
new_heater.setHeaterThermalEfficiency(1.0)
new_heater.setNumberofNodes(12)
new_heater.setAdditionalDestratificationConductivity(0)
new_heater.setUseSideDesignFlowRate(UnitConversions.convert(act_vol, 'gal', 'm^3') / 60.1)
new_heater.setSourceSideDesignFlowRate(0)
new_heater.setSourceSideFlowControlMode('')
new_heater.setSourceSideInletHeight(0)
new_heater.setSourceSideOutletHeight(0)
new_heater.setSourceSideInletHeight((1.0 - (1 - 0.5) / 15) * h_tank) # in the 1st node of a 15-node tank (counting from top)
new_heater.setSourceSideOutletHeight((1.0 - (15 - 0.5) / 15) * h_tank) # in the 15th node of a 15-node tank (counting from top)
new_heater.setSkinLossFractiontoZone(1.0 / unit_multiplier) # Tank losses are multiplied by E+ zone multiplier, so need to compensate here
new_heater.setOffCycleFlueLossFractiontoZone(1.0 / unit_multiplier)
set_stratified_tank_ua(new_heater, u, unit_multiplier)
Expand Down
Loading

0 comments on commit 745026f

Please sign in to comment.