Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
source "https://rubygems.org"

gem "osut", git: "https://github.com/rd2/osut", branch: "airfilm"

gemspec
6 changes: 3 additions & 3 deletions lib/measures/tbd/measure.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<schema_version>3.1</schema_version>
<name>tbd_measure</name>
<uid>8890787b-8c25-4dc8-8641-b6be1b6c2357</uid>
<version_id>833dbf17-e51f-43c7-9c8b-a79ef0e6bd3b</version_id>
<version_modified>2026-02-03T13:53:54Z</version_modified>
<version_id>3d410488-5a03-4645-8d1f-300d24ad8525</version_id>
<version_modified>2026-04-02T12:14:15Z</version_modified>
<xml_checksum>99772807</xml_checksum>
<class_name>TBDMeasure</class_name>
<display_name>Thermal Bridging and Derating - TBD</display_name>
Expand Down Expand Up @@ -547,7 +547,7 @@
<filename>utils.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>118F3A32</checksum>
<checksum>BAFE3A46</checksum>
</file>
<file>
<filename>version.rb</filename>
Expand Down
112 changes: 99 additions & 13 deletions lib/measures/tbd/resources/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,26 +106,28 @@ module OSut
# default inside + outside air film resistances (m2.K/W)
@@film = {
shading: 0.000, # NA
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
ceiling: 0.266, # interzone floor/ceiling
partition: 0.239, # interzone wall partition
wall: 0.150, # exposed wall
roof: 0.135, # exposed roof
floor: 0.192, # exposed floor
basement: 0.120, # basement wall
slab: 0.162, # 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
skylight: 0.135 # e.g. domed 4' x 4' skylight
}.freeze

# default (~1980s) envelope Uo (W/m2•K), based on surface type
@@uo = {
shading: nil, # N/A
ceiling: 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,
basement: nil, # N/A
slab: nil, # N/A
door: 1.800, # insulated, unglazed steel door (single layer)
window: 2.800, # e.g. patio doors (simple glazing)
skylight: 3.500 # all skylight technologies
Expand Down Expand Up @@ -197,6 +199,61 @@ module OSut
@@mats[:door ][:rho] = 600.000
@@mats[:door ][:cp ] = 1000.000

##
# Returns surface air film resistance(s). Surface tilt-dependent values are
# returned if a valid surface tilt [0, PI] is provided. Otherwise, generic
# tilt-independent air film resistances are returned instead.
#
# @param [:to_sym] surface type, e.g. :roof, :wall, :partition, :ceiling
# @param [Numeric] surface tilt (in rad), optional
#
# @return [Float] surface air film resistance(s)
# @return [0.0] if invalid input (see logs)
def filmResistances(type = :wall, tilt = 2 * Math::PI)
mth = "OSut::#{__callee__}"

unless tilt.is_a?(Numeric)
return mismatch("tilt", tilt, Float, mth, DBG, 0.0)
end

unless type.respond_to?(:to_sym)
return mismatch("type", type, Symbol, mth, DBG, 0.0)
end

type = type.to_s.downcase.to_sym

unless @@film.key?(type)
return invalid("type", mth, 1, DBG, 0.0)
end

# Generic, tilt-independent values.
r = @@film[type]
return r if type == :shading

# Valid tilt?
if tilt.between?(0, Math::PI)
r = OpenStudio::Model::PlanarSurface.stillAirFilmResistance(tilt)
return r if type == :basement || type == :slab

if type == :ceiling || type == :partition
# Interzone. Fetch reciprocal tilt, e.g. if tilt == 0°, tiltx = 180°
tiltx = tilt + Math::PI

# Assuming tilt is contrained [0°, 180°] - constrain tiltx [0° 180°]:
# e.g. tiltx == 210° if tilt == 30°, so convert tiltx to 150°
# e.g. tiltx == 330° if tilt == 150°, so convert tiltx to 30°
# e.g. tiltx == 275° if tilt == 95°, so convert tiltx to 85°
tiltx = Math::PI - tilt if tiltx > Math::PI
Copy link
Copy Markdown
Member Author

@brgix brgix Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New OSut filmResistances method (see PR), more aligned with EnergyPlus reported values when dealing with non-vertical interzone paired surfaces.


r += OpenStudio::Model::PlanarSurface.stillAirFilmResistance(tiltx)
else
r += 0.03 # "MOVINGAIR_15MPH"
end
end

r
end

##
# Validates if every material in a layered construction is standard & opaque.
#
Expand Down Expand Up @@ -600,10 +657,6 @@ 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)
id = trim(specs[:id])
id = "OSut:CON:#{specs[:type]}" if id.empty?

if specs.key?(:type)
unless @@uo.keys.include?(specs[:type])
return invalid("surface type", mth, 2, ERR)
Expand All @@ -612,6 +665,10 @@ def genConstruction(model = nil, specs = {})
specs[:type] = :wall
end

specs[:id] = "" unless specs.key?(:id)
id = trim(specs[:id])
id = "OSut:CON:#{specs[:type]}" if id.empty?

specs[:uo] = @@uo[ specs[:type] ] unless specs.key?(:uo) # can be nil
u = specs[:uo]

Expand Down Expand Up @@ -652,6 +709,35 @@ def genConstruction(model = nil, specs = {})
a[:compo][:mat] = @@mats[mt]
a[:compo][:d ] = d
a[:compo][:id ] = "OSut:#{mt}:#{format('%03d', d*1000)[-3..-1]}"
when :ceiling
unless specs[:clad] == :none
mt = :concrete
mt = :material if specs[:clad] == :light
d = 0.015
d = 0.100 if specs[:clad] == :medium
d = 0.200 if specs[:clad] == :heavy
a[:clad][:mat] = @@mats[mt]
a[:clad][:d ] = d
a[:clad][:id ] = "OSut:#{mt}:#{format('%03d', d*1000)[-3..-1]}"
end

mt = :mineral
mt = :polyiso if specs[:frame] == :medium
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 = :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 :partition
unless specs[:clad] == :none
d = 0.015
Expand Down
2 changes: 1 addition & 1 deletion lib/tbd/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@
# SOFTWARE.

module TBD
VERSION = "3.5.2".freeze
VERSION = "3.5.3".freeze
end
10 changes: 8 additions & 2 deletions spec/tbd_tests_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2174,7 +2174,7 @@

argh = { option: "code (Quebec)" }
json = TBD.process(model, argh)
puts TBD.logs
puts TBD.logs unless TBD.logs.empty?
expect(TBD.status).to be_zero
expect(json).to be_a(Hash)
expect(json).to have_key(:io)
Expand Down Expand Up @@ -2559,7 +2559,13 @@
c = c.get.to_LayeredConstruction
expect(c).to_not be_empty
c = c.get
expect(TBD.rsi(c, s.filmResistance)).to be_within(TOL).of(6.38)

rsi1 = s.filmResistance
rsi2 = TBD.filmResistances(:roof)
rsi3 = TBD.filmResistances(:roof, s.tilt)
expect(TBD.rsi(c, rsi1)).to be_within(TOL).of(6.38)
expect(TBD.rsi(c, rsi2)).to be_within(TOL).of(6.31)
expect(TBD.rsi(c, rsi3)).to be_within(TOL).of(6.31)

construction = c if construction.nil?
expect(c).to eq(construction)
Expand Down
3 changes: 2 additions & 1 deletion tbd.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ Gem::Specification.new do |s|
s.metadata = {}

s.add_dependency "topolys", "~> 0"
s.add_dependency "osut", "~> 0"
# s.add_dependency "osut", "~> 0"
s.add_dependency "json-schema", "~> 4"

s.add_development_dependency "osut", "~> 0.8.3"
s.add_development_dependency "bundler", "~> 2.1"
s.add_development_dependency "rake", "~> 13.0"
s.add_development_dependency "rspec", "~> 3.11"
Expand Down
Loading