diff --git a/Rakefile b/Rakefile index 10f9edc..8282834 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # ******************************************************************************* # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC. # All rights reserved. diff --git a/lib/measures/AddOverhangsByProjectionFactor/tests/AddOverhangsByProjectionFactor_Test.rb b/lib/measures/AddOverhangsByProjectionFactor/tests/AddOverhangsByProjectionFactor_Test.rb index c8d2952..213c7a5 100644 --- a/lib/measures/AddOverhangsByProjectionFactor/tests/AddOverhangsByProjectionFactor_Test.rb +++ b/lib/measures/AddOverhangsByProjectionFactor/tests/AddOverhangsByProjectionFactor_Test.rb @@ -92,7 +92,7 @@ def test_AddOverhangsByProjectionFactor_good model = model.get model.getSpaces.each do |space| - if space.name.get =~ Regexp.new(/Space 104/) + if space.name.get.match?(Regexp.new(/Space 104/)) # should be two space shading groups assert_equal(2, space.shadingSurfaceGroups.size) else diff --git a/lib/measures/ImproveFanTotalEfficiencybyPercentage/measure.rb b/lib/measures/ImproveFanTotalEfficiencybyPercentage/measure.rb index be27e3b..b08e1ea 100644 --- a/lib/measures/ImproveFanTotalEfficiencybyPercentage/measure.rb +++ b/lib/measures/ImproveFanTotalEfficiencybyPercentage/measure.rb @@ -1,215 +1,215 @@ -#start the measure -class ImproveFanTotalEfficiencybyPercentage < OpenStudio::Ruleset::ModelUserScript +# frozen_string_literal: true - #define the name that a user will see, this method may be deprecated as - #the display name in PAT comes from the name field in measure.xml +# start the measure +class ImproveFanTotalEfficiencybyPercentage < OpenStudio::Ruleset::ModelUserScript + # define the name that a user will see, this method may be deprecated as + # the display name in PAT comes from the name field in measure.xml def name - return "Improve Fan Total Efficiency by Percentage" + return 'Improve Fan Total Efficiency by Percentage' end - #define the arguments that the user will input + # define the arguments that the user will input def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new - #populate choice argument for constructions that are applied to surfaces in the model + # populate choice argument for constructions that are applied to surfaces in the model loop_handles = OpenStudio::StringVector.new loop_display_names = OpenStudio::StringVector.new - #putting air loops and names into hash + # putting air loops and names into hash loop_args = model.getAirLoopHVACs loop_args_hash = {} loop_args.each do |loop_arg| loop_args_hash[loop_arg.name.to_s] = loop_arg end - #looping through sorted hash of air loops - loop_args_hash.sort.map do |key,value| + # looping through sorted hash of air loops + loop_args_hash.sort.map do |key, value| show_loop = false components = value.supplyComponents components.each do |component| - if not component.to_FanConstantVolume.empty? + if !component.to_FanConstantVolume.empty? show_loop = true end - if not component.to_FanVariableVolume.empty? + if !component.to_FanVariableVolume.empty? show_loop = true end - if not component.to_FanOnOff.empty? + if !component.to_FanOnOff.empty? show_loop = true end end - #if loop as object of correct type then add to hash. + # if loop as object of correct type then add to hash. if show_loop == true loop_handles << value.handle.to_s loop_display_names << key end end - #add building to string vector with air loops + # add building to string vector with air loops building = model.getBuilding loop_handles << building.handle.to_s - loop_display_names << "*All Air Loops*" + loop_display_names << '*All Air Loops*' - #make an argument for air loops - object = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("object", loop_handles, loop_display_names,true) - object.setDisplayName("Choose an Air Loop to Alter.") - object.setDefaultValue("*All Air Loops*") #if no loop is chosen this will run on all air loops + # make an argument for air loops + object = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('object', loop_handles, loop_display_names, true) + object.setDisplayName('Choose an Air Loop to Alter.') + object.setDefaultValue('*All Air Loops*') # if no loop is chosen this will run on all air loops args << object - #todo - change this to choice list from design document - #make an argument to add new space true/false - motor_eff = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("motor_eff",true) - motor_eff.setDisplayName("Fan Total Efficiency Improvement(%).") + # TODO: - change this to choice list from design document + # make an argument to add new space true/false + motor_eff = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('motor_eff', true) + motor_eff.setDisplayName('Fan Total Efficiency Improvement(%).') motor_eff.setDefaultValue(3.0) args << motor_eff - #bool argument to remove existing costs - remove_costs = OpenStudio::Ruleset::OSArgument::makeBoolArgument("remove_costs",true) - remove_costs.setDisplayName("Remove Baseline Costs From Effected Fans?") + # bool argument to remove existing costs + remove_costs = OpenStudio::Ruleset::OSArgument.makeBoolArgument('remove_costs', true) + remove_costs.setDisplayName('Remove Baseline Costs From Effected Fans?') remove_costs.setDefaultValue(false) args << remove_costs - #make an argument for material and installation cost - material_cost = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("material_cost",true) - material_cost.setDisplayName("Material and Installation Costs per Motor ($).") + # make an argument for material and installation cost + material_cost = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('material_cost', true) + material_cost.setDisplayName('Material and Installation Costs per Motor ($).') material_cost.setDefaultValue(0.0) args << material_cost - #make an argument for demolition cost - demolition_cost = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("demolition_cost",true) - demolition_cost.setDisplayName("Demolition Costs per Motor ($).") + # make an argument for demolition cost + demolition_cost = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('demolition_cost', true) + demolition_cost.setDisplayName('Demolition Costs per Motor ($).') demolition_cost.setDefaultValue(0.0) args << demolition_cost - #make an argument for duration in years until costs start - years_until_costs_start = OpenStudio::Ruleset::OSArgument::makeIntegerArgument("years_until_costs_start",true) - years_until_costs_start.setDisplayName("Years Until Costs Start (whole years).") + # make an argument for duration in years until costs start + years_until_costs_start = OpenStudio::Ruleset::OSArgument.makeIntegerArgument('years_until_costs_start', true) + years_until_costs_start.setDisplayName('Years Until Costs Start (whole years).') years_until_costs_start.setDefaultValue(0) args << years_until_costs_start - #make an argument to determine if demolition costs should be included in initial construction - demo_cost_initial_const = OpenStudio::Ruleset::OSArgument::makeBoolArgument("demo_cost_initial_const",true) - demo_cost_initial_const.setDisplayName("Demolition Costs Occur During Initial Construction?") + # make an argument to determine if demolition costs should be included in initial construction + demo_cost_initial_const = OpenStudio::Ruleset::OSArgument.makeBoolArgument('demo_cost_initial_const', true) + demo_cost_initial_const.setDisplayName('Demolition Costs Occur During Initial Construction?') demo_cost_initial_const.setDefaultValue(false) args << demo_cost_initial_const - #make an argument for expected life - expected_life = OpenStudio::Ruleset::OSArgument::makeIntegerArgument("expected_life",true) - expected_life.setDisplayName("Expected Life (whole years).") + # make an argument for expected life + expected_life = OpenStudio::Ruleset::OSArgument.makeIntegerArgument('expected_life', true) + expected_life.setDisplayName('Expected Life (whole years).') expected_life.setDefaultValue(20) args << expected_life - #make an argument for o&m cost - om_cost = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("om_cost",true) - om_cost.setDisplayName("O & M Costs per Motor ($).") + # make an argument for o&m cost + om_cost = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('om_cost', true) + om_cost.setDisplayName('O & M Costs per Motor ($).') om_cost.setDefaultValue(0.0) args << om_cost - #make an argument for o&m frequency - om_frequency = OpenStudio::Ruleset::OSArgument::makeIntegerArgument("om_frequency",true) - om_frequency.setDisplayName("O & M Frequency (whole years).") + # make an argument for o&m frequency + om_frequency = OpenStudio::Ruleset::OSArgument.makeIntegerArgument('om_frequency', true) + om_frequency.setDisplayName('O & M Frequency (whole years).') om_frequency.setDefaultValue(1) args << om_frequency return args - end #end the arguments method + end # end the arguments method - #define what happens when the measure is cop + # define what happens when the measure is cop def run(model, runner, user_arguments) super(model, runner, user_arguments) - #use the built-in error checking - if not runner.validateUserArguments(arguments(model), user_arguments) + # use the built-in error checking + if !runner.validateUserArguments(arguments(model), user_arguments) return false end - #assign the user inputs to variables - object = runner.getOptionalWorkspaceObjectChoiceValue("object",user_arguments,model) #model is passed in because of argument type - motor_eff = runner.getDoubleArgumentValue("motor_eff",user_arguments) - remove_costs = runner.getBoolArgumentValue("remove_costs",user_arguments) - material_cost = runner.getDoubleArgumentValue("material_cost",user_arguments) - demolition_cost = runner.getDoubleArgumentValue("demolition_cost",user_arguments) - years_until_costs_start = runner.getIntegerArgumentValue("years_until_costs_start",user_arguments) - demo_cost_initial_const = runner.getBoolArgumentValue("demo_cost_initial_const",user_arguments) - expected_life = runner.getIntegerArgumentValue("expected_life",user_arguments) - om_cost = runner.getDoubleArgumentValue("om_cost",user_arguments) - om_frequency = runner.getIntegerArgumentValue("om_frequency",user_arguments) - - #check the loop for reasonableness + # assign the user inputs to variables + object = runner.getOptionalWorkspaceObjectChoiceValue('object', user_arguments, model) # model is passed in because of argument type + motor_eff = runner.getDoubleArgumentValue('motor_eff', user_arguments) + remove_costs = runner.getBoolArgumentValue('remove_costs', user_arguments) + material_cost = runner.getDoubleArgumentValue('material_cost', user_arguments) + demolition_cost = runner.getDoubleArgumentValue('demolition_cost', user_arguments) + years_until_costs_start = runner.getIntegerArgumentValue('years_until_costs_start', user_arguments) + demo_cost_initial_const = runner.getBoolArgumentValue('demo_cost_initial_const', user_arguments) + expected_life = runner.getIntegerArgumentValue('expected_life', user_arguments) + om_cost = runner.getDoubleArgumentValue('om_cost', user_arguments) + om_frequency = runner.getIntegerArgumentValue('om_frequency', user_arguments) + + # check the loop for reasonableness apply_to_all_loops = false loop = nil if object.empty? - handle = runner.getStringArgumentValue("loop",user_arguments) + handle = runner.getStringArgumentValue('loop', user_arguments) if handle.empty? - runner.registerError("No loop was chosen.") + runner.registerError('No loop was chosen.') else runner.registerError("The selected loop with handle '#{handle}' was not found in the model. It may have been removed by another measure.") end return false else - if not object.get.to_Loop.empty? + if !object.get.to_Loop.empty? loop = object.get.to_Loop.get - elsif not object.get.to_Building.empty? + elsif !object.get.to_Building.empty? apply_to_all_loops = true else - runner.registerError("Script Error - argument not showing up as loop.") + runner.registerError('Script Error - argument not showing up as loop.') return false end - end #end of if loop.empty? + end # end of if loop.empty? - - #check the user_name for reasonableness - if motor_eff <= 1 or motor_eff >= 5 - runner.registerWarning("Requested motor efficiency improvement is not between expected values of 1% and 5%") + # check the user_name for reasonableness + if (motor_eff <= 1) || (motor_eff >= 5) + runner.registerWarning('Requested motor efficiency improvement is not between expected values of 1% and 5%') end # motor efficiency will be checked motor by motor to see warn if higher than 0.96 and error if not between or equal to 0 and 1 - #set flags to use later + # set flags to use later costs_requested = false - #set values to use later + # set values to use later yr0_capital_totalCosts_baseline = 0 yr0_capital_totalCosts_proposed = 0 - #If demo_cost_initial_const is true then will be applied once in the lifecycle. Future replacements use the demo cost of the new construction. + # If demo_cost_initial_const is true then will be applied once in the lifecycle. Future replacements use the demo cost of the new construction. demo_costs_of_baseline_objects = 0 - #check costs for reasonableness + # check costs for reasonableness if material_cost.abs + demolition_cost.abs + om_cost.abs == 0 - runner.registerInfo("No costs were requested for motors improvements.") + runner.registerInfo('No costs were requested for motors improvements.') else costs_requested = true end - #check lifecycle arguments for reasonableness - if not years_until_costs_start >= 0 and not years_until_costs_start <= expected_life - runner.registerError("Years until costs start should be a non-negative integer less than Expected Life.") + # check lifecycle arguments for reasonableness + if (years_until_costs_start < 0) && (years_until_costs_start > expected_life) + runner.registerError('Years until costs start should be a non-negative integer less than Expected Life.') end - if not expected_life >= 1 and not expected_life <= 100 - runner.registerError("Choose an integer greater than 0 and less than or equal to 100 for Expected Life.") + if (expected_life < 1) && (expected_life > 100) + runner.registerError('Choose an integer greater than 0 and less than or equal to 100 for Expected Life.') end - if not om_frequency >= 1 - runner.registerError("Choose an integer greater than 0 for O & M Frequency.") + if om_frequency < 1 + runner.registerError('Choose an integer greater than 0 for O & M Frequency.') end - #short def to make numbers pretty (converts 4125001.25641 to 4,125,001.26 or 4,125,001). The definition be called through this measure - def neat_numbers(number, roundto = 2) #round to 0 or 2) + # short def to make numbers pretty (converts 4125001.25641 to 4,125,001.26 or 4,125,001). The definition be called through this measure + def neat_numbers(number, roundto = 2) # round to 0 or 2) if roundto == 2 - number = sprintf "%.2f", number + number = format '%.2f', number else number = number.round end - #regex to add commas - number.to_s.reverse.gsub(%r{([0-9]{3}(?=([0-9])))}, "\\1,").reverse - end #end def neat_numbers + # regex to add commas + number.to_s.reverse.gsub(/([0-9]{3}(?=([0-9])))/, '\\1,').reverse + end # end def neat_numbers - #helper that loops through lifecycle costs getting total costs under "Construction" or "Salvage" category and add to counter if occurs during year 0 + # helper that loops through lifecycle costs getting total costs under "Construction" or "Salvage" category and add to counter if occurs during year 0 def get_total_costs_for_objects(objects) counter = 0 objects.each do |object| object_LCCs = object.lifeCycleCosts object_LCCs.each do |object_LCC| - if object_LCC.category == "Construction" or object_LCC.category == "Salvage" + if (object_LCC.category == 'Construction') || (object_LCC.category == 'Salvage') if object_LCC.yearsFromStart == 0 counter += object_LCC.totalCost end @@ -217,25 +217,25 @@ def get_total_costs_for_objects(objects) end end return counter - end #end of def get_total_costs_for_objects(objects) + end # end of def get_total_costs_for_objects(objects) - #get loops for measure + # get loops for measure if apply_to_all_loops loops = model.getAirLoopHVACs else loops = [] - loops << loop #only run on a single space type + loops << loop # only run on a single space type end # get cop values initial_motor_efficiency_values = [] missing_initial_motor_efficiency = 0 - #loop through air loops + # loop through air loops loops.each do |loop| supply_components = loop.supplyComponents - #find fans on loop + # find fans on loop supply_components.each do |supply_component| hVACComponent = supply_component.to_FanConstantVolume if hVACComponent.empty? @@ -245,93 +245,89 @@ def get_total_costs_for_objects(objects) hVACComponent = supply_component.to_FanOnOff end - #alter components of correct type - if not hVACComponent.empty? + # alter components of correct type + if !hVACComponent.empty? hVACComponent = hVACComponent.get - #change and report changes to fans and motors + # change and report changes to fans and motors initial_motor_efficiency = hVACComponent.fanEfficiency target_motor_efficiency = initial_motor_efficiency + motor_eff * 0.01 initial_motor_efficiency_values << initial_motor_efficiency if target_motor_efficiency > 1 hVACComponent.setFanEfficiency(1.0) - runner.registerWarning("Requested efficiency of #{target_motor_efficiency*100}% for #{hVACComponent.name} is not possible. Setting motor efficiency to 100%.") + runner.registerWarning("Requested efficiency of #{target_motor_efficiency * 100}% for #{hVACComponent.name} is not possible. Setting motor efficiency to 100%.") elsif target_motor_efficiency < 0 hVACComponent.setFanEfficiency(0.0) - runner.registerWarning("Requested efficiency of #{target_motor_efficiency*100}% for #{hVACComponent.name} is not possible. Setting motor efficiency to 0%.") + runner.registerWarning("Requested efficiency of #{target_motor_efficiency * 100}% for #{hVACComponent.name} is not possible. Setting motor efficiency to 0%.") else hVACComponent.setFanEfficiency(target_motor_efficiency) - runner.registerInfo("Changing the motor efficiency from #{initial_motor_efficiency*100}% to #{target_motor_efficiency*100}% for '#{hVACComponent.name}' onloop '#{loop.name}.'") + runner.registerInfo("Changing the motor efficiency from #{initial_motor_efficiency * 100}% to #{target_motor_efficiency * 100}% for '#{hVACComponent.name}' onloop '#{loop.name}.'") if target_motor_efficiency > 0.96 - runner.registerWarning("Requested efficiency for #{hVACComponent.name} is greater than 96%.") + runner.registerWarning("Requested efficiency for #{hVACComponent.name} is greater than 96%.") end end - #get initial year 0 cost + # get initial year 0 cost yr0_capital_totalCosts_baseline += get_total_costs_for_objects([hVACComponent]) - #demo value of baseline costs associated with unit + # demo value of baseline costs associated with unit demo_LCCs = hVACComponent.lifeCycleCosts demo_LCCs.each do |demo_LCC| - if demo_LCC.category == "Salvage" + if demo_LCC.category == 'Salvage' demo_costs_of_baseline_objects += demo_LCC.totalCost end end - #remove all old costs - if hVACComponent.lifeCycleCosts.size > 0 and remove_costs == true + # remove all old costs + if !hVACComponent.lifeCycleCosts.empty? && (remove_costs == true) runner.registerInfo("Removing existing lifecycle cost objects associated with #{hVACComponent.name}") - removed_costs = hVACComponent.removeLifeCycleCosts() + removed_costs = hVACComponent.removeLifeCycleCosts end - #add new costs + # add new costs if costs_requested == true - #adding new cost items - lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_Mat - #{hVACComponent.name}", hVACComponent, material_cost, "CostPerEach", "Construction", expected_life, years_until_costs_start) + # adding new cost items + lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_Mat - #{hVACComponent.name}", hVACComponent, material_cost, 'CostPerEach', 'Construction', expected_life, years_until_costs_start) # cost for if demo_initial_Construction == true is added at the end of the measure - lcc_demo = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_Demo - #{hVACComponent.name}", hVACComponent, demolition_cost, "CostPerEach", "Salvage", expected_life, years_until_costs_start+expected_life) - lcc_om = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_OM - #{hVACComponent.name}", hVACComponent, om_cost, "CostPerEach", "Maintenance", om_frequency, 0) + lcc_demo = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_Demo - #{hVACComponent.name}", hVACComponent, demolition_cost, 'CostPerEach', 'Salvage', expected_life, years_until_costs_start + expected_life) + lcc_om = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_OM - #{hVACComponent.name}", hVACComponent, om_cost, 'CostPerEach', 'Maintenance', om_frequency, 0) - #get final year 0 cost + # get final year 0 cost yr0_capital_totalCosts_proposed += get_total_costs_for_objects([hVACComponent]) - end #end of costs_requested == true - - end #end if not hVACComponent.empty? + end # end of costs_requested == true - end #end supply_components.each do + end # end if not hVACComponent.empty? + end # end supply_components.each do + end # end loops.each do - end #end loops.each do - - #add one time demo cost of removed windows if appropriate + # add one time demo cost of removed windows if appropriate if demo_cost_initial_const == true building = model.getBuilding - lcc_baseline_demo = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_baseline_demo", building, demo_costs_of_baseline_objects, "CostPerEach", "Salvage", 0, years_until_costs_start).get #using 0 for repeat period since one time cost. - runner.registerInfo("Adding one time cost of $#{neat_numbers(lcc_baseline_demo.totalCost,0)} related to demolition of baseline objects.") + lcc_baseline_demo = OpenStudio::Model::LifeCycleCost.createLifeCycleCost('LCC_baseline_demo', building, demo_costs_of_baseline_objects, 'CostPerEach', 'Salvage', 0, years_until_costs_start).get # using 0 for repeat period since one time cost. + runner.registerInfo("Adding one time cost of $#{neat_numbers(lcc_baseline_demo.totalCost, 0)} related to demolition of baseline objects.") - #if demo occurs on year 0 then add to initial capital cost counter + # if demo occurs on year 0 then add to initial capital cost counter if lcc_baseline_demo.yearsFromStart == 0 yr0_capital_totalCosts_proposed += lcc_baseline_demo.totalCost end end if initial_motor_efficiency_values.size + missing_initial_motor_efficiency == 0 - runner.registerAsNotApplicable("The affected loop(s) does not contain any fans, the model will not be altered.") + runner.registerAsNotApplicable('The affected loop(s) does not contain any fans, the model will not be altered.') return true end - #reporting initial condition of model - runner.registerInitialCondition("The starting motor efficiency values in affected loop(s) range from #{initial_motor_efficiency_values.min*100}% to #{initial_motor_efficiency_values.max*100}%. Initial year 0 capital costs for affected fans is $#{neat_numbers(yr0_capital_totalCosts_baseline,0)}.") + # reporting initial condition of model + runner.registerInitialCondition("The starting motor efficiency values in affected loop(s) range from #{initial_motor_efficiency_values.min * 100}% to #{initial_motor_efficiency_values.max * 100}%. Initial year 0 capital costs for affected fans is $#{neat_numbers(yr0_capital_totalCosts_baseline, 0)}.") - #reporting final condition of model - runner.registerFinalCondition("#{initial_motor_efficiency_values.size + missing_initial_motor_efficiency} fans had motor efficiency values set to altered. Final year 0 capital costs for affected fans is $#{neat_numbers(yr0_capital_totalCosts_proposed,0)}.") + # reporting final condition of model + runner.registerFinalCondition("#{initial_motor_efficiency_values.size + missing_initial_motor_efficiency} fans had motor efficiency values set to altered. Final year 0 capital costs for affected fans is $#{neat_numbers(yr0_capital_totalCosts_proposed, 0)}.") return true + end # end the cop method +end # end the measure - end #end the cop method - -end #end the measure - -#this allows the measure to be used by the application -ImproveFanTotalEfficiencybyPercentage.new.registerWithApplication \ No newline at end of file +# this allows the measure to be used by the application +ImproveFanTotalEfficiencybyPercentage.new.registerWithApplication diff --git a/lib/measures/IncreaseInsulationRValueForExteriorWalls/tests/IncreaseInsulationRValueForExteriorWalls_01_Test.rb b/lib/measures/IncreaseInsulationRValueForExteriorWalls/tests/IncreaseInsulationRValueForExteriorWalls_01_Test.rb index 133036f..7119861 100644 --- a/lib/measures/IncreaseInsulationRValueForExteriorWalls/tests/IncreaseInsulationRValueForExteriorWalls_01_Test.rb +++ b/lib/measures/IncreaseInsulationRValueForExteriorWalls/tests/IncreaseInsulationRValueForExteriorWalls_01_Test.rb @@ -208,7 +208,7 @@ def test_IncreaseInsulationRValueForExteriorWalls_NewConstruction_FullyCosted expected_messages["Construction 'Test_No Insulation' does not appear to have an insulation layer and was not altered."] = false result.warnings.each do |warning| expected_messages.each_key do |message| - if warning.logMessage =~ Regexp.new(message) + if warning.logMessage.match?(Regexp.new(message)) assert(expected_messages[message] == false, "Message '#{message}' found multiple times") expected_messages[message] = true end diff --git a/lib/measures/ReplaceFanTotalEfficiency/measure.rb b/lib/measures/ReplaceFanTotalEfficiency/measure.rb index 70f11dd..7835abc 100644 --- a/lib/measures/ReplaceFanTotalEfficiency/measure.rb +++ b/lib/measures/ReplaceFanTotalEfficiency/measure.rb @@ -1,208 +1,209 @@ -#start the measure -class ReplaceFanTotalEfficiency < OpenStudio::Ruleset::ModelUserScript +# frozen_string_literal: true - #define the name that a user will see, this method may be deprecated as - #the display name in PAT comes from the name field in measure.xml +# start the measure +class ReplaceFanTotalEfficiency < OpenStudio::Ruleset::ModelUserScript + # define the name that a user will see, this method may be deprecated as + # the display name in PAT comes from the name field in measure.xml def name - return "Replace Fan Total Efficiency" + return 'Replace Fan Total Efficiency' end - #define the arguments that the user will input + # define the arguments that the user will input def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new - #populate choice argument for constructions that are applied to surfaces in the model + # populate choice argument for constructions that are applied to surfaces in the model loop_handles = OpenStudio::StringVector.new loop_display_names = OpenStudio::StringVector.new - #putting air loops and names into hash + # putting air loops and names into hash loop_args = model.getAirLoopHVACs loop_args_hash = {} loop_args.each do |loop_arg| loop_args_hash[loop_arg.name.to_s] = loop_arg end - #looping through sorted hash of air loops - loop_args_hash.sort.map do |key,value| + # looping through sorted hash of air loops + loop_args_hash.sort.map do |key, value| show_loop = false components = value.supplyComponents components.each do |component| - if not component.to_FanConstantVolume.empty? + if !component.to_FanConstantVolume.empty? show_loop = true end - if not component.to_FanVariableVolume.empty? + if !component.to_FanVariableVolume.empty? show_loop = true end - if not component.to_FanOnOff.empty? + if !component.to_FanOnOff.empty? show_loop = true end end - #if loop as object of correct type then add to hash. + # if loop as object of correct type then add to hash. if show_loop == true loop_handles << value.handle.to_s loop_display_names << key end end - #add building to string vector with air loops + # add building to string vector with air loops building = model.getBuilding loop_handles << building.handle.to_s - loop_display_names << "*All Air Loops*" + loop_display_names << '*All Air Loops*' - #make an argument for air loops - object = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("object", loop_handles, loop_display_names,true) - object.setDisplayName("Choose an Air Loop to Alter.") - object.setDefaultValue("*All Air Loops*") #if no loop is chosen this will run on all air loops + # make an argument for air loops + object = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('object', loop_handles, loop_display_names, true) + object.setDisplayName('Choose an Air Loop to Alter.') + object.setDefaultValue('*All Air Loops*') # if no loop is chosen this will run on all air loops args << object - #todo - change this to choice list from design document - #make an argument to add new space true/false - motor_eff = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("motor_eff",true) - motor_eff.setDisplayName("Fan Total Efficiency Replacement in %") + # TODO: - change this to choice list from design document + # make an argument to add new space true/false + motor_eff = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('motor_eff', true) + motor_eff.setDisplayName('Fan Total Efficiency Replacement in %') motor_eff.setDefaultValue(70) args << motor_eff - #bool argument to remove existing costs - remove_costs = OpenStudio::Ruleset::OSArgument::makeBoolArgument("remove_costs",true) - remove_costs.setDisplayName("Remove Baseline Costs From Effected Fans?") + # bool argument to remove existing costs + remove_costs = OpenStudio::Ruleset::OSArgument.makeBoolArgument('remove_costs', true) + remove_costs.setDisplayName('Remove Baseline Costs From Effected Fans?') remove_costs.setDefaultValue(false) args << remove_costs - #make an argument for material and installation cost - material_cost = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("material_cost",true) - material_cost.setDisplayName("Material and Installation Costs per Motor ($).") + # make an argument for material and installation cost + material_cost = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('material_cost', true) + material_cost.setDisplayName('Material and Installation Costs per Motor ($).') material_cost.setDefaultValue(0.0) args << material_cost - #make an argument for demolition cost - demolition_cost = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("demolition_cost",true) - demolition_cost.setDisplayName("Demolition Costs per Motor ($).") + # make an argument for demolition cost + demolition_cost = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('demolition_cost', true) + demolition_cost.setDisplayName('Demolition Costs per Motor ($).') demolition_cost.setDefaultValue(0.0) args << demolition_cost - #make an argument for duration in years until costs start - years_until_costs_start = OpenStudio::Ruleset::OSArgument::makeIntegerArgument("years_until_costs_start",true) - years_until_costs_start.setDisplayName("Years Until Costs Start (whole years).") + # make an argument for duration in years until costs start + years_until_costs_start = OpenStudio::Ruleset::OSArgument.makeIntegerArgument('years_until_costs_start', true) + years_until_costs_start.setDisplayName('Years Until Costs Start (whole years).') years_until_costs_start.setDefaultValue(0) args << years_until_costs_start - #make an argument to determine if demolition costs should be included in initial construction - demo_cost_initial_const = OpenStudio::Ruleset::OSArgument::makeBoolArgument("demo_cost_initial_const",true) - demo_cost_initial_const.setDisplayName("Demolition Costs Occur During Initial Construction?") + # make an argument to determine if demolition costs should be included in initial construction + demo_cost_initial_const = OpenStudio::Ruleset::OSArgument.makeBoolArgument('demo_cost_initial_const', true) + demo_cost_initial_const.setDisplayName('Demolition Costs Occur During Initial Construction?') demo_cost_initial_const.setDefaultValue(false) args << demo_cost_initial_const - #make an argument for expected life - expected_life = OpenStudio::Ruleset::OSArgument::makeIntegerArgument("expected_life",true) - expected_life.setDisplayName("Expected Life (whole years).") + # make an argument for expected life + expected_life = OpenStudio::Ruleset::OSArgument.makeIntegerArgument('expected_life', true) + expected_life.setDisplayName('Expected Life (whole years).') expected_life.setDefaultValue(20) args << expected_life - #make an argument for o&m cost - om_cost = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("om_cost",true) - om_cost.setDisplayName("O & M Costs per Motor ($).") + # make an argument for o&m cost + om_cost = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('om_cost', true) + om_cost.setDisplayName('O & M Costs per Motor ($).') om_cost.setDefaultValue(0.0) args << om_cost - #make an argument for o&m frequency - om_frequency = OpenStudio::Ruleset::OSArgument::makeIntegerArgument("om_frequency",true) - om_frequency.setDisplayName("O & M Frequency (whole years).") + # make an argument for o&m frequency + om_frequency = OpenStudio::Ruleset::OSArgument.makeIntegerArgument('om_frequency', true) + om_frequency.setDisplayName('O & M Frequency (whole years).') om_frequency.setDefaultValue(1) args << om_frequency return args - end #end the arguments method + end # end the arguments method - #define what happens when the measure is cop + # define what happens when the measure is cop def run(model, runner, user_arguments) super(model, runner, user_arguments) - #use the built-in error checking - if not runner.validateUserArguments(arguments(model), user_arguments) + # use the built-in error checking + if !runner.validateUserArguments(arguments(model), user_arguments) return false end - #assign the user inputs to variables - object = runner.getOptionalWorkspaceObjectChoiceValue("object",user_arguments,model) #model is passed in because of argument type - motor_eff = runner.getDoubleArgumentValue("motor_eff",user_arguments) - remove_costs = runner.getBoolArgumentValue("remove_costs",user_arguments) - material_cost = runner.getDoubleArgumentValue("material_cost",user_arguments) - demolition_cost = runner.getDoubleArgumentValue("demolition_cost",user_arguments) - years_until_costs_start = runner.getIntegerArgumentValue("years_until_costs_start",user_arguments) - demo_cost_initial_const = runner.getBoolArgumentValue("demo_cost_initial_const",user_arguments) - expected_life = runner.getIntegerArgumentValue("expected_life",user_arguments) - om_cost = runner.getDoubleArgumentValue("om_cost",user_arguments) - om_frequency = runner.getIntegerArgumentValue("om_frequency",user_arguments) - - #check the loop for reasonableness + # assign the user inputs to variables + object = runner.getOptionalWorkspaceObjectChoiceValue('object', user_arguments, model) # model is passed in because of argument type + motor_eff = runner.getDoubleArgumentValue('motor_eff', user_arguments) + remove_costs = runner.getBoolArgumentValue('remove_costs', user_arguments) + material_cost = runner.getDoubleArgumentValue('material_cost', user_arguments) + demolition_cost = runner.getDoubleArgumentValue('demolition_cost', user_arguments) + years_until_costs_start = runner.getIntegerArgumentValue('years_until_costs_start', user_arguments) + demo_cost_initial_const = runner.getBoolArgumentValue('demo_cost_initial_const', user_arguments) + expected_life = runner.getIntegerArgumentValue('expected_life', user_arguments) + om_cost = runner.getDoubleArgumentValue('om_cost', user_arguments) + om_frequency = runner.getIntegerArgumentValue('om_frequency', user_arguments) + + # check the loop for reasonableness apply_to_all_loops = false loop = nil if object.empty? - handle = runner.getStringArgumentValue("loop",user_arguments) + handle = runner.getStringArgumentValue('loop', user_arguments) if handle.empty? - runner.registerError("No loop was chosen.") + runner.registerError('No loop was chosen.') else runner.registerError("The selected loop with handle '#{handle}' was not found in the model. It may have been removed by another measure.") end return false else - if not object.get.to_Loop.empty? + if !object.get.to_Loop.empty? loop = object.get.to_Loop.get - elsif not object.get.to_Building.empty? + elsif !object.get.to_Building.empty? apply_to_all_loops = true else - runner.registerError("Script Error - argument not showing up as loop.") + runner.registerError('Script Error - argument not showing up as loop.') return false end - end #end of if loop.empty? + end # end of if loop.empty? - #set flags to use later + # set flags to use later costs_requested = false - #set values to use later + # set values to use later yr0_capital_totalCosts_baseline = 0 yr0_capital_totalCosts_proposed = 0 - #If demo_cost_initial_const is true then will be applied once in the lifecycle. Future replacements use the demo cost of the new construction. + # If demo_cost_initial_const is true then will be applied once in the lifecycle. Future replacements use the demo cost of the new construction. demo_costs_of_baseline_objects = 0 - #check costs for reasonableness + # check costs for reasonableness if material_cost.abs + demolition_cost.abs + om_cost.abs == 0 - runner.registerInfo("No costs were requested for motors improvements.") + runner.registerInfo('No costs were requested for motors improvements.') else costs_requested = true end - #check lifecycle arguments for reasonableness - if not years_until_costs_start >= 0 and not years_until_costs_start <= expected_life - runner.registerError("Years until costs start should be a non-negative integer less than Expected Life.") + # check lifecycle arguments for reasonableness + if (years_until_costs_start < 0) && (years_until_costs_start > expected_life) + runner.registerError('Years until costs start should be a non-negative integer less than Expected Life.') end - if not expected_life >= 1 and not expected_life <= 100 - runner.registerError("Choose an integer greater than 0 and less than or equal to 100 for Expected Life.") + if (expected_life < 1) && (expected_life > 100) + runner.registerError('Choose an integer greater than 0 and less than or equal to 100 for Expected Life.') end - if not om_frequency >= 1 - runner.registerError("Choose an integer greater than 0 for O & M Frequency.") + if om_frequency < 1 + runner.registerError('Choose an integer greater than 0 for O & M Frequency.') end - #short def to make numbers pretty (converts 4125001.25641 to 4,125,001.26 or 4,125,001). The definition be called through this measure - def neat_numbers(number, roundto = 2) #round to 0 or 2) + # short def to make numbers pretty (converts 4125001.25641 to 4,125,001.26 or 4,125,001). The definition be called through this measure + def neat_numbers(number, roundto = 2) # round to 0 or 2) if roundto == 2 - number = sprintf "%.2f", number + number = format '%.2f', number else number = number.round end - #regex to add commas - number.to_s.reverse.gsub(%r{([0-9]{3}(?=([0-9])))}, "\\1,").reverse - end #end def neat_numbers + # regex to add commas + number.to_s.reverse.gsub(/([0-9]{3}(?=([0-9])))/, '\\1,').reverse + end # end def neat_numbers - #helper that loops through lifecycle costs getting total costs under "Construction" or "Salvage" category and add to counter if occurs during year 0 + # helper that loops through lifecycle costs getting total costs under "Construction" or "Salvage" category and add to counter if occurs during year 0 def get_total_costs_for_objects(objects) counter = 0 objects.each do |object| object_LCCs = object.lifeCycleCosts object_LCCs.each do |object_LCC| - if object_LCC.category == "Construction" or object_LCC.category == "Salvage" + if (object_LCC.category == 'Construction') || (object_LCC.category == 'Salvage') if object_LCC.yearsFromStart == 0 counter += object_LCC.totalCost end @@ -210,25 +211,25 @@ def get_total_costs_for_objects(objects) end end return counter - end #end of def get_total_costs_for_objects(objects) + end # end of def get_total_costs_for_objects(objects) - #get loops for measure + # get loops for measure if apply_to_all_loops loops = model.getAirLoopHVACs else loops = [] - loops << loop #only run on a single space type + loops << loop # only run on a single space type end # get cop values initial_motor_efficiency_values = [] missing_initial_motor_efficiency = 0 - #loop through air loops + # loop through air loops loops.each do |loop| supply_components = loop.supplyComponents - #find fans on loop + # find fans on loop supply_components.each do |supply_component| hVACComponent = supply_component.to_FanConstantVolume if hVACComponent.empty? @@ -238,96 +239,92 @@ def get_total_costs_for_objects(objects) hVACComponent = supply_component.to_FanOnOff end - #alter components of correct type - if not hVACComponent.empty? + # alter components of correct type + if !hVACComponent.empty? hVACComponent = hVACComponent.get - #change and report changes to fans and motors + # change and report changes to fans and motors initial_motor_efficiency = hVACComponent.fanEfficiency target_motor_efficiency = motor_eff * 0.01 initial_motor_efficiency_values << initial_motor_efficiency if target_motor_efficiency > 1 hVACComponent.setFanEfficiency(1.0) - runner.registerWarning("Requested efficiency of #{target_motor_efficiency*100}% for #{hVACComponent.name} is not possible. Setting motor efficiency to 100%.") + runner.registerWarning("Requested efficiency of #{target_motor_efficiency * 100}% for #{hVACComponent.name} is not possible. Setting motor efficiency to 100%.") elsif target_motor_efficiency < 0 hVACComponent.setFanEfficiency(0.0) - runner.registerWarning("Requested efficiency of #{target_motor_efficiency*100}% for #{hVACComponent.name} is not possible. Setting motor efficiency to 0%.") - elsif target_motor_efficiency < initial_motor_efficiency + runner.registerWarning("Requested efficiency of #{target_motor_efficiency * 100}% for #{hVACComponent.name} is not possible. Setting motor efficiency to 0%.") + elsif target_motor_efficiency < initial_motor_efficiency hVACComponent.setFanEfficiency(initial_motor_efficiency) - runner.registerWarning("Requested efficiency of #{target_motor_efficiency*100}% for #{hVACComponent.name} is the same as the initial efficiency. No changes.") + runner.registerWarning("Requested efficiency of #{target_motor_efficiency * 100}% for #{hVACComponent.name} is the same as the initial efficiency. No changes.") else hVACComponent.setFanEfficiency(target_motor_efficiency) - runner.registerInfo("Changing the motor efficiency from #{initial_motor_efficiency*100}% to #{target_motor_efficiency*100}% for '#{hVACComponent.name}' onloop '#{loop.name}.'") + runner.registerInfo("Changing the motor efficiency from #{initial_motor_efficiency * 100}% to #{target_motor_efficiency * 100}% for '#{hVACComponent.name}' onloop '#{loop.name}.'") if target_motor_efficiency > 0.96 - runner.registerWarning("Requested efficiency for #{hVACComponent.name} is greater than 96%.") + runner.registerWarning("Requested efficiency for #{hVACComponent.name} is greater than 96%.") end end - #get initial year 0 cost + # get initial year 0 cost yr0_capital_totalCosts_baseline += get_total_costs_for_objects([hVACComponent]) - #demo value of baseline costs associated with unit + # demo value of baseline costs associated with unit demo_LCCs = hVACComponent.lifeCycleCosts demo_LCCs.each do |demo_LCC| - if demo_LCC.category == "Salvage" + if demo_LCC.category == 'Salvage' demo_costs_of_baseline_objects += demo_LCC.totalCost end end - #remove all old costs - if hVACComponent.lifeCycleCosts.size > 0 and remove_costs == true + # remove all old costs + if !hVACComponent.lifeCycleCosts.empty? && (remove_costs == true) runner.registerInfo("Removing existing lifecycle cost objects associated with #{hVACComponent.name}") - removed_costs = hVACComponent.removeLifeCycleCosts() + removed_costs = hVACComponent.removeLifeCycleCosts end - #add new costs + # add new costs if costs_requested == true - #adding new cost items - lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_Mat - #{hVACComponent.name}", hVACComponent, material_cost, "CostPerEach", "Construction", expected_life, years_until_costs_start) + # adding new cost items + lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_Mat - #{hVACComponent.name}", hVACComponent, material_cost, 'CostPerEach', 'Construction', expected_life, years_until_costs_start) # cost for if demo_initial_Construction == true is added at the end of the measure - lcc_demo = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_Demo - #{hVACComponent.name}", hVACComponent, demolition_cost, "CostPerEach", "Salvage", expected_life, years_until_costs_start+expected_life) - lcc_om = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_OM - #{hVACComponent.name}", hVACComponent, om_cost, "CostPerEach", "Maintenance", om_frequency, 0) + lcc_demo = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_Demo - #{hVACComponent.name}", hVACComponent, demolition_cost, 'CostPerEach', 'Salvage', expected_life, years_until_costs_start + expected_life) + lcc_om = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_OM - #{hVACComponent.name}", hVACComponent, om_cost, 'CostPerEach', 'Maintenance', om_frequency, 0) - #get final year 0 cost + # get final year 0 cost yr0_capital_totalCosts_proposed += get_total_costs_for_objects([hVACComponent]) - end #end of costs_requested == true - - end #end if not hVACComponent.empty? + end # end of costs_requested == true - end #end supply_components.each do + end # end if not hVACComponent.empty? + end # end supply_components.each do + end # end loops.each do - end #end loops.each do - - #add one time demo cost of removed windows if appropriate + # add one time demo cost of removed windows if appropriate if demo_cost_initial_const == true building = model.getBuilding - lcc_baseline_demo = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_baseline_demo", building, demo_costs_of_baseline_objects, "CostPerEach", "Salvage", 0, years_until_costs_start).get #using 0 for repeat period since one time cost. - runner.registerInfo("Adding one time cost of $#{neat_numbers(lcc_baseline_demo.totalCost,0)} related to demolition of baseline objects.") + lcc_baseline_demo = OpenStudio::Model::LifeCycleCost.createLifeCycleCost('LCC_baseline_demo', building, demo_costs_of_baseline_objects, 'CostPerEach', 'Salvage', 0, years_until_costs_start).get # using 0 for repeat period since one time cost. + runner.registerInfo("Adding one time cost of $#{neat_numbers(lcc_baseline_demo.totalCost, 0)} related to demolition of baseline objects.") - #if demo occurs on year 0 then add to initial capital cost counter + # if demo occurs on year 0 then add to initial capital cost counter if lcc_baseline_demo.yearsFromStart == 0 yr0_capital_totalCosts_proposed += lcc_baseline_demo.totalCost end end if initial_motor_efficiency_values.size + missing_initial_motor_efficiency == 0 - runner.registerAsNotApplicable("The affected loop(s) does not contain any fans, the model will not be altered.") + runner.registerAsNotApplicable('The affected loop(s) does not contain any fans, the model will not be altered.') return true end - #reporting initial condition of model - runner.registerInitialCondition("The starting motor efficiency values in affected loop(s) range from #{initial_motor_efficiency_values.min*100}% to #{initial_motor_efficiency_values.max*100}%. Initial year 0 capital costs for affected fans is $#{neat_numbers(yr0_capital_totalCosts_baseline,0)}.") + # reporting initial condition of model + runner.registerInitialCondition("The starting motor efficiency values in affected loop(s) range from #{initial_motor_efficiency_values.min * 100}% to #{initial_motor_efficiency_values.max * 100}%. Initial year 0 capital costs for affected fans is $#{neat_numbers(yr0_capital_totalCosts_baseline, 0)}.") - #reporting final condition of model - runner.registerFinalCondition("#{initial_motor_efficiency_values.size + missing_initial_motor_efficiency} fans had motor efficiency values set to altered. Final year 0 capital costs for affected fans is $#{neat_numbers(yr0_capital_totalCosts_proposed,0)}.") + # reporting final condition of model + runner.registerFinalCondition("#{initial_motor_efficiency_values.size + missing_initial_motor_efficiency} fans had motor efficiency values set to altered. Final year 0 capital costs for affected fans is $#{neat_numbers(yr0_capital_totalCosts_proposed, 0)}.") return true + end # end the cop method +end # end the measure - end #end the cop method - -end #end the measure - -#this allows the measure to be used by the application -ReplaceFanTotalEfficiency.new.registerWithApplication \ No newline at end of file +# this allows the measure to be used by the application +ReplaceFanTotalEfficiency.new.registerWithApplication diff --git a/lib/measures/add_apszhp_to_each_zone/measure.rb b/lib/measures/add_apszhp_to_each_zone/measure.rb index 52843c3..eaaefec 100644 --- a/lib/measures/add_apszhp_to_each_zone/measure.rb +++ b/lib/measures/add_apszhp_to_each_zone/measure.rb @@ -1,23 +1,21 @@ +# frozen_string_literal: true + # Author: Julien Marrec # email: julien.marrec@gmail.com # start the measure class AddAPSZHPToEachZone < OpenStudio::Ruleset::ModelUserScript - - #define the name that a user will see, this method may be deprecated as - #the display name in PAT comes from the name field in measure.xml + # define the name that a user will see, this method may be deprecated as + # the display name in PAT comes from the name field in measure.xml def name - return "Add a PSZ-HP to each zone" + return 'Add a PSZ-HP to each zone' end - + def description - - return "This will add a Rooftop Packaged Single Zone Heat Pump (RTU with DX cooling and DX heating coils) to each zone of the model." - + return 'This will add a Rooftop Packaged Single Zone Heat Pump (RTU with DX cooling and DX heating coils) to each zone of the model.' end def modeler_description - return "Add a System 4 - PSZ-HP - unit for each zone. This is a single zone system. Parameters: - Double: COP cooling and COP heating (Double) @@ -27,57 +25,55 @@ def modeler_description - DCV enabled or not (Boolean) - Fan type: Variable Volume Fan (VFD) or not (Constant Volume) (Choice) - Filter for the zone name (String): only zones that contains the string you input in filter will receive this system." - end - + # define the arguments that the user will input def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new - delete_existing = OpenStudio::Ruleset::OSArgument::makeBoolArgument('delete_existing', true) + delete_existing = OpenStudio::Ruleset::OSArgument.makeBoolArgument('delete_existing', true) delete_existing.setDisplayName('Delete any existing HVAC equipment?') args << delete_existing - - cop_cooling = OpenStudio::Ruleset::OSArgument::makeDoubleArgument('cop_cooling', true) + + cop_cooling = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('cop_cooling', true) cop_cooling.setDisplayName('COP Cooling (SI)') cop_cooling.setDefaultValue(3.1) args << cop_cooling - cop_heating = OpenStudio::Ruleset::OSArgument::makeDoubleArgument('cop_heating', true) + cop_heating = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('cop_heating', true) cop_heating.setDisplayName('COP Heating (SI)') cop_heating.setDefaultValue(3.1) args << cop_heating - - has_electric_coil = OpenStudio::Ruleset::OSArgument::makeBoolArgument('has_electric_coil', false) + + has_electric_coil = OpenStudio::Ruleset::OSArgument.makeBoolArgument('has_electric_coil', false) has_electric_coil.setDisplayName('Include supplementary electric heating coils?') has_electric_coil.setDefaultValue(true) args << has_electric_coil - - has_dcv = OpenStudio::Ruleset::OSArgument::makeBoolArgument('has_dcv', false) + + has_dcv = OpenStudio::Ruleset::OSArgument.makeBoolArgument('has_dcv', false) has_dcv.setDisplayName('Enable Demand Controlled Ventilation?') has_dcv.setDefaultValue(false) args << has_dcv - + chs = OpenStudio::StringVector.new - chs << "Constant Volume (default)" - chs << "Variable Volume (VFD)" - fan_type = OpenStudio::Ruleset::OSArgument::makeChoiceArgument('fan_type', chs, true) - fan_type.setDisplayName("Select fan type:") + chs << 'Constant Volume (default)' + chs << 'Variable Volume (VFD)' + fan_type = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('fan_type', chs, true) + fan_type.setDisplayName('Select fan type:') args << fan_type - - fan_pressure_rise = OpenStudio::Ruleset::OSArgument::makeDoubleArgument('fan_pressure_rise', false) + + fan_pressure_rise = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('fan_pressure_rise', false) fan_pressure_rise.setDisplayName('Fan Pressure Rise (Pa)') fan_pressure_rise.setDescription('Leave blank for default value') - #fan_pressure_rise.setDefaultValue(0) + # fan_pressure_rise.setDefaultValue(0) args << fan_pressure_rise - chs = OpenStudio::StringVector.new - chs << "By Space Type" + chs << 'By Space Type' chs << "By Space Type's 'Standards Space Type'" - chs << "By Zone Filter" - filter_type = OpenStudio::Ruleset::OSArgument::makeChoiceArgument('filter_type', chs, true) - filter_type.setDisplayName("How do you want to choose the affected zones?") + chs << 'By Zone Filter' + filter_type = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('filter_type', chs, true) + filter_type.setDisplayName('How do you want to choose the affected zones?') args << filter_type # create an argument for a space type to be used in the model. Only return those that are used @@ -89,45 +85,43 @@ def arguments(model) standardsSpaceType = [] spaceTypes.each do |spaceType| - if spaceType.spaces.size > 0 # only show space types used in the building + if !spaceType.spaces.empty? # only show space types used in the building usedSpaceTypes_handle << spaceType.handle.to_s usedSpaceTypes_displayName << spaceType.name.to_s - if not spaceType.standardsSpaceType.empty? + if !spaceType.standardsSpaceType.empty? standardsSpaceType << spaceType.standardsSpaceType.get end end - end + end - # make an argument for space type - space_type = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("space_type", usedSpaceTypes_handle, usedSpaceTypes_displayName,false) - space_type.setDisplayName("a. Which Space Type?") + # make an argument for space type + space_type = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('space_type', usedSpaceTypes_handle, usedSpaceTypes_displayName, false) + space_type.setDisplayName('a. Which Space Type?') args << space_type - - # Argument for Standards Space Type # First, make it unique standardsSpaceType.uniq! - standards_space_type = OpenStudio::Ruleset::OSArgument::makeChoiceArgument('standards_space_type', standardsSpaceType, false) - standards_space_type.setDisplayName("b. Which Standards Space Type") + standards_space_type = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('standards_space_type', standardsSpaceType, false) + standards_space_type.setDisplayName('b. Which Standards Space Type') args << standards_space_type - zone_filter = OpenStudio::Ruleset::OSArgument::makeStringArgument('zone_filter', false) - zone_filter.setDisplayName("c. Only Apply to Zones that contain the following string") + zone_filter = OpenStudio::Ruleset::OSArgument.makeStringArgument('zone_filter', false) + zone_filter.setDisplayName('c. Only Apply to Zones that contain the following string') zone_filter.setDescription("Case insensitive. For example, type 'retail' to apply to zones that have the word 'retail' or 'REtaiL' in their name. Leave blank to apply to all zones") args << zone_filter - + return args end # end the arguments method # define what happens when the measure is run def run(model, runner, user_arguments) super(model, runner, user_arguments) - - # use the built-in error checking - if not runner.validateUserArguments(arguments(model), user_arguments) + + # use the built-in error checking + if !runner.validateUserArguments(arguments(model), user_arguments) return false end @@ -140,7 +134,7 @@ def run(model, runner, user_arguments) # Get fan_pressure_rise: this is an OptionalDouble - we'll use '.get' later fan_pressure_rise = runner.getOptionalDoubleArgumentValue('fan_pressure_rise', user_arguments) - + # FanType fan_type = runner.getStringArgumentValue('fan_type', user_arguments) runner.registerInfo("Fan type: #{fan_type}") @@ -151,17 +145,17 @@ def run(model, runner, user_arguments) has_vfd = false end - filter_type = runner.getStringArgumentValue("filter_type",user_arguments) + filter_type = runner.getStringArgumentValue('filter_type', user_arguments) - if filter_type == "By Space Type" - space_type = runner.getOptionalWorkspaceObjectChoiceValue("space_type",user_arguments,model) - if not space_type.empty? + if filter_type == 'By Space Type' + space_type = runner.getOptionalWorkspaceObjectChoiceValue('space_type', user_arguments, model) + if !space_type.empty? space_type = space_type.get - if not space_type.to_SpaceType.empty? + if !space_type.to_SpaceType.empty? space_type = space_type.to_SpaceType.get zones = [] space_type.spaces.each do |space| - if not space.thermalZone.empty? + if !space.thermalZone.empty? z = space.thermalZone.get zones << z end @@ -171,10 +165,10 @@ def run(model, runner, user_arguments) elsif filter_type == "By Space Type's 'Standards Space Type'" - standards_space_type = runner.getOptionalStringArgumentValue("standards_space_type", user_arguments) + standards_space_type = runner.getOptionalStringArgumentValue('standards_space_type', user_arguments) puts standards_space_type.class - if not standards_space_type.empty? + if !standards_space_type.empty? standards_space_type = standards_space_type.get puts standards_space_type space_types = model.getSpaceTypes @@ -182,12 +176,12 @@ def run(model, runner, user_arguments) zones = [] space_types.each do |space_type| - if space_type.standardsSpaceType.to_s.upcase == standards_space_type.upcase + if space_type.standardsSpaceType.to_s.casecmp(standards_space_type).zero? space_type.spaces.each do |space| - if not space.thermalZone.empty? + if !space.thermalZone.empty? z = space.thermalZone.get # We MUST check if zone isn't in there yet (or at the end do zones.uniq!) because several spaces can refer to the same thermal zone! - if not zones.include?(z) + if !zones.include?(z) zones << z end end @@ -222,14 +216,13 @@ def run(model, runner, user_arguments) end # End of if filter_type - # Output zone names to console puts "\n\n================ ZONES THAT MATCHED THE FILTER ================\n" zones.each do |z| puts z.name end - #info for initial condition + # info for initial condition initial_num_air_loops_demand_control = 0 final_num_air_loops_demand_control = 0 initial_num_fan_VFD = 0 @@ -239,7 +232,6 @@ def run(model, runner, user_arguments) delete_existing_condenser_loops = 0 affected_loops = 0 - # If we need to delete existing HVAC loops, we'll store the PRE-EXISTING Loops in the following variables, # They will be used for clean up at the end if delete_existing @@ -249,155 +241,143 @@ def run(model, runner, user_arguments) runner.registerInfo("Number of initial PlantLoops: #{plant_loops.size}") end - - # For each thermal zones (zones is initialized above, depending on which filter you chose) zones.each do |z| - # Create a system 4 (PSZ-HP) - air_handler = OpenStudio::Model::addSystemType4(model).to_AirLoopHVAC.get - + air_handler = OpenStudio::Model.addSystemType4(model).to_AirLoopHVAC.get + # Set name of Air Loop to be thermal_zone + 'Airloop' # Local variable name convention for a non-constant (dynamic) value is 'snake_case' base_name = z.name.to_s air_handler.setName(base_name + ' AirLoop') - - + # Get existing fan, created with System 4, constant volume by default - old_fan = air_handler.supplyComponents(OpenStudio::Model::FanConstantVolume::iddObjectType).first + old_fan = air_handler.supplyComponents(OpenStudio::Model::FanConstantVolume.iddObjectType).first old_fan = old_fan.to_FanConstantVolume.get - - #If you want a VFD, we replace it with a Variable Volume one + + # If you want a VFD, we replace it with a Variable Volume one if has_vfd - - # Get the outlet node after the existing fan on the loop + + # Get the outlet node after the existing fan on the loop next_node = old_fan.outletModelObject.get.to_Node.get - - #Create the new Variable speed fan + + # Create the new Variable speed fan fan = OpenStudio::Model::FanVariableVolume.new(model) - - #Add the new fan to the oulet node of the existing fan - #before deleting the existing one + + # Add the new fan to the oulet node of the existing fan + # before deleting the existing one fan.addToNode(next_node) - + # Remove the existing fan. When this happens, either the pump's # inlet or outlet node will be deleted and the other will remain old_fan.remove - - # Rename the fan clearly + + # Rename the fan clearly fan.setName(base_name + ' Variable Volume Fan') - + # If fan_pressure_rise has a non zero null value, assign it. if !fan_pressure_rise.empty? - #We need the .get because this is an OptionalDouble. the .get will return a Double (float) + # We need the .get because this is an OptionalDouble. the .get will return a Double (float) fan.setPressureRise(fan_pressure_rise.get) runner.registerInfo("Fan '#{fan.name}' was assigned pressure rise of '#{fan_pressure_rise.get}' Pa") end - + final_num_fan_VFD += 1 - + else # If VFD isn't wanted, we just rename the constant volume fan old_fan.setName(base_name + ' Constant Volume Fan') - + # If fan_pressure_rise has a non zero null value, assign it. if !fan_pressure_rise.empty? - #We need the .get because this is an OptionalDouble. the .get will return a Double (float) + # We need the .get because this is an OptionalDouble. the .get will return a Double (float) old_fan.setPressureRise(fan_pressure_rise.get) puts "Fan '#{old_fan.name}' was assigned pressure rise of '#{fan_pressure_rise.get}' Pa" end - end - + # The Cooling coil expects an OptionalDouble - coil = air_handler.supplyComponents(OpenStudio::Model::CoilCoolingDXSingleSpeed::iddObjectType).first + coil = air_handler.supplyComponents(OpenStudio::Model::CoilCoolingDXSingleSpeed.iddObjectType).first coil = coil.to_CoilCoolingDXSingleSpeed.get # Set CoolingCoil COP coil.setRatedCOP(OpenStudio::OptionalDouble.new(cop_cooling)) # Set CoolingCoil Name - coil.setName(base_name + " Coil Cooling DX Single Speed") - - + coil.setName(base_name + ' Coil Cooling DX Single Speed') + # The Heating coil expects a Double - coilheating = air_handler.supplyComponents(OpenStudio::Model::CoilHeatingDXSingleSpeed::iddObjectType).first + coilheating = air_handler.supplyComponents(OpenStudio::Model::CoilHeatingDXSingleSpeed.iddObjectType).first coilheating = coilheating.to_CoilHeatingDXSingleSpeed.get # Set HeatingCoil COP coilheating.setRatedCOP(cop_heating) # Set HeatingCoil Name - coilheating.setName(base_name + " Coil Heating DX Single Speed") - + coilheating.setName(base_name + ' Coil Heating DX Single Speed') + # Delete the electric heating coil if unwanted if !has_electric_coil - coilheatingelec = air_handler.supplyComponents(OpenStudio::Model::CoilHeatingElectric::iddObjectType).first + coilheatingelec = air_handler.supplyComponents(OpenStudio::Model::CoilHeatingElectric.iddObjectType).first coilheatingelec.remove end - - #Enable DCV (dunno if working) + + # Enable DCV (dunno if working) if has_dcv - - #get air_handler supply components + + # get air_handler supply components supply_components = air_handler.supplyComponents - #find AirLoopHVACOutdoorAirSystem on loop + # find AirLoopHVACOutdoorAirSystem on loop supply_components.each do |supply_component| hVACComponent = supply_component.to_AirLoopHVACOutdoorAirSystem - if not hVACComponent.empty? + if !hVACComponent.empty? hVACComponent = hVACComponent.get - #get ControllerOutdoorAir + # get ControllerOutdoorAir controller_oa = hVACComponent.getControllerOutdoorAir controller_oa.setName(base_name + ' Controller Outdoor Air') - #get ControllerMechanicalVentilation + # get ControllerMechanicalVentilation controller_mv = controller_oa.controllerMechanicalVentilation - #check if demand control is enabled, if not, then enable it + # check if demand control is enabled, if not, then enable it if controller_mv.demandControlledVentilation == true initial_num_air_loops_demand_control += 1 else controller_mv.setDemandControlledVentilation(true) puts "Enabling demand control ventilation for #{air_handler.name}" - end #End of if + end # End of if final_num_air_loops_demand_control += 1 - - end #End of HVACComponent.empty? - - end #end of supply component do loop - - end #End of has_dcv loop - + + end # End of HVACComponent.empty? + end # end of supply component do loop + + end # End of has_dcv loop + # Add a branch for the zone in question air_handler.addBranchForZone(z) - - #Counter - affected_loops +=1 - - end #end of do loop on each thermal zone + # Counter + affected_loops += 1 + end # end of do loop on each thermal zone - #CLEAN-UP SECTION + # CLEAN-UP SECTION # Idea: loop on PRE-EXISTING AirLoops, delete all that don't have any zones anymore # Then loop on chiller loop, delete all that don't have a coil connected to an air loop # then loop on condenser water, delette all that don't have a chiller anymore - #If we need to delete existing HVAC loops, we'll loop on the PRE-EXISTING Loops we stored earlier + # If we need to delete existing HVAC loops, we'll loop on the PRE-EXISTING Loops we stored earlier if delete_existing - # Arrays to store the affected loops chiller_plant_loops = [] boiler_plant_loops = [] condenser_plant_loops = [] - # Display separator for clarity - runner.registerInfo("") - runner.registerInfo("========================== CLEAN-UP: AIR LOOPS ==========================") + runner.registerInfo('') + runner.registerInfo('========================== CLEAN-UP: AIR LOOPS ==========================') # Loop on the pre-existing air loops (not the ones that were created above) air_loops.each do |air_loop| - # Check if it's got a thermal zone attached left or not.. # We assume we'll delete it unless... delete_flag = true @@ -406,29 +386,29 @@ def run(model, runner, user_arguments) # If there is at least a single zone left, we can't delete it if comp.to_ThermalZone.is_initialized delete_flag = false - end #end of if - end #end of do loop on comp + end # end of if + end # end of do loop on comp # If deletion is warranted if delete_flag - #before deletion, let's get the potential associated plant loop. - if air_loop.supplyComponents(OpenStudio::Model::CoilCoolingWater::iddObjectType).empty? + # before deletion, let's get the potential associated plant loop. + if air_loop.supplyComponents(OpenStudio::Model::CoilCoolingWater.iddObjectType).empty? puts "Air loop '#{air_loop.name}' DOES NOT HAVE a CoilHeatingWater" else - cooling_coil = air_loop.supplyComponents(OpenStudio::Model::CoilCoolingWater::iddObjectType).first.to_CoilCoolingWater.get + cooling_coil = air_loop.supplyComponents(OpenStudio::Model::CoilCoolingWater.iddObjectType).first.to_CoilCoolingWater.get chiller_plant_loop = cooling_coil.plantLoop.get # Store handle in array chiller_plant_loops << chiller_plant_loop - runner.registerInfo("Air loop '#{air_loop.name}' has a CoilCoolingWater, connected to CHILLER plant loop '#{chiller_plant_loop.name }'") + runner.registerInfo("Air loop '#{air_loop.name}' has a CoilCoolingWater, connected to CHILLER plant loop '#{chiller_plant_loop.name}'") end - if air_loop.supplyComponents(OpenStudio::Model::CoilHeatingWater::iddObjectType).empty? + if air_loop.supplyComponents(OpenStudio::Model::CoilHeatingWater.iddObjectType).empty? puts "Air loop '#{air_loop.name}' DOES NOT HAVE a CoilHeatingWater" else - heating_coil = air_loop.supplyComponents(OpenStudio::Model::CoilCoolingWater::iddObjectType).first.to_CoilCoolingWater.get + heating_coil = air_loop.supplyComponents(OpenStudio::Model::CoilCoolingWater.iddObjectType).first.to_CoilCoolingWater.get boiler_plant_loop = heating_coil.plantLoop.get # Store handle in array boiler_plant_loops << boiler_plant_loop - runner.registerInfo("Air loop '#{air_loop.name}' has a CoilHeatinggWater, connected to BOILER plant loop '#{boiler_plant_loop.name }'") + runner.registerInfo("Air loop '#{air_loop.name}' has a CoilHeatinggWater, connected to BOILER plant loop '#{boiler_plant_loop.name}'") end # Now we can delete and report. @@ -437,18 +417,15 @@ def run(model, runner, user_arguments) delete_existing_air_loops += 1 else runner.registerInfo("Air Loop '#{air_loop.name}' has thermal zones and was not deleted") - end #end if delete_flag - end #end air_loops.each do - - + end # end if delete_flag + end # end air_loops.each do # Display separator for clarity - runner.registerInfo("") - runner.registerInfo("====================== CLEAN-UP: CHILLER PLANT LOOPS ======================") + runner.registerInfo('') + runner.registerInfo('====================== CLEAN-UP: CHILLER PLANT LOOPS ======================') - #First pass on plant loops: chilled water loops. + # First pass on plant loops: chilled water loops. chiller_plant_loops.each do |chiller_plant_loop| - puts "Chiller plant loop name: #{chiller_plant_loop.name}" # Check if the chiller plant loop has remaining demand components @@ -456,82 +433,79 @@ def run(model, runner, user_arguments) # Delete flag: first assumption is that yes... unless! delete_flag = true - if chiller_plant_loop.demandComponents(OpenStudio::Model::CoilCoolingWater::iddObjectType).empty? + if chiller_plant_loop.demandComponents(OpenStudio::Model::CoilCoolingWater.iddObjectType).empty? puts "Chiller Plant loop '#{chiller_plant_loop.name}' DOES NOT HAVE a CoilCoolingWater" else puts "Chiller Plant loop '#{chiller_plant_loop.name}' has a CoilCoolingWater" - cooling_coil = chiller_plant_loop.demandComponents(OpenStudio::Model::CoilCoolingWater::iddObjectType).first.to_CoilCoolingWater.get + cooling_coil = chiller_plant_loop.demandComponents(OpenStudio::Model::CoilCoolingWater.iddObjectType).first.to_CoilCoolingWater.get if cooling_coil.airLoopHVAC.empty? puts "But Cooling coil '#{cooling_coil.name}' is not connected to any airloopHVAC" else runner.registerInfo("And Cooling coil '#{cooling_coil.name}' is connected to airloopHVAC '#{cooling_coil.airLoopHVAC.get.name}' and therefore can't be deleted") # In this case, we can't delete the chiller plant loop delete_flag = false - end #end cooling_coil.airLoopHVAC.empty? + end # end cooling_coil.airLoopHVAC.empty? - end #end of chiller_plant_loop.demandComponents CoilCoolingWater + end # end of chiller_plant_loop.demandComponents CoilCoolingWater # We know it's a chiller plant so this is likely unnecessary, but better safe than sorry - if chiller_plant_loop.demandComponents(OpenStudio::Model::WaterUseConnections::iddObjectType).empty? + if chiller_plant_loop.demandComponents(OpenStudio::Model::WaterUseConnections.iddObjectType).empty? puts "Chiller Plant loop '#{chiller_plant_loop.name}' DOES NOT HAVE WaterUseConnections" else runner.registerInfo("Chiller Plant loop '#{chiller_plant_loop.name}' has WaterUseConnections and therefore can't be deleted") delete_flag = false end - # If deletion is warranted if delete_flag - #This section below is actually optional (but it's nice to only delete affected ones - #before deletion, let's get the potential associated condenser water plant loop. - if chiller_plant_loop.supplyComponents(OpenStudio::Model::ChillerElectricEIR::iddObjectType).empty? - puts "Chiller Plant loop '#{chiller_plant_loop.name}' DOES NOT HAVE an electric chiller" + # This section below is actually optional (but it's nice to only delete affected ones + # before deletion, let's get the potential associated condenser water plant loop. + if chiller_plant_loop.supplyComponents(OpenStudio::Model::ChillerElectricEIR.iddObjectType).empty? + puts "Chiller Plant loop '#{chiller_plant_loop.name}' DOES NOT HAVE an electric chiller" else - chiller = chiller_plant_loop.supplyComponents(OpenStudio::Model::ChillerElectricEIR::iddObjectType).first.to_ChillerElectricEIR.get + chiller = chiller_plant_loop.supplyComponents(OpenStudio::Model::ChillerElectricEIR.iddObjectType).first.to_ChillerElectricEIR.get puts "Chiller Plant loop '#{chiller_plant_loop.name}' has an electric chiller '#{chiller.name}' with condenser type '#{chiller.condenserType}'" # Check directly if chiller has a secondaryPlantLoop (no need to check if chiller.condenserType == 'WaterCooled' first) if chiller.secondaryPlantLoop.is_initialized # Chiller is WaterCooled therefore should be connected to a condenser water loop condenser_plant_loop = chiller.secondaryPlantLoop.get condenser_plant_loops << condenser_plant_loop - runner.registerInfo("Chiller PlantLoop '#{chiller_plant_loop.name}' has a Water Cooled chiller connected to Condenser Plant Loop '#{condenser_plant_loop.name }'") + runner.registerInfo("Chiller PlantLoop '#{chiller_plant_loop.name}' has a Water Cooled chiller connected to Condenser Plant Loop '#{condenser_plant_loop.name}'") end end # Now we can delete and report. chiller_plant_loop.remove delete_existing_chiller_loops += 1 - #Should I delete the chiller as well? It remains... + # Should I delete the chiller as well? It remains... runner.registerInfo("DELETED: Chiller PlantLoop '#{chiller_plant_loop.name}' wasn't connected to any AirLoopHVAC nor WaterUseConnections and therefore was removed") - end #end of delete_flag - - end #end of chiller_plant_loops.each do + end # end of delete_flag + end # end of chiller_plant_loops.each do # Display separator for clarity - runner.registerInfo("") - runner.registerInfo("===================== CLEAN-UP: CONDENSER PLANT LOOPS ====================") - #Second pass on plant loops: condenser water loops. + runner.registerInfo('') + runner.registerInfo('===================== CLEAN-UP: CONDENSER PLANT LOOPS ====================') + # Second pass on plant loops: condenser water loops. condenser_plant_loops.each do |condenser_plant_loop| - delete_flag = true # If it has got a chiller as a demand component, it could still be empty - if not condenser_plant_loop.demandComponents(OpenStudio::Model::ChillerElectricEIR::iddObjectType).empty? + if !condenser_plant_loop.demandComponents(OpenStudio::Model::ChillerElectricEIR.iddObjectType).empty? - chiller = condenser_plant_loop.demandComponents(OpenStudio::Model::ChillerElectricEIR::iddObjectType).first.to_ChillerElectricEIR.get + chiller = condenser_plant_loop.demandComponents(OpenStudio::Model::ChillerElectricEIR.iddObjectType).first.to_ChillerElectricEIR.get # If chiller is actually connected to a chilled water node, then we shall not delete it - if not chiller.chilledWaterInletNodeName.empty? - runner.registerInfo("On Condenser PlantLoop '#{condenser_plant_loop.name}, there is a demand component of type Chiller '#{chiller.name}'" + - " that is connected to a chilled water loop and therefore cannot be deleted") + if !chiller.chilledWaterInletNodeName.empty? + runner.registerInfo("On Condenser PlantLoop '#{condenser_plant_loop.name}, there is a demand component of type Chiller '#{chiller.name}'" \ + ' that is connected to a chilled water loop and therefore cannot be deleted') delete_flag = false else puts "Plant loop '#{condenser_plant_loop.name}, Chiller '#{chiller.name}' isn't connected to a chilled water loop" - end #end of if chiller.chilledWaterInletNodeName - end #end of plant_loop.demandComponents + end # end of if chiller.chilledWaterInletNodeName + end # end of plant_loop.demandComponents # if deletion is warranted if delete_flag @@ -539,104 +513,94 @@ def run(model, runner, user_arguments) delete_existing_condenser_loops += 1 runner.registerInfo("DELETED: Plant loop '#{condenser_plant_loop.name}' isn't connected to any chilled water loop") end - - end - runner.registerInfo("") + runner.registerInfo('') runner.registerInfo("For more information, go to 'Advanced Output'") # This is the generic way of looping on all loops, checking if it's a condenser plant loop, and to delete it unless it's got a chiller that is connected to chilled water plant loop -=begin - plant_loops.each do |plant_loop| - # Skip the chiller_plant_loops - #next if chiller_plant_loops.include? plant_loop - if chiller_plant_loops.include? plant_loop - runner.registerInfo("Skipping Plant loop '#{plant_loop.name}' because it is a chiller plant") - next - end - runner.registerInfo("Plant loop '#{plant_loop.name}'") - - # Until we know that it is a condenser loop for sure, we assume we can't delete it - delete_flag = false - - # If it has got a chiller as a demand component, it's a condenser water loop - if not plant_loop.demandComponents(OpenStudio::Model::ChillerElectricEIR::iddObjectType).empty? - # Now, we assume we'll delete the loop unless it's actually connected and therefore usefull - delete_flag = true - chiller = plant_loop.demandComponents(OpenStudio::Model::ChillerElectricEIR::iddObjectType).first.to_ChillerElectricEIR.get - # If chiller is actually connected to a chilled water node, then we shall not delete it - if not chiller.chilledWaterInletNodeName.empty? - runner.registerInfo("On Condenser PlantLoop '#{plant_loop.name}, there is a demand component of type Chiller '#{chiller.name}'" + - " that is connected to a chilled water loop and therefore cannot be deleted") - delete_flag = false - else - runner.registerInfo("Plant loop '#{plant_loop.name}, Chiller '#{chiller.name}' isn't connected to a chilled water loop") - end #end of if chiller.chilledWaterInletNodeName - end #end of plant_loop.demandComponents - - # if deletion is warranted - if delete_flag - plant_loop.remove - delete_existing_condenser_loops += 1 - runner.registerInfo("DELETED: Plant loop '#{plant_loop.name}'") - end - - end #end of plant_loops.each do -=end - - #Third pass on plant loops: boiler water loops. + # plant_loops.each do |plant_loop| + # # Skip the chiller_plant_loops + # #next if chiller_plant_loops.include? plant_loop + # if chiller_plant_loops.include? plant_loop + # runner.registerInfo("Skipping Plant loop '#{plant_loop.name}' because it is a chiller plant") + # next + # end + # runner.registerInfo("Plant loop '#{plant_loop.name}'") + # + # # Until we know that it is a condenser loop for sure, we assume we can't delete it + # delete_flag = false + # + # # If it has got a chiller as a demand component, it's a condenser water loop + # if not plant_loop.demandComponents(OpenStudio::Model::ChillerElectricEIR::iddObjectType).empty? + # # Now, we assume we'll delete the loop unless it's actually connected and therefore usefull + # delete_flag = true + # chiller = plant_loop.demandComponents(OpenStudio::Model::ChillerElectricEIR::iddObjectType).first.to_ChillerElectricEIR.get + # # If chiller is actually connected to a chilled water node, then we shall not delete it + # if not chiller.chilledWaterInletNodeName.empty? + # runner.registerInfo("On Condenser PlantLoop '#{plant_loop.name}, there is a demand component of type Chiller '#{chiller.name}'" + + # " that is connected to a chilled water loop and therefore cannot be deleted") + # delete_flag = false + # else + # runner.registerInfo("Plant loop '#{plant_loop.name}, Chiller '#{chiller.name}' isn't connected to a chilled water loop") + # end #end of if chiller.chilledWaterInletNodeName + # end #end of plant_loop.demandComponents + # + # # if deletion is warranted + # if delete_flag + # plant_loop.remove + # delete_existing_condenser_loops += 1 + # runner.registerInfo("DELETED: Plant loop '#{plant_loop.name}'") + # end + # + # end #end of plant_loops.each do + + # Third pass on plant loops: boiler water loops. # TO WRITE + end # end of if delete_existing - end #end of if delete_existing - - #Report Initial Condition + # Report Initial Condition if delete_existing air_loop_str = "\n #{delete_existing_air_loops} existing AirLoopHVACs have been deleted" chiller_plant_loop_str = "\n #{delete_existing_chiller_loops} existing Chiller PlantLoops have been deleted" condenser_plant_loop_str = "\n #{delete_existing_condenser_loops} existing Condenser PlantLoops have been deleted" else - air_loop_str = "" - chiller_plant_loop_str = "" - condenser_plant_loop_str = "" - end #end of delete_existing + air_loop_str = '' + chiller_plant_loop_str = '' + condenser_plant_loop_str = '' + end # end of delete_existing runner.registerInitialCondition("Initially #{initial_num_air_loops_demand_control} air loops had demand controlled ventilation enabled" + air_loop_str + chiller_plant_loop_str + condenser_plant_loop_str + "\n") - - # Report final condition - base_str = "There are #{OpenStudio::toNeatString(affected_loops, 0, true)} zones for which a PSZ-HP system was " + - "created with a Cooling COP (SI) of #{OpenStudio::toNeatString(cop_cooling, 2, true)} " + - "and a Heating COP (SI) of #{OpenStudio::toNeatString(cop_heating, 2, true)}." - + base_str = "There are #{OpenStudio.toNeatString(affected_loops, 0, true)} zones for which a PSZ-HP system was " \ + "created with a Cooling COP (SI) of #{OpenStudio.toNeatString(cop_cooling, 2, true)} " \ + "and a Heating COP (SI) of #{OpenStudio.toNeatString(cop_heating, 2, true)}." + if has_electric_coil - elec_str = "Supplementary electric heating coils were added." + elec_str = 'Supplementary electric heating coils were added.' else - elec_str = "Supplementary electrical heating coils were NOT included." + elec_str = 'Supplementary electrical heating coils were NOT included.' end # end of has_electric_coil - + if has_vfd fan_str = "Fan type was changed to be Variable Volume (VFD) for #{final_num_fan_VFD} fans." else - fan_str = "Fan type was chosen to be Constant Volume." + fan_str = 'Fan type was chosen to be Constant Volume.' end # end of has_vfd - + if final_num_air_loops_demand_control == 0 dcv_str = "Demand Controlled Ventilation wasn't enabled for the new air loops" else dcv_str = "#{final_num_air_loops_demand_control} air loops now have demand controlled ventilation enabled" end - + runner.registerFinalCondition(base_str + "\n" + elec_str + "\n" + fan_str + "\n" + dcv_str + "\n \n") - + return true - - end # end the run method - end # end the measure # this allows the measure to be used by the application diff --git a/lib/measures/add_energy_recovery_ventilator/measure.rb b/lib/measures/add_energy_recovery_ventilator/measure.rb index e220f43..d78c538 100644 --- a/lib/measures/add_energy_recovery_ventilator/measure.rb +++ b/lib/measures/add_energy_recovery_ventilator/measure.rb @@ -1,355 +1,354 @@ -#see the URL below for information on how to write OpenStudio measures +# frozen_string_literal: true + +# see the URL below for information on how to write OpenStudio measures # http://openstudio.nrel.gov/openstudio-measure-writing-guide -#see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) +# see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) # http://openstudio.nrel.gov/sites/openstudio.nrel.gov/files/nv_data/cpp_documentation_it/model/html/namespaces.html -#start the measure +# start the measure class AddEnergyRecoveryVentilator < OpenStudio::Ruleset::ModelUserScript - - #define the name that a user will see, this method may be deprecated as - #the display name in PAT comes from the name field in measure.xml + # define the name that a user will see, this method may be deprecated as + # the display name in PAT comes from the name field in measure.xml def name - return "AddEnergyRecoveryVentilator" + return 'AddEnergyRecoveryVentilator' end - - #define the arguments that the user will input - #define the arguments that the user will input - #define the arguments that the user will input + + # define the arguments that the user will input + # define the arguments that the user will input + # define the arguments that the user will input def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new - - # Determine how many air loops in model - air_loop_handles = OpenStudio::StringVector.new - air_loop_display_names = OpenStudio::StringVector.new - - # Get/show all unitary air conditioners from current loaded model. - air_loop_handles << '0' - air_loop_display_names<<'*All air loops*' - - i_air_loop = 1 - model.getAirLoopHVACs.each do |air_loop| - air_loop_handles << i_air_loop.to_s - air_loop_display_names << air_loop.name.to_s - - i_air_loop = i_air_loop + 1 - end - - if i_air_loop == 1 - info_widget = OpenStudio::Ruleset::OSArgument::makeBoolArgument("info_widget", true) - info_widget.setDisplayName("!!!!*** This Measure is not Applicable to loaded Model. Read the description and choose an appropriate baseline model. ***!!!!") - info_widget.setDefaultValue(true) - args << info_widget - return args - end - - air_loop_widget = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("air_loop_widget", air_loop_handles, air_loop_display_names,true) - air_loop_widget.setDisplayName("Apply the measure to ") - air_loop_widget.setDefaultValue(air_loop_display_names[0]) - args << air_loop_widget - - # Sensible Effectiveness at 100% Heating Air Flow (default of 0.76) - sensible_eff_at_100_heating = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("sensible_eff_at_100_heating", false) - sensible_eff_at_100_heating.setDisplayName("Sensible Effectiveness at 100% Heating Air Flow") - sensible_eff_at_100_heating.setDefaultValue(0.76) - args << sensible_eff_at_100_heating - - # Latent Effectiveness at 100% Heating Air Flow (default of 0.76) - latent_eff_at_100_heating = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("latent_eff_at_100_heating", false) - latent_eff_at_100_heating.setDisplayName("Latent Effectiveness at 100% Heating Air Flow") - latent_eff_at_100_heating.setDefaultValue(0.68) - args << latent_eff_at_100_heating - - # Sensible Effectiveness at 75% Heating Air Flow (default of 0.76) - sensible_eff_at_75_heating = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("sensible_eff_at_75_heating", false) - sensible_eff_at_75_heating.setDisplayName("Sensible Effectiveness at 75% Heating Air Flow") - sensible_eff_at_75_heating.setDefaultValue(0.81) - args << sensible_eff_at_75_heating - - # Latent Effectiveness at 100% Heating Air Flow (default of 0.76) - latent_eff_at_75_heating = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("latent_eff_at_75_heating", false) - latent_eff_at_75_heating.setDisplayName("Latent Effectiveness at 75% Heating Air Flow") - latent_eff_at_75_heating.setDefaultValue(0.73) - args << latent_eff_at_75_heating - - # Sensible Effectiveness at 100% Cooling Air Flow (default of 0.76) - sensible_eff_at_100_cooling = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("sensible_eff_at_100_cooling", false) - sensible_eff_at_100_cooling.setDisplayName("Sensible Effectiveness at 100% Cooling Air Flow") - sensible_eff_at_100_cooling.setDefaultValue(0.76) - args << sensible_eff_at_100_cooling - - # Latent Effectiveness at 100% Cooling Air Flow (default of 0.76) - latent_eff_at_100_cooling = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("latent_eff_at_100_cooling", false) - latent_eff_at_100_cooling.setDisplayName("Latent Effectiveness at 100% Cooling Air Flow") - latent_eff_at_100_cooling.setDefaultValue(0.68) - args << latent_eff_at_100_cooling - - # Sensible Effectiveness at 75% Cooling Air Flow (default of 0.76) - sensible_eff_at_75_cooling = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("sensible_eff_at_75_cooling", false) - sensible_eff_at_75_cooling.setDisplayName("Sensible Effectiveness at 75% Cooling Air Flow") - sensible_eff_at_75_cooling.setDefaultValue(0.81) - args << sensible_eff_at_75_cooling - - # Latent Effectiveness at 100% Cooling Air Flow (default of 0.76) - latent_eff_at_75_cooling = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("latent_eff_at_75_cooling", false) - latent_eff_at_75_cooling.setDisplayName("Latent Effectiveness at 75% Cooling Air Flow") - latent_eff_at_75_cooling.setDefaultValue(0.73) - args << latent_eff_at_75_cooling - - # Show ASHRAE standards - heat_exchanger_type_handles = OpenStudio::StringVector.new - heat_exchanger_type_display_names = OpenStudio::StringVector.new - - heat_exchanger_type_handles << '0' - heat_exchanger_type_display_names << 'Rotary' - - heat_exchanger_type_widget = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("heat_exchanger_type_widget", heat_exchanger_type_handles, heat_exchanger_type_display_names,true) - heat_exchanger_type_widget.setDisplayName("Heat Exchanger Type.") - heat_exchanger_type_widget.setDefaultValue(heat_exchanger_type_display_names[0]) - args << heat_exchanger_type_widget - - # Nominal electric power [W] (Note: this is optional. If no value is entered, do nothing) - nominal_electric_power = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("nominal_electric_power", false) - nominal_electric_power.setDisplayName("Nominal electric power [W]") - args << nominal_electric_power + + # Determine how many air loops in model + air_loop_handles = OpenStudio::StringVector.new + air_loop_display_names = OpenStudio::StringVector.new + + # Get/show all unitary air conditioners from current loaded model. + air_loop_handles << '0' + air_loop_display_names << '*All air loops*' + + i_air_loop = 1 + model.getAirLoopHVACs.each do |air_loop| + air_loop_handles << i_air_loop.to_s + air_loop_display_names << air_loop.name.to_s + + i_air_loop += 1 + end + + if i_air_loop == 1 + info_widget = OpenStudio::Ruleset::OSArgument.makeBoolArgument('info_widget', true) + info_widget.setDisplayName('!!!!*** This Measure is not Applicable to loaded Model. Read the description and choose an appropriate baseline model. ***!!!!') + info_widget.setDefaultValue(true) + args << info_widget + return args + end + + air_loop_widget = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('air_loop_widget', air_loop_handles, air_loop_display_names, true) + air_loop_widget.setDisplayName('Apply the measure to ') + air_loop_widget.setDefaultValue(air_loop_display_names[0]) + args << air_loop_widget + + # Sensible Effectiveness at 100% Heating Air Flow (default of 0.76) + sensible_eff_at_100_heating = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('sensible_eff_at_100_heating', false) + sensible_eff_at_100_heating.setDisplayName('Sensible Effectiveness at 100% Heating Air Flow') + sensible_eff_at_100_heating.setDefaultValue(0.76) + args << sensible_eff_at_100_heating + + # Latent Effectiveness at 100% Heating Air Flow (default of 0.76) + latent_eff_at_100_heating = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('latent_eff_at_100_heating', false) + latent_eff_at_100_heating.setDisplayName('Latent Effectiveness at 100% Heating Air Flow') + latent_eff_at_100_heating.setDefaultValue(0.68) + args << latent_eff_at_100_heating + + # Sensible Effectiveness at 75% Heating Air Flow (default of 0.76) + sensible_eff_at_75_heating = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('sensible_eff_at_75_heating', false) + sensible_eff_at_75_heating.setDisplayName('Sensible Effectiveness at 75% Heating Air Flow') + sensible_eff_at_75_heating.setDefaultValue(0.81) + args << sensible_eff_at_75_heating + + # Latent Effectiveness at 100% Heating Air Flow (default of 0.76) + latent_eff_at_75_heating = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('latent_eff_at_75_heating', false) + latent_eff_at_75_heating.setDisplayName('Latent Effectiveness at 75% Heating Air Flow') + latent_eff_at_75_heating.setDefaultValue(0.73) + args << latent_eff_at_75_heating + + # Sensible Effectiveness at 100% Cooling Air Flow (default of 0.76) + sensible_eff_at_100_cooling = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('sensible_eff_at_100_cooling', false) + sensible_eff_at_100_cooling.setDisplayName('Sensible Effectiveness at 100% Cooling Air Flow') + sensible_eff_at_100_cooling.setDefaultValue(0.76) + args << sensible_eff_at_100_cooling + + # Latent Effectiveness at 100% Cooling Air Flow (default of 0.76) + latent_eff_at_100_cooling = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('latent_eff_at_100_cooling', false) + latent_eff_at_100_cooling.setDisplayName('Latent Effectiveness at 100% Cooling Air Flow') + latent_eff_at_100_cooling.setDefaultValue(0.68) + args << latent_eff_at_100_cooling + + # Sensible Effectiveness at 75% Cooling Air Flow (default of 0.76) + sensible_eff_at_75_cooling = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('sensible_eff_at_75_cooling', false) + sensible_eff_at_75_cooling.setDisplayName('Sensible Effectiveness at 75% Cooling Air Flow') + sensible_eff_at_75_cooling.setDefaultValue(0.81) + args << sensible_eff_at_75_cooling + + # Latent Effectiveness at 100% Cooling Air Flow (default of 0.76) + latent_eff_at_75_cooling = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('latent_eff_at_75_cooling', false) + latent_eff_at_75_cooling.setDisplayName('Latent Effectiveness at 75% Cooling Air Flow') + latent_eff_at_75_cooling.setDefaultValue(0.73) + args << latent_eff_at_75_cooling + + # Show ASHRAE standards + heat_exchanger_type_handles = OpenStudio::StringVector.new + heat_exchanger_type_display_names = OpenStudio::StringVector.new + + heat_exchanger_type_handles << '0' + heat_exchanger_type_display_names << 'Rotary' + + heat_exchanger_type_widget = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('heat_exchanger_type_widget', heat_exchanger_type_handles, heat_exchanger_type_display_names, true) + heat_exchanger_type_widget.setDisplayName('Heat Exchanger Type.') + heat_exchanger_type_widget.setDefaultValue(heat_exchanger_type_display_names[0]) + args << heat_exchanger_type_widget + + # Nominal electric power [W] (Note: this is optional. If no value is entered, do nothing) + nominal_electric_power = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('nominal_electric_power', false) + nominal_electric_power.setDisplayName('Nominal electric power [W]') + args << nominal_electric_power return args - end #end the arguments method + end # end the arguments method def reportValueChangeInfo(value_old, value_new, value_name, airloop_name, runner) - if value_old.nil? - runner.registerInfo("Initial: The #{value_name} on #{airloop_name} was not set.") - else - runner.registerInfo("Initial: The #{value_name} on #{airloop_name} was #{value_old}.") - end - runner.registerInfo("Final: The #{value_name} on #{airloop_name} was set to be #{value_new}.") - return - end - + if value_old.nil? + runner.registerInfo("Initial: The #{value_name} on #{airloop_name} was not set.") + else + runner.registerInfo("Initial: The #{value_name} on #{airloop_name} was #{value_old}.") + end + runner.registerInfo("Final: The #{value_name} on #{airloop_name} was set to be #{value_new}.") + return + end + def setSensibleEffectiveness100Cooling(erv, value_new, airloop_name, runner) - value_old = erv.getSensibleEffectivenessat100CoolingAirFlow() - erv.setSensibleEffectivenessat100CoolingAirFlow(value_new) - reportValueChangeInfo(value_old, value_new, "Sensible Effectiveness at 100% Cooling Air Flow", airloop_name, runner) - return + value_old = erv.getSensibleEffectivenessat100CoolingAirFlow + erv.setSensibleEffectivenessat100CoolingAirFlow(value_new) + reportValueChangeInfo(value_old, value_new, 'Sensible Effectiveness at 100% Cooling Air Flow', airloop_name, runner) + return end def setSensibleEffectiveness75Cooling(erv, value_new, airloop_name, runner) - value_old = erv.getSensibleEffectivenessat75CoolingAirFlow() - erv.setSensibleEffectivenessat75CoolingAirFlow(value_new) - reportValueChangeInfo(value_old, value_new, "Sensible Effectiveness at 75% Cooling Air Flow", airloop_name, runner) - return + value_old = erv.getSensibleEffectivenessat75CoolingAirFlow + erv.setSensibleEffectivenessat75CoolingAirFlow(value_new) + reportValueChangeInfo(value_old, value_new, 'Sensible Effectiveness at 75% Cooling Air Flow', airloop_name, runner) + return end def setLatentEffectiveness100Cooling(erv, value_new, airloop_name, runner) - value_old = erv.getLatentEffectivenessat100CoolingAirFlow() - erv.setLatentEffectivenessat100CoolingAirFlow(value_new) - reportValueChangeInfo(value_old, value_new, "Latent Effectiveness at 100% Cooling Air Flow", airloop_name, runner) - return + value_old = erv.getLatentEffectivenessat100CoolingAirFlow + erv.setLatentEffectivenessat100CoolingAirFlow(value_new) + reportValueChangeInfo(value_old, value_new, 'Latent Effectiveness at 100% Cooling Air Flow', airloop_name, runner) + return end def setLatentEffectiveness75Cooling(erv, value_new, airloop_name, runner) - value_old = erv.getLatentEffectivenessat75CoolingAirFlow() - erv.setLatentEffectivenessat75CoolingAirFlow(value_new) - reportValueChangeInfo(value_old, value_new, "Latent Effectiveness at 75% Cooling Air Flow", airloop_name, runner) - return - end + value_old = erv.getLatentEffectivenessat75CoolingAirFlow + erv.setLatentEffectivenessat75CoolingAirFlow(value_new) + reportValueChangeInfo(value_old, value_new, 'Latent Effectiveness at 75% Cooling Air Flow', airloop_name, runner) + return + end def setSensibleEffectiveness100Heating(erv, value_new, airloop_name, runner) - value_old = erv.getSensibleEffectivenessat100HeatingAirFlow() - erv.setSensibleEffectivenessat100HeatingAirFlow(value_new) - reportValueChangeInfo(value_old, value_new, "Sensible Effectiveness at 100% Heating Air Flow", airloop_name, runner) - return + value_old = erv.getSensibleEffectivenessat100HeatingAirFlow + erv.setSensibleEffectivenessat100HeatingAirFlow(value_new) + reportValueChangeInfo(value_old, value_new, 'Sensible Effectiveness at 100% Heating Air Flow', airloop_name, runner) + return end def setSensibleEffectiveness75Heating(erv, value_new, airloop_name, runner) - value_old = erv.getSensibleEffectivenessat75HeatingAirFlow() - erv.setSensibleEffectivenessat75HeatingAirFlow(value_new) - reportValueChangeInfo(value_old, value_new, "Sensible Effectiveness at 75% Heating Air Flow", airloop_name, runner) - return + value_old = erv.getSensibleEffectivenessat75HeatingAirFlow + erv.setSensibleEffectivenessat75HeatingAirFlow(value_new) + reportValueChangeInfo(value_old, value_new, 'Sensible Effectiveness at 75% Heating Air Flow', airloop_name, runner) + return end def setLatentEffectiveness100Heating(erv, value_new, airloop_name, runner) - value_old = erv.getLatentEffectivenessat100HeatingAirFlow() - erv.setLatentEffectivenessat100HeatingAirFlow(value_new) - reportValueChangeInfo(value_old, value_new, "Latent Effectiveness at 100% Heating Air Flow", airloop_name, runner) - return + value_old = erv.getLatentEffectivenessat100HeatingAirFlow + erv.setLatentEffectivenessat100HeatingAirFlow(value_new) + reportValueChangeInfo(value_old, value_new, 'Latent Effectiveness at 100% Heating Air Flow', airloop_name, runner) + return end def setLatentEffectiveness75Heating(erv, value_new, airloop_name, runner) - value_old = erv.getLatentEffectivenessat75HeatingAirFlow() - erv.setLatentEffectivenessat75HeatingAirFlow(value_new) - reportValueChangeInfo(value_old, value_new, "Latent Effectiveness at 75% Heating Air Flow", airloop_name, runner) - return - end - + value_old = erv.getLatentEffectivenessat75HeatingAirFlow + erv.setLatentEffectivenessat75HeatingAirFlow(value_new) + reportValueChangeInfo(value_old, value_new, 'Latent Effectiveness at 75% Heating Air Flow', airloop_name, runner) + return + end + def setNominalElectricPower(erv, value_new, airloop_name, runner) - value_old = erv.getNominalElectricPower() - erv.setNominalElectricPower(value_new) - reportValueChangeInfo(value_old, value_new, "Nominal electric power", airloop_name, runner) - return - end - + value_old = erv.getNominalElectricPower + erv.setNominalElectricPower(value_new) + reportValueChangeInfo(value_old, value_new, 'Nominal electric power', airloop_name, runner) + return + end + def isOutOfRange(value_new, value_name, runner) - if value_new < 0 or value_new > 1 - runner.registerError("OutOfBound! The #{value_name} must be between 0 and 1. Reset the value.") - return true - end - return false + if (value_new < 0) || (value_new > 1) + runner.registerError("OutOfBound! The #{value_name} must be between 0 and 1. Reset the value.") + return true + end + return false end - - #define what happens when the measure is run + + # define what happens when the measure is run def run(model, runner, user_arguments) super(model, runner, user_arguments) - - #use the built-in error checking - if not runner.validateUserArguments(arguments(model), user_arguments) + + # use the built-in error checking + if !runner.validateUserArguments(arguments(model), user_arguments) return false end - # Determine if the measure is applicable to the model, if not just return and no changes are made. - info_widget = runner.getOptionalWorkspaceObjectChoiceValue("info_widget",user_arguments,model) - if not (info_widget.nil? or info_widget.empty?) - runner.registerInfo("This measure is not applicable.") - return true - end - - air_loop_widget = runner.getOptionalWorkspaceObjectChoiceValue("air_loop_widget",user_arguments,model) - handle = runner.getStringArgumentValue("air_loop_widget",user_arguments) - air_loop_index = handle.to_i - - sensible_eff_at_100_heating = runner.getDoubleArgumentValue("sensible_eff_at_100_heating",user_arguments) - latent_eff_at_100_heating = runner.getDoubleArgumentValue("latent_eff_at_100_heating",user_arguments) - sensible_eff_at_75_heating = runner.getDoubleArgumentValue("sensible_eff_at_75_heating",user_arguments) - latent_eff_at_75_heating = runner.getDoubleArgumentValue("latent_eff_at_75_heating",user_arguments) - - sensible_eff_at_100_cooling = runner.getDoubleArgumentValue("sensible_eff_at_100_cooling",user_arguments) - latent_eff_at_100_cooling = runner.getDoubleArgumentValue("latent_eff_at_100_cooling",user_arguments) - sensible_eff_at_75_cooling = runner.getDoubleArgumentValue("sensible_eff_at_75_cooling",user_arguments) - latent_eff_at_75_cooling = runner.getDoubleArgumentValue("latent_eff_at_75_cooling",user_arguments) - - if isOutOfRange(sensible_eff_at_100_heating, "sensible_eff_at_100_heating", runner) - return false - end - if isOutOfRange(latent_eff_at_100_heating, "latent_eff_at_100_heating", runner) - return false - end - if isOutOfRange(sensible_eff_at_75_heating, "sensible_eff_at_75_heating", runner) - return false - end - if isOutOfRange(latent_eff_at_75_heating, "latent_eff_at_75_heating", runner) - return false - end - if isOutOfRange(sensible_eff_at_100_cooling, "sensible_eff_at_100_cooling", runner) - return false - end - if isOutOfRange(latent_eff_at_100_cooling, "latent_eff_at_100_cooling", runner) - return false - end - if isOutOfRange(sensible_eff_at_75_cooling, "sensible_eff_at_75_cooling", runner) - return false - end - if isOutOfRange(latent_eff_at_75_cooling, "latent_eff_at_75_cooling", runner) - return false - end - - heat_exchanger_type_widget = runner.getOptionalWorkspaceObjectChoiceValue("heat_exchanger_type_widget",user_arguments,model) - handle = runner.getStringArgumentValue("heat_exchanger_type_widget",user_arguments) - heat_exchanger_type_index = handle.to_i - - heat_exchanger_type_list = ["Rotary"] - heat_type = heat_exchanger_type_list[heat_exchanger_type_index] - - nominal_electric_power = runner.getOptionalDoubleArgumentValue("nominal_electric_power",user_arguments) - if nominal_electric_power.empty? - nominal_electric_power = nil - else - nominal_electric_power = runner.getDoubleArgumentValue("nominal_electric_power",user_arguments) - end - - # loop through all air loops - i_air_loop = 0 - model.getAirLoopHVACs.each do |air_loop| - #check if the airloop already has an ERV either on a specified air loop or all air loops - i_air_loop = i_air_loop + 1 - if air_loop_index != 0 and (air_loop_index != i_air_loop) - next - end - - has_ERV = false - air_loop.supplyComponents.each do |supply_component| - #check if the supply component is an ERV - if not supply_component.to_HeatExchangerAirToAirSensibleAndLatent.empty? - has_ERV = true - erv = supply_component.to_HeatExchangerAirToAirSensibleAndLatent.get - erv.setHeatExchangerType(heat_type) - setSensibleEffectiveness100Cooling(erv, sensible_eff_at_100_cooling, air_loop.name, runner) - setSensibleEffectiveness75Cooling(erv, sensible_eff_at_75_cooling, air_loop.name, runner) - setLatentEffectiveness100Cooling(erv, latent_eff_at_100_cooling, air_loop.name, runner) - setLatentEffectiveness75Cooling(erv, latent_eff_at_75_cooling, air_loop.name, runner) - - setSensibleEffectiveness100Heating(erv, sensible_eff_at_100_heating, air_loop.name, runner) - setSensibleEffectiveness75Heating(erv, sensible_eff_at_75_heating, air_loop.name, runner) - setLatentEffectiveness100Heating(erv, latent_eff_at_100_heating, air_loop.name, runner) - setLatentEffectiveness75Heating(erv, latent_eff_at_75_heating, air_loop.name, runner) - - #erv.setEconomizerLockout('Yes') - #erv.setEconomizerLockout(true) - erv.setString(23, "Yes") - - #erv.setSupplyAirOutletTemperatureControl ('No') - #erv.setSupplyAirOutletTemperatureControl (false) - erv.setString(17, "No") - if not nominal_electric_power.nil? - setNominalElectricPower(erv, nominal_electric_power, air_loop.name, runner) - end - end - end - air_loop.supplyComponents.each do |supply_component| - #if no ERV was found, see if the air loop has an outdoor air system - if has_ERV == false - if not supply_component.to_AirLoopHVACOutdoorAirSystem.empty? - #get the outdoor air system - oa_system = supply_component.to_AirLoopHVACOutdoorAirSystem.get - #create a new heat exchanger and add it to the outdoor air system - erv = OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent.new(model) - oa_node = oa_system.outboardOANode - if not oa_node.empty? - #set node connection - erv.addToNode(oa_node.get) - #set required fields to a single default value - erv.setHeatExchangerType(heat_type) - setSensibleEffectiveness100Cooling(erv, sensible_eff_at_100_cooling, air_loop.name, runner) - setSensibleEffectiveness75Cooling(erv, sensible_eff_at_75_cooling, air_loop.name, runner) - setLatentEffectiveness100Cooling(erv, latent_eff_at_100_cooling, air_loop.name, runner) - setLatentEffectiveness75Cooling(erv, latent_eff_at_75_cooling, air_loop.name, runner) - - setSensibleEffectiveness100Heating(erv, sensible_eff_at_100_heating, air_loop.name, runner) - setSensibleEffectiveness75Heating(erv, sensible_eff_at_75_heating, air_loop.name, runner) - setLatentEffectiveness100Heating(erv, latent_eff_at_100_heating, air_loop.name, runner) - setLatentEffectiveness75Heating(erv, latent_eff_at_75_heating, air_loop.name, runner) - - # Temporary solution, may need to fix later. 12/22/2013 Da - #erv.setEconomizerLockout('Yes') - #erv.setEconomizerLockout(true) - erv.setString(23, "Yes") - - #erv.setSupplyAirOutletTemperatureControl ('No') - #erv.setSupplyAirOutletTemperatureControl (false) - erv.setString(17, "No") - - if not nominal_electric_power.nil? - setNominalElectricPower(erv, nominal_electric_power, air_loop.name, runner) - end - end - end - end - end - end - return true - - end #end the run method + # Determine if the measure is applicable to the model, if not just return and no changes are made. + info_widget = runner.getOptionalWorkspaceObjectChoiceValue('info_widget', user_arguments, model) + if !(info_widget.nil? || info_widget.empty?) + runner.registerInfo('This measure is not applicable.') + return true + end -end #end the measure + air_loop_widget = runner.getOptionalWorkspaceObjectChoiceValue('air_loop_widget', user_arguments, model) + handle = runner.getStringArgumentValue('air_loop_widget', user_arguments) + air_loop_index = handle.to_i + + sensible_eff_at_100_heating = runner.getDoubleArgumentValue('sensible_eff_at_100_heating', user_arguments) + latent_eff_at_100_heating = runner.getDoubleArgumentValue('latent_eff_at_100_heating', user_arguments) + sensible_eff_at_75_heating = runner.getDoubleArgumentValue('sensible_eff_at_75_heating', user_arguments) + latent_eff_at_75_heating = runner.getDoubleArgumentValue('latent_eff_at_75_heating', user_arguments) + + sensible_eff_at_100_cooling = runner.getDoubleArgumentValue('sensible_eff_at_100_cooling', user_arguments) + latent_eff_at_100_cooling = runner.getDoubleArgumentValue('latent_eff_at_100_cooling', user_arguments) + sensible_eff_at_75_cooling = runner.getDoubleArgumentValue('sensible_eff_at_75_cooling', user_arguments) + latent_eff_at_75_cooling = runner.getDoubleArgumentValue('latent_eff_at_75_cooling', user_arguments) + + if isOutOfRange(sensible_eff_at_100_heating, 'sensible_eff_at_100_heating', runner) + return false + end + if isOutOfRange(latent_eff_at_100_heating, 'latent_eff_at_100_heating', runner) + return false + end + if isOutOfRange(sensible_eff_at_75_heating, 'sensible_eff_at_75_heating', runner) + return false + end + if isOutOfRange(latent_eff_at_75_heating, 'latent_eff_at_75_heating', runner) + return false + end + if isOutOfRange(sensible_eff_at_100_cooling, 'sensible_eff_at_100_cooling', runner) + return false + end + if isOutOfRange(latent_eff_at_100_cooling, 'latent_eff_at_100_cooling', runner) + return false + end + if isOutOfRange(sensible_eff_at_75_cooling, 'sensible_eff_at_75_cooling', runner) + return false + end + if isOutOfRange(latent_eff_at_75_cooling, 'latent_eff_at_75_cooling', runner) + return false + end + + heat_exchanger_type_widget = runner.getOptionalWorkspaceObjectChoiceValue('heat_exchanger_type_widget', user_arguments, model) + handle = runner.getStringArgumentValue('heat_exchanger_type_widget', user_arguments) + heat_exchanger_type_index = handle.to_i + + heat_exchanger_type_list = ['Rotary'] + heat_type = heat_exchanger_type_list[heat_exchanger_type_index] + + nominal_electric_power = runner.getOptionalDoubleArgumentValue('nominal_electric_power', user_arguments) + if nominal_electric_power.empty? + nominal_electric_power = nil + else + nominal_electric_power = runner.getDoubleArgumentValue('nominal_electric_power', user_arguments) + end + + # loop through all air loops + i_air_loop = 0 + model.getAirLoopHVACs.each do |air_loop| + # check if the airloop already has an ERV either on a specified air loop or all air loops + i_air_loop += 1 + if (air_loop_index != 0) && (air_loop_index != i_air_loop) + next + end + + has_ERV = false + air_loop.supplyComponents.each do |supply_component| + # check if the supply component is an ERV + if !supply_component.to_HeatExchangerAirToAirSensibleAndLatent.empty? + has_ERV = true + erv = supply_component.to_HeatExchangerAirToAirSensibleAndLatent.get + erv.setHeatExchangerType(heat_type) + setSensibleEffectiveness100Cooling(erv, sensible_eff_at_100_cooling, air_loop.name, runner) + setSensibleEffectiveness75Cooling(erv, sensible_eff_at_75_cooling, air_loop.name, runner) + setLatentEffectiveness100Cooling(erv, latent_eff_at_100_cooling, air_loop.name, runner) + setLatentEffectiveness75Cooling(erv, latent_eff_at_75_cooling, air_loop.name, runner) + + setSensibleEffectiveness100Heating(erv, sensible_eff_at_100_heating, air_loop.name, runner) + setSensibleEffectiveness75Heating(erv, sensible_eff_at_75_heating, air_loop.name, runner) + setLatentEffectiveness100Heating(erv, latent_eff_at_100_heating, air_loop.name, runner) + setLatentEffectiveness75Heating(erv, latent_eff_at_75_heating, air_loop.name, runner) + + # erv.setEconomizerLockout('Yes') + # erv.setEconomizerLockout(true) + erv.setString(23, 'Yes') + + # erv.setSupplyAirOutletTemperatureControl ('No') + # erv.setSupplyAirOutletTemperatureControl (false) + erv.setString(17, 'No') + if !nominal_electric_power.nil? + setNominalElectricPower(erv, nominal_electric_power, air_loop.name, runner) + end + end + end + air_loop.supplyComponents.each do |supply_component| + # if no ERV was found, see if the air loop has an outdoor air system + if has_ERV == false + if !supply_component.to_AirLoopHVACOutdoorAirSystem.empty? + # get the outdoor air system + oa_system = supply_component.to_AirLoopHVACOutdoorAirSystem.get + # create a new heat exchanger and add it to the outdoor air system + erv = OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent.new(model) + oa_node = oa_system.outboardOANode + if !oa_node.empty? + # set node connection + erv.addToNode(oa_node.get) + # set required fields to a single default value + erv.setHeatExchangerType(heat_type) + setSensibleEffectiveness100Cooling(erv, sensible_eff_at_100_cooling, air_loop.name, runner) + setSensibleEffectiveness75Cooling(erv, sensible_eff_at_75_cooling, air_loop.name, runner) + setLatentEffectiveness100Cooling(erv, latent_eff_at_100_cooling, air_loop.name, runner) + setLatentEffectiveness75Cooling(erv, latent_eff_at_75_cooling, air_loop.name, runner) + + setSensibleEffectiveness100Heating(erv, sensible_eff_at_100_heating, air_loop.name, runner) + setSensibleEffectiveness75Heating(erv, sensible_eff_at_75_heating, air_loop.name, runner) + setLatentEffectiveness100Heating(erv, latent_eff_at_100_heating, air_loop.name, runner) + setLatentEffectiveness75Heating(erv, latent_eff_at_75_heating, air_loop.name, runner) + + # Temporary solution, may need to fix later. 12/22/2013 Da + # erv.setEconomizerLockout('Yes') + # erv.setEconomizerLockout(true) + erv.setString(23, 'Yes') + + # erv.setSupplyAirOutletTemperatureControl ('No') + # erv.setSupplyAirOutletTemperatureControl (false) + erv.setString(17, 'No') + + if !nominal_electric_power.nil? + setNominalElectricPower(erv, nominal_electric_power, air_loop.name, runner) + end + end + end + end + end + end + return true + end # end the run method +end # end the measure -#this allows the measure to be use by the application -AddEnergyRecoveryVentilator.new.registerWithApplication \ No newline at end of file +# this allows the measure to be use by the application +AddEnergyRecoveryVentilator.new.registerWithApplication diff --git a/lib/measures/add_energy_recovery_ventilator/tests/AddEnergyRecoveryVentilator_Test.rb b/lib/measures/add_energy_recovery_ventilator/tests/AddEnergyRecoveryVentilator_Test.rb index d2e7d14..ce32db1 100644 --- a/lib/measures/add_energy_recovery_ventilator/tests/AddEnergyRecoveryVentilator_Test.rb +++ b/lib/measures/add_energy_recovery_ventilator/tests/AddEnergyRecoveryVentilator_Test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'openstudio' require 'openstudio/ruleset/ShowRunnerOutput' @@ -6,55 +8,51 @@ require 'test/unit' class AddEnergyRecoveryVentilator_Test < Test::Unit::TestCase - # def setup # end # def teardown # end - + def test_AddEnergyRecoveryVentilator - # create an instance of the measure measure = AddEnergyRecoveryVentilator.new - + # create an instance of a runner runner = OpenStudio::Ruleset::OSRunner.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(2, arguments.size) - assert_equal("user_name", arguments[0].name) - assert_equal("add_space", arguments[1].name) - assert((not arguments[0].hasDefaultValue)) + assert_equal('user_name', arguments[0].name) + assert_equal('add_space', arguments[1].name) + assert(!arguments[0].hasDefaultValue) # set argument values to bad values and run the measure argument_map = OpenStudio::Ruleset::OSArgumentMap.new user_name = arguments[0].clone - assert(user_name.setValue("")) - argument_map["user_name"] = user_name + assert(user_name.setValue('')) + argument_map['user_name'] = user_name measure.run(model, runner, argument_map) result = runner.result - assert(result.value.valueName == "Fail") - + assert(result.value.valueName == 'Fail') + # set argument values to good values and run the measure on model with spaces argument_map = OpenStudio::Ruleset::OSArgumentMap.new user_name = arguments[0].clone - assert(user_name.setValue("david")) - argument_map["user_name"] = user_name + assert(user_name.setValue('david')) + argument_map['user_name'] = user_name add_space = arguments[1].clone assert(add_space.setValue(true)) - argument_map["add_space"] = add_space + argument_map['add_space'] = add_space measure.run(model, runner, argument_map) result = runner.result show_output(result) - assert(result.value.valueName == "Success") + assert(result.value.valueName == 'Success') assert(result.warnings.size == 1) assert(result.info.size == 2) - - end - + end end diff --git a/lib/measures/improve_simple_glazing_by_percentage/measure.rb b/lib/measures/improve_simple_glazing_by_percentage/measure.rb index 7107a7f..ad6a053 100644 --- a/lib/measures/improve_simple_glazing_by_percentage/measure.rb +++ b/lib/measures/improve_simple_glazing_by_percentage/measure.rb @@ -1,12 +1,13 @@ +# frozen_string_literal: true + # see the URL below for information on how to write OpenStudio measures # http://nrel.github.io/OpenStudio-user-documentation/reference/measure_writing_guide/ # start the measure class ImproveSimpleGlazingByPercentage < OpenStudio::Ruleset::ModelUserScript - # human readable name def name - return "improve_simple_glazing_by_percentage" + return 'improve_simple_glazing_by_percentage' end # define the arguments that the user will input @@ -14,22 +15,22 @@ def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new # make an argument for glazing u_value improvement percentage - u_value_improvement_percent = OpenStudio::Ruleset::OSArgument.makeDoubleArgument("u_value_improvement_percent", true) - u_value_improvement_percent.setDisplayName("U-value Improvement Percentage (%)") - u_value_improvement_percent.setDefaultValue(20) + u_value_improvement_percent = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('u_value_improvement_percent', true) + u_value_improvement_percent.setDisplayName('U-value Improvement Percentage (%)') + u_value_improvement_percent.setDefaultValue(20) args << u_value_improvement_percent - - # make an argument for glazing shgc improvement percentage - shgc_improvement_percent = OpenStudio::Ruleset::OSArgument.makeDoubleArgument("shgc_improvement_percent", true) - shgc_improvement_percent.setDisplayName("SHGC improvement Percentage (%)") - shgc_improvement_percent.setDefaultValue(20) + + # make an argument for glazing shgc improvement percentage + shgc_improvement_percent = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('shgc_improvement_percent', true) + shgc_improvement_percent.setDisplayName('SHGC improvement Percentage (%)') + shgc_improvement_percent.setDefaultValue(20) args << shgc_improvement_percent return args end # define what happens when the measure is run - def run(model, runner, user_arguments) + def run(model, runner, user_arguments) super(model, runner, user_arguments) # use the built-in error checking @@ -37,46 +38,43 @@ def run(model, runner, user_arguments) return false end - #assign the user inputs to variables - u_value_improvement_percent = runner.getDoubleArgumentValue("u_value_improvement_percent",user_arguments) - shgc_improvement_percent = runner.getDoubleArgumentValue("shgc_improvement_percent",user_arguments) - - # replace simple glazing window parameters - materials = model.getMaterials - materials.each do |material| - if material.to_SimpleGlazing.is_initialized - material_type_glazingsimple = material.to_SimpleGlazing.get - - # get the original value for reporting - u_value_old = nil - shgc_old = nil - u_value_old = material_type_glazingsimple.uFactor - shgc_old = material_type_glazingsimple.solarHeatGainCoefficient - - # Update the values from user input - material_type_glazingsimple.setUFactor(material_type_glazingsimple.uFactor - material_type_glazingsimple.uFactor * u_value_improvement_percent * 0.01) - shgc_new = material_type_glazingsimple.setSolarHeatGainCoefficient(material_type_glazingsimple.solarHeatGainCoefficient - material_type_glazingsimple.solarHeatGainCoefficient * shgc_improvement_percent * 0.01) - - # get the updated value for reporting - u_value_new = nil - shgc_new = nil - u_value_new = material_type_glazingsimple.uFactor - shgc_new = material_type_glazingsimple.solarHeatGainCoefficient - - # report initial condition of model - runner.registerInitialCondition("The building started with #{u_value_old} U-value, #{shgc_old} SHGC.") - - # report final condition of model - runner.registerFinalCondition("The building finished with #{u_value_new} U-value, #{shgc_new} SHGC.") - - end - - end + # assign the user inputs to variables + u_value_improvement_percent = runner.getDoubleArgumentValue('u_value_improvement_percent', user_arguments) + shgc_improvement_percent = runner.getDoubleArgumentValue('shgc_improvement_percent', user_arguments) - return true + # replace simple glazing window parameters + materials = model.getMaterials + materials.each do |material| + if material.to_SimpleGlazing.is_initialized + material_type_glazingsimple = material.to_SimpleGlazing.get + + # get the original value for reporting + u_value_old = nil + shgc_old = nil + u_value_old = material_type_glazingsimple.uFactor + shgc_old = material_type_glazingsimple.solarHeatGainCoefficient + + # Update the values from user input + material_type_glazingsimple.setUFactor(material_type_glazingsimple.uFactor - material_type_glazingsimple.uFactor * u_value_improvement_percent * 0.01) + shgc_new = material_type_glazingsimple.setSolarHeatGainCoefficient(material_type_glazingsimple.solarHeatGainCoefficient - material_type_glazingsimple.solarHeatGainCoefficient * shgc_improvement_percent * 0.01) + # get the updated value for reporting + u_value_new = nil + shgc_new = nil + u_value_new = material_type_glazingsimple.uFactor + shgc_new = material_type_glazingsimple.solarHeatGainCoefficient + + # report initial condition of model + runner.registerInitialCondition("The building started with #{u_value_old} U-value, #{shgc_old} SHGC.") + + # report final condition of model + runner.registerFinalCondition("The building finished with #{u_value_new} U-value, #{shgc_new} SHGC.") + + end + end + + return true end - end # register the measure to be used by the application diff --git a/lib/measures/reduce_water_use_by_percentage/measure.rb b/lib/measures/reduce_water_use_by_percentage/measure.rb index 32ef863..1df5e0f 100644 --- a/lib/measures/reduce_water_use_by_percentage/measure.rb +++ b/lib/measures/reduce_water_use_by_percentage/measure.rb @@ -1,12 +1,13 @@ +# frozen_string_literal: true + # see the URL below for information on how to write OpenStudio measures # http://nrel.github.io/OpenStudio-user-documentation/reference/measure_writing_guide/ # start the measure class ReduceWaterUseByPercentage < OpenStudio::Ruleset::ModelUserScript - # human readable name def name - return "reduce_water_use_by_percentage" + return 'reduce_water_use_by_percentage' end # define the arguments that the user will input @@ -14,16 +15,16 @@ def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new # make an argument for water use reduction percentage - water_use_reduction_percent = OpenStudio::Ruleset::OSArgument.makeDoubleArgument("water_use_reduction_percent", true) - water_use_reduction_percent.setDisplayName("Water Use Reduction Percentage (%)") - water_use_reduction_percent.setDefaultValue(20) + water_use_reduction_percent = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('water_use_reduction_percent', true) + water_use_reduction_percent.setDisplayName('Water Use Reduction Percentage (%)') + water_use_reduction_percent.setDefaultValue(20) args << water_use_reduction_percent return args end # define what happens when the measure is run - def run(model, runner, user_arguments) + def run(model, runner, user_arguments) super(model, runner, user_arguments) # use the built-in error checking @@ -31,33 +32,29 @@ def run(model, runner, user_arguments) return false end - #assign the user inputs to variables - water_use_reduction_percent = runner.getDoubleArgumentValue("water_use_reduction_percent",user_arguments) + # assign the user inputs to variables + water_use_reduction_percent = runner.getDoubleArgumentValue('water_use_reduction_percent', user_arguments) + + # replace water use parameters + model.getWaterUseEquipments.each do |water_use_equipment| + # get the original value for reporting + peak_flow_rate_si_old = water_use_equipment.waterUseEquipmentDefinition.peakFlowRate # m^3/s + + # Update the values from user input + water_use_equipment.waterUseEquipmentDefinition.setPeakFlowRate(water_use_equipment.waterUseEquipmentDefinition.peakFlowRate - water_use_equipment.waterUseEquipmentDefinition.peakFlowRate * water_use_reduction_percent * 0.01) - # replace water use parameters - model.getWaterUseEquipments.each do |water_use_equipment| - - # get the original value for reporting - peak_flow_rate_si_old = water_use_equipment.waterUseEquipmentDefinition.peakFlowRate # m^3/s - - # Update the values from user input - water_use_equipment.waterUseEquipmentDefinition.setPeakFlowRate(water_use_equipment.waterUseEquipmentDefinition.peakFlowRate - water_use_equipment.waterUseEquipmentDefinition.peakFlowRate * water_use_reduction_percent * 0.01) - - # get the updated value for reporting - peak_flow_rate_si_new = water_use_equipment.waterUseEquipmentDefinition.peakFlowRate # m^3/s - - # report initial condition of model - runner.registerInitialCondition("Peak flow rate is #{peak_flow_rate_si_old} m^3/s..") + # get the updated value for reporting + peak_flow_rate_si_new = water_use_equipment.waterUseEquipmentDefinition.peakFlowRate # m^3/s + + # report initial condition of model + runner.registerInitialCondition("Peak flow rate is #{peak_flow_rate_si_old} m^3/s..") # report final condition of model - runner.registerFinalCondition("Peak flow rate is #{peak_flow_rate_si_new} m^3/s.") - - end + runner.registerFinalCondition("Peak flow rate is #{peak_flow_rate_si_new} m^3/s.") + end return true - end - end # register the measure to be used by the application diff --git a/lib/measures/replace_hvac_with_gshp_and_doas/measure.rb b/lib/measures/replace_hvac_with_gshp_and_doas/measure.rb index ad35310..708d75f 100644 --- a/lib/measures/replace_hvac_with_gshp_and_doas/measure.rb +++ b/lib/measures/replace_hvac_with_gshp_and_doas/measure.rb @@ -1,28 +1,29 @@ -#see the URL below for information on how to write OpenStudio measures +# frozen_string_literal: true + +# see the URL below for information on how to write OpenStudio measures # http://openstudio.nrel.gov/openstudio-measure-writing-guide -#see the URL below for information on using life cycle cost objects in OpenStudio +# see the URL below for information on using life cycle cost objects in OpenStudio # http://openstudio.nrel.gov/openstudio-life-cycle-examples -#see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) +# see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) # http://openstudio.nrel.gov/sites/openstudio.nrel.gov/files/nv_data/cpp_documentation_it/model/html/namespaces.html -#load OpenStudio measure libraries -#require "#{File.dirname(__FILE__)}/resources/OsLib_AedgMeasures" +# load OpenStudio measure libraries +# require "#{File.dirname(__FILE__)}/resources/OsLib_AedgMeasures" require "#{File.dirname(__FILE__)}/resources/OsLib_HelperMethods" require "#{File.dirname(__FILE__)}/resources/OsLib_HVAC" require "#{File.dirname(__FILE__)}/resources/OsLib_Schedules" -#start the measure +# start the measure class ReplaceHVACWithGSHPAndDOAS < OpenStudio::Ruleset::ModelUserScript - - #define the name that a user will see, this method may be deprecated as - #the display name in PAT comes from the name field in measure.xml + # define the name that a user will see, this method may be deprecated as + # the display name in PAT comes from the name field in measure.xml def name - return "Replace HVAC with GSHP and DOAS" + return 'Replace HVAC with GSHP and DOAS' end - #define the arguments that the user will input + # define the arguments that the user will input def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new @@ -31,484 +32,480 @@ def arguments(model) used_space_type_handles = OpenStudio::StringVector.new used_space_type_names = OpenStudio::StringVector.new model.getSpaceTypes.sort.each do |space_type| - if space_type.spaces.size > 0 # only show space types used in the building + if !space_type.spaces.empty? # only show space types used in the building used_space_type_handles << space_type.handle.to_s used_space_type_names << space_type.name.to_s end end - + # Make an argument for plenum space type - ceiling_return_plenum_space_type = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("ceiling_return_plenum_space_type", used_space_type_handles, used_space_type_names,false) - ceiling_return_plenum_space_type.setDisplayName("This space type should be part of a ceiling return air plenum.") + ceiling_return_plenum_space_type = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('ceiling_return_plenum_space_type', used_space_type_handles, used_space_type_names, false) + ceiling_return_plenum_space_type.setDisplayName('This space type should be part of a ceiling return air plenum.') args << ceiling_return_plenum_space_type - + # Make a bool argument to edit/not edit each space type - model.getSpaceTypes.sort.each do |space_type| - if space_type.spaces.size > 0 # only show space types used in the building - space_type_to_edit = OpenStudio::Ruleset::OSArgument::makeBoolArgument(space_type.name.get.to_s,false) - # Make a bool argument for this space type - space_type_to_edit.setDisplayName("Add #{space_type.name.get} space type to GSHP system?") - space_type_to_edit.setDefaultValue(false) - args << space_type_to_edit - end - end - - # Heating COP of GSHP - gshp_htg_cop = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("gshp_htg_cop",false) - gshp_htg_cop.setDisplayName("GSHP DX Heating Coil Heating COP") - gshp_htg_cop.setDefaultValue(4.0) - args << gshp_htg_cop - - # Cooling EER of GSHP - gshp_clg_eer = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("gshp_clg_eer",false) - gshp_clg_eer.setDisplayName("GSHP DX Cooling Coil Cooling EER") - gshp_clg_eer.setDefaultValue(14) - args << gshp_clg_eer - - # GSHP Fan Type PSC or ECM - fan_choices = OpenStudio::StringVector.new - fan_choices << "PSC" - fan_choices << "ECM" - gshp_fan_type = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("gshp_fan_type",fan_choices,true) # note ECM fan type may correspond to different set of heat pump performance curves - gshp_fan_type.setDisplayName("GSHP Fan Type: PSC or ECM?") - gshp_fan_type.setDefaultValue("PSC") + model.getSpaceTypes.sort.each do |space_type| + if !space_type.spaces.empty? # only show space types used in the building + space_type_to_edit = OpenStudio::Ruleset::OSArgument.makeBoolArgument(space_type.name.get.to_s, false) + # Make a bool argument for this space type + space_type_to_edit.setDisplayName("Add #{space_type.name.get} space type to GSHP system?") + space_type_to_edit.setDefaultValue(false) + args << space_type_to_edit + end + end + + # Heating COP of GSHP + gshp_htg_cop = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('gshp_htg_cop', false) + gshp_htg_cop.setDisplayName('GSHP DX Heating Coil Heating COP') + gshp_htg_cop.setDefaultValue(4.0) + args << gshp_htg_cop + + # Cooling EER of GSHP + gshp_clg_eer = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('gshp_clg_eer', false) + gshp_clg_eer.setDisplayName('GSHP DX Cooling Coil Cooling EER') + gshp_clg_eer.setDefaultValue(14) + args << gshp_clg_eer + + # GSHP Fan Type PSC or ECM + fan_choices = OpenStudio::StringVector.new + fan_choices << 'PSC' + fan_choices << 'ECM' + gshp_fan_type = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('gshp_fan_type', fan_choices, true) # note ECM fan type may correspond to different set of heat pump performance curves + gshp_fan_type.setDisplayName('GSHP Fan Type: PSC or ECM?') + gshp_fan_type.setDefaultValue('PSC') args << gshp_fan_type - - # Condenser Loop Cooling Temperature - # condLoopCoolingTemp = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("condLoopCoolingTemp",false) - # condLoopCoolingTemp.setDisplayName("Condenser Loop Cooling Temperature (F)") - # condLoopCoolingTemp.setDefaultValue(90) - # args << condLoopCoolingTemp - - # Condenser Loop Heating Temperature - # condLoopHeatingTemp = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("condLoopHeatingTemp",false) - # condLoopHeatingTemp.setDisplayName("Condenser Loop Heating Temperature (F)") - # condLoopHeatingTemp.setDefaultValue(60) - # args << condLoopHeatingTemp - - # Vertical Bore HX - building_area = model.getBuilding.floorArea - building_cool_ton = building_area*10.7639/500 # 500sf/ton estimated - bore_hole_no = OpenStudio::Ruleset::OSArgument::makeIntegerArgument("bore_hole_no",false) - bore_hole_no.setDisplayName("Number of Bore Holes") - bore_hole_no.setDefaultValue(building_cool_ton.to_i) - args << bore_hole_no - - - bore_hole_length = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("bore_hole_length",false) - bore_hole_length.setDisplayName("Bore Hole Length (ft)") - bore_hole_length.setDefaultValue(200) - args << bore_hole_length - - bore_hole_radius = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("bore_hole_radius",false) - bore_hole_radius.setDisplayName("Bore Hole Radius (inch)") - bore_hole_radius.setDefaultValue(6.0) - args << bore_hole_radius - - ground_k_value = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("ground_k_value",false) - ground_k_value.setDisplayName("Ground Conductivity (Btu/hr.F.R") - ground_k_value.setDefaultValue(0.75) - args << ground_k_value - - grout_k_value = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("grout_k_value",false) - grout_k_value.setDisplayName("Grout Conductivity (Btu/hr.F.R") - grout_k_value.setDefaultValue(0.75) - args << grout_k_value - - chs = OpenStudio::StringVector.new - chs << "Yes" - chs << "No" - supplemental_boiler = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("supplemental_boiler",chs, true) - supplemental_boiler.setDisplayName("Supplemental Heating Boiler?") - supplemental_boiler.setDefaultValue("No") - args << supplemental_boiler - - # Boiler Capacity - boiler_cap = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("boiler_cap",false) - boiler_cap.setDisplayName("boiler normal capacity (MBtuh)") - boiler_cap.setDefaultValue(500.0) - args << boiler_cap - - # Boiler Efficiency - boiler_eff = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("boiler_eff",false) - boiler_eff.setDisplayName("Boiler Thermal Efficiency") - boiler_eff.setDefaultValue(0.9) - args << boiler_eff - - # Boiler fuel Type - fuel_choices = OpenStudio::StringVector.new - fuel_choices << "NaturalGas" - fuel_choices << "PropaneGas" - fuel_choices << "FuelOil#1" - fuel_choices << "FuelOil#2" - fuel_choices << "Electricity" - boiler_fuel_type = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("boiler_fuel_type",fuel_choices,false) - boiler_fuel_type.setDisplayName("Boiler Fuel Type") - boiler_fuel_type.setDefaultValue("NaturalGas") - args << boiler_fuel_type - - # boiler Hot water supply temperature - boiler_hw_st = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("boiler_hw_st",false) - boiler_hw_st.setDisplayName("Boiler Design Heating Water Outlet Temperature (F)") - boiler_hw_st.setDefaultValue(120) - args << boiler_hw_st - - # DOAS Fan Type - doas_fan_choices = OpenStudio::StringVector.new - doas_fan_choices << "Constant" - doas_fan_choices << "Variable" - doas_fan_type = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doas_fan_type",doas_fan_choices,true) - doas_fan_type.setDisplayName("DOAS Fan Flow Control - Variable means DCV controls") - doas_fan_type.setDefaultValue("Variable") - args << doas_fan_type - - # DOAS Energy Recovery - erv_choices = OpenStudio::StringVector.new - erv_choices << "plate w/o economizer lockout" - erv_choices << "plate w/ economizer lockout" - erv_choices << "rotary wheel w/o economizer lockout" - erv_choices << "rotary wheel w/ economizer lockout" - erv_choices << "none" - doas_erv = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doas_erv",erv_choices,true) - doas_erv.setDisplayName("DOAS Energy Recovery?") - doas_erv.setDefaultValue("none") - args << doas_erv - - # DOAS Evaporative Cooling - evap_choices = OpenStudio::StringVector.new - evap_choices << "Direct Evaporative Cooler" - evap_choices << "none" - doas_evap = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doas_evap",evap_choices,true) - doas_evap.setDisplayName("DOAS Direct Evaporative Cooling?") - doas_evap.setDefaultValue("none") - args << doas_evap - - # DOAS DX Cooling - doas_dx_eer = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("doas_dx_eer",false) - doas_dx_eer.setDisplayName("DOAS DX Cooling EER") - doas_dx_eer.setDefaultValue(10.0) - args << doas_dx_eer - + + # Condenser Loop Cooling Temperature + # condLoopCoolingTemp = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("condLoopCoolingTemp",false) + # condLoopCoolingTemp.setDisplayName("Condenser Loop Cooling Temperature (F)") + # condLoopCoolingTemp.setDefaultValue(90) + # args << condLoopCoolingTemp + + # Condenser Loop Heating Temperature + # condLoopHeatingTemp = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("condLoopHeatingTemp",false) + # condLoopHeatingTemp.setDisplayName("Condenser Loop Heating Temperature (F)") + # condLoopHeatingTemp.setDefaultValue(60) + # args << condLoopHeatingTemp + + # Vertical Bore HX + building_area = model.getBuilding.floorArea + building_cool_ton = building_area * 10.7639 / 500 # 500sf/ton estimated + bore_hole_no = OpenStudio::Ruleset::OSArgument.makeIntegerArgument('bore_hole_no', false) + bore_hole_no.setDisplayName('Number of Bore Holes') + bore_hole_no.setDefaultValue(building_cool_ton.to_i) + args << bore_hole_no + + bore_hole_length = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('bore_hole_length', false) + bore_hole_length.setDisplayName('Bore Hole Length (ft)') + bore_hole_length.setDefaultValue(200) + args << bore_hole_length + + bore_hole_radius = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('bore_hole_radius', false) + bore_hole_radius.setDisplayName('Bore Hole Radius (inch)') + bore_hole_radius.setDefaultValue(6.0) + args << bore_hole_radius + + ground_k_value = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('ground_k_value', false) + ground_k_value.setDisplayName('Ground Conductivity (Btu/hr.F.R') + ground_k_value.setDefaultValue(0.75) + args << ground_k_value + + grout_k_value = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('grout_k_value', false) + grout_k_value.setDisplayName('Grout Conductivity (Btu/hr.F.R') + grout_k_value.setDefaultValue(0.75) + args << grout_k_value + + chs = OpenStudio::StringVector.new + chs << 'Yes' + chs << 'No' + supplemental_boiler = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('supplemental_boiler', chs, true) + supplemental_boiler.setDisplayName('Supplemental Heating Boiler?') + supplemental_boiler.setDefaultValue('No') + args << supplemental_boiler + + # Boiler Capacity + boiler_cap = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('boiler_cap', false) + boiler_cap.setDisplayName('boiler normal capacity (MBtuh)') + boiler_cap.setDefaultValue(500.0) + args << boiler_cap + + # Boiler Efficiency + boiler_eff = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('boiler_eff', false) + boiler_eff.setDisplayName('Boiler Thermal Efficiency') + boiler_eff.setDefaultValue(0.9) + args << boiler_eff + + # Boiler fuel Type + fuel_choices = OpenStudio::StringVector.new + fuel_choices << 'NaturalGas' + fuel_choices << 'PropaneGas' + fuel_choices << 'FuelOil#1' + fuel_choices << 'FuelOil#2' + fuel_choices << 'Electricity' + boiler_fuel_type = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('boiler_fuel_type', fuel_choices, false) + boiler_fuel_type.setDisplayName('Boiler Fuel Type') + boiler_fuel_type.setDefaultValue('NaturalGas') + args << boiler_fuel_type + + # boiler Hot water supply temperature + boiler_hw_st = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('boiler_hw_st', false) + boiler_hw_st.setDisplayName('Boiler Design Heating Water Outlet Temperature (F)') + boiler_hw_st.setDefaultValue(120) + args << boiler_hw_st + + # DOAS Fan Type + doas_fan_choices = OpenStudio::StringVector.new + doas_fan_choices << 'Constant' + doas_fan_choices << 'Variable' + doas_fan_type = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doas_fan_type', doas_fan_choices, true) + doas_fan_type.setDisplayName('DOAS Fan Flow Control - Variable means DCV controls') + doas_fan_type.setDefaultValue('Variable') + args << doas_fan_type + + # DOAS Energy Recovery + erv_choices = OpenStudio::StringVector.new + erv_choices << 'plate w/o economizer lockout' + erv_choices << 'plate w/ economizer lockout' + erv_choices << 'rotary wheel w/o economizer lockout' + erv_choices << 'rotary wheel w/ economizer lockout' + erv_choices << 'none' + doas_erv = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doas_erv', erv_choices, true) + doas_erv.setDisplayName('DOAS Energy Recovery?') + doas_erv.setDefaultValue('none') + args << doas_erv + + # DOAS Evaporative Cooling + evap_choices = OpenStudio::StringVector.new + evap_choices << 'Direct Evaporative Cooler' + evap_choices << 'none' + doas_evap = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doas_evap', evap_choices, true) + doas_evap.setDisplayName('DOAS Direct Evaporative Cooling?') + doas_evap.setDefaultValue('none') + args << doas_evap + + # DOAS DX Cooling + doas_dx_eer = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('doas_dx_eer', false) + doas_dx_eer.setDisplayName('DOAS DX Cooling EER') + doas_dx_eer.setDefaultValue(10.0) + args << doas_dx_eer + # make an argument for material and installation cost # todo - I would like to split the costing out to the air loops weighted by area of building served vs. just sticking it on the building - cost_total_hvac_system = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("cost_total_hvac_system",true) - cost_total_hvac_system.setDisplayName("Total Cost for HVAC System ($).") + cost_total_hvac_system = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('cost_total_hvac_system', true) + cost_total_hvac_system.setDisplayName('Total Cost for HVAC System ($).') cost_total_hvac_system.setDefaultValue(0.0) args << cost_total_hvac_system - - #make an argument to remove existing costs - remake_schedules = OpenStudio::Ruleset::OSArgument::makeBoolArgument("remake_schedules",true) - remake_schedules.setDisplayName("Apply recommended availability and ventilation schedules for air handlers?") + + # make an argument to remove existing costs + remake_schedules = OpenStudio::Ruleset::OSArgument.makeBoolArgument('remake_schedules', true) + remake_schedules.setDisplayName('Apply recommended availability and ventilation schedules for air handlers?') remake_schedules.setDefaultValue(true) args << remake_schedules return args - end #end the arguments method + end # end the arguments method - #define what happens when the measure is run + # define what happens when the measure is run def run(model, runner, user_arguments) super(model, runner, user_arguments) - # Use the built-in error checking - if not runner.validateUserArguments(arguments(model), user_arguments) + # Use the built-in error checking + if !runner.validateUserArguments(arguments(model), user_arguments) return false end - - # Assign the user inputs to variables - space_type_to_edits_hash = {} - model.getSpaceTypes.each do |space_type| - if space_type.spaces.size > 0 - space_type_to_edit = runner.getBoolArgumentValue(space_type.name.get.to_s,user_arguments) - space_type_to_edits_hash[space_type] = space_type_to_edit - end - end - - bore_hole_no = runner.getIntegerArgumentValue("bore_hole_no",user_arguments) - bore_hole_length = runner.getDoubleArgumentValue("bore_hole_length",user_arguments) - bore_hole_radius = runner.getDoubleArgumentValue("bore_hole_radius",user_arguments) - ground_k_value = runner.getDoubleArgumentValue("ground_k_value",user_arguments) - grout_k_value = runner.getDoubleArgumentValue("grout_k_value",user_arguments) - supplemental_boiler = runner.getStringArgumentValue("supplemental_boiler",user_arguments) - - gshp_htg_cop = runner.getDoubleArgumentValue("gshp_htg_cop",user_arguments) - gshp_clg_eer = runner.getDoubleArgumentValue("gshp_clg_eer",user_arguments) - gshp_fan_type = runner.getStringArgumentValue("gshp_fan_type",user_arguments) - # condLoopCoolingTemp = runner.getDoubleArgumentValue("condLoopCoolingTemp",user_arguments) - # condLoopHeatingTemp = runner.getDoubleArgumentValue("condLoopHeatingTemp",user_arguments) - # coolingTowerWB = runner.getDoubleArgumentValue("coolingTowerWB",user_arguments) - # coolingTowerApproach= runner.getDoubleArgumentValue("coolingTowerApproach",user_arguments) - # coolingTowerDeltaT= runner.getDoubleArgumentValue("coolingTowerDeltaT",user_arguments) - boiler_cap = runner.getDoubleArgumentValue("boiler_cap",user_arguments) - boiler_eff= runner.getDoubleArgumentValue("boiler_eff",user_arguments) - boiler_fuel_type = runner.getStringArgumentValue("boiler_fuel_type",user_arguments) - boiler_hw_st= runner.getDoubleArgumentValue("boiler_hw_st",user_arguments) - doas_fan_type = runner.getStringArgumentValue("doas_fan_type",user_arguments) - doas_erv = runner.getStringArgumentValue("doas_erv",user_arguments) - doas_evap = runner.getStringArgumentValue("doas_evap",user_arguments) - doas_dx_eer= runner.getDoubleArgumentValue("doas_dx_eer",user_arguments) - + + # Assign the user inputs to variables + space_type_to_edits_hash = {} + model.getSpaceTypes.each do |space_type| + if !space_type.spaces.empty? + space_type_to_edit = runner.getBoolArgumentValue(space_type.name.get.to_s, user_arguments) + space_type_to_edits_hash[space_type] = space_type_to_edit + end + end + + bore_hole_no = runner.getIntegerArgumentValue('bore_hole_no', user_arguments) + bore_hole_length = runner.getDoubleArgumentValue('bore_hole_length', user_arguments) + bore_hole_radius = runner.getDoubleArgumentValue('bore_hole_radius', user_arguments) + ground_k_value = runner.getDoubleArgumentValue('ground_k_value', user_arguments) + grout_k_value = runner.getDoubleArgumentValue('grout_k_value', user_arguments) + supplemental_boiler = runner.getStringArgumentValue('supplemental_boiler', user_arguments) + + gshp_htg_cop = runner.getDoubleArgumentValue('gshp_htg_cop', user_arguments) + gshp_clg_eer = runner.getDoubleArgumentValue('gshp_clg_eer', user_arguments) + gshp_fan_type = runner.getStringArgumentValue('gshp_fan_type', user_arguments) + # condLoopCoolingTemp = runner.getDoubleArgumentValue("condLoopCoolingTemp",user_arguments) + # condLoopHeatingTemp = runner.getDoubleArgumentValue("condLoopHeatingTemp",user_arguments) + # coolingTowerWB = runner.getDoubleArgumentValue("coolingTowerWB",user_arguments) + # coolingTowerApproach= runner.getDoubleArgumentValue("coolingTowerApproach",user_arguments) + # coolingTowerDeltaT= runner.getDoubleArgumentValue("coolingTowerDeltaT",user_arguments) + boiler_cap = runner.getDoubleArgumentValue('boiler_cap', user_arguments) + boiler_eff = runner.getDoubleArgumentValue('boiler_eff', user_arguments) + boiler_fuel_type = runner.getStringArgumentValue('boiler_fuel_type', user_arguments) + boiler_hw_st = runner.getDoubleArgumentValue('boiler_hw_st', user_arguments) + doas_fan_type = runner.getStringArgumentValue('doas_fan_type', user_arguments) + doas_erv = runner.getStringArgumentValue('doas_erv', user_arguments) + doas_evap = runner.getStringArgumentValue('doas_evap', user_arguments) + doas_dx_eer = runner.getDoubleArgumentValue('doas_dx_eer', user_arguments) + ### START INPUTS - #assign the user inputs to variables - ceiling_return_plenum_space_type = runner.getOptionalWorkspaceObjectChoiceValue("ceiling_return_plenum_space_type",user_arguments,model) - cost_total_hvac_system = runner.getDoubleArgumentValue("cost_total_hvac_system",user_arguments) - remake_schedules = runner.getBoolArgumentValue("remake_schedules",user_arguments) + # assign the user inputs to variables + ceiling_return_plenum_space_type = runner.getOptionalWorkspaceObjectChoiceValue('ceiling_return_plenum_space_type', user_arguments, model) + cost_total_hvac_system = runner.getDoubleArgumentValue('cost_total_hvac_system', user_arguments) + remake_schedules = runner.getBoolArgumentValue('remake_schedules', user_arguments) # check that space_type was chosen and exists in model - ceiling_return_plenum_space_typeCheck = OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(ceiling_return_plenum_space_type, "ceiling_return_plenum_space_type","to_SpaceType", runner, user_arguments) - if ceiling_return_plenum_space_typeCheck == false then return false else ceiling_return_plenum_space_type = ceiling_return_plenum_space_typeCheck["modelObject"] end + ceiling_return_plenum_space_typeCheck = OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(ceiling_return_plenum_space_type, 'ceiling_return_plenum_space_type', 'to_SpaceType', runner, user_arguments) + ceiling_return_plenum_space_typeCheck == false ? (return false) : (ceiling_return_plenum_space_type = ceiling_return_plenum_space_typeCheck['modelObject']) # default building/ secondary space types - standardBuildingTypeTest = [] #ML Not used yet - #secondarySpaceTypeTest = ["Cafeteria", "Kitchen", "Gym", "Auditorium"] - standardBuildingTypeTest = ["Office"] #ML Not used yet + standardBuildingTypeTest = [] # ML Not used yet + # secondarySpaceTypeTest = ["Cafeteria", "Kitchen", "Gym", "Auditorium"] + standardBuildingTypeTest = ['Office'] # ML Not used yet secondarySpaceTypeTest = [] # empty for office - primarySpaceType = "Office" - if doas_fan_type == "Variable" - primaryHVAC = {"doas" => true, "fan" => "Variable", "heat" => "Gas", "cool" => "SingleDX"} - else - primaryHVAC = {"doas" => true, "fan" => "Constant", "heat" => "Gas", "cool" => "SingleDX"} - end - secondaryHVAC = {"fan" => "None", "heat" => "None", "cool" => "None"} #ML not used for office; leave or empty? - zoneHVAC = "GSHP" - chillerType = "None" #set to none if chiller not used - radiantChillerType = "None" #set to none if not radiant system - allHVAC = {"primary" => primaryHVAC,"secondary" => secondaryHVAC,"zone" => zoneHVAC} - - + primarySpaceType = 'Office' + if doas_fan_type == 'Variable' + primaryHVAC = { 'doas' => true, 'fan' => 'Variable', 'heat' => 'Gas', 'cool' => 'SingleDX' } + else + primaryHVAC = { 'doas' => true, 'fan' => 'Constant', 'heat' => 'Gas', 'cool' => 'SingleDX' } + end + secondaryHVAC = { 'fan' => 'None', 'heat' => 'None', 'cool' => 'None' } # ML not used for office; leave or empty? + zoneHVAC = 'GSHP' + chillerType = 'None' # set to none if chiller not used + radiantChillerType = 'None' # set to none if not radiant system + allHVAC = { 'primary' => primaryHVAC, 'secondary' => secondaryHVAC, 'zone' => zoneHVAC } + ### END INPUTS - - # create a hash incorporating all user inputs on GSHP - parameters = {"gshpCoolingEER" => gshp_clg_eer, - "gshpHeatingCOP" => gshp_htg_cop, - "gshpFanType" => gshp_fan_type, - "groundKValue" => ground_k_value, - "groutKValue" => grout_k_value, - "boreHoleNo" => bore_hole_no, - "boreHoleLength" => bore_hole_length, - "boreHoleRadius" => bore_hole_radius, - "supplementalBoiler" => supplemental_boiler, - "boilerCap" => boiler_cap, - "boilerEff" => boiler_eff, - "boilerFuelType" => boiler_fuel_type, - "boilerHWST" => boiler_hw_st, - "doasFanType" => doas_fan_type, - "doasDXEER" => doas_dx_eer, - "doasERV" => doas_erv, - "doasEvap" => doas_evap} + + # create a hash incorporating all user inputs on GSHP + parameters = { 'gshpCoolingEER' => gshp_clg_eer, + 'gshpHeatingCOP' => gshp_htg_cop, + 'gshpFanType' => gshp_fan_type, + 'groundKValue' => ground_k_value, + 'groutKValue' => grout_k_value, + 'boreHoleNo' => bore_hole_no, + 'boreHoleLength' => bore_hole_length, + 'boreHoleRadius' => bore_hole_radius, + 'supplementalBoiler' => supplemental_boiler, + 'boilerCap' => boiler_cap, + 'boilerEff' => boiler_eff, + 'boilerFuelType' => boiler_fuel_type, + 'boilerHWST' => boiler_hw_st, + 'doasFanType' => doas_fan_type, + 'doasDXEER' => doas_dx_eer, + 'doasERV' => doas_erv, + 'doasEvap' => doas_evap } ### START SORT ZONES - options = {"standardBuildingTypeTest" => standardBuildingTypeTest, #ML Not used yet - "secondarySpaceTypeTest" => secondarySpaceTypeTest, - "ceiling_return_plenum_space_type" => ceiling_return_plenum_space_type} + options = { 'standardBuildingTypeTest' => standardBuildingTypeTest, # ML Not used yet + 'secondarySpaceTypeTest' => secondarySpaceTypeTest, + 'ceiling_return_plenum_space_type' => ceiling_return_plenum_space_type } zonesSorted = OsLib_HVAC.sortZones(model, runner, options, space_type_to_edits_hash) - zonesPrimary = zonesSorted["zonesPrimary"] - zonesSecondary = zonesSorted["zonesSecondary"] - zonesPlenum = zonesSorted["zonesPlenum"] - zonesUnconditioned = zonesSorted["zonesUnconditioned"] + zonesPrimary = zonesSorted['zonesPrimary'] + zonesSecondary = zonesSorted['zonesSecondary'] + zonesPlenum = zonesSorted['zonesPlenum'] + zonesUnconditioned = zonesSorted['zonesUnconditioned'] ### END SORT ZONES - + ### START REPORT INITIAL CONDITIONS - OsLib_HVAC.reportConditions(model, runner, "initial") + OsLib_HVAC.reportConditions(model, runner, 'initial') ### END REPORT INITIAL CONDITIONS ### START ASSIGN HVAC SCHEDULES - options = {"primarySpaceType" => primarySpaceType, - "allHVAC" => allHVAC, - "remake_schedules" => remake_schedules} + options = { 'primarySpaceType' => primarySpaceType, + 'allHVAC' => allHVAC, + 'remake_schedules' => remake_schedules } schedulesHVAC = OsLib_HVAC.assignHVACSchedules(model, runner, options) # assign schedules - primary_SAT_schedule = schedulesHVAC["primary_sat"] - building_HVAC_schedule = schedulesHVAC["hvac"] - building_ventilation_schedule = schedulesHVAC["ventilation"] + primary_SAT_schedule = schedulesHVAC['primary_sat'] + building_HVAC_schedule = schedulesHVAC['hvac'] + building_ventilation_schedule = schedulesHVAC['ventilation'] make_hot_water_plant = false - unless schedulesHVAC["hot_water"].nil? - hot_water_setpoint_schedule = schedulesHVAC["hot_water"] + unless schedulesHVAC['hot_water'].nil? + hot_water_setpoint_schedule = schedulesHVAC['hot_water'] make_hot_water_plant = true end make_chilled_water_plant = false - unless schedulesHVAC["chilled_water"].nil? - chilled_water_setpoint_schedule = schedulesHVAC["chilled_water"] + unless schedulesHVAC['chilled_water'].nil? + chilled_water_setpoint_schedule = schedulesHVAC['chilled_water'] make_chilled_water_plant = true end make_radiant_hot_water_plant = false - unless schedulesHVAC["radiant_hot_water"].nil? - radiant_hot_water_setpoint_schedule = schedulesHVAC["radiant_hot_water"] + unless schedulesHVAC['radiant_hot_water'].nil? + radiant_hot_water_setpoint_schedule = schedulesHVAC['radiant_hot_water'] make_radiant_hot_water_plant = true end make_radiant_chilled_water_plant = false - unless schedulesHVAC["radiant_chilled_water"].nil? - radiant_chilled_water_setpoint_schedule = schedulesHVAC["radiant_chilled_water"] + unless schedulesHVAC['radiant_chilled_water'].nil? + radiant_chilled_water_setpoint_schedule = schedulesHVAC['radiant_chilled_water'] make_radiant_chilled_water_plant = true end - unless schedulesHVAC["hp_loop"].nil? - heat_pump_loop_setpoint_schedule = schedulesHVAC["hp_loop"] + unless schedulesHVAC['hp_loop'].nil? + heat_pump_loop_setpoint_schedule = schedulesHVAC['hp_loop'] end - unless schedulesHVAC["hp_loop_cooling"].nil? - heat_pump_loop_cooling_setpoint_schedule = schedulesHVAC["hp_loop_cooling"] + unless schedulesHVAC['hp_loop_cooling'].nil? + heat_pump_loop_cooling_setpoint_schedule = schedulesHVAC['hp_loop_cooling'] end - unless schedulesHVAC["hp_loop_heating"].nil? - heat_pump_loop_heating_setpoint_schedule = schedulesHVAC["hp_loop_heating"] + unless schedulesHVAC['hp_loop_heating'].nil? + heat_pump_loop_heating_setpoint_schedule = schedulesHVAC['hp_loop_heating'] end - unless schedulesHVAC["mean_radiant_heating"].nil? - mean_radiant_heating_setpoint_schedule = schedulesHVAC["mean_radiant_heating"] + unless schedulesHVAC['mean_radiant_heating'].nil? + mean_radiant_heating_setpoint_schedule = schedulesHVAC['mean_radiant_heating'] end - unless schedulesHVAC["mean_radiant_cooling"].nil? - mean_radiant_cooling_setpoint_schedule = schedulesHVAC["mean_radiant_cooling"] + unless schedulesHVAC['mean_radiant_cooling'].nil? + mean_radiant_cooling_setpoint_schedule = schedulesHVAC['mean_radiant_cooling'] end ### END ASSIGN HVAC SCHEDULES runner.registerInfo("number of bore holes are #{model.getBuilding.floorArea} m2") # START REMOVE EQUIPMENT - options = {} - options["zonesPrimary"] = zonesPrimary - if options["zonesPrimary"].empty? - runner.registerInfo("User did not pick any zones to be added to GSHP system, no changes to the model were made.") - else - OsLib_HVAC.removeEquipment(model, runner, options) - end + options = {} + options['zonesPrimary'] = zonesPrimary + if options['zonesPrimary'].empty? + runner.registerInfo('User did not pick any zones to be added to GSHP system, no changes to the model were made.') + else + OsLib_HVAC.removeEquipment(model, runner, options) + end ### END REMOVE EQUIPMENT - + ### START CREATE NEW PLANTS # create new plants # hot water plant if make_hot_water_plant - hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, "Hot Water", parameters) + hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, 'Hot Water', parameters) end # chilled water plant if make_chilled_water_plant - chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, "Chilled Water", chillerType) + chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, 'Chilled Water', chillerType) end # radiant hot water plant if make_radiant_hot_water_plant - radiant_hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, radiant_hot_water_setpoint_schedule, "Radiant Hot Water") + radiant_hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, radiant_hot_water_setpoint_schedule, 'Radiant Hot Water') end # chilled water plant if make_radiant_chilled_water_plant - radiant_chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, radiant_chilled_water_setpoint_schedule, "Radiant Chilled Water", radiantChillerType) + radiant_chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, radiant_chilled_water_setpoint_schedule, 'Radiant Chilled Water', radiantChillerType) end # condenser loop # need condenser loop if there is a water-cooled chiller or if there is a water source heat pump loop options = {} - options["zonesPrimary"] = zonesPrimary - options["zoneHVAC"] = zoneHVAC - if zoneHVAC.include? "SHP" - options["loop_setpoint_schedule"] = heat_pump_loop_setpoint_schedule - options["cooling_setpoint_schedule"] = heat_pump_loop_cooling_setpoint_schedule - options["heating_setpoint_schedule"] = heat_pump_loop_heating_setpoint_schedule - end - if options["zonesPrimary"].empty? - # runner.registerWarning("User did not pick any space types to be added to the WSHP system, no changes to the model were made") - condenserLoops = {} - # condenserLoops["condenser_loop"] ={} - else - condenserLoops = OsLib_HVAC.createCondenserLoop(model, runner, options, parameters) - end - unless condenserLoops["condenser_loop"].nil? - condenser_loop = condenserLoops["condenser_loop"] - end - unless condenserLoops["heat_pump_loop"].nil? - heat_pump_loop = condenserLoops["heat_pump_loop"] + options['zonesPrimary'] = zonesPrimary + options['zoneHVAC'] = zoneHVAC + if zoneHVAC.include? 'SHP' + options['loop_setpoint_schedule'] = heat_pump_loop_setpoint_schedule + options['cooling_setpoint_schedule'] = heat_pump_loop_cooling_setpoint_schedule + options['heating_setpoint_schedule'] = heat_pump_loop_heating_setpoint_schedule + end + if options['zonesPrimary'].empty? + # runner.registerWarning("User did not pick any space types to be added to the WSHP system, no changes to the model were made") + condenserLoops = {} + # condenserLoops["condenser_loop"] ={} + else + condenserLoops = OsLib_HVAC.createCondenserLoop(model, runner, options, parameters) + end + unless condenserLoops['condenser_loop'].nil? + condenser_loop = condenserLoops['condenser_loop'] + end + unless condenserLoops['heat_pump_loop'].nil? + heat_pump_loop = condenserLoops['heat_pump_loop'] end ### END CREATE NEW PLANTS - + ### START CREATE PRIMARY AIRLOOPS # populate inputs hash for create primary airloops method options = {} - options["zonesPrimary"] = zonesPrimary - options["primaryHVAC"] = primaryHVAC - options["zoneHVAC"] = zoneHVAC - if primaryHVAC["doas"] - options["hvac_schedule"] = building_ventilation_schedule - options["ventilation_schedule"] = building_ventilation_schedule + options['zonesPrimary'] = zonesPrimary + options['primaryHVAC'] = primaryHVAC + options['zoneHVAC'] = zoneHVAC + if primaryHVAC['doas'] + options['hvac_schedule'] = building_ventilation_schedule + options['ventilation_schedule'] = building_ventilation_schedule else # primary HVAC is multizone VAV - unless zoneHVAC == "DualDuct" - # primary system is multizone VAV that cools and ventilates - options["hvac_schedule"] = building_HVAC_schedule - options["ventilation_schedule"] = building_ventilation_schedule - else + if zoneHVAC == 'DualDuct' # primary system is a multizone VAV that cools only (primary system ventilation schedule is set to always off; hvac set to always on) - options["hvac_schedule"] = model.alwaysOnDiscreteSchedule() + options['hvac_schedule'] = model.alwaysOnDiscreteSchedule + else + # primary system is multizone VAV that cools and ventilates + options['hvac_schedule'] = building_HVAC_schedule + options['ventilation_schedule'] = building_ventilation_schedule end end - options["primary_sat_schedule"] = primary_SAT_schedule + options['primary_sat_schedule'] = primary_SAT_schedule if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end primary_airloops = OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) ### END CREATE PRIMARY AIRLOOPS - + ### START CREATE SECONDARY AIRLOOPS # populate inputs hash for create primary airloops method options = {} - options["zonesSecondary"] = zonesSecondary - options["secondaryHVAC"] = secondaryHVAC - options["hvac_schedule"] = building_HVAC_schedule - options["ventilation_schedule"] = building_ventilation_schedule + options['zonesSecondary'] = zonesSecondary + options['secondaryHVAC'] = secondaryHVAC + options['hvac_schedule'] = building_HVAC_schedule + options['ventilation_schedule'] = building_ventilation_schedule if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end secondary_airloops = OsLib_HVAC.createSecondaryAirLoops(model, runner, options) ### END CREATE SECONDARY AIRLOOPS - + ### START ASSIGN PLENUMS - options = {"zonesPrimary" => zonesPrimary,"zonesPlenum" => zonesPlenum} + options = { 'zonesPrimary' => zonesPrimary, 'zonesPlenum' => zonesPlenum } zone_plenum_hash = OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options) ### END ASSIGN PLENUMS - + ### START CREATE PRIMARY ZONE EQUIPMENT options = {} - options["zonesPrimary"] = zonesPrimary - options["zoneHVAC"] = zoneHVAC + options['zonesPrimary'] = zonesPrimary + options['zoneHVAC'] = zoneHVAC if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end - if zoneHVAC.include? "SHP" - options["heat_pump_loop"] = heat_pump_loop + if zoneHVAC.include? 'SHP' + options['heat_pump_loop'] = heat_pump_loop end - if zoneHVAC == "DualDuct" - options["ventilation_schedule"] = building_ventilation_schedule + if zoneHVAC == 'DualDuct' + options['ventilation_schedule'] = building_ventilation_schedule end - if zoneHVAC == "Radiant" - options["radiant_hot_water_plant"] = radiant_hot_water_plant - options["radiant_chilled_water_plant"] = radiant_chilled_water_plant - options["mean_radiant_heating_setpoint_schedule"] = mean_radiant_heating_setpoint_schedule - options["mean_radiant_cooling_setpoint_schedule"] = mean_radiant_cooling_setpoint_schedule + if zoneHVAC == 'Radiant' + options['radiant_hot_water_plant'] = radiant_hot_water_plant + options['radiant_chilled_water_plant'] = radiant_chilled_water_plant + options['mean_radiant_heating_setpoint_schedule'] = mean_radiant_heating_setpoint_schedule + options['mean_radiant_cooling_setpoint_schedule'] = mean_radiant_cooling_setpoint_schedule end OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options, parameters) ### END CREATE PRIMARY ZONE EQUIPMENT - + # START ADD DCV options = {} - unless zoneHVAC == "DualDuct" - options["primary_airloops"] = primary_airloops + unless zoneHVAC == 'DualDuct' + options['primary_airloops'] = primary_airloops end - options["secondary_airloops"] = secondary_airloops - options["allHVAC"] = allHVAC + options['secondary_airloops'] = secondary_airloops + options['allHVAC'] = allHVAC OsLib_HVAC.addDCV(model, runner, options) # END ADD DCV - + # Add in lifecycle costs expected_life = 25 years_until_costs_start = 0 costHVAC = cost_total_hvac_system - lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("HVAC System", model.getBuilding, costHVAC, "CostPerEach", "Construction", expected_life, years_until_costs_start).get + lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost('HVAC System', model.getBuilding, costHVAC, 'CostPerEach', 'Construction', expected_life, years_until_costs_start).get ### START REPORT FINAL CONDITIONS - OsLib_HVAC.reportConditions(model, runner, "final") + OsLib_HVAC.reportConditions(model, runner, 'final') ### END REPORT FINAL CONDITIONS return true + end # end the run method +end # end the measure - end #end the run method - -end #end the measure - -#this allows the measure to be used by the application -ReplaceHVACWithGSHPAndDOAS.new.registerWithApplication \ No newline at end of file +# this allows the measure to be used by the application +ReplaceHVACWithGSHPAndDOAS.new.registerWithApplication diff --git a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_AedgMeasures.rb b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_AedgMeasures.rb index 22bc4aa..0449d71 100644 --- a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_AedgMeasures.rb +++ b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_AedgMeasures.rb @@ -1,17 +1,18 @@ -module OsLib_AedgMeasures +# frozen_string_literal: true - def OsLib_AedgMeasures.getClimateZoneNumber(model,runner) +module OsLib_AedgMeasures + def self.getClimateZoneNumber(model, runner) # get ashrae climate zone from model - ashraeClimateZone = "" + ashraeClimateZone = '' climateZones = model.getClimateZones climateZones.climateZones.each do |climateZone| - if climateZone.institution == "ASHRAE" + if climateZone.institution == 'ASHRAE' ashraeClimateZone = climateZone.value runner.registerInfo("Using ASHRAE Climate zone #{ashraeClimateZone} for AEDG recommendations.") end end - if ashraeClimateZone == ""#should this be not applicable or error? + if ashraeClimateZone == '' # should this be not applicable or error? runner.registerError("Please assign an ASHRAE Climate Zone to your model using the site tab in the OpenStudio application. The measure can't make AEDG recommendations without this information.") return false # note - for this to work need to check for false in measure.rb and add return false there as well. else @@ -19,24 +20,21 @@ def OsLib_AedgMeasures.getClimateZoneNumber(model,runner) end # expected climate zone number should be 1 through 8 - if not ["1","2","3","4","5","6","7","8"].include? climateZoneNumber - runner.registerError("ASHRAE climate zone number is not within expected range of 1 to 8.") + if !['1', '2', '3', '4', '5', '6', '7', '8'].include? climateZoneNumber + runner.registerError('ASHRAE climate zone number is not within expected range of 1 to 8.') return false # note - for this to work need to check for false in measure.rb and add return false there as well. end result = climateZoneNumber # don't add return false here, need to catch errors above + end # end of def OsLib_AedgMeasures.getClimateZoneNumber(model,runner) - end # end of def OsLib_AedgMeasures.getClimateZoneNumber(model,runner) - - - def OsLib_AedgMeasures.getLongHowToTips(guide,aedgTips,runner) - + def self.getLongHowToTips(guide, aedgTips, runner) # get tips - if guide == "K12" - hash = OsLib_AedgMeasures.getK12Tips() - elsif guide == "SmMdOff" - hash = OsLib_AedgMeasures.getSmMdOffTips() + if guide == 'K12' + hash = OsLib_AedgMeasures.getK12Tips + elsif guide == 'SmMdOff' + hash = OsLib_AedgMeasures.getSmMdOffTips else runner.registerError("#{guide} is an invalid value. Can't generate how to tip messages.") return false # note - for this to work need to check for false in measure.rb and add return false there as well. @@ -48,7 +46,7 @@ def OsLib_AedgMeasures.getLongHowToTips(guide,aedgTips,runner) # create info messages aedgTips.each do |aedgtip| - if not hash[aedgtip] == hash[0] + if hash[aedgtip] != hash[0] string << hash[aedgtip] else runner.registerWarning("#{aedgtip} is an invalid key for tip hash. Can't generate tip.") @@ -57,408 +55,400 @@ def OsLib_AedgMeasures.getLongHowToTips(guide,aedgTips,runner) # see if expected number of messages created if aedgTips.size != string.size - runner.registerWarning("One more more messages were not created.") + runner.registerWarning('One more more messages were not created.') end - result = "#{hash[0]}: #{string.join(", ")}." # hash[0] bad key will return default value + result = "#{hash[0]}: #{string.join(', ')}." # hash[0] bad key will return default value # don't add return false here, need to catch errors above + end # end of def OsLib_AedgMeasures.getClimateZoneNumber(model,runner) - end # end of def OsLib_AedgMeasures.getClimateZoneNumber(model,runner) - - - #hash of how to tips for K-12 school AEDG - def OsLib_AedgMeasures.getK12Tips - + # hash of how to tips for K-12 school AEDG + def self.getK12Tips # envelope tips - @aedgK12HowToTipHash = Hash.new("K-12 Schools AEDG How to Implement Recommendations") - @aedgK12HowToTipHash["EN01"] = "EN1 Cool Roofs" - @aedgK12HowToTipHash["EN02"] = "EN2 Roofs-Insulation Entirely above Deck" - @aedgK12HowToTipHash["EN03"] = "EN3 Roofs-Attics, and Other Roofs" - @aedgK12HowToTipHash["EN04"] = "EN4 Roofs-Metal Buildings" - @aedgK12HowToTipHash["EN05"] = "EN5 Walls-Mass" - @aedgK12HowToTipHash["EN06"] = "EN6 Walls-Steel Framed" - @aedgK12HowToTipHash["EN07"] = "EN7 Walls-Wood Frame and Other" - @aedgK12HowToTipHash["EN08"] = "EN8 Walls-Metal Building" - @aedgK12HowToTipHash["EN09"] = "EN9 Below-Grade Walls" - @aedgK12HowToTipHash["EN10"] = "EN10 Floors-Mass" - @aedgK12HowToTipHash["EN11"] = "EN11 Floors-Metal Joist or Wood Joist/Wood Frame" - @aedgK12HowToTipHash["EN12"] = "EN12 Slab-on-Grade Floors-Unheated" - @aedgK12HowToTipHash["EN13"] = "EN13 Slab-on-Grade Floors-Heated" - @aedgK12HowToTipHash["EN14"] = "EN14 Slab Edge Insulation" - @aedgK12HowToTipHash["EN15"] = "EN15 Doors-Opaque, Swinging" - @aedgK12HowToTipHash["EN16"] = "EN16 Doors-Opaque, Roll-Up, or Sliding" - @aedgK12HowToTipHash["EN17"] = "EN17 Air Infiltration Control" - @aedgK12HowToTipHash["EN18"] = "EN18 Vestibules" - @aedgK12HowToTipHash["EN19"] = "EN19 Alternative Constructions" - @aedgK12HowToTipHash["EN20"] = "EN20 Truss Heel Heights" - @aedgK12HowToTipHash["EN21"] = "EN21 Moisture Control" - @aedgK12HowToTipHash["EN22"] = "EN22 Thermal Bridging-Opaque Components" - @aedgK12HowToTipHash["EN23"] = "EN23 Thermal Bridging-Fenestration" - @aedgK12HowToTipHash["EN24"] = "EN24 Fenestration Descriptions" - @aedgK12HowToTipHash["EN25"] = "EN25 View Window-to Floor Area Ratio (VFR)" - @aedgK12HowToTipHash["EN26"] = "EN26 Unwanted Solar Heat Gain Is Most Effectively Controlled on the Outside of the Building" - @aedgK12HowToTipHash["EN27"] = "EN27 Operable versus Fixed Windows" - @aedgK12HowToTipHash["EN28"] = "EN28 Building Form and Window Orientation" - @aedgK12HowToTipHash["EN29"] = "EN29 Glazing" - @aedgK12HowToTipHash["EN30"] = "EN30 Obstructions and Planting" - @aedgK12HowToTipHash["EN31"] = "EN31 Window Orientation" - @aedgK12HowToTipHash["EN32"] = "EN32 Passive Solar" - @aedgK12HowToTipHash["EN33"] = "EN33 Glazing" + @aedgK12HowToTipHash = Hash.new('K-12 Schools AEDG How to Implement Recommendations') + @aedgK12HowToTipHash['EN01'] = 'EN1 Cool Roofs' + @aedgK12HowToTipHash['EN02'] = 'EN2 Roofs-Insulation Entirely above Deck' + @aedgK12HowToTipHash['EN03'] = 'EN3 Roofs-Attics, and Other Roofs' + @aedgK12HowToTipHash['EN04'] = 'EN4 Roofs-Metal Buildings' + @aedgK12HowToTipHash['EN05'] = 'EN5 Walls-Mass' + @aedgK12HowToTipHash['EN06'] = 'EN6 Walls-Steel Framed' + @aedgK12HowToTipHash['EN07'] = 'EN7 Walls-Wood Frame and Other' + @aedgK12HowToTipHash['EN08'] = 'EN8 Walls-Metal Building' + @aedgK12HowToTipHash['EN09'] = 'EN9 Below-Grade Walls' + @aedgK12HowToTipHash['EN10'] = 'EN10 Floors-Mass' + @aedgK12HowToTipHash['EN11'] = 'EN11 Floors-Metal Joist or Wood Joist/Wood Frame' + @aedgK12HowToTipHash['EN12'] = 'EN12 Slab-on-Grade Floors-Unheated' + @aedgK12HowToTipHash['EN13'] = 'EN13 Slab-on-Grade Floors-Heated' + @aedgK12HowToTipHash['EN14'] = 'EN14 Slab Edge Insulation' + @aedgK12HowToTipHash['EN15'] = 'EN15 Doors-Opaque, Swinging' + @aedgK12HowToTipHash['EN16'] = 'EN16 Doors-Opaque, Roll-Up, or Sliding' + @aedgK12HowToTipHash['EN17'] = 'EN17 Air Infiltration Control' + @aedgK12HowToTipHash['EN18'] = 'EN18 Vestibules' + @aedgK12HowToTipHash['EN19'] = 'EN19 Alternative Constructions' + @aedgK12HowToTipHash['EN20'] = 'EN20 Truss Heel Heights' + @aedgK12HowToTipHash['EN21'] = 'EN21 Moisture Control' + @aedgK12HowToTipHash['EN22'] = 'EN22 Thermal Bridging-Opaque Components' + @aedgK12HowToTipHash['EN23'] = 'EN23 Thermal Bridging-Fenestration' + @aedgK12HowToTipHash['EN24'] = 'EN24 Fenestration Descriptions' + @aedgK12HowToTipHash['EN25'] = 'EN25 View Window-to Floor Area Ratio (VFR)' + @aedgK12HowToTipHash['EN26'] = 'EN26 Unwanted Solar Heat Gain Is Most Effectively Controlled on the Outside of the Building' + @aedgK12HowToTipHash['EN27'] = 'EN27 Operable versus Fixed Windows' + @aedgK12HowToTipHash['EN28'] = 'EN28 Building Form and Window Orientation' + @aedgK12HowToTipHash['EN29'] = 'EN29 Glazing' + @aedgK12HowToTipHash['EN30'] = 'EN30 Obstructions and Planting' + @aedgK12HowToTipHash['EN31'] = 'EN31 Window Orientation' + @aedgK12HowToTipHash['EN32'] = 'EN32 Passive Solar' + @aedgK12HowToTipHash['EN33'] = 'EN33 Glazing' # daylighting tips - @aedgK12HowToTipHash["DL01"] = "DL1 General Principles" - @aedgK12HowToTipHash["DL02"] = "DL2 Consider Daylighting Early in the Design Process" - @aedgK12HowToTipHash["DL03"] = "DL3 Space Types" - @aedgK12HowToTipHash["DL04"] = "DL4 How to Select Daylighting Strategies" - @aedgK12HowToTipHash["DL05"] = "DL5 Recommended Daylighting Fenestration-to-Floor Area Ratios" - @aedgK12HowToTipHash["DL06"] = "DL6 View Windows Separate from Daylighting Strategy" - @aedgK12HowToTipHash["DL07"] = "DL7 Lighting Design Criteria" - @aedgK12HowToTipHash["DL08"] = "DL8 Use Daylighting Analysis Tools to Optimize Design" - @aedgK12HowToTipHash["DL09"] = "DL9 Building Orientation" - @aedgK12HowToTipHash["DL10"] = "DL10 Ceiling Height" - @aedgK12HowToTipHash["DL11"] = "DL11 Outdoor Surface Reflectance" - @aedgK12HowToTipHash["DL12"] = "DL12 Eliminate Direct Beam Radiation" - @aedgK12HowToTipHash["DL13"] = "DL13 Daylighting Control for Audio-Visual (AV) Projection Activities" - @aedgK12HowToTipHash["DL14"] = "DL14 Interior Finishes for Daylighting" - @aedgK12HowToTipHash["DL15"] = "DL15 Calibration and Commissioning" - @aedgK12HowToTipHash["DL16"] = "DL16 Dimming Controls" - @aedgK12HowToTipHash["DL17"] = "DL17 Photosensor Placement and Lighting Layout" - @aedgK12HowToTipHash["DL18"] = "DL18 Photosensor Specifications" - @aedgK12HowToTipHash["DL19"] = "DL19 Select Compatible Light Fixtures" - @aedgK12HowToTipHash["DL20"] = "DL20 Sidelighting Patterns" - @aedgK12HowToTipHash["DL21"] = "DL21 South-Facing Classrooms-Configuration of Apertures" - @aedgK12HowToTipHash["DL22"] = "DL22 South-Facing Classrooms-Glazing Area and Fenestration Type" - @aedgK12HowToTipHash["DL23"] = "DL23 View Glazing and VTs" - @aedgK12HowToTipHash["DL24"] = "DL24 South-Facing Classrooms-Make Light Shelf Durable and Reflective" - @aedgK12HowToTipHash["DL25"] = "DL25 North-Facing Classroom-Configuration of Apertures" - @aedgK12HowToTipHash["DL26"] = "DL26 North-Facing Classroom-Glazing Area and Fenestration Type" - @aedgK12HowToTipHash["DL27"] = "DL27 South-and North-Facing Classrooms-Sloped Ceilings" - @aedgK12HowToTipHash["DL28"] = "DL28 South-and North-Facing Classrooms-Recognize the Limits of Side Daylighting" - @aedgK12HowToTipHash["DL29"] = "DL29 Classroom Toplighting Pattern" - @aedgK12HowToTipHash["DL30"] = "DL30 Sizing the Roof Monitors" - @aedgK12HowToTipHash["DL31"] = "DL31 Overhang for Roof Monitor" - @aedgK12HowToTipHash["DL32"] = "DL32 Use Light-Colored Roofing in Front of Monitors" - @aedgK12HowToTipHash["DL33"] = "DL33 Use Baffles to Block Direct Beam Radiation and Diffuse Light" - @aedgK12HowToTipHash["DL34"] = "DL34 Minimize Contrast at Well-Ceiling Intersection" - @aedgK12HowToTipHash["DL35"] = "DL35 Address the Monitor Design" - @aedgK12HowToTipHash["DL36"] = "DL36 Let the Heat Stratify" - @aedgK12HowToTipHash["DL37"] = "DL37 Minimize the Depth of the Ceiling Cavity" - @aedgK12HowToTipHash["DL38"] = "DL38 Classroom Sidelighting Plus Toplighting Pattern" - @aedgK12HowToTipHash["DL39"] = "DL39 Gym Toplighting Overview" - @aedgK12HowToTipHash["DL40"] = "DL40 Gym Toplighting Sizing" - @aedgK12HowToTipHash["DL41"] = "DL41 Gym Toplighting Using South-Facing Roof Monitors" - @aedgK12HowToTipHash["DL42"] = "DL42 Gym Toplighting in Combination with North-and South-Facing Sidelighting" + @aedgK12HowToTipHash['DL01'] = 'DL1 General Principles' + @aedgK12HowToTipHash['DL02'] = 'DL2 Consider Daylighting Early in the Design Process' + @aedgK12HowToTipHash['DL03'] = 'DL3 Space Types' + @aedgK12HowToTipHash['DL04'] = 'DL4 How to Select Daylighting Strategies' + @aedgK12HowToTipHash['DL05'] = 'DL5 Recommended Daylighting Fenestration-to-Floor Area Ratios' + @aedgK12HowToTipHash['DL06'] = 'DL6 View Windows Separate from Daylighting Strategy' + @aedgK12HowToTipHash['DL07'] = 'DL7 Lighting Design Criteria' + @aedgK12HowToTipHash['DL08'] = 'DL8 Use Daylighting Analysis Tools to Optimize Design' + @aedgK12HowToTipHash['DL09'] = 'DL9 Building Orientation' + @aedgK12HowToTipHash['DL10'] = 'DL10 Ceiling Height' + @aedgK12HowToTipHash['DL11'] = 'DL11 Outdoor Surface Reflectance' + @aedgK12HowToTipHash['DL12'] = 'DL12 Eliminate Direct Beam Radiation' + @aedgK12HowToTipHash['DL13'] = 'DL13 Daylighting Control for Audio-Visual (AV) Projection Activities' + @aedgK12HowToTipHash['DL14'] = 'DL14 Interior Finishes for Daylighting' + @aedgK12HowToTipHash['DL15'] = 'DL15 Calibration and Commissioning' + @aedgK12HowToTipHash['DL16'] = 'DL16 Dimming Controls' + @aedgK12HowToTipHash['DL17'] = 'DL17 Photosensor Placement and Lighting Layout' + @aedgK12HowToTipHash['DL18'] = 'DL18 Photosensor Specifications' + @aedgK12HowToTipHash['DL19'] = 'DL19 Select Compatible Light Fixtures' + @aedgK12HowToTipHash['DL20'] = 'DL20 Sidelighting Patterns' + @aedgK12HowToTipHash['DL21'] = 'DL21 South-Facing Classrooms-Configuration of Apertures' + @aedgK12HowToTipHash['DL22'] = 'DL22 South-Facing Classrooms-Glazing Area and Fenestration Type' + @aedgK12HowToTipHash['DL23'] = 'DL23 View Glazing and VTs' + @aedgK12HowToTipHash['DL24'] = 'DL24 South-Facing Classrooms-Make Light Shelf Durable and Reflective' + @aedgK12HowToTipHash['DL25'] = 'DL25 North-Facing Classroom-Configuration of Apertures' + @aedgK12HowToTipHash['DL26'] = 'DL26 North-Facing Classroom-Glazing Area and Fenestration Type' + @aedgK12HowToTipHash['DL27'] = 'DL27 South-and North-Facing Classrooms-Sloped Ceilings' + @aedgK12HowToTipHash['DL28'] = 'DL28 South-and North-Facing Classrooms-Recognize the Limits of Side Daylighting' + @aedgK12HowToTipHash['DL29'] = 'DL29 Classroom Toplighting Pattern' + @aedgK12HowToTipHash['DL30'] = 'DL30 Sizing the Roof Monitors' + @aedgK12HowToTipHash['DL31'] = 'DL31 Overhang for Roof Monitor' + @aedgK12HowToTipHash['DL32'] = 'DL32 Use Light-Colored Roofing in Front of Monitors' + @aedgK12HowToTipHash['DL33'] = 'DL33 Use Baffles to Block Direct Beam Radiation and Diffuse Light' + @aedgK12HowToTipHash['DL34'] = 'DL34 Minimize Contrast at Well-Ceiling Intersection' + @aedgK12HowToTipHash['DL35'] = 'DL35 Address the Monitor Design' + @aedgK12HowToTipHash['DL36'] = 'DL36 Let the Heat Stratify' + @aedgK12HowToTipHash['DL37'] = 'DL37 Minimize the Depth of the Ceiling Cavity' + @aedgK12HowToTipHash['DL38'] = 'DL38 Classroom Sidelighting Plus Toplighting Pattern' + @aedgK12HowToTipHash['DL39'] = 'DL39 Gym Toplighting Overview' + @aedgK12HowToTipHash['DL40'] = 'DL40 Gym Toplighting Sizing' + @aedgK12HowToTipHash['DL41'] = 'DL41 Gym Toplighting Using South-Facing Roof Monitors' + @aedgK12HowToTipHash['DL42'] = 'DL42 Gym Toplighting in Combination with North-and South-Facing Sidelighting' # electric lighting tips - @aedgK12HowToTipHash["EL01"] = "EL1 Light-Colored Interior Finishes" - @aedgK12HowToTipHash["EL02"] = "EL2 Color Rendering Index" - @aedgK12HowToTipHash["EL03"] = "EL3 Color Temperature" - @aedgK12HowToTipHash["EL04"] = "EL4 Linear Fluorescent Lamps and Ballasts" - @aedgK12HowToTipHash["EL05"] = "EL5 Compact Fluorescent" - @aedgK12HowToTipHash["EL06"] = "EL6 Metal Halide" - @aedgK12HowToTipHash["EL07"] = "EL7 Light-Emitting Diode (LED) Lighting" - @aedgK12HowToTipHash["EL08"] = "EL8 Occupancy Sensors" - @aedgK12HowToTipHash["EL09"] = "EL9 Multilevel Switching or Dimming" - @aedgK12HowToTipHash["EL10"] = "EL10 Exit Signs" - @aedgK12HowToTipHash["EL11"] = "EL11 Circuiting and Switching" - @aedgK12HowToTipHash["EL12"] = "EL12 Electrical Lighting Design for Schools" - @aedgK12HowToTipHash["EL13"] = "EL13 Classroom Lighting" - @aedgK12HowToTipHash["EL14"] = "EL14 Gym Lighting" - @aedgK12HowToTipHash["EL15"] = "EL15 Lighting for a Multipurpose Room" - @aedgK12HowToTipHash["EL16"] = "EL16 Lighting for a Library or Media Center" - @aedgK12HowToTipHash["EL17"] = "EL17 Corridor Lighting" - @aedgK12HowToTipHash["EL18"] = "EL18 Lighting for Offices and Teacher Support Rooms" - @aedgK12HowToTipHash["EL19"] = "EL19 Lighting for Locker Areas and Restrooms" - @aedgK12HowToTipHash["EL20"] = "EL20 Twenty-Four Hour Lighting" - @aedgK12HowToTipHash["EL21"] = "EL21 Exterior Lighting Power-Parking Lots and Drives" - @aedgK12HowToTipHash["EL22"] = "EL22 Exterior Lighting Power-Walkways" - @aedgK12HowToTipHash["EL23"] = "EL23 Decorative Façade Lighting" - @aedgK12HowToTipHash["EL24"] = "EL24 Sources" - @aedgK12HowToTipHash["EL25"] = "EL25 Controls" + @aedgK12HowToTipHash['EL01'] = 'EL1 Light-Colored Interior Finishes' + @aedgK12HowToTipHash['EL02'] = 'EL2 Color Rendering Index' + @aedgK12HowToTipHash['EL03'] = 'EL3 Color Temperature' + @aedgK12HowToTipHash['EL04'] = 'EL4 Linear Fluorescent Lamps and Ballasts' + @aedgK12HowToTipHash['EL05'] = 'EL5 Compact Fluorescent' + @aedgK12HowToTipHash['EL06'] = 'EL6 Metal Halide' + @aedgK12HowToTipHash['EL07'] = 'EL7 Light-Emitting Diode (LED) Lighting' + @aedgK12HowToTipHash['EL08'] = 'EL8 Occupancy Sensors' + @aedgK12HowToTipHash['EL09'] = 'EL9 Multilevel Switching or Dimming' + @aedgK12HowToTipHash['EL10'] = 'EL10 Exit Signs' + @aedgK12HowToTipHash['EL11'] = 'EL11 Circuiting and Switching' + @aedgK12HowToTipHash['EL12'] = 'EL12 Electrical Lighting Design for Schools' + @aedgK12HowToTipHash['EL13'] = 'EL13 Classroom Lighting' + @aedgK12HowToTipHash['EL14'] = 'EL14 Gym Lighting' + @aedgK12HowToTipHash['EL15'] = 'EL15 Lighting for a Multipurpose Room' + @aedgK12HowToTipHash['EL16'] = 'EL16 Lighting for a Library or Media Center' + @aedgK12HowToTipHash['EL17'] = 'EL17 Corridor Lighting' + @aedgK12HowToTipHash['EL18'] = 'EL18 Lighting for Offices and Teacher Support Rooms' + @aedgK12HowToTipHash['EL19'] = 'EL19 Lighting for Locker Areas and Restrooms' + @aedgK12HowToTipHash['EL20'] = 'EL20 Twenty-Four Hour Lighting' + @aedgK12HowToTipHash['EL21'] = 'EL21 Exterior Lighting Power-Parking Lots and Drives' + @aedgK12HowToTipHash['EL22'] = 'EL22 Exterior Lighting Power-Walkways' + @aedgK12HowToTipHash['EL23'] = 'EL23 Decorative Façade Lighting' + @aedgK12HowToTipHash['EL24'] = 'EL24 Sources' + @aedgK12HowToTipHash['EL25'] = 'EL25 Controls' # plug load tips - @aedgK12HowToTipHash["PL01"] = "PL1 General Guidance" - @aedgK12HowToTipHash["PL02"] = "PL2 Computer (Information Technology) Equipment" - @aedgK12HowToTipHash["PL03"] = "PL3 Staff and Occupant Equipment Control" - @aedgK12HowToTipHash["PL04"] = "PL4 Phantom/Parasitic Loads" - @aedgK12HowToTipHash["PL05"] = "PL5 ENERGY STAR Appliances/Equipment" - @aedgK12HowToTipHash["PL06"] = "PL6 Electrical Distribution System" + @aedgK12HowToTipHash['PL01'] = 'PL1 General Guidance' + @aedgK12HowToTipHash['PL02'] = 'PL2 Computer (Information Technology) Equipment' + @aedgK12HowToTipHash['PL03'] = 'PL3 Staff and Occupant Equipment Control' + @aedgK12HowToTipHash['PL04'] = 'PL4 Phantom/Parasitic Loads' + @aedgK12HowToTipHash['PL05'] = 'PL5 ENERGY STAR Appliances/Equipment' + @aedgK12HowToTipHash['PL06'] = 'PL6 Electrical Distribution System' # kitchen tips - @aedgK12HowToTipHash["KE01"] = "KE1 General Guidance" - @aedgK12HowToTipHash["KE02"] = "KE2 Energy-Efficient Kitchen Equipment" - @aedgK12HowToTipHash["KE03"] = "KE3 Exhaust and Ventilation Energy Use" - @aedgK12HowToTipHash["KE04"] = "KE4 Minimize Hot-Water Use" - @aedgK12HowToTipHash["KE05"] = "KE5 High-Efficiency Walk-in Refrigeration Systems" - @aedgK12HowToTipHash["KE06"] = "KE6 Position Hooded Appliances to Achieve Lower Exhaust Rates" - @aedgK12HowToTipHash["KE07"] = "KE7 Operating Considerations" + @aedgK12HowToTipHash['KE01'] = 'KE1 General Guidance' + @aedgK12HowToTipHash['KE02'] = 'KE2 Energy-Efficient Kitchen Equipment' + @aedgK12HowToTipHash['KE03'] = 'KE3 Exhaust and Ventilation Energy Use' + @aedgK12HowToTipHash['KE04'] = 'KE4 Minimize Hot-Water Use' + @aedgK12HowToTipHash['KE05'] = 'KE5 High-Efficiency Walk-in Refrigeration Systems' + @aedgK12HowToTipHash['KE06'] = 'KE6 Position Hooded Appliances to Achieve Lower Exhaust Rates' + @aedgK12HowToTipHash['KE07'] = 'KE7 Operating Considerations' # service water heating tips - @aedgK12HowToTipHash["WH01"] = "WH1 Service Water -Heating Types" - @aedgK12HowToTipHash["WH02"] = "WH2 System Descriptions" - @aedgK12HowToTipHash["WH03"] = "WH3 Sizing" - @aedgK12HowToTipHash["WH04"] = "WH4 Equipment Efficiency" - @aedgK12HowToTipHash["WH05"] = "WH5 Location" - @aedgK12HowToTipHash["WH06"] = "WH6 Pipe Insulation" - @aedgK12HowToTipHash["WH07"] = "WH7 Solar Hot-Water Systems" + @aedgK12HowToTipHash['WH01'] = 'WH1 Service Water -Heating Types' + @aedgK12HowToTipHash['WH02'] = 'WH2 System Descriptions' + @aedgK12HowToTipHash['WH03'] = 'WH3 Sizing' + @aedgK12HowToTipHash['WH04'] = 'WH4 Equipment Efficiency' + @aedgK12HowToTipHash['WH05'] = 'WH5 Location' + @aedgK12HowToTipHash['WH06'] = 'WH6 Pipe Insulation' + @aedgK12HowToTipHash['WH07'] = 'WH7 Solar Hot-Water Systems' # hvac tips - @aedgK12HowToTipHash["HV01"] = "HV1 Ground-Source Heat Pump System" - @aedgK12HowToTipHash["HV02"] = "HV2 Fan-Coil System" - @aedgK12HowToTipHash["HV03"] = "HV3 Multiple-Zone, Variable-Air-Volume (VAV) Air Handlers" - @aedgK12HowToTipHash["HV04"] = "HV4 Dedicated Outdoor Air System (DOAS)" - @aedgK12HowToTipHash["HV05"] = "HV5 Exhaust Air Energy Recovery" - @aedgK12HowToTipHash["HV06"] = "HV6 Chilled-Water System" - @aedgK12HowToTipHash["HV07"] = "HV7 Water Heating System" - @aedgK12HowToTipHash["HV08"] = "HV8 Condenser-Water System for GSHPs" - @aedgK12HowToTipHash["HV09"] = "HV9 Cooling and Heating Load Calculations" - @aedgK12HowToTipHash["HV10"] = "HV10 Ventilation Air" - @aedgK12HowToTipHash["HV11"] = "HV11 Cooling and Heating Equipment Efficiencies" - @aedgK12HowToTipHash["HV12"] = "HV12 Fan Power and Motor Efficiencies" - @aedgK12HowToTipHash["HV13"] = "HV13 Part-Load Dehumidification" - @aedgK12HowToTipHash["HV14"] = "HV14 Economizer" - @aedgK12HowToTipHash["HV15"] = "HV15 Demand-Controlled Ventilation" - @aedgK12HowToTipHash["HV16"] = "HV16 System-Level Control Strategies" - @aedgK12HowToTipHash["HV17"] = "HV17 Thermal Zoning" - @aedgK12HowToTipHash["HV18"] = "HV18 Ductwork Design and Construction" - @aedgK12HowToTipHash["HV19"] = "HV19 Duct Insulation" - @aedgK12HowToTipHash["HV20"] = "HV20 Duct Sealing and Leakage Testing" - @aedgK12HowToTipHash["HV21"] = "HV21 Exhaust Air Systems" - @aedgK12HowToTipHash["HV22"] = "HV22 Testing, Adjusting, and Balancing" - @aedgK12HowToTipHash["HV23"] = "HV23 Air Cleaning" - @aedgK12HowToTipHash["HV24"] = "HV24 Relief versus Return Fans" - @aedgK12HowToTipHash["HV25"] = "HV25 Zone Temperature Control" - @aedgK12HowToTipHash["HV26"] = "HV26 Heating Sources" - @aedgK12HowToTipHash["HV27"] = "HV27 Noise Control" - @aedgK12HowToTipHash["HV28"] = "HV28 Proper Maintenance" + @aedgK12HowToTipHash['HV01'] = 'HV1 Ground-Source Heat Pump System' + @aedgK12HowToTipHash['HV02'] = 'HV2 Fan-Coil System' + @aedgK12HowToTipHash['HV03'] = 'HV3 Multiple-Zone, Variable-Air-Volume (VAV) Air Handlers' + @aedgK12HowToTipHash['HV04'] = 'HV4 Dedicated Outdoor Air System (DOAS)' + @aedgK12HowToTipHash['HV05'] = 'HV5 Exhaust Air Energy Recovery' + @aedgK12HowToTipHash['HV06'] = 'HV6 Chilled-Water System' + @aedgK12HowToTipHash['HV07'] = 'HV7 Water Heating System' + @aedgK12HowToTipHash['HV08'] = 'HV8 Condenser-Water System for GSHPs' + @aedgK12HowToTipHash['HV09'] = 'HV9 Cooling and Heating Load Calculations' + @aedgK12HowToTipHash['HV10'] = 'HV10 Ventilation Air' + @aedgK12HowToTipHash['HV11'] = 'HV11 Cooling and Heating Equipment Efficiencies' + @aedgK12HowToTipHash['HV12'] = 'HV12 Fan Power and Motor Efficiencies' + @aedgK12HowToTipHash['HV13'] = 'HV13 Part-Load Dehumidification' + @aedgK12HowToTipHash['HV14'] = 'HV14 Economizer' + @aedgK12HowToTipHash['HV15'] = 'HV15 Demand-Controlled Ventilation' + @aedgK12HowToTipHash['HV16'] = 'HV16 System-Level Control Strategies' + @aedgK12HowToTipHash['HV17'] = 'HV17 Thermal Zoning' + @aedgK12HowToTipHash['HV18'] = 'HV18 Ductwork Design and Construction' + @aedgK12HowToTipHash['HV19'] = 'HV19 Duct Insulation' + @aedgK12HowToTipHash['HV20'] = 'HV20 Duct Sealing and Leakage Testing' + @aedgK12HowToTipHash['HV21'] = 'HV21 Exhaust Air Systems' + @aedgK12HowToTipHash['HV22'] = 'HV22 Testing, Adjusting, and Balancing' + @aedgK12HowToTipHash['HV23'] = 'HV23 Air Cleaning' + @aedgK12HowToTipHash['HV24'] = 'HV24 Relief versus Return Fans' + @aedgK12HowToTipHash['HV25'] = 'HV25 Zone Temperature Control' + @aedgK12HowToTipHash['HV26'] = 'HV26 Heating Sources' + @aedgK12HowToTipHash['HV27'] = 'HV27 Noise Control' + @aedgK12HowToTipHash['HV28'] = 'HV28 Proper Maintenance' # bonus hvac tips - @aedgK12HowToTipHash["HV29"] = "HV29 Natural Ventilation and Naturally Conditioned Spaces" - @aedgK12HowToTipHash["HV30"] = "HV30 Thermal Storage" - @aedgK12HowToTipHash["HV31"] = "HV31 Thermal Mass" - @aedgK12HowToTipHash["HV32"] = "HV32 Thermal Displacement Ventilation" - @aedgK12HowToTipHash["HV33"] = "HV33 ASHRAE Standard 62.1 IAQ Procedure" - @aedgK12HowToTipHash["HV34"] = "HV34 Evaporative Cooling" + @aedgK12HowToTipHash['HV29'] = 'HV29 Natural Ventilation and Naturally Conditioned Spaces' + @aedgK12HowToTipHash['HV30'] = 'HV30 Thermal Storage' + @aedgK12HowToTipHash['HV31'] = 'HV31 Thermal Mass' + @aedgK12HowToTipHash['HV32'] = 'HV32 Thermal Displacement Ventilation' + @aedgK12HowToTipHash['HV33'] = 'HV33 ASHRAE Standard 62.1 IAQ Procedure' + @aedgK12HowToTipHash['HV34'] = 'HV34 Evaporative Cooling' # commissioning tips - @aedgK12HowToTipHash["QA01"] = "QA1 Design and Construction Team" - @aedgK12HowToTipHash["QA02"] = "QA2 Owner’s Project Requirements and Basis of Design" - @aedgK12HowToTipHash["QA03"] = "QA3 Selection of Quality Assurance Provider" - @aedgK12HowToTipHash["QA04"] = "QA4 Design and Construction Schedule" - @aedgK12HowToTipHash["QA05"] = "QA5 Design Review" - @aedgK12HowToTipHash["QA06"] = "QA6 Defining Quality Assurance at Pre-Bid" - @aedgK12HowToTipHash["QA07"] = "QA7 Verifying Building Envelope Construction" - @aedgK12HowToTipHash["QA08"] = "QA8 Verifying Lighting Construction" - @aedgK12HowToTipHash["QA09"] = "QA9 Verifying Electrical and HVAC Systems Construction" - @aedgK12HowToTipHash["QA10"] = "QA10 Functional Performance Testing" - @aedgK12HowToTipHash["QA11"] = "QA11 Substantial Completion" - @aedgK12HowToTipHash["QA12"] = "QA12 Final Acceptance" - @aedgK12HowToTipHash["QA13"] = "QA13 Establish Building Operation and Maintenance Program" - @aedgK12HowToTipHash["QA14"] = "QA14 Monitor Post-Occupancy Performance" - @aedgK12HowToTipHash["QA15"] = "QA15 M&V Electrical Panel Guidance" - @aedgK12HowToTipHash["QA16"] = "QA16 M&V Data Management and Access" - @aedgK12HowToTipHash["QA17"] = "QA17 M&V Benchmarking" - @aedgK12HowToTipHash["QA18"] = "QA18 The Building as a Teaching Tool" + @aedgK12HowToTipHash['QA01'] = 'QA1 Design and Construction Team' + @aedgK12HowToTipHash['QA02'] = 'QA2 Owner’s Project Requirements and Basis of Design' + @aedgK12HowToTipHash['QA03'] = 'QA3 Selection of Quality Assurance Provider' + @aedgK12HowToTipHash['QA04'] = 'QA4 Design and Construction Schedule' + @aedgK12HowToTipHash['QA05'] = 'QA5 Design Review' + @aedgK12HowToTipHash['QA06'] = 'QA6 Defining Quality Assurance at Pre-Bid' + @aedgK12HowToTipHash['QA07'] = 'QA7 Verifying Building Envelope Construction' + @aedgK12HowToTipHash['QA08'] = 'QA8 Verifying Lighting Construction' + @aedgK12HowToTipHash['QA09'] = 'QA9 Verifying Electrical and HVAC Systems Construction' + @aedgK12HowToTipHash['QA10'] = 'QA10 Functional Performance Testing' + @aedgK12HowToTipHash['QA11'] = 'QA11 Substantial Completion' + @aedgK12HowToTipHash['QA12'] = 'QA12 Final Acceptance' + @aedgK12HowToTipHash['QA13'] = 'QA13 Establish Building Operation and Maintenance Program' + @aedgK12HowToTipHash['QA14'] = 'QA14 Monitor Post-Occupancy Performance' + @aedgK12HowToTipHash['QA15'] = 'QA15 M&V Electrical Panel Guidance' + @aedgK12HowToTipHash['QA16'] = 'QA16 M&V Data Management and Access' + @aedgK12HowToTipHash['QA17'] = 'QA17 M&V Benchmarking' + @aedgK12HowToTipHash['QA18'] = 'QA18 The Building as a Teaching Tool' # renewable energy tips - @aedgK12HowToTipHash["RE01"] = "RE1 Photovoltaic (PV) Systems" - @aedgK12HowToTipHash["RE02"] = "RE2 Solar Hot Water Systems" - @aedgK12HowToTipHash["RE03"] = "RE3 Wind Turbine Power" + @aedgK12HowToTipHash['RE01'] = 'RE1 Photovoltaic (PV) Systems' + @aedgK12HowToTipHash['RE02'] = 'RE2 Solar Hot Water Systems' + @aedgK12HowToTipHash['RE03'] = 'RE3 Wind Turbine Power' result = @aedgK12HowToTipHash return result + end # end of OsLib_AedgMeasures.getK12Tips - end #end of OsLib_AedgMeasures.getK12Tips - - - #hash of how to tips for small to medium office buildings AEDG - def OsLib_AedgMeasures.getSmMdOffTips - + # hash of how to tips for small to medium office buildings AEDG + def self.getSmMdOffTips # envelope tips - aedgSmMdOffHowToTipHash = Hash.new("Small and Medium Offices AEDG How to Implement Recommendations") - aedgSmMdOffHowToTipHash["EN01"] = "EN1 Cool Roofs" - aedgSmMdOffHowToTipHash["EN02"] = "EN2 Roofs-Insulation Entirely above Deck" - aedgSmMdOffHowToTipHash["EN03"] = "EN3 Roofs-Attics, and Other Roofs" - aedgSmMdOffHowToTipHash["EN04"] = "EN4 Roofs-Metal Buildings" - aedgSmMdOffHowToTipHash["EN05"] = "EN5 Walls-Mass" - aedgSmMdOffHowToTipHash["EN06"] = "EN6 Walls-Steel Framed" - aedgSmMdOffHowToTipHash["EN07"] = "EN7 Walls-Wood Frame and Other" - aedgSmMdOffHowToTipHash["EN08"] = "EN8 Walls-Metal Building" - aedgSmMdOffHowToTipHash["EN09"] = "EN9 Walls-Below-Grade" - aedgSmMdOffHowToTipHash["EN10"] = "EN10 Floors-Mass" - aedgSmMdOffHowToTipHash["EN11"] = "EN11 Floors-Metal Joist or Wood Joist/Wood Frame" - aedgSmMdOffHowToTipHash["EN12"] = "EN12 Slab-on-Grade Floors-Unheated" - aedgSmMdOffHowToTipHash["EN13"] = "EN13 Slab-on-Grade Floors-Heated" - aedgSmMdOffHowToTipHash["EN14"] = "EN14 Slab Edge Insulation" - aedgSmMdOffHowToTipHash["EN15"] = "EN15 Doors-Opaque, Swinging" - aedgSmMdOffHowToTipHash["EN16"] = "EN16 Doors-Opaque, Roll-Up, or Sliding" - aedgSmMdOffHowToTipHash["EN17"] = "EN17 Air Infiltration Control" - aedgSmMdOffHowToTipHash["EN18"] = "EN18 Vestibules" - aedgSmMdOffHowToTipHash["EN19"] = "EN19 Alternative Constructions" - aedgSmMdOffHowToTipHash["EN20"] = "EN20 Truss Heel Heights" - aedgSmMdOffHowToTipHash["EN21"] = "EN21 Moisture Control" - aedgSmMdOffHowToTipHash["EN22"] = "EN22 Thermal Bridging-Opaque Components" - aedgSmMdOffHowToTipHash["EN23"] = "EN23 Thermal Bridging-Fenestration" - aedgSmMdOffHowToTipHash["EN24"] = "EN24 Vertical Fenestration Descriptions" - aedgSmMdOffHowToTipHash["EN25"] = "EN25 Window-to-Wall Ratio (WWR)" - aedgSmMdOffHowToTipHash["EN26"] = "EN26 Unwanted Solar Heat Gain Is Most Effectively Controlled on the Outside of the Building" - aedgSmMdOffHowToTipHash["EN27"] = "EN27 Operable versus Fixed Windows" - aedgSmMdOffHowToTipHash["EN28"] = "EN28 Building Form and Window Orientation" - aedgSmMdOffHowToTipHash["EN29"] = "EN29 Glazing" - aedgSmMdOffHowToTipHash["EN30"] = "EN30 Obstructions and Planting" - aedgSmMdOffHowToTipHash["EN31"] = "EN31 Window Orientation" - aedgSmMdOffHowToTipHash["EN32"] = "EN32 Passive Solar" - aedgSmMdOffHowToTipHash["EN33"] = "EN33 Glazing" - aedgSmMdOffHowToTipHash["EN34"] = "EN34 Visible Transmittance (VT)" - aedgSmMdOffHowToTipHash["EN35"] = "EN35 Separating Views and Daylight" - aedgSmMdOffHowToTipHash["EN36"] = "EN36 Color-Neutral Glazing" - aedgSmMdOffHowToTipHash["EN37"] = "EN37 Reflectivity of Glass" - aedgSmMdOffHowToTipHash["EN38"] = "EN38 Light-to-Solar-Gain Ratio" - aedgSmMdOffHowToTipHash["EN39"] = "EN39 High Ceilings" - aedgSmMdOffHowToTipHash["EN40"] = "EN40 Light Shelves" + aedgSmMdOffHowToTipHash = Hash.new('Small and Medium Offices AEDG How to Implement Recommendations') + aedgSmMdOffHowToTipHash['EN01'] = 'EN1 Cool Roofs' + aedgSmMdOffHowToTipHash['EN02'] = 'EN2 Roofs-Insulation Entirely above Deck' + aedgSmMdOffHowToTipHash['EN03'] = 'EN3 Roofs-Attics, and Other Roofs' + aedgSmMdOffHowToTipHash['EN04'] = 'EN4 Roofs-Metal Buildings' + aedgSmMdOffHowToTipHash['EN05'] = 'EN5 Walls-Mass' + aedgSmMdOffHowToTipHash['EN06'] = 'EN6 Walls-Steel Framed' + aedgSmMdOffHowToTipHash['EN07'] = 'EN7 Walls-Wood Frame and Other' + aedgSmMdOffHowToTipHash['EN08'] = 'EN8 Walls-Metal Building' + aedgSmMdOffHowToTipHash['EN09'] = 'EN9 Walls-Below-Grade' + aedgSmMdOffHowToTipHash['EN10'] = 'EN10 Floors-Mass' + aedgSmMdOffHowToTipHash['EN11'] = 'EN11 Floors-Metal Joist or Wood Joist/Wood Frame' + aedgSmMdOffHowToTipHash['EN12'] = 'EN12 Slab-on-Grade Floors-Unheated' + aedgSmMdOffHowToTipHash['EN13'] = 'EN13 Slab-on-Grade Floors-Heated' + aedgSmMdOffHowToTipHash['EN14'] = 'EN14 Slab Edge Insulation' + aedgSmMdOffHowToTipHash['EN15'] = 'EN15 Doors-Opaque, Swinging' + aedgSmMdOffHowToTipHash['EN16'] = 'EN16 Doors-Opaque, Roll-Up, or Sliding' + aedgSmMdOffHowToTipHash['EN17'] = 'EN17 Air Infiltration Control' + aedgSmMdOffHowToTipHash['EN18'] = 'EN18 Vestibules' + aedgSmMdOffHowToTipHash['EN19'] = 'EN19 Alternative Constructions' + aedgSmMdOffHowToTipHash['EN20'] = 'EN20 Truss Heel Heights' + aedgSmMdOffHowToTipHash['EN21'] = 'EN21 Moisture Control' + aedgSmMdOffHowToTipHash['EN22'] = 'EN22 Thermal Bridging-Opaque Components' + aedgSmMdOffHowToTipHash['EN23'] = 'EN23 Thermal Bridging-Fenestration' + aedgSmMdOffHowToTipHash['EN24'] = 'EN24 Vertical Fenestration Descriptions' + aedgSmMdOffHowToTipHash['EN25'] = 'EN25 Window-to-Wall Ratio (WWR)' + aedgSmMdOffHowToTipHash['EN26'] = 'EN26 Unwanted Solar Heat Gain Is Most Effectively Controlled on the Outside of the Building' + aedgSmMdOffHowToTipHash['EN27'] = 'EN27 Operable versus Fixed Windows' + aedgSmMdOffHowToTipHash['EN28'] = 'EN28 Building Form and Window Orientation' + aedgSmMdOffHowToTipHash['EN29'] = 'EN29 Glazing' + aedgSmMdOffHowToTipHash['EN30'] = 'EN30 Obstructions and Planting' + aedgSmMdOffHowToTipHash['EN31'] = 'EN31 Window Orientation' + aedgSmMdOffHowToTipHash['EN32'] = 'EN32 Passive Solar' + aedgSmMdOffHowToTipHash['EN33'] = 'EN33 Glazing' + aedgSmMdOffHowToTipHash['EN34'] = 'EN34 Visible Transmittance (VT)' + aedgSmMdOffHowToTipHash['EN35'] = 'EN35 Separating Views and Daylight' + aedgSmMdOffHowToTipHash['EN36'] = 'EN36 Color-Neutral Glazing' + aedgSmMdOffHowToTipHash['EN37'] = 'EN37 Reflectivity of Glass' + aedgSmMdOffHowToTipHash['EN38'] = 'EN38 Light-to-Solar-Gain Ratio' + aedgSmMdOffHowToTipHash['EN39'] = 'EN39 High Ceilings' + aedgSmMdOffHowToTipHash['EN40'] = 'EN40 Light Shelves' # daylighting tips - aedgSmMdOffHowToTipHash["DL01"] = "DL1 Daylighting Early in the Design Process" - aedgSmMdOffHowToTipHash["DL02"] = "DL2 Daylighting Analysis Tools to Optimize Design" - aedgSmMdOffHowToTipHash["DL03"] = "DL3 Space Types, Layout, and Daylight" - aedgSmMdOffHowToTipHash["DL04"] = "DL4 Building Orientation and Daylight" - aedgSmMdOffHowToTipHash["DL05"] = "DL5 Building Shape and Daylight" - aedgSmMdOffHowToTipHash["DL06"] = "DL6 Window-to-Wall Ratio (WWR)" - aedgSmMdOffHowToTipHash["DL07"] = "DL7 Sidelighting-Ceiling and Window Height" - aedgSmMdOffHowToTipHash["DL08"] = "Sidelighting-Clerestory Windows" - aedgSmMdOffHowToTipHash["DL09"] = "DL9 Sidelighting-Borrowed Light" - aedgSmMdOffHowToTipHash["DL10"] = "DL10 Sidelighting-Wall-to-Wall Windows" - aedgSmMdOffHowToTipHash["DL11"] = "DL11 Sidelighting-Punched Windows" - aedgSmMdOffHowToTipHash["DL12"] = "DL12 Shading Systems to Eliminate Direct-Beam Radiation" - aedgSmMdOffHowToTipHash["DL13"] = "DL13 Daylighting Control for Audiovisual Activities" - aedgSmMdOffHowToTipHash["DL14"] = "DL14 Interior Finishes for Daylighting" - aedgSmMdOffHowToTipHash["DL15"] = "DL15 Outdoor Surface Reflectance" - aedgSmMdOffHowToTipHash["DL16"] = "DL16 Calibration and Commissioning" - aedgSmMdOffHowToTipHash["DL17"] = "DL17 Dimming Controls" - aedgSmMdOffHowToTipHash["DL18"] = "DL18 Photosensor Placement and Lighting Layout" - aedgSmMdOffHowToTipHash["DL19"] = "DL19 Photosensor Specifications" - aedgSmMdOffHowToTipHash["DL20"] = "DL20 Select Compatible Light Fixtures" + aedgSmMdOffHowToTipHash['DL01'] = 'DL1 Daylighting Early in the Design Process' + aedgSmMdOffHowToTipHash['DL02'] = 'DL2 Daylighting Analysis Tools to Optimize Design' + aedgSmMdOffHowToTipHash['DL03'] = 'DL3 Space Types, Layout, and Daylight' + aedgSmMdOffHowToTipHash['DL04'] = 'DL4 Building Orientation and Daylight' + aedgSmMdOffHowToTipHash['DL05'] = 'DL5 Building Shape and Daylight' + aedgSmMdOffHowToTipHash['DL06'] = 'DL6 Window-to-Wall Ratio (WWR)' + aedgSmMdOffHowToTipHash['DL07'] = 'DL7 Sidelighting-Ceiling and Window Height' + aedgSmMdOffHowToTipHash['DL08'] = 'Sidelighting-Clerestory Windows' + aedgSmMdOffHowToTipHash['DL09'] = 'DL9 Sidelighting-Borrowed Light' + aedgSmMdOffHowToTipHash['DL10'] = 'DL10 Sidelighting-Wall-to-Wall Windows' + aedgSmMdOffHowToTipHash['DL11'] = 'DL11 Sidelighting-Punched Windows' + aedgSmMdOffHowToTipHash['DL12'] = 'DL12 Shading Systems to Eliminate Direct-Beam Radiation' + aedgSmMdOffHowToTipHash['DL13'] = 'DL13 Daylighting Control for Audiovisual Activities' + aedgSmMdOffHowToTipHash['DL14'] = 'DL14 Interior Finishes for Daylighting' + aedgSmMdOffHowToTipHash['DL15'] = 'DL15 Outdoor Surface Reflectance' + aedgSmMdOffHowToTipHash['DL16'] = 'DL16 Calibration and Commissioning' + aedgSmMdOffHowToTipHash['DL17'] = 'DL17 Dimming Controls' + aedgSmMdOffHowToTipHash['DL18'] = 'DL18 Photosensor Placement and Lighting Layout' + aedgSmMdOffHowToTipHash['DL19'] = 'DL19 Photosensor Specifications' + aedgSmMdOffHowToTipHash['DL20'] = 'DL20 Select Compatible Light Fixtures' # bonus daylighting tips - aedgSmMdOffHowToTipHash["DL21"] = "DL21 Toplighting" - aedgSmMdOffHowToTipHash["DL22"] = "DL22 Rooftop Monitors" - aedgSmMdOffHowToTipHash["DL23"] = "DL23 Rooftop Monitor Design" - aedgSmMdOffHowToTipHash["DL24"] = "DL24 Skylights" - aedgSmMdOffHowToTipHash["DL25"] = "DL25 Toplighting-Thermal Transmittance (Climate Zones 1-3)" - aedgSmMdOffHowToTipHash["DL26"] = "DL26 Toplighting-Thermal Transmittance (Climate Zones 4-8)" - aedgSmMdOffHowToTipHash["DL27"] = "DL27 Toplighting-Ceiling Height Differentials" + aedgSmMdOffHowToTipHash['DL21'] = 'DL21 Toplighting' + aedgSmMdOffHowToTipHash['DL22'] = 'DL22 Rooftop Monitors' + aedgSmMdOffHowToTipHash['DL23'] = 'DL23 Rooftop Monitor Design' + aedgSmMdOffHowToTipHash['DL24'] = 'DL24 Skylights' + aedgSmMdOffHowToTipHash['DL25'] = 'DL25 Toplighting-Thermal Transmittance (Climate Zones 1-3)' + aedgSmMdOffHowToTipHash['DL26'] = 'DL26 Toplighting-Thermal Transmittance (Climate Zones 4-8)' + aedgSmMdOffHowToTipHash['DL27'] = 'DL27 Toplighting-Ceiling Height Differentials' # electric lighting tips - aedgSmMdOffHowToTipHash["EL01"] = "EL1 Savings and Occupant Acceptance" - aedgSmMdOffHowToTipHash["EL02"] = "EL2 Space Planning-Open Offices" - aedgSmMdOffHowToTipHash["EL03"] = "EL3 Space Planning-Private Offices, Conference Rooms, and Break Rooms" - aedgSmMdOffHowToTipHash["EL04"] = "EL4 Light-Colored Interior Finishes" - aedgSmMdOffHowToTipHash["EL05"] = "EL5 Task Lighting" - aedgSmMdOffHowToTipHash["EL06"] = "EL6 Color Rendering Index (CRI)" - aedgSmMdOffHowToTipHash["EL07"] = "EL7 Color Temperature" - aedgSmMdOffHowToTipHash["EL08"] = "EL8 Linear Fluorescent Lamps and Ballasts" - aedgSmMdOffHowToTipHash["EL09"] = "EL9 Occupancy Sensors" - aedgSmMdOffHowToTipHash["EL10"] = "EL10 Multilevel Switching" - aedgSmMdOffHowToTipHash["EL11"] = "EL11 Daylight-Responsive Controls" - aedgSmMdOffHowToTipHash["EL12"] = "EL12 Exit Signs" - aedgSmMdOffHowToTipHash["EL13"] = "EL13 Light Fixture Distribution" - aedgSmMdOffHowToTipHash["EL14"] = "EL14 Open-Plan Offices" - aedgSmMdOffHowToTipHash["EL15"] = "EL15 Private Offices" - aedgSmMdOffHowToTipHash["EL16"] = "EL16 Conference Rooms/Meeting Rooms" - aedgSmMdOffHowToTipHash["EL17"] = "EL17 Corridors" - aedgSmMdOffHowToTipHash["EL18"] = "EL18 Storage Areas" - aedgSmMdOffHowToTipHash["EL19"] = "EL19 Lobbies" - aedgSmMdOffHowToTipHash["EL20"] = "EL20 Twenty-Four Hour Lighting" - aedgSmMdOffHowToTipHash["EL21"] = "EL21 Exterior Lighting Power-Parking Lots and Drives" - aedgSmMdOffHowToTipHash["EL22"] = "EL22 Exterior Lighting Power-Walkways" - aedgSmMdOffHowToTipHash["EL23"] = "EL23 Decorative Façade Lighting" - aedgSmMdOffHowToTipHash["EL24"] = "EL24 Sources" - aedgSmMdOffHowToTipHash["EL25"] = "EL25 Controls" + aedgSmMdOffHowToTipHash['EL01'] = 'EL1 Savings and Occupant Acceptance' + aedgSmMdOffHowToTipHash['EL02'] = 'EL2 Space Planning-Open Offices' + aedgSmMdOffHowToTipHash['EL03'] = 'EL3 Space Planning-Private Offices, Conference Rooms, and Break Rooms' + aedgSmMdOffHowToTipHash['EL04'] = 'EL4 Light-Colored Interior Finishes' + aedgSmMdOffHowToTipHash['EL05'] = 'EL5 Task Lighting' + aedgSmMdOffHowToTipHash['EL06'] = 'EL6 Color Rendering Index (CRI)' + aedgSmMdOffHowToTipHash['EL07'] = 'EL7 Color Temperature' + aedgSmMdOffHowToTipHash['EL08'] = 'EL8 Linear Fluorescent Lamps and Ballasts' + aedgSmMdOffHowToTipHash['EL09'] = 'EL9 Occupancy Sensors' + aedgSmMdOffHowToTipHash['EL10'] = 'EL10 Multilevel Switching' + aedgSmMdOffHowToTipHash['EL11'] = 'EL11 Daylight-Responsive Controls' + aedgSmMdOffHowToTipHash['EL12'] = 'EL12 Exit Signs' + aedgSmMdOffHowToTipHash['EL13'] = 'EL13 Light Fixture Distribution' + aedgSmMdOffHowToTipHash['EL14'] = 'EL14 Open-Plan Offices' + aedgSmMdOffHowToTipHash['EL15'] = 'EL15 Private Offices' + aedgSmMdOffHowToTipHash['EL16'] = 'EL16 Conference Rooms/Meeting Rooms' + aedgSmMdOffHowToTipHash['EL17'] = 'EL17 Corridors' + aedgSmMdOffHowToTipHash['EL18'] = 'EL18 Storage Areas' + aedgSmMdOffHowToTipHash['EL19'] = 'EL19 Lobbies' + aedgSmMdOffHowToTipHash['EL20'] = 'EL20 Twenty-Four Hour Lighting' + aedgSmMdOffHowToTipHash['EL21'] = 'EL21 Exterior Lighting Power-Parking Lots and Drives' + aedgSmMdOffHowToTipHash['EL22'] = 'EL22 Exterior Lighting Power-Walkways' + aedgSmMdOffHowToTipHash['EL23'] = 'EL23 Decorative Façade Lighting' + aedgSmMdOffHowToTipHash['EL24'] = 'EL24 Sources' + aedgSmMdOffHowToTipHash['EL25'] = 'EL25 Controls' # plug load tips - aedgSmMdOffHowToTipHash["PL01"] = "PL1 Connected Wattage" - aedgSmMdOffHowToTipHash["PL02"] = "PL2 Laptop Computers" - aedgSmMdOffHowToTipHash["PL03"] = "PL3 Occupancy Controls" - aedgSmMdOffHowToTipHash["PL04"] = "PL4 Parasitic Loads" - aedgSmMdOffHowToTipHash["PL05"] = "PL5 Printing Equipment" - aedgSmMdOffHowToTipHash["PL06"] = "PL6 Unnecessary Equipment" + aedgSmMdOffHowToTipHash['PL01'] = 'PL1 Connected Wattage' + aedgSmMdOffHowToTipHash['PL02'] = 'PL2 Laptop Computers' + aedgSmMdOffHowToTipHash['PL03'] = 'PL3 Occupancy Controls' + aedgSmMdOffHowToTipHash['PL04'] = 'PL4 Parasitic Loads' + aedgSmMdOffHowToTipHash['PL05'] = 'PL5 Printing Equipment' + aedgSmMdOffHowToTipHash['PL06'] = 'PL6 Unnecessary Equipment' # service water heating tips - aedgSmMdOffHowToTipHash["WH01"] = "WH1 Service Water Heating Types" - aedgSmMdOffHowToTipHash["WH02"] = "WH2 System Descriptions" - aedgSmMdOffHowToTipHash["WH03"] = "WH3 Sizing" - aedgSmMdOffHowToTipHash["WH04"] = "WH4 Equipment Efficiency" - aedgSmMdOffHowToTipHash["WH05"] = "WH5 Location" - aedgSmMdOffHowToTipHash["WH06"] = "WH6 Pipe Insulation" + aedgSmMdOffHowToTipHash['WH01'] = 'WH1 Service Water Heating Types' + aedgSmMdOffHowToTipHash['WH02'] = 'WH2 System Descriptions' + aedgSmMdOffHowToTipHash['WH03'] = 'WH3 Sizing' + aedgSmMdOffHowToTipHash['WH04'] = 'WH4 Equipment Efficiency' + aedgSmMdOffHowToTipHash['WH05'] = 'WH5 Location' + aedgSmMdOffHowToTipHash['WH06'] = 'WH6 Pipe Insulation' # hvac tips - aedgSmMdOffHowToTipHash["HV01"] = "HV1 Cooling and Heating Loads" - aedgSmMdOffHowToTipHash["HV02"] = "HV2 Certification of HVAC Equipment" - aedgSmMdOffHowToTipHash["HV03"] = "HV3 Single-Zone, Packaged Air-Source Heat Pump Systems (or Split Heat Pump + aedgSmMdOffHowToTipHash['HV01'] = 'HV1 Cooling and Heating Loads' + aedgSmMdOffHowToTipHash['HV02'] = 'HV2 Certification of HVAC Equipment' + aedgSmMdOffHowToTipHash['HV03'] = "HV3 Single-Zone, Packaged Air-Source Heat Pump Systems (or Split Heat Pump Systems) with Electric Resistance Supplemental Heat and DOASs" - aedgSmMdOffHowToTipHash["HV04"] = "HV4 Water-Source Heat Pumps (WSHPs)" - aedgSmMdOffHowToTipHash["HV05"] = "HV5 Ground-Coupled Water-Source Heat Pump (WSHP) System" - aedgSmMdOffHowToTipHash["HV06"] = "HV6 Multiple-Zone, VAV Packaged DX Rooftop Units with a Hot-Water Coil, + aedgSmMdOffHowToTipHash['HV04'] = 'HV4 Water-Source Heat Pumps (WSHPs)' + aedgSmMdOffHowToTipHash['HV05'] = 'HV5 Ground-Coupled Water-Source Heat Pump (WSHP) System' + aedgSmMdOffHowToTipHash['HV06'] = "HV6 Multiple-Zone, VAV Packaged DX Rooftop Units with a Hot-Water Coil, Indirect Gas Furnace, or Electric Resistance in the Rooftop Unit and Convection Heat in the Spaces" - aedgSmMdOffHowToTipHash["HV07"] = "HV7 Multiple-Zone, VAV Air-Handling Units with Packaged Air-Cooled Chiller and + aedgSmMdOffHowToTipHash['HV07'] = "HV7 Multiple-Zone, VAV Air-Handling Units with Packaged Air-Cooled Chiller and Gas-Fired Boiler" - aedgSmMdOffHowToTipHash["HV08"] = "Fan-Coils" - aedgSmMdOffHowToTipHash["HV09"] = "HV9 Radiant Heating and Cooling and DOAS" - aedgSmMdOffHowToTipHash["HV10"] = "HV10 Dedicated Outdoor Air Systems (100% Outdoor Air Systems)" - aedgSmMdOffHowToTipHash["HV11"] = "HV11 Part-Load Dehumidification" - aedgSmMdOffHowToTipHash["HV12"] = "HV12 Exhaust Air Energy Recovery" - aedgSmMdOffHowToTipHash["HV13"] = "HV13 Indirect Evaporative Cooling" - aedgSmMdOffHowToTipHash["HV14"] = "HV14 Cooling and Heating Equipment Efficiencies" - aedgSmMdOffHowToTipHash["HV15"] = "HV15 Ventilation Air" - aedgSmMdOffHowToTipHash["HV16"] = "HV16 Economizer" - aedgSmMdOffHowToTipHash["HV17"] = "HV17 Demand-Controlled Ventilation (DCV)" - aedgSmMdOffHowToTipHash["HV18"] = "HV18 Carbon Dioxide (CO2 ) Sensors" - aedgSmMdOffHowToTipHash["HV19"] = "HV19 Exhaust Air Systems" - aedgSmMdOffHowToTipHash["HV20"] = "HV20 Ductwork Design and Construction" - aedgSmMdOffHowToTipHash["HV21"] = "HV21 Duct Insulation" - aedgSmMdOffHowToTipHash["HV22"] = "HV22 Duct Sealing and Leakage Testing" - aedgSmMdOffHowToTipHash["HV23"] = "HV23 Fan Motor Efficiencies" - aedgSmMdOffHowToTipHash["HV24"] = "HV24 Thermal Zoning" - aedgSmMdOffHowToTipHash["HV25"] = "HV25 System-Level Control Strategies" - aedgSmMdOffHowToTipHash["HV26"] = "HV26 Testing, Adjusting, and Balancing" - aedgSmMdOffHowToTipHash["HV27"] = "HV27 Commissioning (Cx)" - aedgSmMdOffHowToTipHash["HV28"] = "HV28 Filters" - aedgSmMdOffHowToTipHash["HV29"] = "HV29 Chilled-Water (CHW) System" - aedgSmMdOffHowToTipHash["HV30"] = "HV30 Water Heating Systems" - aedgSmMdOffHowToTipHash["HV31"] = "HV31 Relief versus Return Fans" - aedgSmMdOffHowToTipHash["HV32"] = "HV32 Heating Sources" - aedgSmMdOffHowToTipHash["HV33"] = "HV33 Noise Control" - aedgSmMdOffHowToTipHash["HV34"] = "HV34 Proper Maintenance" - aedgSmMdOffHowToTipHash["HV35"] = "HV35 Zone Temperature Control" - aedgSmMdOffHowToTipHash["HV36"] = "HV36 Evaporative Condensers on Rooftop Units" + aedgSmMdOffHowToTipHash['HV08'] = 'Fan-Coils' + aedgSmMdOffHowToTipHash['HV09'] = 'HV9 Radiant Heating and Cooling and DOAS' + aedgSmMdOffHowToTipHash['HV10'] = 'HV10 Dedicated Outdoor Air Systems (100% Outdoor Air Systems)' + aedgSmMdOffHowToTipHash['HV11'] = 'HV11 Part-Load Dehumidification' + aedgSmMdOffHowToTipHash['HV12'] = 'HV12 Exhaust Air Energy Recovery' + aedgSmMdOffHowToTipHash['HV13'] = 'HV13 Indirect Evaporative Cooling' + aedgSmMdOffHowToTipHash['HV14'] = 'HV14 Cooling and Heating Equipment Efficiencies' + aedgSmMdOffHowToTipHash['HV15'] = 'HV15 Ventilation Air' + aedgSmMdOffHowToTipHash['HV16'] = 'HV16 Economizer' + aedgSmMdOffHowToTipHash['HV17'] = 'HV17 Demand-Controlled Ventilation (DCV)' + aedgSmMdOffHowToTipHash['HV18'] = 'HV18 Carbon Dioxide (CO2 ) Sensors' + aedgSmMdOffHowToTipHash['HV19'] = 'HV19 Exhaust Air Systems' + aedgSmMdOffHowToTipHash['HV20'] = 'HV20 Ductwork Design and Construction' + aedgSmMdOffHowToTipHash['HV21'] = 'HV21 Duct Insulation' + aedgSmMdOffHowToTipHash['HV22'] = 'HV22 Duct Sealing and Leakage Testing' + aedgSmMdOffHowToTipHash['HV23'] = 'HV23 Fan Motor Efficiencies' + aedgSmMdOffHowToTipHash['HV24'] = 'HV24 Thermal Zoning' + aedgSmMdOffHowToTipHash['HV25'] = 'HV25 System-Level Control Strategies' + aedgSmMdOffHowToTipHash['HV26'] = 'HV26 Testing, Adjusting, and Balancing' + aedgSmMdOffHowToTipHash['HV27'] = 'HV27 Commissioning (Cx)' + aedgSmMdOffHowToTipHash['HV28'] = 'HV28 Filters' + aedgSmMdOffHowToTipHash['HV29'] = 'HV29 Chilled-Water (CHW) System' + aedgSmMdOffHowToTipHash['HV30'] = 'HV30 Water Heating Systems' + aedgSmMdOffHowToTipHash['HV31'] = 'HV31 Relief versus Return Fans' + aedgSmMdOffHowToTipHash['HV32'] = 'HV32 Heating Sources' + aedgSmMdOffHowToTipHash['HV33'] = 'HV33 Noise Control' + aedgSmMdOffHowToTipHash['HV34'] = 'HV34 Proper Maintenance' + aedgSmMdOffHowToTipHash['HV35'] = 'HV35 Zone Temperature Control' + aedgSmMdOffHowToTipHash['HV36'] = 'HV36 Evaporative Condensers on Rooftop Units' # commissioning tips - aedgSmMdOffHowToTipHash["QA01"] = "QA1 Selecting the Design and Construction Team" - aedgSmMdOffHowToTipHash["QA02"] = "QA2 Selecting the QA Provider" - aedgSmMdOffHowToTipHash["QA03"] = "QA3 Owner’s Project Requirements (OPR) and Basis of Design (BoD)" - aedgSmMdOffHowToTipHash["QA04"] = "QA4 Design and Construction Schedule" - aedgSmMdOffHowToTipHash["QA05"] = "QA5 Design Review" - aedgSmMdOffHowToTipHash["QA06"] = "QA6 Defining QA at Pre-Bid" - aedgSmMdOffHowToTipHash["QA07"] = "QA7 Verifying Building Envelope Construction" - aedgSmMdOffHowToTipHash["QA08"] = "QA8 Verifying Lighting Construction" - aedgSmMdOffHowToTipHash["QA09"] = "QA9 Verifying Electrical and HVAC Systems Construction" - aedgSmMdOffHowToTipHash["QA10"] = "QA10 Performance Testing" - aedgSmMdOffHowToTipHash["QA11"] = "QA11 Substantial Completion" - aedgSmMdOffHowToTipHash["QA12"] = "QA12 Final Acceptance" - aedgSmMdOffHowToTipHash["QA13"] = "QA13 Establish a Building Operation and Maintenance (O&M) Program" - aedgSmMdOffHowToTipHash["QA14"] = "QA14 Monitor Post-Occupancy Performance" + aedgSmMdOffHowToTipHash['QA01'] = 'QA1 Selecting the Design and Construction Team' + aedgSmMdOffHowToTipHash['QA02'] = 'QA2 Selecting the QA Provider' + aedgSmMdOffHowToTipHash['QA03'] = 'QA3 Owner’s Project Requirements (OPR) and Basis of Design (BoD)' + aedgSmMdOffHowToTipHash['QA04'] = 'QA4 Design and Construction Schedule' + aedgSmMdOffHowToTipHash['QA05'] = 'QA5 Design Review' + aedgSmMdOffHowToTipHash['QA06'] = 'QA6 Defining QA at Pre-Bid' + aedgSmMdOffHowToTipHash['QA07'] = 'QA7 Verifying Building Envelope Construction' + aedgSmMdOffHowToTipHash['QA08'] = 'QA8 Verifying Lighting Construction' + aedgSmMdOffHowToTipHash['QA09'] = 'QA9 Verifying Electrical and HVAC Systems Construction' + aedgSmMdOffHowToTipHash['QA10'] = 'QA10 Performance Testing' + aedgSmMdOffHowToTipHash['QA11'] = 'QA11 Substantial Completion' + aedgSmMdOffHowToTipHash['QA12'] = 'QA12 Final Acceptance' + aedgSmMdOffHowToTipHash['QA13'] = 'QA13 Establish a Building Operation and Maintenance (O&M) Program' + aedgSmMdOffHowToTipHash['QA14'] = 'QA14 Monitor Post-Occupancy Performance' # natural ventilation tips - aedgSmMdOffHowToTipHash["NV01"] = "NV1 Natural Ventilation and Naturally Conditioned Spaces" + aedgSmMdOffHowToTipHash['NV01'] = 'NV1 Natural Ventilation and Naturally Conditioned Spaces' # renewable energy tips - aedgSmMdOffHowToTipHash["RE01"] = "RE1 Photovoltaic (PV) Systems" - aedgSmMdOffHowToTipHash["RE02"] = "RE2 Wind Turbine Power" - aedgSmMdOffHowToTipHash["RE03"] = "RE3 Transpired Solar Collector" - aedgSmMdOffHowToTipHash["RE04"] = "RE4 Power Purchase Agreements" + aedgSmMdOffHowToTipHash['RE01'] = 'RE1 Photovoltaic (PV) Systems' + aedgSmMdOffHowToTipHash['RE02'] = 'RE2 Wind Turbine Power' + aedgSmMdOffHowToTipHash['RE03'] = 'RE3 Transpired Solar Collector' + aedgSmMdOffHowToTipHash['RE04'] = 'RE4 Power Purchase Agreements' result = aedgSmMdOffHowToTipHash return result - - end #end of OsLib_AedgMeasures.getSmMdOffTips - -end # end of module OsLib_AedgMeasures \ No newline at end of file + end # end of OsLib_AedgMeasures.getSmMdOffTips +end # end of module OsLib_AedgMeasures diff --git a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Constructions.rb b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Constructions.rb index b81d330..7b11ac3 100644 --- a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Constructions.rb +++ b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Constructions.rb @@ -1,28 +1,28 @@ -module OsLib_Constructions +# frozen_string_literal: true +module OsLib_Constructions # infer insulation layer from a construction - def OsLib_Constructions.inferInsulationLayer(construction,minThermalResistance) - + def self.inferInsulationLayer(construction, minThermalResistance) construction_layers = construction.layers counter = 0 max_resistance = 0 thermal_resistance_array = [] - #loop through construction layers and infer insulation layer/material + # loop through construction layers and infer insulation layer/material construction_layers.each do |construction_layer| construction_thermal_resistance = construction_layer.to_OpaqueMaterial.get.thermalResistance - if not thermal_resistance_array.empty? + if !thermal_resistance_array.empty? if construction_thermal_resistance > max_resistance - thermal_resistance_array = [construction_layer,counter,construction_thermal_resistance] + thermal_resistance_array = [construction_layer, counter, construction_thermal_resistance] max_resistance = construction_thermal_resistance end else - thermal_resistance_array = [construction_layer,counter,construction_thermal_resistance] + thermal_resistance_array = [construction_layer, counter, construction_thermal_resistance] end - counter = counter + 1 + counter += 1 end - #test against minimum + # test against minimum if max_resistance > minThermalResistance minTestPass = true else @@ -30,23 +30,22 @@ def OsLib_Constructions.inferInsulationLayer(construction,minThermalResistance) end result = { - "construction" => construction, - "construction_layer" => thermal_resistance_array[0], - "layer_index" => thermal_resistance_array[1], - "construction_thermal_resistance" => thermal_resistance_array[2], - "insulationFound" => minTestPass + 'construction' => construction, + 'construction_layer' => thermal_resistance_array[0], + 'layer_index' => thermal_resistance_array[1], + 'construction_thermal_resistance' => thermal_resistance_array[2], + 'insulationFound' => minTestPass } return result end # change thermal resistance of opaque materials - def OsLib_Constructions.setMaterialThermalResistance(material,thermalResistance,options = {}) - + def self.setMaterialThermalResistance(material, thermalResistance, options = {}) # set defaults to use if user inputs not passed in defaults = { - "cloneMaterial" => true, # in future give user option to clone or change live material - "name" => "#{material.name} - adj", + 'cloneMaterial' => true, # in future give user option to clone or change live material + 'name' => "#{material.name} - adj" } # merge user inputs with defaults @@ -55,21 +54,21 @@ def OsLib_Constructions.setMaterialThermalResistance(material,thermalResistance, # clone input material new_material = material.clone(material.model) new_material = new_material.to_OpaqueMaterial.get - new_material.setName(options["name"]) + new_material.setName(options['name']) - #edit insulation material + # edit insulation material new_material_matt = new_material.to_Material - if not new_material_matt.empty? + if !new_material_matt.empty? starting_thickness = new_material_matt.get.thickness target_thickness = starting_thickness * thermalResistance / material.to_OpaqueMaterial.get.thermalResistance final_thickness = new_material_matt.get.setThickness(target_thickness) end new_material_massless = new_material.to_MasslessOpaqueMaterial - if not new_material_massless.empty? + if !new_material_massless.empty? final_thermal_resistance = new_material_massless.get.setThermalResistance(thermalResistance) end new_material_airgap = new_material.to_AirGap - if not new_material_airgap.empty? + if !new_material_airgap.empty? final_thermal_resistance = new_material_airgap.get.setThermalResistance(thermalResistance) end @@ -78,113 +77,108 @@ def OsLib_Constructions.setMaterialThermalResistance(material,thermalResistance, end # add new material to outside of a construction - def OsLib_Constructions.addNewLayerToConstruction(construction,options = {}) - + def self.addNewLayerToConstruction(construction, options = {}) # set defaults to use if user inputs not passed in defaults = { - "cloneConstruction" => false, # in future give user option to clone or change live construction - "layerIndex" => 0, # 0 will be outside. Measure writer should validate any non 0 layerIndex passed in. - "name" => "#{construction.name} - new material", - "roughness" => nil, - "thickness" => nil, - "conductivity" => nil, - "density" => nil, - "specificHeat" => nil, - "thermalAbsorptance" => nil, - "solarAbsorptance" => nil, - "visibleAbsorptance" => nil, + 'cloneConstruction' => false, # in future give user option to clone or change live construction + 'layerIndex' => 0, # 0 will be outside. Measure writer should validate any non 0 layerIndex passed in. + 'name' => "#{construction.name} - new material", + 'roughness' => nil, + 'thickness' => nil, + 'conductivity' => nil, + 'density' => nil, + 'specificHeat' => nil, + 'thermalAbsorptance' => nil, + 'solarAbsorptance' => nil, + 'visibleAbsorptance' => nil } # merge user inputs with defaults options = defaults.merge(options) - # todo - would be nice to grab surface properties from previous exposed material + # TODO: - would be nice to grab surface properties from previous exposed material # make new material exposedMaterialNew = OpenStudio::Model::StandardOpaqueMaterial.new(construction.model) - exposedMaterialNew.setName(options["name"]) + exposedMaterialNew.setName(options['name']) # set requested material properties - if not options["roughness"].nil? then exposedMaterialNew.setRoughness(options["roughness"]) end - if not options["thickness"].nil? then exposedMaterialNew.setThickness(options["thickness"]) end - if not options["conductivity"].nil? then exposedMaterialNew.setConductivity( options["conductivity"]) end - if not options["density"].nil? then exposedMaterialNew.setDensity(options["density"])end - if not options["specificHeat"].nil? then exposedMaterialNew.setSpecificHeat(options["specificHeat"]) end - if not options["thermalAbsorptance"].nil? then exposedMaterialNew.setThermalAbsorptance(options["thermalAbsorptance"]) end - if not options["solarAbsorptance"].nil? then exposedMaterialNew.setSolarAbsorptance(options["solarAbsorptance"]) end - if not options["visibleAbsorptance"].nil? then exposedMaterialNew.setVisibleAbsorptance(options["visibleAbsorptance"]) end + if !options['roughness'].nil? then exposedMaterialNew.setRoughness(options['roughness']) end + if !options['thickness'].nil? then exposedMaterialNew.setThickness(options['thickness']) end + if !options['conductivity'].nil? then exposedMaterialNew.setConductivity(options['conductivity']) end + if !options['density'].nil? then exposedMaterialNew.setDensity(options['density']) end + if !options['specificHeat'].nil? then exposedMaterialNew.setSpecificHeat(options['specificHeat']) end + if !options['thermalAbsorptance'].nil? then exposedMaterialNew.setThermalAbsorptance(options['thermalAbsorptance']) end + if !options['solarAbsorptance'].nil? then exposedMaterialNew.setSolarAbsorptance(options['solarAbsorptance']) end + if !options['visibleAbsorptance'].nil? then exposedMaterialNew.setVisibleAbsorptance(options['visibleAbsorptance']) end # add material to construction - construction.insertLayer(options["layerIndex"],exposedMaterialNew) + construction.insertLayer(options['layerIndex'], exposedMaterialNew) result = exposedMaterialNew return result end # set material surface properties for specific layer in construction. this should work on OS:Material and OS:MasslessOpaqueMaterial - def OsLib_Constructions.setConstructionSurfaceProperties(construction,options = {}) - + def self.setConstructionSurfaceProperties(construction, options = {}) # set defaults to use if user inputs not passed in defaults = { - "cloneConstruction" => false, # in future give user option to clone or change live construction - "nameConstruction" => "#{construction.name} - adj", # not currently used - "cloneMaterial" => true, - "roughness" => nil, - "thermalAbsorptance" => nil, - "solarAbsorptance" => nil, - "visibleAbsorptance" => nil, + 'cloneConstruction' => false, # in future give user option to clone or change live construction + 'nameConstruction' => "#{construction.name} - adj", # not currently used + 'cloneMaterial' => true, + 'roughness' => nil, + 'thermalAbsorptance' => nil, + 'solarAbsorptance' => nil, + 'visibleAbsorptance' => nil } # merge user inputs with defaults options = defaults.merge(options) exposedMaterial = construction.to_LayeredConstruction.get.getLayer(0) - if options["cloneMaterial"] + if options['cloneMaterial'] - #clone material + # clone material exposedMaterialNew = exposedMaterial.clone(construction.model).to_StandardOpaqueMaterial.get # to_StandardOpaqueMaterial is needed to access roughness, otherwise to_OpaqueMaterial would have been fine. exposedMaterialNew.setName("#{exposedMaterial.name} - adj") # connect new material to original construction construction.eraseLayer(0) - construction.insertLayer(0,exposedMaterialNew) + construction.insertLayer(0, exposedMaterialNew) else exposedMaterialNew = exposedMaterial.to_StandardOpaqueMaterial.get # not being cloned but still want to rename exposedMaterialNew.setName("#{exposedMaterial.name} - adj") end - #todo - need to test with MasslessOpaqueMaterial. Add test if doesn't return anything when use to_StandardOpaqueMaterial.get + # TODO: - need to test with MasslessOpaqueMaterial. Add test if doesn't return anything when use to_StandardOpaqueMaterial.get # set requested material properties - if not options["roughness"].nil? then exposedMaterialNew.setRoughness(options["roughness"]) end - if not options["thermalAbsorptance"].nil? then exposedMaterialNew.setThermalAbsorptance(options["thermalAbsorptance"]) end - if not options["solarAbsorptance"].nil? then exposedMaterialNew.setSolarAbsorptance(options["solarAbsorptance"]) end - if not options["visibleAbsorptance"].nil? then exposedMaterialNew.setVisibleAbsorptance(options["visibleAbsorptance"]) end + if !options['roughness'].nil? then exposedMaterialNew.setRoughness(options['roughness']) end + if !options['thermalAbsorptance'].nil? then exposedMaterialNew.setThermalAbsorptance(options['thermalAbsorptance']) end + if !options['solarAbsorptance'].nil? then exposedMaterialNew.setSolarAbsorptance(options['solarAbsorptance']) end + if !options['visibleAbsorptance'].nil? then exposedMaterialNew.setVisibleAbsorptance(options['visibleAbsorptance']) end - result = {"exposedMaterial" => exposedMaterial,"exposedMaterialNew" => exposedMaterialNew} + result = { 'exposedMaterial' => exposedMaterial, 'exposedMaterialNew' => exposedMaterialNew } return result - end # end of OsLib_Constructions.setMaterialSurfaceProperties - # similar to setMaterialSurfaceProperties but I just pass a material in. Needed this to set material properties for interior walls and both sides of interior partitions. - def OsLib_Constructions.setMaterialSurfaceProperties(material,options = {}) - + def self.setMaterialSurfaceProperties(material, options = {}) # set defaults to use if user inputs not passed in defaults = { - "cloneMaterial" => true, - "roughness" => nil, - "thermalAbsorptance" => nil, - "solarAbsorptance" => nil, - "visibleAbsorptance" => nil, + 'cloneMaterial' => true, + 'roughness' => nil, + 'thermalAbsorptance' => nil, + 'solarAbsorptance' => nil, + 'visibleAbsorptance' => nil } # merge user inputs with defaults options = defaults.merge(options) - if options["cloneMaterial"] - #clone material + if options['cloneMaterial'] + # clone material materialNew = exposedMaterial.clone(construction.model).get materialNew.setName("#{materialNew.name} - adj") else @@ -193,25 +187,24 @@ def OsLib_Constructions.setMaterialSurfaceProperties(material,options = {}) end # to_StandardOpaqueMaterial is needed to access roughness, otherwise to_OpaqueMaterial would have been fine. - if not materialNew.to_StandardOpaqueMaterial.empty? + if !materialNew.to_StandardOpaqueMaterial.empty? materialNew = materialNew.to_StandardOpaqueMaterial.get - elsif not materialNew.to_MasslessOpaqueMaterial.empty? + elsif !materialNew.to_MasslessOpaqueMaterial.empty? materialNew = materialNew.to_MasslessOpaqueMaterial.get end # set requested material properties - if not options["roughness"].nil? then materialNew.setRoughness(options["roughness"]) end - if not options["thermalAbsorptance"].nil? then materialNew.setThermalAbsorptance(options["thermalAbsorptance"]) end - if not options["solarAbsorptance"].nil? then materialNew.setSolarAbsorptance(options["solarAbsorptance"]) end - if not options["visibleAbsorptance"].nil? then materialNew.setVisibleAbsorptance(options["visibleAbsorptance"]) end + if !options['roughness'].nil? then materialNew.setRoughness(options['roughness']) end + if !options['thermalAbsorptance'].nil? then materialNew.setThermalAbsorptance(options['thermalAbsorptance']) end + if !options['solarAbsorptance'].nil? then materialNew.setSolarAbsorptance(options['solarAbsorptance']) end + if !options['visibleAbsorptance'].nil? then materialNew.setVisibleAbsorptance(options['visibleAbsorptance']) end - result = {"material" => material,"materialNew" => materialNew} + result = { 'material' => material, 'materialNew' => materialNew } return result - end # end of OsLib_Constructions.setMaterialSurfaceProperties # sri of exposed surface of a construction (calculation from K-12 AEDG, derived from ASTM E1980 assuming medium wind speed) - def OsLib_Constructions.getConstructionSRI(construction) + def self.getConstructionSRI(construction) exposedMaterial = construction.to_LayeredConstruction.get.getLayer(0) solarAbsorptance = exposedMaterial.to_OpaqueMaterial.get.solarAbsorptance thermalEmissivity = exposedMaterial.to_OpaqueMaterial.get.thermalAbsorptance @@ -219,11 +212,10 @@ def OsLib_Constructions.getConstructionSRI(construction) # solarAbsorptance = 1 - 0.65 # thermalEmissivity = 0.86 - x = (20.797 * solarAbsorptance - 0.603 * thermalEmissivity)/(9.5205 * thermalEmissivity + 12.0) + x = (20.797 * solarAbsorptance - 0.603 * thermalEmissivity) / (9.5205 * thermalEmissivity + 12.0) sri = 123.97 - 141.35 * x + 9.6555 * x * x result = sri return result end # end of OsLib_Constructions.getConstructionSRI - -end \ No newline at end of file +end diff --git a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Geometry.rb b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Geometry.rb index a4ade99..83e43a9 100644 --- a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Geometry.rb +++ b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Geometry.rb @@ -1,13 +1,12 @@ -module OsLib_Geometry +# frozen_string_literal: true +module OsLib_Geometry # lower z value of vertices with starting value above x to new value of y - def OsLib_Geometry.lowerSurfaceZvalue(surfaceArray, zValueTarget) - + def self.lowerSurfaceZvalue(surfaceArray, zValueTarget) counter = 0 # loop over all surfaces surfaceArray.each do |surface| - # create a new set of vertices newVertices = OpenStudio::Point3dVector.new @@ -15,7 +14,6 @@ def OsLib_Geometry.lowerSurfaceZvalue(surfaceArray, zValueTarget) vertices = surface.vertices flag = false vertices.each do |vertex| - # initialize new vertex to old vertex x = vertex.x y = vertex.y @@ -28,20 +26,16 @@ def OsLib_Geometry.lowerSurfaceZvalue(surfaceArray, zValueTarget) end # add point to new vertices - newVertices << OpenStudio::Point3d.new(x,y,z) + newVertices << OpenStudio::Point3d.new(x, y, z) end # set vertices to new vertices - surface.setVertices(newVertices) #todo check if this was made, and issue warning if it was not. Could happen if resulting surface not planer. + surface.setVertices(newVertices) # todo check if this was made, and issue warning if it was not. Could happen if resulting surface not planer. if flag then counter += 1 end - - end #end of surfaceArray.each do + end # end of surfaceArray.each do result = counter return result - end - - -end \ No newline at end of file +end diff --git a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_HVAC.rb b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_HVAC.rb index 22460d0..22e7174 100644 --- a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_HVAC.rb +++ b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_HVAC.rb @@ -1,25 +1,22 @@ -module OsLib_HVAC +# frozen_string_literal: true +module OsLib_HVAC # do something - def OsLib_HVAC.doSomething(input) - + def self.doSomething(input) # do something output = input result = output return result - end # end of def - # validate and make plenum zones - def OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options = {}) - + def self.validateAndAddPlenumZonesToSystem(model, runner, options = {}) # set defaults to use if user inputs not passed in defaults = { - "zonesPlenum" => nil, - "zonesPrimary" => nil, - "type" => "ceilingReturn", + 'zonesPlenum' => nil, + 'zonesPrimary' => nil, + 'type' => 'ceilingReturn' } # merge user inputs with defaults @@ -28,11 +25,11 @@ def OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options = {}) # array of valid ceiling plenums zoneSurfaceHash = {} zonePlenumHash = {} - - if options["zonesPlenum"] == nil - runner.registerWarning("No plenum zones were passed in, validateAndAddPlenumZonesToSystem will not alter the model.") + + if options['zonesPlenum'].nil? + runner.registerWarning('No plenum zones were passed in, validateAndAddPlenumZonesToSystem will not alter the model.') else - options["zonesPlenum"].each do |zone| + options['zonesPlenum'].each do |zone| # get spaces in zone spaces = zone.spaces # get adjacent spaces @@ -41,19 +38,19 @@ def OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options = {}) surfaces = space.surfaces # loop through surfaces looking for floors with surface boundary condition, grab zone that surface's parent space is in. surfaces.each do |surface| - if surface.outsideBoundaryCondition == "Surface" and surface.surfaceType == "Floor" + if (surface.outsideBoundaryCondition == 'Surface') && (surface.surfaceType == 'Floor') next unless surface.adjacentSurface.is_initialized adjacentSurface = surface.adjacentSurface.get next unless adjacentSurface.space.is_initialized adjacentSurfaceSpace = adjacentSurface.space.get next unless adjacentSurfaceSpace.thermalZone.is_initialized adjacentSurfaceSpaceZone = adjacentSurfaceSpace.thermalZone.get - if options["zonesPrimary"].include? adjacentSurfaceSpaceZone - if zoneSurfaceHash[adjacentSurfaceSpaceZone].nil? or surface.grossArea > zoneSurfaceHash[adjacentSurfaceSpaceZone] + if options['zonesPrimary'].include? adjacentSurfaceSpaceZone + if zoneSurfaceHash[adjacentSurfaceSpaceZone].nil? || (surface.grossArea > zoneSurfaceHash[adjacentSurfaceSpaceZone]) adjacentSurfaceSpaceZone.setReturnPlenum(zone) zoneSurfaceHash[adjacentSurfaceSpaceZone] = surface.grossArea zonePlenumHash[adjacentSurfaceSpaceZone] = zone - end + end end end end # end of surfaces.each do @@ -62,23 +59,20 @@ def OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options = {}) end # end of zonesPlenum == nil # report out results of zone-plenum hash - zonePlenumHash.each do |zone,plenum| + zonePlenumHash.each do |zone, plenum| runner.registerInfo("#{plenum.name} has been set as a return air plenum for #{zone.name}.") end - + # pass back zone-plenum hash result = zonePlenumHash return result - end # end of def - - def OsLib_HVAC.sortZones(model, runner, options = {},space_type_to_edits_hash = {}) + def self.sortZones(model, runner, options = {}, space_type_to_edits_hash = {}) # set defaults to use if user inputs not passed in - defaults = {"standardBuildingTypeTest" => nil, # not used for now - "secondarySpaceTypeTest" => nil, - "ceilingReturnPlenumSpaceType" => nil - } + defaults = { 'standardBuildingTypeTest' => nil, # not used for now + 'secondarySpaceTypeTest' => nil, + 'ceilingReturnPlenumSpaceType' => nil } # merge user inputs with defaults options = defaults.merge(options) @@ -88,13 +82,13 @@ def OsLib_HVAC.sortZones(model, runner, options = {},space_type_to_edits_hash = zonesSecondary = [] zonesPlenum = [] zonesUnconditioned = [] - + # get thermal zones zones = model.getThermalZones zones.each do |zone| # assign appropriate zones to zonesPlenum or zonesUnconditioned (those that don't have thermostats or zone HVAC equipment) # if not conditioned then add to zonesPlenum or zonesUnconditioned - unless zone.thermostatSetpointDualSetpoint.is_initialized or zone.equipment.size > 0 + unless zone.thermostatSetpointDualSetpoint.is_initialized || !zone.equipment.empty? # determine if zone is a plenum zone or general unconditioned zone # assume it is a plenum if it has at least one plenum space zone.spaces.each do |space| @@ -102,41 +96,39 @@ def OsLib_HVAC.sortZones(model, runner, options = {},space_type_to_edits_hash = next if zonesPlenum.include? zone # if zone not assigned as a plenum, get space type if it exists # compare to plenum space type if it has been assigned - if space.spaceType.is_initialized and options["ceilingReturnPlenumSpaceType"].nil? == false + if space.spaceType.is_initialized && (options['ceilingReturnPlenumSpaceType'].nil? == false) spaceType = space.spaceType.get - if spaceType == options["ceilingReturnPlenumSpaceType"] + if spaceType == options['ceilingReturnPlenumSpaceType'] zonesPlenum << zone # zone has a plenum space; assign it as a plenum end end end # if zone not assigned as a plenum, assign it as unconditioned - unless zonesPlenum.include? zone + unless zonesPlenum.include? zone zonesUnconditioned << zone - end + end end - end - # zone is conditioned. check if its space type is secondary or primary - spaces = model.getSpaces - spaces.each do |space| - spaceType = space.spaceType.get - if space_type_to_edits_hash[spaceType] == true - zonesPrimary << space.thermalZone.get - end - end # end of spaces each do - # if zone is conditioned and is of space type true, assign it to primary zones - - zonesSorted = {"zonesPrimary" => zonesPrimary, - "zonesSecondary" => zonesSecondary, - "zonesPlenum" => zonesPlenum, - "zonesUnconditioned" => zonesUnconditioned} + end + # zone is conditioned. check if its space type is secondary or primary + spaces = model.getSpaces + spaces.each do |space| + spaceType = space.spaceType.get + if space_type_to_edits_hash[spaceType] == true + zonesPrimary << space.thermalZone.get + end + end # end of spaces each do + # if zone is conditioned and is of space type true, assign it to primary zones + + zonesSorted = { 'zonesPrimary' => zonesPrimary, + 'zonesSecondary' => zonesSecondary, + 'zonesPlenum' => zonesPlenum, + 'zonesUnconditioned' => zonesUnconditioned } # pass back zonesSorted hash result = zonesSorted return result - end # end of def - def OsLib_HVAC.reportConditions(model, runner, condition) - + def self.reportConditions(model, runner, condition) airloops = model.getAirLoopHVACs plantLoops = model.getPlantLoops zones = model.getThermalZones @@ -144,96 +136,92 @@ def OsLib_HVAC.reportConditions(model, runner, condition) # count up zone equipment (not counting zone exhaust fans) zoneHasEquip = false zonesWithEquipCounter = 0 - + zones.each do |zone| - if zone.equipment.size > 0 + if !zone.equipment.empty? zone.equipment.each do |equip| unless equip.to_FanZoneExhaust.is_initialized zonesWithEquipCounter += 1 break end - end + end end - end - - if condition == "initial" + end + + if condition == 'initial' runner.registerInitialCondition("The building started with #{airloops.size} air loops and #{plantLoops.size} plant loops. #{zonesWithEquipCounter} zones were conditioned with zone equipment.") - elsif condition == "final" + elsif condition == 'final' runner.registerFinalCondition("The building finished with #{airloops.size} air loops and #{plantLoops.size} plant loops. #{zonesWithEquipCounter} zones are conditioned with zone equipment.") end - end # end of def - def OsLib_HVAC.removeEquipment(model, runner, options) + def self.removeEquipment(model, runner, options) airloops = model.getAirLoopHVACs plantLoops = model.getPlantLoops - zones = model.getThermalZones + zones = model.getThermalZones - # remove all zone equipment except zone exhaust fans + # remove all zone equipment except zone exhaust fans zones.each do |zone| - # runner.registerInfo("primary zones values are #{value.name}") - if options["zonesPrimary"].include? zone - zone.equipment.each do |equip| - if equip.to_FanZoneExhaust.is_initialized #or (equip.to_ZoneHVACUnitHeater.is_initialized and zone.get.equipment.size == 1) - else - equip.remove - end - end - end - end - - + # runner.registerInfo("primary zones values are #{value.name}") + if options['zonesPrimary'].include? zone + zone.equipment.each do |equip| + if equip.to_FanZoneExhaust.is_initialized # or (equip.to_ZoneHVACUnitHeater.is_initialized and zone.get.equipment.size == 1) + else + equip.remove + end + end + end + end + # remove an air loop if it's empty airloops.each do |air_loop| - air_loop.thermalZones.each do |airZone| - if options["zonesPrimary"].include? airZone - air_loop.removeBranchForZone(airZone) - end - end - if air_loop.thermalZones.empty? - air_loop.remove - end + air_loop.thermalZones.each do |airZone| + if options['zonesPrimary'].include? airZone + air_loop.removeBranchForZone(airZone) + end + end + if air_loop.thermalZones.empty? + air_loop.remove + end end - + # remove plant loops plantLoops.each do |plantLoop| # get the demand components and see if water use connection, then save it # notify user with info statement if supply side of plant loop had heat exchanger for refrigeration - usedForSWHOrRefrigeration = false - usedForZoneHCCoils = false - plantLoop.demandComponents.each do |comp| #AP code to check your comments above - runner.registerInfo("plant loops component is #{comp.name.to_s}") - if comp.to_WaterUseConnections.is_initialized or comp.to_CoilWaterHeatingDesuperheater.is_initialized - usedForSWHOrRefrigeration = true - runner.registerWarning("#{plantLoop.name} is used for SWH or refrigeration. Loop will not be deleted.") - elsif comp.name.to_s.include? "Coil" and comp.name.to_s != "Coil Heating Water 1" and comp.name.to_s != "Coil Cooling Water 1"#to_CoilWaterHeatingDesuperheater.is_initialized or comp.name.to_s.include? "coil" - runner.registerWarning("#{plantLoop.name} has coils used by Zone HVAC components. Loop will not be deleted.") - usedForZoneHCCoils = true - end - end - # runner.registerInfo("Used for ZoneHCCoils Value is #{usedForZoneHCCoils}") - # runner.registerInfo("Used for SWH or refrigeration is #{usedForSWHOrRefrigeration}") - if usedForSWHOrRefrigeration == false #and usedForZoneHCCoils == false # <-- Sang Hoon Lee: "and usedForZoneHCCoils == false" Treated as comment for BRICR Medium office to remove Coil:Heating:Water - plantLoop.remove - runner.registerInfo("Plant Loop #{plantLoop.name} is removed") - end - end # end of plantloop components - + usedForSWHOrRefrigeration = false + usedForZoneHCCoils = false + plantLoop.demandComponents.each do |comp| # AP code to check your comments above + runner.registerInfo("plant loops component is #{comp.name}") + if comp.to_WaterUseConnections.is_initialized || comp.to_CoilWaterHeatingDesuperheater.is_initialized + usedForSWHOrRefrigeration = true + runner.registerWarning("#{plantLoop.name} is used for SWH or refrigeration. Loop will not be deleted.") + elsif comp.name.to_s.include?('Coil') && (comp.name.to_s != 'Coil Heating Water 1') && (comp.name.to_s != 'Coil Cooling Water 1') # to_CoilWaterHeatingDesuperheater.is_initialized or comp.name.to_s.include? "coil" + runner.registerWarning("#{plantLoop.name} has coils used by Zone HVAC components. Loop will not be deleted.") + usedForZoneHCCoils = true + end + end + # runner.registerInfo("Used for ZoneHCCoils Value is #{usedForZoneHCCoils}") + # runner.registerInfo("Used for SWH or refrigeration is #{usedForSWHOrRefrigeration}") + if usedForSWHOrRefrigeration == false # and usedForZoneHCCoils == false # <-- Sang Hoon Lee: "and usedForZoneHCCoils == false" Treated as comment for BRICR Medium office to remove Coil:Heating:Water + plantLoop.remove + runner.registerInfo("Plant Loop #{plantLoop.name} is removed") + end + end # end of plantloop components end # end of def - def OsLib_HVAC.assignHVACSchedules(model, runner, options = {}) - + def self.assignHVACSchedules(model, runner, options = {}) require "#{File.dirname(__FILE__)}/OsLib_Schedules" - + schedulesHVAC = {} airloops = model.getAirLoopHVACs - + # find airloop with most primary spaces max_primary_spaces = 0 representative_airloop = false building_HVAC_schedule = false building_ventilation_schedule = false - unless options["remake_schedules"] + unless options['remake_schedules'] # if remake schedules not selected, get relevant schedules from model if they exist airloops.each do |air_loop| primary_spaces = 0 @@ -241,216 +229,214 @@ def OsLib_HVAC.assignHVACSchedules(model, runner, options = {}) thermal_zone.spaces.each do |space| if space.spaceType.is_initialized if space.spaceType.get.name.is_initialized - if space.spaceType.get.name.get.include? options["primarySpaceType"] + if space.spaceType.get.name.get.include? options['primarySpaceType'] primary_spaces += 1 end - end - end + end + end end end if primary_spaces > max_primary_spaces max_primary_spaces = primary_spaces representative_airloop = air_loop - end + end end - end + end if representative_airloop building_HVAC_schedule = representative_airloop.availabilitySchedule if representative_airloop.airLoopHVACOutdoorAirSystem.is_initialized - building_ventilation_schedule_optional = representative_airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.maximumFractionofOutdoorAirSchedule + building_ventilation_schedule_optional = representative_airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.maximumFractionofOutdoorAirSchedule if building_ventilation_schedule_optional.is_initialized building_ventilation_schedule = building_ventilation_schedule.get end - end + end end # build new airloop schedules if existing model doesn't have them - if options["primarySpaceType"] == "Classroom" + if options['primarySpaceType'] == 'Classroom' # ventilation schedule unless building_ventilation_schedule - runner.registerInfo("Baseline does not have minimum OA ventilation schedule. A new K-12 Ventilation schedule is created") - ruleset_name = "New K-12 Ventilation Schedule" - winter_design_day = [[24,1]] - summer_design_day = [[24,1]] - default_day = ["Weekday",[6,0],[18,1],[24,0]] + runner.registerInfo('Baseline does not have minimum OA ventilation schedule. A new K-12 Ventilation schedule is created') + ruleset_name = 'New K-12 Ventilation Schedule' + winter_design_day = [[24, 1]] + summer_design_day = [[24, 1]] + default_day = ['Weekday', [6, 0], [18, 1], [24, 0]] rules = [] - rules << ["Weekend","1/1-12/31","Sat/Sun",[24,0]] - rules << ["Summer Weekday","7/1-8/31","Mon/Tue/Wed/Thu/Fri",[8,0],[13,1],[24,0]] - options_ventilation = {"name" => ruleset_name, - "winter_design_day" => winter_design_day, - "summer_design_day" => summer_design_day, - "default_day" => default_day, - "rules" => rules} + rules << ['Weekend', '1/1-12/31', 'Sat/Sun', [24, 0]] + rules << ['Summer Weekday', '7/1-8/31', 'Mon/Tue/Wed/Thu/Fri', [8, 0], [13, 1], [24, 0]] + options_ventilation = { 'name' => ruleset_name, + 'winter_design_day' => winter_design_day, + 'summer_design_day' => summer_design_day, + 'default_day' => default_day, + 'rules' => rules } building_ventilation_schedule = OsLib_Schedules.createComplexSchedule(model, options_ventilation) end # HVAC availability schedule unless building_HVAC_schedule - runner.registerInfo("Baseline does not have HVAC availability schedule. A new K-12 HVAC availability schedule is created") - ruleset_name = "New K-12 HVAC Availability Schedule" - winter_design_day = [[24,1]] - summer_design_day = [[24,1]] - default_day = ["Weekday",[6,0],[18,1],[24,0]] + runner.registerInfo('Baseline does not have HVAC availability schedule. A new K-12 HVAC availability schedule is created') + ruleset_name = 'New K-12 HVAC Availability Schedule' + winter_design_day = [[24, 1]] + summer_design_day = [[24, 1]] + default_day = ['Weekday', [6, 0], [18, 1], [24, 0]] rules = [] - rules << ["Weekend","1/1-12/31","Sat/Sun",[24,0]] - rules << ["Summer Weekday","7/1-8/31","Mon/Tue/Wed/Thu/Fri",[8,0],[13,1],[24,0]] - options_hvac = {"name" => ruleset_name, - "winter_design_day" => winter_design_day, - "summer_design_day" => summer_design_day, - "default_day" => default_day, - "rules" => rules} + rules << ['Weekend', '1/1-12/31', 'Sat/Sun', [24, 0]] + rules << ['Summer Weekday', '7/1-8/31', 'Mon/Tue/Wed/Thu/Fri', [8, 0], [13, 1], [24, 0]] + options_hvac = { 'name' => ruleset_name, + 'winter_design_day' => winter_design_day, + 'summer_design_day' => summer_design_day, + 'default_day' => default_day, + 'rules' => rules } building_HVAC_schedule = OsLib_Schedules.createComplexSchedule(model, options_hvac) end - elsif options["primarySpaceType"] == "Office" # xf - leave as is + elsif options['primarySpaceType'] == 'Office' # xf - leave as is # ventilation schedule unless building_ventilation_schedule - runner.registerInfo("Baseline does not have minimum OA ventilation schedule. A new Office Ventilation schedule is created.") - ruleset_name = "New Office Ventilation Schedule" - winter_design_day = [[24,1]] #ML These are not always on in PNNL model - summer_design_day = [[24,1]] #ML These are not always on in PNNL model - default_day = ["Weekday",[7,0],[22,1],[24,0]] #ML PNNL has a one hour ventilation offset + runner.registerInfo('Baseline does not have minimum OA ventilation schedule. A new Office Ventilation schedule is created.') + ruleset_name = 'New Office Ventilation Schedule' + winter_design_day = [[24, 1]] # ML These are not always on in PNNL model + summer_design_day = [[24, 1]] # ML These are not always on in PNNL model + default_day = ['Weekday', [7, 0], [22, 1], [24, 0]] # ML PNNL has a one hour ventilation offset rules = [] - rules << ["Saturday","1/1-12/31","Sat",[7,0],[18,1],[24,0]] #ML PNNL has a one hour ventilation offset - rules << ["Sunday","1/1-12/31","Sun",[24,0]] - options_ventilation = {"name" => ruleset_name, - "winter_design_day" => winter_design_day, - "summer_design_day" => summer_design_day, - "default_day" => default_day, - "rules" => rules} + rules << ['Saturday', '1/1-12/31', 'Sat', [7, 0], [18, 1], [24, 0]] # ML PNNL has a one hour ventilation offset + rules << ['Sunday', '1/1-12/31', 'Sun', [24, 0]] + options_ventilation = { 'name' => ruleset_name, + 'winter_design_day' => winter_design_day, + 'summer_design_day' => summer_design_day, + 'default_day' => default_day, + 'rules' => rules } building_ventilation_schedule = OsLib_Schedules.createComplexSchedule(model, options_ventilation) end # HVAC availability schedule unless building_HVAC_schedule - runner.registerInfo("Baseline does not have HVAC availability schedule. A new office HVAC availability schedule is created") - ruleset_name = "New Office HVAC Availability Schedule" - winter_design_day = [[24,1]] #ML These are not always on in PNNL model - summer_design_day = [[24,1]] #ML These are not always on in PNNL model - default_day = ["Weekday",[6,0],[22,1],[24,0]] #ML PNNL has a one hour ventilation offset + runner.registerInfo('Baseline does not have HVAC availability schedule. A new office HVAC availability schedule is created') + ruleset_name = 'New Office HVAC Availability Schedule' + winter_design_day = [[24, 1]] # ML These are not always on in PNNL model + summer_design_day = [[24, 1]] # ML These are not always on in PNNL model + default_day = ['Weekday', [6, 0], [22, 1], [24, 0]] # ML PNNL has a one hour ventilation offset rules = [] - rules << ["Saturday","1/1-12/31","Sat",[6,0],[18,1],[24,0]] #ML PNNL has a one hour ventilation offset - rules << ["Sunday","1/1-12/31","Sun",[24,0]] - options_hvac = {"name" => ruleset_name, - "winter_design_day" => winter_design_day, - "summer_design_day" => summer_design_day, - "default_day" => default_day, - "rules" => rules} + rules << ['Saturday', '1/1-12/31', 'Sat', [6, 0], [18, 1], [24, 0]] # ML PNNL has a one hour ventilation offset + rules << ['Sunday', '1/1-12/31', 'Sun', [24, 0]] + options_hvac = { 'name' => ruleset_name, + 'winter_design_day' => winter_design_day, + 'summer_design_day' => summer_design_day, + 'default_day' => default_day, + 'rules' => rules } building_HVAC_schedule = OsLib_Schedules.createComplexSchedule(model, options_hvac) end # special loops for radiant system (different temperature setpoints) - if options["allHVAC"]["zone"] == "Radiant" + if options['allHVAC']['zone'] == 'Radiant' # create hot water schedule for radiant heating loop - schedulesHVAC["radiant_hot_water"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HW-Radiant-Loop-Temp-Schedule", - "default_day" => ["All Days",[24,45.0]]}) + schedulesHVAC['radiant_hot_water'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HW-Radiant-Loop-Temp-Schedule', + 'default_day' => ['All Days', [24, 45.0]]) # create hot water schedule for radiant cooling loop - schedulesHVAC["radiant_chilled_water"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New CW-Radiant-Loop-Temp-Schedule", - "default_day" => ["All Days",[24,15.0]]}) + schedulesHVAC['radiant_chilled_water'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New CW-Radiant-Loop-Temp-Schedule', + 'default_day' => ['All Days', [24, 15.0]]) # create mean radiant heating and cooling setpoint schedules # ML ideally, should grab schedules tied to zone thermostat and make modified versions that follow the setback pattern # for now, create new ones that match the recommended HVAC schedule # mean radiant heating setpoint schedule (PNNL values) - ruleset_name = "New Office Mean Radiant Heating Setpoint Schedule" - winter_design_day = [[24,18.8]] - summer_design_day = [[6,18.3],[22,18.8],[24,18.3]] - default_day = ["Weekday",[6,18.3],[22,18.8],[24,18.3]] + ruleset_name = 'New Office Mean Radiant Heating Setpoint Schedule' + winter_design_day = [[24, 18.8]] + summer_design_day = [[6, 18.3], [22, 18.8], [24, 18.3]] + default_day = ['Weekday', [6, 18.3], [22, 18.8], [24, 18.3]] rules = [] - rules << ["Saturday","1/1-12/31","Sat",[6,18.3],[18,18.8],[24,18.3]] - rules << ["Sunday","1/1-12/31","Sun",[24,18.3]] - options_radiant_heating = {"name" => ruleset_name, - "winter_design_day" => winter_design_day, - "summer_design_day" => summer_design_day, - "default_day" => default_day, - "rules" => rules} + rules << ['Saturday', '1/1-12/31', 'Sat', [6, 18.3], [18, 18.8], [24, 18.3]] + rules << ['Sunday', '1/1-12/31', 'Sun', [24, 18.3]] + options_radiant_heating = { 'name' => ruleset_name, + 'winter_design_day' => winter_design_day, + 'summer_design_day' => summer_design_day, + 'default_day' => default_day, + 'rules' => rules } mean_radiant_heating_schedule = OsLib_Schedules.createComplexSchedule(model, options_radiant_heating) - schedulesHVAC["mean_radiant_heating"] = mean_radiant_heating_schedule + schedulesHVAC['mean_radiant_heating'] = mean_radiant_heating_schedule # mean radiant cooling setpoint schedule (PNNL values) - ruleset_name = "New Office Mean Radiant Cooling Setpoint Schedule" - winter_design_day = [[6,26.7],[22,24.0],[24,26.7]] - summer_design_day = [[24,24.0]] - default_day = ["Weekday",[6,26.7],[22,24.0],[24,26.7]] + ruleset_name = 'New Office Mean Radiant Cooling Setpoint Schedule' + winter_design_day = [[6, 26.7], [22, 24.0], [24, 26.7]] + summer_design_day = [[24, 24.0]] + default_day = ['Weekday', [6, 26.7], [22, 24.0], [24, 26.7]] rules = [] - rules << ["Saturday","1/1-12/31","Sat",[6,26.7],[18,24.0],[24,26.7]] - rules << ["Sunday","1/1-12/31","Sun",[24,26.7]] - options_radiant_cooling = {"name" => ruleset_name, - "winter_design_day" => winter_design_day, - "summer_design_day" => summer_design_day, - "default_day" => default_day, - "rules" => rules} + rules << ['Saturday', '1/1-12/31', 'Sat', [6, 26.7], [18, 24.0], [24, 26.7]] + rules << ['Sunday', '1/1-12/31', 'Sun', [24, 26.7]] + options_radiant_cooling = { 'name' => ruleset_name, + 'winter_design_day' => winter_design_day, + 'summer_design_day' => summer_design_day, + 'default_day' => default_day, + 'rules' => rules } mean_radiant_cooling_schedule = OsLib_Schedules.createComplexSchedule(model, options_radiant_cooling) - schedulesHVAC["mean_radiant_cooling"] = mean_radiant_cooling_schedule + schedulesHVAC['mean_radiant_cooling'] = mean_radiant_cooling_schedule end end # SAT schedule - if options["allHVAC"]["primary"]["doas"] + if options['allHVAC']['primary']['doas'] # primary airloop is DOAS - schedulesHVAC["primary_sat"] = sch_ruleset_DOAS_setpoint = OsLib_Schedules.createComplexSchedule(model, {"name" => "DOAS Temperature Setpoint Schedule", - "default_day" => ["All Days",[24,21.111]]}) - else + schedulesHVAC['primary_sat'] = sch_ruleset_DOAS_setpoint = OsLib_Schedules.createComplexSchedule(model, 'name' => 'DOAS Temperature Setpoint Schedule', + 'default_day' => ['All Days', [24, 21.111]]) + else # primary airloop is multizone VAV that cools - schedulesHVAC["primary_sat"] = sch_ruleset_DOAS_setpoint = OsLib_Schedules.createComplexSchedule(model, {"name" => "Cold Deck Temperature Setpoint Schedule", - "default_day" => ["All Days",[24,12.8]]}) + schedulesHVAC['primary_sat'] = sch_ruleset_DOAS_setpoint = OsLib_Schedules.createComplexSchedule(model, 'name' => 'Cold Deck Temperature Setpoint Schedule', + 'default_day' => ['All Days', [24, 12.8]]) end - schedulesHVAC["ventilation"] = building_ventilation_schedule - schedulesHVAC["hvac"] = building_HVAC_schedule + schedulesHVAC['ventilation'] = building_ventilation_schedule + schedulesHVAC['hvac'] = building_HVAC_schedule # build new plant schedules as needed - zoneHVACHotWaterPlant = ["FanCoil","DualDuct","Baseboard"] # dual duct has fan coil and baseboard - zoneHVACChilledWaterPlant = ["FanCoil","DualDuct"] # dual duct has fan coil + zoneHVACHotWaterPlant = ['FanCoil', 'DualDuct', 'Baseboard'] # dual duct has fan coil and baseboard + zoneHVACChilledWaterPlant = ['FanCoil', 'DualDuct'] # dual duct has fan coil # hot water - if options["allHVAC"]["primary"]["heat"] == "Water" or options["allHVAC"]["secondary"]["heat"] == "Water" or zoneHVACHotWaterPlant.include? options["allHVAC"]["zone"] - schedulesHVAC["hot_water"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "HW-Loop-Temp-Schedule", - "default_day" => ["All Days",[24,67.0]]}) + if (options['allHVAC']['primary']['heat'] == 'Water') || (options['allHVAC']['secondary']['heat'] == 'Water') || zoneHVACHotWaterPlant.include?(options['allHVAC']['zone']) + schedulesHVAC['hot_water'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'HW-Loop-Temp-Schedule', + 'default_day' => ['All Days', [24, 67.0]]) end # chilled water - if options["allHVAC"]["primary"]["cool"] == "Water" or options["allHVAC"]["secondary"]["cool"] == "Water" or zoneHVACChilledWaterPlant.include? options["allHVAC"]["zone"] - schedulesHVAC["chilled_water"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "CW-Loop-Temp-Schedule", - "default_day" => ["All Days",[24,6.7]]}) + if (options['allHVAC']['primary']['cool'] == 'Water') || (options['allHVAC']['secondary']['cool'] == 'Water') || zoneHVACChilledWaterPlant.include?(options['allHVAC']['zone']) + schedulesHVAC['chilled_water'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'CW-Loop-Temp-Schedule', + 'default_day' => ['All Days', [24, 6.7]]) end # heat pump condenser loop schedules - if options["allHVAC"]["zone"] == "GSHP" + if options['allHVAC']['zone'] == 'GSHP' # there will be a heat pump condenser loop # loop setpoint schedule - schedulesHVAC["hp_loop"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HP-Loop-Temp-Schedule", - "default_day" => ["All Days",[24,21]]}) + schedulesHVAC['hp_loop'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Temp-Schedule', + 'default_day' => ['All Days', [24, 21]]) # cooling component schedule (#ML won't need this if a ground loop is actually modeled) - schedulesHVAC["hp_loop_cooling"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HP-Loop-Clg-Temp-Schedule", - "default_day" => ["All Days",[24,21]]}) + schedulesHVAC['hp_loop_cooling'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Clg-Temp-Schedule', + 'default_day' => ['All Days', [24, 21]]) # heating component schedule - schedulesHVAC["hp_loop_heating"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HP-Loop-Htg-Temp-Schedule", - "default_day" => ["All Days",[24,5]]}) + schedulesHVAC['hp_loop_heating'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Htg-Temp-Schedule', + 'default_day' => ['All Days', [24, 5]]) end - if options["allHVAC"]["zone"] == "WSHP" + if options['allHVAC']['zone'] == 'WSHP' # there will be a heat pump condenser loop # loop setpoint schedule - schedulesHVAC["hp_loop"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HP-Loop-Temp-Schedule", - "default_day" => ["All Days",[24,30]]}) #PNNL + schedulesHVAC['hp_loop'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Temp-Schedule', + 'default_day' => ['All Days', [24, 30]]) # PNNL # cooling component schedule (#ML won't need this if a ground loop is actually modeled) - schedulesHVAC["hp_loop_cooling"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HP-Loop-Clg-Temp-Schedule", - "default_day" => ["All Days",[24,30]]}) #PNNL + schedulesHVAC['hp_loop_cooling'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Clg-Temp-Schedule', + 'default_day' => ['All Days', [24, 30]]) # PNNL # heating component schedule - schedulesHVAC["hp_loop_heating"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HP-Loop-Htg-Temp-Schedule", - "default_day" => ["All Days",[24,20]]}) #PNNL + schedulesHVAC['hp_loop_heating'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Htg-Temp-Schedule', + 'default_day' => ['All Days', [24, 20]]) # PNNL end - + # pass back schedulesHVAC hash result = schedulesHVAC return result - end # end of def - def OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, loop_type, parameters) - + def self.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, loop_type, parameters) hot_water_plant = OpenStudio::Model::PlantLoop.new(model) hot_water_plant.setName("New #{loop_type} Loop") hot_water_plant.setMaximumLoopTemperature(100) hot_water_plant.setMinimumLoopTemperature(10) loop_sizing = hot_water_plant.sizingPlant - loop_sizing.setLoopType("Heating") - if loop_type == "Hot Water" + loop_sizing.setLoopType('Heating') + if loop_type == 'Hot Water' loop_sizing.setDesignLoopExitTemperature(82) - elsif loop_type == "Radiant Hot Water" - loop_sizing.setDesignLoopExitTemperature(60) #ML follows convention of sizing temp being larger than supplu temp - end + elsif loop_type == 'Radiant Hot Water' + loop_sizing.setDesignLoopExitTemperature(60) # ML follows convention of sizing temp being larger than supplu temp + end loop_sizing.setLoopDesignTemperatureDifference(11) # create a pump pump = OpenStudio::Model::PumpVariableSpeed.new(model) - pump.setRatedPumpHead(119563) #Pa + pump.setRatedPumpHead(119563) # Pa pump.setMotorEfficiency(0.9) pump.setCoefficient1ofthePartLoadPerformanceCurve(0) pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216) @@ -460,7 +446,7 @@ def OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, l boiler = OpenStudio::Model::BoilerHotWater.new(model) boiler.setNominalThermalEfficiency(0.9) # create a scheduled setpoint manager - setpoint_manager_scheduled = OpenStudio::Model::SetpointManagerScheduled.new(model,hot_water_setpoint_schedule) + setpoint_manager_scheduled = OpenStudio::Model::SetpointManagerScheduled.new(model, hot_water_setpoint_schedule) # create a supply bypass pipe pipe_supply_bypass = OpenStudio::Model::PipeAdiabatic.new(model) # create a supply outlet pipe @@ -486,34 +472,32 @@ def OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, l # pass back hot water plant result = hot_water_plant return result - end # end of def - def OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, loop_type, chillerType) - + def self.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, loop_type, chillerType) # chilled water plant chilled_water_plant = OpenStudio::Model::PlantLoop.new(model) chilled_water_plant.setName("New #{loop_type} Loop") chilled_water_plant.setMaximumLoopTemperature(98) chilled_water_plant.setMinimumLoopTemperature(1) loop_sizing = chilled_water_plant.sizingPlant - loop_sizing.setLoopType("Cooling") - if loop_type == "Chilled Water" + loop_sizing.setLoopType('Cooling') + if loop_type == 'Chilled Water' loop_sizing.setDesignLoopExitTemperature(6.7) - elsif loop_type == "Radiant Chilled Water" + elsif loop_type == 'Radiant Chilled Water' loop_sizing.setDesignLoopExitTemperature(15) - end + end loop_sizing.setLoopDesignTemperatureDifference(6.7) # create a pump pump = OpenStudio::Model::PumpVariableSpeed.new(model) - pump.setRatedPumpHead(149453) #Pa + pump.setRatedPumpHead(149453) # Pa pump.setMotorEfficiency(0.9) pump.setCoefficient1ofthePartLoadPerformanceCurve(0) pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216) pump.setCoefficient3ofthePartLoadPerformanceCurve(-0.0325) pump.setCoefficient4ofthePartLoadPerformanceCurve(1.0095) # create a chiller - if chillerType == "WaterCooled" + if chillerType == 'WaterCooled' # create clgCapFuncTempCurve clgCapFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model) clgCapFuncTempCurve.setCoefficient1Constant(1.07E+00) @@ -546,11 +530,11 @@ def OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_sch eirFuncPlrCurve.setMinimumValueofx(0) eirFuncPlrCurve.setMaximumValueofx(1.2) # construct chiller - chiller = OpenStudio::Model::ChillerElectricEIR.new(model,clgCapFuncTempCurve,eirFuncTempCurve,eirFuncPlrCurve) + chiller = OpenStudio::Model::ChillerElectricEIR.new(model, clgCapFuncTempCurve, eirFuncTempCurve, eirFuncPlrCurve) chiller.setReferenceCOP(6.1) - chiller.setCondenserType("WaterCooled") - chiller.setChillerFlowMode("ConstantFlow") - elsif chillerType == "AirCooled" + chiller.setCondenserType('WaterCooled') + chiller.setChillerFlowMode('ConstantFlow') + elsif chillerType == 'AirCooled' # create clgCapFuncTempCurve clgCapFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model) clgCapFuncTempCurve.setCoefficient1Constant(1.05E+00) @@ -583,13 +567,13 @@ def OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_sch eirFuncPlrCurve.setMinimumValueofx(0) eirFuncPlrCurve.setMaximumValueofx(1.2) # construct chiller - chiller = OpenStudio::Model::ChillerElectricEIR.new(model,clgCapFuncTempCurve,eirFuncTempCurve,eirFuncPlrCurve) + chiller = OpenStudio::Model::ChillerElectricEIR.new(model, clgCapFuncTempCurve, eirFuncTempCurve, eirFuncPlrCurve) chiller.setReferenceCOP(2.93) - chiller.setCondenserType("AirCooled") - chiller.setChillerFlowMode("ConstantFlow") + chiller.setCondenserType('AirCooled') + chiller.setChillerFlowMode('ConstantFlow') end # create a scheduled setpoint manager - setpoint_manager_scheduled = OpenStudio::Model::SetpointManagerScheduled.new(model,chilled_water_setpoint_schedule) + setpoint_manager_scheduled = OpenStudio::Model::SetpointManagerScheduled.new(model, chilled_water_setpoint_schedule) # create a supply bypass pipe pipe_supply_bypass = OpenStudio::Model::PipeAdiabatic.new(model) # create a supply outlet pipe @@ -615,185 +599,182 @@ def OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_sch # pass back chilled water plant result = chilled_water_plant return result - end # end of def - def OsLib_HVAC.createCondenserLoop(model, runner, options, parameters) + def self.createCondenserLoop(model, runner, options, parameters) + condenserLoops = {} + # condLoopCoolingTemp_si = OpenStudio::convert(condLoopCoolingTemp,"F","C").get + # condLoopHeatingTemp_si = OpenStudio::convert(parameters["condLoopHeatingTemp"],"F","C").get + # coolingTowerWB_si = OpenStudio::convert(coolingTowerWB,"F","C").get + boilerHWST_si = OpenStudio.convert(parameters['boilerHWST'], 'F', 'C').get + # check for water-cooled chillers + waterCooledChiller = false + model.getChillerElectricEIRs.each do |chiller| + next if waterCooledChiller == true + if chiller.condenserType == 'WaterCooled' + waterCooledChiller = true + end + end + # create condenser loop for water-cooled chillers + if waterCooledChiller + # create condenser loop for water-cooled chiller(s) + condenser_loop = OpenStudio::Model::PlantLoop.new(model) + condenser_loop.setName('New Condenser Loop') + condenser_loop.setMaximumLoopTemperature(80) + condenser_loop.setMinimumLoopTemperature(5) + loop_sizing = condenser_loop.sizingPlant + loop_sizing.setLoopType('Condenser') + loop_sizing.setDesignLoopExitTemperature(29.4) + loop_sizing.setLoopDesignTemperatureDifference(5.6) + # create a pump + pump = OpenStudio::Model::PumpVariableSpeed.new(model) + pump.setRatedPumpHead(134508) # Pa + pump.setMotorEfficiency(0.9) + pump.setCoefficient1ofthePartLoadPerformanceCurve(0) + pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216) + pump.setCoefficient3ofthePartLoadPerformanceCurve(-0.0325) + pump.setCoefficient4ofthePartLoadPerformanceCurve(1.0095) + # create a cooling tower + tower = OpenStudio::Model::CoolingTowerVariableSpeed.new(model) + # create a supply bypass pipe + pipe_supply_bypass = OpenStudio::Model::PipeAdiabatic.new(model) + # create a supply outlet pipe + pipe_supply_outlet = OpenStudio::Model::PipeAdiabatic.new(model) + # create a demand bypass pipe + pipe_demand_bypass = OpenStudio::Model::PipeAdiabatic.new(model) + # create a demand inlet pipe + pipe_demand_inlet = OpenStudio::Model::PipeAdiabatic.new(model) + # create a demand outlet pipe + pipe_demand_outlet = OpenStudio::Model::PipeAdiabatic.new(model) + # create a setpoint manager + setpoint_manager_follow_oa = OpenStudio::Model::SetpointManagerFollowOutdoorAirTemperature.new(model) + setpoint_manager_follow_oa.setOffsetTemperatureDifference(0) + setpoint_manager_follow_oa.setMaximumSetpointTemperature(80) + setpoint_manager_follow_oa.setMinimumSetpointTemperature(5) + # connect components to plant loop + # supply side components + condenser_loop.addSupplyBranchForComponent(tower) + condenser_loop.addSupplyBranchForComponent(pipe_supply_bypass) + pump.addToNode(condenser_loop.supplyInletNode) + pipe_supply_outlet.addToNode(condenser_loop.supplyOutletNode) + setpoint_manager_follow_oa.addToNode(condenser_loop.supplyOutletNode) + # demand side components + model.getChillerElectricEIRs.each do |chiller| + if chiller.condenserType == 'WaterCooled' # works only if chillers not already connected to condenser loop(s) + condenser_loop.addDemandBranchForComponent(chiller) + end + end + condenser_loop.addDemandBranchForComponent(pipe_demand_bypass) + pipe_demand_inlet.addToNode(condenser_loop.demandInletNode) + pipe_demand_outlet.addToNode(condenser_loop.demandOutletNode) + condenserLoops['condenser_loop'] = condenser_loop + end + if (options['zoneHVAC'] == 'WSHP') || (options['zoneHVAC'] == 'GSHP') && options + # create condenser loop for heat pumps + condenser_loop = OpenStudio::Model::PlantLoop.new(model) + condenser_loop.setName('Heat Pump Loop') + condenser_loop.setMaximumLoopTemperature(80) + condenser_loop.setMinimumLoopTemperature(5) + loop_sizing = condenser_loop.sizingPlant + loop_sizing.setLoopType('Condenser') - condenserLoops = {} - # condLoopCoolingTemp_si = OpenStudio::convert(condLoopCoolingTemp,"F","C").get - # condLoopHeatingTemp_si = OpenStudio::convert(parameters["condLoopHeatingTemp"],"F","C").get - # coolingTowerWB_si = OpenStudio::convert(coolingTowerWB,"F","C").get - boilerHWST_si = OpenStudio::convert(parameters["boilerHWST"],"F","C").get - # check for water-cooled chillers - waterCooledChiller = false - model.getChillerElectricEIRs.each do |chiller| - next if waterCooledChiller == true - if chiller.condenserType == "WaterCooled" - waterCooledChiller = true - end - end - # create condenser loop for water-cooled chillers - if waterCooledChiller - # create condenser loop for water-cooled chiller(s) - condenser_loop = OpenStudio::Model::PlantLoop.new(model) - condenser_loop.setName("New Condenser Loop") - condenser_loop.setMaximumLoopTemperature(80) - condenser_loop.setMinimumLoopTemperature(5) - loop_sizing = condenser_loop.sizingPlant - loop_sizing.setLoopType("Condenser") - loop_sizing.setDesignLoopExitTemperature(29.4) - loop_sizing.setLoopDesignTemperatureDifference(5.6) - # create a pump - pump = OpenStudio::Model::PumpVariableSpeed.new(model) - pump.setRatedPumpHead(134508) #Pa - pump.setMotorEfficiency(0.9) - pump.setCoefficient1ofthePartLoadPerformanceCurve(0) - pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216) - pump.setCoefficient3ofthePartLoadPerformanceCurve(-0.0325) - pump.setCoefficient4ofthePartLoadPerformanceCurve(1.0095) - # create a cooling tower - tower = OpenStudio::Model::CoolingTowerVariableSpeed.new(model) - # create a supply bypass pipe - pipe_supply_bypass = OpenStudio::Model::PipeAdiabatic.new(model) - # create a supply outlet pipe - pipe_supply_outlet = OpenStudio::Model::PipeAdiabatic.new(model) - # create a demand bypass pipe - pipe_demand_bypass = OpenStudio::Model::PipeAdiabatic.new(model) - # create a demand inlet pipe - pipe_demand_inlet = OpenStudio::Model::PipeAdiabatic.new(model) - # create a demand outlet pipe - pipe_demand_outlet = OpenStudio::Model::PipeAdiabatic.new(model) - # create a setpoint manager - setpoint_manager_follow_oa = OpenStudio::Model::SetpointManagerFollowOutdoorAirTemperature.new(model) - setpoint_manager_follow_oa.setOffsetTemperatureDifference(0) - setpoint_manager_follow_oa.setMaximumSetpointTemperature(80) - setpoint_manager_follow_oa.setMinimumSetpointTemperature(5) - # connect components to plant loop - # supply side components - condenser_loop.addSupplyBranchForComponent(tower) - condenser_loop.addSupplyBranchForComponent(pipe_supply_bypass) - pump.addToNode(condenser_loop.supplyInletNode) - pipe_supply_outlet.addToNode(condenser_loop.supplyOutletNode) - setpoint_manager_follow_oa.addToNode(condenser_loop.supplyOutletNode) - # demand side components - model.getChillerElectricEIRs.each do |chiller| - if chiller.condenserType == "WaterCooled" # works only if chillers not already connected to condenser loop(s) - condenser_loop.addDemandBranchForComponent(chiller) - end - end - condenser_loop.addDemandBranchForComponent(pipe_demand_bypass) - pipe_demand_inlet.addToNode(condenser_loop.demandInletNode) - pipe_demand_outlet.addToNode(condenser_loop.demandOutletNode) - condenserLoops["condenser_loop"] = condenser_loop - end - if options["zoneHVAC"] == "WSHP" or options["zoneHVAC"] == "GSHP" and options - # create condenser loop for heat pumps - condenser_loop = OpenStudio::Model::PlantLoop.new(model) - condenser_loop.setName("Heat Pump Loop") - condenser_loop.setMaximumLoopTemperature(80) - condenser_loop.setMinimumLoopTemperature(5) - loop_sizing = condenser_loop.sizingPlant - loop_sizing.setLoopType("Condenser") - - if options["zoneHVAC"] == "GSHP" - loop_sizing.setDesignLoopExitTemperature(32.2) - loop_sizing.setLoopDesignTemperatureDifference(5.5556) - elsif options["zoneHVAC"] == "WSHP" - loop_sizing.setDesignLoopExitTemperature(32.2) - loop_sizing.setLoopDesignTemperatureDifference(5.5556) - end - # create a pump - pump = OpenStudio::Model::PumpVariableSpeed.new(model) - pump.setRatedPumpHead(134508) #Pa - pump.setMotorEfficiency(0.9) - pump.setCoefficient1ofthePartLoadPerformanceCurve(0) - pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216) - pump.setCoefficient3ofthePartLoadPerformanceCurve(-0.0325) - pump.setCoefficient4ofthePartLoadPerformanceCurve(1.0095) - # create a supply bypass pipe - pipe_supply_bypass = OpenStudio::Model::PipeAdiabatic.new(model) - # create a supply outlet pipe - pipe_supply_outlet = OpenStudio::Model::PipeAdiabatic.new(model) - # create a demand bypass pipe - pipe_demand_bypass = OpenStudio::Model::PipeAdiabatic.new(model) - # create a demand inlet pipe - pipe_demand_inlet = OpenStudio::Model::PipeAdiabatic.new(model) - # create a demand outlet pipe - pipe_demand_outlet = OpenStudio::Model::PipeAdiabatic.new(model) - # create setpoint managers - setpoint_manager_scheduled_loop = OpenStudio::Model::SetpointManagerScheduled.new(model,options["loop_setpoint_schedule"]) - setpoint_manager_scheduled_cooling = OpenStudio::Model::SetpointManagerScheduled.new(model,options["cooling_setpoint_schedule"]) - setpoint_manager_scheduled_heating = OpenStudio::Model::SetpointManagerScheduled.new(model,options["heating_setpoint_schedule"]) - # connect components to plant loop - # supply side components - condenser_loop.addSupplyBranchForComponent(pipe_supply_bypass) - pump.addToNode(condenser_loop.supplyInletNode) - pipe_supply_outlet.addToNode(condenser_loop.supplyOutletNode) - setpoint_manager_scheduled_loop.addToNode(condenser_loop.supplyOutletNode) - # demand side components - condenser_loop.addDemandBranchForComponent(pipe_demand_bypass) - pipe_demand_inlet.addToNode(condenser_loop.demandInletNode) - pipe_demand_outlet.addToNode(condenser_loop.demandOutletNode) - # add additional components according to specific system type - if options["zoneHVAC"] == "GSHP" - # add vertical ground heat exchanger - verticalGHX = OpenStudio::Model::GroundHeatExchangerVertical.new(model) - boreHoleLength_si = OpenStudio::convert(parameters["boreHoleLength"],"ft", "m").get - boreHoleRadius_si = OpenStudio::convert(parameters["boreHoleRadius"],"in", "m").get - groundKValue_si = OpenStudio::convert(parameters["groundKValue"],"Btu/ft*h*R","W/m*K").get - groutKValue_si = OpenStudio::convert(parameters["groutKValue"],"Btu/ft*h*R","W/m*K").get - verticalGHX.setNumberofBoreHoles(parameters["boreHoleNo"]) - verticalGHX.setBoreHoleLength(boreHoleLength_si) - verticalGHX.setBoreHoleRadius(boreHoleRadius_si) - verticalGHX.setGroundThermalConductivity(groundKValue_si) - verticalGHX.setGroutThermalConductivity(groutKValue_si) - condenser_loop.addSupplyBranchForComponent(verticalGHX) - #setpoint_manager_scheduled_heating.addToNode(verticalGHX.outletModelObject.get.to_Node.get) - # add supplemental heating boiler - if parameters["supplementalBoiler"] == "Yes" - boiler = OpenStudio::Model::BoilerHotWater.new(model) - boiler.setNominalCapacity(parameters["boilerCap"]*1000000) - boiler.setNominalThermalEfficiency(parameters["boilerEff"]) - boiler.setFuelType(parameters["boilerFuelType"]) - boiler.setDesignWaterOutletTemperature(boilerHWST_si) - boiler.addToNode(verticalGHX.outletModelObject.get.to_Node.get) - #condenser_loop.addSupplyBranchForComponent(boiler) - #setpoint_manager_scheduled_heating.addToNode(boiler.outletModelObject.get.to_Node.get) - end - # add heat pumps to demand side after they get created - elsif options["zoneHVAC"] == "WSHP" - # add a boiler and cooling tower to supply side - # create a boiler - boiler = OpenStudio::Model::BoilerHotWater.new(model) - boiler.setNominalThermalEfficiency(parameters["boilerEff"]) - boiler.setFuelType(parameters["boilerFuelType"]) - boiler.setDesignWaterOutletTemperature(parameters["boilerHWST"]) - condenser_loop.addSupplyBranchForComponent(boiler) - setpoint_manager_scheduled_heating.addToNode(boiler.outletModelObject.get.to_Node.get) - # create a cooling tower - tower = OpenStudio::Model::CoolingTowerVariableSpeed.new(model) - # tower.setDesignInletAirWetBulbTemperature(coolingTowerWB_si) - # tower.setDesignApproachTemperature(coolingTowerApproach/1.8) - # tower.setDesignRangeTemperature(coolingTowerDeltaT/1.8) - tower.addToNode(boiler.outletModelObject.get.to_Node.get) - setpoint_manager_scheduled_cooling.addToNode(tower.outletModelObject.get.to_Node.get) - end - condenserLoops["heat_pump_loop"] = condenser_loop - end - - # pass back condenser loop(s) - result = condenserLoops - return result - + if options['zoneHVAC'] == 'GSHP' + loop_sizing.setDesignLoopExitTemperature(32.2) + loop_sizing.setLoopDesignTemperatureDifference(5.5556) + elsif options['zoneHVAC'] == 'WSHP' + loop_sizing.setDesignLoopExitTemperature(32.2) + loop_sizing.setLoopDesignTemperatureDifference(5.5556) + end + # create a pump + pump = OpenStudio::Model::PumpVariableSpeed.new(model) + pump.setRatedPumpHead(134508) # Pa + pump.setMotorEfficiency(0.9) + pump.setCoefficient1ofthePartLoadPerformanceCurve(0) + pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216) + pump.setCoefficient3ofthePartLoadPerformanceCurve(-0.0325) + pump.setCoefficient4ofthePartLoadPerformanceCurve(1.0095) + # create a supply bypass pipe + pipe_supply_bypass = OpenStudio::Model::PipeAdiabatic.new(model) + # create a supply outlet pipe + pipe_supply_outlet = OpenStudio::Model::PipeAdiabatic.new(model) + # create a demand bypass pipe + pipe_demand_bypass = OpenStudio::Model::PipeAdiabatic.new(model) + # create a demand inlet pipe + pipe_demand_inlet = OpenStudio::Model::PipeAdiabatic.new(model) + # create a demand outlet pipe + pipe_demand_outlet = OpenStudio::Model::PipeAdiabatic.new(model) + # create setpoint managers + setpoint_manager_scheduled_loop = OpenStudio::Model::SetpointManagerScheduled.new(model, options['loop_setpoint_schedule']) + setpoint_manager_scheduled_cooling = OpenStudio::Model::SetpointManagerScheduled.new(model, options['cooling_setpoint_schedule']) + setpoint_manager_scheduled_heating = OpenStudio::Model::SetpointManagerScheduled.new(model, options['heating_setpoint_schedule']) + # connect components to plant loop + # supply side components + condenser_loop.addSupplyBranchForComponent(pipe_supply_bypass) + pump.addToNode(condenser_loop.supplyInletNode) + pipe_supply_outlet.addToNode(condenser_loop.supplyOutletNode) + setpoint_manager_scheduled_loop.addToNode(condenser_loop.supplyOutletNode) + # demand side components + condenser_loop.addDemandBranchForComponent(pipe_demand_bypass) + pipe_demand_inlet.addToNode(condenser_loop.demandInletNode) + pipe_demand_outlet.addToNode(condenser_loop.demandOutletNode) + # add additional components according to specific system type + if options['zoneHVAC'] == 'GSHP' + # add vertical ground heat exchanger + verticalGHX = OpenStudio::Model::GroundHeatExchangerVertical.new(model) + boreHoleLength_si = OpenStudio.convert(parameters['boreHoleLength'], 'ft', 'm').get + boreHoleRadius_si = OpenStudio.convert(parameters['boreHoleRadius'], 'in', 'm').get + groundKValue_si = OpenStudio.convert(parameters['groundKValue'], 'Btu/ft*h*R', 'W/m*K').get + groutKValue_si = OpenStudio.convert(parameters['groutKValue'], 'Btu/ft*h*R', 'W/m*K').get + verticalGHX.setNumberofBoreHoles(parameters['boreHoleNo']) + verticalGHX.setBoreHoleLength(boreHoleLength_si) + verticalGHX.setBoreHoleRadius(boreHoleRadius_si) + verticalGHX.setGroundThermalConductivity(groundKValue_si) + verticalGHX.setGroutThermalConductivity(groutKValue_si) + condenser_loop.addSupplyBranchForComponent(verticalGHX) + # setpoint_manager_scheduled_heating.addToNode(verticalGHX.outletModelObject.get.to_Node.get) + # add supplemental heating boiler + if parameters['supplementalBoiler'] == 'Yes' + boiler = OpenStudio::Model::BoilerHotWater.new(model) + boiler.setNominalCapacity(parameters['boilerCap'] * 1000000) + boiler.setNominalThermalEfficiency(parameters['boilerEff']) + boiler.setFuelType(parameters['boilerFuelType']) + boiler.setDesignWaterOutletTemperature(boilerHWST_si) + boiler.addToNode(verticalGHX.outletModelObject.get.to_Node.get) + # condenser_loop.addSupplyBranchForComponent(boiler) + # setpoint_manager_scheduled_heating.addToNode(boiler.outletModelObject.get.to_Node.get) + end + # add heat pumps to demand side after they get created + elsif options['zoneHVAC'] == 'WSHP' + # add a boiler and cooling tower to supply side + # create a boiler + boiler = OpenStudio::Model::BoilerHotWater.new(model) + boiler.setNominalThermalEfficiency(parameters['boilerEff']) + boiler.setFuelType(parameters['boilerFuelType']) + boiler.setDesignWaterOutletTemperature(parameters['boilerHWST']) + condenser_loop.addSupplyBranchForComponent(boiler) + setpoint_manager_scheduled_heating.addToNode(boiler.outletModelObject.get.to_Node.get) + # create a cooling tower + tower = OpenStudio::Model::CoolingTowerVariableSpeed.new(model) + # tower.setDesignInletAirWetBulbTemperature(coolingTowerWB_si) + # tower.setDesignApproachTemperature(coolingTowerApproach/1.8) + # tower.setDesignRangeTemperature(coolingTowerDeltaT/1.8) + tower.addToNode(boiler.outletModelObject.get.to_Node.get) + setpoint_manager_scheduled_cooling.addToNode(tower.outletModelObject.get.to_Node.get) + end + condenserLoops['heat_pump_loop'] = condenser_loop + end + + # pass back condenser loop(s) + result = condenserLoops + return result end # end of def - def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) + def self.createPrimaryAirLoops(model, runner, options, parameters) primary_airloops = [] # create primary airloop for each story assignedThermalZones = [] model.getBuildingStorys.sort.each do |building_story| - #ML stories need to be reordered from the ground up + # ML stories need to be reordered from the ground up thermalZonesToAdd = [] building_story.spaces.each do |space| # make sure spaces are assigned to thermal zones @@ -801,7 +782,7 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) if space.thermalZone.is_initialized thermal_zone = space.thermalZone.get # grab primary zones - if options["zonesPrimary"].include? thermal_zone + if options['zonesPrimary'].include? thermal_zone # make sure zone was not already assigned to another air loop unless assignedThermalZones.include? thermal_zone # make sure thermal zones are not duplicated (spaces can share thermal zones) @@ -809,12 +790,12 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) thermalZonesToAdd << thermal_zone end end - end - end + end + end end # make sure thermal zones don't get added to more than one air loop assignedThermalZones << thermalZonesToAdd - + # create new air loop if story contains primary zones unless thermalZonesToAdd.empty? airloop_primary = OpenStudio::Model::AirLoopHVAC.new(model) @@ -823,31 +804,31 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) sizing_system = airloop_primary.sizingSystem # set central heating and cooling temperatures for sizing sizing_system.setCentralCoolingDesignSupplyAirTemperature(12.8) - sizing_system.setCentralHeatingDesignSupplyAirTemperature(40) #ML OS default is 16.7 + sizing_system.setCentralHeatingDesignSupplyAirTemperature(40) # ML OS default is 16.7 # load specification - sizing_system.setSystemOutdoorAirMethod("VentilationRateProcedure") #ML OS default is ZoneSum - if options["primaryHVAC"]["doas"] - sizing_system.setTypeofLoadtoSizeOn("VentilationRequirement") #DOAS - sizing_system.setAllOutdoorAirinCooling(true) #DOAS - sizing_system.setAllOutdoorAirinHeating(true) #DOAS - else - sizing_system.setTypeofLoadtoSizeOn("Sensible") #VAV - sizing_system.setAllOutdoorAirinCooling(false) #VAV - sizing_system.setAllOutdoorAirinHeating(false) #VAV - end + sizing_system.setSystemOutdoorAirMethod('VentilationRateProcedure') # ML OS default is ZoneSum + if options['primaryHVAC']['doas'] + sizing_system.setTypeofLoadtoSizeOn('VentilationRequirement') # DOAS + sizing_system.setAllOutdoorAirinCooling(true) # DOAS + sizing_system.setAllOutdoorAirinHeating(true) # DOAS + else + sizing_system.setTypeofLoadtoSizeOn('Sensible') # VAV + sizing_system.setAllOutdoorAirinCooling(false) # VAV + sizing_system.setAllOutdoorAirinHeating(false) # VAV + end air_loop_comps = [] # set availability schedule - airloop_primary.setAvailabilitySchedule(options["hvac_schedule"]) + airloop_primary.setAvailabilitySchedule(options['hvac_schedule']) # create air loop fan - if options["primaryHVAC"]["fan"] == "Variable" + if options['primaryHVAC']['fan'] == 'Variable' # create variable speed fan and set system sizing accordingly - sizing_system.setMinimumSystemAirFlowRatio(0.3) #DCV + sizing_system.setMinimumSystemAirFlowRatio(0.3) # DCV # variable speed fan - fan = OpenStudio::Model::FanVariableVolume.new(model, model.alwaysOnDiscreteSchedule()) + fan = OpenStudio::Model::FanVariableVolume.new(model, model.alwaysOnDiscreteSchedule) fan.setFanEfficiency(0.69) - fan.setPressureRise(1125) #Pa - fan.autosizeMaximumFlowRate() + fan.setPressureRise(1125) # Pa + fan.autosizeMaximumFlowRate fan.setFanPowerMinimumFlowFraction(0.6) fan.setMotorEfficiency(0.9) fan.setMotorInAirstreamFraction(1.0) @@ -855,30 +836,30 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) else sizing_system.setMinimumSystemAirFlowRatio(1.0) # No DCV # constant speed fan - fan = OpenStudio::Model::FanConstantVolume.new(model, model.alwaysOnDiscreteSchedule()) + fan = OpenStudio::Model::FanConstantVolume.new(model, model.alwaysOnDiscreteSchedule) fan.setFanEfficiency(0.6) - fan.setPressureRise(500) #Pa - fan.autosizeMaximumFlowRate() + fan.setPressureRise(500) # Pa + fan.autosizeMaximumFlowRate fan.setMotorEfficiency(0.9) fan.setMotorInAirstreamFraction(1.0) air_loop_comps << fan - end + end # create heating coil - if options["primaryHVAC"]["heat"] == "Water" + if options['primaryHVAC']['heat'] == 'Water' # water coil - heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule()) + heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule) air_loop_comps << heating_coil - else + else # gas coil - heating_coil = OpenStudio::Model::CoilHeatingGas.new(model, model.alwaysOnDiscreteSchedule()) + heating_coil = OpenStudio::Model::CoilHeatingGas.new(model, model.alwaysOnDiscreteSchedule) air_loop_comps << heating_coil - end + end # create cooling coil - if options["primaryHVAC"]["cool"] == "Water" + if options['primaryHVAC']['cool'] == 'Water' # water coil - cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule()) + cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule) air_loop_comps << cooling_coil - elsif options["primaryHVAC"]["cool"] == "SingleDX" + elsif options['primaryHVAC']['cool'] == 'SingleDX' # single speed DX coil # create cooling coil # create clgCapFuncTempCurve @@ -928,13 +909,13 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) clgPlrCurve.setMaximumValueofx(1.0) # cooling coil cooling_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model, - model.alwaysOnDiscreteSchedule(), - clgCapFuncTempCurve, - clgCapFuncFlowFracCurve, - clgEirFuncTempCurve, - clgEirFuncFlowFracCurve, - clgPlrCurve) - cooling_coil.setRatedCOP(OpenStudio::OptionalDouble.new(parameters["doasDXEER"]/3.412)) + model.alwaysOnDiscreteSchedule, + clgCapFuncTempCurve, + clgCapFuncFlowFracCurve, + clgEirFuncTempCurve, + clgEirFuncFlowFracCurve, + clgPlrCurve) + cooling_coil.setRatedCOP(OpenStudio::OptionalDouble.new(parameters['doasDXEER'] / 3.412)) air_loop_comps << cooling_coil else # two speed DX coil (PNNL curves) @@ -986,7 +967,7 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) clgPlrCurve.setMaximumValueofx(1.0) # cooling coil cooling_coil = OpenStudio::Model::CoilCoolingDXTwoSpeed.new(model, - model.alwaysOnDiscreteSchedule(), + model.alwaysOnDiscreteSchedule, clgCapFuncTempCurve, clgCapFuncFlowFracCurve, clgEirFuncTempCurve, @@ -994,86 +975,86 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) clgPlrCurve, clgCapFuncTempCurve, clgEirFuncTempCurve) - cooling_coil.setRatedHighSpeedCOP(parameters["doasDXEER"]/3.412) - cooling_coil.setRatedLowSpeedCOP(parameters["doasDXEER"]/3.412) + cooling_coil.setRatedHighSpeedCOP(parameters['doasDXEER'] / 3.412) + cooling_coil.setRatedLowSpeedCOP(parameters['doasDXEER'] / 3.412) air_loop_comps << cooling_coil end - unless options["zoneHVAC"] == "DualDuct" + unless options['zoneHVAC'] == 'DualDuct' # create controller outdoor air controller_OA = OpenStudio::Model::ControllerOutdoorAir.new(model) - controller_OA.autosizeMinimumOutdoorAirFlowRate() - controller_OA.autosizeMaximumOutdoorAirFlowRate() + controller_OA.autosizeMinimumOutdoorAirFlowRate + controller_OA.autosizeMaximumOutdoorAirFlowRate # create ventilation schedules and assign to OA controller - if options["primaryHVAC"]["doas"] - controller_OA.setMinimumFractionofOutdoorAirSchedule(model.alwaysOnDiscreteSchedule()) - controller_OA.setMaximumFractionofOutdoorAirSchedule(model.alwaysOnDiscreteSchedule()) + if options['primaryHVAC']['doas'] + controller_OA.setMinimumFractionofOutdoorAirSchedule(model.alwaysOnDiscreteSchedule) + controller_OA.setMaximumFractionofOutdoorAirSchedule(model.alwaysOnDiscreteSchedule) else # multizone VAV that ventilates - controller_OA.setMaximumFractionofOutdoorAirSchedule(options["ventilation_schedule"]) - controller_OA.setEconomizerControlType("DifferentialEnthalpy") + controller_OA.setMaximumFractionofOutdoorAirSchedule(options['ventilation_schedule']) + controller_OA.setEconomizerControlType('DifferentialEnthalpy') # add night cycling (ML would people actually do this for a VAV system?)) - airloop_primary.setNightCycleControlType("CycleOnAny") #ML Does this work with variable speed fans? - end - controller_OA.setHeatRecoveryBypassControlType("BypassWhenOAFlowGreaterThanMinimum") + airloop_primary.setNightCycleControlType('CycleOnAny') # ML Does this work with variable speed fans? + end + controller_OA.setHeatRecoveryBypassControlType('BypassWhenOAFlowGreaterThanMinimum') # create outdoor air system system_OA = OpenStudio::Model::AirLoopHVACOutdoorAirSystem.new(model, controller_OA) air_loop_comps << system_OA - # create Evaporative cooler - unless parameters["doasEvap"] =="none" - evap_cooler = OpenStudio::Model::EvaporativeCoolerDirectResearchSpecial.new(model,model.alwaysOnDiscreteSchedule()) - evap_cooler.setCoolerEffectiveness(0.85) - end - # create ERV - unless parameters["doasERV"] == "none" - heat_exchanger = OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent.new(model) - heat_exchanger.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule()) - if parameters["doasERV"] == "rotary wheel w/o economizer lockout" - sensible_eff = 0.75 - latent_eff = 0.69 - #heat_exchanger.setEconomizerLockout(false) - heat_exchanger.setString(23,"No") - elsif parameters["doasERV"] == "rotary wheel w/ economizer lockout" - sensible_eff = 0.75 - latent_eff = 0.69 - # heat_exchanger.setEconomizerLockout(true) - heat_exchanger.setString(23,"Yes") - elsif parameters["doasERV"] == "plate w/o economizer lockout" - sensible_eff = 0.52 - latent_eff = 0.50 - #heat_exchanger.setEconomizerLockout(false) - heat_exchanger.setString(23,"No") - elsif parameters["doasERV"] == "plate w/ economizer lockout" - sensible_eff = 0.52 - latent_eff = 0.50 - # heat_exchanger.setEconomizerLockout(true) - heat_exchanger.setString(23,"Yes") - end - heat_exchanger.setSensibleEffectivenessat100CoolingAirFlow(sensible_eff) - heat_exchanger.setSensibleEffectivenessat100HeatingAirFlow(sensible_eff) - heat_exchanger.setSensibleEffectivenessat75CoolingAirFlow(sensible_eff) - heat_exchanger.setSensibleEffectivenessat75HeatingAirFlow(sensible_eff) - heat_exchanger.setLatentEffectivenessat100CoolingAirFlow(latent_eff) - heat_exchanger.setLatentEffectivenessat100HeatingAirFlow(latent_eff) - heat_exchanger.setLatentEffectivenessat75CoolingAirFlow(latent_eff) - heat_exchanger.setLatentEffectivenessat75HeatingAirFlow(latent_eff) - heat_exchanger.setFrostControlType("ExhaustOnly") - heat_exchanger.setThresholdTemperature(-12.2) - heat_exchanger.setInitialDefrostTimeFraction(0.1670) - heat_exchanger.setRateofDefrostTimeFractionIncrease(0.0240) - end + # create Evaporative cooler + unless parameters['doasEvap'] == 'none' + evap_cooler = OpenStudio::Model::EvaporativeCoolerDirectResearchSpecial.new(model, model.alwaysOnDiscreteSchedule) + evap_cooler.setCoolerEffectiveness(0.85) + end + # create ERV + unless parameters['doasERV'] == 'none' + heat_exchanger = OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent.new(model) + heat_exchanger.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule) + if parameters['doasERV'] == 'rotary wheel w/o economizer lockout' + sensible_eff = 0.75 + latent_eff = 0.69 + # heat_exchanger.setEconomizerLockout(false) + heat_exchanger.setString(23, 'No') + elsif parameters['doasERV'] == 'rotary wheel w/ economizer lockout' + sensible_eff = 0.75 + latent_eff = 0.69 + # heat_exchanger.setEconomizerLockout(true) + heat_exchanger.setString(23, 'Yes') + elsif parameters['doasERV'] == 'plate w/o economizer lockout' + sensible_eff = 0.52 + latent_eff = 0.50 + # heat_exchanger.setEconomizerLockout(false) + heat_exchanger.setString(23, 'No') + elsif parameters['doasERV'] == 'plate w/ economizer lockout' + sensible_eff = 0.52 + latent_eff = 0.50 + # heat_exchanger.setEconomizerLockout(true) + heat_exchanger.setString(23, 'Yes') + end + heat_exchanger.setSensibleEffectivenessat100CoolingAirFlow(sensible_eff) + heat_exchanger.setSensibleEffectivenessat100HeatingAirFlow(sensible_eff) + heat_exchanger.setSensibleEffectivenessat75CoolingAirFlow(sensible_eff) + heat_exchanger.setSensibleEffectivenessat75HeatingAirFlow(sensible_eff) + heat_exchanger.setLatentEffectivenessat100CoolingAirFlow(latent_eff) + heat_exchanger.setLatentEffectivenessat100HeatingAirFlow(latent_eff) + heat_exchanger.setLatentEffectivenessat75CoolingAirFlow(latent_eff) + heat_exchanger.setLatentEffectivenessat75HeatingAirFlow(latent_eff) + heat_exchanger.setFrostControlType('ExhaustOnly') + heat_exchanger.setThresholdTemperature(-12.2) + heat_exchanger.setInitialDefrostTimeFraction(0.1670) + heat_exchanger.setRateofDefrostTimeFractionIncrease(0.0240) + end - end + end # create scheduled setpoint manager for airloop - unless (options["primaryHVAC"]["doas"] or options["zoneHVAC"] == "DualDuct") + if options['primaryHVAC']['doas'] || (options['zoneHVAC'] == 'DualDuct') + # DOAS or VAV for cooling and not ventilation + setpoint_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, options['primary_sat_schedule']) + else # VAV for cooling and ventilation setpoint_manager = OpenStudio::Model::SetpointManagerOutdoorAirReset.new(model) setpoint_manager.setSetpointatOutdoorLowTemperature(15.6) setpoint_manager.setOutdoorLowTemperature(14.4) setpoint_manager.setSetpointatOutdoorHighTemperature(12.8) setpoint_manager.setOutdoorHighTemperature(21.1) - else - # DOAS or VAV for cooling and not ventilation - setpoint_manager = OpenStudio::Model::SetpointManagerScheduled.new(model,options["primary_sat_schedule"]) end # connect components to airloop # find the supply inlet node of the airloop @@ -1082,55 +1063,53 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) air_loop_comps.each do |comp| comp.addToNode(airloop_supply_inlet) if comp.to_CoilHeatingWater.is_initialized - options["hot_water_plant"].addDemandBranchForComponent(comp) + options['hot_water_plant'].addDemandBranchForComponent(comp) comp.controllerWaterCoil.get.setMinimumActuatedFlow(0) elsif comp.to_CoilCoolingWater.is_initialized - options["chilled_water_plant"].addDemandBranchForComponent(comp) + options['chilled_water_plant'].addDemandBranchForComponent(comp) comp.controllerWaterCoil.get.setMinimumActuatedFlow(0) end end - unless options["zoneHVAC"] == "DualDuct" or parameters["doasERV"] == "none" - heat_exchanger.addToNode(system_OA.outboardOANode.get) - end - - unless parameters["doasEvap"] == "none" - if parameters["doasERV"] == "none" - evap_cooler.addToNode(system_OA.outboardOANode.get) - else - hxPrimary_outlet_node = heat_exchanger.primaryAirOutletModelObject.get.to_Node.get - evap_cooler.addToNode(hxPrimary_outlet_node) - end - end - + unless (options['zoneHVAC'] == 'DualDuct') || (parameters['doasERV'] == 'none') + heat_exchanger.addToNode(system_OA.outboardOANode.get) + end + + unless parameters['doasEvap'] == 'none' + if parameters['doasERV'] == 'none' + evap_cooler.addToNode(system_OA.outboardOANode.get) + else + hxPrimary_outlet_node = heat_exchanger.primaryAirOutletModelObject.get.to_Node.get + evap_cooler.addToNode(hxPrimary_outlet_node) + end + end + # add setpoint manager to supply equipment outlet node setpoint_manager.addToNode(airloop_primary.supplyOutletNode) # add thermal zones to airloop thermalZonesToAdd.each do |zone| # make an air terminal for the zone - if options["primaryHVAC"]["fan"] == "Variable" - air_terminal = OpenStudio::Model::AirTerminalSingleDuctVAVNoReheat.new(model, model.alwaysOnDiscreteSchedule()) + if options['primaryHVAC']['fan'] == 'Variable' + air_terminal = OpenStudio::Model::AirTerminalSingleDuctVAVNoReheat.new(model, model.alwaysOnDiscreteSchedule) else - air_terminal = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule()) + air_terminal = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule) end # attach new terminal to the zone and to the airloop airloop_primary.addBranchForZone(zone, air_terminal.to_StraightComponent) - end - primary_airloops << airloop_primary + end + primary_airloops << airloop_primary end end # pass back primary airloops result = primary_airloops return result - end # end of def - def OsLib_HVAC.createSecondaryAirLoops(model, runner, options) - + def self.createSecondaryAirLoops(model, runner, options) secondary_airloops = [] # create secondary airloop for each secondary zone model.getThermalZones.each do |zone| - if options["zonesSecondary"].include? zone + if options['zonesSecondary'].include? zone # create secondary airloop airloop_secondary = OpenStudio::Model::AirLoopHVAC.new(model) airloop_secondary.setName("New Air Loop HVAC #{zone.name}") @@ -1138,24 +1117,24 @@ def OsLib_HVAC.createSecondaryAirLoops(model, runner, options) sizing_system = airloop_secondary.sizingSystem # set central heating and cooling temperatures for sizing sizing_system.setCentralCoolingDesignSupplyAirTemperature(12.8) - sizing_system.setCentralHeatingDesignSupplyAirTemperature(40) #ML OS default is 16.7 + sizing_system.setCentralHeatingDesignSupplyAirTemperature(40) # ML OS default is 16.7 # load specification - sizing_system.setSystemOutdoorAirMethod("VentilationRateProcedure") #ML OS default is ZoneSum - sizing_system.setTypeofLoadtoSizeOn("Sensible") #PSZ - sizing_system.setAllOutdoorAirinCooling(false) #PSZ - sizing_system.setAllOutdoorAirinHeating(false) #PSZ - sizing_system.setMinimumSystemAirFlowRatio(1.0) #Constant volume fan + sizing_system.setSystemOutdoorAirMethod('VentilationRateProcedure') # ML OS default is ZoneSum + sizing_system.setTypeofLoadtoSizeOn('Sensible') # PSZ + sizing_system.setAllOutdoorAirinCooling(false) # PSZ + sizing_system.setAllOutdoorAirinHeating(false) # PSZ + sizing_system.setMinimumSystemAirFlowRatio(1.0) # Constant volume fan air_loop_comps = [] # set availability schedule (HVAC operation schedule) - airloop_secondary.setAvailabilitySchedule(options["hvac_schedule"]) - if options["secondaryHVAC"]["fan"] == "Variable" + airloop_secondary.setAvailabilitySchedule(options['hvac_schedule']) + if options['secondaryHVAC']['fan'] == 'Variable' # create variable speed fan and set system sizing accordingly - sizing_system.setMinimumSystemAirFlowRatio(0.3) #DCV + sizing_system.setMinimumSystemAirFlowRatio(0.3) # DCV # variable speed fan - fan = OpenStudio::Model::FanVariableVolume.new(model, model.alwaysOnDiscreteSchedule()) + fan = OpenStudio::Model::FanVariableVolume.new(model, model.alwaysOnDiscreteSchedule) fan.setFanEfficiency(0.69) - fan.setPressureRise(1125) #Pa - fan.autosizeMaximumFlowRate() + fan.setPressureRise(1125) # Pa + fan.autosizeMaximumFlowRate fan.setFanPowerMinimumFlowFraction(0.6) fan.setMotorEfficiency(0.9) fan.setMotorInAirstreamFraction(1.0) @@ -1163,20 +1142,20 @@ def OsLib_HVAC.createSecondaryAirLoops(model, runner, options) else sizing_system.setMinimumSystemAirFlowRatio(1.0) # No DCV # constant speed fan - fan = OpenStudio::Model::FanConstantVolume.new(model, model.alwaysOnDiscreteSchedule()) + fan = OpenStudio::Model::FanConstantVolume.new(model, model.alwaysOnDiscreteSchedule) fan.setFanEfficiency(0.6) - fan.setPressureRise(500) #Pa - fan.autosizeMaximumFlowRate() + fan.setPressureRise(500) # Pa + fan.autosizeMaximumFlowRate fan.setMotorEfficiency(0.9) fan.setMotorInAirstreamFraction(1.0) air_loop_comps << fan - end + end # create cooling coil - if options["secondaryHVAC"]["cool"] == "Water" + if options['secondaryHVAC']['cool'] == 'Water' # water coil - cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule()) + cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule) air_loop_comps << cooling_coil - elsif options["secondaryHVAC"]["cool"] == "SingleDX" + elsif options['secondaryHVAC']['cool'] == 'SingleDX' # single speed DX coil # create cooling coil # create clgCapFuncTempCurve @@ -1226,12 +1205,12 @@ def OsLib_HVAC.createSecondaryAirLoops(model, runner, options) clgPlrCurve.setMaximumValueofx(1.0) # cooling coil cooling_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model, - model.alwaysOnDiscreteSchedule(), - clgCapFuncTempCurve, - clgCapFuncFlowFracCurve, - clgEirFuncTempCurve, - clgEirFuncFlowFracCurve, - clgPlrCurve) + model.alwaysOnDiscreteSchedule, + clgCapFuncTempCurve, + clgCapFuncFlowFracCurve, + clgEirFuncTempCurve, + clgEirFuncFlowFracCurve, + clgPlrCurve) cooling_coil.setRatedCOP(OpenStudio::OptionalDouble.new(4)) air_loop_comps << cooling_coil else @@ -1284,7 +1263,7 @@ def OsLib_HVAC.createSecondaryAirLoops(model, runner, options) clgPlrCurve.setMaximumValueofx(1.0) # cooling coil cooling_coil = OpenStudio::Model::CoilCoolingDXTwoSpeed.new(model, - model.alwaysOnDiscreteSchedule(), + model.alwaysOnDiscreteSchedule, clgCapFuncTempCurve, clgCapFuncFlowFracCurve, clgEirFuncTempCurve, @@ -1295,29 +1274,29 @@ def OsLib_HVAC.createSecondaryAirLoops(model, runner, options) cooling_coil.setRatedHighSpeedCOP(4) cooling_coil.setRatedLowSpeedCOP(4) air_loop_comps << cooling_coil - end - if options["secondaryHVAC"]["heat"] == "Water" + end + if options['secondaryHVAC']['heat'] == 'Water' # water coil - heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule()) + heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule) air_loop_comps << heating_coil - else + else # gas coil - heating_coil = OpenStudio::Model::CoilHeatingGas.new(model, model.alwaysOnDiscreteSchedule()) + heating_coil = OpenStudio::Model::CoilHeatingGas.new(model, model.alwaysOnDiscreteSchedule) air_loop_comps << heating_coil - end + end # create controller outdoor air controller_OA = OpenStudio::Model::ControllerOutdoorAir.new(model) - controller_OA.autosizeMinimumOutdoorAirFlowRate() - controller_OA.autosizeMaximumOutdoorAirFlowRate() - controller_OA.setEconomizerControlType("DifferentialEnthalpy") - controller_OA.setMaximumFractionofOutdoorAirSchedule(options["ventilation_schedule"]) - controller_OA.setHeatRecoveryBypassControlType("BypassWhenOAFlowGreaterThanMinimum") + controller_OA.autosizeMinimumOutdoorAirFlowRate + controller_OA.autosizeMaximumOutdoorAirFlowRate + controller_OA.setEconomizerControlType('DifferentialEnthalpy') + controller_OA.setMaximumFractionofOutdoorAirSchedule(options['ventilation_schedule']) + controller_OA.setHeatRecoveryBypassControlType('BypassWhenOAFlowGreaterThanMinimum') # create outdoor air system system_OA = OpenStudio::Model::AirLoopHVACOutdoorAirSystem.new(model, controller_OA) air_loop_comps << system_OA # create ERV heat_exchanger = OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent.new(model) - heat_exchanger.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule()) + heat_exchanger.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule) sensible_eff = 0.75 latent_eff = 0.69 heat_exchanger.setSensibleEffectivenessat100CoolingAirFlow(sensible_eff) @@ -1328,7 +1307,7 @@ def OsLib_HVAC.createSecondaryAirLoops(model, runner, options) heat_exchanger.setLatentEffectivenessat100HeatingAirFlow(latent_eff) heat_exchanger.setLatentEffectivenessat75CoolingAirFlow(latent_eff) heat_exchanger.setLatentEffectivenessat75HeatingAirFlow(latent_eff) - heat_exchanger.setFrostControlType("ExhaustOnly") + heat_exchanger.setFrostControlType('ExhaustOnly') heat_exchanger.setThresholdTemperature(-12.2) heat_exchanger.setInitialDefrostTimeFraction(0.1670) heat_exchanger.setRateofDefrostTimeFractionIncrease(0.0240) @@ -1345,10 +1324,10 @@ def OsLib_HVAC.createSecondaryAirLoops(model, runner, options) air_loop_comps.each do |comp| comp.addToNode(airloop_supply_inlet) if comp.to_CoilHeatingWater.is_initialized - options["hot_water_plant"].addDemandBranchForComponent(comp) + options['hot_water_plant'].addDemandBranchForComponent(comp) comp.controllerWaterCoil.get.setMinimumActuatedFlow(0) elsif comp.to_CoilCoolingWater.is_initialized - options["chilled_water_plant"].addDemandBranchForComponent(comp) + options['chilled_water_plant'].addDemandBranchForComponent(comp) comp.controllerWaterCoil.get.setMinimumActuatedFlow(0) end end @@ -1357,15 +1336,15 @@ def OsLib_HVAC.createSecondaryAirLoops(model, runner, options) # add setpoint manager to supply equipment outlet node setpoint_manager.addToNode(airloop_secondary.supplyOutletNode) # add thermal zone to airloop - if options["secondaryHVAC"]["fan"] == "Variable" - air_terminal = OpenStudio::Model::AirTerminalSingleDuctVAVNoReheat.new(model, model.alwaysOnDiscreteSchedule()) + if options['secondaryHVAC']['fan'] == 'Variable' + air_terminal = OpenStudio::Model::AirTerminalSingleDuctVAVNoReheat.new(model, model.alwaysOnDiscreteSchedule) else - air_terminal = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule()) + air_terminal = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule) end # attach new terminal to the zone and to the airloop airloop_secondary.addBranchForZone(zone, air_terminal.to_StraightComponent) # add night cycling - airloop_secondary.setNightCycleControlType("CycleOnAny") #ML Does this work with variable speed fans? + airloop_secondary.setNightCycleControlType('CycleOnAny') # ML Does this work with variable speed fans? secondary_airloops << airloop_secondary end end @@ -1373,59 +1352,57 @@ def OsLib_HVAC.createSecondaryAirLoops(model, runner, options) # pass back secondary airloops result = secondary_airloops return result - end # end of def - def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options,parameters) - + def self.createPrimaryZoneEquipment(model, runner, options, parameters) model.getThermalZones.each do |zone| - if options["zonesPrimary"].include? zone - if options["zoneHVAC"] == "FanCoil" + if options['zonesPrimary'].include? zone + if options['zoneHVAC'] == 'FanCoil' # create fan coil # create fan - fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule()) + fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule) fan.setFanEfficiency(0.5) - fan.setPressureRise(75) #Pa - fan.autosizeMaximumFlowRate() + fan.setPressureRise(75) # Pa + fan.autosizeMaximumFlowRate fan.setMotorEfficiency(0.9) fan.setMotorInAirstreamFraction(1.0) # create cooling coil and connect to chilled water plant - cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule()) - options["chilled_water_plant"].addDemandBranchForComponent(cooling_coil) + cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule) + options['chilled_water_plant'].addDemandBranchForComponent(cooling_coil) cooling_coil.controllerWaterCoil.get.setMinimumActuatedFlow(0) # create heating coil and connect to hot water plant - heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule()) - options["hot_water_plant"].addDemandBranchForComponent(heating_coil) + heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule) + options['hot_water_plant'].addDemandBranchForComponent(heating_coil) heating_coil.controllerWaterCoil.get.setMinimumActuatedFlow(0) # construct fan coil fan_coil = OpenStudio::Model::ZoneHVACFourPipeFanCoil.new(model, - model.alwaysOnDiscreteSchedule(), + model.alwaysOnDiscreteSchedule, fan, cooling_coil, heating_coil) - fan_coil.setMaximumOutdoorAirFlowRate(0) + fan_coil.setMaximumOutdoorAirFlowRate(0) # add fan coil to thermal zone fan_coil.addToThermalZone(zone) - elsif options["zoneHVAC"] == "WSHP" or options["zoneHVAC"] == "GSHP" + elsif (options['zoneHVAC'] == 'WSHP') || (options['zoneHVAC'] == 'GSHP') # create water source heat pump and attach to heat pump loop # create fan - fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule()) - fan.setFanEfficiency(0.75) - fan_eff = fan.fanEfficiency() - fan.setMotorEfficiency(0.9) - motor_eff = fan.motorEfficiency() - fan.autosizeMaximumFlowRate() - if parameters["gshpFanType"] == "PSC" # use 0.3W/cfm, ECM - 0.2W/cfm + fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule) + fan.setFanEfficiency(0.75) + fan_eff = fan.fanEfficiency + fan.setMotorEfficiency(0.9) + motor_eff = fan.motorEfficiency + fan.autosizeMaximumFlowRate + if parameters['gshpFanType'] == 'PSC' # use 0.3W/cfm, ECM - 0.2W/cfm watt_per_cfm = 0.30 # W/cfm - else - watt_per_cfm = 0.20 # W/cfm - end - pres_rise = OpenStudio::convert(watt_per_cfm * fan_eff * motor_eff/0.1175,"inH_{2}O","Pa").get - fan.setPressureRise(pres_rise) #Pa - fan.setMotorInAirstreamFraction(1.0) + else + watt_per_cfm = 0.20 # W/cfm + end + pres_rise = OpenStudio.convert(watt_per_cfm * fan_eff * motor_eff / 0.1175, 'inH_{2}O', 'Pa').get + fan.setPressureRise(pres_rise) # Pa + fan.setMotorInAirstreamFraction(1.0) # create cooling coil and connect to heat pump loop cooling_coil = OpenStudio::Model::CoilCoolingWaterToAirHeatPumpEquationFit.new(model) - cooling_coil.setRatedCoolingCoefficientofPerformance(parameters["gshpCoolingEER"]/3.412) # xf 061014: need to change per fan power and pump power adjustment + cooling_coil.setRatedCoolingCoefficientofPerformance(parameters['gshpCoolingEER'] / 3.412) # xf 061014: need to change per fan power and pump power adjustment cooling_coil.setRatedCoolingCoefficientofPerformance(6.45) cooling_coil.setTotalCoolingCapacityCoefficient1(-9.149069561) cooling_coil.setTotalCoolingCapacityCoefficient2(10.87814026) @@ -1443,10 +1420,10 @@ def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options,parameters) cooling_coil.setCoolingPowerConsumptionCoefficient3(3.97892546) cooling_coil.setCoolingPowerConsumptionCoefficient4(0.938181818) cooling_coil.setCoolingPowerConsumptionCoefficient5(0.0) - options["heat_pump_loop"].addDemandBranchForComponent(cooling_coil) + options['heat_pump_loop'].addDemandBranchForComponent(cooling_coil) # create heating coil and connect to heat pump loop heating_coil = OpenStudio::Model::CoilHeatingWaterToAirHeatPumpEquationFit.new(model) - heating_coil.setRatedHeatingCoefficientofPerformance(parameters["gshpHeatingCOP"]) # xf 061014: need to change per fan power and pump power adjustment + heating_coil.setRatedHeatingCoefficientofPerformance(parameters['gshpHeatingCOP']) # xf 061014: need to change per fan power and pump power adjustment heating_coil.setRatedHeatingCoefficientofPerformance(4.0) heating_coil.setHeatingCapacityCoefficient1(-1.361311959) heating_coil.setHeatingCapacityCoefficient2(-2.471798046) @@ -1458,29 +1435,29 @@ def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options,parameters) heating_coil.setHeatingPowerConsumptionCoefficient3(1.570743399) heating_coil.setHeatingPowerConsumptionCoefficient4(0.690793651) heating_coil.setHeatingPowerConsumptionCoefficient5(0.0) - options["heat_pump_loop"].addDemandBranchForComponent(heating_coil) + options['heat_pump_loop'].addDemandBranchForComponent(heating_coil) # create supplemental heating coil - supplemental_heating_coil = OpenStudio::Model::CoilHeatingElectric.new(model, model.alwaysOnDiscreteSchedule()) + supplemental_heating_coil = OpenStudio::Model::CoilHeatingElectric.new(model, model.alwaysOnDiscreteSchedule) # construct heat pump heat_pump = OpenStudio::Model::ZoneHVACWaterToAirHeatPump.new(model, - model.alwaysOnDiscreteSchedule(), + model.alwaysOnDiscreteSchedule, fan, heating_coil, cooling_coil, - supplemental_heating_coil) + supplemental_heating_coil) heat_pump.setSupplyAirFlowRateWhenNoCoolingorHeatingisNeeded(OpenStudio::OptionalDouble.new(0)) heat_pump.setOutdoorAirFlowRateDuringCoolingOperation(OpenStudio::OptionalDouble.new(0)) heat_pump.setOutdoorAirFlowRateDuringHeatingOperation(OpenStudio::OptionalDouble.new(0)) heat_pump.setOutdoorAirFlowRateWhenNoCoolingorHeatingisNeeded(OpenStudio::OptionalDouble.new(0)) # add heat pump to thermal zone heat_pump.addToThermalZone(zone) - elsif options["zoneHVAC"] == "ASHP" + elsif options['zoneHVAC'] == 'ASHP' # create air source heat pump # create fan - fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule()) + fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule) fan.setFanEfficiency(0.5) - fan.setPressureRise(75) #Pa - fan.autosizeMaximumFlowRate() + fan.setPressureRise(75) # Pa + fan.autosizeMaximumFlowRate fan.setMotorEfficiency(0.9) fan.setMotorInAirstreamFraction(1.0) # create heating coil @@ -1524,12 +1501,12 @@ def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options,parameters) htgPlrCurve.setMaximumValueofx(1.0) # heating coil heating_coil = OpenStudio::Model::CoilHeatingDXSingleSpeed.new(model, - model.alwaysOnDiscreteSchedule(), - htgCapFuncTempCurve, - htgCapFuncFlowFracCurve, - htgEirFuncTempCurve, - htgEirFuncFlowFracCurve, - htgPlrCurve) + model.alwaysOnDiscreteSchedule, + htgCapFuncTempCurve, + htgCapFuncFlowFracCurve, + htgEirFuncTempCurve, + htgEirFuncFlowFracCurve, + htgPlrCurve) heating_coil.setRatedCOP(3.4) heating_coil.setCrankcaseHeaterCapacity(200) heating_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(8) @@ -1582,18 +1559,18 @@ def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options,parameters) clgPlrCurve.setMaximumValueofx(1.0) # cooling coil cooling_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model, - model.alwaysOnDiscreteSchedule(), - clgCapFuncTempCurve, - clgCapFuncFlowFracCurve, - clgEirFuncTempCurve, - clgEirFuncFlowFracCurve, - clgPlrCurve) + model.alwaysOnDiscreteSchedule, + clgCapFuncTempCurve, + clgCapFuncFlowFracCurve, + clgEirFuncTempCurve, + clgEirFuncFlowFracCurve, + clgPlrCurve) cooling_coil.setRatedCOP(OpenStudio::OptionalDouble.new(4)) # create supplemental heating coil - supplemental_heating_coil = OpenStudio::Model::CoilHeatingElectric.new(model, model.alwaysOnDiscreteSchedule()) + supplemental_heating_coil = OpenStudio::Model::CoilHeatingElectric.new(model, model.alwaysOnDiscreteSchedule) # construct heat pump heat_pump = OpenStudio::Model::ZoneHVACPackagedTerminalHeatPump.new(model, - model.alwaysOnDiscreteSchedule(), + model.alwaysOnDiscreteSchedule, fan, heating_coil, cooling_coil, @@ -1604,34 +1581,34 @@ def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options,parameters) heat_pump.setOutdoorAirFlowRateWhenNoCoolingorHeatingisNeeded(0) # add heat pump to thermal zone heat_pump.addToThermalZone(zone) - elsif options["zoneHVAC"] == "Baseboard" + elsif options['zoneHVAC'] == 'Baseboard' # create baseboard heater add add to thermal zone and hot water loop baseboard_coil = OpenStudio::Model::CoilHeatingWaterBaseboard.new(model) - baseboard_heater = OpenStudio::Model::ZoneHVACBaseboardConvectiveWater.new(model, model.alwaysOnDiscreteSchedule(), baseboard_coil) - baseboard_heater.addToThermalZone(zone) - options["hot_water_plant"].addDemandBranchForComponent(baseboard_coil) - elsif options["zoneHVAC"] == "Radiant" + baseboard_heater = OpenStudio::Model::ZoneHVACBaseboardConvectiveWater.new(model, model.alwaysOnDiscreteSchedule, baseboard_coil) + baseboard_heater.addToThermalZone(zone) + options['hot_water_plant'].addDemandBranchForComponent(baseboard_coil) + elsif options['zoneHVAC'] == 'Radiant' # create low temperature radiant object and add to thermal zone and radiant plant loops # create hot water coil and attach to radiant hot water loop - heating_coil = OpenStudio::Model::CoilHeatingLowTempRadiantVarFlow.new(model, options["mean_radiant_heating_setpoint_schedule"]) - options["radiant_hot_water_plant"].addDemandBranchForComponent(heating_coil) + heating_coil = OpenStudio::Model::CoilHeatingLowTempRadiantVarFlow.new(model, options['mean_radiant_heating_setpoint_schedule']) + options['radiant_hot_water_plant'].addDemandBranchForComponent(heating_coil) # create chilled water coil and attach to radiant chilled water loop - cooling_coil = OpenStudio::Model::CoilCoolingLowTempRadiantVarFlow.new(model, options["mean_radiant_cooling_setpoint_schedule"]) - options["radiant_chilled_water_plant"].addDemandBranchForComponent(cooling_coil) - low_temp_radiant = OpenStudio::Model::ZoneHVACLowTempRadiantVarFlow.new(model, - model.alwaysOnDiscreteSchedule(), + cooling_coil = OpenStudio::Model::CoilCoolingLowTempRadiantVarFlow.new(model, options['mean_radiant_cooling_setpoint_schedule']) + options['radiant_chilled_water_plant'].addDemandBranchForComponent(cooling_coil) + low_temp_radiant = OpenStudio::Model::ZoneHVACLowTempRadiantVarFlow.new(model, + model.alwaysOnDiscreteSchedule, heating_coil, cooling_coil) - low_temp_radiant.setRadiantSurfaceType("Floors") + low_temp_radiant.setRadiantSurfaceType('Floors') low_temp_radiant.setHydronicTubingInsideDiameter(0.012) - low_temp_radiant.setTemperatureControlType("MeanRadiantTemperature") + low_temp_radiant.setTemperatureControlType('MeanRadiantTemperature') low_temp_radiant.addToThermalZone(zone) # create radiant floor construction and substitute for existing floor (interior or exterior) constructions # create materials for radiant floor construction layers = [] # ignore layer below insulation, which will depend on boundary condition - layers << rigid_insulation_1in = OpenStudio::Model::StandardOpaqueMaterial.new(model,"Rough",0.0254,0.02,56.06,1210) - layers << concrete_2in = OpenStudio::Model::StandardOpaqueMaterial.new(model,"MediumRough",0.0508,2.31,2322,832) + layers << rigid_insulation_1in = OpenStudio::Model::StandardOpaqueMaterial.new(model, 'Rough', 0.0254, 0.02, 56.06, 1210) + layers << concrete_2in = OpenStudio::Model::StandardOpaqueMaterial.new(model, 'MediumRough', 0.0508, 2.31, 2322, 832) layers << concrete_2in # create radiant floor construction from materials radiant_floor = OpenStudio::Model::ConstructionWithInternalSource.new(layers) @@ -1640,73 +1617,66 @@ def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options,parameters) # assign radiant construction to zone floor zone.spaces.each do |space| space.surfaces.each do |surface| - if surface.surfaceType == "Floor" + if surface.surfaceType == 'Floor' surface.setConstruction(radiant_floor) end end end - elsif options["zoneHVAC"] == "DualDuct" + elsif options['zoneHVAC'] == 'DualDuct' # create baseboard heater add add to thermal zone and hot water loop baseboard_coil = OpenStudio::Model::CoilHeatingWaterBaseboard.new(model) - baseboard_heater = OpenStudio::Model::ZoneHVACBaseboardConvectiveWater.new(model, model.alwaysOnDiscreteSchedule(), baseboard_coil) - baseboard_heater.addToThermalZone(zone) - options["hot_water_plant"].addDemandBranchForComponent(baseboard_coil) + baseboard_heater = OpenStudio::Model::ZoneHVACBaseboardConvectiveWater.new(model, model.alwaysOnDiscreteSchedule, baseboard_coil) + baseboard_heater.addToThermalZone(zone) + options['hot_water_plant'].addDemandBranchForComponent(baseboard_coil) # create fan coil (to mimic functionality of DOAS) # variable speed fan - fan = OpenStudio::Model::FanVariableVolume.new(model, model.alwaysOnDiscreteSchedule()) + fan = OpenStudio::Model::FanVariableVolume.new(model, model.alwaysOnDiscreteSchedule) fan.setFanEfficiency(0.69) - fan.setPressureRise(75) #Pa #ML This number is a guess; zone equipment pretending to be a DOAS - fan.autosizeMaximumFlowRate() + fan.setPressureRise(75) # Pa #ML This number is a guess; zone equipment pretending to be a DOAS + fan.autosizeMaximumFlowRate fan.setFanPowerMinimumFlowFraction(0.6) fan.setMotorEfficiency(0.9) fan.setMotorInAirstreamFraction(1.0) # create chilled water coil and attach to chilled water loop - cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule()) - options["chilled_water_plant"].addDemandBranchForComponent(cooling_coil) + cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule) + options['chilled_water_plant'].addDemandBranchForComponent(cooling_coil) cooling_coil.controllerWaterCoil.get.setMinimumActuatedFlow(0) # create hot water coil and attach to hot water loop - heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule()) - options["hot_water_plant"].addDemandBranchForComponent(heating_coil) + heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule) + options['hot_water_plant'].addDemandBranchForComponent(heating_coil) heating_coil.controllerWaterCoil.get.setMinimumActuatedFlow(0) # construct fan coil (DOAS) and attach to thermal zone fan_coil_doas = OpenStudio::Model::ZoneHVACFourPipeFanCoil.new(model, - options["ventilation_schedule"], + options['ventilation_schedule'], fan, cooling_coil, heating_coil) - fan_coil_doas.setCapacityControlMethod("VariableFanVariableFlow") + fan_coil_doas.setCapacityControlMethod('VariableFanVariableFlow') fan_coil_doas.addToThermalZone(zone) end end end - end # end of def - - def OsLib_HVAC.addDCV(model, runner, options) - unless options["primary_airloops"].nil? - options["primary_airloops"].each do |airloop| - if options["allHVAC"]["primary"]["fan"] == "Variable" - if airloop.airLoopHVACOutdoorAirSystem.is_initialized - controller_mv = airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.controllerMechanicalVentilation - controller_mv.setDemandControlledVentilation(true) - runner.registerInfo("Enabling demand control ventilation for #{airloop.name}") - end - end + def self.addDCV(model, runner, options) + options['primary_airloops']&.each do |airloop| + if options['allHVAC']['primary']['fan'] == 'Variable' + if airloop.airLoopHVACOutdoorAirSystem.is_initialized + controller_mv = airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.controllerMechanicalVentilation + controller_mv.setDemandControlledVentilation(true) + runner.registerInfo("Enabling demand control ventilation for #{airloop.name}") + end end end - - unless options["secondary_airloops"].nil? - options["secondary_airloops"].each do |airloop| - if options["allHVAC"]["secondary"]["fan"] == "Variable" - if airloop.airLoopHVACOutdoorAirSystem.is_initialized - controller_mv = airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.controllerMechanicalVentilation - controller_mv.setDemandControlledVentilation(true) - runner.registerInfo("Enabling demand control ventilation for #{airloop.name}") - end - end + + options['secondary_airloops']&.each do |airloop| + if options['allHVAC']['secondary']['fan'] == 'Variable' + if airloop.airLoopHVACOutdoorAirSystem.is_initialized + controller_mv = airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.controllerMechanicalVentilation + controller_mv.setDemandControlledVentilation(true) + runner.registerInfo("Enabling demand control ventilation for #{airloop.name}") + end end end end # end of def - -end \ No newline at end of file +end diff --git a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_HelperMethods.rb b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_HelperMethods.rb index b9d019b..9521c67 100644 --- a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_HelperMethods.rb +++ b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_HelperMethods.rb @@ -1,37 +1,35 @@ -module OsLib_HelperMethods +# frozen_string_literal: true +module OsLib_HelperMethods # populate choice argument from model objects - def OsLib_HelperMethods.populateChoiceArgFromModelObjects(model,modelObject_args_hash, includeBuilding = nil) - + def self.populateChoiceArgFromModelObjects(model, modelObject_args_hash, includeBuilding = nil) # populate choice argument for constructions that are applied to surfaces in the model modelObject_handles = OpenStudio::StringVector.new modelObject_display_names = OpenStudio::StringVector.new # looping through sorted hash of constructions - modelObject_args_hash.sort.map do |key,value| + modelObject_args_hash.sort.map do |key, value| modelObject_handles << value.handle.to_s modelObject_display_names << key end - if not includeBuilding == nil - #add building to string vector with space type + if !includeBuilding.nil? + # add building to string vector with space type building = model.getBuilding modelObject_handles << building.handle.to_s modelObject_display_names << includeBuilding end - result = {"modelObject_handles" => modelObject_handles, "modelObject_display_names" => modelObject_display_names} + result = { 'modelObject_handles' => modelObject_handles, 'modelObject_display_names' => modelObject_display_names } return result - - end #end of OsLib_HelperMethods.populateChoiceArgFromModelObjects + end # end of OsLib_HelperMethods.populateChoiceArgFromModelObjects # check choice argument made from model objects - def OsLib_HelperMethods.checkChoiceArgFromModelObjects(object, variableName,to_ObjectType, runner,user_arguments) - + def self.checkChoiceArgFromModelObjects(object, variableName, to_ObjectType, runner, user_arguments) apply_to_building = false modelObject = nil if object.empty? - handle = runner.getStringArgumentValue(variableName,user_arguments) + handle = runner.getStringArgumentValue(variableName, user_arguments) if handle.empty? runner.registerError("No #{variableName} was chosen.") # this logic makes this not work on an optional model object argument else @@ -39,27 +37,25 @@ def OsLib_HelperMethods.checkChoiceArgFromModelObjects(object, variableName,to_O end return false else - if not eval("object.get.#{to_ObjectType}").empty? + if !eval("object.get.#{to_ObjectType}").empty? modelObject = eval("object.get.#{to_ObjectType}").get - elsif not object.get.to_Building.empty? + elsif !object.get.to_Building.empty? apply_to_building = true else runner.registerError("Script Error - argument not showing up as #{variableName}.") return false end - end #end of if construction.empty? - - result = {"modelObject" => modelObject, "apply_to_building" => apply_to_building} + end # end of if construction.empty? - end #end of OsLib_HelperMethods.checkChoiceArgFromModelObjects + result = { 'modelObject' => modelObject, 'apply_to_building' => apply_to_building } + end # end of OsLib_HelperMethods.checkChoiceArgFromModelObjects # check choice argument made from model objects - def OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(object, variableName,to_ObjectType, runner, user_arguments) - + def self.checkOptionalChoiceArgFromModelObjects(object, variableName, to_ObjectType, runner, user_arguments) apply_to_building = false modelObject = nil if object.empty? - handle = runner.getOptionalStringArgumentValue(variableName,user_arguments) + handle = runner.getOptionalStringArgumentValue(variableName, user_arguments) if handle.empty? # do nothing, this is a valid option modelObject = nil @@ -69,34 +65,32 @@ def OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(object, variableN return false end else - if not eval("object.get.#{to_ObjectType}").empty? + if !eval("object.get.#{to_ObjectType}").empty? modelObject = eval("object.get.#{to_ObjectType}").get - elsif not object.get.to_Building.empty? + elsif !object.get.to_Building.empty? apply_to_building = true else runner.registerError("Script Error - argument not showing up as #{variableName}.") return false end - end #end of if construction.empty? - - result = {"modelObject" => modelObject, "apply_to_building" => apply_to_building} + end # end of if construction.empty? - end #end of OsLib_HelperMethods.checkChoiceArgFromModelObjects + result = { 'modelObject' => modelObject, 'apply_to_building' => apply_to_building } + end # end of OsLib_HelperMethods.checkChoiceArgFromModelObjects # check value of double arguments - def OsLib_HelperMethods.checkDoubleArguments(runner, min, max, argumentHash) - - #error flag + def self.checkDoubleArguments(runner, min, max, argumentHash) + # error flag error = false argumentHash.each do |display, argument| - if not min == nil + if !min.nil? if argument < min runner.registerError("Please enter value between #{min} and #{max} for #{display}.") # add in argument display name error = true end end - if not max == nil + if !max.nil? if argument > max runner.registerError("Please enter value between #{min} and #{max} for #{display}.") # add in argument display name error = true @@ -110,13 +104,11 @@ def OsLib_HelperMethods.checkDoubleArguments(runner, min, max, argumentHash) else return true end - - end #end of OsLib_HelperMethods.checkDoubleArguments + end # end of OsLib_HelperMethods.checkDoubleArguments # OpenStudio has built in toNeatString method # OpenStudio::toNeatString(double,2,true)# double,decimals, show commas # OpenStudio has built in helper for unit conversion. That can be done using OpenStudio::convert() as shown below. # OpenStudio::convert(double,"from unit string","to unit string").get - -end \ No newline at end of file +end diff --git a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_LightingAndEquipment.rb b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_LightingAndEquipment.rb index bc53960..535391e 100644 --- a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_LightingAndEquipment.rb +++ b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_LightingAndEquipment.rb @@ -1,13 +1,13 @@ +# frozen_string_literal: true + require "#{File.dirname(__FILE__)}/OsLib_Schedules" -#load OpenStudio measure libraries +# load OpenStudio measure libraries module OsLib_LightingAndEquipment - include OsLib_Schedules # return min ans max from array - def OsLib_LightingAndEquipment.getExteriorLightsValue(model) - + def self.getExteriorLightsValue(model) facility = model.getFacility starting_exterior_lights_power = 0 starting_exterior_lights = facility.exteriorLights @@ -18,13 +18,12 @@ def OsLib_LightingAndEquipment.getExteriorLightsValue(model) starting_exterior_lights_power += starting_exterior_light_base_power * starting_exterior_light_multiplier end - result = {"exteriorLightingPower" => starting_exterior_lights_power, "exteriorLights" => starting_exterior_lights} + result = { 'exteriorLightingPower' => starting_exterior_lights_power, 'exteriorLights' => starting_exterior_lights } return result - - end #end of OsLib_LightingAndEquipment.getExteriorLightsValue + end # end of OsLib_LightingAndEquipment.getExteriorLightsValue # return min ans max from array - def OsLib_LightingAndEquipment.removeAllExteriorLights(model,runner) + def self.removeAllExteriorLights(model, runner) facility = model.getFacility lightsRemoved = false starting_exterior_lights = facility.exteriorLights @@ -36,69 +35,65 @@ def OsLib_LightingAndEquipment.removeAllExteriorLights(model,runner) result = lightsRemoved return result - - end #end of OsLib_LightingAndEquipment.removeAllExteriorLights + end # end of OsLib_LightingAndEquipment.removeAllExteriorLights # return min ans max from array - def OsLib_LightingAndEquipment.addExteriorLights(model,runner, options = {}) - + def self.addExteriorLights(model, runner, options = {}) # set defaults to use if user inputs not passed in defaults = { - "name" => "Exterior Light", - "power" => 0, - "subCategory" => "Exterior Lighting", - "controlOption" => "AstronomicalClock", - "setbackStartTime" => 0, - "setbackEndTime" => 0, - "setbackFraction" => 0.25, + 'name' => 'Exterior Light', + 'power' => 0, + 'subCategory' => 'Exterior Lighting', + 'controlOption' => 'AstronomicalClock', + 'setbackStartTime' => 0, + 'setbackEndTime' => 0, + 'setbackFraction' => 0.25 } # merge user inputs with defaults options = defaults.merge(options) ext_lights_def = OpenStudio::Model::ExteriorLightsDefinition.new(model) - ext_lights_def.setName("#{options["name"]} Definition") - runner.registerInfo("Setting #{ext_lights_def.name} to a design power of #{options["power"]} Watts") - ext_lights_def.setDesignLevel(options["power"]) + ext_lights_def.setName("#{options['name']} Definition") + runner.registerInfo("Setting #{ext_lights_def.name} to a design power of #{options['power']} Watts") + ext_lights_def.setDesignLevel(options['power']) - #creating schedule type limits for the exterior lights schedule + # creating schedule type limits for the exterior lights schedule ext_lights_sch_type_limits = OpenStudio::Model::ScheduleTypeLimits.new(model) - ext_lights_sch_type_limits.setName("#{options["name"]} Fractional") + ext_lights_sch_type_limits.setName("#{options['name']} Fractional") ext_lights_sch_type_limits.setLowerLimitValue(0) ext_lights_sch_type_limits.setUpperLimitValue(1) - ext_lights_sch_type_limits.setNumericType("Continuous") + ext_lights_sch_type_limits.setNumericType('Continuous') # prepare values for profile - if options["setbackStartTime"] == 24 - profile = {options["setbackEndTime"] => options["setbackFraction"],24.0 => 1.0} - elsif options["setbackStartTime"] == 0 - profile = {options["setbackEndTime"] => options["setbackFraction"],24.0 => 1.0} - elsif options["setbackStartTime"] > options["setbackEndTime"] - profile = {options["setbackEndTime"] => options["setbackFraction"],options["setbackStartTime"] => 1.0,24.0 => options["setbackFraction"]} + if options['setbackStartTime'] == 24 + profile = { options['setbackEndTime'] => options['setbackFraction'], 24.0 => 1.0 } + elsif options['setbackStartTime'] == 0 + profile = { options['setbackEndTime'] => options['setbackFraction'], 24.0 => 1.0 } + elsif options['setbackStartTime'] > options['setbackEndTime'] + profile = { options['setbackEndTime'] => options['setbackFraction'], options['setbackStartTime'] => 1.0, 24.0 => options['setbackFraction'] } else - profile = {options["setbackStartTime"] => 1.0,options["setbackEndTime"] => options["setbackFraction"]} + profile = { options['setbackStartTime'] => 1.0, options['setbackEndTime'] => options['setbackFraction'] } end # inputs createSimpleSchedule_inputs = { - "name" => options["name"], - "winterTimeValuePairs" => profile, - "summerTimeValuePairs" => profile, - "defaultTimeValuePairs" => profile, + 'name' => options['name'], + 'winterTimeValuePairs' => profile, + 'summerTimeValuePairs' => profile, + 'defaultTimeValuePairs' => profile } # create a ruleset schedule with a basic profile ext_lights_sch = OsLib_Schedules.createSimpleSchedule(model, createSimpleSchedule_inputs) - #creating exterior lights object - ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def,ext_lights_sch) - ext_lights.setName("#{options["power"]} w Exterior Light") - ext_lights.setControlOption(options["controlOption"]) - ext_lights.setEndUseSubcategory(options["subCategory"]) + # creating exterior lights object + ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def, ext_lights_sch) + ext_lights.setName("#{options['power']} w Exterior Light") + ext_lights.setControlOption(options['controlOption']) + ext_lights.setEndUseSubcategory(options['subCategory']) result = ext_lights return result - - end #end of OsLib_LightingAndEquipment.addExteriorLights - -end \ No newline at end of file + end # end of OsLib_LightingAndEquipment.addExteriorLights +end diff --git a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Schedules.rb b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Schedules.rb index bc46d3d..8f44c78 100644 --- a/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Schedules.rb +++ b/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Schedules.rb @@ -1,149 +1,142 @@ -module OsLib_Schedules +# frozen_string_literal: true +module OsLib_Schedules # create a ruleset schedule with a basic profile - def OsLib_Schedules.createSimpleSchedule(model, options = {}) - + def self.createSimpleSchedule(model, options = {}) defaults = { - "name" => nil, - "winterTimeValuePairs" => {24.0 => 0.0}, - "summerTimeValuePairs" => {24.0 => 1.0}, - "defaultTimeValuePairs" => {24.0 => 1.0}, + 'name' => nil, + 'winterTimeValuePairs' => { 24.0 => 0.0 }, + 'summerTimeValuePairs' => { 24.0 => 1.0 }, + 'defaultTimeValuePairs' => { 24.0 => 1.0 } } - # merge user inputs with defaults options = defaults.merge(options) - #ScheduleRuleset + # ScheduleRuleset sch_ruleset = OpenStudio::Model::ScheduleRuleset.new(model) if name - sch_ruleset.setName(options["name"]) + sch_ruleset.setName(options['name']) end - #Winter Design Day + # Winter Design Day winter_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setWinterDesignDaySchedule(winter_dsn_day) winter_dsn_day = sch_ruleset.winterDesignDaySchedule winter_dsn_day.setName("#{sch_ruleset.name} Winter Design Day") - options["winterTimeValuePairs"].each do |k,v| + options['winterTimeValuePairs'].each do |k, v| hour = k.truncate - min = ((k - hour)*60).to_i - winter_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0),v) + min = ((k - hour) * 60).to_i + winter_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0), v) end - #Summer Design Day + # Summer Design Day summer_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setSummerDesignDaySchedule(summer_dsn_day) summer_dsn_day = sch_ruleset.summerDesignDaySchedule summer_dsn_day.setName("#{sch_ruleset.name} Summer Design Day") - options["summerTimeValuePairs"].each do |k,v| + options['summerTimeValuePairs'].each do |k, v| hour = k.truncate - min = ((k - hour)*60).to_i - summer_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0),v) + min = ((k - hour) * 60).to_i + summer_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0), v) end - #All Days + # All Days week_day = sch_ruleset.defaultDaySchedule week_day.setName("#{sch_ruleset.name} Schedule Week Day") - options["defaultTimeValuePairs"].each do |k,v| + options['defaultTimeValuePairs'].each do |k, v| hour = k.truncate - min = ((k - hour)*60).to_i - week_day.addValue(OpenStudio::Time.new(0, hour, min, 0),v) + min = ((k - hour) * 60).to_i + week_day.addValue(OpenStudio::Time.new(0, hour, min, 0), v) end result = sch_ruleset return result + end # end of OsLib_Schedules.createSimpleSchedule - end #end of OsLib_Schedules.createSimpleSchedule - # create a complex ruleset schedule - def OsLib_Schedules.createComplexSchedule(model, options = {}) - + def self.createComplexSchedule(model, options = {}) defaults = { - "name" => nil, - "default_day" => ["always_on",[24.0,1.0]] + 'name' => nil, + 'default_day' => ['always_on', [24.0, 1.0]] } # merge user inputs with defaults options = defaults.merge(options) - #ScheduleRuleset + # ScheduleRuleset sch_ruleset = OpenStudio::Model::ScheduleRuleset.new(model) if name - sch_ruleset.setName(options["name"]) + sch_ruleset.setName(options['name']) end - #Winter Design Day - unless options["winter_design_day"].nil? + # Winter Design Day + unless options['winter_design_day'].nil? winter_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setWinterDesignDaySchedule(winter_dsn_day) winter_dsn_day = sch_ruleset.winterDesignDaySchedule winter_dsn_day.setName("#{sch_ruleset.name} Winter Design Day") - options["winter_design_day"].each do |data_pair| + options['winter_design_day'].each do |data_pair| hour = data_pair[0].truncate - min = ((data_pair[0] - hour)*60).to_i - winter_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0),data_pair[1]) + min = ((data_pair[0] - hour) * 60).to_i + winter_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0), data_pair[1]) end - end + end - #Summer Design Day - unless options["summer_design_day"].nil? + # Summer Design Day + unless options['summer_design_day'].nil? summer_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setSummerDesignDaySchedule(summer_dsn_day) summer_dsn_day = sch_ruleset.summerDesignDaySchedule summer_dsn_day.setName("#{sch_ruleset.name} Summer Design Day") - options["summer_design_day"].each do |data_pair| + options['summer_design_day'].each do |data_pair| hour = data_pair[0].truncate - min = ((data_pair[0] - hour)*60).to_i - summer_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0),data_pair[1]) + min = ((data_pair[0] - hour) * 60).to_i + summer_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0), data_pair[1]) end - end - - #Default Day + end + + # Default Day default_day = sch_ruleset.defaultDaySchedule - default_day.setName("#{sch_ruleset.name} #{options["default_day"][0]}") - default_data_array = options["default_day"] + default_day.setName("#{sch_ruleset.name} #{options['default_day'][0]}") + default_data_array = options['default_day'] default_data_array.delete_at(0) default_data_array.each do |data_pair| hour = data_pair[0].truncate - min = ((data_pair[0] - hour)*60).to_i - default_day.addValue(OpenStudio::Time.new(0, hour, min, 0),data_pair[1]) + min = ((data_pair[0] - hour) * 60).to_i + default_day.addValue(OpenStudio::Time.new(0, hour, min, 0), data_pair[1]) + end + + # Rules + options['rules']&.each do |data_array| + rule = OpenStudio::Model::ScheduleRule.new(sch_ruleset) + rule.setName("#{sch_ruleset.name} #{data_array[0]} Rule") + date_range = data_array[1].split('-') + start_date = date_range[0].split('/') + end_date = date_range[1].split('/') + rule.setStartDate(model.getYearDescription.makeDate(start_date[0].to_i, start_date[1].to_i)) + rule.setEndDate(model.getYearDescription.makeDate(end_date[0].to_i, end_date[1].to_i)) + days = data_array[2].split('/') + rule.setApplySunday(true) if days.include? 'Sun' + rule.setApplyMonday(true) if days.include? 'Mon' + rule.setApplyTuesday(true) if days.include? 'Tue' + rule.setApplyWednesday(true) if days.include? 'Wed' + rule.setApplyThursday(true) if days.include? 'Thu' + rule.setApplyFriday(true) if days.include? 'Fri' + rule.setApplySaturday(true) if days.include? 'Sat' + day_schedule = rule.daySchedule + day_schedule.setName("#{sch_ruleset.name} #{data_array[0]}") + data_array.delete_at(0) + data_array.delete_at(0) + data_array.delete_at(0) + data_array.each do |data_pair| + hour = data_pair[0].truncate + min = ((data_pair[0] - hour) * 60).to_i + day_schedule.addValue(OpenStudio::Time.new(0, hour, min, 0), data_pair[1]) + end end - - #Rules - unless options["rules"].nil? - options["rules"].each do |data_array| - rule = OpenStudio::Model::ScheduleRule.new(sch_ruleset) - rule.setName("#{sch_ruleset.name} #{data_array[0]} Rule") - date_range = data_array[1].split("-") - start_date = date_range[0].split("/") - end_date = date_range[1].split("/") - rule.setStartDate(model.getYearDescription.makeDate(start_date[0].to_i,start_date[1].to_i)) - rule.setEndDate(model.getYearDescription.makeDate(end_date[0].to_i,end_date[1].to_i)) - days = data_array[2].split("/") - rule.setApplySunday(true) if days.include? "Sun" - rule.setApplyMonday(true) if days.include? "Mon" - rule.setApplyTuesday(true) if days.include? "Tue" - rule.setApplyWednesday(true) if days.include? "Wed" - rule.setApplyThursday(true) if days.include? "Thu" - rule.setApplyFriday(true) if days.include? "Fri" - rule.setApplySaturday(true) if days.include? "Sat" - day_schedule = rule.daySchedule - day_schedule.setName("#{sch_ruleset.name} #{data_array[0]}") - data_array.delete_at(0) - data_array.delete_at(0) - data_array.delete_at(0) - data_array.each do |data_pair| - hour = data_pair[0].truncate - min = ((data_pair[0] - hour)*60).to_i - day_schedule.addValue(OpenStudio::Time.new(0, hour, min, 0),data_pair[1]) - end - end - end result = sch_ruleset return result - - end #end of OsLib_Schedules.createComplexSchedule - -end \ No newline at end of file + end # end of OsLib_Schedules.createComplexSchedule +end diff --git a/lib/measures/replace_hvac_with_gshp_and_doas/tests/AedgOfficeHvacWshpDoas_Test.rb b/lib/measures/replace_hvac_with_gshp_and_doas/tests/AedgOfficeHvacWshpDoas_Test.rb index 8a79cbd..6ea4c5a 100644 --- a/lib/measures/replace_hvac_with_gshp_and_doas/tests/AedgOfficeHvacWshpDoas_Test.rb +++ b/lib/measures/replace_hvac_with_gshp_and_doas/tests/AedgOfficeHvacWshpDoas_Test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'openstudio' require 'openstudio/ruleset/ShowRunnerOutput' @@ -7,56 +9,51 @@ require 'test/unit' class AedgOfficeHvacWshpDoas_Test < Test::Unit::TestCase - - def test_AedgOfficeHvacWshpDoas - # create an instance of the measure measure = AedgOfficeHvacWshpDoas.new - + # create an instance of a runner runner = OpenStudio::Ruleset::OSRunner.new # load the test model translator = OpenStudio::OSVersion::VersionTranslator.new - path = OpenStudio::Path.new(File.dirname(__FILE__) + "/AEDG_HVAC_GenericTestModel_0225_a.osm") + path = OpenStudio::Path.new(File.dirname(__FILE__) + '/AEDG_HVAC_GenericTestModel_0225_a.osm') model = translator.loadModel(path) - assert((not model.empty?)) + assert(!model.empty?) model = model.get - + # get arguments and test that they are what we are expecting arguments = measure.arguments(model) assert_equal(3, arguments.size) - assert_equal("ceilingReturnPlenumSpaceType", arguments[0].name) - assert_equal("costTotalHVACSystem", arguments[1].name) - assert_equal("remake_schedules", arguments[2].name) - + assert_equal('ceilingReturnPlenumSpaceType', arguments[0].name) + assert_equal('costTotalHVACSystem', arguments[1].name) + assert_equal('remake_schedules', arguments[2].name) + # set argument values to good values and run the measure on model with spaces argument_map = OpenStudio::Ruleset::OSArgumentMap.new ceilingReturnPlenumSpaceType = arguments[0].clone - assert(ceilingReturnPlenumSpaceType.setValue("Plenum")) - argument_map["ceilingReturnPlenumSpaceType"] = ceilingReturnPlenumSpaceType + assert(ceilingReturnPlenumSpaceType.setValue('Plenum')) + argument_map['ceilingReturnPlenumSpaceType'] = ceilingReturnPlenumSpaceType costTotalHVACSystem = arguments[1].clone assert(costTotalHVACSystem.setValue(15000.0)) - argument_map["costTotalHVACSystem"] = costTotalHVACSystem + argument_map['costTotalHVACSystem'] = costTotalHVACSystem remake_schedules = arguments[2].clone assert(remake_schedules.setValue(true)) - argument_map["remake_schedules"] = remake_schedules - + argument_map['remake_schedules'] = remake_schedules + measure.run(model, runner, argument_map) result = runner.result show_output(result) - assert(result.value.valueName == "Success") - #assert(result.warnings.size == 1) - #assert(result.info.size == 2) - - #save the model for testing purposes - output_file_path = OpenStudio::Path.new(File.dirname(__FILE__) + "/test.osm") - model.save(output_file_path,true) - - end - + assert(result.value.valueName == 'Success') + # assert(result.warnings.size == 1) + # assert(result.info.size == 2) + + # save the model for testing purposes + output_file_path = OpenStudio::Path.new(File.dirname(__FILE__) + '/test.osm') + model.save(output_file_path, true) + end end diff --git a/lib/measures/replace_hvac_with_gshp_and_doas/tests/ReplaceHVACwithGSHPandDOAS_Test.rb b/lib/measures/replace_hvac_with_gshp_and_doas/tests/ReplaceHVACwithGSHPandDOAS_Test.rb index ff7131b..4d81fc6 100644 --- a/lib/measures/replace_hvac_with_gshp_and_doas/tests/ReplaceHVACwithGSHPandDOAS_Test.rb +++ b/lib/measures/replace_hvac_with_gshp_and_doas/tests/ReplaceHVACwithGSHPandDOAS_Test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'openstudio' require 'openstudio/ruleset/ShowRunnerOutput' @@ -7,158 +9,155 @@ require 'test/unit' class ReplaceHVACWithGSHPAndDOAS_Test < Test::Unit::TestCase - - def test_yes_plenums_doas_on_classrooms_and_cafeteria - # create an instance of the measure measure = ReplaceHVACWithGSHPAndDOAS.new - + # create an instance of a runner runner = OpenStudio::Ruleset::OSRunner.new # load the test model translator = OpenStudio::OSVersion::VersionTranslator.new - path = OpenStudio::Path.new(File.dirname(__FILE__) + "/AEDG_HVAC_GenericTestModel_0225_a.osm") + path = OpenStudio::Path.new(File.dirname(__FILE__) + '/AEDG_HVAC_GenericTestModel_0225_a.osm') model = translator.loadModel(path) - assert((not model.empty?)) + assert(!model.empty?) model = model.get - + # get arguments and test that they are what we are expecting arguments = measure.arguments(model) assert_equal(25, arguments.size) - + # set argument values to good values and run the measure on model with spaces argument_map = OpenStudio::Ruleset::OSArgumentMap.new - count = -1 - + count = -1 + ceiling_return_plenum_space_type = arguments[count += 1].clone - assert(ceiling_return_plenum_space_type.setValue("Plenum")) - argument_map["ceiling_return_plenum_space_type"] = ceiling_return_plenum_space_type - + assert(ceiling_return_plenum_space_type.setValue('Plenum')) + argument_map['ceiling_return_plenum_space_type'] = ceiling_return_plenum_space_type + # ASHRAE 189.1-2009 ClimateZone 4-8 SecondarySchool Classroom space_type = arguments[count += 1].clone assert(space_type.setValue(true)) - argument_map["ASHRAE 189.1-2009 ClimateZone 4-8 SecondarySchool Classroom"] = space_type - + argument_map['ASHRAE 189.1-2009 ClimateZone 4-8 SecondarySchool Classroom'] = space_type + # ASHRAE 90.1-2004 SecondarySchool Cafeteria space_type = arguments[count += 1].clone assert(space_type.setValue(true)) - argument_map["ASHRAE 90.1-2004 SecondarySchool Cafeteria"] = space_type - + argument_map['ASHRAE 90.1-2004 SecondarySchool Cafeteria'] = space_type + # ASHRAE 90.1-2004 SecondarySchool Gym space_type = arguments[count += 1].clone assert(space_type.setValue(false)) - argument_map["ASHRAE 90.1-2004 SecondarySchool Gym"] = space_type - + argument_map['ASHRAE 90.1-2004 SecondarySchool Gym'] = space_type + # ASHRAE 90.1-2004 SecondarySchool Office space_type = arguments[count += 1].clone assert(space_type.setValue(false)) - argument_map["ASHRAE 90.1-2004 SecondarySchool Office"] = space_type + argument_map['ASHRAE 90.1-2004 SecondarySchool Office'] = space_type # Plenum space_type = arguments[count += 1].clone assert(space_type.setValue(false)) - argument_map["Plenum"] = space_type - + argument_map['Plenum'] = space_type + gshp_htg_cop = arguments[count += 1].clone assert(gshp_htg_cop.setValue(4.5)) - argument_map["gshp_htg_cop"] = gshp_htg_cop + argument_map['gshp_htg_cop'] = gshp_htg_cop gshp_clg_eer = arguments[count += 1].clone assert(gshp_clg_eer.setValue(15.0)) - argument_map["gshp_clg_eer"] = gshp_clg_eer + argument_map['gshp_clg_eer'] = gshp_clg_eer gshp_fan_type = arguments[count += 1].clone - assert(gshp_fan_type.setValue("ECM")) - argument_map["gshp_fan_type"] = gshp_fan_type + assert(gshp_fan_type.setValue('ECM')) + argument_map['gshp_fan_type'] = gshp_fan_type bore_hole_no = arguments[count += 1].clone assert(bore_hole_no.setValue(160)) - argument_map["bore_hole_no"] = bore_hole_no + argument_map['bore_hole_no'] = bore_hole_no bore_hole_length = arguments[count += 1].clone assert(bore_hole_length.setValue(150)) - argument_map["bore_hole_length"] = bore_hole_length + argument_map['bore_hole_length'] = bore_hole_length bore_hole_radius = arguments[count += 1].clone assert(bore_hole_radius.setValue(7)) - argument_map["bore_hole_radius"] = bore_hole_radius + argument_map['bore_hole_radius'] = bore_hole_radius ground_k_value = arguments[count += 1].clone assert(ground_k_value.setValue(0.70)) - argument_map["ground_k_value"] = ground_k_value + argument_map['ground_k_value'] = ground_k_value grout_k_value = arguments[count += 1].clone assert(grout_k_value.setValue(0.80)) - argument_map["grout_k_value"] = grout_k_value + argument_map['grout_k_value'] = grout_k_value supplemental_boiler = arguments[count += 1].clone - assert(supplemental_boiler.setValue("Yes")) - argument_map["supplemental_boiler"] = supplemental_boiler + assert(supplemental_boiler.setValue('Yes')) + argument_map['supplemental_boiler'] = supplemental_boiler boiler_cap = arguments[count += 1].clone assert(boiler_cap.setValue(600)) - argument_map["boiler_cap"] = boiler_cap + argument_map['boiler_cap'] = boiler_cap boiler_eff = arguments[count += 1].clone assert(boiler_eff.setValue(0.85)) - argument_map["boiler_eff"] = boiler_eff - + argument_map['boiler_eff'] = boiler_eff + boiler_fuel_type = arguments[count += 1].clone - assert(boiler_fuel_type.setValue("Electricity")) - argument_map["boiler_fuel_type"] = boiler_fuel_type + assert(boiler_fuel_type.setValue('Electricity')) + argument_map['boiler_fuel_type'] = boiler_fuel_type boiler_hw_st = arguments[count += 1].clone assert(boiler_hw_st.setValue(125)) - argument_map["boiler_hw_st"] = boiler_hw_st - + argument_map['boiler_hw_st'] = boiler_hw_st + doas_fan_type = arguments[count += 1].clone - assert(doas_fan_type.setValue("Constant")) - argument_map["doas_fan_type"] = doas_fan_type + assert(doas_fan_type.setValue('Constant')) + argument_map['doas_fan_type'] = doas_fan_type doas_erv = arguments[count += 1].clone - assert(doas_erv.setValue("rotary wheel w/ economizer lockout")) - argument_map["doas_erv"] = doas_erv + assert(doas_erv.setValue('rotary wheel w/ economizer lockout')) + argument_map['doas_erv'] = doas_erv doas_evap = arguments[count += 1].clone - assert(doas_evap.setValue("Direct Evaporative Cooler")) - argument_map["doas_evap"] = doas_evap + assert(doas_evap.setValue('Direct Evaporative Cooler')) + argument_map['doas_evap'] = doas_evap doas_dx_eer = arguments[count += 1].clone assert(doas_dx_eer.setValue(11.0)) - argument_map["doas_dx_eer"] = doas_dx_eer - + argument_map['doas_dx_eer'] = doas_dx_eer + cost_total_hvac_system = arguments[count += 1].clone assert(cost_total_hvac_system.setValue(15000.0)) - argument_map["cost_total_hvac_system"] = cost_total_hvac_system + argument_map['cost_total_hvac_system'] = cost_total_hvac_system remake_schedules = arguments[count += 1].clone assert(remake_schedules.setValue(true)) - argument_map["remake_schedules"] = remake_schedules + argument_map['remake_schedules'] = remake_schedules # Run the measure measure.run(model, runner, argument_map) result = runner.result show_output(result) - assert(result.value.valueName == "Success") + assert(result.value.valueName == 'Success') # Save the model for testing purposes - output_file_path = OpenStudio::Path.new(File.dirname(__FILE__) + "/test_yes_plenums_doas_on_classrooms_and_cafeteria.osm") - model.save(output_file_path,true) - + output_file_path = OpenStudio::Path.new(File.dirname(__FILE__) + '/test_yes_plenums_doas_on_classrooms_and_cafeteria.osm') + model.save(output_file_path, true) + # Each thermal zone that contains a space of space types # ASHRAE 189.1-2009 ClimateZone 4-8 SecondarySchool Classroom or # ASHRAE 90.1-2004 SecondarySchool Cafeteria - # should be connected to an airloop and contain + # should be connected to an airloop and contain # All other thermal zones should not be connected to an airloop. model.getThermalZones.each do |zone| zone.spaces.each do |space| space_type = space.spaceType if space_type.is_initialized space_type = space_type.get - if space_type.name.get == "ASHRAE 189.1-2009 ClimateZone 4-8 SecondarySchool Classroom" || space_type.name.get == "ASHRAE 90.1-2004 SecondarySchool Cafeteria" + if space_type.name.get == 'ASHRAE 189.1-2009 ClimateZone 4-8 SecondarySchool Classroom' || space_type.name.get == 'ASHRAE 90.1-2004 SecondarySchool Cafeteria' assert(zone.airLoopHVAC.is_initialized) assert_equal(zone.equipment.size, 2) assert(zone.equipment[0].to_AirTerminalSingleDuctUncontrolled.is_initialized) @@ -170,7 +169,5 @@ def test_yes_plenums_doas_on_classrooms_and_cafeteria end end end - - end - + end end diff --git a/lib/measures/replace_hvac_with_gshp_and_doas/tests/measure-backup-1.rb b/lib/measures/replace_hvac_with_gshp_and_doas/tests/measure-backup-1.rb index a32a571..7664027 100644 --- a/lib/measures/replace_hvac_with_gshp_and_doas/tests/measure-backup-1.rb +++ b/lib/measures/replace_hvac_with_gshp_and_doas/tests/measure-backup-1.rb @@ -1,28 +1,29 @@ -#see the URL below for information on how to write OpenStudio measures +# frozen_string_literal: true + +# see the URL below for information on how to write OpenStudio measures # http://openstudio.nrel.gov/openstudio-measure-writing-guide -#see the URL below for information on using life cycle cost objects in OpenStudio +# see the URL below for information on using life cycle cost objects in OpenStudio # http://openstudio.nrel.gov/openstudio-life-cycle-examples -#see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) +# see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) # http://openstudio.nrel.gov/sites/openstudio.nrel.gov/files/nv_data/cpp_documentation_it/model/html/namespaces.html -#load OpenStudio measure libraries +# load OpenStudio measure libraries require "#{File.dirname(__FILE__)}/resources/OsLib_AedgMeasures" require "#{File.dirname(__FILE__)}/resources/OsLib_HelperMethods" require "#{File.dirname(__FILE__)}/resources/OsLib_HVAC" require "#{File.dirname(__FILE__)}/resources/OsLib_Schedules" -#start the measure +# start the measure class WSHPwithDOASMoreDesignParameters < OpenStudio::Ruleset::ModelUserScript - - #define the name that a user will see, this method may be deprecated as - #the display name in PAT comes from the name field in measure.xml + # define the name that a user will see, this method may be deprecated as + # the display name in PAT comes from the name field in measure.xml def name - return "WSHPwithDOASMoreDesignParameters" + return 'WSHPwithDOASMoreDesignParameters' end - #define the arguments that the user will input + # define the arguments that the user will input def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new @@ -30,403 +31,400 @@ def arguments(model) spaceTypes = model.getSpaceTypes usedSpaceTypes_handle = OpenStudio::StringVector.new usedSpaceTypes_displayName = OpenStudio::StringVector.new - spaceTypes.each do |spaceType| #todo - I need to update this to use helper so GUI sorts by display name - if spaceType.spaces.size > 0 # only show space types used in the building + spaceTypes.each do |spaceType| # TODO: - I need to update this to use helper so GUI sorts by display name + if !spaceType.spaces.empty? # only show space types used in the building usedSpaceTypes_handle << spaceType.handle.to_s usedSpaceTypes_displayName << spaceType.name.to_s end end - + # make an argument for space type - ceilingReturnPlenumSpaceType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("ceilingReturnPlenumSpaceType", usedSpaceTypes_handle, usedSpaceTypes_displayName,false) - ceilingReturnPlenumSpaceType.setDisplayName("This space type should be part of a ceiling return air plenum.") - #ceilingReturnPlenumSpaceType.setDefaultValue("We don't want a default, this is an optional argument") + ceilingReturnPlenumSpaceType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('ceilingReturnPlenumSpaceType', usedSpaceTypes_handle, usedSpaceTypes_displayName, false) + ceilingReturnPlenumSpaceType.setDisplayName('This space type should be part of a ceiling return air plenum.') + # ceilingReturnPlenumSpaceType.setDefaultValue("We don't want a default, this is an optional argument") args << ceilingReturnPlenumSpaceType - - # Heating COP of WSHP - wshpHeatingCOP = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("wshpHeatingCOP",false) - wshpHeatingCOP.setDisplayName("WSHP AHRI Heating COP") - wshpHeatingCOP.setDefaultValue(4.0) - args << wshpHeatingCOP - - # Cooling EER of WSHP - wshpCoolingEER = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("wshpCoolingEER",false) - wshpCoolingEER.setDisplayName("WSHP AHRI Cooling EER") - wshpCoolingEER.setDefaultValue(14) - args << wshpCoolingEER - - # WSHP Fan Type PSC or ECM - fanChs = OpenStudio::StringVector.new - fanChs << "PSC" - fanChs << "ECM" - wshpFanType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("wshpFanType",fanChs,true) # note ECM fan type may correspond to different set of heat pump performance curves - wshpFanType.setDisplayName("WSHP Fan Type: PSC or ECM?") - wshpFanType.setDefaultValue("PSC") + + # Heating COP of WSHP + wshpHeatingCOP = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('wshpHeatingCOP', false) + wshpHeatingCOP.setDisplayName('WSHP AHRI Heating COP') + wshpHeatingCOP.setDefaultValue(4.0) + args << wshpHeatingCOP + + # Cooling EER of WSHP + wshpCoolingEER = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('wshpCoolingEER', false) + wshpCoolingEER.setDisplayName('WSHP AHRI Cooling EER') + wshpCoolingEER.setDefaultValue(14) + args << wshpCoolingEER + + # WSHP Fan Type PSC or ECM + fanChs = OpenStudio::StringVector.new + fanChs << 'PSC' + fanChs << 'ECM' + wshpFanType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('wshpFanType', fanChs, true) # note ECM fan type may correspond to different set of heat pump performance curves + wshpFanType.setDisplayName('WSHP Fan Type: PSC or ECM?') + wshpFanType.setDefaultValue('PSC') args << wshpFanType - - # Condenser Loop Cooling Temperature - condLoopCoolingTemp = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("condLoopCoolingTemp",false) - condLoopCoolingTemp.setDisplayName("Condenser Loop Cooling Temperature (F)") - condLoopCoolingTemp.setDefaultValue(90) - args << condLoopCoolingTemp - - # Condenser Loop Heating Temperature - condLoopHeatingTemp = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("condLoopHeatingTemp",false) - condLoopHeatingTemp.setDisplayName("Condenser Loop Heating Temperature (F)") - condLoopHeatingTemp.setDefaultValue(60) - args << condLoopHeatingTemp - - # Cooling Tower - coolingTowerWB = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("coolingTowerWB",false) - coolingTowerWB.setDisplayName("Cooling Tower Design Wet Bulb (F)") - coolingTowerWB.setDefaultValue(68) - args << coolingTowerWB - - coolingTowerApproach = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("coolingTowerApproach",false) - coolingTowerApproach.setDisplayName("Cooling Tower Design Approach (F)") - coolingTowerApproach.setDefaultValue(7.0) - args << coolingTowerApproach - - coolingTowerDeltaT = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("coolingTowerDeltaT",false) - coolingTowerDeltaT.setDisplayName("Cooling Tower Design Delta T (F)") - coolingTowerDeltaT.setDefaultValue(10.0) - args << coolingTowerDeltaT - - # Boiler Efficiency - boilerEff = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("boilerEff",false) - boilerEff.setDisplayName("Boiler Thermal Efficiency") - boilerEff.setDefaultValue(0.9) - args << boilerEff - + + # Condenser Loop Cooling Temperature + condLoopCoolingTemp = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('condLoopCoolingTemp', false) + condLoopCoolingTemp.setDisplayName('Condenser Loop Cooling Temperature (F)') + condLoopCoolingTemp.setDefaultValue(90) + args << condLoopCoolingTemp + + # Condenser Loop Heating Temperature + condLoopHeatingTemp = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('condLoopHeatingTemp', false) + condLoopHeatingTemp.setDisplayName('Condenser Loop Heating Temperature (F)') + condLoopHeatingTemp.setDefaultValue(60) + args << condLoopHeatingTemp + + # Cooling Tower + coolingTowerWB = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('coolingTowerWB', false) + coolingTowerWB.setDisplayName('Cooling Tower Design Wet Bulb (F)') + coolingTowerWB.setDefaultValue(68) + args << coolingTowerWB + + coolingTowerApproach = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('coolingTowerApproach', false) + coolingTowerApproach.setDisplayName('Cooling Tower Design Approach (F)') + coolingTowerApproach.setDefaultValue(7.0) + args << coolingTowerApproach + + coolingTowerDeltaT = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('coolingTowerDeltaT', false) + coolingTowerDeltaT.setDisplayName('Cooling Tower Design Delta T (F)') + coolingTowerDeltaT.setDefaultValue(10.0) + args << coolingTowerDeltaT + + # Boiler Efficiency + boilerEff = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('boilerEff', false) + boilerEff.setDisplayName('Boiler Thermal Efficiency') + boilerEff.setDefaultValue(0.9) + args << boilerEff + # Boiler fuel Type - fuelChs = OpenStudio::StringVector.new - fuelChs << "NaturalGas" - fuelChs << "PropaneGas" - fuelChs << "FuelOil#1" - fuelChs << "FuelOil#2" - fuelChs << "Electricity" - boilerFuelType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("boilerFuelType",fuelChs,false) - boilerFuelType.setDisplayName("Boiler Fuel Type") - boilerFuelType.setDefaultValue("NaturalGas") - args << boilerFuelType - - # boiler Hot water supply temperature - boilerHWST = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("boilerHWST",false) - boilerHWST.setDisplayName("Boiler Design Heating Water Outlet Temperature (F)") - boilerHWST.setDefaultValue(120) - args << boilerHWST - - # DOAS Fan Type - doasFanChs = OpenStudio::StringVector.new - doasFanChs << "Constant" - doasFanChs << "Variable" - doasFanType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doasFanType",doasFanChs,true) - doasFanType.setDisplayName("DOAS Fan Flow Control - Variable means DCV controls") - doasFanType.setDefaultValue("Variable") - args << doasFanType - - # DOAS Energy Recovery - ervChs = OpenStudio::StringVector.new - ervChs << "plate w/o economizer lockout" - ervChs << "plate w/ economizer lockout" - ervChs << "rotary wheel w/o economizer lockout" - ervChs << "rotary wheel w/ economizer lockout" - ervChs << "none" - doasERV = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doasERV",ervChs,true) - doasERV.setDisplayName("DOAS Energy Recovery?") - doasERV.setDefaultValue("none") - args << doasERV - - # DOAS Evaporative Cooling - evapChs = OpenStudio::StringVector.new - evapChs << "Direct Evaporative Cooler" - evapChs << "none" - doasEvap = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doasEvap",evapChs,true) - doasEvap.setDisplayName("DOAS Direct Evaporative Cooling?") - doasEvap.setDefaultValue("none") - args << doasEvap - - # DOAS DX Cooling - doasDXEER = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("doasDXEER",false) - doasDXEER.setDisplayName("DOAS DX Cooling EER") - doasDXEER.setDefaultValue(10.0) - args << doasDXEER - + fuelChs = OpenStudio::StringVector.new + fuelChs << 'NaturalGas' + fuelChs << 'PropaneGas' + fuelChs << 'FuelOil#1' + fuelChs << 'FuelOil#2' + fuelChs << 'Electricity' + boilerFuelType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('boilerFuelType', fuelChs, false) + boilerFuelType.setDisplayName('Boiler Fuel Type') + boilerFuelType.setDefaultValue('NaturalGas') + args << boilerFuelType + + # boiler Hot water supply temperature + boilerHWST = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('boilerHWST', false) + boilerHWST.setDisplayName('Boiler Design Heating Water Outlet Temperature (F)') + boilerHWST.setDefaultValue(120) + args << boilerHWST + + # DOAS Fan Type + doasFanChs = OpenStudio::StringVector.new + doasFanChs << 'Constant' + doasFanChs << 'Variable' + doasFanType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doasFanType', doasFanChs, true) + doasFanType.setDisplayName('DOAS Fan Flow Control - Variable means DCV controls') + doasFanType.setDefaultValue('Variable') + args << doasFanType + + # DOAS Energy Recovery + ervChs = OpenStudio::StringVector.new + ervChs << 'plate w/o economizer lockout' + ervChs << 'plate w/ economizer lockout' + ervChs << 'rotary wheel w/o economizer lockout' + ervChs << 'rotary wheel w/ economizer lockout' + ervChs << 'none' + doasERV = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doasERV', ervChs, true) + doasERV.setDisplayName('DOAS Energy Recovery?') + doasERV.setDefaultValue('none') + args << doasERV + + # DOAS Evaporative Cooling + evapChs = OpenStudio::StringVector.new + evapChs << 'Direct Evaporative Cooler' + evapChs << 'none' + doasEvap = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doasEvap', evapChs, true) + doasEvap.setDisplayName('DOAS Direct Evaporative Cooling?') + doasEvap.setDefaultValue('none') + args << doasEvap + + # DOAS DX Cooling + doasDXEER = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('doasDXEER', false) + doasDXEER.setDisplayName('DOAS DX Cooling EER') + doasDXEER.setDefaultValue(10.0) + args << doasDXEER + # make an argument for material and installation cost # todo - I would like to split the costing out to the air loops weighted by area of building served vs. just sticking it on the building - costTotalHVACSystem = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("costTotalHVACSystem",true) - costTotalHVACSystem.setDisplayName("Total Cost for HVAC System ($).") + costTotalHVACSystem = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('costTotalHVACSystem', true) + costTotalHVACSystem.setDisplayName('Total Cost for HVAC System ($).') costTotalHVACSystem.setDefaultValue(0.0) args << costTotalHVACSystem - - #make an argument to remove existing costs - remake_schedules = OpenStudio::Ruleset::OSArgument::makeBoolArgument("remake_schedules",true) - remake_schedules.setDisplayName("Apply recommended availability and ventilation schedules for air handlers?") + + # make an argument to remove existing costs + remake_schedules = OpenStudio::Ruleset::OSArgument.makeBoolArgument('remake_schedules', true) + remake_schedules.setDisplayName('Apply recommended availability and ventilation schedules for air handlers?') remake_schedules.setDefaultValue(true) args << remake_schedules return args - end #end the arguments method + end # end the arguments method - #define what happens when the measure is run + # define what happens when the measure is run def run(model, runner, user_arguments) super(model, runner, user_arguments) - #use the built-in error checking - if not runner.validateUserArguments(arguments(model), user_arguments) + # use the built-in error checking + if !runner.validateUserArguments(arguments(model), user_arguments) return false end ### START INPUTS - #assign the user inputs to variables - ceilingReturnPlenumSpaceType = runner.getOptionalWorkspaceObjectChoiceValue("ceilingReturnPlenumSpaceType",user_arguments,model) - costTotalHVACSystem = runner.getDoubleArgumentValue("costTotalHVACSystem",user_arguments) - remake_schedules = runner.getBoolArgumentValue("remake_schedules",user_arguments) - + # assign the user inputs to variables + ceilingReturnPlenumSpaceType = runner.getOptionalWorkspaceObjectChoiceValue('ceilingReturnPlenumSpaceType', user_arguments, model) + costTotalHVACSystem = runner.getDoubleArgumentValue('costTotalHVACSystem', user_arguments) + remake_schedules = runner.getBoolArgumentValue('remake_schedules', user_arguments) + # check that spaceType was chosen and exists in model - ceilingReturnPlenumSpaceTypeCheck = OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(ceilingReturnPlenumSpaceType, "ceilingReturnPlenumSpaceType","to_SpaceType", runner, user_arguments) - if ceilingReturnPlenumSpaceTypeCheck == false then return false else ceilingReturnPlenumSpaceType = ceilingReturnPlenumSpaceTypeCheck["modelObject"] end + ceilingReturnPlenumSpaceTypeCheck = OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(ceilingReturnPlenumSpaceType, 'ceilingReturnPlenumSpaceType', 'to_SpaceType', runner, user_arguments) + ceilingReturnPlenumSpaceTypeCheck == false ? (return false) : (ceilingReturnPlenumSpaceType = ceilingReturnPlenumSpaceTypeCheck['modelObject']) # default building/ secondary space types - standardBuildingTypeTest = ["Office"] #ML Not used yet + standardBuildingTypeTest = ['Office'] # ML Not used yet secondarySpaceTypeTest = [] # empty for office - primarySpaceType = "Office" - primaryHVAC = {"doas" => true, "fan" => "Variable", "heat" => "Gas", "cool" => "SingleDX"} #xf notes: need to change - secondaryHVAC = {"fan" => "None", "heat" => "None", "cool" => "None"} #ML not used for office; leave or empty? - zoneHVAC = "WSHP" - chillerType = "None" #set to none if chiller not used - radiantChillerType = "None" #set to none if not radiant system - allHVAC = {"primary" => primaryHVAC,"secondary" => secondaryHVAC,"zone" => zoneHVAC} - - wshpHeatingCOP = runner.getDoubleArgumentValue("wshpHeatingCOP",user_arguments) - wshpCoolingEER = runner.getDoubleArgumentValue("wshpCoolingEER",user_arguments) - wshpFanType = runner.getStringArgumentValue("wshpFanType",user_arguments) - condLoopCoolingTemp = runner.getDoubleArgumentValue("condLoopCoolingTemp",user_arguments) - condLoopHeatingTemp = runner.getDoubleArgumentValue("condLoopHeatingTemp",user_arguments) - coolingTowerWB = runner.getDoubleArgumentValue("coolingTowerWB",user_arguments) - coolingTowerApproach= runner.getDoubleArgumentValue("coolingTowerApproach",user_arguments) - coolingTowerDeltaT= runner.getDoubleArgumentValue("coolingTowerDeltaT",user_arguments) - boilerEff= runner.getDoubleArgumentValue("boilerEff",user_arguments) - boilerFuelType = runner.getStringArgumentValue("boilerFuelType",user_arguments) - boilerHWST= runner.getDoubleArgumentValue("boilerHWST",user_arguments) - doasFanType = runner.getStringArgumentValue("doasFanType",user_arguments) - doasERV = runner.getStringArgumentValue("doasERV",user_arguments) - doasEvap = runner.getStringArgumentValue("doasEvap",user_arguments) - doasDXEER= runner.getDoubleArgumentValue("doasDXEER",user_arguments) - + primarySpaceType = 'Office' + primaryHVAC = { 'doas' => true, 'fan' => 'Variable', 'heat' => 'Gas', 'cool' => 'SingleDX' } # xf notes: need to change + secondaryHVAC = { 'fan' => 'None', 'heat' => 'None', 'cool' => 'None' } # ML not used for office; leave or empty? + zoneHVAC = 'WSHP' + chillerType = 'None' # set to none if chiller not used + radiantChillerType = 'None' # set to none if not radiant system + allHVAC = { 'primary' => primaryHVAC, 'secondary' => secondaryHVAC, 'zone' => zoneHVAC } + + wshpHeatingCOP = runner.getDoubleArgumentValue('wshpHeatingCOP', user_arguments) + wshpCoolingEER = runner.getDoubleArgumentValue('wshpCoolingEER', user_arguments) + wshpFanType = runner.getStringArgumentValue('wshpFanType', user_arguments) + condLoopCoolingTemp = runner.getDoubleArgumentValue('condLoopCoolingTemp', user_arguments) + condLoopHeatingTemp = runner.getDoubleArgumentValue('condLoopHeatingTemp', user_arguments) + coolingTowerWB = runner.getDoubleArgumentValue('coolingTowerWB', user_arguments) + coolingTowerApproach = runner.getDoubleArgumentValue('coolingTowerApproach', user_arguments) + coolingTowerDeltaT = runner.getDoubleArgumentValue('coolingTowerDeltaT', user_arguments) + boilerEff = runner.getDoubleArgumentValue('boilerEff', user_arguments) + boilerFuelType = runner.getStringArgumentValue('boilerFuelType', user_arguments) + boilerHWST = runner.getDoubleArgumentValue('boilerHWST', user_arguments) + doasFanType = runner.getStringArgumentValue('doasFanType', user_arguments) + doasERV = runner.getStringArgumentValue('doasERV', user_arguments) + doasEvap = runner.getStringArgumentValue('doasEvap', user_arguments) + doasDXEER = runner.getDoubleArgumentValue('doasDXEER', user_arguments) + ### END INPUTS - ### START SORT ZONES - options = {"standardBuildingTypeTest" => standardBuildingTypeTest, #ML Not used yet - "secondarySpaceTypeTest" => secondarySpaceTypeTest, - "ceilingReturnPlenumSpaceType" => ceilingReturnPlenumSpaceType} + options = { 'standardBuildingTypeTest' => standardBuildingTypeTest, # ML Not used yet + 'secondarySpaceTypeTest' => secondarySpaceTypeTest, + 'ceilingReturnPlenumSpaceType' => ceilingReturnPlenumSpaceType } zonesSorted = OsLib_HVAC.sortZones(model, runner, options) - zonesPrimary = zonesSorted["zonesPrimary"] - zonesSecondary = zonesSorted["zonesSecondary"] - zonesPlenum = zonesSorted["zonesPlenum"] - zonesUnconditioned = zonesSorted["zonesUnconditioned"] + zonesPrimary = zonesSorted['zonesPrimary'] + zonesSecondary = zonesSorted['zonesSecondary'] + zonesPlenum = zonesSorted['zonesPlenum'] + zonesUnconditioned = zonesSorted['zonesUnconditioned'] ### END SORT ZONES - + ### START REPORT INITIAL CONDITIONS - OsLib_HVAC.reportConditions(model, runner, "initial") + OsLib_HVAC.reportConditions(model, runner, 'initial') ### END REPORT INITIAL CONDITIONS ### START ASSIGN HVAC SCHEDULES - options = {"primarySpaceType" => primarySpaceType, - "allHVAC" => allHVAC, - "remake_schedules" => remake_schedules} + options = { 'primarySpaceType' => primarySpaceType, + 'allHVAC' => allHVAC, + 'remake_schedules' => remake_schedules } schedulesHVAC = OsLib_HVAC.assignHVACSchedules(model, runner, options) # assign schedules - primary_SAT_schedule = schedulesHVAC["primary_sat"] - building_HVAC_schedule = schedulesHVAC["hvac"] - building_ventilation_schedule = schedulesHVAC["ventilation"] + primary_SAT_schedule = schedulesHVAC['primary_sat'] + building_HVAC_schedule = schedulesHVAC['hvac'] + building_ventilation_schedule = schedulesHVAC['ventilation'] make_hot_water_plant = false - unless schedulesHVAC["hot_water"].nil? - hot_water_setpoint_schedule = schedulesHVAC["hot_water"] + unless schedulesHVAC['hot_water'].nil? + hot_water_setpoint_schedule = schedulesHVAC['hot_water'] make_hot_water_plant = true end make_chilled_water_plant = false - unless schedulesHVAC["chilled_water"].nil? - chilled_water_setpoint_schedule = schedulesHVAC["chilled_water"] + unless schedulesHVAC['chilled_water'].nil? + chilled_water_setpoint_schedule = schedulesHVAC['chilled_water'] make_chilled_water_plant = true end make_radiant_hot_water_plant = false - unless schedulesHVAC["radiant_hot_water"].nil? - radiant_hot_water_setpoint_schedule = schedulesHVAC["radiant_hot_water"] + unless schedulesHVAC['radiant_hot_water'].nil? + radiant_hot_water_setpoint_schedule = schedulesHVAC['radiant_hot_water'] make_radiant_hot_water_plant = true end make_radiant_chilled_water_plant = false - unless schedulesHVAC["radiant_chilled_water"].nil? - radiant_chilled_water_setpoint_schedule = schedulesHVAC["radiant_chilled_water"] + unless schedulesHVAC['radiant_chilled_water'].nil? + radiant_chilled_water_setpoint_schedule = schedulesHVAC['radiant_chilled_water'] make_radiant_chilled_water_plant = true end - unless schedulesHVAC["hp_loop"].nil? - heat_pump_loop_setpoint_schedule = schedulesHVAC["hp_loop"] + unless schedulesHVAC['hp_loop'].nil? + heat_pump_loop_setpoint_schedule = schedulesHVAC['hp_loop'] end - unless schedulesHVAC["hp_loop_cooling"].nil? - heat_pump_loop_cooling_setpoint_schedule = schedulesHVAC["hp_loop_cooling"] + unless schedulesHVAC['hp_loop_cooling'].nil? + heat_pump_loop_cooling_setpoint_schedule = schedulesHVAC['hp_loop_cooling'] end - unless schedulesHVAC["hp_loop_heating"].nil? - heat_pump_loop_heating_setpoint_schedule = schedulesHVAC["hp_loop_heating"] + unless schedulesHVAC['hp_loop_heating'].nil? + heat_pump_loop_heating_setpoint_schedule = schedulesHVAC['hp_loop_heating'] end - unless schedulesHVAC["mean_radiant_heating"].nil? - mean_radiant_heating_setpoint_schedule = schedulesHVAC["mean_radiant_heating"] + unless schedulesHVAC['mean_radiant_heating'].nil? + mean_radiant_heating_setpoint_schedule = schedulesHVAC['mean_radiant_heating'] end - unless schedulesHVAC["mean_radiant_cooling"].nil? - mean_radiant_cooling_setpoint_schedule = schedulesHVAC["mean_radiant_cooling"] + unless schedulesHVAC['mean_radiant_cooling'].nil? + mean_radiant_cooling_setpoint_schedule = schedulesHVAC['mean_radiant_cooling'] end ### END ASSIGN HVAC SCHEDULES - + ### START REMOVE EQUIPMENT OsLib_HVAC.removeEquipment(model, runner) ### END REMOVE EQUIPMENT - + ### START CREATE NEW PLANTS # create new plants # hot water plant if make_hot_water_plant - hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, "Hot Water", boilerEff, boilerFuelType, boilerHWST) + hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, 'Hot Water', boilerEff, boilerFuelType, boilerHWST) end # chilled water plant if make_chilled_water_plant - chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, "Chilled Water", chillerType) + chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, 'Chilled Water', chillerType) end # radiant hot water plant if make_radiant_hot_water_plant - radiant_hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, radiant_hot_water_setpoint_schedule, "Radiant Hot Water") + radiant_hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, radiant_hot_water_setpoint_schedule, 'Radiant Hot Water') end # chilled water plant if make_radiant_chilled_water_plant - radiant_chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, radiant_chilled_water_setpoint_schedule, "Radiant Chilled Water", radiantChillerType) + radiant_chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, radiant_chilled_water_setpoint_schedule, 'Radiant Chilled Water', radiantChillerType) end # condenser loop # need condenser loop if there is a water-cooled chiller or if there is a water source heat pump loop options = {} - options["zoneHVAC"] = zoneHVAC - if zoneHVAC.include? "SHP" - options["loop_setpoint_schedule"] = heat_pump_loop_setpoint_schedule - options["cooling_setpoint_schedule"] = heat_pump_loop_cooling_setpoint_schedule - options["heating_setpoint_schedule"] = heat_pump_loop_heating_setpoint_schedule - end - condenserLoops = OsLib_HVAC.createCondenserLoop(model, runner, options,boilerEff,boilerFuelType,boilerHWST,coolingTowerWB,coolingTowerApproach,coolingTowerDeltaT,condLoopCoolingTemp,condLoopHeatingTemp) - unless condenserLoops["condenser_loop"].nil? - condenser_loop = condenserLoops["condenser_loop"] + options['zoneHVAC'] = zoneHVAC + if zoneHVAC.include? 'SHP' + options['loop_setpoint_schedule'] = heat_pump_loop_setpoint_schedule + options['cooling_setpoint_schedule'] = heat_pump_loop_cooling_setpoint_schedule + options['heating_setpoint_schedule'] = heat_pump_loop_heating_setpoint_schedule + end + condenserLoops = OsLib_HVAC.createCondenserLoop(model, runner, options, boilerEff, boilerFuelType, boilerHWST, coolingTowerWB, coolingTowerApproach, coolingTowerDeltaT, condLoopCoolingTemp, condLoopHeatingTemp) + unless condenserLoops['condenser_loop'].nil? + condenser_loop = condenserLoops['condenser_loop'] end - unless condenserLoops["heat_pump_loop"].nil? - heat_pump_loop = condenserLoops["heat_pump_loop"] + unless condenserLoops['heat_pump_loop'].nil? + heat_pump_loop = condenserLoops['heat_pump_loop'] end ### END CREATE NEW PLANTS - + ### START CREATE PRIMARY AIRLOOPS # populate inputs hash for create primary airloops method options = {} - options["zonesPrimary"] = zonesPrimary - options["primaryHVAC"] = primaryHVAC - options["zoneHVAC"] = zoneHVAC - if primaryHVAC["doas"] - options["hvac_schedule"] = building_ventilation_schedule - options["ventilation_schedule"] = building_ventilation_schedule + options['zonesPrimary'] = zonesPrimary + options['primaryHVAC'] = primaryHVAC + options['zoneHVAC'] = zoneHVAC + if primaryHVAC['doas'] + options['hvac_schedule'] = building_ventilation_schedule + options['ventilation_schedule'] = building_ventilation_schedule else # primary HVAC is multizone VAV - unless zoneHVAC == "DualDuct" - # primary system is multizone VAV that cools and ventilates - options["hvac_schedule"] = building_HVAC_schedule - options["ventilation_schedule"] = building_ventilation_schedule - else + if zoneHVAC == 'DualDuct' # primary system is a multizone VAV that cools only (primary system ventilation schedule is set to always off; hvac set to always on) - options["hvac_schedule"] = model.alwaysOnDiscreteSchedule() + options['hvac_schedule'] = model.alwaysOnDiscreteSchedule + else + # primary system is multizone VAV that cools and ventilates + options['hvac_schedule'] = building_HVAC_schedule + options['ventilation_schedule'] = building_ventilation_schedule end end - options["primary_sat_schedule"] = primary_SAT_schedule + options['primary_sat_schedule'] = primary_SAT_schedule if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end - primary_airloops = OsLib_HVAC.createPrimaryAirLoops(model, runner, options,doasFanType,doasERV,doasEvap,doasDXEER) + primary_airloops = OsLib_HVAC.createPrimaryAirLoops(model, runner, options, doasFanType, doasERV, doasEvap, doasDXEER) ### END CREATE PRIMARY AIRLOOPS - + ### START CREATE SECONDARY AIRLOOPS # populate inputs hash for create primary airloops method options = {} - options["zonesSecondary"] = zonesSecondary - options["secondaryHVAC"] = secondaryHVAC - options["hvac_schedule"] = building_HVAC_schedule - options["ventilation_schedule"] = building_ventilation_schedule + options['zonesSecondary'] = zonesSecondary + options['secondaryHVAC'] = secondaryHVAC + options['hvac_schedule'] = building_HVAC_schedule + options['ventilation_schedule'] = building_ventilation_schedule if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end secondary_airloops = OsLib_HVAC.createSecondaryAirLoops(model, runner, options) ### END CREATE SECONDARY AIRLOOPS - + ### START ASSIGN PLENUMS - options = {"zonesPrimary" => zonesPrimary,"zonesPlenum" => zonesPlenum} + options = { 'zonesPrimary' => zonesPrimary, 'zonesPlenum' => zonesPlenum } zone_plenum_hash = OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options) ### END ASSIGN PLENUMS - + ### START CREATE PRIMARY ZONE EQUIPMENT options = {} - options["zonesPrimary"] = zonesPrimary - options["zoneHVAC"] = zoneHVAC + options['zonesPrimary'] = zonesPrimary + options['zoneHVAC'] = zoneHVAC if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end - if zoneHVAC.include? "SHP" - options["heat_pump_loop"] = heat_pump_loop + if zoneHVAC.include? 'SHP' + options['heat_pump_loop'] = heat_pump_loop end - if zoneHVAC == "DualDuct" - options["ventilation_schedule"] = building_ventilation_schedule + if zoneHVAC == 'DualDuct' + options['ventilation_schedule'] = building_ventilation_schedule end - if zoneHVAC == "Radiant" - options["radiant_hot_water_plant"] = radiant_hot_water_plant - options["radiant_chilled_water_plant"] = radiant_chilled_water_plant - options["mean_radiant_heating_setpoint_schedule"] = mean_radiant_heating_setpoint_schedule - options["mean_radiant_cooling_setpoint_schedule"] = mean_radiant_cooling_setpoint_schedule + if zoneHVAC == 'Radiant' + options['radiant_hot_water_plant'] = radiant_hot_water_plant + options['radiant_chilled_water_plant'] = radiant_chilled_water_plant + options['mean_radiant_heating_setpoint_schedule'] = mean_radiant_heating_setpoint_schedule + options['mean_radiant_cooling_setpoint_schedule'] = mean_radiant_cooling_setpoint_schedule end - OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options,wshpCoolingEER, wshpHeatingCOP,wshpFanType) + OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options, wshpCoolingEER, wshpHeatingCOP, wshpFanType) ### END CREATE PRIMARY ZONE EQUIPMENT - + # START ADD DCV options = {} - unless zoneHVAC == "DualDuct" - options["primary_airloops"] = primary_airloops + unless zoneHVAC == 'DualDuct' + options['primary_airloops'] = primary_airloops end - options["secondary_airloops"] = secondary_airloops - options["allHVAC"] = allHVAC + options['secondary_airloops'] = secondary_airloops + options['allHVAC'] = allHVAC OsLib_HVAC.addDCV(model, runner, options) # END ADD DCV - - # todo - add in lifecycle costs + + # TODO: - add in lifecycle costs expected_life = 25 years_until_costs_start = 0 costHVAC = costTotalHVACSystem - lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("HVAC System", model.getBuilding, costHVAC, "CostPerEach", "Construction", expected_life, years_until_costs_start).get + lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost('HVAC System', model.getBuilding, costHVAC, 'CostPerEach', 'Construction', expected_life, years_until_costs_start).get # # # # add AEDG tips - aedgTips = ["HV04","HV10","HV12"] + aedgTips = ['HV04', 'HV10', 'HV12'] # populate how to tip messages - aedgTipsLong = OsLib_AedgMeasures.getLongHowToTips("SmMdOff",aedgTips.uniq.sort,runner) - if not aedgTipsLong - return false # this should only happen if measure writer passes bad values to getLongHowToTips - end + aedgTipsLong = OsLib_AedgMeasures.getLongHowToTips('SmMdOff', aedgTips.uniq.sort, runner) + if !aedgTipsLong + return false # this should only happen if measure writer passes bad values to getLongHowToTips + end ### START REPORT FINAL CONDITIONS - OsLib_HVAC.reportConditions(model, runner, "final") + OsLib_HVAC.reportConditions(model, runner, 'final') ### END REPORT FINAL CONDITIONS return true + end # end the run method +end # end the measure - end #end the run method - -end #end the measure - -#this allows the measure to be used by the application -WSHPwithDOASMoreDesignParameters.new.registerWithApplication \ No newline at end of file +# this allows the measure to be used by the application +WSHPwithDOASMoreDesignParameters.new.registerWithApplication diff --git a/lib/measures/replace_hvac_with_gshp_and_doas/tests/measure-backup.rb b/lib/measures/replace_hvac_with_gshp_and_doas/tests/measure-backup.rb index 42f2889..dfbceac 100644 --- a/lib/measures/replace_hvac_with_gshp_and_doas/tests/measure-backup.rb +++ b/lib/measures/replace_hvac_with_gshp_and_doas/tests/measure-backup.rb @@ -1,28 +1,29 @@ -#see the URL below for information on how to write OpenStudio measures +# frozen_string_literal: true + +# see the URL below for information on how to write OpenStudio measures # http://openstudio.nrel.gov/openstudio-measure-writing-guide -#see the URL below for information on using life cycle cost objects in OpenStudio +# see the URL below for information on using life cycle cost objects in OpenStudio # http://openstudio.nrel.gov/openstudio-life-cycle-examples -#see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) +# see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) # http://openstudio.nrel.gov/sites/openstudio.nrel.gov/files/nv_data/cpp_documentation_it/model/html/namespaces.html -#load OpenStudio measure libraries -#require "#{File.dirname(__FILE__)}/resources/OsLib_AedgMeasures" +# load OpenStudio measure libraries +# require "#{File.dirname(__FILE__)}/resources/OsLib_AedgMeasures" require "#{File.dirname(__FILE__)}/resources/OsLib_HelperMethods" require "#{File.dirname(__FILE__)}/resources/OsLib_HVAC" require "#{File.dirname(__FILE__)}/resources/OsLib_Schedules" -#start the measure +# start the measure class WSHPwithDOASMoreDesignParameters < OpenStudio::Ruleset::ModelUserScript - - #define the name that a user will see, this method may be deprecated as - #the display name in PAT comes from the name field in measure.xml + # define the name that a user will see, this method may be deprecated as + # the display name in PAT comes from the name field in measure.xml def name - return "WSHPwithDOASMoreDesignParameters" + return 'WSHPwithDOASMoreDesignParameters' end - #define the arguments that the user will input + # define the arguments that the user will input def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new @@ -30,386 +31,385 @@ def arguments(model) spaceTypes = model.getSpaceTypes usedSpaceTypes_handle = OpenStudio::StringVector.new usedSpaceTypes_displayName = OpenStudio::StringVector.new - spaceTypes.each do |spaceType| #todo - I need to update this to use helper so GUI sorts by display name - if spaceType.spaces.size > 0 # only show space types used in the building + spaceTypes.each do |spaceType| # TODO: - I need to update this to use helper so GUI sorts by display name + if !spaceType.spaces.empty? # only show space types used in the building usedSpaceTypes_handle << spaceType.handle.to_s usedSpaceTypes_displayName << spaceType.name.to_s end end # make an argument for space type - ceilingReturnPlenumSpaceType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("ceilingReturnPlenumSpaceType", usedSpaceTypes_handle, usedSpaceTypes_displayName,false) - ceilingReturnPlenumSpaceType.setDisplayName("This space type should be part of a ceiling return air plenum.") - #ceilingReturnPlenumSpaceType.setDefaultValue("We don't want a default, this is an optional argument") + ceilingReturnPlenumSpaceType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('ceilingReturnPlenumSpaceType', usedSpaceTypes_handle, usedSpaceTypes_displayName, false) + ceilingReturnPlenumSpaceType.setDisplayName('This space type should be part of a ceiling return air plenum.') + # ceilingReturnPlenumSpaceType.setDefaultValue("We don't want a default, this is an optional argument") args << ceilingReturnPlenumSpaceType - - # Heating COP of WSHP - wshpHeatingCOP = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("wshpHeatingCOP",false) - wshpHeatingCOP.setDisplayName("WSHP AHRI Heating COP") - wshpHeatingCOP.setDefaultValue(4.0) - args << wshpHeatingCOP - - # Cooling EER of WSHP - wshpCoolingEER = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("wshpCoolingEER",false) - wshpCoolingEER.setDisplayName("WSHP AHRI Cooling EER") - wshpCoolingEER.setDefaultValue(14) - args << wshpCoolingEER - - # WSHP Fan Type PSC or ECM - fanChs = OpenStudio::StringVector.new - fanChs << "PSC" - fanChs << "ECM" - wshpFanType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("wshpFanType",fanChs,true) # note ECM fan type may correspond to different set of heat pump performance curves - wshpFanType.setDisplayName("WSHP Fan Type: PSC or ECM?") - wshpFanType.setDefaultValue("PSC") + + # Heating COP of WSHP + wshpHeatingCOP = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('wshpHeatingCOP', false) + wshpHeatingCOP.setDisplayName('WSHP AHRI Heating COP') + wshpHeatingCOP.setDefaultValue(4.0) + args << wshpHeatingCOP + + # Cooling EER of WSHP + wshpCoolingEER = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('wshpCoolingEER', false) + wshpCoolingEER.setDisplayName('WSHP AHRI Cooling EER') + wshpCoolingEER.setDefaultValue(14) + args << wshpCoolingEER + + # WSHP Fan Type PSC or ECM + fanChs = OpenStudio::StringVector.new + fanChs << 'PSC' + fanChs << 'ECM' + wshpFanType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('wshpFanType', fanChs, true) # note ECM fan type may correspond to different set of heat pump performance curves + wshpFanType.setDisplayName('WSHP Fan Type: PSC or ECM?') + wshpFanType.setDefaultValue('PSC') args << wshpFanType - - # Condenser Loop Cooling Temperature - condLoopCoolingTemp = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("condLoopCoolingTemp",false) - condLoopCoolingTemp.setDisplayName("Condenser Loop Cooling Temperature (F)") - condLoopCoolingTemp.setDefaultValue(90) - args << condLoopCoolingTemp - - # Condenser Loop Heating Temperature - condLoopHeatingTemp = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("condLoopHeatingTemp",false) - condLoopHeatingTemp.setDisplayName("Condenser Loop Heating Temperature (F)") - condLoopHeatingTemp.setDefaultValue(60) - args << condLoopHeatingTemp - - # Cooling Tower - coolingTowerWB = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("coolingTowerWB",false) - coolingTowerWB.setDisplayName("Cooling Tower Design Wet Bulb (F)") - coolingTowerWB.setDefaultValue(68) - args << coolingTowerWB - - coolingTowerApproach = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("coolingTowerApproach",false) - coolingTowerApproach.setDisplayName("Cooling Tower Design Approach (F)") - coolingTowerApproach.setDefaultValue(7.0) - args << coolingTowerApproach - - coolingTowerDeltaT = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("coolingTowerDeltaT",false) - coolingTowerDeltaT.setDisplayName("Cooling Tower Design Delta T (F)") - coolingTowerDeltaT.setDefaultValue(10.0) - args << coolingTowerDeltaT - - # Boiler Efficiency - boilerEff = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("boilerEff",false) - boilerEff.setDisplayName("Boiler Thermal Efficiency") - boilerEff.setDefaultValue(0.9) - args << boilerEff - + + # Condenser Loop Cooling Temperature + condLoopCoolingTemp = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('condLoopCoolingTemp', false) + condLoopCoolingTemp.setDisplayName('Condenser Loop Cooling Temperature (F)') + condLoopCoolingTemp.setDefaultValue(90) + args << condLoopCoolingTemp + + # Condenser Loop Heating Temperature + condLoopHeatingTemp = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('condLoopHeatingTemp', false) + condLoopHeatingTemp.setDisplayName('Condenser Loop Heating Temperature (F)') + condLoopHeatingTemp.setDefaultValue(60) + args << condLoopHeatingTemp + + # Cooling Tower + coolingTowerWB = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('coolingTowerWB', false) + coolingTowerWB.setDisplayName('Cooling Tower Design Wet Bulb (F)') + coolingTowerWB.setDefaultValue(68) + args << coolingTowerWB + + coolingTowerApproach = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('coolingTowerApproach', false) + coolingTowerApproach.setDisplayName('Cooling Tower Design Approach (F)') + coolingTowerApproach.setDefaultValue(7.0) + args << coolingTowerApproach + + coolingTowerDeltaT = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('coolingTowerDeltaT', false) + coolingTowerDeltaT.setDisplayName('Cooling Tower Design Delta T (F)') + coolingTowerDeltaT.setDefaultValue(10.0) + args << coolingTowerDeltaT + + # Boiler Efficiency + boilerEff = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('boilerEff', false) + boilerEff.setDisplayName('Boiler Thermal Efficiency') + boilerEff.setDefaultValue(0.9) + args << boilerEff + # Boiler fuel Type - fuelChs = OpenStudio::StringVector.new - fuelChs << "NaturalGas" - fuelChs << "PropaneGas" - fuelChs << "FuelOil#1" - fuelChs << "FuelOil#2" - fuelChs << "Electricity" - boilerFuelType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("boilerFuelType",fuelChs,false) - boilerFuelType.setDisplayName("Boiler Fuel Type") - boilerFuelType.setDefaultValue("NaturalGas") - args << boilerFuelType - - # boiler Hot water supply temperature - boilerHWST = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("boilerHWST",false) - boilerHWST.setDisplayName("Boiler Design Heating Water Outlet Temperature (F)") - boilerHWST.setDefaultValue(120) - args << boilerHWST - - # DOAS Fan Type - doasFanChs = OpenStudio::StringVector.new - doasFanChs << "Constant" - doasFanChs << "Variable" - doasFanType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doasFanType",doasFanChs,true) - doasFanType.setDisplayName("DOAS Fan Flow Control - Variable means DCV controls") - doasFanType.setDefaultValue("Variable") - args << doasFanType - - # DOAS Energy Recovery - ervChs = OpenStudio::StringVector.new - ervChs << "plate w/o economizer lockout" - ervChs << "plate w/ economizer lockout" - ervChs << "rotary wheel w/o economizer lockout" - ervChs << "rotary wheel w/ economizer lockout" - ervChs << "none" - doasERV = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doasERV",ervChs,true) - doasERV.setDisplayName("DOAS Energy Recovery?") - doasERV.setDefaultValue("none") - args << doasERV - - # DOAS Evaporative Cooling - evapChs = OpenStudio::StringVector.new - evapChs << "Direct Evaporative Cooler" - evapChs << "none" - doasEvap = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doasEvap",evapChs,true) - doasEvap.setDisplayName("DOAS Direct Evaporative Cooling?") - doasEvap.setDefaultValue("none") - args << doasEvap - - # DOAS DX Cooling - doasDXEER = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("doasDXEER",false) - doasDXEER.setDisplayName("DOAS DX Cooling EER") - doasDXEER.setDefaultValue(10.0) - args << doasDXEER - + fuelChs = OpenStudio::StringVector.new + fuelChs << 'NaturalGas' + fuelChs << 'PropaneGas' + fuelChs << 'FuelOil#1' + fuelChs << 'FuelOil#2' + fuelChs << 'Electricity' + boilerFuelType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('boilerFuelType', fuelChs, false) + boilerFuelType.setDisplayName('Boiler Fuel Type') + boilerFuelType.setDefaultValue('NaturalGas') + args << boilerFuelType + + # boiler Hot water supply temperature + boilerHWST = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('boilerHWST', false) + boilerHWST.setDisplayName('Boiler Design Heating Water Outlet Temperature (F)') + boilerHWST.setDefaultValue(120) + args << boilerHWST + + # DOAS Fan Type + doasFanChs = OpenStudio::StringVector.new + doasFanChs << 'Constant' + doasFanChs << 'Variable' + doasFanType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doasFanType', doasFanChs, true) + doasFanType.setDisplayName('DOAS Fan Flow Control - Variable means DCV controls') + doasFanType.setDefaultValue('Variable') + args << doasFanType + + # DOAS Energy Recovery + ervChs = OpenStudio::StringVector.new + ervChs << 'plate w/o economizer lockout' + ervChs << 'plate w/ economizer lockout' + ervChs << 'rotary wheel w/o economizer lockout' + ervChs << 'rotary wheel w/ economizer lockout' + ervChs << 'none' + doasERV = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doasERV', ervChs, true) + doasERV.setDisplayName('DOAS Energy Recovery?') + doasERV.setDefaultValue('none') + args << doasERV + + # DOAS Evaporative Cooling + evapChs = OpenStudio::StringVector.new + evapChs << 'Direct Evaporative Cooler' + evapChs << 'none' + doasEvap = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doasEvap', evapChs, true) + doasEvap.setDisplayName('DOAS Direct Evaporative Cooling?') + doasEvap.setDefaultValue('none') + args << doasEvap + + # DOAS DX Cooling + doasDXEER = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('doasDXEER', false) + doasDXEER.setDisplayName('DOAS DX Cooling EER') + doasDXEER.setDefaultValue(10.0) + args << doasDXEER + # make an argument for material and installation cost # todo - I would like to split the costing out to the air loops weighted by area of building served vs. just sticking it on the building - costTotalHVACSystem = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("costTotalHVACSystem",true) - costTotalHVACSystem.setDisplayName("Total Cost for HVAC System ($).") + costTotalHVACSystem = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('costTotalHVACSystem', true) + costTotalHVACSystem.setDisplayName('Total Cost for HVAC System ($).') costTotalHVACSystem.setDefaultValue(0.0) args << costTotalHVACSystem - - #make an argument to remove existing costs - remake_schedules = OpenStudio::Ruleset::OSArgument::makeBoolArgument("remake_schedules",true) - remake_schedules.setDisplayName("Apply recommended availability and ventilation schedules for air handlers?") + + # make an argument to remove existing costs + remake_schedules = OpenStudio::Ruleset::OSArgument.makeBoolArgument('remake_schedules', true) + remake_schedules.setDisplayName('Apply recommended availability and ventilation schedules for air handlers?') remake_schedules.setDefaultValue(true) args << remake_schedules return args - end #end the arguments method + end # end the arguments method - #define what happens when the measure is run + # define what happens when the measure is run def run(model, runner, user_arguments) super(model, runner, user_arguments) - #use the built-in error checking - if not runner.validateUserArguments(arguments(model), user_arguments) + # use the built-in error checking + if !runner.validateUserArguments(arguments(model), user_arguments) return false end - wshpHeatingCOP = runner.getDoubleArgumentValue("wshpHeatingCOP",user_arguments) - wshpCoolingEER = runner.getDoubleArgumentValue("wshpCoolingEER",user_arguments) - wshpFanType = runner.getStringArgumentValue("wshpFanType",user_arguments) - condLoopCoolingTemp = runner.getDoubleArgumentValue("condLoopCoolingTemp",user_arguments) - condLoopHeatingTemp = runner.getDoubleArgumentValue("condLoopHeatingTemp",user_arguments) - coolingTowerWB = runner.getDoubleArgumentValue("coolingTowerWB",user_arguments) - coolingTowerApproach= runner.getDoubleArgumentValue("coolingTowerApproach",user_arguments) - coolingTowerDeltaT= runner.getDoubleArgumentValue("coolingTowerDeltaT",user_arguments) - boilerEff= runner.getDoubleArgumentValue("boilerEff",user_arguments) - boilerFuelType = runner.getStringArgumentValue("boilerFuelType",user_arguments) - boilerHWST= runner.getDoubleArgumentValue("boilerHWST",user_arguments) - doasFanType = runner.getStringArgumentValue("doasFanType",user_arguments) - doasERV = runner.getStringArgumentValue("doasERV",user_arguments) - doasEvap = runner.getStringArgumentValue("doasEvap",user_arguments) - doasDXEER= runner.getDoubleArgumentValue("doasDXEER",user_arguments) - + wshpHeatingCOP = runner.getDoubleArgumentValue('wshpHeatingCOP', user_arguments) + wshpCoolingEER = runner.getDoubleArgumentValue('wshpCoolingEER', user_arguments) + wshpFanType = runner.getStringArgumentValue('wshpFanType', user_arguments) + condLoopCoolingTemp = runner.getDoubleArgumentValue('condLoopCoolingTemp', user_arguments) + condLoopHeatingTemp = runner.getDoubleArgumentValue('condLoopHeatingTemp', user_arguments) + coolingTowerWB = runner.getDoubleArgumentValue('coolingTowerWB', user_arguments) + coolingTowerApproach = runner.getDoubleArgumentValue('coolingTowerApproach', user_arguments) + coolingTowerDeltaT = runner.getDoubleArgumentValue('coolingTowerDeltaT', user_arguments) + boilerEff = runner.getDoubleArgumentValue('boilerEff', user_arguments) + boilerFuelType = runner.getStringArgumentValue('boilerFuelType', user_arguments) + boilerHWST = runner.getDoubleArgumentValue('boilerHWST', user_arguments) + doasFanType = runner.getStringArgumentValue('doasFanType', user_arguments) + doasERV = runner.getStringArgumentValue('doasERV', user_arguments) + doasEvap = runner.getStringArgumentValue('doasEvap', user_arguments) + doasDXEER = runner.getDoubleArgumentValue('doasDXEER', user_arguments) + ### START INPUTS - #assign the user inputs to variables - ceilingReturnPlenumSpaceType = runner.getOptionalWorkspaceObjectChoiceValue("ceilingReturnPlenumSpaceType",user_arguments,model) - costTotalHVACSystem = runner.getDoubleArgumentValue("costTotalHVACSystem",user_arguments) - remake_schedules = runner.getBoolArgumentValue("remake_schedules",user_arguments) + # assign the user inputs to variables + ceilingReturnPlenumSpaceType = runner.getOptionalWorkspaceObjectChoiceValue('ceilingReturnPlenumSpaceType', user_arguments, model) + costTotalHVACSystem = runner.getDoubleArgumentValue('costTotalHVACSystem', user_arguments) + remake_schedules = runner.getBoolArgumentValue('remake_schedules', user_arguments) # check that spaceType was chosen and exists in model - ceilingReturnPlenumSpaceTypeCheck = OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(ceilingReturnPlenumSpaceType, "ceilingReturnPlenumSpaceType","to_SpaceType", runner, user_arguments) - if ceilingReturnPlenumSpaceTypeCheck == false then return false else ceilingReturnPlenumSpaceType = ceilingReturnPlenumSpaceTypeCheck["modelObject"] end + ceilingReturnPlenumSpaceTypeCheck = OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(ceilingReturnPlenumSpaceType, 'ceilingReturnPlenumSpaceType', 'to_SpaceType', runner, user_arguments) + ceilingReturnPlenumSpaceTypeCheck == false ? (return false) : (ceilingReturnPlenumSpaceType = ceilingReturnPlenumSpaceTypeCheck['modelObject']) # default building/ secondary space types - standardBuildingTypeTest = ["Office"] #ML Not used yet + standardBuildingTypeTest = ['Office'] # ML Not used yet secondarySpaceTypeTest = [] # empty for office - primarySpaceType = "Office" - if doasFanType == "Variable" - primaryHVAC = {"doas" => true, "fan" => "Variable", "heat" => "Gas", "cool" => "SingleDX"} - else - primaryHVAC = {"doas" => true, "fan" => "Constant", "heat" => "Gas", "cool" => "SingleDX"} - end - secondaryHVAC = {"fan" => "None", "heat" => "None", "cool" => "None"} #ML not used for office; leave or empty? - zoneHVAC = "WSHP" - chillerType = "None" #set to none if chiller not used - radiantChillerType = "None" #set to none if not radiant system - allHVAC = {"primary" => primaryHVAC,"secondary" => secondaryHVAC,"zone" => zoneHVAC} - - + primarySpaceType = 'Office' + if doasFanType == 'Variable' + primaryHVAC = { 'doas' => true, 'fan' => 'Variable', 'heat' => 'Gas', 'cool' => 'SingleDX' } + else + primaryHVAC = { 'doas' => true, 'fan' => 'Constant', 'heat' => 'Gas', 'cool' => 'SingleDX' } + end + secondaryHVAC = { 'fan' => 'None', 'heat' => 'None', 'cool' => 'None' } # ML not used for office; leave or empty? + zoneHVAC = 'WSHP' + chillerType = 'None' # set to none if chiller not used + radiantChillerType = 'None' # set to none if not radiant system + allHVAC = { 'primary' => primaryHVAC, 'secondary' => secondaryHVAC, 'zone' => zoneHVAC } + ### END INPUTS - + ### START SORT ZONES - options = {"standardBuildingTypeTest" => standardBuildingTypeTest, #ML Not used yet - "secondarySpaceTypeTest" => secondarySpaceTypeTest, - "ceilingReturnPlenumSpaceType" => ceilingReturnPlenumSpaceType} + options = { 'standardBuildingTypeTest' => standardBuildingTypeTest, # ML Not used yet + 'secondarySpaceTypeTest' => secondarySpaceTypeTest, + 'ceilingReturnPlenumSpaceType' => ceilingReturnPlenumSpaceType } zonesSorted = OsLib_HVAC.sortZones(model, runner, options) - zonesPrimary = zonesSorted["zonesPrimary"] - zonesSecondary = zonesSorted["zonesSecondary"] - zonesPlenum = zonesSorted["zonesPlenum"] - zonesUnconditioned = zonesSorted["zonesUnconditioned"] + zonesPrimary = zonesSorted['zonesPrimary'] + zonesSecondary = zonesSorted['zonesSecondary'] + zonesPlenum = zonesSorted['zonesPlenum'] + zonesUnconditioned = zonesSorted['zonesUnconditioned'] ### END SORT ZONES - + ### START REPORT INITIAL CONDITIONS - OsLib_HVAC.reportConditions(model, runner, "initial") + OsLib_HVAC.reportConditions(model, runner, 'initial') ### END REPORT INITIAL CONDITIONS ### START ASSIGN HVAC SCHEDULES - options = {"primarySpaceType" => primarySpaceType, - "allHVAC" => allHVAC, - "remake_schedules" => remake_schedules} + options = { 'primarySpaceType' => primarySpaceType, + 'allHVAC' => allHVAC, + 'remake_schedules' => remake_schedules } schedulesHVAC = OsLib_HVAC.assignHVACSchedules(model, runner, options) # assign schedules - primary_SAT_schedule = schedulesHVAC["primary_sat"] - building_HVAC_schedule = schedulesHVAC["hvac"] - building_ventilation_schedule = schedulesHVAC["ventilation"] + primary_SAT_schedule = schedulesHVAC['primary_sat'] + building_HVAC_schedule = schedulesHVAC['hvac'] + building_ventilation_schedule = schedulesHVAC['ventilation'] make_hot_water_plant = false - unless schedulesHVAC["hot_water"].nil? - hot_water_setpoint_schedule = schedulesHVAC["hot_water"] + unless schedulesHVAC['hot_water'].nil? + hot_water_setpoint_schedule = schedulesHVAC['hot_water'] make_hot_water_plant = true end make_chilled_water_plant = false - unless schedulesHVAC["chilled_water"].nil? - chilled_water_setpoint_schedule = schedulesHVAC["chilled_water"] + unless schedulesHVAC['chilled_water'].nil? + chilled_water_setpoint_schedule = schedulesHVAC['chilled_water'] make_chilled_water_plant = true end make_radiant_hot_water_plant = false - unless schedulesHVAC["radiant_hot_water"].nil? - radiant_hot_water_setpoint_schedule = schedulesHVAC["radiant_hot_water"] + unless schedulesHVAC['radiant_hot_water'].nil? + radiant_hot_water_setpoint_schedule = schedulesHVAC['radiant_hot_water'] make_radiant_hot_water_plant = true end make_radiant_chilled_water_plant = false - unless schedulesHVAC["radiant_chilled_water"].nil? - radiant_chilled_water_setpoint_schedule = schedulesHVAC["radiant_chilled_water"] + unless schedulesHVAC['radiant_chilled_water'].nil? + radiant_chilled_water_setpoint_schedule = schedulesHVAC['radiant_chilled_water'] make_radiant_chilled_water_plant = true end - unless schedulesHVAC["hp_loop"].nil? - heat_pump_loop_setpoint_schedule = schedulesHVAC["hp_loop"] + unless schedulesHVAC['hp_loop'].nil? + heat_pump_loop_setpoint_schedule = schedulesHVAC['hp_loop'] end - unless schedulesHVAC["hp_loop_cooling"].nil? - heat_pump_loop_cooling_setpoint_schedule = schedulesHVAC["hp_loop_cooling"] + unless schedulesHVAC['hp_loop_cooling'].nil? + heat_pump_loop_cooling_setpoint_schedule = schedulesHVAC['hp_loop_cooling'] end - unless schedulesHVAC["hp_loop_heating"].nil? - heat_pump_loop_heating_setpoint_schedule = schedulesHVAC["hp_loop_heating"] + unless schedulesHVAC['hp_loop_heating'].nil? + heat_pump_loop_heating_setpoint_schedule = schedulesHVAC['hp_loop_heating'] end - unless schedulesHVAC["mean_radiant_heating"].nil? - mean_radiant_heating_setpoint_schedule = schedulesHVAC["mean_radiant_heating"] + unless schedulesHVAC['mean_radiant_heating'].nil? + mean_radiant_heating_setpoint_schedule = schedulesHVAC['mean_radiant_heating'] end - unless schedulesHVAC["mean_radiant_cooling"].nil? - mean_radiant_cooling_setpoint_schedule = schedulesHVAC["mean_radiant_cooling"] + unless schedulesHVAC['mean_radiant_cooling'].nil? + mean_radiant_cooling_setpoint_schedule = schedulesHVAC['mean_radiant_cooling'] end ### END ASSIGN HVAC SCHEDULES - + ### START REMOVE EQUIPMENT OsLib_HVAC.removeEquipment(model, runner) ### END REMOVE EQUIPMENT - + ### START CREATE NEW PLANTS # create new plants # hot water plant if make_hot_water_plant - hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, "Hot Water", boilerEff, boilerFuelType, boilerHWST) + hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, 'Hot Water', boilerEff, boilerFuelType, boilerHWST) end # chilled water plant if make_chilled_water_plant - chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, "Chilled Water", chillerType) + chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, 'Chilled Water', chillerType) end # radiant hot water plant if make_radiant_hot_water_plant - radiant_hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, radiant_hot_water_setpoint_schedule, "Radiant Hot Water") + radiant_hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, radiant_hot_water_setpoint_schedule, 'Radiant Hot Water') end # chilled water plant if make_radiant_chilled_water_plant - radiant_chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, radiant_chilled_water_setpoint_schedule, "Radiant Chilled Water", radiantChillerType) + radiant_chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, radiant_chilled_water_setpoint_schedule, 'Radiant Chilled Water', radiantChillerType) end # condenser loop # need condenser loop if there is a water-cooled chiller or if there is a water source heat pump loop options = {} - options["zoneHVAC"] = zoneHVAC - if zoneHVAC.include? "SHP" - options["loop_setpoint_schedule"] = heat_pump_loop_setpoint_schedule - options["cooling_setpoint_schedule"] = heat_pump_loop_cooling_setpoint_schedule - options["heating_setpoint_schedule"] = heat_pump_loop_heating_setpoint_schedule - end - condenserLoops = OsLib_HVAC.createCondenserLoop(model, runner, options,boilerEff,boilerFuelType,boilerHWST,coolingTowerWB,coolingTowerApproach,coolingTowerDeltaT,condLoopCoolingTemp,condLoopHeatingTemp) - unless condenserLoops["condenser_loop"].nil? - condenser_loop = condenserLoops["condenser_loop"] + options['zoneHVAC'] = zoneHVAC + if zoneHVAC.include? 'SHP' + options['loop_setpoint_schedule'] = heat_pump_loop_setpoint_schedule + options['cooling_setpoint_schedule'] = heat_pump_loop_cooling_setpoint_schedule + options['heating_setpoint_schedule'] = heat_pump_loop_heating_setpoint_schedule + end + condenserLoops = OsLib_HVAC.createCondenserLoop(model, runner, options, boilerEff, boilerFuelType, boilerHWST, coolingTowerWB, coolingTowerApproach, coolingTowerDeltaT, condLoopCoolingTemp, condLoopHeatingTemp) + unless condenserLoops['condenser_loop'].nil? + condenser_loop = condenserLoops['condenser_loop'] end - unless condenserLoops["heat_pump_loop"].nil? - heat_pump_loop = condenserLoops["heat_pump_loop"] + unless condenserLoops['heat_pump_loop'].nil? + heat_pump_loop = condenserLoops['heat_pump_loop'] end ### END CREATE NEW PLANTS - + ### START CREATE PRIMARY AIRLOOPS # populate inputs hash for create primary airloops method options = {} - options["zonesPrimary"] = zonesPrimary - options["primaryHVAC"] = primaryHVAC - options["zoneHVAC"] = zoneHVAC - if primaryHVAC["doas"] - options["hvac_schedule"] = building_ventilation_schedule - options["ventilation_schedule"] = building_ventilation_schedule + options['zonesPrimary'] = zonesPrimary + options['primaryHVAC'] = primaryHVAC + options['zoneHVAC'] = zoneHVAC + if primaryHVAC['doas'] + options['hvac_schedule'] = building_ventilation_schedule + options['ventilation_schedule'] = building_ventilation_schedule else # primary HVAC is multizone VAV - unless zoneHVAC == "DualDuct" - # primary system is multizone VAV that cools and ventilates - options["hvac_schedule"] = building_HVAC_schedule - options["ventilation_schedule"] = building_ventilation_schedule - else + if zoneHVAC == 'DualDuct' # primary system is a multizone VAV that cools only (primary system ventilation schedule is set to always off; hvac set to always on) - options["hvac_schedule"] = model.alwaysOnDiscreteSchedule() + options['hvac_schedule'] = model.alwaysOnDiscreteSchedule + else + # primary system is multizone VAV that cools and ventilates + options['hvac_schedule'] = building_HVAC_schedule + options['ventilation_schedule'] = building_ventilation_schedule end end - options["primary_sat_schedule"] = primary_SAT_schedule + options['primary_sat_schedule'] = primary_SAT_schedule if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end - primary_airloops = OsLib_HVAC.createPrimaryAirLoops(model, runner, options,doasFanType,doasERV,doasEvap,doasDXEER) + primary_airloops = OsLib_HVAC.createPrimaryAirLoops(model, runner, options, doasFanType, doasERV, doasEvap, doasDXEER) ### END CREATE PRIMARY AIRLOOPS - + ### START CREATE SECONDARY AIRLOOPS # populate inputs hash for create primary airloops method options = {} - options["zonesSecondary"] = zonesSecondary - options["secondaryHVAC"] = secondaryHVAC - options["hvac_schedule"] = building_HVAC_schedule - options["ventilation_schedule"] = building_ventilation_schedule + options['zonesSecondary'] = zonesSecondary + options['secondaryHVAC'] = secondaryHVAC + options['hvac_schedule'] = building_HVAC_schedule + options['ventilation_schedule'] = building_ventilation_schedule if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end secondary_airloops = OsLib_HVAC.createSecondaryAirLoops(model, runner, options) ### END CREATE SECONDARY AIRLOOPS - + ### START ASSIGN PLENUMS - options = {"zonesPrimary" => zonesPrimary,"zonesPlenum" => zonesPlenum} + options = { 'zonesPrimary' => zonesPrimary, 'zonesPlenum' => zonesPlenum } zone_plenum_hash = OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options) ### END ASSIGN PLENUMS - + ### START CREATE PRIMARY ZONE EQUIPMENT options = {} - options["zonesPrimary"] = zonesPrimary - options["zoneHVAC"] = zoneHVAC + options['zonesPrimary'] = zonesPrimary + options['zoneHVAC'] = zoneHVAC if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end - if zoneHVAC.include? "SHP" - options["heat_pump_loop"] = heat_pump_loop + if zoneHVAC.include? 'SHP' + options['heat_pump_loop'] = heat_pump_loop end - if zoneHVAC == "DualDuct" - options["ventilation_schedule"] = building_ventilation_schedule + if zoneHVAC == 'DualDuct' + options['ventilation_schedule'] = building_ventilation_schedule end - if zoneHVAC == "Radiant" - options["radiant_hot_water_plant"] = radiant_hot_water_plant - options["radiant_chilled_water_plant"] = radiant_chilled_water_plant - options["mean_radiant_heating_setpoint_schedule"] = mean_radiant_heating_setpoint_schedule - options["mean_radiant_cooling_setpoint_schedule"] = mean_radiant_cooling_setpoint_schedule + if zoneHVAC == 'Radiant' + options['radiant_hot_water_plant'] = radiant_hot_water_plant + options['radiant_chilled_water_plant'] = radiant_chilled_water_plant + options['mean_radiant_heating_setpoint_schedule'] = mean_radiant_heating_setpoint_schedule + options['mean_radiant_cooling_setpoint_schedule'] = mean_radiant_cooling_setpoint_schedule end - OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options,wshpCoolingEER, wshpHeatingCOP,wshpFanType) + OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options, wshpCoolingEER, wshpHeatingCOP, wshpFanType) ### END CREATE PRIMARY ZONE EQUIPMENT - + # START ADD DCV options = {} - unless zoneHVAC == "DualDuct" - options["primary_airloops"] = primary_airloops + unless zoneHVAC == 'DualDuct' + options['primary_airloops'] = primary_airloops end - options["secondary_airloops"] = secondary_airloops - options["allHVAC"] = allHVAC + options['secondary_airloops'] = secondary_airloops + options['allHVAC'] = allHVAC OsLib_HVAC.addDCV(model, runner, options) # END ADD DCV - - # todo - add in lifecycle costs + + # TODO: - add in lifecycle costs expected_life = 25 years_until_costs_start = 0 costHVAC = costTotalHVACSystem - lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("HVAC System", model.getBuilding, costHVAC, "CostPerEach", "Construction", expected_life, years_until_costs_start).get + lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost('HVAC System', model.getBuilding, costHVAC, 'CostPerEach', 'Construction', expected_life, years_until_costs_start).get # # add AEDG tips # aedgTips = ["HV04","HV10","HV12"] @@ -417,18 +417,16 @@ def run(model, runner, user_arguments) # # populate how to tip messages # aedgTipsLong = OsLib_AedgMeasures.getLongHowToTips("SmMdOff",aedgTips.uniq.sort,runner) # if not aedgTipsLong - # return false # this should only happen if measure writer passes bad values to getLongHowToTips + # return false # this should only happen if measure writer passes bad values to getLongHowToTips # end ### START REPORT FINAL CONDITIONS - OsLib_HVAC.reportConditions(model, runner, "final") + OsLib_HVAC.reportConditions(model, runner, 'final') ### END REPORT FINAL CONDITIONS return true + end # end the run method +end # end the measure - end #end the run method - -end #end the measure - -#this allows the measure to be used by the application -WSHPwithDOASMoreDesignParameters.new.registerWithApplication \ No newline at end of file +# this allows the measure to be used by the application +WSHPwithDOASMoreDesignParameters.new.registerWithApplication diff --git a/lib/measures/replace_simple_glazing/measure.rb b/lib/measures/replace_simple_glazing/measure.rb index 1e3d639..f6c90fe 100644 --- a/lib/measures/replace_simple_glazing/measure.rb +++ b/lib/measures/replace_simple_glazing/measure.rb @@ -1,12 +1,13 @@ +# frozen_string_literal: true + # see the URL below for information on how to write OpenStudio measures # http://nrel.github.io/OpenStudio-user-documentation/reference/measure_writing_guide/ # start the measure class ReplaceSimpleGlazing < OpenStudio::Ruleset::ModelUserScript - # human readable name def name - return "replace_simple_glazing" + return 'replace_simple_glazing' end # define the arguments that the user will input @@ -14,28 +15,28 @@ def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new # glazing u_value - u_value = OpenStudio::Ruleset::OSArgument.makeDoubleArgument("u_value", true) - u_value.setDisplayName("U-value in W/(K-m2)") - u_value.setDefaultValue(1.65) + u_value = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('u_value', true) + u_value.setDisplayName('U-value in W/(K-m2)') + u_value.setDefaultValue(1.65) args << u_value - - # glazing shgc - shgc = OpenStudio::Ruleset::OSArgument.makeDoubleArgument("shgc", true) - shgc.setDisplayName("shgc") - shgc.setDefaultValue(0.20) + + # glazing shgc + shgc = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('shgc', true) + shgc.setDisplayName('shgc') + shgc.setDefaultValue(0.20) args << shgc - - # glazing visible transmittance - vt = OpenStudio::Ruleset::OSArgument.makeDoubleArgument("vt", true) - vt.setDisplayName("vt") - vt.setDefaultValue(0.81) + + # glazing visible transmittance + vt = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('vt', true) + vt.setDisplayName('vt') + vt.setDefaultValue(0.81) args << vt return args end # define what happens when the measure is run - def run(model, runner, user_arguments) + def run(model, runner, user_arguments) super(model, runner, user_arguments) # use the built-in error checking @@ -43,45 +44,42 @@ def run(model, runner, user_arguments) return false end - #assign the user inputs to variables - u_value = runner.getDoubleArgumentValue("u_value",user_arguments) - shgc = runner.getDoubleArgumentValue("shgc",user_arguments) - vt = runner.getDoubleArgumentValue("vt",user_arguments) - - # replace simple glazing window parameters - materials = model.getMaterials - materials.each do |material| - if material.to_SimpleGlazing.is_initialized - material_type_glazingsimple = material.to_SimpleGlazing.get - - # get the original value for reporting - u_value_old = nil - shgc_old = nil - vt_old = nil - - u_value_old = material_type_glazingsimple.uFactor - shgc_old = material_type_glazingsimple.solarHeatGainCoefficient - vt_old = material_type_glazingsimple.visibleTransmittance - - # set values with user inputs - material_type_glazingsimple.setUFactor(u_value) - material_type_glazingsimple.setSolarHeatGainCoefficient(shgc) - material_type_glazingsimple.setVisibleTransmittance(vt) - - # report initial condition of model - runner.registerInitialCondition("The building started with #{u_value_old} U-value, #{shgc_old} SHGC, #{vt_old} Visible Transmittance.") - - # report final condition of model - runner.registerFinalCondition("The building finished with #{u_value} U-value, #{shgc} SHGC, #{vt} Visible Transmittance.") - - end - - end + # assign the user inputs to variables + u_value = runner.getDoubleArgumentValue('u_value', user_arguments) + shgc = runner.getDoubleArgumentValue('shgc', user_arguments) + vt = runner.getDoubleArgumentValue('vt', user_arguments) - return true + # replace simple glazing window parameters + materials = model.getMaterials + materials.each do |material| + if material.to_SimpleGlazing.is_initialized + material_type_glazingsimple = material.to_SimpleGlazing.get + + # get the original value for reporting + u_value_old = nil + shgc_old = nil + vt_old = nil + + u_value_old = material_type_glazingsimple.uFactor + shgc_old = material_type_glazingsimple.solarHeatGainCoefficient + vt_old = material_type_glazingsimple.visibleTransmittance + # set values with user inputs + material_type_glazingsimple.setUFactor(u_value) + material_type_glazingsimple.setSolarHeatGainCoefficient(shgc) + material_type_glazingsimple.setVisibleTransmittance(vt) + + # report initial condition of model + runner.registerInitialCondition("The building started with #{u_value_old} U-value, #{shgc_old} SHGC, #{vt_old} Visible Transmittance.") + + # report final condition of model + runner.registerFinalCondition("The building finished with #{u_value} U-value, #{shgc} SHGC, #{vt} Visible Transmittance.") + + end + end + + return true end - end # register the measure to be used by the application diff --git a/lib/measures/set_boiler_thermal_efficiency/measure.rb b/lib/measures/set_boiler_thermal_efficiency/measure.rb index eded8dc..3ac3c91 100644 --- a/lib/measures/set_boiler_thermal_efficiency/measure.rb +++ b/lib/measures/set_boiler_thermal_efficiency/measure.rb @@ -1,521 +1,520 @@ -#see the URL below for information on how to write OpenStudio measures +# frozen_string_literal: true + +# see the URL below for information on how to write OpenStudio measures # http://openstudio.nrel.gov/openstudio-measure-writing-guide -#see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) +# see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) # http://openstudio.nrel.gov/sites/openstudio.nrel.gov/files/nv_data/cpp_documentation_it/model/html/namespaces.html -#start the measure +# start the measure class SetBoilerThermalEfficiency < OpenStudio::Ruleset::ModelUserScript - - #define the name that a user will see, this method may be deprecated as - #the display name in PAT comes from the name field in measure.xml + # define the name that a user will see, this method may be deprecated as + # the display name in PAT comes from the name field in measure.xml def name - return "SetBoilerThermalEfficiency" + return 'SetBoilerThermalEfficiency' end - - #define the arguments that the user will input + + # define the arguments that the user will input def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new - - # Determine how many boilers in model - boiler_handles = OpenStudio::StringVector.new - boiler_display_names = OpenStudio::StringVector.new - - # Get/show all boiler units from current loaded model. - boiler_handles << '0' - boiler_display_names <<'*All boilers*' - - i_boiler = 1 - model.getBoilerHotWaters.each do |boiler_water| - if not boiler_water.to_BoilerHotWater.empty? - water_unit = boiler_water.to_BoilerHotWater.get - boiler_handles << i_boiler.to_s - boiler_display_names << water_unit.name.to_s - - i_boiler = i_boiler + 1 - end - end - model.getBoilerSteams.each do |boiler_steam| - if not boiler_steam.to_BoilerSteam.empty? - steam_unit = boiler_water.to_BoilerSteam.get - boiler_handles << i_boiler.to_s - boiler_display_names << steam_unit.name.to_s - i_boiler = i_boiler + 1 - end - end - - if i_boiler == 1 - info_widget = OpenStudio::Ruleset::OSArgument::makeBoolArgument("info_widget", true) - info_widget.setDisplayName("!!!!*** This Measure is not Applicable to loaded Model. Read the description and choose an appropriate baseline model. ***!!!!") - info_widget.setDefaultValue(true) - args << info_widget - return args - end - - boiler_widget = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("boiler_widget", boiler_handles, boiler_display_names,true) - boiler_widget.setDisplayName("Apply the measure to ") - boiler_widget.setDefaultValue(boiler_display_names[0]) - args << boiler_widget - - # Add a check box for specify thermal efficiency manually - input_option_manual = OpenStudio::Ruleset::OSArgument::makeBoolArgument("input_option_manual", false) - input_option_manual.setDisplayName("Option 1, set boiler nominal thermal efficiency to a user defined value") - input_option_manual.setDefaultValue(false) - args << input_option_manual - - # Boiler Thermal Efficiency (default of 0.8) - boiler_thermal_efficiency = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("boiler_thermal_efficiency") - boiler_thermal_efficiency.setDisplayName("Boiler nominal thermal efficiency (between 0 and 1)") - boiler_thermal_efficiency.setDefaultValue(0.8) - args << boiler_thermal_efficiency - - input_option_standard = OpenStudio::Ruleset::OSArgument::makeBoolArgument("input_option_standard", false) - input_option_standard.setDisplayName("Option 2, set boiler nominal thermal efficiency based on ASHRAE Standard 90.1 requirement") - input_option_standard.setDefaultValue(false) - args << input_option_standard - - # Nominal Capacity [W] (default of blank) - nominal_capacity = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("nominal_capacity", false) - nominal_capacity.setDisplayName("Boiler nominal capacity [W] ") - args << nominal_capacity - - # Show fuel type selection - fuel_type_handles = OpenStudio::StringVector.new - fuel_type_display_names = OpenStudio::StringVector.new - - fuel_type_handles << '0' - fuel_type_display_names << 'NaturalGas' - fuel_type_handles << '1' - fuel_type_display_names << 'FuelOil#1' - fuel_type_handles << '2' - fuel_type_display_names << 'FuelOil#2' - + + # Determine how many boilers in model + boiler_handles = OpenStudio::StringVector.new + boiler_display_names = OpenStudio::StringVector.new + + # Get/show all boiler units from current loaded model. + boiler_handles << '0' + boiler_display_names << '*All boilers*' + + i_boiler = 1 + model.getBoilerHotWaters.each do |boiler_water| + if !boiler_water.to_BoilerHotWater.empty? + water_unit = boiler_water.to_BoilerHotWater.get + boiler_handles << i_boiler.to_s + boiler_display_names << water_unit.name.to_s + + i_boiler += 1 + end + end + model.getBoilerSteams.each do |boiler_steam| + if !boiler_steam.to_BoilerSteam.empty? + steam_unit = boiler_water.to_BoilerSteam.get + boiler_handles << i_boiler.to_s + boiler_display_names << steam_unit.name.to_s + i_boiler += 1 + end + end + + if i_boiler == 1 + info_widget = OpenStudio::Ruleset::OSArgument.makeBoolArgument('info_widget', true) + info_widget.setDisplayName('!!!!*** This Measure is not Applicable to loaded Model. Read the description and choose an appropriate baseline model. ***!!!!') + info_widget.setDefaultValue(true) + args << info_widget + return args + end + + boiler_widget = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('boiler_widget', boiler_handles, boiler_display_names, true) + boiler_widget.setDisplayName('Apply the measure to ') + boiler_widget.setDefaultValue(boiler_display_names[0]) + args << boiler_widget + + # Add a check box for specify thermal efficiency manually + input_option_manual = OpenStudio::Ruleset::OSArgument.makeBoolArgument('input_option_manual', false) + input_option_manual.setDisplayName('Option 1, set boiler nominal thermal efficiency to a user defined value') + input_option_manual.setDefaultValue(false) + args << input_option_manual + + # Boiler Thermal Efficiency (default of 0.8) + boiler_thermal_efficiency = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('boiler_thermal_efficiency') + boiler_thermal_efficiency.setDisplayName('Boiler nominal thermal efficiency (between 0 and 1)') + boiler_thermal_efficiency.setDefaultValue(0.8) + args << boiler_thermal_efficiency + + input_option_standard = OpenStudio::Ruleset::OSArgument.makeBoolArgument('input_option_standard', false) + input_option_standard.setDisplayName('Option 2, set boiler nominal thermal efficiency based on ASHRAE Standard 90.1 requirement') + input_option_standard.setDefaultValue(false) + args << input_option_standard + + # Nominal Capacity [W] (default of blank) + nominal_capacity = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('nominal_capacity', false) + nominal_capacity.setDisplayName('Boiler nominal capacity [W] ') + args << nominal_capacity + + # Show fuel type selection + fuel_type_handles = OpenStudio::StringVector.new + fuel_type_display_names = OpenStudio::StringVector.new + + fuel_type_handles << '0' + fuel_type_display_names << 'NaturalGas' + fuel_type_handles << '1' + fuel_type_display_names << 'FuelOil#1' + fuel_type_handles << '2' + fuel_type_display_names << 'FuelOil#2' + # Make a choice argument for Boiler Fuel Type (default of NaturalGas) - fuel_type_widget = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("fuel_type_widget", fuel_type_handles, fuel_type_display_names,false) - fuel_type_widget.setDisplayName("Fuel type") - fuel_type_widget.setDefaultValue(fuel_type_display_names[0]) + fuel_type_widget = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('fuel_type_widget', fuel_type_handles, fuel_type_display_names, false) + fuel_type_widget.setDisplayName('Fuel type') + fuel_type_widget.setDefaultValue(fuel_type_display_names[0]) args << fuel_type_widget - - # Show ASHRAE standards - standards_handles = OpenStudio::StringVector.new - standards_display_names = OpenStudio::StringVector.new - - standards_handles << '0' - standards_handles << '1' - standards_handles << '2' - standards_handles << '3' - standards_handles << '4' - - standards_display_names << '' - standards_display_names << 'ASHRAE 90.1-2004' - standards_display_names << 'ASHRAE 90.1-2007' - standards_display_names << 'ASHRAE 90.1-2010' - standards_display_names << 'ASHRAE 90.1-2013' - - standards_widget = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("standards_widget", standards_handles, standards_display_names,false) - standards_widget.setDisplayName("ASHRAE Standards 90.1") - standards_widget.setDefaultValue(standards_display_names[0]) - args << standards_widget - + + # Show ASHRAE standards + standards_handles = OpenStudio::StringVector.new + standards_display_names = OpenStudio::StringVector.new + + standards_handles << '0' + standards_handles << '1' + standards_handles << '2' + standards_handles << '3' + standards_handles << '4' + + standards_display_names << '' + standards_display_names << 'ASHRAE 90.1-2004' + standards_display_names << 'ASHRAE 90.1-2007' + standards_display_names << 'ASHRAE 90.1-2010' + standards_display_names << 'ASHRAE 90.1-2013' + + standards_widget = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('standards_widget', standards_handles, standards_display_names, false) + standards_widget.setDisplayName('ASHRAE Standards 90.1') + standards_widget.setDefaultValue(standards_display_names[0]) + args << standards_widget + return args - end #end the arguments method + end # end the arguments method def getMinEfficiencyWaterBoiler(standard, capacity, heating_type) - min_efficiency = 0 - standard_list = ["ASHRAE 90.1-2004","ASHRAE 90.1-2007","ASHRAE 90.1-2010","ASHRAE 90.1-2013"] - heating_type_list = ["Gas","Oil"] - if (not standard_list.include? standard) || (not heating_type_list.include? heating_type) - return nil - end - - if standard == standard_list[0] - if heating_type == heating_type_list[0] - if capacity < 87862 - min_efficiency = 0.8 - elsif capacity < 732188 - min_efficiency = 0.75 - else - min_efficiency = 0.85 - end - else - if capacity < 87862 - min_efficiency = 0.8 - elsif capacity < 732188 - min_efficiency = 0.75 - else - min_efficiency = 0.7925 - end - end - elsif standard == standard_list[1] - if heating_type == heating_type_list[0] - if capacity < 87862 - min_efficiency = 0.8 - elsif capacity < 732188 - min_efficiency = 0.8 - else - min_efficiency = 0.8125 - end - else - if capacity < 87862 - min_efficiency = 0.8 - elsif capacity < 732188 - min_efficiency = 0.82 - else - min_efficiency = 0.8325 - end - end - elsif standard == standard_list[3] - if heating_type == heating_type_list[0] - if capacity < 87862 - min_efficiency = 0.8 - elsif capacity < 732188 - min_efficiency = 0.8 - else - min_efficiency = 0.8125 - end - else - if capacity < 87862 - min_efficiency = 0.8 - elsif capacity < 732188 - min_efficiency = 0.82 - else - min_efficiency = 0.8325 - end - end - elsif standard == standard_list[4] - if heating_type == heating_type_list[0] - if capacity < 87862 - min_efficiency = 0.82 - elsif capacity < 732188 - min_efficiency = 0.8 - else - min_efficiency = 0.8125 - end - else - if capacity < 87862 - min_efficiency = 0.84 - elsif capacity < 732188 - min_efficiency = 0.82 - else - min_efficiency = 0.8325 - end - end - end - - return min_efficiency - end - + min_efficiency = 0 + standard_list = ['ASHRAE 90.1-2004', 'ASHRAE 90.1-2007', 'ASHRAE 90.1-2010', 'ASHRAE 90.1-2013'] + heating_type_list = ['Gas', 'Oil'] + if (!standard_list.include? standard) || (!heating_type_list.include? heating_type) + return nil + end + + if standard == standard_list[0] + if heating_type == heating_type_list[0] + if capacity < 87862 + min_efficiency = 0.8 + elsif capacity < 732188 + min_efficiency = 0.75 + else + min_efficiency = 0.85 + end + else + if capacity < 87862 + min_efficiency = 0.8 + elsif capacity < 732188 + min_efficiency = 0.75 + else + min_efficiency = 0.7925 + end + end + elsif standard == standard_list[1] + if heating_type == heating_type_list[0] + if capacity < 87862 + min_efficiency = 0.8 + elsif capacity < 732188 + min_efficiency = 0.8 + else + min_efficiency = 0.8125 + end + else + if capacity < 87862 + min_efficiency = 0.8 + elsif capacity < 732188 + min_efficiency = 0.82 + else + min_efficiency = 0.8325 + end + end + elsif standard == standard_list[3] + if heating_type == heating_type_list[0] + if capacity < 87862 + min_efficiency = 0.8 + elsif capacity < 732188 + min_efficiency = 0.8 + else + min_efficiency = 0.8125 + end + else + if capacity < 87862 + min_efficiency = 0.8 + elsif capacity < 732188 + min_efficiency = 0.82 + else + min_efficiency = 0.8325 + end + end + elsif standard == standard_list[4] + if heating_type == heating_type_list[0] + if capacity < 87862 + min_efficiency = 0.82 + elsif capacity < 732188 + min_efficiency = 0.8 + else + min_efficiency = 0.8125 + end + else + if capacity < 87862 + min_efficiency = 0.84 + elsif capacity < 732188 + min_efficiency = 0.82 + else + min_efficiency = 0.8325 + end + end + end + + return min_efficiency + end + def getMinEfficiencySteamBoiler(standard, capacity, heating_type) - min_efficiency = 0 - standard_list = ["ASHRAE 90.1-2004","ASHRAE 90.1-2007","ASHRAE 90.1-2010","ASHRAE 90.1-2013"] - heating_type_list = ["Gas","Oil"] - if (not standard_list.include? standard) || (not heating_type_list.include? heating_type) - return nil - end - - if standard == standard_list[0] - if heating_type == heating_type_list[0] - if capacity < 87862 - min_efficiency = 0.75 - elsif capacity < 732188 - min_efficiency = 0.75 - else - min_efficiency = 0.7925 - end - else - if capacity < 87862 - min_efficiency = 0.8 - elsif capacity < 732188 - min_efficiency = 0.75 - else - min_efficiency = 0.7925 - end - end - elsif standard == standard_list[1] - if heating_type == heating_type_list[0] - if capacity < 87862 - min_efficiency = 0.75 - elsif capacity < 732188 - min_efficiency = 0.79 - else - min_efficiency = 0.79 - end - else - if capacity < 87862 - min_efficiency = 0.8 - elsif capacity < 732188 - min_efficiency = 0.81 - else - min_efficiency = 0.81 - end - end - elsif standard == standard_list[3] - if heating_type == heating_type_list[0] - if capacity < 87862 - min_efficiency = 0.75 - elsif capacity < 732188 - min_efficiency = 0.79 - else - min_efficiency = 0.79 - end - else - if capacity < 87862 - min_efficiency = 0.8 - elsif capacity < 732188 - min_efficiency = 0.81 - else - min_efficiency = 0.81 - end - end - else standard == standard_list[4] - if heating_type == heating_type_list[0] - if capacity < 87862 - min_efficiency = 0.8 - elsif capacity < 732188 - min_efficiency = 0.79 - else - min_efficiency = 0.79 - end - else - if capacity < 87862 - min_efficiency = 0.82 - elsif capacity < 732188 - min_efficiency = 0.81 - else - min_efficiency = 0.81 - min_efficiency = 0.81 - end - end - end - - return min_efficiency - end - + min_efficiency = 0 + standard_list = ['ASHRAE 90.1-2004', 'ASHRAE 90.1-2007', 'ASHRAE 90.1-2010', 'ASHRAE 90.1-2013'] + heating_type_list = ['Gas', 'Oil'] + if (!standard_list.include? standard) || (!heating_type_list.include? heating_type) + return nil + end + + if standard == standard_list[0] + if heating_type == heating_type_list[0] + if capacity < 87862 + min_efficiency = 0.75 + elsif capacity < 732188 + min_efficiency = 0.75 + else + min_efficiency = 0.7925 + end + else + if capacity < 87862 + min_efficiency = 0.8 + elsif capacity < 732188 + min_efficiency = 0.75 + else + min_efficiency = 0.7925 + end + end + elsif standard == standard_list[1] + if heating_type == heating_type_list[0] + if capacity < 87862 + min_efficiency = 0.75 + elsif capacity < 732188 + min_efficiency = 0.79 + else + min_efficiency = 0.79 + end + else + if capacity < 87862 + min_efficiency = 0.8 + elsif capacity < 732188 + min_efficiency = 0.81 + else + min_efficiency = 0.81 + end + end + elsif standard == standard_list[3] + if heating_type == heating_type_list[0] + if capacity < 87862 + min_efficiency = 0.75 + elsif capacity < 732188 + min_efficiency = 0.79 + else + min_efficiency = 0.79 + end + else + if capacity < 87862 + min_efficiency = 0.8 + elsif capacity < 732188 + min_efficiency = 0.81 + else + min_efficiency = 0.81 + end + end + else standard == standard_list[4] + if heating_type == heating_type_list[0] + if capacity < 87862 + min_efficiency = 0.8 + elsif capacity < 732188 + min_efficiency = 0.79 + else + min_efficiency = 0.79 + end + else + if capacity < 87862 + min_efficiency = 0.82 + elsif capacity < 732188 + min_efficiency = 0.81 + else + min_efficiency = 0.81 + min_efficiency = 0.81 + end + end + end + + return min_efficiency + end + def changeThermalEfficiency(model, boiler_index, efficiency_value_new, runner) - i_boiler = 0 - #loop through to find water boiler - model.getBoilerHotWaters.each do |boiler_water| - if not boiler_water.to_BoilerHotWater.empty? - i_boiler = i_boiler + 1 - if boiler_index != 0 and (boiler_index != i_boiler) - next - end - - water_unit = boiler_water.to_BoilerHotWater.get - unit_name = water_unit.name - - # check capacity, fuel type, and thermal efficiency - thermal_efficiency_old = water_unit.nominalThermalEfficiency() - - #if thermal_efficiency_old.nil? - if not thermal_efficiency_old.is_a? Numeric - runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was not set.") - else - runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was not set.") - end - - water_unit.setNominalThermalEfficiency(efficiency_value_new) - runner.registerInfo("Final: The Thermal Efficiency for '#{unit_name}' was #{efficiency_value_new}") - end - end - - #loop through to find steam boiler - model.getBoilerSteams.each do |boiler_steam| - if not boiler_steam.to_BoilerSteam.empty? - i_boiler = i_boiler + 1 - if boiler_index != 0 and (boiler_index != i_boiler) - next - end - - steam_unit = boiler.to_BoilerSteam.get - steam_unit_fueltype = steam_unit.fuelType - unit_name = steam_unit.name - - thermal_efficiency_old = steam_unit.theoreticalEfficiency() - - if not thermal_efficiency_old.is_a? Numeric - runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was not set.") - else - runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was #{efficiency_value_new}.") - end - - steam_unit.setNominalThermalEfficiency(efficiency_value_new) - runner.registerInfo("Final: The Thermal Efficiency for '#{unit_name}' was #{efficiency_value_new}") - end - end + i_boiler = 0 + # loop through to find water boiler + model.getBoilerHotWaters.each do |boiler_water| + if !boiler_water.to_BoilerHotWater.empty? + i_boiler += 1 + if (boiler_index != 0) && (boiler_index != i_boiler) + next + end + + water_unit = boiler_water.to_BoilerHotWater.get + unit_name = water_unit.name + + # check capacity, fuel type, and thermal efficiency + thermal_efficiency_old = water_unit.nominalThermalEfficiency + + # if thermal_efficiency_old.nil? + if !thermal_efficiency_old.is_a? Numeric + runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was not set.") + else + runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was not set.") + end + + water_unit.setNominalThermalEfficiency(efficiency_value_new) + runner.registerInfo("Final: The Thermal Efficiency for '#{unit_name}' was #{efficiency_value_new}") + end + end + + # loop through to find steam boiler + model.getBoilerSteams.each do |boiler_steam| + if !boiler_steam.to_BoilerSteam.empty? + i_boiler += 1 + if (boiler_index != 0) && (boiler_index != i_boiler) + next + end + + steam_unit = boiler.to_BoilerSteam.get + steam_unit_fueltype = steam_unit.fuelType + unit_name = steam_unit.name + + thermal_efficiency_old = steam_unit.theoreticalEfficiency + + if !thermal_efficiency_old.is_a? Numeric + runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was not set.") + else + runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was #{efficiency_value_new}.") + end + + steam_unit.setNominalThermalEfficiency(efficiency_value_new) + runner.registerInfo("Final: The Thermal Efficiency for '#{unit_name}' was #{efficiency_value_new}") + end + end end - + def changeThermalEfficiencyByStandard(model, boiler_index, efficiency_value_water, efficiency_value_steam, nominal_capacity, fuel_type, runner) - i_boiler = 0 - #loop through to find water boiler - model.getBoilerHotWaters.each do |boiler_water| - if not boiler_water.to_BoilerHotWater.empty? - i_boiler = i_boiler + 1 - if boiler_index != 0 and (boiler_index != i_boiler) - next - end - - water_unit = boiler_water.to_BoilerHotWater.get - unit_name = water_unit.name - - # check capacity, fuel type, and thermal efficiency - thermal_efficiency_old = water_unit.nominalThermalEfficiency() - - #if thermal_efficiency_old.nil? - if not thermal_efficiency_old.is_a? Numeric - runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was not set.") - else - runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was not set.") - end - - water_unit.setNominalThermalEfficiency(efficiency_value_water) - runner.registerInfo("Final: The Thermal Efficiency for '#{unit_name}' was #{efficiency_value_water}") - - # In case there is information about capacity and fuel_type - if not nominal_capacity.nil? - water_unit.setFuelType(fuel_type) - - nominal_capacity_old = water_unit.nominalCapacity() - if not nominal_capacity_old.is_a? Numeric - runner.registerInfo("Initial: The Nominal Capacity for '#{unit_name}' was not set.") - else - runner.registerInfo("Initial: The Nominal Capacity for '#{unit_name}' was #{nominal_capacity_old}.") - end - water_unit.setNominalCapacity(nominal_capacity) - runner.registerInfo("Final: The Nominal Capacity for '#{unit_name}' was #{nominal_capacity}") - end - end - end - - #loop through to find steam boiler - model.getBoilerSteams.each do |boiler_steam| - if not boiler_steam.to_BoilerSteam.empty? - i_boiler = i_boiler + 1 - if boiler_index != 0 and (boiler_index != i_boiler) - next - end - - steam_unit = boiler.to_BoilerSteam.get - steam_unit_fueltype = steam_unit.fuelType - unit_name = steam_unit.name - - thermal_efficiency_old = steam_unit.theoreticalEfficiency() - - if not thermal_efficiency_old.is_a? Numeric - runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was not set.") - else - runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was #{thermal_efficiency_old}.") - end - - steam_unit.setNominalThermalEfficiency(efficiency_value_steam) - runner.registerInfo("Final: The Thermal Efficiency for '#{unit_name}' was #{efficiency_value_steam}") - - # In case there is information about capacity and fuel_type - if not nominal_capacity.nil? - steam_unit.setFuelType(fuel) - - nominal_capacity_old = steam_unit.nominalCapacity() - if not nominal_capacity_old.is_a? Numeric - runner.registerInfo("Initial: The Nominal Capacity for '#{unit_name}' was not set.") - else - runner.registerInfo("Initial: The Nominal Capacity for '#{unit_name}' was #{nominal_capacity_old}.") - end - steam_unit.setNominalCapacity(nominal_capacity) - runner.registerInfo("Final: The Nominal Capacity for '#{unit_name}' was #{nominal_capacity}") - end - end - end + i_boiler = 0 + # loop through to find water boiler + model.getBoilerHotWaters.each do |boiler_water| + if !boiler_water.to_BoilerHotWater.empty? + i_boiler += 1 + if (boiler_index != 0) && (boiler_index != i_boiler) + next + end + + water_unit = boiler_water.to_BoilerHotWater.get + unit_name = water_unit.name + + # check capacity, fuel type, and thermal efficiency + thermal_efficiency_old = water_unit.nominalThermalEfficiency + + # if thermal_efficiency_old.nil? + if !thermal_efficiency_old.is_a? Numeric + runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was not set.") + else + runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was not set.") + end + + water_unit.setNominalThermalEfficiency(efficiency_value_water) + runner.registerInfo("Final: The Thermal Efficiency for '#{unit_name}' was #{efficiency_value_water}") + + # In case there is information about capacity and fuel_type + if !nominal_capacity.nil? + water_unit.setFuelType(fuel_type) + + nominal_capacity_old = water_unit.nominalCapacity + if !nominal_capacity_old.is_a? Numeric + runner.registerInfo("Initial: The Nominal Capacity for '#{unit_name}' was not set.") + else + runner.registerInfo("Initial: The Nominal Capacity for '#{unit_name}' was #{nominal_capacity_old}.") + end + water_unit.setNominalCapacity(nominal_capacity) + runner.registerInfo("Final: The Nominal Capacity for '#{unit_name}' was #{nominal_capacity}") + end + end + end + + # loop through to find steam boiler + model.getBoilerSteams.each do |boiler_steam| + if !boiler_steam.to_BoilerSteam.empty? + i_boiler += 1 + if (boiler_index != 0) && (boiler_index != i_boiler) + next + end + + steam_unit = boiler.to_BoilerSteam.get + steam_unit_fueltype = steam_unit.fuelType + unit_name = steam_unit.name + + thermal_efficiency_old = steam_unit.theoreticalEfficiency + + if !thermal_efficiency_old.is_a? Numeric + runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was not set.") + else + runner.registerInfo("Initial: The Thermal Efficiency for '#{unit_name}' was #{thermal_efficiency_old}.") + end + + steam_unit.setNominalThermalEfficiency(efficiency_value_steam) + runner.registerInfo("Final: The Thermal Efficiency for '#{unit_name}' was #{efficiency_value_steam}") + + # In case there is information about capacity and fuel_type + if !nominal_capacity.nil? + steam_unit.setFuelType(fuel) + + nominal_capacity_old = steam_unit.nominalCapacity + if !nominal_capacity_old.is_a? Numeric + runner.registerInfo("Initial: The Nominal Capacity for '#{unit_name}' was not set.") + else + runner.registerInfo("Initial: The Nominal Capacity for '#{unit_name}' was #{nominal_capacity_old}.") + end + steam_unit.setNominalCapacity(nominal_capacity) + runner.registerInfo("Final: The Nominal Capacity for '#{unit_name}' was #{nominal_capacity}") + end + end + end end - - #define what happens when the measure is run + + # define what happens when the measure is run def run(model, runner, user_arguments) super(model, runner, user_arguments) - - #use the built-in error checking - if not runner.validateUserArguments(arguments(model), user_arguments) + + # use the built-in error checking + if !runner.validateUserArguments(arguments(model), user_arguments) return false end - # Determine if the measure is applicable to the model, if not just return and no changes are made. - info_widget = runner.getOptionalWorkspaceObjectChoiceValue("info_widget",user_arguments,model) - if not (info_widget.nil? or info_widget.empty?) - runner.registerInfo("This measure is not applicable.") - return true - end - - #assign the user inputs to variables - boiler_widget = runner.getOptionalWorkspaceObjectChoiceValue("boiler_widget",user_arguments,model) - standards_widget = runner.getOptionalWorkspaceObjectChoiceValue("standards_widget",user_arguments,model) - nominal_capacity_method_widget = runner.getOptionalWorkspaceObjectChoiceValue("nominal_capacity_method_widget",user_arguments,model) - fuel_type_widget = runner.getOptionalWorkspaceObjectChoiceValue("fuel_type_widget",user_arguments,model) - - handle = runner.getStringArgumentValue("boiler_widget",user_arguments) - boiler_index = handle.to_i - - #check which method is used, if both are checked used the first one - is_option_manual = runner.getBoolArgumentValue("input_option_manual",user_arguments) - is_option_standard = runner.getBoolArgumentValue("input_option_standard",user_arguments) - - if is_option_manual - boiler_thermal_efficiency = runner.getDoubleArgumentValue("boiler_thermal_efficiency",user_arguments) - - # Check if input is valid - if boiler_thermal_efficiency < 0 or boiler_thermal_efficiency > 1 - runner.registerError("Boiler Thermal Efficiency must be between 0 and 1.") - return false - end - - changeThermalEfficiency(model, boiler_index, boiler_thermal_efficiency, runner) - elsif is_option_standard - handle = runner.getStringArgumentValue("standards_widget",user_arguments) - standards_index = handle.to_i - - handle = runner.getStringArgumentValue("fuel_type_widget",user_arguments) - fuel_type_index = handle.to_i - - standard_table = ["","ASHRAE 90.1-2004","ASHRAE 90.1-2007","ASHRAE 90.1-2010","ASHRAE 90.1-2013"] - fuel_table = ["Gas","Oil","Oil"] - fuel_formal_name = ['NaturalGas', 'FuelOil#1', 'FuelOil#2'] - fuel_type = fuel_formal_name[fuel_type_index] - - nominal_capacity = runner.getOptionalDoubleArgumentValue("nominal_capacity",user_arguments) - if nominal_capacity.empty? - runner.registerError("Nominal capacity is not specified.") - return false - else - nominal_capacity = runner.getDoubleArgumentValue("nominal_capacity",user_arguments) - end - # Check if the required inputs - if not nominal_capacity.is_a? Numeric - runner.registerError("'Nominal Capacity' is not specified but required for ASHRAE Standards.") - elsif (nominal_capacity < 0) - runner.registerError("'Nominal Capacity' can not be negative.") - #elsif (nominal_capacity < 87862) or (nominal_capacity > 732188) then - # runner.registerError("'Nominal Capacity' should be between 87.862kW and 732.188kW.") - end - - if standards_index <= 0 - runner.registerError("ASHRAE 90.1 standard is not specified.") - return false - else - runner.registerInfo("Final: ASHRAE Standards #{standard_table[standards_index]} is selected.") - end - - water_unit_min_efficiency = getMinEfficiencyWaterBoiler(standard_table[standards_index],nominal_capacity, fuel_table[fuel_type_index]) - steam_unit_min_efficiency = getMinEfficiencySteamBoiler(standard_table[standards_index],nominal_capacity, fuel_table[fuel_type_index]) - - changeThermalEfficiencyByStandard(model, boiler_index, water_unit_min_efficiency, steam_unit_min_efficiency, nominal_capacity, fuel_type, runner) - - else - runner.registerError("You have to specify using either Option 1 or Option 2.") - return false - end - - return true - - end #end the run method + # Determine if the measure is applicable to the model, if not just return and no changes are made. + info_widget = runner.getOptionalWorkspaceObjectChoiceValue('info_widget', user_arguments, model) + if !(info_widget.nil? || info_widget.empty?) + runner.registerInfo('This measure is not applicable.') + return true + end + + # assign the user inputs to variables + boiler_widget = runner.getOptionalWorkspaceObjectChoiceValue('boiler_widget', user_arguments, model) + standards_widget = runner.getOptionalWorkspaceObjectChoiceValue('standards_widget', user_arguments, model) + nominal_capacity_method_widget = runner.getOptionalWorkspaceObjectChoiceValue('nominal_capacity_method_widget', user_arguments, model) + fuel_type_widget = runner.getOptionalWorkspaceObjectChoiceValue('fuel_type_widget', user_arguments, model) + + handle = runner.getStringArgumentValue('boiler_widget', user_arguments) + boiler_index = handle.to_i + + # check which method is used, if both are checked used the first one + is_option_manual = runner.getBoolArgumentValue('input_option_manual', user_arguments) + is_option_standard = runner.getBoolArgumentValue('input_option_standard', user_arguments) + + if is_option_manual + boiler_thermal_efficiency = runner.getDoubleArgumentValue('boiler_thermal_efficiency', user_arguments) + + # Check if input is valid + if (boiler_thermal_efficiency < 0) || (boiler_thermal_efficiency > 1) + runner.registerError('Boiler Thermal Efficiency must be between 0 and 1.') + return false + end + + changeThermalEfficiency(model, boiler_index, boiler_thermal_efficiency, runner) + elsif is_option_standard + handle = runner.getStringArgumentValue('standards_widget', user_arguments) + standards_index = handle.to_i -end #end the measure + handle = runner.getStringArgumentValue('fuel_type_widget', user_arguments) + fuel_type_index = handle.to_i + + standard_table = ['', 'ASHRAE 90.1-2004', 'ASHRAE 90.1-2007', 'ASHRAE 90.1-2010', 'ASHRAE 90.1-2013'] + fuel_table = ['Gas', 'Oil', 'Oil'] + fuel_formal_name = ['NaturalGas', 'FuelOil#1', 'FuelOil#2'] + fuel_type = fuel_formal_name[fuel_type_index] + + nominal_capacity = runner.getOptionalDoubleArgumentValue('nominal_capacity', user_arguments) + if nominal_capacity.empty? + runner.registerError('Nominal capacity is not specified.') + return false + else + nominal_capacity = runner.getDoubleArgumentValue('nominal_capacity', user_arguments) + end + # Check if the required inputs + if !nominal_capacity.is_a? Numeric + runner.registerError("'Nominal Capacity' is not specified but required for ASHRAE Standards.") + elsif nominal_capacity < 0 + runner.registerError("'Nominal Capacity' can not be negative.") + # elsif (nominal_capacity < 87862) or (nominal_capacity > 732188) then + # runner.registerError("'Nominal Capacity' should be between 87.862kW and 732.188kW.") + end + + if standards_index <= 0 + runner.registerError('ASHRAE 90.1 standard is not specified.') + return false + else + runner.registerInfo("Final: ASHRAE Standards #{standard_table[standards_index]} is selected.") + end + + water_unit_min_efficiency = getMinEfficiencyWaterBoiler(standard_table[standards_index], nominal_capacity, fuel_table[fuel_type_index]) + steam_unit_min_efficiency = getMinEfficiencySteamBoiler(standard_table[standards_index], nominal_capacity, fuel_table[fuel_type_index]) + + changeThermalEfficiencyByStandard(model, boiler_index, water_unit_min_efficiency, steam_unit_min_efficiency, nominal_capacity, fuel_type, runner) + + else + runner.registerError('You have to specify using either Option 1 or Option 2.') + return false + end + + return true + end # end the run method +end # end the measure -#this allows the measure to be use by the application -SetBoilerThermalEfficiency.new.registerWithApplication \ No newline at end of file +# this allows the measure to be use by the application +SetBoilerThermalEfficiency.new.registerWithApplication diff --git a/lib/measures/set_boiler_thermal_efficiency/tests/SetBoilerThermalEfficiency_Test.rb b/lib/measures/set_boiler_thermal_efficiency/tests/SetBoilerThermalEfficiency_Test.rb index d5c1c2a..f49c8e9 100644 --- a/lib/measures/set_boiler_thermal_efficiency/tests/SetBoilerThermalEfficiency_Test.rb +++ b/lib/measures/set_boiler_thermal_efficiency/tests/SetBoilerThermalEfficiency_Test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'openstudio' require 'openstudio/ruleset/ShowRunnerOutput' @@ -6,55 +8,51 @@ require 'test/unit' class SetBoilerThermalEfficiency_Test < Test::Unit::TestCase - # def setup # end # def teardown # end - + def test_SetBoilerThermalEfficiency - # create an instance of the measure measure = SetBoilerThermalEfficiency.new - + # create an instance of a runner runner = OpenStudio::Ruleset::OSRunner.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(2, arguments.size) - assert_equal("user_name", arguments[0].name) - assert_equal("add_space", arguments[1].name) - assert((not arguments[0].hasDefaultValue)) + assert_equal('user_name', arguments[0].name) + assert_equal('add_space', arguments[1].name) + assert(!arguments[0].hasDefaultValue) # set argument values to bad values and run the measure argument_map = OpenStudio::Ruleset::OSArgumentMap.new user_name = arguments[0].clone - assert(user_name.setValue("")) - argument_map["user_name"] = user_name + assert(user_name.setValue('')) + argument_map['user_name'] = user_name measure.run(model, runner, argument_map) result = runner.result - assert(result.value.valueName == "Fail") - + assert(result.value.valueName == 'Fail') + # set argument values to good values and run the measure on model with spaces argument_map = OpenStudio::Ruleset::OSArgumentMap.new user_name = arguments[0].clone - assert(user_name.setValue("david")) - argument_map["user_name"] = user_name + assert(user_name.setValue('david')) + argument_map['user_name'] = user_name add_space = arguments[1].clone assert(add_space.setValue(true)) - argument_map["add_space"] = add_space + argument_map['add_space'] = add_space measure.run(model, runner, argument_map) result = runner.result show_output(result) - assert(result.value.valueName == "Success") + assert(result.value.valueName == 'Success') assert(result.warnings.size == 1) assert(result.info.size == 2) - - end - + end end diff --git a/lib/measures/set_water_heater_efficiency_heat_lossand_peak_water_flow_rate/measure.rb b/lib/measures/set_water_heater_efficiency_heat_lossand_peak_water_flow_rate/measure.rb index 767f130..9bc9d1a 100644 --- a/lib/measures/set_water_heater_efficiency_heat_lossand_peak_water_flow_rate/measure.rb +++ b/lib/measures/set_water_heater_efficiency_heat_lossand_peak_water_flow_rate/measure.rb @@ -1,208 +1,207 @@ -#see the URL below for information on how to write OpenStudio measures +# frozen_string_literal: true + +# see the URL below for information on how to write OpenStudio measures # http://openstudio.nrel.gov/openstudio-measure-writing-guide -#see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) +# see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) # http://openstudio.nrel.gov/sites/openstudio.nrel.gov/files/nv_data/cpp_documentation_it/model/html/namespaces.html -#start the measure +# start the measure class SetWaterHeaterEfficiencyHeatLossandPeakWaterFlowRate < OpenStudio::Ruleset::ModelUserScript - - #define the name that a user will see, this method may be deprecated as - #the display name in PAT comes from the name field in measure.xml + # define the name that a user will see, this method may be deprecated as + # the display name in PAT comes from the name field in measure.xml def name - return "SetWaterHeaterEfficiencyHeatLossandPeakWaterFlowRate" + return 'SetWaterHeaterEfficiencyHeatLossandPeakWaterFlowRate' end - - #define the arguments that the user will input + + # define the arguments that the user will input def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new - - # Determine how many air loops in model - waterheater_handles = OpenStudio::StringVector.new - waterheater_display_names = OpenStudio::StringVector.new - - # Get/show all airloop_hvac which has VAV terminal units from current loaded model. - waterheater_handles << '0' - waterheater_display_names <<'*All service water heaters*' - - water_heaters = model.getWaterHeaterMixeds - i_water_heater = 1 - water_heaters.each do |water_heater| - waterheater_handles << i_water_heater.to_s - waterheater_display_names << water_heater.name.to_s - - i_water_heater = i_water_heater + 1 - end - - if i_water_heater == 1 - info_widget = OpenStudio::Ruleset::OSArgument::makeBoolArgument("info_widget", true) - info_widget.setDisplayName("!!!!*** This Measure is not Applicable to loaded Model. Read the description and choose an appropriate baseline model. ***!!!!") - info_widget.setDefaultValue(true) - args << info_widget - return args - end - - waterheater_widget = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("waterheater_widget", waterheater_handles, waterheater_display_names,true) - waterheater_widget.setDisplayName("Apply the measure to") - waterheater_widget.setDefaultValue(waterheater_display_names[0]) - args << waterheater_widget - - #make a choice argument for economizer control type - heater_fuel_type_handles = OpenStudio::StringVector.new - heater_fuel_type_display_names = OpenStudio::StringVector.new - - fuel_type_array = ["NaturalGas","Electricity","PropaneGas","FuelOil#1","FuelOil#2",\ - "Coal","Diesel","Gasoline","OtherFuel1","OtherFuel2","Steam","DistrictHeating"] - - for i in 0..fuel_type_array.size-1 - heater_fuel_type_handles << i.to_s - heater_fuel_type_display_names << fuel_type_array[i] - end - - #make a choice argument for economizer control type - heater_fuel_type_widget = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("heater_fuel_type_widget", heater_fuel_type_handles, heater_fuel_type_display_names,true) - heater_fuel_type_widget.setDisplayName("Fuel type") - heater_fuel_type_widget.setDefaultValue(heater_fuel_type_display_names[0]) + + # Determine how many air loops in model + waterheater_handles = OpenStudio::StringVector.new + waterheater_display_names = OpenStudio::StringVector.new + + # Get/show all airloop_hvac which has VAV terminal units from current loaded model. + waterheater_handles << '0' + waterheater_display_names << '*All service water heaters*' + + water_heaters = model.getWaterHeaterMixeds + i_water_heater = 1 + water_heaters.each do |water_heater| + waterheater_handles << i_water_heater.to_s + waterheater_display_names << water_heater.name.to_s + + i_water_heater += 1 + end + + if i_water_heater == 1 + info_widget = OpenStudio::Ruleset::OSArgument.makeBoolArgument('info_widget', true) + info_widget.setDisplayName('!!!!*** This Measure is not Applicable to loaded Model. Read the description and choose an appropriate baseline model. ***!!!!') + info_widget.setDefaultValue(true) + args << info_widget + return args + end + + waterheater_widget = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('waterheater_widget', waterheater_handles, waterheater_display_names, true) + waterheater_widget.setDisplayName('Apply the measure to') + waterheater_widget.setDefaultValue(waterheater_display_names[0]) + args << waterheater_widget + + # make a choice argument for economizer control type + heater_fuel_type_handles = OpenStudio::StringVector.new + heater_fuel_type_display_names = OpenStudio::StringVector.new + + fuel_type_array = ['NaturalGas', 'Electricity', 'PropaneGas', 'FuelOil#1', 'FuelOil#2',\ + 'Coal', 'Diesel', 'Gasoline', 'OtherFuel1', 'OtherFuel2', 'Steam', 'DistrictHeating'] + + for i in 0..fuel_type_array.size - 1 + heater_fuel_type_handles << i.to_s + heater_fuel_type_display_names << fuel_type_array[i] + end + + # make a choice argument for economizer control type + heater_fuel_type_widget = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('heater_fuel_type_widget', heater_fuel_type_handles, heater_fuel_type_display_names, true) + heater_fuel_type_widget.setDisplayName('Fuel type') + heater_fuel_type_widget.setDefaultValue(heater_fuel_type_display_names[0]) args << heater_fuel_type_widget - #make an argument for heater Thermal Efficiency (default of 0.8) - heater_thermal_efficiency = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("heater_thermal_efficiency", true) - heater_thermal_efficiency.setDisplayName("Thermal efficiency [between 0 and 1]") + # make an argument for heater Thermal Efficiency (default of 0.8) + heater_thermal_efficiency = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('heater_thermal_efficiency', true) + heater_thermal_efficiency.setDisplayName('Thermal efficiency [between 0 and 1]') heater_thermal_efficiency.setDefaultValue(0.8) args << heater_thermal_efficiency - - #make an argument for On/Off Cycle Loss Coefficient to Ambient Temperature [W/K] [W/K] (default of 0.0) - onoff_cycle_loss_coefficient_to_ambient_temperature = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("onoff_cycle_loss_coefficient_to_ambient_temperature", false) - onoff_cycle_loss_coefficient_to_ambient_temperature.setDisplayName("Loss coefficient to ambient temperature [W/K] (optional input, baseline value will be used if empty)") + + # make an argument for On/Off Cycle Loss Coefficient to Ambient Temperature [W/K] [W/K] (default of 0.0) + onoff_cycle_loss_coefficient_to_ambient_temperature = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('onoff_cycle_loss_coefficient_to_ambient_temperature', false) + onoff_cycle_loss_coefficient_to_ambient_temperature.setDisplayName('Loss coefficient to ambient temperature [W/K] (optional input, baseline value will be used if empty)') onoff_cycle_loss_coefficient_to_ambient_temperature.setDefaultValue(0.0) args << onoff_cycle_loss_coefficient_to_ambient_temperature - #make an argument for Peak Use Flow Rate [m3/s] (No default, thus to be blank) - peak_use_flow_rate = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("peak_use_flow_rate",false) - peak_use_flow_rate.setDisplayName("Peak water use flow rate [m3/s] (optional input, baseline value will be used if empty)") - peak_use_flow_rate.setDefaultValue(0.000379) + # make an argument for Peak Use Flow Rate [m3/s] (No default, thus to be blank) + peak_use_flow_rate = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('peak_use_flow_rate', false) + peak_use_flow_rate.setDisplayName('Peak water use flow rate [m3/s] (optional input, baseline value will be used if empty)') + peak_use_flow_rate.setDefaultValue(0.000379) args << peak_use_flow_rate - + return args - end #end the arguments method + end # end the arguments method - #define what happens when the measure is run + # define what happens when the measure is run def run(model, runner, user_arguments) super(model, runner, user_arguments) - - #use the built-in error checking - if not runner.validateUserArguments(arguments(model), user_arguments) + + # use the built-in error checking + if !runner.validateUserArguments(arguments(model), user_arguments) return false end - - # Determine if the measure is applicable to the model, if not just return and no changes are made. - info_widget = runner.getOptionalWorkspaceObjectChoiceValue("info_widget",user_arguments,model) - if not (info_widget.nil? or info_widget.empty?) - runner.registerInfo("This measure is not applicable.") - return true - end - - #assign the user inputs to variables - waterheater_widget = runner.getOptionalWorkspaceObjectChoiceValue("waterheater_widget",user_arguments,model) - heater_fuel_type_widget = runner.getOptionalWorkspaceObjectChoiceValue("heater_fuel_type_widget",user_arguments,model) - - handle = runner.getStringArgumentValue("waterheater_widget",user_arguments) - waterheater_index = handle.to_i - - fuel_type_array = ['NaturalGas','Electricity','PropaneGas','FuelOil#1','FuelOil#2',\ - 'Coal','Diesel','Gasoline','OtherFuel1','OtherFuel2','Steam','DistrictHeating'] - - handle = runner.getStringArgumentValue("heater_fuel_type_widget",user_arguments) - heater_fuel_type = handle.to_i - heater_fuel = fuel_type_array[heater_fuel_type] - - heater_thermal_efficiency = runner.getDoubleArgumentValue("heater_thermal_efficiency",user_arguments) - onoff_cycle_loss_coefficient_to_ambient_temperature = runner.getDoubleArgumentValue("onoff_cycle_loss_coefficient_to_ambient_temperature",user_arguments) - - peak_use_flow_rate = runner.getDoubleArgumentValue("peak_use_flow_rate",user_arguments) - - if heater_thermal_efficiency <= 0 - runner.registerError("Enter a value greater than zero for the 'Heater Thermal Efficiency'.") - elsif heater_thermal_efficiency > 1.0 - runner.registerError("Enter a value less than or equal to 1.0 for the 'HeaterThermal Efficiency'.") - end - - #if not onoff_cycle_loss_coefficient_to_ambient_temperature.empty? - # if onoff_cycle_loss_coefficient_to_ambient_temperature < 0 - # runner.registerError("Enter a value greater than or equal to zero for the 'On/Off Cycle Loss Coefficient to Ambient Temperature'.") - # return false - # elsif onoff_cycle_loss_coefficient_to_ambient_temperature == 0 - # runner.registerInfo("No heat loss was assumed.") - # end - #else - # onoff_cycle_loss_coefficient_to_ambient_temperature = nil - #end - if onoff_cycle_loss_coefficient_to_ambient_temperature.is_a? Numeric - if onoff_cycle_loss_coefficient_to_ambient_temperature < 0 - runner.registerError("Enter a value greater than or equal to zero for the 'On/Off Cycle Loss Coefficient to Ambient Temperature'.") - return false - elsif onoff_cycle_loss_coefficient_to_ambient_temperature == 0 - runner.registerInfo("No heat loss was assumed.") - end - else - onoff_cycle_loss_coefficient_to_ambient_temperature = nil - end - - if peak_use_flow_rate.is_a? Numeric - if peak_use_flow_rate <= 0.0 then - runner.registerError("Enter a value greater than zero for the 'Peak Use Flow Rate'.") - end - end - - i_water_heater = 0 - model.getWaterHeaterMixeds.each do |water_heater| - i_water_heater = i_water_heater + 1 - - # check if AllAirloop is selected or not. - if waterheater_index != 0 and (waterheater_index != i_water_heater) - next - end - - if not water_heater.to_WaterHeaterMixed.empty? - unit = water_heater.to_WaterHeaterMixed.get - - #get the original value for reporting - heater_thermal_efficiency_old = unit.heaterThermalEfficiency - oncycle_loss_coeff_old = unit.onCycleLossCoefficienttoAmbientTemperature - offcycle_loss_coeff_old = unit.offCycleLossCoefficienttoAmbientTemperature - peak_use_flow_old = unit.peakUseFlowRate - - runner.registerInfo("Initial: Heater Thermal Efficiency of '#{unit.name}' was #{heater_thermal_efficiency_old}.") - runner.registerInfo("Initial: On Cycle Loss Coefficient to Ambient Temperature of '#{unit.name}' was #{oncycle_loss_coeff_old}.") - runner.registerInfo("Initial: Off Cycle Loss Coefficient to Ambient Temperature'#{unit.name}' was #{offcycle_loss_coeff_old}.") - if peak_use_flow_old.is_a? Numeric - runner.registerInfo("Initial: Peak Use Flow Rate of '#{unit.name}' was #{peak_use_flow_old}.") - end - - #now we have all user inputs, so set them to the new model - unit.setHeaterFuelType(heater_fuel) - unit.setHeaterThermalEfficiency(heater_thermal_efficiency) - if not onoff_cycle_loss_coefficient_to_ambient_temperature.nil? - unit.setOnCycleLossCoefficienttoAmbientTemperature(onoff_cycle_loss_coefficient_to_ambient_temperature) - unit.setOffCycleLossCoefficienttoAmbientTemperature(onoff_cycle_loss_coefficient_to_ambient_temperature) - runner.registerInfo("Final: On/Off Cycle Loss Coefficient to Ambient Temperature of '#{unit.name}' was set to be #{onoff_cycle_loss_coefficient_to_ambient_temperature}.") - end - if peak_use_flow_rate.is_a? Numeric - unit.setPeakUseFlowRate(peak_use_flow_rate) - end - - runner.registerInfo("Final: Heater Thermal Efficiency of '#{unit.name}' was set to be #{heater_thermal_efficiency}.") - if peak_use_flow_rate.is_a? Numeric - runner.registerInfo("Final: Peak Use Flow Rate of '#{unit.name}' was set to be #{peak_use_flow_rate}.") - end - end - end - return true - - end #end the run method + # Determine if the measure is applicable to the model, if not just return and no changes are made. + info_widget = runner.getOptionalWorkspaceObjectChoiceValue('info_widget', user_arguments, model) + if !(info_widget.nil? || info_widget.empty?) + runner.registerInfo('This measure is not applicable.') + return true + end + + # assign the user inputs to variables + waterheater_widget = runner.getOptionalWorkspaceObjectChoiceValue('waterheater_widget', user_arguments, model) + heater_fuel_type_widget = runner.getOptionalWorkspaceObjectChoiceValue('heater_fuel_type_widget', user_arguments, model) -end #end the measure + handle = runner.getStringArgumentValue('waterheater_widget', user_arguments) + waterheater_index = handle.to_i + + fuel_type_array = ['NaturalGas', 'Electricity', 'PropaneGas', 'FuelOil#1', 'FuelOil#2',\ + 'Coal', 'Diesel', 'Gasoline', 'OtherFuel1', 'OtherFuel2', 'Steam', 'DistrictHeating'] + + handle = runner.getStringArgumentValue('heater_fuel_type_widget', user_arguments) + heater_fuel_type = handle.to_i + heater_fuel = fuel_type_array[heater_fuel_type] + + heater_thermal_efficiency = runner.getDoubleArgumentValue('heater_thermal_efficiency', user_arguments) + onoff_cycle_loss_coefficient_to_ambient_temperature = runner.getDoubleArgumentValue('onoff_cycle_loss_coefficient_to_ambient_temperature', user_arguments) + + peak_use_flow_rate = runner.getDoubleArgumentValue('peak_use_flow_rate', user_arguments) + + if heater_thermal_efficiency <= 0 + runner.registerError("Enter a value greater than zero for the 'Heater Thermal Efficiency'.") + elsif heater_thermal_efficiency > 1.0 + runner.registerError("Enter a value less than or equal to 1.0 for the 'HeaterThermal Efficiency'.") + end + + # if not onoff_cycle_loss_coefficient_to_ambient_temperature.empty? + # if onoff_cycle_loss_coefficient_to_ambient_temperature < 0 + # runner.registerError("Enter a value greater than or equal to zero for the 'On/Off Cycle Loss Coefficient to Ambient Temperature'.") + # return false + # elsif onoff_cycle_loss_coefficient_to_ambient_temperature == 0 + # runner.registerInfo("No heat loss was assumed.") + # end + # else + # onoff_cycle_loss_coefficient_to_ambient_temperature = nil + # end + if onoff_cycle_loss_coefficient_to_ambient_temperature.is_a? Numeric + if onoff_cycle_loss_coefficient_to_ambient_temperature < 0 + runner.registerError("Enter a value greater than or equal to zero for the 'On/Off Cycle Loss Coefficient to Ambient Temperature'.") + return false + elsif onoff_cycle_loss_coefficient_to_ambient_temperature == 0 + runner.registerInfo('No heat loss was assumed.') + end + else + onoff_cycle_loss_coefficient_to_ambient_temperature = nil + end + + if peak_use_flow_rate.is_a? Numeric + if peak_use_flow_rate <= 0.0 + runner.registerError("Enter a value greater than zero for the 'Peak Use Flow Rate'.") + end + end + + i_water_heater = 0 + model.getWaterHeaterMixeds.each do |water_heater| + i_water_heater += 1 + + # check if AllAirloop is selected or not. + if (waterheater_index != 0) && (waterheater_index != i_water_heater) + next + end + + if !water_heater.to_WaterHeaterMixed.empty? + unit = water_heater.to_WaterHeaterMixed.get + + # get the original value for reporting + heater_thermal_efficiency_old = unit.heaterThermalEfficiency + oncycle_loss_coeff_old = unit.onCycleLossCoefficienttoAmbientTemperature + offcycle_loss_coeff_old = unit.offCycleLossCoefficienttoAmbientTemperature + peak_use_flow_old = unit.peakUseFlowRate + + runner.registerInfo("Initial: Heater Thermal Efficiency of '#{unit.name}' was #{heater_thermal_efficiency_old}.") + runner.registerInfo("Initial: On Cycle Loss Coefficient to Ambient Temperature of '#{unit.name}' was #{oncycle_loss_coeff_old}.") + runner.registerInfo("Initial: Off Cycle Loss Coefficient to Ambient Temperature'#{unit.name}' was #{offcycle_loss_coeff_old}.") + if peak_use_flow_old.is_a? Numeric + runner.registerInfo("Initial: Peak Use Flow Rate of '#{unit.name}' was #{peak_use_flow_old}.") + end + + # now we have all user inputs, so set them to the new model + unit.setHeaterFuelType(heater_fuel) + unit.setHeaterThermalEfficiency(heater_thermal_efficiency) + if !onoff_cycle_loss_coefficient_to_ambient_temperature.nil? + unit.setOnCycleLossCoefficienttoAmbientTemperature(onoff_cycle_loss_coefficient_to_ambient_temperature) + unit.setOffCycleLossCoefficienttoAmbientTemperature(onoff_cycle_loss_coefficient_to_ambient_temperature) + runner.registerInfo("Final: On/Off Cycle Loss Coefficient to Ambient Temperature of '#{unit.name}' was set to be #{onoff_cycle_loss_coefficient_to_ambient_temperature}.") + end + if peak_use_flow_rate.is_a? Numeric + unit.setPeakUseFlowRate(peak_use_flow_rate) + end + + runner.registerInfo("Final: Heater Thermal Efficiency of '#{unit.name}' was set to be #{heater_thermal_efficiency}.") + if peak_use_flow_rate.is_a? Numeric + runner.registerInfo("Final: Peak Use Flow Rate of '#{unit.name}' was set to be #{peak_use_flow_rate}.") + end + end + end + + return true + end # end the run method +end # end the measure -#this allows the measure to be use by the application -SetWaterHeaterEfficiencyHeatLossandPeakWaterFlowRate.new.registerWithApplication \ No newline at end of file +# this allows the measure to be use by the application +SetWaterHeaterEfficiencyHeatLossandPeakWaterFlowRate.new.registerWithApplication diff --git a/lib/measures/set_water_heater_efficiency_heat_lossand_peak_water_flow_rate/tests/SetWaterHeaterEfficiencyHeatLossandPeakWaterFlowRate_Test.rb b/lib/measures/set_water_heater_efficiency_heat_lossand_peak_water_flow_rate/tests/SetWaterHeaterEfficiencyHeatLossandPeakWaterFlowRate_Test.rb index 8232d9b..9d96a81 100644 --- a/lib/measures/set_water_heater_efficiency_heat_lossand_peak_water_flow_rate/tests/SetWaterHeaterEfficiencyHeatLossandPeakWaterFlowRate_Test.rb +++ b/lib/measures/set_water_heater_efficiency_heat_lossand_peak_water_flow_rate/tests/SetWaterHeaterEfficiencyHeatLossandPeakWaterFlowRate_Test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'openstudio' require 'openstudio/ruleset/ShowRunnerOutput' @@ -6,55 +8,51 @@ require 'test/unit' class SetWaterHeaterEfficiencyHeatLossandPeakWaterFlowRate_Test < Test::Unit::TestCase - # def setup # end # def teardown # end - + def test_SetWaterHeaterEfficiencyHeatLossandPeakWaterFlowRate - # create an instance of the measure measure = SetWaterHeaterEfficiencyHeatLossandPeakWaterFlowRate.new - + # create an instance of a runner runner = OpenStudio::Ruleset::OSRunner.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(2, arguments.size) - assert_equal("user_name", arguments[0].name) - assert_equal("add_space", arguments[1].name) - assert((not arguments[0].hasDefaultValue)) + assert_equal('user_name', arguments[0].name) + assert_equal('add_space', arguments[1].name) + assert(!arguments[0].hasDefaultValue) # set argument values to bad values and run the measure argument_map = OpenStudio::Ruleset::OSArgumentMap.new user_name = arguments[0].clone - assert(user_name.setValue("")) - argument_map["user_name"] = user_name + assert(user_name.setValue('')) + argument_map['user_name'] = user_name measure.run(model, runner, argument_map) result = runner.result - assert(result.value.valueName == "Fail") - + assert(result.value.valueName == 'Fail') + # set argument values to good values and run the measure on model with spaces argument_map = OpenStudio::Ruleset::OSArgumentMap.new user_name = arguments[0].clone - assert(user_name.setValue("david")) - argument_map["user_name"] = user_name + assert(user_name.setValue('david')) + argument_map['user_name'] = user_name add_space = arguments[1].clone assert(add_space.setValue(true)) - argument_map["add_space"] = add_space + argument_map['add_space'] = add_space measure.run(model, runner, argument_map) result = runner.result show_output(result) - assert(result.value.valueName == "Success") + assert(result.value.valueName == 'Success') assert(result.warnings.size == 1) assert(result.info.size == 2) - - end - + end end diff --git a/lib/measures/tenant_star_internal_loads/measure.rb b/lib/measures/tenant_star_internal_loads/measure.rb index 91d21e4..08540eb 100644 --- a/lib/measures/tenant_star_internal_loads/measure.rb +++ b/lib/measures/tenant_star_internal_loads/measure.rb @@ -1,30 +1,31 @@ +# frozen_string_literal: true + # see the URL below for information on how to write OpenStudio measures # http://nrel.github.io/OpenStudio-user-documentation/reference/measure_writing_guide/ # start the measure class TenantStarInternalLoads < OpenStudio::Ruleset::ModelUserScript - require 'openstudio-standards' # require all .rb files in resources folder - Dir[File.dirname(__FILE__) + '/resources/*.rb'].each {|file| require file } + Dir[File.dirname(__FILE__) + '/resources/*.rb'].each { |file| require file } # resource file modules include OsLib_HelperMethods # human readable name def name - return "Tenant Star Internal Loads" + return 'Tenant Star Internal Loads' end # human readable description def description - return "Overrides existing model values for lightings, equipment, people, and infiltration." + return 'Overrides existing model values for lightings, equipment, people, and infiltration.' end # human readable description of modeling approach def modeler_description - return "Lighting should be stacked value unless we add uncertainty. Equipment and people will vary based on information provided by tenant, and infiltration will be used for uncertainty. Schedules will be addressed in a separate measure that creates parametric schedules based on hours of operation." + return 'Lighting should be stacked value unless we add uncertainty. Equipment and people will vary based on information provided by tenant, and infiltration will be used for uncertainty. Schedules will be addressed in a separate measure that creates parametric schedules based on hours of operation.' end # define the arguments that the user will input @@ -33,27 +34,27 @@ def arguments(model) # argument for lpd # note: the new consumption method is ontly setup to work on lights that are wattsperSpaceFloorArea and use ScheduleRulesets. It will fail with ruby error if that isn't the case, but for TenantStart this will be fine. - #lpd = OpenStudio::Ruleset::OSArgument.makeDoubleArgument("lpd", true) - #lpd.setDisplayName("Target Annual lighting power consumption") - #lpd.setDefaultValue(5.0) - #lpd.setUnits("kBtu/ft^2") - #lpd.setDescription("This will be used to calculate an LPD by dividing annual consumption by annual_equivalent_full_load_hrs and floor area. Lighting schedules should not be changed after this measure has been run or consumpiton will not be as expected.") - #args << lpd + # lpd = OpenStudio::Ruleset::OSArgument.makeDoubleArgument("lpd", true) + # lpd.setDisplayName("Target Annual lighting power consumption") + # lpd.setDefaultValue(5.0) + # lpd.setUnits("kBtu/ft^2") + # lpd.setDescription("This will be used to calculate an LPD by dividing annual consumption by annual_equivalent_full_load_hrs and floor area. Lighting schedules should not be changed after this measure has been run or consumpiton will not be as expected.") + # args << lpd # argument for epd - epd = OpenStudio::Ruleset::OSArgument.makeDoubleArgument("epd", true) - epd.setDisplayName("Electric Equipment Power Density") + epd = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('epd', true) + epd.setDisplayName('Electric Equipment Power Density') epd.setDefaultValue(0.55) # 0.55 value came from 50% AEDG Table 4.7 - epd.setUnits("W/ft^2") - epd.setDescription("Electric Power Density including servers.") + epd.setUnits('W/ft^2') + epd.setDescription('Electric Power Density including servers.') args << epd # argument for people_per_floor_area - #people_per_floor_area = OpenStudio::Ruleset::OSArgument.makeDoubleArgument("people_per_floor_area", true) - #people_per_floor_area.setDisplayName("People per floor area") - #people_per_floor_area.setDefaultValue(0.005) # default value based on medium office prototype - #people_per_floor_area.setUnits("People/ft^2") - #args << people_per_floor_area + # people_per_floor_area = OpenStudio::Ruleset::OSArgument.makeDoubleArgument("people_per_floor_area", true) + # people_per_floor_area.setDisplayName("People per floor area") + # people_per_floor_area.setDefaultValue(0.005) # default value based on medium office prototype + # people_per_floor_area.setUnits("People/ft^2") + # args << people_per_floor_area return args end @@ -63,20 +64,20 @@ def run(model, runner, user_arguments) super(model, runner, user_arguments) # assign the user inputs to variables - args = OsLib_HelperMethods.createRunVariables(runner, model,user_arguments, arguments(model)) + args = OsLib_HelperMethods.createRunVariables(runner, model, user_arguments, arguments(model)) if !args then return false end - #non_neg_args = ["lpd","epd","people_per_floor_area"] - non_neg_args = ["epd"] - non_neg = OsLib_HelperMethods.checkDoubleAndIntegerArguments(runner, user_arguments,{"min"=>0.0,"max"=>nil,"min_eq_bool"=>true,"max_eq_bool"=>false,"arg_array" =>non_neg_args}) + # non_neg_args = ["lpd","epd","people_per_floor_area"] + non_neg_args = ['epd'] + non_neg = OsLib_HelperMethods.checkDoubleAndIntegerArguments(runner, user_arguments, 'min' => 0.0, 'max' => nil, 'min_eq_bool' => true, 'max_eq_bool' => false, 'arg_array' => non_neg_args) if !non_neg then return false end # report initial condition of model - #runner.registerInitialCondition("The building started with an installed LPD of #{ OpenStudio::convert(model.getBuilding.lightingPowerPerFloorArea,"W/m^2","W/ft^2").get} W/ft^2.") + # runner.registerInitialCondition("The building started with an installed LPD of #{ OpenStudio::convert(model.getBuilding.lightingPowerPerFloorArea,"W/m^2","W/ft^2").get} W/ft^2.") # calculate initial lighting consumtpion (assuming no daylight controls) to determine LPD adjustmnet multiplier) - #initial_consumption = 0.0 - #model.getSpaceTypes.each do |space_type| + # initial_consumption = 0.0 + # model.getSpaceTypes.each do |space_type| # next if space_type.spaces.size == 0 # space_type.lights.each do |light| # floor_area = space_type.floorArea @@ -87,48 +88,46 @@ def run(model, runner, user_arguments) # runner.registerInfo("#{light.name} has #{ann_equiv_hours} annual equiv. hours with total consumption of #{consumption}.") # initial_consumption += consumption # end - #end + # end # calculate LPD multiplier - #lpd_multiplier = OpenStudio::convert(model.getBuilding.floorArea,"m^2","ft^2").get * args['lpd']/OpenStudio::convert(initial_consumption,"Wh","kBtu").get + # lpd_multiplier = OpenStudio::convert(model.getBuilding.floorArea,"m^2","ft^2").get * args['lpd']/OpenStudio::convert(initial_consumption,"Wh","kBtu").get # array of altered lighting defitinos (tracking so isn't altered twice) - #altered_light_defs = [] + # altered_light_defs = [] # loop through spae types altering loads - #model.getSpaceTypes.each do |space_type| + # model.getSpaceTypes.each do |space_type| # next if space_type.spaces.size == 0 - # update lights - #space_type.lights.each do |light| - # light_def = light.lightsDefinition - # if not altered_light_defs.include?(light_def) - # light_def.setWattsperSpaceFloorArea(light_def.wattsperSpaceFloorArea.get * lpd_multiplier) - # altered_light_defs << light_def - # end - #end - - # replace electric equipment - model.getSpaceTypes.each do |space_type| - epd_si = OpenStudio::convert(args['epd'],"W/ft^2","W/m^2").get - space_type.setElectricEquipmentPowerPerFloorArea(epd_si) - runner.registerInfo("Changing EPD for plug loads for #{space_type.name} to #{args['epd']} (W/ft^2)") - end - - # replace people - #people_per_floor_area_si = OpenStudio::convert(args['people_per_floor_area'],"1/ft^2","1/m^2").get - #space_type.setPeoplePerFloorArea(people_per_floor_area_si) - #runner.registerInfo("Changing People per floor area for #{space_type.name} to #{args['people_per_floor_area']} (People/ft^2)") - - #end + # update lights + # space_type.lights.each do |light| + # light_def = light.lightsDefinition + # if not altered_light_defs.include?(light_def) + # light_def.setWattsperSpaceFloorArea(light_def.wattsperSpaceFloorArea.get * lpd_multiplier) + # altered_light_defs << light_def + # end + # end + + # replace electric equipment + model.getSpaceTypes.each do |space_type| + epd_si = OpenStudio.convert(args['epd'], 'W/ft^2', 'W/m^2').get + space_type.setElectricEquipmentPowerPerFloorArea(epd_si) + runner.registerInfo("Changing EPD for plug loads for #{space_type.name} to #{args['epd']} (W/ft^2)") + end + + # replace people + # people_per_floor_area_si = OpenStudio::convert(args['people_per_floor_area'],"1/ft^2","1/m^2").get + # space_type.setPeoplePerFloorArea(people_per_floor_area_si) + # runner.registerInfo("Changing People per floor area for #{space_type.name} to #{args['people_per_floor_area']} (People/ft^2)") + + # end # report final condition of model - #runner.registerFinalCondition("The building finished with an installed LPD of #{ OpenStudio::convert(model.getBuilding.lightingPowerPerFloorArea,"W/m^2","W/ft^2").get} W/ft^2.") + # runner.registerFinalCondition("The building finished with an installed LPD of #{ OpenStudio::convert(model.getBuilding.lightingPowerPerFloorArea,"W/m^2","W/ft^2").get} W/ft^2.") return true - end - end # register the measure to be used by the application diff --git a/lib/measures/tenant_star_internal_loads/resources/os_lib_helper_methods.rb b/lib/measures/tenant_star_internal_loads/resources/os_lib_helper_methods.rb index b38fe48..a9b8d39 100644 --- a/lib/measures/tenant_star_internal_loads/resources/os_lib_helper_methods.rb +++ b/lib/measures/tenant_star_internal_loads/resources/os_lib_helper_methods.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # ******************************************************************************* # OpenStudio(R), Copyright (c) 2008-2018, Alliance for Sustainable Energy, LLC. # All rights reserved. @@ -227,7 +229,7 @@ def self.setup_log_msgs(runner, debug = false) def self.log_msgs @msg_log.logMessages.each do |msg| # DLM: you can filter on log channel here for now - if /openstudio.*/.match(msg.logChannel) # /openstudio\.model\..*/ + if /openstudio.*/.match?(msg.logChannel) # /openstudio\.model\..*/ # Skip certain messages that are irrelevant/misleading next if msg.logMessage.include?('Skipping layer') || # Annoying/bogus "Skipping layer" warnings msg.logChannel.include?('runmanager') || # RunManager messages diff --git a/lib/measures/tenant_star_internal_loads/tests/tenant_star_internal_loads_test.rb b/lib/measures/tenant_star_internal_loads/tests/tenant_star_internal_loads_test.rb index 734c765..e6852a4 100644 --- a/lib/measures/tenant_star_internal_loads/tests/tenant_star_internal_loads_test.rb +++ b/lib/measures/tenant_star_internal_loads/tests/tenant_star_internal_loads_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'openstudio' require 'openstudio/ruleset/ShowRunnerOutput' require 'minitest/autorun' @@ -5,7 +7,6 @@ require 'fileutils' class TenantStarInternalLoads_Test < MiniTest::Unit::TestCase - def test_good_argument_values # create an instance of the measure measure = TenantStarInternalLoads.new @@ -15,9 +16,9 @@ def test_good_argument_values # load the test model translator = OpenStudio::OSVersion::VersionTranslator.new - path = OpenStudio::Path.new(File.dirname(__FILE__) + "/example_model.osm") + path = OpenStudio::Path.new(File.dirname(__FILE__) + '/example_model.osm') model = translator.loadModel(path) - assert((not model.empty?)) + assert(!model.empty?) model = model.get # get arguments @@ -27,13 +28,13 @@ def test_good_argument_values # create hash of argument values. # If the argument has a default that you want to use, you don't need it in the hash args_hash = {} - #args_hash["space_name"] = "New Space" + # args_hash["space_name"] = "New Space" # using defaults values from measure.rb for other arguments # populate argument with specified hash value if specified arguments.each do |arg| temp_arg_var = arg.clone - if args_hash.has_key?(arg.name) + if args_hash.key?(arg.name) assert(temp_arg_var.setValue(args_hash[arg.name])) end argument_map[arg.name] = temp_arg_var @@ -47,13 +48,12 @@ def test_good_argument_values show_output(result) # assert that it ran correctly - assert_equal("Success", result.value.valueName) - #assert(result.info.size == 1) - #assert(result.warnings.size == 0) + assert_equal('Success', result.value.valueName) + # assert(result.info.size == 1) + # assert(result.warnings.size == 0) # save the model to test output directory - output_file_path = OpenStudio::Path.new(File.dirname(__FILE__) + "/output/test_output.osm") - model.save(output_file_path,true) + output_file_path = OpenStudio::Path.new(File.dirname(__FILE__) + '/output/test_output.osm') + model.save(output_file_path, true) end - end diff --git a/lib/measures/vr_fwith_doas/measure.rb b/lib/measures/vr_fwith_doas/measure.rb index e7deb84..85dc05e 100644 --- a/lib/measures/vr_fwith_doas/measure.rb +++ b/lib/measures/vr_fwith_doas/measure.rb @@ -1,27 +1,29 @@ -#see the URL below for information on how to write OpenStudio measures +# frozen_string_literal: true + +# see the URL below for information on how to write OpenStudio measures # http://openstudio.nrel.gov/openstudio-measure-writing-guide -#see the URL below for information on using life cycle cost objects in OpenStudio +# see the URL below for information on using life cycle cost objects in OpenStudio # http://openstudio.nrel.gov/openstudio-life-cycle-examples -#see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) +# see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) # http://openstudio.nrel.gov/sites/openstudio.nrel.gov/files/nv_data/cpp_documentation_it/model/html/namespaces.html -#load OpenStudio measure libraries -#require "#{File.dirname(__FILE__)}/resources/OsLib_AedgMeasures" +# load OpenStudio measure libraries +# require "#{File.dirname(__FILE__)}/resources/OsLib_AedgMeasures" require "#{File.dirname(__FILE__)}/resources/OsLib_HelperMethods" require "#{File.dirname(__FILE__)}/resources/OsLib_HVAC" require "#{File.dirname(__FILE__)}/resources/OsLib_Schedules" -#start the measure +# start the measure class VRFwithDOAS < OpenStudio::Ruleset::ModelUserScript - - #define the name that a user will see, this method may be deprecated as - #the display name in PAT comes from the name field in measure.xml + # define the name that a user will see, this method may be deprecated as + # the display name in PAT comes from the name field in measure.xml def name - return "VRFwithDOAS" + return 'VRFwithDOAS' end - #define the arguments that the user will input + + # define the arguments that the user will input def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new @@ -29,423 +31,421 @@ def arguments(model) spaceTypes = model.getSpaceTypes usedSpaceTypes_handle = OpenStudio::StringVector.new usedSpaceTypes_displayName = OpenStudio::StringVector.new - spaceTypes.each do |spaceType| #todo - I need to update this to use helper so GUI sorts by display name - if spaceType.spaces.size > 0 # only show space types used in the building + spaceTypes.each do |spaceType| # TODO: - I need to update this to use helper so GUI sorts by display name + if !spaceType.spaces.empty? # only show space types used in the building usedSpaceTypes_handle << spaceType.handle.to_s usedSpaceTypes_displayName << spaceType.name.to_s end end - + # make an argument for space type - ceilingReturnPlenumSpaceType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("ceilingReturnPlenumSpaceType", usedSpaceTypes_handle, usedSpaceTypes_displayName,false) - ceilingReturnPlenumSpaceType.setDisplayName("This space type should be part of a ceiling return air plenum.") - #ceilingReturnPlenumSpaceType.setDefaultValue("We don't want a default, this is an optional argument") + ceilingReturnPlenumSpaceType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('ceilingReturnPlenumSpaceType', usedSpaceTypes_handle, usedSpaceTypes_displayName, false) + ceilingReturnPlenumSpaceType.setDisplayName('This space type should be part of a ceiling return air plenum.') + # ceilingReturnPlenumSpaceType.setDefaultValue("We don't want a default, this is an optional argument") args << ceilingReturnPlenumSpaceType - + # make a list of space types that will be changed - spaceTypes = model.getSpaceTypes - spaceTypes.each do |spaceType| - if spaceType.spaces.size > 0 - space_type_to_edit = OpenStudio::Ruleset::OSArgument::makeBoolArgument(spaceType.name.get.to_s,true) - #make a bool argument for each space type - space_type_to_edit.setDisplayName("Add #{spaceType.name.get} space type to VRF system?") - space_type_to_edit.setDefaultValue(false) - args << space_type_to_edit - end - end - + spaceTypes = model.getSpaceTypes + spaceTypes.each do |spaceType| + if !spaceType.spaces.empty? + space_type_to_edit = OpenStudio::Ruleset::OSArgument.makeBoolArgument(spaceType.name.get.to_s, true) + # make a bool argument for each space type + space_type_to_edit.setDisplayName("Add #{spaceType.name.get} space type to VRF system?") + space_type_to_edit.setDefaultValue(false) + args << space_type_to_edit + end + end + # VRF Condenser Type - condenserChs = OpenStudio::StringVector.new - # condenserChs << "WaterCooled" - # condenserChs << "EvaporativelyCooled" - condenserChs << "AirCooled" - vrfCondenserType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("vrfCondenserType",condenserChs,true) - vrfCondenserType.setDisplayName("VRF Condenser Type") - vrfCondenserType.setDefaultValue("AirCooled") - args< 0 - space_type = model.getSpaceTypeByName(space_type.name.get).get - space_type_to_edit = runner.getBoolArgumentValue(space_type.name.get.to_s,user_arguments) - space_type_to_edits_hash[space_type] = space_type_to_edit - end - end - - vrfCondenserType = runner.getStringArgumentValue("vrfCondenserType",user_arguments) - vrfCoolCOP = runner.getDoubleArgumentValue("vrfCoolCOP",user_arguments) - vrfHeatCOP = runner.getDoubleArgumentValue("vrfHeatCOP",user_arguments) - vrfMinOATHPHeat = runner.getDoubleArgumentValue("vrfMinOATHPHeat",user_arguments) - vrfDefrost = runner.getStringArgumentValue("vrfDefrost",user_arguments) - vrfHPHeatRecovery = runner.getStringArgumentValue("vrfHPHeatRecovery",user_arguments) - vrfEquivPipingLength = runner.getDoubleArgumentValue("vrfEquivPipingLength",user_arguments) - vrfPipingHeight = runner.getDoubleArgumentValue("vrfPipingHeight",user_arguments) - doasFanType = runner.getStringArgumentValue("doasFanType",user_arguments) - doasERV = runner.getStringArgumentValue("doasERV",user_arguments) - doasEvap = runner.getStringArgumentValue("doasEvap",user_arguments) - doasDXEER = runner.getDoubleArgumentValue("doasDXEER",user_arguments) - - parameters ={"vrfCondenserType" => vrfCondenserType, - "vrfCoolCOP" => vrfCoolCOP, - "vrfHeatCOP" => vrfHeatCOP, - "vrfMinOATHPHeat" => vrfMinOATHPHeat, - "vrfDefrost" => vrfDefrost, - "vrfHPHeatRecovery" => vrfHPHeatRecovery, - "vrfEquivPipingLength" => vrfEquivPipingLength, - "vrfPipingHeight" => vrfPipingHeight, - "doasFanType" => doasFanType, - "doasERV" => doasERV, - "doasEvap" => doasEvap, - "doasDXEER" => doasDXEER} - - + + # assign the user inputs to variables + space_type_to_edits_hash = {} + space_types = model.getSpaceTypes + space_types.each do |space_type| + if model.getSpaceTypeByName(space_type.name.get).is_initialized && !space_type.spaces.empty? + space_type = model.getSpaceTypeByName(space_type.name.get).get + space_type_to_edit = runner.getBoolArgumentValue(space_type.name.get.to_s, user_arguments) + space_type_to_edits_hash[space_type] = space_type_to_edit + end + end + + vrfCondenserType = runner.getStringArgumentValue('vrfCondenserType', user_arguments) + vrfCoolCOP = runner.getDoubleArgumentValue('vrfCoolCOP', user_arguments) + vrfHeatCOP = runner.getDoubleArgumentValue('vrfHeatCOP', user_arguments) + vrfMinOATHPHeat = runner.getDoubleArgumentValue('vrfMinOATHPHeat', user_arguments) + vrfDefrost = runner.getStringArgumentValue('vrfDefrost', user_arguments) + vrfHPHeatRecovery = runner.getStringArgumentValue('vrfHPHeatRecovery', user_arguments) + vrfEquivPipingLength = runner.getDoubleArgumentValue('vrfEquivPipingLength', user_arguments) + vrfPipingHeight = runner.getDoubleArgumentValue('vrfPipingHeight', user_arguments) + doasFanType = runner.getStringArgumentValue('doasFanType', user_arguments) + doasERV = runner.getStringArgumentValue('doasERV', user_arguments) + doasEvap = runner.getStringArgumentValue('doasEvap', user_arguments) + doasDXEER = runner.getDoubleArgumentValue('doasDXEER', user_arguments) + + parameters = { 'vrfCondenserType' => vrfCondenserType, + 'vrfCoolCOP' => vrfCoolCOP, + 'vrfHeatCOP' => vrfHeatCOP, + 'vrfMinOATHPHeat' => vrfMinOATHPHeat, + 'vrfDefrost' => vrfDefrost, + 'vrfHPHeatRecovery' => vrfHPHeatRecovery, + 'vrfEquivPipingLength' => vrfEquivPipingLength, + 'vrfPipingHeight' => vrfPipingHeight, + 'doasFanType' => doasFanType, + 'doasERV' => doasERV, + 'doasEvap' => doasEvap, + 'doasDXEER' => doasDXEER } + ### START INPUTS - #assign the user inputs to variables - ceilingReturnPlenumSpaceType = runner.getOptionalWorkspaceObjectChoiceValue("ceilingReturnPlenumSpaceType",user_arguments,model) - costTotalHVACSystem = runner.getDoubleArgumentValue("costTotalHVACSystem",user_arguments) - remake_schedules = runner.getBoolArgumentValue("remake_schedules",user_arguments) + # assign the user inputs to variables + ceilingReturnPlenumSpaceType = runner.getOptionalWorkspaceObjectChoiceValue('ceilingReturnPlenumSpaceType', user_arguments, model) + costTotalHVACSystem = runner.getDoubleArgumentValue('costTotalHVACSystem', user_arguments) + remake_schedules = runner.getBoolArgumentValue('remake_schedules', user_arguments) # check that spaceType was chosen and exists in model - ceilingReturnPlenumSpaceTypeCheck = OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(ceilingReturnPlenumSpaceType, "ceilingReturnPlenumSpaceType","to_SpaceType", runner, user_arguments) - if ceilingReturnPlenumSpaceTypeCheck == false then return false else ceilingReturnPlenumSpaceType = ceilingReturnPlenumSpaceTypeCheck["modelObject"] end + ceilingReturnPlenumSpaceTypeCheck = OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(ceilingReturnPlenumSpaceType, 'ceilingReturnPlenumSpaceType', 'to_SpaceType', runner, user_arguments) + ceilingReturnPlenumSpaceTypeCheck == false ? (return false) : (ceilingReturnPlenumSpaceType = ceilingReturnPlenumSpaceTypeCheck['modelObject']) # default building/ secondary space types - standardBuildingTypeTest = [] #ML Not used yet - standardBuildingTypeTest = ["Office"] #ML Not used yet + standardBuildingTypeTest = [] # ML Not used yet + standardBuildingTypeTest = ['Office'] # ML Not used yet secondarySpaceTypeTest = [] # empty for office - primarySpaceType = "Office" - if doasFanType == "Variable" - primaryHVAC = {"doas" => true, "fan" => "Variable", "heat" => "Gas", "cool" => "SingleDX"} - else - primaryHVAC = {"doas" => true, "fan" => "Constant", "heat" => "Gas", "cool" => "SingleDX"} - end - secondaryHVAC = {"fan" => "None", "heat" => "None", "cool" => "None"} #ML not used for office; leave or empty? - zoneHVAC = "VRF" - chillerType = "None" #set to none if chiller not used - radiantChillerType = "None" #set to none if not radiant system - allHVAC = {"primary" => primaryHVAC,"secondary" => secondaryHVAC,"zone" => zoneHVAC} - - + primarySpaceType = 'Office' + if doasFanType == 'Variable' + primaryHVAC = { 'doas' => true, 'fan' => 'Variable', 'heat' => 'Gas', 'cool' => 'SingleDX' } + else + primaryHVAC = { 'doas' => true, 'fan' => 'Constant', 'heat' => 'Gas', 'cool' => 'SingleDX' } + end + secondaryHVAC = { 'fan' => 'None', 'heat' => 'None', 'cool' => 'None' } # ML not used for office; leave or empty? + zoneHVAC = 'VRF' + chillerType = 'None' # set to none if chiller not used + radiantChillerType = 'None' # set to none if not radiant system + allHVAC = { 'primary' => primaryHVAC, 'secondary' => secondaryHVAC, 'zone' => zoneHVAC } + ### END INPUTS - + ### START SORT ZONES - options = {"standardBuildingTypeTest" => standardBuildingTypeTest, #ML Not used yet - "secondarySpaceTypeTest" => secondarySpaceTypeTest, - "ceilingReturnPlenumSpaceType" => ceilingReturnPlenumSpaceType} + options = { 'standardBuildingTypeTest' => standardBuildingTypeTest, # ML Not used yet + 'secondarySpaceTypeTest' => secondarySpaceTypeTest, + 'ceilingReturnPlenumSpaceType' => ceilingReturnPlenumSpaceType } zonesSorted = OsLib_HVAC.sortZones(model, runner, options, space_type_to_edits_hash) - zonesPrimary = zonesSorted["zonesPrimary"] - zonesSecondary = zonesSorted["zonesSecondary"] - zonesPlenum = zonesSorted["zonesPlenum"] - zonesUnconditioned = zonesSorted["zonesUnconditioned"] + zonesPrimary = zonesSorted['zonesPrimary'] + zonesSecondary = zonesSorted['zonesSecondary'] + zonesPlenum = zonesSorted['zonesPlenum'] + zonesUnconditioned = zonesSorted['zonesUnconditioned'] ### END SORT ZONES - + ### START REPORT INITIAL CONDITIONS - OsLib_HVAC.reportConditions(model, runner, "initial") + OsLib_HVAC.reportConditions(model, runner, 'initial') ### END REPORT INITIAL CONDITIONS ### START ASSIGN HVAC SCHEDULES - options = {"primarySpaceType" => primarySpaceType, - "allHVAC" => allHVAC, - "remake_schedules" => remake_schedules} + options = { 'primarySpaceType' => primarySpaceType, + 'allHVAC' => allHVAC, + 'remake_schedules' => remake_schedules } schedulesHVAC = OsLib_HVAC.assignHVACSchedules(model, runner, options) # assign schedules - primary_SAT_schedule = schedulesHVAC["primary_sat"] - building_HVAC_schedule = schedulesHVAC["hvac"] - building_ventilation_schedule = schedulesHVAC["ventilation"] + primary_SAT_schedule = schedulesHVAC['primary_sat'] + building_HVAC_schedule = schedulesHVAC['hvac'] + building_ventilation_schedule = schedulesHVAC['ventilation'] make_hot_water_plant = false - unless schedulesHVAC["hot_water"].nil? - hot_water_setpoint_schedule = schedulesHVAC["hot_water"] + unless schedulesHVAC['hot_water'].nil? + hot_water_setpoint_schedule = schedulesHVAC['hot_water'] make_hot_water_plant = true end make_chilled_water_plant = false - unless schedulesHVAC["chilled_water"].nil? - chilled_water_setpoint_schedule = schedulesHVAC["chilled_water"] + unless schedulesHVAC['chilled_water'].nil? + chilled_water_setpoint_schedule = schedulesHVAC['chilled_water'] make_chilled_water_plant = true end make_radiant_hot_water_plant = false - unless schedulesHVAC["radiant_hot_water"].nil? - radiant_hot_water_setpoint_schedule = schedulesHVAC["radiant_hot_water"] + unless schedulesHVAC['radiant_hot_water'].nil? + radiant_hot_water_setpoint_schedule = schedulesHVAC['radiant_hot_water'] make_radiant_hot_water_plant = true end make_radiant_chilled_water_plant = false - unless schedulesHVAC["radiant_chilled_water"].nil? - radiant_chilled_water_setpoint_schedule = schedulesHVAC["radiant_chilled_water"] + unless schedulesHVAC['radiant_chilled_water'].nil? + radiant_chilled_water_setpoint_schedule = schedulesHVAC['radiant_chilled_water'] make_radiant_chilled_water_plant = true end - unless schedulesHVAC["hp_loop"].nil? - heat_pump_loop_setpoint_schedule = schedulesHVAC["hp_loop"] + unless schedulesHVAC['hp_loop'].nil? + heat_pump_loop_setpoint_schedule = schedulesHVAC['hp_loop'] end - unless schedulesHVAC["hp_loop_cooling"].nil? - heat_pump_loop_cooling_setpoint_schedule = schedulesHVAC["hp_loop_cooling"] + unless schedulesHVAC['hp_loop_cooling'].nil? + heat_pump_loop_cooling_setpoint_schedule = schedulesHVAC['hp_loop_cooling'] end - unless schedulesHVAC["hp_loop_heating"].nil? - heat_pump_loop_heating_setpoint_schedule = schedulesHVAC["hp_loop_heating"] + unless schedulesHVAC['hp_loop_heating'].nil? + heat_pump_loop_heating_setpoint_schedule = schedulesHVAC['hp_loop_heating'] end - unless schedulesHVAC["mean_radiant_heating"].nil? - mean_radiant_heating_setpoint_schedule = schedulesHVAC["mean_radiant_heating"] + unless schedulesHVAC['mean_radiant_heating'].nil? + mean_radiant_heating_setpoint_schedule = schedulesHVAC['mean_radiant_heating'] end - unless schedulesHVAC["mean_radiant_cooling"].nil? - mean_radiant_cooling_setpoint_schedule = schedulesHVAC["mean_radiant_cooling"] + unless schedulesHVAC['mean_radiant_cooling'].nil? + mean_radiant_cooling_setpoint_schedule = schedulesHVAC['mean_radiant_cooling'] end ### END ASSIGN HVAC SCHEDULES - + # START REMOVE EQUIPMENT - options = {} - options["zonesPrimary"] = zonesPrimary - if options["zonesPrimary"].empty? - runner.registerInfo("User did not pick any zones to be added to VRF system, no changes to the model were made.") - else - OsLib_HVAC.removeEquipment(model, runner, options) - end + options = {} + options['zonesPrimary'] = zonesPrimary + if options['zonesPrimary'].empty? + runner.registerInfo('User did not pick any zones to be added to VRF system, no changes to the model were made.') + else + OsLib_HVAC.removeEquipment(model, runner, options) + end ### END REMOVE EQUIPMENT - + ### START CREATE NEW PLANTS # create new plants # hot water plant if make_hot_water_plant - hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, "Hot Water", parameters) + hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, 'Hot Water', parameters) end # chilled water plant if make_chilled_water_plant - chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, "Chilled Water", chillerType) + chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, 'Chilled Water', chillerType) end # radiant hot water plant if make_radiant_hot_water_plant - radiant_hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, radiant_hot_water_setpoint_schedule, "Radiant Hot Water") + radiant_hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, radiant_hot_water_setpoint_schedule, 'Radiant Hot Water') end # chilled water plant if make_radiant_chilled_water_plant - radiant_chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, radiant_chilled_water_setpoint_schedule, "Radiant Chilled Water", radiantChillerType) + radiant_chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, radiant_chilled_water_setpoint_schedule, 'Radiant Chilled Water', radiantChillerType) end # condenser loop # need condenser loop if there is a water-cooled chiller or if there is a water source heat pump loop or a water cooled VRF condenser options = {} - options["zonesPrimary"] = zonesPrimary - options["zoneHVAC"] = zoneHVAC - if zoneHVAC.include? "SHP" or zoneHVAC == "VRF" and parameters["vrfCondenserType"] == "WaterCooled" - options["loop_setpoint_schedule"] = heat_pump_loop_setpoint_schedule - options["cooling_setpoint_schedule"] = heat_pump_loop_cooling_setpoint_schedule - options["heating_setpoint_schedule"] = heat_pump_loop_heating_setpoint_schedule - runner.registerInfo("yes, loop schedule created") - end - unless parameters["vrfCondenserType"] == "WaterCooled" - condenserLoops = {} - else - condenserLoops = OsLib_HVAC.createCondenserLoop(model, runner, options, parameters) - end - unless condenserLoops["condenser_loop"].nil? - condenser_loop = condenserLoops["condenser_loop"] - end - unless condenserLoops["heat_pump_loop"].nil? - heat_pump_loop = condenserLoops["heat_pump_loop"] - runner.registerInfo("vrf condenser loop is created") + options['zonesPrimary'] = zonesPrimary + options['zoneHVAC'] = zoneHVAC + if zoneHVAC.include?('SHP') || (zoneHVAC == 'VRF') && (parameters['vrfCondenserType'] == 'WaterCooled') + options['loop_setpoint_schedule'] = heat_pump_loop_setpoint_schedule + options['cooling_setpoint_schedule'] = heat_pump_loop_cooling_setpoint_schedule + options['heating_setpoint_schedule'] = heat_pump_loop_heating_setpoint_schedule + runner.registerInfo('yes, loop schedule created') + end + if parameters['vrfCondenserType'] == 'WaterCooled' + condenserLoops = OsLib_HVAC.createCondenserLoop(model, runner, options, parameters) + else + condenserLoops = {} + end + unless condenserLoops['condenser_loop'].nil? + condenser_loop = condenserLoops['condenser_loop'] + end + unless condenserLoops['heat_pump_loop'].nil? + heat_pump_loop = condenserLoops['heat_pump_loop'] + runner.registerInfo('vrf condenser loop is created') end ### END CREATE NEW PLANTS - + ### START CREATE PRIMARY AIRLOOPS # populate inputs hash for create primary airloops method options = {} - options["zonesPrimary"] = zonesPrimary - options["primaryHVAC"] = primaryHVAC - options["zoneHVAC"] = zoneHVAC - if primaryHVAC["doas"] - options["hvac_schedule"] = building_ventilation_schedule - options["ventilation_schedule"] = building_ventilation_schedule + options['zonesPrimary'] = zonesPrimary + options['primaryHVAC'] = primaryHVAC + options['zoneHVAC'] = zoneHVAC + if primaryHVAC['doas'] + options['hvac_schedule'] = building_ventilation_schedule + options['ventilation_schedule'] = building_ventilation_schedule else # primary HVAC is multizone VAV - unless zoneHVAC == "DualDuct" - # primary system is multizone VAV that cools and ventilates - options["hvac_schedule"] = building_HVAC_schedule - options["ventilation_schedule"] = building_ventilation_schedule - else + if zoneHVAC == 'DualDuct' # primary system is a multizone VAV that cools only (primary system ventilation schedule is set to always off; hvac set to always on) - options["hvac_schedule"] = model.alwaysOnDiscreteSchedule() + options['hvac_schedule'] = model.alwaysOnDiscreteSchedule + else + # primary system is multizone VAV that cools and ventilates + options['hvac_schedule'] = building_HVAC_schedule + options['ventilation_schedule'] = building_ventilation_schedule end end - options["primary_sat_schedule"] = primary_SAT_schedule + options['primary_sat_schedule'] = primary_SAT_schedule if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end primary_airloops = OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) ### END CREATE PRIMARY AIRLOOPS - if zoneHVAC.include? "VRF" - options["heat_pump_loop"] = heat_pump_loop - end - vrf_airconditioners = OsLib_HVAC.createVRFAirConditioners(model,runner,options,parameters) + if zoneHVAC.include? 'VRF' + options['heat_pump_loop'] = heat_pump_loop + end + vrf_airconditioners = OsLib_HVAC.createVRFAirConditioners(model, runner, options, parameters) ### START CREATE SECONDARY AIRLOOPS # populate inputs hash for create primary airloops method options = {} - options["zonesSecondary"] = zonesSecondary - options["secondaryHVAC"] = secondaryHVAC - options["hvac_schedule"] = building_HVAC_schedule - options["ventilation_schedule"] = building_ventilation_schedule + options['zonesSecondary'] = zonesSecondary + options['secondaryHVAC'] = secondaryHVAC + options['hvac_schedule'] = building_HVAC_schedule + options['ventilation_schedule'] = building_ventilation_schedule if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end # secondary_airloops = OsLib_HVAC.createSecondaryAirLoops(model, runner, options) ### END CREATE SECONDARY AIRLOOPS - + ### START ASSIGN PLENUMS - options = {"zonesPrimary" => zonesPrimary,"zonesPlenum" => zonesPlenum} + options = { 'zonesPrimary' => zonesPrimary, 'zonesPlenum' => zonesPlenum } zone_plenum_hash = OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options) ### END ASSIGN PLENUMS - + ### START CREATE PRIMARY ZONE EQUIPMENT options = {} - options["zonesPrimary"] = zonesPrimary - options["zoneHVAC"] = zoneHVAC + options['zonesPrimary'] = zonesPrimary + options['zoneHVAC'] = zoneHVAC if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end - if zoneHVAC.include? "SHP" or zoneHVAC == "VRF" - options["heat_pump_loop"] = heat_pump_loop + if zoneHVAC.include?('SHP') || (zoneHVAC == 'VRF') + options['heat_pump_loop'] = heat_pump_loop end - if zoneHVAC == "DualDuct" - options["ventilation_schedule"] = building_ventilation_schedule + if zoneHVAC == 'DualDuct' + options['ventilation_schedule'] = building_ventilation_schedule end - if zoneHVAC == "Radiant" - options["radiant_hot_water_plant"] = radiant_hot_water_plant - options["radiant_chilled_water_plant"] = radiant_chilled_water_plant - options["mean_radiant_heating_setpoint_schedule"] = mean_radiant_heating_setpoint_schedule - options["mean_radiant_cooling_setpoint_schedule"] = mean_radiant_cooling_setpoint_schedule + if zoneHVAC == 'Radiant' + options['radiant_hot_water_plant'] = radiant_hot_water_plant + options['radiant_chilled_water_plant'] = radiant_chilled_water_plant + options['mean_radiant_heating_setpoint_schedule'] = mean_radiant_heating_setpoint_schedule + options['mean_radiant_cooling_setpoint_schedule'] = mean_radiant_cooling_setpoint_schedule end OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options, parameters) ### END CREATE PRIMARY ZONE EQUIPMENT - + # START ADD DCV options = {} - unless zoneHVAC == "DualDuct" - options["primary_airloops"] = primary_airloops + unless zoneHVAC == 'DualDuct' + options['primary_airloops'] = primary_airloops end # options["secondary_airloops"] = secondary_airloops - options["allHVAC"] = allHVAC + options['allHVAC'] = allHVAC OsLib_HVAC.addDCV(model, runner, options) # END ADD DCV - - # todo - add in lifecycle costs + + # TODO: - add in lifecycle costs expected_life = 25 years_until_costs_start = 0 costHVAC = costTotalHVACSystem - lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("HVAC System", model.getBuilding, costHVAC, "CostPerEach", "Construction", expected_life, years_until_costs_start).get + lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost('HVAC System', model.getBuilding, costHVAC, 'CostPerEach', 'Construction', expected_life, years_until_costs_start).get # # add AEDG tips # aedgTips = ["HV04","HV10","HV12"] @@ -453,18 +453,16 @@ def run(model, runner, user_arguments) # # populate how to tip messages # aedgTipsLong = OsLib_AedgMeasures.getLongHowToTips("SmMdOff",aedgTips.uniq.sort,runner) # if not aedgTipsLong - # return false # this should only happen if measure writer passes bad values to getLongHowToTips + # return false # this should only happen if measure writer passes bad values to getLongHowToTips # end ### START REPORT FINAL CONDITIONS - OsLib_HVAC.reportConditions(model, runner, "final") + OsLib_HVAC.reportConditions(model, runner, 'final') ### END REPORT FINAL CONDITIONS return true + end # end the run method +end # end the measure - end #end the run method - -end #end the measure - -#this allows the measure to be used by the application -VRFwithDOAS.new.registerWithApplication \ No newline at end of file +# this allows the measure to be used by the application +VRFwithDOAS.new.registerWithApplication diff --git a/lib/measures/vr_fwith_doas/resources/OsLib_AedgMeasures.rb b/lib/measures/vr_fwith_doas/resources/OsLib_AedgMeasures.rb index 22bc4aa..0449d71 100644 --- a/lib/measures/vr_fwith_doas/resources/OsLib_AedgMeasures.rb +++ b/lib/measures/vr_fwith_doas/resources/OsLib_AedgMeasures.rb @@ -1,17 +1,18 @@ -module OsLib_AedgMeasures +# frozen_string_literal: true - def OsLib_AedgMeasures.getClimateZoneNumber(model,runner) +module OsLib_AedgMeasures + def self.getClimateZoneNumber(model, runner) # get ashrae climate zone from model - ashraeClimateZone = "" + ashraeClimateZone = '' climateZones = model.getClimateZones climateZones.climateZones.each do |climateZone| - if climateZone.institution == "ASHRAE" + if climateZone.institution == 'ASHRAE' ashraeClimateZone = climateZone.value runner.registerInfo("Using ASHRAE Climate zone #{ashraeClimateZone} for AEDG recommendations.") end end - if ashraeClimateZone == ""#should this be not applicable or error? + if ashraeClimateZone == '' # should this be not applicable or error? runner.registerError("Please assign an ASHRAE Climate Zone to your model using the site tab in the OpenStudio application. The measure can't make AEDG recommendations without this information.") return false # note - for this to work need to check for false in measure.rb and add return false there as well. else @@ -19,24 +20,21 @@ def OsLib_AedgMeasures.getClimateZoneNumber(model,runner) end # expected climate zone number should be 1 through 8 - if not ["1","2","3","4","5","6","7","8"].include? climateZoneNumber - runner.registerError("ASHRAE climate zone number is not within expected range of 1 to 8.") + if !['1', '2', '3', '4', '5', '6', '7', '8'].include? climateZoneNumber + runner.registerError('ASHRAE climate zone number is not within expected range of 1 to 8.') return false # note - for this to work need to check for false in measure.rb and add return false there as well. end result = climateZoneNumber # don't add return false here, need to catch errors above + end # end of def OsLib_AedgMeasures.getClimateZoneNumber(model,runner) - end # end of def OsLib_AedgMeasures.getClimateZoneNumber(model,runner) - - - def OsLib_AedgMeasures.getLongHowToTips(guide,aedgTips,runner) - + def self.getLongHowToTips(guide, aedgTips, runner) # get tips - if guide == "K12" - hash = OsLib_AedgMeasures.getK12Tips() - elsif guide == "SmMdOff" - hash = OsLib_AedgMeasures.getSmMdOffTips() + if guide == 'K12' + hash = OsLib_AedgMeasures.getK12Tips + elsif guide == 'SmMdOff' + hash = OsLib_AedgMeasures.getSmMdOffTips else runner.registerError("#{guide} is an invalid value. Can't generate how to tip messages.") return false # note - for this to work need to check for false in measure.rb and add return false there as well. @@ -48,7 +46,7 @@ def OsLib_AedgMeasures.getLongHowToTips(guide,aedgTips,runner) # create info messages aedgTips.each do |aedgtip| - if not hash[aedgtip] == hash[0] + if hash[aedgtip] != hash[0] string << hash[aedgtip] else runner.registerWarning("#{aedgtip} is an invalid key for tip hash. Can't generate tip.") @@ -57,408 +55,400 @@ def OsLib_AedgMeasures.getLongHowToTips(guide,aedgTips,runner) # see if expected number of messages created if aedgTips.size != string.size - runner.registerWarning("One more more messages were not created.") + runner.registerWarning('One more more messages were not created.') end - result = "#{hash[0]}: #{string.join(", ")}." # hash[0] bad key will return default value + result = "#{hash[0]}: #{string.join(', ')}." # hash[0] bad key will return default value # don't add return false here, need to catch errors above + end # end of def OsLib_AedgMeasures.getClimateZoneNumber(model,runner) - end # end of def OsLib_AedgMeasures.getClimateZoneNumber(model,runner) - - - #hash of how to tips for K-12 school AEDG - def OsLib_AedgMeasures.getK12Tips - + # hash of how to tips for K-12 school AEDG + def self.getK12Tips # envelope tips - @aedgK12HowToTipHash = Hash.new("K-12 Schools AEDG How to Implement Recommendations") - @aedgK12HowToTipHash["EN01"] = "EN1 Cool Roofs" - @aedgK12HowToTipHash["EN02"] = "EN2 Roofs-Insulation Entirely above Deck" - @aedgK12HowToTipHash["EN03"] = "EN3 Roofs-Attics, and Other Roofs" - @aedgK12HowToTipHash["EN04"] = "EN4 Roofs-Metal Buildings" - @aedgK12HowToTipHash["EN05"] = "EN5 Walls-Mass" - @aedgK12HowToTipHash["EN06"] = "EN6 Walls-Steel Framed" - @aedgK12HowToTipHash["EN07"] = "EN7 Walls-Wood Frame and Other" - @aedgK12HowToTipHash["EN08"] = "EN8 Walls-Metal Building" - @aedgK12HowToTipHash["EN09"] = "EN9 Below-Grade Walls" - @aedgK12HowToTipHash["EN10"] = "EN10 Floors-Mass" - @aedgK12HowToTipHash["EN11"] = "EN11 Floors-Metal Joist or Wood Joist/Wood Frame" - @aedgK12HowToTipHash["EN12"] = "EN12 Slab-on-Grade Floors-Unheated" - @aedgK12HowToTipHash["EN13"] = "EN13 Slab-on-Grade Floors-Heated" - @aedgK12HowToTipHash["EN14"] = "EN14 Slab Edge Insulation" - @aedgK12HowToTipHash["EN15"] = "EN15 Doors-Opaque, Swinging" - @aedgK12HowToTipHash["EN16"] = "EN16 Doors-Opaque, Roll-Up, or Sliding" - @aedgK12HowToTipHash["EN17"] = "EN17 Air Infiltration Control" - @aedgK12HowToTipHash["EN18"] = "EN18 Vestibules" - @aedgK12HowToTipHash["EN19"] = "EN19 Alternative Constructions" - @aedgK12HowToTipHash["EN20"] = "EN20 Truss Heel Heights" - @aedgK12HowToTipHash["EN21"] = "EN21 Moisture Control" - @aedgK12HowToTipHash["EN22"] = "EN22 Thermal Bridging-Opaque Components" - @aedgK12HowToTipHash["EN23"] = "EN23 Thermal Bridging-Fenestration" - @aedgK12HowToTipHash["EN24"] = "EN24 Fenestration Descriptions" - @aedgK12HowToTipHash["EN25"] = "EN25 View Window-to Floor Area Ratio (VFR)" - @aedgK12HowToTipHash["EN26"] = "EN26 Unwanted Solar Heat Gain Is Most Effectively Controlled on the Outside of the Building" - @aedgK12HowToTipHash["EN27"] = "EN27 Operable versus Fixed Windows" - @aedgK12HowToTipHash["EN28"] = "EN28 Building Form and Window Orientation" - @aedgK12HowToTipHash["EN29"] = "EN29 Glazing" - @aedgK12HowToTipHash["EN30"] = "EN30 Obstructions and Planting" - @aedgK12HowToTipHash["EN31"] = "EN31 Window Orientation" - @aedgK12HowToTipHash["EN32"] = "EN32 Passive Solar" - @aedgK12HowToTipHash["EN33"] = "EN33 Glazing" + @aedgK12HowToTipHash = Hash.new('K-12 Schools AEDG How to Implement Recommendations') + @aedgK12HowToTipHash['EN01'] = 'EN1 Cool Roofs' + @aedgK12HowToTipHash['EN02'] = 'EN2 Roofs-Insulation Entirely above Deck' + @aedgK12HowToTipHash['EN03'] = 'EN3 Roofs-Attics, and Other Roofs' + @aedgK12HowToTipHash['EN04'] = 'EN4 Roofs-Metal Buildings' + @aedgK12HowToTipHash['EN05'] = 'EN5 Walls-Mass' + @aedgK12HowToTipHash['EN06'] = 'EN6 Walls-Steel Framed' + @aedgK12HowToTipHash['EN07'] = 'EN7 Walls-Wood Frame and Other' + @aedgK12HowToTipHash['EN08'] = 'EN8 Walls-Metal Building' + @aedgK12HowToTipHash['EN09'] = 'EN9 Below-Grade Walls' + @aedgK12HowToTipHash['EN10'] = 'EN10 Floors-Mass' + @aedgK12HowToTipHash['EN11'] = 'EN11 Floors-Metal Joist or Wood Joist/Wood Frame' + @aedgK12HowToTipHash['EN12'] = 'EN12 Slab-on-Grade Floors-Unheated' + @aedgK12HowToTipHash['EN13'] = 'EN13 Slab-on-Grade Floors-Heated' + @aedgK12HowToTipHash['EN14'] = 'EN14 Slab Edge Insulation' + @aedgK12HowToTipHash['EN15'] = 'EN15 Doors-Opaque, Swinging' + @aedgK12HowToTipHash['EN16'] = 'EN16 Doors-Opaque, Roll-Up, or Sliding' + @aedgK12HowToTipHash['EN17'] = 'EN17 Air Infiltration Control' + @aedgK12HowToTipHash['EN18'] = 'EN18 Vestibules' + @aedgK12HowToTipHash['EN19'] = 'EN19 Alternative Constructions' + @aedgK12HowToTipHash['EN20'] = 'EN20 Truss Heel Heights' + @aedgK12HowToTipHash['EN21'] = 'EN21 Moisture Control' + @aedgK12HowToTipHash['EN22'] = 'EN22 Thermal Bridging-Opaque Components' + @aedgK12HowToTipHash['EN23'] = 'EN23 Thermal Bridging-Fenestration' + @aedgK12HowToTipHash['EN24'] = 'EN24 Fenestration Descriptions' + @aedgK12HowToTipHash['EN25'] = 'EN25 View Window-to Floor Area Ratio (VFR)' + @aedgK12HowToTipHash['EN26'] = 'EN26 Unwanted Solar Heat Gain Is Most Effectively Controlled on the Outside of the Building' + @aedgK12HowToTipHash['EN27'] = 'EN27 Operable versus Fixed Windows' + @aedgK12HowToTipHash['EN28'] = 'EN28 Building Form and Window Orientation' + @aedgK12HowToTipHash['EN29'] = 'EN29 Glazing' + @aedgK12HowToTipHash['EN30'] = 'EN30 Obstructions and Planting' + @aedgK12HowToTipHash['EN31'] = 'EN31 Window Orientation' + @aedgK12HowToTipHash['EN32'] = 'EN32 Passive Solar' + @aedgK12HowToTipHash['EN33'] = 'EN33 Glazing' # daylighting tips - @aedgK12HowToTipHash["DL01"] = "DL1 General Principles" - @aedgK12HowToTipHash["DL02"] = "DL2 Consider Daylighting Early in the Design Process" - @aedgK12HowToTipHash["DL03"] = "DL3 Space Types" - @aedgK12HowToTipHash["DL04"] = "DL4 How to Select Daylighting Strategies" - @aedgK12HowToTipHash["DL05"] = "DL5 Recommended Daylighting Fenestration-to-Floor Area Ratios" - @aedgK12HowToTipHash["DL06"] = "DL6 View Windows Separate from Daylighting Strategy" - @aedgK12HowToTipHash["DL07"] = "DL7 Lighting Design Criteria" - @aedgK12HowToTipHash["DL08"] = "DL8 Use Daylighting Analysis Tools to Optimize Design" - @aedgK12HowToTipHash["DL09"] = "DL9 Building Orientation" - @aedgK12HowToTipHash["DL10"] = "DL10 Ceiling Height" - @aedgK12HowToTipHash["DL11"] = "DL11 Outdoor Surface Reflectance" - @aedgK12HowToTipHash["DL12"] = "DL12 Eliminate Direct Beam Radiation" - @aedgK12HowToTipHash["DL13"] = "DL13 Daylighting Control for Audio-Visual (AV) Projection Activities" - @aedgK12HowToTipHash["DL14"] = "DL14 Interior Finishes for Daylighting" - @aedgK12HowToTipHash["DL15"] = "DL15 Calibration and Commissioning" - @aedgK12HowToTipHash["DL16"] = "DL16 Dimming Controls" - @aedgK12HowToTipHash["DL17"] = "DL17 Photosensor Placement and Lighting Layout" - @aedgK12HowToTipHash["DL18"] = "DL18 Photosensor Specifications" - @aedgK12HowToTipHash["DL19"] = "DL19 Select Compatible Light Fixtures" - @aedgK12HowToTipHash["DL20"] = "DL20 Sidelighting Patterns" - @aedgK12HowToTipHash["DL21"] = "DL21 South-Facing Classrooms-Configuration of Apertures" - @aedgK12HowToTipHash["DL22"] = "DL22 South-Facing Classrooms-Glazing Area and Fenestration Type" - @aedgK12HowToTipHash["DL23"] = "DL23 View Glazing and VTs" - @aedgK12HowToTipHash["DL24"] = "DL24 South-Facing Classrooms-Make Light Shelf Durable and Reflective" - @aedgK12HowToTipHash["DL25"] = "DL25 North-Facing Classroom-Configuration of Apertures" - @aedgK12HowToTipHash["DL26"] = "DL26 North-Facing Classroom-Glazing Area and Fenestration Type" - @aedgK12HowToTipHash["DL27"] = "DL27 South-and North-Facing Classrooms-Sloped Ceilings" - @aedgK12HowToTipHash["DL28"] = "DL28 South-and North-Facing Classrooms-Recognize the Limits of Side Daylighting" - @aedgK12HowToTipHash["DL29"] = "DL29 Classroom Toplighting Pattern" - @aedgK12HowToTipHash["DL30"] = "DL30 Sizing the Roof Monitors" - @aedgK12HowToTipHash["DL31"] = "DL31 Overhang for Roof Monitor" - @aedgK12HowToTipHash["DL32"] = "DL32 Use Light-Colored Roofing in Front of Monitors" - @aedgK12HowToTipHash["DL33"] = "DL33 Use Baffles to Block Direct Beam Radiation and Diffuse Light" - @aedgK12HowToTipHash["DL34"] = "DL34 Minimize Contrast at Well-Ceiling Intersection" - @aedgK12HowToTipHash["DL35"] = "DL35 Address the Monitor Design" - @aedgK12HowToTipHash["DL36"] = "DL36 Let the Heat Stratify" - @aedgK12HowToTipHash["DL37"] = "DL37 Minimize the Depth of the Ceiling Cavity" - @aedgK12HowToTipHash["DL38"] = "DL38 Classroom Sidelighting Plus Toplighting Pattern" - @aedgK12HowToTipHash["DL39"] = "DL39 Gym Toplighting Overview" - @aedgK12HowToTipHash["DL40"] = "DL40 Gym Toplighting Sizing" - @aedgK12HowToTipHash["DL41"] = "DL41 Gym Toplighting Using South-Facing Roof Monitors" - @aedgK12HowToTipHash["DL42"] = "DL42 Gym Toplighting in Combination with North-and South-Facing Sidelighting" + @aedgK12HowToTipHash['DL01'] = 'DL1 General Principles' + @aedgK12HowToTipHash['DL02'] = 'DL2 Consider Daylighting Early in the Design Process' + @aedgK12HowToTipHash['DL03'] = 'DL3 Space Types' + @aedgK12HowToTipHash['DL04'] = 'DL4 How to Select Daylighting Strategies' + @aedgK12HowToTipHash['DL05'] = 'DL5 Recommended Daylighting Fenestration-to-Floor Area Ratios' + @aedgK12HowToTipHash['DL06'] = 'DL6 View Windows Separate from Daylighting Strategy' + @aedgK12HowToTipHash['DL07'] = 'DL7 Lighting Design Criteria' + @aedgK12HowToTipHash['DL08'] = 'DL8 Use Daylighting Analysis Tools to Optimize Design' + @aedgK12HowToTipHash['DL09'] = 'DL9 Building Orientation' + @aedgK12HowToTipHash['DL10'] = 'DL10 Ceiling Height' + @aedgK12HowToTipHash['DL11'] = 'DL11 Outdoor Surface Reflectance' + @aedgK12HowToTipHash['DL12'] = 'DL12 Eliminate Direct Beam Radiation' + @aedgK12HowToTipHash['DL13'] = 'DL13 Daylighting Control for Audio-Visual (AV) Projection Activities' + @aedgK12HowToTipHash['DL14'] = 'DL14 Interior Finishes for Daylighting' + @aedgK12HowToTipHash['DL15'] = 'DL15 Calibration and Commissioning' + @aedgK12HowToTipHash['DL16'] = 'DL16 Dimming Controls' + @aedgK12HowToTipHash['DL17'] = 'DL17 Photosensor Placement and Lighting Layout' + @aedgK12HowToTipHash['DL18'] = 'DL18 Photosensor Specifications' + @aedgK12HowToTipHash['DL19'] = 'DL19 Select Compatible Light Fixtures' + @aedgK12HowToTipHash['DL20'] = 'DL20 Sidelighting Patterns' + @aedgK12HowToTipHash['DL21'] = 'DL21 South-Facing Classrooms-Configuration of Apertures' + @aedgK12HowToTipHash['DL22'] = 'DL22 South-Facing Classrooms-Glazing Area and Fenestration Type' + @aedgK12HowToTipHash['DL23'] = 'DL23 View Glazing and VTs' + @aedgK12HowToTipHash['DL24'] = 'DL24 South-Facing Classrooms-Make Light Shelf Durable and Reflective' + @aedgK12HowToTipHash['DL25'] = 'DL25 North-Facing Classroom-Configuration of Apertures' + @aedgK12HowToTipHash['DL26'] = 'DL26 North-Facing Classroom-Glazing Area and Fenestration Type' + @aedgK12HowToTipHash['DL27'] = 'DL27 South-and North-Facing Classrooms-Sloped Ceilings' + @aedgK12HowToTipHash['DL28'] = 'DL28 South-and North-Facing Classrooms-Recognize the Limits of Side Daylighting' + @aedgK12HowToTipHash['DL29'] = 'DL29 Classroom Toplighting Pattern' + @aedgK12HowToTipHash['DL30'] = 'DL30 Sizing the Roof Monitors' + @aedgK12HowToTipHash['DL31'] = 'DL31 Overhang for Roof Monitor' + @aedgK12HowToTipHash['DL32'] = 'DL32 Use Light-Colored Roofing in Front of Monitors' + @aedgK12HowToTipHash['DL33'] = 'DL33 Use Baffles to Block Direct Beam Radiation and Diffuse Light' + @aedgK12HowToTipHash['DL34'] = 'DL34 Minimize Contrast at Well-Ceiling Intersection' + @aedgK12HowToTipHash['DL35'] = 'DL35 Address the Monitor Design' + @aedgK12HowToTipHash['DL36'] = 'DL36 Let the Heat Stratify' + @aedgK12HowToTipHash['DL37'] = 'DL37 Minimize the Depth of the Ceiling Cavity' + @aedgK12HowToTipHash['DL38'] = 'DL38 Classroom Sidelighting Plus Toplighting Pattern' + @aedgK12HowToTipHash['DL39'] = 'DL39 Gym Toplighting Overview' + @aedgK12HowToTipHash['DL40'] = 'DL40 Gym Toplighting Sizing' + @aedgK12HowToTipHash['DL41'] = 'DL41 Gym Toplighting Using South-Facing Roof Monitors' + @aedgK12HowToTipHash['DL42'] = 'DL42 Gym Toplighting in Combination with North-and South-Facing Sidelighting' # electric lighting tips - @aedgK12HowToTipHash["EL01"] = "EL1 Light-Colored Interior Finishes" - @aedgK12HowToTipHash["EL02"] = "EL2 Color Rendering Index" - @aedgK12HowToTipHash["EL03"] = "EL3 Color Temperature" - @aedgK12HowToTipHash["EL04"] = "EL4 Linear Fluorescent Lamps and Ballasts" - @aedgK12HowToTipHash["EL05"] = "EL5 Compact Fluorescent" - @aedgK12HowToTipHash["EL06"] = "EL6 Metal Halide" - @aedgK12HowToTipHash["EL07"] = "EL7 Light-Emitting Diode (LED) Lighting" - @aedgK12HowToTipHash["EL08"] = "EL8 Occupancy Sensors" - @aedgK12HowToTipHash["EL09"] = "EL9 Multilevel Switching or Dimming" - @aedgK12HowToTipHash["EL10"] = "EL10 Exit Signs" - @aedgK12HowToTipHash["EL11"] = "EL11 Circuiting and Switching" - @aedgK12HowToTipHash["EL12"] = "EL12 Electrical Lighting Design for Schools" - @aedgK12HowToTipHash["EL13"] = "EL13 Classroom Lighting" - @aedgK12HowToTipHash["EL14"] = "EL14 Gym Lighting" - @aedgK12HowToTipHash["EL15"] = "EL15 Lighting for a Multipurpose Room" - @aedgK12HowToTipHash["EL16"] = "EL16 Lighting for a Library or Media Center" - @aedgK12HowToTipHash["EL17"] = "EL17 Corridor Lighting" - @aedgK12HowToTipHash["EL18"] = "EL18 Lighting for Offices and Teacher Support Rooms" - @aedgK12HowToTipHash["EL19"] = "EL19 Lighting for Locker Areas and Restrooms" - @aedgK12HowToTipHash["EL20"] = "EL20 Twenty-Four Hour Lighting" - @aedgK12HowToTipHash["EL21"] = "EL21 Exterior Lighting Power-Parking Lots and Drives" - @aedgK12HowToTipHash["EL22"] = "EL22 Exterior Lighting Power-Walkways" - @aedgK12HowToTipHash["EL23"] = "EL23 Decorative Façade Lighting" - @aedgK12HowToTipHash["EL24"] = "EL24 Sources" - @aedgK12HowToTipHash["EL25"] = "EL25 Controls" + @aedgK12HowToTipHash['EL01'] = 'EL1 Light-Colored Interior Finishes' + @aedgK12HowToTipHash['EL02'] = 'EL2 Color Rendering Index' + @aedgK12HowToTipHash['EL03'] = 'EL3 Color Temperature' + @aedgK12HowToTipHash['EL04'] = 'EL4 Linear Fluorescent Lamps and Ballasts' + @aedgK12HowToTipHash['EL05'] = 'EL5 Compact Fluorescent' + @aedgK12HowToTipHash['EL06'] = 'EL6 Metal Halide' + @aedgK12HowToTipHash['EL07'] = 'EL7 Light-Emitting Diode (LED) Lighting' + @aedgK12HowToTipHash['EL08'] = 'EL8 Occupancy Sensors' + @aedgK12HowToTipHash['EL09'] = 'EL9 Multilevel Switching or Dimming' + @aedgK12HowToTipHash['EL10'] = 'EL10 Exit Signs' + @aedgK12HowToTipHash['EL11'] = 'EL11 Circuiting and Switching' + @aedgK12HowToTipHash['EL12'] = 'EL12 Electrical Lighting Design for Schools' + @aedgK12HowToTipHash['EL13'] = 'EL13 Classroom Lighting' + @aedgK12HowToTipHash['EL14'] = 'EL14 Gym Lighting' + @aedgK12HowToTipHash['EL15'] = 'EL15 Lighting for a Multipurpose Room' + @aedgK12HowToTipHash['EL16'] = 'EL16 Lighting for a Library or Media Center' + @aedgK12HowToTipHash['EL17'] = 'EL17 Corridor Lighting' + @aedgK12HowToTipHash['EL18'] = 'EL18 Lighting for Offices and Teacher Support Rooms' + @aedgK12HowToTipHash['EL19'] = 'EL19 Lighting for Locker Areas and Restrooms' + @aedgK12HowToTipHash['EL20'] = 'EL20 Twenty-Four Hour Lighting' + @aedgK12HowToTipHash['EL21'] = 'EL21 Exterior Lighting Power-Parking Lots and Drives' + @aedgK12HowToTipHash['EL22'] = 'EL22 Exterior Lighting Power-Walkways' + @aedgK12HowToTipHash['EL23'] = 'EL23 Decorative Façade Lighting' + @aedgK12HowToTipHash['EL24'] = 'EL24 Sources' + @aedgK12HowToTipHash['EL25'] = 'EL25 Controls' # plug load tips - @aedgK12HowToTipHash["PL01"] = "PL1 General Guidance" - @aedgK12HowToTipHash["PL02"] = "PL2 Computer (Information Technology) Equipment" - @aedgK12HowToTipHash["PL03"] = "PL3 Staff and Occupant Equipment Control" - @aedgK12HowToTipHash["PL04"] = "PL4 Phantom/Parasitic Loads" - @aedgK12HowToTipHash["PL05"] = "PL5 ENERGY STAR Appliances/Equipment" - @aedgK12HowToTipHash["PL06"] = "PL6 Electrical Distribution System" + @aedgK12HowToTipHash['PL01'] = 'PL1 General Guidance' + @aedgK12HowToTipHash['PL02'] = 'PL2 Computer (Information Technology) Equipment' + @aedgK12HowToTipHash['PL03'] = 'PL3 Staff and Occupant Equipment Control' + @aedgK12HowToTipHash['PL04'] = 'PL4 Phantom/Parasitic Loads' + @aedgK12HowToTipHash['PL05'] = 'PL5 ENERGY STAR Appliances/Equipment' + @aedgK12HowToTipHash['PL06'] = 'PL6 Electrical Distribution System' # kitchen tips - @aedgK12HowToTipHash["KE01"] = "KE1 General Guidance" - @aedgK12HowToTipHash["KE02"] = "KE2 Energy-Efficient Kitchen Equipment" - @aedgK12HowToTipHash["KE03"] = "KE3 Exhaust and Ventilation Energy Use" - @aedgK12HowToTipHash["KE04"] = "KE4 Minimize Hot-Water Use" - @aedgK12HowToTipHash["KE05"] = "KE5 High-Efficiency Walk-in Refrigeration Systems" - @aedgK12HowToTipHash["KE06"] = "KE6 Position Hooded Appliances to Achieve Lower Exhaust Rates" - @aedgK12HowToTipHash["KE07"] = "KE7 Operating Considerations" + @aedgK12HowToTipHash['KE01'] = 'KE1 General Guidance' + @aedgK12HowToTipHash['KE02'] = 'KE2 Energy-Efficient Kitchen Equipment' + @aedgK12HowToTipHash['KE03'] = 'KE3 Exhaust and Ventilation Energy Use' + @aedgK12HowToTipHash['KE04'] = 'KE4 Minimize Hot-Water Use' + @aedgK12HowToTipHash['KE05'] = 'KE5 High-Efficiency Walk-in Refrigeration Systems' + @aedgK12HowToTipHash['KE06'] = 'KE6 Position Hooded Appliances to Achieve Lower Exhaust Rates' + @aedgK12HowToTipHash['KE07'] = 'KE7 Operating Considerations' # service water heating tips - @aedgK12HowToTipHash["WH01"] = "WH1 Service Water -Heating Types" - @aedgK12HowToTipHash["WH02"] = "WH2 System Descriptions" - @aedgK12HowToTipHash["WH03"] = "WH3 Sizing" - @aedgK12HowToTipHash["WH04"] = "WH4 Equipment Efficiency" - @aedgK12HowToTipHash["WH05"] = "WH5 Location" - @aedgK12HowToTipHash["WH06"] = "WH6 Pipe Insulation" - @aedgK12HowToTipHash["WH07"] = "WH7 Solar Hot-Water Systems" + @aedgK12HowToTipHash['WH01'] = 'WH1 Service Water -Heating Types' + @aedgK12HowToTipHash['WH02'] = 'WH2 System Descriptions' + @aedgK12HowToTipHash['WH03'] = 'WH3 Sizing' + @aedgK12HowToTipHash['WH04'] = 'WH4 Equipment Efficiency' + @aedgK12HowToTipHash['WH05'] = 'WH5 Location' + @aedgK12HowToTipHash['WH06'] = 'WH6 Pipe Insulation' + @aedgK12HowToTipHash['WH07'] = 'WH7 Solar Hot-Water Systems' # hvac tips - @aedgK12HowToTipHash["HV01"] = "HV1 Ground-Source Heat Pump System" - @aedgK12HowToTipHash["HV02"] = "HV2 Fan-Coil System" - @aedgK12HowToTipHash["HV03"] = "HV3 Multiple-Zone, Variable-Air-Volume (VAV) Air Handlers" - @aedgK12HowToTipHash["HV04"] = "HV4 Dedicated Outdoor Air System (DOAS)" - @aedgK12HowToTipHash["HV05"] = "HV5 Exhaust Air Energy Recovery" - @aedgK12HowToTipHash["HV06"] = "HV6 Chilled-Water System" - @aedgK12HowToTipHash["HV07"] = "HV7 Water Heating System" - @aedgK12HowToTipHash["HV08"] = "HV8 Condenser-Water System for GSHPs" - @aedgK12HowToTipHash["HV09"] = "HV9 Cooling and Heating Load Calculations" - @aedgK12HowToTipHash["HV10"] = "HV10 Ventilation Air" - @aedgK12HowToTipHash["HV11"] = "HV11 Cooling and Heating Equipment Efficiencies" - @aedgK12HowToTipHash["HV12"] = "HV12 Fan Power and Motor Efficiencies" - @aedgK12HowToTipHash["HV13"] = "HV13 Part-Load Dehumidification" - @aedgK12HowToTipHash["HV14"] = "HV14 Economizer" - @aedgK12HowToTipHash["HV15"] = "HV15 Demand-Controlled Ventilation" - @aedgK12HowToTipHash["HV16"] = "HV16 System-Level Control Strategies" - @aedgK12HowToTipHash["HV17"] = "HV17 Thermal Zoning" - @aedgK12HowToTipHash["HV18"] = "HV18 Ductwork Design and Construction" - @aedgK12HowToTipHash["HV19"] = "HV19 Duct Insulation" - @aedgK12HowToTipHash["HV20"] = "HV20 Duct Sealing and Leakage Testing" - @aedgK12HowToTipHash["HV21"] = "HV21 Exhaust Air Systems" - @aedgK12HowToTipHash["HV22"] = "HV22 Testing, Adjusting, and Balancing" - @aedgK12HowToTipHash["HV23"] = "HV23 Air Cleaning" - @aedgK12HowToTipHash["HV24"] = "HV24 Relief versus Return Fans" - @aedgK12HowToTipHash["HV25"] = "HV25 Zone Temperature Control" - @aedgK12HowToTipHash["HV26"] = "HV26 Heating Sources" - @aedgK12HowToTipHash["HV27"] = "HV27 Noise Control" - @aedgK12HowToTipHash["HV28"] = "HV28 Proper Maintenance" + @aedgK12HowToTipHash['HV01'] = 'HV1 Ground-Source Heat Pump System' + @aedgK12HowToTipHash['HV02'] = 'HV2 Fan-Coil System' + @aedgK12HowToTipHash['HV03'] = 'HV3 Multiple-Zone, Variable-Air-Volume (VAV) Air Handlers' + @aedgK12HowToTipHash['HV04'] = 'HV4 Dedicated Outdoor Air System (DOAS)' + @aedgK12HowToTipHash['HV05'] = 'HV5 Exhaust Air Energy Recovery' + @aedgK12HowToTipHash['HV06'] = 'HV6 Chilled-Water System' + @aedgK12HowToTipHash['HV07'] = 'HV7 Water Heating System' + @aedgK12HowToTipHash['HV08'] = 'HV8 Condenser-Water System for GSHPs' + @aedgK12HowToTipHash['HV09'] = 'HV9 Cooling and Heating Load Calculations' + @aedgK12HowToTipHash['HV10'] = 'HV10 Ventilation Air' + @aedgK12HowToTipHash['HV11'] = 'HV11 Cooling and Heating Equipment Efficiencies' + @aedgK12HowToTipHash['HV12'] = 'HV12 Fan Power and Motor Efficiencies' + @aedgK12HowToTipHash['HV13'] = 'HV13 Part-Load Dehumidification' + @aedgK12HowToTipHash['HV14'] = 'HV14 Economizer' + @aedgK12HowToTipHash['HV15'] = 'HV15 Demand-Controlled Ventilation' + @aedgK12HowToTipHash['HV16'] = 'HV16 System-Level Control Strategies' + @aedgK12HowToTipHash['HV17'] = 'HV17 Thermal Zoning' + @aedgK12HowToTipHash['HV18'] = 'HV18 Ductwork Design and Construction' + @aedgK12HowToTipHash['HV19'] = 'HV19 Duct Insulation' + @aedgK12HowToTipHash['HV20'] = 'HV20 Duct Sealing and Leakage Testing' + @aedgK12HowToTipHash['HV21'] = 'HV21 Exhaust Air Systems' + @aedgK12HowToTipHash['HV22'] = 'HV22 Testing, Adjusting, and Balancing' + @aedgK12HowToTipHash['HV23'] = 'HV23 Air Cleaning' + @aedgK12HowToTipHash['HV24'] = 'HV24 Relief versus Return Fans' + @aedgK12HowToTipHash['HV25'] = 'HV25 Zone Temperature Control' + @aedgK12HowToTipHash['HV26'] = 'HV26 Heating Sources' + @aedgK12HowToTipHash['HV27'] = 'HV27 Noise Control' + @aedgK12HowToTipHash['HV28'] = 'HV28 Proper Maintenance' # bonus hvac tips - @aedgK12HowToTipHash["HV29"] = "HV29 Natural Ventilation and Naturally Conditioned Spaces" - @aedgK12HowToTipHash["HV30"] = "HV30 Thermal Storage" - @aedgK12HowToTipHash["HV31"] = "HV31 Thermal Mass" - @aedgK12HowToTipHash["HV32"] = "HV32 Thermal Displacement Ventilation" - @aedgK12HowToTipHash["HV33"] = "HV33 ASHRAE Standard 62.1 IAQ Procedure" - @aedgK12HowToTipHash["HV34"] = "HV34 Evaporative Cooling" + @aedgK12HowToTipHash['HV29'] = 'HV29 Natural Ventilation and Naturally Conditioned Spaces' + @aedgK12HowToTipHash['HV30'] = 'HV30 Thermal Storage' + @aedgK12HowToTipHash['HV31'] = 'HV31 Thermal Mass' + @aedgK12HowToTipHash['HV32'] = 'HV32 Thermal Displacement Ventilation' + @aedgK12HowToTipHash['HV33'] = 'HV33 ASHRAE Standard 62.1 IAQ Procedure' + @aedgK12HowToTipHash['HV34'] = 'HV34 Evaporative Cooling' # commissioning tips - @aedgK12HowToTipHash["QA01"] = "QA1 Design and Construction Team" - @aedgK12HowToTipHash["QA02"] = "QA2 Owner’s Project Requirements and Basis of Design" - @aedgK12HowToTipHash["QA03"] = "QA3 Selection of Quality Assurance Provider" - @aedgK12HowToTipHash["QA04"] = "QA4 Design and Construction Schedule" - @aedgK12HowToTipHash["QA05"] = "QA5 Design Review" - @aedgK12HowToTipHash["QA06"] = "QA6 Defining Quality Assurance at Pre-Bid" - @aedgK12HowToTipHash["QA07"] = "QA7 Verifying Building Envelope Construction" - @aedgK12HowToTipHash["QA08"] = "QA8 Verifying Lighting Construction" - @aedgK12HowToTipHash["QA09"] = "QA9 Verifying Electrical and HVAC Systems Construction" - @aedgK12HowToTipHash["QA10"] = "QA10 Functional Performance Testing" - @aedgK12HowToTipHash["QA11"] = "QA11 Substantial Completion" - @aedgK12HowToTipHash["QA12"] = "QA12 Final Acceptance" - @aedgK12HowToTipHash["QA13"] = "QA13 Establish Building Operation and Maintenance Program" - @aedgK12HowToTipHash["QA14"] = "QA14 Monitor Post-Occupancy Performance" - @aedgK12HowToTipHash["QA15"] = "QA15 M&V Electrical Panel Guidance" - @aedgK12HowToTipHash["QA16"] = "QA16 M&V Data Management and Access" - @aedgK12HowToTipHash["QA17"] = "QA17 M&V Benchmarking" - @aedgK12HowToTipHash["QA18"] = "QA18 The Building as a Teaching Tool" + @aedgK12HowToTipHash['QA01'] = 'QA1 Design and Construction Team' + @aedgK12HowToTipHash['QA02'] = 'QA2 Owner’s Project Requirements and Basis of Design' + @aedgK12HowToTipHash['QA03'] = 'QA3 Selection of Quality Assurance Provider' + @aedgK12HowToTipHash['QA04'] = 'QA4 Design and Construction Schedule' + @aedgK12HowToTipHash['QA05'] = 'QA5 Design Review' + @aedgK12HowToTipHash['QA06'] = 'QA6 Defining Quality Assurance at Pre-Bid' + @aedgK12HowToTipHash['QA07'] = 'QA7 Verifying Building Envelope Construction' + @aedgK12HowToTipHash['QA08'] = 'QA8 Verifying Lighting Construction' + @aedgK12HowToTipHash['QA09'] = 'QA9 Verifying Electrical and HVAC Systems Construction' + @aedgK12HowToTipHash['QA10'] = 'QA10 Functional Performance Testing' + @aedgK12HowToTipHash['QA11'] = 'QA11 Substantial Completion' + @aedgK12HowToTipHash['QA12'] = 'QA12 Final Acceptance' + @aedgK12HowToTipHash['QA13'] = 'QA13 Establish Building Operation and Maintenance Program' + @aedgK12HowToTipHash['QA14'] = 'QA14 Monitor Post-Occupancy Performance' + @aedgK12HowToTipHash['QA15'] = 'QA15 M&V Electrical Panel Guidance' + @aedgK12HowToTipHash['QA16'] = 'QA16 M&V Data Management and Access' + @aedgK12HowToTipHash['QA17'] = 'QA17 M&V Benchmarking' + @aedgK12HowToTipHash['QA18'] = 'QA18 The Building as a Teaching Tool' # renewable energy tips - @aedgK12HowToTipHash["RE01"] = "RE1 Photovoltaic (PV) Systems" - @aedgK12HowToTipHash["RE02"] = "RE2 Solar Hot Water Systems" - @aedgK12HowToTipHash["RE03"] = "RE3 Wind Turbine Power" + @aedgK12HowToTipHash['RE01'] = 'RE1 Photovoltaic (PV) Systems' + @aedgK12HowToTipHash['RE02'] = 'RE2 Solar Hot Water Systems' + @aedgK12HowToTipHash['RE03'] = 'RE3 Wind Turbine Power' result = @aedgK12HowToTipHash return result + end # end of OsLib_AedgMeasures.getK12Tips - end #end of OsLib_AedgMeasures.getK12Tips - - - #hash of how to tips for small to medium office buildings AEDG - def OsLib_AedgMeasures.getSmMdOffTips - + # hash of how to tips for small to medium office buildings AEDG + def self.getSmMdOffTips # envelope tips - aedgSmMdOffHowToTipHash = Hash.new("Small and Medium Offices AEDG How to Implement Recommendations") - aedgSmMdOffHowToTipHash["EN01"] = "EN1 Cool Roofs" - aedgSmMdOffHowToTipHash["EN02"] = "EN2 Roofs-Insulation Entirely above Deck" - aedgSmMdOffHowToTipHash["EN03"] = "EN3 Roofs-Attics, and Other Roofs" - aedgSmMdOffHowToTipHash["EN04"] = "EN4 Roofs-Metal Buildings" - aedgSmMdOffHowToTipHash["EN05"] = "EN5 Walls-Mass" - aedgSmMdOffHowToTipHash["EN06"] = "EN6 Walls-Steel Framed" - aedgSmMdOffHowToTipHash["EN07"] = "EN7 Walls-Wood Frame and Other" - aedgSmMdOffHowToTipHash["EN08"] = "EN8 Walls-Metal Building" - aedgSmMdOffHowToTipHash["EN09"] = "EN9 Walls-Below-Grade" - aedgSmMdOffHowToTipHash["EN10"] = "EN10 Floors-Mass" - aedgSmMdOffHowToTipHash["EN11"] = "EN11 Floors-Metal Joist or Wood Joist/Wood Frame" - aedgSmMdOffHowToTipHash["EN12"] = "EN12 Slab-on-Grade Floors-Unheated" - aedgSmMdOffHowToTipHash["EN13"] = "EN13 Slab-on-Grade Floors-Heated" - aedgSmMdOffHowToTipHash["EN14"] = "EN14 Slab Edge Insulation" - aedgSmMdOffHowToTipHash["EN15"] = "EN15 Doors-Opaque, Swinging" - aedgSmMdOffHowToTipHash["EN16"] = "EN16 Doors-Opaque, Roll-Up, or Sliding" - aedgSmMdOffHowToTipHash["EN17"] = "EN17 Air Infiltration Control" - aedgSmMdOffHowToTipHash["EN18"] = "EN18 Vestibules" - aedgSmMdOffHowToTipHash["EN19"] = "EN19 Alternative Constructions" - aedgSmMdOffHowToTipHash["EN20"] = "EN20 Truss Heel Heights" - aedgSmMdOffHowToTipHash["EN21"] = "EN21 Moisture Control" - aedgSmMdOffHowToTipHash["EN22"] = "EN22 Thermal Bridging-Opaque Components" - aedgSmMdOffHowToTipHash["EN23"] = "EN23 Thermal Bridging-Fenestration" - aedgSmMdOffHowToTipHash["EN24"] = "EN24 Vertical Fenestration Descriptions" - aedgSmMdOffHowToTipHash["EN25"] = "EN25 Window-to-Wall Ratio (WWR)" - aedgSmMdOffHowToTipHash["EN26"] = "EN26 Unwanted Solar Heat Gain Is Most Effectively Controlled on the Outside of the Building" - aedgSmMdOffHowToTipHash["EN27"] = "EN27 Operable versus Fixed Windows" - aedgSmMdOffHowToTipHash["EN28"] = "EN28 Building Form and Window Orientation" - aedgSmMdOffHowToTipHash["EN29"] = "EN29 Glazing" - aedgSmMdOffHowToTipHash["EN30"] = "EN30 Obstructions and Planting" - aedgSmMdOffHowToTipHash["EN31"] = "EN31 Window Orientation" - aedgSmMdOffHowToTipHash["EN32"] = "EN32 Passive Solar" - aedgSmMdOffHowToTipHash["EN33"] = "EN33 Glazing" - aedgSmMdOffHowToTipHash["EN34"] = "EN34 Visible Transmittance (VT)" - aedgSmMdOffHowToTipHash["EN35"] = "EN35 Separating Views and Daylight" - aedgSmMdOffHowToTipHash["EN36"] = "EN36 Color-Neutral Glazing" - aedgSmMdOffHowToTipHash["EN37"] = "EN37 Reflectivity of Glass" - aedgSmMdOffHowToTipHash["EN38"] = "EN38 Light-to-Solar-Gain Ratio" - aedgSmMdOffHowToTipHash["EN39"] = "EN39 High Ceilings" - aedgSmMdOffHowToTipHash["EN40"] = "EN40 Light Shelves" + aedgSmMdOffHowToTipHash = Hash.new('Small and Medium Offices AEDG How to Implement Recommendations') + aedgSmMdOffHowToTipHash['EN01'] = 'EN1 Cool Roofs' + aedgSmMdOffHowToTipHash['EN02'] = 'EN2 Roofs-Insulation Entirely above Deck' + aedgSmMdOffHowToTipHash['EN03'] = 'EN3 Roofs-Attics, and Other Roofs' + aedgSmMdOffHowToTipHash['EN04'] = 'EN4 Roofs-Metal Buildings' + aedgSmMdOffHowToTipHash['EN05'] = 'EN5 Walls-Mass' + aedgSmMdOffHowToTipHash['EN06'] = 'EN6 Walls-Steel Framed' + aedgSmMdOffHowToTipHash['EN07'] = 'EN7 Walls-Wood Frame and Other' + aedgSmMdOffHowToTipHash['EN08'] = 'EN8 Walls-Metal Building' + aedgSmMdOffHowToTipHash['EN09'] = 'EN9 Walls-Below-Grade' + aedgSmMdOffHowToTipHash['EN10'] = 'EN10 Floors-Mass' + aedgSmMdOffHowToTipHash['EN11'] = 'EN11 Floors-Metal Joist or Wood Joist/Wood Frame' + aedgSmMdOffHowToTipHash['EN12'] = 'EN12 Slab-on-Grade Floors-Unheated' + aedgSmMdOffHowToTipHash['EN13'] = 'EN13 Slab-on-Grade Floors-Heated' + aedgSmMdOffHowToTipHash['EN14'] = 'EN14 Slab Edge Insulation' + aedgSmMdOffHowToTipHash['EN15'] = 'EN15 Doors-Opaque, Swinging' + aedgSmMdOffHowToTipHash['EN16'] = 'EN16 Doors-Opaque, Roll-Up, or Sliding' + aedgSmMdOffHowToTipHash['EN17'] = 'EN17 Air Infiltration Control' + aedgSmMdOffHowToTipHash['EN18'] = 'EN18 Vestibules' + aedgSmMdOffHowToTipHash['EN19'] = 'EN19 Alternative Constructions' + aedgSmMdOffHowToTipHash['EN20'] = 'EN20 Truss Heel Heights' + aedgSmMdOffHowToTipHash['EN21'] = 'EN21 Moisture Control' + aedgSmMdOffHowToTipHash['EN22'] = 'EN22 Thermal Bridging-Opaque Components' + aedgSmMdOffHowToTipHash['EN23'] = 'EN23 Thermal Bridging-Fenestration' + aedgSmMdOffHowToTipHash['EN24'] = 'EN24 Vertical Fenestration Descriptions' + aedgSmMdOffHowToTipHash['EN25'] = 'EN25 Window-to-Wall Ratio (WWR)' + aedgSmMdOffHowToTipHash['EN26'] = 'EN26 Unwanted Solar Heat Gain Is Most Effectively Controlled on the Outside of the Building' + aedgSmMdOffHowToTipHash['EN27'] = 'EN27 Operable versus Fixed Windows' + aedgSmMdOffHowToTipHash['EN28'] = 'EN28 Building Form and Window Orientation' + aedgSmMdOffHowToTipHash['EN29'] = 'EN29 Glazing' + aedgSmMdOffHowToTipHash['EN30'] = 'EN30 Obstructions and Planting' + aedgSmMdOffHowToTipHash['EN31'] = 'EN31 Window Orientation' + aedgSmMdOffHowToTipHash['EN32'] = 'EN32 Passive Solar' + aedgSmMdOffHowToTipHash['EN33'] = 'EN33 Glazing' + aedgSmMdOffHowToTipHash['EN34'] = 'EN34 Visible Transmittance (VT)' + aedgSmMdOffHowToTipHash['EN35'] = 'EN35 Separating Views and Daylight' + aedgSmMdOffHowToTipHash['EN36'] = 'EN36 Color-Neutral Glazing' + aedgSmMdOffHowToTipHash['EN37'] = 'EN37 Reflectivity of Glass' + aedgSmMdOffHowToTipHash['EN38'] = 'EN38 Light-to-Solar-Gain Ratio' + aedgSmMdOffHowToTipHash['EN39'] = 'EN39 High Ceilings' + aedgSmMdOffHowToTipHash['EN40'] = 'EN40 Light Shelves' # daylighting tips - aedgSmMdOffHowToTipHash["DL01"] = "DL1 Daylighting Early in the Design Process" - aedgSmMdOffHowToTipHash["DL02"] = "DL2 Daylighting Analysis Tools to Optimize Design" - aedgSmMdOffHowToTipHash["DL03"] = "DL3 Space Types, Layout, and Daylight" - aedgSmMdOffHowToTipHash["DL04"] = "DL4 Building Orientation and Daylight" - aedgSmMdOffHowToTipHash["DL05"] = "DL5 Building Shape and Daylight" - aedgSmMdOffHowToTipHash["DL06"] = "DL6 Window-to-Wall Ratio (WWR)" - aedgSmMdOffHowToTipHash["DL07"] = "DL7 Sidelighting-Ceiling and Window Height" - aedgSmMdOffHowToTipHash["DL08"] = "Sidelighting-Clerestory Windows" - aedgSmMdOffHowToTipHash["DL09"] = "DL9 Sidelighting-Borrowed Light" - aedgSmMdOffHowToTipHash["DL10"] = "DL10 Sidelighting-Wall-to-Wall Windows" - aedgSmMdOffHowToTipHash["DL11"] = "DL11 Sidelighting-Punched Windows" - aedgSmMdOffHowToTipHash["DL12"] = "DL12 Shading Systems to Eliminate Direct-Beam Radiation" - aedgSmMdOffHowToTipHash["DL13"] = "DL13 Daylighting Control for Audiovisual Activities" - aedgSmMdOffHowToTipHash["DL14"] = "DL14 Interior Finishes for Daylighting" - aedgSmMdOffHowToTipHash["DL15"] = "DL15 Outdoor Surface Reflectance" - aedgSmMdOffHowToTipHash["DL16"] = "DL16 Calibration and Commissioning" - aedgSmMdOffHowToTipHash["DL17"] = "DL17 Dimming Controls" - aedgSmMdOffHowToTipHash["DL18"] = "DL18 Photosensor Placement and Lighting Layout" - aedgSmMdOffHowToTipHash["DL19"] = "DL19 Photosensor Specifications" - aedgSmMdOffHowToTipHash["DL20"] = "DL20 Select Compatible Light Fixtures" + aedgSmMdOffHowToTipHash['DL01'] = 'DL1 Daylighting Early in the Design Process' + aedgSmMdOffHowToTipHash['DL02'] = 'DL2 Daylighting Analysis Tools to Optimize Design' + aedgSmMdOffHowToTipHash['DL03'] = 'DL3 Space Types, Layout, and Daylight' + aedgSmMdOffHowToTipHash['DL04'] = 'DL4 Building Orientation and Daylight' + aedgSmMdOffHowToTipHash['DL05'] = 'DL5 Building Shape and Daylight' + aedgSmMdOffHowToTipHash['DL06'] = 'DL6 Window-to-Wall Ratio (WWR)' + aedgSmMdOffHowToTipHash['DL07'] = 'DL7 Sidelighting-Ceiling and Window Height' + aedgSmMdOffHowToTipHash['DL08'] = 'Sidelighting-Clerestory Windows' + aedgSmMdOffHowToTipHash['DL09'] = 'DL9 Sidelighting-Borrowed Light' + aedgSmMdOffHowToTipHash['DL10'] = 'DL10 Sidelighting-Wall-to-Wall Windows' + aedgSmMdOffHowToTipHash['DL11'] = 'DL11 Sidelighting-Punched Windows' + aedgSmMdOffHowToTipHash['DL12'] = 'DL12 Shading Systems to Eliminate Direct-Beam Radiation' + aedgSmMdOffHowToTipHash['DL13'] = 'DL13 Daylighting Control for Audiovisual Activities' + aedgSmMdOffHowToTipHash['DL14'] = 'DL14 Interior Finishes for Daylighting' + aedgSmMdOffHowToTipHash['DL15'] = 'DL15 Outdoor Surface Reflectance' + aedgSmMdOffHowToTipHash['DL16'] = 'DL16 Calibration and Commissioning' + aedgSmMdOffHowToTipHash['DL17'] = 'DL17 Dimming Controls' + aedgSmMdOffHowToTipHash['DL18'] = 'DL18 Photosensor Placement and Lighting Layout' + aedgSmMdOffHowToTipHash['DL19'] = 'DL19 Photosensor Specifications' + aedgSmMdOffHowToTipHash['DL20'] = 'DL20 Select Compatible Light Fixtures' # bonus daylighting tips - aedgSmMdOffHowToTipHash["DL21"] = "DL21 Toplighting" - aedgSmMdOffHowToTipHash["DL22"] = "DL22 Rooftop Monitors" - aedgSmMdOffHowToTipHash["DL23"] = "DL23 Rooftop Monitor Design" - aedgSmMdOffHowToTipHash["DL24"] = "DL24 Skylights" - aedgSmMdOffHowToTipHash["DL25"] = "DL25 Toplighting-Thermal Transmittance (Climate Zones 1-3)" - aedgSmMdOffHowToTipHash["DL26"] = "DL26 Toplighting-Thermal Transmittance (Climate Zones 4-8)" - aedgSmMdOffHowToTipHash["DL27"] = "DL27 Toplighting-Ceiling Height Differentials" + aedgSmMdOffHowToTipHash['DL21'] = 'DL21 Toplighting' + aedgSmMdOffHowToTipHash['DL22'] = 'DL22 Rooftop Monitors' + aedgSmMdOffHowToTipHash['DL23'] = 'DL23 Rooftop Monitor Design' + aedgSmMdOffHowToTipHash['DL24'] = 'DL24 Skylights' + aedgSmMdOffHowToTipHash['DL25'] = 'DL25 Toplighting-Thermal Transmittance (Climate Zones 1-3)' + aedgSmMdOffHowToTipHash['DL26'] = 'DL26 Toplighting-Thermal Transmittance (Climate Zones 4-8)' + aedgSmMdOffHowToTipHash['DL27'] = 'DL27 Toplighting-Ceiling Height Differentials' # electric lighting tips - aedgSmMdOffHowToTipHash["EL01"] = "EL1 Savings and Occupant Acceptance" - aedgSmMdOffHowToTipHash["EL02"] = "EL2 Space Planning-Open Offices" - aedgSmMdOffHowToTipHash["EL03"] = "EL3 Space Planning-Private Offices, Conference Rooms, and Break Rooms" - aedgSmMdOffHowToTipHash["EL04"] = "EL4 Light-Colored Interior Finishes" - aedgSmMdOffHowToTipHash["EL05"] = "EL5 Task Lighting" - aedgSmMdOffHowToTipHash["EL06"] = "EL6 Color Rendering Index (CRI)" - aedgSmMdOffHowToTipHash["EL07"] = "EL7 Color Temperature" - aedgSmMdOffHowToTipHash["EL08"] = "EL8 Linear Fluorescent Lamps and Ballasts" - aedgSmMdOffHowToTipHash["EL09"] = "EL9 Occupancy Sensors" - aedgSmMdOffHowToTipHash["EL10"] = "EL10 Multilevel Switching" - aedgSmMdOffHowToTipHash["EL11"] = "EL11 Daylight-Responsive Controls" - aedgSmMdOffHowToTipHash["EL12"] = "EL12 Exit Signs" - aedgSmMdOffHowToTipHash["EL13"] = "EL13 Light Fixture Distribution" - aedgSmMdOffHowToTipHash["EL14"] = "EL14 Open-Plan Offices" - aedgSmMdOffHowToTipHash["EL15"] = "EL15 Private Offices" - aedgSmMdOffHowToTipHash["EL16"] = "EL16 Conference Rooms/Meeting Rooms" - aedgSmMdOffHowToTipHash["EL17"] = "EL17 Corridors" - aedgSmMdOffHowToTipHash["EL18"] = "EL18 Storage Areas" - aedgSmMdOffHowToTipHash["EL19"] = "EL19 Lobbies" - aedgSmMdOffHowToTipHash["EL20"] = "EL20 Twenty-Four Hour Lighting" - aedgSmMdOffHowToTipHash["EL21"] = "EL21 Exterior Lighting Power-Parking Lots and Drives" - aedgSmMdOffHowToTipHash["EL22"] = "EL22 Exterior Lighting Power-Walkways" - aedgSmMdOffHowToTipHash["EL23"] = "EL23 Decorative Façade Lighting" - aedgSmMdOffHowToTipHash["EL24"] = "EL24 Sources" - aedgSmMdOffHowToTipHash["EL25"] = "EL25 Controls" + aedgSmMdOffHowToTipHash['EL01'] = 'EL1 Savings and Occupant Acceptance' + aedgSmMdOffHowToTipHash['EL02'] = 'EL2 Space Planning-Open Offices' + aedgSmMdOffHowToTipHash['EL03'] = 'EL3 Space Planning-Private Offices, Conference Rooms, and Break Rooms' + aedgSmMdOffHowToTipHash['EL04'] = 'EL4 Light-Colored Interior Finishes' + aedgSmMdOffHowToTipHash['EL05'] = 'EL5 Task Lighting' + aedgSmMdOffHowToTipHash['EL06'] = 'EL6 Color Rendering Index (CRI)' + aedgSmMdOffHowToTipHash['EL07'] = 'EL7 Color Temperature' + aedgSmMdOffHowToTipHash['EL08'] = 'EL8 Linear Fluorescent Lamps and Ballasts' + aedgSmMdOffHowToTipHash['EL09'] = 'EL9 Occupancy Sensors' + aedgSmMdOffHowToTipHash['EL10'] = 'EL10 Multilevel Switching' + aedgSmMdOffHowToTipHash['EL11'] = 'EL11 Daylight-Responsive Controls' + aedgSmMdOffHowToTipHash['EL12'] = 'EL12 Exit Signs' + aedgSmMdOffHowToTipHash['EL13'] = 'EL13 Light Fixture Distribution' + aedgSmMdOffHowToTipHash['EL14'] = 'EL14 Open-Plan Offices' + aedgSmMdOffHowToTipHash['EL15'] = 'EL15 Private Offices' + aedgSmMdOffHowToTipHash['EL16'] = 'EL16 Conference Rooms/Meeting Rooms' + aedgSmMdOffHowToTipHash['EL17'] = 'EL17 Corridors' + aedgSmMdOffHowToTipHash['EL18'] = 'EL18 Storage Areas' + aedgSmMdOffHowToTipHash['EL19'] = 'EL19 Lobbies' + aedgSmMdOffHowToTipHash['EL20'] = 'EL20 Twenty-Four Hour Lighting' + aedgSmMdOffHowToTipHash['EL21'] = 'EL21 Exterior Lighting Power-Parking Lots and Drives' + aedgSmMdOffHowToTipHash['EL22'] = 'EL22 Exterior Lighting Power-Walkways' + aedgSmMdOffHowToTipHash['EL23'] = 'EL23 Decorative Façade Lighting' + aedgSmMdOffHowToTipHash['EL24'] = 'EL24 Sources' + aedgSmMdOffHowToTipHash['EL25'] = 'EL25 Controls' # plug load tips - aedgSmMdOffHowToTipHash["PL01"] = "PL1 Connected Wattage" - aedgSmMdOffHowToTipHash["PL02"] = "PL2 Laptop Computers" - aedgSmMdOffHowToTipHash["PL03"] = "PL3 Occupancy Controls" - aedgSmMdOffHowToTipHash["PL04"] = "PL4 Parasitic Loads" - aedgSmMdOffHowToTipHash["PL05"] = "PL5 Printing Equipment" - aedgSmMdOffHowToTipHash["PL06"] = "PL6 Unnecessary Equipment" + aedgSmMdOffHowToTipHash['PL01'] = 'PL1 Connected Wattage' + aedgSmMdOffHowToTipHash['PL02'] = 'PL2 Laptop Computers' + aedgSmMdOffHowToTipHash['PL03'] = 'PL3 Occupancy Controls' + aedgSmMdOffHowToTipHash['PL04'] = 'PL4 Parasitic Loads' + aedgSmMdOffHowToTipHash['PL05'] = 'PL5 Printing Equipment' + aedgSmMdOffHowToTipHash['PL06'] = 'PL6 Unnecessary Equipment' # service water heating tips - aedgSmMdOffHowToTipHash["WH01"] = "WH1 Service Water Heating Types" - aedgSmMdOffHowToTipHash["WH02"] = "WH2 System Descriptions" - aedgSmMdOffHowToTipHash["WH03"] = "WH3 Sizing" - aedgSmMdOffHowToTipHash["WH04"] = "WH4 Equipment Efficiency" - aedgSmMdOffHowToTipHash["WH05"] = "WH5 Location" - aedgSmMdOffHowToTipHash["WH06"] = "WH6 Pipe Insulation" + aedgSmMdOffHowToTipHash['WH01'] = 'WH1 Service Water Heating Types' + aedgSmMdOffHowToTipHash['WH02'] = 'WH2 System Descriptions' + aedgSmMdOffHowToTipHash['WH03'] = 'WH3 Sizing' + aedgSmMdOffHowToTipHash['WH04'] = 'WH4 Equipment Efficiency' + aedgSmMdOffHowToTipHash['WH05'] = 'WH5 Location' + aedgSmMdOffHowToTipHash['WH06'] = 'WH6 Pipe Insulation' # hvac tips - aedgSmMdOffHowToTipHash["HV01"] = "HV1 Cooling and Heating Loads" - aedgSmMdOffHowToTipHash["HV02"] = "HV2 Certification of HVAC Equipment" - aedgSmMdOffHowToTipHash["HV03"] = "HV3 Single-Zone, Packaged Air-Source Heat Pump Systems (or Split Heat Pump + aedgSmMdOffHowToTipHash['HV01'] = 'HV1 Cooling and Heating Loads' + aedgSmMdOffHowToTipHash['HV02'] = 'HV2 Certification of HVAC Equipment' + aedgSmMdOffHowToTipHash['HV03'] = "HV3 Single-Zone, Packaged Air-Source Heat Pump Systems (or Split Heat Pump Systems) with Electric Resistance Supplemental Heat and DOASs" - aedgSmMdOffHowToTipHash["HV04"] = "HV4 Water-Source Heat Pumps (WSHPs)" - aedgSmMdOffHowToTipHash["HV05"] = "HV5 Ground-Coupled Water-Source Heat Pump (WSHP) System" - aedgSmMdOffHowToTipHash["HV06"] = "HV6 Multiple-Zone, VAV Packaged DX Rooftop Units with a Hot-Water Coil, + aedgSmMdOffHowToTipHash['HV04'] = 'HV4 Water-Source Heat Pumps (WSHPs)' + aedgSmMdOffHowToTipHash['HV05'] = 'HV5 Ground-Coupled Water-Source Heat Pump (WSHP) System' + aedgSmMdOffHowToTipHash['HV06'] = "HV6 Multiple-Zone, VAV Packaged DX Rooftop Units with a Hot-Water Coil, Indirect Gas Furnace, or Electric Resistance in the Rooftop Unit and Convection Heat in the Spaces" - aedgSmMdOffHowToTipHash["HV07"] = "HV7 Multiple-Zone, VAV Air-Handling Units with Packaged Air-Cooled Chiller and + aedgSmMdOffHowToTipHash['HV07'] = "HV7 Multiple-Zone, VAV Air-Handling Units with Packaged Air-Cooled Chiller and Gas-Fired Boiler" - aedgSmMdOffHowToTipHash["HV08"] = "Fan-Coils" - aedgSmMdOffHowToTipHash["HV09"] = "HV9 Radiant Heating and Cooling and DOAS" - aedgSmMdOffHowToTipHash["HV10"] = "HV10 Dedicated Outdoor Air Systems (100% Outdoor Air Systems)" - aedgSmMdOffHowToTipHash["HV11"] = "HV11 Part-Load Dehumidification" - aedgSmMdOffHowToTipHash["HV12"] = "HV12 Exhaust Air Energy Recovery" - aedgSmMdOffHowToTipHash["HV13"] = "HV13 Indirect Evaporative Cooling" - aedgSmMdOffHowToTipHash["HV14"] = "HV14 Cooling and Heating Equipment Efficiencies" - aedgSmMdOffHowToTipHash["HV15"] = "HV15 Ventilation Air" - aedgSmMdOffHowToTipHash["HV16"] = "HV16 Economizer" - aedgSmMdOffHowToTipHash["HV17"] = "HV17 Demand-Controlled Ventilation (DCV)" - aedgSmMdOffHowToTipHash["HV18"] = "HV18 Carbon Dioxide (CO2 ) Sensors" - aedgSmMdOffHowToTipHash["HV19"] = "HV19 Exhaust Air Systems" - aedgSmMdOffHowToTipHash["HV20"] = "HV20 Ductwork Design and Construction" - aedgSmMdOffHowToTipHash["HV21"] = "HV21 Duct Insulation" - aedgSmMdOffHowToTipHash["HV22"] = "HV22 Duct Sealing and Leakage Testing" - aedgSmMdOffHowToTipHash["HV23"] = "HV23 Fan Motor Efficiencies" - aedgSmMdOffHowToTipHash["HV24"] = "HV24 Thermal Zoning" - aedgSmMdOffHowToTipHash["HV25"] = "HV25 System-Level Control Strategies" - aedgSmMdOffHowToTipHash["HV26"] = "HV26 Testing, Adjusting, and Balancing" - aedgSmMdOffHowToTipHash["HV27"] = "HV27 Commissioning (Cx)" - aedgSmMdOffHowToTipHash["HV28"] = "HV28 Filters" - aedgSmMdOffHowToTipHash["HV29"] = "HV29 Chilled-Water (CHW) System" - aedgSmMdOffHowToTipHash["HV30"] = "HV30 Water Heating Systems" - aedgSmMdOffHowToTipHash["HV31"] = "HV31 Relief versus Return Fans" - aedgSmMdOffHowToTipHash["HV32"] = "HV32 Heating Sources" - aedgSmMdOffHowToTipHash["HV33"] = "HV33 Noise Control" - aedgSmMdOffHowToTipHash["HV34"] = "HV34 Proper Maintenance" - aedgSmMdOffHowToTipHash["HV35"] = "HV35 Zone Temperature Control" - aedgSmMdOffHowToTipHash["HV36"] = "HV36 Evaporative Condensers on Rooftop Units" + aedgSmMdOffHowToTipHash['HV08'] = 'Fan-Coils' + aedgSmMdOffHowToTipHash['HV09'] = 'HV9 Radiant Heating and Cooling and DOAS' + aedgSmMdOffHowToTipHash['HV10'] = 'HV10 Dedicated Outdoor Air Systems (100% Outdoor Air Systems)' + aedgSmMdOffHowToTipHash['HV11'] = 'HV11 Part-Load Dehumidification' + aedgSmMdOffHowToTipHash['HV12'] = 'HV12 Exhaust Air Energy Recovery' + aedgSmMdOffHowToTipHash['HV13'] = 'HV13 Indirect Evaporative Cooling' + aedgSmMdOffHowToTipHash['HV14'] = 'HV14 Cooling and Heating Equipment Efficiencies' + aedgSmMdOffHowToTipHash['HV15'] = 'HV15 Ventilation Air' + aedgSmMdOffHowToTipHash['HV16'] = 'HV16 Economizer' + aedgSmMdOffHowToTipHash['HV17'] = 'HV17 Demand-Controlled Ventilation (DCV)' + aedgSmMdOffHowToTipHash['HV18'] = 'HV18 Carbon Dioxide (CO2 ) Sensors' + aedgSmMdOffHowToTipHash['HV19'] = 'HV19 Exhaust Air Systems' + aedgSmMdOffHowToTipHash['HV20'] = 'HV20 Ductwork Design and Construction' + aedgSmMdOffHowToTipHash['HV21'] = 'HV21 Duct Insulation' + aedgSmMdOffHowToTipHash['HV22'] = 'HV22 Duct Sealing and Leakage Testing' + aedgSmMdOffHowToTipHash['HV23'] = 'HV23 Fan Motor Efficiencies' + aedgSmMdOffHowToTipHash['HV24'] = 'HV24 Thermal Zoning' + aedgSmMdOffHowToTipHash['HV25'] = 'HV25 System-Level Control Strategies' + aedgSmMdOffHowToTipHash['HV26'] = 'HV26 Testing, Adjusting, and Balancing' + aedgSmMdOffHowToTipHash['HV27'] = 'HV27 Commissioning (Cx)' + aedgSmMdOffHowToTipHash['HV28'] = 'HV28 Filters' + aedgSmMdOffHowToTipHash['HV29'] = 'HV29 Chilled-Water (CHW) System' + aedgSmMdOffHowToTipHash['HV30'] = 'HV30 Water Heating Systems' + aedgSmMdOffHowToTipHash['HV31'] = 'HV31 Relief versus Return Fans' + aedgSmMdOffHowToTipHash['HV32'] = 'HV32 Heating Sources' + aedgSmMdOffHowToTipHash['HV33'] = 'HV33 Noise Control' + aedgSmMdOffHowToTipHash['HV34'] = 'HV34 Proper Maintenance' + aedgSmMdOffHowToTipHash['HV35'] = 'HV35 Zone Temperature Control' + aedgSmMdOffHowToTipHash['HV36'] = 'HV36 Evaporative Condensers on Rooftop Units' # commissioning tips - aedgSmMdOffHowToTipHash["QA01"] = "QA1 Selecting the Design and Construction Team" - aedgSmMdOffHowToTipHash["QA02"] = "QA2 Selecting the QA Provider" - aedgSmMdOffHowToTipHash["QA03"] = "QA3 Owner’s Project Requirements (OPR) and Basis of Design (BoD)" - aedgSmMdOffHowToTipHash["QA04"] = "QA4 Design and Construction Schedule" - aedgSmMdOffHowToTipHash["QA05"] = "QA5 Design Review" - aedgSmMdOffHowToTipHash["QA06"] = "QA6 Defining QA at Pre-Bid" - aedgSmMdOffHowToTipHash["QA07"] = "QA7 Verifying Building Envelope Construction" - aedgSmMdOffHowToTipHash["QA08"] = "QA8 Verifying Lighting Construction" - aedgSmMdOffHowToTipHash["QA09"] = "QA9 Verifying Electrical and HVAC Systems Construction" - aedgSmMdOffHowToTipHash["QA10"] = "QA10 Performance Testing" - aedgSmMdOffHowToTipHash["QA11"] = "QA11 Substantial Completion" - aedgSmMdOffHowToTipHash["QA12"] = "QA12 Final Acceptance" - aedgSmMdOffHowToTipHash["QA13"] = "QA13 Establish a Building Operation and Maintenance (O&M) Program" - aedgSmMdOffHowToTipHash["QA14"] = "QA14 Monitor Post-Occupancy Performance" + aedgSmMdOffHowToTipHash['QA01'] = 'QA1 Selecting the Design and Construction Team' + aedgSmMdOffHowToTipHash['QA02'] = 'QA2 Selecting the QA Provider' + aedgSmMdOffHowToTipHash['QA03'] = 'QA3 Owner’s Project Requirements (OPR) and Basis of Design (BoD)' + aedgSmMdOffHowToTipHash['QA04'] = 'QA4 Design and Construction Schedule' + aedgSmMdOffHowToTipHash['QA05'] = 'QA5 Design Review' + aedgSmMdOffHowToTipHash['QA06'] = 'QA6 Defining QA at Pre-Bid' + aedgSmMdOffHowToTipHash['QA07'] = 'QA7 Verifying Building Envelope Construction' + aedgSmMdOffHowToTipHash['QA08'] = 'QA8 Verifying Lighting Construction' + aedgSmMdOffHowToTipHash['QA09'] = 'QA9 Verifying Electrical and HVAC Systems Construction' + aedgSmMdOffHowToTipHash['QA10'] = 'QA10 Performance Testing' + aedgSmMdOffHowToTipHash['QA11'] = 'QA11 Substantial Completion' + aedgSmMdOffHowToTipHash['QA12'] = 'QA12 Final Acceptance' + aedgSmMdOffHowToTipHash['QA13'] = 'QA13 Establish a Building Operation and Maintenance (O&M) Program' + aedgSmMdOffHowToTipHash['QA14'] = 'QA14 Monitor Post-Occupancy Performance' # natural ventilation tips - aedgSmMdOffHowToTipHash["NV01"] = "NV1 Natural Ventilation and Naturally Conditioned Spaces" + aedgSmMdOffHowToTipHash['NV01'] = 'NV1 Natural Ventilation and Naturally Conditioned Spaces' # renewable energy tips - aedgSmMdOffHowToTipHash["RE01"] = "RE1 Photovoltaic (PV) Systems" - aedgSmMdOffHowToTipHash["RE02"] = "RE2 Wind Turbine Power" - aedgSmMdOffHowToTipHash["RE03"] = "RE3 Transpired Solar Collector" - aedgSmMdOffHowToTipHash["RE04"] = "RE4 Power Purchase Agreements" + aedgSmMdOffHowToTipHash['RE01'] = 'RE1 Photovoltaic (PV) Systems' + aedgSmMdOffHowToTipHash['RE02'] = 'RE2 Wind Turbine Power' + aedgSmMdOffHowToTipHash['RE03'] = 'RE3 Transpired Solar Collector' + aedgSmMdOffHowToTipHash['RE04'] = 'RE4 Power Purchase Agreements' result = aedgSmMdOffHowToTipHash return result - - end #end of OsLib_AedgMeasures.getSmMdOffTips - -end # end of module OsLib_AedgMeasures \ No newline at end of file + end # end of OsLib_AedgMeasures.getSmMdOffTips +end # end of module OsLib_AedgMeasures diff --git a/lib/measures/vr_fwith_doas/resources/OsLib_Constructions.rb b/lib/measures/vr_fwith_doas/resources/OsLib_Constructions.rb index b81d330..7b11ac3 100644 --- a/lib/measures/vr_fwith_doas/resources/OsLib_Constructions.rb +++ b/lib/measures/vr_fwith_doas/resources/OsLib_Constructions.rb @@ -1,28 +1,28 @@ -module OsLib_Constructions +# frozen_string_literal: true +module OsLib_Constructions # infer insulation layer from a construction - def OsLib_Constructions.inferInsulationLayer(construction,minThermalResistance) - + def self.inferInsulationLayer(construction, minThermalResistance) construction_layers = construction.layers counter = 0 max_resistance = 0 thermal_resistance_array = [] - #loop through construction layers and infer insulation layer/material + # loop through construction layers and infer insulation layer/material construction_layers.each do |construction_layer| construction_thermal_resistance = construction_layer.to_OpaqueMaterial.get.thermalResistance - if not thermal_resistance_array.empty? + if !thermal_resistance_array.empty? if construction_thermal_resistance > max_resistance - thermal_resistance_array = [construction_layer,counter,construction_thermal_resistance] + thermal_resistance_array = [construction_layer, counter, construction_thermal_resistance] max_resistance = construction_thermal_resistance end else - thermal_resistance_array = [construction_layer,counter,construction_thermal_resistance] + thermal_resistance_array = [construction_layer, counter, construction_thermal_resistance] end - counter = counter + 1 + counter += 1 end - #test against minimum + # test against minimum if max_resistance > minThermalResistance minTestPass = true else @@ -30,23 +30,22 @@ def OsLib_Constructions.inferInsulationLayer(construction,minThermalResistance) end result = { - "construction" => construction, - "construction_layer" => thermal_resistance_array[0], - "layer_index" => thermal_resistance_array[1], - "construction_thermal_resistance" => thermal_resistance_array[2], - "insulationFound" => minTestPass + 'construction' => construction, + 'construction_layer' => thermal_resistance_array[0], + 'layer_index' => thermal_resistance_array[1], + 'construction_thermal_resistance' => thermal_resistance_array[2], + 'insulationFound' => minTestPass } return result end # change thermal resistance of opaque materials - def OsLib_Constructions.setMaterialThermalResistance(material,thermalResistance,options = {}) - + def self.setMaterialThermalResistance(material, thermalResistance, options = {}) # set defaults to use if user inputs not passed in defaults = { - "cloneMaterial" => true, # in future give user option to clone or change live material - "name" => "#{material.name} - adj", + 'cloneMaterial' => true, # in future give user option to clone or change live material + 'name' => "#{material.name} - adj" } # merge user inputs with defaults @@ -55,21 +54,21 @@ def OsLib_Constructions.setMaterialThermalResistance(material,thermalResistance, # clone input material new_material = material.clone(material.model) new_material = new_material.to_OpaqueMaterial.get - new_material.setName(options["name"]) + new_material.setName(options['name']) - #edit insulation material + # edit insulation material new_material_matt = new_material.to_Material - if not new_material_matt.empty? + if !new_material_matt.empty? starting_thickness = new_material_matt.get.thickness target_thickness = starting_thickness * thermalResistance / material.to_OpaqueMaterial.get.thermalResistance final_thickness = new_material_matt.get.setThickness(target_thickness) end new_material_massless = new_material.to_MasslessOpaqueMaterial - if not new_material_massless.empty? + if !new_material_massless.empty? final_thermal_resistance = new_material_massless.get.setThermalResistance(thermalResistance) end new_material_airgap = new_material.to_AirGap - if not new_material_airgap.empty? + if !new_material_airgap.empty? final_thermal_resistance = new_material_airgap.get.setThermalResistance(thermalResistance) end @@ -78,113 +77,108 @@ def OsLib_Constructions.setMaterialThermalResistance(material,thermalResistance, end # add new material to outside of a construction - def OsLib_Constructions.addNewLayerToConstruction(construction,options = {}) - + def self.addNewLayerToConstruction(construction, options = {}) # set defaults to use if user inputs not passed in defaults = { - "cloneConstruction" => false, # in future give user option to clone or change live construction - "layerIndex" => 0, # 0 will be outside. Measure writer should validate any non 0 layerIndex passed in. - "name" => "#{construction.name} - new material", - "roughness" => nil, - "thickness" => nil, - "conductivity" => nil, - "density" => nil, - "specificHeat" => nil, - "thermalAbsorptance" => nil, - "solarAbsorptance" => nil, - "visibleAbsorptance" => nil, + 'cloneConstruction' => false, # in future give user option to clone or change live construction + 'layerIndex' => 0, # 0 will be outside. Measure writer should validate any non 0 layerIndex passed in. + 'name' => "#{construction.name} - new material", + 'roughness' => nil, + 'thickness' => nil, + 'conductivity' => nil, + 'density' => nil, + 'specificHeat' => nil, + 'thermalAbsorptance' => nil, + 'solarAbsorptance' => nil, + 'visibleAbsorptance' => nil } # merge user inputs with defaults options = defaults.merge(options) - # todo - would be nice to grab surface properties from previous exposed material + # TODO: - would be nice to grab surface properties from previous exposed material # make new material exposedMaterialNew = OpenStudio::Model::StandardOpaqueMaterial.new(construction.model) - exposedMaterialNew.setName(options["name"]) + exposedMaterialNew.setName(options['name']) # set requested material properties - if not options["roughness"].nil? then exposedMaterialNew.setRoughness(options["roughness"]) end - if not options["thickness"].nil? then exposedMaterialNew.setThickness(options["thickness"]) end - if not options["conductivity"].nil? then exposedMaterialNew.setConductivity( options["conductivity"]) end - if not options["density"].nil? then exposedMaterialNew.setDensity(options["density"])end - if not options["specificHeat"].nil? then exposedMaterialNew.setSpecificHeat(options["specificHeat"]) end - if not options["thermalAbsorptance"].nil? then exposedMaterialNew.setThermalAbsorptance(options["thermalAbsorptance"]) end - if not options["solarAbsorptance"].nil? then exposedMaterialNew.setSolarAbsorptance(options["solarAbsorptance"]) end - if not options["visibleAbsorptance"].nil? then exposedMaterialNew.setVisibleAbsorptance(options["visibleAbsorptance"]) end + if !options['roughness'].nil? then exposedMaterialNew.setRoughness(options['roughness']) end + if !options['thickness'].nil? then exposedMaterialNew.setThickness(options['thickness']) end + if !options['conductivity'].nil? then exposedMaterialNew.setConductivity(options['conductivity']) end + if !options['density'].nil? then exposedMaterialNew.setDensity(options['density']) end + if !options['specificHeat'].nil? then exposedMaterialNew.setSpecificHeat(options['specificHeat']) end + if !options['thermalAbsorptance'].nil? then exposedMaterialNew.setThermalAbsorptance(options['thermalAbsorptance']) end + if !options['solarAbsorptance'].nil? then exposedMaterialNew.setSolarAbsorptance(options['solarAbsorptance']) end + if !options['visibleAbsorptance'].nil? then exposedMaterialNew.setVisibleAbsorptance(options['visibleAbsorptance']) end # add material to construction - construction.insertLayer(options["layerIndex"],exposedMaterialNew) + construction.insertLayer(options['layerIndex'], exposedMaterialNew) result = exposedMaterialNew return result end # set material surface properties for specific layer in construction. this should work on OS:Material and OS:MasslessOpaqueMaterial - def OsLib_Constructions.setConstructionSurfaceProperties(construction,options = {}) - + def self.setConstructionSurfaceProperties(construction, options = {}) # set defaults to use if user inputs not passed in defaults = { - "cloneConstruction" => false, # in future give user option to clone or change live construction - "nameConstruction" => "#{construction.name} - adj", # not currently used - "cloneMaterial" => true, - "roughness" => nil, - "thermalAbsorptance" => nil, - "solarAbsorptance" => nil, - "visibleAbsorptance" => nil, + 'cloneConstruction' => false, # in future give user option to clone or change live construction + 'nameConstruction' => "#{construction.name} - adj", # not currently used + 'cloneMaterial' => true, + 'roughness' => nil, + 'thermalAbsorptance' => nil, + 'solarAbsorptance' => nil, + 'visibleAbsorptance' => nil } # merge user inputs with defaults options = defaults.merge(options) exposedMaterial = construction.to_LayeredConstruction.get.getLayer(0) - if options["cloneMaterial"] + if options['cloneMaterial'] - #clone material + # clone material exposedMaterialNew = exposedMaterial.clone(construction.model).to_StandardOpaqueMaterial.get # to_StandardOpaqueMaterial is needed to access roughness, otherwise to_OpaqueMaterial would have been fine. exposedMaterialNew.setName("#{exposedMaterial.name} - adj") # connect new material to original construction construction.eraseLayer(0) - construction.insertLayer(0,exposedMaterialNew) + construction.insertLayer(0, exposedMaterialNew) else exposedMaterialNew = exposedMaterial.to_StandardOpaqueMaterial.get # not being cloned but still want to rename exposedMaterialNew.setName("#{exposedMaterial.name} - adj") end - #todo - need to test with MasslessOpaqueMaterial. Add test if doesn't return anything when use to_StandardOpaqueMaterial.get + # TODO: - need to test with MasslessOpaqueMaterial. Add test if doesn't return anything when use to_StandardOpaqueMaterial.get # set requested material properties - if not options["roughness"].nil? then exposedMaterialNew.setRoughness(options["roughness"]) end - if not options["thermalAbsorptance"].nil? then exposedMaterialNew.setThermalAbsorptance(options["thermalAbsorptance"]) end - if not options["solarAbsorptance"].nil? then exposedMaterialNew.setSolarAbsorptance(options["solarAbsorptance"]) end - if not options["visibleAbsorptance"].nil? then exposedMaterialNew.setVisibleAbsorptance(options["visibleAbsorptance"]) end + if !options['roughness'].nil? then exposedMaterialNew.setRoughness(options['roughness']) end + if !options['thermalAbsorptance'].nil? then exposedMaterialNew.setThermalAbsorptance(options['thermalAbsorptance']) end + if !options['solarAbsorptance'].nil? then exposedMaterialNew.setSolarAbsorptance(options['solarAbsorptance']) end + if !options['visibleAbsorptance'].nil? then exposedMaterialNew.setVisibleAbsorptance(options['visibleAbsorptance']) end - result = {"exposedMaterial" => exposedMaterial,"exposedMaterialNew" => exposedMaterialNew} + result = { 'exposedMaterial' => exposedMaterial, 'exposedMaterialNew' => exposedMaterialNew } return result - end # end of OsLib_Constructions.setMaterialSurfaceProperties - # similar to setMaterialSurfaceProperties but I just pass a material in. Needed this to set material properties for interior walls and both sides of interior partitions. - def OsLib_Constructions.setMaterialSurfaceProperties(material,options = {}) - + def self.setMaterialSurfaceProperties(material, options = {}) # set defaults to use if user inputs not passed in defaults = { - "cloneMaterial" => true, - "roughness" => nil, - "thermalAbsorptance" => nil, - "solarAbsorptance" => nil, - "visibleAbsorptance" => nil, + 'cloneMaterial' => true, + 'roughness' => nil, + 'thermalAbsorptance' => nil, + 'solarAbsorptance' => nil, + 'visibleAbsorptance' => nil } # merge user inputs with defaults options = defaults.merge(options) - if options["cloneMaterial"] - #clone material + if options['cloneMaterial'] + # clone material materialNew = exposedMaterial.clone(construction.model).get materialNew.setName("#{materialNew.name} - adj") else @@ -193,25 +187,24 @@ def OsLib_Constructions.setMaterialSurfaceProperties(material,options = {}) end # to_StandardOpaqueMaterial is needed to access roughness, otherwise to_OpaqueMaterial would have been fine. - if not materialNew.to_StandardOpaqueMaterial.empty? + if !materialNew.to_StandardOpaqueMaterial.empty? materialNew = materialNew.to_StandardOpaqueMaterial.get - elsif not materialNew.to_MasslessOpaqueMaterial.empty? + elsif !materialNew.to_MasslessOpaqueMaterial.empty? materialNew = materialNew.to_MasslessOpaqueMaterial.get end # set requested material properties - if not options["roughness"].nil? then materialNew.setRoughness(options["roughness"]) end - if not options["thermalAbsorptance"].nil? then materialNew.setThermalAbsorptance(options["thermalAbsorptance"]) end - if not options["solarAbsorptance"].nil? then materialNew.setSolarAbsorptance(options["solarAbsorptance"]) end - if not options["visibleAbsorptance"].nil? then materialNew.setVisibleAbsorptance(options["visibleAbsorptance"]) end + if !options['roughness'].nil? then materialNew.setRoughness(options['roughness']) end + if !options['thermalAbsorptance'].nil? then materialNew.setThermalAbsorptance(options['thermalAbsorptance']) end + if !options['solarAbsorptance'].nil? then materialNew.setSolarAbsorptance(options['solarAbsorptance']) end + if !options['visibleAbsorptance'].nil? then materialNew.setVisibleAbsorptance(options['visibleAbsorptance']) end - result = {"material" => material,"materialNew" => materialNew} + result = { 'material' => material, 'materialNew' => materialNew } return result - end # end of OsLib_Constructions.setMaterialSurfaceProperties # sri of exposed surface of a construction (calculation from K-12 AEDG, derived from ASTM E1980 assuming medium wind speed) - def OsLib_Constructions.getConstructionSRI(construction) + def self.getConstructionSRI(construction) exposedMaterial = construction.to_LayeredConstruction.get.getLayer(0) solarAbsorptance = exposedMaterial.to_OpaqueMaterial.get.solarAbsorptance thermalEmissivity = exposedMaterial.to_OpaqueMaterial.get.thermalAbsorptance @@ -219,11 +212,10 @@ def OsLib_Constructions.getConstructionSRI(construction) # solarAbsorptance = 1 - 0.65 # thermalEmissivity = 0.86 - x = (20.797 * solarAbsorptance - 0.603 * thermalEmissivity)/(9.5205 * thermalEmissivity + 12.0) + x = (20.797 * solarAbsorptance - 0.603 * thermalEmissivity) / (9.5205 * thermalEmissivity + 12.0) sri = 123.97 - 141.35 * x + 9.6555 * x * x result = sri return result end # end of OsLib_Constructions.getConstructionSRI - -end \ No newline at end of file +end diff --git a/lib/measures/vr_fwith_doas/resources/OsLib_Geometry.rb b/lib/measures/vr_fwith_doas/resources/OsLib_Geometry.rb index a4ade99..83e43a9 100644 --- a/lib/measures/vr_fwith_doas/resources/OsLib_Geometry.rb +++ b/lib/measures/vr_fwith_doas/resources/OsLib_Geometry.rb @@ -1,13 +1,12 @@ -module OsLib_Geometry +# frozen_string_literal: true +module OsLib_Geometry # lower z value of vertices with starting value above x to new value of y - def OsLib_Geometry.lowerSurfaceZvalue(surfaceArray, zValueTarget) - + def self.lowerSurfaceZvalue(surfaceArray, zValueTarget) counter = 0 # loop over all surfaces surfaceArray.each do |surface| - # create a new set of vertices newVertices = OpenStudio::Point3dVector.new @@ -15,7 +14,6 @@ def OsLib_Geometry.lowerSurfaceZvalue(surfaceArray, zValueTarget) vertices = surface.vertices flag = false vertices.each do |vertex| - # initialize new vertex to old vertex x = vertex.x y = vertex.y @@ -28,20 +26,16 @@ def OsLib_Geometry.lowerSurfaceZvalue(surfaceArray, zValueTarget) end # add point to new vertices - newVertices << OpenStudio::Point3d.new(x,y,z) + newVertices << OpenStudio::Point3d.new(x, y, z) end # set vertices to new vertices - surface.setVertices(newVertices) #todo check if this was made, and issue warning if it was not. Could happen if resulting surface not planer. + surface.setVertices(newVertices) # todo check if this was made, and issue warning if it was not. Could happen if resulting surface not planer. if flag then counter += 1 end - - end #end of surfaceArray.each do + end # end of surfaceArray.each do result = counter return result - end - - -end \ No newline at end of file +end diff --git a/lib/measures/vr_fwith_doas/resources/OsLib_HVAC.rb b/lib/measures/vr_fwith_doas/resources/OsLib_HVAC.rb index aac4990..4ef9b7f 100644 --- a/lib/measures/vr_fwith_doas/resources/OsLib_HVAC.rb +++ b/lib/measures/vr_fwith_doas/resources/OsLib_HVAC.rb @@ -1,25 +1,22 @@ -module OsLib_HVAC +# frozen_string_literal: true +module OsLib_HVAC # do something - def OsLib_HVAC.doSomething(input) - + def self.doSomething(input) # do something output = input result = output return result - end # end of def - # validate and make plenum zones - def OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options = {}) - + def self.validateAndAddPlenumZonesToSystem(model, runner, options = {}) # set defaults to use if user inputs not passed in defaults = { - "zonesPlenum" => nil, - "zonesPrimary" => nil, - "type" => "ceilingReturn", + 'zonesPlenum' => nil, + 'zonesPrimary' => nil, + 'type' => 'ceilingReturn' } # merge user inputs with defaults @@ -28,11 +25,11 @@ def OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options = {}) # array of valid ceiling plenums zoneSurfaceHash = {} zonePlenumHash = {} - - if options["zonesPlenum"] == nil - runner.registerWarning("No plenum zones were passed in, validateAndAddPlenumZonesToSystem will not alter the model.") + + if options['zonesPlenum'].nil? + runner.registerWarning('No plenum zones were passed in, validateAndAddPlenumZonesToSystem will not alter the model.') else - options["zonesPlenum"].each do |zone| + options['zonesPlenum'].each do |zone| # get spaces in zone spaces = zone.spaces # get adjacent spaces @@ -41,19 +38,19 @@ def OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options = {}) surfaces = space.surfaces # loop through surfaces looking for floors with surface boundary condition, grab zone that surface's parent space is in. surfaces.each do |surface| - if surface.outsideBoundaryCondition == "Surface" and surface.surfaceType == "Floor" + if (surface.outsideBoundaryCondition == 'Surface') && (surface.surfaceType == 'Floor') next unless surface.adjacentSurface.is_initialized adjacentSurface = surface.adjacentSurface.get next unless adjacentSurface.space.is_initialized adjacentSurfaceSpace = adjacentSurface.space.get next unless adjacentSurfaceSpace.thermalZone.is_initialized adjacentSurfaceSpaceZone = adjacentSurfaceSpace.thermalZone.get - if options["zonesPrimary"].include? adjacentSurfaceSpaceZone - if zoneSurfaceHash[adjacentSurfaceSpaceZone].nil? or surface.grossArea > zoneSurfaceHash[adjacentSurfaceSpaceZone] + if options['zonesPrimary'].include? adjacentSurfaceSpaceZone + if zoneSurfaceHash[adjacentSurfaceSpaceZone].nil? || (surface.grossArea > zoneSurfaceHash[adjacentSurfaceSpaceZone]) adjacentSurfaceSpaceZone.setReturnPlenum(zone) zoneSurfaceHash[adjacentSurfaceSpaceZone] = surface.grossArea zonePlenumHash[adjacentSurfaceSpaceZone] = zone - end + end end end end # end of surfaces.each do @@ -62,23 +59,20 @@ def OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options = {}) end # end of zonesPlenum == nil # report out results of zone-plenum hash - zonePlenumHash.each do |zone,plenum| + zonePlenumHash.each do |zone, plenum| runner.registerInfo("#{plenum.name} has been set as a return air plenum for #{zone.name}.") end - + # pass back zone-plenum hash result = zonePlenumHash return result - end # end of def - - def OsLib_HVAC.sortZones(model, runner, options = {}, space_type_to_edits_hash = {}) + def self.sortZones(model, runner, options = {}, space_type_to_edits_hash = {}) # set defaults to use if user inputs not passed in - defaults = {"standardBuildingTypeTest" => nil, # not used for now - "secondarySpaceTypeTest" => nil, - "ceilingReturnPlenumSpaceType" => nil - } + defaults = { 'standardBuildingTypeTest' => nil, # not used for now + 'secondarySpaceTypeTest' => nil, + 'ceilingReturnPlenumSpaceType' => nil } # merge user inputs with defaults options = defaults.merge(options) @@ -88,13 +82,13 @@ def OsLib_HVAC.sortZones(model, runner, options = {}, space_type_to_edits_hash = zonesSecondary = [] zonesPlenum = [] zonesUnconditioned = [] - + # get thermal zones zones = model.getThermalZones zones.each do |zone| # assign appropriate zones to zonesPlenum or zonesUnconditioned (those that don't have thermostats or zone HVAC equipment) # if not conditioned then add to zonesPlenum or zonesUnconditioned - unless zone.thermostatSetpointDualSetpoint.is_initialized or zone.equipment.size > 0 + unless zone.thermostatSetpointDualSetpoint.is_initialized || !zone.equipment.empty? # determine if zone is a plenum zone or general unconditioned zone # assume it is a plenum if it has at least one plenum space zone.spaces.each do |space| @@ -102,46 +96,43 @@ def OsLib_HVAC.sortZones(model, runner, options = {}, space_type_to_edits_hash = next if zonesPlenum.include? zone # if zone not assigned as a plenum, get space type if it exists # compare to plenum space type if it has been assigned - if space.spaceType.is_initialized and options["ceilingReturnPlenumSpaceType"].nil? == false + if space.spaceType.is_initialized && (options['ceilingReturnPlenumSpaceType'].nil? == false) spaceType = space.spaceType.get - if spaceType == options["ceilingReturnPlenumSpaceType"] + if spaceType == options['ceilingReturnPlenumSpaceType'] zonesPlenum << zone # zone has a plenum space; assign it as a plenum end end end # if zone not assigned as a plenum, assign it as unconditioned - unless zonesPlenum.include? zone + unless zonesPlenum.include? zone zonesUnconditioned << zone - end + end end - end + end # zone is conditioned. check if its space type is secondary or primary - #runner.registerInfo("space type to edit hash is #{space_type_to_edits_hash}") - spaces = model.getSpaces - spaces.each do |space| + # runner.registerInfo("space type to edit hash is #{space_type_to_edits_hash}") + spaces = model.getSpaces + spaces.each do |space| next unless space.spaceType.is_initialized - spaceType = space.spaceType.get - # runner.registerInfo("space type is #{spaceType}") + spaceType = space.spaceType.get + # runner.registerInfo("space type is #{spaceType}") if space_type_to_edits_hash[spaceType] == true - zonesPrimary << space.thermalZone.get - # runner.registerInfo("#{space.thermalZone.get} is a primary zone") - end - end # end of spaces each do - - - # if zone is conditioned and is of space type true, assign it to primary zones - zonesSorted = {"zonesPrimary" => zonesPrimary, - "zonesSecondary" => zonesSecondary, - "zonesPlenum" => zonesPlenum, - "zonesUnconditioned" => zonesUnconditioned} + zonesPrimary << space.thermalZone.get + # runner.registerInfo("#{space.thermalZone.get} is a primary zone") + end + end # end of spaces each do + + # if zone is conditioned and is of space type true, assign it to primary zones + zonesSorted = { 'zonesPrimary' => zonesPrimary, + 'zonesSecondary' => zonesSecondary, + 'zonesPlenum' => zonesPlenum, + 'zonesUnconditioned' => zonesUnconditioned } # pass back zonesSorted hash result = zonesSorted return result - end # end of def - def OsLib_HVAC.reportConditions(model, runner, condition) - + def self.reportConditions(model, runner, condition) airloops = model.getAirLoopHVACs plantLoops = model.getPlantLoops zones = model.getThermalZones @@ -149,96 +140,92 @@ def OsLib_HVAC.reportConditions(model, runner, condition) # count up zone equipment (not counting zone exhaust fans) zoneHasEquip = false zonesWithEquipCounter = 0 - + zones.each do |zone| - if zone.equipment.size > 0 + if !zone.equipment.empty? zone.equipment.each do |equip| unless equip.to_FanZoneExhaust.is_initialized zonesWithEquipCounter += 1 break end - end + end end - end - - if condition == "initial" + end + + if condition == 'initial' runner.registerInitialCondition("The building started with #{airloops.size} air loops and #{plantLoops.size} plant loops. #{zonesWithEquipCounter} zones were conditioned with zone equipment.") - elsif condition == "final" + elsif condition == 'final' runner.registerFinalCondition("The building finished with #{airloops.size} air loops and #{plantLoops.size} plant loops. #{zonesWithEquipCounter} zones are conditioned with zone equipment.") end - end # end of def - def OsLib_HVAC.removeEquipment(model, runner, options) + def self.removeEquipment(model, runner, options) airloops = model.getAirLoopHVACs plantLoops = model.getPlantLoops - zones = model.getThermalZones + zones = model.getThermalZones - # remove all zone equipment except zone exhaust fans + # remove all zone equipment except zone exhaust fans zones.each do |zone| - # runner.registerInfo("primary zones values are #{value.name}") - if options["zonesPrimary"].include? zone - zone.equipment.each do |equip| - if equip.to_FanZoneExhaust.is_initialized #or (equip.to_ZoneHVACUnitHeater.is_initialized and zone.get.equipment.size == 1) - else - equip.remove - end - end - end - end - + # runner.registerInfo("primary zones values are #{value.name}") + if options['zonesPrimary'].include? zone + zone.equipment.each do |equip| + if equip.to_FanZoneExhaust.is_initialized # or (equip.to_ZoneHVACUnitHeater.is_initialized and zone.get.equipment.size == 1) + else + equip.remove + end + end + end + end + # remove an air loop if it's empty airloops.each do |air_loop| - air_loop.thermalZones.each do |airZone| - if options["zonesPrimary"].include? airZone - air_loop.removeBranchForZone(airZone) - end - end - if air_loop.thermalZones.empty? - air_loop.remove - end + air_loop.thermalZones.each do |airZone| + if options['zonesPrimary'].include? airZone + air_loop.removeBranchForZone(airZone) + end + end + if air_loop.thermalZones.empty? + air_loop.remove + end end - + # remove plant loops plantLoops.each do |plantLoop| # get the demand components and see if water use connection, then save it # notify user with info statement if supply side of plant loop had heat exchanger for refrigeration - usedForSWHOrRefrigeration = false - usedForZoneHCCoils = false - plantLoop.demandComponents.each do |comp| #AP code to check your comments above - runner.registerInfo("plant loops component is #{comp.name.to_s}") - if comp.to_WaterUseConnections.is_initialized or comp.to_CoilWaterHeatingDesuperheater.is_initialized - usedForSWHOrRefrigeration = true - runner.registerWarning("#{plantLoop.name} is used for SWH or refrigeration. Loop will not be deleted.") - elsif comp.name.to_s.include? "Coil" and comp.name.to_s != "Coil Heating Water 1" and comp.name.to_s != "Coil Cooling Water 1"#to_CoilWaterHeatingDesuperheater.is_initialized or comp.name.to_s.include? "coil" - runner.registerWarning("#{plantLoop.name} has coils used by Zone HVAC components. Loop will not be deleted.") - usedForZoneHCCoils = true - end - end - # runner.registerInfo("Used for ZoneHCCoils Value is #{usedForZoneHCCoils}") - # runner.registerInfo("Used for SWH or refrigeration is #{usedForSWHOrRefrigeration}") - if usedForSWHOrRefrigeration == false #and usedForZoneHCCoils == false # <-- Sang Hoon Lee: "and usedForZoneHCCoils == false" Treated as comment for BRICR Medium office to remove Coil:Heating:Water - plantLoop.remove - runner.registerInfo("Plant Loop #{plantLoop.name} is removed") - end - end # end of plantloop components - - - end # end of def + usedForSWHOrRefrigeration = false + usedForZoneHCCoils = false + plantLoop.demandComponents.each do |comp| # AP code to check your comments above + runner.registerInfo("plant loops component is #{comp.name}") + if comp.to_WaterUseConnections.is_initialized || comp.to_CoilWaterHeatingDesuperheater.is_initialized + usedForSWHOrRefrigeration = true + runner.registerWarning("#{plantLoop.name} is used for SWH or refrigeration. Loop will not be deleted.") + elsif comp.name.to_s.include?('Coil') && (comp.name.to_s != 'Coil Heating Water 1') && (comp.name.to_s != 'Coil Cooling Water 1') # to_CoilWaterHeatingDesuperheater.is_initialized or comp.name.to_s.include? "coil" + runner.registerWarning("#{plantLoop.name} has coils used by Zone HVAC components. Loop will not be deleted.") + usedForZoneHCCoils = true + end + end + # runner.registerInfo("Used for ZoneHCCoils Value is #{usedForZoneHCCoils}") + # runner.registerInfo("Used for SWH or refrigeration is #{usedForSWHOrRefrigeration}") + if usedForSWHOrRefrigeration == false # and usedForZoneHCCoils == false # <-- Sang Hoon Lee: "and usedForZoneHCCoils == false" Treated as comment for BRICR Medium office to remove Coil:Heating:Water + plantLoop.remove + runner.registerInfo("Plant Loop #{plantLoop.name} is removed") + end + end # end of plantloop components + end # end of def - def OsLib_HVAC.assignHVACSchedules(model, runner, options = {}) - + def self.assignHVACSchedules(model, runner, options = {}) require "#{File.dirname(__FILE__)}/OsLib_Schedules" - + schedulesHVAC = {} airloops = model.getAirLoopHVACs - + # find airloop with most primary spaces max_primary_spaces = 0 representative_airloop = false building_HVAC_schedule = false building_ventilation_schedule = false - unless options["remake_schedules"] + unless options['remake_schedules'] # if remake schedules not selected, get relevant schedules from model if they exist airloops.each do |air_loop| primary_spaces = 0 @@ -246,216 +233,214 @@ def OsLib_HVAC.assignHVACSchedules(model, runner, options = {}) thermal_zone.spaces.each do |space| if space.spaceType.is_initialized if space.spaceType.get.name.is_initialized - if space.spaceType.get.name.get.include? options["primarySpaceType"] + if space.spaceType.get.name.get.include? options['primarySpaceType'] primary_spaces += 1 end - end - end + end + end end end if primary_spaces > max_primary_spaces max_primary_spaces = primary_spaces representative_airloop = air_loop - end + end end - end + end if representative_airloop building_HVAC_schedule = representative_airloop.availabilitySchedule if representative_airloop.airLoopHVACOutdoorAirSystem.is_initialized - building_ventilation_schedule_optional = representative_airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.maximumFractionofOutdoorAirSchedule + building_ventilation_schedule_optional = representative_airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.maximumFractionofOutdoorAirSchedule if building_ventilation_schedule_optional.is_initialized building_ventilation_schedule = building_ventilation_schedule.get end - end + end end # build new airloop schedules if existing model doesn't have them - if options["primarySpaceType"] == "Classroom" + if options['primarySpaceType'] == 'Classroom' # ventilation schedule unless building_ventilation_schedule - runner.registerInfo("Baseline does not have minimum OA ventilation schedule. A new K-12 Ventilation schedule is created") - ruleset_name = "New K-12 Ventilation Schedule" - winter_design_day = [[24,1]] - summer_design_day = [[24,1]] - default_day = ["Weekday",[6,0],[18,1],[24,0]] + runner.registerInfo('Baseline does not have minimum OA ventilation schedule. A new K-12 Ventilation schedule is created') + ruleset_name = 'New K-12 Ventilation Schedule' + winter_design_day = [[24, 1]] + summer_design_day = [[24, 1]] + default_day = ['Weekday', [6, 0], [18, 1], [24, 0]] rules = [] - rules << ["Weekend","1/1-12/31","Sat/Sun",[24,0]] - rules << ["Summer Weekday","7/1-8/31","Mon/Tue/Wed/Thu/Fri",[8,0],[13,1],[24,0]] - options_ventilation = {"name" => ruleset_name, - "winter_design_day" => winter_design_day, - "summer_design_day" => summer_design_day, - "default_day" => default_day, - "rules" => rules} + rules << ['Weekend', '1/1-12/31', 'Sat/Sun', [24, 0]] + rules << ['Summer Weekday', '7/1-8/31', 'Mon/Tue/Wed/Thu/Fri', [8, 0], [13, 1], [24, 0]] + options_ventilation = { 'name' => ruleset_name, + 'winter_design_day' => winter_design_day, + 'summer_design_day' => summer_design_day, + 'default_day' => default_day, + 'rules' => rules } building_ventilation_schedule = OsLib_Schedules.createComplexSchedule(model, options_ventilation) end # HVAC availability schedule unless building_HVAC_schedule - runner.registerInfo("Baseline does not have HVAC availability schedule. A new K-12 HVAC availability schedule is created") - ruleset_name = "New K-12 HVAC Availability Schedule" - winter_design_day = [[24,1]] - summer_design_day = [[24,1]] - default_day = ["Weekday",[6,0],[18,1],[24,0]] + runner.registerInfo('Baseline does not have HVAC availability schedule. A new K-12 HVAC availability schedule is created') + ruleset_name = 'New K-12 HVAC Availability Schedule' + winter_design_day = [[24, 1]] + summer_design_day = [[24, 1]] + default_day = ['Weekday', [6, 0], [18, 1], [24, 0]] rules = [] - rules << ["Weekend","1/1-12/31","Sat/Sun",[24,0]] - rules << ["Summer Weekday","7/1-8/31","Mon/Tue/Wed/Thu/Fri",[8,0],[13,1],[24,0]] - options_hvac = {"name" => ruleset_name, - "winter_design_day" => winter_design_day, - "summer_design_day" => summer_design_day, - "default_day" => default_day, - "rules" => rules} + rules << ['Weekend', '1/1-12/31', 'Sat/Sun', [24, 0]] + rules << ['Summer Weekday', '7/1-8/31', 'Mon/Tue/Wed/Thu/Fri', [8, 0], [13, 1], [24, 0]] + options_hvac = { 'name' => ruleset_name, + 'winter_design_day' => winter_design_day, + 'summer_design_day' => summer_design_day, + 'default_day' => default_day, + 'rules' => rules } building_HVAC_schedule = OsLib_Schedules.createComplexSchedule(model, options_hvac) end - elsif options["primarySpaceType"] == "Office" # xf - leave as is + elsif options['primarySpaceType'] == 'Office' # xf - leave as is # ventilation schedule unless building_ventilation_schedule - runner.registerInfo("Baseline does not have minimum OA ventilation schedule. A new Office Ventilation schedule is created.") - ruleset_name = "New Office Ventilation Schedule" - winter_design_day = [[24,1]] #ML These are not always on in PNNL model - summer_design_day = [[24,1]] #ML These are not always on in PNNL model - default_day = ["Weekday",[7,0],[22,1],[24,0]] #ML PNNL has a one hour ventilation offset + runner.registerInfo('Baseline does not have minimum OA ventilation schedule. A new Office Ventilation schedule is created.') + ruleset_name = 'New Office Ventilation Schedule' + winter_design_day = [[24, 1]] # ML These are not always on in PNNL model + summer_design_day = [[24, 1]] # ML These are not always on in PNNL model + default_day = ['Weekday', [7, 0], [22, 1], [24, 0]] # ML PNNL has a one hour ventilation offset rules = [] - rules << ["Saturday","1/1-12/31","Sat",[7,0],[18,1],[24,0]] #ML PNNL has a one hour ventilation offset - rules << ["Sunday","1/1-12/31","Sun",[24,0]] - options_ventilation = {"name" => ruleset_name, - "winter_design_day" => winter_design_day, - "summer_design_day" => summer_design_day, - "default_day" => default_day, - "rules" => rules} + rules << ['Saturday', '1/1-12/31', 'Sat', [7, 0], [18, 1], [24, 0]] # ML PNNL has a one hour ventilation offset + rules << ['Sunday', '1/1-12/31', 'Sun', [24, 0]] + options_ventilation = { 'name' => ruleset_name, + 'winter_design_day' => winter_design_day, + 'summer_design_day' => summer_design_day, + 'default_day' => default_day, + 'rules' => rules } building_ventilation_schedule = OsLib_Schedules.createComplexSchedule(model, options_ventilation) end # HVAC availability schedule unless building_HVAC_schedule - runner.registerInfo("Baseline does not have HVAC availability schedule. A new office HVAC availability schedule is created") - ruleset_name = "New Office HVAC Availability Schedule" - winter_design_day = [[24,1]] #ML These are not always on in PNNL model - summer_design_day = [[24,1]] #ML These are not always on in PNNL model - default_day = ["Weekday",[6,0],[22,1],[24,0]] #ML PNNL has a one hour ventilation offset + runner.registerInfo('Baseline does not have HVAC availability schedule. A new office HVAC availability schedule is created') + ruleset_name = 'New Office HVAC Availability Schedule' + winter_design_day = [[24, 1]] # ML These are not always on in PNNL model + summer_design_day = [[24, 1]] # ML These are not always on in PNNL model + default_day = ['Weekday', [6, 0], [22, 1], [24, 0]] # ML PNNL has a one hour ventilation offset rules = [] - rules << ["Saturday","1/1-12/31","Sat",[6,0],[18,1],[24,0]] #ML PNNL has a one hour ventilation offset - rules << ["Sunday","1/1-12/31","Sun",[24,0]] - options_hvac = {"name" => ruleset_name, - "winter_design_day" => winter_design_day, - "summer_design_day" => summer_design_day, - "default_day" => default_day, - "rules" => rules} + rules << ['Saturday', '1/1-12/31', 'Sat', [6, 0], [18, 1], [24, 0]] # ML PNNL has a one hour ventilation offset + rules << ['Sunday', '1/1-12/31', 'Sun', [24, 0]] + options_hvac = { 'name' => ruleset_name, + 'winter_design_day' => winter_design_day, + 'summer_design_day' => summer_design_day, + 'default_day' => default_day, + 'rules' => rules } building_HVAC_schedule = OsLib_Schedules.createComplexSchedule(model, options_hvac) end # special loops for radiant system (different temperature setpoints) - if options["allHVAC"]["zone"] == "Radiant" + if options['allHVAC']['zone'] == 'Radiant' # create hot water schedule for radiant heating loop - schedulesHVAC["radiant_hot_water"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HW-Radiant-Loop-Temp-Schedule", - "default_day" => ["All Days",[24,45.0]]}) + schedulesHVAC['radiant_hot_water'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HW-Radiant-Loop-Temp-Schedule', + 'default_day' => ['All Days', [24, 45.0]]) # create hot water schedule for radiant cooling loop - schedulesHVAC["radiant_chilled_water"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New CW-Radiant-Loop-Temp-Schedule", - "default_day" => ["All Days",[24,15.0]]}) + schedulesHVAC['radiant_chilled_water'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New CW-Radiant-Loop-Temp-Schedule', + 'default_day' => ['All Days', [24, 15.0]]) # create mean radiant heating and cooling setpoint schedules # ML ideally, should grab schedules tied to zone thermostat and make modified versions that follow the setback pattern # for now, create new ones that match the recommended HVAC schedule # mean radiant heating setpoint schedule (PNNL values) - ruleset_name = "New Office Mean Radiant Heating Setpoint Schedule" - winter_design_day = [[24,18.8]] - summer_design_day = [[6,18.3],[22,18.8],[24,18.3]] - default_day = ["Weekday",[6,18.3],[22,18.8],[24,18.3]] + ruleset_name = 'New Office Mean Radiant Heating Setpoint Schedule' + winter_design_day = [[24, 18.8]] + summer_design_day = [[6, 18.3], [22, 18.8], [24, 18.3]] + default_day = ['Weekday', [6, 18.3], [22, 18.8], [24, 18.3]] rules = [] - rules << ["Saturday","1/1-12/31","Sat",[6,18.3],[18,18.8],[24,18.3]] - rules << ["Sunday","1/1-12/31","Sun",[24,18.3]] - options_radiant_heating = {"name" => ruleset_name, - "winter_design_day" => winter_design_day, - "summer_design_day" => summer_design_day, - "default_day" => default_day, - "rules" => rules} + rules << ['Saturday', '1/1-12/31', 'Sat', [6, 18.3], [18, 18.8], [24, 18.3]] + rules << ['Sunday', '1/1-12/31', 'Sun', [24, 18.3]] + options_radiant_heating = { 'name' => ruleset_name, + 'winter_design_day' => winter_design_day, + 'summer_design_day' => summer_design_day, + 'default_day' => default_day, + 'rules' => rules } mean_radiant_heating_schedule = OsLib_Schedules.createComplexSchedule(model, options_radiant_heating) - schedulesHVAC["mean_radiant_heating"] = mean_radiant_heating_schedule + schedulesHVAC['mean_radiant_heating'] = mean_radiant_heating_schedule # mean radiant cooling setpoint schedule (PNNL values) - ruleset_name = "New Office Mean Radiant Cooling Setpoint Schedule" - winter_design_day = [[6,26.7],[22,24.0],[24,26.7]] - summer_design_day = [[24,24.0]] - default_day = ["Weekday",[6,26.7],[22,24.0],[24,26.7]] + ruleset_name = 'New Office Mean Radiant Cooling Setpoint Schedule' + winter_design_day = [[6, 26.7], [22, 24.0], [24, 26.7]] + summer_design_day = [[24, 24.0]] + default_day = ['Weekday', [6, 26.7], [22, 24.0], [24, 26.7]] rules = [] - rules << ["Saturday","1/1-12/31","Sat",[6,26.7],[18,24.0],[24,26.7]] - rules << ["Sunday","1/1-12/31","Sun",[24,26.7]] - options_radiant_cooling = {"name" => ruleset_name, - "winter_design_day" => winter_design_day, - "summer_design_day" => summer_design_day, - "default_day" => default_day, - "rules" => rules} + rules << ['Saturday', '1/1-12/31', 'Sat', [6, 26.7], [18, 24.0], [24, 26.7]] + rules << ['Sunday', '1/1-12/31', 'Sun', [24, 26.7]] + options_radiant_cooling = { 'name' => ruleset_name, + 'winter_design_day' => winter_design_day, + 'summer_design_day' => summer_design_day, + 'default_day' => default_day, + 'rules' => rules } mean_radiant_cooling_schedule = OsLib_Schedules.createComplexSchedule(model, options_radiant_cooling) - schedulesHVAC["mean_radiant_cooling"] = mean_radiant_cooling_schedule + schedulesHVAC['mean_radiant_cooling'] = mean_radiant_cooling_schedule end end # SAT schedule - if options["allHVAC"]["primary"]["doas"] + if options['allHVAC']['primary']['doas'] # primary airloop is DOAS - schedulesHVAC["primary_sat"] = sch_ruleset_DOAS_setpoint = OsLib_Schedules.createComplexSchedule(model, {"name" => "DOAS Temperature Setpoint Schedule", - "default_day" => ["All Days",[24,21.111]]}) - else + schedulesHVAC['primary_sat'] = sch_ruleset_DOAS_setpoint = OsLib_Schedules.createComplexSchedule(model, 'name' => 'DOAS Temperature Setpoint Schedule', + 'default_day' => ['All Days', [24, 21.111]]) + else # primary airloop is multizone VAV that cools - schedulesHVAC["primary_sat"] = sch_ruleset_DOAS_setpoint = OsLib_Schedules.createComplexSchedule(model, {"name" => "Cold Deck Temperature Setpoint Schedule", - "default_day" => ["All Days",[24,12.8]]}) + schedulesHVAC['primary_sat'] = sch_ruleset_DOAS_setpoint = OsLib_Schedules.createComplexSchedule(model, 'name' => 'Cold Deck Temperature Setpoint Schedule', + 'default_day' => ['All Days', [24, 12.8]]) end - schedulesHVAC["ventilation"] = building_ventilation_schedule - schedulesHVAC["hvac"] = building_HVAC_schedule + schedulesHVAC['ventilation'] = building_ventilation_schedule + schedulesHVAC['hvac'] = building_HVAC_schedule # build new plant schedules as needed - zoneHVACHotWaterPlant = ["FanCoil","DualDuct","Baseboard"] # dual duct has fan coil and baseboard - zoneHVACChilledWaterPlant = ["FanCoil","DualDuct"] # dual duct has fan coil + zoneHVACHotWaterPlant = ['FanCoil', 'DualDuct', 'Baseboard'] # dual duct has fan coil and baseboard + zoneHVACChilledWaterPlant = ['FanCoil', 'DualDuct'] # dual duct has fan coil # hot water - if options["allHVAC"]["primary"]["heat"] == "Water" or options["allHVAC"]["secondary"]["heat"] == "Water" or zoneHVACHotWaterPlant.include? options["allHVAC"]["zone"] - schedulesHVAC["hot_water"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "HW-Loop-Temp-Schedule", - "default_day" => ["All Days",[24,67.0]]}) + if (options['allHVAC']['primary']['heat'] == 'Water') || (options['allHVAC']['secondary']['heat'] == 'Water') || zoneHVACHotWaterPlant.include?(options['allHVAC']['zone']) + schedulesHVAC['hot_water'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'HW-Loop-Temp-Schedule', + 'default_day' => ['All Days', [24, 67.0]]) end # chilled water - if options["allHVAC"]["primary"]["cool"] == "Water" or options["allHVAC"]["secondary"]["cool"] == "Water" or zoneHVACChilledWaterPlant.include? options["allHVAC"]["zone"] - schedulesHVAC["chilled_water"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "CW-Loop-Temp-Schedule", - "default_day" => ["All Days",[24,6.7]]}) + if (options['allHVAC']['primary']['cool'] == 'Water') || (options['allHVAC']['secondary']['cool'] == 'Water') || zoneHVACChilledWaterPlant.include?(options['allHVAC']['zone']) + schedulesHVAC['chilled_water'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'CW-Loop-Temp-Schedule', + 'default_day' => ['All Days', [24, 6.7]]) end # heat pump condenser loop schedules - if options["allHVAC"]["zone"] == "GSHP" + if options['allHVAC']['zone'] == 'GSHP' # there will be a heat pump condenser loop # loop setpoint schedule - schedulesHVAC["hp_loop"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HP-Loop-Temp-Schedule", - "default_day" => ["All Days",[24,21]]}) + schedulesHVAC['hp_loop'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Temp-Schedule', + 'default_day' => ['All Days', [24, 21]]) # cooling component schedule (#ML won't need this if a ground loop is actually modeled) - schedulesHVAC["hp_loop_cooling"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HP-Loop-Clg-Temp-Schedule", - "default_day" => ["All Days",[24,21]]}) + schedulesHVAC['hp_loop_cooling'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Clg-Temp-Schedule', + 'default_day' => ['All Days', [24, 21]]) # heating component schedule - schedulesHVAC["hp_loop_heating"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HP-Loop-Htg-Temp-Schedule", - "default_day" => ["All Days",[24,5]]}) + schedulesHVAC['hp_loop_heating'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Htg-Temp-Schedule', + 'default_day' => ['All Days', [24, 5]]) end - if options["allHVAC"]["zone"] == "WSHP" or options["allHVAC"]["zone"] == "VRF" + if (options['allHVAC']['zone'] == 'WSHP') || (options['allHVAC']['zone'] == 'VRF') # there will be a heat pump condenser loop # loop setpoint schedule - schedulesHVAC["hp_loop"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HP-Loop-Temp-Schedule", - "default_day" => ["All Days",[24,30]]}) #PNNL + schedulesHVAC['hp_loop'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Temp-Schedule', + 'default_day' => ['All Days', [24, 30]]) # PNNL # cooling component schedule (#ML won't need this if a ground loop is actually modeled) - schedulesHVAC["hp_loop_cooling"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HP-Loop-Clg-Temp-Schedule", - "default_day" => ["All Days",[24,30]]}) #PNNL + schedulesHVAC['hp_loop_cooling'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Clg-Temp-Schedule', + 'default_day' => ['All Days', [24, 30]]) # PNNL # heating component schedule - schedulesHVAC["hp_loop_heating"] = OsLib_Schedules.createComplexSchedule(model, {"name" => "New HP-Loop-Htg-Temp-Schedule", - "default_day" => ["All Days",[24,20]]}) #PNNL + schedulesHVAC['hp_loop_heating'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Htg-Temp-Schedule', + 'default_day' => ['All Days', [24, 20]]) # PNNL end - + # pass back schedulesHVAC hash result = schedulesHVAC return result - end # end of def - def OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, loop_type, parameters) - + def self.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, loop_type, parameters) hot_water_plant = OpenStudio::Model::PlantLoop.new(model) hot_water_plant.setName("New #{loop_type} Loop") hot_water_plant.setMaximumLoopTemperature(100) hot_water_plant.setMinimumLoopTemperature(10) loop_sizing = hot_water_plant.sizingPlant - loop_sizing.setLoopType("Heating") - if loop_type == "Hot Water" + loop_sizing.setLoopType('Heating') + if loop_type == 'Hot Water' loop_sizing.setDesignLoopExitTemperature(82) - elsif loop_type == "Radiant Hot Water" - loop_sizing.setDesignLoopExitTemperature(60) #ML follows convention of sizing temp being larger than supplu temp - end + elsif loop_type == 'Radiant Hot Water' + loop_sizing.setDesignLoopExitTemperature(60) # ML follows convention of sizing temp being larger than supplu temp + end loop_sizing.setLoopDesignTemperatureDifference(11) # create a pump pump = OpenStudio::Model::PumpVariableSpeed.new(model) - pump.setRatedPumpHead(119563) #Pa + pump.setRatedPumpHead(119563) # Pa pump.setMotorEfficiency(0.9) pump.setCoefficient1ofthePartLoadPerformanceCurve(0) pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216) @@ -465,7 +450,7 @@ def OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, l boiler = OpenStudio::Model::BoilerHotWater.new(model) boiler.setNominalThermalEfficiency(0.9) # create a scheduled setpoint manager - setpoint_manager_scheduled = OpenStudio::Model::SetpointManagerScheduled.new(model,hot_water_setpoint_schedule) + setpoint_manager_scheduled = OpenStudio::Model::SetpointManagerScheduled.new(model, hot_water_setpoint_schedule) # create a supply bypass pipe pipe_supply_bypass = OpenStudio::Model::PipeAdiabatic.new(model) # create a supply outlet pipe @@ -491,34 +476,32 @@ def OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, l # pass back hot water plant result = hot_water_plant return result - end # end of def - def OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, loop_type, chillerType) - + def self.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, loop_type, chillerType) # chilled water plant chilled_water_plant = OpenStudio::Model::PlantLoop.new(model) chilled_water_plant.setName("New #{loop_type} Loop") chilled_water_plant.setMaximumLoopTemperature(98) chilled_water_plant.setMinimumLoopTemperature(1) loop_sizing = chilled_water_plant.sizingPlant - loop_sizing.setLoopType("Cooling") - if loop_type == "Chilled Water" + loop_sizing.setLoopType('Cooling') + if loop_type == 'Chilled Water' loop_sizing.setDesignLoopExitTemperature(6.7) - elsif loop_type == "Radiant Chilled Water" + elsif loop_type == 'Radiant Chilled Water' loop_sizing.setDesignLoopExitTemperature(15) - end + end loop_sizing.setLoopDesignTemperatureDifference(6.7) # create a pump pump = OpenStudio::Model::PumpVariableSpeed.new(model) - pump.setRatedPumpHead(149453) #Pa + pump.setRatedPumpHead(149453) # Pa pump.setMotorEfficiency(0.9) pump.setCoefficient1ofthePartLoadPerformanceCurve(0) pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216) pump.setCoefficient3ofthePartLoadPerformanceCurve(-0.0325) pump.setCoefficient4ofthePartLoadPerformanceCurve(1.0095) # create a chiller - if chillerType == "WaterCooled" + if chillerType == 'WaterCooled' # create clgCapFuncTempCurve clgCapFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model) clgCapFuncTempCurve.setCoefficient1Constant(1.07E+00) @@ -551,11 +534,11 @@ def OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_sch eirFuncPlrCurve.setMinimumValueofx(0) eirFuncPlrCurve.setMaximumValueofx(1.2) # construct chiller - chiller = OpenStudio::Model::ChillerElectricEIR.new(model,clgCapFuncTempCurve,eirFuncTempCurve,eirFuncPlrCurve) + chiller = OpenStudio::Model::ChillerElectricEIR.new(model, clgCapFuncTempCurve, eirFuncTempCurve, eirFuncPlrCurve) chiller.setReferenceCOP(6.1) - chiller.setCondenserType("WaterCooled") - chiller.setChillerFlowMode("ConstantFlow") - elsif chillerType == "AirCooled" + chiller.setCondenserType('WaterCooled') + chiller.setChillerFlowMode('ConstantFlow') + elsif chillerType == 'AirCooled' # create clgCapFuncTempCurve clgCapFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model) clgCapFuncTempCurve.setCoefficient1Constant(1.05E+00) @@ -588,13 +571,13 @@ def OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_sch eirFuncPlrCurve.setMinimumValueofx(0) eirFuncPlrCurve.setMaximumValueofx(1.2) # construct chiller - chiller = OpenStudio::Model::ChillerElectricEIR.new(model,clgCapFuncTempCurve,eirFuncTempCurve,eirFuncPlrCurve) + chiller = OpenStudio::Model::ChillerElectricEIR.new(model, clgCapFuncTempCurve, eirFuncTempCurve, eirFuncPlrCurve) chiller.setReferenceCOP(2.93) - chiller.setCondenserType("AirCooled") - chiller.setChillerFlowMode("ConstantFlow") + chiller.setCondenserType('AirCooled') + chiller.setChillerFlowMode('ConstantFlow') end # create a scheduled setpoint manager - setpoint_manager_scheduled = OpenStudio::Model::SetpointManagerScheduled.new(model,chilled_water_setpoint_schedule) + setpoint_manager_scheduled = OpenStudio::Model::SetpointManagerScheduled.new(model, chilled_water_setpoint_schedule) # create a supply bypass pipe pipe_supply_bypass = OpenStudio::Model::PipeAdiabatic.new(model) # create a supply outlet pipe @@ -620,39 +603,37 @@ def OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_sch # pass back chilled water plant result = chilled_water_plant return result - end # end of def - def OsLib_HVAC.createCondenserLoop(model, runner, options, parameters) - + def self.createCondenserLoop(model, runner, options, parameters) condenserLoops = {} # condLoopCoolingTemp_si = OpenStudio::convert(parameters["condLoopCoolingTemp"],"F","C").get # condLoopHeatingTemp_si = OpenStudio::convert(parameters["condLoopHeatingTemp"],"F","C").get - # coolingTowerWB_si = OpenStudio::convert(parameters["coolingTowerWB"],"F","C").get - # boilerHWST_si = OpenStudio::convert(parameters["boilerHWST"],"F","C").get + # coolingTowerWB_si = OpenStudio::convert(parameters["coolingTowerWB"],"F","C").get + # boilerHWST_si = OpenStudio::convert(parameters["boilerHWST"],"F","C").get # check for water-cooled chillers waterCooledChiller = false model.getChillerElectricEIRs.each do |chiller| next if waterCooledChiller == true - if chiller.condenserType == "WaterCooled" + if chiller.condenserType == 'WaterCooled' waterCooledChiller = true - end + end end # create condenser loop for water-cooled chillers if waterCooledChiller # create condenser loop for water-cooled chiller(s) condenser_loop = OpenStudio::Model::PlantLoop.new(model) - condenser_loop.setName("New Condenser Loop") + condenser_loop.setName('New Condenser Loop') condenser_loop.setMaximumLoopTemperature(80) condenser_loop.setMinimumLoopTemperature(5) loop_sizing = condenser_loop.sizingPlant - loop_sizing.setLoopType("Condenser") + loop_sizing.setLoopType('Condenser') loop_sizing.setDesignLoopExitTemperature(29.4) loop_sizing.setLoopDesignTemperatureDifference(5.6) # create a pump pump = OpenStudio::Model::PumpVariableSpeed.new(model) - pump.setRatedPumpHead(134508) #Pa + pump.setRatedPumpHead(134508) # Pa pump.setMotorEfficiency(0.9) pump.setCoefficient1ofthePartLoadPerformanceCurve(0) pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216) @@ -684,34 +665,34 @@ def OsLib_HVAC.createCondenserLoop(model, runner, options, parameters) setpoint_manager_follow_oa.addToNode(condenser_loop.supplyOutletNode) # demand side components model.getChillerElectricEIRs.each do |chiller| - if chiller.condenserType == "WaterCooled" # works only if chillers not already connected to condenser loop(s) + if chiller.condenserType == 'WaterCooled' # works only if chillers not already connected to condenser loop(s) condenser_loop.addDemandBranchForComponent(chiller) - end + end end condenser_loop.addDemandBranchForComponent(pipe_demand_bypass) pipe_demand_inlet.addToNode(condenser_loop.demandInletNode) pipe_demand_outlet.addToNode(condenser_loop.demandOutletNode) - condenserLoops["condenser_loop"] = condenser_loop + condenserLoops['condenser_loop'] = condenser_loop end - if options["zoneHVAC"] == "WSHP" or options["zoneHVAC"] == "VRF" + if (options['zoneHVAC'] == 'WSHP') || (options['zoneHVAC'] == 'VRF') # create condenser loop for heat pumps condenser_loop = OpenStudio::Model::PlantLoop.new(model) - condenser_loop.setName("Heat Pump Loop") + condenser_loop.setName('Heat Pump Loop') condenser_loop.setMaximumLoopTemperature(80) condenser_loop.setMinimumLoopTemperature(5) loop_sizing = condenser_loop.sizingPlant - loop_sizing.setLoopType("Condenser") - - if options["zoneHVAC"] == "GSHP" + loop_sizing.setLoopType('Condenser') + + if options['zoneHVAC'] == 'GSHP' loop_sizing.setDesignLoopExitTemperature(condLoopCoolingTemp_si) - loop_sizing.setLoopDesignTemperatureDifference(10/1.8) - elsif options["zoneHVAC"] == "WSHP" or options["zoneHVAC"] == "VRF" + loop_sizing.setLoopDesignTemperatureDifference(10 / 1.8) + elsif (options['zoneHVAC'] == 'WSHP') || (options['zoneHVAC'] == 'VRF') loop_sizing.setDesignLoopExitTemperature(32.222) - loop_sizing.setLoopDesignTemperatureDifference(10/1.8) - end + loop_sizing.setLoopDesignTemperatureDifference(10 / 1.8) + end # create a pump pump = OpenStudio::Model::PumpVariableSpeed.new(model) - pump.setRatedPumpHead(134508) #Pa + pump.setRatedPumpHead(134508) # Pa pump.setMotorEfficiency(0.9) pump.setCoefficient1ofthePartLoadPerformanceCurve(0) pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216) @@ -728,9 +709,9 @@ def OsLib_HVAC.createCondenserLoop(model, runner, options, parameters) # create a demand outlet pipe pipe_demand_outlet = OpenStudio::Model::PipeAdiabatic.new(model) # create setpoint managers - setpoint_manager_scheduled_loop = OpenStudio::Model::SetpointManagerScheduled.new(model,options["loop_setpoint_schedule"]) - setpoint_manager_scheduled_cooling = OpenStudio::Model::SetpointManagerScheduled.new(model,options["cooling_setpoint_schedule"]) - setpoint_manager_scheduled_heating = OpenStudio::Model::SetpointManagerScheduled.new(model,options["heating_setpoint_schedule"]) + setpoint_manager_scheduled_loop = OpenStudio::Model::SetpointManagerScheduled.new(model, options['loop_setpoint_schedule']) + setpoint_manager_scheduled_cooling = OpenStudio::Model::SetpointManagerScheduled.new(model, options['cooling_setpoint_schedule']) + setpoint_manager_scheduled_heating = OpenStudio::Model::SetpointManagerScheduled.new(model, options['heating_setpoint_schedule']) # connect components to plant loop # supply side components condenser_loop.addSupplyBranchForComponent(pipe_supply_bypass) @@ -742,7 +723,7 @@ def OsLib_HVAC.createCondenserLoop(model, runner, options, parameters) pipe_demand_inlet.addToNode(condenser_loop.demandInletNode) pipe_demand_outlet.addToNode(condenser_loop.demandOutletNode) # add additional components according to specific system type - if options["zoneHVAC"] == "GSHP" + if options['zoneHVAC'] == 'GSHP' # add district cooling and heating to supply side district_cooling = OpenStudio::Model::DistrictCooling.new(model) district_cooling.setNominalCapacity(1000000000000) # large number; no autosizing @@ -753,52 +734,52 @@ def OsLib_HVAC.createCondenserLoop(model, runner, options, parameters) district_heating.addToNode(district_cooling.outletModelObject.get.to_Node.get) setpoint_manager_scheduled_heating.addToNode(district_heating.outletModelObject.get.to_Node.get) # add heat pumps to demand side after they get created - elsif options["zoneHVAC"] == "WSHP" + elsif options['zoneHVAC'] == 'WSHP' # add a boiler and cooling tower to supply side # create a boiler boiler = OpenStudio::Model::BoilerHotWater.new(model) - boiler.setNominalThermalEfficiency(parameters["boilerEff"]) - boiler.setFuelType(parameters["boilerFuelType"]) - boiler.setDesignWaterOutletTemperature(boilerHWST_si) + boiler.setNominalThermalEfficiency(parameters['boilerEff']) + boiler.setFuelType(parameters['boilerFuelType']) + boiler.setDesignWaterOutletTemperature(boilerHWST_si) condenser_loop.addSupplyBranchForComponent(boiler) setpoint_manager_scheduled_heating.addToNode(boiler.outletModelObject.get.to_Node.get) # create a cooling tower tower = OpenStudio::Model::CoolingTowerVariableSpeed.new(model) - tower.setDesignInletAirWetBulbTemperature(coolingTowerWB_si) - tower.setDesignApproachTemperature(parameters["coolingTowerApproach"]/1.8) - tower.setDesignRangeTemperature(parameters["coolingTowerDeltaT"]/1.8) + tower.setDesignInletAirWetBulbTemperature(coolingTowerWB_si) + tower.setDesignApproachTemperature(parameters['coolingTowerApproach'] / 1.8) + tower.setDesignRangeTemperature(parameters['coolingTowerDeltaT'] / 1.8) tower.addToNode(boiler.outletModelObject.get.to_Node.get) setpoint_manager_scheduled_cooling.addToNode(tower.outletModelObject.get.to_Node.get) - elsif options["zoneHVAC"] == "VRF" + elsif options['zoneHVAC'] == 'VRF' # add a boiler and cooling tower to supply side # create a boiler boiler = OpenStudio::Model::BoilerHotWater.new(model) boiler.setNominalThermalEfficiency(0.9) - boiler.setDesignWaterOutletTemperature(48) + boiler.setDesignWaterOutletTemperature(48) condenser_loop.addSupplyBranchForComponent(boiler) setpoint_manager_scheduled_heating.addToNode(boiler.outletModelObject.get.to_Node.get) # create a cooling tower tower = OpenStudio::Model::CoolingTowerVariableSpeed.new(model) - tower.setDesignInletAirWetBulbTemperature(20) - tower.setDesignApproachTemperature(3.89) - tower.setDesignRangeTemperature(5.56) + tower.setDesignInletAirWetBulbTemperature(20) + tower.setDesignApproachTemperature(3.89) + tower.setDesignRangeTemperature(5.56) tower.addToNode(boiler.outletModelObject.get.to_Node.get) - setpoint_manager_scheduled_cooling.addToNode(tower.outletModelObject.get.to_Node.get) + setpoint_manager_scheduled_cooling.addToNode(tower.outletModelObject.get.to_Node.get) end - condenserLoops["heat_pump_loop"] = condenser_loop + condenserLoops['heat_pump_loop'] = condenser_loop end - + # pass back condenser loop(s) result = condenserLoops return result - end # end of def - def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) + + def self.createPrimaryAirLoops(model, runner, options, parameters) primary_airloops = [] # create primary airloop for each story assignedThermalZones = [] model.getBuildingStorys.sort.each do |building_story| - #ML stories need to be reordered from the ground up + # ML stories need to be reordered from the ground up thermalZonesToAdd = [] building_story.spaces.each do |space| # make sure spaces are assigned to thermal zones @@ -806,7 +787,7 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) if space.thermalZone.is_initialized thermal_zone = space.thermalZone.get # grab primary zones - if options["zonesPrimary"].include? thermal_zone + if options['zonesPrimary'].include? thermal_zone # make sure zone was not already assigned to another air loop unless assignedThermalZones.include? thermal_zone # make sure thermal zones are not duplicated (spaces can share thermal zones) @@ -814,12 +795,12 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) thermalZonesToAdd << thermal_zone end end - end - end + end + end end # make sure thermal zones don't get added to more than one air loop assignedThermalZones << thermalZonesToAdd - + # create new air loop if story contains primary zones unless thermalZonesToAdd.empty? airloop_primary = OpenStudio::Model::AirLoopHVAC.new(model) @@ -828,31 +809,31 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) sizing_system = airloop_primary.sizingSystem # set central heating and cooling temperatures for sizing sizing_system.setCentralCoolingDesignSupplyAirTemperature(12.8) - sizing_system.setCentralHeatingDesignSupplyAirTemperature(40) #ML OS default is 16.7 + sizing_system.setCentralHeatingDesignSupplyAirTemperature(40) # ML OS default is 16.7 # load specification - sizing_system.setSystemOutdoorAirMethod("VentilationRateProcedure") #ML OS default is ZoneSum - if options["primaryHVAC"]["doas"] - sizing_system.setTypeofLoadtoSizeOn("VentilationRequirement") #DOAS - sizing_system.setAllOutdoorAirinCooling(true) #DOAS - sizing_system.setAllOutdoorAirinHeating(true) #DOAS - else - sizing_system.setTypeofLoadtoSizeOn("Sensible") #VAV - sizing_system.setAllOutdoorAirinCooling(false) #VAV - sizing_system.setAllOutdoorAirinHeating(false) #VAV - end + sizing_system.setSystemOutdoorAirMethod('VentilationRateProcedure') # ML OS default is ZoneSum + if options['primaryHVAC']['doas'] + sizing_system.setTypeofLoadtoSizeOn('VentilationRequirement') # DOAS + sizing_system.setAllOutdoorAirinCooling(true) # DOAS + sizing_system.setAllOutdoorAirinHeating(true) # DOAS + else + sizing_system.setTypeofLoadtoSizeOn('Sensible') # VAV + sizing_system.setAllOutdoorAirinCooling(false) # VAV + sizing_system.setAllOutdoorAirinHeating(false) # VAV + end air_loop_comps = [] # set availability schedule - airloop_primary.setAvailabilitySchedule(options["hvac_schedule"]) + airloop_primary.setAvailabilitySchedule(options['hvac_schedule']) # create air loop fan - if options["primaryHVAC"]["fan"] == "Variable" + if options['primaryHVAC']['fan'] == 'Variable' # create variable speed fan and set system sizing accordingly - sizing_system.setMinimumSystemAirFlowRatio(0.3) #DCV + sizing_system.setMinimumSystemAirFlowRatio(0.3) # DCV # variable speed fan - fan = OpenStudio::Model::FanVariableVolume.new(model, model.alwaysOnDiscreteSchedule()) + fan = OpenStudio::Model::FanVariableVolume.new(model, model.alwaysOnDiscreteSchedule) fan.setFanEfficiency(0.69) - fan.setPressureRise(1125) #Pa - fan.autosizeMaximumFlowRate() + fan.setPressureRise(1125) # Pa + fan.autosizeMaximumFlowRate fan.setFanPowerMinimumFlowFraction(0.6) fan.setMotorEfficiency(0.9) fan.setMotorInAirstreamFraction(1.0) @@ -860,30 +841,30 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) else sizing_system.setMinimumSystemAirFlowRatio(1.0) # No DCV # constant speed fan - fan = OpenStudio::Model::FanConstantVolume.new(model, model.alwaysOnDiscreteSchedule()) + fan = OpenStudio::Model::FanConstantVolume.new(model, model.alwaysOnDiscreteSchedule) fan.setFanEfficiency(0.6) - fan.setPressureRise(500) #Pa - fan.autosizeMaximumFlowRate() + fan.setPressureRise(500) # Pa + fan.autosizeMaximumFlowRate fan.setMotorEfficiency(0.9) fan.setMotorInAirstreamFraction(1.0) air_loop_comps << fan - end + end # create heating coil - if options["primaryHVAC"]["heat"] == "Water" + if options['primaryHVAC']['heat'] == 'Water' # water coil - heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule()) + heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule) air_loop_comps << heating_coil - else + else # gas coil - heating_coil = OpenStudio::Model::CoilHeatingGas.new(model, model.alwaysOnDiscreteSchedule()) + heating_coil = OpenStudio::Model::CoilHeatingGas.new(model, model.alwaysOnDiscreteSchedule) air_loop_comps << heating_coil - end + end # create cooling coil - if options["primaryHVAC"]["cool"] == "Water" + if options['primaryHVAC']['cool'] == 'Water' # water coil - cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule()) + cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule) air_loop_comps << cooling_coil - elsif options["primaryHVAC"]["cool"] == "SingleDX" + elsif options['primaryHVAC']['cool'] == 'SingleDX' # single speed DX coil # create cooling coil # create clgCapFuncTempCurve @@ -933,13 +914,13 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) clgPlrCurve.setMaximumValueofx(1.0) # cooling coil cooling_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model, - model.alwaysOnDiscreteSchedule(), - clgCapFuncTempCurve, - clgCapFuncFlowFracCurve, - clgEirFuncTempCurve, - clgEirFuncFlowFracCurve, - clgPlrCurve) - cooling_coil.setRatedCOP(OpenStudio::OptionalDouble.new(parameters["doasDXEER"]/3.412)) + model.alwaysOnDiscreteSchedule, + clgCapFuncTempCurve, + clgCapFuncFlowFracCurve, + clgEirFuncTempCurve, + clgEirFuncFlowFracCurve, + clgPlrCurve) + cooling_coil.setRatedCOP(OpenStudio::OptionalDouble.new(parameters['doasDXEER'] / 3.412)) air_loop_comps << cooling_coil else # two speed DX coil (PNNL curves) @@ -991,7 +972,7 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) clgPlrCurve.setMaximumValueofx(1.0) # cooling coil cooling_coil = OpenStudio::Model::CoilCoolingDXTwoSpeed.new(model, - model.alwaysOnDiscreteSchedule(), + model.alwaysOnDiscreteSchedule, clgCapFuncTempCurve, clgCapFuncFlowFracCurve, clgEirFuncTempCurve, @@ -999,86 +980,86 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) clgPlrCurve, clgCapFuncTempCurve, clgEirFuncTempCurve) - cooling_coil.setRatedHighSpeedCOP(parameters["doasDXEER"]/3.412) - cooling_coil.setRatedLowSpeedCOP(parameters["doasDXEER"]/3.412) + cooling_coil.setRatedHighSpeedCOP(parameters['doasDXEER'] / 3.412) + cooling_coil.setRatedLowSpeedCOP(parameters['doasDXEER'] / 3.412) air_loop_comps << cooling_coil end - unless options["zoneHVAC"] == "DualDuct" + unless options['zoneHVAC'] == 'DualDuct' # create controller outdoor air controller_OA = OpenStudio::Model::ControllerOutdoorAir.new(model) - controller_OA.autosizeMinimumOutdoorAirFlowRate() - controller_OA.autosizeMaximumOutdoorAirFlowRate() + controller_OA.autosizeMinimumOutdoorAirFlowRate + controller_OA.autosizeMaximumOutdoorAirFlowRate # create ventilation schedules and assign to OA controller - if options["primaryHVAC"]["doas"] - controller_OA.setMinimumFractionofOutdoorAirSchedule(model.alwaysOnDiscreteSchedule()) - controller_OA.setMaximumFractionofOutdoorAirSchedule(model.alwaysOnDiscreteSchedule()) + if options['primaryHVAC']['doas'] + controller_OA.setMinimumFractionofOutdoorAirSchedule(model.alwaysOnDiscreteSchedule) + controller_OA.setMaximumFractionofOutdoorAirSchedule(model.alwaysOnDiscreteSchedule) else # multizone VAV that ventilates - controller_OA.setMaximumFractionofOutdoorAirSchedule(options["ventilation_schedule"]) - controller_OA.setEconomizerControlType("DifferentialEnthalpy") + controller_OA.setMaximumFractionofOutdoorAirSchedule(options['ventilation_schedule']) + controller_OA.setEconomizerControlType('DifferentialEnthalpy') # add night cycling (ML would people actually do this for a VAV system?)) - airloop_primary.setNightCycleControlType("CycleOnAny") #ML Does this work with variable speed fans? - end - controller_OA.setHeatRecoveryBypassControlType("BypassWhenOAFlowGreaterThanMinimum") + airloop_primary.setNightCycleControlType('CycleOnAny') # ML Does this work with variable speed fans? + end + controller_OA.setHeatRecoveryBypassControlType('BypassWhenOAFlowGreaterThanMinimum') # create outdoor air system system_OA = OpenStudio::Model::AirLoopHVACOutdoorAirSystem.new(model, controller_OA) air_loop_comps << system_OA # create Evaporative cooler - unless parameters["doasEvap"] =="none" - evap_cooler = OpenStudio::Model::EvaporativeCoolerDirectResearchSpecial.new(model,model.alwaysOnDiscreteSchedule()) - evap_cooler.setCoolerEffectiveness(0.85) - end - # create ERV - unless parameters["doasERV"] == "none" - heat_exchanger = OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent.new(model) - heat_exchanger.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule()) - if parameters["doasERV"] == "rotary wheel w/o economizer lockout" - sensible_eff = 0.75 - latent_eff = 0.69 - #heat_exchanger.setEconomizerLockout(false) - heat_exchanger.setString(23,"No") - elsif parameters["doasERV"] == "rotary wheel w/ economizer lockout" - sensible_eff = 0.75 - latent_eff = 0.69 - # heat_exchanger.setEconomizerLockout(true) - heat_exchanger.setString(23,"Yes") - elsif parameters["doasERV"] == "plate w/o economizer lockout" - sensible_eff = 0.52 - latent_eff = 0.50 - #heat_exchanger.setEconomizerLockout(false) - heat_exchanger.setString(23,"No") - elsif parameters["doasERV"] == "plate w/ economizer lockout" - sensible_eff = 0.52 - latent_eff = 0.50 - # heat_exchanger.setEconomizerLockout(true) - heat_exchanger.setString(23,"Yes") - end - heat_exchanger.setSensibleEffectivenessat100CoolingAirFlow(sensible_eff) - heat_exchanger.setSensibleEffectivenessat100HeatingAirFlow(sensible_eff) - heat_exchanger.setSensibleEffectivenessat75CoolingAirFlow(sensible_eff) - heat_exchanger.setSensibleEffectivenessat75HeatingAirFlow(sensible_eff) - heat_exchanger.setLatentEffectivenessat100CoolingAirFlow(latent_eff) - heat_exchanger.setLatentEffectivenessat100HeatingAirFlow(latent_eff) - heat_exchanger.setLatentEffectivenessat75CoolingAirFlow(latent_eff) - heat_exchanger.setLatentEffectivenessat75HeatingAirFlow(latent_eff) - heat_exchanger.setFrostControlType("ExhaustOnly") - heat_exchanger.setThresholdTemperature(-12.2) - heat_exchanger.setInitialDefrostTimeFraction(0.1670) - heat_exchanger.setRateofDefrostTimeFractionIncrease(0.0240) - end + unless parameters['doasEvap'] == 'none' + evap_cooler = OpenStudio::Model::EvaporativeCoolerDirectResearchSpecial.new(model, model.alwaysOnDiscreteSchedule) + evap_cooler.setCoolerEffectiveness(0.85) + end + # create ERV + unless parameters['doasERV'] == 'none' + heat_exchanger = OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent.new(model) + heat_exchanger.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule) + if parameters['doasERV'] == 'rotary wheel w/o economizer lockout' + sensible_eff = 0.75 + latent_eff = 0.69 + # heat_exchanger.setEconomizerLockout(false) + heat_exchanger.setString(23, 'No') + elsif parameters['doasERV'] == 'rotary wheel w/ economizer lockout' + sensible_eff = 0.75 + latent_eff = 0.69 + # heat_exchanger.setEconomizerLockout(true) + heat_exchanger.setString(23, 'Yes') + elsif parameters['doasERV'] == 'plate w/o economizer lockout' + sensible_eff = 0.52 + latent_eff = 0.50 + # heat_exchanger.setEconomizerLockout(false) + heat_exchanger.setString(23, 'No') + elsif parameters['doasERV'] == 'plate w/ economizer lockout' + sensible_eff = 0.52 + latent_eff = 0.50 + # heat_exchanger.setEconomizerLockout(true) + heat_exchanger.setString(23, 'Yes') + end + heat_exchanger.setSensibleEffectivenessat100CoolingAirFlow(sensible_eff) + heat_exchanger.setSensibleEffectivenessat100HeatingAirFlow(sensible_eff) + heat_exchanger.setSensibleEffectivenessat75CoolingAirFlow(sensible_eff) + heat_exchanger.setSensibleEffectivenessat75HeatingAirFlow(sensible_eff) + heat_exchanger.setLatentEffectivenessat100CoolingAirFlow(latent_eff) + heat_exchanger.setLatentEffectivenessat100HeatingAirFlow(latent_eff) + heat_exchanger.setLatentEffectivenessat75CoolingAirFlow(latent_eff) + heat_exchanger.setLatentEffectivenessat75HeatingAirFlow(latent_eff) + heat_exchanger.setFrostControlType('ExhaustOnly') + heat_exchanger.setThresholdTemperature(-12.2) + heat_exchanger.setInitialDefrostTimeFraction(0.1670) + heat_exchanger.setRateofDefrostTimeFractionIncrease(0.0240) + end -end +end # create scheduled setpoint manager for airloop - unless (options["primaryHVAC"]["doas"] or options["zoneHVAC"] == "DualDuct") + if options['primaryHVAC']['doas'] || (options['zoneHVAC'] == 'DualDuct') + # DOAS or VAV for cooling and not ventilation + setpoint_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, options['primary_sat_schedule']) + else # VAV for cooling and ventilation setpoint_manager = OpenStudio::Model::SetpointManagerOutdoorAirReset.new(model) setpoint_manager.setSetpointatOutdoorLowTemperature(15.6) setpoint_manager.setOutdoorLowTemperature(14.4) setpoint_manager.setSetpointatOutdoorHighTemperature(12.8) setpoint_manager.setOutdoorHighTemperature(21.1) - else - # DOAS or VAV for cooling and not ventilation - setpoint_manager = OpenStudio::Model::SetpointManagerScheduled.new(model,options["primary_sat_schedule"]) end # connect components to airloop # find the supply inlet node of the airloop @@ -1087,55 +1068,54 @@ def OsLib_HVAC.createPrimaryAirLoops(model, runner, options, parameters) air_loop_comps.each do |comp| comp.addToNode(airloop_supply_inlet) if comp.to_CoilHeatingWater.is_initialized - options["hot_water_plant"].addDemandBranchForComponent(comp) + options['hot_water_plant'].addDemandBranchForComponent(comp) comp.controllerWaterCoil.get.setMinimumActuatedFlow(0) elsif comp.to_CoilCoolingWater.is_initialized - options["chilled_water_plant"].addDemandBranchForComponent(comp) + options['chilled_water_plant'].addDemandBranchForComponent(comp) comp.controllerWaterCoil.get.setMinimumActuatedFlow(0) end end - unless options["zoneHVAC"] == "DualDuct" or parameters["doasERV"] == "none" - heat_exchanger.addToNode(system_OA.outboardOANode.get) - end - - unless parameters["doasEvap"] == "none" - if parameters["doasERV"] == "none" - evap_cooler.addToNode(system_OA.outboardOANode.get) - else - hxPrimary_outlet_node = heat_exchanger.primaryAirOutletModelObject.get.to_Node.get - evap_cooler.addToNode(hxPrimary_outlet_node) - end - end - + unless (options['zoneHVAC'] == 'DualDuct') || (parameters['doasERV'] == 'none') + heat_exchanger.addToNode(system_OA.outboardOANode.get) + end + + unless parameters['doasEvap'] == 'none' + if parameters['doasERV'] == 'none' + evap_cooler.addToNode(system_OA.outboardOANode.get) + else + hxPrimary_outlet_node = heat_exchanger.primaryAirOutletModelObject.get.to_Node.get + evap_cooler.addToNode(hxPrimary_outlet_node) + end + end + # add setpoint manager to supply equipment outlet node setpoint_manager.addToNode(airloop_primary.supplyOutletNode) # add thermal zones to airloop thermalZonesToAdd.each do |zone| # make an air terminal for the zone - if options["primaryHVAC"]["fan"] == "Variable" - air_terminal = OpenStudio::Model::AirTerminalSingleDuctVAVNoReheat.new(model, model.alwaysOnDiscreteSchedule()) + if options['primaryHVAC']['fan'] == 'Variable' + air_terminal = OpenStudio::Model::AirTerminalSingleDuctVAVNoReheat.new(model, model.alwaysOnDiscreteSchedule) else - air_terminal = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule()) + air_terminal = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule) end # attach new terminal to the zone and to the airloop airloop_primary.addBranchForZone(zone, air_terminal.to_StraightComponent) - end - primary_airloops << airloop_primary + end + primary_airloops << airloop_primary end end # pass back primary airloops result = primary_airloops return result - end # end of def - def OsLib_HVAC.createVRFAirConditioners(model, runner, options, parameters) - vrf_AirConditioners = [] + def self.createVRFAirConditioners(model, runner, options, parameters) + vrf_AirConditioners = [] # create primary airloop for each story assignedThermalZones = [] model.getBuildingStorys.sort.each do |building_story| - #ML stories need to be reordered from the ground up + # ML stories need to be reordered from the ground up thermalZonesToAdd = [] building_story.spaces.each do |space| # make sure spaces are assigned to thermal zones @@ -1143,7 +1123,7 @@ def OsLib_HVAC.createVRFAirConditioners(model, runner, options, parameters) if space.thermalZone.is_initialized thermal_zone = space.thermalZone.get # grab primary zones - if options["zonesPrimary"].include? thermal_zone + if options['zonesPrimary'].include? thermal_zone # make sure zone was not already assigned to another air loop unless assignedThermalZones.include? thermal_zone # make sure thermal zones are not duplicated (spaces can share thermal zones) @@ -1151,114 +1131,112 @@ def OsLib_HVAC.createVRFAirConditioners(model, runner, options, parameters) thermalZonesToAdd << thermal_zone end end - end - end + end + end end # make sure thermal zones don't get added to more than one air loop assignedThermalZones << thermalZonesToAdd - - unless thermalZonesToAdd.empty? - # create new air loop if story contains primary zones - # add an air conditioner variable refrigerant flow to each floor - vrfAirConditioner = OpenStudio::Model::AirConditionerVariableRefrigerantFlow.new(model) - vrfAirConditioner.setName("VRF Heat Pump - #{building_story.name}") - vrfAirConditioner.setRatedCoolingCOP(parameters["vrfCoolCOP"]) - vrfAirConditioner.setRatedHeatingCOP(parameters["vrfHeatCOP"]) - vrfMinOATHPHeat_si = OpenStudio::convert(parameters["vrfMinOATHPHeat"],"F","C").get - vrfAirConditioner.setMinimumOutdoorTemperatureinHeatingMode(vrfMinOATHPHeat_si) - if parameters["vrfHPHeatRecovery"] == "Yes" - vrfAirConditioner.setHeatPumpWasteHeatRecovery(true) - else - vrfAirConditioner.setHeatPumpWasteHeatRecovery(false) - end - vrfAirConditioner.setDefrostStrategy(parameters["vrfDefrost"]) - vrfEquivPipingLength_si = OpenStudio::convert(parameters["vrfEquivPipingLength"],"ft","m").get - vrfPipingHeight_si = OpenStudio::convert(parameters["vrfPipingHeight"],"ft","m").get - vrfAirConditioner.setEquivalentPipingLengthusedforPipingCorrectionFactorinCoolingMode(vrfEquivPipingLength_si) - vrfAirConditioner.setEquivalentPipingLengthusedforPipingCorrectionFactorinHeatingMode(vrfEquivPipingLength_si) - vrfAirConditioner.setVerticalHeightusedforPipingCorrectionFactor(vrfPipingHeight_si) - vrfAirConditioner.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule()) - vrfAirConditioner.setZoneforMasterThermostatLocation(thermalZonesToAdd[0]) - if parameters["vrfCondenserType"] == "WaterCooled" - vrfAirConditioner.setString(56,"WaterCooled") - elsif parameters["vrfCondenserType"] == "EvaporativelyCooled" - vrfAirConditioner.setString(56,"EvaporativelyCooled") - end - if parameters["vrfCondenserType"] == "WaterCooled" - options["heat_pump_loop"].addDemandBranchForComponent(vrfAirConditioner) - end - - # add terminal unit to the air conditioner VRF, one TU per thermal zone - thermalZonesToAdd.each do |zone| - # construct Terminal VRF Unit - vrf_terminalUnit = OpenStudio::Model::ZoneHVACTerminalUnitVariableRefrigerantFlow.new(model) - vrf_terminalUnit.setTerminalUnitAvailabilityschedule(model.alwaysOnDiscreteSchedule()) - vrf_terminalUnit.setOutdoorAirFlowRateDuringCoolingOperation(0) - vrf_terminalUnit.setOutdoorAirFlowRateDuringHeatingOperation(0) - vrf_terminalUnit.setOutdoorAirFlowRateWhenNoCoolingorHeatingisNeeded(0) - vrf_terminalUnit.addToThermalZone(zone) - vrfAirConditioner.addTerminal(vrf_terminalUnit) - end - vrf_AirConditioners << vrfAirConditioner - end + + unless thermalZonesToAdd.empty? + # create new air loop if story contains primary zones + # add an air conditioner variable refrigerant flow to each floor + vrfAirConditioner = OpenStudio::Model::AirConditionerVariableRefrigerantFlow.new(model) + vrfAirConditioner.setName("VRF Heat Pump - #{building_story.name}") + vrfAirConditioner.setRatedCoolingCOP(parameters['vrfCoolCOP']) + vrfAirConditioner.setRatedHeatingCOP(parameters['vrfHeatCOP']) + vrfMinOATHPHeat_si = OpenStudio.convert(parameters['vrfMinOATHPHeat'], 'F', 'C').get + vrfAirConditioner.setMinimumOutdoorTemperatureinHeatingMode(vrfMinOATHPHeat_si) + if parameters['vrfHPHeatRecovery'] == 'Yes' + vrfAirConditioner.setHeatPumpWasteHeatRecovery(true) + else + vrfAirConditioner.setHeatPumpWasteHeatRecovery(false) + end + vrfAirConditioner.setDefrostStrategy(parameters['vrfDefrost']) + vrfEquivPipingLength_si = OpenStudio.convert(parameters['vrfEquivPipingLength'], 'ft', 'm').get + vrfPipingHeight_si = OpenStudio.convert(parameters['vrfPipingHeight'], 'ft', 'm').get + vrfAirConditioner.setEquivalentPipingLengthusedforPipingCorrectionFactorinCoolingMode(vrfEquivPipingLength_si) + vrfAirConditioner.setEquivalentPipingLengthusedforPipingCorrectionFactorinHeatingMode(vrfEquivPipingLength_si) + vrfAirConditioner.setVerticalHeightusedforPipingCorrectionFactor(vrfPipingHeight_si) + vrfAirConditioner.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule) + vrfAirConditioner.setZoneforMasterThermostatLocation(thermalZonesToAdd[0]) + if parameters['vrfCondenserType'] == 'WaterCooled' + vrfAirConditioner.setString(56, 'WaterCooled') + elsif parameters['vrfCondenserType'] == 'EvaporativelyCooled' + vrfAirConditioner.setString(56, 'EvaporativelyCooled') + end + if parameters['vrfCondenserType'] == 'WaterCooled' + options['heat_pump_loop'].addDemandBranchForComponent(vrfAirConditioner) + end + + # add terminal unit to the air conditioner VRF, one TU per thermal zone + thermalZonesToAdd.each do |zone| + # construct Terminal VRF Unit + vrf_terminalUnit = OpenStudio::Model::ZoneHVACTerminalUnitVariableRefrigerantFlow.new(model) + vrf_terminalUnit.setTerminalUnitAvailabilityschedule(model.alwaysOnDiscreteSchedule) + vrf_terminalUnit.setOutdoorAirFlowRateDuringCoolingOperation(0) + vrf_terminalUnit.setOutdoorAirFlowRateDuringHeatingOperation(0) + vrf_terminalUnit.setOutdoorAirFlowRateWhenNoCoolingorHeatingisNeeded(0) + vrf_terminalUnit.addToThermalZone(zone) + vrfAirConditioner.addTerminal(vrf_terminalUnit) + end + vrf_AirConditioners << vrfAirConditioner + end end # pass back primary airloops result = vrf_AirConditioners return result - end # end of def - def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options, parameters) - + def self.createPrimaryZoneEquipment(model, runner, options, parameters) model.getThermalZones.each do |zone| - if options["zonesPrimary"].include? zone - if options["zoneHVAC"] == "FanCoil" + if options['zonesPrimary'].include? zone + if options['zoneHVAC'] == 'FanCoil' # create fan coil # create fan - fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule()) + fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule) fan.setFanEfficiency(0.5) - fan.setPressureRise(75) #Pa - fan.autosizeMaximumFlowRate() + fan.setPressureRise(75) # Pa + fan.autosizeMaximumFlowRate fan.setMotorEfficiency(0.9) fan.setMotorInAirstreamFraction(1.0) # create cooling coil and connect to chilled water plant - cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule()) - options["chilled_water_plant"].addDemandBranchForComponent(cooling_coil) + cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule) + options['chilled_water_plant'].addDemandBranchForComponent(cooling_coil) cooling_coil.controllerWaterCoil.get.setMinimumActuatedFlow(0) # create heating coil and connect to hot water plant - heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule()) - options["hot_water_plant"].addDemandBranchForComponent(heating_coil) + heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule) + options['hot_water_plant'].addDemandBranchForComponent(heating_coil) heating_coil.controllerWaterCoil.get.setMinimumActuatedFlow(0) # construct fan coil fan_coil = OpenStudio::Model::ZoneHVACFourPipeFanCoil.new(model, - model.alwaysOnDiscreteSchedule(), + model.alwaysOnDiscreteSchedule, fan, cooling_coil, heating_coil) - fan_coil.setMaximumOutdoorAirFlowRate(0) + fan_coil.setMaximumOutdoorAirFlowRate(0) # add fan coil to thermal zone fan_coil.addToThermalZone(zone) - elsif options["zoneHVAC"] == "WSHP" or options["zoneHVAC"] == "GSHP" + elsif (options['zoneHVAC'] == 'WSHP') || (options['zoneHVAC'] == 'GSHP') # create water source heat pump and attach to heat pump loop # create fan - fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule()) - fan.setFanEfficiency(0.75) - fan_eff = fan.fanEfficiency() - fan.setMotorEfficiency(0.9) - motor_eff = fan.motorEfficiency() - fan.autosizeMaximumFlowRate() - if parameters["wshpFanType"] == "PSC" # use 0.3W/cfm, ECM - 0.2W/cfm + fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule) + fan.setFanEfficiency(0.75) + fan_eff = fan.fanEfficiency + fan.setMotorEfficiency(0.9) + motor_eff = fan.motorEfficiency + fan.autosizeMaximumFlowRate + if parameters['wshpFanType'] == 'PSC' # use 0.3W/cfm, ECM - 0.2W/cfm watt_per_cfm = 0.30 # W/cfm - else - watt_per_cfm = 0.20 # W/cfm - end - pres_rise = OpenStudio::convert(watt_per_cfm * fan_eff * motor_eff/0.1175,"inH_{2}O","Pa").get - fan.setPressureRise(pres_rise) #Pa - fan.setMotorInAirstreamFraction(1.0) + else + watt_per_cfm = 0.20 # W/cfm + end + pres_rise = OpenStudio.convert(watt_per_cfm * fan_eff * motor_eff / 0.1175, 'inH_{2}O', 'Pa').get + fan.setPressureRise(pres_rise) # Pa + fan.setMotorInAirstreamFraction(1.0) # create cooling coil and connect to heat pump loop cooling_coil = OpenStudio::Model::CoilCoolingWaterToAirHeatPumpEquationFit.new(model) - cooling_coil.setRatedCoolingCoefficientofPerformance(parameters["wshpCoolingEER"]/3.412) # xf 061014: need to change per fan power and pump power adjustment + cooling_coil.setRatedCoolingCoefficientofPerformance(parameters['wshpCoolingEER'] / 3.412) # xf 061014: need to change per fan power and pump power adjustment cooling_coil.setRatedCoolingCoefficientofPerformance(6.45) cooling_coil.setTotalCoolingCapacityCoefficient1(-9.149069561) cooling_coil.setTotalCoolingCapacityCoefficient2(10.87814026) @@ -1276,10 +1254,10 @@ def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options, parameters) cooling_coil.setCoolingPowerConsumptionCoefficient3(3.97892546) cooling_coil.setCoolingPowerConsumptionCoefficient4(0.938181818) cooling_coil.setCoolingPowerConsumptionCoefficient5(0.0) - options["heat_pump_loop"].addDemandBranchForComponent(cooling_coil) + options['heat_pump_loop'].addDemandBranchForComponent(cooling_coil) # create heating coil and connect to heat pump loop heating_coil = OpenStudio::Model::CoilHeatingWaterToAirHeatPumpEquationFit.new(model) - heating_coil.setRatedHeatingCoefficientofPerformance(parameters["wshpHeatingCOP"]) # xf 061014: need to change per fan power and pump power adjustment + heating_coil.setRatedHeatingCoefficientofPerformance(parameters['wshpHeatingCOP']) # xf 061014: need to change per fan power and pump power adjustment heating_coil.setRatedHeatingCoefficientofPerformance(4.0) heating_coil.setHeatingCapacityCoefficient1(-1.361311959) heating_coil.setHeatingCapacityCoefficient2(-2.471798046) @@ -1291,29 +1269,29 @@ def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options, parameters) heating_coil.setHeatingPowerConsumptionCoefficient3(1.570743399) heating_coil.setHeatingPowerConsumptionCoefficient4(0.690793651) heating_coil.setHeatingPowerConsumptionCoefficient5(0.0) - options["heat_pump_loop"].addDemandBranchForComponent(heating_coil) + options['heat_pump_loop'].addDemandBranchForComponent(heating_coil) # create supplemental heating coil - supplemental_heating_coil = OpenStudio::Model::CoilHeatingElectric.new(model, model.alwaysOnDiscreteSchedule()) + supplemental_heating_coil = OpenStudio::Model::CoilHeatingElectric.new(model, model.alwaysOnDiscreteSchedule) # construct heat pump heat_pump = OpenStudio::Model::ZoneHVACWaterToAirHeatPump.new(model, - model.alwaysOnDiscreteSchedule(), + model.alwaysOnDiscreteSchedule, fan, heating_coil, cooling_coil, - supplemental_heating_coil) + supplemental_heating_coil) heat_pump.setSupplyAirFlowRateWhenNoCoolingorHeatingisNeeded(OpenStudio::OptionalDouble.new(0)) heat_pump.setOutdoorAirFlowRateDuringCoolingOperation(OpenStudio::OptionalDouble.new(0)) heat_pump.setOutdoorAirFlowRateDuringHeatingOperation(OpenStudio::OptionalDouble.new(0)) heat_pump.setOutdoorAirFlowRateWhenNoCoolingorHeatingisNeeded(OpenStudio::OptionalDouble.new(0)) # add heat pump to thermal zone heat_pump.addToThermalZone(zone) - elsif options["zoneHVAC"] == "ASHP" + elsif options['zoneHVAC'] == 'ASHP' # create air source heat pump # create fan - fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule()) + fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule) fan.setFanEfficiency(0.5) - fan.setPressureRise(75) #Pa - fan.autosizeMaximumFlowRate() + fan.setPressureRise(75) # Pa + fan.autosizeMaximumFlowRate fan.setMotorEfficiency(0.9) fan.setMotorInAirstreamFraction(1.0) # create heating coil @@ -1357,12 +1335,12 @@ def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options, parameters) htgPlrCurve.setMaximumValueofx(1.0) # heating coil heating_coil = OpenStudio::Model::CoilHeatingDXSingleSpeed.new(model, - model.alwaysOnDiscreteSchedule(), - htgCapFuncTempCurve, - htgCapFuncFlowFracCurve, - htgEirFuncTempCurve, - htgEirFuncFlowFracCurve, - htgPlrCurve) + model.alwaysOnDiscreteSchedule, + htgCapFuncTempCurve, + htgCapFuncFlowFracCurve, + htgEirFuncTempCurve, + htgEirFuncFlowFracCurve, + htgPlrCurve) heating_coil.setRatedCOP(3.4) heating_coil.setCrankcaseHeaterCapacity(200) heating_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(8) @@ -1415,18 +1393,18 @@ def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options, parameters) clgPlrCurve.setMaximumValueofx(1.0) # cooling coil cooling_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model, - model.alwaysOnDiscreteSchedule(), - clgCapFuncTempCurve, - clgCapFuncFlowFracCurve, - clgEirFuncTempCurve, - clgEirFuncFlowFracCurve, - clgPlrCurve) + model.alwaysOnDiscreteSchedule, + clgCapFuncTempCurve, + clgCapFuncFlowFracCurve, + clgEirFuncTempCurve, + clgEirFuncFlowFracCurve, + clgPlrCurve) cooling_coil.setRatedCOP(OpenStudio::OptionalDouble.new(4)) # create supplemental heating coil - supplemental_heating_coil = OpenStudio::Model::CoilHeatingElectric.new(model, model.alwaysOnDiscreteSchedule()) + supplemental_heating_coil = OpenStudio::Model::CoilHeatingElectric.new(model, model.alwaysOnDiscreteSchedule) # construct heat pump heat_pump = OpenStudio::Model::ZoneHVACPackagedTerminalHeatPump.new(model, - model.alwaysOnDiscreteSchedule(), + model.alwaysOnDiscreteSchedule, fan, heating_coil, cooling_coil, @@ -1437,34 +1415,34 @@ def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options, parameters) heat_pump.setOutdoorAirFlowRateWhenNoCoolingorHeatingisNeeded(0) # add heat pump to thermal zone heat_pump.addToThermalZone(zone) - elsif options["zoneHVAC"] == "Baseboard" + elsif options['zoneHVAC'] == 'Baseboard' # create baseboard heater add add to thermal zone and hot water loop baseboard_coil = OpenStudio::Model::CoilHeatingWaterBaseboard.new(model) - baseboard_heater = OpenStudio::Model::ZoneHVACBaseboardConvectiveWater.new(model, model.alwaysOnDiscreteSchedule(), baseboard_coil) - baseboard_heater.addToThermalZone(zone) - options["hot_water_plant"].addDemandBranchForComponent(baseboard_coil) - elsif options["zoneHVAC"] == "Radiant" + baseboard_heater = OpenStudio::Model::ZoneHVACBaseboardConvectiveWater.new(model, model.alwaysOnDiscreteSchedule, baseboard_coil) + baseboard_heater.addToThermalZone(zone) + options['hot_water_plant'].addDemandBranchForComponent(baseboard_coil) + elsif options['zoneHVAC'] == 'Radiant' # create low temperature radiant object and add to thermal zone and radiant plant loops # create hot water coil and attach to radiant hot water loop - heating_coil = OpenStudio::Model::CoilHeatingLowTempRadiantVarFlow.new(model, options["mean_radiant_heating_setpoint_schedule"]) - options["radiant_hot_water_plant"].addDemandBranchForComponent(heating_coil) + heating_coil = OpenStudio::Model::CoilHeatingLowTempRadiantVarFlow.new(model, options['mean_radiant_heating_setpoint_schedule']) + options['radiant_hot_water_plant'].addDemandBranchForComponent(heating_coil) # create chilled water coil and attach to radiant chilled water loop - cooling_coil = OpenStudio::Model::CoilCoolingLowTempRadiantVarFlow.new(model, options["mean_radiant_cooling_setpoint_schedule"]) - options["radiant_chilled_water_plant"].addDemandBranchForComponent(cooling_coil) - low_temp_radiant = OpenStudio::Model::ZoneHVACLowTempRadiantVarFlow.new(model, - model.alwaysOnDiscreteSchedule(), + cooling_coil = OpenStudio::Model::CoilCoolingLowTempRadiantVarFlow.new(model, options['mean_radiant_cooling_setpoint_schedule']) + options['radiant_chilled_water_plant'].addDemandBranchForComponent(cooling_coil) + low_temp_radiant = OpenStudio::Model::ZoneHVACLowTempRadiantVarFlow.new(model, + model.alwaysOnDiscreteSchedule, heating_coil, cooling_coil) - low_temp_radiant.setRadiantSurfaceType("Floors") + low_temp_radiant.setRadiantSurfaceType('Floors') low_temp_radiant.setHydronicTubingInsideDiameter(0.012) - low_temp_radiant.setTemperatureControlType("MeanRadiantTemperature") + low_temp_radiant.setTemperatureControlType('MeanRadiantTemperature') low_temp_radiant.addToThermalZone(zone) # create radiant floor construction and substitute for existing floor (interior or exterior) constructions # create materials for radiant floor construction layers = [] # ignore layer below insulation, which will depend on boundary condition - layers << rigid_insulation_1in = OpenStudio::Model::StandardOpaqueMaterial.new(model,"Rough",0.0254,0.02,56.06,1210) - layers << concrete_2in = OpenStudio::Model::StandardOpaqueMaterial.new(model,"MediumRough",0.0508,2.31,2322,832) + layers << rigid_insulation_1in = OpenStudio::Model::StandardOpaqueMaterial.new(model, 'Rough', 0.0254, 0.02, 56.06, 1210) + layers << concrete_2in = OpenStudio::Model::StandardOpaqueMaterial.new(model, 'MediumRough', 0.0508, 2.31, 2322, 832) layers << concrete_2in # create radiant floor construction from materials radiant_floor = OpenStudio::Model::ConstructionWithInternalSource.new(layers) @@ -1473,72 +1451,66 @@ def OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options, parameters) # assign radiant construction to zone floor zone.spaces.each do |space| space.surfaces.each do |surface| - if surface.surfaceType == "Floor" + if surface.surfaceType == 'Floor' surface.setConstruction(radiant_floor) end end end - elsif options["zoneHVAC"] == "DualDuct" + elsif options['zoneHVAC'] == 'DualDuct' # create baseboard heater add add to thermal zone and hot water loop baseboard_coil = OpenStudio::Model::CoilHeatingWaterBaseboard.new(model) - baseboard_heater = OpenStudio::Model::ZoneHVACBaseboardConvectiveWater.new(model, model.alwaysOnDiscreteSchedule(), baseboard_coil) - baseboard_heater.addToThermalZone(zone) - options["hot_water_plant"].addDemandBranchForComponent(baseboard_coil) + baseboard_heater = OpenStudio::Model::ZoneHVACBaseboardConvectiveWater.new(model, model.alwaysOnDiscreteSchedule, baseboard_coil) + baseboard_heater.addToThermalZone(zone) + options['hot_water_plant'].addDemandBranchForComponent(baseboard_coil) # create fan coil (to mimic functionality of DOAS) # variable speed fan - fan = OpenStudio::Model::FanVariableVolume.new(model, model.alwaysOnDiscreteSchedule()) + fan = OpenStudio::Model::FanVariableVolume.new(model, model.alwaysOnDiscreteSchedule) fan.setFanEfficiency(0.69) - fan.setPressureRise(75) #Pa #ML This number is a guess; zone equipment pretending to be a DOAS - fan.autosizeMaximumFlowRate() + fan.setPressureRise(75) # Pa #ML This number is a guess; zone equipment pretending to be a DOAS + fan.autosizeMaximumFlowRate fan.setFanPowerMinimumFlowFraction(0.6) fan.setMotorEfficiency(0.9) fan.setMotorInAirstreamFraction(1.0) # create chilled water coil and attach to chilled water loop - cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule()) - options["chilled_water_plant"].addDemandBranchForComponent(cooling_coil) + cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule) + options['chilled_water_plant'].addDemandBranchForComponent(cooling_coil) cooling_coil.controllerWaterCoil.get.setMinimumActuatedFlow(0) # create hot water coil and attach to hot water loop - heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule()) - options["hot_water_plant"].addDemandBranchForComponent(heating_coil) + heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule) + options['hot_water_plant'].addDemandBranchForComponent(heating_coil) heating_coil.controllerWaterCoil.get.setMinimumActuatedFlow(0) # construct fan coil (DOAS) and attach to thermal zone fan_coil_doas = OpenStudio::Model::ZoneHVACFourPipeFanCoil.new(model, - options["ventilation_schedule"], + options['ventilation_schedule'], fan, cooling_coil, heating_coil) - fan_coil_doas.setCapacityControlMethod("VariableFanVariableFlow") + fan_coil_doas.setCapacityControlMethod('VariableFanVariableFlow') fan_coil_doas.addToThermalZone(zone) end end end + end # end of def - end # end of def - def OsLib_HVAC.addDCV(model, runner, options) - - unless options["primary_airloops"].nil? - options["primary_airloops"].each do |airloop| - if options["allHVAC"]["primary"]["fan"] == "Variable" - if airloop.airLoopHVACOutdoorAirSystem.is_initialized - controller_mv = airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.controllerMechanicalVentilation - controller_mv.setDemandControlledVentilation(true) - runner.registerInfo("Enabling demand control ventilation for #{airloop.name}") - end - end + def self.addDCV(model, runner, options) + options['primary_airloops']&.each do |airloop| + if options['allHVAC']['primary']['fan'] == 'Variable' + if airloop.airLoopHVACOutdoorAirSystem.is_initialized + controller_mv = airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.controllerMechanicalVentilation + controller_mv.setDemandControlledVentilation(true) + runner.registerInfo("Enabling demand control ventilation for #{airloop.name}") + end end end - - unless options["secondary_airloops"].nil? - options["secondary_airloops"].each do |airloop| - if options["allHVAC"]["secondary"]["fan"] == "Variable" - if airloop.airLoopHVACOutdoorAirSystem.is_initialized - controller_mv = airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.controllerMechanicalVentilation - controller_mv.setDemandControlledVentilation(true) - runner.registerInfo("Enabling demand control ventilation for #{airloop.name}") - end - end + + options['secondary_airloops']&.each do |airloop| + if options['allHVAC']['secondary']['fan'] == 'Variable' + if airloop.airLoopHVACOutdoorAirSystem.is_initialized + controller_mv = airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.controllerMechanicalVentilation + controller_mv.setDemandControlledVentilation(true) + runner.registerInfo("Enabling demand control ventilation for #{airloop.name}") + end end end end # end of def - -end \ No newline at end of file +end diff --git a/lib/measures/vr_fwith_doas/resources/OsLib_HelperMethods.rb b/lib/measures/vr_fwith_doas/resources/OsLib_HelperMethods.rb index b9d019b..9521c67 100644 --- a/lib/measures/vr_fwith_doas/resources/OsLib_HelperMethods.rb +++ b/lib/measures/vr_fwith_doas/resources/OsLib_HelperMethods.rb @@ -1,37 +1,35 @@ -module OsLib_HelperMethods +# frozen_string_literal: true +module OsLib_HelperMethods # populate choice argument from model objects - def OsLib_HelperMethods.populateChoiceArgFromModelObjects(model,modelObject_args_hash, includeBuilding = nil) - + def self.populateChoiceArgFromModelObjects(model, modelObject_args_hash, includeBuilding = nil) # populate choice argument for constructions that are applied to surfaces in the model modelObject_handles = OpenStudio::StringVector.new modelObject_display_names = OpenStudio::StringVector.new # looping through sorted hash of constructions - modelObject_args_hash.sort.map do |key,value| + modelObject_args_hash.sort.map do |key, value| modelObject_handles << value.handle.to_s modelObject_display_names << key end - if not includeBuilding == nil - #add building to string vector with space type + if !includeBuilding.nil? + # add building to string vector with space type building = model.getBuilding modelObject_handles << building.handle.to_s modelObject_display_names << includeBuilding end - result = {"modelObject_handles" => modelObject_handles, "modelObject_display_names" => modelObject_display_names} + result = { 'modelObject_handles' => modelObject_handles, 'modelObject_display_names' => modelObject_display_names } return result - - end #end of OsLib_HelperMethods.populateChoiceArgFromModelObjects + end # end of OsLib_HelperMethods.populateChoiceArgFromModelObjects # check choice argument made from model objects - def OsLib_HelperMethods.checkChoiceArgFromModelObjects(object, variableName,to_ObjectType, runner,user_arguments) - + def self.checkChoiceArgFromModelObjects(object, variableName, to_ObjectType, runner, user_arguments) apply_to_building = false modelObject = nil if object.empty? - handle = runner.getStringArgumentValue(variableName,user_arguments) + handle = runner.getStringArgumentValue(variableName, user_arguments) if handle.empty? runner.registerError("No #{variableName} was chosen.") # this logic makes this not work on an optional model object argument else @@ -39,27 +37,25 @@ def OsLib_HelperMethods.checkChoiceArgFromModelObjects(object, variableName,to_O end return false else - if not eval("object.get.#{to_ObjectType}").empty? + if !eval("object.get.#{to_ObjectType}").empty? modelObject = eval("object.get.#{to_ObjectType}").get - elsif not object.get.to_Building.empty? + elsif !object.get.to_Building.empty? apply_to_building = true else runner.registerError("Script Error - argument not showing up as #{variableName}.") return false end - end #end of if construction.empty? - - result = {"modelObject" => modelObject, "apply_to_building" => apply_to_building} + end # end of if construction.empty? - end #end of OsLib_HelperMethods.checkChoiceArgFromModelObjects + result = { 'modelObject' => modelObject, 'apply_to_building' => apply_to_building } + end # end of OsLib_HelperMethods.checkChoiceArgFromModelObjects # check choice argument made from model objects - def OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(object, variableName,to_ObjectType, runner, user_arguments) - + def self.checkOptionalChoiceArgFromModelObjects(object, variableName, to_ObjectType, runner, user_arguments) apply_to_building = false modelObject = nil if object.empty? - handle = runner.getOptionalStringArgumentValue(variableName,user_arguments) + handle = runner.getOptionalStringArgumentValue(variableName, user_arguments) if handle.empty? # do nothing, this is a valid option modelObject = nil @@ -69,34 +65,32 @@ def OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(object, variableN return false end else - if not eval("object.get.#{to_ObjectType}").empty? + if !eval("object.get.#{to_ObjectType}").empty? modelObject = eval("object.get.#{to_ObjectType}").get - elsif not object.get.to_Building.empty? + elsif !object.get.to_Building.empty? apply_to_building = true else runner.registerError("Script Error - argument not showing up as #{variableName}.") return false end - end #end of if construction.empty? - - result = {"modelObject" => modelObject, "apply_to_building" => apply_to_building} + end # end of if construction.empty? - end #end of OsLib_HelperMethods.checkChoiceArgFromModelObjects + result = { 'modelObject' => modelObject, 'apply_to_building' => apply_to_building } + end # end of OsLib_HelperMethods.checkChoiceArgFromModelObjects # check value of double arguments - def OsLib_HelperMethods.checkDoubleArguments(runner, min, max, argumentHash) - - #error flag + def self.checkDoubleArguments(runner, min, max, argumentHash) + # error flag error = false argumentHash.each do |display, argument| - if not min == nil + if !min.nil? if argument < min runner.registerError("Please enter value between #{min} and #{max} for #{display}.") # add in argument display name error = true end end - if not max == nil + if !max.nil? if argument > max runner.registerError("Please enter value between #{min} and #{max} for #{display}.") # add in argument display name error = true @@ -110,13 +104,11 @@ def OsLib_HelperMethods.checkDoubleArguments(runner, min, max, argumentHash) else return true end - - end #end of OsLib_HelperMethods.checkDoubleArguments + end # end of OsLib_HelperMethods.checkDoubleArguments # OpenStudio has built in toNeatString method # OpenStudio::toNeatString(double,2,true)# double,decimals, show commas # OpenStudio has built in helper for unit conversion. That can be done using OpenStudio::convert() as shown below. # OpenStudio::convert(double,"from unit string","to unit string").get - -end \ No newline at end of file +end diff --git a/lib/measures/vr_fwith_doas/resources/OsLib_LightingAndEquipment.rb b/lib/measures/vr_fwith_doas/resources/OsLib_LightingAndEquipment.rb index bc53960..535391e 100644 --- a/lib/measures/vr_fwith_doas/resources/OsLib_LightingAndEquipment.rb +++ b/lib/measures/vr_fwith_doas/resources/OsLib_LightingAndEquipment.rb @@ -1,13 +1,13 @@ +# frozen_string_literal: true + require "#{File.dirname(__FILE__)}/OsLib_Schedules" -#load OpenStudio measure libraries +# load OpenStudio measure libraries module OsLib_LightingAndEquipment - include OsLib_Schedules # return min ans max from array - def OsLib_LightingAndEquipment.getExteriorLightsValue(model) - + def self.getExteriorLightsValue(model) facility = model.getFacility starting_exterior_lights_power = 0 starting_exterior_lights = facility.exteriorLights @@ -18,13 +18,12 @@ def OsLib_LightingAndEquipment.getExteriorLightsValue(model) starting_exterior_lights_power += starting_exterior_light_base_power * starting_exterior_light_multiplier end - result = {"exteriorLightingPower" => starting_exterior_lights_power, "exteriorLights" => starting_exterior_lights} + result = { 'exteriorLightingPower' => starting_exterior_lights_power, 'exteriorLights' => starting_exterior_lights } return result - - end #end of OsLib_LightingAndEquipment.getExteriorLightsValue + end # end of OsLib_LightingAndEquipment.getExteriorLightsValue # return min ans max from array - def OsLib_LightingAndEquipment.removeAllExteriorLights(model,runner) + def self.removeAllExteriorLights(model, runner) facility = model.getFacility lightsRemoved = false starting_exterior_lights = facility.exteriorLights @@ -36,69 +35,65 @@ def OsLib_LightingAndEquipment.removeAllExteriorLights(model,runner) result = lightsRemoved return result - - end #end of OsLib_LightingAndEquipment.removeAllExteriorLights + end # end of OsLib_LightingAndEquipment.removeAllExteriorLights # return min ans max from array - def OsLib_LightingAndEquipment.addExteriorLights(model,runner, options = {}) - + def self.addExteriorLights(model, runner, options = {}) # set defaults to use if user inputs not passed in defaults = { - "name" => "Exterior Light", - "power" => 0, - "subCategory" => "Exterior Lighting", - "controlOption" => "AstronomicalClock", - "setbackStartTime" => 0, - "setbackEndTime" => 0, - "setbackFraction" => 0.25, + 'name' => 'Exterior Light', + 'power' => 0, + 'subCategory' => 'Exterior Lighting', + 'controlOption' => 'AstronomicalClock', + 'setbackStartTime' => 0, + 'setbackEndTime' => 0, + 'setbackFraction' => 0.25 } # merge user inputs with defaults options = defaults.merge(options) ext_lights_def = OpenStudio::Model::ExteriorLightsDefinition.new(model) - ext_lights_def.setName("#{options["name"]} Definition") - runner.registerInfo("Setting #{ext_lights_def.name} to a design power of #{options["power"]} Watts") - ext_lights_def.setDesignLevel(options["power"]) + ext_lights_def.setName("#{options['name']} Definition") + runner.registerInfo("Setting #{ext_lights_def.name} to a design power of #{options['power']} Watts") + ext_lights_def.setDesignLevel(options['power']) - #creating schedule type limits for the exterior lights schedule + # creating schedule type limits for the exterior lights schedule ext_lights_sch_type_limits = OpenStudio::Model::ScheduleTypeLimits.new(model) - ext_lights_sch_type_limits.setName("#{options["name"]} Fractional") + ext_lights_sch_type_limits.setName("#{options['name']} Fractional") ext_lights_sch_type_limits.setLowerLimitValue(0) ext_lights_sch_type_limits.setUpperLimitValue(1) - ext_lights_sch_type_limits.setNumericType("Continuous") + ext_lights_sch_type_limits.setNumericType('Continuous') # prepare values for profile - if options["setbackStartTime"] == 24 - profile = {options["setbackEndTime"] => options["setbackFraction"],24.0 => 1.0} - elsif options["setbackStartTime"] == 0 - profile = {options["setbackEndTime"] => options["setbackFraction"],24.0 => 1.0} - elsif options["setbackStartTime"] > options["setbackEndTime"] - profile = {options["setbackEndTime"] => options["setbackFraction"],options["setbackStartTime"] => 1.0,24.0 => options["setbackFraction"]} + if options['setbackStartTime'] == 24 + profile = { options['setbackEndTime'] => options['setbackFraction'], 24.0 => 1.0 } + elsif options['setbackStartTime'] == 0 + profile = { options['setbackEndTime'] => options['setbackFraction'], 24.0 => 1.0 } + elsif options['setbackStartTime'] > options['setbackEndTime'] + profile = { options['setbackEndTime'] => options['setbackFraction'], options['setbackStartTime'] => 1.0, 24.0 => options['setbackFraction'] } else - profile = {options["setbackStartTime"] => 1.0,options["setbackEndTime"] => options["setbackFraction"]} + profile = { options['setbackStartTime'] => 1.0, options['setbackEndTime'] => options['setbackFraction'] } end # inputs createSimpleSchedule_inputs = { - "name" => options["name"], - "winterTimeValuePairs" => profile, - "summerTimeValuePairs" => profile, - "defaultTimeValuePairs" => profile, + 'name' => options['name'], + 'winterTimeValuePairs' => profile, + 'summerTimeValuePairs' => profile, + 'defaultTimeValuePairs' => profile } # create a ruleset schedule with a basic profile ext_lights_sch = OsLib_Schedules.createSimpleSchedule(model, createSimpleSchedule_inputs) - #creating exterior lights object - ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def,ext_lights_sch) - ext_lights.setName("#{options["power"]} w Exterior Light") - ext_lights.setControlOption(options["controlOption"]) - ext_lights.setEndUseSubcategory(options["subCategory"]) + # creating exterior lights object + ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def, ext_lights_sch) + ext_lights.setName("#{options['power']} w Exterior Light") + ext_lights.setControlOption(options['controlOption']) + ext_lights.setEndUseSubcategory(options['subCategory']) result = ext_lights return result - - end #end of OsLib_LightingAndEquipment.addExteriorLights - -end \ No newline at end of file + end # end of OsLib_LightingAndEquipment.addExteriorLights +end diff --git a/lib/measures/vr_fwith_doas/resources/OsLib_Schedules.rb b/lib/measures/vr_fwith_doas/resources/OsLib_Schedules.rb index bc46d3d..8f44c78 100644 --- a/lib/measures/vr_fwith_doas/resources/OsLib_Schedules.rb +++ b/lib/measures/vr_fwith_doas/resources/OsLib_Schedules.rb @@ -1,149 +1,142 @@ -module OsLib_Schedules +# frozen_string_literal: true +module OsLib_Schedules # create a ruleset schedule with a basic profile - def OsLib_Schedules.createSimpleSchedule(model, options = {}) - + def self.createSimpleSchedule(model, options = {}) defaults = { - "name" => nil, - "winterTimeValuePairs" => {24.0 => 0.0}, - "summerTimeValuePairs" => {24.0 => 1.0}, - "defaultTimeValuePairs" => {24.0 => 1.0}, + 'name' => nil, + 'winterTimeValuePairs' => { 24.0 => 0.0 }, + 'summerTimeValuePairs' => { 24.0 => 1.0 }, + 'defaultTimeValuePairs' => { 24.0 => 1.0 } } - # merge user inputs with defaults options = defaults.merge(options) - #ScheduleRuleset + # ScheduleRuleset sch_ruleset = OpenStudio::Model::ScheduleRuleset.new(model) if name - sch_ruleset.setName(options["name"]) + sch_ruleset.setName(options['name']) end - #Winter Design Day + # Winter Design Day winter_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setWinterDesignDaySchedule(winter_dsn_day) winter_dsn_day = sch_ruleset.winterDesignDaySchedule winter_dsn_day.setName("#{sch_ruleset.name} Winter Design Day") - options["winterTimeValuePairs"].each do |k,v| + options['winterTimeValuePairs'].each do |k, v| hour = k.truncate - min = ((k - hour)*60).to_i - winter_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0),v) + min = ((k - hour) * 60).to_i + winter_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0), v) end - #Summer Design Day + # Summer Design Day summer_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setSummerDesignDaySchedule(summer_dsn_day) summer_dsn_day = sch_ruleset.summerDesignDaySchedule summer_dsn_day.setName("#{sch_ruleset.name} Summer Design Day") - options["summerTimeValuePairs"].each do |k,v| + options['summerTimeValuePairs'].each do |k, v| hour = k.truncate - min = ((k - hour)*60).to_i - summer_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0),v) + min = ((k - hour) * 60).to_i + summer_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0), v) end - #All Days + # All Days week_day = sch_ruleset.defaultDaySchedule week_day.setName("#{sch_ruleset.name} Schedule Week Day") - options["defaultTimeValuePairs"].each do |k,v| + options['defaultTimeValuePairs'].each do |k, v| hour = k.truncate - min = ((k - hour)*60).to_i - week_day.addValue(OpenStudio::Time.new(0, hour, min, 0),v) + min = ((k - hour) * 60).to_i + week_day.addValue(OpenStudio::Time.new(0, hour, min, 0), v) end result = sch_ruleset return result + end # end of OsLib_Schedules.createSimpleSchedule - end #end of OsLib_Schedules.createSimpleSchedule - # create a complex ruleset schedule - def OsLib_Schedules.createComplexSchedule(model, options = {}) - + def self.createComplexSchedule(model, options = {}) defaults = { - "name" => nil, - "default_day" => ["always_on",[24.0,1.0]] + 'name' => nil, + 'default_day' => ['always_on', [24.0, 1.0]] } # merge user inputs with defaults options = defaults.merge(options) - #ScheduleRuleset + # ScheduleRuleset sch_ruleset = OpenStudio::Model::ScheduleRuleset.new(model) if name - sch_ruleset.setName(options["name"]) + sch_ruleset.setName(options['name']) end - #Winter Design Day - unless options["winter_design_day"].nil? + # Winter Design Day + unless options['winter_design_day'].nil? winter_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setWinterDesignDaySchedule(winter_dsn_day) winter_dsn_day = sch_ruleset.winterDesignDaySchedule winter_dsn_day.setName("#{sch_ruleset.name} Winter Design Day") - options["winter_design_day"].each do |data_pair| + options['winter_design_day'].each do |data_pair| hour = data_pair[0].truncate - min = ((data_pair[0] - hour)*60).to_i - winter_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0),data_pair[1]) + min = ((data_pair[0] - hour) * 60).to_i + winter_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0), data_pair[1]) end - end + end - #Summer Design Day - unless options["summer_design_day"].nil? + # Summer Design Day + unless options['summer_design_day'].nil? summer_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setSummerDesignDaySchedule(summer_dsn_day) summer_dsn_day = sch_ruleset.summerDesignDaySchedule summer_dsn_day.setName("#{sch_ruleset.name} Summer Design Day") - options["summer_design_day"].each do |data_pair| + options['summer_design_day'].each do |data_pair| hour = data_pair[0].truncate - min = ((data_pair[0] - hour)*60).to_i - summer_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0),data_pair[1]) + min = ((data_pair[0] - hour) * 60).to_i + summer_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0), data_pair[1]) end - end - - #Default Day + end + + # Default Day default_day = sch_ruleset.defaultDaySchedule - default_day.setName("#{sch_ruleset.name} #{options["default_day"][0]}") - default_data_array = options["default_day"] + default_day.setName("#{sch_ruleset.name} #{options['default_day'][0]}") + default_data_array = options['default_day'] default_data_array.delete_at(0) default_data_array.each do |data_pair| hour = data_pair[0].truncate - min = ((data_pair[0] - hour)*60).to_i - default_day.addValue(OpenStudio::Time.new(0, hour, min, 0),data_pair[1]) + min = ((data_pair[0] - hour) * 60).to_i + default_day.addValue(OpenStudio::Time.new(0, hour, min, 0), data_pair[1]) + end + + # Rules + options['rules']&.each do |data_array| + rule = OpenStudio::Model::ScheduleRule.new(sch_ruleset) + rule.setName("#{sch_ruleset.name} #{data_array[0]} Rule") + date_range = data_array[1].split('-') + start_date = date_range[0].split('/') + end_date = date_range[1].split('/') + rule.setStartDate(model.getYearDescription.makeDate(start_date[0].to_i, start_date[1].to_i)) + rule.setEndDate(model.getYearDescription.makeDate(end_date[0].to_i, end_date[1].to_i)) + days = data_array[2].split('/') + rule.setApplySunday(true) if days.include? 'Sun' + rule.setApplyMonday(true) if days.include? 'Mon' + rule.setApplyTuesday(true) if days.include? 'Tue' + rule.setApplyWednesday(true) if days.include? 'Wed' + rule.setApplyThursday(true) if days.include? 'Thu' + rule.setApplyFriday(true) if days.include? 'Fri' + rule.setApplySaturday(true) if days.include? 'Sat' + day_schedule = rule.daySchedule + day_schedule.setName("#{sch_ruleset.name} #{data_array[0]}") + data_array.delete_at(0) + data_array.delete_at(0) + data_array.delete_at(0) + data_array.each do |data_pair| + hour = data_pair[0].truncate + min = ((data_pair[0] - hour) * 60).to_i + day_schedule.addValue(OpenStudio::Time.new(0, hour, min, 0), data_pair[1]) + end end - - #Rules - unless options["rules"].nil? - options["rules"].each do |data_array| - rule = OpenStudio::Model::ScheduleRule.new(sch_ruleset) - rule.setName("#{sch_ruleset.name} #{data_array[0]} Rule") - date_range = data_array[1].split("-") - start_date = date_range[0].split("/") - end_date = date_range[1].split("/") - rule.setStartDate(model.getYearDescription.makeDate(start_date[0].to_i,start_date[1].to_i)) - rule.setEndDate(model.getYearDescription.makeDate(end_date[0].to_i,end_date[1].to_i)) - days = data_array[2].split("/") - rule.setApplySunday(true) if days.include? "Sun" - rule.setApplyMonday(true) if days.include? "Mon" - rule.setApplyTuesday(true) if days.include? "Tue" - rule.setApplyWednesday(true) if days.include? "Wed" - rule.setApplyThursday(true) if days.include? "Thu" - rule.setApplyFriday(true) if days.include? "Fri" - rule.setApplySaturday(true) if days.include? "Sat" - day_schedule = rule.daySchedule - day_schedule.setName("#{sch_ruleset.name} #{data_array[0]}") - data_array.delete_at(0) - data_array.delete_at(0) - data_array.delete_at(0) - data_array.each do |data_pair| - hour = data_pair[0].truncate - min = ((data_pair[0] - hour)*60).to_i - day_schedule.addValue(OpenStudio::Time.new(0, hour, min, 0),data_pair[1]) - end - end - end result = sch_ruleset return result - - end #end of OsLib_Schedules.createComplexSchedule - -end \ No newline at end of file + end # end of OsLib_Schedules.createComplexSchedule +end diff --git a/lib/measures/vr_fwith_doas/tests/AedgOfficeHvacWshpDoas_Test.rb b/lib/measures/vr_fwith_doas/tests/AedgOfficeHvacWshpDoas_Test.rb index 8a79cbd..6ea4c5a 100644 --- a/lib/measures/vr_fwith_doas/tests/AedgOfficeHvacWshpDoas_Test.rb +++ b/lib/measures/vr_fwith_doas/tests/AedgOfficeHvacWshpDoas_Test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'openstudio' require 'openstudio/ruleset/ShowRunnerOutput' @@ -7,56 +9,51 @@ require 'test/unit' class AedgOfficeHvacWshpDoas_Test < Test::Unit::TestCase - - def test_AedgOfficeHvacWshpDoas - # create an instance of the measure measure = AedgOfficeHvacWshpDoas.new - + # create an instance of a runner runner = OpenStudio::Ruleset::OSRunner.new # load the test model translator = OpenStudio::OSVersion::VersionTranslator.new - path = OpenStudio::Path.new(File.dirname(__FILE__) + "/AEDG_HVAC_GenericTestModel_0225_a.osm") + path = OpenStudio::Path.new(File.dirname(__FILE__) + '/AEDG_HVAC_GenericTestModel_0225_a.osm') model = translator.loadModel(path) - assert((not model.empty?)) + assert(!model.empty?) model = model.get - + # get arguments and test that they are what we are expecting arguments = measure.arguments(model) assert_equal(3, arguments.size) - assert_equal("ceilingReturnPlenumSpaceType", arguments[0].name) - assert_equal("costTotalHVACSystem", arguments[1].name) - assert_equal("remake_schedules", arguments[2].name) - + assert_equal('ceilingReturnPlenumSpaceType', arguments[0].name) + assert_equal('costTotalHVACSystem', arguments[1].name) + assert_equal('remake_schedules', arguments[2].name) + # set argument values to good values and run the measure on model with spaces argument_map = OpenStudio::Ruleset::OSArgumentMap.new ceilingReturnPlenumSpaceType = arguments[0].clone - assert(ceilingReturnPlenumSpaceType.setValue("Plenum")) - argument_map["ceilingReturnPlenumSpaceType"] = ceilingReturnPlenumSpaceType + assert(ceilingReturnPlenumSpaceType.setValue('Plenum')) + argument_map['ceilingReturnPlenumSpaceType'] = ceilingReturnPlenumSpaceType costTotalHVACSystem = arguments[1].clone assert(costTotalHVACSystem.setValue(15000.0)) - argument_map["costTotalHVACSystem"] = costTotalHVACSystem + argument_map['costTotalHVACSystem'] = costTotalHVACSystem remake_schedules = arguments[2].clone assert(remake_schedules.setValue(true)) - argument_map["remake_schedules"] = remake_schedules - + argument_map['remake_schedules'] = remake_schedules + measure.run(model, runner, argument_map) result = runner.result show_output(result) - assert(result.value.valueName == "Success") - #assert(result.warnings.size == 1) - #assert(result.info.size == 2) - - #save the model for testing purposes - output_file_path = OpenStudio::Path.new(File.dirname(__FILE__) + "/test.osm") - model.save(output_file_path,true) - - end - + assert(result.value.valueName == 'Success') + # assert(result.warnings.size == 1) + # assert(result.info.size == 2) + + # save the model for testing purposes + output_file_path = OpenStudio::Path.new(File.dirname(__FILE__) + '/test.osm') + model.save(output_file_path, true) + end end diff --git a/lib/measures/vr_fwith_doas/tests/measure-backup-1.rb b/lib/measures/vr_fwith_doas/tests/measure-backup-1.rb index a32a571..7664027 100644 --- a/lib/measures/vr_fwith_doas/tests/measure-backup-1.rb +++ b/lib/measures/vr_fwith_doas/tests/measure-backup-1.rb @@ -1,28 +1,29 @@ -#see the URL below for information on how to write OpenStudio measures +# frozen_string_literal: true + +# see the URL below for information on how to write OpenStudio measures # http://openstudio.nrel.gov/openstudio-measure-writing-guide -#see the URL below for information on using life cycle cost objects in OpenStudio +# see the URL below for information on using life cycle cost objects in OpenStudio # http://openstudio.nrel.gov/openstudio-life-cycle-examples -#see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) +# see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) # http://openstudio.nrel.gov/sites/openstudio.nrel.gov/files/nv_data/cpp_documentation_it/model/html/namespaces.html -#load OpenStudio measure libraries +# load OpenStudio measure libraries require "#{File.dirname(__FILE__)}/resources/OsLib_AedgMeasures" require "#{File.dirname(__FILE__)}/resources/OsLib_HelperMethods" require "#{File.dirname(__FILE__)}/resources/OsLib_HVAC" require "#{File.dirname(__FILE__)}/resources/OsLib_Schedules" -#start the measure +# start the measure class WSHPwithDOASMoreDesignParameters < OpenStudio::Ruleset::ModelUserScript - - #define the name that a user will see, this method may be deprecated as - #the display name in PAT comes from the name field in measure.xml + # define the name that a user will see, this method may be deprecated as + # the display name in PAT comes from the name field in measure.xml def name - return "WSHPwithDOASMoreDesignParameters" + return 'WSHPwithDOASMoreDesignParameters' end - #define the arguments that the user will input + # define the arguments that the user will input def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new @@ -30,403 +31,400 @@ def arguments(model) spaceTypes = model.getSpaceTypes usedSpaceTypes_handle = OpenStudio::StringVector.new usedSpaceTypes_displayName = OpenStudio::StringVector.new - spaceTypes.each do |spaceType| #todo - I need to update this to use helper so GUI sorts by display name - if spaceType.spaces.size > 0 # only show space types used in the building + spaceTypes.each do |spaceType| # TODO: - I need to update this to use helper so GUI sorts by display name + if !spaceType.spaces.empty? # only show space types used in the building usedSpaceTypes_handle << spaceType.handle.to_s usedSpaceTypes_displayName << spaceType.name.to_s end end - + # make an argument for space type - ceilingReturnPlenumSpaceType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("ceilingReturnPlenumSpaceType", usedSpaceTypes_handle, usedSpaceTypes_displayName,false) - ceilingReturnPlenumSpaceType.setDisplayName("This space type should be part of a ceiling return air plenum.") - #ceilingReturnPlenumSpaceType.setDefaultValue("We don't want a default, this is an optional argument") + ceilingReturnPlenumSpaceType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('ceilingReturnPlenumSpaceType', usedSpaceTypes_handle, usedSpaceTypes_displayName, false) + ceilingReturnPlenumSpaceType.setDisplayName('This space type should be part of a ceiling return air plenum.') + # ceilingReturnPlenumSpaceType.setDefaultValue("We don't want a default, this is an optional argument") args << ceilingReturnPlenumSpaceType - - # Heating COP of WSHP - wshpHeatingCOP = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("wshpHeatingCOP",false) - wshpHeatingCOP.setDisplayName("WSHP AHRI Heating COP") - wshpHeatingCOP.setDefaultValue(4.0) - args << wshpHeatingCOP - - # Cooling EER of WSHP - wshpCoolingEER = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("wshpCoolingEER",false) - wshpCoolingEER.setDisplayName("WSHP AHRI Cooling EER") - wshpCoolingEER.setDefaultValue(14) - args << wshpCoolingEER - - # WSHP Fan Type PSC or ECM - fanChs = OpenStudio::StringVector.new - fanChs << "PSC" - fanChs << "ECM" - wshpFanType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("wshpFanType",fanChs,true) # note ECM fan type may correspond to different set of heat pump performance curves - wshpFanType.setDisplayName("WSHP Fan Type: PSC or ECM?") - wshpFanType.setDefaultValue("PSC") + + # Heating COP of WSHP + wshpHeatingCOP = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('wshpHeatingCOP', false) + wshpHeatingCOP.setDisplayName('WSHP AHRI Heating COP') + wshpHeatingCOP.setDefaultValue(4.0) + args << wshpHeatingCOP + + # Cooling EER of WSHP + wshpCoolingEER = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('wshpCoolingEER', false) + wshpCoolingEER.setDisplayName('WSHP AHRI Cooling EER') + wshpCoolingEER.setDefaultValue(14) + args << wshpCoolingEER + + # WSHP Fan Type PSC or ECM + fanChs = OpenStudio::StringVector.new + fanChs << 'PSC' + fanChs << 'ECM' + wshpFanType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('wshpFanType', fanChs, true) # note ECM fan type may correspond to different set of heat pump performance curves + wshpFanType.setDisplayName('WSHP Fan Type: PSC or ECM?') + wshpFanType.setDefaultValue('PSC') args << wshpFanType - - # Condenser Loop Cooling Temperature - condLoopCoolingTemp = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("condLoopCoolingTemp",false) - condLoopCoolingTemp.setDisplayName("Condenser Loop Cooling Temperature (F)") - condLoopCoolingTemp.setDefaultValue(90) - args << condLoopCoolingTemp - - # Condenser Loop Heating Temperature - condLoopHeatingTemp = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("condLoopHeatingTemp",false) - condLoopHeatingTemp.setDisplayName("Condenser Loop Heating Temperature (F)") - condLoopHeatingTemp.setDefaultValue(60) - args << condLoopHeatingTemp - - # Cooling Tower - coolingTowerWB = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("coolingTowerWB",false) - coolingTowerWB.setDisplayName("Cooling Tower Design Wet Bulb (F)") - coolingTowerWB.setDefaultValue(68) - args << coolingTowerWB - - coolingTowerApproach = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("coolingTowerApproach",false) - coolingTowerApproach.setDisplayName("Cooling Tower Design Approach (F)") - coolingTowerApproach.setDefaultValue(7.0) - args << coolingTowerApproach - - coolingTowerDeltaT = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("coolingTowerDeltaT",false) - coolingTowerDeltaT.setDisplayName("Cooling Tower Design Delta T (F)") - coolingTowerDeltaT.setDefaultValue(10.0) - args << coolingTowerDeltaT - - # Boiler Efficiency - boilerEff = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("boilerEff",false) - boilerEff.setDisplayName("Boiler Thermal Efficiency") - boilerEff.setDefaultValue(0.9) - args << boilerEff - + + # Condenser Loop Cooling Temperature + condLoopCoolingTemp = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('condLoopCoolingTemp', false) + condLoopCoolingTemp.setDisplayName('Condenser Loop Cooling Temperature (F)') + condLoopCoolingTemp.setDefaultValue(90) + args << condLoopCoolingTemp + + # Condenser Loop Heating Temperature + condLoopHeatingTemp = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('condLoopHeatingTemp', false) + condLoopHeatingTemp.setDisplayName('Condenser Loop Heating Temperature (F)') + condLoopHeatingTemp.setDefaultValue(60) + args << condLoopHeatingTemp + + # Cooling Tower + coolingTowerWB = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('coolingTowerWB', false) + coolingTowerWB.setDisplayName('Cooling Tower Design Wet Bulb (F)') + coolingTowerWB.setDefaultValue(68) + args << coolingTowerWB + + coolingTowerApproach = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('coolingTowerApproach', false) + coolingTowerApproach.setDisplayName('Cooling Tower Design Approach (F)') + coolingTowerApproach.setDefaultValue(7.0) + args << coolingTowerApproach + + coolingTowerDeltaT = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('coolingTowerDeltaT', false) + coolingTowerDeltaT.setDisplayName('Cooling Tower Design Delta T (F)') + coolingTowerDeltaT.setDefaultValue(10.0) + args << coolingTowerDeltaT + + # Boiler Efficiency + boilerEff = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('boilerEff', false) + boilerEff.setDisplayName('Boiler Thermal Efficiency') + boilerEff.setDefaultValue(0.9) + args << boilerEff + # Boiler fuel Type - fuelChs = OpenStudio::StringVector.new - fuelChs << "NaturalGas" - fuelChs << "PropaneGas" - fuelChs << "FuelOil#1" - fuelChs << "FuelOil#2" - fuelChs << "Electricity" - boilerFuelType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("boilerFuelType",fuelChs,false) - boilerFuelType.setDisplayName("Boiler Fuel Type") - boilerFuelType.setDefaultValue("NaturalGas") - args << boilerFuelType - - # boiler Hot water supply temperature - boilerHWST = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("boilerHWST",false) - boilerHWST.setDisplayName("Boiler Design Heating Water Outlet Temperature (F)") - boilerHWST.setDefaultValue(120) - args << boilerHWST - - # DOAS Fan Type - doasFanChs = OpenStudio::StringVector.new - doasFanChs << "Constant" - doasFanChs << "Variable" - doasFanType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doasFanType",doasFanChs,true) - doasFanType.setDisplayName("DOAS Fan Flow Control - Variable means DCV controls") - doasFanType.setDefaultValue("Variable") - args << doasFanType - - # DOAS Energy Recovery - ervChs = OpenStudio::StringVector.new - ervChs << "plate w/o economizer lockout" - ervChs << "plate w/ economizer lockout" - ervChs << "rotary wheel w/o economizer lockout" - ervChs << "rotary wheel w/ economizer lockout" - ervChs << "none" - doasERV = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doasERV",ervChs,true) - doasERV.setDisplayName("DOAS Energy Recovery?") - doasERV.setDefaultValue("none") - args << doasERV - - # DOAS Evaporative Cooling - evapChs = OpenStudio::StringVector.new - evapChs << "Direct Evaporative Cooler" - evapChs << "none" - doasEvap = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doasEvap",evapChs,true) - doasEvap.setDisplayName("DOAS Direct Evaporative Cooling?") - doasEvap.setDefaultValue("none") - args << doasEvap - - # DOAS DX Cooling - doasDXEER = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("doasDXEER",false) - doasDXEER.setDisplayName("DOAS DX Cooling EER") - doasDXEER.setDefaultValue(10.0) - args << doasDXEER - + fuelChs = OpenStudio::StringVector.new + fuelChs << 'NaturalGas' + fuelChs << 'PropaneGas' + fuelChs << 'FuelOil#1' + fuelChs << 'FuelOil#2' + fuelChs << 'Electricity' + boilerFuelType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('boilerFuelType', fuelChs, false) + boilerFuelType.setDisplayName('Boiler Fuel Type') + boilerFuelType.setDefaultValue('NaturalGas') + args << boilerFuelType + + # boiler Hot water supply temperature + boilerHWST = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('boilerHWST', false) + boilerHWST.setDisplayName('Boiler Design Heating Water Outlet Temperature (F)') + boilerHWST.setDefaultValue(120) + args << boilerHWST + + # DOAS Fan Type + doasFanChs = OpenStudio::StringVector.new + doasFanChs << 'Constant' + doasFanChs << 'Variable' + doasFanType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doasFanType', doasFanChs, true) + doasFanType.setDisplayName('DOAS Fan Flow Control - Variable means DCV controls') + doasFanType.setDefaultValue('Variable') + args << doasFanType + + # DOAS Energy Recovery + ervChs = OpenStudio::StringVector.new + ervChs << 'plate w/o economizer lockout' + ervChs << 'plate w/ economizer lockout' + ervChs << 'rotary wheel w/o economizer lockout' + ervChs << 'rotary wheel w/ economizer lockout' + ervChs << 'none' + doasERV = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doasERV', ervChs, true) + doasERV.setDisplayName('DOAS Energy Recovery?') + doasERV.setDefaultValue('none') + args << doasERV + + # DOAS Evaporative Cooling + evapChs = OpenStudio::StringVector.new + evapChs << 'Direct Evaporative Cooler' + evapChs << 'none' + doasEvap = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doasEvap', evapChs, true) + doasEvap.setDisplayName('DOAS Direct Evaporative Cooling?') + doasEvap.setDefaultValue('none') + args << doasEvap + + # DOAS DX Cooling + doasDXEER = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('doasDXEER', false) + doasDXEER.setDisplayName('DOAS DX Cooling EER') + doasDXEER.setDefaultValue(10.0) + args << doasDXEER + # make an argument for material and installation cost # todo - I would like to split the costing out to the air loops weighted by area of building served vs. just sticking it on the building - costTotalHVACSystem = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("costTotalHVACSystem",true) - costTotalHVACSystem.setDisplayName("Total Cost for HVAC System ($).") + costTotalHVACSystem = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('costTotalHVACSystem', true) + costTotalHVACSystem.setDisplayName('Total Cost for HVAC System ($).') costTotalHVACSystem.setDefaultValue(0.0) args << costTotalHVACSystem - - #make an argument to remove existing costs - remake_schedules = OpenStudio::Ruleset::OSArgument::makeBoolArgument("remake_schedules",true) - remake_schedules.setDisplayName("Apply recommended availability and ventilation schedules for air handlers?") + + # make an argument to remove existing costs + remake_schedules = OpenStudio::Ruleset::OSArgument.makeBoolArgument('remake_schedules', true) + remake_schedules.setDisplayName('Apply recommended availability and ventilation schedules for air handlers?') remake_schedules.setDefaultValue(true) args << remake_schedules return args - end #end the arguments method + end # end the arguments method - #define what happens when the measure is run + # define what happens when the measure is run def run(model, runner, user_arguments) super(model, runner, user_arguments) - #use the built-in error checking - if not runner.validateUserArguments(arguments(model), user_arguments) + # use the built-in error checking + if !runner.validateUserArguments(arguments(model), user_arguments) return false end ### START INPUTS - #assign the user inputs to variables - ceilingReturnPlenumSpaceType = runner.getOptionalWorkspaceObjectChoiceValue("ceilingReturnPlenumSpaceType",user_arguments,model) - costTotalHVACSystem = runner.getDoubleArgumentValue("costTotalHVACSystem",user_arguments) - remake_schedules = runner.getBoolArgumentValue("remake_schedules",user_arguments) - + # assign the user inputs to variables + ceilingReturnPlenumSpaceType = runner.getOptionalWorkspaceObjectChoiceValue('ceilingReturnPlenumSpaceType', user_arguments, model) + costTotalHVACSystem = runner.getDoubleArgumentValue('costTotalHVACSystem', user_arguments) + remake_schedules = runner.getBoolArgumentValue('remake_schedules', user_arguments) + # check that spaceType was chosen and exists in model - ceilingReturnPlenumSpaceTypeCheck = OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(ceilingReturnPlenumSpaceType, "ceilingReturnPlenumSpaceType","to_SpaceType", runner, user_arguments) - if ceilingReturnPlenumSpaceTypeCheck == false then return false else ceilingReturnPlenumSpaceType = ceilingReturnPlenumSpaceTypeCheck["modelObject"] end + ceilingReturnPlenumSpaceTypeCheck = OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(ceilingReturnPlenumSpaceType, 'ceilingReturnPlenumSpaceType', 'to_SpaceType', runner, user_arguments) + ceilingReturnPlenumSpaceTypeCheck == false ? (return false) : (ceilingReturnPlenumSpaceType = ceilingReturnPlenumSpaceTypeCheck['modelObject']) # default building/ secondary space types - standardBuildingTypeTest = ["Office"] #ML Not used yet + standardBuildingTypeTest = ['Office'] # ML Not used yet secondarySpaceTypeTest = [] # empty for office - primarySpaceType = "Office" - primaryHVAC = {"doas" => true, "fan" => "Variable", "heat" => "Gas", "cool" => "SingleDX"} #xf notes: need to change - secondaryHVAC = {"fan" => "None", "heat" => "None", "cool" => "None"} #ML not used for office; leave or empty? - zoneHVAC = "WSHP" - chillerType = "None" #set to none if chiller not used - radiantChillerType = "None" #set to none if not radiant system - allHVAC = {"primary" => primaryHVAC,"secondary" => secondaryHVAC,"zone" => zoneHVAC} - - wshpHeatingCOP = runner.getDoubleArgumentValue("wshpHeatingCOP",user_arguments) - wshpCoolingEER = runner.getDoubleArgumentValue("wshpCoolingEER",user_arguments) - wshpFanType = runner.getStringArgumentValue("wshpFanType",user_arguments) - condLoopCoolingTemp = runner.getDoubleArgumentValue("condLoopCoolingTemp",user_arguments) - condLoopHeatingTemp = runner.getDoubleArgumentValue("condLoopHeatingTemp",user_arguments) - coolingTowerWB = runner.getDoubleArgumentValue("coolingTowerWB",user_arguments) - coolingTowerApproach= runner.getDoubleArgumentValue("coolingTowerApproach",user_arguments) - coolingTowerDeltaT= runner.getDoubleArgumentValue("coolingTowerDeltaT",user_arguments) - boilerEff= runner.getDoubleArgumentValue("boilerEff",user_arguments) - boilerFuelType = runner.getStringArgumentValue("boilerFuelType",user_arguments) - boilerHWST= runner.getDoubleArgumentValue("boilerHWST",user_arguments) - doasFanType = runner.getStringArgumentValue("doasFanType",user_arguments) - doasERV = runner.getStringArgumentValue("doasERV",user_arguments) - doasEvap = runner.getStringArgumentValue("doasEvap",user_arguments) - doasDXEER= runner.getDoubleArgumentValue("doasDXEER",user_arguments) - + primarySpaceType = 'Office' + primaryHVAC = { 'doas' => true, 'fan' => 'Variable', 'heat' => 'Gas', 'cool' => 'SingleDX' } # xf notes: need to change + secondaryHVAC = { 'fan' => 'None', 'heat' => 'None', 'cool' => 'None' } # ML not used for office; leave or empty? + zoneHVAC = 'WSHP' + chillerType = 'None' # set to none if chiller not used + radiantChillerType = 'None' # set to none if not radiant system + allHVAC = { 'primary' => primaryHVAC, 'secondary' => secondaryHVAC, 'zone' => zoneHVAC } + + wshpHeatingCOP = runner.getDoubleArgumentValue('wshpHeatingCOP', user_arguments) + wshpCoolingEER = runner.getDoubleArgumentValue('wshpCoolingEER', user_arguments) + wshpFanType = runner.getStringArgumentValue('wshpFanType', user_arguments) + condLoopCoolingTemp = runner.getDoubleArgumentValue('condLoopCoolingTemp', user_arguments) + condLoopHeatingTemp = runner.getDoubleArgumentValue('condLoopHeatingTemp', user_arguments) + coolingTowerWB = runner.getDoubleArgumentValue('coolingTowerWB', user_arguments) + coolingTowerApproach = runner.getDoubleArgumentValue('coolingTowerApproach', user_arguments) + coolingTowerDeltaT = runner.getDoubleArgumentValue('coolingTowerDeltaT', user_arguments) + boilerEff = runner.getDoubleArgumentValue('boilerEff', user_arguments) + boilerFuelType = runner.getStringArgumentValue('boilerFuelType', user_arguments) + boilerHWST = runner.getDoubleArgumentValue('boilerHWST', user_arguments) + doasFanType = runner.getStringArgumentValue('doasFanType', user_arguments) + doasERV = runner.getStringArgumentValue('doasERV', user_arguments) + doasEvap = runner.getStringArgumentValue('doasEvap', user_arguments) + doasDXEER = runner.getDoubleArgumentValue('doasDXEER', user_arguments) + ### END INPUTS - ### START SORT ZONES - options = {"standardBuildingTypeTest" => standardBuildingTypeTest, #ML Not used yet - "secondarySpaceTypeTest" => secondarySpaceTypeTest, - "ceilingReturnPlenumSpaceType" => ceilingReturnPlenumSpaceType} + options = { 'standardBuildingTypeTest' => standardBuildingTypeTest, # ML Not used yet + 'secondarySpaceTypeTest' => secondarySpaceTypeTest, + 'ceilingReturnPlenumSpaceType' => ceilingReturnPlenumSpaceType } zonesSorted = OsLib_HVAC.sortZones(model, runner, options) - zonesPrimary = zonesSorted["zonesPrimary"] - zonesSecondary = zonesSorted["zonesSecondary"] - zonesPlenum = zonesSorted["zonesPlenum"] - zonesUnconditioned = zonesSorted["zonesUnconditioned"] + zonesPrimary = zonesSorted['zonesPrimary'] + zonesSecondary = zonesSorted['zonesSecondary'] + zonesPlenum = zonesSorted['zonesPlenum'] + zonesUnconditioned = zonesSorted['zonesUnconditioned'] ### END SORT ZONES - + ### START REPORT INITIAL CONDITIONS - OsLib_HVAC.reportConditions(model, runner, "initial") + OsLib_HVAC.reportConditions(model, runner, 'initial') ### END REPORT INITIAL CONDITIONS ### START ASSIGN HVAC SCHEDULES - options = {"primarySpaceType" => primarySpaceType, - "allHVAC" => allHVAC, - "remake_schedules" => remake_schedules} + options = { 'primarySpaceType' => primarySpaceType, + 'allHVAC' => allHVAC, + 'remake_schedules' => remake_schedules } schedulesHVAC = OsLib_HVAC.assignHVACSchedules(model, runner, options) # assign schedules - primary_SAT_schedule = schedulesHVAC["primary_sat"] - building_HVAC_schedule = schedulesHVAC["hvac"] - building_ventilation_schedule = schedulesHVAC["ventilation"] + primary_SAT_schedule = schedulesHVAC['primary_sat'] + building_HVAC_schedule = schedulesHVAC['hvac'] + building_ventilation_schedule = schedulesHVAC['ventilation'] make_hot_water_plant = false - unless schedulesHVAC["hot_water"].nil? - hot_water_setpoint_schedule = schedulesHVAC["hot_water"] + unless schedulesHVAC['hot_water'].nil? + hot_water_setpoint_schedule = schedulesHVAC['hot_water'] make_hot_water_plant = true end make_chilled_water_plant = false - unless schedulesHVAC["chilled_water"].nil? - chilled_water_setpoint_schedule = schedulesHVAC["chilled_water"] + unless schedulesHVAC['chilled_water'].nil? + chilled_water_setpoint_schedule = schedulesHVAC['chilled_water'] make_chilled_water_plant = true end make_radiant_hot_water_plant = false - unless schedulesHVAC["radiant_hot_water"].nil? - radiant_hot_water_setpoint_schedule = schedulesHVAC["radiant_hot_water"] + unless schedulesHVAC['radiant_hot_water'].nil? + radiant_hot_water_setpoint_schedule = schedulesHVAC['radiant_hot_water'] make_radiant_hot_water_plant = true end make_radiant_chilled_water_plant = false - unless schedulesHVAC["radiant_chilled_water"].nil? - radiant_chilled_water_setpoint_schedule = schedulesHVAC["radiant_chilled_water"] + unless schedulesHVAC['radiant_chilled_water'].nil? + radiant_chilled_water_setpoint_schedule = schedulesHVAC['radiant_chilled_water'] make_radiant_chilled_water_plant = true end - unless schedulesHVAC["hp_loop"].nil? - heat_pump_loop_setpoint_schedule = schedulesHVAC["hp_loop"] + unless schedulesHVAC['hp_loop'].nil? + heat_pump_loop_setpoint_schedule = schedulesHVAC['hp_loop'] end - unless schedulesHVAC["hp_loop_cooling"].nil? - heat_pump_loop_cooling_setpoint_schedule = schedulesHVAC["hp_loop_cooling"] + unless schedulesHVAC['hp_loop_cooling'].nil? + heat_pump_loop_cooling_setpoint_schedule = schedulesHVAC['hp_loop_cooling'] end - unless schedulesHVAC["hp_loop_heating"].nil? - heat_pump_loop_heating_setpoint_schedule = schedulesHVAC["hp_loop_heating"] + unless schedulesHVAC['hp_loop_heating'].nil? + heat_pump_loop_heating_setpoint_schedule = schedulesHVAC['hp_loop_heating'] end - unless schedulesHVAC["mean_radiant_heating"].nil? - mean_radiant_heating_setpoint_schedule = schedulesHVAC["mean_radiant_heating"] + unless schedulesHVAC['mean_radiant_heating'].nil? + mean_radiant_heating_setpoint_schedule = schedulesHVAC['mean_radiant_heating'] end - unless schedulesHVAC["mean_radiant_cooling"].nil? - mean_radiant_cooling_setpoint_schedule = schedulesHVAC["mean_radiant_cooling"] + unless schedulesHVAC['mean_radiant_cooling'].nil? + mean_radiant_cooling_setpoint_schedule = schedulesHVAC['mean_radiant_cooling'] end ### END ASSIGN HVAC SCHEDULES - + ### START REMOVE EQUIPMENT OsLib_HVAC.removeEquipment(model, runner) ### END REMOVE EQUIPMENT - + ### START CREATE NEW PLANTS # create new plants # hot water plant if make_hot_water_plant - hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, "Hot Water", boilerEff, boilerFuelType, boilerHWST) + hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, 'Hot Water', boilerEff, boilerFuelType, boilerHWST) end # chilled water plant if make_chilled_water_plant - chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, "Chilled Water", chillerType) + chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, 'Chilled Water', chillerType) end # radiant hot water plant if make_radiant_hot_water_plant - radiant_hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, radiant_hot_water_setpoint_schedule, "Radiant Hot Water") + radiant_hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, radiant_hot_water_setpoint_schedule, 'Radiant Hot Water') end # chilled water plant if make_radiant_chilled_water_plant - radiant_chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, radiant_chilled_water_setpoint_schedule, "Radiant Chilled Water", radiantChillerType) + radiant_chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, radiant_chilled_water_setpoint_schedule, 'Radiant Chilled Water', radiantChillerType) end # condenser loop # need condenser loop if there is a water-cooled chiller or if there is a water source heat pump loop options = {} - options["zoneHVAC"] = zoneHVAC - if zoneHVAC.include? "SHP" - options["loop_setpoint_schedule"] = heat_pump_loop_setpoint_schedule - options["cooling_setpoint_schedule"] = heat_pump_loop_cooling_setpoint_schedule - options["heating_setpoint_schedule"] = heat_pump_loop_heating_setpoint_schedule - end - condenserLoops = OsLib_HVAC.createCondenserLoop(model, runner, options,boilerEff,boilerFuelType,boilerHWST,coolingTowerWB,coolingTowerApproach,coolingTowerDeltaT,condLoopCoolingTemp,condLoopHeatingTemp) - unless condenserLoops["condenser_loop"].nil? - condenser_loop = condenserLoops["condenser_loop"] + options['zoneHVAC'] = zoneHVAC + if zoneHVAC.include? 'SHP' + options['loop_setpoint_schedule'] = heat_pump_loop_setpoint_schedule + options['cooling_setpoint_schedule'] = heat_pump_loop_cooling_setpoint_schedule + options['heating_setpoint_schedule'] = heat_pump_loop_heating_setpoint_schedule + end + condenserLoops = OsLib_HVAC.createCondenserLoop(model, runner, options, boilerEff, boilerFuelType, boilerHWST, coolingTowerWB, coolingTowerApproach, coolingTowerDeltaT, condLoopCoolingTemp, condLoopHeatingTemp) + unless condenserLoops['condenser_loop'].nil? + condenser_loop = condenserLoops['condenser_loop'] end - unless condenserLoops["heat_pump_loop"].nil? - heat_pump_loop = condenserLoops["heat_pump_loop"] + unless condenserLoops['heat_pump_loop'].nil? + heat_pump_loop = condenserLoops['heat_pump_loop'] end ### END CREATE NEW PLANTS - + ### START CREATE PRIMARY AIRLOOPS # populate inputs hash for create primary airloops method options = {} - options["zonesPrimary"] = zonesPrimary - options["primaryHVAC"] = primaryHVAC - options["zoneHVAC"] = zoneHVAC - if primaryHVAC["doas"] - options["hvac_schedule"] = building_ventilation_schedule - options["ventilation_schedule"] = building_ventilation_schedule + options['zonesPrimary'] = zonesPrimary + options['primaryHVAC'] = primaryHVAC + options['zoneHVAC'] = zoneHVAC + if primaryHVAC['doas'] + options['hvac_schedule'] = building_ventilation_schedule + options['ventilation_schedule'] = building_ventilation_schedule else # primary HVAC is multizone VAV - unless zoneHVAC == "DualDuct" - # primary system is multizone VAV that cools and ventilates - options["hvac_schedule"] = building_HVAC_schedule - options["ventilation_schedule"] = building_ventilation_schedule - else + if zoneHVAC == 'DualDuct' # primary system is a multizone VAV that cools only (primary system ventilation schedule is set to always off; hvac set to always on) - options["hvac_schedule"] = model.alwaysOnDiscreteSchedule() + options['hvac_schedule'] = model.alwaysOnDiscreteSchedule + else + # primary system is multizone VAV that cools and ventilates + options['hvac_schedule'] = building_HVAC_schedule + options['ventilation_schedule'] = building_ventilation_schedule end end - options["primary_sat_schedule"] = primary_SAT_schedule + options['primary_sat_schedule'] = primary_SAT_schedule if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end - primary_airloops = OsLib_HVAC.createPrimaryAirLoops(model, runner, options,doasFanType,doasERV,doasEvap,doasDXEER) + primary_airloops = OsLib_HVAC.createPrimaryAirLoops(model, runner, options, doasFanType, doasERV, doasEvap, doasDXEER) ### END CREATE PRIMARY AIRLOOPS - + ### START CREATE SECONDARY AIRLOOPS # populate inputs hash for create primary airloops method options = {} - options["zonesSecondary"] = zonesSecondary - options["secondaryHVAC"] = secondaryHVAC - options["hvac_schedule"] = building_HVAC_schedule - options["ventilation_schedule"] = building_ventilation_schedule + options['zonesSecondary'] = zonesSecondary + options['secondaryHVAC'] = secondaryHVAC + options['hvac_schedule'] = building_HVAC_schedule + options['ventilation_schedule'] = building_ventilation_schedule if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end secondary_airloops = OsLib_HVAC.createSecondaryAirLoops(model, runner, options) ### END CREATE SECONDARY AIRLOOPS - + ### START ASSIGN PLENUMS - options = {"zonesPrimary" => zonesPrimary,"zonesPlenum" => zonesPlenum} + options = { 'zonesPrimary' => zonesPrimary, 'zonesPlenum' => zonesPlenum } zone_plenum_hash = OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options) ### END ASSIGN PLENUMS - + ### START CREATE PRIMARY ZONE EQUIPMENT options = {} - options["zonesPrimary"] = zonesPrimary - options["zoneHVAC"] = zoneHVAC + options['zonesPrimary'] = zonesPrimary + options['zoneHVAC'] = zoneHVAC if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end - if zoneHVAC.include? "SHP" - options["heat_pump_loop"] = heat_pump_loop + if zoneHVAC.include? 'SHP' + options['heat_pump_loop'] = heat_pump_loop end - if zoneHVAC == "DualDuct" - options["ventilation_schedule"] = building_ventilation_schedule + if zoneHVAC == 'DualDuct' + options['ventilation_schedule'] = building_ventilation_schedule end - if zoneHVAC == "Radiant" - options["radiant_hot_water_plant"] = radiant_hot_water_plant - options["radiant_chilled_water_plant"] = radiant_chilled_water_plant - options["mean_radiant_heating_setpoint_schedule"] = mean_radiant_heating_setpoint_schedule - options["mean_radiant_cooling_setpoint_schedule"] = mean_radiant_cooling_setpoint_schedule + if zoneHVAC == 'Radiant' + options['radiant_hot_water_plant'] = radiant_hot_water_plant + options['radiant_chilled_water_plant'] = radiant_chilled_water_plant + options['mean_radiant_heating_setpoint_schedule'] = mean_radiant_heating_setpoint_schedule + options['mean_radiant_cooling_setpoint_schedule'] = mean_radiant_cooling_setpoint_schedule end - OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options,wshpCoolingEER, wshpHeatingCOP,wshpFanType) + OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options, wshpCoolingEER, wshpHeatingCOP, wshpFanType) ### END CREATE PRIMARY ZONE EQUIPMENT - + # START ADD DCV options = {} - unless zoneHVAC == "DualDuct" - options["primary_airloops"] = primary_airloops + unless zoneHVAC == 'DualDuct' + options['primary_airloops'] = primary_airloops end - options["secondary_airloops"] = secondary_airloops - options["allHVAC"] = allHVAC + options['secondary_airloops'] = secondary_airloops + options['allHVAC'] = allHVAC OsLib_HVAC.addDCV(model, runner, options) # END ADD DCV - - # todo - add in lifecycle costs + + # TODO: - add in lifecycle costs expected_life = 25 years_until_costs_start = 0 costHVAC = costTotalHVACSystem - lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("HVAC System", model.getBuilding, costHVAC, "CostPerEach", "Construction", expected_life, years_until_costs_start).get + lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost('HVAC System', model.getBuilding, costHVAC, 'CostPerEach', 'Construction', expected_life, years_until_costs_start).get # # # # add AEDG tips - aedgTips = ["HV04","HV10","HV12"] + aedgTips = ['HV04', 'HV10', 'HV12'] # populate how to tip messages - aedgTipsLong = OsLib_AedgMeasures.getLongHowToTips("SmMdOff",aedgTips.uniq.sort,runner) - if not aedgTipsLong - return false # this should only happen if measure writer passes bad values to getLongHowToTips - end + aedgTipsLong = OsLib_AedgMeasures.getLongHowToTips('SmMdOff', aedgTips.uniq.sort, runner) + if !aedgTipsLong + return false # this should only happen if measure writer passes bad values to getLongHowToTips + end ### START REPORT FINAL CONDITIONS - OsLib_HVAC.reportConditions(model, runner, "final") + OsLib_HVAC.reportConditions(model, runner, 'final') ### END REPORT FINAL CONDITIONS return true + end # end the run method +end # end the measure - end #end the run method - -end #end the measure - -#this allows the measure to be used by the application -WSHPwithDOASMoreDesignParameters.new.registerWithApplication \ No newline at end of file +# this allows the measure to be used by the application +WSHPwithDOASMoreDesignParameters.new.registerWithApplication diff --git a/lib/measures/vr_fwith_doas/tests/measure-backup.rb b/lib/measures/vr_fwith_doas/tests/measure-backup.rb index 42f2889..dfbceac 100644 --- a/lib/measures/vr_fwith_doas/tests/measure-backup.rb +++ b/lib/measures/vr_fwith_doas/tests/measure-backup.rb @@ -1,28 +1,29 @@ -#see the URL below for information on how to write OpenStudio measures +# frozen_string_literal: true + +# see the URL below for information on how to write OpenStudio measures # http://openstudio.nrel.gov/openstudio-measure-writing-guide -#see the URL below for information on using life cycle cost objects in OpenStudio +# see the URL below for information on using life cycle cost objects in OpenStudio # http://openstudio.nrel.gov/openstudio-life-cycle-examples -#see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) +# see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) # http://openstudio.nrel.gov/sites/openstudio.nrel.gov/files/nv_data/cpp_documentation_it/model/html/namespaces.html -#load OpenStudio measure libraries -#require "#{File.dirname(__FILE__)}/resources/OsLib_AedgMeasures" +# load OpenStudio measure libraries +# require "#{File.dirname(__FILE__)}/resources/OsLib_AedgMeasures" require "#{File.dirname(__FILE__)}/resources/OsLib_HelperMethods" require "#{File.dirname(__FILE__)}/resources/OsLib_HVAC" require "#{File.dirname(__FILE__)}/resources/OsLib_Schedules" -#start the measure +# start the measure class WSHPwithDOASMoreDesignParameters < OpenStudio::Ruleset::ModelUserScript - - #define the name that a user will see, this method may be deprecated as - #the display name in PAT comes from the name field in measure.xml + # define the name that a user will see, this method may be deprecated as + # the display name in PAT comes from the name field in measure.xml def name - return "WSHPwithDOASMoreDesignParameters" + return 'WSHPwithDOASMoreDesignParameters' end - #define the arguments that the user will input + # define the arguments that the user will input def arguments(model) args = OpenStudio::Ruleset::OSArgumentVector.new @@ -30,386 +31,385 @@ def arguments(model) spaceTypes = model.getSpaceTypes usedSpaceTypes_handle = OpenStudio::StringVector.new usedSpaceTypes_displayName = OpenStudio::StringVector.new - spaceTypes.each do |spaceType| #todo - I need to update this to use helper so GUI sorts by display name - if spaceType.spaces.size > 0 # only show space types used in the building + spaceTypes.each do |spaceType| # TODO: - I need to update this to use helper so GUI sorts by display name + if !spaceType.spaces.empty? # only show space types used in the building usedSpaceTypes_handle << spaceType.handle.to_s usedSpaceTypes_displayName << spaceType.name.to_s end end # make an argument for space type - ceilingReturnPlenumSpaceType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("ceilingReturnPlenumSpaceType", usedSpaceTypes_handle, usedSpaceTypes_displayName,false) - ceilingReturnPlenumSpaceType.setDisplayName("This space type should be part of a ceiling return air plenum.") - #ceilingReturnPlenumSpaceType.setDefaultValue("We don't want a default, this is an optional argument") + ceilingReturnPlenumSpaceType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('ceilingReturnPlenumSpaceType', usedSpaceTypes_handle, usedSpaceTypes_displayName, false) + ceilingReturnPlenumSpaceType.setDisplayName('This space type should be part of a ceiling return air plenum.') + # ceilingReturnPlenumSpaceType.setDefaultValue("We don't want a default, this is an optional argument") args << ceilingReturnPlenumSpaceType - - # Heating COP of WSHP - wshpHeatingCOP = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("wshpHeatingCOP",false) - wshpHeatingCOP.setDisplayName("WSHP AHRI Heating COP") - wshpHeatingCOP.setDefaultValue(4.0) - args << wshpHeatingCOP - - # Cooling EER of WSHP - wshpCoolingEER = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("wshpCoolingEER",false) - wshpCoolingEER.setDisplayName("WSHP AHRI Cooling EER") - wshpCoolingEER.setDefaultValue(14) - args << wshpCoolingEER - - # WSHP Fan Type PSC or ECM - fanChs = OpenStudio::StringVector.new - fanChs << "PSC" - fanChs << "ECM" - wshpFanType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("wshpFanType",fanChs,true) # note ECM fan type may correspond to different set of heat pump performance curves - wshpFanType.setDisplayName("WSHP Fan Type: PSC or ECM?") - wshpFanType.setDefaultValue("PSC") + + # Heating COP of WSHP + wshpHeatingCOP = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('wshpHeatingCOP', false) + wshpHeatingCOP.setDisplayName('WSHP AHRI Heating COP') + wshpHeatingCOP.setDefaultValue(4.0) + args << wshpHeatingCOP + + # Cooling EER of WSHP + wshpCoolingEER = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('wshpCoolingEER', false) + wshpCoolingEER.setDisplayName('WSHP AHRI Cooling EER') + wshpCoolingEER.setDefaultValue(14) + args << wshpCoolingEER + + # WSHP Fan Type PSC or ECM + fanChs = OpenStudio::StringVector.new + fanChs << 'PSC' + fanChs << 'ECM' + wshpFanType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('wshpFanType', fanChs, true) # note ECM fan type may correspond to different set of heat pump performance curves + wshpFanType.setDisplayName('WSHP Fan Type: PSC or ECM?') + wshpFanType.setDefaultValue('PSC') args << wshpFanType - - # Condenser Loop Cooling Temperature - condLoopCoolingTemp = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("condLoopCoolingTemp",false) - condLoopCoolingTemp.setDisplayName("Condenser Loop Cooling Temperature (F)") - condLoopCoolingTemp.setDefaultValue(90) - args << condLoopCoolingTemp - - # Condenser Loop Heating Temperature - condLoopHeatingTemp = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("condLoopHeatingTemp",false) - condLoopHeatingTemp.setDisplayName("Condenser Loop Heating Temperature (F)") - condLoopHeatingTemp.setDefaultValue(60) - args << condLoopHeatingTemp - - # Cooling Tower - coolingTowerWB = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("coolingTowerWB",false) - coolingTowerWB.setDisplayName("Cooling Tower Design Wet Bulb (F)") - coolingTowerWB.setDefaultValue(68) - args << coolingTowerWB - - coolingTowerApproach = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("coolingTowerApproach",false) - coolingTowerApproach.setDisplayName("Cooling Tower Design Approach (F)") - coolingTowerApproach.setDefaultValue(7.0) - args << coolingTowerApproach - - coolingTowerDeltaT = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("coolingTowerDeltaT",false) - coolingTowerDeltaT.setDisplayName("Cooling Tower Design Delta T (F)") - coolingTowerDeltaT.setDefaultValue(10.0) - args << coolingTowerDeltaT - - # Boiler Efficiency - boilerEff = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("boilerEff",false) - boilerEff.setDisplayName("Boiler Thermal Efficiency") - boilerEff.setDefaultValue(0.9) - args << boilerEff - + + # Condenser Loop Cooling Temperature + condLoopCoolingTemp = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('condLoopCoolingTemp', false) + condLoopCoolingTemp.setDisplayName('Condenser Loop Cooling Temperature (F)') + condLoopCoolingTemp.setDefaultValue(90) + args << condLoopCoolingTemp + + # Condenser Loop Heating Temperature + condLoopHeatingTemp = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('condLoopHeatingTemp', false) + condLoopHeatingTemp.setDisplayName('Condenser Loop Heating Temperature (F)') + condLoopHeatingTemp.setDefaultValue(60) + args << condLoopHeatingTemp + + # Cooling Tower + coolingTowerWB = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('coolingTowerWB', false) + coolingTowerWB.setDisplayName('Cooling Tower Design Wet Bulb (F)') + coolingTowerWB.setDefaultValue(68) + args << coolingTowerWB + + coolingTowerApproach = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('coolingTowerApproach', false) + coolingTowerApproach.setDisplayName('Cooling Tower Design Approach (F)') + coolingTowerApproach.setDefaultValue(7.0) + args << coolingTowerApproach + + coolingTowerDeltaT = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('coolingTowerDeltaT', false) + coolingTowerDeltaT.setDisplayName('Cooling Tower Design Delta T (F)') + coolingTowerDeltaT.setDefaultValue(10.0) + args << coolingTowerDeltaT + + # Boiler Efficiency + boilerEff = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('boilerEff', false) + boilerEff.setDisplayName('Boiler Thermal Efficiency') + boilerEff.setDefaultValue(0.9) + args << boilerEff + # Boiler fuel Type - fuelChs = OpenStudio::StringVector.new - fuelChs << "NaturalGas" - fuelChs << "PropaneGas" - fuelChs << "FuelOil#1" - fuelChs << "FuelOil#2" - fuelChs << "Electricity" - boilerFuelType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("boilerFuelType",fuelChs,false) - boilerFuelType.setDisplayName("Boiler Fuel Type") - boilerFuelType.setDefaultValue("NaturalGas") - args << boilerFuelType - - # boiler Hot water supply temperature - boilerHWST = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("boilerHWST",false) - boilerHWST.setDisplayName("Boiler Design Heating Water Outlet Temperature (F)") - boilerHWST.setDefaultValue(120) - args << boilerHWST - - # DOAS Fan Type - doasFanChs = OpenStudio::StringVector.new - doasFanChs << "Constant" - doasFanChs << "Variable" - doasFanType = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doasFanType",doasFanChs,true) - doasFanType.setDisplayName("DOAS Fan Flow Control - Variable means DCV controls") - doasFanType.setDefaultValue("Variable") - args << doasFanType - - # DOAS Energy Recovery - ervChs = OpenStudio::StringVector.new - ervChs << "plate w/o economizer lockout" - ervChs << "plate w/ economizer lockout" - ervChs << "rotary wheel w/o economizer lockout" - ervChs << "rotary wheel w/ economizer lockout" - ervChs << "none" - doasERV = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doasERV",ervChs,true) - doasERV.setDisplayName("DOAS Energy Recovery?") - doasERV.setDefaultValue("none") - args << doasERV - - # DOAS Evaporative Cooling - evapChs = OpenStudio::StringVector.new - evapChs << "Direct Evaporative Cooler" - evapChs << "none" - doasEvap = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("doasEvap",evapChs,true) - doasEvap.setDisplayName("DOAS Direct Evaporative Cooling?") - doasEvap.setDefaultValue("none") - args << doasEvap - - # DOAS DX Cooling - doasDXEER = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("doasDXEER",false) - doasDXEER.setDisplayName("DOAS DX Cooling EER") - doasDXEER.setDefaultValue(10.0) - args << doasDXEER - + fuelChs = OpenStudio::StringVector.new + fuelChs << 'NaturalGas' + fuelChs << 'PropaneGas' + fuelChs << 'FuelOil#1' + fuelChs << 'FuelOil#2' + fuelChs << 'Electricity' + boilerFuelType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('boilerFuelType', fuelChs, false) + boilerFuelType.setDisplayName('Boiler Fuel Type') + boilerFuelType.setDefaultValue('NaturalGas') + args << boilerFuelType + + # boiler Hot water supply temperature + boilerHWST = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('boilerHWST', false) + boilerHWST.setDisplayName('Boiler Design Heating Water Outlet Temperature (F)') + boilerHWST.setDefaultValue(120) + args << boilerHWST + + # DOAS Fan Type + doasFanChs = OpenStudio::StringVector.new + doasFanChs << 'Constant' + doasFanChs << 'Variable' + doasFanType = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doasFanType', doasFanChs, true) + doasFanType.setDisplayName('DOAS Fan Flow Control - Variable means DCV controls') + doasFanType.setDefaultValue('Variable') + args << doasFanType + + # DOAS Energy Recovery + ervChs = OpenStudio::StringVector.new + ervChs << 'plate w/o economizer lockout' + ervChs << 'plate w/ economizer lockout' + ervChs << 'rotary wheel w/o economizer lockout' + ervChs << 'rotary wheel w/ economizer lockout' + ervChs << 'none' + doasERV = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doasERV', ervChs, true) + doasERV.setDisplayName('DOAS Energy Recovery?') + doasERV.setDefaultValue('none') + args << doasERV + + # DOAS Evaporative Cooling + evapChs = OpenStudio::StringVector.new + evapChs << 'Direct Evaporative Cooler' + evapChs << 'none' + doasEvap = OpenStudio::Ruleset::OSArgument.makeChoiceArgument('doasEvap', evapChs, true) + doasEvap.setDisplayName('DOAS Direct Evaporative Cooling?') + doasEvap.setDefaultValue('none') + args << doasEvap + + # DOAS DX Cooling + doasDXEER = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('doasDXEER', false) + doasDXEER.setDisplayName('DOAS DX Cooling EER') + doasDXEER.setDefaultValue(10.0) + args << doasDXEER + # make an argument for material and installation cost # todo - I would like to split the costing out to the air loops weighted by area of building served vs. just sticking it on the building - costTotalHVACSystem = OpenStudio::Ruleset::OSArgument::makeDoubleArgument("costTotalHVACSystem",true) - costTotalHVACSystem.setDisplayName("Total Cost for HVAC System ($).") + costTotalHVACSystem = OpenStudio::Ruleset::OSArgument.makeDoubleArgument('costTotalHVACSystem', true) + costTotalHVACSystem.setDisplayName('Total Cost for HVAC System ($).') costTotalHVACSystem.setDefaultValue(0.0) args << costTotalHVACSystem - - #make an argument to remove existing costs - remake_schedules = OpenStudio::Ruleset::OSArgument::makeBoolArgument("remake_schedules",true) - remake_schedules.setDisplayName("Apply recommended availability and ventilation schedules for air handlers?") + + # make an argument to remove existing costs + remake_schedules = OpenStudio::Ruleset::OSArgument.makeBoolArgument('remake_schedules', true) + remake_schedules.setDisplayName('Apply recommended availability and ventilation schedules for air handlers?') remake_schedules.setDefaultValue(true) args << remake_schedules return args - end #end the arguments method + end # end the arguments method - #define what happens when the measure is run + # define what happens when the measure is run def run(model, runner, user_arguments) super(model, runner, user_arguments) - #use the built-in error checking - if not runner.validateUserArguments(arguments(model), user_arguments) + # use the built-in error checking + if !runner.validateUserArguments(arguments(model), user_arguments) return false end - wshpHeatingCOP = runner.getDoubleArgumentValue("wshpHeatingCOP",user_arguments) - wshpCoolingEER = runner.getDoubleArgumentValue("wshpCoolingEER",user_arguments) - wshpFanType = runner.getStringArgumentValue("wshpFanType",user_arguments) - condLoopCoolingTemp = runner.getDoubleArgumentValue("condLoopCoolingTemp",user_arguments) - condLoopHeatingTemp = runner.getDoubleArgumentValue("condLoopHeatingTemp",user_arguments) - coolingTowerWB = runner.getDoubleArgumentValue("coolingTowerWB",user_arguments) - coolingTowerApproach= runner.getDoubleArgumentValue("coolingTowerApproach",user_arguments) - coolingTowerDeltaT= runner.getDoubleArgumentValue("coolingTowerDeltaT",user_arguments) - boilerEff= runner.getDoubleArgumentValue("boilerEff",user_arguments) - boilerFuelType = runner.getStringArgumentValue("boilerFuelType",user_arguments) - boilerHWST= runner.getDoubleArgumentValue("boilerHWST",user_arguments) - doasFanType = runner.getStringArgumentValue("doasFanType",user_arguments) - doasERV = runner.getStringArgumentValue("doasERV",user_arguments) - doasEvap = runner.getStringArgumentValue("doasEvap",user_arguments) - doasDXEER= runner.getDoubleArgumentValue("doasDXEER",user_arguments) - + wshpHeatingCOP = runner.getDoubleArgumentValue('wshpHeatingCOP', user_arguments) + wshpCoolingEER = runner.getDoubleArgumentValue('wshpCoolingEER', user_arguments) + wshpFanType = runner.getStringArgumentValue('wshpFanType', user_arguments) + condLoopCoolingTemp = runner.getDoubleArgumentValue('condLoopCoolingTemp', user_arguments) + condLoopHeatingTemp = runner.getDoubleArgumentValue('condLoopHeatingTemp', user_arguments) + coolingTowerWB = runner.getDoubleArgumentValue('coolingTowerWB', user_arguments) + coolingTowerApproach = runner.getDoubleArgumentValue('coolingTowerApproach', user_arguments) + coolingTowerDeltaT = runner.getDoubleArgumentValue('coolingTowerDeltaT', user_arguments) + boilerEff = runner.getDoubleArgumentValue('boilerEff', user_arguments) + boilerFuelType = runner.getStringArgumentValue('boilerFuelType', user_arguments) + boilerHWST = runner.getDoubleArgumentValue('boilerHWST', user_arguments) + doasFanType = runner.getStringArgumentValue('doasFanType', user_arguments) + doasERV = runner.getStringArgumentValue('doasERV', user_arguments) + doasEvap = runner.getStringArgumentValue('doasEvap', user_arguments) + doasDXEER = runner.getDoubleArgumentValue('doasDXEER', user_arguments) + ### START INPUTS - #assign the user inputs to variables - ceilingReturnPlenumSpaceType = runner.getOptionalWorkspaceObjectChoiceValue("ceilingReturnPlenumSpaceType",user_arguments,model) - costTotalHVACSystem = runner.getDoubleArgumentValue("costTotalHVACSystem",user_arguments) - remake_schedules = runner.getBoolArgumentValue("remake_schedules",user_arguments) + # assign the user inputs to variables + ceilingReturnPlenumSpaceType = runner.getOptionalWorkspaceObjectChoiceValue('ceilingReturnPlenumSpaceType', user_arguments, model) + costTotalHVACSystem = runner.getDoubleArgumentValue('costTotalHVACSystem', user_arguments) + remake_schedules = runner.getBoolArgumentValue('remake_schedules', user_arguments) # check that spaceType was chosen and exists in model - ceilingReturnPlenumSpaceTypeCheck = OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(ceilingReturnPlenumSpaceType, "ceilingReturnPlenumSpaceType","to_SpaceType", runner, user_arguments) - if ceilingReturnPlenumSpaceTypeCheck == false then return false else ceilingReturnPlenumSpaceType = ceilingReturnPlenumSpaceTypeCheck["modelObject"] end + ceilingReturnPlenumSpaceTypeCheck = OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(ceilingReturnPlenumSpaceType, 'ceilingReturnPlenumSpaceType', 'to_SpaceType', runner, user_arguments) + ceilingReturnPlenumSpaceTypeCheck == false ? (return false) : (ceilingReturnPlenumSpaceType = ceilingReturnPlenumSpaceTypeCheck['modelObject']) # default building/ secondary space types - standardBuildingTypeTest = ["Office"] #ML Not used yet + standardBuildingTypeTest = ['Office'] # ML Not used yet secondarySpaceTypeTest = [] # empty for office - primarySpaceType = "Office" - if doasFanType == "Variable" - primaryHVAC = {"doas" => true, "fan" => "Variable", "heat" => "Gas", "cool" => "SingleDX"} - else - primaryHVAC = {"doas" => true, "fan" => "Constant", "heat" => "Gas", "cool" => "SingleDX"} - end - secondaryHVAC = {"fan" => "None", "heat" => "None", "cool" => "None"} #ML not used for office; leave or empty? - zoneHVAC = "WSHP" - chillerType = "None" #set to none if chiller not used - radiantChillerType = "None" #set to none if not radiant system - allHVAC = {"primary" => primaryHVAC,"secondary" => secondaryHVAC,"zone" => zoneHVAC} - - + primarySpaceType = 'Office' + if doasFanType == 'Variable' + primaryHVAC = { 'doas' => true, 'fan' => 'Variable', 'heat' => 'Gas', 'cool' => 'SingleDX' } + else + primaryHVAC = { 'doas' => true, 'fan' => 'Constant', 'heat' => 'Gas', 'cool' => 'SingleDX' } + end + secondaryHVAC = { 'fan' => 'None', 'heat' => 'None', 'cool' => 'None' } # ML not used for office; leave or empty? + zoneHVAC = 'WSHP' + chillerType = 'None' # set to none if chiller not used + radiantChillerType = 'None' # set to none if not radiant system + allHVAC = { 'primary' => primaryHVAC, 'secondary' => secondaryHVAC, 'zone' => zoneHVAC } + ### END INPUTS - + ### START SORT ZONES - options = {"standardBuildingTypeTest" => standardBuildingTypeTest, #ML Not used yet - "secondarySpaceTypeTest" => secondarySpaceTypeTest, - "ceilingReturnPlenumSpaceType" => ceilingReturnPlenumSpaceType} + options = { 'standardBuildingTypeTest' => standardBuildingTypeTest, # ML Not used yet + 'secondarySpaceTypeTest' => secondarySpaceTypeTest, + 'ceilingReturnPlenumSpaceType' => ceilingReturnPlenumSpaceType } zonesSorted = OsLib_HVAC.sortZones(model, runner, options) - zonesPrimary = zonesSorted["zonesPrimary"] - zonesSecondary = zonesSorted["zonesSecondary"] - zonesPlenum = zonesSorted["zonesPlenum"] - zonesUnconditioned = zonesSorted["zonesUnconditioned"] + zonesPrimary = zonesSorted['zonesPrimary'] + zonesSecondary = zonesSorted['zonesSecondary'] + zonesPlenum = zonesSorted['zonesPlenum'] + zonesUnconditioned = zonesSorted['zonesUnconditioned'] ### END SORT ZONES - + ### START REPORT INITIAL CONDITIONS - OsLib_HVAC.reportConditions(model, runner, "initial") + OsLib_HVAC.reportConditions(model, runner, 'initial') ### END REPORT INITIAL CONDITIONS ### START ASSIGN HVAC SCHEDULES - options = {"primarySpaceType" => primarySpaceType, - "allHVAC" => allHVAC, - "remake_schedules" => remake_schedules} + options = { 'primarySpaceType' => primarySpaceType, + 'allHVAC' => allHVAC, + 'remake_schedules' => remake_schedules } schedulesHVAC = OsLib_HVAC.assignHVACSchedules(model, runner, options) # assign schedules - primary_SAT_schedule = schedulesHVAC["primary_sat"] - building_HVAC_schedule = schedulesHVAC["hvac"] - building_ventilation_schedule = schedulesHVAC["ventilation"] + primary_SAT_schedule = schedulesHVAC['primary_sat'] + building_HVAC_schedule = schedulesHVAC['hvac'] + building_ventilation_schedule = schedulesHVAC['ventilation'] make_hot_water_plant = false - unless schedulesHVAC["hot_water"].nil? - hot_water_setpoint_schedule = schedulesHVAC["hot_water"] + unless schedulesHVAC['hot_water'].nil? + hot_water_setpoint_schedule = schedulesHVAC['hot_water'] make_hot_water_plant = true end make_chilled_water_plant = false - unless schedulesHVAC["chilled_water"].nil? - chilled_water_setpoint_schedule = schedulesHVAC["chilled_water"] + unless schedulesHVAC['chilled_water'].nil? + chilled_water_setpoint_schedule = schedulesHVAC['chilled_water'] make_chilled_water_plant = true end make_radiant_hot_water_plant = false - unless schedulesHVAC["radiant_hot_water"].nil? - radiant_hot_water_setpoint_schedule = schedulesHVAC["radiant_hot_water"] + unless schedulesHVAC['radiant_hot_water'].nil? + radiant_hot_water_setpoint_schedule = schedulesHVAC['radiant_hot_water'] make_radiant_hot_water_plant = true end make_radiant_chilled_water_plant = false - unless schedulesHVAC["radiant_chilled_water"].nil? - radiant_chilled_water_setpoint_schedule = schedulesHVAC["radiant_chilled_water"] + unless schedulesHVAC['radiant_chilled_water'].nil? + radiant_chilled_water_setpoint_schedule = schedulesHVAC['radiant_chilled_water'] make_radiant_chilled_water_plant = true end - unless schedulesHVAC["hp_loop"].nil? - heat_pump_loop_setpoint_schedule = schedulesHVAC["hp_loop"] + unless schedulesHVAC['hp_loop'].nil? + heat_pump_loop_setpoint_schedule = schedulesHVAC['hp_loop'] end - unless schedulesHVAC["hp_loop_cooling"].nil? - heat_pump_loop_cooling_setpoint_schedule = schedulesHVAC["hp_loop_cooling"] + unless schedulesHVAC['hp_loop_cooling'].nil? + heat_pump_loop_cooling_setpoint_schedule = schedulesHVAC['hp_loop_cooling'] end - unless schedulesHVAC["hp_loop_heating"].nil? - heat_pump_loop_heating_setpoint_schedule = schedulesHVAC["hp_loop_heating"] + unless schedulesHVAC['hp_loop_heating'].nil? + heat_pump_loop_heating_setpoint_schedule = schedulesHVAC['hp_loop_heating'] end - unless schedulesHVAC["mean_radiant_heating"].nil? - mean_radiant_heating_setpoint_schedule = schedulesHVAC["mean_radiant_heating"] + unless schedulesHVAC['mean_radiant_heating'].nil? + mean_radiant_heating_setpoint_schedule = schedulesHVAC['mean_radiant_heating'] end - unless schedulesHVAC["mean_radiant_cooling"].nil? - mean_radiant_cooling_setpoint_schedule = schedulesHVAC["mean_radiant_cooling"] + unless schedulesHVAC['mean_radiant_cooling'].nil? + mean_radiant_cooling_setpoint_schedule = schedulesHVAC['mean_radiant_cooling'] end ### END ASSIGN HVAC SCHEDULES - + ### START REMOVE EQUIPMENT OsLib_HVAC.removeEquipment(model, runner) ### END REMOVE EQUIPMENT - + ### START CREATE NEW PLANTS # create new plants # hot water plant if make_hot_water_plant - hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, "Hot Water", boilerEff, boilerFuelType, boilerHWST) + hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, 'Hot Water', boilerEff, boilerFuelType, boilerHWST) end # chilled water plant if make_chilled_water_plant - chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, "Chilled Water", chillerType) + chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, 'Chilled Water', chillerType) end # radiant hot water plant if make_radiant_hot_water_plant - radiant_hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, radiant_hot_water_setpoint_schedule, "Radiant Hot Water") + radiant_hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, radiant_hot_water_setpoint_schedule, 'Radiant Hot Water') end # chilled water plant if make_radiant_chilled_water_plant - radiant_chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, radiant_chilled_water_setpoint_schedule, "Radiant Chilled Water", radiantChillerType) + radiant_chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, radiant_chilled_water_setpoint_schedule, 'Radiant Chilled Water', radiantChillerType) end # condenser loop # need condenser loop if there is a water-cooled chiller or if there is a water source heat pump loop options = {} - options["zoneHVAC"] = zoneHVAC - if zoneHVAC.include? "SHP" - options["loop_setpoint_schedule"] = heat_pump_loop_setpoint_schedule - options["cooling_setpoint_schedule"] = heat_pump_loop_cooling_setpoint_schedule - options["heating_setpoint_schedule"] = heat_pump_loop_heating_setpoint_schedule - end - condenserLoops = OsLib_HVAC.createCondenserLoop(model, runner, options,boilerEff,boilerFuelType,boilerHWST,coolingTowerWB,coolingTowerApproach,coolingTowerDeltaT,condLoopCoolingTemp,condLoopHeatingTemp) - unless condenserLoops["condenser_loop"].nil? - condenser_loop = condenserLoops["condenser_loop"] + options['zoneHVAC'] = zoneHVAC + if zoneHVAC.include? 'SHP' + options['loop_setpoint_schedule'] = heat_pump_loop_setpoint_schedule + options['cooling_setpoint_schedule'] = heat_pump_loop_cooling_setpoint_schedule + options['heating_setpoint_schedule'] = heat_pump_loop_heating_setpoint_schedule + end + condenserLoops = OsLib_HVAC.createCondenserLoop(model, runner, options, boilerEff, boilerFuelType, boilerHWST, coolingTowerWB, coolingTowerApproach, coolingTowerDeltaT, condLoopCoolingTemp, condLoopHeatingTemp) + unless condenserLoops['condenser_loop'].nil? + condenser_loop = condenserLoops['condenser_loop'] end - unless condenserLoops["heat_pump_loop"].nil? - heat_pump_loop = condenserLoops["heat_pump_loop"] + unless condenserLoops['heat_pump_loop'].nil? + heat_pump_loop = condenserLoops['heat_pump_loop'] end ### END CREATE NEW PLANTS - + ### START CREATE PRIMARY AIRLOOPS # populate inputs hash for create primary airloops method options = {} - options["zonesPrimary"] = zonesPrimary - options["primaryHVAC"] = primaryHVAC - options["zoneHVAC"] = zoneHVAC - if primaryHVAC["doas"] - options["hvac_schedule"] = building_ventilation_schedule - options["ventilation_schedule"] = building_ventilation_schedule + options['zonesPrimary'] = zonesPrimary + options['primaryHVAC'] = primaryHVAC + options['zoneHVAC'] = zoneHVAC + if primaryHVAC['doas'] + options['hvac_schedule'] = building_ventilation_schedule + options['ventilation_schedule'] = building_ventilation_schedule else # primary HVAC is multizone VAV - unless zoneHVAC == "DualDuct" - # primary system is multizone VAV that cools and ventilates - options["hvac_schedule"] = building_HVAC_schedule - options["ventilation_schedule"] = building_ventilation_schedule - else + if zoneHVAC == 'DualDuct' # primary system is a multizone VAV that cools only (primary system ventilation schedule is set to always off; hvac set to always on) - options["hvac_schedule"] = model.alwaysOnDiscreteSchedule() + options['hvac_schedule'] = model.alwaysOnDiscreteSchedule + else + # primary system is multizone VAV that cools and ventilates + options['hvac_schedule'] = building_HVAC_schedule + options['ventilation_schedule'] = building_ventilation_schedule end end - options["primary_sat_schedule"] = primary_SAT_schedule + options['primary_sat_schedule'] = primary_SAT_schedule if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end - primary_airloops = OsLib_HVAC.createPrimaryAirLoops(model, runner, options,doasFanType,doasERV,doasEvap,doasDXEER) + primary_airloops = OsLib_HVAC.createPrimaryAirLoops(model, runner, options, doasFanType, doasERV, doasEvap, doasDXEER) ### END CREATE PRIMARY AIRLOOPS - + ### START CREATE SECONDARY AIRLOOPS # populate inputs hash for create primary airloops method options = {} - options["zonesSecondary"] = zonesSecondary - options["secondaryHVAC"] = secondaryHVAC - options["hvac_schedule"] = building_HVAC_schedule - options["ventilation_schedule"] = building_ventilation_schedule + options['zonesSecondary'] = zonesSecondary + options['secondaryHVAC'] = secondaryHVAC + options['hvac_schedule'] = building_HVAC_schedule + options['ventilation_schedule'] = building_ventilation_schedule if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end secondary_airloops = OsLib_HVAC.createSecondaryAirLoops(model, runner, options) ### END CREATE SECONDARY AIRLOOPS - + ### START ASSIGN PLENUMS - options = {"zonesPrimary" => zonesPrimary,"zonesPlenum" => zonesPlenum} + options = { 'zonesPrimary' => zonesPrimary, 'zonesPlenum' => zonesPlenum } zone_plenum_hash = OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options) ### END ASSIGN PLENUMS - + ### START CREATE PRIMARY ZONE EQUIPMENT options = {} - options["zonesPrimary"] = zonesPrimary - options["zoneHVAC"] = zoneHVAC + options['zonesPrimary'] = zonesPrimary + options['zoneHVAC'] = zoneHVAC if make_hot_water_plant - options["hot_water_plant"] = hot_water_plant + options['hot_water_plant'] = hot_water_plant end if make_chilled_water_plant - options["chilled_water_plant"] = chilled_water_plant + options['chilled_water_plant'] = chilled_water_plant end - if zoneHVAC.include? "SHP" - options["heat_pump_loop"] = heat_pump_loop + if zoneHVAC.include? 'SHP' + options['heat_pump_loop'] = heat_pump_loop end - if zoneHVAC == "DualDuct" - options["ventilation_schedule"] = building_ventilation_schedule + if zoneHVAC == 'DualDuct' + options['ventilation_schedule'] = building_ventilation_schedule end - if zoneHVAC == "Radiant" - options["radiant_hot_water_plant"] = radiant_hot_water_plant - options["radiant_chilled_water_plant"] = radiant_chilled_water_plant - options["mean_radiant_heating_setpoint_schedule"] = mean_radiant_heating_setpoint_schedule - options["mean_radiant_cooling_setpoint_schedule"] = mean_radiant_cooling_setpoint_schedule + if zoneHVAC == 'Radiant' + options['radiant_hot_water_plant'] = radiant_hot_water_plant + options['radiant_chilled_water_plant'] = radiant_chilled_water_plant + options['mean_radiant_heating_setpoint_schedule'] = mean_radiant_heating_setpoint_schedule + options['mean_radiant_cooling_setpoint_schedule'] = mean_radiant_cooling_setpoint_schedule end - OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options,wshpCoolingEER, wshpHeatingCOP,wshpFanType) + OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options, wshpCoolingEER, wshpHeatingCOP, wshpFanType) ### END CREATE PRIMARY ZONE EQUIPMENT - + # START ADD DCV options = {} - unless zoneHVAC == "DualDuct" - options["primary_airloops"] = primary_airloops + unless zoneHVAC == 'DualDuct' + options['primary_airloops'] = primary_airloops end - options["secondary_airloops"] = secondary_airloops - options["allHVAC"] = allHVAC + options['secondary_airloops'] = secondary_airloops + options['allHVAC'] = allHVAC OsLib_HVAC.addDCV(model, runner, options) # END ADD DCV - - # todo - add in lifecycle costs + + # TODO: - add in lifecycle costs expected_life = 25 years_until_costs_start = 0 costHVAC = costTotalHVACSystem - lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("HVAC System", model.getBuilding, costHVAC, "CostPerEach", "Construction", expected_life, years_until_costs_start).get + lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost('HVAC System', model.getBuilding, costHVAC, 'CostPerEach', 'Construction', expected_life, years_until_costs_start).get # # add AEDG tips # aedgTips = ["HV04","HV10","HV12"] @@ -417,18 +417,16 @@ def run(model, runner, user_arguments) # # populate how to tip messages # aedgTipsLong = OsLib_AedgMeasures.getLongHowToTips("SmMdOff",aedgTips.uniq.sort,runner) # if not aedgTipsLong - # return false # this should only happen if measure writer passes bad values to getLongHowToTips + # return false # this should only happen if measure writer passes bad values to getLongHowToTips # end ### START REPORT FINAL CONDITIONS - OsLib_HVAC.reportConditions(model, runner, "final") + OsLib_HVAC.reportConditions(model, runner, 'final') ### END REPORT FINAL CONDITIONS return true + end # end the run method +end # end the measure - end #end the run method - -end #end the measure - -#this allows the measure to be used by the application -WSHPwithDOASMoreDesignParameters.new.registerWithApplication \ No newline at end of file +# this allows the measure to be used by the application +WSHPwithDOASMoreDesignParameters.new.registerWithApplication diff --git a/lib/openstudio/ee_measures/version.rb b/lib/openstudio/ee_measures/version.rb index 21abc52..1b4bc8d 100644 --- a/lib/openstudio/ee_measures/version.rb +++ b/lib/openstudio/ee_measures/version.rb @@ -37,6 +37,6 @@ module OpenStudio module EeMeasures - VERSION = '0.2.1'.freeze + VERSION = '0.2.1' end end diff --git a/openstudio-ee.gemspec b/openstudio-ee.gemspec index 1d735ab..8957027 100644 --- a/openstudio-ee.gemspec +++ b/openstudio-ee.gemspec @@ -1,3 +1,5 @@ +# frozen_string_literal: true + lib = File.expand_path('lib', __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'openstudio/ee_measures/version' @@ -12,10 +14,10 @@ Gem::Specification.new do |spec| spec.summary = 'Library and measures for OpenStudio for energy efficiency use cases' spec.description = 'Library and measures for OpenStudio for energy efficiency use cases' spec.metadata = { - 'bug_tracker_uri' => 'https://github.com/NREL/openstudio-ee-gem/issues', - 'changelog_uri' => 'https://github.com/NREL/openstudio-ee-gem/blob/develop/CHANGELOG.md', - # 'documentation_uri' => 'https://www.rubydoc.info/gems/openstudio-ee-gem/#{gem.version}', - 'source_code_uri' => "https://github.com/NREL/openstudio-ee-gem/tree/v#{spec.version}" + 'bug_tracker_uri' => 'https://github.com/NREL/openstudio-ee-gem/issues', + 'changelog_uri' => 'https://github.com/NREL/openstudio-ee-gem/blob/develop/CHANGELOG.md', + # 'documentation_uri' => 'https://www.rubydoc.info/gems/openstudio-ee-gem/#{gem.version}', + 'source_code_uri' => "https://github.com/NREL/openstudio-ee-gem/tree/v#{spec.version}" } spec.files = `git ls-files -z`.split("\x0").reject do |f|