openstudio-standards 0.8.2 → 0.8.4
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.
- checksums.yaml +4 -4
- data/data/standards/OpenStudio_Standards-ashrae_90_1-ALL-comstock(space_types).xlsx +0 -0
- data/data/standards/openstudio_standards_duplicates_log.csv +7962 -0
- data/lib/openstudio-standards/btap/costing/README.md +502 -0
- data/lib/openstudio-standards/btap/costing/btap_costing.rb +473 -0
- data/lib/openstudio-standards/btap/costing/btap_measure_helper.rb +359 -0
- data/lib/openstudio-standards/btap/costing/btap_workflow.rb +117 -0
- data/lib/openstudio-standards/btap/costing/common_paths.rb +78 -0
- data/lib/openstudio-standards/btap/costing/common_resources/ConstructionProperties.csv +52 -0
- data/lib/openstudio-standards/btap/costing/common_resources/Constructions.csv +37 -0
- data/lib/openstudio-standards/btap/costing/common_resources/construction_sets.csv +1270 -0
- data/lib/openstudio-standards/btap/costing/common_resources/constructions_glazing.csv +61 -0
- data/lib/openstudio-standards/btap/costing/common_resources/constructions_opaque.csv +2256 -0
- data/lib/openstudio-standards/btap/costing/common_resources/costs.csv +1904 -0
- data/lib/openstudio-standards/btap/costing/common_resources/costs_local_factors.csv +2315 -0
- data/lib/openstudio-standards/btap/costing/common_resources/hvac_vent_ahu.csv +925 -0
- data/lib/openstudio-standards/btap/costing/common_resources/lighting.csv +364 -0
- data/lib/openstudio-standards/btap/costing/common_resources/lighting_sets.csv +2667 -0
- data/lib/openstudio-standards/btap/costing/common_resources/locations.csv +75 -0
- data/lib/openstudio-standards/btap/costing/common_resources/materials_glazing.csv +35 -0
- data/lib/openstudio-standards/btap/costing/common_resources/materials_hvac.csv +1699 -0
- data/lib/openstudio-standards/btap/costing/common_resources/materials_lighting.csv +267 -0
- data/lib/openstudio-standards/btap/costing/common_resources/materials_opaque.csv +164 -0
- data/lib/openstudio-standards/btap/costing/copy_test_results_files_to_expected_results.rb +11 -0
- data/lib/openstudio-standards/btap/costing/cost_building_from_file.rb +136 -0
- data/lib/openstudio-standards/btap/costing/costing_database_wrapper.rb +177 -0
- data/lib/openstudio-standards/btap/costing/daylighting_sensor_control_costing.rb +353 -0
- data/lib/openstudio-standards/btap/costing/dcv_costing.rb +314 -0
- data/lib/openstudio-standards/btap/costing/dummy.epw +8768 -0
- data/lib/openstudio-standards/btap/costing/dummy.osm +5320 -0
- data/lib/openstudio-standards/btap/costing/envelope_costing.rb +284 -0
- data/lib/openstudio-standards/btap/costing/heating_cooling_costing.rb +2584 -0
- data/lib/openstudio-standards/btap/costing/led_lighting_costing.rb +155 -0
- data/lib/openstudio-standards/btap/costing/lighting_costing.rb +209 -0
- data/lib/openstudio-standards/btap/costing/mech_sizing.json +502 -0
- data/lib/openstudio-standards/btap/costing/neb_end_use_prices.csv +42 -0
- data/lib/openstudio-standards/btap/costing/necb_2011_spacetype_info.csv +225 -0
- data/lib/openstudio-standards/btap/costing/necb_reference_runs.csv +28705 -0
- data/lib/openstudio-standards/btap/costing/nv_costing.rb +547 -0
- data/lib/openstudio-standards/btap/costing/parallel_tests.rb +92 -0
- data/lib/openstudio-standards/btap/costing/pv_ground_costing.rb +687 -0
- data/lib/openstudio-standards/btap/costing/shw_costing.rb +705 -0
- data/lib/openstudio-standards/btap/costing/test_list.txt +17 -0
- data/lib/openstudio-standards/btap/costing/test_run_all_test_locally.rb +26 -0
- data/lib/openstudio-standards/btap/costing/test_run_costing_tests.rb +80 -0
- data/lib/openstudio-standards/btap/costing/ventilation_costing.rb +2616 -0
- data/lib/openstudio-standards/constructions/modify.rb +2 -1
- data/lib/openstudio-standards/refrigeration/create_case.rb +58 -21
- data/lib/openstudio-standards/refrigeration/create_typical_refrigeration.rb +4 -2
- data/lib/openstudio-standards/refrigeration/create_walkin.rb +57 -22
- data/lib/openstudio-standards/refrigeration/data/refrigerated_cases.csv +31 -31
- data/lib/openstudio-standards/refrigeration/data/refrigerated_walkins.csv +76 -76
- data/lib/openstudio-standards/service_water_heating/create_typical.rb +10 -10
- data/lib/openstudio-standards/service_water_heating/create_water_heater.rb +10 -0
- data/lib/openstudio-standards/service_water_heating/create_water_heating_loop.rb +16 -3
- data/lib/openstudio-standards/service_water_heating/data/convert_data.rb +9 -9
- data/lib/openstudio-standards/service_water_heating/data/typical_water_use_equipment.csv +49 -49
- data/lib/openstudio-standards/service_water_heating/data/typical_water_use_equipment.json +159 -159
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXMultiSpeed.rb +7 -18
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXSingleSpeed.rb +10 -20
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXTwoSpeed.rb +6 -15
- data/lib/openstudio-standards/standards/Standards.CoilCoolingWaterToAirHeatPumpEquationFit.rb +5 -6
- data/lib/openstudio-standards/standards/Standards.CoilDX.rb +93 -43
- data/lib/openstudio-standards/standards/Standards.CoilHeatingDXMultiSpeed.rb +5 -5
- data/lib/openstudio-standards/standards/Standards.CoilHeatingDXSingleSpeed.rb +135 -37
- data/lib/openstudio-standards/standards/Standards.CoilHeatingWaterToAirHeatPumpEquationFit.rb +2 -2
- data/lib/openstudio-standards/standards/Standards.Model.rb +48 -13
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.computer_room_acs.json +302 -140
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.heat_pumps.json +648 -326
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.heat_pumps_heating.json +371 -90
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.water_heaters.json +66 -22
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.computer_room_acs.json +302 -140
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.heat_pumps.json +1012 -296
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.heat_pumps_heating.json +443 -79
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.water_heaters.json +66 -22
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.computer_room_acs.json +302 -140
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.heat_pumps.json +672 -306
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.heat_pumps_heating.json +354 -74
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.water_heaters.json +72 -24
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.computer_room_acs.json +302 -140
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.energy_recovery.json +8 -8
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.heat_pumps.json +930 -604
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.heat_pumps_heating.json +415 -111
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.water_heaters.json +72 -24
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.computer_room_acs.json +602 -140
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.heat_pumps.json +1005 -333
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.heat_pumps_heating.json +642 -88
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.water_heaters.json +78 -26
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.computer_room_acs.json +722 -140
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.heat_pumps.json +1741 -426
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.heat_pumps_heating.json +1108 -111
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.water_heaters.json +186 -62
- data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.schedules.json +62 -232
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXSingleSpeed.rb +2 -3
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXTwoSpeed.rb +1 -1
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilDX.rb +7 -18
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingDXSingleSpeed.rb +9 -7
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingGas.rb +1 -1
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb +2 -2
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.heat_pumps.json +154 -69
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.heat_pumps_heating.json +72 -72
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.water_heaters.json +382 -295
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb +6 -1
- data/lib/openstudio-standards/standards/deer/data/deer.schedules.json +62 -232
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/btap_pre1980.rb +2 -27
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/heat_pumps.json +16 -0
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/heat_pumps_heating.json +6 -0
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_3_and_8_single_speed.rb +68 -27
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_4.rb +64 -25
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_6.rb +9 -14
- data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +46 -20
- data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +635 -248
- data/lib/openstudio-standards/standards/necb/NECB2011/data/constants.json +43 -7
- data/lib/openstudio-standards/standards/necb/NECB2011/data/fuel_type_sets.json +7 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/HighriseApartmentMult.osm +14272 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/data/heat_pumps.json +16 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/data/heat_pumps_heating.json +6 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/data/necb_2015_table_c1.json +1 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/space_types.json +437 -437
- data/lib/openstudio-standards/standards/necb/NECB2011/data/systems.json +516 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/data/systems_including_sys5.json +588 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_namer.rb +489 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_1_single_speed.rb +16 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_2_and_5.rb +48 -5
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_multi_speed.rb +2 -2
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_single_speed.rb +35 -27
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_4.rb +34 -23
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_6.rb +8 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +43 -14
- data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +214 -25
- data/lib/openstudio-standards/standards/necb/NECB2011/system_fuels.rb +61 -1
- data/lib/openstudio-standards/standards/necb/NECB2015/data/heat_pumps.json +16 -0
- data/lib/openstudio-standards/standards/necb/NECB2015/data/heat_pumps_heating.json +8 -0
- data/lib/openstudio-standards/standards/necb/NECB2015/data/space_types.json +636 -636
- data/lib/openstudio-standards/standards/necb/NECB2015/data/unitary_acs.json +38 -38
- data/lib/openstudio-standards/standards/necb/NECB2015/hvac_systems.rb +15 -6
- data/lib/openstudio-standards/standards/necb/NECB2017/data/space_types.json +636 -636
- data/lib/openstudio-standards/standards/necb/NECB2020/data/chillers.json +71 -71
- data/lib/openstudio-standards/standards/necb/NECB2020/data/heat_pumps.json +20 -0
- data/lib/openstudio-standards/standards/necb/NECB2020/data/heat_pumps_heating.json +10 -0
- data/lib/openstudio-standards/standards/necb/README.md +343 -0
- data/lib/openstudio-standards/standards/necb/common/btap_data.rb +190 -28
- data/lib/openstudio-standards/standards/necb/common/btap_datapoint.rb +14 -5
- data/lib/openstudio-standards/standards/necb/common/eccc_electric_grid_intensity_20250311.csv +14 -0
- data/lib/openstudio-standards/standards/necb/common/nir_gas_grid_intensity_20250311.csv +14 -0
- data/lib/openstudio-standards/standards/necb/common/system_types.yaml +0 -0
- data/lib/openstudio-standards/utilities/logging.rb +18 -14
- data/lib/openstudio-standards/utilities/simulation.rb +3 -2
- data/lib/openstudio-standards/version.rb +1 -1
- data/lib/openstudio-standards/weather/modify.rb +2 -2
- data/lib/openstudio-standards.rb +12 -0
- metadata +56 -3
@@ -0,0 +1,705 @@
|
|
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
|
46
|
+
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'
|
67
|
+
tank_info[:tank_mult] = get_HVAC_multiplier(tank_info[:heater_fuel_type], tank_info[:nominal_capacity])
|
68
|
+
tank_info[:nominal_capacity] /= tank_info[:tank_mult]
|
69
|
+
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'
|
73
|
+
tank_info[:tank_mult] = get_HVAC_multiplier(tank_info[:heater_fuel_type], tank_info[:nominal_capacity])
|
74
|
+
tank_info[:nominal_capacity] /= tank_info[:tank_mult]
|
75
|
+
tank_info[:heater_volume_gal] /= tank_info[:tank_mult]
|
76
|
+
num_elec_tanks += tank_info[:tank_mult]
|
77
|
+
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]
|
87
|
+
else
|
88
|
+
num_reg_gas_tanks += tank_info[:tank_mult]
|
89
|
+
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]
|
99
|
+
else
|
100
|
+
num_reg_oil_tanks += tank_info[:tank_mult]
|
101
|
+
end
|
102
|
+
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
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
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]
|
167
|
+
tank[:tank_mult] *= shwTankCostInfo[:multiplier]
|
168
|
+
num_high_eff_oil_tanks += tank[:tank_mult]
|
169
|
+
else
|
170
|
+
num_reg_oil_tanks -= tank[:tank_mult]
|
171
|
+
tank[:tank_mult] *= shwTankCostInfo[:multiplier]
|
172
|
+
num_reg_oil_tanks += tank[:tank_mult]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
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]
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
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)
|
261
|
+
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
|
264
|
+
|
265
|
+
#6 inch elbow fitting for header (#386)
|
266
|
+
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)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
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
|
296
|
+
|
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)
|
301
|
+
|
302
|
+
elsif (num_reg_oil_tanks + num_high_eff_oil_tanks) > 0
|
303
|
+
# Oil tanks require fuel line+valves+connectors and electrical conduit
|
304
|
+
|
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
|
309
|
+
|
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
|
314
|
+
|
315
|
+
utilCost += (fuelLineCost * util_dist + fuelFittingCost) * (num_reg_oil_tanks + num_high_eff_oil_tanks) + oilFilterCost + oilTankCost
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
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
|
330
|
+
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
|
333
|
+
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
|
+
# 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
|
403
|
+
|
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?
|
433
|
+
}
|
434
|
+
other_public_wash = true
|
435
|
+
end
|
436
|
+
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
|
451
|
+
end
|
452
|
+
return total_shw_dist_cost
|
453
|
+
end
|
454
|
+
|
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
|
472
|
+
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
|
+
|
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
|
484
|
+
|
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
|
502
|
+
|
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
|
522
|
+
|
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
|
545
|
+
}
|
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
|
560
|
+
|
561
|
+
}
|
562
|
+
return ret_hash
|
563
|
+
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
|
594
|
+
hvac_materials = materials_hvac.select {|data|
|
595
|
+
data['Material'].to_s == materialLookup.to_s && data['Size'].to_f >= materialSize.to_f && data['Fuel'].to_f >= tankVol
|
596
|
+
}
|
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
|
+
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}"
|
601
|
+
elsif hvac_materials.size == 1
|
602
|
+
matCost, labCost = getCost(name, hvac_materials[0], 1.0)
|
603
|
+
ret_hash = {
|
604
|
+
matCost: matCost,
|
605
|
+
labCost: labCost,
|
606
|
+
multiplier: multiplier,
|
607
|
+
Vol_USGal: hvac_materials[0]['Fuel'].to_f,
|
608
|
+
Cap_kW: hvac_materials[0]['Size'].to_f
|
609
|
+
}
|
610
|
+
return ret_hash
|
611
|
+
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]
|
636
|
+
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}
|
639
|
+
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
|
+
end
|
650
|
+
end
|
651
|
+
end
|
652
|
+
|
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
|
674
|
+
|
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
|
697
|
+
end
|
698
|
+
if comp_info.nil?
|
699
|
+
puts("No data found for material: #{mat}, size: #{size}, with unit: #{unit}")
|
700
|
+
raise
|
701
|
+
end
|
702
|
+
return comp_info
|
703
|
+
end
|
704
|
+
|
705
|
+
end
|