diff --git a/lib/measures/nze_hvac/measure.rb b/lib/measures/nze_hvac/measure.rb
index bfce711..e951962 100644
--- a/lib/measures/nze_hvac/measure.rb
+++ b/lib/measures/nze_hvac/measure.rb
@@ -289,10 +289,10 @@ def arguments(model)
hvac_system_partition.setDefaultValue('Automatic Partition')
args << hvac_system_partition
- # add an argument for ventilation schedule
+ # @todo add an argument for ventilation schedule
return args
- end # end the arguments method
+ end
def run(model, runner, user_arguments)
super(model, runner, user_arguments)
@@ -347,6 +347,7 @@ def run(model, runner, user_arguments)
model.getThermalZones.each do |zone|
next if OpenstudioStandards::ThermalZone.thermal_zone_plenum?(zone)
next if !OpenstudioStandards::ThermalZone.thermal_zone_heated?(zone) && !OpenstudioStandards::ThermalZone.thermal_zone_cooled?(zone)
+
conditioned_zones << zone
end
@@ -430,8 +431,8 @@ def run(model, runner, user_arguments)
runner.registerFinalCondition("Added system type #{hvac_system_type} to model.")
return true
- end # end the run method
-end # end the measure
+ end
+end
# this allows the measure to be used by the application
NzeHvac.new.registerWithApplication
diff --git a/lib/measures/nze_hvac/measure.xml b/lib/measures/nze_hvac/measure.xml
index 43fdc25..d7ce6c6 100644
--- a/lib/measures/nze_hvac/measure.xml
+++ b/lib/measures/nze_hvac/measure.xml
@@ -3,8 +3,8 @@
3.1
nze_hvac
f060dff2-b28d-4194-a6af-e66d88ddb33c
- 8cbe5655-0c53-4e6d-8518-bfed32b6b4b8
- 2024-11-16T23:47:44Z
+ 5a23df2a-8da4-419b-b102-64f88077b5d8
+ 2024-11-26T20:39:00Z
0E5E4776
NzeHvac
NZEHVAC
@@ -258,13 +258,7 @@
measure.rb
rb
script
- 7EAD5ED0
-
-
- NZEHVAC_Test.rb
- rb
- test
- 90B2A846
+ F3FAC6D8
USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw
@@ -296,6 +290,12 @@
test
57483CB6
+
+ nze_hvac_test.rb
+ rb
+ test
+ BC3EA04F
+
office_chicago.osm
osm
diff --git a/lib/measures/nze_hvac/tests/NZEHVAC_Test.rb b/lib/measures/nze_hvac/tests/NZEHVAC_Test.rb
deleted file mode 100644
index 3816dfa..0000000
--- a/lib/measures/nze_hvac/tests/NZEHVAC_Test.rb
+++ /dev/null
@@ -1,356 +0,0 @@
-# frozen_string_literal: true
-
-# *******************************************************************************
-# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
-# See also https://openstudio.net/license
-# *******************************************************************************
-
-require 'openstudio'
-require 'openstudio-standards'
-require 'openstudio/measure/ShowRunnerOutput'
-require 'fileutils'
-require 'minitest/autorun'
-require_relative '../measure.rb'
-
-class NzeHvac_Test < Minitest::Test
- # #**** HELPER SCRIPTS ****##
-
- def run_dir(test_name)
- # always generate test output in specially named 'output' directory so result files are not made part of the measure
- return "#{File.dirname(__FILE__)}/output/#{test_name}"
- end
-
- def model_output_path(test_name)
- return "#{run_dir(test_name)}/#{test_name}.osm"
- end
-
- def sql_path(test_name)
- return "#{run_dir(test_name)}/run/eplusout.sql"
- end
-
- def report_path(test_name)
- return "#{run_dir(test_name)}/reports/eplustbl.html"
- end
-
- # applies the measure and then runs the model
- def run_nze_hvac_measure_test(test_name, osm_path, epw_path,
- hvac_system_type_input: 'DOAS with fan coil chiller with central air source heat pump',
- doas_dcv_input: false,
- hvac_system_partition_input: 'Whole Building',
- max_unmet_hrs: 550)
- assert(File.exist?(osm_path))
- assert(File.exist?(epw_path))
-
- # create run directory if it does not exist
- if !File.exist?(run_dir(test_name))
- FileUtils.mkdir_p(run_dir(test_name))
- end
- assert(File.exist?(run_dir(test_name)))
-
- # change into run directory for tests
- start_dir = Dir.pwd
- Dir.chdir run_dir(test_name)
-
- # copy weather file and osm to test directory
- new_osm_path = "#{run_dir(test_name)}/#{File.basename(osm_path)}"
- FileUtils.cp(osm_path, new_osm_path)
- osm_path = new_osm_path
- new_epw_path = "#{run_dir(test_name)}/#{File.basename(epw_path)}"
- FileUtils.cp(epw_path, new_epw_path)
- epw_path = new_epw_path
-
- # remove prior runs if they exist
- if File.exist?(model_output_path(test_name))
- FileUtils.rm(model_output_path(test_name))
- end
- if File.exist?(report_path(test_name))
- FileUtils.rm(report_path(test_name))
- end
-
- # create an instance of the measure
- measure = NzeHvac.new
-
- # create an instance of a runner
- runner = OpenStudio::Measure::OSRunner.new(OpenStudio::WorkflowJSON.new)
-
- # load the test model
- translator = OpenStudio::OSVersion::VersionTranslator.new
- model = translator.loadModel(OpenStudio::Path.new(osm_path))
- assert(!model.empty?)
- model = model.get
-
- # set model weather file
- epw_file = OpenStudio::EpwFile.new(OpenStudio::Path.new(epw_path))
- OpenStudio::Model::WeatherFile.setWeatherFile(model, epw_file)
- assert(model.weatherFile.is_initialized)
-
- # set arguments to good values
- arguments = measure.arguments(model)
- argument_map = OpenStudio::Measure::OSArgumentMap.new
-
- remove_existing_hvac = arguments[0].clone
- assert(remove_existing_hvac.setValue(true))
- argument_map['remove_existing_hvac'] = remove_existing_hvac
-
- hvac_system_type = arguments[1].clone
- assert(hvac_system_type.setValue(hvac_system_type_input))
- argument_map['hvac_system_type'] = hvac_system_type
-
- doas_dcv = arguments[2].clone
- assert(doas_dcv.setValue(doas_dcv_input))
- argument_map['doas_dcv'] = doas_dcv
-
- hvac_system_partition = arguments[3].clone
- assert(hvac_system_partition.setValue(hvac_system_partition_input))
- argument_map['hvac_system_partition'] = hvac_system_partition
-
- # run the measure
- puts '\nAPPLYING MEASURE...'
- measure.run(model, runner, argument_map)
- result = runner.result
-
- # assert that it ran correctly
- assert(result.value.valueName == 'Success')
- assert(result.warnings.empty?)
-
- # show the output
- show_output(result)
-
- # save model
- model.save(model_output_path(test_name), true)
-
- # run the model
- if result.value.valueName == 'Success'
- std = Standard.build('NREL ZNE Ready 2017')
- puts '\nRUNNING MODEL...'
-
- std.model_run_simulation_and_log_errors(model, run_dir(test_name))
-
- # check that the model ran successfully
- assert(File.exist?(sql_path(test_name)))
- end
-
- # check that the model ran successfully and generated a report
- assert(File.exist?(model_output_path(test_name)))
- assert(File.exist?(sql_path(test_name)))
- assert(File.exist?(report_path(test_name)))
-
- # set runner variables
- runner.setLastEpwFilePath(epw_path)
- runner.setLastOpenStudioModelPath(OpenStudio::Path.new(model_output_path(test_name)))
- runner.setLastEnergyPlusSqlFilePath(OpenStudio::Path.new(sql_path(test_name)))
-
- if !runner.lastEnergyPlusSqlFile.empty?
- sql = runner.lastEnergyPlusSqlFile.get
- model.setSqlFile(sql)
-
- # test for unmet hours
- errs = []
- unmet_heating_hrs = OpenstudioStandards::SqlFile.model_get_annual_occupied_unmet_heating_hours(model)
- unmet_cooling_hrs = OpenstudioStandards::SqlFile.model_get_annual_occupied_unmet_cooling_hours(model)
- unmet_hrs = OpenstudioStandards::SqlFile.model_get_annual_occupied_unmet_hours(model)
- if unmet_hrs
- if unmet_hrs > max_unmet_hrs
- errs << "For #{test_name} there were #{unmet_heating_hrs.round(1)} unmet occupied heating hours and #{unmet_cooling_hrs.round(1)} unmet occupied cooling hours (total: #{unmet_hrs.round(1)}), more than the limit of #{max_unmet_hrs}." if unmet_hrs > max_unmet_hrs
- else
- puts "There were #{unmet_heating_hrs.round(1)} unmet occupied heating hours and #{unmet_cooling_hrs.round(1)} unmet occupied cooling hours (total: #{unmet_hrs.round(1)})."
- end
- else
- errs << "For #{test_name} could not determine unmet hours; simulation may have failed."
- end
-
- # calculate EUIs to determine if HVAC EUI is appropriate
- annual_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2(model)
- int_lighting_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Interior Lighting').round(1)
- ext_lighting_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Exterior Lighting').round(1)
- int_equipment_elec_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Interior Equipment').round(1)
- int_equipment_gas_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Natural Gas', 'Interior Equipment').round(1)
- int_equipment_eui = (int_equipment_elec_eui + int_equipment_gas_eui).round(1)
- refrigeration_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Refrigeration').round(1)
- shw_elec_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Water Systems').round(1)
- shw_gas_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Natural Gas', 'Water Systems').round(1)
- shw_eui = (shw_elec_eui + shw_gas_eui).round(1)
- fan_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Fans').round(1)
- pump_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Pumps').round(1)
- cooling_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Cooling').round(1)
- heating_elec_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Heating').round(1)
- heating_gas_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Natural Gas', 'Heating').round(1)
- heating_eui = (heating_elec_eui + heating_gas_eui).round(1)
- hvac_eui = (fan_eui + pump_eui + cooling_eui + heating_eui).round(1)
- puts "Annual EUI (kBtu/ft^2): #{annual_eui.round(1)}, split:"
- puts "exterior lighting: #{ext_lighting_eui}"
- puts "interior lighting: #{int_lighting_eui}"
- puts "equipment: #{int_equipment_eui} (#{int_equipment_elec_eui} elec / #{int_equipment_gas_eui} gas)"
- puts "refrigeration: #{refrigeration_eui}"
- puts "service hot water: #{shw_eui} (#{shw_elec_eui} elec / #{shw_gas_eui} gas)"
- puts "HVAC #{hvac_eui} (fans: #{fan_eui}, pumps: #{pump_eui}, cooling: #{cooling_eui}, heating: #{heating_eui} (#{heating_elec_eui} elec / #{heating_gas_eui} gas))"
-
- if annual_eui > 100
- # don't expect EUIs to be above 100 unless there are very high internal loads
- errs << "The annual eui is #{annual_eui.round(1)} kBtu/ft^2, higher than expected for an NZE building." unless (int_equipment_eui + int_lighting_eui) > 70
- end
-
- assert(errs.empty?, errs.join('\n'))
- end
-
- # change back directory
- Dir.chdir(start_dir)
- end
-
- # #**** TESTS ****##
-
- def test_number_of_arguments_and_argument_names
- # this test ensures that the current test is matched to the measure inputs
- test_name = 'test_number_of_arguments_and_argument_names'
- puts "\n######\nTEST:#{test_name}\n######\n"
-
- # create an instance of the measure
- measure = NzeHvac.new
-
- # empty model
- model = OpenStudio::Model::Model.new
-
- # get arguments and test that they are what we are expecting
- arguments = measure.arguments(model)
- assert_equal(4, arguments.size)
- assert_equal('remove_existing_hvac', arguments[0].name)
- assert_equal('hvac_system_type', arguments[1].name)
- assert_equal('doas_dcv', arguments[2].name)
- assert_equal('hvac_system_partition', arguments[3].name)
- end
-
- def test_primary_school_fancoils_doas
- # this tests adding a fancoils with doas system to the model
- test_name = 'test_primary_school_fancoils_doas'
- puts "\n######\nTEST:#{test_name}\n######\n"
- osm_path = File.dirname(__FILE__) + '/primary_school_burlington.osm'
- epw_path = File.dirname(__FILE__) + '/USA_VT_Burlington.Intl.AP.726170_TMY3.epw'
- run_nze_hvac_measure_test(test_name, osm_path, epw_path,
- hvac_system_type_input: 'DOAS with fan coil chiller with boiler',
- hvac_system_partition_input: 'Whole Building')
- end
-
- def test_office_radiant_doas
- # this tests adding a radiant slab system with doas system to the model
- test_name = 'test_office_radiant_doas'
- puts "\n######\nTEST:#{test_name}\n######\n"
- osm_path = File.dirname(__FILE__) + '/office_chicago_exp_tstat.osm'
- epw_path = File.dirname(__FILE__) + '/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw'
- run_nze_hvac_measure_test(test_name, osm_path, epw_path,
- hvac_system_type_input: 'DOAS with radiant slab chiller with central air source heat pump',
- hvac_system_partition_input: 'Whole Building',
- max_unmet_hrs: 2500.0) # TODO: - lower back to 600 hours after address issue with this test in release after 2.9.0, reased from 650 to 675 foor 3.4
- end
-
- def test_office_doas_vrf_per_story
- # this tests adding a doas with vrf system to the model
- test_name = 'test_office_vrf_doas_per_story'
- puts "\n######\nTEST:#{test_name}\n######\n"
- osm_path = File.dirname(__FILE__) + '/office_chicago.osm'
- epw_path = File.dirname(__FILE__) + '/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw'
- run_nze_hvac_measure_test(test_name, osm_path, epw_path,
- hvac_system_type_input: 'DOAS with VRF',
- hvac_system_partition_input: 'One System Per Building Story')
- end
-
- def test_office_vav_reheat
- # this tests adding a VAV reheat system to the model
- test_name = 'test_office_vav_reheat'
- puts "\n######\nTEST:#{test_name}\n######\n"
- osm_path = File.dirname(__FILE__) + '/office_chicago.osm'
- epw_path = File.dirname(__FILE__) + '/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw'
- run_nze_hvac_measure_test(test_name, osm_path, epw_path,
- hvac_system_type_input: 'VAV chiller with gas boiler reheat',
- hvac_system_partition_input: 'Whole Building')
- end
-
- def test_office_pvav_reheat
- # this tests adding a PVAV reheat system to the model
- test_name = 'test_office_pvav_reheat'
- puts "\n######\nTEST:#{test_name}\n######\n"
- osm_path = File.dirname(__FILE__) + '/office_chicago.osm'
- epw_path = File.dirname(__FILE__) + '/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw'
- run_nze_hvac_measure_test(test_name, osm_path, epw_path,
- hvac_system_type_input: 'PVAV with gas boiler reheat',
- hvac_system_partition_input: 'Whole Building')
- end
-
- def test_mixed_use_vrf_doas
- # this tests adding a vrf with doas system to the model
- test_name = 'test_mixed_use_vrf_doas'
- puts "\n######\nTEST:#{test_name}\n######\n"
- osm_path = File.dirname(__FILE__) + '/office_retail_mix_chicago.osm'
- epw_path = File.dirname(__FILE__) + '/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw'
- run_nze_hvac_measure_test(test_name, osm_path, epw_path,
- hvac_system_type_input: 'DOAS with VRF',
- hvac_system_partition_input: 'One System Per Building Type',
- max_unmet_hrs: 650.0)
- end
-
- def test_mixed_use_gshp_doas
- # this tests adding a ghsp with doas system to the model
- test_name = 'test_mixed_use_gshp_doas'
- puts "\n######\nTEST:#{test_name}\n######\n"
- osm_path = File.dirname(__FILE__) + '/office_retail_mix_chicago.osm'
- epw_path = File.dirname(__FILE__) + '/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw'
- run_nze_hvac_measure_test(test_name, osm_path, epw_path,
- hvac_system_type_input: 'DOAS with water source heat pumps with ground source heat pump',
- hvac_system_partition_input: 'Whole Building')
- end
-
- def test_model_with_sizing_issues
- # this tests adding a vav reheat system to the model with high envelope and internal loads
- test_name = 'test_model_with_sizing_issues'
- puts "\n######\nTEST:#{test_name}\n######\n"
- osm_path = File.dirname(__FILE__) + '/glass_box_baltimore.osm'
- epw_path = File.dirname(__FILE__) + '/USA_MD_Baltimore-Washington.Intl.AP.724060_TMY3.epw'
- run_nze_hvac_measure_test(test_name, osm_path, epw_path,
- hvac_system_type_input: 'VAV air-cooled chiller with central air source heat pump reheat',
- hvac_system_partition_input: 'Whole Building')
- end
-
- def test_humid_office_fancoils_doas
- # this tests adding a fancoils with doas system to the model
- test_name = 'test_humid_office_doas_fancoils'
- puts "\n######\nTEST:#{test_name}\n######\n"
- osm_path = File.dirname(__FILE__) + '/office_houston.osm'
- epw_path = File.dirname(__FILE__) + '/USA_TX_Houston-Bush.Intercontinental.AP.722430_TMY3.epw'
- run_nze_hvac_measure_test(test_name, osm_path, epw_path,
- hvac_system_type_input: 'DOAS with fan coil air-cooled chiller with central air source heat pump',
- hvac_system_partition_input: 'Whole Building')
- end
-
- def test_humid_office_doas_fancoils_dcv
- # this tests adding a fancoils with doas system to the model
- test_name = 'test_humid_office_doas_fancoils_dcv'
- puts "\n######\nTEST:#{test_name}\n######\n"
- osm_path = File.dirname(__FILE__) + '/office_houston.osm'
- epw_path = File.dirname(__FILE__) + '/USA_TX_Houston-Bush.Intercontinental.AP.722430_TMY3.epw'
- run_nze_hvac_measure_test(test_name, osm_path, epw_path,
- hvac_system_type_input: 'DOAS with fan coil air-cooled chiller with central air source heat pump',
- doas_dcv_input: true,
- hvac_system_partition_input: 'Whole Building')
- end
-
- def test_humid_office_fancoils_doas_auto_partition
- # this tests adding a fancoils with doas system to the model with automatic partitioning
- test_name = 'test_humid_office_fancoils_doas_auto_partition'
- puts "\n######\nTEST:#{test_name}\n######\n"
- osm_path = File.dirname(__FILE__) + '/office_houston.osm'
- epw_path = File.dirname(__FILE__) + '/USA_TX_Houston-Bush.Intercontinental.AP.722430_TMY3.epw'
- run_nze_hvac_measure_test(test_name, osm_path, epw_path,
- hvac_system_type_input: 'DOAS with fan coil chiller with central air source heat pump',
- hvac_system_partition_input: 'Automatic Partition')
- end
-
- def test_humid_office_vav_reheat_auto_partition
- # this tests adding a vav reheat system to the model with automatic partitioning
- test_name = 'test_humid_office_vav_reheat_auto_partition'
- puts "\n######\nTEST:#{test_name}\n######\n"
- osm_path = File.dirname(__FILE__) + '/office_houston.osm'
- epw_path = File.dirname(__FILE__) + '/USA_TX_Houston-Bush.Intercontinental.AP.722430_TMY3.epw'
- run_nze_hvac_measure_test(test_name, osm_path, epw_path,
- hvac_system_type_input: 'VAV chiller with central air source heat pump reheat',
- hvac_system_partition_input: 'Automatic Partition')
- end
-end
diff --git a/lib/measures/nze_hvac/tests/nze_hvac_test.rb b/lib/measures/nze_hvac/tests/nze_hvac_test.rb
new file mode 100644
index 0000000..48a07b3
--- /dev/null
+++ b/lib/measures/nze_hvac/tests/nze_hvac_test.rb
@@ -0,0 +1,319 @@
+# frozen_string_literal: true
+
+# *******************************************************************************
+# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
+# See also https://openstudio.net/license
+# *******************************************************************************
+
+# dependencies
+require 'fileutils'
+require 'minitest/autorun'
+require 'openstudio'
+require 'openstudio/measure/ShowRunnerOutput'
+require 'openstudio-standards'
+require_relative '../measure'
+
+class NzeHvacTest < Minitest::Test
+ def run_dir(test_name)
+ # always generate test output in specially named 'output' directory so result files are not made part of the measure
+ return "#{__dir__}/output/#{test_name}"
+ end
+
+ def model_output_path(test_name)
+ return "#{run_dir(test_name)}/out.osm"
+ end
+
+ def sql_path(test_name)
+ return "#{run_dir(test_name)}/run/eplusout.sql"
+ end
+
+ def report_path(test_name)
+ return "#{run_dir(test_name)}/reports/eplustbl.html"
+ end
+
+ # applies the measure and then runs the model
+ def run_nze_hvac_measure_test(test_name, osm_path, epw_path,
+ hvac_system_type_input: 'DOAS with fan coil chiller with central air source heat pump',
+ doas_dcv_input: false,
+ hvac_system_partition_input: 'Whole Building',
+ max_unmet_hrs: 550)
+ assert(File.exist?(osm_path))
+ assert(File.exist?(epw_path))
+
+ # remove prior runs if they exist
+ FileUtils.rm_f(model_output_path(test_name))
+ FileUtils.rm_f(sql_path(test_name))
+ FileUtils.rm_f(report_path(test_name))
+
+ # create run directory if it does not exist
+ FileUtils.mkdir_p(run_dir(test_name))
+
+ # temporarily change directory to the run directory and run the measure
+ # only necessary for measures that do a sizing run
+ start_dir = Dir.pwd
+ begin
+ Dir.chdir run_dir(test_name)
+
+ # create an instance of the measure
+ measure = NzeHvac.new
+
+ # create an instance of a runner
+ runner = OpenStudio::Measure::OSRunner.new(OpenStudio::WorkflowJSON.new)
+
+ # load the test model
+ translator = OpenStudio::OSVersion::VersionTranslator.new
+ model = translator.loadModel(OpenStudio::Path.new(osm_path))
+ assert(!model.empty?)
+ model = model.get
+
+ # set model weather file
+ epw_file = OpenStudio::EpwFile.new(OpenStudio::Path.new(epw_path))
+ OpenStudio::Model::WeatherFile.setWeatherFile(model, epw_file)
+ assert(model.weatherFile.is_initialized)
+
+ # set arguments to good values
+ arguments = measure.arguments(model)
+ argument_map = OpenStudio::Measure::OSArgumentMap.new
+
+ remove_existing_hvac = arguments[0].clone
+ assert(remove_existing_hvac.setValue(true))
+ argument_map['remove_existing_hvac'] = remove_existing_hvac
+
+ hvac_system_type = arguments[1].clone
+ assert(hvac_system_type.setValue(hvac_system_type_input))
+ argument_map['hvac_system_type'] = hvac_system_type
+
+ doas_dcv = arguments[2].clone
+ assert(doas_dcv.setValue(doas_dcv_input))
+ argument_map['doas_dcv'] = doas_dcv
+
+ hvac_system_partition = arguments[3].clone
+ assert(hvac_system_partition.setValue(hvac_system_partition_input))
+ argument_map['hvac_system_partition'] = hvac_system_partition
+
+ # run the measure
+ puts '\nAPPLYING MEASURE...'
+ measure.run(model, runner, argument_map)
+ result = runner.result
+
+ # assert that it ran correctly
+ assert(result.value.valueName == 'Success')
+ assert(result.warnings.empty?)
+
+ # show the output
+ show_output(result)
+
+ # save model
+ model.save(model_output_path(test_name), true)
+
+ # run the model
+ if result.value.valueName == 'Success'
+ std = Standard.build('90.1-2013')
+ puts '\nRUNNING MODEL...'
+
+ std.model_run_simulation_and_log_errors(model, run_dir(test_name))
+
+ # check that the model ran successfully
+ assert(File.exist?(sql_path(test_name)))
+ end
+
+ # check that the model ran successfully and generated a report
+ assert(File.exist?(model_output_path(test_name)))
+ assert(File.exist?(sql_path(test_name)))
+ assert(File.exist?(report_path(test_name)))
+
+ # set runner variables
+ runner.setLastEpwFilePath(epw_path)
+ runner.setLastOpenStudioModelPath(OpenStudio::Path.new(model_output_path(test_name)))
+ runner.setLastEnergyPlusSqlFilePath(OpenStudio::Path.new(sql_path(test_name)))
+
+ if !runner.lastEnergyPlusSqlFile.empty?
+ sql = runner.lastEnergyPlusSqlFile.get
+ model.setSqlFile(sql)
+
+ # test for unmet hours
+ errs = []
+ unmet_heating_hrs = OpenstudioStandards::SqlFile.model_get_annual_occupied_unmet_heating_hours(model)
+ unmet_cooling_hrs = OpenstudioStandards::SqlFile.model_get_annual_occupied_unmet_cooling_hours(model)
+ unmet_hrs = OpenstudioStandards::SqlFile.model_get_annual_occupied_unmet_hours(model)
+ if unmet_hrs
+ if unmet_hrs > max_unmet_hrs
+ errs << "For #{test_name} there were #{unmet_heating_hrs.round(1)} unmet occupied heating hours and #{unmet_cooling_hrs.round(1)} unmet occupied cooling hours (total: #{unmet_hrs.round(1)}), more than the limit of #{max_unmet_hrs}." if unmet_hrs > max_unmet_hrs
+ else
+ puts "There were #{unmet_heating_hrs.round(1)} unmet occupied heating hours and #{unmet_cooling_hrs.round(1)} unmet occupied cooling hours (total: #{unmet_hrs.round(1)})."
+ end
+ else
+ errs << "For #{test_name} could not determine unmet hours; simulation may have failed."
+ end
+
+ # calculate EUIs to determine if HVAC EUI is appropriate
+ annual_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2(model)
+ int_lighting_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Interior Lighting').round(1)
+ ext_lighting_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Exterior Lighting').round(1)
+ int_equipment_elec_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Interior Equipment').round(1)
+ int_equipment_gas_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Natural Gas', 'Interior Equipment').round(1)
+ int_equipment_eui = (int_equipment_elec_eui + int_equipment_gas_eui).round(1)
+ refrigeration_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Refrigeration').round(1)
+ shw_elec_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Water Systems').round(1)
+ shw_gas_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Natural Gas', 'Water Systems').round(1)
+ shw_eui = (shw_elec_eui + shw_gas_eui).round(1)
+ fan_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Fans').round(1)
+ pump_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Pumps').round(1)
+ cooling_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Cooling').round(1)
+ heating_elec_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Electricity', 'Heating').round(1)
+ heating_gas_eui = OpenstudioStandards::SqlFile.model_get_annual_eui_kbtu_per_ft2_by_fuel_and_enduse(model, 'Natural Gas', 'Heating').round(1)
+ heating_eui = (heating_elec_eui + heating_gas_eui).round(1)
+ hvac_eui = (fan_eui + pump_eui + cooling_eui + heating_eui).round(1)
+ puts "Annual EUI (kBtu/ft^2): #{annual_eui.round(1)}, split:"
+ puts "exterior lighting: #{ext_lighting_eui}"
+ puts "interior lighting: #{int_lighting_eui}"
+ puts "equipment: #{int_equipment_eui} (#{int_equipment_elec_eui} elec / #{int_equipment_gas_eui} gas)"
+ puts "refrigeration: #{refrigeration_eui}"
+ puts "service hot water: #{shw_eui} (#{shw_elec_eui} elec / #{shw_gas_eui} gas)"
+ puts "HVAC #{hvac_eui} (fans: #{fan_eui}, pumps: #{pump_eui}, cooling: #{cooling_eui}, heating: #{heating_eui} (#{heating_elec_eui} elec / #{heating_gas_eui} gas))"
+
+ # don't expect EUIs to be above 100 unless there are very high internal loads
+ if (annual_eui > 100) && ((int_equipment_eui + int_lighting_eui) < 70)
+ errs << "The annual eui is #{annual_eui.round(1)} kBtu/ft^2, higher than expected for an NZE building."
+ end
+
+ assert(errs.empty?, errs.join('\n'))
+ end
+ ensure
+ # change back directory
+ Dir.chdir(start_dir)
+ end
+ end
+
+ # #**** TESTS ****##
+ def test_number_of_arguments_and_argument_names
+ # this test ensures that the current test is matched to the measure inputs
+ puts "\n######\nTEST:#{__method__}\n######\n"
+
+ # create an instance of the measure
+ measure = NzeHvac.new
+
+ # empty model
+ model = OpenStudio::Model::Model.new
+
+ # get arguments and test that they are what we are expecting
+ arguments = measure.arguments(model)
+ assert_equal(4, arguments.size)
+ assert_equal('remove_existing_hvac', arguments[0].name)
+ assert_equal('hvac_system_type', arguments[1].name)
+ assert_equal('doas_dcv', arguments[2].name)
+ assert_equal('hvac_system_partition', arguments[3].name)
+ end
+
+ def test_primary_school_fancoils_doas
+ puts "\n######\nTEST:#{__method__}\n######\n"
+ osm_path = "#{__dir__}/primary_school_burlington.osm"
+ epw_path = "#{__dir__}/USA_VT_Burlington.Intl.AP.726170_TMY3.epw"
+ run_nze_hvac_measure_test(__method__, osm_path, epw_path,
+ hvac_system_type_input: 'DOAS with fan coil chiller with boiler',
+ hvac_system_partition_input: 'Whole Building')
+ end
+
+ def test_office_radiant_doas
+ puts "\n######\nTEST:#{__method__}\n######\n"
+ osm_path = "#{__dir__}/office_chicago_exp_tstat.osm"
+ epw_path = "#{__dir__}/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw"
+ run_nze_hvac_measure_test(__method__, osm_path, epw_path,
+ hvac_system_type_input: 'DOAS with radiant slab chiller with central air source heat pump',
+ hvac_system_partition_input: 'Whole Building',
+ max_unmet_hrs: 2500.0) # TODO: - lower back to 600 hours after address issue with this test in release after 2.9.0, reased from 650 to 675 foor 3.4
+ end
+
+ def test_office_doas_vrf_per_story
+ puts "\n######\nTEST:#{__method__}\n######\n"
+ osm_path = "#{__dir__}/office_chicago.osm"
+ epw_path = "#{__dir__}/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw"
+ run_nze_hvac_measure_test(__method__, osm_path, epw_path,
+ hvac_system_type_input: 'DOAS with VRF',
+ hvac_system_partition_input: 'One System Per Building Story')
+ end
+
+ def test_office_vav_reheat
+ puts "\n######\nTEST:#{__method__}\n######\n"
+ osm_path = "#{__dir__}/office_chicago.osm"
+ epw_path = "#{__dir__}/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw"
+ run_nze_hvac_measure_test(__method__, osm_path, epw_path,
+ hvac_system_type_input: 'VAV chiller with gas boiler reheat',
+ hvac_system_partition_input: 'Whole Building')
+ end
+
+ def test_office_pvav_reheat
+ puts "\n######\nTEST:#{__method__}\n######\n"
+ osm_path = "#{__dir__}/office_chicago.osm"
+ epw_path = "#{__dir__}/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw"
+ run_nze_hvac_measure_test(__method__, osm_path, epw_path,
+ hvac_system_type_input: 'PVAV with gas boiler reheat',
+ hvac_system_partition_input: 'Whole Building')
+ end
+
+ def test_mixed_use_vrf_doas
+ puts "\n######\nTEST:#{__method__}\n######\n"
+ osm_path = "#{__dir__}/office_retail_mix_chicago.osm"
+ epw_path = "#{__dir__}/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw"
+ run_nze_hvac_measure_test(__method__, osm_path, epw_path,
+ hvac_system_type_input: 'DOAS with VRF',
+ hvac_system_partition_input: 'One System Per Building Type',
+ max_unmet_hrs: 650.0)
+ end
+
+ def test_mixed_use_gshp_doas
+ puts "\n######\nTEST:#{__method__}\n######\n"
+ osm_path = "#{__dir__}/office_retail_mix_chicago.osm"
+ epw_path = "#{__dir__}/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw"
+ run_nze_hvac_measure_test(__method__, osm_path, epw_path,
+ hvac_system_type_input: 'DOAS with water source heat pumps with ground source heat pump',
+ hvac_system_partition_input: 'Whole Building')
+ end
+
+ # this tests adding a vav reheat system to the model with high envelope and internal loads
+ def test_model_with_sizing_issues
+ puts "\n######\nTEST:#{__method__}\n######\n"
+ osm_path = "#{__dir__}/glass_box_baltimore.osm"
+ epw_path = "#{__dir__}/USA_MD_Baltimore-Washington.Intl.AP.724060_TMY3.epw"
+ run_nze_hvac_measure_test(__method__, osm_path, epw_path,
+ hvac_system_type_input: 'VAV air-cooled chiller with central air source heat pump reheat',
+ hvac_system_partition_input: 'Whole Building')
+ end
+
+ def test_humid_office_fancoils_doas
+ puts "\n######\nTEST:#{__method__}\n######\n"
+ osm_path = "#{__dir__}/office_houston.osm"
+ epw_path = "#{__dir__}/USA_TX_Houston-Bush.Intercontinental.AP.722430_TMY3.epw"
+ run_nze_hvac_measure_test(__method__, osm_path, epw_path,
+ hvac_system_type_input: 'DOAS with fan coil air-cooled chiller with central air source heat pump',
+ hvac_system_partition_input: 'Whole Building')
+ end
+
+ def test_humid_office_doas_fancoils_dcv
+ puts "\n######\nTEST:#{__method__}\n######\n"
+ osm_path = "#{__dir__}/office_houston.osm"
+ epw_path = "#{__dir__}/USA_TX_Houston-Bush.Intercontinental.AP.722430_TMY3.epw"
+ run_nze_hvac_measure_test(__method__, osm_path, epw_path,
+ hvac_system_type_input: 'DOAS with fan coil air-cooled chiller with central air source heat pump',
+ doas_dcv_input: true,
+ hvac_system_partition_input: 'Whole Building')
+ end
+
+ def test_humid_office_fancoils_doas_auto_partition
+ puts "\n######\nTEST:#{__method__}\n######\n"
+ osm_path = "#{__dir__}/office_houston.osm"
+ epw_path = "#{__dir__}/USA_TX_Houston-Bush.Intercontinental.AP.722430_TMY3.epw"
+ run_nze_hvac_measure_test(__method__, osm_path, epw_path,
+ hvac_system_type_input: 'DOAS with fan coil chiller with central air source heat pump',
+ hvac_system_partition_input: 'Automatic Partition')
+ end
+
+ def test_humid_office_vav_reheat_auto_partition
+ puts "\n######\nTEST:#{__method__}\n######\n"
+ osm_path = "#{__dir__}/office_houston.osm"
+ epw_path = "#{__dir__}/USA_TX_Houston-Bush.Intercontinental.AP.722430_TMY3.epw"
+ run_nze_hvac_measure_test(__method__, osm_path, epw_path,
+ hvac_system_type_input: 'VAV chiller with central air source heat pump reheat',
+ hvac_system_partition_input: 'Automatic Partition')
+ end
+end