openstudio-standards 0.8.5 → 0.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. data/data/standards/test_performance_expected_dd_results.csv +90 -90
  3. data/lib/openstudio-standards/btap/activity.rb +858 -61
  4. data/lib/openstudio-standards/btap/attributes.rb +297 -103
  5. data/lib/openstudio-standards/btap/bridging.rb +1335 -593
  6. data/lib/openstudio-standards/btap/btap.rb +60 -181
  7. data/lib/openstudio-standards/btap/carbon/btap_carbon.rb +199 -142
  8. data/lib/openstudio-standards/btap/common/constructions.json +1275 -0
  9. data/lib/openstudio-standards/btap/common/costs.csv +1969 -0
  10. data/lib/openstudio-standards/btap/common/costs_local_factors.csv +2315 -0
  11. data/lib/openstudio-standards/btap/common/materials_glazing.csv +61 -0
  12. data/lib/openstudio-standards/btap/{common_resources → common}/materials_hvac.csv +1685 -1685
  13. data/lib/openstudio-standards/btap/{common_resources → common}/materials_lighting.csv +266 -266
  14. data/lib/openstudio-standards/btap/common/materials_opaque.csv +214 -0
  15. data/lib/openstudio-standards/btap/common/necb_building_types.csv +35 -0
  16. data/lib/openstudio-standards/btap/common/necb_space_types.csv +110 -0
  17. data/lib/openstudio-standards/btap/common/thermal_bridging.csv +73 -0
  18. data/lib/openstudio-standards/btap/costing/btap_costing.rb +346 -429
  19. data/lib/openstudio-standards/btap/costing/database.rb +104 -0
  20. data/lib/openstudio-standards/btap/costing/daylighting_sensor_control_costing.rb +356 -344
  21. data/lib/openstudio-standards/btap/costing/dcv_costing.rb +282 -296
  22. data/lib/openstudio-standards/btap/costing/envelope_costing.rb +179 -192
  23. data/lib/openstudio-standards/btap/costing/heating_cooling_costing.rb +2477 -2316
  24. data/lib/openstudio-standards/btap/costing/led_lighting_costing.rb +127 -142
  25. data/lib/openstudio-standards/btap/costing/lighting_costing.rb +216 -198
  26. data/lib/openstudio-standards/btap/costing/nv_costing.rb +522 -523
  27. data/lib/openstudio-standards/btap/costing/pv_ground_costing.rb +649 -649
  28. data/lib/openstudio-standards/btap/costing/shw_costing.rb +626 -625
  29. data/lib/openstudio-standards/btap/costing/thermal_bridging_costing.rb +72 -0
  30. data/lib/openstudio-standards/btap/costing/ventilation_costing.rb +2363 -2361
  31. data/lib/openstudio-standards/btap/deprecated.rb +1033 -0
  32. data/lib/openstudio-standards/btap/envelope.rb +313 -572
  33. data/lib/openstudio-standards/btap/fileio.rb +152 -1070
  34. data/lib/openstudio-standards/btap/geometry.rb +486 -766
  35. data/lib/openstudio-standards/btap/linear_regression.rb +130 -0
  36. data/lib/openstudio-standards/btap/paths.rb +46 -0
  37. data/lib/openstudio-standards/btap/qaqc/analysis.rb +163 -0
  38. data/lib/openstudio-standards/btap/qaqc/data.rb +2293 -0
  39. data/lib/openstudio-standards/btap/qaqc/datapoint.rb +641 -0
  40. data/lib/openstudio-standards/btap/schedules.rb +11 -611
  41. data/lib/openstudio-standards/btap/structure.rb +574 -189
  42. data/lib/openstudio-standards/constructions/materials/information.rb +1 -1
  43. data/lib/openstudio-standards/create_typical/create_typical.rb +1 -1
  44. data/lib/openstudio-standards/exterior_lighting/create.rb +135 -85
  45. data/lib/openstudio-standards/exterior_lighting/data/typical_exterior_lighting.json +20 -0
  46. data/lib/openstudio-standards/exterior_lighting/information.rb +23 -2
  47. data/lib/openstudio-standards/geometry/create.rb +7 -3
  48. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.Model.rb +3 -2
  49. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.Model.rb +3 -2
  50. data/lib/openstudio-standards/prototypes/common/data/thermostat_schedule_lookup.json +84 -84
  51. data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +4 -4
  52. data/lib/openstudio-standards/refrigeration/create_walkin.rb +45 -5
  53. data/lib/openstudio-standards/refrigeration/data/refrigerated_walkins.csv +75 -75
  54. data/lib/openstudio-standards/schedules/parametric.rb +6 -0
  55. data/lib/openstudio-standards/service_water_heating/create_typical.rb +10 -3
  56. data/lib/openstudio-standards/service_water_heating/create_water_heating_loop.rb +30 -14
  57. data/lib/openstudio-standards/service_water_heating/information.rb +4 -1
  58. data/lib/openstudio-standards/sql_file/unmet_hours.rb +2 -1
  59. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXSingleSpeed.rb +3 -1
  60. data/lib/openstudio-standards/standards/Standards.CoilHeatingDXSingleSpeed.rb +3 -1
  61. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.boilers.json +12 -0
  62. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.construction_properties.json +18432 -3072
  63. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.boilers.json +26 -0
  64. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.construction_properties.json +8532 -1422
  65. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.boilers.json +26 -0
  66. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.construction_properties.json +8532 -1422
  67. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.boilers.json +16 -0
  68. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.computer_room_acs.json +30 -30
  69. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.construction_properties.json +7560 -1260
  70. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.PumpVariableSpeed.rb +1 -2
  71. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.boilers.json +16 -0
  72. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.construction_properties.json +7560 -1260
  73. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.AirLoopHVAC.rb +3 -3
  74. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.PumpVariableSpeed.rb +1 -2
  75. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.boilers.json +22 -0
  76. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.construction_properties.json +7236 -1206
  77. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.furnaces.json +223 -19
  78. data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.schedules.json +37 -1
  79. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.boilers.json +3 -0
  80. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.construction_properties.json +6900 -1150
  81. data/lib/openstudio-standards/standards/cbes/data/cbes.schedules.json +1 -1
  82. data/lib/openstudio-standards/standards/deer/data/deer.schedules.json +1 -1
  83. data/lib/openstudio-standards/standards/necb/BTAP1980TO2010/data/surface_thermal_transmittance.json +76 -40
  84. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/surface_thermal_transmittance.json +76 -40
  85. data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +6 -4
  86. data/lib/openstudio-standards/standards/necb/NECB2011/NECB2011_QAQC.json +2988 -0
  87. data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +25 -3
  88. data/lib/openstudio-standards/standards/necb/NECB2011/building_envelope.rb +672 -534
  89. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/Hospital.osm +1791 -1792
  90. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPMultiTower.osm +7 -1
  91. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPTownHouse.osm +7 -1
  92. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LargeHotel.osm +5 -6
  93. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LargeOffice.osm +8 -9
  94. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernEducation.osm +10 -4
  95. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernHealthCare.osm +14 -15
  96. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/Outpatient.osm +7 -1
  97. data/lib/openstudio-standards/standards/necb/NECB2011/data/surface_thermal_transmittance.json +76 -40
  98. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +14 -6
  99. data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +542 -130
  100. data/lib/openstudio-standards/standards/necb/NECB2011/qaqc/necb_qaqc.rb +30 -63
  101. data/lib/openstudio-standards/standards/necb/NECB2011/service_water_heating.rb +7 -2
  102. data/lib/openstudio-standards/standards/necb/NECB2015/data/surface_thermal_transmittance.json +90 -0
  103. data/lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb +8 -6
  104. data/lib/openstudio-standards/standards/necb/NECB2017/data/surface_thermal_transmittance.json +76 -40
  105. data/lib/openstudio-standards/standards/necb/NECB2017/necb_2017.rb +2 -1
  106. data/lib/openstudio-standards/standards/necb/NECB2020/building_envelope.rb +0 -117
  107. data/lib/openstudio-standards/standards/necb/NECB2020/data/surface_thermal_transmittance.json +76 -45
  108. data/lib/openstudio-standards/standards/necb/NECB2020/necb_2020.rb +218 -0
  109. data/lib/openstudio-standards/standards/necb/common/construction_defaults.osm +12 -7
  110. data/lib/openstudio-standards/standards/standard.rb +1 -1
  111. data/lib/openstudio-standards/version.rb +1 -1
  112. data/lib/openstudio-standards.rb +9 -4
  113. metadata +59 -66
  114. data/data/inventory/thermal_bridging.csv +0 -90
  115. data/data/standards/OpenStudio_Standards-ashrae_90_1-ALL-comstock(space_types).xlsx +0 -0
  116. data/data/standards/openstudio_standards_duplicates_log.csv +0 -7962
  117. data/lib/openstudio-standards/btap/NECB_building_types.csv +0 -35
  118. data/lib/openstudio-standards/btap/NECB_space_types.csv +0 -109
  119. data/lib/openstudio-standards/btap/WeatherData1.json +0 -2110
  120. data/lib/openstudio-standards/btap/WeatherData1.xlsx +0 -0
  121. data/lib/openstudio-standards/btap/btap_result.rb +0 -1144
  122. data/lib/openstudio-standards/btap/btap_test_helper.rb +0 -86
  123. data/lib/openstudio-standards/btap/common_paths.rb +0 -81
  124. data/lib/openstudio-standards/btap/common_resources/ConstructionProperties.csv +0 -52
  125. data/lib/openstudio-standards/btap/common_resources/Constructions.csv +0 -37
  126. data/lib/openstudio-standards/btap/common_resources/construction_sets.csv +0 -1270
  127. data/lib/openstudio-standards/btap/common_resources/constructions_glazing.csv +0 -121
  128. data/lib/openstudio-standards/btap/common_resources/constructions_opaque.csv +0 -2256
  129. data/lib/openstudio-standards/btap/common_resources/costs.csv +0 -1897
  130. data/lib/openstudio-standards/btap/common_resources/costs_local_factors.csv +0 -2315
  131. data/lib/openstudio-standards/btap/common_resources/materials_glazing.csv +0 -35
  132. data/lib/openstudio-standards/btap/common_resources/materials_opaque.csv +0 -164
  133. data/lib/openstudio-standards/btap/costing/btap_measure_helper.rb +0 -359
  134. data/lib/openstudio-standards/btap/costing/btap_workflow.rb +0 -117
  135. data/lib/openstudio-standards/btap/costing/copy_test_results_files_to_expected_results.rb +0 -11
  136. data/lib/openstudio-standards/btap/costing/cost_building_from_file.rb +0 -136
  137. data/lib/openstudio-standards/btap/costing/costing_database_wrapper.rb +0 -173
  138. data/lib/openstudio-standards/btap/costing/dummy.epw +0 -8768
  139. data/lib/openstudio-standards/btap/costing/dummy.osm +0 -5320
  140. data/lib/openstudio-standards/btap/costing/neb_end_use_prices.csv +0 -42
  141. data/lib/openstudio-standards/btap/costing/necb_2011_spacetype_info.csv +0 -225
  142. data/lib/openstudio-standards/btap/costing/necb_reference_runs.csv +0 -28705
  143. data/lib/openstudio-standards/btap/costing/parallel_tests.rb +0 -92
  144. data/lib/openstudio-standards/btap/costing/test_list.txt +0 -15
  145. data/lib/openstudio-standards/btap/costing/test_run_all_test_locally.rb +0 -27
  146. data/lib/openstudio-standards/btap/costing/test_run_costing_tests.rb +0 -80
  147. data/lib/openstudio-standards/btap/necb_2011_spacetype_info.csv +0 -225
  148. data/lib/openstudio-standards/btap/utilities/Add_template_field_to_json.rb +0 -22
  149. data/lib/openstudio-standards/btap/utilities/convert_surfaces_to_adiabatic_necb_8426.rb +0 -204
  150. data/lib/openstudio-standards/btap/utilities/generate_space_types.rb +0 -8
  151. data/lib/openstudio-standards/btap/utilities/necb_to_epw_map.rb +0 -50
  152. data/lib/openstudio-standards/btap/utilities/os_sim_extract.rb +0 -48
  153. data/lib/openstudio-standards/btap/utilities/rename_surfaces.rb +0 -24
  154. data/lib/openstudio-standards/btap/utilities/round_surf_coords.rb +0 -32
  155. data/lib/openstudio-standards/btap/utilities/sched_create.rb +0 -145
  156. data/lib/openstudio-standards/btap/utilities/set_mult_to_adiabatic.rb +0 -53
  157. data/lib/openstudio-standards/btap/utilities/space_type.rb +0 -78
  158. data/lib/openstudio-standards/btap/utilities/weatherData1_xlsx_to_json.rb +0 -56
  159. data/lib/openstudio-standards/btap/vintagizer.rb +0 -161
  160. data/lib/openstudio-standards/btap/visualization.rb +0 -72
  161. data/lib/openstudio-standards/standards/necb/NECB2011/data/necb_2011_spacetype_info.csv +0 -225
  162. data/lib/openstudio-standards/standards/necb/common/btap_analysis.rb +0 -79
  163. data/lib/openstudio-standards/standards/necb/common/btap_data.rb +0 -2656
  164. data/lib/openstudio-standards/standards/necb/common/btap_datapoint.rb +0 -653
  165. data/lib/openstudio-standards/standards/necb/common/necb_reference_runs.csv +0 -28705
  166. data/lib/openstudio-standards/standards/necb/common/utility_pricing_2025-02-20.csv +0 -92
  167. /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_frame.csv +0 -0
  168. /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_glazing.csv +0 -0
  169. /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_opaque.csv +0 -0
  170. /data/lib/openstudio-standards/btap/{common_resources → common}/hvac_vent_ahu.csv +0 -0
  171. /data/lib/openstudio-standards/btap/{common_resources → common}/lighting.csv +0 -0
  172. /data/lib/openstudio-standards/btap/{common_resources → common}/lighting_sets.csv +0 -0
  173. /data/lib/openstudio-standards/btap/{common_resources → common}/locations.csv +0 -0
  174. /data/lib/openstudio-standards/btap/{costing → common}/mech_sizing.json +0 -0
@@ -1,5 +1,5 @@
1
1
  # **************************************************************************** /
2
- # * Copyright (c) 2008-2025, Natural Resources Canada
2
+ # * Copyright (c) 2008-2026, Natural Resources Canada
3
3
  # * All rights reserved.
4
4
  # *
5
5
  # * This library is free software; you can redistribute it and/or
@@ -32,7 +32,7 @@ module BTAP
32
32
  # As detailed a bit further on, this determination is either via user input:
33
33
  # - e.g. "clt" (mass timber) post/beam STRUCTURE, for a school.
34
34
  #
35
- # Or auto-assigned based on the prevalence of model space type assignments:
35
+ # ... or auto-assigned based on the prevalence of model space types:
36
36
  # - e.g. 75% of spaces are commercial in nature (see activity.rb),
37
37
  # therefore the building STRUCTURE defaults to "steel" post/beam.
38
38
  #
@@ -45,7 +45,7 @@ module BTAP
45
45
  #
46
46
  # Ensuring consistency between building STRUCTURE, envelope selection,
47
47
  # internal mass definitions, etc. is key to harmonizing predicted energy
48
- # use, peak demand assessments, GHG emissions, vs thermal resilience and
48
+ # use, peak demand assessments, GHG emissions, thermal resilience and
49
49
  # embodied energy/GHG tallies.
50
50
  #
51
51
  # --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --- #
@@ -72,7 +72,7 @@ module BTAP
72
72
  # NOTES:
73
73
  #
74
74
  # ** Neither "metal" nor "clt" options can be considered as fully
75
- # supported by BTAP, e.g.:
75
+ # supported by BTAP at this stage, e.g.:
76
76
  # - no range of admissible envelope Uo factors
77
77
  # - no associated PSI-factors (thermal bridging)
78
78
  # - no costing data
@@ -104,8 +104,8 @@ module BTAP
104
104
  #
105
105
  # Note that there's a (growing?) need to contrast "metal" buildings against
106
106
  # the default "steel" post/beam option. Like a "wood" framed STRUCTURE or a
107
- # load-bearing "cmu" wall, a "metal" building's envelope structure and skin
108
- # are indistinguishable, i.e. no mixing/matching of STRUCTURE vs envelope.
107
+ # load-bearing "cmu" wall, a "metal" building's structure and envelope are
108
+ # indistinguishable, i.e. no mixing/matching of STRUCTURE vs envelope.
109
109
  #
110
110
  # There are of course several other (smaller scale) structural options,
111
111
  # often load-bearing envelopes like adobe/hemp/straw bale construction. Most
@@ -113,9 +113,15 @@ module BTAP
113
113
  # shortlisting them for commercial building stock assessments. One could
114
114
  # state the same when it comes to the current (marginal) use of "clt". Yet
115
115
  # as the latter is rapidly becoming a robust low-carbon alternative to
116
- # "steel" and "concrete" options, its inclusion is justified. Additional
117
- # options may nonetheless be added in the future.
118
- @@data = {structure: {}, cladding: {}, finish: {}, category: {}}
116
+ # "steel" and "concrete" options, its inclusion seems justified. Additional
117
+ # options may be added in the future.
118
+ @@data = {structure: {}, cladding: {}, finish: {}, category: {}, tags: []}
119
+
120
+ # Admissible AdditionalProperty keys for customization.
121
+ @@data[:tags] << "btap_structure"
122
+ @@data[:tags] << "btap_framing"
123
+ @@data[:tags] << "btap_cladding"
124
+ @@data[:tags] << "btap_finish"
119
125
 
120
126
  # Each STRUCTURE inherits a default FRAMING option. Together with the
121
127
  # STRUCTURE selection, FRAMING determines inter alia:
@@ -133,11 +139,11 @@ module BTAP
133
139
 
134
140
  # An example. STRUCTURE == "wood" + default FRAMING == "wood", e.g. housing:
135
141
  # - typical engineered wood joists + FINISH
136
- # - similar engineered wood rafters + FINISH (if flat or cathedral roof)
142
+ # - similar engineered wood rafters + FINISH (when flat or cathedral roof)
137
143
  # - anchored engineered wood joist balconies
138
144
  #
139
145
  # FRAMING may also determine above-grade exterior wall composition (e.g.
140
- # wool-insulated wood-framed exterior walls, if FRAMING == "wood"). This
146
+ # wool-insulated wood-framed exterior walls, when FRAMING == "wood"). This
141
147
  # may instead be determined by CLADDING selection in several cases.
142
148
  #
143
149
  # Exterior CLADDING and interior FINISH options are both limited to 4
@@ -150,7 +156,7 @@ module BTAP
150
156
  # rare, even in pre-code buildings. An example would be a load-bearing,
151
157
  # "cmu" wall with 2 coats of paint in a semi-heated industrial facility. The
152
158
  # "none" FINISH option is slightly more common, e.g. exposed ceilings, bare
153
- # "clt" walls, and again bare "cmu" walls (or with 2 coats of paint).
159
+ # "clt" walls, and again bare "cmu" walls.
154
160
  @@data[:cladding] = [:none, :light, :medium, :heavy]
155
161
  @@data[:finish ] = [:none, :light, :medium, :heavy]
156
162
 
@@ -161,8 +167,8 @@ module BTAP
161
167
  # - load-bearing basement walls
162
168
  # - basement columns, shear walls, etc. (internal mass)
163
169
  #
164
- # Hopefully, users may also assign STRUCTURE, FRAMING, CLADDING & FINISH
165
- # options per OpenStudio's building-to-space hierarchy, e.g. - @todo:
170
+ # BTAP users can also explicitely assign STRUCTURE, FRAMING, CLADDING &
171
+ # FINISH options per OpenStudio's building-to-space hierarchy, e.g.:
166
172
  #
167
173
  # Example A: Composite STRUCTURE:
168
174
  # - "concrete" post/beam STRUCTURE for first 4 building stories
@@ -179,17 +185,17 @@ module BTAP
179
185
  # With the exception of "metal" buildings, users may optionally interchange
180
186
  # some paired STRUCTURE vs FRAMING options (among available :frames above).
181
187
  # Unusual in some cases, yet not completely unheard of.
182
- @@data[:structure][:steel ][:frames] = [:wood ]
183
- @@data[:structure][:metal ][:frames] = [ ]
184
- @@data[:structure][:concrete][:frames] = [:wood, :cmu ]
185
- @@data[:structure][:cmu ][:frames] = [:wood, :steel]
186
- @@data[:structure][:wood ][:frames] = [:steel ]
187
- @@data[:structure][:clt ][:frames] = [:clt, :steel ]
188
+ @@data[:structure][:steel ][:frames] = [:steel, :wood ]
189
+ @@data[:structure][:metal ][:frames] = [:metal ]
190
+ @@data[:structure][:concrete][:frames] = [:steel, :wood, :cmu ]
191
+ @@data[:structure][:cmu ][:frames] = [:cmu, :wood, :steel]
192
+ @@data[:structure][:wood ][:frames] = [:wood, :steel ]
193
+ @@data[:structure][:clt ][:frames] = [:wood, :clt, :steel]
188
194
 
189
195
  # --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #
190
196
  # To simplify data management, building TYPES (e.g. those listed in Table
191
- # A-8.4.3.2.(2)-A of the NECB 2020) are proposed to fall into more general
192
- # building CATEGORIES (see activity.rb & NECB_building_types.csv):
197
+ # A-8.4.3.2.(2)-A of the NECB 2020) fall into more general building
198
+ # CATEGORIES (see activity.rb & btap_building_types.csv):
193
199
  #
194
200
  # CATEGORY examples
195
201
  # _____________ __________________________________________________________
@@ -201,8 +207,8 @@ module BTAP
201
207
  # "recreation" gymnastics, ice arena, indoor soccer/pool
202
208
  # "robust" penitentiary, parking garage (i.e. heavyduty, resistant)
203
209
  #
204
- # Each CATEGORY holds "small"-scale and "large"-scale STRUCTURE options by
205
- # defaults, depending on the characteristics of the building.
210
+ # Each CATEGORY holds default "small"-scale and "large"-scale STRUCTURE
211
+ # options, set based on building characteristics.
206
212
  @@data[:category] = {}
207
213
  @@data[:category]["housing" ] = {small: :wood , large: :concrete}
208
214
  @@data[:category]["lodging" ] = {small: :wood , large: :concrete}
@@ -251,28 +257,31 @@ module BTAP
251
257
  class BTAP::Structure
252
258
  extend StructureData
253
259
 
254
- # @return [String] building type CATEGORY (e.g. "public")
260
+ # @return [String] default building type CATEGORY (e.g. "public")
255
261
  attr_reader :category
256
262
 
257
- # @return [Symbol] building STRUCTURE selection (e.g. :steel)
263
+ # @return [Symbol] default building STRUCTURE selection (e.g. :steel)
258
264
  attr_reader :structure
259
265
 
260
- # @return [Symbol] building framing (e.g. :steel)
266
+ # @return [Symbol] default building framing (e.g. :steel)
261
267
  attr_reader :framing
262
268
 
263
- # @return [Symbol] building cladding (e.g. :medium)
269
+ # @return [Symbol] default building cladding (e.g. :medium)
264
270
  attr_reader :cladding
265
271
 
266
- # @return [Symbol] building finish (e.g. :light)
272
+ # @return [Symbol] default building finish (e.g. :light)
267
273
  attr_reader :finish
268
274
 
269
- # @return [Float] estimated dead load, in kg/m2 of floor area
275
+ # @return [Hash] customized STRUCTURE, FRAMING, CLADDING & FINISH per space
276
+ attr_reader :spaces
277
+
278
+ # @return [Float] default building dead load, in floor kg/m2
270
279
  attr_reader :deadload
271
280
 
272
- # @return [Float] estimated non-occupant live load, in kg/m2 of floor area
281
+ # @return [Float] default building non-occupant live load, in floor kg/m2
273
282
  attr_reader :liveload
274
283
 
275
- # @return [Hash] calculated embodied carbon (CO2-e kg)
284
+ # @return [Hash] default building STRUCTURE embodied carbon (CO2-e kg)
276
285
  attr_reader :co2
277
286
 
278
287
  # @return [Hash] logged messages
@@ -300,10 +309,10 @@ module BTAP
300
309
  return
301
310
  end
302
311
 
303
- cat = activity.category
312
+ cat = activity.category
304
313
  lload = activity.liveload
305
314
 
306
- if cat.respond_to?(:to_s)
315
+ if cat.respond_to?(:to_sym)
307
316
  cat = cat.to_s.downcase
308
317
 
309
318
  if cat.empty?
@@ -327,13 +336,10 @@ module BTAP
327
336
  return
328
337
  end
329
338
 
330
- # Cap internal mass density to 1000 kg/m3, and thickness to 6".
331
- rho = 1000.0
332
- th = 0.150
333
- bldg = model.getBuilding
334
-
339
+ bldg = model.getBuilding
335
340
  @category = cat
336
341
  @structure = data[:category][cat][:small]
342
+ @spaces = {}
337
343
 
338
344
  # Switch to :large structure, instead of default :small.
339
345
  if data[:category][cat].key?(:stories)
@@ -375,13 +381,228 @@ module BTAP
375
381
 
376
382
  # Set interior finish.
377
383
  @finish = :light
378
- @finish = :none if @framing == :cmu
384
+ @finish = :none if @framing == :cmu
379
385
  @finish = :heavy if @category == "robust"
380
386
 
387
+ # Validate customization requests - override if user requests are invalid.
388
+ # Custom cladding and finish options are caught and held in memory, yet
389
+ # aren't fully supported for all costed constructions - may be ignored.
390
+ [:structure, :framing, :cladding, :finish].each do |item|
391
+ tag = "btap_" + item.to_s
392
+ opt = case item
393
+ when :framing then @framing
394
+ when :cladding then @cladding
395
+ when :finish then @finish
396
+ else @structure
397
+ end
398
+
399
+ if bldg.additionalProperties.hasFeature(tag)
400
+ prp = bldg.additionalProperties.getFeatureAsString(tag)
401
+
402
+ if prp.empty?
403
+ bldg.additionalProperties.setFeature(tag, opt.to_s)
404
+ else
405
+ prp = prp.get.downcase.to_sym
406
+
407
+ case item
408
+ when :structure
409
+ if data[:structure].key?(prp)
410
+ @structure = prp
411
+
412
+ # Reset :clt and :metal structure selections for now - @todo
413
+ @structure = :steel if @structure == :metal
414
+ @structure = :concrete if @structure == :clt
415
+
416
+ # Conditionally reset framing, cladding and/or finish.
417
+ @framing = data[:structure][@structure][:framing]
418
+ @cladding = :medium if @structure == :cmu
419
+ @finish = :none if @framing == :cmu
420
+ else
421
+ bldg.additionalProperties.setFeature(tag, @structure.to_s)
422
+ end
423
+ when :framing
424
+ if data[:structure][@structure][:frames].include?(prp)
425
+ @framing = prp
426
+
427
+ # Conditionally reset finish.
428
+ @finish = :none if @framing == :cmu
429
+ else
430
+ bldg.additionalProperties.setFeature(tag, @framing.to_s)
431
+ end
432
+ when :cladding
433
+ if data[:cladding].include?(prp)
434
+ @cladding = prp
435
+ else
436
+ bldg.additionalProperties.setFeature(tag, @cladding.to_s)
437
+ end
438
+ when :finish
439
+ if data[:finish].include?(prp)
440
+ @finish = prp
441
+ else
442
+ bldg.additionalProperties.setFeature(tag, @finish.to_s)
443
+ end
444
+ end
445
+ end
446
+ else
447
+ bldg.additionalProperties.setFeature(tag, opt.to_s)
448
+ end
449
+ end
450
+
451
+ # Track CONDITIONED spaces, e.g. rooms & plenums - ignore vented attics.
452
+ cspaces = model.getSpaces.reject { |sp| TBD.unconditioned?(sp) }
453
+
454
+ if cspaces.empty?
455
+ lgs << "Only UNCONDITIONED spaces (#{mth})"
456
+ return
457
+ end
458
+
459
+ # Customized space-specific STRUCTURE attributes, overriding
460
+ # default/custom building-wide attributes.
461
+ data[:tags].each do |tag|
462
+ cspaces.each do |space|
463
+ id = space.nameString
464
+ zn = space.thermalZone
465
+ next if zn.empty?
466
+ next unless space.floorArea > 0
467
+
468
+ # Retrieve/validate tagged AdditionalProperty (if assigned to story,
469
+ # spacetype or space).
470
+ prp = property(space, tag)
471
+ next unless prp
472
+
473
+ # Skip if same as building.
474
+ next if tag == "btap_structure" && prp == @structure
475
+ next if tag == "btap_framing" && prp == @framing
476
+ next if tag == "btap_cladding" && prp == @cladding
477
+ next if tag == "btap_finish" && prp == @finish
478
+
479
+ unless @spaces.key?(id)
480
+ @spaces[id] = {}
481
+ @spaces[id][:m2 ] = space.floorArea
482
+ @spaces[id][:h ] = BTAP::Geometry::Spaces.space_height(space)
483
+ @spaces[id][:co2] = {columns: 0, partitions: 0}
484
+
485
+ # Initialized with building attributes by default.
486
+ @spaces[id][:structure] = @structure
487
+ @spaces[id][:framing ] = @framing
488
+ @spaces[id][:cladding ] = @cladding
489
+ @spaces[id][:finish ] = @finish
490
+ end
491
+
492
+ # Reset if compatible.
493
+ case tag
494
+ when "btap_structure"
495
+ @spaces[id][:structure] = prp
496
+
497
+ # Conditionally reset framing, cladding and/or finish.
498
+ @spaces[id][:framing ] = data[:structure][prp][:framing]
499
+ @spaces[id][:cladding] = :medium if @spaces[id][:structure] == :cmu
500
+ @spaces[id][:finish ] = :none if @spaces[id][:framing ] == :cmu
501
+ when "btap_framing"
502
+ @spaces[id][:framing] = prp
503
+
504
+ # Conditionally reset finish.
505
+ @spaces[id][:finish] = :none if @spaces[id][:framing] == :cmu
506
+ when "btap_cladding"
507
+ @spaces[id][:cladding] = prp
508
+ when "btap_finish"
509
+ @spaces[id][:finish] = prp
510
+ else
511
+ end
512
+ end
513
+ end
514
+
515
+ # Prune customized spaces from common collection.
516
+ @spaces.keys.each { |id| cspaces.delete(model.getSpaceByName(id).get) }
517
+
518
+ # Only customized spaces left? Base building STRUCTURE on most common one.
519
+ if cspaces.empty?
520
+ custom = []
521
+ id = @spaces.keys.first
522
+ sp = @spaces.values.first
523
+ espace = model.getSpaceByName(id).get
524
+
525
+ first = {}
526
+ first[:spaces ] = [espace]
527
+ first[:structure] = sp[:structure]
528
+ first[:framing ] = sp[:framing]
529
+ first[:cladding ] = sp[:cladding]
530
+ first[:finish ] = sp[:finish]
531
+ first[:m2 ] = sp[:m2] * espace.multiplier
532
+ custom << first
533
+
534
+ @spaces.each do |id, sp|
535
+ match = false
536
+ space = model.getSpaceByName(id).get
537
+ next if space == espace
538
+
539
+ custom.each do |csp|
540
+ break if match
541
+
542
+ if sp[:structure] == csp[:structure] &&
543
+ sp[:framing ] == sp[:framing ] &&
544
+ sp[:cladding ] == sp[:cladding ] &&
545
+ sp[:finish ] == sp[:finish ]
546
+ csp[:spaces] << space
547
+ csp[:m2 ] += sp[:m2] * space.multiplier
548
+ match = true
549
+ end
550
+ end
551
+
552
+ unless match
553
+ spx = {}
554
+ spx[:spaces ] = [space]
555
+ spx[:structure] = sp[:structure]
556
+ spx[:framing ] = sp[:framing]
557
+ spx[:cladding ] = sp[:cladding]
558
+ spx[:finish ] = sp[:finish]
559
+ spx[:m2 ] = sp[:m2] * space.multiplier
560
+ custom << spx
561
+ end
562
+ end
563
+
564
+ if custom.empty?
565
+ lgs << "Unknown UNCONDITIONED spaces (#{mth})?"
566
+ return
567
+ end
568
+
569
+ csp = custom.sort_by { |sp| sp[:m2] }.reverse.first
570
+
571
+ cspaces = csp[:spaces]
572
+ @structure = csp[:structure]
573
+ @framing = csp[:framing]
574
+ @cladding = csp[:cladding]
575
+ @finish = csp[:finish]
576
+ bldg.additionalProperties.setFeature("btap_structure", @structure.to_s)
577
+ bldg.additionalProperties.setFeature("btap_framing", @framing.to_s)
578
+ bldg.additionalProperties.setFeature("btap_cladding", @cladding.to_s)
579
+ bldg.additionalProperties.setFeature("btap_finish", @finish.to_s)
580
+
581
+ cspaces.each { |space| @spaces.delete(space.nameString) }
582
+ end
583
+
584
+ if cspaces.empty?
585
+ lgs << "Invalid # CONDITIONED spaces (#{mth})?"
586
+ return
587
+ end
588
+
589
+ # Isolate OCCUPIED spaces.
590
+ ospaces = cspaces.select { |space| space.partofTotalFloorArea }
591
+
592
+ # Scenario A - no space customization, i.e. default BTAP scenario:
593
+ # - take-off areas below (m2) reflect all CONDITIONED spaces
594
+ #
595
+ # Scenario B - one or more spaces are customized, e.g. :framing
596
+ # - take-off areas below (m2) reflect non-customized spaces only
597
+ # - look up @spaces to retrieve custom space-specific take-offs.
598
+ m2 = cspaces.sum(&:floorArea)
599
+ om2 = ospaces.sum(&:floorArea)
600
+
601
+ # --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #
381
602
  # 'Dead load' refers to the self-weight of structural elements of a
382
603
  # building, as well as non-structural fixtures that are permanently
383
604
  # attached to the building. They are considered 'dead' as they typically
384
- # do not move around during the life of the building. If/once a building
605
+ # do not move around during the life of the building. Once a building
385
606
  # is resold, its new owners recover dead load as 'real estate assets'.
386
607
  # Dead load typically falls under design scopes of architects/engineers.
387
608
  # Although there are obvious design constraints to consider (e.g. fire
@@ -392,58 +613,78 @@ module BTAP
392
613
  # - between foam vs fibrous insulation options
393
614
  #
394
615
  # Most dead load is modelled explicitly in OpenStudio, like envelope and
395
- # interzone sub/surfaces. Rough estimates of embodied carbon (in CO2-e
396
- # kg/m2) can be reasonably associated to selected construction assemblies
397
- # (based on m2), such as the embodied carbon of chosen insulation
398
- # materials or framing options. Other dead load, like lighting and HVAC,
399
- # are not modelled explicitly. Here, the 'deadload' attribute represents
400
- # a mass floor area density estimate (kg/m2) of non-modelled structural
401
- # and non-structural items like fixed furniture, partitions, columns,
402
- # beams, shear walls and bracing.
403
-
404
- # First, isolate occupied spaces & floors, as well as exposed surfaces.
405
- cspaces = model.getSpaces.select { |sp| sp.partofTotalFloorArea }
406
- floor_m2 = TBD.facets(cspaces, "all", "floor").map(&:grossArea).sum
407
- ofloor_m2 = TBD.facets(cspaces, "outdoors", "floor").map(&:grossArea).sum
408
- ifloor_m2 = TBD.facets(cspaces, "surface", "floor").map(&:grossArea).sum
409
- roof_m2 = TBD.facets(cspaces, "outdoors", "roofceiling").map(&:grossArea).sum
410
- wall_m2 = TBD.facets(cspaces, "outdoors", "walls").map(&:grossArea).sum
411
- iwall_m2 = TBD.facets(cspaces, "surface", "wall").map(&:grossArea).sum
412
-
413
- # In OpenStudio, partitions are usually limited to interzone walls between
414
- # zones, in order to save on simulation times. Partitions typically absent
415
- # from a model include walls surrounding lobbies, stairwells, WCs and
416
- # technical rooms, as well as separations between similar rooms (e.g.
417
- # multiple, side-by-side enclosed offices, a row of hotel rooms).
418
- # Comparing BTAP prototype models and samples of building plans for
419
- # similar facilities suggest matching modelled partition m2 (or total
420
- # floor m2) as a suitable basis to determine the weight of non-modelled
421
- # partitions. As this estimate may be more on the high side for many
422
- # prototype models, fixed appliances (e.g. fixtures, counters, doors and
423
- # windows) are considered included.
424
- # partition_m2 = iwall_m2
425
- # partition_m2 = floor_m2 if partition_m2 > floor_m2
426
- partition_m2 = floor_m2
427
-
428
- # For wood-framed partitions, representative material volumes (per m2):
616
+ # interzone surfaces. Rough estimates of embodied carbon (in CO2-e kg of
617
+ # surface m2) can be reasonably associated to selected construction
618
+ # assemblies, such as the embodied carbon of chosen insulation materials
619
+ # or framing options. Other dead load, like lighting and HVAC, are not
620
+ # modelled explicitly. Here, the 'deadload' attribute represents a mass
621
+ # floor area density estimate (kg/m2) of non-modelled structural and
622
+ # non-structural items like fixed furniture, columns, beams, shear walls
623
+ # and bracing, as well as 'partitions'.
624
+ #
625
+ # Note that OpenStudio supports an InteriorPartitionSurface class, useful
626
+ # mainly for daylighting. Although similar, 'partition' (within the scope
627
+ # of BTAP::Structure) more generally refers to any non-modelled wall, e.g.
628
+ # those surrounding lobbies, stairwells, WCs and technical rooms, as well
629
+ # as separations between similar rooms (e.g. multiple, side-by-side
630
+ # enclosed offices, a row of hotel rooms). Comparing BTAP prototype models
631
+ # and samples of building plans for similar facilities suggests matching
632
+ # modelled partition m2 with floor m2 as a suitable basis to estimate the
633
+ # mass of non-modelled partitions. As this estimate may be more on the
634
+ # high side for many prototype models, fixed appliances (e.g. fixtures,
635
+ # counters, doors and windows) are considered included. Adjusting for
636
+ # larger spaces, based on building category.
637
+ partition_m2 = case @category
638
+ when "commerce" then m2 / 2
639
+ when "industry" then m2 / 4
640
+ when "recreation" then m2 / 3
641
+ else m2
642
+ end
643
+
644
+ # For wood-framed partitions, representative material mass (per m2):
429
645
  # - 16% wood-framing: 0.0224 m3/m2 x 540 kg/m3 = 12.1 kg/m2 (35.7%)
430
646
  # - 84% insulation : 0.1176 m3/m2 x 19 kg/m3 = 2.2 kg/m2 ( 6.5%)
431
647
  # - drywall (2x) : 0.0250 m3/m2 x 785 kg/m3 = 19.6 kg/m2 (57.8%)
432
648
  # = 33.9 kg/m2
433
649
  #
434
- # For steel-framed partitions, representative material volumes (per m2):
650
+ # For steel-framed partitions, representative material mass (per m2):
435
651
  # - 1% steel-framing: 1.25 x 2.5 x 1.5 kg/m = 4.7 kg/m2 (17.3%)
436
652
  # - 99% insulation : 0.1504 m3/m2 x 19 kg/m3 = 2.9 kg/m2 (10.7%)
437
653
  # - drywall (2x) : 0.0250 m3/m2 x 785 kg/m3 = 19.6 kg/m2 (72.0%)
438
654
  # = 27.2 kg/m2
439
655
  #
440
- # For CMU partitions, representative material volumes (per m2):
656
+ # For CMU partitions, representative material mass (per m2):
441
657
  # - 10" medium weight CMU = 250.0 kg/m2 (approx.)
658
+ partition_rho = case @framing
659
+ when :cmu then 250.0
660
+ when :wood then 33.9
661
+ else 27.2
662
+ end
663
+
664
+ # Partition kg / floor area.
665
+ partition_kgm2 = 0
666
+ partition_kgm2 = partition_rho * partition_m2 / m2 if m2 > 0
667
+
668
+ # Repeat for customized spaces.
669
+ @spaces.each do |id, sp|
670
+ sp[:partition_m2] = case @category
671
+ when "commerce" then sp[:m2] / 2
672
+ when "industry" then sp[:m2] / 4
673
+ when "recreation" then sp[:m2] / 3
674
+ else sp[:m2]
675
+ end
676
+
677
+ if sp.key?(:framing)
678
+ p_rho = case sp[:framing]
679
+ when :cmu then 250.0
680
+ when :wood then 33.9
681
+ else 27.2
682
+ end
683
+ else
684
+ p_rho = partition_rho
685
+ end
442
686
 
443
- case @framing
444
- when :cmu then partition_kgm2 = 250.0 * partition_m2 / floor_m2
445
- when :wood then partition_kgm2 = 33.9 * partition_m2 / floor_m2
446
- else partition_kgm2 = 27.2 * partition_m2 / floor_m2
687
+ sp[:partition_kgm2] = p_rho * sp[:partition_m2] / sp[:m2]
447
688
  end
448
689
 
449
690
  # Structural dead load - not explicitly modelled - include columns,
@@ -452,38 +693,68 @@ module BTAP
452
693
  # - 9m x 9m spans
453
694
  # - approx. 15 columns / 1000 m2 of floor area
454
695
  # - approx. 14" x 14" columns (0.126 m2)
455
- # - if structure :steel or :metal (HP14x102):
456
- # - 152 kg/m (x 125% for bracing, etc.) = 190 kg/m
696
+ # - if structure :steel or :metal (W10x49)
697
+ # - 73 kg/m (x 125% for bracing, etc.) = 91 kg/m
457
698
  # - if structure :concrete
458
699
  # - concrete: 2240 kg/m3 x 0.126 m2 x 97% = 274 kg/m
459
700
  # - rebar: 7850 kg/m3 x 0.126 m2 x 3% = 30 kg/m
460
- # = 304 kg/m (+11%)
701
+ # = 304 kg/m
702
+ # - x 125% for shear walls, etc. = 380 kg/m
461
703
  # - if structure :cmu (mix of load bearing walls + smaller pours)
462
- # - 1/2 :concrete = 150 kg/m
704
+ # - 1/2 :concrete = 190 kg/m
463
705
  # - if structure :clt
464
706
  # - wood: 540 kg/m3 x 0.126 m2 x 97% = 66 kg/m
465
707
  # - anchors: 7850 kg/m3 x 0.126 m2 x 3% = 30 kg/m
466
- # = 96 kg/m (+45%)
708
+ # = 96 kg/m
709
+ # - x 125% for shear walls, etc. = 120 kg/m
467
710
  # - if structure :wood
468
- # - 1/2 :clt = 48 kg/m
711
+ # - 1/2 :clt = 60 kg/m
712
+
713
+ # Fetch approx. total column height (m) and linear density.
714
+ column_m = 0
715
+ column_rho = case @structure
716
+ when :steel then 91
717
+ when :metal then 91
718
+ when :cmu then 190
719
+ when :wood then 60
720
+ when :clt then 120
721
+ else 380
722
+ end
469
723
 
470
- # Fetch approx. total column height (m) in building (including plenums).
471
- column_m = 0
724
+ cspaces.each do |space|
725
+ zn = space.thermalZone
726
+ next if zn.empty?
472
727
 
473
- model.getSpaces.each do |space|
474
- column_m += BTAP::Geometry::Spaces.space_height(space) * 15 / 1000
475
- end
728
+ fm2 = space.floorArea
729
+ next unless fm2 > 0
476
730
 
477
- case @structure
478
- when :steel then column_kgm2 = 190 * column_m / floor_m2
479
- when :metal then column_kgm2 = 190 * column_m / floor_m2
480
- when :cmu then column_kgm2 = 150 * column_m / floor_m2
481
- when :wood then column_kgm2 = 48 * column_m / floor_m2
482
- when :clt then column_kgm2 = 96 * column_m / floor_m2
483
- else column_kgm2 = 304 * column_m / floor_m2
731
+ column_m += BTAP::Geometry::Spaces.space_height(space) * fm2 * 15 / 1000
484
732
  end
485
733
 
486
- @deadload = partition_kgm2 + column_kgm2
734
+ column_kgm2 = 0
735
+ column_kgm2 = column_rho * column_m / m2 if m2 > 0
736
+ @deadload = partition_kgm2 + column_kgm2
737
+
738
+ # Repeat for customized spaces.
739
+ @spaces.values.each do |sp|
740
+ col_m = sp[:h] * sp[:m2] * 15 / 1000
741
+
742
+ if sp.key?(:structure)
743
+ c_rho = case sp[:structure]
744
+ when :steel then 91
745
+ when :metal then 91
746
+ when :cmu then 190
747
+ when :wood then 60
748
+ when :clt then 120
749
+ else 380
750
+ end
751
+ else
752
+ c_rho = column_rho
753
+ end
754
+
755
+ sp[:column_kgm2] = c_rho * col_m / sp[:m2]
756
+ sp[:deadload ] = sp[:partition_kgm2] + sp[:column_kgm2]
757
+ end
487
758
 
488
759
  # The 'liveload' attribute represents the mass area density (kg/m2) of
489
760
  # dynamic, yet uniform floor live load from non-permanent items like
@@ -494,7 +765,7 @@ module BTAP
494
765
  # item, live load is not considered when tallying embodied carbon.
495
766
  #
496
767
  # Within BTAP, non-occupant live load estimates are stored in the
497
- # "NECB_building_types.csv" file, parsed/stored in a BTAP::Activity
768
+ # "btap_building_types.csv" file, parsed/stored in a BTAP::Activity
498
769
  # instance (1x per building activity). These estimates are initially based
499
770
  # on NBC Part 4 minimum live load requirements (kPa), as well as data from
500
771
  # established structural engineering resources. Minimum live load kPa (or
@@ -514,18 +785,31 @@ module BTAP
514
785
  # types, including bigbox retail and warehousing. Grain of salt.
515
786
  @liveload = lload
516
787
 
517
- # Add internal mass objects, 1x instance per occupied space.
788
+ # Cap internal mass density to 1000 kg/m3, and thickness to 6".
789
+ rho = 1000.0
790
+ th = 0.150
791
+
792
+ # Add internal mass objects, 1x instance per CONDITIONED space.
518
793
  cspaces.each do |space|
519
794
  break unless massive
520
795
 
521
- matID = "#{space.nameString} : Mass Material"
522
- conID = "#{space.nameString} : Mass Construction"
523
- defID = "#{space.nameString} : Mass Definition"
524
- mssID = "#{space.nameString} : Mass"
796
+ id = space.nameString
797
+
798
+ matID = "#{id} : Mass Material"
799
+ conID = "#{id} : Mass Construction"
800
+ defID = "#{id} : Mass Definition"
801
+ mssID = "#{id} : Mass"
802
+
803
+ # Calculate total internal mass (kg), then thickness.
804
+ if @spaces.key?(id)
805
+ load_kgm2 = @liveload + @spaces[id][:deadload]
806
+ else
807
+ load_kgm2 = @deadload
808
+ load_kgm2 += @liveload if ospaces.include?(space)
809
+ end
525
810
 
526
- # Calculate total mass of internal mass (kg), then thickness.
527
- kg = space.floorArea * (@liveload + @deadload)
528
- m2 = kg / rho / th
811
+ kg = space.floorArea * load_kgm2
812
+ im2 = kg / rho / th
529
813
 
530
814
  mat = OpenStudio::Model::StandardOpaqueMaterial.new(model)
531
815
  mat.setName(matID)
@@ -548,110 +832,211 @@ module BTAP
548
832
  df.setName(defID)
549
833
  df.setConstruction(con)
550
834
  df.setSurfaceArea(space.floorArea)
551
- df.setSurfaceArea(m2)
835
+ df.setSurfaceArea(im2)
552
836
 
553
837
  mass = OpenStudio::Model::InternalMass.new(df)
554
838
  mass.setName(mssID)
555
839
  mass.setSpace(space)
556
840
  end
557
841
 
558
- # Embodied CO2-e kg (A1-A3) of a model is tallied separately as follows:
559
- @co2 = {}
560
- @co2[:structure ] = 0
561
- @co2[:insulation] = 0
562
- @co2[:cladding ] = 0
563
-
564
- # The :structure key/value pair includes above grade 'structures' (e.g.
565
- # slabs, columns) and 'framing' (e.g. wood-framed vs steel-framed). Why
566
- # grouped together? In many smaller-scale facilities, structure and
567
- # framing are synonymous, or at least tightly coupled, e.g.:
568
- # - load-bearing wood-framed walls in small-scale residential
569
- # - load-bearing CMU walls in small-scale industrial
570
- # - metal buildings
571
- #
572
- # Below-grade structures (rebar + poured concrete) are ignored - no
573
- # alternative options are considered for the moment, e.g. lower carbon
574
- # concrete mixes.
842
+ # Embodied CO2-e kg (A1-A3?) of a model's structure is broken down into:
843
+ # - non-modelled above grade items COLUMNS
844
+ # - non-modelled PARTITIONS
575
845
  #
576
- # Upon initialization, only the :structure tally is set. It is assumed
577
- # that structure (and main framing) do not change with NECB U-factor
578
- # requirements, e.g.:
579
- # - NECB 2011 vs 2020
580
- # - Vancouver vs Calgary
846
+ # COLUMN and PARTITION CO2-e kg estimates are limited to non-customized
847
+ # spaces (look for equivalent entries in customized @spaces). Yet
848
+ # all COLUMN and PARTITION estimates (for both custom and non-custom
849
+ # spaces) are ultimately tallied in the STRUCTURE CO2-e kg entry.
581
850
  #
582
- # Once default construction sets are (later) established (+), followed by
583
- # TBD uprating assemblies as per NECB 2017 & 2020 requirements (++),
584
- # embodied carbon tallies can be updated/reset, which would include:
585
- # - cladding
586
- # - insulation
587
- # - secondary framing (proportional to insulation thicknesses)
588
- #
589
- # (+) openstudio-standards/standards/necb/NECB2011/building_envelope.rb
590
- # (++) openstudio-standards/btap/bridging.rb
591
-
592
- # Start with occupied floors & roofs (exclude slabs on grade).
593
- m2 = ofloor_m2 + ifloor_m2 + roof_m2
594
-
595
- case @structure
596
- when :wood then # engineered I-joists + plywood
597
- floor_kg = 50.0 * m2
598
- floor_m3 = floor_kg / 540.0 # kg/m3
599
- floor_co2kg = floor_m3 * 55.0 / floor_kg # kgCO2-e/kg
600
- when :concrete then # 200mm flat slab, 3% rebar + accessories
601
- floor_m3 = 0.200 * m2
602
- floor_kgm3 = (0.03 * 7850.0) + (0.97 * 2240.0) # kg/m3
603
- floor_co2kg = (0.03 * 0.854 ) + (0.97 * 0.250) # kgCO2-e/kg
604
- floor_kg = floor_m3 * floor_kgm3
605
- else # :steel, includes joists/fasteners
606
- floor_m3 = 0.125 * m2
607
- floor_kgm3 = (0.08 * 7850.0) + (0.92 * 2240.0) # kg/m3
608
- floor_co2kg = (0.08 * 0.854 ) + (0.92 * 0.250) # kgCO2-e/kg
609
- floor_kg = floor_m3 * floor_kgm3
610
- end
851
+ # Note that below-grade structures (rebar + poured concrete) are ignored,
852
+ # as there are no alternative BTAP options (e.g. low carbon concrete mix).
853
+ @co2 = {}
854
+
855
+ # Add columns.
856
+ column_kgco2kg = case @structure
857
+ when :steel then 0.854 # 0.854 kgCO2-e/kg
858
+ when :metal then 0.854 # 0.854 kgCO2-e/kg
859
+ when :wood then 55.000 / 540.0 # 55.000 kgCO2-e/m3
860
+ when :clt then 55.000 / 540.0 # 55.000 kgCO2-e/m3
861
+ else 0.268 # 0.268 kgCO2-e/kg
862
+ end
863
+
864
+ @co2[:columns] = column_kgco2kg * column_m * column_rho
865
+
866
+ # Add interior partitions, based on framing options only. Other partition
867
+ # components are ignored for now (e.g. drywall, acoustic insulation).
868
+ partition_kgco2m2 = case @framing
869
+ when :wood then 55.000 * 12.1 / 540.0
870
+ when :cmu then 200.000 * 0.250
871
+ else 0.854 * 4.7
872
+ end
873
+
874
+ @co2[:partitions] = partition_kgco2m2 * partition_m2
875
+ @co2[:structure ] = @co2[:columns] + @co2[:partitions]
876
+
877
+ # Repeat for customized spaces.
878
+ @spaces.each do |id, sp|
879
+ if sp.key?(:structure)
880
+ c_kgco2kg = case sp[:structure]
881
+ when :steel then 0.854 # 0.854 kgCO2-e/kg
882
+ when :metal then 0.854 # 0.854 kgCO2-e/kg
883
+ when :wood then 55.000 / 540.0 # 55.000 kgCO2-e/m3
884
+ when :clt then 55.000 / 540.0 # 55.000 kgCO2-e/m3
885
+ else 0.268 # 0.268 kgCO2-e/kg
886
+ end
887
+ else
888
+ c_kgco2kg = column_kgco2kg
889
+ end
611
890
 
612
- @co2[:structure] += floor_co2kg * floor_kg
613
-
614
- # Add exposed walls and interior partitions.
615
- m2 = wall_m2 + iwall_m2 + partition_m2
616
-
617
- case @framing
618
- when :wood then # basic 2x6 construction, 16% of framing cavity
619
- wall_kg = 12.1 * m2
620
- wall_co2kg = 55.0 / 540.0 # 55 kgCO2-e/m3 / density
621
- when :cmu then # 250mm medium weight CMU, 200 kgCO2-e/m3
622
- wall_m3 = 0.250 * m2 # nominal m3
623
- wall_kg = 250.0 * m2 # volume-weighted concrete/air/grout
624
- wall_kgm3 = 0.250 / 250.0
625
- wall_co2kg = 200.0 / wall_kgm3 # 200 kgCO2-e/m3 / density
626
- else # :steel, 1% lightweight steel-framing
627
- wall_kg = 4.7 * m2
628
- wall_co2kg = 2.440
891
+ if sp.key?(:framing)
892
+ p_kgco2m2 = case sp[:framing]
893
+ when :wood then 55.000 * 12.1 / 540.0
894
+ when :cmu then 200.000 * 0.250
895
+ else 0.854 * 4.7
896
+ end
897
+ else
898
+ p_kgco2m2 = partition_kgco2m2
899
+ end
900
+
901
+ sp[:co2][:columns ] = c_kgco2kg * sp[:column_kgm2] * sp[:m2]
902
+ sp[:co2][:partitions] = p_kgco2m2 * sp[:partition_m2]
903
+
904
+ @co2[:structure] += sp[:co2][:columns] + sp[:co2][:partitions]
629
905
  end
630
906
 
631
- @co2[:structure] += wall_co2kg * wall_kg
907
+ # Set an AdditionalProperty for tallied CO2-e [kg] (A1-A3):
908
+ tag = "co2_structure"
909
+ bldg.additionalProperties.setFeature(tag, @co2[:structure])
632
910
 
633
911
  true
634
912
  end
635
913
 
636
914
  ##
637
- # Updates and returns embodied carbon estimates (A1-A3).
915
+ # Returns an (inherited) AdditionalProperty, applicable to a given space.
916
+ # Four admissible STRUCTURE AdditionalProperty keys: "btap_structure",
917
+ # "btap_framing", "btap_cladding", "btap_finish". If an AdditionalProperty
918
+ # key is correctly identified yet its value invalid (per BTAP::Structure
919
+ # rules), its value is reset to building defaults.
638
920
  #
639
- # @param model [OpenStudio::Model::Model] a model
921
+ # @param space [OpenStudio::Model::Space] a space
922
+ # @param tag [String] AdditionalProperty key, e.g. "btap_structure"
640
923
  #
641
- # @return [Hash] embodied carbon tally (CO2-e kg, A1-A3)
642
- def tallyCO2(model)
924
+ # @return [Symbol] AdditionalProperty value (nil if invalid inputs)
925
+ def property(space = nil, tag = "")
643
926
  mth = "BTAP::Structure::#{__callee__}"
644
- cl = OpenStudio::Model::Model
645
927
  lgs = @feedback[:logs]
928
+ prp = nil
929
+
930
+ unless space.is_a?(OpenStudio::Model::Space)
931
+ lgs << "Invalid or empty OpenStudio space (#{mth})"
932
+ return prp
933
+ end
934
+
935
+ unless tag.respond_to?(:to_sym)
936
+ lgs << "Invalid STRUCTURE AddtionalProperty tag (#{mth})"
937
+ return prp
938
+ end
939
+
940
+ tag = tag.to_s.downcase
941
+
942
+ unless data[:tags].include?(tag)
943
+ lgs << "Unrecognized STRUCTURE AddtionalProperty '#{tag}' (#{mth})"
944
+ return prp
945
+ end
946
+
947
+ # Check if the AdditionalProperty is assigned to the space itself.
948
+ if space.additionalProperties.hasFeature(tag)
949
+ prp = space.additionalProperties.getFeatureAsString(tag)
646
950
 
647
- unless model.is_a?(cl)
648
- lgs << "Invalid OpenStudio model (#{mth})"
649
- return 0
951
+ if prp.empty?
952
+ lgs << "Unknown space AddtionalProperty '#{tag}' (#{mth})"
953
+ prp = nil
954
+ else
955
+ prp = prp.get.downcase.to_sym
956
+ end
957
+ end
958
+
959
+ # Check if the AdditionalProperty is instead assigned to the spacetype.
960
+ unless prp
961
+ type = space.spaceType
962
+
963
+ unless type.empty?
964
+ type = type.get
965
+
966
+ if type.additionalProperties.hasFeature(tag)
967
+ prp = type.additionalProperties.getFeatureAsString(tag)
968
+
969
+ if prp.empty?
970
+ lgs << "Unknown spacetype AddtionalProperty '#{tag}' (#{mth})"
971
+ prp = nil
972
+ else
973
+ prp = prp.get.downcase.to_sym
974
+ end
975
+ end
976
+ end
650
977
  end
651
978
 
652
- # @todo
979
+ # Check if the AdditionalProperty is instead assigned to building story.
980
+ unless prp
981
+ story = space.buildingStory
982
+
983
+ unless story.empty?
984
+ story = story.get
985
+
986
+ if story.additionalProperties.hasFeature(tag)
987
+ prp = story.additionalProperties.getFeatureAsString(tag)
988
+
989
+ if prp.empty?
990
+ lgs << "Unknown story AddtionalProperty '#{tag}' (#{mth})"
991
+ prp = nil
992
+ else
993
+ prp = prp.get.downcase.to_sym
994
+ end
995
+ end
996
+ end
997
+ end
998
+
999
+ # Validate, based on STRUCTURE rules - attempt to fix if invalid.
1000
+ if prp
1001
+ case tag
1002
+ when "btap_structure"
1003
+ if data[:structure].key?(prp)
1004
+ prp = :steel if prp == :metal # temporary - @todo
1005
+ prp = :concrete if prp == :clt # temporary - @todo
1006
+ else
1007
+ prp = @structure
1008
+ space.additionalProperties.setFeature(tag, prp.to_s)
1009
+ end
1010
+ when "btap_framing"
1011
+ structure = property(space, "btap_structure")
1012
+ structure = @structure unless structure
1013
+
1014
+ if data[:structure].key?(structure)
1015
+ unless data[:structure][structure][:frames].include?(prp)
1016
+ prp = data[:structure][structure][:framing]
1017
+ space.additionalProperties.setFeature(tag, prp.to_s)
1018
+ end
1019
+ else
1020
+ prp = data[:structure][@structure][:framing]
1021
+ bldg.additionalProperties.setFeature(tag, prp.to_s)
1022
+ end
1023
+ when "btap_cladding"
1024
+ unless data[:cladding].include?(prp)
1025
+ prp = @cladding
1026
+ space.additionalProperties.setFeature(tag, prp.to_s)
1027
+ end
1028
+ when "btap_finish"
1029
+ unless data[:finish].include?(prp)
1030
+ prp = @finish
1031
+ space.additionalProperties.setFeature(tag, prp.to_s)
1032
+ end
1033
+ else
1034
+ lgs << "Unknown AddtionalProperty '#{tag}' (#{mth})"
1035
+ prp = nil
1036
+ end
1037
+ end
653
1038
 
654
- @co2
1039
+ prp
655
1040
  end
656
1041
  end
657
1042
  end