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 #