LCOV - code coverage report
Current view: top level - EnergyPlus - WaterCoils.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 81.6 % 2778 2268
Test Date: 2025-05-22 16:09:37 Functions: 85.7 % 42 36

            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              : 
      54              : // EnergyPlus Headers
      55              : #include <EnergyPlus/Autosizing/All_Simple_Sizing.hh>
      56              : #include <EnergyPlus/Autosizing/CoolingAirFlowSizing.hh>
      57              : #include <EnergyPlus/Autosizing/CoolingCapacitySizing.hh>
      58              : #include <EnergyPlus/Autosizing/CoolingWaterDesAirInletHumRatSizing.hh>
      59              : #include <EnergyPlus/Autosizing/CoolingWaterDesAirInletTempSizing.hh>
      60              : #include <EnergyPlus/Autosizing/CoolingWaterDesAirOutletHumRatSizing.hh>
      61              : #include <EnergyPlus/Autosizing/CoolingWaterDesAirOutletTempSizing.hh>
      62              : #include <EnergyPlus/Autosizing/CoolingWaterDesWaterInletTempSizing.hh>
      63              : #include <EnergyPlus/Autosizing/CoolingWaterNumofTubesPerRowSizing.hh>
      64              : #include <EnergyPlus/Autosizing/CoolingWaterflowSizing.hh>
      65              : #include <EnergyPlus/Autosizing/HeatingAirFlowSizing.hh>
      66              : #include <EnergyPlus/Autosizing/HeatingAirflowUASizing.hh>
      67              : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
      68              : #include <EnergyPlus/Autosizing/HeatingWaterDesAirInletHumRatSizing.hh>
      69              : #include <EnergyPlus/Autosizing/HeatingWaterDesAirInletTempSizing.hh>
      70              : #include <EnergyPlus/Autosizing/HeatingWaterDesCoilLoadUsedForUASizing.hh>
      71              : #include <EnergyPlus/Autosizing/HeatingWaterDesCoilWaterVolFlowUsedForUASizing.hh>
      72              : #include <EnergyPlus/Autosizing/HeatingWaterflowSizing.hh>
      73              : #include <EnergyPlus/Autosizing/WaterHeatingCapacitySizing.hh>
      74              : #include <EnergyPlus/Autosizing/WaterHeatingCoilUASizing.hh>
      75              : #include <EnergyPlus/BranchNodeConnections.hh>
      76              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      77              : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
      78              : #include <EnergyPlus/DataContaminantBalance.hh>
      79              : #include <EnergyPlus/DataEnvironment.hh>
      80              : #include <EnergyPlus/DataHVACGlobals.hh>
      81              : #include <EnergyPlus/DataIPShortCuts.hh>
      82              : #include <EnergyPlus/DataLoopNode.hh>
      83              : #include <EnergyPlus/DataSizing.hh>
      84              : #include <EnergyPlus/DataWater.hh>
      85              : #include <EnergyPlus/EMSManager.hh>
      86              : #include <EnergyPlus/FaultsManager.hh>
      87              : #include <EnergyPlus/FluidProperties.hh>
      88              : #include <EnergyPlus/General.hh>
      89              : #include <EnergyPlus/GeneralRoutines.hh>
      90              : #include <EnergyPlus/GlobalNames.hh>
      91              : #include <EnergyPlus/HVACControllers.hh>
      92              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      93              : #include <EnergyPlus/NodeInputManager.hh>
      94              : #include <EnergyPlus/OutputProcessor.hh>
      95              : #include <EnergyPlus/OutputReportPredefined.hh>
      96              : #include <EnergyPlus/Plant/DataPlant.hh>
      97              : #include <EnergyPlus/PlantUtilities.hh>
      98              : #include <EnergyPlus/Psychrometrics.hh>
      99              : #include <EnergyPlus/ReportCoilSelection.hh>
     100              : #include <EnergyPlus/ScheduleManager.hh>
     101              : #include <EnergyPlus/SetPointManager.hh>
     102              : #include <EnergyPlus/SimAirServingZones.hh>
     103              : #include <EnergyPlus/UtilityRoutines.hh>
     104              : #include <EnergyPlus/WaterCoils.hh>
     105              : #include <EnergyPlus/WaterManager.hh>
     106              : 
     107              : namespace EnergyPlus::WaterCoils {
     108              : // Module containing the WaterCoil simulation routines
     109              : 
     110              : // MODULE INFORMATION:
     111              : //       AUTHOR         Richard J. Liesen
     112              : //       DATE WRITTEN   April 1998
     113              : //       MODIFIED       April 2004: Rahul Chillar
     114              : //                      Feb. 2010, Brent Griffith, Plant Demand Side Update, general fluid properties
     115              : //       RE-ENGINEERED  na
     116              : 
     117              : // PURPOSE OF THIS MODULE:
     118              : // To encapsulate the data and algorithms required to
     119              : // manage the WaterCoil System Component
     120              : 
     121              : using namespace DataLoopNode;
     122              : 
     123              : using Psychrometrics::PsyCpAirFnW;
     124              : using Psychrometrics::PsyHFnTdbRhPb;
     125              : using Psychrometrics::PsyHFnTdbW;
     126              : using Psychrometrics::PsyRhoAirFnPbTdbW;
     127              : using Psychrometrics::PsyTdbFnHW;
     128              : using Psychrometrics::PsyTdpFnWPb;
     129              : using Psychrometrics::PsyTsatFnHPb;
     130              : using Psychrometrics::PsyWFnTdbH;
     131              : using Psychrometrics::PsyWFnTdbRhPb;
     132              : using Psychrometrics::PsyWFnTdbTwbPb;
     133              : using Psychrometrics::PsyWFnTdpPb;
     134              : 
     135       320689 : void SimulateWaterCoilComponents(EnergyPlusData &state,
     136              :                                  std::string_view CompName,
     137              :                                  bool const FirstHVACIteration,
     138              :                                  int &CompIndex,
     139              :                                  ObjexxFCL::Optional<Real64> QActual,
     140              :                                  ObjexxFCL::Optional<HVAC::FanOp const> fanOpMode,
     141              :                                  ObjexxFCL::Optional<Real64 const> PartLoadRatio)
     142              : {
     143              : 
     144              :     // SUBROUTINE INFORMATION:
     145              :     //       AUTHOR         Richard Liesen
     146              :     //       DATE WRITTEN   February 1998
     147              : 
     148              :     // PURPOSE OF THIS SUBROUTINE:
     149              :     // This subroutine manages WaterCoil component simulation.
     150              : 
     151              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     152              :     int CoilNum;         // The WaterCoil that you are currently loading input into
     153              :     HVAC::FanOp fanOp;   // fan operating mode
     154              :     Real64 PartLoadFrac; // part-load fraction of heating coil
     155              : 
     156              :     // Obtains and Allocates WaterCoil related parameters from input file
     157       320689 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) { // First time subroutine has been entered
     158            0 :         GetWaterCoilInput(state);
     159            0 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
     160              :     }
     161              : 
     162              :     // Find the correct WaterCoilNumber with the Coil Name
     163       320689 :     if (CompIndex == 0) {
     164           52 :         CoilNum = Util::FindItemInList(CompName, state.dataWaterCoils->WaterCoil);
     165           52 :         if (CoilNum == 0) {
     166            0 :             ShowFatalError(state, format("SimulateWaterCoilComponents: Coil not found={}", CompName));
     167              :         }
     168           52 :         CompIndex = CoilNum;
     169              :     } else {
     170       320637 :         CoilNum = CompIndex;
     171       320637 :         if (CoilNum > state.dataWaterCoils->NumWaterCoils || CoilNum < 1) {
     172            0 :             ShowFatalError(state,
     173            0 :                            format("SimulateWaterCoilComponents: Invalid CompIndex passed={}, Number of Water Coils={}, Coil name={}",
     174              :                                   CoilNum,
     175            0 :                                   state.dataWaterCoils->NumWaterCoils,
     176              :                                   CompName));
     177              :         }
     178       320637 :         if (state.dataWaterCoils->CheckEquipName(CoilNum)) {
     179           71 :             auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
     180           71 :             if (CompName != waterCoil.Name) {
     181            0 :                 ShowFatalError(state,
     182            0 :                                format("SimulateWaterCoilComponents: Invalid CompIndex passed={}, Coil name={}, stored Coil Name for that index={}",
     183              :                                       CoilNum,
     184              :                                       CompName,
     185            0 :                                       waterCoil.Name));
     186              :             }
     187           71 :             state.dataWaterCoils->CheckEquipName(CoilNum) = false;
     188              :         }
     189              :     }
     190              : 
     191              :     // With the correct CoilNum Initialize
     192       320689 :     InitWaterCoil(state, CoilNum, FirstHVACIteration); // Initialize all WaterCoil related parameters
     193              : 
     194       320689 :     if (present(fanOpMode)) {
     195       261232 :         fanOp = fanOpMode;
     196              :     } else {
     197        59457 :         fanOp = HVAC::FanOp::Continuous;
     198              :     }
     199       320689 :     if (present(PartLoadRatio)) {
     200       187405 :         PartLoadFrac = PartLoadRatio;
     201              :     } else {
     202       133284 :         PartLoadFrac = 1.0;
     203              :     }
     204              : 
     205       320689 :     auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
     206              : 
     207              :     // Calculate the Correct WaterCoil Model with the current CoilNum
     208       320689 :     if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling) {
     209         8434 :         CalcDetailFlatFinCoolingCoil(state, CoilNum, state.dataWaterCoils->SimCalc, fanOp, PartLoadFrac);
     210         8434 :         if (present(QActual)) QActual = waterCoil.SenWaterCoolingCoilRate;
     211       312255 :     } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) {
     212       147340 :         CoolingCoil(state, CoilNum, FirstHVACIteration, state.dataWaterCoils->SimCalc, fanOp, PartLoadFrac);
     213       147340 :         if (present(QActual)) QActual = waterCoil.SenWaterCoolingCoilRate;
     214              :     }
     215              : 
     216       320689 :     if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
     217       164915 :         CalcSimpleHeatingCoil(state, CoilNum, fanOp, PartLoadFrac, state.dataWaterCoils->SimCalc);
     218       164915 :         if (present(QActual)) QActual = waterCoil.TotWaterHeatingCoilRate;
     219              :     }
     220              : 
     221              :     // Update the current WaterCoil to the outlet nodes
     222       320689 :     UpdateWaterCoil(state, CoilNum);
     223              : 
     224              :     // Report the current WaterCoil
     225       320689 :     ReportWaterCoil(state, CoilNum);
     226       320689 : }
     227              : 
     228              : // Get Input Section of the Module
     229              : //******************************************************************************
     230              : 
     231           71 : void GetWaterCoilInput(EnergyPlusData &state)
     232              : {
     233              : 
     234              :     // SUBROUTINE INFORMATION:
     235              :     //       AUTHOR         Richard Liesen
     236              :     //       DATE WRITTEN   April 1998
     237              :     //       MODIFIED       April 2004: Rahul Chillar
     238              :     //                      November 2013: Tianzhen Hong for fouling coils
     239              :     //       RE-ENGINEERED  na
     240              : 
     241              :     // PURPOSE OF THIS SUBROUTINE:
     242              :     // Obtains input data for coils and stores it in coil data structures
     243              : 
     244              :     // METHODOLOGY EMPLOYED:
     245              :     // Uses "Get" routines to read in data.
     246              : 
     247              :     // SUBROUTINE PARAMETER DEFINITIONS:
     248              :     static constexpr std::string_view RoutineName("GetWaterCoilInput: "); // include trailing blank space
     249              :     static constexpr std::string_view routineName = "GetWaterCoilInput";
     250              : 
     251              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     252              :     int CoilNum; // The WaterCoil that you are currently loading input into
     253           71 :     int NumSimpHeat(0);
     254           71 :     int NumFlatFin(0);
     255           71 :     int NumCooling(0);
     256              :     int SimpHeatNum;
     257              :     int FlatFinNum;
     258              :     int CoolingNum;
     259              :     int NumAlphas;
     260              :     int NumNums;
     261              :     int IOStat;
     262           71 :     std::string CurrentModuleObject; // for ease in getting objects
     263           71 :     Array1D_string AlphArray;        // Alpha input items for object
     264           71 :     Array1D_string cAlphaFields;     // Alpha field names
     265           71 :     Array1D_string cNumericFields;   // Numeric field names
     266           71 :     Array1D<Real64> NumArray;        // Numeric input items for object
     267           71 :     Array1D_bool lAlphaBlanks;       // Logical array, alpha field input BLANK = .TRUE.
     268           71 :     Array1D_bool lNumericBlanks;     // Logical array, numeric field input BLANK = .TRUE.
     269           71 :     int MaxNums(0);                  // Maximum number of numeric input fields
     270           71 :     int MaxAlphas(0);                // Maximum number of alpha input fields
     271           71 :     int TotalArgs(0);                // Total number of alpha and numeric arguments (max) for a certain object in the input file
     272           71 :     bool ErrorsFound(false);         // If errors detected in input
     273              : 
     274           71 :     NumSimpHeat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Heating:Water");
     275           71 :     NumFlatFin = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Cooling:Water:DetailedGeometry");
     276           71 :     NumCooling = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Cooling:Water");
     277           71 :     state.dataWaterCoils->NumWaterCoils = NumSimpHeat + NumFlatFin + NumCooling;
     278              : 
     279           71 :     if (state.dataWaterCoils->NumWaterCoils > 0) {
     280           69 :         state.dataWaterCoils->WaterCoil.allocate(state.dataWaterCoils->NumWaterCoils);
     281           69 :         state.dataWaterCoils->WaterCoilNumericFields.allocate(state.dataWaterCoils->NumWaterCoils);
     282           69 :         state.dataWaterCoils->WaterTempCoolCoilErrs.dimension(state.dataWaterCoils->NumWaterCoils, 0);
     283           69 :         state.dataWaterCoils->PartWetCoolCoilErrs.dimension(state.dataWaterCoils->NumWaterCoils, 0);
     284           69 :         state.dataWaterCoils->CheckEquipName.dimension(state.dataWaterCoils->NumWaterCoils, true);
     285              :     }
     286              : 
     287           71 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Coil:Heating:Water", TotalArgs, NumAlphas, NumNums);
     288           71 :     MaxNums = max(MaxNums, NumNums);
     289           71 :     MaxAlphas = max(MaxAlphas, NumAlphas);
     290           71 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Coil:Cooling:Water:DetailedGeometry", TotalArgs, NumAlphas, NumNums);
     291           71 :     MaxNums = max(MaxNums, NumNums);
     292           71 :     MaxAlphas = max(MaxAlphas, NumAlphas);
     293           71 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Coil:Cooling:Water", TotalArgs, NumAlphas, NumNums);
     294           71 :     MaxNums = max(MaxNums, NumNums);
     295           71 :     MaxAlphas = max(MaxAlphas, NumAlphas);
     296              : 
     297           71 :     AlphArray.allocate(MaxAlphas);
     298           71 :     cAlphaFields.allocate(MaxAlphas);
     299           71 :     cNumericFields.allocate(MaxNums);
     300           71 :     NumArray.dimension(MaxNums, 0.0);
     301           71 :     lAlphaBlanks.dimension(MaxAlphas, true);
     302           71 :     lNumericBlanks.dimension(MaxNums, true);
     303           71 :     auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
     304           71 :     CurrentModuleObject = "Coil:Heating:Water";
     305              :     // Get the data for simple heating coils
     306          121 :     for (SimpHeatNum = 1; SimpHeatNum <= NumSimpHeat; ++SimpHeatNum) {
     307              : 
     308           50 :         CoilNum = SimpHeatNum;
     309              : 
     310           50 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     311              :                                                                  CurrentModuleObject,
     312              :                                                                  SimpHeatNum,
     313              :                                                                  AlphArray,
     314              :                                                                  NumAlphas,
     315              :                                                                  NumArray,
     316              :                                                                  NumNums,
     317              :                                                                  IOStat,
     318              :                                                                  lNumericBlanks,
     319              :                                                                  lAlphaBlanks,
     320              :                                                                  cAlphaFields,
     321              :                                                                  cNumericFields);
     322              : 
     323           50 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     324              : 
     325           50 :         state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames.allocate(MaxNums);
     326           50 :         state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames = "";
     327           50 :         state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames = cNumericFields;
     328           50 :         Util::IsNameEmpty(state, AlphArray(1), cCurrentModuleObject, ErrorsFound);
     329              : 
     330              :         // ErrorsFound will be set to True if problem was found, left untouched otherwise
     331           50 :         GlobalNames::VerifyUniqueCoilName(state, CurrentModuleObject, AlphArray(1), ErrorsFound, CurrentModuleObject + " Name");
     332           50 :         auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
     333              : 
     334           50 :         waterCoil.Name = AlphArray(1);
     335           50 :         if (lAlphaBlanks(2)) {
     336            7 :             waterCoil.availSched = Sched::GetScheduleAlwaysOn(state);
     337           43 :         } else if ((waterCoil.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
     338            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(2), AlphArray(2));
     339            0 :             ErrorsFound = true;
     340              :         }
     341              : 
     342           50 :         waterCoil.WaterCoilModelA = "SIMPLE";
     343           50 :         waterCoil.WaterCoilModel = CoilModel::HeatingSimple; // 'SIMPLE'
     344           50 :         waterCoil.WaterCoilType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
     345              : 
     346           50 :         waterCoil.UACoil = NumArray(1);
     347           50 :         waterCoil.UACoilVariable = waterCoil.UACoil;
     348           50 :         waterCoil.MaxWaterVolFlowRate = NumArray(2);
     349           50 :         waterCoil.WaterInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     350           50 :                                                                           AlphArray(3),
     351              :                                                                           ErrorsFound,
     352              :                                                                           DataLoopNode::ConnectionObjectType::CoilHeatingWater,
     353           50 :                                                                           AlphArray(1),
     354              :                                                                           DataLoopNode::NodeFluidType::Water,
     355              :                                                                           DataLoopNode::ConnectionType::Inlet,
     356              :                                                                           NodeInputManager::CompFluidStream::Secondary,
     357              :                                                                           ObjectIsNotParent);
     358           50 :         waterCoil.WaterOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     359           50 :                                                                            AlphArray(4),
     360              :                                                                            ErrorsFound,
     361              :                                                                            DataLoopNode::ConnectionObjectType::CoilHeatingWater,
     362           50 :                                                                            AlphArray(1),
     363              :                                                                            DataLoopNode::NodeFluidType::Water,
     364              :                                                                            DataLoopNode::ConnectionType::Outlet,
     365              :                                                                            NodeInputManager::CompFluidStream::Secondary,
     366              :                                                                            ObjectIsNotParent);
     367           50 :         waterCoil.AirInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     368           50 :                                                                         AlphArray(5),
     369              :                                                                         ErrorsFound,
     370              :                                                                         DataLoopNode::ConnectionObjectType::CoilHeatingWater,
     371           50 :                                                                         AlphArray(1),
     372              :                                                                         DataLoopNode::NodeFluidType::Air,
     373              :                                                                         DataLoopNode::ConnectionType::Inlet,
     374              :                                                                         NodeInputManager::CompFluidStream::Primary,
     375              :                                                                         ObjectIsNotParent);
     376           50 :         waterCoil.AirOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     377           50 :                                                                          AlphArray(6),
     378              :                                                                          ErrorsFound,
     379              :                                                                          DataLoopNode::ConnectionObjectType::CoilHeatingWater,
     380           50 :                                                                          AlphArray(1),
     381              :                                                                          DataLoopNode::NodeFluidType::Air,
     382              :                                                                          DataLoopNode::ConnectionType::Outlet,
     383              :                                                                          NodeInputManager::CompFluidStream::Primary,
     384              :                                                                          ObjectIsNotParent);
     385              : 
     386           50 :         if (AlphArray(7) == "NOMINALCAPACITY") { // not "UFACTORTIMESAREAANDDESIGNWATERFLOWRATE"
     387            4 :             waterCoil.CoilPerfInpMeth = state.dataWaterCoils->NomCap;
     388              : 
     389              :         } else {
     390              :             // will be caught by input processor
     391           46 :             waterCoil.CoilPerfInpMeth = state.dataWaterCoils->UAandFlow;
     392              :         }
     393              : 
     394           50 :         waterCoil.DesTotWaterCoilLoad = NumArray(3);
     395              : 
     396           50 :         if (waterCoil.UACoil == DataSizing::AutoSize && waterCoil.CoilPerfInpMeth == state.dataWaterCoils->UAandFlow)
     397           28 :             waterCoil.RequestingAutoSize = true;
     398           50 :         if (waterCoil.MaxWaterVolFlowRate == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     399           50 :         if (waterCoil.DesTotWaterCoilLoad == DataSizing::AutoSize && waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap)
     400            2 :             waterCoil.RequestingAutoSize = true;
     401              : 
     402           50 :         waterCoil.DesInletWaterTemp = NumArray(4);
     403           50 :         waterCoil.DesInletAirTemp = NumArray(5);
     404           50 :         waterCoil.DesOutletWaterTemp = NumArray(6);
     405           50 :         waterCoil.DesOutletAirTemp = NumArray(7);
     406           50 :         waterCoil.RatioAirSideToWaterSideConvect = NumArray(8);
     407           50 :         if (!lNumericBlanks(9)) {
     408            0 :             waterCoil.DesignWaterDeltaTemp = NumArray(9);
     409            0 :             waterCoil.UseDesignWaterDeltaTemp = true;
     410              :         } else {
     411           50 :             waterCoil.UseDesignWaterDeltaTemp = false;
     412              :         }
     413           50 :         if (waterCoil.DesInletWaterTemp <= waterCoil.DesOutletWaterTemp) {
     414            0 :             ShowSevereError(state, format("For {}, {}", CurrentModuleObject, AlphArray(1)));
     415            0 :             ShowContinueError(state, format("  the {} must be greater than the {}.", cNumericFields(4), cNumericFields(6)));
     416            0 :             ErrorsFound = true;
     417              :         }
     418           50 :         if (waterCoil.DesInletAirTemp >= waterCoil.DesOutletAirTemp) {
     419            0 :             ShowSevereError(state, format("For {}, {}", CurrentModuleObject, AlphArray(1)));
     420            0 :             ShowContinueError(state, format("  the {} must be less than the {}.", cNumericFields(5), cNumericFields(7)));
     421            0 :             ErrorsFound = true;
     422              :         }
     423           50 :         if (waterCoil.DesInletAirTemp >= waterCoil.DesInletWaterTemp) {
     424            0 :             ShowSevereError(state, format("For {}, {}", CurrentModuleObject, AlphArray(1)));
     425            0 :             ShowContinueError(state, format("  the {} must be less than the {}.", cNumericFields(5), cNumericFields(4)));
     426            0 :             ErrorsFound = true;
     427              :         }
     428              : 
     429          100 :         BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(3), AlphArray(4), "Water Nodes");
     430           50 :         BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(5), AlphArray(6), "Air Nodes");
     431              : 
     432              :         // Setup the Simple Heating Coil reporting variables
     433              :         // CurrentModuleObject = "Coil:Heating:Water"
     434          100 :         SetupOutputVariable(state,
     435              :                             "Heating Coil Heating Energy",
     436              :                             Constant::Units::J,
     437           50 :                             waterCoil.TotWaterHeatingCoilEnergy,
     438              :                             OutputProcessor::TimeStepType::System,
     439              :                             OutputProcessor::StoreType::Sum,
     440           50 :                             waterCoil.Name,
     441              :                             Constant::eResource::EnergyTransfer,
     442              :                             OutputProcessor::Group::HVAC,
     443              :                             OutputProcessor::EndUseCat::HeatingCoils);
     444          100 :         SetupOutputVariable(state,
     445              :                             "Heating Coil Source Side Heat Transfer Energy",
     446              :                             Constant::Units::J,
     447           50 :                             waterCoil.TotWaterHeatingCoilEnergy,
     448              :                             OutputProcessor::TimeStepType::System,
     449              :                             OutputProcessor::StoreType::Sum,
     450           50 :                             waterCoil.Name,
     451              :                             Constant::eResource::PlantLoopHeatingDemand,
     452              :                             OutputProcessor::Group::HVAC,
     453              :                             OutputProcessor::EndUseCat::HeatingCoils);
     454          100 :         SetupOutputVariable(state,
     455              :                             "Heating Coil Heating Rate",
     456              :                             Constant::Units::W,
     457           50 :                             waterCoil.TotWaterHeatingCoilRate,
     458              :                             OutputProcessor::TimeStepType::System,
     459              :                             OutputProcessor::StoreType::Average,
     460           50 :                             waterCoil.Name);
     461          100 :         SetupOutputVariable(state,
     462              :                             "Heating Coil U Factor Times Area Value",
     463              :                             Constant::Units::W_K,
     464           50 :                             waterCoil.UACoilVariable,
     465              :                             OutputProcessor::TimeStepType::System,
     466              :                             OutputProcessor::StoreType::Average,
     467           50 :                             waterCoil.Name);
     468              :     }
     469              : 
     470           71 :     CurrentModuleObject = "Coil:Cooling:Water:DetailedGeometry";
     471              :     // Get the data for detailed cooling coils.
     472           75 :     for (FlatFinNum = 1; FlatFinNum <= NumFlatFin; ++FlatFinNum) {
     473              : 
     474            4 :         CoilNum = NumSimpHeat + FlatFinNum;
     475              : 
     476            4 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     477              :                                                                  CurrentModuleObject,
     478              :                                                                  FlatFinNum,
     479              :                                                                  AlphArray,
     480              :                                                                  NumAlphas,
     481              :                                                                  NumArray,
     482              :                                                                  NumNums,
     483              :                                                                  IOStat,
     484              :                                                                  lNumericBlanks,
     485              :                                                                  lAlphaBlanks,
     486              :                                                                  cAlphaFields,
     487              :                                                                  cNumericFields);
     488              : 
     489            4 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     490              : 
     491            4 :         state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames.allocate(MaxNums);
     492            4 :         state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames = "";
     493            4 :         state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames = cNumericFields;
     494            4 :         Util::IsNameEmpty(state, AlphArray(1), cCurrentModuleObject, ErrorsFound);
     495              : 
     496              :         // ErrorsFound will be set to True if problem was found, left untouched otherwise
     497            4 :         GlobalNames::VerifyUniqueCoilName(state, CurrentModuleObject, AlphArray(1), ErrorsFound, CurrentModuleObject + " Name");
     498              : 
     499            4 :         auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
     500            4 :         waterCoil.Name = AlphArray(1);
     501              : 
     502            4 :         if (lAlphaBlanks(2)) {
     503            3 :             waterCoil.availSched = Sched::GetScheduleAlwaysOn(state);
     504            1 :         } else if ((waterCoil.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
     505            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(2), AlphArray(2));
     506            0 :             ErrorsFound = true;
     507              :         }
     508              : 
     509            4 :         waterCoil.WaterCoilModelA = "DETAILED FLAT FIN";
     510            4 :         waterCoil.WaterCoilModel = CoilModel::CoolingDetailed; // 'DETAILED FLAT FIN'
     511            4 :         waterCoil.WaterCoilType = DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling;
     512              : 
     513            4 :         waterCoil.MaxWaterVolFlowRate = NumArray(1);
     514            4 :         if (waterCoil.MaxWaterVolFlowRate == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     515            4 :         waterCoil.TubeOutsideSurfArea = NumArray(2);
     516            4 :         if (waterCoil.TubeOutsideSurfArea == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     517            4 :         waterCoil.TotTubeInsideArea = NumArray(3);
     518            4 :         if (waterCoil.TotTubeInsideArea == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     519            4 :         waterCoil.FinSurfArea = NumArray(4);
     520            4 :         if (waterCoil.FinSurfArea == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     521            4 :         waterCoil.MinAirFlowArea = NumArray(5);
     522            4 :         if (waterCoil.MinAirFlowArea == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     523            4 :         waterCoil.CoilDepth = NumArray(6);
     524            4 :         if (waterCoil.CoilDepth == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     525            4 :         waterCoil.FinDiam = NumArray(7);
     526            4 :         if (waterCoil.FinDiam == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     527            4 :         waterCoil.FinThickness = NumArray(8);
     528            4 :         if (waterCoil.FinThickness <= 0.0) {
     529            0 :             ShowSevereError(state,
     530            0 :                             format("{}: {} must be > 0.0, for {} = {}", CurrentModuleObject, cNumericFields(8), cAlphaFields(1), waterCoil.Name));
     531            0 :             ErrorsFound = true;
     532              :         }
     533            4 :         waterCoil.TubeInsideDiam = NumArray(9);
     534            4 :         waterCoil.TubeOutsideDiam = NumArray(10);
     535            4 :         waterCoil.TubeThermConductivity = NumArray(11);
     536            4 :         if (waterCoil.TubeThermConductivity <= 0.0) {
     537            0 :             ShowSevereError(state,
     538            0 :                             format("{}: {} must be > 0.0, for {} = {}", CurrentModuleObject, cNumericFields(11), cAlphaFields(1), waterCoil.Name));
     539            0 :             ErrorsFound = true;
     540              :         }
     541            4 :         waterCoil.FinThermConductivity = NumArray(12);
     542            4 :         if (waterCoil.FinThermConductivity <= 0.0) {
     543            0 :             ShowSevereError(state,
     544            0 :                             format("{}: {} must be > 0.0, for {} = {}", CurrentModuleObject, cNumericFields(12), cAlphaFields(1), waterCoil.Name));
     545            0 :             ErrorsFound = true;
     546              :         }
     547            4 :         waterCoil.FinSpacing = NumArray(13);
     548            4 :         waterCoil.TubeDepthSpacing = NumArray(14);
     549            4 :         waterCoil.NumOfTubeRows = NumArray(15);
     550            4 :         waterCoil.NumOfTubesPerRow = NumArray(16);
     551            4 :         if (waterCoil.NumOfTubesPerRow == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     552            4 :         if (!lNumericBlanks(17)) {
     553            1 :             waterCoil.DesignWaterDeltaTemp = NumArray(17);
     554            1 :             waterCoil.UseDesignWaterDeltaTemp = true;
     555              :         } else {
     556            3 :             waterCoil.UseDesignWaterDeltaTemp = false;
     557              :         }
     558            4 :         waterCoil.WaterInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     559            4 :                                                                           AlphArray(3),
     560              :                                                                           ErrorsFound,
     561              :                                                                           DataLoopNode::ConnectionObjectType::CoilCoolingWaterDetailedGeometry,
     562            4 :                                                                           AlphArray(1),
     563              :                                                                           DataLoopNode::NodeFluidType::Water,
     564              :                                                                           DataLoopNode::ConnectionType::Inlet,
     565              :                                                                           NodeInputManager::CompFluidStream::Secondary,
     566              :                                                                           ObjectIsNotParent);
     567            4 :         waterCoil.WaterOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     568            4 :                                                                            AlphArray(4),
     569              :                                                                            ErrorsFound,
     570              :                                                                            DataLoopNode::ConnectionObjectType::CoilCoolingWaterDetailedGeometry,
     571            4 :                                                                            AlphArray(1),
     572              :                                                                            DataLoopNode::NodeFluidType::Water,
     573              :                                                                            DataLoopNode::ConnectionType::Outlet,
     574              :                                                                            NodeInputManager::CompFluidStream::Secondary,
     575              :                                                                            ObjectIsNotParent);
     576            4 :         waterCoil.AirInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     577            4 :                                                                         AlphArray(5),
     578              :                                                                         ErrorsFound,
     579              :                                                                         DataLoopNode::ConnectionObjectType::CoilCoolingWaterDetailedGeometry,
     580            4 :                                                                         AlphArray(1),
     581              :                                                                         DataLoopNode::NodeFluidType::Air,
     582              :                                                                         DataLoopNode::ConnectionType::Inlet,
     583              :                                                                         NodeInputManager::CompFluidStream::Primary,
     584              :                                                                         ObjectIsNotParent);
     585            4 :         waterCoil.AirOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     586            4 :                                                                          AlphArray(6),
     587              :                                                                          ErrorsFound,
     588              :                                                                          DataLoopNode::ConnectionObjectType::CoilCoolingWaterDetailedGeometry,
     589            4 :                                                                          AlphArray(1),
     590              :                                                                          DataLoopNode::NodeFluidType::Air,
     591              :                                                                          DataLoopNode::ConnectionType::Outlet,
     592              :                                                                          NodeInputManager::CompFluidStream::Primary,
     593              :                                                                          ObjectIsNotParent);
     594              : 
     595              :         // A7 ; \field Name of Water Storage Tank for Condensate Collection
     596            4 :         waterCoil.CondensateCollectName = AlphArray(7);
     597            4 :         if (lAlphaBlanks(7)) {
     598            4 :             waterCoil.CondensateCollectMode = state.dataWaterCoils->CondensateDiscarded;
     599              :         } else {
     600            0 :             waterCoil.CondensateCollectMode = state.dataWaterCoils->CondensateToTank;
     601            0 :             WaterManager::SetupTankSupplyComponent(state,
     602              :                                                    waterCoil.Name,
     603              :                                                    CurrentModuleObject,
     604              :                                                    waterCoil.CondensateCollectName,
     605              :                                                    ErrorsFound,
     606            0 :                                                    waterCoil.CondensateTankID,
     607            0 :                                                    waterCoil.CondensateTankSupplyARRID);
     608              :         }
     609              : 
     610            8 :         BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(3), AlphArray(4), "Water Nodes");
     611            4 :         BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(5), AlphArray(6), "Air Nodes");
     612              : 
     613              :         // Setup Report variables for the Detailed Flat Fin Cooling Coils
     614              :         // CurrentModuleObject = "Coil:Cooling:Water:DetailedGeometry"
     615            8 :         SetupOutputVariable(state,
     616              :                             "Cooling Coil Total Cooling Energy",
     617              :                             Constant::Units::J,
     618            4 :                             waterCoil.TotWaterCoolingCoilEnergy,
     619              :                             OutputProcessor::TimeStepType::System,
     620              :                             OutputProcessor::StoreType::Sum,
     621            4 :                             waterCoil.Name,
     622              :                             Constant::eResource::EnergyTransfer,
     623              :                             OutputProcessor::Group::HVAC,
     624              :                             OutputProcessor::EndUseCat::CoolingCoils);
     625            8 :         SetupOutputVariable(state,
     626              :                             "Cooling Coil Source Side Heat Transfer Energy",
     627              :                             Constant::Units::J,
     628            4 :                             waterCoil.TotWaterCoolingCoilEnergy,
     629              :                             OutputProcessor::TimeStepType::System,
     630              :                             OutputProcessor::StoreType::Sum,
     631            4 :                             waterCoil.Name,
     632              :                             Constant::eResource::PlantLoopCoolingDemand,
     633              :                             OutputProcessor::Group::HVAC,
     634              :                             OutputProcessor::EndUseCat::CoolingCoils);
     635            8 :         SetupOutputVariable(state,
     636              :                             "Cooling Coil Sensible Cooling Energy",
     637              :                             Constant::Units::J,
     638            4 :                             waterCoil.SenWaterCoolingCoilEnergy,
     639              :                             OutputProcessor::TimeStepType::System,
     640              :                             OutputProcessor::StoreType::Sum,
     641            4 :                             waterCoil.Name);
     642            8 :         SetupOutputVariable(state,
     643              :                             "Cooling Coil Total Cooling Rate",
     644              :                             Constant::Units::W,
     645            4 :                             waterCoil.TotWaterCoolingCoilRate,
     646              :                             OutputProcessor::TimeStepType::System,
     647              :                             OutputProcessor::StoreType::Average,
     648            4 :                             waterCoil.Name);
     649            8 :         SetupOutputVariable(state,
     650              :                             "Cooling Coil Sensible Cooling Rate",
     651              :                             Constant::Units::W,
     652            4 :                             waterCoil.SenWaterCoolingCoilRate,
     653              :                             OutputProcessor::TimeStepType::System,
     654              :                             OutputProcessor::StoreType::Average,
     655            4 :                             waterCoil.Name);
     656              : 
     657            4 :         if (waterCoil.CondensateCollectMode == state.dataWaterCoils->CondensateToTank) {
     658              : 
     659            0 :             SetupOutputVariable(state,
     660              :                                 "Cooling Coil Condensate Volume Flow Rate",
     661              :                                 Constant::Units::m3_s,
     662            0 :                                 waterCoil.CondensateVdot,
     663              :                                 OutputProcessor::TimeStepType::System,
     664              :                                 OutputProcessor::StoreType::Average,
     665            0 :                                 waterCoil.Name);
     666            0 :             SetupOutputVariable(state,
     667              :                                 "Cooling Coil Condensate Volume",
     668              :                                 Constant::Units::m3,
     669            0 :                                 waterCoil.CondensateVol,
     670              :                                 OutputProcessor::TimeStepType::System,
     671              :                                 OutputProcessor::StoreType::Sum,
     672            0 :                                 waterCoil.Name,
     673              :                                 Constant::eResource::OnSiteWater,
     674              :                                 OutputProcessor::Group::HVAC,
     675              :                                 OutputProcessor::EndUseCat::Condensate);
     676              :         }
     677              :     }
     678              : 
     679           71 :     CurrentModuleObject = "Coil:Cooling:Water";
     680              :     // Get the data for Cooling coils.
     681          126 :     for (CoolingNum = 1; CoolingNum <= NumCooling; ++CoolingNum) {
     682              : 
     683           55 :         CoilNum = NumSimpHeat + NumFlatFin + CoolingNum;
     684              : 
     685           55 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     686              :                                                                  CurrentModuleObject,
     687              :                                                                  CoolingNum,
     688              :                                                                  AlphArray,
     689              :                                                                  NumAlphas,
     690              :                                                                  NumArray,
     691              :                                                                  NumNums,
     692              :                                                                  IOStat,
     693              :                                                                  lNumericBlanks,
     694              :                                                                  lAlphaBlanks,
     695              :                                                                  cAlphaFields,
     696              :                                                                  cNumericFields);
     697              : 
     698           55 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     699           55 :         state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames.allocate(MaxNums);
     700           55 :         state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames = "";
     701           55 :         state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames = cNumericFields;
     702           55 :         Util::IsNameEmpty(state, AlphArray(1), cCurrentModuleObject, ErrorsFound);
     703              : 
     704              :         // ErrorsFound will be set to True if problem was found, left untouched otherwise
     705           55 :         GlobalNames::VerifyUniqueCoilName(state, CurrentModuleObject, AlphArray(1), ErrorsFound, CurrentModuleObject + " Name");
     706              : 
     707           55 :         auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
     708           55 :         waterCoil.Name = AlphArray(1);
     709              : 
     710           55 :         if (lAlphaBlanks(2)) {
     711           13 :             waterCoil.availSched = Sched::GetScheduleAlwaysOn(state);
     712           42 :         } else if ((waterCoil.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
     713            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(2), AlphArray(2));
     714            0 :             ErrorsFound = true;
     715              :         }
     716              : 
     717           55 :         waterCoil.WaterCoilModelA = "Cooling";
     718           55 :         waterCoil.WaterCoilModel = CoilModel::CoolingSimple; // 'Cooling'
     719           55 :         waterCoil.WaterCoilType = DataPlant::PlantEquipmentType::CoilWaterCooling;
     720              : 
     721           55 :         waterCoil.MaxWaterVolFlowRate = NumArray(1); // Liquid mass flow rate at Design  kg/s
     722           55 :         if (waterCoil.MaxWaterVolFlowRate == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     723           55 :         waterCoil.DesAirVolFlowRate = NumArray(2); // Dry air mass flow rate at Design (kg/s)
     724           55 :         if (waterCoil.DesAirVolFlowRate == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     725           55 :         waterCoil.DesInletWaterTemp = NumArray(3); // Entering water temperature at Design C
     726           55 :         if (waterCoil.DesInletWaterTemp == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     727           55 :         waterCoil.DesInletAirTemp = NumArray(4); // Entering air dry bulb temperature at Design(C)
     728           55 :         if (waterCoil.DesInletAirTemp == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     729           55 :         waterCoil.DesOutletAirTemp = NumArray(5); // Leaving air dry bulb temperature at Design(C)
     730           55 :         if (waterCoil.DesOutletAirTemp == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     731           55 :         waterCoil.DesInletAirHumRat = NumArray(6); // Entering air humidity ratio  at Design
     732           55 :         if (waterCoil.DesInletAirHumRat == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     733           55 :         waterCoil.DesOutletAirHumRat = NumArray(7); // Leaving air humidity ratio  at Design
     734           55 :         if (waterCoil.DesOutletAirHumRat == DataSizing::AutoSize) waterCoil.RequestingAutoSize = true;
     735           55 :         if (!lNumericBlanks(8)) {
     736            0 :             waterCoil.DesignWaterDeltaTemp = NumArray(8);
     737            0 :             waterCoil.UseDesignWaterDeltaTemp = true;
     738              :         } else {
     739           55 :             waterCoil.UseDesignWaterDeltaTemp = false;
     740              :         }
     741              : 
     742           55 :         waterCoil.WaterInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     743           55 :                                                                           AlphArray(3),
     744              :                                                                           ErrorsFound,
     745              :                                                                           DataLoopNode::ConnectionObjectType::CoilCoolingWater,
     746           55 :                                                                           AlphArray(1),
     747              :                                                                           DataLoopNode::NodeFluidType::Water,
     748              :                                                                           DataLoopNode::ConnectionType::Inlet,
     749              :                                                                           NodeInputManager::CompFluidStream::Secondary,
     750              :                                                                           ObjectIsNotParent);
     751           55 :         waterCoil.WaterOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     752           55 :                                                                            AlphArray(4),
     753              :                                                                            ErrorsFound,
     754              :                                                                            DataLoopNode::ConnectionObjectType::CoilCoolingWater,
     755           55 :                                                                            AlphArray(1),
     756              :                                                                            DataLoopNode::NodeFluidType::Water,
     757              :                                                                            DataLoopNode::ConnectionType::Outlet,
     758              :                                                                            NodeInputManager::CompFluidStream::Secondary,
     759              :                                                                            ObjectIsNotParent);
     760           55 :         waterCoil.AirInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     761           55 :                                                                         AlphArray(5),
     762              :                                                                         ErrorsFound,
     763              :                                                                         DataLoopNode::ConnectionObjectType::CoilCoolingWater,
     764           55 :                                                                         AlphArray(1),
     765              :                                                                         DataLoopNode::NodeFluidType::Air,
     766              :                                                                         DataLoopNode::ConnectionType::Inlet,
     767              :                                                                         NodeInputManager::CompFluidStream::Primary,
     768              :                                                                         ObjectIsNotParent);
     769           55 :         waterCoil.AirOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     770           55 :                                                                          AlphArray(6),
     771              :                                                                          ErrorsFound,
     772              :                                                                          DataLoopNode::ConnectionObjectType::CoilCoolingWater,
     773           55 :                                                                          AlphArray(1),
     774              :                                                                          DataLoopNode::NodeFluidType::Air,
     775              :                                                                          DataLoopNode::ConnectionType::Outlet,
     776              :                                                                          NodeInputManager::CompFluidStream::Primary,
     777              :                                                                          ObjectIsNotParent);
     778              : 
     779              :         // The default is SimpleAnalysis = 2.  and DetailedAnalysis   =1
     780           55 :         if (AlphArray(7) == "DETAILEDANALYSIS") { // not "SIMPLEANALYSIS"
     781            7 :             waterCoil.CoolingCoilAnalysisMode = state.dataWaterCoils->DetailedAnalysis;
     782              : 
     783              :         } else {
     784           48 :             waterCoil.CoolingCoilAnalysisMode = state.dataWaterCoils->SimpleAnalysis;
     785              :         }
     786              : 
     787              :         // The default is CrossFlow = 2.  and CounterFlow=1
     788           55 :         if (AlphArray(8) == "COUNTERFLOW") { // not "CROSSFLOW"
     789            0 :             waterCoil.HeatExchType = state.dataWaterCoils->CounterFlow;
     790              : 
     791              :         } else {
     792           55 :             waterCoil.HeatExchType = state.dataWaterCoils->CrossFlow;
     793              :         }
     794              : 
     795              :         // A9; \field Name of Water Storage Tank for Condensate Collection
     796           55 :         waterCoil.CondensateCollectName = AlphArray(9);
     797           55 :         if (lAlphaBlanks(9)) {
     798           55 :             waterCoil.CondensateCollectMode = state.dataWaterCoils->CondensateDiscarded;
     799              :         } else {
     800            0 :             waterCoil.CondensateCollectMode = state.dataWaterCoils->CondensateToTank;
     801            0 :             WaterManager::SetupTankSupplyComponent(state,
     802              :                                                    waterCoil.Name,
     803              :                                                    CurrentModuleObject,
     804              :                                                    waterCoil.CondensateCollectName,
     805              :                                                    ErrorsFound,
     806            0 :                                                    waterCoil.CondensateTankID,
     807            0 :                                                    waterCoil.CondensateTankSupplyARRID);
     808              :         }
     809              : 
     810          110 :         BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(3), AlphArray(4), "Water Nodes");
     811           55 :         BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(5), AlphArray(6), "Air Nodes");
     812              : 
     813              :         // Setup Report variables for the Design input Cooling Coils
     814              :         // CurrentModuleObject = "Coil:Cooling:Water"
     815          110 :         SetupOutputVariable(state,
     816              :                             "Cooling Coil Total Cooling Energy",
     817              :                             Constant::Units::J,
     818           55 :                             waterCoil.TotWaterCoolingCoilEnergy,
     819              :                             OutputProcessor::TimeStepType::System,
     820              :                             OutputProcessor::StoreType::Sum,
     821           55 :                             waterCoil.Name,
     822              :                             Constant::eResource::EnergyTransfer,
     823              :                             OutputProcessor::Group::HVAC,
     824              :                             OutputProcessor::EndUseCat::CoolingCoils);
     825          110 :         SetupOutputVariable(state,
     826              :                             "Cooling Coil Source Side Heat Transfer Energy",
     827              :                             Constant::Units::J,
     828           55 :                             waterCoil.TotWaterCoolingCoilEnergy,
     829              :                             OutputProcessor::TimeStepType::System,
     830              :                             OutputProcessor::StoreType::Sum,
     831           55 :                             waterCoil.Name,
     832              :                             Constant::eResource::PlantLoopCoolingDemand,
     833              :                             OutputProcessor::Group::HVAC,
     834              :                             OutputProcessor::EndUseCat::CoolingCoils);
     835          110 :         SetupOutputVariable(state,
     836              :                             "Cooling Coil Sensible Cooling Energy",
     837              :                             Constant::Units::J,
     838           55 :                             waterCoil.SenWaterCoolingCoilEnergy,
     839              :                             OutputProcessor::TimeStepType::System,
     840              :                             OutputProcessor::StoreType::Sum,
     841           55 :                             waterCoil.Name);
     842          110 :         SetupOutputVariable(state,
     843              :                             "Cooling Coil Total Cooling Rate",
     844              :                             Constant::Units::W,
     845           55 :                             waterCoil.TotWaterCoolingCoilRate,
     846              :                             OutputProcessor::TimeStepType::System,
     847              :                             OutputProcessor::StoreType::Average,
     848           55 :                             waterCoil.Name);
     849          110 :         SetupOutputVariable(state,
     850              :                             "Cooling Coil Sensible Cooling Rate",
     851              :                             Constant::Units::W,
     852           55 :                             waterCoil.SenWaterCoolingCoilRate,
     853              :                             OutputProcessor::TimeStepType::System,
     854              :                             OutputProcessor::StoreType::Average,
     855           55 :                             waterCoil.Name);
     856          110 :         SetupOutputVariable(state,
     857              :                             "Cooling Coil Wetted Area Fraction",
     858              :                             Constant::Units::None,
     859           55 :                             waterCoil.SurfAreaWetFraction,
     860              :                             OutputProcessor::TimeStepType::System,
     861              :                             OutputProcessor::StoreType::Average,
     862           55 :                             waterCoil.Name);
     863              : 
     864           55 :         if (waterCoil.CondensateCollectMode == state.dataWaterCoils->CondensateToTank) {
     865              : 
     866            0 :             SetupOutputVariable(state,
     867              :                                 "Cooling Coil Condensate Volume Flow Rate",
     868              :                                 Constant::Units::m3_s,
     869            0 :                                 waterCoil.CondensateVdot,
     870              :                                 OutputProcessor::TimeStepType::System,
     871              :                                 OutputProcessor::StoreType::Average,
     872            0 :                                 waterCoil.Name);
     873            0 :             SetupOutputVariable(state,
     874              :                                 "Cooling Coil Condensate Volume",
     875              :                                 Constant::Units::m3,
     876            0 :                                 waterCoil.CondensateVol,
     877              :                                 OutputProcessor::TimeStepType::System,
     878              :                                 OutputProcessor::StoreType::Sum,
     879            0 :                                 waterCoil.Name,
     880              :                                 Constant::eResource::OnSiteWater,
     881              :                                 OutputProcessor::Group::HVAC,
     882              :                                 OutputProcessor::EndUseCat::Condensate);
     883              :         }
     884              :     }
     885              : 
     886           71 :     if (ErrorsFound) {
     887            0 :         ShowFatalError(state, format("{}Errors found in getting input.", RoutineName));
     888              :     }
     889              : 
     890           71 :     AlphArray.deallocate();
     891           71 :     cAlphaFields.deallocate();
     892           71 :     cNumericFields.deallocate();
     893           71 :     NumArray.deallocate();
     894           71 :     lAlphaBlanks.deallocate();
     895           71 :     lNumericBlanks.deallocate();
     896           71 : }
     897              : 
     898       320692 : void InitWaterCoil(EnergyPlusData &state, int const CoilNum, bool const FirstHVACIteration)
     899              : {
     900              : 
     901              :     // SUBROUTINE INFORMATION:
     902              :     //       AUTHOR         Richard J. Liesen
     903              :     //       DATE WRITTEN   February 1998
     904              :     //       MODIFIED       April 2004: Rahul Chillar
     905              :     //                      November 2013: XP, Tianzhen Hong to handle fouling coils
     906              :     //       RE-ENGINEERED  na
     907              : 
     908              :     // PURPOSE OF THIS SUBROUTINE:
     909              :     // This subroutine is for initializations of the WaterCoil Components.
     910              : 
     911              :     // METHODOLOGY EMPLOYED:
     912              :     // Uses the status flags to trigger initializations.
     913              : 
     914              :     // SUBROUTINE PARAMETER DEFINITIONS:
     915       320692 :     constexpr Real64 SmallNo(1.e-9); // SmallNo number in place of zero
     916       320692 :     constexpr int itmax(10);
     917       320692 :     constexpr int MaxIte(500); // Maximum number of iterations
     918              :     static constexpr std::string_view RoutineName("InitWaterCoil");
     919              : 
     920              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     921              :     int tempCoilNum;                   // loop variable
     922              :     Real64 DesInletAirEnth;            // Entering air enthalpy at rating (J/kg)
     923              :     Real64 DesOutletAirEnth;           // Leaving air enthalpy at rating(J/kg)
     924              :     Real64 DesAirApparatusDewPtEnth;   // Air enthalpy at apparatus dew point at rating(J/kg)
     925              :     Real64 DesSatEnthAtWaterInTemp;    // Saturated enthalpy at entering liquid temp(J/kg)
     926              :     Real64 DesHumRatAtWaterInTemp;     // Enthalpy at water inlet temp and entering air HumRat (J/kg)
     927              :     Real64 CapacitanceAir;             // Air-side capacity rate(W/C)
     928              :     Real64 DesAirTempApparatusDewPt;   // Temperature apparatus dew point at design capacity
     929              :     Real64 DesAirHumRatApparatusDewPt; // Humidity Ratio at apparatus dew point at design capacity
     930              :     Real64 DesBypassFactor;            // ByPass Factor at design condition
     931              :     Real64 SlopeTempVsHumRatio;        // Ratio temperature difference to humidity difference
     932              :     // between entering and leaving air states
     933              :     Real64 TempApparatusDewPtEstimate; // Estimate of TAdp from SlopeTempVsHumRatio
     934              :     Real64 Y1;                         // Previous values of dependent variable in ITERATE
     935              :     Real64 X1;                         // Previous values of independent variable in ITERATE
     936              :     Real64 error;                      // Deviation of dependent variable in iteration
     937              :     int iter;                          // Iteration counter
     938              :     int icvg;                          // Iteration convergence flag
     939              :     Real64 ResultX;                    // Output variable from ITERATE function.
     940              :     int Ipass;                         // loop index for App_Dewpoint_Loop
     941              :     int AirInletNode;
     942              :     int WaterInletNode;
     943              :     int WaterOutletNode;
     944              :     Real64 FinDiamVar;
     945              :     Real64 TubeToFinDiamRatio;
     946              :     Real64 CpAirStd; // specific heat of air at std conditions
     947              :     int SolFla;      // Flag of solver
     948              :     Real64 UA0;      // lower bound for UA
     949              :     Real64 UA1;      // upper bound for UA
     950              :     Real64 UA;
     951              :     Real64 DesUACoilExternalEnth; // enthalpy based UAExternal for wet coil surface {kg/s}
     952              :     Real64 LogMeanEnthDiff;       // long mean enthalpy difference {J/kg}
     953              :     Real64 LogMeanTempDiff;       // long mean temperature difference {C}
     954              :     Real64 DesOutletWaterTemp;
     955              :     Real64 DesSatEnthAtWaterOutTemp;
     956              :     Real64 DesEnthAtWaterOutTempAirInHumRat;
     957              :     Real64 DesEnthWaterOut;
     958              :     Real64 Cp;  // local fluid specific heat
     959              :     Real64 rho; // local fluid density
     960              :     bool errFlag;
     961       320692 :     Real64 EnthCorrFrac(0.0); // enthalpy correction factor
     962       320692 :     Real64 TempCorrFrac(0.0); // temperature correction factor
     963              : 
     964       320692 :     if (state.dataWaterCoils->InitWaterCoilOneTimeFlag) {
     965              :         // initialize the environment and sizing flags
     966           45 :         state.dataWaterCoils->MyEnvrnFlag.allocate(state.dataWaterCoils->NumWaterCoils);
     967           45 :         state.dataWaterCoils->MySizeFlag.allocate(state.dataWaterCoils->NumWaterCoils);
     968           45 :         state.dataWaterCoils->CoilWarningOnceFlag.allocate(state.dataWaterCoils->NumWaterCoils);
     969           45 :         state.dataWaterCoils->DesCpAir.allocate(state.dataWaterCoils->NumWaterCoils);
     970           45 :         state.dataWaterCoils->MyUAAndFlowCalcFlag.allocate(state.dataWaterCoils->NumWaterCoils);
     971           45 :         state.dataWaterCoils->MyCoilDesignFlag.allocate(state.dataWaterCoils->NumWaterCoils);
     972           45 :         state.dataWaterCoils->MyCoilReportFlag.allocate(state.dataWaterCoils->NumWaterCoils);
     973           45 :         state.dataWaterCoils->DesUARangeCheck.allocate(state.dataWaterCoils->NumWaterCoils);
     974           45 :         state.dataWaterCoils->PlantLoopScanFlag.allocate(state.dataWaterCoils->NumWaterCoils);
     975              : 
     976           45 :         state.dataWaterCoils->DesCpAir = 0.0;
     977           45 :         state.dataWaterCoils->DesUARangeCheck = 0.0;
     978           45 :         state.dataWaterCoils->MyEnvrnFlag = true;
     979           45 :         state.dataWaterCoils->MySizeFlag = true;
     980           45 :         state.dataWaterCoils->CoilWarningOnceFlag = true;
     981           45 :         state.dataWaterCoils->MyUAAndFlowCalcFlag = true;
     982           45 :         state.dataWaterCoils->MyCoilDesignFlag = true;
     983           45 :         state.dataWaterCoils->MyCoilReportFlag = true;
     984           45 :         state.dataWaterCoils->InitWaterCoilOneTimeFlag = false;
     985           45 :         state.dataWaterCoils->PlantLoopScanFlag = true;
     986              : 
     987          122 :         for (tempCoilNum = 1; tempCoilNum <= state.dataWaterCoils->NumWaterCoils; ++tempCoilNum) {
     988           77 :             HVACControllers::GetControllerNameAndIndex(state,
     989           77 :                                                        state.dataWaterCoils->WaterCoil(tempCoilNum).WaterInletNodeNum,
     990           77 :                                                        state.dataWaterCoils->WaterCoil(tempCoilNum).ControllerName,
     991           77 :                                                        state.dataWaterCoils->WaterCoil(tempCoilNum).ControllerIndex,
     992              :                                                        errFlag);
     993              :         }
     994              :     }
     995              : 
     996       320692 :     if (state.dataWaterCoils->WaterCoilControllerCheckOneTimeFlag && (state.dataHVACGlobal->GetAirPathDataDone)) {
     997            9 :         bool ErrorsFound = false;
     998            9 :         bool WaterCoilOnAirLoop = true;
     999           32 :         for (tempCoilNum = 1; tempCoilNum <= state.dataWaterCoils->NumWaterCoils; ++tempCoilNum) {
    1000           23 :             if (state.dataWaterCoils->WaterCoil(tempCoilNum).ControllerIndex > 0) {
    1001           10 :                 SimAirServingZones::CompType CoilTypeNum(SimAirServingZones::CompType::Invalid);
    1002           10 :                 std::string CompType;
    1003           10 :                 std::string const &CompName = state.dataWaterCoils->WaterCoil(tempCoilNum).Name;
    1004           10 :                 if (state.dataWaterCoils->WaterCoil(tempCoilNum).WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) {
    1005            4 :                     CoilTypeNum = SimAirServingZones::CompType::WaterCoil_Cooling;
    1006            4 :                     CompType = HVAC::cAllCoilTypes(HVAC::Coil_CoolingWater);
    1007            6 :                 } else if (state.dataWaterCoils->WaterCoil(tempCoilNum).WaterCoilType ==
    1008              :                            DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling) {
    1009            1 :                     CoilTypeNum = SimAirServingZones::CompType::WaterCoil_DetailedCool;
    1010            1 :                     CompType = HVAC::cAllCoilTypes(HVAC::Coil_CoolingWaterDetailed);
    1011            5 :                 } else if (state.dataWaterCoils->WaterCoil(tempCoilNum).WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
    1012            5 :                     CoilTypeNum = SimAirServingZones::CompType::WaterCoil_SimpleHeat;
    1013            5 :                     CompType = HVAC::cAllCoilTypes(HVAC::Coil_HeatingWater);
    1014              :                 }
    1015           10 :                 WaterCoilOnAirLoop = true;
    1016           10 :                 SimAirServingZones::CheckWaterCoilIsOnAirLoop(state, CoilTypeNum, CompType, CompName, WaterCoilOnAirLoop);
    1017           10 :                 if (!WaterCoilOnAirLoop) {
    1018            0 :                     ShowContinueError(state,
    1019            0 :                                       format("Controller:WaterCoil = {}. Invalid water controller entry.",
    1020            0 :                                              state.dataWaterCoils->WaterCoil(tempCoilNum).ControllerName));
    1021            0 :                     ErrorsFound = true;
    1022              :                 }
    1023           10 :             }
    1024              :         }
    1025            9 :         state.dataWaterCoils->WaterCoilControllerCheckOneTimeFlag = false;
    1026            9 :         if (ErrorsFound) {
    1027            0 :             ShowFatalError(state, "Program terminated for previous condition.");
    1028              :         }
    1029              :     }
    1030              : 
    1031       320692 :     auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    1032       320692 :     if (state.dataWaterCoils->PlantLoopScanFlag(CoilNum) && allocated(state.dataPlnt->PlantLoop)) {
    1033           77 :         errFlag = false;
    1034           77 :         PlantUtilities::ScanPlantLoopsForObject(state, waterCoil.Name, waterCoil.WaterCoilType, waterCoil.WaterPlantLoc, errFlag, _, _, _, _, _);
    1035           77 :         if (errFlag) {
    1036            0 :             ShowFatalError(state, "InitWaterCoil: Program terminated for previous conditions.");
    1037              :         }
    1038           77 :         state.dataWaterCoils->PlantLoopScanFlag(CoilNum) = false;
    1039              :     }
    1040       320692 :     if (!state.dataGlobal->SysSizingCalc && state.dataWaterCoils->MySizeFlag(CoilNum)) {
    1041              :         // for each coil, do the sizing once.
    1042           71 :         SizeWaterCoil(state, CoilNum);
    1043              : 
    1044           71 :         state.dataWaterCoils->MySizeFlag(CoilNum) = false;
    1045              :     }
    1046              : 
    1047              :     // Do the Begin Environment initializations
    1048       320692 :     if (state.dataGlobal->BeginEnvrnFlag && state.dataWaterCoils->MyEnvrnFlag(CoilNum)) {
    1049           99 :         rho = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
    1050              :         // Initialize all report variables to a known state at beginning of simulation
    1051           99 :         waterCoil.TotWaterHeatingCoilEnergy = 0.0;
    1052           99 :         waterCoil.TotWaterCoolingCoilEnergy = 0.0;
    1053           99 :         waterCoil.SenWaterCoolingCoilEnergy = 0.0;
    1054           99 :         waterCoil.TotWaterHeatingCoilRate = 0.0;
    1055           99 :         waterCoil.TotWaterCoolingCoilRate = 0.0;
    1056           99 :         waterCoil.SenWaterCoolingCoilRate = 0.0;
    1057              : 
    1058              :         // The rest of the one time initializations
    1059           99 :         AirInletNode = waterCoil.AirInletNodeNum;
    1060           99 :         WaterInletNode = waterCoil.WaterInletNodeNum;
    1061           99 :         WaterOutletNode = waterCoil.WaterOutletNodeNum;
    1062              : 
    1063           99 :         state.dataWaterCoils->DesCpAir(CoilNum) = PsyCpAirFnW(0.0);
    1064           99 :         state.dataWaterCoils->DesUARangeCheck(CoilNum) = (-1568.6 * waterCoil.DesInletAirHumRat + 20.157);
    1065              : 
    1066           99 :         if ((waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) ||
    1067           55 :             (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling)) { // 'Cooling'
    1068           48 :             auto &waterInletNode = state.dataLoopNodes->Node(WaterInletNode);
    1069           48 :             waterInletNode.Temp = 5.0;
    1070              : 
    1071           48 :             Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, waterInletNode.Temp, RoutineName);
    1072              : 
    1073           48 :             waterInletNode.Enthalpy = Cp * waterInletNode.Temp;
    1074           48 :             waterInletNode.Quality = 0.0;
    1075           48 :             waterInletNode.Press = 0.0;
    1076           48 :             waterInletNode.HumRat = 0.0;
    1077              :         }
    1078              : 
    1079           99 :         if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) { // 'Heating'
    1080           51 :             auto &waterInletNode = state.dataLoopNodes->Node(WaterInletNode);
    1081           51 :             waterInletNode.Temp = 60.0;
    1082              : 
    1083           51 :             Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, waterInletNode.Temp, RoutineName);
    1084              : 
    1085           51 :             waterInletNode.Enthalpy = Cp * waterInletNode.Temp;
    1086           51 :             waterInletNode.Quality = 0.0;
    1087           51 :             waterInletNode.Press = 0.0;
    1088           51 :             waterInletNode.HumRat = 0.0;
    1089           51 :             state.dataWaterCoils->MyUAAndFlowCalcFlag(CoilNum) = false;
    1090              :             // fill values for variable UA
    1091           51 :             CpAirStd = PsyCpAirFnW(0.0);
    1092           51 :             waterCoil.DesAirMassFlowRate = state.dataEnvrn->StdRhoAir * waterCoil.DesAirVolFlowRate;
    1093           51 :             waterCoil.LiquidSideNominalConvect =
    1094           51 :                 waterCoil.UACoil * (waterCoil.RatioAirSideToWaterSideConvect + 1) / waterCoil.RatioAirSideToWaterSideConvect;
    1095           51 :             waterCoil.AirSideNominalConvect = waterCoil.RatioAirSideToWaterSideConvect * waterCoil.LiquidSideNominalConvect;
    1096              :         } else {
    1097           48 :             state.dataWaterCoils->MyUAAndFlowCalcFlag(CoilNum) = false;
    1098              :         }
    1099              : 
    1100           99 :         waterCoil.MaxWaterMassFlowRate = rho * waterCoil.MaxWaterVolFlowRate;
    1101              : 
    1102           99 :         PlantUtilities::InitComponentNodes(state, 0.0, waterCoil.MaxWaterMassFlowRate, waterCoil.WaterInletNodeNum, waterCoil.WaterOutletNodeNum);
    1103              : 
    1104              :         // effective fin diameter for detailed flat fin coil
    1105           99 :         if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
    1106            4 :             waterCoil.EffectiveFinDiam =
    1107            4 :                 std::sqrt(4.0 * waterCoil.FinDiam * waterCoil.CoilDepth / (Constant::Pi * waterCoil.NumOfTubeRows * waterCoil.NumOfTubesPerRow));
    1108              : 
    1109              :             //   calculate fixed geometric parameters of the coil:
    1110              :             //   Total Area
    1111            4 :             waterCoil.TotCoilOutsideSurfArea = waterCoil.TubeOutsideSurfArea + waterCoil.FinSurfArea;
    1112              :             //   Effective Tube Inside Diameter - the model assumes that the coil
    1113              :             //   can be simulated as a tube with an equivalent hydraulic diameter.
    1114            4 :             waterCoil.CoilEffectiveInsideDiam = 4.0 * waterCoil.MinAirFlowArea * waterCoil.CoilDepth / waterCoil.TotCoilOutsideSurfArea;
    1115              :             //   Ratio of tube outside diameter to effective fin diameter should always
    1116              :             //   be less than 1
    1117            4 :             TubeToFinDiamRatio = waterCoil.TubeOutsideDiam / waterCoil.EffectiveFinDiam;
    1118            4 :             if (TubeToFinDiamRatio > 1.0) {
    1119            0 :                 ShowWarningError(state, format("InitWaterCoil: Detailed Flat Fin Coil, TubetoFinDiamRatio > 1.0, [{:.4R}]", TubeToFinDiamRatio));
    1120              :                 // reset tube depth spacing and recalc dependent parameters
    1121            0 :                 waterCoil.TubeDepthSpacing *= (pow_2(TubeToFinDiamRatio) + 0.1);
    1122            0 :                 waterCoil.CoilDepth = waterCoil.TubeDepthSpacing * waterCoil.NumOfTubeRows;
    1123            0 :                 waterCoil.EffectiveFinDiam =
    1124            0 :                     std::sqrt(4.0 * waterCoil.FinDiam * waterCoil.CoilDepth / (Constant::Pi * waterCoil.NumOfTubeRows * waterCoil.NumOfTubesPerRow));
    1125            0 :                 waterCoil.CoilEffectiveInsideDiam = 4.0 * waterCoil.MinAirFlowArea * waterCoil.CoilDepth / waterCoil.TotCoilOutsideSurfArea;
    1126            0 :                 TubeToFinDiamRatio = waterCoil.TubeOutsideDiam / waterCoil.EffectiveFinDiam;
    1127            0 :                 ShowContinueError(state, format("  Resetting tube depth spacing to {:.4R} meters", waterCoil.TubeDepthSpacing));
    1128            0 :                 ShowContinueError(state, format("  Resetting coil depth to {:.4R} meters", waterCoil.CoilDepth));
    1129              :             }
    1130              : 
    1131            4 :             CalcDryFinEffCoef(state, TubeToFinDiamRatio, state.dataWaterCoils->CoefSeries);
    1132              : 
    1133            4 :             waterCoil.DryFinEfficncyCoef = state.dataWaterCoils->CoefSeries;
    1134              : 
    1135            4 :             FinDiamVar = 0.5 * (waterCoil.EffectiveFinDiam - waterCoil.TubeOutsideDiam);
    1136              : 
    1137            4 :             waterCoil.GeometryCoef1 = 0.159 * std::pow(waterCoil.FinThickness / waterCoil.CoilEffectiveInsideDiam, -0.065) *
    1138            4 :                                       std::pow(waterCoil.FinThickness / FinDiamVar, 0.141);
    1139            4 :             waterCoil.GeometryCoef2 = -0.323 * std::pow(waterCoil.FinSpacing / FinDiamVar, 0.049) *
    1140            4 :                                       std::pow(waterCoil.EffectiveFinDiam / waterCoil.TubeDepthSpacing, 0.549) *
    1141            4 :                                       std::pow(waterCoil.FinThickness / waterCoil.FinSpacing, -0.028);
    1142              : 
    1143              :             // Set some initial values for simulation
    1144            4 :             waterCoil.SatEnthlCurveConstCoef = -10.57;
    1145            4 :             waterCoil.SatEnthlCurveSlope = 3.3867;
    1146            4 :             waterCoil.EnthVsTempCurveAppxSlope = 3.3867;
    1147            4 :             waterCoil.EnthVsTempCurveConst = -10.57;
    1148              :             // Set Saved Values to Zero
    1149            4 :             waterCoil.SurfAreaWetSaved = 0.0;
    1150            4 :             waterCoil.MeanWaterTempSaved = 0.0;
    1151            4 :             waterCoil.InWaterTempSaved = 0.0;
    1152            4 :             waterCoil.OutWaterTempSaved = 0.0;
    1153              : 
    1154              :         } // End the Detailed Flat Fin Coil Initialization
    1155              : 
    1156              :         // Calculation for Cooling Coil, The part between the '@@@' are design condition
    1157              :         // and are calculated only once to calculate standard values for UAs and other physical parameters of
    1158              :         // the cooling coil.
    1159              :         // Basic Idea for UA:  Heat Transfer= UAenthalpybased*(Delta enthalpy), this is a necessity since the
    1160              :         // coil may be Wet or Dry or Partially Wet-Dry, so latent effects are accounted for in this model while
    1161              :         // calculating the UA. A fictitious specific heat is also defined to calculate the conventional UA.
    1162              :         // On the air side, enthalpy capacity rate is the air mass flow rate,while on water side it is
    1163              :         // enthalpy of saturated air at water temperature.
    1164              :         //@@@ DESIGN CONDITION BEGIN HERE @@@
    1165              : 
    1166              :         // Check for zero design cooling capacity as specified by coil design inputs
    1167          177 :         if (state.dataWaterCoils->MyCoilDesignFlag(CoilNum) && (waterCoil.WaterCoilModel == CoilModel::CoolingSimple) &&
    1168          177 :             (waterCoil.DesAirVolFlowRate > 0.0) && (waterCoil.MaxWaterMassFlowRate > 0.0)) {
    1169              : 
    1170           23 :             DesInletAirEnth = PsyHFnTdbW(waterCoil.DesInletAirTemp, waterCoil.DesInletAirHumRat);
    1171           23 :             DesOutletAirEnth = PsyHFnTdbW(waterCoil.DesOutletAirTemp, waterCoil.DesOutletAirHumRat);
    1172              :             DesSatEnthAtWaterInTemp =
    1173           23 :                 PsyHFnTdbW(waterCoil.DesInletWaterTemp, PsyWFnTdpPb(state, waterCoil.DesInletWaterTemp, state.dataEnvrn->StdBaroPress));
    1174              :             // check for dry coil
    1175           23 :             DesHumRatAtWaterInTemp = PsyWFnTdbH(state, waterCoil.DesInletWaterTemp, DesSatEnthAtWaterInTemp, RoutineName);
    1176           23 :             if (DesHumRatAtWaterInTemp > waterCoil.DesOutletAirHumRat && waterCoil.DesOutletAirTemp > waterCoil.DesInletWaterTemp) {
    1177              :                 // if the design outlet air humrat is lower than the saturated air humrat at the design inlet water temp
    1178              :                 // and the design outlet air temperature is higher than the design inlet water temp (i.e, cooling possible),
    1179              :                 // move the design outlet air saturated enthalpy down (i.e., to Twaterin, Wair,out) to allow the coil to size.
    1180            0 :                 DesSatEnthAtWaterInTemp = PsyHFnTdbW(waterCoil.DesInletWaterTemp, waterCoil.DesOutletAirHumRat) - 0.0001;
    1181              :             }
    1182           23 :             if (DesOutletAirEnth >= DesInletAirEnth || waterCoil.DesInletWaterTemp >= waterCoil.DesInletAirTemp) {
    1183            0 :                 ShowWarningError(state, format("The design cooling capacity is zero for Coil:Cooling:Water {}", waterCoil.Name));
    1184            0 :                 ShowContinueError(state, "  The maximum water flow rate for this coil will be set to zero and the coil will do no cooling.");
    1185            0 :                 ShowContinueError(state,
    1186            0 :                                   format("  Check the following coil design inputs for problems: Tair,in = {:.4R}", waterCoil.DesInletAirTemp));
    1187            0 :                 ShowContinueError(state,
    1188            0 :                                   format("                                                       Wair,in = {:.6R}", waterCoil.DesInletAirHumRat));
    1189            0 :                 ShowContinueError(state,
    1190            0 :                                   format("                                                       Twater,in = {:.4R}", waterCoil.DesInletWaterTemp));
    1191            0 :                 ShowContinueError(state,
    1192            0 :                                   format("                                                       Tair,out = {:.4R}", waterCoil.DesOutletAirTemp));
    1193            0 :                 ShowContinueError(state,
    1194            0 :                                   format("                                                       Wair,out = {:.6R}", waterCoil.DesOutletAirHumRat));
    1195            0 :                 waterCoil.MaxWaterVolFlowRate = 0.0;
    1196            0 :                 waterCoil.MaxWaterMassFlowRate = 0.0;
    1197              :             }
    1198              :         }
    1199              : 
    1200          177 :         if (state.dataWaterCoils->MyCoilDesignFlag(CoilNum) && (waterCoil.WaterCoilModel == CoilModel::CoolingSimple) &&
    1201          177 :             (waterCoil.DesAirVolFlowRate > 0.0) && (waterCoil.MaxWaterMassFlowRate > 0.0)) { // 'Cooling'
    1202              : 
    1203           23 :             state.dataWaterCoils->MyCoilDesignFlag(CoilNum) = false;
    1204           23 :             state.dataWaterCoils->NoSatCurveIntersect = false;
    1205           23 :             state.dataWaterCoils->BelowInletWaterTemp = false;
    1206           23 :             state.dataWaterCoils->CBFTooLarge = false;
    1207           23 :             state.dataWaterCoils->NoExitCondReset = false;
    1208           47 :             for (Ipass = 1; Ipass <= 2; ++Ipass) {
    1209           44 :                 if (Ipass == 2) {
    1210           40 :                     if (!state.dataWaterCoils->NoSatCurveIntersect && !state.dataWaterCoils->BelowInletWaterTemp &&
    1211           19 :                         !state.dataWaterCoils->CBFTooLarge) {
    1212           18 :                         goto Inlet_Conditions_Loop_exit; // coil UA calcs OK
    1213              :                     } else {
    1214            3 :                         ShowWarningError(state, format("In calculating the design coil UA for Coil:Cooling:Water {}", waterCoil.Name));
    1215            3 :                         if (state.dataWaterCoils->NoSatCurveIntersect) {
    1216            6 :                             ShowContinueError(state, "no apparatus dew-point can be found for the initial entering and leaving conditions;");
    1217              :                         }
    1218            3 :                         if (state.dataWaterCoils->BelowInletWaterTemp) {
    1219            0 :                             ShowContinueError(state, "the apparatus dew-point is below the coil design inlet water temperature;");
    1220              :                         }
    1221            3 :                         if (state.dataWaterCoils->CBFTooLarge) {
    1222            3 :                             ShowContinueError(state, "the coil bypass factor is unrealistically large;");
    1223              :                         }
    1224            3 :                         if (!state.dataWaterCoils->NoExitCondReset) {
    1225            3 :                             ShowContinueError(state, "the coil outlet design conditions will be changed to correct the problem.");
    1226              :                         }
    1227            3 :                         ShowContinueError(state, format("The initial design conditions are: Tair,in = {:.4R}", waterCoil.DesInletAirTemp));
    1228            3 :                         ShowContinueError(state, format("                                   Wair,in = {:.6R}", waterCoil.DesInletAirHumRat));
    1229            3 :                         ShowContinueError(state, format("                                   Twater,in = {:.4R}", waterCoil.DesInletWaterTemp));
    1230            3 :                         ShowContinueError(state, format("                                   Tair,out = {:.4R}", waterCoil.DesOutletAirTemp));
    1231            3 :                         ShowContinueError(state, format("                                   Wair,out = {:.6R}", waterCoil.DesOutletAirHumRat));
    1232            3 :                         if (!state.dataWaterCoils->NoExitCondReset) {
    1233            1 :                             ShowContinueError(state, format("The revised design conditions are: Tair,out = {:.4R}", state.dataWaterCoils->TOutNew));
    1234            1 :                             ShowContinueError(state, format("                                   Wair,out = {:.6R}", state.dataWaterCoils->WOutNew));
    1235            1 :                             waterCoil.DesOutletAirHumRat = state.dataWaterCoils->WOutNew;
    1236            1 :                             waterCoil.DesOutletAirTemp = state.dataWaterCoils->TOutNew;
    1237              :                             // update outlet air conditions used for sizing
    1238            1 :                             std::string CompType;
    1239            1 :                             if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) {
    1240            0 :                                 CompType = HVAC::cAllCoilTypes(HVAC::Coil_CoolingWaterDetailed);
    1241              :                             } else {
    1242            1 :                                 CompType = HVAC::cAllCoilTypes(HVAC::Coil_CoolingWater);
    1243              :                             }
    1244            1 :                             state.dataRptCoilSelection->coilSelectionReportObj->setCoilLvgAirTemp(
    1245            1 :                                 state, waterCoil.Name, CompType, state.dataWaterCoils->TOutNew);
    1246            1 :                             state.dataRptCoilSelection->coilSelectionReportObj->setCoilLvgAirHumRat(
    1247            1 :                                 state, waterCoil.Name, CompType, state.dataWaterCoils->WOutNew);
    1248              :                             // end update outlet air conditions used for sizing
    1249            1 :                         }
    1250              :                     }
    1251              :                 }
    1252              : 
    1253              :                 // Volume flow rate being converted to mass flow rate for water
    1254           26 :                 waterCoil.DesAirMassFlowRate = state.dataEnvrn->StdRhoAir * waterCoil.DesAirVolFlowRate;
    1255              : 
    1256              :                 // Enthalpy of Air at Inlet design conditions
    1257           26 :                 DesInletAirEnth = PsyHFnTdbW(waterCoil.DesInletAirTemp, waterCoil.DesInletAirHumRat);
    1258              : 
    1259              :                 // Enthalpy of Air at outlet at design conditions
    1260           26 :                 DesOutletAirEnth = PsyHFnTdbW(waterCoil.DesOutletAirTemp, waterCoil.DesOutletAirHumRat);
    1261              : 
    1262              :                 // already calculated above and possibly reset if dry coil
    1263              :                 //        ! Enthalpy of Water at Inlet design conditions
    1264              :                 //        DesSatEnthAtWaterInTemp =PsyHFnTdbW(WaterCoil(CoilNum)%DesInletWaterTemp, &
    1265              :                 //                                             PsyWFnTdpPb(state, WaterCoil(CoilNum)%DesInletWaterTemp,StdBaroPress))
    1266              : 
    1267              :                 // Total Coil Load from Inlet and Outlet Air States (which include fan heat as appropriate).
    1268           26 :                 waterCoil.DesTotWaterCoilLoad = waterCoil.DesAirMassFlowRate * (DesInletAirEnth - DesOutletAirEnth);
    1269              : 
    1270              :                 // Enthalpy of Water at Inlet design conditions
    1271           26 :                 Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum)
    1272           26 :                          .glycol->getSpecificHeat(state, waterCoil.DesInletWaterTemp, RoutineName);
    1273              : 
    1274           26 :                 DesOutletWaterTemp = waterCoil.DesInletWaterTemp + waterCoil.DesTotWaterCoilLoad / (waterCoil.MaxWaterMassFlowRate * Cp);
    1275              : 
    1276           26 :                 DesSatEnthAtWaterOutTemp = PsyHFnTdbW(DesOutletWaterTemp, PsyWFnTdpPb(state, DesOutletWaterTemp, state.dataEnvrn->StdBaroPress));
    1277           26 :                 DesEnthAtWaterOutTempAirInHumRat = PsyHFnTdbW(DesOutletWaterTemp, waterCoil.DesInletAirHumRat);
    1278           26 :                 DesEnthWaterOut = min(DesSatEnthAtWaterOutTemp, DesEnthAtWaterOutTempAirInHumRat);
    1279              : 
    1280              :                 // dry coil test
    1281           26 :                 if (waterCoil.DesOutletAirHumRat < waterCoil.DesInletAirHumRat && DesHumRatAtWaterInTemp < waterCoil.DesInletAirHumRat) { // wet coil
    1282              : 
    1283              :                     // Calculations for BYPASS FACTOR at design conditions
    1284              :                     // Calculate "slope" of temperature vs. humidity ratio between entering and leaving states
    1285           48 :                     SlopeTempVsHumRatio = (waterCoil.DesInletAirTemp - waterCoil.DesOutletAirTemp) /
    1286           24 :                                           max((waterCoil.DesInletAirHumRat - waterCoil.DesOutletAirHumRat), SmallNo);
    1287              : 
    1288              :                     // Initialize iteration parameters
    1289           24 :                     DesAirTempApparatusDewPt = PsyTdpFnWPb(state, waterCoil.DesOutletAirHumRat, state.dataEnvrn->OutBaroPress);
    1290              : 
    1291              :                     // Iterating to calculate Apparatus Dew Point Temperature at Design Conditions
    1292          128 :                     for (iter = 1; iter <= itmax; ++iter) {
    1293              : 
    1294              :                         // Calculate apparatus dewpoint and compare with predicted value
    1295              :                         // using entering conditions and SlopeTempVsHumRatio
    1296          128 :                         DesAirHumRatApparatusDewPt = PsyWFnTdpPb(state, DesAirTempApparatusDewPt, state.dataEnvrn->OutBaroPress);
    1297              : 
    1298              :                         // Initial Estimate for apparatus Dew Point Temperature
    1299          128 :                         TempApparatusDewPtEstimate =
    1300          128 :                             waterCoil.DesInletAirTemp - SlopeTempVsHumRatio * (waterCoil.DesInletAirHumRat - DesAirHumRatApparatusDewPt);
    1301              : 
    1302              :                         // Iterating to calculate Apparatus Dew Point Temperature at Design Condition
    1303          128 :                         error = DesAirTempApparatusDewPt - TempApparatusDewPtEstimate;
    1304          128 :                         General::Iterate(ResultX, 0.01, DesAirTempApparatusDewPt, error, X1, Y1, iter, icvg);
    1305          128 :                         DesAirTempApparatusDewPt = ResultX;
    1306              : 
    1307              :                         // If converged, exit loop
    1308          128 :                         if (icvg == 1) {
    1309           20 :                             goto App_DewPoint_Loop1_exit;
    1310              :                         }
    1311              : 
    1312              :                         // If not converged due to low Humidity Ratio approximate value at outlet conditions
    1313          108 :                         if (iter == itmax) {
    1314            4 :                             state.dataWaterCoils->NoSatCurveIntersect = true;
    1315            4 :                             DesAirTempApparatusDewPt = PsyTdpFnWPb(state, waterCoil.DesOutletAirHumRat, state.dataEnvrn->OutBaroPress);
    1316            4 :                             DesAirHumRatApparatusDewPt = PsyWFnTdpPb(state, DesAirTempApparatusDewPt, state.dataEnvrn->OutBaroPress);
    1317            4 :                             goto App_DewPoint_Loop1_exit;
    1318              :                         }
    1319              : 
    1320              :                         // End of Loop for Iteration
    1321              :                     }
    1322            0 :                 App_DewPoint_Loop1_exit:;
    1323              : 
    1324              :                     // Air enthalpy at apparatus dew point at design conditions
    1325           24 :                     DesAirApparatusDewPtEnth = PsyHFnTdbW(DesAirTempApparatusDewPt, DesAirHumRatApparatusDewPt);
    1326              : 
    1327              :                     // Calculate bypass factor from enthalpies calculated above.
    1328           24 :                     DesBypassFactor = (DesOutletAirEnth - DesAirApparatusDewPtEnth) / (DesInletAirEnth - DesAirApparatusDewPtEnth);
    1329              : 
    1330              :                     // Check for bypass factor for unsuitable value. Note that bypass factor is never used in the coil calculation
    1331           24 :                     if ((DesBypassFactor > 0.5) || (DesBypassFactor < 0.0)) {
    1332            2 :                         state.dataWaterCoils->CBFTooLarge = true;
    1333            2 :                         DesBypassFactor = 0.37;
    1334              :                     }
    1335              : 
    1336           24 :                     if (DesEnthWaterOut > DesInletAirEnth) {
    1337            1 :                         ShowWarningError(state, format("In calculating the design coil UA for Coil:Cooling:Water {}", waterCoil.Name));
    1338            2 :                         ShowContinueError(state, "the outlet chilled water design enthalpy is greater than the inlet air design enthalpy.");
    1339            2 :                         ShowContinueError(state,
    1340            2 :                                           format("To correct this condition the design chilled water flow rate will be increased from {:.5R}",
    1341            1 :                                                  waterCoil.MaxWaterVolFlowRate));
    1342            1 :                         EnthCorrFrac = (DesEnthWaterOut - DesInletAirEnth) / (DesEnthWaterOut - DesSatEnthAtWaterInTemp);
    1343            1 :                         waterCoil.MaxWaterVolFlowRate *= (1.0 + 2.0 * EnthCorrFrac);
    1344            1 :                         ShowContinueError(state, format("to {:.5R} m3/s", waterCoil.MaxWaterVolFlowRate));
    1345            1 :                         waterCoil.MaxWaterMassFlowRate = rho * waterCoil.MaxWaterVolFlowRate;
    1346            1 :                         DesOutletWaterTemp = waterCoil.DesInletWaterTemp + waterCoil.DesTotWaterCoilLoad / (waterCoil.MaxWaterMassFlowRate * Cp);
    1347              :                         DesSatEnthAtWaterOutTemp =
    1348            1 :                             PsyHFnTdbW(DesOutletWaterTemp, PsyWFnTdpPb(state, DesOutletWaterTemp, state.dataEnvrn->StdBaroPress));
    1349            1 :                         DesEnthAtWaterOutTempAirInHumRat = PsyHFnTdbW(DesOutletWaterTemp, waterCoil.DesInletAirHumRat);
    1350            1 :                         DesEnthWaterOut = min(DesSatEnthAtWaterOutTemp, DesEnthAtWaterOutTempAirInHumRat);
    1351              :                     }
    1352              : 
    1353              :                     // Determine air-side coefficient, UACoilExternal, assuming that the
    1354              :                     // surface temperature is at the apparatus dewpoint temperature
    1355           24 :                     if (DesAirApparatusDewPtEnth <= DesSatEnthAtWaterInTemp) state.dataWaterCoils->BelowInletWaterTemp = true;
    1356           24 :                     if ((DesInletAirEnth - DesEnthWaterOut) > SmallNo && (DesOutletAirEnth - DesSatEnthAtWaterInTemp) > SmallNo) {
    1357           23 :                         LogMeanEnthDiff = ((DesInletAirEnth - DesEnthWaterOut) - (DesOutletAirEnth - DesSatEnthAtWaterInTemp)) /
    1358           23 :                                           std::log((DesInletAirEnth - DesEnthWaterOut) / (DesOutletAirEnth - DesSatEnthAtWaterInTemp));
    1359              :                     } else {
    1360            1 :                         LogMeanEnthDiff = 2000.0; // UA will be 1/2 the design coil load
    1361              :                     }
    1362           24 :                     DesUACoilExternalEnth = waterCoil.DesTotWaterCoilLoad / LogMeanEnthDiff;
    1363           24 :                     waterCoil.UACoilExternal = DesUACoilExternalEnth * PsyCpAirFnW(waterCoil.DesInletAirHumRat);
    1364              : 
    1365           42 :                     if (Ipass == 1 && (state.dataWaterCoils->NoSatCurveIntersect || state.dataWaterCoils->CBFTooLarge ||
    1366           18 :                                        state.dataWaterCoils->BelowInletWaterTemp)) {
    1367              :                         // reset outlet conditions to 90% relative humidity at the same outlet enthalpy
    1368            3 :                         state.dataWaterCoils->TOutNew = TdbFnHRhPb(state, DesOutletAirEnth, 0.9, state.dataEnvrn->StdBaroPress);
    1369            3 :                         state.dataWaterCoils->WOutNew = PsyWFnTdbH(state, state.dataWaterCoils->TOutNew, DesOutletAirEnth);
    1370            6 :                         if (state.dataWaterCoils->WOutNew >= waterCoil.DesInletAirHumRat ||
    1371            3 :                             state.dataWaterCoils->TOutNew > waterCoil.DesOutletAirTemp) {
    1372            2 :                             state.dataWaterCoils->NoExitCondReset = true;
    1373              :                         }
    1374            3 :                         goto Inlet_Conditions_Loop_loop;
    1375              :                     }
    1376              : 
    1377           21 :                     waterCoil.UACoilInternal = waterCoil.UACoilExternal * 3.30;
    1378              :                     // Overall heat transfer coefficient
    1379           21 :                     waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
    1380              : 
    1381              :                 } else { // dry coil
    1382              : 
    1383            2 :                     if (DesOutletWaterTemp > waterCoil.DesInletAirTemp) {
    1384            0 :                         ShowWarningError(state, format("In calculating the design coil UA for Coil:Cooling:Water {}", waterCoil.Name));
    1385            0 :                         ShowContinueError(state, "the outlet chilled water design temperature is greater than the inlet air design temperature.");
    1386            0 :                         ShowContinueError(state,
    1387            0 :                                           format("To correct this condition the design chilled water flow rate will be increased from {:.5R}",
    1388            0 :                                                  waterCoil.MaxWaterVolFlowRate));
    1389            0 :                         TempCorrFrac = (DesOutletWaterTemp - waterCoil.DesInletAirTemp) / (DesOutletWaterTemp - waterCoil.DesInletWaterTemp);
    1390            0 :                         waterCoil.MaxWaterVolFlowRate *= (1.0 + 2.0 * TempCorrFrac);
    1391            0 :                         ShowContinueError(state, format("to {:.5R} m3/s", waterCoil.MaxWaterVolFlowRate));
    1392            0 :                         waterCoil.MaxWaterMassFlowRate = rho * waterCoil.MaxWaterVolFlowRate;
    1393            0 :                         DesOutletWaterTemp = waterCoil.DesInletWaterTemp + waterCoil.DesTotWaterCoilLoad / (waterCoil.MaxWaterMassFlowRate * Cp);
    1394              :                     }
    1395              : 
    1396            2 :                     if ((waterCoil.DesInletAirTemp - DesOutletWaterTemp) > SmallNo &&
    1397            2 :                         (waterCoil.DesOutletAirTemp - waterCoil.DesInletWaterTemp) > SmallNo) {
    1398            2 :                         LogMeanTempDiff =
    1399            2 :                             ((waterCoil.DesInletAirTemp - DesOutletWaterTemp) - (waterCoil.DesOutletAirTemp - waterCoil.DesInletWaterTemp)) /
    1400            2 :                             std::log((waterCoil.DesInletAirTemp - DesOutletWaterTemp) / (waterCoil.DesOutletAirTemp - waterCoil.DesInletWaterTemp));
    1401            2 :                         waterCoil.UACoilExternal = waterCoil.DesTotWaterCoilLoad / LogMeanTempDiff;
    1402              :                     } else {
    1403            0 :                         waterCoil.UACoilExternal = waterCoil.DesTotWaterCoilLoad / 2.0; // make the UA large
    1404              :                     }
    1405            2 :                     waterCoil.UACoilInternal = waterCoil.UACoilExternal * 3.30;
    1406              :                     // Overall heat transfer coefficient
    1407            2 :                     waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
    1408            2 :                     goto Inlet_Conditions_Loop_exit;
    1409              :                 }
    1410              : 
    1411           24 :             Inlet_Conditions_Loop_loop:;
    1412              :             }
    1413            3 :         Inlet_Conditions_Loop_exit:;
    1414              : 
    1415              :             // estimate the heat external transfer surface area using typical design over all U value
    1416           23 :             waterCoil.TotCoilOutsideSurfArea = EstimateHEXSurfaceArea(state, CoilNum);
    1417              :             // calculate internal and external "UA per external surface area"
    1418           23 :             waterCoil.UACoilInternalPerUnitArea = waterCoil.UACoilInternal / waterCoil.TotCoilOutsideSurfArea;
    1419           23 :             waterCoil.UAWetExtPerUnitArea = waterCoil.UACoilExternal / waterCoil.TotCoilOutsideSurfArea;
    1420              :             // approximate the dry UA as 1.0 times wet UA
    1421           23 :             waterCoil.UADryExtPerUnitArea = waterCoil.UAWetExtPerUnitArea;
    1422              : 
    1423              :             // Now use SolveRoot to "invert" the cooling coil model to obtain the UA given the specified design inlet and outlet conditions
    1424              :             // Note that the UAs we have obtained so far are rough estimates that are the starting points for the the following iterative
    1425              :             //   calculation of the actual UAs.
    1426           23 :             waterCoil.InletAirTemp = waterCoil.DesInletAirTemp;
    1427           23 :             waterCoil.InletAirHumRat = waterCoil.DesInletAirHumRat;
    1428           23 :             waterCoil.InletWaterTemp = waterCoil.DesInletWaterTemp;
    1429           23 :             waterCoil.InletWaterMassFlowRate = rho * waterCoil.MaxWaterVolFlowRate;
    1430           23 :             waterCoil.InletAirMassFlowRate = waterCoil.DesAirMassFlowRate;
    1431              :             // set the lower and upper limits on the UA
    1432           23 :             UA0 = 0.1 * waterCoil.UACoilExternal;
    1433           23 :             UA1 = 10.0 * waterCoil.UACoilExternal;
    1434              :             // Invert the simple cooling coil model: given the design inlet conditions and the design load, find the design UA
    1435          385 :             auto f = [&state, CoilNum](Real64 const UA) {
    1436          385 :                 HVAC::FanOp fanOp = HVAC::FanOp::Continuous;
    1437          385 :                 Real64 PartLoadRatio = 1.0;
    1438          385 :                 auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    1439          385 :                 waterCoil.UACoilExternal = UA;
    1440          385 :                 waterCoil.UACoilInternal = waterCoil.UACoilExternal * 3.3;
    1441          385 :                 waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
    1442          385 :                 waterCoil.TotCoilOutsideSurfArea = EstimateHEXSurfaceArea(state, CoilNum);
    1443          385 :                 waterCoil.UACoilInternalPerUnitArea = waterCoil.UACoilInternal / waterCoil.TotCoilOutsideSurfArea;
    1444          385 :                 waterCoil.UAWetExtPerUnitArea = waterCoil.UACoilExternal / waterCoil.TotCoilOutsideSurfArea;
    1445          385 :                 waterCoil.UADryExtPerUnitArea = waterCoil.UAWetExtPerUnitArea;
    1446              : 
    1447          385 :                 CoolingCoil(state, CoilNum, true, state.dataWaterCoils->DesignCalc, fanOp, PartLoadRatio);
    1448              : 
    1449          385 :                 return (waterCoil.DesTotWaterCoilLoad - waterCoil.TotWaterCoolingCoilRate) / waterCoil.DesTotWaterCoilLoad;
    1450           23 :             };
    1451           23 :             General::SolveRoot(state, 0.001, MaxIte, SolFla, UA, f, UA0, UA1);
    1452              :             // if the numerical inversion failed, issue error messages.
    1453           23 :             if (SolFla == -1) {
    1454            0 :                 ShowSevereError(state, format("Calculation of cooling coil design UA failed for coil {}", waterCoil.Name));
    1455            0 :                 ShowContinueError(state, "  Iteration limit exceeded in calculating coil UA");
    1456            0 :                 waterCoil.UACoilExternal = UA0 * 10.0;
    1457            0 :                 waterCoil.UACoilInternal = waterCoil.UACoilExternal * 3.3;
    1458            0 :                 waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
    1459            0 :                 waterCoil.TotCoilOutsideSurfArea = EstimateHEXSurfaceArea(state, CoilNum);
    1460            0 :                 waterCoil.UACoilInternalPerUnitArea = waterCoil.UACoilInternal / waterCoil.TotCoilOutsideSurfArea;
    1461            0 :                 waterCoil.UAWetExtPerUnitArea = waterCoil.UACoilExternal / waterCoil.TotCoilOutsideSurfArea;
    1462            0 :                 waterCoil.UADryExtPerUnitArea = waterCoil.UAWetExtPerUnitArea;
    1463            0 :                 ShowContinueError(state, format(" Coil design UA set to {:.6R} [W/C]", waterCoil.UACoilTotal));
    1464           23 :             } else if (SolFla == -2) {
    1465            3 :                 ShowSevereError(state, format("Calculation of cooling coil design UA failed for coil {}", waterCoil.Name));
    1466            6 :                 ShowContinueError(state, "  Bad starting values for UA");
    1467            3 :                 waterCoil.UACoilExternal = UA0 * 10.0;
    1468            3 :                 waterCoil.UACoilInternal = waterCoil.UACoilExternal * 3.3;
    1469            3 :                 waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
    1470            3 :                 waterCoil.TotCoilOutsideSurfArea = EstimateHEXSurfaceArea(state, CoilNum);
    1471            3 :                 waterCoil.UACoilInternalPerUnitArea = waterCoil.UACoilInternal / waterCoil.TotCoilOutsideSurfArea;
    1472            3 :                 waterCoil.UAWetExtPerUnitArea = waterCoil.UACoilExternal / waterCoil.TotCoilOutsideSurfArea;
    1473            3 :                 waterCoil.UADryExtPerUnitArea = waterCoil.UAWetExtPerUnitArea;
    1474            3 :                 ShowContinueError(state, format(" Coil design UA set to {:.6R} [W/C]", waterCoil.UACoilTotal));
    1475              :             }
    1476              : 
    1477              :             // cooling coil surface area
    1478           23 :             state.dataWaterCoils->SurfaceArea = waterCoil.TotCoilOutsideSurfArea;
    1479              : 
    1480              :             // cooling coil overall UA value
    1481           23 :             state.dataWaterCoils->UATotal = waterCoil.UACoilTotal;
    1482              : 
    1483              :             // save the design internal and external UAs
    1484           23 :             waterCoil.UACoilExternalDes = waterCoil.UACoilExternal;
    1485           23 :             waterCoil.UACoilInternalDes = waterCoil.UACoilInternal;
    1486              :         }
    1487              : 
    1488              :         //@@@@ DESIGN CONDITION END HERE @@@@
    1489              : 
    1490              :         // Calculate rated Total, latent, sensible capacity, SHR, effectiveness
    1491           99 :         if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
    1492           51 :             waterCoil.InletAirTemp = 16.6;
    1493           51 :             waterCoil.InletAirHumRat = PsyWFnTdbRhPb(state, 16.6, 0.5, state.dataEnvrn->StdBaroPress, RoutineName);
    1494           51 :             waterCoil.InletWaterTemp = 82.2;
    1495              :         } else {
    1496           48 :             waterCoil.InletAirTemp = 26.67;
    1497           48 :             waterCoil.InletAirHumRat = PsyWFnTdbTwbPb(state, 26.67, 19.44, state.dataEnvrn->StdBaroPress, RoutineName);
    1498           48 :             waterCoil.InletWaterTemp = 6.67;
    1499              :         }
    1500           99 :         waterCoil.InletAirEnthalpy = PsyHFnTdbW(waterCoil.InletAirTemp, waterCoil.InletAirHumRat);
    1501           99 :         waterCoil.InletWaterMassFlowRate = waterCoil.MaxWaterMassFlowRate;
    1502           99 :         waterCoil.InletAirMassFlowRate = state.dataEnvrn->StdRhoAir * waterCoil.DesAirVolFlowRate;
    1503           99 :         CapacitanceAir = waterCoil.InletAirMassFlowRate * PsyCpAirFnW(waterCoil.InletAirHumRat);
    1504              : 
    1505           99 :         Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, waterCoil.InletWaterTemp, RoutineName);
    1506              : 
    1507           99 :         state.dataWaterCoils->CapacitanceWater = waterCoil.InletWaterMassFlowRate * Cp;
    1508           99 :         state.dataWaterCoils->CMin = min(CapacitanceAir, state.dataWaterCoils->CapacitanceWater);
    1509           99 :         if (state.dataWaterCoils->CMin > 0.0) {
    1510           97 :             if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) {
    1511           44 :                 CoolingCoil(state, CoilNum, FirstHVACIteration, state.dataWaterCoils->DesignCalc, HVAC::FanOp::Continuous, 1.0);
    1512          132 :                 state.dataWaterCoils->CoilEffectiveness = (waterCoil.InletAirTemp - waterCoil.OutletAirTemp) /
    1513           88 :                                                           (waterCoil.InletAirTemp - waterCoil.InletWaterTemp) *
    1514           44 :                                                           (CapacitanceAir / state.dataWaterCoils->CMin);
    1515           44 :                 state.dataWaterCoils->RatedLatentCapacity = waterCoil.TotWaterCoolingCoilRate - waterCoil.SenWaterCoolingCoilRate;
    1516           44 :                 state.dataWaterCoils->RatedSHR = waterCoil.SenWaterCoolingCoilRate / waterCoil.TotWaterCoolingCoilRate;
    1517           53 :             } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling) {
    1518            4 :                 CalcDetailFlatFinCoolingCoil(state, CoilNum, state.dataWaterCoils->DesignCalc, HVAC::FanOp::Continuous, 1.0);
    1519           12 :                 state.dataWaterCoils->CoilEffectiveness = (waterCoil.InletAirTemp - waterCoil.OutletAirTemp) /
    1520            8 :                                                           (waterCoil.InletAirTemp - waterCoil.InletWaterTemp) *
    1521            4 :                                                           (CapacitanceAir / state.dataWaterCoils->CMin);
    1522            4 :                 state.dataWaterCoils->RatedLatentCapacity = waterCoil.TotWaterCoolingCoilRate - waterCoil.SenWaterCoolingCoilRate;
    1523            4 :                 state.dataWaterCoils->RatedSHR = waterCoil.SenWaterCoolingCoilRate / waterCoil.TotWaterCoolingCoilRate;
    1524           49 :             } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
    1525           49 :                 CalcSimpleHeatingCoil(state, CoilNum, HVAC::FanOp::Continuous, 1.0, state.dataWaterCoils->DesignCalc);
    1526           49 :                 state.dataWaterCoils->CoilEffectiveness = (waterCoil.OutletAirTemp - waterCoil.InletAirTemp) /
    1527           98 :                                                           (waterCoil.InletWaterTemp - waterCoil.InletAirTemp) *
    1528           49 :                                                           (CapacitanceAir / state.dataWaterCoils->CMin);
    1529              :             }
    1530              :         } else {
    1531            2 :             state.dataWaterCoils->CoilEffectiveness = 0.0;
    1532            2 :             waterCoil.TotWaterHeatingCoilRate = 0.0;
    1533            2 :             waterCoil.TotWaterCoolingCoilRate = 0.0;
    1534            2 :             waterCoil.SenWaterCoolingCoilRate = 0.0;
    1535            2 :             state.dataWaterCoils->RatedLatentCapacity = 0.0;
    1536            2 :             state.dataWaterCoils->RatedSHR = 0.0;
    1537              :         }
    1538           99 :         state.dataWaterCoils->MyEnvrnFlag(CoilNum) = false;
    1539              : 
    1540              :     } // End If for the Begin Environment initializations
    1541              : 
    1542       320692 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    1543       317409 :         state.dataWaterCoils->MyEnvrnFlag(CoilNum) = true;
    1544              :     }
    1545              : 
    1546       320692 :     if (!state.dataGlobal->DoingSizing) {
    1547       319652 :         if (state.dataWaterCoils->MyCoilReportFlag(CoilNum)) {
    1548              :             // create predefined report entries
    1549           40 :             state.dataWaterCoils->MyCoilReportFlag(CoilNum) = false;
    1550           40 :             switch (waterCoil.WaterCoilType) {
    1551           21 :             case DataPlant::PlantEquipmentType::CoilWaterSimpleHeating: {
    1552           21 :                 if (state.dataWaterCoils->RptCoilHeaderFlag(1)) {
    1553           15 :                     print(state.files.eio, "{}", "! <Water Heating Coil Capacity Information>,Component Type,Name,Nominal Total Capacity {W}\n");
    1554           15 :                     state.dataWaterCoils->RptCoilHeaderFlag(1) = false;
    1555              :                 }
    1556           21 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilType, waterCoil.Name, "Coil:Heating:Water");
    1557           42 :                 OutputReportPredefined::PreDefTableEntry(
    1558           21 :                     state, state.dataOutRptPredefined->pdchHeatCoilDesCap, waterCoil.Name, waterCoil.DesWaterHeatingCoilRate);
    1559           42 :                 OutputReportPredefined::PreDefTableEntry(
    1560           21 :                     state, state.dataOutRptPredefined->pdchHeatCoilNomCap, waterCoil.Name, waterCoil.TotWaterHeatingCoilRate);
    1561           21 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomEff, waterCoil.Name, "-");
    1562           42 :                 OutputReportPredefined::addFootNoteSubTable(
    1563              :                     state,
    1564           21 :                     state.dataOutRptPredefined->pdstHeatCoil,
    1565              :                     "Nominal values are gross at rated conditions, i.e., the supply air fan heat and electric power NOT accounted for.");
    1566           21 :                 print(state.files.eio,
    1567              :                       "{},{},{:.2R}\n",
    1568              :                       "Water Heating Coil Capacity Information,Coil:Heating:Water",
    1569           21 :                       waterCoil.Name,
    1570           21 :                       waterCoil.TotWaterHeatingCoilRate);
    1571           63 :                 state.dataRptCoilSelection->coilSelectionReportObj->setCoilAirFlow(
    1572           42 :                     state, waterCoil.Name, "Coil:Heating:Water", waterCoil.DesAirVolFlowRate, waterCoil.RequestingAutoSize);
    1573           63 :                 state.dataRptCoilSelection->coilSelectionReportObj->setCoilWaterHeaterCapacityNodeNums(
    1574              :                     state,
    1575           21 :                     waterCoil.Name,
    1576              :                     "Coil:Heating:Water",
    1577              :                     waterCoil.DesWaterHeatingCoilRate,
    1578           21 :                     waterCoil.RequestingAutoSize,
    1579              :                     waterCoil.WaterInletNodeNum,
    1580              :                     waterCoil.WaterOutletNodeNum,
    1581              :                     waterCoil.WaterPlantLoc.loopNum); // coil report
    1582           21 :                 break;
    1583              :             }
    1584            2 :             case DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling: {
    1585            2 :                 if (state.dataWaterCoils->RptCoilHeaderFlag(2)) {
    1586            2 :                     print(state.files.eio,
    1587              :                           "{}\n",
    1588              :                           "! <Water Cooling Coil Capacity Information>,Component Type,Name,Nominal Total "
    1589              :                           "Capacity {W},Nominal Sensible Capacity {W},Nominal Latent Capacity {W},Nominal "
    1590              :                           "Sensible Heat Ratio");
    1591            2 :                     state.dataWaterCoils->RptCoilHeaderFlag(2) = false;
    1592              :                 }
    1593            2 :                 state.dataWaterCoils->RatedLatentCapacity = waterCoil.TotWaterCoolingCoilRate - waterCoil.SenWaterCoolingCoilRate;
    1594            2 :                 state.dataWaterCoils->RatedSHR = General::SafeDivide(waterCoil.SenWaterCoolingCoilRate, waterCoil.TotWaterCoolingCoilRate);
    1595            4 :                 OutputReportPredefined::PreDefTableEntry(
    1596            2 :                     state, state.dataOutRptPredefined->pdchCoolCoilType, waterCoil.Name, "Coil:Cooling:Water:DetailedGeometry");
    1597            4 :                 OutputReportPredefined::PreDefTableEntry(
    1598            2 :                     state, state.dataOutRptPredefined->pdchCoolCoilDesCap, waterCoil.Name, waterCoil.DesWaterCoolingCoilRate);
    1599            4 :                 OutputReportPredefined::PreDefTableEntry(
    1600            2 :                     state, state.dataOutRptPredefined->pdchCoolCoilTotCap, waterCoil.Name, waterCoil.TotWaterCoolingCoilRate);
    1601            4 :                 OutputReportPredefined::PreDefTableEntry(
    1602            2 :                     state, state.dataOutRptPredefined->pdchCoolCoilSensCap, waterCoil.Name, waterCoil.SenWaterCoolingCoilRate);
    1603            6 :                 OutputReportPredefined::PreDefTableEntry(
    1604            4 :                     state, state.dataOutRptPredefined->pdchCoolCoilLatCap, waterCoil.Name, state.dataWaterCoils->RatedLatentCapacity);
    1605            6 :                 OutputReportPredefined::PreDefTableEntry(
    1606            4 :                     state, state.dataOutRptPredefined->pdchCoolCoilSHR, waterCoil.Name, state.dataWaterCoils->RatedSHR);
    1607            2 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilNomEff, waterCoil.Name, "-");
    1608            4 :                 OutputReportPredefined::addFootNoteSubTable(
    1609              :                     state,
    1610            2 :                     state.dataOutRptPredefined->pdstCoolCoil,
    1611              :                     "Nominal values are gross at rated conditions, i.e., the supply air fan heat and electric power NOT accounted for.");
    1612            2 :                 print(state.files.eio,
    1613              :                       "{},{},{:.2R},{:.2R},{:.2R},{:.2R}\n",
    1614              :                       "Water Cooling Coil Capacity Information,Coil:Cooling:Water:DetailedGeometry",
    1615            2 :                       waterCoil.Name,
    1616            2 :                       waterCoil.TotWaterCoolingCoilRate,
    1617            2 :                       waterCoil.SenWaterCoolingCoilRate,
    1618            2 :                       state.dataWaterCoils->RatedLatentCapacity,
    1619            2 :                       state.dataWaterCoils->RatedSHR);
    1620            6 :                 state.dataRptCoilSelection->coilSelectionReportObj->setCoilAirFlow(state,
    1621            2 :                                                                                    waterCoil.Name,
    1622              :                                                                                    "Coil:Cooling:Water:DetailedGeometry",
    1623              :                                                                                    waterCoil.DesAirVolFlowRate,
    1624            2 :                                                                                    waterCoil.RequestingAutoSize); // Coil Report
    1625            6 :                 state.dataRptCoilSelection->coilSelectionReportObj->setCoilWaterCoolingCapacity(state,
    1626            2 :                                                                                                 waterCoil.Name,
    1627              :                                                                                                 "Coil:Cooling:Water:DetailedGeometry",
    1628              :                                                                                                 waterCoil.DesWaterCoolingCoilRate,
    1629            2 :                                                                                                 waterCoil.RequestingAutoSize,
    1630              :                                                                                                 waterCoil.WaterInletNodeNum,
    1631              :                                                                                                 waterCoil.WaterOutletNodeNum,
    1632              :                                                                                                 waterCoil.WaterPlantLoc.loopNum); // Coil Report
    1633            2 :                 break;
    1634              :             }
    1635           17 :             case DataPlant::PlantEquipmentType::CoilWaterCooling: {
    1636           17 :                 if (state.dataWaterCoils->RptCoilHeaderFlag(2)) {
    1637           12 :                     print(state.files.eio,
    1638              :                           "{}\n",
    1639              :                           "! <Water Cooling Coil Capacity Information>,Component Type,Name,Nominal Total "
    1640              :                           "Capacity {W},Nominal Sensible Capacity {W},Nominal Latent Capacity {W},Nominal "
    1641              :                           "Sensible Heat Ratio, Nominal Coil UA Value {W/C}, Nominal Coil Surface Area {m2}");
    1642           12 :                     state.dataWaterCoils->RptCoilHeaderFlag(2) = false;
    1643              :                 }
    1644           17 :                 state.dataWaterCoils->RatedLatentCapacity = waterCoil.TotWaterCoolingCoilRate - waterCoil.SenWaterCoolingCoilRate;
    1645           17 :                 state.dataWaterCoils->RatedSHR = General::SafeDivide(waterCoil.SenWaterCoolingCoilRate, waterCoil.TotWaterCoolingCoilRate);
    1646           17 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilType, waterCoil.Name, "Coil:Cooling:Water");
    1647           34 :                 OutputReportPredefined::PreDefTableEntry(
    1648           17 :                     state, state.dataOutRptPredefined->pdchCoolCoilDesCap, waterCoil.Name, waterCoil.DesWaterCoolingCoilRate);
    1649           34 :                 OutputReportPredefined::PreDefTableEntry(
    1650           17 :                     state, state.dataOutRptPredefined->pdchCoolCoilTotCap, waterCoil.Name, waterCoil.TotWaterCoolingCoilRate);
    1651           34 :                 OutputReportPredefined::PreDefTableEntry(
    1652           17 :                     state, state.dataOutRptPredefined->pdchCoolCoilSensCap, waterCoil.Name, waterCoil.SenWaterCoolingCoilRate);
    1653           51 :                 OutputReportPredefined::PreDefTableEntry(
    1654           34 :                     state, state.dataOutRptPredefined->pdchCoolCoilLatCap, waterCoil.Name, state.dataWaterCoils->RatedLatentCapacity);
    1655           51 :                 OutputReportPredefined::PreDefTableEntry(
    1656           34 :                     state, state.dataOutRptPredefined->pdchCoolCoilSHR, waterCoil.Name, state.dataWaterCoils->RatedSHR);
    1657           17 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilNomEff, waterCoil.Name, "-");
    1658           34 :                 OutputReportPredefined::PreDefTableEntry(
    1659           17 :                     state, state.dataOutRptPredefined->pdchCoolCoilUATotal, waterCoil.Name, waterCoil.UACoilTotal);
    1660           34 :                 OutputReportPredefined::PreDefTableEntry(
    1661           17 :                     state, state.dataOutRptPredefined->pdchCoolCoilArea, waterCoil.Name, waterCoil.TotCoilOutsideSurfArea);
    1662           34 :                 OutputReportPredefined::addFootNoteSubTable(
    1663              :                     state,
    1664           17 :                     state.dataOutRptPredefined->pdstCoolCoil,
    1665              :                     "Nominal values are gross at rated conditions, i.e., the supply air fan heat and electric power NOT accounted for.");
    1666           17 :                 print(state.files.eio,
    1667              :                       "{},{},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R}\n",
    1668              :                       "Water Cooling Coil Capacity Information,Coil:Cooling:Water",
    1669           17 :                       waterCoil.Name,
    1670           17 :                       waterCoil.TotWaterCoolingCoilRate,
    1671           17 :                       waterCoil.SenWaterCoolingCoilRate,
    1672           17 :                       state.dataWaterCoils->RatedLatentCapacity,
    1673           17 :                       state.dataWaterCoils->RatedSHR,
    1674           17 :                       state.dataWaterCoils->UATotal,
    1675           17 :                       state.dataWaterCoils->SurfaceArea);
    1676           51 :                 state.dataRptCoilSelection->coilSelectionReportObj->setCoilAirFlow(state,
    1677           17 :                                                                                    waterCoil.Name,
    1678              :                                                                                    "Coil:Cooling:Water",
    1679              :                                                                                    waterCoil.DesAirVolFlowRate,
    1680           17 :                                                                                    waterCoil.RequestingAutoSize); // Coil Report
    1681           51 :                 state.dataRptCoilSelection->coilSelectionReportObj->setCoilWaterCoolingCapacity(state,
    1682           17 :                                                                                                 waterCoil.Name,
    1683              :                                                                                                 "Coil:Cooling:Water",
    1684              :                                                                                                 waterCoil.DesWaterCoolingCoilRate,
    1685           17 :                                                                                                 waterCoil.RequestingAutoSize,
    1686              :                                                                                                 waterCoil.WaterInletNodeNum,
    1687              :                                                                                                 waterCoil.WaterOutletNodeNum,
    1688              :                                                                                                 waterCoil.WaterPlantLoc.loopNum); // Coil Report
    1689           17 :                 break;
    1690              :             }
    1691            0 :             default:
    1692            0 :                 break;
    1693              :             }
    1694           40 :             if (waterCoil.DesWaterCoolingCoilRate <= 0.0) waterCoil.DesWaterCoolingCoilRate = waterCoil.TotWaterCoolingCoilRate;
    1695           40 :             if (waterCoil.DesWaterHeatingCoilRate <= 0.0) waterCoil.DesWaterHeatingCoilRate = waterCoil.TotWaterHeatingCoilRate;
    1696              : 
    1697              :             // call coil model with everything set at rating point
    1698           40 :             waterCoil.InletAirMassFlowRate = waterCoil.DesAirMassFlowRate;
    1699           40 :             waterCoil.InletAirTemp = waterCoil.DesInletAirTemp;
    1700           40 :             waterCoil.InletAirHumRat = waterCoil.DesInletAirHumRat; // fixed in sizing routine
    1701           40 :             waterCoil.InletAirEnthalpy = Psychrometrics::PsyHFnTdbW(waterCoil.DesInletAirTemp, waterCoil.DesInletAirHumRat);
    1702           40 :             Real64 DesInletWetBulb = Psychrometrics::PsyTwbFnTdbWPb(
    1703              :                 state, waterCoil.DesInletAirTemp, waterCoil.DesInletAirHumRat, DataEnvironment::StdPressureSeaLevel, "InitWaterCoils");
    1704           40 :             waterCoil.InletWaterMassFlowRate = waterCoil.MaxWaterMassFlowRate;
    1705           40 :             waterCoil.InletWaterTemp = waterCoil.DesInletWaterTemp;
    1706           40 :             Real64 cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum)
    1707           40 :                             .glycol->getSpecificHeat(state, waterCoil.DesInletWaterTemp, "InitWaterCoil");
    1708           40 :             waterCoil.InletWaterEnthalpy = cp * waterCoil.InletWaterTemp;
    1709              : 
    1710           40 :             waterCoil.UACoilVariable = waterCoil.UACoil;
    1711           40 :             waterCoil.FaultyCoilFoulingFactor = 0.0;
    1712           40 :             Real64 holdOutBaroPress = state.dataEnvrn->OutBaroPress;
    1713           40 :             state.dataEnvrn->OutBaroPress = DataEnvironment::StdPressureSeaLevel; // assume rating is for sea level.
    1714           40 :             CalcAdjustedCoilUA(state, CoilNum);
    1715              : 
    1716           40 :             std::string coilTypeName(" ");
    1717              :             // calculate coil sim model at rating point, full load, continuous fan
    1718           40 :             if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling) {
    1719            2 :                 CalcDetailFlatFinCoolingCoil(state, CoilNum, state.dataWaterCoils->SimCalc, HVAC::FanOp::Continuous, 1.0);
    1720            2 :                 coilTypeName = "Coil:Cooling:Water:DetailedGeometry";
    1721           38 :             } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) {
    1722           17 :                 CoolingCoil(state, CoilNum, FirstHVACIteration, state.dataWaterCoils->SimCalc, HVAC::FanOp::Continuous, 1.0);
    1723           17 :                 coilTypeName = "Coil:Cooling:Water";
    1724           21 :             } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
    1725           21 :                 CalcSimpleHeatingCoil(state, CoilNum, HVAC::FanOp::Continuous, 1.0, state.dataWaterCoils->SimCalc);
    1726           21 :                 coilTypeName = "Coil:Heating:Water";
    1727              :             }
    1728           40 :             state.dataRptCoilSelection->coilSelectionReportObj->setCoilEqNum(
    1729           40 :                 state, waterCoil.Name, coilTypeName, state.dataSize->CurSysNum, state.dataSize->CurOASysNum, state.dataSize->CurZoneEqNum);
    1730              : 
    1731              :             // coil outlets
    1732           40 :             Real64 RatedOutletWetBulb(0.0);
    1733           40 :             RatedOutletWetBulb = Psychrometrics::PsyTwbFnTdbWPb(
    1734              :                 state, waterCoil.OutletAirTemp, waterCoil.OutletAirHumRat, DataEnvironment::StdPressureSeaLevel, "InitWaterCoil");
    1735              : 
    1736              :             // call set routine in coil report
    1737           40 :             if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling ||
    1738           38 :                 waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) {
    1739           19 :                 state.dataRptCoilSelection->coilSelectionReportObj->setRatedCoilConditions(
    1740              :                     state,
    1741           19 :                     waterCoil.Name,
    1742              :                     coilTypeName,
    1743              :                     waterCoil.TotWaterCoolingCoilRate, // this is the report variable
    1744              :                     waterCoil.SenWaterCoolingCoilRate, // this is the report variable
    1745              :                     waterCoil.InletAirMassFlowRate,
    1746              :                     waterCoil.InletAirTemp,
    1747              :                     waterCoil.InletAirHumRat,
    1748              :                     DesInletWetBulb,
    1749              :                     waterCoil.OutletAirTemp,
    1750              :                     waterCoil.OutletAirHumRat,
    1751              :                     RatedOutletWetBulb,
    1752              :                     -999.0,
    1753              :                     -999.0,
    1754              :                     -999.0,
    1755              :                     -999.0); // coil effectiveness
    1756           21 :             } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
    1757           21 :                 state.dataRptCoilSelection->coilSelectionReportObj->setRatedCoilConditions(
    1758              :                     state,
    1759           21 :                     waterCoil.Name,
    1760              :                     coilTypeName,
    1761              :                     waterCoil.TotWaterHeatingCoilRate, // this is the report variable
    1762              :                     waterCoil.TotWaterHeatingCoilRate, // this is the report variable
    1763              :                     waterCoil.InletAirMassFlowRate,
    1764              :                     waterCoil.InletAirTemp,
    1765              :                     waterCoil.InletAirHumRat,
    1766              :                     DesInletWetBulb,
    1767              :                     waterCoil.OutletAirTemp,
    1768              :                     waterCoil.OutletAirHumRat,
    1769              :                     RatedOutletWetBulb,
    1770              :                     -999.0,
    1771              :                     -999.0,
    1772              :                     -999.0,
    1773              :                     -999.0); // coil effectiveness
    1774              :             }
    1775              :             // now replace the outdoor air conditions set above for one time rating point calc
    1776           40 :             state.dataEnvrn->OutBaroPress = holdOutBaroPress;
    1777              :         }
    1778              :     }
    1779              : 
    1780              :     // Do the Begin Day initializations
    1781              :     // NONE
    1782              : 
    1783              :     // Do the begin HVAC time step initializations
    1784              :     // NONE
    1785              : 
    1786              :     // Do the following initializations (every time step): This should be the info from
    1787              :     // the previous components outlets or the node data in this section.
    1788              :     // First set the conditions for the air into the coil model
    1789       320692 :     AirInletNode = waterCoil.AirInletNodeNum;
    1790       320692 :     WaterInletNode = waterCoil.WaterInletNodeNum;
    1791       320692 :     auto const &airInletNode = state.dataLoopNodes->Node(AirInletNode);
    1792       320692 :     waterCoil.InletAirMassFlowRate = airInletNode.MassFlowRate;
    1793       320692 :     waterCoil.InletAirTemp = airInletNode.Temp;
    1794       320692 :     waterCoil.InletAirHumRat = airInletNode.HumRat;
    1795       320692 :     waterCoil.InletAirEnthalpy = airInletNode.Enthalpy;
    1796              : 
    1797       320692 :     auto const &waterInletNode = state.dataLoopNodes->Node(WaterInletNode);
    1798       320692 :     waterCoil.InletWaterMassFlowRate = waterInletNode.MassFlowRate;
    1799       320692 :     waterCoil.InletWaterTemp = waterInletNode.Temp;
    1800       320692 :     waterCoil.InletWaterEnthalpy = waterInletNode.Enthalpy;
    1801              : 
    1802       320692 :     waterCoil.UACoilVariable = waterCoil.UACoil;
    1803              : 
    1804       320692 :     CalcAdjustedCoilUA(state, CoilNum);
    1805              : 
    1806       320692 :     waterCoil.TotWaterHeatingCoilRate = 0.0;
    1807       320692 :     waterCoil.TotWaterCoolingCoilRate = 0.0;
    1808       320692 :     waterCoil.SenWaterCoolingCoilRate = 0.0;
    1809       320692 : }
    1810              : 
    1811              : // refactor coilUA adjustment into separate routine, for use with rating calc
    1812       320732 : void CalcAdjustedCoilUA(EnergyPlusData &state, int const CoilNum)
    1813              : {
    1814              :     // Pull these precalc routines out of big init routine
    1815              :     // modify the coil UA based on model in Wetter 1999
    1816              :     Real64 x_a;                  // result of Eq.70 in Wetter 1999
    1817              :     Real64 x_w;                  // result of Eq.72 in Wetter 1999
    1818              :     Real64 AirConvectTerm;       // result of Eq.71 in Wetter 1999
    1819              :     Real64 WaterConvectTerm;     // result of Eq.73 in Wetter 1999
    1820              :     Real64 WaterConvSensitivity; // "s" in Wetter 1999, temperature sensitivity in water side convection
    1821              : 
    1822       320732 :     auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    1823              :     // Coil:Heating:Water
    1824       485670 :     if ((waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) &&
    1825       164938 :         (!(state.dataWaterCoils->MyUAAndFlowCalcFlag(CoilNum)))) { // update Coil UA based on inlet mass flows and temps
    1826       164692 :         x_a = 1.0 + 4.769E-3 * (waterCoil.InletAirTemp - waterCoil.DesInletAirTemp);
    1827       164692 :         if (waterCoil.DesAirMassFlowRate > 0.0) {
    1828       164643 :             AirConvectTerm = x_a * std::pow(waterCoil.InletAirMassFlowRate / waterCoil.DesAirMassFlowRate, 0.8) * waterCoil.AirSideNominalConvect;
    1829              :         } else {
    1830           49 :             AirConvectTerm = 0.0;
    1831              :         }
    1832       164692 :         WaterConvSensitivity = 0.014 / (1.0 + 0.014 * waterCoil.DesInletWaterTemp);
    1833       164692 :         x_w = 1.0 + WaterConvSensitivity * (waterCoil.InletWaterTemp - waterCoil.DesInletWaterTemp);
    1834       164692 :         if (waterCoil.MaxWaterMassFlowRate > 0.0) {
    1835       164692 :             WaterConvectTerm =
    1836       164692 :                 x_w * std::pow(waterCoil.InletWaterMassFlowRate / waterCoil.MaxWaterMassFlowRate, 0.85) * waterCoil.LiquidSideNominalConvect;
    1837              :         } else {
    1838            0 :             WaterConvectTerm = 0.0;
    1839              :         }
    1840       164692 :         if ((AirConvectTerm > 0.0) && (WaterConvectTerm > 0.0)) {
    1841        58681 :             waterCoil.UACoilVariable = 1.0 / ((1.0 / WaterConvectTerm) + (1.0 / AirConvectTerm));
    1842              :         } else {
    1843              :             // use nominal UA since variable UA cannot be calculated
    1844       106011 :             waterCoil.UACoilVariable = waterCoil.UACoil;
    1845              :         }
    1846              : 
    1847              :         // calculate the Faulty Coil Fouling (thermal insulance) Factor using fault information
    1848       329384 :         if (waterCoil.FaultyCoilFoulingFlag &&
    1849              :             // The fault shouldn't apply during sizing.
    1850       164692 :             (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) && (!state.dataGlobal->KickOffSimulation) &&
    1851              :             // This was preexisting
    1852            0 :             !(state.dataWaterCoils->MyUAAndFlowCalcFlag(CoilNum))) {
    1853              :             // Store original value
    1854            0 :             waterCoil.OriginalUACoilVariable = waterCoil.UACoilVariable;
    1855              : 
    1856            0 :             int FaultIndex = waterCoil.FaultyCoilFoulingIndex;
    1857            0 :             FaultsManager::FaultPropertiesFoulingCoil &fouling = state.dataFaultsMgr->FouledCoils(FaultIndex);
    1858            0 :             Real64 FaultFrac = fouling.FaultFraction(state);
    1859              : 
    1860            0 :             if (fouling.FoulingInputMethod == FaultsManager::FouledCoil::UARated) {
    1861              :                 // 1/UA' = Frac * (1/UAFouled) + (1-Frac) / UA
    1862            0 :                 waterCoil.UACoilVariable = 1 / (FaultFrac / (fouling.UAFouled) + (1 - FaultFrac) / waterCoil.UACoilVariable);
    1863              :             } else {
    1864              :                 // R' = R + Rfoul
    1865              :                 // Rfoul = r_air/A_air + r_water/A_water (FoulingFactor = thermal insulance [K/W, A] = Area [m2], r=fouling factor [m2.K/W]
    1866            0 :                 Real64 FoulingFactor = FaultFrac * (fouling.Rfw / (fouling.Aratio * fouling.Aout) + fouling.Rfa / fouling.Aout);
    1867            0 :                 waterCoil.UACoilVariable = 1.0 / ((1.0 / waterCoil.UACoilVariable) + FoulingFactor);
    1868              :             }
    1869              : 
    1870              :             // Do not allow improving coil performance
    1871            0 :             waterCoil.UACoilVariable = min(waterCoil.UACoilVariable, waterCoil.OriginalUACoilVariable);
    1872              : 
    1873              :             // Only for reporting purposes
    1874            0 :             waterCoil.FaultyCoilFoulingFactor = (1.0 / waterCoil.UACoilVariable) - (1.0 / waterCoil.OriginalUACoilVariable);
    1875              :         } else {
    1876       164692 :             waterCoil.FaultyCoilFoulingFactor = 0;
    1877              :         }
    1878              :     }
    1879              : 
    1880              :     // Coil:Cooling:Water
    1881              :     // update Coil UA based on inlet mass flows and temps
    1882       320732 :     if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling && (!state.dataWaterCoils->MyCoilDesignFlag(CoilNum))) {
    1883       147095 :         if (waterCoil.DesAirMassFlowRate > 0.0) {
    1884       147095 :             x_a = 1.0 + 4.769E-3 * (waterCoil.InletAirTemp - waterCoil.DesInletAirTemp);
    1885       147095 :             waterCoil.UACoilExternal =
    1886       147095 :                 x_a * std::pow(waterCoil.InletAirMassFlowRate / waterCoil.DesAirMassFlowRate, 0.8) * waterCoil.UACoilExternalDes;
    1887              :         } else {
    1888            0 :             waterCoil.UACoilExternal = waterCoil.UACoilExternalDes;
    1889              :         }
    1890              : 
    1891       147095 :         if (waterCoil.MaxWaterMassFlowRate > 0.0) {
    1892       147095 :             WaterConvSensitivity = 0.014 / (1.0 + 0.014 * waterCoil.DesInletWaterTemp);
    1893       147095 :             x_w = 1.0 + WaterConvSensitivity * (waterCoil.InletWaterTemp - waterCoil.DesInletWaterTemp);
    1894       147095 :             waterCoil.UACoilInternal =
    1895       147095 :                 x_w * std::pow(waterCoil.InletWaterMassFlowRate / waterCoil.MaxWaterMassFlowRate, 0.85) * waterCoil.UACoilInternalDes;
    1896              :         } else {
    1897            0 :             waterCoil.UACoilInternal = waterCoil.UACoilInternalDes;
    1898              :         }
    1899              : 
    1900       147095 :         if (!(waterCoil.UACoilInternal > 0.0 && waterCoil.UACoilExternal > 0.0)) {
    1901        93655 :             waterCoil.UACoilInternal = waterCoil.UACoilInternalDes;
    1902        93655 :             waterCoil.UACoilExternal = waterCoil.UACoilExternalDes;
    1903              :         }
    1904              : 
    1905              :         // If Fouling
    1906       294190 :         if (waterCoil.FaultyCoilFoulingFlag &&
    1907              :             // The fault shouldn't apply during sizing.
    1908       147095 :             (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) && (!state.dataGlobal->KickOffSimulation) &&
    1909              :             // This was preexisting
    1910            0 :             !(state.dataWaterCoils->MyUAAndFlowCalcFlag(CoilNum))) {
    1911              :             // Store original value
    1912              :             // This is really UACoilTotal technically, but I don't see the point of declaring another Real on the struct just for that
    1913            0 :             waterCoil.OriginalUACoilVariable = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
    1914              : 
    1915            0 :             waterCoil.OriginalUACoilExternal = waterCoil.UACoilExternal;
    1916            0 :             waterCoil.OriginalUACoilInternal = waterCoil.UACoilInternal;
    1917              : 
    1918            0 :             int FaultIndex = waterCoil.FaultyCoilFoulingIndex;
    1919              : 
    1920            0 :             FaultsManager::FaultPropertiesFoulingCoil &fouling = state.dataFaultsMgr->FouledCoils(FaultIndex);
    1921            0 :             Real64 FaultFrac = fouling.FaultFraction(state);
    1922              : 
    1923            0 :             if (fouling.FoulingInputMethod == FaultsManager::FouledCoil::FoulingFactor) {
    1924              :                 // Adjust the External (air) UA and Internal (water) UA accordingly
    1925            0 :                 Real64 Rfoul_air = FaultFrac * (fouling.Rfa / fouling.Aout);
    1926            0 :                 Real64 Rfoul_water = FaultFrac * (fouling.Rfw / (fouling.Aratio * fouling.Aout));
    1927              : 
    1928            0 :                 waterCoil.UACoilInternal = 1.0 / (1.0 / waterCoil.UACoilInternal + Rfoul_water);
    1929            0 :                 waterCoil.UACoilExternal = 1.0 / (1.0 / waterCoil.UACoilExternal + Rfoul_air);
    1930              :                 //
    1931              :             } else { // iFouledCoil_UARated
    1932              :                 // FouledUARated is supposed to be the overall UA. So we need to split between Internal and External UAs
    1933              : 
    1934              :                 // How should I split fouling between internal/external?
    1935              :                 // We can actually use the current ratio before fouling...
    1936              :                 // splitRatio = UACoilInternal/UACoilExternal
    1937              :                 // UACoilInternal = UACoilExternal * splitRatio
    1938              : 
    1939              :                 // UACoilTotal = 1 / (1 / UACoilExternal + 1 / UACoilInternal)
    1940              :                 // UACoilTotal = 1 / (1 / UACoilExternal + 1 / (UACoilExernal * splitRatio))
    1941              :                 // UACoilTotal = UACoilExternal / (1 + 1 / splitRatio) = UACoilExternal  * splitRatio / (1 + splitRatio)
    1942              :                 // UACoilExternal = UACoilTotal * (1 + splitRatio) / splitRatio
    1943              :                 // UACoilInternal = UACoilTotal * (1 + splitRatio)
    1944              : 
    1945              :                 // Adding in FaultFrac:
    1946              :                 // UACoilExternal = FaultFrac * [UAFouled * (1+splitRatio) / splitRatio] + (1-FaultFrac) * UACoilExternal
    1947              :                 // UACoilInternal = FaultFrac * [UAFouled * splitRatio] + (1-FaultFrac) * UACoilInternal
    1948              : 
    1949            0 :                 Real64 splitRatio = waterCoil.UACoilInternal / waterCoil.UACoilExternal;
    1950              : 
    1951            0 :                 waterCoil.UACoilExternal =
    1952            0 :                     1.0 / ((FaultFrac * splitRatio) / ((1 + splitRatio) * fouling.UAFouled) + (1 - FaultFrac) / waterCoil.UACoilExternal);
    1953              : 
    1954              :                 // WaterCoil(CoilNum).UACoilInternal =   1.0 /
    1955              :                 //( FaultFrac / ((1 + splitRatio) * fouling.UAFouled) +
    1956              :                 //(1-FaultFrac) / WaterCoil(CoilNum).UACoilInternal);
    1957              : 
    1958            0 :                 waterCoil.UACoilInternal = splitRatio * waterCoil.UACoilExternal;
    1959              :             }
    1960              : 
    1961              :             // Do not allow improving coil performance
    1962            0 :             waterCoil.UACoilExternal = min(waterCoil.UACoilExternal, waterCoil.OriginalUACoilExternal);
    1963            0 :             waterCoil.UACoilInternal = min(waterCoil.UACoilInternal, waterCoil.OriginalUACoilInternal);
    1964              : 
    1965              :             // Only for reporting purposes
    1966            0 :             waterCoil.FaultyCoilFoulingFactor = (1.0 / waterCoil.UACoilExternal) - (1.0 / waterCoil.OriginalUACoilExternal) +
    1967            0 :                                                 (1.0 / waterCoil.UACoilInternal) - (1.0 / waterCoil.OriginalUACoilInternal);
    1968              :         } else {
    1969       147095 :             waterCoil.FaultyCoilFoulingFactor = 0;
    1970              :         }
    1971              : 
    1972       147095 :         waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
    1973              : 
    1974       147095 :         waterCoil.UACoilInternalPerUnitArea = waterCoil.UACoilInternal / waterCoil.TotCoilOutsideSurfArea;
    1975       147095 :         waterCoil.UAWetExtPerUnitArea = waterCoil.UACoilExternal / waterCoil.TotCoilOutsideSurfArea;
    1976       147095 :         waterCoil.UADryExtPerUnitArea = waterCoil.UAWetExtPerUnitArea;
    1977              :     }
    1978       320732 : }
    1979              : 
    1980           94 : void SizeWaterCoil(EnergyPlusData &state, int const CoilNum)
    1981              : {
    1982              : 
    1983              :     // SUBROUTINE INFORMATION:
    1984              :     //       AUTHOR         Fred Buhl
    1985              :     //       DATE WRITTEN   November 2001
    1986              :     //       MODIFIED       August 2013 Daeho Kang, add component sizing table entries
    1987              :     //       RE-ENGINEERED  na
    1988              : 
    1989              :     // PURPOSE OF THIS SUBROUTINE:
    1990              :     // This subroutine is for sizing Water Coil Components for which flow rates and UAs have not been
    1991              :     // specified in the input.
    1992              : 
    1993              :     // METHODOLOGY EMPLOYED:
    1994              :     // Obtains flow rates from the zone or system sizing arrays and plant sizing data. UAs are
    1995              :     // calculated by numerically inverting the individual coil calculation routines.
    1996              : 
    1997              :     // SUBROUTINE PARAMETER DEFINITIONS:
    1998              :     static constexpr std::string_view RoutineName("SizeWaterCoil");
    1999              : 
    2000              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2001              :     Real64 rho;
    2002           94 :     std::string CompType;                  // component type
    2003           94 :     std::string SizingString;              // input field sizing description (e.g., Nominal Capacity)
    2004              :     Real64 TempSize;                       // autosized value
    2005              :     Real64 DesCoilWaterInTempSaved;        // coil water inlet temp used for error checking UA sizing
    2006           94 :     Real64 DesCoilInletWaterTempUsed(0.0); // coil design inlet water temp for UA sizing only
    2007              :     Real64 Cp;
    2008              : 
    2009           94 :     bool ErrorsFound = false;
    2010           94 :     bool LoopErrorsFound = false;
    2011           94 :     int PltSizCoolNum = 0;
    2012           94 :     int PltSizHeatNum = 0;
    2013           94 :     Real64 DesCoilAirFlow = 0.0;
    2014           94 :     Real64 DesCoilExitTemp = 0.0;
    2015           94 :     Real64 CpAirStd = PsyCpAirFnW(0.0);
    2016              : 
    2017           94 :     auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    2018              :     // cooling coils
    2019           94 :     if (((waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) ||
    2020           53 :          (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling)) &&
    2021           44 :         waterCoil.RequestingAutoSize) {
    2022              :         // find the appropriate Plant Sizing object
    2023           24 :         PltSizCoolNum = PlantUtilities::MyPlantSizingIndex(
    2024              :             state, "chilled water coil", waterCoil.Name, waterCoil.WaterInletNodeNum, waterCoil.WaterOutletNodeNum, LoopErrorsFound);
    2025              :     }
    2026              : 
    2027           94 :     if (((waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) ||
    2028           53 :          (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling))) { // 'Cooling'
    2029              : 
    2030           44 :         if (waterCoil.UseDesignWaterDeltaTemp) {
    2031            4 :             state.dataSize->DataWaterCoilSizCoolDeltaT = waterCoil.DesignWaterDeltaTemp;
    2032              :         } else {
    2033           40 :             if (PltSizCoolNum > 0) {
    2034           20 :                 state.dataSize->DataWaterCoilSizCoolDeltaT = state.dataSize->PlantSizData(PltSizCoolNum).DeltaT;
    2035              :             }
    2036              :         }
    2037              : 
    2038           44 :         if (PltSizCoolNum > 0) {
    2039              : 
    2040              :             // int FieldNum = 0;
    2041           24 :             state.dataSize->DataPltSizCoolNum = PltSizCoolNum;
    2042           24 :             state.dataSize->DataWaterLoopNum = waterCoil.WaterPlantLoc.loopNum;
    2043              : 
    2044           24 :             if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) {        // 'DETAILED FLAT FIN'
    2045            3 :                 CompType = HVAC::cAllCoilTypes(HVAC::Coil_CoolingWaterDetailed); // Coil:Cooling:Water:DetailedGeometry
    2046              :             } else {
    2047           21 :                 CompType = HVAC::cAllCoilTypes(HVAC::Coil_CoolingWater); // Coil:Cooling:Water
    2048              :             }
    2049              : 
    2050           24 :             bool bPRINT = false; // do not print this sizing request since the autosized value is needed and this input may not be autosized (we
    2051              :                                  // should print this!)
    2052           24 :             if (waterCoil.DesAirVolFlowRate == state.dataSize->DataFlowUsedForSizing) {
    2053            7 :                 TempSize = waterCoil.DesAirVolFlowRate; // represents parent object has hard-sized airflow
    2054              :             } else {
    2055           17 :                 TempSize = DataSizing::AutoSize; // get the autosized air volume flow rate for use in other calculations
    2056              :             }
    2057              : 
    2058           24 :             ErrorsFound = false;
    2059           24 :             CoolingAirFlowSizer sizingCoolingAirFlow;
    2060           24 :             std::string const &CompName = waterCoil.Name;
    2061           24 :             sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2062           24 :             Real64 autoSizedValue = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
    2063           24 :             waterCoil.InletAirMassFlowRate = state.dataEnvrn->StdRhoAir * autoSizedValue; // inlet air mass flow rate is the autosized value
    2064              : 
    2065              :             // Check if the air volume flow rate is defined in parent HVAC equipment and set water coil design air volume flow rate accordingly
    2066           24 :             if (state.dataSize->CurZoneEqNum > 0) {
    2067           11 :                 auto const &ZoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
    2068           11 :                 if (ZoneEqSizing.DesignSizeFromParent && waterCoil.DesAirVolFlowRate == autoSizedValue) {
    2069            7 :                     state.dataSize->DataAirFlowUsedForSizing = ZoneEqSizing.AirVolFlow;
    2070            7 :                     state.dataSize->DataFlowUsedForSizing = ZoneEqSizing.AirVolFlow;
    2071            7 :                     waterCoil.DesAirVolFlowRate = DataSizing::AutoSize; // represents water coil being autosized
    2072              :                 } else {
    2073            4 :                     state.dataSize->DataAirFlowUsedForSizing =
    2074              :                         autoSizedValue; // many autosized inputs use the design (autosized) air volume flow rate, save this value
    2075            4 :                     state.dataSize->DataFlowUsedForSizing = autoSizedValue;
    2076              :                 }
    2077              :             } else {
    2078           13 :                 state.dataSize->DataAirFlowUsedForSizing =
    2079              :                     autoSizedValue; // many autosized inputs use the design (autosized) air volume flow rate, save this value
    2080           13 :                 state.dataSize->DataFlowUsedForSizing = autoSizedValue;
    2081              :             }
    2082              : 
    2083           24 :             if (state.dataSize->CurSysNum > 0 && state.dataSize->CurOASysNum == 0) {
    2084           13 :                 Real64 DesCoilExitHumRat(0.0); // fix coil sizing inconsistency
    2085           13 :                 DataSizing::GetCoilDesFlowT(state, state.dataSize->CurSysNum, CpAirStd, DesCoilAirFlow, DesCoilExitTemp, DesCoilExitHumRat);
    2086           13 :                 state.dataSize->DataAirFlowUsedForSizing = DesCoilAirFlow;
    2087           13 :                 state.dataSize->DataFlowUsedForSizing = DesCoilAirFlow;
    2088           13 :                 state.dataSize->DataDesOutletAirTemp = DesCoilExitTemp;
    2089           13 :                 state.dataSize->DataDesOutletAirHumRat = DesCoilExitHumRat; // need to test for dry coil but inlet conditions not yet known
    2090              :             }
    2091              : 
    2092              :             // calculate pre-sizing data needed for specific functions (e.g., CoolingWaterDesAirInletTempSizing needs HRin and air flow)
    2093              :             // these will be calculated again after other parameters are known
    2094           24 :             if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
    2095            3 :                 TempSize = DataSizing::AutoSize;                          // coil report
    2096              :             } else {
    2097           21 :                 TempSize = waterCoil.DesInletAirHumRat; // preserve input if entered
    2098              :             }
    2099           24 :             CoolingWaterDesAirInletHumRatSizer sizerCWDesInHumRat;
    2100           24 :             sizerCWDesInHumRat.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2101           24 :             state.dataSize->DataDesInletAirHumRat = sizerCWDesInHumRat.size(state, TempSize, ErrorsFound);
    2102              : 
    2103           24 :             TempSize = DataSizing::AutoSize;
    2104           24 :             CoolingCapacitySizer sizerCoolingCapacity;
    2105           24 :             sizerCoolingCapacity.overrideSizingString(SizingString);
    2106           24 :             sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2107           24 :             state.dataSize->DataCapacityUsedForSizing = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
    2108           24 :             TempSize = waterCoil.MaxWaterVolFlowRate;
    2109           24 :             CoolingWaterflowSizer sizerCWWaterflow;
    2110           24 :             sizerCWWaterflow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2111           24 :             Real64 autoSizedCWFlow = sizerCWWaterflow.size(state, TempSize, ErrorsFound);
    2112              :             // Check if the water flow rate is defined in parent HVAC equipment and set water coil design water flow rate accordingly
    2113           24 :             if (state.dataSize->CurZoneEqNum > 0) {
    2114           11 :                 auto const &ZoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
    2115           11 :                 if (ZoneEqSizing.DesignSizeFromParent) {
    2116            8 :                     state.dataSize->DataWaterFlowUsedForSizing = ZoneEqSizing.MaxCWVolFlow;
    2117              :                 } else {
    2118            3 :                     state.dataSize->DataWaterFlowUsedForSizing = autoSizedCWFlow;
    2119              :                 }
    2120              :             } else {
    2121           13 :                 state.dataSize->DataWaterFlowUsedForSizing = autoSizedCWFlow;
    2122              :             }
    2123              :             // end pre-sizing data calculations
    2124              : 
    2125           24 :             if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
    2126            3 :                 bPRINT = false; // do not print this sizing request since this coil does not have a design inlet air temp input field (we
    2127              :                                 // should print this!)
    2128            3 :                 TempSize = DataSizing::AutoSize; // not an input for this model
    2129              :             } else {
    2130           21 :                 bPRINT = true;
    2131           21 :                 TempSize = waterCoil.DesInletAirTemp; // preserve input if entered
    2132              :             }
    2133              : 
    2134           24 :             CoolingWaterDesAirInletTempSizer sizerCWDesInletAirTemp;
    2135           24 :             sizerCWDesInletAirTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2136           24 :             waterCoil.DesInletAirTemp = sizerCWDesInletAirTemp.size(state, TempSize, ErrorsFound);
    2137           24 :             state.dataSize->DataDesInletAirTemp = waterCoil.DesInletAirTemp;
    2138              : 
    2139           24 :             if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
    2140            3 :                 bPRINT = false;                                           // no field for detailed water coil, should print to eio anyway
    2141            3 :                 TempSize = DataSizing::AutoSize;                          // coil report
    2142              :             } else {
    2143           21 :                 bPRINT = true;
    2144           21 :                 TempSize = waterCoil.DesInletWaterTemp; // preserve input if entered
    2145              :             }
    2146           24 :             CoolingWaterDesWaterInletTempSizer sizerCWDesWaterInTemp;
    2147           24 :             sizerCWDesWaterInTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2148           24 :             waterCoil.DesInletWaterTemp = sizerCWDesWaterInTemp.size(state, TempSize, ErrorsFound);
    2149              : 
    2150           24 :             if ((waterCoil.DesInletWaterTemp > state.dataSize->DataDesOutletAirTemp) && state.dataSize->DataDesOutletAirTemp > 0.0) {
    2151            0 :                 ShowWarningError(state, format("Invalid design inlet water temperature for {} = {}", CompType, CompName));
    2152            0 :                 ShowContinueError(state, format("...design inlet water temperature = {:.3R} C", waterCoil.DesInletWaterTemp));
    2153            0 :                 ShowContinueError(state, format("...design outlet air temperature = {:.3R} C", state.dataSize->DataDesOutletAirTemp));
    2154            0 :                 ShowContinueError(state, "...design inlet water temperature should be less than the design outlet air temperature");
    2155            0 :                 ShowContinueError(state, "...design inlet water temperature is set to the design outlet air temperature minus 5.0C");
    2156            0 :                 waterCoil.DesInletWaterTemp = state.dataSize->DataDesOutletAirTemp - 5.0;
    2157              :             }
    2158              : 
    2159           24 :             if (state.dataSize->CurZoneEqNum > 0) { // zone equipment use air inlet humrat to calculate design outlet air temperature
    2160           11 :                 if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
    2161            0 :                     bPRINT = false;                                           // no field for detailed water coil, should print to eio anyway
    2162            0 :                     TempSize = DataSizing::AutoSize;                          // coil report
    2163              :                 } else {
    2164           11 :                     bPRINT = true;
    2165           11 :                     TempSize = waterCoil.DesInletAirHumRat; // preserve input if entered
    2166              :                 }
    2167           11 :                 sizerCWDesInHumRat.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2168           11 :                 waterCoil.DesInletAirHumRat = sizerCWDesInHumRat.size(state, TempSize, ErrorsFound);
    2169              :             }
    2170              : 
    2171           24 :             if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
    2172            3 :                 bPRINT = false;                                           // no field for detailed water coil, should print to eio anyway
    2173            3 :                 TempSize = DataSizing::AutoSize;                          // coil report
    2174              :             } else {
    2175           21 :                 bPRINT = true;
    2176           21 :                 TempSize = waterCoil.DesOutletAirTemp; // preserve input if entered
    2177              :             }
    2178              : 
    2179           24 :             state.dataSize->DataDesInletWaterTemp = waterCoil.DesInletWaterTemp; // used for warning messages
    2180           24 :             CoolingWaterDesAirOutletTempSizer sizerCWDesAirOutTemp;
    2181           24 :             sizerCWDesAirOutTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2182           24 :             waterCoil.DesOutletAirTemp = sizerCWDesAirOutTemp.size(state, TempSize, ErrorsFound);
    2183           24 :             state.dataSize->DataDesOutletAirTemp = waterCoil.DesOutletAirTemp;
    2184              : 
    2185           24 :             if (state.dataSize->CurSysNum > 0) { // This call can be deleted at a future time and remove the if ( CurZoneEqNum > 0 ) check above. This
    2186              :                                                  // will change the order of the eio file.
    2187           13 :                 if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
    2188            3 :                     bPRINT = false;                                           // no field for detailed water coil, should print this to eio anyway
    2189            3 :                     TempSize = DataSizing::AutoSize;                          // coil report
    2190              :                 } else {
    2191           10 :                     bPRINT = true;
    2192           10 :                     TempSize = waterCoil.DesInletAirHumRat;
    2193              :                 }
    2194           13 :                 sizerCWDesInHumRat.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2195           13 :                 waterCoil.DesInletAirHumRat = sizerCWDesInHumRat.size(state, TempSize, ErrorsFound);
    2196              :             }
    2197              : 
    2198           24 :             if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
    2199            3 :                 bPRINT = false;                                           // no field for detailed water coil, should print this to eio anyway
    2200            3 :                 TempSize = DataSizing::AutoSize;                          // coil report
    2201              :             } else {
    2202           21 :                 bPRINT = true;
    2203           21 :                 TempSize = waterCoil.DesOutletAirHumRat; // preserve input if entered
    2204              :             }
    2205           24 :             CoolingWaterDesAirOutletHumRatSizer sizerCWDesOutHumRat;
    2206           24 :             sizerCWDesOutHumRat.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2207           24 :             waterCoil.DesOutletAirHumRat = sizerCWDesOutHumRat.size(state, TempSize, ErrorsFound);
    2208           24 :             state.dataSize->DataDesOutletAirHumRat = waterCoil.DesOutletAirHumRat;
    2209              : 
    2210           24 :             TempSize = DataSizing::AutoSize;
    2211           24 :             bPRINT = true;
    2212           24 :             if (waterCoil.MaxWaterVolFlowRate != DataSizing::AutoSize) bPRINT = false;
    2213           24 :             if (state.dataSize->CurSysNum == 0) bPRINT = false;
    2214           24 :             SizingString = "Design Coil Load [W]"; // there is no input field for this value and this is not the rated capacity (we should
    2215              :                                                    // always print this!)
    2216              :             // air inlet/outlet conditions should be known. Don't include fan heat in capacity calculation.
    2217           24 :             state.dataSize->DataDesAccountForFanHeat = false;
    2218           24 :             CoolingCapacitySizer sizerCoolingCapacity2;
    2219           24 :             sizerCoolingCapacity2.overrideSizingString(SizingString);
    2220           24 :             sizerCoolingCapacity2.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2221           24 :             waterCoil.DesWaterCoolingCoilRate = sizerCoolingCapacity2.size(state, TempSize, ErrorsFound);
    2222           24 :             waterCoil.InletAirMassFlowRate =
    2223           24 :                 state.dataEnvrn->StdRhoAir * state.dataSize->DataFlowUsedForSizing; // inlet air mass flow rate is the autosized value
    2224           24 :             state.dataSize->DataCapacityUsedForSizing = waterCoil.DesWaterCoolingCoilRate;
    2225              : 
    2226              :             // Why isn't the water volume flow rate based on the user inputs for inlet/outlet air/water temps? Water volume flow rate is
    2227              :             // always based on autosized inputs.
    2228           24 :             bPRINT = true;
    2229           24 :             TempSize = waterCoil.MaxWaterVolFlowRate;
    2230           24 :             sizerCWWaterflow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2231           24 :             waterCoil.MaxWaterVolFlowRate = sizerCWWaterflow.size(state, TempSize, ErrorsFound);
    2232           24 :             state.dataSize->DataWaterFlowUsedForSizing = waterCoil.MaxWaterVolFlowRate;
    2233              : 
    2234           24 :             if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
    2235            3 :                 bPRINT = false; // do not print this sizing request since this coil does not have a design air flow rate input field (we
    2236              :                                 // should print this!)
    2237              :             } else {
    2238           21 :                 bPRINT = true;
    2239              :             }
    2240           24 :             TempSize = waterCoil.DesAirVolFlowRate;
    2241           24 :             CoolingAirFlowSizer sizingCoolingAirFlow2;
    2242           24 :             std::string stringOverride = "Design Air Flow Rate [m3/s]";
    2243           24 :             if (state.dataGlobal->isEpJSON) stringOverride = "design_air_flow_rate [m3/s]";
    2244           24 :             sizingCoolingAirFlow2.overrideSizingString(stringOverride);
    2245              :             // sizingCoolingAirFlow2.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    2246           24 :             sizingCoolingAirFlow2.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2247           24 :             waterCoil.DesAirVolFlowRate = sizingCoolingAirFlow2.size(state, TempSize, ErrorsFound);
    2248           24 :             waterCoil.DesAirMassFlowRate = waterCoil.DesAirVolFlowRate * state.dataEnvrn->StdRhoAir;
    2249              : 
    2250           24 :             if (waterCoil.DesAirVolFlowRate <= 0.0) {
    2251            0 :                 waterCoil.DesAirVolFlowRate = 0.0;
    2252            0 :                 ShowWarningError(state, format("The design air flow rate is zero for {} = {}", CompType, CompName));
    2253            0 :                 ShowContinueError(state, "The autosize value for max air volume flow rate is zero");
    2254              :             }
    2255              : 
    2256           24 :             if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) {
    2257              : 
    2258            3 :                 int FieldNum = 16; //  N16, \field Number of Tubes per Row
    2259            3 :                 bPRINT = true;
    2260            3 :                 SizingString = state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames(FieldNum);
    2261              :                 // Auto size detailed cooling coil number of tubes per row = int( 13750.0 * WaterCoil( CoilNum ).MaxWaterVolFlowRate ) + 1
    2262            3 :                 state.dataSize->DataFlowUsedForSizing = waterCoil.MaxWaterVolFlowRate;
    2263            3 :                 TempSize = float(waterCoil.NumOfTubesPerRow);
    2264            3 :                 CoolingWaterNumofTubesPerRowSizer sizerCWNumofTubesPerRow;
    2265            3 :                 sizerCWNumofTubesPerRow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2266            3 :                 waterCoil.NumOfTubesPerRow = sizerCWNumofTubesPerRow.size(state, TempSize, ErrorsFound);
    2267              : 
    2268              :                 // Auto size water coil fin diameter = 0.335 * WaterCoil( CoilNum ).InletAirMassFlowRate
    2269            3 :                 state.dataSize->DataConstantUsedForSizing = waterCoil.InletAirMassFlowRate;
    2270            3 :                 state.dataSize->DataFractionUsedForSizing = 0.335;
    2271            3 :                 TempSize = waterCoil.FinDiam;
    2272              : 
    2273            3 :                 AutoCalculateSizer sizerFinDiameter;
    2274            3 :                 stringOverride = "Fin Diameter [m]";
    2275            3 :                 if (state.dataGlobal->isEpJSON) stringOverride = "fin_diameter [m]";
    2276            3 :                 sizerFinDiameter.overrideSizingString(stringOverride);
    2277            3 :                 sizerFinDiameter.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2278            3 :                 waterCoil.FinDiam = sizerFinDiameter.size(state, TempSize, ErrorsFound);
    2279              : 
    2280              :                 // Auto size water coil minimum airflow area = 0.44 * WaterCoil( CoilNum ).InletAirMassFlowRate
    2281            3 :                 state.dataSize->DataConstantUsedForSizing = waterCoil.InletAirMassFlowRate;
    2282            3 :                 state.dataSize->DataFractionUsedForSizing = 0.44;
    2283            3 :                 TempSize = waterCoil.MinAirFlowArea;
    2284              : 
    2285            3 :                 AutoCalculateSizer sizerMinAirFlowArea;
    2286            3 :                 stringOverride = "Minimum Airflow Area [m2]";
    2287            3 :                 if (state.dataGlobal->isEpJSON) stringOverride = "minimum_airflow_area [m2]";
    2288            3 :                 sizerMinAirFlowArea.overrideSizingString(stringOverride);
    2289            3 :                 sizerMinAirFlowArea.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2290            3 :                 waterCoil.MinAirFlowArea = sizerMinAirFlowArea.size(state, TempSize, ErrorsFound);
    2291              : 
    2292            3 :                 if (waterCoil.MinAirFlowArea <= 0.0) {
    2293            0 :                     ShowSevereError(state, format("Coil:Cooling:Water:DetailedGeometry: \"{}\"", waterCoil.Name));
    2294            0 :                     ShowContinueError(state,
    2295            0 :                                       format("Coil Minimum Airflow Area must be greater than 0. Coil area = {:.6T}", waterCoil.MinAirFlowArea));
    2296            0 :                     ErrorsFound = true;
    2297              :                 }
    2298              : 
    2299              :                 // Auto size water coil finned surface area = 78.5 * WaterCoil( CoilNum ).InletAirMassFlowRate
    2300            6 :                 state.dataSize->DataConstantUsedForSizing =
    2301            3 :                     waterCoil.InletAirMassFlowRate; // actual autosized air mass flow rate, not calculated from user input
    2302            3 :                 state.dataSize->DataFractionUsedForSizing = 78.5;
    2303            3 :                 TempSize = waterCoil.FinSurfArea;
    2304              : 
    2305            3 :                 AutoCalculateSizer sizerFinSurfaceArea;
    2306            3 :                 stringOverride = "Fin Surface Area [m2]";
    2307            3 :                 if (state.dataGlobal->isEpJSON) stringOverride = "fin_surface_area [m2]";
    2308            3 :                 sizerFinSurfaceArea.overrideSizingString(stringOverride);
    2309            3 :                 sizerFinSurfaceArea.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2310            3 :                 waterCoil.FinSurfArea = sizerFinSurfaceArea.size(state, TempSize, ErrorsFound);
    2311              : 
    2312              :                 // Auto size water coil total tube inside surface area = 4.4 * WaterCoil( CoilNum ).TubeInsideDiam * WaterCoil( CoilNum
    2313              :                 // ).NumOfTubeRows * WaterCoil( CoilNum ).NumOfTubesPerRow
    2314            3 :                 state.dataSize->DataConstantUsedForSizing = waterCoil.TubeInsideDiam * waterCoil.NumOfTubeRows * waterCoil.NumOfTubesPerRow;
    2315            3 :                 state.dataSize->DataFractionUsedForSizing = 4.4;
    2316            3 :                 TempSize = waterCoil.TotTubeInsideArea;
    2317              : 
    2318            3 :                 AutoCalculateSizer sizerTubeInsideArea;
    2319            3 :                 stringOverride = "Total Tube Inside Area [m2]";
    2320            3 :                 if (state.dataGlobal->isEpJSON) stringOverride = "total_tube_inside_area [m2]";
    2321            3 :                 sizerTubeInsideArea.overrideSizingString(stringOverride);
    2322            3 :                 sizerTubeInsideArea.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2323            3 :                 waterCoil.TotTubeInsideArea = sizerTubeInsideArea.size(state, TempSize, ErrorsFound);
    2324              : 
    2325              :                 // Auto size water coil total tube outside surface area = 4.1 * WaterCoil( CoilNum ).TubeOutsideDiam * WaterCoil( CoilNum
    2326              :                 // ).NumOfTubeRows * WaterCoil( CoilNum ).NumOfTubesPerRow
    2327            3 :                 state.dataSize->DataConstantUsedForSizing = waterCoil.TubeOutsideDiam * waterCoil.NumOfTubeRows * waterCoil.NumOfTubesPerRow;
    2328            3 :                 state.dataSize->DataFractionUsedForSizing = 4.1;
    2329            3 :                 TempSize = waterCoil.TubeOutsideSurfArea;
    2330              : 
    2331            3 :                 AutoCalculateSizer sizerTubeOutsideArea;
    2332            3 :                 stringOverride = "Tube Outside Surface Area [m2]";
    2333            3 :                 if (state.dataGlobal->isEpJSON) stringOverride = "tube_outside_surface_area [m2]";
    2334            3 :                 sizerTubeOutsideArea.overrideSizingString(stringOverride);
    2335            3 :                 sizerTubeOutsideArea.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2336            3 :                 waterCoil.TubeOutsideSurfArea = sizerTubeOutsideArea.size(state, TempSize, ErrorsFound);
    2337              : 
    2338            3 :                 if ((waterCoil.FinSurfArea + waterCoil.TubeOutsideSurfArea) <= 0.0) {
    2339            0 :                     ShowSevereError(state, format("Coil:Cooling:Water:DetailedGeometry: \"{}\"", waterCoil.Name));
    2340            0 :                     ShowContinueError(
    2341              :                         state,
    2342            0 :                         format("Coil Fin Surface Area plus Coil Tube Outside Surface Area must be greater than 0. Total surface area = {:.6T}",
    2343            0 :                                (waterCoil.FinSurfArea + waterCoil.TubeOutsideSurfArea)));
    2344            0 :                     ErrorsFound = true;
    2345              :                 }
    2346              : 
    2347              :                 // Auto size water coil coil depth = WaterCoil( CoilNum ).TubeDepthSpacing * WaterCoil( CoilNum ).NumOfTubeRows
    2348            3 :                 state.dataSize->DataConstantUsedForSizing = waterCoil.TubeDepthSpacing;
    2349            3 :                 state.dataSize->DataFractionUsedForSizing = waterCoil.NumOfTubeRows;
    2350            3 :                 TempSize = waterCoil.CoilDepth;
    2351              : 
    2352            3 :                 AutoCalculateSizer sizerCoilDepth;
    2353            3 :                 stringOverride = "Coil Depth [m]";
    2354            3 :                 if (state.dataGlobal->isEpJSON) stringOverride = "coil_depth [m]";
    2355            3 :                 sizerCoilDepth.overrideSizingString(stringOverride);
    2356            3 :                 sizerCoilDepth.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2357            3 :                 waterCoil.CoilDepth = sizerCoilDepth.size(state, TempSize, ErrorsFound);
    2358            3 :             }
    2359           24 :             state.dataSize->DataPltSizCoolNum = 0; // reset all globals to 0 to ensure correct sizing for other child components
    2360           24 :             state.dataSize->DataWaterLoopNum = 0;
    2361           24 :             state.dataSize->DataConstantUsedForSizing = 0.0;
    2362           24 :             state.dataSize->DataFractionUsedForSizing = 0.0;
    2363           24 :             state.dataSize->DataAirFlowUsedForSizing = 0.0;
    2364           24 :             state.dataSize->DataFlowUsedForSizing = 0.0;
    2365           24 :             state.dataSize->DataWaterFlowUsedForSizing = 0.0;
    2366           24 :             state.dataSize->DataCapacityUsedForSizing = 0.0;
    2367           24 :             state.dataSize->DataDesInletAirTemp = 0.0;
    2368           24 :             state.dataSize->DataDesOutletAirTemp = 0.0;
    2369           24 :             state.dataSize->DataDesOutletAirHumRat = 0.0;
    2370           24 :             state.dataSize->DataDesInletAirHumRat = 0.0;
    2371           24 :             state.dataSize->DataDesInletWaterTemp = 0.0;
    2372           24 :             state.dataSize->DataWaterCoilSizCoolDeltaT = 0.0;
    2373           24 :             state.dataSize->DataDesAccountForFanHeat = true;
    2374           24 :         } else {
    2375              :             // If there is no cooling Plant Sizing object and autosizing was requested, issue fatal error message
    2376           20 :             if (waterCoil.RequestingAutoSize) {
    2377            0 :                 ShowSevereError(state, "Autosizing of water coil requires a cooling loop Sizing:Plant object");
    2378            0 :                 ShowContinueError(state, format("Occurs in water coil object= {}", waterCoil.Name));
    2379            0 :                 ErrorsFound = true;
    2380              :             }
    2381              :         }
    2382              :         //} // end of cooling Plant Sizing existence IF - ELSE
    2383              :     } // end cooling coil IF
    2384              : 
    2385              :     // if this is a heating coil
    2386           94 :     if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating && waterCoil.RequestingAutoSize) {
    2387              :         // find the appropriate heating Plant Sizing object
    2388           36 :         PltSizHeatNum = PlantUtilities::MyPlantSizingIndex(
    2389              :             state, "hot water coil", waterCoil.Name, waterCoil.WaterInletNodeNum, waterCoil.WaterOutletNodeNum, LoopErrorsFound);
    2390              :     }
    2391              : 
    2392           94 :     if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
    2393              : 
    2394           50 :         if (waterCoil.UseDesignWaterDeltaTemp) {
    2395              :             // use water design deltaT specified in the heating water coils
    2396            1 :             state.dataSize->DataWaterCoilSizHeatDeltaT = waterCoil.DesignWaterDeltaTemp;
    2397              :         } else {
    2398           49 :             if (PltSizHeatNum > 0) {
    2399           35 :                 state.dataSize->DataWaterCoilSizHeatDeltaT = state.dataSize->PlantSizData(PltSizHeatNum).DeltaT;
    2400              :             }
    2401              :         }
    2402              : 
    2403           50 :         if (PltSizHeatNum > 0) {
    2404              : 
    2405           36 :             int FieldNum = 0;
    2406           36 :             bool NomCapUserInp = false; // flag for whether user has onput a nominal heating capacity
    2407              : 
    2408           36 :             state.dataSize->DataPltSizHeatNum = PltSizHeatNum;
    2409           36 :             state.dataSize->DataWaterLoopNum = waterCoil.WaterPlantLoc.loopNum;
    2410           36 :             rho = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
    2411           36 :             Cp = state.dataPlnt->PlantLoop(state.dataSize->DataWaterLoopNum).glycol->getSpecificHeat(state, Constant::HWInitConvTemp, RoutineName);
    2412           36 :             if (waterCoil.DesTotWaterCoilLoad > 0.0) {
    2413            6 :                 NomCapUserInp = true;
    2414           30 :             } else if (state.dataSize->CurSysNum > 0 && state.dataSize->CurSysNum <= state.dataHVACGlobal->NumPrimaryAirSys) {
    2415            8 :                 if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatingCapMethod == DataSizing::CapacityPerFloorArea) {
    2416            0 :                     NomCapUserInp = true;
    2417           15 :                 } else if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatingCapMethod == DataSizing::HeatingDesignCapacity &&
    2418            7 :                            state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatingTotalCapacity > 0.0) {
    2419            1 :                     NomCapUserInp = true;
    2420              :                 }
    2421              :             } else {
    2422           22 :                 NomCapUserInp = false;
    2423              :             }
    2424           36 :             bool bPRINT = false;                                     // do not print this sizing request
    2425           36 :             TempSize = DataSizing::AutoSize;                         // get the autosized air volume flow rate for use in other calculations
    2426           36 :             SizingString.clear();                                    // doesn't matter
    2427           36 :             CompType = HVAC::cAllCoilTypes(HVAC::Coil_HeatingWater); // "Coil:Heating:Water"
    2428           36 :             std::string const &CompName = waterCoil.Name;
    2429           36 :             if (waterCoil.DesiccantRegenerationCoil) {
    2430            1 :                 state.dataSize->DataDesicRegCoil = true;
    2431            1 :                 state.dataSize->DataDesicDehumNum = waterCoil.DesiccantDehumNum;
    2432            1 :                 HeatingCoilDesAirInletTempSizer sizerHeatingDesInletTemp;
    2433            1 :                 ErrorsFound = false;
    2434            1 :                 sizerHeatingDesInletTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2435            1 :                 state.dataSize->DataDesInletAirTemp = sizerHeatingDesInletTemp.size(state, DataSizing::AutoSize, ErrorsFound);
    2436              : 
    2437            1 :                 HeatingCoilDesAirOutletTempSizer sizerHeatingDesOutletTemp;
    2438            1 :                 ErrorsFound = false;
    2439            1 :                 sizerHeatingDesOutletTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2440            1 :                 state.dataSize->DataDesOutletAirTemp = sizerHeatingDesOutletTemp.size(state, DataSizing::AutoSize, ErrorsFound);
    2441              : 
    2442            1 :                 if (state.dataSize->CurOASysNum > 0) {
    2443            0 :                     auto &OASysEqSizing = state.dataSize->OASysEqSizing(state.dataSize->CurOASysNum);
    2444            0 :                     OASysEqSizing.AirFlow = true;
    2445            0 :                     OASysEqSizing.AirVolFlow = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesOutAirVolFlow;
    2446              :                 }
    2447            1 :                 TempSize = DataSizing::AutoSize; // reset back
    2448            1 :             }
    2449           36 :             ErrorsFound = false;
    2450           36 :             HeatingAirFlowSizer sizingHeatingAirFlow;
    2451           36 :             sizingHeatingAirFlow.overrideSizingString(SizingString);
    2452              :             // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    2453           36 :             sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2454           36 :             TempSize = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound);
    2455              :             // reset the design air volume flow rate for air loop coils only
    2456           36 :             if (state.dataSize->CurSysNum > 0) waterCoil.DesAirVolFlowRate = TempSize;
    2457           36 :             waterCoil.InletAirMassFlowRate = state.dataEnvrn->StdRhoAir * TempSize; // inlet air mass flow rate is not the autosized value
    2458           36 :             state.dataSize->DataAirFlowUsedForSizing = TempSize;
    2459           36 :             state.dataSize->DataFlowUsedForSizing = TempSize; // many autosized inputs use the design (autosized) air flow rate, save this value
    2460              : 
    2461           36 :             bPRINT = true;
    2462           36 :             if (waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap && NomCapUserInp) {
    2463            2 :                 TempSize = waterCoil.DesTotWaterCoilLoad;
    2464            2 :                 state.dataSize->DataNomCapInpMeth = true;
    2465              :             } else {
    2466           34 :                 TempSize = DataSizing::AutoSize;
    2467              :             }
    2468           36 :             if (state.dataSize->CurSysNum > 0) {
    2469           17 :                 FieldNum = 3; //  N3 , \field Rated Capacity
    2470           17 :                 SizingString = state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames(FieldNum) + " [W]";
    2471           17 :                 ErrorsFound = false;
    2472           17 :                 HeatingCapacitySizer sizerHeatingCapacity;
    2473           17 :                 sizerHeatingCapacity.overrideSizingString(SizingString);
    2474           17 :                 sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2475           17 :                 TempSize = sizerHeatingCapacity.size(state, TempSize, ErrorsFound);
    2476           17 :                 waterCoil.DesWaterHeatingCoilRate = TempSize;
    2477           17 :                 waterCoil.DesTotWaterCoilLoad = TempSize;
    2478           17 :                 state.dataSize->DataCapacityUsedForSizing = waterCoil.DesWaterHeatingCoilRate;
    2479           17 :             } else {
    2480           19 :                 WaterHeatingCapacitySizer sizerWaterHeatingCapacity;
    2481           19 :                 ErrorsFound = false;
    2482           19 :                 sizerWaterHeatingCapacity.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2483           19 :                 waterCoil.DesWaterHeatingCoilRate = sizerWaterHeatingCapacity.size(state, TempSize, ErrorsFound);
    2484           19 :                 waterCoil.DesTotWaterCoilLoad = waterCoil.DesWaterHeatingCoilRate;
    2485           19 :                 state.dataSize->DataCapacityUsedForSizing = waterCoil.DesWaterHeatingCoilRate;
    2486           19 :             }
    2487              : 
    2488              :             // We now have the design load if it was autosized. For the case of CoilPerfInpMeth == NomCap, calculate the air flow rate
    2489              :             // specified by the NomCap inputs. This overrides all previous values
    2490           36 :             if (waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap && NomCapUserInp) {
    2491            2 :                 waterCoil.InletAirMassFlowRate =
    2492            2 :                     waterCoil.DesTotWaterCoilLoad / (CpAirStd * (waterCoil.DesOutletAirTemp - waterCoil.DesInletAirTemp));
    2493            2 :                 waterCoil.DesAirVolFlowRate = waterCoil.InletAirMassFlowRate / state.dataEnvrn->StdRhoAir;
    2494            2 :                 state.dataSize->DataAirFlowUsedForSizing = waterCoil.DesAirVolFlowRate;
    2495            2 :                 state.dataSize->DataFlowUsedForSizing = waterCoil.DesAirVolFlowRate;
    2496              :             }
    2497              : 
    2498           36 :             TempSize = waterCoil.MaxWaterVolFlowRate;
    2499              : 
    2500           36 :             if (waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap && NomCapUserInp) {
    2501            2 :                 if (waterCoil.DesTotWaterCoilLoad > HVAC::SmallLoad) {
    2502            2 :                     waterCoil.MaxWaterVolFlowRate =
    2503            2 :                         state.dataSize->DataCapacityUsedForSizing / (Cp * rho * (waterCoil.DesInletWaterTemp - waterCoil.DesOutletWaterTemp));
    2504              :                 } else {
    2505            0 :                     waterCoil.MaxWaterVolFlowRate = 0.0;
    2506              :                 }
    2507            2 :                 state.dataSize->DataConstantUsedForSizing = waterCoil.MaxWaterVolFlowRate;
    2508            2 :                 state.dataSize->DataFractionUsedForSizing = 1.0;
    2509              :             }
    2510           36 :             HeatingWaterflowSizer sizerHWWaterflow;
    2511           36 :             sizerHWWaterflow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2512           36 :             Real64 sizedMaxWaterVolFlowRate = sizerHWWaterflow.size(state, TempSize, ErrorsFound);
    2513              :             // Check if the water flow rate is defined in parent HVAC equipment and set water coil design water flow rate accordingly
    2514           36 :             if (state.dataSize->CurZoneEqNum > 0) {
    2515           19 :                 auto const &ZoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
    2516           19 :                 if (ZoneEqSizing.DesignSizeFromParent) {
    2517            8 :                     state.dataSize->DataWaterFlowUsedForSizing = ZoneEqSizing.MaxHWVolFlow;
    2518            8 :                     waterCoil.MaxWaterVolFlowRate = ZoneEqSizing.MaxHWVolFlow;
    2519              :                 } else {
    2520           11 :                     state.dataSize->DataWaterFlowUsedForSizing = sizedMaxWaterVolFlowRate;
    2521           11 :                     waterCoil.MaxWaterVolFlowRate = sizedMaxWaterVolFlowRate;
    2522              :                 }
    2523              :             } else {
    2524           17 :                 state.dataSize->DataWaterFlowUsedForSizing = sizedMaxWaterVolFlowRate;
    2525           17 :                 waterCoil.MaxWaterVolFlowRate = sizedMaxWaterVolFlowRate;
    2526              :             }
    2527           36 :             state.dataSize->DataConstantUsedForSizing = 0.0; // reset these in case NomCapUserInp was true
    2528           36 :             state.dataSize->DataFractionUsedForSizing = 0.0;
    2529           36 :             if (waterCoil.MaxWaterVolFlowRate <= 0.0) {
    2530              :                 //                    MaxWaterVolFlowRateDes = 0.0;
    2531            0 :                 ShowWarningError(state, format("The design coil load is zero for Coil:Heating:Water {}", waterCoil.Name));
    2532            0 :                 ShowContinueError(state, "The autosize value for maximum water flow rate is zero");
    2533            0 :                 ShowContinueError(state, "To change this, input a value for UA, change the heating design day, or raise the");
    2534            0 :                 ShowContinueError(state, "  system heating design supply air temperature. Also check to make sure the Preheat");
    2535            0 :                 ShowContinueError(state, "  Design Temperature is not the same as the Central Heating Design Supply Air Temperature. ");
    2536              :             }
    2537              : 
    2538              :             // initialize the water coil inlet conditions
    2539           36 :             bPRINT = false; // no need to print to eio since we only need the values
    2540           36 :             state.dataSize->DataFlowUsedForSizing = state.dataSize->DataAirFlowUsedForSizing;
    2541           36 :             if (waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap && NomCapUserInp) {
    2542            2 :                 waterCoil.InletAirTemp = waterCoil.DesInletAirTemp;
    2543            2 :                 waterCoil.InletAirHumRat = PsyWFnTdbRhPb(state, waterCoil.DesInletAirTemp, 0.5, state.dataEnvrn->StdBaroPress, RoutineName);
    2544            2 :                 waterCoil.InletAirMassFlowRate = state.dataSize->DataAirFlowUsedForSizing * state.dataEnvrn->StdRhoAir; // don't need this
    2545            2 :                 state.dataSize->DataDesOutletAirTemp = waterCoil.DesOutletAirTemp;                                      // for error messages
    2546            4 :                 state.dataSize->DataDesOutletAirHumRat =
    2547            2 :                     PsyWFnTdbRhPb(state, state.dataSize->DataDesOutletAirTemp, 0.5, state.dataEnvrn->StdBaroPress, RoutineName); // for error messages
    2548            2 :                 waterCoil.InletWaterMassFlowRate = rho * state.dataSize->DataWaterFlowUsedForSizing;
    2549            2 :                 waterCoil.MaxWaterMassFlowRate = rho * state.dataSize->DataWaterFlowUsedForSizing;
    2550            2 :                 waterCoil.InletWaterTemp = waterCoil.DesInletWaterTemp;
    2551           34 :             } else if (waterCoil.DesiccantRegenerationCoil) {
    2552            1 :                 waterCoil.InletAirTemp = state.dataSize->DataDesInletAirTemp;
    2553            1 :                 HeatingCoilDesAirInletHumRatSizer sizerHeatingDesInletHumRat;
    2554            1 :                 ErrorsFound = false;
    2555            1 :                 sizerHeatingDesInletHumRat.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2556            1 :                 waterCoil.DesInletAirHumRat = sizerHeatingDesInletHumRat.size(state, DataSizing::AutoSize, ErrorsFound);
    2557            1 :                 waterCoil.InletAirHumRat = waterCoil.DesInletAirHumRat;
    2558              : 
    2559            1 :                 waterCoil.DesAirVolFlowRate = state.dataSize->DataAirFlowUsedForSizing;                                 // coil report
    2560            1 :                 waterCoil.InletAirMassFlowRate = state.dataSize->DataAirFlowUsedForSizing * state.dataEnvrn->StdRhoAir; // this is stiil volume flow!
    2561            1 :             } else {
    2562           33 :                 HeatingWaterDesAirInletTempSizer sizerHWDesInletTemp;
    2563           33 :                 sizerHWDesInletTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2564           33 :                 waterCoil.InletAirTemp = sizerHWDesInletTemp.size(state, DataSizing::AutoSize, ErrorsFound);
    2565              : 
    2566           33 :                 HeatingWaterDesAirInletHumRatSizer sizerHWAirInletHumRat;
    2567           33 :                 sizerHWAirInletHumRat.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2568           33 :                 waterCoil.DesInletAirHumRat = sizerHWAirInletHumRat.size(state, DataSizing::AutoSize, ErrorsFound);
    2569           33 :                 waterCoil.InletAirHumRat = waterCoil.DesInletAirHumRat;
    2570              : 
    2571           33 :                 HeatingAirflowUASizer sizerHWAirFlowUA;
    2572           33 :                 sizerHWAirFlowUA.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2573           33 :                 waterCoil.DesAirMassFlowRate = sizerHWAirFlowUA.size(state, DataSizing::AutoSize, ErrorsFound);
    2574           33 :                 waterCoil.InletAirMassFlowRate = waterCoil.DesAirMassFlowRate;
    2575           33 :             }
    2576              : 
    2577              :             // zone and air loop coils use different design coil load calculations, air loop coils use air side capacity,
    2578              :             // zone coils use water side capacity
    2579           36 :             state.dataSize->DataDesInletAirTemp = waterCoil.InletAirTemp;                                                  // used in error mesages
    2580           36 :             state.dataSize->DataDesInletAirHumRat = waterCoil.InletAirHumRat;                                              // used in error mesages
    2581           36 :             state.dataSize->DataFlowUsedForSizing = state.dataSize->DataAirFlowUsedForSizing * state.dataEnvrn->StdRhoAir; // used in error mesages
    2582           36 :             waterCoil.MaxWaterVolFlowRate = state.dataSize->DataWaterFlowUsedForSizing;                                    // why is this here?
    2583           36 :             if (!(waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap && NomCapUserInp)) {
    2584              :                 // get the design coil load used to size UA
    2585           34 :                 HeatingWaterDesCoilLoadUsedForUASizer sizerHWDesCoilLoadForUA;
    2586           34 :                 sizerHWDesCoilLoadForUA.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2587           34 :                 state.dataSize->DataCapacityUsedForSizing = sizerHWDesCoilLoadForUA.size(state, DataSizing::AutoSize, ErrorsFound);
    2588              :                 // get the water volume flow rate used to size UA
    2589           34 :                 HeatingWaterDesCoilWaterVolFlowUsedForUASizer sizerHWWaterVolFlowUA;
    2590           34 :                 sizerHWWaterVolFlowUA.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2591           34 :                 state.dataSize->DataWaterFlowUsedForSizing = sizerHWWaterVolFlowUA.size(state, DataSizing::AutoSize, ErrorsFound);
    2592           34 :                 waterCoil.InletWaterTemp = state.dataSize->PlantSizData(PltSizHeatNum).ExitTemp;
    2593           34 :                 waterCoil.InletWaterMassFlowRate = rho * state.dataSize->DataWaterFlowUsedForSizing;
    2594           34 :                 waterCoil.MaxWaterMassFlowRate = rho * state.dataSize->DataWaterFlowUsedForSizing;
    2595           34 :                 waterCoil.DesWaterHeatingCoilRate = state.dataSize->DataCapacityUsedForSizing;
    2596           34 :             }
    2597              :             // calculate UA
    2598           36 :             if (state.dataSize->CurSysNum > 0) waterCoil.DesTotWaterCoilLoad = state.dataSize->DataCapacityUsedForSizing;
    2599           36 :             FieldNum = 1;  // N1 , \field U-Factor Times Area Value
    2600           36 :             bPRINT = true; // report to eio the UA value
    2601           36 :             SizingString = state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames(FieldNum) + " [W/K]";
    2602           36 :             state.dataSize->DataCoilNum = CoilNum;
    2603           36 :             state.dataSize->DataFanOp = HVAC::FanOp::Continuous;
    2604           36 :             if (waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap && NomCapUserInp) {
    2605            2 :                 TempSize = DataSizing::AutoSize;
    2606              :             } else {
    2607           34 :                 TempSize = waterCoil.UACoil;
    2608              :             }
    2609              : 
    2610           36 :             state.dataSize->DataFlowUsedForSizing = waterCoil.InletAirMassFlowRate;
    2611           36 :             DesCoilWaterInTempSaved = state.dataWaterCoils->WaterCoil(state.dataSize->DataCoilNum).InletWaterTemp;
    2612           36 :             if (DesCoilWaterInTempSaved < HVAC::DesCoilHWInletTempMin) {
    2613              :                 // at low coil design water inlet temp, sizing has convergence issue hence slightly higher water inlet temperature
    2614              :                 // is estimated in "EstimateCoilInletWaterTemp" and used for UA autosizing only
    2615            8 :                 EstimateCoilInletWaterTemp(state,
    2616            8 :                                            state.dataSize->DataCoilNum,
    2617            8 :                                            state.dataSize->DataFanOp,
    2618              :                                            1.0,
    2619            8 :                                            state.dataSize->DataCapacityUsedForSizing,
    2620              :                                            DesCoilInletWaterTempUsed);
    2621            8 :                 state.dataWaterCoils->WaterCoil(state.dataSize->DataCoilNum).InletWaterTemp = DesCoilInletWaterTempUsed;
    2622              :             }
    2623              :             // must set DataCapacityUsedForSizing, DataWaterFlowUsedForSizing and DataFlowUsedForSizing to size UA. Any value of 0 will result
    2624              :             // in UA = 1.
    2625           36 :             WaterHeatingCoilUASizer sizerHWCoilUA;
    2626           36 :             sizerHWCoilUA.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    2627           36 :             waterCoil.UACoil = sizerHWCoilUA.size(state, TempSize, ErrorsFound);
    2628           36 :             if (DesCoilWaterInTempSaved < HVAC::DesCoilHWInletTempMin) {
    2629            8 :                 ShowWarningError(state, format("Autosizing of heating coil UA for Coil:Heating:Water \"{}\"", CompName));
    2630           16 :                 ShowContinueError(state,
    2631           16 :                                   format(" Plant design loop exit temperature = {:.2T} C",
    2632            8 :                                          state.dataSize->PlantSizData(state.dataSize->DataPltSizHeatNum).ExitTemp));
    2633           16 :                 ShowContinueError(state, " Plant design loop exit temperature is low for design load and leaving air temperature anticipated.");
    2634           16 :                 ShowContinueError(state,
    2635           16 :                                   format(" Heating coil UA-value is sized using coil water inlet temperature = {:.2T} C", DesCoilInletWaterTempUsed));
    2636            8 :                 state.dataWaterCoils->WaterCoil(state.dataSize->DataCoilNum).InletWaterTemp =
    2637              :                     DesCoilWaterInTempSaved; // reset the Design Coil Inlet Water Temperature
    2638              :             }
    2639              :             // if coil UA did not size due to one of these variables being 0, must set UACoilVariable to avoid crash later on
    2640           72 :             if (state.dataSize->DataCapacityUsedForSizing == 0.0 || state.dataSize->DataWaterFlowUsedForSizing == 0.0 ||
    2641           36 :                 state.dataSize->DataFlowUsedForSizing == 0.0) {
    2642            2 :                 if (waterCoil.UACoilVariable == DataSizing::AutoSize) {
    2643            0 :                     waterCoil.UACoilVariable = waterCoil.UACoil;
    2644              :                 }
    2645              :             }
    2646              :             // WaterCoil(CoilNum).UACoilVariable = WaterCoil(CoilNum).UACoil;
    2647           36 :             waterCoil.DesWaterHeatingCoilRate = state.dataSize->DataCapacityUsedForSizing;
    2648           36 :             state.dataWaterCoils->WaterCoil(state.dataSize->DataCoilNum).InletWaterTemp =
    2649              :                 DesCoilWaterInTempSaved; // reset the Design Coil Inlet Water Temperature
    2650              : 
    2651           36 :             state.dataSize->DataWaterLoopNum = 0; // reset all globals to 0 to ensure correct sizing for other child components
    2652           36 :             state.dataSize->DataPltSizHeatNum = 0;
    2653           36 :             state.dataSize->DataCoilNum = 0;
    2654           36 :             state.dataSize->DataFanOp = HVAC::FanOp::Invalid;
    2655           36 :             state.dataSize->DataCapacityUsedForSizing = 0.0;
    2656           36 :             state.dataSize->DataWaterFlowUsedForSizing = 0.0;
    2657           36 :             state.dataSize->DataDesInletAirTemp = 0.0;
    2658           36 :             state.dataSize->DataDesInletAirHumRat = 0.0;
    2659           36 :             state.dataSize->DataDesOutletAirTemp = 0.0;
    2660           36 :             state.dataSize->DataDesOutletAirHumRat = 0.0;
    2661           36 :             state.dataSize->DataAirFlowUsedForSizing = 0.0;
    2662           36 :             state.dataSize->DataFlowUsedForSizing = 0.0;
    2663           36 :             state.dataSize->DataDesicDehumNum = 0;
    2664           36 :             state.dataSize->DataDesicRegCoil = false;
    2665           36 :             state.dataSize->DataWaterCoilSizHeatDeltaT = 0.0;
    2666           36 :             state.dataSize->DataNomCapInpMeth = false;
    2667              : 
    2668           36 :         } else {
    2669              :             // if there is no heating Plant Sizing object and autosizng was requested, issue an error message
    2670           14 :             if (waterCoil.RequestingAutoSize) {
    2671            0 :                 ShowSevereError(state, "Autosizing of water coil requires a heating loop Sizing:Plant object");
    2672            0 :                 ShowContinueError(state, format("Occurs in water coil object= {}", waterCoil.Name));
    2673            0 :                 ErrorsFound = true;
    2674              :             }
    2675              :         }
    2676              :         //} // end of heating Plant Sizing existence IF - ELSE
    2677              :     } // end heating coil IF
    2678              : 
    2679              :     // save the design water volumetric flow rate for use by the water loop sizing algorithms
    2680           94 :     if (waterCoil.MaxWaterVolFlowRate > 0.0) {
    2681           91 :         PlantUtilities::RegisterPlantCompDesignFlow(state, waterCoil.WaterInletNodeNum, waterCoil.MaxWaterVolFlowRate);
    2682              :     }
    2683              : 
    2684           94 :     if (ErrorsFound || state.dataSize->DataErrorsFound) {
    2685            0 :         ShowFatalError(state, "Preceding water coil sizing errors cause program termination");
    2686              :     }
    2687           94 : }
    2688              : 
    2689              : // End Initialization Section of the Module
    2690              : //******************************************************************************
    2691              : 
    2692              : // Begin Algorithm Section of the Module
    2693              : //******************************************************************************
    2694              : 
    2695       165479 : void CalcSimpleHeatingCoil(EnergyPlusData &state,
    2696              :                            int const CoilNum,          // index to heating coil
    2697              :                            HVAC::FanOp const fanOp,    // fan operating mode
    2698              :                            Real64 const PartLoadRatio, // part-load ratio of heating coil
    2699              :                            int const CalcMode          // 1 = design calc; 2 = simulation calculation
    2700              : )
    2701              : {
    2702              :     // SUBROUTINE INFORMATION:
    2703              :     //       AUTHOR         Rich Liesen
    2704              :     //       DATE WRITTEN
    2705              :     //       MODIFIED       Aug. 2007 - R. Raustad, added fan operating mode and part-load ratio to
    2706              :     //                                  calculate the outlet conditions when fan and coil cycle.
    2707              :     //                                  Air and water outlet temperature are full output with average
    2708              :     //                                  air and water mass flow rate when fan and coil cycle.
    2709              :     //       RE-ENGINEERED  na
    2710              : 
    2711              :     // PURPOSE OF THIS SUBROUTINE:
    2712              :     // Simulates a simple NTU effectiveness model heating coil
    2713              : 
    2714              :     // METHODOLOGY EMPLOYED:
    2715              :     // (1) outlet conditions are calculated from the effectiveness and the inlet conditions.
    2716              :     // (2) Effectiveness is calculated from the NTU formula for a cross flow heat exchanger
    2717              :     //     with both streams unmixed.
    2718              :     // Note: UA is input by user and is fixed.
    2719              : 
    2720              :     // REFERENCES:
    2721              :     // See for instance ASHRAE HVAC 2 Toolkit, page 4-4, formula (4-7)
    2722              : 
    2723              :     // Using/Aliasing
    2724              : 
    2725              :     // Locals
    2726              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    2727              : 
    2728              :     // SUBROUTINE PARAMETER DEFINITIONS:
    2729              :     static constexpr std::string_view RoutineName("CalcSimpleHeatingCoil");
    2730              : 
    2731              :     // INTERFACE BLOCK SPECIFICATIONS
    2732              :     // na
    2733              : 
    2734              :     // DERIVED TYPE DEFINITIONS
    2735              :     // na
    2736              : 
    2737              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2738              :     Real64 WaterMassFlowRate;
    2739              :     Real64 AirMassFlow; // [kg/sec]
    2740              :     Real64 TempAirIn;   // [C]
    2741              :     Real64 TempAirOut;  // [C]
    2742              :     Real64 Win;
    2743              :     Real64 TempWaterIn;
    2744              :     Real64 TempWaterOut;
    2745              :     Real64 UA;
    2746              :     Real64 CapacitanceAir;
    2747              :     Real64 CapacitanceWater;
    2748              :     Real64 CapacitanceMin;
    2749              :     Real64 CapacitanceMax;
    2750              :     Real64 HeatingCoilLoad;
    2751              :     Real64 NTU;
    2752              :     Real64 ETA;
    2753              :     Real64 A;
    2754              :     Real64 CapRatio;
    2755              :     Real64 E1;
    2756              :     Real64 E2;
    2757              :     Real64 Effec;
    2758              :     Real64 Cp;
    2759              : 
    2760       165479 :     auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    2761       165479 :     UA = waterCoil.UACoilVariable;
    2762       165479 :     TempAirIn = waterCoil.InletAirTemp;
    2763       165479 :     Win = waterCoil.InletAirHumRat;
    2764       165479 :     TempWaterIn = waterCoil.InletWaterTemp;
    2765              : 
    2766              :     // adjust mass flow rates for cycling fan cycling coil operation
    2767       165479 :     if (fanOp == HVAC::FanOp::Cycling) {
    2768       130405 :         if (PartLoadRatio > 0.0) {
    2769        91067 :             AirMassFlow = waterCoil.InletAirMassFlowRate / PartLoadRatio;
    2770        91067 :             WaterMassFlowRate = min(waterCoil.InletWaterMassFlowRate / PartLoadRatio, waterCoil.MaxWaterMassFlowRate);
    2771              :         } else {
    2772        39338 :             AirMassFlow = 0.0;
    2773        39338 :             WaterMassFlowRate = 0.0;
    2774              :         }
    2775              :     } else {
    2776        35074 :         AirMassFlow = waterCoil.InletAirMassFlowRate;
    2777        35074 :         WaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
    2778              :     }
    2779              : 
    2780       165479 :     if (WaterMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) { // If the coil is operating
    2781        59378 :         CapacitanceAir = PsyCpAirFnW(Win) * AirMassFlow;
    2782        59378 :         Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, TempWaterIn, RoutineName);
    2783        59378 :         CapacitanceWater = Cp * WaterMassFlowRate;
    2784        59378 :         CapacitanceMin = min(CapacitanceAir, CapacitanceWater);
    2785        59378 :         CapacitanceMax = max(CapacitanceAir, CapacitanceWater);
    2786              :     } else {
    2787       106101 :         CapacitanceAir = 0.0;
    2788       106101 :         CapacitanceWater = 0.0;
    2789              :     }
    2790              : 
    2791              :     // If the coil is operating there should be some heating capacitance
    2792              :     //  across the coil, so do the simulation. If not set outlet to inlet and no load.
    2793              :     //  Also the coil has to be scheduled to be available
    2794       224855 :     if (((CapacitanceAir > 0.0) && (CapacitanceWater > 0.0)) &&
    2795        59376 :         (CalcMode == state.dataWaterCoils->DesignCalc || state.dataWaterCoils->MySizeFlag(CoilNum) ||
    2796        58799 :          state.dataWaterCoils->MyUAAndFlowCalcFlag(CoilNum) || waterCoil.availSched->getCurrentVal() > 0.0)) {
    2797              : 
    2798        57958 :         if (UA <= 0.0) {
    2799            0 :             ShowFatalError(state, format("UA is zero for COIL:Heating:Water {}", waterCoil.Name));
    2800              :         }
    2801        57958 :         NTU = UA / CapacitanceMin;
    2802        57958 :         ETA = std::pow(NTU, 0.22);
    2803        57958 :         CapRatio = CapacitanceMin / CapacitanceMax;
    2804        57958 :         A = CapRatio * NTU / ETA;
    2805              : 
    2806        57958 :         if (A > 20.0) {
    2807            0 :             A = ETA * 1.0 / CapRatio;
    2808              :         } else {
    2809        57958 :             E1 = std::exp(-A);
    2810        57958 :             A = ETA * (1.0 - E1) / CapRatio;
    2811              :         }
    2812              : 
    2813        57958 :         if (A > 20.0) {
    2814           11 :             Effec = 1.0;
    2815              :         } else {
    2816        57947 :             E2 = std::exp(-A);
    2817        57947 :             Effec = 1.0 - E2;
    2818              :         }
    2819              : 
    2820        57958 :         TempAirOut = TempAirIn + Effec * CapacitanceMin * (TempWaterIn - TempAirIn) / CapacitanceAir;
    2821        57958 :         TempWaterOut = TempWaterIn - CapacitanceAir * (TempAirOut - TempAirIn) / CapacitanceWater;
    2822        57958 :         HeatingCoilLoad = CapacitanceWater * (TempWaterIn - TempWaterOut);
    2823              :         // The HeatingCoilLoad is the change in the enthalpy of the water
    2824        57958 :         waterCoil.OutletWaterEnthalpy = waterCoil.InletWaterEnthalpy - HeatingCoilLoad / waterCoil.InletWaterMassFlowRate;
    2825        57958 :         waterCoil.OutletWaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
    2826              : 
    2827              :     } else { // If not running Conditions do not change across coil from inlet to outlet
    2828              : 
    2829       107521 :         TempAirOut = TempAirIn;
    2830       107521 :         TempWaterOut = TempWaterIn;
    2831       107521 :         HeatingCoilLoad = 0.0;
    2832       107521 :         waterCoil.OutletWaterEnthalpy = waterCoil.InletWaterEnthalpy;
    2833       107521 :         waterCoil.OutletWaterMassFlowRate = 0.0;
    2834              :     }
    2835              : 
    2836       165479 :     if (fanOp == HVAC::FanOp::Cycling) {
    2837       130405 :         HeatingCoilLoad *= PartLoadRatio;
    2838              :     }
    2839              : 
    2840              :     // Set the outlet conditions
    2841       165479 :     waterCoil.TotWaterHeatingCoilRate = HeatingCoilLoad;
    2842       165479 :     waterCoil.OutletAirTemp = TempAirOut;
    2843       165479 :     waterCoil.OutletWaterTemp = TempWaterOut;
    2844              : 
    2845              :     // This WaterCoil does not change the moisture or Mass Flow across the component
    2846       165479 :     waterCoil.OutletAirHumRat = waterCoil.InletAirHumRat;
    2847       165479 :     waterCoil.OutletAirMassFlowRate = waterCoil.InletAirMassFlowRate;
    2848              :     // Set the outlet enthalpys for air and water
    2849       165479 :     waterCoil.OutletAirEnthalpy = PsyHFnTdbW(waterCoil.OutletAirTemp, waterCoil.OutletAirHumRat);
    2850       165479 : }
    2851              : 
    2852         8442 : void CalcDetailFlatFinCoolingCoil(EnergyPlusData &state,
    2853              :                                   int const CoilNum,
    2854              :                                   int const CalcMode,
    2855              :                                   HVAC::FanOp const fanOp,   // fan operating mode
    2856              :                                   Real64 const PartLoadRatio // part-load ratio of heating coil
    2857              : )
    2858              : {
    2859              : 
    2860              :     // SUBROUTINE INFORMATION:
    2861              :     //       AUTHOR(S)      Russell Taylor / Richard Liesen
    2862              :     //       DATE WRITTEN   Mar 1997
    2863              :     //       MODIFIED       Feb 2010, B. Nigusse, FSEC, corrected units inconsistency for tube and fins
    2864              :     //                      materials thermal conductivties. Now input values in the idf are in {W/(m.K)}
    2865              :     //       RE-ENGINEERED  Sept 1998
    2866              : 
    2867              :     // PURPOSE OF THIS SUBROUTINE:
    2868              :     // This subroutine simulates a chilled water cooling coil.  Provided with
    2869              :     // the coil geometry and the flow (i.e. air and water) inlet conditions,
    2870              :     // it will calculate the flow outlet conditions and the total and latent
    2871              :     // heat extraction rates from the air.  The coil model has some limitations
    2872              :     // as noted in the code.
    2873              : 
    2874              :     // METHODOLOGY EMPLOYED:
    2875              :     // successive substitution, solve coil as if all wet, then
    2876              :     // again if partly or entirely dry
    2877              : 
    2878              :     // REFERENCES:
    2879              :     // First found in Type 12 from MODSIM, but now
    2880              :     // programmed directly from Elmahdy, A.H. and Mitalas, G.P.  "A
    2881              :     // Simple Model for Cooling and Dehumidifying Coils for Use in
    2882              :     // Calculating Energy Requirements for Buildings"  _ASHRAE
    2883              :     // Transactions_ Vol. 83, Part 2, pp. 103-117 (1977).
    2884              : 
    2885              :     // OTHER NOTES:
    2886              :     // Routine was originally adapted for use in IBLAST by R.D. Taylor in l993.
    2887              :     // Subsequently rewritten and improved by J.C. Vanderzee in 1994
    2888              :     // Revised and further enhanced by R.D. Taylor in Jan 1996
    2889              :     // Re-engineered for EnergyPlus by Richard Liesen PhD in 1998
    2890              : 
    2891              :     // Using/Aliasing
    2892              : 
    2893              :     // Locals
    2894              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    2895              : 
    2896              :     // SUBROUTINE PARAMETER DEFINITIONS:
    2897              :     static Real64 const exp_47(std::exp(-0.41718));
    2898              :     static Real64 const exp_35(std::exp(-0.3574));
    2899              :     static constexpr std::string_view RoutineName("CalcDetailFlatFinCoolingCoil");
    2900              : 
    2901         8442 :     constexpr Real64 AirViscosity(1.846e-5); // Dynamic Viscosity of Air in kg/(m.s)
    2902         8442 :     constexpr Real64 ConvK(1.0e-3);          // Unit conversion factor
    2903         8442 :     constexpr Real64 unity(1.0);
    2904         8442 :     constexpr Real64 zero(0.0);
    2905         8442 :     constexpr Real64 TubeFoulFactor(5.0e-2); // Inside tube fouling factor for water, in m2K/kW
    2906              :     // Changed from m2K/W to m2K/kW for consistency with the
    2907              :     // other parameters in "TubeFoulThermResis" calculation
    2908              : 
    2909              :     // INTERFACE BLOCK SPECIFICATIONS
    2910              :     // na
    2911              : 
    2912              :     // DERIVED TYPE DEFINITIONS
    2913              :     // na
    2914              : 
    2915              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2916              :     //    INTEGER :: CoolCoilErrs = 0
    2917              : 
    2918              :     Real64 AirEnthAtRsdInletWaterTemp;
    2919              :     Real64 AirExitEnthlAtCoilSurfTemp;
    2920              :     Real64 AirExitCoilSurfTemp;
    2921              :     Real64 AirReynoldsNo;
    2922              :     Real64 AirEnthAtWetDryIntrfcSurfTemp;
    2923              :     Real64 AirSideDrySurfFilmCoef;
    2924              :     Real64 AirSideWetSurfFilmCoef;
    2925              :     Real64 AirWetDryInterfcTemp;
    2926              :     Real64 CoilToAirThermResistDrySurf;
    2927              :     Real64 CoilToAirThermResistWetSurf;
    2928              :     Real64 DryAirSpecHeat;
    2929              :     Real64 DryCoilCoeff1;
    2930              :     Real64 DryCoilCoeff;
    2931              :     Real64 DryCoilEfficiency;
    2932              :     Real64 DryFinEfficncy;
    2933              :     Real64 DryCoilInThermResist;
    2934              :     Real64 DrySideEffectiveWaterTemp;
    2935              :     Real64 EnterAirDewPoint;
    2936              :     Real64 EnterAirHumRatDiff;
    2937              :     Real64 WetDryInterSurfTempErrorLast;
    2938              :     Real64 WetDryInterSurfTempError;
    2939              :     Real64 expon;
    2940              :     Real64 FilmCoefEqnFactor;
    2941              :     Real64 FilmCoefReynldsCorrelatnFact;
    2942              :     Real64 FinToTotSurfAreaRatio;
    2943              :     Real64 InCoilSurfTemp;
    2944              :     Real64 InsdToOutsdThermResistRatio;
    2945              :     Real64 InSurfTempSatAirEnthl;
    2946              :     Real64 K1;
    2947              :     Real64 MeanWaterTemp;
    2948              :     Real64 MoistAirSpecificHeat;
    2949              :     Real64 OutCoilSurfTemp;
    2950              :     Real64 OutSurfTempSatAirEnthl;
    2951              :     Real64 RaisedInletWaterTemp;
    2952              :     Real64 RsdInletWaterTempSatAirHumRat;
    2953              :     Real64 ScaledAirMassFlowRate;
    2954              :     Real64 ScaledCoilAirThermResistWetSurf;
    2955              :     Real64 ScaledWaterSpecHeat;
    2956              :     Real64 ScaledWaterToTubeThermResist;
    2957              :     Real64 SensToTotEnthDiffRatio;
    2958              :     Real64 SurfAreaWet;
    2959              :     Real64 TubeFoulThermResist;
    2960              :     Real64 TubeWaterVel;
    2961              :     Real64 UACoilAllWet;
    2962              :     Real64 UACoilPartWet;
    2963              :     Real64 UADryCoil;
    2964              :     Real64 WaterToTubeThermResist;
    2965              :     Real64 WetAreaChange;
    2966              :     Real64 WetAreaLast;
    2967              :     Real64 WetCoilCoeff;
    2968              :     Real64 WetCoilFinEfficncy;
    2969              :     Real64 WetDryInterfcAirEnthl;
    2970              :     Real64 WetDryInterfcSurfTemp;
    2971              :     Real64 WetDryInterfcWaterTemp;
    2972              :     Real64 WetFinEfficncy;
    2973              :     Real64 WetSideEffctvWaterTemp;
    2974              :     Real64 y;
    2975              :     Real64 TempAirIn;
    2976              :     Real64 TempAirOut;
    2977              :     Real64 InletAirHumRat;
    2978              :     Real64 OutletAirHumRat;
    2979              :     Real64 InletAirEnthalpy;
    2980              :     Real64 OutletAirEnthalpy;
    2981              :     Real64 WaterMassFlowRate;
    2982              :     Real64 AirMassFlow;
    2983              :     Real64 TempWaterIn;
    2984              :     Real64 TempWaterOut;
    2985              :     Real64 TotWaterCoilLoad;
    2986              :     Real64 SenWaterCoilLoad;
    2987              :     Real64 AirDensity;
    2988              :     Real64 AirVelocity;
    2989              :     Real64 denom;
    2990              :     Real64 rho;
    2991              :     Real64 Cp;
    2992              : 
    2993              :     // Set derived type variables to shorter local variables
    2994         8442 :     auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    2995         8442 :     TempAirIn = waterCoil.InletAirTemp;
    2996         8442 :     InletAirHumRat = waterCoil.InletAirHumRat;
    2997         8442 :     TempWaterIn = waterCoil.InletWaterTemp;
    2998              : 
    2999              :     //  adjust mass flow rates for cycling fan cycling coil operation
    3000         8442 :     if (fanOp == HVAC::FanOp::Cycling) {
    3001            0 :         if (PartLoadRatio > 0.0) {
    3002            0 :             AirMassFlow = waterCoil.InletAirMassFlowRate / PartLoadRatio;
    3003            0 :             WaterMassFlowRate = min(waterCoil.InletWaterMassFlowRate / PartLoadRatio, waterCoil.MaxWaterMassFlowRate);
    3004              :         } else {
    3005            0 :             AirMassFlow = 0.0;
    3006            0 :             WaterMassFlowRate = 0.0;
    3007              :         }
    3008              :     } else {
    3009         8442 :         AirMassFlow = waterCoil.InletAirMassFlowRate;
    3010         8442 :         WaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
    3011              :     }
    3012              : 
    3013         8442 :     if (WaterMassFlowRate < waterCoil.MaxWaterMassFlowRate * WaterCoils::MinWaterMassFlowFrac) {
    3014         3470 :         WaterMassFlowRate = 0.0;
    3015              :     }
    3016         8442 :     if (TempAirIn <= TempWaterIn) {
    3017            3 :         WaterMassFlowRate = 0.0;
    3018              :     }
    3019         8442 :     WetDryInterfcAirEnthl = 0.0;
    3020         8442 :     OutletAirEnthalpy = 0.0;
    3021         8442 :     InletAirEnthalpy = 0.0;
    3022              : 
    3023              :     // Warning and error messages for large flow rates for the given user input geometry
    3024         8442 :     AirDensity = PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, TempAirIn, InletAirHumRat, RoutineName);
    3025         8442 :     if (AirMassFlow > (5.0 * waterCoil.MinAirFlowArea / AirDensity) && state.dataWaterCoils->CoilWarningOnceFlag(CoilNum)) {
    3026            1 :         ShowWarningError(state, format("Coil:Cooling:Water:DetailedGeometry in Coil ={}", waterCoil.Name));
    3027            2 :         ShowContinueError(state, "Air Flow Rate Velocity has greatly exceeded upper design guidelines of ~2.5 m/s");
    3028            1 :         ShowContinueError(state, format("Air Mass Flow Rate[kg/s]={:.6T}", AirMassFlow));
    3029              :         // [m/s] = [kg/s] / ([m2] * [kg/m3])
    3030            1 :         AirVelocity = AirMassFlow / (waterCoil.MinAirFlowArea * AirDensity);
    3031            1 :         ShowContinueError(state, format("Air Face Velocity[m/s]={:.6T}", AirVelocity));
    3032            1 :         ShowContinueError(state, format("Approximate Mass Flow Rate limit for Face Area[kg/s]={:.6T}", 2.5 * waterCoil.MinAirFlowArea * AirDensity));
    3033            2 :         ShowContinueError(state, "Coil:Cooling:Water:DetailedGeometry could be resized/autosized to handle capacity");
    3034            1 :         state.dataWaterCoils->CoilWarningOnceFlag(CoilNum) = false;
    3035         8441 :     } else if (AirMassFlow > (44.7 * waterCoil.MinAirFlowArea * AirDensity)) {
    3036            1 :         ShowSevereError(state, format("Coil:Cooling:Water:DetailedGeometry in Coil ={}", waterCoil.Name));
    3037            2 :         ShowContinueError(state, "Air Flow Rate Velocity is > 100MPH (44.7m/s) and simulation cannot continue");
    3038            1 :         ShowContinueError(state, format("Air Mass Flow Rate[kg/s]={:.6T}", AirMassFlow));
    3039            1 :         AirVelocity = AirMassFlow / (waterCoil.MinAirFlowArea * AirDensity);
    3040            1 :         ShowContinueError(state, format("Air Face Velocity[m/s]={:.6T}", AirVelocity));
    3041            1 :         ShowContinueError(state, format("Approximate Mass Flow Rate limit for Face Area[kg/s]={:.6T}", 44.7 * waterCoil.MinAirFlowArea * AirDensity));
    3042            3 :         ShowFatalError(state, "Coil:Cooling:Water:DetailedGeometry needs to be resized/autosized to handle capacity");
    3043              :     }
    3044              : 
    3045              :     // If Coil is Scheduled ON then do the simulation
    3046        11914 :     if (((waterCoil.availSched->getCurrentVal() > 0.0) && (WaterMassFlowRate > 0.0) && (AirMassFlow >= WaterCoils::MinAirMassFlow)) ||
    3047         3473 :         (CalcMode == state.dataWaterCoils->DesignCalc)) {
    3048              :         //        transfer inputs to simulation variables and calculate
    3049              :         //        known thermodynamic functions
    3050              :         // All coil calcs are done in KJoules.  Convert to KJ here and then convert
    3051              :         //  back to Joules at the end of the Subroutine.
    3052         4968 :         DryAirSpecHeat = PsyCpAirFnW(zero) * ConvK;
    3053         4968 :         MoistAirSpecificHeat = PsyCpAirFnW(InletAirHumRat) * ConvK;
    3054         4968 :         InletAirEnthalpy = waterCoil.InletAirEnthalpy * ConvK;
    3055              : 
    3056         4968 :         EnterAirDewPoint = PsyTdpFnWPb(state, InletAirHumRat, state.dataEnvrn->OutBaroPress, RoutineName);
    3057              :         //       Ratio of secondary (fin) to total (secondary plus primary) surface areas
    3058         4968 :         FinToTotSurfAreaRatio = waterCoil.FinSurfArea / waterCoil.TotCoilOutsideSurfArea;
    3059              :         //      known water and air flow parameters:
    3060         4968 :         rho = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getDensity(state, TempWaterIn, RoutineName);
    3061              :         //      water flow velocity - assuming number of water circuits = NumOfTubesPerRow
    3062         4968 :         TubeWaterVel =
    3063         4968 :             WaterMassFlowRate * 4.0 / (waterCoil.NumOfTubesPerRow * rho * Constant::Pi * waterCoil.TubeInsideDiam * waterCoil.TubeInsideDiam);
    3064              :         //      air mass flow rate per unit area
    3065         4968 :         ScaledAirMassFlowRate = (1.0 + InletAirHumRat) * AirMassFlow / waterCoil.MinAirFlowArea;
    3066              :         //      air flow Reynold's Number
    3067         4968 :         AirReynoldsNo = waterCoil.CoilEffectiveInsideDiam * ScaledAirMassFlowRate / AirViscosity;
    3068              :         //       heat transfer coefficients and resistance components:
    3069              :         //              inside (water)
    3070         4968 :         WaterToTubeThermResist = std::pow(waterCoil.TubeInsideDiam, 0.2) / (waterCoil.TotTubeInsideArea * 1.429 * std::pow(TubeWaterVel, 0.8));
    3071              :         //              metal and fouling
    3072         4968 :         TubeFoulThermResist =
    3073         4968 :             (0.5 * (waterCoil.TubeOutsideDiam - waterCoil.TubeInsideDiam) / (ConvK * waterCoil.TubeThermConductivity) + TubeFoulFactor) /
    3074         4968 :             waterCoil.TotTubeInsideArea;
    3075              :         //              outside (wet and dry coil)
    3076         4968 :         FilmCoefEqnFactor = waterCoil.GeometryCoef1 * std::pow(AirReynoldsNo, waterCoil.GeometryCoef2);
    3077              :         //       (1.23 is 1/Prandt(air)**(2/3))
    3078         4968 :         AirSideDrySurfFilmCoef = 1.23 * FilmCoefEqnFactor * MoistAirSpecificHeat * ScaledAirMassFlowRate;
    3079         4968 :         FilmCoefReynldsCorrelatnFact = 1.425 + AirReynoldsNo * (-0.51e-3 + AirReynoldsNo * 0.263e-6);
    3080              :         //       NOTE: the equation for FilmCoefReynldsCorrelatnFact generates valid results over
    3081              :         //             a limited range of Air Reynolds Numbers as indicated by
    3082              :         //             deleted code below.  Reynolds Numbers outside this range
    3083              :         //             may result in inaccurate results or failure of the coil
    3084              :         //             simulation to obtain a solution
    3085              :         //             Deleted code by J.C. Vanderzee
    3086              : 
    3087         4968 :         AirSideWetSurfFilmCoef = FilmCoefReynldsCorrelatnFact * AirSideDrySurfFilmCoef;
    3088              :         //--                     need wet fin efficiency for outside
    3089         4968 :         RaisedInletWaterTemp = TempWaterIn + 0.5;
    3090              : 
    3091              :         // By this statement the Inlet Air enthalpy will never be equal to AirEnthAtRsdInletWaterTemp
    3092         4968 :         if ((RaisedInletWaterTemp - TempAirIn) < 0.000001) {
    3093         4968 :             RaisedInletWaterTemp = TempWaterIn + 0.3;
    3094              :         }
    3095         4968 :         if (TempAirIn < RaisedInletWaterTemp) {
    3096            0 :             RaisedInletWaterTemp = TempAirIn - 0.3;
    3097              :         }
    3098              : 
    3099         4968 :         RsdInletWaterTempSatAirHumRat = PsyWFnTdbRhPb(state, RaisedInletWaterTemp, unity, state.dataEnvrn->OutBaroPress, RoutineName);
    3100         4968 :         AirEnthAtRsdInletWaterTemp = PsyHFnTdbW(RaisedInletWaterTemp, RsdInletWaterTempSatAirHumRat) * ConvK;
    3101              : 
    3102         4968 :         SensToTotEnthDiffRatio = DryAirSpecHeat * (TempAirIn - RaisedInletWaterTemp) / (InletAirEnthalpy - AirEnthAtRsdInletWaterTemp);
    3103              : 
    3104         4968 :         EnterAirHumRatDiff = InletAirHumRat - RsdInletWaterTempSatAirHumRat;
    3105         4968 :         DryFinEfficncy = 0.5 * (waterCoil.EffectiveFinDiam - waterCoil.TubeOutsideDiam) *
    3106         4968 :                          std::sqrt(2.0 * AirSideWetSurfFilmCoef / (ConvK * waterCoil.FinThermConductivity * waterCoil.FinThickness));
    3107         4968 :         if (EnterAirHumRatDiff < 0) {
    3108              :             //       note that this condition indicates dry coil
    3109          132 :             EnterAirHumRatDiff = -EnterAirHumRatDiff;
    3110          132 :             SensToTotEnthDiffRatio = std::abs(SensToTotEnthDiffRatio);
    3111              :         }
    3112              : 
    3113         4968 :         if (EnterAirHumRatDiff > 1.0) {
    3114            0 :             EnterAirHumRatDiff = 1.0;
    3115         4968 :         } else if (EnterAirHumRatDiff < 0.00001) {
    3116            0 :             EnterAirHumRatDiff = 0.00001;
    3117              :         }
    3118              : 
    3119         4968 :         if (DryFinEfficncy > 1.0) {
    3120            0 :             DryFinEfficncy = 1.0;
    3121         4968 :         } else if (DryFinEfficncy < 0.00001) {
    3122            0 :             DryFinEfficncy = 0.00001;
    3123              :         }
    3124              : 
    3125         4968 :         if (TempAirIn > 48.0 / 1.8) {
    3126          984 :             WetFinEfficncy =
    3127          984 :                 exp_47 * std::pow(SensToTotEnthDiffRatio, 0.09471) * std::pow(EnterAirHumRatDiff, 0.0108) * std::pow(DryFinEfficncy, -0.50303);
    3128              :         } else {
    3129         3984 :             WetFinEfficncy =
    3130         3984 :                 exp_35 * std::pow(SensToTotEnthDiffRatio, 0.16081) * std::pow(EnterAirHumRatDiff, 0.01995) * std::pow(DryFinEfficncy, -0.52951);
    3131              :         }
    3132              : 
    3133         4968 :         if (WetFinEfficncy > 1.0) WetFinEfficncy = 0.99;
    3134         4968 :         if (WetFinEfficncy < 0.0) WetFinEfficncy = 0.001;
    3135              :         //       wet coil fin efficiency
    3136              : 
    3137         4968 :         WetCoilFinEfficncy = 1.0 + FinToTotSurfAreaRatio * (WetFinEfficncy - 1.0);
    3138              :         //       wet coil outside thermal resistance = [1/UA] (wet coil)
    3139         4968 :         CoilToAirThermResistWetSurf = MoistAirSpecificHeat / (waterCoil.TotCoilOutsideSurfArea * AirSideWetSurfFilmCoef * WetCoilFinEfficncy);
    3140              :         //--                     and dry fin efficiency
    3141         4968 :         DryFinEfficncy = 0.5 * (waterCoil.EffectiveFinDiam - waterCoil.TubeOutsideDiam) *
    3142         4968 :                          std::sqrt(2.0 * AirSideDrySurfFilmCoef / (ConvK * waterCoil.FinThermConductivity * waterCoil.FinThickness));
    3143              :         //      NOTE: The same caveats on the validity of the FilmCoefReynldsCorrelatnFact equation
    3144              :         //            hold for the DryFinEfficncy equation.  Values of DryFinEfficncy outside the
    3145              :         //            specified range of validity are not guaranteed to
    3146              :         //            produce results
    3147              :         //             Deleted code by J.C. Vanderzee
    3148              :         //       dry coil fin efficiency
    3149         4968 :         DryCoilEfficiency = 0.0;
    3150              :         // Tuned Replaced by below to eliminate pow calls
    3151              :         //            for ( CoefPointer = 1; CoefPointer <= 5; ++CoefPointer ) {
    3152              :         //                DryCoilEfficiency += WaterCoil( CoilNum ).DryFinEfficncyCoef( CoefPointer ) * std::pow(
    3153              :         // DryFinEfficncy,
    3154              :         // CoefPointer
    3155              :         //-
    3156              :         // 1
    3157              :         //);             } // CoefPointer
    3158         4968 :         auto const &dry_fin_eff_coef = waterCoil.DryFinEfficncyCoef;
    3159         4968 :         Real64 DryFinEfficncy_pow = 1.0;
    3160        29808 :         for (int CoefPointer = 1; CoefPointer <= 5; ++CoefPointer) {
    3161        24840 :             DryCoilEfficiency += dry_fin_eff_coef(CoefPointer) * DryFinEfficncy_pow;
    3162        24840 :             DryFinEfficncy_pow *= DryFinEfficncy;
    3163              :         } // CoefPointer
    3164         4968 :         DryCoilEfficiency = 1.0 + FinToTotSurfAreaRatio * (DryCoilEfficiency - 1.0);
    3165              :         //       dry coil outside thermal resistance = [1/UA] (dry coil)
    3166         4968 :         CoilToAirThermResistDrySurf = 1.0 / (waterCoil.TotCoilOutsideSurfArea * AirSideDrySurfFilmCoef * DryCoilEfficiency);
    3167              :         //       definitions made to simplify some of the expressions used below
    3168         4968 :         Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, TempWaterIn, RoutineName);
    3169         4968 :         ScaledWaterSpecHeat = WaterMassFlowRate * Cp * ConvK / AirMassFlow;
    3170         4968 :         DryCoilCoeff1 = 1.0 / (AirMassFlow * MoistAirSpecificHeat) - 1.0 / (WaterMassFlowRate * Cp * ConvK);
    3171              :         //       perform initialisations for all wet solution
    3172         4968 :         WetSideEffctvWaterTemp = waterCoil.MeanWaterTempSaved + (TempWaterIn - waterCoil.InWaterTempSaved);
    3173         4968 :         int WaterTempConvgLoop = 0;
    3174         4968 :         bool WaterTempConvg = false;
    3175              :         //       Loop to solve coil as if all wet, converges on MeanWaterTemp eq WetSideEffctvWaterTemp
    3176              :         //       if conv=.TRUE. at any time program exits loop and proceeds
    3177              :         //       to part wet / part dry solution
    3178        17239 :         while (WaterTempConvgLoop < 8 && !WaterTempConvg) {
    3179        12271 :             ++WaterTempConvgLoop;
    3180        12271 :             ScaledWaterToTubeThermResist = WaterToTubeThermResist / (1.0 + 0.0146 * WetSideEffctvWaterTemp);
    3181        12271 :             ScaledCoilAirThermResistWetSurf = CoilToAirThermResistWetSurf / waterCoil.SatEnthlCurveSlope;
    3182        12271 :             UACoilAllWet =
    3183        12271 :                 1.0 / (waterCoil.SatEnthlCurveSlope * (TubeFoulThermResist + ScaledWaterToTubeThermResist + ScaledCoilAirThermResistWetSurf));
    3184              :             //       prevents floating point error when taking exponential
    3185              :             //       of a very large number
    3186        12271 :             expon = UACoilAllWet * (1.0 / AirMassFlow - waterCoil.SatEnthlCurveSlope / (WaterMassFlowRate * Cp * ConvK));
    3187        12271 :             if (expon < 20.0) { // CR7189 changed from ABS(expon) < 20
    3188              :                 //       negative expon can happen, but lead to tiny WetCoilCoef that aren't a problem
    3189        12271 :                 WetCoilCoeff = std::exp(expon);
    3190              :                 // following appears similar to eq. 320 in Eng Ref but neglects K1 term
    3191        12271 :                 TempWaterOut = ((1.0 - WetCoilCoeff) * (InletAirEnthalpy - waterCoil.SatEnthlCurveConstCoef) +
    3192        12271 :                                 WetCoilCoeff * TempWaterIn * (waterCoil.SatEnthlCurveSlope - ScaledWaterSpecHeat)) /
    3193        12271 :                                (waterCoil.SatEnthlCurveSlope - WetCoilCoeff * ScaledWaterSpecHeat);
    3194              :             } else {
    3195              :                 // following appears to be same as above with equation simplified to use only significant terms when WetCoilCoeff very large
    3196            0 :                 TempWaterOut =
    3197            0 :                     ((InletAirEnthalpy - waterCoil.SatEnthlCurveConstCoef) - TempWaterIn * (waterCoil.SatEnthlCurveSlope - ScaledWaterSpecHeat)) /
    3198              :                     ScaledWaterSpecHeat;
    3199              :             }
    3200              :             //      above is inverted form of WaterMassFlowRate*cpw*(TempWaterOut-TempWaterIn) = UA(LMHD)
    3201              :             //      note simplification that hsat = WaterCoil(CoilNum)%SatEnthlCurveConstCoef +  &
    3202              :             //                                      WaterCoil(CoilNum)%SatEnthlCurveSlope*WetSideEffctvWaterTemp
    3203        12271 :             MeanWaterTemp = 0.5 * (TempWaterIn + TempWaterOut);
    3204        12271 :             OutletAirEnthalpy = InletAirEnthalpy - (TempWaterOut - TempWaterIn) * ScaledWaterSpecHeat;
    3205              : 
    3206        12271 :             InsdToOutsdThermResistRatio = (TubeFoulThermResist + ScaledWaterToTubeThermResist) / ScaledCoilAirThermResistWetSurf;
    3207        12271 :             InCoilSurfTemp =
    3208        12271 :                 UACoilAllWet * ScaledCoilAirThermResistWetSurf *
    3209        12271 :                 (waterCoil.SatEnthlCurveSlope * TempWaterIn + (OutletAirEnthalpy - waterCoil.SatEnthlCurveConstCoef) * InsdToOutsdThermResistRatio);
    3210        12271 :             OutCoilSurfTemp =
    3211        12271 :                 UACoilAllWet * ScaledCoilAirThermResistWetSurf *
    3212        12271 :                 (waterCoil.SatEnthlCurveSlope * TempWaterOut + (InletAirEnthalpy - waterCoil.SatEnthlCurveConstCoef) * InsdToOutsdThermResistRatio);
    3213              : 
    3214        12271 :             if (std::abs(MeanWaterTemp - WetSideEffctvWaterTemp) > 0.01) {
    3215         7303 :                 WetSideEffctvWaterTemp = MeanWaterTemp;
    3216         7303 :                 InSurfTempSatAirEnthl = PsyHFnTdbRhPb(state, InCoilSurfTemp, unity, state.dataEnvrn->OutBaroPress, RoutineName) * ConvK;
    3217         7303 :                 OutSurfTempSatAirEnthl = PsyHFnTdbRhPb(state, OutCoilSurfTemp, unity, state.dataEnvrn->OutBaroPress, RoutineName) * ConvK;
    3218              : 
    3219         7303 :                 waterCoil.SatEnthlCurveSlope = (OutSurfTempSatAirEnthl - InSurfTempSatAirEnthl) / (OutCoilSurfTemp - InCoilSurfTemp);
    3220         7303 :                 waterCoil.SatEnthlCurveConstCoef = InSurfTempSatAirEnthl - waterCoil.SatEnthlCurveSlope * InCoilSurfTemp;
    3221              :             } else {
    3222         4968 :                 WaterTempConvg = true;
    3223              :             }
    3224              :         } // End of iteration loop to get MeanWaterTemp=WetSideEffctvWaterTemp
    3225              :         //      if 8 CoolCoilErrs are reached without convergence and the
    3226              :         //      predicted coil surface temperature at the outlet is less than
    3227              :         //      the dew point coil is apparently all wet but a solution
    3228              :         //      cannot be obtained
    3229         4968 :         if (!WaterTempConvg && !state.dataGlobal->WarmupFlag && (OutCoilSurfTemp < EnterAirDewPoint)) {
    3230            0 :             ShowRecurringWarningErrorAtEnd(state,
    3231            0 :                                            waterCoil.Name + " not converged (8 iterations) due to \"Wet Convergence\" conditions.",
    3232            0 :                                            state.dataWaterCoils->WaterTempCoolCoilErrs(CoilNum),
    3233            0 :                                            std::abs(MeanWaterTemp - WetSideEffctvWaterTemp),
    3234            0 :                                            std::abs(MeanWaterTemp - WetSideEffctvWaterTemp));
    3235              :             //       CoolCoilErrs = CoolCoilErrs + 1
    3236              :             //       IF (CoolCoilErrs .LE. MaxCoolCoilErrs) THEN
    3237              :             //          CALL ShowWarningError(state, 'tp12c0:  not converged in 8 CoolCoilErrs')
    3238              :             //       END IF
    3239              :         }
    3240         4968 :         waterCoil.MeanWaterTempSaved = MeanWaterTemp;
    3241              :         //      now simulate wet dry coil - test outlet condition from all
    3242              :         //      wet case to give an idea of the expected solution
    3243         4968 :         int PartWetIterations = 0;
    3244         4968 :         WetDryInterSurfTempError = 0.0;
    3245         4968 :         bool CoilPartWetConvg = false;
    3246              :         //      Surface temp at coil water outlet (air inlet) is less than
    3247              :         //      the dew point - Coil must be completely wet so no need to
    3248              :         //      simulate wet/dry case
    3249         4968 :         if (OutCoilSurfTemp < EnterAirDewPoint) {
    3250           78 :             CoilPartWetConvg = true;
    3251           78 :             waterCoil.SurfAreaWetFraction = 1.0;
    3252           78 :             TotWaterCoilLoad = AirMassFlow * (InletAirEnthalpy - OutletAirEnthalpy);
    3253           78 :             AirWetDryInterfcTemp = TempAirIn;
    3254           78 :             WetDryInterfcAirEnthl = InletAirEnthalpy;
    3255              :             //      Surface temperature at coil water inlet is greater than the
    3256              :             //      dewpoint - coil cannot be all wet but may be all dry -
    3257              :             //      initialise with all dry solution
    3258         4890 :         } else if (InCoilSurfTemp > EnterAirDewPoint) {
    3259         1454 :             SurfAreaWet = 0.0;
    3260         1454 :             waterCoil.SurfAreaWetFraction = 0.0;
    3261         1454 :             WetDryInterfcWaterTemp = TempWaterIn;
    3262         1454 :             TempWaterOut = waterCoil.OutWaterTempSaved + (TempWaterIn - waterCoil.InWaterTempSaved);
    3263         1454 :             WetAreaLast = 0.05 * waterCoil.TotCoilOutsideSurfArea;
    3264              :             //      General case - must be part-wet/part-dry - initialise
    3265              :             //      accordingly with some non-zero wet area
    3266              :         } else {
    3267         3436 :             if (waterCoil.SurfAreaWetSaved != 0.0) {
    3268         3432 :                 SurfAreaWet = waterCoil.SurfAreaWetSaved;
    3269              :             } else {
    3270            4 :                 SurfAreaWet = 0.8 * waterCoil.TotCoilOutsideSurfArea * (EnterAirDewPoint - InCoilSurfTemp) / (OutCoilSurfTemp - InCoilSurfTemp);
    3271              :             }
    3272         3436 :             WetDryInterfcWaterTemp = TempWaterIn + EnterAirDewPoint - InCoilSurfTemp;
    3273         3436 :             WetAreaLast = 0.0;
    3274              :         }
    3275              :         //       Loop to solve partly wet coil, converges on wet area and
    3276              :         //       boundary temperature at dew point
    3277              :         //       Dry coil is special case with zero wet area, converges on
    3278              :         //       mean water temperature
    3279        47766 :         while (PartWetIterations < 40 && !CoilPartWetConvg) {
    3280        42798 :             ++PartWetIterations;
    3281              :             //      effective water temp on dry side of coil
    3282        42798 :             DrySideEffectiveWaterTemp = 0.5 * (TempWaterOut + WetDryInterfcWaterTemp);
    3283              :             //      tube inside thermal resistance
    3284        42798 :             DryCoilInThermResist = WaterToTubeThermResist / (1.0 + 0.0146 * DrySideEffectiveWaterTemp);
    3285              :             //      overall UA, from water to air, of dry portion of coil
    3286              : 
    3287        42798 :             UADryCoil = (waterCoil.TotCoilOutsideSurfArea - SurfAreaWet) /
    3288        42798 :                         (waterCoil.TotCoilOutsideSurfArea * (TubeFoulThermResist + DryCoilInThermResist + CoilToAirThermResistDrySurf));
    3289              : 
    3290              :             // This is a numerical trap for a very small number in the EXP function that is approaching zero
    3291        42798 :             if (UADryCoil * DryCoilCoeff1 < -60.0) {
    3292            0 :                 DryCoilCoeff = 0.0;
    3293              :             } else {
    3294        42798 :                 DryCoilCoeff = std::exp(UADryCoil * DryCoilCoeff1);
    3295              :             }
    3296              : 
    3297        42798 :             K1 = WaterMassFlowRate * Cp * ConvK * (DryCoilCoeff - 1.0) /
    3298        42798 :                  (WaterMassFlowRate * Cp * ConvK * DryCoilCoeff - AirMassFlow * MoistAirSpecificHeat);
    3299        42798 :             if (SurfAreaWet != 0) {
    3300        40680 :                 waterCoil.SurfAreaWetFraction = SurfAreaWet / waterCoil.TotCoilOutsideSurfArea;
    3301              :                 //      effective water temp on wet side of coil
    3302        40680 :                 WetSideEffctvWaterTemp = 0.5 * (TempWaterIn + WetDryInterfcWaterTemp);
    3303              :                 //      tube inside thermal resistance
    3304        40680 :                 ScaledWaterToTubeThermResist = WaterToTubeThermResist / (1.0 + 0.0146 * WetSideEffctvWaterTemp);
    3305        40680 :                 ScaledCoilAirThermResistWetSurf = CoilToAirThermResistWetSurf / waterCoil.EnthVsTempCurveAppxSlope;
    3306              :                 //      overall UA, from water to air, of wet portion of coil
    3307        40680 :                 UACoilAllWet = 1.0 / (waterCoil.EnthVsTempCurveAppxSlope *
    3308        40680 :                                       (TubeFoulThermResist + ScaledWaterToTubeThermResist + ScaledCoilAirThermResistWetSurf));
    3309        40680 :                 UACoilPartWet = waterCoil.SurfAreaWetFraction * UACoilAllWet;
    3310        40680 :                 expon = UACoilPartWet * (1.0 / AirMassFlow - waterCoil.EnthVsTempCurveAppxSlope / (WaterMassFlowRate * Cp * ConvK));
    3311              :                 //        prevents floating point error when taking exponential
    3312              :                 //        of a very large number
    3313        40680 :                 if (expon < 20.0) {
    3314        40680 :                     WetCoilCoeff = std::exp(expon);
    3315              :                     //          write(outputfiledebug,*) ' wcc=',wetcoilcoeff
    3316        40680 :                     denom =
    3317        40680 :                         (waterCoil.EnthVsTempCurveAppxSlope - WetCoilCoeff * ScaledWaterSpecHeat - (1.0 - WetCoilCoeff) * K1 * MoistAirSpecificHeat);
    3318              :                     //          write(outputfiledebug,*) ' denom=',denom
    3319              :                     //          WetDryInterfcWaterTemp = ((1.0 - WetCoilCoeff) * (InletAirEnthalpy - WaterCoil(CoilNum)%EnthVsTempCurveConst -
    3320              :                     //          K1
    3321              :                     //          *  &
    3322              :                     //                                     MoistAirSpecificHeat * TempAirIn) + WetCoilCoeff * &
    3323              :                     //                                     TempWaterIn * (WaterCoil(CoilNum)%EnthVsTempCurveAppxSlope -  &
    3324              :                     //                                     ScaledWaterSpecHeat)) / (WaterCoil(CoilNum)%EnthVsTempCurveAppxSlope -  &
    3325              :                     //                                      WetCoilCoeff * ScaledWaterSpecHeat - (1.0 - WetCoilCoeff) * K1 * &
    3326              :                     //                                     MoistAirSpecificHeat)
    3327        40680 :                     WetDryInterfcWaterTemp =
    3328        40680 :                         ((1.0 - WetCoilCoeff) * (InletAirEnthalpy - waterCoil.EnthVsTempCurveConst - K1 * MoistAirSpecificHeat * TempAirIn) +
    3329        40680 :                          WetCoilCoeff * TempWaterIn * (waterCoil.EnthVsTempCurveAppxSlope - ScaledWaterSpecHeat)) /
    3330              :                         denom;
    3331              :                 } else {
    3332              :                     //         approximation to equation for WetDryInterfcWaterTemp when WetCoilCoeff-->inf.
    3333            0 :                     WetDryInterfcWaterTemp = (TempWaterIn * (waterCoil.EnthVsTempCurveAppxSlope - ScaledWaterSpecHeat) -
    3334            0 :                                               (InletAirEnthalpy - waterCoil.EnthVsTempCurveConst - K1 * MoistAirSpecificHeat * TempAirIn)) /
    3335            0 :                                              (K1 * MoistAirSpecificHeat - ScaledWaterSpecHeat);
    3336              :                 }
    3337              :             }
    3338              :             //        air temperature at wet-dry interface
    3339        42798 :             AirWetDryInterfcTemp = TempAirIn - (TempAirIn - WetDryInterfcWaterTemp) * K1;
    3340              :             //        coil surface temperature at wet-dry interface
    3341        42798 :             WetDryInterfcSurfTemp = WetDryInterfcWaterTemp + (AirWetDryInterfcTemp - WetDryInterfcWaterTemp) *
    3342        42798 :                                                                  (TubeFoulThermResist + DryCoilInThermResist) /
    3343        42798 :                                                                  (TubeFoulThermResist + DryCoilInThermResist + CoilToAirThermResistDrySurf);
    3344        42798 :             if (SurfAreaWet != 0) {
    3345        40680 :                 WetDryInterfcAirEnthl = InletAirEnthalpy - MoistAirSpecificHeat * (TempAirIn - AirWetDryInterfcTemp);
    3346              :                 //        conservation of energy - wet portion of coil
    3347        40680 :                 OutletAirEnthalpy = WetDryInterfcAirEnthl - WaterMassFlowRate * Cp * ConvK * (WetDryInterfcWaterTemp - TempWaterIn) / AirMassFlow;
    3348              :                 //        ratio of inside to outside thermal resistance
    3349        40680 :                 InsdToOutsdThermResistRatio = (TubeFoulThermResist + ScaledWaterToTubeThermResist) / ScaledCoilAirThermResistWetSurf;
    3350              :                 //        coil surface temperature at water inlet (air outlet)
    3351        40680 :                 InCoilSurfTemp = UACoilAllWet * ScaledCoilAirThermResistWetSurf *
    3352        40680 :                                  (waterCoil.EnthVsTempCurveAppxSlope * TempWaterIn +
    3353        40680 :                                   (OutletAirEnthalpy - waterCoil.EnthVsTempCurveConst) * InsdToOutsdThermResistRatio);
    3354        40680 :                 WetDryInterSurfTempErrorLast = WetDryInterSurfTempError;
    3355              :                 //        in part-wet/part-dry solution EnterAirDewPoint=WetDryInterfcSurfTemp drives WetDryInterSurfTempError->0
    3356        40680 :                 WetDryInterSurfTempError = EnterAirDewPoint - WetDryInterfcSurfTemp;
    3357              :             } else {
    3358              :                 //        dry coil solution
    3359         2118 :                 WetDryInterfcAirEnthl = 0.0;
    3360         2118 :                 OutletAirEnthalpy = InletAirEnthalpy - MoistAirSpecificHeat * (TempAirIn - AirWetDryInterfcTemp);
    3361              :             }
    3362              :             //        total cooling = change in air enthalpy across coil
    3363        42798 :             TotWaterCoilLoad = AirMassFlow * (InletAirEnthalpy - OutletAirEnthalpy);
    3364              :             //        conservation of energy on water stream gives water outlet
    3365              :             //        temperature
    3366        42798 :             TempWaterOut = WaterMassFlowRate * Cp * ConvK; // Temp for next calc
    3367        42798 :             TempWaterOut = min(TempWaterIn + TotWaterCoilLoad / TempWaterOut, TempAirIn);
    3368              :             //        update estimate of coil wet area
    3369              : 
    3370        42798 :             if (SurfAreaWet == 0) {
    3371         2118 :                 MeanWaterTemp = 0.5 * (TempWaterOut + WetDryInterfcWaterTemp);
    3372         2118 :                 if (EnterAirDewPoint > WetDryInterfcSurfTemp) {
    3373         1221 :                     SurfAreaWet = 0.5 * WetAreaLast;
    3374          897 :                 } else if (std::abs(MeanWaterTemp - DrySideEffectiveWaterTemp) <= 0.00002) {
    3375          234 :                     CoilPartWetConvg = true;
    3376              :                 }
    3377        45420 :             } else if (std::abs(WetDryInterSurfTempError) > 0.00002 ||
    3378         4740 :                        std::abs(SurfAreaWet - WetAreaLast) / waterCoil.TotCoilOutsideSurfArea > 0.00001) {
    3379        36036 :                 if (WetAreaLast == 0) {
    3380         3436 :                     WetAreaLast = SurfAreaWet;
    3381         3436 :                     SurfAreaWet += 0.4 * waterCoil.TotCoilOutsideSurfArea * WetDryInterSurfTempError / (OutCoilSurfTemp - InCoilSurfTemp);
    3382        32600 :                 } else if (WetDryInterSurfTempError != WetDryInterSurfTempErrorLast) {
    3383        32600 :                     WetAreaChange = SurfAreaWet - WetAreaLast;
    3384        32600 :                     WetAreaLast = SurfAreaWet;
    3385        32600 :                     SurfAreaWet -= 0.8 * WetDryInterSurfTempError * WetAreaChange / (WetDryInterSurfTempError - WetDryInterSurfTempErrorLast);
    3386              :                 }
    3387        36036 :                 if (SurfAreaWet >= waterCoil.TotCoilOutsideSurfArea) {
    3388           60 :                     SurfAreaWet = waterCoil.TotCoilOutsideSurfArea;
    3389           60 :                     MeanWaterTemp = 0.5 * (TempWaterIn + WetDryInterfcWaterTemp);
    3390           60 :                     if (WetAreaLast == waterCoil.TotCoilOutsideSurfArea && std::abs(MeanWaterTemp - WetSideEffctvWaterTemp) <= 0.00002) {
    3391           12 :                         CoilPartWetConvg = true;
    3392              :                     }
    3393              :                 }
    3394        36036 :                 if (SurfAreaWet <= 0) {
    3395            1 :                     SurfAreaWet = 0.0;
    3396            1 :                     waterCoil.SurfAreaWetFraction = 0.0;
    3397            1 :                     WetDryInterfcWaterTemp = TempWaterIn;
    3398              :                 }
    3399        36036 :                 InSurfTempSatAirEnthl = PsyHFnTdbRhPb(state, InCoilSurfTemp, unity, state.dataEnvrn->OutBaroPress, RoutineName) * ConvK;
    3400        36036 :                 if ((EnterAirDewPoint - InCoilSurfTemp) >= 0.0001) {
    3401        35921 :                     AirEnthAtWetDryIntrfcSurfTemp = PsyHFnTdbRhPb(state, EnterAirDewPoint, unity, state.dataEnvrn->OutBaroPress, RoutineName) * ConvK;
    3402        35921 :                     waterCoil.EnthVsTempCurveAppxSlope =
    3403        35921 :                         (AirEnthAtWetDryIntrfcSurfTemp - InSurfTempSatAirEnthl) / (EnterAirDewPoint - InCoilSurfTemp);
    3404              :                 } else {
    3405          115 :                     AirEnthAtWetDryIntrfcSurfTemp =
    3406          115 :                         PsyHFnTdbRhPb(state, InCoilSurfTemp + 0.0001, unity, state.dataEnvrn->OutBaroPress, RoutineName) * ConvK;
    3407          115 :                     waterCoil.EnthVsTempCurveAppxSlope = (AirEnthAtWetDryIntrfcSurfTemp - InSurfTempSatAirEnthl) / 0.0001;
    3408              :                 }
    3409        36036 :                 waterCoil.EnthVsTempCurveConst = InSurfTempSatAirEnthl - waterCoil.EnthVsTempCurveAppxSlope * InCoilSurfTemp;
    3410              :             } else {
    3411         4644 :                 CoilPartWetConvg = true;
    3412              :             }
    3413              :         }
    3414              :         //      error checking to see if convergence has been achieved
    3415         4968 :         if (!CoilPartWetConvg && !state.dataGlobal->WarmupFlag) {
    3416            0 :             ShowRecurringWarningErrorAtEnd(state,
    3417            0 :                                            waterCoil.Name + " not converged (40 iterations) due to \"Partial Wet Convergence\" conditions.",
    3418            0 :                                            state.dataWaterCoils->PartWetCoolCoilErrs(CoilNum));
    3419              :             //      CoolCoilErrs = CoolCoilErrs + 1
    3420              :             //      IF (CoolCoilErrs .LE. MaxCoolCoilErrs) THEN
    3421              :             //        CALL ShowWarningError(state, 'tp12c0:  not converged in 20 CoolCoilErrs')
    3422              :             //      END IF
    3423              :         }
    3424         4968 :         if (waterCoil.SurfAreaWetFraction > 0 && waterCoil.SurfAreaWetFraction < 1) {
    3425         4644 :             waterCoil.SurfAreaWetSaved = SurfAreaWet;
    3426              :         }
    3427              :         //       calculate TempAirOut, OutletAirHumRat, and SensCoolRate based on equations from
    3428              :         //       TYPE12 and the ASHRAE toolkit
    3429         4968 :         if (waterCoil.SurfAreaWetFraction == 0) {
    3430              :             //       dry coil
    3431          234 :             TempAirOut = TempAirIn - TotWaterCoilLoad / (AirMassFlow * MoistAirSpecificHeat);
    3432          234 :             OutletAirHumRat = InletAirHumRat;
    3433          234 :             SenWaterCoilLoad = TotWaterCoilLoad;
    3434              :         } else {
    3435              :             //       coil effectiveness
    3436         4734 :             expon = waterCoil.SurfAreaWetFraction / (CoilToAirThermResistWetSurf * AirMassFlow);
    3437         4734 :             y = 0.0;
    3438         4734 :             if (expon < 20.0) y = std::exp(-expon);
    3439         4734 :             AirExitEnthlAtCoilSurfTemp = WetDryInterfcAirEnthl - (WetDryInterfcAirEnthl - OutletAirEnthalpy) / (1.0 - y);
    3440         4734 :             AirExitCoilSurfTemp = AirExitEnthlAtCoilSurfTemp / ConvK; // TEmporary calc
    3441         4734 :             AirExitCoilSurfTemp = PsyTsatFnHPb(state, AirExitCoilSurfTemp, state.dataEnvrn->OutBaroPress);
    3442              :             //       Implementation of epsilon*NTU method
    3443         4734 :             TempAirOut = AirExitCoilSurfTemp + (AirWetDryInterfcTemp - AirExitCoilSurfTemp) * y;
    3444         4734 :             OutletAirHumRat = PsyWFnTdbH(state, TempAirOut, 1000.0 * OutletAirEnthalpy, RoutineName);
    3445         4734 :             SenWaterCoilLoad = AirMassFlow * (PsyCpAirFnW(InletAirHumRat) * TempAirIn - PsyCpAirFnW(OutletAirHumRat) * TempAirOut) * ConvK;
    3446              :         }
    3447              : 
    3448         4968 :         if (fanOp == HVAC::FanOp::Cycling) {
    3449            0 :             TotWaterCoilLoad *= PartLoadRatio;
    3450            0 :             SenWaterCoilLoad *= PartLoadRatio;
    3451              :         }
    3452              : 
    3453              :         // Set the outlet conditions
    3454         4968 :         waterCoil.TotWaterCoolingCoilRate = TotWaterCoilLoad * 1000.0;
    3455         4968 :         waterCoil.SenWaterCoolingCoilRate = SenWaterCoilLoad * 1000.0;
    3456         4968 :         waterCoil.OutletAirTemp = TempAirOut;
    3457         4968 :         waterCoil.OutletWaterTemp = TempWaterOut;
    3458         4968 :         waterCoil.OutletAirEnthalpy = OutletAirEnthalpy * 1000.0;
    3459         4968 :         waterCoil.OutletAirHumRat = OutletAirHumRat;
    3460              :         // The CoolingCoilLoad is the change in the enthalpy of the water
    3461         4968 :         waterCoil.OutletWaterEnthalpy = waterCoil.InletWaterEnthalpy + waterCoil.TotWaterCoolingCoilRate / waterCoil.InletWaterMassFlowRate;
    3462              : 
    3463              :         // This WaterCoil does not change the Mass Flow across the component
    3464         4968 :         waterCoil.OutletAirMassFlowRate = waterCoil.InletAirMassFlowRate;
    3465         4968 :         waterCoil.OutletWaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
    3466              :     } else {
    3467              :         // If Coil is scheduled OFF then Outlet conditions are set to Inlet Conditions
    3468         3473 :         waterCoil.TotWaterCoolingCoilRate = 0.0;
    3469         3473 :         waterCoil.SenWaterCoolingCoilRate = 0.0;
    3470         3473 :         TempAirOut = TempAirIn;
    3471         3473 :         TempWaterOut = TempWaterIn;
    3472              :         // set the outlet conditions to the coil derived type
    3473         3473 :         waterCoil.OutletAirTemp = TempAirOut;
    3474         3473 :         waterCoil.OutletWaterTemp = TempWaterOut;
    3475         3473 :         waterCoil.OutletAirEnthalpy = waterCoil.InletAirEnthalpy;
    3476         3473 :         waterCoil.OutletAirHumRat = waterCoil.InletAirHumRat;
    3477              :         // The CoolingCoilLoad is the change in the enthalpy of the water
    3478         3473 :         waterCoil.OutletWaterEnthalpy = waterCoil.InletWaterEnthalpy;
    3479              : 
    3480              :         // This WaterCoil does not change the Mass Flow across the component
    3481         3473 :         waterCoil.OutletAirMassFlowRate = waterCoil.InletAirMassFlowRate;
    3482         3473 :         waterCoil.OutletWaterMassFlowRate = 0.0;
    3483              :     }
    3484              : 
    3485              :     // Save some of the Values for next Time step
    3486         8441 :     waterCoil.InWaterTempSaved = TempWaterIn;
    3487         8441 :     waterCoil.OutWaterTempSaved = TempWaterOut;
    3488         8441 : }
    3489              : 
    3490       147786 : void CoolingCoil(EnergyPlusData &state,
    3491              :                  int const CoilNum,
    3492              :                  bool const FirstHVACIteration,
    3493              :                  int const CalcMode,
    3494              :                  HVAC::FanOp const fanOp,   // fan operating mode
    3495              :                  Real64 const PartLoadRatio // part-load ratio of heating coil
    3496              : )
    3497              : {
    3498              : 
    3499              :     // FUNCTION INFORMATION:
    3500              :     // AUTHOR         Rahul Chillar
    3501              :     // DATE WRITTEN   Mar 2004
    3502              : 
    3503              :     // PURPOSE OF THIS FUNCTION:
    3504              :     // The subroutine has the coil logic. Three types of Cooling Coils exist:
    3505              :     // They are 1.CoilDry , 2.CoilWet, 3. CoilPartDryPartWet. The logic for
    3506              :     // the three individual cases is in this subroutine.
    3507              : 
    3508              :     // METHODOLOGY EMPLOYED:
    3509              :     // Simulates a Coil Model from Design conditions and subsequently uses
    3510              :     // configuration values (example: UA)calculated from those design conditions
    3511              :     // to calculate new performance of coil from operating inputs.The values are
    3512              :     // calculated in the Subroutine InitWaterCoil
    3513              : 
    3514              :     // REFERENCES:
    3515              :     // ASHRAE Secondary HVAC Toolkit TRNSYS.  1990.  A Transient System
    3516              :     // Simulation Program: Reference Manual. Solar Energy Laboratory, Univ. Wisconsin-
    3517              :     // Madison, pp. 4.6.8-1 - 4.6.8-12.
    3518              :     // Threlkeld, J.L.  1970.  Thermal Environmental Engineering, 2nd Edition,
    3519              :     // Englewood Cliffs: Prentice-Hall,Inc. pp. 254-270.
    3520              : 
    3521              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    3522              :     Real64 AirInletCoilSurfTemp; // Coil surface temperature at air entrance(C)
    3523              :     Real64 AirDewPointTemp;      // Temperature dew point at operating condition
    3524              :     Real64 OutletAirTemp;        // Outlet air temperature at operating condition
    3525              :     Real64 OutletAirHumRat;      // Outlet air humidity ratio at operating condition
    3526              :     Real64 OutletWaterTemp;      // Outlet water temperature at operating condtitons
    3527              :     Real64 TotWaterCoilLoad;     // Total heat transfer rate(W)
    3528              :     Real64 SenWaterCoilLoad;     // Sensible heat transfer rate
    3529              :     Real64 SurfAreaWetFraction;  // Fraction of surface area wet
    3530              :     Real64 AirMassFlowRate;      // Air mass flow rate for the calculation
    3531              : 
    3532       147786 :     AirInletCoilSurfTemp = 0.0; // Coil surface temperature at air entrance(C)
    3533       147786 :     AirDewPointTemp = 0.0;      // Temperature dew point at operating condition
    3534       147786 :     OutletAirTemp = 0.0;        // Outlet air temperature at operating condition
    3535       147786 :     OutletAirHumRat = 0.0;      // Outlet air humidity ratio at operating condition
    3536       147786 :     OutletWaterTemp = 0.0;      // Outlet water temperature at operating condtitons
    3537       147786 :     TotWaterCoilLoad = 0.0;     // Total heat transfer rate(W)
    3538       147786 :     SenWaterCoilLoad = 0.0;     // Sensible heat transfer rate
    3539       147786 :     SurfAreaWetFraction = 0.0;  // Fraction of surface area wet
    3540              : 
    3541       147786 :     auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    3542       147786 :     if (fanOp == HVAC::FanOp::Cycling && PartLoadRatio > 0.0) { // FB Start
    3543        91138 :         AirMassFlowRate = waterCoil.InletAirMassFlowRate / PartLoadRatio;
    3544              :     } else {
    3545        56648 :         AirMassFlowRate = waterCoil.InletAirMassFlowRate;
    3546              :     }
    3547              : 
    3548              :     // If Coil is Scheduled ON then do the simulation
    3549       295560 :     if (((waterCoil.availSched->getCurrentVal() > 0.0) && (waterCoil.InletWaterMassFlowRate > 0.0) &&
    3550       295572 :          (AirMassFlowRate >= WaterCoils::MinAirMassFlow) && (waterCoil.DesAirVolFlowRate > 0.0) && (waterCoil.MaxWaterMassFlowRate > 0.0)) ||
    3551        93849 :         (CalcMode == state.dataWaterCoils->DesignCalc)) {
    3552              : 
    3553              :         // Calculate Temperature Dew Point at operating conditions.
    3554        53937 :         AirDewPointTemp = PsyTdpFnWPb(state, waterCoil.InletAirHumRat, state.dataEnvrn->OutBaroPress);
    3555              : 
    3556        53937 :         if (waterCoil.CoolingCoilAnalysisMode == state.dataWaterCoils->DetailedAnalysis) {
    3557              :             // Coil is completely dry if AirDewPointTemp is less than InletWaterTemp,hence Call CoilCompletelyDry
    3558        53356 :             if (AirDewPointTemp <= waterCoil.InletWaterTemp) {
    3559              : 
    3560              :                 // Calculate the leaving conditions and performance of dry coil
    3561          216 :                 CoilCompletelyDry(state,
    3562              :                                   CoilNum,
    3563              :                                   waterCoil.InletWaterTemp,
    3564              :                                   waterCoil.InletAirTemp,
    3565              :                                   waterCoil.UACoilTotal,
    3566              :                                   OutletWaterTemp,
    3567              :                                   OutletAirTemp,
    3568              :                                   OutletAirHumRat,
    3569              :                                   TotWaterCoilLoad,
    3570              :                                   fanOp,
    3571              :                                   PartLoadRatio);
    3572              : 
    3573          216 :                 SenWaterCoilLoad = TotWaterCoilLoad;
    3574          216 :                 SurfAreaWetFraction = 0.0;
    3575              : 
    3576              :             } else {
    3577              :                 // Else If AirDewPointTemp is greater than InletWaterTemp then assume the
    3578              :                 // external surface of coil is completely wet,hence Call CoilCompletelyWet
    3579              :                 // Calculate the leaving conditions and performance of wet coil
    3580        53140 :                 CoilCompletelyWet(state,
    3581              :                                   CoilNum,
    3582              :                                   waterCoil.InletWaterTemp,
    3583              :                                   waterCoil.InletAirTemp,
    3584              :                                   waterCoil.InletAirHumRat,
    3585              :                                   waterCoil.UACoilInternal,
    3586              :                                   waterCoil.UACoilExternal,
    3587              :                                   OutletWaterTemp,
    3588              :                                   OutletAirTemp,
    3589              :                                   OutletAirHumRat,
    3590              :                                   TotWaterCoilLoad,
    3591              :                                   SenWaterCoilLoad,
    3592              :                                   SurfAreaWetFraction,
    3593              :                                   AirInletCoilSurfTemp,
    3594              :                                   fanOp,
    3595              :                                   PartLoadRatio);
    3596              : 
    3597              :                 // If AirDewPointTemp is less than temp of coil surface at entry of air
    3598        53140 :                 if (AirDewPointTemp < AirInletCoilSurfTemp) {
    3599              : 
    3600              :                     // Then coil is partially wet and dry hence call CoilPartWetPartDry
    3601              :                     // Calculate the leaving conditions and performance of dry coil
    3602        35521 :                     CoilPartWetPartDry(state,
    3603              :                                        CoilNum,
    3604              :                                        FirstHVACIteration,
    3605              :                                        waterCoil.InletWaterTemp,
    3606              :                                        waterCoil.InletAirTemp,
    3607              :                                        AirDewPointTemp,
    3608              :                                        OutletWaterTemp,
    3609              :                                        OutletAirTemp,
    3610              :                                        OutletAirHumRat,
    3611              :                                        TotWaterCoilLoad,
    3612              :                                        SenWaterCoilLoad,
    3613              :                                        SurfAreaWetFraction,
    3614              :                                        fanOp,
    3615              :                                        PartLoadRatio);
    3616              : 
    3617              :                 } // End if for part wet part dry coil
    3618              :             }     // End if for dry coil
    3619              : 
    3620          581 :         } else if (waterCoil.CoolingCoilAnalysisMode == state.dataWaterCoils->SimpleAnalysis) {
    3621              :             // Coil is completely dry if AirDewPointTemp is less than InletWaterTemp,hence Call CoilCompletelyDry
    3622          581 :             if (AirDewPointTemp <= waterCoil.InletWaterTemp) {
    3623              : 
    3624              :                 // Calculate the leaving conditions and performance of dry coil
    3625           93 :                 CoilCompletelyDry(state,
    3626              :                                   CoilNum,
    3627              :                                   waterCoil.InletWaterTemp,
    3628              :                                   waterCoil.InletAirTemp,
    3629              :                                   waterCoil.UACoilTotal,
    3630              :                                   OutletWaterTemp,
    3631              :                                   OutletAirTemp,
    3632              :                                   OutletAirHumRat,
    3633              :                                   TotWaterCoilLoad,
    3634              :                                   fanOp,
    3635              :                                   PartLoadRatio);
    3636              : 
    3637           93 :                 SenWaterCoilLoad = TotWaterCoilLoad;
    3638           93 :                 SurfAreaWetFraction = 0.0;
    3639              : 
    3640              :             } else {
    3641              :                 // Else If AirDewPointTemp is greater than InletWaterTemp then assume the
    3642              :                 // external surface of coil is completely wet,hence Call CoilCompletelyWet
    3643              :                 // Calculate the leaving conditions and performance of wet coil
    3644          488 :                 CoilCompletelyWet(state,
    3645              :                                   CoilNum,
    3646              :                                   waterCoil.InletWaterTemp,
    3647              :                                   waterCoil.InletAirTemp,
    3648              :                                   waterCoil.InletAirHumRat,
    3649              :                                   waterCoil.UACoilInternal,
    3650              :                                   waterCoil.UACoilExternal,
    3651              :                                   OutletWaterTemp,
    3652              :                                   OutletAirTemp,
    3653              :                                   OutletAirHumRat,
    3654              :                                   TotWaterCoilLoad,
    3655              :                                   SenWaterCoilLoad,
    3656              :                                   SurfAreaWetFraction,
    3657              :                                   AirInletCoilSurfTemp,
    3658              :                                   fanOp,
    3659              :                                   PartLoadRatio);
    3660              : 
    3661              :             } // End if for dry coil
    3662              :         }
    3663              : 
    3664              :         // Report outlet variables at nodes
    3665        53937 :         waterCoil.OutletAirTemp = OutletAirTemp;
    3666        53937 :         waterCoil.OutletAirHumRat = OutletAirHumRat;
    3667        53937 :         waterCoil.OutletWaterTemp = OutletWaterTemp;
    3668              :         // Report output results if the coil was operating
    3669              : 
    3670        53937 :         if (fanOp == HVAC::FanOp::Cycling) {
    3671        42272 :             TotWaterCoilLoad *= PartLoadRatio;
    3672        42272 :             SenWaterCoilLoad *= PartLoadRatio;
    3673              :         }
    3674              : 
    3675        53937 :         waterCoil.TotWaterCoolingCoilRate = TotWaterCoilLoad;
    3676        53937 :         waterCoil.SenWaterCoolingCoilRate = SenWaterCoilLoad;
    3677        53937 :         waterCoil.SurfAreaWetFraction = SurfAreaWetFraction;
    3678              :         //       WaterCoil(CoilNum)%OutletWaterEnthalpy = WaterCoil(CoilNum)%InletWaterEnthalpy+ &
    3679              :         //                                WaterCoil(CoilNum)%TotWaterCoolingCoilRate/WaterCoil(CoilNum)%InletWaterMassFlowRate
    3680        53937 :         waterCoil.OutletWaterEnthalpy =
    3681        53937 :             waterCoil.InletWaterEnthalpy + General::SafeDivide(waterCoil.TotWaterCoolingCoilRate, waterCoil.InletWaterMassFlowRate);
    3682              : 
    3683              :     } else {
    3684              :         // If both mass flow rates are zero, set outputs to inputs and return
    3685        93849 :         waterCoil.OutletWaterTemp = waterCoil.InletWaterTemp;
    3686        93849 :         waterCoil.OutletAirTemp = waterCoil.InletAirTemp;
    3687        93849 :         waterCoil.OutletAirHumRat = waterCoil.InletAirHumRat;
    3688        93849 :         waterCoil.OutletWaterEnthalpy = waterCoil.InletWaterEnthalpy;
    3689        93849 :         waterCoil.TotWaterCoolingCoilEnergy = 0.0;
    3690        93849 :         waterCoil.SenWaterCoolingCoilEnergy = 0.0;
    3691        93849 :         waterCoil.SurfAreaWetFraction = 0.0;
    3692              : 
    3693              :     } // End of the Flow or No flow If block
    3694       147786 :     waterCoil.OutletWaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
    3695       147786 :     waterCoil.OutletAirMassFlowRate = waterCoil.InletAirMassFlowRate;
    3696       147786 :     waterCoil.OutletAirEnthalpy = PsyHFnTdbW(waterCoil.OutletAirTemp, waterCoil.OutletAirHumRat);
    3697       147786 : }
    3698              : 
    3699              : // End Algorithm Section of the Module
    3700              : 
    3701              : // Coil Completely Dry Subroutine for Cooling Coil
    3702              : 
    3703       805792 : void CoilCompletelyDry(EnergyPlusData &state,
    3704              :                        int const CoilNum,
    3705              :                        Real64 const WaterTempIn,  // Entering water temperature
    3706              :                        Real64 const AirTempIn,    // Entering air dry bulb temperature
    3707              :                        Real64 const CoilUA,       // Overall heat transfer coefficient
    3708              :                        Real64 &OutletWaterTemp,   // Leaving water temperature
    3709              :                        Real64 &OutletAirTemp,     // Leaving air dry bulb temperature
    3710              :                        Real64 &OutletAirHumRat,   // Leaving air humidity ratio
    3711              :                        Real64 &Q,                 // Heat transfer rate
    3712              :                        HVAC::FanOp const fanOp,   // fan operating mode
    3713              :                        Real64 const PartLoadRatio // part-load ratio of heating coil
    3714              : )
    3715              : {
    3716              : 
    3717              :     // FUNCTION INFORMATION:
    3718              :     // AUTHOR         Rahul Chillar
    3719              :     // DATE WRITTEN   March 2004
    3720              : 
    3721              :     // PURPOSE OF THIS FUNCTION:
    3722              :     // Calculate the performance of a sensible air-liquid heat exchanger.  Calculated
    3723              :     // results include outlet air temperature and humidity, outlet water temperature,
    3724              :     // and heat transfer rate.
    3725              : 
    3726              :     // METHODOLOGY EMPLOYED:
    3727              :     // Models coil using effectiveness-NTU model.
    3728              : 
    3729              :     // REFERENCES:
    3730              :     // Kays, W.M. and A.L. London.  1964,Compact Heat Exchangers, 2nd Edition,
    3731              :     // New York: McGraw-Hill.
    3732              : 
    3733              :     // FUNCTION PARAMETER DEFINITIONS:
    3734              :     static constexpr std::string_view RoutineName("CoilCompletelyDry");
    3735              : 
    3736              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    3737              :     Real64 CapacitanceAir;   // Air-side capacity rate(W/C)
    3738              :     Real64 CapacitanceWater; // Water-side capacity rate(W/C)
    3739              :     Real64 AirMassFlow;
    3740              :     Real64 WaterMassFlowRate;
    3741              :     Real64 Cp;
    3742              : 
    3743       805792 :     auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    3744              :     //  adjust mass flow rates for cycling fan cycling coil operation
    3745       805792 :     if (fanOp == HVAC::FanOp::Cycling) {
    3746       552779 :         if (PartLoadRatio > 0.0) {
    3747       552779 :             AirMassFlow = waterCoil.InletAirMassFlowRate / PartLoadRatio;
    3748       552779 :             WaterMassFlowRate = min(waterCoil.InletWaterMassFlowRate / PartLoadRatio, waterCoil.MaxWaterMassFlowRate);
    3749              :         } else {
    3750            0 :             AirMassFlow = 0.0;
    3751            0 :             WaterMassFlowRate = 0.0;
    3752              :         }
    3753              :     } else {
    3754       253013 :         AirMassFlow = waterCoil.InletAirMassFlowRate;
    3755       253013 :         WaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
    3756              :     }
    3757              : 
    3758              :     // Calculate air and water capacity rates
    3759       805792 :     CapacitanceAir = AirMassFlow * PsyCpAirFnW(waterCoil.InletAirHumRat);
    3760              :     // Water Capacity Rate
    3761       805792 :     Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, WaterTempIn, RoutineName);
    3762              : 
    3763       805792 :     CapacitanceWater = WaterMassFlowRate * Cp;
    3764              : 
    3765              :     // Determine the air and water outlet conditions
    3766       805792 :     CoilOutletStreamCondition(state, CoilNum, CapacitanceWater, WaterTempIn, CapacitanceAir, AirTempIn, CoilUA, OutletWaterTemp, OutletAirTemp);
    3767              : 
    3768              :     // Calculate the total and sensible heat transfer rate both are equal in case of Dry Coil
    3769       805792 :     Q = CapacitanceAir * (AirTempIn - OutletAirTemp);
    3770              : 
    3771              :     // Outlet humidity is equal to Inlet Humidity because its a dry coil
    3772       805792 :     OutletAirHumRat = waterCoil.InletAirHumRat;
    3773       805792 : }
    3774              : 
    3775              : // Coil Completely Wet Subroutine for Cooling Coil
    3776              : 
    3777       859111 : void CoilCompletelyWet(EnergyPlusData &state,
    3778              :                        int const CoilNum,            // Number of Coil
    3779              :                        Real64 const WaterTempIn,     // Water temperature IN to this function (C)
    3780              :                        Real64 const AirTempIn,       // Air dry bulb temperature IN to this function(C)
    3781              :                        Real64 const AirHumRat,       // Air Humidity Ratio IN to this funcation (C)
    3782              :                        Real64 const UAInternalTotal, // Internal overall heat transfer coefficient(W/m2 C)
    3783              :                        Real64 const UAExternalTotal, // External overall heat transfer coefficient(W/m2 C)
    3784              :                        Real64 &OutletWaterTemp,      // Leaving water temperature (C)
    3785              :                        Real64 &OutletAirTemp,        // Leaving air dry bulb temperature(C)
    3786              :                        Real64 &OutletAirHumRat,      // Leaving air humidity ratio
    3787              :                        Real64 &TotWaterCoilLoad,     // Total heat transfer rate(W)
    3788              :                        Real64 &SenWaterCoilLoad,     // Sensible heat transfer rate(W)
    3789              :                        Real64 &SurfAreaWetFraction,  // Fraction of surface area wet
    3790              :                        Real64 &AirInletCoilSurfTemp, // Surface temperature at air entrance(C)
    3791              :                        HVAC::FanOp const fanOp,      // fan operating mode
    3792              :                        Real64 const PartLoadRatio    // part-load ratio of heating coil
    3793              : )
    3794              : {
    3795              : 
    3796              :     // FUNCTION INFORMATION:
    3797              :     // AUTHOR         Rahul Chillar
    3798              :     // DATE WRITTEN   Mar 2004
    3799              : 
    3800              :     // PURPOSE OF THIS FUNCTION:
    3801              :     // Calculate the performance of a cooling coil when the external fin surface is
    3802              :     // complete wet.  Results include outlet air temperature and humidity,
    3803              :     // outlet water temperature, sensible and total cooling capacities, and the wet
    3804              :     // fraction of the air-side surface area.
    3805              : 
    3806              :     // METHODOLOGY EMPLOYED:
    3807              :     // Models coil as counterflow heat exchanger. Approximates saturated air enthalpy as
    3808              :     // a linear function of temperature
    3809              :     // TRNSYS.  1990.  A Transient System Simulation Program: Reference Manual.
    3810              :     // Solar Energy Laboratory, Univ. Wisconsin Madison, pp. 4.6.8-1 - 4.6.8-12.
    3811              :     // Threlkeld, J.L.  1970.  Thermal Environmental Engineering, 2nd Edition,
    3812              :     // Englewood Cliffs: Prentice-Hall,Inc. pp. 254-270.
    3813              :     // Coil Uses Enthalpy Based Heat Transfer Coefficents and converts them to
    3814              :     // convential UA values. Intermediate value of fictitious Cp is defined. This follow
    3815              :     // the same procedure followed in the Design Calculation of the Coil. See the node in
    3816              :     // the one time calculation for design condition.
    3817              : 
    3818              :     // REFERENCES:
    3819              :     // Elmahdy, A.H. and Mitalas, G.P.  1977."A Simple Model for Cooling and
    3820              :     // Dehumidifying Coils for Use In Calculating Energy Requirements for Buildings,"
    3821              :     // ASHRAE Transactions,Vol.83 Part 2, pp. 103-117.
    3822              : 
    3823              :     // FUNCTION PARAMETER DEFINITIONS:
    3824              :     static constexpr std::string_view RoutineName("CoilCompletelyWet");
    3825              : 
    3826              :     // INTERFACE BLOCK SPECIFICATIONS
    3827              :     // na
    3828              : 
    3829              :     // DERIVED TYPE DEFINITIONS
    3830              :     // na
    3831              : 
    3832              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    3833              :     Real64 AirSideResist;                  // Air-side resistance to heat transfer(m2 C/W)
    3834              :     Real64 WaterSideResist;                // Liquid-side resistance to heat transfer(m2 C/W)
    3835              :     Real64 EnteringAirDewPt;               // Entering air dew point(C)
    3836              :     Real64 UACoilTotalEnth;                // Overall enthalpy heat transfer coefficient(kg/s)
    3837              :     Real64 CapacityRateAirWet;             // Air-side capacity rate(kg/s)
    3838              :     Real64 CapacityRateWaterWet;           // Liquid-side capacity rate(kg/s)
    3839              :     Real64 ResistRatio;                    // Ratio of resistances
    3840              :     Real64 EnthAirOutlet;                  // Outlet air enthalpy
    3841              :     Real64 EnthSatAirInletWaterTemp;       // Saturated enthalpy of air at entering water temperature(J/kg)
    3842              :     Real64 EnthSatAirOutletWaterTemp;      // Saturated enthalpy of air at exit water temperature(J/kg)
    3843              :     Real64 EnthSatAirCoilSurfaceEntryTemp; // Saturated enthalpy of air at entering surface temperature(J/kg)
    3844              :     Real64 EnthSatAirCoilSurfaceExitTemp;  // Saturated enthalpy of air at exit surface temperature(J/kg)
    3845              :     Real64 EnthAirInlet;                   // Enthalpy of air at inlet
    3846              :     Real64 IntermediateCpSat;              // Coefficient for equation below(J/kg C)
    3847              :     // EnthSat1-EnthSat2 = IntermediateCpSat*(TSat1-TSat2)
    3848              :     // (all water and surface temperatures are
    3849              :     // related to saturated air enthalpies for
    3850              :     // wet surface heat transfer calculations)
    3851       859111 :     Real64 constexpr SmallNo(1.e-9); // smallNo used in place of 0
    3852              :     Real64 AirMassFlow;
    3853              :     Real64 WaterMassFlowRate;
    3854              :     Real64 Cp;
    3855              : 
    3856       859111 :     SurfAreaWetFraction = 1.0;
    3857       859111 :     AirSideResist = 1.0 / max(UAExternalTotal, SmallNo);
    3858       859111 :     WaterSideResist = 1.0 / max(UAInternalTotal, SmallNo);
    3859              : 
    3860       859111 :     auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    3861              :     //  adjust mass flow rates for cycling fan cycling coil operation
    3862       859111 :     if (fanOp == HVAC::FanOp::Cycling) {
    3863       595035 :         if (PartLoadRatio > 0.0) {
    3864       595035 :             AirMassFlow = waterCoil.InletAirMassFlowRate / PartLoadRatio;
    3865       595035 :             WaterMassFlowRate = min(waterCoil.InletWaterMassFlowRate / PartLoadRatio, waterCoil.MaxWaterMassFlowRate);
    3866              :         } else {
    3867            0 :             AirMassFlow = 0.0;
    3868            0 :             WaterMassFlowRate = 0.0;
    3869              :         }
    3870              :     } else {
    3871       264076 :         AirMassFlow = waterCoil.InletAirMassFlowRate;
    3872       264076 :         WaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
    3873              :     }
    3874              : 
    3875              :     // Calculate enthalpies of entering air and water
    3876              : 
    3877              :     // Enthalpy of air at inlet to the coil
    3878       859111 :     EnthAirInlet = PsyHFnTdbW(AirTempIn, AirHumRat);
    3879              : 
    3880              :     // Saturation Enthalpy of Air at inlet water temperature
    3881       859111 :     EnthSatAirInletWaterTemp = PsyHFnTdbW(WaterTempIn, PsyWFnTdpPb(state, WaterTempIn, state.dataEnvrn->OutBaroPress));
    3882              : 
    3883              :     // Estimate IntermediateCpSat using entering air dewpoint and water temperature
    3884       859111 :     EnteringAirDewPt = PsyTdpFnWPb(state, AirHumRat, state.dataEnvrn->OutBaroPress);
    3885              : 
    3886              :     // An intermediate value of Specific heat . EnthSat1-EnthSat2 = IntermediateCpSat*(TSat1-TSat2)
    3887       859111 :     IntermediateCpSat =
    3888       859111 :         (PsyHFnTdbW(EnteringAirDewPt, PsyWFnTdpPb(state, EnteringAirDewPt, state.dataEnvrn->OutBaroPress)) - EnthSatAirInletWaterTemp) /
    3889       859111 :         (EnteringAirDewPt - WaterTempIn);
    3890              : 
    3891              :     // Determine air and water enthalpy outlet conditions by modeling
    3892              :     // coil as counterflow enthalpy heat exchanger
    3893       859111 :     UACoilTotalEnth = 1.0 / (IntermediateCpSat * WaterSideResist + AirSideResist * PsyCpAirFnW(0.0));
    3894       859111 :     CapacityRateAirWet = AirMassFlow;
    3895       859111 :     Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, WaterTempIn, RoutineName);
    3896       859111 :     CapacityRateWaterWet = WaterMassFlowRate * (Cp / IntermediateCpSat);
    3897       859111 :     CoilOutletStreamCondition(state,
    3898              :                               CoilNum,
    3899              :                               CapacityRateAirWet,
    3900              :                               EnthAirInlet,
    3901              :                               CapacityRateWaterWet,
    3902              :                               EnthSatAirInletWaterTemp,
    3903              :                               UACoilTotalEnth,
    3904              :                               EnthAirOutlet,
    3905              :                               EnthSatAirOutletWaterTemp);
    3906              : 
    3907              :     // Calculate entering and leaving external surface conditions from
    3908              :     // air and water conditions and the ratio of resistances
    3909       859111 :     ResistRatio = (WaterSideResist) / (WaterSideResist + PsyCpAirFnW(0.0) / IntermediateCpSat * AirSideResist);
    3910       859111 :     EnthSatAirCoilSurfaceEntryTemp = EnthSatAirOutletWaterTemp + ResistRatio * (EnthAirInlet - EnthSatAirOutletWaterTemp);
    3911       859111 :     EnthSatAirCoilSurfaceExitTemp = EnthSatAirInletWaterTemp + ResistRatio * (EnthAirOutlet - EnthSatAirInletWaterTemp);
    3912              : 
    3913              :     // Calculate Coil Surface Temperature at air entry to the coil
    3914       859111 :     AirInletCoilSurfTemp = PsyTsatFnHPb(state, EnthSatAirCoilSurfaceEntryTemp, state.dataEnvrn->OutBaroPress);
    3915              : 
    3916              :     // Calculate outlet air temperature and humidity from enthalpies and surface conditions.
    3917       859111 :     TotWaterCoilLoad = AirMassFlow * (EnthAirInlet - EnthAirOutlet);
    3918       859111 :     OutletWaterTemp = WaterTempIn + TotWaterCoilLoad / max(WaterMassFlowRate, SmallNo) / Cp;
    3919              : 
    3920              :     // Calculates out put variable for  the completely wet coil
    3921       859111 :     WetCoilOutletCondition(state, CoilNum, AirTempIn, EnthAirInlet, EnthAirOutlet, UAExternalTotal, OutletAirTemp, OutletAirHumRat, SenWaterCoilLoad);
    3922       859111 : }
    3923              : 
    3924              : // Coil Part Wet Part Dry Subroutine for Cooling Coil
    3925              : 
    3926        35521 : void CoilPartWetPartDry(EnergyPlusData &state,
    3927              :                         int const CoilNum,             // Number of Coil
    3928              :                         bool const FirstHVACIteration, // Saving Old values
    3929              :                         Real64 const InletWaterTemp,   // Entering liquid temperature(C)
    3930              :                         Real64 const InletAirTemp,     // Entering air dry bulb temperature(C)
    3931              :                         Real64 const AirDewPointTemp,  // Entering air dew point(C)
    3932              :                         Real64 &OutletWaterTemp,       // Leaving liquid temperature(C)
    3933              :                         Real64 &OutletAirTemp,         // Leaving air dry bulb temperature(C)
    3934              :                         Real64 &OutletAirHumRat,       // Leaving air humidity ratio
    3935              :                         Real64 &TotWaterCoilLoad,      // Total heat transfer rate (W)
    3936              :                         Real64 &SenWaterCoilLoad,      // Sensible heat transfer rate (W)
    3937              :                         Real64 &SurfAreaWetFraction,   // Fraction of surface area wet
    3938              :                         HVAC::FanOp const fanOp,       // fan operating mode
    3939              :                         Real64 const PartLoadRatio     // part-load ratio of heating coil
    3940              : )
    3941              : {
    3942              : 
    3943              :     // FUNCTION INFORMATION:
    3944              :     // AUTHOR         Rahul Chillar
    3945              :     // DATE WRITTEN   March 2004
    3946              : 
    3947              :     // PURPOSE OF THIS FUNCTION:
    3948              :     // Calculate the performance of a cooling  coil when the external fin surface is
    3949              :     // part wet and part dry.  Results include outlet air temperature and humidity,
    3950              :     // outlet liquid temperature, sensible and total cooling capacities, and the wet
    3951              :     // fraction of the air-side surface area.
    3952              : 
    3953              :     // METHODOLOGY EMPLOYED:
    3954              :     // Models coil using effectiveness NTU model
    3955              : 
    3956              :     // REFERENCES:
    3957              :     // Elmahdy, A.H. and Mitalas, G.P.  1977. "A Simple Model for Cooling and
    3958              :     // Dehumidifying Coils for Use In Calculating Energy Requirements for Buildings,"
    3959              :     // ASHRAE Transactions,Vol.83 Part 2, pp. 103-117.
    3960              :     // TRNSYS.  1990.  A Transient System Simulation Program: Reference Manual.
    3961              :     // Solar Energy Laboratory, Univ. Wisconsin- Madison, pp. 4.6.8-1 - 4.6.8-12.
    3962              :     // Threlkeld, J.L.  1970.  Thermal Environmental Engineering, 2nd Edition,
    3963              :     // Englewood Cliffs: Prentice-Hall,Inc. pp. 254-270.
    3964              : 
    3965              :     // FUNCTION PARAMETER DEFINITIONS:
    3966        35521 :     int constexpr itmax(60);
    3967        35521 :     Real64 constexpr smalltempdiff(1.0e-9);
    3968              : 
    3969              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    3970              :     Real64 DryCoilHeatTranfer;             // Heat transfer rate for dry coil(W)
    3971              :     Real64 WetCoilTotalHeatTransfer;       // Total heat transfer rate for wet coil(W)
    3972              :     Real64 WetCoilSensibleHeatTransfer;    // Sensible heat transfer rate for wet coil(W)
    3973              :     Real64 SurfAreaWet;                    // Air-side area of wet coil(m2)
    3974              :     Real64 SurfAreaDry;                    // Air-side area of dry coil(m2)
    3975              :     Real64 DryCoilUA;                      // Overall heat transfer coefficient for dry coil(W/C)
    3976              :     Real64 WetDryInterfcWaterTemp;         // Liquid temperature at wet/dry boundary(C)
    3977              :     Real64 WetDryInterfcAirTemp;           // Air temperature at wet/dry boundary(C)
    3978              :     Real64 WetDryInterfcSurfTemp;          // Surface temperature at wet/dry boundary(C)
    3979              :     Real64 EstimateWetDryInterfcWaterTemp; // Estimated liquid temperature at wet/dry boundary(C)
    3980              :     Real64 EstimateSurfAreaWetFraction;    // Initial Estimate for Fraction of Surface Wet with condensation
    3981              :     Real64 WetPartUAInternal;              // UA of Wet Coil Internal
    3982              :     Real64 WetPartUAExternal;              // UA of Dry Coil External
    3983              :     Real64 WetDryInterfcHumRat;            // Humidity Ratio at interface of the wet dry transition
    3984              :     Real64 X1T;                            // Variables used in the two iteration in this subroutine.
    3985              :     Real64 NewSurfAreaWetFrac;             // Variables used in the two iteration in this subroutine.
    3986              :     Real64 ResultXT;                       // Variables used in the two iteration in this subroutine.
    3987              :     Real64 Y1T;                            // Variables used in the two iterations in this subroutine.
    3988              :     Real64 errorT;                         // Error in interation for First If loop
    3989              :     Real64 error;                          // Deviation of dependent variable in iteration
    3990              :     Real64 SurfAreaFracPrevious;
    3991              :     Real64 ErrorPrevious;
    3992              :     Real64 SurfAreaFracLast;
    3993              :     Real64 ErrorLast;
    3994              :     int iter;  // Iteration counter
    3995              :     int icvg;  // Iteration convergence flag
    3996              :     int icvgT; // Iteration Convergence Flag for First If loop
    3997              :     int itT;   // Iteration Counter for First If Loop
    3998              : 
    3999              :     // Iterates on SurfAreaWetFraction to converge on surface temperature equal to
    4000              :     // entering air dewpoint at wet/dry boundary.
    4001              : 
    4002              :     // Preliminary estimates of coil performance to begin iteration
    4003        35521 :     OutletWaterTemp = InletAirTemp;
    4004        35521 :     DryCoilHeatTranfer = 0.0;
    4005        35521 :     WetCoilTotalHeatTransfer = 0.0;
    4006        35521 :     WetCoilSensibleHeatTransfer = 0.0;
    4007              : 
    4008        35521 :     auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    4009        35521 :     if (FirstHVACIteration) {
    4010              :         // Estimate liquid temperature at boundary as entering air dew point
    4011        17439 :         WetDryInterfcWaterTemp = AirDewPointTemp;
    4012              : 
    4013              :         // Estimate fraction wet surface area based on liquid temperatures
    4014        17439 :         if (std::abs(OutletWaterTemp - InletWaterTemp) > smalltempdiff) {
    4015        17439 :             SurfAreaWetFraction = (WetDryInterfcWaterTemp - InletWaterTemp) / (OutletWaterTemp - InletWaterTemp);
    4016              :         } else {
    4017            0 :             SurfAreaWetFraction = 0.0;
    4018              :         }
    4019              : 
    4020              :     } else {
    4021        18082 :         SurfAreaWetFraction = waterCoil.SurfAreaWetFractionSaved;
    4022              :     }
    4023              :     // BEGIN LOOP to converge on SurfAreaWetFraction
    4024              :     // The method employed in this loop is as follows: The coil is partially wet and partially dry,
    4025              :     // we calculate the temperature of the coil at the interface, (the point at which the moisture begins
    4026              :     // to condense) temperature of the  water  at interface and air temp is dew point at that location.
    4027              :     // This is done by Iterating between the Completely Dry and Completely Wet Coil until the outlet
    4028              :     // water temperature of one coil equals the inlet water temperature of another.
    4029              :     // Using this value of interface temperature we now iterate to calculate Surface Fraction Wet, Iterate
    4030              :     // function perturbs the value of Surface Fraction Wet and based on this new value the entire loop is
    4031              :     // repeated to get a new interface water temperature and then surface fraction wet is again calculated.
    4032              :     // This process continues till the error between the Wet Dry Interface Temp and Air Dew Point becomes
    4033              :     // very negligible and in 95% of the cases its is a complete convergence to give the exact surface Wet
    4034              :     // fraction.
    4035        35521 :     NewSurfAreaWetFrac = SurfAreaWetFraction;
    4036        35521 :     error = 0.0;
    4037        35521 :     SurfAreaFracPrevious = SurfAreaWetFraction;
    4038        35521 :     ErrorPrevious = 0.0;
    4039        35521 :     SurfAreaFracLast = SurfAreaWetFraction;
    4040        35521 :     ErrorLast = 0.0;
    4041              : 
    4042       202450 :     for (iter = 1; iter <= itmax; ++iter) {
    4043              : 
    4044              :         // Calculating Surface Area Wet and Surface Area Dry
    4045       202450 :         SurfAreaWet = SurfAreaWetFraction * waterCoil.TotCoilOutsideSurfArea;
    4046       202450 :         SurfAreaDry = waterCoil.TotCoilOutsideSurfArea - SurfAreaWet;
    4047              : 
    4048              :         // Calculating UA values for the Dry Part of the Coil
    4049       202450 :         DryCoilUA = SurfAreaDry / (1.0 / waterCoil.UACoilInternalPerUnitArea + 1.0 / waterCoil.UADryExtPerUnitArea);
    4050              : 
    4051              :         // Calculating UA Value for the Wet part of the Coil
    4052       202450 :         WetPartUAExternal = waterCoil.UAWetExtPerUnitArea * SurfAreaWet;
    4053       202450 :         WetPartUAInternal = waterCoil.UACoilInternalPerUnitArea * SurfAreaWet;
    4054              : 
    4055              :         // Calculating Water Temperature at Wet Dry Interface of the coil
    4056       202450 :         WetDryInterfcWaterTemp = InletWaterTemp + SurfAreaWetFraction * (OutletWaterTemp - InletWaterTemp);
    4057              : 
    4058              :         // BEGIN LOOP to converge on liquid temperature at wet/dry boundary
    4059       805483 :         for (itT = 1; itT <= itmax; ++itT) {
    4060              : 
    4061              :             // Calculate dry coil performance with estimated liquid temperature at the boundary.
    4062       805483 :             CoilCompletelyDry(state,
    4063              :                               CoilNum,
    4064              :                               WetDryInterfcWaterTemp,
    4065              :                               InletAirTemp,
    4066              :                               DryCoilUA,
    4067              :                               OutletWaterTemp,
    4068              :                               WetDryInterfcAirTemp,
    4069              :                               WetDryInterfcHumRat,
    4070              :                               DryCoilHeatTranfer,
    4071              :                               fanOp,
    4072              :                               PartLoadRatio);
    4073              : 
    4074              :             // Calculate wet coil performance with calculated air temperature at the boundary.
    4075       805483 :             CoilCompletelyWet(state,
    4076              :                               CoilNum,
    4077              :                               InletWaterTemp,
    4078              :                               WetDryInterfcAirTemp,
    4079              :                               WetDryInterfcHumRat,
    4080              :                               WetPartUAInternal,
    4081              :                               WetPartUAExternal,
    4082              :                               EstimateWetDryInterfcWaterTemp,
    4083              :                               OutletAirTemp,
    4084              :                               OutletAirHumRat,
    4085              :                               WetCoilTotalHeatTransfer,
    4086              :                               WetCoilSensibleHeatTransfer,
    4087              :                               EstimateSurfAreaWetFraction,
    4088              :                               WetDryInterfcSurfTemp,
    4089              :                               fanOp,
    4090              :                               PartLoadRatio);
    4091              : 
    4092              :             // Iterating to calculate the actual wet dry interface water temperature.
    4093       805483 :             errorT = EstimateWetDryInterfcWaterTemp - WetDryInterfcWaterTemp;
    4094       805483 :             General::Iterate(ResultXT, 0.001, WetDryInterfcWaterTemp, errorT, X1T, Y1T, itT, icvgT);
    4095       805483 :             WetDryInterfcWaterTemp = ResultXT;
    4096              : 
    4097              :             // IF convergence is achieved then exit the itT to itmax Do loop.
    4098       805483 :             if (icvgT == 1) break;
    4099              : 
    4100              :         } // End Do for Liq Boundary temp Convergence
    4101              : 
    4102              :         // Wet Dry Interface temperature not converged after maximum specified iterations.
    4103              :         // Print error message, set return error flag
    4104       202450 :         if ((itT > itmax) && (!state.dataGlobal->WarmupFlag)) {
    4105            0 :             ShowWarningError(state, format("For Coil:Cooling:Water {}", waterCoil.Name));
    4106            0 :             ShowContinueError(state, "CoilPartWetPartDry: Maximum iterations exceeded for Liq Temp, at Interface");
    4107              :         }
    4108              : 
    4109              :         // If Following condition prevails then surface is dry, calculate dry coil performance and return
    4110       202450 :         if (SurfAreaWetFraction <= 0.0 && WetDryInterfcSurfTemp >= AirDewPointTemp) {
    4111              : 
    4112              :             // Calculating Value of Dry UA for the coil
    4113            0 :             DryCoilUA = waterCoil.TotCoilOutsideSurfArea / (1.0 / waterCoil.UACoilInternalPerUnitArea + 1.0 / waterCoil.UADryExtPerUnitArea);
    4114              : 
    4115              :             // Calling the Completely Dry Coil for outputs
    4116            0 :             CoilCompletelyDry(state,
    4117              :                               CoilNum,
    4118              :                               InletWaterTemp,
    4119              :                               InletAirTemp,
    4120              :                               DryCoilUA,
    4121              :                               OutletWaterTemp,
    4122              :                               OutletAirTemp,
    4123              :                               OutletAirHumRat,
    4124              :                               TotWaterCoilLoad,
    4125              :                               fanOp,
    4126              :                               PartLoadRatio);
    4127              : 
    4128              :             // Sensible load = Total load in a Completely Dry Coil
    4129            0 :             SenWaterCoilLoad = TotWaterCoilLoad;
    4130              : 
    4131              :             // All coil is Dry so fraction wet is ofcourse =0
    4132            0 :             SurfAreaWetFraction = 0.0;
    4133            0 :             return;
    4134              :         }
    4135              : 
    4136              :         // IF the coil is not Dry then iterate to calculate Fraction of surface area that is wet.
    4137       202450 :         error = WetDryInterfcSurfTemp - AirDewPointTemp;
    4138       202450 :         CoilAreaFracIter(
    4139              :             NewSurfAreaWetFrac, SurfAreaWetFraction, error, SurfAreaFracPrevious, ErrorPrevious, SurfAreaFracLast, ErrorLast, iter, icvg);
    4140       202450 :         SurfAreaWetFraction = NewSurfAreaWetFrac;
    4141              : 
    4142              :         // If converged, leave iteration loop
    4143       202450 :         if (icvg == 1) break;
    4144              : 
    4145              :         // Surface temperature not converged.  Repeat calculations with new
    4146              :         // estimate of fraction wet surface area.
    4147       166929 :         if (SurfAreaWetFraction > 1.0) SurfAreaWetFraction = 1.0;
    4148       166929 :         if (SurfAreaWetFraction <= 0.0) SurfAreaWetFraction = 0.0098;
    4149              : 
    4150              :     } // End do for the overall iteration
    4151              : 
    4152              :     // Calculate sum of total and sensible heat transfer from dry and wet parts.
    4153        35521 :     TotWaterCoilLoad = DryCoilHeatTranfer + WetCoilTotalHeatTransfer;
    4154        35521 :     SenWaterCoilLoad = DryCoilHeatTranfer + WetCoilSensibleHeatTransfer;
    4155              : 
    4156              :     // Save last iterations values for this current time step
    4157        35521 :     waterCoil.SurfAreaWetFractionSaved = SurfAreaWetFraction;
    4158              : }
    4159              : 
    4160              : // Calculating coil UA for Cooling Coil
    4161              : 
    4162            0 : Real64 CalcCoilUAbyEffectNTU(EnergyPlusData &state,
    4163              :                              int const CoilNum,
    4164              :                              Real64 const CapacityStream1,     // Capacity rate of stream1.(W/C)
    4165              :                              Real64 const EnergyInStreamOne,   // Inlet state of stream1.(C)
    4166              :                              Real64 const CapacityStream2,     // Capacity rate of stream2.(W/C)
    4167              :                              Real64 const EnergyInStreamTwo,   // Inlet state of stream2.(C)
    4168              :                              Real64 const DesTotalHeatTransfer // Heat transfer rate(W)
    4169              : )
    4170              : {
    4171              : 
    4172              :     // FUNCTION INFORMATION:
    4173              :     // AUTHOR         Rahul Chillar
    4174              :     // DATE WRITTEN   March 2004
    4175              : 
    4176              :     // PURPOSE OF THIS FUNCTION:
    4177              :     // Calculate the UA of a heat exchanger using the effectiveness-NTU relationships
    4178              :     // given the entering capacity rate and temperature of each flow stream, the
    4179              :     // heat transfer rate under these conditions and the heat exchanger configuration.
    4180              : 
    4181              :     // METHODOLOGY EMPLOYED:
    4182              :     // Models coil using effectiveness NTU model
    4183              : 
    4184              :     // Enforce explicit typing of all variables in this routine
    4185              : 
    4186              :     // Return value
    4187              :     Real64 CalcCoilUAbyEffectNTU; // Overall heat transfer coefficient(W/C)
    4188              : 
    4189              :     // FUNCTION PARAMETER DEFINITIONS:
    4190            0 :     Real64 constexpr SmallNo(1.e-9);
    4191            0 :     int constexpr itmax(12);
    4192              : 
    4193              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    4194              :     Real64 MaxHeatTransfer;       // Maximum heat transfer from inlet conditions (W)
    4195              :     Real64 EstimatedHeatTransfer; // Estimated heat transfer in iteration(W)
    4196              :     Real64 CoilUA;                // Estimated heat transfer coefficient(W/C)
    4197              :     Real64 error;                 // Deviation of dependent variable in iteration
    4198              :     Real64 X1;                    // Previous values of independent variable in iteration
    4199              :     Real64 Y1;
    4200              :     Real64 ResultX;
    4201              :     Real64 EnergyOutStreamOne;        // Intermediate Variable used
    4202              :     Real64 EnergyOutStreamTwo;        // Intermediate variable used
    4203              :     Real64 DesTotalHeatTransferCheck; // Check value to keep design total heat transfer in range
    4204              :     int iter;                         // Iteration index
    4205              :     int icvg;                         // Iteration convergence flag
    4206              : 
    4207              :     // Check for Q out of range (effectiveness > 1)
    4208            0 :     MaxHeatTransfer = std::abs(min(CapacityStream1, CapacityStream2) * (EnergyInStreamOne - EnergyInStreamTwo));
    4209              : 
    4210            0 :     auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    4211              :     // Error Message
    4212            0 :     if ((std::abs(DesTotalHeatTransfer) - MaxHeatTransfer) / max(MaxHeatTransfer, SmallNo) > SmallNo) {
    4213            0 :         ShowWarningError(state, format("For Coil:Cooling:Water {}", waterCoil.Name));
    4214            0 :         ShowContinueError(state, "CalcCoilUAbyEffectNTU:Given Q impossible for given inlet states, proceeding with MaxHeat Transfer");
    4215            0 :         ShowContinueError(state, "Check the Sizing:System and Sizing:Zone cooling design supply air temperature and ");
    4216            0 :         ShowContinueError(state,
    4217              :                           "the Sizing:Plant design Loop exit temperature.  There must be sufficient difference between these two temperatures.");
    4218              :     }
    4219              : 
    4220              :     // Design Heat Transfer cannot exceed Max heat Transfer , setting it value such that effectiveness<1.0
    4221            0 :     if ((DesTotalHeatTransfer) > (MaxHeatTransfer)) {
    4222              :         // Pegging value so that effectiveness is less than 1.
    4223            0 :         DesTotalHeatTransferCheck = 0.9 * MaxHeatTransfer;
    4224              : 
    4225              :         // Estimate CalcCoilUAbyEffectNTU
    4226            0 :         CoilUA = std::abs(DesTotalHeatTransferCheck / (EnergyInStreamOne - EnergyInStreamTwo));
    4227              : 
    4228              :     } else {
    4229              : 
    4230              :         // Estimate CalcCoilUAbyEffectNTU
    4231            0 :         CoilUA = std::abs(DesTotalHeatTransfer / (EnergyInStreamOne - EnergyInStreamTwo));
    4232              :     }
    4233              : 
    4234              :     // BEGIN LOOP to iteratively calculate CalcCoilUAbyEffectNTU
    4235            0 :     for (iter = 1; iter <= itmax; ++iter) {
    4236              : 
    4237              :         // Calculate heat transfer rate for estimated CalcCoilUAbyEffectNTU
    4238            0 :         CoilOutletStreamCondition(
    4239              :             state, CoilNum, CapacityStream1, EnergyInStreamOne, CapacityStream2, EnergyInStreamTwo, CoilUA, EnergyOutStreamOne, EnergyOutStreamTwo);
    4240              : 
    4241              :         // Initial Guess for a value of heat transfer
    4242            0 :         EstimatedHeatTransfer = CapacityStream1 * (EnergyInStreamOne - EnergyOutStreamOne);
    4243              : 
    4244              :         // Calculate new estimate for CalcCoilUAbyEffectNTU by iteration
    4245            0 :         if (DesTotalHeatTransfer > MaxHeatTransfer) {
    4246            0 :             error = std::abs(EstimatedHeatTransfer) - std::abs(DesTotalHeatTransferCheck);
    4247              :         } else {
    4248            0 :             error = std::abs(EstimatedHeatTransfer) - std::abs(DesTotalHeatTransfer);
    4249              :         }
    4250            0 :         General::Iterate(ResultX, 0.01, CoilUA, error, X1, Y1, iter, icvg);
    4251            0 :         CoilUA = ResultX;
    4252              :         // If converged, leave loop
    4253            0 :         if (icvg == 1) break;
    4254              :     }
    4255              : 
    4256              :     // If not converged after itmax iterations, return error code
    4257            0 :     if ((iter > itmax) && (!state.dataGlobal->WarmupFlag)) {
    4258            0 :         ShowWarningError(state, format("For Coil:Cooling:Water {}", waterCoil.Name));
    4259            0 :         ShowContinueError(state, "CalcCoilUAbyEffectNTU: Maximum iterations exceeded:Coil UA calculation");
    4260            0 :         CalcCoilUAbyEffectNTU = 0.0; // Autodesk:Return Line added to set return value: Using non-converged CoilUA value may be preferred but
    4261              :                                      // that was not happening
    4262              :     } else {
    4263              : 
    4264              :         // Assign value to CalcCoilUAbyEffectNTU
    4265            0 :         CalcCoilUAbyEffectNTU = CoilUA;
    4266              :     }
    4267              : 
    4268            0 :     return CalcCoilUAbyEffectNTU;
    4269              : }
    4270              : 
    4271              : // Calculating coil outlet stream conditions and coil UA for Cooling Coil
    4272              : 
    4273      1664903 : void CoilOutletStreamCondition(EnergyPlusData &state,
    4274              :                                int const CoilNum,
    4275              :                                Real64 const CapacityStream1,   // Capacity rate of stream1(W/C)
    4276              :                                Real64 const EnergyInStreamOne, // Inlet state of stream1 (C)
    4277              :                                Real64 const CapacityStream2,   // Capacity rate of stream2 (W/C)
    4278              :                                Real64 const EnergyInStreamTwo, // Inlet state of stream2 (C)
    4279              :                                Real64 const CoilUA,            // Heat transfer rateW)
    4280              :                                Real64 &EnergyOutStreamOne,     // Outlet state of stream1 (C)
    4281              :                                Real64 &EnergyOutStreamTwo      // Outlet state of stream2 (C)
    4282              : )
    4283              : {
    4284              : 
    4285              :     // FUNCTION INFORMATION:
    4286              :     // AUTHOR         Rahul Chillar
    4287              :     // DATE WRITTEN   March 2004
    4288              : 
    4289              :     // PURPOSE OF THIS FUNCTION:
    4290              :     // Calculate the outlet states of a simple heat exchanger using the effectiveness-Ntu
    4291              :     // method of analysis.
    4292              : 
    4293              :     // REFERENCES:
    4294              :     // Kays, W.M. and A.L. London.  1964.Compact Heat Exchangers, 2nd Ed.McGraw-Hill:New York.
    4295              : 
    4296              :     // FUNCTION PARAMETER DEFINITIONS:
    4297      1664903 :     Real64 constexpr LargeNo(1.e10);  // value used in place of infinity
    4298      1664903 :     Real64 constexpr SmallNo(1.e-15); // value used in place of zero
    4299              : 
    4300              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    4301              :     Real64 MinimumCapacityStream; // Minimum capacity rate of the streams(W/C)
    4302              :     Real64 MaximumCapacityStream; // Maximum capacity rate of the streams(W/C)
    4303              :     Real64 RatioStreamCapacity;   // Ratio of minimum to maximum capacity rate
    4304              :     Real64 NTU;                   // Number of transfer units
    4305      1664903 :     Real64 effectiveness(0.0);    // Heat exchanger effectiveness
    4306              :     Real64 MaxHeatTransfer;       // Maximum heat transfer possible(W)
    4307              :     Real64 e;                     // Intermediate variables in effectiveness equation
    4308              :     Real64 eta;
    4309              :     Real64 b;
    4310              :     Real64 d;
    4311              : 
    4312              :     // NTU and MinimumCapacityStream/MaximumCapacityStream (RatioStreamCapacity) calculations
    4313      1664903 :     MinimumCapacityStream = min(CapacityStream1, CapacityStream2);
    4314      1664903 :     MaximumCapacityStream = max(CapacityStream1, CapacityStream2);
    4315              : 
    4316      1664903 :     if (std::abs(MaximumCapacityStream) <= 1.e-6) { // .EQ. 0.0d0) THEN
    4317            0 :         RatioStreamCapacity = 1.0;
    4318              :     } else {
    4319      1664903 :         RatioStreamCapacity = MinimumCapacityStream / MaximumCapacityStream;
    4320              :     }
    4321              : 
    4322      1664903 :     if (std::abs(MinimumCapacityStream) <= 1.e-6) { // .EQ. 0.0d0) THEN
    4323            0 :         NTU = LargeNo;
    4324              :     } else {
    4325      1664903 :         NTU = CoilUA / MinimumCapacityStream;
    4326              :     }
    4327              : 
    4328      1664903 :     auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    4329              :     // Calculate effectiveness for special limiting cases
    4330      1664903 :     if (NTU <= 0.0) {
    4331        20932 :         effectiveness = 0.0;
    4332              : 
    4333      1643971 :     } else if (RatioStreamCapacity < SmallNo) {
    4334              :         // MinimumCapacityStream/MaximumCapacityStream = 0 and effectiveness is independent of configuration
    4335              :         // 20 is the Limit Chosen for Exponential Function, beyond which there is float point error.
    4336            0 :         if (NTU > 20.0) {
    4337            0 :             effectiveness = 1.0;
    4338              :         } else {
    4339            0 :             effectiveness = 1.0 - std::exp(-NTU);
    4340              :         }
    4341              :         // Calculate effectiveness depending on heat exchanger configuration
    4342      1643971 :     } else if (waterCoil.HeatExchType == state.dataWaterCoils->CounterFlow) {
    4343              : 
    4344              :         // Counterflow Heat Exchanger Configuration
    4345            0 :         if (std::abs(RatioStreamCapacity - 1.0) < SmallNo) {
    4346            0 :             effectiveness = NTU / (NTU + 1.0);
    4347              :         } else {
    4348            0 :             if (NTU * (1.0 - RatioStreamCapacity) > 20.0) {
    4349            0 :                 e = 0.0;
    4350              :             } else {
    4351            0 :                 e = std::exp(-NTU * (1.0 - RatioStreamCapacity));
    4352              :             }
    4353            0 :             effectiveness = (1.0 - e) / (1.0 - RatioStreamCapacity * e);
    4354              :         }
    4355              : 
    4356      1643971 :     } else if (waterCoil.HeatExchType == state.dataWaterCoils->CrossFlow) {
    4357              :         // Cross flow, both streams unmixed
    4358      1643971 :         eta = std::pow(NTU, -0.22);
    4359      1643971 :         if ((NTU * RatioStreamCapacity * eta) > 20.0) {
    4360            0 :             b = 1.0 / (RatioStreamCapacity * eta);
    4361            0 :             if (b > 20.0) {
    4362            0 :                 effectiveness = 1.0;
    4363              :             } else {
    4364            0 :                 effectiveness = 1.0 - std::exp(-b);
    4365            0 :                 if (effectiveness < 0.0) effectiveness = 0.0;
    4366              :             }
    4367              :         } else {
    4368      1643971 :             d = ((std::exp(-NTU * RatioStreamCapacity * eta) - 1.0) / (RatioStreamCapacity * eta));
    4369      1643971 :             if (d < -20.0 || d > 0.0) {
    4370            2 :                 effectiveness = 1.0;
    4371              :             } else {
    4372      1643969 :                 effectiveness = 1.0 - std::exp((std::exp(-NTU * RatioStreamCapacity * eta) - 1.0) / (RatioStreamCapacity * eta));
    4373      1643969 :                 if (effectiveness < 0.0) effectiveness = 0.0;
    4374              :             }
    4375              :         }
    4376              :     }
    4377              : 
    4378              :     // Determine leaving conditions for the two streams
    4379      1664903 :     MaxHeatTransfer = max(MinimumCapacityStream, SmallNo) * (EnergyInStreamOne - EnergyInStreamTwo);
    4380      1664903 :     EnergyOutStreamOne = EnergyInStreamOne - effectiveness * MaxHeatTransfer / max(CapacityStream1, SmallNo);
    4381      1664903 :     EnergyOutStreamTwo = EnergyInStreamTwo + effectiveness * MaxHeatTransfer / max(CapacityStream2, SmallNo);
    4382      1664903 : }
    4383              : 
    4384              : // Subroutine for caculating outlet condition if coil is wet , for Cooling Coil
    4385              : 
    4386       859111 : void WetCoilOutletCondition(EnergyPlusData &state,
    4387              :                             int const CoilNum,
    4388              :                             Real64 const AirTempIn,      // Entering air dry bulb temperature(C)
    4389              :                             Real64 const EnthAirInlet,   // Entering air enthalpy(J/kg)
    4390              :                             Real64 const EnthAirOutlet,  // Leaving air enthalpy(J/kg)
    4391              :                             Real64 const UACoilExternal, // Heat transfer coefficient for external surface (W/C)
    4392              :                             Real64 &OutletAirTemp,       // Leaving air dry bulb temperature(C)
    4393              :                             Real64 &OutletAirHumRat,     // Leaving air humidity ratio
    4394              :                             Real64 &SenWaterCoilLoad     // Sensible heat transfer rate(W)
    4395              : )
    4396              : {
    4397              : 
    4398              :     // FUNCTION INFORMATION:
    4399              :     // AUTHOR         Rahul Chillar
    4400              :     // DATE WRITTEN   Mar 2004
    4401              : 
    4402              :     // PURPOSE OF THIS FUNCTION:
    4403              :     // Calculate the leaving air temperature,the leaving air humidity ratio and the
    4404              :     // sensible cooling capacity of wet cooling coil.
    4405              : 
    4406              :     // METHODOLOGY EMPLOYED:
    4407              :     // Assumes condensate at uniform temperature.
    4408              : 
    4409              :     // REFERENCES:
    4410              :     // Elmahdy, A.H. and Mitalas, G.P.  1977."A Simple Model for Cooling and
    4411              :     // Dehumidifying Coils for Use In Calculating Energy Requirements for Buildings,"
    4412              :     // ASHRAE Transactions,Vol.83 Part 2, pp. 103-117.
    4413              : 
    4414              :     // FUNCTION PARAMETER DEFINITIONS:
    4415       859111 :     Real64 constexpr SmallNo(1.e-9); // SmallNo value used in place of zero
    4416              : 
    4417              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    4418              :     Real64 CapacitanceAir;        // Air capacity rate(W/C)
    4419              :     Real64 NTU;                   // Number of heat transfer units
    4420              :     Real64 effectiveness;         // Heat exchanger effectiveness
    4421              :     Real64 EnthAirCondensateTemp; // Saturated air enthalpy at temperature of condensate(J/kg)
    4422              :     Real64 TempCondensation;      // Temperature of condensate(C)
    4423              :     Real64 TempAirDewPoint;       // Temperature air dew point
    4424              : 
    4425              :     // Determine the temperature effectiveness, assuming the temperature
    4426              :     // of the condensate is constant (MinimumCapacityStream/MaximumCapacityStream = 0) and the specific heat
    4427              :     // of moist air is constant
    4428              : 
    4429       859111 :     auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    4430       859111 :     CapacitanceAir = waterCoil.InletAirMassFlowRate * PsyCpAirFnW(waterCoil.InletAirHumRat);
    4431              : 
    4432              :     // Calculating NTU from UA and Capacitance.
    4433              :     // del      NTU = UACoilExternal/MAX(CapacitanceAir,SmallNo)
    4434              :     // del      effectiveness = 1 - EXP(-MAX(0.0d0,NTU))
    4435              :     // Calculating NTU from UA and Capacitance.
    4436       859111 :     if (UACoilExternal > 0.0) {
    4437       859111 :         if (CapacitanceAir > 0.0) {
    4438       859111 :             NTU = UACoilExternal / CapacitanceAir;
    4439              :         } else {
    4440            0 :             NTU = 0.0;
    4441              :         }
    4442       859111 :         effectiveness = 1.0 - std::exp(-NTU);
    4443              :     } else {
    4444            0 :         effectiveness = 0.0;
    4445              :     }
    4446              : 
    4447              :     // Calculate coil surface enthalpy and temperature at the exit
    4448              :     // of the wet part of the coil using the effectiveness relation
    4449       859111 :     effectiveness = max(effectiveness, SmallNo);
    4450       859111 :     EnthAirCondensateTemp = EnthAirInlet - (EnthAirInlet - EnthAirOutlet) / effectiveness;
    4451              : 
    4452              :     // Calculate condensate temperature as the saturation temperature
    4453              :     // at given saturation enthalpy
    4454       859111 :     TempCondensation = PsyTsatFnHPb(state, EnthAirCondensateTemp, state.dataEnvrn->OutBaroPress);
    4455              : 
    4456       859111 :     TempAirDewPoint = PsyTdpFnWPb(state, waterCoil.InletAirHumRat, state.dataEnvrn->OutBaroPress);
    4457              : 
    4458       859111 :     if ((TempAirDewPoint - TempCondensation) > 0.1) {
    4459              : 
    4460              :         // Calculate Outlet Air Temperature using effectivness
    4461       856898 :         OutletAirTemp = AirTempIn - (AirTempIn - TempCondensation) * effectiveness;
    4462              :         // Calculate Outlet air humidity ratio from PsyWFnTdbH routine
    4463       856898 :         OutletAirHumRat = PsyWFnTdbH(state, OutletAirTemp, EnthAirOutlet);
    4464              : 
    4465              :     } else {
    4466         2213 :         OutletAirHumRat = waterCoil.InletAirHumRat;
    4467         2213 :         OutletAirTemp = PsyTdbFnHW(EnthAirOutlet, OutletAirHumRat);
    4468              :     }
    4469              : 
    4470              :     // Calculate Sensible Coil Load
    4471       859111 :     SenWaterCoilLoad = CapacitanceAir * (AirTempIn - OutletAirTemp);
    4472       859111 : }
    4473              : 
    4474              : // Beginning of Update subroutines for the WaterCoil Module
    4475              : // *****************************************************************************
    4476              : 
    4477       320689 : void UpdateWaterCoil(EnergyPlusData &state, int const CoilNum)
    4478              : {
    4479              :     // SUBROUTINE INFORMATION:
    4480              :     //       AUTHOR         Richard Liesen
    4481              :     //       DATE WRITTEN   1998
    4482              :     //       MODIFIED       April 2004: Rahul Chillar
    4483              :     //                      Feb 2010 B. Griffith, plant upgrades
    4484              :     //       RE-ENGINEERED  na
    4485              : 
    4486              :     // PURPOSE OF THIS SUBROUTINE:
    4487              :     // This subroutine updates the coil outlet nodes.
    4488              : 
    4489              :     // METHODOLOGY EMPLOYED:
    4490              :     // Data is moved from the coil data structure to the coil outlet nodes.
    4491              : 
    4492              :     // Locals
    4493              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    4494              : 
    4495              :     // SUBROUTINE PARAMETER DEFINITIONS:
    4496              :     // na
    4497              : 
    4498              :     // INTERFACE BLOCK SPECIFICATIONS
    4499              :     // na
    4500              : 
    4501              :     // DERIVED TYPE DEFINITIONS
    4502              :     // na
    4503              : 
    4504              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4505       320689 :     auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    4506       320689 :     int const AirInletNode = waterCoil.AirInletNodeNum;
    4507       320689 :     int const AirOutletNode = waterCoil.AirOutletNodeNum;
    4508       320689 :     int const WaterOutletNode = waterCoil.WaterOutletNodeNum;
    4509              : 
    4510              :     // Set the outlet air nodes of the WaterCoil
    4511       320689 :     state.dataLoopNodes->Node(AirOutletNode).MassFlowRate = waterCoil.OutletAirMassFlowRate;
    4512       320689 :     state.dataLoopNodes->Node(AirOutletNode).Temp = waterCoil.OutletAirTemp;
    4513       320689 :     state.dataLoopNodes->Node(AirOutletNode).HumRat = waterCoil.OutletAirHumRat;
    4514       320689 :     state.dataLoopNodes->Node(AirOutletNode).Enthalpy = waterCoil.OutletAirEnthalpy;
    4515              : 
    4516       320689 :     state.dataLoopNodes->Node(WaterOutletNode).Temp = waterCoil.OutletWaterTemp;
    4517       320689 :     state.dataLoopNodes->Node(WaterOutletNode).Enthalpy = waterCoil.OutletWaterEnthalpy;
    4518              : 
    4519              :     // Set the outlet nodes for properties that just pass through & not used
    4520       320689 :     state.dataLoopNodes->Node(AirOutletNode).Quality = state.dataLoopNodes->Node(AirInletNode).Quality;
    4521       320689 :     state.dataLoopNodes->Node(AirOutletNode).Press = state.dataLoopNodes->Node(AirInletNode).Press;
    4522       320689 :     state.dataLoopNodes->Node(AirOutletNode).MassFlowRateMin = state.dataLoopNodes->Node(AirInletNode).MassFlowRateMin;
    4523       320689 :     state.dataLoopNodes->Node(AirOutletNode).MassFlowRateMax = state.dataLoopNodes->Node(AirInletNode).MassFlowRateMax;
    4524       320689 :     state.dataLoopNodes->Node(AirOutletNode).MassFlowRateMinAvail = state.dataLoopNodes->Node(AirInletNode).MassFlowRateMinAvail;
    4525       320689 :     state.dataLoopNodes->Node(AirOutletNode).MassFlowRateMaxAvail = state.dataLoopNodes->Node(AirInletNode).MassFlowRateMaxAvail;
    4526       320689 :     if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    4527            0 :         state.dataLoopNodes->Node(AirOutletNode).CO2 = state.dataLoopNodes->Node(AirInletNode).CO2;
    4528              :     }
    4529       320689 :     if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    4530            0 :         state.dataLoopNodes->Node(AirOutletNode).GenContam = state.dataLoopNodes->Node(AirInletNode).GenContam;
    4531              :     }
    4532       320689 : }
    4533              : 
    4534              : //        End of Update subroutines for the WaterCoil Module
    4535              : // *****************************************************************************
    4536              : 
    4537              : // Beginning of Reporting subroutines for the WaterCoil Module
    4538              : // *****************************************************************************
    4539              : 
    4540       320689 : void ReportWaterCoil(EnergyPlusData &state, int const CoilNum)
    4541              : {
    4542              : 
    4543              :     // SUBROUTINE INFORMATION:
    4544              :     //       AUTHOR         Richard Liesen
    4545              :     //       DATE WRITTEN   1998
    4546              : 
    4547              :     // PURPOSE OF THIS SUBROUTINE:
    4548              :     // This subroutine updates the report variable for the coils.
    4549              : 
    4550       320689 :     auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    4551       320689 :     if (waterCoil.reportCoilFinalSizes) {
    4552        36063 :         if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingHVACSizingSimulations && !state.dataGlobal->DoingSizing) {
    4553           34 :             std::string coilObjClassName;
    4554           34 :             if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
    4555           18 :                 coilObjClassName = "Coil:Heating:Water";
    4556           18 :                 state.dataRptCoilSelection->coilSelectionReportObj->setCoilFinalSizes(state,
    4557           18 :                                                                                       waterCoil.Name,
    4558              :                                                                                       coilObjClassName,
    4559              :                                                                                       waterCoil.DesWaterHeatingCoilRate,
    4560              :                                                                                       waterCoil.DesWaterHeatingCoilRate,
    4561              :                                                                                       waterCoil.DesAirVolFlowRate,
    4562              :                                                                                       waterCoil.MaxWaterVolFlowRate);
    4563           18 :                 waterCoil.reportCoilFinalSizes = false;
    4564           16 :             } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling) {
    4565            1 :                 coilObjClassName = "Coil:Cooling:Water:DetailedGeometry";
    4566            1 :                 state.dataRptCoilSelection->coilSelectionReportObj->setCoilFinalSizes(state,
    4567            1 :                                                                                       waterCoil.Name,
    4568              :                                                                                       coilObjClassName,
    4569              :                                                                                       waterCoil.DesWaterCoolingCoilRate,
    4570              :                                                                                       -999.0,
    4571              :                                                                                       waterCoil.DesAirVolFlowRate,
    4572              :                                                                                       waterCoil.MaxWaterVolFlowRate);
    4573            1 :                 waterCoil.reportCoilFinalSizes = false;
    4574           15 :             } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) {
    4575           15 :                 coilObjClassName = "Coil:Cooling:Water";
    4576           15 :                 state.dataRptCoilSelection->coilSelectionReportObj->setCoilFinalSizes(state,
    4577           15 :                                                                                       waterCoil.Name,
    4578              :                                                                                       coilObjClassName,
    4579              :                                                                                       waterCoil.DesWaterCoolingCoilRate,
    4580              :                                                                                       -999.0,
    4581              :                                                                                       waterCoil.DesAirVolFlowRate,
    4582              :                                                                                       waterCoil.MaxWaterVolFlowRate);
    4583           15 :                 waterCoil.reportCoilFinalSizes = false;
    4584              :             }
    4585           34 :         }
    4586              :     }
    4587       320689 :     Real64 ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
    4588              :     // report the WaterCoil energy from this component
    4589       320689 :     waterCoil.TotWaterHeatingCoilEnergy = waterCoil.TotWaterHeatingCoilRate * ReportingConstant;
    4590       320689 :     waterCoil.TotWaterCoolingCoilEnergy = waterCoil.TotWaterCoolingCoilRate * ReportingConstant;
    4591       320689 :     waterCoil.SenWaterCoolingCoilEnergy = waterCoil.SenWaterCoolingCoilRate * ReportingConstant;
    4592              : 
    4593              :     // report the WaterCoil water collection to water storage tank (if needed)
    4594              : 
    4595       320689 :     if (waterCoil.CondensateCollectMode == state.dataWaterCoils->CondensateToTank) {
    4596              :         // calculate and report condensation rates  (how much water extracted from the air stream)
    4597              :         // water volumetric flow of water in m3/s for water system interactions
    4598              :         //  put here to catch all types of DX coils
    4599            0 :         Real64 Tavg = (waterCoil.InletAirTemp + waterCoil.OutletAirTemp) / 2.0;
    4600              :         //   CR9155 Remove specific humidity calculations
    4601              :         //  mdot * del HumRat / rho water
    4602            0 :         waterCoil.CondensateVdot =
    4603            0 :             max(0.0, (waterCoil.InletAirMassFlowRate * (waterCoil.InletAirHumRat - waterCoil.OutletAirHumRat) / Psychrometrics::RhoH2O(Tavg)));
    4604            0 :         waterCoil.CondensateVol = waterCoil.CondensateVdot * ReportingConstant;
    4605              : 
    4606            0 :         state.dataWaterData->WaterStorage(waterCoil.CondensateTankID).VdotAvailSupply(waterCoil.CondensateTankSupplyARRID) = waterCoil.CondensateVdot;
    4607            0 :         state.dataWaterData->WaterStorage(waterCoil.CondensateTankID).TwaterSupply(waterCoil.CondensateTankSupplyARRID) = waterCoil.OutletAirTemp;
    4608              :     }
    4609       320689 : }
    4610              : 
    4611              : //        End of Reporting subroutines for the WaterCoil Module
    4612              : // *****************************************************************************
    4613              : 
    4614              : // Beginning of Coil Utility subroutines for the Detailed Model
    4615              : // *****************************************************************************
    4616              : 
    4617            4 : void CalcDryFinEffCoef(EnergyPlusData &state, Real64 const OutTubeEffFinDiamRatio, Array1D<Real64> &PolynomCoef)
    4618              : {
    4619              :     // SUBROUTINE INFORMATION:
    4620              :     //       AUTHOR   Unknown
    4621              :     //       DATE WRITTEN   Unknown
    4622              :     //       DATE REWRITTEN  April 1997 by Russell D. Taylor, Ph.D.
    4623              :     //       MODIFIED
    4624              :     //       RE-ENGINEERED
    4625              : 
    4626              :     // PURPOSE OF THIS SUBROUTINE:
    4627              :     // The following subroutines are used once per cooling coil
    4628              :     // simulation to obtain the coefficients of the dry fin
    4629              :     // efficiency equation.  CalcDryFinEffCoef is the main calling
    4630              :     // routine which manages calls to the Bessel funtion and polynomial
    4631              :     // fit routines.
    4632              : 
    4633              :     // REFERENCES:
    4634              :     // First found in MODSIM.
    4635              :     // USE STATEMENTS:
    4636              :     // na
    4637              : 
    4638              :     // Argument array dimensioning
    4639              : 
    4640              :     // Locals
    4641              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    4642              : 
    4643              :     // SUBROUTINE PARAMETER DEFINITIONS:
    4644              :     // na
    4645              : 
    4646              :     // INTERFACE BLOCK SPECIFICATIONS
    4647              :     // na
    4648              : 
    4649              :     // DERIVED TYPE DEFINITIONS
    4650              :     // na
    4651              : 
    4652              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4653              :     Real64 FAI;
    4654              :     Real64 FED;
    4655              :     Real64 FEDnumerator;
    4656              :     int I;
    4657              :     int IE1;
    4658              :     int IE2;
    4659              :     int IE3;
    4660              :     int IE4;
    4661              :     int IE5;
    4662              :     int IE6;
    4663              :     Real64 R1;
    4664              :     Real64 R1I1;
    4665              :     Real64 R1K1;
    4666              :     Real64 R2;
    4667              :     Real64 R2I0;
    4668              :     Real64 R2I1;
    4669              :     Real64 R2K0;
    4670              :     Real64 R2K1;
    4671              :     Real64 RO;
    4672              : 
    4673            4 :     FAI = 0.02;
    4674          244 :     for (I = 1; I <= WaterCoils::MaxOrderedPairs; ++I) {
    4675          240 :         FAI += 0.035;
    4676          240 :         R1 = FAI / (1.0 - OutTubeEffFinDiamRatio);
    4677          240 :         R2 = R1 * OutTubeEffFinDiamRatio;
    4678          240 :         RO = 2.0 * OutTubeEffFinDiamRatio / (FAI * (1.0 + OutTubeEffFinDiamRatio));
    4679          240 :         CalcIBesselFunc(R1, 1, R1I1, IE1);
    4680          240 :         CalcKBesselFunc(R2, 1, R2K1, IE2);
    4681          240 :         CalcIBesselFunc(R2, 1, R2I1, IE3);
    4682          240 :         CalcKBesselFunc(R1, 1, R1K1, IE4);
    4683          240 :         CalcIBesselFunc(R2, 0, R2I0, IE5);
    4684          240 :         CalcKBesselFunc(R2, 0, R2K0, IE6);
    4685          240 :         FEDnumerator = RO * (R1I1 * R2K1 - R2I1 * R1K1);
    4686          240 :         if (FEDnumerator != 0.0) {
    4687          240 :             FED = FEDnumerator / (R2I0 * R1K1 + R1I1 * R2K0);
    4688              :         } else {
    4689            0 :             FED = 0.0;
    4690              :         }
    4691              :         //      FED = RO * (R1I1 * R2K1 - R2I1 * R1K1) / (R2I0 * R1K1 + R1I1 * R2K0)
    4692          240 :         state.dataWaterCoils->OrderedPair(I, 1) = FAI;
    4693          240 :         state.dataWaterCoils->OrderedPair(I, 2) = FED;
    4694              :     }
    4695            4 :     CalcPolynomCoef(state, state.dataWaterCoils->OrderedPair, PolynomCoef);
    4696            4 : }
    4697              : 
    4698          720 : void CalcIBesselFunc(Real64 const BessFuncArg, int const BessFuncOrd, Real64 &IBessFunc, int &ErrorCode)
    4699              : {
    4700              :     // SUBROUTINE INFORMATION:
    4701              :     //       AUTHOR   Unknown
    4702              :     //       DATE WRITTEN   Unknown
    4703              :     //       DATE REWRITTEN  April 1997 by Russell D. Taylor, Ph.D.
    4704              :     //       MODIFIED
    4705              :     //       RE-ENGINEERED
    4706              : 
    4707              :     // PURPOSE OF THIS SUBROUTINE:
    4708              :     // To calculate the modified Bessel Function from order 0 to BessFuncOrd
    4709              :     // BessFuncArg    ARGUMENT OF BESSEL FUNCTION
    4710              :     // BessFuncOrd    ORDER OF BESSEL FUNCTION, GREATER THAN OR EQUAL TO ZERO
    4711              :     // IBessFunc   RESULTANT VALUE OF I BESSEL FUNCTION
    4712              :     // ErrorCode  RESULTANT ERROR CODE:
    4713              :     //       ErrorCode = 0   NO ERROR
    4714              :     //       ErrorCode = 1   BessFuncOrd .LT. 0
    4715              :     //       ErrorCode = 2   BessFuncArg .LT. 0
    4716              :     //       ErrorCode = 3   IBessFunc .LT. 10**(-30),     IBessFunc IS SET TO 0
    4717              :     //       ErrorCode = 4   BessFuncArg .GT. BessFuncOrd & BessFuncArg .GT. 90,  IBessFunc IS SET TO 10**38
    4718              : 
    4719              :     // REFERENCES:
    4720              :     // First found in MODSIM.
    4721              : 
    4722              :     // USE STATEMENTS:
    4723              :     // na
    4724              : 
    4725              :     // Locals
    4726              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    4727              : 
    4728              :     // SUBROUTINE PARAMETER DEFINITIONS:
    4729          720 :     Real64 constexpr ErrorTol(1.0e-06);
    4730              : 
    4731              :     // INTERFACE BLOCK SPECIFICATIONS
    4732              :     // na
    4733              : 
    4734              :     // DERIVED TYPE DEFINITIONS
    4735              :     // na
    4736              : 
    4737              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4738              :     int LoopCount;
    4739              : 
    4740              :     Real64 FI;
    4741              :     Real64 FK;
    4742              :     Real64 TERM;
    4743              : 
    4744          720 :     ErrorCode = 0;
    4745          720 :     IBessFunc = 1.0;
    4746          720 :     if (BessFuncArg == 0.0 && BessFuncOrd == 0) return;
    4747              : 
    4748          720 :     if (BessFuncOrd < 0) {
    4749            0 :         ErrorCode = 1;
    4750            0 :         return;
    4751          720 :     } else if (BessFuncArg < 0.0) {
    4752            0 :         ErrorCode = 2;
    4753            0 :         return;
    4754          720 :     } else if (BessFuncArg > 12.0 && BessFuncArg > BessFuncOrd) {
    4755            0 :         if (BessFuncArg > 90.0) {
    4756            0 :             ErrorCode = 4;
    4757            0 :             IBessFunc = 1.0e30;
    4758            0 :             return;
    4759              :         }
    4760            0 :         TERM = 1.0;
    4761            0 :         IBessFunc = 1.0;
    4762            0 :         for (LoopCount = 1; LoopCount <= 30; ++LoopCount) { // Start of 1st LoopCount Loop
    4763            0 :             if (std::abs(TERM) <= std::abs(ErrorTol * IBessFunc)) {
    4764            0 :                 IBessFunc *= std::exp(BessFuncArg) / std::sqrt(2.0 * Constant::Pi * BessFuncArg);
    4765            0 :                 return;
    4766              :             }
    4767            0 :             TERM *= 0.125 / BessFuncArg * (pow_2(2 * LoopCount - 1) - 4 * BessFuncOrd * BessFuncOrd) / double(LoopCount);
    4768            0 :             IBessFunc += TERM;
    4769              :         } // End of 1st LoopCount loop
    4770              :     }
    4771              : 
    4772          720 :     TERM = 1.0;
    4773          720 :     if (BessFuncOrd > 0) {
    4774          960 :         for (LoopCount = 1; LoopCount <= BessFuncOrd; ++LoopCount) { // Start of 2nd LoopCount Loop
    4775          480 :             FI = LoopCount;
    4776          480 :             if (std::abs(TERM) < 1.0e-30 * FI / (BessFuncArg * 2.0)) {
    4777            0 :                 ErrorCode = 3;
    4778            0 :                 IBessFunc = 0.0;
    4779            0 :                 return;
    4780              :             }
    4781          480 :             TERM *= BessFuncArg / (2.0 * FI);
    4782              :         } // End of 2nd LoopCount loop
    4783              :     }
    4784              : 
    4785          720 :     IBessFunc = TERM;
    4786         4524 :     for (LoopCount = 1; LoopCount <= 1000; ++LoopCount) { // Start of 3rd LoopCount Loop
    4787         4524 :         if (std::abs(TERM) <= std::abs(IBessFunc * ErrorTol)) return;
    4788         3804 :         FK = LoopCount * (BessFuncOrd + LoopCount);
    4789         3804 :         TERM *= pow_2(BessFuncArg) / (4.0 * FK);
    4790         3804 :         IBessFunc += TERM;
    4791              :     } // End of  3rd LoopCount loop
    4792              : }
    4793              : 
    4794          720 : void CalcKBesselFunc(Real64 const BessFuncArg, int const BessFuncOrd, Real64 &KBessFunc, int &ErrorCode)
    4795              : {
    4796              :     // SUBROUTINE INFORMATION:
    4797              :     //       AUTHOR   Unknown
    4798              :     //       DATE WRITTEN   Unknown
    4799              :     //       DATE REWRITTEN  April 1997 by Russell D. Taylor, Ph.D.
    4800              :     //       MODIFIED
    4801              :     //       RE-ENGINEERED
    4802              : 
    4803              :     // PURPOSE OF THIS SUBROUTINE:
    4804              :     // To calculate the K Bessel Function for a given argument and
    4805              :     // order
    4806              :     //  BessFuncArg    THE ARGUMENT OF THE K BESSEL FUNCTION DESIRED
    4807              :     //  BessFuncOrd    THE ORDER OF THE K BESSEL FUNCTION DESIRED
    4808              :     //  KBessFunc   THE RESULTANT K BESSEL FUNCTION
    4809              :     //  ErrorCode  RESULTANT ERROR CODE:
    4810              :     //        ErrorCode=0  NO ERROR
    4811              :     //        ErrorCode=1  BessFuncOrd IS NEGATIVE
    4812              :     //        ErrorCode=2  BessFuncArg IS ZERO OR NEGATIVE
    4813              :     //        ErrorCode=3  BessFuncArg .GT. 85, KBessFunc .LT. 10**-38; KBessFunc SET TO 0.
    4814              :     //        ErrorCode=4  KBessFunc .GT. 10**38; KBessFunc SET TO 10**38
    4815              :     // NOTE: BessFuncOrd MUST BE GREATER THAN OR EQUAL TO ZERO
    4816              :     // METHOD:
    4817              :     //  COMPUTES ZERO ORDER AND FIRST ORDER BESSEL FUNCTIONS USING
    4818              :     //  SERIES APPROXIMATIONS AND THEN COMPUTES BessFuncOrd TH ORDER FUNCTION
    4819              :     //  USING RECURRENCE RELATION.
    4820              :     //  RECURRENCE RELATION AND POLYNOMIAL APPROXIMATION TECHNIQUE
    4821              :     //  AS DESCRIBED BY A.J.M. HITCHCOCK, 'POLYNOMIAL APPROXIMATIONS
    4822              :     //  TO BESSEL FUNCTIONS OF ORDER ZERO AND ONE AND TO RELATED
    4823              :     //  FUNCTIONS,' M.T.A.C., V.11, 1957, PP. 86-88, AND G.BessFuncOrd. WATSON,
    4824              :     //  'A TREATISE ON THE THEORY OF BESSEL FUNCTIONS,' CAMBRIDGE
    4825              :     //  UNIVERSITY PRESS, 1958, P.62
    4826              : 
    4827              :     // USE STATEMENTS:
    4828              :     // na
    4829              : 
    4830              :     // Locals
    4831              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    4832              : 
    4833              :     // SUBROUTINE PARAMETER DEFINITIONS:
    4834          720 :     Real64 constexpr GJMAX(1.0e+38);
    4835              : 
    4836              :     // INTERFACE BLOCK SPECIFICATIONS
    4837              :     // na
    4838              : 
    4839              :     // DERIVED TYPE DEFINITIONS
    4840              :     // na
    4841              : 
    4842              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4843              :     int LoopCount;
    4844              :     bool StopLoop;
    4845              : 
    4846              :     Real64 FACT;
    4847              :     Real64 G0;
    4848              :     Real64 G1;
    4849              :     Real64 GJ;
    4850              :     Real64 HJ;
    4851          720 :     Array1D<Real64> T(12);
    4852              :     Real64 X2J;
    4853              : 
    4854          720 :     KBessFunc = 0.0;
    4855          720 :     G0 = 0.0;
    4856          720 :     GJ = 0.0;
    4857              : 
    4858          720 :     if (BessFuncOrd < 0.0) {
    4859            0 :         ErrorCode = 1;
    4860            0 :         return;
    4861          720 :     } else if (BessFuncArg <= 0.0) {
    4862            0 :         ErrorCode = 2;
    4863            0 :         return;
    4864          720 :     } else if (BessFuncArg > 85.0) {
    4865            0 :         ErrorCode = 3;
    4866            0 :         KBessFunc = 0.0;
    4867            0 :         return;
    4868              :     }
    4869              : 
    4870          720 :     ErrorCode = 0;
    4871              : 
    4872              :     //     Use polynomial approximation if BessFuncArg > 1.
    4873              : 
    4874          720 :     if (BessFuncArg > 1.0) {
    4875          460 :         T(1) = 1.0 / BessFuncArg;
    4876         5520 :         for (LoopCount = 2; LoopCount <= 12; ++LoopCount) {
    4877         5060 :             T(LoopCount) = T(LoopCount - 1) / BessFuncArg;
    4878              :         } // End of LoopCount Loop
    4879          460 :         if (BessFuncOrd != 1) {
    4880              : 
    4881              :             //     Compute K0 using polynomial approximation
    4882              : 
    4883          272 :             G0 = std::exp(-BessFuncArg) *
    4884          136 :                  (1.2533141 - 0.1566642 * T(1) + 0.08811128 * T(2) - 0.09139095 * T(3) + 0.1344596 * T(4) - 0.2299850 * T(5) + 0.3792410 * T(6) -
    4885          136 :                   0.5247277 * T(7) + 0.5575368 * T(8) - 0.4262633 * T(9) + 0.2184518 * T(10) - 0.06680977 * T(11) + 0.009189383 * T(12)) *
    4886          136 :                  std::sqrt(1.0 / BessFuncArg);
    4887          136 :             if (BessFuncOrd == 0) {
    4888          136 :                 KBessFunc = G0;
    4889          136 :                 return;
    4890              :             }
    4891              :         }
    4892              : 
    4893              :         //     Compute K1 using polynomial approximation
    4894              : 
    4895          648 :         G1 = std::exp(-BessFuncArg) *
    4896          324 :              (1.2533141 + 0.4699927 * T(1) - 0.1468583 * T(2) + 0.1280427 * T(3) - 0.1736432 * T(4) + 0.2847618 * T(5) - 0.4594342 * T(6) +
    4897          324 :               0.6283381 * T(7) - 0.6632295 * T(8) + 0.5050239 * T(9) - 0.2581304 * T(10) + 0.07880001 * T(11) - 0.01082418 * T(12)) *
    4898          324 :              std::sqrt(1.0 / BessFuncArg);
    4899          324 :         if (BessFuncOrd == 1) {
    4900          324 :             KBessFunc = G1;
    4901          324 :             return;
    4902              :         }
    4903              :     } else {
    4904              : 
    4905              :         //     Use series expansion if BessFuncArg <= 1.
    4906              : 
    4907          260 :         if (BessFuncOrd != 1) {
    4908              : 
    4909              :             //     Compute K0 using series expansion
    4910              : 
    4911          104 :             G0 = -(0.5772157 + std::log(BessFuncArg / 2.0));
    4912          104 :             X2J = 1.0;
    4913          104 :             FACT = 1.0;
    4914          104 :             HJ = 0.0;
    4915          728 :             for (LoopCount = 1; LoopCount <= 6; ++LoopCount) {
    4916          624 :                 X2J *= pow_2(BessFuncArg) / 4.0;
    4917          624 :                 FACT *= pow_2(1.0 / double(LoopCount));
    4918          624 :                 HJ += 1.0 / double(LoopCount);
    4919          624 :                 G0 += X2J * FACT * (HJ - (0.5772157 + std::log(BessFuncArg / 2.0)));
    4920              :             } // End of LoopCount Loop
    4921          104 :             if (BessFuncOrd == 0.0) {
    4922          104 :                 KBessFunc = G0;
    4923          104 :                 return;
    4924              :             }
    4925              :         }
    4926              : 
    4927              :         //     Compute K1 using series expansion
    4928              : 
    4929          156 :         X2J = BessFuncArg / 2.0;
    4930          156 :         FACT = 1.0;
    4931          156 :         HJ = 1.0;
    4932          156 :         G1 = 1.0 / BessFuncArg + X2J * (0.5 + (0.5772157 + std::log(BessFuncArg / 2.0)) - HJ);
    4933         1248 :         for (LoopCount = 2; LoopCount <= 8; ++LoopCount) {
    4934         1092 :             X2J *= pow_2(BessFuncArg) / 4.0;
    4935         1092 :             FACT *= pow_2(1.0 / double(LoopCount));
    4936         1092 :             HJ += 1.0 / double(LoopCount);
    4937         1092 :             G1 += X2J * FACT * (0.5 + ((0.5772157 + std::log(BessFuncArg / 2.0)) - HJ) * double(LoopCount));
    4938              :         } // End of LoopCount Loop
    4939          156 :         if (BessFuncOrd == 1) {
    4940          156 :             KBessFunc = G1;
    4941          156 :             return;
    4942              :         }
    4943              :     }
    4944              : 
    4945              :     //     From K0 and K1 compute KN using recurrence relation
    4946              : 
    4947            0 :     LoopCount = 2;
    4948            0 :     StopLoop = false;
    4949            0 :     while (LoopCount <= BessFuncOrd && !StopLoop) {
    4950            0 :         GJ = 2.0 * (double(LoopCount) - 1.0) * G1 / BessFuncArg + G0;
    4951            0 :         if (GJ - GJMAX > 0.0) {
    4952            0 :             ErrorCode = 4;
    4953            0 :             GJ = GJMAX;
    4954            0 :             StopLoop = true;
    4955              :         } else {
    4956            0 :             G0 = G1;
    4957            0 :             G1 = GJ;
    4958            0 :             ++LoopCount;
    4959              :         }
    4960              :     } // End of LoopCount Loop
    4961            0 :     KBessFunc = GJ;
    4962          720 : }
    4963              : 
    4964            4 : void CalcPolynomCoef(EnergyPlusData &state, Array2<Real64> const &OrderedPair, Array1D<Real64> &PolynomCoef)
    4965              : {
    4966              :     // SUBROUTINE INFORMATION:
    4967              :     //       AUTHOR   Unknown
    4968              :     //       DATE WRITTEN   Unknown
    4969              :     //       DATE REWRITTEN  April 1997 by Russell D. Taylor, Ph.D.
    4970              :     //       MODIFIED
    4971              :     //       RE-ENGINEERED
    4972              : 
    4973              :     // PURPOSE OF THIS SUBROUTINE:
    4974              :     // Fits polynomial of order from 1 to MaxPolynomOrder to the
    4975              :     // ordered pairs of data points X,Y
    4976              : 
    4977              :     // USE STATEMENTS:
    4978              :     // na
    4979              : 
    4980              :     // Locals
    4981              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    4982              : 
    4983              :     // SUBROUTINE PARAMETER DEFINITIONS:
    4984              :     // na
    4985              : 
    4986              :     // INTERFACE BLOCK SPECIFICATIONS
    4987              :     // na
    4988              : 
    4989              :     // DERIVED TYPE DEFINITIONS
    4990              :     // na
    4991              : 
    4992              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4993              :     bool Converged;
    4994              :     Real64 B;
    4995              :     int I;
    4996              :     int II;
    4997              :     int J;
    4998              :     int PolynomOrder;
    4999              :     int CurrentOrder;
    5000              :     int CurrentOrdPair;
    5001              :     Real64 S1;
    5002              :     Real64 S2;
    5003              : 
    5004            4 :     auto &OrdPairSum = state.dataWaterCoils->OrdPairSum;
    5005              : 
    5006            4 :     OrdPairSum = 0.0;
    5007            4 :     OrdPairSum(1, 1) = WaterCoils::MaxOrderedPairs;
    5008            4 :     PolynomCoef = 0.0;
    5009          244 :     for (CurrentOrdPair = 1; CurrentOrdPair <= WaterCoils::MaxOrderedPairs; ++CurrentOrdPair) {
    5010          240 :         OrdPairSum(2, 1) += OrderedPair(CurrentOrdPair, 1);
    5011          240 :         OrdPairSum(3, 1) += OrderedPair(CurrentOrdPair, 1) * OrderedPair(CurrentOrdPair, 1);
    5012          240 :         OrdPairSum(1, 2) += OrderedPair(CurrentOrdPair, 2);
    5013          240 :         OrdPairSum(2, 2) += OrderedPair(CurrentOrdPair, 1) * OrderedPair(CurrentOrdPair, 2);
    5014              :     }
    5015            4 :     PolynomOrder = 1;
    5016            4 :     Converged = false;
    5017           20 :     while (!Converged) {
    5018           72 :         for (CurrentOrder = 1; CurrentOrder <= PolynomOrder + 1; ++CurrentOrder) {
    5019          272 :             for (J = 1; J <= PolynomOrder + 1; ++J) {
    5020          216 :                 state.dataWaterCoils->OrdPairSumMatrix(J, CurrentOrder) = OrdPairSum(J - 1 + CurrentOrder, 1);
    5021              :             } // End of J loop
    5022           56 :             state.dataWaterCoils->OrdPairSumMatrix(PolynomOrder + 2, CurrentOrder) = OrdPairSum(CurrentOrder, 2);
    5023              :         } // End of CurrentOrder loop
    5024              : 
    5025           72 :         for (CurrentOrder = 1; CurrentOrder <= PolynomOrder + 1; ++CurrentOrder) {
    5026           56 :             state.dataWaterCoils->OrdPairSumMatrix(CurrentOrder, PolynomOrder + 2) = -1.0;
    5027          192 :             for (J = CurrentOrder + 1; J <= PolynomOrder + 2; ++J) {
    5028          136 :                 state.dataWaterCoils->OrdPairSumMatrix(J, PolynomOrder + 2) = 0.0;
    5029              :             } // End of J loop
    5030              : 
    5031          272 :             for (II = 2; II <= PolynomOrder + 2; ++II) {
    5032          772 :                 for (J = CurrentOrder + 1; J <= PolynomOrder + 2; ++J) {
    5033         1112 :                     state.dataWaterCoils->OrdPairSumMatrix(J, II) -= state.dataWaterCoils->OrdPairSumMatrix(J, 1) *
    5034          556 :                                                                      state.dataWaterCoils->OrdPairSumMatrix(CurrentOrder, II) /
    5035          556 :                                                                      state.dataWaterCoils->OrdPairSumMatrix(CurrentOrder, 1);
    5036              :                 } // End of J loop
    5037              :             }     // End of II loop
    5038          272 :             for (II = 1; II <= PolynomOrder + 1; ++II) {
    5039          772 :                 for (J = CurrentOrder + 1; J <= PolynomOrder + 2; ++J) {
    5040          556 :                     state.dataWaterCoils->OrdPairSumMatrix(J, II) = state.dataWaterCoils->OrdPairSumMatrix(J, II + 1);
    5041              :                 } // End of J loop
    5042              :             }     // End of II loop
    5043              :         }         // End of CurrentOrder loop
    5044              : 
    5045           16 :         S2 = 0.0;
    5046          976 :         for (CurrentOrdPair = 1; CurrentOrdPair <= WaterCoils::MaxOrderedPairs; ++CurrentOrdPair) {
    5047          960 :             S1 = state.dataWaterCoils->OrdPairSumMatrix(PolynomOrder + 2, 1);
    5048          960 :             auto const OrderedPair1C = OrderedPair(CurrentOrdPair, 1); // (AUTO_OK_OBJ)
    5049          960 :             Real64 OrderedPair1C_pow = 1.0;
    5050         3360 :             for (CurrentOrder = 1; CurrentOrder <= PolynomOrder; ++CurrentOrder) {
    5051         2400 :                 OrderedPair1C_pow *= OrderedPair1C;
    5052         2400 :                 S1 += state.dataWaterCoils->OrdPairSumMatrix(PolynomOrder + 2, CurrentOrder + 1) * OrderedPair1C_pow;
    5053              :             } // End of CurrentOrder loop
    5054          960 :             S2 += (S1 - OrderedPair(CurrentOrdPair, 2)) * (S1 - OrderedPair(CurrentOrdPair, 2));
    5055              :         } // End of CurrentOrdPair loop
    5056           16 :         B = WaterCoils::MaxOrderedPairs - (PolynomOrder + 1);
    5057           16 :         if (S2 > 0.0001) S2 = std::sqrt(S2 / B);
    5058           72 :         for (CurrentOrder = 1; CurrentOrder <= PolynomOrder + 1; ++CurrentOrder) {
    5059           56 :             PolynomCoef(CurrentOrder) = state.dataWaterCoils->OrdPairSumMatrix(PolynomOrder + 2, CurrentOrder);
    5060              :         } // End of CurrentOrder loop
    5061              : 
    5062           16 :         if ((PolynomOrder - WaterCoils::MaxPolynomOrder < 0) && (S2 - WaterCoils::PolyConvgTol > 0.0)) {
    5063           12 :             ++PolynomOrder;
    5064           12 :             J = 2 * PolynomOrder;
    5065           12 :             OrdPairSum(J, 1) = OrdPairSum(J + 1, 1) = 0.0;
    5066           12 :             auto OrdPairSum2P = OrdPairSum(PolynomOrder + 1, 2) = 0.0; // (AUTO_OK_OBJ)
    5067          732 :             for (I = 1; I <= WaterCoils::MaxOrderedPairs; ++I) {
    5068          720 :                 auto const OrderedPair1I = OrderedPair(I, 1); // (AUTO_OK_OBJ)
    5069          720 :                 Real64 OrderedPair_pow = std::pow(OrderedPair1I, J - 1);
    5070          720 :                 OrdPairSum(J, 1) += OrderedPair_pow;
    5071          720 :                 OrderedPair_pow *= OrderedPair1I;
    5072          720 :                 OrdPairSum(J + 1, 1) += OrderedPair_pow;
    5073          720 :                 OrdPairSum2P += OrderedPair(I, 2) * std::pow(OrderedPair1I, PolynomOrder);
    5074              :             }
    5075           12 :             OrdPairSum(PolynomOrder + 1, 2) = OrdPairSum2P;
    5076           12 :         } else {
    5077            4 :             Converged = true;
    5078              :         }
    5079              :     }
    5080            4 : }
    5081              : 
    5082              : // Iterate Routine for Cooling Coil
    5083              : 
    5084       202450 : void CoilAreaFracIter(Real64 &NewSurfAreaWetFrac,       // Out Value of variable
    5085              :                       Real64 const SurfAreaFracCurrent, // Driver Value
    5086              :                       Real64 const ErrorCurrent,        // Objective Function
    5087              :                       Real64 &SurfAreaFracPrevious,     // First Previous value of Surf Area Fraction
    5088              :                       Real64 &ErrorPrevious,            // First Previous value of error
    5089              :                       Real64 &SurfAreaFracLast,         // Second Previous value of Surf Area Fraction
    5090              :                       Real64 &ErrorLast,                // Second Previous value of error
    5091              :                       int const IterNum,                // Number of Iterations
    5092              :                       int &icvg                         // Iteration convergence flag
    5093              : )
    5094              : {
    5095              :     // FUNCTION INFORMATION:
    5096              :     // AUTHOR         Rahul Chillar
    5097              :     // DATE WRITTEN   June 2004
    5098              : 
    5099              :     // PURPOSE OF THIS FUNCTION:
    5100              :     // Iterately solves for the value of SurfAreaWetFraction for the Cooling Coil.
    5101              : 
    5102              :     // METHODOLOGY EMPLOYED:
    5103              :     // First function generates 2 sets of guess points by perturbation and subsequently
    5104              :     // by Linear Fit and using the generated points calculates coeffecients for Quadratic
    5105              :     // fit to predict the next value of surface area wet fraction.
    5106              : 
    5107              :     // REFERENCES:
    5108              :     // ME 423 Design of Thermal Systems Class Notes.UIUC. W.F.Stoecker
    5109              : 
    5110              :     // FUNCTION PARAMETER DEFINITIONS:
    5111       202450 :     Real64 constexpr Tolerance(1.e-5);         // Relative error tolerance
    5112       202450 :     Real64 constexpr PerturbSurfAreaFrac(0.1); // Perturbation applied to Surf Fraction to initialize iteration
    5113       202450 :     Real64 constexpr SmallNum(1.e-9);          // Small Number
    5114              : 
    5115              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    5116              :     Real64 check;             // Validity Check for moving to Quad Solution
    5117              :     Real64 QuadCoefThree;     // Term under radical in quadratic solution
    5118              :     Real64 QuadCoefOne;       // Term under radical in quadratic solution
    5119              :     Real64 QuadCoefTwo;       // Term under radical in quadratic solution
    5120              :     Real64 Slope;             // Slope for linear fit
    5121              :     Real64 SurfAreaFracOther; // Intermediate Value of Surf Area
    5122              :     int mode;                 // Linear/ perturbation option
    5123              : 
    5124              :     // Convergence Check  by comparing previous and current value of surf area fraction
    5125       202450 :     if ((std::abs(SurfAreaFracCurrent - SurfAreaFracPrevious) < Tolerance * max(std::abs(SurfAreaFracCurrent), SmallNum) && IterNum != 1) ||
    5126              :         ErrorCurrent == 0.0) {
    5127              :         // Setting value for surface area fraction for coil
    5128        35521 :         NewSurfAreaWetFrac = SurfAreaFracCurrent;
    5129        35521 :         icvg = 1; // Convergance Flag
    5130        35521 :         return;
    5131              :     }
    5132              : 
    5133              :     // If Icvg = 0 , it has not converged.By perturbation for getting second set of
    5134              :     // data (mode=1), Getting Third set of data by performing a  linear fit(Mode=2).
    5135              :     // Now using the above 3 points generated by perturbation and Linear Fit to perform
    5136              :     // a quadratic fit.This will happen after second iteration only.
    5137       166929 :     icvg = 0; // Convergance flag = false
    5138              :     // For First Iteration Start with perturbation, For second iteration start with linear fit
    5139              :     // from the previous two values
    5140       166929 :     mode = IterNum;
    5141              : 
    5142          499 : Label10:;
    5143       167428 :     if (mode == 1) {
    5144              : 
    5145              :         // FirstGuess Set of Points provided by perturbation
    5146        35521 :         if (std::abs(SurfAreaFracCurrent) > SmallNum) {
    5147        35521 :             NewSurfAreaWetFrac = SurfAreaFracCurrent * (1.0 + PerturbSurfAreaFrac);
    5148              :         } else {
    5149            0 :             NewSurfAreaWetFrac = PerturbSurfAreaFrac;
    5150              :         }
    5151              : 
    5152              :         // Second set of values being calculated from the first set of values (incoming & perturb)
    5153       131907 :     } else if (mode == 2) {
    5154              : 
    5155              :         // Calculating Slope for interpolating to the New Point (Simple Linear Extrapolation)
    5156        36020 :         Slope = (ErrorPrevious - ErrorCurrent) / (SurfAreaFracPrevious - SurfAreaFracCurrent);
    5157              :         // Error Check for value or Slope
    5158        36020 :         if (Slope == 0.0) {
    5159            0 :             mode = 1; // Go back to Perturbation
    5160            0 :             goto Label10;
    5161              :         }
    5162              :         // Guessing New Value for Surface Area Fraction
    5163        36020 :         NewSurfAreaWetFrac = SurfAreaFracCurrent - ErrorCurrent / Slope;
    5164              :     } else {
    5165              : 
    5166              :         // Check for Quadratic Fit possible here ,Previous value of surf area fraction
    5167              :         // equals current value then Try linear fit for another point.
    5168        95887 :         if (SurfAreaFracCurrent == SurfAreaFracPrevious) {
    5169              :             // Assign Value of previous point to Last Variable for storing
    5170              :             // Go back and calculate new value for Previous.
    5171            0 :             SurfAreaFracPrevious = SurfAreaFracLast;
    5172            0 :             ErrorPrevious = ErrorLast;
    5173            0 :             mode = 2;
    5174            0 :             goto Label10;
    5175        95887 :         } else if (SurfAreaFracCurrent == SurfAreaFracLast) {
    5176              :             // Calculate another value using Linear Fit.
    5177            0 :             mode = 2;
    5178            0 :             goto Label10;
    5179              :         }
    5180              : 
    5181              :         // Now We have enough previous points to calculate coefficients and
    5182              :         // perform a quadratic fit for new guess value of surface area fraction
    5183              : 
    5184              :         // Calculating First Coefficients for Quadratic Curve Fit
    5185        95887 :         QuadCoefThree = ((ErrorLast - ErrorCurrent) / (SurfAreaFracLast - SurfAreaFracCurrent) -
    5186        95887 :                          (ErrorPrevious - ErrorCurrent) / (SurfAreaFracPrevious - SurfAreaFracCurrent)) /
    5187        95887 :                         (SurfAreaFracLast - SurfAreaFracPrevious);
    5188              :         // Calculating Second Coefficients for Quadratic Curve Fit
    5189        95887 :         QuadCoefTwo = (ErrorPrevious - ErrorCurrent) / (SurfAreaFracPrevious - SurfAreaFracCurrent) -
    5190        95887 :                       (SurfAreaFracPrevious + SurfAreaFracCurrent) * QuadCoefThree;
    5191              : 
    5192              :         // Calculating Third Coefficients for Quadratic Curve Fit
    5193        95887 :         QuadCoefOne = ErrorCurrent - (QuadCoefTwo + QuadCoefThree * SurfAreaFracCurrent) * SurfAreaFracCurrent;
    5194              : 
    5195              :         // Check for validity of coefficients , if not REAL(r64) ,Then fit is linear
    5196        95887 :         if (std::abs(QuadCoefThree) < 1.E-10) {
    5197            0 :             mode = 2; // going to Linear mode, due to colinear points.
    5198            0 :             goto Label10;
    5199              :         }
    5200              : 
    5201              :         // If value of Quadratic coefficients not suitable enought due to round off errors
    5202              :         // to predict new point go to linear fit and acertain new values for the coefficients.
    5203        95887 :         if (std::abs((QuadCoefOne + (QuadCoefTwo + QuadCoefThree * SurfAreaFracPrevious) * SurfAreaFracPrevious - ErrorPrevious) / ErrorPrevious) >
    5204              :             1.E-4) {
    5205            0 :             mode = 2; // go to linear mode
    5206            0 :             goto Label10;
    5207              :         }
    5208              : 
    5209              :         // Validity Check for Imaginary roots, In this case go back to linear fit.
    5210        95887 :         check = pow_2(QuadCoefTwo) - 4.0 * QuadCoefOne * QuadCoefThree;
    5211              :         // Imaginary Root Exist
    5212        95887 :         if (check < 0) {
    5213          499 :             mode = 2;
    5214          499 :             goto Label10;
    5215        95388 :         } else if (check > 0) {
    5216              :             // real unequal roots exist, Determine the roots nearest to most recent guess
    5217        95385 :             NewSurfAreaWetFrac = (-QuadCoefTwo + std::sqrt(check)) / QuadCoefThree / 2.0;
    5218        95385 :             SurfAreaFracOther = -NewSurfAreaWetFrac - QuadCoefTwo / QuadCoefThree;
    5219              :             // Assigning value to Surface Area Fraction with recent
    5220        95385 :             if (std::abs(NewSurfAreaWetFrac - SurfAreaFracCurrent) > std::abs(SurfAreaFracOther - SurfAreaFracCurrent))
    5221          225 :                 NewSurfAreaWetFrac = SurfAreaFracOther;
    5222              :         } else {
    5223              :             // The roots are real, one solution exists.
    5224            3 :             NewSurfAreaWetFrac = -QuadCoefTwo / QuadCoefThree / 2;
    5225              :         }
    5226              :     }
    5227              : 
    5228       166929 :     if (mode < 3) {
    5229              :         // No valid previous points to eliminate, since it just has 2 points.
    5230              :         // Loading previous values into last
    5231        71541 :         SurfAreaFracLast = SurfAreaFracPrevious;
    5232        71541 :         ErrorLast = ErrorPrevious;
    5233              :         // Loading Current Values into previous
    5234        71541 :         SurfAreaFracPrevious = SurfAreaFracCurrent;
    5235        71541 :         ErrorPrevious = ErrorCurrent;
    5236              :     } else {
    5237              : 
    5238              :         // Elimination the most distance previous point from the answer based on sign and
    5239              :         // magnitute of the error. Keeping Current Point
    5240        95388 :         if (ErrorPrevious * ErrorCurrent > 0 && ErrorLast * ErrorCurrent > 0) {
    5241              :             // If sign are same , simply eliminate the one with biggest error value.
    5242        18780 :             if (std::abs(ErrorLast) > std::abs(ErrorPrevious)) {
    5243              :                 // Eliminating Last Value
    5244         5836 :                 SurfAreaFracLast = SurfAreaFracPrevious;
    5245         5836 :                 ErrorLast = ErrorPrevious;
    5246              :             }
    5247              :         } else {
    5248              :             // If signs are different eliminate previous error with same sign as current error
    5249        82444 :             if (ErrorLast * ErrorCurrent > 0) {
    5250              :                 // Previous Loaded to Last
    5251        28691 :                 SurfAreaFracLast = SurfAreaFracPrevious;
    5252        28691 :                 ErrorLast = ErrorPrevious;
    5253              :             }
    5254              :         }
    5255              :         // Current Loaded into previous.
    5256        95388 :         SurfAreaFracPrevious = SurfAreaFracCurrent;
    5257        95388 :         ErrorPrevious = ErrorCurrent;
    5258              :     }
    5259              : }
    5260              : 
    5261            0 : void CheckWaterCoilSchedule(EnergyPlusData &state, std::string_view CompName, Real64 &Value, int &CompIndex)
    5262              : {
    5263              : 
    5264              :     // SUBROUTINE INFORMATION:
    5265              :     //       AUTHOR         Linda Lawrie
    5266              :     //       DATE WRITTEN   October 2005
    5267              : 
    5268              :     // Obtains and Allocates WaterCoil related parameters from input file
    5269            0 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) { // First time subroutine has been entered
    5270            0 :         GetWaterCoilInput(state);
    5271            0 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    5272              :     }
    5273              : 
    5274            0 :     int CoilNum = 0;
    5275              :     // Find the correct Coil number
    5276            0 :     if (CompIndex == 0) {
    5277            0 :         CoilNum = Util::FindItemInList(CompName, state.dataWaterCoils->WaterCoil);
    5278            0 :         if (CoilNum == 0) {
    5279            0 :             ShowFatalError(state, format("CheckWaterCoilSchedule: Coil not found={}", CompName));
    5280              :         }
    5281            0 :         CompIndex = CoilNum;
    5282            0 :         Value = state.dataWaterCoils->WaterCoil(CoilNum).availSched->getCurrentVal(); // not scheduled?
    5283              :     } else {
    5284            0 :         CoilNum = CompIndex;
    5285            0 :         if (CoilNum > state.dataWaterCoils->NumWaterCoils || CoilNum < 1) {
    5286            0 :             ShowFatalError(state,
    5287            0 :                            format("CheckWaterCoilSchedule: Invalid CompIndex passed={}, Number of Heating Coils={}, Coil name={}",
    5288              :                                   CoilNum,
    5289            0 :                                   state.dataWaterCoils->NumWaterCoils,
    5290              :                                   CompName));
    5291              :         }
    5292            0 :         auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    5293            0 :         if (CompName != waterCoil.Name) {
    5294            0 :             ShowFatalError(state,
    5295            0 :                            format("CheckWaterCoilSchedule: Invalid CompIndex passed={}, Coil name={}, stored Coil Name for that index={}",
    5296              :                                   CoilNum,
    5297              :                                   CompName,
    5298            0 :                                   waterCoil.Name));
    5299              :         }
    5300            0 :         Value = waterCoil.availSched->getCurrentVal(); // not scheduled?
    5301              :     }
    5302            0 : }
    5303              : 
    5304           21 : Real64 GetCoilMaxWaterFlowRate(EnergyPlusData &state,
    5305              :                                std::string_view CoilType,   // must match coil types in this module
    5306              :                                std::string const &CoilName, // must match coil names for the coil type
    5307              :                                bool &ErrorsFound            // set to true if problem
    5308              : )
    5309              : {
    5310              : 
    5311              :     // FUNCTION INFORMATION:
    5312              :     //       AUTHOR         Linda Lawrie
    5313              :     //       DATE WRITTEN   November 2006
    5314              : 
    5315              :     // PURPOSE OF THIS FUNCTION:
    5316              :     // This function looks up the max water flow rate for the given coil and returns it.  If
    5317              :     // incorrect coil type or name is given, ErrorsFound is returned as true and capacity is returned
    5318              :     // as negative.
    5319              : 
    5320              :     // Return value
    5321              :     Real64 MaxWaterFlowRate; // returned max water flow rate of matched coil
    5322              : 
    5323              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    5324              : 
    5325              :     // Obtains and Allocates WaterCoil related parameters from input file
    5326           21 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) { // First time subroutine has been entered
    5327            1 :         GetWaterCoilInput(state);
    5328            1 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    5329              :     }
    5330              : 
    5331           21 :     int WhichCoil = 0;
    5332           31 :     if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry") ||
    5333           31 :         Util::SameString(CoilType, "Coil:Cooling:Water")) {
    5334           21 :         WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
    5335           21 :         if (WhichCoil != 0) {
    5336              :             // coil does not specify MaxWaterFlowRate
    5337           21 :             MaxWaterFlowRate = state.dataWaterCoils->WaterCoil(WhichCoil).MaxWaterVolFlowRate;
    5338              :         }
    5339              :     } else {
    5340            0 :         WhichCoil = 0;
    5341              :     }
    5342              : 
    5343           21 :     if (WhichCoil == 0) {
    5344            0 :         ShowSevereError(state, format("GetCoilMaxWaterFlowRate: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    5345            0 :         ShowContinueError(state, "... Max Water Flow rate returned as -1000.");
    5346            0 :         ErrorsFound = true;
    5347            0 :         MaxWaterFlowRate = -1000.0;
    5348              :     }
    5349              : 
    5350           21 :     return MaxWaterFlowRate;
    5351              : }
    5352              : 
    5353            6 : int GetCoilInletNode(EnergyPlusData &state,
    5354              :                      std::string_view CoilType,   // must match coil types in this module
    5355              :                      std::string const &CoilName, // must match coil names for the coil type
    5356              :                      bool &ErrorsFound            // set to true if problem
    5357              : )
    5358              : {
    5359              : 
    5360              :     // FUNCTION INFORMATION:
    5361              :     //       AUTHOR         R. Raustad
    5362              :     //       DATE WRITTEN   March 2007
    5363              : 
    5364              :     // PURPOSE OF THIS FUNCTION:
    5365              :     // This function looks up the given coil and returns the inlet node number.  If
    5366              :     // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
    5367              :     // as zero.
    5368              : 
    5369              :     // Obtains and Allocates DXCoils
    5370            6 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
    5371            1 :         GetWaterCoilInput(state);
    5372            1 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    5373              :     }
    5374              : 
    5375            6 :     int NodeNumber = 0;
    5376            6 :     int WhichCoil = 0;
    5377            9 :     if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry") ||
    5378            9 :         Util::SameString(CoilType, "Coil:Cooling:Water")) {
    5379            6 :         WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
    5380            6 :         if (WhichCoil != 0) {
    5381            6 :             NodeNumber = state.dataWaterCoils->WaterCoil(WhichCoil).AirInletNodeNum;
    5382              :         }
    5383              :     } else {
    5384            0 :         WhichCoil = 0;
    5385              :     }
    5386              : 
    5387            6 :     if (WhichCoil == 0) {
    5388            0 :         ShowSevereError(state, format("GetCoilInletNode: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    5389            0 :         ErrorsFound = true;
    5390            0 :         NodeNumber = 0;
    5391              :     }
    5392              : 
    5393            6 :     return NodeNumber;
    5394              : }
    5395              : 
    5396            5 : int GetCoilOutletNode(EnergyPlusData &state,
    5397              :                       std::string_view CoilType,   // must match coil types in this module
    5398              :                       std::string const &CoilName, // must match coil names for the coil type
    5399              :                       bool &ErrorsFound            // set to true if problem
    5400              : )
    5401              : {
    5402              : 
    5403              :     // FUNCTION INFORMATION:
    5404              :     //       AUTHOR         R. Raustad
    5405              :     //       DATE WRITTEN   March 2007
    5406              : 
    5407              :     // PURPOSE OF THIS FUNCTION:
    5408              :     // This function looks up the given coil and returns the inlet node number.  If
    5409              :     // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
    5410              :     // as zero.
    5411              : 
    5412              :     // Obtains and Allocates DXCoils
    5413            5 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
    5414            0 :         GetWaterCoilInput(state);
    5415            0 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    5416              :     }
    5417              : 
    5418            5 :     int WhichCoil = 0;
    5419            5 :     int NodeNumber = 0; // returned node number of matched coil
    5420            6 :     if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry") ||
    5421            6 :         Util::SameString(CoilType, "Coil:Cooling:Water")) {
    5422            5 :         WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
    5423            5 :         if (WhichCoil != 0) {
    5424            5 :             NodeNumber = state.dataWaterCoils->WaterCoil(WhichCoil).AirOutletNodeNum;
    5425              :         }
    5426              :     } else {
    5427            0 :         WhichCoil = 0;
    5428              :     }
    5429              : 
    5430            5 :     if (WhichCoil == 0) {
    5431            0 :         ShowSevereError(
    5432              :             state,
    5433            0 :             format("GetCoilOutletNode: Could not find Coil, Type=\"{}\" Name=\"{}\" when accessing coil outlet node number.", CoilType, CoilName));
    5434            0 :         ErrorsFound = true;
    5435            0 :         NodeNumber = 0;
    5436              :     }
    5437              : 
    5438            5 :     return NodeNumber;
    5439              : }
    5440              : 
    5441           72 : int GetCoilWaterInletNode(EnergyPlusData &state,
    5442              :                           std::string_view CoilType,   // must match coil types in this module
    5443              :                           std::string const &CoilName, // must match coil names for the coil type
    5444              :                           bool &ErrorsFound            // set to true if problem
    5445              : )
    5446              : {
    5447              : 
    5448              :     // FUNCTION INFORMATION:
    5449              :     //       AUTHOR         R. Raustad
    5450              :     //       DATE WRITTEN   July 2007
    5451              : 
    5452              :     // PURPOSE OF THIS FUNCTION:
    5453              :     // This function looks up the given coil and returns the inlet water control node number.  If
    5454              :     // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
    5455              :     // as zero.
    5456              : 
    5457              :     // Obtains and Allocates DXCoils
    5458           72 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
    5459            9 :         GetWaterCoilInput(state);
    5460            9 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    5461              :     }
    5462              : 
    5463           72 :     int NodeNumber = 0; // returned node number of matched coil
    5464           72 :     int WhichCoil = 0;
    5465           97 :     if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry") ||
    5466           97 :         Util::SameString(CoilType, "Coil:Cooling:Water")) {
    5467           72 :         WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
    5468           72 :         if (WhichCoil != 0) {
    5469           72 :             NodeNumber = state.dataWaterCoils->WaterCoil(WhichCoil).WaterInletNodeNum;
    5470              :         }
    5471              :     } else {
    5472            0 :         WhichCoil = 0;
    5473              :     }
    5474              : 
    5475           72 :     if (WhichCoil == 0) {
    5476            0 :         ShowSevereError(state, format("GetCoilWaterInletNode: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    5477            0 :         ErrorsFound = true;
    5478            0 :         NodeNumber = 0;
    5479              :     }
    5480              : 
    5481           72 :     return NodeNumber;
    5482              : }
    5483              : 
    5484           30 : int GetCoilWaterOutletNode(EnergyPlusData &state,
    5485              :                            std::string_view CoilType,   // must match coil types in this module
    5486              :                            std::string const &CoilName, // must match coil names for the coil type
    5487              :                            bool &ErrorsFound            // set to true if problem
    5488              : )
    5489              : {
    5490              : 
    5491              :     // FUNCTION INFORMATION:
    5492              :     //       AUTHOR         R. Raustad
    5493              :     //       DATE WRITTEN   July 2007
    5494              : 
    5495              :     // PURPOSE OF THIS FUNCTION:
    5496              :     // This function looks up the given coil and returns the outlet water node number.  If
    5497              :     // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
    5498              :     // as zero.
    5499              : 
    5500              :     // Obtains and Allocates DXCoils
    5501           30 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
    5502            0 :         GetWaterCoilInput(state);
    5503            0 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    5504              :     }
    5505              : 
    5506           30 :     int NodeNumber = 0; // returned node number of matched coil
    5507           30 :     int WhichCoil = 0;
    5508           44 :     if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry") ||
    5509           44 :         Util::SameString(CoilType, "Coil:Cooling:Water")) {
    5510           30 :         WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
    5511           30 :         if (WhichCoil != 0) {
    5512           30 :             NodeNumber = state.dataWaterCoils->WaterCoil(WhichCoil).WaterOutletNodeNum;
    5513              :         }
    5514              :     } else {
    5515            0 :         WhichCoil = 0;
    5516              :     }
    5517              : 
    5518           30 :     if (WhichCoil == 0) {
    5519            0 :         ShowSevereError(state, format("GetCoilWaterOutletNode: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    5520            0 :         ErrorsFound = true;
    5521            0 :         NodeNumber = 0;
    5522              :     }
    5523              : 
    5524           30 :     return NodeNumber;
    5525              : }
    5526              : 
    5527           62 : void SetCoilDesFlow(EnergyPlusData &state,
    5528              :                     std::string_view CoilType,   // must match coil types in this module
    5529              :                     std::string const &CoilName, // must match coil names for the coil type
    5530              :                     Real64 const CoilDesFlow,    // coil volumetric air flow rate [m3/s]
    5531              :                     bool &ErrorsFound            // set to true if problem
    5532              : )
    5533              : {
    5534              : 
    5535              :     // SUBROUTINE INFORMATION:
    5536              :     //       AUTHOR         Fred Buhl
    5537              :     //       DATE WRITTEN   May 2009
    5538              : 
    5539              :     // PURPOSE OF THIS SUBROUTINE:
    5540              :     // This routine is designed to set the design air volume flow rate in the
    5541              :     // water coil data structure. Some of the coil types do not have this datum as
    5542              :     // an input parameter and it is needed for calculating capacity for output reporting.
    5543              : 
    5544           62 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) { // First time subroutine has been entered
    5545            2 :         GetWaterCoilInput(state);
    5546            2 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    5547              :     }
    5548              : 
    5549           92 :     if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry") ||
    5550           92 :         Util::SameString(CoilType, "Coil:Cooling:Water")) {
    5551           46 :         int WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
    5552           46 :         if (WhichCoil != 0) {
    5553           46 :             if (state.dataWaterCoils->WaterCoil(WhichCoil).DesAirVolFlowRate <= 0.0) {
    5554           37 :                 state.dataWaterCoils->WaterCoil(WhichCoil).DesAirVolFlowRate = CoilDesFlow;
    5555              :             } else {
    5556              :                 // WaterCoil(WhichCoil).DesAirVolFlowRate = CoilDesFlow;
    5557              :             }
    5558              :         } else {
    5559            0 :             ShowSevereError(state, format("GetCoilMaxWaterFlowRate: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    5560            0 :             ErrorsFound = true;
    5561              :         }
    5562              :     }
    5563           62 : }
    5564              : 
    5565            0 : Real64 GetWaterCoilDesAirFlow(EnergyPlusData &state,
    5566              :                               std::string const &CoilType, // must match coil types in this module
    5567              :                               std::string const &CoilName, // must match coil names for the coil type
    5568              :                               bool &ErrorsFound            // set to true if problem
    5569              : )
    5570              : {
    5571              : 
    5572              :     // SUBROUTINE INFORMATION:
    5573              :     //       AUTHOR         Fred Buhl
    5574              :     //       DATE WRITTEN   May 2009
    5575              : 
    5576              :     // PURPOSE OF THIS SUBROUTINE:
    5577              :     // This routine is designed to set the design air volume flow rate in the
    5578              :     // water coil data structure. Some of the coil types do not have this datum as
    5579              :     // an input parameter and it is needed for calculating capacity for output reporting.
    5580              : 
    5581            0 :     Real64 CoilDesAirFlow = 0.0;
    5582              : 
    5583            0 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) { // First time subroutine has been entered
    5584            0 :         GetWaterCoilInput(state);
    5585            0 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    5586              :     }
    5587              : 
    5588            0 :     if (Util::SameString(CoilType, "Coil:Cooling:Water")) {
    5589            0 :         int WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
    5590            0 :         if (WhichCoil != 0) {
    5591            0 :             CoilDesAirFlow = state.dataWaterCoils->WaterCoil(WhichCoil).DesAirVolFlowRate;
    5592              :         } else {
    5593            0 :             ShowSevereError(state, format("GetWaterCoilDesAirFlowRate: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    5594            0 :             ErrorsFound = true;
    5595              :         }
    5596              :     } else {
    5597            0 :         ShowSevereError(state, format("GetWaterCoilDesAirFlowRate: Funciton not valid for Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    5598            0 :         ErrorsFound = true;
    5599              :     }
    5600              : 
    5601            0 :     return CoilDesAirFlow;
    5602              : }
    5603              : 
    5604           30 : void CheckActuatorNode(EnergyPlusData &state,
    5605              :                        int const ActuatorNodeNum,                    // input actuator node number
    5606              :                        DataPlant::PlantEquipmentType &WaterCoilType, // Cooling or Heating or 0
    5607              :                        bool &NodeNotFound                            // true if matching water inlet node not found
    5608              : )
    5609              : {
    5610              : 
    5611              :     // SUBROUTINE INFORMATION:
    5612              :     //       AUTHOR         Fred Buhl
    5613              :     //       DATE WRITTEN   January 2009
    5614              : 
    5615              :     // PURPOSE OF THIS FUNCTION:
    5616              :     // This subroutine checks that the input actuator node number is matched by
    5617              :     // the water inlet node number of some water coil
    5618              : 
    5619              :     // Obtains and Allocates DXCoils
    5620           30 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
    5621            0 :         GetWaterCoilInput(state);
    5622            0 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    5623              :     }
    5624              : 
    5625           30 :     WaterCoilType = DataPlant::PlantEquipmentType::Invalid;
    5626           30 :     NodeNotFound = true;
    5627           52 :     for (int CoilNum = 1; CoilNum <= state.dataWaterCoils->NumWaterCoils; ++CoilNum) {
    5628           52 :         auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    5629           52 :         if (waterCoil.WaterInletNodeNum == ActuatorNodeNum) {
    5630           30 :             WaterCoilType = waterCoil.WaterCoilType;
    5631           30 :             NodeNotFound = false;
    5632           30 :             break;
    5633              :         }
    5634              :     }
    5635           30 : }
    5636              : 
    5637           30 : void CheckForSensorAndSetPointNode(EnergyPlusData &state,
    5638              :                                    int const SensorNodeNum,                          // controller sensor node number
    5639              :                                    HVACControllers::CtrlVarType const ControlledVar, // controlled variable type
    5640              :                                    bool &NodeNotFound                                // true if matching air outlet node not found
    5641              : )
    5642              : {
    5643              : 
    5644              :     // SUBROUTINE INFORMATION:
    5645              :     //       AUTHOR         Bereket Nigusse
    5646              :     //       DATE WRITTEN   March 2013
    5647              : 
    5648              :     // PURPOSE OF THIS SUBROUTINE:
    5649              :     // This subroutine checks that the sensor node number matches the air outlet node number
    5650              :     // of some water coils
    5651              : 
    5652              :     // SUBROUTINE PARAMETER DEFINITIONS:
    5653              :     static constexpr std::string_view RoutineName("CheckForSensorAndSetpointNode: ");
    5654              : 
    5655              :     // Obtains and Allocates DXCoils
    5656           30 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
    5657           12 :         GetWaterCoilInput(state);
    5658           12 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    5659              :     }
    5660              : 
    5661           30 :     int WhichCoil = 0;
    5662           30 :     NodeNotFound = true;
    5663              : 
    5664           52 :     for (int CoilNum = 1; CoilNum <= state.dataWaterCoils->NumWaterCoils; ++CoilNum) {
    5665           52 :         auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    5666           52 :         if (SensorNodeNum != waterCoil.AirOutletNodeNum) continue;
    5667           30 :         NodeNotFound = false;
    5668           30 :         WhichCoil = CoilNum;
    5669           30 :         break;
    5670              :     }
    5671              :     // now if the sensor node is on the water coil air outlet node then check that
    5672              :     // a setpoint is also specified on the water coil outlet node
    5673           30 :     if (!NodeNotFound) {
    5674           30 :         if (WhichCoil > 0) {
    5675           30 :             bool EMSSetPointErrorFlag = false;
    5676           30 :             switch (ControlledVar) {
    5677           17 :             case HVACControllers::CtrlVarType::Temperature: {
    5678           17 :                 EMSManager::CheckIfNodeSetPointManagedByEMS(state, SensorNodeNum, HVAC::CtrlVarType::Temp, EMSSetPointErrorFlag);
    5679           17 :                 state.dataLoopNodes->NodeSetpointCheck(SensorNodeNum).needsSetpointChecking = false;
    5680           17 :                 if (EMSSetPointErrorFlag) {
    5681           17 :                     if (!SetPointManager::NodeHasSPMCtrlVarType(state, SensorNodeNum, HVAC::CtrlVarType::Temp)) {
    5682              :                         std::string_view WaterCoilType =
    5683            6 :                             DataPlant::PlantEquipTypeNames[static_cast<int>(state.dataWaterCoils->WaterCoil(WhichCoil).WaterCoilType)];
    5684            6 :                         ShowWarningError(state, format("{}{}=\"{}\". ", RoutineName, WaterCoilType, state.dataWaterCoils->WaterCoil(WhichCoil).Name));
    5685           12 :                         ShowContinueError(state, " ..Temperature setpoint not found on coil air outlet node.");
    5686           12 :                         ShowContinueError(state,
    5687              :                                           " ..The setpoint may have been placed on a node downstream of the coil or on an airloop outlet node.");
    5688           18 :                         ShowContinueError(state, " ..Specify the setpoint and the sensor on the coil air outlet node when possible.");
    5689              :                     }
    5690              :                 }
    5691           17 :                 break;
    5692              :             }
    5693            7 :             case HVACControllers::CtrlVarType::HumidityRatio: {
    5694            7 :                 EMSManager::CheckIfNodeSetPointManagedByEMS(state, SensorNodeNum, HVAC::CtrlVarType::MaxHumRat, EMSSetPointErrorFlag);
    5695            7 :                 state.dataLoopNodes->NodeSetpointCheck(SensorNodeNum).needsSetpointChecking = false;
    5696            7 :                 if (EMSSetPointErrorFlag) {
    5697            7 :                     if (!SetPointManager::NodeHasSPMCtrlVarType(state, SensorNodeNum, HVAC::CtrlVarType::MaxHumRat)) {
    5698              :                         std::string_view WaterCoilType =
    5699            0 :                             DataPlant::PlantEquipTypeNames[static_cast<int>(state.dataWaterCoils->WaterCoil(WhichCoil).WaterCoilType)];
    5700            0 :                         ShowWarningError(state, format("{}{}=\"{}\". ", RoutineName, WaterCoilType, state.dataWaterCoils->WaterCoil(WhichCoil).Name));
    5701            0 :                         ShowContinueError(state, " ..Humidity ratio setpoint not found on coil air outlet node.");
    5702            0 :                         ShowContinueError(state,
    5703              :                                           " ..The setpoint may have been placed on a node downstream of the coil or on an airloop outlet node.");
    5704            0 :                         ShowContinueError(state, " ..Specify the setpoint and the sensor on the coil air outlet node when possible.");
    5705              :                     }
    5706              :                 }
    5707            7 :                 break;
    5708              :             }
    5709            6 :             case HVACControllers::CtrlVarType::TemperatureAndHumidityRatio: {
    5710            6 :                 EMSManager::CheckIfNodeSetPointManagedByEMS(state, SensorNodeNum, HVAC::CtrlVarType::Temp, EMSSetPointErrorFlag);
    5711            6 :                 state.dataLoopNodes->NodeSetpointCheck(SensorNodeNum).needsSetpointChecking = false;
    5712            6 :                 if (EMSSetPointErrorFlag) {
    5713            6 :                     if (!SetPointManager::NodeHasSPMCtrlVarType(state, SensorNodeNum, HVAC::CtrlVarType::Temp)) {
    5714              :                         std::string_view WaterCoilType =
    5715            6 :                             DataPlant::PlantEquipTypeNames[static_cast<int>(state.dataWaterCoils->WaterCoil(WhichCoil).WaterCoilType)];
    5716            6 :                         ShowWarningError(state, format("{}{}=\"{}\". ", RoutineName, WaterCoilType, state.dataWaterCoils->WaterCoil(WhichCoil).Name));
    5717           12 :                         ShowContinueError(state, " ..Temperature setpoint not found on coil air outlet node.");
    5718           12 :                         ShowContinueError(state,
    5719              :                                           " ..The setpoint may have been placed on a node downstream of the coil or on an airloop outlet node.");
    5720           18 :                         ShowContinueError(state, " ..Specify the setpoint and the sensor on the coil air outlet node when possible.");
    5721              :                     }
    5722              :                 }
    5723            6 :                 EMSSetPointErrorFlag = false;
    5724            6 :                 EMSManager::CheckIfNodeSetPointManagedByEMS(state, SensorNodeNum, HVAC::CtrlVarType::MaxHumRat, EMSSetPointErrorFlag);
    5725            6 :                 state.dataLoopNodes->NodeSetpointCheck(SensorNodeNum).needsSetpointChecking = false;
    5726            6 :                 if (EMSSetPointErrorFlag) {
    5727            6 :                     if (!SetPointManager::NodeHasSPMCtrlVarType(state, SensorNodeNum, HVAC::CtrlVarType::MaxHumRat)) {
    5728              :                         std::string_view WaterCoilType =
    5729            4 :                             DataPlant::PlantEquipTypeNames[static_cast<int>(state.dataWaterCoils->WaterCoil(WhichCoil).WaterCoilType)];
    5730            4 :                         ShowWarningError(state, format("{}{}=\"{}\". ", RoutineName, WaterCoilType, state.dataWaterCoils->WaterCoil(WhichCoil).Name));
    5731            8 :                         ShowContinueError(state, " ..Humidity ratio setpoint not found on coil air outlet node.");
    5732            8 :                         ShowContinueError(state,
    5733              :                                           " ..The setpoint may have been placed on a node downstream of the coil or on an airloop outlet node.");
    5734           12 :                         ShowContinueError(state, " ..Specify the setpoint and the sensor on the coil air outlet node when possible.");
    5735              :                     }
    5736              :                 }
    5737            6 :                 break;
    5738              :             }
    5739            0 :             default:
    5740            0 :                 break;
    5741              :             }
    5742              :         }
    5743              :     }
    5744           30 : }
    5745              : 
    5746            7 : Real64 TdbFnHRhPb(EnergyPlusData &state,
    5747              :                   Real64 const H,  // specific enthalpy {J/kg}
    5748              :                   Real64 const RH, // relative humidity value (0.0-1.0)
    5749              :                   Real64 const PB  // barometric pressure {Pascals}
    5750              : )
    5751              : {
    5752              : 
    5753              :     // FUNCTION INFORMATION:
    5754              :     //       AUTHOR         Fred Buhl
    5755              :     //       DATE WRITTEN   April 1, 2009
    5756              : 
    5757              :     // PURPOSE OF THIS FUNCTION:
    5758              :     // Given the specific enthalpy, relative humidity, and the
    5759              :     // barometric pressure, the function returns the dry bulb temperature.
    5760              : 
    5761              :     // Return value
    5762              :     Real64 T; // result=> humidity ratio
    5763              : 
    5764              :     // Locals
    5765              :     // FUNCTION ARGUMENT DEFINITIONS:
    5766              : 
    5767              :     // FUNCTION PARAMETER DEFINITIONS:
    5768            7 :     int constexpr MaxIte(500); // Maximum number of iterations
    5769            7 :     Real64 constexpr Acc(1.0); // Accuracy of result
    5770              : 
    5771              :     // INTERFACE BLOCK SPECIFICATIONS
    5772              :     // na
    5773              : 
    5774              :     // DERIVED TYPE DEFINITIONS
    5775              :     // na
    5776              : 
    5777              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    5778              :     int SolFla;        // Flag of solver
    5779              :     Real64 T0;         // lower bound for Tprov [C]
    5780              :     Real64 T1;         // upper bound for Tprov [C]
    5781            7 :     Real64 Tprov(0.0); // provisional value of drybulb temperature [C]
    5782              : 
    5783            7 :     T0 = 1.0;
    5784            7 :     T1 = 50.0;
    5785              : 
    5786          122 :     auto f = [&state, H, RH, PB](Real64 const Tprov) { return H - Psychrometrics::PsyHFnTdbRhPb(state, Tprov, RH, PB); };
    5787              : 
    5788            7 :     General::SolveRoot(state, Acc, MaxIte, SolFla, Tprov, f, T0, T1);
    5789              :     // if the numerical inversion failed, issue error messages.
    5790            7 :     if (SolFla == -1) {
    5791            0 :         ShowSevereError(state, "Calculation of drybulb temperature failed in TdbFnHRhPb(H,RH,PB)");
    5792            0 :         ShowContinueError(state, "   Iteration limit exceeded");
    5793            0 :         ShowContinueError(state, format("   H=[{:.6R}], RH=[{:.4R}], PB=[{:.5R}].", H, RH, PB));
    5794            7 :     } else if (SolFla == -2) {
    5795            0 :         ShowSevereError(state, "Calculation of drybulb temperature failed in TdbFnHRhPb(H,RH,PB)");
    5796            0 :         ShowContinueError(state, "  Bad starting values for Tdb");
    5797            0 :         ShowContinueError(state, format("   H=[{:.6R}], RH=[{:.4R}], PB=[{:.5R}].", H, RH, PB));
    5798              :     }
    5799            7 :     if (SolFla < 0) {
    5800            0 :         T = 0.0;
    5801              :     } else {
    5802            7 :         T = Tprov;
    5803              :     }
    5804              : 
    5805            7 :     return T;
    5806              : }
    5807              : 
    5808          411 : Real64 EstimateHEXSurfaceArea(EnergyPlusData &state, int const CoilNum) // coil number, [-]
    5809              : {
    5810              : 
    5811              :     // FUNCTION INFORMATION:
    5812              :     //       AUTHOR         Bereket A Nigusse, FSEC
    5813              :     //       DATE WRITTEN   July 2010
    5814              : 
    5815              :     // PURPOSE OF THIS FUNCTION:
    5816              :     // Splits the UA value of a simple coil:cooling:water heat exchanger model into
    5817              :     // "A" and U" values.
    5818              : 
    5819              :     // METHODOLOGY EMPLOYED:
    5820              :     // A typical design U overall heat transfer coefficient is used to split the "UA" into "A"
    5821              :     // and "U" values. Currently a constant U value calculated for a typical cooling coil is
    5822              :     // used. The assumptions used to calculate a typical U value are:
    5823              :     //     (1) tube side water velocity of 2.0 [m/s]
    5824              :     //     (2) inside to outside total surface area ratio (Ai/Ao) =  0.07 [-]
    5825              :     //     (3) fins overall efficiency = 0.92 based on aluminum fin, 12 fins per inch, and
    5826              :     //         fins area to total outside surafce area ratio of about 90%.
    5827              :     //     (4) air side convection coefficient of 140.0 [W/m2C].  Assumes sensible convection
    5828              :     //         of 58.0 [W/m2C] and 82.0 [W/m2C] sensible convection equivalent of the mass
    5829              :     //         transfer coefficient converted using the approximate relation:
    5830              :     //         hequivalent = hmasstransfer/CpAir.
    5831              : 
    5832              :     // FUNCTION PARAMETER DEFINITIONS:
    5833          411 :     constexpr Real64 OverallFinEfficiency(0.92); // Assumes aluminum fins, 12 fins per inch, fins
    5834              :     // area of about 90% of external surface area Ao.
    5835              : 
    5836          411 :     constexpr Real64 AreaRatio(0.07); // Heat exchanger Inside to Outside surface area ratio
    5837              :     // design values range from (Ai/Ao) = 0.06 to 0.08
    5838              : 
    5839              :     // Constant value air side heat transfer coefficient is assumed. This coefficient has sensible
    5840              :     // (58.d0 [W/m2C]) and latent (82.d0 [W/m2C]) heat transfer coefficient components.
    5841          411 :     constexpr Real64 hAirTubeOutside(58.0 + 82.0); // Air side heat transfer coefficient [W/m2C]
    5842              : 
    5843              :     // Tube side water convection heat transfer coefficient of the cooling coil is calculated for
    5844              :     // inside tube diameter of 0.0122m (~0.5 inch nominal diameter) and water velocity 2.0 m/s:
    5845              :     static Real64 const hWaterTubeInside(1429.0 * std::pow(2.0, 0.8) * std::pow(0.0122, -0.2)); // water (tube) side heat transfer coefficient [W/m2C]
    5846              : 
    5847              :     // Estimate the overall heat transfer coefficient, UOverallHeatTransferCoef in [W/(m2C)].
    5848              :     // Neglecting tube wall and fouling resistance, the overall U value can be estimated as:
    5849              :     // 1/UOverallHeatTransferCoef = 1/(hi*AreaRatio) + 1/(ho*OverallFinEfficiency)
    5850              :     static Real64 const UOverallHeatTransferCoef_inv(
    5851              :         1.0 / (hWaterTubeInside * AreaRatio) +
    5852              :         1.0 / (hAirTubeOutside * OverallFinEfficiency)); // Inverse of overall heat transfer coefficient for coil [W/m2C]
    5853              : 
    5854              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    5855          411 :     auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    5856          411 :     waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
    5857              : 
    5858              :     // the heat exchanger surface area is calculated as follows:
    5859          411 :     return waterCoil.UACoilTotal * UOverallHeatTransferCoef_inv; // Heat exchanger surface area [m2]
    5860              : }
    5861              : 
    5862           85 : int GetWaterCoilIndex(EnergyPlusData &state,
    5863              :                       std::string_view CoilType,   // must match coil types in this module
    5864              :                       std::string const &CoilName, // must match coil names for the coil type
    5865              :                       bool &ErrorsFound            // set to true if problem
    5866              : )
    5867              : {
    5868              : 
    5869              :     // FUNCTION INFORMATION:
    5870              :     //       AUTHOR         B. Nigusse, FSEC
    5871              :     //       DATE WRITTEN   Feb 2012
    5872              : 
    5873              :     // PURPOSE OF THIS FUNCTION:
    5874              :     // This function looks up the index for the given coil and returns it.  If incorrect coil
    5875              :     // type or name is given, ErrorsFound is returned as true and node number is returned
    5876              :     // as zero.
    5877              : 
    5878              :     // Return value
    5879              :     int IndexNum; // returned coil index if matched coil
    5880              : 
    5881              :     // Obtains and allocates WaterCoil related parameters from input file
    5882           85 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
    5883           36 :         GetWaterCoilInput(state);
    5884           36 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    5885              :     }
    5886              : 
    5887           85 :     IndexNum = 0;
    5888           85 :     if (CoilType == "COIL:HEATING:WATER") {
    5889           41 :         IndexNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
    5890           44 :     } else if (CoilType == "COIL:COOLING:WATER") {
    5891           43 :         IndexNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
    5892            1 :     } else if (CoilType == "COIL:COOLING:WATER:DETAILEDGEOMETRY") {
    5893            1 :         IndexNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
    5894              :     } else {
    5895            0 :         IndexNum = 0;
    5896              :     }
    5897              : 
    5898           85 :     if (IndexNum == 0) {
    5899            0 :         ShowSevereError(state, format("GetWaterCoilIndex: Could not find CoilType=\"{}\" with Name=\"{}\"", CoilType, CoilName));
    5900            0 :         ErrorsFound = true;
    5901              :     }
    5902              : 
    5903           85 :     return IndexNum;
    5904              : }
    5905            0 : int GetCompIndex(EnergyPlusData &state, CoilModel compType, std::string_view const coilName)
    5906              : {
    5907              :     static constexpr std::array<std::string_view, (int)WaterCoils::CoilModel::Num> CoilModelNamesUC = {
    5908              :         "COIL:HEATING:WATER", "COIL:COOLING:WATER", "COIL:COOLING:WATER:DETAILED"};
    5909              : 
    5910            0 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
    5911            0 :         GetWaterCoilInput(state);
    5912            0 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    5913              :     }
    5914              : 
    5915            0 :     int index = Util::FindItemInList(coilName, state.dataWaterCoils->WaterCoil);
    5916              : 
    5917            0 :     if (index == 0) { // may not find coil name
    5918            0 :         ShowSevereError(state,
    5919            0 :                         format("GetWaterCoilIndex: Could not find CoilType = \"{}\" with Name = \"{}\"", CoilModelNamesUC[(int)compType], coilName));
    5920              :     }
    5921            0 :     return index;
    5922              : }
    5923              : 
    5924           13 : Real64 GetWaterCoilCapacity(EnergyPlusData &state,
    5925              :                             std::string const &CoilType, // must match coil types in this module
    5926              :                             std::string const &CoilName, // must match coil names for the coil type
    5927              :                             bool &ErrorsFound            // set to true if problem
    5928              : )
    5929              : {
    5930              : 
    5931              :     // FUNCTION INFORMATION:
    5932              :     //       AUTHOR         R. Raustad, FSEC
    5933              :     //       DATE WRITTEN   Sep 2013
    5934              : 
    5935              :     // PURPOSE OF THIS FUNCTION:
    5936              :     // This function looks up the capacity for the given coil and returns it.  If incorrect coil
    5937              :     // type or name is given, ErrorsFound is returned as true and capacity is returned
    5938              :     // as zero.
    5939              : 
    5940              :     // Obtains and allocates WaterCoil related parameters from input file
    5941           13 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
    5942            0 :         GetWaterCoilInput(state);
    5943            0 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    5944              :     }
    5945              : 
    5946              :     int IndexNum;           // index to water coil
    5947           13 :     Real64 Capacity = -1.0; // returned coil capacity if matched coil
    5948              : 
    5949           13 :     if (CoilType == "COIL:HEATING:WATER") {
    5950            6 :         IndexNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
    5951            6 :         Capacity = state.dataWaterCoils->WaterCoil(IndexNum).DesWaterHeatingCoilRate;
    5952            7 :     } else if (CoilType == "COIL:COOLING:WATER") {
    5953            7 :         IndexNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
    5954            7 :         Capacity = state.dataWaterCoils->WaterCoil(IndexNum).DesWaterCoolingCoilRate;
    5955            0 :     } else if (CoilType == "COIL:COOLING:WATER:DETAILEDGEOMETRY") {
    5956            0 :         IndexNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
    5957            0 :         Capacity = state.dataWaterCoils->WaterCoil(IndexNum).DesWaterCoolingCoilRate;
    5958              :     } else {
    5959            0 :         IndexNum = 0;
    5960              :     }
    5961              : 
    5962           13 :     if (IndexNum == 0) {
    5963            0 :         ShowSevereError(state, format("GetWaterCoilCapacity: Could not find CoilType=\"{}\" with Name=\"{}\"", CoilType, CoilName));
    5964            0 :         ErrorsFound = true;
    5965              :     }
    5966              : 
    5967           13 :     return Capacity;
    5968              : }
    5969              : 
    5970            0 : void UpdateWaterToAirCoilPlantConnection(EnergyPlusData &state,
    5971              :                                          DataPlant::PlantEquipmentType const CoilType,
    5972              :                                          std::string const &CoilName,
    5973              :                                          [[maybe_unused]] int const EquipFlowCtrl,   // Flow control mode for the equipment
    5974              :                                          int const LoopNum,                          // Plant loop index for where called from
    5975              :                                          const DataPlant::LoopSideLocation LoopSide, // Plant loop side index for where called from
    5976              :                                          int &CompIndex,                             // Chiller number pointer
    5977              :                                          [[maybe_unused]] bool const FirstHVACIteration,
    5978              :                                          bool &InitLoopEquip // If not zero, calculate the max load for operating conditions
    5979              : )
    5980              : {
    5981              : 
    5982              :     // SUBROUTINE INFORMATION:
    5983              :     //       AUTHOR         B. Griffith
    5984              :     //       DATE WRITTEN   February 2010
    5985              : 
    5986              :     // PURPOSE OF THIS SUBROUTINE:
    5987              :     // update sim routine called from plant
    5988              : 
    5989              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5990              : 
    5991              :     int CoilNum;
    5992            0 :     bool DidAnythingChange(false); // set to true if conditions changed
    5993              :     int InletNodeNum;
    5994              :     int OutletNodeNum;
    5995              : 
    5996              :     // Find the correct water coil
    5997            0 :     if (CompIndex == 0) {
    5998            0 :         CoilNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
    5999            0 :         if (CoilNum == 0) {
    6000            0 :             ShowFatalError(state, format("UpdateWaterToAirCoilPlantConnection: Specified Coil not one of Valid water coils={}", CoilName));
    6001              :         }
    6002            0 :         CompIndex = CoilNum;
    6003              :     } else {
    6004            0 :         CoilNum = CompIndex;
    6005            0 :         if (CoilNum > state.dataWaterCoils->NumWaterCoils || CoilNum < 1) {
    6006            0 :             ShowFatalError(state,
    6007            0 :                            format("UpdateWaterToAirCoilPlantConnection:  Invalid CompIndex passed={}, Number of Coils={}, Entered Coil name={}",
    6008              :                                   CoilNum,
    6009            0 :                                   state.dataWaterCoils->NumWaterCoils,
    6010              :                                   CoilName));
    6011              :         }
    6012            0 :         auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    6013            0 :         if (state.dataGlobal->KickOffSimulation) {
    6014            0 :             if (CoilName != waterCoil.Name) {
    6015            0 :                 ShowFatalError(
    6016              :                     state,
    6017            0 :                     format("UpdateWaterToAirCoilPlantConnection: Invalid CompIndex passed={}, Coil name={}, stored Coil Name for that index={}",
    6018              :                            CoilNum,
    6019              :                            CoilName,
    6020            0 :                            waterCoil.Name));
    6021              :             }
    6022            0 :             if (CoilType != waterCoil.WaterCoilType) {
    6023            0 :                 ShowFatalError(
    6024              :                     state,
    6025            0 :                     format("UpdateWaterToAirCoilPlantConnection: Invalid CompIndex passed={}, Coil name={}, stored Coil Name for that index={}",
    6026              :                            CoilNum,
    6027              :                            CoilName,
    6028            0 :                            DataPlant::PlantEquipTypeNames[static_cast<int>(CoilType)]));
    6029              :             }
    6030              :         }
    6031              :     }
    6032              : 
    6033            0 :     if (InitLoopEquip) {
    6034            0 :         return;
    6035              :     }
    6036              : 
    6037            0 :     DidAnythingChange = false;
    6038              : 
    6039            0 :     auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    6040            0 :     InletNodeNum = waterCoil.WaterInletNodeNum;
    6041            0 :     OutletNodeNum = waterCoil.WaterOutletNodeNum;
    6042              : 
    6043            0 :     if (state.dataLoopNodes->Node(InletNodeNum).Temp != waterCoil.InletWaterTemp) DidAnythingChange = true;
    6044              : 
    6045            0 :     if (state.dataLoopNodes->Node(OutletNodeNum).Temp != waterCoil.OutletWaterTemp) DidAnythingChange = true;
    6046              : 
    6047            0 :     if (state.dataLoopNodes->Node(InletNodeNum).MassFlowRate != waterCoil.OutletWaterMassFlowRate) {
    6048            0 :         DidAnythingChange = true;
    6049            0 :         state.dataLoopNodes->Node(OutletNodeNum).MassFlowRate =
    6050            0 :             state.dataLoopNodes->Node(InletNodeNum).MassFlowRate; // make sure flows are consistent
    6051              :     }
    6052              : 
    6053            0 :     if (state.dataLoopNodes->Node(OutletNodeNum).MassFlowRate != waterCoil.OutletWaterMassFlowRate) DidAnythingChange = true;
    6054              : 
    6055            0 :     if (DidAnythingChange) {
    6056              :         // set sim flag for this loop
    6057            0 :         state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSide).SimLoopSideNeeded = true;
    6058              :         // set sim flags for air side users of coils
    6059              : 
    6060            0 :         state.dataHVACGlobal->SimAirLoopsFlag = true;
    6061            0 :         state.dataHVACGlobal->SimZoneEquipmentFlag = true;
    6062              :     } else { // nothing changed so turn off sim flag
    6063            0 :         state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSide).SimLoopSideNeeded = false;
    6064              :     }
    6065              : }
    6066              : 
    6067            0 : Sched::Schedule *GetWaterCoilAvailSched(EnergyPlusData &state,
    6068              :                                         std::string const &CoilType, // must match coil types in this module
    6069              :                                         std::string const &CoilName, // must match coil names for the coil type
    6070              :                                         bool &ErrorsFound            // set to true if problem
    6071              : )
    6072              : {
    6073              : 
    6074              :     // FUNCTION INFORMATION:
    6075              :     //       AUTHOR         Chandan Sharma, FSEC
    6076              :     //       DATE WRITTEN   February 2013
    6077              : 
    6078              :     // PURPOSE OF THIS FUNCTION:
    6079              :     // This function looks up the given coil and returns the availability schedule index.  If
    6080              :     // incorrect coil type or name is given, ErrorsFound is returned as true and index is returned
    6081              :     // as zero.
    6082              : 
    6083              :     // Obtains and Allocates HeatingCoil related parameters from input file
    6084              :     // Obtains and Allocates DXCoils
    6085            0 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
    6086            0 :         GetWaterCoilInput(state);
    6087            0 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    6088              :     }
    6089              : 
    6090            0 :     int WhichCoil = 0;
    6091              : 
    6092            0 :     if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water") ||
    6093            0 :         Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry")) {
    6094            0 :         WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
    6095            0 :         if (WhichCoil != 0) {
    6096            0 :             return state.dataWaterCoils->WaterCoil(WhichCoil).availSched;
    6097              :         }
    6098              :     } else {
    6099            0 :         WhichCoil = 0;
    6100              :     }
    6101              : 
    6102            0 :     if (WhichCoil == 0) {
    6103            0 :         ShowSevereError(state, format("GetCoilAvailScheduleIndex: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    6104            0 :         ErrorsFound = true;
    6105            0 :         return nullptr;
    6106              :     }
    6107              : 
    6108            0 :     return nullptr;
    6109              : }
    6110              : 
    6111            3 : void SetWaterCoilData(EnergyPlusData &state,
    6112              :                       int const CoilNum,                                  // Number of hot water heating Coil
    6113              :                       bool &ErrorsFound,                                  // Set to true if certain errors found
    6114              :                       ObjexxFCL::Optional_bool DesiccantRegenerationCoil, // Flag that this coil is used as regeneration air heating coil
    6115              :                       ObjexxFCL::Optional_int DesiccantDehumIndex,        // Index for the desiccant dehum system where this caoil is used
    6116              :                       ObjexxFCL::Optional_bool heatRecoveryCoil)          // true if water coil is connected to heat recovery loop
    6117              : {
    6118              : 
    6119              :     // FUNCTION INFORMATION:
    6120              :     //       AUTHOR         Bereket Nigusse
    6121              :     //       DATE WRITTEN   February 2016
    6122              : 
    6123              :     // PURPOSE OF THIS FUNCTION:
    6124              :     // This function sets data to water Heating Coil using the coil index and arguments passed
    6125              : 
    6126            3 :     if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
    6127            0 :         GetWaterCoilInput(state);
    6128            0 :         state.dataWaterCoils->GetWaterCoilsInputFlag = false;
    6129              :     }
    6130              : 
    6131            3 :     if (CoilNum <= 0 || CoilNum > state.dataWaterCoils->NumWaterCoils) {
    6132            0 :         ShowSevereError(state,
    6133            0 :                         format("SetHeatingCoilData: called with heating coil Number out of range={} should be >0 and <{}",
    6134              :                                CoilNum,
    6135            0 :                                state.dataWaterCoils->NumWaterCoils));
    6136            0 :         ErrorsFound = true;
    6137            0 :         return;
    6138              :     }
    6139              : 
    6140            3 :     auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    6141            3 :     if (present(DesiccantRegenerationCoil)) {
    6142            1 :         waterCoil.DesiccantRegenerationCoil = DesiccantRegenerationCoil;
    6143              :     }
    6144              : 
    6145            3 :     if (present(DesiccantDehumIndex)) {
    6146            1 :         waterCoil.DesiccantDehumNum = DesiccantDehumIndex;
    6147              :     }
    6148              : 
    6149            3 :     if (present(heatRecoveryCoil)) {
    6150            2 :         waterCoil.heatRecoveryCoil = heatRecoveryCoil;
    6151              :     }
    6152              : }
    6153              : 
    6154            9 : void EstimateCoilInletWaterTemp(EnergyPlusData &state,
    6155              :                                 int const CoilNum,                // index to heating coil
    6156              :                                 HVAC::FanOp const fanOp,          // fan operating mode
    6157              :                                 Real64 const PartLoadRatio,       // part-load ratio of heating coil
    6158              :                                 Real64 const UAMax,               // maximum UA-Value = design heating capacity
    6159              :                                 Real64 &DesCoilInletWaterTempUsed // estimated coil design inlet water temperature
    6160              : )
    6161              : {
    6162              :     // SUBROUTINE INFORMATION:
    6163              : 
    6164              :     // PURPOSE OF THIS SUBROUTINE:
    6165              :     // returns estimated coil inlet water temperature given UA value for assumed
    6166              :     // maximum effectiveness value for heating coil
    6167              : 
    6168              :     // METHODOLOGY EMPLOYED:
    6169              :     // applies energy balance around the water coil and estimates coil water inlet temperature
    6170              :     // assuming coil effectiveness of 0.8
    6171              : 
    6172              :     // SUBROUTINE PARAMETER DEFINITIONS:
    6173              :     static constexpr std::string_view RoutineName("EstimateCoilInletWaterTemp");
    6174            9 :     constexpr Real64 EffectivenessMaxAssumed(0.80);
    6175              : 
    6176              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6177              :     Real64 WaterMassFlowRate;
    6178              :     Real64 AirMassFlow;
    6179              :     Real64 TempAirIn;
    6180              :     Real64 TempAirOut; // [C]
    6181              :     Real64 Win;
    6182              :     Real64 TempWaterIn;
    6183              :     Real64 UA;
    6184              :     Real64 CapacitanceAir;
    6185              :     Real64 CapacitanceWater;
    6186              :     Real64 CapacitanceMin;
    6187              :     Real64 CapacitanceMax;
    6188              :     Real64 NTU;
    6189              :     Real64 ETA;
    6190              :     Real64 A;
    6191              :     Real64 CapRatio;
    6192              :     Real64 E1;
    6193              :     Real64 E2;
    6194              :     Real64 Effec;
    6195              :     Real64 Cp;
    6196              : 
    6197            9 :     UA = UAMax;
    6198            9 :     DesCoilInletWaterTempUsed = HVAC::DesCoilHWInletTempMin;
    6199            9 :     auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
    6200            9 :     TempAirIn = waterCoil.InletAirTemp;
    6201            9 :     Win = waterCoil.InletAirHumRat;
    6202            9 :     TempWaterIn = waterCoil.InletWaterTemp;
    6203              :     // adjust mass flow rates for cycling fan cycling coil operation
    6204            9 :     if (fanOp == HVAC::FanOp::Cycling) {
    6205            0 :         if (PartLoadRatio > 0.0) {
    6206            0 :             AirMassFlow = waterCoil.InletAirMassFlowRate / PartLoadRatio;
    6207            0 :             WaterMassFlowRate = min(waterCoil.InletWaterMassFlowRate / PartLoadRatio, waterCoil.MaxWaterMassFlowRate);
    6208              :         } else {
    6209            0 :             AirMassFlow = 0.0;
    6210            0 :             WaterMassFlowRate = 0.0;
    6211            0 :             return;
    6212              :         }
    6213              :     } else {
    6214            9 :         AirMassFlow = waterCoil.InletAirMassFlowRate;
    6215            9 :         WaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
    6216              :     }
    6217            9 :     if (WaterMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) { // if the coil is operating
    6218            9 :         CapacitanceAir = PsyCpAirFnW(Win) * AirMassFlow;
    6219            9 :         Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, TempWaterIn, RoutineName);
    6220            9 :         CapacitanceWater = Cp * WaterMassFlowRate;
    6221            9 :         CapacitanceMin = min(CapacitanceAir, CapacitanceWater);
    6222            9 :         CapacitanceMax = max(CapacitanceAir, CapacitanceWater);
    6223              :     } else {
    6224            0 :         CapacitanceAir = 0.0;
    6225            0 :         CapacitanceWater = 0.0;
    6226            0 :         return;
    6227              :     }
    6228              :     // calculate DesCoilInletWaterTempUsed
    6229            9 :     if (((CapacitanceAir > 0.0) && (CapacitanceWater > 0.0))) {
    6230              : 
    6231            9 :         if (UA <= 0.0) {
    6232            0 :             ShowWarningError(state, format("UA is zero for COIL:Heating:Water {}", waterCoil.Name));
    6233            0 :             return;
    6234              :         }
    6235            9 :         NTU = UA / CapacitanceMin;
    6236            9 :         ETA = std::pow(NTU, 0.22);
    6237            9 :         CapRatio = CapacitanceMin / CapacitanceMax;
    6238            9 :         A = CapRatio * NTU / ETA;
    6239              : 
    6240            9 :         if (A > 20.0) {
    6241            0 :             A = ETA * 1.0 / CapRatio;
    6242              :         } else {
    6243            9 :             E1 = std::exp(-A);
    6244            9 :             A = ETA * (1.0 - E1) / CapRatio;
    6245              :         }
    6246              : 
    6247            9 :         if (A > 20.0) {
    6248            2 :             Effec = 1.0;
    6249              :         } else {
    6250            7 :             E2 = std::exp(-A);
    6251            7 :             Effec = 1.0 - E2;
    6252              :         }
    6253            9 :         TempAirOut = TempAirIn + Effec * CapacitanceMin * (TempWaterIn - TempAirIn) / CapacitanceAir;
    6254              :         // this formulation assumes coil effectiveness of 0.80 to increase the estimated coil water inlet temperatures
    6255            9 :         DesCoilInletWaterTempUsed = CapacitanceAir * (TempAirOut - TempAirIn) / (CapacitanceMin * EffectivenessMaxAssumed) + TempAirIn;
    6256              :         // water coil should not be sized at coil water inlet temperature lower than 46.0C (for convergence problem in Regulafalsi)
    6257            9 :         DesCoilInletWaterTempUsed = max(DesCoilInletWaterTempUsed, HVAC::DesCoilHWInletTempMin);
    6258              :     }
    6259              : }
    6260              : 
    6261              : // End of Coil Utility subroutines
    6262              : // *****************************************************************************
    6263              : 
    6264              : } // namespace EnergyPlus::WaterCoils
        

Generated by: LCOV version 2.0-1