LCOV - code coverage report
Current view: top level - EnergyPlus - PipeHeatTransfer.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 83.8 % 858 719
Test Date: 2025-06-02 07:23:51 Functions: 94.1 % 17 16

            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              : #include <memory>
      51              : 
      52              : // ObjexxFCL Headers
      53              : #include <ObjexxFCL/Array.functions.hh>
      54              : #include <ObjexxFCL/Array3D.hh>
      55              : #include <ObjexxFCL/Fmath.hh>
      56              : 
      57              : // EnergyPlus Headers
      58              : #include <EnergyPlus/BranchNodeConnections.hh>
      59              : #include <EnergyPlus/Construction.hh>
      60              : #include <EnergyPlus/ConvectionCoefficients.hh>
      61              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      62              : #include <EnergyPlus/DataEnvironment.hh>
      63              : #include <EnergyPlus/DataHVACGlobals.hh>
      64              : #include <EnergyPlus/DataHeatBalance.hh>
      65              : #include <EnergyPlus/DataIPShortCuts.hh>
      66              : #include <EnergyPlus/DataLoopNode.hh>
      67              : #include <EnergyPlus/FluidProperties.hh>
      68              : #include <EnergyPlus/General.hh>
      69              : #include <EnergyPlus/GlobalNames.hh>
      70              : #include <EnergyPlus/GroundTemperatureModeling/GroundTemperatureModelManager.hh>
      71              : #include <EnergyPlus/HeatBalanceInternalHeatGains.hh>
      72              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      73              : #include <EnergyPlus/Material.hh>
      74              : #include <EnergyPlus/NodeInputManager.hh>
      75              : #include <EnergyPlus/OutAirNodeManager.hh>
      76              : #include <EnergyPlus/OutputProcessor.hh>
      77              : #include <EnergyPlus/PipeHeatTransfer.hh>
      78              : #include <EnergyPlus/Plant/DataPlant.hh>
      79              : #include <EnergyPlus/PlantUtilities.hh>
      80              : #include <EnergyPlus/ScheduleManager.hh>
      81              : #include <EnergyPlus/UtilityRoutines.hh>
      82              : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      83              : 
      84              : namespace EnergyPlus::PipeHeatTransfer {
      85              : 
      86              : // Module containing the routines dealing with pipes with transport delay
      87              : // and heat transfer.
      88              : 
      89              : // MODULE INFORMATION:
      90              : //       AUTHOR         Simon Rees
      91              : //       DATE WRITTEN   July 2007
      92              : //       MODIFIED       May 2008
      93              : //       RE-ENGINEERED  na
      94              : 
      95              : // PURPOSE OF THIS MODULE:
      96              : // The purpose of this module is to simulate a pipe with heat transfer
      97              : 
      98              : // METHODOLOGY EMPLOYED:
      99              : // An implicit finite difference method is used to solve the temperature distribution of the
     100              : // fluid in the pipe as a result of the transport delay and heat transfer to the environment.
     101              : // For buried pipes, the simulation involves an implicit finite difference model of the soil,
     102              : // which was originally based on Piechowski's thesis (below).  Equation numbers for
     103              : // pipe:underground calculations are from Piechowski's thesis.  In Piechowski, the near-pipe
     104              : // region is solved with a detailed finite difference grid, this current model makes use of
     105              : // the Hanby model to simulate the actual pipe.
     106              : 
     107              : // Kusuda, T. & Achenbach, P. (1965), 'Earth temperature and thermal diffusivity at
     108              : //     selected stations in the united states', ASHRAE Transactions 71(1), 61-75.
     109              : // Piechowski, M. (1996), A Ground Coupled Heat Pump System with Energy Storage,
     110              : //     PhD thesis, University of Melbourne.
     111              : 
     112              : // OTHER NOTES: Equation Numbers listed in buried pipe routines are from Piechowski's thesis
     113              : 
     114              : enum class PipeIndoorBoundaryType
     115              : {
     116              :     Invalid = -1,
     117              :     Zone,
     118              :     Schedule,
     119              :     Num
     120              : };
     121              : constexpr std::array<std::string_view, static_cast<int>(PipeIndoorBoundaryType::Num)> pipeIndoorBoundaryTypeNamesUC = {"ZONE", "SCHEDULE"};
     122              : 
     123              : // Functions
     124              : 
     125            4 : PlantComponent *PipeHTData::factory(EnergyPlusData &state, DataPlant::PlantEquipmentType objectType, std::string const &objectName)
     126              : {
     127              :     // Process the input data for pipes if it hasn't been done already
     128            4 :     if (state.dataPipeHT->GetPipeInputFlag) {
     129            4 :         GetPipesHeatTransfer(state);
     130            4 :         state.dataPipeHT->GetPipeInputFlag = false;
     131              :     }
     132              :     // Now look for this particular pipe in the list
     133            4 :     auto thisObj = std::find_if(state.dataPipeHT->PipeHT.begin(),
     134            4 :                                 state.dataPipeHT->PipeHT.end(),
     135            4 :                                 [&objectType, &objectName](const PipeHTData &myObj) { return myObj.Type == objectType && myObj.Name == objectName; });
     136            4 :     if (thisObj != state.dataPipeHT->PipeHT.end()) {
     137            4 :         return thisObj;
     138              :     }
     139              :     // If we didn't find it, fatal
     140            0 :     ShowFatalError(state, format("PipeHTFactory: Error getting inputs for pipe named: {}", objectName));
     141              :     // Shut up the compiler
     142            0 :     return nullptr;
     143              : }
     144              : 
     145        58100 : void PipeHTData::simulate(EnergyPlusData &state,
     146              :                           [[maybe_unused]] const PlantLocation &calledFromLocation,
     147              :                           bool const FirstHVACIteration,
     148              :                           [[maybe_unused]] Real64 &CurLoad,
     149              :                           [[maybe_unused]] bool const RunFlag)
     150              : {
     151        58100 :     this->InitPipesHeatTransfer(state, FirstHVACIteration);
     152              :     // make the calculations
     153       802816 :     for (int InnerTimeStepCtr = 1; InnerTimeStepCtr <= state.dataPipeHT->nsvNumInnerTimeSteps; ++InnerTimeStepCtr) {
     154       744716 :         switch (this->EnvironmentPtr) {
     155       186179 :         case EnvrnPtr::GroundEnv: {
     156       186179 :             this->CalcBuriedPipeSoil(state);
     157       186179 :         } break;
     158       558537 :         default: {
     159       558537 :             this->CalcPipesHeatTransfer(state);
     160       558537 :         } break;
     161              :         }
     162       744716 :         this->PushInnerTimeStepArrays();
     163              :     }
     164              :     // update variables
     165        58100 :     this->UpdatePipesHeatTransfer(state);
     166              :     // update report variables
     167        58100 :     this->ReportPipesHeatTransfer(state);
     168        58100 : }
     169              : 
     170       744716 : void PipeHTData::PushInnerTimeStepArrays()
     171              : {
     172       744716 :     if (this->EnvironmentPtr == EnvrnPtr::GroundEnv) {
     173      3723580 :         for (int LengthIndex = 2; LengthIndex <= this->NumSections; ++LengthIndex) {
     174     31836609 :             for (int DepthIndex = 1; DepthIndex <= this->NumDepthNodes; ++DepthIndex) {
     175    113196832 :                 for (int WidthIndex = 2; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
     176              :                     // This will store the old 'current' values as the new 'previous values'  This allows
     177              :                     // us to use the previous time array as history terms in the equations
     178     84897624 :                     this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Previous) =
     179     84897624 :                         this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Current);
     180              :                 }
     181              :             }
     182              :         }
     183              :     }
     184              :     // Then update the Hanby near pipe model temperatures
     185       744716 :     this->PreviousFluidTemp = this->FluidTemp;
     186       744716 :     this->PreviousPipeTemp = this->PipeTemp;
     187       744716 : }
     188              : 
     189            4 : void GetPipesHeatTransfer(EnergyPlusData &state)
     190              : {
     191              : 
     192              :     // SUBROUTINE INFORMATION:
     193              :     //       AUTHOR         Simon Rees
     194              :     //       DATE WRITTEN   July 2007
     195              :     //       MODIFIED       na
     196              :     //       RE-ENGINEERED  na
     197              :     // PURPOSE OF THIS SUBROUTINE:
     198              :     // This subroutine reads the input for hydronic Pipe Heat Transfers
     199              :     // from the user input file.  This will contain all of the information
     200              :     // needed to define and simulate the surface.
     201              : 
     202              :     // Using/Aliasing
     203              :     using BranchNodeConnections::TestCompSet;
     204              : 
     205              :     using NodeInputManager::GetOnlySingleNode;
     206              :     using namespace DataLoopNode;
     207              :     using OutAirNodeManager::CheckOutAirNodeNumber;
     208              : 
     209              :     static constexpr std::string_view routineName = "GetPipeHeatTransfer";
     210              : 
     211              :     // SUBROUTINE PARAMETER DEFINITIONS:
     212            4 :     int constexpr NumPipeSections(20);
     213            4 :     int constexpr NumberOfDepthNodes(8); // Number of nodes in the cartesian grid-Should be an even # for now
     214              : 
     215              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     216            4 :     bool ErrorsFound(false); // Set to true if errors in input,
     217              : 
     218              :     // fatal at end of routine
     219              :     int IOStatus;       // Used in GetObjectItem
     220              :     int NumAlphas;      // Number of Alphas for each GetObjectItem call
     221              :     int NumNumbers;     // Number of Numbers for each GetObjectItem call
     222              :     int NumOfPipeHTInt; // Number of Pipe Heat Transfer objects
     223              :     int NumOfPipeHTExt; // Number of Pipe Heat Transfer objects
     224              :     int NumOfPipeHTUG;  // Number of Pipe Heat Transfer objects
     225              : 
     226            4 :     auto &s_ipsc = state.dataIPShortCut;
     227            4 :     auto &s_mat = state.dataMaterial;
     228              :     // Initializations and allocations
     229            4 :     s_ipsc->cCurrentModuleObject = "Pipe:Indoor";
     230            4 :     NumOfPipeHTInt = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     231            4 :     s_ipsc->cCurrentModuleObject = "Pipe:Outdoor";
     232            4 :     NumOfPipeHTExt = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     233            4 :     s_ipsc->cCurrentModuleObject = "Pipe:Underground";
     234            4 :     NumOfPipeHTUG = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     235              : 
     236            4 :     state.dataPipeHT->nsvNumOfPipeHT = NumOfPipeHTInt + NumOfPipeHTExt + NumOfPipeHTUG;
     237              :     // allocate data structures
     238            4 :     if (allocated(state.dataPipeHT->PipeHT)) {
     239            0 :         state.dataPipeHT->PipeHT.deallocate();
     240              :     }
     241              : 
     242            4 :     state.dataPipeHT->PipeHT.allocate(state.dataPipeHT->nsvNumOfPipeHT);
     243            4 :     state.dataPipeHT->PipeHTUniqueNames.reserve(static_cast<unsigned>(state.dataPipeHT->nsvNumOfPipeHT));
     244            4 :     int Item = 0;
     245              : 
     246            4 :     s_ipsc->cCurrentModuleObject = "Pipe:Indoor";
     247            6 :     for (int PipeItem = 1; PipeItem <= NumOfPipeHTInt; ++PipeItem) {
     248            2 :         ++Item;
     249              :         // get the object name
     250            4 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     251            2 :                                                                  s_ipsc->cCurrentModuleObject,
     252              :                                                                  PipeItem,
     253            2 :                                                                  s_ipsc->cAlphaArgs,
     254              :                                                                  NumAlphas,
     255            2 :                                                                  s_ipsc->rNumericArgs,
     256              :                                                                  NumNumbers,
     257              :                                                                  IOStatus,
     258            2 :                                                                  s_ipsc->lNumericFieldBlanks,
     259            2 :                                                                  s_ipsc->lAlphaFieldBlanks,
     260            2 :                                                                  s_ipsc->cAlphaFieldNames,
     261            2 :                                                                  s_ipsc->cNumericFieldNames);
     262              : 
     263            2 :         GlobalNames::VerifyUniqueInterObjectName(state,
     264            2 :                                                  state.dataPipeHT->PipeHTUniqueNames,
     265            2 :                                                  s_ipsc->cAlphaArgs(1),
     266            2 :                                                  s_ipsc->cCurrentModuleObject,
     267            2 :                                                  s_ipsc->cAlphaFieldNames(1),
     268              :                                                  ErrorsFound);
     269            2 :         state.dataPipeHT->PipeHT(Item).Name = s_ipsc->cAlphaArgs(1);
     270            2 :         state.dataPipeHT->PipeHT(Item).Type = DataPlant::PlantEquipmentType::PipeInterior;
     271              : 
     272              :         // General user input data
     273            2 :         state.dataPipeHT->PipeHT(Item).Construction = s_ipsc->cAlphaArgs(2);
     274            2 :         state.dataPipeHT->PipeHT(Item).ConstructionNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct);
     275              : 
     276            2 :         if (state.dataPipeHT->PipeHT(Item).ConstructionNum == 0) {
     277            0 :             ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
     278            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     279            0 :             ErrorsFound = true;
     280              :         }
     281              : 
     282              :         // get inlet node data
     283            2 :         state.dataPipeHT->PipeHT(Item).InletNode = s_ipsc->cAlphaArgs(3);
     284            4 :         state.dataPipeHT->PipeHT(Item).InletNodeNum = GetOnlySingleNode(state,
     285            2 :                                                                         s_ipsc->cAlphaArgs(3),
     286              :                                                                         ErrorsFound,
     287              :                                                                         DataLoopNode::ConnectionObjectType::PipeIndoor,
     288            2 :                                                                         s_ipsc->cAlphaArgs(1),
     289              :                                                                         DataLoopNode::NodeFluidType::Water,
     290              :                                                                         DataLoopNode::ConnectionType::Inlet,
     291              :                                                                         NodeInputManager::CompFluidStream::Primary,
     292              :                                                                         ObjectIsNotParent);
     293            2 :         if (state.dataPipeHT->PipeHT(Item).InletNodeNum == 0) {
     294            0 :             ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)));
     295            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     296            0 :             ErrorsFound = true;
     297              :         }
     298              : 
     299              :         // get outlet node data
     300            2 :         state.dataPipeHT->PipeHT(Item).OutletNode = s_ipsc->cAlphaArgs(4);
     301            4 :         state.dataPipeHT->PipeHT(Item).OutletNodeNum = GetOnlySingleNode(state,
     302            2 :                                                                          s_ipsc->cAlphaArgs(4),
     303              :                                                                          ErrorsFound,
     304              :                                                                          DataLoopNode::ConnectionObjectType::PipeIndoor,
     305            2 :                                                                          s_ipsc->cAlphaArgs(1),
     306              :                                                                          DataLoopNode::NodeFluidType::Water,
     307              :                                                                          DataLoopNode::ConnectionType::Outlet,
     308              :                                                                          NodeInputManager::CompFluidStream::Primary,
     309              :                                                                          ObjectIsNotParent);
     310            2 :         if (state.dataPipeHT->PipeHT(Item).OutletNodeNum == 0) {
     311            0 :             ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4)));
     312            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     313            0 :             ErrorsFound = true;
     314              :         }
     315              : 
     316            2 :         TestCompSet(state, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(3), s_ipsc->cAlphaArgs(4), "Pipe Nodes");
     317              : 
     318              :         // get environmental boundary condition type
     319              : 
     320            2 :         if (s_ipsc->lAlphaFieldBlanks(5)) {
     321            0 :             s_ipsc->cAlphaArgs(5) = "ZONE";
     322              :         }
     323              : 
     324            2 :         PipeIndoorBoundaryType indoorType = static_cast<PipeIndoorBoundaryType>(getEnumValue(pipeIndoorBoundaryTypeNamesUC, s_ipsc->cAlphaArgs(5)));
     325            2 :         switch (indoorType) {
     326            1 :         case PipeIndoorBoundaryType::Zone:
     327            1 :             state.dataPipeHT->PipeHT(Item).EnvironmentPtr = EnvrnPtr::ZoneEnv;
     328            1 :             state.dataPipeHT->PipeHT(Item).EnvrZonePtr = Util::FindItemInList(s_ipsc->cAlphaArgs(6), state.dataHeatBal->Zone);
     329            1 :             if (state.dataPipeHT->PipeHT(Item).EnvrZonePtr == 0) {
     330            0 :                 ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6)));
     331            0 :                 ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     332            0 :                 ErrorsFound = true;
     333              :             }
     334            1 :             break;
     335              : 
     336            1 :         case PipeIndoorBoundaryType::Schedule:
     337            1 :             state.dataPipeHT->PipeHT(Item).EnvironmentPtr = EnvrnPtr::ScheduleEnv;
     338              : 
     339            1 :             state.dataPipeHT->PipeHT(Item).envrSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(7));
     340            1 :             state.dataPipeHT->PipeHT(Item).envrVelSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(8));
     341            1 :             if (state.dataPipeHT->PipeHT(Item).envrSched == nullptr) {
     342            0 :                 ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7)));
     343            0 :                 ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     344            0 :                 ErrorsFound = true;
     345              :             }
     346            1 :             if (state.dataPipeHT->PipeHT(Item).envrVelSched == nullptr) {
     347            0 :                 ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(8), s_ipsc->cAlphaArgs(8)));
     348            0 :                 ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     349            0 :                 ErrorsFound = true;
     350              :             }
     351            1 :             break;
     352              : 
     353            0 :         default:
     354            0 :             ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5)));
     355            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     356            0 :             ShowContinueError(state, R"(Should be "ZONE" or "SCHEDULE")"); // TODO rename point
     357            0 :             ErrorsFound = true;
     358              :         }
     359              : 
     360              :         // dimensions
     361            2 :         state.dataPipeHT->PipeHT(Item).PipeID = s_ipsc->rNumericArgs(1);
     362            2 :         if (s_ipsc->rNumericArgs(1) <= 0.0) { // not really necessary because idd field has "minimum> 0"
     363            0 :             ShowSevereError(state, format("GetPipesHeatTransfer: invalid {} of {:.4R}", s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1)));
     364            0 :             ShowContinueError(state, format("{} must be > 0.0", s_ipsc->cNumericFieldNames(1)));
     365            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     366              : 
     367            0 :             ErrorsFound = true;
     368              :         }
     369              : 
     370            2 :         state.dataPipeHT->PipeHT(Item).Length = s_ipsc->rNumericArgs(2);
     371            2 :         if (s_ipsc->rNumericArgs(2) <= 0.0) { // not really necessary because idd field has "minimum> 0"
     372            0 :             ShowSevereError(state, format("GetPipesHeatTransfer: invalid {} of {:.4R}", s_ipsc->cNumericFieldNames(2), s_ipsc->rNumericArgs(2)));
     373            0 :             ShowContinueError(state, format("{} must be > 0.0", s_ipsc->cNumericFieldNames(2)));
     374            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     375            0 :             ErrorsFound = true;
     376              :         }
     377              : 
     378            2 :         if (state.dataPipeHT->PipeHT(Item).ConstructionNum != 0) {
     379            2 :             state.dataPipeHT->PipeHT(Item).ValidatePipeConstruction(state,
     380            2 :                                                                     s_ipsc->cCurrentModuleObject,
     381            2 :                                                                     s_ipsc->cAlphaArgs(2),
     382            2 :                                                                     s_ipsc->cAlphaFieldNames(2),
     383            2 :                                                                     state.dataPipeHT->PipeHT(Item).ConstructionNum,
     384              :                                                                     ErrorsFound);
     385              :         }
     386              : 
     387              :     } // end of input loop
     388              : 
     389            4 :     s_ipsc->cCurrentModuleObject = "Pipe:Outdoor";
     390            5 :     for (int PipeItem = 1; PipeItem <= NumOfPipeHTExt; ++PipeItem) {
     391            1 :         ++Item;
     392              :         // get the object name
     393            2 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     394            1 :                                                                  s_ipsc->cCurrentModuleObject,
     395              :                                                                  PipeItem,
     396            1 :                                                                  s_ipsc->cAlphaArgs,
     397              :                                                                  NumAlphas,
     398            1 :                                                                  s_ipsc->rNumericArgs,
     399              :                                                                  NumNumbers,
     400              :                                                                  IOStatus,
     401            1 :                                                                  s_ipsc->lNumericFieldBlanks,
     402            1 :                                                                  s_ipsc->lAlphaFieldBlanks,
     403            1 :                                                                  s_ipsc->cAlphaFieldNames,
     404            1 :                                                                  s_ipsc->cNumericFieldNames);
     405              : 
     406            1 :         GlobalNames::VerifyUniqueInterObjectName(state,
     407            1 :                                                  state.dataPipeHT->PipeHTUniqueNames,
     408            1 :                                                  s_ipsc->cAlphaArgs(1),
     409            1 :                                                  s_ipsc->cCurrentModuleObject,
     410            1 :                                                  s_ipsc->cAlphaFieldNames(1),
     411              :                                                  ErrorsFound);
     412            1 :         state.dataPipeHT->PipeHT(Item).Name = s_ipsc->cAlphaArgs(1);
     413            1 :         state.dataPipeHT->PipeHT(Item).Type = DataPlant::PlantEquipmentType::PipeExterior;
     414              : 
     415              :         // General user input data
     416            1 :         state.dataPipeHT->PipeHT(Item).Construction = s_ipsc->cAlphaArgs(2);
     417            1 :         state.dataPipeHT->PipeHT(Item).ConstructionNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct);
     418              : 
     419            1 :         if (state.dataPipeHT->PipeHT(Item).ConstructionNum == 0) {
     420            0 :             ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
     421            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     422            0 :             ErrorsFound = true;
     423              :         }
     424              : 
     425              :         // get inlet node data
     426            1 :         state.dataPipeHT->PipeHT(Item).InletNode = s_ipsc->cAlphaArgs(3);
     427            2 :         state.dataPipeHT->PipeHT(Item).InletNodeNum = GetOnlySingleNode(state,
     428            1 :                                                                         s_ipsc->cAlphaArgs(3),
     429              :                                                                         ErrorsFound,
     430              :                                                                         DataLoopNode::ConnectionObjectType::PipeOutdoor,
     431            1 :                                                                         s_ipsc->cAlphaArgs(1),
     432              :                                                                         DataLoopNode::NodeFluidType::Water,
     433              :                                                                         DataLoopNode::ConnectionType::Inlet,
     434              :                                                                         NodeInputManager::CompFluidStream::Primary,
     435              :                                                                         ObjectIsNotParent);
     436            1 :         if (state.dataPipeHT->PipeHT(Item).InletNodeNum == 0) {
     437            0 :             ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)));
     438            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     439            0 :             ErrorsFound = true;
     440              :         }
     441              : 
     442              :         // get outlet node data
     443            1 :         state.dataPipeHT->PipeHT(Item).OutletNode = s_ipsc->cAlphaArgs(4);
     444            2 :         state.dataPipeHT->PipeHT(Item).OutletNodeNum = GetOnlySingleNode(state,
     445            1 :                                                                          s_ipsc->cAlphaArgs(4),
     446              :                                                                          ErrorsFound,
     447              :                                                                          DataLoopNode::ConnectionObjectType::PipeOutdoor,
     448            1 :                                                                          s_ipsc->cAlphaArgs(1),
     449              :                                                                          DataLoopNode::NodeFluidType::Water,
     450              :                                                                          DataLoopNode::ConnectionType::Outlet,
     451              :                                                                          NodeInputManager::CompFluidStream::Primary,
     452              :                                                                          ObjectIsNotParent);
     453            1 :         if (state.dataPipeHT->PipeHT(Item).OutletNodeNum == 0) {
     454            0 :             ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4)));
     455            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     456            0 :             ErrorsFound = true;
     457              :         }
     458              : 
     459            1 :         TestCompSet(state, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(3), s_ipsc->cAlphaArgs(4), "Pipe Nodes");
     460              : 
     461              :         // get environmental boundary condition type
     462              :         //    PipeHT(Item)%Environment = 'OutdoorAir'
     463            1 :         state.dataPipeHT->PipeHT(Item).EnvironmentPtr = EnvrnPtr::OutsideAirEnv;
     464              : 
     465            1 :         state.dataPipeHT->PipeHT(Item).EnvrAirNode = s_ipsc->cAlphaArgs(5);
     466            2 :         state.dataPipeHT->PipeHT(Item).EnvrAirNodeNum = GetOnlySingleNode(state,
     467            1 :                                                                           s_ipsc->cAlphaArgs(5),
     468              :                                                                           ErrorsFound,
     469              :                                                                           DataLoopNode::ConnectionObjectType::PipeOutdoor,
     470            1 :                                                                           s_ipsc->cAlphaArgs(1),
     471              :                                                                           DataLoopNode::NodeFluidType::Air,
     472              :                                                                           DataLoopNode::ConnectionType::OutsideAirReference,
     473              :                                                                           NodeInputManager::CompFluidStream::Primary,
     474              :                                                                           ObjectIsNotParent);
     475            1 :         if (!s_ipsc->lAlphaFieldBlanks(5)) {
     476            1 :             if (!CheckOutAirNodeNumber(state, state.dataPipeHT->PipeHT(Item).EnvrAirNodeNum)) {
     477            0 :                 ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5)));
     478            0 :                 ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     479            0 :                 ShowContinueError(state, "Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node");
     480            0 :                 ErrorsFound = true;
     481              :             }
     482              :         } else {
     483            0 :             ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5)));
     484            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     485            0 :             ShowContinueError(state, format("An {} must be used ", s_ipsc->cAlphaFieldNames(5)));
     486            0 :             ErrorsFound = true;
     487              :         }
     488              : 
     489              :         // dimensions
     490            1 :         state.dataPipeHT->PipeHT(Item).PipeID = s_ipsc->rNumericArgs(1);
     491            1 :         if (s_ipsc->rNumericArgs(1) <= 0.0) { // not really necessary because idd field has "minimum> 0"
     492            0 :             ShowSevereError(state, format("Invalid {} of {:.4R}", s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1)));
     493            0 :             ShowContinueError(state, format("{} must be > 0.0", s_ipsc->cNumericFieldNames(1)));
     494            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     495            0 :             ErrorsFound = true;
     496              :         }
     497              : 
     498            1 :         state.dataPipeHT->PipeHT(Item).Length = s_ipsc->rNumericArgs(2);
     499            1 :         if (s_ipsc->rNumericArgs(2) <= 0.0) { // not really necessary because idd field has "minimum> 0"
     500            0 :             ShowSevereError(state, format("Invalid {} of {:.4R}", s_ipsc->cNumericFieldNames(2), s_ipsc->rNumericArgs(2)));
     501            0 :             ShowContinueError(state, format("{} must be > 0.0", s_ipsc->cNumericFieldNames(2)));
     502            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     503            0 :             ErrorsFound = true;
     504              :         }
     505              : 
     506            1 :         if (state.dataPipeHT->PipeHT(Item).ConstructionNum != 0) {
     507            1 :             state.dataPipeHT->PipeHT(Item).ValidatePipeConstruction(state,
     508            1 :                                                                     s_ipsc->cCurrentModuleObject,
     509            1 :                                                                     s_ipsc->cAlphaArgs(2),
     510            1 :                                                                     s_ipsc->cAlphaFieldNames(2),
     511            1 :                                                                     state.dataPipeHT->PipeHT(Item).ConstructionNum,
     512              :                                                                     ErrorsFound);
     513              :         }
     514              : 
     515              :     } // end of input loop
     516              : 
     517            4 :     s_ipsc->cCurrentModuleObject = "Pipe:Underground";
     518            5 :     for (int PipeItem = 1; PipeItem <= NumOfPipeHTUG; ++PipeItem) {
     519            1 :         ++Item;
     520              :         // get the object name
     521            2 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     522            1 :                                                                  s_ipsc->cCurrentModuleObject,
     523              :                                                                  PipeItem,
     524            1 :                                                                  s_ipsc->cAlphaArgs,
     525              :                                                                  NumAlphas,
     526            1 :                                                                  s_ipsc->rNumericArgs,
     527              :                                                                  NumNumbers,
     528              :                                                                  IOStatus,
     529            1 :                                                                  s_ipsc->lNumericFieldBlanks,
     530            1 :                                                                  s_ipsc->lAlphaFieldBlanks,
     531            1 :                                                                  s_ipsc->cAlphaFieldNames,
     532            1 :                                                                  s_ipsc->cNumericFieldNames);
     533              : 
     534            1 :         ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
     535              : 
     536            1 :         GlobalNames::VerifyUniqueInterObjectName(state,
     537            1 :                                                  state.dataPipeHT->PipeHTUniqueNames,
     538            1 :                                                  s_ipsc->cAlphaArgs(1),
     539            1 :                                                  s_ipsc->cCurrentModuleObject,
     540            1 :                                                  s_ipsc->cAlphaFieldNames(1),
     541              :                                                  ErrorsFound);
     542            1 :         state.dataPipeHT->PipeHT(Item).Name = s_ipsc->cAlphaArgs(1);
     543            1 :         state.dataPipeHT->PipeHT(Item).Type = DataPlant::PlantEquipmentType::PipeUnderground;
     544              : 
     545              :         // General user input data
     546            1 :         state.dataPipeHT->PipeHT(Item).Construction = s_ipsc->cAlphaArgs(2);
     547            1 :         state.dataPipeHT->PipeHT(Item).ConstructionNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct);
     548              : 
     549            1 :         if (state.dataPipeHT->PipeHT(Item).ConstructionNum == 0) {
     550            0 :             ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
     551            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     552            0 :             ErrorsFound = true;
     553              :         }
     554              : 
     555              :         // get inlet node data
     556            1 :         state.dataPipeHT->PipeHT(Item).InletNode = s_ipsc->cAlphaArgs(3);
     557            2 :         state.dataPipeHT->PipeHT(Item).InletNodeNum = GetOnlySingleNode(state,
     558            1 :                                                                         s_ipsc->cAlphaArgs(3),
     559              :                                                                         ErrorsFound,
     560              :                                                                         DataLoopNode::ConnectionObjectType::PipeUnderground,
     561            1 :                                                                         s_ipsc->cAlphaArgs(1),
     562              :                                                                         DataLoopNode::NodeFluidType::Water,
     563              :                                                                         DataLoopNode::ConnectionType::Inlet,
     564              :                                                                         NodeInputManager::CompFluidStream::Primary,
     565              :                                                                         ObjectIsNotParent);
     566            1 :         if (state.dataPipeHT->PipeHT(Item).InletNodeNum == 0) {
     567            0 :             ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)));
     568            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     569            0 :             ErrorsFound = true;
     570              :         }
     571              : 
     572              :         // get outlet node data
     573            1 :         state.dataPipeHT->PipeHT(Item).OutletNode = s_ipsc->cAlphaArgs(4);
     574            2 :         state.dataPipeHT->PipeHT(Item).OutletNodeNum = GetOnlySingleNode(state,
     575            1 :                                                                          s_ipsc->cAlphaArgs(4),
     576              :                                                                          ErrorsFound,
     577              :                                                                          DataLoopNode::ConnectionObjectType::PipeUnderground,
     578            1 :                                                                          s_ipsc->cAlphaArgs(1),
     579              :                                                                          DataLoopNode::NodeFluidType::Water,
     580              :                                                                          DataLoopNode::ConnectionType::Outlet,
     581              :                                                                          NodeInputManager::CompFluidStream::Primary,
     582              :                                                                          ObjectIsNotParent);
     583            1 :         if (state.dataPipeHT->PipeHT(Item).OutletNodeNum == 0) {
     584            0 :             ShowSevereError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4)));
     585            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     586            0 :             ErrorsFound = true;
     587              :         }
     588              : 
     589            1 :         TestCompSet(state, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(3), s_ipsc->cAlphaArgs(4), "Pipe Nodes");
     590              : 
     591            1 :         state.dataPipeHT->PipeHT(Item).EnvironmentPtr = EnvrnPtr::GroundEnv;
     592              : 
     593              :         // Solar inclusion flag
     594              :         // A6,  \field Sun Exposure
     595            1 :         if (Util::SameString(s_ipsc->cAlphaArgs(5), "SUNEXPOSED")) {
     596            1 :             state.dataPipeHT->PipeHT(Item).SolarExposed = true;
     597            0 :         } else if (Util::SameString(s_ipsc->cAlphaArgs(5), "NOSUN")) {
     598            0 :             state.dataPipeHT->PipeHT(Item).SolarExposed = false;
     599              :         } else {
     600            0 :             ShowSevereError(state, format("GetPipesHeatTransfer: invalid key for sun exposure flag for {}", s_ipsc->cAlphaArgs(1)));
     601            0 :             ShowContinueError(state, format("Key should be either SunExposed or NoSun.  Entered Key: {}", s_ipsc->cAlphaArgs(5)));
     602            0 :             ErrorsFound = true;
     603              :         }
     604              : 
     605              :         // dimensions
     606            1 :         state.dataPipeHT->PipeHT(Item).PipeID = s_ipsc->rNumericArgs(1);
     607            1 :         if (s_ipsc->rNumericArgs(1) <= 0.0) { // not really necessary because idd field has "minimum> 0"
     608            0 :             ShowSevereError(state, format("Invalid {} of {:.4R}", s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1)));
     609            0 :             ShowContinueError(state, format("{} must be > 0.0", s_ipsc->cNumericFieldNames(1)));
     610            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     611            0 :             ErrorsFound = true;
     612              :         }
     613              : 
     614            1 :         state.dataPipeHT->PipeHT(Item).Length = s_ipsc->rNumericArgs(2);
     615            1 :         if (s_ipsc->rNumericArgs(2) <= 0.0) { // not really necessary because idd field has "minimum> 0"
     616            0 :             ShowSevereError(state, format("Invalid {} of {:.4R}", s_ipsc->cNumericFieldNames(2), s_ipsc->rNumericArgs(2)));
     617            0 :             ShowContinueError(state, format("{} must be > 0.0", s_ipsc->cNumericFieldNames(2)));
     618            0 :             ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     619            0 :             ErrorsFound = true;
     620              :         }
     621              : 
     622              :         // Also get the soil material name
     623              :         // A7,  \field Soil Material
     624            1 :         state.dataPipeHT->PipeHT(Item).SoilMaterial = s_ipsc->cAlphaArgs(6);
     625            1 :         state.dataPipeHT->PipeHT(Item).SoilMaterialNum = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(6));
     626            1 :         if (state.dataPipeHT->PipeHT(Item).SoilMaterialNum == 0) {
     627            0 :             ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
     628            0 :             ErrorsFound = true;
     629              :         } else {
     630            1 :             auto const *matSoil = s_mat->materials(state.dataPipeHT->PipeHT(Item).SoilMaterialNum);
     631              : 
     632            1 :             state.dataPipeHT->PipeHT(Item).SoilDensity = matSoil->Density;
     633            1 :             state.dataPipeHT->PipeHT(Item).SoilDepth = matSoil->Thickness;
     634            1 :             state.dataPipeHT->PipeHT(Item).SoilCp = matSoil->SpecHeat;
     635            1 :             state.dataPipeHT->PipeHT(Item).SoilConductivity = matSoil->Conductivity;
     636            1 :             state.dataPipeHT->PipeHT(Item).SoilThermAbs = matSoil->AbsorpThermal;
     637            1 :             state.dataPipeHT->PipeHT(Item).SoilSolarAbs = matSoil->AbsorpSolar;
     638            1 :             state.dataPipeHT->PipeHT(Item).SoilRoughness = matSoil->Roughness;
     639            1 :             state.dataPipeHT->PipeHT(Item).PipeDepth = state.dataPipeHT->PipeHT(Item).SoilDepth + state.dataPipeHT->PipeHT(Item).PipeID / 2.0;
     640            1 :             state.dataPipeHT->PipeHT(Item).DomainDepth = state.dataPipeHT->PipeHT(Item).PipeDepth * 2.0;
     641            2 :             state.dataPipeHT->PipeHT(Item).SoilDiffusivity = state.dataPipeHT->PipeHT(Item).SoilConductivity /
     642            1 :                                                              (state.dataPipeHT->PipeHT(Item).SoilDensity * state.dataPipeHT->PipeHT(Item).SoilCp);
     643            1 :             state.dataPipeHT->PipeHT(Item).SoilDiffusivityPerDay = state.dataPipeHT->PipeHT(Item).SoilDiffusivity * Constant::rSecsInDay;
     644              : 
     645              :             // Mesh the cartesian domain
     646            1 :             state.dataPipeHT->PipeHT(Item).NumDepthNodes = NumberOfDepthNodes;
     647            1 :             state.dataPipeHT->PipeHT(Item).PipeNodeDepth = state.dataPipeHT->PipeHT(Item).NumDepthNodes / 2;
     648            1 :             state.dataPipeHT->PipeHT(Item).PipeNodeWidth = state.dataPipeHT->PipeHT(Item).NumDepthNodes / 2;
     649            1 :             state.dataPipeHT->PipeHT(Item).DomainDepth = state.dataPipeHT->PipeHT(Item).PipeDepth * 2.0;
     650            1 :             state.dataPipeHT->PipeHT(Item).dSregular =
     651            1 :                 state.dataPipeHT->PipeHT(Item).DomainDepth / (state.dataPipeHT->PipeHT(Item).NumDepthNodes - 1);
     652              :         }
     653              : 
     654            1 :         if (state.dataPipeHT->PipeHT(Item).ConstructionNum != 0) {
     655            1 :             state.dataPipeHT->PipeHT(Item).ValidatePipeConstruction(state,
     656            1 :                                                                     s_ipsc->cCurrentModuleObject,
     657            1 :                                                                     s_ipsc->cAlphaArgs(2),
     658            1 :                                                                     s_ipsc->cAlphaFieldNames(2),
     659            1 :                                                                     state.dataPipeHT->PipeHT(Item).ConstructionNum,
     660              :                                                                     ErrorsFound);
     661              :         }
     662              : 
     663              :         // Get ground temperature model
     664            1 :         GroundTemp::ModelType gtmType = static_cast<GroundTemp::ModelType>(getEnumValue(GroundTemp::modelTypeNamesUC, s_ipsc->cAlphaArgs(7)));
     665            1 :         if (gtmType == GroundTemp::ModelType::Invalid) {
     666            0 :             ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7));
     667            0 :             ErrorsFound = true;
     668              :         }
     669              : 
     670            1 :         state.dataPipeHT->PipeHT(Item).groundTempModel = GroundTemp::GetGroundTempModelAndInit(state, gtmType, s_ipsc->cAlphaArgs(8));
     671              : 
     672              :         // Select number of pipe sections.  Hanby's optimal number of 20 section is selected.
     673            1 :         state.dataPipeHT->PipeHT(Item).NumSections = NumPipeSections;
     674              : 
     675              :         // For buried pipes, we need to allocate the cartesian finite difference array
     676            2 :         state.dataPipeHT->PipeHT(Item).T.allocate(state.dataPipeHT->PipeHT(Item).PipeNodeWidth,
     677            1 :                                                   state.dataPipeHT->PipeHT(Item).NumDepthNodes,
     678            1 :                                                   state.dataPipeHT->PipeHT(Item).NumSections,
     679              :                                                   TimeIndex::Tentative);
     680            1 :         state.dataPipeHT->PipeHT(Item).T = 0.0;
     681              : 
     682              :     } // PipeUG input loop
     683              : 
     684            8 :     for (Item = 1; Item <= state.dataPipeHT->nsvNumOfPipeHT; ++Item) {
     685              :         // Select number of pipe sections.  Hanby's optimal number of 20 section is selected.
     686            4 :         int NumSections = NumPipeSections;
     687            4 :         state.dataPipeHT->PipeHT(Item).NumSections = NumPipeSections;
     688              : 
     689              :         // We need to allocate the Hanby model arrays for all pipes, including buried
     690            4 :         state.dataPipeHT->PipeHT(Item).TentativeFluidTemp.allocate({0, NumSections});
     691            4 :         state.dataPipeHT->PipeHT(Item).TentativePipeTemp.allocate({0, NumSections});
     692            4 :         state.dataPipeHT->PipeHT(Item).FluidTemp.allocate({0, NumSections});
     693            4 :         state.dataPipeHT->PipeHT(Item).PreviousFluidTemp.allocate({0, NumSections});
     694            4 :         state.dataPipeHT->PipeHT(Item).PipeTemp.allocate({0, NumSections});
     695            4 :         state.dataPipeHT->PipeHT(Item).PreviousPipeTemp.allocate({0, NumSections});
     696              : 
     697            4 :         state.dataPipeHT->PipeHT(Item).TentativeFluidTemp = 0.0;
     698            4 :         state.dataPipeHT->PipeHT(Item).FluidTemp = 0.0;
     699            4 :         state.dataPipeHT->PipeHT(Item).PreviousFluidTemp = 0.0;
     700            4 :         state.dataPipeHT->PipeHT(Item).TentativePipeTemp = 0.0;
     701            4 :         state.dataPipeHT->PipeHT(Item).PipeTemp = 0.0;
     702            4 :         state.dataPipeHT->PipeHT(Item).PreviousPipeTemp = 0.0;
     703              : 
     704              :         // work out heat transfer areas (area per section)
     705            4 :         state.dataPipeHT->PipeHT(Item).InsideArea =
     706            4 :             Constant::Pi * state.dataPipeHT->PipeHT(Item).PipeID * state.dataPipeHT->PipeHT(Item).Length / NumSections;
     707            4 :         state.dataPipeHT->PipeHT(Item).OutsideArea =
     708            4 :             Constant::Pi * (state.dataPipeHT->PipeHT(Item).PipeOD + 2 * state.dataPipeHT->PipeHT(Item).InsulationThickness) *
     709            4 :             state.dataPipeHT->PipeHT(Item).Length / NumSections;
     710              : 
     711              :         // cross sectional area
     712            4 :         state.dataPipeHT->PipeHT(Item).SectionArea = Constant::Pi * 0.25 * pow_2(state.dataPipeHT->PipeHT(Item).PipeID);
     713              : 
     714              :         // pipe & insulation mass
     715            4 :         state.dataPipeHT->PipeHT(Item).PipeHeatCapacity =
     716            4 :             state.dataPipeHT->PipeHT(Item).PipeCp * state.dataPipeHT->PipeHT(Item).PipeDensity *
     717            4 :             (Constant::Pi * 0.25 * pow_2(state.dataPipeHT->PipeHT(Item).PipeOD) - state.dataPipeHT->PipeHT(Item).SectionArea); // the metal component
     718              :     }
     719              : 
     720              :     // final error check
     721            4 :     if (ErrorsFound) {
     722            0 :         ShowFatalError(state, "GetPipesHeatTransfer: Errors found in input. Preceding conditions cause termination.");
     723              :     }
     724              : 
     725              :     // Set up the output variables CurrentModuleObject='Pipe:Indoor/Outdoor/Underground'
     726            8 :     for (Item = 1; Item <= state.dataPipeHT->nsvNumOfPipeHT; ++Item) {
     727              : 
     728            8 :         SetupOutputVariable(state,
     729              :                             "Pipe Fluid Heat Transfer Rate",
     730              :                             Constant::Units::W,
     731            4 :                             state.dataPipeHT->PipeHT(Item).FluidHeatLossRate,
     732              :                             OutputProcessor::TimeStepType::System,
     733              :                             OutputProcessor::StoreType::Average,
     734            4 :                             state.dataPipeHT->PipeHT(Item).Name);
     735            8 :         SetupOutputVariable(state,
     736              :                             "Pipe Fluid Heat Transfer Energy",
     737              :                             Constant::Units::J,
     738            4 :                             state.dataPipeHT->PipeHT(Item).FluidHeatLossEnergy,
     739              :                             OutputProcessor::TimeStepType::System,
     740              :                             OutputProcessor::StoreType::Sum,
     741            4 :                             state.dataPipeHT->PipeHT(Item).Name);
     742              : 
     743            4 :         if (state.dataPipeHT->PipeHT(Item).EnvironmentPtr == EnvrnPtr::ZoneEnv) {
     744            2 :             SetupOutputVariable(state,
     745              :                                 "Pipe Ambient Heat Transfer Rate",
     746              :                                 Constant::Units::W,
     747            1 :                                 state.dataPipeHT->PipeHT(Item).EnvironmentHeatLossRate,
     748              :                                 OutputProcessor::TimeStepType::System,
     749              :                                 OutputProcessor::StoreType::Average,
     750            1 :                                 state.dataPipeHT->PipeHT(Item).Name);
     751            2 :             SetupOutputVariable(state,
     752              :                                 "Pipe Ambient Heat Transfer Energy",
     753              :                                 Constant::Units::J,
     754            1 :                                 state.dataPipeHT->PipeHT(Item).EnvHeatLossEnergy,
     755              :                                 OutputProcessor::TimeStepType::System,
     756              :                                 OutputProcessor::StoreType::Sum,
     757            1 :                                 state.dataPipeHT->PipeHT(Item).Name);
     758              : 
     759            3 :             SetupZoneInternalGain(state,
     760            1 :                                   state.dataPipeHT->PipeHT(Item).EnvrZonePtr,
     761            1 :                                   state.dataPipeHT->PipeHT(Item).Name,
     762              :                                   DataHeatBalance::IntGainType::PipeIndoor,
     763            1 :                                   &state.dataPipeHT->PipeHT(Item).ZoneHeatGainRate);
     764              :         }
     765              : 
     766            8 :         SetupOutputVariable(state,
     767              :                             "Pipe Mass Flow Rate",
     768              :                             Constant::Units::kg_s,
     769            4 :                             state.dataPipeHT->PipeHT(Item).MassFlowRate,
     770              :                             OutputProcessor::TimeStepType::System,
     771              :                             OutputProcessor::StoreType::Average,
     772            4 :                             state.dataPipeHT->PipeHT(Item).Name);
     773            8 :         SetupOutputVariable(state,
     774              :                             "Pipe Volume Flow Rate",
     775              :                             Constant::Units::m3_s,
     776            4 :                             state.dataPipeHT->PipeHT(Item).VolumeFlowRate,
     777              :                             OutputProcessor::TimeStepType::System,
     778              :                             OutputProcessor::StoreType::Average,
     779            4 :                             state.dataPipeHT->PipeHT(Item).Name);
     780            8 :         SetupOutputVariable(state,
     781              :                             "Pipe Inlet Temperature",
     782              :                             Constant::Units::C,
     783            4 :                             state.dataPipeHT->PipeHT(Item).FluidInletTemp,
     784              :                             OutputProcessor::TimeStepType::System,
     785              :                             OutputProcessor::StoreType::Average,
     786            4 :                             state.dataPipeHT->PipeHT(Item).Name);
     787            8 :         SetupOutputVariable(state,
     788              :                             "Pipe Outlet Temperature",
     789              :                             Constant::Units::C,
     790            4 :                             state.dataPipeHT->PipeHT(Item).FluidOutletTemp,
     791              :                             OutputProcessor::TimeStepType::System,
     792              :                             OutputProcessor::StoreType::Average,
     793            4 :                             state.dataPipeHT->PipeHT(Item).Name);
     794              :     }
     795            4 : }
     796              : 
     797            4 : void PipeHTData::ValidatePipeConstruction(EnergyPlusData &state,
     798              :                                           std::string const &PipeType,         // module object of pipe (error messages)
     799              :                                           std::string const &ConstructionName, // construction name of pipe (error messages)
     800              :                                           std::string_view FieldName,          // fieldname of pipe (error messages)
     801              :                                           int const ConstructionNum,           // pointer into construction data
     802              :                                           bool &ErrorsFound                    // set to true if errors found here
     803              : )
     804              : {
     805              : 
     806              :     // SUBROUTINE INFORMATION:
     807              :     //       AUTHOR         Linda Lawrie
     808              :     //       DATE WRITTEN   August 2008
     809              :     //       MODIFIED       na
     810              :     //       RE-ENGINEERED  na
     811              : 
     812              :     // PURPOSE OF THIS SUBROUTINE:
     813              :     // This routine, called from GetInput, validates the pipe construction usage.
     814              : 
     815              :     // METHODOLOGY EMPLOYED:
     816              :     // na
     817              : 
     818              :     // REFERENCES:
     819              :     // na
     820              : 
     821              :     // Using/Aliasing
     822              : 
     823              :     // Locals
     824              :     // SUBROUTINE ARGUMENT DEFINITIONS:
     825              : 
     826              :     // SUBROUTINE PARAMETER DEFINITIONS:
     827              :     // na
     828              : 
     829              :     // INTERFACE BLOCK SPECIFICATIONS:
     830              :     // na
     831              : 
     832              :     // DERIVED TYPE DEFINITIONS:
     833              :     // na
     834              : 
     835              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     836              :     Real64 Density; // average density [kg/m^3]
     837              :     Real64 SpHeat;  // average specific heat [J/kg.K]
     838            4 :     Real64 Resistance = 0.0;
     839            4 :     Real64 TotThickness = 0.0;
     840              : 
     841            4 :     auto const &s_mat = state.dataMaterial;
     842              : 
     843              :     // CTF stuff
     844            4 :     int TotalLayers = state.dataConstruction->Construct(ConstructionNum).TotLayers;
     845              :     // get pipe properties
     846            4 :     if (TotalLayers == 1) { // no insulation layer
     847            0 :         auto const *mat = s_mat->materials(state.dataConstruction->Construct(ConstructionNum).LayerPoint(1));
     848              : 
     849            0 :         this->PipeConductivity = mat->Conductivity;
     850            0 :         this->PipeDensity = mat->Density;
     851            0 :         this->PipeCp = mat->SpecHeat;
     852            0 :         this->PipeOD = this->PipeID + 2.0 * mat->Thickness;
     853            0 :         this->InsulationOD = this->PipeOD;
     854            0 :         this->SumTK = mat->Thickness / mat->Conductivity;
     855              : 
     856            4 :     } else if (TotalLayers >= 2) { // first layers are insulation, last layer is pipe
     857              : 
     858            8 :         for (int LayerNum = 1; LayerNum <= TotalLayers - 1; ++LayerNum) {
     859            4 :             auto const *mat = state.dataMaterial->materials(state.dataConstruction->Construct(ConstructionNum).LayerPoint(LayerNum));
     860            4 :             Resistance += mat->Thickness / mat->Conductivity;
     861            4 :             Density = mat->Density * mat->Thickness;
     862            4 :             TotThickness += mat->Thickness;
     863            4 :             SpHeat = mat->SpecHeat * mat->Thickness;
     864            4 :             this->InsulationThickness = mat->Thickness;
     865            4 :             this->SumTK += mat->Thickness / mat->Conductivity;
     866              :         }
     867              : 
     868            4 :         this->InsulationResistance = Resistance;
     869            4 :         this->InsulationConductivity = TotThickness / Resistance;
     870            4 :         this->InsulationDensity = Density / TotThickness;
     871            4 :         this->InsulationCp = SpHeat / TotThickness;
     872            4 :         this->InsulationThickness = TotThickness;
     873              : 
     874            4 :         auto const *mat = state.dataMaterial->materials(state.dataConstruction->Construct(ConstructionNum).LayerPoint(TotalLayers));
     875            4 :         this->PipeConductivity = mat->Conductivity;
     876            4 :         this->PipeDensity = mat->Density;
     877            4 :         this->PipeCp = mat->SpecHeat;
     878              : 
     879            4 :         this->PipeOD = this->PipeID + 2.0 * mat->Thickness;
     880            4 :         this->InsulationOD = this->PipeOD + 2.0 * this->InsulationThickness;
     881              : 
     882              :     } else {
     883            0 :         ShowSevereError(
     884            0 :             state, format("{}: invalid {}=\"{}\", too many layers=[{}], only 1 or 2 allowed.", PipeType, FieldName, ConstructionName, TotalLayers));
     885            0 :         ErrorsFound = true;
     886              :     }
     887            4 : }
     888              : 
     889            4 : void PipeHTData::oneTimeInit_new(EnergyPlusData &state)
     890              : {
     891            4 :     bool errFlag = false;
     892            4 :     PlantUtilities::ScanPlantLoopsForObject(state, this->Name, this->Type, this->plantLoc, errFlag, _, _, _, _, _);
     893            4 :     if (errFlag) {
     894            0 :         ShowFatalError(state, "InitPipesHeatTransfer: Program terminated due to previous condition(s).");
     895              :     }
     896            4 : }
     897              : 
     898        58100 : void PipeHTData::InitPipesHeatTransfer(EnergyPlusData &state, bool const FirstHVACIteration // component number
     899              : )
     900              : {
     901              : 
     902              :     // SUBROUTINE INFORMATION:
     903              :     //       AUTHOR         Simon Rees
     904              :     //       DATE WRITTEN   July 2007
     905              :     //       MODIFIED       L. Gu, 6/19/08, pipe wall heat capacity has metal layer only
     906              :     //       RE-ENGINEERED  na
     907              : 
     908              :     // PURPOSE OF THIS SUBROUTINE:
     909              :     // This subroutine Resets the elements of the data structure as necessary
     910              :     // at the first step, and start of each call to simulated
     911              : 
     912              :     // METHODOLOGY EMPLOYED:
     913              :     // Check flags and update data structure
     914              : 
     915              :     // Using/Aliasing
     916        58100 :     Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
     917        58100 :     Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
     918              : 
     919              :     // SUBROUTINE PARAMETER DEFINITIONS:
     920              :     static constexpr std::string_view RoutineName("InitPipesHeatTransfer");
     921              : 
     922              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     923              : 
     924              :     Real64 FirstTemperatures; // initial temperature of every node in pipe (set to inlet temp) [C]
     925              :     int TimeIndex;
     926              :     int LengthIndex;
     927              :     int DepthIndex;
     928              :     int WidthIndex;
     929              :     Real64 CurrentDepth;
     930              :     Real64 CurTemp;
     931              :     Real64 CurSimDay;
     932              :     bool PushArrays;
     933              : 
     934              :     // Assign variable
     935        58100 :     CurSimDay = double(state.dataGlobal->DayOfSim);
     936              : 
     937              :     // some useful module variables
     938        58100 :     state.dataPipeHT->nsvInletNodeNum = this->InletNodeNum;
     939        58100 :     state.dataPipeHT->nsvOutletNodeNum = this->OutletNodeNum;
     940        58100 :     state.dataPipeHT->nsvMassFlowRate = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).MassFlowRate;
     941        58100 :     state.dataPipeHT->nsvInletTemp = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).Temp;
     942              : 
     943              :     // initialize temperatures by inlet node temp
     944        58100 :     if ((state.dataGlobal->BeginSimFlag && this->BeginSimInit) || (state.dataGlobal->BeginEnvrnFlag && this->BeginSimEnvrn)) {
     945              : 
     946           20 :         if (this->EnvironmentPtr == EnvrnPtr::GroundEnv) {
     947           20 :             for (TimeIndex = TimeIndex::Previous; TimeIndex <= TimeIndex::Tentative; ++TimeIndex) {
     948              :                 // Loop through all length, depth, and width of pipe to init soil temperature
     949          315 :                 for (LengthIndex = 1; LengthIndex <= this->NumSections; ++LengthIndex) {
     950         2700 :                     for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes; ++DepthIndex) {
     951        12000 :                         for (WidthIndex = 1; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
     952         9600 :                             CurrentDepth = (DepthIndex - 1) * this->dSregular;
     953         9600 :                             this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex) = this->TBND(state, CurrentDepth);
     954              :                         }
     955              :                     }
     956              :                 }
     957              :             }
     958              :         }
     959              : 
     960              :         // We also need to re-init the Hanby arrays for all pipes, including buried
     961           20 :         FirstTemperatures = 21.0; // Node(InletNodeNum)%Temp
     962           20 :         this->TentativeFluidTemp = FirstTemperatures;
     963           20 :         this->FluidTemp = FirstTemperatures;
     964           20 :         this->PreviousFluidTemp = FirstTemperatures;
     965           20 :         this->TentativePipeTemp = FirstTemperatures;
     966           20 :         this->PipeTemp = FirstTemperatures;
     967           20 :         this->PreviousPipeTemp = FirstTemperatures;
     968           20 :         this->PreviousSimTime = 0.0;
     969           20 :         state.dataPipeHT->nsvDeltaTime = 0.0;
     970           20 :         state.dataPipeHT->nsvOutletTemp = 0.0;
     971           20 :         state.dataPipeHT->nsvEnvironmentTemp = 0.0;
     972           20 :         state.dataPipeHT->nsvEnvHeatLossRate = 0.0;
     973           20 :         state.dataPipeHT->nsvFluidHeatLossRate = 0.0;
     974              : 
     975           20 :         this->BeginSimInit = false;
     976           20 :         this->BeginSimEnvrn = false;
     977              :     }
     978              : 
     979        58100 :     if (!state.dataGlobal->BeginSimFlag) {
     980        58100 :         this->BeginSimInit = true;
     981              :     }
     982        58100 :     if (!state.dataGlobal->BeginEnvrnFlag) {
     983        57696 :         this->BeginSimEnvrn = true;
     984              :     }
     985              : 
     986              :     // time step in seconds
     987        58100 :     state.dataPipeHT->nsvDeltaTime = TimeStepSysSec;
     988        58100 :     state.dataPipeHT->nsvNumInnerTimeSteps = int(state.dataPipeHT->nsvDeltaTime / InnerDeltaTime);
     989              : 
     990              :     // previous temps are updated if necessary at start of timestep rather than end
     991        58100 :     if ((FirstHVACIteration && this->FirstHVACupdateFlag) || (state.dataGlobal->BeginEnvrnFlag && this->BeginEnvrnupdateFlag)) {
     992              : 
     993              :         // We need to update boundary conditions here, as well as updating the arrays
     994         7260 :         if (this->EnvironmentPtr == EnvrnPtr::GroundEnv) {
     995              : 
     996              :             // And then update Ground Boundary Conditions
     997         7260 :             for (TimeIndex = 1; TimeIndex <= TimeIndex::Tentative; ++TimeIndex) {
     998       114345 :                 for (LengthIndex = 1; LengthIndex <= this->NumSections; ++LengthIndex) {
     999       980100 :                     for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes; ++DepthIndex) {
    1000              :                         // Farfield boundary
    1001       871200 :                         CurrentDepth = (DepthIndex - 1) * this->dSregular;
    1002       871200 :                         CurTemp = this->TBND(state, CurrentDepth);
    1003       871200 :                         this->T(1, DepthIndex, LengthIndex, TimeIndex) = CurTemp;
    1004              :                     }
    1005       544500 :                     for (WidthIndex = 1; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
    1006              :                         // Bottom side of boundary
    1007       435600 :                         CurrentDepth = this->DomainDepth;
    1008       435600 :                         CurTemp = this->TBND(state, CurrentDepth);
    1009       435600 :                         this->T(WidthIndex, this->NumDepthNodes, LengthIndex, TimeIndex) = CurTemp;
    1010              :                     }
    1011              :                 }
    1012              :             }
    1013              :         }
    1014              : 
    1015              :         // should next choose environment temperature according to coupled with air or ground
    1016         7260 :         switch (this->EnvironmentPtr) {
    1017         1815 :         case EnvrnPtr::GroundEnv: {
    1018              :             // EnvironmentTemp = GroundTemp
    1019         1815 :         } break;
    1020         1815 :         case EnvrnPtr::OutsideAirEnv: {
    1021         1815 :             state.dataPipeHT->nsvEnvironmentTemp = state.dataEnvrn->OutDryBulbTemp;
    1022         1815 :         } break;
    1023         1815 :         case EnvrnPtr::ZoneEnv: {
    1024         1815 :             state.dataPipeHT->nsvEnvironmentTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->EnvrZonePtr).MAT;
    1025         1815 :         } break;
    1026         1815 :         case EnvrnPtr::ScheduleEnv: {
    1027         1815 :             state.dataPipeHT->nsvEnvironmentTemp = this->envrSched->getCurrentVal();
    1028         1815 :         } break;
    1029            0 :         case EnvrnPtr::None: { // default to outside temp
    1030            0 :             state.dataPipeHT->nsvEnvironmentTemp = state.dataEnvrn->OutDryBulbTemp;
    1031            0 :         } break;
    1032            0 :         default:
    1033            0 :             break;
    1034              :         }
    1035              : 
    1036         7260 :         this->BeginEnvrnupdateFlag = false;
    1037         7260 :         this->FirstHVACupdateFlag = false;
    1038              :     }
    1039              : 
    1040        58100 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    1041        57696 :         this->BeginEnvrnupdateFlag = true;
    1042              :     }
    1043        58100 :     if (!FirstHVACIteration) {
    1044        29040 :         this->FirstHVACupdateFlag = true;
    1045              :     }
    1046              : 
    1047              :     // Calculate the current sim time for this pipe (not necessarily structure variable, but it is ok for consistency)
    1048        58100 :     this->CurrentSimTime = (state.dataGlobal->DayOfSim - 1) * 24 + state.dataGlobal->HourOfDay - 1 +
    1049        58100 :                            (state.dataGlobal->TimeStep - 1) * state.dataGlobal->TimeStepZone + SysTimeElapsed;
    1050        58100 :     if (std::abs(this->CurrentSimTime - this->PreviousSimTime) > 1.0e-6) {
    1051         6372 :         PushArrays = true;
    1052         6372 :         this->PreviousSimTime = this->CurrentSimTime;
    1053              :     } else {
    1054        51728 :         PushArrays = false; // Time hasn't passed, don't accept the tentative values yet!
    1055              :     }
    1056              : 
    1057        58100 :     if (PushArrays) {
    1058              : 
    1059              :         // If sim time has changed all values from previous runs should have been acceptable.
    1060              :         // Thus we will now shift the arrays from 2>1 and 3>2 so we can then begin
    1061              :         // to update 2 and 3 again.
    1062         6372 :         if (this->EnvironmentPtr == EnvrnPtr::GroundEnv) {
    1063        31860 :             for (LengthIndex = 2; LengthIndex <= this->NumSections; ++LengthIndex) {
    1064       272403 :                 for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes; ++DepthIndex) {
    1065       968544 :                     for (WidthIndex = 2; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
    1066              :                         // This will essentially 'accept' the tentative values that were calculated last iteration
    1067              :                         // as the new officially 'current' values
    1068       726408 :                         this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Current) =
    1069       726408 :                             this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative);
    1070              :                     }
    1071              :                 }
    1072              :             }
    1073              :         }
    1074              : 
    1075              :         // Then update the Hanby near pipe model temperatures
    1076         6372 :         this->FluidTemp = this->TentativeFluidTemp;
    1077         6372 :         this->PipeTemp = this->TentativePipeTemp;
    1078              : 
    1079              :     } else { //  IF(.NOT. FirstHVACIteration)THEN
    1080              : 
    1081              :         // If we don't have FirstHVAC, the last iteration values were not accepted, and we should
    1082              :         // not step through time.  Thus we will revert our T(3,:,:,:) array back to T(2,:,:,:) to
    1083              :         // start over with the same values as last time.
    1084      1034560 :         for (LengthIndex = 2; LengthIndex <= this->NumSections; ++LengthIndex) {
    1085      2948496 :             for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes; ++DepthIndex) {
    1086      7862656 :                 for (WidthIndex = 2; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
    1087              :                     // This will essentially erase the past iterations and revert back to the correct values
    1088      5896992 :                     this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative) =
    1089      5896992 :                         this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Current);
    1090              :                 }
    1091              :             }
    1092              :         }
    1093              : 
    1094              :         // Similarly for Hanby model arrays
    1095        51728 :         this->TentativeFluidTemp = this->FluidTemp;
    1096        51728 :         this->TentativePipeTemp = this->PipeTemp;
    1097              :     }
    1098              : 
    1099              :     // This still catches even in winter design day
    1100              :     // Even though the loop eventually has no flow rate, it appears it initializes to a value, then converges to OFF
    1101              :     // Thus, this is called at the beginning of every time step once.
    1102              : 
    1103        58100 :     this->FluidSpecHeat =
    1104        58100 :         state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getSpecificHeat(state, state.dataPipeHT->nsvInletTemp, RoutineName);
    1105        58100 :     this->FluidDensity = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getDensity(state, state.dataPipeHT->nsvInletTemp, RoutineName);
    1106              : 
    1107              :     // At this point, for all Pipe:Interior objects we should zero out the energy and rate arrays
    1108        58100 :     this->FluidHeatLossRate = 0.0;
    1109        58100 :     this->FluidHeatLossEnergy = 0.0;
    1110        58100 :     this->EnvironmentHeatLossRate = 0.0;
    1111        58100 :     this->EnvHeatLossEnergy = 0.0;
    1112        58100 :     this->ZoneHeatGainRate = 0.0;
    1113        58100 :     state.dataPipeHT->nsvFluidHeatLossRate = 0.0;
    1114        58100 :     state.dataPipeHT->nsvEnvHeatLossRate = 0.0;
    1115        58100 :     state.dataPipeHT->nsvOutletTemp = 0.0;
    1116              : 
    1117        58100 :     if (this->FluidDensity > 0.0) {
    1118              :         // The density will only be zero the first time through, which will be a warmup day, and not reported
    1119        58100 :         state.dataPipeHT->nsvVolumeFlowRate = state.dataPipeHT->nsvMassFlowRate / this->FluidDensity;
    1120              :     }
    1121        58100 : }
    1122              : 
    1123              : //==============================================================================
    1124              : 
    1125      4467317 : void PipeHTData::CalcPipesHeatTransfer(EnergyPlusData &state, ObjexxFCL::Optional_int_const LengthIndex)
    1126              : {
    1127              : 
    1128              :     //       AUTHOR         Simon Rees
    1129              :     //       DATE WRITTEN   July 2007
    1130              :     //       MODIFIED       na
    1131              :     //       RE-ENGINEERED  na
    1132              : 
    1133              :     // PURPOSE OF THIS SUBROUTINE:
    1134              :     // This subroutine does all of the stuff that is necessary to simulate
    1135              :     // a Pipe Heat Transfer.  Calls are made to appropriate routines
    1136              :     // for heat transfer coefficients
    1137              : 
    1138              :     // METHODOLOGY EMPLOYED:
    1139              :     // Differential equations for pipe and fluid nodes along the pipe are solved
    1140              :     // taking backward differences in time.
    1141              :     // The heat loss/gain calculations are run continuously, even when the loop is off.
    1142              :     // Fluid temps will drift according to environmental conditions when there is zero flow.
    1143              : 
    1144              :     // REFERENCES:
    1145              : 
    1146              :     // Using/Aliasing
    1147              :     using namespace DataEnvironment;
    1148              : 
    1149              :     // fluid node heat balance (see engineering doc).
    1150      4467317 :     Real64 A1(0.0); // sum of the heat balance terms
    1151      4467317 :     Real64 A2(0.0); // mass flow term
    1152      4467317 :     Real64 A3(0.0); // inside pipe wall convection term
    1153      4467317 :     Real64 A4(0.0); // fluid node heat capacity term
    1154              :     // pipe wall node heat balance (see engineering doc).
    1155      4467317 :     Real64 B1(0.0); // sum of the heat balance terms
    1156      4467317 :     Real64 B2(0.0); // inside pipe wall convection term
    1157      4467317 :     Real64 B3(0.0); // outside pipe wall convection term
    1158      4467317 :     Real64 B4(0.0); // fluid node heat capacity term
    1159              : 
    1160      4467317 :     Real64 AirConvCoef(0.0);           // air-pipe convection coefficient
    1161      4467317 :     Real64 FluidConvCoef(0.0);         // fluid-pipe convection coefficient
    1162      4467317 :     Real64 EnvHeatTransCoef(0.0);      // external convection coefficient (outside pipe)
    1163      4467317 :     Real64 FluidNodeHeatCapacity(0.0); // local var for MCp for single node of pipe
    1164              : 
    1165              :     Real64 TempBelow;
    1166              :     Real64 TempBeside;
    1167              :     Real64 TempAbove;
    1168              :     Real64 Numerator;
    1169              :     Real64 Denominator;
    1170              :     Real64 SurfaceTemp;
    1171              : 
    1172              :     // traps fluid properties problems such as freezing conditions
    1173      4467317 :     if (this->FluidSpecHeat <= 0.0 || this->FluidDensity <= 0.0) {
    1174              :         // leave the state of the pipe as it was
    1175            0 :         state.dataPipeHT->nsvOutletTemp = this->TentativeFluidTemp(this->NumSections);
    1176              :         // set heat transfer rates to zero for consistency
    1177            0 :         state.dataPipeHT->nsvEnvHeatLossRate = 0.0;
    1178            0 :         state.dataPipeHT->nsvFluidHeatLossRate = 0.0;
    1179            0 :         return;
    1180              :     }
    1181              : 
    1182              :     //  AirConvCoef =  OutsidePipeHeatTransCoef(PipeHTNum)
    1183              :     // Revised by L. Gu by including insulation conductance 6/19/08
    1184              : 
    1185      4467317 :     if (this->EnvironmentPtr != EnvrnPtr::GroundEnv) {
    1186       558537 :         AirConvCoef = 1.0 / (1.0 / this->OutsidePipeHeatTransCoef(state) + this->InsulationResistance);
    1187              :     }
    1188              : 
    1189      4467317 :     FluidConvCoef = this->CalcPipeHeatTransCoef(state, state.dataPipeHT->nsvInletTemp, state.dataPipeHT->nsvMassFlowRate, this->PipeID);
    1190              : 
    1191              :     // heat transfer to air or ground
    1192      4467317 :     switch (this->EnvironmentPtr) {
    1193      3908780 :     case EnvrnPtr::GroundEnv: {
    1194              :         // Approximate conductance using ground conductivity, (h=k/L), where L is grid spacing
    1195              :         // between pipe wall and next closest node.
    1196      3908780 :         EnvHeatTransCoef = this->SoilConductivity / (this->dSregular - (this->PipeID / 2.0));
    1197      3908780 :     } break;
    1198       186179 :     case EnvrnPtr::OutsideAirEnv: {
    1199       186179 :         EnvHeatTransCoef = AirConvCoef;
    1200       186179 :     } break;
    1201       186179 :     case EnvrnPtr::ZoneEnv: {
    1202       186179 :         EnvHeatTransCoef = AirConvCoef;
    1203       186179 :     } break;
    1204       186179 :     case EnvrnPtr::ScheduleEnv: {
    1205       186179 :         EnvHeatTransCoef = AirConvCoef;
    1206       186179 :     } break;
    1207            0 :     case EnvrnPtr::None: {
    1208            0 :         EnvHeatTransCoef = 0.0;
    1209            0 :     } break;
    1210            0 :     default: {
    1211            0 :         EnvHeatTransCoef = 0.0;
    1212            0 :     } break;
    1213              :     }
    1214              : 
    1215              :     // work out the coefficients
    1216      4467317 :     FluidNodeHeatCapacity =
    1217      4467317 :         this->SectionArea * this->Length / this->NumSections * this->FluidSpecHeat * this->FluidDensity; // Mass of Node x Specific heat
    1218              : 
    1219              :     // coef of fluid heat balance
    1220      4467317 :     A1 = FluidNodeHeatCapacity + state.dataPipeHT->nsvMassFlowRate * this->FluidSpecHeat * state.dataPipeHT->nsvDeltaTime +
    1221      4467317 :          FluidConvCoef * this->InsideArea * state.dataPipeHT->nsvDeltaTime;
    1222              : 
    1223      4467317 :     A2 = state.dataPipeHT->nsvMassFlowRate * this->FluidSpecHeat * state.dataPipeHT->nsvDeltaTime;
    1224              : 
    1225      4467317 :     A3 = FluidConvCoef * this->InsideArea * state.dataPipeHT->nsvDeltaTime;
    1226              : 
    1227      4467317 :     A4 = FluidNodeHeatCapacity;
    1228              : 
    1229              :     // coef of pipe heat balance
    1230      4467317 :     B1 = this->PipeHeatCapacity + FluidConvCoef * this->InsideArea * state.dataPipeHT->nsvDeltaTime +
    1231      4467317 :          EnvHeatTransCoef * this->OutsideArea * state.dataPipeHT->nsvDeltaTime;
    1232              : 
    1233      4467317 :     B2 = A3;
    1234              : 
    1235      4467317 :     B3 = EnvHeatTransCoef * this->OutsideArea * state.dataPipeHT->nsvDeltaTime;
    1236              : 
    1237      4467317 :     B4 = this->PipeHeatCapacity;
    1238              : 
    1239      4467317 :     this->TentativeFluidTemp(0) = state.dataPipeHT->nsvInletTemp;
    1240              : 
    1241      4467317 :     this->TentativePipeTemp(0) = this->PipeTemp(1); // for convenience
    1242              : 
    1243      4467317 :     if (present(LengthIndex)) { // Just simulate the single section if being called from Pipe:Underground
    1244              : 
    1245      3908780 :         int PipeDepth = this->PipeNodeDepth;
    1246      3908780 :         int PipeWidth = this->PipeNodeWidth;
    1247      3908780 :         TempBelow = this->T(PipeWidth, PipeDepth + 1, LengthIndex, TimeIndex::Current);
    1248      3908780 :         TempBeside = this->T(PipeWidth - 1, PipeDepth, LengthIndex, TimeIndex::Current);
    1249      3908780 :         TempAbove = this->T(PipeWidth, PipeDepth - 1, LengthIndex, TimeIndex::Current);
    1250      3908780 :         state.dataPipeHT->nsvEnvironmentTemp = (TempBelow + TempBeside + TempAbove) / 3.0;
    1251              : 
    1252      7817560 :         this->TentativeFluidTemp(LengthIndex) = (A2 * this->TentativeFluidTemp(LengthIndex - 1) +
    1253      3908780 :                                                  A3 / B1 * (B3 * state.dataPipeHT->nsvEnvironmentTemp + B4 * this->PreviousPipeTemp(LengthIndex)) +
    1254      3908780 :                                                  A4 * this->PreviousFluidTemp(LengthIndex)) /
    1255      3908780 :                                                 (A1 - A3 * B2 / B1);
    1256              : 
    1257      3908780 :         this->TentativePipeTemp(LengthIndex) =
    1258      3908780 :             (B2 * this->TentativeFluidTemp(LengthIndex) + B3 * state.dataPipeHT->nsvEnvironmentTemp + B4 * this->PreviousPipeTemp(LengthIndex)) / B1;
    1259              : 
    1260              :         // Get exterior surface temperature from energy balance at the surface
    1261      3908780 :         Numerator = state.dataPipeHT->nsvEnvironmentTemp - this->TentativeFluidTemp(LengthIndex);
    1262      3908780 :         Denominator = EnvHeatTransCoef * ((1 / EnvHeatTransCoef) + this->SumTK);
    1263      3908780 :         SurfaceTemp = state.dataPipeHT->nsvEnvironmentTemp - Numerator / Denominator;
    1264              : 
    1265              :         // keep track of environmental heat loss rate - not same as fluid loss at same time
    1266      3908780 :         state.dataPipeHT->nsvEnvHeatLossRate += EnvHeatTransCoef * this->OutsideArea * (SurfaceTemp - state.dataPipeHT->nsvEnvironmentTemp);
    1267              : 
    1268              :     } else { // Simulate all sections at once if not pipe:underground
    1269              : 
    1270              :         // start loop along pipe
    1271              :         // b1 must not be zero but this should have been checked on input
    1272     11729277 :         for (int curnode = 1; curnode <= this->NumSections; ++curnode) {
    1273     11170740 :             this->TentativeFluidTemp(curnode) = (A2 * this->TentativeFluidTemp(curnode - 1) +
    1274     11170740 :                                                  A3 / B1 * (B3 * state.dataPipeHT->nsvEnvironmentTemp + B4 * this->PreviousPipeTemp(curnode)) +
    1275     11170740 :                                                  A4 * this->PreviousFluidTemp(curnode)) /
    1276     11170740 :                                                 (A1 - A3 * B2 / B1);
    1277              : 
    1278     22341480 :             this->TentativePipeTemp(curnode) =
    1279     11170740 :                 (B2 * this->TentativeFluidTemp(curnode) + B3 * state.dataPipeHT->nsvEnvironmentTemp + B4 * this->PreviousPipeTemp(curnode)) / B1;
    1280              : 
    1281              :             // Get exterior surface temperature from energy balance at the surface
    1282     11170740 :             Numerator = state.dataPipeHT->nsvEnvironmentTemp - this->TentativeFluidTemp(curnode);
    1283     11170740 :             Denominator = EnvHeatTransCoef * ((1 / EnvHeatTransCoef) + this->SumTK);
    1284     11170740 :             SurfaceTemp = state.dataPipeHT->nsvEnvironmentTemp - Numerator / Denominator;
    1285              : 
    1286              :             // Keep track of environmental heat loss
    1287     11170740 :             state.dataPipeHT->nsvEnvHeatLossRate += EnvHeatTransCoef * this->OutsideArea * (SurfaceTemp - state.dataPipeHT->nsvEnvironmentTemp);
    1288              :         }
    1289              :     }
    1290              : 
    1291      8934634 :     state.dataPipeHT->nsvFluidHeatLossRate =
    1292      4467317 :         state.dataPipeHT->nsvMassFlowRate * this->FluidSpecHeat * (this->TentativeFluidTemp(0) - this->TentativeFluidTemp(this->NumSections));
    1293              : 
    1294      4467317 :     state.dataPipeHT->nsvOutletTemp = this->TentativeFluidTemp(this->NumSections);
    1295              : }
    1296              : 
    1297              : //==============================================================================
    1298              : 
    1299       186179 : void PipeHTData::CalcBuriedPipeSoil(EnergyPlusData &state) // Current Simulation Pipe Number
    1300              : {
    1301              : 
    1302              :     //       AUTHOR         Edwin Lee
    1303              :     //       DATE WRITTEN   May 2008
    1304              :     //       MODIFIED       na
    1305              :     //       RE-ENGINEERED  na
    1306              : 
    1307              :     // PURPOSE OF THIS SUBROUTINE:
    1308              :     // This subroutine does all of the stuff that is necessary to simulate
    1309              :     // soil heat transfer with a Buried Pipe.
    1310              : 
    1311              :     // METHODOLOGY EMPLOYED:
    1312              :     // An implicit pseudo 3D finite difference grid
    1313              :     // is set up, which simulates transient behavior in the soil.
    1314              :     // This then interfaces with the Hanby model for near-pipe region
    1315              : 
    1316              :     // Using/Aliasing
    1317              :     using Convect::CalcASHRAESimpExtConvCoeff;
    1318              : 
    1319              :     // SUBROUTINE PARAMETER DEFINITIONS:
    1320       186179 :     int constexpr NumSections(20);
    1321       186179 :     Real64 constexpr ConvCrit(0.05);
    1322       186179 :     int constexpr MaxIterations(200);
    1323       186179 :     Real64 constexpr StefBoltzmann(5.6697e-08); // Stefan-Boltzmann constant
    1324              : 
    1325              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1326       186179 :     int IterationIndex(0);    // Index when stepping through equations
    1327       186179 :     int DepthIndex(0);        // Index for nodes in the depth direction
    1328       186179 :     int WidthIndex(0);        // Index for nodes in the width direction
    1329       186179 :     Real64 ConvCoef(0.0);     // Current convection coefficient = f(Wind Speed,Roughness)
    1330       186179 :     Real64 RadCoef(0.0);      // Current radiation coefficient
    1331       186179 :     Real64 QSolAbsorbed(0.0); // Current total solar energy absorbed
    1332       186179 :     Array3D<Real64> T_O(this->PipeNodeWidth, this->NumDepthNodes, NumSections);
    1333              : 
    1334              :     // Local variable placeholders for code readability
    1335       186179 :     Real64 A1(0.0);                                                               // Placeholder for CoefA1
    1336       186179 :     Real64 A2(0.0);                                                               // Placeholder for CoefA2
    1337       186179 :     Real64 NodeBelow(0.0);                                                        // Placeholder for Node temp below current node
    1338       186179 :     Real64 NodeAbove(0.0);                                                        // Placeholder for Node temp above current node
    1339       186179 :     Real64 NodeRight(0.0);                                                        // Placeholder for Node temp to the right of current node
    1340       186179 :     Real64 NodeLeft(0.0);                                                         // Placeholder for Node temp to the left of current node
    1341       186179 :     Real64 NodePast(0.0);                                                         // Placeholder for Node temp at current node but previous time step
    1342       186179 :     Real64 PastNodeTempAbs(0.0);                                                  // Placeholder for absolute temperature (K) version of NodePast
    1343       186179 :     Real64 Ttemp(0.0);                                                            // Placeholder for a current temperature node in convergence check
    1344       186179 :     Real64 SkyTempAbs(0.0);                                                       // Placeholder for current sky temperature in Kelvin
    1345       186179 :     Material::SurfaceRoughness TopRoughness(Material::SurfaceRoughness::Invalid); // Placeholder for soil surface roughness
    1346       186179 :     Real64 TopThermAbs(0.0);                                                      // Placeholder for soil thermal radiation absorptivity
    1347       186179 :     Real64 TopSolarAbs(0.0);                                                      // Placeholder for soil solar radiation absorptivity
    1348       186179 :     Real64 kSoil(0.0);                                                            // Placeholder for soil conductivity
    1349       186179 :     Real64 dS(0.0);                                                               // Placeholder for soil grid spacing
    1350       186179 :     Real64 rho(0.0);                                                              // Placeholder for soil density
    1351       186179 :     Real64 Cp(0.0);                                                               // Placeholder for soil specific heat
    1352              : 
    1353              :     // There are a number of coefficients which change through the simulation, and they are updated here
    1354       186179 :     this->FourierDS = this->SoilDiffusivity * state.dataPipeHT->nsvDeltaTime / pow_2(this->dSregular); // Eq. D4
    1355       186179 :     this->CoefA1 = this->FourierDS / (1 + 4 * this->FourierDS);                                        // Eq. D2
    1356       186179 :     this->CoefA2 = 1 / (1 + 4 * this->FourierDS);                                                      // Eq. D3
    1357              : 
    1358       195439 :     for (IterationIndex = 1; IterationIndex <= MaxIterations; ++IterationIndex) {
    1359       195439 :         if (IterationIndex == MaxIterations) {
    1360            0 :             ShowWarningError(state, format("BuriedPipeHeatTransfer: Large number of iterations detected in object: {}", this->Name));
    1361              :         }
    1362              : 
    1363              :         // Store computed values in T_O array
    1364      3908780 :         for (int LengthIndex = 2; LengthIndex <= this->NumSections; ++LengthIndex) {
    1365     29706728 :             for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes - 1; ++DepthIndex) {
    1366    103973548 :                 for (WidthIndex = 2; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
    1367     77980161 :                     T_O(WidthIndex, DepthIndex, LengthIndex) = this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative);
    1368              :                 }
    1369              :             }
    1370              :         }
    1371              : 
    1372              :         // Loop along entire length of pipe, analyzing cross sects
    1373      4104219 :         for (int LengthIndex = 1; LengthIndex <= this->NumSections; ++LengthIndex) {
    1374     31270240 :             for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes - 1; ++DepthIndex) {
    1375    109445840 :                 for (WidthIndex = 2; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
    1376              : 
    1377     82084380 :                     if (DepthIndex == 1) { // Soil Surface Boundary
    1378              : 
    1379              :                         // If on soil boundary, load up local variables and perform calculations
    1380     11726340 :                         NodePast = this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Previous);
    1381     11726340 :                         PastNodeTempAbs = NodePast + Constant::Kelvin;
    1382     11726340 :                         SkyTempAbs = state.dataEnvrn->SkyTemp + Constant::Kelvin;
    1383     11726340 :                         TopRoughness = this->SoilRoughness;
    1384     11726340 :                         TopThermAbs = this->SoilThermAbs;
    1385     11726340 :                         TopSolarAbs = this->SoilSolarAbs;
    1386     11726340 :                         kSoil = this->SoilConductivity;
    1387     11726340 :                         dS = this->dSregular;
    1388     11726340 :                         rho = this->SoilDensity;
    1389     11726340 :                         Cp = this->SoilCp;
    1390              : 
    1391              :                         // ASHRAE simple convection coefficient model for external surfaces.
    1392     11726340 :                         this->OutdoorConvCoef = CalcASHRAESimpExtConvCoeff(TopRoughness, state.dataEnvrn->WindSpeed);
    1393     11726340 :                         ConvCoef = this->OutdoorConvCoef;
    1394              : 
    1395              :                         // thermal radiation coefficient using surf temp from past time step
    1396     11726340 :                         if (std::abs(PastNodeTempAbs - SkyTempAbs) > Constant::rTinyValue) {
    1397     11726340 :                             RadCoef = StefBoltzmann * TopThermAbs * (pow_4(PastNodeTempAbs) - pow_4(SkyTempAbs)) / (PastNodeTempAbs - SkyTempAbs);
    1398              :                         } else {
    1399            0 :                             RadCoef = 0.0;
    1400              :                         }
    1401              : 
    1402              :                         // total absorbed solar - no ground solar
    1403     11726340 :                         QSolAbsorbed =
    1404     11726340 :                             TopSolarAbs * (max(state.dataEnvrn->SOLCOS(3), 0.0) * state.dataEnvrn->BeamSolarRad + state.dataEnvrn->DifSolarRad);
    1405              : 
    1406              :                         // If sun is not exposed, then turn off both solar and thermal radiation
    1407     11726340 :                         if (!this->SolarExposed) {
    1408            0 :                             RadCoef = 0.0;
    1409            0 :                             QSolAbsorbed = 0.0;
    1410              :                         }
    1411              : 
    1412     11726340 :                         if (WidthIndex == this->PipeNodeWidth) { // Symmetric centerline boundary
    1413              : 
    1414              :                             //-Coefficients and Temperatures
    1415      3908780 :                             NodeBelow = this->T(WidthIndex, DepthIndex + 1, LengthIndex, TimeIndex::Current);
    1416      3908780 :                             NodeLeft = this->T(WidthIndex - 1, DepthIndex, LengthIndex, TimeIndex::Current);
    1417              : 
    1418              :                             //-Update Equation, basically a detailed energy balance at the surface
    1419      3908780 :                             this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative) =
    1420      3908780 :                                 (QSolAbsorbed + RadCoef * state.dataEnvrn->SkyTemp + ConvCoef * state.dataEnvrn->OutDryBulbTemp +
    1421      3908780 :                                  (kSoil / dS) * (NodeBelow + 2 * NodeLeft) + (rho * Cp / state.dataPipeHT->nsvDeltaTime) * NodePast) /
    1422      3908780 :                                 (RadCoef + ConvCoef + 3 * (kSoil / dS) + (rho * Cp / state.dataPipeHT->nsvDeltaTime));
    1423              : 
    1424              :                         } else { // Soil surface, but not on centerline
    1425              : 
    1426              :                             //-Coefficients and Temperatures
    1427      7817560 :                             NodeBelow = this->T(WidthIndex, DepthIndex + 1, LengthIndex, TimeIndex::Current);
    1428      7817560 :                             NodeLeft = this->T(WidthIndex - 1, DepthIndex, LengthIndex, TimeIndex::Current);
    1429      7817560 :                             NodeRight = this->T(WidthIndex + 1, DepthIndex, LengthIndex, TimeIndex::Current);
    1430              : 
    1431              :                             //-Update Equation
    1432      7817560 :                             this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative) =
    1433      7817560 :                                 (QSolAbsorbed + RadCoef * state.dataEnvrn->SkyTemp + ConvCoef * state.dataEnvrn->OutDryBulbTemp +
    1434      7817560 :                                  (kSoil / dS) * (NodeBelow + NodeLeft + NodeRight) + (rho * Cp / state.dataPipeHT->nsvDeltaTime) * NodePast) /
    1435      7817560 :                                 (RadCoef + ConvCoef + 3 * (kSoil / dS) + (rho * Cp / state.dataPipeHT->nsvDeltaTime));
    1436              : 
    1437              :                         } // Soil-to-air surface node structure
    1438              : 
    1439     70358040 :                     } else if (WidthIndex == this->PipeNodeWidth) { // On Symmetric centerline boundary
    1440              : 
    1441     23452680 :                         if (DepthIndex == this->PipeNodeDepth) { // On the node containing the pipe
    1442              : 
    1443              :                             //-Call to simulate a single pipe segment (by passing OPTIONAL LengthIndex argument)
    1444      3908780 :                             this->CalcPipesHeatTransfer(state, LengthIndex);
    1445              : 
    1446              :                             //-Update node for cartesian system
    1447      3908780 :                             this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative) = this->PipeTemp(LengthIndex);
    1448              : 
    1449              :                         } else { // Not surface node
    1450              : 
    1451              :                             //-Coefficients and Temperatures
    1452     19543900 :                             NodeLeft = this->T(WidthIndex - 1, DepthIndex, LengthIndex, TimeIndex::Current);
    1453     19543900 :                             NodeAbove = this->T(WidthIndex, DepthIndex - 1, LengthIndex, TimeIndex::Current);
    1454     19543900 :                             NodeBelow = this->T(WidthIndex, DepthIndex + 1, LengthIndex, TimeIndex::Current);
    1455     19543900 :                             NodePast = this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Current - 1);
    1456     19543900 :                             A1 = this->CoefA1;
    1457     19543900 :                             A2 = this->CoefA2;
    1458              : 
    1459              :                             //-Update Equation
    1460     19543900 :                             this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative) =
    1461     19543900 :                                 A1 * (NodeBelow + NodeAbove + 2 * NodeLeft) + A2 * NodePast;
    1462              : 
    1463              :                         } // Symmetric centerline node structure
    1464              : 
    1465              :                     } else { // All Normal Interior Nodes
    1466              : 
    1467              :                         //-Coefficients and Temperatures
    1468     46905360 :                         A1 = this->CoefA1;
    1469     46905360 :                         A2 = this->CoefA2;
    1470     46905360 :                         NodeBelow = this->T(WidthIndex, DepthIndex + 1, LengthIndex, TimeIndex::Current);
    1471     46905360 :                         NodeAbove = this->T(WidthIndex, DepthIndex - 1, LengthIndex, TimeIndex::Current);
    1472     46905360 :                         NodeRight = this->T(WidthIndex + 1, DepthIndex, LengthIndex, TimeIndex::Current);
    1473     46905360 :                         NodeLeft = this->T(WidthIndex - 1, DepthIndex, LengthIndex, TimeIndex::Current);
    1474     46905360 :                         NodePast = this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Current - 1);
    1475              : 
    1476              :                         //-Update Equation
    1477     46905360 :                         this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative) =
    1478     46905360 :                             A1 * (NodeBelow + NodeAbove + NodeRight + NodeLeft) + A2 * NodePast; // Eq. D1
    1479              :                     }
    1480              :                 }
    1481              :             }
    1482              :         }
    1483              : 
    1484              :         // Check for convergence
    1485      3739744 :         for (int LengthIndex = 2; LengthIndex <= this->NumSections; ++LengthIndex) {
    1486     28372256 :             for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes - 1; ++DepthIndex) {
    1487     99289775 :                 for (WidthIndex = 2; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
    1488     74471084 :                     Ttemp = this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative);
    1489     74471084 :                     if (std::abs(T_O(WidthIndex, DepthIndex, LengthIndex) - Ttemp) > ConvCrit) {
    1490         9260 :                         goto IterationLoop_loop;
    1491              :                     }
    1492              :                 }
    1493              :             }
    1494              :         }
    1495              : 
    1496              :         // If we didn't cycle back, then the system is converged
    1497              :         // PipeHT(PipeHTNum)%PipeUGIters=IterationIndex
    1498       186179 :         goto IterationLoop_exit;
    1499              : 
    1500         9260 :     IterationLoop_loop:;
    1501              :     }
    1502            0 : IterationLoop_exit:;
    1503       186179 : }
    1504              : 
    1505              : //==============================================================================
    1506              : 
    1507        58100 : void PipeHTData::UpdatePipesHeatTransfer(EnergyPlusData &state)
    1508              : {
    1509              : 
    1510              :     // SUBROUTINE INFORMATION:
    1511              :     //       AUTHOR         Simon Rees
    1512              :     //       DATE WRITTEN   July 2007
    1513              :     //       MODIFIED       na
    1514              :     //       RE-ENGINEERED  na
    1515              : 
    1516              :     // PURPOSE OF THIS SUBROUTINE:
    1517              :     // This subroutine does any updating that needs to be done for
    1518              :     // Pipe Heat Transfers. This routine must also set the outlet water conditions.
    1519              : 
    1520              :     // METHODOLOGY EMPLOYED:
    1521              : 
    1522              :     // REFERENCES:
    1523              :     // na
    1524              : 
    1525              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    1526              :     // INTEGER, INTENT(IN) :: PipeHTNum       ! Index for the surface
    1527              : 
    1528              :     // SUBROUTINE PARAMETER DEFINITIONS:
    1529              : 
    1530              :     // INTERFACE BLOCK SPECIFICATIONS
    1531              :     // na
    1532              : 
    1533              :     // DERIVED TYPE DEFINITIONS
    1534              :     // na
    1535              : 
    1536              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1537              : 
    1538              :     // only outlet node temp should need updating
    1539        58100 :     state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).Temp = state.dataPipeHT->nsvOutletTemp;
    1540              : 
    1541              :     // pass everything else through
    1542        58100 :     state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).TempMin = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).TempMin;
    1543        58100 :     state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).TempMax = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).TempMax;
    1544        58100 :     state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).MassFlowRate =
    1545        58100 :         state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).MassFlowRate;
    1546        58100 :     state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).MassFlowRateMin =
    1547        58100 :         state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).MassFlowRateMin;
    1548        58100 :     state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).MassFlowRateMax =
    1549        58100 :         state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).MassFlowRateMax;
    1550        58100 :     state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).MassFlowRateMinAvail =
    1551        58100 :         state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).MassFlowRateMinAvail;
    1552        58100 :     state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).MassFlowRateMaxAvail =
    1553        58100 :         state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).MassFlowRateMaxAvail;
    1554        58100 :     state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).Quality = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).Quality;
    1555              :     // Only pass pressure if we aren't doing a pressure simulation
    1556        58100 :     switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).PressureSimType) {
    1557        58100 :     case DataPlant::PressSimType::NoPressure:
    1558        58100 :         state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).Press = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).Press;
    1559        58100 :         break;
    1560            0 :     default:
    1561              :         // Don't do anything
    1562            0 :         break;
    1563              :     }
    1564        58100 :     state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).Enthalpy = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).Enthalpy;
    1565        58100 :     state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).HumRat = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).HumRat;
    1566        58100 : }
    1567              : 
    1568              : //==============================================================================
    1569              : 
    1570        58100 : void PipeHTData::ReportPipesHeatTransfer(EnergyPlusData &state)
    1571              : {
    1572              : 
    1573              :     // SUBROUTINE INFORMATION:
    1574              :     //       AUTHOR         Simon Rees
    1575              :     //       DATE WRITTEN   July 2007
    1576              :     //       MODIFIED       na
    1577              :     //       RE-ENGINEERED  na
    1578              : 
    1579              :     // PURPOSE OF THIS SUBROUTINE:
    1580              :     // This subroutine simply updates the report data
    1581              : 
    1582              :     // METHODOLOGY EMPLOYED:
    1583              :     // Standard EnergyPlus methodology.
    1584              : 
    1585              :     // REFERENCES:
    1586              :     // na
    1587              : 
    1588              :     // USE STATEMENTS:
    1589              : 
    1590              :     // Locals
    1591              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    1592              : 
    1593              :     // SUBROUTINE PARAMETER DEFINITIONS:
    1594              :     // na
    1595              : 
    1596              :     // INTERFACE BLOCK SPECIFICATIONS
    1597              :     // na
    1598              : 
    1599              :     // DERIVED TYPE DEFINITIONS
    1600              :     // na
    1601              : 
    1602              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1603              : 
    1604              :     // update flows and temps from module variables
    1605        58100 :     this->FluidInletTemp = state.dataPipeHT->nsvInletTemp;
    1606        58100 :     this->FluidOutletTemp = state.dataPipeHT->nsvOutletTemp;
    1607        58100 :     this->MassFlowRate = state.dataPipeHT->nsvMassFlowRate;
    1608        58100 :     this->VolumeFlowRate = state.dataPipeHT->nsvVolumeFlowRate;
    1609              : 
    1610              :     // update other variables from module variables
    1611        58100 :     this->FluidHeatLossRate = state.dataPipeHT->nsvFluidHeatLossRate;
    1612        58100 :     this->FluidHeatLossEnergy = state.dataPipeHT->nsvFluidHeatLossRate * state.dataPipeHT->nsvDeltaTime; // DeltaTime is in seconds
    1613        58100 :     this->PipeInletTemp = this->PipeTemp(1);
    1614        58100 :     this->PipeOutletTemp = this->PipeTemp(this->NumSections);
    1615              : 
    1616              :     // need to average the heat rate because it is now summing over multiple inner time steps
    1617        58100 :     this->EnvironmentHeatLossRate = state.dataPipeHT->nsvEnvHeatLossRate / state.dataPipeHT->nsvNumInnerTimeSteps;
    1618        58100 :     this->EnvHeatLossEnergy = this->EnvironmentHeatLossRate * state.dataPipeHT->nsvDeltaTime;
    1619              : 
    1620              :     // for zone heat gains, we assign the averaged heat rate over all inner time steps
    1621        58100 :     if (this->EnvironmentPtr == EnvrnPtr::ZoneEnv) {
    1622        14525 :         this->ZoneHeatGainRate = this->EnvironmentHeatLossRate;
    1623              :     }
    1624        58100 : }
    1625              : 
    1626              : //==============================================================================
    1627              : 
    1628      2828408 : void PipeHTData::CalcZonePipesHeatGain(EnergyPlusData &state)
    1629              : {
    1630              : 
    1631              :     // SUBROUTINE INFORMATION:
    1632              :     //       AUTHOR         Edwin Lee
    1633              :     //       DATE WRITTEN   September 2008
    1634              :     //       MODIFIED
    1635              :     //       RE-ENGINEERED  na
    1636              : 
    1637              :     // PURPOSE OF THIS SUBROUTINE:
    1638              :     // Calculates the zone internal gains due to pipe heat transfer objects.
    1639              : 
    1640              :     // METHODOLOGY EMPLOYED:
    1641              :     // Sums the heat losses from all of the water heaters in the zone to add as a gain to the zone.
    1642              : 
    1643              :     // Using/Aliasing
    1644      2828408 :     if (state.dataPipeHT->nsvNumOfPipeHT == 0) {
    1645      2817600 :         return;
    1646              :     }
    1647              : 
    1648        10808 :     if (state.dataGlobal->BeginEnvrnFlag && state.dataPipeHT->MyEnvrnFlag) {
    1649           64 :         for (auto &e : state.dataPipeHT->PipeHT) {
    1650           32 :             e.ZoneHeatGainRate = 0.0;
    1651              :         }
    1652           32 :         state.dataPipeHT->MyEnvrnFlag = false;
    1653              :     }
    1654              : 
    1655        10808 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    1656        10776 :         state.dataPipeHT->MyEnvrnFlag = true;
    1657              :     }
    1658              : }
    1659              : 
    1660              : //==============================================================================
    1661              : 
    1662      4467317 : Real64 PipeHTData::CalcPipeHeatTransCoef(EnergyPlusData &state,
    1663              :                                          Real64 const Temperature,  // Temperature of water entering the surface, in C
    1664              :                                          Real64 const MassFlowRate, // Mass flow rate, in kg/s
    1665              :                                          Real64 const Diameter      // Pipe diameter, m
    1666              : )
    1667              : {
    1668              : 
    1669              :     // FUNCTION INFORMATION:
    1670              :     //       AUTHOR         Simon Rees
    1671              :     //       DATE WRITTEN   July 2007
    1672              :     //       MODIFIED       na
    1673              :     //       RE-ENGINEERED  na
    1674              : 
    1675              :     // PURPOSE OF THIS SUBROUTINE:
    1676              :     // This subroutine calculates pipe/fluid heat transfer coefficients.
    1677              :     // This routine is adapted from that in the low temp radiant surface model.
    1678              : 
    1679              :     // METHODOLOGY EMPLOYED:
    1680              :     // Currently assumes water data when calculating Pr and Re
    1681              : 
    1682              :     // REFERENCES:
    1683              :     // See RadiantSystemLowTemp module.
    1684              :     // Property data for water shown below as parameters taken from
    1685              :     // Incropera and DeWitt, Introduction to Heat Transfer, Table A.6.
    1686              :     // Heat exchanger information also from Incropera and DeWitt.
    1687              :     // Code based loosely on code from IBLAST program (research version)
    1688              : 
    1689              :     // Return value
    1690              :     Real64 CalcPipeHeatTransCoef;
    1691              : 
    1692              :     // Locals
    1693              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    1694              : 
    1695              :     // SUBROUTINE PARAMETER DEFINITIONS:
    1696              :     static constexpr std::string_view RoutineName("PipeHeatTransfer::CalcPipeHeatTransCoef: ");
    1697      4467317 :     Real64 constexpr MaxLaminarRe(2300.0); // Maximum Reynolds number for laminar flow
    1698      4467317 :     int constexpr NumOfPropDivisions(13);  // intervals in property correlation
    1699              :     static constexpr std::array<Real64, NumOfPropDivisions> Temps = {
    1700              :         1.85, 6.85, 11.85, 16.85, 21.85, 26.85, 31.85, 36.85, 41.85, 46.85, 51.85, 56.85, 61.85}; // Temperature, in C
    1701              :     static constexpr std::array<Real64, NumOfPropDivisions> Pr = {
    1702              :         12.22, 10.26, 8.81, 7.56, 6.62, 5.83, 5.20, 4.62, 4.16, 3.77, 3.42, 3.15, 2.88}; // Prandtl number (dimensionless)
    1703              : 
    1704              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1705              :     Real64 InterpFrac;
    1706              :     Real64 NuD;
    1707              :     Real64 ReD;
    1708              :     Real64 Kactual;
    1709              :     Real64 MUactual;
    1710              :     Real64 PRactual;
    1711              :     int LoopNum;
    1712              : 
    1713              :     // retrieve loop index for this component so we can look up fluid properties
    1714      4467317 :     LoopNum = this->plantLoc.loopNum;
    1715              : 
    1716              :     // since the fluid properties routine doesn't have Prandtl, we'll just use water values
    1717      4467317 :     int idx = 0;
    1718     20129911 :     while (idx < NumOfPropDivisions) {
    1719     20129911 :         if (Temperature < Temps[idx]) {
    1720      4467317 :             break;
    1721              :         }
    1722     15662594 :         ++idx;
    1723              :     }
    1724              : 
    1725      4467317 :     if (idx == 0) {
    1726            0 :         PRactual = Pr[idx];
    1727      4467317 :     } else if (idx >= NumOfPropDivisions) {
    1728            0 :         PRactual = Pr[NumOfPropDivisions - 1];
    1729              :     } else {
    1730      4467317 :         InterpFrac = (Temperature - Temps[idx - 1]) / (Temps[idx] - Temps[idx - 1]);
    1731      4467317 :         PRactual = Pr[idx - 1] + InterpFrac * (Pr[idx] - Pr[idx - 1]);
    1732              :     }
    1733              : 
    1734              :     // look up conductivity and viscosity
    1735      4467317 :     Kactual = state.dataPlnt->PlantLoop(LoopNum).glycol->getConductivity(state, this->FluidTemp(0), RoutineName); // W/m-K
    1736      4467317 :     MUactual = state.dataPlnt->PlantLoop(LoopNum).glycol->getViscosity(state, this->FluidTemp(0), RoutineName) /
    1737              :                1000.0; // Note fluid properties routine returns mPa-s, we need Pa-s
    1738              : 
    1739              :     // Calculate the Reynold's number from RE=(4*Mdot)/(Pi*Mu*Diameter) - as RadiantSysLowTemp
    1740      4467317 :     ReD = 4.0 * MassFlowRate / (Constant::Pi * MUactual * Diameter);
    1741              : 
    1742      4467317 :     if (ReD == 0.0) { // No flow
    1743              : 
    1744              :         // For now just leave it how it was doing it before
    1745      1938541 :         NuD = 3.66;
    1746              :         // Although later it would be nice to have a natural convection correlation
    1747              : 
    1748              :     } else { // Calculate the Nusselt number based on what flow regime one is in
    1749              : 
    1750      2528776 :         if (ReD >= MaxLaminarRe) { // Turbulent flow --> use Colburn equation
    1751      2528776 :             NuD = 0.023 * std::pow(ReD, 0.8) * std::pow(PRactual, 1.0 / 3.0);
    1752              :         } else { // Laminar flow --> use constant surface temperature relation
    1753            0 :             NuD = 3.66;
    1754              :         }
    1755              :     }
    1756              : 
    1757      4467317 :     CalcPipeHeatTransCoef = Kactual * NuD / Diameter;
    1758              : 
    1759      4467317 :     return CalcPipeHeatTransCoef;
    1760              : }
    1761              : 
    1762              : //==============================================================================
    1763              : 
    1764       558537 : Real64 PipeHTData::OutsidePipeHeatTransCoef(EnergyPlusData &state)
    1765              : {
    1766              : 
    1767              :     // FUNCTION INFORMATION:
    1768              :     //       AUTHOR         Dan Fisher
    1769              :     //       DATE WRITTEN   July 2007
    1770              :     //       MODIFIED       na
    1771              :     //       RE-ENGINEERED  na
    1772              : 
    1773              :     // PURPOSE OF THIS SUBROUTINE:
    1774              :     // This subroutine calculates the convection heat transfer
    1775              :     // coefficient for a cylinder in cross flow.
    1776              : 
    1777              :     // REFERENCES:
    1778              :     // Fundamentals of Heat and Mass Transfer: Incropera and DeWitt, 4th ed.
    1779              :     // p. 369-370 (Eq. 7:55b)
    1780              : 
    1781              :     // Return value
    1782              :     Real64 OutsidePipeHeatTransCoef;
    1783              : 
    1784              :     // SUBROUTINE PARAMETER DEFINITIONS:
    1785       558537 :     Real64 constexpr Pr(0.7);           // Prandl number for air (assume constant)
    1786       558537 :     Real64 constexpr CondAir(0.025);    // thermal conductivity of air (assume constant) [W/m.K]
    1787       558537 :     Real64 constexpr RoomAirVel(0.381); // room air velocity of 75 ft./min [m/s]
    1788       558537 :     Real64 constexpr NaturalConvNusselt(0.36);
    1789              :     // Nusselt for natural convection for horizontal cylinder
    1790              :     // from: Correlations for Convective Heat Transfer
    1791              :     //      Dr. Bernhard Spang
    1792              :     //      Chemical Engineers' Resource Page: http://www.cheresources.com/convection.pdf
    1793       558537 :     int constexpr NumOfParamDivisions(5); // intervals in property correlation
    1794       558537 :     int constexpr NumOfPropDivisions(12); // intervals in property correlation
    1795              : 
    1796              :     static constexpr std::array<Real64, NumOfParamDivisions> CCoef = {0.989, 0.911, 0.683, 0.193, 0.027};         // correlation coefficient
    1797              :     static constexpr std::array<Real64, NumOfParamDivisions> mExp = {0.33, 0.385, 0.466, 0.618, 0.805};           // exponent
    1798              :     static constexpr std::array<Real64, NumOfParamDivisions> UpperBound = {4.0, 40.0, 4000.0, 40000.0, 400000.0}; // upper bound of correlation range
    1799              :     static constexpr std::array<Real64, NumOfPropDivisions> Temperature = {
    1800              :         -73.0, -23.0, -10.0, 0.0, 10.0, 20.0, 27.0, 30.0, 40.0, 50.0, 76.85, 126.85}; // temperature [C]
    1801              :     static constexpr std::array<Real64, NumOfPropDivisions> DynVisc = {
    1802              :         75.52e-7, 11.37e-6, 12.44e-6, 13.3e-6, 14.18e-6, 15.08e-6, 15.75e-6, 16e-6, 16.95e-6, 17.91e-6, 20.92e-6, 26.41e-6}; // dynamic
    1803              :     // viscosity
    1804              :     // [m^2/s]
    1805              : 
    1806              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1807              :     int idx;
    1808              :     Real64 NuD;
    1809              :     Real64 ReD;
    1810              :     Real64 Coef;
    1811              :     Real64 rExp;
    1812              :     Real64 AirVisc;
    1813              :     Real64 AirVel;
    1814              :     Real64 AirTemp;
    1815              :     Real64 PipeOD;
    1816              :     bool ViscositySet;
    1817              :     bool CoefSet;
    1818              : 
    1819              :     // Set environmental variables
    1820       558537 :     switch (this->Type) {
    1821       372358 :     case DataPlant::PlantEquipmentType::PipeInterior: {
    1822       372358 :         switch (this->EnvironmentPtr) {
    1823       186179 :         case EnvrnPtr::ScheduleEnv: {
    1824       186179 :             AirTemp = this->envrSched->getCurrentVal();
    1825       186179 :             AirVel = this->envrVelSched->getCurrentVal();
    1826       186179 :         } break;
    1827       186179 :         case EnvrnPtr::ZoneEnv: {
    1828       186179 :             AirTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->EnvrZonePtr).MAT;
    1829       186179 :             AirVel = RoomAirVel;
    1830       186179 :         } break;
    1831            0 :         default:
    1832            0 :             break;
    1833              :         }
    1834       372358 :     } break;
    1835       186179 :     case DataPlant::PlantEquipmentType::PipeExterior: {
    1836       186179 :         switch (this->EnvironmentPtr) {
    1837       186179 :         case EnvrnPtr::OutsideAirEnv: {
    1838       186179 :             AirTemp = state.dataLoopNodes->Node(this->EnvrAirNodeNum).Temp;
    1839       186179 :             AirVel = state.dataEnvrn->WindSpeed;
    1840       186179 :         } break;
    1841            0 :         default:
    1842            0 :             break;
    1843              :         }
    1844       186179 :     } break;
    1845            0 :     default:
    1846            0 :         break;
    1847              :     }
    1848              : 
    1849       558537 :     PipeOD = this->InsulationOD;
    1850              : 
    1851       558537 :     ViscositySet = false;
    1852      3702653 :     for (idx = 0; idx < NumOfPropDivisions; ++idx) {
    1853      3702653 :         if (AirTemp <= Temperature[idx]) {
    1854       558537 :             AirVisc = DynVisc[idx];
    1855       558537 :             ViscositySet = true;
    1856       558537 :             break;
    1857              :         }
    1858              :     }
    1859              : 
    1860       558537 :     if (!ViscositySet) {
    1861            0 :         AirVisc = DynVisc[NumOfPropDivisions - 1];
    1862            0 :         if (AirTemp > Temperature[NumOfPropDivisions - 1]) {
    1863            0 :             ShowWarningError(state,
    1864            0 :                              format("Heat Transfer Pipe = {}Viscosity out of range, air temperature too high, setting to upper limit.", this->Name));
    1865              :         }
    1866              :     }
    1867              : 
    1868              :     // Calculate the Reynold's number
    1869       558537 :     CoefSet = false;
    1870       558537 :     if (AirVisc > 0.0) {
    1871       558537 :         ReD = AirVel * PipeOD / (AirVisc);
    1872              :     }
    1873              : 
    1874      2212153 :     for (idx = 0; idx < NumOfParamDivisions; ++idx) {
    1875      2212153 :         if (ReD <= UpperBound[idx]) {
    1876       558537 :             Coef = CCoef[idx];
    1877       558537 :             rExp = mExp[idx];
    1878       558537 :             CoefSet = true;
    1879       558537 :             break;
    1880              :         }
    1881              :     }
    1882              : 
    1883       558537 :     if (!CoefSet) {
    1884            0 :         Coef = CCoef[NumOfParamDivisions - 1];
    1885            0 :         rExp = mExp[NumOfParamDivisions - 1];
    1886            0 :         if (ReD > UpperBound[NumOfParamDivisions - 1]) {
    1887            0 :             ShowWarningError(state, format("Heat Transfer Pipe = {}Reynolds Number out of range, setting coefficients to upper limit.", this->Name));
    1888              :         }
    1889              :     }
    1890              : 
    1891              :     // Calculate the Nusselt number
    1892       558537 :     NuD = Coef * std::pow(ReD, rExp) * std::pow(Pr, 1.0 / 3.0);
    1893              : 
    1894              :     // If the wind speed is too small, we need to use natural convection behavior:
    1895       558537 :     NuD = max(NuD, NaturalConvNusselt);
    1896              : 
    1897              :     // h = (k)(Nu)/D
    1898       558537 :     OutsidePipeHeatTransCoef = CondAir * NuD / PipeOD;
    1899              : 
    1900       558537 :     return OutsidePipeHeatTransCoef;
    1901              : }
    1902              : 
    1903              : //==============================================================================
    1904              : 
    1905      1316400 : Real64 PipeHTData::TBND(EnergyPlusData &state,
    1906              :                         Real64 const z // Current Depth
    1907              : )
    1908              : {
    1909              : 
    1910              :     //       AUTHOR         Edwin Lee
    1911              :     //       DATE WRITTEN   December 2007
    1912              :     //       MODIFIED       na
    1913              :     //       RE-ENGINEERED  na
    1914              : 
    1915              :     // PURPOSE OF THIS FUNCTION:
    1916              :     // Returns a temperature to be used on the boundary of the buried pipe model domain
    1917              : 
    1918              :     // METHODOLOGY EMPLOYED:
    1919              : 
    1920              :     // REFERENCES: See Module Level Description
    1921              : 
    1922              :     // Using/Aliasing
    1923      1316400 :     Real64 curSimTime = state.dataGlobal->DayOfSim * Constant::rSecsInDay;
    1924      1316400 :     return this->groundTempModel->getGroundTempAtTimeInSeconds(state, z, curSimTime);
    1925              : }
    1926              : 
    1927            0 : void PipeHTData::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
    1928              : {
    1929            0 : }
    1930              : 
    1931              : //===============================================================================
    1932              : 
    1933              : //===============================================================================
    1934              : 
    1935              : } // namespace EnergyPlus::PipeHeatTransfer
        

Generated by: LCOV version 2.0-1