LCOV - code coverage report
Current view: top level - EnergyPlus - PondGroundHeatExchanger.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 0.0 % 303 0
Test Date: 2025-05-22 16:09:37 Functions: 0.0 % 13 0

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cmath>
      50              : 
      51              : // ObjexxFCL Headers
      52              : #include <ObjexxFCL/Array.functions.hh>
      53              : #include <ObjexxFCL/Fmath.hh>
      54              : 
      55              : // EnergyPlus Headers
      56              : #include <EnergyPlus/BranchNodeConnections.hh>
      57              : #include <EnergyPlus/ConvectionCoefficients.hh>
      58              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      59              : #include <EnergyPlus/DataEnvironment.hh>
      60              : #include <EnergyPlus/DataHVACGlobals.hh>
      61              : #include <EnergyPlus/DataHeatBalance.hh>
      62              : #include <EnergyPlus/DataIPShortCuts.hh>
      63              : #include <EnergyPlus/DataLoopNode.hh>
      64              : #include <EnergyPlus/DataPrecisionGlobals.hh>
      65              : #include <EnergyPlus/FluidProperties.hh>
      66              : #include <EnergyPlus/General.hh>
      67              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      68              : #include <EnergyPlus/NodeInputManager.hh>
      69              : #include <EnergyPlus/OutputProcessor.hh>
      70              : #include <EnergyPlus/Plant/DataPlant.hh>
      71              : #include <EnergyPlus/PlantUtilities.hh>
      72              : #include <EnergyPlus/PondGroundHeatExchanger.hh>
      73              : #include <EnergyPlus/Psychrometrics.hh>
      74              : #include <EnergyPlus/UtilityRoutines.hh>
      75              : 
      76              : namespace EnergyPlus::PondGroundHeatExchanger {
      77              : 
      78              : // Module containing the routines dealing with pond ground heat exchangers
      79              : 
      80              : // MODULE INFORMATION:
      81              : //       AUTHOR         Simon Rees
      82              : //       DATE WRITTEN   September 2002
      83              : //       MODIFIED       Brent Griffith Sept 2010, plant upgrades
      84              : //       RE-ENGINEERED  na
      85              : 
      86              : // PURPOSE OF THIS MODULE:
      87              : // This model represents a shallow pond with submerged hydronic tubes through
      88              : // which the heat transfer fluid is circulated. The model represents a 'shallow'
      89              : // pond in that no attempt is made to model any stratification effects that may
      90              : // be present in deeper ponds. This type of heat rejector is intended to be
      91              : // connected in a condenser loop, with or without other forms of heat rejector.
      92              : // The pond model is a 'lumped parameter' model where the pond is represented
      93              : // by a single node with thermal mass. The pond surface temperature is the same
      94              : // as the temperature at this node, i.e. the surface temperature is the same as
      95              : // the bulk temperature. A first order differential equation is solved in the
      96              : // model to calculated the pond temperature at each time step. This type of heat
      97              : // rejector is modelled as several circuits connected in parallel.
      98              : 
      99              : // METHODOLOGY EMPLOYED:
     100              : // A heat balance is calculated at a single node that represents the pond.
     101              : // heat transfer takes palce by surface convection, long-wave radiation to the
     102              : // sky, absoption of solar energy, ground heat transfer and heat exchange with
     103              : // the fluid. A heat exchanger analogy is used to calculate the heat transfer
     104              : // between the heat transfer fluid and the pond. The differential equation
     105              : // defined by the heat balance is solved using a fourth order Runge-Kutta
     106              : // numerical integration method.
     107              : 
     108              : // REFERENCES:
     109              : // Chiasson, A. Advances in Modeling of Ground-Source Heat Pump Systems.
     110              : //   M.S. Thesis, Oklahoma State University, December 1999.
     111              : // Chiasson, A.D., J.D. Spitler, S.J. Rees, M.D. Smith.  2000.  A Model For
     112              : //   Simulating The Performance Of A Shallow Pond As A Supplemental Heat Rejecter
     113              : //   With Closed-Loop Ground-Source Heat Pump Systems.
     114              : //   ASHRAE Transactions.  106(2):107-121.
     115              : 
     116              : Real64 constexpr StefBoltzmann(5.6697e-08); // Stefan-Boltzmann constant
     117              : 
     118            0 : void PondGroundHeatExchangerData::simulate(EnergyPlusData &state,
     119              :                                            [[maybe_unused]] const PlantLocation &calledFromLocation,
     120              :                                            bool const FirstHVACIteration,
     121              :                                            [[maybe_unused]] Real64 &CurLoad,
     122              :                                            [[maybe_unused]] bool const RunFlag)
     123              : {
     124            0 :     this->InitPondGroundHeatExchanger(state, FirstHVACIteration);
     125            0 :     this->CalcPondGroundHeatExchanger(state);
     126            0 :     this->UpdatePondGroundHeatExchanger(state);
     127            0 : }
     128              : 
     129            0 : PlantComponent *PondGroundHeatExchangerData::factory(EnergyPlusData &state, std::string const &objectName)
     130              : {
     131            0 :     if (state.dataPondGHE->GetInputFlag) {
     132            0 :         GetPondGroundHeatExchanger(state);
     133            0 :         state.dataPondGHE->GetInputFlag = false;
     134              :     }
     135            0 :     for (auto &ghx : state.dataPondGHE->PondGHE) {
     136            0 :         if (ghx.Name == objectName) {
     137            0 :             return &ghx;
     138              :         }
     139              :     }
     140              :     // If we didn't find it, fatal
     141            0 :     ShowFatalError(state, format("Pond Heat Exchanger Factory: Error getting inputs for GHX named: {}", objectName));
     142              :     // Shut up the compiler
     143            0 :     return nullptr;
     144              : }
     145              : 
     146            0 : void PondGroundHeatExchangerData::onInitLoopEquip(EnergyPlusData &state, [[maybe_unused]] const PlantLocation &calledFromLocation)
     147              : {
     148            0 :     this->InitPondGroundHeatExchanger(state, true);
     149            0 : }
     150              : 
     151            0 : void PondGroundHeatExchangerData::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
     152              :                                                       [[maybe_unused]] const PlantLocation &calledFromLocation,
     153              :                                                       Real64 &MaxLoad,
     154              :                                                       Real64 &MinLoad,
     155              :                                                       Real64 &OptLoad)
     156              : {
     157            0 :     MaxLoad = this->DesignCapacity;
     158            0 :     MinLoad = 0.0;
     159            0 :     OptLoad = this->DesignCapacity;
     160            0 : }
     161              : 
     162            0 : void GetPondGroundHeatExchanger(EnergyPlusData &state)
     163              : {
     164              : 
     165              :     // SUBROUTINE INFORMATION:
     166              :     //       AUTHOR         Simon Rees
     167              :     //       DATE WRITTEN   August 2002
     168              :     //       MODIFIED       na
     169              :     //       RE-ENGINEERED  na
     170              : 
     171              :     // PURPOSE OF THIS SUBROUTINE:
     172              :     // This subroutine reads the input for hydronic Pond Ground Heat Exchangers
     173              :     // from the user input file.  This will contain all of the information
     174              :     // needed to define and simulate the pond.
     175              : 
     176            0 :     bool ErrorsFound(false); // Set to true if errors in input,
     177              : 
     178              :     int IOStatus;   // Used in GetObjectItem
     179              :     int Item;       // Item to be "gotten"
     180              :     int NumAlphas;  // Number of Alphas for each GetObjectItem call
     181              :     int NumNumbers; // Number of Numbers for each GetObjectItem call
     182              : 
     183              :     // Initializations and allocations
     184            0 :     state.dataIPShortCut->cCurrentModuleObject = "GroundHeatExchanger:Pond";
     185            0 :     state.dataPondGHE->NumOfPondGHEs =
     186            0 :         state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
     187              :     // allocate data structures
     188            0 :     if (allocated(state.dataPondGHE->PondGHE)) state.dataPondGHE->PondGHE.deallocate();
     189              : 
     190            0 :     state.dataPondGHE->PondGHE.allocate(state.dataPondGHE->NumOfPondGHEs);
     191              : 
     192              :     // Obtain all of the user data related to the ponds...
     193            0 :     for (Item = 1; Item <= state.dataPondGHE->NumOfPondGHEs; ++Item) {
     194              : 
     195              :         // get the input data
     196            0 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     197            0 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
     198              :                                                                  Item,
     199            0 :                                                                  state.dataIPShortCut->cAlphaArgs,
     200              :                                                                  NumAlphas,
     201            0 :                                                                  state.dataIPShortCut->rNumericArgs,
     202              :                                                                  NumNumbers,
     203              :                                                                  IOStatus,
     204              :                                                                  _,
     205              :                                                                  _,
     206            0 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
     207            0 :                                                                  state.dataIPShortCut->cNumericFieldNames);
     208              : 
     209            0 :         if ((state.dataPondGHE->PondGHE(Item).water = Fluid::GetWater(state)) == nullptr) {
     210            0 :             ShowSevereError(state, "Fluid Properties for WATER not found");
     211            0 :             ErrorsFound = true;
     212              :         }
     213              : 
     214              :         // General user input data
     215            0 :         state.dataPondGHE->PondGHE(Item).Name = state.dataIPShortCut->cAlphaArgs(1);
     216              : 
     217              :         // get inlet node data
     218            0 :         state.dataPondGHE->PondGHE(Item).InletNode = state.dataIPShortCut->cAlphaArgs(2);
     219            0 :         state.dataPondGHE->PondGHE(Item).InletNodeNum =
     220            0 :             NodeInputManager::GetOnlySingleNode(state,
     221            0 :                                                 state.dataIPShortCut->cAlphaArgs(2),
     222              :                                                 ErrorsFound,
     223              :                                                 DataLoopNode::ConnectionObjectType::GroundHeatExchangerPond,
     224            0 :                                                 state.dataIPShortCut->cAlphaArgs(1),
     225              :                                                 DataLoopNode::NodeFluidType::Water,
     226              :                                                 DataLoopNode::ConnectionType::Inlet,
     227              :                                                 NodeInputManager::CompFluidStream::Primary,
     228              :                                                 DataLoopNode::ObjectIsNotParent);
     229            0 :         if (state.dataPondGHE->PondGHE(Item).InletNodeNum == 0) {
     230            0 :             ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2)));
     231            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     232            0 :             ErrorsFound = true;
     233              :         }
     234              : 
     235              :         // get outlet node data
     236            0 :         state.dataPondGHE->PondGHE(Item).OutletNode = state.dataIPShortCut->cAlphaArgs(3);
     237            0 :         state.dataPondGHE->PondGHE(Item).OutletNodeNum =
     238            0 :             NodeInputManager::GetOnlySingleNode(state,
     239            0 :                                                 state.dataIPShortCut->cAlphaArgs(3),
     240              :                                                 ErrorsFound,
     241              :                                                 DataLoopNode::ConnectionObjectType::GroundHeatExchangerPond,
     242            0 :                                                 state.dataIPShortCut->cAlphaArgs(1),
     243              :                                                 DataLoopNode::NodeFluidType::Water,
     244              :                                                 DataLoopNode::ConnectionType::Outlet,
     245              :                                                 NodeInputManager::CompFluidStream::Primary,
     246              :                                                 DataLoopNode::ObjectIsNotParent);
     247            0 :         if (state.dataPondGHE->PondGHE(Item).OutletNodeNum == 0) {
     248            0 :             ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(3), state.dataIPShortCut->cAlphaArgs(3)));
     249            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     250            0 :             ErrorsFound = true;
     251              :         }
     252              : 
     253            0 :         BranchNodeConnections::TestCompSet(state,
     254            0 :                                            state.dataIPShortCut->cCurrentModuleObject,
     255            0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     256            0 :                                            state.dataIPShortCut->cAlphaArgs(2),
     257            0 :                                            state.dataIPShortCut->cAlphaArgs(3),
     258              :                                            "Condenser Water Nodes");
     259              : 
     260              :         // pond geometry data
     261            0 :         state.dataPondGHE->PondGHE(Item).Depth = state.dataIPShortCut->rNumericArgs(1);
     262            0 :         state.dataPondGHE->PondGHE(Item).Area = state.dataIPShortCut->rNumericArgs(2);
     263            0 :         if (state.dataIPShortCut->rNumericArgs(1) <= 0.0) {
     264            0 :             ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->rNumericArgs(1)));
     265            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     266            0 :             ShowContinueError(state, "Value must be greater than 0.0");
     267            0 :             ErrorsFound = true;
     268              :         }
     269            0 :         if (state.dataIPShortCut->rNumericArgs(2) <= 0.0) {
     270            0 :             ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
     271            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     272            0 :             ShowContinueError(state, "Value must be greater than 0.0");
     273            0 :             ErrorsFound = true;
     274              :         }
     275              : 
     276              :         // tube data
     277            0 :         state.dataPondGHE->PondGHE(Item).TubeInDiameter = state.dataIPShortCut->rNumericArgs(3);
     278            0 :         state.dataPondGHE->PondGHE(Item).TubeOutDiameter = state.dataIPShortCut->rNumericArgs(4);
     279              : 
     280            0 :         if (state.dataIPShortCut->rNumericArgs(3) <= 0.0) {
     281            0 :             ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(3), state.dataIPShortCut->rNumericArgs(3)));
     282            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     283            0 :             ShowContinueError(state, "Value must be greater than 0.0");
     284            0 :             ErrorsFound = true;
     285              :         }
     286            0 :         if (state.dataIPShortCut->rNumericArgs(4) <= 0.0) {
     287            0 :             ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(4), state.dataIPShortCut->rNumericArgs(4)));
     288            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     289            0 :             ShowContinueError(state, "Value must be greater than 0.0");
     290            0 :             ErrorsFound = true;
     291              :         }
     292            0 :         if (state.dataIPShortCut->rNumericArgs(3) > state.dataIPShortCut->rNumericArgs(4)) { // error
     293            0 :             ShowSevereError(state, format("For {}: {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     294            0 :             ShowContinueError(state,
     295            0 :                               format("{} [{:.2R}] > {} [{:.2R}]",
     296            0 :                                      state.dataIPShortCut->cNumericFieldNames(3),
     297            0 :                                      state.dataIPShortCut->rNumericArgs(3),
     298            0 :                                      state.dataIPShortCut->cNumericFieldNames(4),
     299            0 :                                      state.dataIPShortCut->rNumericArgs(4)));
     300            0 :             ErrorsFound = true;
     301              :         }
     302              : 
     303              :         // thermal conductivity data
     304            0 :         state.dataPondGHE->PondGHE(Item).TubeConductivity = state.dataIPShortCut->rNumericArgs(5);
     305            0 :         state.dataPondGHE->PondGHE(Item).GrndConductivity = state.dataIPShortCut->rNumericArgs(6);
     306              : 
     307            0 :         if (state.dataIPShortCut->rNumericArgs(5) <= 0.0) {
     308            0 :             ShowSevereError(state, format("Invalid {}={:.4R}", state.dataIPShortCut->cNumericFieldNames(5), state.dataIPShortCut->rNumericArgs(5)));
     309            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     310            0 :             ShowContinueError(state, "Value must be greater than 0.0");
     311            0 :             ErrorsFound = true;
     312              :         }
     313            0 :         if (state.dataIPShortCut->rNumericArgs(6) <= 0.0) {
     314            0 :             ShowSevereError(state, format("Invalid {}={:.4R}", state.dataIPShortCut->cNumericFieldNames(6), state.dataIPShortCut->rNumericArgs(6)));
     315            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     316            0 :             ShowContinueError(state, "Value must be greater than 0.0");
     317            0 :             ErrorsFound = true;
     318              :         }
     319              : 
     320              :         // circuits
     321            0 :         state.dataPondGHE->PondGHE(Item).NumCircuits = state.dataIPShortCut->rNumericArgs(7);
     322              : 
     323            0 :         if (state.dataIPShortCut->rNumericArgs(7) <= 0) {
     324            0 :             ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(7), state.dataIPShortCut->rNumericArgs(7)));
     325            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     326            0 :             ShowContinueError(state, "Value must be greater than 0.0");
     327            0 :             ErrorsFound = true;
     328              :         }
     329            0 :         state.dataPondGHE->PondGHE(Item).CircuitLength = state.dataIPShortCut->rNumericArgs(8);
     330            0 :         if (state.dataIPShortCut->rNumericArgs(8) <= 0) {
     331            0 :             ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(8), state.dataIPShortCut->rNumericArgs(8)));
     332            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     333            0 :             ShowContinueError(state, "Value must be greater than 0.0");
     334            0 :             ErrorsFound = true;
     335              :         }
     336              : 
     337              :     } // end of input loop
     338              : 
     339              :     // final error check
     340            0 :     if (ErrorsFound) {
     341            0 :         ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
     342              :     }
     343              : 
     344            0 :     if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::Deep]) {
     345            0 :         ShowWarningError(state, "GetPondGroundHeatExchanger:  No \"Site:GroundTemperature:Deep\" were input.");
     346            0 :         ShowContinueError(state,
     347            0 :                           format("Defaults, constant throughout the year of ({:.1R}) will be used.",
     348            0 :                                  state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Deep]));
     349              :     }
     350            0 : }
     351              : 
     352            0 : void PondGroundHeatExchangerData::setupOutputVars(EnergyPlusData &state)
     353              : {
     354            0 :     SetupOutputVariable(state,
     355              :                         "Pond Heat Exchanger Heat Transfer Rate",
     356              :                         Constant::Units::W,
     357            0 :                         this->HeatTransferRate,
     358              :                         OutputProcessor::TimeStepType::System,
     359              :                         OutputProcessor::StoreType::Average,
     360            0 :                         this->Name);
     361            0 :     SetupOutputVariable(state,
     362              :                         "Pond Heat Exchanger Heat Transfer Energy",
     363              :                         Constant::Units::J,
     364            0 :                         this->Energy,
     365              :                         OutputProcessor::TimeStepType::System,
     366              :                         OutputProcessor::StoreType::Sum,
     367            0 :                         this->Name);
     368            0 :     SetupOutputVariable(state,
     369              :                         "Pond Heat Exchanger Mass Flow Rate",
     370              :                         Constant::Units::kg_s,
     371            0 :                         this->MassFlowRate,
     372              :                         OutputProcessor::TimeStepType::System,
     373              :                         OutputProcessor::StoreType::Average,
     374            0 :                         this->Name);
     375            0 :     SetupOutputVariable(state,
     376              :                         "Pond Heat Exchanger Inlet Temperature",
     377              :                         Constant::Units::C,
     378            0 :                         this->InletTemp,
     379              :                         OutputProcessor::TimeStepType::System,
     380              :                         OutputProcessor::StoreType::Average,
     381            0 :                         this->Name);
     382            0 :     SetupOutputVariable(state,
     383              :                         "Pond Heat Exchanger Outlet Temperature",
     384              :                         Constant::Units::C,
     385            0 :                         this->OutletTemp,
     386              :                         OutputProcessor::TimeStepType::System,
     387              :                         OutputProcessor::StoreType::Average,
     388            0 :                         this->Name);
     389            0 :     SetupOutputVariable(state,
     390              :                         "Pond Heat Exchanger Bulk Temperature",
     391              :                         Constant::Units::C,
     392            0 :                         this->PondTemp,
     393              :                         OutputProcessor::TimeStepType::System,
     394              :                         OutputProcessor::StoreType::Average,
     395            0 :                         this->Name);
     396            0 : }
     397              : 
     398            0 : void PondGroundHeatExchangerData::InitPondGroundHeatExchanger(EnergyPlusData &state,
     399              :                                                               bool const FirstHVACIteration // TRUE if 1st HVAC simulation of system timestep
     400              : )
     401              : {
     402              : 
     403              :     // SUBROUTINE INFORMATION:
     404              :     //       AUTHOR         Simon Rees
     405              :     //       DATE WRITTEN   August 2002
     406              :     //       MODIFIED       na
     407              :     //       RE-ENGINEERED  na
     408              : 
     409              :     // PURPOSE OF THIS SUBROUTINE:
     410              :     // This subroutine Resets the elements of the data structure as necessary
     411              :     // at the first HVAC iteration of each time step.
     412              : 
     413              :     // METHODOLOGY EMPLOYED:
     414              :     // One of the things done here is to update the record of the past pond
     415              :     // temperature. This is needed in order to solve the diff. eqn. to find
     416              :     // the temperature at the end of the next time step.
     417              :     // Also set module variables to data structure for this pond. Set flow rate
     418              :     // from node data and hypothetical design flow.
     419              : 
     420              :     // repeated warm up days tend to drive the initial pond temperature toward the drybulb temperature
     421              :     // For each environment start the pond midway between drybulb and ground temp.
     422              : 
     423            0 :     this->oneTimeInit(state);
     424              : 
     425            0 :     if (FirstHVACIteration && !state.dataHVACGlobal->ShortenTimeStepSys && this->firstTimeThrough) {
     426              :         // update past temperature
     427            0 :         this->PastBulkTemperature = this->BulkTemperature;
     428            0 :         this->firstTimeThrough = false;
     429            0 :     } else if (!FirstHVACIteration) {
     430            0 :         this->firstTimeThrough = true;
     431              :     }
     432              : 
     433            0 :     this->InletTemp = state.dataLoopNodes->Node(InletNodeNum).Temp;
     434            0 :     this->PondTemp = this->BulkTemperature;
     435              : 
     436              :     // Hypothetical design flow rate
     437            0 :     Real64 DesignFlow = PlantUtilities::RegulateCondenserCompFlowReqOp(state, this->plantLoc, this->DesignMassFlowRate);
     438              : 
     439            0 :     PlantUtilities::SetComponentFlowRate(state, DesignFlow, this->InletNodeNum, this->OutletNodeNum, this->plantLoc);
     440              : 
     441              :     // get the current flow rate - module variable
     442            0 :     this->MassFlowRate = state.dataLoopNodes->Node(InletNodeNum).MassFlowRate;
     443            0 : }
     444              : 
     445            0 : void PondGroundHeatExchangerData::CalcPondGroundHeatExchanger(EnergyPlusData &state)
     446              : {
     447              : 
     448              :     //       AUTHOR         Simon Rees
     449              :     //       DATE WRITTEN   August 2002
     450              :     //       MODIFIED       na
     451              :     //       RE-ENGINEERED  na
     452              : 
     453              :     // PURPOSE OF THIS SUBROUTINE:
     454              :     // This subroutine does all of the stuff that is necessary to simulate
     455              :     // a pond ground heat exchanger.  Calls are made to appropriate subroutines
     456              :     // either in this module or outside of it.
     457              : 
     458              :     // METHODOLOGY EMPLOYED:
     459              :     // The differential equation defined by the heat balance is solved using
     460              :     // a fourth order Runge-Kutta numerical integration method. The differential
     461              :     // equation is:
     462              :     //            Mdot*Cp*dT/dt = Sum of fluxes.
     463              : 
     464              :     // REFERENCES:
     465              :     // Chiasson, A. Advances in Modeling of Ground-Source Heat Pump Systems.
     466              :     //   M.S. Thesis, Oklahoma State University, December 1999.
     467              :     // Chiasson, A.D., J.D. Spitler, S.J. Rees, M.D. Smith.  2000.  A Model For
     468              :     //   Simulating The Performance Of A Shallow Pond As A Supplemental Heat
     469              :     //   Rejecter With Closed-Loop Ground-Source Heat Pump Systems.
     470              :     //   ASHRAE Transactions.  106(2):107-121.
     471              : 
     472              :     static constexpr std::string_view RoutineName("CalcPondGroundHeatExchanger");
     473              : 
     474            0 :     Real64 PondMass = this->Depth * this->Area * this->water->getDensity(state, max(this->PondTemp, 0.0), RoutineName);
     475            0 :     Real64 SpecificHeat = this->water->getSpecificHeat(state, max(this->PondTemp, 0.0), RoutineName);
     476              : 
     477            0 :     Real64 Flux = this->CalcTotalFLux(state, this->PondTemp);
     478              :     Real64 PondTempStar =
     479            0 :         this->PastBulkTemperature + 0.5 * Constant::rSecsInHour * state.dataHVACGlobal->TimeStepSys * Flux / (SpecificHeat * PondMass);
     480              : 
     481            0 :     Real64 FluxStar = this->CalcTotalFLux(state, PondTempStar);
     482              :     Real64 PondTempStarStar =
     483            0 :         this->PastBulkTemperature + 0.5 * Constant::rSecsInHour * state.dataHVACGlobal->TimeStepSys * FluxStar / (SpecificHeat * PondMass);
     484              : 
     485            0 :     Real64 FluxStarStar = this->CalcTotalFLux(state, PondTempStarStar);
     486              :     Real64 PondTempStarStarStar =
     487            0 :         this->PastBulkTemperature + Constant::rSecsInHour * state.dataHVACGlobal->TimeStepSys * FluxStarStar / (SpecificHeat * PondMass);
     488              : 
     489            0 :     this->PondTemp = this->PastBulkTemperature + Constant::rSecsInHour * state.dataHVACGlobal->TimeStepSys *
     490            0 :                                                      (Flux + 2.0 * FluxStar + 2.0 * FluxStarStar + this->CalcTotalFLux(state, PondTempStarStarStar)) /
     491            0 :                                                      (6.0 * SpecificHeat * PondMass);
     492            0 : }
     493              : 
     494            0 : Real64 PondGroundHeatExchangerData::CalcTotalFLux(EnergyPlusData &state, Real64 const PondBulkTemp // pond temp for this flux calculation
     495              : )
     496              : {
     497              :     //       AUTHOR         Simon Rees
     498              :     //       DATE WRITTEN   August 2002
     499              :     //       MODIFIED       na
     500              :     //       RE-ENGINEERED  na
     501              : 
     502              :     // PURPOSE OF THIS FUNCTION:
     503              :     // This calculates the summation of the heat fluxes on the pond for a
     504              :     // given pond temperature. The following heat fluxes are calculated:
     505              :     //   convection,
     506              :     //   long-wave radiation,
     507              :     //   solar gain,
     508              :     //   evaporation,
     509              :     //   ground conduction,
     510              :     //   along with heat exchange with the fluid
     511              : 
     512              :     // METHODOLOGY EMPLOYED:
     513              :     // Convection is calculated with the ASHRAE simple convection coefficients.
     514              :     // Evaporation is calculated assuming a fixed Lewis number - not as in
     515              :     // Chaisson model. Heat transfer with the fluid is calculated using a heat
     516              :     // exchanger Effectiveness-NTU method, where the pond is seen as a static
     517              :     // fluid - this is also different from Chaisson's original model (assumed
     518              :     // pond at average of inlet and outlet temps).
     519              : 
     520              :     // REFERENCES:
     521              :     // Chiasson, A. Advances in Modeling of Ground-Source Heat Pump Systems.
     522              :     //   M.S. Thesis, Oklahoma State University, December 1999.
     523              :     // Chiasson, A.D., J.D. Spitler, S.J. Rees, M.D. Smith.  2000.  A Model For
     524              :     //   Simulating The Performance Of A Shallow Pond As A Supplemental Heat
     525              :     //   Rejecter With Closed-Loop Ground-Source Heat Pump Systems.
     526              :     //   ASHRAE Transactions.  106(2):107-121.
     527              :     // Hull, J.R., K.V. Liu, W.T. Sha, J. Kamal, and C.E. Nielsen, 1984.
     528              :     //   Dependence of Ground Heat Losses Upon Solar Pond Size and Perimeter
     529              :     //   Insulation Calculated and Experimental Results. Solar Energy,33(1):25-33.
     530              : 
     531              :     Real64 CalcTotalFLux; // function return variable
     532              : 
     533            0 :     Real64 constexpr PrandtlAir(0.71); // Prandtl number for air - assumed constant
     534            0 :     Real64 constexpr SchmidtAir(0.6);  // Schmidt number for air - assumed constant
     535            0 :     Real64 constexpr PondHeight(0.0);  // for now
     536              : 
     537              :     static constexpr std::string_view RoutineName("PondGroundHeatExchanger:CalcTotalFlux");
     538              : 
     539              :     // make a surface heat balance and solve for temperature
     540            0 :     Real64 ThermalAbs = 0.9; // thermal absorptivity
     541              : 
     542              :     // set appropriate external temp
     543              :     // use height dependency --  if there was a height for this unit, it could be inserted.
     544              :     // parameter PondHeight=0.0 is used.
     545            0 :     Real64 OutDryBulb = DataEnvironment::OutDryBulbTempAt(state, PondHeight);
     546            0 :     Real64 OutWetBulb = DataEnvironment::OutWetBulbTempAt(state, PondHeight);
     547              : 
     548              :     Real64 ExternalTemp; // external environmental temp - drybulb or wetbulb
     549            0 :     if (state.dataEnvrn->IsSnow || state.dataEnvrn->IsRain) {
     550            0 :         ExternalTemp = OutWetBulb;
     551              :     } else { // normal dry conditions
     552            0 :         ExternalTemp = OutDryBulb;
     553              :     }
     554              : 
     555              :     // absolute temperatures
     556            0 :     Real64 SurfTempAbs = PondBulkTemp + Constant::Kelvin;            // absolute value of surface temp
     557            0 :     Real64 SkyTempAbs = state.dataEnvrn->SkyTemp + Constant::Kelvin; // absolute value of sky temp
     558              : 
     559              :     // ASHRAE simple convection coefficient model for external surfaces.
     560            0 :     Real64 ConvCoef = Convect::CalcASHRAESimpExtConvCoeff(Material::SurfaceRoughness::VeryRough, DataEnvironment::WindSpeedAt(state, PondHeight));
     561              : 
     562              :     // convective flux
     563            0 :     Real64 FluxConvect = ConvCoef * (PondBulkTemp - ExternalTemp);
     564              : 
     565              :     // long-wave radiation between pond and sky.
     566            0 :     Real64 FluxLongwave = StefBoltzmann * ThermalAbs * (pow_4(SurfTempAbs) - pow_4(SkyTempAbs));
     567              : 
     568              :     // total absorbed solar using function - no ground solar
     569            0 :     Real64 FluxSolAbsorbed = CalcSolarFlux(state);
     570              : 
     571              :     // specific heat from fluid prop routines
     572            0 :     Real64 SpecHeat = this->plantLoc.loop->glycol->getSpecificHeat(state, max(this->InletTemp, 0.0), RoutineName);
     573              :     // heat transfer with fluid - heat exchanger analogy.
     574              : 
     575              :     // convective flux
     576            0 :     Real64 effectiveness = this->CalcEffectiveness(state, this->InletTemp, PondBulkTemp, this->MassFlowRate);
     577            0 :     Real64 Qfluid = this->MassFlowRate * SpecHeat * effectiveness * (this->InletTemp - PondBulkTemp);
     578              : 
     579              :     // evaporation flux
     580              :     // get air properties
     581            0 :     Real64 HumRatioAir = Psychrometrics::PsyWFnTdbTwbPb(state, OutDryBulb, OutWetBulb, state.dataEnvrn->OutBaroPress);
     582              : 
     583              :     // humidity ratio at pond surface/film temperature
     584            0 :     Real64 HumRatioFilm = Psychrometrics::PsyWFnTdbTwbPb(state, PondBulkTemp, PondBulkTemp, state.dataEnvrn->OutBaroPress);
     585            0 :     Real64 SpecHeatAir = Psychrometrics::PsyCpAirFnW(HumRatioAir);
     586            0 :     Real64 LatentHeatAir = Psychrometrics::PsyHfgAirFnWTdb(HumRatioAir, OutDryBulb);
     587              : 
     588              :     // evaporative heat flux
     589            0 :     Real64 FluxEvap = pow_2(PrandtlAir / SchmidtAir) / 3.0 * ConvCoef / SpecHeatAir * (HumRatioFilm - HumRatioAir) * LatentHeatAir;
     590              : 
     591              :     // ground heat transfer flux
     592            0 :     Real64 Perimeter = 4.0 * std::sqrt(this->Area); // pond perimeter -- square assumption
     593              : 
     594              :     // ground heat transfer coefficient
     595            0 :     Real64 UvalueGround = 0.999 * (this->GrndConductivity / this->Depth) + 1.37 * (this->GrndConductivity * Perimeter / this->Area);
     596              : 
     597              :     // ground heat transfer flux
     598            0 :     Real64 FluxGround = UvalueGround * (PondBulkTemp - state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Deep]);
     599              : 
     600            0 :     CalcTotalFLux = Qfluid + this->Area * (FluxSolAbsorbed - FluxConvect - FluxLongwave - FluxEvap - FluxGround);
     601              : 
     602            0 :     return CalcTotalFLux;
     603              : }
     604              : 
     605            0 : Real64 PondGroundHeatExchangerData::CalcSolarFlux(EnergyPlusData &state) const
     606              : {
     607              : 
     608              :     // FUNCTION INFORMATION:
     609              :     //       AUTHOR         Simon Rees
     610              :     //       DATE WRITTEN   August 2002
     611              :     //       MODIFIED       na
     612              :     //       RE-ENGINEERED  na
     613              : 
     614              :     // PURPOSE OF THIS SUBROUTINE:
     615              :     // This is used to calculate the net solar flux absorbed by the pond.
     616              : 
     617              :     // METHODOLOGY EMPLOYED:
     618              :     // This is calculated from basic optical formula using the extinction
     619              :     // coefficient of the pond as the main parameter. This can be in a
     620              :     // wide range: 0.13 - 7.5 in the literature depending on algae, suspended
     621              :     // solids etc. ??
     622              : 
     623              :     // REFERENCES:
     624              :     // Duffie, J.A. and W.A. Beckman, 1991. Solar Engineering of Thermal
     625              :     //  Processes, 2 nd Edition. John Wiley and Sons.
     626              :     // Chiasson, A. Advances in Modeling of Ground-Source Heat Pump Systems.
     627              :     //   M.S. Thesis, Oklahoma State University, December 1999.
     628              :     // Chiasson, A.D., J.D. Spitler, S.J. Rees, M.D. Smith.  2000.  A Model For
     629              :     //   Simulating The Performance Of A Shallow Pond As A Supplemental Heat
     630              :     //   Rejecter With Closed-Loop Ground-Source Heat Pump Systems.
     631              :     //   ASHRAE Transactions.  106(2):107-121.
     632              : 
     633              :     Real64 CalcSolarFlux; // Function return variable
     634              : 
     635            0 :     Real64 constexpr WaterRefIndex(1.33); // refractive index of water
     636            0 :     Real64 constexpr AirRefIndex(1.0003); // refractive index of air
     637            0 :     Real64 constexpr PondExtCoef(0.3);    // extinction coefficient of water
     638              : 
     639              :     // check for sun up.
     640            0 :     if (!state.dataEnvrn->SunIsUp) {
     641            0 :         CalcSolarFlux = 0.0;
     642            0 :         return CalcSolarFlux;
     643              :     }
     644              : 
     645              :     // get the incidence and reflection angles
     646            0 :     Real64 IncidAngle = std::acos(state.dataEnvrn->SOLCOS(3));
     647            0 :     Real64 RefractAngle = std::asin(std::sin(IncidAngle) * AirRefIndex / WaterRefIndex);
     648              : 
     649              :     // absorbed component: Tau_a
     650            0 :     Real64 Absorbtance = std::exp(-PondExtCoef * this->Depth / std::cos(RefractAngle));
     651              : 
     652              :     // parallel and perpendicular components
     653            0 :     Real64 ParallelRad = pow_2(std::tan(RefractAngle - IncidAngle)) / pow_2(std::tan(RefractAngle + IncidAngle));
     654            0 :     Real64 PerpendRad = pow_2(std::sin(RefractAngle - IncidAngle)) / pow_2(std::sin(RefractAngle + IncidAngle));
     655              : 
     656              :     // transmittance: Tau
     657            0 :     Real64 Transmitance = 0.5 * Absorbtance * ((1.0 - ParallelRad) / (1.0 + ParallelRad) + (1.0 - PerpendRad) / (1.0 + PerpendRad));
     658              : 
     659              :     // reflectance: Tau_a - Tau
     660            0 :     Real64 Reflectance = Absorbtance - Transmitance;
     661              : 
     662              :     // apply reflectance to beam and diffuse solar to find flux
     663            0 :     CalcSolarFlux = (1.0 - Reflectance) * (state.dataEnvrn->SOLCOS(3) * state.dataEnvrn->BeamSolarRad + state.dataEnvrn->DifSolarRad);
     664              : 
     665            0 :     return CalcSolarFlux;
     666              : }
     667              : 
     668            0 : Real64 PondGroundHeatExchangerData::CalcEffectiveness(EnergyPlusData &state,
     669              :                                                       Real64 const InsideTemperature, // Temperature of fluid in pipe circuit, in C
     670              :                                                       Real64 const PondTemperature,   // Temperature of pond water (i.e. outside the pipe), in C
     671              :                                                       Real64 const massFlowRate       // Mass flow rate, in kg/s
     672              : )
     673              : {
     674              : 
     675              :     // FUNCTION INFORMATION:
     676              :     //       AUTHOR         Simon Rees
     677              :     //       DATE WRITTEN   August 2002
     678              :     //       MODIFIED       na
     679              :     //       RE-ENGINEERED  na
     680              : 
     681              :     // PURPOSE OF THIS SUBROUTINE:
     682              :     // This subroutine calculates the "heat exchanger" effectiveness.
     683              :     // This routine is adapted from that in the low temp radiant pond model.
     684              : 
     685              :     // METHODOLOGY EMPLOYED:
     686              :     // The heat transfer coefficient is calculated at the pipe and
     687              :     // consists of inside and outside convection coefficients and conduction
     688              :     // through the pipe. The other assumptions are that the tube inside
     689              :     // surface temperature is equal to the "source location temperature"
     690              :     // and that it is a CONSTANT throughout the pond. External convection is
     691              :     // natural mode using Churchill and Chu correlation. Inside convection
     692              :     // calculated using the Dittus-Boelter equation.
     693              : 
     694              :     // REFERENCES:
     695              :     // Incropera, F.P. and D.P. DeWitt, 1996. Introduction to Heat Transfer,
     696              :     //   3 rd Edition. John Wiley & Sons.
     697              :     // Churchill, S.W. and H.H.S. Chu. 1975. Correlating Equations for
     698              :     //   Laminar and Turbulent Free Convection from a Horizontal Cylinder.
     699              :     //   International Journal of Heat and Mass Transfer, 18: 1049-1053.
     700              :     // See also RadiantSystemLowTemp module.
     701              : 
     702              :     Real64 CalcEffectiveness; // Function return variable
     703              : 
     704            0 :     Real64 constexpr MaxLaminarRe(2300.0); // Maximum Reynolds number for laminar flow
     705            0 :     Real64 constexpr GravConst(9.81);      // gravitational constant - should be fixed!
     706              :     static constexpr std::string_view CalledFrom("PondGroundHeatExchanger:CalcEffectiveness");
     707              : 
     708              :     // evaluate properties at pipe fluid temperature for given pipe fluid
     709              : 
     710            0 :     Real64 SpecificHeat = this->plantLoc.loop->glycol->getSpecificHeat(state, InsideTemperature, CalledFrom);
     711            0 :     Real64 Conductivity = this->plantLoc.loop->glycol->getConductivity(state, InsideTemperature, CalledFrom);
     712            0 :     Real64 Viscosity = this->plantLoc.loop->glycol->getViscosity(state, InsideTemperature, CalledFrom);
     713              : 
     714              :     // Calculate the Reynold's number from RE=(4*Mdot)/(Pi*Mu*Diameter)
     715            0 :     Real64 ReynoldsNum = 4.0 * massFlowRate / (Constant::Pi * Viscosity * this->TubeInDiameter * this->NumCircuits);
     716              : 
     717            0 :     Real64 PrantlNum = Viscosity * SpecificHeat / Conductivity;
     718              : 
     719              :     Real64 NusseltNum; // Nusselt number (dimensionless)
     720              : 
     721              :     // Calculate the Nusselt number based on what flow regime one is in. h = (k)(Nu)/D
     722            0 :     if (ReynoldsNum >= MaxLaminarRe) { // Turbulent flow --> use Dittus-Boelter equation
     723            0 :         NusseltNum = 0.023 * std::pow(ReynoldsNum, 0.8) * std::pow(PrantlNum, 0.3);
     724              :     } else { // Laminar flow --> use constant surface temperature relation
     725            0 :         NusseltNum = 3.66;
     726              :     }
     727              : 
     728              :     // inside convection resistance, from Nu
     729            0 :     Real64 ConvCoefIn = Conductivity * NusseltNum / this->TubeInDiameter;
     730              : 
     731              :     // now find properties of pond water - always assume pond fluid is water
     732            0 :     Real64 WaterSpecHeat = this->water->getSpecificHeat(state, max(PondTemperature, 0.0), CalledFrom);
     733            0 :     Real64 WaterConductivity = this->water->getConductivity(state, max(PondTemperature, 0.0), CalledFrom);
     734            0 :     Real64 WaterViscosity = this->water->getViscosity(state, max(PondTemperature, 0.0), CalledFrom);
     735            0 :     Real64 WaterDensity = this->water->getDensity(state, max(PondTemperature, 0.0), CalledFrom);
     736              : 
     737              :     // derived properties for natural convection coefficient
     738              :     // expansion coef (Beta) = -1/Rho. dRho/dT
     739              :     // The following code includes some slight modifications from Simon's original code.
     740              :     // It guarantees that the delta T is 10C and also avoids the problems associated with
     741              :     // water hitting a maximum density at around 4C. (RKS)
     742            0 :     Real64 ExpansionCoef = -(this->water->getDensity(state, max(PondTemperature, 10.0) + 5.0, CalledFrom) -
     743            0 :                              this->water->getDensity(state, max(PondTemperature, 10.0) - 5.0, CalledFrom)) /
     744            0 :                            (10.0 * WaterDensity);
     745              : 
     746            0 :     Real64 ThermDiff = WaterConductivity / (WaterDensity * WaterSpecHeat);
     747            0 :     PrantlNum = WaterViscosity * WaterSpecHeat / WaterConductivity;
     748              : 
     749            0 :     Real64 RayleighNum = WaterDensity * GravConst * ExpansionCoef * std::abs(InsideTemperature - PondTemperature) * pow_3(TubeOutDiameter) /
     750            0 :                          (WaterViscosity * ThermDiff);
     751              : 
     752              :     // Calculate the Nusselt number for natural convection at outside of pipe
     753            0 :     NusseltNum = pow_2(0.6 + (0.387 * std::pow(RayleighNum, 1.0 / 6.0) / (std::pow(1.0 + 0.559 / std::pow(PrantlNum, 9.0 / 16.0), 8.0 / 27.0))));
     754              : 
     755              :     // outside convection resistance, from Nu
     756            0 :     Real64 ConvCoefOut = WaterConductivity * NusseltNum / this->TubeOutDiameter;
     757              : 
     758              :     // conduction resistance of pipe
     759            0 :     Real64 PipeResistance = this->TubeInDiameter / this->TubeConductivity * std::log(this->TubeOutDiameter / this->TubeInDiameter);
     760              : 
     761              :     // total pipe thermal resistance - conduction and convection
     762            0 :     Real64 TotalResistance = PipeResistance + 1.0 / ConvCoefIn + this->TubeInDiameter / (this->TubeOutDiameter * ConvCoefOut);
     763              : 
     764              :     // Calculate the NTU parameter
     765              :     // NTU = UA/[(Mdot*Cp)min] = A/[Rtot*(Mdot*Cp)min]
     766              :     // where: Rtot = Ri,convection + Rconduction + Ro,conveciton
     767              :     //        A = Pi*D*TubeLength
     768              : 
     769              :     Real64 NTU; // Number of transfer units, non-dimensional
     770              : 
     771            0 :     if (massFlowRate == 0.0) {
     772            0 :         CalcEffectiveness = 1.0;
     773              :     } else {
     774            0 :         NTU = Constant::Pi * TubeInDiameter * this->CircuitLength * this->NumCircuits / (TotalResistance * massFlowRate * SpecificHeat);
     775              :         // Calculate effectiveness - formula for static fluid
     776            0 :         CalcEffectiveness = (1.0 - std::exp(-NTU));
     777              :     }
     778              : 
     779              :     // Check for frozen pond
     780            0 :     if (PondTemperature < 0.0) {
     781            0 :         ++this->ConsecutiveFrozen;
     782            0 :         if (this->FrozenErrIndex == 0) {
     783            0 :             ShowWarningMessage(state,
     784            0 :                                format("GroundHeatExchanger:Pond=\"{}\", is frozen; Pond model not valid. Calculated Pond Temperature=[{:.2R}] C",
     785            0 :                                       this->Name,
     786              :                                       PondTemperature));
     787            0 :             ShowContinueErrorTimeStamp(state, "");
     788              :         }
     789            0 :         ShowRecurringWarningErrorAtEnd(state,
     790            0 :                                        "GroundHeatExchanger:Pond=\"" + this->Name + "\", is frozen",
     791            0 :                                        this->FrozenErrIndex,
     792              :                                        PondTemperature,
     793              :                                        PondTemperature,
     794              :                                        _,
     795              :                                        "[C]",
     796              :                                        "[C]");
     797            0 :         if (this->ConsecutiveFrozen >= state.dataGlobal->TimeStepsInHour * 30) {
     798            0 :             ShowFatalError(state,
     799            0 :                            format("GroundHeatExchanger:Pond=\"{}\" has been frozen for 30 consecutive hours.  Program terminates.", this->Name));
     800              :         }
     801              :     } else {
     802            0 :         this->ConsecutiveFrozen = 0;
     803              :     }
     804              : 
     805            0 :     return CalcEffectiveness;
     806              : }
     807              : 
     808            0 : void PondGroundHeatExchangerData::UpdatePondGroundHeatExchanger(EnergyPlusData &state)
     809              : {
     810              : 
     811              :     // SUBROUTINE INFORMATION:
     812              :     //       AUTHOR         Simon Rees
     813              :     //       DATE WRITTEN   August 2002
     814              :     //       MODIFIED       na
     815              :     //       RE-ENGINEERED  na
     816              : 
     817              :     // PURPOSE OF THIS SUBROUTINE:
     818              :     // This subroutine does any updating that needs to be done for pond
     819              :     // ground heat exchangers.   This routine must also set the outlet water
     820              :     // conditions.
     821              : 
     822              :     static constexpr std::string_view RoutineName("PondGroundHeatExchanger:Update");
     823              : 
     824              :     // Calculate the water side outlet conditions and set the
     825              :     // appropriate conditions on the correct HVAC node.
     826            0 :     Real64 CpFluid = this->plantLoc.loop->glycol->getSpecificHeat(state, this->InletTemp, RoutineName);
     827              : 
     828            0 :     PlantUtilities::SafeCopyPlantNode(state, InletNodeNum, OutletNodeNum);
     829              : 
     830              :     // update outlet temp
     831            0 :     if ((CpFluid > 0.0) && (this->MassFlowRate > 0.0)) {
     832            0 :         this->OutletTemp = this->InletTemp - this->HeatTransferRate / (this->MassFlowRate * CpFluid);
     833              :     } else {
     834            0 :         this->OutletTemp = this->InletTemp;
     835              :     }
     836              : 
     837              :     // update node
     838            0 :     state.dataLoopNodes->Node(this->OutletNodeNum).Temp = this->OutletTemp;
     839            0 :     state.dataLoopNodes->Node(this->OutletNodeNum).MassFlowRate = this->MassFlowRate;
     840              : 
     841              :     // update heat transfer rate
     842              :     // compute pond heat transfer
     843            0 :     Real64 effectiveness = this->CalcEffectiveness(state, this->InletTemp, this->PondTemp, this->MassFlowRate);
     844            0 :     this->HeatTransferRate = this->MassFlowRate * CpFluid * effectiveness * (this->InletTemp - this->PondTemp);
     845            0 :     this->Energy = this->HeatTransferRate * state.dataHVACGlobal->TimeStepSysSec;
     846              : 
     847              :     // keep track of the bulk temperature
     848            0 :     this->BulkTemperature = this->PondTemp;
     849            0 : }
     850            0 : void PondGroundHeatExchangerData::oneTimeInit(EnergyPlusData &state)
     851              : {
     852            0 :     Real64 constexpr DesignVelocity(0.5); // Hypothetical design max pipe velocity [m/s]
     853            0 :     Real64 constexpr PondHeight(0.0);     // for now
     854              : 
     855            0 :     static std::string const RoutineName("InitPondGroundHeatExchanger");
     856              : 
     857            0 :     if (this->setupOutputVarsFlag) {
     858            0 :         this->setupOutputVars(state);
     859            0 :         this->setupOutputVarsFlag = false;
     860              :     }
     861              : 
     862            0 :     if (this->OneTimeFlag || state.dataGlobal->WarmupFlag) {
     863              :         // initialize pond temps to mean of drybulb and ground temps.
     864            0 :         this->BulkTemperature = this->PastBulkTemperature =
     865            0 :             0.5 * (DataEnvironment::OutDryBulbTempAt(state, PondHeight) + state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Deep]);
     866            0 :         this->OneTimeFlag = false;
     867              :     }
     868              : 
     869              :     // Init more variables
     870            0 :     if (this->MyFlag) {
     871              :         // Locate the hx on the plant loops for later usage
     872            0 :         bool errFlag = false;
     873            0 :         PlantUtilities::ScanPlantLoopsForObject(
     874            0 :             state, this->Name, DataPlant::PlantEquipmentType::GrndHtExchgPond, this->plantLoc, errFlag, _, _, _, _, _);
     875            0 :         if (errFlag) {
     876            0 :             ShowFatalError(state, "InitPondGroundHeatExchanger: Program terminated due to previous condition(s).");
     877              :         }
     878            0 :         Real64 rho = this->plantLoc.loop->glycol->getDensity(state, 0.0, RoutineName);
     879            0 :         Real64 Cp = this->plantLoc.loop->glycol->getSpecificHeat(state, 0.0, RoutineName);
     880            0 :         this->DesignMassFlowRate = Constant::Pi / 4.0 * pow_2(this->TubeInDiameter) * DesignVelocity * rho * this->NumCircuits;
     881            0 :         this->DesignCapacity = this->DesignMassFlowRate * Cp * 10.0; // assume 10C delta T?
     882            0 :         PlantUtilities::InitComponentNodes(state, 0.0, this->DesignMassFlowRate, this->InletNodeNum, this->OutletNodeNum);
     883            0 :         PlantUtilities::RegisterPlantCompDesignFlow(state, this->InletNodeNum, this->DesignMassFlowRate / rho);
     884              : 
     885            0 :         this->MyFlag = false;
     886              :     }
     887            0 : }
     888              : 
     889              : } // namespace EnergyPlus::PondGroundHeatExchanger
        

Generated by: LCOV version 2.0-1