osut 0.2.2 → 0.2.3

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/osut/utils.rb +218 -268
  3. data/lib/osut/version.rb +1 -1
  4. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6694166e055d664bf9ac9b0d155874e6bbf55e9ebdce91bf9566fe8f8c5c4365
4
- data.tar.gz: be5804b79d0df25606a9d4b0a41607d405d8786c89c4695661c56bfcef4d0a93
3
+ metadata.gz: be4500de4b7207ef0f1bb50342c4f63e12714bf22a17779f928b51adba0b862f
4
+ data.tar.gz: 3b4aa51dff5771c31fe5edc89d1326555447d2eaa7844b4944ff43b84b01cad2
5
5
  SHA512:
6
- metadata.gz: d1a0ecc532b9825109b8fc321721041db6da61058ed1bdc6d35736359ffade836843f8b15969d80ec9c7a8b27086ab1bd80b5bdade5b1c9129ad3a6a0c96b477
7
- data.tar.gz: '09e1f33ba5a139332ece204787fd262a3c89e641b8e4b7355a77509f49f166baace2b9686b4485f6c59bc28c1169b4b7d54bffcdfd185260dbdae066d23e0d7a'
6
+ metadata.gz: 47c84a2d136ec1b6552436cdcc555469813987485f64a2a4ddfa99788f5ee1d5b99d4b369b50766652b028f39204d3efccf7793276400e256d81492bbb85127f
7
+ data.tar.gz: af28329f47ff40ac971ec3b9333c0e21cb0ef293f1c2697aeebe96d0009acba34696a1f43c9bf07828b854ae8bd110b95b295bcb849dc8e0ff3e21236e4de308
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) unless sched.respond_to?(NS)
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
- unless val.is_a?(Numeric)
153
- log(WRN, "Skipping non-numeric profile values in '#{id}' (#{mth})")
154
- next
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) unless sched.respond_to?(NS)
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
- unless sched.value.is_a?(Numeric)
193
- return mismatch("'#{id}' value", sched.value, Numeric, mth, ERR, res)
194
- else
195
- res[:min] = sched.value
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) unless sched.respond_to?(NS)
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
- if vals.min.is_a?(Numeric) && vals.max.is_a?(Numeric)
238
- res[:min] = vals.min
239
- res[:max] = vals.max
240
- else
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) unless sched.respond_to?(NS)
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
- if vals.min.is_a?(Numeric) && vals.max.is_a?(Numeric)
267
- res[:min] = vals.min
268
- res[:max] = vals.max
269
- else
270
- log(ERR, "Non-numeric values in '#{id}' (#{mth})")
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) unless zone.respond_to?(NS)
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
 
@@ -310,9 +304,16 @@ module OSut
310
304
  end
311
305
  end
312
306
 
307
+ # unless equip.to_ZoneHVACLowTemperatureRadiantElectric.empty?
308
+ # equip = equip.to_ZoneHVACLowTemperatureRadiantElectric.get
309
+ #
310
+ # unless equip.heatingSetpointTemperatureSchedule.empty?
311
+ # sched = equip.heatingSetpointTemperatureSchedule.get
312
+ # end
313
+ # end
314
+
313
315
  unless equip.to_ZoneHVACLowTemperatureRadiantElectric.empty?
314
316
  equip = equip.to_ZoneHVACLowTemperatureRadiantElectric.get
315
-
316
317
  unless equip.heatingSetpointTemperatureSchedule.empty?
317
318
  sched = equip.heatingSetpointTemperatureSchedule.get
318
319
  end
@@ -377,13 +378,12 @@ module OSut
377
378
  end
378
379
  end
379
380
 
380
- return res if res[:spt]
381
381
  return res if zone.thermostat.empty?
382
- tstat = zone.thermostat.get
382
+ tstat = zone.thermostat.get
383
+ res[:spt] = nil
383
384
 
384
385
  unless tstat.to_ThermostatSetpointDualSetpoint.empty? &&
385
386
  tstat.to_ZoneControlThermostatStagedDualSetpoint.empty?
386
- res[:dual] = true
387
387
 
388
388
  unless tstat.to_ThermostatSetpointDualSetpoint.empty?
389
389
  tstat = tstat.to_ThermostatSetpointDualSetpoint.get
@@ -392,7 +392,8 @@ module OSut
392
392
  end
393
393
 
394
394
  unless tstat.heatingSetpointTemperatureSchedule.empty?
395
- sched = tstat.heatingSetpointTemperatureSchedule.get
395
+ res[:dual] = true
396
+ sched = tstat.heatingSetpointTemperatureSchedule.get
396
397
 
397
398
  unless sched.to_ScheduleRuleset.empty?
398
399
  sched = sched.to_ScheduleRuleset.get
@@ -456,11 +457,10 @@ module OSut
456
457
  #
457
458
  # @return [Bool] true if valid heating temperature setpoints
458
459
  # @return [Bool] false if invalid input
459
- def heatingTemperatureSetpoints?(model)
460
+ def heatingTemperatureSetpoints?(model = nil)
460
461
  mth = "OSut::#{__callee__}"
461
- cl = OpenStudio::Model::Model
462
+ cl = OpenStudio::Model::Model
462
463
 
463
- return invalid("model", mth, 1, DBG, false) unless model
464
464
  return mismatch("model", model, cl, mth, DBG, false) unless model.is_a?(cl)
465
465
 
466
466
  model.getThermalZones.each do |zone|
@@ -478,7 +478,7 @@ module OSut
478
478
  #
479
479
  # @return [Hash] spt: (Float), dual: (Bool)
480
480
  # @return [Hash] spt: nil, dual: false (if invalid input)
481
- def minCoolScheduledSetpoint(zone)
481
+ def minCoolScheduledSetpoint(zone = nil)
482
482
  # Largely inspired from Parker & Marrec's "thermal_zone_cooled?" procedure.
483
483
  #
484
484
  # github.com/NREL/openstudio-standards/blob/
@@ -488,7 +488,7 @@ module OSut
488
488
  cl = OpenStudio::Model::ThermalZone
489
489
  res = { spt: nil, dual: false }
490
490
 
491
- return invalid("zone", mth, 1, DBG, res) unless zone.respond_to?(NS)
491
+ return invalid("zone", mth, 1, DBG, res) unless zone.respond_to?(NS)
492
492
  id = zone.nameString
493
493
  return mismatch(id, zone, cl, mth, DBG, res) unless zone.is_a?(cl)
494
494
 
@@ -555,13 +555,12 @@ module OSut
555
555
  end
556
556
  end
557
557
 
558
- return res if res[:spt]
559
558
  return res if zone.thermostat.empty?
560
- tstat = zone.thermostat.get
559
+ tstat = zone.thermostat.get
560
+ res[:spt] = nil
561
561
 
562
562
  unless tstat.to_ThermostatSetpointDualSetpoint.empty? &&
563
563
  tstat.to_ZoneControlThermostatStagedDualSetpoint.empty?
564
- res[:dual] = true
565
564
 
566
565
  unless tstat.to_ThermostatSetpointDualSetpoint.empty?
567
566
  tstat = tstat.to_ThermostatSetpointDualSetpoint.get
@@ -570,7 +569,8 @@ module OSut
570
569
  end
571
570
 
572
571
  unless tstat.coolingSetpointTemperatureSchedule.empty?
573
- sched = tstat.coolingSetpointTemperatureSchedule.get
572
+ res[:dual] = true
573
+ sched = tstat.coolingSetpointTemperatureSchedule.get
574
574
 
575
575
  unless sched.to_ScheduleRuleset.empty?
576
576
  sched = sched.to_ScheduleRuleset.get
@@ -634,11 +634,10 @@ module OSut
634
634
  #
635
635
  # @return [Bool] true if valid cooling temperature setpoints
636
636
  # @return [Bool] false if invalid input
637
- def coolingTemperatureSetpoints?(model)
637
+ def coolingTemperatureSetpoints?(model = nil)
638
638
  mth = "OSut::#{__callee__}"
639
- cl = OpenStudio::Model::Model
639
+ cl = OpenStudio::Model::Model
640
640
 
641
- return invalid("model", mth, 1, DBG, false) unless model
642
641
  return mismatch("model", model, cl, mth, DBG, false) unless model.is_a?(cl)
643
642
 
644
643
  model.getThermalZones.each do |zone|
@@ -655,11 +654,10 @@ module OSut
655
654
  #
656
655
  # @return [Bool] true if model has one or more HVAC air loops
657
656
  # @return [Bool] false if invalid input
658
- def airLoopsHVAC?(model)
657
+ def airLoopsHVAC?(model = nil)
659
658
  mth = "OSut::#{__callee__}"
660
- cl = OpenStudio::Model::Model
659
+ cl = OpenStudio::Model::Model
661
660
 
662
- return invalid("model", mth, 1, DBG, false) unless model
663
661
  return mismatch("model", model, cl, mth, DBG, false) unless model.is_a?(cl)
664
662
 
665
663
  model.getThermalZones.each do |zone|
@@ -680,68 +678,59 @@ module OSut
680
678
  #
681
679
  # @return [Bool] true if should be tagged as plenum
682
680
  # @return [Bool] false if invalid input
683
- def plenum?(space, loops, setpoints)
681
+ def plenum?(space = nil, loops = nil, setpoints = nil)
684
682
  # Largely inspired from NREL's "space_plenum?" procedure:
685
683
  #
686
684
  # github.com/NREL/openstudio-standards/blob/
687
685
  # 58964222d25783e9da4ae292e375fb0d5c902aa5/lib/openstudio-standards/
688
686
  # standards/Standards.Space.rb#L1384
689
-
687
+ #
690
688
  # A space may be tagged as a plenum if:
691
689
  #
692
690
  # CASE A: its zone's "isPlenum" == true (SDK method) for a fully-developed
693
691
  # OpenStudio model (complete with HVAC air loops);
694
692
  #
695
- # CASE B: it's excluded from building's total floor area yet linked to a
696
- # zone holding an "inactive" thermostat (i.e., can't extract
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
693
+ # CASE B: (IN ABSENCE OF HVAC AIRLOOPS) if it's excluded from a building's
694
+ # total floor area yet linked to a zone holding an 'inactive'
695
+ # thermostat, i.e. can't extract valid setpoints; OR
701
696
  #
702
- # CASE D: its name string holds "plenum" (also case insensitive).
703
-
697
+ # CASE C: (IN ABSENCE OF HVAC AIRLOOPS & VALID SETPOINTS) it has "plenum"
698
+ # (case insensitive) as a spacetype (or as a spacetype's
699
+ # 'standards spacetype').
704
700
  mth = "OSut::#{__callee__}"
705
701
  cl = OpenStudio::Model::Space
706
702
 
707
- return invalid("space", mth, 1, DBG, false) unless space.respond_to?(NS)
703
+ return invalid("space", mth, 1, DBG, false) unless space.respond_to?(NS)
708
704
  id = space.nameString
709
705
  return mismatch(id, space, cl, mth, DBG, false) unless space.is_a?(cl)
710
-
711
706
  valid = loops == true || loops == false
712
- return invalid("loops", mth, 2, DBG, false) unless valid
713
-
707
+ return invalid("loops", mth, 2, DBG, false) unless valid
714
708
  valid = setpoints == true || setpoints == false
715
709
  return invalid("setpoints", mth, 3, DBG, false) unless valid
716
710
 
717
711
  unless space.thermalZone.empty?
718
712
  zone = space.thermalZone.get
719
- return true if zone.isPlenum && loops # CASE A
713
+ return zone.isPlenum if loops # A
720
714
 
721
715
  if setpoints
722
- heating = maxHeatScheduledSetpoint(zone)
723
- cooling = minCoolScheduledSetpoint(zone)
724
-
725
- return false if heating[:spt] || cooling[:spt] # directly conditioned
726
-
727
- unless space.partofTotalFloorArea
728
- return true if heating[:dual] || cooling[:dual] # CASE B
729
- end
716
+ heat = maxHeatScheduledSetpoint(zone)
717
+ cool = minCoolScheduledSetpoint(zone)
718
+ return false if heat[:spt] || cool[:spt] # directly conditioned
719
+ return heat[:dual] || cool[:dual] unless space.partofTotalFloorArea # B
720
+ return false
730
721
  end
731
722
  end
732
723
 
733
724
  unless space.spaceType.empty?
734
725
  type = space.spaceType.get
735
- return true if type.nameString.downcase.include?("plenum") # CASE C
726
+ return type.nameString.downcase == "plenum" # C
736
727
 
737
728
  unless type.standardsSpaceType.empty?
738
729
  type = type.standardsSpaceType.get
739
- return true if type.downcase.include?("plenum") # CASE C
730
+ return type.downcase == "plenum" # C
740
731
  end
741
732
  end
742
733
 
743
- return true if space.nameString.downcase.include?("plenum")
744
-
745
734
  false
746
735
  end
747
736
 
@@ -752,17 +741,16 @@ module OSut
752
741
  # @param avl [String] seasonal availability choice (optional, default "ON")
753
742
  #
754
743
  # @return [OpenStudio::Model::Schedule] HVAC availability sched
755
- # @return [nil] if invalid input
756
- def availabilitySchedule(model, avl = "")
757
- mth = "OSut::#{__callee__}"
758
- cl = OpenStudio::Model::Model
744
+ # @return [NilClass] if invalid input
745
+ def availabilitySchedule(model = nil, avl = "")
746
+ mth = "OSut::#{__callee__}"
747
+ cl = OpenStudio::Model::Model
748
+ limits = nil
759
749
 
760
- return invalid("model", mth, 1) unless model
761
- return mismatch("model", model, cl, mth) unless model.is_a?(cl)
750
+ return mismatch("model", model, cl, mth) unless model.is_a?(cl)
751
+ return invalid("availability", avl, 2, mth) unless avl.respond_to?(:to_s)
762
752
 
763
753
  # Either fetch availability ScheduleTypeLimits object, or create one.
764
- limits = nil
765
-
766
754
  model.getScheduleTypeLimitss.each do |l|
767
755
  break if limits
768
756
  next if l.lowerLimitValue.empty?
@@ -797,7 +785,7 @@ module OSut
797
785
  may01 = year.makeDate(OpenStudio::MonthOfYear.new("May"), 1)
798
786
  oct31 = year.makeDate(OpenStudio::MonthOfYear.new("Oct"), 31)
799
787
 
800
- case avl.downcase
788
+ case avl.to_s.downcase
801
789
  when "winter" # available from November 1 to April 30 (6 months)
802
790
  val = 1
803
791
  sch = off
@@ -838,29 +826,29 @@ module OSut
838
826
  unless schedule.empty?
839
827
  schedule = schedule.get
840
828
  default = schedule.defaultDaySchedule
841
- ok = ok && default.nameString == dft
842
- ok = ok && default.times.size == 1
843
- ok = ok && default.values.size == 1
844
- ok = ok && default.times.first == time
845
- ok = ok && default.values.first == val
829
+ ok = ok && default.nameString == dft
830
+ ok = ok && default.times.size == 1
831
+ ok = ok && default.values.size == 1
832
+ ok = ok && default.times.first == time
833
+ ok = ok && default.values.first == val
846
834
  rules = schedule.scheduleRules
847
835
  ok = ok && (rules.size == 0 || rules.size == 1)
848
836
 
849
837
  if rules.size == 1
850
838
  rule = rules.first
851
- ok = ok && rule.nameString == tag
839
+ ok = ok && rule.nameString == tag
852
840
  ok = ok && !rule.startDate.empty?
853
841
  ok = ok && !rule.endDate.empty?
854
- ok = ok && rule.startDate.get == may01
855
- ok = ok && rule.endDate.get == oct31
842
+ ok = ok && rule.startDate.get == may01
843
+ ok = ok && rule.endDate.get == oct31
856
844
  ok = ok && rule.applyAllDays
857
845
 
858
846
  d = rule.daySchedule
859
- ok = ok && d.nameString == day
860
- ok = ok && d.times.size == 1
861
- ok = ok && d.values.size == 1
847
+ ok = ok && d.nameString == day
848
+ ok = ok && d.times.size == 1
849
+ ok = ok && d.values.size == 1
862
850
  ok = ok && d.times.first.totalSeconds == secs
863
- ok = ok && d.values.first.to_i != val
851
+ ok = ok && d.values.first.to_i != val
864
852
  end
865
853
 
866
854
  return schedule if ok
@@ -869,38 +857,26 @@ module OSut
869
857
 
870
858
  schedule = OpenStudio::Model::ScheduleRuleset.new(model)
871
859
  schedule.setName(nom)
872
-
873
- unless schedule.setScheduleTypeLimits(limits)
874
- log(ERR, "'#{nom}': Can't set schedule type limits (#{mth})")
875
- return nil
876
- end
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
-
860
+ ok = schedule.setScheduleTypeLimits(limits)
861
+ log(ERR, "'#{nom}': Can't set schedule type limits (#{mth})") unless ok
862
+ return nil unless ok
863
+ ok = schedule.defaultDaySchedule.addValue(time, val)
864
+ log(ERR, "'#{nom}': Can't set default day schedule (#{mth})") unless ok
865
+ return nil unless ok
883
866
  schedule.defaultDaySchedule.setName(dft)
884
867
 
885
868
  unless tag.empty?
886
869
  rule = OpenStudio::Model::ScheduleRule.new(schedule, sch)
887
870
  rule.setName(tag)
888
-
889
- unless rule.setStartDate(may01)
890
- log(ERR, "'#{tag}': Can't set start date (#{mth})")
891
- return nil
892
- end
893
-
894
- unless rule.setEndDate(oct31)
895
- log(ERR, "'#{tag}': Can't set end date (#{mth})")
896
- return nil
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
-
871
+ ok = rule.setStartDate(may01)
872
+ log(ERR, "'#{tag}': Can't set start date (#{mth})") unless ok
873
+ return nil unless ok
874
+ ok = rule.setEndDate(oct31)
875
+ log(ERR, "'#{tag}': Can't set end date (#{mth})") unless ok
876
+ return nil unless ok
877
+ ok = rule.setApplyAllDays(true)
878
+ log(ERR, "'#{tag}': Can't apply to all days (#{mth})") unless ok
879
+ return nil unless ok
904
880
  rule.daySchedule.setName(day)
905
881
  end
906
882
 
@@ -911,43 +887,41 @@ module OSut
911
887
  # Validate if default construction set holds a base ground construction.
912
888
  #
913
889
  # @param set [OpenStudio::Model::DefaultConstructionSet] a default set
914
- # @param base [OpensStudio::Model::ConstructionBase] a construction base
915
- # @param ground [Bool] true if ground-facing surface
916
- # @param exterior [Bool] true if exterior-facing surface
917
- # @param type [String] a surface type
890
+ # @param bse [OpensStudio::Model::ConstructionBase] a construction base
891
+ # @param gr [Bool] true if ground-facing surface
892
+ # @param ex [Bool] true if exterior-facing surface
893
+ # @param typ [String] a surface type
918
894
  #
919
895
  # @return [Bool] true if default construction set holds construction
920
896
  # @return [Bool] false if invalid input
921
- def holdsConstruction?(set, base, ground = false, exterior = false, type = "")
897
+ def holdsConstruction?(set = nil, bse = nil, gr = false, ex = false, typ = "")
922
898
  mth = "OSut::#{__callee__}"
923
899
  cl1 = OpenStudio::Model::DefaultConstructionSet
924
900
  cl2 = OpenStudio::Model::ConstructionBase
925
901
 
926
- return invalid("set", mth, 1, DBG, false) unless set.respond_to?(NS)
902
+ return invalid("set", mth, 1, DBG, false) unless set.respond_to?(NS)
927
903
  id = set.nameString
928
- return mismatch(id, set, cl1, mth, DBG, false) unless set.is_a?(cl1)
929
-
930
- return invalid("base", mth, 2, DBG, false) unless base.respond_to?(NS)
931
- id = base.nameString
932
- return mismatch(id, base, cl2, mth, DBG, false) unless base.is_a?(cl2)
933
-
934
- valid = ground == true || ground == false
935
- return invalid("ground", mth, 3, DBG, false) unless valid
936
-
937
- valid = exterior == true || exterior == false
938
- return invalid("exterior", mth, 4, DBG, false) unless valid
939
-
940
- typ = type.to_s.downcase
941
- valid = typ == "floor" || typ == "wall" || typ == "roofceiling"
904
+ return mismatch(id, set, cl1, mth, DBG, false) unless set.is_a?(cl1)
905
+ return invalid("base", mth, 2, DBG, false) unless bse.respond_to?(NS)
906
+ id = bse.nameString
907
+ return mismatch(id, bse, cl2, mth, DBG, false) unless bse.is_a?(cl2)
908
+ valid = gr == true || gr == false
909
+ return invalid("ground", mth, 3, DBG, false) unless valid
910
+ valid = ex == true || ex == false
911
+ return invalid("exterior", mth, 4, DBG, false) unless valid
912
+ valid = typ.respond_to?(:to_s)
913
+ return invalid("surface typ", mth, 4, DBG, false) unless valid
914
+ type = typ.to_s.downcase
915
+ valid = type == "floor" || type == "wall" || type == "roofceiling"
942
916
  return invalid("surface type", mth, 5, DBG, false) unless valid
943
917
 
944
918
  constructions = nil
945
919
 
946
- if ground
920
+ if gr
947
921
  unless set.defaultGroundContactSurfaceConstructions.empty?
948
922
  constructions = set.defaultGroundContactSurfaceConstructions.get
949
923
  end
950
- elsif exterior
924
+ elsif ex
951
925
  unless set.defaultExteriorSurfaceConstructions.empty?
952
926
  constructions = set.defaultExteriorSurfaceConstructions.get
953
927
  end
@@ -959,21 +933,21 @@ module OSut
959
933
 
960
934
  return false unless constructions
961
935
 
962
- case typ
936
+ case type
963
937
  when "roofceiling"
964
938
  unless constructions.roofCeilingConstruction.empty?
965
939
  construction = constructions.roofCeilingConstruction.get
966
- return true if construction == base
940
+ return true if construction == bse
967
941
  end
968
942
  when "floor"
969
943
  unless constructions.floorConstruction.empty?
970
944
  construction = constructions.floorConstruction.get
971
- return true if construction == base
945
+ return true if construction == bse
972
946
  end
973
947
  else
974
948
  unless constructions.wallConstruction.empty?
975
949
  construction = constructions.wallConstruction.get
976
- return true if construction == base
950
+ return true if construction == bse
977
951
  end
978
952
  end
979
953
 
@@ -987,30 +961,25 @@ module OSut
987
961
  # @param s [OpenStudio::Model::Surface] a surface
988
962
  #
989
963
  # @return [OpenStudio::Model::DefaultConstructionSet] default set
990
- # @return [nil] if invalid input
991
- def defaultConstructionSet(model, s)
964
+ # @return [NilClass] if invalid input
965
+ def defaultConstructionSet(model = nil, s = nil)
992
966
  mth = "OSut::#{__callee__}"
993
967
  cl1 = OpenStudio::Model::Model
994
968
  cl2 = OpenStudio::Model::Surface
995
969
 
996
- return invalid("model", mth, 1) unless model
997
970
  return mismatch("model", model, cl1, mth) unless model.is_a?(cl1)
998
-
999
- return invalid("s", mth, 2) unless s.respond_to?(NS)
971
+ return invalid("s", mth, 2) unless s.respond_to?(NS)
1000
972
  id = s.nameString
1001
- return mismatch(id, s, cl2, mth) unless s.is_a?(cl2)
1002
-
1003
- unless s.isConstructionDefaulted
1004
- log(ERR, "'#{id}' construction not defaulted (#{mth})")
1005
- return nil
1006
- end
973
+ return mismatch(id, s, cl2, mth) unless s.is_a?(cl2)
1007
974
 
975
+ ok = s.isConstructionDefaulted
976
+ log(ERR, "'#{id}' construction not defaulted (#{mth})") unless ok
977
+ return nil unless ok
1008
978
  return empty("'#{id}' construction", mth, ERR) if s.construction.empty?
1009
979
  base = s.construction.get
1010
980
  return empty("'#{id}' space", mth, ERR) if s.space.empty?
1011
981
  space = s.space.get
1012
982
  type = s.surfaceType
1013
-
1014
983
  ground = false
1015
984
  exterior = false
1016
985
 
@@ -1060,7 +1029,7 @@ module OSut
1060
1029
  #
1061
1030
  # @return [Bool] true if all layers are valid
1062
1031
  # @return [Bool] false if invalid input
1063
- def standardOpaqueLayers?(lc)
1032
+ def standardOpaqueLayers?(lc = nil)
1064
1033
  mth = "OSut::#{__callee__}"
1065
1034
  cl = OpenStudio::Model::LayeredConstruction
1066
1035
 
@@ -1068,6 +1037,7 @@ module OSut
1068
1037
  return mismatch(lc.nameString, lc, cl, mth, DBG, false) unless lc.is_a?(cl)
1069
1038
 
1070
1039
  lc.layers.each { |m| return false if m.to_StandardOpaqueMaterial.empty? }
1040
+
1071
1041
  true
1072
1042
  end
1073
1043
 
@@ -1078,21 +1048,20 @@ module OSut
1078
1048
  #
1079
1049
  # @return [Double] total layered construction thickness
1080
1050
  # @return [Double] 0 if invalid input
1081
- def thickness(lc)
1051
+ def thickness(lc = nil)
1082
1052
  mth = "OSut::#{__callee__}"
1083
1053
  cl = OpenStudio::Model::LayeredConstruction
1084
1054
 
1085
- return invalid("lc", mth, 1, DBG, 0) unless lc.respond_to?(NS)
1055
+ return invalid("lc", mth, 1, DBG, 0.0) unless lc.respond_to?(NS)
1086
1056
  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
1057
+ return mismatch(id, lc, cl, mth, DBG, 0.0) unless lc.is_a?(cl)
1093
1058
 
1059
+ ok = standardOpaqueLayers?(lc)
1060
+ log(ERR, "'#{id}' holds non-StandardOpaqueMaterial(s) (#{mth})") unless ok
1061
+ return 0.0 unless ok
1094
1062
  thickness = 0.0
1095
1063
  lc.layers.each { |m| thickness += m.thickness }
1064
+
1096
1065
  thickness
1097
1066
  end
1098
1067
 
@@ -1122,11 +1091,12 @@ module OSut
1122
1091
  # The EnergyPlus Engineering calculations were designed for vertical windows
1123
1092
  # - not horizontal, slanted or domed surfaces - use with caution.
1124
1093
  mth = "OSut::#{__callee__}"
1125
- cl = Numeric
1094
+ cl = Numeric
1126
1095
 
1127
- return invalid("usi", mth, 1, DBG, 0.1216) unless usi
1128
- return mismatch("usi", usi, cl, mth, DBG, 0.1216) unless usi.is_a?(cl)
1129
- return invalid("usi", mth, 1, WRN, 0.1216) if usi > 8.0
1096
+ return mismatch("usi", usi, cl, mth, DBG, 0.1216) unless usi.is_a?(cl)
1097
+ return invalid("usi", mth, 1, WRN, 0.1216) if usi > 8.0
1098
+ return negative("usi", mth, WRN, 0.1216) if usi < 0
1099
+ return zero("usi", mth, WRN, 0.1216) if usi.abs < TOL
1130
1100
 
1131
1101
  rsi = 1 / (0.025342 * usi + 29.163853) # exterior film, next interior film
1132
1102
 
@@ -1142,64 +1112,49 @@ module OSut
1142
1112
  # @param t [Float] gas temperature (°C) (optional)
1143
1113
  #
1144
1114
  # @return [Float] calculated RSi at standard conditions (0 if error)
1145
- def rsi(lc, film, t = 0.0)
1115
+ def rsi(lc = nil, film = 0.0, t = 0.0)
1146
1116
  # This is adapted from BTAP's Material Module's "get_conductance" (P. Lopez)
1147
1117
  #
1148
1118
  # https://github.com/NREL/OpenStudio-Prototype-Buildings/blob/
1149
1119
  # c3d5021d8b7aef43e560544699fb5c559e6b721d/lib/btap/measures/
1150
1120
  # btap_equest_converter/envelope.rb#L122
1151
-
1152
1121
  mth = "OSut::#{__callee__}"
1153
1122
  cl1 = OpenStudio::Model::LayeredConstruction
1154
1123
  cl2 = Numeric
1155
1124
 
1156
- return invalid("lc", mth, 1, DBG, 0) unless lc.respond_to?(NS)
1125
+ return invalid("lc", mth, 1, DBG, 0.0) unless lc.respond_to?(NS)
1157
1126
  id = lc.nameString
1158
- return mismatch(id, lc, cl1, mth, DBG, 0) unless lc.is_a?(cl1)
1159
-
1160
- return invalid("film", mth, 2, DBG, 0) unless film
1161
- return invalid("temperature", mth, 3, DBG, 0) unless t
1162
-
1163
- return mismatch("film", film, cl2, mth, DBG, 0) unless film.is_a?(cl2)
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
1127
+ return mismatch(id, lc, cl1, mth, DBG, 0.0) unless lc.is_a?(cl1)
1128
+ return mismatch("film", film, cl2, mth, DBG, 0.0) unless film.is_a?(cl2)
1129
+ return mismatch("temp K", t, cl2, mth, DBG, 0.0) unless t.is_a?(cl2)
1130
+ t += 273.0 # °C to K
1131
+ return negative("temp K", mth, DBG, 0.0) if t < 0
1132
+ return negative("film", mth, DBG, 0.0) if film < 0
1169
1133
 
1170
1134
  rsi = film
1171
1135
 
1172
1136
  lc.layers.each do |m|
1173
1137
  # Fenestration materials first (ignoring shades, screens, etc.)
1174
- unless m.to_SimpleGlazing.empty?
1175
- return 1 / m.to_SimpleGlazing.get.uFactor # no need to loop
1176
- end
1177
- unless m.to_StandardGlazing.empty?
1178
- rsi += m.to_StandardGlazing.get.thermalResistance
1179
- end
1180
- unless m.to_RefractionExtinctionGlazing.empty?
1181
- rsi += m.to_RefractionExtinctionGlazing.get.thermalResistance
1182
- end
1183
- unless m.to_Gas.empty?
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
1138
+ empty = m.to_SimpleGlazing.empty?
1139
+ return 1 / m.to_SimpleGlazing.get.uFactor unless empty
1140
+ empty = m.to_StandardGlazing.empty?
1141
+ rsi += m.to_StandardGlazing.get.thermalResistance unless empty
1142
+ empty = m.to_RefractionExtinctionGlazing.empty?
1143
+ rsi += m.to_RefractionExtinctionGlazing.get.thermalResistance unless empty
1144
+ empty = m.to_Gas.empty?
1145
+ rsi += m.to_Gas.get.getThermalResistance(t) unless empty
1146
+ empty = m.to_GasMixture.empty?
1147
+ rsi += m.to_GasMixture.get.getThermalResistance(t) unless empty
1189
1148
 
1190
1149
  # Opaque materials next.
1191
- unless m.to_StandardOpaqueMaterial.empty?
1192
- rsi += m.to_StandardOpaqueMaterial.get.thermalResistance
1193
- end
1194
- unless m.to_MasslessOpaqueMaterial.empty?
1195
- rsi += m.to_MasslessOpaqueMaterial.get.thermalResistance
1196
- end
1197
- unless m.to_RoofVegetation.empty?
1198
- rsi += m.to_RoofVegetation.get.thermalResistance
1199
- end
1200
- unless m.to_AirGap.empty?
1201
- rsi += m.to_AirGap.get.thermalResistance
1202
- end
1150
+ empty = m.to_StandardOpaqueMaterial.empty?
1151
+ rsi += m.to_StandardOpaqueMaterial.get.thermalResistance unless empty
1152
+ empty = m.to_MasslessOpaqueMaterial.empty?
1153
+ rsi += m.to_MasslessOpaqueMaterial.get.thermalResistance unless empty
1154
+ empty = m.to_RoofVegetation.empty?
1155
+ rsi += m.to_RoofVegetation.get.thermalResistance unless empty
1156
+ empty = m.to_AirGap.empty?
1157
+ rsi += m.to_AirGap.get.thermalResistance unless empty
1203
1158
  end
1204
1159
 
1205
1160
  rsi
@@ -1215,18 +1170,17 @@ module OSut
1215
1170
  #
1216
1171
  # @return [Hash] index: (Integer), type: (:standard or :massless), r: (Float)
1217
1172
  # @return [Hash] index: nil, type: nil, r: 0 (if invalid input)
1218
- def insulatingLayer(lc)
1173
+ def insulatingLayer(lc = nil)
1219
1174
  mth = "OSut::#{__callee__}"
1220
1175
  cl = OpenStudio::Model::LayeredConstruction
1221
1176
  res = { index: nil, type: nil, r: 0.0 }
1222
1177
  i = 0 # iterator
1223
1178
 
1224
- return invalid("lc", mth, 1, DBG, res) unless lc.respond_to?(NS)
1179
+ return invalid("lc", mth, 1, DBG, res) unless lc.respond_to?(NS)
1225
1180
  id = lc.nameString
1226
1181
  return mismatch(id, lc, cl1, mth, DBG, res) unless lc.is_a?(cl)
1227
1182
 
1228
1183
  lc.layers.each do |m|
1229
-
1230
1184
  unless m.to_MasslessOpaqueMaterial.empty?
1231
1185
  m = m.to_MasslessOpaqueMaterial.get
1232
1186
 
@@ -1269,15 +1223,13 @@ module OSut
1269
1223
  #
1270
1224
  # @return [Hash] t: (OpenStudio::Transformation), r: Float
1271
1225
  # @return [Hash] t: nil, r: nil (if invalid input)
1272
- def transforms(model, group)
1226
+ def transforms(model = nil, group = nil)
1273
1227
  mth = "OSut::#{__callee__}"
1274
1228
  cl1 = OpenStudio::Model::Model
1275
1229
  cl2 = OpenStudio::Model::PlanarSurfaceGroup
1276
1230
  res = { t: nil, r: nil }
1277
1231
 
1278
- return invalid("model", mth, 1, DBG, res) unless model
1279
1232
  return mismatch("model", model, cl1, mth, DBG, res) unless model.is_a?(cl1)
1280
-
1281
1233
  return invalid("group", mth, 2, DBG, res) unless group.respond_to?(NS)
1282
1234
  id = group.nameString
1283
1235
  return mismatch(id, group, cl2, mth, DBG, res) unless group.is_a?(cl2)
@@ -1294,16 +1246,14 @@ module OSut
1294
1246
  # @param pts [Array] an OpenStudio Point3D array/vector
1295
1247
  #
1296
1248
  # @return [Array] flattened OpenStudio 3D points
1297
- def flatZ(pts)
1249
+ def flatZ(pts = nil)
1298
1250
  mth = "OSut::#{__callee__}"
1299
1251
  cl1 = OpenStudio::Point3dVector
1300
1252
  cl2 = OpenStudio::Point3d
1301
- v = OpenStudio::Point3dVector.new
1253
+ v = OpenStudio::Point3dVector.new
1302
1254
 
1303
- return invalid("points", mth, 1, DBG, v) unless pts
1304
1255
  valid = pts.is_a?(cl1) || pts.is_a?(Array)
1305
- return mismatch("points", pts, cl1, mth, DBG, v) unless valid
1306
-
1256
+ return mismatch("points", pts, cl1, mth, DBG, v) unless valid
1307
1257
  pts.each { |pt| mismatch("pt", pt, cl2, mth, ERR, v) unless pt.is_a?(cl2) }
1308
1258
  pts.each { |pt| v << OpenStudio::Point3d.new(pt.x, pt.y, 0) }
1309
1259
 
@@ -1320,53 +1270,49 @@ module OSut
1320
1270
  #
1321
1271
  # @return [Bool] true if 1st polygon fits entirely within the 2nd polygon
1322
1272
  # @return [Bool] false if invalid input
1323
- def fits?(p1, p2, id1 = "", id2 = "")
1273
+ def fits?(p1 = nil, p2 = nil, id1 = "", id2 = "")
1324
1274
  mth = "OSut::#{__callee__}"
1325
1275
  cl1 = OpenStudio::Point3dVector
1326
1276
  cl2 = OpenStudio::Point3d
1327
1277
  a = false
1278
+
1279
+ return invalid("id1", mth, 3, DBG, a) unless id1.respond_to?(:to_s)
1280
+ return invalid("id2", mth, 4, DBG, a) unless id2.respond_to?(:to_s)
1328
1281
  i1 = id1.to_s
1329
1282
  i2 = id2.to_s
1330
1283
  i1 = "poly1" if i1.empty?
1331
1284
  i2 = "poly2" if i2.empty?
1332
-
1333
- return invalid(i1, mth, 1, DBG, a) unless p1
1334
- valid = p1.is_a?(cl1) || p1.is_a?(Array)
1335
- return mismatch(i1, p1, cl1, mth, DBG, a) unless valid
1285
+ valid1 = p1.is_a?(cl1) || p1.is_a?(Array)
1286
+ valid2 = p2.is_a?(cl1) || p2.is_a?(Array)
1287
+ return mismatch(i1, p1, cl1, mth, DBG, a) unless valid1
1288
+ return mismatch(i2, p2, cl1, mth, DBG, a) unless valid2
1336
1289
  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
1290
  return empty(i2, mth, ERR, a) if p2.empty?
1342
-
1343
1291
  p1.each { |v| return mismatch(i1, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
1344
1292
  p2.each { |v| return mismatch(i2, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
1345
1293
 
1346
1294
  ft = OpenStudio::Transformation::alignFace(p1).inverse
1347
-
1348
1295
  ft_p1 = flatZ( (ft * p1).reverse )
1349
1296
  return false if ft_p1.empty?
1350
1297
  area1 = OpenStudio::getArea(ft_p1)
1351
- return empty(i1, mth, ERR, a) if area1.empty?
1298
+ return empty("#{i1} area", mth, ERR, a) if area1.empty?
1352
1299
  area1 = area1.get
1353
-
1354
1300
  ft_p2 = flatZ( (ft * p2).reverse )
1355
1301
  return false if ft_p2.empty?
1356
1302
  area2 = OpenStudio::getArea(ft_p2)
1357
- return empty(i2, mth, ERR, a) if area2.empty?
1303
+ return empty("#{i2} area", mth, ERR, a) if area2.empty?
1358
1304
  area2 = area2.get
1359
-
1360
1305
  union = OpenStudio::join(ft_p1, ft_p2, TOL2)
1361
1306
  return false if union.empty?
1362
1307
  union = union.get
1363
1308
  area = OpenStudio::getArea(union)
1364
- return empty("union", mth, ERR, a) if area.empty?
1309
+ return empty("#{i1}:#{i2} union area", mth, ERR, a) if area.empty?
1365
1310
  area = area.get
1366
1311
 
1367
1312
  return false if area < TOL
1368
1313
  return true if (area - area2).abs < TOL
1369
1314
  return false if (area - area2).abs > TOL
1315
+
1370
1316
  true
1371
1317
  end
1372
1318
 
@@ -1380,51 +1326,55 @@ module OSut
1380
1326
  #
1381
1327
  # @return Returns true if polygons overlaps (or either fits into the other)
1382
1328
  # @return [Bool] false if invalid input
1383
- def overlaps?(p1, p2, id1 = "", id2 = "")
1329
+ def overlaps?(p1 = nil, p2 = nil, id1 = "", id2 = "")
1384
1330
  mth = "OSut::#{__callee__}"
1385
1331
  cl1 = OpenStudio::Point3dVector
1386
1332
  cl2 = OpenStudio::Point3d
1387
1333
  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
1334
 
1393
- return invalid(i1, mth, 1, DBG, a) unless p1
1394
- valid = p1.is_a?(cl1) || p1.is_a?(Array)
1395
- return mismatch(i1, p1, cl1, mth, DBG, a) unless valid
1335
+ return invalid("id1", mth, 3, DBG, a) unless id1.respond_to?(:to_s)
1336
+ return invalid("id2", mth, 4, DBG, a) unless id2.respond_to?(:to_s)
1337
+ i1 = id1.to_s
1338
+ i2 = id2.to_s
1339
+ i1 = "poly1" if i1.empty?
1340
+ i2 = "poly2" if i2.empty?
1341
+ valid1 = p1.is_a?(cl1) || p1.is_a?(Array)
1342
+ valid2 = p2.is_a?(cl1) || p2.is_a?(Array)
1343
+ return mismatch(i1, p1, cl1, mth, DBG, a) unless valid1
1344
+ return mismatch(i2, p2, cl1, mth, DBG, a) unless valid2
1396
1345
  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
1346
  return empty(i2, mth, ERR, a) if p2.empty?
1402
-
1403
1347
  p1.each { |v| return mismatch(i1, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
1404
1348
  p2.each { |v| return mismatch(i2, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
1405
1349
 
1406
1350
  ft = OpenStudio::Transformation::alignFace(p1).inverse
1407
-
1408
1351
  ft_p1 = flatZ( (ft * p1).reverse )
1409
1352
  return false if ft_p1.empty?
1410
1353
  area1 = OpenStudio::getArea(ft_p1)
1411
- return empty(i1, mth, ERR, a) if area1.empty?
1354
+ return empty("#{i1} area", mth, ERR, a) if area1.empty?
1412
1355
  area1 = area1.get
1413
-
1414
1356
  ft_p2 = flatZ( (ft * p2).reverse )
1415
1357
  return false if ft_p2.empty?
1416
1358
  area2 = OpenStudio::getArea(ft_p2)
1417
- return empty(i2, mth, ERR, a) if area2.empty?
1359
+ return empty("#{i2} area", mth, ERR, a) if area2.empty?
1418
1360
  area2 = area2.get
1419
-
1420
1361
  union = OpenStudio::join(ft_p1, ft_p2, TOL2)
1421
1362
  return false if union.empty?
1422
1363
  union = union.get
1423
1364
  area = OpenStudio::getArea(union)
1424
- return empty("union", mth, ERR, a) if area.empty?
1365
+ return empty("#{i1}:#{i2} union area", mth, ERR, a) if area.empty?
1425
1366
  area = area.get
1426
1367
 
1427
1368
  return false if area < TOL
1369
+
1428
1370
  true
1429
1371
  end
1372
+
1373
+ ##
1374
+ # Callback when other modules extend OSlg
1375
+ #
1376
+ # @param base [Object] instance or class object
1377
+ def self.extended(base)
1378
+ base.send(:include, self)
1379
+ end
1430
1380
  end
data/lib/osut/version.rb CHANGED
@@ -29,5 +29,5 @@
29
29
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
30
 
31
31
  module OSut
32
- VERSION = "0.2.2".freeze
32
+ VERSION = "0.2.3".freeze
33
33
  end
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.2
4
+ version: 0.2.3
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-07-29 00:00:00.000000000 Z
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.2
93
+ source_code_uri: https://github.com/rd2/osut/tree/v0.2.3
94
94
  bug_tracker_uri: https://github.com/rd2/osut/issues
95
95
  post_install_message:
96
96
  rdoc_options: []