diff --git a/src/EnergyPlus/FanCoilUnits.cc b/src/EnergyPlus/FanCoilUnits.cc index 6effd67830d..c8c374b2364 100644 --- a/src/EnergyPlus/FanCoilUnits.cc +++ b/src/EnergyPlus/FanCoilUnits.cc @@ -3594,8 +3594,7 @@ namespace FanCoilUnits { ZoneCompTurnFansOn, ZoneCompTurnFansOff); } else { - HVACFan::fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate( - FanCoil(FanCoilNum).LowSpeedRatio, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _); + HVACFan::fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate(_, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _); } } else if (FanCoil(FanCoilNum).SpeedFanSel == 2) { @@ -3607,15 +3606,22 @@ namespace FanCoilUnits { ZoneCompTurnFansOn, ZoneCompTurnFansOff); } else { - HVACFan::fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate( - FanCoil(FanCoilNum).MedSpeedRatio, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _); + HVACFan::fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate(_, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _); } - } else { // using 1.0 here for fan speed ratio seems wrong if FCU max flow rate is different than the fan maximum flow rate + } else if (FanCoil(FanCoilNum).SpeedFanSel == 3) { + if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) { Fans::SimulateFanComponents( FanCoil(FanCoilNum).FanName, FirstHVACIteration, FanCoil(FanCoilNum).FanIndex, 1.0, ZoneCompTurnFansOn, ZoneCompTurnFansOff); } else { - HVACFan::fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate(1.0, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _); + HVACFan::fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate(_, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _); + } + } else { // using 1.0 here for fan speed ratio seems wrong if FCU max flow rate is different than the fan maximum flow rate + if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) { + Fans::SimulateFanComponents( + FanCoil(FanCoilNum).FanName, FirstHVACIteration, FanCoil(FanCoilNum).FanIndex, 0.0, ZoneCompTurnFansOn, ZoneCompTurnFansOff); + } else { + HVACFan::fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate(0.0, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _); } } if (FanCoil(FanCoilNum).CCoilType_Num == CCoil_HXAssist) { diff --git a/tst/EnergyPlus/unit/FanCoilUnits.unit.cc b/tst/EnergyPlus/unit/FanCoilUnits.unit.cc index 66db7d78b88..cc3478e5203 100644 --- a/tst/EnergyPlus/unit/FanCoilUnits.unit.cc +++ b/tst/EnergyPlus/unit/FanCoilUnits.unit.cc @@ -2883,4 +2883,407 @@ TEST_F(EnergyPlusFixture, FanCoil_CyclingFanMode) EXPECT_NEAR(Node(1).MassFlowRate, FanCoil(1).PLR * FanCoil(1).MaxAirMassFlow * FanCoil(1).MedSpeedRatio, 0.0000000001); } +TEST_F(EnergyPlusFixture, FanCoil_FanSystemModelCyclingFanMode) +{ + + int FanCoilNum(1); + int ZoneNum(1); + bool FirstHVACIteration(false); + bool ErrorsFound(false); + Real64 QZnReq(0.0); + Real64 HotWaterMassFlowRate(0.0); + Real64 ColdWaterMassFlowRate(0.0); + Real64 QUnitOut(0.0); + Real64 QLatOut(0.0); + Real64 AirMassFlow(0.0); + Real64 MaxAirMassFlow(0.0); + + DataEnvironment::OutBaroPress = 101325.0; + DataEnvironment::StdRhoAir = 1.20; + WaterCoils::GetWaterCoilsInputFlag = true; + NumCoils = 0; + DataGlobals::NumOfTimeStepInHour = 1; + DataGlobals::TimeStep = 1; + DataGlobals::MinutesPerTimeStep = 60; + DataSizing::CurZoneEqNum = 1; + + InitializePsychRoutines(); + + std::string const idf_objects = delimited_string({ + " Zone,", + " EAST ZONE, !- Name", + " 0, !- Direction of Relative North { deg }", + " 0, !- X Origin { m }", + " 0, !- Y Origin { m }", + " 0, !- Z Origin { m }", + " 1, !- Type", + " 1, !- Multiplier", + " autocalculate, !- Ceiling Height { m }", + " autocalculate; !- Volume { m3 }", + + " ZoneHVAC:EquipmentConnections,", + " EAST ZONE, !- Zone Name", + " Zone1Equipment, !- Zone Conditioning Equipment List Name", + " Zone1Inlets, !- Zone Air Inlet Node or NodeList Name", + " Zone1Exhausts, !- Zone Air Exhaust Node or NodeList Name", + " Zone 1 Node, !- Zone Air Node Name", + " Zone 1 Outlet Node; !- Zone Return Air Node Name", + + " ZoneHVAC:EquipmentList,", + " Zone1Equipment, !- Name", + " SequentialLoad, !- Load Distribution Scheme", + " ZoneHVAC:FourPipeFanCoil, !- Zone Equipment 1 Object Type", + " Zone1FanCoil, !- Zone Equipment 1 Name", + " 1, !- Zone Equipment 1 Cooling Sequence", + " 1; !- Zone Equipment 1 Heating or No - Load Sequence", + + " NodeList,", + " Zone1Inlets, !- Name", + " Zone1FanCoilAirOutletNode;!- Node 1 Name", + + " NodeList,", + " Zone1Exhausts, !- Name", + " Zone1FanCoilAirInletNode; !- Node 1 Name", + + " OutdoorAir:NodeList,", + " Zone1FanCoilOAInNode; !- Node or NodeList Name 1", + + " OutdoorAir:Mixer,", + " Zone1FanCoilOAMixer, !- Name", + " Zone1FanCoilOAMixerOutletNode, !- Mixed Air Node Name", + " Zone1FanCoilOAInNode, !- Outdoor Air Stream Node Name", + " Zone1FanCoilExhNode, !- Relief Air Stream Node Name", + " Zone1FanCoilAirInletNode; !- Return Air Stream Node Name", + + " Schedule:Constant,", + " FanAndCoilAvailSched, !- Name", + " FRACTION, !- Schedule Type", + " 1; !- TimeStep Value", + + " ScheduleTypeLimits,", + " Fraction, !- Name", + " 0.0, !- Lower Limit Value", + " 1.0, !- Upper Limit Value", + " CONTINUOUS; !- Numeric Type", + + " Fan:SystemModel,", + " Zone1FanCoilFan, !- Name", + " FanAndCoilAvailSched, !- Availability Schedule Name", + " Zone1FanCoilOAMixerOutletNode, !- Air Inlet Node Name", + " Zone1FanCoilFanOutletNode, !- Air Outlet Node Name", + " 0.6, !- Design Maximum Air Flow Rate {m3/s}", + " Discrete, !- Speed Control Method", + " 0.0, !- Electric Power Minimum Flow Rate Fraction", + " 75, !- Design Pressure Rise {Pa}", + " 0.9, !- Motor Efficiency", + " 1, !- Motor In Air Stream Fraction", + " , !- Design Electric Power Consumption {W}", + " TotalEfficiencyAndPressure, !- Design Power Sizing Method", + " , !- Electric Power Per Unit Flow Rate {W/(m3/s)}", + " , !- Electric Power Per Unit Flow Rate Per Unit Pressure {W/((m3/s)-Pa)}", + " 0.5, !- Fan Total Efficiency", + " , !- Electric Power Function of Flow Fraction Curve Name", + " , !- Night Ventilation Mode Pressure Rise {Pa}", + " , !- Night Ventilation Mode Flow Fraction", + " , !- Motor Loss Zone Name", + " , !- Motor Loss Radiative Fraction", + " General, !- End-Use Subcategory", + " 1, !- Number of Speeds", + " 1.0, !- Speed 1 Flow Fraction", + " 1.0; !- Speed 1 Electric Power Fraction", + + " Coil:Cooling:Water,", + " Zone1FanCoilCoolingCoil, !- Name", + " FanAndCoilAvailSched, !- Availability Schedule Namev", + " 0.0002, !- Design Water Flow Rate { m3 / s }", + " 0.5000, !- Design Air Flow Rate { m3 / s }", + " 7.22, !- Design Inlet Water Temperature { Cv }", + " 24.340, !- Design Inlet Air Temperature { C }", + " 14.000, !- Design Outlet Air Temperature { C }", + " 0.0095, !- Design Inlet Air Humidity Ratio { kgWater / kgDryAir }", + " 0.0090, !- Design Outlet Air Humidity Ratio { kgWater / kgDryAir }", + " Zone1FanCoilChWInletNode, !- Water Inlet Node Name", + " Zone1FanCoilChWOutletNode,!- Water Outlet Node Name", + " Zone1FanCoilFanOutletNode,!- Air Inlet Node Name", + " Zone1FanCoilCCOutletNode, !- Air Outlet Node Name", + " SimpleAnalysis, !- Type of Analysis", + " CrossFlow; !- Heat Exchanger Configuration", + + " Coil:Heating:Water,", + " Zone1FanCoilHeatingCoil, !- Name", + " FanAndCoilAvailSched, !- Availability Schedule Name", + " 150.0, !- U - Factor Times Area Value { W / K }", + " 0.00014, !- Maximum Water Flow Rate { m3 / s }", + " Zone1FanCoilHWInletNode, !- Water Inlet Node Name", + " Zone1FanCoilHWOutletNode, !- Water Outlet Node Name", + " Zone1FanCoilCCOutletNode, !- Air Inlet Node Name", + " Zone1FanCoilAirOutletNode, !- Air Outlet Node Name", + " UFactorTimesAreaAndDesignWaterFlowRate, !- Performance Input Method", + " autosize, !- Rated Capacity { W }", + " 82.2, !- Rated Inlet Water Temperature { C }", + " 16.6, !- Rated Inlet Air Temperature { C }", + " 71.1, !- Rated Outlet Water Temperature { C }", + " 32.2, !- Rated Outlet Air Temperature { C }", + " ; !- Rated Ratio for Air and Water Convection", + + " ZoneHVAC:FourPipeFanCoil,", + " Zone1FanCoil, !- Name", + " FanAndCoilAvailSched, !- Availability Schedule Name", + " CyclingFan, !- Capacity Control Method", + " 0.5, !- Maximum Supply Air Flow Rate { m3 / s }", + " 0.3, !- Low Speed Supply Air Flow Ratio", + " 0.6, !- Medium Speed Supply Air Flow Ratio", + " 0.0, !- Maximum Outdoor Air Flow Rate { m3 / s }", + " FanAndCoilAvailSched, !- Outdoor Air Schedule Name", + " Zone1FanCoilAirInletNode, !- Air Inlet Node Name", + " Zone1FanCoilAirOutletNode, !- Air Outlet Node Name", + " OutdoorAir:Mixer, !- Outdoor Air Mixer Object Type", + " Zone1FanCoilOAMixer, !- Outdoor Air Mixer Name", + " Fan:SystemModel, !- Supply Air Fan Object Type", + " Zone1FanCoilFan, !- Supply Air Fan Name", + " Coil:Cooling:Water, !- Cooling Coil Object Type", + " Zone1FanCoilCoolingCoil, !- Cooling Coil Name", + " 0.00014, !- Maximum Cold Water Flow Rate { m3 / s }", + " 0.0, !- Minimum Cold Water Flow Rate { m3 / s }", + " 0.001, !- Cooling Convergence Tolerance", + " Coil:Heating:Water, !- Heating Coil Object Type", + " Zone1FanCoilHeatingCoil, !- Heating Coil Name", + " 0.00014, !- Maximum Hot Water Flow Rate { m3 / s }", + " 0.0, !- Minimum Hot Water Flow Rate { m3 / s }", + " 0.001; !- Heating Convergence Tolerance", + + }); + + ASSERT_TRUE(process_idf(idf_objects)); + + GetZoneData(ErrorsFound); + EXPECT_EQ("EAST ZONE", Zone(1).Name); + + GetZoneEquipmentData1(); + ProcessScheduleInput(); + ScheduleInputProcessed = true; + + GetFanCoilUnits(); + + auto &thisFanCoil(FanCoil(1)); + + EXPECT_EQ("CYCLINGFAN", thisFanCoil.CapCtrlMeth); + EXPECT_EQ("OUTDOORAIR:MIXER", thisFanCoil.OAMixType); + EXPECT_EQ("FAN:SYSTEMMODEL", thisFanCoil.FanType); + EXPECT_EQ("COIL:COOLING:WATER", thisFanCoil.CCoilType); + EXPECT_EQ("COIL:HEATING:WATER", thisFanCoil.HCoilType); + EXPECT_EQ(DataHVACGlobals::FanType_SystemModelObject, thisFanCoil.FanType_Num); + + TotNumLoops = 2; + PlantLoop.allocate(TotNumLoops); + + AirMassFlow = 0.60; + MaxAirMassFlow = 0.60; + ColdWaterMassFlowRate = 1.0; + HotWaterMassFlowRate = 1.0; + + thisFanCoil.OutAirMassFlow = 0.0; + thisFanCoil.MaxAirMassFlow = MaxAirMassFlow; + Node(thisFanCoil.OutsideAirNode).MassFlowRateMax = 0.0; + + Node(thisFanCoil.AirInNode).MassFlowRate = AirMassFlow; + Node(thisFanCoil.AirInNode).MassFlowRateMin = AirMassFlow; + Node(thisFanCoil.AirInNode).MassFlowRateMinAvail = AirMassFlow; + Node(thisFanCoil.AirInNode).MassFlowRateMax = MaxAirMassFlow; + Node(thisFanCoil.AirInNode).MassFlowRateMaxAvail = MaxAirMassFlow; + + // outside air mixer + auto &MixerOA(OAMixer(1)); + Node(MixerOA.RetNode).MassFlowRate = AirMassFlow; + Node(MixerOA.RetNode).MassFlowRateMax = MaxAirMassFlow; + Node(MixerOA.RetNode).Temp = 22.0; + Node(MixerOA.RetNode).Enthalpy = 36000; + Node(MixerOA.RetNode).HumRat = PsyWFnTdbH(Node(MixerOA.RetNode).Temp, Node(MixerOA.RetNode).Enthalpy); + Node(MixerOA.InletNode).Temp = 10.0; + Node(MixerOA.InletNode).Enthalpy = 18000; + Node(MixerOA.InletNode).HumRat = PsyWFnTdbH(Node(MixerOA.InletNode).Temp, Node(MixerOA.InletNode).Enthalpy); + + // chilled water coil + auto &CWCoil(WaterCoil(2)); + CWCoil.UACoilTotal = 470.0; + CWCoil.UACoilExternal = 611.0; + CWCoil.UACoilInternal = 2010.0; + CWCoil.TotCoilOutsideSurfArea = 50.0; + Node(CWCoil.AirInletNodeNum).MassFlowRate = AirMassFlow; + Node(CWCoil.AirInletNodeNum).MassFlowRateMin = AirMassFlow; + Node(CWCoil.AirInletNodeNum).MassFlowRateMax = AirMassFlow; + Node(CWCoil.AirInletNodeNum).MassFlowRateMaxAvail = AirMassFlow; + CWCoil.InletWaterMassFlowRate = ColdWaterMassFlowRate; + CWCoil.MaxWaterMassFlowRate = ColdWaterMassFlowRate; + Node(CWCoil.WaterInletNodeNum).MassFlowRate = ColdWaterMassFlowRate; + Node(CWCoil.WaterInletNodeNum).MassFlowRateMaxAvail = ColdWaterMassFlowRate; + Node(CWCoil.WaterInletNodeNum).Temp = 6.0; + Node(CWCoil.WaterOutletNodeNum).MassFlowRate = ColdWaterMassFlowRate; + Node(CWCoil.WaterOutletNodeNum).MassFlowRateMaxAvail = ColdWaterMassFlowRate; + CWCoil.WaterLoopNum = 1; + CWCoil.WaterLoopSide = 1; + CWCoil.WaterLoopBranchNum = 1; + CWCoil.WaterLoopCompNum = 1; + + // hot water coil + auto &HWCoil(WaterCoil(1)); + HWCoil.InletWaterMassFlowRate = HotWaterMassFlowRate; + HWCoil.MaxWaterMassFlowRate = HotWaterMassFlowRate; + Node(HWCoil.AirInletNodeNum).MassFlowRate = AirMassFlow; + Node(HWCoil.AirInletNodeNum).MassFlowRateMaxAvail = AirMassFlow; + Node(HWCoil.WaterInletNodeNum).Temp = 60.0; + Node(HWCoil.WaterInletNodeNum).MassFlowRate = HotWaterMassFlowRate; + Node(HWCoil.WaterInletNodeNum).MassFlowRateMaxAvail = HotWaterMassFlowRate; + Node(HWCoil.WaterOutletNodeNum).MassFlowRate = HotWaterMassFlowRate; + Node(HWCoil.WaterOutletNodeNum).MassFlowRateMaxAvail = HotWaterMassFlowRate; + HWCoil.WaterLoopNum = 2; + HWCoil.WaterLoopSide = 1; + HWCoil.WaterLoopBranchNum = 1; + HWCoil.WaterLoopCompNum = 1; + + for (int l = 1; l <= TotNumLoops; ++l) { + auto &loop(PlantLoop(l)); + loop.LoopSide.allocate(2); + auto &loopside(PlantLoop(l).LoopSide(1)); + loopside.TotalBranches = 1; + loopside.Branch.allocate(1); + auto &loopsidebranch(PlantLoop(l).LoopSide(1).Branch(1)); + loopsidebranch.TotalComponents = 1; + loopsidebranch.Comp.allocate(1); + } + // chilled water plant loop + auto &CWLoop(PlantLoop(2)); + CWLoop.Name = "ChilledWaterLoop"; + CWLoop.FluidName = "ChilledWater"; + CWLoop.FluidIndex = 1; + CWLoop.FluidName = "WATER"; + CWLoop.LoopSide(1).Branch(1).Comp(1).Name = CWCoil.Name; + CWLoop.LoopSide(1).Branch(1).Comp(1).TypeOf_Num = WaterCoil_Cooling; + CWLoop.LoopSide(1).Branch(1).Comp(1).NodeNumIn = CWCoil.WaterInletNodeNum; + CWLoop.LoopSide(1).Branch(1).Comp(1).NodeNumOut = CWCoil.WaterOutletNodeNum; + // hot water plant loop + auto &HWLoop(PlantLoop(1)); + HWLoop.Name = "HotWaterLoop"; + HWLoop.FluidName = "HotWater"; + HWLoop.FluidIndex = 1; + HWLoop.FluidName = "WATER"; + HWLoop.LoopSide(1).Branch(1).Comp(1).Name = HWCoil.Name; + HWLoop.LoopSide(1).Branch(1).Comp(1).TypeOf_Num = WaterCoil_SimpleHeating; + HWLoop.LoopSide(1).Branch(1).Comp(1).NodeNumIn = HWCoil.WaterInletNodeNum; + HWLoop.LoopSide(1).Branch(1).Comp(1).NodeNumOut = HWCoil.WaterOutletNodeNum; + + // heating mode tests + CoolingLoad = false; + HeatingLoad = true; + ZoneSysEnergyDemand.allocate(1); + ZoneSysEnergyDemand(1).RemainingOutputReqToCoolSP = 0; + ZoneSysEnergyDemand(1).RemainingOutputReqToHeatSP = 4000.0; + ZoneSysEnergyDemand(1).RemainingOutputRequired = 4000.0; + thisFanCoil.SpeedFanSel = 2; + QUnitOut = 0.0; + QLatOut = 0.0; + QZnReq = 4000.0; + + MyUAAndFlowCalcFlag.allocate(2); + MyUAAndFlowCalcFlag(1) = true; + MyUAAndFlowCalcFlag(2) = true; + DataGlobals::DoingSizing = true; + + LocalTurnFansOff = false; + LocalTurnFansOn = true; + + DataEnvironment::Month = 1; + DataEnvironment::DayOfMonth = 21; + DataGlobals::HourOfDay = 1; + DataEnvironment::DSTIndicator = 0; + DataEnvironment::DayOfWeek = 2; + DataEnvironment::HolidayIndex = 0; + DataEnvironment::DayOfYear_Schedule = General::OrdinalDay(Month, DayOfMonth, 1); + UpdateScheduleValues(); + + ZoneEqSizing.allocate(1); + CurDeadBandOrSetback.allocate(1); + CurDeadBandOrSetback(1) = false; + TempControlType.allocate(1); + TempControlType(1) = 4; + ZoneSizingRunDone = true; + FinalZoneSizing.allocate(1); + FinalZoneSizing(CurZoneEqNum).DesCoolVolFlow = 0.5; + FinalZoneSizing(CurZoneEqNum).DesHeatVolFlow = 0.5; + FinalZoneSizing(CurZoneEqNum).DesCoolCoilInTemp = 30.0; + FinalZoneSizing(CurZoneEqNum).DesCoolCoilInHumRat = 0.01; + FinalZoneSizing(CurZoneEqNum).DesHeatCoilInTemp = 20.0; + FinalZoneSizing(CurZoneEqNum).DesHeatCoilInHumRat = 0.005; + FinalZoneSizing(CurZoneEqNum).DesCoolLoad = 4000.0; + FinalZoneSizing(CurZoneEqNum).DesHeatLoad = 4000.0; + StdRhoAir = 1.2; + + BeginEnvrnFlag = true; + InitFanCoilUnits(FanCoilNum, ZoneNum, ZoneNum); + Sim4PipeFanCoil(FanCoilNum, ZoneNum, ZoneNum, FirstHVACIteration, QUnitOut, QLatOut); + // expect fan speed 3 and near full air and water flow and meet capacity + EXPECT_EQ(thisFanCoil.SpeedFanSel, 3); + EXPECT_NEAR(thisFanCoil.PLR, 0.970, 0.001); + EXPECT_NEAR(QZnReq, QUnitOut, 5.0); + // cycling fan proportional to PLR and fan speed ratio + EXPECT_NEAR(Node(1).MassFlowRate, thisFanCoil.PLR * thisFanCoil.MaxAirMassFlow, 0.0000000001); + // expect minimum flow and meet capacity + ZoneSysEnergyDemand(1).RemainingOutputReqToHeatSP = 1000.0; + ZoneSysEnergyDemand(1).RemainingOutputRequired = 1000.0; + QZnReq = 1000.0; + Sim4PipeFanCoil(FanCoilNum, ZoneNum, ZoneNum, FirstHVACIteration, QUnitOut, QLatOut); + // expect fan speed 1 and moderate air and water flow and meet capacity + EXPECT_EQ(thisFanCoil.SpeedFanSel, 1); + EXPECT_NEAR(thisFanCoil.PLR, 0.636, 0.001); + EXPECT_NEAR(QZnReq, QUnitOut, 5.0); + // cycling fan proportional to PLR and fan speed ratio + EXPECT_NEAR(Node(1).MassFlowRate, thisFanCoil.PLR * thisFanCoil.MaxAirMassFlow * thisFanCoil.LowSpeedRatio, 0.0000000001); + // expect modulated flow and meet capacity + ZoneSysEnergyDemand(1).RemainingOutputReqToHeatSP = 2500.0; + ZoneSysEnergyDemand(1).RemainingOutputRequired = 2500.0; + QZnReq = 2500.0; + Sim4PipeFanCoil(FanCoilNum, ZoneNum, ZoneNum, FirstHVACIteration, QUnitOut, QLatOut); + // expect fan speed 2 and moderate air and water flow and meet capacity + EXPECT_EQ(thisFanCoil.SpeedFanSel, 2); + EXPECT_NEAR(thisFanCoil.PLR, 0.856, 0.001); + EXPECT_NEAR(QZnReq, QUnitOut, 5.0); + // cycling fan proportional to PLR and fan speed ratio + EXPECT_NEAR(Node(1).MassFlowRate, thisFanCoil.PLR * thisFanCoil.MaxAirMassFlow * thisFanCoil.MedSpeedRatio, 0.0000000001); + + // cooling mode tests + // expect full flow and meet capacity + ZoneSysEnergyDemand(1).RemainingOutputReqToHeatSP = 0.0; + ZoneSysEnergyDemand(1).RemainingOutputReqToCoolSP = -4000.0; + ZoneSysEnergyDemand(1).RemainingOutputRequired = -4000.0; + QZnReq = -4000.0; + Sim4PipeFanCoil(FanCoilNum, ZoneNum, ZoneNum, FirstHVACIteration, QUnitOut, QLatOut); + // expect fan speed 3 and near full air and water flow and meet capacity + EXPECT_EQ(3, FanCoil(1).SpeedFanSel); + EXPECT_NEAR(FanCoil(1).PLR, 0.941, 0.001); + EXPECT_NEAR(QZnReq, QUnitOut, 5.0); + // cycling fan proportional to PLR and fan speed ratio + EXPECT_NEAR(Node(1).MassFlowRate, thisFanCoil.PLR * thisFanCoil.MaxAirMassFlow, 0.0000000001); + // expect minimum flow and meet capacity + ZoneSysEnergyDemand(1).RemainingOutputReqToCoolSP = -1000.0; + ZoneSysEnergyDemand(1).RemainingOutputRequired = -1000.0; + QZnReq = -1000.0; + Sim4PipeFanCoil(FanCoilNum, ZoneNum, ZoneNum, FirstHVACIteration, QUnitOut, QLatOut); + // expect fan speed 1 and moderate air and water flow and meet capacity + EXPECT_EQ(1, FanCoil(1).SpeedFanSel); + EXPECT_NEAR(FanCoil(1).PLR, 0.500, 0.001); + EXPECT_NEAR(QZnReq, QUnitOut, 5.0); + // cycling fan proportional to PLR and fan speed ratio + EXPECT_NEAR(Node(1).MassFlowRate, thisFanCoil.PLR * thisFanCoil.MaxAirMassFlow * thisFanCoil.LowSpeedRatio, 0.0000000001); + // expect modulated flow and meet capacity + ZoneSysEnergyDemand(1).RemainingOutputReqToCoolSP = -2500.0; + ZoneSysEnergyDemand(1).RemainingOutputRequired = -2500.0; + QZnReq = -2500.0; + Sim4PipeFanCoil(FanCoilNum, ZoneNum, ZoneNum, FirstHVACIteration, QUnitOut, QLatOut); + // expect fan speed 2 and moderate air and water flow and meet capacity + EXPECT_EQ(2, FanCoil(1).SpeedFanSel); + EXPECT_NEAR(FanCoil(1).PLR, 0.753, 0.001); + EXPECT_NEAR(QZnReq, QUnitOut, 5.0); + EXPECT_NEAR(Node(1).MassFlowRate, thisFanCoil.PLR * thisFanCoil.MaxAirMassFlow * thisFanCoil.MedSpeedRatio, 0.0000000001); +} + } // namespace EnergyPlus