SUBROUTINE CalcOAController(OAControllerNum,AirLoopNum)
! SUBROUTINE INFORMATION:
! AUTHOR Fred Buhl
! DATE WRITTEN Oct 1998
! MODIFIED Shirey/Raustad FSEC, June 2003
! Tianzhen Hong, Feb 2009 for new DCV
! Brent Griffith ,EMS override of OA rate
! Mangesh Basarkar, 06/2011: Modifying outside air calculation based on DCV flag
! Chandan Sharma, FSEC, 25Aug 2011 - Added ProportionalControl
! to enhance CO2 based DCV control
! Tianzhen Hong, March 2012, zone maximum OA fraction - a TRACE feature
! Tianzhen Hong, March 2012, multi-path VRP based on ASHRAE 62.1-2010
! RE-ENGINEERED na
! PURPOSE OF THIS SUBROUTINE
! Determine the outside air flow
! METHODOLOGY EMPLOYED:
! REFERENCES:
! DOE-2.1E Supplement pages 3.97 - 3.100
! BLAST User Reference pages 183 - 186
! ASHRAE Standard 62.1-2010
! USE STATEMENTS:
USE General, ONLY: SolveRegulaFalsi, RoundSigDigits
USE Psychrometrics, ONLY:PsyRhoAirFnPbTdbW, PsyTdpFnWPb, PsyTdbFnHW
USE DataZoneEnergyDemands, ONLY: ZoneSysMoistureDemand, ZoneSysEnergyDemand
USE CurveManager, ONLY: CurveValue
USE InputProcessor, ONLY: FindItemInList, GetNumObjectsFound
USE DataHeatBalance, ONLY: ZoneIntGain, Zone, People, TotPeople
USE DataZoneEquipment, ONLY: ZoneEquipConfig
USE DataHeatBalFanSys, ONLY: ZoneAirHumRat
USE DataContaminantBalance, ONLY: ZoneSysContDemand
USE DataGlobals, ONLY: DisplayExtraWarnings
IMPLICIT NONE
! SUBROUTINE ARGUMENT DEFINITIONS
INTEGER, INTENT(IN) :: OAControllerNum
INTEGER, INTENT(IN) :: AirLoopNum
! SUBROUTINE PARAMETER DEFINITIONS:
INTEGER, PARAMETER :: MaxIte = 500 ! Maximum number of iterations
REAL(r64), PARAMETER :: Acc = 0.0001D0 ! Accuracy of result
CHARACTER(len=*),PARAMETER :: RoutineName='CalcOAController: '
CHARACTER(len=*), PARAMETER :: CurrentModuleObject=CurrentModuleObjects(CMO_MechVentilation)
! INTERFACE BLOCK SPECIFICATIONS
! na
! DERIVED TYPE DEFINITIONS
! na
! SUBROUTINE LOCAL VARIABLE DECLARATIONS:
REAL(r64) :: OutAirSignal ! Used to set OA mass flow rate
REAL(r64) :: OutAirMinFrac ! Local variable used to calculate min OA fraction
REAL(r64) :: MechVentOutsideAirMinFrac ! fraction of OA specified by mechanical ventilation object
REAL(r64) :: MechVentOutsideAirFlow ! outside air mass flow rate specified by mechanical ventilation object
REAL(r64) :: MinOASchedVal ! value of the minimum outside air schedule
REAL(r64) :: EconomizerAirFlowScheduleValue ! value of economizer operation schedule (push-button type control schedule)
REAL(r64) :: OASignal ! Outside air flow rate fraction (0.0 to 1.0)
!unused1208 REAL(r64) :: OADPTemp ! Outside air dew point temperature
REAL(r64), DIMENSION(4) :: Par ! Par(1) = mixed air node number
! Par(2) = return air node number
! Par(3) = outside air node number
! Par(4) = mixed air mass flow rate
INTEGER :: SolFla ! Flag of solver
LOGICAL :: AirLoopEconoLockout ! Economizer lockout flag
LOGICAL :: AirLoopCyclingFan ! Type of air loop fan (TRUE if Fan:OnOff)
LOGICAL :: AirLoopNightVent ! Night Ventilation flag for air loop
REAL(r64) :: MinOAflowfracVal
REAL(r64) :: MaxOAflowfracVal
LOGICAL :: EconomizerOperationFlag ! TRUE if OA economizer is active
LOGICAL :: HighHumidityOperationFlag ! TRUE if zone humidistat senses a high humidity condition
! LOGICAL :: ErrorsFound=.false. ! Flag identifying errors found during get input
! new local variables for DCV
INTEGER :: VentMechObjectNum ! Temporary variable
REAL(r64) :: ZoneOAPeople ! Zone OA flow rate based on number of occupants
REAL(r64) :: ZoneOAArea ! Zone OA flow rate based on space floor area
REAL(r64) :: ZoneOAFlow ! Zone OA flow rate based on simple flow
REAL(r64) :: ZoneOAACH ! Zone OA flow rate based on air changes per hour
REAL(r64) :: ZoneOABZ ! Zone breathing-zone OA flow rate
REAL(r64) :: ZoneOAMin ! Minimum Zone OA flow rate when the zone is unoccupied (i.e. ZoneOAPeople = 0)
! used for "ProportionalControl" System outdoor air method
REAL(r64) :: ZoneOAMax ! Maximum Zone OA flow rate (ZoneOAPeople + ZoneOAArea)
! used for "ProportionalControl" System outdoor air method
REAL(r64) :: ZoneOA ! Zone OA flow rate
REAL(r64) :: ZoneOAFrac ! Zone OA fraction (as a fraction of actual supply air flow rate)
REAL(r64) :: ZoneEz ! Zone air distribution effectiveness
REAL(r64) :: ZoneSA ! Zone supply air flow rate
REAL(r64) :: ZonePA ! Zone primary air flow rate
REAL(r64) :: SysOAuc ! System uncorrected OA flow rate
REAL(r64) :: SysOA ! System supply OA flow rate
REAL(r64) :: SysEv ! System ventilation efficiency
REAL(r64) :: SysSA ! System supply air flow rate
REAL(r64) :: NodeTemp ! node temperature
REAL(r64) :: NodeHumRat ! node humidity ratio
REAL(r64) :: MassFlowRate ! Temporary variable
REAL(r64) :: ZoneLoad ! Zone loads
INTEGER :: InNodeIndex ! Temporary variable
INTEGER :: ZoneEquipConfigNum ! Temporary variable
INTEGER :: ZoneIndex
INTEGER :: ZoneNum
INTEGER :: ZoneADEffSchPtr
CHARACTER(len=MaxNameLength) :: ZoneName ! Zone name
REAL(r64) :: RecircTemp !- return air temp, used for custom economizer control calculation
REAL(r64) :: MixedAirTempAtMinOAFlow !- mixed air temperature at min flow rate, used for custom economizer control calculation
REAL(r64) :: RecircMassFlowRateAtMinOAFlow ! recirc air mass flow rate at min OA, used for custom economizer control calculation
REAL(r64) :: ReliefMassFlowAtMinOA ! relief air mass flow rate at min OA, used for custom economizer control calculation
INTEGER :: OAIndex ! index to design specification outdoor air objects
INTEGER :: PeopleNum
REAL(r64) :: ZoneMaxCO2 ! Breathing-zone CO2 concentartion
REAL(r64) :: ZoneMinCO2 ! Minimum CO2 concentration in zone
REAL(r64) :: ZoneContamControllerSched ! Schedule value for ZoneControl:ContaminantController
LOGICAL :: MultiPath = .FALSE. ! TRUE if multi-path ventilation system such as dual fan dual duct, VAV with fan-powered box
REAL(r64) :: Ep = 1.0d0 ! zone primary air fraction
REAL(r64) :: Er = 0.0d0 ! zone secondary recirculation fraction
REAL(r64) :: Fa = 1.0d0 ! temporary variable used in multi-path VRP calc
REAL(r64) :: Fb = 1.0d0
REAL(r64) :: Fc = 1.0d0
REAL(r64) :: Xs = 1.0d0 ! uncorrected system outdoor air fraction
REAL(r64) :: Evz = 1.0d0 ! zone ventilation efficiency
INTEGER :: PriNode ! primary node of zone terminal unit
INTEGER :: InletNode ! outlet node of zone terminal unit
MinOASchedVal = 1.0d0
ZoneMaxCO2 = 0.d0
ZoneMinCO2 = 0.d0
ZoneOAMin = 0.d0
ZoneOAMax = 0.d0
ZoneContamControllerSched = 0.d0
IF (AirLoopNum > 0) THEN
AirLoopEconoLockout = AirLoopControlInfo(AirLoopNum)%EconoLockout
AirLoopCyclingFan = AirLoopControlInfo(AirLoopNum)%CyclingFan
AirLoopNightVent = AirLoopControlInfo(AirLoopNum)%NightVent
ELSE
AirLoopEconoLockout = .FALSE.
AirLoopCyclingFan = .FALSE.
AirLoopNightVent = .FALSE.
END IF
! Check for no flow
IF (OAController(OAControllerNum)%MixMassFlow .LE. SmallMassFlow) THEN
OAController(OAControllerNum)%OAMassFlow = 0.0d0 ! outside air mass flow rate
OAController(OAControllerNum)%RelMassFlow = 0.0d0 ! relief air mass flow rate
OAController(OAControllerNum)%MixMassFlow = 0.0d0 ! mixed air mass flow rate
OAController(OAControllerNum)%MinOAFracLimit = 0.0d0 ! minimum OA fraction limit
OAController(OAControllerNum)%EconomizerStatus = 0 ! economizer status for reporting
OAController(OAControllerNum)%HeatRecoveryBypassStatus = 0 ! HR bypass status for reporting
OAController(OAControllerNum)%HRHeatingCoilActive = 0 ! resets report variable
OAController(OAControllerNum)%MixedAirTempAtMinOAFlow = Node(OAController(OAControllerNum)%RetNode)%Temp ! track return T
OAController(OAControllerNum)%HighHumCtrlStatus = 0 ! high humdity control status for reporting
OAController(OAControllerNum)%OAFractionRpt = 0.0d0 ! actual OA fraction for reporting
OAControllerInfo(OAControllerNum)%EconoActive = .FALSE. ! DataAirLoop variable (OA Controllers)
OAControllerInfo(OAControllerNum)%HighHumCtrlActive = .FALSE. ! DataAirLoop variable (OA Controllers)
! also reset air loop data for use by other routines
IF (AirLoopNum > 0) THEN
AirLoopControlInfo(AirLoopNum)%EconoActive = .FALSE. ! DataAirLoop variable (AirloopHVAC)
AirLoopControlInfo(AirLoopNum)%HeatRecoveryBypass = .FALSE. ! DataAirLoop variable (AirloopHVAC)
AirLoopControlInfo(AirLoopNum)%HighHumCtrlActive = .FALSE. ! DataAirLoop variable (AirloopHVAC)
AirLoopControlInfo(AirLoopNum)%ResimAirLoopFlag = .FALSE. ! DataAirLoop variable (AirloopHVAC)
AirLoopFlow(AirLoopNum)%OAFrac = 0.d0 ! DataAirLoop variable (AirloopHVAC)
AirLoopFlow(AirLoopNum)%OAMinFrac = 0.d0 ! DataAirLoop variable (AirloopHVAC)
END IF
RETURN
END IF
! set OutAirMinFrac
IF (AirLoopNum > 0) THEN
IF (AirLoopFlow(AirLoopNum)%DesSupply >= SmallAirVolFlow) THEN
OutAirMinFrac = OAController(OAControllerNum)%MinOAMassFlowRate / AirLoopFlow(AirLoopNum)%DesSupply
ELSE
OutAirMinFrac = 0.0d0
END IF
ELSE
IF (OAController(OAControllerNum)%MaxOA >= SmallAirVolFlow) THEN
OutAirMinFrac = OAController(OAControllerNum)%MinOA / OAController(OAControllerNum)%MaxOA
ELSE
OutAirMinFrac = 0.0d0
END IF
END IF
IF (OAController(OAControllerNum)%MinOASchPtr .GT.0) THEN
MinOASchedVal = GetCurrentScheduleValue(OAController(OAControllerNum)%MinOASchPtr)
MinOASchedVal = MIN(MAX(MinOASchedVal,0.0d0),1.0d0)
OutAirMinFrac = OutAirMinFrac * MinOASchedVal
END IF
! Get mechanical ventilation
VentMechObjectNum = OAController(OAControllerNum)%VentMechObjectNum
IF(AirLoopNum > 0 .AND. VentMechObjectNum /= 0)THEN
! Apply mechanical ventilation only when it is available/allowed
IF(GetCurrentScheduleValue(VentilationMechanical(VentMechObjectNum)%SchPtr) > 0)THEN
!IF (VentilationMechanical(VentMechObjectNum)%SystemOAMethod == SOAM_ZoneSum) THEN
! no longer needed due to OA inputs consolidation
! keep simple DCV method implemened in E+ 3.0 which sums the zone OA as the system OA
! without considering the zone air distribution effectiveness or system ventilation efficiency
! MechVentOutsideAirFlow = (VentilationMechanical(VentMechObjectNum)%TotAreaOAFlow + &
! VentilationMechanical(VentMechObjectNum)%TotPeopleOAFlow) * StdRhoAir
!ELSE IF (VentilationMechanical(VentMechObjectNum)%SystemOAMethod == SOAM_IAQP) THEN
IF (VentilationMechanical(VentMechObjectNum)%SystemOAMethod == SOAM_IAQP) THEN
! IAQP for CO2 control
SysOA = 0.0d0
DO ZoneIndex = 1, VentilationMechanical(VentMechObjectNum)%NumofVentMechZones
ZoneNum = VentilationMechanical(VentMechObjectNum)%Zone(ZoneIndex)
SysOA = SysOA + ZoneSysContDemand(ZoneNum)%OutputRequiredToCO2SP
END DO
MechVentOutsideAirFlow = SysOA
ELSE IF (VentilationMechanical(VentMechObjectNum)%SystemOAMethod == SOAM_IAQPGC) THEN
! IAQP for generic contaminant control
SysOA = 0.0d0
DO ZoneIndex = 1, VentilationMechanical(VentMechObjectNum)%NumofVentMechZones
ZoneNum = VentilationMechanical(VentMechObjectNum)%Zone(ZoneIndex)
SysOA = SysOA + ZoneSysContDemand(ZoneNum)%OutputRequiredToGCSP
END DO
MechVentOutsideAirFlow = SysOA
ELSE IF (VentilationMechanical(VentMechObjectNum)%SystemOAMethod == SOAM_IAQPCOM) THEN
! IAQP for both CO2 and generic contaminant control
SysOA = 0.0d0
DO ZoneIndex = 1, VentilationMechanical(VentMechObjectNum)%NumofVentMechZones
ZoneNum = VentilationMechanical(VentMechObjectNum)%Zone(ZoneIndex)
SysOA = SysOA + ZoneSysContDemand(ZoneNum)%OutputRequiredToCO2SP
END DO
MechVentOutsideAirFlow = SysOA
SysOA = 0.0d0
DO ZoneIndex = 1, VentilationMechanical(VentMechObjectNum)%NumofVentMechZones
ZoneNum = VentilationMechanical(VentMechObjectNum)%Zone(ZoneIndex)
SysOA = SysOA + ZoneSysContDemand(ZoneNum)%OutputRequiredToGCSP
END DO
MechVentOutsideAirFlow = MAX(SysOA, MechVentOutsideAirFlow)
ELSE
! for system OA methods: Zone_Sum, VRP, CO2 methods
! new code for DCV method complying with the VRP defined in ASHRAE Standard 62.1-2010
! Loop through each zone first to calc uncorrected system OA flow rate
SysOAuc = 0.0d0
SysOA = 0.0d0
DO ZoneIndex = 1, VentilationMechanical(VentMechObjectNum)%NumofVentMechZones
ZoneNum = VentilationMechanical(VentMechObjectNum)%Zone(ZoneIndex)
! Calc the zone OA flow rate based on the people component
! ZoneIntGain(ZoneNum)%NOFOCC is the number of occupants of a zone at each time step, already counting the occupant schedule
! Checking DCV flag before calculating zone OA per person
IF (VentilationMechanical(VentMechObjectNum)%DCVFlag) THEN
ZoneOAPeople = ZoneIntGain(ZoneNum)%NOFOCC * Zone(ZoneNum)%Multiplier * Zone(ZoneNum)%ListMultiplier * &
VentilationMechanical(VentMechObjectNum)%ZoneOAPeopleRate(ZoneIndex)
ELSE
ZoneOAPeople = 0.0d0
DO PeopleNum=1,TotPeople
IF (People(PeopleNum)%ZonePtr /= ZoneNum) CYCLE
ZoneOAPeople = ZoneOAPeople + People(PeopleNum)%NumberOfPeople * Zone(ZoneNum)%Multiplier * &
Zone(ZoneNum)%ListMultiplier * VentilationMechanical(VentMechObjectNum)%ZoneOAPeopleRate(ZoneIndex)
ENDDO
ENDIF
! Calc the zone OA flow rate based on the floor area component
ZoneOAArea = Zone(ZoneNum)%FloorArea * Zone(ZoneNum)%Multiplier * Zone(ZoneNum)%ListMultiplier * &
VentilationMechanical(VentMechObjectNum)%ZoneOAAreaRate(ZoneIndex)
ZoneOAFlow = Zone(ZoneNum)%Multiplier * Zone(ZoneNum)%ListMultiplier * &
VentilationMechanical(VentMechObjectNum)%ZoneOAFlow(ZoneIndex)
ZoneOAACH = Zone(ZoneNum)%Multiplier * Zone(ZoneNum)%ListMultiplier * &
(VentilationMechanical(VentMechObjectNum)%ZoneOAACH(ZoneIndex)*Zone(ZoneIndex)%Volume)/3600.d0
! Calc the breathing-zone OA flow rate
OAIndex=VentilationMechanical(VentMechObjectNum)%ZoneDesignSpecOAObjIndex(ZoneIndex)
IF (OAIndex > 0) THEN
SELECT CASE(OARequirements(OAIndex)%OAFlowMethod)
CASE(OAFlowPPer)
ZoneOABZ = ZoneOAPeople
CASE(OAFlow)
ZoneOABZ = ZoneOAFlow
CASE(OAFlowPerArea)
ZoneOABZ = ZoneOAArea
CASE(OAFlowACH)
ZoneOABZ = ZoneOAACH
CASE(OAFlowSum)
ZoneOABZ = ZoneOAPeople + ZoneOAArea + ZoneOAFlow + ZoneOAACH
CASE(OAFlowMax)
ZoneOABZ = MAX(ZoneOAPeople,ZoneOAArea,ZoneOAFlow,ZoneOAACH)
CASE DEFAULT
ZoneOABZ = 0.0D0
END SELECT
ELSE
ZoneOABZ = 0.0D0
ENDIF
IF (VentilationMechanical(VentMechObjectNum)%SystemOAMethod == SOAM_ZoneSum) THEN
! Sum the zone OA flow rates and done
SysOA = SysOA + ZoneOABZ
ELSE
! Calc the uncorrected system OA flow rate - VRP and ProportionalControl
SysOAuc = SysOAuc + ZoneOABZ
ENDIF
ENDDO
! get system supply air flow rate
IF (VentilationMechanical(VentMechObjectNum)%SystemOAMethod == SOAM_VRP .OR. &
VentilationMechanical(VentMechObjectNum)%SystemOAMethod == SOAM_ProportionalControl) THEN
! Get system supply air flow rate
IF (AirLoopControlInfo(AirLoopNum)%LoopFlowRateSet) THEN
! if flow rate has been specified by a manager, set it to the specified value
! DesSupply and SupFlow are mass flow rate in kg/s
SysSA = AirLoopFlow(AirLoopNum)%ReqSupplyFrac * AirLoopFlow(AirLoopNum)%DesSupply
ELSE
SysSA = AirLoopFlow(AirLoopNum)%SupFlow
ENDIF
! System supply air flow rate is always greater than or equal the system outdoor air flow rate
IF ((SysSA > 0.0d0) .AND. (SysSA < (SysOAuc*StdRhoAir))) SysSA = SysOAuc*StdRhoAir
! calc Xs - average outdoor air fraction
IF (SysSA > 0.0d0) THEN
Xs = (SysOAuc*StdRhoAir) / SysSA
ELSE
Xs = 0.0d0
ENDIF
! Loop through each zone again
SysEv = 2.0d0 ! starting with a big fraction
DO ZoneIndex = 1, VentilationMechanical(VentMechObjectNum)%NumofVentMechZones
ZoneNum = VentilationMechanical(VentMechObjectNum)%Zone(ZoneIndex)
ZoneName = Zone(ZoneNum)%Name
ZoneEquipConfigNum = ZoneNum ! correspondence - 1:1 of ZoneEquipConfig to Zone index
ZoneEz = 0.0d0
! Calc the zone OA flow rate based on the people component
! ZoneIntGain(ZoneNum)%NOFOCC is the number of occupants of a zone at each time step, already counting the occupant schedule
! Checking DCV flag before calculating zone OA per person
IF (VentilationMechanical(VentMechObjectNum)%DCVFlag) THEN
ZoneOAPeople = ZoneIntGain(ZoneNum)%NOFOCC * Zone(ZoneNum)%Multiplier * Zone(ZoneNum)%ListMultiplier * &
VentilationMechanical(VentMechObjectNum)%ZoneOAPeopleRate(ZoneIndex)
ELSE
ZoneOAPeople = 0.0d0
DO PeopleNum=1,TotPeople
IF (People(PeopleNum)%ZonePtr /= ZoneNum) CYCLE
ZoneOAPeople = ZoneOAPeople + People(PeopleNum)%NumberOfPeople * Zone(ZoneNum)%Multiplier * &
Zone(ZoneNum)%ListMultiplier * VentilationMechanical(VentMechObjectNum)%ZoneOAPeopleRate(ZoneIndex)
ENDDO
ENDIF
! Calc the zone OA flow rate based on the floor area component
ZoneOAArea = Zone(ZoneNum)%FloorArea * Zone(ZoneNum)%Multiplier * Zone(ZoneNum)%ListMultiplier * &
VentilationMechanical(VentMechObjectNum)%ZoneOAAreaRate(ZoneIndex)
ZoneOAFlow = Zone(ZoneNum)%Multiplier * Zone(ZoneNum)%ListMultiplier * &
VentilationMechanical(VentMechObjectNum)%ZoneOAFlow(ZoneIndex)
ZoneOAACH = Zone(ZoneNum)%Multiplier * Zone(ZoneNum)%ListMultiplier * &
(VentilationMechanical(VentMechObjectNum)%ZoneOAACH(ZoneIndex)*Zone(ZoneIndex)%Volume)/3600.d0
! Calc the breathing-zone OA flow rate
OAIndex=VentilationMechanical(VentMechObjectNum)%ZoneDesignSpecOAObjIndex(ZoneIndex)
IF (OAIndex > 0) THEN
SELECT CASE(OARequirements(OAIndex)%OAFlowMethod)
CASE(OAFlowPPer)
ZoneOABZ = ZoneOAPeople
CASE(OAFlow)
ZoneOABZ = ZoneOAFlow
CASE(OAFlowPerArea)
ZoneOABZ = ZoneOAArea
CASE(OAFlowACH)
ZoneOABZ = ZoneOAACH
CASE(OAFlowSum)
ZoneOABZ = ZoneOAPeople + ZoneOAArea + ZoneOAFlow + ZoneOAACH
CASE(OAFlowMax)
ZoneOABZ = MAX(ZoneOAPeople,ZoneOAArea,ZoneOAFlow,ZoneOAACH)
CASE DEFAULT
ZoneOABZ = 0.0D0
END SELECT
ENDIF
! use the ventilation rate procedure in ASHRAE Standard 62.1-2007
! Calc the zone supplied OA flow rate counting the zone air distribution effectiveness
! First check whether the zone air distribution effectiveness schedule exists, if yes uses it;
! otherwise uses the inputs of zone distribution effectiveness in cooling mode or heating mode
ZoneADEffSchPtr = VentilationMechanical(VentMechObjectNum)%ZoneADEffSchPtr(ZoneIndex)
IF (ZoneADEffSchPtr > 0) THEN
! Get schedule value for the zone air distribution effectiveness
ZoneEz = GetCurrentScheduleValue(ZoneADEffSchPtr)
ELSE
ZoneLoad = ZoneSysEnergyDemand(ZoneEquipConfig(ZoneEquipConfigNum)%ActualZoneNum)%TotalOutputRequired
! Zone in cooling mode
IF (ZoneLoad < 0.0d0) ZoneEz = VentilationMechanical(VentMechObjectNum)%ZoneADEffCooling(ZoneIndex)
! Zone in heating mode
IF (ZoneLoad > 0.0d0) ZoneEz = VentilationMechanical(VentMechObjectNum)%ZoneADEffHeating(ZoneIndex)
ENDIF
IF (ZoneEz <= 0.0d0) THEN
!Enforce defaults
ZoneEz = 1.0d0
ENDIF
! Calc zone supply OA flow rate
IF (VentilationMechanical(VentMechObjectNum)%SystemOAMethod == SOAM_VRP) THEN
! the VRP case
ZoneOA = ZoneOABZ / ZoneEz
ELSEIF (VentilationMechanical(VentMechObjectNum)%SystemOAMethod == SOAM_ProportionalControl) THEN
! Check whether "Carbon Dioxide Control Availability Schedule" for ZoneControl:ContaminantController is specified
IF (Zone(ZoneNum)%ZoneContamControllerSchedIndex .GT. 0.d0) THEN
! Check the availability schedule value for ZoneControl:ContaminantController
ZoneContamControllerSched = GetCurrentScheduleValue(Zone(ZoneNum)%ZoneContamControllerSchedIndex)
IF (ZoneContamControllerSched .GT. 0.d0) THEN
ZoneOAMin = ZoneOAArea / ZoneEz
ZoneOAMax = (ZoneOAArea + ZoneOAPeople) / ZoneEz
IF (ZoneOAPeople .GT. 0.0d0) THEN
IF (ZoneCO2GainFromPeople(ZoneNum) .GT. 0.d0) THEN
IF (Zone(ZoneNum)%ZoneMinCO2SchedIndex .GT. 0.d0) THEN
! Take the schedule value of "Minimum Carbon Dioxide Concentration Schedule Name"
! in the ZoneControl:ContaminantController
ZoneMinCO2 = GetCurrentScheduleValue(Zone(ZoneNum)%ZoneMinCO2SchedIndex)
ELSE
ZoneMinCO2 = OutdoorCO2
ENDIF
! Calculate zone maximum target CO2 concentration in PPM
ZoneMaxCO2 = OutdoorCO2 + &
(ZoneCO2GainFromPeople(ZoneNum) * Zone(ZoneNum)%Multiplier * Zone(ZoneNum)%ListMultiplier *1.0d6) &
/ ZoneOAMax
IF (ZoneMaxCO2 .LE. ZoneMinCO2) THEN
VentilationMechanical(VentMechObjectNum)%CO2MaxMinLimitErrorCount = &
VentilationMechanical(VentMechObjectNum)%CO2MaxMinLimitErrorCount+1
IF (VentilationMechanical(VentMechObjectNum)%CO2MaxMinLimitErrorCount < 2) THEN
CALL ShowSevereError(RoutineName//TRIM(CurrentModuleObject)//' = "'// &
TRIM(VentilationMechanical(VentMechObjectNum)%Name) //'".')
CALL ShowContinueError('For System Outdoor Air Method = ProportionalControl,' // &
' maximum target CO2 concentration ('//TRIM(RoundSigDigits(ZoneMaxCO2,2))// &
'), is not greater than minimum target CO2 concentration (' // &
TRIM(RoundSigDigits(ZoneMinCO2,2))// ').')
CALL ShowContinueError('"ProportionalControl" will not be modeled. ' // &
'Default "VentilationRateProcedure" will be modeled. Simulation continues...')
CALL ShowContinueErrorTimeStamp(' ')
ELSE
CALL ShowRecurringWarningErrorAtEnd(TRIM(CurrentModuleObject)//' = "'// &
TRIM(VentilationMechanical(VentMechObjectNum)%Name)//&
'", For System Outdoor Air Method = ProportionalControl,' // &
' maximum target CO2 concentration is not greater than ' // &
' minimum target CO2 concentration. Error continues...' &
, VentilationMechanical(VentMechObjectNum)%CO2MaxMinLimitErrorIndex)
ENDIF
ZoneOA = ZoneOABZ / ZoneEz
ELSE
IF (ZoneAirCO2(ZoneNum) .LE. ZoneMinCO2) THEN
! Zone air CO2 concentration is less than minimum zone CO2 concentration, set the Zone OA flow rate to
! minimum Zone OA flow rate when the zone is unoccupied
ZoneOA = ZoneOAMin
ELSEIF (ZoneAirCO2(ZoneNum) .GE. ZoneMaxCO2) THEN
! Zone air CO2 concentration is greater than maximum zone CO2 concentration, set the Zone OA flow rate to
! maximum Zone OA flow rate (i.e. ZoneOAArea + ZoneOAPeople)
ZoneOA = ZoneOAMax
ELSE
! Zone air CO2 concentration is between maximum and minimum limits of zone CO2 concentration,
! set Zone OA flow rate by proportionally adjusting between ZoneOAMin and ZoneOAMax
ZoneOA = ZoneOAMin + (ZoneOAMax - ZoneOAMin) * &
((ZoneAirCO2(ZoneNum) - ZoneMinCO2)/(ZoneMaxCO2 - ZoneMinCO2))
ENDIF
ENDIF
ELSE
IF (DisplayExtraWarnings) THEN
VentilationMechanical(VentMechObjectNum)%CO2GainErrorCount = &
VentilationMechanical(VentMechObjectNum)%CO2GainErrorCount+1
IF (VentilationMechanical(VentMechObjectNum)%CO2GainErrorCount < 2) THEN
CALL ShowSevereError(RoutineName//TRIM(CurrentModuleObject)//' = "'// &
TRIM(VentilationMechanical(VentMechObjectNum)%Name) //'".')
CALL ShowContinueError('For System Outdoor Air Method = ProportionalControl,' // &
' CO2 generation from people is not greater than zero.' // &
' Occurs in Zone ="'//TRIM(Zone(ZoneNum)%Name)// &
'". ')
CALL ShowContinueError('"ProportionalControl" will not be modeled. ' // &
'Default "VentilationRateProcedure" will be modeled. Simulation continues...')
CALL ShowContinueErrorTimeStamp(' ')
ELSE
CALL ShowRecurringWarningErrorAtEnd(TRIM(CurrentModuleObject)//' = "'// &
TRIM(VentilationMechanical(VentMechObjectNum)%Name)//&
'", For System Outdoor Air Method = ProportionalControl,' // &
' CO2 generation from people is not greater than zero ' // &
' Error continues...' &
, VentilationMechanical(VentMechObjectNum)%CO2GainErrorIndex)
ENDIF
ENDIF
ZoneOA = ZoneOABZ / ZoneEz
ENDIF
ELSE
! ZoneOAPeople is less than or equal to zero
ZoneOA = ZoneOABZ / ZoneEz
ENDIF
ELSE
! ZoneControl:ContaminantController is scheduled off (not available)
ZoneOA = ZoneOABZ / ZoneEz
ENDIF
ELSE
! "Carbon Dioxide Control Availability Schedule" for ZoneControl:ContaminantController not found
ZoneOA = ZoneOABZ / ZoneEz
ENDIF
ENDIF
! Get the zone supply air flow rate
ZoneSA = 0.0d0
ZonePA = 0.0d0
Ep = 1.0d0
IF (ZoneEquipConfigNum > 0) THEN
DO InNodeIndex = 1,ZoneEquipConfig(ZoneEquipConfigNum)%NumInletNodes
! Assume primary air is always stored at the AirDistUnitCool (cooling deck if dual duct)
PriNode = ZoneEquipConfig(ZoneEquipConfigNum)%AirDistUnitCool(InNodeIndex)%InNode
IF (PriNode > 0) THEN
NodeTemp = Node(PriNode)%Temp
NodeHumRat = Node(PriNode)%HumRat
MassFlowRate = Node(PriNode)%MassFlowRate
ELSE
MassFlowRate = 0.0d0
END IF
! total primary air to terminal units of the zone
IF (MassFlowRate > 0.0d0) ZonePA = ZonePA + MassFlowRate / PsyRhoAirFnPbTdbW(OutBaroPress,NodeTemp,NodeHumRat)
! or InletNode = ZoneEquipConfig(ZoneEquipConfigNum)%AirDistUnitCool(InNodeIndex)%OutNode
InletNode = ZoneEquipConfig(ZoneEquipConfigNum)%InletNode(InNodeIndex)
IF (InletNode > 0) THEN
NodeTemp = Node(InletNode)%Temp
NodeHumRat = Node(InletNode)%HumRat ! ZoneAirHumRat(ZoneNum)
MassFlowRate = Node(InletNode)%MassFlowRate
ELSE
MassFlowRate = 0.0d0
END IF
! total supply air to the zone
IF (MassFlowRate > 0.0d0) ZoneSA = ZoneSA + MassFlowRate / PsyRhoAirFnPbTdbW(OutBaroPress,NodeTemp,NodeHumRat)
END DO
! calc zone primary air fraction
IF (ZoneSA > 0.0d0) Ep = ZonePA / ZoneSA
IF (Ep > 1.0d0) Ep = 1.0d0
END IF
! Calc the zone OA fraction = Zone OA flow rate / Zone supply air flow rate
IF (ZoneSA > 0.0d0) THEN
ZoneOAFrac = ZoneOA / ZoneSA
! Zone OA fraction cannot be more than 1
IF (ZoneOAFrac > 1.0d0) ZoneOAFrac = 1.0d0
ELSE
ZoneOAFrac = 0.0d0
ENDIF
! added for TRACE - zone maximum OA fraction - calculate the adjustment factor for the TU/zone supply air flow
! only for VRP system OA method
ZoneSysEnergyDemand(ZoneEquipConfigNum)%SupplyAirAdjustFactor = 1.0D0
IF (VentilationMechanical(VentMechObjectNum)%SystemOAMethod == SOAM_VRP) THEN
IF (ZoneOAFrac > VentilationMechanical(VentMechObjectNum)%ZoneMaxOAFraction) THEN
IF (VentilationMechanical(VentMechObjectNum)%ZoneMaxOAFraction > 0.0d0) THEN
ZoneSysEnergyDemand(ZoneEquipConfigNum)%SupplyAirAdjustFactor = &
ZoneOAFrac / VentilationMechanical(VentMechObjectNum)%ZoneMaxOAFraction
ELSE
ZoneSysEnergyDemand(ZoneEquipConfigNum)%SupplyAirAdjustFactor = 1.0D0
ENDIF
! cap zone OA fraction at the maximum specified
ZoneOAFrac = VentilationMechanical(VentMechObjectNum)%ZoneMaxOAFraction
ENDIF
ENDIF
! Zone air secondary recirculation fraction
Er = VentilationMechanical(VentMechObjectNum)%ZoneSecondaryRecirculation(ZoneIndex)
IF (Er > 0.0d0) THEN
! multi-path ventilation system using VRP
Fa = Ep + (1.0d0 - Ep) * Er
Fb = Ep
Fc = 1.0d0 - (1.0d0 - ZoneEz)*(1.0d0 - Er)*(1.0d0 - Ep)
! Calc zone ventilation efficiency
IF (Fa > 0.0d0) THEN
Evz = 1.0d0 + Xs * Fb / Fa - ZoneOAFrac * Ep * Fc / Fa
ELSE
Evz = 1.0d0
ENDIF
ELSE
! single-path ventilation system
Evz = 1.0d0 + Xs - ZoneOAFrac
ENDIF
! calc system ventilation efficiency = Minimum of zone ventilation efficiency
IF (Evz < 0.0d0) Evz = 0.0d0
IF (Evz < SysEv) SysEv = Evz
ENDDO ! zone loop
! Calc the system supply OA flow rate counting the system ventilation efficiency
IF (SysEv <= 0.0d0) SysEv = 1.0d0
! Calc system outdoor air requirement
SysOA = SysOAuc / SysEv
ENDIF
! Finally calc the system supply OA mass flow rate
MechVentOutsideAirFlow = SysOA * StdRhoAir
ENDIF
MechVentOutsideAirMinFrac = MechVentOutsideAirFlow / AirLoopFlow(AirLoopNum)%DesSupply
ELSE
MechVentOutsideAirMinFrac = 0.0d0
MechVentOutsideAirFlow = 0.0d0
END IF
IF(AirLoopflow(AirLoopNum)%FanPLR .GT. 0.0D0)THEN
MechVentOutsideAirMinFrac = MechVentOutsideAirMinFrac * AirLoopflow(AirLoopNum)%FanPLR
MechVentOutsideAirFlow = MechVentOutsideAirFlow * AirLoopflow(AirLoopNum)%FanPLR
END IF
!****** use greater of Mechanical Ventilation Outside Air fraction and OutAirMinFrac
OutAirMinFrac = MAX(OutAirMinFrac,MechVentOutsideAirMinFrac)
END IF
OutAirMinFrac = MIN(MAX(OutAirMinFrac,0.0d0),1.0d0)
IF (AirLoopNum > 0) THEN
AirLoopFlow(AirLoopNum)%MinOutAir = OutAirMinFrac * AirLoopFlow(AirLoopNum)%DesSupply
END IF
! Define an outside air signal
IF (ABS(OAController(OAControllerNum)%RetTemp - OAController(OAControllerNum)%InletTemp) .GT. SmallTempDiff) THEN
OutAirSignal = (OAController(OAControllerNum)%RetTemp - OAController(OAControllerNum)%MixSetTemp) &
/ (OAController(OAControllerNum)%RetTemp - OAController(OAControllerNum)%InletTemp)
ELSE
IF (OAController(OAControllerNum)%RetTemp - OAController(OAControllerNum)%MixSetTemp .LT. 0.0d0) THEN
IF (OAController(OAControllerNum)%RetTemp - OAController(OAControllerNum)%InletTemp .GE. 0.0d0) THEN
OutAirSignal = -1.d0
ELSE
OutAirSignal = 1.d0
ENDIF
ELSE
IF (OAController(OAControllerNum)%RetTemp - OAController(OAControllerNum)%InletTemp .GE. 0.0d0) THEN
OutAirSignal = 1.d0
ELSE
OutAirSignal = -1.d0
ENDIF
ENDIF
ENDIF
OutAirSignal = MIN(MAX(OutAirSignal,OutAirMinFrac),1.0d0)
! If no economizer, set to minimum and disable economizer and high humidity control
IF (OAController(OAControllerNum)%Econo .EQ. NoEconomizer) THEN
OutAirSignal = OutAirMinFrac
EconomizerOperationFlag = .FALSE.
EconomizerAirFlowScheduleValue = 0.0d0
HighHumidityOperationFlag = .FALSE.
ELSE IF (OAController(OAControllerNum)%MaxOA < SmallAirVolFlow) THEN
OutAirSignal = OutAirMinFrac
EconomizerOperationFlag = .FALSE.
EconomizerAirFlowScheduleValue = 0.0d0
HighHumidityOperationFlag = .FALSE.
ELSE IF (AirLoopEconoLockout) THEN
OutAirSignal = OutAirMinFrac
EconomizerOperationFlag = .FALSE.
EconomizerAirFlowScheduleValue = 0.0d0
HighHumidityOperationFlag = .FALSE.
ELSE
!Changed by Amit for new implementation
! Otherwise do the limit checks
EconomizerOperationFlag = .TRUE.
! Outside air temp greater than mix air setpoint
IF (OAController(OAControllerNum)%InletTemp.GT.OAController(OAControllerNum)%MixSetTemp) THEN
OutAirSignal = 1.0d0
ENDIF
! Return air temp limit
IF (OAController(OAControllerNum)%Econo .EQ. DifferentialDryBulb) THEN
If(OAController(OAControllerNum)%InletTemp.GT.OAController(OAControllerNum)%RetTemp) THEN
OutAirSignal = OutAirMinFrac
EconomizerOperationFlag = .FALSE.
End if
Call Checksetpoints(OAControllerNum,OutAirMinFrac,OutAirSignal,EconomizerOperationFlag)
ENDIF
! Return air enthalpy limit
IF (OAController(OAControllerNum)%Econo.EQ. DifferentialEnthalpy) THEN
IF(OAController(OAControllerNum)%InletEnth.GT.OAController(OAControllerNum)%RetEnth) THEN
OutAirSignal = OutAirMinFrac
EconomizerOperationFlag = .FALSE.
ENDIF
Call Checksetpoints(OAControllerNum,OutAirMinFrac,OutAirSignal,EconomizerOperationFlag)
END IF
! Outside air temperature limit
IF (OAController(OAControllerNum)%Econo .EQ. FixedDryBulb) THEN
Call Checksetpoints(OAControllerNum,OutAirMinFrac,OutAirSignal,EconomizerOperationFlag)
END IF
!Fixed Enthalpy limit
IF (OAController(OAControllerNum)%Econo .EQ. FixedEnthalpy) THEN
Call Checksetpoints(OAControllerNum,OutAirMinFrac,OutAirSignal,EconomizerOperationFlag)
END IF
!FIXED DEW POINT AND DRY BULB TEMPERATURE STRATEGY
IF(OAController(OAControllernum)%Econo .EQ. FixedDewpointAndDryBulb) THEN
Call Checksetpoints(OAControllerNum,OutAirMinFrac,OutAirSignal,EconomizerOperationFlag)
END IF
! ELECRONIC ENTHALPY, HUMIDITY RATIO CURVE
IF(OAController(OAControllernum)%Econo .EQ. ElectronicEnthalpy) THEN
Call Checksetpoints(OAControllerNum,OutAirMinFrac,OutAirSignal,EconomizerOperationFlag)
END IF
! Differential dry bulb and enthalpy strategy
IF(OAController(OAControllerNum)%Econo .EQ. DifferentialDryBulbAndEnthalpy) THEN
If(OAController(OAControllerNum)%InletTemp.GT.OAController(OAControllerNum)%RetTemp) THEN
OutAirSignal = OutAirMinFrac
EconomizerOperationFlag = .FALSE.
End if
IF(OAController(OAControllerNum)%InletEnth.GT.OAController(OAControllerNum)%RetEnth) THEN
OutAirSignal = OutAirMinFrac
EconomizerOperationFlag = .FALSE.
ENDIF
Call Checksetpoints(OAControllerNum,OutAirMinFrac,OutAirSignal,EconomizerOperationFlag)
END IF
IF (OAController(OAControllerNum)%TempLowLim /= BlankNumeric .AND. OAController(OAControllerNum)%OATemp &
.LT.OAController(OAControllerNum)%TempLowLim) THEN
OutAirSignal = OutAirMinFrac
EconomizerOperationFlag = .FALSE.
END IF
! Increase air flow for humidity control
! (HumidistatZoneNum is greater than 0 IF High Humidity Control Flag = YES, checked in GetInput)
IF(OAController(OAControllerNum)%HumidistatZoneNum .GT. 0)THEN
! IF humidistat senses a moisture load check to see if modifying air flow is appropriate, otherwise disable modified air flow
IF(ZoneSysMoistureDemand(OAController(OAControllerNum)%HumidistatZoneNum)%TotalOutputRequired .LT. 0.0d0)THEN
! IF OAController is not allowed to modify air flow during high outdoor humrat condition, then disable modified air flow
! if indoor humrat is less than or equal to outdoor humrat
IF(.NOT. OAController(OAControllerNum)%ModifyDuringHighOAMoisture .AND. &
Node(OAController(OAControllerNum)%NodeNumofHumidistatZone)%HumRat .LE. OAController(OAControllerNum)%OAHumRat)THEN
HighHumidityOperationFlag = .FALSE.
ELSE
HighHumidityOperationFlag = .TRUE.
END IF
ELSE
HighHumidityOperationFlag = .FALSE.
END IF
ELSE
HighHumidityOperationFlag = .FALSE.
END IF
! Check time of day economizer schedule, enable economizer if schedule value > 0
EconomizerAirFlowScheduleValue = 0.0d0
IF(OAController(OAControllerNum)%EconomizerOASchedPtr .GT. 0)THEN
EconomizerAirFlowScheduleValue = GetCurrentScheduleValue(OAController(OAControllerNum)%EconomizerOASchedPtr)
IF(EconomizerAirFlowScheduleValue .GT. 0.0d0) THEN
EconomizerOperationFlag = .TRUE.
OutAirSignal = 1.0d0
END IF
END IF
END IF
! OutAirSignal will not give exactly the correct mixed air temperature (equal to the setpoint) since
! it was calculated using the approximate method of sensible energy balance. Now we have to get the
! accurate result using a full mass, enthalpy and moisture balance and iteration.
IF ( OutAirSignal > OutAirMinFrac .AND. OutAirSignal < 1.0d0 .AND. &
OAController(OAControllerNum)%MixMassFlow > VerySmallMassFlow .AND. &
OAController(OAControllerNum)%ControllerType_Num == ControllerOutsideAir .AND. &
.NOT. AirLoopNightVent) THEN
Par(1) = OAController(OAControllerNum)%MixNode
Par(2) = OAController(OAControllerNum)%RetNode
Par(3) = OAController(OAControllerNum)%InletNode
Par(4) = OAController(OAControllerNum)%MixMassFlow
CALL SolveRegulaFalsi(Acc, MaxIte, SolFla, OASignal, MixedAirControlTempResidual, OutAirMinFrac, 1.0d0, Par)
IF (SolFla < 0) THEN
OASignal = OutAirSignal
END IF
ELSE
OASignal = OutAirSignal
END IF
! Economizer choice "Bypass" forces minimum OA except when high humidity air flow is active based on indoor RH
IF (OAController(OAControllerNum)%EconBypass .AND. &
EconomizerAirFlowScheduleValue .EQ. 0.0d0)THEN
OASignal = OutAirMinFrac
END IF
! Set outdoor air signal based on OA flow ratio if high humidity air flow is enabled
IF(HighHumidityOperationFlag) THEN
IF(OAController(OAControllerNum)%MixMassFlow .GT. 0.0d0)THEN
! calculate the actual ratio of outside air to mixed air so the magnitude of OA during high humidity control is correct
OASignal = MAX(OutAirMinFrac, &
(OAController(OAControllerNum)%HighRHOAFlowRatio*OAController(OAControllerNum)%MaxOAMassFlowRate/ &
OAController(OAControllerNum)%MixMassFlow))
END IF
END IF
! Night ventilation control overrides economizer and high humidity control.
IF (AirLoopNightVent)OASignal = 1.0d0
! Changed by Amit for new feature
IF (OAController(OAControllerNum)%MinOAflowSchPtr .GT.0) THEN
MinOAflowfracVal = GetCurrentScheduleValue(OAController(OAControllerNum)%MinOAflowSchPtr)
MinOAflowfracVal = MIN(MAX(MinOAflowfracVal,0.0d0),1.0d0)
IF(MinOAflowfracVal .GT. OutAirMinFrac)THEN
OutAirMinFrac = MinOAflowfracVal
IF(AirLoopNum > 0) &
AirLoopFlow(AirLoopNum)%MinOutAir = OutAirMinFrac * OAController(OAControllerNum)%MixMassFlow
END IF
OASignal = Max(MinOAflowfracVal, OASignal)
END IF
IF (OAController(OAControllerNum)%MaxOAflowSchPtr .GT.0) THEN
MaxOAflowfracVal = GetCurrentScheduleValue(OAController(OAControllerNum)%MaxOAflowSchPtr)
MaxOAflowfracVal = MIN(MAX(MaxOAflowfracVal,0.0d0),1.0d0)
IF(MaxOAflowfracVal .LT. OutAirMinFrac)THEN
OutAirMinFrac = MaxOAflowfracVal
IF(AirLoopNum > 0) &
AirLoopFlow(AirLoopNum)%MinOutAir = OutAirMinFrac * OAController(OAControllerNum)%MixMassFlow
END IF
OASignal = Min(MaxOAflowfracVal, OASignal)
IF(OAController(OAControllerNum)%MinOAflowSchPtr .GT.0) THEN
IF (MaxOAflowfracVAl .LT. MinOAFlowfracval) THEN
Call Showwarningerror('Min OA flow frac Greater than Max OA flow frac - check the Schedules in "Controller:OutdoorAir " ' &
//TRIM(OAController(OAControllerNum)%MinOAflowSch)//TRIM(OAController(OAControllerNum)%MaxOAflowSch))
END IF
END IF
END IF
! Calculate the outside air mass flow rate
!IF (OAController(OAControllerNum)%FixedMin) Then
!IF(AirloopNum > 0) THEN
! OAController(OAControllerNum)%OAMassflow = OASignal * AirLoopFlow(AirLoopNum)%DesSupply
! ELSE ! No Air Loop
! CALL Showsevereerror('Fixed minimum limit works only with Air loop defined')
! Errorsfound =.TRUE.
!END IF
!ELSE ! Its Propotional Minimum
OAController(OAControllerNum)%OAMassflow = OASignal* OAController(OAControllerNum)%MixMassFlow
!END IF
! Do not allow OA to be below Ventilation:Mechanical flow rate or above mixed mass flow rate
IF(AirLoopNum > 0 .AND. VentMechObjectNum /= 0)THEN
IF(MechVentOutsideAirFlow .GT. OAController(OAControllerNum)%OAMassFlow)THEN
OAController(OAControllerNum)%OAMassFlow = MIN(MechVentOutsideAirFlow,OAController(OAControllerNum)%MixMassFlow)
END IF
END IF
! Do not allow OA to be below Exh for controller:outside air
IF(OAController(OAControllerNum)%ControllerType_Num == ControllerOutsideAir)THEN
OAController(OAControllerNum)%OAMassFlow = MAX(OAController(OAControllerNum)%ExhMassFlow,&
OAController(OAControllerNum)%OAMassFlow)
END IF
! if fixed minimum, don't let go below min OA
IF (OAController(OAControllerNum)%FixedMin) THEN
! cycling fans allow "average" min OA to be below minimum
IF (.NOT. AirLoopCyclingFan) THEN
OAController(OAControllerNum)%OAMassFlow = MAX(OAController(OAControllerNum)%OAMassFlow,&
OAController(OAControllerNum)%MinOAMassFlowRate * MinOASchedVal)
END IF
END IF
! Don't let OA flow be > mixed air flow.
OAController(OAControllerNum)%OAMassFlow = MIN(OAController(OAControllerNum)%OAMassFlow, &
OAController(OAControllerNum)%MixMassFlow)
! Don't let the OA flow be > than the max OA limit. OA for high humidity control is allowed to be greater than max OA.
! Night Ventilation has priority and may override an OASignal > 1 high humidity condition with OASignal = 1
IF(HighHumidityOperationFlag)THEN
OAController(OAControllerNum)%OAMassFlow = MIN(OAController(OAControllerNum)%OAMassFlow,&
OAController(OAControllerNum)%MaxOAMassFlowRate*MAX(1.0d0,OASignal))
ELSE
OAController(OAControllerNum)%OAMassFlow = MIN(OAController(OAControllerNum)%OAMassFlow,&
OAController(OAControllerNum)%MaxOAMassFlowRate)
END IF
IF (OAController(OAControllerNum)%EMSOverrideOARate) THEN
OAController(OAControllerNum)%OAMassFlow = OAController(OAControllerNum)%EMSOARateValue
ENDIF
! save the min outside air flow fraction and max outside air mass flow rate
IF (AirLoopNum > 0) THEN
AirLoopFlow(AirLoopNum)%OAMinFrac = OutAirMinFrac
IF(OAController(OAControllerNum)%MixMassFlow .GT. 0.0d0)THEN
AirLoopFlow(AirLoopNum)%OAFrac = OAController(OAControllerNum)%OAMassflow / OAController(OAControllerNum)%MixMassFlow
ELSE
AirLoopFlow(AirLoopNum)%OAFrac = 0.0D0
END IF
OAController(OAControllerNum)%MinOAFracLimit = OutAirMinFrac
IF(HighHumidityOperationFlag .AND. OASignal .GT. 1.0d0)THEN
AirLoopFlow(AirLoopNum)%MaxOutAir = OAController(OAControllerNum)%MaxOAMassFlowRate * OASignal
ELSE
AirLoopFlow(AirLoopNum)%MaxOutAir = OAController(OAControllerNum)%MaxOAMassFlowRate
END IF
! set the air loop economizer and high humidity control flags.
IF (EconomizerOperationFlag) THEN
IF(OAController(OAControllerNum)%HeatRecoveryBypassControlType == BypassWhenOAFlowGreaterThanMinimum)THEN
! Optional heat recovery bypass control flag uses additional logic to allow ERV optimization
IF(AirLoopControlInfo(AirLoopNum)%CheckHeatRecoveryBypassStatus .AND. &
AirLoopControlInfo(AirLoopNum)%OASysComponentsSimulated)THEN
ReliefMassFlowAtMinOA = MAX(AirLoopFlow(AirLoopNum)%MinOutAir &
- OAController(OAControllerNum)%ExhMassFlow,0.0d0)
RecircMassFlowRateAtMinOAFlow = MAX(Node(OAController(OAControllerNum)%RetNode)%MassFlowRate &
- ReliefMassFlowAtMinOA,0.0d0)
IF((RecircMassFlowRateAtMinOAFlow+AirLoopFlow(AirLoopNum)%MinOutAir) .GT. 0.0D0)THEN
RecircTemp = Node(OAController(OAControllerNum)%RetNode)%Temp
MixedAirTempAtMinOAFlow = (RecircMassFlowRateAtMinOAFlow*RecircTemp + AirLoopFlow(AirLoopNum)%MinOutAir*&
Node(OAController(OAControllerNum)%OANode)%Temp) / &
(RecircMassFlowRateAtMinOAFlow+AirLoopFlow(AirLoopNum)%MinOutAir)
ELSE
MixedAirTempAtMinOAFlow = Node(OAController(OAControllerNum)%RetNode)%Temp
END IF
OAController(OAControllerNum)%MixedAirTempAtMinOAFlow = MixedAirTempAtMinOAFlow
IF (OAController(OAControllerNum)%OAMassFlow > AirLoopFlow(AirLoopNum)%MinOutAir) THEN
AirLoopControlInfo(AirLoopNum)%HeatRecoveryBypass = .TRUE.
OAController(OAControllerNum)%HeatRecoveryBypassStatus = 1
ELSE
AirLoopControlInfo(AirLoopNum)%HeatRecoveryBypass = .FALSE.
OAController(OAControllerNum)%HeatRecoveryBypassStatus = 0
END IF
IF (MixedAirTempAtMinOAFlow .LE. Node(OAController(OAControllerNum)%MixNode)%TempSetPoint) THEN
AirLoopControlInfo(AirLoopNum)%EconomizerFlowLocked = .TRUE.
OAController(OAControllerNum)%OAMassFlow = AirLoopFlow(AirLoopNum)%MinOutAir
AirLoopFlow(AirLoopNum)%OAFrac = OAController(OAControllerNum)%OAMassflow / OAController(OAControllerNum)%MixMassFlow
AirLoopFlow(AirLoopNum)%OAMinFrac = AirLoopFlow(AirLoopNum)%OAFrac
ELSE ! IF (MixedAirTempAtMinOAFlow .LE. Node(OAController(OAControllerNum)%MixNode)%TempSetPoint) THEN
AirLoopControlInfo(AirLoopNum)%EconomizerFlowLocked = .FALSE.
OAController(OAControllerNum)%HRHeatingCoilActive = 0
ENDIF ! IF (MixedAirTempAtMinOAFlow .LE. Node(OAController(OAControllerNum)%MixNode)%TempSetPoint) THEN
AirLoopControlInfo(AirLoopNum)%CheckHeatRecoveryBypassStatus = .FALSE.
END IF ! IF(AirLoopControlInfo(AirLoopNum)%CheckHeatRecoveryBypassStatus .AND. &
ELSE ! IF(OAController(OAControllerNum)%HeatRecoveryBypassControlType == BypassWhenOAFlowGreaterThanMinimum)THEN
AirLoopControlInfo(AirLoopNum)%HeatRecoveryBypass = .TRUE.
OAController(OAControllerNum)%HeatRecoveryBypassStatus = 1
END IF ! IF(OAController(OAControllerNum)%HeatRecoveryBypassControlType == BypassWhenOAFlowGreaterThanMinimum)THEN
ELSE ! IF (EconomizerOperationFlag) THEN
AirLoopControlInfo(AirLoopNum)%HeatRecoveryBypass = .FALSE.
OAController(OAControllerNum)%HeatRecoveryBypassStatus = 0
OAController(OAControllerNum)%MixedAirTempAtMinOAFlow = Node(OAController(OAControllerNum)%RetNode)%Temp
ENDIF ! IF (EconomizerOperationFlag) THEN
AirLoopControlInfo(AirLoopNum)%EconoActive = EconomizerOperationFlag
AirLoopControlInfo(AirLoopNum)%HighHumCtrlActive = HighHumidityOperationFlag
IF(AirLoopControlInfo(AirLoopNum)%EconomizerFlowLocked)THEN
OAController(OAControllerNum)%OAMassFlow = AirLoopFlow(AirLoopNum)%MinOutAir
AirLoopFlow(AirLoopNum)%OAFrac = OAController(OAControllerNum)%OAMassflow / OAController(OAControllerNum)%MixMassFlow
AirLoopFlow(AirLoopNum)%OAMinFrac = AirLoopFlow(AirLoopNum)%OAFrac
END IF
! turn on OA heat exchanger any time heating is active and user requests the special bypass control
IF(AirLoopControlInfo(AirLoopNum)%HeatingActiveFlag .AND. &
OAController(OAControllerNum)%HeatRecoveryBypassControlType == BypassWhenOAFlowGreaterThanMinimum)THEN
AirLoopControlInfo(AirLoopNum)%HeatRecoveryBypass = .FALSE.
OAController(OAControllerNum)%HeatRecoveryBypassStatus = 0
OAController(OAControllerNum)%HRHeatingCoilActive = 1
! reset the OA flow to minimum
OAController(OAControllerNum)%OAMassFlow = AirLoopFlow(AirLoopNum)%MinOutAir
AirLoopFlow(AirLoopNum)%OAFrac = OAController(OAControllerNum)%OAMassflow / OAController(OAControllerNum)%MixMassFlow
AirLoopFlow(AirLoopNum)%OAMinFrac = AirLoopFlow(AirLoopNum)%OAFrac
! The airloop needs to be simulated again so that the heating coil & HX can be resimulated
IF(AirLoopControlInfo(AirLoopNum)%HeatRecoveryResimFlag .AND. AirLoopControlInfo(AirLoopNum)%OASysComponentsSimulated)THEN
AirLoopControlInfo(AirLoopNum)%ResimAirLoopFlag = .TRUE.
AirLoopControlInfo(AirLoopNum)%HeatRecoveryResimFlag = .FALSE.
AirLoopControlInfo(AirLoopNum)%HeatRecoveryResimFlag2 = .TRUE.
! on the first iteration, air loop heating coils have not be simulated so HeatingCoilActive=FALSE
! on the second iteration, the heating coils could have been on, but logic tests here could deactivate heating coil
! reset heating coil active status and HX since logic tests may turn off heating coil
! the ResimAirLoopFlag will force another iteration and things should line up on subsequent iterations
AirLoopControlInfo(AirLoopNum)%HeatingActiveFlag = .FALSE.
OAController(OAControllerNum)%HRHeatingCoilActive = 0
AirLoopControlInfo(AirLoopNum)%HeatRecoveryBypass = .TRUE.
OAController(OAControllerNum)%HeatRecoveryBypassStatus = 1
ELSE IF(AirLoopControlInfo(AirLoopNum)%HeatRecoveryResimFlag2)THEN
AirLoopControlInfo(AirLoopNum)%ResimAirLoopFlag = .TRUE.
AirLoopControlInfo(AirLoopNum)%HeatRecoveryResimFlag2 = .FALSE.
ELSE
AirLoopControlInfo(AirLoopNum)%ResimAirLoopFlag = .FALSE.
END IF
ELSE ! IF(AirLoopControlInfo(AirLoopNum)%HeatingActiveFlag)THEN
OAController(OAControllerNum)%HRHeatingCoilActive = 0
END IF ! IF(AirLoopControlInfo(AirLoopNum)%HeatingActiveFlag)THEN
END IF ! IF (AirLoopNum > 0) THEN
! Set the relief air flow rate (must be done last to account for changes in OAMassflow
OAController(OAControllerNum)%RelMassFlow = MAX(OAController(OAControllerNum)%OAMassFlow &
- OAController(OAControllerNum)%ExhMassFlow,0.0d0)
! Set economizer report variable and status flag
IF (OAController(OAControllerNum)%Econo .EQ. NoEconomizer)THEN
! No economizer
OAController(OAControllerNum)%EconomizerStatus = 0
OAControllerInfo(OAControllerNum)%EconoActive = .FALSE.
ELSE
! With economizer.
IF (EconomizerOperationFlag) THEN
! Economizer is enabled
OAController(OAControllerNum)%EconomizerStatus = 1
OAControllerInfo(OAControllerNum)%EconoActive = .TRUE.
ELSE
! Economizer is disabled
OAController(OAControllerNum)%EconomizerStatus = 0
OAControllerInfo(OAControllerNum)%EconoActive = .FALSE.
ENDIF
ENDIF
! Set high humidity control report variable and status flag
IF(HighHumidityOperationFlag)THEN
OAController(OAControllerNum)%HighHumCtrlStatus = 1
OAControllerInfo(OAControllerNum)%HighHumCtrlActive = .TRUE.
ELSE
OAController(OAControllerNum)%HighHumCtrlStatus = 0
OAControllerInfo(OAControllerNum)%HighHumCtrlActive = .FALSE.
END IF
! Save OA fraction for reporting
IF (OAController(OAControllerNum)%MixMassFlow > 0) THEN
OAController(OAControllerNum)%OAFractionRpt = OAController(OAControllerNum)%OAMassflow / OAController(OAControllerNum)%MixMassFlow
ELSE
IF (OAController(OAControllerNum)%OAMassflow > 0) THEN
OAController(OAControllerNum)%OAFractionRpt = OASignal
ELSE
OAController(OAControllerNum)%OAFractionRpt = 0.0d0
ENDIF
ENDIF
! IF (ErrorsFound) THEN
! CALL ShowFatalError('Errors found in getting Controller:OutdoorAir inputs')
! ENDIF
RETURN
END SUBROUTINE CalcOAController