# ERV unit supply mass flow rate greater than Supply FanOnOff mass flow rate

Hello,

I used Energy Management System to control supply and exhaust FanOnOff (which is used in an ERV unit) air mass flow rate using actuator "Fan" with control type "Fan Air Mass Flow Rate". The EMS worked well but the supply and exhaust flow rate of ERV (Energy Recovery Ventilator) unit were not modified with the values of supply and exhaust FanOnOff air mass flow rate. Therefore, I received a value of zone mechanical ventilation mass flow rate which is different than the FanOnOff mass flow rate but is the same as ERV supply and exhaust flow rate predefined at the beginning of the simulation.

Does anybody have an idea for this? Did I make some mistakes here?

Thank you very much

Please find below my EMS snippet:

def arguments(model)
args = OpenStudio::Measure::OSArgumentVector.new

occupation_erv_fan_position = OpenStudio::Measure::OSArgument.makeDoubleArgument('occupation_erv_fan_position', true)
occupation_erv_fan_position.setDisplayName('Position of fan mass flow rate control during occupation period')
occupation_erv_fan_position.setDefaultValue(2)
args << occupation_erv_fan_position

absent_erv_fan_position = OpenStudio::Measure::OSArgument.makeDoubleArgument('absent_erv_fan_position', true)
absent_erv_fan_position.setDisplayName('Position of fan mass flow rate control during absent period')
absent_erv_fan_position.setDefaultValue(1)
args << absent_erv_fan_position

night_erv_fan_position = OpenStudio::Measure::OSArgument.makeDoubleArgument('night_erv_fan_position', true)
night_erv_fan_position.setDisplayName('Position of fan mass flow rate control during night time')
night_erv_fan_position.setDefaultValue(1)
args << night_erv_fan_position

return args
end

def run(model, runner, user_arguments)
super(model, runner, user_arguments)

# use the built-in error checking
if !runner.validateUserArguments(arguments(model), user_arguments)
return false
end

# assign the user inputs to variables
occupation_erv_fan_position = runner.getDoubleArgumentValue('occupation_erv_fan_position', user_arguments).to_f
absent_erv_fan_position = runner.getDoubleArgumentValue('absent_erv_fan_position', user_arguments).to_f
night_erv_fan_position = runner.getDoubleArgumentValue('night_erv_fan_position', user_arguments).to_f

# get thermal zones
thermal_zones = model.getThermalZones

thermal_zones.each do |thermal_zone|

zone_eqpt = thermal_zone.equipment # vector

zone_eqpt.each do |eqpt| # for each equipment

# Zone HVAC Energy Recovery Ventilator
if eqpt.to_ZoneHVACEnergyRecoveryVentilator.is_initialized

# get Energy Recovery Ventilator Unit
erv_unit = eqpt.to_ZoneHVACEnergyRecoveryVentilator.get
erv_supply_mass_flow_rate = TPEEHVACHelper.erv_supply_flow_rate(thermal_zone).to_f*1.204   # supply air flow rate is in m3/s and assuming that air density is of 1.204 kg/m3
erv_exhaust_mass_flow_rate = TPEEHVACHelper.erv_supply_flow_rate(thermal_zone).to_f*1.204 # supply air flow rate is in m3/s and assuming that air density is of 1.204 kg/m3

erv_supplyAirFan = erv_unit.supplyAirFan.to_FanOnOff.get
erv_exhaustAirFan = erv_unit.exhaustAirFan.to_FanOnOff.get

# Create EMS Actuator Objects
erv_supplyAirFan_ems_actuator = OpenStudio::Model::EnergyManagementSystemActuator.new(erv_supplyAirFan,"Fan","Fan Air Mass Flow Rate")
erv_supplyAirFan_ems_actuator.setName("erv_supplyAirFan_ems_actuator_#{thermal_zone.name.to_s}")
runner.registerInfo("EMS Actuator object named '#{erv_supplyAirFan_ems_actuator.name.to_s}' representing the mass flow rate of erv supply air fan named #{erv_supplyAirFan.name.to_s} added to the model.")

erv_exhaustAirFan_ems_actuator = OpenStudio::Model::EnergyManagementSystemActuator.new(erv_exhaustAirFan,"Fan","Fan Air Mass Flow Rate")
erv_exhaustAirFan_ems_actuator.setName("erv_exhaustAirFan_ems_actuator_#{thermal_zone.name.to_s}")
runner.registerInfo("EMS Actuator object named '#{erv_exhaustAirFan_ems_actuator.name.to_s}' representing the mass flow rate of erv supply air fan named #{erv_exhaustAirFan.name.to_s} added to the model.")

# Create new EnergyManagementSystem:Program object
erv_fan_mass_flow_rate_ems_prg = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
erv_fan_mass_flow_rate_ems_prg.setName("erv_fan_mass_flow_rate_ems_prg_#{thermal_zone.name.to_s}")
erv_fan_mass_flow_rate_ems_prg.addLine("IF ((Hour >= 0) && (Hour <= 6)) || (Hour >= 22)") # night time
#erv_fan_mass_flow_rate_ems_prg ...
edit retag close merge delete

IIUC, you see the EMS program doing its thing, but it's overriden by something else later? Can you show your EMS snippet so we can look at the calling point etc?

( 2019-10-04 02:56:46 -0500 )edit

Hi Julien, thank you very much for your comment. Please see my updated question.

( 2019-10-04 03:20:58 -0500 )edit

BeginTimestepBeforePredictor is most likely a wrong calling point as it should be overriden by the normal operation of the program (95% sure...). AfterPredictorAfterHVACManager looks like a better guess (not saying it's right).