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