require "#{File.dirname(__FILE__)}/btap" class OpenStudio::Model::Construction #This method will search through the layers and find the layer with the #lowest conductance and set that as the insulation layer. Note: Concrete walls #or slabs with no insulation layer but with a carper will see the carpet as the #insulation layer. #@author Phylroy A. Lopez #@return OpenStudio::Model::Material insulation_material_layer def self.find_and_set_insulaton_layer() insulation_material_layer = nil #return if there is already a defined insulation layer. return self.insulation unless self.insulation.empty? #set minimum conductance to 100.0 min_conductance = 100.0 #loop through Layers self.layers.each do |layer| #try casting the layer to an OpaqueMaterial. material = nil material = layer.to_OpaqueMaterial.get unless layer.to_OpaqueMaterial.empty? material = layer.to_FenestrationMaterial.get unless layer.to_FenestrationMaterial.empty? #check if the cast was successful, then find the insulation layer. unless nil == material if BTAP::Resources::Envelope::Materials::get_conductance(material) < min_conductance #Keep track of the highest thermal resistance value. min_conductance = BTAP::Resources::Envelope::Materials::get_conductance(material) insulation_material_layer = material unless material.to_OpaqueMaterial.empty? self.setInsulation(material) end end end end if self.insulation.empty? and self.isOpaque raise ("construction #{self.name.get.to_s} insulation layer could not be set!. This occurs when a insulation layer is duplicated in the construction.") end return insulation_material_layer end #This method will create a new construction based on self and a new conductance value. #It will check to see if a similar construction has already been created by this method #if so it will return the existing construction. If you wish to keep some of the properties, enter the #string "default" instead of a numerical value. #@author Phylroy A. Lopez #@param model [OpenStudio::Model::Model] #@param construction #@param conductance [Fixnum] #@return [ ( 1 / conductance ) #tell user why we are defaulting and set the conductance of the # construction. raise ("could not set conductance of construction #{new_construction.name.to_s} to because existing layers make this impossible. Change the construction to allow for this conductance to be set." + (conductance).to_s + "setting to closest value possible value:" + (1.0 / minimum_resistance).to_s ) # new_construction.setConductance((1.0/minimum_resistance)) else unless new_construction.setConductance(conductance) raise("could not set conductance of construction #{new_construction.name.to_s}") end end end return new_construction elsif self.isFenestration() #get equivilant values for tsol, tvis, and conductances. solarTransmittanceatNormalIncidence = self.get_tsol(model, construction) if solarTransmittanceatNormalIncidence == nil visibleTransmittance = self.get_tvis(model,construction) if visibleTransmittance == nil conductance = self.get_conductance(construction) if conductance == nil frontSideSolarReflectanceatNormalIncidence = 1.0 - solarTransmittanceatNormalIncidence backSideSolarReflectanceatNormalIncidence = 1.0 - solarTransmittanceatNormalIncidence frontSideVisibleReflectanceatNormalIncidence = 0.081000 backSideVisibleReflectanceatNormalIncidence = 0.081000 infraredTransmittanceatNormalIncidence = 0.0 frontSideInfraredHemisphericalEmissivity = 0.84 backSideInfraredHemisphericalEmissivity = 0.84 #store part of fenestation in array bins. glazing_array = Array.new() shading_material_array = Array.new() gas_array = Array.new() construction.layers.each do |material| glazing_array << material unless material.to_Glazing.empty? shading_material_array << material unless material.to_ShadingMaterial.empty? gas_array << material unless material.to_GasLayer.empty? end #set value of fictious glazing based on the fenestrations front and back if available unless glazing_array.first.to_StandardGlazing.empty? frontSideSolarReflectanceatNormalIncidence = glazing_array.first.to_StandardGlazing.get.frontSideSolarReflectanceatNormalIncidence frontSideVisibleReflectanceatNormalIncidence = glazing_array.first.to_StandardGlazing.get.frontSideVisibleReflectanceatNormalIncidence frontSideInfraredHemisphericalEmissivity = glazing_array.first.to_StandardGlazing.get.frontSideInfraredHemisphericalEmissivity end unless glazing_array.last.to_StandardGlazing.empty? backSideSolarReflectanceatNormalIncidence = glazing_array.last.to_StandardGlazing.get.backSideSolarReflectanceatNormalIncidence backSideVisibleReflectanceatNormalIncidence = glazing_array.last.to_StandardGlazing.get.backSideVisibleReflectanceatNormalIncidence backSideInfraredHemisphericalEmissivity = glazing_array.last.to_StandardGlazing.get.backSideInfraredHemisphericalEmissivity end #create fictious glazing. #assume a thickness of 0.10m thickness = 0.10 #calculate conductivity conductivity = conductance * thickness data_name_suffix = " cond=#{("%.3f" % conductivity).to_s} tvis=#{("%.3f" % visibleTransmittance).to_s} tsol=#{("%.3f" % solarTransmittanceatNormalIncidence).to_s}" cons_name = "Customized Fenestration:" + data_name_suffix glazing_name = "Customized Fenestration::" + data_name_suffix #Search to prevent the massive duplication that may ensue. return model.getConstructionByName(cons_name).get unless model.getConstructionByName(cons_name).empty? #fix for Simple glazing conductivity = conductance glazing = BTAP::Resources::Envelope::Materials::Fenestration::create_simple_glazing( construction.model,#model glazing_name, #name 0.60, #SHGC conductivity, #u-factor thickness, #Thickness 0.21 #vis trans ) new_materials_array = Array.new() new_materials_array << glazing new_materials_array.concat(shading_material_array) unless shading_material_array.empty? return self.create_construction(construction.model, cons_name, new_materials_array) end end end # open the class to add methods to size all HVAC equipment class OpenStudio::Model::Model def perform_load_elimination_analysis(folder = Dir.pwd) #remove hvac and only use ideal loads. model = self.clone(true).to_Model BTAP::Resources::HVAC::clear_all_hvac_from_model(model) model.getThermalZones.sort.each {|zone| zone.setUseIdealAirLoads(true)} conductance = 0.200 models = Array.new() #Add baseline models << {:name => 'baseline', :model => model} #Add copies of model with elimination of a characteristic. models << {:name => 'elim_ext_wall', :model => model.clone(true).to_Model.set_all_ext_wall_conductances_to(conductance)} =begin models << {:name => 'elim_ext_roof', :model => model.clone(true).to_Model.set_all_ext_roof_conductances_to(conductance)} models << {:name => 'elim_ground_floor', :model => model.clone(true).to_Model.set_all_ground_floor_conductances_to(conductance)} models << {:name => 'elim_ground_wall', :model => model.clone(true).to_Model.set_all_ground_wall_conductances_to(conductance)} models << {:name => 'elim_win_doors', :model => model.clone(true).to_Model.set_all_ext_windows_and_door_conductances_to(conductance)} models << {:name => 'elim_skylights', :model => model.clone(true).to_Model.set_all_ext_skylight_conductances_to(conductance)} models << {:name => 'elim_people', :model => model.clone(true).to_Model.eliminate_all_people_loads} models << {:name => 'elim_lighting', :model => model.clone(true).to_Model.eliminate_all_lighting_loads} models << {:name => 'elim_plug_loads', :model => model.clone(true).to_Model.eliminate_all_electric_loads} models << {:name => 'elim_outdoor_air', :model => model.clone(true).to_Model.eliminate_all_design_specification_outdoor_air} models << {:name => 'elim_infiltration', :model => model.clone(true).to_Model.eliminate_all_space_infiltration_design_flow_rates} models << {:name => 'elim_all_loads', :model => model.clone(true).to_Model.eliminate_all_loads} =end #Get a handle for the baseline. baseline = models.find {|model| model[:name] == 'baseline' } #Create a result hash. result = Hash.new() models.each do |model| #run each model in its own folder. success = model_run_simulation_and_log_errors(model[:model], "#{folder}/#{model[:name]}") #Run the qa-qc method to get all the results. qa_qc = BTAP::perform_qaqc(model[:model]) #Store total energy in the hash model[:total_end_uses_gj_per_m2] = qa_qc[:end_uses_eui][:total_end_uses_gj_per_m2] #This assumes that the baseline is always the first in the hash. unless model[:name] = 'baseline' result[model[:name]] = model[:total_end_uses_gj_per_m2] / baseline[:total_end_uses_gj_per_m2] end end return result end # Set global changes def set_all_ext_wall_conductances_to(conductance) #Set conductances to needed values in construction set if possible. self.getDefaultConstructionSets.sort.each_with_index do |default_construction_set, index| BTAP::Resources::Envelope::ConstructionSets::customize_default_surface_construction_set_rsi!( self, "Sensitivity Def Cnst Set #{index}", default_construction_set, 1/conductance, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ) end #sets all surfaces to use default constructions sets except adiabatic, where it does a hard assignment of the interior wall construction type. self.getPlanarSurfaces.sort.each {|item| item.resetConstruction} #if the default construction set is defined..try to assign the interior wall to the adiabatic surfaces BTAP::Resources::Envelope::assign_interior_surface_construction_to_adiabatic_surfaces(self, nil) return self end def set_all_ext_roof_conductances_to(conductance) #Set conductances to needed values in construction set if possible. self.getDefaultConstructionSets.sort.each_with_index do |default_construction_set, index| BTAP::Resources::Envelope::ConstructionSets::customize_default_surface_construction_set_rsi!( self, "Sensitivity Def Cnst Set #{index}", default_construction_set, nil, nil, 1/conductance, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ) end #sets all surfaces to use default constructions sets except adiabatic, where it does a hard assignment of the interior wall construction type. self.getPlanarSurfaces.sort.each {|item| item.resetConstruction} #if the default construction set is defined..try to assign the interior wall to the adiabatic surfaces BTAP::Resources::Envelope::assign_interior_surface_construction_to_adiabatic_surfaces(self, nil) return self end def set_all_ground_wall_conductances_to(conductance) #Set conductances to needed values in construction set if possible. self.getDefaultConstructionSets.sort.each_with_index do |default_construction_set, index| BTAP::Resources::Envelope::ConstructionSets::customize_default_surface_construction_set_rsi!( self, "Sensitivity Def Cnst Set #{index}", default_construction_set, nil, nil, nil, 1/conductance, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ) end #sets all surfaces to use default constructions sets except adiabatic, where it does a hard assignment of the interior wall construction type. self.getPlanarSurfaces.sort.each {|item| item.resetConstruction} #if the default construction set is defined..try to assign the interior wall to the adiabatic surfaces BTAP::Resources::Envelope::assign_interior_surface_construction_to_adiabatic_surfaces(self, nil) return self end def set_all_ground_floor_conductances_to(conductance) #Set conductances to needed values in construction set if possible. self.getDefaultConstructionSets.sort.each_with_index do |default_construction_set, index| BTAP::Resources::Envelope::ConstructionSets::customize_default_surface_construction_set_rsi!( self, "Sensitivity Def Cnst Set #{index}", default_construction_set, nil, nil, nil, nil, 1/conductance, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ) end #sets all surfaces to use default constructions sets except adiabatic, where it does a hard assignment of the interior wall construction type. self.getPlanarSurfaces.sort.each {|item| item.resetConstruction} #if the default construction set is defined..try to assign the interior wall to the adiabatic surfaces BTAP::Resources::Envelope::assign_interior_surface_construction_to_adiabatic_surfaces(self, nil) return self end def set_all_ext_windows_and_door_conductances_to(conductance) #Set conductances to needed values in construction set if possible. self.getDefaultConstructionSets.sort.each_with_index do |default_construction_set, index| BTAP::Resources::Envelope::ConstructionSets::customize_default_surface_construction_set_rsi!( self, "Sensitivity Def Cnst Set #{index}", default_construction_set, nil, nil, nil, nil, nil, nil, 1/conductance, nil, nil, 1/conductance, nil, nil, 1/conductance, 1/conductance, nil, nil, 1/conductance, nil, nil, nil, nil, nil, nil, nil, nil, nil ) end #sets all surfaces to use default constructions sets except adiabatic, where it does a hard assignment of the interior wall construction type. self.getPlanarSurfaces.sort.each {|item| item.resetConstruction} #if the default construction set is defined..try to assign the interior wall to the adiabatic surfaces BTAP::Resources::Envelope::assign_interior_surface_construction_to_adiabatic_surfaces(self, nil) return self end def set_all_ext_skylight_conductances_to(conductance) #Set conductances to needed values in construction set if possible. self.getDefaultConstructionSets.sort.each_with_index do |default_construction_set, index| BTAP::Resources::Envelope::ConstructionSets::customize_default_surface_construction_set_rsi!( self, "Sensitivity Def Cnst Set #{index}", default_construction_set, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1/conductance, nil, nil, nil, nil, nil, nil, nil, nil ) end #sets all surfaces to use default constructions sets except adiabatic, where it does a hard assignment of the interior wall construction type. self.getPlanarSurfaces.sort.each {|item| item.resetConstruction} #if the default construction set is defined..try to assign the interior wall to the adiabatic surfaces BTAP::Resources::Envelope::assign_interior_surface_construction_to_adiabatic_surfaces(self, nil) return self end #This method will set the infiltration magnitude. #@author phylroy.lopez@nrcan.gc.ca #@param self [OpenStudio::model::Model] A model object #@param setDesignFlowRate [Float] #@param setFlowperSpaceFloorArea [Float] #@param setFlowperExteriorSurfaceArea [Float] #@param setAirChangesperHour [Float] #@return [String] table def set_all_inflitration_rates(setDesignFlowRate, setFlowperSpaceFloorArea, setFlowperExteriorSurfaceArea, setAirChangesperHour) table = "name,infiltration_method,infiltration_design_flow_rate,infiltration_flow_per_space,infiltration_flow_per_exterior_area,infiltration_air_changes_per_hour\n" self.getSpaceInfiltrationDesignFlowRates.sort.each do |infiltration_load| infiltration_load.setAirChangesperHour(setAirChangesperHour) unless setAirChangesperHour.nil? infiltration_load.setDesignFlowRate(setDesignFlowRate) unless setDesignFlowRate.nil? infiltration_load.setFlowperSpaceFloorArea(setFlowperSpaceFloorArea) unless setFlowperSpaceFloorArea.nil? infiltration_load.setFlowperExteriorSurfaceArea(setFlowperExteriorSurfaceArea) unless setFlowperExteriorSurfaceArea.nil? table << infiltration_load.name.get.to_s << "," table << infiltration_load.designFlowRateCalculationMethod << "," infiltration_load.airChangesperHour.empty? ? ach = "NA" : ach = infiltration_load.airChangesperHour.get infiltration_load.designFlowRate.empty? ? dfr = "NA" : dfr = infiltration_load.designFlowRate.get infiltration_load.flowperSpaceFloorArea.empty? ? fsfa = "NA" : fsfa = infiltration_load.flowperSpaceFloorArea.get infiltration_load.flowperExteriorSurfaceArea.empty? ? fesa = "NA" : fesa = infiltration_load.flowperExteriorSurfaceArea.get table << "#{ach},#{dfr},#{fsfa},#{fesa}\n" end return table end #Scale Global Changes def scale_all_people_loads(factor) self.getPeoples.sort.each do |item| item.setMultiplier(item.multiplier * factor) end end #This method will scale people loads schedule. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param a_coef [Float] #@param b_coef [Float] #@param c_coef [Float] #@param time_shift [Float] #@param time_sign [Float] def scale_people_loads_schedule(a_coef, b_coef, c_coef, time_shift = nil, time_sign = nil) model.getPeoples.sort.each do |item| #Do an in-place modification of the schedule. BTAP::Resources::Schedules::modify_schedule!(self, item.schedule, a_coef, b_coef, c_coef, time_shift, time_sign) end end #This method will scale lighting loads. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param factor [Float] def scale_lighting_loads(factor) self.getLightss.sort.each do |item| item.setMultiplier(item.multiplier * factor) end end #This method will scale lighting loads schedule. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param a_coef [Float] #@param b_coef [Float] #@param c_coef [Float] #@param time_shift [Float] #@param time_sign [Float] def scale_lighting_loads_schedule(a_coef, b_coef, c_coef, time_shift = nil, time_sign = nil) model.getLightss.sort.each do |item| #Do an in-place modification of the schedule. BTAP::Resources::Schedules::modify_schedule!(self, item.schedule, a_coef, b_coef, c_coef, time_shift, time_sign) end end #This method will scale electrical loads. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param factor [Float] def scale_electrical_loads(model, factor) self.getElectricEquipments.sort.each do |item| item.setMultiplier(item.multiplier * factor) end end #This method will scale electrical loads schedule. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param a_coef [Float] #@param b_coef [Float] #@param c_coef [Float] #@param time_shift [Float] #@param time_sign [Float] def scale_electrical_loads_schedule(a_coef, b_coef, c_coef, time_shift = nil, time_sign = nil) self.getElectricEquipments.sort.each do |item| BTAP::Resources::Schedules::modify_schedule!(self, item.schedule, a_coef, b_coef, c_coef, time_shift, time_sign) end end #This method will scale Outdoor Air loads. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param factor [Float] def scale_oa_loads(factor) self.getDesignSpecificationOutdoorAirs.sort.each do |oa_def| oa_def.setOutdoorAirFlowperPerson(oa_def.getOutdoorAirFlowperPerson * factor) unless oa_def.isOutdoorAirFlowperPersonDefaulted oa_def.setOutdoorAirFlowperFloorArea(oa_def.getOutdoorAirFlowperFloorArea * factor) unless oa_def.isOutdoorAirFlowperFloorAreaDefaulted oa_def.setOutdoorAirFlowRate(oa_def.getOutdoorAirFlowRate * factor) unless oa_def.isOutdoorAirFlowRateDefaulted oa_def.setOutdoorAirFlowAirChangesperHour(oa_def.getOutdoorAirFlowAirChangesperHour * factor) unless oa_def.isOutdoorAirFlowAirChangesperHourDefaulted end end #This method will scale infiltration loads. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param factor [Float] def scale_inflitration_loads(factor) self.getSpaceInfiltrationDesignFlowRates.sort.each do |infiltration_load| infiltration_load.setDesignFlowRate(infiltration_load.designFlowRate.get * factor) unless infiltration_load.designFlowRate.empty? infiltration_load.setFlowperSpaceFloorArea(infiltration_load.flowperSpaceFloorArea.get * factor) unless infiltration_load.flowperSpaceFloorArea.empty? infiltration_load.setFlowperExteriorSurfaceArea(infiltration_load.flowperExteriorSurfaceArea.get * factor) unless infiltration_load.flowperExteriorSurfaceArea.empty? infiltration_load.setAirChangesperHour(infiltration_load.airChangesperHour.get * factor) unless infiltration_load.airChangesperHour.empty? end end # Elimination Methods #This method removes people loads from the model. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object def eliminate_all_people_loads() self.getPeoples.sort.each {|people| people.remove} self.getPeopleDefinitions.sort.each {|people| people.remove} return self end #This method removes light loads from model. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object def eliminate_all_lighting_loads() self.getLightss.sort.each {|item| item.remove} self.getLightsDefinitions.sort.each {|item| item.remove} return self end #This method removes elec loads from model. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object def eliminate_all_electric_loads() self.getElectricEquipments.sort.each {|item| item.remove} self.getElectricEquipmentDefinitions.sort.each {|item| item.remove} return self end #This method removes all design specification OA from model. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object def eliminate_all_design_specification_outdoor_air() self.getDesignSpecificationOutdoorAirs.sort.each {|item| item.remove} return self end #This method removes infiltration from model.. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object def eliminate_all_space_infiltration_design_flow_rates() self.getSpaceInfiltrationDesignFlowRates.sort.each {|item| item.remove} return self end #This method removes all space loads from model. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object def eliminate_all_loads() conductance = 0.200 #self.set_all_ext_wall_conductances_to(conductance) #self.set_all_ext_roof_conductances_to(conductance) #self.set_all_ground_floor_conductances_to(conductance) #self.set_all_ground_wall_conductances_to(conductance) #self.set_all_ext_windows_and_door_conductances_to(conductance) #self.set_all_ext_skylight_conductances_to(conductance) self.eliminate_all_people_loads self.eliminate_all_lighting_loads self.eliminate_all_electric_loads self.eliminate_all_design_specification_outdoor_air self.eliminate_all_space_infiltration_design_flow_rates self.eliminate_all_space_infiltration_design_flow_rates return self end end # open the class to add methods to size all HVAC equipment class OpenStudio::Model::Space def get_average_height() roof_datum = 0 total_roof_area = 0 floor_datum = 0 total_floor_area = 0 average_height = 0 #create a model to create a planar object.. Hopefully garbage collection deals with this right. temp_model = OpenStudio::Model::Model.new() self.surfaces.each do |surface| projected_vertices = Array.new() if surface.surfaceType == "Floor" average_surface_height = 0 surface.vertices.each do |point3d| average_surface_height += point3d.z / surface.vertices.size projected_vertices << OpenStudio::Point3d.new(point3d.x, point3d.y, 0) end projected_surface_area = OpenStudio::Model::Surface.new(projected_vertices ,temp_model).grossArea total_roof_area += projected_surface_area floor_datum += average_surface_height * projected_surface_area elsif surface.surfaceType == "RoofCeiling" average_surface_height = 0 surface.vertices.each do |point3d| average_surface_height += point3d.z / surface.vertices.size projected_vertices << OpenStudio::Point3d.new(point3d.x, point3d.y, 0) end projected_surface_area = OpenStudio::Model::Surface.new(projected_vertices ,temp_model).grossArea total_roof_area += projected_surface_area roof_datum += average_surface_height * projected_surface_area end end if total_floor_area > 0 and total_roof_area > 0 average_height = roof_datum / total_roof_area - floor_datum / total_floor_area end return average_height end end