openstudio-extension 0.2.3 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +33 -0
- data/README.md +10 -5
- data/init_templates/gemspec.txt +7 -5
- data/init_templates/template_gemfile.txt +1 -4
- data/lib/openstudio/extension.rb +24 -2
- data/lib/openstudio/extension/core/os_lib_geometry.rb +3 -3
- data/lib/openstudio/extension/core/os_lib_hvac.rb +17 -17
- data/lib/openstudio/extension/core/os_lib_model_generation.rb +87 -49
- data/lib/openstudio/extension/core/os_lib_model_simplification.rb +9 -9
- data/lib/openstudio/extension/core/os_lib_outdoorair_and_infiltration.rb +2 -2
- data/lib/openstudio/extension/rake_task.rb +32 -2
- data/lib/openstudio/extension/runner.rb +27 -12
- data/lib/openstudio/extension/runner_config.rb +3 -1
- data/lib/openstudio/extension/version.rb +1 -1
- data/openstudio-extension.gemspec +2 -2
- metadata +7 -8
- data/lib/openstudio/extension/core/os_lib_reporting.rb +0 -4755
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 14382dd7b9d2ea113c334dc5d478fc543e03c8cfd187e5d1ed702414e1e878cb
|
|
4
|
+
data.tar.gz: 2943baf83593784439ef8e1e4c656bacc1042666eede5f4e2836351c160a5009
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1b0ab92740d7232a7febfbea649b5d39a45f7b5a23b4f172ab0122c06aff38f6b6d692b3d0e7e44f85ca2f346b7afbc39de44c8b439431345a32b74b6cb3dadd
|
|
7
|
+
data.tar.gz: e81c0739957432be1ec8da8ea503a2daad939b36dc94faf21087c17c6871b4c633b02a788e84f7fff2faabbbda11c41b15220b62c2ad30b3d86e34601dea60c8
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# OpenStudio Extension Gem
|
|
2
2
|
|
|
3
|
+
## Version 0.3.2
|
|
4
|
+
|
|
5
|
+
* Update Extension Gem Template
|
|
6
|
+
* Add gemfile path instead of just dirname to the initialization
|
|
7
|
+
* Update to latest workflow gem to support URBANopt Workflow
|
|
8
|
+
|
|
9
|
+
## Version 0.3.1
|
|
10
|
+
|
|
11
|
+
* This change first zeroes-out latent (for good measure) and radiant fractions before setting lost fraction to 1.0 to avoid this error.
|
|
12
|
+
|
|
13
|
+
## Version 0.3.0
|
|
14
|
+
|
|
15
|
+
* remove the os_lib_reporting.rb helpers. This file is only used for OS reporting measure and should not be shared with other users.
|
|
16
|
+
* Upgrade dependency to openstudio-workflow gem to `~> 2.1.0`
|
|
17
|
+
* This version works only with EnergyPlus 9.4 since it depends on OpenStudio workflow `~> 2.1.0`
|
|
18
|
+
|
|
19
|
+
## Version 0.2.5
|
|
20
|
+
|
|
21
|
+
* Support runner options for bundle_install_path and gemfile_path
|
|
22
|
+
* Laboratory and Data Center Support
|
|
23
|
+
|
|
24
|
+
- Fixed [#71]( https://github.com/NREL/openstudio-extension-gem/pull/71 ), another fix for bcl rake tasks
|
|
25
|
+
- Fixed [#72]( https://github.com/NREL/openstudio-extension-gem/pull/72 ), Add laboratory and data centers to os_lib_model_generation
|
|
26
|
+
- Fixed [#74]( https://github.com/NREL/openstudio-extension-gem/pull/74 ), adding bundle path and gemfile path options
|
|
27
|
+
|
|
28
|
+
## Version 0.2.4
|
|
29
|
+
|
|
30
|
+
* Fixed upload of measures to BCL using rake tasks.
|
|
31
|
+
* Support economizer modeling when create_typical measure is split into two parts
|
|
32
|
+
|
|
33
|
+
Closed Issues: 1
|
|
34
|
+
- Fixed [#64]( https://github.com/NREL/openstudio-extension-gem/issues/64 ), README updates
|
|
35
|
+
|
|
3
36
|
## Version 0.2.3
|
|
4
37
|
|
|
5
38
|
* Use new version of rubocop style from S3
|
data/README.md
CHANGED
|
@@ -146,14 +146,17 @@ Common Rake Tasks that are available to derivative extension gems include:
|
|
|
146
146
|
|
|
147
147
|
| Rake Task | Description |
|
|
148
148
|
| --------- | ----------- |
|
|
149
|
+
| openstudio:bcl:test_login | Test BCL login |
|
|
150
|
+
| openstudio:bcl:search_measures | Search BCL |
|
|
151
|
+
| openstudio:bcl:stage[reset] | Copy the measures/components to a staging location |
|
|
152
|
+
| openstudio:bcl:push | Upload measures from the staging location |
|
|
153
|
+
| openstudio:change_log[start_date,end_date,apikey] | Print the change log from GitHub. Specify dates in yyyy-mm-dd format |
|
|
149
154
|
| openstudio:list_measures | List all measures in the calling gem |
|
|
150
155
|
| openstudio:measures:add_license | Add License File to measures in the calling gem |
|
|
151
156
|
| openstudio:measures:add_readme | Add README.md.erb file if it and the README markdown file do not already exist for a measure |
|
|
152
157
|
| openstudio:measures:copy_resources | Copy the resources files to individual measures in the calling gem |
|
|
153
158
|
| openstudio:measures:update_copyright | Update copyright on measure files in the calling gem |
|
|
154
159
|
| openstudio`:runner:`init | Create a runner.conf file running simulations |
|
|
155
|
-
| openstudio:stage_bcl | Copy the measures to a location that can be uploaded to BCL |
|
|
156
|
-
| openstudio:push_bcl | Upload measures from the specified location to the BCL |
|
|
157
160
|
| openstudio:test_with_docker | Use openstudio docker image to run tests |
|
|
158
161
|
| openstudio:test_with_openstudio | Use openstudio system ruby to run tests |
|
|
159
162
|
| openstudio:update_measures | Run the CLI task to check for measure updates and update the measure xml files |
|
|
@@ -176,8 +179,12 @@ The following table contains all current extension gems.
|
|
|
176
179
|
| OpenStudio Common Measures Gem | openstudio-common-measures | https://github.com/NREL/openstudio-common-measures-gem |
|
|
177
180
|
| OpenStudio Model Articulation Gem | openstudio-model-articulation | https://github.com/NREL/openstudio-model-articulation-gem |
|
|
178
181
|
| OpenStudio AEDG Gem | openstudio-aedg | https://github.com/NREL/openstudio-aedg-gem |
|
|
182
|
+
| OpenStudio Calibration Gem | openstudio-calibration | https://github.com/NREL/openstudio-calibration-gem |
|
|
183
|
+
| OpenStudio EE Gem | openstudio-ee | https://github.com/NREL/openstudio-ee-gem |
|
|
179
184
|
| OpenStudio District Systems Gem | openstudio-district-systems | https://github.com/NREL/openstudio-district-systems-gem |
|
|
180
|
-
|
|
|
185
|
+
| URBANopt Core Gem | urbanopt-core | https://github.com/urbanopt/urbanopt-core-gem |
|
|
186
|
+
| URBANopt GeoJSON Gem | urbanopt-geojson | https://github.com/urbanopt/urbanopt-geojson-gem |
|
|
187
|
+
| URBANopt Scenario Gem | urbanopt-scenario | https://github.com/urbanopt/urbanopt-scenario-gem |
|
|
181
188
|
| BuildingSync Gem | buildingsync | https://github.com/BuildingSync/BuildingSync-gem |
|
|
182
189
|
|
|
183
190
|
### Initializing a new Extension Gem
|
|
@@ -236,8 +243,6 @@ Or install it yourself as:
|
|
|
236
243
|
|
|
237
244
|
# TODO
|
|
238
245
|
|
|
239
|
-
- [ ] Rake task ```stage_bcl``` _DLM: BCL gem should be a development dependency only until we can reduce its dependencies and remove native dependencies? should probably put it into a special group so we can bundle without it in openstudio-gems._
|
|
240
|
-
- [ ] Rake task ```push_bcl``` _DLM: how do we want to test this?
|
|
241
246
|
- [ ] Capture useful output from Travis (measure dashboard results, log files, zip of build products, etc) and put it somewhere (s3? naming convention?)
|
|
242
247
|
- [ ] ```Extension::files_dir``` _DLM: I think this can have a default implementation, right?_
|
|
243
248
|
- [ ] ```Extension::minimum_openstudio_version``` _DLM: should we rename? should people overwrite this in their class?_
|
data/init_templates/gemspec.txt
CHANGED
|
@@ -22,11 +22,13 @@ Gem::Specification.new do |spec|
|
|
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
23
23
|
spec.require_paths = ['lib']
|
|
24
24
|
|
|
25
|
-
spec.
|
|
26
|
-
|
|
27
|
-
spec.add_development_dependency '
|
|
25
|
+
spec.required_ruby_version = '~> 2.5.0'
|
|
26
|
+
|
|
27
|
+
spec.add_development_dependency 'bundler', '~> 2.1'
|
|
28
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
|
29
|
+
spec.add_development_dependency 'rspec', '~> 3.9'
|
|
28
30
|
spec.add_development_dependency 'rubocop', '~> 0.54.0'
|
|
29
31
|
|
|
30
|
-
spec.add_dependency 'openstudio-extension', '~> 0.1
|
|
31
|
-
spec.add_dependency 'openstudio-standards', '~> 0.2.
|
|
32
|
+
spec.add_dependency 'openstudio-extension', '~> 0.3.1'
|
|
33
|
+
spec.add_dependency 'openstudio-standards', '~> 0.2.12'
|
|
32
34
|
end
|
|
@@ -16,7 +16,4 @@ elsif allow_local
|
|
|
16
16
|
gem 'openstudio-extension', github: 'NREL/OpenStudio-extension-gem', branch: 'develop'
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
gem 'openstudio_measure_tester', '
|
|
20
|
-
|
|
21
|
-
# simplecov has an unnecessary dependency on native json gem, use fork that does not require this
|
|
22
|
-
gem 'simplecov', github: 'NREL/simplecov'
|
|
19
|
+
gem 'openstudio_measure_tester', '~> 0.2.3' # This includes the dependencies for running unit tests, coverage, and rubocop
|
data/lib/openstudio/extension.rb
CHANGED
|
@@ -91,6 +91,7 @@ module OpenStudio
|
|
|
91
91
|
|
|
92
92
|
result << obj
|
|
93
93
|
end
|
|
94
|
+
|
|
94
95
|
return result.uniq
|
|
95
96
|
end
|
|
96
97
|
|
|
@@ -105,7 +106,7 @@ module OpenStudio
|
|
|
105
106
|
result << dir if dir
|
|
106
107
|
rescue StandardError
|
|
107
108
|
end
|
|
108
|
-
return result.uniq
|
|
109
|
+
return result.uniq.sort
|
|
109
110
|
end
|
|
110
111
|
|
|
111
112
|
##
|
|
@@ -119,7 +120,7 @@ module OpenStudio
|
|
|
119
120
|
result << dir if dir
|
|
120
121
|
rescue StandardError
|
|
121
122
|
end
|
|
122
|
-
return result.uniq
|
|
123
|
+
return result.uniq.sort
|
|
123
124
|
end
|
|
124
125
|
|
|
125
126
|
##
|
|
@@ -226,5 +227,26 @@ module OpenStudio
|
|
|
226
227
|
|
|
227
228
|
return osw
|
|
228
229
|
end
|
|
230
|
+
|
|
231
|
+
##
|
|
232
|
+
# Module method used to check whether a measure is present in an OSW file
|
|
233
|
+
##
|
|
234
|
+
# @param [Hash] in_osw Initial OSW object as a Hash, keys should be symbolized
|
|
235
|
+
# @param [String] measure_dir_name Directory name of measure to set argument on
|
|
236
|
+
# @param [String] step_name Optional argument, if present used to further identify the measure
|
|
237
|
+
#
|
|
238
|
+
# @return [Boolean] true or false
|
|
239
|
+
def self.measure_in_osw(osw, measure_dir_name, step_name = nil)
|
|
240
|
+
result = false
|
|
241
|
+
osw[:steps].each do |step|
|
|
242
|
+
if step[:measure_dir_name] == measure_dir_name
|
|
243
|
+
if step_name.nil? || step[:name] == step_name
|
|
244
|
+
result = true
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
return result
|
|
250
|
+
end
|
|
229
251
|
end
|
|
230
252
|
end
|
|
@@ -765,7 +765,7 @@ module OsLib_Geometry
|
|
|
765
765
|
story_hash.each_with_index do |(story_name, story_data), index|
|
|
766
766
|
# make new story unless story at requested height already exists.
|
|
767
767
|
story = nil
|
|
768
|
-
model.getBuildingStorys.each do |ext_story|
|
|
768
|
+
model.getBuildingStorys.sort.each do |ext_story|
|
|
769
769
|
if (ext_story.nominalZCoordinate.to_f - story_data[:space_origin_z].to_f).abs < 0.01
|
|
770
770
|
story = ext_story
|
|
771
771
|
end
|
|
@@ -1133,11 +1133,11 @@ module OsLib_Geometry
|
|
|
1133
1133
|
# todo - also odd with multi-height spaces
|
|
1134
1134
|
def self.calculate_perimeter(model)
|
|
1135
1135
|
perimeter = 0
|
|
1136
|
-
model.getSpaces.each do |space|
|
|
1136
|
+
model.getSpaces.sort.each do |space|
|
|
1137
1137
|
# counter to use later
|
|
1138
1138
|
edge_hash = {}
|
|
1139
1139
|
edge_counter = 0
|
|
1140
|
-
space.surfaces.each do |surface|
|
|
1140
|
+
space.surfaces.sort.each do |surface|
|
|
1141
1141
|
# get vertices
|
|
1142
1142
|
vertex_hash = {}
|
|
1143
1143
|
vertex_counter = 0
|
|
@@ -117,7 +117,7 @@ module OsLib_HVAC
|
|
|
117
117
|
zonesUnconditioned = []
|
|
118
118
|
|
|
119
119
|
# get thermal zones
|
|
120
|
-
zones = model.getThermalZones
|
|
120
|
+
zones = model.getThermalZones.sort
|
|
121
121
|
zones.each do |zone|
|
|
122
122
|
# assign appropriate zones to zonesPlenum or zonesUnconditioned (those that don't have thermostats or zone HVAC equipment)
|
|
123
123
|
# if not conditioned then add to zonesPlenum or zonesUnconditioned
|
|
@@ -177,9 +177,9 @@ module OsLib_HVAC
|
|
|
177
177
|
|
|
178
178
|
def self.reportConditions(model, runner, condition,extra_string = '')
|
|
179
179
|
|
|
180
|
-
airloops = model.getAirLoopHVACs
|
|
181
|
-
plantLoops = model.getPlantLoops
|
|
182
|
-
zones = model.getThermalZones
|
|
180
|
+
airloops = model.getAirLoopHVACs.sort
|
|
181
|
+
plantLoops = model.getPlantLoops.sort
|
|
182
|
+
zones = model.getThermalZones.sort
|
|
183
183
|
|
|
184
184
|
# count up zone equipment (not counting zone exhaust fans)
|
|
185
185
|
zoneHasEquip = false
|
|
@@ -205,9 +205,9 @@ module OsLib_HVAC
|
|
|
205
205
|
end
|
|
206
206
|
|
|
207
207
|
def self.removeEquipment(model, runner)
|
|
208
|
-
airloops = model.getAirLoopHVACs
|
|
209
|
-
plantLoops = model.getPlantLoops
|
|
210
|
-
zones = model.getThermalZones
|
|
208
|
+
airloops = model.getAirLoopHVACs.sort
|
|
209
|
+
plantLoops = model.getPlantLoops.sort
|
|
210
|
+
zones = model.getThermalZones.sort
|
|
211
211
|
|
|
212
212
|
# remove all airloops
|
|
213
213
|
airloops.each(&:remove)
|
|
@@ -244,7 +244,7 @@ module OsLib_HVAC
|
|
|
244
244
|
require "#{File.dirname(__FILE__)}/os_lib_schedules"
|
|
245
245
|
|
|
246
246
|
schedulesHVAC = {}
|
|
247
|
-
airloops = model.getAirLoopHVACs
|
|
247
|
+
airloops = model.getAirLoopHVACs.sort
|
|
248
248
|
|
|
249
249
|
# find airloop with most primary spaces
|
|
250
250
|
max_primary_spaces = 0
|
|
@@ -628,7 +628,7 @@ module OsLib_HVAC
|
|
|
628
628
|
|
|
629
629
|
# check for water-cooled chillers
|
|
630
630
|
waterCooledChiller = false
|
|
631
|
-
model.getChillerElectricEIRs.each do |chiller|
|
|
631
|
+
model.getChillerElectricEIRs.sort.each do |chiller|
|
|
632
632
|
next if waterCooledChiller == true
|
|
633
633
|
if chiller.condenserType == 'WaterCooled'
|
|
634
634
|
waterCooledChiller = true
|
|
@@ -678,7 +678,7 @@ module OsLib_HVAC
|
|
|
678
678
|
pipe_supply_outlet.addToNode(condenser_loop.supplyOutletNode)
|
|
679
679
|
setpoint_manager_follow_oa.addToNode(condenser_loop.supplyOutletNode)
|
|
680
680
|
# demand side components
|
|
681
|
-
model.getChillerElectricEIRs.each do |chiller|
|
|
681
|
+
model.getChillerElectricEIRs.sort.each do |chiller|
|
|
682
682
|
if chiller.condenserType == 'WaterCooled' # works only if chillers not already connected to condenser loop(s)
|
|
683
683
|
condenser_loop.addDemandBranchForComponent(chiller)
|
|
684
684
|
end
|
|
@@ -771,7 +771,7 @@ module OsLib_HVAC
|
|
|
771
771
|
primary_airloops = []
|
|
772
772
|
# create primary airloop for each story
|
|
773
773
|
assignedThermalZones = []
|
|
774
|
-
model.getBuildingStorys.each do |building_story|
|
|
774
|
+
model.getBuildingStorys.sort.each do |building_story|
|
|
775
775
|
# ML stories need to be reordered from the ground up
|
|
776
776
|
thermalZonesToAdd = []
|
|
777
777
|
building_story.spaces.each do |space|
|
|
@@ -1069,7 +1069,7 @@ module OsLib_HVAC
|
|
|
1069
1069
|
def self.createSecondaryAirLoops(model, runner, options)
|
|
1070
1070
|
secondary_airloops = []
|
|
1071
1071
|
# create secondary airloop for each secondary zone
|
|
1072
|
-
model.getThermalZones.each do |zone|
|
|
1072
|
+
model.getThermalZones.sort.each do |zone|
|
|
1073
1073
|
if options['zonesSecondary'].include? zone
|
|
1074
1074
|
# create secondary airloop
|
|
1075
1075
|
airloop_secondary = OpenStudio::Model::AirLoopHVAC.new(model)
|
|
@@ -1314,7 +1314,7 @@ module OsLib_HVAC
|
|
|
1314
1314
|
end
|
|
1315
1315
|
|
|
1316
1316
|
def self.createPrimaryZoneEquipment(model, runner, options)
|
|
1317
|
-
model.getThermalZones.each do |zone|
|
|
1317
|
+
model.getThermalZones.sort.each do |zone|
|
|
1318
1318
|
if options['zonesPrimary'].include? zone
|
|
1319
1319
|
if options['zoneHVAC'] == 'FanCoil'
|
|
1320
1320
|
# create fan coil
|
|
@@ -1521,7 +1521,7 @@ module OsLib_HVAC
|
|
|
1521
1521
|
def self.get_or_add_hot_water_loop(model)
|
|
1522
1522
|
# How water loop
|
|
1523
1523
|
hw_loop = nil
|
|
1524
|
-
model.getLoops.each do |loop|
|
|
1524
|
+
model.getLoops.sort.each do |loop|
|
|
1525
1525
|
if loop.name.to_s == 'Hot Water Loop' # sizingPlant has loopType method to do this better
|
|
1526
1526
|
hw_loop = loop.to_PlantLoop.get
|
|
1527
1527
|
end
|
|
@@ -1580,7 +1580,7 @@ module OsLib_HVAC
|
|
|
1580
1580
|
# Chilled Water Plant
|
|
1581
1581
|
# todo - add in logic here that if existing chw_loop is air cooled, replace it with this one.
|
|
1582
1582
|
chw_loop = nil
|
|
1583
|
-
model.getLoops.each do |loop|
|
|
1583
|
+
model.getLoops.sort.each do |loop|
|
|
1584
1584
|
if loop.name.to_s == 'Chilled Water Loop'
|
|
1585
1585
|
chw_loop = loop.to_PlantLoop.get
|
|
1586
1586
|
end
|
|
@@ -1658,7 +1658,7 @@ module OsLib_HVAC
|
|
|
1658
1658
|
|
|
1659
1659
|
# Condenser System
|
|
1660
1660
|
cw_loop = nil
|
|
1661
|
-
model.getLoops.each do |loop|
|
|
1661
|
+
model.getLoops.sort.each do |loop|
|
|
1662
1662
|
if loop.name.to_s == 'Condenser Water Loop'
|
|
1663
1663
|
cw_loop = loop.to_PlantLoop.get
|
|
1664
1664
|
end
|
|
@@ -1702,7 +1702,7 @@ module OsLib_HVAC
|
|
|
1702
1702
|
def self.get_or_add_air_cooled_chiller_loop(model)
|
|
1703
1703
|
# Chilled Water Plant
|
|
1704
1704
|
chw_loop = nil
|
|
1705
|
-
model.getLoops.each do |loop|
|
|
1705
|
+
model.getLoops.sort.each do |loop|
|
|
1706
1706
|
if loop.name.to_s == 'Chilled Water Loop'
|
|
1707
1707
|
chw_loop = loop.to_PlantLoop.get
|
|
1708
1708
|
end
|
|
@@ -79,6 +79,11 @@ module OsLib_ModelGeneration
|
|
|
79
79
|
array << 'Hospital'
|
|
80
80
|
array << 'Outpatient'
|
|
81
81
|
array << 'SuperMarket'
|
|
82
|
+
array << 'Laboratory'
|
|
83
|
+
array << 'LargeDataCenterLowITE'
|
|
84
|
+
array << 'LargeDataCenterHighITE'
|
|
85
|
+
array << 'SmallDataCenterLowITE'
|
|
86
|
+
array << 'SmallDataCenterHighITE'
|
|
82
87
|
|
|
83
88
|
return array
|
|
84
89
|
end
|
|
@@ -328,7 +333,7 @@ module OsLib_ModelGeneration
|
|
|
328
333
|
supermarket_a = 45001.0
|
|
329
334
|
supermarket_p = 866.0
|
|
330
335
|
supermarket_wwr = 1880.0 / (supermarket_p * 20.0)
|
|
331
|
-
|
|
336
|
+
supermarket_aspect_ratio = calc_aspect_ratio(supermarket_a, supermarket_p)
|
|
332
337
|
|
|
333
338
|
hash['SmallOffice'] = { aspect_ratio: 1.5, wwr: 0.15, typical_story: 10.0, perim_mult: 1.0 }
|
|
334
339
|
hash['MediumOffice'] = { aspect_ratio: 1.5, wwr: 0.33, typical_story: 13.0, perim_mult: 1.0 }
|
|
@@ -351,7 +356,14 @@ module OsLib_ModelGeneration
|
|
|
351
356
|
hash['MidriseApartment'] = { aspect_ratio: 2.75, wwr: 0.15, typical_story: 10.0, perim_mult: 1.0 }
|
|
352
357
|
hash['HighriseApartment'] = { aspect_ratio: 2.75, wwr: 0.15, typical_story: 10.0, perim_mult: 1.0 }
|
|
353
358
|
# SuperMarket inputs come from prototype model
|
|
354
|
-
hash['SuperMarket'] = { aspect_ratio:
|
|
359
|
+
hash['SuperMarket'] = { aspect_ratio: supermarket_aspect_ratio.round(1), wwr: supermarket_wwr.round(2), typical_story: 20.0, perim_mult: 1.0 }
|
|
360
|
+
|
|
361
|
+
# Add Laboratory and Data Centers
|
|
362
|
+
hash['Laboratory'] = { aspect_ratio: 1.33, wwr: 0.12, typical_story: 10.0, perim_mult: 1.0 }
|
|
363
|
+
hash['LargeDataCenterLowITE'] = { aspect_ratio: 1.67, wwr: 0.0, typical_story: 14.0, perim_mult: 1.0 }
|
|
364
|
+
hash['LargeDataCenterHighITE'] = { aspect_ratio: 1.67, wwr: 0.0, typical_story: 14.0, perim_mult: 1.0 }
|
|
365
|
+
hash['SmallDataCenterLowITE'] = { aspect_ratio: 1.5, wwr: 0.0, typical_story: 14.0, perim_mult: 1.0 }
|
|
366
|
+
hash['SmallDataCenterHighITE'] = { aspect_ratio: 1.5, wwr: 0.0, typical_story: 14.0, perim_mult: 1.0 }
|
|
355
367
|
|
|
356
368
|
# DEER Prototypes
|
|
357
369
|
hash['Asm'] = { aspect_ratio: 1.0, wwr: 0.19, typical_story: 15.0 }
|
|
@@ -664,6 +676,19 @@ module OsLib_ModelGeneration
|
|
|
664
676
|
hash['Meeting'] = { ratio: 0.99, space_type_gen: true, default: true }
|
|
665
677
|
hash['Restroom'] = { ratio: 0.99, space_type_gen: true, default: true }
|
|
666
678
|
hash['Vestibule'] = { ratio: 0.99, space_type_gen: true, default: true }
|
|
679
|
+
elsif building_type == 'Laboratory'
|
|
680
|
+
hash['Office'] = { ratio: 0.50, space_type_gen: true, default: true }
|
|
681
|
+
hash['Open lab'] = { ratio: 0.35, space_type_gen: true, default: true }
|
|
682
|
+
hash['Equipment corridor'] = { ratio: 0.05, space_type_gen: true, default: true }
|
|
683
|
+
hash['Lab with fume hood'] = { ratio: 0.10, space_type_gen: true, default: true }
|
|
684
|
+
elsif building_type == 'LargeDataCenterHighITE'
|
|
685
|
+
hash['StandaloneDataCenter'] = { ratio: 1.0, space_type_gen: true, default: true }
|
|
686
|
+
elsif building_type == 'LargeDataCenterLowITE'
|
|
687
|
+
hash['StandaloneDataCenter'] = { ratio: 1.0, space_type_gen: true, default: true }
|
|
688
|
+
elsif building_type == 'SmallDataCenterHighITE'
|
|
689
|
+
hash['ComputerRoom'] = { ratio: 1.0, space_type_gen: true, default: true }
|
|
690
|
+
elsif building_type == 'SmallDataCenterLowITE'
|
|
691
|
+
hash['ComputerRoom'] = { ratio: 1.0, space_type_gen: true, default: true }
|
|
667
692
|
# DEER Prototypes
|
|
668
693
|
elsif building_type == 'Asm'
|
|
669
694
|
hash['Auditorium'] = { ratio: 0.7658, space_type_gen: true, default: true }
|
|
@@ -884,6 +909,7 @@ module OsLib_ModelGeneration
|
|
|
884
909
|
stories_flat = []
|
|
885
910
|
stories_flat_counter = 0
|
|
886
911
|
bar_hash[:stories].each_with_index do |(k, v), i|
|
|
912
|
+
#runner.registerInfo("STORY: k: #{k}, v: #{v}, index: #{i}")
|
|
887
913
|
# k is invalid in some cases, old story object that has been removed, should be from low to high including basement
|
|
888
914
|
# skip if source story insn't included in building area
|
|
889
915
|
if v[:story_included_in_building_area].nil? || (v[:story_included_in_building_area] == true)
|
|
@@ -1024,7 +1050,7 @@ module OsLib_ModelGeneration
|
|
|
1024
1050
|
# only intersect if make_mid_story_surfaces_adiabatic false
|
|
1025
1051
|
if diagnostic_intersect
|
|
1026
1052
|
|
|
1027
|
-
model.getPlanarSurfaces.each do |surface|
|
|
1053
|
+
model.getPlanarSurfaces.sort.each do |surface|
|
|
1028
1054
|
array = []
|
|
1029
1055
|
vertices = surface.vertices
|
|
1030
1056
|
fixed = false
|
|
@@ -1050,7 +1076,7 @@ module OsLib_ModelGeneration
|
|
|
1050
1076
|
end
|
|
1051
1077
|
|
|
1052
1078
|
# remove collinear points in a surface
|
|
1053
|
-
model.getPlanarSurfaces.each do |surface|
|
|
1079
|
+
model.getPlanarSurfaces.sort.each do |surface|
|
|
1054
1080
|
new_vertices = OpenStudio.removeCollinear(surface.vertices)
|
|
1055
1081
|
starting_count = surface.vertices.size
|
|
1056
1082
|
final_count = new_vertices.size
|
|
@@ -1061,7 +1087,7 @@ module OsLib_ModelGeneration
|
|
|
1061
1087
|
end
|
|
1062
1088
|
|
|
1063
1089
|
# remove duplicate surfaces in a space (should be done after remove duplicate and collinear points)
|
|
1064
|
-
model.getSpaces.each do |space|
|
|
1090
|
+
model.getSpaces.sort.each do |space|
|
|
1065
1091
|
|
|
1066
1092
|
# secondary array to compare against
|
|
1067
1093
|
surfaces_b = space.surfaces.sort
|
|
@@ -1105,7 +1131,7 @@ module OsLib_ModelGeneration
|
|
|
1105
1131
|
end
|
|
1106
1132
|
runner.registerInfo('Intersecting and matching surfaces in model, this will create additional geometry.')
|
|
1107
1133
|
else #elsif bar_hash[:double_loaded_corridor] # only intersect spaces in each story, not between wtory
|
|
1108
|
-
model.getBuilding.buildingStories.each do |story|
|
|
1134
|
+
model.getBuilding.buildingStories.sort.each do |story|
|
|
1109
1135
|
# intersect and surface match two pair by pair
|
|
1110
1136
|
spaces_b = story.spaces.sort
|
|
1111
1137
|
# looping through vector of each space
|
|
@@ -1136,7 +1162,7 @@ module OsLib_ModelGeneration
|
|
|
1136
1162
|
runner.registerInfo('Intersecting and matching surfaces in model, this will create additional geometry.')
|
|
1137
1163
|
end
|
|
1138
1164
|
else #elsif bar_hash[:double_loaded_corridor] # only intersect spaces in each story, not between wtory
|
|
1139
|
-
model.getBuilding.buildingStories.each do |story|
|
|
1165
|
+
model.getBuilding.buildingStories.sort.each do |story|
|
|
1140
1166
|
story_spaces = OpenStudio::Model::SpaceVector.new
|
|
1141
1167
|
story.spaces.sort.each do |space|
|
|
1142
1168
|
story_spaces << space
|
|
@@ -1152,11 +1178,11 @@ module OsLib_ModelGeneration
|
|
|
1152
1178
|
# set boundary conditions if not already set when geometry was created
|
|
1153
1179
|
# todo - update this to use space original z value vs. story name
|
|
1154
1180
|
if bar_hash[:num_stories_below_grade] > 0
|
|
1155
|
-
model.getBuildingStorys.each do |story|
|
|
1181
|
+
model.getBuildingStorys.sort.each do |story|
|
|
1156
1182
|
next if !story.name.to_s.include?('Story B')
|
|
1157
|
-
story.spaces.each do |space|
|
|
1183
|
+
story.spaces.sort.each do |space|
|
|
1158
1184
|
next if not new_spaces.include?(space)
|
|
1159
|
-
space.surfaces.each do |surface|
|
|
1185
|
+
space.surfaces.sort.each do |surface|
|
|
1160
1186
|
next if surface.surfaceType != 'Wall'
|
|
1161
1187
|
next if surface.outsideBoundaryCondition != 'Outdoors'
|
|
1162
1188
|
surface.setOutsideBoundaryCondition('Ground')
|
|
@@ -1621,10 +1647,7 @@ module OsLib_ModelGeneration
|
|
|
1621
1647
|
end
|
|
1622
1648
|
end
|
|
1623
1649
|
end
|
|
1624
|
-
|
|
1625
1650
|
end
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
1651
|
end
|
|
1629
1652
|
|
|
1630
1653
|
# bar_from_building_type_ratios
|
|
@@ -2354,7 +2377,7 @@ module OsLib_ModelGeneration
|
|
|
2354
2377
|
if args['party_wall_fraction'] > 0
|
|
2355
2378
|
actual_ext_wall_area = model.getBuilding.exteriorWallArea
|
|
2356
2379
|
actual_party_wall_area = 0.0
|
|
2357
|
-
model.getSurfaces.each do |surface|
|
|
2380
|
+
model.getSurfaces.sort.each do |surface|
|
|
2358
2381
|
next if surface.outsideBoundaryCondition != 'Adiabatic'
|
|
2359
2382
|
next if surface.surfaceType != 'Wall'
|
|
2360
2383
|
actual_party_wall_area += surface.grossArea * surface.space.get.multiplier
|
|
@@ -2365,7 +2388,7 @@ module OsLib_ModelGeneration
|
|
|
2365
2388
|
end
|
|
2366
2389
|
|
|
2367
2390
|
# check ns/ew aspect ratio (harder to check when party walls are added)
|
|
2368
|
-
wall_and_window_by_orientation = OsLib_Geometry.getExteriorWindowAndWllAreaByOrientation(model,model.getSpaces)
|
|
2391
|
+
wall_and_window_by_orientation = OsLib_Geometry.getExteriorWindowAndWllAreaByOrientation(model,model.getSpaces.sort)
|
|
2369
2392
|
wall_ns = (wall_and_window_by_orientation['northWall'] + wall_and_window_by_orientation['southWall'])
|
|
2370
2393
|
wall_ew = wall_and_window_by_orientation['eastWall'] + wall_and_window_by_orientation['westWall']
|
|
2371
2394
|
wall_ns_ip = OpenStudio.convert(wall_ns,'m^2','ft^2').get
|
|
@@ -2560,6 +2583,19 @@ module OsLib_ModelGeneration
|
|
|
2560
2583
|
# Make the standard applier
|
|
2561
2584
|
standard = Standard.build((args['template']).to_s)
|
|
2562
2585
|
|
|
2586
|
+
# validate climate zone
|
|
2587
|
+
if !args.has_key?('climate_zone') || args['climate_zone'] == 'Lookup From Model'
|
|
2588
|
+
climate_zone = standard.model_get_building_climate_zone_and_building_type(model)['climate_zone']
|
|
2589
|
+
runner.registerInfo("Using climate zone #{climate_zone} from model")
|
|
2590
|
+
else
|
|
2591
|
+
climate_zone = args['climate_zone']
|
|
2592
|
+
runner.registerInfo("Using climate zone #{climate_zone} from user arguments")
|
|
2593
|
+
end
|
|
2594
|
+
if climate_zone == ''
|
|
2595
|
+
runner.registerError("Could not determine climate zone from measure arguments or model.")
|
|
2596
|
+
return false
|
|
2597
|
+
end
|
|
2598
|
+
|
|
2563
2599
|
# make sure daylight savings is turned on up prior to any sizing runs being done.
|
|
2564
2600
|
if args['enable_dst']
|
|
2565
2601
|
start_date = '2nd Sunday in March'
|
|
@@ -2575,7 +2611,7 @@ module OsLib_ModelGeneration
|
|
|
2575
2611
|
|
|
2576
2612
|
# remove internal loads
|
|
2577
2613
|
if args['remove_objects']
|
|
2578
|
-
model.getSpaceLoads.each do |instance|
|
|
2614
|
+
model.getSpaceLoads.sort.each do |instance|
|
|
2579
2615
|
next if instance.name.to_s.include?('Elevator') # most prototype building types model exterior elevators with name Elevator
|
|
2580
2616
|
next if instance.to_InternalMass.is_initialized
|
|
2581
2617
|
next if instance.to_WaterUseEquipment.is_initialized
|
|
@@ -2585,7 +2621,7 @@ module OsLib_ModelGeneration
|
|
|
2585
2621
|
model.getDefaultScheduleSets.each(&:remove)
|
|
2586
2622
|
end
|
|
2587
2623
|
|
|
2588
|
-
model.getSpaceTypes.each do |space_type|
|
|
2624
|
+
model.getSpaceTypes.sort.each do |space_type|
|
|
2589
2625
|
# Don't add infiltration here; will be added later in the script
|
|
2590
2626
|
test = standard.space_type_apply_internal_loads(space_type, true, true, true, true, true, false)
|
|
2591
2627
|
if test == false
|
|
@@ -2604,7 +2640,7 @@ module OsLib_ModelGeneration
|
|
|
2604
2640
|
|
|
2605
2641
|
# warn if spaces in model without space type
|
|
2606
2642
|
spaces_without_space_types = []
|
|
2607
|
-
model.getSpaces.each do |space|
|
|
2643
|
+
model.getSpaces.sort.each do |space|
|
|
2608
2644
|
next if space.spaceType.is_initialized
|
|
2609
2645
|
spaces_without_space_types << space
|
|
2610
2646
|
end
|
|
@@ -2615,7 +2651,7 @@ module OsLib_ModelGeneration
|
|
|
2615
2651
|
|
|
2616
2652
|
# identify primary building type (used for construction, and ideally HVAC as well)
|
|
2617
2653
|
building_types = {}
|
|
2618
|
-
model.getSpaceTypes.each do |space_type|
|
|
2654
|
+
model.getSpaceTypes.sort.each do |space_type|
|
|
2619
2655
|
# populate hash of building types
|
|
2620
2656
|
if space_type.standardsBuildingType.is_initialized
|
|
2621
2657
|
bldg_type = space_type.standardsBuildingType.get
|
|
@@ -2646,13 +2682,6 @@ module OsLib_ModelGeneration
|
|
|
2646
2682
|
else
|
|
2647
2683
|
is_residential = 'No'
|
|
2648
2684
|
end
|
|
2649
|
-
if !args.has_key?('climate_zone') || args['climate_zone'] == 'Lookup From Model'
|
|
2650
|
-
climate_zone = standard.model_get_building_climate_zone_and_building_type(model)['climate_zone']
|
|
2651
|
-
runner.registerInfo("Using climate zone #{climate_zone} from model")
|
|
2652
|
-
else
|
|
2653
|
-
climate_zone = args['climate_zone']
|
|
2654
|
-
runner.registerInfo("Using climate zone #{climate_zone} from user arguments")
|
|
2655
|
-
end
|
|
2656
2685
|
bldg_def_const_set = standard.model_add_construction_set(model, climate_zone, lookup_building_type, nil, is_residential)
|
|
2657
2686
|
if bldg_def_const_set.is_initialized
|
|
2658
2687
|
bldg_def_const_set = bldg_def_const_set.get
|
|
@@ -2666,7 +2695,7 @@ module OsLib_ModelGeneration
|
|
|
2666
2695
|
end
|
|
2667
2696
|
|
|
2668
2697
|
# address any adiabatic surfaces that don't have hard assigned constructions
|
|
2669
|
-
model.getSurfaces.each do |surface|
|
|
2698
|
+
model.getSurfaces.sort.each do |surface|
|
|
2670
2699
|
next if surface.outsideBoundaryCondition != 'Adiabatic'
|
|
2671
2700
|
next if surface.construction.is_initialized
|
|
2672
2701
|
surface.setAdjacentSurface(surface)
|
|
@@ -2690,11 +2719,11 @@ module OsLib_ModelGeneration
|
|
|
2690
2719
|
if args['add_elevators']
|
|
2691
2720
|
|
|
2692
2721
|
# remove elevators as spaceLoads or exteriorLights
|
|
2693
|
-
model.getSpaceLoads.each do |instance|
|
|
2722
|
+
model.getSpaceLoads.sort.each do |instance|
|
|
2694
2723
|
next if !instance.name.to_s.include?('Elevator') # most prototype building types model exterior elevators with name Elevator
|
|
2695
2724
|
instance.remove
|
|
2696
2725
|
end
|
|
2697
|
-
model.getExteriorLightss.each do |ext_light|
|
|
2726
|
+
model.getExteriorLightss.sort.each do |ext_light|
|
|
2698
2727
|
next if !ext_light.name.to_s.include?('Fuel equipment') # some prototype building types model exterior elevators by this name
|
|
2699
2728
|
ext_light.remove
|
|
2700
2729
|
end
|
|
@@ -2706,8 +2735,9 @@ module OsLib_ModelGeneration
|
|
|
2706
2735
|
elevator_def = elevators.electricEquipmentDefinition
|
|
2707
2736
|
design_level = elevator_def.designLevel.get
|
|
2708
2737
|
runner.registerInfo("Adding #{elevators.multiplier.round(1)} elevators each with power of #{OpenStudio.toNeatString(design_level, 0, true)} (W), plus lights and fans.")
|
|
2709
|
-
elevator_def.
|
|
2738
|
+
elevator_def.setFractionLatent(0.0)
|
|
2710
2739
|
elevator_def.setFractionRadiant(0.0)
|
|
2740
|
+
elevator_def.setFractionLost(1.0)
|
|
2711
2741
|
end
|
|
2712
2742
|
end
|
|
2713
2743
|
|
|
@@ -2715,7 +2745,7 @@ module OsLib_ModelGeneration
|
|
|
2715
2745
|
if args['add_exterior_lights']
|
|
2716
2746
|
|
|
2717
2747
|
if args['remove_objects']
|
|
2718
|
-
model.getExteriorLightss.each do |ext_light|
|
|
2748
|
+
model.getExteriorLightss.sort.each do |ext_light|
|
|
2719
2749
|
next if ext_light.name.to_s.include?('Fuel equipment') # some prototype building types model exterior elevators by this name
|
|
2720
2750
|
ext_light.remove
|
|
2721
2751
|
end
|
|
@@ -2797,16 +2827,25 @@ module OsLib_ModelGeneration
|
|
|
2797
2827
|
end
|
|
2798
2828
|
end
|
|
2799
2829
|
|
|
2800
|
-
#
|
|
2830
|
+
# add_daylighting_controls (since outdated measure don't have this default to true if arg not found)
|
|
2831
|
+
if !args.has_key?('add_daylighting_controls')
|
|
2832
|
+
args['add_daylighting_controls'] = true
|
|
2833
|
+
end
|
|
2834
|
+
if args['add_daylighting_controls']
|
|
2835
|
+
# remove add_daylighting_controls objects
|
|
2836
|
+
if args['remove_objects']
|
|
2837
|
+
model.getDaylightingControls.each(&:remove)
|
|
2838
|
+
end
|
|
2801
2839
|
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2840
|
+
# add daylight controls, need to perform a sizing run for 2010
|
|
2841
|
+
if args['template'] == '90.1-2010'
|
|
2842
|
+
if standard.model_run_sizing_run(model, "#{Dir.pwd}/SRvt") == false
|
|
2843
|
+
log_messages_to_runner(runner, debug = true)
|
|
2844
|
+
return false
|
|
2845
|
+
end
|
|
2807
2846
|
end
|
|
2808
|
-
end
|
|
2809
2847
|
standard.model_add_daylighting_controls(model)
|
|
2848
|
+
end
|
|
2810
2849
|
|
|
2811
2850
|
# add refrigeration
|
|
2812
2851
|
if args['add_refrigeration']
|
|
@@ -2824,7 +2863,7 @@ module OsLib_ModelGeneration
|
|
|
2824
2863
|
if args['add_internal_mass']
|
|
2825
2864
|
|
|
2826
2865
|
if args['remove_objects']
|
|
2827
|
-
model.getSpaceLoads.each do |instance|
|
|
2866
|
+
model.getSpaceLoads.sort.each do |instance|
|
|
2828
2867
|
next unless instance.to_InternalMass.is_initialized
|
|
2829
2868
|
instance.remove
|
|
2830
2869
|
end
|
|
@@ -2847,7 +2886,7 @@ module OsLib_ModelGeneration
|
|
|
2847
2886
|
model.getThermostatSetpointDualSetpoints.each(&:remove)
|
|
2848
2887
|
end
|
|
2849
2888
|
|
|
2850
|
-
model.getSpaceTypes.each do |space_type|
|
|
2889
|
+
model.getSpaceTypes.sort.each do |space_type|
|
|
2851
2890
|
# create thermostat schedules
|
|
2852
2891
|
# skip un-recognized space types
|
|
2853
2892
|
next if standard.space_type_get_standards_data(space_type).empty?
|
|
@@ -2855,12 +2894,12 @@ module OsLib_ModelGeneration
|
|
|
2855
2894
|
standard.space_type_apply_internal_load_schedules(space_type, false, false, false, false, false, false, true)
|
|
2856
2895
|
|
|
2857
2896
|
# identify thermal thermostat and apply to zones (apply_internal_load_schedules names )
|
|
2858
|
-
model.getThermostatSetpointDualSetpoints.each do |thermostat|
|
|
2897
|
+
model.getThermostatSetpointDualSetpoints.sort.each do |thermostat|
|
|
2859
2898
|
next if thermostat.name.to_s != "#{space_type.name} Thermostat"
|
|
2860
2899
|
next if !thermostat.coolingSetpointTemperatureSchedule.is_initialized
|
|
2861
2900
|
next if !thermostat.heatingSetpointTemperatureSchedule.is_initialized
|
|
2862
2901
|
runner.registerInfo("Assigning #{thermostat.name} to thermal zones with #{space_type.name} assigned.")
|
|
2863
|
-
space_type.spaces.each do |space|
|
|
2902
|
+
space_type.spaces.sort.each do |space|
|
|
2864
2903
|
next if !space.thermalZone.is_initialized
|
|
2865
2904
|
space.thermalZone.get.setThermostatSetpointDualSetpoint(thermostat)
|
|
2866
2905
|
end
|
|
@@ -3038,7 +3077,7 @@ module OsLib_ModelGeneration
|
|
|
3038
3077
|
if args['add_internal_mass']
|
|
3039
3078
|
|
|
3040
3079
|
if args['remove_objects']
|
|
3041
|
-
model.getSpaceLoads.each do |instance|
|
|
3080
|
+
model.getSpaceLoads.sort.each do |instance|
|
|
3042
3081
|
next unless instance.to_InternalMass.is_initialized
|
|
3043
3082
|
instance.remove
|
|
3044
3083
|
end
|
|
@@ -3091,8 +3130,8 @@ module OsLib_ModelGeneration
|
|
|
3091
3130
|
set_building_defaults = runner.getBoolArgumentValue('set_building_defaults', user_arguments)
|
|
3092
3131
|
|
|
3093
3132
|
# reporting initial condition of model
|
|
3094
|
-
starting_spaceTypes = model.getSpaceTypes
|
|
3095
|
-
starting_constructionSets = model.getDefaultConstructionSets
|
|
3133
|
+
starting_spaceTypes = model.getSpaceTypes.sort
|
|
3134
|
+
starting_constructionSets = model.getDefaultConstructionSets.sort
|
|
3096
3135
|
runner.registerInitialCondition("The building started with #{starting_spaceTypes.size} space types and #{starting_constructionSets.size} construction sets.")
|
|
3097
3136
|
|
|
3098
3137
|
# lookup space types for specified building type (false indicates not to use whole building type only)
|
|
@@ -3129,7 +3168,7 @@ module OsLib_ModelGeneration
|
|
|
3129
3168
|
if create_space_types
|
|
3130
3169
|
|
|
3131
3170
|
# array of starting space types
|
|
3132
|
-
space_types_starting = model.getSpaceTypes
|
|
3171
|
+
space_types_starting = model.getSpaceTypes.sort
|
|
3133
3172
|
|
|
3134
3173
|
# create stub space types
|
|
3135
3174
|
space_type_hash.each do |space_type_name, hash|
|
|
@@ -3242,11 +3281,10 @@ module OsLib_ModelGeneration
|
|
|
3242
3281
|
end
|
|
3243
3282
|
|
|
3244
3283
|
# reporting final condition of model
|
|
3245
|
-
finishing_spaceTypes = model.getSpaceTypes
|
|
3246
|
-
finishing_constructionSets = model.getDefaultConstructionSets
|
|
3284
|
+
finishing_spaceTypes = model.getSpaceTypes.sort
|
|
3285
|
+
finishing_constructionSets = model.getDefaultConstructionSets.sort
|
|
3247
3286
|
runner.registerFinalCondition("The building finished with #{finishing_spaceTypes.size} space types and #{finishing_constructionSets.size} construction sets.")
|
|
3248
3287
|
|
|
3249
3288
|
return true
|
|
3250
3289
|
end
|
|
3251
|
-
|
|
3252
3290
|
end
|