openstudio-standards 0.2.17.rc2 → 0.3.1.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (233) hide show
  1. checksums.yaml +4 -4
  2. data/data/geometry/ASHRAESuperMarket.json +29 -38
  3. data/data/standards/OpenStudio_Standards-deer-ALL-comstock(space_types).xlsx +0 -0
  4. data/data/standards/metadata_units_OpenStudio_Standards-deer-ALL-comstockspace_types.csv +172 -0
  5. data/data/standards/test_performance_expected_dd_results.csv +12 -12
  6. data/lib/openstudio-standards/btap/analysis.rb +389 -389
  7. data/lib/openstudio-standards/btap/bridging.rb +2099 -0
  8. data/lib/openstudio-standards/btap/btap.model.rb +717 -717
  9. data/lib/openstudio-standards/btap/btap.rb +33 -30
  10. data/lib/openstudio-standards/btap/economics.rb +1163 -1163
  11. data/lib/openstudio-standards/btap/envelope.rb +4 -4
  12. data/lib/openstudio-standards/btap/equest.rb +2524 -2524
  13. data/lib/openstudio-standards/btap/fileio.rb +9 -0
  14. data/lib/openstudio-standards/btap/measures.rb +1515 -1515
  15. data/lib/openstudio-standards/btap/mpc.rb +554 -554
  16. data/lib/openstudio-standards/btap/reporting.rb +287 -287
  17. data/lib/openstudio-standards/btap/simmanager.rb +759 -759
  18. data/lib/openstudio-standards/btap/spaceloads.rb +439 -439
  19. data/lib/openstudio-standards/btap/spacetypes.rb +113 -113
  20. data/lib/openstudio-standards/btap/utilities.rb +134 -134
  21. data/lib/openstudio-standards/hvac_sizing/Siz.AirLoopHVAC.rb +8 -83
  22. data/lib/openstudio-standards/hvac_sizing/Siz.CoilCoolingWater.rb +3 -99
  23. data/lib/openstudio-standards/hvac_sizing/Siz.HeatingCoolingFuels.rb +81 -75
  24. data/lib/openstudio-standards/hvac_sizing/Siz.Model.rb +7 -306
  25. data/lib/openstudio-standards/hvac_sizing/Siz.ThermalZone.rb +70 -98
  26. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.Model.rb +41 -14
  27. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.Model.rb +40 -14
  28. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.SuperMarket.rb +1 -23
  29. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.exterior_lights.rb +7 -7
  30. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.rb +5 -1
  31. data/lib/openstudio-standards/prototypes/common/objects/Prototype.ServiceWaterHeating.rb +101 -4
  32. data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +16 -1
  33. data/lib/openstudio-standards/prototypes/common/objects/Prototype.refrigeration.rb +5 -4
  34. data/lib/openstudio-standards/prototypes/common/objects/Prototype.utilities.rb +24 -4
  35. data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +18 -2
  36. data/lib/openstudio-standards/standards/Standards.BoilerHotWater.rb +18 -0
  37. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXSingleSpeed.rb +13 -10
  38. data/lib/openstudio-standards/standards/Standards.CoilDX.rb +5 -3
  39. data/lib/openstudio-standards/standards/Standards.CoilHeatingDXSingleSpeed.rb +11 -8
  40. data/lib/openstudio-standards/standards/Standards.Construction.rb +1 -1
  41. data/lib/openstudio-standards/standards/Standards.Model.rb +68 -52
  42. data/lib/openstudio-standards/standards/Standards.PlantLoop.rb +2 -2
  43. data/lib/openstudio-standards/standards/Standards.Space.rb +16 -18
  44. data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +1 -1
  45. data/lib/openstudio-standards/standards/Standards.WaterHeaterMixed.rb +5 -5
  46. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.ref_cases.json +510 -0
  47. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.refrigeration_compressors.json +18 -0
  48. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.refrigeration_walkins.json +410 -0
  49. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.spc_typ.json +2 -2
  50. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.ref_cases.json +510 -0
  51. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.refrigeration_compressors.json +18 -0
  52. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.refrigeration_walkins.json +410 -0
  53. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.spc_typ.json +2 -2
  54. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.ref_cases.json +510 -0
  55. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.refrigeration_compressors.json +18 -0
  56. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.refrigeration_walkins.json +410 -0
  57. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.spc_typ.json +2 -2
  58. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.ref_cases.json +510 -0
  59. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.refrigeration_compressors.json +18 -0
  60. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.refrigeration_walkins.json +410 -0
  61. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.spc_typ.json +2 -2
  62. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.spc_typ.json +2 -2
  63. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.spc_typ.json +2 -2
  64. data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.entryways.json +13 -2
  65. data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.parking.json +11 -2
  66. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb +9 -0
  67. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb +2 -0
  68. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb +4 -3
  69. data/lib/openstudio-standards/standards/deer/deer_1985/comstock_deer_1985/data/comstock_deer_1985.spc_typ.json +405 -405
  70. data/lib/openstudio-standards/standards/deer/deer_1996/comstock_deer_1996/data/comstock_deer_1996.spc_typ.json +405 -405
  71. data/lib/openstudio-standards/standards/deer/deer_2003/comstock_deer_2003/data/comstock_deer_2003.spc_typ.json +405 -405
  72. data/lib/openstudio-standards/standards/deer/deer_2003/deer_2003.ThermalZone.rb +21 -0
  73. data/lib/openstudio-standards/standards/deer/deer_2007/comstock_deer_2007/data/comstock_deer_2007.spc_typ.json +405 -405
  74. data/lib/openstudio-standards/standards/deer/deer_2007/deer_2007.ThermalZone.rb +21 -0
  75. data/lib/openstudio-standards/standards/deer/deer_2011/comstock_deer_2011/data/comstock_deer_2011.spc_typ.json +405 -405
  76. data/lib/openstudio-standards/standards/deer/deer_2011/deer_2011.ThermalZone.rb +21 -0
  77. data/lib/openstudio-standards/standards/deer/deer_2014/comstock_deer_2014/data/comstock_deer_2014.spc_typ.json +405 -405
  78. data/lib/openstudio-standards/standards/deer/deer_2014/deer_2014.ThermalZone.rb +21 -0
  79. data/lib/openstudio-standards/standards/deer/deer_2015/comstock_deer_2015/data/comstock_deer_2015.spc_typ.json +405 -405
  80. data/lib/openstudio-standards/standards/deer/deer_2015/deer_2015.ThermalZone.rb +21 -0
  81. data/lib/openstudio-standards/standards/deer/deer_2017/comstock_deer_2017/data/comstock_deer_2017.spc_typ.json +405 -405
  82. data/lib/openstudio-standards/standards/deer/deer_2017/deer_2017.ThermalZone.rb +21 -0
  83. data/lib/openstudio-standards/standards/deer/deer_2020/comstock_deer_2020/data/comstock_deer_2020.spc_typ.json +405 -405
  84. data/lib/openstudio-standards/standards/deer/deer_2020/deer_2020.AirLoopHVAC.rb +8 -0
  85. data/lib/openstudio-standards/standards/deer/deer_2020/deer_2020.ThermalZone.rb +21 -0
  86. data/lib/openstudio-standards/standards/deer/deer_2025/comstock_deer_2025/data/comstock_deer_2025.spc_typ.json +405 -405
  87. data/lib/openstudio-standards/standards/deer/deer_2030/comstock_deer_2030/data/comstock_deer_2030.spc_typ.json +405 -405
  88. data/lib/openstudio-standards/standards/deer/deer_2035/comstock_deer_2035/data/comstock_deer_2035.spc_typ.json +405 -405
  89. data/lib/openstudio-standards/standards/deer/deer_2040/comstock_deer_2040/data/comstock_deer_2040.spc_typ.json +405 -405
  90. data/lib/openstudio-standards/standards/deer/deer_2045/comstock_deer_2045/data/comstock_deer_2045.spc_typ.json +405 -405
  91. data/lib/openstudio-standards/standards/deer/deer_2050/comstock_deer_2050/data/comstock_deer_2050.spc_typ.json +405 -405
  92. data/lib/openstudio-standards/standards/deer/deer_2055/comstock_deer_2055/data/comstock_deer_2055.spc_typ.json +405 -405
  93. data/lib/openstudio-standards/standards/deer/deer_2060/comstock_deer_2060/data/comstock_deer_2060.spc_typ.json +405 -405
  94. data/lib/openstudio-standards/standards/deer/deer_2065/comstock_deer_2065/data/comstock_deer_2065.spc_typ.json +405 -405
  95. data/lib/openstudio-standards/standards/deer/deer_2070/comstock_deer_2070/data/comstock_deer_2070.spc_typ.json +405 -405
  96. data/lib/openstudio-standards/standards/deer/deer_2075/comstock_deer_2075/data/comstock_deer_2075.spc_typ.json +405 -405
  97. data/lib/openstudio-standards/standards/deer/deer_pre_1975/comstock_deer_pre_1975/data/comstock_deer_pre_1975.spc_typ.json +405 -405
  98. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/btap_pre1980.rb +1 -1
  99. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_3_and_8_single_speed.rb +3 -1
  100. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_4.rb +3 -1
  101. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_6.rb +2 -2
  102. data/lib/openstudio-standards/standards/necb/ECMS/data/curves.json +233 -0
  103. data/lib/openstudio-standards/standards/necb/ECMS/data/unitary_acs.json +180 -0
  104. data/lib/openstudio-standards/standards/necb/ECMS/ecms.rb +6 -1
  105. data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +807 -258
  106. data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +102 -66
  107. data/lib/openstudio-standards/standards/necb/NECB2011/data/fuel_type_sets.json +85 -8
  108. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/HighriseApartment.osm +2483 -992
  109. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LowriseApartment.osm +4 -336
  110. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/MidriseApartment.osm +228 -231
  111. data/lib/openstudio-standards/standards/necb/NECB2011/data/heat_pumps_heating.json +12 -18
  112. data/lib/openstudio-standards/standards/necb/NECB2011/data/space_type_unit_definitions.txt +76 -0
  113. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_1_multi_speed.rb +6 -1
  114. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_1_single_speed.rb +111 -24
  115. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_2_and_5.rb +1 -0
  116. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_multi_speed.rb +3 -1
  117. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_single_speed.rb +64 -16
  118. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_4.rb +61 -17
  119. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_6.rb +128 -0
  120. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +252 -23
  121. data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +316 -20
  122. data/lib/openstudio-standards/standards/necb/NECB2011/qaqc/necb_qaqc.rb +1 -1
  123. data/lib/openstudio-standards/standards/necb/NECB2011/service_water_heating.rb +4 -6
  124. data/lib/openstudio-standards/standards/necb/NECB2011/system_fuels.rb +38 -0
  125. data/lib/openstudio-standards/standards/necb/NECB2015/data/heat_pumps_heating.json +16 -24
  126. data/lib/openstudio-standards/standards/necb/NECB2015/hvac_systems.rb +48 -25
  127. data/lib/openstudio-standards/standards/necb/NECB2020/building_envelope.rb +3 -3
  128. data/lib/openstudio-standards/standards/necb/NECB2020/data/chillers.json +36 -19
  129. data/lib/openstudio-standards/standards/necb/NECB2020/data/furnaces.json +19 -4
  130. data/lib/openstudio-standards/standards/necb/NECB2020/data/heat_pumps.json +20 -40
  131. data/lib/openstudio-standards/standards/necb/NECB2020/data/heat_pumps_heating.json +74 -36
  132. data/lib/openstudio-standards/standards/necb/NECB2020/necb_2020.rb +0 -2
  133. data/lib/openstudio-standards/standards/necb/NECB2020/service_water_heating.rb +124 -57
  134. data/lib/openstudio-standards/standards/necb/common/btap_data.rb +124 -2
  135. data/lib/openstudio-standards/standards/necb/common/btap_datapoint.rb +15 -2
  136. data/lib/openstudio-standards/standards/necb/common/necb_reference_runs.csv +1 -1
  137. data/lib/openstudio-standards/utilities/simulation.rb +1 -1
  138. data/lib/openstudio-standards/version.rb +1 -1
  139. data/lib/openstudio-standards/weather/Weather.Model.rb +5 -0
  140. data/lib/openstudio-standards/weather/Weather.stat_file.rb +33 -1
  141. data/lib/openstudio-standards.rb +1 -0
  142. metadata +14 -121
  143. data/data/standards/OpenStudio_Standards-ashrae_90_1.xlsx +0 -0
  144. data/data/weather/CAN_ON_Kingston.AP.718200_TMYx.2004-2018.ddy +0 -2342
  145. data/data/weather/CAN_ON_Kingston.AP.718200_TMYx.2004-2018.epw +0 -8768
  146. data/data/weather/CAN_ON_Kingston.AP.718200_TMYx.2004-2018.stat +0 -700
  147. data/data/weather/CAN_ON_Region.of.Waterloo.Intl.AP.713680_TMYx.2004-2018.ddy +0 -2342
  148. data/data/weather/CAN_ON_Region.of.Waterloo.Intl.AP.713680_TMYx.2004-2018.epw +0 -8768
  149. data/data/weather/CAN_ON_Region.of.Waterloo.Intl.AP.713680_TMYx.2004-2018.stat +0 -700
  150. data/data/weather/CAN_ON_Sarnia-Hadfield.AP.717040_TMYx.2004-2018.ddy +0 -2342
  151. data/data/weather/CAN_ON_Sarnia-Hadfield.AP.717040_TMYx.2004-2018.epw +0 -8768
  152. data/data/weather/CAN_ON_Sarnia-Hadfield.AP.717040_TMYx.2004-2018.stat +0 -700
  153. data/data/weather/CAN_QC_Gatineau.AP.716279_TMYx.2004-2018.ddy +0 -276
  154. data/data/weather/CAN_QC_Gatineau.AP.716279_TMYx.2004-2018.epw +0 -8768
  155. data/data/weather/CAN_QC_Gatineau.AP.716279_TMYx.2004-2018.stat +0 -611
  156. data/data/weather/CAN_QC_Granby.710367_TMYx.2004-2018.ddy +0 -276
  157. data/data/weather/CAN_QC_Granby.710367_TMYx.2004-2018.epw +0 -8768
  158. data/data/weather/CAN_QC_Granby.710367_TMYx.2004-2018.stat +0 -610
  159. data/data/weather/CAN_QC_Sherbrooke.AP.716100_TMYx.2004-2018.ddy +0 -2342
  160. data/data/weather/CAN_QC_Sherbrooke.AP.716100_TMYx.2004-2018.epw +0 -8768
  161. data/data/weather/CAN_QC_Sherbrooke.AP.716100_TMYx.2004-2018.stat +0 -700
  162. data/data/weather/CAN_QC_Trois.Rivieres.717240_TMYx.2004-2018.ddy +0 -2342
  163. data/data/weather/CAN_QC_Trois.Rivieres.717240_TMYx.2004-2018.epw +0 -8768
  164. data/data/weather/CAN_QC_Trois.Rivieres.717240_TMYx.2004-2018.stat +0 -700
  165. data/lib/openstudio-standards/hvac_sizing/Siz.AirConditionerVariableRefrigerantFlow.rb +0 -81
  166. data/lib/openstudio-standards/hvac_sizing/Siz.AirLoopHVACUnitaryHeatCoolVAVChngByp.rb +0 -27
  167. data/lib/openstudio-standards/hvac_sizing/Siz.AirLoopHVACUnitaryHeatPumpAirToAir.rb +0 -69
  168. data/lib/openstudio-standards/hvac_sizing/Siz.AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed.rb +0 -178
  169. data/lib/openstudio-standards/hvac_sizing/Siz.AirLoopHVACUnitarySystem.rb +0 -27
  170. data/lib/openstudio-standards/hvac_sizing/Siz.AirTermSnglDuctConstVolCooledBeam.rb +0 -27
  171. data/lib/openstudio-standards/hvac_sizing/Siz.AirTermSnglDuctConstVolFourPipeInduction.rb +0 -27
  172. data/lib/openstudio-standards/hvac_sizing/Siz.AirTermSnglDuctConstVolReheat.rb +0 -27
  173. data/lib/openstudio-standards/hvac_sizing/Siz.AirTermSnglDuctParallelPIUReheat.rb +0 -67
  174. data/lib/openstudio-standards/hvac_sizing/Siz.AirTermSnglDuctSeriesPIUReheat.rb +0 -27
  175. data/lib/openstudio-standards/hvac_sizing/Siz.AirTermSnglDuctUncontrolled.rb +0 -30
  176. data/lib/openstudio-standards/hvac_sizing/Siz.AirTermSnglDuctVAVHeatAndCoolNoReheat.rb +0 -27
  177. data/lib/openstudio-standards/hvac_sizing/Siz.AirTermSnglDuctVAVHeatAndCoolReheat.rb +0 -27
  178. data/lib/openstudio-standards/hvac_sizing/Siz.AirTermSnglDuctVAVNoReheat.rb +0 -68
  179. data/lib/openstudio-standards/hvac_sizing/Siz.AirTermSnglDuctVAVReheat.rb +0 -68
  180. data/lib/openstudio-standards/hvac_sizing/Siz.BoilerHotWater.rb +0 -42
  181. data/lib/openstudio-standards/hvac_sizing/Siz.BoilerSteam.rb +0 -27
  182. data/lib/openstudio-standards/hvac_sizing/Siz.ChillerElectricEIR.rb +0 -58
  183. data/lib/openstudio-standards/hvac_sizing/Siz.CoilCoolingDXMultiSpeed.rb +0 -171
  184. data/lib/openstudio-standards/hvac_sizing/Siz.CoilCoolingDXSingleSpeed.rb +0 -56
  185. data/lib/openstudio-standards/hvac_sizing/Siz.CoilCoolingDXTwoSpeed.rb +0 -89
  186. data/lib/openstudio-standards/hvac_sizing/Siz.CoilCoolingDXVariableRefrigerantFlow.rb +0 -50
  187. data/lib/openstudio-standards/hvac_sizing/Siz.CoilCoolingWaterToAirHeatPumpEquationFit.rb +0 -69
  188. data/lib/openstudio-standards/hvac_sizing/Siz.CoilHeatingDXMultiSpeed.rb +0 -120
  189. data/lib/openstudio-standards/hvac_sizing/Siz.CoilHeatingDXSingleSpeed.rb +0 -56
  190. data/lib/openstudio-standards/hvac_sizing/Siz.CoilHeatingDXVariableRefrigerantFlow.rb +0 -41
  191. data/lib/openstudio-standards/hvac_sizing/Siz.CoilHeatingDesuperheater.rb +0 -27
  192. data/lib/openstudio-standards/hvac_sizing/Siz.CoilHeatingElectric.rb +0 -30
  193. data/lib/openstudio-standards/hvac_sizing/Siz.CoilHeatingGas.rb +0 -30
  194. data/lib/openstudio-standards/hvac_sizing/Siz.CoilHeatingGasMultiStage.rb +0 -68
  195. data/lib/openstudio-standards/hvac_sizing/Siz.CoilHeatingWater.rb +0 -61
  196. data/lib/openstudio-standards/hvac_sizing/Siz.CoilHeatingWaterToAirHeatPumpEquationFit.rb +0 -57
  197. data/lib/openstudio-standards/hvac_sizing/Siz.CoilWaterHeatingDesuperheater.rb +0 -27
  198. data/lib/openstudio-standards/hvac_sizing/Siz.ControllerOutdoorAir.rb +0 -59
  199. data/lib/openstudio-standards/hvac_sizing/Siz.ControllerWaterCoil.rb +0 -49
  200. data/lib/openstudio-standards/hvac_sizing/Siz.CoolingTowerSingleSpeed.rb +0 -90
  201. data/lib/openstudio-standards/hvac_sizing/Siz.CoolingTowerTwoSpeed.rb +0 -83
  202. data/lib/openstudio-standards/hvac_sizing/Siz.CoolingTowerVariableSpeed.rb +0 -57
  203. data/lib/openstudio-standards/hvac_sizing/Siz.DistrictCooling.rb +0 -27
  204. data/lib/openstudio-standards/hvac_sizing/Siz.DistrictHeating.rb +0 -27
  205. data/lib/openstudio-standards/hvac_sizing/Siz.EvaporativeCoolerDirectResearchSpecial.rb +0 -27
  206. data/lib/openstudio-standards/hvac_sizing/Siz.EvaporativeCoolerIndirectResearchSpecial.rb +0 -27
  207. data/lib/openstudio-standards/hvac_sizing/Siz.EvaporativeFluidCoolerSingleSpeed.rb +0 -27
  208. data/lib/openstudio-standards/hvac_sizing/Siz.FanConstantVolume.rb +0 -29
  209. data/lib/openstudio-standards/hvac_sizing/Siz.FanOnOff.rb +0 -27
  210. data/lib/openstudio-standards/hvac_sizing/Siz.FanVariableVolume.rb +0 -29
  211. data/lib/openstudio-standards/hvac_sizing/Siz.HeaderedPumpsConstantSpeed.rb +0 -55
  212. data/lib/openstudio-standards/hvac_sizing/Siz.HeaderedPumpsVariableSpeed.rb +0 -55
  213. data/lib/openstudio-standards/hvac_sizing/Siz.HeatExchangerAirToAirSensibleAndLatent.rb +0 -38
  214. data/lib/openstudio-standards/hvac_sizing/Siz.HeatExchangerFluidToFluid.rb +0 -27
  215. data/lib/openstudio-standards/hvac_sizing/Siz.HumidifierSteamElectric.rb +0 -27
  216. data/lib/openstudio-standards/hvac_sizing/Siz.PlantLoop.rb +0 -42
  217. data/lib/openstudio-standards/hvac_sizing/Siz.PumpConstantSpeed.rb +0 -59
  218. data/lib/openstudio-standards/hvac_sizing/Siz.PumpVariableSpeed.rb +0 -59
  219. data/lib/openstudio-standards/hvac_sizing/Siz.SizingSystem.rb +0 -48
  220. data/lib/openstudio-standards/hvac_sizing/Siz.WaterHeaterMixed.rb +0 -16
  221. data/lib/openstudio-standards/hvac_sizing/Siz.ZoneHVACBaseboardConvectiveElectric.rb +0 -27
  222. data/lib/openstudio-standards/hvac_sizing/Siz.ZoneHVACBaseboardConvectiveWater.rb +0 -27
  223. data/lib/openstudio-standards/hvac_sizing/Siz.ZoneHVACFourPipeFanCoil.rb +0 -27
  224. data/lib/openstudio-standards/hvac_sizing/Siz.ZoneHVACHighTemperatureRadiant.rb +0 -27
  225. data/lib/openstudio-standards/hvac_sizing/Siz.ZoneHVACIdealLoadsAirSystem.rb +0 -27
  226. data/lib/openstudio-standards/hvac_sizing/Siz.ZoneHVACLowTempRadiantConstFlow.rb +0 -27
  227. data/lib/openstudio-standards/hvac_sizing/Siz.ZoneHVACLowTempRadiantVarFlow.rb +0 -27
  228. data/lib/openstudio-standards/hvac_sizing/Siz.ZoneHVACLowTemperatureRadiantElectric.rb +0 -27
  229. data/lib/openstudio-standards/hvac_sizing/Siz.ZoneHVACPackagedTerminalAirConditioner.rb +0 -88
  230. data/lib/openstudio-standards/hvac_sizing/Siz.ZoneHVACPackagedTerminalHeatPump.rb +0 -88
  231. data/lib/openstudio-standards/hvac_sizing/Siz.ZoneHVACTerminalUnitVariableRefrigerantFlow.rb +0 -104
  232. data/lib/openstudio-standards/hvac_sizing/Siz.ZoneHVACUnitHeater.rb +0 -27
  233. data/lib/openstudio-standards/hvac_sizing/Siz.ZoneHVACWaterToAirHeatPump.rb +0 -27
@@ -0,0 +1,2099 @@
1
+ # **************************************************************************** /
2
+ # * Copyright (c) 2008-2023, Natural Resources Canada
3
+ # * All rights reserved.
4
+ # *
5
+ # * This library is free software; you can redistribute it and/or
6
+ # * modify it under the terms of the GNU Lesser General Public
7
+ # * License as published by the Free Software Foundation; either
8
+ # * version 2.1 of the License, or (at your option) any later version.
9
+ # *
10
+ # * This library is distributed in the hope that it will be useful,
11
+ # * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # * Lesser General Public License for more details.
14
+ # *
15
+ # * You should have received a copy of the GNU Lesser General Public
16
+ # * License along with this library; if not, write to the Free Software
17
+ # * Foundation Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ # **************************************************************************** /
19
+
20
+ require "tbd"
21
+
22
+ module BTAP
23
+ module BridgingData
24
+ ##
25
+ # BTAP module/class for Thermal Bridging & Derating (TBD) functionality
26
+ # for linear thermal bridges, e.g. corners, balconies (rd2.github.io/tbd).
27
+ #
28
+ # @author: Denis Bourgeois
29
+
30
+ # BTAP/TBD data extracted from the BTAP costing spreadsheet:
31
+ #
32
+ # - range of clear-field Uo factors
33
+ # - range of PSI factors (i.e. MAJOR thermal bridging), e.g. corners
34
+ # - costing parameters
35
+ #
36
+ # NOTE: This module is be replaced with roo-based spreadsheet parsing,
37
+ # generating a BTAP costing JSON file. TO DO.
38
+ #
39
+ # Ref: EVOKE BTAP costing spreadsheet modifications (2022), synced with:
40
+ # - Building Envelope Thermal Bridging Guide (BETBG)
41
+ # - ASHRAE RP-1365, ISO-12011, etc.
42
+
43
+ # BTAP costing data (both original BTAP constructions and EVOKE's
44
+ # additions) hold sub-variants based on cladding/veneer, e.g.:
45
+ #
46
+ # - "BTAP-ExteriorWall-WoodFramed-5" ... brick veneer
47
+ # - "BTAP-ExteriorWall-WoodFramed-1" ... wood siding
48
+ #
49
+ # Not all of these sub-variants are currently used within BTAP, e.g.
50
+ # "BTAP-ExteriorWall-WoodFramed-1" is unused. BTAP/TBD data is limited
51
+ # to the following wall constructions (paired LP & HP variants).
52
+ #
53
+ # ---- (Basic) Low Performance (LP) assemblies
54
+ #
55
+ # ID : (layers)
56
+ # ----- ------------------------------------------
57
+ # STEL1 : cladding | board | wool | frame | gypsum
58
+ # WOOD5 : brick | board | wool | frame | gypsum
59
+ # MTAL1 : panel | xps | wool | frame | gypsum
60
+ # MASS2 : brick | xps | | cmu |
61
+ # MASS4 : precast | xps | wool | frame | gypsum
62
+ # MASS6 : brick | xps | | cmu |
63
+ #
64
+ # ---- High Performance (HP) variants
65
+ #
66
+ # ID : (layers)
67
+ # ----- ------------------------------------------
68
+ # STEL2 : cladding | board | wool | frame | gypsum
69
+ # WOOD7 : brick | mineral | wool | frame | gypsum
70
+ # MTALD : panel | polyiso | foam | frame | gypsum
71
+ # MASSB : brick | mineral | cmu | foam | gypsum
72
+ # MASS8 : precast | xps | wool | frame | gypsum
73
+ # MASSC : cladding | mineral | cmu | foam | gypsum
74
+ #
75
+ # Paired LPs vs HPs vall variants are critical for 'uprating' cases, e.g.
76
+ # NECB2017. See below, and end of this document for additional NOTES.
77
+
78
+ MASS2 = "BTAP-ExteriorWall-Mass-2" # LP wall
79
+ MASS2_BAD = "BTAP-ExteriorWall-Mass-2 bad" # LP "bad" PSI factors
80
+ MASS2_GOOD = "BTAP-ExteriorWall-Mass-2 good" # LP "good" PSI factors
81
+ MASSB = "BTAP-ExteriorWall-Mass-2b" # HP, from @Uo < 0.183
82
+ MASSB_BAD = "BTAP-ExteriorWall-Mass-2b bad" # HP "bad" PSI factors
83
+ MASSB_GOOD = "BTAP-ExteriorWall-Mass-2b good" # HP "good" PSI factors
84
+
85
+ MASS4 = "BTAP-ExteriorWall-Mass-4"
86
+ MASS4_BAD = "BTAP-ExteriorWall-Mass-4 bad"
87
+ MASS4_GOOD = "BTAP-ExteriorWall-Mass-4 good"
88
+ MASS8 = "BTAP-ExteriorWall-Mass-8c" # HP, from @Uo < 0.183
89
+ MASS8_BAD = "BTAP-ExteriorWall-Mass-8c bad"
90
+ MASS8_GOOD = "BTAP-ExteriorWall-Mass-8c good"
91
+
92
+ MASS6 = "BTAP-ExteriorWall-Mass-6"
93
+ MASS6_BAD = "BTAP-ExteriorWall-Mass-6 bad"
94
+ MASS6_GOOD = "BTAP-ExteriorWall-Mass-6 good"
95
+ MASSC = "BTAP-ExteriorWall-Mass-10c" # HP, from @Uo < 0.247
96
+ MASSC_BAD = "BTAP-ExteriorWall-Mass-10c bad"
97
+ MASSC_GOOD = "BTAP-ExteriorWall-Mass-10c good"
98
+
99
+ MTAL1 = "BTAP-ExteriorWall-Metal-1"
100
+ MTAL1_BAD = "BTAP-ExteriorWall-Metal-1 bad"
101
+ MTAL1_GOOD = "BTAP-ExteriorWall-Metal-1 good"
102
+ MTALD = "BTAP-ExteriorWall-Metal-1d" # HP, from @Uo < 0.183
103
+ MTALD_BAD = "BTAP-ExteriorWall-Metal-1d bad"
104
+ MTALD_GOOD = "BTAP-ExteriorWall-Metal-1d good"
105
+
106
+ WOOD5 = "BTAP-ExteriorWall-WoodFramed-5"
107
+ WOOD5_BAD = "BTAP-ExteriorWall-WoodFramed-5 bad"
108
+ WOOD5_GOOD = "BTAP-ExteriorWall-WoodFramed-5 good"
109
+ WOOD7 = "BTAP-ExteriorWall-WoodFramed-7" # HP, from @Uo < 0.183
110
+ WOOD7_BAD = "BTAP-ExteriorWall-WoodFramed-7 bad"
111
+ WOOD7_GOOD = "BTAP-ExteriorWall-WoodFramed-7 good"
112
+
113
+ STEL1 = "BTAP-ExteriorWall-SteelFramed-1"
114
+ STEL1_BAD = "BTAP-ExteriorWall-SteelFramed-1 bad"
115
+ STEL1_GOOD = "BTAP-ExteriorWall-SteelFramed-1 good"
116
+ STEL2 = "BTAP-ExteriorWall-SteelFramed-2" # HP from @Uo < 0.278
117
+ STEL2_BAD = "BTAP-ExteriorWall-SteelFramed-2 bad"
118
+ STEL2_GOOD = "BTAP-ExteriorWall-SteelFramed-2 good"
119
+
120
+ ROOFS = "BTAP-ExteriorRoof-IEAD-4"
121
+ FLOOR = "BTAP-ExteriorFloor-SteelFramed-1"
122
+
123
+ UMIN = 0.010
124
+ UMAX = 5.678
125
+
126
+ # There are 3 distinct BTAP "building_envelope" classes to enrich with
127
+ # TBD functionality (whether BTAP users choose to activate TBD or not):
128
+ #
129
+ # 1. BTAPPRE1980
130
+ # - superclass for BTAP1980TO2010
131
+ # 2. NECB2011
132
+ # - superclass for NECB2015
133
+ # - superclass for NECB2017 (inherits from NECB2015)
134
+ # - superclass for ECMS
135
+ # 3. NECB2020
136
+ #
137
+ # In all 3 classes, a BTAP/TBD option switch allows BTAP users to activate
138
+ # or deactivate TBD functionality :
139
+ # - "none" : TBD is deactivated, i.e. no up/de-rating
140
+ # - "bad" or "good": (BTAP-costed) PSI factor sets, i.e. derating only
141
+ # - "uprate": iteratively determine initial Uo ... prior to derating
142
+ #
143
+ # For vintages < NECB2017, the default BTAP policy is to switch off TBD,
144
+ # i.e. 'none' (see the NOTE on this topic at the end of this document). To
145
+ # instead assess prescriptive Ut compliance for vintages NECB2017 and
146
+ # NECB2020, the BTAP/TBD must be set to "uprate" so it can iteratively reset
147
+ # combined Uo & PSI factors towards finding the least expensive, yet
148
+ # compliant combination. Why? Improved Uo construction variants are
149
+ # necessarily required, given:
150
+ #
151
+ # Ut = Uo + ( ∑psi L )/A + ( ∑khi n )/A (ref: rd2.github.io/tbd)
152
+ #
153
+ # If one ignores linear ("( ∑psi L )/A") and point ("( ∑khi n )/A")
154
+ # conductances, Ut simply equates to Uo. Yet for ANY added linear or
155
+ # point conductance, Uo factors must necessarily be lower than required
156
+ # NECB2017 or NECB2020 Ut factors. EVOKE's 2022 contribution extends
157
+ # initial (pre-2022) BTAP wall construction variants, offering much
158
+ # lower Uo factors (in some cases slightly below 0.1 W/m2.K or ~R70).
159
+ # These BTAP upgrades provide more options for attaining required Ut
160
+ # factors. For some variants, this simply implies a thicker insulation
161
+ # layer. For others, it involves more radical construction changes, such
162
+ # as switching over to the latest commercially-available HP
163
+ # thermally-broken cladding clips. While some solutions are simple
164
+ # (free) detailing changes, most improvements increase construction
165
+ # costs. Despite adding new HP constructions, it is unlikely that TBD
166
+ # will find NECB2017 or NECB2020 compliant combinations (prescriptive
167
+ # path) for EVERY OpenStudio model. Read here as to "why?":
168
+ #
169
+ # github.com/rd2/tbd/blob/f34ec6a017fcc0f6022f2a46e056b46b9d036b3b/
170
+ # spec/tbd_tests_spec.rb#L9219
171
+ #
172
+ # For these reasons, BTAP's use of TBD rests on an ITERATIVE uprating
173
+ # solution for e.g. NECB2017 and NECB2020:
174
+ #
175
+ # 1. TBD attempts to achieve NECB-required area-weighted Ut factors
176
+ # for above-grade walls (then for roofs and exposed floors),
177
+ # starting with the least expensive combination:
178
+ # - highest admissible Uo factors for the climate zone
179
+ # - "bad" (LP) thermal bridging details
180
+ #
181
+ # 2. If, for a given OpenStudio model, required area-weighted Ut
182
+ # factors cannot be achieved, TBD then switches over to "good"
183
+ # (HP) thermal bridging detailing for that same construction, and
184
+ # repeats the exercise.
185
+ #
186
+ # 3. A subsequent failed attempt triggers a switch over to EVOKE's
187
+ # HP (improved Uo) assemblies. For instance:
188
+ # - "BTAP-ExteriorWall-WoodFramed-5" ... switches over to:
189
+ # - "BTAP-ExteriorWall-WoodFramed-7b"
190
+ #
191
+ # ... switching over to another construction this way also means
192
+ # reverting back to "bad" (LP) thermal bridging PSI factors.
193
+ #
194
+ # 4. A final switch to "good" (HP) details is available (last resort).
195
+ #
196
+ # If none of the available combinations are sufficient:
197
+ # - TBD red-flags a failed attempt at NECB2017 or NECB2020 compliance
198
+ # - TBD keeps iteration #4 Uo + PSI combo, then derates
199
+ # - BTAP runs the simulation (giving some performance gap indication)
200
+
201
+ # Hash of admissible Uo factors. If initial BTAP constructions fail to
202
+ # comply when uprating, jump to subsequent high-performance variant,
203
+ # e.g. "STEL1" switches to "STEL2". In most cases, the solution
204
+ # prioritizes basic solutions (less $), only opting for HP variants as a
205
+ # last recourse. There are 3x exceptions:
206
+ #
207
+ # - Steel-framed construction: the selected HP variant has metal
208
+ # cladding. The only LP steel-framed BTAP option is wood-clad -
209
+ # something of an anomaly in commercial construction. By making the
210
+ # switch earlier to metal cladding, everywhere in Canada except
211
+ # (milder) SW BC and SW NS, it is hoped that a more consistent,
212
+ # apples-to-apples comparison is ensured.
213
+ #
214
+ # - CMU-construction with lightweight cladding: The HP variant 10c
215
+ # (CMU, gypsum-finished, metal-clad) doesn't have any obvious LP
216
+ # construction counterpart. The proposed solution is to rely on
217
+ # Mass-6 constructions (literal copies of Mass-2 constructions,
218
+ # which are unfinished and brick-clad), as a starting point for
219
+ # milder climate zones only, and switch as early as possible to
220
+ # 10c constructions.
221
+ #
222
+ # - ROOF and (exposed) FLOOR surfaces refer to a single LP/HP selection
223
+ # respectively. This is expected to change in the future ...
224
+
225
+ # Preset BTAP/TBD wall construction parameters.
226
+ # :sptypes : BTAP/TBD Hash of linked NECB SpaceTypes (symbols)
227
+ # :uos : BTAP/TBD Hash of associated of Uo sub-variants
228
+ # :lp or :hp : low- or high-performance attribute
229
+ @@data = {}
230
+
231
+ @@data[MASS2] = { sptypes: {}, uos: {}, lp: true }
232
+ @@data[MASSB] = { sptypes: {}, uos: {}, hp: true }
233
+ @@data[MASS4] = { sptypes: {}, uos: {}, lp: true }
234
+ @@data[MASS8] = { sptypes: {}, uos: {}, hp: true }
235
+ @@data[MASS6] = { sptypes: {}, uos: {}, lp: true }
236
+ @@data[MASSC] = { sptypes: {}, uos: {}, hp: true }
237
+ @@data[MTAL1] = { sptypes: {}, uos: {}, lp: true }
238
+ @@data[MTALD] = { sptypes: {}, uos: {}, hp: true }
239
+ @@data[WOOD5] = { sptypes: {}, uos: {}, lp: true }
240
+ @@data[WOOD7] = { sptypes: {}, uos: {}, hp: true }
241
+ @@data[STEL1] = { sptypes: {}, uos: {}, lp: true }
242
+ @@data[STEL2] = { sptypes: {}, uos: {}, hp: true }
243
+ @@data[FLOOR] = { sptypes: {}, uos: {} }
244
+ @@data[ROOFS] = { sptypes: {}, uos: {} }
245
+
246
+ # A construction sub-variant is identified strictly by its Uo factor:
247
+ #
248
+ # e.g. :314 describes a Uo factor of 0.314 W/m2.K
249
+ #
250
+ # Listed items for each sub-variant are layer identifiers (for BTAP
251
+ # costing only). For the moment, they are listed integers (but should
252
+ # be expanded (e.g. as Hash keys) to hold additional costing metadata,
253
+ # e.g. $/m2). This should be (soon) removed from BTAP/TBD data.
254
+ #
255
+ # NOTE: Missing gypsum finish for WOOD7 Uo 0.130?
256
+
257
+ @@data[MASS2][:uos]["314"] = [ 24, 25, 26, 27, 28,134, 20, 21,139,141 ]
258
+ @@data[MASS2][:uos]["278"] = [ 24, 25, 26, 27, 28, 42, 20, 21,139,141 ]
259
+ @@data[MASS2][:uos]["247"] = [ 24, 25, 26, 27, 28, 58, 20, 21,139,141 ]
260
+ @@data[MASS2][:uos]["210"] = [ 24, 25, 26, 27, 28, 55, 20, 21,139,141 ]
261
+ @@data[MASS2][:uos]["183"] = [ 24, 25, 26, 27, 28, 68, 20, 21,139,141 ]
262
+ @@data[MASSB][:uos]["130"] = [ 1, 11, 24,160,164,179,141 ]
263
+ @@data[MASSB][:uos]["100"] = [ 1, 11, 24,160,165,179,141 ]
264
+
265
+ @@data[MASS4][:uos]["314"] = [ 1, 11, 43, 6, 92, 41 ]
266
+ @@data[MASS4][:uos]["278"] = [ 1, 11, 69, 6, 41,150 ]
267
+ @@data[MASS4][:uos]["247"] = [ 1, 11, 43, 6, 58, 41 ]
268
+ @@data[MASS4][:uos]["210"] = [ 1, 11, 43, 6,134, 41 ]
269
+ @@data[MASS4][:uos]["183"] = [ 1, 11, 49, 80, 41 ]
270
+ @@data[MASS8][:uos]["130"] = [ 1, 11,168,195 ]
271
+ @@data[MASS8][:uos]["100"] = [ 1, 11,168,195 ]
272
+
273
+ @@data[MASS6][:uos]["314"] = [ 24, 25, 26, 27, 28,134, 20, 21,139,141 ]
274
+ @@data[MASS6][:uos]["278"] = [ 24, 25, 26, 27, 28, 42, 20, 21,139,141 ]
275
+ @@data[MASS6][:uos]["247"] = [ 24, 25, 26, 27, 28, 58, 20, 21,139,141 ]
276
+ @@data[MASSC][:uos]["210"] = [ 1, 11,160, 24, 25, 26, 27, 28,172,181,162,196,180,141 ]
277
+ @@data[MASSC][:uos]["183"] = [ 1, 11,160, 24, 25, 26, 27, 28,172,182,163,196,180,141 ]
278
+ @@data[MASSC][:uos]["130"] = [ 1, 11,160, 24, 25, 26, 27, 28,172,185,165,196,180,141 ]
279
+ @@data[MASSC][:uos]["100"] = [ 1, 11,160, 24, 25, 26, 27, 28,172,186,163,165,196,180,141]
280
+ @@data[MASSC][:uos]["080"] = [ 1, 11,160, 24, 25, 26, 27, 28,172,188,165,165,196,180,141]
281
+
282
+ @@data[MTAL1][:uos]["314"] = [ 1, 11, 43, 6, 56,150, 48 ]
283
+ @@data[MTAL1][:uos]["278"] = [ 1, 11, 43, 6, 48, 55 ]
284
+ @@data[MTAL1][:uos]["247"] = [ 1, 11, 43, 56, 6, 48, 59 ]
285
+ @@data[MTAL1][:uos]["210"] = [ 1, 11, 43, 63, 6, 48, 59 ]
286
+ @@data[MTAL1][:uos]["183"] = [ 1, 11, 43, 58, 6, 48, 59 ]
287
+ @@data[MTALD][:uos]["130"] = [ 11,160,204,203,205,204,174,173,180, 1 ]
288
+ @@data[MTALD][:uos]["100"] = [ 11,160,204,203,205,204,174,174,180, 1 ]
289
+
290
+ @@data[WOOD5][:uos]["314"] = [138, 3, 43, 5, 6,153, 20, 21,139,141, 1]
291
+ @@data[WOOD5][:uos]["278"] = [138, 3, 53, 56, 5, 6, 20, 21,139,141, 1]
292
+ @@data[WOOD5][:uos]["247"] = [138, 3, 4, 5, 56, 6, 20, 21,139,141, 1]
293
+ @@data[WOOD5][:uos]["210"] = [138, 3, 53, 5, 56, 6, 20, 21,139,141, 1]
294
+ @@data[WOOD5][:uos]["183"] = [138, 3, 53, 5, 67, 6, 20, 21,139,141, 1]
295
+ @@data[WOOD7][:uos]["130"] = [138,160, 56,163,197, 20, 21,139,141, 1 ] # < added '1' for gypsum finish
296
+
297
+ @@data[STEL1][:uos]["314"] = [ 11, 3, 43,153, 6, 7,141, 9, 10, 1 ]
298
+ @@data[STEL1][:uos]["278"] = [ 11, 3, 53, 5, 56, 6, 7,141, 9, 10, 1 ]
299
+ @@data[STEL2][:uos]["247"] = [ 11, 3, 53, 5, 63, 6, 7,141, 9, 10, 1 ]
300
+ @@data[STEL2][:uos]["210"] = [ 11, 3, 53, 5, 67, 6, 7,141, 9, 10, 1 ]
301
+ @@data[STEL2][:uos]["183"] = [ 11, 3, 53, 5, 56, 67, 6, 7,141, 9, 10, 1]
302
+ @@data[STEL2][:uos]["130"] = [ 11, 3, 43,171,172,164,163,186,196,180,141, 1]
303
+ @@data[STEL2][:uos]["100"] = [ 11, 3, 43,171,172,165,163,187,197,180,141, 1]
304
+ @@data[STEL2][:uos]["080"] = [ 11, 3, 43,171,172,165,165,188,197,180,141, 1]
305
+
306
+ @@data[FLOOR][:uos]["227"] = [117,145,118, 3, 99, 6,119 ]
307
+ @@data[FLOOR][:uos]["183"] = [117,145,118, 3, 99, 56, 6,119]
308
+ @@data[FLOOR][:uos]["162"] = [117,145,118, 3, 99, 67, 6,119]
309
+ @@data[FLOOR][:uos]["142"] = [117,145,118, 3, 68, 56, 6,119]
310
+ @@data[FLOOR][:uos]["116"] = [117,145,118, 3,157, 6,157, 6]
311
+ @@data[FLOOR][:uos]["101"] = [117,145,118, 3,157,158, 6,119]
312
+
313
+ @@data[ROOFS][:uos]["227"] = [ 94, 97, 71, 92, 93]
314
+ @@data[ROOFS][:uos]["193"] = [ 94, 97, 80, 80, 93]
315
+ @@data[ROOFS][:uos]["183"] = [ 94, 97,134,134, 93]
316
+ @@data[ROOFS][:uos]["162"] = [ 94, 97,102,153, 93]
317
+ @@data[ROOFS][:uos]["156"] = [ 94, 97,134, 91, 93]
318
+ @@data[ROOFS][:uos]["142"] = [ 94, 97,106, 93 ]
319
+ @@data[ROOFS][:uos]["138"] = [ 94, 97,106, 93 ] # same as :142 ?
320
+ @@data[ROOFS][:uos]["121"] = [ 94, 97,106,150, 93]
321
+ @@data[ROOFS][:uos]["100"] = [ 94, 97,106,106, 93]
322
+
323
+ # In BTAP costing, each NECB building/space type is linked to a default
324
+ # construction set, which holds one of the preceding wall options. This
325
+ # linkage is now extended to OpenStudio models (not just costing),
326
+ # given the construction-specific nature of MAJOR thermal bridging.
327
+ #
328
+ # Each of these wall options holds NECB building (or space) type keywords
329
+ # (see below). The default (fall back) keyword is :office. String pattern
330
+ # recognition, e.g.:
331
+ #
332
+ # :gym from "Gymnasium/Fitness centre exercise area"
333
+ #
334
+ # ... is implemented elsewhere in the BTAP/TBD class. The default BTAP
335
+ # wall construction for :office (fall back) is STEL1. Subsequent PSI
336
+ # factor selection is based strictly on selected wall construction, e.g.
337
+ # regardless of selected roof, fenestration. The linkage remains valid
338
+ # for both building and space types (regardless of NECB vintage).
339
+ #
340
+ # The implementation is likely to be revised in the future, yet would
341
+ # remain conceptually similar.
342
+
343
+ # "BTAP-ExteriorWall-Mass-2" & "BTAP-ExteriorWall-Mass-2b"
344
+ @@data[MASS2][:sptypes][:exercise ] = {}
345
+ @@data[MASS2][:sptypes][:firestation ] = {}
346
+ @@data[MASS2][:sptypes][:gym ] = {}
347
+ @@data[MASSB][:sptypes][:exercise ] = {}
348
+ @@data[MASSB][:sptypes][:firestation ] = {}
349
+ @@data[MASSB][:sptypes][:gym ] = {}
350
+
351
+ # "BTAP-ExteriorWall-Mass-4" & "BTAP-ExteriorWall-Mass-8c"
352
+ @@data[MASS4][:sptypes][:courthouse ] = {}
353
+ @@data[MASS4][:sptypes][:museum ] = {}
354
+ @@data[MASS4][:sptypes][:parking ] = {}
355
+ @@data[MASS4][:sptypes][:post ] = {}
356
+ @@data[MASS4][:sptypes][:transportation ] = {}
357
+ @@data[MASS8][:sptypes][:courthouse ] = {}
358
+ @@data[MASS8][:sptypes][:museum ] = {}
359
+ @@data[MASS8][:sptypes][:parking ] = {}
360
+ @@data[MASS8][:sptypes][:post ] = {}
361
+ @@data[MASS8][:sptypes][:transportation ] = {}
362
+
363
+ # "BTAP-ExteriorWall-Mass-6" & "BTAP-ExteriorWall-Mass-10c"
364
+ @@data[MASS6][:sptypes][:automotive ] = {}
365
+ @@data[MASS6][:sptypes][:penitentiary ] = {}
366
+ @@data[MASS6][:sptypes][:arena ] = {}
367
+ @@data[MASS6][:sptypes][:warehouse ] = {}
368
+ @@data[MASS6][:sptypes][:storage ] = {}
369
+ @@data[MASSC][:sptypes][:automotive ] = {}
370
+ @@data[MASSC][:sptypes][:penitentiary ] = {}
371
+ @@data[MASSC][:sptypes][:arena ] = {}
372
+ @@data[MASSC][:sptypes][:warehouse ] = {}
373
+ @@data[MASSC][:sptypes][:storage ] = {}
374
+
375
+ # "BTAP-ExteriorWall-Metal-1" & "BTAP-ExteriorWall-Metal-1d"
376
+ @@data[MTAL1][:sptypes][:mfg ] = {}
377
+ @@data[MTAL1][:sptypes][:workshop ] = {}
378
+ @@data[MTALD][:sptypes][:mfg ] = {}
379
+ @@data[MTALD][:sptypes][:workshop ] = {}
380
+
381
+ # "BTAP-ExteriorWall-WoodFramed-5" & "BTAP-ExteriorWall-WoodFramed-7"
382
+ @@data[WOOD5][:sptypes][:religious ] = {}
383
+ @@data[WOOD5][:sptypes][:dwelling ] = {} # if < 5 stories
384
+ @@data[WOOD5][:sptypes][:library ] = {} # if < 3 stories
385
+ @@data[WOOD5][:sptypes][:school ] = {} # if < 3 stories
386
+ @@data[WOOD7][:sptypes][:religious ] = {}
387
+ @@data[WOOD7][:sptypes][:dwelling ] = {} # if < 5 stories
388
+ @@data[WOOD7][:sptypes][:library ] = {} # if < 3 stories
389
+ @@data[WOOD7][:sptypes][:school ] = {} # if < 3 stories
390
+
391
+ # "BTAP-ExteriorWall-SteelFramed-1" & "BTAP-ExteriorWall-SteelFramed-2"
392
+ @@data[STEL1][:sptypes][:dwelling5 ] = {} # if > 4 stories
393
+ @@data[STEL1][:sptypes][:library3 ] = {} # if > 2 stories
394
+ @@data[STEL1][:sptypes][:school3 ] = {} # if > 2 stories
395
+ @@data[STEL1][:sptypes][:convention ] = {}
396
+ @@data[STEL1][:sptypes][:dining ] = {}
397
+ @@data[STEL1][:sptypes][:health ] = {}
398
+ @@data[STEL1][:sptypes][:hospital ] = {}
399
+ @@data[STEL1][:sptypes][:motion ] = {}
400
+ @@data[STEL1][:sptypes][:performance ] = {}
401
+ @@data[STEL1][:sptypes][:police ] = {}
402
+ @@data[STEL1][:sptypes][:retail ] = {}
403
+ @@data[STEL1][:sptypes][:town ] = {}
404
+ @@data[STEL1][:sptypes][:office ] = {}
405
+ @@data[STEL2][:sptypes][:dwelling5 ] = {} # if > 4 stories
406
+ @@data[STEL2][:sptypes][:library3 ] = {} # if > 2 stories
407
+ @@data[STEL2][:sptypes][:school3 ] = {} # if > 2 stories
408
+ @@data[STEL2][:sptypes][:convention ] = {}
409
+ @@data[STEL2][:sptypes][:dining ] = {}
410
+ @@data[STEL2][:sptypes][:health ] = {}
411
+ @@data[STEL2][:sptypes][:hospital ] = {}
412
+ @@data[STEL2][:sptypes][:motion ] = {}
413
+ @@data[STEL2][:sptypes][:performance ] = {}
414
+ @@data[STEL2][:sptypes][:police ] = {}
415
+ @@data[STEL2][:sptypes][:retail ] = {}
416
+ @@data[STEL2][:sptypes][:town ] = {}
417
+ @@data[STEL2][:sptypes][:office ] = {}
418
+
419
+ # Initialize PSI factor qualities per wall construction.
420
+ @@data.values.each do |construction|
421
+ construction[:bad ] = {}
422
+ construction[:good] = {}
423
+ end
424
+
425
+ # Thermal bridge types :balcony, :party and :joint are NOT expected to
426
+ # be processed within BTAP. They are not costed out either. At some
427
+ # point, it may become wise to do so (notably for cantilevered balconies
428
+ # in MURBs). Default, generic BETBG PSI factors are nonetheless provided
429
+ # here (just in case):
430
+ #
431
+ # - for the "bad" BTAP cases, retained values are those of the
432
+ # generic "bad" BETBG set
433
+ # - while "good" BTAP values are those of the generic BETBG
434
+ # "efficient" set
435
+
436
+ @@data[MASS2][ :bad][:rimjoist ] = { psi: 0.470 }
437
+ @@data[MASS2][ :bad][:parapet ] = { psi: 0.500 }
438
+ @@data[MASS2][ :bad][:head ] = { psi: 0.350 }
439
+ @@data[MASS2][ :bad][:jamb ] = { psi: 0.350 }
440
+ @@data[MASS2][ :bad][:sill ] = { psi: 0.350 }
441
+ @@data[MASS2][ :bad][:corner ] = { psi: 0.150 }
442
+ @@data[MASS2][ :bad][:balcony ] = { psi: 1.000 }
443
+ @@data[MASS2][ :bad][:party ] = { psi: 0.850 }
444
+ @@data[MASS2][ :bad][:grade ] = { psi: 0.520 }
445
+ @@data[MASS2][ :bad][:joint ] = { psi: 0.300 }
446
+ @@data[MASS2][ :bad][:transition ] = { psi: 0.000 }
447
+
448
+ @@data[MASS2][:good][:rimjoist ] = { psi: 0.100 }
449
+ @@data[MASS2][:good][:parapet ] = { psi: 0.230 }
450
+ @@data[MASS2][:good][:head ] = { psi: 0.078 }
451
+ @@data[MASS2][:good][:jamb ] = { psi: 0.078 }
452
+ @@data[MASS2][:good][:sill ] = { psi: 0.078 }
453
+ @@data[MASS2][:good][:corner ] = { psi: 0.090 }
454
+ @@data[MASS2][:good][:balcony ] = { psi: 0.200 }
455
+ @@data[MASS2][:good][:party ] = { psi: 0.200 }
456
+ @@data[MASS2][:good][:grade ] = { psi: 0.090 }
457
+ @@data[MASS2][:good][:joint ] = { psi: 0.100 }
458
+ @@data[MASS2][:good][:transition ] = { psi: 0.000 }
459
+
460
+ @@data[MASSB][ :bad][:rimjoist ] = { psi: 0.470 }
461
+ @@data[MASSB][ :bad][:parapet ] = { psi: 0.500 }
462
+ @@data[MASSB][ :bad][:head ] = { psi: 0.350 }
463
+ @@data[MASSB][ :bad][:jamb ] = { psi: 0.350 }
464
+ @@data[MASSB][ :bad][:sill ] = { psi: 0.350 }
465
+ @@data[MASSB][ :bad][:corner ] = { psi: 0.150 }
466
+ @@data[MASSB][ :bad][:balcony ] = { psi: 1.000 }
467
+ @@data[MASSB][ :bad][:party ] = { psi: 0.850 }
468
+ @@data[MASSB][ :bad][:grade ] = { psi: 0.520 }
469
+ @@data[MASSB][ :bad][:joint ] = { psi: 0.300 }
470
+ @@data[MASSB][ :bad][:transition ] = { psi: 0.000 }
471
+
472
+ @@data[MASSB][:good][:rimjoist ] = { psi: 0.100 }
473
+ @@data[MASSB][:good][:parapet ] = { psi: 0.230 }
474
+ @@data[MASSB][:good][:head ] = { psi: 0.078 }
475
+ @@data[MASSB][:good][:jamb ] = { psi: 0.078 }
476
+ @@data[MASSB][:good][:sill ] = { psi: 0.078 }
477
+ @@data[MASSB][:good][:corner ] = { psi: 0.090 }
478
+ @@data[MASSB][:good][:balcony ] = { psi: 0.200 }
479
+ @@data[MASSB][:good][:party ] = { psi: 0.200 }
480
+ @@data[MASSB][:good][:grade ] = { psi: 0.090 }
481
+ @@data[MASSB][:good][:joint ] = { psi: 0.100 }
482
+ @@data[MASSB][:good][:transition ] = { psi: 0.000 }
483
+
484
+ @@data[MASS4][ :bad][:rimjoist ] = { psi: 0.200 }
485
+ @@data[MASS4][ :bad][:parapet ] = { psi: 0.650 }
486
+ @@data[MASS4][ :bad][:head ] = { psi: 0.078 }
487
+ @@data[MASS4][ :bad][:jamb ] = { psi: 0.078 }
488
+ @@data[MASS4][ :bad][:sill ] = { psi: 0.078 }
489
+ @@data[MASS4][ :bad][:corner ] = { psi: 0.370 }
490
+ @@data[MASS4][ :bad][:balcony ] = { psi: 1.000 }
491
+ @@data[MASS4][ :bad][:party ] = { psi: 0.850 }
492
+ @@data[MASS4][ :bad][:grade ] = { psi: 0.800 }
493
+ @@data[MASS4][ :bad][:joint ] = { psi: 0.300 }
494
+ @@data[MASS4][ :bad][:transition ] = { psi: 0.000 }
495
+
496
+ @@data[MASS4][:good][:rimjoist ] = { psi: 0.020 }
497
+ @@data[MASS4][:good][:parapet ] = { psi: 0.240 }
498
+ @@data[MASS4][:good][:head ] = { psi: 0.078 }
499
+ @@data[MASS4][:good][:jamb ] = { psi: 0.078 }
500
+ @@data[MASS4][:good][:sill ] = { psi: 0.078 }
501
+ @@data[MASS4][:good][:corner ] = { psi: 0.160 }
502
+ @@data[MASS4][:good][:balcony ] = { psi: 0.200 }
503
+ @@data[MASS4][:good][:party ] = { psi: 0.200 }
504
+ @@data[MASS4][:good][:grade ] = { psi: 0.320 }
505
+ @@data[MASS4][:good][:joint ] = { psi: 0.100 }
506
+ @@data[MASS4][:good][:transition ] = { psi: 0.000 }
507
+
508
+ @@data[MASS8][ :bad][:rimjoist ] = { psi: 0.200 }
509
+ @@data[MASS8][ :bad][:parapet ] = { psi: 0.650 }
510
+ @@data[MASS8][ :bad][:head ] = { psi: 0.078 }
511
+ @@data[MASS8][ :bad][:jamb ] = { psi: 0.078 }
512
+ @@data[MASS8][ :bad][:sill ] = { psi: 0.078 }
513
+ @@data[MASS8][ :bad][:corner ] = { psi: 0.370 }
514
+ @@data[MASS8][ :bad][:balcony ] = { psi: 1.000 }
515
+ @@data[MASS8][ :bad][:party ] = { psi: 0.850 }
516
+ @@data[MASS8][ :bad][:grade ] = { psi: 0.800 }
517
+ @@data[MASS8][ :bad][:joint ] = { psi: 0.300 }
518
+ @@data[MASS8][ :bad][:transition ] = { psi: 0.000 }
519
+
520
+ @@data[MASS8][:good][:rimjoist ] = { psi: 0.020 }
521
+ @@data[MASS8][:good][:parapet ] = { psi: 0.240 }
522
+ @@data[MASS8][:good][:head ] = { psi: 0.078 }
523
+ @@data[MASS8][:good][:jamb ] = { psi: 0.078 }
524
+ @@data[MASS8][:good][:sill ] = { psi: 0.078 }
525
+ @@data[MASS8][:good][:corner ] = { psi: 0.160 }
526
+ @@data[MASS8][:good][:balcony ] = { psi: 0.200 }
527
+ @@data[MASS8][:good][:party ] = { psi: 0.200 }
528
+ @@data[MASS8][:good][:grade ] = { psi: 0.320 }
529
+ @@data[MASS8][:good][:joint ] = { psi: 0.100 }
530
+ @@data[MASS8][:good][:transition ] = { psi: 0.000 }
531
+
532
+ @@data[MASS6][ :bad][:rimjoist ] = { psi: 0.470 }
533
+ @@data[MASS6][ :bad][:parapet ] = { psi: 0.500 }
534
+ @@data[MASS6][ :bad][:head ] = { psi: 0.350 }
535
+ @@data[MASS6][ :bad][:jamb ] = { psi: 0.350 }
536
+ @@data[MASS6][ :bad][:sill ] = { psi: 0.350 }
537
+ @@data[MASS6][ :bad][:corner ] = { psi: 0.150 }
538
+ @@data[MASS6][ :bad][:balcony ] = { psi: 1.000 }
539
+ @@data[MASS6][ :bad][:party ] = { psi: 0.850 }
540
+ @@data[MASS6][ :bad][:grade ] = { psi: 0.520 }
541
+ @@data[MASS6][ :bad][:joint ] = { psi: 0.300 }
542
+ @@data[MASS6][ :bad][:transition ] = { psi: 0.000 }
543
+
544
+ @@data[MASS6][:good][:rimjoist ] = { psi: 0.100 }
545
+ @@data[MASS6][:good][:parapet ] = { psi: 0.230 }
546
+ @@data[MASS6][:good][:head ] = { psi: 0.078 }
547
+ @@data[MASS6][:good][:jamb ] = { psi: 0.078 }
548
+ @@data[MASS6][:good][:sill ] = { psi: 0.078 }
549
+ @@data[MASS6][:good][:corner ] = { psi: 0.090 }
550
+ @@data[MASS6][:good][:balcony ] = { psi: 0.200 }
551
+ @@data[MASS6][:good][:party ] = { psi: 0.200 }
552
+ @@data[MASS6][:good][:grade ] = { psi: 0.090 }
553
+ @@data[MASS6][:good][:joint ] = { psi: 0.100 }
554
+ @@data[MASS6][:good][:transition ] = { psi: 0.000 }
555
+
556
+ @@data[MASSC][ :bad][:rimjoist ] = { psi: 0.170 }
557
+ @@data[MASSC][ :bad][:parapet ] = { psi: 0.500 }
558
+ @@data[MASSC][ :bad][:head ] = { psi: 0.350 }
559
+ @@data[MASSC][ :bad][:jamb ] = { psi: 0.350 }
560
+ @@data[MASSC][ :bad][:sill ] = { psi: 0.350 }
561
+ @@data[MASSC][ :bad][:corner ] = { psi: 0.150 }
562
+ @@data[MASSC][ :bad][:balcony ] = { psi: 1.000 }
563
+ @@data[MASSC][ :bad][:party ] = { psi: 0.850 }
564
+ @@data[MASSC][ :bad][:grade ] = { psi: 0.720 }
565
+ @@data[MASSC][ :bad][:joint ] = { psi: 0.300 }
566
+ @@data[MASSC][ :bad][:transition ] = { psi: 0.000 }
567
+
568
+ @@data[MASSC][:good][:rimjoist ] = { psi: 0.017 }
569
+ @@data[MASSC][:good][:parapet ] = { psi: 0.230 }
570
+ @@data[MASSC][:good][:head ] = { psi: 0.078 }
571
+ @@data[MASSC][:good][:jamb ] = { psi: 0.078 }
572
+ @@data[MASSC][:good][:sill ] = { psi: 0.078 }
573
+ @@data[MASSC][:good][:corner ] = { psi: 0.090 }
574
+ @@data[MASSC][:good][:balcony ] = { psi: 0.200 }
575
+ @@data[MASSC][:good][:party ] = { psi: 0.200 }
576
+ @@data[MASSC][:good][:grade ] = { psi: 0.470 }
577
+ @@data[MASSC][:good][:joint ] = { psi: 0.100 }
578
+ @@data[MASSC][:good][:transition ] = { psi: 0.000 }
579
+
580
+ @@data[MTAL1][ :bad][:rimjoist ] = { psi: 0.320 }
581
+ @@data[MTAL1][ :bad][:parapet ] = { psi: 0.420 }
582
+ @@data[MTAL1][ :bad][:head ] = { psi: 0.520 }
583
+ @@data[MTAL1][ :bad][:jamb ] = { psi: 0.520 }
584
+ @@data[MTAL1][ :bad][:sill ] = { psi: 0.520 }
585
+ @@data[MTAL1][ :bad][:corner ] = { psi: 0.150 }
586
+ @@data[MTAL1][ :bad][:balcony ] = { psi: 1.000 }
587
+ @@data[MTAL1][ :bad][:party ] = { psi: 0.850 }
588
+ @@data[MTAL1][ :bad][:grade ] = { psi: 0.700 }
589
+ @@data[MTAL1][ :bad][:joint ] = { psi: 0.300 }
590
+ @@data[MTAL1][ :bad][:transition ] = { psi: 0.000 }
591
+
592
+ @@data[MTAL1][:good][:rimjoist ] = { psi: 0.030 }
593
+ @@data[MTAL1][:good][:parapet ] = { psi: 0.350 }
594
+ @@data[MTAL1][:good][:head ] = { psi: 0.078 }
595
+ @@data[MTAL1][:good][:jamb ] = { psi: 0.078 }
596
+ @@data[MTAL1][:good][:sill ] = { psi: 0.078 }
597
+ @@data[MTAL1][:good][:corner ] = { psi: 0.070 }
598
+ @@data[MTAL1][:good][:balcony ] = { psi: 0.200 }
599
+ @@data[MTAL1][:good][:party ] = { psi: 0.200 }
600
+ @@data[MTAL1][:good][:grade ] = { psi: 0.500 }
601
+ @@data[MTAL1][:good][:joint ] = { psi: 0.100 }
602
+ @@data[MTAL1][:good][:transition ] = { psi: 0.000 }
603
+
604
+ @@data[MTALD][ :bad][:rimjoist ] = { psi: 0.320 }
605
+ @@data[MTALD][ :bad][:parapet ] = { psi: 0.420 }
606
+ @@data[MTALD][ :bad][:head ] = { psi: 0.520 }
607
+ @@data[MTALD][ :bad][:jamb ] = { psi: 0.520 }
608
+ @@data[MTALD][ :bad][:sill ] = { psi: 0.520 }
609
+ @@data[MTALD][ :bad][:corner ] = { psi: 0.150 }
610
+ @@data[MTALD][ :bad][:balcony ] = { psi: 1.000 }
611
+ @@data[MTALD][ :bad][:party ] = { psi: 0.850 }
612
+ @@data[MTALD][ :bad][:grade ] = { psi: 0.700 }
613
+ @@data[MTALD][ :bad][:joint ] = { psi: 0.300 }
614
+ @@data[MTALD][ :bad][:transition ] = { psi: 0.000 }
615
+
616
+ @@data[MTALD][:good][:rimjoist ] = { psi: 0.030 }
617
+ @@data[MTALD][:good][:parapet ] = { psi: 0.350 }
618
+ @@data[MTALD][:good][:head ] = { psi: 0.078 }
619
+ @@data[MTALD][:good][:jamb ] = { psi: 0.078 }
620
+ @@data[MTALD][:good][:sill ] = { psi: 0.078 }
621
+ @@data[MTALD][:good][:corner ] = { psi: 0.070 }
622
+ @@data[MTALD][:good][:balcony ] = { psi: 0.200 }
623
+ @@data[MTALD][:good][:party ] = { psi: 0.200 }
624
+ @@data[MTALD][:good][:grade ] = { psi: 0.500 }
625
+ @@data[MTALD][:good][:joint ] = { psi: 0.100 }
626
+ @@data[MTALD][:good][:transition ] = { psi: 0.000 }
627
+
628
+ @@data[WOOD5][ :bad][:rimjoist ] = { psi: 0.050 }
629
+ @@data[WOOD5][ :bad][:parapet ] = { psi: 0.050 }
630
+ @@data[WOOD5][ :bad][:head ] = { psi: 0.270 }
631
+ @@data[WOOD5][ :bad][:jamb ] = { psi: 0.270 }
632
+ @@data[WOOD5][ :bad][:sill ] = { psi: 0.270 }
633
+ @@data[WOOD5][ :bad][:corner ] = { psi: 0.040 }
634
+ @@data[WOOD5][ :bad][:balcony ] = { psi: 1.000 }
635
+ @@data[WOOD5][ :bad][:party ] = { psi: 0.850 }
636
+ @@data[WOOD5][ :bad][:grade ] = { psi: 0.550 }
637
+ @@data[WOOD5][ :bad][:joint ] = { psi: 0.300 }
638
+ @@data[WOOD5][ :bad][:transition ] = { psi: 0.000 }
639
+
640
+ @@data[WOOD5][:good][:rimjoist ] = { psi: 0.030 }
641
+ @@data[WOOD5][:good][:parapet ] = { psi: 0.050 }
642
+ @@data[WOOD5][:good][:head ] = { psi: 0.078 }
643
+ @@data[WOOD5][:good][:jamb ] = { psi: 0.078 }
644
+ @@data[WOOD5][:good][:sill ] = { psi: 0.078 }
645
+ @@data[WOOD5][:good][:corner ] = { psi: 0.040 }
646
+ @@data[WOOD5][:good][:balcony ] = { psi: 0.200 }
647
+ @@data[WOOD5][:good][:party ] = { psi: 0.200 }
648
+ @@data[WOOD5][:good][:grade ] = { psi: 0.090 }
649
+ @@data[WOOD5][:good][:joint ] = { psi: 0.100 }
650
+ @@data[WOOD5][:good][:transition ] = { psi: 0.000 }
651
+
652
+ @@data[WOOD7][ :bad][:rimjoist ] = { psi: 0.050 }
653
+ @@data[WOOD7][ :bad][:parapet ] = { psi: 0.050 }
654
+ @@data[WOOD7][ :bad][:head ] = { psi: 0.270 }
655
+ @@data[WOOD7][ :bad][:jamb ] = { psi: 0.270 }
656
+ @@data[WOOD7][ :bad][:sill ] = { psi: 0.270 }
657
+ @@data[WOOD7][ :bad][:corner ] = { psi: 0.040 }
658
+ @@data[WOOD7][ :bad][:balcony ] = { psi: 1.000 }
659
+ @@data[WOOD7][ :bad][:party ] = { psi: 0.850 }
660
+ @@data[WOOD7][ :bad][:grade ] = { psi: 0.550 }
661
+ @@data[WOOD7][ :bad][:joint ] = { psi: 0.300 }
662
+ @@data[WOOD7][ :bad][:transition ] = { psi: 0.000 }
663
+
664
+ @@data[WOOD7][:good][:rimjoist ] = { psi: 0.030 }
665
+ @@data[WOOD7][:good][:parapet ] = { psi: 0.050 }
666
+ @@data[WOOD7][:good][:head ] = { psi: 0.078 }
667
+ @@data[WOOD7][:good][:jamb ] = { psi: 0.078 }
668
+ @@data[WOOD7][:good][:sill ] = { psi: 0.078 }
669
+ @@data[WOOD7][:good][:corner ] = { psi: 0.040 }
670
+ @@data[WOOD7][:good][:balcony ] = { psi: 0.200 }
671
+ @@data[WOOD7][:good][:party ] = { psi: 0.200 }
672
+ @@data[WOOD7][:good][:grade ] = { psi: 0.090 }
673
+ @@data[WOOD7][:good][:joint ] = { psi: 0.100 }
674
+ @@data[WOOD7][:good][:transition ] = { psi: 0.000 }
675
+
676
+ @@data[STEL1][ :bad][:rimjoist ] = { psi: 0.280 }
677
+ @@data[STEL1][ :bad][:parapet ] = { psi: 0.650 }
678
+ @@data[STEL1][ :bad][:head ] = { psi: 0.270 }
679
+ @@data[STEL1][ :bad][:jamb ] = { psi: 0.270 }
680
+ @@data[STEL1][ :bad][:sill ] = { psi: 0.270 }
681
+ @@data[STEL1][ :bad][:corner ] = { psi: 0.150 }
682
+ @@data[STEL1][ :bad][:balcony ] = { psi: 1.000 }
683
+ @@data[STEL1][ :bad][:party ] = { psi: 0.850 }
684
+ @@data[STEL1][ :bad][:grade ] = { psi: 0.720 }
685
+ @@data[STEL1][ :bad][:joint ] = { psi: 0.300 }
686
+ @@data[STEL1][ :bad][:transition ] = { psi: 0.000 }
687
+
688
+ @@data[STEL1][:good][:rimjoist ] = { psi: 0.090 }
689
+ @@data[STEL1][:good][:parapet ] = { psi: 0.350 }
690
+ @@data[STEL1][:good][:head ] = { psi: 0.078 }
691
+ @@data[STEL1][:good][:jamb ] = { psi: 0.078 }
692
+ @@data[STEL1][:good][:sill ] = { psi: 0.078 }
693
+ @@data[STEL1][:good][:corner ] = { psi: 0.090 }
694
+ @@data[STEL1][:good][:balcony ] = { psi: 0.200 }
695
+ @@data[STEL1][:good][:party ] = { psi: 0.200 }
696
+ @@data[STEL1][:good][:grade ] = { psi: 0.470 }
697
+ @@data[STEL1][:good][:joint ] = { psi: 0.100 }
698
+ @@data[STEL1][:good][:transition ] = { psi: 0.000 }
699
+
700
+ @@data[STEL2][ :bad][:rimjoist ] = { psi: 0.280 }
701
+ @@data[STEL2][ :bad][:parapet ] = { psi: 0.650 }
702
+ @@data[STEL2][ :bad][:head ] = { psi: 0.270 }
703
+ @@data[STEL2][ :bad][:jamb ] = { psi: 0.270 }
704
+ @@data[STEL2][ :bad][:sill ] = { psi: 0.270 }
705
+ @@data[STEL2][ :bad][:corner ] = { psi: 0.150 }
706
+ @@data[STEL2][ :bad][:balcony ] = { psi: 1.000 }
707
+ @@data[STEL2][ :bad][:party ] = { psi: 0.850 }
708
+ @@data[STEL2][ :bad][:grade ] = { psi: 0.720 }
709
+ @@data[STEL2][ :bad][:joint ] = { psi: 0.300 }
710
+ @@data[STEL2][ :bad][:transition ] = { psi: 0.000 }
711
+
712
+ @@data[STEL2][:good][:rimjoist ] = { psi: 0.090 }
713
+ @@data[STEL2][:good][:parapet ] = { psi: 0.100 }
714
+ @@data[STEL2][:good][:head ] = { psi: 0.078 }
715
+ @@data[STEL2][:good][:jamb ] = { psi: 0.078 }
716
+ @@data[STEL2][:good][:sill ] = { psi: 0.078 }
717
+ @@data[STEL2][:good][:corner ] = { psi: 0.090 }
718
+ @@data[STEL2][:good][:balcony ] = { psi: 0.200 }
719
+ @@data[STEL2][:good][:party ] = { psi: 0.200 }
720
+ @@data[STEL2][:good][:grade ] = { psi: 0.470 }
721
+ @@data[STEL2][:good][:joint ] = { psi: 0.100 }
722
+ @@data[STEL2][:good][:transition ] = { psi: 0.000 }
723
+
724
+ # Extend for BTAP costing.
725
+ @@data.values.each do |construction|
726
+ construction[:good].values.each { |bridge| bridge[:mat] = {} }
727
+ construction[ :bad].values.each { |bridge| bridge[:mat] = {} }
728
+ end
729
+
730
+ # BTAP costed "materials" (Hash keywords in double quotations) for MAJOR
731
+ # thermal bridges. Corresponding Hash values are multipliers.
732
+ #
733
+ # NOTE: "0" as a NIL placeholder (no cost associated to thermal bridge).
734
+ @@data[MASS2][ :bad][:id ] = MASS2_BAD
735
+ # @@data[MASS2][ :bad][:rimjoist ][:mat][ "21"] = 1.000
736
+ # @@data[MASS2][ :bad][:rimjoist ][:mat]["172"] = 0.250
737
+ # @@data[MASS2][ :bad][:parapet ][:mat][ "0"] = 1.000
738
+ # @@data[MASS2][ :bad][:head ][:mat]["139"] = 0.750
739
+ # @@data[MASS2][ :bad][:jamb ][:mat]["139"] = 0.750
740
+ # @@data[MASS2][ :bad][:sill ][:mat]["139"] = 0.750
741
+ # @@data[MASS2][ :bad][:corner ][:mat][ "0"] = 1.000
742
+ # @@data[MASS2][ :bad][:balcony ][:mat][ ""] = 1.000
743
+ # @@data[MASS2][ :bad][:party ][:mat][ ""] = 1.000
744
+ # @@data[MASS2][ :bad][:grade ][:mat][ "21"] = 1.000
745
+ # @@data[MASS2][ :bad][:grade ][:mat]["139"] = 0.500
746
+ # @@data[MASS2][ :bad][:joint ][:mat][ ""] = 1.000
747
+ # @@data[MASS2][ :bad][:transition ][:mat][ ""] = 1.000
748
+
749
+ @@data[MASS2][:good][:id ] = MASS2_GOOD
750
+ # @@data[MASS2][:good][:rimjoist ][:mat]["189"] = 1.000
751
+ # @@data[MASS2][:good][:rimjoist ][:mat]["172"] = 0.500
752
+ # @@data[MASS2][:good][:parapet ][:mat][ "57"] = 3.300
753
+ # @@data[MASS2][:good][:parapet ][:mat]["139"] = 1.000
754
+ # @@data[MASS2][:good][:head ][:mat]["139"] = 0.500
755
+ # @@data[MASS2][:good][:jamb ][:mat]["139"] = 0.500
756
+ # @@data[MASS2][:good][:sill ][:mat]["139"] = 0.500
757
+ # @@data[MASS2][:good][:corner ][:mat][ "0"] = 1.000
758
+ # @@data[MASS2][:good][:balcony ][:mat][ ""] = 1.000
759
+ # @@data[MASS2][:good][:party ][:mat][ ""] = 1.000
760
+ # @@data[MASS2][:good][:grade ][:mat]["189"] = 1.000
761
+ # @@data[MASS2][:good][:grade ][:mat]["139"] = 0.500
762
+ # @@data[MASS2][:good][:grade ][:mat]["192"] = 0.500
763
+ # @@data[MASS2][:good][:joint ][:mat][ ""] = 1.000
764
+ # @@data[MASS2][:good][:transition ][:mat][ ""] = 1.000
765
+
766
+ @@data[MASSB][ :bad][:id ] = MASSB_BAD
767
+ # @@data[MASSB][ :bad][:rimjoist ][:mat][ "21"] = 1.000
768
+ # @@data[MASSB][ :bad][:rimjoist ][:mat]["172"] = 0.250
769
+ # @@data[MASSB][ :bad][:parapet ][:mat][ "0"] = 1.000
770
+ # @@data[MASSB][ :bad][:head ][:mat]["139"] = 0.750
771
+ # @@data[MASSB][ :bad][:jamb ][:mat]["139"] = 0.750
772
+ # @@data[MASSB][ :bad][:sill ][:mat]["139"] = 0.750
773
+ # @@data[MASSB][ :bad][:corner ][:mat][ "0"] = 1.000
774
+ # @@data[MASSB][ :bad][:balcony ][:mat][ ""] = 1.000
775
+ # @@data[MASSB][ :bad][:party ][:mat][ ""] = 1.000
776
+ # @@data[MASSB][ :bad][:grade ][:mat][ "21"] = 1.000
777
+ # @@data[MASSB][ :bad][:grade ][:mat]["139"] = 0.500
778
+ # @@data[MASSB][ :bad][:joint ][:mat][ ""] = 1.000
779
+ # @@data[MASSB][ :bad][:transition ][:mat][ ""] = 1.000
780
+
781
+ @@data[MASSB][:good][:id ] = MASSB_GOOD
782
+ # @@data[MASSB][:good][:rimjoist ][:mat]["189"] = 1.000
783
+ # @@data[MASSB][:good][:rimjoist ][:mat]["172"] = 0.500
784
+ # @@data[MASSB][:good][:parapet ][:mat][ "57"] = 3.300
785
+ # @@data[MASSB][:good][:parapet ][:mat]["139"] = 1.000
786
+ # @@data[MASSB][:good][:head ][:mat]["139"] = 0.500
787
+ # @@data[MASSB][:good][:jamb ][:mat]["139"] = 0.500
788
+ # @@data[MASSB][:good][:sill ][:mat]["139"] = 0.500
789
+ # @@data[MASSB][:good][:corner ][:mat][ "0"] = 1.000
790
+ # @@data[MASSB][:good][:balcony ][:mat][ ""] = 1.000
791
+ # @@data[MASSB][:good][:party ][:mat][ ""] = 1.000
792
+ # @@data[MASSB][:good][:grade ][:mat]["189"] = 1.000
793
+ # @@data[MASSB][:good][:grade ][:mat]["139"] = 0.500
794
+ # @@data[MASSB][:good][:grade ][:mat]["192"] = 0.500
795
+ # @@data[MASSB][:good][:joint ][:mat][ ""] = 1.000
796
+ # @@data[MASSB][:good][:transition ][:mat][ ""] = 1.000
797
+
798
+ @@data[MASS4][ :bad][:id ] = MASS4_BAD
799
+ # @@data[MASS4][ :bad][:rimjoist ][:mat][ "0"] = 1.000
800
+ # @@data[MASS4][ :bad][:parapet ][:mat][ "0"] = 1.000
801
+ # @@data[MASS4][ :bad][:head ][:mat]["139"] = 0.250
802
+ # @@data[MASS4][ :bad][:jamb ][:mat]["139"] = 0.250
803
+ # @@data[MASS4][ :bad][:sill ][:mat]["139"] = 0.250
804
+ # @@data[MASS4][ :bad][:corner ][:mat]["141"] = 1.000
805
+ # @@data[MASS4][ :bad][:balcony ][:mat][ ""] = 1.000
806
+ # @@data[MASS4][ :bad][:party ][:mat][ ""] = 1.000
807
+ # @@data[MASS4][ :bad][:grade ][:mat]["139"] = 0.500
808
+ # @@data[MASS4][ :bad][:joint ][:mat][ ""] = 1.000
809
+ # @@data[MASS4][ :bad][:transition ][:mat][ ""] = 1.000
810
+
811
+ @@data[MASS4][:good][:id ] = MASS4_GOOD
812
+ # @@data[MASS4][:good][:rimjoist ][:mat][ "0"] = 1.000
813
+ # @@data[MASS4][:good][:parapet ][:mat][ "57"] = 3.300
814
+ # @@data[MASS4][:good][:parapet ][:mat]["139"] = 1.000
815
+ # @@data[MASS4][:good][:head ][:mat]["139"] = 0.250
816
+ # @@data[MASS4][:good][:head ][:mat]["150"] = 0.083
817
+ # @@data[MASS4][:good][:jamb ][:mat]["139"] = 0.250
818
+ # @@data[MASS4][:good][:jamb ][:mat]["150"] = 0.083
819
+ # @@data[MASS4][:good][:sill ][:mat]["139"] = 0.250
820
+ # @@data[MASS4][:good][:sill ][:mat]["150"] = 0.083
821
+ # @@data[MASS4][:good][:corner ][:mat]["141"] = 1.250
822
+ # @@data[MASS4][:good][:balcony ][:mat][ "0"] = 1.000
823
+ # @@data[MASS4][:good][:party ][:mat][ ""] = 1.000
824
+ # @@data[MASS4][:good][:grade ][:mat]["192"] = 0.500
825
+ # @@data[MASS4][:good][:grade ][:mat]["139"] = 0.500
826
+ # @@data[MASS4][:good][:joint ][:mat][ ""] = 1.000
827
+ # @@data[MASS4][:good][:transition ][:mat][ ""] = 1.000
828
+
829
+ @@data[MASS8][ :bad][:id ] = MASS8_BAD
830
+ # @@data[MASS8][ :bad][:rimjoist ][:mat][ "0"] = 1.000
831
+ # @@data[MASS8][ :bad][:parapet ][:mat][ "0"] = 1.000
832
+ # @@data[MASS8][ :bad][:head ][:mat]["139"] = 0.250
833
+ # @@data[MASS8][ :bad][:jamb ][:mat]["139"] = 0.250
834
+ # @@data[MASS8][ :bad][:sill ][:mat]["139"] = 0.250
835
+ # @@data[MASS8][ :bad][:corner ][:mat]["141"] = 1.000
836
+ # @@data[MASS8][ :bad][:balcony ][:mat][ ""] = 1.000
837
+ # @@data[MASS8][ :bad][:party ][:mat][ ""] = 1.000
838
+ # @@data[MASS8][ :bad][:grade ][:mat]["139"] = 0.500
839
+ # @@data[MASS8][ :bad][:joint ][:mat][ ""] = 1.000
840
+ # @@data[MASS8][ :bad][:transition ][:mat][ ""] = 1.000
841
+
842
+ @@data[MASS8][:good][:id ] = MASS8_GOOD
843
+ # @@data[MASS8][:good][:rimjoist ][:mat][ "0"] = 1.000
844
+ # @@data[MASS8][:good][:parapet ][:mat][ "57"] = 3.300
845
+ # @@data[MASS8][:good][:parapet ][:mat]["139"] = 1.000
846
+ # @@data[MASS8][:good][:head ][:mat]["139"] = 0.250
847
+ # @@data[MASS8][:good][:head ][:mat]["150"] = 0.083
848
+ # @@data[MASS8][:good][:jamb ][:mat]["139"] = 0.250
849
+ # @@data[MASS8][:good][:jamb ][:mat]["150"] = 0.083
850
+ # @@data[MASS8][:good][:sill ][:mat]["139"] = 0.250
851
+ # @@data[MASS8][:good][:sill ][:mat]["150"] = 0.083
852
+ # @@data[MASS8][:good][:corner ][:mat]["141"] = 1.250
853
+ # @@data[MASS8][:good][:balcony ][:mat][ "0"] = 1.000
854
+ # @@data[MASS8][:good][:party ][:mat][ ""] = 1.000
855
+ # @@data[MASS8][:good][:grade ][:mat]["192"] = 0.500
856
+ # @@data[MASS8][:good][:grade ][:mat]["139"] = 0.500
857
+ # @@data[MASS8][:good][:joint ][:mat][ ""] = 1.000
858
+ # @@data[MASS8][:good][:transition ][:mat][ ""] = 1.000
859
+
860
+ @@data[MASS6][ :bad][:id ] = MASS6_BAD
861
+ # @@data[MASS6][ :bad][:rimjoist ][:mat][ "21"] = 1.000
862
+ # @@data[MASS6][ :bad][:rimjoist ][:mat]["172"] = 0.250
863
+ # @@data[MASS6][ :bad][:parapet ][:mat][ "0"] = 1.000
864
+ # @@data[MASS6][ :bad][:head ][:mat]["139"] = 0.750
865
+ # @@data[MASS6][ :bad][:jamb ][:mat]["139"] = 0.750
866
+ # @@data[MASS6][ :bad][:sill ][:mat]["139"] = 0.750
867
+ # @@data[MASS6][ :bad][:corner ][:mat][ "0"] = 1.000
868
+ # @@data[MASS6][ :bad][:balcony ][:mat][ ""] = 1.000
869
+ # @@data[MASS6][ :bad][:party ][:mat][ ""] = 1.000
870
+ # @@data[MASS6][ :bad][:grade ][:mat][ "21"] = 1.000
871
+ # @@data[MASS6][ :bad][:grade ][:mat]["139"] = 0.500
872
+ # @@data[MASS6][ :bad][:joint ][:mat][ ""] = 1.000
873
+ # @@data[MASS6][ :bad][:transition ][:mat][ ""] = 1.000
874
+
875
+ @@data[MASS6][:good][:id ] = MASS6_GOOD
876
+ # @@data[MASS6][:good][:rimjoist ][:mat]["189"] = 1.000
877
+ # @@data[MASS6][:good][:rimjoist ][:mat]["172"] = 0.500
878
+ # @@data[MASS6][:good][:parapet ][:mat][ "57"] = 3.300
879
+ # @@data[MASS6][:good][:parapet ][:mat]["139"] = 1.000
880
+ # @@data[MASS6][:good][:head ][:mat]["139"] = 0.500
881
+ # @@data[MASS6][:good][:jamb ][:mat]["139"] = 0.500
882
+ # @@data[MASS6][:good][:sill ][:mat]["139"] = 0.500
883
+ # @@data[MASS6][:good][:corner ][:mat][ "0"] = 1.000
884
+ # @@data[MASS6][:good][:balcony ][:mat][ ""] = 1.000
885
+ # @@data[MASS6][:good][:party ][:mat][ ""] = 1.000
886
+ # @@data[MASS6][:good][:grade ][:mat]["189"] = 1.000
887
+ # @@data[MASS6][:good][:grade ][:mat]["139"] = 0.500
888
+ # @@data[MASS6][:good][:grade ][:mat]["192"] = 0.500
889
+ # @@data[MASS6][:good][:joint ][:mat][ ""] = 1.000
890
+ # @@data[MASS6][:good][:transition ][:mat][ ""] = 1.000
891
+
892
+ @@data[MASSC][ :bad][:id ] = MASSC_BAD
893
+ # @@data[MASSC][ :bad][:rimjoist ][:mat]["139"] = 10.000
894
+ # @@data[MASSC][ :bad][:parapet ][:mat][ "0"] = 1.000
895
+ # @@data[MASSC][ :bad][:head ][:mat]["139"] = 0.750
896
+ # @@data[MASSC][ :bad][:jamb ][:mat]["139"] = 0.750
897
+ # @@data[MASSC][ :bad][:sill ][:mat]["139"] = 0.750
898
+ # @@data[MASSC][ :bad][:corner ][:mat][ "0"] = 1.000
899
+ # @@data[MASSC][ :bad][:balcony ][:mat][ ""] = 1.000
900
+ # @@data[MASSC][ :bad][:party ][:mat][ ""] = 1.000
901
+ # @@data[MASSC][ :bad][:grade ][:mat]["139"] = 0.000
902
+ # @@data[MASSC][ :bad][:joint ][:mat][ ""] = 1.000
903
+ # @@data[MASSC][ :bad][:transition ][:mat][ ""] = 1.000
904
+
905
+ @@data[MASSC][:good][:id ] = MASSC_GOOD
906
+ # @@data[MASSC][:good][:rimjoist ][:mat]["172"] = 0.500
907
+ # @@data[MASSC][:good][:parapet ][:mat][ "57"] = 3.300
908
+ # @@data[MASSC][:good][:parapet ][:mat]["139"] = 1.000
909
+ # @@data[MASSC][:good][:head ][:mat]["139"] = 0.500
910
+ # @@data[MASSC][:good][:jamb ][:mat]["139"] = 0.500
911
+ # @@data[MASSC][:good][:sill ][:mat]["139"] = 0.500
912
+ # @@data[MASSC][:good][:corner ][:mat][ "0"] = 1.000
913
+ # @@data[MASSC][:good][:balcony ][:mat][ ""] = 1.000
914
+ # @@data[MASSC][:good][:party ][:mat][ ""] = 1.000
915
+ # @@data[MASSC][:good][:grade ][:mat]["192"] = 1.000
916
+ # @@data[MASSC][:good][:grade ][:mat]["139"] = 1.000
917
+ # @@data[MASSC][:good][:joint ][:mat][ ""] = 1.000
918
+ # @@data[MASSC][:good][:transition ][:mat][ ""] = 1.000
919
+
920
+ @@data[MTAL1][ :bad][:id ] = MTAL1_BAD
921
+ # @@data[MTAL1][ :bad][:rimjoist ][:mat][ "0"] = 1.000
922
+ # @@data[MTAL1][ :bad][:parapet ][:mat][ "0"] = 1.000
923
+ # @@data[MTAL1][ :bad][:head ][:mat]["139"] = 1.000
924
+ # @@data[MTAL1][ :bad][:jamb ][:mat]["139"] = 1.000
925
+ # @@data[MTAL1][ :bad][:sill ][:mat]["139"] = 1.000
926
+ # @@data[MTAL1][ :bad][:corner ][:mat]["191"] = 1.000
927
+ # @@data[MTAL1][ :bad][:balcony ][:mat][ ""] = 1.000
928
+ # @@data[MTAL1][ :bad][:party ][:mat][ ""] = 1.000
929
+ # @@data[MTAL1][ :bad][:grade ][:mat]["139"] = 0.500
930
+ # @@data[MTAL1][ :bad][:joint ][:mat][ ""] = 1.000
931
+ # @@data[MTAL1][ :bad][:transition ][:mat][ ""] = 1.000
932
+
933
+ @@data[MTAL1][:good][:id ] = MTAL1_GOOD
934
+ # @@data[MTAL1][:good][:rimjoist ][:mat][ "0"] = 1.000
935
+ # @@data[MTAL1][:good][:parapet ][:mat][ "57"] = 3.300
936
+ # @@data[MTAL1][:good][:parapet ][:mat]["139"] = 1.000
937
+ # @@data[MTAL1][:good][:head ][:mat]["139"] = 0.500
938
+ # @@data[MTAL1][:good][:jamb ][:mat]["139"] = 0.500
939
+ # @@data[MTAL1][:good][:sill ][:mat]["139"] = 0.500
940
+ # @@data[MTAL1][:good][:corner ][:mat]["191"] = 1.000
941
+ # @@data[MTAL1][:good][:balcony ][:mat][ ""] = 1.000
942
+ # @@data[MTAL1][:good][:party ][:mat][ ""] = 1.000
943
+ # @@data[MTAL1][:good][:grade ][:mat]["192"] = 0.500
944
+ # @@data[MTAL1][:good][:grade ][:mat]["139"] = 0.500
945
+ # @@data[MTAL1][:good][:joint ][:mat][ ""] = 1.000
946
+ # @@data[MTAL1][:good][:transition ][:mat][ ""] = 1.000
947
+
948
+ @@data[MTALD][ :bad][:id ] = MTALD_BAD
949
+ # @@data[MTALD][ :bad][:rimjoist ][:mat][ "0"] = 1.000
950
+ # @@data[MTALD][ :bad][:parapet ][:mat][ "0"] = 1.000
951
+ # @@data[MTALD][ :bad][:head ][:mat]["139"] = 1.000
952
+ # @@data[MTALD][ :bad][:jamb ][:mat]["139"] = 1.000
953
+ # @@data[MTALD][ :bad][:sill ][:mat]["139"] = 1.000
954
+ # @@data[MTALD][ :bad][:corner ][:mat]["191"] = 1.000
955
+ # @@data[MTALD][ :bad][:balcony ][:mat][ ""] = 1.000
956
+ # @@data[MTALD][ :bad][:party ][:mat][ ""] = 1.000
957
+ # @@data[MTALD][ :bad][:grade ][:mat]["139"] = 0.500
958
+ # @@data[MTALD][ :bad][:joint ][:mat][ ""] = 1.000
959
+ # @@data[MTALD][ :bad][:transition ][:mat][ ""] = 1.000
960
+
961
+ @@data[MTALD][:good][:id ] = MTALD_GOOD
962
+ # @@data[MTALD][:good][:rimjoist ][:mat][ "0"] = 1.000
963
+ # @@data[MTALD][:good][:parapet ][:mat][ "57"] = 3.300
964
+ # @@data[MTALD][:good][:parapet ][:mat]["139"] = 1.000
965
+ # @@data[MTALD][:good][:head ][:mat]["139"] = 0.500
966
+ # @@data[MTALD][:good][:jamb ][:mat]["139"] = 0.500
967
+ # @@data[MTALD][:good][:sill ][:mat]["139"] = 0.500
968
+ # @@data[MTALD][:good][:corner ][:mat]["191"] = 1.000
969
+ # @@data[MTALD][:good][:balcony ][:mat][ ""] = 1.000
970
+ # @@data[MTALD][:good][:party ][:mat][ ""] = 1.000
971
+ # @@data[MTALD][:good][:grade ][:mat]["192"] = 0.500
972
+ # @@data[MTALD][:good][:grade ][:mat]["139"] = 0.500
973
+ # @@data[MTALD][:good][:joint ][:mat][ ""] = 1.000
974
+ # @@data[MTALD][:good][:transition ][:mat][ ""] = 1.000
975
+
976
+ @@data[WOOD5][ :bad][:id ] = WOOD5_BAD
977
+ # @@data[WOOD5][ :bad][:rimjoist ][:mat][ "21"] = 1.000
978
+ # @@data[WOOD5][ :bad][:rimjoist ][:mat]["172"] = 0.250
979
+ # @@data[WOOD5][ :bad][:parapet ][:mat][ "0"] = 1.000
980
+ # @@data[WOOD5][ :bad][:head ][:mat][ "0"] = 1.000
981
+ # @@data[WOOD5][ :bad][:jamb ][:mat][ "0"] = 1.000
982
+ # @@data[WOOD5][ :bad][:sill ][:mat][ "0"] = 1.000
983
+ # @@data[WOOD5][ :bad][:corner ][:mat][ "0"] = 1.000
984
+ # @@data[WOOD5][ :bad][:balcony ][:mat][ ""] = 1.000
985
+ # @@data[WOOD5][ :bad][:party ][:mat][ ""] = 1.000
986
+ # @@data[WOOD5][ :bad][:grade ][:mat][ "21"] = 1.000
987
+ # @@data[WOOD5][ :bad][:grade ][:mat]["139"] = 0.500
988
+ # @@data[WOOD5][ :bad][:joint ][:mat][ ""] = 1.000
989
+ # @@data[WOOD5][ :bad][:transition ][:mat][ ""] = 1.000
990
+
991
+ @@data[WOOD5][:good][:id ] = WOOD5_GOOD
992
+ # @@data[WOOD5][:good][:rimjoist ][:mat]["189"] = 1.000
993
+ # @@data[WOOD5][:good][:rimjoist ][:mat]["172"] = 0.500
994
+ # @@data[WOOD5][:good][:parapet ][:mat]["190"] = 0.500
995
+ # @@data[WOOD5][:good][:head ][:mat][ "0"] = 1.000
996
+ # @@data[WOOD5][:good][:jamb ][:mat][ "0"] = 1.000
997
+ # @@data[WOOD5][:good][:sill ][:mat][ "0"] = 1.000
998
+ # @@data[WOOD5][:good][:corner ][:mat][ "0"] = 1.000
999
+ # @@data[WOOD5][:good][:balcony ][:mat][ ""] = 1.000
1000
+ # @@data[WOOD5][:good][:party ][:mat][ ""] = 1.000
1001
+ # @@data[WOOD5][:good][:grade ][:mat]["189"] = 1.000
1002
+ # @@data[WOOD5][:good][:grade ][:mat]["139"] = 0.500
1003
+ # @@data[WOOD5][:good][:grade ][:mat]["192"] = 0.500
1004
+ # @@data[WOOD5][:good][:joint ][:mat][ ""] = 1.000
1005
+ # @@data[WOOD5][:good][:transition ][:mat][ ""] = 1.000
1006
+
1007
+ @@data[WOOD7][ :bad][:id ] = WOOD7_BAD
1008
+ # @@data[WOOD7][ :bad][:rimjoist ][:mat][ "21"] = 1.000
1009
+ # @@data[WOOD7][ :bad][:rimjoist ][:mat]["172"] = 0.250
1010
+ # @@data[WOOD7][ :bad][:parapet ][:mat][ "0"] = 1.000
1011
+ # @@data[WOOD7][ :bad][:head ][:mat][ "0"] = 1.000
1012
+ # @@data[WOOD7][ :bad][:jamb ][:mat][ "0"] = 1.000
1013
+ # @@data[WOOD7][ :bad][:sill ][:mat][ "0"] = 1.000
1014
+ # @@data[WOOD7][ :bad][:corner ][:mat][ "0"] = 1.000
1015
+ # @@data[WOOD7][ :bad][:balcony ][:mat][ ""] = 1.000
1016
+ # @@data[WOOD7][ :bad][:party ][:mat][ ""] = 1.000
1017
+ # @@data[WOOD7][ :bad][:grade ][:mat][ "21"] = 1.000
1018
+ # @@data[WOOD7][ :bad][:grade ][:mat]["139"] = 0.500
1019
+ # @@data[WOOD7][ :bad][:joint ][:mat][ ""] = 1.000
1020
+ # @@data[WOOD7][ :bad][:transition ][:mat][ ""] = 1.000
1021
+
1022
+ @@data[WOOD7][:good][:id ] = WOOD7_GOOD
1023
+ # @@data[WOOD7][:good][:rimjoist ][:mat]["189"] = 1.000
1024
+ # @@data[WOOD7][:good][:rimjoist ][:mat]["172"] = 0.500
1025
+ # @@data[WOOD7][:good][:parapet ][:mat]["190"] = 0.500
1026
+ # @@data[WOOD7][:good][:head ][:mat][ "0"] = 1.000
1027
+ # @@data[WOOD7][:good][:jamb ][:mat][ "0"] = 1.000
1028
+ # @@data[WOOD7][:good][:sill ][:mat][ "0"] = 1.000
1029
+ # @@data[WOOD7][:good][:corner ][:mat][ "0"] = 1.000
1030
+ # @@data[WOOD7][:good][:balcony ][:mat][ ""] = 1.000
1031
+ # @@data[WOOD7][:good][:party ][:mat][ ""] = 1.000
1032
+ # @@data[WOOD7][:good][:grade ][:mat]["189"] = 1.000
1033
+ # @@data[WOOD7][:good][:grade ][:mat]["139"] = 0.500
1034
+ # @@data[WOOD7][:good][:grade ][:mat]["192"] = 0.500
1035
+ # @@data[WOOD7][:good][:joint ][:mat][ ""] = 1.000
1036
+ # @@data[WOOD7][:good][:transition ][:mat][ ""] = 1.000
1037
+
1038
+ @@data[STEL1][ :bad][:id ] = STEL1_BAD
1039
+ # @@data[STEL1][ :bad][:rimjoist ][:mat]["139"] = 10.000
1040
+ # @@data[STEL1][ :bad][:parapet ][:mat][ "0"] = 1.000
1041
+ # @@data[STEL1][ :bad][:head ][:mat]["139"] = 0.750
1042
+ # @@data[STEL1][ :bad][:jamb ][:mat]["139"] = 0.750
1043
+ # @@data[STEL1][ :bad][:sill ][:mat]["139"] = 0.750
1044
+ # @@data[STEL1][ :bad][:corner ][:mat][ "0"] = 1.000
1045
+ # @@data[STEL1][ :bad][:balcony ][:mat][ ""] = 1.000
1046
+ # @@data[STEL1][ :bad][:party ][:mat][ ""] = 1.000
1047
+ # @@data[STEL1][ :bad][:grade ][:mat]["139"] = 1.000
1048
+ # @@data[STEL1][ :bad][:joint ][:mat][ ""] = 1.000
1049
+ # @@data[STEL1][ :bad][:transition ][:mat][ ""] = 1.000
1050
+
1051
+ @@data[STEL1][:good][:id ] = STEL1_GOOD
1052
+ # @@data[STEL1][:good][:rimjoist ][:mat]["172"] = 0.500
1053
+ # @@data[STEL1][:good][:parapet ][:mat][ "57"] = 3.300
1054
+ # @@data[STEL1][:good][:parapet ][:mat]["139"] = 1.000
1055
+ # @@data[STEL1][:good][:head ][:mat]["139"] = 0.500
1056
+ # @@data[STEL1][:good][:jamb ][:mat]["139"] = 0.500
1057
+ # @@data[STEL1][:good][:sill ][:mat]["139"] = 0.500
1058
+ # @@data[STEL1][:good][:corner ][:mat][ "0"] = 1.000
1059
+ # @@data[STEL1][:good][:balcony ][:mat][ ""] = 1.000
1060
+ # @@data[STEL1][:good][:party ][:mat][ ""] = 1.000
1061
+ # @@data[STEL1][:good][:grade ][:mat]["192"] = 1.000
1062
+ # @@data[STEL1][:good][:grade ][:mat]["139"] = 1.000
1063
+ # @@data[STEL1][:good][:joint ][:mat][ ""] = 1.000
1064
+ # @@data[STEL1][:good][:transition ][:mat][ ""] = 1.000
1065
+
1066
+ @@data[STEL2][ :bad][:id ] = STEL2_BAD
1067
+ # @@data[STEL2][ :bad][:rimjoist ][:mat]["139"] = 10.000
1068
+ # @@data[STEL2][ :bad][:parapet ][:mat][ "0"] = 1.000
1069
+ # @@data[STEL2][ :bad][:head ][:mat]["139"] = 0.750
1070
+ # @@data[STEL2][ :bad][:jamb ][:mat]["139"] = 0.750
1071
+ # @@data[STEL2][ :bad][:sill ][:mat]["139"] = 0.750
1072
+ # @@data[STEL2][ :bad][:corner ][:mat][ "0"] = 1.000
1073
+ # @@data[STEL2][ :bad][:balcony ][:mat][ ""] = 1.000
1074
+ # @@data[STEL2][ :bad][:party ][:mat][ ""] = 1.000
1075
+ # @@data[STEL2][ :bad][:grade ][:mat]["139"] = 1.000
1076
+ # @@data[STEL2][ :bad][:joint ][:mat][ ""] = 1.000
1077
+ # @@data[STEL2][ :bad][:transition ][:mat][ ""] = 1.000
1078
+
1079
+ @@data[STEL2][:good][:id ] = STEL2_GOOD
1080
+ # @@data[STEL2][:good][:rimjoist ][:mat]["172"] = 0.500
1081
+ # @@data[STEL2][:good][:parapet ][:mat]["206"] = 1.000
1082
+ # @@data[STEL2][:good][:head ][:mat]["139"] = 0.500
1083
+ # @@data[STEL2][:good][:jamb ][:mat]["139"] = 0.500
1084
+ # @@data[STEL2][:good][:sill ][:mat]["139"] = 0.500
1085
+ # @@data[STEL2][:good][:corner ][:mat][ "0"] = 1.000
1086
+ # @@data[STEL2][:good][:balcony ][:mat][ ""] = 1.000
1087
+ # @@data[STEL2][:good][:party ][:mat][ ""] = 1.000
1088
+ # @@data[STEL2][:good][:grade ][:mat]["192"] = 1.000
1089
+ # @@data[STEL2][:good][:grade ][:mat]["139"] = 1.000
1090
+ # @@data[STEL2][:good][:joint ][:mat][ ""] = 1.000
1091
+ # @@data[STEL2][:good][:transition ][:mat][ ""] = 1.000
1092
+
1093
+ ##
1094
+ # Retrieve TBD building/space type keyword.
1095
+ #
1096
+ # @param spacetype [String] NECB (or other) building/space type
1097
+ # @param stories [Integer] number of building stories
1098
+ #
1099
+ # @return [Symbol] matching TBD keyword (:office if failure)
1100
+ def sptype(spacetype = "", stories = 999)
1101
+ tp = spacetype.downcase
1102
+ typ = :office
1103
+
1104
+ return typ unless stories.is_a?(Integer) && stories.between?(1,999)
1105
+
1106
+ typ = :exercise if tp.include?("exercise" )
1107
+ typ = :firestation if tp.include?("fire" )
1108
+ typ = :gym if tp.include?("gym" )
1109
+ typ = :gym if tp.include?("locker" )
1110
+ typ = :courthouse if tp.include?("courthouse" )
1111
+ typ = :courtrhouse if tp.include?("courtroom" )
1112
+ typ = :museum if tp.include?("museum" )
1113
+ typ = :parking if tp.include?("parking" )
1114
+ typ = :post if tp.include?("post" )
1115
+ typ = :transportation if tp.include?("transp" )
1116
+ typ = :transportation if tp.include?("maintenance" )
1117
+ typ = :automotive if tp.include?("automotive" )
1118
+ typ = :penitentiary if tp.include?("penitentiary" )
1119
+ typ = :penitentiary if tp.include?("confinement" )
1120
+ typ = :arena if tp.include?("arena" )
1121
+ typ = :warehouse if tp.include?("warehouse" )
1122
+ typ = :storage if tp.include?("storage" )
1123
+ typ = :mfg if tp.include?("mfg" )
1124
+ typ = :mfg if tp.include?("manufacturing")
1125
+ typ = :mfg if tp.include?("loading" )
1126
+ typ = :workshop if tp.include?("workshop" )
1127
+ typ = :religious if tp.include?("religious" )
1128
+ typ = :dwelling5 if tp.include?("dorm" )
1129
+ typ = :dwelling5 if tp.include?("otel" )
1130
+ typ = :dwelling5 if tp.include?("residential" )
1131
+ typ = :dwelling5 if tp.include?("long-term" )
1132
+ typ = :dwelling5 if tp.include?("dwelling" )
1133
+ typ = :dwelling5 if tp.include?("lodging" )
1134
+ typ = :dwelling5 if tp.include?("RP-28" )
1135
+ typ = :dwelling5 if tp.include?("guest" )
1136
+ typ = :dwelling if tp.include?("dorm" ) && stories < 5
1137
+ typ = :dwelling if tp.include?("otel" ) && stories < 5
1138
+ typ = :dwelling if tp.include?("residential" ) && stories < 5
1139
+ typ = :dwelling if tp.include?("long-term" ) && stories < 5
1140
+ typ = :dwelling if tp.include?("dwelling" ) && stories < 5
1141
+ typ = :dwelling if tp.include?("lodging" ) && stories < 5
1142
+ typ = :dwelling if tp.include?("RP-28" ) && stories < 5
1143
+ typ = :dwelling if tp.include?("guest" ) && stories < 5
1144
+ typ = :library3 if tp.include?("library" )
1145
+ typ = :library if tp.include?("library" ) && stories < 3
1146
+ typ = :school3 if tp.include?("school" )
1147
+ typ = :school3 if tp.include?("classroom" )
1148
+ typ = :school3 if tp.include?("lab" )
1149
+ typ = :school3 if tp.include?("auditorium" )
1150
+ typ = :school if tp.include?("school" ) && stories < 3
1151
+ typ = :school if tp.include?("classroom" ) && stories < 3
1152
+ typ = :school if tp.include?("lab" ) && stories < 3
1153
+ typ = :school if tp.include?("auditorium" ) && stories < 3
1154
+ typ = :convention if tp.include?("convention" )
1155
+ typ = :dining if tp.include?("dining" )
1156
+ typ = :dining if tp.include?("food" )
1157
+ typ = :health if tp.include?("health" )
1158
+ typ = :hospital if tp.include?("hospital" )
1159
+ typ = :hospital if tp.include?("emergency" )
1160
+ typ = :hospital if tp.include?("laundry" )
1161
+ typ = :hospital if tp.include?("pharmacy" )
1162
+ typ = :motion if tp.include?("motion" )
1163
+ typ = :performance if tp.include?("perform" )
1164
+ typ = :police if tp.include?("police" )
1165
+ typ = :retail if tp.include?("retail" )
1166
+ typ = :retail if tp.include?("sales" )
1167
+ typ = :town if tp.include?("town" )
1168
+
1169
+ typ
1170
+ end
1171
+
1172
+ ##
1173
+ # Retrieve building/space type-specific assembly/construction.
1174
+ #
1175
+ # @param spacetype [Symbol] BTAP/TBD spacetype
1176
+ # @param stype [Symbol] :walls, :floors or :roofs
1177
+ # @param performance [Symbol] :lp (low-) or :hp (high-performance)
1178
+ #
1179
+ # @return [String] corresponding BTAP construction (STEL2 if fail)
1180
+ def assembly(spacetype = :office, stype = :walls, performance = :hp)
1181
+ return FLOOR if stype == :floors
1182
+ return ROOFS if stype == :roofs
1183
+
1184
+ @@data.each do |id, construction|
1185
+ next unless construction.key?(performance)
1186
+ return id if construction[:sptypes].key?(spacetype)
1187
+ end
1188
+
1189
+ STEL2
1190
+ end
1191
+
1192
+ ##
1193
+ # Retrieve assembly-specific PSI factor set.
1194
+ #
1195
+ # @param assembly [String] BTAP/TBD wall construction
1196
+ # @param quality [Symbol] BTAP/TBD PSI quality (:bad or :good)
1197
+ #
1198
+ # @return [Hash] BTAP/TBD PSI factor set (defaults to STEL2, :good)
1199
+ def set(assembly = STEL2, quality = :good)
1200
+ psi = {}
1201
+ chx = @@data[STEL2][:good ]
1202
+ chx = @@data[STEL2][quality] if @@data[STEL2 ].key?(quality)
1203
+
1204
+ if @@data.key?(assembly)
1205
+ chx = @@data[assembly][quality] if @@data[assembly].key?(quality)
1206
+ chx = @@data[assembly][:good ] unless @@data[assembly].key?(quality)
1207
+ end
1208
+
1209
+ psi[:id ] = chx[:id ]
1210
+ psi[:rimjoist ] = chx[:rimjoist ][:psi]
1211
+ psi[:parapet ] = chx[:parapet ][:psi]
1212
+ psi[:head ] = chx[:head ][:psi]
1213
+ psi[:jamb ] = chx[:jamb ][:psi]
1214
+ psi[:sill ] = chx[:sill ][:psi]
1215
+ psi[:corner ] = chx[:corner ][:psi]
1216
+ psi[:balcony ] = chx[:balcony ][:psi]
1217
+ psi[:party ] = chx[:party ][:psi]
1218
+ psi[:grade ] = chx[:grade ][:psi]
1219
+ psi[:joint ] = chx[:joint ][:psi]
1220
+ psi[:transition] = chx[:transition][:psi]
1221
+
1222
+ psi
1223
+ end
1224
+
1225
+ ##
1226
+ # Return BTAP/TBD data.
1227
+ #
1228
+ # @return [Hash] preset BTAP/TBD data
1229
+ def data
1230
+ @@data
1231
+ end
1232
+
1233
+ def self.extended(base)
1234
+ base.send(:include, self)
1235
+ end
1236
+ end
1237
+
1238
+ class BTAP::Bridging
1239
+ extend BridgingData
1240
+
1241
+ TOL = TBD::TOL
1242
+ TOL2 = TBD::TOL2
1243
+ DBG = TBD::DBG
1244
+ INF = TBD::INF
1245
+ WRN = TBD::WRN
1246
+ ERR = TBD::ERR
1247
+ FTL = TBD::FTL
1248
+
1249
+ # @return [Hash] BTAP/TBD Hash, specific to an OpenStudio model
1250
+ attr_reader :model
1251
+
1252
+ # @return [Hash] logged messages TBD reports back to BTAP
1253
+ attr_reader :feedback
1254
+
1255
+ # @return [Hash] TBD tallies e.g. total lengths of linear thermal bridges
1256
+ attr_reader :tally
1257
+
1258
+ ##
1259
+ # Initialize OpenStudio model-specific BTAP/TBD data - uprates/derates.
1260
+ #
1261
+ # @param model [OpenStudio::Model::Model] a model
1262
+ # @param argh [Hash] BTAP/TBD argument hash
1263
+ def initialize(model = nil, argh = {})
1264
+ @model = {}
1265
+ @tally = {}
1266
+ @feedback = { logs: [] }
1267
+ lgs = @feedback[:logs]
1268
+
1269
+ # BTAP generates free-floating, unoccupied spaces (e.g. attics) as
1270
+ # 'indirectly conditioned', rather than 'unconditioned' (e.g. vented
1271
+ # attics). For instance, all outdoor-facing sloped roof surfaces of an
1272
+ # attic in BTAP are insulated, while attic floors remain uninsulated. BTAP
1273
+ # adds to the thermal zone of each unoccupied space a thermostat without
1274
+ # referecing heating and/or cooling setpoint schedule objects. These
1275
+ # conditions do not meet TBD's internal 'plenum' logic/check (which is
1276
+ # based on OpenStudio-Standards), and so TBD ends up tagging such spaces
1277
+ # as unconditioned. Consequently, TBD attempts to up/de-rate attic floors
1278
+ # - not sloped roof surfaces. The original BTAP solution will undoubtedly
1279
+ # need revision. In the meantime, and in an effort to harmonize TBD with
1280
+ # BTAP's current approach, an OpenStudio model may be temporarily
1281
+ # modified prior to TBD processes, ensuring that each attic space is
1282
+ # temporarily mistaken as a conditioned plenum. The return variable of the
1283
+ # following method is a Hash holding temporarily-modified spaces,
1284
+ # i.e. buffer zones.
1285
+ buffers = self.alter_buffers(model)
1286
+
1287
+ # Populate BTAP/TBD inputs with BTAP & OpenStudio model parameters,
1288
+ # which returns 'true' if successful. Check @feedback logs if failure to
1289
+ # populate (e.g. invalid argument hash, invalid OpenStudio model).
1290
+ return unless self.populate(model, argh)
1291
+
1292
+ # Initialize loop counters, controls and flags.
1293
+ initial = true
1294
+ comply = false
1295
+ redflag = false
1296
+ perform = :lp # Low-performance wall constructions
1297
+ quality = :bad # default PSI factors - BTAP users can reset to :good
1298
+ quality = :good if argh.key?(:quality) && argh[:quality] == :good
1299
+ combo = "#{perform.to_s}_#{quality.to_s}".to_sym # e.g. :lp_bad
1300
+ args = {} # initialize native TBD arguments
1301
+
1302
+ # If uprating, initialize native TBD args.
1303
+ [:walls, :floors, :roofs].each do |stypes|
1304
+ next if @model[stypes].empty?
1305
+ next unless argh.key?(stypes)
1306
+ next unless argh[stypes].key?(:ut)
1307
+
1308
+ ut = argh[stypes][:ut]
1309
+ ok = ut.is_a?(Numeric) && ut.between?(UMIN, UMAX)
1310
+ lgs << "Invalid BTAP/TBD #{stypes} Ut" unless ok
1311
+ next unless ok
1312
+
1313
+ stype = stypes.to_s.chop
1314
+ uprate = "uprate_#{stypes.to_s}".to_sym
1315
+ option = "#{stype}_option".to_sym
1316
+ ut = "#{stype}_ut".to_sym
1317
+
1318
+ args[uprate] = true
1319
+ args[option] = "ALL #{stype} constructions"
1320
+ args[ut ] = ut
1321
+ end
1322
+
1323
+ args[:io_path] = @model[combo] # contents of a "tbd.json" file
1324
+ args[:option ] = "" # safeguard
1325
+
1326
+ loop do
1327
+ if initial
1328
+ initial = false
1329
+ else
1330
+ # Subsequent runs. Upgrade technologies. Reset TBD args.
1331
+ if quality == :bad
1332
+ quality = :good
1333
+ combo = "#{perform.to_s}_#{quality.to_s}".to_sym
1334
+ args[:io_path] = @model[combo]
1335
+ elsif perform == :lp
1336
+ # Switch 'perform' from :lp to :hp - reset quality to :bad.
1337
+ perform = :hp
1338
+ quality = :bad
1339
+ combo = "#{perform.to_s}_#{quality.to_s}".to_sym
1340
+ args[:io_path] = @model[combo]
1341
+ end
1342
+ end
1343
+
1344
+ # Run TBD on cloned OpenStudio models until compliant.
1345
+ mdl = OpenStudio::Model::Model.new
1346
+ mdl.addObjects(model.toIdfFile.objects)
1347
+ TBD.clean!
1348
+ res = TBD.process(mdl, args)
1349
+
1350
+ if TBD.status.zero?
1351
+ comply = true
1352
+ else
1353
+ # TBD logs warnings and non/fatal errors when 'processing'
1354
+ # OpenStudio models, often when faced with invalid OpenStudio
1355
+ # objects that may not be necessarily flagged by OpenStudio
1356
+ # Standards and/or by BTAP. Examples could include subsurfaces not
1357
+ # fitting neatly within a host surface, (slight) overlaps between
1358
+ # subsurfaces, 5-sided windows, and so on. TBD typically logs such
1359
+ # non-fatal errors, ignores the faulty object, and otherwise pursues
1360
+ # its calculations. It would usually be up to BTAP users to decide
1361
+ # how to proceed when faced with most non-fatal errors. However,
1362
+ # when it comes ultimately to failed attempts by TBD to 'uprate'
1363
+ # constructions of an OpenStudio model for NECB compliance, BTAP
1364
+ # should definitely skip to the next loop iteration.
1365
+ unable = false
1366
+
1367
+ TBD.logs.each do |log|
1368
+ break if unable
1369
+
1370
+ unable = log[:message].include?("Unable to uprate ")
1371
+ break if unable
1372
+
1373
+ unable = log[:message].include?("Can't uprate " )
1374
+ end
1375
+
1376
+ if unable
1377
+ # puts # TEMPORARY for debugging
1378
+ # puts "¨¨¨ combo : #{combo}"
1379
+ # puts args[:io_path][:psis]
1380
+ # TBD.logs.each { |lg| puts lg }
1381
+ # puts
1382
+ else
1383
+ comply = true
1384
+ end
1385
+ end
1386
+
1387
+ if comply
1388
+ # Not completely out of the woods yet for uprated cases. Despite
1389
+ # having TBD identify a winning combination, determine if BTAP holds
1390
+ # admissible Uo values (see lines ~245, :uos key). If TBD-estimated
1391
+ # Uo is lower than any of these admissible BTAP Uo factors, then no
1392
+ # commercially available solution has been identified. Reset "comply"
1393
+ # to "false", and loop again (until TBD-reported Uo is above or equal
1394
+ # to any of the BTAP Uo factors). This needs revisiting once BTAP
1395
+ # enables building-type construction selection.
1396
+ [:walls, :floors, :roofs].each do |stypes|
1397
+ break unless comply
1398
+ next if @model[stypes].empty?
1399
+ next unless argh.key?(stypes)
1400
+ next unless argh[stypes].key?(:ut)
1401
+
1402
+ ut = argh[stypes][:ut]
1403
+ stype_uo = "#{stypes.to_s.chop}_uo".to_sym
1404
+
1405
+ # If successul, TBD adds a building-wide uprated Uo factor to its
1406
+ # native input arguments, e.g. "walls_uo". Reject if missing.
1407
+ comply = false unless args.key?(stype_uo)
1408
+ break unless args.key?(stype_uo)
1409
+
1410
+ # Safeguard. TBD should never generate uprated Uo > required Ut.
1411
+ ok = args[stype_uo] < ut || (args[stype_uo] - ut).abs < 0.001
1412
+ comply = false unless ok
1413
+ break unless ok
1414
+
1415
+ # Check if within range of BTAP commercially-available options, for:
1416
+ # - walls, floors & roofs
1417
+ # - specific to each space type
1418
+ @model[:sptypes].each do |id, spacetype|
1419
+ uo_sptype = nil
1420
+ break unless comply
1421
+ next unless spacetype.key?(stypes)
1422
+ next unless spacetype[stypes].key?(perform) # :lp or :hp
1423
+
1424
+ construction = spacetype[stypes][perform]
1425
+ next unless @@data.key?(construction)
1426
+ next unless @@data[construction].key?(:uos)
1427
+
1428
+ # puts
1429
+ # puts "required Uo for #{id} #{stypes}: #{args[stype_uo]}"
1430
+ # puts
1431
+
1432
+ @@data[construction][:uos].keys.each do |u|
1433
+ uo = u.to_f / 1000
1434
+ ok = uo < args[stype_uo] || (uo - args[stype_uo]).abs < 0.001
1435
+ next unless ok
1436
+
1437
+ uo_sptype = uo # winning combo?
1438
+ @model[:constructions] = {} unless @model.key?(:constructions)
1439
+ @model[:constructions][construction] = { uo: uo }
1440
+ break
1441
+ end
1442
+
1443
+ next unless uo_sptype.nil?
1444
+
1445
+ comply = false
1446
+ val = format("%.3f", args[stype_uo])
1447
+ lgs << "... required Uo for #{stypes}: #{val}"
1448
+ end
1449
+ end
1450
+ end
1451
+
1452
+ # Conditional break from the 'loop'.
1453
+ if comply
1454
+ break
1455
+ elsif combo == :hp_good
1456
+ # i.e. TBD's uprating features are requested, yet unable to locate
1457
+ # either a physically- or economically-plausible Uo + PSI combo.
1458
+ redflag = true
1459
+ comply = true # (temporarily) signal compliance
1460
+ lgs << "REDFLAG: no Ut-compliant TBD combo"
1461
+
1462
+ [:walls, :floors, :roofs].each do |stypes|
1463
+ next unless argh.key?(stypes)
1464
+ next unless argh[stypes].key?(:ut)
1465
+
1466
+ groups = {}
1467
+ stype = stypes.to_s.chop
1468
+ uprate = "uprate_#{stypes.to_s}".to_sym
1469
+ option = "#{stype}_option".to_sym
1470
+ ut = "#{stype}_ut".to_sym
1471
+
1472
+ # Cancel uprating request before derating.
1473
+ args.delete(uprate)
1474
+ args.delete(option)
1475
+ args.delete(ut )
1476
+
1477
+ # Group BTAP constructions based on lowest Uo factors e.g.:
1478
+ # - 0.130 for WOOD7
1479
+ # - 0.080 for STEL2
1480
+ # - 0.100 for all ROOFS
1481
+ @model[stypes].each do |id, type|
1482
+ next unless type.key?(:sptype)
1483
+
1484
+ spacetype = type[:sptype] # e.g. :office
1485
+ next unless @model[:sptypes].key?(spacetype)
1486
+ next unless @model[:sptypes][spacetype].key?(stypes)
1487
+ next unless @model[:sptypes][spacetype][stypes].key?(perform)
1488
+
1489
+ construction = @model[:sptypes][spacetype][stypes][perform]
1490
+ next unless @@data.key?(construction)
1491
+ next unless @@data[construction].key?(:uos)
1492
+
1493
+ uos = []
1494
+ @@data[construction][:uos].keys.each { |u| uos << u.to_f / 1000 }
1495
+ uo = uos.min
1496
+ @model[:constructions] = {} unless @model.key?(:constructions)
1497
+ @model[:constructions][construction] = { uo: uo }
1498
+
1499
+ exists = groups.key?(construction)
1500
+ groups[construction] = { uo: uo, faces: [] } unless exists
1501
+ surface = model.getSurfaceByName(id)
1502
+ next if surface.empty?
1503
+
1504
+ groups[construction][:faces] << surface.get
1505
+ end
1506
+
1507
+ groups.each do |id, group|
1508
+ # puts
1509
+ # puts "#{id} : #{stypes} : #{group[:uo]}: #{group[:faces].size}x"
1510
+ # group[:faces].each { |s| puts s.nameString }
1511
+ sss = BTAP::Geometry::Surfaces.set_surfaces_construction_conductance(group[:faces], group[:uo])
1512
+ # puts
1513
+ #
1514
+ # sss.each do |ssss|
1515
+ # lc = ssss.construction.get.to_LayeredConstruction.get
1516
+ # usi = 1 / TBD.rsi(lc, ssss.filmResistance)
1517
+ # puts "#{ssss.construction.get.nameString} : #{usi}"
1518
+ # end
1519
+ #
1520
+ # puts "~~~~~~~~~~"
1521
+ # puts
1522
+ end
1523
+ end
1524
+
1525
+ comply = true # temporary
1526
+ break
1527
+ end
1528
+ end
1529
+
1530
+ @model[:comply ] = comply
1531
+ @model[:perform] = perform
1532
+ @model[:quality] = quality
1533
+ @model[:combo ] = combo
1534
+
1535
+ if comply
1536
+ # Run "process" TBD (with last generated args Hash) one last time on
1537
+ # "model" (not cloned "mdl"). This may uprate (if applicable ... unless
1538
+ # redflagged), then derate BTAP above-grade surface constructions before
1539
+ # simulation.
1540
+ TBD.clean!
1541
+ res = TBD.process(model, args)
1542
+
1543
+ # puts # TEMPORARY
1544
+ # puts args[:io_path][:psis]
1545
+ # puts
1546
+
1547
+ @model[:comply ] = false if redflag
1548
+ @model[:io ] = res[:io ] # TBD outputs (i.e. "tbd.out.json")
1549
+ @model[:surfaces] = res[:surfaces] # TBD derated surface data
1550
+ @model[:args ] = args # last TBD inputs (i.e. "tbd.json")
1551
+
1552
+ self.gen_tallies # tallies for BTAP costing
1553
+ self.gen_feedback # log success messages for BTAP
1554
+ end
1555
+
1556
+ self.purge_buffer_schedules(model, buffers)
1557
+ end
1558
+
1559
+ ##
1560
+ # Modify BTAP-generated 'buffer zones' (e.g. attics) to ensure TBD tags
1561
+ # these as indirectly conditioned spaces (e.g. plenums).
1562
+ #
1563
+ # @param model [OpenStudio::Model::Model] a model
1564
+ #
1565
+ # @return [Array] identifiers of modified buffer spaces in model
1566
+ def alter_buffers(model = nil)
1567
+ buffers = []
1568
+ sched = nil
1569
+ lgs = @feedback[:logs]
1570
+ cl = OpenStudio::Model::Model
1571
+ lgs << "Invalid OpenStudio model (buffers)" unless model.is_a?(cl)
1572
+ return buffers unless model.is_a?(cl)
1573
+
1574
+ model.getSpaces.each do |space|
1575
+ next if space.partofTotalFloorArea
1576
+ next if space.thermalZone.empty?
1577
+
1578
+ id = space.nameString
1579
+ zone = space.thermalZone.get
1580
+ next if zone.isPlenum
1581
+ next if zone.thermostat.empty?
1582
+
1583
+ tstat = zone.thermostat.get
1584
+ staged = tstat.respond_to?(:heatingTemperatureSetpointSchedule)
1585
+ tstat = tstat.to_ZoneControlThermostatStagedDualSetpoint.get if staged
1586
+ tstat = tstat.to_ThermostatSetpointDualSetpoint.get unless staged
1587
+
1588
+ if sched.nil?
1589
+ name = "TBD attic setpoint sched"
1590
+ sched = OpenStudio::Model::ScheduleCompact.new(model)
1591
+ sched.setName(name)
1592
+ end
1593
+
1594
+ tstat.setHeatingTemperatureSetpointSchedule(sched) if staged
1595
+ tstat.setHeatingSetpointTemperatureSchedule(sched) unless staged
1596
+
1597
+ buffers << id
1598
+ end
1599
+
1600
+ buffers
1601
+ end
1602
+
1603
+ ##
1604
+ # Remove previously BTAP/TBD-added heating setpoint schedules for 'buffer
1605
+ # zones' (e.g. attics).
1606
+ #
1607
+ # @param model [OpenStudio::Model::Model] a model
1608
+ # @param buffers [Array] identifiers of modified buffer spaces in model
1609
+ #
1610
+ # @return [Bool] true if successful
1611
+ def purge_buffer_schedules(model = nil, buffers = [])
1612
+ scheds = []
1613
+ lgs = @feedback[:logs]
1614
+ cl = OpenStudio::Model::Model
1615
+ lgs << "Invalid OpenStudio model (purge)" unless model.is_a?(cl)
1616
+ lgs << "Invalid BTAP/TBD buffers" unless buffers.is_a?(Array)
1617
+ return false unless model.is_a?(cl)
1618
+ return false unless buffers.is_a?(Array)
1619
+
1620
+ buffers.each do |id|
1621
+ space = model.getSpaceByName(id)
1622
+ next if space.empty?
1623
+
1624
+ space = space.get
1625
+ next if space.thermalZone.empty?
1626
+
1627
+ zone = space.thermalZone.get
1628
+ next if zone.thermostat.empty?
1629
+
1630
+ tstat = zone.thermostat.get
1631
+ staged = tstat.respond_to?(:heatingTemperatureSetpointSchedule)
1632
+ tstat = tstat.to_ZoneControlThermostatStagedDualSetpoint.get if staged
1633
+ tstat = tstat.to_ThermostatSetpointDualSetpoint.get unless staged
1634
+ sched = tstat.heatingTemperatureSetpointSchedule if staged
1635
+ sched = tstat.heatingSetpointTemperatureSchedule unless staged
1636
+ next if sched.empty?
1637
+
1638
+ sched = sched.get
1639
+ scheds << sched.nameString
1640
+ tstat.resetHeatingSetpointTemperatureSchedule unless staged
1641
+ tstat.resetHeatingTemperatureSetpointSchedule if staged
1642
+ end
1643
+
1644
+ scheds.each do |sched|
1645
+ schd = model.getScheduleByName(sched)
1646
+ next if schd.empty?
1647
+ schd = schd.get
1648
+ schd.remove
1649
+ end
1650
+
1651
+ true
1652
+ end
1653
+
1654
+ ##
1655
+ # Fetch min U-factor of outdoor-facing OpenStudio model surface types.
1656
+ #
1657
+ # @param model [OpenStudio::Model::Model] a model
1658
+ # @param stype [Symbol] model surface type (e.g. :walls)
1659
+ #
1660
+ # @return [Float] min U factor (default 5.678 W/m2.K)
1661
+ def minU(model = nil, stypes = :walls)
1662
+ u = UMAX
1663
+ lgs = @feedback[:logs]
1664
+ cl = OpenStudio::Model::Model
1665
+ stype = stypes.to_s.chop.downcase
1666
+ ok = stype == "wall" || stype == "floor" || stype == "roof"
1667
+ stype = "wall" unless ok
1668
+ lgs << "Invalid OpenStudio model (#{stypes} minU)" unless model.is_a?(cl)
1669
+ return u unless model.is_a?(cl)
1670
+
1671
+ model.getSurfaces.each do |s|
1672
+ next unless s.surfaceType.downcase.include?(stype)
1673
+ next unless s.outsideBoundaryCondition.downcase == "outdoors"
1674
+ next if s.construction.empty?
1675
+ next if s.construction.get.to_LayeredConstruction.empty?
1676
+
1677
+ lc = s.construction.get.to_LayeredConstruction.get
1678
+ uo = 1 / TBD.rsi(lc, s.filmResistance)
1679
+
1680
+ u = [uo, u].min
1681
+ end
1682
+
1683
+ # u0 = format("%.3f", u) # TEMPORARY
1684
+ # puts "~~ Extracted #{stypes} minU (#{u0}) W/m2.K from OpenStudio model"
1685
+
1686
+ u
1687
+ end
1688
+
1689
+ ##
1690
+ # Populate BTAP/TBD model with BTAP & OpenStudio model parameters.
1691
+ #
1692
+ # @param model [OpenStudio::Model::Model] a model
1693
+ # @param argh [Hash] BTAP/TBD argument hash
1694
+ #
1695
+ # @return [Bool] true if valid (check @feedback logs if false)
1696
+ def populate(model = nil, argh = {})
1697
+ lgs = @feedback[:logs]
1698
+ cl = OpenStudio::Model::Model
1699
+ args = { option: "(non thermal bridging)" } # for initial TBD dry run
1700
+
1701
+ # Pre-TBD BTAP validatation.
1702
+ lgs << "Invalid BTAP/TBD feedback" unless @feedback.is_a?(Hash)
1703
+ lgs << "Missing BTAP/TBD logs" unless @feedback.key?(:logs)
1704
+ lgs << "Invalid BTAP/TBD logs" unless @feedback[:logs].is_a?(Array)
1705
+ return false unless @feedback.is_a?(Hash)
1706
+ return false unless @feedback.key?(:logs)
1707
+ return false unless @feedback[:logs].is_a?(Array)
1708
+
1709
+ lgs << "Invalid OpenStudio model to de/up-rate" unless model.is_a?(cl)
1710
+ lgs << "Invalid BTAP/TBD argument Hash" unless argh.is_a?(Hash)
1711
+ lgs << "Empty BTAP/TBD argument hash" if argh.empty?
1712
+ return false unless model.is_a?(cl)
1713
+ return false unless argh.is_a?(Hash)
1714
+ return false if argh.empty?
1715
+
1716
+ # Fetch number of stories in OpenStudio model.
1717
+ stories = model.getBuilding.standardsNumberOfAboveGroundStories
1718
+ stories = stories.get unless stories.empty?
1719
+ stories = model.getBuildingStorys.size unless stories.is_a?(Integer)
1720
+
1721
+ @model[:stories] = stories
1722
+ @model[:stories] = 1 if stories < 1
1723
+ @model[:stories] = 999 if stories > 999
1724
+ @model[:spaces ] = {}
1725
+ @model[:sptypes] = {}
1726
+
1727
+ # Run TBD on cloned OpenStudio models (dry run).
1728
+ mdl = OpenStudio::Model::Model.new
1729
+ mdl.addObjects(model.toIdfFile.objects)
1730
+ TBD.clean!
1731
+ res = TBD.process(mdl, args)
1732
+ surfaces = res[:surfaces]
1733
+
1734
+ # TBD validation of OpenStudio model.
1735
+ lgs << "TBD-identified FATAL error(s):" if TBD.fatal?
1736
+ lgs << "TBD-identified non-FATAL error(s):" if TBD.error?
1737
+ TBD.logs.each { |log| lgs << log[:message] } if TBD.fatal? || TBD.error?
1738
+ return false if TBD.fatal?
1739
+
1740
+ lgs << "TBD: no deratable surfaces in model" if surfaces.nil?
1741
+ return false if surfaces.nil?
1742
+
1743
+ # Initialize deratable walls, exposed floors & roofs.
1744
+ [:walls, :floors, :roofs].each { |stypes| @model[stypes] = {} }
1745
+
1746
+ surfaces.each do |id, surface|
1747
+ next unless surface.key?(:type ) # :wall, :floor, :ceiling
1748
+ next unless surface.key?(:space ) # OpenStudio space object
1749
+ next unless surface.key?(:deratable) # true/false
1750
+ next unless surface[:deratable]
1751
+
1752
+ stypes = :walls if surface[:type] == :wall
1753
+ stypes = :floors if surface[:type] == :floor
1754
+ stypes = :roofs if surface[:type] == :ceiling
1755
+ next unless stypes == :walls || stypes == :floors || stypes == :roofs
1756
+
1757
+ space = surface[:space].nameString
1758
+ spacetype = surface[:stype].nameString if surface.key?(:stype)
1759
+ spacetype = "" unless surface.key?(:stype)
1760
+ typ = self.sptype(spacetype, @model[:stories]) # e.g. :office
1761
+
1762
+ # Keep track of individual surface's space and spacetype keyword.
1763
+ @model[stypes][id] = {}
1764
+ @model[stypes][id][:space ] = space
1765
+ @model[stypes][id][:sptype] = typ
1766
+
1767
+ # Keep track of individual spaces and spacetypes.
1768
+ exists = @model[:spaces].key?(space)
1769
+ @model[:spaces][space] = {} unless exists
1770
+ @model[:spaces][space][:sptype] = typ unless exists
1771
+
1772
+ exists = @model[:sptypes].key?(typ)
1773
+ @model[:sptypes][typ ] = {} unless exists
1774
+ @model[:sptypes][typ ][:sptype] = spacetype unless exists
1775
+ next if @model[:sptypes][typ].key?(stypes)
1776
+
1777
+ # Low- vs Hi-Performance BTAP assemblies.
1778
+ lo = self.assembly(typ, stypes, :lp)
1779
+ hi = self.assembly(typ, stypes, :hp)
1780
+ @model[:sptypes][typ][stypes] = {}
1781
+ @model[:sptypes][typ][stypes][:lp] = lo
1782
+ @model[:sptypes][typ][stypes][:hp] = hi
1783
+ next unless stypes == :walls
1784
+
1785
+ # Fetch bad vs good PSI factor sets - strictly a function of walls.
1786
+ @model[:sptypes][typ][:lp_bad ] = self.set(lo, :bad )
1787
+ @model[:sptypes][typ][:lp_good] = self.set(lo, :good)
1788
+ @model[:sptypes][typ][:hp_bad ] = self.set(hi, :bad )
1789
+ @model[:sptypes][typ][:hp_good] = self.set(hi, :good)
1790
+ end
1791
+
1792
+ # Post-TBD validation: BTAP-fed Uo factors, then Ut factors (optional).
1793
+ [:walls, :floors, :roofs].each do |stypes|
1794
+ lgs << "Missing BTAP/TBD #{stypes}" unless argh.key?(stypes)
1795
+ lgs << "Missing BTAP/TBD #{stypes} Uo" unless argh[stypes].key?(:uo)
1796
+ return false unless argh.key?(stypes)
1797
+ return false unless argh[stypes].key?(:uo)
1798
+ next if @model[stypes].empty?
1799
+
1800
+ uo = self.minU(model, stypes)
1801
+ ok = uo.is_a?(Numeric) && uo.between?(UMIN, UMAX)
1802
+ argh[stypes][:uo] = uo if ok
1803
+ next if ok
1804
+
1805
+ lgs << "Invalid BTAP/TBD #{stypes} Uo"
1806
+ return false
1807
+ end
1808
+
1809
+ [:walls, :floors, :roofs].each do |stypes| # Ut optional
1810
+ next unless argh[stypes].key?(:ut)
1811
+ next if @model[stypes].empty?
1812
+
1813
+ ut = self.minU(model, stypes)
1814
+ ok = ut.is_a?(Numeric) && ut.between?(UMIN, UMAX)
1815
+ argh[stypes][:ut] = ut if ok
1816
+ next if ok
1817
+
1818
+ lgs << "Invalid BTAP #{stypes} Ut"
1819
+ return false
1820
+ end
1821
+
1822
+ # Generate native TBD input Hashes for the model, for both :good & :bad
1823
+ # PSI factor sets. The typical TBD use case involves writing out the
1824
+ # contents of either Hash (e.g. JSON::pretty_generate) as a "tbd.json"
1825
+ # input file, to save under a standard OpenStudio "files" folder. At
1826
+ # runtime, TBD then reopens the JSON file and populates its own data
1827
+ # model in memory. Yet BTAP is not a typical use case. To avoid writing
1828
+ # out (then re-reading) TBD JSON files/hashes (i.e. resource intensive),
1829
+ # BTAP/TBD instead populates the TBD data model directly.
1830
+ @model[:lp_bad ] = self.inputs(:lp, :bad )
1831
+ @model[:lp_good] = self.inputs(:lp, :good)
1832
+ @model[:hp_bad ] = self.inputs(:hp, :bad )
1833
+ @model[:hp_good] = self.inputs(:hp, :good)
1834
+
1835
+ @model[:osm] = model
1836
+
1837
+ true
1838
+ end
1839
+
1840
+ ##
1841
+ # Generate (native) TBD input hash.
1842
+ #
1843
+ # @param perform [Symbol] :lp or :hp wall variant
1844
+ # @param quality [Symbol] :bad or :good PSI-factor
1845
+ #
1846
+ # @return [Hash] native TBD inputs
1847
+ def inputs(perform = :hp, quality = :good)
1848
+ input = {}
1849
+ psis = {} # construction-specific PSI sets
1850
+ types = {} # space type-specific references to previous PSI sets
1851
+ perform = :hp unless perform == :lp || perform == :hp
1852
+ quality = :good unless quality == :bad || quality == :good
1853
+
1854
+ # Once building-type construction selection is introduced within BTAP,
1855
+ # define default TBD "building" PSI set. In the meantime, this is added
1856
+ # strictly as a backup solution (just in case).
1857
+ building = self.set(STEL1, quality) if perform == :lp
1858
+ building = self.set(STEL2, quality) if perform == :hp
1859
+
1860
+ psis[ building[:id] ] = building
1861
+
1862
+ # Collect unique BTAP/TBD instances.
1863
+ combo = "#{perform.to_s}_#{quality.to_s}".to_sym
1864
+
1865
+ @model[:sptypes].values.each do |type|
1866
+ next unless type.key?(combo)
1867
+
1868
+ psi = type[combo]
1869
+ next if psis.key?(psi[:id])
1870
+
1871
+ psis[ psi[:id] ] = psi
1872
+ end
1873
+
1874
+ # TBD JSON schema added as a reminder. No schema validation in BTAP.
1875
+ schema = "https://github.com/rd2/tbd/blob/master/tbd.schema.json"
1876
+
1877
+ input[:schema ] = schema
1878
+ input[:description] = "TBD input for BTAP" # append run # ?
1879
+ input[:psis ] = psis.values
1880
+
1881
+ @model[:sptypes].values.each do |type|
1882
+ next unless type.key?(:sptype)
1883
+ next unless type.key?(combo)
1884
+ next if types.key?(type[:sptype])
1885
+
1886
+ types[ type[:sptype] ] = { psi: type[combo][:id] }
1887
+ end
1888
+
1889
+ types.each do |id, type|
1890
+ input[:spacetypes] = [] unless input.key?(:spacetypes)
1891
+ input[:spacetypes] << { id: id, psi: type[:psi] }
1892
+ end
1893
+
1894
+ input[:building] = { psi: building[:id] }
1895
+
1896
+ input
1897
+ end
1898
+
1899
+ ##
1900
+ # Generate BTAP/TBD tallies
1901
+ #
1902
+ # @return [Bool] true if BTAP/TBD tally is successful
1903
+ def gen_tallies
1904
+ edges = {}
1905
+ return false unless @model.key?(:io)
1906
+ return false unless @model[:io].key?(:edges)
1907
+
1908
+ @model[:io][:edges].each do |e|
1909
+ # Content of TBD-generated 'edges' (hashes):
1910
+ # psi: BTAP PSI set ID, e.g. "BTAP-ExteriorWall-Mass-6 good"
1911
+ # type: thermal bridge type, e.g. :corner
1912
+ # length: (in m)
1913
+ # surfaces: linked OpenStudio surface IDs
1914
+ edges[e[:type]] = {} unless edges.key?(e[:type])
1915
+ edges[e[:type]][e[:psi]] = 0 unless edges[e[:type]].key?(e[:psi])
1916
+ edges[e[:type]][e[:psi]] += e[:length]
1917
+ end
1918
+
1919
+ return false if edges.empty?
1920
+
1921
+ @tally[:edges] = edges
1922
+
1923
+ # Add final selection of (uprated) Uo factors per BTAP construction.
1924
+ return true unless @model.key?(:constructions)
1925
+
1926
+ @tally[:constructions] = @model[:constructions]
1927
+
1928
+ true
1929
+ end
1930
+
1931
+ ##
1932
+ # Generate BTAP/TBD post-processing feedback.
1933
+ #
1934
+ # @return [Bool] true if valid BTAP/TBD model
1935
+ def gen_feedback
1936
+ lgs = @feedback[:logs]
1937
+ return false unless @model.key?(:comply)
1938
+ return false unless @model.key?(:args )
1939
+
1940
+ args = @model[:args]
1941
+
1942
+ # Successfully uprated Uo (if requested).
1943
+ [:walls, :floors, :roofs].each do |stypes|
1944
+ break unless @model[:comply]
1945
+
1946
+ stype_ut = "#{stypes.to_s.chop}_ut".to_sym
1947
+ stype_uo = "#{stypes.to_s.chop}_uo".to_sym
1948
+ next unless args.key?(stype_ut)
1949
+ next unless args.key?(stype_uo)
1950
+ next unless @model.key?(stypes)
1951
+ next if @model[stypes].empty?
1952
+
1953
+ ut = args[stype_ut]
1954
+ uo = args[stype_uo]
1955
+ next unless ut.is_a?(Numeric)
1956
+ next unless uo.is_a?(Numeric)
1957
+
1958
+ ut = format("%.3f", ut)
1959
+ uo = format("%.3f", uo)
1960
+ lgs << "Compliant #{stypes}: Uo #{uo} vs Ut #{ut} W/m2.K"
1961
+ end
1962
+
1963
+ # Uprating unsuccessful: report min Uo factor per construction.
1964
+ if @model.key?(:constructions)
1965
+ @model[:constructions].each do |id, construction|
1966
+ break if @model[:comply]
1967
+
1968
+ lgs << "Non-compliant #{id} Uo factor #{construction[:uo]} (W/K.m^2)"
1969
+ end
1970
+ end
1971
+
1972
+ # Summary of TBD-derated constructions.
1973
+ @model[:osm].getSurfaces.each do |s|
1974
+ next if s.construction.empty?
1975
+ next if s.construction.get.to_LayeredConstruction.empty?
1976
+
1977
+ lc = s.construction.get.to_LayeredConstruction.get
1978
+ next unless lc.nameString.include?(" c tbd")
1979
+
1980
+ rsi = TBD.rsi(lc, s.filmResistance)
1981
+ rsi = format("%.1f", rsi)
1982
+ lgs << "~~ '#{lc.nameString}' derated Rsi: #{rsi} (m^2.K/W)"
1983
+ end
1984
+
1985
+ # Log PSI factor tallies (per thermal bridge type).
1986
+ if @tally.key?(:edges)
1987
+ @tally[:edges].each do |type, e|
1988
+ next if type == :transition
1989
+
1990
+ lgs << "# '#{type}' (#{e.size}x):"
1991
+
1992
+ e.each do |psi, length|
1993
+ l = format("%.2f", length)
1994
+ lgs << "... PSI set '#{psi}' : #{l} m"
1995
+ end
1996
+ end
1997
+ end
1998
+
1999
+ true
2000
+ end
2001
+ end
2002
+ end
2003
+
2004
+ # NOTE: BTAP supports Uo variants for each of the aforementioned wall
2005
+ # constructions, e.g. meeting NECB2011 and NECB2015 prescriptive "Uo"
2006
+ # requirements for each NECB climate zone. By definition, these Uo
2007
+ # variants ignore the effects of MAJOR thermal bridging, such as
2008
+ # intermediate slab edges. This does not imply that NECB2011 and NECB2015
2009
+ # do not hold prescriptive requirements for MAJOR thermal bridging. There
2010
+ # are indeed a handful of general, qualitative requirements (those of the
2011
+ # MNECB1997) that would make NECB2011- and NECB2015-compliant buildings
2012
+ # slightly better than BTAPPRE1980 "bottom-of-the-barrel" construction,
2013
+ # but lilely not any better than circa 1990s "run-of-the-mill" commercial
2014
+ # construction. Currently, BTAP does not assess the impact of MAJOR
2015
+ # thermal bridging for vintages < NECB2017. But ideally it SHOULD, if the
2016
+ # goal remains a fair assessment of the (relative) contribution of more
2017
+ # recent NECB requirements (e.g. 2020).
2018
+
2019
+ # NOTE: The BTAP costing spreadsheet holds entries for curtain wall (CW)
2020
+ # spandrel inserts above/below fenestration for certain spacetypes, see:
2021
+ #
2022
+ # test/necb/unit_tests/resources/btap_spandrels.png
2023
+ #
2024
+ # This is yet to be implemented. This note is an "aide-mémoire" for future
2025
+ # consideration. The BETBG does not hold any CW glazed spandrels achieving
2026
+ # U factors ANYWHERE near NECB requirements, regardless of NECB vintage or
2027
+ # NECB climate zone. Same for the Guide to Low Thermal Energy Demand for
2028
+ # Large Buildings. The original intention was to rely on BTAP variants
2029
+ # "Metal-2" and "Metal-3" as HP CW spandrels ACTUALLY achieving NECB
2030
+ # prescriptive targets, which could only be possible in practice at
2031
+ # tremendous cost and effort.
2032
+ #
2033
+ # If TBD's uprating calculations (e.g. NECB 2017) were in theory no longer
2034
+ # required, BTAP's treatment of HP CW spandrels could be implemented
2035
+ # strictly as a costing adjustment: energy simulation models wouldn't have
2036
+ # to be altered. Otherwise, adaptations would be required. PSI factors are
2037
+ # noticeably different for spandrels (obviously no lintels/shelf-angles).
2038
+ # More importantly, the default assumption with CW technology is that
2039
+ # there wouldn't be any additional linear conductances to consider along
2040
+ # vision vs spandrel sections (as perimeter heat loss would already have
2041
+ # been considered as per NFRC or CSA rating methodologies). On the other
2042
+ # hand, vision jambs along non-CW assemblies (i.e. original BTAP
2043
+ # intention) most certainly constitute (new) MAJOR thermal bridges to
2044
+ # consider (just as with shared edges between spandrels and other wall
2045
+ # assemblies). Again, none of these features are currently implemented
2046
+ # within BTAP. Recommended (future) solution, if desired:
2047
+ #
2048
+ # - Automated OSM façade-splitting feature
2049
+ # - insert spandrels above/below windows
2050
+ # > ~200 lines of Ruby code
2051
+ # - simple cases only e.g., vertical, no overlaps, h > 200mm
2052
+ # > split above/below plenum walls as well
2053
+ # > potentially another 200 lines to catch invalid input
2054
+ #
2055
+ # - Further develop PSI sets to cover CWs (see below)
2056
+ # - e.g. PSI factors for CW vision "jamb" transitions
2057
+ # - e.g. PSI factors for CW spandrel "jamb" transitions
2058
+ #
2059
+ # These added features would simplify the process tremendously. Yet
2060
+ # without admissible CW spandrel U factors down to 0.130 or 0.100 W/m2.K,
2061
+ # TBD's uprating features would necessarily push other wall constructions
2062
+ # to compensate - noticeably for climate zone 7 (or colder). This would
2063
+ # make it MUCH MORE difficult to identify NECB2017 or NECB2020 compliant
2064
+ # combinations of Uo+PSI factors if ever HP CW spandrels were integrated
2065
+ # within BTAP.
2066
+
2067
+ # NOTE: Some of the aforementioned constructions have exterior brick veneer.
2068
+ # For 2-story OpenStudio models with punch windows (i.e. not strip
2069
+ # windows), one would NOT expect a continuous shelf angle along the
2070
+ # intermediate floor slab edge (typically a MAJOR thermal bridge). One
2071
+ # would instead expect loose lintels above punch windows, just as with
2072
+ # doors. Loose lintels usually do not constitute MAJOR thermal bridges.
2073
+ # For taller builings, shelf angles are indeed expected. And if windows
2074
+ # are instead strip windows (not punch windows), then loose lintels would
2075
+ # typically be cast aside in favour of an offset shelf angle (even for
2076
+ # 1-story buildings).
2077
+ #
2078
+ # Many of the US DOE Commercial Benchmark Building and BTAP models are
2079
+ # 1-story or 2-stories in height, yet they all have strip windows as their
2080
+ # default fenestration layout. As a result, BTAP/TBD presumes continuous
2081
+ # shelf angles, offset by the height difference between slab edge and
2082
+ # window head. Loose lintels (included in the clear field costing, $/m2)
2083
+ # should be limited to those above doors (TO-DO).
2084
+ #
2085
+ # NOTE: BTAP costing: In addition to the listed items for parapets as MAJOR
2086
+ # thermal bridges (eventually generating an overall $ per linear meter),
2087
+ # BTAP costing requires extending the areas (m2) of OpenStudio wall
2088
+ # surfaces (along parapet edges) by 3'-6" (1.1 m) x parapet lengths, to
2089
+ # account for the extra cost of completely wrapping the parapet in
2090
+ # insulation for "good" (HP) details. See final TBD tally. TO-DO.
2091
+ #
2092
+ # NOTE: Overview of current BTAP building/space type construction link, e.g.:
2093
+ #
2094
+ # - ALL dwelling units/buildings < 5 stories are wood-framed
2095
+ # - ALL dwelling units/buildings > 4 stories are steel-framed
2096
+ #
2097
+ # ... yet all (public) washrooms, corridors, stairwells, etc. are
2098
+ # steel-framed (regardless of building type). Overview of possible fixes.
2099
+ # TO-DO.