Skip to content

Commit 28756d2

Browse files
committed
Revises preconditioning algorithm based on NREL/OpenStudio-HPXML#753
1 parent 7456da6 commit 28756d2

File tree

1 file changed

+49
-27
lines changed
  • hpxml-measures/HPXMLtoOpenStudio/resources

1 file changed

+49
-27
lines changed

hpxml-measures/HPXMLtoOpenStudio/resources/airflow.rb

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
class Airflow
44
def self.apply(model, runner, weather, spaces, hpxml, cfa, nbeds,
5-
ncfl_ag, duct_systems, nv_clg_ssn_sensor, hvac_map, eri_version,
5+
ncfl_ag, duct_systems, clg_ssn_sensor, hvac_map, eri_version,
66
frac_windows_operable, apply_ashrae140_assumptions)
77

88
# Global variables
@@ -106,10 +106,10 @@ def self.apply(model, runner, weather, spaces, hpxml, cfa, nbeds,
106106
vented_crawl = foundation
107107
end
108108

109-
apply_natural_ventilation_and_whole_house_fan(model, weather, hpxml.site, vent_fans_whf, open_window_area, nv_clg_ssn_sensor)
109+
apply_natural_ventilation_and_whole_house_fan(model, weather, hpxml.site, vent_fans_whf, open_window_area, clg_ssn_sensor)
110110
apply_infiltration_and_ventilation_fans(model, weather, hpxml.site, vent_fans_mech, vent_fans_kitchen, vent_fans_bath, vented_dryers,
111111
hpxml.building_construction.has_flue_or_chimney, hpxml.air_infiltration_measurements,
112-
vented_attic, vented_crawl, hvac_map)
112+
vented_attic, vented_crawl, hvac_map, clg_ssn_sensor)
113113
end
114114

115115
def self.get_default_fraction_of_windows_operable()
@@ -222,7 +222,7 @@ def self.apply_infiltration_to_unconditioned_space(model, space, ach = nil, ela
222222
end
223223
end
224224

225-
def self.apply_natural_ventilation_and_whole_house_fan(model, weather, site, vent_fans_whf, open_window_area, nv_clg_ssn_sensor)
225+
def self.apply_natural_ventilation_and_whole_house_fan(model, weather, site, vent_fans_whf, open_window_area, clg_ssn_sensor)
226226
if @living_zone.thermostatSetpointDualSetpoint.is_initialized
227227
thermostat = @living_zone.thermostatSetpointDualSetpoint.get
228228
htg_sch = thermostat.heatingSetpointTemperatureSchedule.get
@@ -334,7 +334,7 @@ def self.apply_natural_ventilation_and_whole_house_fan(model, weather, site, ven
334334
vent_program.addLine("Set Tnvsp = #{UnitConversions.convert(73.0, 'F', 'C')}") # Assumption when no HVAC system
335335
end
336336
vent_program.addLine("Set NVavail = #{nv_avail_sensor.name}")
337-
vent_program.addLine("Set ClgSsnAvail = #{nv_clg_ssn_sensor.name}")
337+
vent_program.addLine("Set ClgSsnAvail = #{clg_ssn_sensor.name}")
338338
vent_program.addLine('If (Wout < MaxHR) && (Phiout < MaxRH) && (Tin > Tout) && (Tin > Tnvsp) && (ClgSsnAvail > 0)')
339339
vent_program.addLine(' Set WHF_Flow = 0')
340340
vent_fans_whf.each do |vent_whf|
@@ -1503,15 +1503,15 @@ def self.calculate_fan_loads(model, infil_program, vent_mech_erv_hrv_tot, hrv_er
15031503
infil_program.addLine('Set ERVSensHeatTrans = Fan_MFR * OASupCp * (ERVSupOutTemp - OASupInTemp)')
15041504
infil_program.addLine('Set ERVTotalHeatTrans = Fan_MFR * (ERVSupOutEnth - OASupInEnth)')
15051505
infil_program.addLine('Set ERVLatHeatTrans = ERVTotalHeatTrans - ERVSensHeatTrans')
1506-
# ERV/HRV Load calculation
1507-
infil_program.addLine('Set FanTotalToLv = Fan_MFR * (ERVSupOutEnth - ZoneAirEnth)')
1508-
infil_program.addLine('Set FanSensToLv = Fan_MFR * ZoneCp * (ERVSupOutTemp - ZoneTemp)')
1509-
infil_program.addLine('Set FanLatToLv = FanTotalToLv - FanSensToLv')
1506+
infil_program.addLine('Set ZoneInEnth = ERVSupOutEnth')
1507+
infil_program.addLine('Set ZoneInTemp = ERVSupOutTemp')
15101508
else
1511-
infil_program.addLine('Set FanTotalToLv = Fan_MFR * (OASupInEnth - ZoneAirEnth)')
1512-
infil_program.addLine('Set FanSensToLv = Fan_MFR * ZoneCp * (OASupInTemp - ZoneTemp)')
1513-
infil_program.addLine('Set FanLatToLv = FanTotalToLv - FanSensToLv')
1509+
infil_program.addLine('Set ZoneInEnth = OASupInEnth')
1510+
infil_program.addLine('Set ZoneInTemp = OASupInTemp')
15141511
end
1512+
infil_program.addLine('Set FanTotalToLv = Fan_MFR * (ZoneInEnth - ZoneAirEnth)')
1513+
infil_program.addLine('Set FanSensToLv = Fan_MFR * ZoneCp * (ZoneInTemp - ZoneTemp)')
1514+
infil_program.addLine('Set FanLatToLv = FanTotalToLv - FanSensToLv')
15151515

15161516
# Actuator,
15171517
# If preconditioned, handle actuators later in calculate_precond_loads
@@ -1521,11 +1521,23 @@ def self.calculate_fan_loads(model, infil_program, vent_mech_erv_hrv_tot, hrv_er
15211521
end
15221522
end
15231523

1524-
def self.calculate_precond_loads(model, infil_program, vent_mech_preheat, vent_mech_precool, hrv_erv_effectiveness_map, fan_sens_load_actuator, fan_lat_load_actuator, hvac_map)
1524+
def self.calculate_precond_loads(model, infil_program, vent_mech_preheat, vent_mech_precool, hrv_erv_effectiveness_map, fan_sens_load_actuator, fan_lat_load_actuator, hvac_map, clg_ssn_sensor)
15251525
# Preconditioning
15261526
# Assume introducing no sensible loads to zone if preconditioned
1527+
if not vent_mech_preheat.empty?
1528+
htg_stp_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Thermostat Heating Setpoint Temperature')
1529+
htg_stp_sensor.setName("#{Constants.ObjectNameAirflow} htg stp s")
1530+
htg_stp_sensor.setKeyName(@living_zone.name.to_s)
1531+
infil_program.addLine("Set HtgStp = #{htg_stp_sensor.name}") # heating thermostat setpoint
1532+
end
1533+
if not vent_mech_precool.empty?
1534+
clg_stp_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Thermostat Cooling Setpoint Temperature')
1535+
clg_stp_sensor.setName("#{Constants.ObjectNameAirflow} clg stp s")
1536+
clg_stp_sensor.setKeyName(@living_zone.name.to_s)
1537+
infil_program.addLine("Set ClgStp = #{clg_stp_sensor.name}") # cooling thermostat setpoint
1538+
end
15271539
vent_mech_preheat.each_with_index do |f_preheat, i|
1528-
infil_program.addLine('If OASupInTemp < ZoneTemp')
1540+
infil_program.addLine("If (OASupInTemp < HtgStp) && (#{clg_ssn_sensor.name} < 1)")
15291541
htg_energy_actuator = create_other_equipment_object_and_actuator(model: model, name: "shared mech vent preheating energy #{i}", space: @living_space, frac_lat: 0.0, frac_lost: 1.0, hpxml_fuel_type: f_preheat.preheating_fuel, end_use: Constants.ObjectNameMechanicalVentilationPreconditioning)
15301542
hvac_map["#{f_preheat.id}_preheat"] = [htg_energy_actuator.actuatedComponent.get]
15311543
infil_program.addLine(" Set Qpreheat = #{UnitConversions.convert(f_preheat.average_oa_unit_flow_rate, 'cfm', 'm^3/s').round(4)}")
@@ -1536,16 +1548,21 @@ def self.calculate_precond_loads(model, infil_program, vent_mech_preheat, vent_m
15361548
end
15371549
calculate_fan_loads(model, infil_program, vent_mech_erv_hrv_tot, hrv_erv_effectiveness_map, fan_sens_load_actuator, fan_lat_load_actuator, 'Qpreheat', true)
15381550

1539-
infil_program.addLine(" Set PreHeatingEnergy = (-FanSensToLv) * #{f_preheat.preheating_fraction_load_served}")
1540-
infil_program.addLine(" Set #{fan_sens_load_actuator.name} = #{fan_sens_load_actuator.name} + PreHeatingEnergy")
1541-
infil_program.addLine(" Set #{fan_lat_load_actuator.name} = #{fan_lat_load_actuator.name} - FanLatToLv")
1542-
infil_program.addLine(" Set #{htg_energy_actuator.name} = PreHeatingEnergy / #{f_preheat.preheating_efficiency_cop}")
1551+
infil_program.addLine(' If ZoneInTemp < HtgStp')
1552+
infil_program.addLine(' Set FanSensToSpt = Fan_MFR * ZoneCp * (ZoneInTemp - HtgStp)')
1553+
infil_program.addLine(" Set PreHeatingEnergy = (-FanSensToSpt) * #{f_preheat.preheating_fraction_load_served}")
1554+
infil_program.addLine(" Set #{fan_sens_load_actuator.name} = #{fan_sens_load_actuator.name} + PreHeatingEnergy")
1555+
infil_program.addLine(" Set #{fan_lat_load_actuator.name} = #{fan_lat_load_actuator.name} - FanLatToLv") # Fixme:Does this assumption still apply?
1556+
infil_program.addLine(" Set #{htg_energy_actuator.name} = PreHeatingEnergy / #{f_preheat.preheating_efficiency_cop}")
1557+
infil_program.addLine(' Else')
1558+
infil_program.addLine(" Set #{htg_energy_actuator.name} = 0.0")
1559+
infil_program.addLine(' EndIf')
15431560
infil_program.addLine('Else')
15441561
infil_program.addLine(" Set #{htg_energy_actuator.name} = 0.0")
15451562
infil_program.addLine('EndIf')
15461563
end
15471564
vent_mech_precool.each_with_index do |f_precool, i|
1548-
infil_program.addLine('If OASupInTemp > ZoneTemp')
1565+
infil_program.addLine("If (OASupInTemp > ClgStp) && (#{clg_ssn_sensor.name} > 0)")
15491566
clg_energy_actuator = create_other_equipment_object_and_actuator(model: model, name: "shared mech vent precooling energy #{i}", space: @living_space, frac_lat: 0.0, frac_lost: 1.0, hpxml_fuel_type: f_precool.precooling_fuel, end_use: Constants.ObjectNameMechanicalVentilationPreconditioning)
15501567
hvac_map["#{f_precool.id}_precool"] = [clg_energy_actuator.actuatedComponent.get]
15511568
infil_program.addLine(" Set Qprecool = #{UnitConversions.convert(f_precool.average_oa_unit_flow_rate, 'cfm', 'm^3/s').round(4)}")
@@ -1556,18 +1573,23 @@ def self.calculate_precond_loads(model, infil_program, vent_mech_preheat, vent_m
15561573
end
15571574
calculate_fan_loads(model, infil_program, vent_mech_erv_hrv_tot, hrv_erv_effectiveness_map, fan_sens_load_actuator, fan_lat_load_actuator, 'Qprecool', true)
15581575

1559-
infil_program.addLine(" Set PreCoolingEnergy = FanSensToLv * #{f_precool.precooling_fraction_load_served}")
1560-
infil_program.addLine(" Set #{fan_sens_load_actuator.name} = #{fan_sens_load_actuator.name} - PreCoolingEnergy")
1561-
infil_program.addLine(" Set #{fan_lat_load_actuator.name} = #{fan_lat_load_actuator.name} - FanLatToLv")
1562-
infil_program.addLine(" Set #{clg_energy_actuator.name} = PreCoolingEnergy / #{f_precool.precooling_efficiency_cop}")
1576+
infil_program.addLine(' If ZoneInTemp > ClgStp')
1577+
infil_program.addLine(' Set FanSensToSpt = Fan_MFR * ZoneCp * (ZoneInTemp - ClgStp)')
1578+
infil_program.addLine(" Set PreCoolingEnergy = FanSensToSpt * #{f_precool.precooling_fraction_load_served}")
1579+
infil_program.addLine(" Set #{fan_sens_load_actuator.name} = #{fan_sens_load_actuator.name} - PreCoolingEnergy")
1580+
infil_program.addLine(" Set #{fan_lat_load_actuator.name} = #{fan_lat_load_actuator.name} - FanLatToLv") # Fixme:Does this assumption still apply?
1581+
infil_program.addLine(" Set #{clg_energy_actuator.name} = PreCoolingEnergy / #{f_precool.precooling_efficiency_cop}")
1582+
infil_program.addLine(' Else')
1583+
infil_program.addLine(" Set #{clg_energy_actuator.name} = 0.0")
1584+
infil_program.addLine(' EndIf')
15631585
infil_program.addLine('Else')
15641586
infil_program.addLine(" Set #{clg_energy_actuator.name} = 0.0")
15651587
infil_program.addLine('EndIf')
15661588
end
15671589
end
15681590

15691591
def self.apply_infiltration_and_mechanical_ventilation(model, site, vent_fans_mech, living_ach50, living_const_ach, weather, vent_fans_kitchen, vent_fans_bath, vented_dryers,
1570-
range_sch_sensors_map, bath_sch_sensors_map, dryer_exhaust_sch_sensors_map, has_flue_chimney, hvac_map)
1592+
range_sch_sensors_map, bath_sch_sensors_map, dryer_exhaust_sch_sensors_map, has_flue_chimney, hvac_map, clg_ssn_sensor)
15711593
# Categorize fans into different types
15721594
vent_mech_preheat = vent_fans_mech.select { |vent_mech| (not vent_mech.preheating_efficiency_cop.nil?) }
15731595
vent_mech_precool = vent_fans_mech.select { |vent_mech| (not vent_mech.precooling_efficiency_cop.nil?) }
@@ -1642,7 +1664,7 @@ def self.apply_infiltration_and_mechanical_ventilation(model, site, vent_fans_me
16421664
calculate_fan_loads(model, infil_program, vent_mech_erv_hrv_tot, hrv_erv_effectiveness_map, fan_sens_load_actuator, fan_lat_load_actuator, 'Qload')
16431665

16441666
# Address preconditioning
1645-
calculate_precond_loads(model, infil_program, vent_mech_preheat, vent_mech_precool, hrv_erv_effectiveness_map, fan_sens_load_actuator, fan_lat_load_actuator, hvac_map)
1667+
calculate_precond_loads(model, infil_program, vent_mech_preheat, vent_mech_precool, hrv_erv_effectiveness_map, fan_sens_load_actuator, fan_lat_load_actuator, hvac_map, clg_ssn_sensor)
16461668

16471669
program_calling_manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
16481670
program_calling_manager.setName("#{infil_program.name} calling manager")
@@ -1651,7 +1673,7 @@ def self.apply_infiltration_and_mechanical_ventilation(model, site, vent_fans_me
16511673
end
16521674

16531675
def self.apply_infiltration_and_ventilation_fans(model, weather, site, vent_fans_mech, vent_fans_kitchen, vent_fans_bath, vented_dryers,
1654-
has_flue_chimney, air_infils, vented_attic, vented_crawl, hvac_map)
1676+
has_flue_chimney, air_infils, vented_attic, vented_crawl, hvac_map, clg_ssn_sensor)
16551677
# Get living space infiltration
16561678
living_ach50 = nil
16571679
living_const_ach = nil
@@ -1689,7 +1711,7 @@ def self.apply_infiltration_and_ventilation_fans(model, weather, site, vent_fans
16891711

16901712
# Get mechanical ventilation
16911713
apply_infiltration_and_mechanical_ventilation(model, site, vent_fans_mech, living_ach50, living_const_ach, weather, vent_fans_kitchen, vent_fans_bath, vented_dryers,
1692-
range_sch_sensors_map, bath_sch_sensors_map, dryer_exhaust_sch_sensors_map, has_flue_chimney, hvac_map)
1714+
range_sch_sensors_map, bath_sch_sensors_map, dryer_exhaust_sch_sensors_map, has_flue_chimney, hvac_map, clg_ssn_sensor)
16931715
end
16941716

16951717
def self.apply_infiltration_to_living(site, living_ach50, living_const_ach, infil_program, weather, has_flue_chimney)

0 commit comments

Comments
 (0)