# ********************************************************************* # * Copyright (c) 2008-2015, Natural Resources Canada # * All rights reserved. # * # * This library is free software; you can redistribute it and/or # * modify it under the terms of the GNU Lesser General Public # * License as published by the Free Software Foundation; either # * version 2.1 of the License, or (at your option) any later version. # * # * This library is distributed in the hope that it will be useful, # * but WITHOUT ANY WARRANTY; without even the implied warranty of # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # * Lesser General Public License for more details. # * # * You should have received a copy of the GNU Lesser General Public # * License along with this library; if not, write to the Free Software # * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # **********************************************************************/ # To change this template, choose Tools | Templates # and open the template in the editor. require "#{File.dirname(__FILE__)}/btap" class OSMArg ARGUMENT_TYPES = [ "BOOL", "STRING", "INTEGER", "FLOAT", "STRINGCHOICE", "WSCHOICE" ] attr_accessor :runner, :variable_name, :type, :required, :model_dependant, :display_name, :default_value, :min_value, :max_value, :string_choice_array, :os_object_type def self.bool( variable_name,display_name,required,default_value ) raise "#{default_value} defaut value is not a bool." unless default_value.is_a?(Bool) default_value.respond_to?(:to_s) arg = OSMArg.new( "BOOL", variable_name, display_name, required) arg.default_value = default_value return arg end def self.string( variable_name,display_name,required,default_value ) raise "#{default_value} defaut value is not a string." unless default_value.respond_to?(:to_s) arg = OSMArg.new( "STRING", variable_name, display_name, required) arg.default_value = default_value return arg end def self.integer( variable_name,display_name,required,default_value,min_value,max_value ) raise "#{default_value} defaut value is not a integer." unless default_value.respond_to?(:to_i) arg = OSMArg.new( "INTEGER", variable_name, display_name, required) arg.default_value = default_value arg.min_value = min_value arg.max_value = max_value return arg end def self.float( variable_name, display_name, required,default_value,min_value, max_value ) raise "#{default_value} defaut value is not a float." unless default_value.respond_to?(:to_f) arg = OSMArg.new( "INTEGER", variable_name, display_name, required) arg.default_value = default_value arg.min_value = min_value arg.max_value = max_value return arg end def self.choice(variable_name,display_name,required,default_value,string_choice_array) raise "#{default_value} defaut value is not an array." unless default_value.is_a?(Array) arg = OSMArg.new( "STRINGCHOICE", variable_name, display_name, required) arg.default_value = default_value arg.string_choice_array = string_choice_array return arg end def self.wschoice( variable_name, display_name, required, default_value, os_object_type) arg = OSMArg.new( "WSCHOICE", variable_name, display_name, required ) arg.default_value = default_value arg.os_object_type = os_object_type return arg end def initialize( type, variable_name, display_name, required ) self.type = type self.variable_name = variable_name self.display_name = display_name self.required = required self.model_dependant = false if self.type == "WSCHOICE" self.model_dependant = true else self.model_dependant = false end return self end end module BTAP module Measures module OSMeasures class BTAPModelUserScript < OpenStudio::Ruleset::ModelUserScript #if and E+ measure replace OpenStudio::Ruleset::ModelUserScript with OpenStudio::Ruleset::WorkspaceUserScript #Array containing information of all inputs required by measure. attr_accessor :argument_array_of_arrays attr_accessor :argument_array attr_accessor :file #Name of measure #attr_accessor :name #if and E+ measure replace OpenStudio::Ruleset::ModelUserScript with OpenStudio::Ruleset::WorkspaceUserScript def name "BTAPModelUserScript" OSMArgument.new end #this method will output the ruby macro to perform the change. def generate_ruby_macro(model,runner) if @file == nil or @file == "" @file = "Enter_Path_To_#{self.class.name}_measure.rb_File!" end BTAP::runner_register("MACRO", "\##{self.class.name} Measure Start", runner) BTAP::runner_register("MACRO", "require \"#{@file}\"", runner) BTAP::runner_register("MACRO", "argument_values = #{@arg_table}", runner) BTAP::runner_register("MACRO", "#{self.class.name}.new.set_user_arguments_and_apply(model,argument_values,runner)",runner) BTAP::runner_register("MACRO", "\##{self.class.name} Measure End", runner) end def set_user_arguments_and_apply(model,argument_values,runner) message = "Settting Arguments" runner.nil? ? puts(message) : runner.registerInfo(message) #create argument map user_arguments = OpenStudio::Ruleset::OSArgumentMap.new #get argument list arguments = self.arguments(model) #go through each argument arguments.each do |argument| found = false #go through each passed argument_values argument_values.each do |pair| #when a match is found. if argument.name == pair[0] clone_argument = argument.clone unless clone_argument.setValue(pair[1]) message = "Could not set #{argument.name} to #{pair[1]}" runner.nil? ? puts(message) : runner.registerError(message) else message = "Set #{argument.name} to #{pair[1]}" runner.nil? ? puts(message) : runner.registerInfo(message) end user_arguments[pair[0]] = clone_argument #log message message = " Argument set to #{user_arguments}" runner.nil? ? puts(message) : runner.registerInfo(message) end found = true end puts ("Warning: value for argument #{argument.name} not set!.") if found == false end self.run(model, runner, user_arguments) end def run(model, runner, user_arguments) #IF and E+ measure replace model with workspace as the argument #Boilerplate start super(model, runner, user_arguments) BTAP::runner_register("INFO", "Initial model being modified by #{self.class.name}",runner) if not runner.validateUserArguments(self.arguments(model),user_arguments) return false end #Set argument to instance variables. self.argument_getter(model, runner,user_arguments) #will run the childs method measure_code result = self.measure_code(model,runner) generate_ruby_macro(model,runner) return result end # end method run def argument_setter(model,args) #***boilerplate code starts. Do not edit... #iterate through array of hashes and make arguments based on type and set # max and min values where applicable. @argument_array.each do |row| #strip out first char that contains the @ symbol row.variable_name[0] = '' arg = nil case row.type when "BOOL" arg = OpenStudio::Ruleset::OSArgument::makeBoolArgument(row.variable_name,row.required,row.model_dependant) when "STRING" arg = OpenStudio::Ruleset::OSArgument::makeStringArgument(row.variable_name,row.required,row.model_dependant) when "INTEGER" arg = OpenStudio::Ruleset::OSArgument::makeIntegerArgument(row.variable_name,row.required,row.model_dependant) arg.setMaxValue( row.max_value.to_i ) unless row.min_value.nil? arg.setMaxValue( row.max_value.to_i ) unless row.max_value.nil? when "FLOAT" arg = OpenStudio::Ruleset::OSArgument::makeDoubleArgument(row.variable_name,row.required,row.model_dependant) arg.setMaxValue( row.max_value.to_f ) unless row.min_value.nil? arg.setMaxValue( row.max_value.to_f ) unless row.max_value.nil? when "STRINGCHOICE" # #add string choices one by one. chs = OpenStudio::StringVector.new row.string_choice_array.each {|choice| chs << choice} arg = OpenStudio::Ruleset::OSArgument::makeChoiceArgument(row.variable_name, chs,row.required,row.model_dependant) when "PATH" arg = OpenStudio::Ruleset::OSArgument::makePathArgument("alternativeModelPath",true,"osm") when "WSCHOICE" arg = OpenStudio::Ruleset::makeChoiceArgumentOfWorkspaceObjects( row.variable_name, row.os_object_type.to_IddObjectType , model, row.required) end # #common argument aspects. unless arg.nil? arg.setDisplayName(row.display_name) arg.setDefaultValue(row.default_value) unless row.default_value.nil? args << arg end end return args end def argument_getter(model, runner,user_arguments) @arg_table = [] unless @argument_array == nil @argument_array.each do |row| name = row.variable_name case row.type when "BOOL" value = runner.getBoolArgumentValue(name, user_arguments) instance_variable_set("@#{name}",value) @arg_table << [name,value] when "STRING" value = runner.getStringArgumentValue(name, user_arguments) instance_variable_set("@#{name}",value) @arg_table << [name,value] when "INTEGER" value = runner.getIntegerArgumentValue(name, user_arguments) instance_variable_set("@#{name}",value) @arg_table << [name,value] if ( not row.min_value.nil? and instance_variable_get("@#{name}") < row.min_value ) or ( not row.max_value.nil? and instance_variable_get("@#{name}") > row.max_value ) runner.registerError("#{row.display_name} must be greater than or equal to #{row.min_value} and less than or equal to #{row.max_value}. You entered #{instance_variable_get("@#{name}")}.") return false end when "FLOAT" value = runner.getDoubleArgumentValue(name, user_arguments) instance_variable_set("@#{name}",value) @arg_table << [name,value] if ( not row.min_value.nil? and instance_variable_get("@#{name}") < row.min_value ) or ( not row.max_value.nil? and instance_variable_get("@#{name}") > row.max_value ) runner.registerError("#{row.display_name} must be greater than or equal to #{row.min_value} and less than or equal to #{row.max_value}. You entered #{instance_variable_get("@#{name}")}.") return false end when "STRINGCHOICE" @arg_table << [name,runner.getBoolArgumentValue(name, user_arguments)] instance_variable_set("@#{name}", runner.getStringArgumentValue(name, user_arguments) ) when "WSCHOICE" @arg_table << [name,runner.getBoolArgumentValue(name, user_arguments)] instance_variable_set("@#{name}", runner.getOptionalWorkspaceObjectChoiceValue(name, user_arguments,model) ) when "PATH" @arg_table << [name,runner.getBoolArgumentValue(name, user_arguments)] instance_variable_set("@#{name}", runner.getPathArgument(name, user_arguments) ) end #end case end #end do end return @arg_table end end #Measure Template simplified. class TemplateModelMeasure < BTAPModelUserScript def name "BTAPTempModelMeasure" end def arguments(model) #bool @argument_array << OSMArgument.bool(variable_name,display_name,required,default_value) #string @argument_array << OSMArgument.string(variable_name,display_name,required,default_value) #integer @argument_array << OSMArgument.integer(variable_name,display_name,required,default_value,min_value,max_value) #float @argument_array << OSMArgument.float(variable_name,display_name,required,default_value,min_value,max_value) #Choice @argument_array << OSMArgument.choice(variable_name,display_name,required,default_value,string_choice_array) #Workspace choice (using zones as an example) @argument_array << OSMArgument.wschoice(variable_name,display_name,required,default_value,string_choice_array) args = super(model,@argument_array) return args end def run(model, runner, user_arguments) #IF and E+ measure replace model with workspace as the argument #Boilerplate start parent_method_is_true = super(model, runner, user_arguments) #Start measure changes based on model. puts @boolean_argument_name puts @string_argument_name puts @integer_argument_name puts @float_argument_name puts @choice_argument_name puts @ws_choice_argument_name #Do your stuff here! #Here are some logging methods for reference. # runner.registerInitialCondition("Model initial condition (for example number of floors.") # runner.registerInfo("Use this for information to user.") # runner.registerWarning("Use this for warnings to user.") # runner.registerError("Use this for fatal error message to user. Will not continue. Return a false.") ; return false # runner.registerAsNotApplicable("Measure not applicable because XYZ. Return a true and will continue with other chained measures."); return true # runner.registerFinalCondition("Model ended with # of floors for example") # runner.registerFinalCondition("Indicate what was changed.") #If everything went well.. return true ? parent_method_is_true : false end # end method run #For manually running script via an IDE or a command line. #Using the template above as an example..... # argument_values = [ # # ["boolean_argument_name", true ], # ["string_argument_name", "some string" ], # ["integer_argument_name", 1 ], # ["float_argument_name", 0.001 ], # ["choice_argument_name", "choice1" ], # ["ws_choice_argument_name", "zone1" ], # ["path_argument_name", OpenStudio::Path.new(File.dirname(__FILE__))] # ] # def set_user_arguments_and_apply(model,argument_values,runner) self.run(model, runner, super(model,argument_values,runner) ) end end class ArchetypeScan < BTAPModelUserScript def name "BTAPTempModelMeasure" end def arguments(model) #get all osm files in resource folder. osmfiles = OpenStudio::StringVector.new BTAP::FileIO::get_find_files_from_folder_by_extension(File.dirname(__FILE__), ".osm").each {|filename| osmfiles << File.basename(file_name, ",osm")} #list of arguments as they will appear in the interface. They are available in the run command as @variable_name. @argument_array_of_arrays = [ [ "variable_name", "type", "required", "model_dependant", "display_name", "default_value", "min_value", "max_value", "string_choice_array", "os_object_type" ], [ "archetype_name", "STRINGCHOICE", true, false, "archetype_name", osmfiles[0].to_s , nil, nil, osmfiles, nil ], ] args = super(model,@argument_array_of_arrays) return args end def run(model, runner, user_arguments) #run the super parent_method_is_true = super(model, runner, user_arguments) ############### #Set Archetype name in runner. runner.registerValue('archetype_name',@archetype_name) #Set path to OSM files. alternative_model_path = OpenStudio::Path.new("#{File.dirname(__FILE__)}/#{@archetype_name}.osm") #load model and test. translator = OpenStudio::OSVersion::VersionTranslator.new oModel = translator.loadModel(alternative_model_path) if oModel.empty? runner.registerError("Could not load alternative model from '" + alternative_model_path.to_s + "'.") return false end new_model = oModel.get # pull original weather file object over weather_file = new_model.getOptionalWeatherFile if not weather_file.empty? weather_file.get.remove runner.registerInfo("Removed alternate model's weather file object.") end original_weather_file = model.getOptionalWeatherFile if not original_weather_file.empty? original_weather_file.get.clone(new_model) end # pull original design days over new_model.getDesignDays.each { |designDay| designDay.remove } model.getDesignDays.each { |designDay| designDay.clone(new_model) } #swap underlying data in model with underlying data in newModel model.swap(new_model) runner.registerFinalCondition("Model replaced with alternative #{alternative_model_path}.") return true ? parent_method_is_true : false end # end method run #For manually running script via an IDE or a command line script. #Using the template above as an example..... # argument_values = [ # ["archetype_name", "FullServiceRestaurant" ] # ] # def set_user_arguments_and_apply(model,argument_values,runner) self.run(model, runner, super(model,argument_values,runner) ) end end end class CSV_Measures def initialize( csv_file, script_root_folder_path ) @csv_file_path = csv_file @csv_data = nil @script_root_folder_path = script_root_folder_path end # A tiny bit of metacode to assign some instance variables named as above. This will set # the above variable first to nil, then, if present in the csv row data received, the actual construction data values. # So we should after this loop access @ext_wall_rsi for example. If the variable is not present in the row. It will default the value to zero. # It should automatically make floats and strings accordingly. def set_instance_variables(measure_values) measure_values.each do |variable| instance_variable_set("@#{variable}", nil ) instance_variable_set("@#{variable}", @csv_data[ variable ] ) unless ( (@csv_data.nil? == true ) or (@csv_data.has_key?(variable) == false) or (@csv_data[variable].to_s.strip.downcase == "na")) end end def are_all_instance_variables_nil?(measure_values) value = true measure_values.each do |variable| value = false unless instance_variable_get("@#{variable}").nil? end return value end end class CSV_OS_Measures < CSV_Measures #loading methods def side_load_base_model_building( model ) log_message = "" measure_values =["base_model_rel_path"] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) puts osm_model_full_path = "#{@script_root_folder_path}/#{@base_model_rel_path}" newModel = BTAP::FileIO::load_osm(osm_model_full_path,"-") model.swap(newModel) log_message << "\nModel replaced with alternative model #{osm_model_full_path}.\n" end def load_base_model_building() log_message = "" measure_values =[ "base_model_rel_path" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) osm_model_full_path = "#{@script_root_folder_path}/#{@base_model_rel_path}" model = BTAP::FileIO::load_osm(osm_model_full_path,"-") log_message << "\nModel rloaded #{osm_model_full_path}.\n" return model end def set_weather_file(model) measure_values =["weather_file_rel_path"] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) BTAP::Site::set_weather_file(model,"#{@script_root_folder_path}/#{@weather_file_rel_path}") unless @weather_file_rel_path.nil? return "Set weather file to #{@weather_file_rel_path}.\n" end def set_hourly_output(model) #create array of output variables strings from E+ output_variable_array = [ "Facility Total Electric Demand Power", "Water Heater Gas Rate", "Plant Supply Side Heating Demand Rate", "Heating Coil Gas Rate", "Cooling Coil Electric Power", "Boiler Gas Rate", "Heating Coil Air Heating Rate", "Heating Coil Electric Power", "Cooling Coil Total Cooling Rate", "Water Heater Heating Rate", # "Facility Total HVAC Electric Demand Power", # "Facility Total Electric Demand Power", "Zone Air Temperature", "Water Heater Electric Power" # "Baseboard Air Inlet Temperature", # "Baseboard Air Outlet Temperature", # "Baseboard Water Inlet Temperature", # "Baseboard Water Outlet Temperature", # "Boiler Inlet Temperature", # "Boiler Outlet Temperature", # "Plant Supply Side Inlet Temperature", # "Plant Supply Side Outlet Temperature", # "People Radiant Heating Rate", # "People Sensible Heating Rate", # "People Latent Gain Rate", # "People Total Heating Rate", # "Lights Total Heating Rate", # "Electric Equipment Total Heating Rate", # "Other Equipment Total Heating Rate", # "District Heating Hot Water Rate", # "District Heating Rate", # "Air System Outdoor Air Flow Fraction", # "Air System Outdoor Air Minimum Flow Fraction", # "Air System Fan Electric Energy" ] BTAP::Reports::set_output_variables(model,"Hourly", output_variable_array) return "added output variables ..." << output_variable_array.to_s << "\n" end #Helper methods def create_cold_lake_vintages(output_folder = nil) # check if only a single vintage was requested or a full set. baseline_models = Hash.new() prototype_models = Hash.new() puts "Creating Baseline models" CSV.foreach( @csv_file_path, :headers => true, :converters => :all ) do |row| @csv_data = row unless @csv_data["measure_id"] == "NA" model = self.load_base_model_building() self.set_weather_file(model) self.set_hourly_output(model) model,log = self.apply_ecms(model,@csv_data) BTAP::FileIO::save_osm( model, "#{output_folder}/#{BTAP::FileIO::get_name(model)}.osm") unless output_folder.nil? File.open("#{output_folder}/#{BTAP::FileIO::get_name(model)}.log", 'w') { |file| file.write(log) } unless output_folder.nil? baseline_models[BTAP::FileIO::get_name(model)] = model end end #create ECM models. puts "Creating ECM models" counter = 0 baseline_models.each do |name,model| #Scan folder and get the ecm csv files. ecm_csv_files = Dir.glob( "#{@script_root_folder_path}/**/ecm_*.csv" ) #iterate through each csv file. ecm_csv_files.each do |ecm_csv_file| puts "evaluating #{ecm_csv_file}" # iterate through each row CSV.foreach( ecm_csv_file, :headers => true, :converters => :all ) do |row| # If row baseline matches current baseline name then if name == "#{row["building_type"]}~#{row["vintage_name"]}~baseline" #Skip row if measure_id is NA counter = counter + 1 if row["measure_id"].nil? or row["measure_id"].upcase.strip == "NA" or row["measure_id"].upcase.strip == "" else new_model = BTAP::FileIO::deep_copy(model) new_model,log = self.apply_ecms(new_model,row) BTAP::FileIO::save_osm( new_model, "#{output_folder}/#{BTAP::FileIO::get_name(new_model)}.osm") unless output_folder.nil? File.open("#{output_folder}/#{BTAP::FileIO::get_name(new_model)}.log", 'w') { |file| file.write(log) } unless output_folder.nil? end end end end end puts "ECM generation completed." end def apply_ecms(model,row_data) log = "" @csv_data = row_data self.methods.select{ |i| i[/^ecm_.*$/] }.each do |ecm_method_name| log << "**********#{ecm_method_name}\n" raise ("model is nil") if model.nil? raise ("name is nil") if ecm_method_name.nil? log << self.method(ecm_method_name).call(model) end return model,log end #ecms def ecm_capital_costs(model) log = "" measure_values = [ "measure_id", "cost_per_floor_m2", "cost_per_building" ] self.set_instance_variables( measure_values ) #cost per building and building area building = model.building.get raise ("you did not enter a cost for measure #{@measure_id}. All measures must have a cost of at least 0.0 . Please add a cost_per_building field.") if @cost_per_building.nil? unless @cost_per_building.nil? BTAP::Resources::Economics::object_cost(building,"#{@measure_id} Capital Cost per building",@cost_per_building.to_f,"CostPerEach") log << "added cost of #{@measure_id} per building for #{@measure_id}" puts log end return log end def ecm_id(model) log = "" measure_values = [ "building_type", "vintage_name", "measure_id" ] self.set_instance_variables( measure_values ) BTAP::FileIO::set_name(model,"#{@building_type}~#{@vintage_name}~#{@measure_id}") puts BTAP::FileIO::get_name(model) return "Changed name to #{BTAP::FileIO::get_name(model)}" end def ecm_envelope( model ) log = "" #List of variables required by this measure that are to be extracted from CSV row. measure_values = [ "library_file", "default_construction_set_name", "ext_wall_rsi", "ext_floor_rsi", "ext_roof_rsi", "ground_wall_rsi", "ground_floor_rsi", "ground_roof_rsi", "fixed_window_rsi", "fixed_wind_solar_trans", "fixed_wind_vis_trans", "operable_window_rsi", "operable_wind_solar_trans", "operable_wind_vis_trans", "door_construction_rsi", "glass_door_rsi", "glass_door_solar_trans", "glass_door_vis_trans", "overhead_door_rsi", "skylight_rsi", "skylight_solar_trans", "skylight_vis_trans", "tubular_daylight_dome_rsi", "tubular_daylight_dome_solar_trans", "tubular_daylight_dome_vis_trans", "tubular_daylight_diffuser_rsi", "tubular_daylight_diffuser_solar_trans", "tubular_daylight_diffuser_vis_trans", "ext_wall_cost_m3", "ext_floor_cost_m3", "ext_roof_cost_m3", "ground_wall_cost_m3", "ground_floor_cost_m3", "ground_roof_cost_m3", "fixed_window_cost_m3", "operable_window_cost_m3", "door_construction_cost_m3", "glass_door_cost_m3", "overhead_door_cost_m3", "skylight_cost_m3", "tubular_daylight_dome_cost_m3", "tubular_daylight_diffuser_cost_m3", "total_building_construction_set_cost" ] self.set_instance_variables(measure_values) unless @default_construction_set_name.nil? or @library_file.nil? # #Remove all existing constructions from model. BTAP::Resources::Envelope::remove_all_envelope_information( model ) # #Load Contruction osm library. construction_lib = BTAP::FileIO::load_osm("#{@script_root_folder_path}/#{@library_file}") #Get construction set.. I/O expensive so doing it here. vintage_construction_set = construction_lib.getDefaultConstructionSetByName(@default_construction_set_name) if vintage_construction_set.empty? raise("#{@default_construction_set} does not exist in #{@script_root_folder_path}/#{@library_file} library ") else vintage_construction_set = construction_lib.getDefaultConstructionSetByName(@default_construction_set_name).get end new_construction_set =vintage_construction_set.clone(model).to_DefaultConstructionSet.get #Set conductances to needed values in construction set if possible. BTAP::Resources::Envelope::ConstructionSets::customize_default_surface_construction_set_rsi!( model, "#{@default_construction_set}-modified",new_construction_set, @ext_wall_rsi, @ext_floor_rsi, @ext_roof_rsi, @ground_wall_rsi, @ground_floor_rsi, @ground_roof_rsi, @fixed_window_rsi, @fixed_wind_solar_trans, @fixed_wind_vis_trans, @operable_window_rsi, @operable_wind_solar_trans, @operable_wind_vis_trans, @door_construction_rsi, @glass_door_rsi, @glass_door_solar_trans, @glass_door_vis_trans, @overhead_door_rsi, @skylight_rsi, @skylight_solar_trans, @skylight_vis_trans, @tubular_daylight_dome_rsi, @tubular_daylight_dome_solar_trans, @tubular_daylight_dome_vis_trans, @tubular_daylight_diffuser_rsi, @tubular_daylight_diffuser_solar_trans, @tubular_daylight_diffuser_vis_trans ) #Set as default to model. model.building.get.setDefaultConstructionSet( new_construction_set ) #Set cost information. BTAP::Resources::Envelope::ConstructionSets::customize_default_surface_construction_set_costs(new_construction_set, @ext_wall_cost_m2, @ext_floor_cost_m2, @ext_roof_cost_m2, @ground_wall_cost_m2, @ground_floor_cost_m2, @ground_roof_cost_m2, @fixed_window_cost_m2, @operable_window_cost_m2, @door_construction_cost_m2, @glass_door_cost_m2, @overhead_door_cost_m2, @skylight_cost_m2, @tubular_daylight_dome_cost_m2, @tubular_daylight_diffuser_cost_m2, @total_building_construction_set_cost ) #Give adiabatic surfaces a construction. Does not matter what. This is a bug in Openstudio that leave these surfaces unassigned by the default construction set. all_adiabatic_surfaces = BTAP::Geometry::Surfaces::filter_by_boundary_condition(model.getSurfaces, "Adiabatic") unless all_adiabatic_surfaces.empty? BTAP::Geometry::Surfaces::set_surfaces_construction( all_adiabatic_surfaces, model.building.get.defaultConstructionSet.get.defaultInteriorSurfaceConstructions.get.wallConstruction.get) end #Create sample csv file. CSV.open("#{@script_root_folder_path}/sample_envelope_ecm.csv", 'w') { |csv| csv << measure_values.unshift("measure_id") } return BTAP::Resources::Envelope::ConstructionSets::get_construction_set_info( new_construction_set ) end return "Constructions were unchanged.\n" end def ecm_infiltration( model ) measure_values = [ "infiltration_design_flow_rate", "infiltration_flow_per_space", "infiltration_flow_per_exterior_area", "infiltration_air_changes_per_hour" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) log = BTAP::Resources::SpaceLoads::ScaleLoads::set_inflitration_magnitude( model, @infiltration_design_flow_rate, @infiltration_flow_per_space, @infiltration_flow_per_exterior_area, @infiltration_air_changes_per_hour ) return log end def ecm_fans( model ) measure_values = [ "fan_total_eff", "fan_motor_eff", "fan_volume_type" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) log = "" unless model.getFanVariableVolumes.empty? log = "fan_variable_volume_name,fan_total_eff,fan_motor_eff\n" model.getFanVariableVolumes.each do |fan| fan.setFanEfficiency( @fan_total_eff ) unless @fan_total_eff.nil? fan.setMotorEfficiency( @fan_motor_eff ) unless @fan_motor_eff.nil? log << fan.getAttribute("name").get.valueAsString << ",#{fan.fanEfficiency},#{fan.motorEfficiency}\n" end end unless model.getFanConstantVolumes.empty? log = "fan_constant_volume_name,fan_total_eff,fan_motor_eff\n" model.getFanConstantVolumes.each do |fan| fan.setFanEfficiency( @fan_total_eff ) unless @fan_total_eff.nil? fan.setMotorEfficiency( @fan_motor_eff ) unless @fan_motor_eff.nil? log << fan.getAttribute("name").get.valueAsString << ",#{fan.fanEfficiency},#{fan.motorEfficiency}\n" end end case @fan_volume_type when "VariableVolume" model.getFanConstantVolumes.each do |fan_const| #check that this is indeed connected to an airloop. log << "Found Const Vol Fan #{fan_const.getAttribute("name").get.valueAsString}" unless fan_const.loop.empty? fan_variable = OpenStudio::Model::FanVariableVolume.new(model,fan_const.availabilitySchedule) #pass information from old fan as much as possible. fan_variable.setFanEfficiency(fan_const.fanEfficiency) fan_variable.setPressureRise( fan_const.pressureRise() ) fan_variable.autosizeMaximumFlowRate fan_variable.setFanPowerMinimumFlowRateInputMethod("FixedFlowRate") fan_variable.setFanPowerMinimumFlowFraction(0.25) fan_variable.setMotorInAirstreamFraction( fan_const.motorInAirstreamFraction() ) fan_variable.setFanPowerCoefficient1(0.35071223) fan_variable.setFanPowerCoefficient2(0.30850535) fan_variable.setFanPowerCoefficient3(-0.54137364) fan_variable.setFanPowerCoefficient4(0.87198823) #get the airloop. air_loop = fan_const.loop.get #add the FanVariableVolume fan_variable.addToNode(air_loop.supplyOutletNode()) #Remove FanConstantVolume fan_const.remove() log << "Replaced by Variable Vol Fan #{fan_variable.getAttribute("name").get.valueAsString}" end end when "ConstantVolume" model.getFanVariableVolumes.each do |fan| #check that this is indeed connected to an airloop. log << "Found Const Vol Fan #{fan.getAttribute("name").get.valueAsString}" unless fan.loop.empty? new_fan = OpenStudio::Model::FanConstantVolume.new(model,fan.availabilitySchedule) #pass information from constant speed fan as much as possible. new_fan.setFanEfficiency(fan.fanEfficiency) new_fan.setPressureRise( fan.pressureRise() ) new_fan.setMotorEfficiency(fan.motorEfficiency) new_fan.setMotorInAirstreamFraction( fan.motorInAirstreamFraction() ) new_fan.autosizeMaximumFlowRate #get the airloop. air_loop = fan.loop.get #add the FanVariableVolume new_fan.addToNode(air_loop.supplyOutletNode()) #Remove FanConstantVolume fan.remove() log << "Replaced by Constant Vol Fan #{new_fan.getAttribute("name").get.valueAsString}" end end when nil log << "No changes to Fan." else raise("fan_volume_type should be ConstantVolume or VariableVolume") end return log end def ecm_pumps( model ) measure_values = [ "pump_motor_eff", "pump_control_type", "pump_speed_type" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) log = "" unless model.getPumpVariableSpeeds.empty? log = "pump_variable_speed_name,@pump_motor_eff\n" model.getPumpVariableSpeeds.each do |pump| pump.setMotorEfficiency( @pump_motor_eff.to_f ) unless @pump_motor_eff.nil? pump.setPumpControlType( @pump_control_type ) unless @pump_control_type.nil? log << pump.getAttribute("name").get.valueAsString << ",#{pump.motorEfficiency}\n" end end unless model.getPumpConstantSpeeds.empty? log << "pump_variable_speed_name,@pump_motor_eff\n" model.getPumpConstantSpeeds.each do |pump| pump.setMotorEfficiency( @pump_motor_eff.to_f ) unless @pump_motor_eff.nil? pump.setPumpControlType( @pump_control_type ) unless @pump_control_type.nil? log << pump.getAttribute("name").get.valueAsString << ",#{pump.motorEfficiency}\n" end end #set pump speed type based on existing pump. case @pump_speed_type when "VariableSpeed" model.getPumpConstantSpeeds.each do |pump_const| log << "Found Const Vol Fan #{pump_const.getAttribute("name").get.valueAsString}" #check that this is indeed connected to an plant loop. unless pump_const.plantLoop.empty? pump_variable = OpenStudio::Model::PumpVariableSpeed.new(model) #pass information from constant speed fan as much as possible. pump_variable.setRatedFlowRate(pump_const.getRatedFlowRate.get) pump_variable.setRatedPumpHead(pump_const.ratedPumpHead()) pump_variable.setRatedPowerConsumption(pump_const.ratedPowerConsumption.to_f) pump_variable.setMotorEfficiency(pump_const.motorEfficiency().to_f) pump_variable.setPumpControlType( pump_const.pumpControlType ) pump_variable.setFractionofMotorInefficienciestoFluidStream(pump_const.fractionofMotorInefficienciestoFluidStream().to_f) pump_variable.autosizeRatedFlowRate if pump_const.isRatedFlowRateAutosized pump_variable.autosizeRatedPowerConsumption if pump_const.isRatedPowerConsumptionAutosized #get the hot water loop. hw_loop = pump_const.plantLoop.get #Remove PumpConstantSpeed pump_const.remove() #add pump_variable.addToNode(hw_loop.supplyInletNode) log << "Replaced by Variable Vol Pump #{pump_variable.getAttribute("name").get.valueAsString}" end end #end loop PumpConstantSpeeds when "ConstantSpeed" model.getPumpVariableSpeeds.each do |pump| log << "Found Variable Speed Pump #{pump.getAttribute("name").get.valueAsString}" #check that this is indeed connected to an plant loop. unless pump.plantLoop.empty? new_pump = OpenStudio::Model::PumpVariableSpeed.new(model) #pass information from constant speed fan as much as possible. new_pump.setRatedFlowRate(pump.getRatedFlowRate.get) new_pump.setRatedPumpHead(pump.ratedPumpHead()) new_pump.setRatedPowerConsumption(pump.ratedPowerConsumption.to_f) new_pump.setMotorEfficiency(pump.motorEfficiency().to_f) new_pump.setFractionofMotorInefficienciestoFluidStream(pump.fractionofMotorInefficienciestoFluidStream().to_f) new_pump.setPumpControlType( pump.pumpControlType ) new_pump.autosizeRatedFlowRate if pump.isRatedFlowRateAutosized new_pump.autosizeRatedPowerConsumption if pump.isRatedPowerConsumptionAutosized #get the hot water loop. hw_loop = pump.plantLoop.get #Remove PumpVariableSpeed pump.remove() #add the pump to loop. new_pump.addToNode(hw_loop.supplyInletNode) log << "Replaced by constant speed Pump #{new_pump.getAttribute("name").get.valueAsString}" end end #end loop Pump variable Speeds when nil log << "No changes" else raise( "pump_speed_type field is not ConstantSpeed or VariableSpeed" ) end #Create sample csv file. CSV.open("#{@script_root_folder_path}/sample_pump_eff_ecm.csv", 'w') { |csv| csv << measure_values.unshift("measure_id") } return log end def ecm_cooling_cop( model ) log = "" measure_values =[ "cop" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) unless model.getCoilCoolingDXSingleSpeeds.empty? log = "coil_cooling_dx_single_speed_name,cop\n" model.getCoilCoolingDXSingleSpeeds.each do |cooling_coil| cooling_coil.setRatedCOP( OpenStudio::OptionalDouble.new( @cop ) ) unless @cop.nil? cop = "NA" cop = cooling_coil.ratedCOP.get unless cooling_coil.ratedCOP.empty? log << cooling_coil.getAttribute("name").get.valueAsString << ",#{cop}\n" end end unless model.getCoilCoolingDXTwoSpeeds.empty? log << "coil_cooling_dx_two_speed_name,cop\n" model.getCoilCoolingDXTwoSpeeds.each do |cooling_coil| cooling_coil.setRatedHighSpeedCOP( @cop ) unless @cop.nil? cooling_coil.setRatedLowSpeedCOP( @cop ) unless @cop.nil? cop_high = "NA" cop_high = cooling_coil.ratedHighSpeedCOP.get unless cooling_coil.ratedHighSpeedCOP.empty? cop_low = "NA" cop_low = cooling_coil.ratedLowSpeedCOP.get unless cooling_coil.ratedLowSpeedCOP.empty? log << cooling_coil.getAttribute("name").get.valueAsString << ",#{cop_high},#{cop_low}\n" end end return log end def ecm_economizers( model ) measure_values =[ "economizer_control_type", "economizer_control_action_type", "economizer_maximum_limit_dry_bulb_temperature", "economizer_maximum_limit_enthalpy", "economizer_maximum_limit_dewpoint_temperature", "economizer_minimum_limit_dry_bulb_temperature" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) log = "" unless @economizer_control_type.nil? log << BTAP::Resources::HVAC::enable_economizer( model, @economizer_control_type, @economizer_control_action_type, @economizer_maximum_limit_dry_bulb_temperature, @economizer_maximum_limit_enthalpy, @economizer_maximum_limit_dewpoint_temperature, @economizer_minimum_limit_dry_bulb_temperature ) end return log end def ecm_sizing( model) measure_values =[ "heating_sizing_factor", "cooling_sizing_factor", "zone_heating_sizing_factor", "zone_cooling_sizing_factor" ] table = "*Sizing Factor Measure*" #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) table = "handle,heating_sizing_factor,cooling_sizing_factor\n" #Sizing Parameters model.getSizingParameters.setHeatingSizingFactor(@heating_sizing_factor) unless @heating_sizing_factor.nil? model.getSizingParameters.setCoolingSizingFactor(@cooling_sizing_factor) unless @cooling_sizing_factor.nil? #SizingZone table << "handle,zone_heating_sizing_factor,zone_cooling_sizing_factor\n" model.getSizingZones.each do |item| item.setZoneHeatingSizingFactor(@zone_heating_sizing_factor) unless @zone_heating_sizing_factor.nil? item.setZoneCoolingSizingFactor(@zone_cooling_sizing_factor) unless @zone_cooling_sizing_factor.nil? table << "#{item.handle},#{item.zoneHeatingSizingFactor.get},#{item.zoneCoolingSizingFactor.get}\n" end #Create sample csv file. CSV.open("#{@script_root_folder_path}/sample_sizing_param_ecm.csv", 'w') { |csv| csv << measure_values.unshift("measure_id") } return table end def ecm_dhw( model ) log = "shw_setpoint_sched,shw_heater_fuel_type,shw_thermal_eff\n" measure_values =[ "shw_setpoint_sched_name", "shw_heater_fuel_type", "shw_thermal_eff" ] log = "*SHW Measures*\n" #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) #Create Schedule #schedule = BTAP::Resources::Schedules::create_annual_ruleset_schedule_detailed_json(model, @shw_setpoint_sched) unless @shw_setpoint_sched_name.nil? or @shw_setpoint_sched.nil? #iterate through water heaters. model.getWaterHeaterMixeds.each do |item| unless @shw_setpoint_sched_name.nil? or @shw_setpoint_sched.nil? item.setSetpointTemperatureSchedule(schedule) end item.setHeaterFuelType(@shw_heater_fuel_type) unless @shw_heater_fuel_type.nil? item.setHeaterThermalEfficiency(@shw_thermal_eff) unless @shw_thermal_eff.nil? log << item.getAttribute("name").get.valueAsString << ",#{item.setpointTemperatureSchedule},#{item.heaterFuelType},#{item.getHeaterThermalEfficiency.get}\n" end return log end def ecm_hotwater_boilers( model ) measure_values = [ "hw_boiler_design_water_outlet_temperature", "hw_boiler_fuel_type", "hw_boiler_thermal_eff", "hw_boiler_curve", "hw_boiler_flow_mode",# "hw_boiler_eff_curve_temp_eval_var",# "hw_boiler_reset_highsupplytemp" , "hw_boiler_reset_outsidehighsupplytemp" , "hw_boiler_reset_lowsupplytemp" , "hw_boiler_reset_outsidelowsupplytemp" , ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) table = "name,boiler_design_water_outlet_temperature,boiler_fuel_type,boiler_thermal_eff\n" model.getPlantLoops.each do |iplantloop| iplantloop.components.each do |icomponent| if icomponent.to_BoilerHotWater.is_initialized boiler = icomponent.to_BoilerHotWater.get #set design outlet temp boiler.setDesignWaterOutletTemperature(@hw_boiler_design_water_outlet_temperature) unless @hw_boiler_design_water_outlet_temperature.nil? #set fuel type boiler.setFuelType(@hw_boiler_fuel_type) unless @hw_boiler_fuel_type.nil? #set thermal eff boiler.setNominalThermalEfficiency(@hw_boiler_thermal_eff) unless @hw_boiler_thermal_eff.nil? #set boiler flow mode unless @hw_boiler_flow_mode.nil? ["ConstantFlow","LeavingSetpointModulated","NotModulated"].include?(@hw_boiler_flow_mode) ? boiler.setBoilerFlowMode(@hw_boiler_flow_mode) : raise("Boiler flow mode #{@hw_boiler_flow_mode} invalid.") end #set setDesignWaterOutletTemperature boiler.setDesignWaterOutletTemperature(@hotwaterboiler_reset_highsupplytemp) unless @hotwaterboiler_reset_highsupplytemp.nil? #set EfficiencyCurveTemperatureEvaluationVariable unless @hw_boiler_eff_curve_temp_eval_var.nil? ["LeavingBoiler","EnteringBoiler"].include?(@hw_boiler_eff_curve_temp_eval_var) ? boiler.setEfficiencyCurveTemperatureEvaluationVariable(@hw_boiler_eff_curve_temp_eval_var) : raise("EfficiencyCurveTemperatureEvaluationVariable #{@hw_boiler_eff_curve_temp_eval_var} invalid.") end #Set boiler curve curve = boiler.normalizedBoilerEfficiencyCurve if not @hw_boiler_curve.nil? and curve.is_initialized and curve.get.to_CurveBiquadratic.is_initialized case @hw_boiler_curve.downcase when "atmospheric" biqcurve = curve.get.to_CurveBiquadratic.get biqcurve.setCoefficient1Constant(1.057059) biqcurve.setCoefficient1Constant(1.057059) biqcurve.setCoefficient2x(-0.0774177) biqcurve.setCoefficient3xPOW2(0.07875142) biqcurve.setCoefficient4y(0.0003943856) biqcurve.setCoefficient5yPOW2(-0.000004074629) biqcurve.setCoefficient6xTIMESY(-0.002202606) biqcurve.setMinimumValueofx(0.3) biqcurve.setMaximumValueofx(1.0) biqcurve.setMinimumValueofy(40.0) biqcurve.setMaximumValueofy(90.0) biqcurve.setMinimumCurveOutput(0.0) biqcurve.setMaximumCurveOutput(1.1) biqcurve.setInputUnitTypeforX("Dimensionless") biqcurve.setInputUnitTypeforY("Temperature") biqcurve.setOutputUnitType("Dimensionless") when "condensing" biqcurve = curve.get.to_CurveBiquadratic.get biqcurve.setCoefficient1Constant(0.4873) biqcurve.setCoefficient2x(1.1322) biqcurve.setCoefficient3xPOW2(-0.6425) biqcurve.setCoefficient4y(0.0) biqcurve.setCoefficient5yPOW2(0.0) biqcurve.setCoefficient6xTIMESY(0.0) biqcurve.setMinimumValueofx(0.1) biqcurve.setMaximumValueofx(1.0) biqcurve.setMinimumValueofy(0.0) biqcurve.setMaximumValueofy(0.0) biqcurve.setMinimumCurveOutput(0.0) biqcurve.setMaximumCurveOutput(1.0) biqcurve.setInputUnitTypeforX("Dimensionless") biqcurve.setInputUnitTypeforY("Temperature") biqcurve.setOutputUnitType("Dimensionless") else raise("#{@hotwaterboiler_curve} is not a valid boiler curve name (condensing_boiler_curve,atmospheric_boiler_curve") end end #boiler reset setpoint manager unless @hotwaterboiler_reset_lowsupplytemp.nil? and @hotwaterboiler_reset_outsidelowsupplytemp.nil? and @hotwaterboiler_reset_highsupplytemp.nil? and @hotwaterboiler_reset_outsidehighsupplytemp.nil? #check if setpoint manager is present at supply outlet #Find any setpoint manager if it exists and outlet node and remove it. iplantloop.supplyOutletNode.setpointManagers.each {|sm| sm.disconnect} #Add new setpoint manager oar_stpt_manager = OpenStudio::Model::SetpointManagerOutdoorAirReset.new(model) oar_stpt_manager.addToNode(iplantloop.supplyOutletNode) oar_stpt_manager.setSetpointatOutdoorHighTemperature(@hw_boiler_reset_lowsupplytemp) unless @hw_boiler_reset_lowsupplytemp.nil? oar_stpt_manager.setOutdoorHighTemperature(@hotwaterboiler_reset_outsidelowsupplytemp) unless @hw_boiler_reset_outsidelowsupplytemp.nil? oar_stpt_manager.setSetpointatOutdoorLowTemperature(@hw_boiler_reset_highsupplytemp) unless @hw_boiler_reset_highsupplytemp.nil? oar_stpt_manager.setOutdoorLowTemperature(@hw_boiler_reset_outsidehighsupplytemp) unless @hw_boiler_reset_outsidehighsupplytemp.nil? end table << boiler.getAttribute("name").get.valueAsString << "," boiler.designWaterOutletTemperature.empty? ? dowt = "NA" : dowt = boiler.designWaterOutletTemperature.get table << "#{dowt},#{boiler.fuelType},#{boiler.nominalThermalEfficiency}\n" end end end #end boilers loop return table end def ecm_dcv( model ) log = "" measure_values =[ "dcv_enabled" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) unless @dcv_enabled.nil? log = BTAP::Resources::HVAC::enable_demand_control_ventilation(model,@dcv_enabled.to_bool) end return log end def ecm_heating_cooling_setpoints(model) log = "" measure_values =[ "library_file", "heating_schedule_name", "cooling_schedule_name" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) library_file = @library_file heating_schedule_name = @heating_schedule_name cooling_schedule_name = @cooling_schedule_name unless @heating_schedule_name.nil? and @cooling_schedule_name.nil? #Load Contruction osm library. lib = BTAP::FileIO::load_osm("#{@script_root_folder_path}/#{library_file}") unless heating_schedule_name.nil? #Get heating schedule from library and clone it. heating_schedule = lib.getScheduleRulesetByName(heating_schedule_name) if heating_schedule.empty? raise("#{heating_schedule_name} does not exist in #{library_file} library ") else heating_schedule = lib.getScheduleRulesetByName(heating_schedule_name).get.clone(model).to_ScheduleRuleset.get end end unless cooling_schedule_name.nil? #Get cooling schedule from library and clone it. cooling_schedule = lib.getScheduleRulesetByName(cooling_schedule_name) if cooling_schedule.empty? raise("#{cooling_schedule_name} does not exist in #{library_file} library ") else cooling_schedule = lib.getScheduleRulesetByName(cooling_schedule_name).get.clone(model).to_ScheduleRuleset.get end end model.getThermostatSetpointDualSetpoints.each do |dual_setpoint| unless heating_schedule_name.nil? raise ("Could not set heating Schedule") unless dual_setpoint.setHeatingSetpointTemperatureSchedule(heating_schedule) end unless cooling_schedule_name.nil? raise ("Could not set cooling Schedule") unless dual_setpoint.setCoolingSetpointTemperatureSchedule(cooling_schedule) end end end return log end def ecm_erv( model ) log = "" measure_values =[ "erv_enabled", "erv_autosizeNominalSupplyAirFlowRate", "erv_NominalSupplyAirFlowRate", "erv_HeatExchangerType", "erv_SensibleEffectivenessat100CoolingAirFlow", "erv_SensibleEffectivenessat75CoolingAirFlow", "erv_LatentEffectiveness100Cooling", "erv_LatentEffectiveness75Cooling", "erv_SensibleEffectiveness100Heating", "erv_SensibleEffectiveness75Heating", "erv_LatentEffectiveness100Heating", "erv_LatentEffectiveness75Heating", "erv_SupplyAirOutletTemperatureControl", "erv_setFrostControlType", "erv_ThresholdTemperature", "erv_InitialDefrostTimeFraction", "erv_nominal_electric_power", "erv_economizer_lockout" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) unless @erv_enabled.nil? or @erv_enabled.to_bool == false BTAP::Resources::HVAC::enable_erv( model, @erv_autosizeNominalSupplyAirFlowRate, @erv_NominalSupplyAirFlowRate, @erv_HeatExchangerType, @erv_SensibleEffectivenessat100CoolingAirFlow, @erv_SensibleEffectivenessat75CoolingAirFlow, @erv_LatentEffectiveness100Cooling, @erv_LatentEffectiveness75Cooling, @erv_SensibleEffectiveness100Heating, @erv_SensibleEffectiveness75Heating, @erv_LatentEffectiveness100Heating, @erv_LatentEffectiveness75Heating, @erv_SupplyAirOutletTemperatureControl.to_bool, @erv_setFrostControlType, @erv_ThresholdTemperature, @erv_InitialDefrostTimeFraction, @erv_nominal_electric_power, @erv_economizer_lockout.to_bool ).each { |erv| log << erv.to_s } #Add setpoint manager to all OA object in airloops. model.getHeatExchangerAirToAirSensibleAndLatents.each do |erv| #needed to get the supply outlet node from the erv to place the setpoint manager. node = erv.primaryAirOutletModelObject.get.to_Node.get if erv.primaryAirOutletModelObject.is_initialized new_set_point_manager = OpenStudio::Model::SetpointManagerWarmest.new(model) raise ("Could not add setpoint manager") unless new_set_point_manager.addToNode(node) log << "added warmest control to node #{node}" new_set_point_manager.setMaximumSetpointTemperature(16.0) new_set_point_manager.setMinimumSetpointTemperature(5.0) new_set_point_manager.setStrategy("MaximumTemperature") new_set_point_manager.setControlVariable("Temperature") end log << "ERV have been modified.\n" else log << "ERV not changed." end return log end def ecm_exhaust_fans( model ) log = "" #Exhaust ECM measure_values =[ "exhaust_fans_occ_control_enabled" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) unless @exhaust_fans_occ_control_enabled.nil? or @exhaust_fans_occ_control_enabled.to_bool == false fans = BTAP::Resources::Schedules::set_exhaust_fans_availability_to_building_default_occ_schedule(model) fans.each { |fan| log << fan.to_s} else log << "No changes to exhaust fans." end return log end def ecm_lighting( model ) log = "" #Lighting ECM measure_values =[ "lighting_scaling_factor", "lighting_fraction_radiant", "lighting_fraction_visible", "lighting_return_air_fraction" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) BTAP::Resources::SpaceLoads::ScaleLoads::scale_lighting_loads( model, @lighting_scaling_factor ) unless @lighting_scaling_factor.nil? #Set lighting variables model.getLightsDefinitions.each do |lightsdef| lightsdef.setFractionRadiant(@lighting_fraction_radiant.to_f) lightsdef.setFractionVisible(@lighting_fraction_visible.to_f) lightsdef.setReturnAirFraction(@lighting_return_air_fraction.to_f) end return log end def ecm_plugs( model ) log = "" #Plug loads ECM measure_values = [ "elec_equipment_scaling_factor", "elec_equipment_fraction_radiant", "elec_equipment_fraction_latent", "elec_equipment_fraction_lost" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) BTAP::Resources::SpaceLoads::ScaleLoads::scale_electrical_loads( model, @elec_equipment_scaling_factor) unless @elec_equipment_scaling_factor.nil? #Set plug loads variables model.getElectricEquipmentDefinitions.each do |elec_equip_def| elec_equip_def.setFractionRadiant(@elec_equipment_fraction_radiant.to_f) elec_equip_def.setFractionLatent(@elec_equipment_fraction_latent.to_f) elec_equip_def.setFractionLost(@elec_equipment_fraction_lost.to_f) end CSV.open("#{@script_root_folder_path}/sample_scale_plug_loads_ecm.csv", 'w') { |csv| csv << measure_values.unshift("measure_id") } return log end def ecm_cold_deck_reset_control( model ) log = "" measure_values = [ "cold_deck_reset_enabled", "cold_deck_reset_max_supply_air_temp", "cold_deck_reset_min_supply_air_temp", ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) if @cold_deck_reset_enabled.to_bool == true model.getAirLoopHVACs.each do |iairloop| cooling_present = false set_point_manager = nil iairloop.components.each do |icomponent| if icomponent.to_CoilCoolingDXSingleSpeed.is_initialized or icomponent.to_CoilCoolingDXTwoSpeed.is_initialized or icomponent.to_CoilCoolingWater.is_initialized or icomponent.to_CoilCoolingCooledBeam.is_initialized or icomponent.to_CoilCoolingDXMultiSpeed.is_initialized or icomponent.to_CoilCoolingDXVariableRefrigerantFlow.is_initialized or icomponent.to_CoilCoolingLowTempRadiantConstFlow.is_initialized or icomponent.to_CoilCoolingLowTempRadiantVarFlow.is_initialized cooling_present = true log << "found cooling." end end #check if setpoint manager is present at supply outlet. model.getSetpointManagerSingleZoneReheats.each do |manager| if iairloop.supplyOutletNode == manager.setpointNode.get set_point_manager = manager end end if set_point_manager.nil? and cooling_present == true set_point_manager = OpenStudio::Model::SetpointManagerSingleZoneReheat.new(model) set_point_manager.addToNode(iairloop.supplyOutletNode) end if cooling_present == true and not set_point_manager.nil? set_point_manager.setMaximumSupplyAirTemperature(@cold_deck_reset_max_supply_air_temp) set_point_manager.setMinimumSupplyAirTemperature(@cold_deck_reset_min_supply_air_temp) log << "to_SetpointManagerSingleZoneReheat set to 20.0 and 13.0" end end end return log end def ecm_sat_reset( model ) log = "" measure_values = [ "sat_reset_enabled", "sat_reset_outdoor_high_temperature", "sat_reset_outdoor_low_temperature", "sat_reset_setpoint_at_outdoor_high_temperature", "sat_reset_setpoint_at_outdoor_low_temperature" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) if @sat_reset_enabled.to_bool == true model.getAirLoopHVACs.each do |iairloop| #check if setpoint manager is present at supply outlet model.getSetpointManagerSingleZoneReheats.each do |manager| if iairloop.supplyOutletNode == manager.setpointNode.get manager.disconnect end end new_set_point_manager = OpenStudio::Model::SetpointManagerOutdoorAirReset.new(model) new_set_point_manager.addToNode(iairloop.supplyOutletNode) new_set_point_manager.setOutdoorHighTemperature(@sat_reset_outdoor_high_temperature) new_set_point_manager.setOutdoorLowTemperature(@sat_reset_outdoor_low_temperature) new_set_point_manager.setSetpointatOutdoorHighTemperature(@sat_reset_setpoint_at_outdoor_high_temperature) new_set_point_manager.setSetpointatOutdoorLowTemperature(@sat_reset_setpoint_at_outdoor_low_temperature) new_set_point_manager.setControlVariable("Temperature") log << "Replaced SingleZoneReheat with OA reset control." end end return log end def ecm_temp_setback( model ) log = "" measure_values = [ "occ_stbck_enabled", "occ_stbck_tolerance", "occ_stbck_heat_setback", "occ_stbck_heat_setpoint", "occ_stbck_cool_setback", "occ_stbck_cool_setpoint" ] #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil. self.set_instance_variables(measure_values) # get occupancy schedule if possible. unless @occ_stbck_enabled.nil? or @occ_stbck_enabled == false if model.building.get.defaultScheduleSet.is_initialized and model.building.get.defaultScheduleSet.get.numberofPeopleSchedule.is_initialized and model.building.get.defaultScheduleSet.get.numberofPeopleSchedule.get.to_ScheduleRuleset.is_initialized occupancy_schedule = model.building.get.defaultScheduleSet.get.numberofPeopleSchedule.get heating_schedule,cooling_schedule = BTAP::Resources::Schedules::create_setback_schedule_based_on_another_schedule( model, occupancy_schedule, @occ_stbck_tolerance.to_f, @occ_stbck_heat_setpoint.to_f, @occ_stbck_heat_setback.to_f, @occ_stbck_cool_setpoint.to_f, @occ_stbck_cool_setback.to_f) model.getThermostatSetpointDualSetpoints.each do |dual_setpoint| raise ("Could not set setback heating Schedule") unless dual_setpoint.setHeatingSetpointTemperatureSchedule(heating_schedule) raise ("Could not set setback cooling Schedule") unless dual_setpoint.setCoolingSetpointTemperatureSchedule(cooling_schedule) log << "modified....#{dual_setpoint}" end end else log << "no change to setbacks." end return log end end end end