tbd 3.1.1 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|