Skip to content

Commit a2c4fb5

Browse files
committed
Code changes from #753, energy impact only.
1 parent f6f88ca commit a2c4fb5

File tree

3 files changed

+58
-35
lines changed

3 files changed

+58
-35
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ __New Features__
88
- Adds an `--ep-input-format` argument to run_simulation.rb to choose epJSON as the EnergyPlus input file format instead of IDF.
99
- Allows `HeatingSeason` & `CoolingSeason` to be specified for defining heating and cooling equipment availability.
1010
- Removes error-check for number of bedrooms based on conditioned floor area, per RESNET guidance.
11+
- Revises shared mechanical ventilation preconditioning control logic to operate less often.
1112

1213
__Bugfixes__
1314
- Improves ground reflectance when there is shading of windows/skylights.

HPXMLtoOpenStudio/measure.xml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
<error>Unable to extract OpenStudio::Measure::OSMeasure object from /mnt/c/git/openstudio-hpxml/HPXMLtoOpenStudio/measure.rb. The script should contain a class that derives from OpenStudio::Measure::OSMeasure and should close with a line stating the class name followed by .new.registerWithApplication.</error>
55
<name>hpxm_lto_openstudio</name>
66
<uid>b1543b30-9465-45ff-ba04-1d1f85e763bc</uid>
7-
<version_id>c929f134-7b14-43a4-a9ee-11bb8d27da1f</version_id>
8-
<version_modified>20210513T171148Z</version_modified>
7+
<version_id>9d668d73-be14-4a65-b206-764f86eca574</version_id>
8+
<version_modified>20210514T182320Z</version_modified>
99
<xml_checksum>D8922A73</xml_checksum>
1010
<class_name>HPXMLtoOpenStudio</class_name>
1111
<display_name>HPXML to OpenStudio Translator</display_name>
@@ -407,12 +407,6 @@
407407
<usage_type>test</usage_type>
408408
<checksum>4C662AE0</checksum>
409409
</file>
410-
<file>
411-
<filename>airflow.rb</filename>
412-
<filetype>rb</filetype>
413-
<usage_type>resource</usage_type>
414-
<checksum>99EB6060</checksum>
415-
</file>
416410
<file>
417411
<filename>geometry.rb</filename>
418412
<filetype>rb</filetype>
@@ -586,5 +580,11 @@
586580
<usage_type>resource</usage_type>
587581
<checksum>4BBE084E</checksum>
588582
</file>
583+
<file>
584+
<filename>airflow.rb</filename>
585+
<filetype>rb</filetype>
586+
<usage_type>resource</usage_type>
587+
<checksum>E5C505B7</checksum>
588+
</file>
589589
</files>
590590
</measure>

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()
@@ -1486,6 +1486,8 @@ def self.calculate_fan_loads(model, infil_program, vent_mech_erv_hrv_tot, hrv_er
14861486
# Calculate mass flow rate based on outdoor air density
14871487
# Address load with flow-weighted combined effectiveness
14881488
infil_program.addLine("Set Fan_MFR = #{q_var} * OASupRho")
1489+
infil_program.addLine('Set ZoneInEnth = OASupInEnth')
1490+
infil_program.addLine('Set ZoneInTemp = OASupInTemp')
14891491
if not vent_mech_erv_hrv_tot.empty?
14901492
# ERV/HRV EMS load model
14911493
# E+ ERV model is using standard density for MFR calculation, caused discrepancy with other system types.
@@ -1502,14 +1504,12 @@ def self.calculate_fan_loads(model, infil_program, vent_mech_erv_hrv_tot, hrv_er
15021504
infil_program.addLine('Set ERVTotalHeatTrans = Fan_MFR * (ERVSupOutEnth - OASupInEnth)')
15031505
infil_program.addLine('Set ERVLatHeatTrans = ERVTotalHeatTrans - ERVSensHeatTrans')
15041506
# ERV/HRV Load calculation
1505-
infil_program.addLine('Set FanTotalToLv = Fan_MFR * (ERVSupOutEnth - ZoneAirEnth)')
1506-
infil_program.addLine('Set FanSensToLv = Fan_MFR * ZoneCp * (ERVSupOutTemp - ZoneTemp)')
1507-
infil_program.addLine('Set FanLatToLv = FanTotalToLv - FanSensToLv')
1508-
else
1509-
infil_program.addLine('Set FanTotalToLv = Fan_MFR * (OASupInEnth - ZoneAirEnth)')
1510-
infil_program.addLine('Set FanSensToLv = Fan_MFR * ZoneCp * (OASupInTemp - ZoneTemp)')
1511-
infil_program.addLine('Set FanLatToLv = FanTotalToLv - FanSensToLv')
1507+
infil_program.addLine('Set ZoneInEnth = ERVSupOutEnth')
1508+
infil_program.addLine('Set ZoneInTemp = ERVSupOutTemp')
15121509
end
1510+
infil_program.addLine('Set FanTotalToLv = Fan_MFR * (ZoneInEnth - ZoneAirEnth)')
1511+
infil_program.addLine('Set FanSensToLv = Fan_MFR * ZoneCp * (ZoneInTemp - ZoneTemp)')
1512+
infil_program.addLine('Set FanLatToLv = FanTotalToLv - FanSensToLv')
15131513

15141514
# Actuator,
15151515
# If preconditioned, handle actuators later in calculate_precond_loads
@@ -1519,11 +1519,23 @@ def self.calculate_fan_loads(model, infil_program, vent_mech_erv_hrv_tot, hrv_er
15191519
end
15201520
end
15211521

1522-
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)
1522+
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)
15231523
# Preconditioning
15241524
# Assume introducing no sensible loads to zone if preconditioned
1525+
if not vent_mech_preheat.empty?
1526+
htg_stp_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Thermostat Heating Setpoint Temperature')
1527+
htg_stp_sensor.setName("#{Constants.ObjectNameAirflow} htg stp s")
1528+
htg_stp_sensor.setKeyName(@living_zone.name.to_s)
1529+
infil_program.addLine("Set HtgStp = #{htg_stp_sensor.name}") # heating thermostat setpoint
1530+
end
1531+
if not vent_mech_precool.empty?
1532+
clg_stp_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Thermostat Cooling Setpoint Temperature')
1533+
clg_stp_sensor.setName("#{Constants.ObjectNameAirflow} clg stp s")
1534+
clg_stp_sensor.setKeyName(@living_zone.name.to_s)
1535+
infil_program.addLine("Set ClgStp = #{clg_stp_sensor.name}") # cooling thermostat setpoint
1536+
end
15251537
vent_mech_preheat.each_with_index do |f_preheat, i|
1526-
infil_program.addLine('If OASupInTemp < ZoneTemp')
1538+
infil_program.addLine("If (OASupInTemp < HtgStp) && (#{clg_ssn_sensor.name} < 1)")
15271539
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)
15281540
hvac_map["#{f_preheat.id}_preheat"] = [htg_energy_actuator.actuatedComponent.get]
15291541
infil_program.addLine(" Set Qpreheat = #{UnitConversions.convert(f_preheat.average_oa_unit_flow_rate, 'cfm', 'm^3/s').round(4)}")
@@ -1534,16 +1546,21 @@ def self.calculate_precond_loads(model, infil_program, vent_mech_preheat, vent_m
15341546
end
15351547
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)
15361548

1537-
infil_program.addLine(" Set PreHeatingEnergy = (-FanSensToLv) * #{f_preheat.preheating_fraction_load_served}")
1538-
infil_program.addLine(" Set #{fan_sens_load_actuator.name} = #{fan_sens_load_actuator.name} + PreHeatingEnergy")
1539-
infil_program.addLine(" Set #{fan_lat_load_actuator.name} = #{fan_lat_load_actuator.name} - FanLatToLv")
1540-
infil_program.addLine(" Set #{htg_energy_actuator.name} = PreHeatingEnergy / #{f_preheat.preheating_efficiency_cop}")
1549+
infil_program.addLine(' If ZoneInTemp < HtgStp')
1550+
infil_program.addLine(' Set FanSensToSpt = Fan_MFR * ZoneCp * (ZoneInTemp - HtgStp)')
1551+
infil_program.addLine(" Set PreHeatingWatt = (-FanSensToSpt) * #{f_preheat.preheating_fraction_load_served}")
1552+
infil_program.addLine(" Set #{fan_sens_load_actuator.name} = #{fan_sens_load_actuator.name} + PreHeatingWatt")
1553+
infil_program.addLine(" Set #{fan_lat_load_actuator.name} = #{fan_lat_load_actuator.name} - FanLatToLv") # Fixme:Does this assumption still apply?
1554+
infil_program.addLine(' Else')
1555+
infil_program.addLine(' Set PreHeatingWatt = 0.0')
1556+
infil_program.addLine(' EndIf')
15411557
infil_program.addLine('Else')
1542-
infil_program.addLine(" Set #{htg_energy_actuator.name} = 0.0")
1558+
infil_program.addLine(' Set PreHeatingWatt = 0.0')
15431559
infil_program.addLine('EndIf')
1560+
infil_program.addLine("Set #{htg_energy_actuator.name} = PreHeatingWatt / #{f_preheat.preheating_efficiency_cop}")
15441561
end
15451562
vent_mech_precool.each_with_index do |f_precool, i|
1546-
infil_program.addLine('If OASupInTemp > ZoneTemp')
1563+
infil_program.addLine("If (OASupInTemp > ClgStp) && (#{clg_ssn_sensor.name} > 0)")
15471564
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)
15481565
hvac_map["#{f_precool.id}_precool"] = [clg_energy_actuator.actuatedComponent.get]
15491566
infil_program.addLine(" Set Qprecool = #{UnitConversions.convert(f_precool.average_oa_unit_flow_rate, 'cfm', 'm^3/s').round(4)}")
@@ -1554,18 +1571,23 @@ def self.calculate_precond_loads(model, infil_program, vent_mech_preheat, vent_m
15541571
end
15551572
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)
15561573

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

15671589
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,
1568-
range_sch_sensors_map, bath_sch_sensors_map, dryer_exhaust_sch_sensors_map, has_flue_chimney, hvac_map)
1590+
range_sch_sensors_map, bath_sch_sensors_map, dryer_exhaust_sch_sensors_map, has_flue_chimney, hvac_map, clg_ssn_sensor)
15691591
# Categorize fans into different types
15701592
vent_mech_preheat = vent_fans_mech.select { |vent_mech| (not vent_mech.preheating_efficiency_cop.nil?) }
15711593
vent_mech_precool = vent_fans_mech.select { |vent_mech| (not vent_mech.precooling_efficiency_cop.nil?) }
@@ -1640,7 +1662,7 @@ def self.apply_infiltration_and_mechanical_ventilation(model, site, vent_fans_me
16401662
calculate_fan_loads(model, infil_program, vent_mech_erv_hrv_tot, hrv_erv_effectiveness_map, fan_sens_load_actuator, fan_lat_load_actuator, 'Qload')
16411663

16421664
# Address preconditioning
1643-
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)
1665+
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)
16441666

16451667
program_calling_manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
16461668
program_calling_manager.setName("#{infil_program.name} calling manager")
@@ -1649,7 +1671,7 @@ def self.apply_infiltration_and_mechanical_ventilation(model, site, vent_fans_me
16491671
end
16501672

16511673
def self.apply_infiltration_and_ventilation_fans(model, weather, site, vent_fans_mech, vent_fans_kitchen, vent_fans_bath, vented_dryers,
1652-
has_flue_chimney, air_infils, vented_attic, vented_crawl, hvac_map)
1674+
has_flue_chimney, air_infils, vented_attic, vented_crawl, hvac_map, clg_ssn_sensor)
16531675
# Get living space infiltration
16541676
living_ach50 = nil
16551677
living_const_ach = nil
@@ -1687,7 +1709,7 @@ def self.apply_infiltration_and_ventilation_fans(model, weather, site, vent_fans
16871709

16881710
# Get mechanical ventilation
16891711
apply_infiltration_and_mechanical_ventilation(model, site, vent_fans_mech, living_ach50, living_const_ach, weather, vent_fans_kitchen, vent_fans_bath, vented_dryers,
1690-
range_sch_sensors_map, bath_sch_sensors_map, dryer_exhaust_sch_sensors_map, has_flue_chimney, hvac_map)
1712+
range_sch_sensors_map, bath_sch_sensors_map, dryer_exhaust_sch_sensors_map, has_flue_chimney, hvac_map, clg_ssn_sensor)
16911713
end
16921714

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

0 commit comments

Comments
 (0)