lib/openstudio-standards/btap/bridging.rb in openstudio-standards-0.4.0 vs lib/openstudio-standards/btap/bridging.rb in openstudio-standards-0.5.0.rc1
- old
+ new
@@ -18,30 +18,33 @@
# **************************************************************************** /
require 'tbd'
module BTAP
+ # ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- #
module BridgingData
##
# BTAP module/class for Thermal Bridging & Derating (TBD) functionality
# for linear thermal bridges, e.g. corners, balconies (rd2.github.io/tbd).
#
# @author: Denis Bourgeois
+ # --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --- #
# BTAP/TBD data extracted from the BTAP costing spreadsheet:
#
# - range of clear-field Uo factors
# - range of PSI factors (i.e. MAJOR thermal bridging), e.g. corners
# - costing parameters
#
- # NOTE: This module is be replaced with roo-based spreadsheet parsing,
+ # NOTE: This module is to be replaced with roo-based spreadsheet parsing,
# generating a BTAP costing JSON file. TO DO.
#
# Ref: EVOKE BTAP costing spreadsheet modifications (2022), synced with:
# - Building Envelope Thermal Bridging Guide (BETBG)
# - ASHRAE RP-1365, ISO-12011, etc.
+ # --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --- #
# BTAP costing data (both original BTAP constructions and EVOKE's
# additions) hold sub-variants based on cladding/veneer, e.g.:
#
# - "BTAP-ExteriorWall-WoodFramed-5" ... brick veneer
# - "BTAP-ExteriorWall-WoodFramed-1" ... wood siding
@@ -63,18 +66,18 @@
#
# ---- High Performance (HP) variants
#
# ID : (layers)
# ----- ------------------------------------------
- # STEL2 : cladding | board | wool | frame | gypsum
- # WOOD7 : brick | mineral | wool | frame | gypsum
- # MTALD : panel | polyiso | foam | frame | gypsum
- # MASSB : brick | mineral | cmu | foam | gypsum
- # MASS8 : precast | xps | wool | frame | gypsum
- # MASSC : cladding | mineral | cmu | foam | gypsum
+ # STEL2 : cladding | board | wool | frame | gypsum ... switch from STEL1
+ # WOOD7 : brick | mineral | wool | frame | gypsum ... switch from WOOD5
+ # MTALD : panel | polyiso | foam | frame | gypsum ... switch from MTAL1
+ # MASSB : brick | mineral | cmu | foam | gypsum ... switch from MASS2
+ # MASS8 : precast | xps | wool | frame | gypsum ... switch from MASS4
+ # MASSC : cladding | mineral | cmu | foam | gypsum ... switch from MASS6
#
- # Paired LPs vs HPs vall variants are critical for 'uprating' cases, e.g.
+ # Paired LPs & HPs vall variants are critical for 'uprating' cases, e.g.
# NECB2017. See below, and end of this document for additional NOTES.
MASS2 = "BTAP-ExteriorWall-Mass-2" # LP wall
MASS2_BAD = "BTAP-ExteriorWall-Mass-2 bad" # LP "bad" PSI factors
MASS2_GOOD = "BTAP-ExteriorWall-Mass-2 good" # LP "good" PSI factors
@@ -121,10 +124,11 @@
FLOOR = "BTAP-ExteriorFloor-SteelFramed-1"
UMIN = 0.010
UMAX = 5.678
+ # --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --- #
# There are 3 distinct BTAP "building_envelope" classes to enrich with
# TBD functionality (whether BTAP users choose to activate TBD or not):
#
# 1. BTAPPRE1980
# - superclass for BTAP1980TO2010
@@ -143,11 +147,11 @@
# For vintages < NECB2017, the default BTAP policy is to switch off TBD,
# i.e. 'none' (see the NOTE on this topic at the end of this document). To
# instead assess prescriptive Ut compliance for vintages NECB2017 and
# NECB2020, the BTAP/TBD must be set to "uprate" so it can iteratively reset
# combined Uo & PSI factors towards finding the least expensive, yet
- # compliant combination. Why? Improved Uo construction variants are
+ # compliant, combination. Why? Improved Uo construction variants are
# necessarily required, given:
#
# Ut = Uo + ( ∑psi L )/A + ( ∑khi n )/A (ref: rd2.github.io/tbd)
#
# If one ignores linear ("( ∑psi L )/A") and point ("( ∑khi n )/A")
@@ -191,20 +195,18 @@
# ... switching over to another construction this way also means
# reverting back to "bad" (LP) thermal bridging PSI factors.
#
# 4. A final switch to "good" (HP) details is available (last resort).
#
- # If none of the available combinations are sufficient:
- # - TBD red-flags a failed attempt at NECB2017 or NECB2020 compliance
- # - TBD keeps iteration #4 Uo + PSI combo, then derates
- # - BTAP runs the simulation (giving some performance gap indication)
+ # If NONE of the available combinations are sufficient:
+ # - TBD red-flags a failed attempt at e.g. NECB2017 or NECB2020 compliance
+ # - TBD keeps iteration #4 Uo + PSI combo, then derates before a
+ # BTAP simulation run (giving some performance gap indication)
- # Hash of admissible Uo factors. If initial BTAP constructions fail to
- # comply when uprating, jump to subsequent high-performance variant,
- # e.g. "STEL1" switches to "STEL2". In most cases, the solution
- # prioritizes basic solutions (less $), only opting for HP variants as a
- # last recourse. There are 3x exceptions:
+ # --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --- #
+ # There are 3x exceptions to the aforementioned iterative solution,
+ # hopefully to correct (TO-DO):
#
# - Steel-framed construction: the selected HP variant has metal
# cladding. The only LP steel-framed BTAP option is wood-clad -
# something of an anomaly in commercial construction. By making the
# switch earlier to metal cladding, everywhere in Canada except
@@ -220,10 +222,11 @@
# 10c constructions.
#
# - ROOF and (exposed) FLOOR surfaces refer to a single LP/HP selection
# respectively. This is expected to change in the future ...
+ # --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --- #
# Preset BTAP/TBD wall construction parameters.
# :sptypes : BTAP/TBD Hash of linked NECB SpaceTypes (symbols)
# :uos : BTAP/TBD Hash of associated of Uo sub-variants
# :lp or :hp : low- or high-performance attribute
@@data = {}
@@ -241,17 +244,18 @@
@@data[STEL1] = { sptypes: {}, uos: {}, lp: true }
@@data[STEL2] = { sptypes: {}, uos: {}, hp: true }
@@data[FLOOR] = { sptypes: {}, uos: {} }
@@data[ROOFS] = { sptypes: {}, uos: {} }
+ # --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --- #
# A construction sub-variant is identified strictly by its Uo factor:
#
- # e.g. :314 describes a Uo factor of 0.314 W/m2.K
+ # e.g. "314" describes a Uo factor of 0.314 W/m2.K
#
# Listed items for each sub-variant are layer identifiers (for BTAP
# costing only). For the moment, they are listed integers (but should
- # be expanded (e.g. as Hash keys) to hold additional costing metadata,
+ # be expanded - e.g. as Hash keys - to hold additional costing metadata,
# e.g. $/m2). This should be (soon) removed from BTAP/TBD data.
#
# NOTE: Missing gypsum finish for WOOD7 Uo 0.130?
@@data[MASS2][:uos]["314"] = [ 24, 25, 26, 27, 28,134, 20, 21,139,141 ]
@@ -318,10 +322,11 @@
@@data[ROOFS][:uos]["142"] = [ 94, 97,106, 93 ]
@@data[ROOFS][:uos]["138"] = [ 94, 97,106, 93 ] # same as :142 ?
@@data[ROOFS][:uos]["121"] = [ 94, 97,106,150, 93]
@@data[ROOFS][:uos]["100"] = [ 94, 97,106,106, 93]
+ # --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --- #
# In BTAP costing, each NECB building/space type is linked to a default
# construction set, which holds one of the preceding wall options. This
# linkage is now extended to OpenStudio models (not just costing),
# given the construction-specific nature of MAJOR thermal bridging.
#
@@ -331,12 +336,12 @@
#
# :gym from "Gymnasium/Fitness centre exercise area"
#
# ... is implemented elsewhere in the BTAP/TBD class. The default BTAP
# wall construction for :office (fall back) is STEL1. Subsequent PSI
- # factor selection is based strictly on selected wall construction, e.g.
- # regardless of selected roof, fenestration. The linkage remains valid
+ # factor selection is based strictly on selected wall construction, i.e.
+ # regardless of selected roof, fenestration, etc. The linkage remains valid
# for both building and space types (regardless of NECB vintage).
#
# The implementation is likely to be revised in the future, yet would
# remain conceptually similar.
@@ -414,10 +419,11 @@
@@data[STEL2][:sptypes][:police ] = {}
@@data[STEL2][:sptypes][:retail ] = {}
@@data[STEL2][:sptypes][:town ] = {}
@@data[STEL2][:sptypes][:office ] = {}
+ # --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --- #
# Initialize PSI factor qualities per wall construction.
@@data.values.each do |construction|
construction[:bad ] = {}
construction[:good] = {}
end
@@ -719,10 +725,11 @@
@@data[STEL2][:good][:party ] = { psi: 0.200 }
@@data[STEL2][:good][:grade ] = { psi: 0.470 }
@@data[STEL2][:good][:joint ] = { psi: 0.100 }
@@data[STEL2][:good][:transition ] = { psi: 0.000 }
+ # --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --- #
# Extend for BTAP costing.
@@data.values.each do |construction|
construction[:good].values.each { |bridge| bridge[:mat] = {} }
construction[ :bad].values.each { |bridge| bridge[:mat] = {} }
end
@@ -730,377 +737,378 @@
# BTAP costed "materials" (Hash keywords in double quotations) for MAJOR
# thermal bridges. Corresponding Hash values are multipliers.
#
# NOTE: "0" as a NIL placeholder (no cost associated to thermal bridge).
@@data[MASS2][ :bad][:id ] = MASS2_BAD
- # @@data[MASS2][ :bad][:rimjoist ][:mat][ "21"] = 1.000
- # @@data[MASS2][ :bad][:rimjoist ][:mat]["172"] = 0.250
- # @@data[MASS2][ :bad][:parapet ][:mat][ "0"] = 1.000
- # @@data[MASS2][ :bad][:head ][:mat]["139"] = 0.750
- # @@data[MASS2][ :bad][:jamb ][:mat]["139"] = 0.750
- # @@data[MASS2][ :bad][:sill ][:mat]["139"] = 0.750
- # @@data[MASS2][ :bad][:corner ][:mat][ "0"] = 1.000
- # @@data[MASS2][ :bad][:balcony ][:mat][ ""] = 1.000
- # @@data[MASS2][ :bad][:party ][:mat][ ""] = 1.000
- # @@data[MASS2][ :bad][:grade ][:mat][ "21"] = 1.000
- # @@data[MASS2][ :bad][:grade ][:mat]["139"] = 0.500
- # @@data[MASS2][ :bad][:joint ][:mat][ ""] = 1.000
- # @@data[MASS2][ :bad][:transition ][:mat][ ""] = 1.000
+ @@data[MASS2][ :bad][:rimjoist ][:mat][ "21"] = 1.000
+ @@data[MASS2][ :bad][:rimjoist ][:mat]["172"] = 0.250
+ @@data[MASS2][ :bad][:parapet ][:mat][ "0"] = 1.000
+ @@data[MASS2][ :bad][:head ][:mat]["139"] = 0.750
+ @@data[MASS2][ :bad][:jamb ][:mat]["139"] = 0.750
+ @@data[MASS2][ :bad][:sill ][:mat]["139"] = 0.750
+ @@data[MASS2][ :bad][:corner ][:mat][ "0"] = 1.000
+ @@data[MASS2][ :bad][:balcony ][:mat][ ""] = 1.000
+ @@data[MASS2][ :bad][:party ][:mat][ ""] = 1.000
+ @@data[MASS2][ :bad][:grade ][:mat][ "21"] = 1.000
+ @@data[MASS2][ :bad][:grade ][:mat]["139"] = 0.500
+ @@data[MASS2][ :bad][:joint ][:mat][ ""] = 1.000
+ @@data[MASS2][ :bad][:transition ][:mat][ ""] = 1.000
@@data[MASS2][:good][:id ] = MASS2_GOOD
- # @@data[MASS2][:good][:rimjoist ][:mat]["189"] = 1.000
- # @@data[MASS2][:good][:rimjoist ][:mat]["172"] = 0.500
- # @@data[MASS2][:good][:parapet ][:mat][ "57"] = 3.300
- # @@data[MASS2][:good][:parapet ][:mat]["139"] = 1.000
- # @@data[MASS2][:good][:head ][:mat]["139"] = 0.500
- # @@data[MASS2][:good][:jamb ][:mat]["139"] = 0.500
- # @@data[MASS2][:good][:sill ][:mat]["139"] = 0.500
- # @@data[MASS2][:good][:corner ][:mat][ "0"] = 1.000
- # @@data[MASS2][:good][:balcony ][:mat][ ""] = 1.000
- # @@data[MASS2][:good][:party ][:mat][ ""] = 1.000
- # @@data[MASS2][:good][:grade ][:mat]["189"] = 1.000
- # @@data[MASS2][:good][:grade ][:mat]["139"] = 0.500
- # @@data[MASS2][:good][:grade ][:mat]["192"] = 0.500
- # @@data[MASS2][:good][:joint ][:mat][ ""] = 1.000
- # @@data[MASS2][:good][:transition ][:mat][ ""] = 1.000
+ @@data[MASS2][:good][:rimjoist ][:mat]["189"] = 1.000
+ @@data[MASS2][:good][:rimjoist ][:mat]["172"] = 0.500
+ @@data[MASS2][:good][:parapet ][:mat][ "57"] = 3.300
+ @@data[MASS2][:good][:parapet ][:mat]["139"] = 1.000
+ @@data[MASS2][:good][:head ][:mat]["139"] = 0.500
+ @@data[MASS2][:good][:jamb ][:mat]["139"] = 0.500
+ @@data[MASS2][:good][:sill ][:mat]["139"] = 0.500
+ @@data[MASS2][:good][:corner ][:mat][ "0"] = 1.000
+ @@data[MASS2][:good][:balcony ][:mat][ ""] = 1.000
+ @@data[MASS2][:good][:party ][:mat][ ""] = 1.000
+ @@data[MASS2][:good][:grade ][:mat]["189"] = 1.000
+ @@data[MASS2][:good][:grade ][:mat]["139"] = 0.500
+ @@data[MASS2][:good][:grade ][:mat]["192"] = 0.500
+ @@data[MASS2][:good][:joint ][:mat][ ""] = 1.000
+ @@data[MASS2][:good][:transition ][:mat][ ""] = 1.000
@@data[MASSB][ :bad][:id ] = MASSB_BAD
- # @@data[MASSB][ :bad][:rimjoist ][:mat][ "21"] = 1.000
- # @@data[MASSB][ :bad][:rimjoist ][:mat]["172"] = 0.250
- # @@data[MASSB][ :bad][:parapet ][:mat][ "0"] = 1.000
- # @@data[MASSB][ :bad][:head ][:mat]["139"] = 0.750
- # @@data[MASSB][ :bad][:jamb ][:mat]["139"] = 0.750
- # @@data[MASSB][ :bad][:sill ][:mat]["139"] = 0.750
- # @@data[MASSB][ :bad][:corner ][:mat][ "0"] = 1.000
- # @@data[MASSB][ :bad][:balcony ][:mat][ ""] = 1.000
- # @@data[MASSB][ :bad][:party ][:mat][ ""] = 1.000
- # @@data[MASSB][ :bad][:grade ][:mat][ "21"] = 1.000
- # @@data[MASSB][ :bad][:grade ][:mat]["139"] = 0.500
- # @@data[MASSB][ :bad][:joint ][:mat][ ""] = 1.000
- # @@data[MASSB][ :bad][:transition ][:mat][ ""] = 1.000
+ @@data[MASSB][ :bad][:rimjoist ][:mat][ "21"] = 1.000
+ @@data[MASSB][ :bad][:rimjoist ][:mat]["172"] = 0.250
+ @@data[MASSB][ :bad][:parapet ][:mat][ "0"] = 1.000
+ @@data[MASSB][ :bad][:head ][:mat]["139"] = 0.750
+ @@data[MASSB][ :bad][:jamb ][:mat]["139"] = 0.750
+ @@data[MASSB][ :bad][:sill ][:mat]["139"] = 0.750
+ @@data[MASSB][ :bad][:corner ][:mat][ "0"] = 1.000
+ @@data[MASSB][ :bad][:balcony ][:mat][ ""] = 1.000
+ @@data[MASSB][ :bad][:party ][:mat][ ""] = 1.000
+ @@data[MASSB][ :bad][:grade ][:mat][ "21"] = 1.000
+ @@data[MASSB][ :bad][:grade ][:mat]["139"] = 0.500
+ @@data[MASSB][ :bad][:joint ][:mat][ ""] = 1.000
+ @@data[MASSB][ :bad][:transition ][:mat][ ""] = 1.000
@@data[MASSB][:good][:id ] = MASSB_GOOD
- # @@data[MASSB][:good][:rimjoist ][:mat]["189"] = 1.000
- # @@data[MASSB][:good][:rimjoist ][:mat]["172"] = 0.500
- # @@data[MASSB][:good][:parapet ][:mat][ "57"] = 3.300
- # @@data[MASSB][:good][:parapet ][:mat]["139"] = 1.000
- # @@data[MASSB][:good][:head ][:mat]["139"] = 0.500
- # @@data[MASSB][:good][:jamb ][:mat]["139"] = 0.500
- # @@data[MASSB][:good][:sill ][:mat]["139"] = 0.500
- # @@data[MASSB][:good][:corner ][:mat][ "0"] = 1.000
- # @@data[MASSB][:good][:balcony ][:mat][ ""] = 1.000
- # @@data[MASSB][:good][:party ][:mat][ ""] = 1.000
- # @@data[MASSB][:good][:grade ][:mat]["189"] = 1.000
- # @@data[MASSB][:good][:grade ][:mat]["139"] = 0.500
- # @@data[MASSB][:good][:grade ][:mat]["192"] = 0.500
- # @@data[MASSB][:good][:joint ][:mat][ ""] = 1.000
- # @@data[MASSB][:good][:transition ][:mat][ ""] = 1.000
+ @@data[MASSB][:good][:rimjoist ][:mat]["189"] = 1.000
+ @@data[MASSB][:good][:rimjoist ][:mat]["172"] = 0.500
+ @@data[MASSB][:good][:parapet ][:mat][ "57"] = 3.300
+ @@data[MASSB][:good][:parapet ][:mat]["139"] = 1.000
+ @@data[MASSB][:good][:head ][:mat]["139"] = 0.500
+ @@data[MASSB][:good][:jamb ][:mat]["139"] = 0.500
+ @@data[MASSB][:good][:sill ][:mat]["139"] = 0.500
+ @@data[MASSB][:good][:corner ][:mat][ "0"] = 1.000
+ @@data[MASSB][:good][:balcony ][:mat][ ""] = 1.000
+ @@data[MASSB][:good][:party ][:mat][ ""] = 1.000
+ @@data[MASSB][:good][:grade ][:mat]["189"] = 1.000
+ @@data[MASSB][:good][:grade ][:mat]["139"] = 0.500
+ @@data[MASSB][:good][:grade ][:mat]["192"] = 0.500
+ @@data[MASSB][:good][:joint ][:mat][ ""] = 1.000
+ @@data[MASSB][:good][:transition ][:mat][ ""] = 1.000
@@data[MASS4][ :bad][:id ] = MASS4_BAD
- # @@data[MASS4][ :bad][:rimjoist ][:mat][ "0"] = 1.000
- # @@data[MASS4][ :bad][:parapet ][:mat][ "0"] = 1.000
- # @@data[MASS4][ :bad][:head ][:mat]["139"] = 0.250
- # @@data[MASS4][ :bad][:jamb ][:mat]["139"] = 0.250
- # @@data[MASS4][ :bad][:sill ][:mat]["139"] = 0.250
- # @@data[MASS4][ :bad][:corner ][:mat]["141"] = 1.000
- # @@data[MASS4][ :bad][:balcony ][:mat][ ""] = 1.000
- # @@data[MASS4][ :bad][:party ][:mat][ ""] = 1.000
- # @@data[MASS4][ :bad][:grade ][:mat]["139"] = 0.500
- # @@data[MASS4][ :bad][:joint ][:mat][ ""] = 1.000
- # @@data[MASS4][ :bad][:transition ][:mat][ ""] = 1.000
+ @@data[MASS4][ :bad][:rimjoist ][:mat][ "0"] = 1.000
+ @@data[MASS4][ :bad][:parapet ][:mat][ "0"] = 1.000
+ @@data[MASS4][ :bad][:head ][:mat]["139"] = 0.250
+ @@data[MASS4][ :bad][:jamb ][:mat]["139"] = 0.250
+ @@data[MASS4][ :bad][:sill ][:mat]["139"] = 0.250
+ @@data[MASS4][ :bad][:corner ][:mat]["141"] = 1.000
+ @@data[MASS4][ :bad][:balcony ][:mat][ ""] = 1.000
+ @@data[MASS4][ :bad][:party ][:mat][ ""] = 1.000
+ @@data[MASS4][ :bad][:grade ][:mat]["139"] = 0.500
+ @@data[MASS4][ :bad][:joint ][:mat][ ""] = 1.000
+ @@data[MASS4][ :bad][:transition ][:mat][ ""] = 1.000
@@data[MASS4][:good][:id ] = MASS4_GOOD
- # @@data[MASS4][:good][:rimjoist ][:mat][ "0"] = 1.000
- # @@data[MASS4][:good][:parapet ][:mat][ "57"] = 3.300
- # @@data[MASS4][:good][:parapet ][:mat]["139"] = 1.000
- # @@data[MASS4][:good][:head ][:mat]["139"] = 0.250
- # @@data[MASS4][:good][:head ][:mat]["150"] = 0.083
- # @@data[MASS4][:good][:jamb ][:mat]["139"] = 0.250
- # @@data[MASS4][:good][:jamb ][:mat]["150"] = 0.083
- # @@data[MASS4][:good][:sill ][:mat]["139"] = 0.250
- # @@data[MASS4][:good][:sill ][:mat]["150"] = 0.083
- # @@data[MASS4][:good][:corner ][:mat]["141"] = 1.250
- # @@data[MASS4][:good][:balcony ][:mat][ "0"] = 1.000
- # @@data[MASS4][:good][:party ][:mat][ ""] = 1.000
- # @@data[MASS4][:good][:grade ][:mat]["192"] = 0.500
- # @@data[MASS4][:good][:grade ][:mat]["139"] = 0.500
- # @@data[MASS4][:good][:joint ][:mat][ ""] = 1.000
- # @@data[MASS4][:good][:transition ][:mat][ ""] = 1.000
+ @@data[MASS4][:good][:rimjoist ][:mat][ "0"] = 1.000
+ @@data[MASS4][:good][:parapet ][:mat][ "57"] = 3.300
+ @@data[MASS4][:good][:parapet ][:mat]["139"] = 1.000
+ @@data[MASS4][:good][:head ][:mat]["139"] = 0.250
+ @@data[MASS4][:good][:head ][:mat]["150"] = 0.083
+ @@data[MASS4][:good][:jamb ][:mat]["139"] = 0.250
+ @@data[MASS4][:good][:jamb ][:mat]["150"] = 0.083
+ @@data[MASS4][:good][:sill ][:mat]["139"] = 0.250
+ @@data[MASS4][:good][:sill ][:mat]["150"] = 0.083
+ @@data[MASS4][:good][:corner ][:mat]["141"] = 1.250
+ @@data[MASS4][:good][:balcony ][:mat][ "0"] = 1.000
+ @@data[MASS4][:good][:party ][:mat][ ""] = 1.000
+ @@data[MASS4][:good][:grade ][:mat]["192"] = 0.500
+ @@data[MASS4][:good][:grade ][:mat]["139"] = 0.500
+ @@data[MASS4][:good][:joint ][:mat][ ""] = 1.000
+ @@data[MASS4][:good][:transition ][:mat][ ""] = 1.000
@@data[MASS8][ :bad][:id ] = MASS8_BAD
- # @@data[MASS8][ :bad][:rimjoist ][:mat][ "0"] = 1.000
- # @@data[MASS8][ :bad][:parapet ][:mat][ "0"] = 1.000
- # @@data[MASS8][ :bad][:head ][:mat]["139"] = 0.250
- # @@data[MASS8][ :bad][:jamb ][:mat]["139"] = 0.250
- # @@data[MASS8][ :bad][:sill ][:mat]["139"] = 0.250
- # @@data[MASS8][ :bad][:corner ][:mat]["141"] = 1.000
- # @@data[MASS8][ :bad][:balcony ][:mat][ ""] = 1.000
- # @@data[MASS8][ :bad][:party ][:mat][ ""] = 1.000
- # @@data[MASS8][ :bad][:grade ][:mat]["139"] = 0.500
- # @@data[MASS8][ :bad][:joint ][:mat][ ""] = 1.000
- # @@data[MASS8][ :bad][:transition ][:mat][ ""] = 1.000
+ @@data[MASS8][ :bad][:rimjoist ][:mat][ "0"] = 1.000
+ @@data[MASS8][ :bad][:parapet ][:mat][ "0"] = 1.000
+ @@data[MASS8][ :bad][:head ][:mat]["139"] = 0.250
+ @@data[MASS8][ :bad][:jamb ][:mat]["139"] = 0.250
+ @@data[MASS8][ :bad][:sill ][:mat]["139"] = 0.250
+ @@data[MASS8][ :bad][:corner ][:mat]["141"] = 1.000
+ @@data[MASS8][ :bad][:balcony ][:mat][ ""] = 1.000
+ @@data[MASS8][ :bad][:party ][:mat][ ""] = 1.000
+ @@data[MASS8][ :bad][:grade ][:mat]["139"] = 0.500
+ @@data[MASS8][ :bad][:joint ][:mat][ ""] = 1.000
+ @@data[MASS8][ :bad][:transition ][:mat][ ""] = 1.000
@@data[MASS8][:good][:id ] = MASS8_GOOD
- # @@data[MASS8][:good][:rimjoist ][:mat][ "0"] = 1.000
- # @@data[MASS8][:good][:parapet ][:mat][ "57"] = 3.300
- # @@data[MASS8][:good][:parapet ][:mat]["139"] = 1.000
- # @@data[MASS8][:good][:head ][:mat]["139"] = 0.250
- # @@data[MASS8][:good][:head ][:mat]["150"] = 0.083
- # @@data[MASS8][:good][:jamb ][:mat]["139"] = 0.250
- # @@data[MASS8][:good][:jamb ][:mat]["150"] = 0.083
- # @@data[MASS8][:good][:sill ][:mat]["139"] = 0.250
- # @@data[MASS8][:good][:sill ][:mat]["150"] = 0.083
- # @@data[MASS8][:good][:corner ][:mat]["141"] = 1.250
- # @@data[MASS8][:good][:balcony ][:mat][ "0"] = 1.000
- # @@data[MASS8][:good][:party ][:mat][ ""] = 1.000
- # @@data[MASS8][:good][:grade ][:mat]["192"] = 0.500
- # @@data[MASS8][:good][:grade ][:mat]["139"] = 0.500
- # @@data[MASS8][:good][:joint ][:mat][ ""] = 1.000
- # @@data[MASS8][:good][:transition ][:mat][ ""] = 1.000
+ @@data[MASS8][:good][:rimjoist ][:mat][ "0"] = 1.000
+ @@data[MASS8][:good][:parapet ][:mat][ "57"] = 3.300
+ @@data[MASS8][:good][:parapet ][:mat]["139"] = 1.000
+ @@data[MASS8][:good][:head ][:mat]["139"] = 0.250
+ @@data[MASS8][:good][:head ][:mat]["150"] = 0.083
+ @@data[MASS8][:good][:jamb ][:mat]["139"] = 0.250
+ @@data[MASS8][:good][:jamb ][:mat]["150"] = 0.083
+ @@data[MASS8][:good][:sill ][:mat]["139"] = 0.250
+ @@data[MASS8][:good][:sill ][:mat]["150"] = 0.083
+ @@data[MASS8][:good][:corner ][:mat]["141"] = 1.250
+ @@data[MASS8][:good][:balcony ][:mat][ "0"] = 1.000
+ @@data[MASS8][:good][:party ][:mat][ ""] = 1.000
+ @@data[MASS8][:good][:grade ][:mat]["192"] = 0.500
+ @@data[MASS8][:good][:grade ][:mat]["139"] = 0.500
+ @@data[MASS8][:good][:joint ][:mat][ ""] = 1.000
+ @@data[MASS8][:good][:transition ][:mat][ ""] = 1.000
@@data[MASS6][ :bad][:id ] = MASS6_BAD
- # @@data[MASS6][ :bad][:rimjoist ][:mat][ "21"] = 1.000
- # @@data[MASS6][ :bad][:rimjoist ][:mat]["172"] = 0.250
- # @@data[MASS6][ :bad][:parapet ][:mat][ "0"] = 1.000
- # @@data[MASS6][ :bad][:head ][:mat]["139"] = 0.750
- # @@data[MASS6][ :bad][:jamb ][:mat]["139"] = 0.750
- # @@data[MASS6][ :bad][:sill ][:mat]["139"] = 0.750
- # @@data[MASS6][ :bad][:corner ][:mat][ "0"] = 1.000
- # @@data[MASS6][ :bad][:balcony ][:mat][ ""] = 1.000
- # @@data[MASS6][ :bad][:party ][:mat][ ""] = 1.000
- # @@data[MASS6][ :bad][:grade ][:mat][ "21"] = 1.000
- # @@data[MASS6][ :bad][:grade ][:mat]["139"] = 0.500
- # @@data[MASS6][ :bad][:joint ][:mat][ ""] = 1.000
- # @@data[MASS6][ :bad][:transition ][:mat][ ""] = 1.000
+ @@data[MASS6][ :bad][:rimjoist ][:mat][ "21"] = 1.000
+ @@data[MASS6][ :bad][:rimjoist ][:mat]["172"] = 0.250
+ @@data[MASS6][ :bad][:parapet ][:mat][ "0"] = 1.000
+ @@data[MASS6][ :bad][:head ][:mat]["139"] = 0.750
+ @@data[MASS6][ :bad][:jamb ][:mat]["139"] = 0.750
+ @@data[MASS6][ :bad][:sill ][:mat]["139"] = 0.750
+ @@data[MASS6][ :bad][:corner ][:mat][ "0"] = 1.000
+ @@data[MASS6][ :bad][:balcony ][:mat][ ""] = 1.000
+ @@data[MASS6][ :bad][:party ][:mat][ ""] = 1.000
+ @@data[MASS6][ :bad][:grade ][:mat][ "21"] = 1.000
+ @@data[MASS6][ :bad][:grade ][:mat]["139"] = 0.500
+ @@data[MASS6][ :bad][:joint ][:mat][ ""] = 1.000
+ @@data[MASS6][ :bad][:transition ][:mat][ ""] = 1.000
@@data[MASS6][:good][:id ] = MASS6_GOOD
- # @@data[MASS6][:good][:rimjoist ][:mat]["189"] = 1.000
- # @@data[MASS6][:good][:rimjoist ][:mat]["172"] = 0.500
- # @@data[MASS6][:good][:parapet ][:mat][ "57"] = 3.300
- # @@data[MASS6][:good][:parapet ][:mat]["139"] = 1.000
- # @@data[MASS6][:good][:head ][:mat]["139"] = 0.500
- # @@data[MASS6][:good][:jamb ][:mat]["139"] = 0.500
- # @@data[MASS6][:good][:sill ][:mat]["139"] = 0.500
- # @@data[MASS6][:good][:corner ][:mat][ "0"] = 1.000
- # @@data[MASS6][:good][:balcony ][:mat][ ""] = 1.000
- # @@data[MASS6][:good][:party ][:mat][ ""] = 1.000
- # @@data[MASS6][:good][:grade ][:mat]["189"] = 1.000
- # @@data[MASS6][:good][:grade ][:mat]["139"] = 0.500
- # @@data[MASS6][:good][:grade ][:mat]["192"] = 0.500
- # @@data[MASS6][:good][:joint ][:mat][ ""] = 1.000
- # @@data[MASS6][:good][:transition ][:mat][ ""] = 1.000
+ @@data[MASS6][:good][:rimjoist ][:mat]["189"] = 1.000
+ @@data[MASS6][:good][:rimjoist ][:mat]["172"] = 0.500
+ @@data[MASS6][:good][:parapet ][:mat][ "57"] = 3.300
+ @@data[MASS6][:good][:parapet ][:mat]["139"] = 1.000
+ @@data[MASS6][:good][:head ][:mat]["139"] = 0.500
+ @@data[MASS6][:good][:jamb ][:mat]["139"] = 0.500
+ @@data[MASS6][:good][:sill ][:mat]["139"] = 0.500
+ @@data[MASS6][:good][:corner ][:mat][ "0"] = 1.000
+ @@data[MASS6][:good][:balcony ][:mat][ ""] = 1.000
+ @@data[MASS6][:good][:party ][:mat][ ""] = 1.000
+ @@data[MASS6][:good][:grade ][:mat]["189"] = 1.000
+ @@data[MASS6][:good][:grade ][:mat]["139"] = 0.500
+ @@data[MASS6][:good][:grade ][:mat]["192"] = 0.500
+ @@data[MASS6][:good][:joint ][:mat][ ""] = 1.000
+ @@data[MASS6][:good][:transition ][:mat][ ""] = 1.000
@@data[MASSC][ :bad][:id ] = MASSC_BAD
- # @@data[MASSC][ :bad][:rimjoist ][:mat]["139"] = 10.000
- # @@data[MASSC][ :bad][:parapet ][:mat][ "0"] = 1.000
- # @@data[MASSC][ :bad][:head ][:mat]["139"] = 0.750
- # @@data[MASSC][ :bad][:jamb ][:mat]["139"] = 0.750
- # @@data[MASSC][ :bad][:sill ][:mat]["139"] = 0.750
- # @@data[MASSC][ :bad][:corner ][:mat][ "0"] = 1.000
- # @@data[MASSC][ :bad][:balcony ][:mat][ ""] = 1.000
- # @@data[MASSC][ :bad][:party ][:mat][ ""] = 1.000
- # @@data[MASSC][ :bad][:grade ][:mat]["139"] = 0.000
- # @@data[MASSC][ :bad][:joint ][:mat][ ""] = 1.000
- # @@data[MASSC][ :bad][:transition ][:mat][ ""] = 1.000
+ @@data[MASSC][ :bad][:rimjoist ][:mat]["139"] = 10.000
+ @@data[MASSC][ :bad][:parapet ][:mat][ "0"] = 1.000
+ @@data[MASSC][ :bad][:head ][:mat]["139"] = 0.750
+ @@data[MASSC][ :bad][:jamb ][:mat]["139"] = 0.750
+ @@data[MASSC][ :bad][:sill ][:mat]["139"] = 0.750
+ @@data[MASSC][ :bad][:corner ][:mat][ "0"] = 1.000
+ @@data[MASSC][ :bad][:balcony ][:mat][ ""] = 1.000
+ @@data[MASSC][ :bad][:party ][:mat][ ""] = 1.000
+ @@data[MASSC][ :bad][:grade ][:mat]["139"] = 0.000
+ @@data[MASSC][ :bad][:joint ][:mat][ ""] = 1.000
+ @@data[MASSC][ :bad][:transition ][:mat][ ""] = 1.000
@@data[MASSC][:good][:id ] = MASSC_GOOD
- # @@data[MASSC][:good][:rimjoist ][:mat]["172"] = 0.500
- # @@data[MASSC][:good][:parapet ][:mat][ "57"] = 3.300
- # @@data[MASSC][:good][:parapet ][:mat]["139"] = 1.000
- # @@data[MASSC][:good][:head ][:mat]["139"] = 0.500
- # @@data[MASSC][:good][:jamb ][:mat]["139"] = 0.500
- # @@data[MASSC][:good][:sill ][:mat]["139"] = 0.500
- # @@data[MASSC][:good][:corner ][:mat][ "0"] = 1.000
- # @@data[MASSC][:good][:balcony ][:mat][ ""] = 1.000
- # @@data[MASSC][:good][:party ][:mat][ ""] = 1.000
- # @@data[MASSC][:good][:grade ][:mat]["192"] = 1.000
- # @@data[MASSC][:good][:grade ][:mat]["139"] = 1.000
- # @@data[MASSC][:good][:joint ][:mat][ ""] = 1.000
- # @@data[MASSC][:good][:transition ][:mat][ ""] = 1.000
+ @@data[MASSC][:good][:rimjoist ][:mat]["172"] = 0.500
+ @@data[MASSC][:good][:parapet ][:mat][ "57"] = 3.300
+ @@data[MASSC][:good][:parapet ][:mat]["139"] = 1.000
+ @@data[MASSC][:good][:head ][:mat]["139"] = 0.500
+ @@data[MASSC][:good][:jamb ][:mat]["139"] = 0.500
+ @@data[MASSC][:good][:sill ][:mat]["139"] = 0.500
+ @@data[MASSC][:good][:corner ][:mat][ "0"] = 1.000
+ @@data[MASSC][:good][:balcony ][:mat][ ""] = 1.000
+ @@data[MASSC][:good][:party ][:mat][ ""] = 1.000
+ @@data[MASSC][:good][:grade ][:mat]["192"] = 1.000
+ @@data[MASSC][:good][:grade ][:mat]["139"] = 1.000
+ @@data[MASSC][:good][:joint ][:mat][ ""] = 1.000
+ @@data[MASSC][:good][:transition ][:mat][ ""] = 1.000
@@data[MTAL1][ :bad][:id ] = MTAL1_BAD
- # @@data[MTAL1][ :bad][:rimjoist ][:mat][ "0"] = 1.000
- # @@data[MTAL1][ :bad][:parapet ][:mat][ "0"] = 1.000
- # @@data[MTAL1][ :bad][:head ][:mat]["139"] = 1.000
- # @@data[MTAL1][ :bad][:jamb ][:mat]["139"] = 1.000
- # @@data[MTAL1][ :bad][:sill ][:mat]["139"] = 1.000
- # @@data[MTAL1][ :bad][:corner ][:mat]["191"] = 1.000
- # @@data[MTAL1][ :bad][:balcony ][:mat][ ""] = 1.000
- # @@data[MTAL1][ :bad][:party ][:mat][ ""] = 1.000
- # @@data[MTAL1][ :bad][:grade ][:mat]["139"] = 0.500
- # @@data[MTAL1][ :bad][:joint ][:mat][ ""] = 1.000
- # @@data[MTAL1][ :bad][:transition ][:mat][ ""] = 1.000
+ @@data[MTAL1][ :bad][:rimjoist ][:mat][ "0"] = 1.000
+ @@data[MTAL1][ :bad][:parapet ][:mat][ "0"] = 1.000
+ @@data[MTAL1][ :bad][:head ][:mat]["139"] = 1.000
+ @@data[MTAL1][ :bad][:jamb ][:mat]["139"] = 1.000
+ @@data[MTAL1][ :bad][:sill ][:mat]["139"] = 1.000
+ @@data[MTAL1][ :bad][:corner ][:mat]["191"] = 1.000
+ @@data[MTAL1][ :bad][:balcony ][:mat][ ""] = 1.000
+ @@data[MTAL1][ :bad][:party ][:mat][ ""] = 1.000
+ @@data[MTAL1][ :bad][:grade ][:mat]["139"] = 0.500
+ @@data[MTAL1][ :bad][:joint ][:mat][ ""] = 1.000
+ @@data[MTAL1][ :bad][:transition ][:mat][ ""] = 1.000
@@data[MTAL1][:good][:id ] = MTAL1_GOOD
- # @@data[MTAL1][:good][:rimjoist ][:mat][ "0"] = 1.000
- # @@data[MTAL1][:good][:parapet ][:mat][ "57"] = 3.300
- # @@data[MTAL1][:good][:parapet ][:mat]["139"] = 1.000
- # @@data[MTAL1][:good][:head ][:mat]["139"] = 0.500
- # @@data[MTAL1][:good][:jamb ][:mat]["139"] = 0.500
- # @@data[MTAL1][:good][:sill ][:mat]["139"] = 0.500
- # @@data[MTAL1][:good][:corner ][:mat]["191"] = 1.000
- # @@data[MTAL1][:good][:balcony ][:mat][ ""] = 1.000
- # @@data[MTAL1][:good][:party ][:mat][ ""] = 1.000
- # @@data[MTAL1][:good][:grade ][:mat]["192"] = 0.500
- # @@data[MTAL1][:good][:grade ][:mat]["139"] = 0.500
- # @@data[MTAL1][:good][:joint ][:mat][ ""] = 1.000
- # @@data[MTAL1][:good][:transition ][:mat][ ""] = 1.000
+ @@data[MTAL1][:good][:rimjoist ][:mat][ "0"] = 1.000
+ @@data[MTAL1][:good][:parapet ][:mat][ "57"] = 3.300
+ @@data[MTAL1][:good][:parapet ][:mat]["139"] = 1.000
+ @@data[MTAL1][:good][:head ][:mat]["139"] = 0.500
+ @@data[MTAL1][:good][:jamb ][:mat]["139"] = 0.500
+ @@data[MTAL1][:good][:sill ][:mat]["139"] = 0.500
+ @@data[MTAL1][:good][:corner ][:mat]["191"] = 1.000
+ @@data[MTAL1][:good][:balcony ][:mat][ ""] = 1.000
+ @@data[MTAL1][:good][:party ][:mat][ ""] = 1.000
+ @@data[MTAL1][:good][:grade ][:mat]["192"] = 0.500
+ @@data[MTAL1][:good][:grade ][:mat]["139"] = 0.500
+ @@data[MTAL1][:good][:joint ][:mat][ ""] = 1.000
+ @@data[MTAL1][:good][:transition ][:mat][ ""] = 1.000
@@data[MTALD][ :bad][:id ] = MTALD_BAD
- # @@data[MTALD][ :bad][:rimjoist ][:mat][ "0"] = 1.000
- # @@data[MTALD][ :bad][:parapet ][:mat][ "0"] = 1.000
- # @@data[MTALD][ :bad][:head ][:mat]["139"] = 1.000
- # @@data[MTALD][ :bad][:jamb ][:mat]["139"] = 1.000
- # @@data[MTALD][ :bad][:sill ][:mat]["139"] = 1.000
- # @@data[MTALD][ :bad][:corner ][:mat]["191"] = 1.000
- # @@data[MTALD][ :bad][:balcony ][:mat][ ""] = 1.000
- # @@data[MTALD][ :bad][:party ][:mat][ ""] = 1.000
- # @@data[MTALD][ :bad][:grade ][:mat]["139"] = 0.500
- # @@data[MTALD][ :bad][:joint ][:mat][ ""] = 1.000
- # @@data[MTALD][ :bad][:transition ][:mat][ ""] = 1.000
+ @@data[MTALD][ :bad][:rimjoist ][:mat][ "0"] = 1.000
+ @@data[MTALD][ :bad][:parapet ][:mat][ "0"] = 1.000
+ @@data[MTALD][ :bad][:head ][:mat]["139"] = 1.000
+ @@data[MTALD][ :bad][:jamb ][:mat]["139"] = 1.000
+ @@data[MTALD][ :bad][:sill ][:mat]["139"] = 1.000
+ @@data[MTALD][ :bad][:corner ][:mat]["191"] = 1.000
+ @@data[MTALD][ :bad][:balcony ][:mat][ ""] = 1.000
+ @@data[MTALD][ :bad][:party ][:mat][ ""] = 1.000
+ @@data[MTALD][ :bad][:grade ][:mat]["139"] = 0.500
+ @@data[MTALD][ :bad][:joint ][:mat][ ""] = 1.000
+ @@data[MTALD][ :bad][:transition ][:mat][ ""] = 1.000
@@data[MTALD][:good][:id ] = MTALD_GOOD
- # @@data[MTALD][:good][:rimjoist ][:mat][ "0"] = 1.000
- # @@data[MTALD][:good][:parapet ][:mat][ "57"] = 3.300
- # @@data[MTALD][:good][:parapet ][:mat]["139"] = 1.000
- # @@data[MTALD][:good][:head ][:mat]["139"] = 0.500
- # @@data[MTALD][:good][:jamb ][:mat]["139"] = 0.500
- # @@data[MTALD][:good][:sill ][:mat]["139"] = 0.500
- # @@data[MTALD][:good][:corner ][:mat]["191"] = 1.000
- # @@data[MTALD][:good][:balcony ][:mat][ ""] = 1.000
- # @@data[MTALD][:good][:party ][:mat][ ""] = 1.000
- # @@data[MTALD][:good][:grade ][:mat]["192"] = 0.500
- # @@data[MTALD][:good][:grade ][:mat]["139"] = 0.500
- # @@data[MTALD][:good][:joint ][:mat][ ""] = 1.000
- # @@data[MTALD][:good][:transition ][:mat][ ""] = 1.000
+ @@data[MTALD][:good][:rimjoist ][:mat][ "0"] = 1.000
+ @@data[MTALD][:good][:parapet ][:mat][ "57"] = 3.300
+ @@data[MTALD][:good][:parapet ][:mat]["139"] = 1.000
+ @@data[MTALD][:good][:head ][:mat]["139"] = 0.500
+ @@data[MTALD][:good][:jamb ][:mat]["139"] = 0.500
+ @@data[MTALD][:good][:sill ][:mat]["139"] = 0.500
+ @@data[MTALD][:good][:corner ][:mat]["191"] = 1.000
+ @@data[MTALD][:good][:balcony ][:mat][ ""] = 1.000
+ @@data[MTALD][:good][:party ][:mat][ ""] = 1.000
+ @@data[MTALD][:good][:grade ][:mat]["192"] = 0.500
+ @@data[MTALD][:good][:grade ][:mat]["139"] = 0.500
+ @@data[MTALD][:good][:joint ][:mat][ ""] = 1.000
+ @@data[MTALD][:good][:transition ][:mat][ ""] = 1.000
@@data[WOOD5][ :bad][:id ] = WOOD5_BAD
- # @@data[WOOD5][ :bad][:rimjoist ][:mat][ "21"] = 1.000
- # @@data[WOOD5][ :bad][:rimjoist ][:mat]["172"] = 0.250
- # @@data[WOOD5][ :bad][:parapet ][:mat][ "0"] = 1.000
- # @@data[WOOD5][ :bad][:head ][:mat][ "0"] = 1.000
- # @@data[WOOD5][ :bad][:jamb ][:mat][ "0"] = 1.000
- # @@data[WOOD5][ :bad][:sill ][:mat][ "0"] = 1.000
- # @@data[WOOD5][ :bad][:corner ][:mat][ "0"] = 1.000
- # @@data[WOOD5][ :bad][:balcony ][:mat][ ""] = 1.000
- # @@data[WOOD5][ :bad][:party ][:mat][ ""] = 1.000
- # @@data[WOOD5][ :bad][:grade ][:mat][ "21"] = 1.000
- # @@data[WOOD5][ :bad][:grade ][:mat]["139"] = 0.500
- # @@data[WOOD5][ :bad][:joint ][:mat][ ""] = 1.000
- # @@data[WOOD5][ :bad][:transition ][:mat][ ""] = 1.000
+ @@data[WOOD5][ :bad][:rimjoist ][:mat][ "21"] = 1.000
+ @@data[WOOD5][ :bad][:rimjoist ][:mat]["172"] = 0.250
+ @@data[WOOD5][ :bad][:parapet ][:mat][ "0"] = 1.000
+ @@data[WOOD5][ :bad][:head ][:mat][ "0"] = 1.000
+ @@data[WOOD5][ :bad][:jamb ][:mat][ "0"] = 1.000
+ @@data[WOOD5][ :bad][:sill ][:mat][ "0"] = 1.000
+ @@data[WOOD5][ :bad][:corner ][:mat][ "0"] = 1.000
+ @@data[WOOD5][ :bad][:balcony ][:mat][ ""] = 1.000
+ @@data[WOOD5][ :bad][:party ][:mat][ ""] = 1.000
+ @@data[WOOD5][ :bad][:grade ][:mat][ "21"] = 1.000
+ @@data[WOOD5][ :bad][:grade ][:mat]["139"] = 0.500
+ @@data[WOOD5][ :bad][:joint ][:mat][ ""] = 1.000
+ @@data[WOOD5][ :bad][:transition ][:mat][ ""] = 1.000
@@data[WOOD5][:good][:id ] = WOOD5_GOOD
- # @@data[WOOD5][:good][:rimjoist ][:mat]["189"] = 1.000
- # @@data[WOOD5][:good][:rimjoist ][:mat]["172"] = 0.500
- # @@data[WOOD5][:good][:parapet ][:mat]["190"] = 0.500
- # @@data[WOOD5][:good][:head ][:mat][ "0"] = 1.000
- # @@data[WOOD5][:good][:jamb ][:mat][ "0"] = 1.000
- # @@data[WOOD5][:good][:sill ][:mat][ "0"] = 1.000
- # @@data[WOOD5][:good][:corner ][:mat][ "0"] = 1.000
- # @@data[WOOD5][:good][:balcony ][:mat][ ""] = 1.000
- # @@data[WOOD5][:good][:party ][:mat][ ""] = 1.000
- # @@data[WOOD5][:good][:grade ][:mat]["189"] = 1.000
- # @@data[WOOD5][:good][:grade ][:mat]["139"] = 0.500
- # @@data[WOOD5][:good][:grade ][:mat]["192"] = 0.500
- # @@data[WOOD5][:good][:joint ][:mat][ ""] = 1.000
- # @@data[WOOD5][:good][:transition ][:mat][ ""] = 1.000
+ @@data[WOOD5][:good][:rimjoist ][:mat]["189"] = 1.000
+ @@data[WOOD5][:good][:rimjoist ][:mat]["172"] = 0.500
+ @@data[WOOD5][:good][:parapet ][:mat]["190"] = 0.500
+ @@data[WOOD5][:good][:head ][:mat][ "0"] = 1.000
+ @@data[WOOD5][:good][:jamb ][:mat][ "0"] = 1.000
+ @@data[WOOD5][:good][:sill ][:mat][ "0"] = 1.000
+ @@data[WOOD5][:good][:corner ][:mat][ "0"] = 1.000
+ @@data[WOOD5][:good][:balcony ][:mat][ ""] = 1.000
+ @@data[WOOD5][:good][:party ][:mat][ ""] = 1.000
+ @@data[WOOD5][:good][:grade ][:mat]["189"] = 1.000
+ @@data[WOOD5][:good][:grade ][:mat]["139"] = 0.500
+ @@data[WOOD5][:good][:grade ][:mat]["192"] = 0.500
+ @@data[WOOD5][:good][:joint ][:mat][ ""] = 1.000
+ @@data[WOOD5][:good][:transition ][:mat][ ""] = 1.000
@@data[WOOD7][ :bad][:id ] = WOOD7_BAD
- # @@data[WOOD7][ :bad][:rimjoist ][:mat][ "21"] = 1.000
- # @@data[WOOD7][ :bad][:rimjoist ][:mat]["172"] = 0.250
- # @@data[WOOD7][ :bad][:parapet ][:mat][ "0"] = 1.000
- # @@data[WOOD7][ :bad][:head ][:mat][ "0"] = 1.000
- # @@data[WOOD7][ :bad][:jamb ][:mat][ "0"] = 1.000
- # @@data[WOOD7][ :bad][:sill ][:mat][ "0"] = 1.000
- # @@data[WOOD7][ :bad][:corner ][:mat][ "0"] = 1.000
- # @@data[WOOD7][ :bad][:balcony ][:mat][ ""] = 1.000
- # @@data[WOOD7][ :bad][:party ][:mat][ ""] = 1.000
- # @@data[WOOD7][ :bad][:grade ][:mat][ "21"] = 1.000
- # @@data[WOOD7][ :bad][:grade ][:mat]["139"] = 0.500
- # @@data[WOOD7][ :bad][:joint ][:mat][ ""] = 1.000
- # @@data[WOOD7][ :bad][:transition ][:mat][ ""] = 1.000
+ @@data[WOOD7][ :bad][:rimjoist ][:mat][ "21"] = 1.000
+ @@data[WOOD7][ :bad][:rimjoist ][:mat]["172"] = 0.250
+ @@data[WOOD7][ :bad][:parapet ][:mat][ "0"] = 1.000
+ @@data[WOOD7][ :bad][:head ][:mat][ "0"] = 1.000
+ @@data[WOOD7][ :bad][:jamb ][:mat][ "0"] = 1.000
+ @@data[WOOD7][ :bad][:sill ][:mat][ "0"] = 1.000
+ @@data[WOOD7][ :bad][:corner ][:mat][ "0"] = 1.000
+ @@data[WOOD7][ :bad][:balcony ][:mat][ ""] = 1.000
+ @@data[WOOD7][ :bad][:party ][:mat][ ""] = 1.000
+ @@data[WOOD7][ :bad][:grade ][:mat][ "21"] = 1.000
+ @@data[WOOD7][ :bad][:grade ][:mat]["139"] = 0.500
+ @@data[WOOD7][ :bad][:joint ][:mat][ ""] = 1.000
+ @@data[WOOD7][ :bad][:transition ][:mat][ ""] = 1.000
@@data[WOOD7][:good][:id ] = WOOD7_GOOD
- # @@data[WOOD7][:good][:rimjoist ][:mat]["189"] = 1.000
- # @@data[WOOD7][:good][:rimjoist ][:mat]["172"] = 0.500
- # @@data[WOOD7][:good][:parapet ][:mat]["190"] = 0.500
- # @@data[WOOD7][:good][:head ][:mat][ "0"] = 1.000
- # @@data[WOOD7][:good][:jamb ][:mat][ "0"] = 1.000
- # @@data[WOOD7][:good][:sill ][:mat][ "0"] = 1.000
- # @@data[WOOD7][:good][:corner ][:mat][ "0"] = 1.000
- # @@data[WOOD7][:good][:balcony ][:mat][ ""] = 1.000
- # @@data[WOOD7][:good][:party ][:mat][ ""] = 1.000
- # @@data[WOOD7][:good][:grade ][:mat]["189"] = 1.000
- # @@data[WOOD7][:good][:grade ][:mat]["139"] = 0.500
- # @@data[WOOD7][:good][:grade ][:mat]["192"] = 0.500
- # @@data[WOOD7][:good][:joint ][:mat][ ""] = 1.000
- # @@data[WOOD7][:good][:transition ][:mat][ ""] = 1.000
+ @@data[WOOD7][:good][:rimjoist ][:mat]["189"] = 1.000
+ @@data[WOOD7][:good][:rimjoist ][:mat]["172"] = 0.500
+ @@data[WOOD7][:good][:parapet ][:mat]["190"] = 0.500
+ @@data[WOOD7][:good][:head ][:mat][ "0"] = 1.000
+ @@data[WOOD7][:good][:jamb ][:mat][ "0"] = 1.000
+ @@data[WOOD7][:good][:sill ][:mat][ "0"] = 1.000
+ @@data[WOOD7][:good][:corner ][:mat][ "0"] = 1.000
+ @@data[WOOD7][:good][:balcony ][:mat][ ""] = 1.000
+ @@data[WOOD7][:good][:party ][:mat][ ""] = 1.000
+ @@data[WOOD7][:good][:grade ][:mat]["189"] = 1.000
+ @@data[WOOD7][:good][:grade ][:mat]["139"] = 0.500
+ @@data[WOOD7][:good][:grade ][:mat]["192"] = 0.500
+ @@data[WOOD7][:good][:joint ][:mat][ ""] = 1.000
+ @@data[WOOD7][:good][:transition ][:mat][ ""] = 1.000
@@data[STEL1][ :bad][:id ] = STEL1_BAD
- # @@data[STEL1][ :bad][:rimjoist ][:mat]["139"] = 10.000
- # @@data[STEL1][ :bad][:parapet ][:mat][ "0"] = 1.000
- # @@data[STEL1][ :bad][:head ][:mat]["139"] = 0.750
- # @@data[STEL1][ :bad][:jamb ][:mat]["139"] = 0.750
- # @@data[STEL1][ :bad][:sill ][:mat]["139"] = 0.750
- # @@data[STEL1][ :bad][:corner ][:mat][ "0"] = 1.000
- # @@data[STEL1][ :bad][:balcony ][:mat][ ""] = 1.000
- # @@data[STEL1][ :bad][:party ][:mat][ ""] = 1.000
- # @@data[STEL1][ :bad][:grade ][:mat]["139"] = 1.000
- # @@data[STEL1][ :bad][:joint ][:mat][ ""] = 1.000
- # @@data[STEL1][ :bad][:transition ][:mat][ ""] = 1.000
+ @@data[STEL1][ :bad][:rimjoist ][:mat]["139"] = 10.000
+ @@data[STEL1][ :bad][:parapet ][:mat][ "0"] = 1.000
+ @@data[STEL1][ :bad][:head ][:mat]["139"] = 0.750
+ @@data[STEL1][ :bad][:jamb ][:mat]["139"] = 0.750
+ @@data[STEL1][ :bad][:sill ][:mat]["139"] = 0.750
+ @@data[STEL1][ :bad][:corner ][:mat][ "0"] = 1.000
+ @@data[STEL1][ :bad][:balcony ][:mat][ ""] = 1.000
+ @@data[STEL1][ :bad][:party ][:mat][ ""] = 1.000
+ @@data[STEL1][ :bad][:grade ][:mat]["139"] = 1.000
+ @@data[STEL1][ :bad][:joint ][:mat][ ""] = 1.000
+ @@data[STEL1][ :bad][:transition ][:mat][ ""] = 1.000
@@data[STEL1][:good][:id ] = STEL1_GOOD
- # @@data[STEL1][:good][:rimjoist ][:mat]["172"] = 0.500
- # @@data[STEL1][:good][:parapet ][:mat][ "57"] = 3.300
- # @@data[STEL1][:good][:parapet ][:mat]["139"] = 1.000
- # @@data[STEL1][:good][:head ][:mat]["139"] = 0.500
- # @@data[STEL1][:good][:jamb ][:mat]["139"] = 0.500
- # @@data[STEL1][:good][:sill ][:mat]["139"] = 0.500
- # @@data[STEL1][:good][:corner ][:mat][ "0"] = 1.000
- # @@data[STEL1][:good][:balcony ][:mat][ ""] = 1.000
- # @@data[STEL1][:good][:party ][:mat][ ""] = 1.000
- # @@data[STEL1][:good][:grade ][:mat]["192"] = 1.000
- # @@data[STEL1][:good][:grade ][:mat]["139"] = 1.000
- # @@data[STEL1][:good][:joint ][:mat][ ""] = 1.000
- # @@data[STEL1][:good][:transition ][:mat][ ""] = 1.000
+ @@data[STEL1][:good][:rimjoist ][:mat]["172"] = 0.500
+ @@data[STEL1][:good][:parapet ][:mat][ "57"] = 3.300
+ @@data[STEL1][:good][:parapet ][:mat]["139"] = 1.000
+ @@data[STEL1][:good][:head ][:mat]["139"] = 0.500
+ @@data[STEL1][:good][:jamb ][:mat]["139"] = 0.500
+ @@data[STEL1][:good][:sill ][:mat]["139"] = 0.500
+ @@data[STEL1][:good][:corner ][:mat][ "0"] = 1.000
+ @@data[STEL1][:good][:balcony ][:mat][ ""] = 1.000
+ @@data[STEL1][:good][:party ][:mat][ ""] = 1.000
+ @@data[STEL1][:good][:grade ][:mat]["192"] = 1.000
+ @@data[STEL1][:good][:grade ][:mat]["139"] = 1.000
+ @@data[STEL1][:good][:joint ][:mat][ ""] = 1.000
+ @@data[STEL1][:good][:transition ][:mat][ ""] = 1.000
@@data[STEL2][ :bad][:id ] = STEL2_BAD
- # @@data[STEL2][ :bad][:rimjoist ][:mat]["139"] = 10.000
- # @@data[STEL2][ :bad][:parapet ][:mat][ "0"] = 1.000
- # @@data[STEL2][ :bad][:head ][:mat]["139"] = 0.750
- # @@data[STEL2][ :bad][:jamb ][:mat]["139"] = 0.750
- # @@data[STEL2][ :bad][:sill ][:mat]["139"] = 0.750
- # @@data[STEL2][ :bad][:corner ][:mat][ "0"] = 1.000
- # @@data[STEL2][ :bad][:balcony ][:mat][ ""] = 1.000
- # @@data[STEL2][ :bad][:party ][:mat][ ""] = 1.000
- # @@data[STEL2][ :bad][:grade ][:mat]["139"] = 1.000
- # @@data[STEL2][ :bad][:joint ][:mat][ ""] = 1.000
- # @@data[STEL2][ :bad][:transition ][:mat][ ""] = 1.000
+ @@data[STEL2][ :bad][:rimjoist ][:mat]["139"] = 10.000
+ @@data[STEL2][ :bad][:parapet ][:mat][ "0"] = 1.000
+ @@data[STEL2][ :bad][:head ][:mat]["139"] = 0.750
+ @@data[STEL2][ :bad][:jamb ][:mat]["139"] = 0.750
+ @@data[STEL2][ :bad][:sill ][:mat]["139"] = 0.750
+ @@data[STEL2][ :bad][:corner ][:mat][ "0"] = 1.000
+ @@data[STEL2][ :bad][:balcony ][:mat][ ""] = 1.000
+ @@data[STEL2][ :bad][:party ][:mat][ ""] = 1.000
+ @@data[STEL2][ :bad][:grade ][:mat]["139"] = 1.000
+ @@data[STEL2][ :bad][:joint ][:mat][ ""] = 1.000
+ @@data[STEL2][ :bad][:transition ][:mat][ ""] = 1.000
@@data[STEL2][:good][:id ] = STEL2_GOOD
- # @@data[STEL2][:good][:rimjoist ][:mat]["172"] = 0.500
- # @@data[STEL2][:good][:parapet ][:mat]["206"] = 1.000
- # @@data[STEL2][:good][:head ][:mat]["139"] = 0.500
- # @@data[STEL2][:good][:jamb ][:mat]["139"] = 0.500
- # @@data[STEL2][:good][:sill ][:mat]["139"] = 0.500
- # @@data[STEL2][:good][:corner ][:mat][ "0"] = 1.000
- # @@data[STEL2][:good][:balcony ][:mat][ ""] = 1.000
- # @@data[STEL2][:good][:party ][:mat][ ""] = 1.000
- # @@data[STEL2][:good][:grade ][:mat]["192"] = 1.000
- # @@data[STEL2][:good][:grade ][:mat]["139"] = 1.000
- # @@data[STEL2][:good][:joint ][:mat][ ""] = 1.000
- # @@data[STEL2][:good][:transition ][:mat][ ""] = 1.000
+ @@data[STEL2][:good][:rimjoist ][:mat]["172"] = 0.500
+ @@data[STEL2][:good][:parapet ][:mat]["206"] = 1.000
+ @@data[STEL2][:good][:head ][:mat]["139"] = 0.500
+ @@data[STEL2][:good][:jamb ][:mat]["139"] = 0.500
+ @@data[STEL2][:good][:sill ][:mat]["139"] = 0.500
+ @@data[STEL2][:good][:corner ][:mat][ "0"] = 1.000
+ @@data[STEL2][:good][:balcony ][:mat][ ""] = 1.000
+ @@data[STEL2][:good][:party ][:mat][ ""] = 1.000
+ @@data[STEL2][:good][:grade ][:mat]["192"] = 1.000
+ @@data[STEL2][:good][:grade ][:mat]["139"] = 1.000
+ @@data[STEL2][:good][:joint ][:mat][ ""] = 1.000
+ @@data[STEL2][:good][:transition ][:mat][ ""] = 1.000
+ # --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --- #
##
# Retrieve TBD building/space type keyword.
#
# @param spacetype [String] NECB (or other) building/space type
# @param stories [Integer] number of building stories
#
# @return [Symbol] matching TBD keyword (:office if failure)
- def sptype(spacetype = "", stories = 999)
- tp = spacetype.downcase
+ def spacetype(sptype = "", stories = 999)
+ tp = sptype.downcase
typ = :office
return typ unless stories.is_a?(Integer) && stories.between?(1,999)
typ = :exercise if tp.include?("exercise" )
@@ -1170,28 +1178,70 @@
end
##
# Retrieve building/space type-specific assembly/construction.
#
- # @param spacetype [Symbol] BTAP/TBD spacetype
- # @param stype [Symbol] :walls, :floors or :roofs
- # @param performance [Symbol] :lp (low-) or :hp (high-performance)
+ # @param sptype [Symbol] BTAP/TBD spacetype
+ # @param stypes [Symbol] :walls, :floors or :roofs
+ # @param perform [Symbol] :lp (low-) or :hp (high-performance)
#
# @return [String] corresponding BTAP construction (STEL2 if fail)
- def assembly(spacetype = :office, stype = :walls, performance = :hp)
- return FLOOR if stype == :floors
- return ROOFS if stype == :roofs
+ def assembly(sptype = :office, stypes = :walls, perform = :hp)
+ return FLOOR if stypes == :floors
+ return ROOFS if stypes == :roofs
@@data.each do |id, construction|
- next unless construction.key?(performance)
- return id if construction[:sptypes].key?(spacetype)
+ next unless construction.key?(perform)
+ return id if construction[:sptypes].key?(sptype)
end
STEL2
end
##
+ # Retrieve nearest building/space type-specific assembly Uo factor.
+ #
+ # @param construction [String] BTAP construction identifier
+ # @param uo [Double] target Uo in W/m2.K
+ #
+ # @return [Double] costed BTAP construction Uo factor (nil if fail)
+ def costed_uo(construction = STEL2, uo = UMAX)
+ construction = STEL2 unless @@data.key?(construction)
+ uo = UMAX unless uo.is_a?(Numeric) && uo.between?(UMIN, UMAX)
+
+ @@data[construction][:uos].keys.each do |u|
+ val = u.to_f / 1000
+ return nil unless val.is_a?(Numeric) && val.between?(UMIN, UMAX)
+ return val if val < uo || (val - uo).abs < 0.001
+ end
+
+ nil
+ end
+
+ ##
+ # Retrieve lowest building/space type-specific assembly Uo factor.
+ #
+ # @param construction [String] BTAP construction identifier
+ #
+ # @return [Double] lowest costed BTAP construction Uo factor (nil if fail)
+ def lowest_uo(construction = STEL2)
+ uos = []
+ construction = STEL2 unless @@data.key?(construction)
+
+ @@data[construction][:uos].keys.each do |u|
+ val = u.to_f / 1000
+ return nil unless val.is_a?(Numeric) && val.between?(UMIN, UMAX)
+
+ uos << val
+ end
+
+ return uos.min unless uos.empty?
+
+ nil
+ end
+
+ ##
# Retrieve assembly-specific PSI factor set.
#
# @param assembly [String] BTAP/TBD wall construction
# @param quality [Symbol] BTAP/TBD PSI quality (:bad or :good)
#
@@ -1233,10 +1283,11 @@
def self.extended(base)
base.send(:include, self)
end
end
+ # ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- #
class BTAP::Bridging
extend BridgingData
TOL = TBD::TOL
TOL2 = TBD::TOL2
@@ -1264,20 +1315,22 @@
@model = {}
@tally = {}
@feedback = { logs: [] }
lgs = @feedback[:logs]
+ argh[:interpolate] = false unless argh.key?(:interpolate)
+
# BTAP generates free-floating, unoccupied spaces (e.g. attics) as
# 'indirectly conditioned', rather than 'unconditioned' (e.g. vented
# attics). For instance, all outdoor-facing sloped roof surfaces of an
# attic in BTAP are insulated, while attic floors remain uninsulated. BTAP
# adds to the thermal zone of each unoccupied space a thermostat without
- # referecing heating and/or cooling setpoint schedule objects. These
+ # referencing heating and/or cooling setpoint schedule objects. These
# conditions do not meet TBD's internal 'plenum' logic/check (which is
# based on OpenStudio-Standards), and so TBD ends up tagging such spaces
# as unconditioned. Consequently, TBD attempts to up/de-rate attic floors
- # - not sloped roof surfaces. The original BTAP solution will undoubtedly
+ # - not sloped roof surfaces. The upstream BTAP solution will undoubtedly
# need revision. In the meantime, and in an effort to harmonize TBD with
# BTAP's current approach, an OpenStudio model may be temporarily
# modified prior to TBD processes, ensuring that each attic space is
# temporarily mistaken as a conditioned plenum. The return variable of the
# following method is a Hash holding temporarily-modified spaces,
@@ -1287,39 +1340,38 @@
# Populate BTAP/TBD inputs with BTAP & OpenStudio model parameters,
# which returns 'true' if successful. Check @feedback logs if failure to
# populate (e.g. invalid argument hash, invalid OpenStudio model).
return unless self.populate(model, argh)
- # Initialize loop counters, controls and flags.
- initial = true
- comply = false
- redflag = false
- perform = :lp # Low-performance wall constructions
- quality = :bad # default PSI factors - BTAP users can reset to :good
- quality = :good if argh.key?(:quality) && argh[:quality] == :good
- combo = "#{perform.to_s}_#{quality.to_s}".to_sym # e.g. :lp_bad
- args = {} # initialize native TBD arguments
+ # Initialize loop controls and flags.
+ initial = true
+ complies = false
+ comply = {} # specific to :walls, :floors & :roofs
+ perform = :lp # Low-performance wall constructions (revise, TO-DO ...)
+ quality = :bad # default PSI factors - BTAP users can reset to :good
+ quality = :good if argh.key?(:quality) && argh[:quality] == :good
+ combo = "#{perform.to_s}_#{quality.to_s}".to_sym # e.g. :lp_bad
+ args = {} # initialize native TBD arguments
- # If uprating, initialize native TBD args.
+ # Initialize surface types & native TBD args (if uprating).
[:walls, :floors, :roofs].each do |stypes|
- next if @model[stypes].empty?
+ next if @model[stypes].empty?
next unless argh.key?(stypes)
next unless argh[stypes].key?(:ut)
- ut = argh[stypes][:ut]
- ok = ut.is_a?(Numeric) && ut.between?(UMIN, UMAX)
- lgs << "Invalid BTAP/TBD #{stypes} Ut" unless ok
- next unless ok
-
stype = stypes.to_s.chop
uprate = "uprate_#{stypes.to_s}".to_sym
option = "#{stype}_option".to_sym
ut = "#{stype}_ut".to_sym
- args[uprate] = true
- args[option] = "ALL #{stype} constructions"
- args[ut ] = ut
+ args[uprate ] = true
+ args[option ] = "ALL #{stype} constructions"
+ args[ut ] = argh[stypes][:ut]
+
+ comply[stypes] = false
+
+ @model[:constructions] = {} unless @model.key?(:constructions)
end
args[:io_path] = @model[combo] # contents of a "tbd.json" file
args[:option ] = "" # safeguard
@@ -1337,224 +1389,143 @@
perform = :hp
quality = :bad
combo = "#{perform.to_s}_#{quality.to_s}".to_sym
args[:io_path] = @model[combo]
end
+
+ # Delete previously-generated TBD args Uo key/value pairs.
+ [:walls, :floors, :roofs].each do |stypes|
+ next unless comply.key?(stypes)
+
+ uo = "#{stypes.to_s.chop}_uo".to_sym
+ args.delete(uo) if args.key?(uo)
+ end
+
+ # Reset previous @model constructions.
+ @model.delete(:constructions) if @model.key?(:constructions)
+ @model[:constructions] = {}
end
- # Run TBD on cloned OpenStudio models until compliant.
+ # Run TBD on cloned OpenStudio model - compliant combo?
mdl = OpenStudio::Model::Model.new
mdl.addObjects(model.toIdfFile.objects)
TBD.clean!
res = TBD.process(mdl, args)
- if TBD.status.zero?
- comply = true
- else
- # TBD logs warnings and non/fatal errors when 'processing'
- # OpenStudio models, often when faced with invalid OpenStudio
- # objects that may not be necessarily flagged by OpenStudio
- # Standards and/or by BTAP. Examples could include subsurfaces not
- # fitting neatly within a host surface, (slight) overlaps between
- # subsurfaces, 5-sided windows, and so on. TBD typically logs such
- # non-fatal errors, ignores the faulty object, and otherwise pursues
- # its calculations. It would usually be up to BTAP users to decide
- # how to proceed when faced with most non-fatal errors. However,
- # when it comes ultimately to failed attempts by TBD to 'uprate'
- # constructions of an OpenStudio model for NECB compliance, BTAP
- # should definitely skip to the next loop iteration.
- unable = false
-
- TBD.logs.each do |log|
- break if unable
-
- unable = log[:message].include?("Unable to uprate ")
- break if unable
-
- unable = log[:message].include?("Can't uprate " )
- end
-
- if unable
- # puts # TEMPORARY for debugging
- # puts "¨¨¨ combo : #{combo}"
- # puts args[:io_path][:psis]
- # TBD.logs.each { |lg| puts lg }
- # puts
- else
- comply = true
- end
+ # Halt all processes if fatal errors raised by TBD (e.g. badly formatted
+ # TBD arguments, poorly-structured OpenStudio models).
+ if TBD.fatal?
+ TBD.logs.each { |lg| lgs << lg[:message] if lg[:level] == TBD::FTL }
+ break
end
- if comply
- # Not completely out of the woods yet for uprated cases. Despite
- # having TBD identify a winning combination, determine if BTAP holds
- # admissible Uo values (see lines ~245, :uos key). If TBD-estimated
- # Uo is lower than any of these admissible BTAP Uo factors, then no
- # commercially available solution has been identified. Reset "comply"
- # to "false", and loop again (until TBD-reported Uo is above or equal
- # to any of the BTAP Uo factors). This needs revisiting once BTAP
- # enables building-type construction selection.
- [:walls, :floors, :roofs].each do |stypes|
- break unless comply
- next if @model[stypes].empty?
- next unless argh.key?(stypes)
- next unless argh[stypes].key?(:ut)
+ complies = true
+ # Check if TBD-uprated Uo factors are valid: TBD args Hash holds (new)
+ # uprated Uo keys/values for :walls, :floors AND/OR :roofs if uprating
+ # is successful. In most cases, uprating tends to fail for wall
+ # constructions rather than roof or floor constructions, due to the
+ # typically larger density of linear thermal bridging per surface type
+ # area. Yet even if all constructions were successfully uprated by TBD,
+ # one must then determine if BTAP holds admissible (i.e. costed)
+ # assembly variants with corresponding Uo factors (see :uos key). If
+ # TBD-uprated Uo factors are lower than any of these admissible BTAP Uo
+ # factors, then no commercially available solution can been identified.
+ [:walls, :floors, :roofs].each do |stypes|
+ next unless comply.key?(stypes) # true only if uprating
- ut = argh[stypes][:ut]
- stype_uo = "#{stypes.to_s.chop}_uo".to_sym
+ stype_uo = "#{stypes.to_s.chop}_uo".to_sym
+ target = nil # uprated Uo (if successful)
+ target = args[stype_uo] if args.key?(stype_uo) # ... may be nil
- # If successul, TBD adds a building-wide uprated Uo factor to its
- # native input arguments, e.g. "walls_uo". Reject if missing.
- comply = false unless args.key?(stype_uo)
- break unless args.key?(stype_uo)
+ comply[stypes] = true
- # Safeguard. TBD should never generate uprated Uo > required Ut.
- ok = args[stype_uo] < ut || (args[stype_uo] - ut).abs < 0.001
- comply = false unless ok
- break unless ok
+ @model[stypes].each do |id, surface|
+ next unless surface.key?(:sptype)
- # Check if within range of BTAP commercially-available options, for:
- # - walls, floors & roofs
- # - specific to each space type
- @model[:sptypes].each do |id, spacetype|
- uo_sptype = nil
- break unless comply
- next unless spacetype.key?(stypes)
- next unless spacetype[stypes].key?(perform) # :lp or :hp
+ sptype = surface[:sptype] # e.g. :office
+ next unless @model[:sptypes].key?(sptype)
+ next unless @model[:sptypes][sptype].key?(stypes)
+ next unless @model[:sptypes][sptype][stypes].key?(perform)
- construction = spacetype[stypes][perform]
- next unless @@data.key?(construction)
- next unless @@data[construction].key?(:uos)
+ construction = @model[:sptypes][sptype][stypes][perform]
+ uo = nil
+ ok = true
+ uo = self.costed_uo(construction, target) if target
+ ok = false if uo.nil?
+ uo = target if ok && argh[:interpolate]
+ uo = self.lowest_uo(construction) unless ok # fallback
+ comply[stypes] = false unless ok
- # puts
- # puts "required Uo for #{id} #{stypes}: #{args[stype_uo]}"
- # puts
+ unless @model[:constructions].key?(construction)
+ @model[:constructions][construction] = {}
+ @model[:constructions][construction][:stypes ] = stypes
+ @model[:constructions][construction][:uo ] = uo
+ @model[:constructions][construction][:compliant] = ok
+ @model[:constructions][construction][:surfaces ] = {}
+ end
- @@data[construction][:uos].keys.each do |u|
- uo = u.to_f / 1000
- ok = uo < args[stype_uo] || (uo - args[stype_uo]).abs < 0.001
- next unless ok
+ face = model.getSurfaceByName(id)
+ next if face.empty?
- uo_sptype = uo # winning combo?
- @model[:constructions] = {} unless @model.key?(:constructions)
- @model[:constructions][construction] = { uo: uo }
- break
- end
-
- next unless uo_sptype.nil?
-
- comply = false
- val = format("%.3f", args[stype_uo])
- lgs << "... required Uo for #{stypes}: #{val}"
- end
+ face = face.get
+ @model[:constructions][construction][:surfaces][id] = face
end
+
+ complies = false unless comply[stypes]
end
- # Conditional break from the 'loop'.
- if comply
- break
- elsif combo == :hp_good
- # i.e. TBD's uprating features are requested, yet unable to locate
- # either a physically- or economically-plausible Uo + PSI combo.
- redflag = true
- comply = true # (temporarily) signal compliance
- lgs << "REDFLAG: no Ut-compliant TBD combo"
+ break if complies
+ # Final BTAP uprating option, yet non-compliant: TBD's uprating
+ # features are requested, yet unable to locate either a physically- or
+ # economically-plausible Uo + PSI combo for 1x or more surface types.
+ break if combo == :hp_good
+ end # of loop
- [:walls, :floors, :roofs].each do |stypes|
- next unless argh.key?(stypes)
- next unless argh[stypes].key?(:ut)
+ # Post-loop steps (if uprating).
+ [:walls, :floors, :roofs].each do |stypes|
+ next unless comply.key?(stypes) # true only if uprating
- groups = {}
- stype = stypes.to_s.chop
- uprate = "uprate_#{stypes.to_s}".to_sym
- option = "#{stype}_option".to_sym
- ut = "#{stype}_ut".to_sym
+ # Cancel uprating request before final derating.
+ stype = stypes.to_s.chop
+ uprate = "uprate_#{stypes.to_s}".to_sym
+ option = "#{stype}_option".to_sym
+ ut = "#{stype}_ut".to_sym
+ args.delete(uprate)
+ args.delete(option)
+ args.delete(ut )
- # Cancel uprating request before derating.
- args.delete(uprate)
- args.delete(option)
- args.delete(ut )
+ # Set uprated Uo factor for each BTAP 'deratable' construction.
+ @model[:constructions].each do |id, construction|
+ next unless construction.key?(:stypes )
+ next unless construction.key?(:uo )
+ next unless construction.key?(:compliant)
+ next unless construction.key?(:surfaces )
+ next unless construction[:stypes ] == stypes
+ next if construction[:surfaces].empty?
- # Group BTAP constructions based on lowest Uo factors e.g.:
- # - 0.130 for WOOD7
- # - 0.080 for STEL2
- # - 0.100 for all ROOFS
- @model[stypes].each do |id, type|
- next unless type.key?(:sptype)
-
- spacetype = type[:sptype] # e.g. :office
- next unless @model[:sptypes].key?(spacetype)
- next unless @model[:sptypes][spacetype].key?(stypes)
- next unless @model[:sptypes][spacetype][stypes].key?(perform)
-
- construction = @model[:sptypes][spacetype][stypes][perform]
- next unless @@data.key?(construction)
- next unless @@data[construction].key?(:uos)
-
- uos = []
- @@data[construction][:uos].keys.each { |u| uos << u.to_f / 1000 }
- uo = uos.min
- @model[:constructions] = {} unless @model.key?(:constructions)
- @model[:constructions][construction] = { uo: uo }
-
- exists = groups.key?(construction)
- groups[construction] = { uo: uo, faces: [] } unless exists
- surface = model.getSurfaceByName(id)
- next if surface.empty?
-
- groups[construction][:faces] << surface.get
- end
-
- groups.each do |id, group|
- # puts
- # puts "#{id} : #{stypes} : #{group[:uo]}: #{group[:faces].size}x"
- # group[:faces].each { |s| puts s.nameString }
- sss = BTAP::Geometry::Surfaces.set_surfaces_construction_conductance(group[:faces], group[:uo])
- # puts
- #
- # sss.each do |ssss|
- # lc = ssss.construction.get.to_LayeredConstruction.get
- # usi = 1 / TBD.rsi(lc, ssss.filmResistance)
- # puts "#{ssss.construction.get.nameString} : #{usi}"
- # end
- #
- # puts "~~~~~~~~~~"
- # puts
- end
- end
-
- comply = true # temporary
- break
+ BTAP::Geometry::Surfaces.set_surfaces_construction_conductance(construction[:surfaces].values, construction[:uo])
end
end
- @model[:comply ] = comply
- @model[:perform] = perform
- @model[:quality] = quality
- @model[:combo ] = combo
+ @model[:comply ] = comply
+ @model[:complies] = complies
+ @model[:perform ] = perform
+ @model[:quality ] = quality
+ @model[:combo ] = combo
- if comply
- # Run "process" TBD (with last generated args Hash) one last time on
- # "model" (not cloned "mdl"). This may uprate (if applicable ... unless
- # redflagged), then derate BTAP above-grade surface constructions before
- # simulation.
- TBD.clean!
- res = TBD.process(model, args)
+ # Run "process" TBD one last time, on "model" (not cloned "mdl").
+ TBD.clean!
+ res = TBD.process(model, args)
- # puts # TEMPORARY
- # puts args[:io_path][:psis]
- # puts
+ @model[:io ] = res[:io ] # TBD outputs (i.e. "tbd.out.json")
+ @model[:surfaces] = res[:surfaces] # TBD derated surface data
+ @model[:argh ] = argh # method argument Hash
+ @model[:args ] = args # last TBD inputs (i.e. "tbd.json")
- @model[:comply ] = false if redflag
- @model[:io ] = res[:io ] # TBD outputs (i.e. "tbd.out.json")
- @model[:surfaces] = res[:surfaces] # TBD derated surface data
- @model[:args ] = args # last TBD inputs (i.e. "tbd.json")
+ self.gen_tallies # tallies for BTAP costing
+ self.gen_feedback # log success messages for BTAP
- self.gen_tallies # tallies for BTAP costing
- self.gen_feedback # log success messages for BTAP
- end
-
self.purge_buffer_schedules(model, buffers)
end
##
# Modify BTAP-generated 'buffer zones' (e.g. attics) to ensure TBD tags
@@ -1605,11 +1576,11 @@
# zones' (e.g. attics).
#
# @param model [OpenStudio::Model::Model] a model
# @param buffers [Array] identifiers of modified buffer spaces in model
#
- # @return [Bool] true if successful
+ # @return [Boolean] true if successful
def purge_buffer_schedules(model = nil, buffers = [])
scheds = []
lgs = @feedback[:logs]
cl = OpenStudio::Model::Model
lgs << "Invalid OpenStudio model (purge)" unless model.is_a?(cl)
@@ -1690,24 +1661,16 @@
# Populate BTAP/TBD model with BTAP & OpenStudio model parameters.
#
# @param model [OpenStudio::Model::Model] a model
# @param argh [Hash] BTAP/TBD argument hash
#
- # @return [Bool] true if valid (check @feedback logs if false)
+ # @return [Boolean] true if valid (check @feedback logs if false)
def populate(model = nil, argh = {})
- lgs = @feedback[:logs]
cl = OpenStudio::Model::Model
args = { option: "(non thermal bridging)" } # for initial TBD dry run
+ lgs = @feedback[:logs]
- # Pre-TBD BTAP validatation.
- lgs << "Invalid BTAP/TBD feedback" unless @feedback.is_a?(Hash)
- lgs << "Missing BTAP/TBD logs" unless @feedback.key?(:logs)
- lgs << "Invalid BTAP/TBD logs" unless @feedback[:logs].is_a?(Array)
- return false unless @feedback.is_a?(Hash)
- return false unless @feedback.key?(:logs)
- return false unless @feedback[:logs].is_a?(Array)
-
lgs << "Invalid OpenStudio model to de/up-rate" unless model.is_a?(cl)
lgs << "Invalid BTAP/TBD argument Hash" unless argh.is_a?(Hash)
lgs << "Empty BTAP/TBD argument hash" if argh.empty?
return false unless model.is_a?(cl)
return false unless argh.is_a?(Hash)
@@ -1722,11 +1685,11 @@
@model[:stories] = 1 if stories < 1
@model[:stories] = 999 if stories > 999
@model[:spaces ] = {}
@model[:sptypes] = {}
- # Run TBD on cloned OpenStudio models (dry run).
+ # Run TBD on a cloned OpenStudio model (dry run).
mdl = OpenStudio::Model::Model.new
mdl.addObjects(model.toIdfFile.objects)
TBD.clean!
res = TBD.process(mdl, args)
surfaces = res[:surfaces]
@@ -1752,28 +1715,28 @@
stypes = :walls if surface[:type] == :wall
stypes = :floors if surface[:type] == :floor
stypes = :roofs if surface[:type] == :ceiling
next unless stypes == :walls || stypes == :floors || stypes == :roofs
- space = surface[:space].nameString
- spacetype = surface[:stype].nameString if surface.key?(:stype)
- spacetype = "" unless surface.key?(:stype)
- typ = self.sptype(spacetype, @model[:stories]) # e.g. :office
+ space = surface[:space].nameString
+ sptype = surface[:stype].nameString if surface.key?(:stype)
+ sptype = "" unless surface.key?(:stype)
+ typ = self.spacetype(sptype, @model[:stories]) # e.g. :office
# Keep track of individual surface's space and spacetype keyword.
@model[stypes][id] = {}
@model[stypes][id][:space ] = space
@model[stypes][id][:sptype] = typ
# Keep track of individual spaces and spacetypes.
exists = @model[:spaces].key?(space)
- @model[:spaces][space] = {} unless exists
- @model[:spaces][space][:sptype] = typ unless exists
+ @model[:spaces][space] = {} unless exists
+ @model[:spaces][space][:sptype] = typ unless exists
exists = @model[:sptypes].key?(typ)
- @model[:sptypes][typ ] = {} unless exists
- @model[:sptypes][typ ][:sptype] = spacetype unless exists
+ @model[:sptypes][typ ] = {} unless exists
+ @model[:sptypes][typ ][:sptype] = sptype unless exists
next if @model[:sptypes][typ].key?(stypes)
# Low- vs Hi-Performance BTAP assemblies.
lo = self.assembly(typ, stypes, :lp)
hi = self.assembly(typ, stypes, :hp)
@@ -1787,38 +1750,31 @@
@model[:sptypes][typ][:lp_good] = self.set(lo, :good)
@model[:sptypes][typ][:hp_bad ] = self.set(hi, :bad )
@model[:sptypes][typ][:hp_good] = self.set(hi, :good)
end
- # Post-TBD validation: BTAP-fed Uo factors, then Ut factors (optional).
+ # BTAP-fed Uo (+ optional Ut) factors.
[:walls, :floors, :roofs].each do |stypes|
lgs << "Missing BTAP/TBD #{stypes}" unless argh.key?(stypes)
lgs << "Missing BTAP/TBD #{stypes} Uo" unless argh[stypes].key?(:uo)
return false unless argh.key?(stypes)
return false unless argh[stypes].key?(:uo)
next if @model[stypes].empty?
+ uo = argh[stypes][:uo]
+ ok = uo.is_a?(Numeric) && uo.between?(UMIN, UMAX)
+ next if ok
+
uo = self.minU(model, stypes)
ok = uo.is_a?(Numeric) && uo.between?(UMIN, UMAX)
- argh[stypes][:uo] = uo if ok
- next if ok
+ lgs << "Invalid BTAP/TBD #{stypes} Uo" unless ok
+ return false unless ok
- lgs << "Invalid BTAP/TBD #{stypes} Uo"
- return false
- end
-
- [:walls, :floors, :roofs].each do |stypes| # Ut optional
+ argh[stypes][:uo] = uo
next unless argh[stypes].key?(:ut)
- next if @model[stypes].empty?
- ut = self.minU(model, stypes)
- ok = ut.is_a?(Numeric) && ut.between?(UMIN, UMAX)
- argh[stypes][:ut] = ut if ok
- next if ok
-
- lgs << "Invalid BTAP #{stypes} Ut"
- return false
+ argh[stypes][:ut] = uo
end
# Generate native TBD input Hashes for the model, for both :good & :bad
# PSI factor sets. The typical TBD use case involves writing out the
# contents of either Hash (e.g. JSON::pretty_generate) as a "tbd.json"
@@ -1830,11 +1786,11 @@
@model[:lp_bad ] = self.inputs(:lp, :bad )
@model[:lp_good] = self.inputs(:lp, :good)
@model[:hp_bad ] = self.inputs(:hp, :bad )
@model[:hp_good] = self.inputs(:hp, :good)
- @model[:osm] = model
+ @model[:osm ] = model
true
end
##
@@ -1845,11 +1801,11 @@
#
# @return [Hash] native TBD inputs
def inputs(perform = :hp, quality = :good)
input = {}
psis = {} # construction-specific PSI sets
- types = {} # space type-specific references to previous PSI sets
+ sptypes = {} # space type-specific references to previous PSI sets
perform = :hp unless perform == :lp || perform == :hp
quality = :good unless quality == :bad || quality == :good
# Once building-type construction selection is introduced within BTAP,
# define default TBD "building" PSI set. In the meantime, this is added
@@ -1860,14 +1816,14 @@
psis[ building[:id] ] = building
# Collect unique BTAP/TBD instances.
combo = "#{perform.to_s}_#{quality.to_s}".to_sym
- @model[:sptypes].values.each do |type|
- next unless type.key?(combo)
+ @model[:sptypes].values.each do |sptype|
+ next unless sptype.key?(combo)
- psi = type[combo]
+ psi = sptype[combo]
next if psis.key?(psi[:id])
psis[ psi[:id] ] = psi
end
@@ -1876,32 +1832,32 @@
input[:schema ] = schema
input[:description] = "TBD input for BTAP" # append run # ?
input[:psis ] = psis.values
- @model[:sptypes].values.each do |type|
- next unless type.key?(:sptype)
- next unless type.key?(combo)
- next if types.key?(type[:sptype])
+ @model[:sptypes].values.each do |sptype|
+ next unless sptype.key?(combo)
+ next unless sptype.key?(:sptype)
+ next if sptypes.key?(sptype[:sptype])
- types[ type[:sptype] ] = { psi: type[combo][:id] }
+ sptypes[ sptype[:sptype] ] = { psi: sptype[combo][:id] }
end
- types.each do |id, type|
+ sptypes.each do |id, sptype|
input[:spacetypes] = [] unless input.key?(:spacetypes)
- input[:spacetypes] << { id: id, psi: type[:psi] }
+ input[:spacetypes] << { id: id, psi: sptype[:psi] }
end
input[:building] = { psi: building[:id] }
input
end
##
# Generate BTAP/TBD tallies
#
- # @return [Bool] true if BTAP/TBD tally is successful
+ # @return [Boolean] true if BTAP/TBD tally is successful
def gen_tallies
edges = {}
return false unless @model.key?(:io)
return false unless @model[:io].key?(:edges)
@@ -1929,59 +1885,61 @@
end
##
# Generate BTAP/TBD post-processing feedback.
#
- # @return [Bool] true if valid BTAP/TBD model
+ # @return [Boolean] true if valid BTAP/TBD model
def gen_feedback
lgs = @feedback[:logs]
- return false unless @model.key?(:comply)
- return false unless @model.key?(:args )
+ return false unless @model.key?(:complies) # all model constructions
+ return false unless @model.key?(:comply ) # surface type specific ...
+ return false unless @model.key?(:argh ) # BTAP/TBD inputs + ouputs
- args = @model[:args]
+ argh = @model[:argh]
- # Successfully uprated Uo (if requested).
+ # Uprating. Report first on surface types (compliant or not).
[:walls, :floors, :roofs].each do |stypes|
- break unless @model[:comply]
+ next unless @model[:comply].key?(stypes)
- stype_ut = "#{stypes.to_s.chop}_ut".to_sym
- stype_uo = "#{stypes.to_s.chop}_uo".to_sym
- next unless args.key?(stype_ut)
- next unless args.key?(stype_uo)
- next unless @model.key?(stypes)
- next if @model[stypes].empty?
+ ut = format("%.3f", argh[stypes][:ut])
+ lg = "Compliant " if @model[:comply][stypes]
+ lg = "Non-compliant " unless @model[:comply][stypes]
+ lg += "#{stypes}: Ut #{ut} W/m2.K"
+ lgs << lg
- ut = args[stype_ut]
- uo = args[stype_uo]
- next unless ut.is_a?(Numeric)
- next unless uo.is_a?(Numeric)
-
- ut = format("%.3f", ut)
- uo = format("%.3f", uo)
- lgs << "Compliant #{stypes}: Uo #{uo} vs Ut #{ut} W/m2.K"
- end
-
- # Uprating unsuccessful: report min Uo factor per construction.
- if @model.key?(:constructions)
+ # Report then on required Uo factor per construction (compliant or not).
@model[:constructions].each do |id, construction|
- break if @model[:comply]
+ next unless construction.key?(:stypes )
+ next unless construction.key?(:uo )
+ next unless construction.key?(:compliant)
+ next unless construction.key?(:surfaces )
+ next unless construction[:stypes ] == stypes
+ next if construction[:surfaces].empty?
- lgs << "Non-compliant #{id} Uo factor #{construction[:uo]} (W/K.m^2)"
+ uo = format("%.3f", construction[:uo])
+ lg = " Compliant " if construction[:compliant]
+ lg = " Non-compliant " unless construction[:compliant]
+ lg += "#{id} Uo #{uo} (W/K.m2)"
+ lgs << lg
end
end
# Summary of TBD-derated constructions.
@model[:osm].getSurfaces.each do |s|
next if s.construction.empty?
next if s.construction.get.to_LayeredConstruction.empty?
lc = s.construction.get.to_LayeredConstruction.get
- next unless lc.nameString.include?(" c tbd")
+ id = lc.nameString
+ next unless id.include?(" c tbd")
- rsi = TBD.rsi(lc, s.filmResistance)
- rsi = format("%.1f", rsi)
- lgs << "~~ '#{lc.nameString}' derated Rsi: #{rsi} (m^2.K/W)"
+ rsi = TBD.rsi(lc, s.filmResistance)
+ usi = format("%.3f", 1/rsi)
+ rsi = format("%.1f", rsi)
+ area = format("%.1f", lc.getNetArea) + " m2"
+
+ lgs << "~ '#{id}' derated Rsi: #{rsi} [Usi #{usi} x #{area}]"
end
# Log PSI factor tallies (per thermal bridge type).
if @tally.key?(:edges)
@tally[:edges].each do |type, e|
@@ -1996,23 +1954,80 @@
end
end
true
end
+
+ def get_material_quantities()
+ material_quantities = {}
+ csv = CSV.read("#{File.dirname(__FILE__)}/../../../data/inventory/thermal_bridging.csv", headers: true)
+ tally_edges = @tally[:edges].transform_keys(&:to_s)
+
+ #tally_edges = JSON.parse('{"edges":{"jamb":{"BTAP-ExteriorWall-SteelFramed-1 good":13.708557548340757},"sill":{"BTAP-ExteriorWall-SteelFramed-1 good":90.13000000000001},"head":{"BTAP-ExteriorWall-SteelFramed-1 good":90.13000000000001},"gradeconvex":{"BTAP-ExteriorWall-SteelFramed-1 good":90.4348},"parapetconvex":{"BTAP-ExteriorWall-SteelFramed-1 good":45.2174},"parapet":{"BTAP-ExteriorWall-SteelFramed-1 good":45.2174},"transition":{"BTAP-ExteriorWall-SteelFramed-1 good":71.16038874419307},"cornerconvex":{"BTAP-ExteriorWall-SteelFramed-1 good":12.1952}}}')['edges']
+ tally_edges.each do |edge_type_full, value|
+ edge_type = edge_type_full.delete_suffix('convex')
+ if ['head', 'jamb', 'sill'].include?(edge_type)
+ edge_type = 'fenestration'
+ end
+ value.each do |wall_ref_and_quality, quantity|
+ /(.*)\s(.*)/ =~ wall_ref_and_quality
+ wall_reference = $1
+ quality = $2
+
+ if wall_reference =='BTAP-ExteriorWall-SteelFramed-1'
+ wall_reference = 'BTAP-ExteriorWall-SteelFramed-2'
+ end
+
+ if edge_type == 'transition'
+ next
+ end
+
+ result = csv.find { |row| row['edge_type'] == edge_type &&
+ row['quality'] == quality &&
+ row['wall_reference'] == wall_reference
+ }
+ if result.nil?
+ puts ("#{edge_type}-#{wall_reference}-#{quality}")
+ puts "not found in tb database"
+ next
+ end
+
+ # Split
+ material_opaque_id_layers = result['material_opaque_id_layers'].split(",")
+ id_layers_quantity_multipliers = result['id_layers_quantity_multipliers'].split(",")
+
+ material_opaque_id_layers.zip(id_layers_quantity_multipliers).each do |id, scale|
+ if material_quantities[id].nil? then material_quantities[id] = 0.0 end
+ material_quantities[id] = material_quantities[id] + scale.to_f * quantity.to_f
+ end
+ end
+ end
+ material_opaque_id_quantities = []
+ material_quantities.each do |id,quantity|
+ material_opaque_id_quantities << { 'materials_opaque_id' => id, 'quantity' => quantity, 'domain'=> 'thermal_bridging' }
+ end
+
+ return material_opaque_id_quantities
+ end
+
+
end
+
+
end
+# ----- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----- #
# NOTE: BTAP supports Uo variants for each of the aforementioned wall
# constructions, e.g. meeting NECB2011 and NECB2015 prescriptive "Uo"
# requirements for each NECB climate zone. By definition, these Uo
# variants ignore the effects of MAJOR thermal bridging, such as
# intermediate slab edges. This does not imply that NECB2011 and NECB2015
# do not hold prescriptive requirements for MAJOR thermal bridging. There
# are indeed a handful of general, qualitative requirements (those of the
# MNECB1997) that would make NECB2011- and NECB2015-compliant buildings
# slightly better than BTAPPRE1980 "bottom-of-the-barrel" construction,
-# but lilely not any better than circa 1990s "run-of-the-mill" commercial
+# but likely not any better than circa 1990s "run-of-the-mill" commercial
# construction. Currently, BTAP does not assess the impact of MAJOR
# thermal bridging for vintages < NECB2017. But ideally it SHOULD, if the
# goal remains a fair assessment of the (relative) contribution of more
# recent NECB requirements (e.g. 2020).
@@ -2026,11 +2041,11 @@
# U factors ANYWHERE near NECB requirements, regardless of NECB vintage or
# NECB climate zone. Same for the Guide to Low Thermal Energy Demand for
# Large Buildings. The original intention was to rely on BTAP variants
# "Metal-2" and "Metal-3" as HP CW spandrels ACTUALLY achieving NECB
# prescriptive targets, which could only be possible in practice at
-# tremendous cost and effort.
+# great cost and effort (e.g. a 2nd insulated wall behind the spandrel).
#
# If TBD's uprating calculations (e.g. NECB 2017) were in theory no longer
# required, BTAP's treatment of HP CW spandrels could be implemented
# strictly as a costing adjustment: energy simulation models wouldn't have
# to be altered. Otherwise, adaptations would be required. PSI factors are
@@ -2056,32 +2071,36 @@
# - e.g. PSI factors for CW vision "jamb" transitions
# - e.g. PSI factors for CW spandrel "jamb" transitions
#
# These added features would simplify the process tremendously. Yet
# without admissible CW spandrel U factors down to 0.130 or 0.100 W/m2.K,
-# TBD's uprating features would necessarily push other wall constructions
+# TBD's uprating features would necessarily push OTHER wall constructions
# to compensate - noticeably for climate zone 7 (or colder). This would
# make it MUCH MORE difficult to identify NECB2017 or NECB2020 compliant
# combinations of Uo+PSI factors if ever HP CW spandrels were integrated
# within BTAP.
# NOTE: Some of the aforementioned constructions have exterior brick veneer.
# For 2-story OpenStudio models with punch windows (i.e. not strip
-# windows), one would NOT expect a continuous shelf angle along the
+# windows), one would NOT expect a continuous steel shelf angle along the
# intermediate floor slab edge (typically a MAJOR thermal bridge). One
# would instead expect loose lintels above punch windows, just as with
-# doors. Loose lintels usually do not constitute MAJOR thermal bridges.
+# doors. Loose lintels usually compound heat loss along window head edges,
+# but are currently considered as factored in the retained PSI factors for
+# window and door head details (a postulate that likely needs revision).
# For taller builings, shelf angles are indeed expected. And if windows
# are instead strip windows (not punch windows), then loose lintels would
# typically be cast aside in favour of an offset shelf angle (even for
# 1-story buildings).
#
# Many of the US DOE Commercial Benchmark Building and BTAP models are
-# 1-story or 2-stories in height, yet they all have strip windows as their
+# 1-story or 2-stories in height, yet they ALL have strip windows as their
# default fenestration layout. As a result, BTAP/TBD presumes continuous
# shelf angles, offset by the height difference between slab edge and
-# window head. Loose lintels (included in the clear field costing, $/m2)
-# should be limited to those above doors (TO-DO).
+# window head. Loose lintels are however included in the clear field
+# costing ($/m2), yet should be limited to doors (TO-DO). A more flexible,
+# general solution would be required for 3rd-party OpenStudio models
+# (without strip windows as a basic fenestration layout).
#
# NOTE: BTAP costing: In addition to the listed items for parapets as MAJOR
# thermal bridges (eventually generating an overall $ per linear meter),
# BTAP costing requires extending the areas (m2) of OpenStudio wall
# surfaces (along parapet edges) by 3'-6" (1.1 m) x parapet lengths, to
\ No newline at end of file