LCOV - code coverage report
Current view: top level - EnergyPlus - PipeHeatTransfer.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 744 890 83.6 %
Date: 2023-01-17 19:17:23 Functions: 17 18 94.4 %

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

Generated by: LCOV version 1.13