From dded0190dc46d4ff6ce08a02285b6113916f61c5 Mon Sep 17 00:00:00 2001 From: Eric Ringold Date: Wed, 6 Mar 2024 12:27:39 -0700 Subject: [PATCH 1/9] change_building_location test fixes --- .../tests/change_building_location_test.rb | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/resources/measures/ChangeBuildingLocation/tests/change_building_location_test.rb b/resources/measures/ChangeBuildingLocation/tests/change_building_location_test.rb index 92f0bfd98..aa218de97 100644 --- a/resources/measures/ChangeBuildingLocation/tests/change_building_location_test.rb +++ b/resources/measures/ChangeBuildingLocation/tests/change_building_location_test.rb @@ -135,38 +135,43 @@ def apply_measure_to_model(test_name, args, model_name = nil, result_value = 'Su def test_weather_file args = {} + args['year'] = '2018' args['weather_file_name'] = 'USA_MA_Boston-Logan.Intl.AP.725090_TMY3.epw' # seems to search directory of OSW even with empty file_paths - args['climate_zone'] = 'ASHRAE 169-2013-5A' - apply_measure_to_model(__method__.to_s.gsub('test_', ''), args, 'test.osm', nil, nil, nil) + args['climate_zone'] = 'ASHRAE 169-2013-5A' + apply_measure_to_model(__method__.to_s.gsub('test_', ''), args, 'test.osm', nil, nil, nil, 3) end def test_weather_file_WA_Renton args = {} + args['year'] = '2018' args['weather_file_name'] = 'USA_WA_Renton.Muni.AP.727934_TMY3.epw' # seems to search directory of OSW even with empty file_paths - args['climate_zone'] = 'ASHRAE 169-2013-4C' + args['climate_zone'] = 'ASHRAE 169-2013-4C' args['set_year'] = 2012 apply_measure_to_model(__method__.to_s.gsub('test_', ''), args, 'test.osm', nil, 2, nil, 0) end def test_multiyear_weather_file args = {} + args['year'] = '2018' args['weather_file_name'] = 'multiyear.epw' # seems to search directory of OSW even with empty file_paths - args['climate_zone'] = 'ASHRAE 169-2013-4C' - apply_measure_to_model(__method__.to_s.gsub('test_', ''), args, 'test.osm', nil, nil, nil) + args['climate_zone'] = 'ASHRAE 169-2013-4C' + apply_measure_to_model(__method__.to_s.gsub('test_', ''), args, 'test.osm', nil, nil, nil, 3) end def test_weather_file_bad args = {} + args['year'] = '2018' args['weather_file_name'] = 'BadFileName.epw' # seems to search directory of OSW even with empty file_paths - args['climate_zone'] = 'ASHRAE 169-2013-5A' + args['climate_zone'] = 'ASHRAE 169-2013-5A' apply_measure_to_model(__method__.to_s.gsub('test_', ''), args, 'test.osm', 'Fail', nil, nil) end def test_weather_file_monthly_design_days args = {} + args['year'] = '2018' args['weather_file_name'] = 'CA_LOS-ANGELES-IAP_722950S_12.epw' # seems to search directory of OSW even with empty file_paths - args['climate_zone'] = 'T24-CEC8' - apply_measure_to_model(__method__.to_s.gsub('test_', ''), args, 'test.osm', nil, nil, nil, 14) + args['climate_zone'] = 'T24-CEC8' + apply_measure_to_model(__method__.to_s.gsub('test_', ''), args, 'test.osm', nil, nil, nil, 6) end def test_soil_conductivity @@ -176,7 +181,7 @@ def test_soil_conductivity args['year'] = '2018' args['soil_conductivity'] = 1.8 test_name = __method__.to_s.gsub('test_', '') - apply_measure_to_model(test_name, args, 'test.osm', nil, nil, nil, 14) + apply_measure_to_model(test_name, args, 'test.osm', nil, nil, nil, 6) # load the test model model_path = File.dirname(__FILE__) + "/output/#{test_name}_test_output.osm" From dc684fd6d2c873dfd0d94edd99dd5feb7a590bf5 Mon Sep 17 00:00:00 2001 From: Eric Ringold Date: Wed, 6 Mar 2024 13:35:53 -0700 Subject: [PATCH 2/9] fix EnvRoofInsulAedgTest --- .../tests/env_roof_insul_aedg_test.rb | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/resources/measures/upgrade_env_roof_insul_aedg/tests/env_roof_insul_aedg_test.rb b/resources/measures/upgrade_env_roof_insul_aedg/tests/env_roof_insul_aedg_test.rb index e1f383a98..37b290319 100644 --- a/resources/measures/upgrade_env_roof_insul_aedg/tests/env_roof_insul_aedg_test.rb +++ b/resources/measures/upgrade_env_roof_insul_aedg/tests/env_roof_insul_aedg_test.rb @@ -63,9 +63,7 @@ def test_number_of_arguments_and_argument_names # get arguments and test that they are what we are expecting arguments = measure.arguments(model) - assert_equal(2, arguments.size) - assert_equal('r_val', arguments[0].name) - assert_equal('allow_reduct', arguments[1].name) + assert_equal(0, arguments.size) end # return file paths to test models in test directory @@ -177,9 +175,9 @@ def apply_measure_and_run(test_name, measure, argument_map, osm_path, epw_path, # create an array of hashes with model name, weather, and expected result def models_to_test test_sets = [] - test_sets << { model: 'Warehouse_5A', weather: 'MI_DETROIT_725375_12', result: 'Success' } - test_sets << { model: 'Retail_7', weather: 'MN_Cloquet_Carlton_Co_726558_16', result: 'Success' } - test_sets << { model: 'Small_Office_2A', weather: 'TX_Port_Arthur_Jeffers_722410_16', result: 'Success' } + test_sets << { model: 'Warehouse_5A', weather: 'MI_DETROIT_725375_12', result: 'Success', new_r: 33 } + test_sets << { model: 'Retail_7', weather: 'MN_Cloquet_Carlton_Co_726558_16', result: 'Success', new_r: 37} + test_sets << { model: 'Small_Office_2A', weather: 'TX_Port_Arthur_Jeffers_722410_16', result: 'Success', new_r: 26} return test_sets end @@ -216,15 +214,15 @@ def test_doe_models end ################ END CUSTOMIZE ######################### - # set R-value argument - r_val = arguments[0].clone - assert(r_val.setValue(30.0)) - argument_map['r_val'] = r_val + # # set R-value argument + # r_val = arguments[0].clone + # assert(r_val.setValue(30.0)) + # argument_map['r_val'] = r_val - # set allow reduction argument - allow_reduct = arguments[1].clone - assert(allow_reduct.setValue(false)) - argument_map['allow_reduct'] = allow_reduct + # # set allow reduction argument + # allow_reduct = arguments[1].clone + # assert(allow_reduct.setValue(false)) + # argument_map['allow_reduct'] = allow_reduct # apply the measure to the model and optionally run the model result = apply_measure_and_run(instance_test_name, measure, argument_map, osm_path, epw_path, run_model: false) @@ -237,7 +235,7 @@ def test_doe_models new_r_val_si = 1 / surface.thermalConductance.to_f new_r_val_ip = OpenStudio.convert(new_r_val_si, 'm^2*K/W', 'ft^2*h*R/Btu').get assert(old_r_val_ip < new_r_val_ip) - assert((new_r_val_ip - 30).abs < 0.6) + assert((new_r_val_ip - set[:new_r]).abs < 0.6) end ################ END CUSTOMIZE ######################### end From 2232069f092c5e289698eec9d67839d1035f3d49 Mon Sep 17 00:00:00 2001 From: Eric Ringold Date: Wed, 6 Mar 2024 13:36:23 -0700 Subject: [PATCH 3/9] clean up EnvRoofInsulAedg --- .../upgrade_env_roof_insul_aedg/measure.rb | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/resources/measures/upgrade_env_roof_insul_aedg/measure.rb b/resources/measures/upgrade_env_roof_insul_aedg/measure.rb index ec0c2f211..a93036b71 100644 --- a/resources/measures/upgrade_env_roof_insul_aedg/measure.rb +++ b/resources/measures/upgrade_env_roof_insul_aedg/measure.rb @@ -40,41 +40,41 @@ require 'openstudio-standards' # start the measure -class EnvRoofInsulAedg < OpenStudio::Measure::ModelMeasure +class EnvRoofInsulAedg < OpenStudio::Measure::ModelMeasure # human readable name - def name - return "Roof Insulation AEDG" + def name + return "Roof Insulation AEDG" end # human readable description - def description - return "Roof Insulation is defined as sky facing horizontal surfaces, or surfaces sloped within 60 degrees of sky facing horizontal" + def description + return "Roof Insulation is defined as sky facing horizontal surfaces, or surfaces sloped within 60 degrees of sky facing horizontal" end # human readable description of modeling approach def modeler_description return 'Determine the thickness of extruded polystyrene insulation required to meet the specified R-value, determined from the AEDG target assembly performance for each climate zone. Find all the constructions used by roofs in the model, clone them, add a layer of insulation to the cloned constructions, and then assign the construction back to the roof.' end - + # define the arguments that the user will input for the model - def arguments(model) - args = OpenStudio::Measure::OSArgumentVector.new + def arguments(model) + args = OpenStudio::Measure::OSArgumentVector.new - return args - end + return args + end # define what happens when the measure is run - def run(model, runner, user_arguments) - super(model, runner, user_arguments) + def run(model, runner, user_arguments) + super(model, runner, user_arguments) - # use the built-in error checking - if !runner.validateUserArguments(arguments(model), user_arguments) + # use the built-in error checking + if !runner.validateUserArguments(arguments(model), user_arguments) return false end # set limit for minimum insulation in IP units -- this is used to limit input and for inferring insulation layer in construction min_exp_r_val_ip = 1.0 - + # build standard to use OS standards methods template = 'ComStock 90.1-2019' std = Standard.build(template) @@ -92,7 +92,7 @@ def run(model, runner, user_arguments) target_r_val_ip = 37 else # all DEER climate zones except 15 and 16 target_r_val_ip = 26 - end + end # Convert target_r_val_ip to si target_r_val_si = OpenStudio.convert(target_r_val_ip, 'ft^2*h*R/Btu', 'm^2*K/W').get @@ -110,39 +110,39 @@ def run(model, runner, user_arguments) end # create an array of roofs and find range of starting construction R-value (not just insulation layer) - ext_surfs = [] - ext_surf_consts = [] - ext_surf_const_names = [] - roof_resist = [] - model.getSurfaces.each do |surface| + ext_surfs = [] + ext_surf_consts = [] + ext_surf_const_names = [] + roof_resist = [] + model.getSurfaces.each do |surface| next unless (surface.outsideBoundaryCondition == 'Outdoors') && (surface.surfaceType == 'RoofCeiling') #which are outdoor roofs - ext_surfs << surface - roof_const = surface.construction.get + ext_surfs << surface + roof_const = surface.construction.get # only add construction if it hasn't been added yet - ext_surf_consts << roof_const.to_Construction.get unless ext_surf_const_names.include?(roof_const.name.to_s) - ext_surf_const_names << roof_const.name.to_s - roof_resist << 1 / roof_const.thermalConductance.to_f + ext_surf_consts << roof_const.to_Construction.get unless ext_surf_const_names.include?(roof_const.name.to_s) + ext_surf_const_names << roof_const.name.to_s + roof_resist << 1 / roof_const.thermalConductance.to_f end # hashes to track constructions and materials made by the measure, to avoid duplicates - consts_old_new = {} + consts_old_new = {} # used to get net area of new construction - consts_new_old = {} - matls_hash = {} + consts_new_old = {} + matls_hash = {} # array and counter for new constructions that are made, used for reporting final condition - final_consts = [] + final_consts = [] # loop through all constructions and materials used on roofs, edit and clone - ext_surf_consts.each do |ext_surf_const| + ext_surf_consts.each do |ext_surf_const| matls_in_const = ext_surf_const.layers.map.with_index { |l, i| { 'name' => l.name.to_s, 'index' => i, 'nomass' => !l.to_MasslessOpaqueMaterial.empty?, 'r_val' => l.to_OpaqueMaterial.get.thermalResistance, 'matl' => l } } - no_mass_matls = matls_in_const.select { |m| m['nomass'] == true } + no_mass_matls = matls_in_const.select { |m| m['nomass'] == true } # measure will select the no-mass material with the highest R-value as the insulation layer -- if no no-mass materials are present, the measure will select the material with the highest R-value per inch - if !no_mass_matls.empty? + if !no_mass_matls.empty? r_vals = no_mass_matls.map { |m| m['r_val'] } # - max_matl_hash = no_mass_matls.select { |m| m['r_val'] >= r_vals.max } + max_matl_hash = no_mass_matls.select { |m| m['r_val'] >= r_vals.max } else r_val_per_thick_vals = matls_in_const.map { |m| m['r_val'] / m['mat'].thickness } max_matl_hash = matls_in_const.select { |m| m['index'] == r_val_per_thick_vals.index(r_val_per_thick_vals.max) } @@ -153,7 +153,7 @@ def run(model, runner, user_arguments) # check to make sure assumed insulation layer is between reasonable bounds if max_r_val_matl.to_OpaqueMaterial.get.thermalResistance <= OpenStudio.convert(min_exp_r_val_ip, 'ft^2*h*R/Btu', 'm^2*K/W').get runner.registerWarning("Construction '#{ext_surf_const.name}' does not appear to have an insulation layer and was not altered") - elsif (max_r_val_matl.to_OpaqueMaterial.get.thermalResistance >= target_r_val_si) + elsif (max_r_val_matl.to_OpaqueMaterial.get.thermalResistance >= target_r_val_si) runner.registerInfo("The insulation layer of construction #{ext_surf_const.name} exceeds the requested R-value and was not altered") else @@ -170,7 +170,7 @@ def run(model, runner, user_arguments) # clone the construction final_const = ext_surf_const.clone(model).to_Construction.get # get r-value - final_const_r_si = 1 / final_const.thermalConductance.to_f + final_const_r_si = 1 / final_const.thermalConductance.to_f final_const_r_ip = OpenStudio.convert(final_const_r_si, 'm^2*K/W' , 'ft^2*h*R/Btu').get # determine required r-value of XPS insulation to bring roof up to target xps_target_r_val_si = target_r_val_si - final_const_r_si @@ -210,7 +210,7 @@ def run(model, runner, user_arguments) end end - # register as not applicable if + # register as not applicable if if final_consts.empty? runner.registerAsNotApplicable("No applicable roofs were found.") return true @@ -299,17 +299,17 @@ def run(model, runner, user_arguments) end # nothing will be done if there are no exterior surfaces - if ext_surfs.empty? - runner.registerAsNotApplicable('The building has no roofs.') - return true - end + if ext_surfs.empty? + runner.registerAsNotApplicable('The building has no roofs.') + return true + end # report strings for initial condition - init_str = [] - ext_surf_consts.uniq.each do |ext_surf_const| + init_str = [] + ext_surf_consts.uniq.each do |ext_surf_const| # unit conversion of roof insulation from SI units (m2-K/W) to IP units (ft2-h-R/Btu) init_r_val_ip = OpenStudio.convert(1 / ext_surf_const.thermalConductance.to_f, 'm^2*K/W', 'ft^2*h*R/Btu').get - init_str << "#{ext_surf_const.name} (R-#{(format '%.1f', init_r_val_ip)})" + init_str << "#{ext_surf_const.name} (R-#{(format '%.1f', init_r_val_ip)})" end # report strings for final condition, not all roof constructions, but only new ones made -- if roof didn't have insulation and was not altered we don't want to show it @@ -333,10 +333,10 @@ def run(model, runner, user_arguments) end # Report the initial condition - runner.registerInitialCondition("The building had #{init_str.size} roof constructions: #{init_str.sort.join(', ')}") + runner.registerInitialCondition("The building had #{init_str.size} roof constructions: #{init_str.sort.join(', ')}") # Report the final condition - runner.registerFinalCondition("The insulation for roofs was set to R-#{target_r_val_ip} -- this was applied to #{area_changed_ip.round(2)} ft2 across #{final_str.size} roof constructions: #{final_str.sort.join(', ')}") + runner.registerFinalCondition("The insulation for roofs was set to R-#{target_r_val_ip.round(1)} -- this was applied to #{area_changed_ip.round(2)} ft2 across #{final_str.size} roof constructions: #{final_str.sort.join(', ')}") runner.registerValue('env_roof_insul_roof_area_ft2', area_changed_ip.round(2), 'ft2') return true end From 4fce609cb01d881814f2531f4256d7331ed26063 Mon Sep 17 00:00:00 2001 From: Eric Ringold Date: Wed, 6 Mar 2024 13:49:34 -0700 Subject: [PATCH 4/9] remove EnvStormWindowsTest - measure not in comstock --- .../tests/env_new_aedg_windows_test.rb | 268 ------------------ test/resource_measure_tests.txt | 1 - 2 files changed, 269 deletions(-) delete mode 100644 resources/measures/upgrade_env_new_aedg_windows/tests/env_new_aedg_windows_test.rb diff --git a/resources/measures/upgrade_env_new_aedg_windows/tests/env_new_aedg_windows_test.rb b/resources/measures/upgrade_env_new_aedg_windows/tests/env_new_aedg_windows_test.rb deleted file mode 100644 index 5076b67dc..000000000 --- a/resources/measures/upgrade_env_new_aedg_windows/tests/env_new_aedg_windows_test.rb +++ /dev/null @@ -1,268 +0,0 @@ -# ComStockā„¢, Copyright (c) 2023 Alliance for Sustainable Energy, LLC. All rights reserved. -# See top level LICENSE.txt file for license terms. - -# ******************************************************************************* -# OpenStudio(R), Copyright (c) 2008-2018, Alliance for Sustainable Energy, LLC. -# All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# (1) Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# (2) Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# (3) Neither the name of the copyright holder nor the names of any contributors -# may be used to endorse or promote products derived from this software without -# specific prior written permission from the respective party. -# -# (4) Other than as required in clauses (1) and (2), distributions in any form -# of modifications or other derivative works may not use the "OpenStudio" -# trademark, "OS", "os", or any other confusingly similar designation without -# specific prior written permission from Alliance for Sustainable Energy, LLC. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE -# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF -# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ******************************************************************************* - -# dependencies -require 'openstudio' -require 'openstudio/measure/ShowRunnerOutput' -require 'fileutils' -require 'minitest/autorun' -require_relative '../../../../test/helpers/minitest_helper' -require_relative '../measure.rb' - -class EnvStormWindowsTest < Minitest::Test - # all tests are a sub definition of this class, e.g.: - # def test_new_kind_of_test - # test content - # end - - 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 = EnvStormWindows.new - - # make an empty model - model = OpenStudio::Model::Model.new - - # get arguments and test that they are what we are expecting - arguments = measure.arguments(model) - assert_equal(3, arguments.size) - assert_equal('single_pane_threshold_ip', arguments[0].name) - assert_equal('u_val_reduct_ip', arguments[1].name) - assert_equal('shgc_reduct', arguments[2].name) - assert_equal('vlt_reduct', arguments[3].name) - end - - # return file paths to test models in test directory - def models_for_tests - paths = Dir.glob(File.join(File.dirname(__FILE__), '../../../tests/models/*.osm')) - paths = paths.map { |path| File.expand_path(path) } - return paths - end - - # return file paths to epw files in test directory - def epws_for_tests - paths = Dir.glob(File.join(File.dirname(__FILE__), '../../../tests/weather/*.epw')) - paths = paths.map { |path| File.expand_path(path) } - return paths - end - - def load_model(osm_path) - translator = OpenStudio::OSVersion::VersionTranslator.new - model = translator.loadModel(OpenStudio::Path.new(osm_path)) - assert(!model.empty?) - model = model.get - return model - end - - 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 apply_measure_and_run(test_name, measure, argument_map, osm_path, epw_path, run_model: false) - 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) - - # 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 - - # copy the osm and epw to the test directory - new_osm_path = "#{run_dir(test_name)}/#{File.basename(osm_path)}" - FileUtils.cp(osm_path, new_osm_path) - new_epw_path = "#{run_dir(test_name)}/#{File.basename(epw_path)}" - FileUtils.cp(epw_path, new_epw_path) - # create an instance of a runner - runner = OpenStudio::Measure::OSRunner.new(OpenStudio::WorkflowJSON.new) - - # load the test model - model = load_model(new_osm_path) - - # set model weather file - epw_file = OpenStudio::EpwFile.new(OpenStudio::Path.new(new_epw_path)) - OpenStudio::Model::WeatherFile.setWeatherFile(model, epw_file) - assert(model.weatherFile.is_initialized) - - # run the measure - puts "\nAPPLYING MEASURE..." - measure.run(model, runner, argument_map) - result = runner.result - result_success = result.value.valueName == 'Success' - - # show the output - show_output(result) - - # save model - model.save(model_output_path(test_name), true) - - if run_model && result_success - puts "\nRUNNING MODEL..." - - std = Standard.build('90.1-2013') - 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 - - # change back directory - Dir.chdir(start_dir) - - return result - end - - # create an array of hashes with model name, weather, and expected result - def models_to_test - test_sets = [] - test_sets << { model: 'Warehouse_5A', weather: 'MI_DETROIT_725375_12', result: 'Success' } - test_sets << { model: 'Retail_7', weather: 'MN_Cloquet_Carlton_Co_726558_16', result: 'Success' } - test_sets << { model: 'Small_Office_2A', weather: 'TX_Port_Arthur_Jeffers_722410_16', result: 'Success' } - return test_sets - end - - def test_doe_models - test_name = 'test_doe_models' - puts "\n######\nTEST:#{test_name}\n######\n" - - models_to_test.each do |set| - instance_test_name = set[:model] - puts "instance test name: #{instance_test_name}" - osm_path = models_for_tests.select { |x| set[:model] == File.basename(x, '.osm') } - epw_path = epws_for_tests.select { |x| set[:weather] == File.basename(x, '.epw') } - assert(!osm_path.empty?) - assert(!epw_path.empty?) - osm_path = osm_path[0] - epw_path = epw_path[0] - - # create an instance of the measure - measure = EnvStormWindows.new - - # load the model; only used here for populating arguments - model = load_model(osm_path) - arguments = measure.arguments(model) - argument_map = OpenStudio::Measure::OSArgumentMap.new - - ############### BEGIN CUSTOMIZE ################## - old_u_val = nil - old_shgc = nil - old_vlt = nil - model.getSubSurfaces.each do |sub_surface| - if sub_surface.subSurfaceType.include?('Window') - old_simple_glazing_obj = sub_surface.construction.get.to_Construction.get.layers[0].to_SimpleGlazing.get - old_u_val = old_simple_glazing_obj.uFactor - old_shgc = old_simple_glazing_obj.solarHeatGainCoefficient - old_vlt = old_simple_glazing_obj.visibleTransmittance.get - end - end - ################ END CUSTOMIZE #################### - - # set arguments here; will vary by measure - # set u-value reduction argument - single_pane_threshold_ip = arguments[0].clone - assert(single_pane_threshold_ip.setValue(0.85)) - argument_map['single_pane_threshold_ip'] = single_pane_threshold_ip - - # set u-value reduction argument - u_val_reduct_ip = arguments[1].clone - assert(u_val_reduct_ip.setValue(0.69)) - argument_map['u_val_reduct_ip'] = u_val_reduct_ip - - # set SHGC reduction argument - shgc_reduct = arguments[2].clone - assert(shgc_reduct.setValue(0.57)) - argument_map['shgc_reduct'] = shgc_reduct - - # set VLT reduction argument - vlt_reduct = arguments[3].clone - assert(vlt_reduct.setValue(0.38)) - argument_map['vlt_reduct'] = vlt_reduct - - # apply the measure to the model and optionally run the model - result = apply_measure_and_run(instance_test_name, measure, argument_map, osm_path, epw_path, run_model: false) - - ############### BEGIN CUSTOMIZE ################## - model = load_model(model_output_path(instance_test_name)) - model.getSubSurfaces.each do |sub_surface| - if sub_surface.subSurfaceType.include?('Window') - new_simple_glazing_obj = sub_surface.construction.get.to_Construction.get.layers[0].to_SimpleGlazing.get - model_u_val = new_simple_glazing_obj.uFactor - model_shgc = new_simple_glazing_obj.solarHeatGainCoefficient - model_vlt = new_simple_glazing_obj.visibleTransmittance.get - u_val_reduct_si = 0.69 * 5.678 - expected_u_val = old_u_val - u_val_reduct_si - expected_shgc = old_shgc * (1 - 0.57) - expected_vlt = old_vlt * (1 - 0.38) - assert((expected_u_val - model_u_val).abs < 0.001) - assert((expected_shgc - model_shgc).abs < 0.001) - assert((expected_vlt - model_vlt).abs < 0.001) - end - end - ################ END CUSTOMIZE #################### - end - end -end diff --git a/test/resource_measure_tests.txt b/test/resource_measure_tests.txt index ded2de5f9..4a4b13ab3 100644 --- a/test/resource_measure_tests.txt +++ b/test/resource_measure_tests.txt @@ -2,7 +2,6 @@ resources/measures/upgrade_env_roof_insul_aedg/tests/env_roof_insul_aedg_test.rb resources/measures/set_exterior_lighting_template/tests/measure_test.rb resources/measures/set_wall_template/tests/measure_test.rb resources/measures/upgrade_env_new_aedg_windows/tests/measure_test.rb -resources/measures/upgrade_env_new_aedg_windows/tests/env_new_aedg_windows_test.rb resources/measures/create_bar_from_building_type_ratios/tests/create_bar_from_building_type_ratios_test.rb resources/measures/set_roof_template/tests/measure_test.rb resources/measures/upgrade_light_led/tests/light_led_test.rb From 3415bed2da09fc974237577e4590e8c930ab0500 Mon Sep 17 00:00:00 2001 From: Eric Ringold Date: Wed, 6 Mar 2024 13:58:41 -0700 Subject: [PATCH 5/9] changebuildinglocation xml --- resources/measures/ChangeBuildingLocation/measure.xml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/resources/measures/ChangeBuildingLocation/measure.xml b/resources/measures/ChangeBuildingLocation/measure.xml index 5d2f0f1b6..2368f7994 100644 --- a/resources/measures/ChangeBuildingLocation/measure.xml +++ b/resources/measures/ChangeBuildingLocation/measure.xml @@ -3,8 +3,8 @@ 3.1 change_building_location d4db4971-f5ba-11e3-a3ac-0800200c9a66 - b2127c2c-d32e-48c2-98e6-1974815395ca - 2024-01-26T03:26:16Z + 6fb0b369-c51c-4c06-ac43-db84efdd5632 + 2024-03-06T20:56:01Z 057E8D9D ChangeBuildingLocation ChangeBuildingLocation @@ -26,7 +26,6 @@ String true false - 2018 climate_zone @@ -335,7 +334,7 @@ measure.rb rb script - 680AE904 + ED117F7E epw.rb @@ -431,7 +430,7 @@ change_building_location_test.rb rb test - 290BBD22 + 2B466B1C multiyear.ddy From 44d9d325d0c6a4983d4611aadbac09b8a9011ce7 Mon Sep 17 00:00:00 2001 From: Eric Ringold Date: Wed, 6 Mar 2024 14:00:00 -0700 Subject: [PATCH 6/9] upgrade_env_roof_insul_aedg xml --- .../measures/upgrade_env_roof_insul_aedg/measure.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/measures/upgrade_env_roof_insul_aedg/measure.xml b/resources/measures/upgrade_env_roof_insul_aedg/measure.xml index 39997ec1a..9955ef358 100644 --- a/resources/measures/upgrade_env_roof_insul_aedg/measure.xml +++ b/resources/measures/upgrade_env_roof_insul_aedg/measure.xml @@ -3,8 +3,8 @@ 3.1 env_roof_insul_aedg 8afedac6-d5b8-4ee6-80d9-107c5cd77b0e - 3a7f4df0-2e78-4abb-8f1b-789cfcd12dab - 2023-10-16T20:24:46Z + b7893eaa-7f37-4346-926e-0004a55013c7 + 2024-03-06T20:59:10Z A465C8A5 EnvRoofInsulAedg Roof Insulation AEDG @@ -81,13 +81,13 @@ measure.rb rb script - 31905DA3 + 199D4B12 env_roof_insul_aedg_test.rb rb test - 8DEC6933 + E22EA670 From 5262cfa7fd2f375b81dbd9986bc8cbd7e62d847f Mon Sep 17 00:00:00 2001 From: Eric Ringold Date: Wed, 6 Mar 2024 14:01:13 -0700 Subject: [PATCH 7/9] upgrade_env_new_aedg_windows xml --- .../measures/upgrade_env_new_aedg_windows/measure.xml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/resources/measures/upgrade_env_new_aedg_windows/measure.xml b/resources/measures/upgrade_env_new_aedg_windows/measure.xml index fa1625cf9..4fa0ba700 100644 --- a/resources/measures/upgrade_env_new_aedg_windows/measure.xml +++ b/resources/measures/upgrade_env_new_aedg_windows/measure.xml @@ -3,8 +3,8 @@ 3.1 env_new_aedg_windows b0167804-5cb4-4641-b9de-961c640f02ea - ef420e4f-52d6-44ea-a526-174efcc1712b - 2023-10-16T20:24:51Z + 593deab0-8a25-4700-aee7-818aec1b8214 + 2024-03-06T21:00:41Z 4A8A93C6 EnvNewAedgWindows env_new_aedg_windows @@ -55,12 +55,6 @@ script 55EF9A96 - - env_new_aedg_windows_test.rb - rb - test - DA1FD041 - measure_test.rb rb From 5c8634dfce9bc4ec4e3051c7bb5dc63271f8f389 Mon Sep 17 00:00:00 2001 From: Eric Ringold Date: Wed, 6 Mar 2024 15:49:34 -0700 Subject: [PATCH 8/9] fix failing economizer test - run with existing test epw --- .../tests/hvac_economizer_test.rb | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/resources/measures/upgrade_hvac_economizer/tests/hvac_economizer_test.rb b/resources/measures/upgrade_hvac_economizer/tests/hvac_economizer_test.rb index 550c78337..c15508454 100644 --- a/resources/measures/upgrade_hvac_economizer/tests/hvac_economizer_test.rb +++ b/resources/measures/upgrade_hvac_economizer/tests/hvac_economizer_test.rb @@ -309,22 +309,22 @@ def run_simulation_and_get_timeseries(model, year, max_doy, num_timesteps_in_hr, unless availableReportingFrequencies.include?(reportingfrequency) raise "reportingfrequency of #{reportingfrequency} not included in available options: #{availableReportingFrequencies}" end - end + end # Check if timeseries name is available in sql timeseriesnames.each do |timeseriesname| - unless availableEnvPeriods.include?(envperiod) + unless availableEnvPeriods.include?(envperiod) raise "envperiod of #{envperiod} not included in available options: #{availableEnvPeriods}" end # puts("### DEBUGGING: availableTimeSeries = #{availableTimeSeries}") - unless availableTimeSeries.include?(timeseriesname) + unless availableTimeSeries.include?(timeseriesname) raise "timeseriesname of #{timeseriesname} not included in available options: #{availableTimeSeries}" end end # Extract timeseries data timeseries_results_combined = {} - + timeseriesnames.each do |timeseriesname| availableKeyValues = sqlFile.availableKeyValues(envperiod,reportingfrequency,timeseriesname).to_a @@ -336,7 +336,7 @@ def run_simulation_and_get_timeseries(model, year, max_doy, num_timesteps_in_hr, unless timeseries_results_combined.key?(key_value) timeseries_results_combined[key_value] = {} end - timeseries_result = sqlFile.timeSeries(envperiod,reportingfrequency,timeseriesname,key_value).get + timeseries_result = sqlFile.timeSeries(envperiod,reportingfrequency,timeseriesname,key_value).get vals = [] elec_vals = timeseries_result.values for i in 0..(elec_vals.size - 1) @@ -349,14 +349,14 @@ def run_simulation_and_get_timeseries(model, year, max_doy, num_timesteps_in_hr, timeseries_results_combined[key_value][timeseriesname] = vals end end - + return timeseries_results_combined end def models_to_test_final_oa_rates # suggestion: test all of these models locally but only include one model that can test quickly since the test requires simulation run. test_sets = [] - test_sets << { model: 'Outpatient_VAV_economizer_test', weather: 'G4201010', result: 'Success' } + test_sets << { model: 'Outpatient_VAV_economizer_test', weather: 'VA_MANASSAS_724036_12', result: 'Success' } return test_sets end @@ -364,7 +364,7 @@ def compare_arrays_with_tolerance(array1, array2, tolerance1, tolerance2) # raise if array sizes are different return false if array1.length != array2.length - + # Count values that violate tolerance 1 violations_count = array1.zip(array2).count { |a, b| (a - b).abs > (tolerance1 / 100.0) * a } @@ -373,7 +373,7 @@ def compare_arrays_with_tolerance(array1, array2, tolerance1, tolerance2) # puts row.join(', ') # end # puts("#################################################################") - + # Check if the ratio of violations to the total count is within tolerance 2 violations_ratio = violations_count.to_f / array1.length violation_final = violations_ratio > tolerance2 / 100.0 @@ -401,8 +401,8 @@ def test_final_oa_rates puts "instance test name: #{instance_test_name}" osm_path = models_for_tests.select { |x| set[:model] == File.basename(x, '.osm') } epw_path = epws_for_tests.select { |x| set[:weather] == File.basename(x, '.epw') } - assert(!osm_path.empty?) - assert(!epw_path.empty?) + assert(!osm_path.empty?, "Could not find osm file at #{osm_path}") + assert(!epw_path.empty?, "Could not find epw file at #{epw_path}") osm_path = osm_path[0] epw_path = epw_path[0] @@ -439,7 +439,7 @@ def test_final_oa_rates economizer_count_before = economizer_available(model) # Run simulation prior to measure application - puts("### DEBUGGING: first simulation prior to measure application") + puts("### DEBUGGING: first simulation prior to measure application") timeseries_results_combined_before = run_simulation_and_get_timeseries(model, 2016, number_of_days_to_test, number_of_timesteps_in_an_hr_test, timeseriesnames, epw_path=epw_path, run_dir = run_dir(instance_test_name)+'/beforemeasure') timeseries_results_combined['before'] = timeseries_results_combined_before @@ -617,7 +617,7 @@ def test_models # Apply the measure to the model and optionally run the model result = apply_measure_and_run(instance_test_name, measure, argument_map, osm_path, epw_path, run_model: false) - + # check the measure result; result values will equal Success, Fail, or Not Applicable # also check the amount of warnings, info, and error messages # use if or case statements to change expected assertion depending on model characteristics From acf115980ef53ca8f705cf21cce85f2ec8a79436 Mon Sep 17 00:00:00 2001 From: Eric Ringold Date: Wed, 6 Mar 2024 15:50:13 -0700 Subject: [PATCH 9/9] update economizer measure xml --- resources/measures/upgrade_hvac_economizer/measure.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/measures/upgrade_hvac_economizer/measure.xml b/resources/measures/upgrade_hvac_economizer/measure.xml index 00d1a08cd..2601b88e1 100644 --- a/resources/measures/upgrade_hvac_economizer/measure.xml +++ b/resources/measures/upgrade_hvac_economizer/measure.xml @@ -3,8 +3,8 @@ 3.1 hvac_economizer 8781f87a-daa2-4712-a567-6206a340efa7 - dd86969d-f482-4111-9658-1e75a9dfc0e2 - 2024-02-12T16:38:35Z + 587784e4-6557-4bc7-b7da-9041f19ec7f2 + 2024-03-06T22:49:48Z 356BE47F HVACEconomizer HVACEconomizer @@ -60,13 +60,13 @@ measure.rb rb script - 1F8A19C4 + D801FE86 hvac_economizer_test.rb rb test - 6DDABDB9 + 16F5DCC3