osut 0.2.2 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|