openstudio-extension 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +29 -26
- data/.rspec +3 -3
- data/.rubocop.yml +10 -9
- data/CHANGELOG.md +16 -0
- data/Gemfile +6 -6
- data/Jenkinsfile +10 -10
- data/README.md +251 -250
- data/Rakefile +119 -119
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/doc_templates/LICENSE.md +26 -26
- data/doc_templates/README.md.erb +41 -41
- data/doc_templates/copyright_erb.txt +35 -35
- data/doc_templates/copyright_js.txt +3 -3
- data/doc_templates/copyright_ruby.txt +33 -33
- data/init_templates/README.md +37 -37
- data/init_templates/gemspec.txt +32 -32
- data/init_templates/openstudio_module.rb +50 -50
- data/init_templates/spec.rb +47 -47
- data/init_templates/spec_helper.rb +49 -49
- data/init_templates/template_gemfile.txt +17 -17
- data/init_templates/template_rakefile.txt +15 -15
- data/init_templates/version.rb +40 -40
- data/lib/files/openstudio-extension-gem-test.ddy +536 -536
- data/lib/files/openstudio-extension-gem-test.epw +8768 -8768
- data/lib/files/openstudio-extension-gem-test.stat +554 -554
- data/lib/measures/openstudio_extension_test_measure/LICENSE.md +26 -26
- data/lib/measures/openstudio_extension_test_measure/README.md +26 -26
- data/lib/measures/openstudio_extension_test_measure/README.md.erb +41 -41
- data/lib/measures/openstudio_extension_test_measure/measure.rb +72 -72
- data/lib/measures/openstudio_extension_test_measure/measure.xml +83 -83
- data/lib/measures/openstudio_extension_test_measure/resources/os_lib_helper_methods.rb +399 -399
- data/lib/measures/openstudio_extension_test_measure/tests/{OpenStudioExtensionTestMeasure_Test.rb → openstudio_extension_test_measure_test.rb} +74 -75
- data/lib/openstudio-extension.rb +1 -1
- data/lib/openstudio/extension.rb +234 -229
- data/lib/openstudio/extension/core/CreateResults.rb +886 -886
- data/lib/openstudio/extension/core/check_air_sys_temps.rb +190 -190
- data/lib/openstudio/extension/core/check_calibration.rb +155 -155
- data/lib/openstudio/extension/core/check_cond_zns.rb +84 -84
- data/lib/openstudio/extension/core/check_domestic_hot_water.rb +334 -334
- data/lib/openstudio/extension/core/check_envelope_conductance.rb +453 -453
- data/lib/openstudio/extension/core/check_eui_by_end_use.rb +162 -162
- data/lib/openstudio/extension/core/check_eui_reasonableness.rb +135 -135
- data/lib/openstudio/extension/core/check_fan_pwr.rb +98 -98
- data/lib/openstudio/extension/core/check_internal_loads.rb +393 -393
- data/lib/openstudio/extension/core/check_mech_sys_capacity.rb +226 -226
- data/lib/openstudio/extension/core/check_mech_sys_efficiency.rb +326 -326
- data/lib/openstudio/extension/core/check_mech_sys_part_load_eff.rb +464 -464
- data/lib/openstudio/extension/core/check_mech_sys_type.rb +139 -139
- data/lib/openstudio/extension/core/check_part_loads.rb +451 -451
- data/lib/openstudio/extension/core/check_placeholder.rb +75 -75
- data/lib/openstudio/extension/core/check_plant_cap.rb +123 -123
- data/lib/openstudio/extension/core/check_plant_temps.rb +159 -159
- data/lib/openstudio/extension/core/check_plenum_loads.rb +87 -87
- data/lib/openstudio/extension/core/check_pump_pwr.rb +108 -108
- data/lib/openstudio/extension/core/check_sch_coord.rb +241 -241
- data/lib/openstudio/extension/core/check_schedules.rb +311 -311
- data/lib/openstudio/extension/core/check_simultaneous_heating_and_cooling.rb +158 -158
- data/lib/openstudio/extension/core/check_supply_air_and_thermostat_temp_difference.rb +148 -148
- data/lib/openstudio/extension/core/check_weather_files.rb +132 -132
- data/lib/openstudio/extension/core/deer_vintages.rb +311 -311
- data/lib/openstudio/extension/core/os_lib_aedg_measures.rb +491 -491
- data/lib/openstudio/extension/core/os_lib_cofee.rb +258 -258
- data/lib/openstudio/extension/core/os_lib_constructions.rb +378 -378
- data/lib/openstudio/extension/core/os_lib_geometry.rb +1022 -1022
- data/lib/openstudio/extension/core/os_lib_helper_methods.rb +399 -399
- data/lib/openstudio/extension/core/os_lib_hvac.rb +2171 -2171
- data/lib/openstudio/extension/core/os_lib_lighting_and_equipment.rb +214 -214
- data/lib/openstudio/extension/core/os_lib_model_generation.rb +817 -817
- data/lib/openstudio/extension/core/os_lib_model_simplification.rb +1049 -1049
- data/lib/openstudio/extension/core/os_lib_outdoorair_and_infiltration.rb +165 -165
- data/lib/openstudio/extension/core/os_lib_reporting.rb +4651 -4651
- data/lib/openstudio/extension/core/os_lib_reporting_qaqc.rb +200 -200
- data/lib/openstudio/extension/core/os_lib_schedules.rb +963 -963
- data/lib/openstudio/extension/rake_task.rb +159 -149
- data/lib/openstudio/extension/runner.rb +667 -644
- data/lib/openstudio/extension/runner_config.rb +114 -0
- data/lib/openstudio/extension/version.rb +40 -40
- data/openstudio-extension.gemspec +34 -33
- metadata +39 -37
@@ -1,214 +1,214 @@
|
|
1
|
-
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
|
3
|
-
# All rights reserved.
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are met:
|
6
|
-
#
|
7
|
-
# (1) Redistributions of source code must retain the above copyright notice,
|
8
|
-
# this list of conditions and the following disclaimer.
|
9
|
-
#
|
10
|
-
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
11
|
-
# this list of conditions and the following disclaimer in the documentation
|
12
|
-
# and/or other materials provided with the distribution.
|
13
|
-
#
|
14
|
-
# (3) Neither the name of the copyright holder nor the names of any contributors
|
15
|
-
# may be used to endorse or promote products derived from this software without
|
16
|
-
# specific prior written permission from the respective party.
|
17
|
-
#
|
18
|
-
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
19
|
-
# of modifications or other derivative works may not use the "OpenStudio"
|
20
|
-
# trademark, "OS", "os", or any other confusingly similar designation without
|
21
|
-
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
22
|
-
#
|
23
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
|
24
|
-
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
25
|
-
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26
|
-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
|
27
|
-
# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
|
28
|
-
# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
29
|
-
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
30
|
-
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
31
|
-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
32
|
-
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
33
|
-
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
-
# *******************************************************************************
|
35
|
-
|
36
|
-
require "#{File.dirname(__FILE__)}/os_lib_schedules"
|
37
|
-
|
38
|
-
# load OpenStudio measure libraries
|
39
|
-
module OsLib_LightingAndEquipment
|
40
|
-
include OsLib_Schedules
|
41
|
-
|
42
|
-
# return min ans max from array
|
43
|
-
def self.getExteriorLightsValue(model)
|
44
|
-
facility = model.getFacility
|
45
|
-
exterior_lights_power = 0
|
46
|
-
exterior_lights = facility.exteriorLights
|
47
|
-
exterior_lights.each do |exterior_light|
|
48
|
-
exterior_light_multiplier = exterior_light.multiplier
|
49
|
-
exterior_light_def = exterior_light.exteriorLightsDefinition
|
50
|
-
exterior_light_base_power = exterior_light_def.designLevel
|
51
|
-
exterior_lights_power += exterior_light_base_power * exterior_light_multiplier
|
52
|
-
end
|
53
|
-
|
54
|
-
result = { 'exterior_lighting_power' => exterior_lights_power, 'exterior_lights' => exterior_lights }
|
55
|
-
return result
|
56
|
-
end
|
57
|
-
|
58
|
-
# return min ans max from array
|
59
|
-
def self.removeAllExteriorLights(model, runner)
|
60
|
-
facility = model.getFacility
|
61
|
-
lightsRemoved = false
|
62
|
-
exterior_lights = facility.exteriorLights
|
63
|
-
exterior_lights.each do |exterior_light|
|
64
|
-
runner.registerInfo("Removed exterior light named #{exterior_light.name}.")
|
65
|
-
exterior_light.remove
|
66
|
-
lightsRemoved = true
|
67
|
-
end
|
68
|
-
|
69
|
-
result = lightsRemoved
|
70
|
-
return result
|
71
|
-
end
|
72
|
-
|
73
|
-
# return min ans max from array
|
74
|
-
def self.addExteriorLights(model, runner, options = {})
|
75
|
-
# set defaults to use if user inputs not passed in
|
76
|
-
defaults = {
|
77
|
-
'name' => 'Exterior Light',
|
78
|
-
'power' => 0,
|
79
|
-
'subCategory' => 'Exterior Lighting',
|
80
|
-
'controlOption' => 'AstronomicalClock',
|
81
|
-
'setbackStartTime' => 0,
|
82
|
-
'setbackEndTime' => 0,
|
83
|
-
'setbackFraction' => 0.25
|
84
|
-
}
|
85
|
-
|
86
|
-
# merge user inputs with defaults
|
87
|
-
options = defaults.merge(options)
|
88
|
-
|
89
|
-
ext_lights_def = OpenStudio::Model::ExteriorLightsDefinition.new(model)
|
90
|
-
ext_lights_def.setName("#{options['name']} Definition")
|
91
|
-
runner.registerInfo("Setting #{ext_lights_def.name} to a design power of #{options['power']} Watts")
|
92
|
-
ext_lights_def.setDesignLevel(options['power'])
|
93
|
-
|
94
|
-
# creating schedule type limits for the exterior lights schedule
|
95
|
-
ext_lights_sch_type_limits = OpenStudio::Model::ScheduleTypeLimits.new(model)
|
96
|
-
ext_lights_sch_type_limits.setName("#{options['name']} Fractional")
|
97
|
-
ext_lights_sch_type_limits.setLowerLimitValue(0)
|
98
|
-
ext_lights_sch_type_limits.setUpperLimitValue(1)
|
99
|
-
ext_lights_sch_type_limits.setNumericType('Continuous')
|
100
|
-
|
101
|
-
# prepare values for profile
|
102
|
-
if options['setbackStartTime'] == 24
|
103
|
-
profile = { options['setbackEndTime'] => options['setbackFraction'], 24.0 => 1.0 }
|
104
|
-
elsif options['setbackStartTime'] == 0
|
105
|
-
profile = { options['setbackEndTime'] => options['setbackFraction'], 24.0 => 1.0 }
|
106
|
-
elsif options['setbackStartTime'] > options['setbackEndTime']
|
107
|
-
profile = { options['setbackEndTime'] => options['setbackFraction'], options['setbackStartTime'] => 1.0, 24.0 => options['setbackFraction'] }
|
108
|
-
else
|
109
|
-
profile = { options['setbackStartTime'] => 1.0, options['setbackEndTime'] => options['setbackFraction'] }
|
110
|
-
end
|
111
|
-
|
112
|
-
# inputs
|
113
|
-
createSimpleSchedule_inputs = {
|
114
|
-
'name' => options['name'],
|
115
|
-
'winterTimeValuePairs' => profile,
|
116
|
-
'summerTimeValuePairs' => profile,
|
117
|
-
'defaultTimeValuePairs' => profile
|
118
|
-
}
|
119
|
-
|
120
|
-
# create a ruleset schedule with a basic profile
|
121
|
-
ext_lights_sch = OsLib_Schedules.createSimpleSchedule(model, createSimpleSchedule_inputs)
|
122
|
-
|
123
|
-
# creating exterior lights object
|
124
|
-
ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def, ext_lights_sch)
|
125
|
-
ext_lights.setName("#{options['power']} w Exterior Light")
|
126
|
-
ext_lights.setControlOption(options['controlOption'])
|
127
|
-
ext_lights.setEndUseSubcategory(options['subCategory'])
|
128
|
-
|
129
|
-
result = ext_lights
|
130
|
-
return result
|
131
|
-
end
|
132
|
-
|
133
|
-
# add daylight sensor
|
134
|
-
def self.addDaylightSensor(model, options = {})
|
135
|
-
# set defaults to use if user inputs not passed in
|
136
|
-
defaults = {
|
137
|
-
'name' => nil,
|
138
|
-
'space' => nil,
|
139
|
-
'position' => nil,
|
140
|
-
'phiRotationAroundZAxis' => nil,
|
141
|
-
'illuminanceSetpoint' => nil,
|
142
|
-
'lightingControlType' => '1', # 1 = Continuous
|
143
|
-
'minInputPowerFractionContinuous' => nil,
|
144
|
-
'minOutputPowerFractionContinuous' => nil,
|
145
|
-
'numberOfSteppedControlSteps' => nil
|
146
|
-
}
|
147
|
-
|
148
|
-
# merge user inputs with defaults
|
149
|
-
options = defaults.merge(options)
|
150
|
-
|
151
|
-
pri_light_sensor = OpenStudio::Model::DaylightingControl.new(model)
|
152
|
-
if !options['name'].nil? then pri_light_sensor.setName(options['name']) end
|
153
|
-
if !options['space'].nil? then pri_light_sensor.setSpace(options['space']) end
|
154
|
-
if !options['position'].nil? then pri_light_sensor.setPosition(options['position']) end
|
155
|
-
if !options['phiRotationAroundZAxis'].nil? then pri_light_sensor.setPhiRotationAroundZAxis(options['phiRotationAroundZAxis']) end
|
156
|
-
if !options['illuminanceSetpoint'].nil? then pri_light_sensor.setIlluminanceSetpoint(options['illuminanceSetpoint']) end
|
157
|
-
if !options['lightingControlType'].nil? then pri_light_sensor.setLightingControlType(options['lightingControlType']) end
|
158
|
-
|
159
|
-
result = pri_light_sensor
|
160
|
-
return result
|
161
|
-
end
|
162
|
-
|
163
|
-
# make hash of hard assigned schedules with lighting levels
|
164
|
-
def self.createHashOfInternalLoadWithHardAssignedSchedules(internalLoadArray)
|
165
|
-
hardAssignedScheduleHash = {}
|
166
|
-
internalLoadArray.each do |load|
|
167
|
-
if !load.isScheduleDefaulted
|
168
|
-
# add to schedule hash
|
169
|
-
if !load.schedule.empty?
|
170
|
-
if !(hardAssignedScheduleHash[load.schedule.get])
|
171
|
-
hardAssignedScheduleHash[load.schedule.get] = 1
|
172
|
-
else
|
173
|
-
hardAssignedScheduleHash[load.schedule.get] += 1 # this is to catch multiple objects instances using the same hard assigned schedule
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
result = hardAssignedScheduleHash
|
180
|
-
return result
|
181
|
-
end
|
182
|
-
|
183
|
-
# get value per area for electric equipment loads in space array.
|
184
|
-
def self.getEpdForSpaceArray(spaceArray)
|
185
|
-
floorArea = 0
|
186
|
-
electricEquipmentPower = 0
|
187
|
-
|
188
|
-
spaceArray.each do |space|
|
189
|
-
floorArea += space.floorArea * space.multiplier
|
190
|
-
electricEquipmentPower += space.electricEquipmentPower * space.multiplier
|
191
|
-
end
|
192
|
-
|
193
|
-
epd = electricEquipmentPower / floorArea
|
194
|
-
|
195
|
-
result = epd
|
196
|
-
return result
|
197
|
-
end
|
198
|
-
|
199
|
-
# get value per area for electric equipment loads in space array.
|
200
|
-
def self.getLpdForSpaceArray(spaceArray)
|
201
|
-
floorArea = 0
|
202
|
-
lightingPower = 0
|
203
|
-
|
204
|
-
spaceArray.each do |space|
|
205
|
-
floorArea += space.floorArea * space.multiplier
|
206
|
-
lightingPower += space.lightingPower * space.multiplier
|
207
|
-
end
|
208
|
-
|
209
|
-
lpd = lightingPower / floorArea
|
210
|
-
|
211
|
-
result = lpd
|
212
|
-
return result
|
213
|
-
end
|
214
|
-
end
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
|
3
|
+
# All rights reserved.
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# (1) Redistributions of source code must retain the above copyright notice,
|
8
|
+
# this list of conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
#
|
14
|
+
# (3) Neither the name of the copyright holder nor the names of any contributors
|
15
|
+
# may be used to endorse or promote products derived from this software without
|
16
|
+
# specific prior written permission from the respective party.
|
17
|
+
#
|
18
|
+
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
19
|
+
# of modifications or other derivative works may not use the "OpenStudio"
|
20
|
+
# trademark, "OS", "os", or any other confusingly similar designation without
|
21
|
+
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
|
24
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
25
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
|
27
|
+
# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
|
28
|
+
# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
29
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
30
|
+
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
31
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
32
|
+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
33
|
+
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
# *******************************************************************************
|
35
|
+
|
36
|
+
require "#{File.dirname(__FILE__)}/os_lib_schedules"
|
37
|
+
|
38
|
+
# load OpenStudio measure libraries
|
39
|
+
module OsLib_LightingAndEquipment
|
40
|
+
include OsLib_Schedules
|
41
|
+
|
42
|
+
# return min ans max from array
|
43
|
+
def self.getExteriorLightsValue(model)
|
44
|
+
facility = model.getFacility
|
45
|
+
exterior_lights_power = 0
|
46
|
+
exterior_lights = facility.exteriorLights
|
47
|
+
exterior_lights.each do |exterior_light|
|
48
|
+
exterior_light_multiplier = exterior_light.multiplier
|
49
|
+
exterior_light_def = exterior_light.exteriorLightsDefinition
|
50
|
+
exterior_light_base_power = exterior_light_def.designLevel
|
51
|
+
exterior_lights_power += exterior_light_base_power * exterior_light_multiplier
|
52
|
+
end
|
53
|
+
|
54
|
+
result = { 'exterior_lighting_power' => exterior_lights_power, 'exterior_lights' => exterior_lights }
|
55
|
+
return result
|
56
|
+
end
|
57
|
+
|
58
|
+
# return min ans max from array
|
59
|
+
def self.removeAllExteriorLights(model, runner)
|
60
|
+
facility = model.getFacility
|
61
|
+
lightsRemoved = false
|
62
|
+
exterior_lights = facility.exteriorLights
|
63
|
+
exterior_lights.each do |exterior_light|
|
64
|
+
runner.registerInfo("Removed exterior light named #{exterior_light.name}.")
|
65
|
+
exterior_light.remove
|
66
|
+
lightsRemoved = true
|
67
|
+
end
|
68
|
+
|
69
|
+
result = lightsRemoved
|
70
|
+
return result
|
71
|
+
end
|
72
|
+
|
73
|
+
# return min ans max from array
|
74
|
+
def self.addExteriorLights(model, runner, options = {})
|
75
|
+
# set defaults to use if user inputs not passed in
|
76
|
+
defaults = {
|
77
|
+
'name' => 'Exterior Light',
|
78
|
+
'power' => 0,
|
79
|
+
'subCategory' => 'Exterior Lighting',
|
80
|
+
'controlOption' => 'AstronomicalClock',
|
81
|
+
'setbackStartTime' => 0,
|
82
|
+
'setbackEndTime' => 0,
|
83
|
+
'setbackFraction' => 0.25
|
84
|
+
}
|
85
|
+
|
86
|
+
# merge user inputs with defaults
|
87
|
+
options = defaults.merge(options)
|
88
|
+
|
89
|
+
ext_lights_def = OpenStudio::Model::ExteriorLightsDefinition.new(model)
|
90
|
+
ext_lights_def.setName("#{options['name']} Definition")
|
91
|
+
runner.registerInfo("Setting #{ext_lights_def.name} to a design power of #{options['power']} Watts")
|
92
|
+
ext_lights_def.setDesignLevel(options['power'])
|
93
|
+
|
94
|
+
# creating schedule type limits for the exterior lights schedule
|
95
|
+
ext_lights_sch_type_limits = OpenStudio::Model::ScheduleTypeLimits.new(model)
|
96
|
+
ext_lights_sch_type_limits.setName("#{options['name']} Fractional")
|
97
|
+
ext_lights_sch_type_limits.setLowerLimitValue(0)
|
98
|
+
ext_lights_sch_type_limits.setUpperLimitValue(1)
|
99
|
+
ext_lights_sch_type_limits.setNumericType('Continuous')
|
100
|
+
|
101
|
+
# prepare values for profile
|
102
|
+
if options['setbackStartTime'] == 24
|
103
|
+
profile = { options['setbackEndTime'] => options['setbackFraction'], 24.0 => 1.0 }
|
104
|
+
elsif options['setbackStartTime'] == 0
|
105
|
+
profile = { options['setbackEndTime'] => options['setbackFraction'], 24.0 => 1.0 }
|
106
|
+
elsif options['setbackStartTime'] > options['setbackEndTime']
|
107
|
+
profile = { options['setbackEndTime'] => options['setbackFraction'], options['setbackStartTime'] => 1.0, 24.0 => options['setbackFraction'] }
|
108
|
+
else
|
109
|
+
profile = { options['setbackStartTime'] => 1.0, options['setbackEndTime'] => options['setbackFraction'] }
|
110
|
+
end
|
111
|
+
|
112
|
+
# inputs
|
113
|
+
createSimpleSchedule_inputs = {
|
114
|
+
'name' => options['name'],
|
115
|
+
'winterTimeValuePairs' => profile,
|
116
|
+
'summerTimeValuePairs' => profile,
|
117
|
+
'defaultTimeValuePairs' => profile
|
118
|
+
}
|
119
|
+
|
120
|
+
# create a ruleset schedule with a basic profile
|
121
|
+
ext_lights_sch = OsLib_Schedules.createSimpleSchedule(model, createSimpleSchedule_inputs)
|
122
|
+
|
123
|
+
# creating exterior lights object
|
124
|
+
ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def, ext_lights_sch)
|
125
|
+
ext_lights.setName("#{options['power']} w Exterior Light")
|
126
|
+
ext_lights.setControlOption(options['controlOption'])
|
127
|
+
ext_lights.setEndUseSubcategory(options['subCategory'])
|
128
|
+
|
129
|
+
result = ext_lights
|
130
|
+
return result
|
131
|
+
end
|
132
|
+
|
133
|
+
# add daylight sensor
|
134
|
+
def self.addDaylightSensor(model, options = {})
|
135
|
+
# set defaults to use if user inputs not passed in
|
136
|
+
defaults = {
|
137
|
+
'name' => nil,
|
138
|
+
'space' => nil,
|
139
|
+
'position' => nil,
|
140
|
+
'phiRotationAroundZAxis' => nil,
|
141
|
+
'illuminanceSetpoint' => nil,
|
142
|
+
'lightingControlType' => '1', # 1 = Continuous
|
143
|
+
'minInputPowerFractionContinuous' => nil,
|
144
|
+
'minOutputPowerFractionContinuous' => nil,
|
145
|
+
'numberOfSteppedControlSteps' => nil
|
146
|
+
}
|
147
|
+
|
148
|
+
# merge user inputs with defaults
|
149
|
+
options = defaults.merge(options)
|
150
|
+
|
151
|
+
pri_light_sensor = OpenStudio::Model::DaylightingControl.new(model)
|
152
|
+
if !options['name'].nil? then pri_light_sensor.setName(options['name']) end
|
153
|
+
if !options['space'].nil? then pri_light_sensor.setSpace(options['space']) end
|
154
|
+
if !options['position'].nil? then pri_light_sensor.setPosition(options['position']) end
|
155
|
+
if !options['phiRotationAroundZAxis'].nil? then pri_light_sensor.setPhiRotationAroundZAxis(options['phiRotationAroundZAxis']) end
|
156
|
+
if !options['illuminanceSetpoint'].nil? then pri_light_sensor.setIlluminanceSetpoint(options['illuminanceSetpoint']) end
|
157
|
+
if !options['lightingControlType'].nil? then pri_light_sensor.setLightingControlType(options['lightingControlType']) end
|
158
|
+
|
159
|
+
result = pri_light_sensor
|
160
|
+
return result
|
161
|
+
end
|
162
|
+
|
163
|
+
# make hash of hard assigned schedules with lighting levels
|
164
|
+
def self.createHashOfInternalLoadWithHardAssignedSchedules(internalLoadArray)
|
165
|
+
hardAssignedScheduleHash = {}
|
166
|
+
internalLoadArray.each do |load|
|
167
|
+
if !load.isScheduleDefaulted
|
168
|
+
# add to schedule hash
|
169
|
+
if !load.schedule.empty?
|
170
|
+
if !(hardAssignedScheduleHash[load.schedule.get])
|
171
|
+
hardAssignedScheduleHash[load.schedule.get] = 1
|
172
|
+
else
|
173
|
+
hardAssignedScheduleHash[load.schedule.get] += 1 # this is to catch multiple objects instances using the same hard assigned schedule
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
result = hardAssignedScheduleHash
|
180
|
+
return result
|
181
|
+
end
|
182
|
+
|
183
|
+
# get value per area for electric equipment loads in space array.
|
184
|
+
def self.getEpdForSpaceArray(spaceArray)
|
185
|
+
floorArea = 0
|
186
|
+
electricEquipmentPower = 0
|
187
|
+
|
188
|
+
spaceArray.each do |space|
|
189
|
+
floorArea += space.floorArea * space.multiplier
|
190
|
+
electricEquipmentPower += space.electricEquipmentPower * space.multiplier
|
191
|
+
end
|
192
|
+
|
193
|
+
epd = electricEquipmentPower / floorArea
|
194
|
+
|
195
|
+
result = epd
|
196
|
+
return result
|
197
|
+
end
|
198
|
+
|
199
|
+
# get value per area for electric equipment loads in space array.
|
200
|
+
def self.getLpdForSpaceArray(spaceArray)
|
201
|
+
floorArea = 0
|
202
|
+
lightingPower = 0
|
203
|
+
|
204
|
+
spaceArray.each do |space|
|
205
|
+
floorArea += space.floorArea * space.multiplier
|
206
|
+
lightingPower += space.lightingPower * space.multiplier
|
207
|
+
end
|
208
|
+
|
209
|
+
lpd = lightingPower / floorArea
|
210
|
+
|
211
|
+
result = lpd
|
212
|
+
return result
|
213
|
+
end
|
214
|
+
end
|
@@ -1,817 +1,817 @@
|
|
1
|
-
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
|
3
|
-
# All rights reserved.
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are met:
|
6
|
-
#
|
7
|
-
# (1) Redistributions of source code must retain the above copyright notice,
|
8
|
-
# this list of conditions and the following disclaimer.
|
9
|
-
#
|
10
|
-
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
11
|
-
# this list of conditions and the following disclaimer in the documentation
|
12
|
-
# and/or other materials provided with the distribution.
|
13
|
-
#
|
14
|
-
# (3) Neither the name of the copyright holder nor the names of any contributors
|
15
|
-
# may be used to endorse or promote products derived from this software without
|
16
|
-
# specific prior written permission from the respective party.
|
17
|
-
#
|
18
|
-
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
19
|
-
# of modifications or other derivative works may not use the "OpenStudio"
|
20
|
-
# trademark, "OS", "os", or any other confusingly similar designation without
|
21
|
-
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
22
|
-
#
|
23
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
|
24
|
-
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
25
|
-
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26
|
-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
|
27
|
-
# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
|
28
|
-
# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
29
|
-
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
30
|
-
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
31
|
-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
32
|
-
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
33
|
-
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
-
# *******************************************************************************
|
35
|
-
|
36
|
-
module OsLib_ModelGeneration
|
37
|
-
# simple list of building types that are valid for get_space_types_from_building_type
|
38
|
-
def get_building_types
|
39
|
-
array = OpenStudio::StringVector.new
|
40
|
-
array << 'SecondarySchool'
|
41
|
-
array << 'PrimarySchool'
|
42
|
-
array << 'SmallOffice'
|
43
|
-
array << 'MediumOffice'
|
44
|
-
array << 'LargeOffice'
|
45
|
-
array << 'SmallHotel'
|
46
|
-
array << 'LargeHotel'
|
47
|
-
array << 'Warehouse'
|
48
|
-
array << 'RetailStandalone'
|
49
|
-
array << 'RetailStripmall'
|
50
|
-
array << 'QuickServiceRestaurant'
|
51
|
-
array << 'FullServiceRestaurant'
|
52
|
-
array << 'MidriseApartment'
|
53
|
-
array << 'HighriseApartment'
|
54
|
-
array << 'Hospital'
|
55
|
-
array << 'Outpatient'
|
56
|
-
array << 'SuperMarket'
|
57
|
-
|
58
|
-
return array
|
59
|
-
end
|
60
|
-
|
61
|
-
# simple list of templates that are valid for get_space_types_from_building_type
|
62
|
-
def get_templates
|
63
|
-
array = OpenStudio::StringVector.new
|
64
|
-
array << 'DOE Ref Pre-1980'
|
65
|
-
array << 'DOE Ref 1980-2004'
|
66
|
-
array << '90.1-2004'
|
67
|
-
array << '90.1-2007'
|
68
|
-
# array << '189.1-2009' # if turn this on need to update space_type_array for RetailStripmall
|
69
|
-
array << '90.1-2010'
|
70
|
-
array << '90.1-2013'
|
71
|
-
array << 'NREL ZNE Ready 2017'
|
72
|
-
|
73
|
-
return array
|
74
|
-
end
|
75
|
-
|
76
|
-
# calculate aspect ratio from area and perimeter
|
77
|
-
def calc_aspect_ratio(a, p)
|
78
|
-
l = 0.25 * (p + Math.sqrt(p**2 - 16 * a))
|
79
|
-
w = 0.25 * (p - Math.sqrt(p**2 - 16 * a))
|
80
|
-
aspect_ratio = l / w
|
81
|
-
|
82
|
-
return aspect_ratio
|
83
|
-
end
|
84
|
-
|
85
|
-
# Building Form Defaults from Table 4.2 in Achieving the 30% Goal: Energy and Cost Savings Analysis of ASHRAE Standard 90.1-2010
|
86
|
-
# aspect ratio for NA replaced with floor area to perimeter ratio from prototype model
|
87
|
-
def building_form_defaults(building_type)
|
88
|
-
hash = {}
|
89
|
-
|
90
|
-
# calculate aspect ratios not represented on Table 4.2
|
91
|
-
primary_aspet_ratio = calc_aspect_ratio(73958.0, 2060.0)
|
92
|
-
secondary_aspet_ratio = calc_aspect_ratio(128112.0, 2447.0)
|
93
|
-
outpatient_aspet_ratio = calc_aspect_ratio(14782.0, 588.0)
|
94
|
-
supermarket_a = 45001.0
|
95
|
-
supermarket_p = 866.0
|
96
|
-
supermarket_wwr = 1880.0 / (supermarket_p * 20.0)
|
97
|
-
supermarket_aspet_ratio = calc_aspect_ratio(supermarket_a, supermarket_p)
|
98
|
-
|
99
|
-
hash['SmallOffice'] = { aspect_ratio: 1.5, wwr: 0.15, typical_story: 10.0 }
|
100
|
-
hash['MediumOffice'] = { aspect_ratio: 1.5, wwr: 0.33, typical_story: 13.0 }
|
101
|
-
hash['LargeOffice'] = { aspect_ratio: 1.5, wwr: 0.15, typical_story: 13.0 }
|
102
|
-
hash['RetailStandalone'] = { aspect_ratio: 1.28, wwr: 0.07, typical_story: 20.0 }
|
103
|
-
hash['RetailStripmall'] = { aspect_ratio: 4.0, wwr: 0.11, typical_story: 17.0 }
|
104
|
-
hash['PrimarySchool'] = { aspect_ratio: primary_aspet_ratio.round(1), wwr: 0.35, typical_story: 13.0 }
|
105
|
-
hash['SecondarySchool'] = { aspect_ratio: secondary_aspet_ratio.round(1), wwr: 0.33, typical_story: 13.0 }
|
106
|
-
hash['Outpatient'] = { aspect_ratio: outpatient_aspet_ratio.round(1), wwr: 0.20, typical_story: 10.0 }
|
107
|
-
hash['Hospital'] = { aspect_ratio: 1.33, wwr: 0.16, typical_story: 14.0 }
|
108
|
-
hash['SmallHotel'] = { aspect_ratio: 3.0, wwr: 0.11, typical_story: 9.0, first_story: 11.0 }
|
109
|
-
hash['LargeHotel'] = { aspect_ratio: 5.1, wwr: 0.27, typical_story: 10.0, first_story: 13.0 }
|
110
|
-
|
111
|
-
# code in get_space_types_from_building_type is used to override building wwr with space type specific wwr
|
112
|
-
hash['Warehouse'] = { aspect_ratio: 2.2, wwr: 0.0, typical_story: 28.0}
|
113
|
-
|
114
|
-
hash['QuickServiceRestaurant'] = { aspect_ratio: 1.0, wwr: 0.14, typical_story: 10.0 }
|
115
|
-
hash['FullServiceRestaurant'] = { aspect_ratio: 1.0, wwr: 0.18, typical_story: 10.0 }
|
116
|
-
hash['QuickServiceRestaurant'] = { aspect_ratio: 1.0, wwr: 0.18, typical_story: 10.0 }
|
117
|
-
hash['MidriseApartment'] = { aspect_ratio: 2.75, wwr: 0.15, typical_story: 10.0 }
|
118
|
-
hash['HighriseApartment'] = { aspect_ratio: 2.75, wwr: 0.15, typical_story: 10.0 }
|
119
|
-
# SuperMarket inputs come from prototype model
|
120
|
-
hash['SuperMarket'] = { aspect_ratio: supermarket_aspet_ratio.round(1), wwr: supermarket_wwr.round(2), typical_story: 20.0 }
|
121
|
-
|
122
|
-
return hash[building_type]
|
123
|
-
end
|
124
|
-
|
125
|
-
# create hash of space types and generic ratios of building floor area
|
126
|
-
def get_space_types_from_building_type(building_type, template, whole_building = true)
|
127
|
-
hash = {}
|
128
|
-
|
129
|
-
# TODO: - Confirm that these work for all standards
|
130
|
-
|
131
|
-
if building_type == 'SecondarySchool'
|
132
|
-
hash['Auditorium'] = { ratio: 0.0504, space_type_gen: true, default: false }
|
133
|
-
hash['Cafeteria'] = { ratio: 0.0319, space_type_gen: true, default: false }
|
134
|
-
hash['Classroom'] = { ratio: 0.3528, space_type_gen: true, default: true }
|
135
|
-
hash['Corridor'] = { ratio: 0.2144, space_type_gen: true, default: false }
|
136
|
-
hash['Gym'] = { ratio: 0.1646, space_type_gen: true, default: false }
|
137
|
-
hash['Kitchen'] = { ratio: 0.0110, space_type_gen: true, default: false }
|
138
|
-
hash['Library'] = { ratio: 0.0429, space_type_gen: true, default: false } # not in prototype
|
139
|
-
hash['Lobby'] = { ratio: 0.0214, space_type_gen: true, default: false }
|
140
|
-
hash['Mechanical'] = { ratio: 0.0349, space_type_gen: true, default: false }
|
141
|
-
hash['Office'] = { ratio: 0.0543, space_type_gen: true, default: false }
|
142
|
-
hash['Restroom'] = { ratio: 0.0214, space_type_gen: true, default: false }
|
143
|
-
elsif building_type == 'PrimarySchool'
|
144
|
-
hash['Cafeteria'] = { ratio: 0.0458, space_type_gen: true, default: false }
|
145
|
-
hash['Classroom'] = { ratio: 0.5610, space_type_gen: true, default: true }
|
146
|
-
hash['Corridor'] = { ratio: 0.1633, space_type_gen: true, default: false }
|
147
|
-
hash['Gym'] = { ratio: 0.0520, space_type_gen: true, default: false }
|
148
|
-
hash['Kitchen'] = { ratio: 0.0244, space_type_gen: true, default: false }
|
149
|
-
# TODO: - confirm if Library is 0.0 for all templates
|
150
|
-
hash['Library'] = { ratio: 0.0, space_type_gen: true, default: false }
|
151
|
-
hash['Lobby'] = { ratio: 0.0249, space_type_gen: true, default: false }
|
152
|
-
hash['Mechanical'] = { ratio: 0.0367, space_type_gen: true, default: false }
|
153
|
-
hash['Office'] = { ratio: 0.0642, space_type_gen: true, default: false }
|
154
|
-
hash['Restroom'] = { ratio: 0.0277, space_type_gen: true, default: false }
|
155
|
-
elsif building_type == 'SmallOffice'
|
156
|
-
# TODO: - populate Small, Medium, and Large office for whole_building false
|
157
|
-
if whole_building
|
158
|
-
hash['WholeBuilding - Sm Office'] = { ratio: 1.0, space_type_gen: true, default: true }
|
159
|
-
else
|
160
|
-
hash['SmallOffice - Breakroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
161
|
-
hash['SmallOffice - ClosedOffice'] = { ratio: 0.99, space_type_gen: true, default: false }
|
162
|
-
hash['SmallOffice - Conference'] = { ratio: 0.99, space_type_gen: true, default: false }
|
163
|
-
hash['SmallOffice - Corridor'] = { ratio: 0.99, space_type_gen: true, default: false }
|
164
|
-
hash['SmallOffice - Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
165
|
-
hash['SmallOffice - Lobby'] = { ratio: 0.99, space_type_gen: true, default: false }
|
166
|
-
hash['SmallOffice - OpenOffice'] = { ratio: 0.99, space_type_gen: true, default: true }
|
167
|
-
hash['SmallOffice - Restroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
168
|
-
hash['SmallOffice - Stair'] = { ratio: 0.99, space_type_gen: true, default: false }
|
169
|
-
hash['SmallOffice - Storage'] = { ratio: 0.99, space_type_gen: true, default: false }
|
170
|
-
hash['SmallOffice - Classroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
171
|
-
hash['SmallOffice - Dining'] = { ratio: 0.99, space_type_gen: true, default: false }
|
172
|
-
hash['WholeBuilding - Sm Office'] = { ratio: 0.0, space_type_gen: true, default: false }
|
173
|
-
end
|
174
|
-
elsif building_type == 'MediumOffice'
|
175
|
-
if whole_building
|
176
|
-
hash['WholeBuilding - Md Office'] = { ratio: 1.0, space_type_gen: true, default: true }
|
177
|
-
else
|
178
|
-
hash['MediumOffice - Breakroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
179
|
-
hash['MediumOffice - ClosedOffice'] = { ratio: 0.99, space_type_gen: true, default: false }
|
180
|
-
hash['MediumOffice - Conference'] = { ratio: 0.99, space_type_gen: true, default: false }
|
181
|
-
hash['MediumOffice - Corridor'] = { ratio: 0.99, space_type_gen: true, default: false }
|
182
|
-
hash['MediumOffice - Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
183
|
-
hash['MediumOffice - Lobby'] = { ratio: 0.99, space_type_gen: true, default: false }
|
184
|
-
hash['MediumOffice - OpenOffice'] = { ratio: 0.99, space_type_gen: true, default: true }
|
185
|
-
hash['MediumOffice - Restroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
186
|
-
hash['MediumOffice - Stair'] = { ratio: 0.99, space_type_gen: true, default: false }
|
187
|
-
hash['MediumOffice - Storage'] = { ratio: 0.99, space_type_gen: true, default: false }
|
188
|
-
hash['MediumOffice - Classroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
189
|
-
hash['MediumOffice - Dining'] = { ratio: 0.99, space_type_gen: true, default: false }
|
190
|
-
hash['WholeBuilding - Md Office'] = { ratio: 0.0, space_type_gen: true, default: false }
|
191
|
-
end
|
192
|
-
elsif building_type == 'LargeOffice'
|
193
|
-
if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004'].include?(template)
|
194
|
-
if whole_building
|
195
|
-
hash['WholeBuilding - Lg Office'] = { ratio: 1.0, space_type_gen: true, default: true }
|
196
|
-
else
|
197
|
-
hash['BreakRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
198
|
-
hash['ClosedOffice'] = { ratio: 0.99, space_type_gen: true, default: false }
|
199
|
-
hash['Conference'] = { ratio: 0.99, space_type_gen: true, default: false }
|
200
|
-
hash['Corridor'] = { ratio: 0.99, space_type_gen: true, default: false }
|
201
|
-
hash['Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
202
|
-
hash['IT_Room'] = { ratio: 0.99, space_type_gen: true, default: false }
|
203
|
-
hash['Lobby'] = { ratio: 0.99, space_type_gen: true, default: false }
|
204
|
-
hash['OpenOffice'] = { ratio: 0.99, space_type_gen: true, default: true }
|
205
|
-
hash['PrintRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
206
|
-
hash['Restroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
207
|
-
hash['Stair'] = { ratio: 0.99, space_type_gen: true, default: false }
|
208
|
-
hash['Storage'] = { ratio: 0.99, space_type_gen: true, default: false }
|
209
|
-
hash['Vending'] = { ratio: 0.99, space_type_gen: true, default: false }
|
210
|
-
hash['WholeBuilding - Lg Office'] = { ratio: 0.0, space_type_gen: true, default: false }
|
211
|
-
end
|
212
|
-
else
|
213
|
-
if whole_building
|
214
|
-
hash['WholeBuilding - Lg Office'] = { ratio: 0.9737, space_type_gen: true, default: true }
|
215
|
-
hash['OfficeLarge Data Center'] = { ratio: 0.0094, space_type_gen: true, default: false }
|
216
|
-
hash['OfficeLarge Main Data Center'] = { ratio: 0.0169, space_type_gen: true, default: false }
|
217
|
-
else
|
218
|
-
hash['BreakRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
219
|
-
hash['ClosedOffice'] = { ratio: 0.99, space_type_gen: true, default: false }
|
220
|
-
hash['Conference'] = { ratio: 0.99, space_type_gen: true, default: false }
|
221
|
-
hash['Corridor'] = { ratio: 0.99, space_type_gen: true, default: false }
|
222
|
-
hash['Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
223
|
-
hash['IT_Room'] = { ratio: 0.99, space_type_gen: true, default: false }
|
224
|
-
hash['Lobby'] = { ratio: 0.99, space_type_gen: true, default: false }
|
225
|
-
hash['OpenOffice'] = { ratio: 0.99, space_type_gen: true, default: true }
|
226
|
-
hash['PrintRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
227
|
-
hash['Restroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
228
|
-
hash['Stair'] = { ratio: 0.99, space_type_gen: true, default: false }
|
229
|
-
hash['Storage'] = { ratio: 0.99, space_type_gen: true, default: false }
|
230
|
-
hash['Vending'] = { ratio: 0.99, space_type_gen: true, default: false }
|
231
|
-
hash['WholeBuilding - Lg Office'] = { ratio: 0.0, space_type_gen: true, default: false }
|
232
|
-
hash['OfficeLarge Data Center'] = { ratio: 0.0, space_type_gen: true, default: false }
|
233
|
-
hash['OfficeLarge Main Data Center'] = { ratio: 0.0, space_type_gen: true, default: false }
|
234
|
-
end
|
235
|
-
end
|
236
|
-
elsif building_type == 'SmallHotel'
|
237
|
-
if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004'].include?(template)
|
238
|
-
hash['Corridor'] = { ratio: 0.1313, space_type_gen: true, default: false }
|
239
|
-
hash['Elec/MechRoom'] = { ratio: 0.0038, space_type_gen: true, default: false }
|
240
|
-
hash['ElevatorCore'] = { ratio: 0.0113, space_type_gen: true, default: false }
|
241
|
-
hash['Exercise'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
242
|
-
hash['GuestLounge'] = { ratio: 0.0406, space_type_gen: true, default: false }
|
243
|
-
hash['GuestRoom'] = { ratio: 0.6313, space_type_gen: true, default: true }
|
244
|
-
hash['Laundry'] = { ratio: 0.0244, space_type_gen: true, default: false }
|
245
|
-
hash['Mechanical'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
246
|
-
hash['Meeting'] = { ratio: 0.0200, space_type_gen: true, default: false }
|
247
|
-
hash['Office'] = { ratio: 0.0325, space_type_gen: true, default: false }
|
248
|
-
hash['PublicRestroom'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
249
|
-
hash['StaffLounge'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
250
|
-
hash['Stair'] = { ratio: 0.0400, space_type_gen: true, default: false }
|
251
|
-
hash['Storage'] = { ratio: 0.0325, space_type_gen: true, default: false }
|
252
|
-
else
|
253
|
-
hash['Corridor'] = { ratio: 0.1313, space_type_gen: true, default: false }
|
254
|
-
hash['Elec/MechRoom'] = { ratio: 0.0038, space_type_gen: true, default: false }
|
255
|
-
hash['ElevatorCore'] = { ratio: 0.0113, space_type_gen: true, default: false }
|
256
|
-
hash['Exercise'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
257
|
-
hash['GuestLounge'] = { ratio: 0.0406, space_type_gen: true, default: false }
|
258
|
-
hash['GuestRoom123Occ'] = { ratio: 0.4081, space_type_gen: true, default: true }
|
259
|
-
hash['GuestRoom123Vac'] = { ratio: 0.2231, space_type_gen: true, default: false }
|
260
|
-
hash['Laundry'] = { ratio: 0.0244, space_type_gen: true, default: false }
|
261
|
-
hash['Mechanical'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
262
|
-
hash['Meeting'] = { ratio: 0.0200, space_type_gen: true, default: false }
|
263
|
-
hash['Office'] = { ratio: 0.0325, space_type_gen: true, default: false }
|
264
|
-
hash['PublicRestroom'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
265
|
-
hash['StaffLounge'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
266
|
-
hash['Stair'] = { ratio: 0.0400, space_type_gen: true, default: false }
|
267
|
-
hash['Storage'] = { ratio: 0.0325, space_type_gen: true, default: false }
|
268
|
-
end
|
269
|
-
elsif building_type == 'LargeHotel'
|
270
|
-
hash['Banquet'] = { ratio: 0.0585, space_type_gen: true, default: false }
|
271
|
-
hash['Basement'] = { ratio: 0.1744, space_type_gen: false, default: false }
|
272
|
-
hash['Cafe'] = { ratio: 0.0166, space_type_gen: true, default: false }
|
273
|
-
hash['Corridor'] = { ratio: 0.1736, space_type_gen: true, default: false }
|
274
|
-
hash['GuestRoom'] = { ratio: 0.4099, space_type_gen: true, default: true }
|
275
|
-
hash['Kitchen'] = { ratio: 0.0091, space_type_gen: true, default: false }
|
276
|
-
hash['Laundry'] = { ratio: 0.0069, space_type_gen: true, default: false }
|
277
|
-
hash['Lobby'] = { ratio: 0.1153, space_type_gen: true, default: false }
|
278
|
-
hash['Mechanical'] = { ratio: 0.0145, space_type_gen: true, default: false }
|
279
|
-
hash['Retail'] = { ratio: 0.0128, space_type_gen: true, default: false }
|
280
|
-
hash['Storage'] = { ratio: 0.0084, space_type_gen: true, default: false }
|
281
|
-
elsif building_type == 'Warehouse'
|
282
|
-
hash['Bulk'] = { ratio: 0.6628, space_type_gen: true, default: true }
|
283
|
-
hash['Fine'] = { ratio: 0.2882, space_type_gen: true, default: false }
|
284
|
-
hash['Office'] = { ratio: 0.0490, space_type_gen: true, default: false, wwr: 0.71 }
|
285
|
-
elsif building_type == 'RetailStandalone'
|
286
|
-
hash['Back_Space'] = { ratio: 0.1656, space_type_gen: true, default: false }
|
287
|
-
hash['Entry'] = { ratio: 0.0052, space_type_gen: true, default: false }
|
288
|
-
hash['Point_of_Sale'] = { ratio: 0.0657, space_type_gen: true, default: false }
|
289
|
-
hash['Retail'] = { ratio: 0.7635, space_type_gen: true, default: true }
|
290
|
-
elsif building_type == 'RetailStripmall'
|
291
|
-
hash['Strip mall - type 1'] = { ratio: 0.25, space_type_gen: true, default: false }
|
292
|
-
hash['Strip mall - type 2'] = { ratio: 0.25, space_type_gen: true, default: false }
|
293
|
-
hash['Strip mall - type 3'] = { ratio: 0.50, space_type_gen: true, default: true }
|
294
|
-
elsif building_type == 'QuickServiceRestaurant'
|
295
|
-
hash['Dining'] = { ratio: 0.5, space_type_gen: true, default: true }
|
296
|
-
hash['Kitchen'] = { ratio: 0.5, space_type_gen: true, default: false }
|
297
|
-
elsif building_type == 'FullServiceRestaurant'
|
298
|
-
hash['Dining'] = { ratio: 0.7272, space_type_gen: true, default: true }
|
299
|
-
hash['Kitchen'] = { ratio: 0.2728, space_type_gen: true, default: false }
|
300
|
-
elsif building_type == 'MidriseApartment'
|
301
|
-
hash['Apartment'] = { ratio: 0.8727, space_type_gen: true, default: true }
|
302
|
-
hash['Corridor'] = { ratio: 0.0991, space_type_gen: true, default: false }
|
303
|
-
hash['Office'] = { ratio: 0.0282, space_type_gen: true, default: false }
|
304
|
-
elsif building_type == 'HighriseApartment'
|
305
|
-
hash['Apartment'] = { ratio: 0.8896, space_type_gen: true, default: true }
|
306
|
-
hash['Corridor'] = { ratio: 0.0991, space_type_gen: true, default: false }
|
307
|
-
hash['Office'] = { ratio: 0.0113, space_type_gen: true, default: false }
|
308
|
-
elsif building_type == 'Hospital'
|
309
|
-
hash['Basement'] = { ratio: 0.1667, space_type_gen: false, default: false }
|
310
|
-
hash['Corridor'] = { ratio: 0.1741, space_type_gen: true, default: false }
|
311
|
-
hash['Dining'] = { ratio: 0.0311, space_type_gen: true, default: false }
|
312
|
-
hash['ER_Exam'] = { ratio: 0.0099, space_type_gen: true, default: false }
|
313
|
-
hash['ER_NurseStn'] = { ratio: 0.0551, space_type_gen: true, default: false }
|
314
|
-
hash['ER_Trauma'] = { ratio: 0.0025, space_type_gen: true, default: false }
|
315
|
-
hash['ER_Triage'] = { ratio: 0.0050, space_type_gen: true, default: false }
|
316
|
-
hash['ICU_NurseStn'] = { ratio: 0.0298, space_type_gen: true, default: false }
|
317
|
-
hash['ICE_Open'] = { ratio: 0.0275, space_type_gen: true, default: false }
|
318
|
-
hash['ICU_PatRm'] = { ratio: 0.0115, space_type_gen: true, default: false }
|
319
|
-
hash['Kitchen'] = { ratio: 0.0414, space_type_gen: true, default: false }
|
320
|
-
hash['Lab'] = { ratio: 0.0236, space_type_gen: true, default: false }
|
321
|
-
hash['Lobby'] = { ratio: 0.0657, space_type_gen: true, default: false }
|
322
|
-
hash['NurseStn'] = { ratio: 0.1723, space_type_gen: true, default: false }
|
323
|
-
hash['Office'] = { ratio: 0.0286, space_type_gen: true, default: false }
|
324
|
-
hash['OR'] = { ratio: 0.0273, space_type_gen: true, default: false }
|
325
|
-
hash['PatCorridor'] = { ratio: 0.0, space_type_gen: true, default: false } # not in prototype
|
326
|
-
hash['PatRoom'] = { ratio: 0.0845, space_type_gen: true, default: true }
|
327
|
-
hash['PhysTherapy'] = { ratio: 0.0217, space_type_gen: true, default: false }
|
328
|
-
hash['Radiology'] = { ratio: 0.0217, space_type_gen: true, default: false }
|
329
|
-
elsif building_type == 'Outpatient'
|
330
|
-
hash['Anesthesia'] = { ratio: 0.0026, space_type_gen: true, default: false }
|
331
|
-
hash['BioHazard'] = { ratio: 0.0014, space_type_gen: true, default: false }
|
332
|
-
hash['Cafe'] = { ratio: 0.0103, space_type_gen: true, default: false }
|
333
|
-
hash['CleanWork'] = { ratio: 0.0071, space_type_gen: true, default: false }
|
334
|
-
hash['Conference'] = { ratio: 0.0082, space_type_gen: true, default: false }
|
335
|
-
hash['DresingRoom'] = { ratio: 0.0021, space_type_gen: true, default: false }
|
336
|
-
hash['Elec/MechRoom'] = { ratio: 0.0109, space_type_gen: true, default: false }
|
337
|
-
hash['ElevatorPumpRoom'] = { ratio: 0.0022, space_type_gen: true, default: false }
|
338
|
-
hash['Exam'] = { ratio: 0.1029, space_type_gen: true, default: true }
|
339
|
-
hash['Hall'] = { ratio: 0.1924, space_type_gen: true, default: false }
|
340
|
-
hash['IT_Room'] = { ratio: 0.0027, space_type_gen: true, default: false }
|
341
|
-
hash['Janitor'] = { ratio: 0.0672, space_type_gen: true, default: false }
|
342
|
-
hash['Lobby'] = { ratio: 0.0152, space_type_gen: true, default: false }
|
343
|
-
hash['LockerRoom'] = { ratio: 0.0190, space_type_gen: true, default: false }
|
344
|
-
hash['Lounge'] = { ratio: 0.0293, space_type_gen: true, default: false }
|
345
|
-
hash['MedGas'] = { ratio: 0.0014, space_type_gen: true, default: false }
|
346
|
-
hash['MRI'] = { ratio: 0.0107, space_type_gen: true, default: false }
|
347
|
-
hash['MRI_Control'] = { ratio: 0.0041, space_type_gen: true, default: false }
|
348
|
-
hash['NurseStation'] = { ratio: 0.0189, space_type_gen: true, default: false }
|
349
|
-
hash['Office'] = { ratio: 0.1828, space_type_gen: true, default: false }
|
350
|
-
hash['OR'] = { ratio: 0.0346, space_type_gen: true, default: false }
|
351
|
-
hash['PACU'] = { ratio: 0.0232, space_type_gen: true, default: false }
|
352
|
-
hash['PhysicalTherapy'] = { ratio: 0.0462, space_type_gen: true, default: false }
|
353
|
-
hash['PreOp'] = { ratio: 0.0129, space_type_gen: true, default: false }
|
354
|
-
hash['ProcedureRoom'] = { ratio: 0.0070, space_type_gen: true, default: false }
|
355
|
-
hash['Reception'] = { ratio: 0.0365, space_type_gen: true, default: false }
|
356
|
-
hash['Soil Work'] = { ratio: 0.0088, space_type_gen: true, default: false }
|
357
|
-
hash['Stair'] = { ratio: 0.0146, space_type_gen: true, default: false }
|
358
|
-
hash['Toilet'] = { ratio: 0.0193, space_type_gen: true, default: false }
|
359
|
-
hash['Undeveloped'] = { ratio: 0.0835, space_type_gen: false, default: false }
|
360
|
-
hash['Xray'] = { ratio: 0.0220, space_type_gen: true, default: false }
|
361
|
-
elsif building_type == 'SuperMarket'
|
362
|
-
# TODO: - populate ratios for SuperMarket
|
363
|
-
hash['Bakery'] = { ratio: 0.99, space_type_gen: true, default: false }
|
364
|
-
hash['Deli'] = { ratio: 0.99, space_type_gen: true, default: false }
|
365
|
-
hash['DryStorage'] = { ratio: 0.99, space_type_gen: true, default: false }
|
366
|
-
hash['Office'] = { ratio: 0.99, space_type_gen: true, default: false }
|
367
|
-
hash['Produce'] = { ratio: 0.99, space_type_gen: true, default: true }
|
368
|
-
hash['Sales'] = { ratio: 0.99, space_type_gen: true, default: true }
|
369
|
-
hash['Corridor'] = { ratio: 0.99, space_type_gen: true, default: true }
|
370
|
-
hash['Dining'] = { ratio: 0.99, space_type_gen: true, default: true }
|
371
|
-
hash['Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: true }
|
372
|
-
hash['Meeting'] = { ratio: 0.99, space_type_gen: true, default: true }
|
373
|
-
hash['Restroom'] = { ratio: 0.99, space_type_gen: true, default: true }
|
374
|
-
hash['Vestibule'] = { ratio: 0.99, space_type_gen: true, default: true }
|
375
|
-
else
|
376
|
-
return false
|
377
|
-
end
|
378
|
-
|
379
|
-
return hash
|
380
|
-
end
|
381
|
-
|
382
|
-
# remove existing non resource objects from the model
|
383
|
-
# technically thermostats and building stories are resources but still want to remove them.
|
384
|
-
def remove_non_resource_objects(runner, model, options = nil)
|
385
|
-
if options.nil?
|
386
|
-
options = {}
|
387
|
-
options[:remove_building_stories] = true
|
388
|
-
options[:remove_thermostats] = true
|
389
|
-
options[:remove_air_loops] = true
|
390
|
-
options[:remove_non_swh_plant_loops] = true
|
391
|
-
|
392
|
-
# leave these in by default unless requsted when method called
|
393
|
-
options[:remove_swh_plant_loops] = false
|
394
|
-
options[:remove_exterior_lights] = false
|
395
|
-
options[:remove_site_shading] = false
|
396
|
-
end
|
397
|
-
|
398
|
-
num_model_objects = model.objects.size
|
399
|
-
|
400
|
-
# remove non-resource objects not removed by removing the building
|
401
|
-
if options[:remove_building_stories] then model.getBuildingStorys.each(&:remove) end
|
402
|
-
if options[:remove_thermostats] then model.getThermostats.each(&:remove) end
|
403
|
-
if options[:remove_air_loops] then model.getAirLoopHVACs.each(&:remove) end
|
404
|
-
if options[:remove_exterior_lights] then model.getFacility.exteriorLights.each(&:remove) end
|
405
|
-
if options[:remove_site_shading] then model.getSite.shadingSurfaceGroups.each(&:remove) end
|
406
|
-
|
407
|
-
# see if plant loop is swh or not and take proper action (booter loop doesn't have water use equipment)
|
408
|
-
model.getPlantLoops.each do |plant_loop|
|
409
|
-
is_swh_loop = false
|
410
|
-
plant_loop.supplyComponents.each do |component|
|
411
|
-
if component.to_WaterHeaterMixed.is_initialized
|
412
|
-
is_swh_loop = true
|
413
|
-
next
|
414
|
-
end
|
415
|
-
end
|
416
|
-
|
417
|
-
if is_swh_loop
|
418
|
-
if options[:remove_swh_plant_loops] then plant_loop.remove end
|
419
|
-
else
|
420
|
-
if options[:remove_non_swh_plant_loops] then plant_loop.remove end
|
421
|
-
end
|
422
|
-
end
|
423
|
-
|
424
|
-
# remove water use connections (may be removed when loop is removed)
|
425
|
-
if options[:remove_swh_plant_loops] then model.getWaterConnectionss.each(&:remove) end
|
426
|
-
if options[:remove_swh_plant_loops] then model.getWaterUseEquipments.each(&:remove) end
|
427
|
-
|
428
|
-
# remove building but reset fields on new building object.
|
429
|
-
building_fields = []
|
430
|
-
building = model.getBuilding
|
431
|
-
num_fields = building.numFields
|
432
|
-
num_fields.times.each do |i|
|
433
|
-
building_fields << building.getString(i).get
|
434
|
-
end
|
435
|
-
# removes spaces, space's child objects, thermal zones, zone equipment, non site surfaces, building stories and water use connections.
|
436
|
-
model.getBuilding.remove
|
437
|
-
building = model.getBuilding
|
438
|
-
num_fields.times.each do |i|
|
439
|
-
next if i == 0 # don't try and set handle
|
440
|
-
building_fields << building.setString(i, building_fields[i])
|
441
|
-
end
|
442
|
-
|
443
|
-
# other than optionally site shading and exterior lights not messing with site characteristics
|
444
|
-
|
445
|
-
if num_model_objects - model.objects.size > 0
|
446
|
-
runner.registerInfo("Removed #{num_model_objects - model.objects.size} non resource objects from the model.")
|
447
|
-
end
|
448
|
-
|
449
|
-
return true
|
450
|
-
end
|
451
|
-
|
452
|
-
# create_bar(runner,model,bar_hash)
|
453
|
-
# measures using this method should include OsLibGeometry and OsLibHelperMethods
|
454
|
-
def create_bar(runner, model, bar_hash, story_multiplier_method = 'Basements Ground Mid Top')
|
455
|
-
# warn about site shading
|
456
|
-
if !model.getSite.shadingSurfaceGroups.empty?
|
457
|
-
runner.registerWarning('The model has one or more site shading surafces. New geometry may not be positioned where expected, it will be centered over the center of the original geometry.')
|
458
|
-
end
|
459
|
-
|
460
|
-
# make custom story hash when number of stories below grade > 0
|
461
|
-
# todo - update this so have option basements are not below 0? (useful for simplifying existing model and maintaining z position relative to site shading)
|
462
|
-
story_hash = {}
|
463
|
-
eff_below = bar_hash[:num_stories_below_grade]
|
464
|
-
eff_above = bar_hash[:num_stories_above_grade]
|
465
|
-
footprint_origin = bar_hash[:center_of_footprint]
|
466
|
-
typical_story_height = bar_hash[:floor_height]
|
467
|
-
|
468
|
-
# flatten story_hash out to individual stories included in building area
|
469
|
-
stories_flat = []
|
470
|
-
stories_flat_counter = 0
|
471
|
-
bar_hash[:stories].each_with_index do |(k, v), i|
|
472
|
-
# k is invalid in some cases, old story object that has been removed, should be from low to high including basement
|
473
|
-
# skip if source story insn't included in building area
|
474
|
-
if v[:story_included_in_building_area].nil? || (v[:story_included_in_building_area] == true)
|
475
|
-
|
476
|
-
# add to counter
|
477
|
-
stories_flat_counter += v[:story_min_multiplier]
|
478
|
-
|
479
|
-
flat_hash = {}
|
480
|
-
flat_hash[:story_party_walls] = v[:story_party_walls]
|
481
|
-
flat_hash[:below_partial_story] = v[:below_partial_story]
|
482
|
-
flat_hash[:bottom_story_ground_exposed_floor] = v[:bottom_story_ground_exposed_floor]
|
483
|
-
flat_hash[:top_story_exterior_exposed_roof] = v[:top_story_exterior_exposed_roof]
|
484
|
-
if i < eff_below
|
485
|
-
flat_hash[:story_type] = 'B'
|
486
|
-
flat_hash[:multiplier] = 1
|
487
|
-
elsif i == eff_below
|
488
|
-
flat_hash[:story_type] = 'Ground'
|
489
|
-
flat_hash[:multiplier] = 1
|
490
|
-
elsif stories_flat_counter == eff_below + eff_above.ceil
|
491
|
-
flat_hash[:story_type] = 'Top'
|
492
|
-
flat_hash[:multiplier] = 1
|
493
|
-
else
|
494
|
-
flat_hash[:story_type] = 'Mid'
|
495
|
-
flat_hash[:multiplier] = v[:story_min_multiplier]
|
496
|
-
end
|
497
|
-
|
498
|
-
compare_hash = {}
|
499
|
-
if !stories_flat.empty?
|
500
|
-
stories_flat.last.each { |k, v| compare_hash[k] = flat_hash[k] if flat_hash[k] != v }
|
501
|
-
end
|
502
|
-
if (story_multiplier_method != 'None' && stories_flat.last == flat_hash) || (story_multiplier_method != 'None' && compare_hash.size == 1 && compare_hash.include?(:multiplier))
|
503
|
-
stories_flat.last[:multiplier] += v[:story_min_multiplier]
|
504
|
-
else
|
505
|
-
stories_flat << flat_hash
|
506
|
-
end
|
507
|
-
end
|
508
|
-
end
|
509
|
-
|
510
|
-
if bar_hash[:num_stories_below_grade] > 0
|
511
|
-
|
512
|
-
# add in below grade levels (may want to add below grade multipliers at some point if we start running deep basements)
|
513
|
-
eff_below.times do |i|
|
514
|
-
story_hash["B#{i + 1}"] = { space_origin_z: footprint_origin.z - typical_story_height * (i + 1), space_height: typical_story_height, multiplier: 1 }
|
515
|
-
end
|
516
|
-
end
|
517
|
-
|
518
|
-
# add in above grade levels
|
519
|
-
if eff_above > 2
|
520
|
-
story_hash['Ground'] = { space_origin_z: footprint_origin.z, space_height: typical_story_height, multiplier: 1 }
|
521
|
-
|
522
|
-
footprint_counter = 0
|
523
|
-
effective_stories_counter = 1
|
524
|
-
stories_flat.each do |hash|
|
525
|
-
next if hash[:story_type] != 'Mid'
|
526
|
-
if footprint_counter == 0
|
527
|
-
string = 'Mid'
|
528
|
-
else
|
529
|
-
string = "Mid#{footprint_counter + 1}"
|
530
|
-
end
|
531
|
-
story_hash[string] = { space_origin_z: footprint_origin.z + typical_story_height * effective_stories_counter + typical_story_height * (hash[:multiplier] - 1) / 2.0, space_height: typical_story_height, multiplier: hash[:multiplier] }
|
532
|
-
footprint_counter += 1
|
533
|
-
effective_stories_counter += hash[:multiplier]
|
534
|
-
end
|
535
|
-
|
536
|
-
story_hash['Top'] = { space_origin_z: footprint_origin.z + typical_story_height * (eff_above.ceil - 1), space_height: typical_story_height, multiplier: 1 }
|
537
|
-
elsif eff_above > 1
|
538
|
-
story_hash['Ground'] = { space_origin_z: footprint_origin.z, space_height: typical_story_height, multiplier: 1 }
|
539
|
-
story_hash['Top'] = { space_origin_z: footprint_origin.z + typical_story_height * (eff_above.ceil - 1), space_height: typical_story_height, multiplier: 1 }
|
540
|
-
else # one story only
|
541
|
-
story_hash['Ground'] = { space_origin_z: footprint_origin.z, space_height: typical_story_height, multiplier: 1 }
|
542
|
-
end
|
543
|
-
|
544
|
-
# create footprints
|
545
|
-
if bar_hash[:bar_division_method] == 'Multiple Space Types - Simple Sliced'
|
546
|
-
footprints = []
|
547
|
-
story_hash.size.times do |i|
|
548
|
-
# adjust size of bar of top story is not a full story
|
549
|
-
if i + 1 == story_hash.size
|
550
|
-
area_multiplier = (1.0 - bar_hash[:num_stories_above_grade].ceil + bar_hash[:num_stories_above_grade])
|
551
|
-
edge_multiplier = Math.sqrt(area_multiplier)
|
552
|
-
length = bar_hash[:length] * edge_multiplier
|
553
|
-
width = bar_hash[:width] * edge_multiplier
|
554
|
-
else
|
555
|
-
length = bar_hash[:length]
|
556
|
-
width = bar_hash[:width]
|
557
|
-
end
|
558
|
-
footprints << OsLib_Geometry.make_sliced_bar_simple_polygons(runner, bar_hash[:space_types], length, width, bar_hash[:center_of_footprint])
|
559
|
-
end
|
560
|
-
|
561
|
-
elsif bar_hash[:bar_division_method] == 'Multiple Space Types - Individual Stories Sliced'
|
562
|
-
|
563
|
-
# update story_hash for partial_story_above
|
564
|
-
story_hash.each_with_index do |(k, v), i|
|
565
|
-
# adjust size of bar of top story is not a full story
|
566
|
-
if i + 1 == story_hash.size
|
567
|
-
story_hash[k][:partial_story_multiplier] = (1.0 - bar_hash[:num_stories_above_grade].ceil + bar_hash[:num_stories_above_grade])
|
568
|
-
end
|
569
|
-
end
|
570
|
-
|
571
|
-
footprints = OsLib_Geometry.make_sliced_bar_multi_polygons(runner, bar_hash[:space_types], bar_hash[:length], bar_hash[:width], bar_hash[:center_of_footprint], story_hash)
|
572
|
-
|
573
|
-
else
|
574
|
-
footprints = []
|
575
|
-
story_hash.size.times do |i|
|
576
|
-
# adjust size of bar of top story is not a full story
|
577
|
-
if i + 1 == story_hash.size
|
578
|
-
area_multiplier = (1.0 - bar_hash[:num_stories_above_grade].ceil + bar_hash[:num_stories_above_grade])
|
579
|
-
edge_multiplier = Math.sqrt(area_multiplier)
|
580
|
-
length = bar_hash[:length] * edge_multiplier
|
581
|
-
width = bar_hash[:width] * edge_multiplier
|
582
|
-
else
|
583
|
-
length = bar_hash[:length]
|
584
|
-
width = bar_hash[:width]
|
585
|
-
end
|
586
|
-
footprints << OsLib_Geometry.make_core_and_perimeter_polygons(runner, length, width, bar_hash[:center_of_footprint]) # perimeter defaults to 15'
|
587
|
-
end
|
588
|
-
|
589
|
-
# set primary space type to building default space type
|
590
|
-
space_types = bar_hash[:space_types].sort_by { |k, v| v[:floor_area] }
|
591
|
-
model.getBuilding.setSpaceType(space_types.last.first)
|
592
|
-
|
593
|
-
end
|
594
|
-
|
595
|
-
# makeSpacesFromPolygons
|
596
|
-
OsLib_Geometry.makeSpacesFromPolygons(runner, model, footprints, bar_hash[:floor_height], bar_hash[:num_stories], bar_hash[:center_of_footprint], story_hash)
|
597
|
-
|
598
|
-
# put all of the spaces in the model into a vector for intersection and surface matching
|
599
|
-
spaces = OpenStudio::Model::SpaceVector.new
|
600
|
-
model.getSpaces.sort.each do |space|
|
601
|
-
spaces << space
|
602
|
-
end
|
603
|
-
|
604
|
-
# only intersect if make_mid_story_surfaces_adiabatic false
|
605
|
-
if !(bar_hash[:make_mid_story_surfaces_adiabatic])
|
606
|
-
# intersect surfaces
|
607
|
-
# (when bottom floor has many space types and one above doesn't will end up with heavily subdivided floor. Maybe use adiabatic and don't intersect floor/ceilings)
|
608
|
-
intersect_surfaces = true
|
609
|
-
if intersect_surfaces
|
610
|
-
OpenStudio::Model.intersectSurfaces(spaces)
|
611
|
-
runner.registerInfo('Intersecting surfaces, this will create additional geometry.')
|
612
|
-
end
|
613
|
-
end
|
614
|
-
|
615
|
-
# match surfaces for each space in the vector
|
616
|
-
OpenStudio::Model.matchSurfaces(spaces)
|
617
|
-
|
618
|
-
# set boundary conditions if not already set when geometry was created
|
619
|
-
# todo - update this to use space original z value vs. story name
|
620
|
-
if bar_hash[:num_stories_below_grade] > 0
|
621
|
-
model.getBuildingStorys.each do |story|
|
622
|
-
next if !story.name.to_s.include?('Story B')
|
623
|
-
story.spaces.each do |space|
|
624
|
-
space.surfaces.each do |surface|
|
625
|
-
next if surface.surfaceType != 'Wall'
|
626
|
-
next if surface.outsideBoundaryCondition != 'Outdoors'
|
627
|
-
surface.setOutsideBoundaryCondition('Ground')
|
628
|
-
end
|
629
|
-
end
|
630
|
-
end
|
631
|
-
end
|
632
|
-
|
633
|
-
# sort stories (by name for now but need better way)
|
634
|
-
# todo - need to change this so doesn't create issues when models have existing stories and spaces. Should be able to run it multiple times
|
635
|
-
sorted_stories = {}
|
636
|
-
model.getBuildingStorys.each do |story|
|
637
|
-
sorted_stories[story.name.to_s] = story
|
638
|
-
end
|
639
|
-
|
640
|
-
# flag space types that have wwr overrides
|
641
|
-
space_type_wwr_overrides = {}
|
642
|
-
|
643
|
-
# loop through building stories, spaces, and surfaces
|
644
|
-
sorted_stories.sort.each_with_index do |(key, story), i|
|
645
|
-
# flag for adiabatic floor if building doesn't have ground exposed floor
|
646
|
-
if stories_flat[i][:bottom_story_ground_exposed_floor] == false
|
647
|
-
adiabatic_floor = true
|
648
|
-
end
|
649
|
-
# flag for adiabatic roof if building doesn't have exterior exposed roof
|
650
|
-
if stories_flat[i][:top_story_exterior_exposed_roof] == false
|
651
|
-
adiabatic_ceiling = true
|
652
|
-
end
|
653
|
-
|
654
|
-
# make all mid story floor and celings adiabiatc if requested
|
655
|
-
if bar_hash[:make_mid_story_surfaces_adiabatic]
|
656
|
-
if i > 0
|
657
|
-
adiabatic_floor = true
|
658
|
-
end
|
659
|
-
if i < sorted_stories.size - 1
|
660
|
-
adiabatic_ceiling = true
|
661
|
-
end
|
662
|
-
end
|
663
|
-
|
664
|
-
# flag orientations for this story to recieve party walls
|
665
|
-
party_wall_facades = stories_flat[i][:story_party_walls]
|
666
|
-
|
667
|
-
story.spaces.each do |space|
|
668
|
-
space.surfaces. each do |surface|
|
669
|
-
# set floor to adiabatic if requited
|
670
|
-
if adiabatic_floor && surface.surfaceType == 'Floor'
|
671
|
-
make_surfaces_adiabatic([surface])
|
672
|
-
elsif adiabatic_ceiling && surface.surfaceType == 'RoofCeiling'
|
673
|
-
make_surfaces_adiabatic([surface])
|
674
|
-
end
|
675
|
-
|
676
|
-
# skip of not exterior wall
|
677
|
-
next if surface.surfaceType != 'Wall'
|
678
|
-
next if surface.outsideBoundaryCondition != 'Outdoors'
|
679
|
-
|
680
|
-
# get the absoluteAzimuth for the surface so we can categorize it
|
681
|
-
absoluteAzimuth = OpenStudio.convert(surface.azimuth, 'rad', 'deg').get + surface.space.get.directionofRelativeNorth + model.getBuilding.northAxis
|
682
|
-
absoluteAzimuth = absoluteAzimuth % 360.0 # should result in value between 0 and 360
|
683
|
-
absoluteAzimuth = absoluteAzimuth.round(5) # this was creating issues at 45 deg angles with opposing facades
|
684
|
-
|
685
|
-
# target wwr values that may be changed for specific space types
|
686
|
-
wwr_n = bar_hash[:building_wwr_n]
|
687
|
-
wwr_e = bar_hash[:building_wwr_e]
|
688
|
-
wwr_s = bar_hash[:building_wwr_s]
|
689
|
-
wwr_w = bar_hash[:building_wwr_w]
|
690
|
-
|
691
|
-
# look for space type specific wwr values
|
692
|
-
if surface.space.is_initialized && surface.space.get.spaceType.is_initialized
|
693
|
-
space_type = surface.space.get.spaceType.get
|
694
|
-
|
695
|
-
# see if space type has wwr value
|
696
|
-
bar_hash[:space_types].each do |k,v|
|
697
|
-
if v.has_key?(:space_type) && space_type == v[:space_type]
|
698
|
-
|
699
|
-
# if matching space type specifies a wwr then override the orientaiton specific recommendations for this surface.
|
700
|
-
if v.has_key?(:wwr)
|
701
|
-
wwr_n = v[:wwr]
|
702
|
-
wwr_e = v[:wwr]
|
703
|
-
wwr_s = v[:wwr]
|
704
|
-
wwr_w = v[:wwr]
|
705
|
-
space_type_wwr_overrides[space_type] = v[:wwr]
|
706
|
-
end
|
707
|
-
end
|
708
|
-
end
|
709
|
-
end
|
710
|
-
|
711
|
-
# add fenestration (wwr for now, maybe overhang and overhead doors later)
|
712
|
-
if (absoluteAzimuth >= 315.0) || (absoluteAzimuth < 45.0)
|
713
|
-
if party_wall_facades.include?('north')
|
714
|
-
make_surfaces_adiabatic([surface])
|
715
|
-
else
|
716
|
-
surface.setWindowToWallRatio(wwr_n)
|
717
|
-
end
|
718
|
-
elsif (absoluteAzimuth >= 45.0) && (absoluteAzimuth < 135.0)
|
719
|
-
if party_wall_facades.include?('east')
|
720
|
-
make_surfaces_adiabatic([surface])
|
721
|
-
else
|
722
|
-
surface.setWindowToWallRatio(wwr_e)
|
723
|
-
end
|
724
|
-
elsif (absoluteAzimuth >= 135.0) && (absoluteAzimuth < 225.0)
|
725
|
-
if party_wall_facades.include?('south')
|
726
|
-
make_surfaces_adiabatic([surface])
|
727
|
-
else
|
728
|
-
surface.setWindowToWallRatio(wwr_s)
|
729
|
-
end
|
730
|
-
elsif (absoluteAzimuth >= 225.0) && (absoluteAzimuth < 315.0)
|
731
|
-
if party_wall_facades.include?('west')
|
732
|
-
make_surfaces_adiabatic([surface])
|
733
|
-
else
|
734
|
-
surface.setWindowToWallRatio(wwr_w)
|
735
|
-
end
|
736
|
-
else
|
737
|
-
runner.registerError('Unexpected value of facade: ' + absoluteAzimuth + '.')
|
738
|
-
return false
|
739
|
-
end
|
740
|
-
end
|
741
|
-
end
|
742
|
-
end
|
743
|
-
|
744
|
-
# report space types with custom wwr values
|
745
|
-
space_type_wwr_overrides.each do |space_type,wwr|
|
746
|
-
runner.registerInfo("For #{space_type.name} the default building wwr was replaced with a space type specifc value of #{wwr}")
|
747
|
-
end
|
748
|
-
|
749
|
-
final_floor_area_ip = OpenStudio.convert(model.getBuilding.floorArea, 'm^2', 'ft^2').get
|
750
|
-
runner.registerInfo("Created Bar envlope with floor area of #{OpenStudio.toNeatString(final_floor_area_ip, 0, true)} (ft^2)")
|
751
|
-
end
|
752
|
-
|
753
|
-
# make selected surfaces adiabatic
|
754
|
-
def make_surfaces_adiabatic(surfaces)
|
755
|
-
surfaces.each do |surface|
|
756
|
-
if surface.construction.is_initialized
|
757
|
-
surface.setConstruction(surface.construction.get)
|
758
|
-
end
|
759
|
-
surface.setOutsideBoundaryCondition('Adiabatic')
|
760
|
-
end
|
761
|
-
end
|
762
|
-
|
763
|
-
# get length and width of rectangle matching bounding box aspect ratio will maintaining proper floor area
|
764
|
-
def calc_bar_reduced_bounding_box(envelope_data_hash)
|
765
|
-
bar = {}
|
766
|
-
|
767
|
-
bounding_length = envelope_data_hash[:building_max_xyz][0] - envelope_data_hash[:building_min_xyz][0]
|
768
|
-
bounding_width = envelope_data_hash[:building_max_xyz][1] - envelope_data_hash[:building_min_xyz][1]
|
769
|
-
bounding_area = bounding_length * bounding_width
|
770
|
-
footprint_area = envelope_data_hash[:building_floor_area] / envelope_data_hash[:effective__num_stories].to_f
|
771
|
-
area_multiplier = footprint_area / bounding_area
|
772
|
-
edge_multiplier = Math.sqrt(area_multiplier)
|
773
|
-
bar[:length] = bounding_length * edge_multiplier
|
774
|
-
bar[:width] = bounding_width * edge_multiplier
|
775
|
-
|
776
|
-
return bar
|
777
|
-
end
|
778
|
-
|
779
|
-
# get length and width of rectangle matching longer of two edges, and reducing the other way until floor area matches
|
780
|
-
def calc_bar_reduced_width(envelope_data_hash)
|
781
|
-
bar = {}
|
782
|
-
|
783
|
-
bounding_length = envelope_data_hash[:building_max_xyz][0] - envelope_data_hash[:building_min_xyz][0]
|
784
|
-
bounding_width = envelope_data_hash[:building_max_xyz][1] - envelope_data_hash[:building_min_xyz][1]
|
785
|
-
footprint_area = envelope_data_hash[:building_floor_area] / envelope_data_hash[:effective__num_stories].to_f
|
786
|
-
|
787
|
-
if bounding_length >= bounding_width
|
788
|
-
bar[:length] = bounding_length
|
789
|
-
bar[:width] = footprint_area / bounding_length
|
790
|
-
else
|
791
|
-
bar[:width] = bounding_width
|
792
|
-
bar[:length] = footprint_area / bounding_width
|
793
|
-
end
|
794
|
-
|
795
|
-
return bar
|
796
|
-
end
|
797
|
-
|
798
|
-
# get length and width of rectangle by stretching it until both floor area and exterior wall area or perimeter match
|
799
|
-
def calc_bar_stretched(envelope_data_hash)
|
800
|
-
bar = {}
|
801
|
-
|
802
|
-
bounding_length = envelope_data_hash[:building_max_xyz][0] - envelope_data_hash[:building_min_xyz][0]
|
803
|
-
bounding_width = envelope_data_hash[:building_max_xyz][1] - envelope_data_hash[:building_min_xyz][1]
|
804
|
-
a = envelope_data_hash[:building_floor_area] / envelope_data_hash[:effective__num_stories].to_f
|
805
|
-
p = envelope_data_hash[:building_perimeter]
|
806
|
-
|
807
|
-
if bounding_length >= bounding_width
|
808
|
-
bar[:length] = 0.25 * (p + Math.sqrt(p**2 - 16 * a))
|
809
|
-
bar[:width] = 0.25 * (p - Math.sqrt(p**2 - 16 * a))
|
810
|
-
else
|
811
|
-
bar[:length] = 0.25 * (p - Math.sqrt(p**2 - 16 * a))
|
812
|
-
bar[:width] = 0.25 * (p + Math.sqrt(p**2 - 16 * a))
|
813
|
-
end
|
814
|
-
|
815
|
-
return bar
|
816
|
-
end
|
817
|
-
end
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
|
3
|
+
# All rights reserved.
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# (1) Redistributions of source code must retain the above copyright notice,
|
8
|
+
# this list of conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
#
|
14
|
+
# (3) Neither the name of the copyright holder nor the names of any contributors
|
15
|
+
# may be used to endorse or promote products derived from this software without
|
16
|
+
# specific prior written permission from the respective party.
|
17
|
+
#
|
18
|
+
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
19
|
+
# of modifications or other derivative works may not use the "OpenStudio"
|
20
|
+
# trademark, "OS", "os", or any other confusingly similar designation without
|
21
|
+
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
|
24
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
25
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
|
27
|
+
# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
|
28
|
+
# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
29
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
30
|
+
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
31
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
32
|
+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
33
|
+
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
# *******************************************************************************
|
35
|
+
|
36
|
+
module OsLib_ModelGeneration
|
37
|
+
# simple list of building types that are valid for get_space_types_from_building_type
|
38
|
+
def get_building_types
|
39
|
+
array = OpenStudio::StringVector.new
|
40
|
+
array << 'SecondarySchool'
|
41
|
+
array << 'PrimarySchool'
|
42
|
+
array << 'SmallOffice'
|
43
|
+
array << 'MediumOffice'
|
44
|
+
array << 'LargeOffice'
|
45
|
+
array << 'SmallHotel'
|
46
|
+
array << 'LargeHotel'
|
47
|
+
array << 'Warehouse'
|
48
|
+
array << 'RetailStandalone'
|
49
|
+
array << 'RetailStripmall'
|
50
|
+
array << 'QuickServiceRestaurant'
|
51
|
+
array << 'FullServiceRestaurant'
|
52
|
+
array << 'MidriseApartment'
|
53
|
+
array << 'HighriseApartment'
|
54
|
+
array << 'Hospital'
|
55
|
+
array << 'Outpatient'
|
56
|
+
array << 'SuperMarket'
|
57
|
+
|
58
|
+
return array
|
59
|
+
end
|
60
|
+
|
61
|
+
# simple list of templates that are valid for get_space_types_from_building_type
|
62
|
+
def get_templates
|
63
|
+
array = OpenStudio::StringVector.new
|
64
|
+
array << 'DOE Ref Pre-1980'
|
65
|
+
array << 'DOE Ref 1980-2004'
|
66
|
+
array << '90.1-2004'
|
67
|
+
array << '90.1-2007'
|
68
|
+
# array << '189.1-2009' # if turn this on need to update space_type_array for RetailStripmall
|
69
|
+
array << '90.1-2010'
|
70
|
+
array << '90.1-2013'
|
71
|
+
array << 'NREL ZNE Ready 2017'
|
72
|
+
|
73
|
+
return array
|
74
|
+
end
|
75
|
+
|
76
|
+
# calculate aspect ratio from area and perimeter
|
77
|
+
def calc_aspect_ratio(a, p)
|
78
|
+
l = 0.25 * (p + Math.sqrt(p**2 - 16 * a))
|
79
|
+
w = 0.25 * (p - Math.sqrt(p**2 - 16 * a))
|
80
|
+
aspect_ratio = l / w
|
81
|
+
|
82
|
+
return aspect_ratio
|
83
|
+
end
|
84
|
+
|
85
|
+
# Building Form Defaults from Table 4.2 in Achieving the 30% Goal: Energy and Cost Savings Analysis of ASHRAE Standard 90.1-2010
|
86
|
+
# aspect ratio for NA replaced with floor area to perimeter ratio from prototype model
|
87
|
+
def building_form_defaults(building_type)
|
88
|
+
hash = {}
|
89
|
+
|
90
|
+
# calculate aspect ratios not represented on Table 4.2
|
91
|
+
primary_aspet_ratio = calc_aspect_ratio(73958.0, 2060.0)
|
92
|
+
secondary_aspet_ratio = calc_aspect_ratio(128112.0, 2447.0)
|
93
|
+
outpatient_aspet_ratio = calc_aspect_ratio(14782.0, 588.0)
|
94
|
+
supermarket_a = 45001.0
|
95
|
+
supermarket_p = 866.0
|
96
|
+
supermarket_wwr = 1880.0 / (supermarket_p * 20.0)
|
97
|
+
supermarket_aspet_ratio = calc_aspect_ratio(supermarket_a, supermarket_p)
|
98
|
+
|
99
|
+
hash['SmallOffice'] = { aspect_ratio: 1.5, wwr: 0.15, typical_story: 10.0 }
|
100
|
+
hash['MediumOffice'] = { aspect_ratio: 1.5, wwr: 0.33, typical_story: 13.0 }
|
101
|
+
hash['LargeOffice'] = { aspect_ratio: 1.5, wwr: 0.15, typical_story: 13.0 }
|
102
|
+
hash['RetailStandalone'] = { aspect_ratio: 1.28, wwr: 0.07, typical_story: 20.0 }
|
103
|
+
hash['RetailStripmall'] = { aspect_ratio: 4.0, wwr: 0.11, typical_story: 17.0 }
|
104
|
+
hash['PrimarySchool'] = { aspect_ratio: primary_aspet_ratio.round(1), wwr: 0.35, typical_story: 13.0 }
|
105
|
+
hash['SecondarySchool'] = { aspect_ratio: secondary_aspet_ratio.round(1), wwr: 0.33, typical_story: 13.0 }
|
106
|
+
hash['Outpatient'] = { aspect_ratio: outpatient_aspet_ratio.round(1), wwr: 0.20, typical_story: 10.0 }
|
107
|
+
hash['Hospital'] = { aspect_ratio: 1.33, wwr: 0.16, typical_story: 14.0 }
|
108
|
+
hash['SmallHotel'] = { aspect_ratio: 3.0, wwr: 0.11, typical_story: 9.0, first_story: 11.0 }
|
109
|
+
hash['LargeHotel'] = { aspect_ratio: 5.1, wwr: 0.27, typical_story: 10.0, first_story: 13.0 }
|
110
|
+
|
111
|
+
# code in get_space_types_from_building_type is used to override building wwr with space type specific wwr
|
112
|
+
hash['Warehouse'] = { aspect_ratio: 2.2, wwr: 0.0, typical_story: 28.0}
|
113
|
+
|
114
|
+
hash['QuickServiceRestaurant'] = { aspect_ratio: 1.0, wwr: 0.14, typical_story: 10.0 }
|
115
|
+
hash['FullServiceRestaurant'] = { aspect_ratio: 1.0, wwr: 0.18, typical_story: 10.0 }
|
116
|
+
hash['QuickServiceRestaurant'] = { aspect_ratio: 1.0, wwr: 0.18, typical_story: 10.0 }
|
117
|
+
hash['MidriseApartment'] = { aspect_ratio: 2.75, wwr: 0.15, typical_story: 10.0 }
|
118
|
+
hash['HighriseApartment'] = { aspect_ratio: 2.75, wwr: 0.15, typical_story: 10.0 }
|
119
|
+
# SuperMarket inputs come from prototype model
|
120
|
+
hash['SuperMarket'] = { aspect_ratio: supermarket_aspet_ratio.round(1), wwr: supermarket_wwr.round(2), typical_story: 20.0 }
|
121
|
+
|
122
|
+
return hash[building_type]
|
123
|
+
end
|
124
|
+
|
125
|
+
# create hash of space types and generic ratios of building floor area
|
126
|
+
def get_space_types_from_building_type(building_type, template, whole_building = true)
|
127
|
+
hash = {}
|
128
|
+
|
129
|
+
# TODO: - Confirm that these work for all standards
|
130
|
+
|
131
|
+
if building_type == 'SecondarySchool'
|
132
|
+
hash['Auditorium'] = { ratio: 0.0504, space_type_gen: true, default: false }
|
133
|
+
hash['Cafeteria'] = { ratio: 0.0319, space_type_gen: true, default: false }
|
134
|
+
hash['Classroom'] = { ratio: 0.3528, space_type_gen: true, default: true }
|
135
|
+
hash['Corridor'] = { ratio: 0.2144, space_type_gen: true, default: false }
|
136
|
+
hash['Gym'] = { ratio: 0.1646, space_type_gen: true, default: false }
|
137
|
+
hash['Kitchen'] = { ratio: 0.0110, space_type_gen: true, default: false }
|
138
|
+
hash['Library'] = { ratio: 0.0429, space_type_gen: true, default: false } # not in prototype
|
139
|
+
hash['Lobby'] = { ratio: 0.0214, space_type_gen: true, default: false }
|
140
|
+
hash['Mechanical'] = { ratio: 0.0349, space_type_gen: true, default: false }
|
141
|
+
hash['Office'] = { ratio: 0.0543, space_type_gen: true, default: false }
|
142
|
+
hash['Restroom'] = { ratio: 0.0214, space_type_gen: true, default: false }
|
143
|
+
elsif building_type == 'PrimarySchool'
|
144
|
+
hash['Cafeteria'] = { ratio: 0.0458, space_type_gen: true, default: false }
|
145
|
+
hash['Classroom'] = { ratio: 0.5610, space_type_gen: true, default: true }
|
146
|
+
hash['Corridor'] = { ratio: 0.1633, space_type_gen: true, default: false }
|
147
|
+
hash['Gym'] = { ratio: 0.0520, space_type_gen: true, default: false }
|
148
|
+
hash['Kitchen'] = { ratio: 0.0244, space_type_gen: true, default: false }
|
149
|
+
# TODO: - confirm if Library is 0.0 for all templates
|
150
|
+
hash['Library'] = { ratio: 0.0, space_type_gen: true, default: false }
|
151
|
+
hash['Lobby'] = { ratio: 0.0249, space_type_gen: true, default: false }
|
152
|
+
hash['Mechanical'] = { ratio: 0.0367, space_type_gen: true, default: false }
|
153
|
+
hash['Office'] = { ratio: 0.0642, space_type_gen: true, default: false }
|
154
|
+
hash['Restroom'] = { ratio: 0.0277, space_type_gen: true, default: false }
|
155
|
+
elsif building_type == 'SmallOffice'
|
156
|
+
# TODO: - populate Small, Medium, and Large office for whole_building false
|
157
|
+
if whole_building
|
158
|
+
hash['WholeBuilding - Sm Office'] = { ratio: 1.0, space_type_gen: true, default: true }
|
159
|
+
else
|
160
|
+
hash['SmallOffice - Breakroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
161
|
+
hash['SmallOffice - ClosedOffice'] = { ratio: 0.99, space_type_gen: true, default: false }
|
162
|
+
hash['SmallOffice - Conference'] = { ratio: 0.99, space_type_gen: true, default: false }
|
163
|
+
hash['SmallOffice - Corridor'] = { ratio: 0.99, space_type_gen: true, default: false }
|
164
|
+
hash['SmallOffice - Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
165
|
+
hash['SmallOffice - Lobby'] = { ratio: 0.99, space_type_gen: true, default: false }
|
166
|
+
hash['SmallOffice - OpenOffice'] = { ratio: 0.99, space_type_gen: true, default: true }
|
167
|
+
hash['SmallOffice - Restroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
168
|
+
hash['SmallOffice - Stair'] = { ratio: 0.99, space_type_gen: true, default: false }
|
169
|
+
hash['SmallOffice - Storage'] = { ratio: 0.99, space_type_gen: true, default: false }
|
170
|
+
hash['SmallOffice - Classroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
171
|
+
hash['SmallOffice - Dining'] = { ratio: 0.99, space_type_gen: true, default: false }
|
172
|
+
hash['WholeBuilding - Sm Office'] = { ratio: 0.0, space_type_gen: true, default: false }
|
173
|
+
end
|
174
|
+
elsif building_type == 'MediumOffice'
|
175
|
+
if whole_building
|
176
|
+
hash['WholeBuilding - Md Office'] = { ratio: 1.0, space_type_gen: true, default: true }
|
177
|
+
else
|
178
|
+
hash['MediumOffice - Breakroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
179
|
+
hash['MediumOffice - ClosedOffice'] = { ratio: 0.99, space_type_gen: true, default: false }
|
180
|
+
hash['MediumOffice - Conference'] = { ratio: 0.99, space_type_gen: true, default: false }
|
181
|
+
hash['MediumOffice - Corridor'] = { ratio: 0.99, space_type_gen: true, default: false }
|
182
|
+
hash['MediumOffice - Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
183
|
+
hash['MediumOffice - Lobby'] = { ratio: 0.99, space_type_gen: true, default: false }
|
184
|
+
hash['MediumOffice - OpenOffice'] = { ratio: 0.99, space_type_gen: true, default: true }
|
185
|
+
hash['MediumOffice - Restroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
186
|
+
hash['MediumOffice - Stair'] = { ratio: 0.99, space_type_gen: true, default: false }
|
187
|
+
hash['MediumOffice - Storage'] = { ratio: 0.99, space_type_gen: true, default: false }
|
188
|
+
hash['MediumOffice - Classroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
189
|
+
hash['MediumOffice - Dining'] = { ratio: 0.99, space_type_gen: true, default: false }
|
190
|
+
hash['WholeBuilding - Md Office'] = { ratio: 0.0, space_type_gen: true, default: false }
|
191
|
+
end
|
192
|
+
elsif building_type == 'LargeOffice'
|
193
|
+
if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004'].include?(template)
|
194
|
+
if whole_building
|
195
|
+
hash['WholeBuilding - Lg Office'] = { ratio: 1.0, space_type_gen: true, default: true }
|
196
|
+
else
|
197
|
+
hash['BreakRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
198
|
+
hash['ClosedOffice'] = { ratio: 0.99, space_type_gen: true, default: false }
|
199
|
+
hash['Conference'] = { ratio: 0.99, space_type_gen: true, default: false }
|
200
|
+
hash['Corridor'] = { ratio: 0.99, space_type_gen: true, default: false }
|
201
|
+
hash['Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
202
|
+
hash['IT_Room'] = { ratio: 0.99, space_type_gen: true, default: false }
|
203
|
+
hash['Lobby'] = { ratio: 0.99, space_type_gen: true, default: false }
|
204
|
+
hash['OpenOffice'] = { ratio: 0.99, space_type_gen: true, default: true }
|
205
|
+
hash['PrintRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
206
|
+
hash['Restroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
207
|
+
hash['Stair'] = { ratio: 0.99, space_type_gen: true, default: false }
|
208
|
+
hash['Storage'] = { ratio: 0.99, space_type_gen: true, default: false }
|
209
|
+
hash['Vending'] = { ratio: 0.99, space_type_gen: true, default: false }
|
210
|
+
hash['WholeBuilding - Lg Office'] = { ratio: 0.0, space_type_gen: true, default: false }
|
211
|
+
end
|
212
|
+
else
|
213
|
+
if whole_building
|
214
|
+
hash['WholeBuilding - Lg Office'] = { ratio: 0.9737, space_type_gen: true, default: true }
|
215
|
+
hash['OfficeLarge Data Center'] = { ratio: 0.0094, space_type_gen: true, default: false }
|
216
|
+
hash['OfficeLarge Main Data Center'] = { ratio: 0.0169, space_type_gen: true, default: false }
|
217
|
+
else
|
218
|
+
hash['BreakRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
219
|
+
hash['ClosedOffice'] = { ratio: 0.99, space_type_gen: true, default: false }
|
220
|
+
hash['Conference'] = { ratio: 0.99, space_type_gen: true, default: false }
|
221
|
+
hash['Corridor'] = { ratio: 0.99, space_type_gen: true, default: false }
|
222
|
+
hash['Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
223
|
+
hash['IT_Room'] = { ratio: 0.99, space_type_gen: true, default: false }
|
224
|
+
hash['Lobby'] = { ratio: 0.99, space_type_gen: true, default: false }
|
225
|
+
hash['OpenOffice'] = { ratio: 0.99, space_type_gen: true, default: true }
|
226
|
+
hash['PrintRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
227
|
+
hash['Restroom'] = { ratio: 0.99, space_type_gen: true, default: false }
|
228
|
+
hash['Stair'] = { ratio: 0.99, space_type_gen: true, default: false }
|
229
|
+
hash['Storage'] = { ratio: 0.99, space_type_gen: true, default: false }
|
230
|
+
hash['Vending'] = { ratio: 0.99, space_type_gen: true, default: false }
|
231
|
+
hash['WholeBuilding - Lg Office'] = { ratio: 0.0, space_type_gen: true, default: false }
|
232
|
+
hash['OfficeLarge Data Center'] = { ratio: 0.0, space_type_gen: true, default: false }
|
233
|
+
hash['OfficeLarge Main Data Center'] = { ratio: 0.0, space_type_gen: true, default: false }
|
234
|
+
end
|
235
|
+
end
|
236
|
+
elsif building_type == 'SmallHotel'
|
237
|
+
if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004'].include?(template)
|
238
|
+
hash['Corridor'] = { ratio: 0.1313, space_type_gen: true, default: false }
|
239
|
+
hash['Elec/MechRoom'] = { ratio: 0.0038, space_type_gen: true, default: false }
|
240
|
+
hash['ElevatorCore'] = { ratio: 0.0113, space_type_gen: true, default: false }
|
241
|
+
hash['Exercise'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
242
|
+
hash['GuestLounge'] = { ratio: 0.0406, space_type_gen: true, default: false }
|
243
|
+
hash['GuestRoom'] = { ratio: 0.6313, space_type_gen: true, default: true }
|
244
|
+
hash['Laundry'] = { ratio: 0.0244, space_type_gen: true, default: false }
|
245
|
+
hash['Mechanical'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
246
|
+
hash['Meeting'] = { ratio: 0.0200, space_type_gen: true, default: false }
|
247
|
+
hash['Office'] = { ratio: 0.0325, space_type_gen: true, default: false }
|
248
|
+
hash['PublicRestroom'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
249
|
+
hash['StaffLounge'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
250
|
+
hash['Stair'] = { ratio: 0.0400, space_type_gen: true, default: false }
|
251
|
+
hash['Storage'] = { ratio: 0.0325, space_type_gen: true, default: false }
|
252
|
+
else
|
253
|
+
hash['Corridor'] = { ratio: 0.1313, space_type_gen: true, default: false }
|
254
|
+
hash['Elec/MechRoom'] = { ratio: 0.0038, space_type_gen: true, default: false }
|
255
|
+
hash['ElevatorCore'] = { ratio: 0.0113, space_type_gen: true, default: false }
|
256
|
+
hash['Exercise'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
257
|
+
hash['GuestLounge'] = { ratio: 0.0406, space_type_gen: true, default: false }
|
258
|
+
hash['GuestRoom123Occ'] = { ratio: 0.4081, space_type_gen: true, default: true }
|
259
|
+
hash['GuestRoom123Vac'] = { ratio: 0.2231, space_type_gen: true, default: false }
|
260
|
+
hash['Laundry'] = { ratio: 0.0244, space_type_gen: true, default: false }
|
261
|
+
hash['Mechanical'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
262
|
+
hash['Meeting'] = { ratio: 0.0200, space_type_gen: true, default: false }
|
263
|
+
hash['Office'] = { ratio: 0.0325, space_type_gen: true, default: false }
|
264
|
+
hash['PublicRestroom'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
265
|
+
hash['StaffLounge'] = { ratio: 0.0081, space_type_gen: true, default: false }
|
266
|
+
hash['Stair'] = { ratio: 0.0400, space_type_gen: true, default: false }
|
267
|
+
hash['Storage'] = { ratio: 0.0325, space_type_gen: true, default: false }
|
268
|
+
end
|
269
|
+
elsif building_type == 'LargeHotel'
|
270
|
+
hash['Banquet'] = { ratio: 0.0585, space_type_gen: true, default: false }
|
271
|
+
hash['Basement'] = { ratio: 0.1744, space_type_gen: false, default: false }
|
272
|
+
hash['Cafe'] = { ratio: 0.0166, space_type_gen: true, default: false }
|
273
|
+
hash['Corridor'] = { ratio: 0.1736, space_type_gen: true, default: false }
|
274
|
+
hash['GuestRoom'] = { ratio: 0.4099, space_type_gen: true, default: true }
|
275
|
+
hash['Kitchen'] = { ratio: 0.0091, space_type_gen: true, default: false }
|
276
|
+
hash['Laundry'] = { ratio: 0.0069, space_type_gen: true, default: false }
|
277
|
+
hash['Lobby'] = { ratio: 0.1153, space_type_gen: true, default: false }
|
278
|
+
hash['Mechanical'] = { ratio: 0.0145, space_type_gen: true, default: false }
|
279
|
+
hash['Retail'] = { ratio: 0.0128, space_type_gen: true, default: false }
|
280
|
+
hash['Storage'] = { ratio: 0.0084, space_type_gen: true, default: false }
|
281
|
+
elsif building_type == 'Warehouse'
|
282
|
+
hash['Bulk'] = { ratio: 0.6628, space_type_gen: true, default: true }
|
283
|
+
hash['Fine'] = { ratio: 0.2882, space_type_gen: true, default: false }
|
284
|
+
hash['Office'] = { ratio: 0.0490, space_type_gen: true, default: false, wwr: 0.71 }
|
285
|
+
elsif building_type == 'RetailStandalone'
|
286
|
+
hash['Back_Space'] = { ratio: 0.1656, space_type_gen: true, default: false }
|
287
|
+
hash['Entry'] = { ratio: 0.0052, space_type_gen: true, default: false }
|
288
|
+
hash['Point_of_Sale'] = { ratio: 0.0657, space_type_gen: true, default: false }
|
289
|
+
hash['Retail'] = { ratio: 0.7635, space_type_gen: true, default: true }
|
290
|
+
elsif building_type == 'RetailStripmall'
|
291
|
+
hash['Strip mall - type 1'] = { ratio: 0.25, space_type_gen: true, default: false }
|
292
|
+
hash['Strip mall - type 2'] = { ratio: 0.25, space_type_gen: true, default: false }
|
293
|
+
hash['Strip mall - type 3'] = { ratio: 0.50, space_type_gen: true, default: true }
|
294
|
+
elsif building_type == 'QuickServiceRestaurant'
|
295
|
+
hash['Dining'] = { ratio: 0.5, space_type_gen: true, default: true }
|
296
|
+
hash['Kitchen'] = { ratio: 0.5, space_type_gen: true, default: false }
|
297
|
+
elsif building_type == 'FullServiceRestaurant'
|
298
|
+
hash['Dining'] = { ratio: 0.7272, space_type_gen: true, default: true }
|
299
|
+
hash['Kitchen'] = { ratio: 0.2728, space_type_gen: true, default: false }
|
300
|
+
elsif building_type == 'MidriseApartment'
|
301
|
+
hash['Apartment'] = { ratio: 0.8727, space_type_gen: true, default: true }
|
302
|
+
hash['Corridor'] = { ratio: 0.0991, space_type_gen: true, default: false }
|
303
|
+
hash['Office'] = { ratio: 0.0282, space_type_gen: true, default: false }
|
304
|
+
elsif building_type == 'HighriseApartment'
|
305
|
+
hash['Apartment'] = { ratio: 0.8896, space_type_gen: true, default: true }
|
306
|
+
hash['Corridor'] = { ratio: 0.0991, space_type_gen: true, default: false }
|
307
|
+
hash['Office'] = { ratio: 0.0113, space_type_gen: true, default: false }
|
308
|
+
elsif building_type == 'Hospital'
|
309
|
+
hash['Basement'] = { ratio: 0.1667, space_type_gen: false, default: false }
|
310
|
+
hash['Corridor'] = { ratio: 0.1741, space_type_gen: true, default: false }
|
311
|
+
hash['Dining'] = { ratio: 0.0311, space_type_gen: true, default: false }
|
312
|
+
hash['ER_Exam'] = { ratio: 0.0099, space_type_gen: true, default: false }
|
313
|
+
hash['ER_NurseStn'] = { ratio: 0.0551, space_type_gen: true, default: false }
|
314
|
+
hash['ER_Trauma'] = { ratio: 0.0025, space_type_gen: true, default: false }
|
315
|
+
hash['ER_Triage'] = { ratio: 0.0050, space_type_gen: true, default: false }
|
316
|
+
hash['ICU_NurseStn'] = { ratio: 0.0298, space_type_gen: true, default: false }
|
317
|
+
hash['ICE_Open'] = { ratio: 0.0275, space_type_gen: true, default: false }
|
318
|
+
hash['ICU_PatRm'] = { ratio: 0.0115, space_type_gen: true, default: false }
|
319
|
+
hash['Kitchen'] = { ratio: 0.0414, space_type_gen: true, default: false }
|
320
|
+
hash['Lab'] = { ratio: 0.0236, space_type_gen: true, default: false }
|
321
|
+
hash['Lobby'] = { ratio: 0.0657, space_type_gen: true, default: false }
|
322
|
+
hash['NurseStn'] = { ratio: 0.1723, space_type_gen: true, default: false }
|
323
|
+
hash['Office'] = { ratio: 0.0286, space_type_gen: true, default: false }
|
324
|
+
hash['OR'] = { ratio: 0.0273, space_type_gen: true, default: false }
|
325
|
+
hash['PatCorridor'] = { ratio: 0.0, space_type_gen: true, default: false } # not in prototype
|
326
|
+
hash['PatRoom'] = { ratio: 0.0845, space_type_gen: true, default: true }
|
327
|
+
hash['PhysTherapy'] = { ratio: 0.0217, space_type_gen: true, default: false }
|
328
|
+
hash['Radiology'] = { ratio: 0.0217, space_type_gen: true, default: false }
|
329
|
+
elsif building_type == 'Outpatient'
|
330
|
+
hash['Anesthesia'] = { ratio: 0.0026, space_type_gen: true, default: false }
|
331
|
+
hash['BioHazard'] = { ratio: 0.0014, space_type_gen: true, default: false }
|
332
|
+
hash['Cafe'] = { ratio: 0.0103, space_type_gen: true, default: false }
|
333
|
+
hash['CleanWork'] = { ratio: 0.0071, space_type_gen: true, default: false }
|
334
|
+
hash['Conference'] = { ratio: 0.0082, space_type_gen: true, default: false }
|
335
|
+
hash['DresingRoom'] = { ratio: 0.0021, space_type_gen: true, default: false }
|
336
|
+
hash['Elec/MechRoom'] = { ratio: 0.0109, space_type_gen: true, default: false }
|
337
|
+
hash['ElevatorPumpRoom'] = { ratio: 0.0022, space_type_gen: true, default: false }
|
338
|
+
hash['Exam'] = { ratio: 0.1029, space_type_gen: true, default: true }
|
339
|
+
hash['Hall'] = { ratio: 0.1924, space_type_gen: true, default: false }
|
340
|
+
hash['IT_Room'] = { ratio: 0.0027, space_type_gen: true, default: false }
|
341
|
+
hash['Janitor'] = { ratio: 0.0672, space_type_gen: true, default: false }
|
342
|
+
hash['Lobby'] = { ratio: 0.0152, space_type_gen: true, default: false }
|
343
|
+
hash['LockerRoom'] = { ratio: 0.0190, space_type_gen: true, default: false }
|
344
|
+
hash['Lounge'] = { ratio: 0.0293, space_type_gen: true, default: false }
|
345
|
+
hash['MedGas'] = { ratio: 0.0014, space_type_gen: true, default: false }
|
346
|
+
hash['MRI'] = { ratio: 0.0107, space_type_gen: true, default: false }
|
347
|
+
hash['MRI_Control'] = { ratio: 0.0041, space_type_gen: true, default: false }
|
348
|
+
hash['NurseStation'] = { ratio: 0.0189, space_type_gen: true, default: false }
|
349
|
+
hash['Office'] = { ratio: 0.1828, space_type_gen: true, default: false }
|
350
|
+
hash['OR'] = { ratio: 0.0346, space_type_gen: true, default: false }
|
351
|
+
hash['PACU'] = { ratio: 0.0232, space_type_gen: true, default: false }
|
352
|
+
hash['PhysicalTherapy'] = { ratio: 0.0462, space_type_gen: true, default: false }
|
353
|
+
hash['PreOp'] = { ratio: 0.0129, space_type_gen: true, default: false }
|
354
|
+
hash['ProcedureRoom'] = { ratio: 0.0070, space_type_gen: true, default: false }
|
355
|
+
hash['Reception'] = { ratio: 0.0365, space_type_gen: true, default: false }
|
356
|
+
hash['Soil Work'] = { ratio: 0.0088, space_type_gen: true, default: false }
|
357
|
+
hash['Stair'] = { ratio: 0.0146, space_type_gen: true, default: false }
|
358
|
+
hash['Toilet'] = { ratio: 0.0193, space_type_gen: true, default: false }
|
359
|
+
hash['Undeveloped'] = { ratio: 0.0835, space_type_gen: false, default: false }
|
360
|
+
hash['Xray'] = { ratio: 0.0220, space_type_gen: true, default: false }
|
361
|
+
elsif building_type == 'SuperMarket'
|
362
|
+
# TODO: - populate ratios for SuperMarket
|
363
|
+
hash['Bakery'] = { ratio: 0.99, space_type_gen: true, default: false }
|
364
|
+
hash['Deli'] = { ratio: 0.99, space_type_gen: true, default: false }
|
365
|
+
hash['DryStorage'] = { ratio: 0.99, space_type_gen: true, default: false }
|
366
|
+
hash['Office'] = { ratio: 0.99, space_type_gen: true, default: false }
|
367
|
+
hash['Produce'] = { ratio: 0.99, space_type_gen: true, default: true }
|
368
|
+
hash['Sales'] = { ratio: 0.99, space_type_gen: true, default: true }
|
369
|
+
hash['Corridor'] = { ratio: 0.99, space_type_gen: true, default: true }
|
370
|
+
hash['Dining'] = { ratio: 0.99, space_type_gen: true, default: true }
|
371
|
+
hash['Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: true }
|
372
|
+
hash['Meeting'] = { ratio: 0.99, space_type_gen: true, default: true }
|
373
|
+
hash['Restroom'] = { ratio: 0.99, space_type_gen: true, default: true }
|
374
|
+
hash['Vestibule'] = { ratio: 0.99, space_type_gen: true, default: true }
|
375
|
+
else
|
376
|
+
return false
|
377
|
+
end
|
378
|
+
|
379
|
+
return hash
|
380
|
+
end
|
381
|
+
|
382
|
+
# remove existing non resource objects from the model
|
383
|
+
# technically thermostats and building stories are resources but still want to remove them.
|
384
|
+
def remove_non_resource_objects(runner, model, options = nil)
|
385
|
+
if options.nil?
|
386
|
+
options = {}
|
387
|
+
options[:remove_building_stories] = true
|
388
|
+
options[:remove_thermostats] = true
|
389
|
+
options[:remove_air_loops] = true
|
390
|
+
options[:remove_non_swh_plant_loops] = true
|
391
|
+
|
392
|
+
# leave these in by default unless requsted when method called
|
393
|
+
options[:remove_swh_plant_loops] = false
|
394
|
+
options[:remove_exterior_lights] = false
|
395
|
+
options[:remove_site_shading] = false
|
396
|
+
end
|
397
|
+
|
398
|
+
num_model_objects = model.objects.size
|
399
|
+
|
400
|
+
# remove non-resource objects not removed by removing the building
|
401
|
+
if options[:remove_building_stories] then model.getBuildingStorys.each(&:remove) end
|
402
|
+
if options[:remove_thermostats] then model.getThermostats.each(&:remove) end
|
403
|
+
if options[:remove_air_loops] then model.getAirLoopHVACs.each(&:remove) end
|
404
|
+
if options[:remove_exterior_lights] then model.getFacility.exteriorLights.each(&:remove) end
|
405
|
+
if options[:remove_site_shading] then model.getSite.shadingSurfaceGroups.each(&:remove) end
|
406
|
+
|
407
|
+
# see if plant loop is swh or not and take proper action (booter loop doesn't have water use equipment)
|
408
|
+
model.getPlantLoops.each do |plant_loop|
|
409
|
+
is_swh_loop = false
|
410
|
+
plant_loop.supplyComponents.each do |component|
|
411
|
+
if component.to_WaterHeaterMixed.is_initialized
|
412
|
+
is_swh_loop = true
|
413
|
+
next
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
if is_swh_loop
|
418
|
+
if options[:remove_swh_plant_loops] then plant_loop.remove end
|
419
|
+
else
|
420
|
+
if options[:remove_non_swh_plant_loops] then plant_loop.remove end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
# remove water use connections (may be removed when loop is removed)
|
425
|
+
if options[:remove_swh_plant_loops] then model.getWaterConnectionss.each(&:remove) end
|
426
|
+
if options[:remove_swh_plant_loops] then model.getWaterUseEquipments.each(&:remove) end
|
427
|
+
|
428
|
+
# remove building but reset fields on new building object.
|
429
|
+
building_fields = []
|
430
|
+
building = model.getBuilding
|
431
|
+
num_fields = building.numFields
|
432
|
+
num_fields.times.each do |i|
|
433
|
+
building_fields << building.getString(i).get
|
434
|
+
end
|
435
|
+
# removes spaces, space's child objects, thermal zones, zone equipment, non site surfaces, building stories and water use connections.
|
436
|
+
model.getBuilding.remove
|
437
|
+
building = model.getBuilding
|
438
|
+
num_fields.times.each do |i|
|
439
|
+
next if i == 0 # don't try and set handle
|
440
|
+
building_fields << building.setString(i, building_fields[i])
|
441
|
+
end
|
442
|
+
|
443
|
+
# other than optionally site shading and exterior lights not messing with site characteristics
|
444
|
+
|
445
|
+
if num_model_objects - model.objects.size > 0
|
446
|
+
runner.registerInfo("Removed #{num_model_objects - model.objects.size} non resource objects from the model.")
|
447
|
+
end
|
448
|
+
|
449
|
+
return true
|
450
|
+
end
|
451
|
+
|
452
|
+
# create_bar(runner,model,bar_hash)
|
453
|
+
# measures using this method should include OsLibGeometry and OsLibHelperMethods
|
454
|
+
def create_bar(runner, model, bar_hash, story_multiplier_method = 'Basements Ground Mid Top')
|
455
|
+
# warn about site shading
|
456
|
+
if !model.getSite.shadingSurfaceGroups.empty?
|
457
|
+
runner.registerWarning('The model has one or more site shading surafces. New geometry may not be positioned where expected, it will be centered over the center of the original geometry.')
|
458
|
+
end
|
459
|
+
|
460
|
+
# make custom story hash when number of stories below grade > 0
|
461
|
+
# todo - update this so have option basements are not below 0? (useful for simplifying existing model and maintaining z position relative to site shading)
|
462
|
+
story_hash = {}
|
463
|
+
eff_below = bar_hash[:num_stories_below_grade]
|
464
|
+
eff_above = bar_hash[:num_stories_above_grade]
|
465
|
+
footprint_origin = bar_hash[:center_of_footprint]
|
466
|
+
typical_story_height = bar_hash[:floor_height]
|
467
|
+
|
468
|
+
# flatten story_hash out to individual stories included in building area
|
469
|
+
stories_flat = []
|
470
|
+
stories_flat_counter = 0
|
471
|
+
bar_hash[:stories].each_with_index do |(k, v), i|
|
472
|
+
# k is invalid in some cases, old story object that has been removed, should be from low to high including basement
|
473
|
+
# skip if source story insn't included in building area
|
474
|
+
if v[:story_included_in_building_area].nil? || (v[:story_included_in_building_area] == true)
|
475
|
+
|
476
|
+
# add to counter
|
477
|
+
stories_flat_counter += v[:story_min_multiplier]
|
478
|
+
|
479
|
+
flat_hash = {}
|
480
|
+
flat_hash[:story_party_walls] = v[:story_party_walls]
|
481
|
+
flat_hash[:below_partial_story] = v[:below_partial_story]
|
482
|
+
flat_hash[:bottom_story_ground_exposed_floor] = v[:bottom_story_ground_exposed_floor]
|
483
|
+
flat_hash[:top_story_exterior_exposed_roof] = v[:top_story_exterior_exposed_roof]
|
484
|
+
if i < eff_below
|
485
|
+
flat_hash[:story_type] = 'B'
|
486
|
+
flat_hash[:multiplier] = 1
|
487
|
+
elsif i == eff_below
|
488
|
+
flat_hash[:story_type] = 'Ground'
|
489
|
+
flat_hash[:multiplier] = 1
|
490
|
+
elsif stories_flat_counter == eff_below + eff_above.ceil
|
491
|
+
flat_hash[:story_type] = 'Top'
|
492
|
+
flat_hash[:multiplier] = 1
|
493
|
+
else
|
494
|
+
flat_hash[:story_type] = 'Mid'
|
495
|
+
flat_hash[:multiplier] = v[:story_min_multiplier]
|
496
|
+
end
|
497
|
+
|
498
|
+
compare_hash = {}
|
499
|
+
if !stories_flat.empty?
|
500
|
+
stories_flat.last.each { |k, v| compare_hash[k] = flat_hash[k] if flat_hash[k] != v }
|
501
|
+
end
|
502
|
+
if (story_multiplier_method != 'None' && stories_flat.last == flat_hash) || (story_multiplier_method != 'None' && compare_hash.size == 1 && compare_hash.include?(:multiplier))
|
503
|
+
stories_flat.last[:multiplier] += v[:story_min_multiplier]
|
504
|
+
else
|
505
|
+
stories_flat << flat_hash
|
506
|
+
end
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
if bar_hash[:num_stories_below_grade] > 0
|
511
|
+
|
512
|
+
# add in below grade levels (may want to add below grade multipliers at some point if we start running deep basements)
|
513
|
+
eff_below.times do |i|
|
514
|
+
story_hash["B#{i + 1}"] = { space_origin_z: footprint_origin.z - typical_story_height * (i + 1), space_height: typical_story_height, multiplier: 1 }
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
# add in above grade levels
|
519
|
+
if eff_above > 2
|
520
|
+
story_hash['Ground'] = { space_origin_z: footprint_origin.z, space_height: typical_story_height, multiplier: 1 }
|
521
|
+
|
522
|
+
footprint_counter = 0
|
523
|
+
effective_stories_counter = 1
|
524
|
+
stories_flat.each do |hash|
|
525
|
+
next if hash[:story_type] != 'Mid'
|
526
|
+
if footprint_counter == 0
|
527
|
+
string = 'Mid'
|
528
|
+
else
|
529
|
+
string = "Mid#{footprint_counter + 1}"
|
530
|
+
end
|
531
|
+
story_hash[string] = { space_origin_z: footprint_origin.z + typical_story_height * effective_stories_counter + typical_story_height * (hash[:multiplier] - 1) / 2.0, space_height: typical_story_height, multiplier: hash[:multiplier] }
|
532
|
+
footprint_counter += 1
|
533
|
+
effective_stories_counter += hash[:multiplier]
|
534
|
+
end
|
535
|
+
|
536
|
+
story_hash['Top'] = { space_origin_z: footprint_origin.z + typical_story_height * (eff_above.ceil - 1), space_height: typical_story_height, multiplier: 1 }
|
537
|
+
elsif eff_above > 1
|
538
|
+
story_hash['Ground'] = { space_origin_z: footprint_origin.z, space_height: typical_story_height, multiplier: 1 }
|
539
|
+
story_hash['Top'] = { space_origin_z: footprint_origin.z + typical_story_height * (eff_above.ceil - 1), space_height: typical_story_height, multiplier: 1 }
|
540
|
+
else # one story only
|
541
|
+
story_hash['Ground'] = { space_origin_z: footprint_origin.z, space_height: typical_story_height, multiplier: 1 }
|
542
|
+
end
|
543
|
+
|
544
|
+
# create footprints
|
545
|
+
if bar_hash[:bar_division_method] == 'Multiple Space Types - Simple Sliced'
|
546
|
+
footprints = []
|
547
|
+
story_hash.size.times do |i|
|
548
|
+
# adjust size of bar of top story is not a full story
|
549
|
+
if i + 1 == story_hash.size
|
550
|
+
area_multiplier = (1.0 - bar_hash[:num_stories_above_grade].ceil + bar_hash[:num_stories_above_grade])
|
551
|
+
edge_multiplier = Math.sqrt(area_multiplier)
|
552
|
+
length = bar_hash[:length] * edge_multiplier
|
553
|
+
width = bar_hash[:width] * edge_multiplier
|
554
|
+
else
|
555
|
+
length = bar_hash[:length]
|
556
|
+
width = bar_hash[:width]
|
557
|
+
end
|
558
|
+
footprints << OsLib_Geometry.make_sliced_bar_simple_polygons(runner, bar_hash[:space_types], length, width, bar_hash[:center_of_footprint])
|
559
|
+
end
|
560
|
+
|
561
|
+
elsif bar_hash[:bar_division_method] == 'Multiple Space Types - Individual Stories Sliced'
|
562
|
+
|
563
|
+
# update story_hash for partial_story_above
|
564
|
+
story_hash.each_with_index do |(k, v), i|
|
565
|
+
# adjust size of bar of top story is not a full story
|
566
|
+
if i + 1 == story_hash.size
|
567
|
+
story_hash[k][:partial_story_multiplier] = (1.0 - bar_hash[:num_stories_above_grade].ceil + bar_hash[:num_stories_above_grade])
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
footprints = OsLib_Geometry.make_sliced_bar_multi_polygons(runner, bar_hash[:space_types], bar_hash[:length], bar_hash[:width], bar_hash[:center_of_footprint], story_hash)
|
572
|
+
|
573
|
+
else
|
574
|
+
footprints = []
|
575
|
+
story_hash.size.times do |i|
|
576
|
+
# adjust size of bar of top story is not a full story
|
577
|
+
if i + 1 == story_hash.size
|
578
|
+
area_multiplier = (1.0 - bar_hash[:num_stories_above_grade].ceil + bar_hash[:num_stories_above_grade])
|
579
|
+
edge_multiplier = Math.sqrt(area_multiplier)
|
580
|
+
length = bar_hash[:length] * edge_multiplier
|
581
|
+
width = bar_hash[:width] * edge_multiplier
|
582
|
+
else
|
583
|
+
length = bar_hash[:length]
|
584
|
+
width = bar_hash[:width]
|
585
|
+
end
|
586
|
+
footprints << OsLib_Geometry.make_core_and_perimeter_polygons(runner, length, width, bar_hash[:center_of_footprint]) # perimeter defaults to 15'
|
587
|
+
end
|
588
|
+
|
589
|
+
# set primary space type to building default space type
|
590
|
+
space_types = bar_hash[:space_types].sort_by { |k, v| v[:floor_area] }
|
591
|
+
model.getBuilding.setSpaceType(space_types.last.first)
|
592
|
+
|
593
|
+
end
|
594
|
+
|
595
|
+
# makeSpacesFromPolygons
|
596
|
+
OsLib_Geometry.makeSpacesFromPolygons(runner, model, footprints, bar_hash[:floor_height], bar_hash[:num_stories], bar_hash[:center_of_footprint], story_hash)
|
597
|
+
|
598
|
+
# put all of the spaces in the model into a vector for intersection and surface matching
|
599
|
+
spaces = OpenStudio::Model::SpaceVector.new
|
600
|
+
model.getSpaces.sort.each do |space|
|
601
|
+
spaces << space
|
602
|
+
end
|
603
|
+
|
604
|
+
# only intersect if make_mid_story_surfaces_adiabatic false
|
605
|
+
if !(bar_hash[:make_mid_story_surfaces_adiabatic])
|
606
|
+
# intersect surfaces
|
607
|
+
# (when bottom floor has many space types and one above doesn't will end up with heavily subdivided floor. Maybe use adiabatic and don't intersect floor/ceilings)
|
608
|
+
intersect_surfaces = true
|
609
|
+
if intersect_surfaces
|
610
|
+
OpenStudio::Model.intersectSurfaces(spaces)
|
611
|
+
runner.registerInfo('Intersecting surfaces, this will create additional geometry.')
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
# match surfaces for each space in the vector
|
616
|
+
OpenStudio::Model.matchSurfaces(spaces)
|
617
|
+
|
618
|
+
# set boundary conditions if not already set when geometry was created
|
619
|
+
# todo - update this to use space original z value vs. story name
|
620
|
+
if bar_hash[:num_stories_below_grade] > 0
|
621
|
+
model.getBuildingStorys.each do |story|
|
622
|
+
next if !story.name.to_s.include?('Story B')
|
623
|
+
story.spaces.each do |space|
|
624
|
+
space.surfaces.each do |surface|
|
625
|
+
next if surface.surfaceType != 'Wall'
|
626
|
+
next if surface.outsideBoundaryCondition != 'Outdoors'
|
627
|
+
surface.setOutsideBoundaryCondition('Ground')
|
628
|
+
end
|
629
|
+
end
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
633
|
+
# sort stories (by name for now but need better way)
|
634
|
+
# todo - need to change this so doesn't create issues when models have existing stories and spaces. Should be able to run it multiple times
|
635
|
+
sorted_stories = {}
|
636
|
+
model.getBuildingStorys.each do |story|
|
637
|
+
sorted_stories[story.name.to_s] = story
|
638
|
+
end
|
639
|
+
|
640
|
+
# flag space types that have wwr overrides
|
641
|
+
space_type_wwr_overrides = {}
|
642
|
+
|
643
|
+
# loop through building stories, spaces, and surfaces
|
644
|
+
sorted_stories.sort.each_with_index do |(key, story), i|
|
645
|
+
# flag for adiabatic floor if building doesn't have ground exposed floor
|
646
|
+
if stories_flat[i][:bottom_story_ground_exposed_floor] == false
|
647
|
+
adiabatic_floor = true
|
648
|
+
end
|
649
|
+
# flag for adiabatic roof if building doesn't have exterior exposed roof
|
650
|
+
if stories_flat[i][:top_story_exterior_exposed_roof] == false
|
651
|
+
adiabatic_ceiling = true
|
652
|
+
end
|
653
|
+
|
654
|
+
# make all mid story floor and celings adiabiatc if requested
|
655
|
+
if bar_hash[:make_mid_story_surfaces_adiabatic]
|
656
|
+
if i > 0
|
657
|
+
adiabatic_floor = true
|
658
|
+
end
|
659
|
+
if i < sorted_stories.size - 1
|
660
|
+
adiabatic_ceiling = true
|
661
|
+
end
|
662
|
+
end
|
663
|
+
|
664
|
+
# flag orientations for this story to recieve party walls
|
665
|
+
party_wall_facades = stories_flat[i][:story_party_walls]
|
666
|
+
|
667
|
+
story.spaces.each do |space|
|
668
|
+
space.surfaces. each do |surface|
|
669
|
+
# set floor to adiabatic if requited
|
670
|
+
if adiabatic_floor && surface.surfaceType == 'Floor'
|
671
|
+
make_surfaces_adiabatic([surface])
|
672
|
+
elsif adiabatic_ceiling && surface.surfaceType == 'RoofCeiling'
|
673
|
+
make_surfaces_adiabatic([surface])
|
674
|
+
end
|
675
|
+
|
676
|
+
# skip of not exterior wall
|
677
|
+
next if surface.surfaceType != 'Wall'
|
678
|
+
next if surface.outsideBoundaryCondition != 'Outdoors'
|
679
|
+
|
680
|
+
# get the absoluteAzimuth for the surface so we can categorize it
|
681
|
+
absoluteAzimuth = OpenStudio.convert(surface.azimuth, 'rad', 'deg').get + surface.space.get.directionofRelativeNorth + model.getBuilding.northAxis
|
682
|
+
absoluteAzimuth = absoluteAzimuth % 360.0 # should result in value between 0 and 360
|
683
|
+
absoluteAzimuth = absoluteAzimuth.round(5) # this was creating issues at 45 deg angles with opposing facades
|
684
|
+
|
685
|
+
# target wwr values that may be changed for specific space types
|
686
|
+
wwr_n = bar_hash[:building_wwr_n]
|
687
|
+
wwr_e = bar_hash[:building_wwr_e]
|
688
|
+
wwr_s = bar_hash[:building_wwr_s]
|
689
|
+
wwr_w = bar_hash[:building_wwr_w]
|
690
|
+
|
691
|
+
# look for space type specific wwr values
|
692
|
+
if surface.space.is_initialized && surface.space.get.spaceType.is_initialized
|
693
|
+
space_type = surface.space.get.spaceType.get
|
694
|
+
|
695
|
+
# see if space type has wwr value
|
696
|
+
bar_hash[:space_types].each do |k,v|
|
697
|
+
if v.has_key?(:space_type) && space_type == v[:space_type]
|
698
|
+
|
699
|
+
# if matching space type specifies a wwr then override the orientaiton specific recommendations for this surface.
|
700
|
+
if v.has_key?(:wwr)
|
701
|
+
wwr_n = v[:wwr]
|
702
|
+
wwr_e = v[:wwr]
|
703
|
+
wwr_s = v[:wwr]
|
704
|
+
wwr_w = v[:wwr]
|
705
|
+
space_type_wwr_overrides[space_type] = v[:wwr]
|
706
|
+
end
|
707
|
+
end
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
# add fenestration (wwr for now, maybe overhang and overhead doors later)
|
712
|
+
if (absoluteAzimuth >= 315.0) || (absoluteAzimuth < 45.0)
|
713
|
+
if party_wall_facades.include?('north')
|
714
|
+
make_surfaces_adiabatic([surface])
|
715
|
+
else
|
716
|
+
surface.setWindowToWallRatio(wwr_n)
|
717
|
+
end
|
718
|
+
elsif (absoluteAzimuth >= 45.0) && (absoluteAzimuth < 135.0)
|
719
|
+
if party_wall_facades.include?('east')
|
720
|
+
make_surfaces_adiabatic([surface])
|
721
|
+
else
|
722
|
+
surface.setWindowToWallRatio(wwr_e)
|
723
|
+
end
|
724
|
+
elsif (absoluteAzimuth >= 135.0) && (absoluteAzimuth < 225.0)
|
725
|
+
if party_wall_facades.include?('south')
|
726
|
+
make_surfaces_adiabatic([surface])
|
727
|
+
else
|
728
|
+
surface.setWindowToWallRatio(wwr_s)
|
729
|
+
end
|
730
|
+
elsif (absoluteAzimuth >= 225.0) && (absoluteAzimuth < 315.0)
|
731
|
+
if party_wall_facades.include?('west')
|
732
|
+
make_surfaces_adiabatic([surface])
|
733
|
+
else
|
734
|
+
surface.setWindowToWallRatio(wwr_w)
|
735
|
+
end
|
736
|
+
else
|
737
|
+
runner.registerError('Unexpected value of facade: ' + absoluteAzimuth + '.')
|
738
|
+
return false
|
739
|
+
end
|
740
|
+
end
|
741
|
+
end
|
742
|
+
end
|
743
|
+
|
744
|
+
# report space types with custom wwr values
|
745
|
+
space_type_wwr_overrides.each do |space_type,wwr|
|
746
|
+
runner.registerInfo("For #{space_type.name} the default building wwr was replaced with a space type specifc value of #{wwr}")
|
747
|
+
end
|
748
|
+
|
749
|
+
final_floor_area_ip = OpenStudio.convert(model.getBuilding.floorArea, 'm^2', 'ft^2').get
|
750
|
+
runner.registerInfo("Created Bar envlope with floor area of #{OpenStudio.toNeatString(final_floor_area_ip, 0, true)} (ft^2)")
|
751
|
+
end
|
752
|
+
|
753
|
+
# make selected surfaces adiabatic
|
754
|
+
def make_surfaces_adiabatic(surfaces)
|
755
|
+
surfaces.each do |surface|
|
756
|
+
if surface.construction.is_initialized
|
757
|
+
surface.setConstruction(surface.construction.get)
|
758
|
+
end
|
759
|
+
surface.setOutsideBoundaryCondition('Adiabatic')
|
760
|
+
end
|
761
|
+
end
|
762
|
+
|
763
|
+
# get length and width of rectangle matching bounding box aspect ratio will maintaining proper floor area
|
764
|
+
def calc_bar_reduced_bounding_box(envelope_data_hash)
|
765
|
+
bar = {}
|
766
|
+
|
767
|
+
bounding_length = envelope_data_hash[:building_max_xyz][0] - envelope_data_hash[:building_min_xyz][0]
|
768
|
+
bounding_width = envelope_data_hash[:building_max_xyz][1] - envelope_data_hash[:building_min_xyz][1]
|
769
|
+
bounding_area = bounding_length * bounding_width
|
770
|
+
footprint_area = envelope_data_hash[:building_floor_area] / envelope_data_hash[:effective__num_stories].to_f
|
771
|
+
area_multiplier = footprint_area / bounding_area
|
772
|
+
edge_multiplier = Math.sqrt(area_multiplier)
|
773
|
+
bar[:length] = bounding_length * edge_multiplier
|
774
|
+
bar[:width] = bounding_width * edge_multiplier
|
775
|
+
|
776
|
+
return bar
|
777
|
+
end
|
778
|
+
|
779
|
+
# get length and width of rectangle matching longer of two edges, and reducing the other way until floor area matches
|
780
|
+
def calc_bar_reduced_width(envelope_data_hash)
|
781
|
+
bar = {}
|
782
|
+
|
783
|
+
bounding_length = envelope_data_hash[:building_max_xyz][0] - envelope_data_hash[:building_min_xyz][0]
|
784
|
+
bounding_width = envelope_data_hash[:building_max_xyz][1] - envelope_data_hash[:building_min_xyz][1]
|
785
|
+
footprint_area = envelope_data_hash[:building_floor_area] / envelope_data_hash[:effective__num_stories].to_f
|
786
|
+
|
787
|
+
if bounding_length >= bounding_width
|
788
|
+
bar[:length] = bounding_length
|
789
|
+
bar[:width] = footprint_area / bounding_length
|
790
|
+
else
|
791
|
+
bar[:width] = bounding_width
|
792
|
+
bar[:length] = footprint_area / bounding_width
|
793
|
+
end
|
794
|
+
|
795
|
+
return bar
|
796
|
+
end
|
797
|
+
|
798
|
+
# get length and width of rectangle by stretching it until both floor area and exterior wall area or perimeter match
|
799
|
+
def calc_bar_stretched(envelope_data_hash)
|
800
|
+
bar = {}
|
801
|
+
|
802
|
+
bounding_length = envelope_data_hash[:building_max_xyz][0] - envelope_data_hash[:building_min_xyz][0]
|
803
|
+
bounding_width = envelope_data_hash[:building_max_xyz][1] - envelope_data_hash[:building_min_xyz][1]
|
804
|
+
a = envelope_data_hash[:building_floor_area] / envelope_data_hash[:effective__num_stories].to_f
|
805
|
+
p = envelope_data_hash[:building_perimeter]
|
806
|
+
|
807
|
+
if bounding_length >= bounding_width
|
808
|
+
bar[:length] = 0.25 * (p + Math.sqrt(p**2 - 16 * a))
|
809
|
+
bar[:width] = 0.25 * (p - Math.sqrt(p**2 - 16 * a))
|
810
|
+
else
|
811
|
+
bar[:length] = 0.25 * (p - Math.sqrt(p**2 - 16 * a))
|
812
|
+
bar[:width] = 0.25 * (p + Math.sqrt(p**2 - 16 * a))
|
813
|
+
end
|
814
|
+
|
815
|
+
return bar
|
816
|
+
end
|
817
|
+
end
|