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.
- checksums.yaml +4 -4
- data/data/standards/test_performance_expected_dd_results.csv +90 -90
- data/lib/openstudio-standards/btap/activity.rb +858 -61
- data/lib/openstudio-standards/btap/attributes.rb +297 -103
- data/lib/openstudio-standards/btap/bridging.rb +1335 -593
- data/lib/openstudio-standards/btap/btap.rb +60 -181
- data/lib/openstudio-standards/btap/carbon/btap_carbon.rb +199 -142
- data/lib/openstudio-standards/btap/common/constructions.json +1275 -0
- data/lib/openstudio-standards/btap/common/costs.csv +1969 -0
- data/lib/openstudio-standards/btap/common/costs_local_factors.csv +2315 -0
- data/lib/openstudio-standards/btap/common/materials_glazing.csv +61 -0
- data/lib/openstudio-standards/btap/{common_resources → common}/materials_hvac.csv +1685 -1685
- data/lib/openstudio-standards/btap/{common_resources → common}/materials_lighting.csv +266 -266
- data/lib/openstudio-standards/btap/common/materials_opaque.csv +214 -0
- data/lib/openstudio-standards/btap/common/necb_building_types.csv +35 -0
- data/lib/openstudio-standards/btap/common/necb_space_types.csv +110 -0
- data/lib/openstudio-standards/btap/common/thermal_bridging.csv +73 -0
- data/lib/openstudio-standards/btap/costing/btap_costing.rb +346 -429
- data/lib/openstudio-standards/btap/costing/database.rb +104 -0
- data/lib/openstudio-standards/btap/costing/daylighting_sensor_control_costing.rb +356 -344
- data/lib/openstudio-standards/btap/costing/dcv_costing.rb +282 -296
- data/lib/openstudio-standards/btap/costing/envelope_costing.rb +179 -192
- data/lib/openstudio-standards/btap/costing/heating_cooling_costing.rb +2477 -2316
- data/lib/openstudio-standards/btap/costing/led_lighting_costing.rb +127 -142
- data/lib/openstudio-standards/btap/costing/lighting_costing.rb +216 -198
- data/lib/openstudio-standards/btap/costing/nv_costing.rb +522 -523
- data/lib/openstudio-standards/btap/costing/pv_ground_costing.rb +649 -649
- data/lib/openstudio-standards/btap/costing/shw_costing.rb +626 -625
- data/lib/openstudio-standards/btap/costing/thermal_bridging_costing.rb +72 -0
- data/lib/openstudio-standards/btap/costing/ventilation_costing.rb +2363 -2361
- data/lib/openstudio-standards/btap/deprecated.rb +1033 -0
- data/lib/openstudio-standards/btap/envelope.rb +313 -572
- data/lib/openstudio-standards/btap/fileio.rb +152 -1070
- data/lib/openstudio-standards/btap/geometry.rb +486 -766
- data/lib/openstudio-standards/btap/linear_regression.rb +130 -0
- data/lib/openstudio-standards/btap/paths.rb +46 -0
- data/lib/openstudio-standards/btap/qaqc/analysis.rb +163 -0
- data/lib/openstudio-standards/btap/qaqc/data.rb +2293 -0
- data/lib/openstudio-standards/btap/qaqc/datapoint.rb +641 -0
- data/lib/openstudio-standards/btap/schedules.rb +11 -611
- data/lib/openstudio-standards/btap/structure.rb +574 -189
- data/lib/openstudio-standards/constructions/materials/information.rb +1 -1
- data/lib/openstudio-standards/create_typical/create_typical.rb +1 -1
- data/lib/openstudio-standards/exterior_lighting/create.rb +135 -85
- data/lib/openstudio-standards/exterior_lighting/data/typical_exterior_lighting.json +20 -0
- data/lib/openstudio-standards/exterior_lighting/information.rb +23 -2
- data/lib/openstudio-standards/geometry/create.rb +7 -3
- data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.Model.rb +3 -2
- data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.Model.rb +3 -2
- data/lib/openstudio-standards/prototypes/common/data/thermostat_schedule_lookup.json +84 -84
- data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +4 -4
- data/lib/openstudio-standards/refrigeration/create_walkin.rb +45 -5
- data/lib/openstudio-standards/refrigeration/data/refrigerated_walkins.csv +75 -75
- data/lib/openstudio-standards/schedules/parametric.rb +6 -0
- data/lib/openstudio-standards/service_water_heating/create_typical.rb +10 -3
- data/lib/openstudio-standards/service_water_heating/create_water_heating_loop.rb +30 -14
- data/lib/openstudio-standards/service_water_heating/information.rb +4 -1
- data/lib/openstudio-standards/sql_file/unmet_hours.rb +2 -1
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXSingleSpeed.rb +3 -1
- data/lib/openstudio-standards/standards/Standards.CoilHeatingDXSingleSpeed.rb +3 -1
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.boilers.json +12 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.construction_properties.json +18432 -3072
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.boilers.json +26 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.construction_properties.json +8532 -1422
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.boilers.json +26 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.construction_properties.json +8532 -1422
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.boilers.json +16 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.computer_room_acs.json +30 -30
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.construction_properties.json +7560 -1260
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.PumpVariableSpeed.rb +1 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.boilers.json +16 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.construction_properties.json +7560 -1260
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.AirLoopHVAC.rb +3 -3
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.PumpVariableSpeed.rb +1 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.boilers.json +22 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.construction_properties.json +7236 -1206
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.furnaces.json +223 -19
- data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.schedules.json +37 -1
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.boilers.json +3 -0
- 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
- data/lib/openstudio-standards/standards/cbes/data/cbes.schedules.json +1 -1
- data/lib/openstudio-standards/standards/deer/data/deer.schedules.json +1 -1
- data/lib/openstudio-standards/standards/necb/BTAP1980TO2010/data/surface_thermal_transmittance.json +76 -40
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/surface_thermal_transmittance.json +76 -40
- data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +6 -4
- data/lib/openstudio-standards/standards/necb/NECB2011/NECB2011_QAQC.json +2988 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +25 -3
- data/lib/openstudio-standards/standards/necb/NECB2011/building_envelope.rb +672 -534
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/Hospital.osm +1791 -1792
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPMultiTower.osm +7 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPTownHouse.osm +7 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LargeHotel.osm +5 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LargeOffice.osm +8 -9
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernEducation.osm +10 -4
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernHealthCare.osm +14 -15
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/Outpatient.osm +7 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/surface_thermal_transmittance.json +76 -40
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +14 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +542 -130
- data/lib/openstudio-standards/standards/necb/NECB2011/qaqc/necb_qaqc.rb +30 -63
- data/lib/openstudio-standards/standards/necb/NECB2011/service_water_heating.rb +7 -2
- data/lib/openstudio-standards/standards/necb/NECB2015/data/surface_thermal_transmittance.json +90 -0
- data/lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb +8 -6
- data/lib/openstudio-standards/standards/necb/NECB2017/data/surface_thermal_transmittance.json +76 -40
- data/lib/openstudio-standards/standards/necb/NECB2017/necb_2017.rb +2 -1
- data/lib/openstudio-standards/standards/necb/NECB2020/building_envelope.rb +0 -117
- data/lib/openstudio-standards/standards/necb/NECB2020/data/surface_thermal_transmittance.json +76 -45
- data/lib/openstudio-standards/standards/necb/NECB2020/necb_2020.rb +218 -0
- data/lib/openstudio-standards/standards/necb/common/construction_defaults.osm +12 -7
- data/lib/openstudio-standards/standards/standard.rb +1 -1
- data/lib/openstudio-standards/version.rb +1 -1
- data/lib/openstudio-standards.rb +9 -4
- metadata +59 -66
- data/data/inventory/thermal_bridging.csv +0 -90
- data/data/standards/OpenStudio_Standards-ashrae_90_1-ALL-comstock(space_types).xlsx +0 -0
- data/data/standards/openstudio_standards_duplicates_log.csv +0 -7962
- data/lib/openstudio-standards/btap/NECB_building_types.csv +0 -35
- data/lib/openstudio-standards/btap/NECB_space_types.csv +0 -109
- data/lib/openstudio-standards/btap/WeatherData1.json +0 -2110
- data/lib/openstudio-standards/btap/WeatherData1.xlsx +0 -0
- data/lib/openstudio-standards/btap/btap_result.rb +0 -1144
- data/lib/openstudio-standards/btap/btap_test_helper.rb +0 -86
- data/lib/openstudio-standards/btap/common_paths.rb +0 -81
- data/lib/openstudio-standards/btap/common_resources/ConstructionProperties.csv +0 -52
- data/lib/openstudio-standards/btap/common_resources/Constructions.csv +0 -37
- data/lib/openstudio-standards/btap/common_resources/construction_sets.csv +0 -1270
- data/lib/openstudio-standards/btap/common_resources/constructions_glazing.csv +0 -121
- data/lib/openstudio-standards/btap/common_resources/constructions_opaque.csv +0 -2256
- data/lib/openstudio-standards/btap/common_resources/costs.csv +0 -1897
- data/lib/openstudio-standards/btap/common_resources/costs_local_factors.csv +0 -2315
- data/lib/openstudio-standards/btap/common_resources/materials_glazing.csv +0 -35
- data/lib/openstudio-standards/btap/common_resources/materials_opaque.csv +0 -164
- data/lib/openstudio-standards/btap/costing/btap_measure_helper.rb +0 -359
- data/lib/openstudio-standards/btap/costing/btap_workflow.rb +0 -117
- data/lib/openstudio-standards/btap/costing/copy_test_results_files_to_expected_results.rb +0 -11
- data/lib/openstudio-standards/btap/costing/cost_building_from_file.rb +0 -136
- data/lib/openstudio-standards/btap/costing/costing_database_wrapper.rb +0 -173
- data/lib/openstudio-standards/btap/costing/dummy.epw +0 -8768
- data/lib/openstudio-standards/btap/costing/dummy.osm +0 -5320
- data/lib/openstudio-standards/btap/costing/neb_end_use_prices.csv +0 -42
- data/lib/openstudio-standards/btap/costing/necb_2011_spacetype_info.csv +0 -225
- data/lib/openstudio-standards/btap/costing/necb_reference_runs.csv +0 -28705
- data/lib/openstudio-standards/btap/costing/parallel_tests.rb +0 -92
- data/lib/openstudio-standards/btap/costing/test_list.txt +0 -15
- data/lib/openstudio-standards/btap/costing/test_run_all_test_locally.rb +0 -27
- data/lib/openstudio-standards/btap/costing/test_run_costing_tests.rb +0 -80
- data/lib/openstudio-standards/btap/necb_2011_spacetype_info.csv +0 -225
- data/lib/openstudio-standards/btap/utilities/Add_template_field_to_json.rb +0 -22
- data/lib/openstudio-standards/btap/utilities/convert_surfaces_to_adiabatic_necb_8426.rb +0 -204
- data/lib/openstudio-standards/btap/utilities/generate_space_types.rb +0 -8
- data/lib/openstudio-standards/btap/utilities/necb_to_epw_map.rb +0 -50
- data/lib/openstudio-standards/btap/utilities/os_sim_extract.rb +0 -48
- data/lib/openstudio-standards/btap/utilities/rename_surfaces.rb +0 -24
- data/lib/openstudio-standards/btap/utilities/round_surf_coords.rb +0 -32
- data/lib/openstudio-standards/btap/utilities/sched_create.rb +0 -145
- data/lib/openstudio-standards/btap/utilities/set_mult_to_adiabatic.rb +0 -53
- data/lib/openstudio-standards/btap/utilities/space_type.rb +0 -78
- data/lib/openstudio-standards/btap/utilities/weatherData1_xlsx_to_json.rb +0 -56
- data/lib/openstudio-standards/btap/vintagizer.rb +0 -161
- data/lib/openstudio-standards/btap/visualization.rb +0 -72
- data/lib/openstudio-standards/standards/necb/NECB2011/data/necb_2011_spacetype_info.csv +0 -225
- data/lib/openstudio-standards/standards/necb/common/btap_analysis.rb +0 -79
- data/lib/openstudio-standards/standards/necb/common/btap_data.rb +0 -2656
- data/lib/openstudio-standards/standards/necb/common/btap_datapoint.rb +0 -653
- data/lib/openstudio-standards/standards/necb/common/necb_reference_runs.csv +0 -28705
- data/lib/openstudio-standards/standards/necb/common/utility_pricing_2025-02-20.csv +0 -92
- /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_frame.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_glazing.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_opaque.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/hvac_vent_ahu.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/lighting.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/lighting_sets.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/locations.csv +0 -0
- /data/lib/openstudio-standards/btap/{costing → common}/mech_sizing.json +0 -0
|
@@ -1,603 +1,615 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
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
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if
|
|
84
|
-
|
|
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
|
-
|
|
112
|
+
csPumpSize = csPump.ratedPowerConsumption.to_f
|
|
89
113
|
end
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
|
263
|
-
|
|
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
|
|
245
|
+
#6 inch elbow fitting (#386)
|
|
266
246
|
materialHash = get_cost_info(mat: 'VentingElbow', size: 6)
|
|
267
|
-
matCost, labCost = getCost('flue
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
#
|
|
271
|
-
|
|
272
|
-
|
|
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
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
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
|
-
|
|
303
|
-
|
|
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
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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
|
-
|
|
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
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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, '
|
|
332
|
-
pumpCost += matCost *
|
|
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
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
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
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
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
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
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
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
565
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
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
|
-
#
|
|
638
|
-
|
|
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
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
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
|
-
|
|
676
|
-
|
|
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
|
-
|
|
699
|
-
|
|
700
|
-
|
|
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
|