class NECB2015
This class holds methods that apply NECB2011
rules. @ref [References::NECB2011]
Public Class Methods
new()
click to toggle source
Calls superclass method
NECB2011::new
# File lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb, line 7 def initialize super() @standards_data = load_standards_database_new corrupt_standards_database end
Public Instance Methods
apply_lighting_schedule(space_type, space_type_properties, default_sch_set)
click to toggle source
# File lib/openstudio-standards/standards/necb/NECB2015/lighting.rb, line 10 def apply_lighting_schedule(space_type, space_type_properties, default_sch_set) require 'date' lighting_per_area = space_type_properties['lighting_per_area'].to_f lights_rel_absence_occ = space_type_properties['rel_absence_occ'].to_f lights_personal_control = space_type_properties['personal_control'].to_f lights_occ_sense = space_type_properties['occ_sense'].to_f occupancy_schedule = space_type_properties['occupancy_schedule'].to_s orig_lighting_sch = space_type_properties['lighting_schedule'].to_s schedule_table = @standards_data['schedules'] # checks which rules to apply based on LPD if lighting_per_area <= 0.799256505 # 8.6 W/m2 # do not apply occupancy sensor control orig_lighting_sch = space_type_properties['lighting_schedule'] unless orig_lighting_sch.nil? default_sch_set.setLightingSchedule(model_add_schedule(space_type.model, orig_lighting_sch)) OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.SpaceType', "#{space_type.name} set lighting schedule to #{orig_lighting_sch}.") end else # LPD > 8.6 W/m2 # apply occupancy sensor control # get occupancy schedule's day rules rules = model_find_objects(schedule_table, 'name' => occupancy_schedule) # returns all schedules with schedule name entered # check if it exists if rules.empty? # does not exist -apply default lighting sched OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Model', "Cannot find data for schedule: #{occupancy_schedule}. Cannot apply occupancy sensor control for lighting for space: #{space_type.name} ") orig_lighting_sch = space_type_properties['lighting_schedule'] unless orig_lighting_sch.nil? default_sch_set.setLightingSchedule(model_add_schedule(space_type.model, orig_lighting_sch)) OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.SpaceType', "#{space_type.name} set lighting schedule to #{orig_lighting_sch}.") end else # exists # check if schedule exists already . # First check model and return schedule if it already exists space_type.model.getSchedules.sort.each do |exisiting_light_ruleset| if exisiting_light_ruleset.name.get.to_s == "#{occupancy_schedule}-#{orig_lighting_sch}-#{lights_rel_absence_occ}-#{lights_personal_control}-#{lights_occ_sense}-Light Ruleset" OpenStudio.logFree(OpenStudio::Debug, 'openstudio.standards.Model', "Already added schedule: #{exisiting_light_ruleset.name.get}") # set the lighting schedule unless exisiting_light_ruleset.nil? default_sch_set.setLightingSchedule(exisiting_light_ruleset) OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.SpaceType', "#{space_type.name} set lighting schedule to #{exisiting_light_ruleset}.") return true end end end # Create new lighting schedule lighting_sch_ruleset = OpenStudio::Model::ScheduleRuleset.new(space_type.model) lighting_sch_ruleset.setName("#{occupancy_schedule}-#{orig_lighting_sch}-#{lights_rel_absence_occ}-#{lights_personal_control}-#{lights_occ_sense}-Light Ruleset") # loop through the number of day types (each occupancy schedule day) rules.each do |rule| # get day type, hourly values from the occupancy schedule day day_types = rule['day_types'] # Default Wkdy, Wknd, Mon, Tue, Wed, Thu, Fri, Sat, Sun, WntrDsn, SmrDsn occupancy_value = rule['values'] sch_type = rule['type'] # should be 'Hourly' start_date = DateTime.parse(rule['start_date']) end_date = DateTime.parse(rule['end_date']) # create new array to hold occ_control values for each day-type/schedule day hourly_occ_control = [] # loop through hourly values to check if occupancy sensor control should apply and store the new lighting day hourly value hourly_index = 0 for hourly_value in occupancy_value do # default light schedule hourly value lighting_sched_value = 999 # get the hourly value from the .json schedule # get lighting schedule orig_lighting_rules = model_find_objects(schedule_table, 'name' => orig_lighting_sch) # returns all schedules with schedule name if orig_lighting_rules.empty? OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Model', "Cannot find data for schedule: #{orig_lighting_sch}.") end if hourly_value < lights_rel_absence_occ # occupancy sensor control applies for this hour occ_control = 1 - (lights_rel_absence_occ * lights_occ_sense) - lights_personal_control # go through lighitng schedule and adjust the value for the hour orig_lighting_rules.each do |orig_lighting_rule| if day_types == orig_lighting_rule['day_types'] # if light day schedule type matches occupancy day type orig_hourly_values = orig_lighting_rule['values'] lighting_sched_value = (orig_hourly_values[hourly_index]) * occ_control end end else # occupancy sensor control does not apply for this hour. Use default schedule value from .json file # go through each lighting schedule day to find the one with the matching day type # assuming occupancy schedule day matches lighting schedule day orig_lighting_rules.each do |orig_lighting_rule| if day_types == orig_lighting_rule['day_types'] # if light day schedule type matches occupancy day type orig_hourly_values = orig_lighting_rule['values'] occ_control = 1 lighting_sched_value = orig_hourly_values[hourly_index] # set the current hourly_index's original lighting schedule day value to lighting_sched_value end end # if hourly_value<lights_rel_absence_occ end # store the lighting_sched_value factor for this hour to the array hourly_occ_control << lighting_sched_value # update index hourly_index += 1 # for hourly_value in occupancy_value do end # for each schedule day, create a new day rule with the new hourly schedule values for lighting if day_types.include?('Default') day_sch = lighting_sch_ruleset.defaultDaySchedule day_sch.setName("#{occupancy_schedule}-#{orig_lighting_sch}-#{lights_rel_absence_occ}-#{lights_personal_control}-#{lights_occ_sense}-Light Default") model_add_vals_to_sch(space_type.model, day_sch, sch_type, hourly_occ_control) end if day_types.include?('Wknd') || day_types.include?('Wkdy') || day_types.include?('Sat') || day_types.include?('Sun') || day_types.include?('Mon') || day_types.include?('Tue') || day_types.include?('Wed') || day_types.include?('Thu') || day_types.include?('Fri') # Make the Rule sch_rule = OpenStudio::Model::ScheduleRule.new(lighting_sch_ruleset) day_sch = sch_rule.daySchedule day_sch.setName("#{occupancy_schedule}-#{orig_lighting_sch}-#{lights_rel_absence_occ}-#{lights_personal_control}-#{lights_occ_sense}-#{day_types}-Light Day") model_add_vals_to_sch(space_type.model, day_sch, sch_type, hourly_occ_control) # Set the dates when the rule applies sch_rule.setStartDate(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(start_date.month.to_i), start_date.day.to_i)) sch_rule.setEndDate(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(end_date.month.to_i), end_date.day.to_i)) # Set the days when the rule applies # Weekends if day_types.include?('Wknd') sch_rule.setApplySaturday(true) sch_rule.setApplySunday(true) end # Weekdays if day_types.include?('Wkdy') sch_rule.setApplyMonday(true) sch_rule.setApplyTuesday(true) sch_rule.setApplyWednesday(true) sch_rule.setApplyThursday(true) sch_rule.setApplyFriday(true) end # Individual Days sch_rule.setApplyMonday(true) if day_types.include?('Mon') sch_rule.setApplyTuesday(true) if day_types.include?('Tue') sch_rule.setApplyWednesday(true) if day_types.include?('Wed') sch_rule.setApplyThursday(true) if day_types.include?('Thu') sch_rule.setApplyFriday(true) if day_types.include?('Fri') sch_rule.setApplySaturday(true) if day_types.include?('Sat') sch_rule.setApplySunday(true) if day_types.include?('Sun') end if day_types.include?('WntrDsn') day_sch = OpenStudio::Model::ScheduleDay.new(space_type.model) lighting_sch_ruleset.setWinterDesignDaySchedule(day_sch) day_sch = lighting_sch_ruleset.winterDesignDaySchedule day_sch.setName("#{occupancy_schedule}-#{orig_lighting_sch}-#{lights_rel_absence_occ}-#{lights_personal_control}-#{lights_occ_sense}-Light Winter Design") model_add_vals_to_sch(space_type.model, day_sch, sch_type, hourly_occ_control) end if day_types.include?('SmrDsn') day_sch = OpenStudio::Model::ScheduleDay.new(space_type.model) lighting_sch_ruleset.setSummerDesignDaySchedule(day_sch) day_sch = lighting_sch_ruleset.summerDesignDaySchedule day_sch.setName("#{occupancy_schedule}-#{orig_lighting_sch}-#{lights_rel_absence_occ}-#{lights_personal_control}-#{lights_occ_sense}-Light Summer Design") model_add_vals_to_sch(space_type.model, day_sch, sch_type, hourly_occ_control) end # rules.each do|rule| end # set the lighting schedule unless lighting_sch_ruleset.nil? default_sch_set.setLightingSchedule(lighting_sch_ruleset) OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.SpaceType', "#{space_type.name} set lighting schedule to #{lighting_sch_ruleset}.") end # if rules.empty? #does not exist end # if lighting_per_area <= 0.7999256505 #8.6 W/m2 end end
apply_loop_pump_power(model:, sizing_run_dir:)
click to toggle source
# File lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb, line 52 def apply_loop_pump_power(model:, sizing_run_dir:) # NECB2015 Custom code # Do another sizing run to take into account adjustments to equipment efficiency etc. on capacities. This was done primarily # because the cooling tower loop capacity is affected by the chiller COP. If the chiller COP is not properly set then # the cooling tower loop capacity can be significantly off which will affect the NECB 2015 maximum loop pump capacity. Found # all sizing was off somewhat if the additional sizing run was not done. if model_run_sizing_run(model, "#{sizing_run_dir}/SR2") == false raise('sizing run 2 failed!') end # Apply maxmimum loop pump power normalized by peak demand by served spaces as per NECB2015 5.2.6.3.(1) apply_maximum_loop_pump_power(model) # model = BTAP::FileIO::remove_duplicate_materials_and_constructions(model) return model end
apply_maximum_loop_pump_power(model)
click to toggle source
Searches through any hydronic loops and applies the maxmimum total pump power by modifying the pump design power consumption. This is as per NECB2015
5.2.6.3.(1)
# File lib/openstudio-standards/standards/necb/NECB2015/hvac_systems.rb, line 126 def apply_maximum_loop_pump_power(model) plant_loops = model.getPlantLoops plant_loops.each do |plantloop| next if plant_loop_swh_loop?(plantloop) == true pumps = [] max_powertoload = 0 total_pump_power = 0 # This cycles through the plant loop supply side components to determine if there is a heat pump present or a pump # If a heat pump is present the pump power to total demand ratio is set to what NECB 2015 table 5.2.6.3. say it should be. # If a pump is present, this is a handy time to grab it for modification later. Also, it adds the pump power consumption # to a total which will be used to determine how much to modify the pump power consumption later. max_total_loop_pump_power_table = @standards_data['max_total_loop_pump_power'] plantloop.supplyComponents.each do |supplycomp| case supplycomp.iddObjectType.valueName.to_s when 'OS_CentralHeatPumpSystem', 'OS_Coil_Heating_WaterToAirHeatPump_EquationFit', 'OS_Coil_Heating_WaterToAirHeatPump_VariableSpeedEquationFit', 'OS_Coil_Heating_WaterToAirHeatPump_VariableSpeedEquationFit_SpeedData' search_hash = { 'hydronic_system_type' => 'WSHP' } max_powertoload = model_find_object(max_total_loop_pump_power_table, search_hash)['total_normalized_pump_power_wperkw'] when 'OS_GroundHeatExchanger_Vertical' max_powertoload = 21.0 when 'OS_Pump_VariableSpeed' pump = supplycomp.to_PumpVariableSpeed.get pumps << pump total_pump_power += pump.autosizedRatedPowerConsumption.get when 'OS_Pump_ConstantSpeed' pump = supplycomp.to_PumpConstantSpeed.get pumps << pump total_pump_power += pump.autosizedRatedPowerConsumption.get when 'OS_HeaderedPumps_ConstantSpeed' OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.PlantLoop', "A pump used in the plant loop named #{plantloop.name} is headered. This may result in an error and cause a failure.") pump = supplycomp.to_HeaderedPumpsConstantSpeed.get pumps << pump total_pump_power += pump.autosizedRatedPowerConsumption.get when 'OS_HeaderedPumps_VariableSpeed' OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.PlantLoop', "A pump used in the plant loop named #{plantloop.name} is headered. This may result in an error and cause a failure.") pump = supplycomp.to_HeaderedPumpsVariableSpeed.get pumps << pump total_pump_power += pump.autosizedRatedPowerConsumption.get end end var_spd_pumps = pumps.select {|pump| pump.to_PumpVariableSpeed.is_initialized} # EnergyPlus doesn't currently properly account for variable speed pumps operation in the condenser loop. # This code is an approximation for a correction to the pump head when the loop has variable speed pumps for ground-source condenser loops. # These estimates were confirmed with OS runs using Montreal weather file for offices, schoold, and apartment bldgs. Office estimates are # then for other bldg types. if plantloop.name.to_s.upcase.include? "GLHX" max_powertoload = 21.0 if !var_spd_pumps.empty? if model.getBuilding.standardsBuildingType.to_s.include? 'Office' max_powertoload = 21.0/4.0 elsif model.getBuilding.standardsBuildingType.to_s.include? 'School' max_powertoload = 21.0/18.0 elsif model.getBuilding.standardsBuildingType.to_s.include? 'Apartment' max_powertoload = 21.0/3.0 else max_powertoload = 21.0/4.0 end end end # If no pumps were found then there is nothing to set so go to the next plant loop next if pumps.empty? # If a heat pump was found then the pump power to total demand ratio should have been set to what NECB 2015 table 5.2.6.3 says. # If the pump power to total demand ratio was not set then no heat pump was present so set according to if the plant loop is # used for heating, cooling, or heat rejection (condeser as OpenStudio calls it). unless max_powertoload > 0 case plantloop.sizingPlant.loopType when 'Heating' search_hash = { 'hydronic_system_type' => 'Heating' } max_powertoload = model_find_object(max_total_loop_pump_power_table, search_hash)['total_normalized_pump_power_wperkw'] when 'Cooling' search_hash = { 'hydronic_system_type' => 'Cooling' } max_powertoload = model_find_object(max_total_loop_pump_power_table, search_hash)['total_normalized_pump_power_wperkw'] when 'Condenser' search_hash = { 'hydronic_system_type' => 'Heat_rejection' } max_powertoload = model_find_object(max_total_loop_pump_power_table, search_hash)['total_normalized_pump_power_wperkw'] end end # If nothing was found then do nothing (though by this point if nothing was found then an error should have been thrown). next if max_powertoload == 0 # Get the capacity of the loop (using the more general method of calculating via maxflow*temp diff*density*heat capacity) # This is more general than the other method in Standards.PlantLoop.rb which only looks at heat and cooling. Also, # that method looks for spceific equipment and would be thrown if other equipment was present. However my method # only works for water for now. plantloop_capacity = plant_loop_capacity_w_by_maxflow_and_delta_t_forwater(plantloop) # Sizing factor is pump power (W)/ zone demand (in kW, as approximated using plant loop capacity). necb_pump_power_cap = plantloop_capacity * max_powertoload / 1000 pump_power_adjustment = necb_pump_power_cap / total_pump_power # Update rated pump head to make pump power in line with NECB 2015. pumps.each do |pump| if pump.designPowerSizingMethod != "PowerPerFlowPerPressure" then OpenStudio::logFree(OpenStudio::Error, 'openstudio.standards.PlantLoop', 'Design power sizing method for pump ',pump.name.to_s,' not set to PowerPerFlowPerPressure') end new_pump_head = pump_power_adjustment*pump.ratedPumpHead.to_f pump.setRatedPumpHead(new_pump_head) end end return model end
chiller_electric_eir_apply_efficiency_and_curves(chiller_electric_eir, clg_tower_objs)
click to toggle source
Applies the standard efficiency ratings and typical performance curves to this object.
@return [Boolean] true if successful, false if not
# File lib/openstudio-standards/standards/necb/NECB2015/hvac_systems.rb, line 5 def chiller_electric_eir_apply_efficiency_and_curves(chiller_electric_eir, clg_tower_objs) chillers = standards_data['chillers'] # Define the criteria to find the chiller properties # in the hvac standards data set. search_criteria = chiller_electric_eir_find_search_criteria(chiller_electric_eir) cooling_type = search_criteria['cooling_type'] condenser_type = search_criteria['condenser_type'] compressor_type = search_criteria['compressor_type'] # Get the chiller capacity capacity_w = chiller_electric_eir_find_capacity(chiller_electric_eir) # All chillers must be modulating down to 25% of their capacity chiller_electric_eir.setChillerFlowMode('LeavingSetpointModulated') chiller_electric_eir.setMinimumPartLoadRatio(0.25) chiller_electric_eir.setMinimumUnloadingRatio(0.25) chiller_capacity = capacity_w if (chiller_electric_eir.name.to_s.include? 'Primary') || (chiller_electric_eir.name.to_s.include? 'Secondary') if (capacity_w / 1000.0) < 2100.0 if chiller_electric_eir.name.to_s.include? 'Primary Chiller' chiller_capacity = capacity_w elsif chiller_electric_eir.name.to_s.include? 'Secondary Chiller' chiller_capacity = 0.001 end else chiller_capacity = capacity_w / 2.0 end end chiller_electric_eir.setReferenceCapacity(chiller_capacity) # Convert capacity to tons capacity_tons = OpenStudio.convert(chiller_capacity, 'W', 'ton').get # Get chiller compressor type if needed chiller_types = ['reciprocating','scroll','rotary screw','centrifugal'] chiller_name_has_type = chiller_types.any? {|type| chiller_electric_eir.name.to_s.downcase.include? type} unless chiller_name_has_type chlr_type_search_criteria = {} chlr_type_search_criteria['cooling_type'] = cooling_type chlr_types_table = @standards_data['chiller_types'] chlr_type_props = model_find_object(chlr_types_table, chlr_type_search_criteria, capacity_tons) unless chlr_type_props OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.ChillerElectricEIR', "For #{chiller_electric_eir.name}, cannot find chiller types information") successfully_set_all_properties = false return successfully_set_all_properties end compressor_type = chlr_type_props['compressor_type'] chiller_electric_eir.setName(chiller_electric_eir.name.to_s + ' ' + compressor_type) end # Get the chiller properties search_criteria['compressor_type'] = compressor_type chlr_table = @standards_data['chillers'] chlr_props = model_find_object(chlr_table, search_criteria, capacity_tons, Date.today) unless chlr_props OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.ChillerElectricEIR', "For #{chiller_electric_eir.name}, cannot find chiller properties, cannot apply standard efficiencies or curves.") successfully_set_all_properties = false return successfully_set_all_properties end # Make the CAPFT curve cool_cap_ft = model_add_curve(chiller_electric_eir.model, chlr_props['capft']) if cool_cap_ft chiller_electric_eir.setCoolingCapacityFunctionOfTemperature(cool_cap_ft) else OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.ChillerElectricEIR', "For #{chiller_electric_eir.name}, cannot find cool_cap_ft curve, will not be set.") successfully_set_all_properties = false end # Make the EIRFT curve cool_eir_ft = model_add_curve(chiller_electric_eir.model, chlr_props['eirft']) if cool_eir_ft chiller_electric_eir.setElectricInputToCoolingOutputRatioFunctionOfTemperature(cool_eir_ft) else OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.ChillerElectricEIR', "For #{chiller_electric_eir.name}, cannot find cool_eir_ft curve, will not be set.") successfully_set_all_properties = false end # Make the EIRFPLR curve # which may be either a CurveBicubic or a CurveQuadratic based on chiller type cool_plf_fplr = model_add_curve(chiller_electric_eir.model, chlr_props['eirfplr']) if cool_plf_fplr chiller_electric_eir.setElectricInputToCoolingOutputRatioFunctionOfPLR(cool_plf_fplr) else OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.ChillerElectricEIR', "For #{chiller_electric_eir.name}, cannot find cool_plf_fplr curve, will not be set.") successfully_set_all_properties = false end # Set the efficiency value kw_per_ton = nil cop = nil if chlr_props['minimum_full_load_efficiency'] kw_per_ton = chlr_props['minimum_full_load_efficiency'] cop = kw_per_ton_to_cop(kw_per_ton) chiller_electric_eir.setReferenceCOP(cop) else OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.ChillerElectricEIR', "For #{chiller_electric_eir.name}, cannot find minimum full load efficiency, will not be set.") successfully_set_all_properties = false end # Set cooling tower properties now that the new COP of the chiller is set if chiller_electric_eir.name.to_s.include? 'Primary Chiller' # Single speed tower model assumes 25% extra for compressor power tower_cap = capacity_w * (1.0 + 1.0 / chiller_electric_eir.referenceCOP) if (tower_cap / 1000.0) < 1750 clg_tower_objs[0].setNumberofCells(1) else clg_tower_objs[0].setNumberofCells((tower_cap / (1000 * 1750) + 0.5).round) end clg_tower_objs[0].setFanPoweratDesignAirFlowRate(0.013 * tower_cap) end # Append the name with size and kw/ton chiller_electric_eir.setName("#{chiller_electric_eir.name} #{capacity_tons.round}tons #{kw_per_ton.round(1)}kW/ton") OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.ChillerElectricEIR', "For #{template}: #{chiller_electric_eir.name}: #{cooling_type} #{condenser_type} #{compressor_type} Capacity = #{capacity_tons.round}tons; COP = #{cop.round(1)} (#{kw_per_ton.round(1)}kW/ton)") return successfully_set_all_properties end
load_qaqc_database_new()
click to toggle source
Calls superclass method
NECB2011#load_qaqc_database_new
# File lib/openstudio-standards/standards/necb/NECB2015/qaqc/necb_2015_qaqc.rb, line 2 def load_qaqc_database_new super() # replace 2011 to 2015 for all references in the tables. # puts JSON.pretty_generate( @standards_data['tables'] ) @qaqc_data['tables'].each do |table| if table.key?('refs') # check if the reference is an array if table['refs'].is_a?(Array) table['refs'].each do |item| # Supply air system - necb_design_supply_temp_compliance item.gsub!('NECB2011-8.4.4.19', 'NECB2015-8.4.4.18') # Zone sizing compliance - Re: heating_sizing_factor and cooling_sizing_factor item.gsub!('NECB2011-8.4.4.9', 'NECB2015-8.4.4.8') item.gsub!('NECB2011', 'NECB2015') end # if the reference is a hash (e.g. see space.json compliance), then # replace the 2011 in the value with 2015 elsif table['refs'].is_a?(Hash) table['refs'].keys.each do |key| table['refs'][key].gsub!('NECB2011', 'NECB2015') unless table['refs'][key].nil? end end end end # Overwrite the data present from 2011 with the data read from the JSON files files = Dir.glob("#{File.dirname(__FILE__)}/qaqc_data/*.json").select { |e| File.file? e } puts "\n\n#{files}\n\n" files.each do |file| puts "loading standards data from #{file}" data = JSON.parse(File.read(file)) if !data['tables'].nil? && (data['tables'].first['data_type'] == 'table') @qaqc_data['tables'] << data['tables'].first else @qaqc_data[data.keys.first] = data[data.keys.first] end end # needed for compatibility of standards database format @qaqc_data['tables'].each do |table| @qaqc_data[table['name']] = table end return @qaqc_data end
load_standards_database_new()
click to toggle source
Calls superclass method
NECB2011#load_standards_database_new
# File lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb, line 13 def load_standards_database_new # load NECB2011 data. super() if __dir__[0] == ':' # Running from OpenStudio CLI embedded_files_relative('data/', /.*\.json/).each do |file| data = JSON.parse(EmbeddedScripting.getFileAsString(file)) if !data['tables'].nil? @standards_data['tables'] = [*@standards_data['tables'], *data['tables']].to_h elsif !data['constants'].nil? @standards_data['constants'] = [*@standards_data['constants'], *data['constants']].to_h elsif !data['constants'].nil? @standards_data['formulas'] = [*@standards_data['formulas'], *data['formulas']].to_h end end else files = Dir.glob("#{File.dirname(__FILE__)}/data/*.json").select { |e| File.file? e } files.each do |file| data = JSON.parse(File.read(file)) if !data['tables'].nil? @standards_data['tables'] = [*@standards_data['tables'], *data['tables']].to_h elsif !data['constants'].nil? @standards_data['constants'] = [*@standards_data['constants'], *data['constants']].to_h elsif !data['formulas'].nil? @standards_data['formulas'] = [*@standards_data['formulas'], *data['formulas']].to_h end end end # Write database to file. # File.open(File.join(File.dirname(__FILE__), '..', 'NECB2017.json'), 'w') {|f| f.write(JSON.pretty_generate(@standards_data))} return @standards_data end
necb_envelope_compliance(qaqc)
click to toggle source
# File lib/openstudio-standards/standards/necb/NECB2015/qaqc/necb_2015_qaqc.rb, line 47 def necb_envelope_compliance(qaqc) puts "\nUsing necb_envelope_compliance in NECB2015 Class\n" # Envelope necb_section_name = 'NECB2015-Section 3.2.1.4' # store hdd in short form hdd = qaqc[:geography][:hdd] # calculate fdwr based on hdd. # [fdwr] *maximum* allowable total vertical fenestration and door area to # gross wall area ratio fdwr = 0 # if hdd < 4000 [NECB 2011] if hdd <= 4000 fdwr = 0.40 # elsif hdd >= 4000 and hdd <=7000 [NECB 2011] elsif (hdd > 4000) && (hdd < 7000) fdwr = (2000 - 0.2 * hdd) / 3000 # elsif hdd >7000 [NECB 2011] elsif hdd >= 7000 fdwr = 0.20 end # hardset srr to 0.05 srr = 0.05 # perform test. result must be equal to. necb_section_test( qaqc, (fdwr * 100), # fdwr is the maximum value possible '>=', # NECB 2011 [No Change] qaqc[:envelope][:fdwr].round(3), necb_section_name, '[ENVELOPE]fenestration_to_door_and_window_percentage', 1 # padmassun added tollerance ) # The total skylight area shall be less than 5% of gross roof area as determined # in article 3.1.1.6 necb_section_test( qaqc, (srr * 100), '>=', # NECB 2011 [No Change] qaqc[:envelope][:srr].round(3), necb_section_name, '[ENVELOPE]skylight_to_roof_percentage', 1 # padmassun added tollerance ) end
necb_qaqc(qaqc, model)
click to toggle source
# File lib/openstudio-standards/standards/necb/NECB2015/qaqc/necb_2015_qaqc.rb, line 147 def necb_qaqc(qaqc, model) puts "\n\nin necb_qaqc 2015 now\n\n" # Now perform basic QA/QC on items for NECB2015 qaqc[:information] = [] qaqc[:warnings] = [] qaqc[:errors] = [] qaqc[:unique_errors] = [] necb_space_compliance(qaqc) necb_envelope_compliance(qaqc) # [DONE] necb_infiltration_compliance(qaqc, model) # [DONE-NC] necb_exterior_opaque_compliance(qaqc) # [DONE-NC] necb_exterior_fenestration_compliance(qaqc) # [DONE-NC] necb_exterior_ground_surfaces_compliance(qaqc) # [DONE-NC] necb_zone_sizing_compliance(qaqc) # [DONE] made changes to NECB section numbers necb_design_supply_temp_compliance(qaqc) # [DONE] made changes to NECB section numbers # Cannot implement 5.2.2.8.(4) and 5.2.2.8.(5) due to OpenStudio's limitation. necb_economizer_compliance(qaqc) # [DONE-NC] # NECB code regarding MURBS (Section 5.2.10.4) has not been implemented in both NECB 2011 and 2015 necb_hrv_compliance(qaqc, model) # [DONE-NC] necb_vav_fan_power_compliance(qaqc) # [DONE-NC] sanity_check(qaqc) necb_plantloop_sanity(qaqc) qaqc[:information] = qaqc[:information].sort qaqc[:warnings] = qaqc[:warnings].sort qaqc[:errors] = qaqc[:errors].sort qaqc[:unique_errors] = qaqc[:unique_errors].sort return qaqc end
necb_space_compliance(qaqc)
click to toggle source
# File lib/openstudio-standards/standards/necb/NECB2015/qaqc/necb_2015_qaqc.rb, line 94 def necb_space_compliance(qaqc) # #Padmassun's Code Start # csv_file_name ="#{File.dirname(__FILE__)}/necb_2011_spacetype_info.csv" qaqc[:spaces].each do |space| building_type = '' space_type = '' if space[:space_type_name].include? 'Space Function ' space_type = space[:space_type_name].to_s.rpartition('Space Function ')[2].strip building_type = 'Space Function' elsif space[:space_type_name].include? ' WholeBuilding' space_type = space[:space_type_name].to_s.rpartition(' WholeBuilding')[0].strip building_type = 'WholeBuilding' end ['occupancy_per_area_people_per_m2', 'occupancy_schedule', 'electric_equipment_per_area_w_per_m2'].each do |compliance_var| # qaqc_table = get_qaqc_table("space_compliance", {"template" => 'NECB2015', "building_type" => building_type, "space_type" => space_type}).first # qaqc_table = @qaqc_data['space_compliance'] search_criteria = { 'template' => 'NECB2015', 'building_type' => building_type, 'space_type' => space_type } table_to_search = @standards_data[@qaqc_data['space_compliance']] qaqc_table = model_find_objects(table_to_search, search_criteria) qaqc_table = qaqc_table.first puts "{\"building_type\" => #{building_type}, \"space_type\" => #{space_type}}" puts "#{qaqc_table}\n\n" necb_section_name = get_qaqc_table(table_name: 'space_compliance')['refs'][compliance_var] tolerance = get_qaqc_table(table_name: 'space_compliance')['tolerance'][compliance_var] # puts "\ncompliance_var:#{compliance_var}\n\tnecb_section_name:#{necb_section_name}\n\texp Value:#{qaqc_table[compliance_var]}\n" if compliance_var == 'occupancy_per_area_people_per_m2' result_value = space[:occ_per_m2] elsif compliance_var == 'occupancy_schedule' result_value = space[:occupancy_schedule] elsif compliance_var == 'electric_equipment_per_area_w_per_m2' result_value = space[:electric_w_per_m2] end test_text = "[SPACE][#{space[:name]}]-[TYPE:][#{space_type}]-#{compliance_var}" next if result_value.nil? necb_section_test( qaqc, result_value, '==', qaqc_table[compliance_var], necb_section_name, test_text, tolerance ) end end # Padmassun's Code End end
set_lighting_per_area(space_type:, definition:, lighting_per_area:, lights_scale:)
click to toggle source
# File lib/openstudio-standards/standards/necb/NECB2015/lighting.rb, line 2 def set_lighting_per_area(space_type:, definition:, lighting_per_area:, lights_scale:) definition.setWattsperSpaceFloorArea(OpenStudio.convert(lighting_per_area.to_f * lights_scale, 'W/ft^2', 'W/m^2').get) OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.SpaceType', "#{space_type.name} set LPD to #{lighting_per_area} W/ft^2.") end
set_lighting_per_area_led_lighting(space_type:, definition:, lighting_per_area_led_lighting:, lights_scale:)
click to toggle source
# File lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb, line 68 def set_lighting_per_area_led_lighting(space_type:, definition:, lighting_per_area_led_lighting:, lights_scale:) # puts "#{space_type.name.to_s} - 'space_height' - #{space_height.to_s}" # @todo Note that 'occ_sens_lpd_frac' in this function has been removed for NECB2015 and 2017. # ##### Since Atrium's LPD for LED lighting depends on atrium's height, the height of the atrium (if applicable) should be found. standards_space_type = space_type.standardsSpaceType.is_initialized ? space_type.standardsSpaceType.get : nil # Sara if standards_space_type.include? 'Atrium' # @todo Note that since none of the archetypes has Atrium, this was tested for 'Dining'. #Atrium puts "#{standards_space_type} - has atrium" # space_type.name.to_s # puts space_height if get_max_space_height_for_space_type(space_type: space_type) < 12.0 # @todo Regarding the below equations, identify which version of ASHRAE 90.1 was used in NECB2015. atrium_lpd_eq_smaller_12_intercept = 0 atrium_lpd_eq_smaller_12_slope = 1.06 atrium_lpd_eq_larger_12_intercept = 4.3 atrium_lpd_eq_larger_12_slope = 1.06 lighting_per_area_led_lighting_atrium = (atrium_lpd_eq_smaller_12_intercept + atrium_lpd_eq_smaller_12_slope * space_height) * 0.092903 # W/ft2 else # i.e. space_height >= 12.0 lighting_per_area_led_lighting_atrium = (atrium_lpd_eq_larger_12_intercept + atrium_lpd_eq_larger_12_slope * space_height) * 0.092903 # W/ft2 end puts "#{standards_space_type} - has lighting_per_area_led_lighting_atrium - #{lighting_per_area_led_lighting_atrium}" lighting_per_area_led_lighting = lighting_per_area_led_lighting_atrium end lighting_per_area_led_lighting *= lights_scale definition.setWattsperSpaceFloorArea(OpenStudio.convert(lighting_per_area_led_lighting.to_f, 'W/ft^2', 'W/m^2').get) OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.SpaceType', "#{space_type.name} set LPD to #{lighting_per_area_led_lighting} W/ft^2.") end
set_occ_sensor_spacetypes(model, space_type_map)
click to toggle source
occupancy sensor control applied using lighting schedule, see apply_lighting_schedule
method
# File lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb, line 48 def set_occ_sensor_spacetypes(model, space_type_map) return true end