Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Building Energy Standards Motors Data Update #1716

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
4 changes: 4 additions & 0 deletions lib/openstudio-standards.rb
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ module OpenstudioStandards
require_relative "#{stds}/Standards.HeaderedPumpsVariableSpeed"
require_relative "#{stds}/Standards.HeatExchangerSensLat"
require_relative "#{stds}/Standards.Model"
require_relative "#{stds}/Standards.Motor"
require_relative "#{stds}/Standards.PlanarSurface"
require_relative "#{stds}/Standards.PlantLoop"
require_relative "#{stds}/Standards.PumpConstantSpeed"
Expand Down Expand Up @@ -333,6 +334,7 @@ module OpenstudioStandards
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.CoolingTowerVariableSpeed"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.FanVariableVolume"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.Model"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.Motor"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.PlantLoop"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.Space"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2013/ashrae_90_1_2013.ThermalZone"
Expand All @@ -348,6 +350,7 @@ module OpenstudioStandards
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.CoolingTowerVariableSpeed"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.FanVariableVolume"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.Model"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.Motor"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.Space"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.ThermalZone"
# 90.1-2019
Expand All @@ -362,6 +365,7 @@ module OpenstudioStandards
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.CoolingTowerVariableSpeed"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.FanVariableVolume"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.Model"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.Motor"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.Space"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.ThermalZone"
require_relative "#{stds}/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.WaterHeaterMixed"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,6 @@ def prototype_fan_apply_prototype_fan_efficiency(fan)
allowed_hp = 0.01
end

# Minimum motor size for efficiency lookup
# is 1 HP unless the motor serves an exhaust fan,
# a powered VAV terminal, or a fan coil unit.
if !fan_small_fan?(fan) && allowed_hp < 1.0
allowed_hp = 1.01
end

# Find the motor efficiency
motor_eff, nominal_hp = fan_standard_minimum_motor_efficiency_and_size(fan, allowed_hp)

Expand Down
61 changes: 44 additions & 17 deletions lib/openstudio-standards/standards/Standards.CoolingTower.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,28 +84,55 @@ def cooling_tower_apply_minimum_power_per_flow(cooling_tower)
# per method used in PNNL prototype buildings.
# Assumes that the fan brake horsepower is 90%
# of the fan nameplate rated motor power.
fan_motor_nameplate_hp = design_water_flow_gpm / min_gpm_per_hp
fan_bhp = 0.9 * fan_motor_nameplate_hp

# Lookup the minimum motor efficiency
# Source: Thornton et al. (2011), Achieving the 30% Goal: Energy and Cost Savings Analysis of ASHRAE Standard 90.1-2010, Section 4.5.4
nominal_hp = design_water_flow_gpm / min_gpm_per_hp
fan_bhp = 0.9 * nominal_hp
fan_motor_eff = 0.85
motors = standards_data['motors']

# Assuming all fan motors are 4-pole Enclosed
search_criteria = {
'template' => template,
'number_of_poles' => 4.0,
'type' => 'Enclosed'
}
if nominal_hp <= 0.75
motor_type = motor_type(nominal_hp)
motor_properties = motor_fractional_hp_efficiencies(nominal_hp, motor_type = motor_type)
else
# Lookup the minimum motor efficiency
motors = standards_data['motors']

# Assuming all fan motors are 4-pole Enclosed
search_criteria = {
'template' => template,
'number_of_poles' => 4.0,
'type' => 'Enclosed'
}

# Use the efficiency largest motor efficiency when BHP is greater than the largest size for which a requirement is provided
data = model_find_objects(motors, search_criteria)
if data.empty?
search_criteria = {
'template' => template,
'type' => nil
}
data = model_find_objects(motors, search_criteria)
end
maximum_capacity = model_find_maximum_value(data, 'maximum_capacity')
if fan_bhp > maximum_capacity
fan_bhp = maximum_capacity
end

motor_properties = model_find_object(motors, search_criteria, capacity = nil, date = Date.today, area = nil, num_floors = nil, fan_motor_bhp = fan_bhp)

if motor_properties.nil?
# Retry without the date
motor_properties = model_find_object(motors, search_criteria, capacity = nil, date = nil, area = nil, num_floors = nil, fan_motor_bhp = fan_bhp)
end
end

motor_properties = model_find_object(motors, search_criteria, fan_motor_nameplate_hp)
if motor_properties.nil?
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.CoolingTower', "For #{cooling_tower.name}, could not find motor properties using search criteria: #{search_criteria}, motor_hp = #{fan_motor_nameplate_hp} hp.")
return false
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.CoolingTower', "For #{cooling_tower.name}, could not find motor properties using search criteria: #{search_criteria}, motor_hp = #{nominal_hp} hp. Using a default value of #{fan_motor_eff}.")
end

fan_motor_eff = motor_properties['nominal_full_load_efficiency']
nominal_hp = motor_properties['maximum_capacity'].to_f.round(1)
unless motor_properties.nil?
fan_motor_eff = motor_properties['nominal_full_load_efficiency']
nominal_hp = motor_properties['maximum_capacity'].to_f.round(1)
end
# Round to nearest whole HP for niceness
if nominal_hp >= 2
nominal_hp = nominal_hp.round
Expand All @@ -116,7 +143,7 @@ def cooling_tower_apply_minimum_power_per_flow(cooling_tower)
# Convert to W
fan_motor_actual_power_w = fan_motor_actual_power_hp * 745.7 # 745.7 W/HP

OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoolingTower', "For #{cooling_tower.name}, allowed fan motor nameplate hp = #{fan_motor_nameplate_hp.round(1)} hp, fan brake horsepower = #{fan_bhp.round(1)}, and fan motor actual power = #{fan_motor_actual_power_hp.round(1)} hp (#{fan_motor_actual_power_w.round} W) at #{fan_motor_eff} motor efficiency.")
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoolingTower', "For #{cooling_tower.name}, allowed fan motor nameplate hp = #{nominal_hp.round(1)} hp, fan brake horsepower = #{fan_bhp.round(1)}, and fan motor actual power = #{fan_motor_actual_power_hp.round(1)} hp (#{fan_motor_actual_power_w.round} W) at #{fan_motor_eff} motor efficiency.")

# Append the efficiency to the name
cooling_tower.setName("#{cooling_tower.name} #{min_gpm_per_hp.to_f.round(1)} gpm/hp")
Expand Down
53 changes: 32 additions & 21 deletions lib/openstudio-standards/standards/Standards.Fan.rb
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ def fan_baseline_impeller_efficiency(fan)

# Determines the minimum fan motor efficiency and nominal size for a given motor bhp.
# This should be the total brake horsepower with any desired safety factor already included.
# This method picks the next nominal motor catgory larger than the required brake horsepower,
# This method picks the next nominal motor category larger than the required brake horsepower,
# and the efficiency is based on that size.
# For example, if the bhp = 6.3, the nominal size will be 7.5HP and the efficiency
# for 90.1-2010 will be 91.7% from Table 10.8B.
Expand All @@ -243,7 +243,12 @@ def fan_baseline_impeller_efficiency(fan)
# @return [Array<Double>] minimum motor efficiency (0.0 to 1.0), nominal horsepower
def fan_standard_minimum_motor_efficiency_and_size(fan, motor_bhp)
fan_motor_eff = 0.85
nominal_hp = motor_bhp
# Calculate the allowed fan brake horsepower
# per method used in PNNL prototype buildings.
# Assumes that the fan brake horsepower is 90%
# of the fan nameplate rated motor power.
# Source: Thornton et al. (2011), Achieving the 30% Goal: Energy and Cost Savings Analysis of ASHRAE Standard 90.1-2010, Section 4.5.4
nominal_hp = motor_bhp * 1.1

# Don't attempt to look up motor efficiency
# for zero-hp fans, which may occur when there is no
Expand All @@ -267,34 +272,40 @@ def fan_standard_minimum_motor_efficiency_and_size(fan, motor_bhp)
# In this case, use the 0.5 HP for the lookup.
if fan_small_fan?(fan)
nominal_hp = 0.5
else
motor_properties = model_find_object(motors, search_criteria, motor_bhp)

# Get the efficiency based on the nominal horsepower
motor_type = motor_type(nominal_hp)
motor_properties = motor_fractional_hp_efficiencies(nominal_hp, motor_type = motor_type)

if motor_properties.nil?
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Fan', "For #{fan.name}, could not find motor properties using search criteria: #{search_criteria}, motor_bhp = #{motor_bhp} hp.")
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Fan', "For #{fan.name}, could not find nominal motor properties using search criteria: #{search_criteria}, motor_hp = #{nominal_hp} hp.")
return [fan_motor_eff, nominal_hp]
end

nominal_hp = motor_properties['maximum_capacity'].to_f.round(1)
# If the biggest fan motor size is hit, use the highest category efficiency
if nominal_hp > 9998.0
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Fan', "For #{fan.name}, there is no greater nominal HP. Use the efficiency of the largest motor category.")
nominal_hp = motor_bhp
else
# Use the efficiency largest motor efficiency when BHP is greater than the largest size for which a requirement is provided
data = model_find_objects(motors, search_criteria)
maximum_capacity = model_find_maximum_value(data, 'maximum_capacity')
if motor_bhp > maximum_capacity
motor_bhp = maximum_capacity
end

# Round to nearest whole HP for niceness
if nominal_hp >= 2
nominal_hp = nominal_hp.round
motor_properties = model_find_object(motors, search_criteria, capacity = nil, date = Date.today, area = nil, num_floors = nil, fan_motor_bhp = motor_bhp)
if motor_properties.nil?
# Retry without the date
motor_properties = model_find_object(motors, search_criteria, capacity = nil, date = nil, area = nil, num_floors = nil, fan_motor_bhp = motor_bhp)
if motor_properties.nil?
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Fan', "For #{fan.name}, could not find motor properties using search criteria: #{search_criteria}, motor_bhp = #{motor_bhp} hp.")
return [fan_motor_eff, nominal_hp]
end
end
end

# Get the efficiency based on the nominal horsepower
# Add 0.01 hp to avoid search errors.
motor_properties = model_find_object(motors, search_criteria, nominal_hp + 0.01)

if motor_properties.nil?
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Fan', "For #{fan.name}, could not find nominal motor properties using search criteria: #{search_criteria}, motor_hp = #{nominal_hp} hp.")
return [fan_motor_eff, nominal_hp]
nominal_hp = motor_properties['maximum_capacity'].to_f.round(1)
# Round to nearest whole HP for niceness
if nominal_hp >= 2
nominal_hp = nominal_hp.round
end

fan_motor_eff = motor_properties['nominal_full_load_efficiency']

return [fan_motor_eff, nominal_hp]
Expand Down
63 changes: 45 additions & 18 deletions lib/openstudio-standards/standards/Standards.FluidCooler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,27 +76,54 @@ def fluid_cooler_apply_minimum_power_per_flow(fluid_cooler, equipment_type: 'Clo
# per method used in PNNL prototype buildings.
# Assumes that the fan brake horsepower is 90%
# of the fan nameplate rated motor power.
fan_motor_nameplate_hp = design_water_flow_gpm / min_gpm_per_hp
fan_bhp = 0.9 * fan_motor_nameplate_hp

# Lookup the minimum motor efficiency
motors = standards_data['motors']

# Assuming all fan motors are 4-pole Enclosed
search_criteria = {
'template' => template,
'number_of_poles' => 4.0,
'type' => 'Enclosed'
}
# Source: Thornton et al. (2011), Achieving the 30% Goal: Energy and Cost Savings Analysis of ASHRAE Standard 90.1-2010, Section 4.5.4
nominal_hp = design_water_flow_gpm / min_gpm_per_hp
fan_bhp = 0.9 * nominal_hp
fan_motor_eff = 0.85

if nominal_hp <= 0.75
motor_type = motor_type(nominal_hp)
motor_properties = motor_fractional_hp_efficiencies(nominal_hp, motor_type = motor_type)
else
# Lookup the minimum motor efficiency
motors = standards_data['motors']

# Assuming all fan motors are 4-pole Enclosed
search_criteria = {
'template' => template,
'number_of_poles' => 4.0,
'type' => 'Enclosed'
}

# Use the efficiency largest motor efficiency when BHP is greater than the largest size for which a requirement is provided
data = model_find_objects(motors, search_criteria)
if data.empty?
search_criteria = {
'template' => template,
'type' => nil
}
data = model_find_objects(motors, search_criteria)
end
maximum_capacity = model_find_maximum_value(data, 'maximum_capacity')
if fan_bhp > maximum_capacity
fan_bhp = maximum_capacity
end

motor_properties = model_find_object(motors, search_criteria, capacity = nil, date = Date.today, area = nil, num_floors = nil, fan_motor_bhp = fan_bhp)
if motor_properties.nil?
# Retry without the date
motor_properties = model_find_object(motors, search_criteria, capacity = nil, date = nil, area = nil, num_floors = nil, fan_motor_bhp = fan_bhp)
end
end

motor_properties = model_find_object(motors, search_criteria, fan_motor_nameplate_hp)
if motor_properties.nil?
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.FluidCooler', "For #{fluid_cooler.name}, could not find motor properties using search criteria: #{search_criteria}, motor_hp = #{motor_hp} hp.")
return false
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.FluidCooler', "For #{fluid_cooler.name}, could not find motor properties using search criteria: #{search_criteria}, motor_hp = #{norminal_hp} hp. Using a default value of #{fan_motor_eff}.")
end

fan_motor_eff = motor_properties['nominal_full_load_efficiency']
nominal_hp = motor_properties['maximum_capacity'].to_f.round(1)
unless motor_properties.nil?
fan_motor_eff = motor_properties['nominal_full_load_efficiency']
nominal_hp = motor_properties['maximum_capacity'].to_f.round(1)
end
# Round to nearest whole HP for niceness
if nominal_hp >= 2
nominal_hp = nominal_hp.round
Expand All @@ -107,7 +134,7 @@ def fluid_cooler_apply_minimum_power_per_flow(fluid_cooler, equipment_type: 'Clo
# Convert to W
fan_motor_actual_power_w = fan_motor_actual_power_hp * 745.7 # 745.7 W/HP

OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.FluidCooler', "For #{fluid_cooler.name}, allowed fan motor nameplate hp = #{fan_motor_nameplate_hp.round(1)} hp, fan brake horsepower = #{fan_bhp.round(1)}, and fan motor actual power = #{fan_motor_actual_power_hp.round(1)} hp (#{fan_motor_actual_power_w.round} W) at #{fan_motor_eff} motor efficiency.")
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.FluidCooler', "For #{fluid_cooler.name}, allowed fan motor nameplate hp = #{nominal_hp.round(1)} hp, fan brake horsepower = #{fan_bhp.round(1)}, and fan motor actual power = #{fan_motor_actual_power_hp.round(1)} hp (#{fan_motor_actual_power_w.round} W) at #{fan_motor_eff} motor efficiency.")

# Append the efficiency to the name
fluid_cooler.setName("#{fluid_cooler.name} #{min_gpm_per_hp.to_f.round(1)} gpm/hp")
Expand Down
Loading