Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correct physics based VRF model to align inlet and outlet air flow rates #7295

Merged
merged 12 commits into from
May 17, 2019
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,7 @@ \subsubsection{Overview}\label{VRF-FluidTCtrl-HP-overview}

Note that a number of calculation steps are coupled together in the VRF-FluidTCtrl model, for instance, the piping loss calculation and the system performance calculation. More specifically, the piping loss changes the operating conditions of the system, which may lead to a different control strategy and thus in reverse affect the amount of piping loss. This makes it difficult to obtain an analytical solution for a number of operational parameters (e.g., enthalpy of refrigerant entering the indoor unit), and therefore numerical iterations are employed to address this problem (refer to Figure VRF-FluidTCtrl-3 for more details). Therefore, the VRF-FluidTCtrl model can have a longer execution time to perform the simulation than the VRF-SysCurve model.

The object connections for VRF-FluidTCtrl model is similar to those for VRF-SysCurve model. The difference lies in the object used to describe a specific components. For example, VRF-SysCurve model uses \emph{AirConditioner:VariableRefrigerantFlow} object to describe the VRF outdoor unit performance, while in VRF-FluidTCtrl model the \emph{AirConditioner:VariableRefrigerantFlow} object is used.
The object connections for VRF-FluidTCtrl model is similar to those for VRF-SysCurve model. The difference lies in the object used to describe a specific components. For example, VRF-SysCurve model uses \emph{AirConditioner:VariableRefrigerantFlow} object to describe the VRF outdoor unit performance, while in VRF-FluidTCtrl model the \emph{AirConditioner:VariableRefrigerantFlow:FluidTemperatureControl} object is used.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good find.


\begin{figure}[hbtp] % figure VRF-FluidTCtrl-1b
\centering
Expand Down
88 changes: 27 additions & 61 deletions src/EnergyPlus/HVACVariableRefrigerantFlow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3287,6 +3287,8 @@ namespace HVACVariableRefrigerantFlow {
if (errFlag) {
ShowContinueError("...occurs in " + cCurrentModuleObject + " = " + VRFTU(VRFTUNum).Name);
ErrorsFound = true;
} else {
VRFTU(VRFTUNum).fanOutletNode = Fans::Fan(VRFTU(VRFTUNum).FanIndex).OutletNodeNum;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Save fan outlet node for use in TeTc calculations.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable enough, if you are going to have to query what the fan is doing, you can check the outlet node.

}

// Set the Design Fan Volume Flow Rate
Expand Down Expand Up @@ -3350,6 +3352,7 @@ namespace HVACVariableRefrigerantFlow {
FanInletNodeNum = HVACFan::fanObjs[VRFTU(VRFTUNum).FanIndex]->inletNodeNum;
FanOutletNodeNum = HVACFan::fanObjs[VRFTU(VRFTUNum).FanIndex]->outletNodeNum;
VRFTU(VRFTUNum).FanAvailSchedPtr = HVACFan::fanObjs[VRFTU(VRFTUNum).FanIndex]->availSchedIndex;
VRFTU(VRFTUNum).fanOutletNode = HVACFan::fanObjs[VRFTU(VRFTUNum).FanIndex]->outletNodeNum;
}
} else { // IF (FanType_Num == FanType_SimpleOnOff .OR. FanType_Num == FanType_SimpleConstVolume)THEN
ShowSevereError(cCurrentModuleObject + " = " + VRFTU(VRFTUNum).Name);
Expand Down Expand Up @@ -7017,6 +7020,15 @@ namespace HVACVariableRefrigerantFlow {
// Algorithm Type: VRF model based on physics, appliable for Fluid Temperature Control
VRFTU(VRFTUNum).ControlVRF_FluidTCtrl(VRFTUNum, QZnReq, FirstHVACIteration, PartLoadRatio, OnOffAirFlowRatio);
VRFTU(VRFTUNum).CalcVRF_FluidTCtrl(VRFTUNum, FirstHVACIteration, PartLoadRatio, SysOutputProvided, OnOffAirFlowRatio, LatOutputProvided);
if (PartLoadRatio == 0.0) { // set coil inlet conditions when coil does not operate. Inlet conditions are set in ControlVRF_FluidTCtrl when PLR=1
if (VRFTU(VRFTUNum).CoolingCoilPresent) {
VRFTU(VRFTUNum).coilInNodeT = DataLoopNode::Node(DXCoils::DXCoil(VRFTU(VRFTUNum).CoolCoilIndex).AirInNode).Temp;
VRFTU(VRFTUNum).coilInNodeW = DataLoopNode::Node(DXCoils::DXCoil(VRFTU(VRFTUNum).CoolCoilIndex).AirInNode).HumRat;
} else {
VRFTU(VRFTUNum).coilInNodeT = DataLoopNode::Node(DXCoils::DXCoil(VRFTU(VRFTUNum).HeatCoilIndex).AirInNode).Temp;
VRFTU(VRFTUNum).coilInNodeW = DataLoopNode::Node(DXCoils::DXCoil(VRFTU(VRFTUNum).HeatCoilIndex).AirInNode).HumRat;
}
}
// CalcVRF( VRFTUNum, FirstHVACIteration, PartLoadRatio, SysOutputProvided, OnOffAirFlowRatio, LatOutputProvided );
} else {
// Algorithm Type: VRF model based on system curve
Expand Down Expand Up @@ -7094,7 +7106,6 @@ namespace HVACVariableRefrigerantFlow {
// The RETURNS here will jump back to SimVRF where the CalcVRF routine will simulate with latest PLR

// do nothing else if TU is scheduled off
//!!LKL Discrepancy < 0
if (GetCurrentScheduleValue(VRFTU(VRFTUNum).SchedPtr) == 0.0) return;

// do nothing if TU has no load (TU will be modeled using PLR=0)
Expand Down Expand Up @@ -8526,7 +8537,7 @@ namespace HVACVariableRefrigerantFlow {
for (int i = 1; i <= TerminalUnitList(TUListNum).NumTUInList; i++) {
int VRFTUNum = TerminalUnitList(TUListNum).ZoneTUPtr(i);
// analyze the conditions of each IU
VRFTU(VRFTUNum).CalcVRFIUVariableTeTc(VRFTUNum, EvapTemp(i), CondTemp(i));
VRFTU(VRFTUNum).CalcVRFIUVariableTeTc(EvapTemp(i), CondTemp(i));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 👍 👍 👍


// select the Te/Tc that can satisfy all the zones
IUMinEvapTemp = min(IUMinEvapTemp, EvapTemp(i), this->IUEvapTempHigh);
Expand All @@ -8543,8 +8554,7 @@ namespace HVACVariableRefrigerantFlow {
}
}

void VRFTerminalUnitEquipment::CalcVRFIUVariableTeTc(int const VRFTUNum, // Index to VRF terminal unit
Real64 &EvapTemp, // evaporating temperature
void VRFTerminalUnitEquipment::CalcVRFIUVariableTeTc(Real64 &EvapTemp, // evaporating temperature
Real64 &CondTemp // condensing temperature
)
{
Expand All @@ -8570,7 +8580,6 @@ namespace HVACVariableRefrigerantFlow {
using DXCoils::DXCoil;
using HVACVariableRefrigerantFlow::VRF;
using HVACVariableRefrigerantFlow::VRFTU;
using MixedAir::OAMixer;
using MixedAir::SimOAMixer;
using Psychrometrics::PsyHFnTdbW;
using SingleDuct::SimATMixer;
Expand All @@ -8588,12 +8597,8 @@ namespace HVACVariableRefrigerantFlow {
// na

// SUBROUTINE LOCAL VARIABLE DECLARATIONS:
int const Mode(1); // Performance mode for MultiMode DX coil. Always 1 for other coil types
int CoolCoilNum; // index to the VRF Cooling DX coil to be simulated
int FanOutletNode; // index to the outlet node of the fan
int HeatCoilNum; // index to the VRF Heating DX coil to be simulated
int OAMixerNum; // OA mixer index
int OAMixNode; // index to the mix node of OA mixer
int IndexToTUInTUList; // index to TU in specific list for the VRF system
int TUListIndex; // index to TU list for this VRF system
int VRFNum; // index to VRF that the VRF Terminal Unit serves
Expand All @@ -8619,7 +8624,6 @@ namespace HVACVariableRefrigerantFlow {
Real64 RHsat; // Relative humidity of the air at saturated condition(-)
Real64 SH; // Super heating degrees (C)
Real64 SC; // Subcooling degrees (C)
Real64 temp; // for temporary use
Real64 T_coil_in; // Temperature of the air at the coil inlet, after absorbing the heat released by fan (C)
Real64 T_TU_in; // Air temperature at the indoor unit inlet (C)
Real64 Tout; // Air temperature at the indoor unit outlet (C)
Expand Down Expand Up @@ -8651,46 +8655,11 @@ namespace HVACVariableRefrigerantFlow {
C2Tcond = DXCoil(HeatCoilNum).C2Tc;
C3Tcond = DXCoil(HeatCoilNum).C3Tc;

// Rated air flow rate for the coil
if ((!VRF(VRFNum).HeatRecoveryUsed && CoolingLoad(VRFNum)) ||
(VRF(VRFNum).HeatRecoveryUsed && TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList))) {
// VRF terminal unit is on cooling mode
CompOnMassFlow = DXCoil(CoolCoilNum).RatedAirMassFlowRate(Mode);
} else if ((!VRF(VRFNum).HeatRecoveryUsed && HeatingLoad(VRFNum)) ||
(VRF(VRFNum).HeatRecoveryUsed && TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList))) {
// VRF terminal unit is on heating mode
CompOnMassFlow = DXCoil(HeatCoilNum).RatedAirMassFlowRate(Mode);
}

// Set inlet air mass flow rate based on PLR and compressor on/off air flow rates
SetAverageAirFlow(VRFTUNum, 1.0, temp);
VRFInletNode = this->VRFTUInletNodeNum;
T_TU_in = Node(VRFInletNode).Temp;
W_TU_in = Node(VRFInletNode).HumRat;
T_coil_in = T_TU_in;
W_coil_in = W_TU_in;

// Simulation the OAMixer if there is any
if (this->OAMixerUsed) {
SimOAMixer(this->OAMixerName, false, this->OAMixerIndex);

OAMixerNum = UtilityRoutines::FindItemInList(this->OAMixerName, OAMixer);
OAMixNode = OAMixer(OAMixerNum).MixNode;
T_coil_in = Node(OAMixNode).Temp;
W_coil_in = Node(OAMixNode).HumRat;
}
// Simulate the blow-through fan if there is any
if (this->FanPlace == BlowThru) {
if (this->fanType_Num == DataHVACGlobals::FanType_SystemModelObject) {
HVACFan::fanObjs[this->FanIndex]->simulate(1.0 / temp, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _);
FanOutletNode = HVACFan::fanObjs[this->FanIndex]->outletNodeNum;
} else {
Fans::SimulateFanComponents("", false, this->FanIndex, FanSpeedRatio, ZoneCompTurnFansOn, ZoneCompTurnFansOff);
FanOutletNode = Fans::Fan(this->FanIndex).OutletNodeNum;
}
T_coil_in = Node(FanOutletNode).Temp;
W_coil_in = Node(FanOutletNode).HumRat;
}
T_coil_in = this->coilInNodeT;
W_coil_in = this->coilInNodeW;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change here is that coil inlet temps are now used so it doesn't matter if blow thru fan or OA mixer is used. Gets rid of a lot of unnecessary code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 👍 👍 👍 👍 👍 👍 👍 👍 👍 👍


Garate = CompOnMassFlow;
H_coil_in = PsyHFnTdbW(T_coil_in, W_coil_in);
Expand Down Expand Up @@ -10076,8 +10045,7 @@ namespace HVACVariableRefrigerantFlow {
bool const FirstHVACIteration, // flag for 1st HVAC iteration in the time step
Real64 &PartLoadRatio, // unit part load ratio
Real64 &OnOffAirFlowRatio // ratio of compressor ON airflow to AVERAGE airflow over timestep
)
{
) {

// SUBROUTINE INFORMATION:
// AUTHOR Rongpeng Zhang
Expand Down Expand Up @@ -10150,7 +10118,6 @@ namespace HVACVariableRefrigerantFlow {
// The RETURNS here will jump back to SimVRF where the CalcVRF routine will simulate with latest PLR

// do nothing else if TU is scheduled off
//!!LKL Discrepancy < 0
if (GetCurrentScheduleValue(this->SchedPtr) == 0.0) return;

// Block the following statement: QZnReq==0 doesn't mean QCoilReq==0 due to possible OA mixer operation. zrp_201511
Expand Down Expand Up @@ -10186,6 +10153,13 @@ namespace HVACVariableRefrigerantFlow {
// Otherwise the coil needs to turn on. Get full load result
PartLoadRatio = 1.0;
this->CalcVRF_FluidTCtrl(VRFTUNum, FirstHVACIteration, PartLoadRatio, FullOutput, OnOffAirFlowRatio);
if (this->CoolingCoilPresent) {
this->coilInNodeT = DataLoopNode::Node(DXCoils::DXCoil(this->CoolCoilIndex).AirInNode).Temp;
this->coilInNodeW = DataLoopNode::Node(DXCoils::DXCoil(this->CoolCoilIndex).AirInNode).HumRat;
} else {
this->coilInNodeT = DataLoopNode::Node(DXCoils::DXCoil(this->HeatCoilIndex).AirInNode).Temp;
this->coilInNodeW = DataLoopNode::Node(DXCoils::DXCoil(this->HeatCoilIndex).AirInNode).HumRat;
}

PartLoadRatio = 0.0;

Expand Down Expand Up @@ -10400,7 +10374,6 @@ namespace HVACVariableRefrigerantFlow {
Fans::SimulateFanComponents("", FirstHVACIteration, this->FanIndex, FanSpeedRatio, ZoneCompTurnFansOn, ZoneCompTurnFansOff);
}
}

if (this->CoolingCoilPresent) {
// above condition for heat pump mode, below condition for heat recovery mode
if ((!VRF(VRFCond).HeatRecoveryUsed && CoolingLoad(VRFCond)) ||
Expand Down Expand Up @@ -10673,8 +10646,6 @@ namespace HVACVariableRefrigerantFlow {
// FUNCTION LOCAL VARIABLE DECLARATIONS:
int const Mode(1); // Performance mode for MultiMode DX coil. Always 1 for other coil types
int CoilIndex; // index to coil
int FanOutletNode; // index to the outlet node of the fan
int OAMixerNum; // OA mixer index
int OAMixNode; // index to the mix node of OA mixer
int VRFCond; // index to VRF condenser
int VRFTUNum; // Unit index in VRF terminal unit array
Expand Down Expand Up @@ -10724,24 +10695,19 @@ namespace HVACVariableRefrigerantFlow {
// Simulation the OAMixer if there is any
if (VRFTU(VRFTUNum).OAMixerUsed) {
SimOAMixer(VRFTU(VRFTUNum).OAMixerName, FirstHVACIteration, VRFTU(VRFTUNum).OAMixerIndex);

OAMixerNum = UtilityRoutines::FindItemInList(VRFTU(VRFTUNum).OAMixerName,
OAMixer); // this not needed, why not use VRFTU( VRFTUNum ).OAMixerIndex var
OAMixNode = OAMixer(OAMixerNum).MixNode;
OAMixNode = OAMixer(VRFTU(VRFTUNum).OAMixerIndex).MixNode;
Tin = Node(OAMixNode).Temp;
Win = Node(OAMixNode).HumRat;
}
// Simulate the blow-through fan if there is any
if (VRFTU(VRFTUNum).FanPlace == BlowThru) {
if (VRFTU(VRFTUNum).fanType_Num == DataHVACGlobals::FanType_SystemModelObject) {
HVACFan::fanObjs[VRFTU(VRFTUNum).FanIndex]->simulate(1.0 / temp, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _);
FanOutletNode = HVACFan::fanObjs[VRFTU(VRFTUNum).FanIndex]->outletNodeNum;
} else {
Fans::SimulateFanComponents("", false, VRFTU(VRFTUNum).FanIndex, FanSpeedRatio, ZoneCompTurnFansOn, ZoneCompTurnFansOff);
FanOutletNode = Fans::Fan(VRFTU(VRFTUNum).FanIndex).OutletNodeNum;
}
Tin = Node(FanOutletNode).Temp;
Win = Node(FanOutletNode).HumRat;
Tin = Node(VRFTU(VRFTUNum).fanOutletNode).Temp;
Win = Node(VRFTU(VRFTUNum).fanOutletNode).HumRat;
}

// Call the coil control logic to determine the air flow rate to match the given coil load
Expand Down
9 changes: 6 additions & 3 deletions src/EnergyPlus/HVACVariableRefrigerantFlow.hh
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,9 @@ namespace HVACVariableRefrigerantFlow {
int ATMixerSecNode; // secondary air inlet node number for the air terminal mixer
int ATMixerOutNode; // outlet air node number for the air terminal mixer
bool firstPass; // used to reset global sizing data
Real64 coilInNodeT; // coil inlet node temp at full flow (C)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new variables to hold data in order to eliminate the problem with flow mismatch from inlet to outlet.

Real64 coilInNodeW; // coil inlet node humidity ratio at full flow (kg/kg)
int fanOutletNode; // fan outlet node index
// Default Constructor
VRFTerminalUnitEquipment()
: VRFTUType_Num(0), SchedPtr(-1), VRFSysNum(0), TUListIndex(0), IndexToTUInTUList(0), ZoneNum(0), VRFTUInletNodeNum(0),
Expand All @@ -715,7 +718,8 @@ namespace HVACVariableRefrigerantFlow {
SensibleCoolingRate(0.0), SensibleHeatingRate(0.0), LatentCoolingRate(0.0), LatentHeatingRate(0.0), TotalCoolingEnergy(0.0),
TotalHeatingEnergy(0.0), SensibleCoolingEnergy(0.0), SensibleHeatingEnergy(0.0), LatentCoolingEnergy(0.0), LatentHeatingEnergy(0.0),
EMSOverridePartLoadFrac(false), EMSValueForPartLoadFrac(0.0), IterLimitExceeded(0), FirstIterfailed(0), ZonePtr(0), HVACSizingIndex(0),
ATMixerExists(false), ATMixerIndex(0), ATMixerType(0), ATMixerPriNode(0), ATMixerSecNode(0), ATMixerOutNode(0), firstPass(true)
ATMixerExists(false), ATMixerIndex(0), ATMixerType(0), ATMixerPriNode(0), ATMixerSecNode(0), ATMixerOutNode(0), firstPass(true),
coilInNodeT(0.0), coilInNodeW(0.0), fanOutletNode(0)
{
}

Expand All @@ -725,8 +729,7 @@ namespace HVACVariableRefrigerantFlow {
// Note: the argument VRFTUNum should be removed later in the deeper OO re-factor. Now this argument may be used by other functions that are
// not member functions of this class.

void CalcVRFIUVariableTeTc(int const VRFTUNum, // Index to VRF terminal unit
Real64 &EvapTemp, // evaporating temperature
void CalcVRFIUVariableTeTc(Real64 &EvapTemp, // evaporating temperature
Real64 &CondTemp // condensing temperature
);

Expand Down