add logic for warmup, kickoffsimulation and doing sizing here
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
integer, | intent(in) | :: | WaterThermalTankNum | |||
logical, | intent(in) | :: | FirstHVACIteration |
SUBROUTINE CalcHeatPumpWaterHeater(WaterThermalTankNum,FirstHVACIteration)
! SUBROUTINE INFORMATION:
! AUTHOR Richard Raustad
! DATE WRITTEN March 2005
! MODIFIED B. Griffith, Jan 2012 for stratified tank
! RE-ENGINEERED na
! PURPOSE OF THIS SUBROUTINE:
! Simulates a heat pump water heater
! METHODOLOGY EMPLOYED:
! Simulate the water heater tank, DX coil, and fan to meet the water heating requirements.
! USE STATEMENTS:
USE DataLoopNode, ONLY: Node
USE DataHVACGlobals, ONLY: ShortenTimeStepSys, TimeStepSys, HPWHInletDBTemp, HPWHInletWBTemp, HPWHCrankcaseDBTemp, &
BlowThru, CycFanCycCoil, SmallTempDiff
USE DataGlobals, ONLY: WarmupFlag, DoingSizing, KickOffSimulation
USE DataInterfaces, ONLY: ShowFatalError, ShowSevereError, ShowWarningError, ShowContinueError, &
ShowContinueErrorTimeStamp, ShowRecurringWarningErrorAtEnd
USE DXCoils, ONLY: SimDXCoil, CalcHPWHDXCoil
USE Fans, ONLY: SimulateFanComponents
USE ScheduleManager, ONLY: GetCurrentScheduleValue
USE General, ONLY: SolveRegulaFalsi, RoundSigDigits
USE Psychrometrics, ONLY: CPHW, PsyRhoAirFnPbTdbW, PsyCpAirFnWTdb, RhoH2O !, PsyWFnTdbTwbPb
IMPLICIT NONE ! Enforce explicit typing of all variables in this routine
! SUBROUTINE ARGUMENT DEFINITIONS:
INTEGER, INTENT(IN) :: WaterThermalTankNum ! Water Heater tank being simulated
LOGICAL, INTENT(IN) :: FirstHVACIteration ! TRUE if First iteration of simulation
! SUBROUTINE PARAMETER DEFINITIONS:
INTEGER, PARAMETER :: MaxIte = 500 ! maximum number of iterations
REAL(r64), PARAMETER :: Acc = 0.001D0 ! Accuracy of result from RegulaFalsi
! SUBROUTINE LOCAL VARIABLE DECLARATIONS:
REAL(r64) :: AvailSchedule ! HP compressor availability schedule
REAL(r64) :: SetPointTemp ! HP set point temperature (cut-out temperature, C)
REAL(r64) :: DeadbandTempDiff ! HP dead band temperature difference (C)
REAL(r64) :: TankTemp ! tank temperature before simulation, C
REAL(r64) :: NewTankTemp ! tank temperature after simulation, C
REAL(r64) :: CpAir ! specific heat of air, kJ/kg/K
REAL(r64) :: MdotWater ! mass flow rate of condenser water, kg/s
REAL(r64) :: OutletAirSplitterSch ! output of outlet air splitter schedule
INTEGER :: HPAirInletNode ! HP air inlet node number
INTEGER :: HPAirOutletNode ! HP air outlet node number
INTEGER :: OutdoorAirNode ! Outdoor air inlet node number
INTEGER :: ExhaustAirNode ! Exhaust air outlet node number
INTEGER :: HPWaterInletNode ! HP condenser water inlet node number
INTEGER :: HPWaterOutletNode ! HP condenser water outlet node number
INTEGER :: InletAirMixerNode ! HP inlet air mixer node number
INTEGER :: OutletAirSplitterNode ! HP outlet air splitter node number
INTEGER :: DXCoilAirInletNode ! Inlet air node number of DX coil
INTEGER :: HPNum ! Index to heat pump water heater
INTEGER :: SolFla ! Flag of RegulaFalsi solver
REAL(r64), DIMENSION(5) :: Par ! Parameters passed to RegulaFalsi
REAL(r64) :: HPMinTemp ! used for error messages, C
CHARACTER(len=MaxNameLength) :: HPMinTempChar ! used for error messages
CHARACTER(len=20) :: IterNum ! Max number of iterations for warning message
INTEGER :: CompOp ! DX compressor operation; 1=on, 0=off
REAL(r64) :: CondenserDeltaT ! HPWH condenser water temperature difference
REAL(r64) :: HPWHCondInletNodeLast ! Water temp sent from WH on last iteration
INTEGER :: loopIter ! iteration loop counter
! FLOW:
! initialize local variables
HPNum = WaterThermalTank(WaterThermalTankNum)%HeatPumpNum
AvailSchedule = GetCurrentScheduleValue(HPWaterHeater(HPNum)%AvailSchedPtr)
HPAirInletNode = HPWaterHeater(HPNum)%HeatPumpAirInletNode
HPAirOutletNode = HPWaterHeater(HPNum)%HeatPumpAirOutletNode
OutdoorAirNode = HPWaterHeater(HPNum)%OutsideAirNode
ExhaustAirNode = HPWaterHeater(HPNum)%ExhaustAirNode
HPWaterInletNode = HPWaterHeater(HPNum)%CondWaterInletNode
HPWaterOutletNode = HPWaterHeater(HPNum)%CondWaterOutletNode
InletAirMixerNode = HPWaterHeater(HPNum)%InletAirMixerNode
OutletAirSplitterNode = HPWaterHeater(HPNum)%OutletAirSplitterNode
DXCoilAirInletNode = HPWaterHeater(HPNum)%DXCoilAirInletNode
HPPartLoadRatio = 0.0d0
CompOp = 0
HPWaterHeater(HPNum)%OnCycParaFuelRate = 0.0d0
HPWaterHeater(HPNum)%OnCycParaFuelEnergy = 0.0d0
HPWaterHeater(HPNum)%OffCycParaFuelRate = 0.0d0
HPWaterHeater(HPNum)%OffCycParaFuelEnergy = 0.0d0
Node(HPWaterOutletNode) = Node(HPWaterInletNode)
! assign set point temperature (cut-out) and dead band temp diff (cut-in = cut-out minus dead band temp diff)
SetPointTemp = HPWaterHeater(HPNum)%SetpointTemp
DeadbandTempDiff = HPWaterHeater(HPNum)%DeadbandTempDiff
! store first iteration tank temperature and HP mode of operation
! this code can be called more than once with FirstHVACIteration = .TRUE., use FirstTimeThroughFlag to control save
IF (FirstHVACIteration .AND. .NOT. ShortenTimeStepSys .AND. HPWaterHeater(HPNum)%FirstTimeThroughFlag) THEN
WaterThermalTank(WaterThermalTankNum)%SavedTankTemp = WaterThermalTank(WaterThermalTankNum)%TankTemp
HPWaterHeater(HPNum)%SaveMode = HPWaterHeater(HPNum)%Mode
HPWaterHeater(HPNum)%SaveWHMode = WaterThermalTank(WaterThermalTankNum)%Mode
HPWaterHeater(HPNum)%FirstTimeThroughFlag = .FALSE.
END IF
IF(.NOT. FirstHVACIteration)HPWaterHeater(HPNum)%FirstTimeThroughFlag = .TRUE.
! check if HPWH is off for some reason and simulate HPWH air- and water-side mass flow rates of 0
! simulate only water heater tank if HP compressor is scheduled off
IF(AvailSchedule .EQ. 0.0d0 .OR. &
! simulate only water heater tank if HP compressor cut-out temperature is lower than the tank's cut-in temperature
(SetPointTemp - DeadbandTempDiff) .LE. WaterThermalTank(WaterThermalTankNum)%SetpointTemp .OR. &
! simulate only water heater tank if HP inlet air temperature is below minimum temperature for HP compressor operation
HPWHInletDBTemp .LT. HPWaterHeater(HPNum)%MinAirTempForHPOperation .OR. &
! if the tank maximum temperature limit is less than the HPWH set point temp, disable HPWH
SetPointTemp .GE. WaterThermalTank(WaterThermalTankNum)%TankTempLimit)THEN
! revert to float mode any time HPWH compressor is OFF
HPWaterHeater(HPNum)%Mode = FloatMode
IF(InletAirMixerNode .GT. 0) THEN
Node(InletAirMixerNode) = Node(HPAirInletNode)
END IF
! pass node info and simulate crankcase heater
IF(HPWaterHeater(HPNum)%FanPlacement .EQ. BlowThru) THEN
CALL SimulateFanComponents(HPWaterHeater(HPNum)%FanName, FirstHVACIteration,HPWaterHeater(HPNum)%FanNum)
CALL SimDXCoil(HPWaterHeater(HPNum)%DXCoilName, CompOp, FirstHVACIteration,HPPartLoadRatio, &
HPWaterHeater(HPNum)%DXCoilNum,CycFanCycCoil)
ELSE
CALL SimDXCoil(HPWaterHeater(HPNum)%DXCoilName, CompOp, FirstHVACIteration,HPPartLoadRatio, &
HPWaterHeater(HPNum)%DXCoilNum,CycFanCycCoil)
CALL SimulateFanComponents(HPWaterHeater(HPNum)%FanName, FirstHVACIteration,HPWaterHeater(HPNum)%FanNum)
END IF
IF(OutletAirSplitterNode .GT. 0) THEN
Node(HPAirOutletNode) = Node(OutletAirSplitterNode)
END IF
! Simulate tank if HP compressor unavailable for water heating
SELECT CASE(HPWaterHeater(HPNum)%TankTypeNum)
CASE(MixedWaterHeater)
CALL CalcWaterThermalTankMixed(WaterThermalTankNum)
CASE((StratifiedWaterHeater))
CALL CalcWaterThermalTankStratified(WaterThermalTankNum)
END SELECT
! If HPWH compressor is available and unit is off for another reason, off-cycle parasitics are calculated
IF(AvailSchedule .NE. 0)THEN
HPWaterHeater(HPNum)%OffCycParaFuelRate = HPWaterHeater(HPNum)%OffCycParaLoad * (1.0d0-HPPartLoadRatio)
HPWaterHeater(HPNum)%OffCycParaFuelEnergy = HPWaterHeater(HPNum)%OffCycParaFuelRate * TimeStepSys * SecInHour
END IF
! Warn if HPWH compressor cut-in temperature is less than the water heater tank's set point temp
IF(.NOT. WarmupFlag .AND. .NOT. DoingSizing .AND. .NOT. KickOffSimulation ) THEN
IF((SetPointTemp - DeadbandTempDiff) .LE. WaterThermalTank(WaterThermalTankNum)%SetpointTemp)THEN
HPMinTemp = SetPointTemp - DeadbandTempDiff
WRITE(HPMinTempChar,*) HPMinTemp
HPWaterHeater(HPNum)%HPSetPointError=HPWaterHeater(HPNum)%HPSetPointError+1
!!add logic for warmup, kickoffsimulation and doing sizing here
IF (HPWaterHeater(HPNum)%HPSetPointError .EQ. 1) THEN
CALL ShowWarningError(TRIM(HPWaterHeater(HPNum)%Type)//' "'//TRIM(HPWaterHeater(HPNum)%Name)//&
': Water heater tank set point temperature is greater than or equal to the cut-in temperature'// &
' of the heat pump water heater. Heat Pump will be disabled and simulation continues.')
CALL ShowContinueErrorTimeStamp(' '//'...Heat Pump cut-in temperature='//TRIM(HPMinTempChar))
ELSE
CALL ShowRecurringWarningErrorAtEnd(TRIM(HPWaterHeater(HPNum)%Type)//' "'//TRIM(HPWaterHeater(HPNum)%Name)//&
': Water heater tank set point temperature is greater than or equal to the cut-in temperature'// &
' of the heat pump water heater. Heat Pump will be disabled error continues...' &
, HPWaterHeater(HPNum)%HPSetPointErrIndex1, HPMinTemp, HPMinTemp)
END IF
END IF
ENDIF
RETURN
END IF
SELECT CASE(HPWaterHeater(HPNum)%TankTypeNum)
CASE(MixedWaterHeater)
TankTemp = WaterThermalTank(WaterThermalTankNum)%SavedTankTemp
CASE(StratifiedWaterHeater)
TankTemp = FindStratifiedTankSensedTemp(WaterThermalTankNum, &
HPWaterHeater(HPNum)%ControlSensorLocation)
END SELECT
HPWaterHeater(HPNum)%Mode = HPWaterHeater(HPNum)%SaveMode
! set the heat pump air- and water-side mass flow rate
MdotWater = HPWaterHeater(HPNum)%OperatingWaterFlowRate * RhoH2O(TankTemp)
! select mode of operation (float mode or heat mode)
SELECT CASE(HPWaterHeater(HPNum)%Mode)
! HPWH was heating last iteration and will continue to heat until the set point is reached
CASE(HeatMode)
HPPartLoadRatio = 1.0d0
! set up full air flow on DX coil inlet node
Node(DXCoilAirInletNode)%MassFlowRate = MdotAir
! set the condenser inlet node mass flow rate prior to calling the HPWH DX coil
Node(HPWaterInletNode)%MassFlowRate = MdotWater
WaterThermalTank(WaterThermalTankNum)%SourceMassFlowRate = MdotWater
HPWHCondInletNodeLast = Node(HPWaterInletNode)%Temp
DO loopIter = 1, 4
CALL CalcHPWHDXCoil(HPWaterHeater(HPNum)%DXCoilNum, HPPartLoadRatio)
! Currently, HPWH heating rate is only a function of inlet evap conditions and air flow rate
! If HPWH is ever allowed to vary fan speed, this next sub should be called.
! (possibly with an iteration loop to converge on a solution)
! CALL CalcDOE2DXCoil(DXCoilNum, HPPartLoadRatio, FirstHVACIteration,PartLoadRatio, FanOpMode)
CondenserDeltaT = Node(HPWaterOutletNode)%Temp - Node(HPWaterInletNode)%Temp
! move the full load outlet temperature rate to the water heater structure variables
! (water heaters source inlet node temperature/mdot are set in Init, set it here after CalcHPWHDXCoil has been called)
WaterThermalTank(WaterThermalTankNum)%SourceInletTemp = Node(HPWaterInletNode)%Temp + CondenserDeltaT
WaterThermalTank(WaterThermalTankNum)%SourceMassFlowRate = MdotWater
! this CALL does not update node temps, must use WaterThermalTank variables
! select tank type
SELECT CASE(HPWaterHeater(HPNum)%TankTypeNum)
CASE(MixedWaterHeater)
CALL CalcWaterThermalTankMixed(WaterThermalTankNum)
NewTankTemp = WaterThermalTank(WaterThermalTankNum)%TankTemp
CASE(StratifiedWaterHeater)
CALL CalcWaterThermalTankStratified(WaterThermalTankNum)
NewTankTemp = FindStratifiedTankSensedTemp(WaterThermalTankNum, &
HPWaterHeater(HPNum)%ControlSensorLocation)
END SELECT
Node(HPWaterInletNode)%Temp = WaterThermalTank(WaterThermalTankNum)%SourceOutletTemp
IF(ABS(Node(HPWaterInletNode)%Temp - HPWHCondInletNodeLast) < SmallTempDiff)EXIT
HPWHCondInletNodeLast = Node(HPWaterInletNode)%Temp
END DO
! if tank temperature is greater than set point, calculate a PLR needed to exactly reach the set point
IF(NewTankTemp .GT. SetPointTemp) THEN
HPWaterHeater(HPNum)%Mode = FloatMode
Par(1) = SetPointTemp
Par(2) = HPWaterHeater(HPNum)%SaveWHMode
Par(3) = WaterThermalTankNum
IF(FirstHVACIteration) THEN
Par(4) = 1.0d0
ELSE
Par(4) = 0.0d0
END IF
Par(5) = MdotWater
SELECT CASE(HPWaterHeater(HPNum)%TankTypeNum)
CASE(MixedWaterHeater)
CALL SolveRegulaFalsi(Acc, MaxIte, SolFla, HPPartLoadRatio, PLRResidualMixedTank, 0.0d0, &
1.0d0, Par)
CASE(StratifiedWaterHeater)
CALL SolveRegulaFalsi(Acc, MaxIte, SolFla, HPPartLoadRatio, PLRResidualStratifiedTank, 0.0d0, &
1.0d0, Par)
END SELECT
IF (SolFla == -1) THEN
WRITE(IterNum,*) MaxIte
IterNum=ADJUSTL(IterNum)
IF(.NOT. WarmupFlag)THEN
HPWaterHeater(HPNum)%IterLimitExceededNum1 = HPWaterHeater(HPNum)%IterLimitExceededNum1 + 1
IF (HPWaterHeater(HPNum)%IterLimitExceededNum1 .EQ. 1) THEN
CALL ShowWarningError(TRIM(HPWaterHeater(HPNum)%Type)//' "'//TRIM(HPWaterHeater(HPNum)%Name)//'"')
CALL ShowContinueError('Iteration limit exceeded calculating heat pump water heater compressor'// &
' part-load ratio, maximum iterations = '//TRIM(IterNum)// &
'. Part-load ratio returned = '//TRIM(RoundSigDigits(HPPartLoadRatio,3)))
CALL ShowContinueErrorTimeStamp('This error occurred in heating mode.')
ELSE
CALL ShowRecurringWarningErrorAtEnd(TRIM(HPWaterHeater(HPNum)%Type)//' "' &
//TRIM(HPWaterHeater(HPNum)%Name)//&
'": Iteration limit exceeded in heating mode warning continues. Part-load ratio statistics follow.' &
, HPWaterHeater(HPNum)%IterLimitErrIndex1, HPPartLoadRatio, HPPartLoadRatio)
END IF
END IF
ELSE IF (SolFla == -2) THEN
HPPartLoadRatio = MAX(0.0d0,MIN(1.0d0,(SetPointTemp - TankTemp)/(NewTankTemp - TankTemp)))
IF(.NOT. WarmupFlag)THEN
HPWaterHeater(HPNum)%RegulaFalsiFailedNum1 = HPWaterHeater(HPNum)%RegulaFalsiFailedNum1 + 1
IF (HPWaterHeater(HPNum)%RegulaFalsiFailedNum1 .EQ. 1) THEN
CALL ShowWarningError(TRIM(HPWaterHeater(HPNum)%Type)//' "'//TRIM(HPWaterHeater(HPNum)%Name)//'"')
CALL ShowContinueError('Heat pump water heater compressor part-load ratio calculation failed: PLR limits ' &
//'of 0 to 1 exceeded. Part-load ratio used = '//TRIM(RoundSigDigits(HPPartLoadRatio,3)))
CALL ShowContinueError('Please send this information to the EnergyPlus support group.')
CALL ShowContinueErrorTimeStamp('This error occured in heating mode.')
ELSE
CALL ShowRecurringWarningErrorAtEnd(TRIM(HPWaterHeater(HPNum)%Type)//' "' &
//TRIM(HPWaterHeater(HPNum)%Name)//&
'": Part-load ratio calculation failed in heating mode warning continues. Part-load ratio statistics follow.'&
, HPWaterHeater(HPNum)%RegulaFalsiFailedIndex1, HPPartLoadRatio, HPPartLoadRatio)
END IF
END IF
END IF
SELECT CASE(HPWaterHeater(HPNum)%TankTypeNum)
CASE(MixedWaterHeater)
NewTankTemp = WaterThermalTank(WaterThermalTankNum)%TankTemp
CASE(StratifiedWaterHeater)
NewTankTemp = FindStratifiedTankSensedTemp(WaterThermalTankNum, &
HPWaterHeater(HPNum)%ControlSensorLocation)
END SELECT
ELSE
HPPartLoadRatio = 1.0d0
END IF
! HPWH was floating last iteration and will continue to float until the cut-in temperature is reached
CASE(FloatMode)
! set the condenser inlet node temperature and full mass flow rate prior to calling the HPWH DX coil
SELECT CASE(HPWaterHeater(HPNum)%TankTypeNum)
CASE(MixedWaterHeater)
Node(HPWaterInletNode)%Temp = TankTemp
Node(HPWaterOutletNode)%Temp = TankTemp
CASE(StratifiedWaterHeater)
Node(HPWaterInletNode)%Temp = WaterThermalTank(WaterThermalTankNum)%SourceOutletTemp
Node(HPWaterOutletNode)%Temp = WaterThermalTank(WaterThermalTankNum)%SourceInletTemp
END SELECT
Node(HPWaterInletNode)%MassFlowRate = 0.0d0
Node(HPWaterOutletNode)%MassFlowRate = 0.0d0
! check tank temperature by setting source inlet mass flow rate to zero
HPPartLoadRatio = 0.0d0
! set the full load outlet temperature on the water heater source inlet node (init has already been called)
WaterThermalTank(WaterThermalTankNum)%SourceInletTemp = Node(HPWaterOutletNode)%Temp
! check tank temperature by setting source inlet mass flow rate to zero
WaterThermalTank(WaterThermalTankNum)%SourceMassFlowRate = 0.0d0
! disable the tank's internal heating element to find PLR of the HPWH using floating temperatures
WaterThermalTank(WaterThermalTankNum)%MaxCapacity = 0.0d0
WaterThermalTank(WaterThermalTankNum)%MinCapacity = 0.0d0
SELECT CASE(HPWaterHeater(HPNum)%TankTypeNum)
CASE(MixedWaterHeater)
CALL CalcWaterThermalTankMixed(WaterThermalTankNum)
NewTankTemp = WaterThermalTank(WaterThermalTankNum)%TankTemp
CASE(StratifiedWaterHeater)
CALL CalcWaterThermalTankStratified(WaterThermalTankNum)
NewTankTemp = FindStratifiedTankSensedTemp(WaterThermalTankNum, &
HPWaterHeater(HPNum)%ControlSensorLocation)
END SELECT
! reset the tank's internal heating element capacity
WaterThermalTank(WaterThermalTankNum)%MaxCapacity = HPWaterHeater(HPNum)%BackupElementCapacity
WaterThermalTank(WaterThermalTankNum)%MinCapacity = HPWaterHeater(HPNum)%BackupElementCapacity
IF(NewTankTemp .LE. (SetPointTemp - DeadbandTempDiff)) THEN
! HPWH is now in heating mode
HPWaterHeater(HPNum)%Mode = HeatMode
! reset the water heater's mode (call above may have changed modes)
WaterThermalTank(WaterThermalTankNum)%Mode = HPWaterHeater(HPNum)%SaveWHMode
! estimate portion of time step that the HP operates based on a linear interpolation of the tank temperature decay
! this assumes that all heating sources are off
IF(Tanktemp .NE. NewTankTemp) THEN
HPPartLoadRatio = MAX(0.0d0,MIN(1.0d0,((SetPointTemp - DeadbandTempDiff) - NewTankTemp) / (Tanktemp - NewTankTemp)))
ELSE
HPPartLoadRatio = 1.0d0
END IF
! set the condenser inlet node mass flow rate prior to calling the CalcHPWHDXCoil
Node(HPWaterInletNode)%MassFlowRate = MdotWater * HPPartLoadRatio
WaterThermalTank(WaterThermalTankNum)%SourceMassFlowRate = MdotWater * HPPartLoadRatio
Node(DXCoilAirInletNode)%MassFlowRate = MdotAir * HPPartLoadRatio
HPWHCondInletNodeLast = Node(HPWaterInletNode)%Temp
DO loopIter = 1, 4
CALL CalcHPWHDXCoil(HPWaterHeater(HPNum)%DXCoilNum, HPPartLoadRatio)
! Currently, HPWH heating rate is only a function of inlet evap conditions and air flow rate
! If HPWH is ever allowed to vary fan speed, this next sub should be called.
! CALL CalcDOE2DXCoil(DXCoilNum, HPPartLoadRatio, FirstHVACIteration,PartLoadRatio, FanOpMode)
! (possibly with an iteration loop to converge on a solution)
CondenserDeltaT = Node(HPWaterOutletNode)%Temp - Node(HPWaterInletNode)%Temp
WaterThermalTank(WaterThermalTankNum)%SourceInletTemp = Node(HPWaterInletNode)%Temp + CondenserDeltaT
! this CALL does not update node temps, must use WaterThermalTank variables
! select tank type
SELECT CASE(HPWaterHeater(HPNum)%TankTypeNum)
CASE(MixedWaterHeater)
CALL CalcWaterThermalTankMixed(WaterThermalTankNum)
NewTankTemp = WaterThermalTank(WaterThermalTankNum)%TankTemp
CASE(StratifiedWaterHeater)
CALL CalcWaterThermalTankStratified(WaterThermalTankNum)
NewTankTemp = FindStratifiedTankSensedTemp(WaterThermalTankNum, &
HPWaterHeater(HPNum)%ControlSensorLocation)
END SELECT
Node(HPWaterInletNode)%Temp = WaterThermalTank(WaterThermalTankNum)%SourceOutletTemp
IF(ABS(Node(HPWaterInletNode)%Temp - HPWHCondInletNodeLast) < SmallTempDiff)EXIT
HPWHCondInletNodeLast = Node(HPWaterInletNode)%Temp
END DO
! if tank temperature is greater than set point, calculate a PLR needed to exactly reach the set point
IF(NewTankTemp .GT. SetPointTemp) THEN
HPWaterHeater(HPNum)%Mode = FloatMode
Par(1) = SetPointTemp
Par(2) = HPWaterHeater(HPNum)%SaveWHMode
Par(3) = WaterThermalTankNum
IF(FirstHVACIteration) THEN
Par(4) = 1.0d0
ELSE
Par(4) = 0.0d0
END IF
Par(5) = MdotWater
SELECT CASE(HPWaterHeater(HPNum)%TankTypeNum)
CASE(MixedWaterHeater)
CALL SolveRegulaFalsi(Acc, MaxIte, SolFla, HPPartLoadRatio, PLRResidualMixedTank, 0.0d0, &
1.0d0, Par)
CASE(StratifiedWaterHeater)
CALL SolveRegulaFalsi(Acc, MaxIte, SolFla, HPPartLoadRatio, PLRResidualStratifiedTank, 0.0d0, &
1.0d0, Par)
END SELECT
IF (SolFla == -1) THEN
WRITE(IterNum,*) MaxIte
IterNum=ADJUSTL(IterNum)
IF(.NOT. WarmupFlag)THEN
HPWaterHeater(HPNum)%IterLimitExceededNum2 = HPWaterHeater(HPNum)%IterLimitExceededNum2 + 1
IF (HPWaterHeater(HPNum)%IterLimitExceededNum2 .EQ. 1) THEN
CALL ShowWarningError(TRIM(HPWaterHeater(HPNum)%Type)//' "'//TRIM(HPWaterHeater(HPNum)%Name)//'"')
CALL ShowContinueError('Iteration limit exceeded calculating heat pump water heater compressor'// &
' part-load ratio, maximum iterations = '//TRIM(IterNum)// &
'. Part-load ratio returned = '//TRIM(RoundSigDigits(HPPartLoadRatio,3)))
CALL ShowContinueErrorTimeStamp('This error occurred in float mode.')
ELSE
CALL ShowRecurringWarningErrorAtEnd(TRIM(HPWaterHeater(HPNum)%Type)//' "' &
//TRIM(HPWaterHeater(HPNum)%Name)//&
'": Iteration limit exceeded in float mode warning continues. Part-load ratio statistics follow.' &
, HPWaterHeater(HPNum)%IterLimitErrIndex2, HPPartLoadRatio, HPPartLoadRatio)
END IF
END IF
ELSE IF (SolFla == -2) THEN
HPPartLoadRatio = MAX(0.0d0,MIN(1.0d0,(SetPointTemp - TankTemp)/(NewTankTemp - TankTemp)))
IF(.NOT. WarmupFlag)THEN
HPWaterHeater(HPNum)%RegulaFalsiFailedNum2 = HPWaterHeater(HPNum)%RegulaFalsiFailedNum2 + 1
IF (HPWaterHeater(HPNum)%RegulaFalsiFailedNum2 .EQ. 1) THEN
CALL ShowWarningError(TRIM(HPWaterHeater(HPNum)%Type)//' "'//TRIM(HPWaterHeater(HPNum)%Name)//'"')
CALL ShowContinueError('Heat pump water heater compressor part-load ratio calculation failed: PLR limits ' &
//'of 0 to 1 exceeded. Part-load ratio used = '//TRIM(RoundSigDigits(HPPartLoadRatio,3)))
CALL ShowContinueError('Please send this information to the EnergyPlus support group.')
CALL ShowContinueErrorTimeStamp('This error occured in float mode.')
ELSE
CALL ShowRecurringWarningErrorAtEnd(TRIM(HPWaterHeater(HPNum)%Type)//' "' &
//TRIM(HPWaterHeater(HPNum)%Name)//&
'": Part-load ratio calculation failed in float mode warning continues. Part-load ratio statistics follow.' &
, HPWaterHeater(HPNum)%RegulaFalsiFailedIndex2, HPPartLoadRatio, HPPartLoadRatio)
END IF
END IF
END IF
END IF
END IF
CASE DEFAULT
! Never gets here, only allowed modes for HPWH are float and heat
END SELECT
! set air-side mass flow rate for final calculation
IF(InletAirMixerNode .GT. 0) THEN
Node(InletAirMixerNode)%MassFlowRate = MdotAir * HPPartLoadRatio
Node(HPAirInletNode)%MassFlowRate = MdotAir * HPPartLoadRatio * (1.0d0 - MixerInletAirSchedule)
Node(OutdoorAirNode)%MassFlowRate = MdotAir * HPPartLoadRatio * MixerInletAirSchedule
! IF HPWH is off, pass zone node conditions through HPWH air-side
IF(HPPartLoadRatio .EQ. 0)Node(InletAirMixerNode) = Node(HPAirInletNode)
ELSE
IF(OutdoorAirNode .EQ. 0)THEN
Node(HPAirInletNode)%MassFlowRate = MdotAir * HPPartLoadRatio
ELSE
Node(OutdoorAirNode)%MassFlowRate = MdotAir * HPPartLoadRatio
END IF
END IF
IF(HPPartLoadRatio .EQ. 0)WaterThermalTank(WaterThermalTankNum)%SourceInletTemp = &
WaterThermalTank(WaterThermalTankNum)%SourceOutletTemp
! set water-side mass flow rate for final calculation
Node(HPWaterInletNode)%MassFlowRate = MdotWater * HPPartLoadRatio
! pass node information using resulting PLR
IF(HPWaterHeater(HPNum)%FanPlacement .EQ. BlowThru) THEN
! simulate fan and DX coil twice to pass PLF (OnOffFanPartLoadFraction) to fan
CALL SimulateFanComponents(HPWaterHeater(HPNum)%FanName, FirstHVACIteration,HPWaterHeater(HPNum)%FanNum)
CALL SimDXCoil(HPWaterHeater(HPNum)%DXCoilName, CompOp, FirstHVACIteration,HPPartLoadRatio, &
HPWaterHeater(HPNum)%DXCoilNum,CycFanCycCoil)
CALL SimulateFanComponents(HPWaterHeater(HPNum)%FanName, FirstHVACIteration,HPWaterHeater(HPNum)%FanNum)
CALL SimDXCoil(HPWaterHeater(HPNum)%DXCoilName, CompOp,FirstHVACIteration, HPPartLoadRatio, &
HPWaterHeater(HPNum)%DXCoilNum,CycFanCycCoil)
ELSE
! simulate DX coil and fan twice to pass fan power (FanElecPower) to DX coil
CALL SimDXCoil(HPWaterHeater(HPNum)%DXCoilName, CompOp, FirstHVACIteration,HPPartLoadRatio, &
HPWaterHeater(HPNum)%DXCoilNum,CycFanCycCoil)
CALL SimulateFanComponents(HPWaterHeater(HPNum)%FanName, FirstHVACIteration,HPWaterHeater(HPNum)%FanNum)
CALL SimDXCoil(HPWaterHeater(HPNum)%DXCoilName, CompOp, FirstHVACIteration,HPPartLoadRatio, &
HPWaterHeater(HPNum)%DXCoilNum,CycFanCycCoil)
CALL SimulateFanComponents(HPWaterHeater(HPNum)%FanName, FirstHVACIteration,HPWaterHeater(HPNum)%FanNum)
END IF
! set HPWH outlet node equal to the outlet air splitter node conditions if outlet air splitter node exists
IF(OutletAirSplitterNode .GT. 0)THEN
Node(HPAirOutletNode) = Node(OutletAirSplitterNode)
Node(ExhaustAirNode) = Node(OutletAirSplitterNode)
END IF
! Check schedule to divert air-side cooling to outdoors.
IF(HPWaterHeater(HPNum)%OutletAirSplitterSchPtr .GT. 0)THEN
OutletAirSplitterSch = GetCurrentScheduleValue(HPWaterHeater(HPNum)%OutletAirSplitterSchPtr)
Node(HPAirOutletNode)%MassFlowRate = MdotAir * HPPartLoadRatio * (1.0d0 - OutletAirSplitterSch)
Node(ExhaustAirNode)%MassFlowRate = MdotAir * HPPartLoadRatio * OutletAirSplitterSch
END IF
HPWaterHeater(HPNum)%HeatingPLR = HPPartLoadRatio
HPWaterHeater(HPNum)%OnCycParaFuelRate = HPWaterHeater(HPNum)%OnCycParaLoad * HPPartLoadRatio
HPWaterHeater(HPNum)%OnCycParaFuelEnergy = HPWaterHeater(HPNum)%OnCycParaFuelRate * TimeStepSys * SecInHour
HPWaterHeater(HPNum)%OffCycParaFuelRate = HPWaterHeater(HPNum)%OffCycParaLoad * (1.0d0-HPPartLoadRatio)
HPWaterHeater(HPNum)%OffCycParaFuelEnergy = HPWaterHeater(HPNum)%OffCycParaFuelRate * TimeStepSys * SecInHour
SELECT CASE (HPWaterHeater(HPNum)%InletAirConfiguration)
! no sensible capacity to zone for outdoor and scheduled HPWH
CASE (AmbientTempOutsideAir)
HPWaterHeater(HPNum)%HPWaterHeaterSensibleCapacity = 0.0d0
HPWaterHeater(HPNum)%HPWaterHeaterLatentCapacity = 0.0d0
CASE (AmbientTempSchedule)
HPWaterHeater(HPNum)%HPWaterHeaterSensibleCapacity = 0.0d0
HPWaterHeater(HPNum)%HPWaterHeaterLatentCapacity = 0.0d0
! calculate sensible capacity to zone for inlet air configuration equals Zone Only or Zone And Outdoor Air configurations
CASE DEFAULT
CpAir = PsyCpAirFnWTdb(Node(HPAirInletNode)%HumRat,Node(HPAirInletNode)%Temp)
! add parasitics to zone heat balance if parasitic heat load is to zone otherwise neglect parasitics
IF(HPWaterHeater(HPNum)%ParasiticTempIndicator .EQ. AmbientTempZone)THEN
HPWaterHeater(HPNum)%HPWaterHeaterSensibleCapacity = (Node(HPAirOutletNode)%MassFlowRate * CpAir * &
(Node(HPAirOutletNode)%Temp - Node(HPAirInletNode)%Temp)) + &
HPWaterHeater(HPNum)%OnCycParaFuelRate + HPWaterHeater(HPNum)%OffCycParaFuelRate
ELSE
HPWaterHeater(HPNum)%HPWaterHeaterSensibleCapacity = Node(HPAirOutletNode)%MassFlowRate * CpAir * &
(Node(HPAirOutletNode)%Temp - Node(HPAirInletNode)%Temp)
END IF
HPWaterHeater(HPNum)%HPWaterHeaterLatentCapacity = Node(HPAirOutletNode)%MassFlowRate * &
(Node(HPAirOutletNode)%HumRat - Node(HPAirInletNode)%HumRat)
END SELECT
RETURN
END SUBROUTINE CalcHeatPumpWaterHeater