Question-and-Answer Resource for the Building Energy Modeling Community
Get started with the Help page
Ask Your Question

Revision history [back]

Oh, I do not like non-freedom units. But you are right, that is the way of doing it.

I am copying below a section of the openstudio-standards gem in OpenStudio that handles that calculation :)

  def cooling_tower_apply_minimum_power_per_flow(cooling_tower)
# Get the design water flow rate
design_water_flow_m3_per_s = nil
if cooling_tower.designWaterFlowRate.is_initialized
  design_water_flow_m3_per_s = cooling_tower.designWaterFlowRate.get
elsif cooling_tower.autosizedDesignWaterFlowRate.is_initialized
  design_water_flow_m3_per_s = cooling_tower.autosizedDesignWaterFlowRate.get
else
  OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoolingTower', "For #{cooling_tower.name} design water flow rate is not available, cannot apply efficiency standard.")
  return false
end
design_water_flow_gpm = OpenStudio.convert(design_water_flow_m3_per_s, 'm^3/s', 'gal/min').get

# Get the table of cooling tower efficiencies
heat_rejection = standards_data['heat_rejection']

# Define the criteria to find the cooling tower properties
# in the hvac standards data set.
search_criteria = {}
search_criteria['template'] = template

# By definition cooling towers in E+ are open.
# Closed cooling towers are the fluidcooler objects.
search_criteria['equipment_type'] = 'Open Cooling Tower'

# @todo Standards replace this with a mechanism to store this
# data in the cooling tower object itself.
# For now, retrieve the fan type from the name
name = cooling_tower.name.get
fan_type = nil
if name.include?('Centrifugal')
  fan_type = 'Centrifugal'
elsif name.include?('Propeller or Axial')
  fan_type = 'Propeller or Axial'
end
unless fan_type.nil?
  search_criteria['fan_type'] = fan_type
end

# Limit on Centrifugal Fan
# Open Circuit Cooling Towers.
if fan_type == 'Centrifugal'
  gpm_limit = cooling_tower_apply_minimum_power_per_flow_gpm_limit(cooling_tower)
  if gpm_limit
    if design_water_flow_gpm >= gpm_limit
      fan_type = 'Propeller or Axial'
      search_criteria['fan_type'] = fan_type
      OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoolingTower', "For #{cooling_tower.name}, the design flow rate of #{design_water_flow_gpm.round} gpm is higher than the limit of #{gpm_limit.round} gpm for open centrifugal towers.  This tower must meet the minimum performance of #{fan_type} instead.")
    end
  end
end

# Get the cooling tower properties
ct_props = model_find_object(heat_rejection, search_criteria)
unless ct_props
  OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoolingTower', "For #{cooling_tower.name}, cannot find heat rejection properties, cannot apply standard efficiencies or curves.")
  return false
end

# Get cooling tower efficiency
min_gpm_per_hp = ct_props['minimum_performance']
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoolingTower', "For #{cooling_tower.name}, design water flow = #{design_water_flow_gpm.round} gpm, minimum performance = #{min_gpm_per_hp} gpm/hp (nameplate).")

# 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.
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
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'
}

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
end

fan_motor_eff = motor_properties['nominal_full_load_efficiency']
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

# Calculate the fan motor power
fan_motor_actual_power_hp = fan_bhp / fan_motor_eff
# 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.")

# Append the efficiency to the name
cooling_tower.setName("#{cooling_tower.name} #{min_gpm_per_hp.round(1)} gpm/hp")

# Hard size the design fan power.
# Leave the water flow and air flow autosized.
if cooling_tower.to_CoolingTowerSingleSpeed.is_initialized
  cooling_tower.setFanPoweratDesignAirFlowRate(fan_motor_actual_power_w)
elsif cooling_tower.to_CoolingTowerTwoSpeed.is_initialized
  cooling_tower.setHighFanSpeedFanPower(fan_motor_actual_power_w)
  cooling_tower.setLowFanSpeedFanPower(0.3 * fan_motor_actual_power_w)
elsif cooling_tower.to_CoolingTowerVariableSpeed.is_initialized
  cooling_tower.setDesignFanPower(fan_motor_actual_power_w)
end

return true
end