diff --git a/src/EnergyPlus/HVACVariableRefrigerantFlow.cc b/src/EnergyPlus/HVACVariableRefrigerantFlow.cc index 4d94a8e06ae..f8669d76bba 100644 --- a/src/EnergyPlus/HVACVariableRefrigerantFlow.cc +++ b/src/EnergyPlus/HVACVariableRefrigerantFlow.cc @@ -12660,6 +12660,25 @@ void VRFTerminalUnitEquipment::CalcVRF_FluidTCtrl(EnergyPlusData &state, // now calculate the the mixer outlet air conditions (and the secondary air inlet flow rate). The mixer outlet flow rate has already // been set above (it is the "inlet" node flow rate) SimATMixer(state, this->ATMixerName, FirstHVACIteration, this->ATMixerIndex); + // inlet side ATMixer can change the VRF TU inlet condition and therefore the operating air flow rate + if (this->fanOp == HVAC::FanOp::Cycling && PartLoadRatio > 0) { + if (this->HeatingCoilPresent && state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond) < Constant::MaxCap) { + // Only fix heating only mode for now + state.dataHVACVarRefFlow->CompOnMassFlow = CalVRFTUAirFlowRate_FluidTCtrl( + state, VRFTUNum, PartLoadRatio, FirstHVACIteration, state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond)); + } else { + state.dataHVACVarRefFlow->CompOnMassFlow = CalVRFTUAirFlowRate_FluidTCtrl(state, VRFTUNum, PartLoadRatio, FirstHVACIteration, _); + } + if (std::abs(state.dataHVACVarRefFlow->CompOnMassFlow - AirMassFlow) > HVAC::SmallMassFlow) { + SetAverageAirFlow(state, VRFTUNum, PartLoadRatio, OnOffAirFlowRatio); + AirMassFlow = state.dataLoopNodes->Node(VRFTUInletNodeNum).MassFlowRate; + // set the primary air inlet mass flow rate + state.dataLoopNodes->Node(this->ATMixerPriNode).MassFlowRate = + min(state.dataLoopNodes->Node(this->ATMixerPriNode).MassFlowRateMaxAvail, + state.dataLoopNodes->Node(VRFTUInletNodeNum).MassFlowRate); + SimATMixer(state, this->ATMixerName, FirstHVACIteration, this->ATMixerIndex); + } + } } } else { state.dataHVACVarRefFlow->ATMixOutNode2 = 0; diff --git a/src/EnergyPlus/SingleDuct.cc b/src/EnergyPlus/SingleDuct.cc index 7fbafbed007..edbeecbfff0 100644 --- a/src/EnergyPlus/SingleDuct.cc +++ b/src/EnergyPlus/SingleDuct.cc @@ -5347,57 +5347,40 @@ void CalcATMixer(EnergyPlusData &state, int const SysNum) // PURPOSE OF THIS SUBROUTINE // Calculate the mixed air flow and conditions in the air terminal mixer - // Using/Aliasing - using Psychrometrics::PsyTdbFnHW; - - state.dataSingleDuct->PriEnthalpyCATM = state.dataLoopNodes->Node(state.dataSingleDuct->SysATMixer(SysNum).PriInNode).Enthalpy; - state.dataSingleDuct->PriHumRatCATM = state.dataLoopNodes->Node(state.dataSingleDuct->SysATMixer(SysNum).PriInNode).HumRat; - state.dataSingleDuct->PriTempCATM = state.dataLoopNodes->Node(state.dataSingleDuct->SysATMixer(SysNum).PriInNode).Temp; - state.dataSingleDuct->PriMassFlowRateCATM = state.dataLoopNodes->Node(state.dataSingleDuct->SysATMixer(SysNum).PriInNode).MassFlowRate; + auto &atMixer = state.dataSingleDuct->SysATMixer(SysNum); + auto &priInNode = state.dataLoopNodes->Node(atMixer.PriInNode); + auto &secInNode = state.dataLoopNodes->Node(atMixer.SecInNode); + auto &mixedAirOutNode = state.dataLoopNodes->Node(atMixer.MixedAirOutNode); - state.dataSingleDuct->SecAirMassFlowRateCATM = state.dataLoopNodes->Node(state.dataSingleDuct->SysATMixer(SysNum).SecInNode).MassFlowRate; - state.dataSingleDuct->SecAirEnthalpyCATM = state.dataLoopNodes->Node(state.dataSingleDuct->SysATMixer(SysNum).SecInNode).Enthalpy; - state.dataSingleDuct->SecAirHumRatCATM = state.dataLoopNodes->Node(state.dataSingleDuct->SysATMixer(SysNum).SecInNode).HumRat; - state.dataSingleDuct->SecAirTempCATM = state.dataLoopNodes->Node(state.dataSingleDuct->SysATMixer(SysNum).SecInNode).Temp; + Real64 MixedAirMassFlowRate = + (atMixer.type == HVAC::MixerType::SupplySide) ? secInNode.MassFlowRate + priInNode.MassFlowRate : mixedAirOutNode.MassFlowRate; - if (state.dataSingleDuct->SysATMixer(SysNum).type == HVAC::MixerType::SupplySide) { - state.dataSingleDuct->MixedAirMassFlowRateCATM = state.dataSingleDuct->SecAirMassFlowRateCATM + state.dataSingleDuct->PriMassFlowRateCATM; - } else { + if (atMixer.type == HVAC::MixerType::InletSide) { // for inlet side mixer, the mixed air flow has been set, but we don't know the secondary flow - state.dataSingleDuct->MixedAirMassFlowRateCATM = - state.dataLoopNodes->Node(state.dataSingleDuct->SysATMixer(SysNum).MixedAirOutNode).MassFlowRate; - state.dataSingleDuct->SecAirMassFlowRateCATM = - max(state.dataSingleDuct->MixedAirMassFlowRateCATM - state.dataSingleDuct->PriMassFlowRateCATM, 0.0); - state.dataLoopNodes->Node(state.dataSingleDuct->SysATMixer(SysNum).SecInNode).MassFlowRate = state.dataSingleDuct->SecAirMassFlowRateCATM; - if (std::abs(state.dataSingleDuct->PriMassFlowRateCATM + state.dataSingleDuct->SecAirMassFlowRateCATM - - state.dataSingleDuct->MixedAirMassFlowRateCATM) > SmallMassFlow) { - ShowSevereError( - state, - format("CalcATMixer: Invalid mass flow rates in AirTerminal:SingleDuct:Mixer={}", state.dataSingleDuct->SysATMixer(SysNum).Name)); + secInNode.MassFlowRate = max(MixedAirMassFlowRate - priInNode.MassFlowRate, 0.0); + if (std::abs(priInNode.MassFlowRate + secInNode.MassFlowRate - MixedAirMassFlowRate) > SmallMassFlow) { + ShowSevereError(state, format("CalcATMixer: Invalid mass flow rates in AirTerminal:SingleDuct:Mixer={}", atMixer.Name)); ShowContinueErrorTimeStamp(state, format("Primary mass flow rate={:.6R}Secondary mass flow rate={:.6R}Mixed mass flow rate={:.6R}", - state.dataSingleDuct->PriMassFlowRateCATM, - state.dataSingleDuct->SecAirMassFlowRateCATM, - state.dataSingleDuct->MixedAirMassFlowRateCATM)); + priInNode.MassFlowRate, + secInNode.MassFlowRate, + MixedAirMassFlowRate)); ShowFatalError(state, "Simulation terminates."); } } // now calculate the mixed (outlet) conditions - if (state.dataSingleDuct->MixedAirMassFlowRateCATM > 0.0) { - state.dataSingleDuct->MixedAirEnthalpyCATM = (state.dataSingleDuct->SecAirMassFlowRateCATM * state.dataSingleDuct->SecAirEnthalpyCATM + - state.dataSingleDuct->PriMassFlowRateCATM * state.dataSingleDuct->PriEnthalpyCATM) / - state.dataSingleDuct->MixedAirMassFlowRateCATM; - state.dataSingleDuct->MixedAirHumRatCATM = (state.dataSingleDuct->SecAirMassFlowRateCATM * state.dataSingleDuct->SecAirHumRatCATM + - state.dataSingleDuct->PriMassFlowRateCATM * state.dataSingleDuct->PriHumRatCATM) / - state.dataSingleDuct->MixedAirMassFlowRateCATM; + if ((atMixer.MixedAirMassFlowRate = MixedAirMassFlowRate) > 0.0) { + Real64 MixedAirEnthalpy = (secInNode.MassFlowRate * secInNode.Enthalpy + priInNode.MassFlowRate * priInNode.Enthalpy) / MixedAirMassFlowRate; + Real64 MixedAirHumRat = (secInNode.MassFlowRate * secInNode.HumRat + priInNode.MassFlowRate * priInNode.HumRat) / MixedAirMassFlowRate; // Mixed air temperature is calculated from the mixed air enthalpy and humidity ratio. - state.dataSingleDuct->MixedAirTempCATM = PsyTdbFnHW(state.dataSingleDuct->MixedAirEnthalpyCATM, state.dataSingleDuct->MixedAirHumRatCATM); + atMixer.MixedAirTemp = Psychrometrics::PsyTdbFnHW(MixedAirEnthalpy, MixedAirHumRat); + atMixer.MixedAirEnthalpy = MixedAirEnthalpy; + atMixer.MixedAirHumRat = MixedAirHumRat; + } else { + atMixer.MixedAirEnthalpy = priInNode.Enthalpy; + atMixer.MixedAirHumRat = priInNode.HumRat; + atMixer.MixedAirTemp = priInNode.Temp; } - - state.dataSingleDuct->SysATMixer(SysNum).MixedAirMassFlowRate = state.dataSingleDuct->MixedAirMassFlowRateCATM; - state.dataSingleDuct->SysATMixer(SysNum).MixedAirEnthalpy = state.dataSingleDuct->MixedAirEnthalpyCATM; - state.dataSingleDuct->SysATMixer(SysNum).MixedAirHumRat = state.dataSingleDuct->MixedAirHumRatCATM; - state.dataSingleDuct->SysATMixer(SysNum).MixedAirTemp = state.dataSingleDuct->MixedAirTempCATM; } void UpdateATMixer(EnergyPlusData &state, int const SysNum) diff --git a/src/EnergyPlus/SingleDuct.hh b/src/EnergyPlus/SingleDuct.hh index 0de7e36788b..9c74b910c17 100644 --- a/src/EnergyPlus/SingleDuct.hh +++ b/src/EnergyPlus/SingleDuct.hh @@ -403,20 +403,6 @@ struct SingleDuctData : BaseGlobalStruct Real64 ZoneTempSCV = 0.0; // Zone temperature [C] Real64 QMax2SCV = 0.0; int SysNumSATM = 0; - Real64 PriMassFlowRateCATM = 0.0; - Real64 PriEnthalpyCATM = 0.0; - Real64 PriHumRatCATM = 0.0; - Real64 PriTempCATM = 0.0; - - Real64 SecAirMassFlowRateCATM = 0.0; - Real64 SecAirEnthalpyCATM = 0.0; - Real64 SecAirHumRatCATM = 0.0; - Real64 SecAirTempCATM = 0.0; - - Real64 MixedAirMassFlowRateCATM = 0.0; - Real64 MixedAirEnthalpyCATM = 0.0; - Real64 MixedAirHumRatCATM = 0.0; - Real64 MixedAirTempCATM = 0.0; Real64 ZoneTempSDAT = 0.0; // zone air temperature [C] Real64 MaxHeatTempSDAT = 0.0; // maximum supply air temperature [C] diff --git a/tst/EnergyPlus/unit/AirTerminalSingleDuctMixer.unit.cc b/tst/EnergyPlus/unit/AirTerminalSingleDuctMixer.unit.cc index 0d39e33183d..58ae4aa0a70 100644 --- a/tst/EnergyPlus/unit/AirTerminalSingleDuctMixer.unit.cc +++ b/tst/EnergyPlus/unit/AirTerminalSingleDuctMixer.unit.cc @@ -3314,7 +3314,7 @@ TEST_F(EnergyPlusFixture, AirTerminalSingleDuctMixer_SimVRF_ATMSupplySide) // check the terminal air mixer outlet air mass flow rate ATMixerOutletMassFlowRate = SecondaryAirMassFlowRate + PrimaryAirMassFlowRate; ASSERT_EQ(ATMixerOutletMassFlowRate, state->dataSingleDuct->SysATMixer(1).MixedAirMassFlowRate); - // check the cooling output delivered is within 2.0 Watt of zone cooling load + // check the cooling output delivered is within 4.0 Watt of zone cooling load ASSERT_NEAR(QZnReq, QUnitOutVRFTU, 4.0); } @@ -5094,6 +5094,7 @@ TEST_F(EnergyPlusFixture, AirTerminalSingleDuctMixer_SimVRFfluidCntrl_ATMInletSi ASSERT_EQ(HVACInletMassFlowRate, state->dataSingleDuct->SysATMixer(1).MixedAirMassFlowRate); // check the cooling output delivered is within 5.0 Watt of zone cooling load ASSERT_NEAR(QZnReq, QUnitOutVRFTU, 5.0); + EXPECT_NEAR(0.965, state->dataDXCoils->DXCoil(1).PartLoadRatio, 0.001); } TEST_F(EnergyPlusFixture, AirTerminalSingleDuctMixer_SimVRFfluidCntrl_ATMSupplySide)