Nodes of different colours represent the following:
Solid arrows point from a parent (sub)module to the submodule which is descended from it. Dashed arrows point from a module being used to the module or program unit using it. Where possible, edges connecting nodes are given different colours to make them easier to distinguish in large graphs.
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
integer, | intent(in) | :: | DamperNum | |||
integer, | intent(in) | :: | ZoneNum | |||
integer, | intent(in) | :: | ZoneNodeNum |
Nodes of different colours represent the following:
Solid arrows point from a procedure to one which it calls. Dashed arrows point from an interface to procedures which implement that interface. This could include the module procedures in a generic interface or the implementation in a submodule of an interface in a parent module. Where possible, edges connecting nodes are given different colours to make them easier to distinguish in large graphs.
Nodes of different colours represent the following:
Solid arrows point from a procedure to one which it calls. Dashed arrows point from an interface to procedures which implement that interface. This could include the module procedures in a generic interface or the implementation in a submodule of an interface in a parent module. Where possible, edges connecting nodes are given different colours to make them easier to distinguish in large graphs.
SUBROUTINE SimDualDuctVAVOutdoorAir(DamperNum, ZoneNum, ZoneNodeNum)
! SUBROUTINE INFORMATION:
! AUTHOR Clayton Miller
! DATE WRITTEN Aug 2010
! MODIFIED B. Griffith, Dec 2010, major rework
! RE-ENGINEERED na
! PURPOSE OF THIS SUBROUTINE:
! Designed to accommodate for systems with outdoor air (OA) and recirculated air (RA)
! as two separate air streams to controlled at the zone level in a dual duct system.
! METHODOLOGY EMPLOYED:
! The terminal unit is be designed to set the airflow of the of the OA stream at the zone
! level based on the zonal ventilation requirements and the RA stream flowrate of recirculated
! cooling air stream in order to meet the remaining thermal load.
! If the zone calls for cooling but the inlet air temperature is too warm, recirc side set to zero
! if the zone calls for heating and the inlet air is warm enough, modulate damper to meet load
! if the zone calls for heating and the inlet air is too cold, zero flow (will not control sans reheat)
! REFERENCES:
! na
! USE STATEMENTS:
USE DataZoneEnergyDemands
USE Psychrometrics, ONLY:PsyCpAirFnWTdb, PsyTdbFnHW
USE DataGlobals
USE General, ONLY: TrimSigDigits
USE DataHeatBalFanSys, ONLY: ZoneThermostatSetPointLo, ZoneThermostatSetPointHi
USE DataHVACGlobals, ONLY:SmallTempDiff
IMPLICIT NONE ! Enforce explicit typing of all variables in this routine
! SUBROUTINE ARGUMENT DEFINITIONS:
INTEGER, INTENT(IN) :: DamperNum
INTEGER, INTENT(IN) :: ZoneNum
INTEGER, INTENT (IN):: ZoneNodeNum
! SUBROUTINE PARAMETER DEFINITIONS:
! na
! INTERFACE BLOCK SPECIFICATIONS
! na
! DERIVED TYPE DEFINITIONS
! na
! SUBROUTINE LOCAL VARIABLE DECLARATIONS:
REAL(r64) :: MassFlowMax ! [kg/sec] Maximum Mass Flow Rate from OA and Recirc Inlets
REAL(r64) :: HumRat ! [Kg Moisture / Kg dry air]
REAL(r64) :: Enthalpy ! [Watts]
REAL(r64) :: Temperature ! [C]
REAL(r64) :: QTotLoadRemain ! [W]
REAL(r64) :: QtoHeatSPRemain ! [W]
REAL(r64) :: QtoCoolSPRemain ! [W]
! REAL(r64) :: QTotRemainAdjust ! [W]
REAL(r64) :: QtoHeatSPRemainAdjust ! [W]
REAL(r64) :: QtoCoolSPRemainAdjust ! [W]
REAL(r64) :: QOALoadToHeatSP ! [W]
REAL(r64) :: QOALoadToCoolSP ! [W]
REAL(r64) :: QOALoad ! Amount of cooling load accounted for by OA Stream [W]
REAL(r64) :: QRALoad ! Amount of cooling load accounted for by Recirc Stream [W]
REAL(r64) :: CpAirZn ! specific heat of zone air
REAL(r64) :: CpAirSysOA ! specific heat of outdoor air
REAL(r64) :: CpAirSysRA ! specific heat of recirculated air
REAL(r64) :: OAMassFlow ! Supply air flow rate based on minimum OA requirement - for printing
REAL(r64) :: TotMassFlow ! [kg/sec] Total Mass Flow Rate from OA and Recirc Inlets
INTEGER :: OAInletNodeNum
INTEGER :: RecircInletNodeNum
OAInletNodeNum = Damper(DamperNum)%OAInletNodeNum
IF ( Damper(DamperNum)%RecircIsUsed ) THEN
RecircInletNodeNum = Damper(DamperNum)%RecircAirInletNodeNum
ENDIF
! Calculate required ventilation air flow rate based on user specified OA requirement
CALL CalcOAOnlyMassFlow(DamperNum, OAMassFlow)
! The calculated load from the Heat Balance, adjusted for any equipment sequenced before terminal
QTotLoadRemain = ZoneSysEnergyDemand(ZoneNum)%RemainingOutputRequired
QtoHeatSPRemain = ZoneSysEnergyDemand(ZoneNum)%RemainingOutputReqToHeatSP
QtoCoolSPRemain = ZoneSysEnergyDemand(ZoneNum)%RemainingOutputReqToCoolSP
!Calculate all of the required Cp's
CpAirZn = PsyCpAirFnWTdb(Node(ZoneNodeNum)%HumRat, Node(ZoneNodeNum)%Temp)
CpAirSysOA = PsyCpAirFnWTdb(Node(OAInletNodeNum)%HumRat, Node(OAInletNodeNum)%Temp)
IF ( Damper(DamperNum)%RecircIsUsed ) CpAirSysRA = PsyCpAirFnWTdb(Node(RecircInletNodeNum)%HumRat,Node(RecircInletNodeNum)%Temp)
! Set the OA Damper to the calculated ventilation flow rate
DamperOAInlet(DamperNum)%AirMassFlowRate = OAMassFlow
!Need to make sure that the OA flows are within limits
IF(DamperOAInlet(DamperNum)%AirMassFlowRate .gt. DamperOAInlet(DamperNum)%AirMassFlowRateMaxAvail) THEN
DamperOAInlet(DamperNum)%AirMassFlowRate = DamperOAInlet(DamperNum)%AirMassFlowRateMaxAvail
ELSE IF(DamperOAInlet(DamperNum)%AirMassFlowRate .lt. 0.0d0)THEN
DamperOAInlet(DamperNum)%AirMassFlowRate = 0.0d0
END IF
!..Find the amount of load that the OAMassFlow accounted for
IF(ABS((CpAirSysOA*DamperOAInlet(DamperNum)%AirTemp) - (CpAirZn*Node(ZoneNodeNum)%Temp))/CpAirZn > SmallTempDiff) THEN
QOALoad = DamperOAInlet(DamperNum)%AirMassFlowRate * &
(CpAirSysOA * DamperOAInlet(DamperNum)%AirTemp - CpAirZn * Node(ZoneNodeNum)%Temp)
QOALoadToHeatSP = DamperOAInlet(DamperNum)%AirMassFlowRate * &
(CpAirSysOA * DamperOAInlet(DamperNum)%AirTemp - CpAirZn * ZoneThermostatSetPointLo(ZoneNum))
QOALoadToCoolSP = DamperOAInlet(DamperNum)%AirMassFlowRate * &
(CpAirSysOA * DamperOAInlet(DamperNum)%AirTemp - CpAirZn * ZoneThermostatSetPointHi(ZoneNum))
ELSE
QOALoad = 0.0d0
QOALoadToHeatSP = 0.0d0
QOALoadToCoolSP = 0.0d0
END IF
IF ( Damper(DamperNum)%RecircIsUsed ) THEN
!correct load for recirc side to account for impact of OA side
! QTotRemainAdjust = QTotLoadRemain - QOALoad
QtoHeatSPRemainAdjust = QtoHeatSPRemain - QOALoadToHeatSP
QtoCoolSPRemainAdjust = QtoCoolSPRemain - QOALoadToCoolSP
IF (QtoCoolSPRemainAdjust < 0.d0) THEN
QRALoad = QtoCoolSPRemainAdjust
ELSEIF (QtoHeatSPRemainAdjust > 0.d0) THEN
QRALoad = QtoHeatSPRemainAdjust
ELSE
QRALoad = 0.0d0
ENDIF
!
! IF (QTotLoadRemain == 0.d0) THEN ! floating in deadband
! IF ((QTotRemainAdjust < 0.d0) .AND. (QtoCoolSPRemainAdjust < 0.d0)) THEN !really need cooling
! QRALoad = QtoCoolSPRemainAdjust
! ELSEIF ((QTotRemainAdjust > 0.d0) .AND. (QtoHeatSPRemainAdjust > 0.d0)) THEN ! really need heating
! QRALoad = QtoHeatSPRemainAdjust
! ELSE
! QRALoad = 0.0 ! still floating in deadband even with impact of OA side
! ENDIF
! ELSE
! QRALoad = QTotRemainAdjust
! ENDIF
IF (QRALoad < 0.d0) THEN ! cooling
IF ((DamperRecircAirInlet(DamperNum)%AirTemp - Node(ZoneNodeNum)%Temp) < -0.5d0) THEN ! can cool
! Find the Mass Flow Rate of the RA Stream needed to meet the zone cooling load
IF(ABS((CpAirSysRA*DamperRecircAirInlet(DamperNum)%AirTemp)-(CpAirZn*Node(ZoneNodeNum)%Temp))/CpAirZn > SmallTempDiff) THEN
DamperRecircAirInlet(DamperNum)%AirMassFlowRate = QRALoad / &
(CpAirSysRA*DamperRecircAirInlet(DamperNum)%AirTemp - CpAirZn*Node(ZoneNodeNum)%Temp)
ENDIF
ELSE
DamperRecircAirInlet(DamperNum)%AirMassFlowRate = 0.d0
ENDIF
ELSEIF (QRALoad > 0.d0) THEN ! heating
! IF ((DamperRecircAirInlet(DamperNum)%AirTemp - Node(ZoneNodeNum)%Temp) > 2.0d0) THEN ! can heat
! DamperRecircAirInlet(DamperNum)%AirMassFlowRate = QRALoad / &
! (CpAirSysRA*DamperRecircAirInlet(DamperNum)%AirTemp - CpAirZn*Node(ZoneNodeNum)%Temp)
! ELSE
DamperRecircAirInlet(DamperNum)%AirMassFlowRate = 0.d0
! ENDIF
ELSE ! none needed.
DamperRecircAirInlet(DamperNum)%AirMassFlowRate = 0.d0
ENDIF
!Need to make sure that the RA flows are within limits
IF(DamperRecircAirInlet(DamperNum)%AirMassFlowRate .gt. DamperRecircAirInlet(DamperNum)%AirMassFlowRateMaxAvail) THEN
DamperRecircAirInlet(DamperNum)%AirMassFlowRate = DamperRecircAirInlet(DamperNum)%AirMassFlowRateMaxAvail
!These are shutoff boxes for either the hot or the cold, therfore one side or other can = 0.0
ELSE IF(DamperRecircAirInlet(DamperNum)%AirMassFlowRate < 0.d0)THEN
DamperRecircAirInlet(DamperNum)%AirMassFlowRate = 0.d0
END IF
ELSE
DamperRecircAirInlet(DamperNum)%AirMassFlowRate = 0.d0
DamperRecircAirInlet(DamperNum)%AirMassFlowRateMaxAvail = 0.d0
ENDIF ! recirc used
! look for bang-bang condition: flow rate oscillating between 2 values during the air loop / zone
! equipment iteration. If detected, set flow rate to previous value.
IF ( ( (ABS(DamperRecircAirInlet(DamperNum)%AirMassFlowRate &
-DamperRecircAirInlet(DamperNum)%AirMassFlowRateHist2) &
< DamperRecircAirInlet(DamperNum)%AirMassFlowDiffMag) .OR. &
(ABS(DamperRecircAirInlet(DamperNum)%AirMassFlowRate &
-DamperRecircAirInlet(DamperNum)%AirMassFlowRateHist3) &
< DamperRecircAirInlet(DamperNum)%AirMassFlowDiffMag) ) .AND. &
(ABS(DamperRecircAirInlet(DamperNum)%AirMassFlowRate &
-DamperRecircAirInlet(DamperNum)%AirMassFlowRateHist1) &
>= DamperRecircAirInlet(DamperNum)%AirMassFlowDiffMag) ) THEN
IF (DamperRecircAirInlet(DamperNum)%AirMassFlowRate > 0.0d0) THEN
DamperRecircAirInlet(DamperNum)%AirMassFlowRate = DamperRecircAirInlet(DamperNum)%AirMassFlowRateHist1
ENDIF
END IF
! Find the Max Box Flow Rate.
MassFlowMax = DamperOAInlet(DamperNum)%AirMassFlowRateMaxAvail + DamperRecircAirInlet(DamperNum)%AirMassFlowRateMaxAvail
IF (GetCurrentScheduleValue(Damper(DamperNum)%SchedPtr) .gt. 0.0d0) THEN
TotMassFlow = DamperOAInlet(DamperNum)%AirMassFlowRate + DamperRecircAirInlet(DamperNum)%AirMassFlowRate
ELSE
TotMassFlow = 0.d0
ENDIF
IF (TotMassFlow .GT. SmallMassFlow) THEN
! If the sum of the two air streams' flow is greater than the Max Box Flow Rate then reset the RA Stream
IF (TotMassFlow > MassFlowMax) THEN
DamperRecircAirInlet(DamperNum)%AirMassFlowRate = MassFlowMax - DamperOAInlet(DamperNum)%AirMassFlowRate
END IF
!After the flow rates are determined the properties are calculated.
TotMassFlow = DamperOAInlet(DamperNum)%AirMassFlowRate + DamperRecircAirInlet(DamperNum)%AirMassFlowRate
IF (TotMassFlow .GT. SmallMassFlow) THEN
HumRat = (DamperOAInlet(DamperNum)%AirHumRat * &
DamperOAInlet(DamperNum)%AirMassFlowRate + &
DamperRecircAirInlet(DamperNum)%AirHumRat * &
DamperRecircAirInlet(DamperNum)%AirMassFlowRate) / TotMassFlow
Enthalpy = (DamperOAInlet(DamperNum)%AirEnthalpy * &
DamperOAInlet(DamperNum)%AirMassFlowRate + &
DamperRecircAirInlet(DamperNum)%AirEnthalpy * &
DamperRecircAirInlet(DamperNum)%AirMassFlowRate) / TotMassFlow
ELSE
HumRat =(DamperRecircAirInlet(DamperNum)%AirHumRat + DamperOAInlet(DamperNum)%AirHumRat)/2.0d0
Enthalpy = (DamperRecircAirInlet(DamperNum)%AirEnthalpy + DamperOAInlet(DamperNum)%AirEnthalpy)/2.0d0
ENDIF
ELSE
! The Max Box Flow Rate is zero and the box is off.
DamperRecircAirInlet(DamperNum)%AirMassFlowRate = 0.0d0
DamperOAInlet(DamperNum)%AirMassFlowRate = 0.0d0
HumRat =(DamperRecircAirInlet(DamperNum)%AirHumRat + DamperOAInlet(DamperNum)%AirHumRat)/2.0d0
Enthalpy = (DamperRecircAirInlet(DamperNum)%AirEnthalpy + DamperOAInlet(DamperNum)%AirEnthalpy)/2.0d0
END IF
Temperature = PsyTdbFnHW(Enthalpy,HumRat)
DamperOutlet(DamperNum)%AirTemp = Temperature
DamperOutlet(DamperNum)%AirHumRat = HumRat
DamperOutlet(DamperNum)%AirMassFlowRate = TotMassFlow
DamperOutlet(DamperNum)%AirMassFlowRateMaxAvail = MassFlowMax
DamperOutlet(DamperNum)%AirEnthalpy = Enthalpy
!Calculate the OA and RA damper position in %
IF ( Damper(DamperNum)%RecircIsUsed ) THEN
IF (DamperRecircAirInlet(DamperNum)%AirmassFlowRateMax == 0.d0) THEN !protect div by zero
Damper(DamperNum)%RecircAirDamperPosition = 0.0d0
ELSE
Damper(DamperNum)%RecircAirDamperPosition = DamperRecircAirInlet(DamperNum)%AirMassFlowRate/ &
DamperRecircAirInlet(DamperNum)%AirmassFlowRateMax
ENDIF
ENDIF
IF (DamperOAInlet(DamperNum)%AirmassFlowRateMax == 0.0d0) THEN !protect div by zero
Damper(DamperNum)%OADamperPosition = 0.0d0
ELSE
Damper(DamperNum)%OADamperPosition = DamperOAInlet(DamperNum)%AirMassFlowRate/ &
DamperOAInlet(DamperNum)%AirmassFlowRateMax
ENDIF
!Calculate OAFraction of mixed air after the box
IF (TotMassFlow > 0) THEN
IF (Damper(DamperNum)%RecircIsUsed) THEN
If(DamperOAInlet(DamperNum)%AirmassFlowRate == 0.0d0) THEN
Damper(DamperNum)%OAFraction = 0.0d0
ELSEIF( DamperRecircAirInlet(DamperNum)%AirmassFlowRate == 0.0d0) THEN
Damper(DamperNum)%OAFraction = 1.0d0
ELSE
Damper(DamperNum)%OAFraction = DamperOAInlet(DamperNum)%AirmassFlowRate / TotMassFlow
END IF
ELSE
Damper(DamperNum)%OAFraction = 1.0d0
ENDIF
ELSE
Damper(DamperNum)%OAFraction = 0.0d0
ENDIF
DamperRecircAirInlet(DamperNum)%AirMassFlowRateHist3 = DamperRecircAirInlet(DamperNum)%AirMassFlowRateHist2
DamperRecircAirInlet(DamperNum)%AirMassFlowRateHist2 = DamperRecircAirInlet(DamperNum)%AirMassFlowRateHist1
DamperRecircAirInlet(DamperNum)%AirMassFlowRateHist1 = DamperRecircAirInlet(DamperNum)%AirmassFlowRate
RETURN
END SUBROUTINE SimDualDuctVAVOutdoorAir