SUBROUTINE CalcPurchAirLoads(PurchAirNum, SysOutputProvided, MoistOutputProvided, ControlledZoneNum, ActualZoneNum)
          ! SUBROUTINE INFORMATION:
          !       AUTHOR         Russ Taylor
          !       DATE WRITTEN   Nov 1997
          !       MODIFIED       Shirey, Aug 2009 (LatOutputProvided - now MoistOutputProvided)
          !                      M. Witte June 2011, add new features including DCV, economizer, dehumidification
          !                          and humidification,
          !                      July 2012, Chandan Sharma - FSEC: Added hybrid ventilation manager
          !       RE-ENGINEERED  na
          ! PURPOSE OF THIS SUBROUTINE:
          ! Needs description.
          ! METHODOLOGY EMPLOYED:
          ! Needs description, as appropriate.
          ! REFERENCES:
          ! na
          ! USE STATEMENTS:
         USE DataZoneEnergyDemands, ONLY: ZoneSysEnergyDemand, ZoneSysMoistureDemand
         USE DataLoopNode, ONLY: Node
         USE DataZoneEquipment, ONLY: ZoneEquipConfig
         USE DataHVACGlobals, ONLY: SmallLoad, ZoneComp, ForceOff
         USE DataHeatBalance, ONLY: Zone
         USE DataHeatBalFanSys, ONLY:TempControlType
         USE General, ONLY: TrimSigDigits
         USE DataContaminantBalance, ONLY: Contaminant
         USE DataZoneEquipment, ONLY: PurchasedAir_Num
        IMPLICIT NONE ! Enforce explicit typing of all variables in this routine
          ! SUBROUTINE ARGUMENT DEFINITIONS:
         REAL(r64), INTENT(INOUT) :: SysOutputProvided ! Sensible output provided [W] cooling = negative
         REAL(r64), INTENT(OUT)   :: MoistOutputProvided ! Moisture output provided [kg/s] dehumidification = negative
         INTEGER, INTENT(IN) :: ActualZoneNum
         INTEGER, INTENT(IN) :: ControlledZoneNum
         INTEGER, INTENT(IN) :: PurchAirNum
          ! SUBROUTINE PARAMETER DEFINITIONS:
          ! na
          ! INTERFACE BLOCK SPECIFICATIONS:
          ! na
          ! DERIVED TYPE DEFINITIONS:
          ! na
          ! SUBROUTINE LOCAL VARIABLE DECLARATIONS:
         INTEGER   :: InNodeNum         ! Ideal loads supply node to zone
!         INTEGER   :: ExhNodeNum        ! Ideal loads exhaust node from zone
         INTEGER   :: ZoneNodeNum       ! Zone air node
         INTEGER   :: OANodeNum         ! Outdoor air inlet node
         INTEGER   :: RecircNodeNum     ! Return air or zone exhaust node
         INTEGER   :: OperatingMode     ! current operating mode, Off, Heat, Cool, or Deadband
         REAL(r64) :: SupplyMassFlowRate  ! System supply air mass flow rate [kg/s]
         REAL(r64) :: SupplyMassFlowRateForHumid  ! System supply air mass flow rate required to meet humdification load [kg/s]
         REAL(r64) :: SupplyMassFlowRateForDehum  ! System supply air mass flow rate required to meet dehumidification load [kg/s]
         REAL(r64) :: SupplyMassFlowRateForCool   ! System supply air mass flow rate required to meet sensible cooling load[kg/s]
         REAL(r64) :: SupplyMassFlowRateForHeat   ! System supply air mass flow rate required to meet sensible heating load[kg/s]
         REAL(r64) :: SupplyHumRatForHumid ! Supply air humidity ratio require to meet the humidification load [kgH2O/kgAir]
         REAL(r64) :: SupplyHumRatForDehum ! Supply air humidity ratio require to meet the dehumidification load [kgH2O/kgAir]
         REAL(r64) :: OAMassFlowRate    ! Outdoor air mass flow rate [kg/s]
         REAL(r64) :: OAVolFlowRate     ! Outdoor air volume flow rate at standard density [m3/s]
         REAL(r64) :: MinOASensOutput   ! Minimum Outdoor air sensible output [W], <0 means OA is cooler than zone air
         REAL(r64) :: MinOALatOutput    ! Minimum Outdoor air moisture load [kg/s]
         REAL(r64) :: SensOutput        ! Sensible output [W] (psitive means heating, negative means cooling)
         REAL(r64) :: HeatSensOutput    ! Heating sensible output [W]
         REAL(r64) :: CoolSensOutput    ! Cooling sensible output [W] (positive value menas cooling)
         REAL(r64) :: LatOutput         ! Latent output [W] (positive value means hudmification, negative means dehumidification)
         REAL(r64) :: CoolLatOutput     ! Cooling latent output [W] (positive value means dehumidification)
         REAL(r64) :: CoolTotOutput     ! Cooling total output [W] (positive value means cooling)
         REAL(r64) :: DeltaT            ! Delta temperature - reused in multiple places
         REAL(r64) :: DeltaHumRat       ! Delta humidity ratio - reused in multiple places
         REAL(r64) :: QZnHeatSP         ! Load required to meet heating setpoint [W] (>0 is a heating load)
         REAL(r64) :: QZnCoolSP         ! Load required to meet cooling setpoint [W] (<0 is a cooling load)
         REAL(r64) :: MdotZnHumidSP     ! Load required to meet humidifying setpoint [kg H2O/s] (>0 = a humidify load)
         REAL(r64) :: MdotZnDehumidSP   ! Load required to meet dehumidifying setpoint [kg H2O/s] (<0 = a dehumidify load)
         LOGICAL   :: UnitOn
         LOGICAL   :: HeatOn            ! Flag for heating and humidification availbility schedule, true if heating is on
         LOGICAL   :: CoolOn            ! Flag for cooling and dehumidification availbility schedule, true if cooling is on
         LOGICAL   :: EconoOn           ! Flag for economizer operation, true if economizer is on
         REAL(r64) :: SupplyTemp        ! Supply inlet to zone dry bulb temperature [C]
         REAL(r64) :: SupplyHumRat      ! Supply inlet to zone humidity ratio [kg H2O/kg Air]
         REAL(r64) :: SupplyHumRatOrig  ! Supply inlet to zone humidity ratio before saturation check [kg H2O/kg Air]
         REAL(r64) :: SupplyHumRatSat   ! Supply inlet to zone humidity ratio saturation at SupplyTemp [kg H2O/kg Air]
         REAL(r64) :: SupplyEnthalpy    ! Supply inlet to zone enthalpy [J/kg]
         REAL(r64) :: MixedAirTemp      ! Mixed air dry bulb temperature [C]
         REAL(r64) :: MixedAirHumRat    ! Mixed air humidity ratio [kg H2O/kg Air]
         REAL(r64) :: MixedAirEnthalpy  ! Mixed air enthalpy [J/kg]
         REAL(r64) :: CpAir        ! Specific heat [J/kg-C] reused in multiple places
!         REAL(r64) :: SpecHumOut   ! Specific humidity ratio of outlet air (kg moisture / kg moist air)
!         REAL(r64) :: SpecHumIn    ! Specific humidity ratio of inlet [zone] air (kg moisture / kg moist air)
           ! Sign convention: SysOutputProvided <0 Supply air is heated on entering zone (zone is cooled)
           !                  SysOutputProvided >0 Supply air is cooled on entering zone (zone is heated)
         InNodeNum = PurchAir(PurchAirNum)%ZoneSupplyAirNodeNum
         ZoneNodeNum = ZoneEquipConfig(ControlledZoneNum)%ZoneNode
         OANodeNum = PurchAir(PurchAirNum)%OutdoorAirNodeNum
         RecircNodeNum = PurchAir(PurchAirNum)%ZoneRecircAirNodeNum
         SupplyMassFlowRate = 0.0d0
         OAMassFlowRate = 0.0d0
         PurchAir(PurchAirNum)%MinOAMassFlowRate = 0.0d0
         PurchAir(PurchAirNum)%TimeEconoActive = 0.0d0
         PurchAir(PurchAirNum)%TimeHtRecActive = 0.0d0
         SysOutputProvided = 0.0d0
         MoistOutputProvided = 0.0d0
         CoolSensOutput = 0.0d0
         CoolLatOutput = 0.0d0
         CoolTotOutput = 0.0d0
         HeatSensOutput = 0.0d0
         LatOutput = 0.0d0
            ! default unit to ON
         UnitOn = .TRUE.
         EconoOn = .FALSE.
            ! get current zone requirements
         QZnHeatSP       = ZoneSysEnergyDemand(ActualZoneNum)%RemainingOutputReqToHeatSP
         QZnCoolSP       = ZoneSysEnergyDemand(ActualZoneNum)%RemainingOutputReqToCoolSP
         IF (ALLOCATED(ZoneComp)) THEN
           ZoneComp(PurchasedAir_Num)%ZoneCompAvailMgrs(PurchAirNum)%ZoneNum = ActualZoneNum
           PurchAir(PurchAirNum)%AvailStatus = ZoneComp(PurchasedAir_Num)%ZoneCompAvailMgrs(PurchAirNum)%AvailStatus
            ! Check if the hybrid ventilation availability manager is turning the unit off
           IF (PurchAir(PurchAirNum)%AvailStatus .EQ. ForceOFf) THEN
             UnitOn = .FALSE.
           END IF
         ENDIF
            ! Check if the unit is scheduled off
!         IF (PurchAir(PurchAirNum)%AvailSchedPtr > 0) THEN
             IF (GetCurrentScheduleValue(PurchAir(PurchAirNum)%AvailSchedPtr) <= 0) THEN
                 UnitOn = .FALSE.
             END IF
!         END IF
            ! Check if heating and cooling available
         HeatOn = .TRUE.
!         IF (PurchAir(PurchAirNum)%HeatSchedPtr > 0) THEN
             IF (GetCurrentScheduleValue(PurchAir(PurchAirNum)%HeatSchedPtr) <= 0) THEN
                 HeatOn = .FALSE.
             END IF
!         END IF
         CoolOn = .TRUE.
!         IF (PurchAir(PurchAirNum)%CoolSchedPtr > 0) THEN
             IF (GetCurrentScheduleValue(PurchAir(PurchAirNum)%CoolSchedPtr) <= 0) THEN
                 CoolOn = .FALSE.
             END IF
!         END IF
         IF (UnitON) THEN
             ! Calculate current minimum outdoor air flow rate based on design OA specifications and DCV or CO2 control
             CALL CalcPurchAirMinOAMassFlow(PurchAirNum, ActualZoneNum, OAMassFlowRate)
             ! EMS override point  Purch air outdoor air massflow rate.....
             IF (PurchAir(PurchAirNum)%EMSOverrideOAMdotOn) THEN
               OAMassFlowRate = PurchAir(PurchAirNum)%EMSValueOAMassFlowRate
             ENDIF
             ! Calculate minimum outdoor air sensible and latent load
             IF (PurchAir(PurchAirNum)%OutdoorAir) THEN
               CpAir = PsyCpAirFnWTdb(Node(OANodeNum)%HumRat,Node(OANodeNum)%Temp, 'CalcPurchAirLoads')
               MinOASensOutput = OAMassFlowRate * CpAir * (Node(OANodeNum)%Temp - Node(ZoneNodeNum)%Temp)
               MinOALatOutput  = OAMassFlowRate * (Node(OANodeNum)%HumRat - Node(ZoneNodeNum)%HumRat)
             ELSE
               MinOASensOutput = 0.0d0
               MinOALatOutput  = 0.0d0
             ENDIF
             SupplyMassFlowRate = OAMassFlowRate
             ! Check if cooling of the supply air stream is required
                                     ! Cooling operation
           IF ((MinOASensOutput >= QZnCoolSP) .AND. (TempControlType(ActualZoneNum) .NE. SingleHeatingSetPoint)) THEN
             OperatingMode = Cool
             ! Calculate supply mass flow, temp and humidity with the following constraints:
             !  Min cooling supply temp
             !  Max total cooling capacity
             !  Max cooling airflow
             !  Min cooling supply humrat  (and Max heating supply humrat)
             !  Min OA mass flow rate
             ! Check if OA flow rate greater than max cooling airflow limit
             IF (((PurchAir(PurchAirNum)%CoolingLimit == LimitFlowRate) .OR. &
                  (PurchAir(PurchAirNum)%CoolingLimit == LimitFlowRateAndCapacity)) &
                  .AND. (OAMassFlowRate .GT. PurchAir(PurchAirNum)%MaxCoolMassFlowRate)) THEN
               OAVolFlowRate = OAMassFlowRate / StdRhoAir
               IF (PurchAir(PurchAirNum)%OAFlowMaxCoolOutputError < 1) THEN
                 PurchAir(PurchAirNum)%OAFlowMaxCoolOutputError = PurchAir(PurchAirNum)%OAFlowMaxCoolOutputError + 1
                 Call ShowWarningError(TRIM(PurchAir(PurchAirNum)%cObjectName)//' "'//TRIM(PurchAir(PurchAirNum)%Name)//'"'&
                                       //' Requested outdoor air flow rate = '//TRIM(TrimSigDigits(OAVolFlowRate,5)) &
                                       //' [m3/s] exceeds limit.')
                 CALL ShowContinueError(' Will be reduced to the Maximum Cooling Air Flow Rate = ' &
                                        //TRIM(TrimSigDigits(PurchAir(PurchAirNum)%MaxCoolVolFlowRate,5))//' [m3/s]')
                 CALL ShowContinueErrorTimeStamp(' ')
               ELSE
                 CALL ShowRecurringWarningErrorAtEnd(TRIM(PurchAir(PurchAirNum)%cObjectName)//' "'&
                       //TRIM(PurchAir(PurchAirNum)%Name)//'"'//&
                       ' Requested outdoor air flow rate [m3/s] reduced to Maximum Cooling Air Flow Rate warning continues...' &
                       , PurchAir(PurchAirNum)%OAFlowMaxCoolOutputIndex, OAVolFlowRate)
               END IF
               OAMassFlowRate = PurchAir(PurchAirNum)%MaxCoolMassFlowRate
             ELSE
               ! Model economizer
               IF (PurchAir(PurchAirNum)%EconomizerType /= NoEconomizer) THEN
                 IF (((PurchAir(PurchAirNum)%EconomizerType == DifferentialDryBulb) &
                       .AND. (Node(OANodeNum)%Temp < Node(PurchAir(PurchAirNum)%ZoneRecircAirNodeNum)%Temp)) .OR. &
                     ((PurchAir(PurchAirNum)%EconomizerType == DifferentialEnthalpy) &
                       .AND. (Node(OANodeNum)%Enthalpy < Node(PurchAir(PurchAirNum)%ZoneRecircAirNodeNum)%Enthalpy))) THEN
                    ! Calculate supply MassFlowRate based on sensible load but limit to Max Cooling Supply Air Flow Rate if specified
                   CpAir = PsyCpAirFnWTdb(ZoneAirHumRat(ActualZoneNum),Node(ZoneNodeNum)%Temp, 'CalcPurchAirLoads')
                   DeltaT = (Node(OANodeNum)%Temp - Node(ZoneNodeNum)%Temp)
                   IF (DeltaT < -SmallTempDiff) THEN
                     SupplyMassFlowRate = QZnCoolSP/CPAir/DeltaT
                     IF (((PurchAir(PurchAirNum)%CoolingLimit == LimitFlowRate) .OR. &
                          (PurchAir(PurchAirNum)%CoolingLimit == LimitFlowRateAndCapacity)) &
                          .AND. (PurchAir(PurchAirNum)%MaxCoolMassFlowRate .GT. 0.0d0)) THEN
                       SupplyMassFlowRate = MIN(MAX(SupplyMassFlowRate,0.0d0),PurchAir(PurchAirNum)%MaxCoolMassFlowRate)
                     END IF
                     IF (SupplyMassFlowRate > OAMassFlowRate) THEN
                       EconoOn = .TRUE.
                       OAMassFlowRate = SupplyMassFlowRate
                       PurchAir(PurchAirNum)%TimeEconoActive = TimeStepSys
                     END IF
                   END IF
                 END IF
               END IF
             END IF
             ! Determine supply mass flow rate
                 ! Mass flow rate to meet sensible load, at Minimum Cooling Supply Air Temperature
             SupplyMassFlowRateForCool = 0.0d0
             IF (CoolOn) THEN
               CpAir = PsyCpAirFnWTdb(ZoneAirHumRat(ActualZoneNum),Node(ZoneNodeNum)%Temp, 'CalcPurchAirLoads')
               DeltaT = (PurchAir(PurchAirNum)%MinCoolSuppAirTemp - Node(ZoneNodeNum)%Temp)
               IF (DeltaT < -SmallTempDiff) THEN
                 SupplyMassFlowRateForCool = QZnCoolSP/CPAir/DeltaT
               ENDIF
             ENDIF
                 ! Mass flow rate to meet dehumidification load, if applicable, at Minimum Cooling Supply Humidity Ratio
             SupplyMassFlowRateForDehum = 0.0d0
             IF (CoolOn) THEN
               IF (PurchAir(PurchAirNum)%DehumidCtrlType .EQ. Humidistat) THEN
                 MdotZnDehumidSP= ZoneSysMoistureDemand(ActualZoneNum)%RemainingOutputReqToDehumidSP
                 DeltaHumRat = (PurchAir(PurchAirNum)%MinCoolSuppAirHumRat - Node(ZoneNodeNum)%HumRat)
                 IF ((DeltaHumRat < -SmallDeltaHumRat) .AND. (MdotZnDehumidSP .LT. 0.0d0)) THEN
                   SupplyMassFlowRateForDehum = MdotZnDehumidSP/DeltaHumRat
                 ENDIF
               ENDIF
             ENDIF
                 ! Mass flow rate to meet humidification load, if applicable, at Maximum Heating Supply Humidity Ratio
                 ! This section is the cooling section, so humidification should activate only if humidification control = humidistat
                 !   and if dehumidification control = humidistat or none
             SupplyMassFlowRateForHumid = 0.0d0
             IF (HeatOn) THEN
               IF (PurchAir(PurchAirNum)%HumidCtrlType .EQ. Humidistat) THEN
                 IF ((PurchAir(PurchAirNum)%DehumidCtrlType .EQ. Humidistat) .OR. &
                     (PurchAir(PurchAirNum)%DehumidCtrlType .EQ. None)) THEN
                   MdotZnHumidSP = ZoneSysMoistureDemand(ActualZoneNum)%RemainingOutputReqToHumidSP
                   DeltaHumRat = (PurchAir(PurchAirNum)%MaxHeatSuppAirHumRat - Node(ZoneNodeNum)%HumRat)
                   IF ((DeltaHumRat > SmallDeltaHumRat) .AND. (MdotZnHumidSP .GT. 0.0d0)) THEN
                     SupplyMassFlowRateForHumid = MdotZnHumidSP/DeltaHumRat
                   ENDIF
                 ENDIF
               ENDIF
             ENDIF
                 ! Supply mass flow is greatest of these, but limit to cooling max flow rate, if applicable
             SupplyMassFlowRate = MAX(0.0d0, OAMassFlowRate, SupplyMassFlowRateForCool, &
                                     SupplyMassFlowRateForDehum, SupplyMassFlowRateForHumid)
             ! EMS override point  Purch air massflow rate..... but only if unit is on, i.e. SupplyMassFlowRate>0.0
             IF ((PurchAir(PurchAirNum)%EMSOverrideMdotOn) .AND. (SupplyMassFlowRate > 0.0d0)) THEN
               SupplyMassFlowRate = PurchAir(PurchAirNum)%EMSValueMassFlowRate
               OAMassFlowRate = MIN(OAMassFlowRate,SupplyMassFlowRate)
             ENDIF
             IF (((PurchAir(PurchAirNum)%CoolingLimit == LimitFlowRate) .OR. &
                  (PurchAir(PurchAirNum)%CoolingLimit == LimitFlowRateAndCapacity)) &
                  .AND. (PurchAir(PurchAirNum)%MaxCoolMassFlowRate .GT. 0.0d0)) THEN
               SupplyMassFlowRate = MIN(SupplyMassFlowRate,PurchAir(PurchAirNum)%MaxCoolMassFlowRate)
             END IF
             IF (SupplyMassFlowRate <= VerySmallMassFlow) SupplyMassFlowRate = 0.0d0
             ! Calculate mixed air conditions
             CALL CalcPurchAirMixedAir(PurchAirNum, OAMassFlowRate, SupplyMassFlowRate, &
                                         MixedAirTemp, MixedAirHumRat, MixedAirEnthalpy, OperatingMode)
             ! Calculate supply air conditions using final massflow rate, imposing capacity limits if specified
             ! If capacity limits are exceeded, keep massflow rate where it is and adjust supply temp
             ! In general, in the cooling section, don't let SupplyTemp be set to something that results in heating
             IF (SupplyMassFlowRate .GT. 0.0d0) THEN
               ! Calculate supply temp at SupplyMassFlowRate and recheck limit on Minimum Cooling Supply Air Temperature
               CpAir = PsyCpAirFnWTdb(ZoneAirHumRat(ActualZoneNum),Node(ZoneNodeNum)%Temp, 'CalcPurchAirLoads')
               SupplyTemp = QZnCoolSP/(CPAir*SupplyMassFlowRate) + Node(ZoneNodeNum)%Temp
               SupplyTemp = MAX(SupplyTemp,PurchAir(PurchAirNum)%MinCoolSuppAirTemp)
               ! This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
               SupplyTemp = MIN(SupplyTemp,MixedAirTemp)
               SupplyHumRat = MixedAirHumRat
               SupplyEnthalpy = PsyHFnTdbW(SupplyTemp,SupplyHumRat, 'CalcPurchAirLoads')
               ! Check sensible load vs max total cooling capacity, if specified, and adjust supply temp before applying humidity controls
               ! Will check again later, too
               IF ((PurchAir(PurchAirNum)%CoolingLimit == LimitCapacity) .OR. &
                   (PurchAir(PurchAirNum)%CoolingLimit == LimitFlowRateAndCapacity)) THEN
                 CpAir = PsyCpAirFnWTdb(MixedAirHumRat,MixedAirTemp, 'CalcPurchAirLoads')
                 CoolSensOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy)
                 IF (CoolSensOutput >= PurchAir(PurchAirNum)%MaxCoolTotCap) THEN
                   CoolSensOutput = PurchAir(PurchAirNum)%MaxCoolTotCap
                   SupplyEnthalpy = MixedAirEnthalpy - CoolSensOutput/SupplyMassFlowRate
                   SupplyTemp = PsyTdbFnHW(SupplyEnthalpy,SupplyHumRat, 'CalcPurchAirLoads')
                   ! This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
                   SupplyTemp = MIN(SupplyTemp,MixedAirTemp)
                 END IF ! Capacity limit exceeded
               END IF
               ! Set supply humidity ratio for cooling/dehumidification
               SupplyHumRat = MixedAirHumRat
               SELECT CASE(PurchAir(PurchAirNum)%DehumidCtrlType)
                 CASE(None)
                   SupplyHumRat = MixedAirHumRat
                 CASE(ConstantSensibleHeatRatio)
                   ! SHR = CoolSensOutput/CoolTotOutput
                   ! CoolTotOutput = CoolSensOutput/SHR
                   CpAir = PsyCpAirFnWTdb(MixedAirHumRat,MixedAirTemp, 'CalcPurchAirLoads')
                   CoolSensOutput = SupplyMassFlowRate * CpAir * (MixedAirTemp - SupplyTemp)
                   CoolTotOutput = CoolSensOutput/PurchAir(PurchAirNum)%CoolSHR
                   SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput/SupplyMassFlowRate
                   !  Limit for overdrying (avoid Pysch errors which occur if SupplyEnthalpy is too low for SupplyTemp)
                   SupplyEnthalpy = MAX(SupplyEnthalpy,PsyHFnTdbW(SupplyTemp,0.00001D0, 'CalcPurchAirLoads'))
                   SupplyHumRat = MIN(SupplyHumRat,PsyWFnTdbH(SupplyTemp,SupplyEnthalpy, 'CalcPurchAirLoads'))
                   ! Apply min cooling humidity ratio limit
                   SupplyHumRat = MAX(SupplyHumRat, PurchAir(PurchAirNum)%MinCoolSuppAirHumRat)
                   ! But don't let it be higher than incoming MixedAirHumRat
                   SupplyHumRat = MIN(SupplyHumRat,MixedAirHumRat)
                 CASE(Humidistat)
                   MdotZnDehumidSP= ZoneSysMoistureDemand(ActualZoneNum)%RemainingOutputReqToDehumidSP
                   SupplyHumRatForDehum = MdotZnDehumidSP/SupplyMassFlowRate + Node(ZoneNodeNum)%HumRat
                   SupplyHumRatForDehum = MIN(SupplyHumRatForDehum,PurchAir(PurchAirNum)%MinCoolSuppAirHumRat)
                   SupplyHumRat = MIN(MixedAirHumRat,SupplyHumRatForDehum)
                 CASE(ConstantSupplyHumidityRatio)
                   SupplyHumRat = PurchAir(PurchAirNum)%MinCoolSuppAirHumRat
                 CASE DEFAULT
                   SupplyHumRat = MixedAirHumRat
               END SELECT
                   ! Check supply humidity ratio for humidification (SupplyHumRatForHum should always be < SupplyHumRatForDehum)
                   ! This section is the cooling section, so humidification should activate only if humidification control = humidistat
                   !   and if dehumidification control = humidistat or none
               IF (HeatOn) THEN
                 IF (PurchAir(PurchAirNum)%HumidCtrlType .EQ. Humidistat) THEN
                   IF ((PurchAir(PurchAirNum)%DehumidCtrlType .EQ. Humidistat) .OR. &
                       (PurchAir(PurchAirNum)%DehumidCtrlType .EQ. None)) THEN
                     MdotZnHumidSP = ZoneSysMoistureDemand(ActualZoneNum)%RemainingOutputReqToHumidSP
                     SupplyHumRatForHumid = MdotZnHumidSP/SupplyMassFlowRate + Node(ZoneNodeNum)%HumRat
                     SupplyHumRatForHumid = MIN(SupplyHumRatForHumid,PurchAir(PurchAirNum)%MaxHeatSuppAirHumRat)
                     SupplyHumRat = MAX(SupplyHumRat,SupplyHumRatForHumid)
                   END IF
                 END IF
               END IF
               !   Limit supply humidity ratio to saturation at supply outlet temp
               SupplyHumRatOrig = SupplyHumRat
               SupplyHumRatSat  = PsyWFnTdbRhPb(SupplyTemp,1.0d0,OutBaroPress, 'CalcPurchAirLoads')
               SupplyHumRat = MIN(SupplyHumRatOrig,SupplyHumRatSat)
               SupplyEnthalpy = PsyHFnTdbW(SupplyTemp,SupplyHumRat, 'CalcPurchAirLoads')
               ! Check max total Cooling capacity, if specified
               IF ((PurchAir(PurchAirNum)%CoolingLimit == LimitCapacity) .OR. &
                   (PurchAir(PurchAirNum)%CoolingLimit == LimitFlowRateAndCapacity)) THEN
                 ! If dehumidifying, compare total cooling to the limit
                 IF (SupplyHumRat < MixedAirHumRat) THEN ! Dehumidifying
                   CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy)
                   IF ((CoolTotOutput) > PurchAir(PurchAirNum)%MaxCoolTotCap) THEN
                     CoolTotOutput = PurchAir(PurchAirNum)%MaxCoolTotCap
                     SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput/SupplyMassFlowRate
                     ! Adjust output based on dehumidification control type
                     SELECT CASE(PurchAir(PurchAirNum)%DehumidCtrlType)
                       CASE(ConstantSensibleHeatRatio)
                         ! Adjust both supply temp and humidity ratio to maintain SHR
                         ! SHR = CoolSensOutput/CoolTotOutput
                         ! CoolSensOutput = SHR*CoolTotOutput
                         CpAir = PsyCpAirFnWTdb(MixedAirHumRat,MixedAirTemp, 'CalcPurchAirLoads')
                         CoolSensOutput = CoolTotOutput * PurchAir(PurchAirNum)%CoolSHR
                         SupplyTemp = MixedAirTemp - CoolSensOutput/(CPAir*SupplyMassFlowRate)
                         ! This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
                         SupplyTemp = MIN(SupplyTemp,MixedAirTemp)
                         !  Limit for overdrying (avoid Pysch errors which occur if SupplyEnthalpy is too low for SupplyTemp)
                         SupplyEnthalpy = MAX(SupplyEnthalpy,PsyHFnTdbW(SupplyTemp,0.00001D0, 'CalcPurchAirLoads'))
                         SupplyHumRat = PsyWFnTdbH(SupplyTemp,SupplyEnthalpy, 'CalcPurchAirLoads')
                       CASE(Humidistat)
                         ! Keep supply temp and adjust humidity ratio to reduce load
                         SupplyHumRat = PsyWFnTdbH(SupplyTemp,SupplyEnthalpy, 'CalcPurchAirLoads')
                       CASE(None, ConstantSupplyHumidityRatio)
                         ! Keep humidity ratio and adjust supply temp
                         ! Check if latent output exceeds capacity
                         CpAir = PsyCpAirFnWTdb(MixedAirHumRat,MixedAirTemp, 'CalcPurchAirLoads')
                         CoolSensOutput = SupplyMassFlowRate * CpAir * (MixedAirTemp - SupplyTemp)
                         CoolLatOutput = CoolTotOutput - CoolSensOutput
                         IF (CoolLatOutput >= PurchAir(PurchAirNum)%MaxCoolTotCap) THEN
                           SupplyTemp   = MixedAirTemp
                           SupplyHumRat = PsyWFnTdbH(SupplyTemp,SupplyEnthalpy, 'CalcPurchAirLoads')
                           CoolLatOutput = PurchAir(PurchAirNum)%MaxCoolTotCap
                         ELSE
                           SupplyTemp = PsyTdbFnHW(SupplyEnthalpy,SupplyHumRat, 'CalcPurchAirLoads')
                           ! This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
                           SupplyTemp = MIN(SupplyTemp,MixedAirTemp)
                         END IF
                     END SELECT
                     ! Limit supply humidity ratio to saturation at supply outlet temp
                     ! If saturation exceeded, then honor capacity limit and set to dew point at supplyenthalpy
                     SupplyHumRatOrig = SupplyHumRat
                     SupplyHumRatSat  = PsyWFnTdbRhPb(SupplyTemp,1.0d0,OutBaroPress, 'CalcPurchAirLoads')
                     IF (SupplyHumRatSat < SupplyHumRatOrig) THEN
                       SupplyTemp = PsyTsatFnHPb(SupplyEnthalpy,OutBaroPress,'CalcPurchAirLoads')
                       ! This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
                       SupplyTemp = MIN(SupplyTemp,MixedAirTemp)
                       SupplyHumRat = PsyWFnTdbH(SupplyTemp,SupplyEnthalpy,'CalcPurchAirLoads')
                       SupplyEnthalpy = PsyHFnTdbW(SupplyTemp,SupplyHumRat, 'CalcPurchAirLoads')
                       ! CpAir = PsyCpAirFnWTdb(MixedAirHumRat,MixedAirTemp, 'CalcPurchAirLoads')
                       ! CoolSensOutput = SupplyMassFlowRate * CpAir * (MixedAirTemp - SupplyTemp)
                       ! CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy)
                     END IF
                   END IF ! Capacity limit exceeded
                 ELSE  ! Not dehumidifying
                   ! If not dehumidifying, compare sensible cooling to the limit
                   ! This section will only increase supply temp, so no need to recheck for super-saturation
                   CpAir = PsyCpAirFnWTdb(MixedAirHumRat,MixedAirTemp, 'CalcPurchAirLoads')
                   CoolSensOutput = SupplyMassFlowRate * CpAir * (MixedAirTemp - SupplyTemp)
                   IF (CoolSensOutput >= PurchAir(PurchAirNum)%MaxCoolTotCap) THEN
                     CoolSensOutput = PurchAir(PurchAirNum)%MaxCoolTotCap
                     SupplyTemp = MixedAirTemp - CoolSensOutput/(SupplyMassFlowRate * CpAir)
                   END IF ! Capacity limit exceeded
                 END IF  ! Dehumidifying or not
               END IF  ! Capacity limit active
             ELSE ! SupplyMassFlowRate is zero
               SupplyEnthalpy = MixedAirEnthalpy
               SupplyHumRat   = MixedAirHumRat
               SupplyTemp     = MixedAirTemp
               CoolSensOutput = 0.0d0
               CoolTotOutput  = 0.0d0
             END IF
                                     ! Heating or no-load operation
           ELSE  ! Heating or no-load case
             IF ((MinOASensOutput .LT. QZnHeatSP) .AND. (TempControlType(ActualZoneNum) .NE. SingleCoolingSetPoint)) THEN
               OperatingMode = Heat
             ELSE ! Deadband mode shuts off heat recovery and economizer
               OperatingMode = Deadband
             END IF
             ! Calculate supply mass flow, temp and humidity with the following constraints:
             !  Max heating supply temp
             !  Max sensible heating capacity
             !  Max heating airflow
             !  Max heating supply humrat (and Min cooling supply humrat)
             !  Min OA mass flow rate
             ! Check if OA flow rate greater than max heating airflow limit
             IF (((PurchAir(PurchAirNum)%HeatingLimit == LimitFlowRate) .OR. &
                  (PurchAir(PurchAirNum)%HeatingLimit == LimitFlowRateAndCapacity)) &
                  .AND. (OAMassFlowRate .GT. PurchAir(PurchAirNum)%MaxHeatMassFlowRate)) THEN
               OAVolFlowRate = OAMassFlowRate / StdRhoAir
               IF (PurchAir(PurchAirNum)%OAFlowMaxHeatOutputError < 1) THEN
                 PurchAir(PurchAirNum)%OAFlowMaxHeatOutputError = PurchAir(PurchAirNum)%OAFlowMaxHeatOutputError + 1
                 Call ShowWarningError(TRIM(PurchAir(PurchAirNum)%cObjectName)//' "'//TRIM(PurchAir(PurchAirNum)%Name)//'"'&
                                       //' Requested outdoor air flow rate = '//TRIM(TrimSigDigits(OAVolFlowRate,5)) &
                                       //' [m3/s] exceeds limit.')
                 CALL ShowContinueError(' Will be reduced to the Maximum Heating Air Flow Rate = ' &
                                        //TRIM(TrimSigDigits(PurchAir(PurchAirNum)%MaxHeatVolFlowRate,5))//' [m3/s]')
                 CALL ShowContinueErrorTimeStamp(' ')
               ELSE
                 CALL ShowRecurringWarningErrorAtEnd(TRIM(PurchAir(PurchAirNum)%cObjectName)//' "'&
                       //TRIM(PurchAir(PurchAirNum)%Name)//'"'//&
                       ' Requested outdoor air flow rate [m3/s] reduced to Maximum Heating Air Flow Rate warning continues...' &
                       , PurchAir(PurchAirNum)%OAFlowMaxHeatOutputIndex, OAVolFlowRate)
               END IF
               OAMassFlowRate = PurchAir(PurchAirNum)%MaxHeatMassFlowRate
             ENDIF
             SupplyMassFlowRate = OAMassFlowRate
             ! Determine supply mass flow rate
                 ! Mass flow rate to meet sensible load, at Minimum Cooling Supply Air Temperature
             SupplyMassFlowRateForHeat = 0.0d0
             IF ((HeatOn) .AND. (OperatingMode == Heat)) THEN
               CpAir = PsyCpAirFnWTdb(ZoneAirHumRat(ActualZoneNum),Node(ZoneNodeNum)%Temp, 'CalcPurchAirLoads')
               DeltaT = (PurchAir(PurchAirNum)%MaxHeatSuppAirTemp - Node(ZoneNodeNum)%Temp)
               IF (DeltaT > SmallTempDiff) THEN
                 SupplyMassFlowRateForHeat = QZnHeatSP/CPAir/DeltaT
               ENDIF
             ENDIF
                 ! Mass flow rate to meet dehumidification load, if applicable, at Minimum Cooling Supply Humidity Ratio
                 ! This section is the heating/deadband section, so dehumidification should activate
                 !   only if dehumidification control = humidistat
                 !   and if humidification control = humidistat or none or if operating in deadband mode
             SupplyMassFlowRateForDehum = 0.0d0
             IF (CoolOn) THEN
               IF (PurchAir(PurchAirNum)%DehumidCtrlType .EQ. Humidistat) THEN
                 IF ((PurchAir(PurchAirNum)%HumidCtrlType .EQ. Humidistat) .OR. &
                     (PurchAir(PurchAirNum)%HumidCtrlType .EQ. None) .OR. &
                     (OperatingMode == Deadband)) THEN
                   MdotZnDehumidSP= ZoneSysMoistureDemand(ActualZoneNum)%RemainingOutputReqToDehumidSP
                   DeltaHumRat = (PurchAir(PurchAirNum)%MinCoolSuppAirHumRat - Node(ZoneNodeNum)%HumRat)
                   IF ((DeltaHumRat < -SmallDeltaHumRat) .AND. (MdotZnDehumidSP .LT. 0.0d0)) THEN
                     SupplyMassFlowRateForDehum = MdotZnDehumidSP/DeltaHumRat
                   ENDIF
                 ENDIF
               ENDIF
             ENDIF
                 ! Mass flow rate to meet humidification load, if applicable, at Maximum Heating Supply Humidity Ratio
             SupplyMassFlowRateForHumid = 0.0d0
             IF (HeatOn) THEN
               IF (PurchAir(PurchAirNum)%HumidCtrlType .EQ. Humidistat) THEN
                 MdotZnHumidSP = ZoneSysMoistureDemand(ActualZoneNum)%RemainingOutputReqToHumidSP
                 DeltaHumRat = (PurchAir(PurchAirNum)%MaxHeatSuppAirHumRat - Node(ZoneNodeNum)%HumRat)
                 IF ((DeltaHumRat > SmallDeltaHumRat) .AND. (MdotZnHumidSP .GT. 0.0d0)) THEN
                   SupplyMassFlowRateForHumid = MdotZnHumidSP/DeltaHumRat
                 ENDIF
               ENDIF
             ENDIF
                 ! Supply mass flow is greatest of these, but limit to heating max flow rate, if applicable
             SupplyMassFlowRate = MAX(0.0d0, OAMassFlowRate, SupplyMassFlowRateForHeat, &
                                     SupplyMassFlowRateForDehum, SupplyMassFlowRateForHumid)
             ! EMS override point  Purch air massflow rate..... but only if unit is on, i.e. SupplyMassFlowRate>0.0
             IF ((PurchAir(PurchAirNum)%EMSOverrideMdotOn) .AND. (SupplyMassFlowRate > 0.0d0)) THEN
               SupplyMassFlowRate = PurchAir(PurchAirNum)%EMSValueMassFlowRate
               OAMassFlowRate = MIN(OAMassFlowRate,SupplyMassFlowRate)
             ENDIF
             IF (((PurchAir(PurchAirNum)%HeatingLimit == LimitFlowRate) .OR. &
                  (PurchAir(PurchAirNum)%HeatingLimit == LimitFlowRateAndCapacity)) &
                  .AND. (PurchAir(PurchAirNum)%MaxHeatMassFlowRate .GT. 0.0d0)) THEN
               SupplyMassFlowRate = MIN(SupplyMassFlowRate,PurchAir(PurchAirNum)%MaxHeatMassFlowRate)
             END IF
             IF (SupplyMassFlowRate <= VerySmallMassFlow) SupplyMassFlowRate = 0.0d0
             ! Calculate mixed air conditions
             CALL CalcPurchAirMixedAir(PurchAirNum, OAMassFlowRate, SupplyMassFlowRate, &
                                         MixedAirTemp, MixedAirHumRat, MixedAirEnthalpy, OperatingMode)
             ! Calculate supply air conditions using final massflow rate, imposing capacity limits if specified
             ! If capacity limits are exceeded, keep massflow rate where it is and adjust supply temp
             IF (SupplyMassFlowRate .GT. 0.0d0) THEN
               IF ((HeatOn) .AND. (OperatingMode == Heat)) THEN
                 ! Calculate supply temp at SupplyMassFlowRate and check limit on Maximum Heating Supply Air Temperature
                 CpAir = PsyCpAirFnWTdb(ZoneAirHumRat(ActualZoneNum),Node(ZoneNodeNum)%Temp, 'CalcPurchAirLoads')
                 SupplyTemp = QZnHeatSP/(CPAir*SupplyMassFlowRate) + Node(ZoneNodeNum)%Temp
                 SupplyTemp = MIN(SupplyTemp,PurchAir(PurchAirNum)%MaxHeatSuppAirTemp)
                 ! This is the heating mode, so SupplyTemp can't be less than MixedAirTemp
                 SupplyTemp = MAX(SupplyTemp,MixedAirTemp)
                 ! Check max heating capacity, if specified
                 IF ((PurchAir(PurchAirNum)%HeatingLimit == LimitCapacity) .OR. &
                   (PurchAir(PurchAirNum)%HeatingLimit == LimitFlowRateAndCapacity)) THEN
                   CpAir = PsyCpAirFnWTdb(MixedAirHumRat,MixedAirTemp, 'CalcPurchAirLoads')
                   HeatSensOutput = SupplyMassFlowRate * CpAir * (SupplyTemp - MixedAirTemp)
                   IF (HeatSensOutput > PurchAir(PurchAirNum)%MaxHeatSensCap) THEN
                     SupplyTemp = PurchAir(PurchAirNum)%MaxHeatSensCap/(SupplyMassFlowRate * CpAir) + MixedAirTemp
                     HeatSensOutput = PurchAir(PurchAirNum)%MaxHeatSensCap
                   END IF
                 END IF
               ELSE ! Heat is off or operating mode is deadband (i.e. don't do any heating)
                 SupplyTemp = MixedAirTemp
               END IF
               ! Set supply humidity ratio first for heating/humidification
               SupplyHumRat = MixedAirHumRat
               SELECT CASE(PurchAir(PurchAirNum)%HumidCtrlType)
                 CASE(None)
                   SupplyHumRat = MixedAirHumRat
                 CASE(Humidistat)
                   MdotZnHumidSP = ZoneSysMoistureDemand(ActualZoneNum)%RemainingOutputReqToHumidSP
                   SupplyHumRatForHumid = MdotZnHumidSP/SupplyMassFlowRate + Node(ZoneNodeNum)%HumRat
                   SupplyHumRatForHumid = MIN(SupplyHumRatForHumid,PurchAir(PurchAirNum)%MaxHeatSuppAirHumRat)
                   SupplyHumRat = MAX(SupplyHumRat,SupplyHumRatForHumid)
                 CASE(ConstantSupplyHumidityRatio)
                   IF (OperatingMode == Heat) THEN
                     ! If this results in dehumidification, must check cooling capacity limit
                     IF (MixedAirHumRat > PurchAir(PurchAirNum)%MaxHeatSuppAirHumRat) THEN
                       IF ((PurchAir(PurchAirNum)%CoolingLimit == LimitCapacity) .OR. &
                           (PurchAir(PurchAirNum)%CoolingLimit == LimitFlowRateAndCapacity)) THEN
                         SupplyHumRat = PurchAir(PurchAirNum)%MaxHeatSuppAirHumRat
                         SupplyEnthalpy = PsyHFnTdbW(SupplyTemp,SupplyHumRat, 'CalcPurchAirLoads')
                         CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy)
                         CpAir = PsyCpAirFnWTdb(MixedAirHumRat,MixedAirTemp, 'CalcPurchAirLoads')
                         CoolSensOutput = SupplyMassFlowRate * CpAir * (MixedAirTemp - SupplyTemp)
                         CoolLatOutput = CoolTotOutput - CoolSensOutput
                         IF (CoolLatOutput >= PurchAir(PurchAirNum)%MaxCoolTotCap) THEN
                           CoolLatOutput = PurchAir(PurchAirNum)%MaxCoolTotCap
                           CoolTotOutput = CoolSensOutput + CoolLatOutput
                           SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput/SupplyMassFlowRate
                           SupplyHumRat = PsyWFnTdbH(SupplyTemp,SupplyEnthalpy, 'CalcPurchAirLoads')
                         END IF
                       ELSE
                         SupplyHumRat = PurchAir(PurchAirNum)%MaxHeatSuppAirHumRat
                       END IF
                     ELSE
                       SupplyHumRat = PurchAir(PurchAirNum)%MaxHeatSuppAirHumRat
                     END IF
                   ELSE
                     SupplyHumRat = MixedAirHumRat
                   END IF
                 CASE DEFAULT
                   SupplyHumRat = MixedAirHumRat
               END SELECT
               SupplyEnthalpy = PsyHFnTdbW(SupplyTemp,SupplyHumRat, 'CalcPurchAirLoads')
                 ! Check supply humidity ratio for dehumidification (SupplyHumRatForHumid should always be < SupplyHumRatForDehum)
                 ! This section is the heating/deadband section, so dehumidification should activate
                 !   only if dehumidification control = humidistat
                 !   and if humidification control = humidistat or none or if operating in deadband mode
               IF (CoolOn) THEN
                 IF (PurchAir(PurchAirNum)%DehumidCtrlType .EQ. Humidistat) THEN
                   IF ((PurchAir(PurchAirNum)%HumidCtrlType .EQ. Humidistat) .OR. &
                       (PurchAir(PurchAirNum)%HumidCtrlType .EQ. None) .OR. &
                       (OperatingMode == Deadband)) THEN
                     MdotZnDehumidSP= ZoneSysMoistureDemand(ActualZoneNum)%RemainingOutputReqToDehumidSP
                     SupplyHumRatForDehum = MdotZnDehumidSP/SupplyMassFlowRate + Node(ZoneNodeNum)%HumRat
                     SupplyHumRatForDehum = MAX(SupplyHumRatForDehum,PurchAir(PurchAirNum)%MinCoolSuppAirHumRat)
                     SupplyHumRat = MIN(SupplyHumRat, SupplyHumRatForDehum)
                     SupplyEnthalpy = PsyHFnTdbW(SupplyTemp,SupplyHumRat, 'CalcPurchAirLoads')
                     IF (SupplyHumRat < MixedAirHumRat) THEN
                       ! At this point, the system is heating or deadband but dehumidifying, check max cooling cap limit
                       CpAir = PsyCpAirFnWTdb(MixedAirHumRat,MixedAirTemp)
                       SensOutput = SupplyMassFlowRate * CpAir * (SupplyTemp - MixedAirTemp)
                       LatOutput = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy) - SensOutput
                       IF ((PurchAir(PurchAirNum)%CoolingLimit == LimitCapacity) .OR. &
                           (PurchAir(PurchAirNum)%CoolingLimit == LimitFlowRateAndCapacity)) THEN
                         IF (LatOutput > PurchAir(PurchAirNum)%MaxCoolTotCap) THEN
                           LatOutput = PurchAir(PurchAirNum)%MaxCoolTotCap
                           SupplyEnthalpy = MixedAirEnthalpy + (LatOutput + SensOutput)/SupplyMassFlowRate
                           SupplyHumRat = PsyWFnTdbH(SupplyTemp,SupplyEnthalpy, 'CalcPurchAirLoads')
                         END IF
                       END IF
                     END IF
                   END IF
                 END IF
               END IF
                 !   Limit supply humidity ratio to saturation at supply outlet temp
               SupplyHumRatOrig = SupplyHumRat
               SupplyHumRat = MIN(SupplyHumRat,PsyWFnTdbRhPb(SupplyTemp,1.0d0,OutBaroPress, 'CalcPurchAirLoads'))
               SupplyEnthalpy = PsyHFnTdbW(SupplyTemp,SupplyHumRat, 'CalcPurchAirLoads')
             ELSE ! SupplyMassFlowRate is zero
               SupplyEnthalpy = MixedAirEnthalpy
               SupplyHumRat   = MixedAirHumRat
               SupplyTemp     = MixedAirTemp
               HeatSensOutput = 0.0d0
             END IF
           END IF ! Cooling or heating required
             ! EMS override point  Purch air supply temp and humidty ratio ..... but only if unit is on, SupplyMassFlowRate>0.0
           IF ((PurchAir(PurchAirNum)%EMSOverrideSupplyTempOn) .AND. (SupplyMassFlowRate > 0.0d0)) THEN
             SupplyTemp = PurchAir(PurchAirNum)%EMSValueSupplyTemp
           ENDIF
           IF ((PurchAir(PurchAirNum)%EMSOverrideSupplyHumRatOn) .AND. (SupplyMassFlowRate > 0.0d0)) THEN
             SupplyHumRat = PurchAir(PurchAirNum)%EMSValueSupplyHumRat
           ENDIF
           IF (SupplyMassFlowRate > 0.0d0) THEN
             PurchAir(PurchAirNum)%FinalMixedAirTemp = MixedAirtemp
             PurchAir(PurchAirNum)%FinalMixedAirHumRat = MixedAirHumRat
             ! compute coil loads
             IF ((SupplyHumRat == MixedAirHumRat) .AND. (SupplyTemp == MixedAirTemp)) THEN
               ! If no change in humrat or temp, then set loads to zero
               PurchAir(PurchAirNum)%SenCoilLoad = 0.0d0
               PurchAir(PurchAirNum)%LatCoilLoad = 0.0d0
             ELSE IF ((SupplyHumRat == MixedAirHumRat) .AND. (SupplyTemp .NE. MixedAirTemp)) THEN
               ! If no change in humrat, then set latent load to zero and use enthalpies to calculate sensible load
               PurchAir(PurchAirNum)%SenCoilLoad = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy)
               PurchAir(PurchAirNum)%LatCoilLoad = 0.0d0
             ELSE
               CpAir = PsyCpAirFnWTdb(MixedAirHumRat,MixedAirTemp)
               PurchAir(PurchAirNum)%SenCoilLoad = SupplyMassFlowRate * CpAir * (SupplyTemp - MixedAirTemp)
               PurchAir(PurchAirNum)%LatCoilLoad = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy) &
                                                         - PurchAir(PurchAirNum)%SenCoilLoad
             END IF
             ! Apply heating and cooling availability schedules to sensible load
             IF (((PurchAir(PurchAirNum)%SenCoilLoad > 0.0d0) .AND. .NOT. HeatOn) &
                                  .OR.                                                       &
                 ((PurchAir(PurchAirNum)%SenCoilLoad < 0.0d0) .AND. .NOT. CoolOn)) THEN
               ! Coil is off
               PurchAir(PurchAirNum)%SenCoilLoad = 0.0d0
               SupplyTemp = MixedAirTemp
             END IF
             ! Apply heating and cooling availability schedules to latent load
             IF (((PurchAir(PurchAirNum)%LatCoilLoad > 0.0d0) .AND. .NOT. HeatOn) &
                                  .OR.                                                       &
                 ((PurchAir(PurchAirNum)%LatCoilLoad < 0.0d0) .AND. .NOT. CoolOn)) THEN
               ! Coil is off
               PurchAir(PurchAirNum)%LatCoilLoad = 0.0d0
               SupplyHumRat = MixedAirHumRat
             END IF
             ! Double-check if saturation exceeded, then thow warning, shouldn't happen here, don't reset, just warn
             SupplyHumRatOrig = SupplyHumRat
             SupplyHumRatSat  = PsyWFnTdbRhPb(SupplyTemp,1.0d0,OutBaroPress, 'CalcPurchAirLoads')
             DeltaHumRat = SupplyHumRatOrig - SupplyHumRatSat
             IF (DeltaHumRat > SmallDeltaHumRat) THEN
               IF (PurchAir(PurchAirNum)%SaturationOutputError < 1) THEN
                 PurchAir(PurchAirNum)%SaturationOutputError = PurchAir(PurchAirNum)%SaturationOutputError + 1
                 Call ShowWarningError(TRIM(PurchAir(PurchAirNum)%cObjectName)//' "'//TRIM(PurchAir(PurchAirNum)%Name)//'"'&
                                       //' Supply humidity ratio = '//TRIM(TrimSigDigits(SupplyHumRatOrig,5)) &
                                       //' exceeds saturation limit '//TRIM(TrimSigDigits(SupplyHumRatSat,5))//  &
                                       ' [kgWater/kgDryAir]')
                 CALL ShowContinueError(' Simulation continuing . . . ')
                 CALL ShowContinueErrorTimeStamp(' ')
               ELSE
                 CALL ShowRecurringWarningErrorAtEnd(TRIM(PurchAir(PurchAirNum)%cObjectName)//' "'&
                       //TRIM(PurchAir(PurchAirNum)%Name)//'"'//&
                       ' Supply humidity ratio exceeds saturation limit warning continues, delta max/min [kgWater/kgDryAir]...' &
                       , PurchAir(PurchAirNum)%SaturationOutputIndex, DeltaHumRat, DeltaHumRat)
               END IF
             END IF
             SupplyEnthalpy = PsyHFnTdbW(SupplyTemp,SupplyHumRat, 'CalcPurchAirLoads')
             CpAir = PsyCpAirFnWTdb(ZoneAirHumRat(ActualZoneNum),Node(ZoneNodeNum)%Temp)
             SysOutputProvided = SupplyMassFlowRate * CpAir * (SupplyTemp - Node(ZoneNodeNum)%Temp)
             MoistOutputProvided = SupplyMassFlowRate * (SupplyHumRat - Node(ZoneNodeNum)%HumRat) ! Latent rate, kg/s
             PurchAir(PurchAirNum)%SenOutputToZone = SysOutputProvided
             PurchAir(PurchAirNum)%LatOutputToZone = SupplyMassFlowRate * (SupplyEnthalpy - Node(ZoneNodeNum)%Enthalpy) &
                                                       - PurchAir(PurchAirNum)%SenOutputToZone
             CpAir = PsyCpAirFnWTdb(ZoneAirHumRat(ActualZoneNum),Node(ZoneNodeNum)%Temp)
             IF (PurchAir(PurchAirNum)%OutdoorAir) THEN
               PurchAir(PurchAirNum)%OASenOutput = OAMassFlowRate * CpAir * (Node(OANodeNum)%Temp - Node(ZoneNodeNum)%Temp)
               PurchAir(PurchAirNum)%OALatOutput = OAMassFlowRate * (Node(OANodeNum)%Enthalpy - Node(ZoneNodeNum)%Enthalpy) &
                                                       - PurchAir(PurchAirNum)%OASenOutput
             ELSE
               PurchAir(PurchAirNum)%OASenOutput = 0.0d0
               PurchAir(PurchAirNum)%OALatOutput = 0.0d0
             ENDIF
             IF (Contaminant%CO2Simulation) THEN
               IF (PurchAir(PurchAirNum)%OutdoorAir) THEN
                 Node(InNodeNum)%CO2 = ((SupplyMassFlowRate - OAMassFlowRate)*Node(RecircNodeNum)%CO2 + &
                    OAMassFlowRate*Node(OANodeNum)%CO2) / SupplyMassFlowRate
               Else
                 Node(InNodeNum)%CO2 = Node(RecircNodeNum)%CO2
               End If
             END IF
             IF (Contaminant%GenericContamSimulation) THEN
               IF (PurchAir(PurchAirNum)%OutdoorAir) THEN
                 Node(InNodeNum)%GenContam = ((SupplyMassFlowRate - OAMassFlowRate)*Node(RecircNodeNum)%GenContam + &
                    OAMassFlowRate*Node(OANodeNum)%GenContam) / SupplyMassFlowRate
               Else
                 Node(InNodeNum)%GenContam = Node(RecircNodeNum)%GenContam
               End If
             END IF
           ELSE ! SupplyMassFlowRate = 0.0
             SysOutputProvided  = 0.0d0
             MoistOutputProvided  = 0.0d0
             PurchAir(PurchAirNum)%SenOutputToZone = 0.0d0
             PurchAir(PurchAirNum)%LatOutputToZone = 0.0d0
             PurchAir(PurchAirNum)%SenCoilLoad = 0.0d0
             PurchAir(PurchAirNum)%LatCoilLoad = 0.0d0
             PurchAir(PurchAirNum)%OASenOutput = 0.0d0
             PurchAir(PurchAirNum)%OALatOutput = 0.0d0
             PurchAir(PurchAirNum)%FinalMixedAirTemp = Node(RecircNodeNum)%Temp
             PurchAir(PurchAirNum)%FinalMixedAirHumRat = Node(RecircNodeNum)%HumRat
             IF (Contaminant%CO2Simulation) THEN
               Node(InNodeNum)%CO2        = Node(ZoneNodeNum)%CO2
             END IF
             IF (Contaminant%GenericContamSimulation) THEN
               Node(InNodeNum)%GenContam  = Node(ZoneNodeNum)%GenContam
             END IF
           END IF
           Node(InNodeNum)%Temp         = SupplyTemp
           Node(InNodeNum)%HumRat       = SupplyHumRat
           Node(InNodeNum)%Enthalpy     = SupplyEnthalpy
           Node(InNodeNum)%MassFlowRate = SupplyMassFlowRate
           IF (PurchAir(PurchAirNum)%OutdoorAir) Node(OANodeNum)%MassFlowRate = OAMassFlowRate
         ELSE ! purchased air OFF
           SysOutputProvided  = 0.0d0
           MoistOutputProvided  = 0.0d0
           SupplyMassFlowRate = 0.0d0
           OAMassFlowRate     = 0.0d0
           Node(InNodeNum)%Temp         = Node(ZoneNodeNum)%Temp
           Node(InNodeNum)%HumRat       = Node(ZoneNodeNum)%HumRat
           Node(InNodeNum)%Enthalpy     = Node(ZoneNodeNum)%Enthalpy
           IF (Contaminant%CO2Simulation) THEN
             Node(InNodeNum)%CO2        = Node(ZoneNodeNum)%CO2
           END IF
           IF (Contaminant%GenericContamSimulation) THEN
             Node(InNodeNum)%GenContam  = Node(ZoneNodeNum)%GenContam
           END IF
           Node(InNodeNum)%MassFlowRate = 0.0d0
           IF (PurchAir(PurchAirNum)%OutdoorAir) Node(OANodeNum)%MassFlowRate = 0.0d0
           PurchAir(PurchAirNum)%SenHeatRate = 0.0d0
           PurchAir(PurchAirNum)%SenCoolRate = 0.0d0
           PurchAir(PurchAirNum)%TotCoolRate = 0.0d0
           PurchAir(PurchAirNum)%SenOutputToZone = 0.0d0
           PurchAir(PurchAirNum)%LatOutputToZone = 0.0d0
           PurchAir(PurchAirNum)%SenCoilLoad = 0.0d0
           PurchAir(PurchAirNum)%LatCoilLoad = 0.0d0
           PurchAir(PurchAirNum)%OASenOutput = 0.0d0
           PurchAir(PurchAirNum)%OALatOutput = 0.0d0
           PurchAir(PurchAirNum)%FinalMixedAirTemp = Node(RecircNodeNum)%Temp
           PurchAir(PurchAirNum)%FinalMixedAirHumRat = Node(RecircNodeNum)%HumRat
         END IF
         PurchAir(PurchAirNum)%OutdoorAirMassFlowRate = OAMassFlowRate
         RETURN
    END SUBROUTINE CalcPurchAirLoads