LCOV - code coverage report
Current view: top level - EnergyPlus - SwimmingPool.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 409 553 74.0 %
Date: 2023-01-17 19:17:23 Functions: 17 19 89.5 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cmath>
      50             : 
      51             : // ObjexxFCL Headers
      52             : #include <ObjexxFCL/Array.functions.hh>
      53             : #include <ObjexxFCL/Fmath.hh>
      54             : 
      55             : // EnergyPlus Headers
      56             : #include <EnergyPlus/BranchNodeConnections.hh>
      57             : #include <EnergyPlus/Construction.hh>
      58             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      59             : #include <EnergyPlus/DataConversions.hh>
      60             : #include <EnergyPlus/DataEnvironment.hh>
      61             : #include <EnergyPlus/DataHVACGlobals.hh>
      62             : #include <EnergyPlus/DataHeatBalFanSys.hh>
      63             : #include <EnergyPlus/DataHeatBalSurface.hh>
      64             : #include <EnergyPlus/DataHeatBalance.hh>
      65             : #include <EnergyPlus/DataLoopNode.hh>
      66             : #include <EnergyPlus/DataSizing.hh>
      67             : #include <EnergyPlus/DataSurfaceLists.hh>
      68             : #include <EnergyPlus/DataSurfaces.hh>
      69             : #include <EnergyPlus/FluidProperties.hh>
      70             : #include <EnergyPlus/General.hh>
      71             : #include <EnergyPlus/GeneralRoutines.hh>
      72             : #include <EnergyPlus/HeatBalanceSurfaceManager.hh>
      73             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      74             : #include <EnergyPlus/NodeInputManager.hh>
      75             : #include <EnergyPlus/OutputProcessor.hh>
      76             : #include <EnergyPlus/Plant/DataPlant.hh>
      77             : #include <EnergyPlus/Plant/PlantLocation.hh>
      78             : #include <EnergyPlus/PlantUtilities.hh>
      79             : #include <EnergyPlus/Psychrometrics.hh>
      80             : #include <EnergyPlus/ScheduleManager.hh>
      81             : #include <EnergyPlus/SwimmingPool.hh>
      82             : #include <EnergyPlus/UtilityRoutines.hh>
      83             : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      84             : 
      85             : namespace EnergyPlus::SwimmingPool {
      86             : 
      87             : // MODULE INFORMATION:
      88             : //       AUTHOR         Rick Strand, Ho-Sung Kim
      89             : //       DATE WRITTEN   June 2012 (F90) and October 2014 (C++)
      90             : 
      91             : // PURPOSE OF THIS MODULE:
      92             : // The purpose of this module is to encapsulate the data and algorithms required
      93             : // to manage the SwimmingPool System Component.
      94             : 
      95             : // METHODOLOGY EMPLOYED:
      96             : // The swimming pool acts as a surface within the heat balance and then connects
      97             : // to the plant via a water loop.
      98             : 
      99             : // REFERENCES:
     100             : // 1. ASHRAE (2011). 2011 ASHRAE Handbook - HVAC Applications. Atlanta: American Society of Heating,
     101             : //    Refrigerating and Air-Conditioning Engineers, Inc., p.5.6-5.9.
     102             : // 2. Janis, R. and W. Tao (2005). Mechanical and Electrical Systems in Buildings. 3rd ed. Upper
     103             : //    Saddle River, NJ: Pearson Education, Inc., p.246.
     104             : // 3. Kittler, R. (1989). Indoor Natatorium Design and Energy Recycling. ASHRAE Transactions 95(1), p.521-526.
     105             : // 4. Smith, C., R. Jones, and G. Lof (1993). Energy Requirements and Potential Savings for Heated
     106             : //    Indoor Swimming Pools. ASHRAE Transactions 99(2), p.864-874.
     107             : 
     108     6050562 : void SimSwimmingPool(EnergyPlusData &state, bool FirstHVACIteration)
     109             : {
     110             :     // Process the input data if it hasn't been done already
     111     6050562 :     if (state.dataSwimmingPools->getSwimmingPoolInput) {
     112         770 :         GetSwimmingPool(state);
     113         770 :         state.dataSwimmingPools->getSwimmingPoolInput = false;
     114             :     }
     115             : 
     116             :     // System wide (for all pools) inits
     117     6050562 :     state.dataHeatBalFanSys->SumConvPool = 0.0;
     118     6050562 :     state.dataHeatBalFanSys->SumLatentPool = 0.0;
     119             : 
     120     6050562 :     PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
     121     6050562 :     Real64 CurLoad = 0.0;
     122     6050562 :     bool RunFlag = true;
     123             : 
     124     6056100 :     for (auto &thisPool : state.dataSwimmingPools->Pool) {
     125        5538 :         thisPool.simulate(state, A, FirstHVACIteration, CurLoad, RunFlag);
     126             :     }
     127             : 
     128     6050562 :     if (state.dataSwimmingPools->NumSwimmingPools > 0) HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state);
     129             : 
     130     6050562 :     ReportSwimmingPool(state);
     131     6050562 : }
     132             : 
     133        5538 : void SwimmingPoolData::simulate(EnergyPlusData &state,
     134             :                                 [[maybe_unused]] const PlantLocation &calledFromLocation,
     135             :                                 bool FirstHVACIteration,
     136             :                                 [[maybe_unused]] Real64 &CurLoad,
     137             :                                 [[maybe_unused]] bool RunFlag)
     138             : {
     139        5538 :     this->initialize(state, FirstHVACIteration);
     140             : 
     141        5538 :     this->calculate(state);
     142             : 
     143        5538 :     this->update(state);
     144        5538 : }
     145             : 
     146         770 : void GetSwimmingPool(EnergyPlusData &state)
     147             : {
     148             :     // SUBROUTINE INFORMATION:
     149             :     //       AUTHOR         Rick Strand, Ho-Sung Kim
     150             :     //       DATE WRITTEN   October 2014
     151             : 
     152             :     // PURPOSE OF THIS SUBROUTINE:
     153             :     // This subroutine reads the input for all swimming pools present in
     154             :     // the user input file.  This will contain all of the information needed
     155             :     // to simulate a swimming pool.
     156             : 
     157             :     // SUBROUTINE PARAMETER DEFINITIONS:
     158             :     static constexpr std::string_view RoutineName("GetSwimmingPool: "); // include trailing blank space
     159         770 :     Real64 constexpr MinCoverFactor(0.0);                               // minimum value for cover factors
     160         770 :     Real64 constexpr MaxCoverFactor(1.0);                               // maximum value for cover factors
     161         770 :     Real64 constexpr MinDepth(0.05);                                    // minimum average pool depth (to avoid obvious input errors)
     162         770 :     Real64 constexpr MaxDepth(10.0);                                    // maximum average pool depth (to avoid obvious input errors)
     163         770 :     Real64 constexpr MinPowerFactor(0.0);                               // minimum power factor for miscellaneous equipment
     164             : 
     165             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     166         770 :     bool ErrorsFound(false);         // Set to true if something goes wrong
     167        1540 :     std::string CurrentModuleObject; // for ease in getting objects
     168        1540 :     Array1D_string Alphas;           // Alpha items for object
     169        1540 :     Array1D_string cAlphaFields;     // Alpha field names
     170        1540 :     Array1D_string cNumericFields;   // Numeric field names
     171         770 :     int IOStatus = 0;                // Used in GetObjectItem
     172        1540 :     Array1D<Real64> Numbers;         // Numeric items for object
     173         770 :     int NumAlphas = 0;               // Number of Alphas for each GetObjectItem call
     174         770 :     int NumArgs = 0;                 // Unused variable that is part of a subroutine call
     175         770 :     int NumNumbers = 0;              // Number of Numbers for each GetObjectItem call
     176        1540 :     Array1D_bool lAlphaBlanks;       // Logical array, alpha field input BLANK = .TRUE.
     177        1540 :     Array1D_bool lNumericBlanks;     // Logical array, numeric field input BLANK = .TRUE.
     178             : 
     179             :     // Initializations and allocations
     180         770 :     int MaxAlphas = 0;  // Maximum number of alphas for these input keywords
     181         770 :     int MaxNumbers = 0; // Maximum number of numbers for these input keywords
     182             : 
     183         770 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "SwimmingPool:Indoor", NumArgs, NumAlphas, NumNumbers);
     184         770 :     MaxAlphas = max(MaxAlphas, NumAlphas);
     185         770 :     MaxNumbers = max(MaxNumbers, NumNumbers);
     186             : 
     187         770 :     Alphas.allocate(MaxAlphas);
     188         770 :     Alphas = "";
     189         770 :     Numbers.allocate(MaxNumbers);
     190         770 :     Numbers = 0.0;
     191         770 :     cAlphaFields.allocate(MaxAlphas);
     192         770 :     cAlphaFields = "";
     193         770 :     cNumericFields.allocate(MaxNumbers);
     194         770 :     cNumericFields = "";
     195         770 :     lAlphaBlanks.allocate(MaxAlphas);
     196         770 :     lAlphaBlanks = true;
     197         770 :     lNumericBlanks.allocate(MaxNumbers);
     198         770 :     lNumericBlanks = true;
     199             : 
     200         770 :     state.dataSwimmingPools->NumSwimmingPools = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SwimmingPool:Indoor");
     201         770 :     state.dataSwimmingPools->CheckEquipName.allocate(state.dataSwimmingPools->NumSwimmingPools);
     202         770 :     state.dataSwimmingPools->CheckEquipName = true;
     203             : 
     204         770 :     state.dataSwimmingPools->Pool.allocate(state.dataSwimmingPools->NumSwimmingPools);
     205             : 
     206             :     // Obtain all of the user data related to indoor swimming pools...
     207         770 :     CurrentModuleObject = "SwimmingPool:Indoor";
     208         772 :     for (int Item = 1; Item <= state.dataSwimmingPools->NumSwimmingPools; ++Item) {
     209             : 
     210           2 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     211             :                                                                  CurrentModuleObject,
     212             :                                                                  Item,
     213             :                                                                  Alphas,
     214             :                                                                  NumAlphas,
     215             :                                                                  Numbers,
     216             :                                                                  NumNumbers,
     217             :                                                                  IOStatus,
     218             :                                                                  lNumericBlanks,
     219             :                                                                  lAlphaBlanks,
     220             :                                                                  cAlphaFields,
     221             :                                                                  cNumericFields);
     222           2 :         UtilityRoutines::IsNameEmpty(state, Alphas(1), CurrentModuleObject, ErrorsFound);
     223           2 :         state.dataSwimmingPools->Pool(Item).Name = Alphas(1);
     224             : 
     225           2 :         state.dataSwimmingPools->Pool(Item).SurfaceName = Alphas(2);
     226           2 :         state.dataSwimmingPools->Pool(Item).SurfacePtr = 0;
     227          38 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     228          38 :             if (UtilityRoutines::SameString(state.dataSurface->Surface(SurfNum).Name, state.dataSwimmingPools->Pool(Item).SurfaceName)) {
     229           2 :                 state.dataSwimmingPools->Pool(Item).SurfacePtr = SurfNum;
     230           2 :                 break;
     231             :             }
     232             :         }
     233             : 
     234           2 :         state.dataSwimmingPools->Pool(Item).ErrorCheckSetupPoolSurface(state, Alphas(1), Alphas(2), cAlphaFields(2), ErrorsFound);
     235             : 
     236           2 :         state.dataSwimmingPools->Pool(Item).AvgDepth = Numbers(1);
     237           2 :         if (state.dataSwimmingPools->Pool(Item).AvgDepth < MinDepth) {
     238           0 :             ShowWarningError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has an average depth that is too small.");
     239           0 :             ShowContinueError(state, "The pool average depth has been reset to the minimum allowed depth.");
     240           2 :         } else if (state.dataSwimmingPools->Pool(Item).AvgDepth > MaxDepth) {
     241           0 :             ShowSevereError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has an average depth that is too large.");
     242           0 :             ShowContinueError(state, "The pool depth must be less than the maximum average depth of 10 meters.");
     243           0 :             ErrorsFound = true;
     244             :         }
     245             : 
     246           2 :         state.dataSwimmingPools->Pool(Item).ActivityFactorSchedName = Alphas(3);
     247           2 :         state.dataSwimmingPools->Pool(Item).ActivityFactorSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(3));
     248           2 :         if ((state.dataSwimmingPools->Pool(Item).ActivityFactorSchedPtr == 0) && (!lAlphaBlanks(3))) {
     249           0 :             ShowSevereError(state, cAlphaFields(3) + " not found: " + Alphas(3));
     250           0 :             ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
     251           0 :             ErrorsFound = true;
     252             :         }
     253             : 
     254           2 :         state.dataSwimmingPools->Pool(Item).MakeupWaterSupplySchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(4));
     255           2 :         if ((state.dataSwimmingPools->Pool(Item).MakeupWaterSupplySchedPtr == 0) && (!lAlphaBlanks(4))) {
     256           0 :             ShowSevereError(state, cAlphaFields(4) + " not found: " + Alphas(4));
     257           0 :             ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
     258           0 :             ErrorsFound = true;
     259             :         }
     260             : 
     261           2 :         state.dataSwimmingPools->Pool(Item).CoverSchedName = Alphas(5);
     262           2 :         state.dataSwimmingPools->Pool(Item).CoverSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(5));
     263           2 :         if ((state.dataSwimmingPools->Pool(Item).CoverSchedPtr == 0) && (!lAlphaBlanks(5))) {
     264           0 :             ShowSevereError(state, cAlphaFields(5) + " not found: " + Alphas(5));
     265           0 :             ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
     266           0 :             ErrorsFound = true;
     267             :         }
     268             : 
     269           2 :         state.dataSwimmingPools->Pool(Item).CoverEvapFactor = Numbers(2);
     270           2 :         if (state.dataSwimmingPools->Pool(Item).CoverEvapFactor < MinCoverFactor) {
     271           0 :             ShowWarningError(state,
     272           0 :                              std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has an evaporation cover factor less than zero.");
     273           0 :             ShowContinueError(state, "The evaporation cover factor has been reset to zero.");
     274           0 :             state.dataSwimmingPools->Pool(Item).CoverEvapFactor = MinCoverFactor;
     275           2 :         } else if (state.dataSwimmingPools->Pool(Item).CoverEvapFactor > MaxCoverFactor) {
     276           0 :             ShowWarningError(
     277           0 :                 state, std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has an evaporation cover factor greater than one.");
     278           0 :             ShowContinueError(state, "The evaporation cover factor has been reset to one.");
     279           0 :             state.dataSwimmingPools->Pool(Item).CoverEvapFactor = MaxCoverFactor;
     280             :         }
     281             : 
     282           2 :         state.dataSwimmingPools->Pool(Item).CoverConvFactor = Numbers(3);
     283           2 :         if (state.dataSwimmingPools->Pool(Item).CoverConvFactor < MinCoverFactor) {
     284           0 :             ShowWarningError(state,
     285           0 :                              std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has a convection cover factor less than zero.");
     286           0 :             ShowContinueError(state, "The convection cover factor has been reset to zero.");
     287           0 :             state.dataSwimmingPools->Pool(Item).CoverConvFactor = MinCoverFactor;
     288           2 :         } else if (state.dataSwimmingPools->Pool(Item).CoverConvFactor > MaxCoverFactor) {
     289           0 :             ShowWarningError(state,
     290           0 :                              std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has a convection cover factor greater than one.");
     291           0 :             ShowContinueError(state, "The convection cover factor has been reset to one.");
     292           0 :             state.dataSwimmingPools->Pool(Item).CoverConvFactor = MaxCoverFactor;
     293             :         }
     294             : 
     295           2 :         state.dataSwimmingPools->Pool(Item).CoverSWRadFactor = Numbers(4);
     296           2 :         if (state.dataSwimmingPools->Pool(Item).CoverSWRadFactor < MinCoverFactor) {
     297           0 :             ShowWarningError(state,
     298           0 :                              std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) +
     299             :                                  " has a short-wavelength radiation cover factor less than zero.");
     300           0 :             ShowContinueError(state, "The short-wavelength radiation cover factor has been reset to zero.");
     301           0 :             state.dataSwimmingPools->Pool(Item).CoverSWRadFactor = MinCoverFactor;
     302           2 :         } else if (state.dataSwimmingPools->Pool(Item).CoverSWRadFactor > MaxCoverFactor) {
     303           0 :             ShowWarningError(state,
     304           0 :                              std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) +
     305             :                                  " has a short-wavelength radiation cover factor greater than one.");
     306           0 :             ShowContinueError(state, "The short-wavelength radiation cover factor has been reset to one.");
     307           0 :             state.dataSwimmingPools->Pool(Item).CoverSWRadFactor = MaxCoverFactor;
     308             :         }
     309             : 
     310           2 :         state.dataSwimmingPools->Pool(Item).CoverLWRadFactor = Numbers(5);
     311           2 :         if (state.dataSwimmingPools->Pool(Item).CoverLWRadFactor < MinCoverFactor) {
     312           0 :             ShowWarningError(state,
     313           0 :                              std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) +
     314             :                                  " has a long-wavelength radiation cover factor less than zero.");
     315           0 :             ShowContinueError(state, "The long-wavelength radiation cover factor has been reset to zero.");
     316           0 :             state.dataSwimmingPools->Pool(Item).CoverLWRadFactor = MinCoverFactor;
     317           2 :         } else if (state.dataSwimmingPools->Pool(Item).CoverLWRadFactor > MaxCoverFactor) {
     318           0 :             ShowWarningError(state,
     319           0 :                              std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) +
     320             :                                  " has a long-wavelength radiation cover factor greater than one.");
     321           0 :             ShowContinueError(state, "The long-wavelength radiation cover factor has been reset to one.");
     322           0 :             state.dataSwimmingPools->Pool(Item).CoverLWRadFactor = MaxCoverFactor;
     323             :         }
     324             : 
     325           2 :         state.dataSwimmingPools->Pool(Item).WaterInletNodeName = Alphas(6);
     326           2 :         state.dataSwimmingPools->Pool(Item).WaterOutletNodeName = Alphas(7);
     327           2 :         state.dataSwimmingPools->Pool(Item).WaterInletNode =
     328           4 :             NodeInputManager::GetOnlySingleNode(state,
     329           2 :                                                 Alphas(6),
     330             :                                                 ErrorsFound,
     331             :                                                 DataLoopNode::ConnectionObjectType::SwimmingPoolIndoor,
     332           2 :                                                 Alphas(1),
     333             :                                                 DataLoopNode::NodeFluidType::Water,
     334             :                                                 DataLoopNode::ConnectionType::Inlet,
     335             :                                                 NodeInputManager::CompFluidStream::Primary,
     336           2 :                                                 DataLoopNode::ObjectIsNotParent);
     337           2 :         state.dataSwimmingPools->Pool(Item).WaterOutletNode =
     338           4 :             NodeInputManager::GetOnlySingleNode(state,
     339           2 :                                                 Alphas(7),
     340             :                                                 ErrorsFound,
     341             :                                                 DataLoopNode::ConnectionObjectType::SwimmingPoolIndoor,
     342           2 :                                                 Alphas(1),
     343             :                                                 DataLoopNode::NodeFluidType::Water,
     344             :                                                 DataLoopNode::ConnectionType::Outlet,
     345             :                                                 NodeInputManager::CompFluidStream::Primary,
     346           2 :                                                 DataLoopNode::ObjectIsNotParent);
     347           2 :         if ((!lAlphaBlanks(6)) || (!lAlphaBlanks(7))) {
     348           2 :             BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(6), Alphas(7), "Hot Water Nodes");
     349             :         }
     350           2 :         state.dataSwimmingPools->Pool(Item).WaterVolFlowMax = Numbers(6);
     351           2 :         state.dataSwimmingPools->Pool(Item).MiscPowerFactor = Numbers(7);
     352           2 :         if (state.dataSwimmingPools->Pool(Item).MiscPowerFactor < MinPowerFactor) {
     353           0 :             ShowWarningError(
     354           0 :                 state, std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has a miscellaneous power factor less than zero.");
     355           0 :             ShowContinueError(state, "The miscellaneous power factor has been reset to zero.");
     356           0 :             state.dataSwimmingPools->Pool(Item).MiscPowerFactor = MinPowerFactor;
     357             :         }
     358             : 
     359           2 :         state.dataSwimmingPools->Pool(Item).SetPtTempSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(8));
     360           2 :         if ((state.dataSwimmingPools->Pool(Item).SetPtTempSchedPtr == 0) && (!lAlphaBlanks(8))) {
     361           0 :             ShowSevereError(state, cAlphaFields(8) + " not found: " + Alphas(8));
     362           0 :             ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
     363           0 :             ErrorsFound = true;
     364             :         }
     365           2 :         if (lAlphaBlanks(8)) {
     366           0 :             ShowSevereError(state, cAlphaFields(8) + " left blank.  This is NOT allowed as there must be a pool water setpoint temperature.");
     367           0 :             ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
     368           0 :             ErrorsFound = true;
     369             :         }
     370             : 
     371           2 :         state.dataSwimmingPools->Pool(Item).MaxNumOfPeople = Numbers(8);
     372           2 :         if (state.dataSwimmingPools->Pool(Item).MaxNumOfPeople < 0.0) {
     373           0 :             ShowWarningError(state,
     374           0 :                              std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) +
     375             :                                  " was entered with negative people.  This is not allowed.");
     376           0 :             ShowContinueError(state, "The number of people has been reset to zero.");
     377           0 :             state.dataSwimmingPools->Pool(Item).MaxNumOfPeople = 0.0;
     378             :         }
     379             : 
     380           2 :         state.dataSwimmingPools->Pool(Item).PeopleSchedName = Alphas(9);
     381           2 :         state.dataSwimmingPools->Pool(Item).PeopleSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(9));
     382           2 :         if ((state.dataSwimmingPools->Pool(Item).PeopleSchedPtr == 0) && (!lAlphaBlanks(9))) {
     383           0 :             ShowSevereError(state, cAlphaFields(9) + " not found: " + Alphas(9));
     384           0 :             ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
     385           0 :             ErrorsFound = true;
     386             :         }
     387             : 
     388           2 :         state.dataSwimmingPools->Pool(Item).PeopleHeatGainSchedName = Alphas(10);
     389           2 :         state.dataSwimmingPools->Pool(Item).PeopleHeatGainSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(10));
     390           2 :         if ((state.dataSwimmingPools->Pool(Item).PeopleHeatGainSchedPtr == 0) && (!lAlphaBlanks(10))) {
     391           0 :             ShowSevereError(state, cAlphaFields(10) + " not found: " + Alphas(10));
     392           0 :             ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
     393           0 :             ErrorsFound = true;
     394             :         }
     395             :     }
     396             : 
     397         770 :     Alphas.deallocate();
     398         770 :     Numbers.deallocate();
     399         770 :     cAlphaFields.deallocate();
     400         770 :     cNumericFields.deallocate();
     401         770 :     lAlphaBlanks.deallocate();
     402         770 :     lNumericBlanks.deallocate();
     403             : 
     404         770 :     if (ErrorsFound) {
     405           0 :         ShowFatalError(state, std::string{RoutineName} + "Errors found in swimming pool input. Preceding conditions cause termination.");
     406             :     }
     407         770 : }
     408             : 
     409           2 : void SwimmingPoolData::ErrorCheckSetupPoolSurface(
     410             :     EnergyPlusData &state, std::string_view Alpha1, std::string_view Alpha2, std::string_view cAlphaField2, bool &ErrorsFound)
     411             : {
     412             : 
     413             :     static constexpr std::string_view RoutineName("ErrorCheckSetupPoolSurface: "); // include trailing blank space
     414             :     static constexpr std::string_view CurrentModuleObject("SwimmingPool:Indoor");
     415             : 
     416           2 :     if (this->SurfacePtr <= 0) {
     417           0 :         ShowSevereError(state, std::string{RoutineName} + "Invalid " + std::string{cAlphaField2} + " = " + std::string{Alpha2});
     418           0 :         ShowContinueError(state, "Occurs in " + std::string{CurrentModuleObject} + " = " + std::string{Alpha1});
     419           0 :         ErrorsFound = true;
     420           2 :     } else if (state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(this->SurfacePtr)) {
     421           0 :         ShowSevereError(state, std::string{RoutineName} + std::string{CurrentModuleObject} + "=\"" + std::string{Alpha1} + "\", Invalid Surface");
     422           0 :         ShowContinueError(
     423           0 :             state, std::string{cAlphaField2} + "=\"" + std::string{Alpha2} + "\" has been used in another radiant system, ventilated slab, or pool.");
     424           0 :         ShowContinueError(state,
     425             :                           "A single surface can only be a radiant system, a ventilated slab, or a pool.  It CANNOT be more than one of these.");
     426           0 :         ErrorsFound = true;
     427             :         // Something present that is not allowed for a swimming pool (non-CTF algorithm, movable insulation, or radiant source/sink
     428           2 :     } else if (state.dataSurface->Surface(this->SurfacePtr).HeatTransferAlgorithm != DataSurfaces::HeatTransferModel::CTF) {
     429           0 :         ShowSevereError(state,
     430           0 :                         state.dataSurface->Surface(this->SurfacePtr).Name +
     431             :                             " is a pool and is attempting to use a non-CTF solution algorithm.  This is "
     432             :                             "not allowed.  Use the CTF solution algorithm for this surface.");
     433           0 :         ErrorsFound = true;
     434             : 
     435           2 :     } else if (state.dataSurface->Surface(this->SurfacePtr).Class == DataSurfaces::SurfaceClass::Window) {
     436           0 :         ShowSevereError(state,
     437           0 :                         state.dataSurface->Surface(this->SurfacePtr).Name +
     438             :                             " is a pool and is defined as a window.  This is not allowed.  A pool must be a floor that is NOT a window.");
     439           0 :         ErrorsFound = true;
     440           2 :     } else if (state.dataSurface->SurfMaterialMovInsulInt(this->SurfacePtr) > 0) {
     441           0 :         ShowSevereError(state,
     442           0 :                         state.dataSurface->Surface(this->SurfacePtr).Name +
     443             :                             " is a pool and has movable insulation.  This is not allowed.  Remove the movable insulation for this surface.");
     444           0 :         ErrorsFound = true;
     445           2 :     } else if (state.dataConstruction->Construct(state.dataSurface->Surface(this->SurfacePtr).Construction).SourceSinkPresent) {
     446           0 :         ShowSevereError(
     447             :             state,
     448           0 :             state.dataSurface->Surface(this->SurfacePtr).Name +
     449             :                 " is a pool and uses a construction with a source/sink.  This is not allowed.  Use a standard construction for this surface.");
     450           0 :         ErrorsFound = true;
     451             :     } else { // ( Pool( Item ).SurfacePtr > 0 )
     452           2 :         state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(this->SurfacePtr) = true;
     453           2 :         state.dataSurface->SurfIsPool(this->SurfacePtr) = true;
     454           2 :         this->ZonePtr = state.dataSurface->Surface(this->SurfacePtr).Zone;
     455             :         // Check to make sure pool surface is a floor
     456           2 :         if (state.dataSurface->Surface(this->SurfacePtr).Class != DataSurfaces::SurfaceClass::Floor) {
     457           0 :             ShowSevereError(state,
     458           0 :                             std::string{RoutineName} + std::string{CurrentModuleObject} + "=\"" + std::string{Alpha1} +
     459             :                                 " contains a surface name that is NOT a floor.");
     460           0 :             ShowContinueError(
     461             :                 state, "A swimming pool must be associated with a surface that is a FLOOR.  Association with other surface types is not permitted.");
     462           0 :             ErrorsFound = true;
     463             :         }
     464             :     }
     465           2 : }
     466             : 
     467        5538 : void SwimmingPoolData::initialize(EnergyPlusData &state, bool const FirstHVACIteration // true during the first HVAC iteration
     468             : )
     469             : {
     470             :     // SUBROUTINE INFORMATION:
     471             :     //       AUTHOR         Rick Strand, Ho-Sung Kim
     472             :     //       DATE WRITTEN   October 2014
     473             : 
     474             :     // PURPOSE OF THIS SUBROUTINE:
     475             :     // This subroutine initializes variables relating to indoor swimming pools.
     476             : 
     477             :     // SUBROUTINE PARAMETER DEFINITIONS:
     478             :     static constexpr std::string_view RoutineName("InitSwimmingPool");
     479        5538 :     Real64 constexpr MinActivityFactor = 0.0;  // Minimum value for activity factor
     480        5538 :     Real64 constexpr MaxActivityFactor = 10.0; // Maximum value for activity factor (realistically)
     481             : 
     482             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     483        5538 :     Real64 HeatGainPerPerson = ScheduleManager::GetCurrentScheduleValue(state, this->PeopleHeatGainSchedPtr);
     484        5538 :     Real64 PeopleModifier = ScheduleManager::GetCurrentScheduleValue(state, this->PeopleSchedPtr);
     485             : 
     486        5538 :     if (this->MyOneTimeFlag) {
     487           2 :         this->setupOutputVars(state); // Set up the output variables once here
     488           2 :         this->ZeroSourceSumHATsurf.allocate(state.dataGlobal->NumOfZones);
     489           2 :         this->ZeroSourceSumHATsurf = 0.0;
     490           2 :         this->QPoolSrcAvg.allocate(state.dataSurface->TotSurfaces);
     491           2 :         this->QPoolSrcAvg = 0.0;
     492           2 :         this->HeatTransCoefsAvg.allocate(state.dataSurface->TotSurfaces);
     493           2 :         this->HeatTransCoefsAvg = 0.0;
     494           2 :         this->LastQPoolSrc.allocate(state.dataSurface->TotSurfaces);
     495           2 :         this->LastQPoolSrc = 0.0;
     496           2 :         this->LastHeatTransCoefs.allocate(state.dataSurface->TotSurfaces);
     497           2 :         this->LastHeatTransCoefs = 0.0;
     498           2 :         this->LastSysTimeElapsed.allocate(state.dataSurface->TotSurfaces);
     499           2 :         this->LastSysTimeElapsed = 0.0;
     500           2 :         this->LastTimeStepSys.allocate(state.dataSurface->TotSurfaces);
     501           2 :         this->LastTimeStepSys = 0.0;
     502           2 :         this->MyOneTimeFlag = false;
     503             :     }
     504             : 
     505        5538 :     SwimmingPoolData::initSwimmingPoolPlantLoopIndex(state);
     506             : 
     507        5538 :     if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlagGeneral) {
     508          10 :         this->ZeroSourceSumHATsurf = 0.0;
     509          10 :         this->QPoolSrcAvg = 0.0;
     510          10 :         this->HeatTransCoefsAvg = 0.0;
     511          10 :         this->LastQPoolSrc = 0.0;
     512          10 :         this->LastHeatTransCoefs = 0.0;
     513          10 :         this->LastSysTimeElapsed = 0.0;
     514          10 :         this->LastTimeStepSys = 0.0;
     515          10 :         this->MyEnvrnFlagGeneral = false;
     516             :     }
     517             : 
     518        5538 :     if (!state.dataGlobal->BeginEnvrnFlag) this->MyEnvrnFlagGeneral = true;
     519             : 
     520        5538 :     if (state.dataGlobal->BeginEnvrnFlag) {
     521          32 :         this->PoolWaterTemp = 23.0;
     522          32 :         this->HeatPower = 0.0;
     523          32 :         this->HeatEnergy = 0.0;
     524          32 :         this->MiscEquipPower = 0.0;
     525          32 :         this->MiscEquipEnergy = 0.0;
     526          32 :         this->WaterInletTemp = 0.0;
     527          32 :         this->WaterOutletTemp = 0.0;
     528          32 :         this->WaterMassFlowRate = 0.0;
     529          32 :         this->PeopleHeatGain = 0.0;
     530          32 :         Real64 Density = FluidProperties::GetDensityGlycol(state, "WATER", this->PoolWaterTemp, this->GlycolIndex, RoutineName);
     531          32 :         this->WaterMass = state.dataSurface->Surface(this->SurfacePtr).Area * this->AvgDepth * Density;
     532          32 :         this->WaterMassFlowRateMax = this->WaterVolFlowMax * Density;
     533          32 :         this->initSwimmingPoolPlantNodeFlow(state);
     534             :     }
     535             : 
     536        5538 :     if (state.dataGlobal->BeginTimeStepFlag && FirstHVACIteration) { // This is the first pass through in a particular time step
     537             : 
     538        2706 :         int ZoneNum = this->ZonePtr;
     539        2706 :         this->ZeroSourceSumHATsurf(ZoneNum) =
     540        2706 :             state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state); // Set this to figure what part of the load the radiant system meets
     541        2706 :         int SurfNum = this->SurfacePtr;
     542        2706 :         this->QPoolSrcAvg(SurfNum) = 0.0;        // Initialize this variable to zero (pool parameters "off")
     543        2706 :         this->HeatTransCoefsAvg(SurfNum) = 0.0;  // Initialize this variable to zero (pool parameters "off")
     544        2706 :         this->LastQPoolSrc(SurfNum) = 0.0;       // At the start of a time step, reset to zero so average calculation can begin again
     545        2706 :         this->LastSysTimeElapsed(SurfNum) = 0.0; // At the start of a time step, reset to zero so average calculation can begin again
     546        2706 :         this->LastTimeStepSys(SurfNum) = 0.0;    // At the start of a time step, reset to zero so average calculation can begin again
     547             :     }
     548             : 
     549             :     // initialize the flow rate for the component on the plant side (this follows standard procedure for other components like low temperature
     550             :     // radiant systems)
     551        5538 :     Real64 mdot = 0.0;
     552        5538 :     PlantUtilities::SetComponentFlowRate(state, mdot, this->WaterInletNode, this->WaterOutletNode, this->HWplantLoc);
     553        5538 :     this->WaterInletTemp = state.dataLoopNodes->Node(this->WaterInletNode).Temp;
     554             : 
     555             :     // get the schedule values for different scheduled parameters
     556        5538 :     if (this->ActivityFactorSchedPtr > 0) {
     557        5538 :         this->CurActivityFactor = ScheduleManager::GetCurrentScheduleValue(state, this->ActivityFactorSchedPtr);
     558        5538 :         if (this->CurActivityFactor < MinActivityFactor) {
     559           0 :             this->CurActivityFactor = MinActivityFactor;
     560           0 :             ShowWarningError(state,
     561           0 :                              std::string{RoutineName} + ": Swimming Pool =\"" + this->Name + " Activity Factor Schedule =\"" +
     562           0 :                                  this->ActivityFactorSchedName + " has a negative value.  This is not allowed.");
     563           0 :             ShowContinueError(state, "The activity factor has been reset to zero.");
     564             :         }
     565        5538 :         if (this->CurActivityFactor > MaxActivityFactor) {
     566           0 :             this->CurActivityFactor = 1.0;
     567           0 :             ShowWarningError(state,
     568           0 :                              std::string{RoutineName} + ": Swimming Pool =\"" + this->Name + " Activity Factor Schedule =\"" +
     569           0 :                                  this->ActivityFactorSchedName + " has a value larger than 10.  This is not allowed.");
     570           0 :             ShowContinueError(state, "The activity factor has been reset to unity.");
     571             :         }
     572             :     } else {
     573             :         // default is activity factor of 1.0
     574           0 :         this->CurActivityFactor = 1.0;
     575             :     }
     576             : 
     577        5538 :     this->CurSetPtTemp = ScheduleManager::GetCurrentScheduleValue(state, this->SetPtTempSchedPtr);
     578             : 
     579        5538 :     if (this->MakeupWaterSupplySchedPtr > 0) {
     580        5538 :         this->CurMakeupWaterTemp = ScheduleManager::GetCurrentScheduleValue(state, this->MakeupWaterSupplySchedPtr);
     581             :     } else {
     582             :         // use water main temperaure if no schedule present in input
     583           0 :         this->CurMakeupWaterTemp = state.dataEnvrn->WaterMainsTemp;
     584             :     }
     585             : 
     586             :     // determine the current heat gain from people
     587        5538 :     if (this->PeopleHeatGainSchedPtr > 0) {
     588        5538 :         if (HeatGainPerPerson < 0.0) {
     589           0 :             ShowWarningError(state,
     590           0 :                              std::string{RoutineName} + ": Swimming Pool =\"" + this->Name + " Heat Gain Schedule =\"" +
     591           0 :                                  this->PeopleHeatGainSchedName + " has a negative value.  This is not allowed.");
     592           0 :             ShowContinueError(state, "The heat gain per person has been reset to zero.");
     593           0 :             HeatGainPerPerson = 0.0;
     594             :         }
     595        5538 :         if (this->PeopleSchedPtr > 0) {
     596        5538 :             if (PeopleModifier < 0.0) {
     597           0 :                 ShowWarningError(state,
     598           0 :                                  std::string{RoutineName} + ": Swimming Pool =\"" + this->Name + " People Schedule =\"" + this->PeopleSchedName +
     599             :                                      " has a negative value.  This is not allowed.");
     600           0 :                 ShowContinueError(state, "The number of people has been reset to zero.");
     601           0 :                 PeopleModifier = 0.0;
     602             :             }
     603             :         } else { // no people schedule entered--assume that full number always present
     604           0 :             PeopleModifier = 1.0;
     605             :         }
     606             :     } else { // no heat gain schedule added--assume a zero value for Heat Gain per Person and no people present
     607           0 :         HeatGainPerPerson = 0.0;
     608           0 :         PeopleModifier = 0.0;
     609             :     }
     610        5538 :     this->PeopleHeatGain = PeopleModifier * HeatGainPerPerson * this->MaxNumOfPeople;
     611             : 
     612             :     // once cover schedule value is established, define the current values of the cover heat transfer factors
     613        5538 :     if (this->CoverSchedPtr > 0) {
     614        5538 :         this->CurCoverSchedVal = ScheduleManager::GetCurrentScheduleValue(state, this->CoverSchedPtr);
     615        5538 :         if (this->CurCoverSchedVal > 1.0) {
     616           0 :             ShowWarningError(state,
     617           0 :                              std::string{RoutineName} + ": Swimming Pool =\"" + this->Name + " Cover Schedule =\"" + this->CoverSchedName +
     618             :                                  " has a value greater than 1.0 (100%).  This is not allowed.");
     619           0 :             ShowContinueError(state, "The cover has been reset to one or fully covered.");
     620           0 :             this->CurCoverSchedVal = 1.0;
     621        5538 :         } else if (this->CurCoverSchedVal < 0.0) {
     622           0 :             ShowWarningError(state,
     623           0 :                              std::string{RoutineName} + ": Swimming Pool =\"" + this->Name + " Cover Schedule =\"" + this->CoverSchedName +
     624             :                                  " has a negative value.  This is not allowed.");
     625           0 :             ShowContinueError(state, "The cover has been reset to zero or uncovered.");
     626           0 :             this->CurCoverSchedVal = 0.0;
     627             :         }
     628             :     } else {
     629             :         // default is NO pool cover
     630           0 :         this->CurCoverSchedVal = 0.0;
     631             :     }
     632             :     // for the current cover factors, a value of 1.0 means that the pool is open (not covered)
     633             :     // the user input values determine the amount the pool cover degrades one of the factors
     634             :     // for example, if the cover reduces convection by 50% and the pool is half covered, then
     635             :     // the reduction factor for convection is 25% or 75% of the normal value.  this establishes
     636             :     // the following relationships and how they are used in other parts of the code.
     637             :     // note that for the radiation factors, the reduction in absorption of radiation caused by
     638             :     // the cover will result in a net imbalance if this energy which is no longer accounted for
     639             :     // in the surface heat balance is not accounted for elsewhere.  thus, these terms will dump
     640             :     // any reduced radiation into the air heat balance as an additional convective gain to avoid
     641             :     // any loss of energy in the overall heat balance.
     642        5538 :     this->CurCoverEvapFac = 1.0 - (this->CurCoverSchedVal * this->CoverEvapFactor);
     643        5538 :     this->CurCoverConvFac = 1.0 - (this->CurCoverSchedVal * this->CoverConvFactor);
     644        5538 :     this->CurCoverSWRadFac = 1.0 - (this->CurCoverSchedVal * this->CoverSWRadFactor);
     645        5538 :     this->CurCoverLWRadFac = 1.0 - (this->CurCoverSchedVal * this->CoverLWRadFactor);
     646        5538 : }
     647             : 
     648           2 : void SwimmingPoolData::setupOutputVars(EnergyPlusData &state)
     649             : {
     650           4 :     SetupOutputVariable(state,
     651             :                         "Indoor Pool Makeup Water Rate",
     652             :                         OutputProcessor::Unit::m3_s,
     653             :                         this->MakeUpWaterVolFlowRate,
     654             :                         OutputProcessor::SOVTimeStepType::System,
     655             :                         OutputProcessor::SOVStoreType::Average,
     656           2 :                         this->Name);
     657           4 :     SetupOutputVariable(state,
     658             :                         "Indoor Pool Makeup Water Volume",
     659             :                         OutputProcessor::Unit::m3,
     660             :                         this->MakeUpWaterVol,
     661             :                         OutputProcessor::SOVTimeStepType::System,
     662             :                         OutputProcessor::SOVStoreType::Summed,
     663             :                         this->Name,
     664             :                         _,
     665             :                         "MainsWater",
     666             :                         "Heating",
     667             :                         _,
     668           2 :                         "System");
     669           4 :     SetupOutputVariable(state,
     670             :                         "Indoor Pool Makeup Water Temperature",
     671             :                         OutputProcessor::Unit::C,
     672             :                         this->CurMakeupWaterTemp,
     673             :                         OutputProcessor::SOVTimeStepType::System,
     674             :                         OutputProcessor::SOVStoreType::Average,
     675           2 :                         this->Name);
     676           4 :     SetupOutputVariable(state,
     677             :                         "Indoor Pool Water Temperature",
     678             :                         OutputProcessor::Unit::C,
     679             :                         this->PoolWaterTemp,
     680             :                         OutputProcessor::SOVTimeStepType::System,
     681             :                         OutputProcessor::SOVStoreType::Average,
     682           2 :                         this->Name);
     683           4 :     SetupOutputVariable(state,
     684             :                         "Indoor Pool Inlet Water Temperature",
     685             :                         OutputProcessor::Unit::C,
     686             :                         this->WaterInletTemp,
     687             :                         OutputProcessor::SOVTimeStepType::System,
     688             :                         OutputProcessor::SOVStoreType::Average,
     689           2 :                         this->Name);
     690           4 :     SetupOutputVariable(state,
     691             :                         "Indoor Pool Inlet Water Mass Flow Rate",
     692             :                         OutputProcessor::Unit::kg_s,
     693             :                         this->WaterMassFlowRate,
     694             :                         OutputProcessor::SOVTimeStepType::System,
     695             :                         OutputProcessor::SOVStoreType::Average,
     696           2 :                         this->Name);
     697           4 :     SetupOutputVariable(state,
     698             :                         "Indoor Pool Miscellaneous Equipment Power",
     699             :                         OutputProcessor::Unit::W,
     700             :                         this->MiscEquipPower,
     701             :                         OutputProcessor::SOVTimeStepType::System,
     702             :                         OutputProcessor::SOVStoreType::Average,
     703           2 :                         this->Name);
     704           4 :     SetupOutputVariable(state,
     705             :                         "Indoor Pool Miscellaneous Equipment Energy",
     706             :                         OutputProcessor::Unit::J,
     707             :                         this->MiscEquipEnergy,
     708             :                         OutputProcessor::SOVTimeStepType::System,
     709             :                         OutputProcessor::SOVStoreType::Summed,
     710           2 :                         this->Name);
     711           4 :     SetupOutputVariable(state,
     712             :                         "Indoor Pool Water Heating Rate",
     713             :                         OutputProcessor::Unit::W,
     714             :                         this->HeatPower,
     715             :                         OutputProcessor::SOVTimeStepType::System,
     716             :                         OutputProcessor::SOVStoreType::Average,
     717           2 :                         this->Name);
     718           4 :     SetupOutputVariable(state,
     719             :                         "Indoor Pool Water Heating Energy",
     720             :                         OutputProcessor::Unit::J,
     721             :                         this->HeatEnergy,
     722             :                         OutputProcessor::SOVTimeStepType::System,
     723             :                         OutputProcessor::SOVStoreType::Summed,
     724             :                         this->Name,
     725             :                         _,
     726             :                         "ENERGYTRANSFER",
     727             :                         "HEATINGCOILS",
     728             :                         _,
     729           2 :                         "System");
     730           4 :     SetupOutputVariable(state,
     731             :                         "Indoor Pool Radiant to Convection by Cover",
     732             :                         OutputProcessor::Unit::W,
     733             :                         this->RadConvertToConvect,
     734             :                         OutputProcessor::SOVTimeStepType::System,
     735             :                         OutputProcessor::SOVStoreType::Average,
     736           2 :                         this->Name);
     737           4 :     SetupOutputVariable(state,
     738             :                         "Indoor Pool People Heat Gain",
     739             :                         OutputProcessor::Unit::W,
     740             :                         this->PeopleHeatGain,
     741             :                         OutputProcessor::SOVTimeStepType::System,
     742             :                         OutputProcessor::SOVStoreType::Average,
     743           2 :                         this->Name);
     744           4 :     SetupOutputVariable(state,
     745             :                         "Indoor Pool Current Activity Factor",
     746             :                         OutputProcessor::Unit::None,
     747             :                         this->CurActivityFactor,
     748             :                         OutputProcessor::SOVTimeStepType::System,
     749             :                         OutputProcessor::SOVStoreType::Average,
     750           2 :                         this->Name);
     751           4 :     SetupOutputVariable(state,
     752             :                         "Indoor Pool Current Cover Factor",
     753             :                         OutputProcessor::Unit::None,
     754             :                         this->CurCoverSchedVal,
     755             :                         OutputProcessor::SOVTimeStepType::System,
     756             :                         OutputProcessor::SOVStoreType::Average,
     757           2 :                         this->Name);
     758           4 :     SetupOutputVariable(state,
     759             :                         "Indoor Pool Evaporative Heat Loss Rate",
     760             :                         OutputProcessor::Unit::W,
     761             :                         this->EvapHeatLossRate,
     762             :                         OutputProcessor::SOVTimeStepType::System,
     763             :                         OutputProcessor::SOVStoreType::Average,
     764           2 :                         this->Name);
     765           4 :     SetupOutputVariable(state,
     766             :                         "Indoor Pool Evaporative Heat Loss Energy",
     767             :                         OutputProcessor::Unit::J,
     768             :                         this->EvapEnergyLoss,
     769             :                         OutputProcessor::SOVTimeStepType::System,
     770             :                         OutputProcessor::SOVStoreType::Summed,
     771           2 :                         this->Name);
     772           4 :     SetupOutputVariable(state,
     773             :                         "Indoor Pool Saturation Pressure at Pool Temperature",
     774             :                         OutputProcessor::Unit::Pa,
     775             :                         this->SatPressPoolWaterTemp,
     776             :                         OutputProcessor::SOVTimeStepType::System,
     777             :                         OutputProcessor::SOVStoreType::Average,
     778           2 :                         this->Name);
     779           4 :     SetupOutputVariable(state,
     780             :                         "Indoor Pool Partial Pressure of Water Vapor in Air",
     781             :                         OutputProcessor::Unit::Pa,
     782             :                         this->PartPressZoneAirTemp,
     783             :                         OutputProcessor::SOVTimeStepType::System,
     784             :                         OutputProcessor::SOVStoreType::Average,
     785           2 :                         this->Name);
     786           4 :     SetupOutputVariable(state,
     787             :                         "Indoor Pool Current Cover Evaporation Factor",
     788             :                         OutputProcessor::Unit::None,
     789             :                         this->CurCoverEvapFac,
     790             :                         OutputProcessor::SOVTimeStepType::System,
     791             :                         OutputProcessor::SOVStoreType::Average,
     792           2 :                         this->Name);
     793           4 :     SetupOutputVariable(state,
     794             :                         "Indoor Pool Current Cover Convective Factor",
     795             :                         OutputProcessor::Unit::None,
     796             :                         this->CurCoverConvFac,
     797             :                         OutputProcessor::SOVTimeStepType::System,
     798             :                         OutputProcessor::SOVStoreType::Average,
     799           2 :                         this->Name);
     800           4 :     SetupOutputVariable(state,
     801             :                         "Indoor Pool Current Cover SW Radiation Factor",
     802             :                         OutputProcessor::Unit::None,
     803             :                         this->CurCoverSWRadFac,
     804             :                         OutputProcessor::SOVTimeStepType::System,
     805             :                         OutputProcessor::SOVStoreType::Average,
     806           2 :                         this->Name);
     807           4 :     SetupOutputVariable(state,
     808             :                         "Indoor Pool Current Cover LW Radiation Factor",
     809             :                         OutputProcessor::Unit::None,
     810             :                         this->CurCoverLWRadFac,
     811             :                         OutputProcessor::SOVTimeStepType::System,
     812             :                         OutputProcessor::SOVStoreType::Average,
     813           2 :                         this->Name);
     814           2 : }
     815             : 
     816        5538 : void SwimmingPoolData::initSwimmingPoolPlantLoopIndex(EnergyPlusData &state)
     817             : {
     818             :     // SUBROUTINE INFORMATION:
     819             :     //       AUTHOR         Rick Strand
     820             :     //       DATE WRITTEN   June 2017
     821             : 
     822             :     static constexpr std::string_view RoutineName("InitSwimmingPoolPlantLoopIndex");
     823             : 
     824        5538 :     if (this->MyPlantScanFlagPool && allocated(state.dataPlnt->PlantLoop)) {
     825           2 :         bool errFlag = false;
     826           2 :         if (this->WaterInletNode > 0) {
     827           2 :             PlantUtilities::ScanPlantLoopsForObject(
     828             :                 state, this->Name, DataPlant::PlantEquipmentType::SwimmingPool_Indoor, this->HWplantLoc, errFlag, _, _, _, this->WaterInletNode, _);
     829           2 :             if (errFlag) {
     830           0 :                 ShowFatalError(state, std::string{RoutineName} + ": Program terminated due to previous condition(s).");
     831             :             }
     832             :         }
     833           2 :         this->MyPlantScanFlagPool = false;
     834        5536 :     } else if (this->MyPlantScanFlagPool && !state.dataGlobal->AnyPlantInModel) {
     835           0 :         this->MyPlantScanFlagPool = false;
     836             :     }
     837        5538 : }
     838             : 
     839          32 : void SwimmingPoolData::initSwimmingPoolPlantNodeFlow(EnergyPlusData &state) const
     840             : {
     841             : 
     842          32 :     if (!this->MyPlantScanFlagPool) {
     843          32 :         if (this->WaterInletNode > 0) {
     844          32 :             PlantUtilities::InitComponentNodes(state, 0.0, this->WaterMassFlowRateMax, this->WaterInletNode, this->WaterOutletNode);
     845          32 :             PlantUtilities::RegisterPlantCompDesignFlow(state, this->WaterInletNode, this->WaterVolFlowMax);
     846             :         }
     847             :     }
     848          32 : }
     849             : 
     850        5538 : void SwimmingPoolData::calculate(EnergyPlusData &state)
     851             : {
     852             :     // SUBROUTINE INFORMATION:
     853             :     //       AUTHOR         Rick Strand, Ho-Sung Kim
     854             :     //       DATE WRITTEN   October 2014
     855             : 
     856             :     // PURPOSE OF THIS SUBROUTINE:
     857             :     // This subroutine simulates the components making up the Indoor Swimming Pool model.
     858             : 
     859             :     // METHODOLOGY EMPLOYED:
     860             :     // The swimming pool is modeled as a SURFACE to get access to all of the existing
     861             :     // surface related algorithms.  This subroutine mainly models the components of the
     862             :     // swimming pool so that information can be used in a standard surface heat balance.
     863             :     // The pool is assumed to be located at the inside surface face with a possible cover
     864             :     // affecting the heat balance.  The pool model takes the form of an equation solving
     865             :     // for the inside surface temperature which is assumed to be the same as the pool
     866             :     // water temperature.
     867             :     // Standard Heat Balance Equation:
     868             :     //        SurfTempInTmp( SurfNum ) = ( SurfCTFConstInPart( SurfNum ) + SurfQRadThermInAbs( SurfNum ) + SurfOpaqQRadSWInAbs( SurfNum ) + HConvIn(
     869             :     //        SurfNum
     870             :     //)
     871             :     //* RefAirTemp( SurfNum ) + SurfNetLWRadToSurf( SurfNum ) + Construct( ConstrNum ).CTFSourceIn( 0 ) * SurfQsrcHist( 1, SurfNum ) +
     872             :     // SurfQdotRadHVACInPerArea( SurfNum ) + IterDampConst * SurfTempInsOld(
     873             :     // SurfNum ) + Construct( ConstrNum ).CTFCross( 0 ) * TH11 ) / ( Construct( ConstrNum ).CTFInside( 0 ) + HConvIn( SurfNum ) + IterDampConst );
     874             :     //// Constant part of conduction eq (history terms) | LW radiation from internal sources | SW radiation from internal sources | Convection
     875             :     // from surface to zone air | Net radiant exchange with other zone surfaces | Heat source/sink term for radiant systems | (if there is one
     876             :     // present) | Radiant flux from high temp radiant heater | Radiant flux from a hot water baseboard heater | Radiant flux from a steam
     877             :     // baseboard  heater | Radiant flux from an electric baseboard heater | Iterative damping term (for stability) | Current conduction from | the
     878             :     // outside  surface | Coefficient for conduction (current time) | Convection and damping term
     879             :     // That equation is modified to include pool specific terms and removes the IterDampConst
     880             :     // term which is for iterations within the inside surface heat balance.  Then, the resulting
     881             :     // equation is solved for the plant loop mass flow rate.  It also assigns the appropriate
     882             :     // terms for use in the actual heat balance routine.
     883             : 
     884             :     // REFERENCES:
     885             :     //  1. ASHRAE (2011). 2011 ASHRAE Handbook - HVAC Applications. Atlanta: American Society of Heating,
     886             :     //     Refrigerating and Air-Conditioning Engineers, Inc., p.5.6-5.9.
     887             :     //  2. Janis, R. and W. Tao (2005). Mechanical and Electrical Systems in Buildings. 3rd ed. Upper
     888             :     //     Saddle River, NJ: Pearson Education, Inc., p.246.
     889             :     //  3. Kittler, R. (1989). Indoor Natatorium Design and Energy Recycling. ASHRAE Transactions 95(1), p.521-526.
     890             :     //  4. Smith, C., R. Jones, and G. Lof (1993). Energy Requirements and Potential Savings for Heated
     891             :     //     Indoor Swimming Pools. ASHRAE Transactions 99(2), p.864-874.
     892             : 
     893             :     // SUBROUTINE PARAMETER DEFINITIONS:
     894             :     static constexpr std::string_view RoutineName("CalcSwimmingPool");
     895             : 
     896             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     897        5538 :     Real64 EvapRate = 0.0; // evaporation rate for pool in kg/s
     898             : 
     899             :     // initialize local variables
     900        5538 :     int SurfNum = this->SurfacePtr;                         // surface number of floor that is the pool
     901        5538 :     int ZoneNum = state.dataSurface->Surface(SurfNum).Zone; // index to zone array
     902        5538 :     auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
     903             : 
     904             :     // Convection coefficient calculation
     905             :     Real64 HConvIn =
     906        5538 :         0.22 * std::pow(std::abs(this->PoolWaterTemp - thisZoneHB.MAT), 1.0 / 3.0) * this->CurCoverConvFac; // convection coefficient for pool
     907        5538 :     calcSwimmingPoolEvap(state, EvapRate, SurfNum, thisZoneHB.MAT, thisZoneHB.ZoneAirHumRat);
     908        5538 :     this->MakeUpWaterMassFlowRate = EvapRate;
     909       11076 :     Real64 EvapEnergyLossPerArea = -EvapRate *
     910        5538 :                                    Psychrometrics::PsyHfgAirFnWTdb(thisZoneHB.ZoneAirHumRat,
     911             :                                                                    thisZoneHB.MAT) /
     912        5538 :                                    state.dataSurface->Surface(SurfNum).Area; // energy effect of evaporation rate per unit area in W/m2
     913        5538 :     this->EvapHeatLossRate = EvapEnergyLossPerArea * state.dataSurface->Surface(SurfNum).Area;
     914             :     // LW and SW radiation term modification: any "excess" radiation blocked by the cover gets convected
     915             :     // to the air directly and added to the zone air heat balance
     916        5538 :     Real64 LWsum = (state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNum) + state.dataHeatBalSurf->SurfQdotRadNetLWInPerArea(SurfNum) +
     917        5538 :                     state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNum)); // summation of all long-wavelenth radiation going to surface
     918        5538 :     Real64 LWtotal = this->CurCoverLWRadFac * LWsum;                           // total flux from long-wavelength radiation to surface
     919             :     Real64 SWtotal =
     920        5538 :         this->CurCoverSWRadFac * state.dataHeatBalSurf->SurfOpaqQRadSWInAbs(SurfNum); // total flux from short-wavelength radiation to surface
     921        5538 :     this->RadConvertToConvect =
     922        5538 :         ((1.0 - this->CurCoverLWRadFac) * LWsum) + ((1.0 - this->CurCoverSWRadFac) * state.dataHeatBalSurf->SurfOpaqQRadSWInAbs(SurfNum));
     923             : 
     924             :     // Heat gain from people (assumed to be all convective to pool water)
     925             :     Real64 PeopleGain =
     926        5538 :         this->PeopleHeatGain / state.dataSurface->Surface(SurfNum).Area; // heat gain from people in pool (assumed to be all convective)
     927             : 
     928             :     // Get an estimate of the pool water specific heat
     929             :     Real64 Cp =
     930        5538 :         FluidProperties::GetSpecificHeatGlycol(state, "WATER", this->PoolWaterTemp, this->GlycolIndex, RoutineName); // specific heat of pool water
     931             : 
     932        5538 :     Real64 TH22 = state.dataHeatBalSurf->SurfInsideTempHist(2)(
     933        5538 :         SurfNum); // inside surface temperature at the previous time step equals the old pool water temperature
     934        5538 :     Real64 TInSurf =
     935             :         this->CurSetPtTemp; // Setpoint temperature for pool which is also the goal temperature and also the inside surface face temperature
     936        5538 :     Real64 Tmuw = this->CurMakeupWaterTemp;                                       // Inlet makeup water temperature
     937        5538 :     Real64 TLoopInletTemp = state.dataLoopNodes->Node(this->WaterInletNode).Temp; // Inlet water temperature from the plant loop
     938        5538 :     this->WaterInletTemp = TLoopInletTemp;
     939             : 
     940             :     // Now calculate the requested mass flow rate from the plant loop to achieve the proper pool temperature
     941             :     // old equation using surface heat balance form: MassFlowRate = CpDeltaTi * ( CondTerms + ConvTerm + SWtotal + LWtotal + PeopleGain +
     942             :     // PoolMassTerm + MUWTerm + EvapEnergyLossPerArea );
     943       11076 :     Real64 MassFlowRate = (this->WaterMass / (state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour)) *
     944       11076 :                           ((TInSurf - TH22) / (TLoopInletTemp - TInSurf)); // Target mass flow rate to achieve the proper setpoint temperature
     945        5538 :     if (MassFlowRate > this->WaterMassFlowRateMax) {
     946           0 :         MassFlowRate = this->WaterMassFlowRateMax;
     947        5538 :     } else if (MassFlowRate < 0.0) {
     948           2 :         MassFlowRate = 0.0;
     949             :     }
     950        5538 :     PlantUtilities::SetComponentFlowRate(state, MassFlowRate, this->WaterInletNode, this->WaterOutletNode, this->HWplantLoc);
     951        5538 :     this->WaterMassFlowRate = MassFlowRate;
     952             : 
     953             :     // We now have a flow rate so we can assemble the terms needed for the surface heat balance that is solved for the inside face temperature
     954        5538 :     state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum) =
     955       11076 :         SWtotal + LWtotal + PeopleGain + EvapEnergyLossPerArea + HConvIn * thisZoneHB.MAT +
     956       11076 :         (EvapRate * Tmuw + MassFlowRate * TLoopInletTemp + (this->WaterMass * TH22 / state.dataGlobal->TimeStepZoneSec)) * Cp /
     957        5538 :             state.dataSurface->Surface(SurfNum).Area;
     958        5538 :     state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum) =
     959        5538 :         HConvIn + (EvapRate + MassFlowRate + (this->WaterMass / state.dataGlobal->TimeStepZoneSec)) * Cp / state.dataSurface->Surface(SurfNum).Area;
     960             : 
     961             :     // Finally take care of the latent and convective gains resulting from the pool
     962        5538 :     state.dataHeatBalFanSys->SumConvPool(ZoneNum) += this->RadConvertToConvect;
     963        5538 :     state.dataHeatBalFanSys->SumLatentPool(ZoneNum) += EvapRate * Psychrometrics::PsyHfgAirFnWTdb(thisZoneHB.ZoneAirHumRat, thisZoneHB.MAT);
     964        5538 : }
     965             : 
     966        5538 : void SwimmingPoolData::calcSwimmingPoolEvap(EnergyPlusData &state,
     967             :                                             Real64 &EvapRate,   // evaporation rate of pool
     968             :                                             int const SurfNum,  // surface index
     969             :                                             Real64 const MAT,   // mean air temperature
     970             :                                             Real64 const HumRat // zone air humidity ratio
     971             : )
     972             : {
     973             :     static constexpr std::string_view RoutineName("CalcSwimmingPoolEvap");
     974        5538 :     Real64 constexpr CFinHg(0.00029613); // Multiple pressure in Pa by this constant to get inches of Hg
     975             : 
     976             :     // Evaporation calculation:
     977             :     // Evaporation Rate (lb/h) = 0.1 * Area (ft2) * Activity Factor * (Psat,pool - Ppar,air) (in Hg)
     978             :     // So evaporation rate, area, and pressures have to be converted to standard E+ units (kg/s, m2, and Pa, respectively)
     979             :     // Evaporation Rate per Area = Evaporation Rate * Heat of Vaporization / Area of Surface
     980             : 
     981        5538 :     Real64 PSatPool = Psychrometrics::PsyPsatFnTemp(state, this->PoolWaterTemp, RoutineName);
     982             :     Real64 PParAir =
     983        5538 :         Psychrometrics::PsyPsatFnTemp(state, MAT, RoutineName) * Psychrometrics::PsyRhFnTdbWPb(state, MAT, HumRat, state.dataEnvrn->OutBaroPress);
     984        5538 :     if (PSatPool < PParAir) PSatPool = PParAir;
     985        5538 :     this->SatPressPoolWaterTemp = PSatPool;
     986        5538 :     this->PartPressZoneAirTemp = PParAir;
     987       11076 :     EvapRate = (0.1 * (state.dataSurface->Surface(SurfNum).Area / DataConversions::CFA) * this->CurActivityFactor * ((PSatPool - PParAir) * CFinHg)) *
     988        5538 :                DataConversions::CFMF * this->CurCoverEvapFac;
     989        5538 : }
     990             : 
     991        5538 : void SwimmingPoolData::update(EnergyPlusData &state)
     992             : {
     993             :     // SUBROUTINE INFORMATION:
     994             :     //       AUTHOR         Rick Strand, Ho-Sung Kim
     995             :     //       DATE WRITTEN   October 2014
     996             : 
     997             :     // PURPOSE OF THIS SUBROUTINE:
     998             :     // This subroutine does any updating that needs to be done for the swimming pool model.
     999             : 
    1000        5538 :     int SurfNum = this->SurfacePtr; // surface number/pointer
    1001             : 
    1002        5538 :     if (this->LastSysTimeElapsed(SurfNum) == state.dataHVACGlobal->SysTimeElapsed) {
    1003             :         // Still iterating or reducing system time step, so subtract old values which were
    1004             :         // not valid
    1005        5534 :         this->QPoolSrcAvg(SurfNum) -= this->LastQPoolSrc(SurfNum) * this->LastTimeStepSys(SurfNum) / state.dataGlobal->TimeStepZone;
    1006        5534 :         this->HeatTransCoefsAvg(SurfNum) -= this->LastHeatTransCoefs(SurfNum) * this->LastTimeStepSys(SurfNum) / state.dataGlobal->TimeStepZone;
    1007             :     }
    1008             : 
    1009             :     // Update the running average and the "last" values with the current values of the appropriate variables
    1010        5538 :     this->QPoolSrcAvg(SurfNum) +=
    1011        5538 :         state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum) * state.dataHVACGlobal->TimeStepSys / state.dataGlobal->TimeStepZone;
    1012        5538 :     this->HeatTransCoefsAvg(SurfNum) +=
    1013        5538 :         state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum) * state.dataHVACGlobal->TimeStepSys / state.dataGlobal->TimeStepZone;
    1014             : 
    1015        5538 :     this->LastQPoolSrc(SurfNum) = state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum);
    1016        5538 :     this->LastHeatTransCoefs(SurfNum) = state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum);
    1017        5538 :     this->LastSysTimeElapsed(SurfNum) = state.dataHVACGlobal->SysTimeElapsed;
    1018        5538 :     this->LastTimeStepSys(SurfNum) = state.dataHVACGlobal->TimeStepSys;
    1019             : 
    1020        5538 :     PlantUtilities::SafeCopyPlantNode(state, this->WaterInletNode, this->WaterOutletNode);
    1021             : 
    1022        5538 :     Real64 WaterMassFlow = state.dataLoopNodes->Node(this->WaterInletNode).MassFlowRate; // water mass flow rate
    1023        5538 :     if (WaterMassFlow > 0.0) state.dataLoopNodes->Node(this->WaterOutletNode).Temp = this->PoolWaterTemp;
    1024        5538 : }
    1025           0 : void SwimmingPoolData::oneTimeInit_new([[maybe_unused]] EnergyPlusData &state)
    1026             : {
    1027           0 : }
    1028           0 : void SwimmingPoolData::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
    1029             : {
    1030           0 : }
    1031             : 
    1032     2568313 : void UpdatePoolSourceValAvg(EnergyPlusData &state, bool &SwimmingPoolOn) // .TRUE. if the swimming pool "runs" this zone time step
    1033             : {
    1034             :     // SUBROUTINE INFORMATION:
    1035             :     //       AUTHOR         Rick Strand
    1036             :     //       DATE WRITTEN   October 2014
    1037             : 
    1038             :     // PURPOSE OF THIS SUBROUTINE:
    1039             :     // To transfer the average value of the pool heat balance term over the entire zone time step back to the heat balance routines so that the
    1040             :     // heat balance algorithms can simulate one last time with the average source to maintain some reasonable amount of continuity and energy
    1041             :     // balance in the temperature and flux histories.
    1042             : 
    1043             :     // METHODOLOGY EMPLOYED:
    1044             :     // All of the record keeping for the average term is done in the Update routine so the only other thing that this subroutine does is check to
    1045             :     // see if the system was even on.  If any average term is non-zero, then one or more of the swimming pools was running.  Method borrowed from
    1046             :     // radiant systems.
    1047             : 
    1048             :     // SUBROUTINE PARAMETER DEFINITIONS:
    1049     2568313 :     Real64 constexpr CloseEnough(0.01); // Some arbitrarily small value to avoid zeros and numbers that are almost the same
    1050             : 
    1051             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1052     2568313 :     SwimmingPoolOn = false;
    1053             : 
    1054             :     // If this was never allocated, then there are no radiant systems in this input file (just RETURN)
    1055     2571019 :     for (int PoolNum = 1; PoolNum <= state.dataSwimmingPools->NumSwimmingPools; ++PoolNum) {
    1056        2706 :         if (!allocated(state.dataSwimmingPools->Pool(PoolNum).QPoolSrcAvg)) return;
    1057             : 
    1058             :         // If it was allocated, then we have to check to see if this was running at all
    1059       51414 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1060       51414 :             if (state.dataSwimmingPools->Pool(PoolNum).QPoolSrcAvg(SurfNum) != 0.0) {
    1061        2706 :                 SwimmingPoolOn = true;
    1062        2706 :                 break; // DO loop
    1063             :             }
    1064             :         }
    1065             : 
    1066        2706 :         state.dataHeatBalFanSys->QPoolSurfNumerator = state.dataSwimmingPools->Pool(PoolNum).QPoolSrcAvg;
    1067        2706 :         state.dataHeatBalFanSys->PoolHeatTransCoefs = state.dataSwimmingPools->Pool(PoolNum).HeatTransCoefsAvg;
    1068             :     }
    1069             : 
    1070             :     // For interzone surfaces, modQPoolSrcAvg was only updated for the "active" side.  The active side
    1071             :     // would have a non-zero value at this point.  If the numbers differ, then we have to manually update.
    1072   166705567 :     for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1073   164137254 :         if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0 && state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) {
    1074   184307730 :             if (std::abs(state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum) -
    1075   122871820 :                          state.dataHeatBalFanSys->QPoolSurfNumerator(state.dataSurface->Surface(SurfNum).ExtBoundCond)) >
    1076             :                 CloseEnough) { // numbers differ
    1077           0 :                 if (std::abs(state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum)) >
    1078           0 :                     std::abs(state.dataHeatBalFanSys->QPoolSurfNumerator(state.dataSurface->Surface(SurfNum).ExtBoundCond))) {
    1079           0 :                     state.dataHeatBalFanSys->QPoolSurfNumerator(state.dataSurface->Surface(SurfNum).ExtBoundCond) =
    1080           0 :                         state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum);
    1081             :                 } else {
    1082           0 :                     state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum) =
    1083           0 :                         state.dataHeatBalFanSys->QPoolSurfNumerator(state.dataSurface->Surface(SurfNum).ExtBoundCond);
    1084             :                 }
    1085             :             }
    1086             :         }
    1087             :     }
    1088             :     // For interzone surfaces, PoolHeatTransCoefs was only updated for the "active" side.  The active side
    1089             :     // would have a non-zero value at this point.  If the numbers differ, then we have to manually update.
    1090   166705567 :     for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1091   164137254 :         if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0 && state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) {
    1092   184307730 :             if (std::abs(state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum) -
    1093   122871820 :                          state.dataHeatBalFanSys->PoolHeatTransCoefs(state.dataSurface->Surface(SurfNum).ExtBoundCond)) >
    1094             :                 CloseEnough) { // numbers differ
    1095           0 :                 if (std::abs(state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum)) >
    1096           0 :                     std::abs(state.dataHeatBalFanSys->PoolHeatTransCoefs(state.dataSurface->Surface(SurfNum).ExtBoundCond))) {
    1097           0 :                     state.dataHeatBalFanSys->PoolHeatTransCoefs(state.dataSurface->Surface(SurfNum).ExtBoundCond) =
    1098           0 :                         state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum);
    1099             :                 } else {
    1100           0 :                     state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum) =
    1101           0 :                         state.dataHeatBalFanSys->PoolHeatTransCoefs(state.dataSurface->Surface(SurfNum).ExtBoundCond);
    1102             :                 }
    1103             :             }
    1104             :         }
    1105             :     }
    1106             : }
    1107             : 
    1108     6050562 : void ReportSwimmingPool(EnergyPlusData &state)
    1109             : {
    1110             :     // SUBROUTINE INFORMATION:
    1111             :     //       AUTHOR         Rick Strand, Ho-Sung Kim
    1112             :     //       DATE WRITTEN   October 2014
    1113             : 
    1114             :     // PURPOSE OF THIS SUBROUTINE:
    1115             :     // This subroutine simply produces output for the swimming pool model.
    1116             : 
    1117             :     // SUBROUTINE PARAMETER DEFINITIONS:
    1118             :     static constexpr std::string_view RoutineName("ReportSwimmingPool");
    1119     6050562 :     Real64 constexpr MinDensity = 1.0; // to avoid a divide by zero
    1120             : 
    1121     6056100 :     for (int PoolNum = 1; PoolNum <= state.dataSwimmingPools->NumSwimmingPools; ++PoolNum) {
    1122             : 
    1123        5538 :         int SurfNum = state.dataSwimmingPools->Pool(PoolNum).SurfacePtr; // surface number index
    1124             : 
    1125             :         // First transfer the surface inside temperature data to the current pool water temperature
    1126        5538 :         state.dataSwimmingPools->Pool(PoolNum).PoolWaterTemp = state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfNum);
    1127             : 
    1128             :         // Next calculate the amount of heating done by the plant loop
    1129       16614 :         Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state,
    1130             :                                                            "WATER",
    1131        5538 :                                                            state.dataSwimmingPools->Pool(PoolNum).PoolWaterTemp,
    1132        5538 :                                                            state.dataSwimmingPools->Pool(PoolNum).GlycolIndex,
    1133        5538 :                                                            RoutineName); // specific heat of water
    1134        5538 :         state.dataSwimmingPools->Pool(PoolNum).HeatPower =
    1135       11076 :             state.dataSwimmingPools->Pool(PoolNum).WaterMassFlowRate * Cp *
    1136        5538 :             (state.dataSwimmingPools->Pool(PoolNum).WaterInletTemp - state.dataSwimmingPools->Pool(PoolNum).PoolWaterTemp);
    1137             : 
    1138             :         // Now the power consumption of miscellaneous equipment
    1139       16614 :         Real64 Density = FluidProperties::GetDensityGlycol(state,
    1140             :                                                            "WATER",
    1141        5538 :                                                            state.dataSwimmingPools->Pool(PoolNum).PoolWaterTemp,
    1142        5538 :                                                            state.dataSwimmingPools->Pool(PoolNum).GlycolIndex,
    1143        5538 :                                                            RoutineName); // density of water
    1144        5538 :         if (Density > MinDensity) {
    1145        5538 :             state.dataSwimmingPools->Pool(PoolNum).MiscEquipPower =
    1146        5538 :                 state.dataSwimmingPools->Pool(PoolNum).MiscPowerFactor * state.dataSwimmingPools->Pool(PoolNum).WaterMassFlowRate / Density;
    1147             :         } else {
    1148           0 :             state.dataSwimmingPools->Pool(PoolNum).MiscEquipPower = 0.0;
    1149             :         }
    1150             : 
    1151             :         // Also the radiant exchange converted to convection by the pool cover
    1152        5538 :         state.dataSwimmingPools->Pool(PoolNum).RadConvertToConvectRep =
    1153        5538 :             state.dataSwimmingPools->Pool(PoolNum).RadConvertToConvect * state.dataSurface->Surface(SurfNum).Area;
    1154             : 
    1155             :         // Finally calculate the summed up report variables
    1156        5538 :         state.dataSwimmingPools->Pool(PoolNum).MiscEquipEnergy =
    1157        5538 :             state.dataSwimmingPools->Pool(PoolNum).MiscEquipPower * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
    1158        5538 :         state.dataSwimmingPools->Pool(PoolNum).HeatEnergy =
    1159        5538 :             state.dataSwimmingPools->Pool(PoolNum).HeatPower * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
    1160        5538 :         state.dataSwimmingPools->Pool(PoolNum).MakeUpWaterMass =
    1161        5538 :             state.dataSwimmingPools->Pool(PoolNum).MakeUpWaterMassFlowRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
    1162        5538 :         state.dataSwimmingPools->Pool(PoolNum).EvapEnergyLoss =
    1163        5538 :             state.dataSwimmingPools->Pool(PoolNum).EvapHeatLossRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
    1164             : 
    1165        5538 :         state.dataSwimmingPools->Pool(PoolNum).MakeUpWaterVolFlowRate =
    1166        5538 :             MakeUpWaterVolFlowFunct(state.dataSwimmingPools->Pool(PoolNum).MakeUpWaterMassFlowRate, Density);
    1167        5538 :         state.dataSwimmingPools->Pool(PoolNum).MakeUpWaterVol = MakeUpWaterVolFunct(state.dataSwimmingPools->Pool(PoolNum).MakeUpWaterMass, Density);
    1168             :     }
    1169     6050562 : }
    1170             : 
    1171        5538 : Real64 MakeUpWaterVolFlowFunct(Real64 MakeUpWaterMassFlowRate, Real64 Density)
    1172             : {
    1173        5538 :     return MakeUpWaterMassFlowRate / Density;
    1174             : }
    1175             : 
    1176        5538 : Real64 MakeUpWaterVolFunct(Real64 MakeUpWaterMass, Real64 Density)
    1177             : {
    1178        5538 :     return MakeUpWaterMass / Density;
    1179             : }
    1180             : 
    1181        2313 : } // namespace EnergyPlus::SwimmingPool

Generated by: LCOV version 1.13