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,177 +1,234 @@
1
- class BTAPCarbon
2
- def initialize(attributes:, standards_data:)
3
- @carbon_database = {}
4
- @costing_database = CostingDatabase.instance
5
- @cp = CommonPaths.instance
6
- @attributes = attributes
7
- @carbon_report = {}
8
- @frame_m_to_kg = standards_data["constants"]["glazing_frame_m_to_kg"]
9
-
10
- # Build the carbon database.
11
- carbon_opaque = CSV.read(@cp.carbon_opaque_path)
12
- @carbon_database["opaque"] = Array.new
13
-
14
- 1.upto carbon_opaque.length - 1 do |i|
15
- row = carbon_opaque[i]
16
- index = row.each
17
- item = Hash.new
18
-
19
- item["materials_opaque_id"] = index.next
20
- item["description"] = index.next
21
- item["type"] = index.next
22
- item["quantity"] = index.next.to_f
23
- item["per m2"] = index.next.to_f
24
- item["Product Category"] = index.next
25
- item["Embodied Carbon (A1-A5)"] = index.next.to_f
26
- item["Embodied Carbon (A-C)"] = index.next.to_f
27
- item["Environmental Product Declaration (EPD)"] = index.next
28
-
29
- @carbon_database["opaque"] << item
30
- end
1
+ # BTAP Carbon
2
+ #
3
+ # Calculates embodied carbon emissions currently accounting only for building
4
+ # envelopes.
5
+
6
+ module BTAP
7
+ class Carbon
8
+
9
+ # @param attributes [BTAP::Attributes]
10
+ # @param standards_data [Hash] Required for window frame conversions.
11
+ def initialize(attributes:, standards_data:)
12
+ @carbon_database = {}
13
+ @costing_database = Database.instance
14
+ @attributes = attributes
15
+ @carbon_report = {}
16
+ @frame_m_to_kg = standards_data["constants"]["glazing_frame_m_to_kg"]
17
+
18
+ # Build the carbon database.
19
+ carbon_opaque = CSV.read(Paths::CARBON_OPAQUE_PATH)
20
+ @carbon_database["opaque"] = Array.new
21
+
22
+ 1.upto carbon_opaque.length - 1 do |i|
23
+ row = carbon_opaque[i]
24
+ index = row.each
25
+ item = Hash.new
26
+
27
+ item["materials_opaque_id"] = index.next
28
+ item["description"] = index.next
29
+ item["type"] = index.next
30
+ item["quantity"] = index.next.to_f
31
+ item["per m2"] = index.next.to_f
32
+ item["Product Category"] = index.next
33
+ item["Embodied Carbon (A1-A5)"] = index.next.to_f
34
+ item["Embodied Carbon (A-C)"] = index.next.to_f
35
+ item["Environmental Product Declaration (EPD)"] = index.next
36
+
37
+ @carbon_database["opaque"] << item
38
+ end
31
39
 
32
- carbon_glazing = CSV.read(@cp.carbon_glazing_path)
33
- @carbon_database["glazing"] = Array.new
40
+ carbon_glazing = CSV.read(Paths::CARBON_GLAZING_PATH)
41
+ @carbon_database["glazing"] = Array.new
34
42
 
35
- 1.upto carbon_glazing.length - 1 do |i|
36
- row = carbon_glazing[i]
37
- index = row.each
38
- item = Hash.new
43
+ 1.upto carbon_glazing.length - 1 do |i|
44
+ row = carbon_glazing[i]
45
+ index = row.each
46
+ item = Hash.new
39
47
 
40
- item["materials_glazing_id"] = index.next
41
- item["description"] = index.next
42
- item["per m2"] = index.next.to_f
43
- item["Embodied Carbon (A1-A5)"] = index.next.to_f
44
- item["Embodied Carbon (A-C)"] = index.next.to_f
45
- item["Environmental Product Declaration (EPD)"] = index.next
48
+ item["materials_glazing_id"] = index.next
49
+ item["description"] = index.next
50
+ item["per m2"] = index.next.to_f
51
+ item["Embodied Carbon (A1-A5)"] = index.next.to_f
52
+ item["Embodied Carbon (A-C)"] = index.next.to_f
53
+ item["Environmental Product Declaration (EPD)"] = index.next
46
54
 
47
- @carbon_database["glazing"] << item
48
- end
55
+ @carbon_database["glazing"] << item
56
+ end
49
57
 
50
- carbon_frame = CSV.read(@cp.carbon_frame_path)
51
- @carbon_database["frame"] = Array.new
58
+ carbon_frame = CSV.read(Paths::CARBON_FRAME_PATH)
59
+ @carbon_database["frame"] = Array.new
52
60
 
53
- 1.upto carbon_frame.length - 1 do |i|
54
- row = carbon_frame[i]
55
- index = row.each
56
- item = Hash.new
61
+ 1.upto carbon_frame.length - 1 do |i|
62
+ row = carbon_frame[i]
63
+ index = row.each
64
+ item = Hash.new
57
65
 
58
- item["materials_glazing_id"] = index.next
59
- item["description"] = index.next
60
- item["per m2"] = index.next.to_f
61
- item["Embodied Carbon (A1-A5)"] = index.next.to_f
62
- item["Embodied Carbon (A-C)"] = index.next.to_f
63
- item["Environmental Product Declaration (EPD)"] = index.next
66
+ item["materials_glazing_id"] = index.next
67
+ item["description"] = index.next
68
+ item["per m2"] = index.next.to_f
69
+ item["Embodied Carbon (A1-A5)"] = index.next.to_f
70
+ item["Embodied Carbon (A-C)"] = index.next.to_f
71
+ item["Environmental Product Declaration (EPD)"] = index.next
64
72
 
65
- @carbon_database["frame"] << item
73
+ @carbon_database["frame"] << item
74
+ end
66
75
  end
67
- end
68
76
 
69
- def audit_embodied_carbon
70
- @attributes.surface_types.each do |surface_type|
71
- @carbon_report["#{surface_type.underscore}_area_m2"] = 0.0
72
- @carbon_report["#{surface_type.underscore}_carbon"] = 0.0
73
- end
77
+ def audit_embodied_carbon
78
+ total_emissions = 0
74
79
 
75
- @attributes.spaces.each do |space|
76
80
  @attributes.surface_types.each do |surface_type|
77
- space.surfaces_hash[surface_type].each do |surface|
78
- surface_area = surface.netArea * space.thermalZone.get.multiplier
79
- @carbon_report["#{surface_type.underscore}_area_m2"] = \
80
- (@carbon_report["#{surface_type.underscore}_area_m2"] + surface_area).round(2)
81
-
82
- # Get the carbon emissions for each material in the space.
83
- if surface.construction_hash.nil?
84
- emissions = 0.0
85
- else
86
- emissions = get_carbon_emissions(surface.construction_hash, surface, surface_area)
87
- construction = surface.construction_hash
88
- end
81
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_area_m2"] = 0.0
82
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_carbon"] = 0.0
83
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_carbon_per_m2"] = 0.0
84
+ end
89
85
 
90
- # Calculate the carbon emissions
91
- @carbon_report["#{surface_type.underscore}_carbon"] = \
92
- (@carbon_report["#{surface_type.underscore}_carbon"] + emissions).round(2)
86
+ # Calculate emissions for all constructions found by BTAP Attributes.
87
+ @attributes.constructions.each_value do |construction|
88
+ construction["subsets"].each do |subset|
89
+ subset["carbon"] = emissions_from_construction(subset, construction["type"])
93
90
  end
94
91
  end
95
- end
96
92
 
97
- # Get the total emissions from all the surface types.
98
- total_emissions = 0
99
- @attributes.surface_types.each do |surface_type|
100
- total_emissions += @carbon_report["#{surface_type.underscore}_carbon"]
101
- end
93
+ # Calculate window perimeter for frame calculations.
94
+ @attributes.compile_window_perimeter
102
95
 
103
- @carbon_report["total"] = total_emissions
104
- return @carbon_report
105
- end
96
+ @attributes.surface_types.each do |surface_type|
97
+ unless @attributes.surface_types_to_assembly_tallies[surface_type].empty?
98
+ @attributes.surface_types_to_assembly_tallies[surface_type].each_pair do |assembly_name, tallies|
99
+ total_area = tallies["area"]
100
+ construction = @attributes.constructions[assembly_name]
101
+ rsi = construction["rsi"]
102
+ surface_is_glazing = surface_type =~ /Window/
103
+
104
+ # Factor in window frame emissions if this is a glazing
105
+ # construction. Currently we only have data for fixed and operable
106
+ # windows.
107
+ if surface_is_glazing
108
+ carbon_range_array = construction["subsets"].map { |subset|
109
+ [subset["rsi"], subset["carbon"] + emissions_from_window_frame(subset, tallies["perimeter"])] }
110
+ else
111
+ carbon_range_array = construction["subsets"].map { |subset| [subset["rsi"], subset["carbon"]] }
112
+ end
113
+
114
+ emissions, _ = BTAP::LinearRegression.interpolate(x_y_array: carbon_range_array, x2: rsi)
115
+
116
+ # Calculate the carbon emissions for the surface type and append the
117
+ # result to the total emissions.
118
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_carbon"] = emissions
119
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_area_m2"] = total_area
120
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_carbon_per_m2"] = (
121
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_carbon"] /
122
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_area_m2"])
123
+
124
+ total_emissions += emissions * total_area
125
+ end
126
+ end
127
+ end
106
128
 
107
- # Retrieve the carbon emissions given a surface, its construction, and its area.
108
- def get_carbon_emissions(construction, surface, surface_area)
109
- total_emissions = 0.0
110
- materials_file = "materials_#{construction["type"]}"
111
- id_column = materials_file + "_id"
112
- id_layers_column = "material_#{construction["type"]}_id_layers"
129
+ # Get the total emissions from all the surface types.
130
+ @attributes.surface_types.each do |surface_type|
131
+ total_emissions += @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_carbon"]
132
+ end
113
133
 
114
- construction[id_layers_column].split(',').each do |material_id|
134
+ # Add the embodied carbon tallied from TBD which tallies carbon emissions
135
+ # of items that aren't explicitly modeled
136
+ structure_carbon = @attributes.model.getBuilding.additionalProperties.getFeatureAsDouble("co2_structure").get
137
+ @carbon_report["structure_carbon"] = structure_carbon.round(2)
138
+ total_emissions += structure_carbon
139
+
140
+ # Factor in parapets likewise for costing in `envelope_costing.rb`.
141
+ if @attributes.use_tbd
142
+ wall_carbon_per_m2 = @carbon_report["exterior_wall_carbon_per_m2"]
143
+ parapet_carbon = @attributes.tbd_edge_tallies["parapet"].values.first * wall_carbon_per_m2
144
+ @carbon_report["parapet_carbon"] = parapet_carbon.round(2)
145
+ total_emissions += parapet_carbon
146
+ end
115
147
 
116
- # Locate the material entry in the carbon database
117
- material_carbon = @carbon_database[construction["type"]].find { |row|
118
- row[id_column] == material_id }["Embodied Carbon (A-C)"]
148
+ puts "Warning: Interpolation limits exceeded." if BTAP::LinearRegression.extrapolation_boundaries_exceeded?
119
149
 
120
- if material_carbon.nil?
121
- raise("Error: Could not find material with ID #{material_id} in the carbon database.")
150
+ # Round everything at the end.
151
+ @attributes.surface_types.each do |surface_type|
152
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_carbon"] = \
153
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_carbon"].round(2)
154
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_area_m2"] = \
155
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_area_m2"].round(2)
156
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_carbon_per_m2"] = \
157
+ @carbon_report["#{@attributes.surface_types_to_snake[surface_type]}_carbon_per_m2"].round(2)
122
158
  end
123
159
 
124
- # If the material is glazing, the frame must be calculated by retrieving the perimeter of the window
125
- # and converting according to the correct attributes of the window.
126
- if construction["type"] == "glazing"
127
- fenestration_type = construction["fenestration_type"]
160
+ puts "\nEmbodied carbon data successfully generated. Total embodied carbon emissions is " \
161
+ "#{total_emissions.to_f.round(2)} kg/m^2"
162
+ @carbon_report["total"] = total_emissions
163
+ return @carbon_report
164
+ end
128
165
 
129
- # Skip skylights and doors since we don't have the data for them.
130
- # Only consider fixed and operable windows.
131
- if fenestration_type != "FixedWindow" and fenestration_type != "OperableWindow"
132
- puts "Fenestration type #{fenestration_type} is not defined for carbon calculation, skipping this component."
133
- next
134
- end
166
+ # Retrieve the carbon emissions given a construction.
167
+ #
168
+ # @param construction [Hash]
169
+ # @param type [String] either "opaque" or "glazing"
170
+ # @return [Float]
171
+ def emissions_from_construction(construction, type)
172
+ total_emissions = 0.0
173
+ materials_file = "materials_#{type}"
174
+ id_column = materials_file + "_id"
175
+
176
+ construction["id_layers"].each do |material_id|
177
+ material_entry = get_material_entry(material_id, id_column, type)
178
+ next if material_entry.nil?
179
+ material_emissions = material_entry["Embodied Carbon (A-C)"]
180
+ total_emissions += material_emissions
181
+ end
135
182
 
136
- material_frame = @carbon_database["frame"].find { |row|
137
- row[id_column] == material_id }["Embodied Carbon (A-C)"]
183
+ return total_emissions
184
+ end
138
185
 
139
- # Get the materials_glazing entry from the costing database to access the number of panes the window has.
140
- material_costing = @costing_database["raw"][materials_file].find { |row| row[id_column] == material_id }
186
+ # Retrieve the carbon emissions for window frames. This requires its surface,
187
+ # its construction, and its perimeter.
188
+ #
189
+ # @param construction [Hash]
190
+ # @param Perimeter [Float]
191
+ # @return [Float]
192
+ def emissions_from_window_frame(construction, perimeter)
193
+ fenestration_type = construction["fenestration_type"]
194
+
195
+ # Skip skylights and doors since we don't have the data for them.
196
+ # Only consider fixed and operable windows.
197
+ if fenestration_type != "FixedWindow" and fenestration_type != "OperableWindow"
198
+ puts "Warning: #{construction["name"]} is not available for carbon calculation, returning zero."
199
+ return 0.0
200
+ end
141
201
 
142
- if material_costing.nil?
143
- raise("Error: Could not find material with ID #{material_id} in the costing database.")
144
- end
202
+ frame_emissions = 0.0
203
+ frame_material = construction["frame_material"]
204
+ fenestration_number_of_panes = construction["fenestration_number_of_panes"]
145
205
 
146
- fenestration_number_of_panes = material_costing["fenestration_number_of_panes"]
147
-
148
- # Try to get the correct frame material.
149
- frame_material = nil
150
- construction_component = construction["component"].downcase
151
- construction_description = construction["description"].downcase
152
- ["vinyl-wood", "plastic", "aluminum"].each do |material|
153
- if material in construction_component
154
- frame_material = material
155
- break
156
- elsif material in construction_description
157
- frame_material = material
158
- break
159
- end
160
- end
206
+ construction["id_layers"].each do |material_id|
207
+ material_entry = get_material_entry(material_id, "materials_glazing_id", "frame")
208
+ next if material_entry.nil?
209
+ frame_emissions += material_entry["Embodied Carbon (A-C)"]
210
+ end
161
211
 
162
- if frame_material.nil?
163
- raise("Error: Could not find frame material for glazing ID #{material_id} in constructions_glazing.csv.")
164
- end
212
+ # Get the conversion factor for the window frame and add it to the total emissions.
213
+ conversion_factor = @frame_m_to_kg[frame_material][fenestration_type][fenestration_number_of_panes]
214
+ return frame_emissions * perimeter * conversion_factor
215
+ end
165
216
 
166
- # Get the conversion factor for the window frame and add it to the total emissions.
167
- conversion_factor = @frame_m_to_kg[frame_material][fenestration_type][fenestration_number_of_panes]
168
- perimeter = BTAP::Geometry::Surfaces.getSurfacePerimeterFromVertices(vertices: surface.vertices)
169
- total_emissions += material_frame * perimeter * conversion_factor
217
+ # Get a material entry from the carbon database.
218
+ #
219
+ # @param type [String] Name of the hash key.
220
+ def get_material_entry(id, id_column, materials_file)
221
+ material_entry = @carbon_database[materials_file].find { |row| row[id_column] == id }
222
+
223
+ if material_entry.nil?
224
+ # TODO: This will happen a lot because of the new thermal bridging entries
225
+ # as of nrcan_476. The carbon database needs to be updated. BTAP Carbon
226
+ # will not be very useful until then.
227
+ puts "Error: Could not find #{materials_file} material with ID #{id} in the carbon database. " \
228
+ "Skipping."
170
229
  end
171
230
 
172
- total_emissions += material_carbon * surface_area
231
+ return material_entry
173
232
  end
174
-
175
- return total_emissions
176
233
  end
177
234
  end