diff --git a/lib/measures/tbd/measure.xml b/lib/measures/tbd/measure.xml
index 9be55b8..11ccf45 100644
--- a/lib/measures/tbd/measure.xml
+++ b/lib/measures/tbd/measure.xml
@@ -3,8 +3,8 @@
3.1
tbd_measure
8890787b-8c25-4dc8-8641-b6be1b6c2357
- 247ec62b-4661-4ed1-b2b6-64113bcacf11
- 2024-04-13T20:03:13Z
+ 082a1485-3472-43ff-ae54-4bdd356432b6
+ 2024-04-16T19:57:33Z
99772807
TBDMeasure
Thermal Bridging and Derating - TBD
@@ -547,7 +547,7 @@
utils.rb
rb
resource
- 83EACDDB
+ E3B4AF4B
version.rb
diff --git a/lib/measures/tbd/resources/utils.rb b/lib/measures/tbd/resources/utils.rb
index d57735e..2b38034 100644
--- a/lib/measures/tbd/resources/utils.rb
+++ b/lib/measures/tbd/resources/utils.rb
@@ -61,14 +61,14 @@ module OSut
# - thickness : 0.1 m
# - thermal conductivity (k ) : 0.1 W/m.K
# - density (rho) : 0.1 kg/m3
- # - specific heat (cp ) : 1400.0 J/kg.K
+ # - specific heat (cp ) : 1400.0 J/kg•K
#
# https://s3.amazonaws.com/openstudio-sdk-documentation/cpp/
# OpenStudio-3.6.1-doc/model/html/
# classopenstudio_1_1model_1_1_standard_opaque_material.html
#
# ... apart from surface roughness, rarely would these material properties be
- # suitable - and are therefore explicitely set below. On roughness:
+ # suitable - and are therefore explicitly set below. On roughness:
# - "Very Rough" : stucco
# - "Rough" : brick
# - "Medium Rough" : concrete
@@ -76,7 +76,7 @@ module OSut
# - "Smooth" : smooth plaster
# - "Very Smooth" : glass
- # thermal mass categories (e.g. exterior cladding, interior finish, framing)
+ # Thermal mass categories (e.g. exterior cladding, interior finish, framing).
@@mass = [
:none, # token for 'no user selection', resort to defaults
:light, # e.g. 16mm drywall interior
@@ -84,43 +84,42 @@ module OSut
:heavy # e.g. 200mm poured concrete
].freeze
- # basic materials (StandardOpaqueMaterials only)
+ # Basic materials (StandardOpaqueMaterials only).
@@mats = {
+ material: {}, # generic, e.g. lightweight cladding over furring, fibreboard
sand: {},
concrete: {},
brick: {},
- cladding: {}, # e.g. lightweight cladding over furring
- sheathing: {}, # e.g. plywood
+ drywall: {}, # e.g. finished drywall, intermediate sheating
+ mineral: {}, # e.g. light, semi-rigid rock wool insulation
polyiso: {}, # e.g. polyisocyanurate panel (or similar)
- cellulose: {}, # e.g. blown, dry/stabilized fiber
- mineral: {}, # e.g. semi-rigid rock wool insulation
- drywall: {},
+ cellulose: {}, # e.g. blown, dry/stabilized fibre
door: {} # single composite material (45mm insulated steel door)
}.freeze
- # default inside+outside air film resistances (m2.K/W)
+ # default inside + outside air film resistances (m2.K/W)
@@film = {
shading: 0.000, # NA
- partition: 0.000,
- wall: 0.150,
- roof: 0.140,
- floor: 0.190,
- basement: 0.120,
- slab: 0.160,
- door: 0.150,
- window: 0.150, # ignored if SimpleGlazingMaterial
- skylight: 0.140 # ignored if SimpleGlazingMaterial
+ partition: 0.150, # uninsulated wood- or steel-framed wall
+ wall: 0.150, # un/insulated wall
+ roof: 0.140, # un/insulated roof
+ floor: 0.190, # un/insulated (exposed) floor
+ basement: 0.120, # un/insulated basement wall
+ slab: 0.160, # un/insulated basement slab or slab-on-grade
+ door: 0.150, # standard, 45mm insulated steel (opaque) door
+ window: 0.150, # vertical fenestration, e.g. glazed doors, windows
+ skylight: 0.140 # e.g. domed 4' x 4' skylight
}.freeze
# default (~1980s) envelope Uo (W/m2•K), based on surface type
@@uo = {
- shading: 0.000, # N/A
- partition: 0.000, # N/A
- wall: 0.384, # rated Ro ~14.8 hr•ft2F/Btu
- roof: 0.327, # rated Ro ~17.6 hr•ft2F/Btu
- floor: 0.317, # rated Ro ~17.9 hr•ft2F/Btu (exposed floor)
- basement: 0.000, # uninsulated
- slab: 0.000, # uninsulated
+ shading: nil, # N/A
+ partition: nil, # N/A
+ wall: 0.384, # rated R14.8 hr•ft2F/Btu
+ roof: 0.327, # rated R17.6 hr•ft2F/Btu
+ floor: 0.317, # rated R17.9 hr•ft2F/Btu (exposed floor)
+ basement: nil,
+ slab: nil,
door: 1.800, # insulated, unglazed steel door (single layer)
window: 2.800, # e.g. patio doors (simple glazing)
skylight: 3.500 # all skylight technologies
@@ -128,9 +127,9 @@ module OSut
# Standard opaque materials, taken from a variety of sources (e.g. energy
# codes, NREL's BCL). Material identifiers are symbols, e.g.:
- # - :brick
# - :sand
# - :concrete
+ # - :brick
#
# Material properties remain largely constant between projects. What does
# tend to vary (between projects) are thicknesses. Actual OpenStudio opaque
@@ -146,7 +145,12 @@ module OSut
# - solar (sol) : 70%
# - visible (vis) : 70%
#
- # These can also be explicitly set, here (e.g. a redundant 'sand' example):
+ # These can also be explicitly set (see :sand).
+ @@mats[:material ][:rgh] = "MediumSmooth"
+ @@mats[:material ][:k ] = 0.115
+ @@mats[:material ][:rho] = 540.000
+ @@mats[:material ][:cp ] = 1200.000
+
@@mats[:sand ][:rgh] = "Rough"
@@mats[:sand ][:k ] = 1.290
@@mats[:sand ][:rho] = 2240.000
@@ -165,14 +169,13 @@ module OSut
@@mats[:brick ][:rho] = 1600.000
@@mats[:brick ][:cp ] = 790.000
- @@mats[:cladding ][:rgh] = "MediumSmooth"
- @@mats[:cladding ][:k ] = 0.115
- @@mats[:cladding ][:rho] = 540.000
- @@mats[:cladding ][:cp ] = 1200.000
+ @@mats[:drywall ][:k ] = 0.160
+ @@mats[:drywall ][:rho] = 785.000
+ @@mats[:drywall ][:cp ] = 1090.000
- @@mats[:sheathing][:k ] = 0.160
- @@mats[:sheathing][:rho] = 545.000
- @@mats[:sheathing][:cp ] = 1210.000
+ @@mats[:mineral ][:k ] = 0.050
+ @@mats[:mineral ][:rho] = 19.000
+ @@mats[:mineral ][:cp ] = 960.000
@@mats[:polyiso ][:k ] = 0.025
@@mats[:polyiso ][:rho] = 25.000
@@ -183,27 +186,19 @@ module OSut
@@mats[:cellulose][:rho] = 80.000
@@mats[:cellulose][:cp ] = 835.000
- @@mats[:mineral ][:k ] = 0.050
- @@mats[:mineral ][:rho] = 19.000
- @@mats[:mineral ][:cp ] = 960.000
-
- @@mats[:drywall ][:k ] = 0.160
- @@mats[:drywall ][:rho] = 785.000
- @@mats[:drywall ][:cp ] = 1090.000
-
@@mats[:door ][:rgh] = "MediumSmooth"
@@mats[:door ][:k ] = 0.080
@@mats[:door ][:rho] = 600.000
@@mats[:door ][:cp ] = 1000.000
##
- # Generates an OpenStudio multilayered construction; materials if needed.
+ # Generates an OpenStudio multilayered construction, + materials if needed.
#
# @param model [OpenStudio::Model::Model] a model
# @param [Hash] specs OpenStudio construction specifications
# @option specs [#to_s] :id ("") construction identifier
# @option specs [Symbol] :type (:wall), see @@uo
- # @option specs [Numeric] :uo clear-field Uo, in W/m2.K, see @@uo
+ # @option specs [Numeric] :uo assembly clear-field Uo, in W/m2•K, see @@uo
# @option specs [Symbol] :clad (:light) exterior cladding, see @@mass
# @option specs [Symbol] :frame (:light) assembly framing, see @@mass
# @option specs [Symbol] :finish (:light) interior finishing, see @@mass
@@ -217,18 +212,22 @@ def genConstruction(model = nil, specs = {})
return mismatch("model", model, cl1, mth) unless model.is_a?(cl1)
return mismatch("specs", specs, cl2, mth) unless specs.is_a?(cl2)
- specs[:id ] = "" unless specs.key?(:id )
+ specs[:id] = "" unless specs.key?(:id)
+ id = trim(specs[:id])
+ id = "OSut|CON|#{specs[:type]}" if id.empty?
+
specs[:type] = :wall unless specs.key?(:type)
chk = @@uo.keys.include?(specs[:type])
return invalid("surface type", mth, 2, ERR) unless chk
- id = trim(specs[:id])
- id = "OSut|CON|#{specs[:type]}" if id.empty?
specs[:uo] = @@uo[ specs[:type] ] unless specs.key?(:uo)
u = specs[:uo]
- return mismatch("#{id} Uo", u, Numeric, mth) unless u.is_a?(Numeric)
- return invalid("#{id} Uo (> 5.678)", mth, 2, ERR) if u > 5.678
- return negative("#{id} Uo" , mth, ERR) if u < 0
+
+ if u
+ return mismatch("#{id} Uo", u, Numeric, mth) unless u.is_a?(Numeric)
+ return invalid("#{id} Uo (> 5.678)", mth, 2, ERR) if u > 5.678
+ return negative("#{id} Uo" , mth, ERR) if u < 0
+ end
# Optional specs. Log/reset if invalid.
specs[:clad ] = :light unless specs.key?(:clad ) # exterior
@@ -252,31 +251,41 @@ def genConstruction(model = nil, specs = {})
case specs[:type]
when :shading
- mt = :sheathing
+ mt = :material
d = 0.015
a[:compo][:mat] = @@mats[mt]
a[:compo][:d ] = d
a[:compo][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
when :partition
- d = 0.015
- mt = :drywall
- a[:clad][:mat] = @@mats[mt]
- a[:clad][:d ] = d
- a[:clad][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
+ unless specs[:clad] == :none
+ d = 0.015
+ mt = :drywall
+ a[:clad][:mat] = @@mats[mt]
+ a[:clad][:d ] = d
+ a[:clad][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
+ end
- # TO DO: replace sheathing by mineral below a certain Uo factor.
- mt = :sheathing
+ d = 0.015
+ d = 0.100 if specs[:frame] == :medium
+ d = 0.200 if specs[:frame] == :heavy
+ d = 0.100 if u
+ mt = :concrete
+ mt = :material if specs[:frame] == :light
+ mt = :mineral if u
a[:compo][:mat] = @@mats[mt]
a[:compo][:d ] = d
a[:compo][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
- mt = :drywall
- a[:finish][:mat] = @@mats[mt]
- a[:finish][:d ] = d
- a[:finish][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
+ unless specs[:finish] == :none
+ d = 0.015
+ mt = :drywall
+ a[:finish][:mat] = @@mats[mt]
+ a[:finish][:d ] = d
+ a[:finish][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
+ end
when :wall
unless specs[:clad] == :none
- mt = :cladding
+ mt = :material
mt = :brick if specs[:clad] == :medium
mt = :concrete if specs[:clad] == :heavy
d = 0.100
@@ -287,18 +296,22 @@ def genConstruction(model = nil, specs = {})
end
mt = :drywall
- mt = :polyiso if specs[:frame] == :medium
- mt = :mineral if specs[:frame] == :heavy
+ mt = :mineral if specs[:frame] == :medium
+ mt = :polyiso if specs[:frame] == :heavy
d = 0.100
- d = 0.015 if specs[:frame] == :light
+ d = 0.015 if specs[:frame] == :light
a[:sheath][:mat] = @@mats[mt]
a[:sheath][:d ] = d
a[:sheath][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
- mt = :concrete
- mt = :mineral if specs[:frame] == :light
+ mt = :mineral
+ mt = :cellulose if specs[:frame] == :medium
+ mt = :concrete if specs[:frame] == :heavy
+ mt = :material unless u
d = 0.100
d = 0.200 if specs[:frame] == :heavy
+ d = 0.015 unless u
+
a[:compo][:mat] = @@mats[mt]
a[:compo][:d ] = d
a[:compo][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
@@ -316,25 +329,21 @@ def genConstruction(model = nil, specs = {})
when :roof
unless specs[:clad] == :none
mt = :concrete
- mt = :cladding if specs[:clad] == :light
+ mt = :material if specs[:clad] == :light
d = 0.015
d = 0.100 if specs[:clad] == :medium # e.g. terrace
d = 0.200 if specs[:clad] == :heavy # e.g. parking garage
a[:clad][:mat] = @@mats[mt]
a[:clad][:d ] = d
a[:clad][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
-
- mt = :sheathing
- d = 0.015
- a[:sheath][:mat] = @@mats[mt]
- a[:sheath][:d ] = d
- a[:sheath][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
end
- mt = :cellulose
+ mt = :mineral
mt = :polyiso if specs[:frame] == :medium
- mt = :mineral if specs[:frame] == :heavy
+ mt = :cellulose if specs[:frame] == :heavy
+ mt = :material unless u
d = 0.100
+ d = 0.015 unless u
a[:compo][:mat] = @@mats[mt]
a[:compo][:d ] = d
a[:compo][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
@@ -349,32 +358,28 @@ def genConstruction(model = nil, specs = {})
a[:finish][:d ] = d
a[:finish][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
end
- when :floor # exposed
+ when :floor
unless specs[:clad] == :none
- mt = :cladding
+ mt = :material
d = 0.015
a[:clad][:mat] = @@mats[mt]
a[:clad][:d ] = d
a[:clad][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
-
- mt = :sheathing
- d = 0.015
- a[:sheath][:mat] = @@mats[mt]
- a[:sheath][:d ] = d
- a[:sheath][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
end
- mt = :cellulose
+ mt = :mineral
mt = :polyiso if specs[:frame] == :medium
- mt = :mineral if specs[:frame] == :heavy
- d = 0.100 # possibly an insulating layer to reset
+ mt = :cellulose if specs[:frame] == :heavy
+ mt = :material unless u
+ d = 0.100
+ d = 0.015 unless u
a[:compo][:mat] = @@mats[mt]
a[:compo][:d ] = d
a[:compo][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
unless specs[:finish] == :none
mt = :concrete
- mt = :sheathing if specs[:finish] == :light
+ mt = :material if specs[:finish] == :light
d = 0.015
d = 0.100 if specs[:finish] == :medium
d = 0.200 if specs[:finish] == :heavy
@@ -382,7 +387,7 @@ def genConstruction(model = nil, specs = {})
a[:finish][:d ] = d
a[:finish][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
end
- when :slab # basement slab or slab-on-grade
+ when :slab
mt = :sand
d = 0.100
a[:clad][:mat] = @@mats[mt]
@@ -405,18 +410,18 @@ def genConstruction(model = nil, specs = {})
a[:compo][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
unless specs[:finish] == :none
- mt = :sheathing
+ mt = :material
d = 0.015
a[:finish][:mat] = @@mats[mt]
a[:finish][:d ] = d
a[:finish][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
end
- when :basement # wall
+ when :basement
unless specs[:clad] == :none
mt = :concrete
- mt = :sheathing if specs[:clad] == :light
+ mt = :material if specs[:clad] == :light
d = 0.100
- d = 0.015 if specs[:clad] == :light
+ d = 0.015 if specs[:clad] == :light
a[:clad][:mat] = @@mats[mt]
a[:clad][:d ] = d
a[:clad][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
@@ -453,16 +458,14 @@ def genConstruction(model = nil, specs = {})
a[:finish][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
end
end
- when :door # opaque
- # 45mm insulated (composite) steel door.
+ when :door
mt = :door
d = 0.045
a[:compo ][:mat ] = @@mats[mt]
a[:compo ][:d ] = d
a[:compo ][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"
- when :window # e.g. patio doors (simple glazing)
- # SimpleGlazingMaterial.
+ when :window
a[:glazing][:u ] = specs[:uo ]
a[:glazing][:shgc] = 0.450
a[:glazing][:shgc] = specs[:shgc] if specs.key?(:shgc)
@@ -470,7 +473,6 @@ def genConstruction(model = nil, specs = {})
a[:glazing][:id ] += "|U#{format('%.1f', a[:glazing][:u])}"
a[:glazing][:id ] += "|SHGC#{format('%d', a[:glazing][:shgc]*100)}"
when :skylight
- # SimpleGlazingMaterial.
a[:glazing][:u ] = specs[:uo ]
a[:glazing][:shgc] = 0.450
a[:glazing][:shgc] = specs[:shgc] if specs.key?(:shgc)
@@ -530,7 +532,7 @@ def genConstruction(model = nil, specs = {})
# Adjust insulating layer thickness or conductivity to match requested Uo.
unless glazed
ro = 0
- ro = 1 / specs[:uo] - @@film[ specs[:type] ] if specs[:uo] > 0
+ ro = 1 / specs[:uo] - @@film[ specs[:type] ] if specs[:uo]
if specs[:type] == :door # 1x layer, adjust conductivity
layer = c.getLayer(0).to_StandardOpaqueMaterial
@@ -5097,7 +5099,7 @@ def daylit?(space = nil, sidelit = true, toplit = true, baselit = true)
(walls + roofs + floors).each do |surface|
surface.subSurfaces.each do |sub|
# All fenestrated subsurface types are considered, as user can set these
- # explicitely (e.g. skylight in a wall) in OpenStudio.
+ # explicitly (e.g. skylight in a wall) in OpenStudio.
return true if fenestration?(sub)
end
end
@@ -5954,7 +5956,7 @@ def addSkyLights(spaces = [], opts = {})
#
# For the simple case below (steep 4-sided hip roof, UNENCLOSED ventilated
# attic), 90.1 users typically choose between either:
- # 1. modelling the ventilated attic explicitely, or
+ # 1. modelling the ventilated attic explicitly, or
# 2. ignoring the ventilated attic altogether.
#
# If skylights were added to the model, option (1) would require one or more
@@ -7265,7 +7267,6 @@ def addSkyLights(spaces = [], opts = {})
end
end
-
# New direct roof loop. No overlaps, so no need for relative space
# coordinate adjustments.
rooms.each do |space, room|