LCOV - code coverage report
Current view: top level - EnergyPlus - SwimmingPool.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 399 555 71.9 %
Date: 2024-08-24 18:31:18 Functions: 17 18 94.4 %

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

Generated by: LCOV version 1.14