osut 0.2.2 → 0.2.6
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/lib/osut/utils.rb +211 -271
- data/lib/osut/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 04db3007d81904287c0c36c677270a1e1bc5e45375d3b37bbac9068d51c43754
|
|
4
|
+
data.tar.gz: aafa2bb60bdfaf5b5df03e99aca0cb3181f6270468a761652d2b6d0438037daa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ca60fd088aa106b52bfe15fe4fd352c55a2c79083f95212d7e9e37250f1832b3b94f0dc415e664f5289e837600aad2ab936eff304e9d5cdba0c3a977a56cd7d0
|
|
7
|
+
data.tar.gz: 8aa96937a55520f99a9c122d0fe98f69ec97d45cbe0cac1e0db7626b48cacee5d65f801eb4a9791e3a6953d64473555b981b3bd9646d7948b6b5c26b2d02e041
|
data/lib/osut/utils.rb
CHANGED
|
@@ -35,12 +35,12 @@ module OSut
|
|
|
35
35
|
|
|
36
36
|
TOL = 0.01
|
|
37
37
|
TOL2 = TOL * TOL
|
|
38
|
-
NS = "nameString" # OpenStudio IdfObject nameString method
|
|
39
38
|
DBG = OSut::DEBUG # mainly to flag invalid arguments to devs (buggy code)
|
|
40
39
|
INF = OSut::INFO # not currently used in OSut
|
|
41
40
|
WRN = OSut::WARN # WARN users of 'iffy' .osm inputs (yet not critical)
|
|
42
41
|
ERR = OSut::ERROR # flag invalid .osm inputs (then exit via 'return')
|
|
43
42
|
FTL = OSut::FATAL # not currently used in OSut
|
|
43
|
+
NS = "nameString" # OpenStudio IdfObject nameString method
|
|
44
44
|
|
|
45
45
|
# This first set of utilities (~750 lines) help distinguishing spaces that
|
|
46
46
|
# are directly vs indirectly CONDITIONED, vs SEMI-HEATED. The solution here
|
|
@@ -127,7 +127,7 @@ module OSut
|
|
|
127
127
|
#
|
|
128
128
|
# @return [Hash] min: (Float), max: (Float)
|
|
129
129
|
# @return [Hash] min: nil, max: nil (if invalid input)
|
|
130
|
-
def scheduleRulesetMinMax(sched)
|
|
130
|
+
def scheduleRulesetMinMax(sched = nil)
|
|
131
131
|
# Largely inspired from David Goldwasser's
|
|
132
132
|
# "schedule_ruleset_annual_min_max_value":
|
|
133
133
|
#
|
|
@@ -138,7 +138,7 @@ module OSut
|
|
|
138
138
|
cl = OpenStudio::Model::ScheduleRuleset
|
|
139
139
|
res = { min: nil, max: nil }
|
|
140
140
|
|
|
141
|
-
return invalid("sched", mth, 1, DBG, res)
|
|
141
|
+
return invalid("sched", mth, 1, DBG, res) unless sched.respond_to?(NS)
|
|
142
142
|
id = sched.nameString
|
|
143
143
|
return mismatch(id, sched, cl, mth, DBG, res) unless sched.is_a?(cl)
|
|
144
144
|
|
|
@@ -148,11 +148,11 @@ module OSut
|
|
|
148
148
|
|
|
149
149
|
profiles.each do |profile|
|
|
150
150
|
id = profile.nameString
|
|
151
|
+
|
|
151
152
|
profile.values.each do |val|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
end
|
|
153
|
+
ok = val.is_a?(Numeric)
|
|
154
|
+
log(WRN, "Skipping non-numeric value in '#{id}' (#{mth})") unless ok
|
|
155
|
+
next unless ok
|
|
156
156
|
|
|
157
157
|
res[:min] = val unless res[:min]
|
|
158
158
|
res[:min] = val if res[:min] > val
|
|
@@ -174,7 +174,7 @@ module OSut
|
|
|
174
174
|
#
|
|
175
175
|
# @return [Hash] min: (Float), max: (Float)
|
|
176
176
|
# @return [Hash] min: nil, max: nil (if invalid input)
|
|
177
|
-
def scheduleConstantMinMax(sched)
|
|
177
|
+
def scheduleConstantMinMax(sched = nil)
|
|
178
178
|
# Largely inspired from David Goldwasser's
|
|
179
179
|
# "schedule_constant_annual_min_max_value":
|
|
180
180
|
#
|
|
@@ -185,16 +185,14 @@ module OSut
|
|
|
185
185
|
cl = OpenStudio::Model::ScheduleConstant
|
|
186
186
|
res = { min: nil, max: nil }
|
|
187
187
|
|
|
188
|
-
return invalid("sched", mth, 1, DBG, res)
|
|
188
|
+
return invalid("sched", mth, 1, DBG, res) unless sched.respond_to?(NS)
|
|
189
189
|
id = sched.nameString
|
|
190
190
|
return mismatch(id, sched, cl, mth, DBG, res) unless sched.is_a?(cl)
|
|
191
191
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
res[:max] = sched.value
|
|
197
|
-
end
|
|
192
|
+
valid = sched.value.is_a?(Numeric)
|
|
193
|
+
mismatch("'#{id}' value", sched.value, Numeric, mth, ERR, res) unless valid
|
|
194
|
+
res[:min] = sched.value
|
|
195
|
+
res[:max] = sched.value
|
|
198
196
|
|
|
199
197
|
res
|
|
200
198
|
end
|
|
@@ -206,7 +204,7 @@ module OSut
|
|
|
206
204
|
#
|
|
207
205
|
# @return [Hash] min: (Float), max: (Float)
|
|
208
206
|
# @return [Hash] min: nil, max: nil (if invalid input)
|
|
209
|
-
def scheduleCompactMinMax(sched)
|
|
207
|
+
def scheduleCompactMinMax(sched = nil)
|
|
210
208
|
# Largely inspired from Andrew Parker's
|
|
211
209
|
# "schedule_compact_annual_min_max_value":
|
|
212
210
|
#
|
|
@@ -219,7 +217,7 @@ module OSut
|
|
|
219
217
|
prev_str = ""
|
|
220
218
|
res = { min: nil, max: nil }
|
|
221
219
|
|
|
222
|
-
return invalid("sched", mth, 1, DBG, res)
|
|
220
|
+
return invalid("sched", mth, 1, DBG, res) unless sched.respond_to?(NS)
|
|
223
221
|
id = sched.nameString
|
|
224
222
|
return mismatch(id, sched, cl, mth, DBG, res) unless sched.is_a?(cl)
|
|
225
223
|
|
|
@@ -233,13 +231,11 @@ module OSut
|
|
|
233
231
|
end
|
|
234
232
|
|
|
235
233
|
return empty("'#{id}' values", mth, ERR, res) if vals.empty?
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
log(ERR, "Non-numeric values in '#{id}' (#{mth})")
|
|
242
|
-
end
|
|
234
|
+
ok = vals.min.is_a?(Numeric) && vals.max.is_a?(Numeric)
|
|
235
|
+
log(ERR, "Non-numeric values in '#{id}' (#{mth})") unless ok
|
|
236
|
+
return res unless ok
|
|
237
|
+
res[:min] = vals.min
|
|
238
|
+
res[:max] = vals.max
|
|
243
239
|
|
|
244
240
|
res
|
|
245
241
|
end
|
|
@@ -251,24 +247,22 @@ module OSut
|
|
|
251
247
|
#
|
|
252
248
|
# @return [Hash] min: (Float), max: (Float)
|
|
253
249
|
# @return [Hash] min: nil, max: nil (if invalid input)
|
|
254
|
-
def scheduleIntervalMinMax(sched)
|
|
250
|
+
def scheduleIntervalMinMax(sched = nil)
|
|
255
251
|
mth = "OSut::#{__callee__}"
|
|
256
252
|
cl = OpenStudio::Model::ScheduleInterval
|
|
257
253
|
vals = []
|
|
258
254
|
prev_str = ""
|
|
259
255
|
res = { min: nil, max: nil }
|
|
260
256
|
|
|
261
|
-
return invalid("sched", mth, 1, DBG, res)
|
|
257
|
+
return invalid("sched", mth, 1, DBG, res) unless sched.respond_to?(NS)
|
|
262
258
|
id = sched.nameString
|
|
263
259
|
return mismatch(id, sched, cl, mth, DBG, res) unless sched.is_a?(cl)
|
|
264
|
-
|
|
265
260
|
vals = sched.timeSeries.values
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
end
|
|
261
|
+
ok = vals.min.is_a?(Numeric) && vals.max.is_a?(Numeric)
|
|
262
|
+
log(ERR, "Non-numeric values in '#{id}' (#{mth})") unless ok
|
|
263
|
+
return res unless ok
|
|
264
|
+
res[:min] = vals.min
|
|
265
|
+
res[:max] = vals.max
|
|
272
266
|
|
|
273
267
|
res
|
|
274
268
|
end
|
|
@@ -281,7 +275,7 @@ module OSut
|
|
|
281
275
|
#
|
|
282
276
|
# @return [Hash] spt: (Float), dual: (Bool)
|
|
283
277
|
# @return [Hash] spt: nil, dual: false (if invalid input)
|
|
284
|
-
def maxHeatScheduledSetpoint(zone)
|
|
278
|
+
def maxHeatScheduledSetpoint(zone = nil)
|
|
285
279
|
# Largely inspired from Parker & Marrec's "thermal_zone_heated?" procedure.
|
|
286
280
|
# The solution here is a tad more relaxed to encompass SEMI-HEATED zones as
|
|
287
281
|
# per Canadian NECB criteria (basically any space with at least 10 W/m2 of
|
|
@@ -294,7 +288,7 @@ module OSut
|
|
|
294
288
|
cl = OpenStudio::Model::ThermalZone
|
|
295
289
|
res = { spt: nil, dual: false }
|
|
296
290
|
|
|
297
|
-
return invalid("zone", mth, 1, DBG, res)
|
|
291
|
+
return invalid("zone", mth, 1, DBG, res) unless zone.respond_to?(NS)
|
|
298
292
|
id = zone.nameString
|
|
299
293
|
return mismatch(id, zone, cl, mth, DBG, res) unless zone.is_a?(cl)
|
|
300
294
|
|
|
@@ -312,10 +306,7 @@ module OSut
|
|
|
312
306
|
|
|
313
307
|
unless equip.to_ZoneHVACLowTemperatureRadiantElectric.empty?
|
|
314
308
|
equip = equip.to_ZoneHVACLowTemperatureRadiantElectric.get
|
|
315
|
-
|
|
316
|
-
unless equip.heatingSetpointTemperatureSchedule.empty?
|
|
317
|
-
sched = equip.heatingSetpointTemperatureSchedule.get
|
|
318
|
-
end
|
|
309
|
+
sched = equip.heatingSetpointTemperatureSchedule
|
|
319
310
|
end
|
|
320
311
|
|
|
321
312
|
unless equip.to_ZoneHVACLowTempRadiantConstFlow.empty?
|
|
@@ -377,13 +368,12 @@ module OSut
|
|
|
377
368
|
end
|
|
378
369
|
end
|
|
379
370
|
|
|
380
|
-
return res if res[:spt]
|
|
381
371
|
return res if zone.thermostat.empty?
|
|
382
|
-
tstat
|
|
372
|
+
tstat = zone.thermostat.get
|
|
373
|
+
res[:spt] = nil
|
|
383
374
|
|
|
384
375
|
unless tstat.to_ThermostatSetpointDualSetpoint.empty? &&
|
|
385
376
|
tstat.to_ZoneControlThermostatStagedDualSetpoint.empty?
|
|
386
|
-
res[:dual] = true
|
|
387
377
|
|
|
388
378
|
unless tstat.to_ThermostatSetpointDualSetpoint.empty?
|
|
389
379
|
tstat = tstat.to_ThermostatSetpointDualSetpoint.get
|
|
@@ -392,7 +382,8 @@ module OSut
|
|
|
392
382
|
end
|
|
393
383
|
|
|
394
384
|
unless tstat.heatingSetpointTemperatureSchedule.empty?
|
|
395
|
-
|
|
385
|
+
res[:dual] = true
|
|
386
|
+
sched = tstat.heatingSetpointTemperatureSchedule.get
|
|
396
387
|
|
|
397
388
|
unless sched.to_ScheduleRuleset.empty?
|
|
398
389
|
sched = sched.to_ScheduleRuleset.get
|
|
@@ -456,11 +447,10 @@ module OSut
|
|
|
456
447
|
#
|
|
457
448
|
# @return [Bool] true if valid heating temperature setpoints
|
|
458
449
|
# @return [Bool] false if invalid input
|
|
459
|
-
def heatingTemperatureSetpoints?(model)
|
|
450
|
+
def heatingTemperatureSetpoints?(model = nil)
|
|
460
451
|
mth = "OSut::#{__callee__}"
|
|
461
|
-
cl
|
|
452
|
+
cl = OpenStudio::Model::Model
|
|
462
453
|
|
|
463
|
-
return invalid("model", mth, 1, DBG, false) unless model
|
|
464
454
|
return mismatch("model", model, cl, mth, DBG, false) unless model.is_a?(cl)
|
|
465
455
|
|
|
466
456
|
model.getThermalZones.each do |zone|
|
|
@@ -478,7 +468,7 @@ module OSut
|
|
|
478
468
|
#
|
|
479
469
|
# @return [Hash] spt: (Float), dual: (Bool)
|
|
480
470
|
# @return [Hash] spt: nil, dual: false (if invalid input)
|
|
481
|
-
def minCoolScheduledSetpoint(zone)
|
|
471
|
+
def minCoolScheduledSetpoint(zone = nil)
|
|
482
472
|
# Largely inspired from Parker & Marrec's "thermal_zone_cooled?" procedure.
|
|
483
473
|
#
|
|
484
474
|
# github.com/NREL/openstudio-standards/blob/
|
|
@@ -488,7 +478,7 @@ module OSut
|
|
|
488
478
|
cl = OpenStudio::Model::ThermalZone
|
|
489
479
|
res = { spt: nil, dual: false }
|
|
490
480
|
|
|
491
|
-
return invalid("zone", mth, 1, DBG, res)
|
|
481
|
+
return invalid("zone", mth, 1, DBG, res) unless zone.respond_to?(NS)
|
|
492
482
|
id = zone.nameString
|
|
493
483
|
return mismatch(id, zone, cl, mth, DBG, res) unless zone.is_a?(cl)
|
|
494
484
|
|
|
@@ -555,13 +545,12 @@ module OSut
|
|
|
555
545
|
end
|
|
556
546
|
end
|
|
557
547
|
|
|
558
|
-
return res if res[:spt]
|
|
559
548
|
return res if zone.thermostat.empty?
|
|
560
|
-
tstat
|
|
549
|
+
tstat = zone.thermostat.get
|
|
550
|
+
res[:spt] = nil
|
|
561
551
|
|
|
562
552
|
unless tstat.to_ThermostatSetpointDualSetpoint.empty? &&
|
|
563
553
|
tstat.to_ZoneControlThermostatStagedDualSetpoint.empty?
|
|
564
|
-
res[:dual] = true
|
|
565
554
|
|
|
566
555
|
unless tstat.to_ThermostatSetpointDualSetpoint.empty?
|
|
567
556
|
tstat = tstat.to_ThermostatSetpointDualSetpoint.get
|
|
@@ -570,7 +559,8 @@ module OSut
|
|
|
570
559
|
end
|
|
571
560
|
|
|
572
561
|
unless tstat.coolingSetpointTemperatureSchedule.empty?
|
|
573
|
-
|
|
562
|
+
res[:dual] = true
|
|
563
|
+
sched = tstat.coolingSetpointTemperatureSchedule.get
|
|
574
564
|
|
|
575
565
|
unless sched.to_ScheduleRuleset.empty?
|
|
576
566
|
sched = sched.to_ScheduleRuleset.get
|
|
@@ -634,11 +624,10 @@ module OSut
|
|
|
634
624
|
#
|
|
635
625
|
# @return [Bool] true if valid cooling temperature setpoints
|
|
636
626
|
# @return [Bool] false if invalid input
|
|
637
|
-
def coolingTemperatureSetpoints?(model)
|
|
627
|
+
def coolingTemperatureSetpoints?(model = nil)
|
|
638
628
|
mth = "OSut::#{__callee__}"
|
|
639
|
-
cl
|
|
629
|
+
cl = OpenStudio::Model::Model
|
|
640
630
|
|
|
641
|
-
return invalid("model", mth, 1, DBG, false) unless model
|
|
642
631
|
return mismatch("model", model, cl, mth, DBG, false) unless model.is_a?(cl)
|
|
643
632
|
|
|
644
633
|
model.getThermalZones.each do |zone|
|
|
@@ -655,11 +644,10 @@ module OSut
|
|
|
655
644
|
#
|
|
656
645
|
# @return [Bool] true if model has one or more HVAC air loops
|
|
657
646
|
# @return [Bool] false if invalid input
|
|
658
|
-
def airLoopsHVAC?(model)
|
|
647
|
+
def airLoopsHVAC?(model = nil)
|
|
659
648
|
mth = "OSut::#{__callee__}"
|
|
660
|
-
cl
|
|
649
|
+
cl = OpenStudio::Model::Model
|
|
661
650
|
|
|
662
|
-
return invalid("model", mth, 1, DBG, false) unless model
|
|
663
651
|
return mismatch("model", model, cl, mth, DBG, false) unless model.is_a?(cl)
|
|
664
652
|
|
|
665
653
|
model.getThermalZones.each do |zone|
|
|
@@ -680,68 +668,59 @@ module OSut
|
|
|
680
668
|
#
|
|
681
669
|
# @return [Bool] true if should be tagged as plenum
|
|
682
670
|
# @return [Bool] false if invalid input
|
|
683
|
-
def plenum?(space, loops, setpoints)
|
|
671
|
+
def plenum?(space = nil, loops = nil, setpoints = nil)
|
|
684
672
|
# Largely inspired from NREL's "space_plenum?" procedure:
|
|
685
673
|
#
|
|
686
674
|
# github.com/NREL/openstudio-standards/blob/
|
|
687
675
|
# 58964222d25783e9da4ae292e375fb0d5c902aa5/lib/openstudio-standards/
|
|
688
676
|
# standards/Standards.Space.rb#L1384
|
|
689
|
-
|
|
677
|
+
#
|
|
690
678
|
# A space may be tagged as a plenum if:
|
|
691
679
|
#
|
|
692
680
|
# CASE A: its zone's "isPlenum" == true (SDK method) for a fully-developed
|
|
693
681
|
# OpenStudio model (complete with HVAC air loops);
|
|
694
682
|
#
|
|
695
|
-
# CASE B: it's excluded from building's
|
|
696
|
-
# zone holding an
|
|
697
|
-
# valid setpoints
|
|
698
|
-
#
|
|
699
|
-
# CASE C: it has a spacetype whose name holds "plenum", or a spacetype with
|
|
700
|
-
# a 'standards spacetype' holding "plenum" (case insensitive); OR
|
|
683
|
+
# CASE B: (IN ABSENCE OF HVAC AIRLOOPS) if it's excluded from a building's
|
|
684
|
+
# total floor area yet linked to a zone holding an 'inactive'
|
|
685
|
+
# thermostat, i.e. can't extract valid setpoints; OR
|
|
701
686
|
#
|
|
702
|
-
# CASE
|
|
703
|
-
|
|
687
|
+
# CASE C: (IN ABSENCE OF HVAC AIRLOOPS & VALID SETPOINTS) it has "plenum"
|
|
688
|
+
# (case insensitive) as a spacetype (or as a spacetype's
|
|
689
|
+
# 'standards spacetype').
|
|
704
690
|
mth = "OSut::#{__callee__}"
|
|
705
691
|
cl = OpenStudio::Model::Space
|
|
706
692
|
|
|
707
|
-
return invalid("space", mth, 1, DBG, false)
|
|
693
|
+
return invalid("space", mth, 1, DBG, false) unless space.respond_to?(NS)
|
|
708
694
|
id = space.nameString
|
|
709
695
|
return mismatch(id, space, cl, mth, DBG, false) unless space.is_a?(cl)
|
|
710
|
-
|
|
711
696
|
valid = loops == true || loops == false
|
|
712
|
-
return invalid("loops", mth, 2, DBG, false)
|
|
713
|
-
|
|
697
|
+
return invalid("loops", mth, 2, DBG, false) unless valid
|
|
714
698
|
valid = setpoints == true || setpoints == false
|
|
715
699
|
return invalid("setpoints", mth, 3, DBG, false) unless valid
|
|
716
700
|
|
|
717
701
|
unless space.thermalZone.empty?
|
|
718
702
|
zone = space.thermalZone.get
|
|
719
|
-
return
|
|
703
|
+
return zone.isPlenum if loops # A
|
|
720
704
|
|
|
721
705
|
if setpoints
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
return
|
|
726
|
-
|
|
727
|
-
unless space.partofTotalFloorArea
|
|
728
|
-
return true if heating[:dual] || cooling[:dual] # CASE B
|
|
729
|
-
end
|
|
706
|
+
heat = maxHeatScheduledSetpoint(zone)
|
|
707
|
+
cool = minCoolScheduledSetpoint(zone)
|
|
708
|
+
return false if heat[:spt] || cool[:spt] # directly conditioned
|
|
709
|
+
return heat[:dual] || cool[:dual] unless space.partofTotalFloorArea # B
|
|
710
|
+
return false
|
|
730
711
|
end
|
|
731
712
|
end
|
|
732
713
|
|
|
733
714
|
unless space.spaceType.empty?
|
|
734
715
|
type = space.spaceType.get
|
|
735
|
-
return
|
|
716
|
+
return type.nameString.downcase == "plenum" # C
|
|
736
717
|
|
|
737
718
|
unless type.standardsSpaceType.empty?
|
|
738
719
|
type = type.standardsSpaceType.get
|
|
739
|
-
return
|
|
720
|
+
return type.downcase == "plenum" # C
|
|
740
721
|
end
|
|
741
722
|
end
|
|
742
723
|
|
|
743
|
-
return true if space.nameString.downcase.include?("plenum")
|
|
744
|
-
|
|
745
724
|
false
|
|
746
725
|
end
|
|
747
726
|
|
|
@@ -752,17 +731,16 @@ module OSut
|
|
|
752
731
|
# @param avl [String] seasonal availability choice (optional, default "ON")
|
|
753
732
|
#
|
|
754
733
|
# @return [OpenStudio::Model::Schedule] HVAC availability sched
|
|
755
|
-
# @return [
|
|
756
|
-
def availabilitySchedule(model, avl = "")
|
|
757
|
-
mth
|
|
758
|
-
cl
|
|
734
|
+
# @return [NilClass] if invalid input
|
|
735
|
+
def availabilitySchedule(model = nil, avl = "")
|
|
736
|
+
mth = "OSut::#{__callee__}"
|
|
737
|
+
cl = OpenStudio::Model::Model
|
|
738
|
+
limits = nil
|
|
759
739
|
|
|
760
|
-
return
|
|
761
|
-
return
|
|
740
|
+
return mismatch("model", model, cl, mth) unless model.is_a?(cl)
|
|
741
|
+
return invalid("availability", avl, 2, mth) unless avl.respond_to?(:to_s)
|
|
762
742
|
|
|
763
743
|
# Either fetch availability ScheduleTypeLimits object, or create one.
|
|
764
|
-
limits = nil
|
|
765
|
-
|
|
766
744
|
model.getScheduleTypeLimitss.each do |l|
|
|
767
745
|
break if limits
|
|
768
746
|
next if l.lowerLimitValue.empty?
|
|
@@ -797,7 +775,7 @@ module OSut
|
|
|
797
775
|
may01 = year.makeDate(OpenStudio::MonthOfYear.new("May"), 1)
|
|
798
776
|
oct31 = year.makeDate(OpenStudio::MonthOfYear.new("Oct"), 31)
|
|
799
777
|
|
|
800
|
-
case avl.downcase
|
|
778
|
+
case avl.to_s.downcase
|
|
801
779
|
when "winter" # available from November 1 to April 30 (6 months)
|
|
802
780
|
val = 1
|
|
803
781
|
sch = off
|
|
@@ -838,29 +816,29 @@ module OSut
|
|
|
838
816
|
unless schedule.empty?
|
|
839
817
|
schedule = schedule.get
|
|
840
818
|
default = schedule.defaultDaySchedule
|
|
841
|
-
ok = ok && default.nameString
|
|
842
|
-
ok = ok && default.times.size
|
|
843
|
-
ok = ok && default.values.size
|
|
844
|
-
ok = ok && default.times.first
|
|
845
|
-
ok = ok && default.values.first
|
|
819
|
+
ok = ok && default.nameString == dft
|
|
820
|
+
ok = ok && default.times.size == 1
|
|
821
|
+
ok = ok && default.values.size == 1
|
|
822
|
+
ok = ok && default.times.first == time
|
|
823
|
+
ok = ok && default.values.first == val
|
|
846
824
|
rules = schedule.scheduleRules
|
|
847
825
|
ok = ok && (rules.size == 0 || rules.size == 1)
|
|
848
826
|
|
|
849
827
|
if rules.size == 1
|
|
850
828
|
rule = rules.first
|
|
851
|
-
ok = ok && rule.nameString
|
|
829
|
+
ok = ok && rule.nameString == tag
|
|
852
830
|
ok = ok && !rule.startDate.empty?
|
|
853
831
|
ok = ok && !rule.endDate.empty?
|
|
854
|
-
ok = ok && rule.startDate.get
|
|
855
|
-
ok = ok && rule.endDate.get
|
|
832
|
+
ok = ok && rule.startDate.get == may01
|
|
833
|
+
ok = ok && rule.endDate.get == oct31
|
|
856
834
|
ok = ok && rule.applyAllDays
|
|
857
835
|
|
|
858
836
|
d = rule.daySchedule
|
|
859
|
-
ok = ok && d.nameString
|
|
860
|
-
ok = ok && d.times.size
|
|
861
|
-
ok = ok && d.values.size
|
|
837
|
+
ok = ok && d.nameString == day
|
|
838
|
+
ok = ok && d.times.size == 1
|
|
839
|
+
ok = ok && d.values.size == 1
|
|
862
840
|
ok = ok && d.times.first.totalSeconds == secs
|
|
863
|
-
ok = ok && d.values.first.to_i
|
|
841
|
+
ok = ok && d.values.first.to_i != val
|
|
864
842
|
end
|
|
865
843
|
|
|
866
844
|
return schedule if ok
|
|
@@ -869,38 +847,26 @@ module OSut
|
|
|
869
847
|
|
|
870
848
|
schedule = OpenStudio::Model::ScheduleRuleset.new(model)
|
|
871
849
|
schedule.setName(nom)
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
unless schedule.defaultDaySchedule.addValue(time, val)
|
|
879
|
-
log(ERR, "'#{nom}': Can't set default day schedule (#{mth})")
|
|
880
|
-
return nil
|
|
881
|
-
end
|
|
882
|
-
|
|
850
|
+
ok = schedule.setScheduleTypeLimits(limits)
|
|
851
|
+
log(ERR, "'#{nom}': Can't set schedule type limits (#{mth})") unless ok
|
|
852
|
+
return nil unless ok
|
|
853
|
+
ok = schedule.defaultDaySchedule.addValue(time, val)
|
|
854
|
+
log(ERR, "'#{nom}': Can't set default day schedule (#{mth})") unless ok
|
|
855
|
+
return nil unless ok
|
|
883
856
|
schedule.defaultDaySchedule.setName(dft)
|
|
884
857
|
|
|
885
858
|
unless tag.empty?
|
|
886
859
|
rule = OpenStudio::Model::ScheduleRule.new(schedule, sch)
|
|
887
860
|
rule.setName(tag)
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
end
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
end
|
|
898
|
-
|
|
899
|
-
unless rule.setApplyAllDays(true)
|
|
900
|
-
log(ERR, "'#{tag}': Can't apply to all days (#{mth})")
|
|
901
|
-
return nil
|
|
902
|
-
end
|
|
903
|
-
|
|
861
|
+
ok = rule.setStartDate(may01)
|
|
862
|
+
log(ERR, "'#{tag}': Can't set start date (#{mth})") unless ok
|
|
863
|
+
return nil unless ok
|
|
864
|
+
ok = rule.setEndDate(oct31)
|
|
865
|
+
log(ERR, "'#{tag}': Can't set end date (#{mth})") unless ok
|
|
866
|
+
return nil unless ok
|
|
867
|
+
ok = rule.setApplyAllDays(true)
|
|
868
|
+
log(ERR, "'#{tag}': Can't apply to all days (#{mth})") unless ok
|
|
869
|
+
return nil unless ok
|
|
904
870
|
rule.daySchedule.setName(day)
|
|
905
871
|
end
|
|
906
872
|
|
|
@@ -911,43 +877,41 @@ module OSut
|
|
|
911
877
|
# Validate if default construction set holds a base ground construction.
|
|
912
878
|
#
|
|
913
879
|
# @param set [OpenStudio::Model::DefaultConstructionSet] a default set
|
|
914
|
-
# @param
|
|
915
|
-
# @param
|
|
916
|
-
# @param
|
|
917
|
-
# @param
|
|
880
|
+
# @param bse [OpensStudio::Model::ConstructionBase] a construction base
|
|
881
|
+
# @param gr [Bool] true if ground-facing surface
|
|
882
|
+
# @param ex [Bool] true if exterior-facing surface
|
|
883
|
+
# @param typ [String] a surface type
|
|
918
884
|
#
|
|
919
885
|
# @return [Bool] true if default construction set holds construction
|
|
920
886
|
# @return [Bool] false if invalid input
|
|
921
|
-
def holdsConstruction?(set,
|
|
887
|
+
def holdsConstruction?(set = nil, bse = nil, gr = false, ex = false, typ = "")
|
|
922
888
|
mth = "OSut::#{__callee__}"
|
|
923
889
|
cl1 = OpenStudio::Model::DefaultConstructionSet
|
|
924
890
|
cl2 = OpenStudio::Model::ConstructionBase
|
|
925
891
|
|
|
926
|
-
return invalid("set", mth, 1, DBG, false)
|
|
892
|
+
return invalid("set", mth, 1, DBG, false) unless set.respond_to?(NS)
|
|
927
893
|
id = set.nameString
|
|
928
|
-
return mismatch(id, set, cl1, mth, DBG, false)
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
id
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
valid =
|
|
935
|
-
return invalid("
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
typ = type.to_s.downcase
|
|
941
|
-
valid = typ == "floor" || typ == "wall" || typ == "roofceiling"
|
|
894
|
+
return mismatch(id, set, cl1, mth, DBG, false) unless set.is_a?(cl1)
|
|
895
|
+
return invalid("base", mth, 2, DBG, false) unless bse.respond_to?(NS)
|
|
896
|
+
id = bse.nameString
|
|
897
|
+
return mismatch(id, bse, cl2, mth, DBG, false) unless bse.is_a?(cl2)
|
|
898
|
+
valid = gr == true || gr == false
|
|
899
|
+
return invalid("ground", mth, 3, DBG, false) unless valid
|
|
900
|
+
valid = ex == true || ex == false
|
|
901
|
+
return invalid("exterior", mth, 4, DBG, false) unless valid
|
|
902
|
+
valid = typ.respond_to?(:to_s)
|
|
903
|
+
return invalid("surface typ", mth, 4, DBG, false) unless valid
|
|
904
|
+
type = typ.to_s.downcase
|
|
905
|
+
valid = type == "floor" || type == "wall" || type == "roofceiling"
|
|
942
906
|
return invalid("surface type", mth, 5, DBG, false) unless valid
|
|
943
907
|
|
|
944
908
|
constructions = nil
|
|
945
909
|
|
|
946
|
-
if
|
|
910
|
+
if gr
|
|
947
911
|
unless set.defaultGroundContactSurfaceConstructions.empty?
|
|
948
912
|
constructions = set.defaultGroundContactSurfaceConstructions.get
|
|
949
913
|
end
|
|
950
|
-
elsif
|
|
914
|
+
elsif ex
|
|
951
915
|
unless set.defaultExteriorSurfaceConstructions.empty?
|
|
952
916
|
constructions = set.defaultExteriorSurfaceConstructions.get
|
|
953
917
|
end
|
|
@@ -959,21 +923,21 @@ module OSut
|
|
|
959
923
|
|
|
960
924
|
return false unless constructions
|
|
961
925
|
|
|
962
|
-
case
|
|
926
|
+
case type
|
|
963
927
|
when "roofceiling"
|
|
964
928
|
unless constructions.roofCeilingConstruction.empty?
|
|
965
929
|
construction = constructions.roofCeilingConstruction.get
|
|
966
|
-
return true if construction ==
|
|
930
|
+
return true if construction == bse
|
|
967
931
|
end
|
|
968
932
|
when "floor"
|
|
969
933
|
unless constructions.floorConstruction.empty?
|
|
970
934
|
construction = constructions.floorConstruction.get
|
|
971
|
-
return true if construction ==
|
|
935
|
+
return true if construction == bse
|
|
972
936
|
end
|
|
973
937
|
else
|
|
974
938
|
unless constructions.wallConstruction.empty?
|
|
975
939
|
construction = constructions.wallConstruction.get
|
|
976
|
-
return true if construction ==
|
|
940
|
+
return true if construction == bse
|
|
977
941
|
end
|
|
978
942
|
end
|
|
979
943
|
|
|
@@ -987,30 +951,25 @@ module OSut
|
|
|
987
951
|
# @param s [OpenStudio::Model::Surface] a surface
|
|
988
952
|
#
|
|
989
953
|
# @return [OpenStudio::Model::DefaultConstructionSet] default set
|
|
990
|
-
# @return [
|
|
991
|
-
def defaultConstructionSet(model, s)
|
|
954
|
+
# @return [NilClass] if invalid input
|
|
955
|
+
def defaultConstructionSet(model = nil, s = nil)
|
|
992
956
|
mth = "OSut::#{__callee__}"
|
|
993
957
|
cl1 = OpenStudio::Model::Model
|
|
994
958
|
cl2 = OpenStudio::Model::Surface
|
|
995
959
|
|
|
996
|
-
return invalid("model", mth, 1) unless model
|
|
997
960
|
return mismatch("model", model, cl1, mth) unless model.is_a?(cl1)
|
|
998
|
-
|
|
999
|
-
return invalid("s", mth, 2) unless s.respond_to?(NS)
|
|
961
|
+
return invalid("s", mth, 2) unless s.respond_to?(NS)
|
|
1000
962
|
id = s.nameString
|
|
1001
|
-
return mismatch(id, s, cl2, mth)
|
|
1002
|
-
|
|
1003
|
-
unless s.isConstructionDefaulted
|
|
1004
|
-
log(ERR, "'#{id}' construction not defaulted (#{mth})")
|
|
1005
|
-
return nil
|
|
1006
|
-
end
|
|
963
|
+
return mismatch(id, s, cl2, mth) unless s.is_a?(cl2)
|
|
1007
964
|
|
|
965
|
+
ok = s.isConstructionDefaulted
|
|
966
|
+
log(ERR, "'#{id}' construction not defaulted (#{mth})") unless ok
|
|
967
|
+
return nil unless ok
|
|
1008
968
|
return empty("'#{id}' construction", mth, ERR) if s.construction.empty?
|
|
1009
969
|
base = s.construction.get
|
|
1010
970
|
return empty("'#{id}' space", mth, ERR) if s.space.empty?
|
|
1011
971
|
space = s.space.get
|
|
1012
972
|
type = s.surfaceType
|
|
1013
|
-
|
|
1014
973
|
ground = false
|
|
1015
974
|
exterior = false
|
|
1016
975
|
|
|
@@ -1060,7 +1019,7 @@ module OSut
|
|
|
1060
1019
|
#
|
|
1061
1020
|
# @return [Bool] true if all layers are valid
|
|
1062
1021
|
# @return [Bool] false if invalid input
|
|
1063
|
-
def standardOpaqueLayers?(lc)
|
|
1022
|
+
def standardOpaqueLayers?(lc = nil)
|
|
1064
1023
|
mth = "OSut::#{__callee__}"
|
|
1065
1024
|
cl = OpenStudio::Model::LayeredConstruction
|
|
1066
1025
|
|
|
@@ -1068,6 +1027,7 @@ module OSut
|
|
|
1068
1027
|
return mismatch(lc.nameString, lc, cl, mth, DBG, false) unless lc.is_a?(cl)
|
|
1069
1028
|
|
|
1070
1029
|
lc.layers.each { |m| return false if m.to_StandardOpaqueMaterial.empty? }
|
|
1030
|
+
|
|
1071
1031
|
true
|
|
1072
1032
|
end
|
|
1073
1033
|
|
|
@@ -1078,21 +1038,20 @@ module OSut
|
|
|
1078
1038
|
#
|
|
1079
1039
|
# @return [Double] total layered construction thickness
|
|
1080
1040
|
# @return [Double] 0 if invalid input
|
|
1081
|
-
def thickness(lc)
|
|
1041
|
+
def thickness(lc = nil)
|
|
1082
1042
|
mth = "OSut::#{__callee__}"
|
|
1083
1043
|
cl = OpenStudio::Model::LayeredConstruction
|
|
1084
1044
|
|
|
1085
|
-
return invalid("lc", mth, 1, DBG, 0)
|
|
1045
|
+
return invalid("lc", mth, 1, DBG, 0.0) unless lc.respond_to?(NS)
|
|
1086
1046
|
id = lc.nameString
|
|
1087
|
-
return mismatch(id, lc, cl, mth, DBG, 0) unless lc.is_a?(cl)
|
|
1088
|
-
|
|
1089
|
-
unless standardOpaqueLayers?(lc)
|
|
1090
|
-
log(ERR, "'#{id}' holds non-StandardOpaqueMaterial(s) (#{mth})")
|
|
1091
|
-
return 0
|
|
1092
|
-
end
|
|
1047
|
+
return mismatch(id, lc, cl, mth, DBG, 0.0) unless lc.is_a?(cl)
|
|
1093
1048
|
|
|
1049
|
+
ok = standardOpaqueLayers?(lc)
|
|
1050
|
+
log(ERR, "'#{id}' holds non-StandardOpaqueMaterial(s) (#{mth})") unless ok
|
|
1051
|
+
return 0.0 unless ok
|
|
1094
1052
|
thickness = 0.0
|
|
1095
1053
|
lc.layers.each { |m| thickness += m.thickness }
|
|
1054
|
+
|
|
1096
1055
|
thickness
|
|
1097
1056
|
end
|
|
1098
1057
|
|
|
@@ -1122,11 +1081,12 @@ module OSut
|
|
|
1122
1081
|
# The EnergyPlus Engineering calculations were designed for vertical windows
|
|
1123
1082
|
# - not horizontal, slanted or domed surfaces - use with caution.
|
|
1124
1083
|
mth = "OSut::#{__callee__}"
|
|
1125
|
-
cl
|
|
1084
|
+
cl = Numeric
|
|
1126
1085
|
|
|
1127
|
-
return
|
|
1128
|
-
return
|
|
1129
|
-
return
|
|
1086
|
+
return mismatch("usi", usi, cl, mth, DBG, 0.1216) unless usi.is_a?(cl)
|
|
1087
|
+
return invalid("usi", mth, 1, WRN, 0.1216) if usi > 8.0
|
|
1088
|
+
return negative("usi", mth, WRN, 0.1216) if usi < 0
|
|
1089
|
+
return zero("usi", mth, WRN, 0.1216) if usi.abs < TOL
|
|
1130
1090
|
|
|
1131
1091
|
rsi = 1 / (0.025342 * usi + 29.163853) # exterior film, next interior film
|
|
1132
1092
|
|
|
@@ -1142,64 +1102,49 @@ module OSut
|
|
|
1142
1102
|
# @param t [Float] gas temperature (°C) (optional)
|
|
1143
1103
|
#
|
|
1144
1104
|
# @return [Float] calculated RSi at standard conditions (0 if error)
|
|
1145
|
-
def rsi(lc, film, t = 0.0)
|
|
1105
|
+
def rsi(lc = nil, film = 0.0, t = 0.0)
|
|
1146
1106
|
# This is adapted from BTAP's Material Module's "get_conductance" (P. Lopez)
|
|
1147
1107
|
#
|
|
1148
1108
|
# https://github.com/NREL/OpenStudio-Prototype-Buildings/blob/
|
|
1149
1109
|
# c3d5021d8b7aef43e560544699fb5c559e6b721d/lib/btap/measures/
|
|
1150
1110
|
# btap_equest_converter/envelope.rb#L122
|
|
1151
|
-
|
|
1152
1111
|
mth = "OSut::#{__callee__}"
|
|
1153
1112
|
cl1 = OpenStudio::Model::LayeredConstruction
|
|
1154
1113
|
cl2 = Numeric
|
|
1155
1114
|
|
|
1156
|
-
return invalid("lc", mth, 1, DBG, 0)
|
|
1115
|
+
return invalid("lc", mth, 1, DBG, 0.0) unless lc.respond_to?(NS)
|
|
1157
1116
|
id = lc.nameString
|
|
1158
|
-
return mismatch(id, lc, cl1, mth, DBG, 0)
|
|
1159
|
-
|
|
1160
|
-
return
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
return
|
|
1164
|
-
return mismatch("temperature", t, cl2, mth, DBG, 0) unless t.is_a?(cl2)
|
|
1165
|
-
|
|
1166
|
-
tt = t + 273.0 # °C to K
|
|
1167
|
-
return negative("temp K", mth, DBG, 0) if tt < 0
|
|
1168
|
-
return negative("film", mth, DBG, 0) if film < 0
|
|
1117
|
+
return mismatch(id, lc, cl1, mth, DBG, 0.0) unless lc.is_a?(cl1)
|
|
1118
|
+
return mismatch("film", film, cl2, mth, DBG, 0.0) unless film.is_a?(cl2)
|
|
1119
|
+
return mismatch("temp K", t, cl2, mth, DBG, 0.0) unless t.is_a?(cl2)
|
|
1120
|
+
t += 273.0 # °C to K
|
|
1121
|
+
return negative("temp K", mth, DBG, 0.0) if t < 0
|
|
1122
|
+
return negative("film", mth, DBG, 0.0) if film < 0
|
|
1169
1123
|
|
|
1170
1124
|
rsi = film
|
|
1171
1125
|
|
|
1172
1126
|
lc.layers.each do |m|
|
|
1173
1127
|
# Fenestration materials first (ignoring shades, screens, etc.)
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
rsi += m.to_Gas.get.getThermalResistance(tt)
|
|
1185
|
-
end
|
|
1186
|
-
unless m.to_GasMixture.empty?
|
|
1187
|
-
rsi += m.to_GasMixture.get.getThermalResistance(tt)
|
|
1188
|
-
end
|
|
1128
|
+
empty = m.to_SimpleGlazing.empty?
|
|
1129
|
+
return 1 / m.to_SimpleGlazing.get.uFactor unless empty
|
|
1130
|
+
empty = m.to_StandardGlazing.empty?
|
|
1131
|
+
rsi += m.to_StandardGlazing.get.thermalResistance unless empty
|
|
1132
|
+
empty = m.to_RefractionExtinctionGlazing.empty?
|
|
1133
|
+
rsi += m.to_RefractionExtinctionGlazing.get.thermalResistance unless empty
|
|
1134
|
+
empty = m.to_Gas.empty?
|
|
1135
|
+
rsi += m.to_Gas.get.getThermalResistance(t) unless empty
|
|
1136
|
+
empty = m.to_GasMixture.empty?
|
|
1137
|
+
rsi += m.to_GasMixture.get.getThermalResistance(t) unless empty
|
|
1189
1138
|
|
|
1190
1139
|
# Opaque materials next.
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
end
|
|
1200
|
-
unless m.to_AirGap.empty?
|
|
1201
|
-
rsi += m.to_AirGap.get.thermalResistance
|
|
1202
|
-
end
|
|
1140
|
+
empty = m.to_StandardOpaqueMaterial.empty?
|
|
1141
|
+
rsi += m.to_StandardOpaqueMaterial.get.thermalResistance unless empty
|
|
1142
|
+
empty = m.to_MasslessOpaqueMaterial.empty?
|
|
1143
|
+
rsi += m.to_MasslessOpaqueMaterial.get.thermalResistance unless empty
|
|
1144
|
+
empty = m.to_RoofVegetation.empty?
|
|
1145
|
+
rsi += m.to_RoofVegetation.get.thermalResistance unless empty
|
|
1146
|
+
empty = m.to_AirGap.empty?
|
|
1147
|
+
rsi += m.to_AirGap.get.thermalResistance unless empty
|
|
1203
1148
|
end
|
|
1204
1149
|
|
|
1205
1150
|
rsi
|
|
@@ -1215,18 +1160,17 @@ module OSut
|
|
|
1215
1160
|
#
|
|
1216
1161
|
# @return [Hash] index: (Integer), type: (:standard or :massless), r: (Float)
|
|
1217
1162
|
# @return [Hash] index: nil, type: nil, r: 0 (if invalid input)
|
|
1218
|
-
def insulatingLayer(lc)
|
|
1163
|
+
def insulatingLayer(lc = nil)
|
|
1219
1164
|
mth = "OSut::#{__callee__}"
|
|
1220
1165
|
cl = OpenStudio::Model::LayeredConstruction
|
|
1221
1166
|
res = { index: nil, type: nil, r: 0.0 }
|
|
1222
1167
|
i = 0 # iterator
|
|
1223
1168
|
|
|
1224
|
-
return invalid("lc", mth, 1, DBG, res)
|
|
1169
|
+
return invalid("lc", mth, 1, DBG, res) unless lc.respond_to?(NS)
|
|
1225
1170
|
id = lc.nameString
|
|
1226
1171
|
return mismatch(id, lc, cl1, mth, DBG, res) unless lc.is_a?(cl)
|
|
1227
1172
|
|
|
1228
1173
|
lc.layers.each do |m|
|
|
1229
|
-
|
|
1230
1174
|
unless m.to_MasslessOpaqueMaterial.empty?
|
|
1231
1175
|
m = m.to_MasslessOpaqueMaterial.get
|
|
1232
1176
|
|
|
@@ -1269,15 +1213,13 @@ module OSut
|
|
|
1269
1213
|
#
|
|
1270
1214
|
# @return [Hash] t: (OpenStudio::Transformation), r: Float
|
|
1271
1215
|
# @return [Hash] t: nil, r: nil (if invalid input)
|
|
1272
|
-
def transforms(model, group)
|
|
1216
|
+
def transforms(model = nil, group = nil)
|
|
1273
1217
|
mth = "OSut::#{__callee__}"
|
|
1274
1218
|
cl1 = OpenStudio::Model::Model
|
|
1275
1219
|
cl2 = OpenStudio::Model::PlanarSurfaceGroup
|
|
1276
1220
|
res = { t: nil, r: nil }
|
|
1277
1221
|
|
|
1278
|
-
return invalid("model", mth, 1, DBG, res) unless model
|
|
1279
1222
|
return mismatch("model", model, cl1, mth, DBG, res) unless model.is_a?(cl1)
|
|
1280
|
-
|
|
1281
1223
|
return invalid("group", mth, 2, DBG, res) unless group.respond_to?(NS)
|
|
1282
1224
|
id = group.nameString
|
|
1283
1225
|
return mismatch(id, group, cl2, mth, DBG, res) unless group.is_a?(cl2)
|
|
@@ -1294,16 +1236,14 @@ module OSut
|
|
|
1294
1236
|
# @param pts [Array] an OpenStudio Point3D array/vector
|
|
1295
1237
|
#
|
|
1296
1238
|
# @return [Array] flattened OpenStudio 3D points
|
|
1297
|
-
def flatZ(pts)
|
|
1239
|
+
def flatZ(pts = nil)
|
|
1298
1240
|
mth = "OSut::#{__callee__}"
|
|
1299
1241
|
cl1 = OpenStudio::Point3dVector
|
|
1300
1242
|
cl2 = OpenStudio::Point3d
|
|
1301
|
-
v
|
|
1243
|
+
v = OpenStudio::Point3dVector.new
|
|
1302
1244
|
|
|
1303
|
-
return invalid("points", mth, 1, DBG, v) unless pts
|
|
1304
1245
|
valid = pts.is_a?(cl1) || pts.is_a?(Array)
|
|
1305
|
-
return mismatch("points", pts, cl1, mth, DBG, v)
|
|
1306
|
-
|
|
1246
|
+
return mismatch("points", pts, cl1, mth, DBG, v) unless valid
|
|
1307
1247
|
pts.each { |pt| mismatch("pt", pt, cl2, mth, ERR, v) unless pt.is_a?(cl2) }
|
|
1308
1248
|
pts.each { |pt| v << OpenStudio::Point3d.new(pt.x, pt.y, 0) }
|
|
1309
1249
|
|
|
@@ -1320,53 +1260,49 @@ module OSut
|
|
|
1320
1260
|
#
|
|
1321
1261
|
# @return [Bool] true if 1st polygon fits entirely within the 2nd polygon
|
|
1322
1262
|
# @return [Bool] false if invalid input
|
|
1323
|
-
def fits?(p1, p2, id1 = "", id2 = "")
|
|
1263
|
+
def fits?(p1 = nil, p2 = nil, id1 = "", id2 = "")
|
|
1324
1264
|
mth = "OSut::#{__callee__}"
|
|
1325
1265
|
cl1 = OpenStudio::Point3dVector
|
|
1326
1266
|
cl2 = OpenStudio::Point3d
|
|
1327
1267
|
a = false
|
|
1268
|
+
|
|
1269
|
+
return invalid("id1", mth, 3, DBG, a) unless id1.respond_to?(:to_s)
|
|
1270
|
+
return invalid("id2", mth, 4, DBG, a) unless id2.respond_to?(:to_s)
|
|
1328
1271
|
i1 = id1.to_s
|
|
1329
1272
|
i2 = id2.to_s
|
|
1330
1273
|
i1 = "poly1" if i1.empty?
|
|
1331
1274
|
i2 = "poly2" if i2.empty?
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
return mismatch(
|
|
1275
|
+
valid1 = p1.is_a?(cl1) || p1.is_a?(Array)
|
|
1276
|
+
valid2 = p2.is_a?(cl1) || p2.is_a?(Array)
|
|
1277
|
+
return mismatch(i1, p1, cl1, mth, DBG, a) unless valid1
|
|
1278
|
+
return mismatch(i2, p2, cl1, mth, DBG, a) unless valid2
|
|
1336
1279
|
return empty(i1, mth, ERR, a) if p1.empty?
|
|
1337
|
-
|
|
1338
|
-
return invalid(i2, mth, 2, DBG, a) unless p2
|
|
1339
|
-
valid = p2.is_a?(cl1) || p2.is_a?(Array)
|
|
1340
|
-
return mismatch(i2, p2, cl1, mth, DBG, a) unless valid
|
|
1341
1280
|
return empty(i2, mth, ERR, a) if p2.empty?
|
|
1342
|
-
|
|
1343
1281
|
p1.each { |v| return mismatch(i1, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
|
|
1344
1282
|
p2.each { |v| return mismatch(i2, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
|
|
1345
1283
|
|
|
1346
1284
|
ft = OpenStudio::Transformation::alignFace(p1).inverse
|
|
1347
|
-
|
|
1348
1285
|
ft_p1 = flatZ( (ft * p1).reverse )
|
|
1349
1286
|
return false if ft_p1.empty?
|
|
1350
1287
|
area1 = OpenStudio::getArea(ft_p1)
|
|
1351
|
-
return empty(i1, mth, ERR, a) if area1.empty?
|
|
1288
|
+
return empty("#{i1} area", mth, ERR, a) if area1.empty?
|
|
1352
1289
|
area1 = area1.get
|
|
1353
|
-
|
|
1354
1290
|
ft_p2 = flatZ( (ft * p2).reverse )
|
|
1355
1291
|
return false if ft_p2.empty?
|
|
1356
1292
|
area2 = OpenStudio::getArea(ft_p2)
|
|
1357
|
-
return empty(i2, mth, ERR, a) if area2.empty?
|
|
1293
|
+
return empty("#{i2} area", mth, ERR, a) if area2.empty?
|
|
1358
1294
|
area2 = area2.get
|
|
1359
|
-
|
|
1360
1295
|
union = OpenStudio::join(ft_p1, ft_p2, TOL2)
|
|
1361
1296
|
return false if union.empty?
|
|
1362
1297
|
union = union.get
|
|
1363
1298
|
area = OpenStudio::getArea(union)
|
|
1364
|
-
return empty("union", mth, ERR, a) if area.empty?
|
|
1299
|
+
return empty("#{i1}:#{i2} union area", mth, ERR, a) if area.empty?
|
|
1365
1300
|
area = area.get
|
|
1366
1301
|
|
|
1367
1302
|
return false if area < TOL
|
|
1368
1303
|
return true if (area - area2).abs < TOL
|
|
1369
1304
|
return false if (area - area2).abs > TOL
|
|
1305
|
+
|
|
1370
1306
|
true
|
|
1371
1307
|
end
|
|
1372
1308
|
|
|
@@ -1380,51 +1316,55 @@ module OSut
|
|
|
1380
1316
|
#
|
|
1381
1317
|
# @return Returns true if polygons overlaps (or either fits into the other)
|
|
1382
1318
|
# @return [Bool] false if invalid input
|
|
1383
|
-
def overlaps?(p1, p2, id1 = "", id2 = "")
|
|
1319
|
+
def overlaps?(p1 = nil, p2 = nil, id1 = "", id2 = "")
|
|
1384
1320
|
mth = "OSut::#{__callee__}"
|
|
1385
1321
|
cl1 = OpenStudio::Point3dVector
|
|
1386
1322
|
cl2 = OpenStudio::Point3d
|
|
1387
1323
|
a = false
|
|
1388
|
-
i1 = id1.to_s
|
|
1389
|
-
i2 = id2.to_s
|
|
1390
|
-
i1 = "poly1" if i1.empty?
|
|
1391
|
-
i2 = "poly2" if i2.empty?
|
|
1392
1324
|
|
|
1393
|
-
return invalid(
|
|
1394
|
-
|
|
1395
|
-
|
|
1325
|
+
return invalid("id1", mth, 3, DBG, a) unless id1.respond_to?(:to_s)
|
|
1326
|
+
return invalid("id2", mth, 4, DBG, a) unless id2.respond_to?(:to_s)
|
|
1327
|
+
i1 = id1.to_s
|
|
1328
|
+
i2 = id2.to_s
|
|
1329
|
+
i1 = "poly1" if i1.empty?
|
|
1330
|
+
i2 = "poly2" if i2.empty?
|
|
1331
|
+
valid1 = p1.is_a?(cl1) || p1.is_a?(Array)
|
|
1332
|
+
valid2 = p2.is_a?(cl1) || p2.is_a?(Array)
|
|
1333
|
+
return mismatch(i1, p1, cl1, mth, DBG, a) unless valid1
|
|
1334
|
+
return mismatch(i2, p2, cl1, mth, DBG, a) unless valid2
|
|
1396
1335
|
return empty(i1, mth, ERR, a) if p1.empty?
|
|
1397
|
-
|
|
1398
|
-
return invalid(i2, mth, 2, DBG, a) unless p2
|
|
1399
|
-
valid = p2.is_a?(cl1) || p2.is_a?(Array)
|
|
1400
|
-
return mismatch(i2, p2, cl1, mth, DBG, a) unless valid
|
|
1401
1336
|
return empty(i2, mth, ERR, a) if p2.empty?
|
|
1402
|
-
|
|
1403
1337
|
p1.each { |v| return mismatch(i1, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
|
|
1404
1338
|
p2.each { |v| return mismatch(i2, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
|
|
1405
1339
|
|
|
1406
1340
|
ft = OpenStudio::Transformation::alignFace(p1).inverse
|
|
1407
|
-
|
|
1408
1341
|
ft_p1 = flatZ( (ft * p1).reverse )
|
|
1409
1342
|
return false if ft_p1.empty?
|
|
1410
1343
|
area1 = OpenStudio::getArea(ft_p1)
|
|
1411
|
-
return empty(i1, mth, ERR, a) if area1.empty?
|
|
1344
|
+
return empty("#{i1} area", mth, ERR, a) if area1.empty?
|
|
1412
1345
|
area1 = area1.get
|
|
1413
|
-
|
|
1414
1346
|
ft_p2 = flatZ( (ft * p2).reverse )
|
|
1415
1347
|
return false if ft_p2.empty?
|
|
1416
1348
|
area2 = OpenStudio::getArea(ft_p2)
|
|
1417
|
-
return empty(i2, mth, ERR, a) if area2.empty?
|
|
1349
|
+
return empty("#{i2} area", mth, ERR, a) if area2.empty?
|
|
1418
1350
|
area2 = area2.get
|
|
1419
|
-
|
|
1420
1351
|
union = OpenStudio::join(ft_p1, ft_p2, TOL2)
|
|
1421
1352
|
return false if union.empty?
|
|
1422
1353
|
union = union.get
|
|
1423
1354
|
area = OpenStudio::getArea(union)
|
|
1424
|
-
return empty("union", mth, ERR, a) if area.empty?
|
|
1355
|
+
return empty("#{i1}:#{i2} union area", mth, ERR, a) if area.empty?
|
|
1425
1356
|
area = area.get
|
|
1426
1357
|
|
|
1427
1358
|
return false if area < TOL
|
|
1359
|
+
|
|
1428
1360
|
true
|
|
1429
1361
|
end
|
|
1362
|
+
|
|
1363
|
+
##
|
|
1364
|
+
# Callback when other modules extend OSlg
|
|
1365
|
+
#
|
|
1366
|
+
# @param base [Object] instance or class object
|
|
1367
|
+
def self.extended(base)
|
|
1368
|
+
base.send(:include, self)
|
|
1369
|
+
end
|
|
1430
1370
|
end
|
data/lib/osut/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: osut
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Denis Bourgeois
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-
|
|
11
|
+
date: 2022-08-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: oslg
|
|
@@ -90,7 +90,7 @@ licenses:
|
|
|
90
90
|
- BSD-3-Clause
|
|
91
91
|
metadata:
|
|
92
92
|
homepage_uri: https://github.com/rd2/osut
|
|
93
|
-
source_code_uri: https://github.com/rd2/osut/tree/v0.2.
|
|
93
|
+
source_code_uri: https://github.com/rd2/osut/tree/v0.2.6
|
|
94
94
|
bug_tracker_uri: https://github.com/rd2/osut/issues
|
|
95
95
|
post_install_message:
|
|
96
96
|
rdoc_options: []
|