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,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
|