LCOV - code coverage report
Current view: top level - EnergyPlus - SwimmingPool.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 72.7 % 553 402
Test Date: 2025-06-02 07:23:51 Functions: 94.4 % 18 17

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

Generated by: LCOV version 2.0-1