Question-and-Answer Resource for the Building Energy Modeling Community
Get started with the Help page
Ask Your Question

Revision history [back]

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

Long

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.addLine("SET #{erv_supplyAirFan_ems_actuator.name} = #{erv_supply_mass_flow_rate}*#{night_erv_fan_position}/3.0")
          erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_exhaustAirFan_ems_actuator.name} = #{erv_exhaust_mass_flow_rate}*#{night_erv_fan_position}/3.0")
          #erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_flow_cst_sch_ems_actuator.name} = #{erv_exhaust_mass_flow_rate}*#{night_erv_fan_position}/3.0")
          erv_fan_mass_flow_rate_ems_prg.addLine("ELSEIF (Hour >= 8) && (Hour <= 16)")              # absent period
          erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_supplyAirFan_ems_actuator.name} = #{erv_supply_mass_flow_rate}*#{absent_erv_fan_position}/3.0")
          erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_exhaustAirFan_ems_actuator.name} = #{erv_exhaust_mass_flow_rate}*#{absent_erv_fan_position}/3.0")
          #erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_flow_cst_sch_ems_actuator.name} = #{erv_exhaust_mass_flow_rate}*#{absent_erv_fan_position}/3.0")          
          erv_fan_mass_flow_rate_ems_prg.addLine("ELSE")                                            # occupation period
          erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_supplyAirFan_ems_actuator.name} = #{erv_supply_mass_flow_rate}*#{occupation_erv_fan_position}/3.0")
          erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_exhaustAirFan_ems_actuator.name} = #{erv_exhaust_mass_flow_rate}*#{occupation_erv_fan_position}/3.0")
          #erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_flow_cst_sch_ems_actuator.name} = #{erv_exhaust_mass_flow_rate}*#{occupation_erv_fan_position}/3.0")
          erv_fan_mass_flow_rate_ems_prg.addLine("ENDIF")

          # create new EnergyManagementSystem:ProgramCallingManager object
          ems_prgm_calling_mngr = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
          ems_prgm_calling_mngr.setName("erv_fan_mass_flow_rate_ems_call_#{thermal_zone.name.to_s}")
          ems_prgm_calling_mngr.setCallingPoint("BeginTimestepBeforePredictor")
          ems_prgm_calling_mngr.addProgram(erv_fan_mass_flow_rate_ems_prg)
          runner.registerInfo("EMS Program Calling Manager object named '#{ems_prgm_calling_mngr.name}' added to call #{erv_fan_mass_flow_rate_ems_prg.name} EMS programs.")          
        end
      end
    end

    return true
  end

Long

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.addLine("SET #{erv_supplyAirFan_ems_actuator.name} = #{erv_supply_mass_flow_rate}*#{night_erv_fan_position}/3.0")
          erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_exhaustAirFan_ems_actuator.name} = #{erv_exhaust_mass_flow_rate}*#{night_erv_fan_position}/3.0")
          #erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_flow_cst_sch_ems_actuator.name} = #{erv_exhaust_mass_flow_rate}*#{night_erv_fan_position}/3.0")
          erv_fan_mass_flow_rate_ems_prg.addLine("ELSEIF (Hour >= 8) && (Hour <= 16)")              # absent period
          erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_supplyAirFan_ems_actuator.name} = #{erv_supply_mass_flow_rate}*#{absent_erv_fan_position}/3.0")
          erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_exhaustAirFan_ems_actuator.name} = #{erv_exhaust_mass_flow_rate}*#{absent_erv_fan_position}/3.0")
          #erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_flow_cst_sch_ems_actuator.name} = #{erv_exhaust_mass_flow_rate}*#{absent_erv_fan_position}/3.0")          
          erv_fan_mass_flow_rate_ems_prg.addLine("ELSE")                                            # occupation period
          erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_supplyAirFan_ems_actuator.name} = #{erv_supply_mass_flow_rate}*#{occupation_erv_fan_position}/3.0")
          erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_exhaustAirFan_ems_actuator.name} = #{erv_exhaust_mass_flow_rate}*#{occupation_erv_fan_position}/3.0")
          #erv_fan_mass_flow_rate_ems_prg.addLine("SET #{erv_flow_cst_sch_ems_actuator.name} = #{erv_exhaust_mass_flow_rate}*#{occupation_erv_fan_position}/3.0")
          erv_fan_mass_flow_rate_ems_prg.addLine("ENDIF")

          # create new EnergyManagementSystem:ProgramCallingManager object
          ems_prgm_calling_mngr = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
          ems_prgm_calling_mngr.setName("erv_fan_mass_flow_rate_ems_call_#{thermal_zone.name.to_s}")
          ems_prgm_calling_mngr.setCallingPoint("BeginTimestepBeforePredictor")
          ems_prgm_calling_mngr.addProgram(erv_fan_mass_flow_rate_ems_prg)
          runner.registerInfo("EMS Program Calling Manager object named '#{ems_prgm_calling_mngr.name}' added to call #{erv_fan_mass_flow_rate_ems_prg.name} EMS programs.")          
        end
      end
    end

    return true
  end

And below is the difference between mechanical zone ventilation mass flow rate and controlled fan onoff mass flow rate of ERV unit: image description

Long