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