lib/openstudio-standards/standards/Standards.ZoneHVACComponent.rb in openstudio-standards-0.2.2 vs lib/openstudio-standards/standards/Standards.ZoneHVACComponent.rb in openstudio-standards-0.2.3
- old
+ new
@@ -68,6 +68,140 @@
fan_efficacy_new_w_per_cfm = fan_power_new_w / max_air_flow_rate_cfm
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.ZoneHVACComponent', "For #{zone_hvac_component.name}: fan efficacy set to #{fan_efficacy_new_w_per_cfm.round(2)} W/cfm.")
return true
end
+
+ # Apply all standard required controls to the zone equipment
+ #
+ # @return [Bool] returns true if successful, false if not
+ def zone_hvac_component_apply_standard_controls(zone_hvac_component)
+
+ # Vestibule heating control
+ if zone_hvac_component_vestibule_heating_control_required?(zone_hvac_component)
+ zone_hvac_component_apply_vestibule_heating_control(zone_hvac_component)
+ end
+
+ return true
+ end
+
+ # Determine if vestibule heating control is required.
+ # Defaults to 90.1-2004 through 2010, not required.
+ #
+ # @return [Bool] returns true if successful, false if not
+ def zone_hvac_component_vestibule_heating_control_required?(zone_hvac_component)
+ vest_htg_control_required = false
+ return vest_htg_control_required
+ end
+
+ # Turns off vestibule heating below 45F
+ #
+ # @return [Bool] returns true if successful, false if not
+ def zone_hvac_component_apply_vestibule_heating_control(zone_hvac_component)
+
+ # Ensure that the equipment is assigned to a thermal zone
+ if zone_hvac_component.thermalZone.empty?
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.model.ZoneHVACComponent', "For #{zone_hvac_component.name}: equipment is not assigned to a thermal zone, cannot apply vestibule heating control.")
+ return true
+ end
+
+ # Convert this to the actual class type
+ zone_hvac = if zone_hvac_component.to_ZoneHVACFourPipeFanCoil.is_initialized
+ zone_hvac_component.to_ZoneHVACFourPipeFanCoil.get
+ elsif zone_hvac_component.to_ZoneHVACUnitHeater.is_initialized
+ zone_hvac_component.to_ZoneHVACUnitHeater.get
+ elsif zone_hvac_component.to_ZoneHVACPackagedTerminalAirConditioner.is_initialized
+ zone_hvac_component.to_ZoneHVACPackagedTerminalAirConditioner.get
+ elsif zone_hvac_component.to_ZoneHVACPackagedTerminalHeatPump.is_initialized
+ zone_hvac_component.to_ZoneHVACPackagedTerminalHeatPump.get
+ else
+ nil
+ end
+
+ # Do nothing for other types of zone HVAC equipment
+ if zone_hvac.nil?
+ return true
+ end
+
+ # Get the heating coil and fan
+ htg_coil = zone_hvac.heatingCoil
+ htg_coil = if htg_coil.to_CoilHeatingGas.is_initialized
+ htg_coil.to_CoilHeatingGas.get
+ elsif htg_coil.to_CoilHeatingElectric.is_initialized
+ htg_coil.to_CoilHeatingElectric.get
+ elsif htg_coil.to_CoilHeatingWater.is_initialized
+ htg_coil.to_CoilHeatingWater.get
+ elsif htg_coil.to_CoilHeatingDXSingleSpeed.is_initialized
+ htg_coil.to_CoilHeatingDXSingleSpeed.get
+ end
+
+ fan = zone_hvac.supplyAirFan
+ fan = if fan.to_FanOnOff.is_initialized
+ fan.to_FanOnOff.get
+ elsif fan.to_FanConstantVolume.is_initialized
+ fan.to_FanConstantVolume.get
+ elsif fan.to_FanVariableVolume.is_initialized
+ fan.to_FanVariableVolume.get
+ end
+
+ # Get existing heater availability schedule if present
+ # or create a new one
+ avail_sch = nil
+ avail_sch_name = 'VestibuleHeaterAvailSch'
+ if zone_hvac_component.model.getScheduleConstantByName(avail_sch_name).is_initialized
+ avail_sch = zone_hvac_component.model.getScheduleConstantByName(avail_sch_name).get
+ else
+ avail_sch = OpenStudio::Model::ScheduleConstant.new(zone_hvac_component.model)
+ avail_sch.setName(avail_sch_name)
+ avail_sch.setValue(1)
+ end
+
+ # Replace the existing availabilty schedule with the one
+ # that will be controlled via EMS
+ htg_coil.setAvailabilitySchedule(avail_sch)
+ fan.setAvailabilitySchedule(avail_sch)
+
+ # Clean name of zone HVAC
+ equip_name_clean = zone_hvac.name.get.to_s.gsub(/\W/, '').delete('_')
+ # If the name starts with a number, prepend with a letter
+ if equip_name_clean[0] =~ /[0-9]/
+ equip_name_clean = "EQUIP#{equip_name_clean}"
+ end
+
+ # Sensors
+ # Get existing OAT sensor if present
+ oat_db_c_sen = nil
+ if zone_hvac_component.model.getEnergyManagementSystemSensorByName('OATVestibule').is_initialized
+ oat_db_c_sen = zone_hvac_component.model.getEnergyManagementSystemSensorByName('OATVestibule').get
+ else
+ oat_db_c_sen = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Site Outdoor Air Drybulb Temperature')
+ oat_db_c_sen.setName("OATVestibule")
+ oat_db_c_sen.setKeyName("Environment")
+ end
+
+ # Actuators
+ avail_sch_act = OpenStudio::Model::EnergyManagementSystemActuator.new(avail_sch, 'Schedule:Constant', 'Schedule Value')
+ avail_sch_act.setName("#{equip_name_clean}VestHtgAvailSch")
+
+ # Programs
+ htg_lim_f = 45
+ vestibule_htg_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
+ vestibule_htg_prg.setName("#{equip_name_clean}VestHtgPrg")
+ vestibule_htg_prg_body = <<-EMS
+ IF #{oat_db_c_sen.handle} > #{OpenStudio.convert(htg_lim_f, 'F', 'C').get}
+ SET #{avail_sch_act.handle} = 0
+ ENDIF
+ EMS
+ vestibule_htg_prg.setBody(vestibule_htg_prg_body)
+
+ # Program Calling Managers
+ vestibule_htg_mgr = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
+ vestibule_htg_mgr.setName("#{equip_name_clean}VestHtgMgr")
+ vestibule_htg_mgr.setCallingPoint('BeginTimestepBeforePredictor')
+ vestibule_htg_mgr.addProgram(vestibule_htg_prg)
+
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{zone_hvac_component.name}: Vestibule heating control applied, heating disabled below #{htg_lim_f} F.")
+
+ return true
+ end
+
end