LCOV - code coverage report
Current view: top level - EnergyPlus - FanCoilUnits.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 54.1 % 2579 1394
Test Date: 2025-06-02 12:03:30 Functions: 90.0 % 30 27

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cmath>
      50              : 
      51              : // ObjexxFCL Headers
      52              : #include <ObjexxFCL/Array.functions.hh>
      53              : #include <ObjexxFCL/Fmath.hh>
      54              : 
      55              : // EnergyPlus Headers
      56              : #include <EnergyPlus/Autosizing/All_Simple_Sizing.hh>
      57              : #include <EnergyPlus/Autosizing/CoolingAirFlowSizing.hh>
      58              : #include <EnergyPlus/Autosizing/CoolingCapacitySizing.hh>
      59              : #include <EnergyPlus/Autosizing/HeatingAirFlowSizing.hh>
      60              : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
      61              : #include <EnergyPlus/Autosizing/SystemAirFlowSizing.hh>
      62              : #include <EnergyPlus/BranchNodeConnections.hh>
      63              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      64              : #include <EnergyPlus/DataAirSystems.hh>
      65              : #include <EnergyPlus/DataEnvironment.hh>
      66              : #include <EnergyPlus/DataHVACGlobals.hh>
      67              : #include <EnergyPlus/DataHeatBalFanSys.hh>
      68              : #include <EnergyPlus/DataHeatBalance.hh>
      69              : #include <EnergyPlus/DataLoopNode.hh>
      70              : #include <EnergyPlus/DataPrecisionGlobals.hh>
      71              : #include <EnergyPlus/DataSizing.hh>
      72              : #include <EnergyPlus/DataZoneEnergyDemands.hh>
      73              : #include <EnergyPlus/DataZoneEquipment.hh>
      74              : #include <EnergyPlus/FanCoilUnits.hh>
      75              : #include <EnergyPlus/Fans.hh>
      76              : #include <EnergyPlus/FluidProperties.hh>
      77              : #include <EnergyPlus/GeneralRoutines.hh>
      78              : #include <EnergyPlus/HVACHXAssistedCoolingCoil.hh>
      79              : #include <EnergyPlus/HeatingCoils.hh>
      80              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      81              : #include <EnergyPlus/MixedAir.hh>
      82              : #include <EnergyPlus/NodeInputManager.hh>
      83              : #include <EnergyPlus/OutputProcessor.hh>
      84              : #include <EnergyPlus/Plant/DataPlant.hh>
      85              : #include <EnergyPlus/PlantUtilities.hh>
      86              : #include <EnergyPlus/Psychrometrics.hh>
      87              : #include <EnergyPlus/ReportCoilSelection.hh>
      88              : #include <EnergyPlus/SZVAVModel.hh>
      89              : #include <EnergyPlus/ScheduleManager.hh>
      90              : #include <EnergyPlus/SingleDuct.hh>
      91              : #include <EnergyPlus/UtilityRoutines.hh>
      92              : #include <EnergyPlus/WaterCoils.hh>
      93              : #include <EnergyPlus/ZoneEquipmentManager.hh>
      94              : #include <EnergyPlus/ZonePlenum.hh>
      95              : 
      96              : namespace EnergyPlus {
      97              : 
      98              : namespace FanCoilUnits {
      99              : 
     100              :     // Module containing the routines dealing with 2 and 4 pipe fan coil units
     101              : 
     102              :     // MODULE INFORMATION:
     103              :     //       AUTHOR         Fred Buhl
     104              :     //       DATE WRITTEN   March 2000
     105              :     //       MODIFIED       October 2003 (FSEC added cooling coil type)
     106              :     //                      June 2010    Arnaud Flament LBNL added 3-speed and variables-speed fan capacity control;
     107              :     //                                   outside air schedule; and removed coil water inlet node inputs
     108              :     //                      Sept 2010    Brent Griffith, plant upgrades for water coils, fluid properties
     109              : 
     110              :     // PURPOSE OF THIS MODULE:
     111              :     // To encapsulate the data and algorithms needed to simulate 2 and 4 pipe
     112              :     // fan coil units.
     113              : 
     114              :     // METHODOLOGY EMPLOYED:
     115              :     // Units are modeled as a collection of components: outside air mixer,
     116              :     // fan, heating coil and/or cooling coil plus an integrated control
     117              :     // algorithm that adjusts the hot or cold water flow to meet the zone
     118              :     // load. Or varies the air flow rate to meet the zone load. Or both.
     119              : 
     120        20300 :     void SimFanCoilUnit(EnergyPlusData &state,
     121              :                         std::string_view CompName,     // name of the fan coil unit
     122              :                         int const ControlledZoneNum,   // number of zone being served
     123              :                         bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
     124              :                         Real64 &PowerMet,              // Sensible power supplied (W)
     125              :                         Real64 &LatOutputProvided,     // Latent add/removal supplied by window AC (kg/s), dehumid = negative
     126              :                         int &CompIndex)
     127              :     {
     128              : 
     129              :         // SUBROUTINE INFORMATION:
     130              :         //       AUTHOR         Fred Buhl
     131              :         //       DATE WRITTEN   March 2000
     132              :         //       MODIFIED       Don Shirey, Aug 2009 (LatOutputProvided)
     133              : 
     134              :         // PURPOSE OF THIS SUBROUTINE:
     135              :         // Manages the simulation of a fan coil unit. Called from SimZone Equipment
     136              : 
     137              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     138              :         int FanCoilNum; // index of fan coil unit being simulated
     139              : 
     140              :         // First time SimFanCoilUnit is called, get the input for all the fan coil units
     141        20300 :         if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
     142            1 :             GetFanCoilUnits(state);
     143            1 :             state.dataFanCoilUnits->GetFanCoilInputFlag = false;
     144              :         }
     145              : 
     146              :         // Find the correct Fan Coil Equipment
     147        20300 :         if (CompIndex == 0) {
     148            5 :             FanCoilNum = Util::FindItemInList(CompName, state.dataFanCoilUnits->FanCoil);
     149            5 :             if (FanCoilNum == 0) {
     150            0 :                 ShowFatalError(state, format("SimFanCoil: Unit not found={}", CompName));
     151              :             }
     152            5 :             CompIndex = FanCoilNum;
     153              :         } else {
     154        20295 :             FanCoilNum = CompIndex;
     155        20295 :             if (FanCoilNum > state.dataFanCoilUnits->NumFanCoils || FanCoilNum < 1) {
     156            0 :                 ShowFatalError(state,
     157            0 :                                format("SimFanCoil:  Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
     158              :                                       FanCoilNum,
     159            0 :                                       state.dataFanCoilUnits->NumFanCoils,
     160              :                                       CompName));
     161              :             }
     162        20295 :             if (state.dataFanCoilUnits->CheckEquipName(FanCoilNum)) {
     163            5 :                 if (CompName != state.dataFanCoilUnits->FanCoil(FanCoilNum).Name) {
     164            0 :                     ShowFatalError(state,
     165            0 :                                    format("SimFanCoil: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
     166              :                                           FanCoilNum,
     167              :                                           CompName,
     168            0 :                                           state.dataFanCoilUnits->FanCoil(FanCoilNum).Name));
     169              :                 }
     170            5 :                 state.dataFanCoilUnits->CheckEquipName(FanCoilNum) = false;
     171              :             }
     172              :         }
     173              : 
     174        20300 :         state.dataSize->ZoneEqFanCoil = true;
     175              : 
     176              :         // Initialize the fan coil unit
     177        20300 :         InitFanCoilUnits(state, FanCoilNum, ControlledZoneNum);
     178              : 
     179              :         // Select the correct unit type
     180        20300 :         if (state.dataFanCoilUnits->FanCoil(FanCoilNum).UnitType_Num == FanCoilUnit_4Pipe) {
     181        20300 :             Sim4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, PowerMet, LatOutputProvided);
     182              :         }
     183              : 
     184              :         // Report the result of the simulation
     185        20300 :         ReportFanCoilUnit(state, FanCoilNum);
     186              : 
     187        20300 :         state.dataSize->ZoneEqFanCoil = false;
     188        20300 :     }
     189              : 
     190           18 :     void GetFanCoilUnits(EnergyPlusData &state)
     191              :     {
     192              : 
     193              :         // SUBROUTINE INFORMATION:
     194              :         //       AUTHOR         Fred Buhl
     195              :         //       DATE WRITTEN   March 2000
     196              :         //       MODIFIED       Bereket Nigusse, FSEC, April 2011: eliminated input node names
     197              :         //                                                         added OA Mixer object type
     198              :         //                                                         and fan object type
     199              :         //                      Chandan Sharma, FSEC, July 2012: Added zone sys avail managers
     200              : 
     201              :         // PURPOSE OF THIS SUBROUTINE:
     202              :         // Obtains input data for fan coil units and stores it in fan coil data structures
     203              : 
     204              :         // METHODOLOGY EMPLOYED:
     205              :         // Uses "Get" routines to read in data.
     206              : 
     207              :         // Locals
     208              :         // SUBROUTINE ARGUMENT DEFINITIONS:
     209              :         static constexpr std::string_view RoutineName("GetFanCoilUnits: "); // include trailing blank space
     210              :         static constexpr std::string_view routineName = "GetFanCoilUnits";
     211              : 
     212              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     213              :         int NumAlphas;                 // Number of Alphas for each GetObjectItem call
     214              :         int NumNumbers;                // Number of Numbers for each GetObjectItem call
     215           18 :         Array1D_int OANodeNums(4);     // Node numbers of Outdoor air mixer (OA, EA, RA, MA)
     216              :         int IOStatus;                  // Used in GetObjectItem
     217              :         bool IsNotOK;                  // Flag to verify name
     218           18 :         Array1D_string Alphas;         // Alpha input items for object
     219           18 :         Array1D_string cAlphaFields;   // Alpha field names
     220           18 :         Array1D_string cNumericFields; // Numeric field names
     221           18 :         Array1D<Real64> Numbers;       // Numeric input items for object
     222           18 :         Array1D_bool lAlphaBlanks;     // Logical array, alpha field input BLANK = .TRUE.
     223           18 :         Array1D_bool lNumericBlanks;   // Logical array, numeric field input BLANK = .TRUE.
     224              :         int NodeNum;                   // index to loop counter
     225           18 :         std::string ATMixerName;
     226              : 
     227           18 :         auto &ErrorsFound = state.dataFanCoilUnits->ErrorsFound;
     228           18 :         bool &errFlag = state.dataFanCoilUnits->errFlag;
     229              : 
     230              :         // find the number of each type of fan coil unit
     231              : 
     232           18 :         std::string CurrentModuleObject = state.dataFanCoilUnits->cMO_FanCoil;
     233           18 :         state.dataFanCoilUnits->Num4PipeFanCoils = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     234           18 :         state.dataFanCoilUnits->NumFanCoils = state.dataFanCoilUnits->Num4PipeFanCoils;
     235              :         // allocate the data structures
     236           18 :         state.dataFanCoilUnits->FanCoil.allocate(state.dataFanCoilUnits->NumFanCoils);
     237           18 :         state.dataFanCoilUnits->FanCoilNumericFields.allocate(state.dataFanCoilUnits->NumFanCoils);
     238           18 :         state.dataFanCoilUnits->CheckEquipName.dimension(state.dataFanCoilUnits->NumFanCoils, true);
     239              : 
     240           36 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
     241           18 :             state, CurrentModuleObject, state.dataFanCoilUnits->TotalArgs, NumAlphas, NumNumbers);
     242           18 :         Alphas.allocate(NumAlphas);
     243           18 :         cAlphaFields.allocate(NumAlphas);
     244           18 :         cNumericFields.allocate(NumNumbers);
     245           18 :         Numbers.dimension(NumNumbers, 0.0);
     246           18 :         lAlphaBlanks.dimension(NumAlphas, true);
     247           18 :         lNumericBlanks.dimension(NumNumbers, true);
     248              : 
     249              :         // loop over 4 pipe fan coil units; get and load the input data
     250           40 :         for (int FanCoilIndex = 1; FanCoilIndex <= state.dataFanCoilUnits->Num4PipeFanCoils; ++FanCoilIndex) {
     251           22 :             auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilIndex);
     252              : 
     253           22 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     254              :                                                                      CurrentModuleObject,
     255              :                                                                      FanCoilIndex,
     256              :                                                                      Alphas,
     257              :                                                                      NumAlphas,
     258              :                                                                      Numbers,
     259              :                                                                      NumNumbers,
     260              :                                                                      IOStatus,
     261              :                                                                      lNumericBlanks,
     262              :                                                                      lAlphaBlanks,
     263              :                                                                      cAlphaFields,
     264              :                                                                      cNumericFields);
     265              : 
     266           22 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     267              : 
     268           22 :             state.dataFanCoilUnits->FanCoilNumericFields(FanCoilIndex).FieldNames.allocate(NumNumbers);
     269           22 :             state.dataFanCoilUnits->FanCoilNumericFields(FanCoilIndex).FieldNames = "";
     270           22 :             state.dataFanCoilUnits->FanCoilNumericFields(FanCoilIndex).FieldNames = cNumericFields;
     271              : 
     272           22 :             fanCoil.Name = Alphas(1);
     273           22 :             fanCoil.UnitType = CurrentModuleObject;
     274           22 :             fanCoil.UnitType_Num = FanCoilUnit_4Pipe;
     275              : 
     276           22 :             if (lAlphaBlanks(2)) {
     277            0 :                 fanCoil.availSched = Sched::GetScheduleAlwaysOn(state);
     278           22 :             } else if ((fanCoil.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
     279            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
     280            0 :                 ErrorsFound = true;
     281              :             }
     282           22 :             constexpr std::array<std::string_view, static_cast<int>(CCM::Num)> CapCtrlMethUC{"CONSTANTFANVARIABLEFLOW",
     283              :                                                                                              "CYCLINGFAN",
     284              :                                                                                              "VARIABLEFANVARIABLEFLOW",
     285              :                                                                                              "VARIABLEFANCONSTANTFLOW",
     286              :                                                                                              "MULTISPEEDFAN",
     287              :                                                                                              "ASHRAE90VARIABLEFAN"};
     288           22 :             std::string capCtrlMeth = Alphas(3);
     289           22 :             fanCoil.CapCtrlMeth_Num = static_cast<CCM>(getEnumValue(CapCtrlMethUC, capCtrlMeth));
     290           22 :             if (fanCoil.CapCtrlMeth_Num == CCM::ASHRAE) {
     291            3 :                 fanCoil.DesZoneCoolingLoad = DataSizing::AutoSize;
     292            3 :                 fanCoil.DesZoneHeatingLoad = DataSizing::AutoSize;
     293            3 :                 fanCoil.fanOp = HVAC::FanOp::Continuous;
     294              :             }
     295              : 
     296           22 :             if (!lAlphaBlanks(4) && ((fanCoil.oaSched = Sched::GetSchedule(state, Alphas(4))) == nullptr)) {
     297            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(4), Alphas(4));
     298            0 :                 ErrorsFound = true;
     299              :             }
     300           22 :             fanCoil.MaxAirVolFlow = Numbers(1);
     301           22 :             fanCoil.LowSpeedRatio = Numbers(2);
     302           22 :             fanCoil.MedSpeedRatio = Numbers(3);
     303              :             // check if low speed ratio < medium speed ratio, if not : warning & set to default values
     304           22 :             if (fanCoil.LowSpeedRatio > fanCoil.MedSpeedRatio) {
     305            0 :                 ShowWarningError(state, format("{}{}=\"{}\",", RoutineName, CurrentModuleObject, fanCoil.Name));
     306            0 :                 ShowContinueError(state, format("... {} is greater than the medium speed supply air flow ratio.", cNumericFields(2)));
     307            0 :                 ShowContinueError(state, format("... Fan Coil Unit low speed supply air flow ratio = {:.5T} ", fanCoil.LowSpeedRatio));
     308            0 :                 ShowContinueError(state, format("... Fan Coit Unit medium speed supply air flow ratio = {:.5T} ", fanCoil.MedSpeedRatio));
     309            0 :                 ShowContinueError(state,
     310              :                                   "... Fan Coil Unit low speed supply air flow ratio and medium speed supply air flow ratio set to default values");
     311            0 :                 fanCoil.LowSpeedRatio = 1.0 / 3.0;
     312            0 :                 fanCoil.MedSpeedRatio = 2.0 / 3.0;
     313              :             }
     314              : 
     315           22 :             fanCoil.OutAirVolFlow = Numbers(4);
     316              : 
     317           22 :             fanCoil.AirInNode = NodeInputManager::GetOnlySingleNode(state,
     318           22 :                                                                     Alphas(5),
     319              :                                                                     ErrorsFound,
     320              :                                                                     DataLoopNode::ConnectionObjectType::ZoneHVACFourPipeFanCoil,
     321           22 :                                                                     Alphas(1),
     322              :                                                                     DataLoopNode::NodeFluidType::Air,
     323              :                                                                     DataLoopNode::ConnectionType::Inlet,
     324              :                                                                     NodeInputManager::CompFluidStream::Primary,
     325              :                                                                     DataLoopNode::ObjectIsParent); // air input node
     326              : 
     327           22 :             fanCoil.AirOutNode = NodeInputManager::GetOnlySingleNode(state,
     328           22 :                                                                      Alphas(6),
     329              :                                                                      ErrorsFound,
     330              :                                                                      DataLoopNode::ConnectionObjectType::ZoneHVACFourPipeFanCoil,
     331           22 :                                                                      Alphas(1),
     332              :                                                                      DataLoopNode::NodeFluidType::Air,
     333              :                                                                      DataLoopNode::ConnectionType::Outlet,
     334              :                                                                      NodeInputManager::CompFluidStream::Primary,
     335              :                                                                      DataLoopNode::ObjectIsParent); // air outlet node
     336              : 
     337           22 :             fanCoil.OAMixType = Alphas(7);
     338           22 :             fanCoil.OAMixName = Alphas(8);
     339              :             // check to see if local OA mixer specified
     340           22 :             if (!lAlphaBlanks(8)) {
     341           20 :                 errFlag = false;
     342           20 :                 ValidateComponent(state, fanCoil.OAMixType, fanCoil.OAMixName, errFlag, CurrentModuleObject);
     343           20 :                 if (errFlag) {
     344            0 :                     ShowContinueError(state, format("specified in {} = \"{}\".", CurrentModuleObject, fanCoil.Name));
     345            0 :                     ErrorsFound = true;
     346              :                 } else {
     347              :                     // Get outdoor air mixer node numbers
     348           20 :                     OANodeNums = MixedAir::GetOAMixerNodeNumbers(state, fanCoil.OAMixName, errFlag);
     349           20 :                     if (errFlag) {
     350            0 :                         ShowContinueError(state, format("that was specified in {} = {}", CurrentModuleObject, fanCoil.Name));
     351            0 :                         ShowContinueError(state, "..OutdoorAir:Mixer is required. Enter an OutdoorAir:Mixer object with this name.");
     352            0 :                         ErrorsFound = true;
     353              :                     } else {
     354           20 :                         fanCoil.OutsideAirNode = OANodeNums(1);
     355           20 :                         fanCoil.AirReliefNode = OANodeNums(2);
     356           20 :                         fanCoil.MixedAirNode = OANodeNums(4);
     357              :                     }
     358              :                 }
     359              :             }
     360              : 
     361           22 :             fanCoil.CCoilName = Alphas(12);
     362           22 :             fanCoil.MaxColdWaterVolFlow = Numbers(5);
     363           22 :             fanCoil.MinColdWaterVolFlow = Numbers(6);
     364           22 :             fanCoil.ColdControlOffset = Numbers(7);
     365           22 :             fanCoil.HCoilName = Alphas(14);
     366           22 :             fanCoil.HCoilType = Alphas(13);
     367           22 :             fanCoil.MaxHotWaterVolFlow = Numbers(8);
     368           22 :             fanCoil.MinHotWaterVolFlow = Numbers(9);
     369           22 :             fanCoil.HotControlOffset = Numbers(10);
     370              : 
     371           22 :             if (Util::SameString(Alphas(11), "Coil:Cooling:Water") || Util::SameString(Alphas(11), "Coil:Cooling:Water:DetailedGeometry") ||
     372           22 :                 Util::SameString(Alphas(11), "CoilSystem:Cooling:Water:HeatExchangerAssisted")) {
     373           22 :                 fanCoil.CCoilType = Alphas(11);
     374           22 :                 if (Util::SameString(Alphas(11), "Coil:Cooling:Water")) {
     375           22 :                     fanCoil.CCoilType_Num = CCoil::Water;
     376           22 :                     fanCoil.CCoilPlantName = fanCoil.CCoilName;
     377           22 :                     fanCoil.CCoilPlantType = DataPlant::PlantEquipmentType::CoilWaterCooling;
     378              :                 }
     379           22 :                 if (Util::SameString(Alphas(11), "Coil:Cooling:Water:DetailedGeometry")) {
     380            0 :                     fanCoil.CCoilType_Num = CCoil::Detailed;
     381            0 :                     fanCoil.CCoilPlantName = fanCoil.CCoilName;
     382            0 :                     fanCoil.CCoilPlantType = DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling;
     383              :                 }
     384           22 :                 std::string CCoilType;
     385           22 :                 if (Util::SameString(Alphas(11), "CoilSystem:Cooling:Water:HeatExchangerAssisted")) {
     386            0 :                     fanCoil.CCoilType_Num = CCoil::HXAssist;
     387            0 :                     HVACHXAssistedCoolingCoil::GetHXCoilTypeAndName(
     388            0 :                         state, fanCoil.CCoilType, fanCoil.CCoilName, ErrorsFound, CCoilType, fanCoil.CCoilPlantName);
     389            0 :                     if (Util::SameString(CCoilType, "Coil:Cooling:Water")) {
     390            0 :                         fanCoil.CCoilPlantType = DataPlant::PlantEquipmentType::CoilWaterCooling;
     391            0 :                     } else if (Util::SameString(CCoilType, "Coil:Cooling:Water:DetailedGeometry")) {
     392            0 :                         fanCoil.CCoilPlantType = DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling;
     393              :                     } else {
     394            0 :                         ShowSevereError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, fanCoil.Name));
     395            0 :                         ShowContinueError(state, format("For: {}=\"{}\".", cAlphaFields(11), Alphas(11)));
     396            0 :                         ShowContinueError(state, format("Invalid Coil Type={}, Name={}", CCoilType, fanCoil.CCoilPlantName));
     397            0 :                         ShowContinueError(state, "must be \"Coil:Cooling:Water\" or \"Coil:Cooling:Water:DetailedGeometry\"");
     398            0 :                         ErrorsFound = true;
     399              :                     }
     400              :                 }
     401           22 :                 IsNotOK = false;
     402           22 :                 ValidateComponent(state, fanCoil.CCoilType, fanCoil.CCoilName, IsNotOK, fanCoil.UnitType);
     403           22 :                 if (IsNotOK) {
     404            0 :                     ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, fanCoil.Name));
     405            0 :                     ErrorsFound = true;
     406              :                 } else {
     407           22 :                     if (fanCoil.CCoilType_Num != CCoil::HXAssist) {
     408              :                         // mine the cold water node from the coil object
     409           22 :                         int coilIndex = WaterCoils::GetWaterCoilIndex(state, fanCoil.CCoilType, fanCoil.CCoilName, IsNotOK);
     410              :                         // Other error checks should trap before it gets to this point in the code, but including just in case.
     411           22 :                         if (IsNotOK) {
     412            0 :                             ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, fanCoil.Name));
     413            0 :                             ErrorsFound = true;
     414              :                         } else {
     415           22 :                             fanCoil.CoolCoilFluidInletNode = state.dataWaterCoils->WaterCoil(coilIndex).WaterInletNodeNum;
     416           22 :                             fanCoil.CoolCoilInletNodeNum = state.dataWaterCoils->WaterCoil(coilIndex).AirInletNodeNum;
     417           22 :                             fanCoil.CoolCoilOutletNodeNum = state.dataWaterCoils->WaterCoil(coilIndex).AirOutletNodeNum;
     418              :                         }
     419              :                     } else {
     420              :                         // mine the cold water node from the coil object
     421            0 :                         int coilIndex = WaterCoils::GetWaterCoilIndex(state, CCoilType, fanCoil.CCoilPlantName, IsNotOK);
     422              :                         // Other error checks should trap before it gets to this point in the code, but including just in case.
     423            0 :                         if (IsNotOK) {
     424            0 :                             ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, fanCoil.Name));
     425            0 :                             ErrorsFound = true;
     426              :                         } else {
     427            0 :                             fanCoil.CoolCoilFluidInletNode = state.dataWaterCoils->WaterCoil(coilIndex).WaterInletNodeNum;
     428            0 :                             fanCoil.CoolCoilInletNodeNum = state.dataWaterCoils->WaterCoil(coilIndex).AirInletNodeNum;
     429            0 :                             fanCoil.CoolCoilOutletNodeNum = state.dataWaterCoils->WaterCoil(coilIndex).AirOutletNodeNum;
     430              :                         }
     431              :                     }
     432              :                 }
     433           22 :             } else {
     434            0 :                 ShowSevereError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, fanCoil.Name));
     435            0 :                 ShowContinueError(state, format("illegal value: {}=\"{}\".", cAlphaFields(11), Alphas(11)));
     436            0 :                 ErrorsFound = true;
     437              :             }
     438              : 
     439           22 :             if (Util::SameString(Alphas(13), "Coil:Heating:Water")) {
     440           16 :                 fanCoil.HCoilType_Num = HCoil::Water;
     441           16 :                 fanCoil.HCoilPlantTypeOf = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
     442           16 :                 IsNotOK = false;
     443           16 :                 ValidateComponent(state, fanCoil.HCoilType, fanCoil.HCoilName, IsNotOK, CurrentModuleObject);
     444           16 :                 if (IsNotOK) {
     445            0 :                     ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, fanCoil.Name));
     446            0 :                     ErrorsFound = true;
     447              :                 } else {
     448              :                     // mine the hot water node from the coil object
     449           16 :                     int coilIndex = WaterCoils::GetWaterCoilIndex(state, fanCoil.HCoilType, fanCoil.HCoilName, IsNotOK);
     450           16 :                     if (IsNotOK) {
     451            0 :                         ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, fanCoil.Name));
     452            0 :                         ErrorsFound = true;
     453              :                     } else {
     454           16 :                         fanCoil.HeatCoilFluidInletNode = state.dataWaterCoils->WaterCoil(coilIndex).WaterInletNodeNum;
     455           16 :                         fanCoil.HeatCoilInletNodeNum = state.dataWaterCoils->WaterCoil(coilIndex).AirInletNodeNum;
     456           16 :                         fanCoil.HeatCoilOutletNodeNum = state.dataWaterCoils->WaterCoil(coilIndex).AirOutletNodeNum;
     457              :                     }
     458              :                 }
     459            6 :             } else if (Util::SameString(Alphas(13), "Coil:Heating:Electric")) {
     460            6 :                 fanCoil.HCoilType_Num = HCoil::Electric;
     461            6 :                 IsNotOK = false;
     462            6 :                 ValidateComponent(state, fanCoil.HCoilType, fanCoil.HCoilName, IsNotOK, CurrentModuleObject);
     463            6 :                 if (IsNotOK) {
     464            0 :                     ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, fanCoil.Name));
     465            0 :                     ErrorsFound = true;
     466              :                 } else {
     467              :                     int coilIndex;
     468            6 :                     HeatingCoils::GetCoilIndex(state, fanCoil.HCoilName, coilIndex, IsNotOK);
     469            6 :                     if (IsNotOK) {
     470            0 :                         ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, fanCoil.Name));
     471            0 :                         ErrorsFound = true;
     472              :                     } else {
     473            6 :                         fanCoil.DesignHeatingCapacity = state.dataHeatingCoils->HeatingCoil(coilIndex).NominalCapacity;
     474            6 :                         fanCoil.HeatCoilInletNodeNum = state.dataHeatingCoils->HeatingCoil(coilIndex).AirInletNodeNum;
     475            6 :                         fanCoil.HeatCoilOutletNodeNum = state.dataHeatingCoils->HeatingCoil(coilIndex).AirOutletNodeNum;
     476              :                     }
     477              :                 }
     478              :             } else {
     479            0 :                 ShowSevereError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, fanCoil.Name));
     480            0 :                 ShowContinueError(state, format("illegal value: {}=\"{}\".", cAlphaFields(13), Alphas(13)));
     481            0 :                 ErrorsFound = true;
     482              :             }
     483              : 
     484           22 :             fanCoil.FanName = Alphas(10);
     485              : 
     486           22 :             if (!lAlphaBlanks(15)) {
     487            0 :                 fanCoil.AvailManagerListName = Alphas(15);
     488              :             }
     489              : 
     490           22 :             fanCoil.HVACSizingIndex = 0;
     491           22 :             if (!lAlphaBlanks(16)) {
     492            0 :                 fanCoil.HVACSizingIndex = Util::FindItemInList(Alphas(16), state.dataSize->ZoneHVACSizing);
     493            0 :                 if (fanCoil.HVACSizingIndex == 0) {
     494            0 :                     ShowSevereError(state, format("{} = {} not found.", cAlphaFields(16), Alphas(16)));
     495            0 :                     ShowContinueError(state, format("Occurs in {} = {}", state.dataFanCoilUnits->cMO_FanCoil, fanCoil.Name));
     496            0 :                     ErrorsFound = true;
     497              :                 }
     498              :             }
     499              : 
     500           22 :             fanCoil.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(9)));
     501           22 :             if (fanCoil.fanType != HVAC::FanType::Constant && fanCoil.fanType != HVAC::FanType::VAV && fanCoil.fanType != HVAC::FanType::OnOff &&
     502            4 :                 fanCoil.fanType != HVAC::FanType::SystemModel) {
     503            0 :                 ShowSevereInvalidKey(state,
     504              :                                      eoh,
     505            0 :                                      cAlphaFields(9),
     506            0 :                                      Alphas(9),
     507              :                                      "Fan Type must be Fan:OnOff, Fan:ConstantVolume, Fan:VariableVolume, or Fan:SystemModel.");
     508            0 :                 ErrorsFound = true;
     509           22 :             } else if ((fanCoil.FanIndex = Fans::GetFanIndex(state, fanCoil.FanName)) == 0) {
     510            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(10), Alphas(10));
     511            0 :                 ErrorsFound = true;
     512              :             } else {
     513           22 :                 auto *fan = state.dataFans->fans(fanCoil.FanIndex);
     514              : 
     515           22 :                 if (fanCoil.fanType != fan->type) {
     516            0 :                     ShowSevereCustom(state,
     517              :                                      eoh,
     518            0 :                                      format("{} was specified as having type {}, but has type {}",
     519            0 :                                             fanCoil.FanName,
     520            0 :                                             HVAC::fanTypeNamesUC[(int)fanCoil.fanType],
     521            0 :                                             HVAC::fanTypeNamesUC[(int)fan->type]));
     522            0 :                     ErrorsFound = true;
     523              :                 }
     524              : 
     525           22 :                 fanCoil.fanAvailSched = fan->availSched;
     526           22 :                 fanCoil.FanAirVolFlow = fan->maxAirFlowRate;
     527              : 
     528           22 :                 if (fanCoil.MaxAirVolFlow > fanCoil.FanAirVolFlow && fanCoil.FanAirVolFlow != DataSizing::AutoSize) {
     529            0 :                     ShowWarningError(state, format("{}{}: {}", RoutineName, fanCoil.UnitType, fanCoil.Name));
     530            0 :                     ShowContinueError(state, format("... {} is greater than the maximum fan flow rate.", cNumericFields(1)));
     531            0 :                     ShowContinueError(state, format("... Fan Coil Unit flow = {:.5T} m3/s.", fanCoil.MaxAirVolFlow));
     532            0 :                     ShowContinueError(state, format("... Fan = {}: {}", HVAC::fanTypeNames[(int)fanCoil.fanType], fanCoil.FanName));
     533            0 :                     ShowContinueError(state, format("... Fan flow = {:.5T} m3/s.", fanCoil.FanAirVolFlow));
     534            0 :                     ShowContinueError(state, "... Fan Coil Unit flow rate reduced to match the fan flow rate and the simulation continues.");
     535            0 :                     fanCoil.MaxAirVolFlow = fanCoil.FanAirVolFlow;
     536              :                 }
     537              : 
     538           22 :                 if (fanCoil.fanType == HVAC::FanType::Constant || fanCoil.fanType == HVAC::FanType::VAV || fanCoil.fanType == HVAC::FanType::OnOff) {
     539              :                     // Get fan air volume flow rate
     540              :                     // Check that the fan volumetric flow rate is greater than or equal to the FCU volumetric flow rate
     541              : 
     542              :                     // Check that the fan type match with the capacity control method selected
     543           18 :                     if ((fanCoil.CapCtrlMeth_Num == CCM::ConsFanVarFlow && (fanCoil.fanType == HVAC::FanType::VAV)) ||
     544           18 :                         (fanCoil.CapCtrlMeth_Num == CCM::CycFan && fanCoil.fanType != HVAC::FanType::OnOff) ||
     545           18 :                         (fanCoil.CapCtrlMeth_Num == CCM::VarFanVarFlow && fanCoil.fanType != HVAC::FanType::VAV) ||
     546           18 :                         (fanCoil.CapCtrlMeth_Num == CCM::VarFanConsFlow && fanCoil.fanType != HVAC::FanType::VAV)) {
     547            0 :                         ShowSevereError(state, format("{}{}: {}", RoutineName, fanCoil.UnitType, fanCoil.Name));
     548            0 :                         ShowContinueError(state,
     549            0 :                                           format("...the fan type of the object : {} does not match with the capacity control method selected : "
     550              :                                                  "{} please see I/O reference",
     551            0 :                                                  fanCoil.FanName,
     552              :                                                  capCtrlMeth));
     553            0 :                         ShowContinueError(state, "...for ConstantFanVariableFlow a Fan:OnOff or Fan:ConstantVolume is valid.");
     554            0 :                         ShowContinueError(state, "...for CyclingFan a Fan:OnOff is valid.");
     555            0 :                         ShowContinueError(state, "...for VariableFanVariableFlow or VariableFanConstantFlow a Fan:VariableVolume is valid.");
     556            0 :                         ErrorsFound = true;
     557              :                     }
     558              :                 } else {
     559              :                     // check that for VariableFanVariableFlow or VariableFanConstantFlow that the fan speed control is continuous
     560            4 :                     if (fanCoil.CapCtrlMeth_Num == CCM::VarFanVarFlow || fanCoil.CapCtrlMeth_Num == CCM::VarFanConsFlow ||
     561            4 :                         fanCoil.CapCtrlMeth_Num == CCM::ASHRAE) { // then expect continuous speed control fan
     562            0 :                         if (dynamic_cast<Fans::FanSystem *>(state.dataFans->fans(fanCoil.FanIndex))->speedControl != Fans::SpeedControl::Continuous) {
     563            0 :                             ShowSevereError(state, format("{}{}: {}", RoutineName, fanCoil.UnitType, fanCoil.Name));
     564            0 :                             ShowContinueError(state,
     565            0 :                                               format("...the fan type of the object : {} does not match with the capacity control method selected : "
     566              :                                                      "{} please see I/O reference",
     567            0 :                                                      fanCoil.FanName,
     568              :                                                      capCtrlMeth));
     569            0 :                             ShowContinueError(
     570              :                                 state,
     571              :                                 "...for VariableFanVariableFlow or VariableFanConstantFlow a Fan:SystemModel should have Continuous speed control.");
     572            0 :                             ErrorsFound = true;
     573              :                         }
     574              :                     }
     575              :                 }
     576              :             }
     577              : 
     578              :             // check low speed fan ratio when using ASHRAE90.1 capacity control method
     579           22 :             if (fanCoil.CapCtrlMeth_Num == CCM::ASHRAE) {
     580            3 :                 if (fanCoil.LowSpeedRatio > 0.5) {
     581            0 :                     ShowWarningError(state, format("{}{}=\"{}\",", RoutineName, CurrentModuleObject, fanCoil.Name));
     582            0 :                     ShowContinueError(state, format("... {} is greater than the 50% of the supply air flow ratio.", cNumericFields(2)));
     583            0 :                     ShowContinueError(state, format("... Fan Coil Unit low speed supply air flow ratio = {:.5T} ", fanCoil.LowSpeedRatio));
     584            3 :                 } else if (fanCoil.LowSpeedRatio == 0.0) {
     585            0 :                     ShowWarningError(state, format("{}{}=\"{}\",", RoutineName, CurrentModuleObject, fanCoil.Name));
     586            0 :                     ShowContinueError(state, format("... {} is equal to 0.", cNumericFields(2)));
     587            0 :                     ShowContinueError(state, "... Fan Coil Unit low speed supply air flow ratio should be greater than 0 to comply with ASHRAE90.1.");
     588            0 :                     ShowContinueError(state, "... Fan Coil Unit low speed supply air flow ratio set to 0.5");
     589            0 :                     fanCoil.LowSpeedRatio = 0.5;
     590              :                 }
     591              :             }
     592              : 
     593              :             // Set defaults for convergence tolerance
     594           22 :             if (fanCoil.ColdControlOffset <= 0.0) {
     595            0 :                 fanCoil.ColdControlOffset = 0.001;
     596              :             }
     597           22 :             if (fanCoil.HotControlOffset <= 0.0) {
     598            0 :                 fanCoil.HotControlOffset = 0.001;
     599              :             }
     600              : 
     601              :             // check for inlet side air mixer
     602           44 :             SingleDuct::GetATMixer(state,
     603           22 :                                    fanCoil.Name,
     604              :                                    ATMixerName,
     605           22 :                                    state.dataFanCoilUnits->ATMixerNum,
     606           22 :                                    state.dataFanCoilUnits->ATMixerType,
     607           22 :                                    state.dataFanCoilUnits->ATMixerPriNode,
     608           22 :                                    state.dataFanCoilUnits->ATMixerSecNode,
     609           22 :                                    state.dataFanCoilUnits->ATMixerOutNode,
     610              :                                    fanCoil.AirOutNode);
     611           22 :             fanCoil.ControlZoneNum =
     612           22 :                 DataZoneEquipment::GetZoneEquipControlledZoneNum(state, DataZoneEquipment::ZoneEquipType::FourPipeFanCoil, fanCoil.Name);
     613           22 :             if (fanCoil.ControlZoneNum == 0) {
     614            0 :                 ErrorsFound = true;
     615              :             }
     616           22 :             if (state.dataFanCoilUnits->ATMixerType == HVAC::MixerType::InletSide) {
     617              :                 // save the air terminal mixer data in the fan coil data array
     618            2 :                 fanCoil.ATMixerExists = true;
     619            2 :                 fanCoil.ATMixerIndex = state.dataFanCoilUnits->ATMixerNum;
     620            2 :                 fanCoil.ATMixerName = ATMixerName;
     621            2 :                 fanCoil.ATMixerType = HVAC::MixerType::InletSide;
     622            2 :                 fanCoil.ATMixerPriNode = state.dataFanCoilUnits->ATMixerPriNode;
     623            2 :                 fanCoil.ATMixerSecNode = state.dataFanCoilUnits->ATMixerSecNode;
     624            2 :                 fanCoil.ATMixerOutNode = state.dataFanCoilUnits->ATMixerOutNode;
     625              :                 // check that fan coil doesn' have local outside air
     626            2 :                 if (!lAlphaBlanks(8)) {
     627            0 :                     ShowSevereError(
     628              :                         state,
     629            0 :                         format("{} = \"{}\". Fan coil unit has local as well as central outdoor air specified", CurrentModuleObject, fanCoil.Name));
     630              :                 }
     631              :                 // check that the air teminal mixer out node is the fan coil inlet node
     632            2 :                 if (fanCoil.AirInNode != state.dataFanCoilUnits->ATMixerOutNode) {
     633            0 :                     ShowSevereError(
     634              :                         state,
     635            0 :                         format("{} = \"{}\". Fan coil unit air inlet node name must be the same as an air terminal mixer outlet node name.",
     636              :                                CurrentModuleObject,
     637            0 :                                fanCoil.Name));
     638            0 :                     ShowContinueError(state, "..Air terminal mixer outlet node name is specified in AirTerminal:SingleDuct:InletSideMixer object.");
     639            0 :                     ShowContinueError(state, format("..Fan coil unit air inlet node name = {}", state.dataLoopNodes->NodeID(fanCoil.AirInNode)));
     640            0 :                     ErrorsFound = true;
     641              :                 }
     642              :                 // check for supply side air terminal mixer
     643           20 :             } else if (state.dataFanCoilUnits->ATMixerType == HVAC::MixerType::SupplySide) {
     644              :                 // save the air terminal mixer data in the fan coil data array
     645            0 :                 fanCoil.ATMixerExists = true;
     646            0 :                 fanCoil.ATMixerIndex = state.dataFanCoilUnits->ATMixerNum;
     647            0 :                 fanCoil.ATMixerName = ATMixerName;
     648            0 :                 fanCoil.ATMixerType = HVAC::MixerType::SupplySide;
     649            0 :                 fanCoil.ATMixerPriNode = state.dataFanCoilUnits->ATMixerPriNode;
     650            0 :                 fanCoil.ATMixerSecNode = state.dataFanCoilUnits->ATMixerSecNode;
     651            0 :                 fanCoil.ATMixerOutNode = state.dataFanCoilUnits->ATMixerOutNode;
     652              :                 // check that fan coil doesn' have local outside air
     653            0 :                 if (!lAlphaBlanks(8)) {
     654            0 :                     ShowSevereError(
     655              :                         state,
     656            0 :                         format("{} = \"{}\". Fan coil unit has local as well as central outdoor air specified", CurrentModuleObject, fanCoil.Name));
     657              :                 }
     658              :                 // check that the air teminal mixer secondary air inlet node is the fan coil outlet node
     659            0 :                 if (fanCoil.AirOutNode != state.dataFanCoilUnits->ATMixerSecNode) {
     660            0 :                     ShowSevereError(state,
     661            0 :                                     format("{} = \"{}\". Fan coil unit air outlet node name must be the same as the air terminal mixer secondary air "
     662              :                                            "inlet node name.",
     663              :                                            CurrentModuleObject,
     664            0 :                                            fanCoil.Name));
     665            0 :                     ShowContinueError(
     666              :                         state, "..Air terminal mixer secondary inlet node name is specified in AirTerminal:SingleDuct:SupplySideMixer object.");
     667            0 :                     ShowContinueError(state, format("..Fan coil unit air outlet node name = {}", state.dataLoopNodes->NodeID(fanCoil.AirOutNode)));
     668            0 :                     ErrorsFound = true;
     669              :                 }
     670            0 :                 bool ZoneNodeNotFound = true;
     671            0 :                 for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).NumExhaustNodes; ++NodeNum) {
     672            0 :                     if (fanCoil.AirInNode == state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).ExhaustNode(NodeNum)) {
     673            0 :                         ZoneNodeNotFound = false;
     674            0 :                         break;
     675              :                     }
     676              :                 }
     677            0 :                 if (ZoneNodeNotFound) {
     678            0 :                     bool InletNodeFound = false;
     679            0 :                     if (fanCoil.ControlZoneNum > 0) {
     680            0 :                         InletNodeFound = ZonePlenum::ValidateInducedNode(state,
     681              :                                                                          fanCoil.AirInNode,
     682            0 :                                                                          state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).NumReturnNodes,
     683            0 :                                                                          state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).ReturnNode);
     684              :                     }
     685            0 :                     if (!InletNodeFound) {
     686            0 :                         ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, CurrentModuleObject, fanCoil.Name));
     687            0 :                         ShowContinueError(state,
     688              :                                           "..FanCoil inlet node name must be the same as either a zone exhaust node name or an induced "
     689              :                                           "air node in ZonePlenum.");
     690            0 :                         ShowContinueError(state, "..Zone exhaust node name is specified in ZoneHVAC:EquipmentConnections object.");
     691            0 :                         ShowContinueError(state, "..Induced Air Outlet Node name is specified in AirLoopHVAC:ReturnPlenum object.");
     692            0 :                         ShowContinueError(state, format("..FanCoil inlet node name = {}", state.dataLoopNodes->NodeID(fanCoil.AirInNode)));
     693            0 :                         ErrorsFound = true;
     694              :                     }
     695              :                 }
     696              :                 // no air terminal mixer; do the normal connectivity checks
     697              :             } else {
     698              :                 // check that the fan coil inlet node is the same as one of the zone exhaust nodes
     699           20 :                 state.dataFanCoilUnits->ZoneExNodeNotFound = true;
     700           20 :                 for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).NumExhaustNodes; ++NodeNum) {
     701           20 :                     if (fanCoil.AirInNode == state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).ExhaustNode(NodeNum)) {
     702           20 :                         state.dataFanCoilUnits->ZoneExNodeNotFound = false;
     703           20 :                         break;
     704              :                     }
     705              :                 }
     706           20 :                 if (state.dataFanCoilUnits->ZoneExNodeNotFound) {
     707            0 :                     bool InletNodeFound = false;
     708            0 :                     InletNodeFound = ZonePlenum::ValidateInducedNode(state,
     709              :                                                                      fanCoil.AirInNode,
     710            0 :                                                                      state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).NumReturnNodes,
     711            0 :                                                                      state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).ReturnNode);
     712              : 
     713            0 :                     if (!InletNodeFound) {
     714            0 :                         ShowSevereError(state,
     715            0 :                                         format("{} = \"{}\". Fan coil unit air inlet node name must be the same either as a zone exhaust node name "
     716              :                                                "or an induce air node in ZoePlenum.",
     717              :                                                CurrentModuleObject,
     718            0 :                                                fanCoil.Name));
     719            0 :                         ShowContinueError(state, "..Zone exhaust node name is specified in ZoneHVAC:EquipmentConnections object.");
     720            0 :                         ShowContinueError(state, "..Induced Air Outlet Node name is specified in AirLoopHVAC:ReturnPlenum object.");
     721            0 :                         ShowContinueError(state, format("..Fan coil unit air inlet node name = {}", state.dataLoopNodes->NodeID(fanCoil.AirInNode)));
     722            0 :                         ErrorsFound = true;
     723              :                     }
     724              :                 }
     725              :                 // check that the fan coil outlet node is the same as one of the zone inlet nodes
     726           20 :                 state.dataFanCoilUnits->ZoneInNodeNotFound = true;
     727           20 :                 if (fanCoil.ControlZoneNum > 0) {
     728           20 :                     fanCoil.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(fanCoil.ControlZoneNum).ZoneNode;
     729           20 :                     state.dataFanCoilUnits->ZoneInNodeNotFound = false;
     730              :                 }
     731              : 
     732           20 :                 if (state.dataFanCoilUnits->ZoneInNodeNotFound) {
     733            0 :                     ShowSevereError(state,
     734            0 :                                     format("{} = \"{}\". Fan coil unit air outlet node name must be the same as a zone inlet node name.",
     735              :                                            CurrentModuleObject,
     736            0 :                                            fanCoil.Name));
     737            0 :                     ShowContinueError(state, "..Zone inlet node name is specified in ZoneHVAC:EquipmentConnections object.");
     738            0 :                     ShowContinueError(state, format("..Fan coil unit air outlet node name = {}", state.dataLoopNodes->NodeID(fanCoil.AirOutNode)));
     739              : 
     740            0 :                     ErrorsFound = true;
     741              :                 }
     742              :             }
     743           22 :             if (fanCoil.CapCtrlMeth_Num == CCM::MultiSpeedFan) {
     744            6 :                 if (!lAlphaBlanks(17)) {
     745            3 :                     fanCoil.fanOpModeSched = Sched::GetSchedule(state, Alphas(17));
     746            3 :                     if (fanCoil.fanType != HVAC::FanType::OnOff && fanCoil.fanType != HVAC::FanType::SystemModel) {
     747            0 :                         ShowSevereError(state, format("{} = {}", CurrentModuleObject, fanCoil.Name));
     748            0 :                         ShowContinueError(state, format("For {} = {}", cAlphaFields(17), Alphas(17)));
     749            0 :                         ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(9), Alphas(9)));
     750            0 :                         ShowContinueError(state, "...fan operating schedule is allowed for on off or system model fan type only )");
     751            0 :                         ErrorsFound = true;
     752            3 :                     } else if (fanCoil.fanOpModeSched == nullptr) {
     753            0 :                         ShowSevereItemNotFound(state, eoh, cAlphaFields(17), Alphas(17));
     754            0 :                         ErrorsFound = true;
     755              :                     }
     756            3 :                 } else if (fanCoil.fanType == HVAC::FanType::OnOff || fanCoil.fanType == HVAC::FanType::SystemModel) {
     757            2 :                     fanCoil.fanOp = HVAC::FanOp::Cycling;
     758              :                 }
     759              :             }
     760              : 
     761           22 :             if (!lNumericBlanks(11)) {
     762            3 :                 fanCoil.DesignMinOutletTemp = Numbers(11);
     763            3 :                 if (lNumericBlanks(12)) {
     764            0 :                     ShowWarningError(state, format("{}{}=\"{}\",", RoutineName, CurrentModuleObject, fanCoil.Name));
     765            0 :                     ShowContinueError(state, format("... {} and {} must be used in unison.", cNumericFields(11), cNumericFields(12)));
     766            0 :                     ErrorsFound = true;
     767              :                 }
     768              :             }
     769              : 
     770           22 :             if (!lNumericBlanks(12)) {
     771            3 :                 fanCoil.DesignMaxOutletTemp = Numbers(12);
     772            3 :                 if (fanCoil.DesignMinOutletTemp != DataSizing::AutoSize && fanCoil.DesignMaxOutletTemp != DataSizing::AutoSize) {
     773            1 :                     if (fanCoil.DesignMaxOutletTemp < fanCoil.DesignMinOutletTemp) {
     774            0 :                         ShowWarningError(state, format("{}{}=\"{}\",", RoutineName, CurrentModuleObject, fanCoil.Name));
     775            0 :                         ShowContinueError(state, format("... {} is greater than {}.", cNumericFields(11), cNumericFields(12)));
     776            0 :                         ShowContinueError(state, format("... {} = {:.2T} [C].", cNumericFields(11), fanCoil.DesignMinOutletTemp));
     777            0 :                         ShowContinueError(state, format("... {} = {:.2T} [C].", cNumericFields(12), fanCoil.DesignMaxOutletTemp));
     778            0 :                         ErrorsFound = true;
     779              :                     }
     780              :                 }
     781            3 :                 if (lNumericBlanks(11)) {
     782            0 :                     ShowWarningError(state, format("{}{}=\"{}\",", RoutineName, CurrentModuleObject, fanCoil.Name));
     783            0 :                     ShowContinueError(state, format("... {} and {} must be used in unison.", cNumericFields(11), cNumericFields(12)));
     784            0 :                     ErrorsFound = true;
     785              :                 }
     786              :             }
     787              : 
     788           22 :             if (fanCoil.DesignMinOutletTemp > 0.0 && fanCoil.DesignMaxOutletTemp > 0.0) {
     789            1 :                 fanCoil.ASHRAETempControl = true;
     790           21 :             } else if (fanCoil.DesignMinOutletTemp == DataSizing::AutoSize || fanCoil.DesignMaxOutletTemp == DataSizing::AutoSize) {
     791            2 :                 fanCoil.ASHRAETempControl = true;
     792              :             }
     793              : 
     794              :             // Set up component set for supply fan
     795           22 :             if (fanCoil.OutsideAirNode > 0) {
     796           60 :                 BranchNodeConnections::SetUpCompSets(state,
     797              :                                                      fanCoil.UnitType,
     798              :                                                      fanCoil.Name,
     799           20 :                                                      HVAC::fanTypeNames[(int)fanCoil.fanType],
     800              :                                                      fanCoil.FanName,
     801           20 :                                                      state.dataLoopNodes->NodeID(fanCoil.MixedAirNode),
     802              :                                                      "UNDEFINED");
     803              :             } else {
     804            6 :                 BranchNodeConnections::SetUpCompSets(state,
     805              :                                                      fanCoil.UnitType,
     806              :                                                      fanCoil.Name,
     807            2 :                                                      HVAC::fanTypeNames[(int)fanCoil.fanType],
     808              :                                                      fanCoil.FanName,
     809            2 :                                                      state.dataLoopNodes->NodeID(fanCoil.AirInNode),
     810              :                                                      "UNDEFINED");
     811              :             }
     812              :             // Set up component set for cooling coil
     813           22 :             BranchNodeConnections::SetUpCompSets(
     814              :                 state, fanCoil.UnitType, fanCoil.Name, fanCoil.CCoilType, fanCoil.CCoilName, "UNDEFINED", "UNDEFINED");
     815              : 
     816              :             // Set up component set for heating coil
     817           44 :             BranchNodeConnections::SetUpCompSets(state,
     818              :                                                  fanCoil.UnitType,
     819              :                                                  fanCoil.Name,
     820              :                                                  fanCoil.HCoilType,
     821              :                                                  fanCoil.HCoilName,
     822              :                                                  "UNDEFINED",
     823           22 :                                                  state.dataLoopNodes->NodeID(fanCoil.AirOutNode));
     824              : 
     825              :             // Set up component set for OA mixer - use OA node and Mixed air node
     826           22 :             if (fanCoil.OutsideAirNode > 0) {
     827           40 :                 BranchNodeConnections::SetUpCompSets(state,
     828              :                                                      fanCoil.UnitType,
     829              :                                                      fanCoil.Name,
     830              :                                                      fanCoil.OAMixType,
     831              :                                                      fanCoil.OAMixName,
     832           20 :                                                      state.dataLoopNodes->NodeID(fanCoil.OutsideAirNode),
     833           20 :                                                      state.dataLoopNodes->NodeID(fanCoil.MixedAirNode));
     834              :             }
     835           22 :         }
     836              : 
     837           18 :         Alphas.deallocate();
     838           18 :         cAlphaFields.deallocate();
     839           18 :         cNumericFields.deallocate();
     840           18 :         Numbers.deallocate();
     841           18 :         lAlphaBlanks.deallocate();
     842           18 :         lNumericBlanks.deallocate();
     843              : 
     844           18 :         if (ErrorsFound) {
     845            0 :             ShowFatalError(state, format("{}Errors found in input. Preceding condition(s) cause termination.", RoutineName));
     846              :         }
     847              : 
     848           40 :         for (auto &fanCoil : state.dataFanCoilUnits->FanCoil) {
     849              :             // Setup Report variables for the Fan Coils
     850              :             // CurrentModuleObject='ZoneHVAC:FourPipeFanCoil'
     851           44 :             SetupOutputVariable(state,
     852              :                                 "Fan Coil Heating Rate",
     853              :                                 Constant::Units::W,
     854           22 :                                 fanCoil.HeatPower,
     855              :                                 OutputProcessor::TimeStepType::System,
     856              :                                 OutputProcessor::StoreType::Average,
     857           22 :                                 fanCoil.Name);
     858           44 :             SetupOutputVariable(state,
     859              :                                 "Fan Coil Heating Energy",
     860              :                                 Constant::Units::J,
     861           22 :                                 fanCoil.HeatEnergy,
     862              :                                 OutputProcessor::TimeStepType::System,
     863              :                                 OutputProcessor::StoreType::Sum,
     864           22 :                                 fanCoil.Name);
     865           44 :             SetupOutputVariable(state,
     866              :                                 "Fan Coil Total Cooling Rate",
     867              :                                 Constant::Units::W,
     868           22 :                                 fanCoil.TotCoolPower,
     869              :                                 OutputProcessor::TimeStepType::System,
     870              :                                 OutputProcessor::StoreType::Average,
     871           22 :                                 fanCoil.Name);
     872           44 :             SetupOutputVariable(state,
     873              :                                 "Fan Coil Total Cooling Energy",
     874              :                                 Constant::Units::J,
     875           22 :                                 fanCoil.TotCoolEnergy,
     876              :                                 OutputProcessor::TimeStepType::System,
     877              :                                 OutputProcessor::StoreType::Sum,
     878           22 :                                 fanCoil.Name);
     879           44 :             SetupOutputVariable(state,
     880              :                                 "Fan Coil Sensible Cooling Rate",
     881              :                                 Constant::Units::W,
     882           22 :                                 fanCoil.SensCoolPower,
     883              :                                 OutputProcessor::TimeStepType::System,
     884              :                                 OutputProcessor::StoreType::Average,
     885           22 :                                 fanCoil.Name);
     886           44 :             SetupOutputVariable(state,
     887              :                                 "Fan Coil Sensible Cooling Energy",
     888              :                                 Constant::Units::J,
     889           22 :                                 fanCoil.SensCoolEnergy,
     890              :                                 OutputProcessor::TimeStepType::System,
     891              :                                 OutputProcessor::StoreType::Sum,
     892           22 :                                 fanCoil.Name);
     893           44 :             SetupOutputVariable(state,
     894              :                                 "Fan Coil Fan Electricity Rate",
     895              :                                 Constant::Units::W,
     896           22 :                                 fanCoil.ElecPower,
     897              :                                 OutputProcessor::TimeStepType::System,
     898              :                                 OutputProcessor::StoreType::Average,
     899           22 :                                 fanCoil.Name);
     900           44 :             SetupOutputVariable(state,
     901              :                                 "Fan Coil Fan Electricity Energy",
     902              :                                 Constant::Units::J,
     903           22 :                                 fanCoil.ElecEnergy,
     904              :                                 OutputProcessor::TimeStepType::System,
     905              :                                 OutputProcessor::StoreType::Sum,
     906           22 :                                 fanCoil.Name);
     907           22 :             if (fanCoil.CapCtrlMeth_Num == CCM::CycFan || fanCoil.CapCtrlMeth_Num == CCM::MultiSpeedFan) {
     908           26 :                 SetupOutputVariable(state,
     909              :                                     "Fan Coil Runtime Fraction",
     910              :                                     Constant::Units::None,
     911           13 :                                     fanCoil.PLR,
     912              :                                     OutputProcessor::TimeStepType::System,
     913              :                                     OutputProcessor::StoreType::Average,
     914           13 :                                     fanCoil.Name);
     915           13 :                 SetupOutputVariable(state,
     916              :                                     "Fan Coil Fan Speed Level",
     917              :                                     Constant::Units::None,
     918           13 :                                     fanCoil.SpeedFanSel,
     919              :                                     OutputProcessor::TimeStepType::System,
     920              :                                     OutputProcessor::StoreType::Average,
     921           13 :                                     fanCoil.Name);
     922           13 :                 if (fanCoil.CapCtrlMeth_Num == CCM::MultiSpeedFan) {
     923           12 :                     SetupOutputVariable(state,
     924              :                                         "Fan Coil Speed Ratio",
     925              :                                         Constant::Units::None,
     926            6 :                                         fanCoil.SpeedRatio,
     927              :                                         OutputProcessor::TimeStepType::System,
     928              :                                         OutputProcessor::StoreType::Average,
     929            6 :                                         fanCoil.Name);
     930           12 :                     SetupOutputVariable(state,
     931              :                                         "Fan Coil Part Load Ratio",
     932              :                                         Constant::Units::None,
     933            6 :                                         fanCoil.PLR,
     934              :                                         OutputProcessor::TimeStepType::System,
     935              :                                         OutputProcessor::StoreType::Average,
     936            6 :                                         fanCoil.Name);
     937              :                 }
     938              :             }
     939           22 :             if (fanCoil.CapCtrlMeth_Num == CCM::VarFanVarFlow || fanCoil.CapCtrlMeth_Num == CCM::VarFanConsFlow) {
     940            4 :                 SetupOutputVariable(state,
     941              :                                     "Fan Coil Part Load Ratio",
     942              :                                     Constant::Units::None,
     943            2 :                                     fanCoil.PLR,
     944              :                                     OutputProcessor::TimeStepType::System,
     945              :                                     OutputProcessor::StoreType::Average,
     946            2 :                                     fanCoil.Name);
     947              :             }
     948           22 :             SetupOutputVariable(state,
     949              :                                 "Fan Coil Availability Status",
     950              :                                 Constant::Units::None,
     951           22 :                                 (int &)fanCoil.availStatus,
     952              :                                 OutputProcessor::TimeStepType::System,
     953              :                                 OutputProcessor::StoreType::Average,
     954           22 :                                 fanCoil.Name);
     955              : 
     956           22 :             state.dataRptCoilSelection->coilSelectionReportObj->setCoilSupplyFanInfo(
     957           22 :                 state, fanCoil.CCoilName, fanCoil.CCoilType, fanCoil.FanName, fanCoil.fanType, fanCoil.FanIndex);
     958           22 :             state.dataRptCoilSelection->coilSelectionReportObj->setCoilSupplyFanInfo(
     959           22 :                 state, fanCoil.HCoilName, fanCoil.HCoilType, fanCoil.FanName, fanCoil.fanType, fanCoil.FanIndex);
     960              :         }
     961           18 :     }
     962              : 
     963        20319 :     void InitFanCoilUnits(EnergyPlusData &state,
     964              :                           int const FanCoilNum,       // number of the current fan coil unit being simulated
     965              :                           int const ControlledZoneNum // number of zone being served
     966              :     )
     967              :     {
     968              : 
     969              :         // SUBROUTINE INFORMATION:
     970              :         //       AUTHOR         Fred Buhl
     971              :         //       DATE WRITTEN   March 2000
     972              :         //       MODIFIED       July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
     973              : 
     974              :         // PURPOSE OF THIS SUBROUTINE:
     975              :         // This subroutine is for initializations of the Fan Coil Components.
     976              : 
     977              :         // METHODOLOGY EMPLOYED:
     978              :         // Uses the status flags to trigger initializations.
     979              : 
     980              :         // SUBROUTINE PARAMETER DEFINITIONS:
     981              :         static constexpr std::string_view RoutineName("InitFanCoilUnits");
     982              : 
     983        20319 :         auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum);
     984              : 
     985              :         // Do the one time initializations
     986        20319 :         if (state.dataFanCoilUnits->InitFanCoilUnitsOneTimeFlag) {
     987              : 
     988           11 :             state.dataFanCoilUnits->MyEnvrnFlag.allocate(state.dataFanCoilUnits->NumFanCoils);
     989           11 :             state.dataFanCoilUnits->MySizeFlag.allocate(state.dataFanCoilUnits->NumFanCoils);
     990           11 :             state.dataFanCoilUnits->MyPlantScanFlag.allocate(state.dataFanCoilUnits->NumFanCoils);
     991           11 :             state.dataFanCoilUnits->MyZoneEqFlag.allocate(state.dataFanCoilUnits->NumFanCoils);
     992           11 :             state.dataFanCoilUnits->MyEnvrnFlag = true;
     993           11 :             state.dataFanCoilUnits->MySizeFlag = true;
     994           11 :             state.dataFanCoilUnits->MyPlantScanFlag = true;
     995           11 :             state.dataFanCoilUnits->MyZoneEqFlag = true;
     996           11 :             state.dataFanCoilUnits->InitFanCoilUnitsOneTimeFlag = false;
     997              :         }
     998              : 
     999        20319 :         if (allocated(state.dataAvail->ZoneComp)) {
    1000        20302 :             auto &availMgr = state.dataAvail->ZoneComp(DataZoneEquipment::ZoneEquipType::FourPipeFanCoil).ZoneCompAvailMgrs(FanCoilNum);
    1001        20302 :             if (state.dataFanCoilUnits->MyZoneEqFlag(FanCoilNum)) { // initialize the name of each availability manager list and zone number
    1002            6 :                 availMgr.AvailManagerListName = fanCoil.AvailManagerListName;
    1003            6 :                 availMgr.ZoneNum = ControlledZoneNum;
    1004            6 :                 state.dataFanCoilUnits->MyZoneEqFlag(FanCoilNum) = false;
    1005              :             }
    1006        20302 :             fanCoil.availStatus = availMgr.availStatus;
    1007              :         }
    1008              : 
    1009        20319 :         if (state.dataFanCoilUnits->MyPlantScanFlag(FanCoilNum) && allocated(state.dataPlnt->PlantLoop)) {
    1010           15 :             bool errFlag = false;
    1011           15 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    1012           20 :                 PlantUtilities::ScanPlantLoopsForObject(
    1013           10 :                     state, fanCoil.HCoilName, fanCoil.HCoilPlantTypeOf, fanCoil.HeatCoilPlantLoc, errFlag, _, _, _, _, _);
    1014              : 
    1015           10 :                 if (errFlag) {
    1016            0 :                     ShowContinueError(state, format("Reference Unit=\"{}\", type={}", fanCoil.Name, fanCoil.UnitType));
    1017            0 :                     ShowFatalError(state, "InitFanCoilUnits: Program terminated for previous conditions.");
    1018              :                 }
    1019              : 
    1020           10 :                 fanCoil.HeatCoilFluidOutletNodeNum = DataPlant::CompData::getPlantComponent(state, fanCoil.HeatCoilPlantLoc).NodeNumOut;
    1021              : 
    1022            5 :             } else if (fanCoil.HCoilType_Num == HCoil::Electric) {
    1023              :                 // do nothing, valid type
    1024              :             } else {
    1025            0 :                 ShowFatalError(state, format("InitFanCoilUnits: FanCoil={}, invalid heating coil type. Program terminated.", fanCoil.Name));
    1026              :             }
    1027              : 
    1028           15 :             if ((fanCoil.CCoilPlantType == DataPlant::PlantEquipmentType::CoilWaterCooling) ||
    1029            0 :                 (fanCoil.CCoilPlantType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling)) {
    1030           30 :                 PlantUtilities::ScanPlantLoopsForObject(
    1031           15 :                     state, fanCoil.CCoilPlantName, fanCoil.CCoilPlantType, fanCoil.CoolCoilPlantLoc, errFlag, _, _, _, _, _);
    1032           15 :                 if (errFlag) {
    1033            0 :                     ShowContinueError(state, format("Reference Unit=\"{}\", type={}", fanCoil.Name, fanCoil.UnitType));
    1034            0 :                     ShowFatalError(state, "InitFanCoilUnits: Program terminated for previous conditions.");
    1035              :                 }
    1036           15 :                 fanCoil.CoolCoilFluidOutletNodeNum = DataPlant::CompData::getPlantComponent(state, fanCoil.CoolCoilPlantLoc).NodeNumOut;
    1037              :             } else {
    1038            0 :                 ShowFatalError(state, format("InitFanCoilUnits: FanCoil={}, invalid cooling coil type. Program terminated.", fanCoil.Name));
    1039              :             }
    1040              : 
    1041           15 :             state.dataFanCoilUnits->MyPlantScanFlag(FanCoilNum) = false;
    1042              :         }
    1043              : 
    1044        20319 :         if (!state.dataFanCoilUnits->InitFanCoilUnitsCheckInZoneEquipmentListFlag && state.dataZoneEquip->ZoneEquipInputsFilled) {
    1045            1 :             state.dataFanCoilUnits->InitFanCoilUnitsCheckInZoneEquipmentListFlag = true;
    1046            6 :             for (int Loop = 1; Loop <= state.dataFanCoilUnits->NumFanCoils; ++Loop) {
    1047           10 :                 if (DataZoneEquipment::CheckZoneEquipmentList(
    1048            5 :                         state, state.dataFanCoilUnits->FanCoil(Loop).UnitType, state.dataFanCoilUnits->FanCoil(Loop).Name)) {
    1049            5 :                     continue;
    1050              :                 }
    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        20332 :         if (!state.dataGlobal->SysSizingCalc && state.dataFanCoilUnits->MySizeFlag(FanCoilNum) &&
    1059           13 :             !state.dataFanCoilUnits->MyPlantScanFlag(FanCoilNum)) {
    1060              : 
    1061           13 :             SizeFanCoilUnit(state, FanCoilNum, ControlledZoneNum);
    1062              : 
    1063           13 :             state.dataFanCoilUnits->MySizeFlag(FanCoilNum) = false;
    1064              :         }
    1065              : 
    1066              :         // Do the Begin Environment initializations
    1067        20348 :         if (state.dataGlobal->BeginEnvrnFlag && state.dataFanCoilUnits->MyEnvrnFlag(FanCoilNum) &&
    1068           29 :             !state.dataFanCoilUnits->MyPlantScanFlag(FanCoilNum)) {
    1069           29 :             Real64 RhoAir = state.dataEnvrn->StdRhoAir;
    1070              :             // set the mass flow rates from the input volume flow rates
    1071           29 :             fanCoil.MaxAirMassFlow = RhoAir * fanCoil.MaxAirVolFlow;
    1072           29 :             fanCoil.OutAirMassFlow = RhoAir * fanCoil.OutAirVolFlow;
    1073              : 
    1074           29 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    1075              :                 Real64 rho =
    1076           25 :                     state.dataPlnt->PlantLoop(fanCoil.HeatCoilPlantLoc.loopNum).glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
    1077           25 :                 fanCoil.MaxHeatCoilFluidFlow = rho * fanCoil.MaxHotWaterVolFlow;
    1078           25 :                 fanCoil.MinHotWaterFlow = rho * fanCoil.MinHotWaterVolFlow;
    1079              :             }
    1080              : 
    1081           29 :             Real64 rho = state.dataPlnt->PlantLoop(fanCoil.CoolCoilPlantLoc.loopNum).glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
    1082           29 :             fanCoil.MaxCoolCoilFluidFlow = rho * fanCoil.MaxColdWaterVolFlow;
    1083           29 :             fanCoil.MinColdWaterFlow = rho * fanCoil.MinColdWaterVolFlow;
    1084              : 
    1085              :             // set the node max and min mass flow rates
    1086           29 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    1087           25 :                 PlantUtilities::InitComponentNodes(
    1088              :                     state, fanCoil.MinHotWaterFlow, fanCoil.MaxHeatCoilFluidFlow, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum);
    1089              :             }
    1090              : 
    1091           29 :             PlantUtilities::InitComponentNodes(
    1092              :                 state, fanCoil.MinColdWaterFlow, fanCoil.MaxCoolCoilFluidFlow, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum);
    1093              : 
    1094           29 :             if (fanCoil.OutsideAirNode > 0) {
    1095           27 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMax = fanCoil.OutAirMassFlow;
    1096           27 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMin = 0.0;
    1097              :             }
    1098           29 :             state.dataLoopNodes->Node(fanCoil.AirOutNode).MassFlowRateMax = fanCoil.MaxAirMassFlow;
    1099           29 :             state.dataLoopNodes->Node(fanCoil.AirOutNode).MassFlowRateMin = 0.0;
    1100           29 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRateMax = fanCoil.MaxAirMassFlow;
    1101           29 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRateMin = 0.0;
    1102           29 :             state.dataFanCoilUnits->MyEnvrnFlag(FanCoilNum) = false;
    1103              :         } // end one time inits
    1104              : 
    1105        20319 :         if (!state.dataGlobal->BeginEnvrnFlag) {
    1106        20186 :             state.dataFanCoilUnits->MyEnvrnFlag(FanCoilNum) = true;
    1107              :         }
    1108              : 
    1109              :         // These initializations are done every iteration
    1110        20319 :         fanCoil.SpeedRatio = 0.0;
    1111        20319 :         if (fanCoil.fanOpModeSched != nullptr) {
    1112            9 :             fanCoil.fanOp = (fanCoil.fanOpModeSched->getCurrentVal() == 0.0) ? HVAC::FanOp::Cycling : HVAC::FanOp::Continuous;
    1113              :         }
    1114              :         // Set the inlet node mass flow rate
    1115        40637 :         if (((fanCoil.availSched->getCurrentVal() > 0.0 && fanCoil.fanAvailSched->getCurrentVal() > 0.0) || state.dataHVACGlobal->TurnFansOn) &&
    1116        20318 :             !state.dataHVACGlobal->TurnFansOff) {
    1117        20318 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRate = fanCoil.MaxAirMassFlow;
    1118        20318 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRateMaxAvail = state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRate;
    1119        20318 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRateMinAvail = 0.0;
    1120              : 
    1121        20318 :             if (fanCoil.OutsideAirNode > 0) {
    1122        20315 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRate = fanCoil.OutAirMassFlow;
    1123        20315 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMaxAvail = fanCoil.OutAirMassFlow;
    1124        20315 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMinAvail = fanCoil.OutAirMassFlow;
    1125        20315 :                 state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRate = fanCoil.OutAirMassFlow;
    1126        20315 :                 state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRateMaxAvail = fanCoil.OutAirMassFlow;
    1127        20315 :                 state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRateMinAvail = fanCoil.OutAirMassFlow;
    1128              :             }
    1129              : 
    1130              :         } else {
    1131            1 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRate = 0.0;
    1132            1 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRateMaxAvail = 0.0;
    1133            1 :             state.dataLoopNodes->Node(fanCoil.AirInNode).MassFlowRateMinAvail = 0.0;
    1134            1 :             if (fanCoil.OutsideAirNode > 0) {
    1135            0 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRate = 0.0;
    1136            0 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMaxAvail = 0.0;
    1137            0 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMinAvail = 0.0;
    1138            0 :                 state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRate = 0.0;
    1139            0 :                 state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRateMaxAvail = 0.0;
    1140            0 :                 state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRateMinAvail = 0.0;
    1141              :             }
    1142              :         }
    1143        20319 :     }
    1144              : 
    1145           13 :     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           13 :         std::string CoolingCoilName;
    1171           13 :         std::string CoolingCoilType;
    1172              :         Real64 rho;
    1173              :         Real64 Cp;
    1174              :         int zoneHVACIndex;        // index of zoneHVAC equipment sizing specification
    1175           13 :         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           13 :         bool ErrorsFound = false;             // TRUE if errors found during sizing
    1185           13 :         bool IsAutoSize = false;              // Indicator to autosize for reporting
    1186           13 :         Real64 MaxAirVolFlowDes = 0.0;        // Autosized max air flow for reporting
    1187           13 :         Real64 MaxAirVolFlowUser = 0.0;       // Hardsized max air flow for reporting
    1188           13 :         Real64 OutAirVolFlowDes = 0.0;        // Autosized outdoor air flow for reporting
    1189           13 :         Real64 OutAirVolFlowUser = 0.0;       // Hardsized outdoor air flow for reporting
    1190           13 :         Real64 MaxHotWaterVolFlowDes = 0.0;   // Autosized hot water flow for reporting
    1191           13 :         Real64 MaxHotWaterVolFlowUser = 0.0;  // Hardsized hot water flow for reporting
    1192           13 :         Real64 MaxColdWaterVolFlowDes = 0.0;  // Autosized cold water flow for reporting
    1193           13 :         Real64 MaxColdWaterVolFlowUser = 0.0; // Hardsized cold water flow for reporting
    1194           13 :         Real64 CoolingAirVolFlowDes = 0.0;    // cooling supply air flow rate
    1195           13 :         Real64 HeatingAirVolFlowDes = 0.0;    // heating supply air flow rate
    1196              : 
    1197           13 :         state.dataSize->ZoneHeatingOnlyFan = false;
    1198           13 :         state.dataSize->ZoneCoolingOnlyFan = false;
    1199           13 :         state.dataSize->DataScalableSizingON = false;
    1200           13 :         state.dataSize->DataScalableCapSizingON = false;
    1201              : 
    1202           13 :         state.dataSize->DataFracOfAutosizedCoolingAirflow = 1.0;
    1203           13 :         state.dataSize->DataFracOfAutosizedHeatingAirflow = 1.0;
    1204           13 :         state.dataSize->DataFracOfAutosizedCoolingCapacity = 1.0;
    1205           13 :         state.dataSize->DataFracOfAutosizedHeatingCapacity = 1.0;
    1206              : 
    1207           13 :         auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum);
    1208              : 
    1209           13 :         std::string CompType = fanCoil.UnitType;
    1210           13 :         std::string CompName = fanCoil.Name;
    1211           13 :         state.dataSize->DataZoneNumber = fanCoil.ControlZoneNum;
    1212           13 :         state.dataSize->DataFanType = fanCoil.fanType;
    1213           13 :         state.dataSize->DataFanIndex = fanCoil.FanIndex;
    1214              :         // fan coil unit is always blow thru
    1215           13 :         state.dataSize->DataFanPlacement = HVAC::FanPlace::BlowThru;
    1216              : 
    1217           13 :         auto &zoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
    1218              : 
    1219           13 :         if (state.dataSize->CurZoneEqNum > 0) {
    1220           13 :             if (fanCoil.HVACSizingIndex > 0) {
    1221              : 
    1222              :                 // initialize OA flow for sizing other inputs (e.g., inlet temp, capacity, etc.)
    1223            0 :                 if (fanCoil.OutAirVolFlow == DataSizing::AutoSize) {
    1224            0 :                     zoneEqSizing.OAVolFlow = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
    1225              :                 } else {
    1226            0 :                     zoneEqSizing.OAVolFlow = fanCoil.OutAirVolFlow;
    1227              :                 }
    1228            0 :                 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            0 :                 zoneHVACIndex = fanCoil.HVACSizingIndex;
    1234            0 :                 int FieldNum = 1; // IDD numeric field number where input field description is found
    1235            0 :                 PrintFlag = true;
    1236              :                 int SAFMethod; // supply air flow rate sizing method (SupplyAirFlowRate, FlowPerFloorArea, FractionOfAutosizedCoolingAirflow,
    1237            0 :                 SizingString = state.dataFanCoilUnits->FanCoilNumericFields(FanCoilNum).FieldNames(FieldNum) + " [m3/s]";
    1238            0 :                 if (state.dataGlobal->isEpJSON) {
    1239            0 :                     SizingString = "maximum_supply_air_flow_rate [m3/s]";
    1240              :                 }
    1241            0 :                 if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod > 0) {
    1242            0 :                     SizingMethod = HVAC::CoolingAirflowSizing;
    1243            0 :                     SAFMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod;
    1244            0 :                     zoneEqSizing.SizingMethod(SizingMethod) = SAFMethod;
    1245            0 :                     if (SAFMethod == DataSizing::SupplyAirFlowRate || SAFMethod == DataSizing::FlowPerFloorArea ||
    1246              :                         SAFMethod == DataSizing::FractionOfAutosizedCoolingAirflow) {
    1247            0 :                         if (SAFMethod == DataSizing::SupplyAirFlowRate) {
    1248            0 :                             if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow > 0.0) {
    1249            0 :                                 zoneEqSizing.AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
    1250            0 :                                 zoneEqSizing.SystemAirFlow = true;
    1251              :                             }
    1252            0 :                             TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
    1253            0 :                         } else if (SAFMethod == DataSizing::FlowPerFloorArea) {
    1254            0 :                             zoneEqSizing.SystemAirFlow = true;
    1255            0 :                             zoneEqSizing.AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow *
    1256            0 :                                                       state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1257            0 :                             TempSize = zoneEqSizing.AirVolFlow;
    1258            0 :                             state.dataSize->DataScalableSizingON = true;
    1259            0 :                         } else if (SAFMethod == DataSizing::FractionOfAutosizedCoolingAirflow) {
    1260            0 :                             state.dataSize->DataFracOfAutosizedCoolingAirflow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
    1261            0 :                             TempSize = DataSizing::AutoSize;
    1262            0 :                             state.dataSize->DataScalableSizingON = true;
    1263              :                         } else {
    1264            0 :                             TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
    1265              :                         }
    1266            0 :                         CoolingAirFlowSizer sizingCoolingAirFlow;
    1267            0 :                         sizingCoolingAirFlow.overrideSizingString(SizingString);
    1268              :                         // sizingCoolingAirFlow.setHVACSizingIndexData(fanCoil.HVACSizingIndex);
    1269            0 :                         sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1270            0 :                         CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
    1271              : 
    1272            0 :                     } 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            0 :                 if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == DataSizing::AutoSize ||
    1358            0 :                     state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == DataSizing::AutoSize) {
    1359            0 :                     IsAutoSize = true;
    1360            0 :                     fanCoil.MaxAirVolFlow = DataSizing::AutoSize;
    1361            0 :                     MaxAirVolFlowDes = max(CoolingAirVolFlowDes, HeatingAirVolFlowDes);
    1362              :                 } else {
    1363            0 :                     fanCoil.MaxAirVolFlow = max(CoolingAirVolFlowDes, HeatingAirVolFlowDes);
    1364            0 :                     MaxAirVolFlowDes = 0.0;
    1365              :                 }
    1366              :             } else {
    1367              :                 // SizingString = "Supply Air Maximum Flow Rate [m3/s]";
    1368           13 :                 TempSize = fanCoil.MaxAirVolFlow;
    1369           13 :                 PrintFlag = true;
    1370           13 :                 if (fanCoil.MaxAirVolFlow == DataSizing::AutoSize) {
    1371            7 :                     IsAutoSize = true;
    1372            7 :                     SystemAirFlowSizer sizerSystemAirFlow;
    1373              :                     // sizerSystemAirFlow.setHVACSizingIndexData(fanCoil.HVACSizingIndex);
    1374            7 :                     sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1375            7 :                     MaxAirVolFlowDes = sizerSystemAirFlow.size(state, TempSize, ErrorsFound);
    1376            7 :                 } else {
    1377            6 :                     MaxAirVolFlowDes = 0.0;
    1378              :                 }
    1379              :             }
    1380              :         }
    1381              : 
    1382           13 :         if (state.dataSize->CurZoneEqNum > 0) {
    1383           13 :             if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) {
    1384              : 
    1385              :             } else {
    1386           13 :                 if (MaxAirVolFlowDes < HVAC::SmallAirVolFlow) {
    1387            6 :                     MaxAirVolFlowDes = 0.0;
    1388              :                 }
    1389              : 
    1390              :                 //     If fan is autosized, get fan volumetric flow rate
    1391           13 :                 if (fanCoil.FanAirVolFlow == DataSizing::AutoSize) {
    1392            7 :                     state.dataFans->fans(fanCoil.FanIndex)->simulate(state, true, _, _);
    1393            7 :                     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           13 :                 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           13 :                 if (IsAutoSize) {
    1407            7 :                     fanCoil.MaxAirVolFlow = MaxAirVolFlowDes;
    1408              :                 } else { // Hard size with sizing data
    1409            6 :                     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           13 :         IsAutoSize = false;
    1443           13 :         if (fanCoil.OutAirVolFlow == DataSizing::AutoSize) {
    1444            2 :             IsAutoSize = true;
    1445              :         }
    1446              : 
    1447           13 :         if (state.dataSize->CurZoneEqNum > 0) {
    1448           13 :             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           13 :                 CheckZoneSizing(state, fanCoil.UnitType, fanCoil.Name);
    1455           13 :                 OutAirVolFlowDes = min(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA, fanCoil.MaxAirVolFlow);
    1456           13 :                 if (OutAirVolFlowDes < HVAC::SmallAirVolFlow) {
    1457            8 :                     OutAirVolFlowDes = 0.0;
    1458              :                 }
    1459           13 :                 if (IsAutoSize) {
    1460            2 :                     fanCoil.OutAirVolFlow = OutAirVolFlowDes;
    1461            2 :                     BaseSizer::reportSizerOutput(
    1462              :                         state, fanCoil.UnitType, fanCoil.Name, "Design Size Maximum Outdoor Air Flow Rate [m3/s]", OutAirVolFlowDes);
    1463              :                 } else {
    1464           11 :                     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           13 :             zoneEqSizing.OAVolFlow = fanCoil.OutAirVolFlow; // sets OA frac in sizing
    1489              : 
    1490           13 :             if (fanCoil.ATMixerExists) {      // set up ATMixer conditions for use in component sizing
    1491            2 :                 zoneEqSizing.OAVolFlow = 0.0; // Equipment OA flow should always be 0 when ATMixer is used
    1492            2 :                 SingleDuct::setATMixerSizingProperties(state, fanCoil.ATMixerIndex, ControlledZoneNum, state.dataSize->CurZoneEqNum);
    1493              :             }
    1494              :         }
    1495              : 
    1496           13 :         if (fanCoil.HCoilType_Num == HCoil::Water) {
    1497           10 :             IsAutoSize = false;
    1498           10 :             if (fanCoil.MaxHotWaterVolFlow == DataSizing::AutoSize) {
    1499            7 :                 IsAutoSize = true;
    1500              :             }
    1501              : 
    1502           10 :             if (state.dataSize->CurZoneEqNum > 0) {
    1503           10 :                 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           20 :                     state.dataFanCoilUnits->CoilWaterInletNode =
    1510           10 :                         WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", fanCoil.HCoilName, ErrorsFound);
    1511           20 :                     state.dataFanCoilUnits->CoilWaterOutletNode =
    1512           10 :                         WaterCoils::GetCoilWaterOutletNode(state, "Coil:Heating:Water", fanCoil.HCoilName, ErrorsFound);
    1513           10 :                     if (IsAutoSize) {
    1514            7 :                         int PltSizHeatNum = PlantUtilities::MyPlantSizingIndex(state,
    1515              :                                                                                "Coil:Heating:Water",
    1516              :                                                                                fanCoil.HCoilName,
    1517            7 :                                                                                state.dataFanCoilUnits->CoilWaterInletNode,
    1518            7 :                                                                                state.dataFanCoilUnits->CoilWaterOutletNode,
    1519              :                                                                                ErrorsFound);
    1520            7 :                         CoilNum = WaterCoils::GetWaterCoilIndex(state, "COIL:HEATING:WATER", fanCoil.HCoilName, ErrorsFound);
    1521              :                         bool DoWaterCoilSizing; // if TRUE do water coil sizing calculation
    1522            7 :                         if (state.dataWaterCoils->WaterCoil(CoilNum).UseDesignWaterDeltaTemp) {
    1523            0 :                             WaterCoilSizDeltaT = state.dataWaterCoils->WaterCoil(CoilNum).DesignWaterDeltaTemp;
    1524            0 :                             DoWaterCoilSizing = true;
    1525              :                         } else {
    1526            7 :                             if (PltSizHeatNum > 0) {
    1527            7 :                                 WaterCoilSizDeltaT = state.dataSize->PlantSizData(PltSizHeatNum).DeltaT;
    1528            7 :                                 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            7 :                         if (DoWaterCoilSizing) {
    1538            7 :                             SizingMethod = HVAC::HeatingCapacitySizing;
    1539            7 :                             if (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatMassFlow > 0.0) {
    1540            7 :                                 state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatOAFlowFrac =
    1541            7 :                                     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            7 :                             if (fanCoil.HVACSizingIndex > 0) {
    1546            0 :                                 zoneHVACIndex = fanCoil.HVACSizingIndex;
    1547            0 :                                 int CapSizingMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingCapMethod;
    1548            0 :                                 zoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
    1549            0 :                                 if (CapSizingMethod == DataSizing::HeatingDesignCapacity || CapSizingMethod == DataSizing::CapacityPerFloorArea ||
    1550              :                                     CapSizingMethod == DataSizing::FractionOfAutosizedHeatingCapacity) {
    1551            0 :                                     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            0 :                                     } else if (CapSizingMethod == DataSizing::CapacityPerFloorArea) {
    1558            0 :                                         if (state.dataSize->ZoneSizingRunDone) {
    1559            0 :                                             PrintFlag = false;
    1560            0 :                                             TempSize = DataSizing::AutoSize;
    1561            0 :                                             state.dataSize->DataFlowUsedForSizing =
    1562            0 :                                                 state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
    1563            0 :                                             bool errorsFound = false;
    1564            0 :                                             HeatingCapacitySizer sizerHeatingCapacity;
    1565            0 :                                             sizerHeatingCapacity.overrideSizingString(SizingString);
    1566            0 :                                             sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1567            0 :                                             zoneEqSizing.DesHeatingLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1568            0 :                                             zoneEqSizing.HeatingCapacity = true;
    1569            0 :                                         }
    1570            0 :                                         TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity *
    1571            0 :                                                    state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1572            0 :                                         state.dataSize->DataScalableCapSizingON = true;
    1573            0 :                                     } else if (CapSizingMethod == DataSizing::FractionOfAutosizedHeatingCapacity) {
    1574            0 :                                         CheckZoneSizing(state, CompType, CompName);
    1575            0 :                                         PrintFlag = false;
    1576            0 :                                         TempSize = DataSizing::AutoSize;
    1577            0 :                                         state.dataSize->DataFlowUsedForSizing =
    1578            0 :                                             state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
    1579            0 :                                         bool errorsFound = false;
    1580            0 :                                         HeatingCapacitySizer sizerHeatingCapacity;
    1581            0 :                                         sizerHeatingCapacity.overrideSizingString(SizingString);
    1582            0 :                                         sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1583            0 :                                         zoneEqSizing.DesHeatingLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1584            0 :                                         zoneEqSizing.HeatingCapacity = true;
    1585            0 :                                         TempSize = zoneEqSizing.DesHeatingLoad * state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
    1586            0 :                                         state.dataSize->DataScalableCapSizingON = true;
    1587            0 :                                     }
    1588              :                                 }
    1589            0 :                                 SizingString = "Heating Design Capacity [W]";
    1590            0 :                                 PrintFlag = false;
    1591            0 :                                 bool errorsFound = false;
    1592            0 :                                 HeatingCapacitySizer sizerHeatingCapacity;
    1593            0 :                                 sizerHeatingCapacity.overrideSizingString(SizingString);
    1594            0 :                                 sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1595            0 :                                 DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1596            0 :                                 state.dataSize->DataScalableCapSizingON = false;
    1597            0 :                                 state.dataSize->DataFlowUsedForSizing = 0.0;
    1598              : 
    1599            0 :                             } else {
    1600            7 :                                 SizingString = "Heating Design Capacity [W]";
    1601            7 :                                 PrintFlag = false;
    1602            7 :                                 TempSize = DataSizing::AutoSize;
    1603            7 :                                 bool errorsFound = false;
    1604            7 :                                 HeatingCapacitySizer sizerHeatingCapacity;
    1605            7 :                                 sizerHeatingCapacity.overrideSizingString(SizingString);
    1606            7 :                                 sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1607            7 :                                 DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1608            7 :                             }
    1609            7 :                             fanCoil.DesHeatingLoad = DesCoilLoad;
    1610            7 :                             if (DesCoilLoad >= HVAC::SmallLoad) {
    1611            7 :                                 rho = state.dataPlnt->PlantLoop(fanCoil.HeatCoilPlantLoc.loopNum)
    1612            7 :                                           .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineNameNoSpace);
    1613            7 :                                 Cp = state.dataPlnt->PlantLoop(fanCoil.HeatCoilPlantLoc.loopNum)
    1614            7 :                                          .glycol->getSpecificHeat(state, Constant::HWInitConvTemp, RoutineNameNoSpace);
    1615              : 
    1616            7 :                                 MaxHotWaterVolFlowDes = DesCoilLoad / (WaterCoilSizDeltaT * Cp * rho);
    1617              :                             } else {
    1618            0 :                                 MaxHotWaterVolFlowDes = 0.0;
    1619              :                             }
    1620              :                         }
    1621              :                     }
    1622              :                 }
    1623              : 
    1624           10 :                 if (IsAutoSize) {
    1625            7 :                     fanCoil.MaxHotWaterVolFlow = MaxHotWaterVolFlowDes;
    1626            7 :                     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            3 :                     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            3 :         } else if (fanCoil.HCoilType_Num == HCoil::Electric) {
    1655            3 :             if (fanCoil.DesignHeatingCapacity == DataSizing::AutoSize) {
    1656            0 :                 CompName = fanCoil.HCoilName;
    1657            0 :                 CompType = fanCoil.HCoilType;
    1658            0 :                 SizingMethod = HVAC::HeatingCapacitySizing;
    1659            0 :                 PrintFlag = false;
    1660            0 :                 TempSize = fanCoil.DesignHeatingCapacity;
    1661            0 :                 SizingString = "Nominal Heating Capacity [W]";
    1662            0 :                 bool errorsFound = false;
    1663            0 :                 HeatingCapacitySizer sizerHeatingCapacity;
    1664            0 :                 sizerHeatingCapacity.overrideSizingString(SizingString);
    1665            0 :                 sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1666            0 :                 fanCoil.DesignHeatingCapacity = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1667            0 :                 fanCoil.DesHeatingLoad = fanCoil.DesignHeatingCapacity;
    1668            0 :             }
    1669              :         }
    1670              : 
    1671           13 :         IsAutoSize = false;
    1672           13 :         if (fanCoil.MaxColdWaterVolFlow == DataSizing::AutoSize) {
    1673            7 :             IsAutoSize = true;
    1674              :         }
    1675           13 :         if (state.dataSize->CurZoneEqNum > 0) {
    1676           13 :             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           13 :                 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           13 :                     CoolingCoilName = fanCoil.CCoilName;
    1687           13 :                     CoolingCoilType = fanCoil.CCoilType;
    1688              :                 }
    1689           13 :                 state.dataFanCoilUnits->CoilWaterInletNode = WaterCoils::GetCoilWaterInletNode(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
    1690           26 :                 state.dataFanCoilUnits->CoilWaterOutletNode =
    1691           13 :                     WaterCoils::GetCoilWaterOutletNode(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
    1692           13 :                 if (IsAutoSize) {
    1693            7 :                     int PltSizCoolNum = PlantUtilities::MyPlantSizingIndex(state,
    1694              :                                                                            CoolingCoilType,
    1695              :                                                                            CoolingCoilName,
    1696            7 :                                                                            state.dataFanCoilUnits->CoilWaterInletNode,
    1697            7 :                                                                            state.dataFanCoilUnits->CoilWaterOutletNode,
    1698              :                                                                            ErrorsFound);
    1699            7 :                     CoilNum = WaterCoils::GetWaterCoilIndex(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
    1700              :                     bool DoWaterCoilSizing; // if TRUE do water coil sizing calculation
    1701            7 :                     if (state.dataWaterCoils->WaterCoil(CoilNum).UseDesignWaterDeltaTemp) {
    1702            0 :                         WaterCoilSizDeltaT = state.dataWaterCoils->WaterCoil(CoilNum).DesignWaterDeltaTemp;
    1703            0 :                         DoWaterCoilSizing = true;
    1704              :                     } else {
    1705            7 :                         if (PltSizCoolNum > 0) {
    1706            7 :                             WaterCoilSizDeltaT = state.dataSize->PlantSizData(PltSizCoolNum).DeltaT;
    1707            7 :                             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            7 :                     if (DoWaterCoilSizing) {
    1718            7 :                         SizingMethod = HVAC::CoolingCapacitySizing;
    1719            7 :                         if (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolMassFlow > 0.0) {
    1720            7 :                             state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolOAFlowFrac =
    1721            7 :                                 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            7 :                         if (fanCoil.HVACSizingIndex > 0) {
    1726            0 :                             zoneHVACIndex = fanCoil.HVACSizingIndex;
    1727            0 :                             int CapSizingMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingCapMethod;
    1728            0 :                             zoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
    1729            0 :                             if (CapSizingMethod == DataSizing::CoolingDesignCapacity || CapSizingMethod == DataSizing::CapacityPerFloorArea ||
    1730              :                                 CapSizingMethod == DataSizing::FractionOfAutosizedCoolingCapacity) {
    1731            0 :                                 if (CapSizingMethod == DataSizing::CoolingDesignCapacity) {
    1732            0 :                                     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            0 :                                         state.dataSize->DataFlowUsedForSizing =
    1737            0 :                                             state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
    1738              :                                     }
    1739            0 :                                     TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
    1740            0 :                                 } else if (CapSizingMethod == DataSizing::CapacityPerFloorArea) {
    1741            0 :                                     if (state.dataSize->ZoneSizingRunDone) {
    1742            0 :                                         CheckZoneSizing(state, CompType, CompName);
    1743            0 :                                         PrintFlag = false;
    1744            0 :                                         TempSize = DataSizing::AutoSize;
    1745            0 :                                         state.dataSize->DataFlowUsedForSizing =
    1746            0 :                                             state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
    1747            0 :                                         CoolingCapacitySizer sizerCoolingCapacity;
    1748            0 :                                         sizerCoolingCapacity.overrideSizingString(SizingString);
    1749            0 :                                         sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1750            0 :                                         zoneEqSizing.DesCoolingLoad = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
    1751            0 :                                         zoneEqSizing.CoolingCapacity = true;
    1752            0 :                                     }
    1753            0 :                                     TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity *
    1754            0 :                                                state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1755            0 :                                     state.dataSize->DataScalableCapSizingON = true;
    1756            0 :                                 } else if (CapSizingMethod == DataSizing::FractionOfAutosizedCoolingCapacity) {
    1757            0 :                                     PrintFlag = false;
    1758            0 :                                     TempSize = DataSizing::AutoSize;
    1759            0 :                                     state.dataSize->DataFlowUsedForSizing =
    1760            0 :                                         state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
    1761            0 :                                     CoolingCapacitySizer sizerCoolingCapacity2;
    1762            0 :                                     sizerCoolingCapacity2.overrideSizingString(SizingString);
    1763            0 :                                     sizerCoolingCapacity2.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1764            0 :                                     zoneEqSizing.DesCoolingLoad = sizerCoolingCapacity2.size(state, TempSize, ErrorsFound);
    1765            0 :                                     zoneEqSizing.CoolingCapacity = true;
    1766            0 :                                     TempSize = zoneEqSizing.DesCoolingLoad * state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
    1767            0 :                                     state.dataSize->DataScalableCapSizingON = true;
    1768            0 :                                 }
    1769              :                             }
    1770            0 :                             SizingString = "Cooling Design Capacity [W]";
    1771            0 :                             PrintFlag = false;
    1772            0 :                             CoolingCapacitySizer sizerCoolingCapacity3;
    1773            0 :                             sizerCoolingCapacity3.overrideSizingString(SizingString);
    1774            0 :                             sizerCoolingCapacity3.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1775            0 :                             DesCoilLoad = sizerCoolingCapacity3.size(state, TempSize, ErrorsFound);
    1776            0 :                             state.dataSize->DataScalableCapSizingON = false;
    1777            0 :                             state.dataSize->DataFlowUsedForSizing = 0.0;
    1778            0 :                         } else {
    1779            7 :                             SizingString = "Cooling Design Capacity [W]";
    1780            7 :                             PrintFlag = false;
    1781            7 :                             TempSize = DataSizing::AutoSize;
    1782            7 :                             state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
    1783            7 :                             CoolingCapacitySizer sizerCoolingCapacity;
    1784            7 :                             sizerCoolingCapacity.overrideSizingString(SizingString);
    1785            7 :                             sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1786            7 :                             DesCoilLoad = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
    1787            7 :                         }
    1788            7 :                         fanCoil.DesCoolingLoad = DesCoilLoad;
    1789            7 :                         if (DesCoilLoad >= HVAC::SmallLoad) {
    1790            7 :                             rho = state.dataPlnt->PlantLoop(fanCoil.CoolCoilPlantLoc.loopNum).glycol->getDensity(state, 5., RoutineNameNoSpace);
    1791            7 :                             Cp = state.dataPlnt->PlantLoop(fanCoil.CoolCoilPlantLoc.loopNum).glycol->getSpecificHeat(state, 5., RoutineNameNoSpace);
    1792            7 :                             MaxColdWaterVolFlowDes = DesCoilLoad / (WaterCoilSizDeltaT * Cp * rho);
    1793              :                         } else {
    1794            0 :                             MaxColdWaterVolFlowDes = 0.0;
    1795              :                         }
    1796              :                     }
    1797            7 :                     fanCoil.MaxColdWaterVolFlow = MaxColdWaterVolFlowDes;
    1798            7 :                     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            6 :                     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           13 :             if (fanCoil.CapCtrlMeth_Num == CCM::ASHRAE && !fanCoil.ASHRAETempControl) {
    1828              : 
    1829            0 :                 CompType = fanCoil.UnitType;
    1830            0 :                 CompName = fanCoil.Name;
    1831            0 :                 PrintFlag = true;
    1832              : 
    1833            0 :                 ZoneCoolingLoadSizer sizerZoneCoolingLoad;
    1834            0 :                 sizerZoneCoolingLoad.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1835            0 :                 fanCoil.DesZoneCoolingLoad = sizerZoneCoolingLoad.size(state, fanCoil.DesZoneCoolingLoad, ErrorsFound);
    1836            0 :                 fanCoil.DesZoneCoolingLoad *= -1.0;
    1837              : 
    1838            0 :                 ZoneHeatingLoadSizer sizerZoneHeatingLoad;
    1839            0 :                 sizerZoneHeatingLoad.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1840            0 :                 fanCoil.DesZoneHeatingLoad = sizerZoneHeatingLoad.size(state, fanCoil.DesZoneHeatingLoad, ErrorsFound);
    1841              : 
    1842            0 :                 fanCoil.DSOAPtr = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneDesignSpecOAIndex;
    1843              : 
    1844           13 :             } else if (fanCoil.CapCtrlMeth_Num == CCM::ASHRAE && fanCoil.ASHRAETempControl) {
    1845              : 
    1846            1 :                 CompType = fanCoil.UnitType;
    1847            1 :                 CompName = fanCoil.Name;
    1848            1 :                 Real64 capacityMultiplier = 0.6; // 60% of design zone load for water coils
    1849            1 :                 state.dataSize->DataCapacityUsedForSizing = fanCoil.DesCoolingLoad * capacityMultiplier;
    1850            1 :                 bool SizingDesRunThisZone = false;
    1851            1 :                 CheckThisZoneForSizing(state, state.dataSize->CurZoneEqNum, SizingDesRunThisZone);
    1852            1 :                 if (SizingDesRunThisZone) {
    1853            0 :                     state.dataSize->DataCapacityUsedForSizing =
    1854            0 :                         state.dataSize->FinalZoneSizing(fanCoil.ControlZoneNum).DesCoolLoad * capacityMultiplier;
    1855              :                 } else {
    1856            1 :                     state.dataSize->DataCapacityUsedForSizing = fanCoil.DesCoolingLoad * capacityMultiplier;
    1857              :                 }
    1858            1 :                 state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
    1859            1 :                 PrintFlag = true;
    1860            1 :                 ASHRAEMinSATCoolingSizer sizerASHRAEMinSATCooling;
    1861            1 :                 sizerASHRAEMinSATCooling.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1862            1 :                 fanCoil.DesignMinOutletTemp = sizerASHRAEMinSATCooling.size(state, fanCoil.DesignMinOutletTemp, ErrorsFound);
    1863              : 
    1864            1 :                 if (SizingDesRunThisZone) {
    1865            0 :                     state.dataSize->DataCapacityUsedForSizing =
    1866            0 :                         state.dataSize->FinalZoneSizing(fanCoil.ControlZoneNum).DesHeatLoad * capacityMultiplier;
    1867              :                 } else {
    1868            1 :                     state.dataSize->DataCapacityUsedForSizing = fanCoil.DesHeatingLoad * capacityMultiplier;
    1869              :                 }
    1870            1 :                 state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
    1871            1 :                 ASHRAEMaxSATHeatingSizer sizerASHRAEMaxSATHeating;
    1872            1 :                 sizerASHRAEMaxSATHeating.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1873            1 :                 fanCoil.DesignMaxOutletTemp = sizerASHRAEMaxSATHeating.size(state, fanCoil.DesignMaxOutletTemp, ErrorsFound);
    1874              : 
    1875            1 :                 state.dataSize->DataCapacityUsedForSizing = 0.0; // reset so other routines don't use this inadvertently
    1876            1 :                 state.dataSize->DataFlowUsedForSizing = 0.0;
    1877              : 
    1878            1 :                 SizingDesRunThisZone = false;
    1879            1 :                 CheckThisZoneForSizing(state, state.dataSize->CurZoneEqNum, SizingDesRunThisZone);
    1880              : 
    1881            1 :                 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            1 :                     fanCoil.DesZoneCoolingLoad = -1.0 * fanCoil.DesCoolingLoad;
    1892            1 :                     fanCoil.DesZoneHeatingLoad = fanCoil.DesHeatingLoad;
    1893              :                 }
    1894            1 :             }
    1895              : 
    1896              :         } // if ( CurZoneEqNum > 0 )
    1897              : 
    1898              :         // set the design air flow rates for the heating and cooling coils
    1899           13 :         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           13 :             CoolingCoilName = fanCoil.CCoilName;
    1904           13 :             CoolingCoilType = fanCoil.CCoilType;
    1905              :         }
    1906           13 :         if (state.dataSize->ZoneSizingRunDone) {
    1907           13 :             WaterCoils::SetCoilDesFlow(
    1908           13 :                 state, CoolingCoilType, CoolingCoilName, state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow, ErrorsFound);
    1909           13 :             WaterCoils::SetCoilDesFlow(state,
    1910              :                                        fanCoil.HCoilType,
    1911           13 :                                        fanCoil.HCoilName,
    1912           13 :                                        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           13 :         if (state.dataSize->CurZoneEqNum > 0) {
    1919           13 :             zoneEqSizing.MaxHWVolFlow = fanCoil.MaxHotWaterVolFlow;
    1920           13 :             zoneEqSizing.MaxCWVolFlow = fanCoil.MaxColdWaterVolFlow;
    1921           13 :             zoneEqSizing.AirVolFlow = fanCoil.MaxAirVolFlow;
    1922           13 :             zoneEqSizing.DesCoolingLoad = fanCoil.DesCoolingLoad;
    1923           13 :             zoneEqSizing.DesHeatingLoad = fanCoil.DesHeatingLoad;
    1924           13 :             zoneEqSizing.DesignSizeFromParent = true;
    1925              :         }
    1926              : 
    1927           13 :         if (ErrorsFound) {
    1928            0 :             ShowFatalError(state, "Preceding sizing errors cause program termination");
    1929              :         }
    1930           13 :     }
    1931              : 
    1932        20349 :     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        20349 :         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        20349 :         auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum);
    1986              : 
    1987              :         // initialize local variables
    1988        20349 :         bool UnitOn = true;         // TRUE if unit is on
    1989        20349 :         Real64 QUnitOut = 0.0;      // heating or sens. cooling provided by fan coil unit [watts]
    1990        20349 :         Real64 QUnitOutMax = 0.0;   // heating or sens. cooling provided by fan coil unit (running during an entire timestep)
    1991        20349 :         Real64 PLR = 0.0;           // Part Load Ratio, fraction of time step fancoil is on
    1992        20349 :         Real64 LatentOutput = 0.0;  // Latent (moisture) add/removal rate, negative is dehumidification [kg/s]
    1993        20349 :         Real64 QUnitOutNoHC = 0.0;  // unit output with no active heating or cooling [W]
    1994        20349 :         Real64 QCoilHeatSP = 0.0;   // coil load to the heating setpoint [W]
    1995        20349 :         Real64 QCoilCoolSP = 0.0;   // coil load to the cooling setpoint [W]
    1996        20349 :         Real64 QZnReq = 0.0;        // heating or cooling needed by zone [watts]
    1997        20349 :         Real64 ControlOffset = 0.0; // tolerance for output control
    1998        20349 :         Real64 MaxWaterFlow = 0.0;  // maximum water flow for heating or cooling [kg/sec]
    1999        20349 :         Real64 MinWaterFlow = 0.0;  // minimum water flow for heating or cooling [kg/sec]
    2000        20349 :         int OutletNode = fanCoil.AirOutNode;
    2001        20349 :         int InletNode = fanCoil.AirInNode;
    2002        20349 :         Real64 AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate; // air mass flow rate [kg/sec]
    2003        20349 :         Real64 Error = 1.0;                                                     // Error between QZnReq and QUnitOut
    2004        20349 :         Real64 AbsError = 2.0 * HVAC::SmallLoad;                                // Absolute error between QZnReq and QUnitOut [W]   !FB
    2005        20349 :         Real64 Relax = 1.0;
    2006        20349 :         Real64 HWFlow = 0.0;         // hot water mass flow rate solution [kg/s]
    2007        20349 :         Real64 HWFlowBypass = 0.0;   // hot water bypassed mass flow rate [kg/s]
    2008        20349 :         Real64 MdotLockH = 0.0;      // saved value of locked chilled water mass flow rate [kg/s]
    2009        20349 :         Real64 MdotLockC = 0.0;      // saved value of locked hot water mass flow rate [kg/s]
    2010        20349 :         bool ColdFlowLocked = false; // if true cold water flow is locked
    2011        20349 :         bool HotFlowLocked = false;  // if true Hot water flow is locked
    2012              : 
    2013              :         // select capacity control method
    2014        20349 :         switch (fanCoil.CapCtrlMeth_Num) {
    2015           14 :         case CCM::ConsFanVarFlow: {
    2016              : 
    2017           14 :             if (AirMassFlow < HVAC::SmallMassFlow) {
    2018            0 :                 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           14 :             mdot = 0.0;
    2024           14 :             PlantUtilities::SetComponentFlowRate(
    2025           14 :                 state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2026           14 :             if (state.dataPlnt->PlantLoop(fanCoil.CoolCoilPlantLoc.loopNum).LoopSide(fanCoil.CoolCoilPlantLoc.loopSideNum).FlowLock ==
    2027              :                 DataPlant::FlowLock::Locked) {
    2028            2 :                 ColdFlowLocked = true; // check for flow lock
    2029              :             }
    2030           14 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    2031           12 :                 mdot = 0.0;
    2032           12 :                 PlantUtilities::SetComponentFlowRate(
    2033           12 :                     state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2034           12 :                 if (state.dataPlnt->PlantLoop(fanCoil.HeatCoilPlantLoc.loopNum).LoopSide(fanCoil.HeatCoilPlantLoc.loopSideNum).FlowLock ==
    2035              :                     DataPlant::FlowLock::Locked) {
    2036            3 :                     HotFlowLocked = true; // save locked flow
    2037              :                 }
    2038              :             }
    2039              :             // obtain unit output with no active heating/cooling
    2040           14 :             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutNoHC, 0.0);
    2041              : 
    2042           14 :             if (ColdFlowLocked || HotFlowLocked) {
    2043            5 :                 QUnitOutNoHC = fanCoil.QUnitOutNoHC;
    2044              :             } else { // continue to update QUnitOutNoHC while flow is unlocked
    2045            9 :                 fanCoil.QUnitOutNoHC = QUnitOutNoHC;
    2046              :             }
    2047              : 
    2048              :             // then calculate the loads at the coils
    2049           14 :             QCoilHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP - QUnitOutNoHC;
    2050           14 :             QCoilCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP - QUnitOutNoHC;
    2051              : 
    2052              :             // if cooling
    2053           19 :             if (UnitOn && QCoilCoolSP < -HVAC::SmallLoad &&
    2054            5 :                 state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleHeat) {
    2055            5 :                 int ControlNode = fanCoil.CoolCoilFluidInletNode;
    2056            5 :                 ControlOffset = fanCoil.ColdControlOffset;
    2057            5 :                 MaxWaterFlow = fanCoil.MaxCoolCoilFluidFlow;
    2058            5 :                 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            5 :                 if (!FirstHVACIteration) {
    2062            3 :                     MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
    2063            3 :                     MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
    2064              :                 }
    2065              :                 // get full load result
    2066            5 :                 mdot = MaxWaterFlow;
    2067            5 :                 PlantUtilities::SetComponentFlowRate(
    2068            5 :                     state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2069            5 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMaxC);
    2070            5 :                 if (!ColdFlowLocked) {
    2071            3 :                     fanCoil.QUnitOutMaxC = QUnitOutMaxC;
    2072              :                 } else {
    2073            2 :                     QUnitOutMaxC = fanCoil.QUnitOutMaxC;
    2074            2 :                     MdotLockC = mdot; // save locked flow
    2075              :                 }
    2076            5 :                 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
    2077            5 :                 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           51 :                     auto f = [&state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq](Real64 const CWFlow) {
    2081           48 :                         return CalcFanCoilCWLoadResidual(state, CWFlow, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq);
    2082            3 :                     };
    2083            3 :                     General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, CWFlow, f, 0.0, MaxWaterFlow);
    2084            3 :                     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            3 :                     } 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            2 :                     CWFlow = MaxWaterFlow;
    2143              :                 }
    2144            5 :                 if (!ColdFlowLocked) {
    2145            3 :                     mdot = CWFlow; // not flowlocked - set flow to CWFlow
    2146            3 :                     PlantUtilities::SetComponentFlowRate(
    2147            3 :                         state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2148            3 :                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); // get QUnitOut
    2149              :                 } else {
    2150              :                     // flow lock on
    2151            2 :                     if (MdotLockC > CWFlow) { // if mdot > CWFlow, bypass extra flow
    2152            1 :                         Calc4PipeFanCoil(state,
    2153              :                                          FanCoilNum,
    2154              :                                          ControlledZoneNum,
    2155              :                                          FirstHVACIteration,
    2156              :                                          QUnitOut); // get QUnitOut with CWFlow; rest will be bypassed
    2157            1 :                         state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate =
    2158              :                             MdotLockC; // reset flow to locked value. Since lock is on, must do this by hand
    2159            1 :                         state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).MassFlowRate = MdotLockC;
    2160              :                         // Keep soln flow rate but reset outlet water temperature - i.e. bypass extra water
    2161            1 :                         CWFlowBypass = MdotLockC - CWFlow;
    2162              :                         // change water outlet temperature and enthalpy
    2163            1 :                         state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).Temp =
    2164            1 :                             (CWFlowBypass * state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).Temp +
    2165            1 :                              CWFlow * state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).Temp) /
    2166              :                             MdotLockC;
    2167            1 :                         state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).Enthalpy =
    2168            1 :                             (CWFlowBypass * state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).Enthalpy +
    2169            1 :                              CWFlow * state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).Enthalpy) /
    2170              :                             MdotLockC;
    2171              :                     } else {
    2172              :                         // if MdotLockC <= CWFlow use MdotLockC as is
    2173            1 :                         state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate =
    2174              :                             MdotLockC; // reset flow to locked value. Since lock is on, must do this by hand
    2175            1 :                         state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).MassFlowRate = MdotLockC;
    2176            1 :                         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    2177              :                     }
    2178              :                 }
    2179            5 :                 QUnitOut = calcZoneSensibleOutput(AirMassFlow,
    2180            5 :                                                   state.dataLoopNodes->Node(OutletNode).Temp,
    2181            5 :                                                   state.dataLoopNodes->Node(InletNode).Temp,
    2182            5 :                                                   state.dataLoopNodes->Node(InletNode).HumRat);
    2183              : 
    2184              :                 // if heating
    2185           18 :             } else if (UnitOn && QCoilHeatSP > HVAC::SmallLoad &&
    2186            9 :                        state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleCool) {
    2187              :                 // get full load result
    2188            9 :                 if (fanCoil.HCoilType_Num == HCoil::Water) { // if HW Coil
    2189            7 :                     int ControlNode = fanCoil.HeatCoilFluidInletNode;
    2190            7 :                     ControlOffset = fanCoil.HotControlOffset;
    2191            7 :                     MaxWaterFlow = fanCoil.MaxHeatCoilFluidFlow;
    2192            7 :                     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            7 :                     if (!FirstHVACIteration) {
    2196            6 :                         MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
    2197            6 :                         MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
    2198              :                     }
    2199            7 :                     mdot = MaxWaterFlow;
    2200            7 :                     PlantUtilities::SetComponentFlowRate(
    2201            7 :                         state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2202            7 :                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMaxH);
    2203            7 :                     if (!HotFlowLocked) {
    2204            4 :                         fanCoil.QUnitOutMaxH = QUnitOutMaxH;
    2205              :                     } else {
    2206            3 :                         QUnitOutMaxH = fanCoil.QUnitOutMaxH;
    2207            3 :                         MdotLockH = mdot; // save locked flow
    2208              :                     }
    2209              :                 } else {
    2210              :                     // not HW coil
    2211            2 :                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMaxH, 1.0);
    2212              :                 }
    2213            9 :                 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
    2214            9 :                 if (QUnitOutMaxH > QZnReq) {
    2215              :                     // more heating than required, find reduced water flow rate to meet the load
    2216            7 :                     if (fanCoil.HCoilType_Num == HCoil::Water) {
    2217              :                         // solve for the hot water flow rate with no limit set by flow rate lockdown
    2218          102 :                         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           96 :                             state.dataLoopNodes->Node(state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatCoilFluidInletNode).MassFlowRate = HWFlow;
    2222           96 :                             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, 1.0);
    2223              :                             // Calculate residual based on output magnitude
    2224           96 :                             if (std::abs(QZnReq) <= 100.0) {
    2225           12 :                                 return (QUnitOut - QZnReq) / 100.0;
    2226              :                             } else {
    2227           84 :                                 return (QUnitOut - QZnReq) / QZnReq;
    2228              :                             }
    2229            6 :                         };
    2230            6 :                         General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, HWFlow, f, 0.0, MaxWaterFlow);
    2231            6 :                         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            6 :                         } 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            4 :                         auto f = [&state, FirstHVACIteration, FanCoilNum, ControlledZoneNum, QZnReq](Real64 const PartLoadRatio) {
    2289            3 :                             return CalcFanCoilLoadResidual(state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq, PartLoadRatio);
    2290            1 :                         };
    2291            1 :                         General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, 0.0, 1.0);
    2292              :                     }
    2293              :                 } else {
    2294              :                     // demand greater than capacity
    2295            2 :                     if (fanCoil.HCoilType_Num == HCoil::Water) {
    2296            1 :                         HWFlow = MaxWaterFlow;
    2297              :                     } else {
    2298            1 :                         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, 1.0);
    2299              :                     }
    2300              :                 }
    2301            9 :                 if (fanCoil.HCoilType_Num == HCoil::Water) {
    2302            7 :                     if (!HotFlowLocked) {
    2303            4 :                         mdot = HWFlow; // not flowlocked - set flow to HWFlow
    2304            4 :                         PlantUtilities::SetComponentFlowRate(
    2305            4 :                             state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2306            4 :                         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); // get QUnitOut
    2307              :                     } else {
    2308              :                         // flow lock on
    2309            3 :                         if (MdotLockH > HWFlow) { // if mdot > HWFlow, bypass extra flow
    2310            1 :                             Calc4PipeFanCoil(state,
    2311              :                                              FanCoilNum,
    2312              :                                              ControlledZoneNum,
    2313              :                                              FirstHVACIteration,
    2314              :                                              QUnitOut); // get QUnitOut with HWFlow; rest will be bypassed
    2315            1 :                             state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).MassFlowRate =
    2316              :                                 MdotLockH; // reset flow to locked value. Since lock is on, must do this by hand
    2317            1 :                             state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).MassFlowRate = MdotLockH;
    2318              :                             // Keep soln flow rate but reset outlet water temperature - i.e. bypass extra water
    2319            1 :                             HWFlowBypass = MdotLockH - HWFlow;
    2320              :                             // change outlet water temperature and enthalpy
    2321            1 :                             state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).Temp =
    2322            1 :                                 (HWFlowBypass * state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).Temp +
    2323            1 :                                  HWFlow * state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).Temp) /
    2324              :                                 MdotLockH;
    2325            1 :                             state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).Enthalpy =
    2326            1 :                                 (HWFlowBypass * state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).Enthalpy +
    2327            1 :                                  HWFlow * state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).Enthalpy) /
    2328              :                                 MdotLockH;
    2329              :                         } else {
    2330              :                             // if MdotLockH <= HWFlow use MdotLockH as is
    2331            2 :                             state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).MassFlowRate =
    2332              :                                 MdotLockH; // reset flow to locked value. Since lock is on, must do this by hand
    2333            2 :                             state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).MassFlowRate = MdotLockH;
    2334            2 :                             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    2335              :                         }
    2336              :                     }
    2337              :                 }
    2338            9 :                 QUnitOut = calcZoneSensibleOutput(AirMassFlow,
    2339            9 :                                                   state.dataLoopNodes->Node(OutletNode).Temp,
    2340            9 :                                                   state.dataLoopNodes->Node(InletNode).Temp,
    2341            9 :                                                   state.dataLoopNodes->Node(InletNode).HumRat);
    2342              :             } else {
    2343              :                 // no action
    2344            0 :                 QUnitOut = QUnitOutNoHC;
    2345              :             }
    2346              : 
    2347              :             // CR9155 Remove specific humidity calculations
    2348           14 :             SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
    2349           14 :             SpecHumIn = state.dataLoopNodes->Node(InletNode).HumRat;
    2350           14 :             LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
    2351           14 :             QTotUnitOut = AirMassFlow * (state.dataLoopNodes->Node(OutletNode).Enthalpy - state.dataLoopNodes->Node(InletNode).Enthalpy);
    2352              :             // report variables
    2353           14 :             fanCoil.HeatPower = max(0.0, QUnitOut);
    2354           14 :             fanCoil.SensCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QUnitOut));
    2355           14 :             fanCoil.TotCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QTotUnitOut));
    2356           14 :             fanCoil.ElecPower = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    2357              : 
    2358           14 :             PowerMet = QUnitOut;
    2359           14 :             LatOutputProvided = LatentOutput;
    2360              : 
    2361              :             // cycling fan constant water flow AND VarFanVarFlow
    2362           14 :         } break;
    2363        20316 :         case CCM::CycFan:
    2364              :         case CCM::VarFanVarFlow: {
    2365              : 
    2366        20316 :             if (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ControlledZoneNum) || AirMassFlow < HVAC::SmallMassFlow) {
    2367         7250 :                 UnitOn = false;
    2368              :             }
    2369              : 
    2370              :             // zero the hot & cold water flows
    2371        20316 :             mdot = 0.0;
    2372        20316 :             PlantUtilities::SetComponentFlowRate(
    2373        20316 :                 state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2374        20316 :             if (state.dataPlnt->PlantLoop(fanCoil.CoolCoilPlantLoc.loopNum).LoopSide(fanCoil.CoolCoilPlantLoc.loopSideNum).FlowLock ==
    2375              :                 DataPlant::FlowLock::Locked) {
    2376            0 :                 ColdFlowLocked = true; // check for flow lock
    2377              :             }
    2378        20316 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    2379        20316 :                 mdot = 0.0;
    2380        20316 :                 PlantUtilities::SetComponentFlowRate(
    2381        20316 :                     state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2382        20316 :                 if (state.dataPlnt->PlantLoop(fanCoil.HeatCoilPlantLoc.loopNum).LoopSide(fanCoil.HeatCoilPlantLoc.loopSideNum).FlowLock ==
    2383              :                     DataPlant::FlowLock::Locked) {
    2384            0 :                     HotFlowLocked = true; // save locked flow
    2385              :                 }
    2386              :             }
    2387              : 
    2388              :             // obtain unit output with no active heating/cooling
    2389        20316 :             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutNoHC, 0.0);
    2390              : 
    2391              :             // get the loads at the coil
    2392        20316 :             QCoilHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP - QUnitOutNoHC;
    2393        20316 :             QCoilCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP - QUnitOutNoHC;
    2394              : 
    2395              :             // speed fan selection only for multispeed cycling fan
    2396        20316 :             if (UnitOn && (fanCoil.CapCtrlMeth_Num == CCM::CycFan)) {
    2397        13063 :                 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputRequired;
    2398              : 
    2399              :                 // set water side mass flow rate
    2400        13063 :                 if (QCoilCoolSP < 0) {
    2401         5962 :                     state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate = fanCoil.MaxCoolCoilFluidFlow;
    2402         7101 :                 } else if (QCoilHeatSP > 0 && fanCoil.HCoilType_Num != HCoil::Electric) {
    2403         7101 :                     state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).MassFlowRate = fanCoil.MaxHeatCoilFluidFlow;
    2404              :                 }
    2405              : 
    2406        13063 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    2407        13063 :                 fanCoil.SpeedFanSel = 1;
    2408        13063 :                 fanCoil.SpeedFanRatSel = fanCoil.LowSpeedRatio;
    2409        13063 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
    2410        13063 :                 if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
    2411        10734 :                     state.dataLoopNodes->Node(InletNode).MassFlowRateMax = fanCoil.MedSpeedRatio * fanCoil.MaxAirMassFlow;
    2412        10734 :                     fanCoil.SpeedFanSel = 2;
    2413        10734 :                     fanCoil.SpeedFanRatSel = fanCoil.MedSpeedRatio;
    2414        10734 :                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
    2415              :                 }
    2416        17587 :                 if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
    2417         4524 :                     fanCoil.SpeedFanSel = 3;
    2418         4524 :                     fanCoil.SpeedFanRatSel = 1.0;
    2419         4524 :                     state.dataLoopNodes->Node(InletNode).MassFlowRateMax = fanCoil.MaxAirMassFlow;
    2420              :                 }
    2421              :             } else {
    2422         7253 :                 fanCoil.SpeedFanSel = 0;
    2423              :             }
    2424              : 
    2425              :             // meet the coil load adjusted for fan operation
    2426        26279 :             if (UnitOn && QCoilCoolSP < (-1.0 * HVAC::SmallLoad) &&
    2427         5963 :                 state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleHeat) {
    2428              :                 // cooling coil action, maximum cold water flow
    2429         5963 :                 mdot = fanCoil.MaxCoolCoilFluidFlow;
    2430         5963 :                 PlantUtilities::SetComponentFlowRate(
    2431         5963 :                     state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2432              : 
    2433         5963 :                 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
    2434         5963 :                 ControlOffset = fanCoil.ColdControlOffset;
    2435              : 
    2436              :                 // get the maximum output of the fcu
    2437         5963 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax); // call without PLR means PLR = 1
    2438              : 
    2439         5963 :                 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        32446 :                     auto f = [&state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq](Real64 const PLR) {
    2443        79449 :                         return CalcFanCoilPLRResidual(state,
    2444              :                                                       PLR,
    2445              :                                                       FanCoilNum,
    2446              :                                                       FirstHVACIteration,
    2447              :                                                       ControlledZoneNum,
    2448        26483 :                                                       state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode,
    2449        26483 :                                                       QZnReq);
    2450         5963 :                     };
    2451         5963 :                     General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, 0.0, 1.0);
    2452         5963 :                     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         5963 :                     } 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         5963 :                     mdot = PLR * fanCoil.MaxCoolCoilFluidFlow;
    2508         5963 :                     PlantUtilities::SetComponentFlowRate(
    2509         5963 :                         state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2510              :                 } else {
    2511            0 :                     PLR = 1.0;
    2512            0 :                     mdot = PLR * fanCoil.MaxCoolCoilFluidFlow;
    2513            0 :                     PlantUtilities::SetComponentFlowRate(
    2514            0 :                         state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2515              :                 }
    2516              : 
    2517              :                 // at the end calculate output
    2518         5963 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2519              : 
    2520        21456 :             } else if (UnitOn && QCoilHeatSP > HVAC::SmallLoad &&
    2521         7103 :                        state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleCool) {
    2522              :                 // heating coil action, maximun hot water flow
    2523              : 
    2524         7103 :                 if (fanCoil.HCoilType_Num == HCoil::Water) {
    2525         7103 :                     mdot = fanCoil.MaxHeatCoilFluidFlow;
    2526         7103 :                     PlantUtilities::SetComponentFlowRate(
    2527         7103 :                         state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2528              :                 }
    2529              : 
    2530         7103 :                 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
    2531         7103 :                 ControlOffset = fanCoil.HotControlOffset;
    2532              : 
    2533              :                 // get the maximum output of the fcu
    2534         7103 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
    2535              :                 // calculate the PLR, if load greater than output, PLR = 1 (output = max)
    2536         7103 :                 if (QUnitOutMax > QZnReq) {
    2537              :                     // more heating than required, find reduced water flow rate to meet the load
    2538         5817 :                     if (fanCoil.HCoilType_Num == HCoil::Water) {
    2539              :                         // solve for the hot water flow rate with no limit set by flow rate lockdown
    2540        32216 :                         auto f = [&state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq](Real64 const PLR) {
    2541        79197 :                             return CalcFanCoilPLRResidual(state,
    2542              :                                                           PLR,
    2543              :                                                           FanCoilNum,
    2544              :                                                           FirstHVACIteration,
    2545              :                                                           ControlledZoneNum,
    2546        26399 :                                                           state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatCoilFluidInletNode,
    2547        26399 :                                                           QZnReq);
    2548         5817 :                         };
    2549         5817 :                         General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, 0.0, 1.0);
    2550         5817 :                         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         5817 :                         } 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         5817 :                         HWFlow = PLR * fanCoil.MaxHeatCoilFluidFlow;
    2610         5817 :                         PlantUtilities::SetComponentFlowRate(
    2611         5817 :                             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         1286 :                     PLR = 1.0;
    2621         1286 :                     if (fanCoil.HCoilType_Num == HCoil::Water) {
    2622         1286 :                         mdot = PLR * fanCoil.MaxHeatCoilFluidFlow;
    2623         1286 :                         PlantUtilities::SetComponentFlowRate(
    2624         1286 :                             state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2625              :                     }
    2626              :                 }
    2627              : 
    2628              :                 // at the end calculate output with adjusted PLR
    2629         7103 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2630              : 
    2631              :             } else {
    2632              :                 // no action, zero the air flow rate, the unit is off
    2633         7250 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
    2634         7250 :                 state.dataLoopNodes->Node(OutletNode).MassFlowRate = 0.0;
    2635         7250 :                 fanCoil.SpeedFanSel = 0;
    2636         7250 :                 PLR = 0.0;
    2637         7250 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2638              :             }
    2639              : 
    2640        20316 :             AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    2641              :             // CR9155 Remove specific humidity calculations
    2642        20316 :             SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
    2643        20316 :             SpecHumIn = state.dataLoopNodes->Node(InletNode).HumRat;
    2644        20316 :             LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
    2645        20316 :             QTotUnitOut = AirMassFlow * (state.dataLoopNodes->Node(OutletNode).Enthalpy - state.dataLoopNodes->Node(InletNode).Enthalpy);
    2646              :             // report variables
    2647        20316 :             fanCoil.HeatPower = max(0.0, QUnitOut);
    2648        20316 :             fanCoil.SensCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QUnitOut));
    2649        20316 :             fanCoil.TotCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QTotUnitOut));
    2650        20316 :             fanCoil.ElecPower = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    2651              : 
    2652        20316 :             fanCoil.PLR = PLR;
    2653        20316 :             PowerMet = QUnitOut;
    2654        20316 :             LatOutputProvided = LatentOutput;
    2655              : 
    2656        20316 :         } break;
    2657           10 :         case CCM::ASHRAE: {
    2658              : 
    2659           10 :             if (AirMassFlow < HVAC::SmallMassFlow) {
    2660            0 :                 UnitOn = false;
    2661              :             }
    2662              : 
    2663              :             //  zero the hot & cold water flows
    2664           10 :             mdot = 0.0;
    2665           10 :             PlantUtilities::SetComponentFlowRate(
    2666           10 :                 state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2667              : 
    2668           10 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    2669            7 :                 mdot = 0.0;
    2670            7 :                 PlantUtilities::SetComponentFlowRate(
    2671            7 :                     state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2672              :             }
    2673              : 
    2674           10 :             OAMassFlow = 0.0;
    2675              : 
    2676              :             // determine minimum outdoor air flow rate
    2677           10 :             if (fanCoil.DSOAPtr > 0 && fanCoil.OutsideAirNode > 0) {
    2678            0 :                 OAVolumeFlowRate = DataSizing::calcDesignSpecificationOutdoorAir(state, fanCoil.DSOAPtr, ControlledZoneNum, true, true);
    2679            0 :                 RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state,
    2680            0 :                                                            state.dataLoopNodes->Node(fanCoil.OutsideAirNode).Press,
    2681            0 :                                                            state.dataLoopNodes->Node(fanCoil.OutsideAirNode).Temp,
    2682            0 :                                                            state.dataLoopNodes->Node(fanCoil.OutsideAirNode).HumRat);
    2683            0 :                 OAMassFlow = OAVolumeFlowRate * RhoAir;
    2684              :             }
    2685              : 
    2686           10 :             MinSAMassFlowRate = min(max(OAMassFlow, fanCoil.MaxAirMassFlow * fanCoil.LowSpeedRatio), fanCoil.MaxAirMassFlow);
    2687           10 :             MaxSAMassFlowRate = fanCoil.MaxAirMassFlow;
    2688           10 :             state.dataFanCoilUnits->HeatingLoad = false;
    2689           10 :             state.dataFanCoilUnits->CoolingLoad = false;
    2690           10 :             if (UnitOn) {
    2691           10 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = MinSAMassFlowRate;
    2692           10 :                 fanCoil.MaxNoCoolHeatAirMassFlow = MinSAMassFlowRate;
    2693           10 :                 fanCoil.MaxCoolAirMassFlow = MaxSAMassFlowRate;
    2694           10 :                 fanCoil.MaxHeatAirMassFlow = MaxSAMassFlowRate;
    2695           10 :                 fanCoil.LowSpeedCoolFanRatio = MinSAMassFlowRate / MaxSAMassFlowRate;
    2696           10 :                 fanCoil.LowSpeedHeatFanRatio = MinSAMassFlowRate / MaxSAMassFlowRate;
    2697              : 
    2698           10 :                 Calc4PipeFanCoil(state,
    2699              :                                  FanCoilNum,
    2700              :                                  ControlledZoneNum,
    2701              :                                  FirstHVACIteration,
    2702              :                                  QUnitOutNoHC,
    2703           10 :                                  0.0); // needs PLR=0 for electric heating coil, otherwise will run at full capacity
    2704              : 
    2705           10 :                 QCoilCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
    2706           10 :                 QCoilHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
    2707              : 
    2708           15 :                 if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0 &&
    2709            5 :                     state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleCool) {
    2710            5 :                     QZnReq = QCoilHeatSP;
    2711            5 :                     state.dataFanCoilUnits->HeatingLoad = true;
    2712            5 :                 } else if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0 &&
    2713            0 :                            state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) == HVAC::SetptType::SingleCool) {
    2714            0 :                     QZnReq = 0.0;
    2715            9 :                 } else if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0 &&
    2716            4 :                            state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleHeat) {
    2717            4 :                     QZnReq = QCoilCoolSP;
    2718            4 :                     state.dataFanCoilUnits->CoolingLoad = true;
    2719            1 :                 } else if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0 &&
    2720            0 :                            state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) == HVAC::SetptType::SingleHeat) {
    2721            0 :                     QZnReq = 0.0;
    2722            1 :                 } else if (QCoilHeatSP <= 0.0 && QCoilCoolSP >= 0.0) {
    2723            1 :                     QZnReq = 0.0;
    2724              :                 }
    2725              :             }
    2726              : 
    2727           10 :             if (state.dataFanCoilUnits->CoolingLoad) {
    2728              : 
    2729            4 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = MaxSAMassFlowRate;
    2730              : 
    2731            4 :                 mdot = fanCoil.MaxCoolCoilFluidFlow;
    2732            4 :                 PlantUtilities::SetComponentFlowRate(
    2733            4 :                     state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    2734              : 
    2735            6 :             } else if (state.dataFanCoilUnits->HeatingLoad) {
    2736              : 
    2737            5 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = MaxSAMassFlowRate;
    2738              : 
    2739            5 :                 if (fanCoil.HCoilType_Num == HCoil::Water) {
    2740            3 :                     mdot = fanCoil.MaxHeatCoilFluidFlow;
    2741            3 :                     PlantUtilities::SetComponentFlowRate(
    2742            3 :                         state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    2743              :                 }
    2744              :             }
    2745              : 
    2746           10 :             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
    2747              : 
    2748           10 :             if ((state.dataFanCoilUnits->CoolingLoad && QUnitOutMax < QZnReq) || (state.dataFanCoilUnits->HeatingLoad && QUnitOutMax > QZnReq)) {
    2749           16 :                 if ((state.dataFanCoilUnits->CoolingLoad && QUnitOutNoHC < QZnReq) ||
    2750            8 :                     (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            8 :                     Real64 OnOffAirFlowRatio = 1.0;
    2766            8 :                     bool HXUnitOn = false;
    2767            8 :                     int AirLoopNum = 0;
    2768            8 :                     HVAC::CompressorOp CompressorOnFlag = HVAC::CompressorOp::Off;
    2769            8 :                     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           24 :                     SZVAVModel::calcSZVAVModel(state,
    2773              :                                                SZVAVModel,
    2774              :                                                FanCoilNum,
    2775              :                                                FirstHVACIteration,
    2776            8 :                                                state.dataFanCoilUnits->CoolingLoad,
    2777            8 :                                                state.dataFanCoilUnits->HeatingLoad,
    2778              :                                                QZnReq,
    2779              :                                                OnOffAirFlowRatio,
    2780              :                                                HXUnitOn,
    2781              :                                                AirLoopNum,
    2782              :                                                PLR,
    2783              :                                                CompressorOnFlag);
    2784              :                 }
    2785            4 :             } else if ((state.dataFanCoilUnits->CoolingLoad && QUnitOutMax > QZnReq && QZnReq < 0.0) ||
    2786            2 :                        (state.dataFanCoilUnits->HeatingLoad && QUnitOutMax < QZnReq && QZnReq > 0.0)) {
    2787              :                 // load is larger than capacity, thus run the fancoil unit at full capacity
    2788            1 :                 PLR = 1.0;
    2789              :             }
    2790           10 :             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
    2791           10 :             PowerMet = QUnitOut;
    2792           10 :             AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    2793              :             // CR9155 Remove specific humidity calculations
    2794           10 :             SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
    2795           10 :             SpecHumIn = state.dataLoopNodes->Node(InletNode).HumRat;
    2796              :             // Latent rate (kg/s), dehumid = negative
    2797           10 :             LatOutputProvided = AirMassFlow * (SpecHumOut - SpecHumIn);
    2798           10 :             fanCoil.PLR = PLR;
    2799              : 
    2800              :             // cycling fan constant water flow AND VarFanVarFlow
    2801           10 :         } 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            9 :         case CCM::MultiSpeedFan: {
    2977              :             // call multi-speed fan staging calculation
    2978            9 :             SimMultiStage4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    2979            9 :             AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    2980            9 :             SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
    2981            9 :             SpecHumIn = state.dataLoopNodes->Node(InletNode).HumRat;
    2982            9 :             LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
    2983           36 :             QSensUnitOutNoATM = calcZoneSensibleOutput(AirMassFlow,
    2984            9 :                                                        state.dataLoopNodes->Node(OutletNode).Temp,
    2985            9 :                                                        state.dataLoopNodes->Node(InletNode).Temp,
    2986            9 :                                                        state.dataLoopNodes->Node(InletNode).HumRat);
    2987            9 :             QTotUnitOut = AirMassFlow * (state.dataLoopNodes->Node(OutletNode).Enthalpy - state.dataLoopNodes->Node(InletNode).Enthalpy);
    2988              :             // report variables
    2989            9 :             fanCoil.HeatPower = max(0.0, QSensUnitOutNoATM);
    2990            9 :             fanCoil.SensCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QSensUnitOutNoATM));
    2991            9 :             fanCoil.TotCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QTotUnitOut));
    2992            9 :             fanCoil.ElecPower = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    2993              : 
    2994            9 :             PowerMet = QUnitOut;
    2995            9 :             LatOutputProvided = LatentOutput;
    2996            9 :         } break;
    2997            0 :         default:
    2998            0 :             break;
    2999              :         }
    3000        20349 :     }
    3001              : 
    3002            7 :     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            7 :         mdot = MaxWaterFlow * 0.1;
    3028            7 :         state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
    3029            7 :         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    3030            7 :         if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3031            5 :             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            5 :             mdot *= 0.1;
    3034            5 :             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
    3035            5 :             Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    3036            5 :             if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3037            4 :                 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            4 :                 mdot *= 0.1;
    3040            4 :                 state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
    3041            4 :                 Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    3042            4 :                 if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3043            3 :                     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            3 :                     mdot *= 0.1;
    3046            3 :                     state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
    3047            3 :                     Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    3048            3 :                     if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3049            2 :                         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            2 :                         mdot *= 0.1;
    3053            2 :                         state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
    3054            2 :                         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
    3055            2 :                         if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
    3056            1 :                             MaxWaterFlow = mdot;
    3057              :                         } else {
    3058            1 :                             MinWaterFlow = mdot;
    3059              :                         }
    3060              :                     } else {
    3061            1 :                         MinWaterFlow = mdot;
    3062              :                     }
    3063              :                 } else {
    3064            1 :                     MinWaterFlow = mdot;
    3065              :                 }
    3066              :             } else {
    3067            1 :                 MinWaterFlow = mdot;
    3068              :             }
    3069              :         } else {
    3070            2 :             MinWaterFlow = mdot;
    3071              :         }
    3072            7 :     }
    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       130805 :     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       130805 :         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       130805 :         auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum);
    3198              : 
    3199              :         // if PLR present in arguments, get its value, else default PLR = 1
    3200       130805 :         if (present(PLR)) {
    3201        93809 :             PartLoad = PLR;
    3202              :         } else {
    3203        36996 :             PartLoad = 1.0;
    3204              :         }
    3205              : 
    3206       130805 :         int OutletNode = fanCoil.AirOutNode;
    3207       130805 :         int InletNode = fanCoil.AirInNode;
    3208       130805 :         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       261605 :         if (((fanCoil.availSched->getCurrentVal() > 0.0 && fanCoil.fanAvailSched->getCurrentVal() > 0.0) || state.dataHVACGlobal->TurnFansOn) &&
    3213       130800 :             !state.dataHVACGlobal->TurnFansOff) {
    3214       130800 :             if (fanCoil.CapCtrlMeth_Num != CCM::ConsFanVarFlow) {
    3215       130615 :                 if (fanCoil.CapCtrlMeth_Num != CCM::ASHRAE) {
    3216       130490 :                     state.dataLoopNodes->Node(InletNode).MassFlowRate = PartLoad * state.dataLoopNodes->Node(InletNode).MassFlowRateMax;
    3217              :                 }
    3218              :             } else {
    3219          185 :                 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       130805 :         OASchedValue = (fanCoil.oaSched != nullptr) ? fanCoil.oaSched->getCurrentVal() : 1.0;
    3225              : 
    3226       130805 :         if (fanCoil.ATMixerExists) {
    3227           22 :             state.dataFanCoilUnits->ATMixOutNode = fanCoil.ATMixerOutNode;
    3228           22 :             if (fanCoil.ATMixerType == HVAC::MixerType::InletSide) {
    3229              :                 // set the primary air inlet mass flow rate
    3230           22 :                 state.dataLoopNodes->Node(fanCoil.ATMixerPriNode).MassFlowRate =
    3231           22 :                     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           22 :                 SingleDuct::SimATMixer(state, fanCoil.ATMixerName, FirstHVACIteration, fanCoil.ATMixerIndex);
    3235              :             }
    3236           22 :             AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    3237              :         } else {
    3238              :             // OutdoorAir:Mixer
    3239       130783 :             if (fanCoil.CapCtrlMeth_Num == CCM::CycFan) {
    3240       130355 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRate =
    3241       130355 :                     min(OASchedValue * state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMax * PartLoad * fanCoil.SpeedFanRatSel,
    3242       130355 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate);
    3243          428 :             } else if (fanCoil.CapCtrlMeth_Num == CCM::MultiSpeedFan) {
    3244          115 :                 state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRate =
    3245          115 :                     min(OASchedValue * state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMax * PartLoad *
    3246          115 :                             state.dataFanCoilUnits->FanFlowRatio,
    3247          115 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate);
    3248              :             } else {
    3249          313 :                 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          313 :                     state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRate =
    3255          313 :                         min(OASchedValue * state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRateMax,
    3256          313 :                             state.dataLoopNodes->Node(InletNode).MassFlowRate);
    3257              :                 }
    3258              :             }
    3259       130783 :             state.dataLoopNodes->Node(fanCoil.AirReliefNode).MassFlowRate = state.dataLoopNodes->Node(fanCoil.OutsideAirNode).MassFlowRate;
    3260       130783 :             AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    3261       130783 :             MixedAir::SimOAMixer(state, fanCoil.OAMixName, fanCoil.OAMixIndex);
    3262              :         }
    3263              : 
    3264       130805 :         if (fanCoil.CapCtrlMeth_Num == CCM::CycFan) {
    3265              :             // cycling fan coil unit calculation
    3266       130355 :             if (fanCoil.SpeedFanSel == 1) {
    3267        31420 :                 state.dataFans->fans(fanCoil.FanIndex)->simulate(state, FirstHVACIteration, fanCoil.LowSpeedRatio);
    3268        98935 :             } else if (fanCoil.SpeedFanSel == 2) {
    3269        57722 :                 state.dataFans->fans(fanCoil.FanIndex)->simulate(state, FirstHVACIteration, fanCoil.MedSpeedRatio);
    3270        41213 :             } else if (fanCoil.SpeedFanSel == 3) {
    3271        26710 :                 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        14503 :                 state.dataFans->fans(fanCoil.FanIndex)->simulate(state, FirstHVACIteration, 0.0, _, 0.0);
    3274              :             }
    3275       130355 :             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       521420 :                 WaterCoils::SimulateWaterCoilComponents(
    3280       391065 :                     state, fanCoil.CCoilName, FirstHVACIteration, fanCoil.CCoilName_Index, _, HVAC::FanOp::Cycling, PLR);
    3281              :             }
    3282       130355 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    3283       521420 :                 WaterCoils::SimulateWaterCoilComponents(
    3284       391065 :                     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          450 :         } else if (fanCoil.CapCtrlMeth_Num == CCM::MultiSpeedFan) {
    3301          115 :             if (fanCoil.fanType != HVAC::FanType::SystemModel) {
    3302           47 :                 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           68 :                 Real64 ActFanFlowRatio = state.dataFanCoilUnits->FanFlowRatio * PartLoad;
    3306           68 :                 state.dataFans->fans(fanCoil.FanIndex)->simulate(state, FirstHVACIteration, _, _, ActFanFlowRatio);
    3307              :             }
    3308          115 :             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          460 :                 WaterCoils::SimulateWaterCoilComponents(
    3313          345 :                     state, fanCoil.CCoilName, FirstHVACIteration, fanCoil.CCoilName_Index, _, HVAC::FanOp::Cycling, PLR);
    3314              :             }
    3315          115 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    3316          188 :                 WaterCoils::SimulateWaterCoilComponents(
    3317          141 :                     state, fanCoil.HCoilName, FirstHVACIteration, fanCoil.HCoilName_Index, _, HVAC::FanOp::Cycling, PLR);
    3318              :             } else {
    3319           68 :                 if (state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate > 0.0) {
    3320            0 :                     ElecHeaterControl = 0.0;
    3321              :                 }
    3322           68 :                 Real64 QZnReq = 0.0;
    3323           68 :                 if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3324           41 :                     QZnReq = fanCoil.DesignHeatingCapacity * state.dataFanCoilUnits->FanFlowRatio * eHeatCoilCyclingR * ElecHeaterControl;
    3325              :                 } else {
    3326              :                     // proportionally reduce the full flow capacity based on fan flow fraction
    3327           27 :                     QZnReq = fanCoil.DesignHeatingCapacity * state.dataFanCoilUnits->FanFlowRatio * PartLoad * eHeatCoilCyclingR * ElecHeaterControl;
    3328              :                 }
    3329          272 :                 HeatingCoils::SimulateHeatingCoilComponents(state,
    3330              :                                                             fanCoil.HCoilName,
    3331              :                                                             FirstHVACIteration,
    3332              :                                                             QZnReq,
    3333           68 :                                                             fanCoil.HCoilName_Index,
    3334              :                                                             _,
    3335          136 :                                                             false,
    3336           68 :                                                             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          335 :             FanSpeedRatio = state.dataLoopNodes->Node(InletNode).MassFlowRate / (fanCoil.FanAirVolFlow * state.dataEnvrn->StdRhoAir);
    3344              : 
    3345              :             // Constant fan and variable flow calculation AND variable fan
    3346              : 
    3347          335 :             state.dataFans->fans(fanCoil.FanIndex)->simulate(state, FirstHVACIteration, FanSpeedRatio, _, FanSpeedRatio);
    3348              : 
    3349          335 :             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          335 :                 WaterCoils::SimulateWaterCoilComponents(state, fanCoil.CCoilName, FirstHVACIteration, fanCoil.CCoilName_Index);
    3354              :             }
    3355          335 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    3356          295 :                 WaterCoils::SimulateWaterCoilComponents(state, fanCoil.HCoilName, FirstHVACIteration, fanCoil.HCoilName_Index);
    3357              :             } else {
    3358           40 :                 if (state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate > 0.0) {
    3359            0 :                     ElecHeaterControl = 0.0;
    3360              :                 }
    3361          200 :                 HeatingCoils::SimulateHeatingCoilComponents(state,
    3362              :                                                             fanCoil.HCoilName,
    3363              :                                                             FirstHVACIteration,
    3364           80 :                                                             fanCoil.DesignHeatingCapacity * PartLoad * ElecHeaterControl,
    3365           40 :                                                             fanCoil.HCoilName_Index,
    3366              :                                                             _,
    3367           80 :                                                             false,
    3368           80 :                                                             HVAC::FanOp::Continuous,
    3369              :                                                             PartLoad);
    3370              :             }
    3371              :         }
    3372              : 
    3373       130805 :         if (fanCoil.ATMixerExists) {
    3374           22 :             if (fanCoil.ATMixerType == HVAC::MixerType::SupplySide) {
    3375              :                 // Now calculate the ATM mixer if it is on the supply side of the zone unit
    3376            0 :                 SingleDuct::SimATMixer(state, fanCoil.ATMixerName, FirstHVACIteration, fanCoil.ATMixerIndex);
    3377            0 :                 LoadMet = calcZoneSensibleOutput(state.dataLoopNodes->Node(state.dataFanCoilUnits->ATMixOutNode).MassFlowRate,
    3378            0 :                                                  state.dataLoopNodes->Node(state.dataFanCoilUnits->ATMixOutNode).Temp,
    3379            0 :                                                  state.dataLoopNodes->Node(state.dataFanCoilUnits->ZoneNode).Temp,
    3380            0 :                                                  state.dataLoopNodes->Node(state.dataFanCoilUnits->ZoneNode).HumRat);
    3381              :             } else {
    3382              :                 // ATM Mixer on inlet side
    3383           22 :                 LoadMet = calcZoneSensibleOutput(AirMassFlow,
    3384           22 :                                                  state.dataLoopNodes->Node(OutletNode).Temp,
    3385           22 :                                                  state.dataLoopNodes->Node(state.dataFanCoilUnits->ZoneNode).Temp,
    3386           22 :                                                  state.dataLoopNodes->Node(state.dataFanCoilUnits->ZoneNode).HumRat);
    3387              :             }
    3388              :         } else {
    3389       130783 :             LoadMet = calcZoneSensibleOutput(AirMassFlow,
    3390       130783 :                                              state.dataLoopNodes->Node(OutletNode).Temp,
    3391       130783 :                                              state.dataLoopNodes->Node(InletNode).Temp,
    3392       130783 :                                              state.dataLoopNodes->Node(InletNode).HumRat);
    3393              :         }
    3394       130805 :     }
    3395              : 
    3396            9 :     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            9 :         auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum);
    3420            9 :         auto &HeatingLoad = state.dataFanCoilUnits->HeatingLoad;
    3421            9 :         auto &CoolingLoad = state.dataFanCoilUnits->CoolingLoad;
    3422              : 
    3423              :         // initialize local variables
    3424            9 :         bool UnitOn = true;         // TRUE if unit is on
    3425            9 :         Real64 SpeedRatio = 0.0;    // ratio between lower and higher fan speed
    3426            9 :         Real64 PartLoadRatio = 0.0; // Part Load Ratio, fraction of time step fancoil is on
    3427            9 :         Real64 QZnReq = 0.0;        // heating or cooling needed by zone [watts]
    3428            9 :         Real64 QUnitOut = 0.0;      // heating or sens. cooling provided by fan coil unit [watts]
    3429            9 :         Real64 QUnitOutMax = 0.0;   // heating or sens. cooling provided by fan coil unit (running during an entire timestep)
    3430            9 :         Real64 QUnitOutNoHC = 0.0;  // unit output with no active heating or cooling [W]
    3431              : 
    3432            9 :         int OutletNode = fanCoil.AirOutNode;
    3433            9 :         int InletNode = fanCoil.AirInNode;
    3434            9 :         Real64 AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    3435              : 
    3436            9 :         if (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum) || AirMassFlow < HVAC::SmallMassFlow) {
    3437            0 :             UnitOn = false;
    3438              :         }
    3439              : 
    3440            9 :         fanCoil.SpeedFanSel = 1;
    3441            9 :         fanCoil.SpeedFanRatSel = fanCoil.LowSpeedRatio;
    3442            9 :         state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3443            9 :         AirMassFlow = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3444            9 :         state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3445            9 :         state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3446            9 :         state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3447            9 :         state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
    3448              : 
    3449            9 :         if (fanCoil.HCoilType_Num == HCoil::Water) {
    3450            0 :             mdot = 0.0;
    3451            0 :             PlantUtilities::SetComponentFlowRate(
    3452            0 :                 state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    3453              :         }
    3454            9 :         mdot = 0.0;
    3455            9 :         PlantUtilities::SetComponentFlowRate(
    3456            9 :             state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    3457              :         // no load output, requires setting eHeatCoilCyclingR = 0.0, for electric heating coils
    3458            9 :         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutNoHC, _, 0.0);
    3459              : 
    3460            9 :         Real64 QCoilCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToCoolSP;
    3461            9 :         Real64 QCoilHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP;
    3462            9 :         state.dataFanCoilUnits->HeatingLoad = false;
    3463            9 :         state.dataFanCoilUnits->CoolingLoad = false;
    3464              : 
    3465            9 :         if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0 && state.dataHeatBalFanSys->TempControlType(ZoneNum) != HVAC::SetptType::SingleCool) {
    3466            9 :             QZnReq = QCoilHeatSP;
    3467            9 :             HeatingLoad = true;
    3468            0 :         } else if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0 && state.dataHeatBalFanSys->TempControlType(ZoneNum) == HVAC::SetptType::SingleCool) {
    3469            0 :             QZnReq = 0.0;
    3470            0 :         } else if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0 && state.dataHeatBalFanSys->TempControlType(ZoneNum) != HVAC::SetptType::SingleHeat) {
    3471            0 :             QZnReq = QCoilCoolSP;
    3472            0 :             CoolingLoad = true;
    3473            0 :         } else if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0 && state.dataHeatBalFanSys->TempControlType(ZoneNum) == HVAC::SetptType::SingleHeat) {
    3474            0 :             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            9 :         if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3481            5 :             switch (state.dataHeatBalFanSys->TempControlType(ZoneNum)) {
    3482            0 :             case HVAC::SetptType::SingleHeat: {
    3483            0 :                 CoolingLoad = false;
    3484              :                 // No heating load and constant fan pushes zone below heating set point
    3485            0 :                 if (QUnitOutNoHC < 0.0 && QCoilHeatSP < 0.0 && QUnitOutNoHC - QCoilHeatSP < -HVAC::SmallLoad) {
    3486            0 :                     HeatingLoad = true;
    3487            0 :                     CoolingLoad = false;
    3488            0 :                     QZnReq = QCoilHeatSP;
    3489              :                 }
    3490            0 :             } break;
    3491            0 :             case HVAC::SetptType::SingleCool: {
    3492            0 :                 HeatingLoad = false;
    3493              :                 // No heating load and constant fan pushes zone above cooling set point
    3494            0 :                 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            0 :             } 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            5 :             case HVAC::SetptType::DualHeatCool: {
    3520              :                 // zone temp above cooling and heating set point temps
    3521            5 :                 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            5 :                 } else if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0) {
    3536              :                     // zone pushed into deadband
    3537            5 :                     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            5 :                     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            5 :             } break;
    3563            0 :             default:
    3564            0 :                 break;
    3565              :             }
    3566              :             // IF small loads to meet, just shut down unit
    3567            5 :             if (std::abs(QZnReq) < FanCoilUnits::Small5WLoad) {
    3568            0 :                 QZnReq = 0.0;
    3569            0 :                 CoolingLoad = false;
    3570            0 :                 HeatingLoad = false;
    3571              :             }
    3572              :         }
    3573              : 
    3574            9 :         if (UnitOn && QZnReq < (-1.0 * FanCoilUnits::Small5WLoad) && CoolingLoad) {
    3575            0 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    3576            0 :                 mdot = 0.0;
    3577            0 :                 PlantUtilities::SetComponentFlowRate(
    3578            0 :                     state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    3579              :             }
    3580            0 :             mdot = fanCoil.MaxCoolCoilFluidFlow;
    3581            0 :             PlantUtilities::SetComponentFlowRate(
    3582            0 :                 state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    3583              :             // select fan speed
    3584            0 :             fanCoil.SpeedFanSel = 1;
    3585            0 :             fanCoil.SpeedFanRatSel = fanCoil.LowSpeedRatio;
    3586            0 :             state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3587            0 :             AirMassFlow = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3588            0 :             state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3589            0 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3590            0 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3591            0 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
    3592            0 :             Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
    3593            0 :             if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
    3594            0 :                 fanCoil.SpeedFanSel = 2;
    3595            0 :                 fanCoil.SpeedFanRatSel = fanCoil.MedSpeedRatio;
    3596            0 :                 state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3597            0 :                 AirMassFlow = fanCoil.MedSpeedRatio * fanCoil.MaxAirMassFlow;
    3598            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3599            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3600            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3601            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3602            0 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
    3603              :             }
    3604            0 :             if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
    3605            0 :                 fanCoil.SpeedFanSel = 3;
    3606            0 :                 fanCoil.SpeedFanRatSel = 1.0;
    3607            0 :                 state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3608            0 :                 AirMassFlow = fanCoil.MaxAirMassFlow;
    3609            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3610            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3611            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3612            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = fanCoil.MedSpeedRatio * fanCoil.MaxAirMassFlow;
    3613              :             }
    3614            0 :             CalcMultiStage4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QZnReq, SpeedRatio, PartLoadRatio, QUnitOut);
    3615              : 
    3616            9 :         } else if (UnitOn && QZnReq > FanCoilUnits::Small5WLoad && HeatingLoad) {
    3617              : 
    3618            9 :             mdot = 0.0;
    3619            9 :             PlantUtilities::SetComponentFlowRate(
    3620            9 :                 state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    3621              : 
    3622            9 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    3623            0 :                 mdot = fanCoil.MaxHeatCoilFluidFlow;
    3624            0 :                 PlantUtilities::SetComponentFlowRate(
    3625            0 :                     state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    3626              :             }
    3627              :             // select fan speed
    3628            9 :             fanCoil.SpeedFanSel = 1;
    3629            9 :             fanCoil.SpeedFanRatSel = fanCoil.LowSpeedRatio;
    3630            9 :             state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3631            9 :             AirMassFlow = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3632            9 :             state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3633            9 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3634            9 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3635            9 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
    3636            9 :             Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
    3637            9 :             if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
    3638            6 :                 fanCoil.SpeedFanSel = 2;
    3639            6 :                 fanCoil.SpeedFanRatSel = fanCoil.MedSpeedRatio;
    3640            6 :                 state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3641            6 :                 AirMassFlow = fanCoil.MedSpeedRatio * fanCoil.MaxAirMassFlow;
    3642            6 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3643            6 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3644            6 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3645            6 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3646            6 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
    3647              :             }
    3648            9 :             if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
    3649            4 :                 fanCoil.SpeedFanSel = 3;
    3650            4 :                 fanCoil.SpeedFanRatSel = 1.0;
    3651            4 :                 state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3652            4 :                 AirMassFlow = fanCoil.MaxAirMassFlow;
    3653            4 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3654            4 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3655            4 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3656            4 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = fanCoil.MedSpeedRatio * fanCoil.MaxAirMassFlow;
    3657              :             }
    3658              : 
    3659            9 :             CalcMultiStage4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QZnReq, SpeedRatio, PartLoadRatio, QUnitOut);
    3660              : 
    3661              :         } else {
    3662              :             // SpeedRatio = 0.0;
    3663            0 :             if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3664            0 :                 PartLoadRatio = 1.0;
    3665            0 :                 fanCoil.SpeedFanSel = 1;
    3666            0 :                 fanCoil.SpeedFanRatSel = fanCoil.LowSpeedRatio;
    3667            0 :                 state.dataFanCoilUnits->FanFlowRatio = fanCoil.SpeedFanRatSel;
    3668            0 :                 AirMassFlow = fanCoil.LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3669            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3670            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3671            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3672            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
    3673              :             } else {
    3674            0 :                 PartLoadRatio = 0.0;
    3675            0 :                 AirMassFlow = 0.0;
    3676            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
    3677            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
    3678            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    3679            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
    3680            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
    3681            0 :                 state.dataLoopNodes->Node(OutletNode).MassFlowRate = 0.0;
    3682            0 :                 fanCoil.SpeedFanSel = 0;
    3683            0 :                 state.dataFanCoilUnits->FanFlowRatio = 0.0;
    3684              :             }
    3685              : 
    3686            0 :             mdot = 0.0;
    3687            0 :             if (fanCoil.HCoilType_Num == HCoil::Water) {
    3688            0 :                 PlantUtilities::SetComponentFlowRate(
    3689            0 :                     state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    3690              :             }
    3691            0 :             PlantUtilities::SetComponentFlowRate(
    3692            0 :                 state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    3693              :             // No load output, eHeatCoilCyclingR = 0.0 for electric heating coil
    3694            0 :             Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PartLoadRatio, 0.0);
    3695              :         }
    3696              :         // output variable
    3697            9 :         state.dataLoopNodes->Node(OutletNode).MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    3698            9 :         fanCoil.PLR = PartLoadRatio;
    3699            9 :         fanCoil.SpeedRatio = SpeedRatio;
    3700            9 :         PowerMet = QUnitOut;
    3701            9 :     }
    3702              : 
    3703           11 :     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           11 :         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           11 :         auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum);
    3740              : 
    3741              :         // initialize local variables
    3742           11 :         Real64 mdot = 0.0;                                 // chilled or hot water flow rate through the water coils
    3743           11 :         Real64 PLR = 1.0;                                  // Part Load Ratio, fraction of time step fancoil is on
    3744           11 :         Real64 SRatio = 0.0;                               // capacity speed ratio of the for multi-stage fan fancoil unit
    3745           11 :         Real64 QUnitOut = 0.0;                             // heating or sens. cooling provided by fan coil unit [watts]
    3746           11 :         Real64 QUnitOutMax = 0.0;                          // max heating or sens. cooling provided by fan coil unit [watts]
    3747           11 :         Real64 ControlOffset = 0.0;                        // tolerance for output control
    3748           11 :         Real64 FanElecPowerHS = 0.0;                       // fan electric power calculated at (fan) higher speed
    3749           11 :         Real64 FanElecPowerLS = 0.0;                       // fan electric power calculated at (fan) lower speed
    3750           11 :         Real64 AirMassFlowAvg = 0.0;                       // supply air flow rate weighted by speed ratio
    3751           11 :         Real64 AirMassFlowLow = 0.0;                       // supply air flow rate at lower speed
    3752           11 :         Real64 AirMassFlowHigh = 0.0;                      // supply air flow rate at higher speed
    3753           11 :         Real64 AbsError = 2.0 * FanCoilUnits::Small5WLoad; // Absolute error between QZnReq and QUnitOut [W]   !FB
    3754           11 :         Real64 Error = 1.0;                                // Error between QZnReq and QUnitOut
    3755           11 :         Real64 Relax = 1.0;
    3756           11 :         int Iter = 0; // iteration counter
    3757              : 
    3758           11 :         auto &inletNode = state.dataLoopNodes->Node(fanCoil.AirInNode);
    3759              : 
    3760           11 :         if (QZnReq < (-1.0 * FanCoilUnits::Small5WLoad) && state.dataFanCoilUnits->CoolingLoad) {
    3761            1 :             ControlOffset = fanCoil.ColdControlOffset;
    3762            1 :             if (fanCoil.SpeedFanSel == 1) {
    3763            0 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
    3764            0 :                 PLR = std::abs(QZnReq / QUnitOutMax);
    3765            0 :                 if (PLR > 1.0) {
    3766            0 :                     PLR = 1.0;
    3767              :                 }
    3768              :                 // adjust the PLR to meet the cooling load by calling Calc4PipeFanCoil repeatedly
    3769            0 :                 while (std::abs(Error) > ControlOffset && std::abs(AbsError) > FanCoilUnits::Small5WLoad && Iter < MaxIterCycl && PLR != 1.0) {
    3770            0 :                     inletNode.MassFlowRateMinAvail = inletNode.MassFlowRate;
    3771            0 :                     mdot = PLR * fanCoil.MaxCoolCoilFluidFlow;
    3772            0 :                     PlantUtilities::SetComponentFlowRate(
    3773            0 :                         state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc);
    3774            0 :                     if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3775            0 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3776              :                     } else {
    3777            0 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3778              :                     }
    3779            0 :                     Error = (QZnReq - QUnitOut) / QZnReq;
    3780            0 :                     AbsError = QZnReq - QUnitOut;
    3781            0 :                     DelPLR = (QZnReq - QUnitOut) / QUnitOutMax;
    3782            0 :                     PLR += Relax * DelPLR;
    3783            0 :                     PLR = max(0.0, min(1.0, PLR));
    3784            0 :                     ++Iter;
    3785            0 :                     if (Iter == 32) {
    3786            0 :                         Relax = 0.5;
    3787              :                     }
    3788            0 :                     if (Iter == 65) {
    3789            0 :                         Relax = 0.25;
    3790              :                     }
    3791            0 :                     if (Iter > 70 && PLR == 0.0 && DelPLR < 0.0) {
    3792            0 :                         Error = 0.0;
    3793              :                     }
    3794              :                 }
    3795            0 :                 if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3796            0 :                     Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3797              :                 } else {
    3798            0 :                     Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3799              :                 }
    3800              :                 // warning if not converged
    3801            0 :                 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            1 :                 if (fanCoil.SpeedFanSel == 2) {
    3817            1 :                     HighSpeedRatio = fanCoil.MedSpeedRatio;
    3818            1 :                     LowSpeedRatio = fanCoil.LowSpeedRatio;
    3819              :                 } else {
    3820            0 :                     HighSpeedRatio = 1;
    3821            0 :                     LowSpeedRatio = fanCoil.MedSpeedRatio;
    3822              :                 }
    3823              :                 // get capacity at lower speed
    3824            1 :                 fanCoil.SpeedFanRatSel = LowSpeedRatio;
    3825            1 :                 fanCoil.SpeedFanSel = fanCoil.SpeedFanSel - 1;
    3826            1 :                 AirMassFlowLow = LowSpeedRatio * fanCoil.MaxAirMassFlow;
    3827            1 :                 inletNode.MassFlowRate = AirMassFlowLow;
    3828            1 :                 inletNode.MassFlowRateMax = AirMassFlowLow;
    3829            1 :                 inletNode.MassFlowRateMaxAvail = AirMassFlowLow;
    3830            1 :                 inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    3831            1 :                 state.dataFanCoilUnits->FanFlowRatio = LowSpeedRatio;
    3832            1 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMaxLS);
    3833            1 :                 FanElecPowerLS = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    3834              :                 // get capacity at higher speed
    3835            1 :                 fanCoil.SpeedFanRatSel = HighSpeedRatio;
    3836            1 :                 fanCoil.SpeedFanSel = fanCoil.SpeedFanSel + 1;
    3837            1 :                 AirMassFlowHigh = HighSpeedRatio * fanCoil.MaxAirMassFlow;
    3838            1 :                 inletNode.MassFlowRate = AirMassFlowHigh;
    3839            1 :                 inletNode.MassFlowRateMax = AirMassFlowHigh;
    3840            1 :                 inletNode.MassFlowRateMaxAvail = AirMassFlowHigh;
    3841            1 :                 inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    3842            1 :                 state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio;
    3843            1 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMaxHS);
    3844            1 :                 FanElecPowerHS = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    3845              :                 // calc speed ratio
    3846            1 :                 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            1 :                     SRatio = std::abs((QZnReq - QUnitOutMaxLS) / (QUnitOutMaxHS - QUnitOutMaxLS));
    3857            1 :                     if (SRatio > 1.0) {
    3858            0 :                         SRatio = 1.0;
    3859              :                     }
    3860            1 :                     AirMassFlowAvg = AirMassFlowHigh * SRatio + AirMassFlowLow * (1.0 - SRatio);
    3861            1 :                     inletNode.MassFlowRate = AirMassFlowAvg;
    3862            1 :                     inletNode.MassFlowRateMax = AirMassFlowAvg;
    3863            1 :                     inletNode.MassFlowRateMaxAvail = AirMassFlowAvg;
    3864            1 :                     inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    3865            1 :                     state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio * SRatio + LowSpeedRatio * (1.0 - SRatio);
    3866            1 :                     Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3867              :                     // adjust the PLR to meet the cooling load by calling Calc4PipeFanCoil repeatedly
    3868            4 :                     while (std::abs(Error) > ControlOffset && std::abs(AbsError) > FanCoilUnits::Small5WLoad && Iter < MaxIterCycl && SRatio != 1.0) {
    3869            3 :                         AirMassFlowAvg = AirMassFlowHigh * SRatio + AirMassFlowLow * (1.0 - SRatio);
    3870            3 :                         state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio * SRatio + LowSpeedRatio * (1.0 - SRatio);
    3871            3 :                         inletNode.MassFlowRate = AirMassFlowAvg;
    3872            3 :                         inletNode.MassFlowRateMax = AirMassFlowAvg;
    3873            3 :                         inletNode.MassFlowRateMaxAvail = AirMassFlowAvg;
    3874            3 :                         inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    3875            3 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3876            3 :                         Error = (QZnReq - QUnitOut) / QZnReq;
    3877            3 :                         AbsError = QZnReq - QUnitOut;
    3878            3 :                         DelPLR = (QZnReq - QUnitOut) / (QUnitOutMaxHS - QUnitOutMaxLS);
    3879            3 :                         SRatio += Relax * DelPLR;
    3880            3 :                         SRatio = max(0.0, min(1.0, SRatio));
    3881            3 :                         ++Iter;
    3882            3 :                         if (Iter == 32) {
    3883            0 :                             Relax = 0.5;
    3884              :                         }
    3885            3 :                         if (Iter == 65) {
    3886            0 :                             Relax = 0.25;
    3887              :                         }
    3888            3 :                         if (Iter > 70 && SRatio == 0.0 && DelPLR < 0.0) {
    3889            0 :                             Error = 0.0;
    3890              :                         }
    3891              :                     }
    3892              :                 }
    3893              :             }
    3894           10 :         } else if (QZnReq > FanCoilUnits::Small5WLoad && state.dataFanCoilUnits->HeatingLoad) {
    3895           10 :             ControlOffset = fanCoil.HotControlOffset;
    3896           10 :             if (fanCoil.SpeedFanSel == 1) {
    3897            3 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
    3898            3 :                 PLR = std::abs(QZnReq / QUnitOutMax);
    3899            3 :                 if (PLR > 1.0) {
    3900            0 :                     PLR = 1.0;
    3901              :                 }
    3902            3 :                 if (fanCoil.HCoilType_Num == HCoil::Water) {
    3903              :                     // adjust the PLR to meet the heating load by calling Calc4PipeFanCoil repeatedly
    3904            0 :                     while (std::abs(Error) > ControlOffset && std::abs(AbsError) > FanCoilUnits::Small5WLoad && Iter < MaxIterCycl && PLR != 1.0) {
    3905            0 :                         inletNode.MassFlowRateMinAvail = inletNode.MassFlowRate;
    3906            0 :                         mdot = PLR * fanCoil.MaxHeatCoilFluidFlow;
    3907            0 :                         PlantUtilities::SetComponentFlowRate(
    3908            0 :                             state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc);
    3909            0 :                         if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3910            0 :                             Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3911              :                         } else {
    3912            0 :                             Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3913              :                         }
    3914            0 :                         Error = (QZnReq - QUnitOut) / QZnReq;
    3915            0 :                         AbsError = QZnReq - QUnitOut;
    3916            0 :                         DelPLR = (QZnReq - QUnitOut) / QUnitOutMax;
    3917            0 :                         PLR += Relax * DelPLR;
    3918            0 :                         PLR = max(0.0, min(1.0, PLR));
    3919            0 :                         ++Iter;
    3920            0 :                         if (Iter == 32) {
    3921            0 :                             Relax = 0.5;
    3922              :                         }
    3923            0 :                         if (Iter == 65) {
    3924            0 :                             Relax = 0.25;
    3925              :                         }
    3926            0 :                         if (Iter > 70 && PLR == 0.0 && DelPLR < 0.0) {
    3927            0 :                             Error = 0.0; // exit loop if PLR = 0
    3928              :                         }
    3929              :                     }
    3930            0 :                     if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3931            0 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    3932              :                     } else {
    3933            0 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
    3934              :                     }
    3935              :                     // warning if not converged
    3936            0 :                     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            3 :                     Real64 eHeatCoilPLR = PLR;
    3951              :                     // electric heating coil
    3952            3 :                     if (QUnitOutMax > QZnReq) {
    3953              :                         // heating coil output is larger than required, mudulate the electric heating coil output to meet the load
    3954            3 :                         inletNode.MassFlowRateMinAvail = inletNode.MassFlowRate;
    3955              : 
    3956            3 :                         if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    3957            8 :                             auto f = [&state, FanCoilNum, FirstHVACIteration, ZoneNum, QZnReq](Real64 const CyclingR) {
    3958            6 :                                 return CalcFanCoilHeatCoilPLRResidual(state, CyclingR, FanCoilNum, FirstHVACIteration, ZoneNum, QZnReq);
    3959            2 :                             };
    3960            2 :                             General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, eHeatCoilPLR, f, 0.0, 1.0);
    3961              :                         } else {
    3962            4 :                             auto f = [&state, FirstHVACIteration, FanCoilNum, ZoneNum, QZnReq](Real64 const PartLoadRatio) {
    3963            3 :                                 return CalcFanCoilLoadResidual(state, FanCoilNum, FirstHVACIteration, ZoneNum, QZnReq, PartLoadRatio);
    3964            1 :                             };
    3965            1 :                             General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, eHeatCoilPLR, f, 0.0, 1.0);
    3966              :                         }
    3967            3 :                         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            3 :                         } 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            3 :                     PLR = eHeatCoilPLR;
    3998              :                     // at the end calculate output
    3999            3 :                     if (fanCoil.fanOp == HVAC::FanOp::Continuous) {
    4000            2 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, _, eHeatCoilPLR);
    4001              :                     } else {
    4002            1 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
    4003              :                     }
    4004              :                 }
    4005              : 
    4006              :             } else {
    4007            7 :                 if (fanCoil.SpeedFanSel == 2) {
    4008            3 :                     HighSpeedRatio = fanCoil.MedSpeedRatio;
    4009            3 :                     LowSpeedRatio = fanCoil.LowSpeedRatio;
    4010              :                 } else {
    4011            4 :                     HighSpeedRatio = 1;
    4012            4 :                     LowSpeedRatio = fanCoil.MedSpeedRatio;
    4013              :                 }
    4014              :                 // get capacity at lower speed ratio
    4015            7 :                 fanCoil.SpeedFanRatSel = LowSpeedRatio;
    4016            7 :                 fanCoil.SpeedFanSel = fanCoil.SpeedFanSel - 1;
    4017            7 :                 AirMassFlowLow = LowSpeedRatio * fanCoil.MaxAirMassFlow;
    4018            7 :                 inletNode.MassFlowRate = AirMassFlowLow;
    4019            7 :                 inletNode.MassFlowRateMax = AirMassFlowLow;
    4020            7 :                 inletNode.MassFlowRateMaxAvail = AirMassFlowLow;
    4021            7 :                 inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    4022            7 :                 state.dataFanCoilUnits->FanFlowRatio = LowSpeedRatio;
    4023            7 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMaxLS);
    4024            7 :                 FanElecPowerLS = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    4025              :                 // get capacity at higher speed
    4026            7 :                 fanCoil.SpeedFanRatSel = HighSpeedRatio;
    4027            7 :                 fanCoil.SpeedFanSel = fanCoil.SpeedFanSel + 1;
    4028            7 :                 AirMassFlowHigh = HighSpeedRatio * fanCoil.MaxAirMassFlow;
    4029            7 :                 inletNode.MassFlowRate = AirMassFlowHigh;
    4030            7 :                 inletNode.MassFlowRateMax = AirMassFlowHigh;
    4031            7 :                 inletNode.MassFlowRateMaxAvail = AirMassFlowHigh;
    4032            7 :                 inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    4033            7 :                 state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio;
    4034            7 :                 Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMaxHS);
    4035            7 :                 FanElecPowerHS = state.dataFans->fans(fanCoil.FanIndex)->totalPower;
    4036              :                 // calc speed ratio
    4037            7 :                 if (std::abs(QZnReq) > std::abs(QUnitOutMaxHS)) {
    4038            2 :                     SRatio = 1.0;
    4039            2 :                     AirMassFlowAvg = AirMassFlowHigh;
    4040            2 :                     inletNode.MassFlowRate = AirMassFlowAvg;
    4041            2 :                     inletNode.MassFlowRateMax = AirMassFlowAvg;
    4042            2 :                     inletNode.MassFlowRateMaxAvail = AirMassFlowAvg;
    4043            2 :                     inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    4044            2 :                     state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio;
    4045            2 :                     Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    4046              :                 } else {
    4047            5 :                     SRatio = std::abs((QZnReq - QUnitOutMaxLS) / (QUnitOutMaxHS - QUnitOutMaxLS));
    4048            5 :                     if (SRatio > 1.0) {
    4049            0 :                         SRatio = 1.0;
    4050              :                     }
    4051            5 :                     AirMassFlowAvg = AirMassFlowHigh * SRatio + AirMassFlowLow * (1.0 - SRatio);
    4052            5 :                     inletNode.MassFlowRate = AirMassFlowAvg;
    4053            5 :                     inletNode.MassFlowRateMax = AirMassFlowAvg;
    4054            5 :                     inletNode.MassFlowRateMaxAvail = AirMassFlowAvg;
    4055            5 :                     inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    4056            5 :                     state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio * SRatio + LowSpeedRatio * (1.0 - SRatio);
    4057            5 :                     Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    4058            5 :                     ControlOffset = fanCoil.HotControlOffset;
    4059              :                     // adjust the PLR to meet the heating load calling Calc4PipeFanCoil repeatedly
    4060           14 :                     while (std::abs(Error) > ControlOffset && std::abs(AbsError) > FanCoilUnits::Small5WLoad && Iter < MaxIterCycl && SRatio != 1.0) {
    4061            9 :                         AirMassFlowAvg = AirMassFlowHigh * SRatio + AirMassFlowLow * (1.0 - SRatio);
    4062            9 :                         inletNode.MassFlowRate = AirMassFlowAvg;
    4063            9 :                         inletNode.MassFlowRateMax = AirMassFlowAvg;
    4064            9 :                         inletNode.MassFlowRateMaxAvail = AirMassFlowAvg;
    4065            9 :                         inletNode.MassFlowRateMinAvail = AirMassFlowLow;
    4066            9 :                         state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio * SRatio + LowSpeedRatio * (1.0 - SRatio);
    4067            9 :                         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
    4068            9 :                         Error = (QZnReq - QUnitOut) / QZnReq;
    4069            9 :                         AbsError = QZnReq - QUnitOut;
    4070            9 :                         DelPLR = (QZnReq - QUnitOut) / (QUnitOutMaxHS - QUnitOutMaxLS);
    4071            9 :                         SRatio += Relax * DelPLR;
    4072            9 :                         SRatio = max(0.0, min(1.0, SRatio));
    4073            9 :                         ++Iter;
    4074            9 :                         if (Iter == 32) {
    4075            0 :                             Relax = 0.5;
    4076              :                         }
    4077            9 :                         if (Iter == 65) {
    4078            0 :                             Relax = 0.25;
    4079              :                         }
    4080            9 :                         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            7 :                 fanCoil.ElecPower = FanElecPowerHS * SRatio + FanElecPowerLS * (1.0 - SRatio);
    4087              :             }
    4088              :         }
    4089           11 :         state.dataLoopNodes->Node(fanCoil.AirOutNode).MassFlowRate = inletNode.MassFlowRate;
    4090           11 :         PartLoadRatio = PLR;
    4091           11 :         SpeedRatio = SRatio;
    4092           11 :         PowerMet = QUnitOut;
    4093           11 :     }
    4094              : 
    4095        20300 :     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        20300 :         Real64 ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
    4107              : 
    4108        20300 :         state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatEnergy = state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatPower * ReportingConstant;
    4109        20300 :         state.dataFanCoilUnits->FanCoil(FanCoilNum).SensCoolEnergy = state.dataFanCoilUnits->FanCoil(FanCoilNum).SensCoolPower * ReportingConstant;
    4110        20300 :         state.dataFanCoilUnits->FanCoil(FanCoilNum).TotCoolEnergy = state.dataFanCoilUnits->FanCoil(FanCoilNum).TotCoolPower * ReportingConstant;
    4111        20300 :         state.dataFanCoilUnits->FanCoil(FanCoilNum).ElecEnergy = state.dataFanCoilUnits->FanCoil(FanCoilNum).ElecPower * ReportingConstant;
    4112              : 
    4113        20300 :         if (state.dataFanCoilUnits->FanCoil(FanCoilNum).FirstPass) { // reset sizing flags so other zone equipment can size normally
    4114           10 :             if (!state.dataGlobal->SysSizingCalc) {
    4115            5 :                 DataSizing::resetHVACSizingGlobals(state, state.dataSize->CurZoneEqNum, 0, state.dataFanCoilUnits->FanCoil(FanCoilNum).FirstPass);
    4116              :             }
    4117              :         }
    4118        20300 :     }
    4119              : 
    4120         1201 :     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         1201 :         if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
    4131            0 :             GetFanCoilUnits(state);
    4132            0 :             state.dataFanCoilUnits->GetFanCoilInputFlag = false;
    4133              :         }
    4134              : 
    4135         1201 :         if (FanCoilNum > 0 && FanCoilNum <= state.dataFanCoilUnits->NumFanCoils) {
    4136         1201 :             return state.dataFanCoilUnits->FanCoil(FanCoilNum).AirOutNode;
    4137              :         }
    4138              : 
    4139            0 :         return 0;
    4140              :     }
    4141              : 
    4142         1201 :     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         1201 :         if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
    4153            0 :             GetFanCoilUnits(state);
    4154            0 :             state.dataFanCoilUnits->GetFanCoilInputFlag = false;
    4155              :         }
    4156              : 
    4157         1201 :         if (FanCoilNum > 0 && FanCoilNum <= state.dataFanCoilUnits->NumFanCoils) {
    4158         1201 :             return state.dataFanCoilUnits->FanCoil(FanCoilNum).OutsideAirNode;
    4159              :         }
    4160              : 
    4161            0 :         return 0;
    4162              :     }
    4163              : 
    4164         1201 :     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         1201 :         if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
    4175            0 :             GetFanCoilUnits(state);
    4176            0 :             state.dataFanCoilUnits->GetFanCoilInputFlag = false;
    4177              :         }
    4178              : 
    4179         1201 :         if (FanCoilNum > 0 && FanCoilNum <= state.dataFanCoilUnits->NumFanCoils) {
    4180         1201 :             if (state.dataFanCoilUnits->FanCoil(FanCoilNum).OAMixIndex > 0) {
    4181         1200 :                 return MixedAir::GetOAMixerReturnNodeNumber(state, state.dataFanCoilUnits->FanCoil(FanCoilNum).OAMixIndex);
    4182              :             }
    4183              :         }
    4184              : 
    4185            1 :         return 0;
    4186              :     }
    4187              : 
    4188         1201 :     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         1201 :         if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
    4199            0 :             GetFanCoilUnits(state);
    4200            0 :             state.dataFanCoilUnits->GetFanCoilInputFlag = false;
    4201              :         }
    4202              : 
    4203         1201 :         if (FanCoilNum > 0 && FanCoilNum <= state.dataFanCoilUnits->NumFanCoils) {
    4204         1201 :             if (state.dataFanCoilUnits->FanCoil(FanCoilNum).OAMixIndex > 0) {
    4205         1200 :                 return MixedAir::GetOAMixerMixedNodeNumber(state, state.dataFanCoilUnits->FanCoil(FanCoilNum).OAMixIndex);
    4206              :             }
    4207              :         }
    4208              : 
    4209            1 :         return 0;
    4210              :     }
    4211              : 
    4212           18 :     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           18 :         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           18 :         if (std::abs(QZnReq) <= 100.0) {
    4236            0 :             return (QUnitOut - QZnReq) / 100.0;
    4237              :         } else {
    4238           18 :             return (QUnitOut - QZnReq) / QZnReq;
    4239              :         }
    4240              :     }
    4241              : 
    4242        52882 :     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        52882 :         if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode) {
    4259        26483 :             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * state.dataFanCoilUnits->FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
    4260        26483 :             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        52798 :         } else if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatCoilFluidInletNode &&
    4267        26399 :                    state.dataFanCoilUnits->FanCoil(FanCoilNum).HCoilType_Num != HCoil::Electric) {
    4268        26399 :             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * state.dataFanCoilUnits->FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
    4269        26399 :             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        52882 :         if (std::abs(QZnReq) <= 100.0) {
    4281         1201 :             return (QUnitOut - QZnReq) / 100.0;
    4282              :         } else {
    4283        51681 :             return (QUnitOut - QZnReq) / QZnReq;
    4284              :         }
    4285              :     }
    4286              : 
    4287           12 :     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           12 :         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           12 :         Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR, CyclingR);
    4305              : 
    4306              :         // Calculate residual based on output magnitude
    4307           12 :         if (std::abs(QZnReq) <= 100.0) {
    4308            0 :             return (QUnitOut - QZnReq) / 100.0;
    4309              :         } else {
    4310           12 :             return (QUnitOut - QZnReq) / QZnReq;
    4311              :         }
    4312              :     }
    4313              : 
    4314           48 :     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           48 :         state.dataLoopNodes->Node(state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode).MassFlowRate = CWFlow;
    4331           48 :         Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, 1.0);
    4332              : 
    4333              :         // Calculate residual based on output magnitude
    4334           48 :         if (std::abs(QZnReq) <= 100.0) {
    4335            0 :             return (QUnitOut - QZnReq) / 100.0;
    4336              :         } else {
    4337           48 :             return (QUnitOut - QZnReq) / QZnReq;
    4338              :         }
    4339              :     }
    4340              : 
    4341           60 :     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           60 :         Real64 const mDot = PLR * maxCoilFluidFlow;
    4361           60 :         if (WaterControlNode > 0) {
    4362           60 :             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mDot;
    4363              :         }
    4364           60 :         state.dataLoopNodes->Node(AirInNode).MassFlowRate = AirMassFlowRate;
    4365              : 
    4366              :         Real64 QUnitOut;
    4367           97 :         if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode ||
    4368           37 :             (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatCoilFluidInletNode &&
    4369           37 :              state.dataFanCoilUnits->FanCoil(FanCoilNum).HCoilType_Num != HCoil::Electric)) {
    4370              : 
    4371           60 :             Calc4PipeFanCoil(state,
    4372              :                              FanCoilNum,
    4373              :                              ControlledZoneNum,
    4374              :                              FirstHVACIteration,
    4375              :                              QUnitOut,
    4376          120 :                              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           60 :         if (std::abs(QZnReq) <= 100.0) {
    4384            0 :             return (QUnitOut - QZnReq) / 100.0;
    4385              :         } else {
    4386           60 :             return (QUnitOut - QZnReq) / QZnReq;
    4387              :         }
    4388              :     }
    4389              : 
    4390            0 :     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            0 :         state.dataLoopNodes->Node(AirInNode).MassFlowRate =
    4413            0 :             state.dataFanCoilUnits->FanCoil(FanCoilNum).MaxAirMassFlow *
    4414            0 :             (state.dataFanCoilUnits->FanCoil(FanCoilNum).LowSpeedRatio + (PLR * (1.0 - state.dataFanCoilUnits->FanCoil(FanCoilNum).LowSpeedRatio)));
    4415              :         // set water flow rate
    4416            0 :         if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode) {
    4417            0 :             state.dataLoopNodes->Node(WaterControlNode).MassFlowRate =
    4418            0 :                 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            0 :         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            0 :         if (std::abs(QZnReq) <= 100.0) {
    4438            0 :             return (QUnitOut - QZnReq) / 100.0;
    4439              :         } else {
    4440            0 :             return (QUnitOut - QZnReq) / QZnReq;
    4441              :         }
    4442              :     }
    4443              : 
    4444            1 :     int getEqIndex(EnergyPlusData &state, std::string_view CompName)
    4445              :     {
    4446            1 :         if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
    4447            0 :             GetFanCoilUnits(state);
    4448            0 :             state.dataFanCoilUnits->GetFanCoilInputFlag = false;
    4449              :         }
    4450              : 
    4451            1 :         for (int FanCoilIndex = 1; FanCoilIndex <= state.dataFanCoilUnits->NumFanCoils; ++FanCoilIndex) {
    4452            1 :             auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilIndex);
    4453            1 :             if (Util::SameString(fanCoil.Name, CompName)) {
    4454            1 :                 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