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