class BTAPPRE1980

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/BTAPPRE1980/btap_pre1980.rb, line 7
def initialize
  super()
  @standards_data = load_standards_database_new
  corrupt_standards_database
end

Public Instance Methods

add_exhaust_fan(zone:, model:, name:) click to toggle source

This adds a zone exhaust fan to the zone passed to it. The flow rate for the exhaust fan is set to the sum of the outdoor air requirements for the spaces in the zone. If the exhaust fan is set to run whenever the supply fan runs.

# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_systems.rb, line 309
def add_exhaust_fan(zone:, model:, name:)
  outdoor_air = 0.0
  zone.spaces.sort.each do |space|
    outdoor_air_rate = space.designSpecificationOutdoorAir.get.outdoorAirFlowperFloorArea
    floor_area = space.floorArea
    outdoor_air += (outdoor_air_rate * floor_area)
  end
  exhaust_fan = OpenStudio::Model::FanZoneExhaust.new(model)
  exhaust_fan.setName(name)
  exhaust_fan.setSystemAvailabilityManagerCouplingMode('Coupled')
  exhaust_fan.setMaximumFlowRate(outdoor_air.to_f)
  exhaust_fan.addToThermalZone(zone)
end
add_sys3_and_8_zone_equip(air_loop, baseboard_type, hw_loop, model, zone) click to toggle source
# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_3_and_8_single_speed.rb, line 193
def add_sys3_and_8_zone_equip(air_loop,
                              baseboard_type,
                              hw_loop, model,
                              zone)
  always_on = model.alwaysOnDiscreteSchedule
  diffuser = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, always_on)
  air_loop.addBranchForZone(zone, diffuser.to_StraightComponent)
  add_zone_baseboards(baseboard_type: baseboard_type, hw_loop: hw_loop, model: model, zone: zone)
end
add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating_single_speed(model:, zones:, heating_coil_type:, baseboard_type:, hw_loop:, new_auto_zoner: true, necb_reference_hp: false, necb_reference_hp_supp_fuel: 'DefaultFuel') click to toggle source

Some tests still require a simple way to set up a system without sizing.. so we are keeping the auto_zoner flag for this method.

# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_3_and_8_single_speed.rb, line 4
def add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating_single_speed(model:,
                                                                                       zones:,
                                                                                       heating_coil_type:,
                                                                                       baseboard_type:,
                                                                                       hw_loop:,
                                                                                       new_auto_zoner: true,
                                                                                       necb_reference_hp: false,
                                                                                       necb_reference_hp_supp_fuel: 'DefaultFuel')

  system_data = {}
  system_data[:name] = 'Sys_3_PSZ'
  system_data[:CentralCoolingDesignSupplyAirTemperature] = 13.0
  system_data[:CentralHeatingDesignSupplyAirTemperature] = 43.0
  system_data[:AllOutdoorAirinCooling] = false
  system_data[:AllOutdoorAirinHeating] = false
  system_data[:TypeofLoadtoSizeOn] = 'Sensible'
  system_data[:MinimumSystemAirFlowRatio] = 1.0

  system_data[:PreheatDesignTemperature] = 7.0
  system_data[:PreheatDesignHumidityRatio] = 0.008
  system_data[:PrecoolDesignTemperature] = 13.0
  system_data[:PrecoolDesignHumidityRatio] = 0.008
  system_data[:SizingOption] = 'NonCoincident'
  system_data[:CoolingDesignAirFlowMethod] = 'DesignDay'
  system_data[:CoolingDesignAirFlowRate] = 0.0
  system_data[:HeatingDesignAirFlowMethod] = 'DesignDay'
  system_data[:HeatingDesignAirFlowRate] = 0.0
  system_data[:SystemOutdoorAirMethod] = 'ZoneSum'
  system_data[:CentralCoolingDesignSupplyAirHumidityRatio] = 0.0085
  system_data[:CentralHeatingDesignSupplyAirHumidityRatio] = 0.0080

  # System 3 Zone data
  system_data[:ZoneCoolingDesignSupplyAirTemperatureInputMethod] = 'TemperatureDifference'
  system_data[:ZoneCoolingDesignSupplyAirTemperatureDifference] = 11.0
  system_data[:ZoneHeatingDesignSupplyAirTemperatureInputMethod] = 'TemperatureDifference'
  system_data[:ZoneHeatingDesignSupplyAirTemperatureDifference] = 21.0
  system_data[:SetpointManagerSingleZoneReheatSupplyTempMin] = 13.0
  system_data[:SetpointManagerSingleZoneReheatSupplyTempMax] = 43.0
  system_data[:ZoneDXCoolingSizingFactor] = 1.0
  system_data[:ZoneDXHeatingSizingFactor] = 1.3
  system_data[:ZoneCoolingSizingFactor] = 1.1
  system_data[:ZoneHeatingSizingFactor] = 1.3
  system_data[:MinimumOutdoorDryBulbTemperatureforCompressorOperation] = -10.0

  if new_auto_zoner == true
    # Create system airloop

    # Add Air Loop
    air_loop = add_system_3_and_8_airloop(heating_coil_type,
                                          model,
                                          system_data,
                                          determine_control_zone(zones))
    # Add Zone equipment
    zones.each do |zone| # Zone sizing temperature
      sizing_zone = zone.sizingZone
      sizing_zone.setZoneCoolingDesignSupplyAirTemperatureInputMethod(system_data[:ZoneCoolingDesignSupplyAirTemperatureInputMethod])
      sizing_zone.setZoneCoolingDesignSupplyAirTemperatureDifference(system_data[:ZoneCoolingDesignSupplyAirTemperatureDifference])
      sizing_zone.setZoneHeatingDesignSupplyAirTemperatureInputMethod(system_data[:ZoneHeatingDesignSupplyAirTemperatureInputMethod])
      sizing_zone.setZoneHeatingDesignSupplyAirTemperatureDifference(system_data[:ZoneHeatingDesignSupplyAirTemperatureDifference])
      sizing_zone.setZoneCoolingSizingFactor(system_data[:ZoneCoolingSizingFactor])
      sizing_zone.setZoneHeatingSizingFactor(system_data[:ZoneHeatingSizingFactor])
      add_sys3_and_8_zone_equip(air_loop,
                                baseboard_type,
                                hw_loop,
                                model,
                                zone)
    end
  else
    zones.each do |zone|
      air_loop = add_system_3_and_8_airloop(heating_coil_type, model, system_data, zone)
      add_sys3_and_8_zone_equip(air_loop,
                                baseboard_type,
                                hw_loop,
                                model,
                                zone)
    end
  end

  # Modifying airloop name.
  sys_name_pars = {}
  sys_name_pars['sys_hr'] = 'none'
  sys_name_pars['sys_clg'] = 'dx'
  sys_name_pars['sys_htg'] = heating_coil_type
  sys_name_pars['sys_sf'] = 'cv'
  sys_name_pars['zone_htg'] = baseboard_type
  sys_name_pars['zone_clg'] = 'none'
  sys_name_pars['sys_rf'] = 'none'
  assign_base_sys_name(air_loop,
                       sys_abbr: 'sys_3',
                       sys_oa: 'mixed',
                       sys_name_pars: sys_name_pars)
  return true
end
add_sys4_single_zone_make_up_air_unit_with_baseboard_heating(model:, zones:, heating_coil_type:, baseboard_type:, hw_loop:, necb_reference_hp:false, necb_reference_hp_supp_fuel:'DefaultFuel') click to toggle source
# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_4.rb, line 2
def add_sys4_single_zone_make_up_air_unit_with_baseboard_heating(model:,
                                                                 zones:,
                                                                 heating_coil_type:,
                                                                 baseboard_type:,
                                                                 hw_loop:,
                                                                 necb_reference_hp:false,
                                                                 necb_reference_hp_supp_fuel:'DefaultFuel')
  system_data = {}
  system_data[:name] = 'Sys_4_PSZ'
  system_data[:CentralCoolingDesignSupplyAirTemperature] = 13.0
  system_data[:CentralHeatingDesignSupplyAirTemperature] = 43.0
  system_data[:AllOutdoorAirinCooling] = false
  system_data[:AllOutdoorAirinHeating] = false
  # Setting system 4 airloops in BTAPPRE1980 and BTAP1980TO2010 buildings to size by ventilation requirement rather
  # than cooling or heating load.
  system_data[:TypeofLoadtoSizeOn] = 'VentilationRequirement'
  system_data[:MinimumSystemAirFlowRatio] = 1.0

  system_data[:PreheatDesignTemperature] = 7.0
  system_data[:PreheatDesignHumidityRatio] = 0.008
  system_data[:PrecoolDesignTemperature] = 13.0
  system_data[:PrecoolDesignHumidityRatio] = 0.008
  system_data[:SizingOption] = 'NonCoincident'
  system_data[:CoolingDesignAirFlowMethod] = 'DesignDay'
  system_data[:CoolingDesignAirFlowRate] = 0.0
  system_data[:HeatingDesignAirFlowMethod] = 'DesignDay'
  system_data[:HeatingDesignAirFlowRate] = 0.0
  system_data[:SystemOutdoorAirMethod] = 'ZoneSum'
  system_data[:CentralCoolingDesignSupplyAirHumidityRatio] = 0.0085
  system_data[:CentralHeatingDesignSupplyAirHumidityRatio] = 0.0080

  # zone
  system_data[:SetpointManagerSingleZoneReheatSupplyTempMax] = 43.0
  system_data[:SetpointManagerSingleZoneReheatSupplyTempMin] = 13.0
  system_data[:ZoneCoolingDesignSupplyAirTemperatureInputMethod] = 'TemperatureDifference'
  system_data[:ZoneCoolingDesignSupplyAirTemperatureDifference] = 11.0
  system_data[:ZoneHeatingDesignSupplyAirTemperatureInputMethod] = 'TemperatureDifference'
  system_data[:ZoneHeatingDesignSupplyAirTemperatureDifference] = 21.0
  system_data[:ZoneCoolingSizingFactor] = 1.1
  system_data[:ZoneHeatingSizingFactor] = 1.3

  # System Type 4: PSZ-AC
  # This measure creates:
  # -a constant volume packaged single-zone A/C unit
  # for each zone in the building; DX cooling with
  # heating coil: fuel-fired or electric, depending on argument heating_coil_type
  # heating_coil_type choices are "Electric", "Gas"
  # zone baseboards: hot water or electric, depending on argument baseboard_type
  # baseboard_type choices are "Hot Water" or "Electric"
  # boiler_fueltype choices match OS choices for Boiler component fuel type, i.e.
  # "NaturalGas","Electricity","PropaneGas","FuelOilNo1","FuelOilNo2","Coal","Diesel","Gasoline","OtherFuel1"
  # NOTE: This is the same as system type 3 (single zone make-up air unit and single zone rooftop unit are both PSZ systems)
  # SHOULD WE COMBINE sys3 and sys4 into one script?
  #
  # control_zone = determine_control_zone(zones)
  # Todo change this when control zone method is working.
  control_zone = zones.first

  always_on = model.alwaysOnDiscreteSchedule

  # Create a PSZ for each zone
  # TO DO: need to apply this system to space types:
  # (1) automotive area: repair/parking garage, fire engine room, indoor truck bay
  # (2) supermarket/food service: food preparation with kitchen hood/vented appliance
  # (3) warehouse area (non-refrigerated spaces)

  air_loop = common_air_loop(model: model, system_data: system_data)
  air_loop.setName("#{system_data[:name]}_#{control_zone.name}")

  # Zone sizing temperature
  sizing_zone = control_zone.sizingZone
  sizing_zone.setZoneCoolingDesignSupplyAirTemperatureInputMethod(system_data[:ZoneCoolingDesignSupplyAirTemperatureInputMethod])
  sizing_zone.setZoneCoolingDesignSupplyAirTemperatureDifference(system_data[:ZoneCoolingDesignSupplyAirTemperatureDifference])
  sizing_zone.setZoneHeatingDesignSupplyAirTemperatureInputMethod(system_data[:ZoneHeatingDesignSupplyAirTemperatureInputMethod])
  sizing_zone.setZoneHeatingDesignSupplyAirTemperatureDifference(system_data[:ZoneHeatingDesignSupplyAirTemperatureDifference])
  sizing_zone.setZoneCoolingSizingFactor(system_data[:ZoneCoolingSizingFactor])
  sizing_zone.setZoneHeatingSizingFactor(system_data[:ZoneHeatingSizingFactor])

  fan = OpenStudio::Model::FanConstantVolume.new(model, always_on)

  if heating_coil_type == 'Electric' # electric coil
    htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model, always_on)
  end

  if heating_coil_type == 'Gas'
    htg_coil = OpenStudio::Model::CoilHeatingGas.new(model, always_on)
  end

  # TO DO: other fuel-fired heating coil types? (not available in OpenStudio/E+ - may need to play with efficiency to mimic other fuel types)

  # Set up DX coil with NECB performance curve characteristics;

  clg_coil = add_onespeed_DX_coil(model, always_on)
  clg_coil.setName('CoilCoolingDXSingleSpeed_dx')

  # oa_controller
  oa_controller = OpenStudio::Model::ControllerOutdoorAir.new(model)
  oa_controller.autosizeMinimumOutdoorAirFlowRate

  # Set mechanical ventilation controller outdoor air to ZoneSum (used to be defaulted to ZoneSum but now should be
  # set explicitly)
  oa_controller.controllerMechanicalVentilation.setSystemOutdoorAirMethod('ZoneSum')

  # oa_system
  oa_system = OpenStudio::Model::AirLoopHVACOutdoorAirSystem.new(model, oa_controller)

  # Add the components to the air loop
  # in order from closest to zone to furthest from zone
  supply_inlet_node = air_loop.supplyInletNode
  fan.addToNode(supply_inlet_node)
  htg_coil.addToNode(supply_inlet_node)
  clg_coil.addToNode(supply_inlet_node)
  oa_system.addToNode(supply_inlet_node)

  # Add a setpoint manager single zone reheat to control the
  # supply air temperature based on the needs of this zone
  setpoint_mgr_single_zone_reheat = OpenStudio::Model::SetpointManagerSingleZoneReheat.new(model)
  setpoint_mgr_single_zone_reheat.setControlZone(control_zone)
  setpoint_mgr_single_zone_reheat.setMinimumSupplyAirTemperature(system_data[:SetpointManagerSingleZoneReheatSupplyTempMin])
  setpoint_mgr_single_zone_reheat.setMaximumSupplyAirTemperature(system_data[:SetpointManagerSingleZoneReheatSupplyTempMax])
  setpoint_mgr_single_zone_reheat.addToNode(air_loop.supplyOutletNode)

  # Create sensible heat exchanger
  #              heat_exchanger = BTAP::Resources::HVAC::Plant::add_hrv(model)
  #              heat_exchanger.setSensibleEffectivenessat100HeatingAirFlow(0.5)
  #              heat_exchanger.setSensibleEffectivenessat75HeatingAirFlow(0.5)
  #              heat_exchanger.setSensibleEffectivenessat100CoolingAirFlow(0.5)
  #              heat_exchanger.setSensibleEffectivenessat75CoolingAirFlow(0.5)
  #              heat_exchanger.setLatentEffectivenessat100HeatingAirFlow(0.0)
  #              heat_exchanger.setLatentEffectivenessat75HeatingAirFlow(0.0)
  #              heat_exchanger.setLatentEffectivenessat100CoolingAirFlow(0.0)
  #              heat_exchanger.setLatentEffectivenessat75CoolingAirFlow(0.0)
  #              heat_exchanger.setSupplyAirOutletTemperatureControl(false)
  #
  #              Connect heat exchanger
  #              oa_node = oa_system.outboardOANode
  #              heat_exchanger.addToNode(oa_node.get)

  exhaust_fan_name = 'Sys_4_zone_exhaust_fan'
  zones.each do |zone|
    sizing_zone = zone.sizingZone
    sizing_zone.setZoneCoolingDesignSupplyAirTemperatureInputMethod(system_data[:ZoneCoolingDesignSupplyAirTemperatureInputMethod])
    sizing_zone.setZoneCoolingDesignSupplyAirTemperatureDifference(system_data[:ZoneCoolingDesignSupplyAirTemperatureDifference])
    sizing_zone.setZoneHeatingDesignSupplyAirTemperatureInputMethod(system_data[:ZoneHeatingDesignSupplyAirTemperatureInputMethod])
    sizing_zone.setZoneHeatingDesignSupplyAirTemperatureDifference(system_data[:ZoneHeatingDesignSupplyAirTemperatureDifference])
    sizing_zone.setZoneCoolingSizingFactor(system_data[:ZoneCoolingSizingFactor])
    sizing_zone.setZoneHeatingSizingFactor(system_data[:ZoneHeatingSizingFactor])
    # Create a diffuser and attach the zone/diffuser pair to the air loop
    # diffuser = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model,always_on)
    diffuser = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, always_on)
    air_loop.addBranchForZone(zone, diffuser.to_StraightComponent)
    add_zone_baseboards(baseboard_type: baseboard_type,
                        hw_loop: hw_loop,
                        model: model,
                        zone: zone)
    add_exhaust_fan(zone: zone, model: model, name: exhaust_fan_name)
  end
  # zone loop

  # Modifying airloop name
  sys_name_pars = {}
  sys_name_pars['sys_hr'] = 'none'
  sys_name_pars['sys_clg'] = 'dx'
  sys_name_pars['sys_htg'] = heating_coil_type
  sys_name_pars['sys_sf'] = 'cv'
  sys_name_pars['zone_htg'] = baseboard_type
  sys_name_pars['zone_clg'] = 'none'
  sys_name_pars['sys_rf'] = 'none'
  assign_base_sys_name(air_loop,
                       sys_abbr: 'sys_4',
                       sys_oa: 'mixed',
                       sys_name_pars: sys_name_pars)

  return true
end
add_sys6_multi_zone_built_up_system_with_baseboard_heating(model:, zones:, heating_coil_type:, baseboard_type:, chiller_type:, fan_type:, hw_loop:) click to toggle source

end add_sys4_single_zone_make_up_air_unit_with_baseboard_heating

# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_6.rb, line 4
def add_sys6_multi_zone_built_up_system_with_baseboard_heating(model:,
                                                               zones:,
                                                               heating_coil_type:,
                                                               baseboard_type:,
                                                               chiller_type:,
                                                               fan_type:,
                                                               hw_loop:)
  # System Type 6: VAV w/ Reheat
  # This measure creates:
  # a single hot water loop with a natural gas or electric boiler or for the building
  # a single chilled water loop with water cooled chiller for the building
  # a single condenser water loop for heat rejection from the chiller
  # a VAV system w/ hot water or electric heating, chilled water cooling, and
  # hot water or electric reheat for each story of the building
  # Arguments:
  # "boiler_fueltype" choices match OS choices for boiler fuel type:
  # "NaturalGas","Electricity","PropaneGas","FuelOilNo1","FuelOilNO2","Coal","Diesel","Gasoline","OtherFuel1"
  # "heating_coil_type": "Electric" or "Hot Water"
  # "baseboard_type": "Electric" and "Hot Water"
  # "chiller_type": "Scroll";"Centrifugal";""Screw";"Reciprocating"
  # "fan_type": "AF_or_BI_rdg_fancurve";"AF_or_BI_inletvanes";"fc_inletvanes";"var_speed_drive"
  #
  system_data = {}
  system_data[:name] = 'Sys_6_VAV with Reheat'
  system_data[:CentralCoolingDesignSupplyAirTemperature] = 13.0
  system_data[:CentralHeatingDesignSupplyAirTemperature] = 20.0
  system_data[:AllOutdoorAirinCooling] = false
  system_data[:AllOutdoorAirinHeating] = false
  system_data[:MinimumSystemAirFlowRatio] = 0.3

  # zone data
  system_data[:max_system_supply_air_temperature] = 43.0
  system_data[:min_system_supply_air_temperature] = 13.0
  system_data[:ZoneCoolingDesignSupplyAirTemperatureInputMethod] = 'TemperatureDifference'
  system_data[:ZoneCoolingDesignSupplyAirTemperatureDifference] = 11.0
  system_data[:ZoneHeatingDesignSupplyAirTemperatureInputMethod] = 'TemperatureDifference'
  system_data[:ZoneHeatingDesignSupplyAirTemperatureDifference] = 21.0
  system_data[:ZoneCoolingSizingFactor] = 1.1
  system_data[:ZoneHeatingSizingFactor] = 1.3
  system_data[:ZoneVAVMinFlowFactorPerFloorArea] = 0.002
  system_data[:ZoneVAVMaxReheatTemp] = 43.0
  system_data[:ZoneVAVDamperAction] = 'Normal'

  always_on = model.alwaysOnDiscreteSchedule

  # Chilled Water Plant

  chw_loop = OpenStudio::Model::PlantLoop.new(model)
  chiller1, chiller2 = setup_chw_loop_with_components(model, chw_loop, chiller_type)

  # Condenser System

  cw_loop = OpenStudio::Model::PlantLoop.new(model)
  ctower = setup_cw_loop_with_components(model, cw_loop, chiller1, chiller2)

  # Make a Packaged VAV w/ PFP Boxes for each story of the building
  model.getBuildingStorys.sort.each do |story|
    unless (OpenstudioStandards::Geometry.building_story_get_thermal_zones(story) & zones).empty?

      air_loop = common_air_loop(model: model, system_data: system_data)
      air_loop.setName('Sys_6_VAV with Reheat')

      supply_fan = OpenStudio::Model::FanVariableVolume.new(model, always_on)
      supply_fan.setName('Sys6 Supply Fan')
      return_fan = OpenStudio::Model::FanVariableVolume.new(model, always_on)
      return_fan.setName('Sys6 Return Fan')

      if heating_coil_type == 'Hot Water'
        htg_coil = OpenStudio::Model::CoilHeatingWater.new(model, always_on)
        hw_loop.addDemandBranchForComponent(htg_coil)
      end
      if heating_coil_type == 'Electric'
        htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model, always_on)
      end

      clg_coil = OpenStudio::Model::CoilCoolingWater.new(model, always_on)
      chw_loop.addDemandBranchForComponent(clg_coil)

      oa_controller = OpenStudio::Model::ControllerOutdoorAir.new(model)
      oa_controller.autosizeMinimumOutdoorAirFlowRate

      # Set mechanical ventilation controller outdoor air to ZoneSum (used to be defaulted to ZoneSum but now should be
      # set explicitly)
      oa_controller.controllerMechanicalVentilation.setSystemOutdoorAirMethod('ZoneSum')

      oa_system = OpenStudio::Model::AirLoopHVACOutdoorAirSystem.new(model, oa_controller)

      # Add the components to the air loop
      # in order from closest to zone to furthest from zone
      supply_inlet_node = air_loop.supplyInletNode
      supply_outlet_node = air_loop.supplyOutletNode
      supply_fan.addToNode(supply_inlet_node)
      htg_coil.addToNode(supply_inlet_node)
      clg_coil.addToNode(supply_inlet_node)
      oa_system.addToNode(supply_inlet_node)
      returnAirNode = oa_system.returnAirModelObject.get.to_Node.get
      return_fan.addToNode(returnAirNode)

      # Add a setpoint manager to control the supply air.  The controller will set the supply air to be the warmest
      # that can still meet the cooling load of the warmest thermal zone it services.  This differs from the NECB
      # which uses a constant 13 C supply air temperature.
      # sat_sch = OpenStudio::Model::ScheduleRuleset.new(model)
      # sat_sch.setName('Supply Air Temp')
      # sat_sch.defaultDaySchedule.setName('Supply Air Temp Default')
      # sat_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), system_data[:system_supply_air_temperature])
      # sat_stpt_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, sat_sch)
      sat_stpt_manager = OpenStudio::Model::SetpointManagerWarmest.new(model)
      sat_stpt_manager.setMaximumSetpointTemperature(system_data[:max_system_supply_air_temperature])
      sat_stpt_manager.setMinimumSetpointTemperature(system_data[:min_system_supply_air_temperature])
      sat_stpt_manager.addToNode(supply_outlet_node)

      # Make a VAV terminal with HW reheat for each zone on this story that is in intersection with the zones array.
      # and hook the reheat coil to the HW loop
      (OpenstudioStandards::Geometry.building_story_get_thermal_zones(story) & zones).each do |zone|
        # Zone sizing parameters
        sizing_zone = zone.sizingZone
        sizing_zone.setZoneCoolingDesignSupplyAirTemperatureInputMethod(system_data[:ZoneCoolingDesignSupplyAirTemperatureInputMethod])
        sizing_zone.setZoneCoolingDesignSupplyAirTemperatureDifference(system_data[:ZoneCoolingDesignSupplyAirTemperatureDifference])
        sizing_zone.setZoneHeatingDesignSupplyAirTemperatureInputMethod(system_data[:ZoneHeatingDesignSupplyAirTemperatureInputMethod])
        sizing_zone.setZoneHeatingDesignSupplyAirTemperatureDifference(system_data[:ZoneHeatingDesignSupplyAirTemperatureDifference])
        sizing_zone.setZoneCoolingSizingFactor(system_data[:ZoneCoolingSizingFactor])
        sizing_zone.setZoneHeatingSizingFactor(system_data[:ZoneHeatingSizingFactor])

        if heating_coil_type == 'Hot Water'
          reheat_coil = OpenStudio::Model::CoilHeatingWater.new(model, always_on)
          hw_loop.addDemandBranchForComponent(reheat_coil)
        elsif heating_coil_type == 'Electric'
          reheat_coil = OpenStudio::Model::CoilHeatingElectric.new(model, always_on)
        end

        vav_terminal = OpenStudio::Model::AirTerminalSingleDuctVAVReheat.new(model, always_on, reheat_coil)
        air_loop.addBranchForZone(zone, vav_terminal.to_StraightComponent)
        # NECB2011 minimum zone airflow setting
        vav_terminal.setFixedMinimumAirFlowRate(system_data[:ZoneVAVMinFlowFactorPerFloorArea] * zone.floorArea)
        vav_terminal.setMaximumReheatAirTemperature(system_data[:ZoneVAVMaxReheatTemp])
        vav_terminal.setDamperHeatingAction(system_data[:ZoneVAVDamperAction])

        # Set zone baseboards
        add_zone_baseboards(model: model,
                            zone: zone,
                            baseboard_type: baseboard_type,
                            hw_loop: hw_loop)
      end

      # Modifying airloop name.
      sys_name_pars = {}
      sys_name_pars['sys_hr'] = 'none'
      sys_name_pars['sys_htg'] = heating_coil_type
      sys_name_pars['sys_clg'] = 'Chilled Water'
      sys_name_pars['sys_sf'] = 'vv'
      sys_name_pars['zone_htg'] = baseboard_type
      sys_name_pars['zone_clg'] = 'none'
      sys_name_pars['sys_rf'] = 'vv'
      assign_base_sys_name(air_loop,
                           sys_abbr: 'sys_6',
                           sys_oa: 'mixed',
                           sys_name_pars: sys_name_pars)
    end
  end
  # next story

  # for debugging
  # puts "end add_sys6_multi_zone_built_up_with_baseboard_heating"

  return true
end
add_system_3_and_8_airloop(heating_coil_type, model, system_data, control_zone) click to toggle source
# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_3_and_8_single_speed.rb, line 98
def add_system_3_and_8_airloop(heating_coil_type, model, system_data, control_zone)
  # System Type 3: PSZ-AC
  # This measure creates:
  # -a constant volume packaged single-zone A/C unit
  # for each zone in the building; DX cooling with
  # heating coil: fuel-fired or electric, depending on argument heating_coil_type
  # heating_coil_type choices are "Electric", "Gas", "DX"
  # zone baseboards: hot water or electric, depending on argument baseboard_type
  # baseboard_type choices are "Hot Water" or "Electric"
  # boiler_fueltype choices match OS choices for Boiler component fuel type, i.e.
  # "NaturalGas","Electricity","PropaneGas","FuelOilNo1","FuelOilNo2","Coal","Diesel","Gasoline","OtherFuel1"
  # For BTAPPRE1980 (and BTAP1980TO2010 which is created from BTAPPRE1980) add a constant speed return fan

  always_on = model.alwaysOnDiscreteSchedule
  air_loop = common_air_loop(model: model, system_data: system_data)
  air_loop.setName("#{system_data[:name]} #{control_zone.name}")

  # Zone sizing temperature
  sizing_zone = control_zone.sizingZone
  sizing_zone.setZoneCoolingDesignSupplyAirTemperatureInputMethod(system_data[:ZoneCoolingDesignSupplyAirTemperatureInputMethod])
  sizing_zone.setZoneCoolingDesignSupplyAirTemperatureDifference(system_data[:ZoneCoolingDesignSupplyAirTemperatureDifference])
  sizing_zone.setZoneHeatingDesignSupplyAirTemperatureInputMethod(system_data[:ZoneHeatingDesignSupplyAirTemperatureInputMethod])
  sizing_zone.setZoneHeatingDesignSupplyAirTemperatureDifference(system_data[:ZoneHeatingDesignSupplyAirTemperatureDifference])
  sizing_zone.setZoneCoolingSizingFactor(system_data[:ZoneCoolingSizingFactor])
  sizing_zone.setZoneHeatingSizingFactor(system_data[:ZoneHeatingSizingFactor])

  fan = OpenStudio::Model::FanConstantVolume.new(model, always_on)

  # Create a return fan for BTAPPRE1980 system 3 systems
  return_fan = OpenStudio::Model::FanConstantVolume.new(model, always_on)
  return_fan.setName('Sys3 Return Fan')
  return_fan.setEndUseSubcategory('Return_Fan')

  case heating_coil_type
  when 'Electric' # electric coil
    htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model, always_on)
  when 'Gas'
    htg_coil = OpenStudio::Model::CoilHeatingGas.new(model, always_on)
  when 'DX'
    htg_coil = OpenStudio::Model::CoilHeatingDXSingleSpeed.new(model)
    supplemental_htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model, always_on)
    htg_coil.setMinimumOutdoorDryBulbTemperatureforCompressorOperation(system_data[:MinimumOutdoorDryBulbTemperatureforCompressorOperation])
    sizing_zone.setZoneHeatingSizingFactor(system_data[:ZoneDXHeatingSizingFactor])
    sizing_zone.setZoneCoolingSizingFactor(system_data[:ZoneDXCoolingSizingFactor])
  else
    raise("#{heating_coil_type} is not a valid heating coil type.)")
  end

  # TO DO: other fuel-fired heating coil types? (not available in OpenStudio/E+ - may need to play with efficiency to mimic other fuel types)

  # Set up DX coil with NECB performance curve characteristics;
  clg_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model)
  clg_coil.setName('CoilCoolingDXSingleSpeed_dx')

  # oa_controller
  oa_controller = OpenStudio::Model::ControllerOutdoorAir.new(model)
  oa_controller.autosizeMinimumOutdoorAirFlowRate

  # Set mechanical ventilation controller outdoor air to ZoneSum (used to be defaulted to ZoneSum but now should be
  # set explicitly)
  oa_controller.controllerMechanicalVentilation.setSystemOutdoorAirMethod('ZoneSum')

  # oa_system
  oa_system = OpenStudio::Model::AirLoopHVACOutdoorAirSystem.new(model, oa_controller)

  # Add the components to the air loop
  # in order from closest to zone to furthest from zone
  supply_inlet_node = air_loop.supplyInletNode
  if heating_coil_type == 'DX'
    air_to_air_heatpump = OpenStudio::Model::AirLoopHVACUnitaryHeatPumpAirToAir.new(model, always_on, fan, htg_coil, clg_coil, supplemental_htg_coil)
    air_to_air_heatpump.setName("#{control_zone.name} ASHP")
    air_to_air_heatpump.setControllingZone(control_zone)
    air_to_air_heatpump.setSupplyAirFanOperatingModeSchedule(always_on)
    air_to_air_heatpump.addToNode(supply_inlet_node)
  else
    fan.addToNode(supply_inlet_node)
    htg_coil.addToNode(supply_inlet_node)
    clg_coil.addToNode(supply_inlet_node)
  end
  oa_system.addToNode(supply_inlet_node)

  # Find return air node and add a return air fan to it for BTAPPRE1980 system 3 airloops.
  returnAirNode = oa_system.returnAirModelObject.get.to_Node.get
  return_fan.addToNode(returnAirNode)

  # Add a setpoint manager single zone reheat to control the
  # supply air temperature based on the needs of this zone
  setpoint_mgr_single_zone_reheat = OpenStudio::Model::SetpointManagerSingleZoneReheat.new(model)
  setpoint_mgr_single_zone_reheat.setControlZone(control_zone)
  setpoint_mgr_single_zone_reheat.setMinimumSupplyAirTemperature(system_data[:SetpointManagerSingleZoneReheatSupplyTempMin])
  setpoint_mgr_single_zone_reheat.setMaximumSupplyAirTemperature(system_data[:SetpointManagerSingleZoneReheatSupplyTempMax])
  setpoint_mgr_single_zone_reheat.addToNode(air_loop.supplyOutletNode)
  return air_loop
end
air_loop_hvac_energy_recovery_ventilator_required?(air_loop_hvac, climate_zone) click to toggle source

Check if ERV is required on this airloop.

@param (see economizer_required?) @return [Boolean] Returns true if required, false if not.

# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_systems.rb, line 6
def air_loop_hvac_energy_recovery_ventilator_required?(air_loop_hvac, climate_zone)
  # Do not apply ERV to BTAPPRE1980 buildings.
  erv_required = false
  return erv_required
end
apply_fdwr_srr_daylighting(model:, fdwr_set: -2.0, srr_set: -2.0, necb_hdd: true) click to toggle source

Thermal zones need to be set to determine conditioned spaces when applying fdwr and srr limits.

# fdwr_set/srr_set settings:
# 0-1:  Remove all windows/skylights and add windows/skylights to match this fdwr/srr
# -1:  Remove all windows/skylights and add windows/skylights to match max fdwr/srr from NECB
# -2:  Do not apply any fdwr/srr changes, leave windows/skylights alone (also works for fdwr/srr > 1)
# -3:  Use old method which reduces existing window/skylight size (if necessary) to meet maximum NECB fdwr/srr
# limit
# <-3.1:  Remove all the windows/skylights
# > 1:  Do nothing
# File lib/openstudio-standards/standards/necb/BTAPPRE1980/btap_pre1980.rb, line 56
def apply_fdwr_srr_daylighting(model:, fdwr_set: -2.0, srr_set: -2.0, necb_hdd: true)
  fdwr_set = -2.0 if (fdwr_set == 'NECB_default') || fdwr_set.nil? || (fdwr_set.to_f.round(0) == -1.0)
  srr_set = -2.0 if (srr_set == 'NECB_default') || srr_set.nil? || (srr_set.to_f.round(0) == -1.0)
  fdwr_set = fdwr_set.to_f
  srr_set = srr_set.to_f
  apply_standard_window_to_wall_ratio(model: model, fdwr_set: fdwr_set, necb_hdd: true)
  apply_standard_skylight_to_roof_ratio(model: model, srr_set: srr_set)
  # model_add_daylighting_controls(model) # to be removed after refactor.
end
apply_pump_impeller_efficiency(pump:, motor_eff:) click to toggle source

Set the pump design shaft power per unit flow rate per unit head to incorporate total pump efficiency (adjusted for motor efficiency).

# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_systems.rb, line 219
def apply_pump_impeller_efficiency(pump:, motor_eff:)
  # Get the pump efficiency table from the pump_efficiencies.json
  pump_data = @standards_data['pump_combined_eff']
  pump_info = nil
  # Go through the components of the plant loop the plant is attached to.  Find the type of plant loop based on the
  # equipment in it (e.g. it is a hot water loop if the loop contains a boiler supply component).  Once we know the
  # type of plant loop get the combined pump efficiency from pump_data
  pump.plantLoop.get.supplyComponents.each do |comp|
    obj_type = comp.iddObjectType.valueName.to_s
    break if pump_info == pump_data.find { |plant_pump| plant_pump['components'].find { |component| component.include?(obj_type) } }
  end

  return if pump_info.nil?

  # DesignShaftPowerPerUnitFlowRatePerUnitHead seems to be the inverse of an efficiency so get the inverse efficiency
  # by dividing the motor efficiency from the total pump efficiency.
  inv_impeller_eff = motor_eff / pump_info['comb_eff'].to_f
  pump.setDesignShaftPowerPerUnitFlowRatePerUnitHead(inv_impeller_eff)
end
apply_standard_construction_properties( model:, runner: nil, ext_wall_cond: nil, ext_floor_cond: nil, ext_roof_cond: nil, ground_wall_cond: nil, ground_floor_cond: nil, ground_roof_cond: nil, door_construction_cond: nil, fixed_window_cond: nil, glass_door_cond: nil, overhead_door_cond: nil, skylight_cond: nil, glass_door_solar_trans: nil, fixed_wind_solar_trans: nil, skylight_solar_trans: nil, necb_hdd: true ) click to toggle source

Go through the default construction sets and hard-assigned constructions. Clone the existing constructions and set their intended surface type and standards construction type per the PRM. For some standards, this will involve making modifications. For others, it will not.

90.1-2007, 90.1-2010, 90.1-2013 @return [Boolean] returns true if successful, false if not

# File lib/openstudio-standards/standards/necb/BTAPPRE1980/building_envelope.rb, line 161
def apply_standard_construction_properties(
  model:,
  runner: nil,
  ext_wall_cond: nil,
  ext_floor_cond: nil,
  ext_roof_cond: nil,
  ground_wall_cond: nil,
  ground_floor_cond: nil,
  ground_roof_cond: nil,
  door_construction_cond: nil,
  fixed_window_cond: nil,
  glass_door_cond: nil,
  overhead_door_cond: nil,
  skylight_cond: nil,
  glass_door_solar_trans: nil,
  fixed_wind_solar_trans: nil,
  skylight_solar_trans: nil,
  necb_hdd: true
)
  # this call should be removed for a more general application.
  model.getDefaultConstructionSets.sort.each do |set|
    # Set the SHGC of the default glazing material before making new constructions based on it and changing U-values.
    assign_SHGC_to_windows(model: model, default_construction_set: set, necb_hdd: necb_hdd)
  end
  super(model: model,
        runner: runner,
        ext_wall_cond: ext_wall_cond,
        ext_floor_cond: ext_floor_cond,
        ext_roof_cond: ext_roof_cond,
        ground_wall_cond: ground_wall_cond,
        ground_floor_cond: ground_floor_cond,
        ground_roof_cond: ground_roof_cond,
        door_construction_cond: door_construction_cond,
        fixed_window_cond: fixed_window_cond,
        glass_door_cond: glass_door_cond,
        overhead_door_cond: overhead_door_cond,
        skylight_cond: skylight_cond,
        glass_door_solar_trans: glass_door_solar_trans,
        fixed_wind_solar_trans: fixed_wind_solar_trans,
        skylight_solar_trans: skylight_solar_trans,
        necb_hdd: necb_hdd)
end
apply_standard_efficiencies(model:, sizing_run_dir:, dcv_type: 'NECB_Default', necb_reference_hp:false) click to toggle source
# File lib/openstudio-standards/standards/necb/BTAPPRE1980/btap_pre1980.rb, line 66
def apply_standard_efficiencies(model:, sizing_run_dir:, dcv_type: 'NECB_Default', necb_reference_hp:false)
  raise('validation of model failed.') unless validate_initial_model(model)

  climate_zone = 'NECB HDD Method'
  raise("sizing run 1 failed! check #{sizing_run_dir}") if model_run_sizing_run(model, "#{sizing_run_dir}/plant_loops") == false

  # This is needed for NECB2011 as a workaround for sizing the reheat boxes
  model.getAirTerminalSingleDuctVAVReheats.each { |iobj| air_terminal_single_duct_vav_reheat_set_heating_cap(iobj) }
  # Apply the prototype HVAC assumptions
  model_apply_prototype_hvac_assumptions(model, nil, climate_zone)
  # Apply the HVAC efficiency standard
  sql_db_vars_map = {}
  model_apply_hvac_efficiency_standard(model, climate_zone, sql_db_vars_map: sql_db_vars_map)
  model_enable_demand_controlled_ventilation(model, dcv_type)
  model_apply_existing_building_fan_performance(model: model)
  return sql_db_vars_map
end
apply_standard_skylight_to_roof_ratio(model:, srr_set: -1.0) click to toggle source

Reduces the SRR to the values specified by the PRM. SRR reduction will be done by shrinking vertices toward the centroid.

# File lib/openstudio-standards/standards/necb/BTAPPRE1980/building_envelope.rb, line 28
def apply_standard_skylight_to_roof_ratio(model:, srr_set: -1.0)
  # If srr_set is between 1.0 and 1.2 set it to the maximum allowed by the NECB.  If srr_set is between 0.0 and 1.0
  # apply whatever was passed.  If srr_set >= 1.2 then set the existing srr of the building to be the necb maximum
  # only if the the srr exceeds this maximum (otherwise leave it to be whatever was modeled).

  # srr_set settings:
  # 0-1:  Remove all skylights and add skylights to match this srr
  # -1:  Remove all skylights and add skylights to match max srr from NECB
  # -2:  Do not apply any srr changes, leave skylights alone (also works for srr > 1)
  # -3:  Use old method which reduces existing skylight size (if necessary) to meet maximum NECB skylight limit
  # <-3.1:  Remove all the skylights
  # > 1:  Do nothing

  return if srr_set.to_f > 1.0
  return apply_max_srr_nrcan(model: model, srr_lim: srr_set.to_f) if srr_set.to_f >= 0.0 && srr_set <= 1.0

  # No skylights set for BTAPPRE1980 buildings.
  return if srr_set.to_f >= -1.1 && srr_set <= -0.9
  return if srr_set.to_f >= -2.1 && srr_set <= -1.9
  return apply_max_srr_nrcan(model: model, srr_lim: srr_set.to_f) if srr_set < -3.1

  # Continue with the rest of this method, use old method which reduces existing skylight size (if necessary) to
  # meet maximum srr limit
  return unless srr_set.to_f >= -3.1 && srr_set <= -2.9

  # SRR limit
  srr_lim = get_standards_constant('skylight_to_roof_ratio_max_value') * 100.0

  # Loop through all spaces in the model, and
  # per the PNNL PRM Reference Manual, find the areas
  # of each space conditioning category (res, nonres, semi-heated)
  # separately.  Include space multipliers.
  nr_wall_m2 = 0.001 # Avoids divide by zero errors later
  nr_sky_m2 = 0
  res_wall_m2 = 0.001
  res_sky_m2 = 0
  sh_wall_m2 = 0.001
  sh_sky_m2 = 0
  total_roof_m2 = 0.001
  total_subsurface_m2 = 0
  model.getSpaces.sort.each do |space|
    # Loop through all surfaces in this space
    wall_area_m2 = 0
    sky_area_m2 = 0
    space.surfaces.sort.each do |surface|
      # Skip non-outdoor surfaces
      next unless surface.outsideBoundaryCondition == 'Outdoors'

      # Skip non-walls
      next unless surface.surfaceType == 'RoofCeiling'

      # This wall's gross area (including skylight area)
      wall_area_m2 += surface.grossArea * space.multiplier
      # Subsurfaces in this surface
      surface.subSurfaces.sort.each do |ss|
        sky_area_m2 += ss.netArea * space.multiplier
      end
    end

    # Determine the space category
    cat = 'NonRes'
    if OpenstudioStandards::Space.space_residential?(space)
      cat = 'Res'
    end
    # if space.is_semiheated
    # cat = 'Semiheated'
    # end

    # Add to the correct category
    case cat
    when 'NonRes'
      nr_wall_m2 += wall_area_m2
      nr_sky_m2 += sky_area_m2
    when 'Res'
      res_wall_m2 += wall_area_m2
      res_sky_m2 += sky_area_m2
    when 'Semiheated'
      sh_wall_m2 += wall_area_m2
      sh_sky_m2 += sky_area_m2
    end
    total_roof_m2 += wall_area_m2
    total_subsurface_m2 += sky_area_m2
  end

  # Calculate the SRR of each category
  srr_nr = ((nr_sky_m2 / nr_wall_m2) * 100).round(1)
  srr_res = ((res_sky_m2 / res_wall_m2) * 100).round(1)
  srr_sh = ((sh_sky_m2 / sh_wall_m2) * 100).round(1)
  srr = ((total_subsurface_m2 / total_roof_m2) * 100.0).round(1)
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "The skylight to roof ratios (SRRs) are: NonRes: #{srr_nr.round}%, Res: #{srr_res.round}%.")

  # Check against SRR limit
  red_nr = srr_nr > srr_lim
  red_res = srr_res > srr_lim
  red_sh = srr_sh > srr_lim

  # Stop here unless windows need reducing
  return true unless srr > srr_lim

  OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "Reducing the size of all windows (by raising sill height) to reduce window area down to the limit of #{srr_lim.round}%.")
  # Determine the factors by which to reduce the window / door area
  mult = srr_lim / srr

  # Reduce the subsurface areas
  model.getSpaces.sort.each do |space|
    # Loop through all surfaces in this space
    space.surfaces.sort.each do |surface|
      # Skip non-outdoor surfaces
      next unless surface.outsideBoundaryCondition == 'Outdoors'
      # Skip non-walls
      next unless surface.surfaceType == 'RoofCeiling'

      # Subsurfaces in this surface
      surface.subSurfaces.sort.each do |ss|
        # Reduce the size of the subsurface
        red = 1.0 - mult
        OpenstudioStandards::Geometry.sub_surface_reduce_area_by_percent_by_shrinking_toward_centroid(ss, red)
      end
    end
  end

  return true
end
apply_standard_window_to_wall_ratio(model:, fdwr_set: -1.0, necb_hdd: true) click to toggle source

Reduces the WWR to the values specified by the NECB NECB 3.2.1.4

# File lib/openstudio-standards/standards/necb/BTAPPRE1980/building_envelope.rb, line 4
def apply_standard_window_to_wall_ratio(model:, fdwr_set: -1.0, necb_hdd: true)
  # NECB FDWR limit
  hdd = get_necb_hdd18(model: model, necb_hdd: necb_hdd)

  # Get the maximum NECB fdwr
  # fdwr_set settings:
  # 0-1:  Remove all windows and add windows to match this fdwr
  # -1:  Remove all windows and add windows to match max fdwr from NECB
  # -2:  Do not apply any fdwr changes, leave windows alone (also works for fdwr > 1)
  # -3:  Use old method which reduces existing window size (if necessary) to meet maximum NECB fdwr limit
  # <-3.1:  Remove all the windows
  # > 1:  Do nothing

  return if fdwr_set.to_f > 1.0
  return apply_max_fdwr_nrcan(model: model, fdwr_lim: fdwr_set.to_f) if fdwr_set.to_f >= 0.0 && fdwr_set <= 1.0
  return if fdwr_set.to_f >= -1.1 && fdwr_set <= -0.9
  return if fdwr_set.to_f >= -2.1 && fdwr_set <= -1.9
  return apply_limit_fdwr(model: model, fdwr_lim: (max_fwdr(hdd) * 100.0).to_f.round(1)) if fdwr_set.to_f >= -3.1 && fdwr_set <= -2.9
  return apply_max_fdwr_nrcan(model: model, fdwr_lim: fdwr_set.to_f) if fdwr_set < -3.1
end
assign_SHGC_to_windows(model:, default_construction_set:, necb_hdd: true) click to toggle source
# File lib/openstudio-standards/standards/necb/BTAPPRE1980/building_envelope.rb, line 204
def assign_SHGC_to_windows(model:, default_construction_set:, necb_hdd: true)
  # Get HDD to determine which SHGC to use
  hdd = get_necb_hdd18(model: model, necb_hdd: necb_hdd)
  # Determine the solar heat gain coefficient from the standards data
  shgc_table = @standards_data['SHGC']
  shgc = eval(shgc_table[0]['formula'])
  # Find the default window construction material
  sub_surf_consts = default_construction_set.defaultExteriorSubSurfaceConstructions.get
  fixed_window_material = OpenStudio::Model.getConstructionByName(model, sub_surf_consts.fixedWindowConstruction.get.name.to_s).get.getLayer(0).to_SimpleGlazing.get
  # Reset the SHGC for the window material.  When I wrote this all of the windows, doors etc. used the same window
  # material.  So I set the SHGC for that material expecting it will be modified for all of the other constructions
  # too.
  fixed_window_material.setSolarHeatGainCoefficient(shgc.to_f)
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 from MNECB Supplement 5.4.8.3.

@return [Boolean] true if successful, false if not

# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_systems.rb, line 15
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)

  if (capacity_w / 1000.0) <= 700.0
    # As per MNECB if chiller capacity <= 700 kW the compressor should be reciprocating so change the type here in
    # the name, compressor_type and search_criteria which is where the compressor type is used.
    search_criteria['compressor_type'] = 'Reciprocating'
    compressor_type = search_criteria['compressor_type']
    chiller_electric_eir = replace_compressor_name(chiller: chiller_electric_eir, comp_type: compressor_type, chillers: chillers)
    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
  elsif ((capacity_w / 1000.0) > 700.0) && ((capacity_w / 1000.0) <= 2100.0)
    # As per MNECB if chiller capacity > 700 kW the compressor should be centrifugal so change the type here in
    # the name, compressor_type and search_criteria which is where the compressor type is used.
    search_criteria['compressor_type'] = 'Centrifugal'
    compressor_type = search_criteria['compressor_type']
    chiller_electric_eir = replace_compressor_name(chiller: chiller_electric_eir, comp_type: compressor_type, chillers: chillers)
    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
    search_criteria['compressor_type'] = 'Centrifugal'
    compressor_type = search_criteria['compressor_type']
    chiller_electric_eir = replace_compressor_name(chiller: chiller_electric_eir, comp_type: compressor_type, chillers: chillers)
    chiller_capacity = capacity_w / 2.0
  end
  chiller_electric_eir.setReferenceCapacity(chiller_capacity)

  # Convert capacity to tons
  capacity_tons = OpenStudio.convert(chiller_capacity, 'W', 'ton').get

  # Get the chiller properties
  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['cop']
    cop = chlr_props['cop']
    kw_per_ton = cop_to_kw_per_ton(cop)
    chiller_electric_eir.setReferenceCOP(cop)
  elsif !chlr_props['cop'] && 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.015 * 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
get_fan_chars(fan_type:, motor_type: nil, press_rise:) click to toggle source

This method gets the required fan performance characteristics. It would probably be better to change the appropriate methods in standards or prototype or create another class but I did this here for expediency. The method looks for: -the total fan efficiency in fans.json (a custom json just for BTAP vintage files) -the motor efficiency (if applicable) in moters.json -the pressure rise in constants.json If the above cannot be found it defaults values (this should not happen). The method return a hash containing the total fan efficiency, motor efficiency and pressure rise.

# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_systems.rb, line 277
def get_fan_chars(fan_type:, motor_type: nil, press_rise:)
  standards_fan_total_efficiency = @standards_data['fans'].select { |standards_fan| standards_fan['fan_type'] == fan_type }
  if standards_fan_total_efficiency.empty?
    fan_total_efficiency = 0.25
    OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.model_apply_existing_building_fan_characteristics', "Cannot find fan data in standards fans data.  Defaulting total fan efficiency to #{fan_total_efficiency}.")
  else
    fan_total_efficiency = standards_fan_total_efficiency[0]['fan_total_efficiency']
  end
  fan_motor_efficiency = nil
  unless motor_type.nil?
    standards_fan_motor_efficiency = @standards_data['motors'].select { |standards_motor| (standards_motor['motor_use'] == 'FAN' && standards_motor['motor_type'] == motor_type) }
    if standards_fan_motor_efficiency.empty?
      fan_motor_efficiency = 0.385
      OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.model_apply_existing_building_fan_characteristics', "Cannot find fan motor data in standards fans data.  Defaulting fan moter efficinecy to #{fan_motor_efficiency}.")
    else
      fan_motor_efficiency = standards_fan_motor_efficiency[0]['nominal_full_load_efficiency']
    end
  end
  fan_pressure_rise = @standards_data['constants'][press_rise]['value']
  if fan_pressure_rise.nil?
    fan_pressure_rise = 150.0
    OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.model_apply_existing_building_fan_characteristics', "Cannot find fan pressure data in constants data.  Defaulting total fan pressure rise to #{fan_pressure_rise}.")
  end
  return {
    total_eff: fan_total_efficiency,
    motor_eff: fan_motor_efficiency,
    press_rise: fan_pressure_rise
  }
end
load_standards_database_new() click to toggle source
Calls superclass method NECB2011#load_standards_database_new
# File lib/openstudio-standards/standards/necb/BTAPPRE1980/btap_pre1980.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
model_apply_existing_building_fan_performance(model:) click to toggle source

Adjust the total efficiency, motor efficiency (if applicable), and pressure rise for fans used in BTAPPRE1980 and BTAP1980TO2010. This probably should be implemented a different way but rather than truly understanding the code I wrote this. So far it applies fan performance to system 3 return fans and to zone exhaust fans which were added to BTAPPRE1980 and BTAP1980TO2010 since they are not used in NECB2011, NECB2015, or NECB2017.

# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_systems.rb, line 243
def model_apply_existing_building_fan_performance(model:)
  ret_fans = model.getFanConstantVolumes.select { |ret_fan| ret_fan.endUseSubcategory.to_s == 'Return_Fan' }
  return if ret_fans.empty?

  fan_type = 'CONSTANT-RETURN'
  motor_type = 'CONSTANT-RETURN'
  pressure_rise = 'return_fan_constant_volume_pressure_rise_value'
  fan_hash = get_fan_chars(fan_type: fan_type, motor_type: motor_type, press_rise: pressure_rise)
  ret_fans.each do |ret_fan|
    ret_fan.setPressureRise(fan_hash[:press_rise].to_f)
    ret_fan.setFanTotalEfficiency(fan_hash[:total_eff].to_f)
    ret_fan.setMotorEfficiency(fan_hash[:motor_eff].to_f)
  end
  exhaust_fans = model.getFanZoneExhausts

  return if exhaust_fans.empty?

  fan_type = 'EXHAUST'
  pressure_rise = 'exhaust_fan_pressure_rise_value'
  fan_hash = get_fan_chars(fan_type: fan_type, press_rise: pressure_rise)
  exhaust_fans.sort.each do |exhaust_fan|
    exhaust_fan.setFanTotalEfficiency(fan_hash[:total_eff])
    exhaust_fan.setPressureRise(fan_hash[:press_rise])
  end
end
new_add_sys6_multi_zone_built_up_system_with_baseboard_heating( model:, zones:, heating_coil_type:, baseboard_type:, chiller_type:, fan_type:, hw_loop: ) click to toggle source
# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_6.rb, line 171
def new_add_sys6_multi_zone_built_up_system_with_baseboard_heating(
  model:,
  zones:,
  heating_coil_type:,
  baseboard_type:,
  chiller_type:,
  fan_type:,
  hw_loop:
)
  # System Type 6: VAV w/ Reheat
  # This measure creates:
  # a single hot water loop with a natural gas or electric boiler or for the building
  # a single chilled water loop with water cooled chiller for the building
  # a single condenser water loop for heat rejection from the chiller
  # a VAV system w/ hot water or electric heating, chilled water cooling, and
  # hot water or electric reheat for each story of the building
  # Arguments:
  # "boiler_fueltype" choices match OS choices for boiler fuel type:
  # "NaturalGas","Electricity","PropaneGas","FuelOilNo1","FuelOilNo2","Coal","Diesel","Gasoline","OtherFuel1"
  # "heating_coil_type": "Electric" or "Hot Water"
  # "baseboard_type": "Electric" and "Hot Water"
  # "chiller_type": "Scroll";"Centrifugal";""Screw";"Reciprocating"
  # "fan_type": "AF_or_BI_rdg_fancurve";"AF_or_BI_inletvanes";"fc_inletvanes";"var_speed_drive"
  system_6_data = {}
  system_6_data[:name] = 'Sys_6_VAV with Reheat'
  system_6_data[:CentralCoolingDesignSupplyAirTemperature] = 13.0
  system_6_data[:CentralHeatingDesignSupplyAirTemperature] = 20.0
  system_6_data[:AllOutdoorAirinCooling] = false
  system_6_data[:AllOutdoorAirinHeating] = false
  system_6_data[:MinimumSystemAirFlowRatio] = 0.03
  # zone data
  system_6_data[:max_system_supply_air_temperature] = 43.0
  system_6_data[:min_system_supply_air_temperature] = 13.0
  system_6_data[:ZoneCoolingDesignSupplyAirTemperatureInputMethod] = 'TemperatureDifference'
  system_6_data[:ZoneCoolingDesignSupplyAirTemperatureDifference] = 11.0
  system_6_data[:ZoneHeatingDesignSupplyAirTemperatureInputMethod] = 'TemperatureDifference'
  system_6_data[:ZoneHeatingDesignSupplyAirTemperatureDifference] = 21.0
  system_6_data[:ZoneCoolingSizingFactor] = 1.1
  system_6_data[:ZoneHeatingSizingFactor] = 1.3
  system_6_data[:ZoneVAVMinFlowFactorPerFloorArea] = 0.002
  system_6_data[:ZoneVAVMaxReheatTemp] = 43.0
  system_6_data[:ZoneVAVDamperAction] = 'Normal'
  system_data = system_6_data

  always_on = model.alwaysOnDiscreteSchedule

  # Chilled Water Plant

  chw_loop = OpenStudio::Model::PlantLoop.new(model)
  chiller1, chiller2 = setup_chw_loop_with_components(model, chw_loop, chiller_type)

  # Condenser System

  cw_loop = OpenStudio::Model::PlantLoop.new(model)
  ctower = setup_cw_loop_with_components(model, cw_loop, chiller1, chiller2)

  # Make a Packaged VAV w/ PFP Boxes for each story of the building
  model.getBuildingStorys.sort.each do |story|
    unless (OpenstudioStandards::Geometry.building_story_get_thermal_zones(story) & zones).empty?

      air_loop = common_air_loop(model: model, system_data: system_data)
      air_loop.setName(system_data[:name])
      air_loop_sizing = air_loop.sizingSystem
      air_loop_sizing.setCentralCoolingDesignSupplyAirTemperature(system_data[:CentralCoolingDesignSupplyAirTemperature])
      air_loop_sizing.setCentralHeatingDesignSupplyAirTemperature(system_data[:CentralHeatingDesignSupplyAirTemperature])
      air_loop_sizing.setAllOutdoorAirinCooling(system_data[:AllOutdoorAirinCooling])
      air_loop_sizing.setAllOutdoorAirinHeating(system_data[:AllOutdoorAirinHeating])
      if model.version < OpenStudio::VersionString.new('2.7.0')
        air_loop_sizing.setMinimumSystemAirFlowRatio(system_data[:MinimumSystemAirFlowRatio]) unless system_data[:MinimumSystemAirFlowRatio].nil?
      else
        air_loop_sizing.setCentralHeatingMaximumSystemAirFlowRatio(system_data[:MinimumSystemAirFlowRatio]) unless system_data[:MinimumSystemAirFlowRatio].nil?
      end

      supply_fan = OpenStudio::Model::FanVariableVolume.new(model, always_on)
      supply_fan.setName('Sys6 Supply Fan')
      return_fan = OpenStudio::Model::FanVariableVolume.new(model, always_on)
      return_fan.setName('Sys6 Return Fan')

      if heating_coil_type == 'Hot Water'
        htg_coil = OpenStudio::Model::CoilHeatingWater.new(model, always_on)
        hw_loop.addDemandBranchForComponent(htg_coil)
      end
      if heating_coil_type == 'Electric'
        htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model, always_on)
      end

      clg_coil = OpenStudio::Model::CoilCoolingWater.new(model, always_on)
      chw_loop.addDemandBranchForComponent(clg_coil)

      oa_controller = OpenStudio::Model::ControllerOutdoorAir.new(model)
      oa_controller.autosizeMinimumOutdoorAirFlowRate

      # Set mechanical ventilation controller outdoor air to ZoneSum (used to be defaulted to ZoneSum but now should be
      # set explicitly)
      oa_controller.controllerMechanicalVentilation.setSystemOutdoorAirMethod('ZoneSum')

      oa_system = OpenStudio::Model::AirLoopHVACOutdoorAirSystem.new(model, oa_controller)

      # Add the components to the air loop
      # in order from closest to zone to furthest from zone
      supply_inlet_node = air_loop.supplyInletNode
      supply_outlet_node = air_loop.supplyOutletNode
      supply_fan.addToNode(supply_inlet_node)
      htg_coil.addToNode(supply_inlet_node)
      clg_coil.addToNode(supply_inlet_node)
      oa_system.addToNode(supply_inlet_node)
      returnAirNode = oa_system.returnAirModelObject.get.to_Node.get
      return_fan.addToNode(returnAirNode)

      # Add a setpoint manager to control the supply air.  The controller will set the supply air to be the warmest
      # that can still meet the cooling load of the warmest thermal zone it services.  This differs from the NECB
      # which uses a constant 13 C supply air temperature.

      # sat_sch = OpenStudio::Model::ScheduleRuleset.new(model)
      # sat_sch.setName('Supply Air Temp')
      # sat_sch.defaultDaySchedule.setName('Supply Air Temp Default')
      # sat_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), system_data[:system_supply_air_temperature])
      sat_stpt_manager = OpenStudio::Model::SetpointManagerWarmest.new(model)
      sat_stpt_manager.setMaximumSetpointTemperature(system_data[:max_system_supply_air_temperature])
      sat_stpt_manager.setMinimumSetpointTemperature(system_data[:min_system_supply_air_temperature])
      sat_stpt_manager.addToNode(supply_outlet_node)

      # Make a VAV terminal with HW reheat for each zone on this story that is in intersection with the zones array.
      # and hook the reheat coil to the HW loop
      (OpenstudioStandards::Geometry.building_story_get_thermal_zones(story) & zones).each do |zone|
        # Zone sizing parameters
        sizing_zone = zone.sizingZone
        sizing_zone.setZoneCoolingDesignSupplyAirTemperatureInputMethod(system_data[:ZoneCoolingDesignSupplyAirTemperatureInputMethod])
        sizing_zone.setZoneCoolingDesignSupplyAirTemperatureDifference(system_data[:ZoneCoolingDesignSupplyAirTemperatureDifference])
        sizing_zone.setZoneHeatingDesignSupplyAirTemperatureInputMethod(system_data[:ZoneHeatingDesignSupplyAirTemperatureInputMethod])
        sizing_zone.setZoneHeatingDesignSupplyAirTemperatureDifference(system_data[:ZoneHeatingDesignSupplyAirTemperatureDifference])
        sizing_zone.setZoneCoolingSizingFactor(system_data[:ZoneCoolingSizingFactor])
        sizing_zone.setZoneHeatingSizingFactor(system_data[:ZoneHeatingSizingFactor])

        if heating_coil_type == 'Hot Water'
          reheat_coil = OpenStudio::Model::CoilHeatingWater.new(model, always_on)
          hw_loop.addDemandBranchForComponent(reheat_coil)
        elsif heating_coil_type == 'Electric'
          reheat_coil = OpenStudio::Model::CoilHeatingElectric.new(model, always_on)
        end

        vav_terminal = OpenStudio::Model::AirTerminalSingleDuctVAVReheat.new(model, always_on, reheat_coil)
        air_loop.addBranchForZone(zone, vav_terminal.to_StraightComponent)
        # NECB2011 minimum zone airflow setting
        vav_terminal.setFixedMinimumAirFlowRate(system_data[:ZoneVAVMinFlowFactorPerFloorArea] * zone.floorArea)
        vav_terminal.setMaximumReheatAirTemperature(system_data[:ZoneVAVMaxReheatTemp])
        vav_terminal.setDamperHeatingAction(system_data[:ZoneVAVDamperAction])

        # Set zone baseboards
        add_zone_baseboards(model: model,
                            zone: zone,
                            baseboard_type: baseboard_type,
                            hw_loop: hw_loop)
      end
    end
  end
  # next story

  # for debugging
  # puts "end add_sys6_multi_zone_built_up_with_baseboard_heating"

  return true
end
pump_standard_minimum_motor_efficiency_and_size(pump, motor_bhp) click to toggle source

Determines the minimum pump motor efficiency and nominal size for a given motor bhp. This should be the total brake horsepower with any desired safety factor already included. This method picks the next nominal motor catgory larger than the required brake horsepower, and the efficiency is based on that size. For example, if the bhp = 6.3, the nominal size will be 7.5HP and the efficiency for 90.1-2010 will be 91.7% from Table 10.8B. This method assumes 4-pole, 1800rpm totally-enclosed fan-cooled motors.

@param motor_bhp [Double] motor brake horsepower (hp) @return [Array<Double>] minimum motor efficiency (0.0 to 1.0), nominal horsepower

# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_systems.rb, line 149
def pump_standard_minimum_motor_efficiency_and_size(pump, motor_bhp)
  motor_eff = 0.85
  nominal_hp = motor_bhp

  # Don't attempt to look up motor efficiency
  # for zero-hp pumps (required for circulation-pump-free
  # service water heating systems).
  return [1.0, 0] if motor_bhp == 0.0

  # Lookup the minimum motor efficiency
  motors = @standards_data['motors']

  # Assuming all pump motors are 4-pole ODP
  search_criteria = {
    'motor_use' => 'PUMP',
    'number_of_poles' => 4.0,
    'type' => 'Enclosed'
  }

  motor_properties = model_find_object(motors, search_criteria, motor_bhp)
  if motor_properties.nil?
    OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Pump', "For #{pump.name}, could not find motor properties using search criteria: #{search_criteria}, motor_bhp = #{motor_bhp} hp.")
    return [motor_eff, nominal_hp]
  end

  motor_eff = motor_properties['nominal_full_load_efficiency']
  nominal_hp = motor_properties['maximum_capacity'].to_f.round(1)
  # Round to nearest whole HP for niceness
  if nominal_hp >= 2
    nominal_hp = nominal_hp.round
  end

  # Get the efficiency based on the nominal horsepower
  # Add 0.01 hp to avoid search errors.
  motor_properties = model_find_object(motors, search_criteria, nominal_hp + 0.01)
  if motor_properties.nil?
    OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Fan', "For #{pump.name}, could not find nominal motor properties using search criteria: #{search_criteria}, motor_hp = #{nominal_hp} hp.")
    return [motor_eff, nominal_hp]
  end
  motor_eff = motor_properties['nominal_full_load_efficiency']

  # Change the pump design shaft power per unit flow rate per unit head to use MNECB combined efficiency values
  apply_pump_impeller_efficiency(pump: pump, motor_eff: motor_eff)
  return [motor_eff, nominal_hp]
end
replace_compressor_name(chiller:, comp_type:, chillers:) click to toggle source

Replace the chiller compressor type in the chiller name.

# File lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_systems.rb, line 196
def replace_compressor_name(chiller:, comp_type:, chillers:)
  # Get the current name.
  chiller_name = chiller.name.to_s
  # Get the unique compressor types from the chiller table (from the chillers.json file.)
  chiller_types = chillers.uniq { |chill_param| chill_param['compressor_type'] }
  new_name = chiller_name
  # Go through each chiller compressor type from the chiller table and see if it is in the chiller name.  If it is,
  # then replace the old compressor type in the name with the new one.
  chlr_name_updated = false
  chiller_types.each do |chill_type|
    if chiller_name.include? chill_type['compressor_type']
      new_name = chiller_name.sub(chill_type['compressor_type'], comp_type)
      chlr_name_updated = true
      break
    end
  end
  new_name = chiller_name + ' ' + comp_type if !chlr_name_updated
  chiller.setName(new_name)
  return chiller
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/BTAPPRE1980/btap_pre1980.rb, line 85
def set_occ_sensor_spacetypes(model, space_type_map)
  return true
end