LCOV - code coverage report
Current view: top level - EnergyPlus - FanCoilUnits.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 54.7 % 2545 1392
Test Date: 2025-05-22 16:09:37 Functions: 90.0 % 30 27

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cmath>
      50              : 
      51              : // ObjexxFCL Headers
      52              : #include <ObjexxFCL/Array.functions.hh>
      53              : #include <ObjexxFCL/Fmath.hh>
      54              : 
      55              : // EnergyPlus Headers
      56              : #include <EnergyPlus/Autosizing/All_Simple_Sizing.hh>
      57              : #include <EnergyPlus/Autosizing/CoolingAirFlowSizing.hh>
      58              : #include <EnergyPlus/Autosizing/CoolingCapacitySizing.hh>
      59              : #include <EnergyPlus/Autosizing/HeatingAirFlowSizing.hh>
      60              : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
      61              : #include <EnergyPlus/Autosizing/SystemAirFlowSizing.hh>
      62              : #include <EnergyPlus/BranchNodeConnections.hh>
      63              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      64              : #include <EnergyPlus/DataAirSystems.hh>
      65              : #include <EnergyPlus/DataEnvironment.hh>
      66              : #include <EnergyPlus/DataHVACGlobals.hh>
      67              : #include <EnergyPlus/DataHeatBalFanSys.hh>
      68              : #include <EnergyPlus/DataHeatBalance.hh>
      69              : #include <EnergyPlus/DataLoopNode.hh>
      70              : #include <EnergyPlus/DataPrecisionGlobals.hh>
      71              : #include <EnergyPlus/DataSizing.hh>
      72              : #include <EnergyPlus/DataZoneEnergyDemands.hh>
      73              : #include <EnergyPlus/DataZoneEquipment.hh>
      74              : #include <EnergyPlus/FanCoilUnits.hh>
      75              : #include <EnergyPlus/Fans.hh>
      76              : #include <EnergyPlus/FluidProperties.hh>
      77              : #include <EnergyPlus/GeneralRoutines.hh>
      78              : #include <EnergyPlus/HVACHXAssistedCoolingCoil.hh>
      79              : #include <EnergyPlus/HeatingCoils.hh>
      80              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      81              : #include <EnergyPlus/MixedAir.hh>
      82              : #include <EnergyPlus/NodeInputManager.hh>
      83              : #include <EnergyPlus/OutputProcessor.hh>
      84              : #include <EnergyPlus/Plant/DataPlant.hh>
      85              : #include <EnergyPlus/PlantUtilities.hh>
      86              : #include <EnergyPlus/Psychrometrics.hh>
      87              : #include <EnergyPlus/ReportCoilSelection.hh>
      88              : #include <EnergyPlus/SZVAVModel.hh>
      89              : #include <EnergyPlus/ScheduleManager.hh>
      90              : #include <EnergyPlus/SingleDuct.hh>
      91              : #include <EnergyPlus/UtilityRoutines.hh>
      92              : #include <EnergyPlus/WaterCoils.hh>
      93              : #include <EnergyPlus/ZoneEquipmentManager.hh>
      94              : #include <EnergyPlus/ZonePlenum.hh>
      95              : 
      96              : namespace EnergyPlus {
      97              : 
      98              : namespace FanCoilUnits {
      99              : 
     100              :     // Module containing the routines dealing with 2 and 4 pipe fan coil units
     101              : 
     102              :     // MODULE INFORMATION:
     103              :     //       AUTHOR         Fred Buhl
     104              :     //       DATE WRITTEN   March 2000
     105              :     //       MODIFIED       October 2003 (FSEC added cooling coil type)
     106              :     //                      June 2010    Arnaud Flament LBNL added 3-speed and variables-speed fan capacity control;
     107              :     //                                   outside air schedule; and removed coil water inlet node inputs
     108              :     //                      Sept 2010    Brent Griffith, plant upgrades for water coils, fluid properties
     109              : 
     110              :     // PURPOSE OF THIS MODULE:
     111              :     // To encapsulate the data and algorithms needed to simulate 2 and 4 pipe
     112              :     // fan coil units.
     113              : 
     114              :     // METHODOLOGY EMPLOYED:
     115              :     // Units are modeled as a collection of components: outside air mixer,
     116              :     // fan, heating coil and/or cooling coil plus an integrated control
     117              :     // algorithm that adjusts the hot or cold water flow to meet the zone
     118              :     // load. Or varies the air flow rate to meet the zone load. Or both.
     119              : 
     120        20300 :     void SimFanCoilUnit(EnergyPlusData &state,
     121              :                         std::string_view CompName,     // name of the fan coil unit
     122              :                         int const ControlledZoneNum,   // number of zone being served
     123              :                         bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
     124              :                         Real64 &PowerMet,              // Sensible power supplied (W)
     125              :                         Real64 &LatOutputProvided,     // Latent add/removal supplied by window AC (kg/s), dehumid = negative
     126              :                         int &CompIndex)
     127              :     {
     128              : 
     129              :         // SUBROUTINE INFORMATION:
     130              :         //       AUTHOR         Fred Buhl
     131              :         //       DATE WRITTEN   March 2000
     132              :         //       MODIFIED       Don Shirey, Aug 2009 (LatOutputProvided)
     133              : 
     134              :         // PURPOSE OF THIS SUBROUTINE:
     135              :         // Manages the simulation of a fan coil unit. Called from SimZone Equipment
     136              : 
     137              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     138              :         int FanCoilNum; // index of fan coil unit being simulated
     139              : 
     140              :         // First time SimFanCoilUnit is called, get the input for all the fan coil units
     141        20300 :         if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
     142            1 :             GetFanCoilUnits(state);
     143            1 :             state.dataFanCoilUnits->GetFanCoilInputFlag = false;
     144              :         }
     145              : 
     146              :         // Find the correct Fan Coil Equipment
     147        20300 :         if (CompIndex == 0) {
     148            5 :             FanCoilNum = Util::FindItemInList(CompName, state.dataFanCoilUnits->FanCoil);
     149            5 :             if (FanCoilNum == 0) {
     150            0 :                 ShowFatalError(state, format("SimFanCoil: Unit not found={}", CompName));
     151              :             }
     152            5 :             CompIndex = FanCoilNum;
     153              :         } else {
     154        20295 :             FanCoilNum = CompIndex;
     155        20295 :             if (FanCoilNum > state.dataFanCoilUnits->NumFanCoils || FanCoilNum < 1) {
     156            0 :                 ShowFatalError(state,
     157            0 :                                format("SimFanCoil:  Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
     158              :                                       FanCoilNum,
     159            0 :                                       state.dataFanCoilUnits->NumFanCoils,
     160              :                                       CompName));
     161              :             }
     162        20295 :             if (state.dataFanCoilUnits->CheckEquipName(FanCoilNum)) {
     163            5 :                 if (CompName != state.dataFanCoilUnits->FanCoil(FanCoilNum).Name) {
     164            0 :                     ShowFatalError(state,
     165            0 :                                    format("SimFanCoil: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
     166              :                                           FanCoilNum,
     167              :                                           CompName,
     168            0 :                                           state.dataFanCoilUnits->FanCoil(FanCoilNum).Name));
     169              :                 }
     170            5 :                 state.dataFanCoilUnits->CheckEquipName(FanCoilNum) = false;
     171              :             }
     172              :         }
     173              : 
     174        20300 :         state.dataSize->ZoneEqFanCoil = true;
     175              : 
     176              :         // Initialize the fan coil unit
     177        20300 :         InitFanCoilUnits(state, FanCoilNum, ControlledZoneNum);
     178              : 
     179              :         // Select the correct unit type
     180        20300 :         if (state.dataFanCoilUnits->FanCoil(FanCoilNum).UnitType_Num == FanCoilUnit_4Pipe) {
     181        20300 :             Sim4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, PowerMet, LatOutputProvided);
     182              :         }
     183              : 
     184              :         // Report the result of the simulation
     185        20300 :         ReportFanCoilUnit(state, FanCoilNum);
     186              : 
     187        20300 :         state.dataSize->ZoneEqFanCoil = false;
     188        20300 :     }
     189              : 
     190           18 :     void GetFanCoilUnits(EnergyPlusData &state)
     191              :     {
     192              : 
     193              :         // SUBROUTINE INFORMATION:
     194              :         //       AUTHOR         Fred Buhl
     195              :         //       DATE WRITTEN   March 2000
     196              :         //       MODIFIED       Bereket Nigusse, FSEC, April 2011: eliminated input node names
     197              :         //                                                         added OA Mixer object type
     198              :         //                                                         and fan object type
     199              :         //                      Chandan Sharma, FSEC, July 2012: Added zone sys avail managers
     200              : 
     201              :         // PURPOSE OF THIS SUBROUTINE:
     202              :         // Obtains input data for fan coil units and stores it in fan coil data structures
     203              : 
     204              :         // METHODOLOGY EMPLOYED:
     205              :         // Uses "Get" routines to read in data.
     206              : 
     207              :         // Locals
     208              :         // SUBROUTINE ARGUMENT DEFINITIONS:
     209              :         static constexpr std::string_view RoutineName("GetFanCoilUnits: "); // include trailing blank space
     210              :         static constexpr std::string_view routineName = "GetFanCoilUnits";
     211              : 
     212              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     213              :         int NumAlphas;                 // Number of Alphas for each GetObjectItem call
     214              :         int NumNumbers;                // Number of Numbers for each GetObjectItem call
     215           18 :         Array1D_int OANodeNums(4);     // Node numbers of Outdoor air mixer (OA, EA, RA, MA)
     216              :         int IOStatus;                  // Used in GetObjectItem
     217              :         bool IsNotOK;                  // Flag to verify name
     218           18 :         Array1D_string Alphas;         // Alpha input items for object
     219           18 :         Array1D_string cAlphaFields;   // Alpha field names
     220           18 :         Array1D_string cNumericFields; // Numeric field names
     221           18 :         Array1D<Real64> Numbers;       // Numeric input items for object
     222           18 :         Array1D_bool lAlphaBlanks;     // Logical array, alpha field input BLANK = .TRUE.
     223           18 :         Array1D_bool lNumericBlanks;   // Logical array, numeric field input BLANK = .TRUE.
     224              :         int NodeNum;                   // index to loop counter
     225           18 :         std::string ATMixerName;
     226              : 
     227           18 :         auto &ErrorsFound = state.dataFanCoilUnits->ErrorsFound;
     228           18 :         bool &errFlag = state.dataFanCoilUnits->errFlag;
     229              : 
     230              :         // find the number of each type of fan coil unit
     231              : 
     232           18 :         std::string CurrentModuleObject = state.dataFanCoilUnits->cMO_FanCoil;
     233           18 :         state.dataFanCoilUnits->Num4PipeFanCoils = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     234           18 :         state.dataFanCoilUnits->NumFanCoils = state.dataFanCoilUnits->Num4PipeFanCoils;
     235              :         // allocate the data structures
     236           18 :         state.dataFanCoilUnits->FanCoil.allocate(state.dataFanCoilUnits->NumFanCoils);
     237           18 :         state.dataFanCoilUnits->FanCoilNumericFields.allocate(state.dataFanCoilUnits->NumFanCoils);
     238           18 :         state.dataFanCoilUnits->CheckEquipName.dimension(state.dataFanCoilUnits->NumFanCoils, true);
     239              : 
     240           36 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
     241           18 :             state, CurrentModuleObject, state.dataFanCoilUnits->TotalArgs, NumAlphas, NumNumbers);
     242           18 :         Alphas.allocate(NumAlphas);
     243           18 :         cAlphaFields.allocate(NumAlphas);
     244           18 :         cNumericFields.allocate(NumNumbers);
     245           18 :         Numbers.dimension(NumNumbers, 0.0);
     246           18 :         lAlphaBlanks.dimension(NumAlphas, true);
     247           18 :         lNumericBlanks.dimension(NumNumbers, true);
     248              : 
     249              :         // loop over 4 pipe fan coil units; get and load the input data
     250           40 :         for (int FanCoilIndex = 1; FanCoilIndex <= state.dataFanCoilUnits->Num4PipeFanCoils; ++FanCoilIndex) {
     251           22 :             auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilIndex);
     252              : 
     253           22 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     254              :                                                                      CurrentModuleObject,
     255              :                                                                      FanCoilIndex,
     256              :                                                                      Alphas,
     257              :                                                                      NumAlphas,
     258              :                                                                      Numbers,
     259              :                                                                      NumNumbers,
     260              :                                                                      IOStatus,
     261              :                                                                      lNumericBlanks,
     262              :                                                                      lAlphaBlanks,
     263              :                                                                      cAlphaFields,
     264              :                                                                      cNumericFields);
     265              : 
     266           22 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     267              : 
     268           22 :             state.dataFanCoilUnits->FanCoilNumericFields(FanCoilIndex).FieldNames.allocate(NumNumbers);
     269           22 :             state.dataFanCoilUnits->FanCoilNumericFields(FanCoilIndex).FieldNames = "";
     270           22 :             state.dataFanCoilUnits->FanCoilNumericFields(FanCoilIndex).FieldNames = cNumericFields;
     271              : 
     272           22 :             fanCoil.Name = Alphas(1);
     273           22 :             fanCoil.UnitType = CurrentModuleObject;
     274           22 :             fanCoil.UnitType_Num = FanCoilUnit_4Pipe;
     275              : 
     276           22 :             if (lAlphaBlanks(2)) {
     277            0 :                 fanCoil.availSched = Sched::GetScheduleAlwaysOn(state);
     278           22 :             } else if ((fanCoil.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
     279            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
     280            0 :                 ErrorsFound = true;
     281              :             }
     282           22 :             constexpr std::array<std::string_view, static_cast<int>(CCM::Num)> CapCtrlMethUC{"CONSTANTFANVARIABLEFLOW",
     283              :                                                                                              "CYCLINGFAN",
     284              :                                                                                              "VARIABLEFANVARIABLEFLOW",
     285              :                                                                                              "VARIABLEFANCONSTANTFLOW",
     286              :                                                                                              "MULTISPEEDFAN",
     287              :                                                                                              "ASHRAE90VARIABLEFAN"};
     288           22 :             std::string capCtrlMeth = Alphas(3);
     289           22 :             fanCoil.CapCtrlMeth_Num = static_cast<CCM>(getEnumValue(CapCtrlMethUC, capCtrlMeth));
     290           22 :             if (fanCoil.CapCtrlMeth_Num == CCM::ASHRAE) {
     291            3 :                 fanCoil.DesZoneCoolingLoad = DataSizing::AutoSize;
     292            3 :                 fanCoil.DesZoneHeatingLoad = DataSizing::AutoSize;
     293            3 :                 fanCoil.fanOp = HVAC::FanOp::Continuous;
     294              :             }
     295              : 
     296           22 :             if (!lAlphaBlanks(4) && ((fanCoil.oaSched = Sched::GetSchedule(state, Alphas(4))) == nullptr)) {
     297            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(4), Alphas(4));
     298            0 :                 ErrorsFound = true;
     299              :             }
     300           22 :             fanCoil.MaxAirVolFlow = Numbers(1);
     301           22 :             fanCoil.LowSpeedRatio = Numbers(2);
     302           22 :             fanCoil.MedSpeedRatio = Numbers(3);
     303              :             // check if low speed ratio < medium speed ratio, if not : warning & set to default values
     304           22 :             if (fanCoil.LowSpeedRatio > fanCoil.MedSpeedRatio) {
     305            0 :                 ShowWarningError(state, format("{}{}=\"{}\",", RoutineName, CurrentModuleObject, fanCoil.Name));
     306            0 :                 ShowContinueError(state, format("... {} is greater than the medium speed supply air flow ratio.", cNumericFields(2)));
     307            0 :                 ShowContinueError(state, format("... Fan Coil Unit low speed supply air flow ratio = {:.5T} ", fanCoil.LowSpeedRatio));
     308            0 :                 ShowContinueError(state, format("... Fan Coit Unit medium speed supply air flow ratio = {:.5T} ", fanCoil.MedSpeedRatio));
     309            0 :                 ShowContinueError(state,
     310              :                                   "... Fan Coil Unit low speed supply air flow ratio and medium speed supply air flow ratio set to default values");
     311            0 :                 fanCoil.LowSpeedRatio = 1.0 / 3.0;
     312            0 :                 fanCoil.MedSpeedRatio = 2.0 / 3.0;
     313              :             }
     314              : 
     315           22 :             fanCoil.OutAirVolFlow = Numbers(4);
     316              : 
     317           22 :             fanCoil.AirInNode = NodeInputManager::GetOnlySingleNode(state,
     318           22 :                                                                     Alphas(5),
     319              :                                                                     ErrorsFound,
     320              :                                                                     DataLoopNode::ConnectionObjectType::ZoneHVACFourPipeFanCoil,
     321           22 :                                                                     Alphas(1),
     322              :                                                                     DataLoopNode::NodeFluidType::Air,
     323              :                                                                     DataLoopNode::ConnectionType::Inlet,
     324              :                                                                     NodeInputManager::CompFluidStream::Primary,
     325              :                                                                     DataLoopNode::ObjectIsParent); // air input node
     326              : 
     327           22 :             fanCoil.AirOutNode = NodeInputManager::GetOnlySingleNode(state,
     328           22 :                                                                      Alphas(6),
     329              :                                                                      ErrorsFound,
     330              :                                                                      DataLoopNode::ConnectionObjectType::ZoneHVACFourPipeFanCoil,
     331           22 :                                                                      Alphas(1),
     332              :                                                                      DataLoopNode::NodeFluidType::Air,
     333              :                                                                      DataLoopNode::ConnectionType::Outlet,
     334              :                                                                      NodeInputManager::CompFluidStream::Primary,
     335              :                                                                      DataLoopNode::ObjectIsParent); // air outlet node
     336              : 
     337           22 :             fanCoil.OAMixType = Alphas(7);
     338           22 :             fanCoil.OAMixName = Alphas(8);
     339              :             // check to see if local OA mixer specified
     340           22 :             if (!lAlphaBlanks(8)) {
     341           20 :                 errFlag = false;
     342           20 :                 ValidateComponent(state, fanCoil.OAMixType, fanCoil.OAMixName, errFlag, CurrentModuleObject);
     343           20 :                 if (errFlag) {
     344            0 :                     ShowContinueError(state, format("specified in {} = \"{}\".", CurrentModuleObject, fanCoil.Name));
     345            0 :                     ErrorsFound = true;
     346              :                 } else {
     347              :                     // Get outdoor air mixer node numbers
     348           20 :                     OANodeNums = MixedAir::GetOAMixerNodeNumbers(state, fanCoil.OAMixName, errFlag);
     349           20 :                     if (errFlag) {
     350            0 :                         ShowContinueError(state, format("that was specified in {} = {}", CurrentModuleObject, fanCoil.Name));
     351            0 :                         ShowContinueError(state, "..OutdoorAir:Mixer is required. Enter an OutdoorAir:Mixer object with this name.");
     352            0 :                         ErrorsFound = true;
     353              :                     } else {
     354           20 :                         fanCoil.OutsideAirNode = OANodeNums(1);
     355           20 :                         fanCoil.AirReliefNode = OANodeNums(2);
     356           20 :                         fanCoil.MixedAirNode = OANodeNums(4);
     357              :                     }
     358              :                 }
     359              :             }
     360              : 
     361           22 :             fanCoil.CCoilName = Alphas(12);
     362           22 :             fanCoil.MaxColdWaterVolFlow = Numbers(5);
     363           22 :             fanCoil.MinColdWaterVolFlow = Numbers(6);
     364           22 :             fanCoil.ColdControlOffset = Numbers(7);
     365           22 :             fanCoil.HCoilName = Alphas(14);
     366           22 :             fanCoil.HCoilType = Alphas(13);
     367           22 :             fanCoil.MaxHotWaterVolFlow = Numbers(8);
     368           22 :             fanCoil.MinHotWaterVolFlow = Numbers(9);
     369           22 :             fanCoil.HotControlOffset = Numbers(10);
     370              : 
     371           22 :             if (Util::SameString(Alphas(11), "Coil:Cooling:Water") || Util::SameString(Alphas(11), "Coil:Cooling:Water:DetailedGeometry") ||
     372           22 :                 Util::SameString(Alphas(11), "CoilSystem:Cooling:Water:HeatExchangerAssisted")) {
     373           22 :                 fanCoil.CCoilType = Alphas(11);
     374           22 :                 if (Util::SameString(Alphas(11), "Coil:Cooling:Water")) {
     375           22 :                     fanCoil.CCoilType_Num = CCoil::Water;
     376           22 :                     fanCoil.CCoilPlantName = fanCoil.CCoilName;
     377           22 :                     fanCoil.CCoilPlantType = DataPlant::PlantEquipmentType::CoilWaterCooling;
     378              :                 }
     379           22 :                 if (Util::SameString(Alphas(11), "Coil:Cooling:Water:DetailedGeometry")) {
     380            0 :                     fanCoil.CCoilType_Num = CCoil::Detailed;
     381            0 :                     fanCoil.CCoilPlantName = fanCoil.CCoilName;
     382            0 :                     fanCoil.CCoilPlantType = DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling;
     383              :                 }
     384           22 :                 std::string CCoilType;
     385           22 :                 if (Util::SameString(Alphas(11), "CoilSystem:Cooling:Water:HeatExchangerAssisted")) {
     386            0 :                     fanCoil.CCoilType_Num = CCoil::HXAssist;
     387            0 :                     HVACHXAssistedCoolingCoil::GetHXCoilTypeAndName(
     388            0 :                         state, fanCoil.CCoilType, fanCoil.CCoilName, ErrorsFound, CCoilType, fanCoil.CCoilPlantName);
     389            0 :                     if (Util::SameString(CCoilType, "Coil:Cooling:Water")) {
     390            0 :                         fanCoil.CCoilPlantType = DataPlant::PlantEquipmentType::CoilWaterCooling;
     391            0 :                     } else if (Util::SameString(CCoilType, "Coil:Cooling:Water:DetailedGeometry")) {
     392            0 :                         fanCoil.CCoilPlantType = DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling;
     393              :                     } else {
     394            0 :                         ShowSevereError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, fanCoil.Name));
     395            0 :                         ShowContinueError(state, format("For: {}=\"{}\".", cAlphaFields(11), Alphas(11)));
     396            0 :                         ShowContinueError(state, format("Invalid Coil Type={}, Name={}", CCoilType, fanCoil.CCoilPlantName));
     397            0 :                         ShowContinueError(state, "must be \"Coil:Cooling:Water\" or \"Coil:Cooling:Water:DetailedGeometry\"");
     398            0 :                         ErrorsFound = true;
     399              :                     }
     400              :                 }
     401           22 :                 IsNotOK = false;
     402           22 :                 ValidateComponent(state, fanCoil.CCoilType, fanCoil.CCoilName, IsNotOK, fanCoil.UnitType);
     403           22 :                 if (IsNotOK) {
     404            0 :                     ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, fanCoil.Name));
     405            0 :                     ErrorsFound = true;
     406              :                 } else {
     407           22 :                     if (fanCoil.CCoilType_Num != CCoil::HXAssist) {
     408              :                         // mine the cold water node from the coil object
     409           22 :                         int coilIndex = WaterCoils::GetWaterCoilIndex(state, fanCoil.CCoilType, fanCoil.CCoilName, IsNotOK);
     410              :                         // Other error checks should trap before it gets to this point in the code, but including just in case.
     411           22 :                         if (IsNotOK) {
     412            0 :                             ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, fanCoil.Name));
     413            0 :                             ErrorsFound = true;
     414              :                         } else {
     415           22 :                             fanCoil.CoolCoilFluidInletNode = state.dataWaterCoils->WaterCoil(coilIndex).WaterInletNodeNum;
     416           22 :                             fanCoil.CoolCoilInletNodeNum = state.dataWaterCoils->WaterCoil(coilIndex).AirInletNodeNum;
     417           22 :                             fanCoil.CoolCoilOutletNodeNum = state.dataWaterCoils->WaterCoil(coilIndex).AirOutletNodeNum;
     418              :                         }
     419              :                     } else {
     420              :                         // mine the cold water node from the coil object
     421            0 :                         int coilIndex = WaterCoils::GetWaterCoilIndex(state, CCoilType, fanCoil.CCoilPlantName, IsNotOK);
     422              :                         // Other error checks should trap before it gets to this point in the code, but including just in case.
     423            0 :                         if (IsNotOK) {
     424            0 :                             ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, fanCoil.Name));
     425            0 :                             ErrorsFound = true;
     426              :                         } else {
     427            0 :                             fanCoil.CoolCoilFluidInletNode = state.dataWaterCoils->WaterCoil(coilIndex).WaterInletNodeNum;
     428            0 :                             fanCoil.CoolCoilInletNodeNum = state.dataWaterCoils->WaterCoil(coilIndex).AirInletNodeNum;
     429            0 :                             fanCoil.CoolCoilOutletNodeNum = state.dataWaterCoils->WaterCoil(coilIndex).AirOutletNodeNum;
     430              :                         }
     431              :                     }
     432              :                 }
     433           22 :             } else {
     434            0 :                 ShowSevereError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, fanCoil.Name));
     435            0 :                 ShowContinueError(state, format("illegal value: {}=\"{}\".", cAlphaFields(11), Alphas(11)));
     436            0 :                 ErrorsFound = true;
     437              :             }
     438              : 
     439           22 :             if (Util::SameString(Alphas(13), "Coil:Heating:Water")) {
     440           16 :                 fanCoil.HCoilType_Num = HCoil::Water;
     441           16 :                 fanCoil.HCoilPlantTypeOf = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
     442           16 :                 IsNotOK = false;
     443           16 :                 ValidateComponent(state, fanCoil.HCoilType, fanCoil.HCoilName, IsNotOK, CurrentModuleObject);
     444           16 :                 if (IsNotOK) {
     445            0 :                     ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, fanCoil.Name));
     446            0 :                     ErrorsFound = true;
     447              :                 } else {
     448              :                     // mine the hot water node from the coil object
     449           16 :                     int coilIndex = WaterCoils::GetWaterCoilIndex(state, fanCoil.HCoilType, fanCoil.HCoilName, IsNotOK);
     450           16 :                     if (IsNotOK) {
     451            0 :                         ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, fanCoil.Name));
     452            0 :                         ErrorsFound = true;
     453              :                     } else {
     454           16 :                         fanCoil.HeatCoilFluidInletNode = state.dataWaterCoils->WaterCoil(coilIndex).WaterInletNodeNum;
     455           16 :                         fanCoil.HeatCoilInletNodeNum = state.dataWaterCoils->WaterCoil(coilIndex).AirInletNodeNum;
     456           16 :                         fanCoil.HeatCoilOutletNodeNum = state.dataWaterCoils->WaterCoil(coilIndex).AirOutletNodeNum;
     457              :                     }
     458              :                 }
     459            6 :             } else if (Util::SameString(Alphas(13), "Coil:Heating:Electric")) {
     460            6 :                 fanCoil.HCoilType_Num = HCoil::Electric;
     461            6 :                 IsNotOK = false;
     462            6 :                 ValidateComponent(state, fanCoil.HCoilType, fanCoil.HCoilName, IsNotOK, CurrentModuleObject);
     463            6 :                 if (IsNotOK) {
     464            0 :                     ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, fanCoil.Name));
     465            0 :                     ErrorsFound = true;
     466              :                 } else {
     467              :                     int coilIndex;
     468            6 :                     HeatingCoils::GetCoilIndex(state, fanCoil.HCoilName, coilIndex, IsNotOK);
     469            6 :                     if (IsNotOK) {
     470            0 :                         ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, fanCoil.Name));
     471            0 :                         ErrorsFound = true;
     472              :                     } else {
     473            6 :                         fanCoil.DesignHeatingCapacity = state.dataHeatingCoils->HeatingCoil(coilIndex).NominalCapacity;
     474            6 :                         fanCoil.HeatCoilInletNodeNum = state.dataHeatingCoils->HeatingCoil(coilIndex).AirInletNodeNum;
     475            6 :                         fanCoil.HeatCoilOutletNodeNum = state.dataHeatingCoils->HeatingCoil(coilIndex).AirOutletNodeNum;
     476              :                     }
     477              :                 }
     478              :             } else {
     479            0 :                 ShowSevereError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, fanCoil.Name));
     480            0 :                 ShowContinueError(state, format("illegal value: {}=\"{}\".", cAlphaFields(13), Alphas(13)));
     481            0 :                 ErrorsFound = true;
     482              :             }
     483              : 
     484           22 :             fanCoil.FanName = Alphas(10);
     485              : 
     486           22 :             if (!lAlphaBlanks(15)) {
     487            0 :                 fanCoil.AvailManagerListName = Alphas(15);
     488              :             }
     489              : 
     490           22 :             fanCoil.HVACSizingIndex = 0;
     491           22 :             if (!lAlphaBlanks(16)) {
     492            0 :                 fanCoil.HVACSizingIndex = Util::FindItemInList(Alphas(16), state.dataSize->ZoneHVACSizing);
     493            0 :                 if (fanCoil.HVACSizingIndex == 0) {
     494            0 :                     ShowSevereError(state, format("{} = {} not found.", cAlphaFields(16), Alphas(16)));
     495            0 :                     ShowContinueError(state, format("Occurs in {} = {}", state.dataFanCoilUnits->cMO_FanCoil, fanCoil.Name));
     496            0 :                     ErrorsFound = true;
     497              :                 }
     498              :             }
     499              : 
     500           22 :             fanCoil.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(9)));
     501           22 :             if (fanCoil.fanType != HVAC::FanType::Constant && fanCoil.fanType != HVAC::FanType::VAV && fanCoil.fanType != HVAC::FanType::OnOff &&
     502            4 :                 fanCoil.fanType != HVAC::FanType::SystemModel) {
     503            0 :                 ShowSevereInvalidKey(state,
     504              :                                      eoh,
     505            0 :                                      cAlphaFields(9),
     506            0 :                                      Alphas(9),
     507              :                                      "Fan Type must be Fan:OnOff, Fan:ConstantVolume, Fan:VariableVolume, or Fan:SystemModel.");
     508            0 :                 ErrorsFound = true;
     509           22 :             } else if ((fanCoil.FanIndex = Fans::GetFanIndex(state, fanCoil.FanName)) == 0) {
     510            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(10), Alphas(10));
     511            0 :                 ErrorsFound = true;
     512              :             } else {
     513           22 :                 auto *fan = state.dataFans->fans(fanCoil.FanIndex);
     514              : 
     515           22 :                 if (fanCoil.fanType != fan->type) {
     516            0 :                     ShowSevereCustom(state,
     517              :                                      eoh,
     518            0 :                                      format("{} was specified as having type {}, but has type {}",
     519            0 :                                             fanCoil.FanName,
     520            0 :                                             HVAC::fanTypeNamesUC[(int)fanCoil.fanType],
     521            0 :                                             HVAC::fanTypeNamesUC[(int)fan->type]));
     522            0 :                     ErrorsFound = true;
     523              :                 }
     524              : 
     525           22 :                 fanCoil.fanAvailSched = fan->availSched;
     526           22 :                 fanCoil.FanAirVolFlow = fan->maxAirFlowRate;
     527              : 
     528           22 :                 if (fanCoil.MaxAirVolFlow > fanCoil.FanAirVolFlow && fanCoil.FanAirVolFlow != DataSizing::AutoSize) {
     529            0 :                     ShowWarningError(state, format("{}{}: {}", RoutineName, fanCoil.UnitType, fanCoil.Name));
     530            0 :                     ShowContinueError(state, format("... {} is greater than the maximum fan flow rate.", cNumericFields(1)));
     531            0 :                     ShowContinueError(state, format("... Fan Coil Unit flow = {:.5T} m3/s.", fanCoil.MaxAirVolFlow));
     532            0 :                     ShowContinueError(state, format("... Fan = {}: {}", HVAC::fanTypeNames[(int)fanCoil.fanType], fanCoil.FanName));
     533            0 :                     ShowContinueError(state, format("... Fan flow = {:.5T} m3/s.", fanCoil.FanAirVolFlow));
     534            0 :                     ShowContinueError(state, "... Fan Coil Unit flow rate reduced to match the fan flow rate and the simulation continues.");
     535            0 :                     fanCoil.MaxAirVolFlow = fanCoil.FanAirVolFlow;
     536              :                 }
     537              : 
     538           22 :                 if (fanCoil.fanType == HVAC::FanType::Constant || fanCoil.fanType == HVAC::FanType::VAV || fanCoil.fanType == HVAC::FanType::OnOff) {
     539              :                     // Get fan air volume flow rate
     540              :                     // Check that the fan volumetric flow rate is greater than or equal to the FCU volumetric flow rate
     541              : 
     542              :                     // Check that the fan type match with the capacity control method selected
     543           18 :                     if ((fanCoil.CapCtrlMeth_Num == CCM::ConsFanVarFlow && (fanCoil.fanType == HVAC::FanType::VAV)) ||
     544           18 :                         (fanCoil.CapCtrlMeth_Num == CCM::CycFan && fanCoil.fanType != HVAC::FanType::OnOff) ||
     545           18 :                         (fanCoil.CapCtrlMeth_Num == CCM::VarFanVarFlow && fanCoil.fanType != HVAC::FanType::VAV) ||
     546           18 :                         (fanCoil.CapCtrlMeth_Num == CCM::VarFanConsFlow && fanCoil.fanType != HVAC::FanType::VAV)) {
     547            0 :                         ShowSevereError(state, format("{}{}: {}", RoutineName, fanCoil.UnitType, fanCoil.Name));
     548            0 :                         ShowContinueError(state,
     549            0 :                                           format("...the fan type of the object : {} does not match with the capacity control method selected : "
     550              :                                                  "{} please see I/O reference",
     551            0 :                                                  fanCoil.FanName,
     552              :                                                  capCtrlMeth));
     553            0 :                         ShowContinueError(state, "...for ConstantFanVariableFlow a Fan:OnOff or Fan:ConstantVolume is valid.");
     554            0 :                         ShowContinueError(state, "...for CyclingFan a Fan:OnOff is valid.");
     555            0 :                         ShowContinueError(state, "...for VariableFanVariableFlow or VariableFanConstantFlow a Fan:VariableVolume is valid.");
     556            0 :                         ErrorsFound = true;
     557              :                     }
     558              :                 } else {
     559              :                     // check that for VariableFanVariableFlow or VariableFanConstantFlow that the fan speed control is continuous
     560            4 :                     if (fanCoil.CapCtrlMeth_Num == CCM::VarFanVarFlow || fanCoil.CapCtrlMeth_Num == CCM::VarFanConsFlow ||
     561            4 :                         fanCoil.CapCtrlMeth_Num == CCM::ASHRAE) { // then expect continuous speed control fan
     562            0 :                         if (dynamic_cast<Fans::FanSystem *>(state.dataFans->fans(fanCoil.FanIndex))->speedControl != Fans::SpeedControl::Continuous) {
     563            0 :                             ShowSevereError(state, format("{}{}: {}", RoutineName, fanCoil.UnitType, fanCoil.Name));
     564            0 :                             ShowContinueError(state,
     565            0 :                                               format("...the fan type of the object : {} does not match with the capacity control method selected : "
     566              :                                                      "{} please see I/O reference",
     567            0 :                                                      fanCoil.FanName,
     568              :                                                      capCtrlMeth));
     569            0 :                             ShowContinueError(
     570              :                                 state,
     571              :                                 "...for VariableFanVariableFlow or VariableFanConstantFlow a Fan:SystemModel should have Continuous speed control.");
     572            0 :                             ErrorsFound = true;
     573              :                         }
     574              :                     }
     575              :                 }
     576              :             }
     577              : 
     578              :             // check low speed fan ratio when using ASHRAE90.1 capacity control method
     579           22 :             if (fanCoil.CapCtrlMeth_Num == CCM::ASHRAE) {
     580            3 :                 if (fanCoil.LowSpeedRatio > 0.5) {
     581            0 :                     ShowWarningError(state, format("{}{}=\"{}\",", RoutineName, CurrentModuleObject, fanCoil.Name));
     582            0 :                     ShowContinueError(state, format("... {} is greater than the 50% of the supply air flow ratio.", cNumericFields(2)));
     583            0 :                     ShowContinueError(state, format("... Fan Coil Unit low speed supply air flow ratio = {:.5T} ", fanCoil.LowSpeedRatio));
     584            3 :                 } else if (fanCoil.LowSpeedRatio == 0.0) {
     585            0 :                     ShowWarningError(state, format("{}{}=\"{}\",", RoutineName, CurrentModuleObject, fanCoil.Name));
     586            0 :                     ShowContinueError(state, format("... {} is equal to 0.", cNumericFields(2)));
     587            0 :                     ShowContinueError(state, "... Fan Coil Unit low speed supply air flow ratio should be greater than 0 to comply with ASHRAE90.1.");
     588            0 :                     ShowContinueError(state, "... Fan Coil Unit low speed supply air flow ratio set to 0.5");
     589            0 :                     fanCoil.LowSpeedRatio = 0.5;
     590              :                 }
     591              :             }
     592              : 
     593              :             // Set defaults for convergence tolerance
     594           22 :             if (fanCoil.ColdControlOffset <= 0.0) {
     595            0 :                 fanCoil.ColdControlOffset = 0.001;
     596              :             }
     597           22 :             if (fanCoil.HotControlOffset <= 0.0) {
     598            0 :                 fanCoil.HotControlOffset = 0.001;
     599              :             }
     600              : 
     601              :             // check for inlet side air mixer
     602           44 :             SingleDuct::GetATMixer(state,
     603           22 :                                    fanCoil.Name,
     604              :                                    ATMixerName,
     605           22 :                                    state.dataFanCoilUnits->ATMixerNum,
     606           22 :                                    state.dataFanCoilUnits->ATMixerType,
     607           22 :                                    state.dataFanCoilUnits->ATMixerPriNode,
     608           22 :                                    state.dataFanCoilUnits->ATMixerSecNode,
     609           22 :                                    state.dataFanCoilUnits->ATMixerOutNode,
     610              :                                    fanCoil.AirOutNode);
     611           22 :             fanCoil.ControlZoneNum =
     612           22 :                 DataZoneEquipment::GetZoneEquipControlledZoneNum(state, DataZoneEquipment::ZoneEquipType::FourPipeFanCoil, fanCoil.Name);
     613           22 :             if (fanCoil.ControlZoneNum == 0) {
     614            0 :                 ErrorsFound = true;
     615              :             }
     616           22 :             if (state.dataFanCoilUnits->ATMixerType == HVAC::MixerType::InletSide) {
     617              :                 // save the air terminal mixer data in the fan coil data array
     618            2 :                 fanCoil.ATMixerExists = true;
     619            2 :                 fanCoil.ATMixerIndex = state.dataFanCoilUnits->ATMixerNum;
     620            2 :                 fanCoil.ATMixerName = ATMixerName;
     621            2 :                 fanCoil.ATMixerType = HVAC::MixerType::InletSide;
     622            2 :                 fanCoil.ATMixerPriNode = state.dataFanCoilUnits->ATMixerPriNode;
     623            2 :                 fanCoil.ATMixerSecNode = state.dataFanCoilUnits->ATMixerSecNode;
     624            2 :                 fanCoil.ATMixerOutNode = state.dataFanCoilUnits->ATMixerOutNode;
     625              :                 // check that fan coil doesn' have local outside air
     626            2 :                 if (!lAlphaBlanks(8)) {
     627            0 :                     ShowSevereError(
     628              :                         state,
     629            0 :                         format("{} = \"{}\". Fan coil unit has local as well as central outdoor air specified", CurrentModuleObject, fanCoil.Name));
     630              :                 }
     631              :                 // check that the air teminal mixer out node is the fan coil inlet node
     632            2 :                 if (fanCoil.AirInNode != state.dataFanCoilUnits->ATMixerOutNode) {
     633            0 :                     ShowSevereError(
     634              :                         state,
     635            0 :                         format("{} = \"{}\". Fan coil unit air inlet node name must be the same as an air terminal mixer outlet node name.",
     636              :                                CurrentModuleObject,
     637            0 :                                fanCoil.Name));
     638            0 :                     ShowContinueError(state, "..Air terminal mixer outlet node name is specified in AirTerminal:SingleDuct:InletSideMixer object.");
     639            0 :                     ShowContinueError(state, format("..Fan coil unit air inlet node name = {}", state.dataLoopNodes->NodeID(fanCoil.AirInNode)));
     640            0 :                     ErrorsFound = true;
     641              :                 }
     642              :                 // check for supply side air terminal mixer
     643           20 :             } else if (state.dataFanCoilUnits->ATMixerType == HVAC::MixerType::SupplySide) {
     644              :                 // save the air terminal mixer data in the fan coil data array
     645            0 :                 fanCoil.ATMixerExists = true;
     646            0 :                 fanCoil.ATMixerIndex = state.dataFanCoilUnits->ATMixerNum;
     647            0 :                 fanCoil.ATMixerName = ATMixerName;
     648            0 :                 fanCoil.ATMixerType = HVAC::MixerType::SupplySide;
     649            0 :                 fanCoil.ATMixerPriNode = state.dataFanCoilUnits->ATMixerPriNode;
     650            0 :                 fanCoil.ATMixerSecNode = state.dataFanCoilUnits->ATMixerSecNode;
     651            0 :                 fanCoil.ATMixerOutNode = state.dataFanCoilUnits->ATMixerOutNode;
     652              :                 // check that fan coil doesn' have local outside air
     653            0 :                 if (!lAlphaBlanks(8)) {
     654            0 :                     ShowSevereError(
     655              :                         state,
     656            0 :                         format("{} = \"{}\". Fan coil unit has local as well as central outdoor air specified", CurrentModuleObject, fanCoil.Name));
     657              :                 }
     658              :                 // check that the air teminal mixer secondary air inlet node is the fan coil outlet node
     659            0 :                 if (fanCoil.AirOutNode != state.dataFanCoilUnits->ATMixerSecNode) {
     660            0 :                     ShowSevereError(state,
     661            0 :                                     format("{} = \"{}\". Fan coil unit air outlet node name must be the same as the air terminal mixer secondary air "
     662              :                                            "inlet node name.",
     663              :                                            CurrentModuleObject,
     664            0 :                                            fanCoil.Name));
     665            0 :                     ShowContinueError(
     666              :                         state, "..Air terminal mixer secondary inlet node name is specified in AirTerminal:SingleDuct:SupplySideMixer object.");
     667            0 :                     ShowContinueError(state, format("..Fan coil unit air outlet node name = {}", state.dataLoopNodes->NodeID(fanCoil.AirOutNode)));
     668            0 :                     ErrorsFound = true;
     669              :                 }
     670            0 :                 bool ZoneNodeNotFound = true;
     671            0 :                 for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).NumExhaustNodes; ++NodeNum) {
     672            0 :                     if (fanCoil.AirInNode == state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).ExhaustNode(NodeNum)) {
     673            0 :                         ZoneNodeNotFound = false;
     674            0 :                         break;
     675              :                     }
     676              :                 }
     677            0 :                 if (ZoneNodeNotFound) {
     678            0 :                     bool InletNodeFound = false;
     679            0 :                     if (fanCoil.ControlZoneNum > 0) {
     680            0 :                         InletNodeFound = ZonePlenum::ValidateInducedNode(state,
     681              :                                                                          fanCoil.AirInNode,
     682            0 :                                                                          state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).NumReturnNodes,
     683            0 :                                                                          state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).ReturnNode);
     684              :                     }
     685            0 :                     if (!InletNodeFound) {
     686            0 :                         ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, CurrentModuleObject, fanCoil.Name));
     687            0 :                         ShowContinueError(state,
     688              :                                           "..FanCoil inlet node name must be the same as either a zone exhaust node name or an induced "
     689              :                                           "air node in ZonePlenum.");
     690            0 :                         ShowContinueError(state, "..Zone exhaust node name is specified in ZoneHVAC:EquipmentConnections object.");
     691            0 :                         ShowContinueError(state, "..Induced Air Outlet Node name is specified in AirLoopHVAC:ReturnPlenum object.");
     692            0 :                         ShowContinueError(state, format("..FanCoil inlet node name = {}", state.dataLoopNodes->NodeID(fanCoil.AirInNode)));
     693            0 :                         ErrorsFound = true;
     694              :                     }
     695              :                 }
     696              :                 // no air terminal mixer; do the normal connectivity checks
     697              :             } else {
     698              :                 // check that the fan coil inlet node is the same as one of the zone exhaust nodes
     699           20 :                 state.dataFanCoilUnits->ZoneExNodeNotFound = true;
     700           20 :                 for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).NumExhaustNodes; ++NodeNum) {
     701           20 :                     if (fanCoil.AirInNode == state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).ExhaustNode(NodeNum)) {
     702           20 :                         state.dataFanCoilUnits->ZoneExNodeNotFound = false;
     703           20 :                         break;
     704              :                     }
     705              :                 }
     706           20 :                 if (state.dataFanCoilUnits->ZoneExNodeNotFound) {
     707            0 :                     bool InletNodeFound = false;
     708            0 :                     InletNodeFound = ZonePlenum::ValidateInducedNode(state,
     709              :                                                                      fanCoil.AirInNode,
     710            0 :                                                                      state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).NumReturnNodes,
     711            0 :                                                                      state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).ReturnNode);
     712              : 
     713            0 :                     if (!InletNodeFound) {
     714            0 :                         ShowSevereError(state,
     715            0 :                                         format("{} = \"{}\". Fan coil unit air inlet node name must be the same either as a zone exhaust node name "
     716              :                                                "or an induce air node in ZoePlenum.",
     717              :                                                CurrentModuleObject,
     718            0 :                                                fanCoil.Name));
     719            0 :                         ShowContinueError(state, "..Zone exhaust node name is specified in ZoneHVAC:EquipmentConnections object.");
     720            0 :                         ShowContinueError(state, "..Induced Air Outlet Node name is specified in AirLoopHVAC:ReturnPlenum object.");
     721            0 :                         ShowContinueError(state, format("..Fan coil unit air inlet node name = {}", state.dataLoopNodes->NodeID(fanCoil.AirInNode)));
     722            0 :                         ErrorsFound = true;
     723              :                     }
     724              :                 }
     725              :                 // check that the fan coil outlet node is the same as one of the zone inlet nodes
     726           20 :                 state.dataFanCoilUnits->ZoneInNodeNotFound = true;
     727           20 :                 if (fanCoil.ControlZoneNum > 0) {
     728           20 :                     fanCoil.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).ZoneNode;
     729           20 :                     state.dataFanCoilUnits->ZoneInNodeNotFound = false;
     730              :                 }
     731              : 
     732           20 :                 if (state.dataFanCoilUnits->ZoneInNodeNotFound) {
     733            0 :                     ShowSevereError(state,
     734            0 :                                     format("{} = \"{}\". Fan coil unit air outlet node name must be the same as a zone inlet node name.",
     735              :                                            CurrentModuleObject,
     736            0 :                                            fanCoil.Name));
     737            0 :                     ShowContinueError(state, "..Zone inlet node name is specified in ZoneHVAC:EquipmentConnections object.");
     738            0 :                     ShowContinueError(state, format("..Fan coil unit air outlet node name = {}", state.dataLoopNodes->NodeID(fanCoil.AirOutNode)));
     739              : 
     740            0 :                     ErrorsFound = true;
     741              :                 }
     742              :             }
     743           22 :             if (fanCoil.CapCtrlMeth_Num == CCM::MultiSpeedFan) {
     744            6 :                 if (!lAlphaBlanks(17)) {
     745            3 :                     fanCoil.fanOpModeSched = Sched::GetSchedule(state, Alphas(17));
     746            3 :                     if (fanCoil.fanType != HVAC::FanType::OnOff && fanCoil.fanType != HVAC::FanType::SystemModel) {
     747            0 :                         ShowSevereError(state, format("{} = {}", CurrentModuleObject, fanCoil.Name));
     748            0 :                         ShowContinueError(state, format("For {} = {}", cAlphaFields(17), Alphas(17)));
     749            0 :                         ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(9), Alphas(9)));
     750            0 :                         ShowContinueError(state, "...fan operating schedule is allowed for on off or system model fan type only )");
     751            0 :                         ErrorsFound = true;
     752            3 :                     } else if (fanCoil.fanOpModeSched == nullptr) {
     753            0 :                         ShowSevereItemNotFound(state, eoh, cAlphaFields(17), Alphas(17));
     754            0 :                         ErrorsFound = true;
     755              :                     }
     756            3 :                 } else if (fanCoil.fanType == HVAC::FanType::OnOff || fanCoil.fanType == HVAC::FanType::SystemModel) {
     757            2 :                     fanCoil.fanOp = HVAC::FanOp::Cycling;
     758              :                 }
     759              :             }
     760              : 
     761           22 :             if (!lNumericBlanks(11)) {
     762            3 :                 fanCoil.DesignMinOutletTemp = Numbers(11);
     763            3 :                 if (lNumericBlanks(12)) {
     764            0 :                     ShowWarningError(state, format("{}{}=\"{}\",", RoutineName, CurrentModuleObject, fanCoil.Name));
     765            0 :                     ShowContinueError(state, format("... {} and {} must be used in unison.", cNumericFields(11), cNumericFields(12)));
     766            0 :                     ErrorsFound = true;
     767              :                 }
     768              :             }
     769              : 
     770           22 :             if (!lNumericBlanks(12)) {
     771            3 :                 fanCoil.DesignMaxOutletTemp = Numbers(12);
     772            3 :                 if (fanCoil.DesignMinOutletTemp != DataSizing::AutoSize && fanCoil.DesignMaxOutletTemp != DataSizing::AutoSize) {
     773            1 :                     if (fanCoil.DesignMaxOutletTemp < fanCoil.DesignMinOutletTemp) {
     774            0 :                         ShowWarningError(state, format("{}{}=\"{}\",", RoutineName, CurrentModuleObject, fanCoil.Name));
     775            0 :                         ShowContinueError(state, format("... {} is greater than {}.", cNumericFields(11), cNumericFields(12)));
     776            0 :                         ShowContinueError(state, format("... {} = {:.2T} [C].", cNumericFields(11), fanCoil.DesignMinOutletTemp));
     777            0 :                         ShowContinueError(state, format("... {} = {:.2T} [C].", cNumericFields(12), fanCoil.DesignMaxOutletTemp));
     778            0 :                         ErrorsFound = true;
     779              :                     }
     780              :                 }
     781            3 :                 if (lNumericBlanks(11)) {
     782            0 :                     ShowWarningError(state, format("{}{}=\"{}\",", RoutineName, CurrentModuleObject, fanCoil.Name));
     783            0 :                     ShowContinueError(state, format("... {} and {} must be used in unison.", cNumericFields(11), cNumericFields(12)));
     784            0 :                     ErrorsFound = true;
     785              :                 }
     786              :             }
     787              : 
     788           22 :             if (fanCoil.DesignMinOutletTemp > 0.0 && fanCoil.DesignMaxOutletTemp > 0.0) {
     789            1 :                 fanCoil.ASHRAETempControl = true;
     790           21 :             } else if (fanCoil.DesignMinOutletTemp == DataSizing::AutoSize || fanCoil.DesignMaxOutletTemp == DataSizing::AutoSize) {
     791            2 :                 fanCoil.ASHRAETempControl = true;
     792              :             }
     793              : 
     794              :             // Set up component set for supply fan
     795           22 :             if (fanCoil.OutsideAirNode > 0) {
     796           60 :                 BranchNodeConnections::SetUpCompSets(state,
     797              :                                                      fanCoil.UnitType,
     798              :                                                      fanCoil.Name,
     799           20 :                                                      HVAC::fanTypeNames[(int)fanCoil.fanType],
     800              :                                                      fanCoil.FanName,
     801           20 :                                                      state.dataLoopNodes->NodeID(fanCoil.MixedAirNode),
     802              :                                                      "UNDEFINED");
     803              :             } else {
     804            6 :                 BranchNodeConnections::SetUpCompSets(state,
     805              :                                                      fanCoil.UnitType,
     806              :                                                      fanCoil.Name,
     807            2 :                                                      HVAC::fanTypeNames[(int)fanCoil.fanType],
     808              :                                                      fanCoil.FanName,
     809            2 :                                                      state.dataLoopNodes->NodeID(fanCoil.AirInNode),
     810              :                                                      "UNDEFINED");
     811              :             }
     812              :             // Set up component set for cooling coil
     813           22 :             BranchNodeConnections::SetUpCompSets(
     814              :                 state, fanCoil.UnitType, fanCoil.Name, fanCoil.CCoilType, fanCoil.CCoilName, "UNDEFINED", "UNDEFINED");
     815              : 
     816              :             // Set up component set for heating coil
     817           44 :             BranchNodeConnections::SetUpCompSets(state,
     818              :                                                  fanCoil.UnitType,
     819              :                                                  fanCoil.Name,
     820              :                                                  fanCoil.HCoilType,
     821              :                                                  fanCoil.HCoilName,
     822              :                                                  "UNDEFINED",
     823           22 :                                                  state.dataLoopNodes->NodeID(fanCoil.AirOutNode));
     824              : 
     825              :             // Set up component set for OA mixer - use OA node and Mixed air node
     826           22 :             if (fanCoil.OutsideAirNode > 0) {
     827           40 :                 BranchNodeConnections::SetUpCompSets(state,
     828              :                                                      fanCoil.UnitType,
     829              :                                                      fanCoil.Name,
     830              :                                                      fanCoil.OAMixType,
     831              :                                                      fanCoil.OAMixName,
     832           20 :                                                      state.dataLoopNodes->NodeID(fanCoil.OutsideAirNode),
     833           20 :                                                      state.dataLoopNodes->NodeID(fanCoil.MixedAirNode));
     834              :             }
     835           22 :         }
     836              : 
     837           18 :         Alphas.deallocate();
     838           18 :         cAlphaFields.deallocate();
     839           18 :         cNumericFields.deallocate();
     840           18 :         Numbers.deallocate();
     841           18 :         lAlphaBlanks.deallocate();
     842           18 :         lNumericBlanks.deallocate();
     843              : 
     844           18 :         if (ErrorsFound) {
     845            0 :             ShowFatalError(state, format("{}Errors found in input. Preceding condition(s) cause termination.", RoutineName));
     846              :         }
     847              : 
     848           40 :         for (auto &fanCoil : state.dataFanCoilUnits->FanCoil) {
     849              :             // Setup Report variables for the Fan Coils
     850              :             // CurrentModuleObject='ZoneHVAC:FourPipeFanCoil'
     851           44 :             SetupOutputVariable(state,
     852              :                                 "Fan Coil Heating Rate",
     853              :                                 Constant::Units::W,
     854           22 :                                 fanCoil.HeatPower,
     855              :                                 OutputProcessor::TimeStepType::System,
     856              :                                 OutputProcessor::StoreType::Average,
     857           22 :                                 fanCoil.Name);
     858           44 :             SetupOutputVariable(state,
     859              :                                 "Fan Coil Heating Energy",
     860              :                                 Constant::Units::J,
     861           22 :                                 fanCoil.HeatEnergy,
     862              :                                 OutputProcessor::TimeStepType::System,
     863              :                                 OutputProcessor::StoreType::Sum,
     864           22 :                                 fanCoil.Name);
     865           44 :             SetupOutputVariable(state,
     866              :                                 "Fan Coil Total Cooling Rate",
     867              :                                 Constant::Units::W,
     868           22 :                                 fanCoil.TotCoolPower,
     869              :                                 OutputProcessor::TimeStepType::System,
     870              :                                 OutputProcessor::StoreType::Average,
     871           22 :                                 fanCoil.Name);
     872           44 :             SetupOutputVariable(state,
     873              :                                 "Fan Coil Total Cooling Energy",
     874              :                                 Constant::Units::J,
     875           22 :                                 fanCoil.TotCoolEnergy,
     876              :                                 OutputProcessor::TimeStepType::System,
     877              :                                 OutputProcessor::StoreType::Sum,
     878           22 :                                 fanCoil.Name);
     879           44 :             SetupOutputVariable(state,
     880              :                                 "Fan Coil Sensible Cooling Rate",
     881              :                                 Constant::Units::W,
     882           22 :                                 fanCoil.SensCoolPower,
     883              :                                 OutputProcessor::TimeStepType::System,
     884              :                                 OutputProcessor::StoreType::Average,
     885           22 :                                 fanCoil.Name);
     886           44 :             SetupOutputVariable(state,
     887              :                                 "Fan Coil Sensible Cooling Energy",
     888              :                                 Constant::Units::J,
     889           22 :                                 fanCoil.SensCoolEnergy,
     890              :                                 OutputProcessor::TimeStepType::System,
     891              :                                 OutputProcessor::StoreType::Sum,
     892           22 :                                 fanCoil.Name);
     893           44 :             SetupOutputVariable(state,
     894              :                                 "Fan Coil Fan Electricity Rate",
     895              :                                 Constant::Units::W,
     896           22 :                                 fanCoil.ElecPower,
     897              :                                 OutputProcessor::TimeStepType::System,
     898              :                                 OutputProcessor::StoreType::Average,
     899           22 :                                 fanCoil.Name);
     900           44 :             SetupOutputVariable(state,
     901              :                                 "Fan Coil Fan Electricity Energy",
     902              :                                 Constant::Units::J,
     903           22 :                                 fanCoil.ElecEnergy,
     904              :                                 OutputProcessor::TimeStepType::System,
     905              :                                 OutputProcessor::StoreType::Sum,
     906           22 :                                 fanCoil.Name);
     907           22 :             if (fanCoil.CapCtrlMeth_Num == CCM::CycFan || fanCoil.CapCtrlMeth_Num == CCM::MultiSpeedFan) {
     908           26 :                 SetupOutputVariable(state,
     909              :                                     "Fan Coil Runtime Fraction",
     910              :                                     Constant::Units::None,
     911           13 :                                     fanCoil.PLR,
     912              :                                     OutputProcessor::TimeStepType::System,
     913              :                                     OutputProcessor::StoreType::Average,
     914           13 :                                     fanCoil.Name);
     915           13 :                 SetupOutputVariable(state,
     916              :                                     "Fan Coil Fan Speed Level",
     917              :                                     Constant::Units::None,
     918           13 :                                     fanCoil.SpeedFanSel,
     919              :                                     OutputProcessor::TimeStepType::System,
     920              :                                     OutputProcessor::StoreType::Average,
     921           13 :                                     fanCoil.Name);
     922           13 :                 if (fanCoil.CapCtrlMeth_Num == CCM::MultiSpeedFan) {
     923           12 :                     SetupOutputVariable(state,
     924              :                                         "Fan Coil Speed Ratio",
     925              :                                         Constant::Units::None,
     926            6 :                                         fanCoil.SpeedRatio,
     927              :                                         OutputProcessor::TimeStepType::System,
     928              :                                         OutputProcessor::StoreType::Average,
     929            6 :                                         fanCoil.Name);
     930           12 :                     SetupOutputVariable(state,
     931              :                                         "Fan Coil Part Load Ratio",
     932              :                                         Constant::Units::None,
     933            6 :                                         fanCoil.PLR,
     934              :                                         OutputProcessor::TimeStepType::System,
     935              :                                         OutputProcessor::StoreType::Average,
     936            6 :                                         fanCoil.Name);
     937              :                 }
     938              :             }
     939           22 :             if (fanCoil.CapCtrlMeth_Num == CCM::VarFanVarFlow || fanCoil.CapCtrlMeth_Num == CCM::VarFanConsFlow) {
     940            4 :                 SetupOutputVariable(state,
     941              :                                     "Fan Coil Part Load Ratio",
     942              :                                     Constant::Units::None,
     943            2 :                                     fanCoil.PLR,
     944              :                                     OutputProcessor::TimeStepType::System,
     945              :                                     OutputProcessor::StoreType::Average,
     946            2 :                                     fanCoil.Name);
     947              :             }
     948           22 :             SetupOutputVariable(state,
     949              :                                 "Fan Coil Availability Status",
     950              :                                 Constant::Units::None,
     951           22 :                                 (int &)fanCoil.availStatus,
     952              :                                 OutputProcessor::TimeStepType::System,
     953              :                                 OutputProcessor::StoreType::Average,
     954           22 :                                 fanCoil.Name);
     955              : 
     956           22 :             state.dataRptCoilSelection->coilSelectionReportObj->setCoilSupplyFanInfo(
     957           22 :                 state, fanCoil.CCoilName, fanCoil.CCoilType, fanCoil.FanName, fanCoil.fanType, fanCoil.FanIndex);
     958           22 :             state.dataRptCoilSelection->coilSelectionReportObj->setCoilSupplyFanInfo(
     959           22 :                 state, fanCoil.HCoilName, fanCoil.HCoilType, fanCoil.FanName, fanCoil.fanType, fanCoil.FanIndex);
     960              :         }
     961           18 :     }
     962              : 
     963        20319 :     void InitFanCoilUnits(EnergyPlusData &state,
     964              :                           int const FanCoilNum,       // number of the current fan coil unit being simulated
     965              :                           int const ControlledZoneNum // number of zone being served
     966              :     )
     967              :     {
     968              : 
     969              :         // SUBROUTINE INFORMATION:
     970              :         //       AUTHOR         Fred Buhl
     971              :         //       DATE WRITTEN   March 2000
     972              :         //       MODIFIED       July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
     973              : 
     974              :         // PURPOSE OF THIS SUBROUTINE:
     975              :         // This subroutine is for initializations of the Fan Coil Components.
     976              : 
     977              :         // METHODOLOGY EMPLOYED:
     978              :         // Uses the status flags to trigger initializations.
     979              : 
     980              :         // SUBROUTINE PARAMETER DEFINITIONS:
     981              :         static constexpr std::string_view RoutineName("InitFanCoilUnits");
     982              : 
     983        20319 :         auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum);
     984              : 
     985              :         // Do the one time initializations
     986        20319 :         if (state.dataFanCoilUnits->InitFanCoilUnitsOneTimeFlag) {
     987              : 
     988           11 :             state.dataFanCoilUnits->MyEnvrnFlag.allocate(state.dataFanCoilUnits->NumFanCoils);
     989           11 :             state.dataFanCoilUnits->MySizeFlag.allocate(state.dataFanCoilUnits->NumFanCoils);
     990           11 :             state.dataFanCoilUnits->MyPlantScanFlag.allocate(state.dataFanCoilUnits->NumFanCoils);
     991           11 :             state.dataFanCoilUnits->MyZoneEqFlag.allocate(state.dataFanCoilUnits->NumFanCoils);
     992           11 :             state.dataFanCoilUnits->MyEnvrnFlag = true;
     993           11 :             state.dataFanCoilUnits->MySizeFlag = true;
     994           11 :             state.dataFanCoilUnits->MyPlantScanFlag = true;
     995           11 :             state.dataFanCoilUnits->MyZoneEqFlag = true;
     996           11 :             state.dataFanCoilUnits->InitFanCoilUnitsOneTimeFlag = false;
     997              :         }
     998              : 
     999        20319 :         if (allocated(state.dataAvail->ZoneComp)) {
    1000        20302 :             auto &availMgr = state.dataAvail->ZoneComp(DataZoneEquipment::ZoneEquipType::FourPipeFanCoil).ZoneCompAvailMgrs(FanCoilNum);
    1001        20302 :             if (state.dataFanCoilUnits->MyZoneEqFlag(FanCoilNum)) { // initialize the name of each availability manager list and zone number
    1002            6 :                 availMgr.AvailManagerListName = fanCoil.AvailManagerListName;
    1003            6 :                 availMgr.ZoneNum = ControlledZoneNum;
    1004            6 :                 state.dataFanCoilUnits->MyZoneEqFlag(FanCoilNum) = false;
    1005              :             }
    1006        20302 :             fanCoil.availStatus = availMgr.availStatus;
    1007              :         }
    1008              : 
    1009        20319 :         if (state.dataFanCoilUnits->MyPlantScanFlag(FanCoilNum) && allocated(state.dataPlnt->PlantLoop)) {
    1010           15 :             bool errFlag = false;
    1011           15 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    1012           20 :                 PlantUtilities::ScanPlantLoopsForObject(
    1013           10 :                     state, fanCoil.HCoilName, fanCoil.HCoilPlantTypeOf, fanCoil.HeatCoilPlantLoc, errFlag, _, _, _, _, _);
    1014              : 
    1015           10 :                 if (errFlag) {
    1016            0 :                     ShowContinueError(state, format("Reference Unit=\"{}\", type={}", fanCoil.Name, fanCoil.UnitType));
    1017            0 :                     ShowFatalError(state, "InitFanCoilUnits: Program terminated for previous conditions.");
    1018              :                 }
    1019              : 
    1020           10 :                 fanCoil.HeatCoilFluidOutletNodeNum = DataPlant::CompData::getPlantComponent(state, fanCoil.HeatCoilPlantLoc).NodeNumOut;
    1021              : 
    1022            5 :             } else if (fanCoil.HCoilType_Num == HCoil::Electric) {
    1023              :                 // do nothing, valid type
    1024              :             } else {
    1025            0 :                 ShowFatalError(state, format("InitFanCoilUnits: FanCoil={}, invalid heating coil type. Program terminated.", fanCoil.Name));
    1026              :             }
    1027              : 
    1028           15 :             if ((fanCoil.CCoilPlantType == DataPlant::PlantEquipmentType::CoilWaterCooling) ||
    1029            0 :                 (fanCoil.CCoilPlantType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling)) {
    1030           30 :                 PlantUtilities::ScanPlantLoopsForObject(
    1031           15 :                     state, fanCoil.CCoilPlantName, fanCoil.CCoilPlantType, fanCoil.CoolCoilPlantLoc, errFlag, _, _, _, _, _);
    1032           15 :                 if (errFlag) {
    1033            0 :                     ShowContinueError(state, format("Reference Unit=\"{}\", type={}", fanCoil.Name, fanCoil.UnitType));
    1034            0 :                     ShowFatalError(state, "InitFanCoilUnits: Program terminated for previous conditions.");
    1035              :                 }
    1036           15 :                 fanCoil.CoolCoilFluidOutletNodeNum = DataPlant::CompData::getPlantComponent(state, fanCoil.CoolCoilPlantLoc).NodeNumOut;
    1037              :             } else {
    1038            0 :                 ShowFatalError(state, format("InitFanCoilUnits: FanCoil={}, invalid cooling coil type. Program terminated.", fanCoil.Name));
    1039              :             }
    1040              : 
    1041           15 :             state.dataFanCoilUnits->MyPlantScanFlag(FanCoilNum) = false;
    1042              :         }
    1043              : 
    1044        20319 :         if (!state.dataFanCoilUnits->InitFanCoilUnitsCheckInZoneEquipmentListFlag && state.dataZoneEquip->ZoneEquipInputsFilled) {
    1045            1 :             state.dataFanCoilUnits->InitFanCoilUnitsCheckInZoneEquipmentListFlag = true;
    1046            6 :             for (int Loop = 1; Loop <= state.dataFanCoilUnits->NumFanCoils; ++Loop) {
    1047           10 :                 if (DataZoneEquipment::CheckZoneEquipmentList(
    1048            5 :                         state, state.dataFanCoilUnits->FanCoil(Loop).UnitType, state.dataFanCoilUnits->FanCoil(Loop).Name))
    1049            5 :                     continue;
    1050            0 :                 ShowSevereError(state,
    1051            0 :                                 format("InitFanCoil: FanCoil Unit=[{},{}] is not on any ZoneHVAC:EquipmentList.  It will not be simulated.",
    1052            0 :                                        state.dataFanCoilUnits->FanCoil(Loop).UnitType,
    1053            0 :                                        state.dataFanCoilUnits->FanCoil(Loop).Name));
    1054              :             }
    1055              :         }
    1056              : 
    1057        20332 :         if (!state.dataGlobal->SysSizingCalc && state.dataFanCoilUnits->MySizeFlag(FanCoilNum) &&
    1058           13 :             !state.dataFanCoilUnits->MyPlantScanFlag(FanCoilNum)) {
    1059              : 
    1060           13 :             SizeFanCoilUnit(state, FanCoilNum, ControlledZoneNum);
    1061              : 
    1062           13 :             state.dataFanCoilUnits->MySizeFlag(FanCoilNum) = false;
    1063              :         }
    1064              : 
    1065              :         // Do the Begin Environment initializations
    1066        20348 :         if (state.dataGlobal->BeginEnvrnFlag && state.dataFanCoilUnits->MyEnvrnFlag(FanCoilNum) &&
    1067           29 :             !state.dataFanCoilUnits->MyPlantScanFlag(FanCoilNum)) {
    1068           29 :             Real64 RhoAir = state.dataEnvrn->StdRhoAir;
    1069              :             // set the mass flow rates from the input volume flow rates
    1070           29 :             fanCoil.MaxAirMassFlow = RhoAir * fanCoil.MaxAirVolFlow;
    1071           29 :             fanCoil.OutAirMassFlow = RhoAir * fanCoil.OutAirVolFlow;
    1072              : 
    1073           29 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    1074              :                 Real64 rho =
    1075           25 :                     state.dataPlnt->PlantLoop(fanCoil.HeatCoilPlantLoc.loopNum).glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
    1076           25 :                 fanCoil.MaxHeatCoilFluidFlow = rho * fanCoil.MaxHotWaterVolFlow;
    1077           25 :                 fanCoil.MinHotWaterFlow = rho * fanCoil.MinHotWaterVolFlow;
    1078              :             }
    1079              : 
    1080           29 :             Real64 rho = state.dataPlnt->PlantLoop(fanCoil.CoolCoilPlantLoc.loopNum).glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
    1081           29 :             fanCoil.MaxCoolCoilFluidFlow = rho * fanCoil.MaxColdWaterVolFlow;
    1082           29 :             fanCoil.MinColdWaterFlow = rho * fanCoil.MinColdWaterVolFlow;
    1083              : 
    1084              :             // set the node max and min mass flow rates
    1085           29 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    1086           25 :                 PlantUtilities::InitComponentNodes(
    1087              :                     state, fanCoil.MinHotWaterFlow, fanCoil.MaxHeatCoilFluidFlow, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum);
    1088              :             }
    1089              : 
    1090           29 :             PlantUtilities::InitComponentNodes(
    1091              :                 state, fanCoil.MinColdWaterFlow, fanCoil.MaxCoolCoilFluidFlow, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum);
    1092              : 
    1093           29 :             if (fanCoil.OutsideAirNode > 0) {
    1094           27 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMax = fanCoil.OutAirMassFlow;
    1095           27 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMin = 0.0;
    1096              :             }
    1097           29 :             state.dataLoopNodes->Node(fanCoil.AirOutNode).MassFlowRateMax = fanCoil.MaxAirMassFlow;
    1098           29 :             state.dataLoopNodes->Node(fanCoil.AirOutNode).MassFlowRateMin = 0.0;
    1099           29 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRateMax = fanCoil.MaxAirMassFlow;
    1100           29 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRateMin = 0.0;
    1101           29 :             state.dataFanCoilUnits->MyEnvrnFlag(FanCoilNum) = false;
    1102              :         } // end one time inits
    1103              : 
    1104        20319 :         if (!state.dataGlobal->BeginEnvrnFlag) {
    1105        20186 :             state.dataFanCoilUnits->MyEnvrnFlag(FanCoilNum) = true;
    1106              :         }
    1107              : 
    1108              :         // These initializations are done every iteration
    1109        20319 :         fanCoil.SpeedRatio = 0.0;
    1110        20319 :         if (fanCoil.fanOpModeSched != nullptr) {
    1111            9 :             fanCoil.fanOp = (fanCoil.fanOpModeSched->getCurrentVal() == 0.0) ? HVAC::FanOp::Cycling : HVAC::FanOp::Continuous;
    1112              :         }
    1113              :         // Set the inlet node mass flow rate
    1114        40637 :         if (((fanCoil.availSched->getCurrentVal() > 0.0 && fanCoil.fanAvailSched->getCurrentVal() > 0.0) || state.dataHVACGlobal->TurnFansOn) &&
    1115        20318 :             !state.dataHVACGlobal->TurnFansOff) {
    1116        20318 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRate = fanCoil.MaxAirMassFlow;
    1117        20318 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRateMaxAvail = state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRate;
    1118        20318 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRateMinAvail = 0.0;
    1119              : 
    1120        20318 :             if (fanCoil.OutsideAirNode > 0) {
    1121        20315 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRate = fanCoil.OutAirMassFlow;
    1122        20315 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMaxAvail = fanCoil.OutAirMassFlow;
    1123        20315 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMinAvail = fanCoil.OutAirMassFlow;
    1124        20315 :                 state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRate = fanCoil.OutAirMassFlow;
    1125        20315 :                 state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRateMaxAvail = fanCoil.OutAirMassFlow;
    1126        20315 :                 state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRateMinAvail = fanCoil.OutAirMassFlow;
    1127              :             }
    1128              : 
    1129              :         } else {
    1130            1 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRate = 0.0;
    1131            1 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRateMaxAvail = 0.0;
    1132            1 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRateMinAvail = 0.0;
    1133            1 :             if (fanCoil.OutsideAirNode > 0) {
    1134            0 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRate = 0.0;
    1135            0 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMaxAvail = 0.0;
    1136            0 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMinAvail = 0.0;
    1137            0 :                 state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRate = 0.0;
    1138            0 :                 state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRateMaxAvail = 0.0;
    1139            0 :                 state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRateMinAvail = 0.0;
    1140              :             }
    1141              :         }
    1142        20319 :     }
    1143              : 
    1144           13 :     void SizeFanCoilUnit(EnergyPlusData &state,
    1145              :                          int const FanCoilNum,
    1146              :                          int const ControlledZoneNum // index into ZoneEquipConfig array
    1147              :     )
    1148              :     {
    1149              : 
    1150              :         // SUBROUTINE INFORMATION:
    1151              :         //       AUTHOR         Fred Buhl
    1152              :         //       DATE WRITTEN   January 2002
    1153              :         //       MODIFIED       August 2013 Daeho Kang, add component sizing table entries
    1154              :         //                      July 2014, B. Nigusse, added scalable sizing
    1155              : 
    1156              :         // PURPOSE OF THIS SUBROUTINE:
    1157              :         // This subroutine is for sizing Fan Coil Unit components for which flow rates have not been
    1158              :         // specified in the input.
    1159              : 
    1160              :         // METHODOLOGY EMPLOYED:
    1161              :         // Obtains flow rates from the zone or system sizing arrays and plant sizing data.
    1162              : 
    1163              :         // SUBROUTINE PARAMETER DEFINITIONS:
    1164              :         static constexpr std::string_view RoutineName("SizeFanCoilUnit: "); // include trailing blank space
    1165              :         static constexpr std::string_view RoutineNameNoSpace("SizeFanCoilUnit");
    1166              : 
    1167              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1168              :         Real64 DesCoilLoad; // coil load used for sizing [W]
    1169           13 :         std::string CoolingCoilName;
    1170           13 :         std::string CoolingCoilType;
    1171              :         Real64 rho;
    1172              :         Real64 Cp;
    1173              :         int zoneHVACIndex;        // index of zoneHVAC equipment sizing specification
    1174           13 :         std::string SizingString; // input field sizing description (e.g., Nominal Capacity)
    1175              :         Real64 TempSize;          // autosized value of coil input field
    1176              :         int SizingMethod; // Integer representation of sizing method name (e.g., CoolingAirflowSizing, HeatingAirflowSizing, CoolingCapacitySizing,
    1177              :                           // HeatingCapacitySizing, etc.)
    1178              :         bool PrintFlag;   // TRUE when sizing information is reported in the eio file
    1179              :                           // FractionOfAutosizedHeatingAirflow ...)
    1180              :         Real64 WaterCoilSizDeltaT; // water coil deltaT for design water flow rate autosizing
    1181              :         int CoilNum;               // index of water coil object
    1182              : 
    1183           13 :         bool ErrorsFound = false;             // TRUE if errors found during sizing
    1184           13 :         bool IsAutoSize = false;              // Indicator to autosize for reporting
    1185           13 :         Real64 MaxAirVolFlowDes = 0.0;        // Autosized max air flow for reporting
    1186           13 :         Real64 MaxAirVolFlowUser = 0.0;       // Hardsized max air flow for reporting
    1187           13 :         Real64 OutAirVolFlowDes = 0.0;        // Autosized outdoor air flow for reporting
    1188           13 :         Real64 OutAirVolFlowUser = 0.0;       // Hardsized outdoor air flow for reporting
    1189           13 :         Real64 MaxHotWaterVolFlowDes = 0.0;   // Autosized hot water flow for reporting
    1190           13 :         Real64 MaxHotWaterVolFlowUser = 0.0;  // Hardsized hot water flow for reporting
    1191           13 :         Real64 MaxColdWaterVolFlowDes = 0.0;  // Autosized cold water flow for reporting
    1192           13 :         Real64 MaxColdWaterVolFlowUser = 0.0; // Hardsized cold water flow for reporting
    1193           13 :         Real64 CoolingAirVolFlowDes = 0.0;    // cooling supply air flow rate
    1194           13 :         Real64 HeatingAirVolFlowDes = 0.0;    // heating supply air flow rate
    1195              : 
    1196           13 :         state.dataSize->ZoneHeatingOnlyFan = false;
    1197           13 :         state.dataSize->ZoneCoolingOnlyFan = false;
    1198           13 :         state.dataSize->DataScalableSizingON = false;
    1199           13 :         state.dataSize->DataScalableCapSizingON = false;
    1200              : 
    1201           13 :         state.dataSize->DataFracOfAutosizedCoolingAirflow = 1.0;
    1202           13 :         state.dataSize->DataFracOfAutosizedHeatingAirflow = 1.0;
    1203           13 :         state.dataSize->DataFracOfAutosizedCoolingCapacity = 1.0;
    1204           13 :         state.dataSize->DataFracOfAutosizedHeatingCapacity = 1.0;
    1205              : 
    1206           13 :         auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum);
    1207              : 
    1208           13 :         std::string CompType = fanCoil.UnitType;
    1209           13 :         std::string CompName = fanCoil.Name;
    1210           13 :         state.dataSize->DataZoneNumber = fanCoil.ControlZoneNum;
    1211           13 :         state.dataSize->DataFanType = fanCoil.fanType;
    1212           13 :         state.dataSize->DataFanIndex = fanCoil.FanIndex;
    1213              :         // fan coil unit is always blow thru
    1214           13 :         state.dataSize->DataFanPlacement = HVAC::FanPlace::BlowThru;
    1215              : 
    1216           13 :         auto &zoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
    1217              : 
    1218           13 :         if (state.dataSize->CurZoneEqNum > 0) {
    1219           13 :             if (fanCoil.HVACSizingIndex > 0) {
    1220              : 
    1221              :                 // initialize OA flow for sizing other inputs (e.g., inlet temp, capacity, etc.)
    1222            0 :                 if (fanCoil.OutAirVolFlow == DataSizing::AutoSize) {
    1223            0 :                     zoneEqSizing.OAVolFlow = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
    1224              :                 } else {
    1225            0 :                     zoneEqSizing.OAVolFlow = fanCoil.OutAirVolFlow;
    1226              :                 }
    1227            0 :                 if (fanCoil.ATMixerExists) {      // set up ATMixer conditions for scalable capacity sizing
    1228            0 :                     zoneEqSizing.OAVolFlow = 0.0; // Equipment OA flow should always be 0 when ATMixer is used
    1229            0 :                     SingleDuct::setATMixerSizingProperties(state, fanCoil.ATMixerIndex, ControlledZoneNum, state.dataSize->CurZoneEqNum);
    1230              :                 }
    1231              : 
    1232            0 :                 zoneHVACIndex = fanCoil.HVACSizingIndex;
    1233            0 :                 int FieldNum = 1; // IDD numeric field number where input field description is found
    1234            0 :                 PrintFlag = true;
    1235              :                 int SAFMethod; // supply air flow rate sizing method (SupplyAirFlowRate, FlowPerFloorArea, FractionOfAutosizedCoolingAirflow,
    1236            0 :                 SizingString = state.dataFanCoilUnits->FanCoilNumericFields(FanCoilNum).FieldNames(FieldNum) + " [m3/s]";
    1237            0 :                 if (state.dataGlobal->isEpJSON) SizingString = "maximum_supply_air_flow_rate [m3/s]";
    1238            0 :                 if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod > 0) {
    1239            0 :                     SizingMethod = HVAC::CoolingAirflowSizing;
    1240            0 :                     SAFMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod;
    1241            0 :                     zoneEqSizing.SizingMethod(SizingMethod) = SAFMethod;
    1242            0 :                     if (SAFMethod == DataSizing::SupplyAirFlowRate || SAFMethod == DataSizing::FlowPerFloorArea ||
    1243              :                         SAFMethod == DataSizing::FractionOfAutosizedCoolingAirflow) {
    1244            0 :                         if (SAFMethod == DataSizing::SupplyAirFlowRate) {
    1245            0 :                             if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow > 0.0) {
    1246            0 :                                 zoneEqSizing.AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
    1247            0 :                                 zoneEqSizing.SystemAirFlow = true;
    1248              :                             }
    1249            0 :                             TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
    1250            0 :                         } else if (SAFMethod == DataSizing::FlowPerFloorArea) {
    1251            0 :                             zoneEqSizing.SystemAirFlow = true;
    1252            0 :                             zoneEqSizing.AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow *
    1253            0 :                                                       state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1254            0 :                             TempSize = zoneEqSizing.AirVolFlow;
    1255            0 :                             state.dataSize->DataScalableSizingON = true;
    1256            0 :                         } else if (SAFMethod == DataSizing::FractionOfAutosizedCoolingAirflow) {
    1257            0 :                             state.dataSize->DataFracOfAutosizedCoolingAirflow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
    1258            0 :                             TempSize = DataSizing::AutoSize;
    1259            0 :                             state.dataSize->DataScalableSizingON = true;
    1260              :                         } else {
    1261            0 :                             TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
    1262              :                         }
    1263            0 :                         CoolingAirFlowSizer sizingCoolingAirFlow;
    1264            0 :                         sizingCoolingAirFlow.overrideSizingString(SizingString);
    1265              :                         // sizingCoolingAirFlow.setHVACSizingIndexData(fanCoil.HVACSizingIndex);
    1266            0 :                         sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1267            0 :                         CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
    1268              : 
    1269            0 :                     } else if (SAFMethod == DataSizing::FlowPerCoolingCapacity) {
    1270            0 :                         SizingMethod = HVAC::CoolingCapacitySizing;
    1271            0 :                         TempSize = DataSizing::AutoSize;
    1272            0 :                         PrintFlag = false;
    1273            0 :                         CoolingCapacitySizer sizerCoolingCapacity;
    1274            0 :                         sizerCoolingCapacity.overrideSizingString(SizingString);
    1275            0 :                         sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1276            0 :                         state.dataSize->DataAutosizedCoolingCapacity = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
    1277            0 :                         if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingCapMethod == DataSizing::FractionOfAutosizedCoolingCapacity) {
    1278            0 :                             state.dataSize->DataFracOfAutosizedCoolingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
    1279              :                         }
    1280            0 :                         state.dataSize->DataFlowPerCoolingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
    1281            0 :                         PrintFlag = true;
    1282            0 :                         TempSize = DataSizing::AutoSize;
    1283            0 :                         state.dataSize->DataScalableSizingON = true;
    1284            0 :                         CoolingAirFlowSizer sizingCoolingAirFlow;
    1285            0 :                         sizingCoolingAirFlow.overrideSizingString(SizingString);
    1286              :                         // sizingCoolingAirFlow.setHVACSizingIndexData(fanCoil.HVACSizingIndex);
    1287            0 :                         sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1288            0 :                         CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
    1289            0 :                     }
    1290            0 :                 } else if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingSAFMethod > 0) {
    1291              :                     // now do heating supply air flow rate sizing
    1292            0 :                     SizingMethod = HVAC::HeatingAirflowSizing;
    1293            0 :                     SAFMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingSAFMethod;
    1294            0 :                     zoneEqSizing.SizingMethod(SizingMethod) = SAFMethod;
    1295            0 :                     if (SAFMethod == DataSizing::SupplyAirFlowRate || SAFMethod == DataSizing::FlowPerFloorArea ||
    1296              :                         SAFMethod == DataSizing::FractionOfAutosizedHeatingAirflow) {
    1297            0 :                         if (SAFMethod == DataSizing::SupplyAirFlowRate) {
    1298            0 :                             if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow > 0.0) {
    1299            0 :                                 zoneEqSizing.AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
    1300            0 :                                 zoneEqSizing.SystemAirFlow = true;
    1301              :                             }
    1302            0 :                             TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
    1303            0 :                         } else if (SAFMethod == DataSizing::FlowPerFloorArea) {
    1304            0 :                             zoneEqSizing.SystemAirFlow = true;
    1305            0 :                             zoneEqSizing.AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow *
    1306            0 :                                                       state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1307            0 :                             TempSize = zoneEqSizing.AirVolFlow;
    1308            0 :                             state.dataSize->DataScalableSizingON = true;
    1309            0 :                         } else if (SAFMethod == DataSizing::FractionOfAutosizedHeatingAirflow) {
    1310            0 :                             state.dataSize->DataFracOfAutosizedHeatingAirflow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
    1311            0 :                             TempSize = DataSizing::AutoSize;
    1312            0 :                             state.dataSize->DataScalableSizingON = true;
    1313              :                         } else {
    1314            0 :                             TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
    1315              :                         }
    1316            0 :                         bool errorsFound = false;
    1317            0 :                         HeatingAirFlowSizer sizingHeatingAirFlow;
    1318            0 :                         sizingHeatingAirFlow.overrideSizingString(SizingString);
    1319              :                         // sizingHeatingAirFlow.setHVACSizingIndexData(fanCoil.HVACSizingIndex);
    1320            0 :                         sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1321            0 :                         HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, errorsFound);
    1322            0 :                     } else if (SAFMethod == DataSizing::FlowPerHeatingCapacity) {
    1323            0 :                         SizingMethod = HVAC::HeatingCapacitySizing;
    1324            0 :                         TempSize = DataSizing::AutoSize;
    1325            0 :                         PrintFlag = false;
    1326            0 :                         state.dataSize->DataScalableSizingON = true;
    1327              :                         // initialize OA flow for sizing capacity
    1328            0 :                         if (fanCoil.OutAirVolFlow == DataSizing::AutoSize) {
    1329            0 :                             zoneEqSizing.OAVolFlow = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
    1330              :                         } else {
    1331            0 :                             zoneEqSizing.OAVolFlow = fanCoil.OutAirVolFlow;
    1332              :                         }
    1333            0 :                         bool errorsFound = false;
    1334            0 :                         HeatingCapacitySizer sizerHeatingCapacity;
    1335            0 :                         sizerHeatingCapacity.overrideSizingString(SizingString);
    1336            0 :                         sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1337            0 :                         TempSize = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1338            0 :                         if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingCapMethod == DataSizing::FractionOfAutosizedHeatingCapacity) {
    1339            0 :                             state.dataSize->DataFracOfAutosizedHeatingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
    1340              :                         }
    1341            0 :                         state.dataSize->DataAutosizedHeatingCapacity = TempSize;
    1342            0 :                         state.dataSize->DataFlowPerHeatingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
    1343            0 :                         PrintFlag = true;
    1344            0 :                         TempSize = DataSizing::AutoSize;
    1345            0 :                         errorsFound = false;
    1346            0 :                         HeatingAirFlowSizer sizingHeatingAirFlow;
    1347            0 :                         sizingHeatingAirFlow.overrideSizingString(SizingString);
    1348              :                         // sizingHeatingAirFlow.setHVACSizingIndexData(fanCoil.HVACSizingIndex);
    1349            0 :                         sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1350            0 :                         HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, errorsFound);
    1351            0 :                     }
    1352              :                 }
    1353              : 
    1354            0 :                 if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == DataSizing::AutoSize ||
    1355            0 :                     state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == DataSizing::AutoSize) {
    1356            0 :                     IsAutoSize = true;
    1357            0 :                     fanCoil.MaxAirVolFlow = DataSizing::AutoSize;
    1358            0 :                     MaxAirVolFlowDes = max(CoolingAirVolFlowDes, HeatingAirVolFlowDes);
    1359              :                 } else {
    1360            0 :                     fanCoil.MaxAirVolFlow = max(CoolingAirVolFlowDes, HeatingAirVolFlowDes);
    1361            0 :                     MaxAirVolFlowDes = 0.0;
    1362              :                 }
    1363              :             } else {
    1364              :                 // SizingString = "Supply Air Maximum Flow Rate [m3/s]";
    1365           13 :                 TempSize = fanCoil.MaxAirVolFlow;
    1366           13 :                 PrintFlag = true;
    1367           13 :                 if (fanCoil.MaxAirVolFlow == DataSizing::AutoSize) {
    1368            7 :                     IsAutoSize = true;
    1369            7 :                     SystemAirFlowSizer sizerSystemAirFlow;
    1370              :                     // sizerSystemAirFlow.setHVACSizingIndexData(fanCoil.HVACSizingIndex);
    1371            7 :                     sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1372            7 :                     MaxAirVolFlowDes = sizerSystemAirFlow.size(state, TempSize, ErrorsFound);
    1373            7 :                 } else {
    1374            6 :                     MaxAirVolFlowDes = 0.0;
    1375              :                 }
    1376              :             }
    1377              :         }
    1378              : 
    1379           13 :         if (state.dataSize->CurZoneEqNum > 0) {
    1380           13 :             if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) {
    1381              : 
    1382              :             } else {
    1383           13 :                 if (MaxAirVolFlowDes < HVAC::SmallAirVolFlow) {
    1384            6 :                     MaxAirVolFlowDes = 0.0;
    1385              :                 }
    1386              : 
    1387              :                 //     If fan is autosized, get fan volumetric flow rate
    1388           13 :                 if (fanCoil.FanAirVolFlow == DataSizing::AutoSize) {
    1389            7 :                     state.dataFans->fans(fanCoil.FanIndex)->simulate(state, true, _, _);
    1390            7 :                     fanCoil.FanAirVolFlow = state.dataFans->fans(fanCoil.FanIndex)->maxAirFlowRate;
    1391              :                 }
    1392              :                 //     Check that the fan volumetric flow rate is greater than or equal to the FCU volumetric flow rate
    1393           13 :                 if (MaxAirVolFlowDes > fanCoil.FanAirVolFlow) {
    1394            0 :                     ShowWarningError(state, format("{}{}: {}", RoutineName, fanCoil.UnitType, fanCoil.Name));
    1395            0 :                     ShowContinueError(state, "... Maximum supply air flow rate is greater than the maximum fan flow rate.");
    1396            0 :                     ShowContinueError(state, format("... Fan Coil Unit flow = {:.5T} [m3/s].", MaxAirVolFlowDes));
    1397            0 :                     ShowContinueError(state, format("... Fan = {}: {}", HVAC::fanTypeNames[(int)fanCoil.fanType], fanCoil.FanName));
    1398            0 :                     ShowContinueError(state, format("... Fan flow = {:.5T} [m3/s].", fanCoil.FanAirVolFlow));
    1399            0 :                     ShowContinueError(state, "... Fan Coil Unit flow rate reduced to match the fan flow rate and the simulation continues.");
    1400            0 :                     MaxAirVolFlowDes = fanCoil.FanAirVolFlow;
    1401              :                 }
    1402              : 
    1403           13 :                 if (IsAutoSize) {
    1404            7 :                     fanCoil.MaxAirVolFlow = MaxAirVolFlowDes;
    1405              :                 } else { // Hard size with sizing data
    1406            6 :                     if (fanCoil.MaxAirVolFlow > 0.0 && MaxAirVolFlowDes > 0.0) {
    1407            0 :                         MaxAirVolFlowUser = fanCoil.MaxAirVolFlow;
    1408            0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    1409            0 :                             if ((std::abs(MaxAirVolFlowDes - MaxAirVolFlowUser) / MaxAirVolFlowUser) > state.dataSize->AutoVsHardSizingThreshold) {
    1410            0 :                                 ShowMessage(
    1411              :                                     state,
    1412            0 :                                     format("SizeFanCoilUnit: Potential issue with equipment sizing for {} {}", fanCoil.UnitType, fanCoil.Name));
    1413            0 :                                 ShowContinueError(state, format("User-Specified Supply Air Maximum Flow Rate of {:.5R} [m3/s]", MaxAirVolFlowUser));
    1414            0 :                                 ShowContinueError(state,
    1415            0 :                                                   format("differs from Design Size Supply Air Maximum Flow Rate of {:.5R} [m3/s]", MaxAirVolFlowDes));
    1416            0 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1417            0 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1418              :                             }
    1419              :                         }
    1420              :                     }
    1421              :                 }
    1422              :             }
    1423            0 :         } else if (fanCoil.FanAirVolFlow == DataSizing::AutoSize) {
    1424            0 :             state.dataFans->fans(fanCoil.FanIndex)->simulate(state, true, _, _);
    1425            0 :             fanCoil.FanAirVolFlow = state.dataFans->fans(fanCoil.FanIndex)->maxAirFlowRate;
    1426              : 
    1427              :             //   Check that the fan volumetric flow rate is greater than or equal to the FCU volumetric flow rate
    1428            0 :             if (fanCoil.MaxAirVolFlow > fanCoil.FanAirVolFlow) {
    1429            0 :                 ShowWarningError(state, format("{}{}: {}", RoutineName, fanCoil.UnitType, fanCoil.Name));
    1430            0 :                 ShowContinueError(state, "... Maximum supply air flow rate is greater than the maximum fan flow rate.");
    1431            0 :                 ShowContinueError(state, format("... Fan Coil Unit flow = {:.5T} m3/s.", fanCoil.MaxAirVolFlow));
    1432            0 :                 ShowContinueError(state, format("... Fan = {}: {}", HVAC::fanTypeNames[(int)fanCoil.fanType], fanCoil.FanName));
    1433            0 :                 ShowContinueError(state, format("... Fan flow = {:.5T} m3/s.", fanCoil.FanAirVolFlow));
    1434            0 :                 ShowContinueError(state, "... Fan Coil Unit flow rate reduced to match the fan flow rate and the simulation continues.");
    1435            0 :                 fanCoil.MaxAirVolFlow = fanCoil.FanAirVolFlow;
    1436              :             }
    1437              :         }
    1438              : 
    1439           13 :         IsAutoSize = false;
    1440           13 :         if (fanCoil.OutAirVolFlow == DataSizing::AutoSize) {
    1441            2 :             IsAutoSize = true;
    1442              :         }
    1443              : 
    1444           13 :         if (state.dataSize->CurZoneEqNum > 0) {
    1445           13 :             if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) {
    1446            0 :                 if (fanCoil.OutAirVolFlow > 0.0) {
    1447            0 :                     BaseSizer::reportSizerOutput(
    1448              :                         state, fanCoil.UnitType, fanCoil.Name, "User-Specified Maximum Outdoor Air Flow Rate [m3/s]", fanCoil.OutAirVolFlow);
    1449              :                 }
    1450              :             } else {
    1451           13 :                 CheckZoneSizing(state, fanCoil.UnitType, fanCoil.Name);
    1452           13 :                 OutAirVolFlowDes = min(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA, fanCoil.MaxAirVolFlow);
    1453           13 :                 if (OutAirVolFlowDes < HVAC::SmallAirVolFlow) {
    1454            8 :                     OutAirVolFlowDes = 0.0;
    1455              :                 }
    1456           13 :                 if (IsAutoSize) {
    1457            2 :                     fanCoil.OutAirVolFlow = OutAirVolFlowDes;
    1458            2 :                     BaseSizer::reportSizerOutput(
    1459              :                         state, fanCoil.UnitType, fanCoil.Name, "Design Size Maximum Outdoor Air Flow Rate [m3/s]", OutAirVolFlowDes);
    1460              :                 } else {
    1461           11 :                     if (fanCoil.OutAirVolFlow > 0.0 && OutAirVolFlowDes > 0.0) {
    1462            0 :                         OutAirVolFlowUser = fanCoil.OutAirVolFlow;
    1463            0 :                         BaseSizer::reportSizerOutput(state,
    1464              :                                                      fanCoil.UnitType,
    1465              :                                                      fanCoil.Name,
    1466              :                                                      "Design Size Maximum Outdoor Air Flow Rate [m3/s]",
    1467              :                                                      OutAirVolFlowDes,
    1468              :                                                      "User-Specified Maximum Outdoor Air Flow Rate [m3/s]",
    1469              :                                                      OutAirVolFlowUser);
    1470            0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    1471            0 :                             if ((std::abs(OutAirVolFlowDes - OutAirVolFlowUser) / OutAirVolFlowUser) > state.dataSize->AutoVsHardSizingThreshold) {
    1472            0 :                                 ShowMessage(
    1473              :                                     state,
    1474            0 :                                     format("SizeFanCoilUnit: Potential issue with equipment sizing for {} {}", fanCoil.UnitType, fanCoil.Name));
    1475            0 :                                 ShowContinueError(state, format("User-Specified Maximum Outdoor Air Flow Rate of {:.5R} [m3/s]", OutAirVolFlowUser));
    1476            0 :                                 ShowContinueError(
    1477            0 :                                     state, format("differs from Design Size Maximum Outdoor Air Flow Rate of {:.5R} [m3/s]", OutAirVolFlowDes));
    1478            0 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1479            0 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1480              :                             }
    1481              :                         }
    1482              :                     }
    1483              :                 }
    1484              :             }
    1485           13 :             zoneEqSizing.OAVolFlow = fanCoil.OutAirVolFlow; // sets OA frac in sizing
    1486              : 
    1487           13 :             if (fanCoil.ATMixerExists) {      // set up ATMixer conditions for use in component sizing
    1488            2 :                 zoneEqSizing.OAVolFlow = 0.0; // Equipment OA flow should always be 0 when ATMixer is used
    1489            2 :                 SingleDuct::setATMixerSizingProperties(state, fanCoil.ATMixerIndex, ControlledZoneNum, state.dataSize->CurZoneEqNum);
    1490              :             }
    1491              :         }
    1492              : 
    1493           13 :         if (fanCoil.HCoilType_Num == HCoil::Water) {
    1494           10 :             IsAutoSize = false;
    1495           10 :             if (fanCoil.MaxHotWaterVolFlow == DataSizing::AutoSize) {
    1496            7 :                 IsAutoSize = true;
    1497              :             }
    1498              : 
    1499           10 :             if (state.dataSize->CurZoneEqNum > 0) {
    1500           10 :                 if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) {
    1501            0 :                     if (fanCoil.MaxHotWaterVolFlow > 0.0) {
    1502            0 :                         BaseSizer::reportSizerOutput(
    1503              :                             state, fanCoil.UnitType, fanCoil.Name, "User-Specified Maximum Hot Water Flow [m3/s]", fanCoil.MaxHotWaterVolFlow);
    1504              :                     }
    1505              :                 } else {
    1506           20 :                     state.dataFanCoilUnits->CoilWaterInletNode =
    1507           10 :                         WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", fanCoil.HCoilName, ErrorsFound);
    1508           20 :                     state.dataFanCoilUnits->CoilWaterOutletNode =
    1509           10 :                         WaterCoils::GetCoilWaterOutletNode(state, "Coil:Heating:Water", fanCoil.HCoilName, ErrorsFound);
    1510           10 :                     if (IsAutoSize) {
    1511            7 :                         int PltSizHeatNum = PlantUtilities::MyPlantSizingIndex(state,
    1512              :                                                                                "Coil:Heating:Water",
    1513              :                                                                                fanCoil.HCoilName,
    1514            7 :                                                                                state.dataFanCoilUnits->CoilWaterInletNode,
    1515            7 :                                                                                state.dataFanCoilUnits->CoilWaterOutletNode,
    1516              :                                                                                ErrorsFound);
    1517            7 :                         CoilNum = WaterCoils::GetWaterCoilIndex(state, "COIL:HEATING:WATER", fanCoil.HCoilName, ErrorsFound);
    1518              :                         bool DoWaterCoilSizing; // if TRUE do water coil sizing calculation
    1519            7 :                         if (state.dataWaterCoils->WaterCoil(CoilNum).UseDesignWaterDeltaTemp) {
    1520            0 :                             WaterCoilSizDeltaT = state.dataWaterCoils->WaterCoil(CoilNum).DesignWaterDeltaTemp;
    1521            0 :                             DoWaterCoilSizing = true;
    1522              :                         } else {
    1523            7 :                             if (PltSizHeatNum > 0) {
    1524            7 :                                 WaterCoilSizDeltaT = state.dataSize->PlantSizData(PltSizHeatNum).DeltaT;
    1525            7 :                                 DoWaterCoilSizing = true;
    1526              :                             } else {
    1527            0 :                                 DoWaterCoilSizing = false;
    1528              :                                 // If there is no heating Plant Sizing object and autosizing was requested, issue fatal error message
    1529            0 :                                 ShowSevereError(state, "Autosizing of water coil requires a heating loop Sizing:Plant object");
    1530            0 :                                 ShowContinueError(state, format("Occurs in {} Object={}", fanCoil.UnitType, fanCoil.Name));
    1531            0 :                                 ErrorsFound = true;
    1532              :                             }
    1533              :                         }
    1534            7 :                         if (DoWaterCoilSizing) {
    1535            7 :                             SizingMethod = HVAC::HeatingCapacitySizing;
    1536            7 :                             if (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatMassFlow > 0.0) {
    1537            7 :                                 state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatOAFlowFrac =
    1538            7 :                                     min(fanCoil.OutAirVolFlow / state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatMassFlow, 1.0);
    1539              :                             } else {
    1540            0 :                                 state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatOAFlowFrac = 0.0;
    1541              :                             }
    1542            7 :                             if (fanCoil.HVACSizingIndex > 0) {
    1543            0 :                                 zoneHVACIndex = fanCoil.HVACSizingIndex;
    1544            0 :                                 int CapSizingMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingCapMethod;
    1545            0 :                                 zoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
    1546            0 :                                 if (CapSizingMethod == DataSizing::HeatingDesignCapacity || CapSizingMethod == DataSizing::CapacityPerFloorArea ||
    1547              :                                     CapSizingMethod == DataSizing::FractionOfAutosizedHeatingCapacity) {
    1548            0 :                                     if (CapSizingMethod == DataSizing::HeatingDesignCapacity) {
    1549            0 :                                         if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity > 0.0) {
    1550            0 :                                             zoneEqSizing.HeatingCapacity = true;
    1551            0 :                                             zoneEqSizing.DesHeatingLoad = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
    1552              :                                         }
    1553            0 :                                         TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
    1554            0 :                                     } else if (CapSizingMethod == DataSizing::CapacityPerFloorArea) {
    1555            0 :                                         if (state.dataSize->ZoneSizingRunDone) {
    1556            0 :                                             PrintFlag = false;
    1557            0 :                                             TempSize = DataSizing::AutoSize;
    1558            0 :                                             state.dataSize->DataFlowUsedForSizing =
    1559            0 :                                                 state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
    1560            0 :                                             bool errorsFound = false;
    1561            0 :                                             HeatingCapacitySizer sizerHeatingCapacity;
    1562            0 :                                             sizerHeatingCapacity.overrideSizingString(SizingString);
    1563            0 :                                             sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1564            0 :                                             zoneEqSizing.DesHeatingLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1565            0 :                                             zoneEqSizing.HeatingCapacity = true;
    1566            0 :                                         }
    1567            0 :                                         TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity *
    1568            0 :                                                    state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1569            0 :                                         state.dataSize->DataScalableCapSizingON = true;
    1570            0 :                                     } else if (CapSizingMethod == DataSizing::FractionOfAutosizedHeatingCapacity) {
    1571            0 :                                         CheckZoneSizing(state, CompType, CompName);
    1572            0 :                                         PrintFlag = false;
    1573            0 :                                         TempSize = DataSizing::AutoSize;
    1574            0 :                                         state.dataSize->DataFlowUsedForSizing =
    1575            0 :                                             state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
    1576            0 :                                         bool errorsFound = false;
    1577            0 :                                         HeatingCapacitySizer sizerHeatingCapacity;
    1578            0 :                                         sizerHeatingCapacity.overrideSizingString(SizingString);
    1579            0 :                                         sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1580            0 :                                         zoneEqSizing.DesHeatingLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1581            0 :                                         zoneEqSizing.HeatingCapacity = true;
    1582            0 :                                         TempSize = zoneEqSizing.DesHeatingLoad * state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
    1583            0 :                                         state.dataSize->DataScalableCapSizingON = true;
    1584            0 :                                     }
    1585              :                                 }
    1586            0 :                                 SizingString = "Heating Design Capacity [W]";
    1587            0 :                                 PrintFlag = false;
    1588            0 :                                 bool errorsFound = false;
    1589            0 :                                 HeatingCapacitySizer sizerHeatingCapacity;
    1590            0 :                                 sizerHeatingCapacity.overrideSizingString(SizingString);
    1591            0 :                                 sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1592            0 :                                 DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1593            0 :                                 state.dataSize->DataScalableCapSizingON = false;
    1594            0 :                                 state.dataSize->DataFlowUsedForSizing = 0.0;
    1595              : 
    1596            0 :                             } else {
    1597            7 :                                 SizingString = "Heating Design Capacity [W]";
    1598            7 :                                 PrintFlag = false;
    1599            7 :                                 TempSize = DataSizing::AutoSize;
    1600            7 :                                 bool errorsFound = false;
    1601            7 :                                 HeatingCapacitySizer sizerHeatingCapacity;
    1602            7 :                                 sizerHeatingCapacity.overrideSizingString(SizingString);
    1603            7 :                                 sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1604            7 :                                 DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1605            7 :                             }
    1606            7 :                             fanCoil.DesHeatingLoad = DesCoilLoad;
    1607            7 :                             if (DesCoilLoad >= HVAC::SmallLoad) {
    1608            7 :                                 rho = state.dataPlnt->PlantLoop(fanCoil.HeatCoilPlantLoc.loopNum)
    1609            7 :                                           .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineNameNoSpace);
    1610            7 :                                 Cp = state.dataPlnt->PlantLoop(fanCoil.HeatCoilPlantLoc.loopNum)
    1611            7 :                                          .glycol->getSpecificHeat(state, Constant::HWInitConvTemp, RoutineNameNoSpace);
    1612              : 
    1613            7 :                                 MaxHotWaterVolFlowDes = DesCoilLoad / (WaterCoilSizDeltaT * Cp * rho);
    1614              :                             } else {
    1615            0 :                                 MaxHotWaterVolFlowDes = 0.0;
    1616              :                             }
    1617              :                         }
    1618              :                     }
    1619              :                 }
    1620              : 
    1621           10 :                 if (IsAutoSize) {
    1622            7 :                     fanCoil.MaxHotWaterVolFlow = MaxHotWaterVolFlowDes;
    1623            7 :                     BaseSizer::reportSizerOutput(
    1624              :                         state, fanCoil.UnitType, fanCoil.Name, "Design Size Maximum Hot Water Flow [m3/s]", MaxHotWaterVolFlowDes);
    1625              :                 } else { // Hard size with sizing data
    1626            3 :                     if (fanCoil.MaxHotWaterVolFlow > 0.0 && MaxHotWaterVolFlowDes > 0.0) {
    1627            0 :                         MaxHotWaterVolFlowDes = fanCoil.MaxHotWaterVolFlow;
    1628            0 :                         BaseSizer::reportSizerOutput(state,
    1629              :                                                      fanCoil.UnitType,
    1630              :                                                      fanCoil.Name,
    1631              :                                                      "Design Size Maximum Hot Water Flow [m3/s]",
    1632              :                                                      MaxHotWaterVolFlowDes,
    1633              :                                                      "User-Specified Maximum Hot Water Flow [m3/s]",
    1634              :                                                      MaxHotWaterVolFlowUser);
    1635            0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    1636            0 :                             if ((std::abs(MaxHotWaterVolFlowDes - MaxHotWaterVolFlowUser) / MaxHotWaterVolFlowUser) >
    1637            0 :                                 state.dataSize->AutoVsHardSizingThreshold) {
    1638            0 :                                 ShowMessage(
    1639              :                                     state,
    1640            0 :                                     format("SizeFanCoilUnit: Potential issue with equipment sizing for {} {}", fanCoil.UnitType, fanCoil.Name));
    1641            0 :                                 ShowContinueError(state, format("User-Specified Maximum Hot Water Flow of {:.5R} [m3/s]", MaxHotWaterVolFlowUser));
    1642            0 :                                 ShowContinueError(state,
    1643            0 :                                                   format("differs from Design Size Maximum Hot Water Flow of {:.5R} [m3/s]", MaxHotWaterVolFlowDes));
    1644            0 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1645            0 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1646              :                             }
    1647              :                         }
    1648              :                     }
    1649              :                 }
    1650              :             }
    1651            3 :         } else if (fanCoil.HCoilType_Num == HCoil::Electric) {
    1652            3 :             if (fanCoil.DesignHeatingCapacity == DataSizing::AutoSize) {
    1653            0 :                 CompName = fanCoil.HCoilName;
    1654            0 :                 CompType = fanCoil.HCoilType;
    1655            0 :                 SizingMethod = HVAC::HeatingCapacitySizing;
    1656            0 :                 PrintFlag = false;
    1657            0 :                 TempSize = fanCoil.DesignHeatingCapacity;
    1658            0 :                 SizingString = "Nominal Heating Capacity [W]";
    1659            0 :                 bool errorsFound = false;
    1660            0 :                 HeatingCapacitySizer sizerHeatingCapacity;
    1661            0 :                 sizerHeatingCapacity.overrideSizingString(SizingString);
    1662            0 :                 sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1663            0 :                 fanCoil.DesignHeatingCapacity = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1664            0 :                 fanCoil.DesHeatingLoad = fanCoil.DesignHeatingCapacity;
    1665            0 :             }
    1666              :         }
    1667              : 
    1668           13 :         IsAutoSize = false;
    1669           13 :         if (fanCoil.MaxColdWaterVolFlow == DataSizing::AutoSize) {
    1670            7 :             IsAutoSize = true;
    1671              :         }
    1672           13 :         if (state.dataSize->CurZoneEqNum > 0) {
    1673           13 :             if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) {
    1674            0 :                 if (fanCoil.MaxColdWaterVolFlow > 0.0) {
    1675            0 :                     BaseSizer::reportSizerOutput(
    1676              :                         state, fanCoil.UnitType, fanCoil.Name, "User-Specified Maximum Cold Water Flow [m3/s]", fanCoil.MaxColdWaterVolFlow);
    1677              :                 }
    1678              :             } else {
    1679           13 :                 if (Util::SameString(fanCoil.CCoilType, "CoilSystem:Cooling:Water:HeatExchangerAssisted")) {
    1680            0 :                     CoolingCoilName = HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, fanCoil.CCoilType, fanCoil.CCoilName, ErrorsFound);
    1681            0 :                     CoolingCoilType = HVACHXAssistedCoolingCoil::GetHXCoilType(state, fanCoil.CCoilType, fanCoil.CCoilName, ErrorsFound);
    1682              :                 } else {
    1683           13 :                     CoolingCoilName = fanCoil.CCoilName;
    1684           13 :                     CoolingCoilType = fanCoil.CCoilType;
    1685              :                 }
    1686           13 :                 state.dataFanCoilUnits->CoilWaterInletNode = WaterCoils::GetCoilWaterInletNode(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
    1687           26 :                 state.dataFanCoilUnits->CoilWaterOutletNode =
    1688           13 :                     WaterCoils::GetCoilWaterOutletNode(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
    1689           13 :                 if (IsAutoSize) {
    1690            7 :                     int PltSizCoolNum = PlantUtilities::MyPlantSizingIndex(state,
    1691              :                                                                            CoolingCoilType,
    1692              :                                                                            CoolingCoilName,
    1693            7 :                                                                            state.dataFanCoilUnits->CoilWaterInletNode,
    1694            7 :                                                                            state.dataFanCoilUnits->CoilWaterOutletNode,
    1695              :                                                                            ErrorsFound);
    1696            7 :                     CoilNum = WaterCoils::GetWaterCoilIndex(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
    1697              :                     bool DoWaterCoilSizing; // if TRUE do water coil sizing calculation
    1698            7 :                     if (state.dataWaterCoils->WaterCoil(CoilNum).UseDesignWaterDeltaTemp) {
    1699            0 :                         WaterCoilSizDeltaT = state.dataWaterCoils->WaterCoil(CoilNum).DesignWaterDeltaTemp;
    1700            0 :                         DoWaterCoilSizing = true;
    1701              :                     } else {
    1702            7 :                         if (PltSizCoolNum > 0) {
    1703            7 :                             WaterCoilSizDeltaT = state.dataSize->PlantSizData(PltSizCoolNum).DeltaT;
    1704            7 :                             DoWaterCoilSizing = true;
    1705              :                         } else {
    1706            0 :                             DoWaterCoilSizing = false;
    1707              :                             // If there is no cooling Plant Sizing object and autosizing was requested, issue fatal error message
    1708            0 :                             ShowSevereError(state, "Autosizing of water coil requires a cooling loop Sizing:Plant object");
    1709            0 :                             ShowContinueError(state, format("Occurs in {} Object={}", fanCoil.UnitType, fanCoil.Name));
    1710            0 :                             ErrorsFound = true;
    1711              :                         }
    1712              :                     }
    1713              : 
    1714            7 :                     if (DoWaterCoilSizing) {
    1715            7 :                         SizingMethod = HVAC::CoolingCapacitySizing;
    1716            7 :                         if (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolMassFlow > 0.0) {
    1717            7 :                             state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolOAFlowFrac =
    1718            7 :                                 min(fanCoil.OutAirVolFlow / state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolMassFlow, 1.0);
    1719              :                         } else {
    1720            0 :                             state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolOAFlowFrac = 0.0;
    1721              :                         }
    1722            7 :                         if (fanCoil.HVACSizingIndex > 0) {
    1723            0 :                             zoneHVACIndex = fanCoil.HVACSizingIndex;
    1724            0 :                             int CapSizingMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingCapMethod;
    1725            0 :                             zoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
    1726            0 :                             if (CapSizingMethod == DataSizing::CoolingDesignCapacity || CapSizingMethod == DataSizing::CapacityPerFloorArea ||
    1727              :                                 CapSizingMethod == DataSizing::FractionOfAutosizedCoolingCapacity) {
    1728            0 :                                 if (CapSizingMethod == DataSizing::CoolingDesignCapacity) {
    1729            0 :                                     if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity > 0.0) {
    1730            0 :                                         zoneEqSizing.CoolingCapacity = true;
    1731            0 :                                         zoneEqSizing.DesCoolingLoad = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
    1732              :                                     } else {
    1733            0 :                                         state.dataSize->DataFlowUsedForSizing =
    1734            0 :                                             state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
    1735              :                                     }
    1736            0 :                                     TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
    1737            0 :                                 } else if (CapSizingMethod == DataSizing::CapacityPerFloorArea) {
    1738            0 :                                     if (state.dataSize->ZoneSizingRunDone) {
    1739            0 :                                         CheckZoneSizing(state, CompType, CompName);
    1740            0 :                                         PrintFlag = false;
    1741            0 :                                         TempSize = DataSizing::AutoSize;
    1742            0 :                                         state.dataSize->DataFlowUsedForSizing =
    1743            0 :                                             state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
    1744            0 :                                         CoolingCapacitySizer sizerCoolingCapacity;
    1745            0 :                                         sizerCoolingCapacity.overrideSizingString(SizingString);
    1746            0 :                                         sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1747            0 :                                         zoneEqSizing.DesCoolingLoad = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
    1748            0 :                                         zoneEqSizing.CoolingCapacity = true;
    1749            0 :                                     }
    1750            0 :                                     TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity *
    1751            0 :                                                state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1752            0 :                                     state.dataSize->DataScalableCapSizingON = true;
    1753            0 :                                 } else if (CapSizingMethod == DataSizing::FractionOfAutosizedCoolingCapacity) {
    1754            0 :                                     PrintFlag = false;
    1755            0 :                                     TempSize = DataSizing::AutoSize;
    1756            0 :                                     state.dataSize->DataFlowUsedForSizing =
    1757            0 :                                         state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
    1758            0 :                                     CoolingCapacitySizer sizerCoolingCapacity2;
    1759            0 :                                     sizerCoolingCapacity2.overrideSizingString(SizingString);
    1760            0 :                                     sizerCoolingCapacity2.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1761            0 :                                     zoneEqSizing.DesCoolingLoad = sizerCoolingCapacity2.size(state, TempSize, ErrorsFound);
    1762            0 :                                     zoneEqSizing.CoolingCapacity = true;
    1763            0 :                                     TempSize = zoneEqSizing.DesCoolingLoad * state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
    1764            0 :                                     state.dataSize->DataScalableCapSizingON = true;
    1765            0 :                                 }
    1766              :                             }
    1767            0 :                             SizingString = "Cooling Design Capacity [W]";
    1768            0 :                             PrintFlag = false;
    1769            0 :                             CoolingCapacitySizer sizerCoolingCapacity3;
    1770            0 :                             sizerCoolingCapacity3.overrideSizingString(SizingString);
    1771            0 :                             sizerCoolingCapacity3.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1772            0 :                             DesCoilLoad = sizerCoolingCapacity3.size(state, TempSize, ErrorsFound);
    1773            0 :                             state.dataSize->DataScalableCapSizingON = false;
    1774            0 :                             state.dataSize->DataFlowUsedForSizing = 0.0;
    1775            0 :                         } else {
    1776            7 :                             SizingString = "Cooling Design Capacity [W]";
    1777            7 :                             PrintFlag = false;
    1778            7 :                             TempSize = DataSizing::AutoSize;
    1779            7 :                             state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
    1780            7 :                             CoolingCapacitySizer sizerCoolingCapacity;
    1781            7 :                             sizerCoolingCapacity.overrideSizingString(SizingString);
    1782            7 :                             sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1783            7 :                             DesCoilLoad = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
    1784            7 :                         }
    1785            7 :                         fanCoil.DesCoolingLoad = DesCoilLoad;
    1786            7 :                         if (DesCoilLoad >= HVAC::SmallLoad) {
    1787            7 :                             rho = state.dataPlnt->PlantLoop(fanCoil.CoolCoilPlantLoc.loopNum).glycol->getDensity(state, 5., RoutineNameNoSpace);
    1788            7 :                             Cp = state.dataPlnt->PlantLoop(fanCoil.CoolCoilPlantLoc.loopNum).glycol->getSpecificHeat(state, 5., RoutineNameNoSpace);
    1789            7 :                             MaxColdWaterVolFlowDes = DesCoilLoad / (WaterCoilSizDeltaT * Cp * rho);
    1790              :                         } else {
    1791            0 :                             MaxColdWaterVolFlowDes = 0.0;
    1792              :                         }
    1793              :                     }
    1794            7 :                     fanCoil.MaxColdWaterVolFlow = MaxColdWaterVolFlowDes;
    1795            7 :                     BaseSizer::reportSizerOutput(
    1796              :                         state, fanCoil.UnitType, fanCoil.Name, "Design Size Maximum Cold Water Flow [m3/s]", MaxColdWaterVolFlowDes);
    1797              :                 } else { // Hard size with sizing data
    1798            6 :                     if (fanCoil.MaxColdWaterVolFlow > 0.0 && MaxColdWaterVolFlowDes > 0.0) {
    1799            0 :                         MaxColdWaterVolFlowUser = fanCoil.MaxColdWaterVolFlow;
    1800            0 :                         BaseSizer::reportSizerOutput(state,
    1801              :                                                      fanCoil.UnitType,
    1802              :                                                      fanCoil.Name,
    1803              :                                                      "Design Size Maximum Cold Water Flow [m3/s]",
    1804              :                                                      MaxColdWaterVolFlowDes,
    1805              :                                                      "User-Specified Maximum Cold Water Flow [m3/s]",
    1806              :                                                      MaxColdWaterVolFlowUser);
    1807            0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    1808            0 :                             if ((std::abs(MaxColdWaterVolFlowDes - MaxColdWaterVolFlowUser) / MaxColdWaterVolFlowUser) >
    1809            0 :                                 state.dataSize->AutoVsHardSizingThreshold) {
    1810            0 :                                 ShowMessage(
    1811              :                                     state,
    1812            0 :                                     format("SizeFanCoilUnit: Potential issue with equipment sizing for {} {}", fanCoil.UnitType, fanCoil.Name));
    1813            0 :                                 ShowContinueError(state, format("User-Specified Maximum Cold Water Flow of {:.5R}[m3/s]", MaxColdWaterVolFlowUser));
    1814            0 :                                 ShowContinueError(state,
    1815            0 :                                                   format("differs from Design Size Maximum Cold Water Flow of {:.5R}[m3/s]", MaxColdWaterVolFlowDes));
    1816            0 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1817            0 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1818              :                             }
    1819              :                         }
    1820              :                     }
    1821              :                 }
    1822              :             }
    1823              : 
    1824           13 :             if (fanCoil.CapCtrlMeth_Num == CCM::ASHRAE && !fanCoil.ASHRAETempControl) {
    1825              : 
    1826            0 :                 CompType = fanCoil.UnitType;
    1827            0 :                 CompName = fanCoil.Name;
    1828            0 :                 PrintFlag = true;
    1829              : 
    1830            0 :                 ZoneCoolingLoadSizer sizerZoneCoolingLoad;
    1831            0 :                 sizerZoneCoolingLoad.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1832            0 :                 fanCoil.DesZoneCoolingLoad = sizerZoneCoolingLoad.size(state, fanCoil.DesZoneCoolingLoad, ErrorsFound);
    1833            0 :                 fanCoil.DesZoneCoolingLoad *= -1.0;
    1834              : 
    1835            0 :                 ZoneHeatingLoadSizer sizerZoneHeatingLoad;
    1836            0 :                 sizerZoneHeatingLoad.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1837            0 :                 fanCoil.DesZoneHeatingLoad = sizerZoneHeatingLoad.size(state, fanCoil.DesZoneHeatingLoad, ErrorsFound);
    1838              : 
    1839            0 :                 fanCoil.DSOAPtr = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneDesignSpecOAIndex;
    1840              : 
    1841           13 :             } else if (fanCoil.CapCtrlMeth_Num == CCM::ASHRAE && fanCoil.ASHRAETempControl) {
    1842              : 
    1843            1 :                 CompType = fanCoil.UnitType;
    1844            1 :                 CompName = fanCoil.Name;
    1845            1 :                 Real64 capacityMultiplier = 0.6; // 60% of design zone load for water coils
    1846            1 :                 state.dataSize->DataCapacityUsedForSizing = fanCoil.DesCoolingLoad * capacityMultiplier;
    1847            1 :                 bool SizingDesRunThisZone = false;
    1848            1 :                 CheckThisZoneForSizing(state, state.dataSize->CurZoneEqNum, SizingDesRunThisZone);
    1849            1 :                 if (SizingDesRunThisZone) {
    1850            0 :                     state.dataSize->DataCapacityUsedForSizing =
    1851            0 :                         state.dataSize->FinalZoneSizing(fanCoil.ControlZoneNum).DesCoolLoad * capacityMultiplier;
    1852              :                 } else {
    1853            1 :                     state.dataSize->DataCapacityUsedForSizing = fanCoil.DesCoolingLoad * capacityMultiplier;
    1854              :                 }
    1855            1 :                 state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
    1856            1 :                 PrintFlag = true;
    1857            1 :                 ASHRAEMinSATCoolingSizer sizerASHRAEMinSATCooling;
    1858            1 :                 sizerASHRAEMinSATCooling.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1859            1 :                 fanCoil.DesignMinOutletTemp = sizerASHRAEMinSATCooling.size(state, fanCoil.DesignMinOutletTemp, ErrorsFound);
    1860              : 
    1861            1 :                 if (SizingDesRunThisZone) {
    1862            0 :                     state.dataSize->DataCapacityUsedForSizing =
    1863            0 :                         state.dataSize->FinalZoneSizing(fanCoil.ControlZoneNum).DesHeatLoad * capacityMultiplier;
    1864              :                 } else {
    1865            1 :                     state.dataSize->DataCapacityUsedForSizing = fanCoil.DesHeatingLoad * capacityMultiplier;
    1866              :                 }
    1867            1 :                 state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
    1868            1 :                 ASHRAEMaxSATHeatingSizer sizerASHRAEMaxSATHeating;
    1869            1 :                 sizerASHRAEMaxSATHeating.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1870            1 :                 fanCoil.DesignMaxOutletTemp = sizerASHRAEMaxSATHeating.size(state, fanCoil.DesignMaxOutletTemp, ErrorsFound);
    1871              : 
    1872            1 :                 state.dataSize->DataCapacityUsedForSizing = 0.0; // reset so other routines don't use this inadvertently
    1873            1 :                 state.dataSize->DataFlowUsedForSizing = 0.0;
    1874              : 
    1875            1 :                 SizingDesRunThisZone = false;
    1876            1 :                 CheckThisZoneForSizing(state, state.dataSize->CurZoneEqNum, SizingDesRunThisZone);
    1877              : 
    1878            1 :                 if (SizingDesRunThisZone) {
    1879              : 
    1880            0 :                     fanCoil.DesZoneCoolingLoad =
    1881            0 :                         -1.0 * (fanCoil.DesCoolingLoad / state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).CoolSizingFactor);
    1882            0 :                     fanCoil.DesZoneHeatingLoad =
    1883            0 :                         fanCoil.DesHeatingLoad / state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).HeatSizingFactor;
    1884            0 :                     fanCoil.DSOAPtr = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneDesignSpecOAIndex;
    1885              : 
    1886              :                 } else {
    1887              : 
    1888            1 :                     fanCoil.DesZoneCoolingLoad = -1.0 * fanCoil.DesCoolingLoad;
    1889            1 :                     fanCoil.DesZoneHeatingLoad = fanCoil.DesHeatingLoad;
    1890              :                 }
    1891            1 :             }
    1892              : 
    1893              :         } // if ( CurZoneEqNum > 0 )
    1894              : 
    1895              :         // set the design air flow rates for the heating and cooling coils
    1896           13 :         if (Util::SameString(fanCoil.CCoilType, "CoilSystem:Cooling:Water:HeatExchangerAssisted")) {
    1897            0 :             CoolingCoilName = HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, fanCoil.CCoilType, fanCoil.CCoilName, ErrorsFound);
    1898            0 :             CoolingCoilType = HVACHXAssistedCoolingCoil::GetHXCoilType(state, fanCoil.CCoilType, fanCoil.CCoilName, ErrorsFound);
    1899              :         } else {
    1900           13 :             CoolingCoilName = fanCoil.CCoilName;
    1901           13 :             CoolingCoilType = fanCoil.CCoilType;
    1902              :         }
    1903           13 :         if (state.dataSize->ZoneSizingRunDone) {
    1904           13 :             WaterCoils::SetCoilDesFlow(
    1905           13 :                 state, CoolingCoilType, CoolingCoilName, state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow, ErrorsFound);
    1906           13 :             WaterCoils::SetCoilDesFlow(state,
    1907              :                                        fanCoil.HCoilType,
    1908           13 :                                        fanCoil.HCoilName,
    1909           13 :                                        state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow,
    1910              :                                        ErrorsFound);
    1911              :         } else {
    1912            0 :             WaterCoils::SetCoilDesFlow(state, CoolingCoilType, CoolingCoilName, fanCoil.MaxAirVolFlow, ErrorsFound);
    1913            0 :             WaterCoils::SetCoilDesFlow(state, fanCoil.HCoilType, fanCoil.HCoilName, fanCoil.MaxAirVolFlow, ErrorsFound);
    1914              :         }
    1915           13 :         if (state.dataSize->CurZoneEqNum > 0) {
    1916           13 :             zoneEqSizing.MaxHWVolFlow = fanCoil.MaxHotWaterVolFlow;
    1917           13 :             zoneEqSizing.MaxCWVolFlow = fanCoil.MaxColdWaterVolFlow;
    1918           13 :             zoneEqSizing.AirVolFlow = fanCoil.MaxAirVolFlow;
    1919           13 :             zoneEqSizing.DesCoolingLoad = fanCoil.DesCoolingLoad;
    1920           13 :             zoneEqSizing.DesHeatingLoad = fanCoil.DesHeatingLoad;
    1921           13 :             zoneEqSizing.DesignSizeFromParent = true;
    1922              :         }
    1923              : 
    1924           13 :         if (ErrorsFound) {
    1925            0 :             ShowFatalError(state, "Preceding sizing errors cause program termination");
    1926              :         }
    1927           13 :     }
    1928              : 
    1929        20349 :     void Sim4PipeFanCoil(EnergyPlusData &state,
    1930              :                          int &FanCoilNum,               // number of the current fan coil unit being simulated
    1931              :                          int const ControlledZoneNum,   // index into ZoneEqupConfig
    1932              :                          bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
    1933              :                          Real64 &PowerMet,              // Sensible power supplied (W)
    1934              :                          Real64 &LatOutputProvided      // Latent power supplied (kg/s), negative = dehumidification
    1935              :     )
    1936              :     {
    1937              : 
    1938              :         // SUBROUTINE INFORMATION:
    1939              :         //       AUTHOR         Fred Buhl
    1940              :         //       DATE WRITTEN   March 2000
    1941              :         //       MODIFIED       Don Shirey, Aug 2009 (LatOutputProvided)
    1942              :         //       MODIFIED       Arnaud Flament June 2010 (added airflow capacity control methods)
    1943              :         //       MODIFIED      R. Raustad, FSEC, Feb 2016 (added ASHRAE 90.1 SZVAV system control)
    1944              : 
    1945              :         // PURPOSE OF THIS SUBROUTINE:
    1946              :         // Simulate a 4 pipe fan coil unit; adjust its output to match the
    1947              :         // remaining zone load.
    1948              : 
    1949              :         // METHODOLOGY EMPLOYED:
    1950              :         // If unit is on, calls ControlCompOutput to obtain the desired unit output
    1951              : 
    1952              :         // REFERENCES:
    1953              :         // SZVAV sysetm control:
    1954              :         // ASHRAE 90.1 2010 Section 6.4.3.10 - Single Zone Variable-Air-volume Controls (described in Trane newsletter entitled Understanding
    1955              :         // Single-Zone VAV Systems) Trane Engineers Newsletter -
    1956              :         // https://www.trane.com/content/dam/Trane/Commercial/global/products-systems/education-training/engineers-newsletters/airside-design/admapn047en_0413.pdf
    1957              :         //
    1958              : 
    1959        20349 :         int constexpr MaxIterCycl(100);
    1960              : 
    1961              :         Real64 PLRMin;       // minimum PLR used for tighter control of air and water flow rate
    1962              :         Real64 PLRMax;       // maximum PLR used for tighter control of air and water flow rate
    1963              :         Real64 QTotUnitOut;  // total unit output [watts]
    1964              :         Real64 QUnitOutMaxC; // unit output with full active cooling [W]
    1965              :         Real64 QUnitOutMaxH; // unit output with full active heating [W]
    1966              :         Real64 SpecHumOut;   // Specific humidity ratio of outlet air (kg moisture / kg moist air)
    1967              :         Real64 SpecHumIn;    // Specific humidity ratio of inlet air (kg moisture / kg moist air)
    1968              :         Real64 DelPLR;
    1969              :         Real64 mdot;
    1970              :         // Real64 Low_mdot;
    1971              :         Real64 QSensUnitOutNoATM; // unit output not including air added by supply side air terminal mixer
    1972              :         int SolFlag;              // return flag from RegulaFalsi for sensible load
    1973              :         Real64 OAVolumeFlowRate;  // OA volume flow rate based on design specifications object [m3/s]
    1974              :         Real64 OAMassFlow;        // OA mass flow rate based on design specifications object [kg/s]
    1975              :         Real64 RhoAir;            // density of air [kg/m3]
    1976              :         Real64 MinSAMassFlowRate; // minimum supply air mass flow rate [kg/s]
    1977              :         Real64 MaxSAMassFlowRate; // maximum supply air mass flow rate [kg/s]
    1978              :         // Real64 FCOutletTempOn;        // ASHRAE outlet air temperature when coil is on [C]
    1979              :         Real64 CWFlow;       // cold water mass flow rate solution [kg/s]
    1980              :         Real64 CWFlowBypass; // cold water bypassed mass flow rate [kg/s]
    1981              : 
    1982        20349 :         auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum);
    1983              : 
    1984              :         // initialize local variables
    1985        20349 :         bool UnitOn = true;         // TRUE if unit is on
    1986        20349 :         Real64 QUnitOut = 0.0;      // heating or sens. cooling provided by fan coil unit [watts]
    1987        20349 :         Real64 QUnitOutMax = 0.0;   // heating or sens. cooling provided by fan coil unit (running during an entire timestep)
    1988        20349 :         Real64 PLR = 0.0;           // Part Load Ratio, fraction of time step fancoil is on
    1989        20349 :         Real64 LatentOutput = 0.0;  // Latent (moisture) add/removal rate, negative is dehumidification [kg/s]
    1990        20349 :         Real64 QUnitOutNoHC = 0.0;  // unit output with no active heating or cooling [W]
    1991        20349 :         Real64 QCoilHeatSP = 0.0;   // coil load to the heating setpoint [W]
    1992        20349 :         Real64 QCoilCoolSP = 0.0;   // coil load to the cooling setpoint [W]
    1993        20349 :         Real64 QZnReq = 0.0;        // heating or cooling needed by zone [watts]
    1994        20349 :         Real64 ControlOffset = 0.0; // tolerance for output control
    1995        20349 :         Real64 MaxWaterFlow = 0.0;  // maximum water flow for heating or cooling [kg/sec]
    1996        20349 :         Real64 MinWaterFlow = 0.0;  // minimum water flow for heating or cooling [kg/sec]
    1997        20349 :         int OutletNode = fanCoil.AirOutNode;
    1998        20349 :         int InletNode = fanCoil.AirInNode;
    1999        20349 :         Real64 AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate; // air mass flow rate [kg/sec]
    2000        20349 :         Real64 Error = 1.0;                                                     // Error between QZnReq and QUnitOut
    2001        20349 :         Real64 AbsError = 2.0 * HVAC::SmallLoad;                                // Absolute error between QZnReq and QUnitOut [W]   !FB
    2002        20349 :         Real64 Relax = 1.0;
    2003        20349 :         Real64 HWFlow = 0.0;         // hot water mass flow rate solution [kg/s]
    2004        20349 :         Real64 HWFlowBypass = 0.0;   // hot water bypassed mass flow rate [kg/s]
    2005        20349 :         Real64 MdotLockH = 0.0;      // saved value of locked chilled water mass flow rate [kg/s]
    2006        20349 :         Real64 MdotLockC = 0.0;      // saved value of locked hot water mass flow rate [kg/s]
    2007        20349 :         bool ColdFlowLocked = false; // if true cold water flow is locked
    2008        20349 :         bool HotFlowLocked = false;  // if true Hot water flow is locked
    2009              : 
    2010              :         // select capacity control method
    2011        20349 :         switch (fanCoil.CapCtrlMeth_Num) {
    2012           14 :         case CCM::ConsFanVarFlow: {
    2013              : 
    2014           14 :             if (AirMassFlow < HVAC::SmallMassFlow) UnitOn = false;
    2015              :             // zero the hot & cold water flows
    2016              : 
    2017              :             // set water coil flow rate to 0 to calculate coil off capacity (only valid while flow is unlocked)
    2018           14 :             mdot = 0.0;
    2019           14 :             PlantUtilities::SetComponentFlowRate(
    2020           14 :                 state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2021           14 :             if (state.dataPlnt->PlantLoop(fanCoil.CoolCoilPlantLoc.loopNum).LoopSide(fanCoil.CoolCoilPlantLoc.loopSideNum).FlowLock ==
    2022              :                 DataPlant::FlowLock::Locked) {
    2023            2 :                 ColdFlowLocked = true; // check for flow lock
    2024              :             }
    2025           14 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    2026           12 :                 mdot = 0.0;
    2027           12 :                 PlantUtilities::SetComponentFlowRate(
    2028           12 :                     state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2029           12 :                 if (state.dataPlnt->PlantLoop(fanCoil.HeatCoilPlantLoc.loopNum).LoopSide(fanCoil.HeatCoilPlantLoc.loopSideNum).FlowLock ==
    2030              :                     DataPlant::FlowLock::Locked) {
    2031            3 :                     HotFlowLocked = true; // save locked flow
    2032              :                 }
    2033              :             }
    2034              :             // obtain unit output with no active heating/cooling
    2035           14 :             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutNoHC, 0.0);
    2036              : 
    2037           14 :             if (ColdFlowLocked || HotFlowLocked) {
    2038            5 :                 QUnitOutNoHC = fanCoil.QUnitOutNoHC;
    2039              :             } else { // continue to update QUnitOutNoHC while flow is unlocked
    2040            9 :                 fanCoil.QUnitOutNoHC = QUnitOutNoHC;
    2041              :             }
    2042              : 
    2043              :             // then calculate the loads at the coils
    2044           14 :             QCoilHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP - QUnitOutNoHC;
    2045           14 :             QCoilCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP - QUnitOutNoHC;
    2046              : 
    2047              :             // if cooling
    2048           19 :             if (UnitOn && QCoilCoolSP < -HVAC::SmallLoad &&
    2049            5 :                 state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleHeat) {
    2050            5 :                 int ControlNode = fanCoil.CoolCoilFluidInletNode;
    2051            5 :                 ControlOffset = fanCoil.ColdControlOffset;
    2052            5 :                 MaxWaterFlow = fanCoil.MaxCoolCoilFluidFlow;
    2053            5 :                 MinWaterFlow = fanCoil.MinColdWaterFlow;
    2054              :                 // On the first HVAC iteration the system values are given to the controller, but after that
    2055              :                 // the demand limits are in place and there needs to be feedback to the Zone Equipment
    2056            5 :                 if (!FirstHVACIteration) {
    2057            3 :                     MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
    2058            3 :                     MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
    2059              :                 }
    2060              :                 // get full load result
    2061            5 :                 mdot = MaxWaterFlow;
    2062            5 :                 PlantUtilities::SetComponentFlowRate(
    2063            5 :                     state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2064            5 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMaxC);
    2065            5 :                 if (!ColdFlowLocked) {
    2066            3 :                     fanCoil.QUnitOutMaxC = QUnitOutMaxC;
    2067              :                 } else {
    2068            2 :                     QUnitOutMaxC = fanCoil.QUnitOutMaxC;
    2069            2 :                     MdotLockC = mdot; // save locked flow
    2070              :                 }
    2071            5 :                 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
    2072            5 :                 if (QUnitOutMaxC < QZnReq) {
    2073              :                     // more cooling than required, find reduced water flow rate to meet the load
    2074              :                     // solve for the cold water flow rate with no limit set by flow rate lockdown
    2075           51 :                     auto f = [&state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq](Real64 const CWFlow) {
    2076           48 :                         return CalcFanCoilCWLoadResidual(state, CWFlow, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq);
    2077            3 :                     };
    2078            3 :                     General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, CWFlow, f, 0.0, MaxWaterFlow);
    2079            3 :                     if (SolFlag == -1) {
    2080              :                         // tighten limits on water flow rate to see if this allows convergence
    2081            0 :                         state.dataFanCoilUnits->CoolingLoad = true;
    2082            0 :                         state.dataFanCoilUnits->HeatingLoad = false;
    2083            0 :                         TightenWaterFlowLimits(state,
    2084              :                                                FanCoilNum,
    2085            0 :                                                state.dataFanCoilUnits->CoolingLoad,
    2086            0 :                                                state.dataFanCoilUnits->HeatingLoad,
    2087              :                                                fanCoil.CoolCoilFluidInletNode,
    2088              :                                                ControlledZoneNum,
    2089              :                                                FirstHVACIteration,
    2090              :                                                QZnReq,
    2091              :                                                MinWaterFlow,
    2092              :                                                MaxWaterFlow);
    2093            0 :                         General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, CWFlow, f, MinWaterFlow, MaxWaterFlow);
    2094            0 :                         if (SolFlag == -1) {
    2095            0 :                             ++fanCoil.ConvgErrCountC;
    2096            0 :                             if (fanCoil.ConvgErrCountC < 2) {
    2097            0 :                                 ShowWarningError(state, format("Cold Water control failed in fan coil unit {}", fanCoil.Name));
    2098            0 :                                 ShowContinueError(state, "  Iteration limit exceeded in calculating water flow rate ");
    2099            0 :                                 state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate = CWFlow;
    2100            0 :                                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    2101            0 :                                 ShowContinueErrorTimeStamp(state, format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut));
    2102            0 :                                 ShowContinueErrorTimeStamp(
    2103              :                                     state,
    2104            0 :                                     format("Min water flow used during iterations = {}, Max water flow used during iterations = {}",
    2105              :                                            MinWaterFlow,
    2106              :                                            MaxWaterFlow));
    2107            0 :                                 ShowContinueErrorTimeStamp(state, format("Water flow rate on last iteration = {}", CWFlow));
    2108            0 :                                 ShowContinueErrorTimeStamp(state, "..Water flow rate set to last iteration value ");
    2109              :                             } else {
    2110            0 :                                 ShowRecurringWarningErrorAtEnd(
    2111            0 :                                     state, "Cold water flow Iteration limit exceeded in fan coil unit " + fanCoil.Name, fanCoil.MaxIterIndexC);
    2112              :                             }
    2113            0 :                         } else if (SolFlag == -2) {
    2114            0 :                             ++fanCoil.LimitErrCountC;
    2115            0 :                             if (fanCoil.LimitErrCountC < 2) {
    2116            0 :                                 ShowWarningError(state, format("Cold Water control failed in fan coil unit {}", fanCoil.Name));
    2117            0 :                                 ShowContinueError(state, "  Bad cold water mass flow limits");
    2118            0 :                                 ShowContinueErrorTimeStamp(state, "..Water flow rate set to lower limit ");
    2119              :                             } else {
    2120            0 :                                 ShowRecurringWarningErrorAtEnd(
    2121            0 :                                     state, "Cold Water control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexC);
    2122              :                             }
    2123              :                         }
    2124            3 :                     } else if (SolFlag == -2) {
    2125            0 :                         ++fanCoil.LimitErrCountC;
    2126            0 :                         if (fanCoil.LimitErrCountC < 2) {
    2127            0 :                             ShowWarningError(state, format("Cold Water control failed in fan coil unit {}", fanCoil.Name));
    2128            0 :                             ShowContinueError(state, "  Bad cold water mass flow limits");
    2129            0 :                             ShowContinueErrorTimeStamp(state, "..Water flow rate set to lower limit ");
    2130              :                         } else {
    2131            0 :                             ShowRecurringWarningErrorAtEnd(
    2132            0 :                                 state, "Cold Water control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexC);
    2133              :                         }
    2134              :                     }
    2135              :                 } else {
    2136              :                     // demand greater than capacity
    2137            2 :                     CWFlow = MaxWaterFlow;
    2138              :                 }
    2139            5 :                 if (!ColdFlowLocked) {
    2140            3 :                     mdot = CWFlow; // not flowlocked - set flow to CWFlow
    2141            3 :                     PlantUtilities::SetComponentFlowRate(
    2142            3 :                         state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2143            3 :                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); // get QUnitOut
    2144              :                 } else {
    2145              :                     // flow lock on
    2146            2 :                     if (MdotLockC > CWFlow) { // if mdot > CWFlow, bypass extra flow
    2147            1 :                         Calc4PipeFanCoil(state,
    2148              :                                          FanCoilNum,
    2149              :                                          ControlledZoneNum,
    2150              :                                          FirstHVACIteration,
    2151              :                                          QUnitOut); // get QUnitOut with CWFlow; rest will be bypassed
    2152            1 :                         state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate =
    2153              :                             MdotLockC; // reset flow to locked value. Since lock is on, must do this by hand
    2154            1 :                         state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).MassFlowRate = MdotLockC;
    2155              :                         // Keep soln flow rate but reset outlet water temperature - i.e. bypass extra water
    2156            1 :                         CWFlowBypass = MdotLockC - CWFlow;
    2157              :                         // change water outlet temperature and enthalpy
    2158            1 :                         state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).Temp =
    2159            1 :                             (CWFlowBypass * state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).Temp +
    2160            1 :                              CWFlow * state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).Temp) /
    2161              :                             MdotLockC;
    2162            1 :                         state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).Enthalpy =
    2163            1 :                             (CWFlowBypass * state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).Enthalpy +
    2164            1 :                              CWFlow * state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).Enthalpy) /
    2165              :                             MdotLockC;
    2166              :                     } else {
    2167              :                         // if MdotLockC <= CWFlow use MdotLockC as is
    2168            1 :                         state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate =
    2169              :                             MdotLockC; // reset flow to locked value. Since lock is on, must do this by hand
    2170            1 :                         state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).MassFlowRate = MdotLockC;
    2171            1 :                         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    2172              :                     }
    2173              :                 }
    2174            5 :                 QUnitOut = calcZoneSensibleOutput(AirMassFlow,
    2175            5 :                                                   state.dataLoopNodes->Node(OutletNode).Temp,
    2176            5 :                                                   state.dataLoopNodes->Node(InletNode).Temp,
    2177            5 :                                                   state.dataLoopNodes->Node(InletNode).HumRat);
    2178              : 
    2179              :                 // if heating
    2180           18 :             } else if (UnitOn && QCoilHeatSP > HVAC::SmallLoad &&
    2181            9 :                        state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleCool) {
    2182              :                 // get full load result
    2183            9 :                 if (fanCoil.HCoilType_Num == HCoil::Water) { // if HW Coil
    2184            7 :                     int ControlNode = fanCoil.HeatCoilFluidInletNode;
    2185            7 :                     ControlOffset = fanCoil.HotControlOffset;
    2186            7 :                     MaxWaterFlow = fanCoil.MaxHeatCoilFluidFlow;
    2187            7 :                     MinWaterFlow = fanCoil.MinHotWaterFlow;
    2188              :                     // On the first HVAC iteration the system values are given to the controller, but after that
    2189              :                     // the demand limits are in place and there needs to be feedback to the Zone Equipment
    2190            7 :                     if (!FirstHVACIteration) {
    2191            6 :                         MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
    2192            6 :                         MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
    2193              :                     }
    2194            7 :                     mdot = MaxWaterFlow;
    2195            7 :                     PlantUtilities::SetComponentFlowRate(
    2196            7 :                         state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2197            7 :                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMaxH);
    2198            7 :                     if (!HotFlowLocked) {
    2199            4 :                         fanCoil.QUnitOutMaxH = QUnitOutMaxH;
    2200              :                     } else {
    2201            3 :                         QUnitOutMaxH = fanCoil.QUnitOutMaxH;
    2202            3 :                         MdotLockH = mdot; // save locked flow
    2203              :                     }
    2204              :                 } else {
    2205              :                     // not HW coil
    2206            2 :                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMaxH, 1.0);
    2207              :                 }
    2208            9 :                 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
    2209            9 :                 if (QUnitOutMaxH > QZnReq) {
    2210              :                     // more heating than required, find reduced water flow rate to meet the load
    2211            7 :                     if (fanCoil.HCoilType_Num == HCoil::Water) {
    2212              :                         // solve for the hot water flow rate with no limit set by flow rate lockdown
    2213          102 :                         auto f = [&state, FirstHVACIteration, FanCoilNum, ControlledZoneNum, QZnReq](Real64 HWFlow) {
    2214              :                             // To calculate the part-load ratio for the FCU with electric heating coil
    2215              :                             Real64 QUnitOut; // delivered capacity [W]
    2216           96 :                             state.dataLoopNodes->Node(state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatCoilFluidInletNode).MassFlowRate = HWFlow;
    2217           96 :                             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, 1.0);
    2218              :                             // Calculate residual based on output magnitude
    2219           96 :                             if (std::abs(QZnReq) <= 100.0) {
    2220           12 :                                 return (QUnitOut - QZnReq) / 100.0;
    2221              :                             } else {
    2222           84 :                                 return (QUnitOut - QZnReq) / QZnReq;
    2223              :                             }
    2224            6 :                         };
    2225            6 :                         General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, HWFlow, f, 0.0, MaxWaterFlow);
    2226            6 :                         if (SolFlag == -1) {
    2227              :                             // tighten limits on water flow rate to see if this allows convergence
    2228            0 :                             state.dataFanCoilUnits->CoolingLoad = false;
    2229            0 :                             state.dataFanCoilUnits->HeatingLoad = true;
    2230            0 :                             TightenWaterFlowLimits(state,
    2231              :                                                    FanCoilNum,
    2232            0 :                                                    state.dataFanCoilUnits->CoolingLoad,
    2233            0 :                                                    state.dataFanCoilUnits->HeatingLoad,
    2234              :                                                    fanCoil.HeatCoilFluidInletNode,
    2235              :                                                    ControlledZoneNum,
    2236              :                                                    FirstHVACIteration,
    2237              :                                                    QZnReq,
    2238              :                                                    MinWaterFlow,
    2239              :                                                    MaxWaterFlow);
    2240            0 :                             General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, HWFlow, f, MinWaterFlow, MaxWaterFlow);
    2241            0 :                             if (SolFlag == -1) {
    2242            0 :                                 ++fanCoil.ConvgErrCountH;
    2243            0 :                                 if (fanCoil.ConvgErrCountH < 2) {
    2244            0 :                                     ShowWarningError(state, format("Hot Water control failed in fan coil unit {}", fanCoil.Name));
    2245            0 :                                     ShowContinueError(state, "  Iteration limit exceeded in calculating water flow rate ");
    2246            0 :                                     state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).MassFlowRate = HWFlow;
    2247            0 :                                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    2248            0 :                                     ShowContinueErrorTimeStamp(state, format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut));
    2249            0 :                                     ShowContinueErrorTimeStamp(
    2250              :                                         state,
    2251            0 :                                         format("Min water flow used during iterations = {}, Max water flow used during iterations = {}",
    2252              :                                                MinWaterFlow,
    2253              :                                                MaxWaterFlow));
    2254            0 :                                     ShowContinueErrorTimeStamp(state, format("Water flow rate on last iteration = {}", HWFlow));
    2255            0 :                                     ShowContinueErrorTimeStamp(state, "..Water flow rate set to last iteration value ");
    2256              :                                 } else {
    2257            0 :                                     ShowRecurringWarningErrorAtEnd(
    2258            0 :                                         state, "Hot water flow Iteration limit exceeded in fan coil unit " + fanCoil.Name, fanCoil.MaxIterIndexH);
    2259              :                                 }
    2260            0 :                             } else if (SolFlag == -2) {
    2261            0 :                                 ++fanCoil.LimitErrCountH;
    2262            0 :                                 if (fanCoil.LimitErrCountH < 2) {
    2263            0 :                                     ShowWarningError(state, format("Hot Water control failed in fan coil unit {}", fanCoil.Name));
    2264            0 :                                     ShowContinueError(state, "  Bad hot water mass flow limits");
    2265            0 :                                     ShowContinueErrorTimeStamp(state, "..Water flow rate set to lower limit ");
    2266              :                                 } else {
    2267            0 :                                     ShowRecurringWarningErrorAtEnd(
    2268            0 :                                         state, "Hot Water control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexH);
    2269              :                                 }
    2270              :                             }
    2271            6 :                         } else if (SolFlag == -2) {
    2272            0 :                             ++fanCoil.LimitErrCountH;
    2273            0 :                             if (fanCoil.LimitErrCountH < 2) {
    2274            0 :                                 ShowWarningError(state, format("Hot Water control failed in fan coil unit {}", fanCoil.Name));
    2275            0 :                                 ShowContinueError(state, "  Bad hot water mass flow limits");
    2276            0 :                                 ShowContinueErrorTimeStamp(state, "..Water flow rate set to lower limit ");
    2277              :                             } else {
    2278            0 :                                 ShowRecurringWarningErrorAtEnd(
    2279            0 :                                     state, "Hot Water control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexH);
    2280              :                             }
    2281              :                         }
    2282              :                     } else {
    2283            4 :                         auto f = [&state, FirstHVACIteration, FanCoilNum, ControlledZoneNum, QZnReq](Real64 const PartLoadRatio) {
    2284            3 :                             return CalcFanCoilLoadResidual(state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq, PartLoadRatio);
    2285            1 :                         };
    2286            1 :                         General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, 0.0, 1.0);
    2287              :                     }
    2288              :                 } else {
    2289              :                     // demand greater than capacity
    2290            2 :                     if (fanCoil.HCoilType_Num == HCoil::Water) {
    2291            1 :                         HWFlow = MaxWaterFlow;
    2292              :                     } else {
    2293            1 :                         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, 1.0);
    2294              :                     }
    2295              :                 }
    2296            9 :                 if (fanCoil.HCoilType_Num == HCoil::Water) {
    2297            7 :                     if (!HotFlowLocked) {
    2298            4 :                         mdot = HWFlow; // not flowlocked - set flow to HWFlow
    2299            4 :                         PlantUtilities::SetComponentFlowRate(
    2300            4 :                             state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2301            4 :                         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); // get QUnitOut
    2302              :                     } else {
    2303              :                         // flow lock on
    2304            3 :                         if (MdotLockH > HWFlow) { // if mdot > HWFlow, bypass extra flow
    2305            1 :                             Calc4PipeFanCoil(state,
    2306              :                                              FanCoilNum,
    2307              :                                              ControlledZoneNum,
    2308              :                                              FirstHVACIteration,
    2309              :                                              QUnitOut); // get QUnitOut with HWFlow; rest will be bypassed
    2310            1 :                             state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).MassFlowRate =
    2311              :                                 MdotLockH; // reset flow to locked value. Since lock is on, must do this by hand
    2312            1 :                             state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).MassFlowRate = MdotLockH;
    2313              :                             // Keep soln flow rate but reset outlet water temperature - i.e. bypass extra water
    2314            1 :                             HWFlowBypass = MdotLockH - HWFlow;
    2315              :                             // change outlet water temperature and enthalpy
    2316            1 :                             state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).Temp =
    2317            1 :                                 (HWFlowBypass * state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).Temp +
    2318            1 :                                  HWFlow * state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).Temp) /
    2319              :                                 MdotLockH;
    2320            1 :                             state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).Enthalpy =
    2321            1 :                                 (HWFlowBypass * state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).Enthalpy +
    2322            1 :                                  HWFlow * state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).Enthalpy) /
    2323              :                                 MdotLockH;
    2324              :                         } else {
    2325              :                             // if MdotLockH <= HWFlow use MdotLockH as is
    2326            2 :                             state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).MassFlowRate =
    2327              :                                 MdotLockH; // reset flow to locked value. Since lock is on, must do this by hand
    2328            2 :                             state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).MassFlowRate = MdotLockH;
    2329            2 :                             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    2330              :                         }
    2331              :                     }
    2332              :                 }
    2333            9 :                 QUnitOut = calcZoneSensibleOutput(AirMassFlow,
    2334            9 :                                                   state.dataLoopNodes->Node(OutletNode).Temp,
    2335            9 :                                                   state.dataLoopNodes->Node(InletNode).Temp,
    2336            9 :                                                   state.dataLoopNodes->Node(InletNode).HumRat);
    2337              :             } else {
    2338              :                 // no action
    2339            0 :                 QUnitOut = QUnitOutNoHC;
    2340              :             }
    2341              : 
    2342              :             // CR9155 Remove specific humidity calculations
    2343           14 :             SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
    2344           14 :             SpecHumIn = state.dataLoopNodes->Node(InletNode).HumRat;
    2345           14 :             LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
    2346           14 :             QTotUnitOut = AirMassFlow * (state.dataLoopNodes->Node(OutletNode).Enthalpy - state.dataLoopNodes->Node(InletNode).Enthalpy);
    2347              :             // report variables
    2348           14 :             fanCoil.HeatPower = max(0.0, QUnitOut);
    2349           14 :             fanCoil.SensCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QUnitOut));
    2350           14 :             fanCoil.TotCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QTotUnitOut));
    2351           14 :             fanCoil.ElecPower = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    2352              : 
    2353           14 :             PowerMet = QUnitOut;
    2354           14 :             LatOutputProvided = LatentOutput;
    2355              : 
    2356              :             // cycling fan constant water flow AND VarFanVarFlow
    2357           14 :         } break;
    2358        20316 :         case CCM::CycFan:
    2359              :         case CCM::VarFanVarFlow: {
    2360              : 
    2361        20316 :             if (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ControlledZoneNum) || AirMassFlow < HVAC::SmallMassFlow) UnitOn = false;
    2362              : 
    2363              :             // zero the hot & cold water flows
    2364        20316 :             mdot = 0.0;
    2365        20316 :             PlantUtilities::SetComponentFlowRate(
    2366        20316 :                 state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2367        20316 :             if (state.dataPlnt->PlantLoop(fanCoil.CoolCoilPlantLoc.loopNum).LoopSide(fanCoil.CoolCoilPlantLoc.loopSideNum).FlowLock ==
    2368              :                 DataPlant::FlowLock::Locked) {
    2369            0 :                 ColdFlowLocked = true; // check for flow lock
    2370              :             }
    2371        20316 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    2372        20316 :                 mdot = 0.0;
    2373        20316 :                 PlantUtilities::SetComponentFlowRate(
    2374        20316 :                     state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2375        20316 :                 if (state.dataPlnt->PlantLoop(fanCoil.HeatCoilPlantLoc.loopNum).LoopSide(fanCoil.HeatCoilPlantLoc.loopSideNum).FlowLock ==
    2376              :                     DataPlant::FlowLock::Locked) {
    2377            0 :                     HotFlowLocked = true; // save locked flow
    2378              :                 }
    2379              :             }
    2380              : 
    2381              :             // obtain unit output with no active heating/cooling
    2382        20316 :             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutNoHC, 0.0);
    2383              : 
    2384              :             // get the loads at the coil
    2385        20316 :             QCoilHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP - QUnitOutNoHC;
    2386        20316 :             QCoilCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP - QUnitOutNoHC;
    2387              : 
    2388              :             // speed fan selection only for multispeed cycling fan
    2389        20316 :             if (UnitOn && (fanCoil.CapCtrlMeth_Num == CCM::CycFan)) {
    2390        13063 :                 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputRequired;
    2391              : 
    2392              :                 // set water side mass flow rate
    2393        13063 :                 if (QCoilCoolSP < 0) {
    2394         5962 :                     state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate = fanCoil.MaxCoolCoilFluidFlow;
    2395         7101 :                 } else if (QCoilHeatSP > 0 && fanCoil.HCoilType_Num != HCoil::Electric) {
    2396         7101 :                     state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).MassFlowRate = fanCoil.MaxHeatCoilFluidFlow;
    2397              :                 }
    2398              : 
    2399        13063 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    2400        13063 :                 fanCoil.SpeedFanSel = 1;
    2401        13063 :                 fanCoil.SpeedFanRatSel = fanCoil.LowSpeedRatio;
    2402        13063 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
    2403        13063 :                 if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
    2404        10734 :                     state.dataLoopNodes->Node(InletNode).MassFlowRateMax = fanCoil.MedSpeedRatio * fanCoil.MaxAirMassFlow;
    2405        10734 :                     fanCoil.SpeedFanSel = 2;
    2406        10734 :                     fanCoil.SpeedFanRatSel = fanCoil.MedSpeedRatio;
    2407        10734 :                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
    2408              :                 }
    2409        17587 :                 if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
    2410         4524 :                     fanCoil.SpeedFanSel = 3;
    2411         4524 :                     fanCoil.SpeedFanRatSel = 1.0;
    2412         4524 :                     state.dataLoopNodes->Node(InletNode).MassFlowRateMax = fanCoil.MaxAirMassFlow;
    2413              :                 }
    2414              :             } else {
    2415         7253 :                 fanCoil.SpeedFanSel = 0;
    2416              :             }
    2417              : 
    2418              :             // meet the coil load adjusted for fan operation
    2419        26279 :             if (UnitOn && QCoilCoolSP < (-1.0 * HVAC::SmallLoad) &&
    2420         5963 :                 state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleHeat) {
    2421              :                 // cooling coil action, maximum cold water flow
    2422         5963 :                 mdot = fanCoil.MaxCoolCoilFluidFlow;
    2423         5963 :                 PlantUtilities::SetComponentFlowRate(
    2424         5963 :                     state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2425              : 
    2426         5963 :                 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
    2427         5963 :                 ControlOffset = fanCoil.ColdControlOffset;
    2428              : 
    2429              :                 // get the maximum output of the fcu
    2430         5963 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax); // call without PLR means PLR = 1
    2431              : 
    2432         5963 :                 if (QUnitOutMax < QZnReq) {
    2433              :                     // more cooling than required, find reduced air and water flow rate to meet the load
    2434              :                     // solve for the cold water flow rate with no limit set by flow rate lockdown
    2435        32446 :                     auto f = [&state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq](Real64 const PLR) {
    2436        79449 :                         return CalcFanCoilPLRResidual(state,
    2437              :                                                       PLR,
    2438              :                                                       FanCoilNum,
    2439              :                                                       FirstHVACIteration,
    2440              :                                                       ControlledZoneNum,
    2441        26483 :                                                       state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode,
    2442        26483 :                                                       QZnReq);
    2443         5963 :                     };
    2444         5963 :                     General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, 0.0, 1.0);
    2445         5963 :                     if (SolFlag == -1) {
    2446              :                         // tighten limits on water flow rate to see if this allows convergence
    2447            0 :                         state.dataFanCoilUnits->CoolingLoad = true;
    2448            0 :                         state.dataFanCoilUnits->HeatingLoad = false;
    2449            0 :                         TightenAirAndWaterFlowLimits(state,
    2450              :                                                      FanCoilNum,
    2451            0 :                                                      state.dataFanCoilUnits->CoolingLoad,
    2452            0 :                                                      state.dataFanCoilUnits->HeatingLoad,
    2453              :                                                      fanCoil.CoolCoilFluidInletNode,
    2454              :                                                      ControlledZoneNum,
    2455              :                                                      FirstHVACIteration,
    2456              :                                                      QZnReq,
    2457              :                                                      PLRMin,
    2458              :                                                      PLRMax);
    2459            0 :                         General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, PLRMin, PLRMax);
    2460            0 :                         if (SolFlag == -1) {
    2461            0 :                             ++fanCoil.ConvgErrCountC;
    2462            0 :                             if (fanCoil.ConvgErrCountC < 2) {
    2463            0 :                                 ShowWarningError(state, format("Part-load ratio cooling control failed in fan coil unit {}", fanCoil.Name));
    2464            0 :                                 ShowContinueError(state, "  Iteration limit exceeded in calculating FCU part-load ratio ");
    2465            0 :                                 state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate = PLR * fanCoil.MaxCoolCoilFluidFlow;
    2466            0 :                                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2467            0 :                                 ShowContinueErrorTimeStamp(state, format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut));
    2468            0 :                                 ShowContinueErrorTimeStamp(
    2469              :                                     state,
    2470            0 :                                     format("Min part-load used during iterations = {}, Max part-load used during iterations = {}", PLRMin, PLRMax));
    2471            0 :                                 ShowContinueErrorTimeStamp(state, format("Part-load ratio on last iteration = {}", PLR));
    2472            0 :                                 ShowContinueErrorTimeStamp(state, "..Part-load ratio set to last iteration value ");
    2473              :                             } else {
    2474            0 :                                 ShowRecurringWarningErrorAtEnd(state,
    2475            0 :                                                                "Part-load ratio cooling iteration limit exceeded in fan coil unit " + fanCoil.Name,
    2476            0 :                                                                fanCoil.MaxIterIndexC);
    2477              :                             }
    2478            0 :                         } else if (SolFlag == -2) {
    2479            0 :                             ++fanCoil.LimitErrCountC;
    2480            0 :                             if (fanCoil.LimitErrCountC < 2) {
    2481            0 :                                 ShowWarningError(state, format("Part-load ratio cooling control failed in fan coil unit {}", fanCoil.Name));
    2482            0 :                                 ShowContinueError(state, "  Bad part-load ratio limits");
    2483            0 :                                 ShowContinueErrorTimeStamp(state, format("..Part-load ratio set to {}", PLRMin));
    2484              :                             } else {
    2485            0 :                                 ShowRecurringWarningErrorAtEnd(
    2486            0 :                                     state, "Part-load ratio cooling control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexC);
    2487              :                             }
    2488              :                         }
    2489         5963 :                     } else if (SolFlag == -2) {
    2490            0 :                         ++fanCoil.LimitErrCountC;
    2491            0 :                         if (fanCoil.LimitErrCountC < 2) {
    2492            0 :                             ShowWarningError(state, format("Part-load ratio control failed in fan coil unit {}", fanCoil.Name));
    2493            0 :                             ShowContinueError(state, "  Bad part-load ratio limits");
    2494            0 :                             ShowContinueErrorTimeStamp(state, "..Part-load ratio set to 0");
    2495              :                         } else {
    2496            0 :                             ShowRecurringWarningErrorAtEnd(
    2497            0 :                                 state, "Part-load ratio control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexC);
    2498              :                         }
    2499              :                     }
    2500         5963 :                     mdot = PLR * fanCoil.MaxCoolCoilFluidFlow;
    2501         5963 :                     PlantUtilities::SetComponentFlowRate(
    2502         5963 :                         state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2503              :                 } else {
    2504            0 :                     PLR = 1.0;
    2505            0 :                     mdot = PLR * fanCoil.MaxCoolCoilFluidFlow;
    2506            0 :                     PlantUtilities::SetComponentFlowRate(
    2507            0 :                         state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2508              :                 }
    2509              : 
    2510              :                 // at the end calculate output
    2511         5963 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2512              : 
    2513        21456 :             } else if (UnitOn && QCoilHeatSP > HVAC::SmallLoad &&
    2514         7103 :                        state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleCool) {
    2515              :                 // heating coil action, maximun hot water flow
    2516              : 
    2517         7103 :                 if (fanCoil.HCoilType_Num == HCoil::Water) {
    2518         7103 :                     mdot = fanCoil.MaxHeatCoilFluidFlow;
    2519         7103 :                     PlantUtilities::SetComponentFlowRate(
    2520         7103 :                         state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2521              :                 }
    2522              : 
    2523         7103 :                 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
    2524         7103 :                 ControlOffset = fanCoil.HotControlOffset;
    2525              : 
    2526              :                 // get the maximum output of the fcu
    2527         7103 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
    2528              :                 // calculate the PLR, if load greater than output, PLR = 1 (output = max)
    2529         7103 :                 if (QUnitOutMax > QZnReq) {
    2530              :                     // more heating than required, find reduced water flow rate to meet the load
    2531         5817 :                     if (fanCoil.HCoilType_Num == HCoil::Water) {
    2532              :                         // solve for the hot water flow rate with no limit set by flow rate lockdown
    2533        32216 :                         auto f = [&state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq](Real64 const PLR) {
    2534        79197 :                             return CalcFanCoilPLRResidual(state,
    2535              :                                                           PLR,
    2536              :                                                           FanCoilNum,
    2537              :                                                           FirstHVACIteration,
    2538              :                                                           ControlledZoneNum,
    2539        26399 :                                                           state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatCoilFluidInletNode,
    2540        26399 :                                                           QZnReq);
    2541         5817 :                         };
    2542         5817 :                         General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, 0.0, 1.0);
    2543         5817 :                         if (SolFlag == -1) {
    2544              :                             // tighten limits on water flow rate to see if this allows convergence
    2545            0 :                             state.dataFanCoilUnits->CoolingLoad = false;
    2546            0 :                             state.dataFanCoilUnits->HeatingLoad = true;
    2547            0 :                             TightenAirAndWaterFlowLimits(state,
    2548              :                                                          FanCoilNum,
    2549            0 :                                                          state.dataFanCoilUnits->CoolingLoad,
    2550            0 :                                                          state.dataFanCoilUnits->HeatingLoad,
    2551              :                                                          fanCoil.HeatCoilFluidInletNode,
    2552              :                                                          ControlledZoneNum,
    2553              :                                                          FirstHVACIteration,
    2554              :                                                          QZnReq,
    2555              :                                                          PLRMin,
    2556              :                                                          PLRMax);
    2557            0 :                             General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, PLRMin, PLRMax);
    2558            0 :                             if (SolFlag == -1) {
    2559            0 :                                 ++fanCoil.ConvgErrCountH;
    2560            0 :                                 if (fanCoil.ConvgErrCountH < 2) {
    2561            0 :                                     ShowWarningError(state, format("Part-load ratio heating control failed in fan coil unit {}", fanCoil.Name));
    2562            0 :                                     ShowContinueError(state, "  Iteration limit exceeded in calculating FCU part-load ratio ");
    2563            0 :                                     state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).MassFlowRate = PLR * fanCoil.MaxHeatCoilFluidFlow;
    2564            0 :                                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2565            0 :                                     ShowContinueErrorTimeStamp(state, format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut));
    2566            0 :                                     ShowContinueErrorTimeStamp(
    2567              :                                         state,
    2568            0 :                                         format("Min part-load ratio used during iterations = {}, Max part-load used during iterations = {}",
    2569              :                                                PLRMin,
    2570              :                                                PLRMax));
    2571            0 :                                     ShowContinueErrorTimeStamp(state, format("Part-load ratio on last iteration = {}", PLR));
    2572            0 :                                     ShowContinueErrorTimeStamp(state, "..Part-load ratio set to last iteration value ");
    2573              :                                 } else {
    2574            0 :                                     ShowRecurringWarningErrorAtEnd(state,
    2575            0 :                                                                    "Part-load ratio heating iteration limit exceeded in fan coil unit " +
    2576            0 :                                                                        fanCoil.Name,
    2577            0 :                                                                    fanCoil.MaxIterIndexH);
    2578              :                                 }
    2579            0 :                             } else if (SolFlag == -2) {
    2580            0 :                                 ++fanCoil.LimitErrCountH;
    2581            0 :                                 if (fanCoil.LimitErrCountH < 2) {
    2582            0 :                                     ShowWarningError(state, format("Part-load ratio heating control failed in fan coil unit {}", fanCoil.Name));
    2583            0 :                                     ShowContinueError(state, "  Bad hot part-load ratio limits");
    2584            0 :                                     ShowContinueErrorTimeStamp(state, format("..Part-load ratio set to {}", PLRMin));
    2585              :                                 } else {
    2586            0 :                                     ShowRecurringWarningErrorAtEnd(state,
    2587            0 :                                                                    "Part-load ratio heating control failed in fan coil unit " + fanCoil.Name,
    2588            0 :                                                                    fanCoil.BadMassFlowLimIndexH);
    2589              :                                 }
    2590              :                             }
    2591         5817 :                         } else if (SolFlag == -2) {
    2592            0 :                             ++fanCoil.LimitErrCountH;
    2593            0 :                             if (fanCoil.LimitErrCountH < 2) {
    2594            0 :                                 ShowWarningError(state, format("Part-load ratio heating control failed in fan coil unit {}", fanCoil.Name));
    2595            0 :                                 ShowContinueError(state, "  Bad part-load ratio limits");
    2596            0 :                                 ShowContinueErrorTimeStamp(state, "..Part-load ratio set to 0");
    2597              :                             } else {
    2598            0 :                                 ShowRecurringWarningErrorAtEnd(
    2599            0 :                                     state, "Part-load ratio heating control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexH);
    2600              :                             }
    2601              :                         }
    2602         5817 :                         HWFlow = PLR * fanCoil.MaxHeatCoilFluidFlow;
    2603         5817 :                         PlantUtilities::SetComponentFlowRate(
    2604         5817 :                             state, HWFlow, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2605              : 
    2606              :                     } else {
    2607            0 :                         auto f = [&state, FirstHVACIteration, FanCoilNum, ControlledZoneNum, QZnReq](Real64 const PartLoadRatio) {
    2608            0 :                             return CalcFanCoilLoadResidual(state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq, PartLoadRatio);
    2609            0 :                         };
    2610            0 :                         General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, 0.0, 1.0);
    2611              :                     }
    2612              :                 } else {
    2613         1286 :                     PLR = 1.0;
    2614         1286 :                     if (fanCoil.HCoilType_Num == HCoil::Water) {
    2615         1286 :                         mdot = PLR * fanCoil.MaxHeatCoilFluidFlow;
    2616         1286 :                         PlantUtilities::SetComponentFlowRate(
    2617         1286 :                             state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2618              :                     }
    2619              :                 }
    2620              : 
    2621              :                 // at the end calculate output with adjusted PLR
    2622         7103 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2623              : 
    2624              :             } else {
    2625              :                 // no action, zero the air flow rate, the unit is off
    2626         7250 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
    2627         7250 :                 state.dataLoopNodes->Node(OutletNode).MassFlowRate = 0.0;
    2628         7250 :                 fanCoil.SpeedFanSel = 0;
    2629         7250 :                 PLR = 0.0;
    2630         7250 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2631              :             }
    2632              : 
    2633        20316 :             AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    2634              :             // CR9155 Remove specific humidity calculations
    2635        20316 :             SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
    2636        20316 :             SpecHumIn = state.dataLoopNodes->Node(InletNode).HumRat;
    2637        20316 :             LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
    2638        20316 :             QTotUnitOut = AirMassFlow * (state.dataLoopNodes->Node(OutletNode).Enthalpy - state.dataLoopNodes->Node(InletNode).Enthalpy);
    2639              :             // report variables
    2640        20316 :             fanCoil.HeatPower = max(0.0, QUnitOut);
    2641        20316 :             fanCoil.SensCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QUnitOut));
    2642        20316 :             fanCoil.TotCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QTotUnitOut));
    2643        20316 :             fanCoil.ElecPower = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    2644              : 
    2645        20316 :             fanCoil.PLR = PLR;
    2646        20316 :             PowerMet = QUnitOut;
    2647        20316 :             LatOutputProvided = LatentOutput;
    2648              : 
    2649        20316 :         } break;
    2650           10 :         case CCM::ASHRAE: {
    2651              : 
    2652           10 :             if (AirMassFlow < HVAC::SmallMassFlow) UnitOn = false;
    2653              : 
    2654              :             //  zero the hot & cold water flows
    2655           10 :             mdot = 0.0;
    2656           10 :             PlantUtilities::SetComponentFlowRate(
    2657           10 :                 state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2658              : 
    2659           10 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    2660            7 :                 mdot = 0.0;
    2661            7 :                 PlantUtilities::SetComponentFlowRate(
    2662            7 :                     state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2663              :             }
    2664              : 
    2665           10 :             OAMassFlow = 0.0;
    2666              : 
    2667              :             // determine minimum outdoor air flow rate
    2668           10 :             if (fanCoil.DSOAPtr > 0 && fanCoil.OutsideAirNode > 0) {
    2669            0 :                 OAVolumeFlowRate = DataSizing::calcDesignSpecificationOutdoorAir(state, fanCoil.DSOAPtr, ControlledZoneNum, true, true);
    2670            0 :                 RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state,
    2671            0 :                                                            state.dataLoopNodes->Node(fanCoil.OutsideAirNode).Press,
    2672            0 :                                                            state.dataLoopNodes->Node(fanCoil.OutsideAirNode).Temp,
    2673            0 :                                                            state.dataLoopNodes->Node(fanCoil.OutsideAirNode).HumRat);
    2674            0 :                 OAMassFlow = OAVolumeFlowRate * RhoAir;
    2675              :             }
    2676              : 
    2677           10 :             MinSAMassFlowRate = min(max(OAMassFlow, fanCoil.MaxAirMassFlow * fanCoil.LowSpeedRatio), fanCoil.MaxAirMassFlow);
    2678           10 :             MaxSAMassFlowRate = fanCoil.MaxAirMassFlow;
    2679           10 :             state.dataFanCoilUnits->HeatingLoad = false;
    2680           10 :             state.dataFanCoilUnits->CoolingLoad = false;
    2681           10 :             if (UnitOn) {
    2682           10 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = MinSAMassFlowRate;
    2683           10 :                 fanCoil.MaxNoCoolHeatAirMassFlow = MinSAMassFlowRate;
    2684           10 :                 fanCoil.MaxCoolAirMassFlow = MaxSAMassFlowRate;
    2685           10 :                 fanCoil.MaxHeatAirMassFlow = MaxSAMassFlowRate;
    2686           10 :                 fanCoil.LowSpeedCoolFanRatio = MinSAMassFlowRate / MaxSAMassFlowRate;
    2687           10 :                 fanCoil.LowSpeedHeatFanRatio = MinSAMassFlowRate / MaxSAMassFlowRate;
    2688              : 
    2689           10 :                 Calc4PipeFanCoil(state,
    2690              :                                  FanCoilNum,
    2691              :                                  ControlledZoneNum,
    2692              :                                  FirstHVACIteration,
    2693              :                                  QUnitOutNoHC,
    2694           10 :                                  0.0); // needs PLR=0 for electric heating coil, otherwise will run at full capacity
    2695              : 
    2696           10 :                 QCoilCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
    2697           10 :                 QCoilHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
    2698              : 
    2699           15 :                 if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0 &&
    2700            5 :                     state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleCool) {
    2701            5 :                     QZnReq = QCoilHeatSP;
    2702            5 :                     state.dataFanCoilUnits->HeatingLoad = true;
    2703            5 :                 } else if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0 &&
    2704            0 :                            state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) == HVAC::SetptType::SingleCool) {
    2705            0 :                     QZnReq = 0.0;
    2706            9 :                 } else if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0 &&
    2707            4 :                            state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleHeat) {
    2708            4 :                     QZnReq = QCoilCoolSP;
    2709            4 :                     state.dataFanCoilUnits->CoolingLoad = true;
    2710            1 :                 } else if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0 &&
    2711            0 :                            state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) == HVAC::SetptType::SingleHeat) {
    2712            0 :                     QZnReq = 0.0;
    2713            1 :                 } else if (QCoilHeatSP <= 0.0 && QCoilCoolSP >= 0.0) {
    2714            1 :                     QZnReq = 0.0;
    2715              :                 }
    2716              :             }
    2717              : 
    2718           10 :             if (state.dataFanCoilUnits->CoolingLoad) {
    2719              : 
    2720            4 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = MaxSAMassFlowRate;
    2721              : 
    2722            4 :                 mdot = fanCoil.MaxCoolCoilFluidFlow;
    2723            4 :                 PlantUtilities::SetComponentFlowRate(
    2724            4 :                     state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2725              : 
    2726            6 :             } else if (state.dataFanCoilUnits->HeatingLoad) {
    2727              : 
    2728            5 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = MaxSAMassFlowRate;
    2729              : 
    2730            5 :                 if (fanCoil.HCoilType_Num == HCoil::Water) {
    2731            3 :                     mdot = fanCoil.MaxHeatCoilFluidFlow;
    2732            3 :                     PlantUtilities::SetComponentFlowRate(
    2733            3 :                         state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2734              :                 }
    2735              :             }
    2736              : 
    2737           10 :             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
    2738              : 
    2739           10 :             if ((state.dataFanCoilUnits->CoolingLoad && QUnitOutMax < QZnReq) || (state.dataFanCoilUnits->HeatingLoad && QUnitOutMax > QZnReq)) {
    2740           16 :                 if ((state.dataFanCoilUnits->CoolingLoad && QUnitOutNoHC < QZnReq) ||
    2741            8 :                     (state.dataFanCoilUnits->HeatingLoad && QUnitOutNoHC > QZnReq)) {
    2742            0 :                     PLR = 0.0;
    2743            0 :                     fanCoil.FanPartLoadRatio = 0.0; // set SZVAV model variable
    2744            0 :                     state.dataLoopNodes->Node(InletNode).MassFlowRate =
    2745              :                         MinSAMassFlowRate; // = min air flow rate + ((max-min) air flow rate * FanPartLoadRatio)
    2746            0 :                     mdot = 0.0;
    2747            0 :                     PlantUtilities::SetComponentFlowRate(
    2748            0 :                         state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2749              : 
    2750            0 :                     if (fanCoil.HCoilType_Num == HCoil::Water) {
    2751            0 :                         mdot = 0.0;
    2752            0 :                         PlantUtilities::SetComponentFlowRate(
    2753            0 :                             state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2754              :                     }
    2755              :                 } else {
    2756            8 :                     Real64 OnOffAirFlowRatio = 1.0;
    2757            8 :                     bool HXUnitOn = false;
    2758            8 :                     int AirLoopNum = 0;
    2759            8 :                     HVAC::CompressorOp CompressorOnFlag = HVAC::CompressorOp::Off;
    2760            8 :                     auto &SZVAVModel(fanCoil);
    2761              :                     // seems like passing these (arguments 2-n) as an array (similar to Par) would make this more uniform across different
    2762              :                     // models
    2763           24 :                     SZVAVModel::calcSZVAVModel(state,
    2764              :                                                SZVAVModel,
    2765              :                                                FanCoilNum,
    2766              :                                                FirstHVACIteration,
    2767            8 :                                                state.dataFanCoilUnits->CoolingLoad,
    2768            8 :                                                state.dataFanCoilUnits->HeatingLoad,
    2769              :                                                QZnReq,
    2770              :                                                OnOffAirFlowRatio,
    2771              :                                                HXUnitOn,
    2772              :                                                AirLoopNum,
    2773              :                                                PLR,
    2774              :                                                CompressorOnFlag);
    2775              :                 }
    2776            4 :             } else if ((state.dataFanCoilUnits->CoolingLoad && QUnitOutMax > QZnReq && QZnReq < 0.0) ||
    2777            2 :                        (state.dataFanCoilUnits->HeatingLoad && QUnitOutMax < QZnReq && QZnReq > 0.0)) {
    2778              :                 // load is larger than capacity, thus run the fancoil unit at full capacity
    2779            1 :                 PLR = 1.0;
    2780              :             }
    2781           10 :             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2782           10 :             PowerMet = QUnitOut;
    2783           10 :             AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    2784              :             // CR9155 Remove specific humidity calculations
    2785           10 :             SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
    2786           10 :             SpecHumIn = state.dataLoopNodes->Node(InletNode).HumRat;
    2787              :             // Latent rate (kg/s), dehumid = negative
    2788           10 :             LatOutputProvided = AirMassFlow * (SpecHumOut - SpecHumIn);
    2789           10 :             fanCoil.PLR = PLR;
    2790              : 
    2791              :             // cycling fan constant water flow AND VarFanVarFlow
    2792           10 :         } break;
    2793            0 :         case CCM::VarFanConsFlow: {
    2794              : 
    2795            0 :             if (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ControlledZoneNum) || AirMassFlow < HVAC::SmallMassFlow) UnitOn = false;
    2796              : 
    2797              :             //  zero the hot & cold water flows
    2798              :             //    Node(fanCoil%CoolCoilFluidInletNode)%MassFlowRate = 0.0
    2799              :             //    Node(fanCoil%HeatCoilFluidInletNode)%MassFlowRate = 0.0
    2800            0 :             mdot = 0.0;
    2801            0 :             PlantUtilities::SetComponentFlowRate(
    2802            0 :                 state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2803              : 
    2804            0 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    2805            0 :                 mdot = 0.0;
    2806            0 :                 PlantUtilities::SetComponentFlowRate(
    2807            0 :                     state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2808              :             }
    2809            0 :             Calc4PipeFanCoil(state,
    2810              :                              FanCoilNum,
    2811              :                              ControlledZoneNum,
    2812              :                              FirstHVACIteration,
    2813              :                              QUnitOutNoHC,
    2814            0 :                              0.0); // needs PLR=0 for electric heating coil, otherwise will run at full capacity
    2815              : 
    2816            0 :             int Iter = 0;
    2817            0 :             if (UnitOn && state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP < (-1.0 * HVAC::SmallLoad) &&
    2818            0 :                 state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleHeat) {
    2819              :                 // cooling coil action, maximum cold water flow
    2820            0 :                 mdot = fanCoil.MaxCoolCoilFluidFlow;
    2821            0 :                 PlantUtilities::SetComponentFlowRate(
    2822            0 :                     state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2823            0 :                 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
    2824            0 :                 ControlOffset = fanCoil.ColdControlOffset;
    2825              : 
    2826              :                 // get the maximum output of the fcu
    2827            0 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
    2828              :                 // calculate the PLR, if load greater than output, PLR = 1 (output = max)
    2829            0 :                 if (QUnitOutMax != 0.0) PLR = std::abs(QZnReq / QUnitOutMax);
    2830            0 :                 if (PLR > 1.0) PLR = 1.0;
    2831              : 
    2832              :                 // adjust the PLR to meet the cooling load calling Calc4PipeFanCoil repeatedly with the PLR adjusted
    2833            0 :                 while (std::abs(Error) > ControlOffset && std::abs(AbsError) > HVAC::SmallLoad && Iter < MaxIterCycl && PLR != 1.0) {
    2834            0 :                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2835            0 :                     Error = (QZnReq - QUnitOut) / QZnReq;
    2836            0 :                     AbsError = QZnReq - QUnitOut;
    2837            0 :                     DelPLR = (QZnReq - QUnitOut) / QUnitOutMax;
    2838            0 :                     PLR += Relax * DelPLR;
    2839            0 :                     PLR = max(0.0, min(1.0, PLR));
    2840            0 :                     ++Iter;
    2841            0 :                     if (Iter == 32) Relax = 0.5;
    2842            0 :                     if (Iter == 65) Relax = 0.25;
    2843              :                 }
    2844              : 
    2845              :                 // warning if not converged
    2846            0 :                 if (Iter > (MaxIterCycl - 1)) {
    2847            0 :                     if (fanCoil.MaxIterIndexC == 0) {
    2848            0 :                         ShowWarningMessage(state,
    2849            0 :                                            format("ZoneHVAC:FourPipeFanCoil=\"{}\" -- Exceeded max iterations while adjusting cycling fan sensible "
    2850              :                                                   "runtime to meet the zone load within the cooling convergence tolerance.",
    2851            0 :                                                   fanCoil.Name));
    2852            0 :                         ShowContinueErrorTimeStamp(state, format("Iterations={}", MaxIterCycl));
    2853              :                     }
    2854            0 :                     ShowRecurringWarningErrorAtEnd(state,
    2855            0 :                                                    "ZoneHVAC:FourPipeFanCoil=\"" + fanCoil.Name +
    2856              :                                                        "\"  -- Exceeded max iterations error (sensible runtime) continues...",
    2857            0 :                                                    fanCoil.MaxIterIndexC);
    2858              :                 }
    2859              : 
    2860              :                 // at the end calculate output with adjusted PLR
    2861            0 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2862              : 
    2863            0 :             } else if (UnitOn && state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP > HVAC::SmallLoad &&
    2864            0 :                        state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleCool) {
    2865              :                 // heating coil action, maximun hot water flow
    2866            0 :                 if (fanCoil.HCoilType_Num == HCoil::Water) {
    2867            0 :                     mdot = fanCoil.MaxHeatCoilFluidFlow;
    2868            0 :                     PlantUtilities::SetComponentFlowRate(
    2869            0 :                         state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2870              :                 }
    2871            0 :                 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
    2872            0 :                 ControlOffset = fanCoil.HotControlOffset;
    2873              : 
    2874              :                 // get the maximum output of the fcu
    2875            0 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
    2876              :                 // calculate the PLR, if load greater than output, PLR = 1 (output = max)
    2877            0 :                 if (QUnitOutMax != 0.0) PLR = std::abs(QZnReq / QUnitOutMax);
    2878            0 :                 if (PLR > 1.0) PLR = 1.0;
    2879              : 
    2880              :                 // adjust the PLR to meet the heating load calling Calc4PipeFanCoil repeatedly with the PLR adjusted
    2881            0 :                 while (std::abs(Error) > ControlOffset && std::abs(AbsError) > HVAC::SmallLoad && Iter < MaxIterCycl && PLR != 1.0) {
    2882            0 :                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2883            0 :                     Error = (QZnReq - QUnitOut) / QZnReq;
    2884            0 :                     AbsError = QZnReq - QUnitOut;
    2885            0 :                     DelPLR = (QZnReq - QUnitOut) / QUnitOutMax;
    2886            0 :                     PLR += Relax * DelPLR;
    2887            0 :                     PLR = max(0.0, min(1.0, PLR));
    2888            0 :                     ++Iter;
    2889            0 :                     if (Iter == 32) Relax = 0.5;
    2890            0 :                     if (Iter == 65) Relax = 0.25;
    2891              :                 }
    2892              : 
    2893              :                 // warning if not converged
    2894            0 :                 if (Iter > (MaxIterCycl - 1)) {
    2895            0 :                     if (fanCoil.MaxIterIndexH == 0) {
    2896            0 :                         ShowWarningMessage(state,
    2897            0 :                                            format("ZoneHVAC:FourPipeFanCoil=\"{}\" -- Exceeded max iterations while adjusting cycling fan sensible "
    2898              :                                                   "runtime to meet the zone load within the heating convergence tolerance.",
    2899            0 :                                                   fanCoil.Name));
    2900            0 :                         ShowContinueError(state, format("...Requested zone load = {:.3T} [W]", QZnReq));
    2901            0 :                         ShowContinueError(state, format("...Fan coil capacity   = {:.3T} [W]", QUnitOut));
    2902            0 :                         ShowContinueErrorTimeStamp(state, format("Iterations={}", MaxIterCycl));
    2903              :                     }
    2904            0 :                     ShowRecurringWarningErrorAtEnd(state,
    2905            0 :                                                    "ZoneHVAC:FourPipeFanCoil=\"" + fanCoil.Name +
    2906              :                                                        "\"  -- Exceeded max iterations error (sensible runtime) continues...",
    2907            0 :                                                    fanCoil.MaxIterIndexH);
    2908              :                 }
    2909              : 
    2910              :                 // at the end calculate output with adjusted PLR
    2911            0 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2912              : 
    2913              :                 // this part of the code is just if we want ventilation in the deadband zone
    2914              :                 // ELSE IF (AirMassFlow .gt. 0.0d0) THEN
    2915              :                 // if fan scheduled available : just ventilation, PLR = 1
    2916              :                 // QUnitOut = QUnitOutNOHC
    2917              :                 // PLR = 1.
    2918              : 
    2919              :             } else {
    2920              :                 // no action, zero the air flow rate, the unit is off
    2921            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
    2922            0 :                 state.dataLoopNodes->Node(OutletNode).MassFlowRate = 0.0;
    2923            0 :                 fanCoil.SpeedFanSel = 0;
    2924            0 :                 PLR = 0.0;
    2925            0 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2926              :             }
    2927              : 
    2928            0 :             AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    2929              :             // CR9155 Remove specific humidity calculations
    2930            0 :             SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
    2931            0 :             SpecHumIn = state.dataLoopNodes->Node(InletNode).HumRat;
    2932            0 :             LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
    2933            0 :             QSensUnitOutNoATM = calcZoneSensibleOutput(AirMassFlow,
    2934            0 :                                                        state.dataLoopNodes->Node(OutletNode).Temp,
    2935            0 :                                                        state.dataLoopNodes->Node(InletNode).Temp,
    2936            0 :                                                        state.dataLoopNodes->Node(InletNode).HumRat);
    2937            0 :             QTotUnitOut = AirMassFlow * (state.dataLoopNodes->Node(OutletNode).Enthalpy - state.dataLoopNodes->Node(InletNode).Enthalpy);
    2938              :             // report variables
    2939            0 :             fanCoil.HeatPower = max(0.0, QSensUnitOutNoATM);
    2940            0 :             fanCoil.SensCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QSensUnitOutNoATM));
    2941            0 :             fanCoil.TotCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QTotUnitOut));
    2942            0 :             fanCoil.ElecPower = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    2943              : 
    2944            0 :             fanCoil.PLR = PLR;
    2945            0 :             PowerMet = QUnitOut;
    2946            0 :             LatOutputProvided = LatentOutput;
    2947              : 
    2948            0 :         } break;
    2949            9 :         case CCM::MultiSpeedFan: {
    2950              :             // call multi-speed fan staging calculation
    2951            9 :             SimMultiStage4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    2952            9 :             AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    2953            9 :             SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
    2954            9 :             SpecHumIn = state.dataLoopNodes->Node(InletNode).HumRat;
    2955            9 :             LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
    2956           36 :             QSensUnitOutNoATM = calcZoneSensibleOutput(AirMassFlow,
    2957            9 :                                                        state.dataLoopNodes->Node(OutletNode).Temp,
    2958            9 :                                                        state.dataLoopNodes->Node(InletNode).Temp,
    2959            9 :                                                        state.dataLoopNodes->Node(InletNode).HumRat);
    2960            9 :             QTotUnitOut = AirMassFlow * (state.dataLoopNodes->Node(OutletNode).Enthalpy - state.dataLoopNodes->Node(InletNode).Enthalpy);
    2961              :             // report variables
    2962            9 :             fanCoil.HeatPower = max(0.0, QSensUnitOutNoATM);
    2963            9 :             fanCoil.SensCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QSensUnitOutNoATM));
    2964            9 :             fanCoil.TotCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QTotUnitOut));
    2965            9 :             fanCoil.ElecPower = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    2966              : 
    2967            9 :             PowerMet = QUnitOut;
    2968            9 :             LatOutputProvided = LatentOutput;
    2969            9 :         } break;
    2970            0 :         default:
    2971            0 :             break;
    2972              :         }
    2973        20349 :     }
    2974              : 
    2975            7 :     void TightenWaterFlowLimits(EnergyPlusData &state,
    2976              :                                 int const FanCoilNum,          // Unit index in fan coil array
    2977              :                                 bool const CoolingLoad,        // true if zone requires cooling
    2978              :                                 bool const HeatingLoad,        // true if zone requires heating
    2979              :                                 int const WaterControlNode,    // water control node, either cold or hot water
    2980              :                                 int const ControlledZoneNum,   // controlling zone index
    2981              :                                 bool const FirstHVACIteration, //  TRUE if 1st HVAC simulation of system timestep
    2982              :                                 Real64 const QZnReq,           // zone load [W]
    2983              :                                 Real64 &MinWaterFlow,          // minimum water flow rate
    2984              :                                 Real64 &MaxWaterFlow           // maximum water flow rate
    2985              :     )
    2986              :     {
    2987              : 
    2988              :         // SUBROUTINE INFORMATION:
    2989              :         //       AUTHOR         R. Raustad, FSEC
    2990              :         //       DATE WRITTEN   May 2016
    2991              : 
    2992              :         // PURPOSE OF THIS SUBROUTINE:
    2993              :         // Find tighter limits of water flow rate for fan coil unit.
    2994              : 
    2995              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2996              :         Real64 QUnitOut; // fan coil delivered capacity [W]
    2997              :         Real64 mdot;     // water flow rate passed to fan coil unit [kg/s]
    2998              : 
    2999              :         // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 10% of flow before iterating
    3000            7 :         mdot = MaxWaterFlow * 0.1;
    3001            7 :         state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
    3002            7 :         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    3003            7 :         if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3004            5 :             MaxWaterFlow = mdot;
    3005              :             // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 1% of flow before iterating
    3006            5 :             mdot *= 0.1;
    3007            5 :             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
    3008            5 :             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    3009            5 :             if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3010            4 :                 MaxWaterFlow = mdot;
    3011              :                 // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 0.1% of flow before iterating
    3012            4 :                 mdot *= 0.1;
    3013            4 :                 state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
    3014            4 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    3015            4 :                 if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3016            3 :                     MaxWaterFlow = mdot;
    3017              :                     // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 0.01% of flow before iterating
    3018            3 :                     mdot *= 0.1;
    3019            3 :                     state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
    3020            3 :                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    3021            3 :                     if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3022            2 :                         MaxWaterFlow = mdot;
    3023              :                         // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 0.001% of flow before
    3024              :                         // iterating
    3025            2 :                         mdot *= 0.1;
    3026            2 :                         state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
    3027            2 :                         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    3028            2 :                         if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3029            1 :                             MaxWaterFlow = mdot;
    3030              :                         } else {
    3031            1 :                             MinWaterFlow = mdot;
    3032              :                         }
    3033              :                     } else {
    3034            1 :                         MinWaterFlow = mdot;
    3035              :                     }
    3036              :                 } else {
    3037            1 :                     MinWaterFlow = mdot;
    3038              :                 }
    3039              :             } else {
    3040            1 :                 MinWaterFlow = mdot;
    3041              :             }
    3042              :         } else {
    3043            2 :             MinWaterFlow = mdot;
    3044              :         }
    3045            7 :     }
    3046              : 
    3047            0 :     void TightenAirAndWaterFlowLimits(EnergyPlusData &state,
    3048              :                                       int const FanCoilNum,          // Unit index in fan coil array
    3049              :                                       bool const CoolingLoad,        // true if zone requires cooling
    3050              :                                       bool const HeatingLoad,        // true if zone requires heating
    3051              :                                       int const WaterControlNode,    // water control node, either cold or hot water
    3052              :                                       int const ControlledZoneNum,   // controlling zone index
    3053              :                                       bool const FirstHVACIteration, //  TRUE if 1st HVAC simulation of system timestep
    3054              :                                       Real64 const QZnReq,           // zone load [W]
    3055              :                                       Real64 &PLRMin,                // minimum part-load ratio
    3056              :                                       Real64 &PLRMax                 // maximum part-load ratio
    3057              :     )
    3058              :     {
    3059              : 
    3060              :         // SUBROUTINE INFORMATION:
    3061              :         //       AUTHOR         R. Raustad, FSEC
    3062              :         //       DATE WRITTEN   August 2016
    3063              : 
    3064              :         // PURPOSE OF THIS SUBROUTINE:
    3065              :         // Find tighter limits of air and water flow rate for fan coil unit.
    3066              : 
    3067              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3068              :         Real64 QUnitOut; // fan coil delivered capacity [W]
    3069              : 
    3070            0 :         auto const &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum);
    3071              : 
    3072              :         // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 100% of flow before iterating
    3073            0 :         PLRMin = 0.0;
    3074            0 :         PLRMax = 1.0;
    3075            0 :         Real64 PLR = 1.0; // operating part-load ratio
    3076            0 :         if (WaterControlNode == fanCoil.CoolCoilFluidInletNode) {
    3077            0 :             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * fanCoil.MaxCoolCoilFluidFlow;
    3078            0 :         } else if (WaterControlNode == fanCoil.HeatCoilFluidInletNode && fanCoil.HCoilType_Num != HCoil::Electric) {
    3079            0 :             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * fanCoil.MaxHeatCoilFluidFlow;
    3080              :         }
    3081            0 :         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3082            0 :         if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3083            0 :             PLRMax = PLR;
    3084            0 :             PLR *= 0.1;
    3085              :             // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 10% of flow before iterating
    3086            0 :             if (WaterControlNode == fanCoil.CoolCoilFluidInletNode) {
    3087            0 :                 state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * fanCoil.MaxCoolCoilFluidFlow;
    3088            0 :             } else if (WaterControlNode == fanCoil.HeatCoilFluidInletNode && fanCoil.HCoilType_Num != HCoil::Electric) {
    3089            0 :                 state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * fanCoil.MaxHeatCoilFluidFlow;
    3090              :             }
    3091            0 :             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3092            0 :             if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3093            0 :                 PLRMax = PLR;
    3094            0 :                 PLR *= 0.1;
    3095              :                 // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 1% of flow before iterating
    3096            0 :                 if (WaterControlNode == fanCoil.CoolCoilFluidInletNode) {
    3097            0 :                     state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * fanCoil.MaxCoolCoilFluidFlow;
    3098            0 :                 } else if (WaterControlNode == fanCoil.HeatCoilFluidInletNode && fanCoil.HCoilType_Num != HCoil::Electric) {
    3099            0 :                     state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * fanCoil.MaxHeatCoilFluidFlow;
    3100              :                 }
    3101            0 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3102            0 :                 if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3103            0 :                     PLRMax = PLR;
    3104            0 :                     PLR *= 0.1;
    3105              :                     // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 0.1% of flow before iterating
    3106            0 :                     if (WaterControlNode == fanCoil.CoolCoilFluidInletNode) {
    3107            0 :                         state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * fanCoil.MaxCoolCoilFluidFlow;
    3108            0 :                     } else if (WaterControlNode == fanCoil.HeatCoilFluidInletNode && fanCoil.HCoilType_Num != HCoil::Electric) {
    3109            0 :                         state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * fanCoil.MaxHeatCoilFluidFlow;
    3110              :                     }
    3111            0 :                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3112            0 :                     if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3113            0 :                         PLRMax = PLR;
    3114            0 :                         PLR *= 0.1;
    3115              :                         // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 0.01% of flow before
    3116              :                         // iterating
    3117            0 :                         if (WaterControlNode == fanCoil.CoolCoilFluidInletNode) {
    3118            0 :                             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * fanCoil.MaxCoolCoilFluidFlow;
    3119            0 :                         } else if (WaterControlNode == fanCoil.HeatCoilFluidInletNode && fanCoil.HCoilType_Num != HCoil::Electric) {
    3120            0 :                             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * fanCoil.MaxHeatCoilFluidFlow;
    3121              :                         }
    3122            0 :                         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3123            0 :                         if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3124            0 :                             PLRMax = PLR;
    3125              :                         } else {
    3126            0 :                             PLRMin = PLR;
    3127              :                         }
    3128              :                     } else {
    3129            0 :                         PLRMin = PLR;
    3130              :                     }
    3131              :                 } else {
    3132            0 :                     PLRMin = PLR;
    3133              :                 }
    3134              :             } else {
    3135            0 :                 PLRMin = PLR;
    3136              :             }
    3137              :         } else {
    3138            0 :             PLRMin = PLR;
    3139              :         }
    3140            0 :     }
    3141              : 
    3142       130805 :     void Calc4PipeFanCoil(EnergyPlusData &state,
    3143              :                           int const FanCoilNum,            // Unit index in fan coil array
    3144              :                           int const ControlledZoneNum,     // ZoneEquipConfig index
    3145              :                           bool const FirstHVACIteration,   // flag for 1st HVAV iteration in the time step
    3146              :                           Real64 &LoadMet,                 // load met by unit (watts)
    3147              :                           ObjexxFCL::Optional<Real64> PLR, // Part Load Ratio, fraction of time step fancoil is on
    3148              :                           Real64 eHeatCoilCyclingR         // electric heating coil cycling ratio  used with MultiSpeedFan capacity control
    3149              :     )
    3150              :     {
    3151              : 
    3152              :         // SUBROUTINE INFORMATION:
    3153              :         //       AUTHOR         Fred Buhl
    3154              :         //       DATE WRITTEN   March 2000
    3155              :         //       MODIFIED       July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
    3156              : 
    3157              :         // PURPOSE OF THIS SUBROUTINE:
    3158              :         // Simulate the components making up the 4 pipe fan coil unit.
    3159              : 
    3160              :         // METHODOLOGY EMPLOYED:
    3161              :         // Simulates the unit components sequentially in the air flow direction.
    3162              : 
    3163              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3164              :         Real64 AirMassFlow;            // total mass flow through the unit
    3165              :         Real64 PartLoad;               // if PLR present PartLoad = PLR
    3166              :         Real64 OASchedValue;           // value of OASchedValue, =1 if not schedule
    3167       130805 :         Real64 ElecHeaterControl(1.0); // 1 or 0, enables or disables heating coil
    3168              :         Real64 FanSpeedRatio;          // ratio of actual fan flow to max design fan flow
    3169              : 
    3170       130805 :         auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum);
    3171              : 
    3172              :         // if PLR present in arguments, get its value, else default PLR = 1
    3173       130805 :         if (present(PLR)) {
    3174        93809 :             PartLoad = PLR;
    3175              :         } else {
    3176        36996 :             PartLoad = 1.0;
    3177              :         }
    3178              : 
    3179       130805 :         int OutletNode = fanCoil.AirOutNode;
    3180       130805 :         int InletNode = fanCoil.AirInNode;
    3181       130805 :         state.dataFanCoilUnits->ZoneNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
    3182              : 
    3183              :         // Assume the unit is able to vary the flow. A cycling unit is treated as
    3184              :         // if it were variable flow, with the flow being the averaqe flow over the time step
    3185       261605 :         if (((fanCoil.availSched->getCurrentVal() > 0.0 && fanCoil.fanAvailSched->getCurrentVal() > 0.0) || state.dataHVACGlobal->TurnFansOn) &&
    3186       130800 :             !state.dataHVACGlobal->TurnFansOff) {
    3187       130800 :             if (fanCoil.CapCtrlMeth_Num != CCM::ConsFanVarFlow) {
    3188       130615 :                 if (fanCoil.CapCtrlMeth_Num != CCM::ASHRAE)
    3189       130490 :                     state.dataLoopNodes->Node(InletNode).MassFlowRate = PartLoad * state.dataLoopNodes->Node(InletNode).MassFlowRateMax;
    3190              :             } else {
    3191          185 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRateMax;
    3192              :             }
    3193              :         }
    3194              : 
    3195              :         // use the value of the outside air schedule if present
    3196       130805 :         OASchedValue = (fanCoil.oaSched != nullptr) ? fanCoil.oaSched->getCurrentVal() : 1.0;
    3197              : 
    3198       130805 :         if (fanCoil.ATMixerExists) {
    3199           22 :             state.dataFanCoilUnits->ATMixOutNode = fanCoil.ATMixerOutNode;
    3200           22 :             if (fanCoil.ATMixerType == HVAC::MixerType::InletSide) {
    3201              :                 // set the primary air inlet mass flow rate
    3202           22 :                 state.dataLoopNodes->Node(fanCoil.ATMixerPriNode).MassFlowRate =
    3203           22 :                     min(state.dataLoopNodes->Node(fanCoil.ATMixerPriNode).MassFlowRateMaxAvail, state.dataLoopNodes->Node(InletNode).MassFlowRate);
    3204              :                 // now calculate the the mixer outlet conditions (and the secondary air inlet flow rate)
    3205              :                 // the mixer outlet flow rate has already been set above (it is the "inlet" node flow rate)
    3206           22 :                 SingleDuct::SimATMixer(state, fanCoil.ATMixerName, FirstHVACIteration, fanCoil.ATMixerIndex);
    3207              :             }
    3208           22 :             AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    3209              :         } else {
    3210              :             // OutdoorAir:Mixer
    3211       130783 :             if (fanCoil.CapCtrlMeth_Num == CCM::CycFan) {
    3212       130355 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRate =
    3213       130355 :                     min(OASchedValue * state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMax * PartLoad * fanCoil.SpeedFanRatSel,
    3214       130355 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate);
    3215          428 :             } else if (fanCoil.CapCtrlMeth_Num == CCM::MultiSpeedFan) {
    3216          115 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRate =
    3217          115 :                     min(OASchedValue * state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMax * PartLoad *
    3218          115 :                             state.dataFanCoilUnits->FanFlowRatio,
    3219          115 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate);
    3220              :             } else {
    3221          313 :                 if (fanCoil.CapCtrlMeth_Num != CCM::ConsFanVarFlow && fanCoil.CapCtrlMeth_Num != CCM::ASHRAE) {
    3222            0 :                     state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRate =
    3223            0 :                         min(OASchedValue * state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMax * PartLoad,
    3224            0 :                             state.dataLoopNodes->Node(InletNode).MassFlowRate);
    3225              :                 } else {
    3226          313 :                     state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRate =
    3227          313 :                         min(OASchedValue * state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMax,
    3228          313 :                             state.dataLoopNodes->Node(InletNode).MassFlowRate);
    3229              :                 }
    3230              :             }
    3231       130783 :             state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRate = state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRate;
    3232       130783 :             AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    3233       130783 :             MixedAir::SimOAMixer(state, fanCoil.OAMixName, fanCoil.OAMixIndex);
    3234              :         }
    3235              : 
    3236       130805 :         if (fanCoil.CapCtrlMeth_Num == CCM::CycFan) {
    3237              :             // cycling fan coil unit calculation
    3238       130355 :             if (fanCoil.SpeedFanSel == 1) {
    3239        31420 :                 state.dataFans->fans(fanCoil.FanIndex)->simulate(state, FirstHVACIteration, fanCoil.LowSpeedRatio);
    3240        98935 :             } else if (fanCoil.SpeedFanSel == 2) {
    3241        57722 :                 state.dataFans->fans(fanCoil.FanIndex)->simulate(state, FirstHVACIteration, fanCoil.MedSpeedRatio);
    3242        41213 :             } else if (fanCoil.SpeedFanSel == 3) {
    3243        26710 :                 state.dataFans->fans(fanCoil.FanIndex)->simulate(state, FirstHVACIteration, 1.0);
    3244              :             } else { // using 1.0 here for fan speed ratio seems wrong if FCU max flow rate is different than the fan maximum flow rate
    3245        14503 :                 state.dataFans->fans(fanCoil.FanIndex)->simulate(state, FirstHVACIteration, 0.0, _, 0.0);
    3246              :             }
    3247       130355 :             if (fanCoil.CCoilType_Num == CCoil::HXAssist) {
    3248            0 :                 HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(
    3249            0 :                     state, fanCoil.CCoilName, FirstHVACIteration, HVAC::CompressorOp::On, 0.0, fanCoil.CCoilName_Index, HVAC::FanOp::Continuous);
    3250              :             } else {
    3251       521420 :                 WaterCoils::SimulateWaterCoilComponents(
    3252       391065 :                     state, fanCoil.CCoilName, FirstHVACIteration, fanCoil.CCoilName_Index, _, HVAC::FanOp::Cycling, PLR);
    3253              :             }
    3254       130355 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    3255       521420 :                 WaterCoils::SimulateWaterCoilComponents(
    3256       391065 :                     state, fanCoil.HCoilName, FirstHVACIteration, fanCoil.HCoilName_Index, _, HVAC::FanOp::Cycling, PLR);
    3257              :             } else {
    3258            0 :                 if (state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate > 0.0) ElecHeaterControl = 0.0;
    3259            0 :                 HeatingCoils::SimulateHeatingCoilComponents(state,
    3260              :                                                             fanCoil.HCoilName,
    3261              :                                                             FirstHVACIteration,
    3262            0 :                                                             fanCoil.DesignHeatingCapacity * PartLoad * ElecHeaterControl,
    3263            0 :                                                             fanCoil.HCoilName_Index,
    3264              :                                                             _,
    3265            0 :                                                             false,
    3266            0 :                                                             HVAC::FanOp::Continuous,
    3267              :                                                             PartLoad);
    3268              :             }
    3269              : 
    3270          450 :         } else if (fanCoil.CapCtrlMeth_Num == CCM::MultiSpeedFan) {
    3271          115 :             if (fanCoil.fanType != HVAC::FanType::SystemModel) {
    3272           47 :                 state.dataFans->fans(fanCoil.FanIndex)->simulate(state, FirstHVACIteration, state.dataFanCoilUnits->FanFlowRatio);
    3273              :             } else {
    3274              :                 // FanFlowRatio needs to be accurate here for new fan model
    3275           68 :                 Real64 ActFanFlowRatio = state.dataFanCoilUnits->FanFlowRatio * PartLoad;
    3276           68 :                 state.dataFans->fans(fanCoil.FanIndex)->simulate(state, FirstHVACIteration, _, _, ActFanFlowRatio);
    3277              :             }
    3278          115 :             if (fanCoil.CCoilType_Num == CCoil::HXAssist) {
    3279            0 :                 HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(
    3280            0 :                     state, fanCoil.CCoilName, FirstHVACIteration, HVAC::CompressorOp::On, 0.0, fanCoil.CCoilName_Index, HVAC::FanOp::Continuous);
    3281              :             } else {
    3282          460 :                 WaterCoils::SimulateWaterCoilComponents(
    3283          345 :                     state, fanCoil.CCoilName, FirstHVACIteration, fanCoil.CCoilName_Index, _, HVAC::FanOp::Cycling, PLR);
    3284              :             }
    3285          115 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    3286          188 :                 WaterCoils::SimulateWaterCoilComponents(
    3287          141 :                     state, fanCoil.HCoilName, FirstHVACIteration, fanCoil.HCoilName_Index, _, HVAC::FanOp::Cycling, PLR);
    3288              :             } else {
    3289           68 :                 if (state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate > 0.0) ElecHeaterControl = 0.0;
    3290           68 :                 Real64 QZnReq = 0.0;
    3291           68 :                 if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3292           41 :                     QZnReq = fanCoil.DesignHeatingCapacity * state.dataFanCoilUnits->FanFlowRatio * eHeatCoilCyclingR * ElecHeaterControl;
    3293              :                 } else {
    3294              :                     // proportionally reduce the full flow capacity based on fan flow fraction
    3295           27 :                     QZnReq = fanCoil.DesignHeatingCapacity * state.dataFanCoilUnits->FanFlowRatio * PartLoad * eHeatCoilCyclingR * ElecHeaterControl;
    3296              :                 }
    3297          272 :                 HeatingCoils::SimulateHeatingCoilComponents(state,
    3298              :                                                             fanCoil.HCoilName,
    3299              :                                                             FirstHVACIteration,
    3300              :                                                             QZnReq,
    3301           68 :                                                             fanCoil.HCoilName_Index,
    3302              :                                                             _,
    3303          136 :                                                             false,
    3304           68 :                                                             fanCoil.fanOp, // fanCoil.FanOpMode, // FanOp::Continuous, FanOp::Cycling
    3305              :                                                             PartLoad);
    3306              :             }
    3307              :         } else { // capacity control method is VariableFanVariableFlow, VariableFanConstantFlow, or ASHRAE90.1
    3308              : 
    3309              :             // calculate fan speed ratio for Fan:OnOff or Fan:SystemModel (not used for other fan types). Only used in fan:OnOff model if performance
    3310              :             // curves are present.
    3311          335 :             FanSpeedRatio = state.dataLoopNodes->Node(InletNode).MassFlowRate / (fanCoil.FanAirVolFlow * state.dataEnvrn->StdRhoAir);
    3312              : 
    3313              :             // Constant fan and variable flow calculation AND variable fan
    3314              : 
    3315          335 :             state.dataFans->fans(fanCoil.FanIndex)->simulate(state, FirstHVACIteration, FanSpeedRatio, _, FanSpeedRatio);
    3316              : 
    3317          335 :             if (fanCoil.CCoilType_Num == CCoil::HXAssist) {
    3318            0 :                 HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(
    3319            0 :                     state, fanCoil.CCoilName, FirstHVACIteration, HVAC::CompressorOp::On, 0.0, fanCoil.CCoilName_Index, HVAC::FanOp::Continuous);
    3320              :             } else {
    3321          335 :                 WaterCoils::SimulateWaterCoilComponents(state, fanCoil.CCoilName, FirstHVACIteration, fanCoil.CCoilName_Index);
    3322              :             }
    3323          335 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    3324          295 :                 WaterCoils::SimulateWaterCoilComponents(state, fanCoil.HCoilName, FirstHVACIteration, fanCoil.HCoilName_Index);
    3325              :             } else {
    3326           40 :                 if (state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate > 0.0) ElecHeaterControl = 0.0;
    3327          200 :                 HeatingCoils::SimulateHeatingCoilComponents(state,
    3328              :                                                             fanCoil.HCoilName,
    3329              :                                                             FirstHVACIteration,
    3330           80 :                                                             fanCoil.DesignHeatingCapacity * PartLoad * ElecHeaterControl,
    3331           40 :                                                             fanCoil.HCoilName_Index,
    3332              :                                                             _,
    3333           80 :                                                             false,
    3334           80 :                                                             HVAC::FanOp::Continuous,
    3335              :                                                             PartLoad);
    3336              :             }
    3337              :         }
    3338              : 
    3339       130805 :         if (fanCoil.ATMixerExists) {
    3340           22 :             if (fanCoil.ATMixerType == HVAC::MixerType::SupplySide) {
    3341              :                 // Now calculate the ATM mixer if it is on the supply side of the zone unit
    3342            0 :                 SingleDuct::SimATMixer(state, fanCoil.ATMixerName, FirstHVACIteration, fanCoil.ATMixerIndex);
    3343            0 :                 LoadMet = calcZoneSensibleOutput(state.dataLoopNodes->Node(state.dataFanCoilUnits->ATMixOutNode).MassFlowRate,
    3344            0 :                                                  state.dataLoopNodes->Node(state.dataFanCoilUnits->ATMixOutNode).Temp,
    3345            0 :                                                  state.dataLoopNodes->Node(state.dataFanCoilUnits->ZoneNode).Temp,
    3346            0 :                                                  state.dataLoopNodes->Node(state.dataFanCoilUnits->ZoneNode).HumRat);
    3347              :             } else {
    3348              :                 // ATM Mixer on inlet side
    3349           22 :                 LoadMet = calcZoneSensibleOutput(AirMassFlow,
    3350           22 :                                                  state.dataLoopNodes->Node(OutletNode).Temp,
    3351           22 :                                                  state.dataLoopNodes->Node(state.dataFanCoilUnits->ZoneNode).Temp,
    3352           22 :                                                  state.dataLoopNodes->Node(state.dataFanCoilUnits->ZoneNode).HumRat);
    3353              :             }
    3354              :         } else {
    3355       130783 :             LoadMet = calcZoneSensibleOutput(AirMassFlow,
    3356       130783 :                                              state.dataLoopNodes->Node(OutletNode).Temp,
    3357       130783 :                                              state.dataLoopNodes->Node(InletNode).Temp,
    3358       130783 :                                              state.dataLoopNodes->Node(InletNode).HumRat);
    3359              :         }
    3360       130805 :     }
    3361              : 
    3362            9 :     void SimMultiStage4PipeFanCoil(EnergyPlusData &state,
    3363              :                                    int &FanCoilNum,               // number of the current fan coil unit being simulated
    3364              :                                    int const ZoneNum,             // number of zone being served
    3365              :                                    bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
    3366              :                                    Real64 &PowerMet               // Sensible power supplied (W)
    3367              :     )
    3368              :     {
    3369              : 
    3370              :         // SUBROUTINE INFORMATION:
    3371              :         //       AUTHOR         Bereket Nigusse
    3372              :         //       DATE WRITTEN   July 2015
    3373              : 
    3374              :         // PURPOSE OF THIS SUBROUTINE:
    3375              :         // Manages multi-speed fancoil unit simulation;
    3376              : 
    3377              :         // METHODOLOGY EMPLOYED:
    3378              :         // Selects the appropriate fan speed for a given zone heating or cooling load
    3379              :         // and determines whether heating or cooling is required, then runs the hot
    3380              :         // or chilled water coils.
    3381              : 
    3382              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3383              :         Real64 mdot; // chilled or hot water flow rate through the water coils
    3384              : 
    3385            9 :         auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum);
    3386            9 :         auto &HeatingLoad = state.dataFanCoilUnits->HeatingLoad;
    3387            9 :         auto &CoolingLoad = state.dataFanCoilUnits->CoolingLoad;
    3388              : 
    3389              :         // initialize local variables
    3390            9 :         bool UnitOn = true;         // TRUE if unit is on
    3391            9 :         Real64 SpeedRatio = 0.0;    // ratio between lower and higher fan speed
    3392            9 :         Real64 PartLoadRatio = 0.0; // Part Load Ratio, fraction of time step fancoil is on
    3393            9 :         Real64 QZnReq = 0.0;        // heating or cooling needed by zone [watts]
    3394            9 :         Real64 QUnitOut = 0.0;      // heating or sens. cooling provided by fan coil unit [watts]
    3395            9 :         Real64 QUnitOutMax = 0.0;   // heating or sens. cooling provided by fan coil unit (running during an entire timestep)
    3396            9 :         Real64 QUnitOutNoHC = 0.0;  // unit output with no active heating or cooling [W]
    3397              : 
    3398            9 :         int OutletNode = fanCoil.AirOutNode;
    3399            9 :         int InletNode = fanCoil.AirInNode;
    3400            9 :         Real64 AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    3401              : 
    3402            9 :         if (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum) || AirMassFlow < HVAC::SmallMassFlow) UnitOn = false;
    3403              : 
    3404            9 :         fanCoil.SpeedFanSel = 1;
    3405            9 :         fanCoil.SpeedFanRatSel = fanCoil.LowSpeedRatio;
    3406            9 :         state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3407            9 :         AirMassFlow = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3408            9 :         state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3409            9 :         state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3410            9 :         state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3411            9 :         state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
    3412              : 
    3413            9 :         if (fanCoil.HCoilType_Num == HCoil::Water) {
    3414            0 :             mdot = 0.0;
    3415            0 :             PlantUtilities::SetComponentFlowRate(
    3416            0 :                 state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    3417              :         }
    3418            9 :         mdot = 0.0;
    3419            9 :         PlantUtilities::SetComponentFlowRate(
    3420            9 :             state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    3421              :         // no load output, requires setting eHeatCoilCyclingR = 0.0, for electric heating coils
    3422            9 :         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutNoHC, _, 0.0);
    3423              : 
    3424            9 :         Real64 QCoilCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToCoolSP;
    3425            9 :         Real64 QCoilHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP;
    3426            9 :         state.dataFanCoilUnits->HeatingLoad = false;
    3427            9 :         state.dataFanCoilUnits->CoolingLoad = false;
    3428              : 
    3429            9 :         if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0 && state.dataHeatBalFanSys->TempControlType(ZoneNum) != HVAC::SetptType::SingleCool) {
    3430            9 :             QZnReq = QCoilHeatSP;
    3431            9 :             HeatingLoad = true;
    3432            0 :         } else if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0 && state.dataHeatBalFanSys->TempControlType(ZoneNum) == HVAC::SetptType::SingleCool) {
    3433            0 :             QZnReq = 0.0;
    3434            0 :         } else if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0 && state.dataHeatBalFanSys->TempControlType(ZoneNum) != HVAC::SetptType::SingleHeat) {
    3435            0 :             QZnReq = QCoilCoolSP;
    3436            0 :             CoolingLoad = true;
    3437            0 :         } else if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0 && state.dataHeatBalFanSys->TempControlType(ZoneNum) == HVAC::SetptType::SingleHeat) {
    3438            0 :             QZnReq = 0.0;
    3439            0 :         } else if (QCoilHeatSP <= 0.0 && QCoilCoolSP >= 0.0) {
    3440            0 :             QZnReq = 0.0;
    3441              :         }
    3442              : 
    3443              :         // Zone load calculation for constant fan systems, adopted from unitary system
    3444            9 :         if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3445            5 :             switch (state.dataHeatBalFanSys->TempControlType(ZoneNum)) {
    3446            0 :             case HVAC::SetptType::SingleHeat: {
    3447            0 :                 CoolingLoad = false;
    3448              :                 // No heating load and constant fan pushes zone below heating set point
    3449            0 :                 if (QUnitOutNoHC < 0.0 && QCoilHeatSP < 0.0 && QUnitOutNoHC - QCoilHeatSP < -HVAC::SmallLoad) {
    3450            0 :                     HeatingLoad = true;
    3451            0 :                     CoolingLoad = false;
    3452            0 :                     QZnReq = QCoilHeatSP;
    3453              :                 }
    3454            0 :             } break;
    3455            0 :             case HVAC::SetptType::SingleCool: {
    3456            0 :                 HeatingLoad = false;
    3457              :                 // No heating load and constant fan pushes zone above cooling set point
    3458            0 :                 if (QUnitOutNoHC > 0.0 && QCoilCoolSP > 0.0 && QUnitOutNoHC - QCoilCoolSP > HVAC::SmallLoad) {
    3459            0 :                     HeatingLoad = false;
    3460            0 :                     CoolingLoad = true;
    3461            0 :                     QZnReq = QCoilCoolSP;
    3462              :                 }
    3463            0 :             } break;
    3464            0 :             case HVAC::SetptType::SingleHeatCool: {
    3465              :                 // zone temp above cooling and heating set point temps
    3466            0 :                 if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0) {
    3467              :                     // zone pushed below heating set point
    3468            0 :                     if (QUnitOutNoHC < 0.0 && QCoilHeatSP - QUnitOutNoHC > HVAC::SmallLoad) {
    3469            0 :                         HeatingLoad = true;
    3470            0 :                         CoolingLoad = false;
    3471            0 :                         QZnReq = QCoilHeatSP;
    3472              :                     }
    3473              :                     // zone temp below heating set point temp
    3474            0 :                 } else if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0) {
    3475              :                     // zone pushed above cooling set point
    3476            0 :                     if (QUnitOutNoHC > 0.0 && QCoilCoolSP - QUnitOutNoHC > HVAC::SmallLoad) {
    3477            0 :                         HeatingLoad = false;
    3478            0 :                         CoolingLoad = true;
    3479            0 :                         QZnReq = QCoilCoolSP;
    3480              :                     }
    3481              :                 }
    3482            0 :             } break;
    3483            5 :             case HVAC::SetptType::DualHeatCool: {
    3484              :                 // zone temp above cooling and heating set point temps
    3485            5 :                 if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0) {
    3486              :                     // zone pushed into deadband
    3487            0 :                     if (QUnitOutNoHC < 0.0 && QCoilCoolSP - QUnitOutNoHC > HVAC::SmallLoad) {
    3488            0 :                         HeatingLoad = false;
    3489            0 :                         CoolingLoad = false;
    3490            0 :                         QZnReq = 0.0;
    3491              :                     }
    3492              :                     // zone pushed below heating set point
    3493            0 :                     if (QUnitOutNoHC < 0.0 && QCoilHeatSP - QUnitOutNoHC > HVAC::SmallLoad) {
    3494            0 :                         HeatingLoad = true;
    3495            0 :                         CoolingLoad = false;
    3496            0 :                         QZnReq = QCoilHeatSP;
    3497              :                     }
    3498              :                     // zone temp below heating set point temp
    3499            5 :                 } else if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0) {
    3500              :                     // zone pushed into deadband
    3501            5 :                     if (QUnitOutNoHC > 0.0 && QUnitOutNoHC - QCoilHeatSP > HVAC::SmallLoad) {
    3502            0 :                         HeatingLoad = false;
    3503            0 :                         CoolingLoad = false;
    3504            0 :                         QZnReq = 0.0;
    3505              :                     }
    3506              :                     // zone pushed above cooling set point
    3507            5 :                     if (QUnitOutNoHC > 0.0 && QUnitOutNoHC - QCoilCoolSP > HVAC::SmallLoad) {
    3508            0 :                         HeatingLoad = false;
    3509            0 :                         CoolingLoad = true;
    3510            0 :                         QZnReq = QCoilCoolSP;
    3511              :                     }
    3512              :                     // zone temp between set point temps
    3513            0 :                 } else if (QCoilHeatSP < 0.0 && QCoilCoolSP > 0.0) {
    3514              :                     // zone pushed below heating set point
    3515            0 :                     if (QUnitOutNoHC < 0.0 && QUnitOutNoHC - QCoilHeatSP < -HVAC::SmallLoad) {
    3516            0 :                         HeatingLoad = true;
    3517            0 :                         CoolingLoad = false;
    3518            0 :                         QZnReq = QCoilHeatSP;
    3519              :                         // zone pushed above cooling set point
    3520            0 :                     } else if (QUnitOutNoHC > 0.0 && QUnitOutNoHC - QCoilCoolSP > HVAC::SmallLoad) {
    3521            0 :                         HeatingLoad = false;
    3522            0 :                         CoolingLoad = true;
    3523            0 :                         QZnReq = QCoilCoolSP;
    3524              :                     }
    3525              :                 }
    3526            5 :             } break;
    3527            0 :             default:
    3528            0 :                 break;
    3529              :             }
    3530              :             // IF small loads to meet, just shut down unit
    3531            5 :             if (std::abs(QZnReq) < FanCoilUnits::Small5WLoad) {
    3532            0 :                 QZnReq = 0.0;
    3533            0 :                 CoolingLoad = false;
    3534            0 :                 HeatingLoad = false;
    3535              :             }
    3536              :         }
    3537              : 
    3538            9 :         if (UnitOn && QZnReq < (-1.0 * FanCoilUnits::Small5WLoad) && CoolingLoad) {
    3539            0 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    3540            0 :                 mdot = 0.0;
    3541            0 :                 PlantUtilities::SetComponentFlowRate(
    3542            0 :                     state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    3543              :             }
    3544            0 :             mdot = fanCoil.MaxCoolCoilFluidFlow;
    3545            0 :             PlantUtilities::SetComponentFlowRate(
    3546            0 :                 state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    3547              :             // select fan speed
    3548            0 :             fanCoil.SpeedFanSel = 1;
    3549            0 :             fanCoil.SpeedFanRatSel = fanCoil.LowSpeedRatio;
    3550            0 :             state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3551            0 :             AirMassFlow = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3552            0 :             state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3553            0 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3554            0 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3555            0 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
    3556            0 :             Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
    3557            0 :             if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
    3558            0 :                 fanCoil.SpeedFanSel = 2;
    3559            0 :                 fanCoil.SpeedFanRatSel = fanCoil.MedSpeedRatio;
    3560            0 :                 state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3561            0 :                 AirMassFlow = fanCoil.MedSpeedRatio * fanCoil.MaxAirMassFlow;
    3562            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3563            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3564            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3565            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3566            0 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
    3567              :             }
    3568            0 :             if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
    3569            0 :                 fanCoil.SpeedFanSel = 3;
    3570            0 :                 fanCoil.SpeedFanRatSel = 1.0;
    3571            0 :                 state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3572            0 :                 AirMassFlow = fanCoil.MaxAirMassFlow;
    3573            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3574            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3575            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3576            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = fanCoil.MedSpeedRatio * fanCoil.MaxAirMassFlow;
    3577              :             }
    3578            0 :             CalcMultiStage4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QZnReq, SpeedRatio, PartLoadRatio, QUnitOut);
    3579              : 
    3580            9 :         } else if (UnitOn && QZnReq > FanCoilUnits::Small5WLoad && HeatingLoad) {
    3581              : 
    3582            9 :             mdot = 0.0;
    3583            9 :             PlantUtilities::SetComponentFlowRate(
    3584            9 :                 state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    3585              : 
    3586            9 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    3587            0 :                 mdot = fanCoil.MaxHeatCoilFluidFlow;
    3588            0 :                 PlantUtilities::SetComponentFlowRate(
    3589            0 :                     state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    3590              :             }
    3591              :             // select fan speed
    3592            9 :             fanCoil.SpeedFanSel = 1;
    3593            9 :             fanCoil.SpeedFanRatSel = fanCoil.LowSpeedRatio;
    3594            9 :             state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3595            9 :             AirMassFlow = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3596            9 :             state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3597            9 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3598            9 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3599            9 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
    3600            9 :             Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
    3601            9 :             if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
    3602            6 :                 fanCoil.SpeedFanSel = 2;
    3603            6 :                 fanCoil.SpeedFanRatSel = fanCoil.MedSpeedRatio;
    3604            6 :                 state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3605            6 :                 AirMassFlow = fanCoil.MedSpeedRatio * fanCoil.MaxAirMassFlow;
    3606            6 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3607            6 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3608            6 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3609            6 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3610            6 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
    3611              :             }
    3612            9 :             if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
    3613            4 :                 fanCoil.SpeedFanSel = 3;
    3614            4 :                 fanCoil.SpeedFanRatSel = 1.0;
    3615            4 :                 state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3616            4 :                 AirMassFlow = fanCoil.MaxAirMassFlow;
    3617            4 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3618            4 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3619            4 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3620            4 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = fanCoil.MedSpeedRatio * fanCoil.MaxAirMassFlow;
    3621              :             }
    3622              : 
    3623            9 :             CalcMultiStage4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QZnReq, SpeedRatio, PartLoadRatio, QUnitOut);
    3624              : 
    3625              :         } else {
    3626              :             // SpeedRatio = 0.0;
    3627            0 :             if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3628            0 :                 PartLoadRatio = 1.0;
    3629            0 :                 fanCoil.SpeedFanSel = 1;
    3630            0 :                 fanCoil.SpeedFanRatSel = fanCoil.LowSpeedRatio;
    3631            0 :                 state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3632            0 :                 AirMassFlow = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3633            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3634            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3635            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3636            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
    3637              :             } else {
    3638            0 :                 PartLoadRatio = 0.0;
    3639            0 :                 AirMassFlow = 0.0;
    3640            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3641            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3642            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3643            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
    3644            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
    3645            0 :                 state.dataLoopNodes->Node(OutletNode).MassFlowRate = 0.0;
    3646            0 :                 fanCoil.SpeedFanSel = 0;
    3647            0 :                 state.dataFanCoilUnits->FanFlowRatio = 0.0;
    3648              :             }
    3649              : 
    3650            0 :             mdot = 0.0;
    3651            0 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    3652            0 :                 PlantUtilities::SetComponentFlowRate(
    3653            0 :                     state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    3654              :             }
    3655            0 :             PlantUtilities::SetComponentFlowRate(
    3656            0 :                 state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    3657              :             // No load output, eHeatCoilCyclingR = 0.0 for electric heating coil
    3658            0 :             Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PartLoadRatio, 0.0);
    3659              :         }
    3660              :         // output variable
    3661            9 :         state.dataLoopNodes->Node(OutletNode).MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    3662            9 :         fanCoil.PLR = PartLoadRatio;
    3663            9 :         fanCoil.SpeedRatio = SpeedRatio;
    3664            9 :         PowerMet = QUnitOut;
    3665            9 :     }
    3666              : 
    3667           11 :     void CalcMultiStage4PipeFanCoil(EnergyPlusData &state,
    3668              :                                     int &FanCoilNum,               // number of the current fan coil unit being simulated
    3669              :                                     int const ZoneNum,             // number of zone being served
    3670              :                                     bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
    3671              :                                     Real64 const QZnReq,           // current zone cooling or heating load
    3672              :                                     Real64 &SpeedRatio,            // fan coil speed ratio
    3673              :                                     Real64 &PartLoadRatio,         // fan coil part load ratio
    3674              :                                     Real64 &PowerMet               // Sensible power supplied (W)
    3675              :     )
    3676              :     {
    3677              : 
    3678              :         // SUBROUTINE INFORMATION:
    3679              :         //       AUTHOR         Bereket Nigusse
    3680              :         //       DATE WRITTEN   July 2015
    3681              : 
    3682              :         // PURPOSE OF THIS SUBROUTINE:
    3683              :         // Simulate a multi-stage fan 4 pipe fan coil unit; adjust its output to
    3684              :         // match the remaining zone load.
    3685              : 
    3686              :         // METHODOLOGY EMPLOYED:
    3687              :         // If this unit is on, calculated the speed ratio when cycling between
    3688              :         // consecutive fan speeds. The hot or chilled water flows either at
    3689              :         // maximum or zero.  The water flow rate is set to zero if there is no
    3690              :         // load.
    3691              : 
    3692              :         // SUBROUTINE PARAMETER DEFINITIONS:
    3693           11 :         constexpr int MaxIterCycl(100);
    3694              : 
    3695              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3696              :         Real64 QUnitOutMaxHS;  // higher fan speed output
    3697              :         Real64 QUnitOutMaxLS;  // lower fan speed output
    3698              :         Real64 HighSpeedRatio; // fan flow ratio at low speed
    3699              :         Real64 LowSpeedRatio;  // fan flow ratio at low speed
    3700              :         Real64 DelPLR;
    3701              :         int SolFlag; // return flag from RegulaFalsi for sensible load
    3702              : 
    3703           11 :         auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum);
    3704              : 
    3705              :         // initialize local variables
    3706           11 :         Real64 mdot = 0.0;                                 // chilled or hot water flow rate through the water coils
    3707           11 :         Real64 PLR = 1.0;                                  // Part Load Ratio, fraction of time step fancoil is on
    3708           11 :         Real64 SRatio = 0.0;                               // capacity speed ratio of the for multi-stage fan fancoil unit
    3709           11 :         Real64 QUnitOut = 0.0;                             // heating or sens. cooling provided by fan coil unit [watts]
    3710           11 :         Real64 QUnitOutMax = 0.0;                          // max heating or sens. cooling provided by fan coil unit [watts]
    3711           11 :         Real64 ControlOffset = 0.0;                        // tolerance for output control
    3712           11 :         Real64 FanElecPowerHS = 0.0;                       // fan electric power calculated at (fan) higher speed
    3713           11 :         Real64 FanElecPowerLS = 0.0;                       // fan electric power calculated at (fan) lower speed
    3714           11 :         Real64 AirMassFlowAvg = 0.0;                       // supply air flow rate weighted by speed ratio
    3715           11 :         Real64 AirMassFlowLow = 0.0;                       // supply air flow rate at lower speed
    3716           11 :         Real64 AirMassFlowHigh = 0.0;                      // supply air flow rate at higher speed
    3717           11 :         Real64 AbsError = 2.0 * FanCoilUnits::Small5WLoad; // Absolute error between QZnReq and QUnitOut [W]   !FB
    3718           11 :         Real64 Error = 1.0;                                // Error between QZnReq and QUnitOut
    3719           11 :         Real64 Relax = 1.0;
    3720           11 :         int Iter = 0; // iteration counter
    3721              : 
    3722           11 :         auto &inletNode = state.dataLoopNodes->Node(fanCoil.AirInNode);
    3723              : 
    3724           11 :         if (QZnReq < (-1.0 * FanCoilUnits::Small5WLoad) && state.dataFanCoilUnits->CoolingLoad) {
    3725            1 :             ControlOffset = fanCoil.ColdControlOffset;
    3726            1 :             if (fanCoil.SpeedFanSel == 1) {
    3727            0 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
    3728            0 :                 PLR = std::abs(QZnReq / QUnitOutMax);
    3729            0 :                 if (PLR > 1.0) PLR = 1.0;
    3730              :                 // adjust the PLR to meet the cooling load by calling Calc4PipeFanCoil repeatedly
    3731            0 :                 while (std::abs(Error) > ControlOffset && std::abs(AbsError) > FanCoilUnits::Small5WLoad && Iter < MaxIterCycl && PLR != 1.0) {
    3732            0 :                     inletNode.MassFlowRateMinAvail = inletNode.MassFlowRate;
    3733            0 :                     mdot = PLR * fanCoil.MaxCoolCoilFluidFlow;
    3734            0 :                     PlantUtilities::SetComponentFlowRate(
    3735            0 :                         state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    3736            0 :                     if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3737            0 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3738              :                     } else {
    3739            0 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3740              :                     }
    3741            0 :                     Error = (QZnReq - QUnitOut) / QZnReq;
    3742            0 :                     AbsError = QZnReq - QUnitOut;
    3743            0 :                     DelPLR = (QZnReq - QUnitOut) / QUnitOutMax;
    3744            0 :                     PLR += Relax * DelPLR;
    3745            0 :                     PLR = max(0.0, min(1.0, PLR));
    3746            0 :                     ++Iter;
    3747            0 :                     if (Iter == 32) Relax = 0.5;
    3748            0 :                     if (Iter == 65) Relax = 0.25;
    3749            0 :                     if (Iter > 70 && PLR == 0.0 && DelPLR < 0.0) Error = 0.0;
    3750              :                 }
    3751            0 :                 if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3752            0 :                     Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3753              :                 } else {
    3754            0 :                     Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3755              :                 }
    3756              :                 // warning if not converged
    3757            0 :                 if (Iter > (MaxIterCycl - 1)) {
    3758            0 :                     if (fanCoil.MaxIterIndexC == 0) {
    3759            0 :                         ShowWarningMessage(state,
    3760            0 :                                            format("ZoneHVAC:FourPipeFanCoil=\"{}\" -- Exceeded max iterations while adjusting cycling fan sensible "
    3761              :                                                   "runtime to meet the zone load within the cooling convergence tolerance.",
    3762            0 :                                                   fanCoil.Name));
    3763            0 :                         ShowContinueErrorTimeStamp(state, format("Iterations={}", MaxIterCycl));
    3764              :                     }
    3765            0 :                     ShowRecurringWarningErrorAtEnd(state,
    3766            0 :                                                    "ZoneHVAC:FourPipeFanCoil=\"" + fanCoil.Name +
    3767              :                                                        "\"  -- Exceeded max iterations error (sensible runtime) continues...",
    3768            0 :                                                    fanCoil.MaxIterIndexC);
    3769              :                 }
    3770              : 
    3771              :             } else {
    3772            1 :                 if (fanCoil.SpeedFanSel == 2) {
    3773            1 :                     HighSpeedRatio = fanCoil.MedSpeedRatio;
    3774            1 :                     LowSpeedRatio = fanCoil.LowSpeedRatio;
    3775              :                 } else {
    3776            0 :                     HighSpeedRatio = 1;
    3777            0 :                     LowSpeedRatio = fanCoil.MedSpeedRatio;
    3778              :                 }
    3779              :                 // get capacity at lower speed
    3780            1 :                 fanCoil.SpeedFanRatSel = LowSpeedRatio;
    3781            1 :                 fanCoil.SpeedFanSel = fanCoil.SpeedFanSel - 1;
    3782            1 :                 AirMassFlowLow = LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3783            1 :                 inletNode.MassFlowRate = AirMassFlowLow;
    3784            1 :                 inletNode.MassFlowRateMax = AirMassFlowLow;
    3785            1 :                 inletNode.MassFlowRateMaxAvail = AirMassFlowLow;
    3786            1 :                 inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    3787            1 :                 state.dataFanCoilUnits->FanFlowRatio = LowSpeedRatio;
    3788            1 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMaxLS);
    3789            1 :                 FanElecPowerLS = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    3790              :                 // get capacity at higher speed
    3791            1 :                 fanCoil.SpeedFanRatSel = HighSpeedRatio;
    3792            1 :                 fanCoil.SpeedFanSel = fanCoil.SpeedFanSel + 1;
    3793            1 :                 AirMassFlowHigh = HighSpeedRatio * fanCoil.MaxAirMassFlow;
    3794            1 :                 inletNode.MassFlowRate = AirMassFlowHigh;
    3795            1 :                 inletNode.MassFlowRateMax = AirMassFlowHigh;
    3796            1 :                 inletNode.MassFlowRateMaxAvail = AirMassFlowHigh;
    3797            1 :                 inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    3798            1 :                 state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio;
    3799            1 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMaxHS);
    3800            1 :                 FanElecPowerHS = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    3801              :                 // calc speed ratio
    3802            1 :                 if (std::abs(QZnReq) > std::abs(QUnitOutMaxHS)) {
    3803            0 :                     SRatio = 1.0;
    3804            0 :                     AirMassFlowAvg = AirMassFlowHigh;
    3805            0 :                     inletNode.MassFlowRate = AirMassFlowHigh;
    3806            0 :                     inletNode.MassFlowRateMax = AirMassFlowHigh;
    3807            0 :                     inletNode.MassFlowRateMaxAvail = AirMassFlowHigh;
    3808            0 :                     inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    3809            0 :                     state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio;
    3810            0 :                     Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3811              :                 } else {
    3812            1 :                     SRatio = std::abs((QZnReq - QUnitOutMaxLS) / (QUnitOutMaxHS - QUnitOutMaxLS));
    3813            1 :                     if (SRatio > 1.0) SRatio = 1.0;
    3814            1 :                     AirMassFlowAvg = AirMassFlowHigh * SRatio + AirMassFlowLow * (1.0 - SRatio);
    3815            1 :                     inletNode.MassFlowRate = AirMassFlowAvg;
    3816            1 :                     inletNode.MassFlowRateMax = AirMassFlowAvg;
    3817            1 :                     inletNode.MassFlowRateMaxAvail = AirMassFlowAvg;
    3818            1 :                     inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    3819            1 :                     state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio * SRatio + LowSpeedRatio * (1.0 - SRatio);
    3820            1 :                     Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3821              :                     // adjust the PLR to meet the cooling load by calling Calc4PipeFanCoil repeatedly
    3822            4 :                     while (std::abs(Error) > ControlOffset && std::abs(AbsError) > FanCoilUnits::Small5WLoad && Iter < MaxIterCycl && SRatio != 1.0) {
    3823            3 :                         AirMassFlowAvg = AirMassFlowHigh * SRatio + AirMassFlowLow * (1.0 - SRatio);
    3824            3 :                         state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio * SRatio + LowSpeedRatio * (1.0 - SRatio);
    3825            3 :                         inletNode.MassFlowRate = AirMassFlowAvg;
    3826            3 :                         inletNode.MassFlowRateMax = AirMassFlowAvg;
    3827            3 :                         inletNode.MassFlowRateMaxAvail = AirMassFlowAvg;
    3828            3 :                         inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    3829            3 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3830            3 :                         Error = (QZnReq - QUnitOut) / QZnReq;
    3831            3 :                         AbsError = QZnReq - QUnitOut;
    3832            3 :                         DelPLR = (QZnReq - QUnitOut) / (QUnitOutMaxHS - QUnitOutMaxLS);
    3833            3 :                         SRatio += Relax * DelPLR;
    3834            3 :                         SRatio = max(0.0, min(1.0, SRatio));
    3835            3 :                         ++Iter;
    3836            3 :                         if (Iter == 32) Relax = 0.5;
    3837            3 :                         if (Iter == 65) Relax = 0.25;
    3838            3 :                         if (Iter > 70 && SRatio == 0.0 && DelPLR < 0.0) Error = 0.0;
    3839              :                     }
    3840              :                 }
    3841              :             }
    3842           10 :         } else if (QZnReq > FanCoilUnits::Small5WLoad && state.dataFanCoilUnits->HeatingLoad) {
    3843           10 :             ControlOffset = fanCoil.HotControlOffset;
    3844           10 :             if (fanCoil.SpeedFanSel == 1) {
    3845            3 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
    3846            3 :                 PLR = std::abs(QZnReq / QUnitOutMax);
    3847            3 :                 if (PLR > 1.0) PLR = 1.0;
    3848            3 :                 if (fanCoil.HCoilType_Num == HCoil::Water) {
    3849              :                     // adjust the PLR to meet the heating load by calling Calc4PipeFanCoil repeatedly
    3850            0 :                     while (std::abs(Error) > ControlOffset && std::abs(AbsError) > FanCoilUnits::Small5WLoad && Iter < MaxIterCycl && PLR != 1.0) {
    3851            0 :                         inletNode.MassFlowRateMinAvail = inletNode.MassFlowRate;
    3852            0 :                         mdot = PLR * fanCoil.MaxHeatCoilFluidFlow;
    3853            0 :                         PlantUtilities::SetComponentFlowRate(
    3854            0 :                             state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    3855            0 :                         if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3856            0 :                             Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3857              :                         } else {
    3858            0 :                             Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3859              :                         }
    3860            0 :                         Error = (QZnReq - QUnitOut) / QZnReq;
    3861            0 :                         AbsError = QZnReq - QUnitOut;
    3862            0 :                         DelPLR = (QZnReq - QUnitOut) / QUnitOutMax;
    3863            0 :                         PLR += Relax * DelPLR;
    3864            0 :                         PLR = max(0.0, min(1.0, PLR));
    3865            0 :                         ++Iter;
    3866            0 :                         if (Iter == 32) Relax = 0.5;
    3867            0 :                         if (Iter == 65) Relax = 0.25;
    3868            0 :                         if (Iter > 70 && PLR == 0.0 && DelPLR < 0.0) Error = 0.0; // exit loop if PLR = 0
    3869              :                     }
    3870            0 :                     if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3871            0 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3872              :                     } else {
    3873            0 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3874              :                     }
    3875              :                     // warning if not converged
    3876            0 :                     if (Iter > (MaxIterCycl - 1)) {
    3877            0 :                         if (fanCoil.MaxIterIndexH == 0) {
    3878            0 :                             ShowWarningMessage(state,
    3879            0 :                                                format("ZoneHVAC:FourPipeFanCoil=\"{}\" -- Exceeded max iterations while adjusting cycling fan "
    3880              :                                                       "sensible runtime to meet the zone load within the heating convergence tolerance.",
    3881            0 :                                                       fanCoil.Name));
    3882            0 :                             ShowContinueErrorTimeStamp(state, format("Iterations={}", MaxIterCycl));
    3883              :                         }
    3884            0 :                         ShowRecurringWarningErrorAtEnd(state,
    3885            0 :                                                        "ZoneHVAC:FourPipeFanCoil=\"" + fanCoil.Name +
    3886              :                                                            "\"  -- Exceeded max iterations error (sensible runtime) continues...",
    3887            0 :                                                        fanCoil.MaxIterIndexH);
    3888              :                     }
    3889              :                 } else {
    3890            3 :                     Real64 eHeatCoilPLR = PLR;
    3891              :                     // electric heating coil
    3892            3 :                     if (QUnitOutMax > QZnReq) {
    3893              :                         // heating coil output is larger than required, mudulate the electric heating coil output to meet the load
    3894            3 :                         inletNode.MassFlowRateMinAvail = inletNode.MassFlowRate;
    3895              : 
    3896            3 :                         if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3897            8 :                             auto f = [&state, FanCoilNum, FirstHVACIteration, ZoneNum, QZnReq](Real64 const CyclingR) {
    3898            6 :                                 return CalcFanCoilHeatCoilPLRResidual(state, CyclingR, FanCoilNum, FirstHVACIteration, ZoneNum, QZnReq);
    3899            2 :                             };
    3900            2 :                             General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, eHeatCoilPLR, f, 0.0, 1.0);
    3901              :                         } else {
    3902            4 :                             auto f = [&state, FirstHVACIteration, FanCoilNum, ZoneNum, QZnReq](Real64 const PartLoadRatio) {
    3903            3 :                                 return CalcFanCoilLoadResidual(state, FanCoilNum, FirstHVACIteration, ZoneNum, QZnReq, PartLoadRatio);
    3904            1 :                             };
    3905            1 :                             General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, eHeatCoilPLR, f, 0.0, 1.0);
    3906              :                         }
    3907            3 :                         if (SolFlag == -1) {
    3908            0 :                             ++fanCoil.ConvgErrCountH;
    3909            0 :                             if (fanCoil.ConvgErrCountH < 2) {
    3910            0 :                                 ShowWarningError(state, format("Electric heating coil control failed in fan coil unit {}", fanCoil.Name));
    3911            0 :                                 ShowContinueError(state, "  Iteration limit exceeded in calculating electric heating coil capacity modulation ");
    3912            0 :                                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, _, eHeatCoilPLR);
    3913            0 :                                 ShowContinueErrorTimeStamp(state, format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut));
    3914            0 :                                 ShowContinueErrorTimeStamp(
    3915            0 :                                     state, format("Electric heating coil part load ratio used during last iterations = {}", eHeatCoilPLR));
    3916              :                             } else {
    3917            0 :                                 ShowRecurringWarningErrorAtEnd(
    3918            0 :                                     state, "Electric heating coil Iteration limit exceeded in fan coil unit " + fanCoil.Name, fanCoil.MaxIterIndexH);
    3919              :                             }
    3920            3 :                         } else if (SolFlag == -2) {
    3921            0 :                             ++fanCoil.LimitErrCountH;
    3922            0 :                             if (fanCoil.LimitErrCountH < 2) {
    3923            0 :                                 ShowWarningError(state,
    3924            0 :                                                  format("Part load ratio electric heating coil control failed in fan coil unit {}", fanCoil.Name));
    3925            0 :                                 ShowContinueError(state, "  Bad par load ratio limits");
    3926            0 :                                 ShowContinueErrorTimeStamp(state, "..Par load ratio set to 0");
    3927              :                             } else {
    3928            0 :                                 ShowRecurringWarningErrorAtEnd(state,
    3929            0 :                                                                "Part load ratio electric heating coil control failed in fan coil unit " +
    3930            0 :                                                                    fanCoil.Name,
    3931            0 :                                                                fanCoil.BadMassFlowLimIndexH);
    3932              :                             }
    3933              :                         }
    3934              :                     } else {
    3935            0 :                         eHeatCoilPLR = 1.0;
    3936              :                     }
    3937            3 :                     PLR = eHeatCoilPLR;
    3938              :                     // at the end calculate output
    3939            3 :                     if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3940            2 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, _, eHeatCoilPLR);
    3941              :                     } else {
    3942            1 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3943              :                     }
    3944              :                 }
    3945              : 
    3946              :             } else {
    3947            7 :                 if (fanCoil.SpeedFanSel == 2) {
    3948            3 :                     HighSpeedRatio = fanCoil.MedSpeedRatio;
    3949            3 :                     LowSpeedRatio = fanCoil.LowSpeedRatio;
    3950              :                 } else {
    3951            4 :                     HighSpeedRatio = 1;
    3952            4 :                     LowSpeedRatio = fanCoil.MedSpeedRatio;
    3953              :                 }
    3954              :                 // get capacity at lower speed ratio
    3955            7 :                 fanCoil.SpeedFanRatSel = LowSpeedRatio;
    3956            7 :                 fanCoil.SpeedFanSel = fanCoil.SpeedFanSel - 1;
    3957            7 :                 AirMassFlowLow = LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3958            7 :                 inletNode.MassFlowRate = AirMassFlowLow;
    3959            7 :                 inletNode.MassFlowRateMax = AirMassFlowLow;
    3960            7 :                 inletNode.MassFlowRateMaxAvail = AirMassFlowLow;
    3961            7 :                 inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    3962            7 :                 state.dataFanCoilUnits->FanFlowRatio = LowSpeedRatio;
    3963            7 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMaxLS);
    3964            7 :                 FanElecPowerLS = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    3965              :                 // get capacity at higher speed
    3966            7 :                 fanCoil.SpeedFanRatSel = HighSpeedRatio;
    3967            7 :                 fanCoil.SpeedFanSel = fanCoil.SpeedFanSel + 1;
    3968            7 :                 AirMassFlowHigh = HighSpeedRatio * fanCoil.MaxAirMassFlow;
    3969            7 :                 inletNode.MassFlowRate = AirMassFlowHigh;
    3970            7 :                 inletNode.MassFlowRateMax = AirMassFlowHigh;
    3971            7 :                 inletNode.MassFlowRateMaxAvail = AirMassFlowHigh;
    3972            7 :                 inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    3973            7 :                 state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio;
    3974            7 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMaxHS);
    3975            7 :                 FanElecPowerHS = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    3976              :                 // calc speed ratio
    3977            7 :                 if (std::abs(QZnReq) > std::abs(QUnitOutMaxHS)) {
    3978            2 :                     SRatio = 1.0;
    3979            2 :                     AirMassFlowAvg = AirMassFlowHigh;
    3980            2 :                     inletNode.MassFlowRate = AirMassFlowAvg;
    3981            2 :                     inletNode.MassFlowRateMax = AirMassFlowAvg;
    3982            2 :                     inletNode.MassFlowRateMaxAvail = AirMassFlowAvg;
    3983            2 :                     inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    3984            2 :                     state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio;
    3985            2 :                     Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3986              :                 } else {
    3987            5 :                     SRatio = std::abs((QZnReq - QUnitOutMaxLS) / (QUnitOutMaxHS - QUnitOutMaxLS));
    3988            5 :                     if (SRatio > 1.0) SRatio = 1.0;
    3989            5 :                     AirMassFlowAvg = AirMassFlowHigh * SRatio + AirMassFlowLow * (1.0 - SRatio);
    3990            5 :                     inletNode.MassFlowRate = AirMassFlowAvg;
    3991            5 :                     inletNode.MassFlowRateMax = AirMassFlowAvg;
    3992            5 :                     inletNode.MassFlowRateMaxAvail = AirMassFlowAvg;
    3993            5 :                     inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    3994            5 :                     state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio * SRatio + LowSpeedRatio * (1.0 - SRatio);
    3995            5 :                     Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3996            5 :                     ControlOffset = fanCoil.HotControlOffset;
    3997              :                     // adjust the PLR to meet the heating load calling Calc4PipeFanCoil repeatedly
    3998           14 :                     while (std::abs(Error) > ControlOffset && std::abs(AbsError) > FanCoilUnits::Small5WLoad && Iter < MaxIterCycl && SRatio != 1.0) {
    3999            9 :                         AirMassFlowAvg = AirMassFlowHigh * SRatio + AirMassFlowLow * (1.0 - SRatio);
    4000            9 :                         inletNode.MassFlowRate = AirMassFlowAvg;
    4001            9 :                         inletNode.MassFlowRateMax = AirMassFlowAvg;
    4002            9 :                         inletNode.MassFlowRateMaxAvail = AirMassFlowAvg;
    4003            9 :                         inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    4004            9 :                         state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio * SRatio + LowSpeedRatio * (1.0 - SRatio);
    4005            9 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    4006            9 :                         Error = (QZnReq - QUnitOut) / QZnReq;
    4007            9 :                         AbsError = QZnReq - QUnitOut;
    4008            9 :                         DelPLR = (QZnReq - QUnitOut) / (QUnitOutMaxHS - QUnitOutMaxLS);
    4009            9 :                         SRatio += Relax * DelPLR;
    4010            9 :                         SRatio = max(0.0, min(1.0, SRatio));
    4011            9 :                         ++Iter;
    4012            9 :                         if (Iter == 32) Relax = 0.5;
    4013            9 :                         if (Iter == 65) Relax = 0.25;
    4014            9 :                         if (Iter > 70 && SRatio == 0.0 && DelPLR < 0.0) Error = 0.0;
    4015              :                     }
    4016              :                 }
    4017              :                 // FanElecPower = FanElecPowerHS * SRatio + FanElecPowerLS * ( 1.0 - SRatio ); // why set the ugly global here?
    4018            7 :                 fanCoil.ElecPower = FanElecPowerHS * SRatio + FanElecPowerLS * (1.0 - SRatio);
    4019              :             }
    4020              :         }
    4021           11 :         state.dataLoopNodes->Node(fanCoil.AirOutNode).MassFlowRate = inletNode.MassFlowRate;
    4022           11 :         PartLoadRatio = PLR;
    4023           11 :         SpeedRatio = SRatio;
    4024           11 :         PowerMet = QUnitOut;
    4025           11 :     }
    4026              : 
    4027        20300 :     void ReportFanCoilUnit(EnergyPlusData &state, int const FanCoilNum) // number of the current fan coil unit being simulated
    4028              :     {
    4029              : 
    4030              :         // SUBROUTINE INFORMATION:
    4031              :         //       AUTHOR         Fred Buhl
    4032              :         //       DATE WRITTEN   March 2000
    4033              : 
    4034              :         // PURPOSE OF THIS SUBROUTINE:
    4035              :         // Fills some of the report variables for the fan coil units
    4036              : 
    4037              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4038        20300 :         Real64 ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
    4039              : 
    4040        20300 :         state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatEnergy = state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatPower * ReportingConstant;
    4041        20300 :         state.dataFanCoilUnits->FanCoil(FanCoilNum).SensCoolEnergy = state.dataFanCoilUnits->FanCoil(FanCoilNum).SensCoolPower * ReportingConstant;
    4042        20300 :         state.dataFanCoilUnits->FanCoil(FanCoilNum).TotCoolEnergy = state.dataFanCoilUnits->FanCoil(FanCoilNum).TotCoolPower * ReportingConstant;
    4043        20300 :         state.dataFanCoilUnits->FanCoil(FanCoilNum).ElecEnergy = state.dataFanCoilUnits->FanCoil(FanCoilNum).ElecPower * ReportingConstant;
    4044              : 
    4045        20300 :         if (state.dataFanCoilUnits->FanCoil(FanCoilNum).FirstPass) { // reset sizing flags so other zone equipment can size normally
    4046           10 :             if (!state.dataGlobal->SysSizingCalc) {
    4047            5 :                 DataSizing::resetHVACSizingGlobals(state, state.dataSize->CurZoneEqNum, 0, state.dataFanCoilUnits->FanCoil(FanCoilNum).FirstPass);
    4048              :             }
    4049              :         }
    4050        20300 :     }
    4051              : 
    4052         1201 :     int GetFanCoilZoneInletAirNode(EnergyPlusData &state, int const FanCoilNum)
    4053              :     {
    4054              : 
    4055              :         // FUNCTION INFORMATION:
    4056              :         //       AUTHOR         B Griffith
    4057              :         //       DATE WRITTEN   Dec  2006
    4058              : 
    4059              :         // PURPOSE OF THIS FUNCTION:
    4060              :         // lookup function for OA inlet node for ventilation rate reporting
    4061              : 
    4062         1201 :         if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
    4063            0 :             GetFanCoilUnits(state);
    4064            0 :             state.dataFanCoilUnits->GetFanCoilInputFlag = false;
    4065              :         }
    4066              : 
    4067         1201 :         if (FanCoilNum > 0 && FanCoilNum <= state.dataFanCoilUnits->NumFanCoils) {
    4068         1201 :             return state.dataFanCoilUnits->FanCoil(FanCoilNum).AirOutNode;
    4069              :         }
    4070              : 
    4071            0 :         return 0;
    4072              :     }
    4073              : 
    4074         1201 :     int GetFanCoilOutAirNode(EnergyPlusData &state, int const FanCoilNum)
    4075              :     {
    4076              : 
    4077              :         // FUNCTION INFORMATION:
    4078              :         //       AUTHOR         B Griffith
    4079              :         //       DATE WRITTEN   Dec  2006
    4080              : 
    4081              :         // PURPOSE OF THIS FUNCTION:
    4082              :         // lookup function for OA inlet node for ventilation rate reporting
    4083              : 
    4084         1201 :         if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
    4085            0 :             GetFanCoilUnits(state);
    4086            0 :             state.dataFanCoilUnits->GetFanCoilInputFlag = false;
    4087              :         }
    4088              : 
    4089         1201 :         if (FanCoilNum > 0 && FanCoilNum <= state.dataFanCoilUnits->NumFanCoils) {
    4090         1201 :             return state.dataFanCoilUnits->FanCoil(FanCoilNum).OutsideAirNode;
    4091              :         }
    4092              : 
    4093            0 :         return 0;
    4094              :     }
    4095              : 
    4096         1201 :     int GetFanCoilReturnAirNode(EnergyPlusData &state, int const FanCoilNum)
    4097              :     {
    4098              : 
    4099              :         // FUNCTION INFORMATION:
    4100              :         //       AUTHOR         B Griffith
    4101              :         //       DATE WRITTEN   Dec  2006
    4102              : 
    4103              :         // PURPOSE OF THIS FUNCTION:
    4104              :         // lookup function for mixer's return node
    4105              : 
    4106         1201 :         if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
    4107            0 :             GetFanCoilUnits(state);
    4108            0 :             state.dataFanCoilUnits->GetFanCoilInputFlag = false;
    4109              :         }
    4110              : 
    4111         1201 :         if (FanCoilNum > 0 && FanCoilNum <= state.dataFanCoilUnits->NumFanCoils) {
    4112         1201 :             if (state.dataFanCoilUnits->FanCoil(FanCoilNum).OAMixIndex > 0) {
    4113         1200 :                 return MixedAir::GetOAMixerReturnNodeNumber(state, state.dataFanCoilUnits->FanCoil(FanCoilNum).OAMixIndex);
    4114              :             }
    4115              :         }
    4116              : 
    4117            1 :         return 0;
    4118              :     }
    4119              : 
    4120         1201 :     int GetFanCoilMixedAirNode(EnergyPlusData &state, int const FanCoilNum)
    4121              :     {
    4122              : 
    4123              :         // FUNCTION INFORMATION:
    4124              :         //       AUTHOR         B Griffith
    4125              :         //       DATE WRITTEN   Dec  2006
    4126              : 
    4127              :         // PURPOSE OF THIS FUNCTION:
    4128              :         // lookup function for mixer's return node
    4129              : 
    4130         1201 :         if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
    4131            0 :             GetFanCoilUnits(state);
    4132            0 :             state.dataFanCoilUnits->GetFanCoilInputFlag = false;
    4133              :         }
    4134              : 
    4135         1201 :         if (FanCoilNum > 0 && FanCoilNum <= state.dataFanCoilUnits->NumFanCoils) {
    4136         1201 :             if (state.dataFanCoilUnits->FanCoil(FanCoilNum).OAMixIndex > 0) {
    4137         1200 :                 return MixedAir::GetOAMixerMixedNodeNumber(state, state.dataFanCoilUnits->FanCoil(FanCoilNum).OAMixIndex);
    4138              :             }
    4139              :         }
    4140              : 
    4141            1 :         return 0;
    4142              :     }
    4143              : 
    4144           18 :     Real64 CalcFanCoilLoadResidual(EnergyPlusData &state,
    4145              :                                    int FanCoilNum,            // Index to this fan coil unit
    4146              :                                    bool FirstHVACIteration,   // FirstHVACIteration flag
    4147              :                                    int ControlledZoneNum,     // zone index
    4148              :                                    Real64 QZnReq,             // Sensible load to be met [W]
    4149              :                                    Real64 const PartLoadRatio // coil part load ratio
    4150              :     )
    4151              :     {
    4152              :         // FUNCTION INFORMATION:
    4153              :         //       AUTHOR         Richard Raustad, FSEC
    4154              :         //       DATE WRITTEN   July 2015
    4155              : 
    4156              :         // PURPOSE OF THIS SUBROUTINE:
    4157              :         // To calculate the part-load ratio for the FCU with electric heating coil
    4158              : 
    4159              :         Real64 QUnitOut; // delivered capacity [W]
    4160           18 :         Calc4PipeFanCoil(state,
    4161              :                          FanCoilNum,
    4162              :                          ControlledZoneNum,
    4163              :                          FirstHVACIteration,
    4164              :                          QUnitOut,
    4165              :                          PartLoadRatio); // needs PLR=0 for electric heating coil, otherwise will run a full capacity
    4166              :         // Calculate residual based on output magnitude
    4167           18 :         if (std::abs(QZnReq) <= 100.0) {
    4168            0 :             return (QUnitOut - QZnReq) / 100.0;
    4169              :         } else {
    4170           18 :             return (QUnitOut - QZnReq) / QZnReq;
    4171              :         }
    4172              :     }
    4173              : 
    4174        52882 :     Real64 CalcFanCoilPLRResidual(EnergyPlusData &state,
    4175              :                                   Real64 const PLR,        // part-load ratio of air and water mass flow rate
    4176              :                                   int FanCoilNum,          // Index to this fan coil unit
    4177              :                                   bool FirstHVACIteration, // FirstHVACIteration flag
    4178              :                                   int ControlledZoneNum,   // zone index
    4179              :                                   int WaterControlNode,    // water node to control
    4180              :                                   Real64 QZnReq            // Sensible load to be met [W] // Function parameters
    4181              :     )
    4182              :     {
    4183              : 
    4184              :         // FUNCTION INFORMATION:
    4185              :         //       AUTHOR         Richard Raustad
    4186              :         //       DATE WRITTEN   August 2016
    4187              : 
    4188              :         // PURPOSE OF THIS SUBROUTINE:
    4189              :         Real64 QUnitOut; // delivered capacity [W]
    4190        52882 :         if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode) {
    4191        26483 :             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * state.dataFanCoilUnits->FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
    4192        26483 :             Calc4PipeFanCoil(state,
    4193              :                              FanCoilNum,
    4194              :                              ControlledZoneNum,
    4195              :                              FirstHVACIteration,
    4196              :                              QUnitOut,
    4197              :                              PLR); // needs PLR=0 for electric heating coil, otherwise will run a full capacity
    4198        52798 :         } else if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatCoilFluidInletNode &&
    4199        26399 :                    state.dataFanCoilUnits->FanCoil(FanCoilNum).HCoilType_Num != HCoil::Electric) {
    4200        26399 :             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * state.dataFanCoilUnits->FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
    4201        26399 :             Calc4PipeFanCoil(state,
    4202              :                              FanCoilNum,
    4203              :                              ControlledZoneNum,
    4204              :                              FirstHVACIteration,
    4205              :                              QUnitOut,
    4206              :                              PLR); // needs PLR=0 for electric heating coil, otherwise will run a full capacity
    4207              :         } else {
    4208            0 :             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR); // needs PLR=1 for electric heating coil
    4209              :         }
    4210              : 
    4211              :         // Calculate residual based on output magnitude
    4212        52882 :         if (std::abs(QZnReq) <= 100.0) {
    4213         1201 :             return (QUnitOut - QZnReq) / 100.0;
    4214              :         } else {
    4215        51681 :             return (QUnitOut - QZnReq) / QZnReq;
    4216              :         }
    4217              :     }
    4218              : 
    4219           12 :     Real64 CalcFanCoilHeatCoilPLRResidual(EnergyPlusData &state,
    4220              :                                           Real64 const CyclingR, // electric heating coil cycling ratio
    4221              :                                           int const FanCoilNum,
    4222              :                                           bool const FirstHVACIteration,
    4223              :                                           int const ZoneNum,
    4224              :                                           Real64 const QZnReq)
    4225              :     {
    4226              :         // PURPOSE OF THIS SUBROUTINE:
    4227              :         // Calculate electric heating coil cycling ratio of FanCoilUnit with MultiSpeedFan
    4228              :         // capacity control method when running with at lowest speed for a continuous
    4229              :         // fan operating mode.
    4230              : 
    4231              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4232              :         Real64 QUnitOut;            // delivered capacity [W]
    4233           12 :         Real64 constexpr PLR = 1.0; // fan coil unit PLR
    4234              : 
    4235              :         // electric heating coil cycling ratio at minimum air flow for constant fan operating mode
    4236           12 :         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR, CyclingR);
    4237              : 
    4238              :         // Calculate residual based on output magnitude
    4239           12 :         if (std::abs(QZnReq) <= 100.0) {
    4240            0 :             return (QUnitOut - QZnReq) / 100.0;
    4241              :         } else {
    4242           12 :             return (QUnitOut - QZnReq) / QZnReq;
    4243              :         }
    4244              :     }
    4245              : 
    4246           48 :     Real64 CalcFanCoilCWLoadResidual(EnergyPlusData &state,
    4247              :                                      Real64 const CWFlow, // water mass flow rate [kg/s]
    4248              :                                      int const FanCoilNum,
    4249              :                                      bool const FirstHVACIteration,
    4250              :                                      int const ControlledZoneNum,
    4251              :                                      Real64 const QZnReq)
    4252              :     {
    4253              : 
    4254              :         // FUNCTION INFORMATION:
    4255              :         //       AUTHOR         Fred Buhl Jan 2016
    4256              :         //       DATE WRITTEN   July 2015
    4257              : 
    4258              :         // PURPOSE OF THIS SUBROUTINE:
    4259              :         // To calculate the part-load ratio for the FCU with electric heating coil
    4260              : 
    4261              :         Real64 QUnitOut; // delivered capacity [W]
    4262           48 :         state.dataLoopNodes->Node(state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode).MassFlowRate = CWFlow;
    4263           48 :         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, 1.0);
    4264              : 
    4265              :         // Calculate residual based on output magnitude
    4266           48 :         if (std::abs(QZnReq) <= 100.0) {
    4267            0 :             return (QUnitOut - QZnReq) / 100.0;
    4268              :         } else {
    4269           48 :             return (QUnitOut - QZnReq) / QZnReq;
    4270              :         }
    4271              :     }
    4272              : 
    4273           60 :     Real64 CalcFanCoilWaterFlowResidual(EnergyPlusData &state,
    4274              :                                         Real64 const PLR,
    4275              :                                         int FanCoilNum,
    4276              :                                         bool FirstHVACIteration,
    4277              :                                         int ControlledZoneNum,
    4278              :                                         Real64 QZnReq,
    4279              :                                         int AirInNode,
    4280              :                                         int WaterControlNode,
    4281              :                                         Real64 maxCoilFluidFlow,
    4282              :                                         Real64 AirMassFlowRate)
    4283              :     {
    4284              : 
    4285              :         // FUNCTION INFORMATION:
    4286              :         //       AUTHOR         Richard Raustad, FSEC
    4287              :         //       DATE WRITTEN   December 2015
    4288              : 
    4289              :         // PURPOSE OF THIS SUBROUTINE:
    4290              :         // To calculate the part-load ratio for the FCU with varying water flow rate
    4291              : 
    4292           60 :         Real64 const mDot = PLR * maxCoilFluidFlow;
    4293           60 :         if (WaterControlNode > 0) state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mDot;
    4294           60 :         state.dataLoopNodes->Node(AirInNode).MassFlowRate = AirMassFlowRate;
    4295              : 
    4296              :         Real64 QUnitOut;
    4297           97 :         if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode ||
    4298           37 :             (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatCoilFluidInletNode &&
    4299           37 :              state.dataFanCoilUnits->FanCoil(FanCoilNum).HCoilType_Num != HCoil::Electric)) {
    4300              : 
    4301           60 :             Calc4PipeFanCoil(state,
    4302              :                              FanCoilNum,
    4303              :                              ControlledZoneNum,
    4304              :                              FirstHVACIteration,
    4305              :                              QUnitOut,
    4306          120 :                              0.0); // needs PLR=0 for electric heating coil, otherwise will run a full capacity
    4307              : 
    4308              :         } else {
    4309            0 :             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    4310              :         }
    4311              : 
    4312              :         // Calculate residual based on output magnitude
    4313           60 :         if (std::abs(QZnReq) <= 100.0) {
    4314            0 :             return (QUnitOut - QZnReq) / 100.0;
    4315              :         } else {
    4316           60 :             return (QUnitOut - QZnReq) / QZnReq;
    4317              :         }
    4318              :     }
    4319              : 
    4320            0 :     Real64 CalcFanCoilAirAndWaterFlowResidual(EnergyPlusData &state,
    4321              :                                               Real64 const PLR, // water and air part load ratio
    4322              :                                               int FanCoilNum,
    4323              :                                               bool FirstHVACIteration,
    4324              :                                               int ControlledZoneNum,
    4325              :                                               Real64 QZnReq,
    4326              :                                               int AirInNode,
    4327              :                                               int WaterControlNode,
    4328              :                                               Real64 MinWaterFlow)
    4329              :     {
    4330              : 
    4331              :         // FUNCTION INFORMATION:
    4332              :         //       AUTHOR         Richard Raustad, FSEC
    4333              :         //       DATE WRITTEN   December 2015
    4334              : 
    4335              :         // PURPOSE OF THIS SUBROUTINE:
    4336              :         // To calculate the part-load ratio for the FCU with varying water flow rate
    4337              : 
    4338              :         // METHODOLOGY EMPLOYED:
    4339              :         // Use SolveRoot to CALL this Function to converge on a solution
    4340              : 
    4341              :         // set air flow rate
    4342            0 :         state.dataLoopNodes->Node(AirInNode).MassFlowRate =
    4343            0 :             state.dataFanCoilUnits->FanCoil(FanCoilNum).MaxAirMassFlow *
    4344            0 :             (state.dataFanCoilUnits->FanCoil(FanCoilNum).LowSpeedRatio + (PLR * (1.0 - state.dataFanCoilUnits->FanCoil(FanCoilNum).LowSpeedRatio)));
    4345              :         // set water flow rate
    4346            0 :         if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode) {
    4347            0 :             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate =
    4348            0 :                 MinWaterFlow + (PLR * (state.dataFanCoilUnits->FanCoil(FanCoilNum).MaxCoolCoilFluidFlow - MinWaterFlow));
    4349            0 :         } else if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatCoilFluidInletNode) {
    4350            0 :             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate =
    4351            0 :                 MinWaterFlow + (PLR * (state.dataFanCoilUnits->FanCoil(FanCoilNum).MaxHeatCoilFluidFlow - MinWaterFlow));
    4352              :         } else {
    4353              :             // developer error
    4354            0 :             ShowFatalError(state,
    4355            0 :                            format("Developer Error - CalcFanCoilAirAndWaterFlowResidual: Water control node not found for {}",
    4356            0 :                                   state.dataFanCoilUnits->FanCoil(FanCoilNum).Name));
    4357              :         }
    4358              :         Real64 QUnitOut; // delivered capacity [W]
    4359            0 :         Calc4PipeFanCoil(state,
    4360              :                          FanCoilNum,
    4361              :                          ControlledZoneNum,
    4362              :                          FirstHVACIteration,
    4363              :                          QUnitOut,
    4364              :                          PLR); // needs PLR for electric heating coil to output a specific capacity
    4365              : 
    4366              :         // Calculate residual based on output magnitude
    4367            0 :         if (std::abs(QZnReq) <= 100.0) {
    4368            0 :             return (QUnitOut - QZnReq) / 100.0;
    4369              :         } else {
    4370            0 :             return (QUnitOut - QZnReq) / QZnReq;
    4371              :         }
    4372              :     }
    4373              : 
    4374            1 :     int getEqIndex(EnergyPlusData &state, std::string_view CompName)
    4375              :     {
    4376            1 :         if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
    4377            0 :             GetFanCoilUnits(state);
    4378            0 :             state.dataFanCoilUnits->GetFanCoilInputFlag = false;
    4379              :         }
    4380              : 
    4381            1 :         for (int FanCoilIndex = 1; FanCoilIndex <= state.dataFanCoilUnits->NumFanCoils; ++FanCoilIndex) {
    4382            1 :             auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilIndex);
    4383            1 :             if (Util::SameString(fanCoil.Name, CompName)) {
    4384            1 :                 return FanCoilIndex;
    4385              :             }
    4386              :         }
    4387              : 
    4388            0 :         return 0;
    4389              :     }
    4390              : 
    4391              : } // namespace FanCoilUnits
    4392              : 
    4393              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1