openstudio-standards 0.2.15 → 0.2.16.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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,314 +1,5 @@
|
|
1
|
-
class NECB2020
|
2
|
-
|
3
|
-
# Reduces the WWR to the values specified by the NECB
|
4
|
-
# NECB 3.2.1.4
|
5
|
-
def apply_standard_window_to_wall_ratio(model:, fdwr_set: -1.0)
|
6
|
-
# NECB FDWR limit
|
7
|
-
hdd = self.get_necb_hdd18(model)
|
8
|
-
|
9
|
-
# Get the maximum NECB fdwr
|
10
|
-
# fdwr_set settings:
|
11
|
-
# 0-1: Remove all windows and add windows to match this fdwr
|
12
|
-
# -1: Remove all windows and add windows to match max fdwr from NECB
|
13
|
-
# -2: Do not apply any fdwr changes, leave windows alone (also works for fdwr > 1)
|
14
|
-
# -3: Use old method which reduces existing window size (if necessary) to meet maximum NECB fdwr limit
|
15
|
-
# <-3.1: Remove all the windows
|
16
|
-
# > 1: Do nothing
|
17
|
-
|
18
|
-
if fdwr_set.to_f > 1.0
|
19
|
-
return
|
20
|
-
elsif fdwr_set.to_f >= 0.0 and fdwr_set <= 1.0
|
21
|
-
apply_max_fdwr_nrcan(model: model, fdwr_lim: fdwr_set.to_f)
|
22
|
-
return
|
23
|
-
elsif fdwr_set.to_f >= -1.1 and fdwr_set <= -0.9
|
24
|
-
fdwr_lim = (max_fwdr(hdd)).round(3)
|
25
|
-
apply_max_fdwr_nrcan(model: model, fdwr_lim: fdwr_lim.to_f)
|
26
|
-
return
|
27
|
-
elsif fdwr_set.to_f >= -2.1 and fdwr_set <= -1.9
|
28
|
-
return
|
29
|
-
elsif fdwr_set.to_f >= -3.1 and fdwr_set <= -2.9
|
30
|
-
fdwr_lim = (max_fwdr(hdd) * 100.0).round(1)
|
31
|
-
return apply_limit_fdwr(model: model, fdwr_lim: fdwr_lim.to_f)
|
32
|
-
elsif fdwr_set < -3.1
|
33
|
-
apply_max_fdwr_nrcan(model: model, fdwr_lim: fdwr_set.to_f)
|
34
|
-
return
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def apply_limit_fdwr(model:, fdwr_lim:)
|
39
|
-
# Loop through all spaces in the model, and
|
40
|
-
# per the PNNL PRM Reference Manual, find the areas
|
41
|
-
# of each space conditioning category (res, nonres, semi-heated)
|
42
|
-
# separately. Include space multipliers.
|
43
|
-
nr_wall_m2 = 0.001 # Avoids divide by zero errors later
|
44
|
-
nr_wind_m2 = 0
|
45
|
-
res_wall_m2 = 0.001
|
46
|
-
res_wind_m2 = 0
|
47
|
-
sh_wall_m2 = 0.001
|
48
|
-
sh_wind_m2 = 0
|
49
|
-
total_wall_m2 = 0.001
|
50
|
-
total_subsurface_m2 = 0.0
|
51
|
-
# Store the space conditioning category for later use
|
52
|
-
space_cats = {}
|
53
|
-
model.getSpaces.sort.each do |space|
|
54
|
-
# Loop through all surfaces in this space
|
55
|
-
wall_area_m2 = 0
|
56
|
-
wind_area_m2 = 0
|
57
|
-
space.surfaces.sort.each do |surface|
|
58
|
-
# Skip non-outdoor surfaces
|
59
|
-
next unless surface.outsideBoundaryCondition == 'Outdoors'
|
60
|
-
# Skip non-walls
|
61
|
-
next unless surface.surfaceType.casecmp('wall').zero?
|
62
|
-
# This wall's gross area (including window area)
|
63
|
-
wall_area_m2 += surface.grossArea * space.multiplier
|
64
|
-
# Subsurfaces in this surface
|
65
|
-
surface.subSurfaces.sort.each do |ss|
|
66
|
-
wind_area_m2 += ss.netArea * space.multiplier
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# Determine the space category
|
71
|
-
# zTODO This should really use the heating/cooling loads
|
72
|
-
# from the proposed building. However, in an attempt
|
73
|
-
# to avoid another sizing run just for this purpose,
|
74
|
-
# conditioned status is based on heating/cooling
|
75
|
-
# setpoints. If heated-only, will be assumed Semiheated.
|
76
|
-
# The full-bore method is on the next line in case needed.
|
77
|
-
# cat = thermal_zone_conditioning_category(space, template, climate_zone)
|
78
|
-
cooled = space_cooled?(space)
|
79
|
-
heated = space_heated?(space)
|
80
|
-
cat = 'Unconditioned'
|
81
|
-
# Unconditioned
|
82
|
-
if !heated && !cooled
|
83
|
-
cat = 'Unconditioned'
|
84
|
-
# Heated-Only
|
85
|
-
elsif heated && !cooled
|
86
|
-
cat = 'Semiheated'
|
87
|
-
# Heated and Cooled
|
88
|
-
else
|
89
|
-
res = thermal_zone_residential?(space.thermalZone.get)
|
90
|
-
cat = if res
|
91
|
-
'ResConditioned'
|
92
|
-
else
|
93
|
-
'NonResConditioned'
|
94
|
-
end
|
95
|
-
end
|
96
|
-
space_cats[space] = cat
|
97
|
-
# NECB2011 keep track of totals for NECB regardless of conditioned or not.
|
98
|
-
total_wall_m2 += wall_area_m2
|
99
|
-
total_subsurface_m2 += wind_area_m2 # this contains doors as well.
|
100
|
-
|
101
|
-
# Add to the correct category
|
102
|
-
case cat
|
103
|
-
when 'Unconditioned'
|
104
|
-
next # Skip unconditioned spaces
|
105
|
-
when 'NonResConditioned'
|
106
|
-
nr_wall_m2 += wall_area_m2
|
107
|
-
nr_wind_m2 += wind_area_m2
|
108
|
-
when 'ResConditioned'
|
109
|
-
res_wall_m2 += wall_area_m2
|
110
|
-
res_wind_m2 += wind_area_m2
|
111
|
-
when 'Semiheated'
|
112
|
-
sh_wall_m2 += wall_area_m2
|
113
|
-
sh_wind_m2 += wind_area_m2
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
# Calculate the WWR of each category
|
118
|
-
wwr_nr = ((nr_wind_m2 / nr_wall_m2) * 100.0).round(1)
|
119
|
-
wwr_res = ((res_wind_m2 / res_wall_m2) * 100).round(1)
|
120
|
-
wwr_sh = ((sh_wind_m2 / sh_wall_m2) * 100).round(1)
|
121
|
-
fdwr = ((total_subsurface_m2 / total_wall_m2) * 100).round(1) # used by NECB2011
|
122
|
-
|
123
|
-
# Convert to IP and report
|
124
|
-
nr_wind_ft2 = OpenStudio.convert(nr_wind_m2, 'm^2', 'ft^2').get
|
125
|
-
nr_wall_ft2 = OpenStudio.convert(nr_wall_m2, 'm^2', 'ft^2').get
|
126
|
-
|
127
|
-
res_wind_ft2 = OpenStudio.convert(res_wind_m2, 'm^2', 'ft^2').get
|
128
|
-
res_wall_ft2 = OpenStudio.convert(res_wall_m2, 'm^2', 'ft^2').get
|
129
|
-
|
130
|
-
sh_wind_ft2 = OpenStudio.convert(sh_wind_m2, 'm^2', 'ft^2').get
|
131
|
-
sh_wall_ft2 = OpenStudio.convert(sh_wall_m2, 'm^2', 'ft^2').get
|
132
|
-
|
133
|
-
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "WWR NonRes = #{wwr_nr.round}%; window = #{nr_wind_ft2.round} ft2, wall = #{nr_wall_ft2.round} ft2.")
|
134
|
-
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "WWR Res = #{wwr_res.round}%; window = #{res_wind_ft2.round} ft2, wall = #{res_wall_ft2.round} ft2.")
|
135
|
-
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "WWR Semiheated = #{wwr_sh.round}%; window = #{sh_wind_ft2.round} ft2, wall = #{sh_wall_ft2.round} ft2.")
|
136
|
-
|
137
|
-
# WWR limit
|
138
|
-
wwr_lim = 40.0
|
139
|
-
|
140
|
-
# Check against WWR limit
|
141
|
-
red_nr = wwr_nr > wwr_lim
|
142
|
-
red_res = wwr_res > wwr_lim
|
143
|
-
red_sh = wwr_sh > wwr_lim
|
144
|
-
|
145
|
-
# puts "Current FDWR is #{fdwr}, must be less than #{fdwr_lim}."
|
146
|
-
# puts "Current subsurf area is #{total_subsurface_m2} and gross surface area is #{total_wall_m2}"
|
147
|
-
# Stop here unless windows / doors need reducing
|
148
|
-
return true unless fdwr > fdwr_lim
|
149
|
-
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "Reducing the size of all windows (by raising sill height) to reduce window area down to the limit of #{wwr_lim.round}%.")
|
150
|
-
# Determine the factors by which to reduce the window / door area
|
151
|
-
mult = fdwr_lim / fdwr
|
152
|
-
# Reduce the window area if any of the categories necessary
|
153
|
-
model.getSpaces.sort.each do |space|
|
154
|
-
# Loop through all surfaces in this space
|
155
|
-
space.surfaces.sort.each do |surface|
|
156
|
-
# Skip non-outdoor surfaces
|
157
|
-
next unless surface.outsideBoundaryCondition == 'Outdoors'
|
158
|
-
# Skip non-walls
|
159
|
-
next unless surface.surfaceType == 'Wall'
|
160
|
-
# Subsurfaces in this surface
|
161
|
-
surface.subSurfaces.sort.each do |ss|
|
162
|
-
# Reduce the size of the window
|
163
|
-
red = 1.0 - mult
|
164
|
-
sub_surface_reduce_area_by_percent_by_raising_sill(ss, red)
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
return true
|
169
|
-
end
|
170
|
-
|
171
|
-
# Reduces the SRR to the values specified by the PRM. SRR reduction
|
172
|
-
# will be done by shrinking vertices toward the centroid.
|
173
|
-
#
|
174
|
-
def apply_standard_skylight_to_roof_ratio(model:, srr_set: -1.0)
|
175
|
-
|
176
|
-
# If srr_set is between 1.0 and 1.2 set it to the maximum allowed by the NECB. If srr_set is between 0.0 and 1.0
|
177
|
-
# apply whatever was passed. If srr_set >= 1.2 then set the existing srr of the building to be the necb maximum
|
178
|
-
# only if the the srr exceeds this maximum (otherwise leave it to be whatever was modeled).
|
179
|
-
|
180
|
-
# srr_set settings:
|
181
|
-
# 0-1: Remove all skylights and add skylights to match this srr
|
182
|
-
# -1: Remove all skylights and add skylights to match max srr from NECB
|
183
|
-
# -2: Do not apply any srr changes, leave skylights alone (also works for srr > 1)
|
184
|
-
# -3: Use old method which reduces existing skylight size (if necessary) to meet maximum NECB skylight limit
|
185
|
-
# <-3.1: Remove all the skylights
|
186
|
-
# > 1: Do nothing
|
187
|
-
|
188
|
-
if srr_set.to_f > 1.0
|
189
|
-
return
|
190
|
-
elsif srr_set.to_f >= 0.0 && srr_set <= 1.0
|
191
|
-
apply_max_srr_nrcan(model: model, srr_lim: srr_set.to_f)
|
192
|
-
return
|
193
|
-
elsif srr_set.to_f >= -1.1 && srr_set <= -0.9
|
194
|
-
# Get the maximum NECB srr
|
195
|
-
srr_lim = self.get_standards_constant('skylight_to_roof_ratio_max_value')
|
196
|
-
apply_max_srr_nrcan(model: model, srr_lim: srr_lim.to_f)
|
197
|
-
return
|
198
|
-
elsif srr_set.to_f >= -2.1 && srr_set <= -1.9
|
199
|
-
return
|
200
|
-
elsif srr_set.to_f >= -3.1 && srr_set <= -2.9
|
201
|
-
# Continue with the rest of this method, use old method which reduces existing skylight size (if necessary) to
|
202
|
-
# meet maximum srr limit
|
203
|
-
elsif srr_set < -3.1
|
204
|
-
apply_max_srr_nrcan(model: model, srr_lim: srr_set.to_f)
|
205
|
-
return
|
206
|
-
else
|
207
|
-
return
|
208
|
-
end
|
209
|
-
|
210
|
-
# SRR limit
|
211
|
-
srr_lim = self.get_standards_constant('skylight_to_roof_ratio_max_value') * 100.0
|
212
|
-
|
213
|
-
# Loop through all spaces in the model, and
|
214
|
-
# per the PNNL PRM Reference Manual, find the areas
|
215
|
-
# of each space conditioning category (res, nonres, semi-heated)
|
216
|
-
# separately. Include space multipliers.
|
217
|
-
nr_wall_m2 = 0.001 # Avoids divide by zero errors later
|
218
|
-
nr_sky_m2 = 0
|
219
|
-
res_wall_m2 = 0.001
|
220
|
-
res_sky_m2 = 0
|
221
|
-
sh_wall_m2 = 0.001
|
222
|
-
sh_sky_m2 = 0
|
223
|
-
total_roof_m2 = 0.001
|
224
|
-
total_subsurface_m2 = 0
|
225
|
-
model.getSpaces.sort.each do |space|
|
226
|
-
# Loop through all surfaces in this space
|
227
|
-
wall_area_m2 = 0
|
228
|
-
sky_area_m2 = 0
|
229
|
-
space.surfaces.sort.each do |surface|
|
230
|
-
# Skip non-outdoor surfaces
|
231
|
-
next unless surface.outsideBoundaryCondition == 'Outdoors'
|
232
|
-
# Skip non-walls
|
233
|
-
next unless surface.surfaceType == 'RoofCeiling'
|
234
|
-
# This wall's gross area (including skylight area)
|
235
|
-
wall_area_m2 += surface.grossArea * space.multiplier
|
236
|
-
# Subsurfaces in this surface
|
237
|
-
surface.subSurfaces.sort.each do |ss|
|
238
|
-
sky_area_m2 += ss.netArea * space.multiplier
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
# Determine the space category
|
243
|
-
cat = 'NonRes'
|
244
|
-
if space_residential?(space)
|
245
|
-
cat = 'Res'
|
246
|
-
end
|
247
|
-
# if space.is_semiheated
|
248
|
-
# cat = 'Semiheated'
|
249
|
-
# end
|
250
|
-
|
251
|
-
# Add to the correct category
|
252
|
-
case cat
|
253
|
-
when 'NonRes'
|
254
|
-
nr_wall_m2 += wall_area_m2
|
255
|
-
nr_sky_m2 += sky_area_m2
|
256
|
-
when 'Res'
|
257
|
-
res_wall_m2 += wall_area_m2
|
258
|
-
res_sky_m2 += sky_area_m2
|
259
|
-
when 'Semiheated'
|
260
|
-
sh_wall_m2 += wall_area_m2
|
261
|
-
sh_sky_m2 += sky_area_m2
|
262
|
-
end
|
263
|
-
total_roof_m2 += wall_area_m2
|
264
|
-
total_subsurface_m2 += sky_area_m2
|
265
|
-
end
|
266
|
-
|
267
|
-
# Calculate the SRR of each category
|
268
|
-
srr_nr = ((nr_sky_m2 / nr_wall_m2) * 100).round(1)
|
269
|
-
srr_res = ((res_sky_m2 / res_wall_m2) * 100).round(1)
|
270
|
-
srr_sh = ((sh_sky_m2 / sh_wall_m2) * 100).round(1)
|
271
|
-
srr = ((total_subsurface_m2 / total_roof_m2) * 100.0).round(1)
|
272
|
-
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "The skylight to roof ratios (SRRs) are: NonRes: #{srr_nr.round}%, Res: #{srr_res.round}%.")
|
273
|
-
|
274
|
-
# Check against SRR limit
|
275
|
-
red_nr = srr_nr > srr_lim
|
276
|
-
red_res = srr_res > srr_lim
|
277
|
-
red_sh = srr_sh > srr_lim
|
278
1
|
|
279
|
-
|
280
|
-
return true unless srr > srr_lim
|
281
|
-
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "Reducing the size of all windows (by raising sill height) to reduce window area down to the limit of #{srr_lim.round}%.")
|
282
|
-
# Determine the factors by which to reduce the window / door area
|
283
|
-
mult = srr_lim / srr
|
284
|
-
|
285
|
-
# Reduce the subsurface areas
|
286
|
-
model.getSpaces.sort.each do |space|
|
287
|
-
# Loop through all surfaces in this space
|
288
|
-
space.surfaces.sort.each do |surface|
|
289
|
-
# Skip non-outdoor surfaces
|
290
|
-
next unless surface.outsideBoundaryCondition == 'Outdoors'
|
291
|
-
# Skip non-walls
|
292
|
-
next unless surface.surfaceType == 'RoofCeiling'
|
293
|
-
# Subsurfaces in this surface
|
294
|
-
surface.subSurfaces.sort.each do |ss|
|
295
|
-
# Reduce the size of the subsurface
|
296
|
-
red = 1.0 - mult
|
297
|
-
sub_surface_reduce_area_by_percent_by_shrinking_toward_centroid(ss, red)
|
298
|
-
end
|
299
|
-
end
|
300
|
-
end
|
301
|
-
|
302
|
-
return true
|
303
|
-
end
|
304
|
-
|
305
|
-
# @author phylroy.lopez@nrcan.gc.ca
|
306
|
-
# @param hdd [Float]
|
307
|
-
# @return [Double] a constant float
|
308
|
-
def max_fwdr(hdd)
|
309
|
-
# get formula from json database.
|
310
|
-
return eval(get_standards_formula('fdwr_formula'))
|
311
|
-
end
|
2
|
+
class NECB2020
|
312
3
|
|
313
4
|
# Go through the default construction sets and hard-assigned
|
314
5
|
# constructions. Clone the existing constructions and set their
|
@@ -365,20 +56,21 @@ class NECB2020
|
|
365
56
|
return false
|
366
57
|
end
|
367
58
|
|
59
|
+
# hdd required to get correct conductance values from the json file.
|
60
|
+
hdd = get_necb_hdd18(model)
|
61
|
+
|
368
62
|
# Lambdas are preferred over methods in methods for small utility methods.
|
369
63
|
correct_cond = lambda do |conductivity, surface_type|
|
370
|
-
|
371
|
-
hdd = get_necb_hdd18(model)
|
372
|
-
return conductivity.nil? || conductivity.to_f <= 0.0 || conductivity =="NECB_Default" ? eval(model_find_objects(@standards_data['surface_thermal_transmittance'], surface_type)[0]['formula']) : conductivity.to_f
|
64
|
+
return conductivity.nil? || conductivity.to_f <= 0.0 || conductivity == 'NECB_Default' ? eval(model_find_objects(@standards_data['surface_thermal_transmittance'], surface_type)[0]['formula']) : conductivity.to_f
|
373
65
|
end
|
374
66
|
|
375
67
|
# Converts trans and vis to nil if requesting default.. or casts the string to a float.
|
376
68
|
correct_vis_trans = lambda do |value|
|
377
|
-
return value.nil? || value.to_f <= 0.0 || value ==
|
69
|
+
return value.nil? || value.to_f <= 0.0 || value == 'NECB_Default' ? nil : value.to_f
|
378
70
|
end
|
379
71
|
|
380
72
|
BTAP::Resources::Envelope::ConstructionSets.customize_default_surface_construction_set!(model: model,
|
381
|
-
name: "#{default_surface_construction_set.name.get} at hdd = #{
|
73
|
+
name: "#{default_surface_construction_set.name.get} at hdd = #{hdd}",
|
382
74
|
default_surface_construction_set: default_surface_construction_set,
|
383
75
|
# ext surfaces
|
384
76
|
ext_wall_cond: correct_cond.call(ext_wall_cond, {'boundary_condition' => 'Outdoors', 'surface' => 'Wall'}),
|
@@ -416,57 +108,12 @@ class NECB2020
|
|
416
108
|
tubular_daylight_diffuser_solar_trans: correct_vis_trans.call(tubular_daylight_diffuser_solar_trans),
|
417
109
|
tubular_daylight_diffuser_vis_trans: correct_vis_trans.call(tubular_daylight_diffuser_vis_trans)
|
418
110
|
)
|
419
|
-
|
420
|
-
|
421
111
|
end
|
422
112
|
# sets all surfaces to use default constructions sets except adiabatic, where it does a hard assignment of the interior wall construction type.
|
423
113
|
model.getPlanarSurfaces.sort.each(&:resetConstruction)
|
424
114
|
# if the default construction set is defined..try to assign the interior wall to the adiabatic surfaces
|
425
115
|
BTAP::Resources::Envelope.assign_interior_surface_construction_to_adiabatic_surfaces(model, nil)
|
426
116
|
BTAP.runner_register('Info', ' apply_standard_construction_properties was sucessful.', runner)
|
427
|
-
|
428
|
-
end
|
429
|
-
|
430
|
-
# Set all external surface conductances to NECB values.
|
431
|
-
# @author phylroy.lopez@nrcan.gc.ca
|
432
|
-
# @param surface [String]
|
433
|
-
# @param hdd [Float]
|
434
|
-
# @param is_radiant [Boolian]
|
435
|
-
# @param scaling_factor [Float]
|
436
|
-
# @return [String] surface as RSI
|
437
|
-
def set_necb_external_surface_conductance(surface, hdd, is_radiant = false, scaling_factor = 1.0)
|
438
|
-
conductance_value = 0
|
439
|
-
|
440
|
-
if surface.outsideBoundaryCondition.casecmp('outdoors').zero?
|
441
|
-
|
442
|
-
case surface.surfaceType.downcase
|
443
|
-
when 'wall'
|
444
|
-
conductance_value = @standards_data['conductances']['Wall'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
|
445
|
-
when 'floor'
|
446
|
-
conductance_value = @standards_data['conductances']['Floor'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
|
447
|
-
when 'roofceiling'
|
448
|
-
conductance_value = @standards_data['conductances']['Roof'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
|
449
|
-
end
|
450
|
-
if is_radiant
|
451
|
-
conductance_value *= 0.80
|
452
|
-
end
|
453
|
-
return BTAP::Geometry::Surfaces.set_surfaces_construction_conductance([surface], conductance_value)
|
454
|
-
end
|
455
|
-
|
456
|
-
if surface.outsideBoundaryCondition.downcase =~ /ground/
|
457
|
-
case surface.surfaceType.downcase
|
458
|
-
when 'wall'
|
459
|
-
conductance_value = @standards_data['conductances']['GroundWall'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
|
460
|
-
when 'floor'
|
461
|
-
conductance_value = @standards_data['conductances']['GroundFloor'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
|
462
|
-
when 'roofceiling'
|
463
|
-
conductance_value = @standards_data['conductances']['GroundRoof'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
|
464
|
-
end
|
465
|
-
if is_radiant
|
466
|
-
conductance_value *= 0.80
|
467
|
-
end
|
468
|
-
return BTAP::Geometry::Surfaces.set_surfaces_construction_conductance([surface], conductance_value)
|
469
|
-
end
|
470
117
|
end
|
471
118
|
|
472
119
|
# Set all external subsurfaces (doors, windows, skylights) to NECB values.
|
@@ -480,300 +127,12 @@ class NECB2020
|
|
480
127
|
case subsurface.subSurfaceType.downcase
|
481
128
|
when /window/
|
482
129
|
conductance_value = @standards_data['conductances']['Window'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
|
130
|
+
when /skylight/
|
131
|
+
conductance_value = @standards_data['conductances']['Skylight'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
|
483
132
|
when /door/
|
484
133
|
conductance_value = @standards_data['conductances']['Door'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
|
485
134
|
end
|
486
135
|
subsurface.setRSI(1 / conductance_value)
|
487
136
|
end
|
488
137
|
end
|
489
|
-
|
490
|
-
# Adds code-minimum constructions based on the building type
|
491
|
-
# as defined in the OpenStudio_Standards_construction_sets.json file.
|
492
|
-
# Where there is a separate construction set specified for the
|
493
|
-
# individual space type, this construction set will be created and applied
|
494
|
-
# to this space type, overriding the whole-building construction set.
|
495
|
-
#
|
496
|
-
# @param building_type [String] the type of building
|
497
|
-
# @param climate_zone [String] the name of the climate zone the building is in
|
498
|
-
# @return [Bool] returns true if successful, false if not
|
499
|
-
def model_add_constructions(model)
|
500
|
-
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started applying constructions')
|
501
|
-
|
502
|
-
# Assign construction to adiabatic construction
|
503
|
-
# Assign a material to all internal mass objects
|
504
|
-
assign_contruction_to_adiabatic_surfaces(model)
|
505
|
-
# The constructions lookup table uses a slightly different list of
|
506
|
-
# building types.
|
507
|
-
apply_building_default_constructionset(model)
|
508
|
-
# Make a construction set for each space type, if one is specified
|
509
|
-
# apply_default_constructionsets_to_spacetypes(climate_zone, model)
|
510
|
-
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished applying constructions')
|
511
|
-
return true
|
512
|
-
end
|
513
|
-
|
514
|
-
def apply_building_default_constructionset(model)
|
515
|
-
|
516
|
-
bldg_def_const_set = model_add_construction_set_from_osm(model: model)
|
517
|
-
model.getBuilding.setDefaultConstructionSet(bldg_def_const_set)
|
518
|
-
|
519
|
-
end
|
520
|
-
|
521
|
-
def apply_default_constructionsets_to_spacetypes(climate_zone, model)
|
522
|
-
model.getSpaceTypes.sort.each do |space_type|
|
523
|
-
# Get the standards building type
|
524
|
-
stds_building_type = nil
|
525
|
-
if space_type.standardsBuildingType.is_initialized
|
526
|
-
stds_building_type = space_type.standardsBuildingType.get
|
527
|
-
else
|
528
|
-
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Space type called '#{space_type.name}' has no standards building type.")
|
529
|
-
end
|
530
|
-
|
531
|
-
# Get the standards space type
|
532
|
-
stds_spc_type = nil
|
533
|
-
if space_type.standardsSpaceType.is_initialized
|
534
|
-
stds_spc_type = space_type.standardsSpaceType.get
|
535
|
-
else
|
536
|
-
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Space type called '#{space_type.name}' has no standards space type.")
|
537
|
-
end
|
538
|
-
|
539
|
-
# If the standards space type is Attic,
|
540
|
-
# the building type should be blank.
|
541
|
-
if stds_spc_type == 'Attic'
|
542
|
-
stds_building_type = ''
|
543
|
-
end
|
544
|
-
|
545
|
-
# Attempt to make a construction set for this space type
|
546
|
-
# and assign it if it can be created.
|
547
|
-
spc_type_const_set = model_add_construction_set_from_osm(model: model)
|
548
|
-
if spc_type_const_set.is_initialized
|
549
|
-
space_type.setDefaultConstructionSet(spc_type_const_set.get)
|
550
|
-
end
|
551
|
-
end
|
552
|
-
end
|
553
|
-
|
554
|
-
def model_add_construction_set_from_osm(model:,
|
555
|
-
construction_set_name: 'BTAP-Mass',
|
556
|
-
osm_path: File.absolute_path(File.join(__FILE__, '..', '..', 'common/construction_defaults.osm')))
|
557
|
-
# load resources model
|
558
|
-
construction_library = BTAP::FileIO::load_osm(osm_path)
|
559
|
-
|
560
|
-
if not construction_library.getDefaultConstructionSetByName(construction_set_name.to_s).is_initialized
|
561
|
-
runner.registerError('Did not find the expected construction in library.')
|
562
|
-
return false
|
563
|
-
end
|
564
|
-
selected_construction_set = construction_library.getDefaultConstructionSetByName(construction_set_name.to_s).get
|
565
|
-
new_construction_set = selected_construction_set.clone(model).to_DefaultConstructionSet.get
|
566
|
-
return new_construction_set
|
567
|
-
end
|
568
|
-
|
569
|
-
def assign_contruction_to_adiabatic_surfaces(model)
|
570
|
-
cp02_carpet_pad = OpenStudio::Model::MasslessOpaqueMaterial.new(model)
|
571
|
-
cp02_carpet_pad.setName('CP02 CARPET PAD')
|
572
|
-
cp02_carpet_pad.setRoughness('VeryRough')
|
573
|
-
cp02_carpet_pad.setThermalResistance(0.21648)
|
574
|
-
cp02_carpet_pad.setThermalAbsorptance(0.9)
|
575
|
-
cp02_carpet_pad.setSolarAbsorptance(0.7)
|
576
|
-
cp02_carpet_pad.setVisibleAbsorptance(0.8)
|
577
|
-
|
578
|
-
normalweight_concrete_floor = OpenStudio::Model::StandardOpaqueMaterial.new(model)
|
579
|
-
normalweight_concrete_floor.setName('100mm Normalweight concrete floor')
|
580
|
-
normalweight_concrete_floor.setRoughness('MediumSmooth')
|
581
|
-
normalweight_concrete_floor.setThickness(0.1016)
|
582
|
-
normalweight_concrete_floor.setConductivity(2.31)
|
583
|
-
normalweight_concrete_floor.setDensity(2322)
|
584
|
-
normalweight_concrete_floor.setSpecificHeat(832)
|
585
|
-
|
586
|
-
nonres_floor_insulation = OpenStudio::Model::MasslessOpaqueMaterial.new(model)
|
587
|
-
nonres_floor_insulation.setName('Nonres_Floor_Insulation')
|
588
|
-
nonres_floor_insulation.setRoughness('MediumSmooth')
|
589
|
-
nonres_floor_insulation.setThermalResistance(2.88291975297193)
|
590
|
-
nonres_floor_insulation.setThermalAbsorptance(0.9)
|
591
|
-
nonres_floor_insulation.setSolarAbsorptance(0.7)
|
592
|
-
nonres_floor_insulation.setVisibleAbsorptance(0.7)
|
593
|
-
|
594
|
-
floor_adiabatic_construction = OpenStudio::Model::Construction.new(model)
|
595
|
-
floor_adiabatic_construction.setName('Floor Adiabatic construction')
|
596
|
-
floor_layers = OpenStudio::Model::MaterialVector.new
|
597
|
-
floor_layers << cp02_carpet_pad
|
598
|
-
floor_layers << normalweight_concrete_floor
|
599
|
-
floor_layers << nonres_floor_insulation
|
600
|
-
floor_adiabatic_construction.setLayers(floor_layers)
|
601
|
-
|
602
|
-
g01_13mm_gypsum_board = OpenStudio::Model::StandardOpaqueMaterial.new(model)
|
603
|
-
g01_13mm_gypsum_board.setName('G01 13mm gypsum board')
|
604
|
-
g01_13mm_gypsum_board.setRoughness('Smooth')
|
605
|
-
g01_13mm_gypsum_board.setThickness(0.0127)
|
606
|
-
g01_13mm_gypsum_board.setConductivity(0.1600)
|
607
|
-
g01_13mm_gypsum_board.setDensity(800)
|
608
|
-
g01_13mm_gypsum_board.setSpecificHeat(1090)
|
609
|
-
g01_13mm_gypsum_board.setThermalAbsorptance(0.9)
|
610
|
-
g01_13mm_gypsum_board.setSolarAbsorptance(0.7)
|
611
|
-
g01_13mm_gypsum_board.setVisibleAbsorptance(0.5)
|
612
|
-
|
613
|
-
wall_adiabatic_construction = OpenStudio::Model::Construction.new(model)
|
614
|
-
wall_adiabatic_construction.setName('Wall Adiabatic construction')
|
615
|
-
wall_layers = OpenStudio::Model::MaterialVector.new
|
616
|
-
wall_layers << g01_13mm_gypsum_board
|
617
|
-
wall_layers << g01_13mm_gypsum_board
|
618
|
-
wall_adiabatic_construction.setLayers(wall_layers)
|
619
|
-
|
620
|
-
m10_200mm_concrete_block_basement_wall = OpenStudio::Model::StandardOpaqueMaterial.new(model)
|
621
|
-
m10_200mm_concrete_block_basement_wall.setName('M10 200mm concrete block basement wall')
|
622
|
-
m10_200mm_concrete_block_basement_wall.setRoughness('MediumRough')
|
623
|
-
m10_200mm_concrete_block_basement_wall.setThickness(0.2032)
|
624
|
-
m10_200mm_concrete_block_basement_wall.setConductivity(1.326)
|
625
|
-
m10_200mm_concrete_block_basement_wall.setDensity(1842)
|
626
|
-
m10_200mm_concrete_block_basement_wall.setSpecificHeat(912)
|
627
|
-
|
628
|
-
basement_wall_construction = OpenStudio::Model::Construction.new(model)
|
629
|
-
basement_wall_construction.setName('Basement Wall construction')
|
630
|
-
basement_wall_layers = OpenStudio::Model::MaterialVector.new
|
631
|
-
basement_wall_layers << m10_200mm_concrete_block_basement_wall
|
632
|
-
basement_wall_construction.setLayers(basement_wall_layers)
|
633
|
-
|
634
|
-
basement_floor_construction = OpenStudio::Model::Construction.new(model)
|
635
|
-
basement_floor_construction.setName('Basement Floor construction')
|
636
|
-
basement_floor_layers = OpenStudio::Model::MaterialVector.new
|
637
|
-
basement_floor_layers << m10_200mm_concrete_block_basement_wall
|
638
|
-
basement_floor_layers << cp02_carpet_pad
|
639
|
-
basement_floor_construction.setLayers(basement_floor_layers)
|
640
|
-
|
641
|
-
model.getSurfaces.sort.each do |surface|
|
642
|
-
if surface.outsideBoundaryCondition.to_s == 'Adiabatic'
|
643
|
-
if surface.surfaceType.to_s == 'Wall'
|
644
|
-
surface.setConstruction(wall_adiabatic_construction)
|
645
|
-
else
|
646
|
-
surface.setConstruction(floor_adiabatic_construction)
|
647
|
-
end
|
648
|
-
elsif surface.outsideBoundaryCondition.to_s == 'OtherSideCoefficients'
|
649
|
-
# Ground
|
650
|
-
if surface.surfaceType.to_s == 'Wall'
|
651
|
-
surface.setOutsideBoundaryCondition('Ground')
|
652
|
-
surface.setConstruction(basement_wall_construction)
|
653
|
-
else
|
654
|
-
surface.setOutsideBoundaryCondition('Ground')
|
655
|
-
surface.setConstruction(basement_floor_construction)
|
656
|
-
end
|
657
|
-
end
|
658
|
-
end
|
659
|
-
end
|
660
|
-
|
661
|
-
def scale_model_geometry(model, x_scale, y_scale, z_scale)
|
662
|
-
# Identity matrix for setting space origins
|
663
|
-
m = OpenStudio::Matrix.new(4, 4, 0)
|
664
|
-
|
665
|
-
m[0, 0] = 1.0 / x_scale
|
666
|
-
m[1, 1] = 1.0 / y_scale
|
667
|
-
m[2, 2] = 1.0 / z_scale
|
668
|
-
m[3, 3] = 1.0
|
669
|
-
t = OpenStudio::Transformation.new(m)
|
670
|
-
model.getPlanarSurfaceGroups().each do |planar_surface|
|
671
|
-
planar_surface.changeTransformation(t)
|
672
|
-
end
|
673
|
-
return model
|
674
|
-
end
|
675
|
-
|
676
|
-
# This method applies the maximum fenestration and door to wall ratio to a building as per NECB 2011 8.4.4.3 and
|
677
|
-
# 3.2.1.4 (or equivalent in other versions of the NECB). It first checks for al exterior walls adjacent to conditioned
|
678
|
-
# spaces. It distinguishes between plenums and other conditioned spaces. It uses both to calculate the maximum window
|
679
|
-
# area to be applied to the building but attempts to put these windows only on non-plenum conditioned spaces (if
|
680
|
-
# possible).
|
681
|
-
def apply_max_fdwr_nrcan(model:, fdwr_lim:)
|
682
|
-
# First determine which vertical (between 89 and 91 degrees from horizontal) walls are adjacent to conditioned
|
683
|
-
# spaces.
|
684
|
-
exp_surf_info = find_exposed_conditioned_vertical_surfaces(model)
|
685
|
-
# If there are none (or very few) then throw a warning.
|
686
|
-
if exp_surf_info["total_exp_wall_area_m2"] < 0.1
|
687
|
-
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.model.Model', "This building has no exposed walls adjacent to heated spaces.")
|
688
|
-
return false
|
689
|
-
end
|
690
|
-
|
691
|
-
construct_set = model.getBuilding.defaultConstructionSet.get
|
692
|
-
fixed_window_construct_set = construct_set.defaultExteriorSubSurfaceConstructions.get.fixedWindowConstruction.get
|
693
|
-
|
694
|
-
# IF FDWR is greater than 1 then something is wrong raise an error. If it is less than 0.001 assume all the windows
|
695
|
-
# should go.
|
696
|
-
if fdwr_lim > 1
|
697
|
-
OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "This building requires a larger window area than there is wall area.")
|
698
|
-
return false
|
699
|
-
elsif fdwr_lim < 0.001
|
700
|
-
exp_surf_info["exp_nonplenum_walls"].sort.each do |exp_surf|
|
701
|
-
remove_All_Subsurfaces(surface: exp_surf)
|
702
|
-
end
|
703
|
-
return true
|
704
|
-
end
|
705
|
-
# Get the required window area.
|
706
|
-
win_area = fdwr_lim * exp_surf_info["total_exp_wall_area_m2"]
|
707
|
-
# Try to put the windows on non-plenum walls if possible. So determine if you can fit the required window area
|
708
|
-
# on the non-plenum wall area.
|
709
|
-
if win_area <= exp_surf_info["exp_nonplenum_wall_area_m2"]
|
710
|
-
# If you can fit the windows on the non-plenum wall area then recalculate the window ratio so that is is only for
|
711
|
-
# the non-plenum walls.
|
712
|
-
nonplenum_fdwr = win_area / exp_surf_info["exp_nonplenum_wall_area_m2"]
|
713
|
-
exp_surf_info["exp_nonplenum_walls"].sort.each do |exp_surf|
|
714
|
-
# Remove any subsurfaces, add the window, set the name to be whatever the surface name is plus the subsurface
|
715
|
-
# type (which will be 'fixedwindow')
|
716
|
-
remove_All_Subsurfaces(surface: exp_surf)
|
717
|
-
set_Window_To_Wall_Ratio_set_name(surface: exp_surf, area_fraction: nonplenum_fdwr, construction: fixed_window_construct_set)
|
718
|
-
end
|
719
|
-
else
|
720
|
-
# There was not enough non-plenum wall area so add the windows to both the plenum and non-plenum walls. This is
|
721
|
-
# done separately because the 'find_exposed_conditioned_vertical_surfaces' method returns the plenum and
|
722
|
-
# non-plenum walls separately.
|
723
|
-
exp_surf_info["exp_nonplenum_walls"].sort.each do |exp_surf|
|
724
|
-
# Remove any subsurfaces, add the window, set the name to be whatever the surface name is plus the subsurface
|
725
|
-
# type (which will be 'fixedwindow')
|
726
|
-
remove_All_Subsurfaces(surface: exp_surf)
|
727
|
-
set_Window_To_Wall_Ratio_set_name(surface: exp_surf, area_fraction: fdwr_lim, construction: fixed_window_construct_set)
|
728
|
-
end
|
729
|
-
exp_surf_info["exp_plenum_walls"].sort.each do |exp_surf|
|
730
|
-
# Remove any subsurfaces, add the window, set the name to be whatever the surface name is plus the subsurface
|
731
|
-
# type (which will be 'fixedwindow')
|
732
|
-
remove_All_Subsurfaces(surface: exp_surf)
|
733
|
-
set_Window_To_Wall_Ratio_set_name(surface: exp_surf, area_fraction: fdwr_lim, construction: fixed_window_construct_set)
|
734
|
-
end
|
735
|
-
end
|
736
|
-
return true
|
737
|
-
end
|
738
|
-
|
739
|
-
# This method is similar to the 'apply_max_fdwr' method above but applies the maximum skylight to roof area ratio to a
|
740
|
-
# building as per NECB 2011 8.4.4.3 and 3.2.1.4 (or equivalent in other versions of the NECB). It first checks for all
|
741
|
-
# exterior roofs adjacent to conditioned spaces. It distinguishes between plenums and other conditioned spaces. It
|
742
|
-
# uses only the non-plenum roof area to calculate the maximum skylight area to be applied to the building.
|
743
|
-
def apply_max_srr_nrcan(model:, srr_lim:)
|
744
|
-
# First determine which roof surfaces are adjacent to heated spaces (both plenum and non-plenum).
|
745
|
-
exp_surf_info = find_exposed_conditioned_roof_surfaces(model)
|
746
|
-
# If the non-plenum roof area is very small raise a warning. It may be perfectly fine but it is probably a good
|
747
|
-
# idea to warn the user.
|
748
|
-
if exp_surf_info["exp_nonplenum_roof_area_m2"] < 0.1
|
749
|
-
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "This building has no exposed ceilings adjacent to spaces that are not attics or plenums. No skylights will be added.")
|
750
|
-
return false
|
751
|
-
end
|
752
|
-
|
753
|
-
# If the SRR is greater than one something is seriously wrong so raise an error. If it is less than 0.001 assume
|
754
|
-
# all the skylights should go.
|
755
|
-
if srr_lim > 1
|
756
|
-
OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "This building requires a larger skylight area than there is roof area.")
|
757
|
-
return false
|
758
|
-
elsif srr_lim < 0.001
|
759
|
-
exp_surf_info["exp_nonplenum_roofs"].sort.each do |exp_surf|
|
760
|
-
remove_All_Subsurfaces(surface: exp_surf)
|
761
|
-
end
|
762
|
-
return true
|
763
|
-
end
|
764
|
-
|
765
|
-
construct_set = model.getBuilding.defaultConstructionSet.get
|
766
|
-
skylight_construct_set = construct_set.defaultExteriorSubSurfaceConstructions.get.skylightConstruction.get
|
767
|
-
|
768
|
-
# Go through all of exposed roofs adjacent to heated, non-plenum spaces, remove any existing subsurfaces, and add
|
769
|
-
# a skylight in the centroid of the surface, with the same shape of the surface, only scaled to be the area
|
770
|
-
# determined by the SRR. The name of the skylight will be the surface name with the subsurface type attached
|
771
|
-
# ('skylight' in this case). Note that this method will only work if the surface does not fold into itself (like an
|
772
|
-
# L or a V).
|
773
|
-
exp_surf_info["exp_nonplenum_roofs"].sort.each do |roof|
|
774
|
-
# sub_surface_create_centered_subsurface_from_scaled_surface(roof, srr_lim, model)
|
775
|
-
sub_surface_create_scaled_subsurfaces_from_surface(surface: roof, area_fraction: srr_lim, model: model, consturction: skylight_construct_set)
|
776
|
-
end
|
777
|
-
return true
|
778
|
-
end
|
779
|
-
end
|
138
|
+
end
|