lib/openstudio-standards/qaqc/hvac.rb in openstudio-standards-0.6.0.rc2 vs lib/openstudio-standards/qaqc/hvac.rb in openstudio-standards-0.6.3
- old
+ new
@@ -31,15 +31,13 @@
# get the weather file run period (as opposed to design day run period)
ann_env_pd = nil
@sql = @model.sqlFile.get
@sql.availableEnvPeriods.each do |env_pd|
env_type = @sql.environmentType(env_pd)
- if env_type.is_initialized
- if env_type.get == OpenStudio::EnvironmentType.new('WeatherRunPeriod')
- ann_env_pd = env_pd
- break
- end
+ if env_type.is_initialized && (env_type.get == OpenStudio::EnvironmentType.new('WeatherRunPeriod'))
+ ann_env_pd = env_pd
+ break
end
end
# only try to get the annual timeseries if an annual simulation was run
if ann_env_pd.nil?
@@ -96,19 +94,15 @@
end
end
end
# check setpoint manager temperatures against design temperatures
- if spm_min_temp_f
- if (spm_min_temp_f - design_cooling_sat).abs > max_sizing_temp_delta
- check_elems << OpenStudio::Attribute.new('flag', "Minor Error: Air loop '#{air_loop.name}' sizing uses a #{design_cooling_sat.round(1)}F design cooling supply air temperature, but the setpoint manager operates down to #{spm_min_temp_f.round(1)}F.")
- end
+ if spm_min_temp_f && ((spm_min_temp_f - design_cooling_sat).abs > max_sizing_temp_delta)
+ check_elems << OpenStudio::Attribute.new('flag', "Minor Error: Air loop '#{air_loop.name}' sizing uses a #{design_cooling_sat.round(1)}F design cooling supply air temperature, but the setpoint manager operates down to #{spm_min_temp_f.round(1)}F.")
end
- if spm_max_temp_f
- if (spm_max_temp_f - design_heating_sat).abs > max_sizing_temp_delta
- check_elems << OpenStudio::Attribute.new('flag', "Minor Error: Air loop '#{air_loop.name}' sizing uses a #{design_heating_sat.round(1)}F design heating supply air temperature, but the setpoint manager operates up to #{spm_max_temp_f.round(1)}F.")
- end
+ if spm_max_temp_f && ((spm_max_temp_f - design_heating_sat).abs > max_sizing_temp_delta)
+ check_elems << OpenStudio::Attribute.new('flag', "Minor Error: Air loop '#{air_loop.name}' sizing uses a #{design_heating_sat.round(1)}F design heating supply air temperature, but the setpoint manager operates up to #{spm_max_temp_f.round(1)}F.")
end
# set expected minimums for operating temperatures
expected_min = spm_min_temp_f.nil? ? design_cooling_sat : [design_cooling_sat, spm_min_temp_f].min
expected_max = spm_max_temp_f.nil? ? design_heating_sat : [design_heating_sat, spm_max_temp_f].max
@@ -131,16 +125,13 @@
reheat_zone = true
when 'OS_AirTerminal_SingleDuct_VAV_Reheat'
term = equipment.to_AirTerminalSingleDuctVAVReheat.get
reheat_op_f = OpenStudio.convert(term.maximumReheatAirTemperature, 'C', 'F').get
reheat_zone = true
- when 'OS_AirTerminal_SingleDuct_ParallelPIU_Reheat'
+ when 'OS_AirTerminal_SingleDuct_ParallelPIU_Reheat', 'OS_AirTerminal_SingleDuct_SeriesPIU_Reheat'
# reheat_op_f = # Not an OpenStudio input
reheat_zone = true
- when 'OS_AirTerminal_SingleDuct_SeriesPIU_Reheat'
- # reheat_op_f = # Not an OpenStudio input
- reheat_zone = true
end
end
# get the zone heating and cooling SAT for sizing
sizing_zone = zone.sizingZone
@@ -193,11 +184,11 @@
end
end
# check reasonableness of supply air temperatures when supply air flow rate is operating
flow_tolerance = OpenStudio.convert(10.0, 'cfm', 'm^3/s').get
operating_temperatures = temperatures.select.with_index { |_t, k| flowrates[k] > flow_tolerance }
- operating_temperatures = operating_temperatures.map { |t| (t * 1.8 + 32.0) }
+ operating_temperatures = operating_temperatures.map { |t| ((t * 1.8) + 32.0) }
next if operating_temperatures.empty?
runtime_fraction = operating_temperatures.size.to_f / temperatures.size
temps_out_of_bounds = operating_temperatures.select { |t| ((t < 40.0) || (t > 110.0) || ((t + max_operating_temp_delta) < expected_min) || ((t - max_operating_temp_delta) > expected_max)) }
@@ -492,14 +483,13 @@
elsif model_normalized_flow_rate_ip > air_loop_max_flow_rate_max_warning
check_elems << OpenStudio::Attribute.new('flag', "Warning: Flow Rate of #{model_normalized_flow_rate_ip.round(2)} #{air_loop_max_flow_rate_units_ip} for #{air_loop.name.get} is above #{air_loop_max_flow_rate_max_warning.round(2)} #{air_loop_max_flow_rate_units_ip}.")
elsif model_normalized_flow_rate_ip > air_loop_max_flow_rate_max_error
check_elems << OpenStudio::Attribute.new('flag', "Error: Flow Rate of #{model_normalized_flow_rate_ip.round(2)} #{air_loop_max_flow_rate_units_ip} for #{air_loop.name.get} is above #{air_loop_max_flow_rate_max_error.round(2)} #{air_loop_max_flow_rate_units_ip}.")
end
- end
- # loop through air loops to get max flow rate and cooling capacity.
- @model.getAirLoopHVACs.sort.each do |air_loop|
+ # loop through air loops to get max flow rate and cooling capacity.
+
# check if DOAS, don't check airflow or cooling capacity if it is
sizing_system = air_loop.sizingSystem
next if sizing_system.typeofLoadtoSizeOn.to_s == 'VentilationRequirement'
# gather argument options for air_loop_cooling_capacity checks
@@ -538,11 +528,11 @@
max_error = sizing_benchmarks['zone_heating_capacity']['max_error']
units_ip = sizing_benchmarks['zone_heating_capacity']['units']
@model.getThermalZones.sort.each do |thermal_zone|
next if thermal_zone.canBePlenum
- next if thermal_zone.exteriorSurfaceArea == 0.0
+ next if thermal_zone.exteriorSurfaceArea < 0.01
# check actual against target
query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='#{report_name}' and TableName='#{table_name}' and RowName= '#{thermal_zone.name.get.upcase}' and ColumnName= '#{column_name}'"
results = @sql.execAndReturnFirstDouble(query)
model_zone_heating_capacity_ip = OpenStudio.convert(results.to_f, 'W/m^2', units_ip).get
@@ -746,11 +736,11 @@
# eff values from model
motor_eff = component.motorEfficiency
# get eff values from standards
motor_bhp = std.pump_brake_horsepower(component)
- next if motor_bhp == 0.0
+ next if motor_bhp < 0.0001 # less than 1 watt
standard_minimum_motor_efficiency_and_size = std.pump_standard_minimum_motor_efficiency_and_size(component, motor_bhp)[0]
# check actual against target
if standard_minimum_motor_efficiency_and_size.nil?
@@ -767,11 +757,11 @@
# eff values from model
motor_eff = component.motorEfficiency
# get eff values from standards
motor_bhp = std.pump_brake_horsepower(component)
- next if motor_bhp == 0.0
+ next if motor_bhp < 0.0001 # less than 1 watt
standard_minimum_motor_efficiency_and_size = std.pump_standard_minimum_motor_efficiency_and_size(component, motor_bhp)[0]
# check actual against target
if standard_minimum_motor_efficiency_and_size.nil?
@@ -855,29 +845,27 @@
search_criteria['condenser_type'] = condenser_type
next
end
end
# if no match and also no absorption_type then issue warning
- if !search_criteria.key?('condenser_type') || search_criteria['condenser_type'].nil?
- if !search_criteria.key?('absorption_type') || search_criteria['absorption_type'].nil?
- check_elems << OpenStudio::Attribute.new('flag', "Can't find unique search criteria for #{component.name}. #{search_criteria}")
- next # don't go past here
- end
+ if (!search_criteria.key?('condenser_type') || search_criteria['condenser_type'].nil?) &&
+ (!search_criteria.key?('absorption_type') || search_criteria['absorption_type'].nil?)
+ check_elems << OpenStudio::Attribute.new('flag', "Can't find unique search criteria for #{component.name}. #{search_criteria}")
+ next # don't go past here
end
elsif search_criteria['cooling_type'] == 'WaterCooled'
chiller_air_cooled_condenser_types.each do |compressor_type|
if component.name.to_s.include?(compressor_type)
search_criteria['compressor_type'] = compressor_type
next
end
end
# if no match and also no absorption_type then issue warning
- if !search_criteria.key?('compressor_type') || search_criteria['compressor_type'].nil?
- if !search_criteria.key?('absorption_type') || search_criteria['absorption_type'].nil?
- check_elems << OpenStudio::Attribute.new('flag', "Can't find unique search criteria for #{component.name}. #{search_criteria}")
- next # don't go past here
- end
+ if (!search_criteria.key?('compressor_type') || search_criteria['compressor_type'].nil?) &&
+ (!search_criteria.key?('absorption_type') || search_criteria['absorption_type'].nil?)
+ check_elems << OpenStudio::Attribute.new('flag', "Can't find unique search criteria for #{component.name}. #{search_criteria}")
+ next # don't go past here
end
end
# lookup chiller
capacity_w = std.chiller_electric_eir_find_capacity(component)
@@ -1055,11 +1043,11 @@
next unless airloop.thermalZones.size > 1.0
end
# skip of brake horsepower is 0
- next if std.fan_brake_horsepower(component) == 0.0
+ next if std.fan_brake_horsepower(component) < 0.0001 # less than 1 wat
# temp model for use by temp model and target curve
model_temp = OpenStudio::Model::Model.new
# get coeficents for fan
@@ -1283,20 +1271,16 @@
end
# check setpoint manager temperatures against design temperatures
case plant_loop.sizingPlant.loopType
when 'Heating'
- if spm_max_temp_f
- if (spm_max_temp_f - design_supply_temperature).abs > max_sizing_temp_delta
- check_elems << OpenStudio::Attribute.new('flag', "Minor Error: #{plant_loop.name} sizing uses a #{design_supply_temperature.round(1)}F supply water temperature, but the setpoint manager operates up to #{spm_max_temp_f.round(1)}F.")
- end
+ if spm_max_temp_f && ((spm_max_temp_f - design_supply_temperature).abs > max_sizing_temp_delta)
+ check_elems << OpenStudio::Attribute.new('flag', "Minor Error: #{plant_loop.name} sizing uses a #{design_supply_temperature.round(1)}F supply water temperature, but the setpoint manager operates up to #{spm_max_temp_f.round(1)}F.")
end
when 'Cooling'
- if spm_min_temp_f
- if (spm_min_temp_f - design_supply_temperature).abs > max_sizing_temp_delta
- check_elems << OpenStudio::Attribute.new('flag', "Minor Error: #{plant_loop.name} sizing uses a #{design_supply_temperature.round(1)}F supply water temperature, but the setpoint manager operates down to #{spm_min_temp_f.round(1)}F.")
- end
+ if spm_min_temp_f && ((spm_min_temp_f - design_supply_temperature).abs > max_sizing_temp_delta)
+ check_elems << OpenStudio::Attribute.new('flag', "Minor Error: #{plant_loop.name} sizing uses a #{design_supply_temperature.round(1)}F supply water temperature, but the setpoint manager operates down to #{spm_min_temp_f.round(1)}F.")
end
end
# get supply water temperatures for supply outlet node
supply_temp_timeseries = @sql.timeSeries(ann_env_pd, 'Timestep', 'System Node Temperature', supply_outlet_node_name)
@@ -1326,18 +1310,18 @@
end
end
# check reasonableness of supply water temperatures when supply water flow rate is operating
operating_temperatures = temperatures.select.with_index { |_t, k| flowrates[k] > 1e-8 }
- operating_temperatures = operating_temperatures.map { |t| (t * 1.8 + 32.0) }
+ operating_temperatures = operating_temperatures.map { |t| ((t * 1.8) + 32.0) }
if operating_temperatures.empty?
check_elems << OpenStudio::Attribute.new('flag', "Warning: Flowrates are all zero in supply node timeseries for '#{plant_loop.name}'")
next
end
- runtime_fraction = operating_temperatures.size.to_f / temperatures.size.to_f
+ runtime_fraction = operating_temperatures.size / temperatures.size.to_f
temps_out_of_bounds = []
case plant_loop.sizingPlant.loopType
when 'Heating'
design_return_temperature = design_supply_temperature - design_temperature_difference
expected_max = spm_max_temp_f.nil? ? design_supply_temperature : [design_supply_temperature, spm_max_temp_f].max
@@ -1418,16 +1402,14 @@
# Check each plant loop
@model.getPlantLoops.sort.each do |plant_loop|
# Set the expected/typical W/gpm
loop_type = plant_loop.sizingPlant.loopType
case loop_type
- when 'Heating'
+ when 'Heating', 'Condenser'
expected_w_per_gpm = 19.0
when 'Cooling'
expected_w_per_gpm = 22.0
- when 'Condenser'
- expected_w_per_gpm = 19.0
end
# Check the W/gpm for each pump on each plant loop
plant_loop.supplyComponents.each do |component|
# Get the W/gpm for the pump
@@ -1495,15 +1477,13 @@
begin
# get the weather file run period (as opposed to design day run period)
ann_env_pd = nil
@sql.availableEnvPeriods.each do |env_pd|
env_type = @sql.environmentType(env_pd)
- if env_type.is_initialized
- if env_type.get == OpenStudio::EnvironmentType.new('WeatherRunPeriod')
- ann_env_pd = env_pd
- break
- end
+ if env_type.is_initialized && (env_type.get == OpenStudio::EnvironmentType.new('WeatherRunPeriod'))
+ ann_env_pd = env_pd
+ break
end
end
# only try to get the annual timeseries if an annual simulation was run
if ann_env_pd.nil?
@@ -1661,11 +1641,11 @@
# Convert to array
ts = ts.get.values
plrs = []
for i in 0..(ts.size - 1)
- plrs << ts[i] / design_power.to_f
+ plrs << (ts[i] / design_power.to_f)
end
# Bin part load ratios
bins = OpenstudioStandards::HVAC.hourly_part_load_ratio_bins(plrs)
frac_hrs_above_90 = bins[10]
@@ -1725,14 +1705,12 @@
# get the weather file run period (as opposed to design day run period)
ann_env_pd = nil
@sql.availableEnvPeriods.each do |env_pd|
env_type = @sql.environmentType(env_pd)
- if env_type.is_initialized
- if env_type.get == OpenStudio::EnvironmentType.new('WeatherRunPeriod')
- ann_env_pd = env_pd
- break
- end
+ if env_type.is_initialized && (env_type.get == OpenStudio::EnvironmentType.new('WeatherRunPeriod'))
+ ann_env_pd = env_pd
+ break
end
end
# only try to get the annual timeseries if an annual simulation was run
if ann_env_pd.nil?