LCOV - code coverage report
Current view: top level - EnergyPlus - FanCoilUnits.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1623 2573 63.1 %
Date: 2024-08-24 18:31:18 Functions: 22 30 73.3 %

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

Generated by: LCOV version 1.14