LCOV - code coverage report
Current view: top level - EnergyPlus - FanCoilUnits.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 62.4 % 2579 1609
Test Date: 2025-06-02 07:23:51 Functions: 73.3 % 30 22

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

Generated by: LCOV version 2.0-1