tbd 3.2.0 → 3.2.2
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/README.md +3 -7
- data/Rakefile +8 -7
- data/lib/measures/tbd/measure.xml +24 -24
- data/lib/measures/tbd/resources/geo.rb +7 -3
- data/lib/measures/tbd/resources/model.rb +0 -6
- data/lib/measures/tbd/resources/psi.rb +4 -3
- data/lib/measures/tbd/resources/ua.rb +154 -145
- data/lib/measures/tbd/resources/version.rb +1 -1
- data/lib/tbd/geo.rb +7 -3
- data/lib/tbd/psi.rb +4 -3
- data/lib/tbd/ua.rb +154 -145
- data/lib/tbd/version.rb +1 -1
- data/lib/tbd.rb +8 -8
- 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: 858b576df6d2a7c00b547c1bcb86fcae917f441c236f012610309b5df96f2d19
|
4
|
+
data.tar.gz: ee47f03ce21e7ef8d95968aa0d159a39875ca546c32b48c8f96d7779b1ef341d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d7d4ad54c0d8d06776b868037a717d8efc11d4f1e1290cbf972202bae04ef4e6e6ea21cf227a8405c508c1d31f1bbb9e5667a21af9186984b28eee19a5e4395
|
7
|
+
data.tar.gz: eaae502337964abffe89643e4c1e6070f3a228db3ef6d87983f0cc7c9218f124e72eae6e502bd06ff7119fd594ed784d3f4232a3bd1ddb03c1d23f7bcce1c951
|
data/README.md
CHANGED
@@ -32,9 +32,7 @@ TBD is systematically tested against updated OpenStudio versions (since v3.0.0).
|
|
32
32
|
|
33
33
|
### Windows Installation
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
From the command line, check that the ruby installation returns the correct Ruby version:
|
35
|
+
Either install Ruby using the [RubyInstaller](https://rubyinstaller.org/downloads/archives/) for [Ruby 2.7.2 (x64)](https://github.com/oneclick/rubyinstaller2/releases/tag/RubyInstaller-2.7.2-1/rubyinstaller-2.7.2-1-x64.exe), or preferably under [WSL2](https://gist.github.com/brgix/0d968d8f32c41f13300dc6769414df79). Run the following steps if going down the _RubyInstaller_ route. From the command line, check that the ruby installation returns the correct Ruby version:
|
38
36
|
```
|
39
37
|
ruby -v
|
40
38
|
```
|
@@ -57,9 +55,6 @@ Verify your OpenStudio and Ruby configuration:
|
|
57
55
|
ruby -e "require 'openstudio'" -e "puts OpenStudio::Model::Model.new"
|
58
56
|
```
|
59
57
|
|
60
|
-
`git clone` the TBD repo, then run basic tests to ensure the measure operates properly (see end of this README).
|
61
|
-
|
62
|
-
|
63
58
|
### MacOS Installation
|
64
59
|
|
65
60
|
MacOS already comes with Ruby, but likely not the right Ruby version for the desired OpenStudio measure development [environment](https://github.com/NREL/OpenStudio/wiki/OpenStudio-SDK-Version-Compatibility-Matrix). Instructions here show how to install Ruby v2.7.2 alongside MacOS's own Ruby version. Although no longer officially supported, instructions for an OpenStudio v2.9.1 setup is described [here](https://github.com/rd2/tbd/blob/master/v291_MacOS.md).
|
@@ -117,8 +112,9 @@ cd ~/Documents/sandbox340
|
|
117
112
|
ruby -e "require 'openstudio'" -e "puts OpenStudio::Model::Model.new"
|
118
113
|
```
|
119
114
|
|
120
|
-
|
115
|
+
## Clone TBD
|
121
116
|
|
117
|
+
Once done with either the Windows or MacOS setup, install the latest version of _git_ (e.g. through Homebrew), then ```git clone``` the TBD repo, e.g. under "sandbox340". Run the basic tests below to ensure the measure operates as expected.
|
122
118
|
|
123
119
|
## Complete list of test commands
|
124
120
|
|
data/Rakefile
CHANGED
@@ -2,28 +2,29 @@ require "bundler/gem_tasks"
|
|
2
2
|
require "rspec/core/rake_task"
|
3
3
|
|
4
4
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
5
|
-
|
5
|
+
t.rspec_opts = "--exclude-pattern \'spec/**/*suite_spec.rb\'"
|
6
6
|
end
|
7
7
|
|
8
8
|
task default: :spec
|
9
9
|
|
10
10
|
desc "Update Library Files"
|
11
11
|
task :libraries do
|
12
|
-
puts "Updating Library Files"
|
12
|
+
# puts "Updating Library Files"
|
13
13
|
|
14
14
|
require "fileutils"
|
15
15
|
|
16
16
|
libs = ["topolys", "osut", "oslg", "tbd"]
|
17
17
|
files = {}
|
18
|
-
|
18
|
+
|
19
19
|
$:.each do |path|
|
20
20
|
libs.each do |l|
|
21
21
|
next unless path.include?(l)
|
22
|
+
|
22
23
|
files[l] = Dir.glob(File.join(path, "#{l}/*.rb"))
|
23
24
|
files[l].delete_if { |f| f.include?("version.rb") } unless l == "topolys"
|
24
|
-
puts "#{l} lib files:"
|
25
|
-
files[l].each { |lf| puts "... #{lf}" }
|
26
|
-
puts
|
25
|
+
# puts "#{l} lib files:"
|
26
|
+
# files[l].each { |lf| puts "... #{lf}" }
|
27
|
+
# puts
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
@@ -38,7 +39,7 @@ end
|
|
38
39
|
|
39
40
|
desc "Update Measure"
|
40
41
|
task measure: [:libraries] do
|
41
|
-
puts "Updating Measure"
|
42
|
+
# puts "Updating Measure"
|
42
43
|
|
43
44
|
require "openstudio"
|
44
45
|
require "open3"
|
@@ -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>ca5db4f4-8624-4699-a544-609690a03d14</version_id>
|
7
|
+
<version_modified>20230322T224647Z</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>
|
@@ -388,18 +388,6 @@
|
|
388
388
|
<usage_type>resource</usage_type>
|
389
389
|
<checksum>D80E9AE6</checksum>
|
390
390
|
</file>
|
391
|
-
<file>
|
392
|
-
<filename>model.rb</filename>
|
393
|
-
<filetype>rb</filetype>
|
394
|
-
<usage_type>resource</usage_type>
|
395
|
-
<checksum>57ED37BF</checksum>
|
396
|
-
</file>
|
397
|
-
<file>
|
398
|
-
<filename>version.rb</filename>
|
399
|
-
<filetype>rb</filetype>
|
400
|
-
<usage_type>resource</usage_type>
|
401
|
-
<checksum>05CC939E</checksum>
|
402
|
-
</file>
|
403
391
|
<file>
|
404
392
|
<filename>LICENSE.md</filename>
|
405
393
|
<filetype>md</filetype>
|
@@ -442,28 +430,40 @@
|
|
442
430
|
<checksum>58ED6635</checksum>
|
443
431
|
</file>
|
444
432
|
<file>
|
445
|
-
<filename>
|
433
|
+
<filename>README.md</filename>
|
434
|
+
<filetype>md</filetype>
|
435
|
+
<usage_type>readme</usage_type>
|
436
|
+
<checksum>B836C43A</checksum>
|
437
|
+
</file>
|
438
|
+
<file>
|
439
|
+
<filename>psi.rb</filename>
|
446
440
|
<filetype>rb</filetype>
|
447
441
|
<usage_type>resource</usage_type>
|
448
|
-
<checksum>
|
442
|
+
<checksum>1045EF38</checksum>
|
449
443
|
</file>
|
450
444
|
<file>
|
451
|
-
<filename>
|
445
|
+
<filename>model.rb</filename>
|
452
446
|
<filetype>rb</filetype>
|
453
447
|
<usage_type>resource</usage_type>
|
454
|
-
<checksum>
|
448
|
+
<checksum>8E9A76C7</checksum>
|
455
449
|
</file>
|
456
450
|
<file>
|
457
|
-
<filename>
|
458
|
-
<filetype>
|
459
|
-
<usage_type>
|
460
|
-
<checksum>
|
451
|
+
<filename>version.rb</filename>
|
452
|
+
<filetype>rb</filetype>
|
453
|
+
<usage_type>resource</usage_type>
|
454
|
+
<checksum>A3BB982A</checksum>
|
461
455
|
</file>
|
462
456
|
<file>
|
463
|
-
<filename>
|
457
|
+
<filename>geo.rb</filename>
|
458
|
+
<filetype>rb</filetype>
|
459
|
+
<usage_type>resource</usage_type>
|
460
|
+
<checksum>8242FCEF</checksum>
|
461
|
+
</file>
|
462
|
+
<file>
|
463
|
+
<filename>ua.rb</filename>
|
464
464
|
<filetype>rb</filetype>
|
465
465
|
<usage_type>resource</usage_type>
|
466
|
-
<checksum>
|
466
|
+
<checksum>695F5AC2</checksum>
|
467
467
|
</file>
|
468
468
|
</files>
|
469
469
|
</measure>
|
@@ -292,28 +292,31 @@ module TBD
|
|
292
292
|
|
293
293
|
return mismatch("model", model, cl1, mth) unless model.is_a?(cl1)
|
294
294
|
return mismatch("surface", surface, cl2, mth) unless surface.is_a?(cl2)
|
295
|
-
|
296
|
-
return nil unless validate(surface)
|
295
|
+
return nil unless validate(surface)
|
297
296
|
|
298
297
|
nom = surface.nameString
|
299
298
|
surf = {}
|
300
299
|
subs = {}
|
301
300
|
fd = false
|
302
301
|
return empty("'#{nom}' space", mth, ERR) if surface.space.empty?
|
302
|
+
|
303
303
|
space = surface.space.get
|
304
304
|
stype = space.spaceType
|
305
305
|
story = space.buildingStory
|
306
306
|
tr = transforms(model, space)
|
307
307
|
return invalid("'#{nom}' transform", mth, 0, FTL) unless tr[:t] && tr[:r]
|
308
|
+
|
308
309
|
t = tr[:t]
|
309
310
|
n = trueNormal(surface, tr[:r])
|
310
311
|
return invalid("'#{nom}' normal", mth, 0, FTL) unless n
|
312
|
+
|
311
313
|
type = surface.surfaceType.downcase
|
312
314
|
facing = surface.outsideBoundaryCondition
|
313
315
|
|
314
316
|
if facing.downcase == "surface"
|
315
317
|
empty = surface.adjacentSurface.empty?
|
316
|
-
return invalid("'#{nom}': adjacent surface", mth, 0, ERR)
|
318
|
+
return invalid("'#{nom}': adjacent surface", mth, 0, ERR) if empty
|
319
|
+
|
317
320
|
facing = surface.adjacentSurface.get.nameString
|
318
321
|
end
|
319
322
|
|
@@ -350,6 +353,7 @@ module TBD
|
|
350
353
|
surf[:story ] = story.get unless story.empty?
|
351
354
|
surf[:n ] = n
|
352
355
|
surf[:gross ] = surface.grossArea
|
356
|
+
surf[:filmRSI ] = surface.filmResistance
|
353
357
|
|
354
358
|
surface.subSurfaces.sort_by { |s| s.nameString }.each do |s|
|
355
359
|
next unless validate(s)
|
@@ -975,8 +975,9 @@ module TBD
|
|
975
975
|
end
|
976
976
|
end
|
977
977
|
|
978
|
-
|
979
|
-
surface[:
|
978
|
+
# Recover if valid setpoints.
|
979
|
+
surface[:heating] = heat[:spt] if heat && heat[:spt]
|
980
|
+
surface[:cooling] = cool[:spt] if cool && cool[:spt]
|
980
981
|
|
981
982
|
tbd[:surfaces][s.nameString] = surface
|
982
983
|
end # (opaque) surfaces populated
|
@@ -1486,7 +1487,7 @@ module TBD
|
|
1486
1487
|
|
1487
1488
|
edge[:surfaces].keys.each do |i|
|
1488
1489
|
break if is[:rimjoist] || is[:balcony]
|
1489
|
-
break unless deratables.size
|
1490
|
+
break unless deratables.size > 0
|
1490
1491
|
break if floors.key?(id)
|
1491
1492
|
next if i == id
|
1492
1493
|
next unless floors.key?(i)
|
@@ -39,13 +39,14 @@ module TBD
|
|
39
39
|
cl1 = OpenStudio::Model::Model
|
40
40
|
cl2 = OpenStudio::Model::LayeredConstruction
|
41
41
|
cl3 = Numeric
|
42
|
+
cl4 = String
|
42
43
|
|
43
|
-
return mismatch("model", model, cl1, mth, DBG, res)
|
44
|
-
return mismatch("id",
|
45
|
-
return mismatch("lc",
|
46
|
-
return mismatch("hloss", hloss, cl3, mth, DBG, res)
|
47
|
-
return mismatch("film",
|
48
|
-
return mismatch("Ut",
|
44
|
+
return mismatch("model", model, cl1, mth, DBG, res) unless model.is_a?(cl1)
|
45
|
+
return mismatch("id" , id, cl4, mth, DBG, res) unless id.is_a?(cl4)
|
46
|
+
return mismatch("lc" , lc, cl2, mth, DBG, res) unless lc.is_a?(cl2)
|
47
|
+
return mismatch("hloss", hloss, cl3, mth, DBG, res) unless hloss.is_a?(cl3)
|
48
|
+
return mismatch("film" , film, cl3, mth, DBG, res) unless film.is_a?(cl3)
|
49
|
+
return mismatch("Ut" , ut, cl3, mth, DBG, res) unless ut.is_a?(cl3)
|
49
50
|
|
50
51
|
loss = 0.0 # residual heatloss (not assigned) [W/K]
|
51
52
|
area = lc.getNetArea
|
@@ -54,12 +55,12 @@ module TBD
|
|
54
55
|
lyr[:index] = nil unless lyr[:index] >= 0
|
55
56
|
lyr[:index] = nil unless lyr[:index] < lc.layers.size
|
56
57
|
|
57
|
-
return invalid("'#{id}' layer index", mth, 0, ERR, res)
|
58
|
-
return zero("'#{id}': heatloss", mth,
|
59
|
-
return zero("'#{id}': films", mth,
|
60
|
-
return zero("'#{id}': Ut", mth,
|
61
|
-
return invalid("'#{id}': Ut", mth, 0, WRN, res)
|
62
|
-
return zero("'#{id}': net area (m2)", mth,
|
58
|
+
return invalid("'#{id}' layer index", mth, 0, ERR, res) unless lyr[:index]
|
59
|
+
return zero("'#{id}': heatloss" , mth, WRN, res) unless hloss > TOL
|
60
|
+
return zero("'#{id}': films" , mth, WRN, res) unless film > TOL
|
61
|
+
return zero("'#{id}': Ut" , mth, WRN, res) unless ut > TOL
|
62
|
+
return invalid("'#{id}': Ut" , mth, 0, WRN, res) unless ut < 5.678
|
63
|
+
return zero("'#{id}': net area (m2)", mth, ERR, res) unless area > TOL
|
63
64
|
|
64
65
|
# First, calculate initial layer RSi to initially meet Ut target.
|
65
66
|
rt = 1 / ut # target construction Rt
|
@@ -76,7 +77,7 @@ module TBD
|
|
76
77
|
|
77
78
|
if lyr[:type] == :massless
|
78
79
|
m = lc.getLayer(lyr[:index]).to_MasslessOpaqueMaterial
|
79
|
-
return invalid("'#{id}' massless layer?", mth, 0)
|
80
|
+
return invalid("'#{id}' massless layer?", mth, 0, DBG, res) if m.empty?
|
80
81
|
|
81
82
|
m = m.get.clone(model).to_MasslessOpaqueMaterial.get
|
82
83
|
m.setName("#{id} uprated")
|
@@ -85,7 +86,7 @@ module TBD
|
|
85
86
|
m.setThermalResistance(new_r)
|
86
87
|
else # type == :standard
|
87
88
|
m = lc.getLayer(lyr[:index]).to_StandardOpaqueMaterial
|
88
|
-
return invalid("'#{id}' standard layer?", mth, 0)
|
89
|
+
return invalid("'#{id}' standard layer?", mth, 0, DBG, res) if m.empty?
|
89
90
|
|
90
91
|
m = m.get.clone(model).to_StandardOpaqueMaterial.get
|
91
92
|
m.setName("#{id} uprated")
|
@@ -141,11 +142,12 @@ module TBD
|
|
141
142
|
mth = "TBD::#{__callee__}"
|
142
143
|
cl1 = OpenStudio::Model::Model
|
143
144
|
cl2 = Hash
|
145
|
+
cl3 = OpenStudio::Model::LayeredConstruction
|
144
146
|
a = false
|
145
147
|
|
146
|
-
return mismatch("model", model, cl1, mth, DBG, a)
|
147
|
-
return mismatch("surfaces",
|
148
|
-
return mismatch("argh", model, cl1, mth, DBG, a)
|
148
|
+
return mismatch("model" , model, cl1, mth, DBG, a) unless model.is_a?(cl1)
|
149
|
+
return mismatch("surfaces", s, cl2, mth, DBG, a) unless s.is_a?(cl2)
|
150
|
+
return mismatch("argh" , model, cl1, mth, DBG, a) unless argh.is_a?(cl2)
|
149
151
|
|
150
152
|
argh[:uprate_walls ] = false unless argh.key?(:uprate_walls )
|
151
153
|
argh[:uprate_roofs ] = false unless argh.key?(:uprate_roofs )
|
@@ -168,11 +170,13 @@ module TBD
|
|
168
170
|
groups[:roof ][:op] = argh[:roof_option ]
|
169
171
|
groups[:floor][:op] = argh[:floor_option ]
|
170
172
|
|
171
|
-
groups.each do |
|
173
|
+
groups.each do |type, g|
|
172
174
|
next unless g[:up]
|
173
175
|
next unless g[:ut].is_a?(Numeric)
|
174
176
|
next unless g[:ut] < 5.678
|
175
177
|
|
178
|
+
typ = type
|
179
|
+
typ = :ceiling if typ == :roof # fix in future revision. TO-DO.
|
176
180
|
coll = {}
|
177
181
|
area = 0
|
178
182
|
film = 100000000000000
|
@@ -183,86 +187,81 @@ module TBD
|
|
183
187
|
g[:op].downcase == "all floor constructions"
|
184
188
|
|
185
189
|
if g[:op].empty?
|
186
|
-
log(ERR, "Construction to uprate? (#{mth})")
|
190
|
+
log(ERR, "Construction (#{type}) to uprate? (#{mth})")
|
187
191
|
elsif all
|
188
|
-
|
189
|
-
next unless
|
190
|
-
next unless
|
191
|
-
next
|
192
|
-
next
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
192
|
+
s.each do |nom, surface|
|
193
|
+
next unless surface.key?(:deratable )
|
194
|
+
next unless surface.key?(:type )
|
195
|
+
next unless surface.key?(:construction)
|
196
|
+
next unless surface.key?(:filmRSI )
|
197
|
+
next unless surface.key?(:index )
|
198
|
+
next unless surface.key?(:ltype )
|
199
|
+
next unless surface.key?(:r )
|
200
|
+
next unless surface[:deratable ]
|
201
|
+
next unless surface[:type ] == typ
|
202
|
+
next unless surface[:construction].is_a?(cl3)
|
203
|
+
next if surface[:index ].nil?
|
204
|
+
|
205
|
+
# Retain lowest surface film resistance (e.g. tilted surfaces).
|
206
|
+
c = surface[:construction]
|
207
|
+
i = c.nameString
|
208
|
+
aire = c.getNetArea
|
209
|
+
film = surface[:filmRSI] if surface[:filmRSI] < film
|
210
|
+
|
211
|
+
# Retain construction covering largest area. The following conditional
|
212
|
+
# is reliable UNLESS linked to other deratable surface types e.g. both
|
213
|
+
# floors AND walls (see "elsif lc" corrections below).
|
214
|
+
if aire > area
|
200
215
|
lc = c
|
216
|
+
area = aire
|
201
217
|
id = i
|
202
218
|
end
|
203
219
|
|
204
|
-
|
205
|
-
nom
|
206
|
-
coll[i] = { area: c.getNetArea, lc: c, s: {} } unless coll.key?(i)
|
207
|
-
coll[i][:s][nom] = { a: sss.netArea } unless coll[i][:s].key?(nom)
|
220
|
+
coll[i] = { area: aire, lc: c, s: {} } unless coll.key?(i)
|
221
|
+
coll[i][:s][nom] = { a: surface[:net] } unless coll[i][:s].key?(nom)
|
208
222
|
end
|
209
223
|
else
|
210
224
|
id = g[:op]
|
211
|
-
|
212
|
-
|
213
|
-
if
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
225
|
+
lc = model.getConstructionByName(id)
|
226
|
+
log(ERR, "Construction '#{id}'? (#{mth})") if lc.empty?
|
227
|
+
next if lc.empty?
|
228
|
+
|
229
|
+
lc = lc.get.to_LayeredConstruction
|
230
|
+
log(ERR, "'#{id}' layered construction? (#{mth})") if lc.empty?
|
231
|
+
next if lc.empty?
|
232
|
+
|
233
|
+
lc = lc.get
|
234
|
+
area = lc.getNetArea
|
235
|
+
coll[id] = { area: area, lc: lc, s: {} }
|
236
|
+
|
237
|
+
s.each do |nom, surface|
|
238
|
+
next unless surface.key?(:deratable )
|
239
|
+
next unless surface.key?(:type )
|
240
|
+
next unless surface.key?(:construction)
|
241
|
+
next unless surface.key?(:filmRSI )
|
242
|
+
next unless surface.key?(:index )
|
243
|
+
next unless surface.key?(:ltype )
|
244
|
+
next unless surface.key?(:r )
|
245
|
+
next unless surface[:deratable ]
|
246
|
+
next unless surface[:type ] == typ
|
247
|
+
next unless surface[:construction].is_a?(cl3)
|
248
|
+
next if surface[:index ].nil?
|
249
|
+
|
250
|
+
i = surface[:construction].nameString
|
251
|
+
next unless i == id
|
252
|
+
|
253
|
+
# Retain lowest surface film resistance (e.g. tilted surfaces).
|
254
|
+
film = surface[:filmRSI] if surface[:filmRSI] < film
|
255
|
+
|
256
|
+
coll[i][:s][nom] = { a: surface[:net] } unless coll[i][:s].key?(nom)
|
238
257
|
end
|
239
258
|
end
|
240
259
|
|
241
260
|
if coll.empty?
|
242
|
-
log(ERR, "No #{
|
261
|
+
log(ERR, "No #{type} construction to uprate - skipping (#{mth})")
|
243
262
|
next
|
244
|
-
elsif lc
|
245
|
-
#
|
246
|
-
model.getSurfaces.each do |sss|
|
247
|
-
next if sss.construction.empty?
|
248
|
-
next if sss.construction.get.to_LayeredConstruction.empty?
|
249
|
-
c = sss.construction.get.to_LayeredConstruction.get
|
250
|
-
i = c.nameString
|
251
|
-
next unless coll.key?(i)
|
252
|
-
|
253
|
-
unless sss.surfaceType.downcase.include?(label.to_s)
|
254
|
-
log(ERR, "Uprating #{label.to_s}, not '#{sss.nameString}' (#{mth})")
|
255
|
-
cloned = c.clone(model).to_LayeredConstruction.get
|
256
|
-
cloned.setName("'#{i}' cloned")
|
257
|
-
sss.setConstruction(cloned)
|
258
|
-
ok = s.key?(sss.nameString)
|
259
|
-
s[sss.nameString][:construction] = cloned if ok
|
260
|
-
coll[i][:s].delete(sss.nameString)
|
261
|
-
coll[i][:area] = c.getNetArea
|
262
|
-
next
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
263
|
+
elsif lc
|
264
|
+
# Valid layered construction - good to uprate!
|
266
265
|
lyr = insulatingLayer(lc)
|
267
266
|
lyr[:index] = nil unless lyr[:index].is_a?(Numeric)
|
268
267
|
lyr[:index] = nil unless lyr[:index] >= 0
|
@@ -270,64 +269,81 @@ module TBD
|
|
270
269
|
|
271
270
|
log(ERR, "Insulation index for '#{id}'? (#{mth})") unless lyr[:index]
|
272
271
|
next unless lyr[:index]
|
273
|
-
hloss = 0 # sum of applicable psi & khi effects [W/K]
|
274
272
|
|
275
|
-
|
276
|
-
|
277
|
-
|
273
|
+
# Ensure lc is exclusively linked to deratable surfaces of right type.
|
274
|
+
# If not, assign new lc clone to non-targeted surfaces.
|
275
|
+
s.each do |nom, surface|
|
276
|
+
next unless surface.key?(:type )
|
277
|
+
next unless surface.key?(:deratable )
|
278
|
+
next unless surface.key?(:construction)
|
279
|
+
next unless surface[:construction].is_a?(cl3)
|
280
|
+
next unless surface[:construction] == lc
|
281
|
+
|
282
|
+
ok = true
|
283
|
+
ok = false unless surface[:type ] == typ
|
284
|
+
ok = false unless surface[:deratable]
|
285
|
+
ok = false unless coll.key?(id)
|
286
|
+
ok = false unless coll[id][:s].key?(nom)
|
287
|
+
|
288
|
+
unless ok
|
289
|
+
log(WRN, "Cloning '#{nom}' construction - not '#{id}' (#{mth})")
|
290
|
+
sss = model.getSurfaceByName(nom)
|
291
|
+
next if sss.empty?
|
292
|
+
|
293
|
+
sss = sss.get
|
294
|
+
cloned = lc.clone(model).to_LayeredConstruction.get
|
295
|
+
cloned.setName("#{nom} - cloned")
|
296
|
+
sss.setConstruction(cloned)
|
297
|
+
surface[:construction] = cloned
|
298
|
+
coll[id][:s].delete(nom)
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
hloss = 0 # sum of applicable psi & khi effects [W/K]
|
278
303
|
|
304
|
+
# Tally applicable psi + khi losses. Possible construction reassignment.
|
305
|
+
coll.each do |i, col|
|
279
306
|
col[:s].keys.each do |nom|
|
280
307
|
next unless s.key?(nom)
|
281
|
-
next unless s[nom].key?(:deratable )
|
282
308
|
next unless s[nom].key?(:construction)
|
283
309
|
next unless s[nom].key?(:index )
|
284
310
|
next unless s[nom].key?(:ltype )
|
285
311
|
next unless s[nom].key?(:r )
|
286
|
-
next unless s[nom].key?(:type )
|
287
|
-
|
288
|
-
next unless s[nom][:deratable]
|
289
|
-
type = s[nom][:type].to_s.downcase
|
290
|
-
type = "roof" if type == "ceiling"
|
291
|
-
next unless type.include?(label.to_s)
|
292
312
|
|
293
313
|
# Tally applicable psi + khi.
|
294
|
-
hloss += s[nom][:heatloss] if s[nom].key?(:heatloss)
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
sss = sss.get
|
301
|
-
|
302
|
-
if sss.isConstructionDefaulted
|
303
|
-
set = defaultConstructionSet(model, sss)
|
304
|
-
constructions = set.defaultExteriorSurfaceConstructions.get
|
305
|
-
|
306
|
-
case sss.surfaceType.downcase
|
307
|
-
when "roofceiling"
|
308
|
-
constructions.setRoofCeilingConstruction(lc)
|
309
|
-
when "floor"
|
310
|
-
constructions.setFloorConstruction(lc)
|
311
|
-
else
|
312
|
-
constructions.setWallConstruction(lc)
|
313
|
-
end
|
314
|
-
else
|
315
|
-
sss.setConstruction(lc)
|
316
|
-
end
|
314
|
+
hloss += s[nom][:heatloss ] if s[nom].key?(:heatloss)
|
315
|
+
next if s[nom][:construction] == lc
|
316
|
+
|
317
|
+
# Reassign construction unless referencing lc.
|
318
|
+
sss = model.getSurfaceByName(nom)
|
319
|
+
next if sss.empty?
|
317
320
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
321
|
+
sss = sss.get
|
322
|
+
|
323
|
+
if sss.isConstructionDefaulted
|
324
|
+
set = defaultConstructionSet(model, sss) # building? story?
|
325
|
+
constructions = set.defaultExteriorSurfaceConstructions
|
326
|
+
|
327
|
+
unless constructions.empty?
|
328
|
+
constructions = constructions.get
|
329
|
+
constructions.setWallConstruction(lc) if typ == :wall
|
330
|
+
constructions.setFloorConstruction(lc) if typ == :floor
|
331
|
+
constructions.setRoofCeilingConstruction(lc) if typ == :ceiling
|
332
|
+
end
|
333
|
+
else
|
334
|
+
sss.setConstruction(lc)
|
322
335
|
end
|
336
|
+
|
337
|
+
s[nom][:construction] = lc # reset TBD attributes
|
338
|
+
s[nom][:index ] = lyr[:index]
|
339
|
+
s[nom][:ltype ] = lyr[:type ]
|
340
|
+
s[nom][:r ] = lyr[:r ] # temporary
|
323
341
|
end
|
324
342
|
end
|
325
343
|
|
326
344
|
# Merge to ensure a single entry for coll Hash.
|
327
345
|
coll.each do |i, col|
|
328
346
|
next if i == id
|
329
|
-
next unless coll.key?(id)
|
330
|
-
coll[id][:area] += col[:area]
|
331
347
|
|
332
348
|
col[:s].each do |nom, sss|
|
333
349
|
coll[id][:s][nom] = sss unless coll[id][:s].key?(nom)
|
@@ -338,6 +354,8 @@ module TBD
|
|
338
354
|
log(DBG, "Collection == 1? for '#{id}' (#{mth})") unless coll.size == 1
|
339
355
|
next unless coll.size == 1
|
340
356
|
|
357
|
+
area = lc.getNetArea
|
358
|
+
coll[id][:area] = area
|
341
359
|
res = uo(model, lc, id, hloss, film, g[:ut])
|
342
360
|
log(ERR, "Unable to uprate '#{id}' (#{mth})") unless res[:uo] && res[:m]
|
343
361
|
next unless res[:uo] && res[:m]
|
@@ -347,27 +365,18 @@ module TBD
|
|
347
365
|
# Loop through coll :s, and reset :r - likely modified by uo().
|
348
366
|
coll.values.first[:s].keys.each do |nom|
|
349
367
|
next unless s.key?(nom)
|
350
|
-
next unless s[nom].key?(:
|
351
|
-
next unless s[nom].key?(:
|
352
|
-
next unless s[nom].key?(:
|
353
|
-
next unless s[nom]
|
354
|
-
next unless s[nom]
|
355
|
-
|
356
|
-
|
357
|
-
next unless s[nom][:construction] == lc
|
358
|
-
next unless s[nom][:index ] == lyr[:index]
|
359
|
-
next unless s[nom][:ltype ] == lyr[:type]
|
360
|
-
|
361
|
-
type = s[nom][:type].to_s.downcase
|
362
|
-
type = "roof" if type == "ceiling"
|
363
|
-
next unless type.include?(label.to_s)
|
364
|
-
next unless s[nom].key?(:r)
|
365
|
-
s[nom][:r] = lyr[:r] # final
|
368
|
+
next unless s[nom].key?(:index)
|
369
|
+
next unless s[nom].key?(:ltype)
|
370
|
+
next unless s[nom].key?(:r )
|
371
|
+
next unless s[nom][:index] == lyr[:index]
|
372
|
+
next unless s[nom][:ltype] == lyr[:type ]
|
373
|
+
|
374
|
+
s[nom][:r] = lyr[:r] # uprated insulating RSi factor, before derating
|
366
375
|
end
|
367
376
|
|
368
|
-
argh[:wall_uo ] = res[:uo] if
|
369
|
-
argh[:roof_uo ] = res[:uo] if
|
370
|
-
argh[:floor_uo] = res[:uo] if
|
377
|
+
argh[:wall_uo ] = res[:uo] if typ == :wall
|
378
|
+
argh[:roof_uo ] = res[:uo] if typ == :ceiling
|
379
|
+
argh[:floor_uo] = res[:uo] if typ == :floor
|
371
380
|
else
|
372
381
|
log(ERR, "Nilled construction to uprate - (#{mth})")
|
373
382
|
return false
|
@@ -920,7 +929,7 @@ module TBD
|
|
920
929
|
model = "* modèle : #{ua[:file]}" if ua.key?(:file) && lang == :fr
|
921
930
|
model += " (v#{ua[:version]})" if ua.key?(:version)
|
922
931
|
report << model unless model.empty?
|
923
|
-
report << "* TBD : v3.2.
|
932
|
+
report << "* TBD : v3.2.2"
|
924
933
|
report << "* date : #{ua[:date]}"
|
925
934
|
|
926
935
|
if lang == :en
|
data/lib/tbd/geo.rb
CHANGED
@@ -292,28 +292,31 @@ module TBD
|
|
292
292
|
|
293
293
|
return mismatch("model", model, cl1, mth) unless model.is_a?(cl1)
|
294
294
|
return mismatch("surface", surface, cl2, mth) unless surface.is_a?(cl2)
|
295
|
-
|
296
|
-
return nil unless validate(surface)
|
295
|
+
return nil unless validate(surface)
|
297
296
|
|
298
297
|
nom = surface.nameString
|
299
298
|
surf = {}
|
300
299
|
subs = {}
|
301
300
|
fd = false
|
302
301
|
return empty("'#{nom}' space", mth, ERR) if surface.space.empty?
|
302
|
+
|
303
303
|
space = surface.space.get
|
304
304
|
stype = space.spaceType
|
305
305
|
story = space.buildingStory
|
306
306
|
tr = transforms(model, space)
|
307
307
|
return invalid("'#{nom}' transform", mth, 0, FTL) unless tr[:t] && tr[:r]
|
308
|
+
|
308
309
|
t = tr[:t]
|
309
310
|
n = trueNormal(surface, tr[:r])
|
310
311
|
return invalid("'#{nom}' normal", mth, 0, FTL) unless n
|
312
|
+
|
311
313
|
type = surface.surfaceType.downcase
|
312
314
|
facing = surface.outsideBoundaryCondition
|
313
315
|
|
314
316
|
if facing.downcase == "surface"
|
315
317
|
empty = surface.adjacentSurface.empty?
|
316
|
-
return invalid("'#{nom}': adjacent surface", mth, 0, ERR)
|
318
|
+
return invalid("'#{nom}': adjacent surface", mth, 0, ERR) if empty
|
319
|
+
|
317
320
|
facing = surface.adjacentSurface.get.nameString
|
318
321
|
end
|
319
322
|
|
@@ -350,6 +353,7 @@ module TBD
|
|
350
353
|
surf[:story ] = story.get unless story.empty?
|
351
354
|
surf[:n ] = n
|
352
355
|
surf[:gross ] = surface.grossArea
|
356
|
+
surf[:filmRSI ] = surface.filmResistance
|
353
357
|
|
354
358
|
surface.subSurfaces.sort_by { |s| s.nameString }.each do |s|
|
355
359
|
next unless validate(s)
|
data/lib/tbd/psi.rb
CHANGED
@@ -975,8 +975,9 @@ module TBD
|
|
975
975
|
end
|
976
976
|
end
|
977
977
|
|
978
|
-
|
979
|
-
surface[:
|
978
|
+
# Recover if valid setpoints.
|
979
|
+
surface[:heating] = heat[:spt] if heat && heat[:spt]
|
980
|
+
surface[:cooling] = cool[:spt] if cool && cool[:spt]
|
980
981
|
|
981
982
|
tbd[:surfaces][s.nameString] = surface
|
982
983
|
end # (opaque) surfaces populated
|
@@ -1486,7 +1487,7 @@ module TBD
|
|
1486
1487
|
|
1487
1488
|
edge[:surfaces].keys.each do |i|
|
1488
1489
|
break if is[:rimjoist] || is[:balcony]
|
1489
|
-
break unless deratables.size
|
1490
|
+
break unless deratables.size > 0
|
1490
1491
|
break if floors.key?(id)
|
1491
1492
|
next if i == id
|
1492
1493
|
next unless floors.key?(i)
|
data/lib/tbd/ua.rb
CHANGED
@@ -39,13 +39,14 @@ module TBD
|
|
39
39
|
cl1 = OpenStudio::Model::Model
|
40
40
|
cl2 = OpenStudio::Model::LayeredConstruction
|
41
41
|
cl3 = Numeric
|
42
|
+
cl4 = String
|
42
43
|
|
43
|
-
return mismatch("model", model, cl1, mth, DBG, res)
|
44
|
-
return mismatch("id",
|
45
|
-
return mismatch("lc",
|
46
|
-
return mismatch("hloss", hloss, cl3, mth, DBG, res)
|
47
|
-
return mismatch("film",
|
48
|
-
return mismatch("Ut",
|
44
|
+
return mismatch("model", model, cl1, mth, DBG, res) unless model.is_a?(cl1)
|
45
|
+
return mismatch("id" , id, cl4, mth, DBG, res) unless id.is_a?(cl4)
|
46
|
+
return mismatch("lc" , lc, cl2, mth, DBG, res) unless lc.is_a?(cl2)
|
47
|
+
return mismatch("hloss", hloss, cl3, mth, DBG, res) unless hloss.is_a?(cl3)
|
48
|
+
return mismatch("film" , film, cl3, mth, DBG, res) unless film.is_a?(cl3)
|
49
|
+
return mismatch("Ut" , ut, cl3, mth, DBG, res) unless ut.is_a?(cl3)
|
49
50
|
|
50
51
|
loss = 0.0 # residual heatloss (not assigned) [W/K]
|
51
52
|
area = lc.getNetArea
|
@@ -54,12 +55,12 @@ module TBD
|
|
54
55
|
lyr[:index] = nil unless lyr[:index] >= 0
|
55
56
|
lyr[:index] = nil unless lyr[:index] < lc.layers.size
|
56
57
|
|
57
|
-
return invalid("'#{id}' layer index", mth, 0, ERR, res)
|
58
|
-
return zero("'#{id}': heatloss", mth,
|
59
|
-
return zero("'#{id}': films", mth,
|
60
|
-
return zero("'#{id}': Ut", mth,
|
61
|
-
return invalid("'#{id}': Ut", mth, 0, WRN, res)
|
62
|
-
return zero("'#{id}': net area (m2)", mth,
|
58
|
+
return invalid("'#{id}' layer index", mth, 0, ERR, res) unless lyr[:index]
|
59
|
+
return zero("'#{id}': heatloss" , mth, WRN, res) unless hloss > TOL
|
60
|
+
return zero("'#{id}': films" , mth, WRN, res) unless film > TOL
|
61
|
+
return zero("'#{id}': Ut" , mth, WRN, res) unless ut > TOL
|
62
|
+
return invalid("'#{id}': Ut" , mth, 0, WRN, res) unless ut < 5.678
|
63
|
+
return zero("'#{id}': net area (m2)", mth, ERR, res) unless area > TOL
|
63
64
|
|
64
65
|
# First, calculate initial layer RSi to initially meet Ut target.
|
65
66
|
rt = 1 / ut # target construction Rt
|
@@ -76,7 +77,7 @@ module TBD
|
|
76
77
|
|
77
78
|
if lyr[:type] == :massless
|
78
79
|
m = lc.getLayer(lyr[:index]).to_MasslessOpaqueMaterial
|
79
|
-
return invalid("'#{id}' massless layer?", mth, 0)
|
80
|
+
return invalid("'#{id}' massless layer?", mth, 0, DBG, res) if m.empty?
|
80
81
|
|
81
82
|
m = m.get.clone(model).to_MasslessOpaqueMaterial.get
|
82
83
|
m.setName("#{id} uprated")
|
@@ -85,7 +86,7 @@ module TBD
|
|
85
86
|
m.setThermalResistance(new_r)
|
86
87
|
else # type == :standard
|
87
88
|
m = lc.getLayer(lyr[:index]).to_StandardOpaqueMaterial
|
88
|
-
return invalid("'#{id}' standard layer?", mth, 0)
|
89
|
+
return invalid("'#{id}' standard layer?", mth, 0, DBG, res) if m.empty?
|
89
90
|
|
90
91
|
m = m.get.clone(model).to_StandardOpaqueMaterial.get
|
91
92
|
m.setName("#{id} uprated")
|
@@ -141,11 +142,12 @@ module TBD
|
|
141
142
|
mth = "TBD::#{__callee__}"
|
142
143
|
cl1 = OpenStudio::Model::Model
|
143
144
|
cl2 = Hash
|
145
|
+
cl3 = OpenStudio::Model::LayeredConstruction
|
144
146
|
a = false
|
145
147
|
|
146
|
-
return mismatch("model", model, cl1, mth, DBG, a)
|
147
|
-
return mismatch("surfaces",
|
148
|
-
return mismatch("argh", model, cl1, mth, DBG, a)
|
148
|
+
return mismatch("model" , model, cl1, mth, DBG, a) unless model.is_a?(cl1)
|
149
|
+
return mismatch("surfaces", s, cl2, mth, DBG, a) unless s.is_a?(cl2)
|
150
|
+
return mismatch("argh" , model, cl1, mth, DBG, a) unless argh.is_a?(cl2)
|
149
151
|
|
150
152
|
argh[:uprate_walls ] = false unless argh.key?(:uprate_walls )
|
151
153
|
argh[:uprate_roofs ] = false unless argh.key?(:uprate_roofs )
|
@@ -168,11 +170,13 @@ module TBD
|
|
168
170
|
groups[:roof ][:op] = argh[:roof_option ]
|
169
171
|
groups[:floor][:op] = argh[:floor_option ]
|
170
172
|
|
171
|
-
groups.each do |
|
173
|
+
groups.each do |type, g|
|
172
174
|
next unless g[:up]
|
173
175
|
next unless g[:ut].is_a?(Numeric)
|
174
176
|
next unless g[:ut] < 5.678
|
175
177
|
|
178
|
+
typ = type
|
179
|
+
typ = :ceiling if typ == :roof # fix in future revision. TO-DO.
|
176
180
|
coll = {}
|
177
181
|
area = 0
|
178
182
|
film = 100000000000000
|
@@ -183,86 +187,81 @@ module TBD
|
|
183
187
|
g[:op].downcase == "all floor constructions"
|
184
188
|
|
185
189
|
if g[:op].empty?
|
186
|
-
log(ERR, "Construction to uprate? (#{mth})")
|
190
|
+
log(ERR, "Construction (#{type}) to uprate? (#{mth})")
|
187
191
|
elsif all
|
188
|
-
|
189
|
-
next unless
|
190
|
-
next unless
|
191
|
-
next
|
192
|
-
next
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
192
|
+
s.each do |nom, surface|
|
193
|
+
next unless surface.key?(:deratable )
|
194
|
+
next unless surface.key?(:type )
|
195
|
+
next unless surface.key?(:construction)
|
196
|
+
next unless surface.key?(:filmRSI )
|
197
|
+
next unless surface.key?(:index )
|
198
|
+
next unless surface.key?(:ltype )
|
199
|
+
next unless surface.key?(:r )
|
200
|
+
next unless surface[:deratable ]
|
201
|
+
next unless surface[:type ] == typ
|
202
|
+
next unless surface[:construction].is_a?(cl3)
|
203
|
+
next if surface[:index ].nil?
|
204
|
+
|
205
|
+
# Retain lowest surface film resistance (e.g. tilted surfaces).
|
206
|
+
c = surface[:construction]
|
207
|
+
i = c.nameString
|
208
|
+
aire = c.getNetArea
|
209
|
+
film = surface[:filmRSI] if surface[:filmRSI] < film
|
210
|
+
|
211
|
+
# Retain construction covering largest area. The following conditional
|
212
|
+
# is reliable UNLESS linked to other deratable surface types e.g. both
|
213
|
+
# floors AND walls (see "elsif lc" corrections below).
|
214
|
+
if aire > area
|
200
215
|
lc = c
|
216
|
+
area = aire
|
201
217
|
id = i
|
202
218
|
end
|
203
219
|
|
204
|
-
|
205
|
-
nom
|
206
|
-
coll[i] = { area: c.getNetArea, lc: c, s: {} } unless coll.key?(i)
|
207
|
-
coll[i][:s][nom] = { a: sss.netArea } unless coll[i][:s].key?(nom)
|
220
|
+
coll[i] = { area: aire, lc: c, s: {} } unless coll.key?(i)
|
221
|
+
coll[i][:s][nom] = { a: surface[:net] } unless coll[i][:s].key?(nom)
|
208
222
|
end
|
209
223
|
else
|
210
224
|
id = g[:op]
|
211
|
-
|
212
|
-
|
213
|
-
if
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
225
|
+
lc = model.getConstructionByName(id)
|
226
|
+
log(ERR, "Construction '#{id}'? (#{mth})") if lc.empty?
|
227
|
+
next if lc.empty?
|
228
|
+
|
229
|
+
lc = lc.get.to_LayeredConstruction
|
230
|
+
log(ERR, "'#{id}' layered construction? (#{mth})") if lc.empty?
|
231
|
+
next if lc.empty?
|
232
|
+
|
233
|
+
lc = lc.get
|
234
|
+
area = lc.getNetArea
|
235
|
+
coll[id] = { area: area, lc: lc, s: {} }
|
236
|
+
|
237
|
+
s.each do |nom, surface|
|
238
|
+
next unless surface.key?(:deratable )
|
239
|
+
next unless surface.key?(:type )
|
240
|
+
next unless surface.key?(:construction)
|
241
|
+
next unless surface.key?(:filmRSI )
|
242
|
+
next unless surface.key?(:index )
|
243
|
+
next unless surface.key?(:ltype )
|
244
|
+
next unless surface.key?(:r )
|
245
|
+
next unless surface[:deratable ]
|
246
|
+
next unless surface[:type ] == typ
|
247
|
+
next unless surface[:construction].is_a?(cl3)
|
248
|
+
next if surface[:index ].nil?
|
249
|
+
|
250
|
+
i = surface[:construction].nameString
|
251
|
+
next unless i == id
|
252
|
+
|
253
|
+
# Retain lowest surface film resistance (e.g. tilted surfaces).
|
254
|
+
film = surface[:filmRSI] if surface[:filmRSI] < film
|
255
|
+
|
256
|
+
coll[i][:s][nom] = { a: surface[:net] } unless coll[i][:s].key?(nom)
|
238
257
|
end
|
239
258
|
end
|
240
259
|
|
241
260
|
if coll.empty?
|
242
|
-
log(ERR, "No #{
|
261
|
+
log(ERR, "No #{type} construction to uprate - skipping (#{mth})")
|
243
262
|
next
|
244
|
-
elsif lc
|
245
|
-
#
|
246
|
-
model.getSurfaces.each do |sss|
|
247
|
-
next if sss.construction.empty?
|
248
|
-
next if sss.construction.get.to_LayeredConstruction.empty?
|
249
|
-
c = sss.construction.get.to_LayeredConstruction.get
|
250
|
-
i = c.nameString
|
251
|
-
next unless coll.key?(i)
|
252
|
-
|
253
|
-
unless sss.surfaceType.downcase.include?(label.to_s)
|
254
|
-
log(ERR, "Uprating #{label.to_s}, not '#{sss.nameString}' (#{mth})")
|
255
|
-
cloned = c.clone(model).to_LayeredConstruction.get
|
256
|
-
cloned.setName("'#{i}' cloned")
|
257
|
-
sss.setConstruction(cloned)
|
258
|
-
ok = s.key?(sss.nameString)
|
259
|
-
s[sss.nameString][:construction] = cloned if ok
|
260
|
-
coll[i][:s].delete(sss.nameString)
|
261
|
-
coll[i][:area] = c.getNetArea
|
262
|
-
next
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
263
|
+
elsif lc
|
264
|
+
# Valid layered construction - good to uprate!
|
266
265
|
lyr = insulatingLayer(lc)
|
267
266
|
lyr[:index] = nil unless lyr[:index].is_a?(Numeric)
|
268
267
|
lyr[:index] = nil unless lyr[:index] >= 0
|
@@ -270,64 +269,81 @@ module TBD
|
|
270
269
|
|
271
270
|
log(ERR, "Insulation index for '#{id}'? (#{mth})") unless lyr[:index]
|
272
271
|
next unless lyr[:index]
|
273
|
-
hloss = 0 # sum of applicable psi & khi effects [W/K]
|
274
272
|
|
275
|
-
|
276
|
-
|
277
|
-
|
273
|
+
# Ensure lc is exclusively linked to deratable surfaces of right type.
|
274
|
+
# If not, assign new lc clone to non-targeted surfaces.
|
275
|
+
s.each do |nom, surface|
|
276
|
+
next unless surface.key?(:type )
|
277
|
+
next unless surface.key?(:deratable )
|
278
|
+
next unless surface.key?(:construction)
|
279
|
+
next unless surface[:construction].is_a?(cl3)
|
280
|
+
next unless surface[:construction] == lc
|
281
|
+
|
282
|
+
ok = true
|
283
|
+
ok = false unless surface[:type ] == typ
|
284
|
+
ok = false unless surface[:deratable]
|
285
|
+
ok = false unless coll.key?(id)
|
286
|
+
ok = false unless coll[id][:s].key?(nom)
|
287
|
+
|
288
|
+
unless ok
|
289
|
+
log(WRN, "Cloning '#{nom}' construction - not '#{id}' (#{mth})")
|
290
|
+
sss = model.getSurfaceByName(nom)
|
291
|
+
next if sss.empty?
|
292
|
+
|
293
|
+
sss = sss.get
|
294
|
+
cloned = lc.clone(model).to_LayeredConstruction.get
|
295
|
+
cloned.setName("#{nom} - cloned")
|
296
|
+
sss.setConstruction(cloned)
|
297
|
+
surface[:construction] = cloned
|
298
|
+
coll[id][:s].delete(nom)
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
hloss = 0 # sum of applicable psi & khi effects [W/K]
|
278
303
|
|
304
|
+
# Tally applicable psi + khi losses. Possible construction reassignment.
|
305
|
+
coll.each do |i, col|
|
279
306
|
col[:s].keys.each do |nom|
|
280
307
|
next unless s.key?(nom)
|
281
|
-
next unless s[nom].key?(:deratable )
|
282
308
|
next unless s[nom].key?(:construction)
|
283
309
|
next unless s[nom].key?(:index )
|
284
310
|
next unless s[nom].key?(:ltype )
|
285
311
|
next unless s[nom].key?(:r )
|
286
|
-
next unless s[nom].key?(:type )
|
287
|
-
|
288
|
-
next unless s[nom][:deratable]
|
289
|
-
type = s[nom][:type].to_s.downcase
|
290
|
-
type = "roof" if type == "ceiling"
|
291
|
-
next unless type.include?(label.to_s)
|
292
312
|
|
293
313
|
# Tally applicable psi + khi.
|
294
|
-
hloss += s[nom][:heatloss] if s[nom].key?(:heatloss)
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
sss = sss.get
|
301
|
-
|
302
|
-
if sss.isConstructionDefaulted
|
303
|
-
set = defaultConstructionSet(model, sss)
|
304
|
-
constructions = set.defaultExteriorSurfaceConstructions.get
|
305
|
-
|
306
|
-
case sss.surfaceType.downcase
|
307
|
-
when "roofceiling"
|
308
|
-
constructions.setRoofCeilingConstruction(lc)
|
309
|
-
when "floor"
|
310
|
-
constructions.setFloorConstruction(lc)
|
311
|
-
else
|
312
|
-
constructions.setWallConstruction(lc)
|
313
|
-
end
|
314
|
-
else
|
315
|
-
sss.setConstruction(lc)
|
316
|
-
end
|
314
|
+
hloss += s[nom][:heatloss ] if s[nom].key?(:heatloss)
|
315
|
+
next if s[nom][:construction] == lc
|
316
|
+
|
317
|
+
# Reassign construction unless referencing lc.
|
318
|
+
sss = model.getSurfaceByName(nom)
|
319
|
+
next if sss.empty?
|
317
320
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
321
|
+
sss = sss.get
|
322
|
+
|
323
|
+
if sss.isConstructionDefaulted
|
324
|
+
set = defaultConstructionSet(model, sss) # building? story?
|
325
|
+
constructions = set.defaultExteriorSurfaceConstructions
|
326
|
+
|
327
|
+
unless constructions.empty?
|
328
|
+
constructions = constructions.get
|
329
|
+
constructions.setWallConstruction(lc) if typ == :wall
|
330
|
+
constructions.setFloorConstruction(lc) if typ == :floor
|
331
|
+
constructions.setRoofCeilingConstruction(lc) if typ == :ceiling
|
332
|
+
end
|
333
|
+
else
|
334
|
+
sss.setConstruction(lc)
|
322
335
|
end
|
336
|
+
|
337
|
+
s[nom][:construction] = lc # reset TBD attributes
|
338
|
+
s[nom][:index ] = lyr[:index]
|
339
|
+
s[nom][:ltype ] = lyr[:type ]
|
340
|
+
s[nom][:r ] = lyr[:r ] # temporary
|
323
341
|
end
|
324
342
|
end
|
325
343
|
|
326
344
|
# Merge to ensure a single entry for coll Hash.
|
327
345
|
coll.each do |i, col|
|
328
346
|
next if i == id
|
329
|
-
next unless coll.key?(id)
|
330
|
-
coll[id][:area] += col[:area]
|
331
347
|
|
332
348
|
col[:s].each do |nom, sss|
|
333
349
|
coll[id][:s][nom] = sss unless coll[id][:s].key?(nom)
|
@@ -338,6 +354,8 @@ module TBD
|
|
338
354
|
log(DBG, "Collection == 1? for '#{id}' (#{mth})") unless coll.size == 1
|
339
355
|
next unless coll.size == 1
|
340
356
|
|
357
|
+
area = lc.getNetArea
|
358
|
+
coll[id][:area] = area
|
341
359
|
res = uo(model, lc, id, hloss, film, g[:ut])
|
342
360
|
log(ERR, "Unable to uprate '#{id}' (#{mth})") unless res[:uo] && res[:m]
|
343
361
|
next unless res[:uo] && res[:m]
|
@@ -347,27 +365,18 @@ module TBD
|
|
347
365
|
# Loop through coll :s, and reset :r - likely modified by uo().
|
348
366
|
coll.values.first[:s].keys.each do |nom|
|
349
367
|
next unless s.key?(nom)
|
350
|
-
next unless s[nom].key?(:
|
351
|
-
next unless s[nom].key?(:
|
352
|
-
next unless s[nom].key?(:
|
353
|
-
next unless s[nom]
|
354
|
-
next unless s[nom]
|
355
|
-
|
356
|
-
|
357
|
-
next unless s[nom][:construction] == lc
|
358
|
-
next unless s[nom][:index ] == lyr[:index]
|
359
|
-
next unless s[nom][:ltype ] == lyr[:type]
|
360
|
-
|
361
|
-
type = s[nom][:type].to_s.downcase
|
362
|
-
type = "roof" if type == "ceiling"
|
363
|
-
next unless type.include?(label.to_s)
|
364
|
-
next unless s[nom].key?(:r)
|
365
|
-
s[nom][:r] = lyr[:r] # final
|
368
|
+
next unless s[nom].key?(:index)
|
369
|
+
next unless s[nom].key?(:ltype)
|
370
|
+
next unless s[nom].key?(:r )
|
371
|
+
next unless s[nom][:index] == lyr[:index]
|
372
|
+
next unless s[nom][:ltype] == lyr[:type ]
|
373
|
+
|
374
|
+
s[nom][:r] = lyr[:r] # uprated insulating RSi factor, before derating
|
366
375
|
end
|
367
376
|
|
368
|
-
argh[:wall_uo ] = res[:uo] if
|
369
|
-
argh[:roof_uo ] = res[:uo] if
|
370
|
-
argh[:floor_uo] = res[:uo] if
|
377
|
+
argh[:wall_uo ] = res[:uo] if typ == :wall
|
378
|
+
argh[:roof_uo ] = res[:uo] if typ == :ceiling
|
379
|
+
argh[:floor_uo] = res[:uo] if typ == :floor
|
371
380
|
else
|
372
381
|
log(ERR, "Nilled construction to uprate - (#{mth})")
|
373
382
|
return false
|
@@ -920,7 +929,7 @@ module TBD
|
|
920
929
|
model = "* modèle : #{ua[:file]}" if ua.key?(:file) && lang == :fr
|
921
930
|
model += " (v#{ua[:version]})" if ua.key?(:version)
|
922
931
|
report << model unless model.empty?
|
923
|
-
report << "* TBD : v3.2.
|
932
|
+
report << "* TBD : v3.2.2"
|
924
933
|
report << "* date : #{ua[:date]}"
|
925
934
|
|
926
935
|
if lang == :en
|
data/lib/tbd/version.rb
CHANGED
data/lib/tbd.rb
CHANGED
@@ -26,38 +26,38 @@ begin
|
|
26
26
|
# Try to load from the Topolys gem.
|
27
27
|
require "topolys"
|
28
28
|
|
29
|
-
puts "... relying on the Topolys gem"
|
29
|
+
# puts "... relying on the Topolys gem"
|
30
30
|
rescue LoadError
|
31
31
|
require_relative "topolys/model"
|
32
32
|
require_relative "topolys/geometry"
|
33
33
|
require_relative "topolys/transformation"
|
34
34
|
require_relative "topolys/version"
|
35
35
|
|
36
|
-
puts "... fallback to local Topolys files"
|
36
|
+
# puts "... fallback to local Topolys files"
|
37
37
|
end
|
38
38
|
|
39
39
|
begin
|
40
40
|
# Try to load from the OSlg gem.
|
41
41
|
require "oslg"
|
42
42
|
|
43
|
-
puts "... relying on the OSlg gem"
|
43
|
+
# puts "... relying on the OSlg gem"
|
44
44
|
rescue LoadError
|
45
45
|
require_relative "oslg/oslog"
|
46
46
|
require_relative "osut/version"
|
47
47
|
|
48
|
-
puts "... fallback to local OSlg files"
|
48
|
+
# puts "... fallback to local OSlg files"
|
49
49
|
end
|
50
50
|
|
51
51
|
begin
|
52
52
|
# Try to load from the OSut gem.
|
53
53
|
require "osut"
|
54
54
|
|
55
|
-
puts "... relying on the OSut gem"
|
55
|
+
# puts "... relying on the OSut gem"
|
56
56
|
rescue LoadError
|
57
57
|
require_relative "osut/utils"
|
58
58
|
require_relative "osut/version"
|
59
59
|
|
60
|
-
puts "... fallback to local OSut files"
|
60
|
+
# puts "... fallback to local OSut files"
|
61
61
|
end
|
62
62
|
|
63
63
|
begin
|
@@ -67,14 +67,14 @@ begin
|
|
67
67
|
require "tbd/ua"
|
68
68
|
require "tbd/version"
|
69
69
|
|
70
|
-
puts "... relying on the TBD gem"
|
70
|
+
# puts "... relying on the TBD gem"
|
71
71
|
rescue LoadError
|
72
72
|
require_relative "tbd/psi"
|
73
73
|
require_relative "tbd/geo"
|
74
74
|
require_relative "tbd/ua"
|
75
75
|
require_relative "tbd/version"
|
76
76
|
|
77
|
-
puts "... fallback to local TBD files"
|
77
|
+
# puts "... fallback to local TBD files"
|
78
78
|
end
|
79
79
|
|
80
80
|
module TBD
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tbd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Bourgeois & Dan Macumber
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: topolys
|
@@ -161,7 +161,7 @@ licenses:
|
|
161
161
|
- MIT
|
162
162
|
metadata:
|
163
163
|
homepage_uri: https://github.com/rd2/tbd
|
164
|
-
source_code_uri: https://github.com/rd2/tbd/tree/v3.2.
|
164
|
+
source_code_uri: https://github.com/rd2/tbd/tree/v3.2.2
|
165
165
|
bug_tracker_uri: https://github.com/rd2/tbd/issues
|
166
166
|
post_install_message:
|
167
167
|
rdoc_options: []
|