openstudio-standards 0.2.15 → 0.2.16.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/data/geometry/ASHRAEHighriseApartment.osm +0 -27
- data/data/standards/OpenStudio_Standards-ashrae_90_1.xlsx +0 -0
- data/data/standards/OpenStudio_Standards-ashrae_90_1_28Jan2022.xlsx +0 -0
- data/data/standards/test_performance_expected_dd_results.csv +710 -710
- data/lib/openstudio-standards/btap/btap_result.rb +2 -2
- data/lib/openstudio-standards/btap/reporting.rb +2 -2
- data/lib/openstudio-standards/btap/simmanager.rb +2 -2
- data/lib/openstudio-standards/hvac_sizing/Siz.ControllerOutdoorAir.rb +0 -54
- data/lib/openstudio-standards/hvac_sizing/Siz.HeatingCoolingFuels.rb +11 -1
- data/lib/openstudio-standards/hvac_sizing/Siz.Model.rb +1 -1
- data/lib/openstudio-standards/prototypes/common/buildings/Prototype.College.rb +26 -5
- data/lib/openstudio-standards/prototypes/common/objects/Prototype.CoilCoolingWaterToAirHeatPumpEquationFit.rb +35 -16
- data/lib/openstudio-standards/prototypes/common/objects/Prototype.CoilHeatingWaterToAirHeatPumpEquationFit.rb +23 -10
- data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.rb +36 -0
- data/lib/openstudio-standards/prototypes/common/objects/Prototype.ServiceWaterHeating.rb +6 -6
- data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +0 -3
- data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +2 -2
- data/lib/openstudio-standards/standards/Standards.CoilCoolingWaterToAirHeatPumpEquationFit.rb +9 -3
- data/lib/openstudio-standards/standards/Standards.CoilHeatingGas.rb +2 -0
- data/lib/openstudio-standards/standards/Standards.Construction.rb +12 -6
- data/lib/openstudio-standards/standards/Standards.Model.rb +38 -7
- data/lib/openstudio-standards/standards/Standards.Space.rb +1 -1
- data/lib/openstudio-standards/standards/Standards.SpaceType.rb +7 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/ashrae_90_1_2004.Model.rb +32 -11
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.construction_properties.json +22 -742
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.construction_sets.json +2 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.prototype_inputs.json +3 -3
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.spc_typ.json +6 -6
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.construction_properties.json +19 -559
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.construction_sets.json +2 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.prototype_inputs.json +3 -3
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.spc_typ.json +6 -6
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.construction_properties.json +19 -559
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.construction_sets.json +2 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.prototype_inputs.json +5 -5
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.spc_typ.json +7 -7
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.construction_properties.json +19 -559
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.construction_sets.json +2 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.prototype_inputs.json +5 -5
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.spc_typ.json +7 -7
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.construction_properties.json +370 -910
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.construction_sets.json +2 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.prototype_inputs.json +6 -6
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.refrigeration_system.json +0 -8
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.spc_typ.json +12 -12
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.AirLoopHVAC.rb +19 -6
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.construction_properties.json +2380 -1300
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.construction_sets.json +2 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.prototype_inputs.json +6 -6
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.refrigeration_system.json +0 -8
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.spc_typ.json +12 -12
- data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.constructions.json +140 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.schedules.json +1176 -312
- data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/data/doe_ref_1980_2004.construction_properties.json +172 -1132
- data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/data/doe_ref_1980_2004.construction_sets.json +14 -14
- data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/data/doe_ref_1980_2004.prototype_inputs.json +2 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/data/doe_ref_1980_2004.spc_typ.json +9 -9
- data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/data/doe_ref_pre_1980.construction_properties.json +180 -1140
- data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/data/doe_ref_pre_1980.construction_sets.json +14 -14
- data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/data/doe_ref_pre_1980.prototype_inputs.json +2 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/data/doe_ref_pre_1980.spc_typ.json +10 -10
- data/lib/openstudio-standards/standards/ashrae_90_1/nrel_zne_ready_2017/data/nrel_zne_ready_2017.construction_properties.json +9 -9
- data/lib/openstudio-standards/standards/ashrae_90_1/ze_aedg_multifamily/data/ze_aedg_multifamily.construction_properties.json +9 -9
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_3_and_8_single_speed.rb +12 -6
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_4.rb +12 -6
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_6.rb +16 -8
- data/lib/openstudio-standards/standards/necb/ECMS/ecms.rb +10 -20
- data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +209 -37
- data/lib/openstudio-standards/standards/necb/ECMS/loads.rb +1 -0
- data/lib/openstudio-standards/standards/necb/ECMS/pv_ground.rb +8 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +16 -9
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/HighriseApartment.osm +1 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LowriseApartment.osm +1 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/MidriseApartment.osm +1 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_1_multi_speed.rb +9 -5
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_1_single_speed.rb +10 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_2_and_5.rb +9 -5
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_multi_speed.rb +14 -8
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_single_speed.rb +14 -8
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_4.rb +13 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_6.rb +12 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +4 -2
- data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +38 -19
- data/lib/openstudio-standards/standards/necb/NECB2011/qaqc/necb_qaqc.rb +2 -2
- data/lib/openstudio-standards/standards/necb/NECB2011/service_water_heating.rb +15 -4
- data/lib/openstudio-standards/standards/necb/NECB2020/building_envelope.rb +10 -651
- data/lib/openstudio-standards/standards/necb/NECB2020/necb_2020.rb +8 -38
- data/lib/openstudio-standards/standards/necb/NECB2020/service_water_heating.rb +159 -0
- data/lib/openstudio-standards/standards/necb/common/btap_data.rb +41 -43
- data/lib/openstudio-standards/standards/necb/common/btap_datapoint.rb +7 -4
- data/lib/openstudio-standards/version.rb +1 -1
- data/lib/openstudio-standards.rb +1 -0
- metadata +4 -2
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# This class holds methods that apply NECB2020 rules.
|
|
2
2
|
|
|
3
3
|
# Notes for adding new version of NECB:
|
|
4
|
-
# Essentially all you need to do is copy this file to a new folder and update the class name
|
|
5
|
-
# files if the content has changed. Do not forget to update the class name in the rb files
|
|
4
|
+
# Essentially all you need to do is copy this file to a new folder and update the class name (only the initialize and load_standards_database_new methods are required,
|
|
5
|
+
# everything else will be inherited. Only add methods, json files and other rb files if the content/functionality has changed. Do not forget to update the class name in the rb files!
|
|
6
6
|
# The spacetypes and led lighting json files are required (in the data folder) as they have the NECB version hardcoded (which requires updating).
|
|
7
7
|
# However there are a few other files to update:
|
|
8
8
|
# 1) NECB2011/necb_2011.rb:determine_spacetype_vintage method has an array of available versions of NECB hardcoded. Add the new one.
|
|
9
9
|
# 2) common/space_type_upgrade_map.json needs all the space types for the new version defined (386 in NECB 2020).
|
|
10
|
-
# 3) Add references to the
|
|
10
|
+
# 3) Add references to the rb files in this folder to openstudio_standards.rb
|
|
11
11
|
|
|
12
12
|
# @ref [References::NECB2020]
|
|
13
13
|
class NECB2020 < NECB2017
|
|
@@ -21,8 +21,8 @@ class NECB2020 < NECB2017
|
|
|
21
21
|
self.corrupt_standards_database()
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def load_standards_database_new
|
|
25
|
-
#load
|
|
24
|
+
def load_standards_database_new
|
|
25
|
+
# load NECB2020 data.
|
|
26
26
|
super()
|
|
27
27
|
|
|
28
28
|
if __dir__[0] == ':' # Running from OpenStudio CLI
|
|
@@ -37,7 +37,7 @@ class NECB2020 < NECB2017
|
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
else
|
|
40
|
-
files = Dir.glob("#{File.dirname(__FILE__)}/data/*.json").select {|e| File.file? e}
|
|
40
|
+
files = Dir.glob("#{File.dirname(__FILE__)}/data/*.json").select { |e| File.file? e }
|
|
41
41
|
files.each do |file|
|
|
42
42
|
data = JSON.parse(File.read(file))
|
|
43
43
|
if !data['tables'].nil?
|
|
@@ -49,41 +49,11 @@ class NECB2020 < NECB2017
|
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
|
-
#Write test report file.
|
|
52
|
+
# Write test report file.
|
|
53
53
|
# Write database to file.
|
|
54
|
-
# File.open(File.join(File.dirname(__FILE__), '..', '
|
|
55
|
-
|
|
54
|
+
# File.open(File.join(File.dirname(__FILE__), '..', 'NECB2017.json'), 'w') {|f| f.write(JSON.pretty_generate(@standards_data))}
|
|
56
55
|
return @standards_data
|
|
57
56
|
end
|
|
58
|
-
|
|
59
|
-
def set_lighting_per_area_led_lighting(space_type:, definition:, lighting_per_area_led_lighting:, lights_scale:)
|
|
60
|
-
|
|
61
|
-
# puts "#{space_type.name.to_s} - 'space_height' - #{space_height.to_s}"
|
|
62
|
-
#TODO: Note that 'occ_sens_lpd_frac' in this function has been removed for NECB2015 and 2017.
|
|
63
|
-
# ##### Since Atrium's LPD for LED lighting depends on atrium's height, the height of the atrium (if applicable) should be found.
|
|
64
|
-
standards_space_type = space_type.standardsSpaceType.is_initialized ? space_type.standardsSpaceType.get : nil #Sara
|
|
65
|
-
if standards_space_type.include? 'Atrium' # TODO: Note that since none of the archetypes has Atrium, this was tested for 'Dining'. #Atrium
|
|
66
|
-
puts "#{standards_space_type} - has atrium" # space_type.name.to_s
|
|
67
|
-
# puts space_height
|
|
68
|
-
if get_max_space_height_for_space_type(space_type: space_type) < 12.0
|
|
69
|
-
# TODO: Regarding the below equations, identify which version of ASHRAE 90.1 was used in NECB2017.
|
|
70
|
-
atrium_lpd_eq_smaller_12_intercept = 0
|
|
71
|
-
atrium_lpd_eq_smaller_12_slope = 1.06
|
|
72
|
-
atrium_lpd_eq_larger_12_intercept = 4.3
|
|
73
|
-
atrium_lpd_eq_larger_12_slope = 0.71
|
|
74
|
-
lighting_per_area_led_lighting_atrium = (atrium_lpd_eq_smaller_12_intercept + atrium_lpd_eq_smaller_12_slope * space_height) * 0.092903 # W/ft2
|
|
75
|
-
else # i.e. get_max_space_height_for_space_type >= 12.0
|
|
76
|
-
lighting_per_area_led_lighting_atrium = (atrium_lpd_eq_larger_12_intercept + atrium_lpd_eq_larger_12_slope * space_height) * 0.092903 # W/ft2
|
|
77
|
-
end
|
|
78
|
-
puts "#{standards_space_type} - has lighting_per_area_led_lighting_atrium - #{lighting_per_area_led_lighting_atrium}"
|
|
79
|
-
lighting_per_area_led_lighting = lighting_per_area_led_lighting_atrium
|
|
80
|
-
end
|
|
81
|
-
lighting_per_area_led_lighting *= lights_scale
|
|
82
|
-
|
|
83
|
-
definition.setWattsperSpaceFloorArea(OpenStudio.convert(lighting_per_area_led_lighting.to_f, 'W/ft^2', 'W/m^2').get)
|
|
84
|
-
|
|
85
|
-
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.SpaceType', "#{space_type.name} set LPD to #{lighting_per_area_led_lighting} W/ft^2.")
|
|
86
|
-
end
|
|
87
57
|
|
|
88
58
|
# Set the infiltration rate for this space to include
|
|
89
59
|
# the impact of air leakage requirements in the standard.
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
class NECB2020
|
|
2
|
+
|
|
3
|
+
# Applies the standard efficiency ratings and typical losses and paraisitic loads to this object.
|
|
4
|
+
# Efficiency and skin loss coefficient (UA)
|
|
5
|
+
# Per PNNL http://www.energycodes.gov/sites/default/files/documents/PrototypeModelEnhancements_2014_0.pdf
|
|
6
|
+
# Appendix A: Service Water Heating
|
|
7
|
+
#
|
|
8
|
+
# @return [Bool] true if successful, false if not
|
|
9
|
+
#
|
|
10
|
+
# This was modified in PCF 1630
|
|
11
|
+
#
|
|
12
|
+
def water_heater_mixed_apply_efficiency(water_heater_mixed)
|
|
13
|
+
# Get the capacity of the water heater
|
|
14
|
+
# TODO add capability to pull autosized water heater capacity
|
|
15
|
+
# if the Sizing:WaterHeater object is ever implemented in OpenStudio.
|
|
16
|
+
capacity_w = water_heater_mixed.heaterMaximumCapacity
|
|
17
|
+
if capacity_w.empty?
|
|
18
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.WaterHeaterMixed', "For #{water_heater_mixed.name}, cannot find capacity, standard will not be applied.")
|
|
19
|
+
return false
|
|
20
|
+
else
|
|
21
|
+
capacity_w = capacity_w.get
|
|
22
|
+
end
|
|
23
|
+
capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get
|
|
24
|
+
capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get
|
|
25
|
+
|
|
26
|
+
# Get the volume of the water heater
|
|
27
|
+
# TODO add capability to pull autosized water heater volume
|
|
28
|
+
# if the Sizing:WaterHeater object is ever implemented in OpenStudio.
|
|
29
|
+
volume_m3 = water_heater_mixed.tankVolume
|
|
30
|
+
if volume_m3.empty?
|
|
31
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.WaterHeaterMixed', "For #{water_heater_mixed.name}, cannot find volume, standard will not be applied.")
|
|
32
|
+
return false
|
|
33
|
+
else
|
|
34
|
+
volume_m3 = volume_m3.get
|
|
35
|
+
end
|
|
36
|
+
volume_gal = OpenStudio.convert(volume_m3, 'm^3', 'gal').get
|
|
37
|
+
|
|
38
|
+
# Get the heater fuel type
|
|
39
|
+
fuel_type = water_heater_mixed.heaterFuelType
|
|
40
|
+
unless fuel_type == 'NaturalGas' || fuel_type == 'Electricity' || fuel_type == 'FuelOilNo2'
|
|
41
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.WaterHeaterMixed', "For #{water_heater_mixed.name}, fuel type of #{fuel_type} is not yet supported, standard will not be applied.")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Calculate the water heater efficiency and
|
|
45
|
+
# skin loss coefficient (UA)
|
|
46
|
+
# Calculate the energy factor (EF)
|
|
47
|
+
# From PNNL http://www.energycodes.gov/sites/default/files/documents/PrototypeModelEnhancements_2014_0.pdf
|
|
48
|
+
# Appendix A: Service Water Heating
|
|
49
|
+
# and modified by PCF 1630 as noted below.
|
|
50
|
+
water_heater_eff = nil
|
|
51
|
+
ua_btu_per_hr_per_f = nil
|
|
52
|
+
sl_btu_per_hr = nil
|
|
53
|
+
case fuel_type
|
|
54
|
+
when 'Electricity'
|
|
55
|
+
volume_l_per_s = volume_m3 * 1000
|
|
56
|
+
if capacity_btu_per_hr <= OpenStudio.convert(12, 'kW', 'Btu/hr').get
|
|
57
|
+
# Fixed water heater efficiency per PNNL
|
|
58
|
+
water_heater_eff = 1
|
|
59
|
+
# Calculate the max allowable standby loss (SL)
|
|
60
|
+
sl_w = if volume_l_per_s < 270
|
|
61
|
+
40 + 0.2 * volume_l_per_s # assume bottom inlet
|
|
62
|
+
else
|
|
63
|
+
0.472 * volume_l_per_s - 33.5
|
|
64
|
+
# assume bottom inlet
|
|
65
|
+
end
|
|
66
|
+
sl_btu_per_hr = OpenStudio.convert(sl_w, 'W', 'Btu/hr').get
|
|
67
|
+
else
|
|
68
|
+
# Fixed water heater efficiency per PNNL
|
|
69
|
+
water_heater_eff = 1
|
|
70
|
+
# Calculate the max allowable standby loss (SL) # use this - NECB does not give SL calculation for cap > 12 kW
|
|
71
|
+
sl_btu_per_hr = 20 + (35 * Math.sqrt(volume_gal))
|
|
72
|
+
end
|
|
73
|
+
# Calculate the skin loss coefficient (UA)
|
|
74
|
+
ua_btu_per_hr_per_f = sl_btu_per_hr / 70
|
|
75
|
+
when 'NaturalGas'
|
|
76
|
+
volume_l = volume_m3 / 1000
|
|
77
|
+
if capacity_btu_per_hr <= 75_000
|
|
78
|
+
# Fixed water heater thermal efficiency per PNNL
|
|
79
|
+
water_heater_eff = 0.82
|
|
80
|
+
|
|
81
|
+
# Calculate the minimum Energy Factor (EF) (This was introduced in PCF 1630)
|
|
82
|
+
if volume_l < 68
|
|
83
|
+
uef = 0.5982 - 0.0005 * volume_l
|
|
84
|
+
ef = 1.0005 * uef + 0.0019
|
|
85
|
+
elsif volume_l >= 68 and volume_l < 193
|
|
86
|
+
uef = 0.6483 - 0.00045 * volume_l
|
|
87
|
+
ef = 1.0005 * uef + 0.0019
|
|
88
|
+
elsif volume_l >= 193 and volume_l < 284
|
|
89
|
+
uef = 0.692 - 0.00034 * volume_l
|
|
90
|
+
ef = 1.0005 * uef + 0.0019
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Calculate the Recovery Efficiency (RE)
|
|
94
|
+
# based on a fixed capacity of 75,000 Btu/hr
|
|
95
|
+
# and a fixed volume of 40 gallons by solving
|
|
96
|
+
# this system of equations:
|
|
97
|
+
# ua = (1/.95-1/re)/(67.5*(24/41094-1/(re*cap)))
|
|
98
|
+
# 0.82 = (ua*67.5+cap*re)/cap
|
|
99
|
+
cap = 75_000.0
|
|
100
|
+
re = (Math.sqrt(6724 * ef**2 * cap**2 + 40_409_100 * ef**2 * cap - 28_080_900 * ef * cap + 29_318_000_625 * ef**2 - 58_636_001_250 * ef + 29_318_000_625) + 82 * ef * cap + 171_225 * ef - 171_225) / (200 * ef * cap)
|
|
101
|
+
|
|
102
|
+
# Calculate the skin loss coefficient (UA)
|
|
103
|
+
# based on the actual capacity.
|
|
104
|
+
ua_btu_per_hr_per_f = (water_heater_eff - re) * capacity_btu_per_hr / 67.5
|
|
105
|
+
|
|
106
|
+
# This capacity band was introduced in PCF 1630
|
|
107
|
+
elsif capacity_btu_per_hr > 75_000 and capacity_btu_per_hr < 103977 and volume_l < 454
|
|
108
|
+
water_heater_eff = 0.82
|
|
109
|
+
uef = 0.8107 - 0.00021 * volume_l
|
|
110
|
+
ef = 1.0005 * uef + 0.0019
|
|
111
|
+
cap = 103977
|
|
112
|
+
re = (Math.sqrt(6724 * ef**2 * cap**2 + 40_409_100 * ef**2 * cap - 28_080_900 * ef * cap + 29_318_000_625 * ef**2 - 58_636_001_250 * ef + 29_318_000_625) + 82 * ef * cap + 171_225 * ef - 171_225) / (200 * ef * cap)
|
|
113
|
+
|
|
114
|
+
# Calculate the skin loss coefficient (UA)
|
|
115
|
+
# based on the actual capacity.
|
|
116
|
+
ua_btu_per_hr_per_f = (water_heater_eff - re) * capacity_btu_per_hr / 67.5
|
|
117
|
+
else
|
|
118
|
+
# Thermal efficiency (PCF 1630 update)
|
|
119
|
+
et = 0.9
|
|
120
|
+
sl_w = 0.84 * capacity_btu_per_hr / 3412.412 / 0.234 + 16.57 * (volume_l ** 0.5)
|
|
121
|
+
sl_btu_per_hr = sl_w * 3.412
|
|
122
|
+
# Calculate the skin loss coefficient (UA)
|
|
123
|
+
ua_btu_per_hr_per_f = (sl_btu_per_hr * et) / 70
|
|
124
|
+
# Calculate water heater efficiency
|
|
125
|
+
water_heater_eff = (ua_btu_per_hr_per_f * 70 + capacity_btu_per_hr * et) / capacity_btu_per_hr
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Convert to SI
|
|
130
|
+
ua_btu_per_hr_per_c = OpenStudio.convert(ua_btu_per_hr_per_f, 'Btu/hr*R', 'W/K').get
|
|
131
|
+
|
|
132
|
+
# Set the water heater properties
|
|
133
|
+
# Efficiency
|
|
134
|
+
water_heater_mixed.setHeaterThermalEfficiency(water_heater_eff)
|
|
135
|
+
# Skin loss
|
|
136
|
+
water_heater_mixed.setOffCycleLossCoefficienttoAmbientTemperature(ua_btu_per_hr_per_c)
|
|
137
|
+
water_heater_mixed.setOnCycleLossCoefficienttoAmbientTemperature(ua_btu_per_hr_per_c)
|
|
138
|
+
# TODO: Parasitic loss (pilot light)
|
|
139
|
+
# PNNL document says pilot lights were removed, but IDFs
|
|
140
|
+
# still have the on/off cycle parasitic fuel consumptions filled in
|
|
141
|
+
water_heater_mixed.setOnCycleParasiticFuelType(fuel_type)
|
|
142
|
+
# self.setOffCycleParasiticFuelConsumptionRate(??)
|
|
143
|
+
water_heater_mixed.setOnCycleParasiticHeatFractiontoTank(0)
|
|
144
|
+
water_heater_mixed.setOffCycleParasiticFuelType(fuel_type)
|
|
145
|
+
# self.setOffCycleParasiticFuelConsumptionRate(??)
|
|
146
|
+
water_heater_mixed.setOffCycleParasiticHeatFractiontoTank(0.8)
|
|
147
|
+
|
|
148
|
+
# set part-load performance curve
|
|
149
|
+
if (fuel_type == 'NaturalGas') || (fuel_type == 'FuelOilNo2')
|
|
150
|
+
plf_vs_plr_curve = model_add_curve(water_heater_mixed.model, 'SWH-EFFFPLR-NECB2011')
|
|
151
|
+
water_heater_mixed.setPartLoadFactorCurve(plf_vs_plr_curve)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Append the name with standards information
|
|
155
|
+
water_heater_mixed.setName("#{water_heater_mixed.name} #{water_heater_eff.round(3)} Therm Eff")
|
|
156
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.WaterHeaterMixed', "For #{template}: #{water_heater_mixed.name}; thermal efficiency = #{water_heater_eff.round(3)}, skin-loss UA = #{ua_btu_per_hr_per_f.round}Btu/hr")
|
|
157
|
+
return true
|
|
158
|
+
end
|
|
159
|
+
end
|
|
@@ -408,9 +408,19 @@ class BTAPData
|
|
|
408
408
|
'NU' => 'Nunavut' }
|
|
409
409
|
building_type = 'Commercial'
|
|
410
410
|
province = provinces_names_map[model.getWeatherFile.stateProvinceRegion]
|
|
411
|
-
neb_eplus_fuel_map = { '
|
|
412
|
-
|
|
413
|
-
|
|
411
|
+
neb_eplus_fuel_map = {'Natural Gas' => {eplus_fuel_name: 'NaturalGas',
|
|
412
|
+
eplus_table_name: 'Annual and Peak Values - Natural Gas',
|
|
413
|
+
eplus_row_name: 'NaturalGas:Facility',
|
|
414
|
+
eplus_column_name: 'Natural Gas Annual Value'},
|
|
415
|
+
'Electricity' => {eplus_fuel_name: 'Electricity',
|
|
416
|
+
eplus_table_name: 'Annual and Peak Values - Electricity',
|
|
417
|
+
eplus_row_name: 'Electricity:Facility',
|
|
418
|
+
eplus_column_name: 'Electricity Annual Value'},
|
|
419
|
+
'Oil' => {eplus_fuel_name: 'FuelOilNo2',
|
|
420
|
+
eplus_table_name: 'Annual and Peak Values - Other',
|
|
421
|
+
eplus_row_name: 'FuelOilNo2:Facility',
|
|
422
|
+
eplus_column_name: 'Annual Value'}
|
|
423
|
+
}
|
|
414
424
|
economics_data['cost_utility_neb_total_cost_per_m_sq'] = 0.0
|
|
415
425
|
economics_data['cost_utility_ghg_total_kg_per_m_sq'] = 0.0
|
|
416
426
|
# Create a hash of the neb data.
|
|
@@ -424,32 +434,20 @@ class BTAPData
|
|
|
424
434
|
end
|
|
425
435
|
neb_fuel_cost = row['2020']
|
|
426
436
|
fuel_consumption_gj = 0.0
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
fuel_consumption_gj = model.sqlFile.get.execAndReturnFirstDouble(sql_command).is_initialized ? model.sqlFile.get.execAndReturnFirstDouble(sql_command).get : 0.0
|
|
436
|
-
else
|
|
437
|
-
sql_command = " SELECT Value FROM tabulardatawithstrings
|
|
438
|
-
WHERE ReportName='EnergyMeters'
|
|
439
|
-
AND ReportForString='Entire Facility'
|
|
440
|
-
AND TableName='Annual and Peak Values - Other'
|
|
441
|
-
AND RowName='#{ep_fuel}:Facility'
|
|
442
|
-
AND ColumnName='Annual Value'
|
|
443
|
-
AND Units='GJ'"
|
|
444
|
-
|
|
445
|
-
fuel_consumption_gj = model.sqlFile.get.execAndReturnFirstDouble(sql_command).is_initialized ? model.sqlFile.get.execAndReturnFirstDouble(sql_command).get : 0.0
|
|
446
|
-
end
|
|
437
|
+
sql_command = "SELECT Value FROM tabulardatawithstrings
|
|
438
|
+
WHERE ReportName='EnergyMeters'
|
|
439
|
+
AND ReportForString='Entire Facility'
|
|
440
|
+
AND TableName='#{ep_fuel[:eplus_table_name]}'
|
|
441
|
+
AND RowName='#{ep_fuel[:eplus_row_name]}'
|
|
442
|
+
AND ColumnName='#{ep_fuel[:eplus_column_name]}'
|
|
443
|
+
AND Units='GJ'"
|
|
444
|
+
fuel_consumption_gj = model.sqlFile.get.execAndReturnFirstDouble(sql_command).is_initialized ? model.sqlFile.get.execAndReturnFirstDouble(sql_command).get : 0.0
|
|
447
445
|
|
|
448
446
|
# Determine costs in $$
|
|
449
447
|
economics_data["cost_utility_neb_#{neb_fuel.downcase}_cost_per_m_sq"] = fuel_consumption_gj * neb_fuel_cost.to_f / @conditioned_floor_area_m_sq
|
|
450
448
|
economics_data['cost_utility_neb_total_cost_per_m_sq'] += economics_data["cost_utility_neb_#{neb_fuel.downcase}_cost_per_m_sq"]
|
|
451
449
|
# Determine cost in GHG kg of CO2
|
|
452
|
-
economics_data["cost_utility_ghg_#{neb_fuel.downcase}_kg_per_m_sq"] = fuel_consumption_gj * get_utility_ghg_kg_per_gj(province: model.getWeatherFile.stateProvinceRegion, fuel_type: ep_fuel) / @conditioned_floor_area_m_sq
|
|
450
|
+
economics_data["cost_utility_ghg_#{neb_fuel.downcase}_kg_per_m_sq"] = fuel_consumption_gj * get_utility_ghg_kg_per_gj(province: model.getWeatherFile.stateProvinceRegion, fuel_type: ep_fuel[:eplus_fuel_name]) / @conditioned_floor_area_m_sq
|
|
453
451
|
economics_data['cost_utility_ghg_total_kg_per_m_sq'] += economics_data["cost_utility_ghg_#{neb_fuel.downcase}_kg_per_m_sq"]
|
|
454
452
|
end
|
|
455
453
|
# Commenting out block charge rates for now....
|
|
@@ -1242,8 +1240,8 @@ class BTAPData
|
|
|
1242
1240
|
" AND ReportForString='Entire Facility' AND TableName='Annual and Peak Values - Electricity' AND RowName='Electricity:Facility'" \
|
|
1243
1241
|
" AND ColumnName='Electricity Maximum Value' AND Units='W'")
|
|
1244
1242
|
natural_gas_peak = @model.sqlFile.get.execAndReturnFirstDouble("SELECT Value FROM tabulardatawithstrings WHERE ReportName='EnergyMeters'" \
|
|
1245
|
-
" AND ReportForString='Entire Facility' AND TableName='Annual and Peak Values - Gas' AND RowName='
|
|
1246
|
-
" AND ColumnName='Gas Maximum Value' AND Units='W'")
|
|
1243
|
+
" AND ReportForString='Entire Facility' AND TableName='Annual and Peak Values - Natural Gas' AND RowName='NaturalGas:Facility'" \
|
|
1244
|
+
" AND ColumnName='Natural Gas Maximum Value' AND Units='W'")
|
|
1247
1245
|
data['energy_peak_electric_w_per_m_sq'] = electric_peak.empty? ? 0.0 : electric_peak.get / @conditioned_floor_area_m_sq
|
|
1248
1246
|
data['energy_peak_natural_gas_w_per_m_sq'] = natural_gas_peak.empty? ? 0.0 : natural_gas_peak.get / @conditioned_floor_area_m_sq
|
|
1249
1247
|
|
|
@@ -1261,9 +1259,9 @@ class BTAPData
|
|
|
1261
1259
|
FROM TabularDataWithStrings
|
|
1262
1260
|
WHERE ReportName='EnergyMeters'
|
|
1263
1261
|
AND ReportForString='Entire Facility'
|
|
1264
|
-
AND TableName='Annual and Peak Values - Gas'
|
|
1262
|
+
AND TableName='Annual and Peak Values - Natural Gas'
|
|
1265
1263
|
AND RowName='Heating:Gas'
|
|
1266
|
-
AND ColumnName='Gas Maximum Value'
|
|
1264
|
+
AND ColumnName='Natural Gas Maximum Value'
|
|
1267
1265
|
AND Units='W'"
|
|
1268
1266
|
heating_peak_w_gas = @sqlite_file.get.execAndReturnFirstDouble(command)
|
|
1269
1267
|
heating_peak_w = [heating_peak_w_electricity.to_f, heating_peak_w_gas.to_f].max
|
|
@@ -1283,7 +1281,7 @@ class BTAPData
|
|
|
1283
1281
|
FROM TabularDataWithStrings
|
|
1284
1282
|
WHERE ReportName='EnergyMeters'
|
|
1285
1283
|
AND ReportForString='Entire Facility'
|
|
1286
|
-
AND TableName='Annual and Peak Values - Gas'
|
|
1284
|
+
AND TableName='Annual and Peak Values - Natural Gas'
|
|
1287
1285
|
AND RowName='Cooling:Electricity'
|
|
1288
1286
|
AND ColumnName='Electricity Maximum Value'
|
|
1289
1287
|
AND Units='W'"
|
|
@@ -1406,7 +1404,7 @@ class BTAPData
|
|
|
1406
1404
|
# ["InputVerificationandResultsSummary", "Entire Facility", "Skylight-Roof Ratio"],
|
|
1407
1405
|
# ["DemandEndUseComponentsSummary", "Entire Facility", "End Uses"],
|
|
1408
1406
|
# ["ComponentSizingSummary", "Entire Facility", "AirLoopHVAC"],
|
|
1409
|
-
# ["EnergyMeters", "Entire Facility", 'Annual and Peak Values - Gas'],
|
|
1407
|
+
# ["EnergyMeters", "Entire Facility", 'Annual and Peak Values - Natural Gas'],
|
|
1410
1408
|
# ["EnergyMeters", "Entire Facility", 'Annual and Peak Values - Electricity'],
|
|
1411
1409
|
# ["EnergyMeters", "Entire Facility", 'Annual and Peak Values - FuelOilNo2'],
|
|
1412
1410
|
# ["EnergyMeters", "Entire Facility", 'Annual and Peak Values - Other'],
|
|
@@ -1648,19 +1646,19 @@ class BTAPData
|
|
|
1648
1646
|
def get_utility_ghg_kg_per_gj(province:, fuel_type:)
|
|
1649
1647
|
ghg_data = [
|
|
1650
1648
|
# Obtained from Portfolio Manager https://portfoliomanager.energystar.gov/pdf/reference/Emissions.pdf 10/10/2020
|
|
1651
|
-
{ "province": 'AB', "fuel_type": '
|
|
1652
|
-
{ "province": 'BC', "fuel_type": '
|
|
1653
|
-
{ "province": 'MB', "fuel_type": '
|
|
1654
|
-
{ "province": 'NB', "fuel_type": '
|
|
1655
|
-
{ "province": 'NL', "fuel_type": '
|
|
1656
|
-
{ "province": 'NT', "fuel_type": '
|
|
1657
|
-
{ "province": 'NS', "fuel_type": '
|
|
1658
|
-
{ "province": 'NU', "fuel_type": '
|
|
1659
|
-
{ "province": 'ON', "fuel_type": '
|
|
1660
|
-
{ "province": 'PE', "fuel_type": '
|
|
1661
|
-
{ "province": 'QC', "fuel_type": '
|
|
1662
|
-
{ "province": 'SK', "fuel_type": '
|
|
1663
|
-
{ "province": 'YT', "fuel_type": '
|
|
1649
|
+
{ "province": 'AB', "fuel_type": 'NaturalGas', "CO2eq Emissions (kg/MBtu)": 53.24, "CO2eq Emissions (g/m3)": 1939.0 },
|
|
1650
|
+
{ "province": 'BC', "fuel_type": 'NaturalGas', "CO2eq Emissions (kg/MBtu)": 53.19, "CO2eq Emissions (g/m3)": 1937.0 },
|
|
1651
|
+
{ "province": 'MB', "fuel_type": 'NaturalGas', "CO2eq Emissions (kg/MBtu)": 52.09, "CO2eq Emissions (g/m3)": 1897.0 },
|
|
1652
|
+
{ "province": 'NB', "fuel_type": 'NaturalGas', "CO2eq Emissions (kg/MBtu)": 52.50, "CO2eq Emissions (g/m3)": 1912.0 },
|
|
1653
|
+
{ "province": 'NL', "fuel_type": 'NaturalGas', "CO2eq Emissions (kg/MBtu)": 52.50, "CO2eq Emissions (g/m3)": 1912.0 },
|
|
1654
|
+
{ "province": 'NT', "fuel_type": 'NaturalGas', "CO2eq Emissions (kg/MBtu)": 52.50, "CO2eq Emissions (g/m3)": 1912.0 },
|
|
1655
|
+
{ "province": 'NS', "fuel_type": 'NaturalGas', "CO2eq Emissions (kg/MBtu)": 52.50, "CO2eq Emissions (g/m3)": 1912.0 },
|
|
1656
|
+
{ "province": 'NU', "fuel_type": 'NaturalGas', "CO2eq Emissions (kg/MBtu)": 52.50, "CO2eq Emissions (g/m3)": 1912.0 },
|
|
1657
|
+
{ "province": 'ON', "fuel_type": 'NaturalGas', "CO2eq Emissions (kg/MBtu)": 52.14, "CO2eq Emissions (g/m3)": 1912.0 },
|
|
1658
|
+
{ "province": 'PE', "fuel_type": 'NaturalGas', "CO2eq Emissions (kg/MBtu)": 52.50, "CO2eq Emissions (g/m3)": 1912.0 },
|
|
1659
|
+
{ "province": 'QC', "fuel_type": 'NaturalGas', "CO2eq Emissions (kg/MBtu)": 52.12, "CO2eq Emissions (g/m3)": 1898.0 },
|
|
1660
|
+
{ "province": 'SK', "fuel_type": 'NaturalGas', "CO2eq Emissions (kg/MBtu)": 50.53, "CO2eq Emissions (g/m3)": 1840.0 },
|
|
1661
|
+
{ "province": 'YT', "fuel_type": 'NaturalGas', "CO2eq Emissions (kg/MBtu)": 52.50, "CO2eq Emissions (g/m3)": 1912.0 },
|
|
1664
1662
|
|
|
1665
1663
|
{ "province": 'AB', "fuel_type": 'FuelOilNo2', "CO2eq Emissions (kg/MBtu)": 75.13, "CO2eq Emissions (g/m3)": 2763.0 },
|
|
1666
1664
|
{ "province": 'BC', "fuel_type": 'FuelOilNo2', "CO2eq Emissions (kg/MBtu)": 75.13, "CO2eq Emissions (g/m3)": 2763.0 },
|
|
@@ -2,7 +2,7 @@ require 'openstudio'
|
|
|
2
2
|
require 'securerandom'
|
|
3
3
|
require 'optparse'
|
|
4
4
|
require 'yaml'
|
|
5
|
-
#
|
|
5
|
+
#require 'git-revision'
|
|
6
6
|
# resource_folder = File.join(__dir__, '..', '..', 'measures/btap_results/resources')
|
|
7
7
|
# OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
|
|
8
8
|
|
|
@@ -113,6 +113,7 @@ class BTAPDatapoint
|
|
|
113
113
|
lights_scale: @options[:lights_scale],
|
|
114
114
|
daylighting_type: @options[:daylighting_type], # Two options: @options[: (1) 'NECB_Default', (2) 'add_daylighting_controls'
|
|
115
115
|
ecm_system_name: @options[:ecm_system_name],
|
|
116
|
+
ecm_system_zones_map_option: @options[:ecm_system_zones_map_option], # (1) 'NECB_Default' (2) 'one_sys_per_floor' (3) 'one_sys_per_bldg'
|
|
116
117
|
erv_package: @options[:erv_package],
|
|
117
118
|
boiler_eff: @options[:boiler_eff],
|
|
118
119
|
# Inconsistent naming Todo Chris K.
|
|
@@ -155,7 +156,9 @@ class BTAPDatapoint
|
|
|
155
156
|
chiller_type: @options[:chiller_type],
|
|
156
157
|
output_variables: @options[:output_variables],
|
|
157
158
|
output_meters: @options[:output_meters],
|
|
158
|
-
airloop_economizer_type: @options[:airloop_economizer_type]
|
|
159
|
+
airloop_economizer_type: @options[:airloop_economizer_type],
|
|
160
|
+
shw_scale: @options[:shw_scale],
|
|
161
|
+
baseline_system_zones_map_option: @options[:baseline_system_zones_map_option])
|
|
159
162
|
end
|
|
160
163
|
|
|
161
164
|
# Save model to to disk.
|
|
@@ -267,8 +270,8 @@ class BTAPDatapoint
|
|
|
267
270
|
end
|
|
268
271
|
|
|
269
272
|
def s3_copy_file_to_s3(bucket_name:, source_file:, target_file:, n: 0)
|
|
270
|
-
require 'aws-sdk-core'
|
|
271
|
-
require 'aws-sdk-s3'
|
|
273
|
+
# require 'aws-sdk-core'
|
|
274
|
+
# require 'aws-sdk-s3'
|
|
272
275
|
Aws.use_bundled_cert!
|
|
273
276
|
s3_resource = Aws::S3::Resource.new(region: 'ca-central-1')
|
|
274
277
|
|
data/lib/openstudio-standards.rb
CHANGED
|
@@ -55,6 +55,7 @@ module OpenstudioStandards
|
|
|
55
55
|
# NECB2020 Code
|
|
56
56
|
require_relative "#{stds}/necb/NECB2020/necb_2020"
|
|
57
57
|
require_relative "#{stds}/necb/NECB2020/building_envelope"
|
|
58
|
+
require_relative "#{stds}/necb/NECB2020/service_water_heating"
|
|
58
59
|
|
|
59
60
|
# BTAPPRE1980
|
|
60
61
|
require_relative "#{stds}/necb/BTAPPRE1980/btap_pre1980"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openstudio-standards
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.16.rc1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Parker
|
|
@@ -28,7 +28,7 @@ authors:
|
|
|
28
28
|
autorequire:
|
|
29
29
|
bindir: bin
|
|
30
30
|
cert_chain: []
|
|
31
|
-
date:
|
|
31
|
+
date: 2022-03-18 00:00:00.000000000 Z
|
|
32
32
|
dependencies:
|
|
33
33
|
- !ruby/object:Gem::Dependency
|
|
34
34
|
name: minitest-reporters
|
|
@@ -640,6 +640,7 @@ files:
|
|
|
640
640
|
- data/geometry/DOERefWarehouse.json
|
|
641
641
|
- data/geometry/DOERefWarehouse.osm
|
|
642
642
|
- data/standards/OpenStudio_Standards-ashrae_90_1.xlsx
|
|
643
|
+
- data/standards/OpenStudio_Standards-ashrae_90_1_28Jan2022.xlsx
|
|
643
644
|
- data/standards/exclude_list.csv
|
|
644
645
|
- data/standards/export_OpenStudio_libraries.rb
|
|
645
646
|
- data/standards/legacy_dd_results.csv
|
|
@@ -2879,6 +2880,7 @@ files:
|
|
|
2879
2880
|
- lib/openstudio-standards/standards/necb/NECB2020/data/surface_thermal_transmittance.json
|
|
2880
2881
|
- lib/openstudio-standards/standards/necb/NECB2020/data/unitary_acs.json
|
|
2881
2882
|
- lib/openstudio-standards/standards/necb/NECB2020/necb_2020.rb
|
|
2883
|
+
- lib/openstudio-standards/standards/necb/NECB2020/service_water_heating.rb
|
|
2882
2884
|
- lib/openstudio-standards/standards/necb/common/bc_step_code_indicators.md
|
|
2883
2885
|
- lib/openstudio-standards/standards/necb/common/btap_data.rb
|
|
2884
2886
|
- lib/openstudio-standards/standards/necb/common/btap_datapoint.rb
|