openstudio-extension 0.2.0 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +45 -1
- data/Jenkinsfile +2 -2
- data/README.md +22 -28
- data/Rakefile +1 -1
- data/lib/change_log.rb +138 -128
- data/lib/measures/openstudio_extension_test_measure/measure.xml +20 -19
- data/lib/openstudio/extension.rb +27 -10
- data/lib/openstudio/extension/core/CreateResults.rb +178 -1
- data/lib/openstudio/extension/core/os_lib_constructions.rb +6 -1
- data/lib/openstudio/extension/core/os_lib_geometry.rb +255 -77
- data/lib/openstudio/extension/core/os_lib_model_generation.rb +2547 -86
- data/lib/openstudio/extension/core/os_lib_reporting.rb +133 -30
- data/lib/openstudio/extension/rake_task.rb +232 -18
- data/lib/openstudio/extension/runner.rb +32 -19
- data/lib/openstudio/extension/runner_config.rb +16 -1
- data/lib/openstudio/extension/version.rb +1 -1
- data/openstudio-extension.gemspec +12 -12
- metadata +30 -33
- data/lib/measures/openstudio_extension_test_measure/tests/openstudio_extension_test_measure_test.rb +0 -74
- data/lib/openstudio/extension/core/os_lib_cofee.rb +0 -259
@@ -1,17 +1,18 @@
|
|
1
|
+
<?xml version="1.0"?>
|
1
2
|
<measure>
|
2
3
|
<schema_version>3.0</schema_version>
|
3
4
|
<name>openstudio_extension_test_measure</name>
|
4
5
|
<uid>36b99a29-41e1-4d85-9272-85d43b966e5a</uid>
|
5
|
-
<version_id>
|
6
|
-
<version_modified>
|
6
|
+
<version_id>edf7f103-9f51-4944-a5af-1d8fa2b0c9b7</version_id>
|
7
|
+
<version_modified>20200427T230714Z</version_modified>
|
7
8
|
<xml_checksum>49BEF039</xml_checksum>
|
8
9
|
<class_name>OpenStudioExtensionTestMeasure</class_name>
|
9
10
|
<display_name>OpenStudio Extension Test Measure</display_name>
|
10
|
-
<description>
|
11
|
-
<modeler_description>
|
12
|
-
<arguments/>
|
13
|
-
<outputs/>
|
14
|
-
<provenances/>
|
11
|
+
<description>A measure that tests OpenStudio Extension gem functionality</description>
|
12
|
+
<modeler_description>This is a test measure that tests OpenStudio Extension gem functionality.</modeler_description>
|
13
|
+
<arguments />
|
14
|
+
<outputs />
|
15
|
+
<provenances />
|
15
16
|
<tags>
|
16
17
|
<tag>Envelope.Form</tag>
|
17
18
|
</tags>
|
@@ -38,12 +39,6 @@
|
|
38
39
|
</attribute>
|
39
40
|
</attributes>
|
40
41
|
<files>
|
41
|
-
<file>
|
42
|
-
<filename>LICENSE.md</filename>
|
43
|
-
<filetype>md</filetype>
|
44
|
-
<usage_type>license</usage_type>
|
45
|
-
<checksum>9640B6CB</checksum>
|
46
|
-
</file>
|
47
42
|
<file>
|
48
43
|
<filename>README.md.erb</filename>
|
49
44
|
<filetype>erb</filetype>
|
@@ -51,16 +46,16 @@
|
|
51
46
|
<checksum>703C9964</checksum>
|
52
47
|
</file>
|
53
48
|
<file>
|
54
|
-
<filename>
|
49
|
+
<filename>LICENSE.md</filename>
|
55
50
|
<filetype>md</filetype>
|
56
|
-
<usage_type>
|
57
|
-
<checksum>
|
51
|
+
<usage_type>license</usage_type>
|
52
|
+
<checksum>E0468DD6</checksum>
|
58
53
|
</file>
|
59
54
|
<file>
|
60
55
|
<filename>OpenStudioExtensionTestMeasure_Test.rb</filename>
|
61
56
|
<filetype>rb</filetype>
|
62
57
|
<usage_type>test</usage_type>
|
63
|
-
<checksum>
|
58
|
+
<checksum>66A00EA8</checksum>
|
64
59
|
</file>
|
65
60
|
<file>
|
66
61
|
<version>
|
@@ -71,13 +66,19 @@
|
|
71
66
|
<filename>measure.rb</filename>
|
72
67
|
<filetype>rb</filetype>
|
73
68
|
<usage_type>script</usage_type>
|
74
|
-
<checksum>
|
69
|
+
<checksum>51BB85EF</checksum>
|
75
70
|
</file>
|
76
71
|
<file>
|
77
72
|
<filename>os_lib_helper_methods.rb</filename>
|
78
73
|
<filetype>rb</filetype>
|
79
74
|
<usage_type>resource</usage_type>
|
80
|
-
<checksum>
|
75
|
+
<checksum>07B01D67</checksum>
|
76
|
+
</file>
|
77
|
+
<file>
|
78
|
+
<filename>README.md</filename>
|
79
|
+
<filetype>md</filetype>
|
80
|
+
<usage_type>readme</usage_type>
|
81
|
+
<checksum>7258830F</checksum>
|
81
82
|
</file>
|
82
83
|
</files>
|
83
84
|
</measure>
|
data/lib/openstudio/extension.rb
CHANGED
@@ -101,11 +101,9 @@ module OpenStudio
|
|
101
101
|
def self.all_measure_dirs
|
102
102
|
result = []
|
103
103
|
all_extensions.each do |obj|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
rescue StandardError
|
108
|
-
end
|
104
|
+
dir = obj.new.measures_dir
|
105
|
+
result << dir if dir
|
106
|
+
rescue StandardError
|
109
107
|
end
|
110
108
|
return result.uniq
|
111
109
|
end
|
@@ -117,11 +115,9 @@ module OpenStudio
|
|
117
115
|
def self.all_file_dirs
|
118
116
|
result = []
|
119
117
|
all_extensions.each do |obj|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
rescue StandardError
|
124
|
-
end
|
118
|
+
dir = obj.new.files_dir
|
119
|
+
result << dir if dir
|
120
|
+
rescue StandardError
|
125
121
|
end
|
126
122
|
return result.uniq
|
127
123
|
end
|
@@ -230,5 +226,26 @@ module OpenStudio
|
|
230
226
|
|
231
227
|
return osw
|
232
228
|
end
|
229
|
+
|
230
|
+
##
|
231
|
+
# Module method used to check whether a measure is present in an OSW file
|
232
|
+
##
|
233
|
+
# @param [Hash] in_osw Initial OSW object as a Hash, keys should be symbolized
|
234
|
+
# @param [String] measure_dir_name Directory name of measure to set argument on
|
235
|
+
# @param [String] step_name Optional argument, if present used to further identify the measure
|
236
|
+
#
|
237
|
+
# @return [Boolean] true or false
|
238
|
+
def self.measure_in_osw(osw, measure_dir_name, step_name = nil)
|
239
|
+
result = false
|
240
|
+
osw[:steps].each do |step|
|
241
|
+
if step[:measure_dir_name] == measure_dir_name
|
242
|
+
if step_name.nil? || step[:name] == step_name
|
243
|
+
result = true
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
return result
|
249
|
+
end
|
233
250
|
end
|
234
251
|
end
|
@@ -45,6 +45,23 @@ module OsLib_CreateResults
|
|
45
45
|
# @param end_mo [String] the end month for the peak demand window
|
46
46
|
# @param end_day [Integer] the end day for the peak demand window
|
47
47
|
# @param end_hr [Integer] the end hour for the peak demand window, using 24-hr clock
|
48
|
+
# @param electricity_consumption_tou_periods [Array<Hash>] optional array of hashes to add
|
49
|
+
# time-of-use electricity consumption values to the annual consumption information.
|
50
|
+
# Periods may overlap, but should be listed in the order in which they must be checked,
|
51
|
+
# where the value will be assigned to the first encountered period it falls into.
|
52
|
+
# An example hash looks like this:
|
53
|
+
# {
|
54
|
+
# 'tou_name' => 'system_peak',
|
55
|
+
# 'tou_id' => 1,
|
56
|
+
# 'skip_weekends' => true,
|
57
|
+
# 'skip_holidays' => true,
|
58
|
+
# 'start_mo' => 'July',
|
59
|
+
# 'start_day' => 1,
|
60
|
+
# 'start_hr' => 14,
|
61
|
+
# 'end_mo' => 'August',
|
62
|
+
# 'end_day' => 31,
|
63
|
+
# 'end_hr' => 18
|
64
|
+
# }
|
48
65
|
# @return [OpenStudio::AttributeVector] a vector of results needed by EDAPT
|
49
66
|
def create_results(skip_weekends = true,
|
50
67
|
skip_holidays = true,
|
@@ -53,7 +70,8 @@ module OsLib_CreateResults
|
|
53
70
|
start_hr = 14,
|
54
71
|
end_mo = 'September',
|
55
72
|
end_day = 30,
|
56
|
-
end_hr = 18
|
73
|
+
end_hr = 18,
|
74
|
+
electricity_consumption_tou_periods = [])
|
57
75
|
|
58
76
|
# get the current version of OS being used to determine if sql query
|
59
77
|
# changes are needed (for when E+ changes).
|
@@ -497,6 +515,83 @@ module OsLib_CreateResults
|
|
497
515
|
@runner.registerValue('annual_demand_electricity_peak_demand', 0.0, 'kW')
|
498
516
|
end
|
499
517
|
|
518
|
+
# Describe the TOU periods
|
519
|
+
electricity_consumption_tou_periods.each do |tou_pd|
|
520
|
+
@runner.registerInfo("TOU period #{tou_pd['tou_id']} represents #{tou_pd['tou_name']} and covers #{tou_pd['start_mo']}-#{tou_pd['start_day']} to #{tou_pd['end_mo']}-#{tou_pd['end_day']} from #{tou_pd['start_hr']} to #{tou_pd['end_hr']}, skip weekends = #{tou_pd['skip_weekends']}, skip holidays = #{tou_pd['skip_holidays']}")
|
521
|
+
end
|
522
|
+
|
523
|
+
# electricity time-of-use periods
|
524
|
+
elec = @sql.timeSeries(ann_env_pd, 'Zone Timestep', 'Electricity:Facility', '')
|
525
|
+
if elec.is_initialized && day_types
|
526
|
+
elec = elec.get
|
527
|
+
# Put timeseries into array
|
528
|
+
elec_vals = []
|
529
|
+
ann_elec_vals = elec.values
|
530
|
+
for i in 0..(ann_elec_vals.size - 1)
|
531
|
+
elec_vals << ann_elec_vals[i]
|
532
|
+
end
|
533
|
+
|
534
|
+
# Put values into array
|
535
|
+
elec_times = []
|
536
|
+
ann_elec_times = elec.dateTimes
|
537
|
+
for i in 0..(ann_elec_times.size - 1)
|
538
|
+
elec_times << ann_elec_times[i]
|
539
|
+
end
|
540
|
+
|
541
|
+
# Loop through the time/value pairs and find the peak
|
542
|
+
# excluding the times outside of the Xcel peak demand window
|
543
|
+
electricity_tou_vals = Hash.new(0)
|
544
|
+
elec_times.zip(elec_vals).each_with_index do |vs, ind|
|
545
|
+
date_time = vs[0]
|
546
|
+
joules = vs[1]
|
547
|
+
day_type = day_types[ind]
|
548
|
+
time = date_time.time
|
549
|
+
date = date_time.date
|
550
|
+
|
551
|
+
# puts("#{val_kW}kW; #{date}; #{time}; #{day_of_week.valueName}")
|
552
|
+
|
553
|
+
# Determine which TOU period this hour falls into
|
554
|
+
tou_period_assigned = false
|
555
|
+
electricity_consumption_tou_periods.each do |tou_pd|
|
556
|
+
pd_start_date = OpenStudio::DateTime.new(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(tou_pd['start_mo']), tou_pd['start_day'], timeseries_yr), OpenStudio::Time.new(0, 0, 0, 0))
|
557
|
+
pd_end_date = OpenStudio::DateTime.new(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(tou_pd['end_mo']), tou_pd['end_day'], timeseries_yr), OpenStudio::Time.new(0, 24, 0, 0))
|
558
|
+
pd_start_time = OpenStudio::Time.new(0, tou_pd['start_hr'], 0, 0)
|
559
|
+
pd_end_time = OpenStudio::Time.new(0, tou_pd['end_hr'], 0, 0)
|
560
|
+
# Skip times outside of the correct months
|
561
|
+
next if date_time < pd_start_date || date_time > pd_end_date
|
562
|
+
# Skip times before some time and after another time
|
563
|
+
next if time < pd_start_time || time > pd_end_time
|
564
|
+
# Skip weekends if asked
|
565
|
+
if tou_pd['skip_weekends']
|
566
|
+
# Sunday = 1, Saturday = 7
|
567
|
+
next if day_type == 1 || day_type == 7
|
568
|
+
end
|
569
|
+
# Skip holidays if asked
|
570
|
+
if tou_pd['skip_holidays']
|
571
|
+
# Holiday = 8
|
572
|
+
next if day_type == 8
|
573
|
+
end
|
574
|
+
# If here, this hour falls into the specified period
|
575
|
+
tou_period_assigned = true
|
576
|
+
electricity_tou_vals[tou_pd['tou_id']] += joules
|
577
|
+
break
|
578
|
+
end
|
579
|
+
# Ensure that the value fell into a period
|
580
|
+
unless tou_period_assigned
|
581
|
+
@runner.registerError("Did not find a TOU period covering #{time} on #{date}, kWh will not be included in any TOU period.")
|
582
|
+
end
|
583
|
+
end
|
584
|
+
# Register values for any time-of-use period with kWh
|
585
|
+
electricity_tou_vals.each do |tou_pd_id, joules_in_pd|
|
586
|
+
gj_in_pd = OpenStudio.convert(joules_in_pd, 'J', 'GJ').get
|
587
|
+
kwh_in_pd = OpenStudio.convert(joules_in_pd, 'J', 'kWh').get
|
588
|
+
@runner.registerValue("annual_consumption_electricity_tou_#{tou_pd_id}", gj_in_pd, 'GJ')
|
589
|
+
@runner.registerInfo("TOU period #{tou_pd_id} annual electricity consumption = #{kwh_in_pd} kWh.")
|
590
|
+
end
|
591
|
+
else
|
592
|
+
@runner.registerError('Electricity timeseries (Electricity:Facility at zone timestep) could not be found, cannot determine the information needed to calculate savings or incentives.')
|
593
|
+
end
|
594
|
+
|
500
595
|
# electricity_annual_avg_peak_demand
|
501
596
|
val = @sql.electricityTotalEndUses
|
502
597
|
if val.is_initialized
|
@@ -587,6 +682,88 @@ module OsLib_CreateResults
|
|
587
682
|
@runner.registerValue('annual_demand_district_cooling_peak_demand', 0.0, 'kW')
|
588
683
|
end
|
589
684
|
|
685
|
+
# district cooling time-of-use periods
|
686
|
+
dist_clg = @sql.timeSeries(ann_env_pd, 'Zone Timestep', 'DistrictCooling:Facility', '')
|
687
|
+
if dist_clg.is_initialized && day_types
|
688
|
+
dist_clg = dist_clg.get
|
689
|
+
# Put timeseries into array
|
690
|
+
dist_clg_vals = []
|
691
|
+
ann_dist_clg_vals = dist_clg.values
|
692
|
+
for i in 0..(ann_dist_clg_vals.size - 1)
|
693
|
+
dist_clg_vals << ann_dist_clg_vals[i]
|
694
|
+
end
|
695
|
+
|
696
|
+
# Put values into array
|
697
|
+
dist_clg_times = []
|
698
|
+
ann_dist_clg_times = dist_clg.dateTimes
|
699
|
+
for i in 0..(ann_dist_clg_times.size - 1)
|
700
|
+
dist_clg_times << ann_dist_clg_times[i]
|
701
|
+
end
|
702
|
+
|
703
|
+
# Loop through the time/value pairs and find the peak
|
704
|
+
# excluding the times outside of the Xcel peak demand window
|
705
|
+
dist_clg_tou_vals = Hash.new(0)
|
706
|
+
dist_clg_times.zip(dist_clg_vals).each_with_index do |vs, ind|
|
707
|
+
date_time = vs[0]
|
708
|
+
joules = vs[1]
|
709
|
+
day_type = day_types[ind]
|
710
|
+
time = date_time.time
|
711
|
+
date = date_time.date
|
712
|
+
|
713
|
+
# puts("#{val_kW}kW; #{date}; #{time}; #{day_of_week.valueName}")
|
714
|
+
|
715
|
+
# Determine which TOU period this hour falls into
|
716
|
+
tou_period_assigned = false
|
717
|
+
electricity_consumption_tou_periods.each do |tou_pd|
|
718
|
+
pd_start_date = OpenStudio::DateTime.new(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(tou_pd['start_mo']), tou_pd['start_day'], timeseries_yr), OpenStudio::Time.new(0, 0, 0, 0))
|
719
|
+
pd_end_date = OpenStudio::DateTime.new(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(tou_pd['end_mo']), tou_pd['end_day'], timeseries_yr), OpenStudio::Time.new(0, 24, 0, 0))
|
720
|
+
pd_start_time = OpenStudio::Time.new(0, tou_pd['start_hr'], 0, 0)
|
721
|
+
pd_end_time = OpenStudio::Time.new(0, tou_pd['end_hr'], 0, 0)
|
722
|
+
# Skip times outside of the correct months
|
723
|
+
next if date_time < pd_start_date || date_time > pd_end_date
|
724
|
+
# Skip times before some time and after another time
|
725
|
+
next if time < pd_start_time || time > pd_end_time
|
726
|
+
# Skip weekends if asked
|
727
|
+
if tou_pd['skip_weekends']
|
728
|
+
# Sunday = 1, Saturday = 7
|
729
|
+
next if day_type == 1 || day_type == 7
|
730
|
+
end
|
731
|
+
# Skip holidays if asked
|
732
|
+
if tou_pd['skip_holidays']
|
733
|
+
# Holiday = 8
|
734
|
+
next if day_type == 8
|
735
|
+
end
|
736
|
+
# If here, this hour falls into the specified period
|
737
|
+
tou_period_assigned = true
|
738
|
+
dist_clg_tou_vals[tou_pd['tou_id']] += joules
|
739
|
+
break
|
740
|
+
end
|
741
|
+
# Ensure that the value fell into a period
|
742
|
+
unless tou_period_assigned
|
743
|
+
@runner.registerError("Did not find a TOU period covering #{time} on #{date}, kWh will not be included in any TOU period.")
|
744
|
+
end
|
745
|
+
end
|
746
|
+
# Register values for any time-of-use period with kWh
|
747
|
+
dist_clg_tou_vals.each do |tou_pd_id, joules_in_pd|
|
748
|
+
gj_in_pd = OpenStudio.convert(joules_in_pd, 'J', 'GJ').get
|
749
|
+
kwh_in_pd = OpenStudio.convert(joules_in_pd, 'J', 'kWh').get
|
750
|
+
@runner.registerValue("annual_consumption_district_cooling_tou_#{tou_pd_id}", gj_in_pd, 'GJ')
|
751
|
+
@runner.registerInfo("TOU period #{tou_pd_id} annual district cooling consumption = #{kwh_in_pd} kWh.")
|
752
|
+
end
|
753
|
+
else
|
754
|
+
# If TOU periods were specified but this model has no district cooling, report zeroes
|
755
|
+
if electricity_consumption_tou_periods.size > 0
|
756
|
+
# Get the TOU ids
|
757
|
+
tou_ids = []
|
758
|
+
electricity_consumption_tou_periods.each do |tou_pd|
|
759
|
+
tou_ids << tou_pd['tou_id']
|
760
|
+
end
|
761
|
+
tou_ids.uniq.each do |tou_id|
|
762
|
+
@runner.registerValue("annual_consumption_district_cooling_tou_#{tou_id}", 0.0, 'GJ')
|
763
|
+
end
|
764
|
+
end
|
765
|
+
end
|
766
|
+
|
590
767
|
else
|
591
768
|
@runner.registerError('Could not find an annual run period')
|
592
769
|
return OpenStudio::Attribute.new('report', result_elems)
|
@@ -283,7 +283,12 @@ module OsLib_Constructions
|
|
283
283
|
# create info message
|
284
284
|
if !runner.nil? # todo - need to look for bad visible transmittance here
|
285
285
|
uFactorSiToIpConversion = OpenStudio.convert(material.uFactor, 'W/m^2*K', 'Btu/ft^2*h*R').get
|
286
|
-
|
286
|
+
# version check to support 2.x and 3.x
|
287
|
+
if Gem::Version.new(OpenStudio::openStudioVersion) > Gem::Version.new("2.9.1")
|
288
|
+
runner.registerInfo("Created #{construction.name} construction. U-factor: #{OpenStudio.toNeatString(uFactorSiToIpConversion, 2, true)}(Btu/ft^2*h*R), SHGC: #{material.solarHeatGainCoefficient}, VT: #{material.getVisibleTransmittance.get}.")
|
289
|
+
else
|
290
|
+
runner.registerInfo("Created #{construction.name} construction. U-factor: #{OpenStudio.toNeatString(uFactorSiToIpConversion, 2, true)}(Btu/ft^2*h*R), SHGC: #{material.getSolarHeatGainCoefficient}, VT: #{material.getVisibleTransmittance.get}.")
|
291
|
+
end
|
287
292
|
end
|
288
293
|
|
289
294
|
result = construction
|
@@ -327,7 +327,8 @@ module OsLib_Geometry
|
|
327
327
|
end
|
328
328
|
|
329
329
|
# sort array by floor area, this hash will be altered to reduce floor area for each space type to 0
|
330
|
-
space_types_running_count = space_types.sort_by { |k, v| v[:floor_area] }
|
330
|
+
#space_types_running_count = space_types.sort_by { |k, v| v[:floor_area] }
|
331
|
+
space_types_running_count = space_types
|
331
332
|
|
332
333
|
# array entry for each story
|
333
334
|
footprints = []
|
@@ -354,8 +355,10 @@ module OsLib_Geometry
|
|
354
355
|
|
355
356
|
space_types_running_count.each do |space_type, space_type_hash|
|
356
357
|
# next if floor area is full or space type is empty
|
357
|
-
|
358
|
-
|
358
|
+
|
359
|
+
tol_value = 0.0001
|
360
|
+
next if current_footprint_area + tol_value >= target_footprint_area
|
361
|
+
next if space_type_hash[:floor_area] <= tol_value
|
359
362
|
|
360
363
|
# special test for when total floor area is smaller than valid_bar_area_min, just make bar smaller that valid min and warn user
|
361
364
|
if target_per_space_type[space_type] < valid_bar_area_min
|
@@ -367,20 +370,18 @@ module OsLib_Geometry
|
|
367
370
|
|
368
371
|
# add entry for space type if it doesn't have one yet
|
369
372
|
if !space_types_local_count.key?(space_type)
|
370
|
-
|
373
|
+
if space_type_hash.has_key?(:children)
|
374
|
+
space_type = space_type_hash[:children][:default][:space_type] # will re-using space type create issue
|
375
|
+
space_types_local_count[space_type] = { floor_area: 0.0 }
|
376
|
+
space_types_local_count[space_type][:children] = space_type_hash[:children]
|
377
|
+
else
|
378
|
+
space_types_local_count[space_type] = { floor_area: 0.0 }
|
379
|
+
end
|
371
380
|
end
|
372
381
|
|
373
382
|
# if there is enough of this space type to fill rest of floor area
|
374
383
|
remaining_in_footprint = target_footprint_area - current_footprint_area
|
375
|
-
|
376
|
-
|
377
|
-
# add to local count for story and remove from running count from space type
|
378
|
-
raw_footprint_area_used = remaining_in_footprint
|
379
|
-
|
380
|
-
else
|
381
|
-
# if not then use up the rest of the floor area and move on to next space type
|
382
|
-
raw_footprint_area_used = space_type_hash[:floor_area]
|
383
|
-
end
|
384
|
+
raw_footprint_area_used = [space_type_hash[:floor_area],remaining_in_footprint].min
|
384
385
|
|
385
386
|
# add to local hash
|
386
387
|
space_types_local_count[space_type][:floor_area] = raw_footprint_area_used / v[:multiplier].to_f
|
@@ -389,13 +390,13 @@ module OsLib_Geometry
|
|
389
390
|
current_footprint_area += raw_footprint_area_used
|
390
391
|
space_type_hash[:floor_area] -= raw_footprint_area_used
|
391
392
|
|
392
|
-
# test if think
|
393
|
+
# test if think sliver left on current floor.
|
393
394
|
# fix by moving smallest space type to next floor and and the same amount more of the sliver space type to this story
|
394
395
|
raw_footprint_area_used < valid_bar_area_min && sliver_override == false ? (test_a = true) : (test_a = false)
|
395
396
|
|
396
397
|
# test if what would be left of the current space type would result in a sliver on the next story.
|
397
398
|
# fix by removing some of this space type so their is enough left for the next story, and replace the removed amount with the largest space type in the model
|
398
|
-
(space_type_hash[:floor_area] < valid_bar_area_min) && (space_type_hash[:floor_area] >
|
399
|
+
(space_type_hash[:floor_area] < valid_bar_area_min) && (space_type_hash[:floor_area] > tol_value) ? (test_b = true) : (test_b = false)
|
399
400
|
|
400
401
|
# identify very small slices and re-arrange spaces to different stories to avoid this
|
401
402
|
if test_a
|
@@ -422,6 +423,10 @@ module OsLib_Geometry
|
|
422
423
|
|
423
424
|
# swap size
|
424
425
|
swap_size = valid_bar_area_min * 5 # currently equal to default perimeter zone depth of 15'
|
426
|
+
# this prevents too much area from being swapped resulting in a negative number for floor area
|
427
|
+
if swap_size > space_types_local_count[space_type][:floor_area] * v[:multiplier].to_f
|
428
|
+
swap_size = space_types_local_count[space_type][:floor_area] * v[:multiplier].to_f
|
429
|
+
end
|
425
430
|
|
426
431
|
# adjust running count for current space type
|
427
432
|
space_type_hash[:floor_area] += swap_size
|
@@ -445,12 +450,18 @@ module OsLib_Geometry
|
|
445
450
|
end
|
446
451
|
|
447
452
|
# sliced bar simple creates a single sliced bar for space types passed in
|
448
|
-
#
|
453
|
+
# look at length and width to adjust slicing direction
|
449
454
|
def self.make_sliced_bar_simple_polygons(runner, space_types, length, width, footprint_origin = OpenStudio::Point3d.new(0, 0, 0), perimeter_zone_depth = OpenStudio.convert(15, 'ft', 'm').get)
|
450
455
|
hash_of_point_vectors = {} # key is name, value is a hash, one item of which is polygon. Another could be space type
|
451
456
|
|
457
|
+
reverse_slice = false
|
458
|
+
if length < width
|
459
|
+
reverse_slice = true
|
460
|
+
#runner.registerInfo("reverse typical slice direction for bar because of aspect ratio less than 1.0.")
|
461
|
+
end
|
462
|
+
|
452
463
|
# determine if core and perimeter zoning can be used
|
453
|
-
if !(length > perimeter_zone_depth * 2.5 && width > perimeter_zone_depth * 2.5)
|
464
|
+
if !([length,width].min > perimeter_zone_depth * 2.5 && [length,width].min > perimeter_zone_depth * 2.5)
|
454
465
|
perimeter_zone_depth = 0 # if any size is to small then just model floor as single zone, issue warning
|
455
466
|
runner.registerWarning('Not modeling core and perimeter zones for some portion of the model.')
|
456
467
|
end
|
@@ -461,6 +472,7 @@ module OsLib_Geometry
|
|
461
472
|
# this represents the entire bar, not individual space type slices
|
462
473
|
nw_point = OpenStudio::Point3d.new(x_delta, y_delta + width, z)
|
463
474
|
sw_point = OpenStudio::Point3d.new(x_delta, y_delta, z)
|
475
|
+
se_point = OpenStudio::Point3d.new(x_delta + length, y_delta, z) # used when length is less than width
|
464
476
|
|
465
477
|
# total building floor area to calculate ratios from space type floor areas
|
466
478
|
total_floor_area = 0.0
|
@@ -470,7 +482,7 @@ module OsLib_Geometry
|
|
470
482
|
|
471
483
|
# sort array by floor area but shift largest object to front
|
472
484
|
space_types = space_types.sort_by { |k, v| v[:floor_area] }
|
473
|
-
space_types.insert(0, space_types.delete_at(space_types.size - 1))
|
485
|
+
space_types.insert(0, space_types.delete_at(space_types.size - 1)) #.to_h
|
474
486
|
|
475
487
|
# min and max bar end values
|
476
488
|
min_bar_end_multiplier = 0.75
|
@@ -484,20 +496,20 @@ module OsLib_Geometry
|
|
484
496
|
start_perimeter_width_deduction = 0.0
|
485
497
|
end_perimeter_width_deduction = 0.0
|
486
498
|
if space_type == space_types.first[0]
|
487
|
-
if length * space_type_hash[:floor_area] / total_floor_area > max_bar_end_multiplier * perimeter_zone_depth
|
499
|
+
if [length,width].max * space_type_hash[:floor_area] / total_floor_area > max_bar_end_multiplier * perimeter_zone_depth
|
488
500
|
start_perimeter_width_deduction = perimeter_zone_depth
|
489
501
|
end
|
490
502
|
# see if last space type is too small for perimeter. If it is then save some of this space type
|
491
|
-
if length * space_types.last[1][:floor_area] / total_floor_area < perimeter_zone_depth * min_bar_end_multiplier
|
503
|
+
if [length,width].max * space_types.last[1][:floor_area] / total_floor_area < perimeter_zone_depth * min_bar_end_multiplier
|
492
504
|
re_apply_largest_space_type_at_end = true
|
493
505
|
end
|
494
506
|
end
|
495
507
|
if space_type == space_types.last[0]
|
496
|
-
if length * space_type_hash[:floor_area] / total_floor_area > max_bar_end_multiplier * perimeter_zone_depth
|
508
|
+
if [length,width].max * space_type_hash[:floor_area] / total_floor_area > max_bar_end_multiplier * perimeter_zone_depth
|
497
509
|
end_perimeter_width_deduction = perimeter_zone_depth
|
498
510
|
end
|
499
511
|
end
|
500
|
-
non_end_adjusted_width = (length * space_type_hash[:floor_area] / total_floor_area) - start_perimeter_width_deduction - end_perimeter_width_deduction
|
512
|
+
non_end_adjusted_width = ([length,width].max * space_type_hash[:floor_area] / total_floor_area) - start_perimeter_width_deduction - end_perimeter_width_deduction
|
501
513
|
|
502
514
|
# adjustment of end space type is too small and is replaced with largest space type
|
503
515
|
if (space_type == space_types.first[0]) && re_apply_largest_space_type_at_end
|
@@ -506,69 +518,223 @@ module OsLib_Geometry
|
|
506
518
|
end
|
507
519
|
if (space_type == space_types.last[0]) && re_apply_largest_space_type_at_end
|
508
520
|
end_perimeter_width_deduction = space_types.first[0]
|
521
|
+
end_b_flag = true
|
522
|
+
else
|
523
|
+
end_b_flag = false
|
509
524
|
end
|
510
525
|
|
511
|
-
#
|
526
|
+
# populate data for core and perimeter of slice
|
512
527
|
section_hash_for_space_type = {}
|
513
528
|
section_hash_for_space_type['end_a'] = start_perimeter_width_deduction
|
514
529
|
section_hash_for_space_type[''] = non_end_adjusted_width
|
515
530
|
section_hash_for_space_type['end_b'] = end_perimeter_width_deduction
|
516
531
|
|
532
|
+
# determine if this space+type is double loaded corridor, and if so what the perimeter zone depth should be based on building width
|
533
|
+
# look at reverse_slice to see if length or width should be used to determine perimeter depth
|
534
|
+
if space_type_hash.has_key?(:children)
|
535
|
+
core_ratio = space_type_hash[:children][:circ][:orig_ratio]
|
536
|
+
perim_ratio = space_type_hash[:children][:default][:orig_ratio]
|
537
|
+
core_ratio_adj = core_ratio / (core_ratio + perim_ratio)
|
538
|
+
perim_ratio_adj = perim_ratio / (core_ratio + perim_ratio)
|
539
|
+
core_space_type = space_type_hash[:children][:circ][:space_type]
|
540
|
+
perim_space_type = space_type_hash[:children][:default][:space_type]
|
541
|
+
if !reverse_slice
|
542
|
+
custom_cor_val = width * core_ratio_adj
|
543
|
+
custom_perim_val = (width - custom_cor_val)/2.0
|
544
|
+
else
|
545
|
+
custom_cor_val = length * core_ratio_adj
|
546
|
+
custom_perim_val = (length - custom_cor_val)/2.0
|
547
|
+
end
|
548
|
+
actual_perim = custom_perim_val
|
549
|
+
double_loaded_corridor = true
|
550
|
+
else
|
551
|
+
actual_perim = perimeter_zone_depth
|
552
|
+
double_loaded_corridor = false
|
553
|
+
end
|
554
|
+
|
555
|
+
# may overwrite
|
556
|
+
first_space_type_hash = space_types.first[1]
|
557
|
+
if end_b_flag && first_space_type_hash.has_key?(:children)
|
558
|
+
end_b_core_ratio = first_space_type_hash[:children][:circ][:orig_ratio]
|
559
|
+
end_b_perim_ratio = first_space_type_hash[:children][:default][:orig_ratio]
|
560
|
+
end_b_core_ratio_adj = end_b_core_ratio / (end_b_core_ratio + end_b_perim_ratio)
|
561
|
+
end_b_perim_ratio_adj = end_b_perim_ratio / (end_b_core_ratio + end_b_perim_ratio)
|
562
|
+
end_b_core_space_type = first_space_type_hash[:children][:circ][:space_type]
|
563
|
+
end_b_perim_space_type = first_space_type_hash[:children][:default][:space_type]
|
564
|
+
if !reverse_slice
|
565
|
+
end_b_custom_cor_val = width * end_b_core_ratio_adj
|
566
|
+
end_b_custom_perim_val = (width - end_b_custom_cor_val)/2.0
|
567
|
+
else
|
568
|
+
end_b_custom_cor_val = length * end_b_core_ratio_adj
|
569
|
+
end_b_custom_perim_val = (length - end_b_custom_cor_val)/2.0
|
570
|
+
end
|
571
|
+
end_b_actual_perim = end_b_custom_perim_val
|
572
|
+
end_b_double_loaded_corridor = true
|
573
|
+
else
|
574
|
+
end_b_actual_perim = perimeter_zone_depth
|
575
|
+
end_b_double_loaded_corridor = false
|
576
|
+
end
|
577
|
+
|
517
578
|
# loop through sections for space type (main and possibly one or two end perimeter sections)
|
518
|
-
section_hash_for_space_type.each do |k,
|
519
|
-
|
520
|
-
|
579
|
+
section_hash_for_space_type.each do |k, slice|
|
580
|
+
|
581
|
+
# need to use different space type for end_b
|
582
|
+
if end_b_flag && k == "end_b" && space_types.first[1].has_key?(:children)
|
583
|
+
slice = space_types.first[0]
|
584
|
+
actual_perim = end_b_actual_perim
|
585
|
+
double_loaded_corridor = end_b_double_loaded_corridor
|
586
|
+
core_ratio = end_b_core_ratio
|
587
|
+
perim_ratio = end_b_perim_ratio
|
588
|
+
core_ratio_adj = end_b_core_ratio_adj
|
589
|
+
perim_ratio_adj = end_b_perim_ratio_adj
|
590
|
+
core_space_type = end_b_core_space_type
|
591
|
+
perim_space_type = end_b_perim_space_type
|
592
|
+
end
|
593
|
+
|
594
|
+
if slice.class.to_s == 'OpenStudio::Model::SpaceType' || slice.class.to_s == 'OpenStudio::Model::Building'
|
595
|
+
space_type = slice
|
521
596
|
max_reduction = [perimeter_zone_depth, max_reduction].min
|
522
|
-
|
597
|
+
slice = max_reduction
|
523
598
|
end
|
524
|
-
if
|
599
|
+
if slice == 0
|
525
600
|
next
|
526
601
|
end
|
527
602
|
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
603
|
+
if !reverse_slice
|
604
|
+
|
605
|
+
ne_point = nw_point + OpenStudio::Vector3d.new(slice, 0, 0)
|
606
|
+
se_point = sw_point + OpenStudio::Vector3d.new(slice, 0, 0)
|
607
|
+
|
608
|
+
if actual_perim > 0 && (actual_perim * 2.0) < width
|
609
|
+
polygon_a = OpenStudio::Point3dVector.new
|
610
|
+
polygon_a << sw_point
|
611
|
+
polygon_a << sw_point + OpenStudio::Vector3d.new(0, actual_perim, 0)
|
612
|
+
polygon_a << se_point + OpenStudio::Vector3d.new(0, actual_perim, 0)
|
613
|
+
polygon_a << se_point
|
614
|
+
if double_loaded_corridor
|
615
|
+
hash_of_point_vectors["#{perim_space_type.name} A #{k}"] = {}
|
616
|
+
hash_of_point_vectors["#{perim_space_type.name} A #{k}"][:space_type] = perim_space_type
|
617
|
+
hash_of_point_vectors["#{perim_space_type.name} A #{k}"][:polygon] = polygon_a
|
618
|
+
else
|
619
|
+
hash_of_point_vectors["#{space_type.name} A #{k}"] = {}
|
620
|
+
hash_of_point_vectors["#{space_type.name} A #{k}"][:space_type] = space_type
|
621
|
+
hash_of_point_vectors["#{space_type.name} A #{k}"][:polygon] = polygon_a
|
622
|
+
end
|
623
|
+
|
624
|
+
polygon_b = OpenStudio::Point3dVector.new
|
625
|
+
polygon_b << sw_point + OpenStudio::Vector3d.new(0, actual_perim, 0)
|
626
|
+
polygon_b << nw_point + OpenStudio::Vector3d.new(0, - actual_perim, 0)
|
627
|
+
polygon_b << ne_point + OpenStudio::Vector3d.new(0, - actual_perim, 0)
|
628
|
+
polygon_b << se_point + OpenStudio::Vector3d.new(0, actual_perim, 0)
|
629
|
+
if double_loaded_corridor
|
630
|
+
hash_of_point_vectors["#{core_space_type.name} B #{k}"] = {}
|
631
|
+
hash_of_point_vectors["#{core_space_type.name} B #{k}"][:space_type] = core_space_type
|
632
|
+
hash_of_point_vectors["#{core_space_type.name} B #{k}"][:polygon] = polygon_b
|
633
|
+
else
|
634
|
+
hash_of_point_vectors["#{space_type.name} B #{k}"] = {}
|
635
|
+
hash_of_point_vectors["#{space_type.name} B #{k}"][:space_type] = space_type
|
636
|
+
hash_of_point_vectors["#{space_type.name} B #{k}"][:polygon] = polygon_b
|
637
|
+
end
|
638
|
+
|
639
|
+
polygon_c = OpenStudio::Point3dVector.new
|
640
|
+
polygon_c << nw_point + OpenStudio::Vector3d.new(0, - actual_perim, 0)
|
641
|
+
polygon_c << nw_point
|
642
|
+
polygon_c << ne_point
|
643
|
+
polygon_c << ne_point + OpenStudio::Vector3d.new(0, - actual_perim, 0)
|
644
|
+
if double_loaded_corridor
|
645
|
+
hash_of_point_vectors["#{perim_space_type.name} C #{k}"] = {}
|
646
|
+
hash_of_point_vectors["#{perim_space_type.name} C #{k}"][:space_type] = perim_space_type
|
647
|
+
hash_of_point_vectors["#{perim_space_type.name} C #{k}"][:polygon] = polygon_c
|
648
|
+
else
|
649
|
+
hash_of_point_vectors["#{space_type.name} C #{k}"] = {}
|
650
|
+
hash_of_point_vectors["#{space_type.name} C #{k}"][:space_type] = space_type
|
651
|
+
hash_of_point_vectors["#{space_type.name} C #{k}"][:polygon] = polygon_c
|
652
|
+
end
|
653
|
+
else
|
654
|
+
polygon_a = OpenStudio::Point3dVector.new
|
655
|
+
polygon_a << sw_point
|
656
|
+
polygon_a << nw_point
|
657
|
+
polygon_a << ne_point
|
658
|
+
polygon_a << se_point
|
659
|
+
hash_of_point_vectors["#{space_type.name} #{k}"] = {}
|
660
|
+
hash_of_point_vectors["#{space_type.name} #{k}"][:space_type] = space_type
|
661
|
+
hash_of_point_vectors["#{space_type.name} #{k}"][:polygon] = polygon_a
|
662
|
+
end
|
663
|
+
|
664
|
+
# update west points
|
665
|
+
nw_point = ne_point
|
666
|
+
sw_point = se_point
|
667
|
+
|
558
668
|
else
|
559
|
-
polygon_a = OpenStudio::Point3dVector.new
|
560
|
-
polygon_a << sw_point
|
561
|
-
polygon_a << nw_point
|
562
|
-
polygon_a << ne_point
|
563
|
-
polygon_a << se_point
|
564
|
-
hash_of_point_vectors["#{space_type.name} #{k}"] = {}
|
565
|
-
hash_of_point_vectors["#{space_type.name} #{k}"][:space_type] = space_type
|
566
|
-
hash_of_point_vectors["#{space_type.name} #{k}"][:polygon] = polygon_a
|
567
|
-
end
|
568
669
|
|
569
|
-
|
570
|
-
|
571
|
-
|
670
|
+
# create_bar at 90 degrees if aspect ration is less than 1.0
|
671
|
+
# typical order (sw,nw,ne,se)
|
672
|
+
# order used here (se,sw,nw,ne)
|
673
|
+
|
674
|
+
nw_point = sw_point + OpenStudio::Vector3d.new(0, slice, 0)
|
675
|
+
ne_point = se_point + OpenStudio::Vector3d.new(0, slice, 0)
|
676
|
+
|
677
|
+
if actual_perim > 0 && (actual_perim * 2.0) < length
|
678
|
+
polygon_a = OpenStudio::Point3dVector.new
|
679
|
+
polygon_a << se_point
|
680
|
+
polygon_a << se_point + OpenStudio::Vector3d.new(- actual_perim, 0, 0)
|
681
|
+
polygon_a << ne_point + OpenStudio::Vector3d.new(- actual_perim, 0, 0)
|
682
|
+
polygon_a << ne_point
|
683
|
+
if double_loaded_corridor
|
684
|
+
hash_of_point_vectors["#{perim_space_type.name} A #{k}"] = {}
|
685
|
+
hash_of_point_vectors["#{perim_space_type.name} A #{k}"][:space_type] = perim_space_type
|
686
|
+
hash_of_point_vectors["#{perim_space_type.name} A #{k}"][:polygon] = polygon_a
|
687
|
+
else
|
688
|
+
hash_of_point_vectors["#{space_type.name} A #{k}"] = {}
|
689
|
+
hash_of_point_vectors["#{space_type.name} A #{k}"][:space_type] = space_type
|
690
|
+
hash_of_point_vectors["#{space_type.name} A #{k}"][:polygon] = polygon_a
|
691
|
+
end
|
692
|
+
|
693
|
+
polygon_b = OpenStudio::Point3dVector.new
|
694
|
+
polygon_b << se_point + OpenStudio::Vector3d.new(- actual_perim, 0, 0)
|
695
|
+
polygon_b << sw_point + OpenStudio::Vector3d.new(actual_perim, 0, 0)
|
696
|
+
polygon_b << nw_point + OpenStudio::Vector3d.new(actual_perim, 0, 0)
|
697
|
+
polygon_b << ne_point + OpenStudio::Vector3d.new(- actual_perim, 0, 0)
|
698
|
+
if double_loaded_corridor
|
699
|
+
hash_of_point_vectors["#{core_space_type.name} B #{k}"] = {}
|
700
|
+
hash_of_point_vectors["#{core_space_type.name} B #{k}"][:space_type] = core_space_type
|
701
|
+
hash_of_point_vectors["#{core_space_type.name} B #{k}"][:polygon] = polygon_b
|
702
|
+
else
|
703
|
+
hash_of_point_vectors["#{space_type.name} B #{k}"] = {}
|
704
|
+
hash_of_point_vectors["#{space_type.name} B #{k}"][:space_type] = space_type
|
705
|
+
hash_of_point_vectors["#{space_type.name} B #{k}"][:polygon] = polygon_b
|
706
|
+
end
|
707
|
+
|
708
|
+
polygon_c = OpenStudio::Point3dVector.new
|
709
|
+
polygon_c << sw_point + OpenStudio::Vector3d.new(actual_perim, 0, 0)
|
710
|
+
polygon_c << sw_point
|
711
|
+
polygon_c << nw_point
|
712
|
+
polygon_c << nw_point + OpenStudio::Vector3d.new(actual_perim, 0, 0)
|
713
|
+
if double_loaded_corridor
|
714
|
+
hash_of_point_vectors["#{perim_space_type.name} C #{k}"] = {}
|
715
|
+
hash_of_point_vectors["#{perim_space_type.name} C #{k}"][:space_type] = perim_space_type
|
716
|
+
hash_of_point_vectors["#{perim_space_type.name} C #{k}"][:polygon] = polygon_c
|
717
|
+
else
|
718
|
+
hash_of_point_vectors["#{space_type.name} C #{k}"] = {}
|
719
|
+
hash_of_point_vectors["#{space_type.name} C #{k}"][:space_type] = space_type
|
720
|
+
hash_of_point_vectors["#{space_type.name} C #{k}"][:polygon] = polygon_c
|
721
|
+
end
|
722
|
+
else
|
723
|
+
polygon_a = OpenStudio::Point3dVector.new
|
724
|
+
polygon_a << se_point
|
725
|
+
polygon_a << sw_point
|
726
|
+
polygon_a << nw_point
|
727
|
+
polygon_a << ne_point
|
728
|
+
hash_of_point_vectors["#{space_type.name} #{k}"] = {}
|
729
|
+
hash_of_point_vectors["#{space_type.name} #{k}"][:space_type] = space_type
|
730
|
+
hash_of_point_vectors["#{space_type.name} #{k}"][:polygon] = polygon_a
|
731
|
+
end
|
732
|
+
|
733
|
+
# update west points
|
734
|
+
sw_point = nw_point
|
735
|
+
se_point = ne_point
|
736
|
+
|
737
|
+
end
|
572
738
|
end
|
573
739
|
end
|
574
740
|
|
@@ -592,13 +758,24 @@ module OsLib_Geometry
|
|
592
758
|
end
|
593
759
|
end
|
594
760
|
|
761
|
+
# hash of new spaces (only change boundary conditions for these)
|
762
|
+
new_spaces = []
|
763
|
+
|
595
764
|
# loop through story_hash and polygons to generate all of the spaces
|
596
765
|
story_hash.each_with_index do |(story_name, story_data), index|
|
597
|
-
# make new story
|
598
|
-
story =
|
599
|
-
|
600
|
-
|
601
|
-
|
766
|
+
# make new story unless story at requested height already exists.
|
767
|
+
story = nil
|
768
|
+
model.getBuildingStorys.each do |ext_story|
|
769
|
+
if (ext_story.nominalZCoordinate.to_f - story_data[:space_origin_z].to_f).abs < 0.01
|
770
|
+
story = ext_story
|
771
|
+
end
|
772
|
+
end
|
773
|
+
if story.nil?
|
774
|
+
story = OpenStudio::Model::BuildingStory.new(model)
|
775
|
+
story.setNominalFloortoFloorHeight(story_data[:space_height]) # not used for anything
|
776
|
+
story.setNominalZCoordinate (story_data[:space_origin_z]) # not used for anything
|
777
|
+
story.setName("Story #{story_name}")
|
778
|
+
end
|
602
779
|
|
603
780
|
# multiplier values for adjacent stories to be altered below as needed
|
604
781
|
multiplier_story_above = 1
|
@@ -647,6 +824,7 @@ module OsLib_Geometry
|
|
647
824
|
|
648
825
|
# make space
|
649
826
|
space = OsLib_Geometry.makeSpaceFromPolygon(model, space_data[:polygon].first, space_data[:polygon], options)
|
827
|
+
new_spaces << space
|
650
828
|
|
651
829
|
# set z origin to proper position
|
652
830
|
space.setZOrigin(story_data[:space_origin_z])
|
@@ -676,7 +854,7 @@ module OsLib_Geometry
|
|
676
854
|
# any changes to wall boundary conditions will be handled by same code that calls this method.
|
677
855
|
# this method doesn't need to know about basements and party walls.
|
678
856
|
|
679
|
-
return
|
857
|
+
return new_spaces
|
680
858
|
end
|
681
859
|
|
682
860
|
# add def to create a space from input, optionally take a name, space type, story and thermal zone.
|
@@ -714,7 +892,7 @@ module OsLib_Geometry
|
|
714
892
|
space.setName(options['name'])
|
715
893
|
end
|
716
894
|
|
717
|
-
if !options['spaceType'].nil?
|
895
|
+
if !options['spaceType'].nil? && options['spaceType'].class.to_s == 'OpenStudio::Model::SpaceType'
|
718
896
|
space.setSpaceType(options['spaceType'])
|
719
897
|
end
|
720
898
|
|