tbd 3.1.1 → 3.2.0
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/.github/workflows/pull_request.yml +16 -0
- data/LICENSE.md +1 -1
- data/lib/measures/tbd/LICENSE.md +1 -1
- data/lib/measures/tbd/README.md +8 -0
- data/lib/measures/tbd/measure.rb +44 -2
- data/lib/measures/tbd/measure.xml +33 -24
- data/lib/measures/tbd/resources/geo.rb +56 -16
- data/lib/measures/tbd/resources/oslog.rb +17 -7
- data/lib/measures/tbd/resources/psi.rb +113 -7
- data/lib/measures/tbd/resources/tbd.rb +1 -1
- data/lib/measures/tbd/resources/ua.rb +36 -69
- data/lib/measures/tbd/resources/utils.rb +86 -28
- data/lib/measures/tbd/tests/tbd_tests.rb +117 -87
- data/lib/tbd/geo.rb +56 -16
- data/lib/tbd/psi.rb +113 -7
- data/lib/tbd/ua.rb +36 -69
- data/lib/tbd/version.rb +2 -2
- data/lib/tbd.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: 92789b60b438d1518f82d2596a12314ea5c6903de2bd902f1cbbea1a2379fd1d
|
4
|
+
data.tar.gz: e0e17c13b6db89a38fe39a9f8a6f4e2249e09976c08049250da3d6546689064f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a054444e9871a6a6844c4535913b50700b94588f338434e47b8dd41ec6d73c78df8f2efd773a4bc1f86d25cd37216b7ebe48ba94e18a6f4e8547b2be987c5ecb
|
7
|
+
data.tar.gz: 360c811de3c35599d73741985d80df474379a29fbad16714a0afa553b4719d50b41415f18006462176f9adc26377980507e535c616a64b77f0398b24d3fa435c
|
@@ -70,3 +70,19 @@ jobs:
|
|
70
70
|
docker exec -t test bundle update
|
71
71
|
docker exec -t test bundle exec rake
|
72
72
|
docker kill test
|
73
|
+
test_351x:
|
74
|
+
runs-on: ubuntu-22.04
|
75
|
+
steps:
|
76
|
+
- name: Check out repository
|
77
|
+
uses: actions/checkout@v2
|
78
|
+
- name: Run Tests
|
79
|
+
run: |
|
80
|
+
echo $(pwd)
|
81
|
+
echo $(ls)
|
82
|
+
docker pull nrel/openstudio:3.5.1
|
83
|
+
docker run --name test --rm -d -t -v $(pwd):/work -w /work nrel/openstudio:3.5.1
|
84
|
+
docker exec -t test pwd
|
85
|
+
docker exec -t test ls
|
86
|
+
docker exec -t test bundle update
|
87
|
+
docker exec -t test bundle exec rake
|
88
|
+
docker kill test
|
data/LICENSE.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
MIT License
|
2
2
|
|
3
|
-
Copyright (c) 2020-
|
3
|
+
Copyright (c) 2020-2023 Denis Bourgeois & Dan Macumber
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/lib/measures/tbd/LICENSE.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
MIT License
|
2
2
|
|
3
|
-
Copyright (c) 2020-
|
3
|
+
Copyright (c) 2020-2023 Denis Bourgeois & Dan Macumber
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/lib/measures/tbd/README.md
CHANGED
@@ -27,6 +27,14 @@ For EnergyPlus simulations, leave CHECKED. For iterative exploration with Apply
|
|
27
27
|
**Required:** false,
|
28
28
|
**Model Dependent:** false
|
29
29
|
|
30
|
+
### Proximity tolerance (m)
|
31
|
+
Proximity tolerance (e.g. 0.100 m) between subsurface edges, e.g. between near-adjacent window jambs.
|
32
|
+
**Name:** sub_tol,
|
33
|
+
**Type:** Double,
|
34
|
+
**Units:** ,
|
35
|
+
**Required:** false,
|
36
|
+
**Model Dependent:** false
|
37
|
+
|
30
38
|
### Load 'tbd.json'
|
31
39
|
Loads existing 'tbd.json' file (under '/files'), may override 'default thermal bridge' set.
|
32
40
|
**Name:** load_tbd_json,
|
data/lib/measures/tbd/measure.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# MIT License
|
2
2
|
#
|
3
|
-
# Copyright (c) 2020-
|
3
|
+
# Copyright (c) 2020-2023 Denis Bourgeois & Dan Macumber
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -48,6 +48,15 @@ class TBDMeasure < OpenStudio::Measure::ModelMeasure
|
|
48
48
|
alter.setDefaultValue(true)
|
49
49
|
args << alter
|
50
50
|
|
51
|
+
arg = "sub_tol"
|
52
|
+
dsc = "Proximity tolerance (e.g. 0.100 m) between subsurface edges, e.g. " \
|
53
|
+
"between near-adjacent window jambs."
|
54
|
+
sub_tol = OpenStudio::Measure::OSArgument.makeDoubleArgument(arg, false)
|
55
|
+
sub_tol.setDisplayName("Proximity tolerance (m)")
|
56
|
+
sub_tol.setDescription(dsc)
|
57
|
+
sub_tol.setDefaultValue(TBD::TOL)
|
58
|
+
args << sub_tol
|
59
|
+
|
51
60
|
arg = "load_tbd_json"
|
52
61
|
dsc = "Loads existing 'tbd.json' file (under '/files'), may override " \
|
53
62
|
"'default thermal bridge' set."
|
@@ -225,6 +234,7 @@ class TBDMeasure < OpenStudio::Measure::ModelMeasure
|
|
225
234
|
|
226
235
|
argh = {}
|
227
236
|
argh[:alter ] = runner.getBoolArgumentValue("alter_model", args)
|
237
|
+
argh[:sub_tol ] = runner.getDoubleArgumentValue("sub_tol", args)
|
228
238
|
argh[:load_tbd ] = runner.getBoolArgumentValue("load_tbd_json", args)
|
229
239
|
argh[:option ] = runner.getStringArgumentValue("option", args)
|
230
240
|
argh[:write_tbd ] = runner.getBoolArgumentValue("write_tbd_json", args)
|
@@ -286,6 +296,38 @@ class TBDMeasure < OpenStudio::Measure::ModelMeasure
|
|
286
296
|
end
|
287
297
|
end
|
288
298
|
|
299
|
+
# Pre-validate ground-facing constructions for KIVA.
|
300
|
+
if argh[:kiva_force] || argh[:gen_kiva]
|
301
|
+
kva = true
|
302
|
+
|
303
|
+
mdl.getSurfaces.each do |s|
|
304
|
+
id = s.nameString
|
305
|
+
construction = s.construction
|
306
|
+
next unless s.isGroundSurface
|
307
|
+
|
308
|
+
if construction.empty?
|
309
|
+
runner.registerError("Invalid construction for KIVA (#{id})")
|
310
|
+
kva = false if kva
|
311
|
+
else
|
312
|
+
construction = construction.get.to_LayeredConstruction
|
313
|
+
|
314
|
+
if construction.empty?
|
315
|
+
runner.registerError("KIVA requires layered constructions (#{id})")
|
316
|
+
kva = false if kva
|
317
|
+
else
|
318
|
+
construction = construction.get
|
319
|
+
|
320
|
+
unless TBD.standardOpaqueLayers?(construction)
|
321
|
+
runner.registerError("KIVA requires standard materials (#{id})")
|
322
|
+
kva = false if kva
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
return false unless kva
|
329
|
+
end
|
330
|
+
|
289
331
|
# Process all ground-facing surfaces as foundation-facing.
|
290
332
|
if argh[:kiva_force]
|
291
333
|
argh[:gen_kiva] = true
|
@@ -313,7 +355,7 @@ class TBDMeasure < OpenStudio::Measure::ModelMeasure
|
|
313
355
|
|
314
356
|
argh[:version ] = model.getVersion.versionIdentifier
|
315
357
|
tbd = TBD.process(model, argh)
|
316
|
-
argh[:io ] = tbd[:io]
|
358
|
+
argh[:io ] = tbd[:io ]
|
317
359
|
argh[:surfaces] = tbd[:surfaces]
|
318
360
|
setpoints = TBD.heatingTemperatureSetpoints?(model)
|
319
361
|
setpoints = TBD.coolingTemperatureSetpoints?(model) || setpoints
|
@@ -3,8 +3,8 @@
|
|
3
3
|
<schema_version>3.0</schema_version>
|
4
4
|
<name>tbd_measure</name>
|
5
5
|
<uid>8890787b-8c25-4dc8-8641-b6be1b6c2357</uid>
|
6
|
-
<version_id>
|
7
|
-
<version_modified>
|
6
|
+
<version_id>216d4e2e-fab7-49c6-95e9-7262edbf3277</version_id>
|
7
|
+
<version_modified>20230111T223650Z</version_modified>
|
8
8
|
<xml_checksum>99772807</xml_checksum>
|
9
9
|
<class_name>TBDMeasure</class_name>
|
10
10
|
<display_name>Thermal Bridging and Derating - TBD</display_name>
|
@@ -30,6 +30,15 @@
|
|
30
30
|
</choice>
|
31
31
|
</choices>
|
32
32
|
</argument>
|
33
|
+
<argument>
|
34
|
+
<name>sub_tol</name>
|
35
|
+
<display_name>Proximity tolerance (m)</display_name>
|
36
|
+
<description>Proximity tolerance (e.g. 0.100 m) between subsurface edges, e.g. between near-adjacent window jambs.</description>
|
37
|
+
<type>Double</type>
|
38
|
+
<required>false</required>
|
39
|
+
<model_dependent>false</model_dependent>
|
40
|
+
<default_value>0.01</default_value>
|
41
|
+
</argument>
|
33
42
|
<argument>
|
34
43
|
<name>load_tbd_json</name>
|
35
44
|
<display_name>Load 'tbd.json'</display_name>
|
@@ -373,12 +382,6 @@
|
|
373
382
|
<usage_type>doc</usage_type>
|
374
383
|
<checksum>32D70693</checksum>
|
375
384
|
</file>
|
376
|
-
<file>
|
377
|
-
<filename>LICENSE.md</filename>
|
378
|
-
<filetype>md</filetype>
|
379
|
-
<usage_type>license</usage_type>
|
380
|
-
<checksum>CB393A2B</checksum>
|
381
|
-
</file>
|
382
385
|
<file>
|
383
386
|
<filename>geometry.rb</filename>
|
384
387
|
<filetype>rb</filetype>
|
@@ -397,23 +400,29 @@
|
|
397
400
|
<usage_type>resource</usage_type>
|
398
401
|
<checksum>05CC939E</checksum>
|
399
402
|
</file>
|
403
|
+
<file>
|
404
|
+
<filename>LICENSE.md</filename>
|
405
|
+
<filetype>md</filetype>
|
406
|
+
<usage_type>license</usage_type>
|
407
|
+
<checksum>A91E64A0</checksum>
|
408
|
+
</file>
|
400
409
|
<file>
|
401
410
|
<filename>oslog.rb</filename>
|
402
411
|
<filetype>rb</filetype>
|
403
412
|
<usage_type>resource</usage_type>
|
404
|
-
<checksum>
|
413
|
+
<checksum>E97617E3</checksum>
|
405
414
|
</file>
|
406
415
|
<file>
|
407
416
|
<filename>tbd.rb</filename>
|
408
417
|
<filetype>rb</filetype>
|
409
418
|
<usage_type>resource</usage_type>
|
410
|
-
<checksum>
|
419
|
+
<checksum>A4E8433C</checksum>
|
411
420
|
</file>
|
412
421
|
<file>
|
413
422
|
<filename>utils.rb</filename>
|
414
423
|
<filetype>rb</filetype>
|
415
424
|
<usage_type>resource</usage_type>
|
416
|
-
<checksum>
|
425
|
+
<checksum>283C976C</checksum>
|
417
426
|
</file>
|
418
427
|
<file>
|
419
428
|
<version>
|
@@ -424,37 +433,37 @@
|
|
424
433
|
<filename>measure.rb</filename>
|
425
434
|
<filetype>rb</filetype>
|
426
435
|
<usage_type>script</usage_type>
|
427
|
-
<checksum>
|
436
|
+
<checksum>44B11139</checksum>
|
428
437
|
</file>
|
429
438
|
<file>
|
430
439
|
<filename>tbd_tests.rb</filename>
|
431
440
|
<filetype>rb</filetype>
|
432
441
|
<usage_type>test</usage_type>
|
433
|
-
<checksum>
|
442
|
+
<checksum>58ED6635</checksum>
|
434
443
|
</file>
|
435
444
|
<file>
|
436
|
-
<filename>
|
437
|
-
<filetype>
|
438
|
-
<usage_type>
|
439
|
-
<checksum>
|
445
|
+
<filename>ua.rb</filename>
|
446
|
+
<filetype>rb</filetype>
|
447
|
+
<usage_type>resource</usage_type>
|
448
|
+
<checksum>9EBACA60</checksum>
|
440
449
|
</file>
|
441
450
|
<file>
|
442
451
|
<filename>geo.rb</filename>
|
443
452
|
<filetype>rb</filetype>
|
444
453
|
<usage_type>resource</usage_type>
|
445
|
-
<checksum>
|
454
|
+
<checksum>F447D8CE</checksum>
|
446
455
|
</file>
|
447
456
|
<file>
|
448
|
-
<filename>
|
449
|
-
<filetype>
|
450
|
-
<usage_type>
|
451
|
-
<checksum>
|
457
|
+
<filename>README.md</filename>
|
458
|
+
<filetype>md</filetype>
|
459
|
+
<usage_type>readme</usage_type>
|
460
|
+
<checksum>B836C43A</checksum>
|
452
461
|
</file>
|
453
462
|
<file>
|
454
|
-
<filename>
|
463
|
+
<filename>psi.rb</filename>
|
455
464
|
<filetype>rb</filetype>
|
456
465
|
<usage_type>resource</usage_type>
|
457
|
-
<checksum>
|
466
|
+
<checksum>E6ED8157</checksum>
|
458
467
|
</file>
|
459
468
|
</files>
|
460
469
|
</measure>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# MIT License
|
2
2
|
#
|
3
|
-
# Copyright (c) 2020-
|
3
|
+
# Copyright (c) 2020-2023 Denis Bourgeois & Dan Macumber
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -22,24 +22,27 @@
|
|
22
22
|
|
23
23
|
module TBD
|
24
24
|
##
|
25
|
-
# Check for matching Topolys vertex pairs between edges
|
25
|
+
# Check for matching Topolys vertex pairs between edges.
|
26
26
|
#
|
27
27
|
# @param e1 [Hash] first edge
|
28
28
|
# @param e2 [Hash] second edge
|
29
|
+
# @param tol [Float] user-set tolerance (> TOL) in m
|
29
30
|
#
|
30
31
|
# @return [Bool] true if edges share vertex pairs
|
31
32
|
# @return [Bool] false if invalid input
|
32
|
-
def matches?(e1 = {}, e2 = {})
|
33
|
+
def matches?(e1 = {}, e2 = {}, tol = TOL)
|
33
34
|
mth = "TBD::#{__callee__}"
|
34
35
|
cl = Topolys::Point3D
|
35
36
|
a = false
|
36
37
|
|
37
38
|
return mismatch("e1", e1, Hash, mth, DBG, a) unless e1.is_a?(Hash)
|
38
39
|
return mismatch("e2", e2, Hash, mth, DBG, a) unless e2.is_a?(Hash)
|
40
|
+
|
39
41
|
return hashkey("e1", e1, :v0, mth, DBG, a) unless e1.key?(:v0)
|
40
42
|
return hashkey("e1", e1, :v1, mth, DBG, a) unless e1.key?(:v1)
|
41
43
|
return hashkey("e2", e2, :v0, mth, DBG, a) unless e2.key?(:v0)
|
42
44
|
return hashkey("e2", e2, :v1, mth, DBG, a) unless e2.key?(:v1)
|
45
|
+
|
43
46
|
return mismatch("e1 :v0", e1[:v0], cl, mth, DBG, a) unless e1[:v0].is_a?(cl)
|
44
47
|
return mismatch("e1 :v1", e1[:v1], cl, mth, DBG, a) unless e1[:v1].is_a?(cl)
|
45
48
|
return mismatch("e2 :v0", e2[:v0], cl, mth, DBG, a) unless e2[:v0].is_a?(cl)
|
@@ -51,26 +54,29 @@ module TBD
|
|
51
54
|
return zero("e1", mth, DBG, a) if e1_vector.magnitude < TOL
|
52
55
|
return zero("e2", mth, DBG, a) if e2_vector.magnitude < TOL
|
53
56
|
|
57
|
+
return mismatch("e1", e1, Hash, mth, DBG, a) unless tol.is_a?(Numeric)
|
58
|
+
return zero("tol", mth, DBG, a) if tol < TOL
|
59
|
+
|
54
60
|
return true if
|
55
61
|
(
|
56
62
|
(
|
57
|
-
( (e1[:v0].x - e2[:v0].x).abs <
|
58
|
-
(e1[:v0].y - e2[:v0].y).abs <
|
59
|
-
(e1[:v0].z - e2[:v0].z).abs <
|
63
|
+
( (e1[:v0].x - e2[:v0].x).abs < tol &&
|
64
|
+
(e1[:v0].y - e2[:v0].y).abs < tol &&
|
65
|
+
(e1[:v0].z - e2[:v0].z).abs < tol
|
60
66
|
) ||
|
61
|
-
( (e1[:v0].x - e2[:v1].x).abs <
|
62
|
-
(e1[:v0].y - e2[:v1].y).abs <
|
63
|
-
(e1[:v0].z - e2[:v1].z).abs <
|
67
|
+
( (e1[:v0].x - e2[:v1].x).abs < tol &&
|
68
|
+
(e1[:v0].y - e2[:v1].y).abs < tol &&
|
69
|
+
(e1[:v0].z - e2[:v1].z).abs < tol
|
64
70
|
)
|
65
71
|
) &&
|
66
72
|
(
|
67
|
-
( (e1[:v1].x - e2[:v0].x).abs <
|
68
|
-
(e1[:v1].y - e2[:v0].y).abs <
|
69
|
-
(e1[:v1].z - e2[:v0].z).abs <
|
73
|
+
( (e1[:v1].x - e2[:v0].x).abs < tol &&
|
74
|
+
(e1[:v1].y - e2[:v0].y).abs < tol &&
|
75
|
+
(e1[:v1].z - e2[:v0].z).abs < tol
|
70
76
|
) ||
|
71
|
-
( (e1[:v1].x - e2[:v1].x).abs <
|
72
|
-
(e1[:v1].y - e2[:v1].y).abs <
|
73
|
-
(e1[:v1].z - e2[:v1].z).abs <
|
77
|
+
( (e1[:v1].x - e2[:v1].x).abs < tol &&
|
78
|
+
(e1[:v1].y - e2[:v1].y).abs < tol &&
|
79
|
+
(e1[:v1].z - e2[:v1].z).abs < tol
|
74
80
|
)
|
75
81
|
)
|
76
82
|
)
|
@@ -354,6 +360,7 @@ module TBD
|
|
354
360
|
next unless valid
|
355
361
|
vec = s.vertices
|
356
362
|
area = s.grossArea
|
363
|
+
mult = s.multiplier
|
357
364
|
typ = s.subSurfaceType.downcase
|
358
365
|
type = :skylight
|
359
366
|
type = :window if typ.include?("window" )
|
@@ -442,6 +449,7 @@ module TBD
|
|
442
449
|
n: n,
|
443
450
|
gross: s.grossArea,
|
444
451
|
area: area,
|
452
|
+
mult: mult,
|
445
453
|
type: type,
|
446
454
|
u: u,
|
447
455
|
unhinged: unhinged }
|
@@ -478,7 +486,9 @@ module TBD
|
|
478
486
|
end
|
479
487
|
|
480
488
|
subarea = 0
|
481
|
-
|
489
|
+
|
490
|
+
subs.values.each { |sub| subarea += sub[:area] * sub[:mult] }
|
491
|
+
|
482
492
|
surf[:net] = surf[:gross] - subarea
|
483
493
|
|
484
494
|
# Tranform final Point 3D sets, and store.
|
@@ -604,6 +614,36 @@ module TBD
|
|
604
614
|
return mismatch("floors", floors, cl2, mth, DBG, a) unless floors.is_a?(cl2)
|
605
615
|
return mismatch("edges", edges, cl2, mth, DBG, a) unless edges.is_a?(cl2)
|
606
616
|
|
617
|
+
kva = true
|
618
|
+
|
619
|
+
# Pre-validate foundation-facing constructions.
|
620
|
+
model.getSurfaces.each do |s|
|
621
|
+
id = s.nameString
|
622
|
+
construction = s.construction
|
623
|
+
next unless s.outsideBoundaryCondition.downcase == "foundation"
|
624
|
+
|
625
|
+
if construction.empty?
|
626
|
+
log(ERR, "Invalid construction for KIVA (see #{id})")
|
627
|
+
kva = false if kva
|
628
|
+
else
|
629
|
+
construction = construction.get.to_LayeredConstruction
|
630
|
+
|
631
|
+
if construction.empty?
|
632
|
+
log(ERR, "KIVA requires layered constructions (see #{id})")
|
633
|
+
kva = false if kva
|
634
|
+
else
|
635
|
+
construction = construction.get
|
636
|
+
|
637
|
+
unless standardOpaqueLayers?(construction)
|
638
|
+
log(ERR, "KIVA requires standard materials (see #{id})")
|
639
|
+
kva = false if kva
|
640
|
+
end
|
641
|
+
end
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
return a unless kva
|
646
|
+
|
607
647
|
# Strictly relying on Kiva's total exposed perimeter approach.
|
608
648
|
arg = "TotalExposedPerimeter"
|
609
649
|
kiva = true
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# BSD 3-Clause License
|
2
2
|
#
|
3
|
-
# Copyright (c) 2022, Denis Bourgeois
|
3
|
+
# Copyright (c) 2022-2023, Denis Bourgeois
|
4
4
|
# All rights reserved.
|
5
5
|
#
|
6
6
|
# Redistribution and use in source and binary forms, with or without
|
@@ -127,6 +127,7 @@ module OSlg
|
|
127
127
|
# @return [String] "DEBUG", "INFO", "WARN", "ERROR" or "FATAL"
|
128
128
|
def tag(level)
|
129
129
|
return @@tag[level] if level >= DEBUG && level <= FATAL
|
130
|
+
|
130
131
|
""
|
131
132
|
end
|
132
133
|
|
@@ -138,6 +139,7 @@ module OSlg
|
|
138
139
|
# @return [String] preset OSlg message
|
139
140
|
def msg(status)
|
140
141
|
return @@msg[status] if status >= DEBUG && status <= FATAL
|
142
|
+
|
141
143
|
""
|
142
144
|
end
|
143
145
|
|
@@ -163,6 +165,7 @@ module OSlg
|
|
163
165
|
@@logs << {level: level, message: message}
|
164
166
|
@@status = level if level > @@status
|
165
167
|
end
|
168
|
+
|
166
169
|
@@status
|
167
170
|
end
|
168
171
|
|
@@ -194,10 +197,11 @@ module OSlg
|
|
194
197
|
mth = mth[0...60] + " ..." if mth.length > 60
|
195
198
|
return res if mth.empty?
|
196
199
|
|
197
|
-
msg
|
200
|
+
msg = "Invalid '#{id}' "
|
198
201
|
msg += "arg ##{ord} " if ord > 0
|
199
202
|
msg += "(#{mth})"
|
200
203
|
log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL
|
204
|
+
|
201
205
|
res
|
202
206
|
end
|
203
207
|
|
@@ -232,6 +236,7 @@ module OSlg
|
|
232
236
|
|
233
237
|
msg = "'#{id}' #{obj.class}? expecting #{cl} (#{mth})"
|
234
238
|
log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL
|
239
|
+
|
235
240
|
res
|
236
241
|
end
|
237
242
|
|
@@ -264,8 +269,9 @@ module OSlg
|
|
264
269
|
mth = mth[0...60] + " ..." if mth.length > 60
|
265
270
|
return res if mth.empty?
|
266
271
|
|
267
|
-
msg
|
272
|
+
msg = "Missing '#{key}' key in '#{id}' Hash (#{mth})"
|
268
273
|
log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL
|
274
|
+
|
269
275
|
res
|
270
276
|
end
|
271
277
|
|
@@ -294,8 +300,9 @@ module OSlg
|
|
294
300
|
mth = mth[0...60] + " ..." if mth.length > 60
|
295
301
|
return res if mth.empty?
|
296
302
|
|
297
|
-
msg
|
303
|
+
msg = "Empty '#{id}' (#{mth})"
|
298
304
|
log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL
|
305
|
+
|
299
306
|
res
|
300
307
|
end
|
301
308
|
|
@@ -325,8 +332,9 @@ module OSlg
|
|
325
332
|
mth = mth[0...60] + " ..." if mth.length > 60
|
326
333
|
return res if mth.empty?
|
327
334
|
|
328
|
-
msg
|
335
|
+
msg = "Zero '#{id}' (#{mth})"
|
329
336
|
log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL
|
337
|
+
|
330
338
|
res
|
331
339
|
end
|
332
340
|
|
@@ -355,9 +363,10 @@ module OSlg
|
|
355
363
|
|
356
364
|
mth = mth[0...60] + " ..." if mth.length > 60
|
357
365
|
return res if mth.empty?
|
358
|
-
|
359
|
-
msg
|
366
|
+
|
367
|
+
msg = "Negative '#{id}' (#{mth})"
|
360
368
|
log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL
|
369
|
+
|
361
370
|
res
|
362
371
|
end
|
363
372
|
|
@@ -368,6 +377,7 @@ module OSlg
|
|
368
377
|
def clean!
|
369
378
|
@@status = 0
|
370
379
|
@@logs = []
|
380
|
+
|
371
381
|
@@level
|
372
382
|
end
|
373
383
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# MIT License
|
2
2
|
#
|
3
|
-
# Copyright (c) 2020-
|
3
|
+
# Copyright (c) 2020-2023 Denis Bourgeois & Dan Macumber
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -913,6 +913,7 @@ module TBD
|
|
913
913
|
return mismatch("argh", argh, Hash, mth, DBG, tbd) unless argh.is_a?(Hash)
|
914
914
|
|
915
915
|
argh = {} if argh.empty?
|
916
|
+
argh[:sub_tol ] = TBD::TOL unless argh.key?(:sub_tol )
|
916
917
|
argh[:option ] = "" unless argh.key?(:option )
|
917
918
|
argh[:io_path ] = nil unless argh.key?(:io_path )
|
918
919
|
argh[:schema_path ] = nil unless argh.key?(:schema_path )
|
@@ -1174,9 +1175,6 @@ module TBD
|
|
1174
1175
|
farthest_V = origin_point_V if farther
|
1175
1176
|
end
|
1176
1177
|
|
1177
|
-
puts "ADDITION!!" if id == "ADDITION"
|
1178
|
-
puts "#{reference_V} vs #{farthest_V}" if id == "ADDITION"
|
1179
|
-
|
1180
1178
|
angle = reference_V.angle(farthest_V)
|
1181
1179
|
invalid("#{id} polar angle", mth, 0, ERROR, 0) if angle.nil?
|
1182
1180
|
angle = 0 if angle.nil?
|
@@ -1771,13 +1769,120 @@ module TBD
|
|
1771
1769
|
end
|
1772
1770
|
end
|
1773
1771
|
|
1772
|
+
# Fetch edge multipliers for subsurfaces, if applicable.
|
1773
|
+
edges.values.each do |edge|
|
1774
|
+
next if edge.key?(:mult) # skip if already assigned
|
1775
|
+
next unless edge.key?(:surfaces)
|
1776
|
+
next unless edge.key?(:psi)
|
1777
|
+
ok = false
|
1778
|
+
|
1779
|
+
edge[:psi].keys.each do |k|
|
1780
|
+
break if ok
|
1781
|
+
|
1782
|
+
jamb = k.to_s.include?("jamb")
|
1783
|
+
sill = k.to_s.include?("sill")
|
1784
|
+
head = k.to_s.include?("head")
|
1785
|
+
ok = jamb || sill || head
|
1786
|
+
end
|
1787
|
+
|
1788
|
+
next unless ok # if OK, edge links subsurface(s) ... yet which one(s)?
|
1789
|
+
|
1790
|
+
edge[:surfaces].each do |id, surface|
|
1791
|
+
next unless tbd[:surfaces].key?(id) # look up parent (opaque) surface
|
1792
|
+
|
1793
|
+
[:windows, :doors, :skylights].each do |subtypes|
|
1794
|
+
next unless tbd[:surfaces][id].key?(subtypes)
|
1795
|
+
|
1796
|
+
tbd[:surfaces][id][subtypes].each do |nom, sub|
|
1797
|
+
next unless edge[:surfaces].key?(nom)
|
1798
|
+
next unless sub[:mult] > 1
|
1799
|
+
|
1800
|
+
# An edge may be tagged with (potentially conflicting) multipliers.
|
1801
|
+
# This is only possible if the edge links 2 subsurfaces, e.g. a
|
1802
|
+
# shared jamb between window & door. By default, TBD tags common
|
1803
|
+
# subsurface edges as (mild) "transitions" (i.e. PSI 0 W/K.m), so
|
1804
|
+
# there would be no point in assigning an edge multiplier. Users
|
1805
|
+
# can however reset an edge type via a TBD JSON input file (e.g.
|
1806
|
+
# "joint" instead of "transition"). It would be a very odd choice,
|
1807
|
+
# but TBD doesn't prohibit it. If linked subsurfaces have different
|
1808
|
+
# multipliers (e.g. 2 vs 3), TBD tracks the highest value.
|
1809
|
+
edge[:mult] = sub[:mult] unless edge.key?(:mult)
|
1810
|
+
edge[:mult] = sub[:mult] if sub[:mult] > edge[:mult]
|
1811
|
+
end
|
1812
|
+
end
|
1813
|
+
end
|
1814
|
+
end
|
1815
|
+
|
1816
|
+
# Unless a user has set the thermal bridge type of an individual edge via
|
1817
|
+
# JSON input, reset any subsurface's head, sill or jamb edges as (mild)
|
1818
|
+
# transitions when in close proximity to another subsurface edge. Both
|
1819
|
+
# edges' origin and terminal vertices must be in close proximity. Edges
|
1820
|
+
# of unhinged subsurfaces are ignored.
|
1821
|
+
edges.each do |id, edge|
|
1822
|
+
nb = 0 # linked subsurfaces (i.e. "holes")
|
1823
|
+
match = false
|
1824
|
+
next if edge.key?(:io_type) # skip if set in JSON
|
1825
|
+
next unless edge.key?(:v0)
|
1826
|
+
next unless edge.key?(:v1)
|
1827
|
+
next unless edge.key?(:psi)
|
1828
|
+
next unless edge.key?(:surfaces)
|
1829
|
+
|
1830
|
+
edge[:surfaces].keys.each do |identifier|
|
1831
|
+
break if match
|
1832
|
+
next unless holes.key?(identifier)
|
1833
|
+
|
1834
|
+
if holes[identifier].attributes.key?(:unhinged)
|
1835
|
+
nb = 0 if holes[identifier].attributes[:unhinged]
|
1836
|
+
break if holes[identifier].attributes[:unhinged]
|
1837
|
+
end
|
1838
|
+
|
1839
|
+
nb += 1
|
1840
|
+
match = true if nb > 1
|
1841
|
+
end
|
1842
|
+
|
1843
|
+
if nb == 1 # linking 1x subsurface, search for 1x other.
|
1844
|
+
e1 = { v0: edge[:v0].point, v1: edge[:v1].point }
|
1845
|
+
|
1846
|
+
edges.each do |nom, e|
|
1847
|
+
nb = 0
|
1848
|
+
break if match
|
1849
|
+
next if nom == id
|
1850
|
+
next if e.key?(:io_type)
|
1851
|
+
next unless e.key?(:psi)
|
1852
|
+
next unless e.key?(:surfaces)
|
1853
|
+
|
1854
|
+
e[:surfaces].keys.each do |identifier|
|
1855
|
+
next unless holes.key?(identifier)
|
1856
|
+
|
1857
|
+
if holes[identifier].attributes.key?(:unhinged)
|
1858
|
+
nb = 0 if holes[identifier].attributes[:unhinged]
|
1859
|
+
break if holes[identifier].attributes[:unhinged]
|
1860
|
+
end
|
1861
|
+
|
1862
|
+
nb += 1
|
1863
|
+
end
|
1864
|
+
|
1865
|
+
next unless nb == 1 # only process edge if linking 1x subsurface
|
1866
|
+
|
1867
|
+
e2 = { v0: e[:v0].point, v1: e[:v1].point }
|
1868
|
+
match = matches?(e1, e2, argh[:sub_tol])
|
1869
|
+
end
|
1870
|
+
end
|
1871
|
+
|
1872
|
+
next unless match
|
1873
|
+
|
1874
|
+
edge[:psi] = { transition: 0.000 }
|
1875
|
+
edge[:set] = json[:io][:building][:psi]
|
1876
|
+
end
|
1877
|
+
|
1774
1878
|
# Loop through each edge and assign heat loss to linked surfaces.
|
1775
1879
|
edges.each do |identifier, edge|
|
1776
1880
|
next unless edge.key?(:psi)
|
1777
1881
|
rsi = 0
|
1778
|
-
max = edge[:psi].values.max
|
1779
|
-
type = edge[:psi].key(max)
|
1882
|
+
max = edge[:psi ].values.max
|
1883
|
+
type = edge[:psi ].key(max)
|
1780
1884
|
length = edge[:length]
|
1885
|
+
length *= edge[:mult ] if edge.key?(:mult)
|
1781
1886
|
bridge = { psi: max, type: type, length: length }
|
1782
1887
|
deratables = {}
|
1783
1888
|
apertures = {}
|
@@ -1869,7 +1974,7 @@ module TBD
|
|
1869
1974
|
# ... first 'uprate' targeted insulation layers (see ua.rb) before derating.
|
1870
1975
|
# Check for new argh keys [:wall_uo], [:roof_uo] and/or [:floor_uo].
|
1871
1976
|
up = argh[:uprate_walls] || argh[:uprate_roofs] || argh[:uprate_floors]
|
1872
|
-
uprate(model, tbd[:surfaces], argh)
|
1977
|
+
uprate(model, tbd[:surfaces], argh) if up
|
1873
1978
|
|
1874
1979
|
# Derated (cloned) constructions are unique to each deratable surface.
|
1875
1980
|
# Unique construction names are prefixed with the surface name,
|
@@ -1975,6 +2080,7 @@ module TBD
|
|
1975
2080
|
set = e[:set]
|
1976
2081
|
t = e[:psi].key(v)
|
1977
2082
|
l = e[:length]
|
2083
|
+
l *= e[:mult] if e.key?(:mult)
|
1978
2084
|
edge = { psi: set, type: t, length: l, surfaces: e[:surfaces].keys }
|
1979
2085
|
edge[:v0x] = e[:v0].point.x
|
1980
2086
|
edge[:v0y] = e[:v0].point.y
|