lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb in openstudio-standards-0.4.0 vs lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb in openstudio-standards-0.5.0.rc1
- old
+ new
@@ -4,11 +4,11 @@
# Apply multizone vav outdoor air method and adjust multizone VAV damper positions
# to achieve a system minimum ventilation effectiveness of 0.6 per PNNL.
# Hard-size the resulting min OA into the sizing:system object.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # return [Bool] returns true if successful, false if not
+ # return [Boolean] returns true if successful, false if not
# @todo move building-type-specific code to Prototype classes
def air_loop_hvac_apply_multizone_vav_outdoor_air_sizing(air_loop_hvac)
# First time adjustment:
# Only applies to multi-zone vav systems
# exclusion: for Outpatient: (1) both AHU1 and AHU2 in 'DOE Ref Pre-1980' and 'DOE Ref 1980-2004'
@@ -23,11 +23,11 @@
# Apply all standard required controls to the airloop
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
# @todo optimum start
# @todo night damper shutoff
# @todo nightcycle control
# @todo night fan shutoff
def air_loop_hvac_apply_standard_controls(air_loop_hvac, climate_zone)
@@ -188,11 +188,11 @@
# Only applies those controls that differ from the normal prescriptive controls,
# which are added via air_loop_hvac_apply_standard_controls(air_loop_hvac, climate_zone)
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_apply_prm_baseline_controls(air_loop_hvac, climate_zone)
# Economizers
if air_loop_hvac_prm_baseline_economizer_required?(air_loop_hvac, climate_zone)
air_loop_hvac_apply_prm_baseline_economizer(air_loop_hvac, climate_zone)
else
@@ -231,11 +231,11 @@
# Determines if optimum start control is required.
# Defaults to 90.1-2004 logic, which requires optimum start if > 10,000 cfm
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
def air_loop_hvac_optimum_start_required?(air_loop_hvac)
opt_start_required = false
# data centers don't require optimum start as generally not occupied
return opt_start_required if air_loop_hvac.name.to_s.include?('CRAH') ||
@@ -266,11 +266,11 @@
end
# Adds optimum start control to the airloop.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_enable_optimum_start(air_loop_hvac)
# Get the heating and cooling setpoint schedules
# for all zones on this airloop.
htg_clg_schs = []
air_loop_hvac.thermalZones.each do |zone|
@@ -372,11 +372,11 @@
return true
end
# Set default fan curve to be VSD with static pressure reset
- # @return [string] name of appropriate curve for this code version
+ # @return [String name of appropriate curve for this code version
def air_loop_hvac_set_vsd_curve_type
return 'Multi Zone VAV with VSD and SP Setpoint Reset'
end
# Calculate and apply the performance rating method baseline fan power to this air loop.
@@ -385,11 +385,11 @@
# Also adjusts the fan power and flow rates of any parallel PIU terminals on the system.
# @todo Figure out how to split fan power between multiple fans
# if the proposed model had multiple fans (supply, return, exhaust, etc.)
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # return [Bool] true if successful, false if not
+ # return [Boolean] true if successful, false if not
def air_loop_hvac_apply_prm_baseline_fan_power(air_loop_hvac)
# Main AHU fans
# Calculate the allowable fan motor bhp
# for the entire airloop.
@@ -623,11 +623,11 @@
# Determine the total brake horsepower of the fans on the system
# with or without the fans inside of fan powered terminals.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @param include_terminal_fans [Bool] if true, power from fan powered terminals will be included
+ # @param include_terminal_fans [Boolean] if true, power from fan powered terminals will be included
# @return [Double] total brake horsepower of the fans on the system, in units of horsepower
def air_loop_hvac_system_fan_brake_horsepower(air_loop_hvac, include_terminal_fans = true)
# @todo get the template from the parent model itself?
# Or not because maybe you want to see the difference between two standards?
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "#{air_loop_hvac.name}-Determining #{template} allowable system fan power.")
@@ -666,11 +666,11 @@
# Set the fan pressure rises that will result in
# the system hitting the baseline allowable fan power
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_apply_baseline_fan_pressure_rise(air_loop_hvac)
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "#{air_loop_hvac.name}-Setting #{template} baseline fan power.")
# Get the total system bhp from the proposed system, including terminal fans
proposed_sys_bhp = air_loop_hvac_system_fan_brake_horsepower(air_loop_hvac, true)
@@ -782,10 +782,14 @@
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name} capacity of #{coil.name} is not available, total cooling capacity of air loop will be incorrect when applying standard.")
end
# CoilCoolingWater
elsif sc.to_CoilCoolingWater.is_initialized
coil = sc.to_CoilCoolingWater.get
+ # error if the design coil capacity method isn't available
+ if coil.model.version < OpenStudio::VersionString.new('3.6.0')
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.AirLoopHVAC', 'Required CoilCoolingWater method .autosizedDesignCoilLoad is not available in pre-OpenStudio 3.6.0 versions. Use a more recent version of OpenStudio.')
+ end
if coil.autosizedDesignCoilLoad.is_initialized
# @todo Change to pull water coil nominal capacity instead of design load
total_cooling_capacity_w += coil.autosizedDesignCoilLoad.get
else
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name} capacity of #{coil.name} is not available, total cooling capacity of air loop will be incorrect when applying standard.")
@@ -825,10 +829,14 @@
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name} capacity of #{coil.name} is not available, total cooling capacity of air loop will be incorrect when applying standard.")
end
# CoilCoolingWater
elsif clg_coil.to_CoilCoolingWater.is_initialized
coil = clg_coil.to_CoilCoolingWater.get
+ # error if the design coil capacity method isn't available
+ if coil.model.version < OpenStudio::VersionString.new('3.6.0')
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.AirLoopHVAC', 'Required CoilCoolingWater method .autosizedDesignCoilLoad is not available in pre-OpenStudio 3.6.0 versions. Use a more recent version of OpenStudio.')
+ end
if coil.autosizedDesignCoilLoad.is_initialized
# @todo Change to pull water coil nominal capacity instead of design load
total_cooling_capacity_w += coil.autosizedDesignCoilLoad.get
else
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name} capacity of #{coil.name} is not available, total cooling capacity of air loop will be incorrect when applying standard.")
@@ -869,10 +877,14 @@
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name} capacity of #{coil.name} is not available, total cooling capacity of air loop will be incorrect when applying standard.")
end
# CoilCoolingWater
elsif clg_coil.to_CoilCoolingWater.is_initialized
coil = clg_coil.to_CoilCoolingWater.get
+ # error if the design coil capacity method isn't available
+ if coil.model.version < OpenStudio::VersionString.new('3.6.0')
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.AirLoopHVAC', 'Required CoilCoolingWater method .autosizedDesignCoilLoad is not available in pre-OpenStudio 3.6.0 versions. Use a more recent version of OpenStudio.')
+ end
if coil.autosizedDesignCoilLoad.is_initialized
# @todo Change to pull water coil nominal capacity instead of design load
total_cooling_capacity_w += coil.autosizedDesignCoilLoad.get
else
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name} capacity of #{coil.name} is not available, total cooling capacity of air loop will be incorrect when applying standard.")
@@ -935,11 +947,11 @@
# Determine whether or not this system is required to have an economizer.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if an economizer is required, false if not
+ # @return [Boolean] returns true if an economizer is required, false if not
def air_loop_hvac_economizer_required?(air_loop_hvac, climate_zone)
economizer_required = false
# skip systems without outdoor air
return economizer_required unless air_loop_hvac.airLoopHVACOutdoorAirSystem.is_initialized
@@ -1011,11 +1023,11 @@
# Set the economizer limits per the standard. Limits are based on the economizer
# type currently specified in the ControllerOutdoorAir object on this air loop.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_apply_economizer_limits(air_loop_hvac, climate_zone)
# EnergyPlus economizer types
# 'NoEconomizer'
# 'FixedDryBulb'
# 'FixedEnthalpy'
@@ -1058,10 +1070,16 @@
if drybulb_limit_f
drybulb_limit_c = OpenStudio.convert(drybulb_limit_f, 'F', 'C').get
oa_control.setEconomizerMaximumLimitDryBulbTemperature(drybulb_limit_c)
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name}: Economizer type = #{economizer_type}, dry bulb limit = #{drybulb_limit_f}F")
end
+ # Some templates include fixed enthalpy limits in addition to fixed dry bulb limits
+ if enthalpy_limit_btu_per_lb
+ enthalpy_limit_j_per_kg = OpenStudio.convert(enthalpy_limit_btu_per_lb, 'Btu/lb', 'J/kg').get
+ oa_control.setEconomizerMaximumLimitEnthalpy(enthalpy_limit_j_per_kg)
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name}: additional economizer enthalpy limit = #{enthalpy_limit_btu_per_lb}Btu/lb")
+ end
when 'FixedEnthalpy'
if enthalpy_limit_btu_per_lb
enthalpy_limit_j_per_kg = OpenStudio.convert(enthalpy_limit_btu_per_lb, 'Btu/lb', 'J/kg').get
oa_control.setEconomizerMaximumLimitEnthalpy(enthalpy_limit_j_per_kg)
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name}: Economizer type = #{economizer_type}, enthalpy limit = #{enthalpy_limit_btu_per_lb}Btu/lb")
@@ -1121,11 +1139,11 @@
# set the economizer to integrated on non-integrated per the standard.
# @note this method assumes you previously checked that an economizer is required at all via #economizer_required?
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_apply_economizer_integration(air_loop_hvac, climate_zone)
# Determine if an integrated economizer is required
integrated_economizer_required = air_loop_hvac_integrated_economizer_required?(air_loop_hvac, climate_zone)
# Get the OA system and OA controller
@@ -1156,21 +1174,21 @@
end
# Determine if the airloop includes hydronic cooling coils
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if hydronic cooling coils are included on the airloop
+ # @return [Boolean] returns true if hydronic cooling coils are included on the airloop
def air_loop_hvac_include_hydronic_cooling_coil?(air_loop_hvac)
air_loop_hvac.supplyComponents.each do |comp|
return true if comp.to_CoilCoolingWater.is_initialized
end
return false
end
# Determine if the airloop includes cooling coils
#
- # @return [Bool] returns true if cooling coils are included on the airloop
+ # @return [Boolean] returns true if cooling coils are included on the airloop
def air_loop_hvac_include_cooling_coil?(air_loop_hvac)
air_loop_hvac.supplyComponents.each do |comp|
return true if comp.to_CoilCoolingWater.is_initialized
return true if comp.to_CoilCoolingWater.is_initialized
return true if comp.to_CoilCoolingCooledBeam.is_initialized
@@ -1212,22 +1230,22 @@
return false
end
# Determine if the airloop includes evaporative coolers
#
- # @return [Bool] returns true if evaporative coolers are included on the airloop
+ # @return [Boolean] returns true if evaporative coolers are included on the airloop
def air_loop_hvac_include_evaporative_cooler?(air_loop_hvac)
air_loop_hvac.supplyComponents.each do |comp|
return true if comp.to_EvaporativeCoolerDirectResearchSpecial.is_initialized
return true if comp.to_EvaporativeCoolerIndirectResearchSpecial.is_initialized
end
return false
end
# Determine if the airloop includes an air-economizer
#
- # @return [Bool] returns true if the airloop has an air-economizer
+ # @return [Boolean] returns true if the airloop has an air-economizer
def air_loop_hvac_include_economizer?(air_loop_hvac)
return false unless air_loop_hvac.airLoopHVACOutdoorAirSystem.is_initialized
# Get OA system
air_loop_hvac_oa_system = air_loop_hvac.airLoopHVACOutdoorAirSystem.get
@@ -1243,11 +1261,11 @@
end
# Determine if the airloop includes WSHP cooling coils
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if WSHP cooling coils are included on the airloop
+ # @return [Boolean] returns true if WSHP cooling coils are included on the airloop
def air_loop_hvac_include_wshp?(air_loop_hvac)
air_loop_hvac.supplyComponents.each do |comp|
return true if comp.to_CoilCoolingWaterToAirHeatPumpEquationFit.is_initialized
if comp.to_AirLoopHVACUnitarySystem.is_initialized
@@ -1259,11 +1277,11 @@
return false
end
# Determine if the air loop includes a unitary system
#
- # @return [Bool] returns true if a unitary system is included on the air loop
+ # @return [Boolean] returns true if a unitary system is included on the air loop
def air_loop_hvac_include_unitary_system?(air_loop_hvac)
air_loop_hvac.supplyComponents.each do |comp|
return true if comp.to_AirLoopHVACUnitarySystem.is_initialized
end
@@ -1273,11 +1291,11 @@
# Determine if the system economizer must be integrated or not.
# Default logic is from 90.1-2004.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
def air_loop_hvac_integrated_economizer_required?(air_loop_hvac, climate_zone)
# Determine if it is a VAV system
is_vav = air_loop_hvac_vav_system?(air_loop_hvac)
# Determine the number of zones the system serves
@@ -1351,11 +1369,11 @@
# Determine if an economizer is required per the PRM.
# Default logic from 90.1-2007
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
def air_loop_hvac_prm_baseline_economizer_required?(air_loop_hvac, climate_zone)
economizer_required = false
# A big number of ft2 as the minimum requirement
infinity_ft2 = 999_999_999_999
@@ -1413,11 +1431,11 @@
# Apply the PRM economizer type and set temperature limits
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_apply_prm_baseline_economizer(air_loop_hvac, climate_zone)
# EnergyPlus economizer types
# 'NoEconomizer'
# 'FixedDryBulb'
# 'FixedEnthalpy'
@@ -1533,11 +1551,11 @@
# Check the economizer type currently specified in the ControllerOutdoorAir object on this air loop
# is acceptable per the standard. Defaults to 90.1-2007 logic.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if allowable, if the system has no economizer or no OA system
+ # @return [Boolean] returns true if allowable, if the system has no economizer or no OA system
# Returns false if the economizer type is not allowable.
def air_loop_hvac_economizer_type_allowable?(air_loop_hvac, climate_zone)
# EnergyPlus economizer types
# 'NoEconomizer'
# 'FixedDryBulb'
@@ -1618,11 +1636,11 @@
# Check if ERV is required on this airloop.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
# @todo Add exception logic for systems serving parking garage, warehouse, or multifamily
def air_loop_hvac_energy_recovery_ventilator_required?(air_loop_hvac, climate_zone)
# ERV Not Applicable for AHUs that serve
# parking garage, warehouse, or multifamily
# if space_types_served_names.include?('PNNL_Asset_Rating_Apartment_Space_Type') ||
@@ -1778,11 +1796,11 @@
# Add an ERV to this airloop
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
# @todo Add exception logic for systems serving parking garage, warehouse, or multifamily
def air_loop_hvac_apply_energy_recovery_ventilator(air_loop_hvac, climate_zone)
# Get the OA system
oa_system = nil
if air_loop_hvac.airLoopHVACOutdoorAirSystem.is_initialized
@@ -1890,22 +1908,22 @@
# Determine if multizone vav optimization is required.
# Defaults to 90.1-2007 logic, where it is not required.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
# @todo Add exception logic for systems with AIA healthcare ventilation requirements dual duct systems
def air_loop_hvac_multizone_vav_optimization_required?(air_loop_hvac, climate_zone)
multizone_opt_required = false
return multizone_opt_required
end
# Enable multizone vav optimization by changing the Outdoor Air Method
# in the Controller:MechanicalVentilation object to 'VentilationRateProcedure'
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
def air_loop_hvac_enable_multizone_vav_optimization(air_loop_hvac)
# Enable multizone vav optimization
# at each timestep.
if air_loop_hvac.airLoopHVACOutdoorAirSystem.is_initialized
oa_system = air_loop_hvac.airLoopHVACOutdoorAirSystem.get
@@ -1926,11 +1944,11 @@
# Disable multizone vav optimization by changing the Outdoor Air Method
# in the Controller:MechanicalVentilation object to 'ZoneSum'
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
def air_loop_hvac_disable_multizone_vav_optimization(air_loop_hvac)
# Disable multizone vav optimization
# at each timestep.
if air_loop_hvac.airLoopHVACOutdoorAirSystem.is_initialized
oa_system = air_loop_hvac.airLoopHVACOutdoorAirSystem.get
@@ -1955,13 +1973,13 @@
end
# Set the minimum VAV damper positions.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @param has_ddc [Bool] if true, will assume that there is DDC control of vav terminals.
+ # @param has_ddc [Boolean] if true, will assume that there is DDC control of vav terminals.
# If false, assumes otherwise.
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_apply_minimum_vav_damper_positions(air_loop_hvac, has_ddc = true)
air_loop_hvac.thermalZones.each do |zone|
zone.equipment.each do |equip|
if equip.to_AirTerminalSingleDuctVAVReheat.is_initialized
zone_oa = thermal_zone_outdoor_airflow_rate(zone)
@@ -1976,11 +1994,11 @@
# Adjust minimum VAV damper positions and set minimum design
# system outdoor air flow
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
# @todo Add exception logic for systems serving parking garage, warehouse, or multifamily
def air_loop_hvac_adjust_minimum_vav_damper_positions(air_loop_hvac)
# Do not apply the adjustment to some of the system in
# the hospital and outpatient which have their minimum
# damper position determined based on AIA 2001 ventilation
@@ -2025,11 +2043,17 @@
e_vzs = []
e_vzs_adj = []
num_zones_adj = 0
# Retrieve the sum of the zone minimum primary airflow
- vpz_min_sum = air_loop_hvac.autosizeSumMinimumHeatingAirFlowRates
+ if air_loop_hvac.model.version < OpenStudio::VersionString.new('3.6.0')
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.AirLoopHVAC', 'Required AirLoopHVAC method .autosizedSumMinimumHeatingAirFlowRates is not available in pre-OpenStudio 3.6.0 versions. Use a more recent version of OpenStudio.')
+ elsif air_loop_hvac.autosizedSumMinimumHeatingAirFlowRates.is_initialized
+ vpz_min_sum = air_loop_hvac.autosizedSumMinimumHeatingAirFlowRates.get
+ else
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.AirLoopHVAC', "autosizedSumMinimumHeatingAirFlowRates is not available for air loop #{air_loop_hvac}.")
+ end
air_loop_hvac.thermalZones.sort.each do |zone|
# Breathing zone airflow rate
v_bz = thermal_zone_outdoor_airflow_rate(zone)
@@ -2041,10 +2065,16 @@
# Primary design airflow rate
# max of heating and cooling
# design air flow rates
v_pz = 0.0
+
+ # error if zone autosized methods are not available
+ if air_loop_hvac.model.version < OpenStudio::VersionString.new('3.6.0')
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.AirLoopHVAC', 'Required ThermalZone method .autosizedCoolingDesignAirFlowRate and .autosizedHeatingDesignAirFlowRate are not available in pre-OpenStudio 3.6.0 versions. Use a more recent version of OpenStudio.')
+ end
+
clg_dsn_flow = zone.autosizedCoolingDesignAirFlowRate
if clg_dsn_flow.is_initialized
clg_dsn_flow = clg_dsn_flow.get
if clg_dsn_flow > v_pz
v_pz = clg_dsn_flow
@@ -2172,11 +2202,21 @@
# Adjust minimum damper position if the sum of maximum
# zone airflow are lower than the calculated system
# outdoor air intake
if v_ot_adj > vpz_min_sum && v_ot_adj > 0
- mdp_adj = [v_ot_adj / air_loop_hvac.autosizeSumAirTerminalMaxAirFlowRate, 1].min
+
+ # Retrieve the sum of the zone maximum air flow rates
+ if air_loop_hvac.model.version < OpenStudio::VersionString.new('3.6.0')
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.AirLoopHVAC', 'Required AirLoopHVAC method .autosizedSumAirTerminalMaxAirFlowRate is not available in pre-OpenStudio 3.6.0 versions. Use a more recent version of OpenStudio.')
+ elsif air_loop_hvac.autosizedSumAirTerminalMaxAirFlowRate.is_initialized
+ v_max = air_loop_hvac.autosizedSumAirTerminalMaxAirFlowRate.get
+ else
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.AirLoopHVAC', "autosizedSumAirTerminalMaxAirFlowRate is not available for air loop #{air_loop_hvac}.")
+ end
+
+ mdp_adj = [v_ot_adj / v_max, 1].min
air_loop_hvac.thermalZones.sort.each do |zone|
air_loop_hvac_set_minimum_damper_position(zone, mdp_adj)
end
end
@@ -2198,11 +2238,11 @@
# Set an air terminal's minimum damper position
#
# @param zone [OpenStudio::Model::ThermalZone] thermal zone
# @param mdp [Double] minimum damper position
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_set_minimum_damper_position(zone, mdp)
zone.equipment.each do |equip|
if equip.to_AirTerminalSingleDuctVAVHeatAndCoolNoReheat.is_initialized
term = equip.to_AirTerminalSingleDuctVAVHeatAndCoolNoReheat.get
term.setZoneMinimumAirFlowFraction(mdp)
@@ -2227,11 +2267,11 @@
# Reference: <Achieving the 30% Goal: Energy and Cost Savings Analysis of ASHRAE Standard 90.1-2010> Page109-111
# For implementation purpose, since it is time-consuming to perform autosizing in three climate zones, just use
# the results of the current climate zone
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_adjust_minimum_vav_damper_positions_outpatient(air_loop_hvac)
air_loop_hvac.model.getSpaces.sort.each do |space|
zone = space.thermalZone.get
sizing_zone = zone.sizingZone
space_area = space.floorArea
@@ -2265,11 +2305,11 @@
# Determine if demand control ventilation (DCV) is required for this air loop.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
# @todo Add exception logic for systems that serve multifamily, parking garage, warehouse
def air_loop_hvac_demand_control_ventilation_required?(air_loop_hvac, climate_zone)
dcv_required = false
# OA flow limits
@@ -2360,11 +2400,11 @@
# Determine if the standard has an exception for demand control ventilation
# when an energy recovery device is present. Defaults to true.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
def air_loop_hvac_dcv_required_when_erv(air_loop_hvac)
dcv_required_when_erv_present = false
return dcv_required_when_erv_present
end
@@ -2372,11 +2412,11 @@
# Zones on this loop that require DCV preserve both per-area and per-person OA reqs.
# Other zones have OA reqs converted to per-area values only so that DCV won't impact these zones.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
def air_loop_hvac_enable_demand_control_ventilation(air_loop_hvac, climate_zone)
# Get the OA intake
controller_oa = nil
controller_mv = nil
if air_loop_hvac.airLoopHVACOutdoorAirSystem.is_initialized
@@ -2405,20 +2445,20 @@
# Determine if the system required supply air temperature (SAT) reset.
# Defaults to 90.1-2007, no SAT reset required.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
def air_loop_hvac_supply_air_temperature_reset_required?(air_loop_hvac, climate_zone)
is_sat_reset_required = false
return is_sat_reset_required
end
# Enable supply air temperature (SAT) reset based on the cooling demand of the warmest zone.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_enable_supply_air_temperature_reset_warmest_zone(air_loop_hvac)
# Get the current setpoint and calculate
# the new setpoint.
sizing_system = air_loop_hvac.sizingSystem
design_sat_c = sizing_system.centralCoolingDesignSupplyAirTemperature
@@ -2461,11 +2501,11 @@
# SAT will be kept at the current design temperature when outdoor air is above 70F,
# increased by 5F when outdoor air is below 50F,
# and reset linearly when outdoor air is between 50F and 70F.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_enable_supply_air_temperature_reset_outdoor_temperature(air_loop_hvac)
# for AHU1 in Outpatient, SAT is 52F constant, no reset
return true if air_loop_hvac.name.get == 'PVAV Outpatient F1'
# Get the current setpoint and calculate
@@ -2504,11 +2544,11 @@
end
# Determine if the system has an economizer
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
def air_loop_hvac_economizer?(air_loop_hvac)
# Get the OA system and OA controller
oa_sys = air_loop_hvac.airLoopHVACOutdoorAirSystem
return false unless oa_sys.is_initialized
@@ -2523,11 +2563,11 @@
end
# Determine if the system is a VAV system based on the fan which may be inside of a unitary system.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if vav system, false if not
+ # @return [Boolean] returns true if vav system, false if not
def air_loop_hvac_vav_system?(air_loop_hvac)
is_vav = false
air_loop_hvac.supplyComponents.reverse.each do |comp|
if comp.to_FanVariableVolume.is_initialized
is_vav = true
@@ -2550,11 +2590,11 @@
end
# Determine if the system is a multizone VAV system
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if multizone vav, false if not
+ # @return [Boolean] returns true if multizone vav, false if not
def air_loop_hvac_multizone_vav_system?(air_loop_hvac)
multizone_vav_system = false
# Must serve more than 1 zone
if air_loop_hvac.thermalZones.size < 2
@@ -2574,11 +2614,11 @@
end
# Determine if the system has terminal reheat
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if has one or more reheat terminals, false if it doesn't
+ # @return [Boolean] returns true if has one or more reheat terminals, false if it doesn't
def air_loop_hvac_terminal_reheat?(air_loop_hvac)
has_term_rht = false
air_loop_hvac.demandComponents.each do |sc|
if sc.to_AirTerminalSingleDuctConstantVolumeReheat.is_initialized ||
sc.to_AirTerminalSingleDuctParallelPIUReheat.is_initialized ||
@@ -2594,11 +2634,11 @@
end
# Determine if the system has energy recovery already
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if an ERV is present, false if not
+ # @return [Boolean] returns true if an ERV is present, false if not
def air_loop_hvac_energy_recovery?(air_loop_hvac)
has_erv = false
# Get the OA system
oa_sys = air_loop_hvac.airLoopHVACOutdoorAirSystem
@@ -2616,11 +2656,11 @@
end
# Determine if the air loop is a unitary system
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if a unitary system is present, false if not
+ # @return [Boolean] returns true if a unitary system is present, false if not
def air_loop_hvac_unitary_system?(air_loop_hvac)
is_unitary_system = false
air_loop_hvac.supplyComponents.each do |component|
obj_type = component.iddObjectType.valueName.to_s
case obj_type
@@ -2632,11 +2672,11 @@
end
# Set the VAV damper control to single maximum or dual maximum control depending on the standard.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
# @todo see if this impacts the sizing run.
def air_loop_hvac_apply_vav_damper_action(air_loop_hvac)
damper_action = air_loop_hvac_vav_damper_action(air_loop_hvac)
# Interpret this as an EnergyPlus input
@@ -2662,15 +2702,15 @@
# Dual maximum only applies to terminals with HW reheat coils
if damper_action == 'Dual Maximum'
if term.reheatCoil.to_CoilHeatingWater.is_initialized
term.setDamperHeatingAction(damper_action_eplus)
control_type_set = true
+ term.setMaximumFlowFractionDuringReheat(0.5)
end
else
term.setDamperHeatingAction(damper_action_eplus)
control_type_set = true
- term.setMaximumFlowFractionDuringReheat(0.5)
end
end
end
if control_type_set
@@ -2692,11 +2732,11 @@
# Determine if a motorized OA damper is required
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
def air_loop_hvac_motorized_oa_damper_required?(air_loop_hvac, climate_zone)
motorized_oa_damper_required = false
# @todo refactor: Remove building type dependent logic
if air_loop_hvac.name.to_s.include? 'Outpatient F1'
@@ -2787,11 +2827,11 @@
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param min_occ_pct [Double] the fractional value below which the system will be considered unoccupied.
# @param occ_sch [OpenStudio::Model::Schedule] the occupancy schedule.
# If not supplied, one will be created based on the supplied occupancy threshold.
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_add_motorized_oa_damper(air_loop_hvac, min_occ_pct = 0.05, occ_sch = nil)
# Get the OA system and OA controller
oa_sys = air_loop_hvac.airLoopHVACOutdoorAirSystem
return false unless oa_sys.is_initialized
@@ -2830,11 +2870,11 @@
# the damper will be open and OA will be brought into the building.
# This reflects the use of a backdraft gravity damper, and
# increases building loads unnecessarily during unoccupied hours.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_remove_motorized_oa_damper(air_loop_hvac)
# Get the OA system and OA controller
oa_sys = air_loop_hvac.airLoopHVACOutdoorAirSystem
return false unless oa_sys.is_initialized
@@ -2868,11 +2908,11 @@
# Generate the EMS used to implement the economizer and staging controls for packaged single zone units.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_apply_single_zone_controls(air_loop_hvac, climate_zone)
# These controls only apply to systems with DX cooling
unless air_loop_hvac_dx_cooling?(air_loop_hvac)
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name}: Single zone controls not applicable because no DX cooling.")
return true
@@ -3240,12 +3280,12 @@
# has DDC control of VAV terminals or not, determine this
# from the system itself. This may require additional information
# be added to the OpenStudio data model.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @param has_ddc [Bool] whether or not the system has DDC control over VAV terminals.
- # return [Bool] returns true if static pressure reset is required, false if not
+ # @param has_ddc [Boolean] whether or not the system has DDC control over VAV terminals.
+ # return [Boolean] returns true if static pressure reset is required, false if not
def air_loop_hvac_static_pressure_reset_required?(air_loop_hvac, has_ddc)
sp_reset_required = false
if has_ddc
sp_reset_required = true
@@ -3259,11 +3299,11 @@
# Determine if a system's fans must shut off when not required.
# Per ASHRAE 90.1 section 6.4.3.3, HVAC systems are required to have off-hour controls
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if required, false if not
+ # @return [Boolean] returns true if required, false if not
def air_loop_hvac_unoccupied_fan_shutoff_required?(air_loop_hvac)
shutoff_required = true
# Determine if the airloop serves any computer rooms or data centers, which default to always on.
if air_loop_hvac_data_center_area_served(air_loop_hvac) > 0
@@ -3303,11 +3343,11 @@
# If the system has an Always-On schedule assigned, a new schedule will be created.
# In this case, occupied is defined as the total percent occupancy for the loop for all zones served.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param min_occ_pct [Double] the fractional value below which the system will be considered unoccupied.
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_enable_unoccupied_fan_shutoff(air_loop_hvac, min_occ_pct = 0.05)
# Set the system to night cycle
# The fan of a parallel PIU terminal are set to only cycle during heating operation
# This is achieved using the CycleOnAnyCoolingOrHeatingZone; During cooling operation
# the load is met by running the central system which stays off during heating
@@ -3508,11 +3548,11 @@
# Sets the maximum reheat temperature to the specified value for all reheat terminals (of any type) on the loop.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
# @param max_reheat_c [Double] the maximum reheat temperature, in degrees Celsius
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_apply_maximum_reheat_temperature(air_loop_hvac, max_reheat_c)
air_loop_hvac.demandComponents.each do |sc|
if sc.to_AirTerminalSingleDuctConstantVolumeReheat.is_initialized
term = sc.to_AirTerminalSingleDuctConstantVolumeReheat.get
term.setMaximumReheatAirTemperature(max_reheat_c)
@@ -3536,11 +3576,11 @@
end
# Set the system sizing properties based on the zone sizing information
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if successful, false if not
+ # @return [Boolean] returns true if successful, false if not
def air_loop_hvac_apply_prm_sizing_temperatures(air_loop_hvac)
# Get the design heating and cooling SAT information
# for all zones served by the system.
htg_setpts_c = []
clg_setpts_c = []
@@ -3608,11 +3648,11 @@
end
# Determine if this Air Loop uses DX cooling.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if uses DX cooling, false if not
+ # @return [Boolean] returns true if uses DX cooling, false if not
def air_loop_hvac_dx_cooling?(air_loop_hvac)
dx_clg = false
# Check for all DX coil types
dx_types = [
@@ -3656,11 +3696,11 @@
end
# Determine if this Air Loop uses multi-stage DX cooling.
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
- # @return [Bool] returns true if uses multi-stage DX cooling, false if not
+ # @return [Boolean] returns true if uses multi-stage DX cooling, false if not
def air_loop_hvac_multi_stage_dx_cooling?(air_loop_hvac)
dx_clg = false
# Check for all DX coil types
dx_types = [
@@ -3699,12 +3739,12 @@
return dx_clg
end
# Get return fan power for airloop
#
- # @param model [OpenStudio::model::AirLoopHVAC] AirLoopHVAC object
- # @return [Float] Fan power
+ # @param air_loop [OpenStudio::Model::AirLoopHVAC] AirLoopHVAC object
+ # @return [Double] Fan power
def air_loop_hvac_get_return_fan_power(air_loop)
return_fan_power = 0
if air_loop.returnFan.is_initialized
# Get return fan
@@ -3726,12 +3766,12 @@
return return_fan_power
end
# Get supply fan power for airloop
#
- # @param model [OpenStudio::model::AirLoopHVAC] AirLoopHVAC object
- # @return [Float] Fan power
+ # @param air_loop [OpenStudio::Model::AirLoopHVAC] AirLoopHVAC object
+ # @return [Double] Fan power
def air_loop_hvac_get_supply_fan_power(air_loop)
supply_fan_power = 0
# Get fan
fan = air_loop_hvac_get_supply_fan(air_loop)
@@ -3744,11 +3784,11 @@
return supply_fan_power
end
# Get supply fan for airloop
#
- # @param model [OpenStudio::model::AirLoopHVAC] AirLoopHVAC object
+ # @param air_loop [OpenStudio::Model::AirLoopHVAC] AirLoopHVAC object
# @return fan
def air_loop_hvac_get_supply_fan(air_loop)
fan = nil
if air_loop.supplyFan.is_initialized
# Get return fan
@@ -3784,12 +3824,12 @@
return fan
end
# Get relief fan power for airloop
#
- # @param model [OpenStudio::model::AirLoopHVAC] AirLoopHVAC object
- # @return [Float] Fan power
+ # @param air_loop [OpenStudio::Model::AirLoopHVAC] AirLoopHVAC object
+ # @return [Double] Fan power
def air_loop_hvac_get_relief_fan_power(air_loop)
relief_fan_power = 0
if air_loop.reliefFan.is_initialized
# Get return fan
@@ -3815,12 +3855,12 @@
# When the thermostat schedule is setup or setback
# the ventilation is shutoff. Currently this is done
# by scheduling air terminal dampers (so load can
# still be met) and cycling unitary system fans
#
- # @param air_loop_hvac [OpenStudio::model::AirLoopHVAC] OpenStudio AirLoopHVAC object
- # @param standby_mode_space [Array] List of all spaces required to have standby mode controls
+ # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] OpenStudio AirLoopHVAC object
+ # @param standby_mode_spaces [Array<OpenStudio::Model::Space>] List of all spaces required to have standby mode controls
# @return [Boolean] true if sucessful, false otherwise
def air_loop_hvac_standby_mode_occupancy_control(air_loop_hvac, standby_mode_spaces)
return true
end
@@ -3828,19 +3868,18 @@
# For ASHRAE 90.1 2019, a maximum of 75% to reflect damper leakage per PNNL
#
# @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] HVAC air loop object
# @param oa_control [OpenStudio::Model::ControllerOutdoorAir] Outdoor air controller object to have this maximum OA fraction schedule
# @param snc [String] System name
- #
# @return [OpenStudio::Model::ScheduleRuleset] Generated maximum outdoor air fraction schedule for later use
def set_maximum_fraction_outdoor_air_schedule(air_loop_hvac, oa_control, snc)
max_oa_sch_name = "#{snc}maxOASch"
max_oa_sch = OpenStudio::Model::ScheduleRuleset.new(air_loop_hvac.model)
max_oa_sch.setName(max_oa_sch_name)
max_oa_sch.defaultDaySchedule.setName("#{max_oa_sch_name}Default")
max_oa_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0.7)
oa_control.setMaximumFractionofOutdoorAirSchedule(max_oa_sch)
- max_oa_sch
+ return max_oa_sch
end
# Checks if zones served by the air loop use zone exhaust fan
# a simplified approach to model transfer air
#