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,603 +1,615 @@
1
- class BTAPCosting
2
-
3
- # --------------------------------------------------------------------------------------------------
4
- # This function gets all costs associated with SHW/DHW (i.e., tanks, pumps, flues, piping and
5
- # utility costs)
6
- # --------------------------------------------------------------------------------------------------
7
- def shw_costing(model, prototype_creator)
8
-
9
- @costing_report['shw'] = {}
10
- totalCost = 0.0
11
-
12
- # Get regional cost factors for this province and city
13
- materials_hvac = @costing_database["raw"]["materials_hvac"]
14
- hvac_material = materials_hvac.select {|data|
15
- data['Material'].to_s == "WaterGas"}.first # Get any row from spreadsheet in case of region error
16
- regional_material, regional_installation =
17
- get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material)
18
- # Use wiring to get regional cost factors for electrical equipment such as conduit and VFDs
19
- hvac_material_elec = get_cost_info(mat: 'Wiring', size: 14, unit: nil)
20
- regional_material_elec, regional_installation_elec =
21
- get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material_elec)
22
-
23
- # Store some geometry data for use below...
24
- util_dist, ht_roof, nominal_flr2flr_height, horizontal_dist = getGeometryData(model, prototype_creator)
25
-
26
- template_type = prototype_creator.template
27
-
28
- plant_loop_info = {}
29
- plant_loop_info[:shwtanks] = []
30
- plant_loop_info[:shwpumps] = []
31
- hphw_tank_names = []
32
-
33
- num_reg_gas_tanks = 0
34
- num_reg_oil_tanks = 0
35
- num_elec_tanks = 0
36
- num_hphw_tanks = 0
37
- num_high_eff_gas_tanks = 0
38
- num_high_eff_oil_tanks = 0
39
-
40
- # HPHW heaters are stored outside of the plant loop
41
- # Iterate through these first to determine if their are HPHW heaters
42
- model.getWaterHeaterHeatPumps.each do |hphw|
43
- if hphw.to_WaterHeaterHeatPump.is_initialized
44
- hphw_tank_name = hphw.tank.name.get
45
- hphw_tank_names << hphw_tank_name
1
+ module BTAP
2
+ class Costing
3
+
4
+ # --------------------------------------------------------------------------------------------------
5
+ # This function gets all costs associated with SHW/DHW (i.e., tanks, pumps, flues, piping and
6
+ # utility costs)
7
+ # --------------------------------------------------------------------------------------------------
8
+ def shw_costing(model, prototype_creator)
9
+
10
+ @costing_report['shw'] = {}
11
+ totalCost = 0.0
12
+
13
+ # Get regional cost factors for this province and city
14
+ materials_hvac = @costing_database["raw"]["materials_hvac"]
15
+ hvac_material = materials_hvac.select {|data|
16
+ data['Material'].to_s == "WaterGas"}.first # Get any row from spreadsheet in case of region error
17
+ regional_material, regional_installation =
18
+ get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material)
19
+ # Use wiring to get regional cost factors for electrical equipment such as conduit and VFDs
20
+ hvac_material_elec = get_cost_info(mat: 'Wiring', size: 14, unit: nil)
21
+ regional_material_elec, regional_installation_elec =
22
+ get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material_elec)
23
+
24
+ # Store some geometry data for use below...
25
+ util_dist, ht_roof, nominal_flr2flr_height, horizontal_dist = getGeometryData(model, prototype_creator)
26
+
27
+ template_type = prototype_creator.template
28
+
29
+ plant_loop_info = {}
30
+ plant_loop_info[:shwtanks] = []
31
+ plant_loop_info[:shwpumps] = []
32
+ hphw_tank_names = []
33
+
34
+ num_reg_gas_tanks = 0
35
+ num_reg_oil_tanks = 0
36
+ num_elec_tanks = 0
37
+ num_hphw_tanks = 0
38
+ num_high_eff_gas_tanks = 0
39
+ num_high_eff_oil_tanks = 0
40
+
41
+ # HPHW heaters are stored outside of the plant loop
42
+ # Iterate through these first to determine if their are HPHW heaters
43
+ model.getWaterHeaterHeatPumps.each do |hphw|
44
+ if hphw.to_WaterHeaterHeatPump.is_initialized
45
+ hphw_tank_name = hphw.tank.name.get
46
+ hphw_tank_names << hphw_tank_name
47
+ end
46
48
  end
47
- end
48
- # Iterate through the plant loops to get shw tank & pump data...
49
- model.getPlantLoops.each do |plant_loop|
50
- next unless plant_loop.name.get.to_s =~ /Main Service Water Loop/i
51
- plant_loop.supplyComponents.each do |supply_comp|
52
- if supply_comp.to_WaterHeaterMixed.is_initialized
53
- tank = supply_comp.to_WaterHeaterMixed.get
54
- tank_info = {}
55
- plant_loop_info[:shwtanks] << tank_info
56
- tank_info[:name] = tank.name.get
57
- tank_info[:type] = "WaterHeater:Mixed"
58
- tank_info[:heater_thermal_efficiency] = tank.heaterThermalEfficiency.get unless tank.heaterThermalEfficiency.empty?
59
- tank_info[:heater_fuel_type] = tank.heaterFuelType
60
- tank_info[:nominal_capacity] = tank.heaterMaximumCapacity.to_f / 1000 # kW
61
- tank_info[:heater_volume_gal] = (OpenStudio.convert(tank.tankVolume.to_f, 'm^3', 'gal').get)
62
- tank_info[:eff_mult] = 1.0
63
- if tank.heaterFuelType =~ /Electric/i
64
- # Check if the tank is associated with a HPHW heater
65
- if hphw_tank_names.include?(tank.name.get)
66
- tank_info[:heater_fuel_type] = 'HPHW_Heater'
49
+ # Iterate through the plant loops to get shw tank & pump data...
50
+ model.getPlantLoops.each do |plant_loop|
51
+ next unless plant_loop.name.get.to_s =~ /Main Service Water Loop/i
52
+ plant_loop.supplyComponents.each do |supply_comp|
53
+ if supply_comp.to_WaterHeaterMixed.is_initialized
54
+ tank = supply_comp.to_WaterHeaterMixed.get
55
+ tank_info = {}
56
+ plant_loop_info[:shwtanks] << tank_info
57
+ tank_info[:name] = tank.name.get
58
+ tank_info[:type] = "WaterHeater:Mixed"
59
+ tank_info[:heater_thermal_efficiency] = tank.heaterThermalEfficiency.get unless tank.heaterThermalEfficiency.empty?
60
+ tank_info[:heater_fuel_type] = tank.heaterFuelType
61
+ tank_info[:nominal_capacity] = tank.heaterMaximumCapacity.to_f / 1000 # kW
62
+ tank_info[:heater_volume_gal] = (OpenStudio.convert(tank.tankVolume.to_f, 'm^3', 'gal').get)
63
+ tank_info[:eff_mult] = 1.0
64
+ if tank.heaterFuelType =~ /Electric/i
65
+ # Check if the tank is associated with a HPHW heater
66
+ if hphw_tank_names.include?(tank.name.get)
67
+ tank_info[:heater_fuel_type] = 'HPHW_Heater'
68
+ tank_info[:tank_mult] = get_HVAC_multiplier(tank_info[:heater_fuel_type], tank_info[:nominal_capacity])
69
+ tank_info[:nominal_capacity] /= tank_info[:tank_mult]
70
+ tank_info[:heater_volume_gal] /= tank_info[:tank_mult]
71
+ num_hphw_tanks += tank_info[:tank_mult]
72
+ elsif !hphw_tank_names.include?(tank.name.get)
73
+ tank_info[:heater_fuel_type] = 'WaterElec'
74
+ tank_info[:tank_mult] = get_HVAC_multiplier(tank_info[:heater_fuel_type], tank_info[:nominal_capacity])
75
+ tank_info[:nominal_capacity] /= tank_info[:tank_mult]
76
+ tank_info[:heater_volume_gal] /= tank_info[:tank_mult]
77
+ num_elec_tanks += tank_info[:tank_mult]
78
+ end
79
+ elsif tank.heaterFuelType =~ /NaturalGas/i
80
+ tank_info[:heater_fuel_type] = 'WaterGas'
67
81
  tank_info[:tank_mult] = get_HVAC_multiplier(tank_info[:heater_fuel_type], tank_info[:nominal_capacity])
68
82
  tank_info[:nominal_capacity] /= tank_info[:tank_mult]
69
83
  tank_info[:heater_volume_gal] /= tank_info[:tank_mult]
70
- num_hphw_tanks += tank_info[:tank_mult]
71
- elsif !hphw_tank_names.include?(tank.name.get)
72
- tank_info[:heater_fuel_type] = 'WaterElec'
84
+ if tank_info[:heater_thermal_efficiency] >= 0.85
85
+ tank_info[:heater_fuel_type] = 'WaterGas_HE'
86
+ tank_info[:eff_mult] = 1.3
87
+ num_high_eff_gas_tanks += tank_info[:tank_mult]
88
+ else
89
+ num_reg_gas_tanks += tank_info[:tank_mult]
90
+ end
91
+ elsif tank.heaterFuelType =~ /Oil/i # Oil, FuelOil, FuelOil#2
92
+ tank_info[:heater_fuel_type] = 'WaterOil'
73
93
  tank_info[:tank_mult] = get_HVAC_multiplier(tank_info[:heater_fuel_type], tank_info[:nominal_capacity])
74
94
  tank_info[:nominal_capacity] /= tank_info[:tank_mult]
75
95
  tank_info[:heater_volume_gal] /= tank_info[:tank_mult]
76
- num_elec_tanks += tank_info[:tank_mult]
96
+ if tank_info[:heater_thermal_efficiency] >= 0.85
97
+ tank_info[:heater_fuel_type] = 'WaterOil_HE'
98
+ tank_info[:eff_mult] = 1.3
99
+ num_high_eff_oil_tanks += tank_info[:tank_mult]
100
+ else
101
+ num_reg_oil_tanks += tank_info[:tank_mult]
102
+ end
77
103
  end
78
- elsif tank.heaterFuelType =~ /NaturalGas/i
79
- tank_info[:heater_fuel_type] = 'WaterGas'
80
- tank_info[:tank_mult] = get_HVAC_multiplier(tank_info[:heater_fuel_type], tank_info[:nominal_capacity])
81
- tank_info[:nominal_capacity] /= tank_info[:tank_mult]
82
- tank_info[:heater_volume_gal] /= tank_info[:tank_mult]
83
- if tank_info[:heater_thermal_efficiency] >= 0.85
84
- tank_info[:heater_fuel_type] = 'WaterGas_HE'
85
- tank_info[:eff_mult] = 1.3
86
- num_high_eff_gas_tanks += tank_info[:tank_mult]
104
+ elsif supply_comp.to_PumpConstantSpeed.is_initialized
105
+ csPump = supply_comp.to_PumpConstantSpeed.get
106
+ csPump_info = {}
107
+ plant_loop_info[:shwpumps] << csPump_info
108
+ csPump_info[:name] = csPump.name.get
109
+ if csPump.isRatedPowerConsumptionAutosized.to_bool
110
+ csPumpSize = csPump.autosizedRatedPowerConsumption.to_f
87
111
  else
88
- num_reg_gas_tanks += tank_info[:tank_mult]
112
+ csPumpSize = csPump.ratedPowerConsumption.to_f
89
113
  end
90
- elsif tank.heaterFuelType =~ /Oil/i # Oil, FuelOil, FuelOil#2
91
- tank_info[:heater_fuel_type] = 'WaterOil'
92
- tank_info[:tank_mult] = get_HVAC_multiplier(tank_info[:heater_fuel_type], tank_info[:nominal_capacity])
93
- tank_info[:nominal_capacity] /= tank_info[:tank_mult]
94
- tank_info[:heater_volume_gal] /= tank_info[:tank_mult]
95
- if tank_info[:heater_thermal_efficiency] >= 0.85
96
- tank_info[:heater_fuel_type] = 'WaterOil_HE'
97
- tank_info[:eff_mult] = 1.3
98
- num_high_eff_oil_tanks += tank_info[:tank_mult]
114
+ csPump_info[:size] = csPumpSize.to_f # Watts
115
+ elsif supply_comp.to_PumpVariableSpeed.is_initialized
116
+ vsPump = supply_comp.to_PumpVariableSpeed.get
117
+ vsPump_info = {}
118
+ plant_loop_info[:shwpumps] << vsPump_info
119
+ vsPump_info[:name] = vsPump.name.get
120
+ if vsPump.isRatedPowerConsumptionAutosized.to_bool
121
+ vsPumpSize = vsPump.autosizedRatedPowerConsumption.to_f
99
122
  else
100
- num_reg_oil_tanks += tank_info[:tank_mult]
123
+ vsPumpSize = vsPump.ratedPowerConsumption.to_f
101
124
  end
125
+ vsPump_info[:size] = vsPumpSize.to_f # Watts
102
126
  end
103
- elsif supply_comp.to_PumpConstantSpeed.is_initialized
104
- csPump = supply_comp.to_PumpConstantSpeed.get
105
- csPump_info = {}
106
- plant_loop_info[:shwpumps] << csPump_info
107
- csPump_info[:name] = csPump.name.get
108
- if csPump.isRatedPowerConsumptionAutosized.to_bool
109
- csPumpSize = csPump.autosizedRatedPowerConsumption.to_f
110
- else
111
- csPumpSize = csPump.ratedPowerConsumption.to_f
112
- end
113
- csPump_info[:size] = csPumpSize.to_f # Watts
114
- elsif supply_comp.to_PumpVariableSpeed.is_initialized
115
- vsPump = supply_comp.to_PumpVariableSpeed.get
116
- vsPump_info = {}
117
- plant_loop_info[:shwpumps] << vsPump_info
118
- vsPump_info[:name] = vsPump.name.get
119
- if vsPump.isRatedPowerConsumptionAutosized.to_bool
120
- vsPumpSize = vsPump.autosizedRatedPowerConsumption.to_f
121
- else
122
- vsPumpSize = vsPump.ratedPowerConsumption.to_f
123
- end
124
- vsPump_info[:size] = vsPumpSize.to_f # Watts
125
127
  end
126
128
  end
127
- end
128
129
 
129
- # Get costs associated with each shw tank
130
- tankCost = 0.0 ; flueCost = 0.0 ; utilCost = 0.0 ; fuelFittingCost = 0.0; fuelLineCost = 0.0
131
- multiplier = 1.0 ; primaryFuel = ''; primaryCap = 0
132
-
133
- plant_loop_info[:shwtanks].each do |tank|
134
- # Get primary/secondary/backup tank cost based on fuel type and capacity for each tank
135
- #set to local variables.
136
- primaryFuel = tank[:heater_fuel_type]
137
- primaryCap = tank[:nominal_capacity].to_f
138
- heaterVolGal = tank[:heater_volume_gal].to_f
139
-
140
- #Get tank cost.
141
- if primaryFuel.include?("WaterGas")
142
- # For gas fired shw tanks we don't have to bother with volume. However, we have to accept a revised tank volume
143
- # which is there for electric and oil tanks even though we won't use it.
144
- shwTankCostInfo = getSHWTankCost(name: tank[:name], materialLookup: primaryFuel, materialSize: primaryCap, tankVol: nil)
145
- tank[:nominal_cacacity] = shwTankCostInfo[:Cap_kW]
146
- else
147
- # If the SHW tank is electric or oil need to find the cost for one with a large enough capacity and volume. If
148
- # no tanks have a large enough volume then get_SHWTankCost will find the tank with the largest volume and find
149
- # how many tanks of that size are needed (multiplier). Below, if this multiplier is larger than one then
150
- # the tank volume is adjusted to be the largest one that was found (by revVol) and the tank required capacity is
151
- # reduced by dividing by the multiplier.
152
- shwTankCostInfo = getSHWTankCost(name: tank[:name], materialLookup: primaryFuel, materialSize: primaryCap, tankVol: heaterVolGal)
153
- tank[:heater_volume_gal] = shwTankCostInfo[:Vol_USGal]
154
- tank[:nominal_capacity] = shwTankCostInfo[:Cap_kW]
155
- if shwTankCostInfo[:multiplier] > 1.0
156
- if primaryFuel.include?("WaterElec")
157
- num_elec_tanks -= tank[:tank_mult]
158
- tank[:tank_mult] *= shwTankCostInfo[:multiplier]
159
- num_elec_tanks += tank[:tank_mult]
160
- elsif primaryFuel.include?("HPHW_Heater")
161
- num_hphw_tanks -= tank[:tank_mult]
162
- tank[:tank_mult] *= shwTankCostInfo[:multiplier]
163
- num_hphw_tanks += tank[:tank_mult]
164
- else
165
- if tank[:heater_thermal_efficiency] >= 0.85
166
- num_high_eff_oil_tanks -= tank[:tank_mult]
130
+ # Get costs associated with each shw tank
131
+ tankCost = 0.0 ; flueCost = 0.0 ; utilCost = 0.0 ; fuelFittingCost = 0.0; fuelLineCost = 0.0
132
+ multiplier = 1.0 ; primaryFuel = ''; primaryCap = 0
133
+
134
+ plant_loop_info[:shwtanks].each do |tank|
135
+ # Get primary/secondary/backup tank cost based on fuel type and capacity for each tank
136
+ #set to local variables.
137
+ primaryFuel = tank[:heater_fuel_type]
138
+ primaryCap = tank[:nominal_capacity].to_f
139
+ heaterVolGal = tank[:heater_volume_gal].to_f
140
+
141
+ #Get tank cost.
142
+ if primaryFuel.include?("WaterGas")
143
+ # For gas fired shw tanks we don't have to bother with volume. However, we have to accept a revised tank volume
144
+ # which is there for electric and oil tanks even though we won't use it.
145
+ shwTankCostInfo = getSHWTankCost(name: tank[:name], materialLookup: primaryFuel, materialSize: primaryCap, tankVol: nil)
146
+ tank[:nominal_cacacity] = shwTankCostInfo[:Cap_kW]
147
+ else
148
+ # If the SHW tank is electric or oil need to find the cost for one with a large enough capacity and volume. If
149
+ # no tanks have a large enough volume then get_SHWTankCost will find the tank with the largest volume and find
150
+ # how many tanks of that size are needed (multiplier). Below, if this multiplier is larger than one then
151
+ # the tank volume is adjusted to be the largest one that was found (by revVol) and the tank required capacity is
152
+ # reduced by dividing by the multiplier.
153
+ shwTankCostInfo = getSHWTankCost(name: tank[:name], materialLookup: primaryFuel, materialSize: primaryCap, tankVol: heaterVolGal)
154
+ tank[:heater_volume_gal] = shwTankCostInfo[:Vol_USGal]
155
+ tank[:nominal_capacity] = shwTankCostInfo[:Cap_kW]
156
+ if shwTankCostInfo[:multiplier] > 1.0
157
+ if primaryFuel.include?("WaterElec")
158
+ num_elec_tanks -= tank[:tank_mult]
167
159
  tank[:tank_mult] *= shwTankCostInfo[:multiplier]
168
- num_high_eff_oil_tanks += tank[:tank_mult]
169
- else
170
- num_reg_oil_tanks -= tank[:tank_mult]
160
+ num_elec_tanks += tank[:tank_mult]
161
+ elsif primaryFuel.include?("HPHW_Heater")
162
+ num_hphw_tanks -= tank[:tank_mult]
171
163
  tank[:tank_mult] *= shwTankCostInfo[:multiplier]
172
- num_reg_oil_tanks += tank[:tank_mult]
164
+ num_hphw_tanks += tank[:tank_mult]
165
+ else
166
+ if tank[:heater_thermal_efficiency] >= 0.85
167
+ num_high_eff_oil_tanks -= tank[:tank_mult]
168
+ tank[:tank_mult] *= shwTankCostInfo[:multiplier]
169
+ num_high_eff_oil_tanks += tank[:tank_mult]
170
+ else
171
+ num_reg_oil_tanks -= tank[:tank_mult]
172
+ tank[:tank_mult] *= shwTankCostInfo[:multiplier]
173
+ num_reg_oil_tanks += tank[:tank_mult]
174
+ end
173
175
  end
174
176
  end
175
177
  end
176
- end
177
- matCost = shwTankCostInfo[:matCost]*tank[:tank_mult].to_f
178
- labCost = shwTankCostInfo[:labCost]*tank[:tank_mult].to_f
179
-
180
- thisTankCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
181
- tankCost += thisTankCost
182
-
183
- # Determine power venting costs for high efficiency tanks. Doing this here because tank multiplier and capacity
184
- # may have changed.
185
- if tank[:eff_mult] > 1.1
186
- if shwTankCostInfo[:Cap_kW] < 200
187
- # 1/8 hp power vent
188
- materialHash = materials_hvac.find {|data|
189
- data['Material'].to_s == 'Waterheater_power_vent' && data['Size'].to_s == '0.125'}
190
- matCost, labCost = getCost('1/8 hp power vent', materialHash, multiplier)
191
- flueCost += (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * tank[:tank_mult]
192
- else
193
- # 1/2 hp power vent
194
- materialHash = materials_hvac.find {|data|
195
- data['Material'].to_s == 'Waterheater_power_vent' && data['Size'].to_s == '0.5'}
196
- matCost, labCost = getCost('1/2 hp power vent', materialHash, multiplier)
197
- flueCost += (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * tank[:tank_mult]
178
+ matCost = shwTankCostInfo[:matCost]*tank[:tank_mult].to_f
179
+ labCost = shwTankCostInfo[:labCost]*tank[:tank_mult].to_f
180
+
181
+ thisTankCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
182
+ tankCost += thisTankCost
183
+
184
+ # Determine power venting costs for high efficiency tanks. Doing this here because tank multiplier and capacity
185
+ # may have changed.
186
+ if tank[:eff_mult] > 1.1
187
+ if shwTankCostInfo[:Cap_kW] < 200
188
+ # 1/8 hp power vent
189
+ materialHash = materials_hvac.find {|data|
190
+ data['Material'].to_s == 'Waterheater_power_vent' && data['Size'].to_s == '0.125'}
191
+ matCost, labCost = getCost('1/8 hp power vent', materialHash, multiplier)
192
+ flueCost += (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * tank[:tank_mult]
193
+ else
194
+ # 1/2 hp power vent
195
+ materialHash = materials_hvac.find {|data|
196
+ data['Material'].to_s == 'Waterheater_power_vent' && data['Size'].to_s == '0.5'}
197
+ matCost, labCost = getCost('1/2 hp power vent', materialHash, multiplier)
198
+ flueCost += (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * tank[:tank_mult]
199
+ end
198
200
  end
199
201
  end
200
- end
201
202
 
202
- numTanks = num_elec_tanks + num_hphw_tanks + num_reg_gas_tanks + num_high_eff_gas_tanks + num_reg_oil_tanks + num_high_eff_oil_tanks
203
- numFuelTanks = num_reg_gas_tanks + num_high_eff_gas_tanks + num_reg_oil_tanks + num_high_eff_oil_tanks
204
-
205
- if numTanks > 0
206
- # Electric utility cost components (i.e., power lines).
207
-
208
- # elec 600V #14 wire /100 ft (#848)
209
- materialHash = get_cost_info(mat: 'Wiring', size: 14)
210
- matCost, labCost = getCost('electrical wire - 600V #14', materialHash, multiplier)
211
- elecWireCost = matCost * regional_material_elec / 100.0 + labCost * regional_installation_elec / 100.0
212
-
213
- # 1 inch metal conduit (#851)
214
- materialHash = get_cost_info(mat: 'Conduit', unit: 'L.F.')
215
- matCost, labCost = getCost('1 inch metal conduit', materialHash, multiplier)
216
- metalConduitCost = matCost * regional_material_elec / 100.0 + labCost * regional_installation_elec / 100.0
217
-
218
- # Electric utility wire and conduit cost used by all tanks except HPHW
219
- utilCost += (metalConduitCost * util_dist + elecWireCost * util_dist / 100) * (numTanks - num_hphw_tanks)
220
-
221
- # Get costs condition on fuel types.
222
- if numFuelTanks> 0
223
- numRegFuelTanks = num_reg_gas_tanks + num_reg_oil_tanks
224
- numHighEffFuelTanks = num_high_eff_gas_tanks + num_high_eff_oil_tanks
225
-
226
- # Gas/Oil line piping cost per ft (#1)
227
- materialHash = get_cost_info(mat: 'GasLine', unit: 'L.F.')
228
- matCost, labCost = getCost('fuel line', materialHash, multiplier)
229
- fuelLineCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
230
-
231
- # Gas/Oil line fitting connection per tank (#2)
232
- materialHash = get_cost_info(mat: 'GasLine', unit: 'each')
233
- matCost, labCost = getCost('fuel line fitting connection', materialHash, multiplier)
234
- fuelFittingCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
235
-
236
- if numRegFuelTanks > 0
237
- # Flue and utility component costs (for gas and oil tanks only)
238
- # Calculate flue costs once for all tanks since flues combined by header when multiple tanks
239
- # 6 inch diameter flue (#384)
240
- materialHash = get_cost_info(mat: 'Venting', size: 6)
241
- matCost, labCost = getCost('flue', materialHash, multiplier)
242
- flueVentCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
243
-
244
- #6 inch elbow fitting (#386)
245
- materialHash = get_cost_info(mat: 'VentingElbow', size: 6)
246
- matCost, labCost = getCost('flue elbow', materialHash, multiplier)
247
- flueElbowCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
248
-
249
- # 6 inch top (#392)
250
- materialHash = get_cost_info(mat: 'VentingTop', size: 6)
251
- matCost, labCost = getCost('flue top', materialHash, multiplier)
252
- flueTopCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
253
-
254
- # Adding one regular flue if any regular efficiency shw tanks are present
255
- flueCost += flueVentCost * ht_roof + flueElbowCost + flueTopCost
256
-
257
- # Header cost only non-zero if there is a secondary/backup gas/oil tank
258
- if numRegFuelTanks > 1
259
- # Check if need a flue header (i.e., there are both primary and secondary/backup tanks)
260
- # 6 inch diameter header (#384)
203
+ numTanks = num_elec_tanks + num_hphw_tanks + num_reg_gas_tanks + num_high_eff_gas_tanks + num_reg_oil_tanks + num_high_eff_oil_tanks
204
+ numFuelTanks = num_reg_gas_tanks + num_high_eff_gas_tanks + num_reg_oil_tanks + num_high_eff_oil_tanks
205
+
206
+ if numTanks > 0
207
+ # Electric utility cost components (i.e., power lines).
208
+
209
+ # elec 600V #14 wire /100 ft (#848)
210
+ materialHash = get_cost_info(mat: 'Wiring', size: 14)
211
+ matCost, labCost = getCost('electrical wire - 600V #14', materialHash, multiplier)
212
+ elecWireCost = matCost * regional_material_elec / 100.0 + labCost * regional_installation_elec / 100.0
213
+
214
+ # 1 inch metal conduit (#851)
215
+ materialHash = get_cost_info(mat: 'Conduit', unit: 'L.F.')
216
+ matCost, labCost = getCost('1 inch metal conduit', materialHash, multiplier)
217
+ metalConduitCost = matCost * regional_material_elec / 100.0 + labCost * regional_installation_elec / 100.0
218
+
219
+ # Electric utility wire and conduit cost used by all tanks except HPHW
220
+ utilCost += (metalConduitCost * util_dist + elecWireCost * util_dist / 100) * (numTanks - num_hphw_tanks)
221
+
222
+ # Get costs condition on fuel types.
223
+ if numFuelTanks> 0
224
+ numRegFuelTanks = num_reg_gas_tanks + num_reg_oil_tanks
225
+ numHighEffFuelTanks = num_high_eff_gas_tanks + num_high_eff_oil_tanks
226
+
227
+ # Gas/Oil line piping cost per ft (#1)
228
+ materialHash = get_cost_info(mat: 'GasLine', unit: 'L.F.')
229
+ matCost, labCost = getCost('fuel line', materialHash, multiplier)
230
+ fuelLineCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
231
+
232
+ # Gas/Oil line fitting connection per tank (#2)
233
+ materialHash = get_cost_info(mat: 'GasLine', unit: 'each')
234
+ matCost, labCost = getCost('fuel line fitting connection', materialHash, multiplier)
235
+ fuelFittingCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
236
+
237
+ if numRegFuelTanks > 0
238
+ # Flue and utility component costs (for gas and oil tanks only)
239
+ # Calculate flue costs once for all tanks since flues combined by header when multiple tanks
240
+ # 6 inch diameter flue (#384)
261
241
  materialHash = get_cost_info(mat: 'Venting', size: 6)
262
- matCost, labCost = getCost('flue header', materialHash, multiplier)
263
- headerVentCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
242
+ matCost, labCost = getCost('flue', materialHash, multiplier)
243
+ flueVentCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
264
244
 
265
- #6 inch elbow fitting for header (#386)
245
+ #6 inch elbow fitting (#386)
266
246
  materialHash = get_cost_info(mat: 'VentingElbow', size: 6)
267
- matCost, labCost = getCost('flue header elbow', materialHash, multiplier)
268
- headerElbowCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
269
-
270
- # Adding a regular tank header for every additional regular efficiency SHW tank present
271
- # Assume a header length of 20 ft and an elbow fitting for each tank connected to the header
272
- flueCost += (headerVentCost * 20 + headerElbowCost) * (numRegFuelTanks - 1)
247
+ matCost, labCost = getCost('flue elbow', materialHash, multiplier)
248
+ flueElbowCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
249
+
250
+ # 6 inch top (#392)
251
+ materialHash = get_cost_info(mat: 'VentingTop', size: 6)
252
+ matCost, labCost = getCost('flue top', materialHash, multiplier)
253
+ flueTopCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
254
+
255
+ # Adding one regular flue if any regular efficiency shw tanks are present
256
+ flueCost += flueVentCost * ht_roof + flueElbowCost + flueTopCost
257
+
258
+ # Header cost only non-zero if there is a secondary/backup gas/oil tank
259
+ if numRegFuelTanks > 1
260
+ # Check if need a flue header (i.e., there are both primary and secondary/backup tanks)
261
+ # 6 inch diameter header (#384)
262
+ materialHash = get_cost_info(mat: 'Venting', size: 6)
263
+ matCost, labCost = getCost('flue header', materialHash, multiplier)
264
+ headerVentCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
265
+
266
+ #6 inch elbow fitting for header (#386)
267
+ materialHash = get_cost_info(mat: 'VentingElbow', size: 6)
268
+ matCost, labCost = getCost('flue header elbow', materialHash, multiplier)
269
+ headerElbowCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
270
+
271
+ # Adding a regular tank header for every additional regular efficiency SHW tank present
272
+ # Assume a header length of 20 ft and an elbow fitting for each tank connected to the header
273
+ flueCost += (headerVentCost * 20 + headerElbowCost) * (numRegFuelTanks - 1)
274
+ end
273
275
  end
274
- end
275
276
 
276
- # If high efficiency fuel fired shw tanks are present add flues (1 per tank)
277
- if numHighEffFuelTanks > 0
278
- #6 inch PVC pipe (#1327)
279
- materialHash = get_cost_info(mat: 'Vent_pvc', size: 6)
280
- matCost, labCost = getCost('flue', materialHash, multiplier)
281
- pvcFluePipe = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0)
282
-
283
- #6 inch PVC Coupling (#1319)
284
- materialHash = get_cost_info(mat: 'Vent_pvc_coupling', size: 6)
285
- matCost, labCost = getCost('flue elbow', materialHash, multiplier)
286
- pvcFlueCoupling = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
287
-
288
- # 6 inch PVC elbow (#1329)
289
- materialHash = get_cost_info(mat: 'Vent_pvc_elbow', size: 6)
290
- matCost, labCost = getCost('flue top', materialHash, multiplier)
291
- pvcFlueElbow = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
292
-
293
- # Adding PVC flue costs for all high efficiency fuel fired SHW tanks
294
- flueCost += (pvcFluePipe * 20.0 + pvcFlueCoupling + pvcFlueElbow) * numHighEffFuelTanks
295
- end
277
+ # If high efficiency fuel fired shw tanks are present add flues (1 per tank)
278
+ if numHighEffFuelTanks > 0
279
+ #6 inch PVC pipe (#1327)
280
+ materialHash = get_cost_info(mat: 'Vent_pvc', size: 6)
281
+ matCost, labCost = getCost('flue', materialHash, multiplier)
282
+ pvcFluePipe = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0)
283
+
284
+ #6 inch PVC Coupling (#1319)
285
+ materialHash = get_cost_info(mat: 'Vent_pvc_coupling', size: 6)
286
+ matCost, labCost = getCost('flue elbow', materialHash, multiplier)
287
+ pvcFlueCoupling = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
288
+
289
+ # 6 inch PVC elbow (#1329)
290
+ materialHash = get_cost_info(mat: 'Vent_pvc_elbow', size: 6)
291
+ matCost, labCost = getCost('flue top', materialHash, multiplier)
292
+ pvcFlueElbow = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
293
+
294
+ # Adding PVC flue costs for all high efficiency fuel fired SHW tanks
295
+ flueCost += (pvcFluePipe * 20.0 + pvcFlueCoupling + pvcFlueElbow) * numHighEffFuelTanks
296
+ end
296
297
 
297
- # If natural gas tanks are present include fuel line and connectors
298
- if (num_reg_gas_tanks + num_reg_gas_tanks) > 0
299
- # Gas tanks require fuel line+valves+connectors
300
- utilCost += (fuelLineCost * util_dist + fuelFittingCost) * (num_reg_gas_tanks + num_high_eff_gas_tanks)
298
+ # If natural gas tanks are present include fuel line and connectors
299
+ if (num_reg_gas_tanks + num_high_eff_gas_tanks) > 0
300
+ # Gas tanks require fuel line+valves+connectors
301
+ utilCost += (fuelLineCost * util_dist + fuelFittingCost) * (num_reg_gas_tanks + num_high_eff_gas_tanks)
301
302
 
302
- elsif (num_reg_oil_tanks + num_high_eff_oil_tanks) > 0
303
- # Oil tanks require fuel line+valves+connectors and electrical conduit
303
+ elsif (num_reg_oil_tanks + num_high_eff_oil_tanks) > 0
304
+ # Oil tanks require fuel line+valves+connectors and electrical conduit
304
305
 
305
- # Oil filtering system (#4)
306
- materialHash = get_cost_info(mat: 'OilLine', unit: 'each')
307
- matCost, labCost = getCost('Oil filtering system', materialHash, multiplier)
308
- oilFilterCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
306
+ # Oil filtering system (#4)
307
+ materialHash = get_cost_info(mat: 'OilLine', unit: 'each')
308
+ matCost, labCost = getCost('Oil filtering system', materialHash, multiplier)
309
+ oilFilterCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
309
310
 
310
- # 2000 USG above ground tank (#5)
311
- materialHash = get_cost_info(mat: 'OilTanks', size: 2000)
312
- matCost, labCost = getCost('Oil tank (2000 USG)', materialHash, multiplier)
313
- oilTankCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
311
+ # 2000 USG above ground tank (#5)
312
+ materialHash = get_cost_info(mat: 'OilTanks', size: 2000)
313
+ matCost, labCost = getCost('Oil tank (2000 USG)', materialHash, multiplier)
314
+ oilTankCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
314
315
 
315
- utilCost += (fuelLineCost * util_dist + fuelFittingCost) * (num_reg_oil_tanks + num_high_eff_oil_tanks) + oilFilterCost + oilTankCost
316
+ utilCost += (fuelLineCost * util_dist + fuelFittingCost) * (num_reg_oil_tanks + num_high_eff_oil_tanks) + oilFilterCost + oilTankCost
317
+ end
316
318
  end
317
319
  end
318
- end
319
320
 
320
- # Tank pump costs
321
- pumpCost = 0.0; pipingCost = 0.0; numPumps = 0; pumpName = ''; pumpSize = 0.0
322
- plant_loop_info[:shwpumps].each do |pump|
323
- numPumps += 1
324
- # Cost variable and constant volume pumps the same (the difference is in extra cost for VFD controller)
325
- pumpSize = pump[:size]; pumpName = pump[:name]
326
- matCost, labCost = getHVACCost(pumpName, 'Pumps', pumpSize, false)
327
- pumpCost += matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
328
- if pump[:name] =~ /variable/i
329
- # Cost the VFD controller for the variable pump costed above
321
+ # Tank pump costs
322
+ pumpCost = 0.0; pipingCost = 0.0; numPumps = 0; pumpName = ''; pumpSize = 0.0
323
+ plant_loop_info[:shwpumps].each do |pump|
324
+ numPumps += 1
325
+ # Cost variable and constant volume pumps the same (the difference is in extra cost for VFD controller)
330
326
  pumpSize = pump[:size]; pumpName = pump[:name]
331
- matCost, labCost = getHVACCost(pumpName, 'VFD', pumpSize, false)
332
- pumpCost += matCost * regional_material_elec / 100.0 + labCost * regional_installation_elec / 100.0
327
+ matCost, labCost = getHVACCost(pumpName, 'Pumps', pumpSize, false)
328
+ pumpCost += matCost * regional_material / 100.0 + labCost * regional_installation / 100.0
329
+ if pump[:name] =~ /variable/i
330
+ # Cost the VFD controller for the variable pump costed above
331
+ pumpSize = pump[:size]; pumpName = pump[:name]
332
+ matCost, labCost = getHVACCost(pumpName, 'VFD', pumpSize, false)
333
+ pumpCost += matCost * regional_material_elec / 100.0 + labCost * regional_installation_elec / 100.0
334
+ end
335
+ end
336
+ #if numTanks > 1 && numPumps < 2
337
+ # Add pump costing for the backup tank pump.
338
+ # 2024-04-25: No longer including redundant costs.
339
+ #pumpCost *= 2.0
340
+ #numPumps = 2 # reset the number of pumps for piping costs below
341
+ #end
342
+ # Double the pump costs to accomodate the costing of a backup pumps for each tank!
343
+ # 2024-04-25: No longer including redundant casts.
344
+ # pumpCost *= 2.0
345
+
346
+ # Tank water piping cost: Add piping elbows, valves and insulation from the tank(s)
347
+ # to the pumps(s) assuming a pipe diameter of 1” and a distance of 10 ft per pump
348
+ if numTanks > 0
349
+ # 1 inch Steel pipe
350
+ matCost, labCost = getHVACCost('1 inch steel pipe', 'SteelPipe', 1)
351
+ pipingCost += 10.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0)
352
+
353
+ # 1 inch Steel pipe insulation
354
+ matCost, labCost = getHVACCost('1 inch pipe insulation', 'PipeInsulation', 1)
355
+ pipingCost += 10.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0)
356
+
357
+ # 1 inch Steel pipe elbow
358
+ matCost, labCost = getHVACCost('1 inch steel pipe elbow', 'SteelPipeElbow', 1)
359
+ pipingCost += 2.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0)
360
+
361
+ # 1 inch gate valves
362
+ matCost, labCost = getHVACCost('1 inch gate valves', 'ValvesGate', 1)
363
+ pipingCost += 1.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0)
333
364
  end
334
- end
335
- #if numTanks > 1 && numPumps < 2
336
- # Add pump costing for the backup tank pump.
337
- # 2024-04-25: No longer including redundant costs.
338
- #pumpCost *= 2.0
339
- #numPumps = 2 # reset the number of pumps for piping costs below
340
- #end
341
- # Double the pump costs to accomodate the costing of a backup pumps for each tank!
342
- # 2024-04-25: No longer including redundant casts.
343
- # pumpCost *= 2.0
344
-
345
- # Tank water piping cost: Add piping elbows, valves and insulation from the tank(s)
346
- # to the pumps(s) assuming a pipe diameter of 1” and a distance of 10 ft per pump
347
- if numTanks > 0
348
- # 1 inch Steel pipe
349
- matCost, labCost = getHVACCost('1 inch steel pipe', 'SteelPipe', 1)
350
- pipingCost += 10.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0)
351
-
352
- # 1 inch Steel pipe insulation
353
- matCost, labCost = getHVACCost('1 inch pipe insulation', 'PipeInsulation', 1)
354
- pipingCost += 10.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0)
355
-
356
- # 1 inch Steel pipe elbow
357
- matCost, labCost = getHVACCost('1 inch steel pipe elbow', 'SteelPipeElbow', 1)
358
- pipingCost += 2.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0)
359
-
360
- # 1 inch gate valves
361
- matCost, labCost = getHVACCost('1 inch gate valves', 'ValvesGate', 1)
362
- pipingCost += 1.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0)
363
- end
364
365
 
365
- # 2023-04-25: Removing costing for redundant equipment and piping.
366
- #if numTanks > 1
367
- # Double pump piping cost to account for second tank
368
- # pipingCost *= 2
369
- #end
370
-
371
- # ckirney, 2019-04-12: shw_distribution_costing mostly completed however priorities have changed for now so
372
- # completion and testing will be delayed. Adding code to master for now but it will not be called until it is
373
- # ready.
374
- # distCost = shw_distribution_costing(model: model, prototype_creator: prototype_creator)
375
-
376
- totalCost = tankCost + flueCost + utilCost + pumpCost + pipingCost
377
-
378
- @costing_report['shw'] = {
379
- 'shw_nom_flr2flr_hght_ft' => nominal_flr2flr_height.round(1),
380
- 'shw_ht_roof' => ht_roof.round(1),
381
- 'shw_longest_distance_to_ext_ft' => horizontal_dist.round(1),
382
- 'shw_utility_distance_ft' => util_dist.round(1),
383
- 'shw_tanks' => tankCost.round(2),
384
- 'shw_num_of_modeled_tanks' => plant_loop_info[:shwtanks].size,
385
- 'num_elec_tanks' => num_elec_tanks,
386
- 'num_hphw_tanks' => num_hphw_tanks,
387
- 'shw_num_reg_eff_gas_tanks' => num_reg_gas_tanks,
388
- 'shw_num_high_eff_gas_tanks' => num_high_eff_gas_tanks,
389
- 'shw_num_reg_eff_oil_tanks' => num_reg_oil_tanks,
390
- 'shw_num_high_eff_oil_tanks' => num_high_eff_oil_tanks,
391
- 'shw_num_of_costed_tanks' => numTanks,
392
- 'shw_flues' => flueCost.round(2),
393
- 'shw_utilties' => utilCost.round(2),
394
- 'shw_pumps' => pumpCost.round(2),
395
- 'shw_num_of_pumps' => plant_loop_info[:shwpumps].size,
396
- 'shw_piping' => pipingCost.round(2),
397
- 'shw_total' => totalCost.round(2)
398
- }
399
- puts "\nHVAC SHW costing data successfully generated. Total shw costs: $#{totalCost.round(2)}"
400
-
401
- return totalCost
402
- end
366
+ # 2023-04-25: Removing costing for redundant equipment and piping.
367
+ #if numTanks > 1
368
+ # Double pump piping cost to account for second tank
369
+ # pipingCost *= 2
370
+ #end
371
+
372
+ # ckirney, 2019-04-12: shw_distribution_costing mostly completed however priorities have changed for now so
373
+ # completion and testing will be delayed. Adding code to master for now but it will not be called until it is
374
+ # ready.
375
+ # distCost = shw_distribution_costing(model: model, prototype_creator: prototype_creator)
376
+
377
+ totalCost = tankCost + flueCost + utilCost + pumpCost + pipingCost
378
+
379
+ @costing_report['shw'] = {
380
+ 'shw_nom_flr2flr_hght_ft' => nominal_flr2flr_height.round(1),
381
+ 'shw_ht_roof' => ht_roof.round(1),
382
+ 'shw_longest_distance_to_ext_ft' => horizontal_dist.round(1),
383
+ 'shw_utility_distance_ft' => util_dist.round(1),
384
+ 'shw_tanks' => tankCost.round(2),
385
+ 'shw_num_of_modeled_tanks' => plant_loop_info[:shwtanks].size,
386
+ 'num_elec_tanks' => num_elec_tanks,
387
+ 'num_hphw_tanks' => num_hphw_tanks,
388
+ 'shw_num_reg_eff_gas_tanks' => num_reg_gas_tanks,
389
+ 'shw_num_high_eff_gas_tanks' => num_high_eff_gas_tanks,
390
+ 'shw_num_reg_eff_oil_tanks' => num_reg_oil_tanks,
391
+ 'shw_num_high_eff_oil_tanks' => num_high_eff_oil_tanks,
392
+ 'shw_num_of_costed_tanks' => numTanks,
393
+ 'shw_flues' => flueCost.round(2),
394
+ 'shw_utilties' => utilCost.round(2),
395
+ 'shw_pumps' => pumpCost.round(2),
396
+ 'shw_num_of_pumps' => plant_loop_info[:shwpumps].size,
397
+ 'shw_piping' => pipingCost.round(2),
398
+ 'shw_total' => totalCost.round(2)
399
+ }
400
+ puts "\nHVAC SHW costing data successfully generated. Total shw costs: $#{totalCost.round(2)}"
403
401
 
404
- def shw_distribution_costing(model:, prototype_creator:)
405
- total_shw_dist_cost = 0
406
- roof_cent = prototype_creator.find_highest_roof_centre(model)
407
- mech_room, cond_spaces = prototype_creator.find_mech_room(model)
408
- min_space = get_lowest_space(spaces: cond_spaces)
409
- mech_sizing_info = read_mech_sizing()
410
- shw_sp_types = get_mech_table(mech_size_info: mech_sizing_info, table_name: 'shw_space_types')
411
- excl_sp_types = get_mech_table(mech_size_info: mech_sizing_info, table_name: 'exclusive_shw_space_types')
412
- shw_main_cost = cost_shw_main(mech_room: mech_room, roof_cent: roof_cent, min_space: min_space)
413
- total_shw_dist_cost += shw_main_cost[:cost]
414
- #determine if space is wet: prototype_creator.is_an_necb_wet_space?(space)
415
- #Sort spaces by floor and conditioned spaces
416
- space_mod = OpenstudioStandards::Space
417
- model.getBuildingStorys.sort.each do |build_story|
418
- public_wash = false
419
- other_public_wash = false
420
- build_story.spaces.sort.each do |space|
421
- next unless (space_mod.space_heated?(space) || space_mod.space_cooled?(space)) && !space_mod.space_plenum?(space)
422
- sp_type_name = space.spaceType.get.nameString
423
- shw_neccesary = shw_sp_types.select {|table_sp_type|
424
- !/#{table_sp_type.upcase}/.match(sp_type_name.upcase).nil?
425
- }
426
- if shw_neccesary.empty?
427
- public_wash = true
428
- else
429
- shw_dist_cost = get_shw_dist_cost(space: space, roof_cent: roof_cent)
430
- total_shw_dist_cost += shw_dist_cost[:cost]
431
- public_shw = excl_sp_types.select {|ex_table_sp_type|
432
- !/#{ex_table_sp_type.upcase}/.match(sp_type_name.upcase).nil?
402
+ return totalCost
403
+ end
404
+
405
+ def shw_distribution_costing(model:, prototype_creator:)
406
+ total_shw_dist_cost = 0
407
+ roof_cent = prototype_creator.find_highest_roof_centre(model)
408
+ mech_room, cond_spaces = prototype_creator.find_mech_room(model)
409
+ min_space = get_lowest_space(spaces: cond_spaces)
410
+ mech_sizing_info = read_mech_sizing()
411
+ shw_sp_types = get_mech_table(mech_size_info: mech_sizing_info, table_name: 'shw_space_types')
412
+ excl_sp_types = get_mech_table(mech_size_info: mech_sizing_info, table_name: 'exclusive_shw_space_types')
413
+ shw_main_cost = cost_shw_main(mech_room: mech_room, roof_cent: roof_cent, min_space: min_space)
414
+ total_shw_dist_cost += shw_main_cost[:cost]
415
+ #determine if space is wet: prototype_creator.is_an_necb_wet_space?(space)
416
+ #Sort spaces by floor and conditioned spaces
417
+ space_mod = OpenstudioStandards::Space
418
+ model.getBuildingStorys.sort.each do |build_story|
419
+ public_wash = false
420
+ other_public_wash = false
421
+ build_story.spaces.sort.each do |space|
422
+ next unless (space_mod.space_heated?(space) || space_mod.space_cooled?(space)) && !space_mod.space_plenum?(space)
423
+ sp_type_name = space.spaceType.get.nameString
424
+ shw_neccesary = shw_sp_types.select {|table_sp_type|
425
+ !/#{table_sp_type.upcase}/.match(sp_type_name.upcase).nil?
433
426
  }
434
- other_public_wash = true
427
+ if shw_neccesary.empty?
428
+ public_wash = true
429
+ else
430
+ shw_dist_cost = get_shw_dist_cost(space: space, roof_cent: roof_cent)
431
+ total_shw_dist_cost += shw_dist_cost[:cost]
432
+ public_shw = excl_sp_types.select {|ex_table_sp_type|
433
+ !/#{ex_table_sp_type.upcase}/.match(sp_type_name.upcase).nil?
434
+ }
435
+ other_public_wash = true
436
+ end
437
+ end
438
+ if public_wash == true && other_public_wash == false
439
+ #Cost two shw piping to two washrooms in the center of the story. Assume each has 20 feet of supply and return
440
+ #shw piping to the story center (10 feet supply, 10 feet return).
441
+ dist_ft = 40
442
+ shw_dist_search = []
443
+ shw_dist_search << {
444
+ mat: 'CopperPipe',
445
+ unit: 'L.F.',
446
+ size: 0.75,
447
+ mult: dist_ft
448
+ }
449
+ washroom_shw_cost = get_comp_cost(cost_info: shw_dist_search)
450
+ total_shw_dist_cost += washroom_shw_cost
435
451
  end
436
452
  end
437
- if public_wash == true && other_public_wash == false
438
- #Cost two shw piping to two washrooms in the center of the story. Assume each has 20 feet of supply and return
439
- #shw piping to the story center (10 feet supply, 10 feet return).
440
- dist_ft = 40
441
- shw_dist_search = []
442
- shw_dist_search << {
443
- mat: 'CopperPipe',
444
- unit: 'L.F.',
445
- size: 0.75,
446
- mult: dist_ft
447
- }
448
- washroom_shw_cost = get_comp_cost(cost_info: shw_dist_search)
449
- total_shw_dist_cost += washroom_shw_cost
450
- end
453
+ return total_shw_dist_cost
451
454
  end
452
- return total_shw_dist_cost
453
- end
454
455
 
455
- def get_space_floor_centroid(space:)
456
- # Determine the bottom surface of the space and calculate it's centroid.
457
- # Get the coordinates of the origin for the space (the coordinates of points in the space are relative to this).
458
- xOrigin = space.xOrigin
459
- yOrigin = space.yOrigin
460
- zOrigin = space.zOrigin
461
- # Get the surfaces for the space.
462
- space_surfaces = space.surfaces
463
- # Find the floor (aka the surface with the lowest centroid).
464
- min_surf = space_surfaces.min_by{|sp_surface| (sp_surface.centroid.z.to_f)}
465
- # The following is added to determine the overall floor centroid because some spaces have floors composed of more than one surface.
466
- floor_centroid = [0, 0, 0]
467
- space_surfaces.each do |sp_surface|
468
- if min_surf.centroid.z.to_f.round(8) == sp_surface.centroid.z.to_f.round(8)
469
- floor_centroid[0] = floor_centroid[0] + sp_surface.centroid.x.to_f*sp_surface.grossArea.to_f
470
- floor_centroid[1] = floor_centroid[1] + sp_surface.centroid.y.to_f*sp_surface.grossArea.to_f
471
- floor_centroid[2] = floor_centroid[2] + sp_surface.grossArea
456
+ def get_space_floor_centroid(space:)
457
+ # Determine the bottom surface of the space and calculate it's centroid.
458
+ # Get the coordinates of the origin for the space (the coordinates of points in the space are relative to this).
459
+ xOrigin = space.xOrigin
460
+ yOrigin = space.yOrigin
461
+ zOrigin = space.zOrigin
462
+ # Get the surfaces for the space.
463
+ space_surfaces = space.surfaces
464
+ # Find the floor (aka the surface with the lowest centroid).
465
+ min_surf = space_surfaces.min_by{|sp_surface| (sp_surface.centroid.z.to_f)}
466
+ # The following is added to determine the overall floor centroid because some spaces have floors composed of more than one surface.
467
+ floor_centroid = [0, 0, 0]
468
+ space_surfaces.each do |sp_surface|
469
+ if min_surf.centroid.z.to_f.round(8) == sp_surface.centroid.z.to_f.round(8)
470
+ floor_centroid[0] = floor_centroid[0] + sp_surface.centroid.x.to_f*sp_surface.grossArea.to_f
471
+ floor_centroid[1] = floor_centroid[1] + sp_surface.centroid.y.to_f*sp_surface.grossArea.to_f
472
+ floor_centroid[2] = floor_centroid[2] + sp_surface.grossArea
473
+ end
472
474
  end
473
- end
474
-
475
- # Determine the floor centroid
476
- floor_centroid[0] = floor_centroid[0]/floor_centroid[2]
477
- floor_centroid[1] = floor_centroid[1]/floor_centroid[2]
478
475
 
479
- return {
480
- centroid: [floor_centroid[0] + xOrigin, floor_centroid[1] + yOrigin, min_surf.centroid.z.to_f + zOrigin],
481
- floor_area_m2: floor_centroid[2]
482
- }
483
- end
476
+ # Determine the floor centroid
477
+ floor_centroid[0] = floor_centroid[0]/floor_centroid[2]
478
+ floor_centroid[1] = floor_centroid[1]/floor_centroid[2]
484
479
 
485
- def get_shw_dist_cost(space:, roof_cent:)
486
- shw_dist_search = []
487
- space_cent = get_space_floor_centroid(space: space)
488
- dist_m = (roof_cent[:roof_centroid][0] - space_cent[:centroid][0]).abs + (roof_cent[:roof_centroid][1] - space_cent[:centroid][1]).abs
489
- dist_ft = OpenStudio.convert(dist_m, 'm', 'ft').get
490
- shw_dist_search << {
491
- mat: 'CopperPipe',
492
- unit: 'L.F.',
493
- size: 0.75,
494
- mult: dist_ft
495
- }
496
- total_comp_cost = get_comp_cost(cost_info: shw_dist_search)
497
- return {
498
- length_m: dist_m,
499
- cost: total_comp_cost
500
- }
501
- end
480
+ return {
481
+ centroid: [floor_centroid[0] + xOrigin, floor_centroid[1] + yOrigin, min_surf.centroid.z.to_f + zOrigin],
482
+ floor_area_m2: floor_centroid[2]
483
+ }
484
+ end
502
485
 
503
- def cost_shw_main(mech_room:, roof_cent:, min_space:)
504
- shw_dist_search = []
505
- building_height_m = (roof_cent[:roof_centroid][2] - min_space[:roof_cent][2]).abs
506
- mech_to_cent_dist_m = (roof_cent[:roof_centroid][0] - mech_room['space_centroid'][0]).abs + (roof_cent[:roof_centroid][1] - mech_room['space_centroid'][1]).abs
507
- #Twice the distance to account for supply and return shw piping.
508
- total_dist_m = 2*(building_height_m + mech_to_cent_dist_m)
509
- total_dist_ft = OpenStudio.convert(total_dist_m, 'm', 'ft').get
510
- shw_dist_search << {
511
- mat: 'CopperPipe',
512
- unit: 'L.F.',
513
- size: 0.75,
514
- mult: total_dist_ft
515
- }
516
- total_comp_cost = get_comp_cost(cost_info: shw_dist_search)
517
- return {
518
- length_m: total_dist_m,
519
- cost: total_comp_cost
520
- }
521
- end
486
+ def get_shw_dist_cost(space:, roof_cent:)
487
+ shw_dist_search = []
488
+ space_cent = get_space_floor_centroid(space: space)
489
+ dist_m = (roof_cent[:roof_centroid][0] - space_cent[:centroid][0]).abs + (roof_cent[:roof_centroid][1] - space_cent[:centroid][1]).abs
490
+ dist_ft = OpenStudio.convert(dist_m, 'm', 'ft').get
491
+ shw_dist_search << {
492
+ mat: 'CopperPipe',
493
+ unit: 'L.F.',
494
+ size: 0.75,
495
+ mult: dist_ft
496
+ }
497
+ total_comp_cost = get_comp_cost(cost_info: shw_dist_search)
498
+ return {
499
+ length_m: dist_m,
500
+ cost: total_comp_cost
501
+ }
502
+ end
522
503
 
523
- # Getting cost for SHW Tanks. This method is different from the getHVACCost method used everywhere else in that it
524
- # accepts a tank volume argument in addition to the tank capacity (materialSize in this case). This additional
525
- # argument means that the method must search for a SHW tank heated with the right fuel that has a large enough
526
- # capacity and volume.
527
- #
528
- # IMPORTANT: This method assumes that when SHW tanks are retrieved from the model their capacity is checked against
529
- # the capacities of costed tanks. If the modeled capacity is too large then it is costed as though multiple smaller
530
- # tanks are present. Thus, this method assumes that anything passed to it will be small enough to be costed. This is
531
- # another difference from the getHVACCost method which includes a call to get_HVAC_multiplier that checks if a costed
532
- # item is too big and should be replaced by several smaller items.
533
- #
534
- # Note that the multiplier is always set to 1.0 when claculating the cost. That is because the multiplier is applied
535
- # to the cost in the main shw_costing method.
536
- def getSHWTankCost(name:, materialLookup:, materialSize:, tankVol:)
537
- multiplier = 1.0
538
- materials_hvac = @costing_database['raw']['materials_hvac']
539
- # Get costing spreadsheet data for gas and oil fired mixed shw tanks
540
- if tankVol.nil?
541
- # If no tank volume is provided then only look at capacity.
542
- # Get all capacities hor that type of tank.
543
- hvac_materials = materials_hvac.select {|data|
544
- data['Material'].to_s == materialLookup.to_s && data['Size'].to_f >= materialSize.to_f
504
+ def cost_shw_main(mech_room:, roof_cent:, min_space:)
505
+ shw_dist_search = []
506
+ building_height_m = (roof_cent[:roof_centroid][2] - min_space[:roof_cent][2]).abs
507
+ mech_to_cent_dist_m = (roof_cent[:roof_centroid][0] - mech_room['space_centroid'][0]).abs + (roof_cent[:roof_centroid][1] - mech_room['space_centroid'][1]).abs
508
+ #Twice the distance to account for supply and return shw piping.
509
+ total_dist_m = 2*(building_height_m + mech_to_cent_dist_m)
510
+ total_dist_ft = OpenStudio.convert(total_dist_m, 'm', 'ft').get
511
+ shw_dist_search << {
512
+ mat: 'CopperPipe',
513
+ unit: 'L.F.',
514
+ size: 0.75,
515
+ mult: total_dist_ft
545
516
  }
546
- if hvac_materials.empty?
547
- # If no tanks have a big enough capacity then something is amiss and return an error (this should never happen
548
- # because tanks capacity should be checked before this method is called).
549
- puts "HVAC material error! Could not find next largest size for #{name} in #{materials_hvac}"
550
- raise
551
- elsif hvac_materials.size == 1
552
- # Only one tank has an appropriate capacity find it's cost and return it.
553
- matCost, labCost = getCost(name, hvac_materials[0], 1.0)
554
- ret_hash = {
555
- matCost: matCost,
556
- labCost: labCost,
557
- multiplier: multiplier,
558
- Vol_USGal: tankVol,
559
- Cap_kW: hvac_materials[0]['Size'].to_f
517
+ total_comp_cost = get_comp_cost(cost_info: shw_dist_search)
518
+ return {
519
+ length_m: total_dist_m,
520
+ cost: total_comp_cost
521
+ }
522
+ end
560
523
 
524
+ # Getting cost for SHW Tanks. This method is different from the getHVACCost method used everywhere else in that it
525
+ # accepts a tank volume argument in addition to the tank capacity (materialSize in this case). This additional
526
+ # argument means that the method must search for a SHW tank heated with the right fuel that has a large enough
527
+ # capacity and volume.
528
+ #
529
+ # IMPORTANT: This method assumes that when SHW tanks are retrieved from the model their capacity is checked against
530
+ # the capacities of costed tanks. If the modeled capacity is too large then it is costed as though multiple smaller
531
+ # tanks are present. Thus, this method assumes that anything passed to it will be small enough to be costed. This is
532
+ # another difference from the getHVACCost method which includes a call to get_HVAC_multiplier that checks if a costed
533
+ # item is too big and should be replaced by several smaller items.
534
+ #
535
+ # Note that the multiplier is always set to 1.0 when claculating the cost. That is because the multiplier is applied
536
+ # to the cost in the main shw_costing method.
537
+ def getSHWTankCost(name:, materialLookup:, materialSize:, tankVol:)
538
+ multiplier = 1.0
539
+ materials_hvac = @costing_database['raw']['materials_hvac']
540
+ # Get costing spreadsheet data for gas and oil fired mixed shw tanks
541
+ if tankVol.nil?
542
+ # If no tank volume is provided then only look at capacity.
543
+ # Get all capacities hor that type of tank.
544
+ hvac_materials = materials_hvac.select {|data|
545
+ data['Material'].to_s == materialLookup.to_s && data['Size'].to_f >= materialSize.to_f
561
546
  }
562
- return ret_hash
547
+ if hvac_materials.empty?
548
+ # If no tanks have a big enough capacity then something is amiss and return an error (this should never happen
549
+ # because tanks capacity should be checked before this method is called).
550
+ puts "HVAC material error! Could not find next largest size for #{name} in #{materials_hvac}"
551
+ raise
552
+ elsif hvac_materials.size == 1
553
+ # Only one tank has an appropriate capacity find it's cost and return it.
554
+ matCost, labCost = getCost(name, hvac_materials[0], 1.0)
555
+ ret_hash = {
556
+ matCost: matCost,
557
+ labCost: labCost,
558
+ multiplier: multiplier,
559
+ Vol_USGal: tankVol,
560
+ Cap_kW: hvac_materials[0]['Size'].to_f
561
+
562
+ }
563
+ return ret_hash
564
+ else
565
+ # More than one tank has a big enough capacity. Find the cost of the one with teh smallest capacity and return
566
+ # it.
567
+ hvac_material = hvac_materials.min_by {|data| data['Size'].to_f}
568
+ matCost, labCost = getCost(name, hvac_material, 1.0)
569
+ ret_hash = {
570
+ matCost: matCost,
571
+ labCost: labCost,
572
+ multiplier: multiplier,
573
+ Vol_USGal: tankVol,
574
+ Cap_kW: hvac_material['Size'].to_f
575
+ }
576
+ return ret_hash
577
+ end
563
578
  else
564
- # More than one tank has a big enough capacity. Find the cost of the one with teh smallest capacity and return
565
- # it.
566
- hvac_material = hvac_materials.min_by {|data| data['Size'].to_f}
567
- matCost, labCost = getCost(name, hvac_material, 1.0)
568
- ret_hash = {
569
- matCost: matCost,
570
- labCost: labCost,
571
- multiplier: multiplier,
572
- Vol_USGal: tankVol,
573
- Cap_kW: hvac_material['Size'].to_f
574
- }
575
- return ret_hash
576
- end
577
- else
578
- # We need to find a tank with a big enough capacity and volume.
579
- # First see if a unique tank with a large enough capacity and volume exists
580
- hvac_materials = materials_hvac.select {|data|
581
- data['Material'].to_s == materialLookup.to_s && data['Size'].to_f >= materialSize.to_f && data['Fuel'].to_f >= tankVol
582
- }
583
- if hvac_materials.empty?
584
- # If none exists see if the tank volume is big enough. Note that tank capacity was checked earlier so capacity
585
- # should not be an issue. However, volume was not checked. It is possible that tanks with a big enough
586
- # capacity are in the costing database but not a big enough volume.
587
- #
588
- # Find the largest volume tank with a big enough capacity. Find out how many of those tanks are needed to
589
- # satisfy the volume requirement.
590
- multiplier, revVol = get_SHW_vol_multiplier(materialLookup: materialLookup, materialSize: materialSize, materialVol: tankVol)
591
- materialSize /= multiplier
592
- tankVol = revVol
593
- # Try again to get tanks with a large enough size and capacity
579
+ # We need to find a tank with a big enough capacity and volume.
580
+ # First see if a unique tank with a large enough capacity and volume exists
594
581
  hvac_materials = materials_hvac.select {|data|
595
582
  data['Material'].to_s == materialLookup.to_s && data['Size'].to_f >= materialSize.to_f && data['Fuel'].to_f >= tankVol
596
583
  }
597
- # You may notice that there is no handling for cases where there is more than one tank with a large enough
598
- # capacity and volume. There actually is, it is just a little further below.
599
584
  if hvac_materials.empty?
600
- puts "HVAC material error! Could not find a #{name} tank with a capacity >= #{materialSize} kW and a volume >= #{tankVol} US Gal in #{materials_hvac}"
585
+ # If none exists see if the tank volume is big enough. Note that tank capacity was checked earlier so capacity
586
+ # should not be an issue. However, volume was not checked. It is possible that tanks with a big enough
587
+ # capacity are in the costing database but not a big enough volume.
588
+ #
589
+ # Find the largest volume tank with a big enough capacity. Find out how many of those tanks are needed to
590
+ # satisfy the volume requirement.
591
+ multiplier, revVol = get_SHW_vol_multiplier(materialLookup: materialLookup, materialSize: materialSize, materialVol: tankVol)
592
+ materialSize /= multiplier
593
+ tankVol = revVol
594
+ # Try again to get tanks with a large enough size and capacity
595
+ hvac_materials = materials_hvac.select {|data|
596
+ data['Material'].to_s == materialLookup.to_s && data['Size'].to_f >= materialSize.to_f && data['Fuel'].to_f >= tankVol
597
+ }
598
+ # You may notice that there is no handling for cases where there is more than one tank with a large enough
599
+ # capacity and volume. There actually is, it is just a little further below.
600
+ if hvac_materials.empty?
601
+ puts "HVAC material error! Could not find a #{name} tank with a capacity >= #{materialSize} kW and a volume >= #{tankVol} US Gal in #{materials_hvac}"
602
+ elsif hvac_materials.size == 1
603
+ matCost, labCost = getCost(name, hvac_materials[0], 1.0)
604
+ ret_hash = {
605
+ matCost: matCost,
606
+ labCost: labCost,
607
+ multiplier: multiplier,
608
+ Vol_USGal: hvac_materials[0]['Fuel'].to_f,
609
+ Cap_kW: hvac_materials[0]['Size'].to_f
610
+ }
611
+ return ret_hash
612
+ end
601
613
  elsif hvac_materials.size == 1
602
614
  matCost, labCost = getCost(name, hvac_materials[0], 1.0)
603
615
  ret_hash = {
@@ -609,97 +621,86 @@ class BTAPCosting
609
621
  }
610
622
  return ret_hash
611
623
  end
612
- elsif hvac_materials.size == 1
613
- matCost, labCost = getCost(name, hvac_materials[0], 1.0)
614
- ret_hash = {
615
- matCost: matCost,
616
- labCost: labCost,
617
- multiplier: multiplier,
618
- Vol_USGal: hvac_materials[0]['Fuel'].to_f,
619
- Cap_kW: hvac_materials[0]['Size'].to_f
620
- }
621
- return ret_hash
622
- end
623
- # If mare than one tank has a lorge enough capacity and volume then find the one with the smallest volume.
624
- hvac_materials_min_vol = hvac_materials.min_by {|data| data['Fuel'].to_f}
625
- if hvac_materials_min_vol.nil?
626
- # Well, something went horribly wrong. You should have gotten this far only if there were several tanks that
627
- # had a large enough capacity and volume. Now we can't find the smallest one. Not sure what happened but
628
- # whatever it was it is not good.
629
- puts "HVAC material error! Could not find a #{name} tank with a capacity >= #{materialSize} kW and a volume >= #{materialVol} US Gal in costing database."
630
- raise
631
- else
632
- # Find how many tanks have the lowest volume.
633
- hvac_materials_vol = hvac_materials.select {|data| data['Fuel'].to_f == hvac_materials_min_vol['Fuel'].to_f}
634
- if hvac_materials_vol.size == 1
635
- hvac_material = hvac_materials_vol[0]
624
+ # If mare than one tank has a lorge enough capacity and volume then find the one with the smallest volume.
625
+ hvac_materials_min_vol = hvac_materials.min_by {|data| data['Fuel'].to_f}
626
+ if hvac_materials_min_vol.nil?
627
+ # Well, something went horribly wrong. You should have gotten this far only if there were several tanks that
628
+ # had a large enough capacity and volume. Now we can't find the smallest one. Not sure what happened but
629
+ # whatever it was it is not good.
630
+ puts "HVAC material error! Could not find a #{name} tank with a capacity >= #{materialSize} kW and a volume >= #{materialVol} US Gal in costing database."
631
+ raise
636
632
  else
637
- # If more than one tank as a small enough volume choose the one with the smallest capacity.
638
- hvac_material = hvac_materials_vol.min_by {|data| data['Size'].to_f}
633
+ # Find how many tanks have the lowest volume.
634
+ hvac_materials_vol = hvac_materials.select {|data| data['Fuel'].to_f == hvac_materials_min_vol['Fuel'].to_f}
635
+ if hvac_materials_vol.size == 1
636
+ hvac_material = hvac_materials_vol[0]
637
+ else
638
+ # If more than one tank as a small enough volume choose the one with the smallest capacity.
639
+ hvac_material = hvac_materials_vol.min_by {|data| data['Size'].to_f}
640
+ end
641
+ matCost, labCost = getCost(name, hvac_material, 1.0)
642
+ ret_hash = {
643
+ matCost: matCost,
644
+ labCost: labCost,
645
+ multiplier: multiplier,
646
+ Vol_USGal: hvac_material['Fuel'].to_f,
647
+ Cap_kW: hvac_material['Size'].to_f
648
+ }
649
+ return ret_hash
639
650
  end
640
- matCost, labCost = getCost(name, hvac_material, 1.0)
641
- ret_hash = {
642
- matCost: matCost,
643
- labCost: labCost,
644
- multiplier: multiplier,
645
- Vol_USGal: hvac_material['Fuel'].to_f,
646
- Cap_kW: hvac_material['Size'].to_f
647
- }
648
- return ret_hash
649
651
  end
650
652
  end
651
- end
652
653
 
653
- # This method is a copy of get_HVAC_multiplier but searches for volume in the 'Fuel' column of the materials_hvac
654
- # sheet. The 'Fuel' column is where tank volume information is kept for electric and oil SHW tanks.
655
- def get_SHW_vol_multiplier(materialLookup:, materialSize:, materialVol:)
656
- multiplier = 1.0
657
- materials_hvac = @costing_database['raw']['materials_hvac'].select {|data|
658
- data['Material'].to_s.upcase == materialLookup.to_s.upcase && data['Size'].to_f >= materialSize
659
- }
660
- if materials_hvac.nil? || materials_hvac.empty?
661
- puts("Error: no hvac information available for equipment #{materialLookup}!")
662
- raise
663
- end
664
- materials_hvac.length == 1 ? max_size = materials_hvac[0] : max_size = materials_hvac.max_by {|d| d['Fuel'].to_f}
665
- if max_size['Fuel'].to_f <= 0
666
- puts("Error: #{materialLookup} has a volume of 0 or less. Please check that the correct costing_database.json file is being used or check the costing spreadsheet!")
667
- raise
668
- end
669
- mult = materialVol.to_f / (max_size['Fuel'].to_f)
670
-
671
- multiplier = (mult.to_i).to_f + 1.0 # Use next largest integer for multiplier
672
- return multiplier.to_f, max_size['Fuel'].to_f
673
- end
654
+ # This method is a copy of get_HVAC_multiplier but searches for volume in the 'Fuel' column of the materials_hvac
655
+ # sheet. The 'Fuel' column is where tank volume information is kept for electric and oil SHW tanks.
656
+ def get_SHW_vol_multiplier(materialLookup:, materialSize:, materialVol:)
657
+ multiplier = 1.0
658
+ materials_hvac = @costing_database['raw']['materials_hvac'].select {|data|
659
+ data['Material'].to_s.upcase == materialLookup.to_s.upcase && data['Size'].to_f >= materialSize
660
+ }
661
+ if materials_hvac.nil? || materials_hvac.empty?
662
+ puts("Error: no hvac information available for equipment #{materialLookup}!")
663
+ raise
664
+ end
665
+ materials_hvac.length == 1 ? max_size = materials_hvac[0] : max_size = materials_hvac.max_by {|d| d['Fuel'].to_f}
666
+ if max_size['Fuel'].to_f <= 0
667
+ puts("Error: #{materialLookup} has a volume of 0 or less. Please check that the correct costing_database.json file is being used or check the costing spreadsheet!")
668
+ raise
669
+ end
670
+ mult = materialVol.to_f / (max_size['Fuel'].to_f)
674
671
 
675
- def get_cost_info(mat:, size: nil, unit: nil)
676
- comp_info = nil
677
- if unit.nil?
678
- comp_info = @costing_database['raw']['materials_hvac'].select {|data|
679
- data['Material'].to_s.upcase == mat.to_s.upcase and
680
- data['Size'].to_f.round(2) == size.to_f.round(2)
681
- }.first
682
- elsif size.nil?
683
- comp_info = @costing_database['raw']['materials_hvac'].select {|data|
684
- data['Material'].to_s.upcase == mat.to_s.upcase and
685
- data['unit'].to_s.upcase == unit.to_s.upcase
686
- }.first
687
- elsif size.nil? && unit.nil?
688
- comp_info = @costing_database['raw']['materials_hvac'].select {|data|
689
- data['Material'].to_s.upcase == mat.to_s.upcase
690
- }.first
691
- else
692
- comp_info = @costing_database['raw']['materials_hvac'].select {|data|
693
- data['Material'].to_s.upcase == mat.to_s.upcase and
694
- data['Size'].to_f.round(2) == size.to_f.round(2) and
695
- data['unit'].to_s.upcase == unit.to_s.upcase
696
- }.first
672
+ multiplier = (mult.to_i).to_f + 1.0 # Use next largest integer for multiplier
673
+ return multiplier.to_f, max_size['Fuel'].to_f
697
674
  end
698
- if comp_info.nil?
699
- puts("No data found for material: #{mat}, size: #{size}, with unit: #{unit}")
700
- raise
675
+
676
+ def get_cost_info(mat:, size: nil, unit: nil)
677
+ comp_info = nil
678
+ if unit.nil?
679
+ comp_info = @costing_database['raw']['materials_hvac'].select {|data|
680
+ data['Material'].to_s.upcase == mat.to_s.upcase and
681
+ data['Size'].to_f.round(2) == size.to_f.round(2)
682
+ }.first
683
+ elsif size.nil?
684
+ comp_info = @costing_database['raw']['materials_hvac'].select {|data|
685
+ data['Material'].to_s.upcase == mat.to_s.upcase and
686
+ data['unit'].to_s.upcase == unit.to_s.upcase
687
+ }.first
688
+ elsif size.nil? && unit.nil?
689
+ comp_info = @costing_database['raw']['materials_hvac'].select {|data|
690
+ data['Material'].to_s.upcase == mat.to_s.upcase
691
+ }.first
692
+ else
693
+ comp_info = @costing_database['raw']['materials_hvac'].select {|data|
694
+ data['Material'].to_s.upcase == mat.to_s.upcase and
695
+ data['Size'].to_f.round(2) == size.to_f.round(2) and
696
+ data['unit'].to_s.upcase == unit.to_s.upcase
697
+ }.first
698
+ end
699
+ if comp_info.nil?
700
+ puts("No data found for material: #{mat}, size: #{size}, with unit: #{unit}")
701
+ raise
702
+ end
703
+ return comp_info
701
704
  end
702
- return comp_info
703
705
  end
704
-
705
706
  end