diff --git a/src/EnergyPlus/DXCoils.cc b/src/EnergyPlus/DXCoils.cc index 9de06284896..b85819dc288 100644 --- a/src/EnergyPlus/DXCoils.cc +++ b/src/EnergyPlus/DXCoils.cc @@ -17326,12 +17326,20 @@ void ControlVRFIUCoil(EnergyPlusData &state, if (QCoilSenHeatingLoad > QinSenMin1) { // Modulate fan speed to meet room sensible load; SC is not updated FanSpdRatioMax = 1.0; - auto f = [QCoilSenHeatingLoad, Ts_1, Tin, Garate, BF](Real64 FanSpdRto) { - return FanSpdResidualHeat(FanSpdRto, QCoilSenHeatingLoad, Ts_1, Tin, Garate, BF); + Tout = Tin + (Ts_1 - Tin) * (1 - BF); + Real64 RatedAirMassFlowRate = state.dataDXCoils->DXCoil(CoilIndex).RatedAirMassFlowRate[0]; + auto f = [QCoilSenHeatingLoad, RatedAirMassFlowRate, Tout, Tin, Win](Real64 FanSpdRto) { + return FanSpdResidualHeatUsingH(FanSpdRto, QCoilSenHeatingLoad, RatedAirMassFlowRate, Tout, Tin, Win); }; General::SolveRoot(state, 1.0e-3, MaxIter, SolFla, Ratio1, f, FanSpdRatioMin, FanSpdRatioMax); // this will likely cause problems eventually, -1 and -2 mean different things - if (SolFla < 0) Ratio1 = FanSpdRatioMax; // over capacity + if (SolFla < 0) { + if (f(FanSpdRatioMin) <= 0) { // capacity <= demand + Ratio1 = FanSpdRatioMax; // over capacity + } else { // capacity > demand even for the minimum fan speed + Ratio1 = FanSpdRatioMin; + } + } FanSpdRatio = Ratio1; CoilOnOffRatio = 1.0; @@ -17612,6 +17620,28 @@ Real64 FanSpdResidualHeat(Real64 FanSpdRto, Real64 QCoilSenHeatingLoad, Real64 T return (TotCap - ZnSenLoad) / ZnSenLoad; } +Real64 FanSpdResidualHeatUsingH(Real64 FanSpdRto, Real64 QCoilSenHeatingLoad, Real64 RatedAirMassFlowRate, Real64 Tout, Real64 Tin, Real64 Win) +{ + + // FUNCTION INFORMATION: + // AUTHOR Yujie Xu (yujiex) + // DATE WRITTEN Jul 2024 + // + // PURPOSE OF THIS FUNCTION: + // Calculates residual function (desired zone heating load - actual heating coil capacity) + // This is used to modify the fan speed to adjust the coil heating capacity to match + // the zone heating load. This one uses Hin and Hout difference rather than Tin and Tout difference + // like in FanSpdResidualHeat + // + Real64 ZnSenLoad = QCoilSenHeatingLoad; + // +-100 W minimum zone load? + // not sure why this is needed, inherited from FanSpdResidualHeat + // if (std::abs(ZnSenLoad) < 100.0) ZnSenLoad = sign(100.0, ZnSenLoad); + Real64 Wout = Win; + Real64 TotCap = FanSpdRto * RatedAirMassFlowRate * (PsyHFnTdbW(Tout, Wout) - PsyHFnTdbW(Tin, Win)); + return (TotCap - ZnSenLoad) / ZnSenLoad; +} + void SetMSHPDXCoilHeatRecoveryFlag(EnergyPlusData &state, int const DXCoilNum) { diff --git a/src/EnergyPlus/DXCoils.hh b/src/EnergyPlus/DXCoils.hh index ea35193b925..219c6d3118b 100644 --- a/src/EnergyPlus/DXCoils.hh +++ b/src/EnergyPlus/DXCoils.hh @@ -932,6 +932,8 @@ namespace DXCoils { Real64 FanSpdResidualHeat(Real64 FanSpdRto, Real64 QCoilSenHeatingLoad, Real64 Ts_1, Real64 Tin, Real64 Garate, Real64 BF); + Real64 FanSpdResidualHeatUsingH(Real64 FanSpdRto, Real64 QCoilSenHeatingLoad, Real64 RatedAirMassFlowRate, Real64 Tout, Real64 Tin, Real64 Win); + void SetMSHPDXCoilHeatRecoveryFlag(EnergyPlusData &state, int const DXCoilNum); // must match coil names for the coil type void SetDXCoilAirLoopNumber(EnergyPlusData &state, std::string const &CoilName, int const AirLoopNum); // must match coil names for the coil type diff --git a/src/EnergyPlus/HVACVariableRefrigerantFlow.cc b/src/EnergyPlus/HVACVariableRefrigerantFlow.cc index 58d610b342c..eecba3566fe 100644 --- a/src/EnergyPlus/HVACVariableRefrigerantFlow.cc +++ b/src/EnergyPlus/HVACVariableRefrigerantFlow.cc @@ -267,6 +267,45 @@ void SimulateVRF(EnergyPlusData &state, if (state.dataHVACVarRefFlow->VRF(VRFCondenser).VRFAlgorithmType == AlgorithmType::FluidTCtrl) { // Algorithm Type: VRF model based on physics, applicable for Fluid Temperature Control state.dataHVACVarRefFlow->VRF(VRFCondenser).CalcVRFCondenser_FluidTCtrl(state, FirstHVACIteration); + + // update heating coil heating rate with the new OU output and piping correction factor + for (int VRFTUNum = 1; VRFTUNum <= state.dataHVACVarRefFlow->NumVRFTU; ++VRFTUNum) { + auto const &thisTU = state.dataHVACVarRefFlow->VRFTU(VRFTUNum); + if (state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCondenser) < Constant::MaxCap) { + auto &heatingCoil = state.dataDXCoils->DXCoil(thisTU.HeatCoilIndex); + Real64 FanSpdRatio; + Real64 OutletAirHumRat; + Real64 OutletAirTemp; + Real64 OutletAirEnthalpy; + Real64 ActualSH; + Real64 ActualSC; + Real64 AirMassFlowMin = state.dataHVACVarRefFlow->OACompOnMassFlow; + if (heatingCoil.PartLoadRatio == 0.0) { + AirMassFlowMin = state.dataHVACVarRefFlow->OACompOffMassFlow; + } + DXCoils::ControlVRFIUCoil(state, + thisTU.HeatCoilIndex, + state.dataHVACVarRefFlow->VRF(VRFCondenser).TotalHeatingCapacity * + state.dataHVACVarRefFlow->VRF(VRFCondenser).PipingCorrectionHeating, + heatingCoil.InletAirTemp, + heatingCoil.InletAirHumRat, + heatingCoil.CondensingTemp, + AirMassFlowMin, + FanSpdRatio, + OutletAirHumRat, + OutletAirTemp, + OutletAirEnthalpy, + ActualSH, + ActualSC); + Real64 AirMassFlow = FanSpdRatio * heatingCoil.RatedAirMassFlowRate(1); // heating mode + // fixme: temporary remove multiply of coil PLR + heatingCoil.TotalHeatingEnergyRate = AirMassFlow * (OutletAirEnthalpy - heatingCoil.InletAirEnthalpy); + if (heatingCoil.PartLoadRatio > 0.0) { + heatingCoil.TotalHeatingEnergyRate *= heatingCoil.PartLoadRatio; + } + } + } + } else { // Algorithm Type: VRF model based on system curve CalcVRFCondenser(state, VRFCondenser);